framework2
1079 строк · 31.6 Кб
1#include "ofOpenALSoundPlayer.h"2
3#ifdef OF_SOUND_PLAYER_OPENAL4
5#define GLM_FORCE_CTOR_INIT6#include <glm/gtc/constants.hpp>7#include "glm/common.hpp"8#include "ofLog.h"9#include "ofEvents.h"10
11#if defined (TARGET_OF_IOS) || defined (TARGET_OSX)12#include <OpenAL/al.h>13#include <OpenAL/alc.h>14#else15#include <AL/al.h>16#include <AL/alc.h>17#endif18
19#ifdef OF_USING_MPG12320#include <mpg123.h>21#endif22
23static ALCdevice * alDevice = nullptr;24static ALCcontext * alContext = nullptr;25std::vector<float> ofOpenALSoundPlayer::window;26float ofOpenALSoundPlayer::windowSum = 0.f;27
28
29kiss_fftr_cfg ofOpenALSoundPlayer::systemFftCfg=0;30std::vector<float> ofOpenALSoundPlayer::systemWindowedSignal;31std::vector<float> ofOpenALSoundPlayer::systemBins;32std::vector<kiss_fft_cpx> ofOpenALSoundPlayer::systemCx_out;33
34static std::set<ofOpenALSoundPlayer*> & players(){35static std::set<ofOpenALSoundPlayer*> * players = new std::set<ofOpenALSoundPlayer*>;36return *players;37}
38
39void ofOpenALSoundUpdate(){40alcProcessContext(alContext);41}
42
43// ----------------------------------------------------------------------------
44// from http://devmaster.net/posts/2893/openal-lesson-6-advanced-loading-and-error-handles
45static std::string getALErrorString(ALenum error) {46switch(error) {47case AL_NO_ERROR:48return "AL_NO_ERROR";49case AL_INVALID_NAME:50return "AL_INVALID_NAME";51case AL_INVALID_ENUM:52return "AL_INVALID_ENUM";53case AL_INVALID_VALUE:54return "AL_INVALID_VALUE";55case AL_INVALID_OPERATION:56return "AL_INVALID_OPERATION";57case AL_OUT_OF_MEMORY:58return "AL_OUT_OF_MEMORY";59};60return "UNKWOWN_ERROR";61}
62
63static std::string getALCErrorString(ALCenum error) {64switch(error) {65case ALC_NO_ERROR:66return "ALC_NO_ERROR";67case ALC_INVALID_DEVICE:68return "ALC_INVALID_DEVICE";69case ALC_INVALID_CONTEXT:70return "ALC_INVALID_CONTEXT";71case ALC_INVALID_ENUM:72return "ALC_INVALID_ENUM";73case ALC_INVALID_VALUE:74return "ALC_INVALID_VALUE";75case ALC_OUT_OF_MEMORY:76return "ALC_OUT_OF_MEMORY";77};78return "UNKWOWN_ERROR";79}
80
81#ifdef OF_USING_MPG12382static std::string getMpg123EncodingString(int encoding) {83switch(encoding) {84case MPG123_ENC_16:85return "MPG123_ENC_16";86#if MPG123_API_VERSION>=3687case MPG123_ENC_24:88return "MPG123_ENC_24";89#endif90case MPG123_ENC_32:91return "MPG123_ENC_32";92case MPG123_ENC_8:93return "MPG123_ENC_8";94case MPG123_ENC_ALAW_8:95return "MPG123_ENC_ALAW_8";96case MPG123_ENC_FLOAT:97return "MPG123_ENC_FLOAT";98case MPG123_ENC_FLOAT_32:99return "MPG123_ENC_FLOAT_32";100case MPG123_ENC_FLOAT_64:101return "MPG123_ENC_FLOAT_64";102case MPG123_ENC_SIGNED:103return "MPG123_ENC_SIGNED";104case MPG123_ENC_SIGNED_16:105return "MPG123_ENC_SIGNED_16";106#if MPG123_API_VERSION>=36107case MPG123_ENC_SIGNED_24:108return "MPG123_ENC_SIGNED_24";109#endif110case MPG123_ENC_SIGNED_32:111return "MPG123_ENC_SIGNED_32";112case MPG123_ENC_SIGNED_8:113return "MPG123_ENC_SIGNED_8";114case MPG123_ENC_ULAW_8:115return "MPG123_ENC_ULAW_8";116case MPG123_ENC_UNSIGNED_16:117return "MPG123_ENC_UNSIGNED_16";118#if MPG123_API_VERSION>=36119case MPG123_ENC_UNSIGNED_24:120return "MPG123_ENC_UNSIGNED_24";121#endif122case MPG123_ENC_UNSIGNED_32:123return "MPG123_ENC_UNSIGNED_32";124case MPG123_ENC_UNSIGNED_8:125return "MPG123_ENC_UNSIGNED_8";126default:127return "MPG123_ENC_ANY";128}129}
130#endif131
132#define BUFFER_STREAM_SIZE 4096133
134// now, the individual sound player:
135//------------------------------------------------------------
136ofOpenALSoundPlayer::ofOpenALSoundPlayer(){137bLoop = false;138bLoadedOk = false;139pan = 0.0f; // range for oF is -1 to 1,140volume = 1.0f;141internalFreq = 44100;142speed = 1;143bPaused = false;144isStreaming = false;145channels = 0;146duration = 0;147fftCfg = 0;148streamf = 0;149#ifdef OF_USING_MPG123150mp3streamf = 0;151#endif152players().insert(this);153}
154
155// ----------------------------------------------------------------------------
156ofOpenALSoundPlayer::~ofOpenALSoundPlayer(){157unload();158kiss_fftr_free(fftCfg);159players().erase(this);160if( players().empty() ){161close();162}163}
164
165//---------------------------------------
166// this should only be called once
167void ofOpenALSoundPlayer::initialize(){168if( !alDevice ){169alDevice = alcOpenDevice( nullptr );170if( !alDevice ){171ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't open OpenAL default device";172return;173}else{174ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): opening "<< alcGetString( alDevice, ALC_DEVICE_SPECIFIER );175}176// Create OpenAL context and make it current. If fails, close the OpenAL device that was just opened.177alContext = alcCreateContext( alDevice, nullptr );178if( !alContext ){179ALCenum err = alcGetError( alDevice );180ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not create OpenAL context: "<< getALCErrorString( err );181close();182return;183}184
185if( alcMakeContextCurrent( alContext )==ALC_FALSE ){186ALCenum err = alcGetError( alDevice );187ofLogError("ofOpenALSoundPlayer") << "initialize(): couldn't not make current the create OpenAL context: "<< getALCErrorString( err );188close();189return;190};191alListener3f( AL_POSITION, 0,0,0 );192#ifdef OF_USING_MPG123193mpg123_init();194#endif195
196}197ofLogVerbose("ofOpenALSoundPlayer") << "initialize(): Done";198}
199
200//---------------------------------------
201void ofOpenALSoundPlayer::createWindow(int size){202if(int(window.size())!=size){203windowSum = 0;204window.resize(size);205// hanning window206for(int i = 0; i < size; i++){207window[i] = .54 - .46 * cos((glm::two_pi<float>() * i) / (size - 1));208windowSum += window[i];209}210}211}
212
213//---------------------------------------
214void ofOpenALSoundPlayer::close(){215// Destroy the OpenAL context (if any) before closing the device216if( alDevice ){217if( alContext ){218#ifdef OF_USING_MPG123219mpg123_exit();220#endif221alcMakeContextCurrent(nullptr);222alcDestroyContext(alContext);223alContext = nullptr;224}225if( alcCloseDevice( alDevice )==ALC_FALSE ){226ofLogNotice("ofOpenALSoundPlayer") << "initialize(): error closing OpenAL device";227}228alDevice = nullptr;229}230}
231
232// ----------------------------------------------------------------------------
233bool ofOpenALSoundPlayer::sfReadFile(const of::filesystem::path& path, std::vector<short> & buffer, std::vector<float> & fftAuxBuffer){234SF_INFO sfInfo;235SNDFILE* f = sf_open(path.string().c_str(),SFM_READ,&sfInfo);236if(!f){237ofLogError("ofOpenALSoundPlayer") << "sfReadFile(): couldn't read \"" << path << "\"";238return false;239}240
241buffer.resize(sfInfo.frames*sfInfo.channels);242fftAuxBuffer.resize(sfInfo.frames*sfInfo.channels);243
244int subformat = sfInfo.format & SF_FORMAT_SUBMASK ;245if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE){246double scale ;247sf_command (f, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ;248if (scale < 1e-10)249scale = 1.0 ;250else251scale = 32700.0 / scale ;252
253sf_count_t samples_read = sf_read_float (f, &fftAuxBuffer[0], fftAuxBuffer.size());254if(samples_read<(int)fftAuxBuffer.size()){255ofLogWarning("ofOpenALSoundPlayer") << "sfReadFile(): read " << samples_read << " float samples, expected "256<< fftAuxBuffer.size() << " for \"" << path << "\"";257}258for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){259fftAuxBuffer[i] *= scale ;260buffer[i] = 32565.0 * fftAuxBuffer[i];261}262}else{263sf_count_t frames_read = sf_readf_short(f,&buffer[0],sfInfo.frames);264if(frames_read<sfInfo.frames){265ofLogError("ofOpenALSoundPlayer") << "sfReadFile(): read " << frames_read << " frames from buffer, expected "266<< sfInfo.frames << " for \"" << path << "\"";267return false;268}269sf_seek(f,0,SEEK_SET);270frames_read = sf_readf_float(f,&fftAuxBuffer[0],sfInfo.frames);271if(frames_read<sfInfo.frames){272ofLogError("ofOpenALSoundPlayer") << "sfReadFile(): read " << frames_read << " frames from fft buffer, expected "273<< sfInfo.frames << " for \"" << path << "\"";274return false;275}276}277sf_close(f);278
279channels = sfInfo.channels;280duration = float(sfInfo.frames) / float(sfInfo.samplerate);281samplerate = sfInfo.samplerate;282return true;283}
284
285#ifdef OF_USING_MPG123286//------------------------------------------------------------
287bool ofOpenALSoundPlayer::mpg123ReadFile(const of::filesystem::path& path,std::vector<short> & buffer,std::vector<float> & fftAuxBuffer){288int err = MPG123_OK;289mpg123_handle * f = mpg123_new(nullptr,&err);290if(mpg123_open(f,path.string().c_str())!=MPG123_OK){291ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): couldn't read \"" << path << "\"";292return false;293}294
295mpg123_enc_enum encoding;296long int rate;297mpg123_getformat(f,&rate,&channels,(int*)&encoding);298if(encoding!=MPG123_ENC_SIGNED_16){299ofLogError("ofOpenALSoundPlayer") << "mpg123ReadFile(): " << getMpg123EncodingString(encoding)300<< " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16";301return false;302}303samplerate = rate;304
305size_t done=0;306size_t buffer_size = mpg123_outblock( f );307buffer.resize(buffer_size/2);308while(mpg123_read(f,(unsigned char*)&buffer[buffer.size()-buffer_size/2],buffer_size,&done)!=MPG123_DONE){309buffer.resize(buffer.size()+buffer_size/2);310};311buffer.resize(buffer.size()-(buffer_size/2-done/2));312mpg123_close(f);313mpg123_delete(f);314
315fftAuxBuffer.resize(buffer.size());316for(int i=0;i<(int)buffer.size();i++){317fftAuxBuffer[i] = float(buffer[i])/32565.f;318}319duration = float(buffer.size()/channels) / float(samplerate);320return true;321}
322#endif323
324//------------------------------------------------------------
325bool ofOpenALSoundPlayer::sfStream(const of::filesystem::path& path,std::vector<short> & buffer,std::vector<float> & fftAuxBuffer){326if(!streamf){327SF_INFO sfInfo;328streamf = sf_open(path.string().c_str(),SFM_READ,&sfInfo);329if(!streamf){330ofLogError("ofOpenALSoundPlayer") << "sfStream(): couldn't read \"" << path << "\"";331return false;332}333
334stream_subformat = sfInfo.format & SF_FORMAT_SUBMASK ;335if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){336sf_command (streamf, SFC_CALC_SIGNAL_MAX, &stream_scale, sizeof (stream_scale)) ;337if (stream_scale < 1e-10)338stream_scale = 1.0 ;339else340stream_scale = 32700.0 / stream_scale ;341}342channels = sfInfo.channels;343duration = float(sfInfo.frames) / float(sfInfo.samplerate);344samplerate = sfInfo.samplerate;345stream_samples_read = 0;346}347
348int curr_buffer_size = BUFFER_STREAM_SIZE*channels;349if(speed>1) curr_buffer_size *= (int)round(speed);350buffer.resize(curr_buffer_size);351fftAuxBuffer.resize(buffer.size());352if (stream_subformat == SF_FORMAT_FLOAT || stream_subformat == SF_FORMAT_DOUBLE){353sf_count_t samples_read = sf_read_float (streamf, &fftAuxBuffer[0], fftAuxBuffer.size());354stream_samples_read += samples_read;355if(samples_read<(int)fftAuxBuffer.size()){356fftAuxBuffer.resize(samples_read);357buffer.resize(samples_read);358setPosition(0);359if(!bLoop) stopThread();360stream_samples_read = 0;361stream_end = true;362}363for (int i = 0 ; i < int(fftAuxBuffer.size()) ; i++){364fftAuxBuffer[i] *= stream_scale ;365buffer[i] = 32565.0 * fftAuxBuffer[i];366}367}else{368sf_count_t frames_read = sf_readf_short(streamf,&buffer[0],curr_buffer_size/channels);369stream_samples_read += frames_read*channels;370if(frames_read<curr_buffer_size/channels){371fftAuxBuffer.resize(frames_read*channels);372buffer.resize(frames_read*channels);373setPosition(0);374if(!bLoop) stopThread();375stream_samples_read = 0;376stream_end = true;377}378for(int i=0;i<(int)buffer.size();i++){379fftAuxBuffer[i]=float(buffer[i])/32565.0f;380}381}382
383return true;384}
385
386#ifdef OF_USING_MPG123387//------------------------------------------------------------
388bool ofOpenALSoundPlayer::mpg123Stream(const of::filesystem::path& path,std::vector<short> & buffer,std::vector<float> & fftAuxBuffer){389if(!mp3streamf){390int err = MPG123_OK;391mp3streamf = mpg123_new(nullptr,&err);392if(mpg123_open(mp3streamf,path.string().c_str())!=MPG123_OK){393mpg123_close(mp3streamf);394mpg123_delete(mp3streamf);395ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): couldn't read \"" << path << "\"";396return false;397}398
399long int rate;400mpg123_getformat(mp3streamf,&rate,&channels,(int*)&stream_encoding);401if(stream_encoding!=MPG123_ENC_SIGNED_16){402ofLogError("ofOpenALSoundPlayer") << "mpg123Stream(): " << getMpg123EncodingString(stream_encoding)403<< " encoding for \"" << path << "\"" << " unsupported, expecting MPG123_ENC_SIGNED_16";404return false;405}406samplerate = rate;407mp3_buffer_size = mpg123_outblock( mp3streamf );408
409
410mpg123_seek(mp3streamf,0,SEEK_END);411off_t samples = mpg123_tell(mp3streamf);412duration = float(samples/channels) / float(samplerate);413mpg123_seek(mp3streamf,0,SEEK_SET);414}415
416int curr_buffer_size = mp3_buffer_size;417if(speed>1) curr_buffer_size *= (int)round(speed);418buffer.resize(curr_buffer_size);419fftAuxBuffer.resize(buffer.size());420size_t done=0;421if(mpg123_read(mp3streamf,(unsigned char*)&buffer[0],curr_buffer_size*2,&done)==MPG123_DONE){422setPosition(0);423buffer.resize(done/2);424fftAuxBuffer.resize(done/2);425if(!bLoop) stopThread();426stream_end = true;427}428
429
430for(int i=0;i<(int)buffer.size();i++){431fftAuxBuffer[i] = float(buffer[i])/32565.f;432}433
434return true;435}
436#endif437
438//------------------------------------------------------------
439bool ofOpenALSoundPlayer::stream(const of::filesystem::path& fileName, std::vector<short> & buffer){440#ifdef OF_USING_MPG123441if(ofFilePath::getFileExt(fileName)=="mp3" || ofFilePath::getFileExt(fileName)=="MP3" || mp3streamf){442if(!mpg123Stream(fileName,buffer,fftAuxBuffer)) return false;443}else444#endif445if(!sfStream(fileName,buffer,fftAuxBuffer)) return false;446
447fftBuffers.resize(channels);448int numFrames = buffer.size()/channels;449
450for(int i=0;i<channels;i++){451fftBuffers[i].resize(numFrames);452for(int j=0;j<numFrames;j++){453fftBuffers[i][j] = fftAuxBuffer[j*channels+i];454}455}456return true;457}
458
459bool ofOpenALSoundPlayer::readFile(const of::filesystem::path& fileName, std::vector<short> & buffer){460#ifdef OF_USING_MPG123461if(ofFilePath::getFileExt(fileName)!="mp3" && ofFilePath::getFileExt(fileName)!="MP3"){462if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false;463}else{464if(!mpg123ReadFile(fileName,buffer,fftAuxBuffer)) return false;465}466#else467if(!sfReadFile(fileName,buffer,fftAuxBuffer)) return false;468#endif469fftBuffers.resize(channels);470int numFrames = buffer.size()/channels;471
472for(int i=0;i<channels;i++){473fftBuffers[i].resize(numFrames);474for(int j=0;j<numFrames;j++){475fftBuffers[i][j] = fftAuxBuffer[j*channels+i];476}477}478return true;479}
480
481//------------------------------------------------------------
482bool ofOpenALSoundPlayer::load(const of::filesystem::path& _fileName, bool is_stream){483
484auto fileName = ofToDataPath(_fileName);485
486bMultiPlay = false;487isStreaming = is_stream;488int err = AL_NO_ERROR;489
490// [1] init sound systems, if necessary491initialize();492
493// [2] try to unload any previously loaded sounds494// & prevent user-created memory leaks495// if they call "loadSound" repeatedly, for example496
497unload();498ALenum format=AL_FORMAT_MONO16;499bLoadedOk = false;500
501if(!isStreaming){502bLoadedOk = readFile(fileName, buffer);503}else{504bLoadedOk = stream(fileName, buffer);505}506if( !bLoadedOk ) {507ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't read \"" << fileName << "\"";508return false;509}510
511int numFrames = buffer.size()/channels;512
513if(isStreaming){514buffers.resize(channels*2);515}else{516buffers.resize(channels);517}518alGenBuffers(buffers.size(), &buffers[0]);519if(channels==1){520sources.resize(1);521alGetError(); // Clear error.522alGenSources(1, &sources[0]);523err = alGetError();524if (err != AL_NO_ERROR){525ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't generate source for \"" << fileName << "\": "526<< (int) err << " " << getALErrorString(err);527return false;528}529
530for(int i=0; i<(int)buffers.size(); i++){531alGetError(); // Clear error.532alBufferData(buffers[i],format,&buffer[0],buffer.size()*2,samplerate);533err = alGetError();534if (err != AL_NO_ERROR){535ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't create buffer for \"" << fileName << "\": "536<< (int) err << " " << getALErrorString(err);537return false;538}539if(isStreaming){540stream(fileName,buffer);541}542}543if(isStreaming){544alSourceQueueBuffers(sources[0],buffers.size(),&buffers[0]);545}else{546alSourcei (sources[0], AL_BUFFER, buffers[0]);547}548
549alSourcef (sources[0], AL_PITCH, 1.0f);550alSourcef (sources[0], AL_GAIN, 1.0f);551alSourcef (sources[0], AL_ROLLOFF_FACTOR, 0.0);552alSourcei (sources[0], AL_SOURCE_RELATIVE, AL_TRUE);553}else{554std::vector<std::vector<short> > multibuffer;555multibuffer.resize(channels);556sources.resize(channels);557alGenSources(channels, &sources[0]);558if(isStreaming){559for(int s=0; s<2;s++){560for(int i=0;i<channels;i++){561multibuffer[i].resize(buffer.size()/channels);562for(int j=0;j<numFrames;j++){563multibuffer[i][j] = buffer[j*channels+i];564}565alGetError(); // Clear error.566alBufferData(buffers[s*2+i],format,&multibuffer[i][0],buffer.size()/channels*2,samplerate);567err = alGetError();568if ( err != AL_NO_ERROR){569ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't create stereo buffers for \"" << fileName << "\": " << (int) err << " " << getALErrorString(err);570return false;571}572alSourceQueueBuffers(sources[i],1,&buffers[s*2+i]);573stream(fileName,buffer);574}575}576}else{577for(int i=0;i<channels;i++){578multibuffer[i].resize(buffer.size()/channels);579for(int j=0;j<numFrames;j++){580multibuffer[i][j] = buffer[j*channels+i];581}582alGetError(); // Clear error.583alBufferData(buffers[i],format,&multibuffer[i][0],buffer.size()/channels*2,samplerate);584err = alGetError();585if (err != AL_NO_ERROR){586ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't create stereo buffers for \"" << fileName << "\": "587<< (int) err << " " << getALErrorString(err);588return false;589}590alSourcei (sources[i], AL_BUFFER, buffers[i] );591}592}593
594
595for(int i=0;i<channels;i++){596err = alGetError();597if (err != AL_NO_ERROR){598ofLogError("ofOpenALSoundPlayer") << "loadSound(): couldn't create stereo sources for \"" << fileName << "\": "599<< (int) err << " " << getALErrorString(err);600return false;601}602
603// only stereo panning604if(i==0){605float pos[3] = {-1,0,0};606alSourcefv(sources[i],AL_POSITION,pos);607}else{608float pos[3] = {1,0,0};609alSourcefv(sources[i],AL_POSITION,pos);610}611alSourcef (sources[i], AL_ROLLOFF_FACTOR, 0.0);612alSourcei (sources[i], AL_SOURCE_RELATIVE, AL_TRUE);613}614}615
616bLoadedOk = true;617return bLoadedOk;618
619}
620
621//------------------------------------------------------------
622bool ofOpenALSoundPlayer::isLoaded() const{623return bLoadedOk;624}
625
626//------------------------------------------------------------
627void ofOpenALSoundPlayer::threadedFunction(){628std::vector<std::vector<short> > multibuffer;629multibuffer.resize(channels);630while(isThreadRunning()){631std::unique_lock<std::mutex> lock(mutex);632for(int i=0; i<int(sources.size())/channels; i++){633int processed;634alGetSourcei(sources[i*channels], AL_BUFFERS_PROCESSED, &processed);635
636while(processed--)637{638stream("",buffer);639int numFrames = buffer.size()/channels;640if(channels>1){641for(int j=0;j<channels;j++){642multibuffer[j].resize(buffer.size()/channels);643for(int k=0;k<numFrames;k++){644multibuffer[j][k] = buffer[k*channels+j];645}646ALuint albuffer;647alSourceUnqueueBuffers(sources[i*channels+j], 1, &albuffer);648alBufferData(albuffer,AL_FORMAT_MONO16,&multibuffer[j][0],buffer.size()*2/channels,samplerate);649alSourceQueueBuffers(sources[i*channels+j], 1, &albuffer);650}651}else{652ALuint albuffer;653alSourceUnqueueBuffers(sources[i], 1, &albuffer);654alBufferData(albuffer,AL_FORMAT_MONO16,&buffer[0],buffer.size()*2/channels,samplerate);655alSourceQueueBuffers(sources[i], 1, &albuffer);656}657if(stream_end){658break;659}660}661ALint state;662alGetSourcei(sources[i*channels],AL_SOURCE_STATE,&state);663bool stream_running=false;664#ifdef OF_USING_MPG123665stream_running = streamf || mp3streamf;666#else667stream_running = streamf;668#endif669if(state != AL_PLAYING && stream_running && !stream_end){670alSourcePlayv(channels,&sources[i*channels]);671}672
673stream_end = false;674}675sleep(1);676}677}
678
679//------------------------------------------------------------
680void ofOpenALSoundPlayer::update(ofEventArgs & args){681
682for(int i=1; i<int(sources.size())/channels; ){683ALint state;684alGetSourcei(sources[i*channels],AL_SOURCE_STATE,&state);685if(state != AL_PLAYING){686alDeleteSources(channels,&sources[i*channels]);687for(int j=0;j<channels;j++){688sources.erase(sources.begin()+i*channels);689}690}else{691i++;692}693}694}
695
696//------------------------------------------------------------
697void ofOpenALSoundPlayer::unload(){698stop();699ofRemoveListener(ofEvents().update,this,&ofOpenALSoundPlayer::update);700
701// Only lock the thread where necessary.702{703std::unique_lock<std::mutex> lock(mutex);704
705// Delete sources before buffers.706alDeleteSources(sources.size(),&sources[0]);707alDeleteBuffers(buffers.size(),&buffers[0]);708
709sources.clear();710buffers.clear();711}712
713// Free resources and close file descriptors.714#ifdef OF_USING_MPG123715if(mp3streamf){716mpg123_close(mp3streamf);717mpg123_delete(mp3streamf);718}719mp3streamf = 0;720#endif721
722if(streamf){723sf_close(streamf);724}725streamf = 0;726
727bLoadedOk = false;728}
729
730//------------------------------------------------------------
731bool ofOpenALSoundPlayer::isPlaying() const{732if(sources.empty()) return false;733if(isStreaming) return isThreadRunning();734ALint state;735bool playing=false;736for(int i=0;i<(int)sources.size();i++){737alGetSourcei(sources[i],AL_SOURCE_STATE,&state);738playing |= (state == AL_PLAYING);739}740return playing;741}
742
743//------------------------------------------------------------
744bool ofOpenALSoundPlayer::isPaused() const{745if(sources.empty()) return false;746ALint state;747bool paused=true;748for(int i=0;i<(int)sources.size();i++){749alGetSourcei(sources[i],AL_SOURCE_STATE,&state);750paused &= (state == AL_PAUSED);751}752return paused;753}
754
755//------------------------------------------------------------
756float ofOpenALSoundPlayer::getSpeed() const{757return speed;758}
759
760//------------------------------------------------------------
761float ofOpenALSoundPlayer::getPan() const{762return pan;763}
764
765//------------------------------------------------------------
766float ofOpenALSoundPlayer::getVolume() const{767return volume;768}
769
770//------------------------------------------------------------
771void ofOpenALSoundPlayer::setVolume(float vol){772volume = vol;773if(sources.empty()) return;774if(channels==1){775alSourcef (sources[sources.size()-1], AL_GAIN, vol);776}else{777setPan(pan);778}779}
780
781//------------------------------------------------------------
782void ofOpenALSoundPlayer::setPosition(float pct){783setPositionMS(duration*pct*1000.f);784}
785
786//------------------------------------------------------------
787void ofOpenALSoundPlayer::setPositionMS(int ms){788if(sources.empty()) return;789#ifdef OF_USING_MPG123790if(mp3streamf){791mpg123_seek(mp3streamf,float(ms)/1000.f*samplerate,SEEK_SET);792}else793#endif794if(streamf){795stream_samples_read = sf_seek(streamf,float(ms)/1000.f*samplerate,SEEK_SET) * channels;796}else{797for(int i=0;i<(int)channels;i++){798alSourcef(sources[sources.size()-channels+i],AL_SEC_OFFSET,float(ms)/1000.f);799}800}801}
802
803//------------------------------------------------------------
804float ofOpenALSoundPlayer::getPosition() const{805if(duration==0 || sources.empty())806return 0;807else808return getPositionMS()/(1000.f*duration);809}
810
811//------------------------------------------------------------
812int ofOpenALSoundPlayer::getPositionMS() const{813if(sources.empty()) return 0;814float pos;815#ifdef OF_USING_MPG123816if(mp3streamf){817pos = float(mpg123_tell(mp3streamf)) / float(samplerate);818}else819#endif820if(streamf){821pos = float(stream_samples_read) / float(channels) / float(samplerate);822}else{823alGetSourcef(sources[sources.size()-1],AL_SEC_OFFSET,&pos);824}825return pos * 1000.f;826}
827
828//------------------------------------------------------------
829void ofOpenALSoundPlayer::setPan(float p){830if(sources.empty()) return;831p = glm::clamp(p, -1.f, 1.f);832pan = p;833if(channels==1){834float pos[3] = {p,0,0};835alSourcefv(sources[sources.size()-1],AL_POSITION,pos);836}else{837// calculates left/right volumes from pan-value (constant panning law)838// see: Curtis Roads: Computer Music Tutorial p 460839// thanks to jasch840
841float angle = p * glm::quarter_pi<float>(); // in radians from -45. to +45.842float cosAngle = cos(angle);843float sinAngle = sin(angle);844
845float leftVol = (cosAngle - sinAngle) * glm::one_over_root_two<float>(); //// multiplied by 1/sqrt(2)846float rightVol = (cosAngle + sinAngle) * glm::one_over_root_two<float>(); // multiplied by 1/sqrt(2)847for(int i=0;i<(int)channels;i++){848if(i==0){849alSourcef(sources[sources.size()-channels+i],AL_GAIN,leftVol*volume);850}else{851alSourcef(sources[sources.size()-channels+i],AL_GAIN,rightVol*volume);852}853}854}855}
856
857
858//------------------------------------------------------------
859void ofOpenALSoundPlayer::setPaused(bool bP){860if(sources.empty()) return;861std::unique_lock<std::mutex> lock(mutex);862if(bP){863alSourcePausev(sources.size(),&sources[0]);864if(isStreaming){865stopThread();866}867}else{868alSourcePlayv(sources.size(),&sources[0]);869if(isStreaming){870startThread();871}872}873
874bPaused = bP;875}
876
877
878//------------------------------------------------------------
879void ofOpenALSoundPlayer::setSpeed(float spd){880for(int i=0;i<channels;i++){881alSourcef(sources[sources.size()-channels+i],AL_PITCH,spd);882}883speed = spd;884}
885
886
887//------------------------------------------------------------
888void ofOpenALSoundPlayer::setLoop(bool bLp){889if(bMultiPlay) return; // no looping on multiplay890bLoop = bLp;891if(isStreaming) return;892for(int i=0;i<(int)sources.size();i++){893alSourcei(sources[i],AL_LOOPING,bLp?AL_TRUE:AL_FALSE);894}895}
896
897// ----------------------------------------------------------------------------
898void ofOpenALSoundPlayer::setMultiPlay(bool bMp){899if(isStreaming && bMp){900ofLogWarning("ofOpenALSoundPlayer") << "setMultiPlay(): sorry, no support for multiplay streams";901return;902}903bMultiPlay = bMp; // be careful with this...904if(sources.empty()) return;905if(bMultiPlay){906ofAddListener(ofEvents().update,this,&ofOpenALSoundPlayer::update);907}else{908ofRemoveListener(ofEvents().update,this,&ofOpenALSoundPlayer::update);909}910}
911
912// ----------------------------------------------------------------------------
913void ofOpenALSoundPlayer::play(){914std::unique_lock<std::mutex> lock(mutex);915int err = alGetError();916
917// if the sound is set to multiplay, then create new sources,918// do not multiplay on loop or we won't be able to stop it919if (bMultiPlay && !bLoop){920sources.resize(sources.size()+channels);921alGetError(); // Clear error.922alGenSources(channels, &sources[sources.size()-channels]);923err = alGetError();924if (err != AL_NO_ERROR){925ofLogError("ofOpenALSoundPlayer") << "play(): couldn't create multiplay stereo sources: "926<< (int) err << " " << getALErrorString(err);927return;928}929for(int i=0;i<channels;i++){930alSourcei (sources[sources.size()-channels+i], AL_BUFFER, buffers[i] );931// only stereo panning932if(i==0){933float pos[3] = {-1,0,0};934alSourcefv(sources[sources.size()-channels+i],AL_POSITION,pos);935}else{936float pos[3] = {1,0,0};937alSourcefv(sources[sources.size()-channels+i],AL_POSITION,pos);938}939alSourcef (sources[sources.size()-channels+i], AL_ROLLOFF_FACTOR, 0.0);940alSourcei (sources[sources.size()-channels+i], AL_SOURCE_RELATIVE, AL_TRUE);941}942
943err = alGetError();944if (err != AL_NO_ERROR){945ofLogError("ofOpenALSoundPlayer") << "play(): couldn't assign multiplay buffers: "946<< (int) err << " " << getALErrorString(err);947return;948}949}950alSourcePlayv(channels,&sources[sources.size()-channels]);951
952if(bMultiPlay){953ofAddListener(ofEvents().update,this,&ofOpenALSoundPlayer::update);954}955if(isStreaming){956setPosition(0);957stream_end = false;958startThread();959}960
961}
962
963// ----------------------------------------------------------------------------
964void ofOpenALSoundPlayer::stop(){965if(sources.empty()) return;966std::unique_lock<std::mutex> lock(mutex);967alSourceStopv(channels,&sources[sources.size()-channels]);968if(isStreaming){969setPosition(0);970stopThread();971}972}
973
974// ----------------------------------------------------------------------------
975void ofOpenALSoundPlayer::initFFT(int bands){976if(int(bins.size())==bands) return;977int signalSize = (bands-1)*2;978if(fftCfg!=0) kiss_fftr_free(fftCfg);979fftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr);980cx_out.resize(bands);981bins.resize(bands);982createWindow(signalSize);983}
984
985// ----------------------------------------------------------------------------
986void ofOpenALSoundPlayer::initSystemFFT(int bands){987if(int(systemBins.size())==bands) return;988int signalSize = (bands-1)*2;989if(systemFftCfg!=0) kiss_fftr_free(systemFftCfg);990systemFftCfg = kiss_fftr_alloc(signalSize, 0, nullptr, nullptr);991systemCx_out.resize(bands);992systemBins.resize(bands);993createWindow(signalSize);994}
995
996float * ofOpenALSoundPlayer::getCurrentBufferSum(int size){997if(int(windowedSignal.size())!=size){998windowedSignal.resize(size);999}1000windowedSignal.assign(windowedSignal.size(),0);1001for(int k=0;k<int(sources.size())/channels;k++){1002if(!isStreaming){1003ALint state;1004alGetSourcei(sources[k*channels],AL_SOURCE_STATE,&state);1005if( state != AL_PLAYING ) continue;1006}1007int pos;1008alGetSourcei(sources[k*channels],AL_SAMPLE_OFFSET,&pos);1009//if(pos+size>=(int)fftBuffers[0].size()) continue;1010for(int i=0;i<channels;i++){1011float gain;1012alGetSourcef(sources[k*channels+i],AL_GAIN,&gain);1013for(int j=0;j<size;j++){1014if(pos+j<(int)fftBuffers[i].size())1015windowedSignal[j]+=fftBuffers[i][pos+j]*gain;1016else1017windowedSignal[j]=0;1018}1019}1020}1021return &windowedSignal[0];1022}
1023
1024// ----------------------------------------------------------------------------
1025float * ofOpenALSoundPlayer::getSpectrum(int bands){1026initFFT(bands);1027bins.assign(bins.size(),0);1028if(sources.empty()) return &bins[0];1029
1030int signalSize = (bands-1)*2;1031getCurrentBufferSum(signalSize);1032
1033float normalizer = 2. / windowSum;1034runWindow(windowedSignal);1035kiss_fftr(fftCfg, &windowedSignal[0], &cx_out[0]);1036for(int i= 0; i < bands; i++) {1037bins[i] += sqrtf(cx_out[i].r * cx_out[i].r + cx_out[i].i * cx_out[i].i) * normalizer;1038}1039return &bins[0];1040}
1041
1042// ----------------------------------------------------------------------------
1043float * ofOpenALSoundPlayer::getSystemSpectrum(int bands){1044initSystemFFT(bands);1045systemBins.assign(systemBins.size(),0);1046if(players().empty()) return &systemBins[0];1047
1048int signalSize = (bands-1)*2;1049if(int(systemWindowedSignal.size())!=signalSize){1050systemWindowedSignal.resize(signalSize);1051}1052systemWindowedSignal.assign(systemWindowedSignal.size(),0);1053
1054std::set<ofOpenALSoundPlayer*>::iterator it;1055for(it=players().begin();it!=players().end();it++){1056if(!(*it)->isPlaying()) continue;1057float * buffer = (*it)->getCurrentBufferSum(signalSize);1058for(int i=0;i<signalSize;i++){1059systemWindowedSignal[i]+=buffer[i];1060}1061}1062
1063float normalizer = 2. / windowSum;1064runWindow(systemWindowedSignal);1065kiss_fftr(systemFftCfg, &systemWindowedSignal[0], &systemCx_out[0]);1066for(int i= 0; i < bands; i++) {1067systemBins[i] += sqrtf(systemCx_out[i].r * systemCx_out[i].r + systemCx_out[i].i * systemCx_out[i].i) * normalizer;1068}1069return &systemBins[0];1070}
1071
1072// ----------------------------------------------------------------------------
1073void ofOpenALSoundPlayer::runWindow(std::vector<float> & signal){1074for(int i = 0; i < (int)signal.size(); i++)1075signal[i] *= window[i];1076}
1077
1078
1079#endif1080