QJ.NET | Videos | Forums | iPhone | MMORPG | Nintendo DS | Wii | PlayStation 3 | PSP | Xbox 360 | PC | Downloads | Contact Us
Forums | Gaming News | Videos | Downloads | Today's Posts | Mark Forums Read | Chat | FAQ | Members List | Contact

QJ.net Game Discussion - PSP, Xbox, Wii, PS3, PSP Homebrew, and PSP Guides

Go Back   QJ.net Game Discussion - PSP, Xbox, Wii, PS3, PSP Homebrew, and PSP Guides > Developers Corner > PSP Development, Hacks, and Homebrew > PSP Development Forum
The above video goes away if you are a member and logged in, so log in now!

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

This is a discussion on A small hack to enable libmikmod to play 2-channel PCM files within the PSP Development Forum forums, part of the PSP Development, Hacks, and Homebrew category; libmikmod (or mikmodlib) is pretty good but it only supports mono PCM (Wav) files at the moment. You'll get a ...

Reply
 
LinkBack Thread Tools
Old 09-28-2006, 07:33 PM   #1
 
Join Date: Dec 2005
Posts: 29
Trader Feedback: 0
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 @_@):

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!
__________________
[url="http://jge.khors.com/"]JGE++ forums[/url]

Last edited by dr_watson; 09-28-2006 at 07:44 PM..
dr_watson is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Old 09-28-2006, 07:55 PM   #2
 
FreePlay's Avatar
 
Join Date: Dec 2005
Location: h0000000rj
Posts: 12,858
Trader Feedback: 0
Default

Very nice hack!
__________________
[qj now fails.]
FreePlay is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Old 09-28-2006, 08:15 PM   #3
Art

Bush Programmer
 
Art's Avatar
 
Join Date: Nov 2005
Posts: 3,557
Trader Feedback: 0
Default

How is that any different that using the pan variable to play a mono file
through both speakers?
Code:
int pan = 127;

voice = Sample_Play(sf,0,0);
Voice_SetVolume(voice, vol);
Voice_SetPanning(voice, pan);
-= Double Post =-
Personally, what I find interesting is it appears you loaded the sample from memory
rather than from a file,
care to share?

Last edited by Art; 09-28-2006 at 08:15 PM.. Reason: Automerged Doublepost
Art is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Old 09-28-2006, 08:26 PM   #4
 
FreePlay's Avatar
 
Join Date: Dec 2005
Location: h0000000rj
Posts: 12,858
Trader Feedback: 0
Default

Quote:
Originally Posted by Art
How is that any different that using the pan variable to play a mono file
through both speakers?
... Um... well, this is playing a stereo file through both speakers, in mono... while before it wouldn't even open a stereo file. Something like that, from what I gleaned.
__________________
[qj now fails.]
FreePlay is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Old 09-28-2006, 08:58 PM   #5
Art

Bush Programmer
 
Art's Avatar
 
Join Date: Nov 2005
Posts: 3,557
Trader Feedback: 0
Default

That's right, but it seems a long way round to reencoding the wav file as mono
for use in a PSP program, unless for some reason you are being forced to read stereo files.
... I'm not trying to be an ahole, I just wonder why that approach...
Art is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Old 09-29-2006, 12:25 AM   #6
 
Join Date: Dec 2005
Posts: 29
Trader Feedback: 0
Default

I'd just like to load the proper "stereo" wav files since I'm using the same wav files for both PSP and PC version of the same game. On the PC side I'm using fmod and of course it plays the wav files in real stereo.

Sure it'll be much better if someone can actually do a proper hack to enable libmikmod to play real stereo noises
__________________
[url="http://jge.khors.com/"]JGE++ forums[/url]
dr_watson is offline  
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply

Tags
2channel , enable , files , hack , libmikmod , pcm , play , small

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off



All times are GMT -8. The time now is 09:44 AM.



Use of this Web site constitutes acceptance of the TERMS & CONDITIONS and PRIVACY POLICY
Copyright © 2009, QJ.NET. All Rights Reserved.
Contact Us