Затухание между двумя музыкальными треками продолжается в 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")