[Openal] How can I play mono wav sound in specific channel?

Chris Robinson chris.kcat at gmail.com
Thu Apr 16 03:38:23 PDT 2009


On Thursday 16 April 2009 2:53:45 am you wrote:
> Hi Chris;
>
> > ALshort monodata[samples];
> >
> > you can fill it into a 7.1 buffer like this:
> >
> > ALshort data71[samples*8];
> > for(int i = 0;i < samples;i++) {
> >    data71[i*8 + 0] = 0; // front-left
> >    data71[i*8 + 1] = 0; // front-right
> >    data71[i*8 + 2] = 0; // front-center
> >    data71[i*8 + 3] = 0; // lfe (sub-woofer)
> >    data71[i*8 + 4] = 0; // back-left
> >    data71[i*8 + 5] = 0; // back-right
> >    data71[i*8 + 6] = monodata[i]; // side-left
> >    data71[i*8 + 7] = monodata[i]; // side-right
> > }
> > alBufferData(bID, alGetEnumValue("AL_FORMAT_71CHN16"), data71,
> >             samples*8*sizeof(ALshort), frequency);
> >
> I have look at the Framework and there is ALFWLoadWaveToBuffer;
>
> ALboolean ALFWLoadWaveToBuffer(const char *szWaveFile, ALuint uiBufferID,
> ALenum eXRAMBufferMode)
> {
>     WAVEID    WaveID;
>     ALint     iDataSize, iFrequency;
>     ALenum    eBufferFormat;
>     ALchar    *pData;
>     ALboolean bReturn;
>
>     bReturn = AL_FALSE;
>     if(g_pWaveLoader)
>     {
>         if(SUCCEEDED(g_pWaveLoader->LoadWaveFile(szWaveFile, &WaveID)))
>         {
>             if((SUCCEEDED(g_pWaveLoader->GetWaveSize(WaveID, (unsigned
> long*)&iDataSize))) &&
>                (SUCCEEDED(g_pWaveLoader->GetWaveData(WaveID,
> (void**)&pData))) &&
>                (SUCCEEDED(g_pWaveLoader->GetWaveFrequency(WaveID, (unsigned
> long*)&iFrequency))) &&
>                (SUCCEEDED(g_pWaveLoader->GetWaveALBufferFormat(WaveID,
> &alGetEnumValue, (unsigned long*)&eBufferFormat))))
>             {
>                 // Set XRAM Mode (ifapplication)
>                 if(eaxSetBufferMode && eXRAMBufferMode)
>                 {
>                     eaxSetBufferMode(1, &uiBufferID, eXRAMBufferMode);
>                 }
>
>                 alGetError();
>                 alBufferData(uiBufferID, eBufferFormat, pData, iDataSize,
> iFrequency);
>
>                 if(alGetError() == AL_NO_ERROR)
>                 {
>                     bReturn = AL_TRUE;
>                 }
>
>                 g_pWaveLoader->DeleteWaveFile(WaveID);
>             }
>         }
>     }
>
>     return bReturn;
> }
>
> You have given ALshort monodata[samples]; but in this code ALchar *pData;
> This variable are same or not. because alBufferData takes void format and
> ALchar is 1 byte and ALshort 2 byte. I can't get what should I do.

They aren't the same. That function uses pData because the loaded wave data 
may be 8-bit, or 16-bit (or possible 32-bit), so it just uses a generic char 
type.

g_pWaveLoader has a GetWaveFormatExHeader method you can use to get a 
WAVEFORMATEX struct, which has a wBitsPerSample field. You need to check that 
field and act on the data depending on the value (eg. if it's 8, use ALubyte, 
if it's 16, use ALshort).

And example of doing this in C++ would be something like:

template<typename T>
T *load_data(const T *data, int size)
{
  size /= sizeof(T);

  T *data71 = new T[size*8];
  for(int i = 0;i < size;i++) {
     data71[i*8 + 0] = 0; // front-left
     data71[i*8 + 1] = 0; // front-right
     data71[i*8 + 2] = 0; // front-center
     data71[i*8 + 3] = 0; // lfe (sub-woofer)
     data71[i*8 + 4] = 0; // back-left
     data71[i*8 + 5] = 0; // back-right
     data71[i*8 + 6] = data[i]; // side-left
     data71[i*8 + 7] = data[i]; // side-right
  }

  return data71;
}

...

WAVEFORMATEX fmt;

g_pWaveLoader->GetWaveFormatExHeader(WaveID, &fmt);
if(fmt.wBitsPerSample == 8) {
    ALubyte *data = load_data((const ALubyte*)pData, iDataSize);
    alBufferData(uiBufferID, alGetEnumValue("AL_FORMAT_71CHN8"),
                 data, iDataSize*8, iFrequency);
    delete[] data;
} else if(fmt.wBitsPerSample == 16) {
    ALshort *data = load_data((const ALshort*)pData, iDataSize);
    alBufferData(uiBufferID, alGetEnumValue("AL_FORMAT_71CHN16"),
                 data, iDataSize*8, iFrequency);
    delete[] data;
} else if(fmt.wBitsPerSample == 32) { // assumes 32-bit float
    ALshort *data = load_data((const ALfloat*)pData, iDataSize);
    alBufferData(uiBufferID, alGetEnumValue("AL_FORMAT_71CHN32"),
                 data, iDataSize*8, iFrequency);
    delete[] data;
}

..
completely untested, but the concept should work. It would load the sound so 
that when it plays, it'll play out the side speakers.


More information about the Openal mailing list