FPGA-RISC-V-CPU / hardware / scripts / audio / audio_from_sim
audio_from_sim
Raw
#!/usr/bin/env python3
import wave
import argparse
import struct
# import matplotlib.pyplot as plt

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description='Convert a text file of binary samples to an audio file',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('--f-samp', default=60000, type=float, help="Sampling frequency")
    # parser.add_argument('--num-int-bits', default=9, type=int, help="Number of integer bits (including sign) for each sample")
    # parser.add_argument('--num-frac-bits', default=3, type=int, help="Number of fractional bits for each sample")
    parser.add_argument('input_file', type=str, help="Input .txt file path")
    parser.add_argument('output_file', default="output.wav", type=str, help="Output .wav file path")
    args = parser.parse_args()

    def renormalize(n, range1, range2):
        delta1 = range1[1] - range1[0]
        delta2 = range2[1] - range2[0]
        return (delta2 * (n - range1[0]) / delta1) + range2[0]

    def bin_str_to_sint(bin_str: str) -> int:
        # extend binary string to 32 bits
        bin_str = bin_str + '0' * (32 - len(bin_str))
        # interpret as unsigned 32-bit integer
        unsigned_bytes = struct.pack("I", int(bin_str, 2))
        # cast to signed 32-bit value
        return struct.unpack("i", unsigned_bytes)[0]

    with open(args.input_file, 'r') as samples_file:
        samples_bin_str = [line.rstrip('\n') for line in samples_file]
        # assert all(len(x) == args.num_int_bits + args.num_frac_bits for x in samples_bin_str)

        samples = [bin_str_to_sint(x) for x in samples_bin_str]
        # print(min(samples), max(samples))
        # plt.plot(samples_scaled)
        # plt.show()

        samples_scaled = [renormalize(s, (-2**31, 2**31-1), (-2**15, 2**15-1)) for s in samples]
        samples_packed = [struct.pack('<h', int(v)) for v in samples_scaled]

        output_wav = wave.open(args.output_file, 'w')
        # nchannels (1 = mono), sampwidth (2 bytes per sample), framerate (~ 122 kHz), nframes (0)
        output_wav.setparams((1, 2, args.f_samp, 0, 'NONE', 'not compressed'))
        output_wav.writeframes(b''.join(samples_packed))
        output_wav.close()