1 /*
2  * Copyright (C) 2002 - David W. Durham
3  *
4  * This file is part of ReZound, an audio editing application.
5  *
6  * ReZound is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * ReZound is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  */
20 
21 #include "ASoundPlayer.h"
22 
23 #include <stdexcept>
24 #include <algorithm>
25 
26 #include <math.h>
27 
28 #include "CSound.h"
29 #include "CSoundPlayerChannel.h"
30 
31 #include "settings.h"
32 
33 #include "unit_conv.h"
34 
ASoundPlayer()35 ASoundPlayer::ASoundPlayer()
36 {
37 #ifdef HAVE_FFTW
38 	analyzerPlan=NULL;
39 #endif
40 }
41 
~ASoundPlayer()42 ASoundPlayer::~ASoundPlayer()
43 {
44 #ifdef HAVE_FFTW
45 	for(map<size_t,TAutoBuffer<fftw_real> *>::iterator i=hammingWindows.begin();i!=hammingWindows.end();i++)
46 		delete i->second;
47 #endif
48 }
49 
initialize()50 void ASoundPlayer::initialize()
51 {
52 	for(unsigned t=0;t<MAX_CHANNELS;t++)
53 	{
54 		maxRMSLevels[t]=peakLevels[t]=0;
55 		resetMaxRMSLevels[t]=resetPeakLevels[t]=false;
56 	}
57 	samplingForStereoPhaseMeters.setSize(gStereoPhaseMeterPointCount*devices[0].channelCount); // ??? only device zero
58 
59 	// only handling the first device ???
60 	for(unsigned t=0;t<devices[0].channelCount;t++)
61 		RMSLevelDetectors[t].setWindowTime(ms_to_samples(gMeterRMSWindowTime,devices[0].sampleRate));
62 
63 
64 
65 #ifdef HAVE_FFTW
66 	frequencyAnalysisBufferPrepared=false;
67 	for(size_t t=0;t<ASP_ANALYSIS_BUFFER_SIZE;t++)
68 		frequencyAnalysisBuffer[t]=0.0;
69 
70 	analyzerPlan = fftw_plan_r2r_1d(ASP_ANALYSIS_BUFFER_SIZE, frequencyAnalysisBuffer, data, FFTW_HC2R, FFTW_ESTIMATE);
71 
72 	// this causes calculateAnalyzerBandIndexRanges() to be called later when getting the analysis
73 	bandLowerIndexes.clear();
74 	bandUpperIndexes.clear();
75 #endif
76 }
77 
deinitialize()78 void ASoundPlayer::deinitialize()
79 {
80 	stopAll();
81 
82 #ifdef HAVE_FFTW
83 	if(analyzerPlan!=NULL)
84 	{
85 		fftw_destroy_plan(analyzerPlan);
86 		analyzerPlan=NULL;
87 	}
88 #endif
89 }
90 
newSoundPlayerChannel(CSound * sound)91 CSoundPlayerChannel *ASoundPlayer::newSoundPlayerChannel(CSound *sound)
92 {
93 	return(new CSoundPlayerChannel(this,sound));
94 }
95 
addSoundPlayerChannel(CSoundPlayerChannel * soundPlayerChannel)96 void ASoundPlayer::addSoundPlayerChannel(CSoundPlayerChannel *soundPlayerChannel)
97 {
98 	CMutexLocker ml(m);
99 	if(!soundPlayerChannels.insert(soundPlayerChannel).second)
100 		throw(runtime_error(string(__func__)+" -- sound player channel already in list"));
101 }
102 
removeSoundPlayerChannel(CSoundPlayerChannel * soundPlayerChannel)103 void ASoundPlayer::removeSoundPlayerChannel(CSoundPlayerChannel *soundPlayerChannel)
104 {
105 	CMutexLocker ml(m);
106 
107 	soundPlayerChannel->stop();
108 
109 	set<CSoundPlayerChannel *>::const_iterator i=soundPlayerChannels.find(soundPlayerChannel);
110 	if(i!=soundPlayerChannels.end())
111 		soundPlayerChannels.erase(i);
112 }
113 
mixSoundPlayerChannels(const unsigned nChannels,sample_t * const buffer,const size_t bufferSize)114 void ASoundPlayer::mixSoundPlayerChannels(const unsigned nChannels,sample_t * const buffer,const size_t bufferSize)
115 {
116 	memset(buffer,0,bufferSize*sizeof(*buffer)*nChannels);
117 
118 	// ??? it might be nice that if no sound player channel object is playing that this method would not return
119 	// so that the caller wouldn't eat any CPU time doing anything with the silence returned
120 
121 	{
122 		CMutexLocker ml(m);
123 		for(set<CSoundPlayerChannel *>::iterator i=soundPlayerChannels.begin();i!=soundPlayerChannels.end();i++)
124 			(*i)->mixOntoBuffer(nChannels,buffer,bufferSize);
125 	}
126 
127 
128 // ??? could just schedule this to occur (by making a copy of the buffer) the next time getLevel or getAnalysis is called rather than doing it here in the callback for mixing audio
129 	// calculate the peak levels and max RMS levels for this chunk
130 	if(gLevelMetersEnabled)
131 	{
132 		for(unsigned i=0;i<nChannels;i++)
133 		{
134 			size_t p=i;
135 			sample_t peak=resetPeakLevels[i] ? 0 : peakLevels[i];
136 			resetPeakLevels[i]=false;
137 			sample_t maxRMSLevel=resetMaxRMSLevels[i] ? 0 : maxRMSLevels[i];
138 			resetMaxRMSLevels[i]=false;
139 			for(size_t t=0;t<bufferSize;t++)
140 			{
141 				// m = max(m,abs(buffer[p]);
142 				sample_t s=buffer[p];
143 
144 				s= s<0 ? -s : s; // s=abs(s)
145 
146 				// peak=max(peak,s)
147 				if(peak<s)
148 					peak=s;
149 
150 				// update the RMS level detectors
151 				sample_t RMSLevel=RMSLevelDetectors[i].readLevel(s);
152 
153 				// RMSLevel=max(maxRMSLevel,RMSLevel)
154 				if(maxRMSLevel<RMSLevel)
155 					maxRMSLevel=RMSLevel;
156 
157 				p+=nChannels;
158 			}
159 
160 			maxRMSLevels[i]=maxRMSLevel;
161 			peakLevels[i]=peak;
162 		}
163 
164 		// set peak levels to zero for values above the current number of channels
165 		for(unsigned i=nChannels;i<MAX_CHANNELS;i++)
166 			peakLevels[i]=0;
167 	}
168 
169 	if(gStereoPhaseMetersEnabled)
170 		samplingForStereoPhaseMeters.write(buffer,bufferSize*nChannels, false); // NOTE: nChannels is supposed to equal devices[0].channelCount
171 
172 #ifdef HAVE_FFTW
173 	if(gFrequencyAnalyzerEnabled)
174 	{
175 		CMutexLocker l(frequencyAnalysisBufferMutex);
176 
177 		// put data into the frequency analysis buffer
178 		const size_t copyAmount=min((size_t)ASP_ANALYSIS_BUFFER_SIZE,(size_t)bufferSize); // only copy part of the output buffer (whichever is smaller)
179 
180 		// mix all the output channels onto the buffer (copying the first channel and adding the others
181 		size_t q=0;
182 		for(size_t t=0;t<copyAmount;t++)
183 		{
184 			frequencyAnalysisBuffer[t]=buffer[q];
185 			q+=nChannels;
186 		}
187 		for(size_t i=1;i<nChannels;i++)
188 		{
189 			q=i;
190 			for(size_t t=0;t<copyAmount;t++)
191 			{
192 				frequencyAnalysisBuffer[t]+=buffer[q];
193 				q+=nChannels;
194 			}
195 		}
196 
197 		// I would normalize and apply the Hamming window here, but I'll defer that until the call to getFrequencyAnalysis()
198 		frequencyAnalysisBufferPrepared=false;
199 		frequencyAnalysisBufferLength=copyAmount;
200 	}
201 #endif
202 
203 }
204 
stopAll()205 void ASoundPlayer::stopAll()
206 {
207 	CMutexLocker ml(m);
208 	for(set<CSoundPlayerChannel *>::iterator i=soundPlayerChannels.begin();i!=soundPlayerChannels.end();i++)
209 		(*i)->stop();
210 }
211 
getRMSLevel(unsigned channel) const212 const sample_t ASoundPlayer::getRMSLevel(unsigned channel) const
213 {
214 	if(!isInitialized())
215 		return 0;
216 
217 	//return RMSLevelDetectors[channel].readCurrentLevel();
218 	const sample_t r=maxRMSLevels[channel];
219 	resetMaxRMSLevels[channel]=true;
220 	return r;
221 }
222 
getPeakLevel(unsigned channel) const223 const sample_t ASoundPlayer::getPeakLevel(unsigned channel) const
224 {
225 	if(!isInitialized())
226 		return 0;
227 
228 	const sample_t p=peakLevels[channel];
229 	resetPeakLevels[channel]=true;
230 	return p;
231 }
232 
233 
getSamplingForStereoPhaseMeters(sample_t * buffer,size_t bufferSizeInSamples) const234 const size_t ASoundPlayer::getSamplingForStereoPhaseMeters(sample_t *buffer,size_t bufferSizeInSamples) const
235 {
236 	return samplingForStereoPhaseMeters.read(buffer,min(bufferSizeInSamples,(size_t)(gStereoPhaseMeterPointCount*devices[0].channelCount)), false)/devices[0].channelCount; // ??? only device zero
237 }
238 
239 #ifdef HAVE_FFTW
240 
241 // NOTE: when I say 'band', a band is expressed in terms of an
242 // octave (where octave is a real number) and each band is a
243 // multiple of deltaOctave (i.e when deltaOctave is 0.5, then
244 // the bands are defined as octaves: 0, 0.5, 1.0, 1.5, 2.0, 2.5, etc)
245 
246 // ??? these need to be settings in the registry and have enforced limits
247 static const float baseOctave=40;	// bottom frequency of analyzer  (actually the first band contains from 0Hz to upperFreqAtOctave(0) )
248 static const size_t octaveStride=6;	// 6 bands per octave
249 static const float deltaOctave=1.0f/octaveStride;
250 
251 // returns the frequency (in Hz) given the octave
freqAtOctave(float octave)252 static float freqAtOctave(float octave)
253 {
254 	return baseOctave*powf(2.0f,octave);
255 }
256 
257 // return middle of the previous band's frequency and our band's frequency
lowerFreqAtOctave(float octave)258 static float lowerFreqAtOctave(float octave)
259 {
260 	return (freqAtOctave(octave-deltaOctave)+freqAtOctave(octave))/2.0f;
261 }
262 
263 // return middle of the our band's frequency and the next band's frequency
upperFreqAtOctave(float octave)264 static float upperFreqAtOctave(float octave)
265 {
266 	return (freqAtOctave(octave)+freqAtOctave(octave+deltaOctave))/2.0f;
267 }
268 
269 // returns the index (into an frequency domain array) given a frequency (but doesn't always return an integer, it returns what index we would wish to be there (perhaps between two elements))
indexAtFreq(float freq,unsigned sampleRate)270 static float indexAtFreq(float freq,unsigned sampleRate)
271 {
272 	return (2.0f*(ASP_ANALYSIS_BUFFER_SIZE/2)*freq)/(float)sampleRate;
273 }
274 
275 // returns the (integer) lower index of the given band (expressed as an octave) into a frequency domain array
lowerIndexAtOctave(float octave,unsigned sampleRate)276 static size_t lowerIndexAtOctave(float octave,unsigned sampleRate)
277 {
278 	return (size_t)floor(indexAtFreq(lowerFreqAtOctave(octave),sampleRate));
279 }
280 
281 // returns the (integer) upper index of the given band (expressed as an octave) into a frequency domain array
upperIndexAtOctave(float octave,unsigned sampleRate)282 static size_t upperIndexAtOctave(float octave,unsigned sampleRate)
283 {
284 	return (size_t)(floor(indexAtFreq(upperFreqAtOctave(octave),sampleRate)));
285 }
286 
calculateAnalyzerBandIndexRanges() const287 void ASoundPlayer::calculateAnalyzerBandIndexRanges() const
288 {
289 	bandLowerIndexes.clear();
290 	bandUpperIndexes.clear();
291 
292 	float octave=0;
293 	while(freqAtOctave(octave)<(devices[0].sampleRate/2))
294 	{
295 		bandLowerIndexes.push_back(lowerIndexAtOctave(octave,devices[0].sampleRate));
296 		bandUpperIndexes.push_back(upperIndexAtOctave(octave,devices[0].sampleRate));
297 
298 		octave+=deltaOctave;
299 	}
300 	if(bandLowerIndexes.size()>0)
301 	{
302 		// make sure the first band includes the first element (but not actually 0Hz because that's just the DC offset)
303 		bandLowerIndexes[0]=1;
304 
305 		// make sure all the indexes are in range
306 		for(size_t t=0;t<bandUpperIndexes.size();t++)
307 		{
308 			bandLowerIndexes[t]=max((int)1,min((int)ASP_ANALYSIS_BUFFER_SIZE/2,(int)bandLowerIndexes[t]));
309 			bandUpperIndexes[t]=max((int)1,min((int)ASP_ANALYSIS_BUFFER_SIZE/2,(int)bandUpperIndexes[t]));
310 		}
311 	}
312 	else
313 	{
314 		// shouldn't happen, but if it does, do this to avoid calling this method over and over by adding soemthing to the vectors
315 		bandLowerIndexes.push_back(0);
316 		bandUpperIndexes.push_back(0);
317 	}
318 
319 	/*
320 	for(size_t t=0;t<bandLowerIndexes.size();t++)
321 		printf("%d .. %d\n",bandLowerIndexes[t],bandUpperIndexes[t]);
322 	*/
323 }
324 
createHammingWindow(size_t windowSize)325 TAutoBuffer<fftw_real> *ASoundPlayer::createHammingWindow(size_t windowSize)
326 {
327 //printf("creating for length %d\n",windowSize);
328 	TAutoBuffer<fftw_real> *h=new TAutoBuffer<fftw_real>(windowSize, true);
329 
330 	for(size_t t=0;t<windowSize;t++)
331 		(*h)[t]=0.54-0.46*cos(2.0*M_PI*t/windowSize);
332 
333 	return h;
334 }
335 
336 #endif
337 
338 
339 #include <stdlib.h>
getFrequencyAnalysis() const340 const vector<float> ASoundPlayer::getFrequencyAnalysis() const
341 {
342 	vector<float> v;
343 
344 	if(!isInitialized())
345 		return v;
346 
347 #ifdef HAVE_FFTW
348 	CMutexLocker l(frequencyAnalysisBufferMutex);
349 
350 	if(!frequencyAnalysisBufferPrepared)
351 	{
352 		// now divide by MAX_SAMPLE to normalize the values
353 		// and multiply by the Hamming window
354 		const fftw_real k=1.0/MAX_SAMPLE;
355 
356 		if(hammingWindows.find(frequencyAnalysisBufferLength)==hammingWindows.end())
357 			hammingWindows[frequencyAnalysisBufferLength]=createHammingWindow(frequencyAnalysisBufferLength);
358 		const fftw_real *hammingWindow=*(hammingWindows[frequencyAnalysisBufferLength]);
359 
360 		for(size_t t=0;t<frequencyAnalysisBufferLength;t++)
361 			frequencyAnalysisBuffer[t]*=k*hammingWindow[t];
362 
363 
364 		// in case bufferSize was less than ASP_ANALYSIS_BUFFER_SIZE pad the data with zeros
365 		for(size_t t=frequencyAnalysisBufferLength;t<ASP_ANALYSIS_BUFFER_SIZE;t++)
366 			frequencyAnalysisBuffer[t]=0.0;
367 
368 		frequencyAnalysisBufferPrepared=true;
369 	}
370 
371 /*
372 for(size_t t=0;t<ASP_ANALYSIS_BUFFER_SIZE;t++)
373 	((fftw_real *)frequencyAnalysisBuffer)[t]=((float)(rand()*2.0)/RAND_MAX)-1.0;
374 */
375 
376 	if(bandLowerIndexes.size()<=0) // calculate the index ranges for each band in the returned analysis since we haven't done it yet (I would do it on initialization, but I might not know the sampling rate at that point)
377 		calculateAnalyzerBandIndexRanges();
378 
379 
380 /*
381 for(int t=0;t<ASP_ANALYSIS_BUFFER_SIZE;t++)
382 {
383 	frequencyAnalysisBuffer[t]=sin(5.0*(t*M_PI*2.0/(ASP_ANALYSIS_BUFFER_SIZE)));
384 	frequencyAnalysisBuffer[t]+=0.5*sin(15.0*(t*M_PI*2.0/(ASP_ANALYSIS_BUFFER_SIZE)));
385 }
386 */
387 
388 	fftw_execute(analyzerPlan);
389 
390 	for(size_t t=0;t<bandLowerIndexes.size();t++)
391 	{
392 		const size_t l=bandLowerIndexes[t];
393 		const size_t u=bandUpperIndexes[t];
394 
395 		float sum=0;
396 		for(size_t i=l;i<u;i++)
397 		{
398 			const fftw_real re=data[i];
399 			const fftw_real im= (i==ASP_ANALYSIS_BUFFER_SIZE/2) ? 0 : data[ASP_ANALYSIS_BUFFER_SIZE-i];
400 
401 			const fftw_real power=sqrt(re*re+im*im)/(ASP_ANALYSIS_BUFFER_SIZE/2);
402 
403 			//sum+=power*power;
404 
405 			// find max magnitude of a frequency within band i
406 			if(sum<power)
407 				sum=power;
408 		}
409 		//sum/=(u-l);
410 		//sum=sqrt(sum);
411 		//v.push_back(sum);
412 
413 		v.push_back(sum);
414 	}
415 
416 #endif
417 
418 
419 #if 1
420 	// this enables the returned values to be averaged with the previous NUM_AVG-1 analysies
421 	#define NUM_AVG 2
422 	static vector<float> prevVs[NUM_AVG];
423 	static size_t currentPrevV=0;
424 
425 	// overwrite the oldest prev vector
426 	prevVs[currentPrevV]=v;
427 
428 	currentPrevV++;
429 	currentPrevV%=NUM_AVG;
430 
431 	vector<float> temp;
432 
433 	if(prevVs[NUM_AVG-1].size()>0)
434 	{
435 		// create initial values in temp
436 		temp=prevVs[0];
437 
438 		// add all over prev vectors to temp
439 		for(size_t i=1;i<NUM_AVG;i++)
440 		{
441 			for(size_t t=0;t<v.size();t++)
442 				temp[t]+=prevVs[i][t];
443 		}
444 
445 		// divide by number of sums for an average
446 		for(size_t t=0;t<v.size();t++)
447 			temp[t]/=NUM_AVG;
448 	}
449 
450 	return temp;
451 #else
452 	return v;
453 #endif
454 }
455 
getFrequency(size_t index) const456 const size_t ASoundPlayer::getFrequency(size_t index) const
457 {
458 #ifdef HAVE_FFTW
459 	return (size_t)freqAtOctave((float)index/(float)octaveStride);
460 #else
461 	return 0;
462 #endif
463 }
464 
getFrequencyAnalysisOctaveStride() const465 const size_t ASoundPlayer::getFrequencyAnalysisOctaveStride() const
466 {
467 #ifdef HAVE_FFTW
468 	return octaveStride;
469 #else
470 	return 1;
471 #endif
472 }
473 
474 
475 // ----------------------------
476 
477 #include <stdio.h> // just for fprintf
478 #include <vector>
479 #include <string>
480 
481 #include "CNULLSoundPlayer.h"
482 #include "COSSSoundPlayer.h"
483 #include "CALSASoundPlayer.h"
484 #include "CPortAudioSoundPlayer.h"
485 #include "CJACKSoundPlayer.h"
486 #include "CPulseSoundPlayer.h"
487 
488 #include "AStatusComm.h"
489 
490 #include <CNestedDataFile/CNestedDataFile.h>
491 
createInitializedSoundPlayer()492 ASoundPlayer *ASoundPlayer::createInitializedSoundPlayer()
493 {
494 	// if the registry doesn't already contain a methods setting, then create the default one
495 	if(gSettingsRegistry->keyExists("AudioOutputMethods")!=CNestedDataFile::ktValue)
496 	{
497 		vector<string> methods;
498 		methods.push_back("pulse");
499 		methods.push_back("oss");
500 		methods.push_back("alsa");
501 		methods.push_back("jack");
502 		methods.push_back("portaudio");
503 		gSettingsRegistry->setValue("AudioOutputMethods",methods);
504 	}
505 
506 
507 	bool initializeThrewException=false;
508 	ASoundPlayer *soundPlayer=NULL;
509 
510 	vector<string> methods=gSettingsRegistry->getValue<vector<string> >("AudioOutputMethods");
511 
512 	// add --audio-method=... to the beginning
513 	if(gDefaultAudioMethod!="")
514 		methods.insert(methods.begin(),gDefaultAudioMethod);
515 
516 	// try this as a last resort (it just holds the pointer place (so it's not NULL throughout the rest of the code) but it is written to fail to initialize
517 	methods.push_back("null");
518 
519 	// for each requested method in registry.AudioOutputMethods try each until one succeeds
520 	// 'suceeding' is true if the method was enabled at build time and it can initialize now at run-time
521 	for(size_t t=0;t<methods.size();t++)
522 	{
523 		const string method=methods[t];
524 		try
525 		{
526 #define INITIALIZE_PLAYER(ClassName)					\
527 			{						\
528 				initializeThrewException=false;		\
529 				delete soundPlayer;			\
530 				soundPlayer=new ClassName();		\
531 				soundPlayer->initialize();		\
532 				break; /* no exception thrown from initialize() so we're good to go */ \
533 			}
534 
535 			if(method=="oss")
536 			{
537 #ifdef ENABLE_OSS
538 				INITIALIZE_PLAYER(COSSSoundPlayer)
539 #endif
540 			}
541 			else if(method=="alsa")
542 			{
543 #ifdef ENABLE_ALSA
544 				INITIALIZE_PLAYER(CALSASoundPlayer)
545 #endif
546 			}
547 			else if(method=="jack")
548 			{
549 #ifdef ENABLE_JACK
550 				INITIALIZE_PLAYER(CJACKSoundPlayer)
551 #endif
552 			}
553 			else if(method=="portaudio")
554 			{
555 #ifdef ENABLE_PORTAUDIO
556 				INITIALIZE_PLAYER(CPortAudioSoundPlayer)
557 #endif
558 			}
559 			else if(method=="pulse")
560 			{
561 #ifdef ENABLE_PULSE
562 				INITIALIZE_PLAYER(CPulseSoundPlayer)
563 #endif
564 			}
565 			else if(method=="null")
566 			{
567 				INITIALIZE_PLAYER(CNULLSoundPlayer)
568 			}
569 			else
570 			{
571 				Warning("unhandled method type in the registry:AudioOutputMethods[] '"+method+"'");
572 				continue;
573 			}
574 		}
575 		catch(exception &e)
576 		{ // now really give up
577 			fprintf(stderr,"Error occurred while initializing audio output method '%s' -- %s\n",method.c_str(),e.what());
578 			initializeThrewException=true;
579 		}
580 	}
581 
582 	if(soundPlayer)
583 	{
584 		if(initializeThrewException)
585 			Error(_("No audio output method could be initialized -- Playing will be disabled."));
586 
587 		return soundPlayer;
588 	}
589 	else	/* ??? this should never happen anymore now with CNULLSoundPlayer */
590 		throw runtime_error(string(__func__)+" -- "+_("Either no audio output method was enabled at configure-time, or no method was recognized in the registry:AudioOutputMethods[] setting"));
591 }
592 
593