2015-02-17 52 views
5

这让我头痛了一天,但是因为我想明白了,所以我想将它发布到某个地方以防万一它有帮助。使用wave(不是scipy.io.wavfile)模块将numpy数组写入波形缓冲区中

我正在使用python的wave模块将数据写入wave文件。我不使用scipy.io.wavfile,因为数据可能是一个巨大的矢量(16kHz的音频小时数),我不想/不能一次加载到内存中。我的理解是,scipy.io.wavfile只给你全文界面,而wave可以让你读写缓冲区。如果我错了,我很想纠正这个问题。

我遇到的问题归结为如何将float数据转换为wave.writeframes函数的字节。我的数据没有按正确的顺序写入。这是因为我用的是numpy.getbuffer()函数将数据转换成字节转换,这不尊重数据的方向:

x0 = np.array([[0,1],[2,3],[4,5]],dtype='int8') 
x1 = np.array([[0,2,4],[1,3,5]],dtype='int8').transpose() 
if np.array_equal(x0, x1): 
    print "Data are equal" 
else: 
    print "Data are not equal" 
b0 = np.getbuffer(x0) 
b1 = np.getbuffer(x1) 

结果:

Data are equal 

In [453]: [b for b in b0] 
Out[453]: ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05'] 

In [454]: [b for b in b1] 
Out[454]: ['\x00', '\x02', '\x04', '\x01', '\x03', '\x05'] 

我假定顺序的字节数由内存中的初始分配决定,因为numpy.transpose()不会重写数据,只是返回一个视图。然而,因为这个事实被numpy数组的接口所掩盖,所以在知道这是个问题之前进行调试是一件很麻烦的事情。

一个解决方案是使用numpy的的toString()函数:

s0 = x0.tostring() 
s1 = x1.tostring() 
In [455]: s0 
Out[455]: '\x00\x01\x02\x03\x04\x05' 

In [456]: s1 
Out[456]: '\x00\x01\x02\x03\x04\x05' 

这可能是显而易见的人谁第一个说的ToString()函数,但不知何故,我的搜索没有挖就如何任何好的文档为使用scipy.io.wavfile以外的波形文件编写格式化整个numpy数组。所以在这里。只是为了完成(注意,“功能”是最初n_channels X N_SAMPLES次,这就是为什么我有这个数据顺序问题开始:

outfile = wave.open(output_file, mode='w') 
outfile.setnchannels(features.shape[0]) 
outfile.setframerate(fs) 
outfile.setsampwidth(2) 
bytes = (features*(2**15-1)).astype('i2').transpose().tostring() 
outfile.writeframes(bytes) 
outfile.close() 
+1

相反tostring'的',您可以用'struct.pack ',它允许你指定字节顺序和大小。参见http://stackoverflow.com/a/19999599/120261用'struct.unpack'阅读,希望这将是一个有用的起点,如果你想尝试这种其他方式。 – mtrw 2015-02-17 21:11:39

+1

尝试''np.getbuffer(x1.ravel())''。另外,如何使用''x0.tofile()''而不是''x0.tostring()''?如果你关心Endianess,请阅读http://docs.scipy.org/doc/numpy/user/basics.byteswapping.html – Dietrich 2015-02-17 23:04:42

+0

我忘记了:创建多维数组时,可以使用参数''order''来确定它们被写入内存的方式:http://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html – Dietrich 2015-02-17 23:11:02

回答

1

对我来说tostring工作正常,请注意,在WAVE 8位文件必须签名,而另一些(16位或32位)必须是无符号

一些肮脏的演示代码为我的作品:

import wave 
import numpy as np 

SAMPLERATE=44100 
BITWIDTH=8 
CHANNELS=2 

def gensine(freq, dur): 
    t = np.linspace(0, dur, round(dur*SAMPLERATE)) 
    x = np.sin(2.0*np.pi*freq*t) 
    if BITWIDTH==8: 
     x = x+abs(min(x)) 
     x = np.array(np.round((x/max(x)) * 255) , dtype=np.dtype('<u1')) 
    else: 
     x = np.array(np.round(x * ((2**(BITWIDTH-1))-1)), dtype=np.dtype('<i%d' % (BITWIDTH/8))) 

    return np.repeat(x,CHANNELS).reshape((len(x),CHANNELS)) 

output_file="test.wav" 

outfile = wave.open(output_file, mode='wb') 
outfile.setparams((CHANNELS, BITWIDTH/8, SAMPLERATE, 0, 'NONE', 'not compressed')) 
outfile.writeframes(gensine(440, 1).tostring()) 
outfile.writeframes(gensine(880, 1).tostring()) 
outfile.close() 
相关问题