Stereo files with SDL_mixer + SDL_sound

Hi,

I want to play a stereo OGG, WAV… files using SDL_sound + SDL_mixer. I
use SDL_sound to decode the OGG file and SDL_mixer to mix it with other
samples.

I’ve redefined the “musicplayer” playback in this way (assumes 16bit sound):

bool playing_music=true;
Sound_Sample *music_sample;

void myMusicPlayer(void *udata, Uint8 *stream, int len)
{
int i,act=0;
Sint16 *ptr2;

if (stream!=0) {
ptr2=(Sint16 )stream;
if (playing_music) {
while(act<len) {
if (music_sample!=0) {
/
Play a music file: /
if (music_sample->flags&SOUND_SAMPLEFLAG_EOF)) {
/
End of file: /
Sound_Rewind(music_sample);
} else {
/
In the middle of the file: */
int decoded=0;
Sint16 *ptr;

             Sound_SetBufferSize(music_sample, len-act);
             decoded=Sound_Decode(music_sample);
             ptr=(Sint16 *)music_sample->buffer;
             for(i=0;i<decoded;i+=2,ptr++,ptr2++)
                *ptr2=((Sint32(*ptr)*Sint32(music_volume))/127);

             act+=decoded;
          } /* if */
       } else {
          /* No music file loaded: */
          for(i=act;i<len;i++) stream[i]=0;
          act=len;
       } /* if */
     } /* while */
  } else {
     /* No music to play: */
     for(i=0;i<len;i++) stream[i]=0;
  } /* if */

} else {
fprintf(stderr,“ERROR in myMusicPlayer(): null music stream!!\n”);
} /* if /
} /
myMusicPlayer */

But now, I want to extend it to be able to play stereo files, and I
don’t know how to do it, since the “Uint8 stream” is a single stream!
How do I have to fill it with the right and left channel data?

But now, I want to extend it to be able to play stereo files, and I
don’t know how to do it, since the “Uint8 stream” is a single stream!
How do I have to fill it with the right and left channel data?

The stereo data is interleaved L/R+L/R+L/R+L/R Usually you can just
copy it exactly like mono data since if you’ve requested 2 channels
(stereo format) when opening the audio, it’ll be in the same format
as your stereo audio data.

-Sam Lantinga, Software Engineer, Blizzard Entertainment

Santi Onta??n wrote:

Hi,

I want to play a stereo OGG, WAV… files using SDL_sound + SDL_mixer. I
use SDL_sound to decode the OGG file and SDL_mixer to mix it with other
samples.

I’ve redefined the “musicplayer” playback in this way (assumes 16bit sound):

bool playing_music=true;
Sound_Sample *music_sample;

void myMusicPlayer(void *udata, Uint8 *stream, int len)
{
int i,act=0;
Sint16 *ptr2;

if (stream!=0) {
ptr2=(Sint16 )stream;
if (playing_music) {
while(act<len) {
if (music_sample!=0) {
/
Play a music file: /
if (music_sample->flags&SOUND_SAMPLEFLAG_EOF)) {
/
End of file: /
Sound_Rewind(music_sample);
} else {
/
In the middle of the file: */
int decoded=0;
Sint16 *ptr;

             Sound_SetBufferSize(music_sample, len-act);
             decoded=Sound_Decode(music_sample);
             ptr=(Sint16 *)music_sample->buffer;
             for(i=0;i<decoded;i+=2,ptr++,ptr2++)
                *ptr2=((Sint32(*ptr)*Sint32(music_volume))/127);

             act+=decoded;
          } /* if */
       } else {
          /* No music file loaded: */
          for(i=act;i<len;i++) stream[i]=0;
          act=len;
       } /* if */
     } /* while */
  } else {
     /* No music to play: */
     for(i=0;i<len;i++) stream[i]=0;
  } /* if */

} else {
fprintf(stderr,“ERROR in myMusicPlayer(): null music stream!!\n”);
} /* if /
} /
myMusicPlayer */

But now, I want to extend it to be able to play stereo files, and I
don’t know how to do it, since the “Uint8 stream” is a single stream!
How do I have to fill it with the right and left channel data?


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl

Code looks decent, but can likely be simplified… s’not a good idea to resize
the buffer every time you decode, for example…

In any case, there’s no need for worry - SDL_sound produces sound data in any
format requested without you having to worry about converting it in your own
code. As for how stereo works, it’s quite simple - they’re interleaved. Stored
as “right-left, right-left, right-left, …” Which, uncoincidentally, is
precisely how SDL wants it. Your decoder doesn’t even need to worry about what
format the music’s in, as long as it’s in an identical format to that of the
mixer… the pointers are Uint8 *'s simply out of convenience; the actual data
is in the format you requested. Lemme try rewriting this a bit…

#include <string.h>
#include “SDL_sound.h”

int playing_music=1; //plain C doesn’t have bool, used int instead
Sound_Sample *music_sample;

void myMusicPlayer(void *udata, Uint8 *stream, int len)
{
int size;
static int soundAvailable=0;
static int soundUsed=0;

//If we’re not playing, or there’s no sample loaded
if((!playing_music)||(music_sample==NULL))
{ //Fill stream with silence
memset(stream,0,len);
return;
}

while(len>0)
{ /* Play a music file: /
if (music_sample->flags&SOUND_SAMPLEFLAG_EOF))
{ /
End of file: */
Sound_Rewind(music_sample);
}

 //If we've used up the previously decoded sound:
 if(soundAvailable==soundUsed)
 {
    soundUsed=0;
    soundAvailable=Sound_Decode(music_sample);

    if(soundAvailable==0)
    { //Go back to the top of the while look to catch EOF
       continue;
    }
    else if(soundAvailable<0) //An error occured?
    {  //Stop playing of music
       playing_music=0;
       soundAvailable=0;
       soundUsed=0;

       //Fill the remainder of the stream with silence
       memset(stream,0,len);
       return;
    }
 }

 size=soundAvailable-soundUsed;
 if(size>len) size=len;     //Don't copy more than stream can hold

 //Copy data into stream
 memcpy(stream,((Uint8 *)(music_sample->buffer))+soundUsed,size);

 //Decrement length
 len-=size;

 //Increment amount used, stream
 soundUsed+=size;
 stream+=size;

}
} /* myMusicPlayer */

That’s nearly verbatim the routine I’m using for my experiments with SDL_sound
streaming in SDL_mixer… it ought to work for any format, as long as the
format you specified in Sound_NewSample matches the mixer format.

Thanks guys, now everything works!

The problem was (as you said) that I wasn’t initializing SDL_mixer and
SDL_sound with the same number of channels.