在python中创建32位float wav文件?

问题描述 投票:3回答:3

我想在Python(2.x)中创建32位float WAV文件。虽然“标准” WAV文件通常使用int,但许多专业音频应用程序将音频数据处理(并保存)为浮点型。标准wave模块无法执行此操作:http://bugs.python.org/issue16525没有人在不使用补丁模块的情况下实现了这一目标吗? tnx寻求帮助。

python audio python-2.7 floating-point wav
3个回答
4
投票

这听起来很有趣(请参见我的手柄),所以我锤了一些东西。也许您可以使用它。如果您的Python脚本生成的单音波形的数值介于[-1.0 .. 1.0]之间,请通过sample_array发送该波形并指定sample_rate(例如44100或48000)。这将返回一个数组,您可以将其作为.wav文件写入磁盘。

我在Windows Media Player,Apple QuickTime Player和VLC(全部在Windows 7中)中测试了所得的.wav输出。他们都玩过。

def float32_wav_file(sample_array, sample_rate):
  byte_count = (len(sample_array)) * 4  # 32-bit floats
  wav_file = ""
  # write the header
  wav_file += struct.pack('<ccccIccccccccIHHIIHH',
    'R', 'I', 'F', 'F',
    byte_count + 0x2c - 8,  # header size
    'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
    0x10,  # size of 'fmt ' header
    3,  # format 3 = floating-point PCM
    1,  # channels
    sample_rate,  # samples / second
    sample_rate * 4,  # bytes / second
    4,  # block alignment
    32)  # bits / sample
  wav_file += struct.pack('<ccccI',
    'd', 'a', 't', 'a', byte_count)
  for sample in sample_array:
    wav_file += struct.pack("<f", sample)
  return wav_file

2
投票

[这是我的贡献...包括任意字长和任意数量的频道。我已经自由更改了float32_wav_file,以包含一个保存用于测试的文件。请注意,文件结构的多通道数据部分是交错的。我敢肯定,该循环可能会被极大地Python化。

# see http://stackoverflow.com/questions/15576798/create-32bit-float-wav-file-in-python
# see... http://blog.theroyweb.com/extracting-wav-file-header-information-using-a-python-script
import struct
def float32_wav_file(file_name, sample_array, sample_rate):
    (M,N)=sample_array.shape
    #print "len sample_array=(%d,%d)" % (M,N)
    byte_count = M * N * 4 # (len(sample_array)) * 4  # 32-bit floats
    wav_file = ""
    # write the header
    wav_file += struct.pack('<ccccIccccccccIHHIIHH',
        'R', 'I', 'F', 'F',
        byte_count + 0x2c - 8,  # header size
        'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
        0x10,  # size of 'fmt ' header
        3,  # format 3 = floating-point PCM
        M,  # channels
        sample_rate,  # samples / second
        sample_rate * 4,  # bytes / second
        4,  # block alignment
        32)  # bits / sample
    wav_file += struct.pack('<ccccI',
        'd', 'a', 't', 'a', byte_count)
    print "packing..."
    for j in range(0,N):
        for k in range(0,M):
            wav_file += struct.pack("<f", sample_array[k,j])
    print "saving..."
    fi=open(file_name,'wb')
    for value in wav_file:
        fi.write(value)
    fi.close()

    return wav_file

import numpy as np
def wav_file_read(filename):
    fi=open(filename,'rb')
    data=fi.read()
    fi.close()
    A, B, C,  D        =struct.unpack('4c', data[0:4])      # 'RIFF'
    ChunkSize     =struct.unpack('<l', data[4:8])[0]   #4+(8+SubChunk1Size)+8+SubChunk2Size)
    A, B, C,  D        =struct.unpack('4c', data[8:12])     # 'WAVE'
    A, B, C,  D        =struct.unpack('4c', data[12:16])    # 'fmt '
    Subchunk1Size =struct.unpack('<l', data[16:20])[0] # LITTLE ENDIAN, long, 16
    AudioFormat   =struct.unpack('<h', data[20:22])[0] # LITTLE ENDIAN, short, 1
    NumChannels   =struct.unpack('<h', data[22:24])[0] # LITTLE ENDIAN, short, Mono = 1, Stereo = 2
    SampleRate    =struct.unpack('<l', data[24:28])[0] # LITTLE ENDIAN, long,  sample rate in samples per second
    ByteRate      =struct.unpack('<l', data[28:32])[0] # self.SampleRate * self.NumChannels * self.BitsPerSample/8)) # (ByteRate) LITTLE ENDIAN, long
    BlockAlign    =struct.unpack('<h', data[32:34])[0] # self.NumChannels * self.BitsPerSample/8))  # (BlockAlign) LITTLE ENDIAN, short
    BitsPerSample =struct.unpack('<h', data[34:36])[0] # LITTLE ENDIAN, short
    A,  B,  C,  D      =struct.unpack('4c', data[36:40])    # BIG ENDIAN, char*4
    SubChunk2Size      =struct.unpack('<l', data[40:44])[0] # LITTLE ENDIAN, long
    waveData=data[44:]
    (M,N)=(len(waveData),len(waveData[0]))   

    print("ChunkSize     =%d\nSubchunk1Size =%d\nAudioFormat   =%d\nNumChannels   =%d\nSampleRate    =%d\nByteRate      =%d\nBlockAlign    =%d\nBitsPerSample =%d\nA:%c,  B:%c,  C:%c,  D:%c\nSubChunk2Size =%d" %
        (ChunkSize     , 
        Subchunk1Size, 
        AudioFormat   ,
        NumChannels   ,
        SampleRate    ,
        ByteRate      ,
        BlockAlign    ,
        BitsPerSample ,
        A,  B,  C,  D ,
        SubChunk2Size ))    


    if BitsPerSample==8:
        print "Unpacking 8 bits on len(waveData)=%d" % len(waveData)
        d=np.fromstring(waveData,np.uint8)
        floatdata=d.astype(np.float64)/np.float(127)    
    elif BitsPerSample==16:
        print "Unpacking 16 bits on len(waveData)=%d" % len(waveData)
        d=np.zeros(SubChunk2Size/2, dtype=np.int16)
        j=0
        for k in range(0, SubChunk2Size, 2):
            d[j]=struct.unpack('<h',waveData[k:k+2])[0]
            j=j+1
        floatdata=d.astype(np.float64)/np.float(32767)    
    elif BitsPerSample==24:
        print "Unpacking 24 bits on len(waveData)=%d" % len(waveData)
        d=np.zeros(SubChunk2Size/3,  dtype=np.int32)
        j=0
        for k in range(0, SubChunk2Size, 3):
            d[j]=struct.unpack('<l',struct.pack('c',waveData[k])+waveData[k:k+3])[0]
            j=j+1
        floatdata=d.astype(np.float64)/np.float(2147483647)    
    else: # anything else will be considered 32 bits
        print "Unpacking 32 bits on len(waveData)=%d" % len(waveData)
        d=np.fromstring(waveData,np.int32)
        floatdata=d.astype(np.float64)/np.float(2147483647)   
    v=floatdata[0::NumChannels]
    for i in range(1,NumChannels):
        v=np.vstack((v,floatdata[i::NumChannels]))
    #return (np.vstack((floatdata[0::2],floatdata[1::2])), SampleRate, NumChannels, BitsPerSample)
    return (v, SampleRate, NumChannels, BitsPerSample)

if __name__ == "__main__":
    (array,SampleRate,NumChannels,BitsPerSample)=wav_file_read("my_input_file.wav")
    wavefile=float32_wav_file("test_file.wav",array,SampleRate)

0
投票

我尝试测试P Moran的代码,但绝对无法正常工作,例如'len(int(3))?'。抱歉,我认为它没有经过测试。但是不要担心,现代python有办法!

import numpy as np
songtime=np.arange(0,100,60/44100.,dtype=float)
coswav=np.cos(songtime)
sinewav=np.sin(songtime)
np.column_stack((coswav,sinwav))
songwav=np.column_stack((coswav,sinwav)).astype('float32')

import scipy.io.wavfile as scipy_io_wavfile
scipy_io_wavfile.write("5secof60Hz.wav",44100,songwav)

https://docs.python.org/3.7/library/wave.htmlhttps://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.write.html

© www.soinside.com 2019 - 2024. All rights reserved.