这本身不是 python 问题,而是解构任务问题。
音量
首先,您需要知道如何调整声音的音量。这其实超级简单!
PCM 声音(您正在使用的声音)存储为距离零的有符号距离。我喜欢将其可视化为“扬声器锥体所在的位置”——零表示扬声器处于静止状态,负值将扬声器锥体吸入,正值将扬声器推出。
如果您曾经看过扬声器,就会知道扬声器移动得越远,声音就越大。为了使扬声器移动得更少,请将每个样本乘以 0 到 1 之间的某个数字。
所以,要缩放你的两个声音,这样的方法是可行的:
def amplify(s1, amplify_value):
sr = int(getSamplingRate(s1))
newSound = makeEmptySound(getLength(s1), sr)
for t in range(getLength(newSound)):
sv1 = getSampleValueAt(s1, t)
setSampleValueAt(newSound, t, sv1 * amplify_value)
return newSound
爬坡量
现在您知道如何让声音变大或变小,您需要知道随着时间的推移每个声音的幅度会发生什么变化。
开始时第一个声音的幅度应该是多少?第二个呢?
在开始时,第二个声音应该是无声的,所以它的幅度为零。第一个声音应该是全音量,所以它的幅度是1:
firstSoundVolume = 1
secondSoundVolume = 0
最后是相反的:
firstSoundVolume = 0
secondSoundVolume = 1
你怎么能用这个?基本上,您希望将每个幅度从其起始值平滑地滑动到其结束值。有很多不同的方法可以做到这一点,但我最喜欢的是这样的:
- 以秒或样本为单位计算出您在淡入淡出的位置。你打电话给这个
t,这是完美的。
- 将其转换为交叉渐变中的位置,作为交叉渐变长度的一部分。 (即
t/length)。我会打电话给u。
- 您现在可以直接使用
u 进行缩放(就像 gnibbler 的示例一样),或者通过另一个函数来获取缩放因子。
这里又是 gnibbler 的示例,扩展为明确包含 u:
n = getLength(newSound)
for t in range(n):
u = t / float(n)
sv1 = getSampleValueAt(s1, t)
sv2 = getSampleValueAt(s2, t)
setSampleValueAt(newSound, t, sv1 * (1-u) + sv2 * u)
其他交叉淡入淡出功能
现在你有了 0 u
这是用函数完成的相同的线性淡入淡出。
def linear(u):
return (1-u, u)
def mergeSounds(s1, s2, fade=linear):
"""Crossfade two sounds, using linear fading by default"""
sr = int(getSamplingRate(s1))
newSound = makeEmptySound(getLength(s1), sr)
n = getLength(newSound)
for t in range(n):
u = t / float(n)
amp1, amp2 = fade(u)
sv1 = getSampleValueAt(s1, t)
sv2 = getSampleValueAt(s2, t)
setSampleValueAt(newSound, t, (sv1 * amp1) + (sv2 * amp2))
return newSound
现在你可以做一些其他的交叉淡入淡出,比如这些:
def quadratic_out(u):
u = u * u
return (1-u, u)
def quadratic_in(u):
u = 1-u
u = u * u
return (u, 1-u)
def linear_bounce(u):
u = 2 * ( 0.5-u if u > 0.5 else u)
return (1-u, u)