Results 1 to 2 of 2

Thread: A small hack to enable libmikmod to play 2-channel PCM files

                  
   
  1. #1

    Default A small hack to enable libmikmod to play 2-channel PCM files

    libmikmod (or mikmodlib) is pretty good but it only supports mono PCM (Wav) files at the moment. You'll get a NULL pointer if trying to load a Wav file with 2 channels. Here is a small hack to make it load and play 2-channel Wav files. Technically speaking, this is not REAL stereo because, libmikmod somehow mixes the 2 channels together. But still, it's better than just having the sound effect played in your left ear only ;)

    All we need to do is just to modify few lines in mwav.c as shown below (marked with @_@):



    SAMPLE* Sample_LoadGeneric_internal(MREADER* reader)
    {
    SAMPLE *si=NULL;
    WAV wh;
    BOOL have_fmt=0;

    /* read wav header */
    _mm_read_string(wh.rID,4,reader);
    wh.rLen = _mm_read_I_ULONG(reader);
    _mm_read_string(wh.wID,4,reader);

    /* check for correct header */
    if(_mm_eof(reader)|| memcmp(wh.rID,"RIFF",4) || memcmp(wh.wID,"WAVE",4)) {
    _mm_errno = MMERR_UNKNOWN_WAVE_TYPE;
    return NULL;
    }

    /* scan all RIFF blocks until we find the sample data */
    for(;;) {
    CHAR dID[4];
    ULONG len,start;

    _mm_read_string(dID,4,reader);
    len = _mm_read_I_ULONG(reader);
    /* truncated file ? */
    if (_mm_eof(reader)) {
    _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
    return NULL;
    }
    start = _mm_ftell(reader);

    /* sample format block
    should be present only once and before a data block */
    if(!memcmp(dID,"fmt ",4)) {
    wh.wFormatTag = _mm_read_I_UWORD(reader);
    wh.nChannels = _mm_read_I_UWORD(reader);
    wh.nSamplesPerSec = _mm_read_I_ULONG(reader);
    wh.nAvgBytesPerSec = _mm_read_I_ULONG(reader);
    wh.nBlockAlign = _mm_read_I_UWORD(reader);
    wh.nFormatSpecific = _mm_read_I_UWORD(reader);

    #ifdef MIKMOD_DEBUG
    fprintf(stderr,"\rwavloader : wFormatTag=%04x blockalign=%04x nFormatSpc=%04x\n",
    wh.wFormatTag,wh.nBlockAlign,wh.nFormatSpecific);
    #endif

    if((have_fmt)||(wh.nChannels>2)) { // @_@: changed 1 to 2
    _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
    return NULL;
    }
    have_fmt=1;
    } else
    /* sample data block
    should be present only once and after a format block */
    if(!memcmp(dID,"data",4)) {

    int samp_size, num_samp; // @_@: newly added variables

    if(!have_fmt) {
    _mm_errno=MMERR_UNKNOWN_WAVE_TYPE;
    return NULL;
    }
    if(!(si=(SAMPLE*)_mm_malloc(sizeof(SAMPLE)))) return NULL;
    si->speed = wh.nSamplesPerSec*wh.nChannels; // @_@: changed from (/) to (*)
    si->volume = 64;
    si->length = len;

    samp_size = 1;
    if((wh.nBlockAlign/wh.nChannels) == 2) { // @_@: take into account the channel as well
    si->flags = SF_16BITS | SF_SIGNED;
    //si->length >>= 1; // @_@: keep the size
    samp_size = 2; // @_@: 16 bit sample
    }

    if (wh.nChannels == 2) // @_@: stereo
    si->flags |= SF_STEREO;

    num_samp = si->length/samp_size/wh.nChannels; // @_@: setting up proper values for si
    si->loopstart=0;
    si->length=num_samp;
    si->loopend=num_samp;
    si->panning = PAN_CENTER; // @_@: this one is the most important one!
    // was not initialized in the original code so
    // it default to PAN_LEFT

    si->inflags = si->flags;
    SL_RegisterSample(si,MD_SNDFX,reader);
    SL_LoadSamples();

    /* skip any other remaining blocks - so in case of repeated sample
    fragments, we'll return the first anyway instead of an error */
    break;
    }
    /* onto next block */
    _mm_fseek(reader,start+len,SEEK_SET);
    if (_mm_eof(reader))
    break;
    }

    return si;
    }

    I believe you can do the same hack to mikmodlib as well.

    Cheers!

    (btw.. the [ CODE ] [/ CODE ] tags seem to be broken)

  2. #2

    Default

    cool. Nice job.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •