gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Calling for help to fix SDL_Mixer

#173342 - protomank - Fri Apr 02, 2010 12:04 pm

Is there anyone with free time and will to help me to fix the SDL_Mixer?

Currently, the problem is in wave reading, in this part of the code:

Code:

#define SDL_RWread(ctx, ptr, size, n)   (ctx)->read(ctx, ptr, size, n)

static int ReadChunk(SDL_RWops *src, Chunk *chunk)
{
   chunk->magic   = SDL_ReadLE32(src);
   chunk->length   = SDL_ReadLE32(src);
   chunk->data = (Uint8 *)malloc(chunk->length);
   if ( chunk->data == NULL ) {
      SDL_Error(SDL_ENOMEM);
      return(-1);
   }
   if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
      SDL_Error(SDL_EFREAD);
      free(chunk->data);
      return(-1);
   }
   return(chunk->length);
}


It is always returning SDL_EFREAD. Here is the big function that call ReadChunk:


Code:
SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc,
      SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
   int was_error;
   Chunk chunk;
   int lenread;
   int MS_ADPCM_encoded, IMA_ADPCM_encoded;
   int samplesize;

   /* WAV magic header */
   Uint32 RIFFchunk;
   Uint32 wavelen;
   Uint32 WAVEmagic;

   /* FMT chunk */
   WaveFMT *format = NULL;

   /* Make sure we are passed a valid data source */
   was_error = 0;
   if ( src == NULL ) {
      was_error = 1;
      goto done;
   }
      
   /* Check the magic header */
   RIFFchunk   = SDL_ReadLE32(src);
   wavelen      = SDL_ReadLE32(src);
   if ( wavelen == WAVE ) { /* The RIFFchunk has already been read */
      WAVEmagic = wavelen;
      wavelen   = RIFFchunk;
      RIFFchunk = RIFF;
   } else {
      WAVEmagic = SDL_ReadLE32(src);
   }
   if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
      SDL_SetError("Unrecognized file type (not WAVE)");
      was_error = 1;
      goto done;
   }

   /* Read the audio data format chunk */
   chunk.data = NULL;
   do {
      if ( chunk.data != NULL ) {
         free(chunk.data);
      }
      lenread = ReadChunk(src, &chunk);
      if ( lenread < 0 ) {
         was_error = 1;
         goto done;
      }
   } while ( (chunk.magic == FACT) || (chunk.magic == LIST) );

   /* Decode the audio data format */
   format = (WaveFMT *)chunk.data;
   if ( chunk.magic != FMT ) {
      SDL_SetError("Complex WAVE files not supported");
      was_error = 1;
      goto done;
   }
   MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
   switch (SDL_SwapLE16(format->encoding)) {
      case PCM_CODE:
         /* We can understand this */
         break;
      case MS_ADPCM_CODE:
         /* Try to understand this */
         if ( InitMS_ADPCM(format) < 0 ) {
            was_error = 1;
            goto done;
         }
         MS_ADPCM_encoded = 1;
         break;
      case IMA_ADPCM_CODE:
         /* Try to understand this */
         if ( InitIMA_ADPCM(format) < 0 ) {
            was_error = 1;
            goto done;
         }
         IMA_ADPCM_encoded = 1;
         break;
      default:
         SDL_SetError("Unknown WAVE data format: 0x%.4x",
               SDL_SwapLE16(format->encoding));
         was_error = 1;
         goto done;
   }
   memset(spec, 0, (sizeof *spec));
   spec->freq = SDL_SwapLE32(format->frequency);
   switch (SDL_SwapLE16(format->bitspersample)) {
      case 4:
         if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) {
            spec->format = AUDIO_S16;
         } else {
            was_error = 1;
         }
         break;
      case 8:
         spec->format = AUDIO_U8;
         break;
      case 16:
         spec->format = AUDIO_S16;
         break;
      default:
         was_error = 1;
         break;
   }
   if ( was_error ) {
      SDL_SetError("Unknown %d-bit PCM data format",
         SDL_SwapLE16(format->bitspersample));
      goto done;
   }
   spec->channels = (Uint8)SDL_SwapLE16(format->channels);
   spec->samples = 4096;      /* Good default buffer size */

   /* Read the audio data chunk */
   *audio_buf = NULL;
   do {
      if ( *audio_buf != NULL ) {
         free(*audio_buf);
      }
      lenread = ReadChunk(src, &chunk);
      if ( lenread < 0 ) {
         was_error = 1;
         goto done;
      }
      *audio_len = lenread;
      *audio_buf = chunk.data;
   } while ( chunk.magic != DATA );

   if ( MS_ADPCM_encoded ) {
      if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) {
         was_error = 1;
         goto done;
      }
   }
   if ( IMA_ADPCM_encoded ) {
      if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) {
         was_error = 1;
         goto done;
      }
   }

   /* Don't return a buffer that isn't a multiple of samplesize */
   samplesize = ((spec->format & 0xFF)/8)*spec->channels;
   *audio_len &= ~(samplesize-1);

done:
   if ( format != NULL ) {
      free(format);
   }
   if ( freesrc && src ) {
      SDL_RWclose(src);
   }
   if ( was_error ) {
      spec = NULL;
   }
   return(spec);
}


The struct that contains the wave (I believe the problem is here):

Code:

typedef struct SDL_RWops {
   /* Seek to 'offset' relative to whence, one of stdio's whence values:
      SEEK_SET, SEEK_CUR, SEEK_END
      Returns the final offset in the data source.
    */
   int (SDLCALL *seek)(struct SDL_RWops *context, int offset, int whence);

   /* Read up to 'num' objects each of size 'objsize' from the data
      source to the area pointed at by 'ptr'.
      Returns the number of objects read, or -1 if the read failed.
    */
   int (SDLCALL *read)(struct SDL_RWops *context, void *ptr, int size, int maxnum);

   /* Write exactly 'num' objects each of size 'objsize' from the area
      pointed at by 'ptr' to data source.
      Returns 'num', or -1 if the write failed.
    */
   int (SDLCALL *write)(struct SDL_RWops *context, const void *ptr, int size, int num);

   /* Close and free an allocated SDL_FSops structure */
   int (SDLCALL *close)(struct SDL_RWops *context);

   Uint32 type;
   union {
       struct {
      int autoclose;
       FILE *fp;
       } stdio;
       struct {
      Uint8 *base;
       Uint8 *here;
      Uint8 *stop;
       } mem;
       struct {
      void *data1;
       } unknown;
   } hidden;

} SDL_RWops;



It does not seem too complex to fix, but I lack any knowledge about wave format :-(
_________________
Iuri Fiedoruk
http://rockbot.upperland.net

#173344 - wintermute - Fri Apr 02, 2010 12:12 pm

You'll be much better off getting rid of SDL, it's really not suited to the DS at all.
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#173346 - protomank - Fri Apr 02, 2010 12:39 pm

No, thanks!!!!

Reason is that SDL is GREAT, VERY GREAT for multi-platform. Currently I have ports for Windows, Linux, Mac, playstation 2 and Nintendo DS. I know that with little time I can also port it to Wii and XBox. Also, it currently runs very, very well on the DS, except for the sound part.

I can't use maxmod, because there is a conflict, mas both it and SDL seems to be using the same IRQs, so I my game get stucks when updating a stream in maxmod.
_________________
Iuri Fiedoruk
http://rockbot.upperland.net

#173358 - Dwedit - Fri Apr 02, 2010 5:47 pm

Maybe someone should make a LibNDS-like API that runs on top of SDL when compiled on anything other than the NDS? Nothing like debugging your NDS code with Visual C++. Like an emulator without emulating the CPU (except maybe for running ARM ASM code included in the program).
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#173360 - elhobbs - Fri Apr 02, 2010 6:09 pm

why do you think the problem lies with SDL_RWops?

#173365 - protomank - Fri Apr 02, 2010 7:59 pm

Because this is the part that files:

Code:
if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
      SDL_Error(SDL_EFREAD);


I've used multiple wayrs of opening the file, like loading it to memory first, and in all the cases I got SDL_EFREAD in the end.
Sure, this is just what I got by backtracing the problem, Iit is a bit hard, once when SDL is initializwed, I can't see the printfs anymore, and for some reason, redirecting stdout to a file always produce a empty one. If I had a way to bebug, or communicate with the DS like I do with PS2 (it uses a program called ps2client), probally it would be easier.
_________________
Iuri Fiedoruk
http://rockbot.upperland.net

#173374 - elhobbs - Sat Apr 03, 2010 4:10 am

SDL_RWread is just a wrapper for fread. fread returns the number of bytes read. In this case it is trying to read 1 byte from the file. This code is verifying that the read is completing successfully it is not verifying what was read. Are you sure that libfat has been I initialized properly by calling fatInitDefault? Does your device auto dldi patch or do you need to do it manually?

#173375 - protomank - Sat Apr 03, 2010 4:59 am

Libfat is not the problem. I did placed debug to check if fopen is working (ok), if it was loaded into memory (ok) if load_wav got it (ok), but when it tryies to play, it complains that the stream is bad.

SDL_RWread actually sets the chunk->length of the sdl struct to the size of the data in stream, and that is the part that is not working.
_________________
Iuri Fiedoruk
http://rockbot.upperland.net

#173767 - protomank - Thu Apr 29, 2010 8:48 pm

So, actually no one wants to fix the SDL for Nintendo DS? Or at least, help me to do so with your expertise?
_________________
Iuri Fiedoruk
http://rockbot.upperland.net

#173769 - FluBBa - Thu Apr 29, 2010 9:31 pm

So, it expects chunk->length to not be 1 and still get 1 in return?
I haven't read up enough on how filereading works for that...
_________________
I probably suck, my not is a programmer.