ofSoundPlayer get the volume from an mp3 file

I’m trying to get the magnitude of a song played through the ofSoundPlayer. What I would like to have is the RMS value as explained in the chapter “Reacting to live audio” of the ofBook http://openframeworks.cc/ofBook/chapters/sound.html

What I’ve done until now is to follow the example soundPlayerFFTExample.

In my .h file

ofSoundPlayer soundPlayer;
float 		  * fftSmoothed;
int           nBandsToGet;

In the setup method

void ofApp::setup(){
    soundPlayer.load("chainsaw-01.mp3");
    nBandsToGet = 6; // i do not care about all the frequencies

    fftSmoothed = new float[8192];
    for (int i = 0; i < 8192; i++){
        fftSmoothed[i] = 0;
    }

    float * val = ofSoundGetSpectrum(nBandsToGet);// request 6 values for fft
    for (int i = 0;i < nBandsToGet; i++){
        fftSmoothed[i] *= 0.96f;
        if (fftSmoothed[i] < val[i]) fftSmoothed[i] = val[i];
    }
    soundPlayer.play();
}
void ofApp::update(){
    ofSoundUpdate();
    float * val = ofSoundGetSpectrum(nBandsToGet);
    for (int i = 0;i < nBandsToGet; i++){
        fftSmoothed[i] *= 0.96f;
        if (fftSmoothed[i] < val[i]) fftSmoothed[i] = val[i];
    }
    cout << ofToString(fftSmoothed[0]*2) << endl;
}

The cout is printing out values that are changing accordingly to the volume, that is less or more what I was looking for, but I’ve some questions:

  1. Is this really the simplest way to get the “loudness” out of a played audio file?
  2. Does it makes sense to reduce the bands to nBandsToGet = 1? As I’m interested only in the volume, and the first band contains enough information?
  3. The values are scattering, is there a way to have a smoother differences through the values?
    4)How to get RMS out of this? in the ofBook there is this snippet:
// modified from audioInputExample
float rms = 0.0;
int numCounted = 0;

for (int i = 0; i < bufferSize; i++){
    float leftSample = input[i * 2] * 0.5;
    float rightSample = input[i * 2 + 1] * 0.5;
    
    rms += leftSample * leftSample;
    rms += rightSample * rightSample;
    numCounted += 2;
}

rms /= (float)numCounted;
rms = sqrt(rms);
// rms is now calculated

The problem is that I do not have a buffer to iterate.

Any suggestion is more than welcome :wink:

I’ve just used ofxMaxim, it has an handy method called magnitudesDB that does what i want.

ofApp.h

    // Audio output and input methods
    void audioOut(float * output, int bufferSize, int nChannels);
    void audioIn(float * input, int bufferSize, int nChannels);

    int		bufferSize;
    int		sampleRate;
    int     fftSize;

    ofxMaxiSample sample;
    maxiMix mymix;
    double wave;
    double outputs[2];
    ofxMaxiFFT fft;

ofApp.cpp

void ofApp::setup(){
    ofSetVerticalSync(true);
    ofEnableAlphaBlending();
    ofEnableSmoothing();
    ofBackground(0,0,0);

    sample.load(ofToDataPath("beat2.wav"));

    sampleRate 	= 44100; /* Sampling Rate */
    bufferSize	= 512; /* Buffer Size. you have to fill this buffer with sound using the for loop in the audioOut method */

    ofxMaxiSettings::setup(sampleRate, 2, bufferSize);
    // the higher the value, the more accurate will be the fft analysis
    fftSize = 1024;
    fft.setup(fftSize, 512, 256);
    /* this has to happen at the end of setup - it switches on the DAC */
    ofSoundStreamSetup(2,2,this, sampleRate, bufferSize, 4);
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetColor(255, 255, 255);
    for(int i = 0; i < fftSize ;i++){
        ofDrawRectangle(i * 2, ofGetHeight(), 2, -(fft.magnitudesDB[i]) * 8);
    }
}

//--------------------------------------------------------------
void ofApp::audioOut(float * output, int bufferSize, int nChannels) {
    for (int i = 0; i < bufferSize; i++){
        wave = sample.play();
        //fft
        if(fft.process(wave)){
            fft.magsToDB();
        }
        mymix.stereo(wave, outputs, 0.5);
        output[i*nChannels    ] = outputs[0];
        output[i*nChannels + 1] = outputs[1];
    }
}