diff src/modplug/load_far.cxx @ 136:6b5a52635b3b trunk

[svn] - like with so many other things, modplug is now maintained by us.
author nenolod
date Sun, 29 Oct 2006 01:04:52 -0700
parents
children 032053ca08ab 3673c7ec4ea2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modplug/load_far.cxx	Sun Oct 29 01:04:52 2006 -0700
@@ -0,0 +1,270 @@
+/*
+ * This source code is public domain.
+ *
+ * Authors: Olivier Lapicque <olivierl@jps.net>
+*/
+
+////////////////////////////////////////
+// Farandole (FAR) module loader	  //
+////////////////////////////////////////
+#include "stdafx.h"
+#include "sndfile.h"
+
+//#pragma warning(disable:4244)
+
+#define FARFILEMAGIC	0xFE524146	// "FAR"
+
+#pragma pack(1)
+
+typedef struct FARHEADER1
+{
+	DWORD id;				// file magic FAR=
+	CHAR songname[40];		// songname
+	CHAR magic2[3];			// 13,10,26
+	WORD headerlen;			// remaining length of header in bytes
+	BYTE version;			// 0xD1
+	BYTE onoff[16];
+	BYTE edit1[9];
+	BYTE speed;
+	BYTE panning[16];
+	BYTE edit2[4];
+	WORD stlen;
+} FARHEADER1;
+
+typedef struct FARHEADER2
+{
+	BYTE orders[256];
+	BYTE numpat;
+	BYTE snglen;
+	BYTE loopto;
+	WORD patsiz[256];
+} FARHEADER2;
+
+typedef struct FARSAMPLE
+{
+	CHAR samplename[32];
+	DWORD length;
+	BYTE finetune;
+	BYTE volume;
+	DWORD reppos;
+	DWORD repend;
+	BYTE type;
+	BYTE loop;
+} FARSAMPLE;
+
+#pragma pack()
+
+
+BOOL CSoundFile::ReadFAR(const BYTE *lpStream, DWORD dwMemLength)
+//---------------------------------------------------------------
+{
+	FARHEADER1 *pmh1 = (FARHEADER1 *)lpStream;
+	FARHEADER2 *pmh2;
+	DWORD dwMemPos = sizeof(FARHEADER1);
+	UINT headerlen;
+	BYTE samplemap[8];
+
+	if ((!lpStream) || (dwMemLength < 1024) || (bswapLE32(pmh1->id) != FARFILEMAGIC)
+	 || (pmh1->magic2[0] != 13) || (pmh1->magic2[1] != 10) || (pmh1->magic2[2] != 26)) return FALSE;
+	headerlen = bswapLE16(pmh1->headerlen);
+	pmh1->stlen = bswapLE16( pmh1->stlen ); /* inplace byteswap -- Toad */
+	if ((headerlen >= dwMemLength) || (dwMemPos + pmh1->stlen + sizeof(FARHEADER2) >= dwMemLength)) return FALSE;
+	// Globals
+	m_nType = MOD_TYPE_FAR;
+	m_nChannels = 16;
+	m_nInstruments = 0;
+	m_nSamples = 0;
+	m_nSongPreAmp = 0x20;
+	m_nDefaultSpeed = pmh1->speed;
+	m_nDefaultTempo = 80;
+	m_nDefaultGlobalVolume = 256;
+
+	memcpy(m_szNames[0], pmh1->songname, 32);
+	// Channel Setting
+	for (UINT nchpan=0; nchpan<16; nchpan++)
+	{
+		ChnSettings[nchpan].dwFlags = 0;
+		ChnSettings[nchpan].nPan = ((pmh1->panning[nchpan] & 0x0F) << 4) + 8;
+		ChnSettings[nchpan].nVolume = 64;
+	}
+	// Reading comment
+	if (pmh1->stlen)
+	{
+		UINT szLen = pmh1->stlen;
+		if (szLen > dwMemLength - dwMemPos) szLen = dwMemLength - dwMemPos;
+		if ((m_lpszSongComments = new char[szLen + 1]) != NULL)
+		{
+			memcpy(m_lpszSongComments, lpStream+dwMemPos, szLen);
+			m_lpszSongComments[szLen] = 0;
+		}
+		dwMemPos += pmh1->stlen;
+	}
+	// Reading orders
+	pmh2 = (FARHEADER2 *)(lpStream + dwMemPos);
+	dwMemPos += sizeof(FARHEADER2);
+	if (dwMemPos >= dwMemLength) return TRUE;
+	for (UINT iorder=0; iorder<MAX_ORDERS; iorder++)
+	{
+		Order[iorder] = (iorder <= pmh2->snglen) ? pmh2->orders[iorder] : 0xFF;
+	}
+	m_nRestartPos = pmh2->loopto;
+	// Reading Patterns	
+	dwMemPos += headerlen - (869 + pmh1->stlen);
+	if (dwMemPos >= dwMemLength) return TRUE;
+
+	// byteswap pattern data -- Toad
+	UINT psfix = 0 ;
+	while( psfix++ < 256 )
+	{
+		pmh2->patsiz[psfix] = bswapLE16( pmh2->patsiz[psfix] ) ;
+	}
+	// end byteswap of pattern data
+
+	WORD *patsiz = (WORD *)pmh2->patsiz;
+	for (UINT ipat=0; ipat<256; ipat++) if (patsiz[ipat])
+	{
+		UINT patlen = patsiz[ipat];
+		if ((ipat >= MAX_PATTERNS) || (patsiz[ipat] < 2))
+		{
+			dwMemPos += patlen;
+			continue;
+		}
+		if (dwMemPos + patlen >= dwMemLength) return TRUE;
+		UINT rows = (patlen - 2) >> 6;
+		if (!rows)
+		{
+			dwMemPos += patlen;
+			continue;
+		}
+		if (rows > 256) rows = 256;
+		if (rows < 16) rows = 16;
+		PatternSize[ipat] = rows;
+		if ((Patterns[ipat] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE;
+		MODCOMMAND *m = Patterns[ipat];
+		UINT patbrk = lpStream[dwMemPos];
+		const BYTE *p = lpStream + dwMemPos + 2;
+		UINT max = rows*16*4;
+		if (max > patlen-2) max = patlen-2;
+		for (UINT len=0; len<max; len += 4, m++)
+		{
+			BYTE note = p[len];
+			BYTE ins = p[len+1];
+			BYTE vol = p[len+2];
+			BYTE eff = p[len+3];
+			if (note)
+			{
+				m->instr = ins + 1;
+				m->note = note + 36;
+			}
+			if (vol & 0x0F)
+			{
+				m->volcmd = VOLCMD_VOLUME;
+				m->vol = (vol & 0x0F) << 2;
+				if (m->vol <= 4) m->vol = 0;
+			}
+			switch(eff & 0xF0)
+			{
+			// 1.x: Portamento Up
+			case 0x10:
+				m->command = CMD_PORTAMENTOUP;
+				m->param = eff & 0x0F;
+				break;
+			// 2.x: Portamento Down
+			case 0x20:
+				m->command = CMD_PORTAMENTODOWN;
+				m->param = eff & 0x0F;
+				break;
+			// 3.x: Tone-Portamento
+			case 0x30:
+				m->command = CMD_TONEPORTAMENTO;
+				m->param = (eff & 0x0F) << 2;
+				break;
+			// 4.x: Retrigger
+			case 0x40:
+				m->command = CMD_RETRIG;
+				m->param = 6 / (1+(eff&0x0F)) + 1;
+				break;
+			// 5.x: Set Vibrato Depth
+			case 0x50:
+				m->command = CMD_VIBRATO;
+				m->param = (eff & 0x0F);
+				break;
+			// 6.x: Set Vibrato Speed
+			case 0x60:
+				m->command = CMD_VIBRATO;
+				m->param = (eff & 0x0F) << 4;
+				break;
+			// 7.x: Vol Slide Up
+			case 0x70:
+				m->command = CMD_VOLUMESLIDE;
+				m->param = (eff & 0x0F) << 4;
+				break;
+			// 8.x: Vol Slide Down
+			case 0x80:
+				m->command = CMD_VOLUMESLIDE;
+				m->param = (eff & 0x0F);
+				break;
+			// A.x: Port to vol
+			case 0xA0:
+				m->volcmd = VOLCMD_VOLUME;
+				m->vol = ((eff & 0x0F) << 2) + 4;
+				break;
+			// B.x: Set Balance
+			case 0xB0:
+				m->command = CMD_PANNING8;
+				m->param = (eff & 0x0F) << 4;
+				break;
+			// F.x: Set Speed
+			case 0xF0:
+				m->command = CMD_SPEED;
+				m->param = eff & 0x0F;
+				break;
+			default:
+				if ((patbrk) &&	(patbrk+1 == (len >> 6)) && (patbrk+1 != rows-1))
+				{
+					m->command = CMD_PATTERNBREAK;
+					patbrk = 0;
+				}
+			}
+		}
+		dwMemPos += patlen;
+	}
+	// Reading samples
+	if (dwMemPos + 8 >= dwMemLength) return TRUE;
+	memcpy(samplemap, lpStream+dwMemPos, 8);
+	dwMemPos += 8;
+	MODINSTRUMENT *pins = &Ins[1];
+	for (UINT ismp=0; ismp<64; ismp++, pins++) if (samplemap[ismp >> 3] & (1 << (ismp & 7)))
+	{
+		if (dwMemPos + sizeof(FARSAMPLE) > dwMemLength) return TRUE;
+		FARSAMPLE *pfs = (FARSAMPLE *)(lpStream + dwMemPos);
+		dwMemPos += sizeof(FARSAMPLE);
+		m_nSamples = ismp + 1;
+		memcpy(m_szNames[ismp+1], pfs->samplename, 32);
+		pfs->length = bswapLE32( pfs->length ) ; /* endian fix - Toad */
+		pins->nLength = pfs->length ;
+		pins->nLoopStart = bswapLE32(pfs->reppos) ;
+		pins->nLoopEnd = bswapLE32(pfs->repend) ;
+		pins->nFineTune = 0;
+		pins->nC4Speed = 8363*2;
+		pins->nGlobalVol = 64;
+		pins->nVolume = pfs->volume << 4;
+		pins->uFlags = 0;
+		if ((pins->nLength > 3) && (dwMemPos + 4 < dwMemLength))
+		{
+			if (pfs->type & 1)
+			{
+				pins->uFlags |= CHN_16BIT;
+				pins->nLength >>= 1;
+				pins->nLoopStart >>= 1;
+				pins->nLoopEnd >>= 1;
+			}
+			if ((pfs->loop & 8) && (pins->nLoopEnd > 4)) pins->uFlags |= CHN_LOOP;
+			ReadSample(pins, (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S,
+						(LPSTR)(lpStream+dwMemPos), dwMemLength - dwMemPos);
+		}
+		dwMemPos += pfs->length;
+	}
+	return TRUE;
+}
+