问题
Hello I am taking a programming class and I am completely lost with a question. We need to take two sounds and add them together. But the first sound starts of at full volume and the second starts silent and then slowing shifting the balance till the first sound is silent and the second is at full volume. So I was able to put the sounds together but i am not sure how to make them get louder over the course of the sound.
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
回答1:
This is not a python problem per se, but rather a deconstructing the task problem.
Sound volume
Firstly, you need to know how to scale the volume of a sound. This is actually super easy!
PCM sound (which is what you're working with) is stored as a signed distance from zero. I like to visualize it as "where the speaker cone is" - a zero means the speaker is at rest, a negative value sucks the speaker cone in, and a positive value pushes the speaker out.
If you've ever watched a speaker, you know that the further the speaker move, the louder the sound. To make the speaker move less, multiply each sample by some number between 0 and 1.
So, to just scale both of your sounds, something like this works:
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
Ramping volume
Now you know how to actually make a sound louder or quieter, you need to know what has to happen to the amplitude of each sound over time.
What should the amplitude of the first sound be at the start? What about the second?
At the start, the second sound should be silent, so its amplitude is zero. The first sound should be full volume, so its amplitude is 1:
firstSoundVolume = 1
secondSoundVolume = 0
At the end, it's the opposite:
firstSoundVolume = 0
secondSoundVolume = 1
How can you use this? Basically you want to smoothly slide each amplitude from its starting value to its ending one. There are a bunch of different ways to do this, but my favourite is something like this:
- Work out where in the crossfade you are, in seconds or samples. You are calling this
t
, which is perfect. - Convert that to a position in the crossfade, as a fraction of the crossfade length. (ie
t
/length
). I'll call thisu
. - You can now scale using
u
directly (as gnibbler's example does), or go through another function to get the scaling factors.
Here's gnibbler's example again, expanded to include u
explicitly:
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)
Other crossfading functions
Now that you have 0 < u
< 1, you can use a bunch of functions to do the actual crossfade.
Here's the same linear fade done with a function.
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
Now you can do some other crossfades, like these ones:
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)
来源:https://stackoverflow.com/questions/20135362/beginner-python-programming-help-to-crossfade-sounds