我的目的是拥有两个音乐曲目,它们在性质上相似,在不同时间之间相互淡化。当发生这样的淡入淡出时,一个音乐曲目应该在短时间内从全音量淡入淡出,同时,另一个曲目应该从0渐变到100并继续从同一时间指数播放。他们必须能够随时动态 - 当某个动作发生时,淡入淡出将发生并且新曲目将开始在同一位置播放一个人离开了。
通过使用音量操作或启动和停止音乐,这可能是合理的(但是,似乎只存在“淡出”选项,而且缺少“fadein”选项)。我怎样才能做到这一点?存在的最佳方法是什么?如果使用Pygame是不可能的, Pygame的替代品是可以接受的。
答案 0 :(得分:2)
这不是问题的答案,但对于未来的googlers,我写了一个脚本,在早上从第0卷淡入我的音乐,这就是我使用的:
max_volume = 40
current_volume = 0
# set the volume to the given percent using amixer
def set_volume_to(percent):
subprocess.call(["amixer", "-D", "pulse", "sset", "Master",
str(percent) + "%", "stdout=devnull"])
# play the song and fade in the song to the max_volume
def play_song(song_file):
global current_volume
print("Song starting: " + song_file)
pygame.mixer.music.load(song_file)
pygame.mixer.music.play()
# gradually increase volume to max
while pygame.mixer.music.get_busy():
if current_volume < max_volume:
set_volume_to(current_volume)
current_volume += 1
pygame.time.Clock().tick(1)
play_song("foo.mp3")
答案 1 :(得分:1)
伪代码:
track1 = ...
track2 = ...
track1.play_forever()
track1.volume = 100
track2.play_forever()
track2.volume = 0
playing = track1
tracks = [track1, track2]
def volume_switcher():
while True:
playing.volume = min(playing.volume + 1, 100)
for track in tracks:
if track != playing:
track.volume = max(track.volume - 1, 100)
time.sleep(0.1)
Thread(target=volume_switcher).start()
答案 2 :(得分:1)
所以看起来你想在pygame中做的是创建两个'Sound'对象,并在它们之间的音量上创建一个线性插值。
我会创建两个向量,每个向量来自[0,100],并将它们与某个常量相反。 因此,当声音A为100时,声音b为0.然后当动作发生时,修改常量。
t = 0时
答:[0 ... 100 ]
B:[ 0 ... 100]
T = 1
行动
T = 1.1
答:[0 .. 50 .. 100]
B:[0 .. 50 .. 100]
T = 2
答:[ 0 ... 100]
B:[0 ... 100 ]
现在有些代码了。我不熟悉pygame,但这应该会让你走上正轨。
class Song(object):
def __init__(self, songfilename):
self.song = pygame.mixer.Sound(songfilename)
def setVolume(self, somenumber):
#number validation
#possibly do some volume curve here if you wanted
self.song.set_volume(somenumber)
class SongFader(object):
def __init__(self, song1, song2):
self.song1 = song1
self.song2 = song2
self.__xAxisMax = 100
self.__xAxisMin = 0
def fade(self, xaxis):
assert(self.__xAxisMin <= xaxis <= self.__xAxisMax)
#could be any numbers you want.
#i chose 0-100 for convenience
self.song1.setVolume(xaxis)
self.song2.setVolume(self.__xAxisMax-xaxis)
song1 = Song('Song1.wav')
song2 = Song('Song2.wav')
fader = SongFader(song1, song2)
#Inside some event loop when you action is triggered
fader.fade(100) #Only song2 is playing
fader.fade(50) #Songs are evenly split
fader.fade(0) #Only left song is playing
线性插值可能是这里更重要的概念,所以我修改了推子类,灵感来自Eric的线程理念。
class SongFader(object):
def __init__(self, song1, song2):
self.song1 = song1
self.song2 = song2
self.lefttoright = False
self.starttime = 0
self.endtime = 0
def fade(self, starttime, fadeleft):
self.lefttoright = fadeleft == True #Being verbose here
self.starttime = starttime #assuming time is in millis
self.endtime = starttime + 1000
Thread(target = self.fadeHelper).start()
#this is where you define how the two songs are faded
def fadeHelper(self):
#if using thread, make sure you mutex the 'self.' variables
starttime = self.starttime
endtime = self.endtime
lefttoright = self.lefttoright
while starttime < endtime:
fadevalue = (starttime - endtime) / 1000 #a val between [0,1]
if lefttoright:
self.song1.setVolume(fadevalue)
self.song2.setVolume(1-fadevalue)
else:
self.song1.setVolume(1-fadevalue)
self.song2.setVolume(fadefalue)
starttime = getGameTimeFromSomewhere()
答案 3 :(得分:1)
试试这个,这很直接......
import pygame
pygame.mixer.init()
pygame.init()
# Maybe you can subclass the pygame.mixer.Sound and
# add the methods below to it..
class Fader(object):
instances = []
def __init__(self, fname):
super(Fader, self).__init__()
assert isinstance(fname, basestring)
self.sound = pygame.mixer.Sound(fname)
self.increment = 0.01 # tweak for speed of effect!!
self.next_vol = 1 # fade to 100 on start
Fader.instances.append(self)
def fade_to(self, new_vol):
# you could change the increment here based on something..
self.next_vol = new_vol
@classmethod
def update(cls):
for inst in cls.instances:
curr_volume = inst.sound.get_volume()
# print inst, curr_volume, inst.next_vol
if inst.next_vol > curr_volume:
inst.sound.set_volume(curr_volume + inst.increment)
elif inst.next_vol < curr_volume:
inst.sound.set_volume(curr_volume - inst.increment)
sound1 = Fader("1.wav")
sound2 = Fader("2.wav")
sound1.sound.play()
sound2.sound.play()
sound2.sound.set_volume(0)
# fading..
sound1.fade_to(0)
sound2.fade_to(1)
while True:
Fader.update() # a call that will update all the faders..