diff src/modplug/load_wav.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_wav.cxx	Sun Oct 29 01:04:52 2006 -0700
@@ -0,0 +1,220 @@
+/*
+ * This source code is public domain.
+ *
+ * Authors: Olivier Lapicque <olivierl@jps.net>
+*/
+
+#include "stdafx.h"
+#include "sndfile.h"
+
+#ifndef WAVE_FORMAT_EXTENSIBLE
+#define WAVE_FORMAT_EXTENSIBLE	0xFFFE
+#endif
+
+/////////////////////////////////////////////////////////////
+// WAV file support
+
+BOOL CSoundFile::ReadWav(const BYTE *lpStream, DWORD dwMemLength)
+//---------------------------------------------------------------
+{
+	DWORD dwMemPos = 0;
+	WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream;
+	WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER));
+	if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE;
+	if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE)
+	 || (pfmt->id_fmt != IFFID_fmt)) return FALSE;
+	dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen;
+	if ((dwMemPos + 8 >= dwMemLength)
+	 || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE))
+	 || (pfmt->channels > 4)
+	 || (!pfmt->channels)
+	 || (!pfmt->freqHz)
+	 || (pfmt->bitspersample & 7)
+	 || (pfmt->bitspersample < 8)
+	 || (pfmt->bitspersample > 32))  return FALSE;
+	WAVEDATAHEADER *pdata;
+	for (;;)
+	{
+		pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos);
+		if (pdata->id_data == IFFID_data) break;
+		dwMemPos += pdata->length + 8;
+		if (dwMemPos + 8 >= dwMemLength) return FALSE;
+	}
+	m_nType = MOD_TYPE_WAV;
+	m_nSamples = 0;
+	m_nInstruments = 0;
+	m_nChannels = 4;
+	m_nDefaultSpeed = 8;
+	m_nDefaultTempo = 125;
+	m_dwSongFlags |= SONG_LINEARSLIDES; // For no resampling
+	Order[0] = 0;
+	Order[1] = 0xFF;
+	PatternSize[0] = PatternSize[1] = 64;
+	if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE;
+	if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE;
+	UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3;
+	UINT len = pdata->length, bytelen;
+	if (dwMemPos + len > dwMemLength - 8) len = dwMemLength - dwMemPos - 8;
+	len /= samplesize;
+	bytelen = len;
+	if (pfmt->bitspersample >= 16) bytelen *= 2;
+	if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH;
+	if (!len) return TRUE;
+	// Setting up module length
+	DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1;
+	DWORD framesperrow = (dwTime + 63) / 63;
+	if (framesperrow < 4) framesperrow = 4;
+	UINT norders = 1;
+	while (framesperrow >= 0x20)
+	{
+		Order[norders++] = 1;
+		Order[norders] = 0xFF;
+		framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders);
+		if (norders >= MAX_ORDERS-1) break;
+	}
+	m_nDefaultSpeed = framesperrow;
+	for (UINT iChn=0; iChn<4; iChn++)
+	{
+		ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0;
+		ChnSettings[iChn].nVolume = 64;
+		ChnSettings[iChn].dwFlags = 0;
+	}
+	// Setting up speed command
+	MODCOMMAND *pcmd = Patterns[0];
+	pcmd[0].command = CMD_SPEED;
+	pcmd[0].param = (BYTE)m_nDefaultSpeed;
+	pcmd[0].note = 5*12+1;
+	pcmd[0].instr = 1;
+	pcmd[1].note = pcmd[0].note;
+	pcmd[1].instr = pcmd[0].instr;
+	m_nSamples = pfmt->channels;
+	// Support for Multichannel Wave
+	for (UINT nChn=0; nChn<m_nSamples; nChn++)
+	{
+		MODINSTRUMENT *pins = &Ins[nChn+1];
+		pcmd[nChn].note = pcmd[0].note;
+		pcmd[nChn].instr = (BYTE)(nChn+1);
+		pins->nLength = len;
+		pins->nC4Speed = pfmt->freqHz;
+		pins->nVolume = 256;
+		pins->nPan = 128;
+		pins->nGlobalVol = 64;
+		pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0);
+		pins->uFlags |= CHN_PANNING;
+		if (m_nSamples > 1)
+		{
+			switch(nChn)
+			{
+			case 0:	pins->nPan = 0; break;
+			case 1:	pins->nPan = 256; break;
+			case 2: pins->nPan = (WORD)((m_nSamples == 3) ? 128 : 64); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
+			case 3: pins->nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break;
+			default: pins->nPan = 128; break;
+			}
+		}
+		if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE;
+		if (pfmt->bitspersample >= 16)
+		{
+			int slsize = pfmt->bitspersample >> 3;
+			signed short *p = (signed short *)pins->pSample;
+			signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2);
+			for (UINT i=0; i<len; i++)
+			{
+				p[i] = *((signed short *)psrc);
+				psrc += samplesize;
+			}
+			p[len+1] = p[len] = p[len-1];
+		} else
+		{
+			signed char *p = (signed char *)pins->pSample;
+			signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn);
+			for (UINT i=0; i<len; i++)
+			{
+				p[i] = (signed char)((*psrc) + 0x80);
+				psrc += samplesize;
+			}
+			p[len+1] = p[len] = p[len-1];
+		}
+	}
+	return TRUE;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+// IMA ADPCM Support
+
+#pragma pack(1)
+
+typedef struct IMAADPCMBLOCK
+{
+	WORD sample;
+	BYTE index;
+	BYTE Reserved;
+} DVI_ADPCMBLOCKHEADER;
+
+#pragma pack()
+
+static const int gIMAUnpackTable[90] = 
+{
+  7,     8,     9,    10,    11,    12,    13,    14,
+  16,    17,    19,    21,    23,    25,    28,    31,
+  34,    37,    41,    45,    50,    55,    60,    66,
+  73,    80,    88,    97,   107,   118,   130,   143,
+  157,   173,   190,   209,   230,   253,   279,   307,
+  337,   371,   408,   449,   494,   544,   598,   658,
+  724,   796,   876,   963,  1060,  1166,  1282,  1411,
+  1552,  1707,  1878,  2066,  2272,  2499,  2749,  3024,
+  3327,  3660,  4026,  4428,  4871,  5358,  5894,  6484,
+  7132,  7845,  8630,  9493, 10442, 11487, 12635, 13899,
+  15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+  32767, 0
+};
+
+
+BOOL IMAADPCMUnpack16(signed short *pdest, UINT nLen, LPBYTE psrc, DWORD dwBytes, UINT pkBlkAlign)
+//------------------------------------------------------------------------------------------------
+{
+	static const int gIMAIndexTab[8] =  { -1, -1, -1, -1, 2, 4, 6, 8 };
+	UINT nPos;
+	int value;
+
+	if ((nLen < 4) || (!pdest) || (!psrc)
+	 || (pkBlkAlign < 5) || (pkBlkAlign > dwBytes)) return FALSE;
+	nPos = 0;
+	while ((nPos < nLen) && (dwBytes > 4))
+	{
+		int nIndex;
+		value = *((short int *)psrc);
+		nIndex = psrc[2];
+		psrc += 4;
+		dwBytes -= 4;
+		pdest[nPos++] = (short int)value;
+		for (UINT i=0; ((i<(pkBlkAlign-4)*2) && (nPos < nLen) && (dwBytes)); i++)
+		{
+			BYTE delta;
+			if (i & 1)
+			{
+				delta = (BYTE)(((*(psrc++)) >> 4) & 0x0F);
+				dwBytes--;
+			} else
+			{
+				delta = (BYTE)((*psrc) & 0x0F);
+			}
+			int v = gIMAUnpackTable[nIndex] >> 3;
+			if (delta & 1) v += gIMAUnpackTable[nIndex] >> 2;
+			if (delta & 2) v += gIMAUnpackTable[nIndex] >> 1;
+			if (delta & 4) v += gIMAUnpackTable[nIndex];
+			if (delta & 8) value -= v; else value += v;
+			nIndex += gIMAIndexTab[delta & 7];
+			if (nIndex < 0) nIndex = 0; else
+			if (nIndex > 88) nIndex = 88;
+			if (value > 32767) value = 32767; else
+			if (value < -32768) value = -32768;
+			pdest[nPos++] = (short int)value;
+		}
+	}
+	return TRUE;
+}
+
+
+