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

Daniel PEACOCK dpeacock at creativelabs.com
Thu Apr 16 08:41:37 PDT 2009





"Note that when using the “Generic Software” device, the multi-channel
buffers are mixed down to a stereo output"

The behaviour you are seeing on the "Generic Software" device is expected.
This device only supports stereo (2.0) output.  It supports playback of
multi-channel buffers (e.g 5.1 or 7.1), and rather than lose any audio
contained in the extra channels, that data is mixed into the stereo output
- preserving left-right separation (e.g all the left channels of a
multichannel buffer are mixed into the output left channel and all the
right channels are mixed into the output right channel).

Your soundcard is likely to be upmixing the stereo output of the "Generic
Software" device to 5.1which is why you hear audio in all the channels.

The bottom line is that the "Generic Software" device won't let you send a
discrete signal to a side or rear channel.  The other Creative devices will
all support this feature - and so will Chris' OpenAL-Soft.

Dan
Creative Labs (UK) Ltd.

Notice
The information in this message is confidential and may be legally
privileged.  It is intended solely for the addressee.  Access to this
message by anyone else is unauthorized.  If you are not the intended
recipient,  any disclosure,  copying or distribution of the message,  or
any action taken by you in reliance on it,  is prohibited and may be
unlawful.  If you have received this message in error,  please delete it
and contact the sender immediately.  Thank you.

Creative Labs UK Ltd company number 2658256 registered in England and Wales
at Belmont Road, Belmont Place, Maidenhead, Berkshire, SL6 6TB



                                                                           
             Ümit Uzun                                                     
             <umituzun84 at gmail                                             
             .com>                                                      To 
             Sent by:                  OpenAL                              
             openal-bounces at op         <openal at opensource.creative.com>    
             ensource.creative                                          cc 
             .com                                                          
                                                                   Subject 
                                       Re: [Openal] How can I play mono    
             04/16/2009 02:06          wav sound in specific channel?      
             PM                                                            
                                                                           
                                                                           
                                                                           
                                                                           
                                                                           




Hi Chris;

I have implemented your code in Framework.cpp and it works like a charm :D
Thanks so much for your awesome helps :D But I have some questions to
solve. I have implemented your suggestion on 5.1 speaker system like that;

template<typename T>
T *load_data(const T *data, int size)
{  size /= sizeof(T);   T *data71 = new T[size*6];  for(int i = 0;i < size;i++)
{
    data71[i*6 + 0] = 0; // front-left     data71[i*6 + 1] = 0; //
front-right     data71[i*6 + 2] = 0; // front-center     data71[i*6 + 3] = 0;
// lfe (sub-woofer)     data71[i*6 + 4] = 0; // back-left     data71[i*6 + 5]
= 0; // back-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_51CHN8"),                 data, iDataSize*6,
iFrequency);    delete[] data;
} else if(fmt.wBitsPerSample == 16) {    ALshort *data = load_data((const
ALshort*)pData, iDataSize);    alBufferData(uiBufferID,
alGetEnumValue("AL_FORMAT_51CHN16"),                 data, iDataSize*6,
iFrequency);    delete[] data;
} else if(fmt.wBitsPerSample == 32) { // assumes 32-bit float    ALfloat
*data = load_data((const ALfloat*)pData,
iDataSize);    alBufferData(uiBufferID,
alGetEnumValue("AL_FORMAT_51CHN32"),                 data, iDataSize*6,
iFrequency);    delete[] data;
}

It works on while using Generic Hardware. I mean I can direct each sound to
each wanted channel errorless, but when I try same operation while using
Generic Software it works but it is mixing the channels. For example I want
to play on back- left, but sound is heard from front-left, back-left,
front-center and lfe and vice-versa for the back-right.

I mean Generic Software can't play related channel on related side. Do you
think it is problem of generic software or what? I have looked at the
OpenALProgrammingGuide and there is a statement about kind of this
situation but I can't really understand what does it mean? Can you explain
what could be the problem?

>From OpenALProgrammingGuide;
"The multi-channel extension provides a mechanism to play multi-channel
data via OpenAL. A variety of formats are supported. Multi-channel buffers
can be attached or queued on a source.
Note that when using the “Generic Software” device, the multi-channel
buffers are mixed down to a stereo output. On a hardware device (such as
the “Generic Hardware” device or a native device), each channel of a buffer
requires a hardware voice. So, for example playing a buffer using the
AL_FORMAT_51CHN16 format will require 6 free hardware voices. If the
hardware resources are unavailable, the call to alSourceQueueBuffers or
alSourcei will fail."

Thanks so much.
Best Regards.

2009/4/16 Chris Robinson <chris.kcat at gmail.com>
  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.
  _______________________________________________
  Openal mailing list
  Openal at opensource.creative.com
  http://opensource.creative.com/mailman/listinfo/openal



--
Ümit Uzun_______________________________________________
Openal mailing list
Openal at opensource.creative.com
http://opensource.creative.com/mailman/listinfo/openal

ForwardSourceID:NT0006B3A2



More information about the Openal mailing list