Panda3d 支持淡入淡出(Fading)的音频管理模块和类

嘛 因为需求音频的淡入淡出 但Panda3d默认不支持淡入淡出
于是就在Panda3d的基础上稍微写了一个支持淡入淡出的音频播放器模块
用了一些panda的Intervals,淡入淡出的效果还不错
还默认使用了loader后台读取的特性:)

from runtime_data import game_settings是窝的游戏设置,把相关的东西改成自己的后就可以直接用了!
AudioPlayer在Panda3D的ShowBase初始化之后再实例化即可

audio_player.py

#-*- coding:utf-8 -*-
'''
====================================================================================

   Copyright 2013, 2014 Windy Darian (大地无敌), Studio "Sekai no Kagami" 
   (世界之镜制作组) of Seven Ocean Game Arts (七海游戏文化社
   , 北京航空航天大学学生七海游戏文化社) @ http://sogarts.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================================
Created on Jul 29, 2013
Audio manager.
@author: Windy Darian (大地无敌)@ http://www.agrp.info 
'''
from panda3d.core import AudioSound,AudioManager
from direct.showbase.DirectObject import DirectObject
from direct.interval.LerpInterval import LerpFunc
from direct.interval.FunctionInterval import Func,Wait
from direct.interval.IntervalGlobal import Sequence
from direct.stdpy.file import exists    #use panda3d's file API to support panda's virtual folder

from runtime_data import game_settings    #spec for my game

_fadeinIntervalTable = {}
_intervals = []

def play_audio(audio,fadein = 0, volume = 1, loop = False):
    '''plays an AudioSound'''
    if loop:
        audio.setLoop(True)
    if not fadein:
        audio.setVolume(volume)
        audio.play()
    else:
        interval = LerpFunc(_lerpAdjust, duration = fadein,
                            fromData = 0, toData = volume,
                            extraArgs = , blendType = 'easeOut')
        _fadeinIntervalTable = interval   
        _intervals.append(interval)    
            #save the interval in the table so if the audio stops during the interval it can stop the interval first
        audio.play()
        interval.start()
        
    
def stop_audio(audio,fadeout = 0):
    '''stops an AudioSound, instant or fade-out'''
    if _fadeinIntervalTable.has_key(audio):     #If the audio is currently on fade-in, then stop and remove the fade-in interval
        _fadeinIntervalTable.pause()
        _intervals.remove(_fadeinIntervalTable)
        del _fadeinIntervalTable
           
    if not fadeout:
        audio.stop()
    else:
        sequence = Sequence(LerpFunc(_lerpAdjust, duration = fadeout,
                                     fromData = audio.getVolume(), toData = 0,
                                     extraArgs = , blendType = 'easeIn'),
                            Func(audio.stop)
                            )
        sequence.start()  #reduce volume and stop the sound
        
        
def play(filepath, manager, loop = False, fadein = 0, volume = 1):
    '''load a sound in background, and play it when loading finishes'''
    loader.loadSound(manager,
                     filepath,
                     callback = play_audio,extraArgs = [fadein, volume, loop])    
    

def _lerpAdjust(volume,audio):
    '''Adjust the volume dynamiclly in fadein and fadeout'''
    audio.setVolume(volume)
    
_bgmMgr = None
_envMgr = None
_voiceMgr = None
_sfxMgr = None

class AudioPlayer(DirectObject):
    
    '''Audio Player class of Sogal
    usually there only need 1 instance
    '''
    def __init__(self):
        DirectObject.__init__(self)
        
        global _bgmMgr,_envMgr,_sfxMgr,_voiceMgr    
        '''if we already has an AudioPlayer instance,
           we just need to refer to the existing AudioManagers
           insead of creating some new ones'''
        if not _bgmMgr:
            _bgmMgr = AudioManager.createAudioManager()          #don't use ShowBase.musicManager for it can only play 1 music at the same time defaultly so it don't support cross-fade
            base.addSfxManager(_bgmMgr)
        if not _envMgr:
            _envMgr = AudioManager.createAudioManager()
            base.addSfxManager(_envMgr)
        if not _voiceMgr:
            _voiceMgr = AudioManager.createAudioManager()
            base.addSfxManager(_voiceMgr)
        if not _sfxMgr:
            _sfxMgr = AudioManager.createAudioManager()
            base.addSfxManager(_sfxMgr)
            
        self.bgmMgr = _bgmMgr
        self.envMgr = _envMgr
        self.voiceMgr = _voiceMgr
        self.sfxMgr = _sfxMgr 
        
        self.applySettings()
        
        self._currentBGM = None #to define there can only be one bgm
        self._currentENV = None # and one environment sound at the same time
        
        '''#test1 Load and play a music
        loader.loadSound(self.bgmMgr,
                         'audio/music/God-only-knows-Secrets-of-the-Goddess-.wav',
                         callback = play_audio,extraArgs = [3,1])
        '''
        '''#test2 A fade-out stop before the fade-in is completed
        sound = loader.loadSound(self.bgmMgr,'audio/music/God-only-knows-Secrets-of-the-Goddess-.wav')
        sq = Sequence(Func(play_audio,sound,10),Wait(5),Func(stop_audio,sound,5))
        sq.start()
        '''
        '''#test3  Load and play a music
        self.playBGM('church-organ-music', 2, 1, True)
        '''
        '''#test4 Another music before the fade-in is completed
        sq = Sequence(Func(self.playBGM,'audio/music/God-only-knows-Secrets-of-the-Goddess-.wav',10),
                      Wait(5),
                      Func(self.playBGM,'audio/music/church-organ-music.wav',10),
                      )
        sq.start()
        '''
        
    def applySettings(self):
        self.bgmMgr.setVolume(game_settings['music_volume']) #0.75
        self.envMgr.setVolume(game_settings['env_volume']) #0.75
        self.voiceMgr.setVolume(game_settings['voice_volume']) #1
        self.sfxMgr.setVolume(game_settings['sfx_volume']) #1
        
        
    def playVoice(self, path, volume = 1):    
        pathes = game_settings['voicepathes']
        types = game_settings['soundtypes']
        for ft in ((folder,type) for folder in pathes for type in types):
            if exists(ft[0] + path + ft[1]):
                path = ft[0] + path + ft[1]
                break
        play(path, self.voiceMgr, volume = volume)
    
    def playSound(self, path, volume = 1):
        pathes = game_settings['sfxpathes']  #example: ['audio/music','audio','']
        types = game_settings['soundtypes']  #example: ['.wav','.ogg','']
        for ft in ((folder,type) for folder in pathes for type in types):
            if exists(ft[0] + path + ft[1]):
                path = ft[0] + path + ft[1]
                break
        play(path,self.sfxMgr, volume = volume)
        
    def playBGM(self, path, fadein = 0, volume = 1, loop = True):
        if self._currentBGM:    #if there is a music playing then stop it
            self.stopBGM(fadein)
        pathes = game_settings['musicpathes']
        types = game_settings['soundtypes']
        for ft in ((folder,type) for folder in pathes for type in types):
            if exists(ft[0] + path + ft[1]):
                path = ft[0] + path + ft[1]
                break
        loader.loadSound(self.bgmMgr,
                     path,
                     callback = self._setAndPlayBGM,extraArgs = [fadein, volume, loop])    
    
    def playENV(self, path, fadein = 0, volume = 1, loop = True):
        if self._currentENV:
            self.stopENV(fadein)
        pathes = game_settings['envsoundpathes']
        types = game_settings['soundtypes']
        for ft in ((folder,type) for folder in pathes for type in types):
            if exists(ft[0] + path + ft[1]):
                path = ft[0] + path + ft[1]
                break
        loader.loadSound(self.envMgr,
                     path,
                     callback = self._setAndPlayENV,extraArgs = [fadein, volume, loop]) 
        
    def stopBGM(self, fadeout = 0):
        if self._currentBGM:
            stop_audio(self._currentBGM, fadeout)
        
    def stopENV(self, fadeout = 0):
        if self._currentENV:
            stop_audio(self._currentENV, fadeout)
    
    def stopVoice(self):
        self.voiceMgr.stopAllSounds()
    
    def stopSound(self):
        self.sfxMgr.stopAllSounds()
    
    def _setAndPlayBGM(self, audio, fadein, volume, loop):
        self._currentBGM = audio
        play_audio(audio, fadein, volume, loop)
        
    def _setAndPlayENV(self, audio, fadein, volume, loop):
        self._currentENV = audio
        play_audio(audio, fadein, volume, loop)
        
    

        

……嘛继续填坑去

Leave a Reply

Your email address will not be published. Required fields are marked *