Python音频帧音高变换

4
我正在尝试使用pyaudio制作语音掩蔽器。目前的设置是,我只需要输入声音,即时改变音高并将其分块输出。第一和最后部分都已经实现了,而且我认为我已经接近改变音高了...强调一下,“接近”这个词。
不幸的是,我对我正在处理的数据类型以及如何按照我想要的方式操作它并不太熟悉。我已经查阅了audioop文档,但没有找到我需要的内容(虽然里面确实有一些我可以用的东西)。我想问的是...
这些音频帧的数据格式是什么样子的?
我如何改变帧的音高(如果可以的话),或者它是否能够像这样工作?
import pyaudio
import sys
import numpy as np
import wave
import audioop
import struct

chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 41000
RECORD_SECONDS = 5

p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,
                channels = CHANNELS,
                rate = RATE,
                input = True,
                output = True,
                frames_per_buffer = chunk)

swidth = 2

print "* recording"



while(True):

    data = stream.read(chunk)
    data = np.array(wave.struct.unpack("%dh"%(len(data)/swidth), data))*2

    data = np.fft.rfft(data)
    #MANipulation
    data = np.fft.irfft(data)



    stream.write(data3, chunk)




print "* done"

stream.stop_stream()
stream.close()
p.terminate()

我是否遗漏了什么,还是在调用stream.writedata3应该是data - SwiftsNamesake
2个回答

5
irfft行之后,在stream.write行之前,您需要使用struct.pack调用将数据转换回16位整数。
data = np.fft.irfft(data)
dataout = np.array(data*0.5, dtype='int16') #undo the *2 that was done at reading
chunkout = struct.pack("%dh"%(len(dataout)), *list(dataout)) #convert back to 16-bit data
stream.write(chunkout)

明白了...太完美了。非常感谢你们。 - Lebull on Wow
1
这太棒了,非常有帮助,谢谢!不过,我认为有一个错别字 - 第三行不应该是“chunkout = wave.struct.pack[...]”吗? - scubbo
@scubbo - 谢谢。我认为应该是struct.pack而不是wave.struct.pack,但是没错,你是对的。 - mtrw
@mtrw 你如何改变你想要的音高偏移量?(+1)。 - Neil
@Neil - 这个答案只涉及问题的数据格式部分。音高转换是一个非常庞大的主题,我对此并不了解。你可能想在 https://dsp.stackexchange.com 上提问。 - mtrw

3
要改变音调,你需要对多帧进行FFT,然后在频率上移动数据(将数据移动到不同的频率区间)并执行逆FFT。
如果您不介意音频片段变长而降低音调(或升高音调时更高),则可以重新采样这些帧。例如,您可以将每个帧加倍(在流中插入每个帧的副本),从而降低播放速度和音调。然后,您可以通过改进重新采样算法来使用某种插值和/或滤波器来提高音频质量。

我尝试立即执行FTT和IFFT...返回静态。数组中是否仍应该有虚数部分? - Lebull on Wow
不,如果在实信号上执行FFT,然后再进行IFFT,结果将是一个实信号。 - Han
嘿...好吧,我想问题应该在解包上而不是FTT上。我已经更新了代码到我现在拥有的内容。 - Lebull on Wow
你能解释一下如何进行“将数据移动到不同频率引脚”的部分吗?要改变音高,仅需要通过某个常数缩放数据数组中的所有值吗? - bkr879
如果你的FFT数据存储在一个数组x[1]...x[N]中,那么你可以将所有元素向上移动y[n] = x[n-k],或向下移动y[n] = x[n+k]。音高的变化量为k*f/2,其中f是采样率。 - Han

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接