Затухание между двумя музыкальными треками продолжается в Pygame
Мое намерение состоит в том, чтобы две музыкальные треки, похожие по своей природе, исчезают между собой в разное время. Когда происходит такое затухание, одна музыкальная дорожка должна исчезнуть из полной громкости, чтобы отключить ее в течение короткого периода времени, и одновременно другая дорожка должна исчезнуть с 0 до 100 и продолжить воспроизведение с тем же индексом времени. Они должны иметь возможность делать это динамически в любое время - когда произойдет определенное действие, произойдет затухание и новый трек начнет воспроизводиться в той же позиции, что другой один остановился на.
Это может быть правдоподобно либо с помощью манипуляции томом, либо путем запуска и остановки музыки (однако, похоже, что существует только опция "fadeout", и отсутствует опция "fadein" ). Как я могу это сделать? Какой лучший метод, если таковой существует, существует? Если это невозможно с помощью Pygame, альтернативы Pygame приемлемы.
Ответы
Ответ 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..
Ответ 2
псевдокод:
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()
Ответ 3
Итак, похоже, что вы хотите сделать в pygame, создайте два объекта "Sound" и создайте линейную интерполяцию на томе между ними.
Я бы создал два вектора, каждый из которых был [0,100], и связал их обратно с некоторой константой.
Поэтому, когда звук A равен 100, звук b равен 0. Затем, когда действие происходит, вы изменяете константу.
т = 0
A: [0... 100]
B: [ 0... 100]
т = 1
ДЕЙСТВИЯ
т = 1,1
A: [0.. 50.. 100]
B: [0.. 50.. 100]
т = 2
A: [ 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()
Ответ 4
Это не совсем ответ на вопрос, но для будущих гуглеров я написал script для того, чтобы угасать мою музыку с тома 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")