How do I write a 24-bit WAV file in Python?

前端 未结 7 2168
遇见更好的自我
遇见更好的自我 2020-12-11 02:05

I want to generate a 24-bit WAV-format audio file using Python 2.7 from an array of floating point values between -1 and 1. I can\'t use scipy.io.wavfile.write because it on

相关标签:
7条回答
  • 2020-12-11 02:10

    You should try scikits.audiolab:

    import numpy as np
    from scikits.audiolab import Sndfile, Format
    
    sig = np.array([0, 1, 0, -1, 0], dtype=np.float32)
    f = Sndfile('test_pcm24.wav', 'w', Format('wav', 'pcm24'), 1, 44100)
    f.write_frames(sig)
    f.close()  # use contextlib.closing in real code
    

    And to read it again:

    f = Sndfile('test_pcm24.wav')
    sig = f.read_frames(f.nframes, dtype=np.float32)
    f.close()  # use contextlib.closing in real code
    

    scikits.audiolab uses libsndfile, so in addition to WAV files, you can also use FLAC, OGG and some more file formats.

    0 讨论(0)
  • 2020-12-11 02:12

    Make use of ffmpeg to interchange between wav codecs, below is a sample code

    command = "ffmpeg -i input.wav -ar 22050 output.wav"
    subprocess.call(command, shell=True)
    
    0 讨论(0)
  • 2020-12-11 02:15

    I already submitted an answer to this question 2 years ago, where I recommended scikits.audiolab.

    In the meantime, the situation has changed and now there is a library available which is much easier to use and much easier to install, it even comes with its own copy of the libsndfile library for Windows and OSX (on Linux it's easy to install anyway): PySoundFile!

    If you have CFFI and NumPy installed, you can install PySoundFile simply by running

    pip install soundfile --user
    

    Writing a 24-bit WAV file is easy:

    import soundfile as sf
    sf.write('my_24bit_file.wav', my_audio_data, 44100, 'PCM_24')
    

    In this example, my_audio_data has to be a NumPy array with dtype 'float64', 'float32', 'int32' or 'int16'.

    BTW, I made an overview page where I tried to compare many available Python libraries for reading/writing sound files.

    0 讨论(0)
  • 2020-12-11 02:15

    Try the wave module:

    In [1]: import wave
    
    In [2]: w = wave.open('foo.wav', 'w') # open for writing
    
    In [3]: w.setsampwidth(3) # 3 bytes/sample
    

    Python can only pack integers in 2 and 4 bite sizes. So you can use a numpy array with a dtype on int32, and use a list comprehension to get 3/4 of the bytes of each integer:

    In [14]: d = np.array([1,2,3,4], dtype=np.int32)
    
    In [15]: d
    Out[15]: array([1, 2, 3, 4], dtype=int32)
    
    In [16]: [d.data[i:i+3] for i in range(0,len(d)*d.dtype.itemsize, d.dtype.itemsize)]
    Out[16]: ['\x01\x00\x00', '\x02\x00\x00', '\x03\x00\x00', '\x04\x00\x00']
    
    0 讨论(0)
  • 2020-12-11 02:26

    Another option is available in wavio (also on PyPI: https://pypi.python.org/pypi/wavio), a small module I created as a work-around to the problem of scipy not yet supporting 24 bit WAV files. The file wavio.py contains the function write, which writes a numpy array to a WAV file. To write a 24-bit file, use the argument sampwidth=3. The only dependency of wavio is numpy; wavio uses the standard library wave to deal with the WAV file format.

    For example,

    In [21]: import numpy as np
    
    In [22]: import wavio
    
    In [23]: rate = 22050             # samples per second
    
    In [24]: T = 3                    # sample duration (seconds)
    
    In [25]: f = 440.0                # sound frequency (Hz)
    
    In [26]: t = np.linspace(0, T, T*rate, endpoint=False)
    
    In [27]: sig = np.sin(2 * np.pi * f * t)
    
    In [28]: wavio.write("sine24.wav", sig, rate, sampwidth=3)
    
    0 讨论(0)
  • 2020-12-11 02:26

    Using the wave module, the Wave_write.writeframes function expects WAV data to be packed into a 3-byte string in little-endian format. The following code does the trick:

    import wave
    from contextlib import closing
    import struct
    
    def wavwrite_24(fname, fs, data):
        data_as_bytes = (struct.pack('<i', int(samp*(2**23-1))) for samp in data)
        with closing(wave.open(fname, 'wb')) as wavwriter:
            wavwriter.setnchannels(1)
            wavwriter.setsampwidth(3)
            wavwriter.setframerate(fs)
            for data_bytes in data_as_bytes:
                wavwriter.writeframes(data_bytes[0:3])
    
    0 讨论(0)
提交回复
热议问题