#include "ofFmodSoundPlayer.h"
#ifdef OF_SOUND_PLAYER_FMOD
#include "ofUtils.h"
#include "ofMath.h"
#include "ofLog.h"
static bool bFmodInitialized_ = false;
static float fftValues_[8192];
static float fftInterpValues_[8192];
static float fftSpectrum_[8192];
static unsigned int buffersize = 1024;
static FMOD_CHANNELGROUP * channelgroup;
static FMOD_SYSTEM * sys;
void ofFmodSoundStopAll(){
ofFmodSoundPlayer::initializeFmod();
FMOD_ChannelGroup_Stop(channelgroup);
}
void ofFmodSoundSetVolume(float vol){
ofFmodSoundPlayer::initializeFmod();
FMOD_ChannelGroup_SetVolume(channelgroup, vol);
}
void ofFmodSoundUpdate(){
if (bFmodInitialized_){
FMOD_System_Update(sys);
}
}
float * ofFmodSoundGetSpectrum(int nBands){
ofFmodSoundPlayer::initializeFmod();
for (int i = 0; i < 8192; i++){
fftInterpValues_[i] = 0;
}
if (nBands > 8192){
ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using maximum of 8192";
nBands = 8192;
} else if (nBands <= 0){
ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): requested number of bands " << nBands << ", using minimum of 1";
nBands = 1;
return fftInterpValues_;
}
int nBandsToGet = ofNextPow2(nBands);
if (nBandsToGet < 64) nBandsToGet = 64;
FMOD_System_GetSpectrum(sys, fftSpectrum_, nBandsToGet, 0, FMOD_DSP_FFT_WINDOW_HANNING);
for(int i = 0; i < nBandsToGet; i++){
fftValues_[i] = 10.0f * (float)log10(1 + fftSpectrum_[i]) * 2.0f;
}
if (nBandsToGet == nBands){
for(int i = 0; i < nBandsToGet; i++){
fftInterpValues_[i] = fftValues_[i];
}
} else {
float step = (float)nBandsToGet / (float)nBands;
int currentBand = 0;
for(int i = 0; i < nBandsToGet; i++){
if (i >= ((currentBand+1)*step)){
float fraction = ((currentBand+1)*step) - (i-1);
float one_m_fraction = 1 - fraction;
fftInterpValues_[currentBand] += fraction * fftValues_[i];
currentBand++;
if (currentBand >= nBands){
ofLogWarning("ofFmodSoundPlayer") << "ofFmodGetSpectrum(): currentBand >= nBands";
}
fftInterpValues_[currentBand] += one_m_fraction * fftValues_[i];
} else {
fftInterpValues_[currentBand] += fftValues_[i];
}
}
for (int i = 0; i < nBands; i++){
fftInterpValues_[i] /= step;
if (fftInterpValues_[i] > 1)fftInterpValues_[i] = 1;
}
}
return fftInterpValues_;
}
void ofFmodSetBuffersize(unsigned int bs){
buffersize = bs;
}
ofFmodSoundPlayer::ofFmodSoundPlayer(){
bLoop = false;
bLoadedOk = false;
pan = 0.0;
volume = 1.0f;
internalFreq = 44100;
speed = 1;
bPaused = false;
isStreaming = false;
}
ofFmodSoundPlayer::~ofFmodSoundPlayer(){
unload();
}
void ofFmodSoundPlayer::initializeFmod(){
if(!bFmodInitialized_){
FMOD_System_Create(&sys);
unsigned int bsTmp;
int nbTmp;
FMOD_System_GetDSPBufferSize(sys, &bsTmp, &nbTmp);
FMOD_System_SetDSPBufferSize(sys, buffersize, nbTmp);
#ifdef TARGET_LINUX
FMOD_System_SetOutput(sys,FMOD_OUTPUTTYPE_ALSA);
#endif
FMOD_System_Init(sys, 32, FMOD_INIT_NORMAL, nullptr);
FMOD_System_GetMasterChannelGroup(sys, &channelgroup);
bFmodInitialized_ = true;
}
}
void ofFmodSoundPlayer::closeFmod(){
if(bFmodInitialized_){
FMOD_System_Close(sys);
bFmodInitialized_ = false;
}
}
bool ofFmodSoundPlayer::load(const std::filesystem::path& _fileName, bool stream){
auto fileName = ofToDataPath(_fileName);
bMultiPlay = false;
initializeFmod();
unload();
int fmodFlags = FMOD_SOFTWARE;
if(stream)fmodFlags = FMOD_SOFTWARE | FMOD_CREATESTREAM;
result = FMOD_System_CreateSound(sys, fileName.data(), fmodFlags, nullptr, &sound);
if (result != FMOD_OK){
bLoadedOk = false;
ofLogError("ofFmodSoundPlayer") << "loadSound(): could not load \"" << fileName << "\"";
} else {
bLoadedOk = true;
FMOD_Sound_GetLength(sound, &length, FMOD_TIMEUNIT_PCM);
isStreaming = stream;
}
return bLoadedOk;
}
void ofFmodSoundPlayer::unload(){
if (bLoadedOk){
stop();
FMOD_Sound_Release(sound);
bLoadedOk = false;
}
}
bool ofFmodSoundPlayer::isPlaying() const{
if (!bLoadedOk) return false;
int playing = 0;
FMOD_Channel_IsPlaying(channel, &playing);
return (playing != 0 ? true : false);
}
float ofFmodSoundPlayer::getSpeed() const{
return speed;
}
float ofFmodSoundPlayer::getPan() const{
return pan;
}
float ofFmodSoundPlayer::getVolume() const{
return volume;
}
bool ofFmodSoundPlayer::isLoaded() const{
return bLoadedOk;
}
void ofFmodSoundPlayer::setVolume(float vol){
if (isPlaying()){
FMOD_Channel_SetVolume(channel, vol);
}
volume = vol;
}
void ofFmodSoundPlayer::setPosition(float pct){
if (isPlaying()){
int sampleToBeAt = (int)(length * pct);
FMOD_Channel_SetPosition(channel, sampleToBeAt, FMOD_TIMEUNIT_PCM);
}
}
void ofFmodSoundPlayer::setPositionMS(int ms) {
if (isPlaying()){
FMOD_Channel_SetPosition(channel, ms, FMOD_TIMEUNIT_MS);
}
}
float ofFmodSoundPlayer::getPosition() const{
if (isPlaying()){
unsigned int sampleImAt;
FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_PCM);
float pct = 0.0f;
if (length > 0){
pct = sampleImAt / (float)length;
}
return pct;
} else {
return 0;
}
}
int ofFmodSoundPlayer::getPositionMS() const{
if (isPlaying()){
unsigned int sampleImAt;
FMOD_Channel_GetPosition(channel, &sampleImAt, FMOD_TIMEUNIT_MS);
return sampleImAt;
} else {
return 0;
}
}
void ofFmodSoundPlayer::setPan(float p){
pan = p;
p = ofClamp(p, -1, 1);
if (isPlaying()){
FMOD_Channel_SetPan(channel,p);
}
}
void ofFmodSoundPlayer::setPaused(bool bP){
if (isPlaying()){
FMOD_Channel_SetPaused(channel,bP);
bPaused = bP;
}
}
void ofFmodSoundPlayer::setSpeed(float spd){
if (isPlaying()){
FMOD_Channel_SetFrequency(channel, internalFreq * spd);
}
speed = spd;
}
void ofFmodSoundPlayer::setLoop(bool bLp){
if (isPlaying()){
FMOD_Channel_SetMode(channel, (bLp == true) ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
}
bLoop = bLp;
}
void ofFmodSoundPlayer::setMultiPlay(bool bMp){
bMultiPlay = bMp;
}
void ofFmodSoundPlayer::play(){
if (bLoop == true){
FMOD_Channel_Stop(channel);
}
if (!bMultiPlay){
FMOD_Channel_Stop(channel);
}
FMOD_System_PlaySound(sys, FMOD_CHANNEL_FREE, sound, bPaused, &channel);
FMOD_Channel_GetFrequency(channel, &internalFreq);
FMOD_Channel_SetVolume(channel,volume);
setPan(pan);
FMOD_Channel_SetFrequency(channel, internalFreq * speed);
FMOD_Channel_SetMode(channel, (bLoop == true) ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
FMOD_System_Update(sys);
}
void ofFmodSoundPlayer::stop(){
FMOD_Channel_Stop(channel);
}
#endif
Comments