初学者 python 编程帮助交叉淡入淡出声音

Posted

技术标签:

【中文标题】初学者 python 编程帮助交叉淡入淡出声音【英文标题】:Beginner python programming help to crossfade sounds 【发布时间】:2013-11-22 01:34:53 【问题描述】:

您好,我正在上编程课,但我完全被一个问题迷住了。我们需要把两个声音加在一起。但是第一个声音以最大音量开始,第二个声音开始静音,然后放慢平衡,直到第一个声音静音,第二个声音达到最大音量。所以我能够把声音放在一起,但我不知道如何让它们在声音的过程中变得更响亮。

    def mergeSounds(s1, s2):
      sr = int(getSamplingRate(s1))
      newSound = makeEmptySound(getLength(s1), sr)
      for t in range(getLength(newSound)):
         sv1 = getSampleValueAt(s1, t)
         sv2 = getSampleValueAt(s2, t)
         setSampleValueAt(newSound, t, sv1 + sv2)
      return newSound

【问题讨论】:

这个问题似乎离题了,因为它与 Python 甚至编程本身无关。 @martineau,我不同意。知道如何在一个范围内线性增加一个值是一项非常常见的编程任务。 【参考方案1】:

这本身不是 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)

【讨论】:

【参考方案2】:
n = getLength(newSound) - 1.0        # n should be a float for Python2
for t in range(int(n + 1)):
     sv1 = getSampleValueAt(s1, t)
     sv2 = getSampleValueAt(s2, t)
     setSampleValueAt(newSound, t, sv1 * (1 - t / n) + sv2 * t / n)

【讨论】:

谢谢。非常感谢 其实应该是sv1*(1-t/float(n-1)) + sv2*t/float(n-1),否则最终的值不会是sv2 @martineau,是的。我用稍微不同的方式修复了它 @martineau 现在你需要特殊情况的长度为一的声音 @kibibu:在我的评论提到的代码版本和当前版本中都是如此,并且很容易添加检查。 IMO,这个要求是可以接受的,因为一步不可能也不可能在两个不同的值之间变化。实际上,无论哪种方式,只允许引发异常都可以,因为尝试它没有意义。

以上是关于初学者 python 编程帮助交叉淡入淡出声音的主要内容,如果未能解决你的问题,请参考以下文章

jquery淡入淡出div中的背景图像 - 交叉淡入淡出

为啥这个 CSS @keyframes 规则不交叉淡入淡出?

使用 NAudio 交叉淡入淡出

两个 UILabel 之间的交叉淡入淡出

淡入/淡出声音

AVMutableVideoComposition 中的交叉淡入淡出