合成声音,声音在数学上可以表示为具有特定幅度、频率和相位的正弦波。我们可以从维基百科页面http://en.wikipedia.org/wiki/Piano_key_frequencies提供的列表中随机地选择频率。这些频率值是用如下公式得到的。
上式中的变量n是钢琴中的琴键编号,其取值范围是1~88。幅度、持续时间和相位参数将随机选取。
具体步骤
首先将初始化随机变量,再生成正弦波,然后谱曲,最后用Matplotlib绘制生成的声音数据。
- 初始化。
随机变量的初始化:
- 幅度值在200到2000之间
- 持续时间在0.01到0.2之间
- 用上述公式选择频率
- 初始相位值在0到2π之间
- NTONES = int(sys.argv[1])
amps = 2000. * numpy.random.random
((NTONES,)) + 200.
durations = 0.19 * numpy.random.random
((NTONES,)) + 0.01
keys = numpy.random.random_integers
(1, 88, NTONES)
freqs = 440.0 * 2 ** ((keys - 49.)/12.)
phi = 2 * numpy.pi * numpy.random.random((NTONES,))
- 生成正弦波。
编写generate
函数,用来生成正弦波。
def generate(freq, amp, duration, phi):
t = numpy.linspace
(0, duration, duration * RATE)
data = numpy.sin(2 * numpy.pi *
freq * t + phi) * amp
return data.astype(DTYPE)
- 谱曲。
生成数个声调后,我们需要谱写一段连贯的旋律。我们暂时只是把各个正弦波连接在一起。这不会生成一段好听的旋律,但可以作为一个起点,以后可以做更多的尝试。
for i in xrange(NTONES):
newtone = generate(freqs[i], amp=amps[i],
duration=durations[i], phi=phi[i])
tone = numpy.concatenate((tone, newtone))
- 绘制数据。
用Matplotlib绘制合成的声音数据。
matplotlib.pyplot.plot(numpy.linspace (0, len(tone)/RATE, len(tone)), tone)
matplotlib.pyplot.show()
合成的声音数据如下图所示:
本攻略的完整代码如下。
import scipy.io.wavfile
import numpy
import sys
import matplotlib.pyplot
RATE = 44100
DTYPE = numpy.int16
# 生成正弦波
def generate(freq, amp, duration, phi):
t = numpy.linspace(0, duration, duration * RATE)
data = numpy.sin(2 * numpy.pi * freq * t + phi) * amp
return data.astype(DTYPE)
if len(sys.argv) != 2:
print "Please input the number of tones to generate"
sys.exit()
# 初始化
NTONES = int(sys.argv[1])
amps = 2000. * numpy.random.random((NTONES,)) + 200.
durations = 0.19 * numpy.random.random((NTONES,)) + 0.01
keys = numpy.random.random_integers(1, 88, NTONES)
freqs = 440.0 * 2 ** ((keys - 49.)/12.)
phi = 2 * numpy.pi * numpy.random.random((NTONES,))
tone = numpy.array([], dtype=DTYPE)
# 谱曲
for i in xrange(NTONES):
newtone = generate(freqs[i], amp=amps[i], duration=durations[i], phi=phi[i])
tone = numpy.concatenate((tone, newtone))
scipy.io.wavfile.write('generated_tone.wav', RATE, tone)
# 绘制声音数据
matplotlib.pyplot.plot(numpy.linspace(0, len(tone)/RATE, len(tone)), tone)
matplotlib.pyplot.show()
攻略小结
我们用随机生成的声音创建了一个WAV文件。concatenate
函数用来把各个正弦波连接起来。