Python,变调,电脑钢琴
admin
2023-07-31 01:42:57
0

录一段音频,把它的音高改变50次并把每一个新的音频匹配到键盘的一个键位,你就能把电脑变成一架钢琴!

一段音频可以被编码为一组数值的数组(或者列表),像这样:

1

我们可以在数组中每隔一秒拿掉一秒的值来将这段音频的速度变成两倍:

2

如此我们不仅将音频的长度减半了,而且我们还将它的频率翻倍了,这样使得它拥有比原来更高的音高(pitch)。

相反地,假如我们将数组中每个值重复一次,我们将得到一段更慢,周期更长,即音高更低的音频:

3

这里提供一个可以按任意系数改变音频速度的任意简单的Python函数:

1234567 import numpy as np def speedx(sound_array, factor):    \”\”\” 将音频速度乘以任意系数`factor` \”\”\”    indices = np.round( np.arange(0, len(snd_array), factor) )    indices = indices[indices < len(snd_array)].astype(int)    return sound_array[ indices.astype(int) ]

这个问题更困难的地方在于改变音频长度的同时保持它的音高(变速,音频拉伸(sound stretching)),或者在改变音频的音高的同时保持它的长度(变调(pitch shifting))。

变速

变速可以通过传统的相位声码器phase vocoder,感兴趣的朋友可以读一下维基百科的页面)来实现。首先将音频分解成重叠的比特,然后将这些比特重新排列使得他们重叠得更多(将缩短声音的长度)或者更少(将拉伸音频的长度),如下图所示:

4

困难之处在于重新排列的比特可能很严重的互相影响,那么这里就需要用到相位变换来确保它们之间没有影响。这里有一段Python代码,取自这个网页(打不开的话,您懂的。——译者注):

1234567891011121314151617181920212223242526 def stretch(sound_array, f, window_size, h):    \”\”\” 将音频按系数`f`拉伸 \”\”\”     phase  = np.zeros(window_size)    hanning_window = np.hanning(window_size)    result = np.zeros( len(sound_array) /f + window_size)     for i in np.arange(0, len(sound_array)(window_size+h), h*f):         # 两个可能互相重叠的子数列        a1 = sound_array[i: i + window_size]        a2 = sound_array[i + h: i + window_size + h]         # 按第一个数列重新同步第二个数列        s1 =  np.fft.fft(hanning_window * a1)        s2 =  np.fft.fft(hanning_window * a2)        phase = (phase + np.angle(s2/s1)) % 2*np.pi        a2_rephased = np.fft.ifft(np.abs(s2)*np.exp(1j*phase))         # 加入到结果中        i2 = int(i/f)        result[i2 : i2 + window_size] += hanning_window*a2_rephased     result = ((2**(164)) * result/result.max()) # 归一化 (16bit)     return result.astype(\’int16\’)

 

变调

一旦你实现了变速以后,变调就不难了。如果需要一个更高的音高,可以先将这段音频拉伸并保持音高不变,然后再加快它的速度,如此最后得到的音频将具有原始音频同样的长度,更高的频率,即更高的音高。

把一段音频的频率翻倍将把音高提高一个八度,也就是12个半音。因此,要将音高提高n个半音的话,我们需要将频率乘上系数2^(n/12):

12345 def pitchshift(snd_array, n, window_size=2**13, h=2**11):    \”\”\” 将一段音频的音高提高“n“个半音 \”\”\”    factor = 2**(1.0 * n / 12.0)    stretched = stretch(snd_array, 1.0/factor, window_size, h)    return speedx(stretched[window_size:], factor)

 

小程序:电脑钢琴

让我们来玩一下我们的变调器。我们先敲碗来确定一个“标准音高”:

[youku id=”XNzM1NDM2NTky”]

接下来我们基于之前的音频创造50个变调的音高,从很低到很高:

12345 from scipy.io import wavfile fps, bowl_sound = wavfile.read(\”bowl.wav\”)tones = range(25,25)transposed = [pitchshift(bowl_sound, n) for n in tones]

接下来根据这个文件中的顺序,我们把每一个音频匹配到键盘的一个键位,如下图所示:

5

我们只需要在代码中告诉计算机当一个键按下来的时候播放其对应的声音,然后当按键松开后停止播放就可以了:

12345678910111213141516171819202122232425262728293031323334 import pygame pygame.mixer.init(fps, 16, 1, 512) # 太灵活了

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...