Fade Between Two Music Tracks in-progress in Pygame

前端 未结 4 1028
南方客
南方客 2020-12-31 11:50

My intention is to have two music tracks, which are similar in nature, fade between each other at various times. When such a fade occurs,

相关标签:
4条回答
  • 2020-12-31 12:20

    So it looks like what you want to do in pygame is create two 'Sound' objects, and create a linear interpolation on the volume between the two of them.

    I would create two vectors, each from [0,100], and relate them inversely with some constant. So when sound A is at 100, sound b is at 0. Then when an action occurs, you modify the constant.

    t=0
    A: [0 ... 100]
    B: [0 ... 100]

    t=1
    ACTION

    t=1.1
    A:[0 .. 50 .. 100]
    B:[0 .. 50 .. 100]

    t=2
    A:[0 ... 100]
    B:[0 ... 100]

    Now some code. I'm not familiar with pygame, but this should put you on the right track.

    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
    

    edit

    The linear interpolation is probably the more important concept here, so i have modified the fader class, with inspiration from Eric 's thread idea.

    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()
    
    0 讨论(0)
  • 2020-12-31 12:35

    This isn't exactly an answer to the question, but for future-googlers I wrote a script to fade-in my music from volume 0 in the morning and this is what I used:

    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")
    
    0 讨论(0)
  • 2020-12-31 12:37

    Pseudocode:

    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()
    
    0 讨论(0)
  • 2020-12-31 12:43

    Try this, it's pretty straight forward..

    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..
    
    0 讨论(0)
提交回复
热议问题