framework2

Форк
0
391 строка · 10.8 Кб
1
#include "ofFmodSoundPlayer.h"
2
#ifdef OF_SOUND_PLAYER_FMOD
3

4
#include "ofUtils.h"
5
#include "ofMath.h"
6
#include "ofLog.h"
7

8

9
static bool bFmodInitialized_ = false;
10
static float fftInterpValues_[8192];			//
11
static float fftSpectrum_[8192];		// maximum #ofFmodSoundPlayer is 8192, in fmod....
12
static unsigned int buffersize = 1024;
13
static FMOD_DSP* fftDSP = NULL;
14

15
// ---------------------  static vars
16
static FMOD_CHANNELGROUP * channelgroup = NULL;
17
static FMOD_SYSTEM       * sys = NULL;
18

19
// these are global functions, that affect every sound / channel:
20
// ------------------------------------------------------------
21
// ------------------------------------------------------------
22

23
//--------------------
24
void ofFmodSoundStopAll(){
25
	ofFmodSoundPlayer::initializeFmod();
26
	FMOD_ChannelGroup_Stop(channelgroup);
27
}
28

29
//--------------------
30
void ofFmodSoundSetVolume(float vol){
31
	ofFmodSoundPlayer::initializeFmod();
32
	FMOD_ChannelGroup_SetVolume(channelgroup, vol);
33
}
34

35
//--------------------
36
void ofFmodSoundUpdate(){
37
	if (bFmodInitialized_){
38
		FMOD_System_Update(sys);
39
	}
40
}
41

42
//--------------------
43
float * ofFmodSoundGetSpectrum(int nBands){
44

45
	ofFmodSoundPlayer::initializeFmod();
46

47

48
	// 	set to 0
49
	for (int i = 0; i < 8192; i++){
50
		fftInterpValues_[i] = 0;
51
        fftSpectrum_[i] = 0;
52
	}
53

54
	// 	check what the user wants vs. what we can do:
55
	if (nBands > 8192){
56
		ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using maximum of 8192";
57
		nBands = 8192;
58
	} else if (nBands <= 0){
59
		ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using minimum of 1";
60
		nBands = 1;
61
		return fftInterpValues_;
62
	}
63

64
    //  get the fft
65
    //  useful info here: https://www.parallelcube.com/2018/03/10/frequency-spectrum-using-fmod-and-ue4/
66
    if( fftDSP == NULL ){
67
        FMOD_System_CreateDSPByType(sys, FMOD_DSP_TYPE_FFT,&fftDSP);
68
        FMOD_ChannelGroup_AddDSP(channelgroup,0,fftDSP);
69
        FMOD_DSP_SetParameterInt(fftDSP, FMOD_DSP_FFT_WINDOWTYPE, FMOD_DSP_FFT_WINDOW_HANNING);
70
    }
71
    
72
    if( fftDSP != NULL ){
73
        FMOD_DSP_PARAMETER_FFT *fft;
74
        auto result = FMOD_DSP_GetParameterData(fftDSP, FMOD_DSP_FFT_SPECTRUMDATA, (void **)&fft, 0, 0, 0);
75
        if( result == 0 ){
76
        
77
            // Only read / display half of the buffer typically for analysis
78
            // as the 2nd half is usually the same data reversed due to the nature of the way FFT works. ( comment from link above )
79
            int length = fft->length/2;
80
            if( length > 0 ){
81
        
82
                std::vector <float> avgValCount;
83
                avgValCount.assign(nBands, 0.0); 
84
                
85
                float normalizedBand = 0;
86
                float normStep = 1.0 / (float)length;
87
                
88
                for (int bin = 0; bin < length; bin++){
89
                    //should map 0 to nBands but accounting for lower frequency bands being more important
90
                    int logIndexBand = log10(1.0 + normalizedBand*9.0) * nBands;
91
                    
92
                    //get both channels as that is what the old FMOD call did
93
                    for (int channel = 0; channel < fft->numchannels; channel++){
94
                        fftSpectrum_[logIndexBand] += fft->spectrum[channel][bin];
95
                        avgValCount[logIndexBand] += 1.0;
96
                    }
97
                    
98
                    normalizedBand += normStep;
99
                }
100
                                
101
                //average the remapped bands based on how many times we added to each bin
102
                for(int i = 0; i < nBands; i++){
103
                    if( avgValCount[i] > 1.0 ){
104
                        fftSpectrum_[i] /= avgValCount[i];
105
                    }
106
                }
107
            }
108
        }
109
    }
110

111
	// 	convert to db scale
112
	for(int i = 0; i < nBands; i++){
113
        fftInterpValues_[i] = 10.0f * (float)log10(1 + fftSpectrum_[i]) * 2.0f;
114
	}
115

116
	return fftInterpValues_;
117
}
118

119
void ofFmodSetBuffersize(unsigned int bs){
120
	buffersize = bs;
121
}
122

123
// ------------------------------------------------------------
124
// ------------------------------------------------------------
125

126

127
// now, the individual sound player:
128
//------------------------------------------------------------
129
ofFmodSoundPlayer::ofFmodSoundPlayer(){
130
	bLoop 			= false;
131
	bLoadedOk 		= false;
132
	pan 			= 0.0; // range for oF is -1 to 1
133
	volume 			= 1.0f;
134
	internalFreq 	= 44100;
135
	speed 			= 1;
136
	bPaused 		= false;
137
	isStreaming		= false;
138
}
139

140
ofFmodSoundPlayer::~ofFmodSoundPlayer(){
141
	unload();
142
}
143

144

145

146
//---------------------------------------
147
// this should only be called once
148
void ofFmodSoundPlayer::initializeFmod(){
149
	if(!bFmodInitialized_){
150
		
151
		FMOD_System_Create(&sys);
152
		
153
		// set buffersize, keep number of buffers
154
		unsigned int bsTmp;
155
		int nbTmp;
156
		FMOD_System_GetDSPBufferSize(sys, &bsTmp, &nbTmp);
157
		FMOD_System_SetDSPBufferSize(sys, buffersize, nbTmp);
158

159
		#ifdef TARGET_LINUX
160
			FMOD_System_SetOutput(sys,FMOD_OUTPUTTYPE_ALSA);
161
		#endif
162
		FMOD_System_Init(sys, 512, FMOD_INIT_NORMAL, nullptr);  //do we want just 512 channels?
163
		FMOD_System_GetMasterChannelGroup(sys, &channelgroup);
164
		bFmodInitialized_ = true;
165
	}
166
}
167

168

169

170

171
//---------------------------------------
172
void ofFmodSoundPlayer::closeFmod(){
173
	if(bFmodInitialized_){
174
		FMOD_System_Close(sys);
175
		bFmodInitialized_ = false;
176
	}
177
}
178

179
//------------------------------------------------------------
180
bool ofFmodSoundPlayer::load(const of::filesystem::path& _fileName, bool stream){
181

182
	auto fileName = ofToDataPath(_fileName);
183

184
	// fmod uses IO posix internally, might have trouble
185
	// 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-a
188
	// for now we use FMODs way, but we could switch if
189
	// there are problems:
190

191
	bMultiPlay = false;
192

193
	// [1] init fmod, if necessary
194

195
	initializeFmod();
196

197
	// [2] try to unload any previously loaded sounds
198
	// & prevent user-created memory leaks
199
	// if they call "loadSound" repeatedly, for example
200

201
	unload();
202

203
	// [3] load sound
204

205
	//choose if we want streaming
206
	int fmodFlags =  FMOD_DEFAULT;
207
	if(stream)fmodFlags =  FMOD_DEFAULT | FMOD_CREATESTREAM;
208

209
    result = FMOD_System_CreateSound(sys, fileName.c_str(),  fmodFlags, nullptr, &sound);
210

211
	if (result != FMOD_OK){
212
		bLoadedOk = false;
213
		ofLogError("ofFmodSoundPlayer") << "loadSound(): could not load \"" << fileName << "\"";
214
	} else {
215
		bLoadedOk = true;
216
		FMOD_Sound_GetLength(sound, &length, FMOD_TIMEUNIT_PCM);
217
		isStreaming = stream;
218
	}
219

220
	return bLoadedOk;
221
}
222

223
//------------------------------------------------------------
224
void ofFmodSoundPlayer::unload(){
225
	if (bLoadedOk){
226
		stop();						// try to stop the sound
227
		FMOD_Sound_Release(sound);
228
		bLoadedOk = false;
229
	}
230
}
231

232
//------------------------------------------------------------
233
bool ofFmodSoundPlayer::isPlaying() const{
234

235
	if (!bLoadedOk) return false;
236
	if(channel == NULL) return false;
237
	int playing = 0;
238
	FMOD_Channel_IsPlaying(channel, &playing);
239
	return (playing != 0 ? true : false);
240
}
241

242
//------------------------------------------------------------
243
float ofFmodSoundPlayer::getSpeed() const{
244
	return speed;
245
}
246

247
//------------------------------------------------------------
248
float ofFmodSoundPlayer::getPan() const{
249
	return pan;
250
}
251

252
//------------------------------------------------------------
253
float ofFmodSoundPlayer::getVolume() const{
254
	return volume;
255
}
256

257
//------------------------------------------------------------
258
bool ofFmodSoundPlayer::isLoaded() const{
259
	return bLoadedOk;
260
}
261

262
//------------------------------------------------------------
263
void ofFmodSoundPlayer::setVolume(float vol){
264
	if (isPlaying()){
265
		FMOD_Channel_SetVolume(channel, vol);
266
	}
267
	volume = vol;
268
}
269

270
//------------------------------------------------------------
271
void ofFmodSoundPlayer::setPosition(float pct){
272
	if (isPlaying()){
273
		int sampleToBeAt = (int)(length * pct);
274
		FMOD_Channel_SetPosition(channel, sampleToBeAt, FMOD_TIMEUNIT_PCM);
275
	}
276
}
277

278
void ofFmodSoundPlayer::setPositionMS(int ms) {
279
	if (isPlaying()){
280
		FMOD_Channel_SetPosition(channel, ms, FMOD_TIMEUNIT_MS);
281
	}
282
}
283

284
//------------------------------------------------------------
285
float ofFmodSoundPlayer::getPosition() const{
286
	if (isPlaying()){
287
		unsigned int sampleImAt;
288

289
		FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_PCM);
290

291
		float pct = 0.0f;
292
		if (length > 0){
293
			pct = sampleImAt / (float)length;
294
		}
295
		return pct;
296
	} else {
297
		return 0;
298
	}
299
}
300

301
//------------------------------------------------------------
302
int ofFmodSoundPlayer::getPositionMS() const{
303
	if (isPlaying()){
304
		unsigned int sampleImAt;
305

306
		FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_MS);
307

308
		return sampleImAt;
309
	} else {
310
		return 0;
311
	}
312
}
313

314
//------------------------------------------------------------
315
void ofFmodSoundPlayer::setPan(float p){
316
	pan = p;
317
	p = ofClamp(p, -1, 1);
318
	if (isPlaying()){
319
		FMOD_Channel_SetPan(channel,p);
320
	}
321
}
322

323

324
//------------------------------------------------------------
325
void ofFmodSoundPlayer::setPaused(bool bP){
326
	if (isPlaying()){
327
		FMOD_Channel_SetPaused(channel,bP);
328
		bPaused = bP;
329
	}
330
}
331

332

333
//------------------------------------------------------------
334
void ofFmodSoundPlayer::setSpeed(float spd){
335
	if (isPlaying()){
336
			FMOD_Channel_SetFrequency(channel, internalFreq * spd);
337
	}
338
	speed = spd;
339
}
340

341

342
//------------------------------------------------------------
343
void ofFmodSoundPlayer::setLoop(bool bLp){
344
	if (isPlaying()){
345
		FMOD_Channel_SetMode(channel,  (bLp == true) ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
346
	}
347
	bLoop = bLp;
348
}
349

350
// ----------------------------------------------------------------------------
351
void ofFmodSoundPlayer::setMultiPlay(bool bMp){
352
	bMultiPlay = bMp;		// be careful with this...
353
}
354

355
// ----------------------------------------------------------------------------
356
void 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 looping
360
	if (bLoop == true){
361
		FMOD_Channel_Stop(channel);
362
	}
363

364
	// if the sound is not set to multiplay, then stop the current,
365
	// before we start another
366
	if (!bMultiPlay){
367
		FMOD_Channel_Stop(channel);
368
	}
369

370
	FMOD_System_PlaySound(sys, sound, channelgroup, bPaused, &channel);
371

372
	FMOD_Channel_GetFrequency(channel, &internalFreq);
373
	FMOD_Channel_SetVolume(channel,volume);
374
	setPan(pan);
375
	FMOD_Channel_SetFrequency(channel, internalFreq * speed);
376
	FMOD_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 able
380
	//to be reused.  we should have some sort of global update function but putting it here
381
	//solves the channel bug
382
	FMOD_System_Update(sys);
383

384
}
385

386
// ----------------------------------------------------------------------------
387
void ofFmodSoundPlayer::stop(){
388
	FMOD_Channel_Stop(channel);
389
}
390

391
#endif //OF_SOUND_PLAYER_FMOD
392

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.