mpg123 to audioRequested

audioRequested requires that data be insert in to an array of floats, of which I have two channels setup to output.

I’m using mpg123 to decode an MP3. I’m not 100% sure what mpg123 is giving me back, but I can tell you it’s an unsigned char array.

According to getFormat the encoding is unsigned short, and there’s two channels.

I know that I need to alternate left and right audio in the float array for audioRequested, but I’m not sure what sort of translation is required between mpg123 unsigned char array and audioRequested float array. Here’s what I have so far, which returns noise that sounds close, but not quite there. Does anyone know how to open an MP3 via mpg123 and output via audioRequested?

  
  
void TestApp::audioRequested (float * output, int bufferSize, int nChannels) {  
  bzero(output, bufferSize*sizeof(float));  
  bzero(mpg123Buffer, bufferSize);  
  
  short b;  
  size_t done;  
  mpg123_read(mpg123Handle, buffer, bufferSize, &done);  
  for (int i=0; i<bufferSize; i+=2*sizeof(short)) {  
    memcpy(&b, &buffer[i], sizeof(short));  
    output[i] = b;  
    memcpy(&b, &buffer[i+sizeof(short)], sizeof(short));  
    output[i+1] = b;  
  }  
}  
  

Any help appreciated. Thanks!

I don’t know if this if useful, but I found some mpg123 code in a previous version of Alure, an OpenAL wrapper:

  
  
    virtual ALuint GetData(ALubyte *data, ALuint bytes)  
    {  
        const ALuint blockAlign = channels*2;  
        bytes -= bytes%blockAlign;  
  
        ALuint amt = 0;  
        do {  
            size_t got = 0;  
            int ret = mpg123_read(mp3File, data, bytes, &got);  
  
            bytes -= got;  
            data += got;  
            amt += got;  
  
            if(ret == MPG123_NEED_MORE)  
            {  
                ALuint insize = std::min(64*1024u, memInfo.Length-memInfo.Pos);  
                if(insize > 0 &&  
                   mpg123_decode(mp3File, const_cast<unsigned char*>(memInfo.Data+memInfo.Pos), insize, NULL, 0, NULL) == MPG123_OK)  
                {  
                    memInfo.Pos += insize;  
                    continue;  
                }  
                memInfo.Pos += insize;  
            }  
  
            return amt;  
        } while(1);  
    }  

Does it not working if you cast the data to float? Keep in mind you might need to do some byte swapping depending on your platform.

Have you tried this?:

  
  
unsigned short *u16_buffer = (unsigned short *)buf; // where buf is your data   
float sample[samplesInBuffer]  
  
for (int i=0; i<samplesInBuffer; i++)  
   sample[i]=u16_buffer[i]; // implicit conversion to float  
  
  

Thanks for your help Grimus.

Eventually I got this going, so I’ll post the solution. It was pretty straight forward in the end but it took me a long time to work out due to lack of documentation and experience in this type of coding, plus stupid mistakes on my part!

  
  
void TestApp::audioRequested (float * output, int bufferSize, int nChannels) {  
  mpg123Buffer = new short[bufferSize*nChannels];  
    
  size_t done;  
  mpg123_read(mpg123Handle, (unsigned char*)mpg123Buffer, bufferSize*nChannels*sizeof(short), &done);  
  for (int i=0; i<done/sizeof(short); i++) {  
    output[i] = mpg123Buffer[i];  
    output[i] *= 0.001f;  
  }  
    
  delete mpg123Buffer;  
}  
  

mpg123Buffer is an array of shorts. Multiplying by fractions is to change the volume.

What tripped me up until the very end was that the size of the output buffer is in fact bufferSize * nChannels, and not just bufferSize as I had originally thought. This is documented on the wiki so completely my own fault!