 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
dr_watson
Joined: 28 Nov 2005 Posts: 42
|
Posted: Fri Sep 29, 2006 11:57 am Post subject: 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 @_@):
| Code: |
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! |
|
| Back to top |
|
 |
bpoint

Joined: 10 Mar 2005 Posts: 24 Location: Okinawa, Japan
|
Posted: Tue Oct 10, 2006 5:28 pm Post subject: |
|
|
Your hack does not do what you think it does. libmikmod does not "somehow" mix the two channels together -- you simply set the playback sample rate to twice the speed of the original sample:
| Code: | | si->speed = wh.nSamplesPerSec*wh.nChannels; // @_@: changed from (/) to (*) |
This means a 44100hz sample will be played back at 88200hz, effectively skipping every other sample -- which happens to be the right channel since the data is interleaved. So all your patch is doing is allowing libmikmod to load a stereo sample and play back only the left channel.
If you use this hack and try to change the sample rate to anything other than the default, the skipped right channel will be intermixed with the left and will sound very strange. |
|
| Back to top |
|
 |
dr_watson
Joined: 28 Nov 2005 Posts: 42
|
Posted: Thu Oct 12, 2006 1:28 pm Post subject: |
|
|
| bpoint wrote: | Your hack does not do what you think it does. libmikmod does not "somehow" mix the two channels together -- you simply set the playback sample rate to twice the speed of the original sample:
| Code: | | si->speed = wh.nSamplesPerSec*wh.nChannels; // @_@: changed from (/) to (*) |
This means a 44100hz sample will be played back at 88200hz, effectively skipping every other sample -- which happens to be the right channel since the data is interleaved. So all your patch is doing is allowing libmikmod to load a stereo sample and play back only the left channel.
If you use this hack and try to change the sample rate to anything other than the default, the skipped right channel will be intermixed with the left and will sound very strange. |
well... I'm afraid this is not 100% correct though. I tested the hack with a WAV file that has different sounds at left and right channel. When I played it, I could hear BOTH sounds at both ears. From your theory, I should have heard the sound from the left channel only. Any ideas? |
|
| Back to top |
|
 |
Raphael

Joined: 17 Jan 2006 Posts: 646 Location: Germany
|
Posted: Thu Oct 12, 2006 4:53 pm Post subject: |
|
|
| Quote: | | When I played it, I could hear BOTH sounds at both ears. From your theory, I should have heard the sound from the left channel only. Any ideas? | Yes, because it doesn't skip samples when the sample rate is higher then the number of samples in the stream would suggest, it would only read the first half of the stream and output that at double speed. This then compensates for the half playback speed induced when playing double the number of channels without real stereo output (mono played back on stereo speakers will be output at both sides - it would not make sense to play a mono title only on one side, since mono doesn't mean only left or right, but rather "center"). So what you get with your hack is playing the left and right signals on both sides at double rate, thus creating your "mixing" (which only happens in your ears, not in libmikmod or the psp). If you want real stereo playback, you'd need to keep the si->speed at the normal speed (no / or *) and adjust the output functions of libmikmod to tell the psp that the incoming samples are indeed stereo (so the appropriate samples will be sent to the appropriate sides).
Regards,
Raphael _________________ <Don't push the river, it flows.>
http://wordpress.fx-world.org - my devblog
http://wiki.fx-world.org - VFPU documentation wiki
Alexander Berl |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|