Problem with MODPLUG Code!

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
theHobbit
Posts: 65
Joined: Sat Sep 30, 2006 5:26 am

Problem with MODPLUG Code!

Post by theHobbit »

Hi there, i'm porting modplug for my GameMusicGear app, but i'm having some problems with the amf format. I'm using psplink and a psp slim for testing.

Ok the code looks like this:

Code: Select all

#define bswapLE16(X) (X)
#define READU16&#40;X&#41;		 &#40;&#40;&#40;&#40;unsigned short&#41;&#40;&#40;X&#41;&#91;0&#93;&#41;&#41;<<0&#41; | \
											  &#40;&#40;&#40;unsigned short&#41;&#40;&#40;X&#41;&#91;1&#93;&#41;&#41;<<8&#41; &#41;

BOOL CSoundFile&#58;&#58;ReadAMF&#40;LPCBYTE lpStream, DWORD dwMemLength&#41;
//-----------------------------------------------------------
&#123;
	AMFFILEHEADER *pfh = &#40;AMFFILEHEADER *&#41;lpStream;
	DWORD dwMemPos;
	
	if &#40;&#40;!lpStream&#41; || &#40;dwMemLength < 2048&#41;&#41; return FALSE;
	if &#40;&#40;!strncmp&#40;&#40;LPCTSTR&#41;lpStream, "ASYLUM Music Format V1.0", 25&#41;&#41; && &#40;dwMemLength > 4096&#41;&#41;
	&#123;
		UINT numorders, numpats, numsamples;

		dwMemPos = 32;
		numpats = lpStream&#91;dwMemPos+3&#93;;
		numorders = lpStream&#91;dwMemPos+4&#93;;
		numsamples = 64;
		dwMemPos += 6;
		if &#40;&#40;!numpats&#41; || &#40;numpats > MAX_PATTERNS&#41; || &#40;!numorders&#41;
		 || &#40;numpats*64*32 + 294 + 37*64 >= dwMemLength&#41;&#41; return FALSE;
		m_nType = MOD_TYPE_AMF0;
		m_nChannels = 8;
		m_nInstruments = 0;
		m_nSamples = 31;
		m_nDefaultTempo = 125;
		m_nDefaultSpeed = 6;
		for &#40;UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++&#41;
		&#123;
			Order&#91;iOrd&#93; = &#40;iOrd < numorders&#41; ? lpStream&#91;dwMemPos+iOrd&#93; &#58; 0xFF;
		&#125;
		dwMemPos = 294; // ???
		for &#40;UINT iSmp=0; iSmp<numsamples; iSmp++&#41;
		&#123;
			MODINSTRUMENT *psmp = &Ins&#91;iSmp+1&#93;;
			memcpy&#40;m_szNames&#91;iSmp+1&#93;, lpStream+dwMemPos, 22&#41;;
			psmp->nFineTune = MOD2XMFineTune&#40;lpStream&#91;dwMemPos+22&#93;&#41;;
			psmp->nVolume = lpStream&#91;dwMemPos+23&#93;;
			psmp->nGlobalVol = 64;
			if &#40;psmp->nVolume > 0x40&#41; psmp->nVolume = 0x40;
			psmp->nVolume <<= 2;
			psmp->nLength = READU32&#40;lpStream+dwMemPos+25&#41;;
			psmp->nLoopStart = READU32&#40;lpStream+dwMemPos+29&#41;;
			psmp->nLoopEnd = psmp->nLoopStart + READU32&#40;lpStream+dwMemPos+33&#41;;
			if &#40;&#40;psmp->nLoopEnd > psmp->nLoopStart&#41; && &#40;psmp->nLoopEnd <= psmp->nLength&#41;&#41;
			&#123;
				psmp->uFlags = CHN_LOOP;
			&#125; else
			&#123;
				psmp->nLoopStart = psmp->nLoopEnd = 0;
			&#125;
			if &#40;&#40;psmp->nLength&#41; && &#40;iSmp>31&#41;&#41; m_nSamples = iSmp+1;
			dwMemPos += 37;
		&#125;
		
		for &#40;UINT iPat=0; iPat<numpats; iPat++&#41;
		&#123;
			MODCOMMAND *p = AllocatePattern&#40;64, m_nChannels&#41;;
			if &#40;!p&#41; break;
			Patterns&#91;iPat&#93; = p;
			PatternSize&#91;iPat&#93; = 64;
			const UCHAR *pin = lpStream + dwMemPos;
			for &#40;UINT i=0; i<8*64; i++&#41;
			&#123;
				p->note = 0;

				if &#40;pin&#91;0&#93;&#41;
				&#123;
					p->note = pin&#91;0&#93; + 13;
				&#125;
				p->instr = pin&#91;1&#93;;
				p->command = pin&#91;2&#93;;
				p->param = pin&#91;3&#93;;
				if &#40;p->command > 0x0F&#41;
				&#123;
				#ifdef AMFLOG
					Log&#40;"0x%02X.0x%02X ?", p->command, p->param&#41;;
				#endif
					p->command = 0;
				&#125;
				ConvertModCommand&#40;p&#41;;
				pin += 4;
				p++;
			&#125;
			dwMemPos += 64*32;
		&#125;
		// Read samples
		for &#40;UINT iData=0; iData<m_nSamples; iData++&#41;
		&#123;
			MODINSTRUMENT *psmp = &Ins&#91;iData+1&#93;;
			if &#40;psmp->nLength&#41;
			&#123;
				dwMemPos += ReadSample&#40;psmp, RS_PCM8S, &#40;LPCSTR&#41;&#40;lpStream+dwMemPos&#41;, dwMemLength&#41;;
			&#125;
		&#125;
		return TRUE;
	&#125;
	
	////////////////////////////
	// DSM/AMF
	USHORT *ptracks&#91;MAX_PATTERNS&#93;;
	DWORD sampleseekpos&#91;MAX_SAMPLES&#93;;

	if &#40;&#40;pfh->szAMF&#91;0&#93; != 'A'&#41; || &#40;pfh->szAMF&#91;1&#93; != 'M'&#41; || &#40;pfh->szAMF&#91;2&#93; != 'F'&#41;
	 || &#40;pfh->version < 10&#41; || &#40;pfh->version > 14&#41; || &#40;!bswapLE16&#40;pfh->numtracks&#41;&#41;
	 || &#40;!pfh->numorders&#41; || &#40;pfh->numorders > MAX_PATTERNS&#41;
	 || &#40;!pfh->numsamples&#41; || &#40;pfh->numsamples > MAX_SAMPLES&#41;
	 || &#40;pfh->numchannels < 4&#41; || &#40;pfh->numchannels > 32&#41;&#41;
		return FALSE;
	memcpy&#40;m_szNames&#91;0&#93;, pfh->title, 32&#41;;
	dwMemPos = sizeof&#40;AMFFILEHEADER&#41;;
	m_nType = MOD_TYPE_AMF;
	m_nChannels = pfh->numchannels;
	m_nSamples = pfh->numsamples;
	m_nInstruments = 0;
	// Setup Channel Pan Positions
	if &#40;pfh->version >= 11&#41;
	&#123;
		signed char *panpos = &#40;signed char *&#41;&#40;lpStream + dwMemPos&#41;;
		UINT nchannels = &#40;pfh->version >= 13&#41; ? 32 &#58; 16;
		for &#40;UINT i=0; i<nchannels; i++&#41;
		&#123;
			int pan = &#40;panpos&#91;i&#93; + 64&#41; * 2;
			if &#40;pan < 0&#41; pan = 0;
			if &#40;pan > 256&#41; &#123; pan = 128; ChnSettings&#91;i&#93;.dwFlags |= CHN_SURROUND; &#125;
			ChnSettings&#91;i&#93;.nPan = pan;
		&#125;
		dwMemPos += nchannels;
	&#125; else
	&#123;
		for &#40;UINT i=0; i<16; i++&#41;
		&#123;
			ChnSettings&#91;i&#93;.nPan = &#40;lpStream&#91;dwMemPos+i&#93; & 1&#41; ? 0x30 &#58; 0xD0;
		&#125;
		dwMemPos += 16;
	&#125;
	
	// Get Tempo/Speed
	m_nDefaultTempo = 125;
	m_nDefaultSpeed = 6;
	if &#40;pfh->version >= 13&#41;
	&#123;
		if &#40;lpStream&#91;dwMemPos&#93; >= 32&#41; m_nDefaultTempo = lpStream&#91;dwMemPos&#93;;
		if &#40;lpStream&#91;dwMemPos+1&#93; <= 32&#41; m_nDefaultSpeed = lpStream&#91;dwMemPos+1&#93;;
		dwMemPos += 2;
	&#125;
	
	// Setup sequence list
	for &#40;UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++&#41;
	&#123;
		Order&#91;iOrd&#93; = 0xFF;
		if &#40;iOrd < pfh->numorders&#41;
		&#123;
			Order&#91;iOrd&#93; = iOrd;
			PatternSize&#91;iOrd&#93; = 64;
			if &#40;pfh->version >= 14&#41;
			&#123;
				PatternSize&#91;iOrd&#93; = READU16&#40;lpStream+dwMemPos&#41;;
				dwMemPos += 2;
			&#125;
			ptracks&#91;iOrd&#93; = &#40;USHORT *&#41;&#40;lpStream+dwMemPos&#41;;
			dwMemPos += m_nChannels * sizeof&#40;USHORT&#41;;
		&#125;
	&#125;
	
	if &#40;dwMemPos + m_nSamples * &#40;sizeof&#40;AMFSAMPLE&#41;+8&#41; > dwMemLength&#41; return TRUE;
	// Read Samples
	UINT maxsampleseekpos = 0;
	
	for &#40;UINT iIns=0; iIns<m_nSamples; iIns++&#41;
	&#123;
		MODINSTRUMENT *pins = &Ins&#91;iIns+1&#93;;
		AMFSAMPLE *psh = &#40;AMFSAMPLE *&#41;&#40;lpStream + dwMemPos&#41;;

		dwMemPos += sizeof&#40;AMFSAMPLE&#41;;
		memcpy&#40;m_szNames&#91;iIns+1&#93;, psh->samplename, 32&#41;;
		memcpy&#40;pins->name, psh->filename, 13&#41;;
		pins->nLength = bswapLE32&#40;psh->length&#41;;
		pins->nC4Speed = bswapLE16&#40;psh->c2spd&#41;;
		pins->nGlobalVol = 64;
		pins->nVolume = psh->volume * 4;
		if &#40;pfh->version >= 11&#41;
		&#123;
			pins->nLoopStart = READU32&#40;lpStream+dwMemPos&#41;;
			pins->nLoopEnd = READU32&#40;lpStream+dwMemPos+4&#41;;
			dwMemPos += 8;
		&#125; else
		&#123;
			pins->nLoopStart = READU16&#40;lpStream+dwMemPos&#41;;
			pins->nLoopEnd = pins->nLength;
			dwMemPos += 2;
		&#125;
		sampleseekpos&#91;iIns&#93; = 0;
		if &#40;&#40;psh->type&#41; && &#40;bswapLE32&#40;psh->offset&#41; < dwMemLength-1&#41;&#41;
		&#123;
			sampleseekpos&#91;iIns&#93; = bswapLE32&#40;psh->offset&#41;;
			if &#40;bswapLE32&#40;psh->offset&#41; > maxsampleseekpos&#41; 
				maxsampleseekpos = bswapLE32&#40;psh->offset&#41;;
			if &#40;&#40;pins->nLoopEnd > pins->nLoopStart + 2&#41;
			 && &#40;pins->nLoopEnd <= pins->nLength&#41;&#41; pins->uFlags |= CHN_LOOP;
		&#125;
	&#125;
	// Read Track Mapping Table
	USHORT *pTrackMap = &#40;USHORT *&#41;&#40;lpStream+dwMemPos&#41;;
	UINT realtrackcnt = 0;
	dwMemPos += pfh->numtracks * sizeof&#40;USHORT&#41;;
	for &#40;UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++&#41;
	&#123;
		if &#40;realtrackcnt < pTrackMap&#91;iTrkMap&#93;&#41; realtrackcnt = pTrackMap&#91;iTrkMap&#93;;
	&#125;
	// Store tracks positions
	BYTE **pTrackData = new BYTE *&#91;realtrackcnt&#93;;
	memset&#40;pTrackData, 0, sizeof&#40;pTrackData&#41;&#41;;
	for &#40;UINT iTrack=0; iTrack<realtrackcnt; iTrack++&#41; if &#40;dwMemPos + 3 <= dwMemLength&#41;
	&#123;
		UINT nTrkSize = READU16&#40;lpStream+dwMemPos&#41;;
		nTrkSize += &#40;UINT&#41;lpStream&#91;dwMemPos+2&#93; << 16;

		if &#40;dwMemPos + nTrkSize * 3 + 3 <= dwMemLength&#41;
		&#123;
			pTrackData&#91;iTrack&#93; = &#40;BYTE *&#41;&#40;lpStream + dwMemPos&#41;;
		&#125;
		dwMemPos += nTrkSize * 3 + 3;
	&#125;
	// Create the patterns from the list of tracks
	for &#40;UINT iPat=0; iPat<pfh->numorders; iPat++&#41;
	&#123;
		MODCOMMAND *p;
		p = AllocatePattern&#40;PatternSize&#91;iPat&#93;, m_nChannels&#41;;
		if &#40;!p&#41; break;
		Patterns&#91;iPat&#93; = p;
		for &#40;UINT iChn=0; iChn<m_nChannels; iChn++&#41;
		&#123;
			fprintf&#40;stderr, "foo error\n"&#41;;
			UINT nTrack = bswapLE16&#40;ptracks&#91;iPat&#93;&#91;iChn&#93;&#41;;
			if &#40;&#40;nTrack&#41; && &#40;nTrack <= pfh->numtracks&#41;&#41;
			&#123;
				UINT realtrk = bswapLE16&#40;pTrackMap&#91;nTrack-1&#93;&#41;;
				if &#40;realtrk&#41;
				&#123;
					realtrk--;
					if &#40;&#40;realtrk < realtrackcnt&#41; && &#40;pTrackData&#91;realtrk&#93;&#41;&#41;
					&#123;
						AMF_Unpack&#40;p+iChn, pTrackData&#91;realtrk&#93;, PatternSize&#91;iPat&#93;, m_nChannels&#41;;
					&#125;
				&#125;
			&#125;
		&#125;
	&#125;
	delete pTrackData;
	// Read Sample Data
	for &#40;UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++&#41;
	&#123;
		if &#40;dwMemPos >= dwMemLength&#41; break;
		for &#40;UINT iSmp=0; iSmp<m_nSamples; iSmp++&#41; if &#40;iSeek == sampleseekpos&#91;iSmp&#93;&#41;
		&#123;
			MODINSTRUMENT *pins = &Ins&#91;iSmp+1&#93;;
			dwMemPos += ReadSample&#40;pins, RS_PCM8U, &#40;LPCSTR&#41;&#40;lpStream+dwMemPos&#41;, dwMemLength-dwMemPos&#41;;
			break;
		&#125;
	&#125;
	return TRUE;
&#125;
The code gives an addres load/inst fetch exception in the line after the "foo error" message:
UINT nTrack = bswapLE16(ptracks[iPat][iChn]);

Well i have tried to understand whats hapenning but i have only found that the problem is with the ptracks pointer array and that the exception occurs exactly in that line :|.

And also does anyone knows how to use the psp-addr2line in a prx? Well hope anyone can help
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Code: Select all

         ptracks&#91;iOrd&#93; = &#40;USHORT *&#41;&#40;lpStream+dwMemPos&#41;;
is probably odd, so

Code: Select all

         UINT nTrack = bswapLE16&#40;ptracks&#91;iPat&#93;&#91;iChn&#93;&#41;;
is generating an unaligned access exception. You can't fetch unaligned data on the MIPS. Data has to be on its natural alignment.
theHobbit
Posts: 65
Joined: Sat Sep 30, 2006 5:26 am

Post by theHobbit »

Thanks for your answer, i have tried changing USHORT by BYTE and it works but the song is playing weird. Am i missing something? Do you know how can I fix the unaligned issue? Thanks in advance!
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

ptracks[][] is a word, so simply changing it to a byte doesn't fetch all the data. Look at the macro from the code again:

Code: Select all

#define READU16&#40;X&#41;       &#40;&#40;&#40;&#40;unsigned short&#41;&#40;&#40;X&#41;&#91;0&#93;&#41;&#41;<<0&#41; | \
                                   &#40;&#40;&#40;unsigned short&#41;&#40;&#40;X&#41;&#91;1&#93;&#41;&#41;<<8&#41; &#41;
See what it does? It fetches a word by getting the two bytes and putting them together. That's what you need to do to get unaligned words. Any place in the code that gets a word needs to fetch it as two bytes unless you KNOW the pointer is word aligned.
theHobbit
Posts: 65
Joined: Sat Sep 30, 2006 5:26 am

Post by theHobbit »

Thanks, i have solved it doing this:

Code: Select all

UINT nTrack = bswapLE16&#40;ptracks&#91;iPat&#93;&#91;iChn*sizeof&#40;USHORT&#41;&#93;&#41;;
But well i don't know if it's the best solution :)
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

theHobbit wrote:Thanks, i have solved it doing this:

Code: Select all

UINT nTrack = bswapLE16&#40;ptracks&#91;iPat&#93;&#91;iChn*sizeof&#40;USHORT&#41;&#93;&#41;;
But well i don't know if it's the best solution :)
That only makes it skip entries in the array. You need to go back through the code and find every place the STREAM is accessed and make sure that access is via byte accesses, not words or longs.
Post Reply