framework2
391 строка · 10.8 Кб
1#include "ofFmodSoundPlayer.h"2#ifdef OF_SOUND_PLAYER_FMOD3
4#include "ofUtils.h"5#include "ofMath.h"6#include "ofLog.h"7
8
9static bool bFmodInitialized_ = false;10static float fftInterpValues_[8192]; //11static float fftSpectrum_[8192]; // maximum #ofFmodSoundPlayer is 8192, in fmod....12static unsigned int buffersize = 1024;13static FMOD_DSP* fftDSP = NULL;14
15// --------------------- static vars
16static FMOD_CHANNELGROUP * channelgroup = NULL;17static FMOD_SYSTEM * sys = NULL;18
19// these are global functions, that affect every sound / channel:
20// ------------------------------------------------------------
21// ------------------------------------------------------------
22
23//--------------------
24void ofFmodSoundStopAll(){25ofFmodSoundPlayer::initializeFmod();26FMOD_ChannelGroup_Stop(channelgroup);27}
28
29//--------------------
30void ofFmodSoundSetVolume(float vol){31ofFmodSoundPlayer::initializeFmod();32FMOD_ChannelGroup_SetVolume(channelgroup, vol);33}
34
35//--------------------
36void ofFmodSoundUpdate(){37if (bFmodInitialized_){38FMOD_System_Update(sys);39}40}
41
42//--------------------
43float * ofFmodSoundGetSpectrum(int nBands){44
45ofFmodSoundPlayer::initializeFmod();46
47
48// set to 049for (int i = 0; i < 8192; i++){50fftInterpValues_[i] = 0;51fftSpectrum_[i] = 0;52}53
54// check what the user wants vs. what we can do:55if (nBands > 8192){56ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using maximum of 8192";57nBands = 8192;58} else if (nBands <= 0){59ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using minimum of 1";60nBands = 1;61return fftInterpValues_;62}63
64// get the fft65// useful info here: https://www.parallelcube.com/2018/03/10/frequency-spectrum-using-fmod-and-ue4/66if( fftDSP == NULL ){67FMOD_System_CreateDSPByType(sys, FMOD_DSP_TYPE_FFT,&fftDSP);68FMOD_ChannelGroup_AddDSP(channelgroup,0,fftDSP);69FMOD_DSP_SetParameterInt(fftDSP, FMOD_DSP_FFT_WINDOWTYPE, FMOD_DSP_FFT_WINDOW_HANNING);70}71
72if( fftDSP != NULL ){73FMOD_DSP_PARAMETER_FFT *fft;74auto result = FMOD_DSP_GetParameterData(fftDSP, FMOD_DSP_FFT_SPECTRUMDATA, (void **)&fft, 0, 0, 0);75if( result == 0 ){76
77// Only read / display half of the buffer typically for analysis78// as the 2nd half is usually the same data reversed due to the nature of the way FFT works. ( comment from link above )79int length = fft->length/2;80if( length > 0 ){81
82std::vector <float> avgValCount;83avgValCount.assign(nBands, 0.0);84
85float normalizedBand = 0;86float normStep = 1.0 / (float)length;87
88for (int bin = 0; bin < length; bin++){89//should map 0 to nBands but accounting for lower frequency bands being more important90int logIndexBand = log10(1.0 + normalizedBand*9.0) * nBands;91
92//get both channels as that is what the old FMOD call did93for (int channel = 0; channel < fft->numchannels; channel++){94fftSpectrum_[logIndexBand] += fft->spectrum[channel][bin];95avgValCount[logIndexBand] += 1.0;96}97
98normalizedBand += normStep;99}100
101//average the remapped bands based on how many times we added to each bin102for(int i = 0; i < nBands; i++){103if( avgValCount[i] > 1.0 ){104fftSpectrum_[i] /= avgValCount[i];105}106}107}108}109}110
111// convert to db scale112for(int i = 0; i < nBands; i++){113fftInterpValues_[i] = 10.0f * (float)log10(1 + fftSpectrum_[i]) * 2.0f;114}115
116return fftInterpValues_;117}
118
119void ofFmodSetBuffersize(unsigned int bs){120buffersize = bs;121}
122
123// ------------------------------------------------------------
124// ------------------------------------------------------------
125
126
127// now, the individual sound player:
128//------------------------------------------------------------
129ofFmodSoundPlayer::ofFmodSoundPlayer(){130bLoop = false;131bLoadedOk = false;132pan = 0.0; // range for oF is -1 to 1133volume = 1.0f;134internalFreq = 44100;135speed = 1;136bPaused = false;137isStreaming = false;138}
139
140ofFmodSoundPlayer::~ofFmodSoundPlayer(){141unload();142}
143
144
145
146//---------------------------------------
147// this should only be called once
148void ofFmodSoundPlayer::initializeFmod(){149if(!bFmodInitialized_){150
151FMOD_System_Create(&sys);152
153// set buffersize, keep number of buffers154unsigned int bsTmp;155int nbTmp;156FMOD_System_GetDSPBufferSize(sys, &bsTmp, &nbTmp);157FMOD_System_SetDSPBufferSize(sys, buffersize, nbTmp);158
159#ifdef TARGET_LINUX160FMOD_System_SetOutput(sys,FMOD_OUTPUTTYPE_ALSA);161#endif162FMOD_System_Init(sys, 512, FMOD_INIT_NORMAL, nullptr); //do we want just 512 channels?163FMOD_System_GetMasterChannelGroup(sys, &channelgroup);164bFmodInitialized_ = true;165}166}
167
168
169
170
171//---------------------------------------
172void ofFmodSoundPlayer::closeFmod(){173if(bFmodInitialized_){174FMOD_System_Close(sys);175bFmodInitialized_ = false;176}177}
178
179//------------------------------------------------------------
180bool ofFmodSoundPlayer::load(const of::filesystem::path& _fileName, bool stream){181
182auto fileName = ofToDataPath(_fileName);183
184// fmod uses IO posix internally, might have trouble185// with unicode paths...186// says this code:187// http://66.102.9.104/search?q=cache:LM47mq8hytwJ:www.cleeker.com/doxygen/audioengine__fmod_8cpp-source.html+FSOUND_Sample_Load+cpp&hl=en&ct=clnk&cd=18&client=firefox-a188// for now we use FMODs way, but we could switch if189// there are problems:190
191bMultiPlay = false;192
193// [1] init fmod, if necessary194
195initializeFmod();196
197// [2] try to unload any previously loaded sounds198// & prevent user-created memory leaks199// if they call "loadSound" repeatedly, for example200
201unload();202
203// [3] load sound204
205//choose if we want streaming206int fmodFlags = FMOD_DEFAULT;207if(stream)fmodFlags = FMOD_DEFAULT | FMOD_CREATESTREAM;208
209result = FMOD_System_CreateSound(sys, fileName.c_str(), fmodFlags, nullptr, &sound);210
211if (result != FMOD_OK){212bLoadedOk = false;213ofLogError("ofFmodSoundPlayer") << "loadSound(): could not load \"" << fileName << "\"";214} else {215bLoadedOk = true;216FMOD_Sound_GetLength(sound, &length, FMOD_TIMEUNIT_PCM);217isStreaming = stream;218}219
220return bLoadedOk;221}
222
223//------------------------------------------------------------
224void ofFmodSoundPlayer::unload(){225if (bLoadedOk){226stop(); // try to stop the sound227FMOD_Sound_Release(sound);228bLoadedOk = false;229}230}
231
232//------------------------------------------------------------
233bool ofFmodSoundPlayer::isPlaying() const{234
235if (!bLoadedOk) return false;236if(channel == NULL) return false;237int playing = 0;238FMOD_Channel_IsPlaying(channel, &playing);239return (playing != 0 ? true : false);240}
241
242//------------------------------------------------------------
243float ofFmodSoundPlayer::getSpeed() const{244return speed;245}
246
247//------------------------------------------------------------
248float ofFmodSoundPlayer::getPan() const{249return pan;250}
251
252//------------------------------------------------------------
253float ofFmodSoundPlayer::getVolume() const{254return volume;255}
256
257//------------------------------------------------------------
258bool ofFmodSoundPlayer::isLoaded() const{259return bLoadedOk;260}
261
262//------------------------------------------------------------
263void ofFmodSoundPlayer::setVolume(float vol){264if (isPlaying()){265FMOD_Channel_SetVolume(channel, vol);266}267volume = vol;268}
269
270//------------------------------------------------------------
271void ofFmodSoundPlayer::setPosition(float pct){272if (isPlaying()){273int sampleToBeAt = (int)(length * pct);274FMOD_Channel_SetPosition(channel, sampleToBeAt, FMOD_TIMEUNIT_PCM);275}276}
277
278void ofFmodSoundPlayer::setPositionMS(int ms) {279if (isPlaying()){280FMOD_Channel_SetPosition(channel, ms, FMOD_TIMEUNIT_MS);281}282}
283
284//------------------------------------------------------------
285float ofFmodSoundPlayer::getPosition() const{286if (isPlaying()){287unsigned int sampleImAt;288
289FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_PCM);290
291float pct = 0.0f;292if (length > 0){293pct = sampleImAt / (float)length;294}295return pct;296} else {297return 0;298}299}
300
301//------------------------------------------------------------
302int ofFmodSoundPlayer::getPositionMS() const{303if (isPlaying()){304unsigned int sampleImAt;305
306FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_MS);307
308return sampleImAt;309} else {310return 0;311}312}
313
314//------------------------------------------------------------
315void ofFmodSoundPlayer::setPan(float p){316pan = p;317p = ofClamp(p, -1, 1);318if (isPlaying()){319FMOD_Channel_SetPan(channel,p);320}321}
322
323
324//------------------------------------------------------------
325void ofFmodSoundPlayer::setPaused(bool bP){326if (isPlaying()){327FMOD_Channel_SetPaused(channel,bP);328bPaused = bP;329}330}
331
332
333//------------------------------------------------------------
334void ofFmodSoundPlayer::setSpeed(float spd){335if (isPlaying()){336FMOD_Channel_SetFrequency(channel, internalFreq * spd);337}338speed = spd;339}
340
341
342//------------------------------------------------------------
343void ofFmodSoundPlayer::setLoop(bool bLp){344if (isPlaying()){345FMOD_Channel_SetMode(channel, (bLp == true) ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);346}347bLoop = bLp;348}
349
350// ----------------------------------------------------------------------------
351void ofFmodSoundPlayer::setMultiPlay(bool bMp){352bMultiPlay = bMp; // be careful with this...353}
354
355// ----------------------------------------------------------------------------
356void ofFmodSoundPlayer::play(){357
358// if it's a looping sound, we should try to kill it, no?359// or else people will have orphan channels that are looping360if (bLoop == true){361FMOD_Channel_Stop(channel);362}363
364// if the sound is not set to multiplay, then stop the current,365// before we start another366if (!bMultiPlay){367FMOD_Channel_Stop(channel);368}369
370FMOD_System_PlaySound(sys, sound, channelgroup, bPaused, &channel);371
372FMOD_Channel_GetFrequency(channel, &internalFreq);373FMOD_Channel_SetVolume(channel,volume);374setPan(pan);375FMOD_Channel_SetFrequency(channel, internalFreq * speed);376FMOD_Channel_SetMode(channel, (bLoop == true) ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);377
378//fmod update() should be called every frame - according to the docs.379//we have been using fmod without calling it at all which resulted in channels not being able380//to be reused. we should have some sort of global update function but putting it here381//solves the channel bug382FMOD_System_Update(sys);383
384}
385
386// ----------------------------------------------------------------------------
387void ofFmodSoundPlayer::stop(){388FMOD_Channel_Stop(channel);389}
390
391#endif //OF_SOUND_PLAYER_FMOD392