summaryrefslogtreecommitdiff
authorerik <erik>2007-01-31 22:21:38 (UTC)
committer erik <erik>2007-01-31 22:21:38 (UTC)
commited5fba8cdb27174427b2e7780508bafa05536ca1 (patch) (side-by-side diff)
tree9dca5bd75617c8f18ba066bbd90ef88dc2473d84
parent9395cf2a65184e493714c699bb23b02ea31feef5 (diff)
downloadopie-ed5fba8cdb27174427b2e7780508bafa05536ca1.zip
opie-ed5fba8cdb27174427b2e7780508bafa05536ca1.tar.gz
opie-ed5fba8cdb27174427b2e7780508bafa05536ca1.tar.bz2
A few files that have dynamically allocated arrays that are not properly
de-allocated (forgot to use []).
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/modplug/load_amf.cpp2
-rw-r--r--core/multimedia/opieplayer/modplug/load_ams.cpp2
-rw-r--r--core/multimedia/opieplayer/modplug/load_mdl.cpp2
3 files changed, 3 insertions, 3 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_amf.cpp b/core/multimedia/opieplayer/modplug/load_amf.cpp
index 188b5f5..2cf131b 100644
--- a/core/multimedia/opieplayer/modplug/load_amf.cpp
+++ b/core/multimedia/opieplayer/modplug/load_amf.cpp
@@ -1,420 +1,420 @@
/*
* This program is free software; you can redistribute it and modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the license or (at your
* option) any later version.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
///////////////////////////////////////////////////
//
// AMF module loader
//
// There is 2 types of AMF files:
// - ASYLUM Music Format
// - Advanced Music Format(DSM)
//
///////////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#define AMFLOG
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct _AMFFILEHEADER
{
UCHAR szAMF[3];
UCHAR version;
CHAR title[32];
UCHAR numsamples;
UCHAR numorders;
USHORT numtracks;
UCHAR numchannels;
} Q_PACKED AMFFILEHEADER;
typedef struct _AMFSAMPLE
{
UCHAR type;
CHAR samplename[32];
CHAR filename[13];
ULONG offset;
ULONG length;
USHORT c2spd;
UCHAR volume;
} Q_PACKED AMFSAMPLE;
#pragma pack()
#ifdef AMFLOG
extern void Log(LPCSTR, ...);
#endif
VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels)
//-------------------------------------------------------------------------------
{
UINT lastinstr = 0;
UINT nTrkSize = *(USHORT *)pTrack;
nTrkSize += (UINT)pTrack[2] << 16;
pTrack += 3;
while (nTrkSize--)
{
UINT row = pTrack[0];
UINT cmd = pTrack[1];
UINT arg = pTrack[2];
if (row >= nRows) break;
MODCOMMAND *m = pPat + row * nChannels;
if (cmd < 0x7F) // note+vol
{
m->note = cmd+1;
if (!m->instr) m->instr = lastinstr;
m->volcmd = VOLCMD_VOLUME;
m->vol = arg;
} else
if (cmd == 0x7F) // duplicate row
{
signed char rdelta = (signed char)arg;
int rowsrc = (int)row + (int)rdelta;
if ((rowsrc >= 0) && (rowsrc < (int)nRows)) *m = pPat[rowsrc*nChannels];
} else
if (cmd == 0x80) // instrument
{
m->instr = arg+1;
lastinstr = m->instr;
} else
if (cmd == 0x83) // volume
{
m->volcmd = VOLCMD_VOLUME;
m->vol = arg;
} else
// effect
{
UINT command = cmd & 0x7F;
UINT param = arg;
switch(command)
{
// 0x01: Set Speed
case 0x01: command = CMD_SPEED; break;
// 0x02: Volume Slide
// 0x0A: Tone Porta + Vol Slide
// 0x0B: Vibrato + Vol Slide
case 0x02: command = CMD_VOLUMESLIDE;
case 0x0A: if (command == 0x0A) command = CMD_TONEPORTAVOL;
case 0x0B: if (command == 0x0B) command = CMD_VIBRATOVOL;
if (param & 0x80) param = (-(signed char)param)&0x0F;
else param = (param&0x0F)<<4;
break;
// 0x04: Porta Up/Down
case 0x04: if (param & 0x80) { command = CMD_PORTAMENTOUP; param = -(signed char)param; }
else { command = CMD_PORTAMENTODOWN; } break;
// 0x06: Tone Portamento
case 0x06: command = CMD_TONEPORTAMENTO; break;
// 0x07: Tremor
case 0x07: command = CMD_TREMOR; break;
// 0x08: Arpeggio
case 0x08: command = CMD_ARPEGGIO; break;
// 0x09: Vibrato
case 0x09: command = CMD_VIBRATO; break;
// 0x0C: Pattern Break
case 0x0C: command = CMD_PATTERNBREAK; break;
// 0x0D: Position Jump
case 0x0D: command = CMD_POSITIONJUMP; break;
// 0x0F: Retrig
case 0x0F: command = CMD_RETRIG; break;
// 0x10: Offset
case 0x10: command = CMD_OFFSET; break;
// 0x11: Fine Volume Slide
case 0x11: if (param) { command = CMD_VOLUMESLIDE;
if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F);
else param = 0x0F|((param&0x0F)<<4);
} else command = 0; break;
// 0x12: Fine Portamento
// 0x16: Extra Fine Portamento
case 0x12:
case 0x16: if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0;
command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
if (param & 0x80) param = mask|((-(signed char)param)&0x0F);
else param |= mask;
} else command = 0; break;
// 0x13: Note Delay
case 0x13: command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break;
// 0x14: Note Cut
case 0x14: command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break;
// 0x15: Set Tempo
case 0x15: command = CMD_TEMPO; break;
// 0x17: Panning
case 0x17: param = (param+64)&0x7F;
if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING; m->vol = param/2; } command = 0; }
else { command = CMD_PANNING8; }
// Unknown effects
default: command = param = 0;
}
if (command)
{
m->command = command;
m->param = param;
}
}
pTrack += 3;
}
}
BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream;
DWORD dwMemPos;
if ((!lpStream) || (dwMemLength < 2048)) return FALSE;
if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096))
{
UINT numorders, numpats, numsamples;
dwMemPos = 32;
numpats = lpStream[dwMemPos+3];
numorders = lpStream[dwMemPos+4];
numsamples = 64;
dwMemPos += 6;
if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders)
|| (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE;
m_nType = MOD_TYPE_AMF0;
m_nChannels = 8;
m_nInstruments = 0;
m_nSamples = 31;
m_nDefaultTempo = 125;
m_nDefaultSpeed = 6;
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
{
Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF;
}
dwMemPos = 294; // ???
for (UINT iSmp=0; iSmp<numsamples; iSmp++)
{
MODINSTRUMENT *psmp = &Ins[iSmp+1];
memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22);
psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]);
psmp->nVolume = lpStream[dwMemPos+23];
psmp->nGlobalVol = 64;
if (psmp->nVolume > 0x40) psmp->nVolume = 0x40;
psmp->nVolume <<= 2;
psmp->nLength = *((LPDWORD)(lpStream+dwMemPos+25));
psmp->nLoopStart = *((LPDWORD)(lpStream+dwMemPos+29));
psmp->nLoopEnd = psmp->nLoopStart + *((LPDWORD)(lpStream+dwMemPos+33));
if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength))
{
psmp->uFlags = CHN_LOOP;
} else
{
psmp->nLoopStart = psmp->nLoopEnd = 0;
}
if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1;
dwMemPos += 37;
}
for (UINT iPat=0; iPat<numpats; iPat++)
{
MODCOMMAND *p = AllocatePattern(64, m_nChannels);
if (!p) break;
Patterns[iPat] = p;
PatternSize[iPat] = 64;
const UCHAR *pin = lpStream + dwMemPos;
for (UINT i=0; i<8*64; i++)
{
p->note = 0;
if (pin[0])
{
p->note = pin[0] + 13;
}
p->instr = pin[1];
p->command = pin[2];
p->param = pin[3];
if (p->command > 0x0F)
{
#ifdef AMFLOG
Log("0x%02X.0x%02X ?", p->command, p->param);
#endif
p->command = 0;
}
ConvertModCommand(p);
pin += 4;
p++;
}
dwMemPos += 64*32;
}
// Read samples
for (UINT iData=0; iData<m_nSamples; iData++)
{
MODINSTRUMENT *psmp = &Ins[iData+1];
if (psmp->nLength)
{
dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength);
}
}
return TRUE;
}
////////////////////////////
// DSM/AMF
USHORT *ptracks[MAX_PATTERNS];
DWORD sampleseekpos[MAX_SAMPLES];
if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F')
|| (pfh->version < 10) || (pfh->version > 14) || (!pfh->numtracks)
|| (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS)
|| (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES)
|| (pfh->numchannels < 4) || (pfh->numchannels > 32))
return FALSE;
memcpy(m_szNames[0], pfh->title, 32);
dwMemPos = sizeof(AMFFILEHEADER);
m_nType = MOD_TYPE_AMF;
m_nChannels = pfh->numchannels;
m_nSamples = pfh->numsamples;
m_nInstruments = 0;
// Setup Channel Pan Positions
if (pfh->version >= 11)
{
signed char *panpos = (signed char *)(lpStream + dwMemPos);
UINT nchannels = (pfh->version >= 13) ? 32 : 16;
for (UINT i=0; i<nchannels; i++)
{
int pan = (panpos[i] + 64) * 2;
if (pan < 0) pan = 0;
if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; }
ChnSettings[i].nPan = pan;
}
dwMemPos += nchannels;
} else
{
for (UINT i=0; i<16; i++)
{
ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0;
}
dwMemPos += 16;
}
// Get Tempo/Speed
m_nDefaultTempo = 125;
m_nDefaultSpeed = 6;
if (pfh->version >= 13)
{
if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos];
if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1];
dwMemPos += 2;
}
// Setup sequence list
for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++)
{
Order[iOrd] = 0xFF;
if (iOrd < pfh->numorders)
{
Order[iOrd] = iOrd;
PatternSize[iOrd] = 64;
if (pfh->version >= 14)
{
PatternSize[iOrd] = *(USHORT *)(lpStream+dwMemPos);
dwMemPos += 2;
}
ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos);
dwMemPos += m_nChannels * sizeof(USHORT);
}
}
if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE;
// Read Samples
UINT maxsampleseekpos = 0;
for (UINT iIns=0; iIns<m_nSamples; iIns++)
{
MODINSTRUMENT *pins = &Ins[iIns+1];
AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos);
dwMemPos += sizeof(AMFSAMPLE);
memcpy(m_szNames[iIns+1], psh->samplename, 32);
memcpy(pins->name, psh->filename, 13);
pins->nLength = psh->length;
pins->nC4Speed = psh->c2spd;
pins->nGlobalVol = 64;
pins->nVolume = psh->volume * 4;
if (pfh->version >= 11)
{
pins->nLoopStart = *(DWORD *)(lpStream+dwMemPos);
pins->nLoopEnd = *(DWORD *)(lpStream+dwMemPos+4);
dwMemPos += 8;
} else
{
pins->nLoopStart = *(WORD *)(lpStream+dwMemPos);
pins->nLoopEnd = pins->nLength;
dwMemPos += 2;
}
sampleseekpos[iIns] = 0;
if ((psh->type) && (psh->offset < dwMemLength-1))
{
sampleseekpos[iIns] = psh->offset;
if (psh->offset > maxsampleseekpos) maxsampleseekpos = psh->offset;
if ((pins->nLoopEnd > pins->nLoopStart + 2)
&& (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP;
}
}
// Read Track Mapping Table
USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos);
UINT realtrackcnt = 0;
dwMemPos += pfh->numtracks * sizeof(USHORT);
for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++)
{
if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap];
}
// Store tracks positions
BYTE **pTrackData = new BYTE *[realtrackcnt];
memset(pTrackData, 0, sizeof(pTrackData));
for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos + 3 <= dwMemLength)
{
UINT nTrkSize = *(USHORT *)(lpStream+dwMemPos);
nTrkSize += (UINT)lpStream[dwMemPos+2] << 16;
if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength)
{
pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos);
}
dwMemPos += nTrkSize * 3 + 3;
}
// Create the patterns from the list of tracks
for (UINT iPat=0; iPat<pfh->numorders; iPat++)
{
MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels);
if (!p) break;
Patterns[iPat] = p;
for (UINT iChn=0; iChn<m_nChannels; iChn++)
{
UINT nTrack = ptracks[iPat][iChn];
if ((nTrack) && (nTrack <= pfh->numtracks))
{
UINT realtrk = pTrackMap[nTrack-1];
if (realtrk)
{
realtrk--;
if ((realtrk < realtrackcnt) && (pTrackData[realtrk]))
{
AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels);
}
}
}
}
}
- delete pTrackData;
+ delete [] pTrackData;
// Read Sample Data
for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++)
{
if (dwMemPos >= dwMemLength) break;
for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp])
{
MODINSTRUMENT *pins = &Ins[iSmp+1];
dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
break;
}
}
return TRUE;
}
diff --git a/core/multimedia/opieplayer/modplug/load_ams.cpp b/core/multimedia/opieplayer/modplug/load_ams.cpp
index 3dd1c2b..ad1cc01 100644
--- a/core/multimedia/opieplayer/modplug/load_ams.cpp
+++ b/core/multimedia/opieplayer/modplug/load_ams.cpp
@@ -1,631 +1,631 @@
/*
* This program is free software; you can redistribute it and modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the license or (at your
* option) any later version.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
//////////////////////////////////////////////
// AMS module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
#pragma pack(1)
typedef struct AMSFILEHEADER
{
char szHeader[7]; // "Extreme" // changed from CHAR
BYTE verlo, verhi; // 0x??,0x01
BYTE chncfg;
BYTE samples;
WORD patterns;
WORD orders;
BYTE vmidi;
WORD extra;
} Q_PACKED AMSFILEHEADER;
typedef struct AMSSAMPLEHEADER
{
DWORD length;
DWORD loopstart;
DWORD loopend;
BYTE finetune_and_pan;
WORD samplerate; // C-2 = 8363
BYTE volume; // 0-127
BYTE infobyte;
} Q_PACKED AMSSAMPLEHEADER;
#pragma pack()
BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength)
//-----------------------------------------------------------
{
BYTE pkinf[MAX_SAMPLES];
AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream;
DWORD dwMemPos;
UINT tmp, tmp2;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7))
|| (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples > MAX_SAMPLES)
|| (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS))
{
return ReadAMS2(lpStream, dwMemLength);
}
dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra;
if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE;
m_nType = MOD_TYPE_AMS;
m_nInstruments = 0;
m_nChannels = (pfh->chncfg & 0x1F) + 1;
m_nSamples = pfh->samples;
for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER))
{
AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos);
MODINSTRUMENT *pins = &Ins[nSmp];
pins->nLength = psh->length;
pins->nLoopStart = psh->loopstart;
pins->nLoopEnd = psh->loopend;
pins->nGlobalVol = 64;
pins->nVolume = psh->volume << 1;
pins->nC4Speed = psh->samplerate;
pins->nPan = (psh->finetune_and_pan & 0xF0);
if (pins->nPan < 0x80) pins->nPan += 0x10;
pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F);
pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0;
if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP;
pkinf[nSmp] = psh->infobyte;
}
// Read Song Name
tmp = lpStream[dwMemPos++];
if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE;
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2);
m_szNames[0][tmp2] = 0;
dwMemPos += tmp;
// Read sample names
for (UINT sNam=1; sNam<=m_nSamples; sNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2);
dwMemPos += tmp;
}
// Skip Channel names
for (UINT cNam=0; cNam<m_nChannels; cNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
dwMemPos += tmp;
}
// Read Pattern Names
m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR
if (!m_lpszPatternNames) return TRUE;
m_nPatternNames = pfh->patterns;
memset(m_lpszPatternNames, 0, m_nPatternNames * 32);
for (UINT pNam=0; pNam < m_nPatternNames; pNam++)
{
if (dwMemPos + 32 >= dwMemLength) return TRUE;
tmp = lpStream[dwMemPos++];
tmp2 = (tmp < 32) ? tmp : 31;
if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2);
dwMemPos += tmp;
}
// Read Song Comments
tmp = *((WORD *)(lpStream+dwMemPos));
dwMemPos += 2;
if (dwMemPos + tmp >= dwMemLength) return TRUE;
if (tmp)
{
m_lpszSongComments = new char[tmp+1]; // changed from CHAR
if (!m_lpszSongComments) return TRUE;
memset(m_lpszSongComments, 0, tmp+1);
memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp);
dwMemPos += tmp;
}
// Read Order List
for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2)
{
UINT n = *((WORD *)(lpStream+dwMemPos));
Order[iOrd] = (BYTE)n;
}
// Read Patterns
for (UINT iPat=0; iPat<pfh->patterns; iPat++)
{
if (dwMemPos + 4 >= dwMemLength) return TRUE;
UINT len = *((DWORD *)(lpStream + dwMemPos));
dwMemPos += 4;
if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE;
PatternSize[iPat] = 64;
MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels);
if (!m) return TRUE;
Patterns[iPat] = m;
const BYTE *p = lpStream + dwMemPos;
UINT row = 0, i = 0;
while ((row < PatternSize[iPat]) && (i+2 < len))
{
BYTE b0 = p[i++];
BYTE b1 = p[i++];
BYTE b2 = 0;
UINT ch = b0 & 0x3F;
// Note+Instr
if (!(b0 & 0x40))
{
b2 = p[i++];
if (ch < m_nChannels)
{
if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25;
m[ch].instr = b2;
}
if (b1 & 0x80)
{
b0 |= 0x40;
b1 = p[i++];
}
}
// Effect
if (b0 & 0x40)
{
anothercommand:
if (b1 & 0x40)
{
if (ch < m_nChannels)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = b1 & 0x3F;
}
} else
{
b2 = p[i++];
if (ch < m_nChannels)
{
UINT cmd = b1 & 0x3F;
if (cmd == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = b2 >> 1;
} else
if (cmd == 0x0E)
{
if (!m[ch].command)
{
UINT command = CMD_S3MCMDEX;
UINT param = b2;
switch(param & 0xF0)
{
case 0x00: if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break;
case 0x10: command = CMD_PORTAMENTOUP; param |= 0xF0; break;
case 0x20: command = CMD_PORTAMENTODOWN; param |= 0xF0; break;
case 0x30: param = (param & 0x0F) | 0x10; break;
case 0x40: param = (param & 0x0F) | 0x30; break;
case 0x50: param = (param & 0x0F) | 0x20; break;
case 0x60: param = (param & 0x0F) | 0xB0; break;
case 0x70: param = (param & 0x0F) | 0x40; break;
case 0x90: command = CMD_RETRIG; param &= 0x0F; break;
case 0xA0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break;
case 0xB0: if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break;
}
m[ch].command = command;
m[ch].param = param;
}
} else
{
m[ch].command = cmd;
m[ch].param = b2;
ConvertModCommand(&m[ch]);
}
}
}
if (b1 & 0x80)
{
b1 = p[i++];
if (i <= len) goto anothercommand;
}
}
if (b0 & 0x80)
{
row++;
m += m_nChannels;
}
}
dwMemPos += len;
}
// Read Samples
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
{
if (dwMemPos >= dwMemLength - 9) return TRUE;
UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////
// AMS 2.2 loader
#pragma pack(1)
typedef struct AMS2FILEHEADER
{
DWORD dwHdr1; // AMShdr
WORD wHdr2;
BYTE b1A; // 0x1A
BYTE titlelen; // 30-bytes max
CHAR szTitle[30]; // [titlelen]
} Q_PACKED AMS2FILEHEADER;
typedef struct AMS2SONGHEADER
{
WORD version;
BYTE instruments;
WORD patterns;
WORD orders;
WORD bpm;
BYTE speed;
BYTE channels;
BYTE commands;
BYTE rows;
WORD flags;
} Q_PACKED AMS2SONGHEADER;
typedef struct AMS2INSTRUMENT
{
BYTE samples;
BYTE notemap[120];
} Q_PACKED AMS2INSTRUMENT;
typedef struct AMS2ENVELOPE
{
BYTE speed;
BYTE sustain;
BYTE loopbegin;
BYTE loopend;
BYTE points;
BYTE info[3];
} Q_PACKED AMS2ENVELOPE;
typedef struct AMS2SAMPLE
{
DWORD length;
DWORD loopstart;
DWORD loopend;
WORD frequency;
BYTE finetune;
WORD c4speed;
CHAR transpose;
BYTE volume;
BYTE flags;
} Q_PACKED AMS2SAMPLE;
#pragma pack()
BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength)
//------------------------------------------------------------
{
AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream;
AMS2SONGHEADER *psh;
DWORD dwMemPos;
BYTE smpmap[16];
BYTE packedsamples[MAX_SAMPLES];
if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264)
|| (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE;
dwMemPos = pfh->titlelen + 8;
psh = (AMS2SONGHEADER *)(lpStream + dwMemPos);
if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments)
|| (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE;
dwMemPos += sizeof(AMS2SONGHEADER);
if (pfh->titlelen)
{
memcpy(m_szNames, pfh->szTitle, pfh->titlelen);
m_szNames[0][pfh->titlelen] = 0;
}
m_nType = MOD_TYPE_AMS;
m_nChannels = 32;
m_nDefaultTempo = psh->bpm >> 8;
m_nDefaultSpeed = psh->speed;
m_nInstruments = psh->instruments;
m_nSamples = 0;
if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES;
for (UINT nIns=1; nIns<=m_nInstruments; nIns++)
{
UINT insnamelen = lpStream[dwMemPos];
CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1);
dwMemPos += insnamelen + 1;
AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos);
dwMemPos += sizeof(AMS2INSTRUMENT);
if (dwMemPos + 1024 >= dwMemLength) return TRUE;
AMS2ENVELOPE *volenv, *panenv, *pitchenv;
volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + volenv->points*3;
panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + panenv->points*3;
pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos);
dwMemPos += 5 + pitchenv->points*3;
INSTRUMENTHEADER *penv = new INSTRUMENTHEADER;
if (!penv) return TRUE;
memset(smpmap, 0, sizeof(smpmap));
memset(penv, 0, sizeof(INSTRUMENTHEADER));
for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++)
{
if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break;
m_nSamples++;
smpmap[ismpmap] = m_nSamples;
}
penv->nGlobalVol = 64;
penv->nPan = 128;
penv->nPPC = 60;
Headers[nIns] = penv;
if (insnamelen)
{
if (insnamelen > 31) insnamelen = 31;
memcpy(penv->name, pinsname, insnamelen);
penv->name[insnamelen] = 0;
}
for (UINT inotemap=0; inotemap<120; inotemap++)
{
penv->NoteMap[inotemap] = inotemap+1;
penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F];
}
// Volume Envelope
{
UINT pos = 0;
penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points;
penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain;
penv->nVolLoopStart = volenv->loopbegin;
penv->nVolLoopEnd = volenv->loopend;
for (UINT i=0; i<penv->nVolEnv; i++)
{
penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1);
pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8);
penv->VolPoints[i] = (WORD)pos;
}
}
penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3;
UINT envflags = lpStream[dwMemPos+3];
if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP;
if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN;
if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME;
dwMemPos += 5;
// Read Samples
for (UINT ismp=0; ismp<pins->samples; ismp++)
{
MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL;
UINT smpnamelen = lpStream[dwMemPos];
if ((psmp) && (smpnamelen) && (smpnamelen <= 22))
{
memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen);
}
dwMemPos += smpnamelen + 1;
if (psmp)
{
AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos);
psmp->nGlobalVol = 64;
psmp->nPan = 128;
psmp->nLength = pams->length;
psmp->nLoopStart = pams->loopstart;
psmp->nLoopEnd = pams->loopend;
psmp->nC4Speed = pams->c4speed;
psmp->RelativeTone = pams->transpose;
psmp->nVolume = pams->volume / 2;
packedsamples[smpmap[ismp]] = pams->flags;
if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT;
if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP;
if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP;
}
dwMemPos += sizeof(AMS2SAMPLE);
}
}
if (dwMemPos + 256 >= dwMemLength) return TRUE;
// Comments
{
UINT composernamelen = lpStream[dwMemPos];
if (composernamelen)
{
m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen);
m_lpszSongComments[composernamelen] = 0;
}
}
dwMemPos += composernamelen + 1;
// channel names
for (UINT i=0; i<32; i++)
{
UINT chnnamlen = lpStream[dwMemPos];
if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME))
{
memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen);
}
dwMemPos += chnnamlen + 1;
if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE;
}
// packed comments (ignored)
UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos));
dwMemPos += songtextlen;
if (dwMemPos + 256 >= dwMemLength) return TRUE;
}
// Order List
{
for (UINT i=0; i<MAX_ORDERS; i++)
{
Order[i] = 0xFF;
if (dwMemPos + 2 >= dwMemLength) return TRUE;
if (i < psh->orders)
{
Order[i] = lpStream[dwMemPos];
dwMemPos += 2;
}
}
}
// Pattern Data
for (UINT ipat=0; ipat<psh->patterns; ipat++)
{
if (dwMemPos+8 >= dwMemLength) return TRUE;
UINT packedlen = *((LPDWORD)(lpStream+dwMemPos));
UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]);
//UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F);
//UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5);
UINT patnamlen = lpStream[dwMemPos+6];
dwMemPos += 4;
if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8))
{
if ((patnamlen) && (patnamlen < MAX_PATTERNNAME))
{
char s[MAX_PATTERNNAME]; // changed from CHAR
memcpy(s, lpStream+dwMemPos+3, patnamlen);
s[patnamlen] = 0;
SetPatternName(ipat, s);
}
PatternSize[ipat] = numrows;
Patterns[ipat] = AllocatePattern(numrows, m_nChannels);
if (!Patterns[ipat]) return TRUE;
// Unpack Pattern Data
LPCBYTE psrc = lpStream + dwMemPos;
UINT pos = 3 + patnamlen;
UINT row = 0;
while ((pos < packedlen) && (row < numrows))
{
MODCOMMAND *m = Patterns[ipat] + row * m_nChannels;
UINT byte1 = psrc[pos++];
UINT ch = byte1 & 0x1F;
// Read Note + Instr
if (!(byte1 & 0x40))
{
UINT byte2 = psrc[pos++];
UINT note = byte2 & 0x7F;
if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF;
m[ch].instr = psrc[pos++];
// Read Effect
while (byte2 & 0x80)
{
byte2 = psrc[pos++];
if (byte2 & 0x40)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = byte2 & 0x3F;
} else
{
UINT command = byte2 & 0x3F;
UINT param = psrc[pos++];
if (command == 0x0C)
{
m[ch].volcmd = VOLCMD_VOLUME;
m[ch].vol = param / 2;
} else
if (command < 0x10)
{
m[ch].command = command;
m[ch].param = param;
ConvertModCommand(&m[ch]);
} else
{
// TODO: AMS effects
}
}
}
}
if (byte1 & 0x80) row++;
}
}
dwMemPos += packedlen;
}
// Read Samples
for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength)
{
if (dwMemPos >= dwMemLength - 9) return TRUE;
UINT flags;
if (packedsamples[iSmp] & 0x03)
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8;
} else
{
flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
}
dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////
// AMS Sample unpacking
void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter)
{
UINT tmplen = dmax;
signed char *amstmp = new signed char[tmplen];
if (!amstmp) return;
// Unpack Loop
{
signed char *p = amstmp;
UINT i=0, j=0;
while ((i < inputlen) && (j < tmplen))
{
signed char ch = psrc[i++];
if (ch == packcharacter)
{
BYTE ch2 = psrc[i++];
if (ch2)
{
ch = psrc[i++];
while (ch2--)
{
p[j++] = ch;
if (j >= tmplen) break;
}
} else p[j++] = packcharacter;
} else p[j++] = ch;
}
}
// Bit Unpack Loop
{
signed char *p = amstmp;
UINT bitcount = 0x80, dh;
UINT k=0;
for (UINT i=0; i<dmax; i++)
{
BYTE al = *p++;
dh = 0;
for (UINT count=0; count<8; count++)
{
UINT bl = al & bitcount;
bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF;
bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF;
pdest[k++] |= bl;
if (k >= dmax)
{
k = 0;
dh++;
}
}
bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF;
}
}
// Delta Unpack
{
signed char old = 0;
for (UINT i=0; i<dmax; i++)
{
int pos = ((LPBYTE)pdest)[i];
if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F);
old -= (signed char)pos;
pdest[i] = old;
}
}
- delete amstmp;
+ delete [] amstmp;
}
diff --git a/core/multimedia/opieplayer/modplug/load_mdl.cpp b/core/multimedia/opieplayer/modplug/load_mdl.cpp
index 806b68b..e1f78d5 100644
--- a/core/multimedia/opieplayer/modplug/load_mdl.cpp
+++ b/core/multimedia/opieplayer/modplug/load_mdl.cpp
@@ -1,506 +1,506 @@
/*
* This program is free software; you can redistribute it and modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the license or (at your
* option) any later version.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
*/
//////////////////////////////////////////////
// DigiTracker (MDL) module loader //
//////////////////////////////////////////////
#include "stdafx.h"
#include "sndfile.h"
//#pragma warning(disable:4244)
typedef struct MDLSONGHEADER
{
DWORD id; // "DMDL" = 0x4C444D44
BYTE version;
} Q_PACKED MDLSONGHEADER;
typedef struct MDLINFOBLOCK
{
CHAR songname[32];
CHAR composer[20];
WORD norders;
WORD repeatpos;
BYTE globalvol;
BYTE speed;
BYTE tempo;
BYTE channelinfo[32];
BYTE seq[256];
} Q_PACKED MDLINFOBLOCK;
typedef struct MDLPATTERNDATA
{
BYTE channels;
BYTE lastrow; // nrows = lastrow+1
CHAR name[16];
WORD data[1];
} Q_PACKED MDLPATTERNDATA;
void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data)
//--------------------------------------------------------
{
UINT command = 0, param = data;
switch(eff)
{
case 0x01: command = CMD_PORTAMENTOUP; break;
case 0x02: command = CMD_PORTAMENTODOWN; break;
case 0x03: command = CMD_TONEPORTAMENTO; break;
case 0x04: command = CMD_VIBRATO; break;
case 0x05: command = CMD_ARPEGGIO; break;
case 0x07: command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
case 0x08: command = CMD_PANNING8; param <<= 1; break;
case 0x0B: command = CMD_POSITIONJUMP; break;
case 0x0C: command = CMD_GLOBALVOLUME; break;
case 0x0D: command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break;
case 0x0E:
command = CMD_S3MCMDEX;
switch(data & 0xF0)
{
case 0x00: command = 0; break; // What is E0x in MDL (there is a bunch) ?
case 0x10: if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break;
case 0x20: if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break;
case 0x30: param = (data & 0x0F) | 0x10; break; // glissando
case 0x40: param = (data & 0x0F) | 0x30; break; // vibrato waveform
case 0x60: param = (data & 0x0F) | 0xB0; break;
case 0x70: param = (data & 0x0F) | 0x40; break; // tremolo waveform
case 0x90: command = CMD_RETRIG; param &= 0x0F; break;
case 0xA0: param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break;
case 0xB0: param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break;
case 0xF0: param = ((data >> 8) & 0x0F) | 0xA0; break;
}
break;
case 0x0F: command = CMD_SPEED; break;
case 0x10: if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break;
case 0x20: if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break;
case 0x30: command = CMD_RETRIG; break;
case 0x40: command = CMD_TREMOLO; break;
case 0x50: command = CMD_TREMOR; break;
case 0xEF: if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break;
}
if (command)
{
m->command = command;
m->param = param;
}
}
void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks)
//-------------------------------------------------------------------------------------------------
{
MODCOMMAND cmd, *m = pat;
UINT len = *((WORD *)lpTracks);
UINT pos = 0, row = 0, i;
lpTracks += 2;
for (UINT ntrk=1; ntrk<nTrack; ntrk++)
{
lpTracks += len;
len = *((WORD *)lpTracks);
lpTracks += 2;
}
cmd.note = cmd.instr = 0;
cmd.volcmd = cmd.vol = 0;
cmd.command = cmd.param = 0;
while ((row < nRows) && (pos < len))
{
UINT xx;
BYTE b = lpTracks[pos++];
xx = b >> 2;
switch(b & 0x03)
{
case 0x01:
for (i=0; i<=xx; i++)
{
if (row) *m = *(m-nChannels);
m += nChannels;
row++;
if (row >= nRows) break;
}
break;
case 0x02:
if (xx < row) *m = pat[nChannels*xx];
m += nChannels;
row++;
break;
case 0x03:
{
cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0;
cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0;
cmd.volcmd = cmd.vol = 0;
cmd.command = cmd.param = 0;
if ((cmd.note < 120-12) && (cmd.note)) cmd.note += 12;
UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0;
UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0;
UINT command1 = commands & 0x0F;
UINT command2 = commands & 0xF0;
UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0;
UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0;
if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2))
{
param1 = ((param1 & 0x0F) << 8) | param2;
command1 = 0xEF;
command2 = param2 = 0;
}
if (volume)
{
cmd.volcmd = VOLCMD_VOLUME;
cmd.vol = (volume+1) >> 2;
}
ConvertMDLCommand(&cmd, command1, param1);
if ((cmd.command != CMD_SPEED)
&& (cmd.command != CMD_TEMPO)
&& (cmd.command != CMD_PATTERNBREAK))
ConvertMDLCommand(&cmd, command2, param2);
*m = cmd;
m += nChannels;
row++;
}
break;
// Empty Slots
default:
row += xx+1;
m += (xx+1)*nChannels;
if (row >= nRows) break;
}
}
}
BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength)
//---------------------------------------------------------------
{
DWORD dwMemPos, dwPos, blocklen, dwTrackPos;
const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream;
MDLINFOBLOCK *pmib;
MDLPATTERNDATA *pmpd;
UINT i,j, norders = 0, npatterns = 0, ntracks = 0;
UINT ninstruments = 0, nsamples = 0;
WORD block;
WORD patterntracks[MAX_PATTERNS*32];
BYTE smpinfo[MAX_SAMPLES];
BYTE insvolenv[MAX_INSTRUMENTS];
BYTE inspanenv[MAX_INSTRUMENTS];
LPCBYTE pvolenv, ppanenv, ppitchenv;
UINT nvolenv, npanenv, npitchenv;
if ((!lpStream) || (dwMemLength < 1024)) return FALSE;
if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE;
memset(patterntracks, 0, sizeof(patterntracks));
memset(smpinfo, 0, sizeof(smpinfo));
memset(insvolenv, 0, sizeof(insvolenv));
memset(inspanenv, 0, sizeof(inspanenv));
dwMemPos = 5;
dwTrackPos = 0;
pvolenv = ppanenv = ppitchenv = NULL;
nvolenv = npanenv = npitchenv = 0;
m_nSamples = m_nInstruments = 0;
while (dwMemPos+6 < dwMemLength)
{
block = *((WORD *)(lpStream+dwMemPos));
blocklen = *((DWORD *)(lpStream+dwMemPos+2));
dwMemPos += 6;
if (dwMemPos + blocklen > dwMemLength)
{
if (dwMemPos == 11) return FALSE;
break;
}
switch(block)
{
// IN: infoblock
case 0x4E49:
pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos);
memcpy(m_szNames[0], pmib->songname, 32);
norders = pmib->norders;
if (norders > MAX_ORDERS) norders = MAX_ORDERS;
m_nRestartPos = pmib->repeatpos;
m_nDefaultGlobalVolume = pmib->globalvol;
m_nDefaultTempo = pmib->tempo;
m_nDefaultSpeed = pmib->speed;
m_nChannels = 4;
for (i=0; i<32; i++)
{
ChnSettings[i].nVolume = 64;
ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1;
if (pmib->channelinfo[i] & 0x80)
ChnSettings[i].dwFlags |= CHN_MUTE;
else
m_nChannels = i+1;
}
for (j=0; j<norders; j++) Order[j] = pmib->seq[j];
break;
// ME: song message
case 0x454D:
if (blocklen)
{
- if (m_lpszSongComments) delete m_lpszSongComments;
+ if (m_lpszSongComments) delete [] m_lpszSongComments;
m_lpszSongComments = new char[blocklen];
if (m_lpszSongComments)
{
memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen);
m_lpszSongComments[blocklen-1] = 0;
}
}
break;
// PA: Pattern Data
case 0x4150:
npatterns = lpStream[dwMemPos];
if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS;
dwPos = dwMemPos + 1;
for (i=0; i<npatterns; i++)
{
if (dwPos+18 >= dwMemLength) break;
pmpd = (MDLPATTERNDATA *)(lpStream + dwPos);
if (pmpd->channels > 32) break;
PatternSize[i] = pmpd->lastrow+1;
if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels;
dwPos += 18 + 2*pmpd->channels;
for (j=0; j<pmpd->channels; j++)
{
patterntracks[i*32+j] = pmpd->data[j];
}
}
break;
// TR: Track Data
case 0x5254:
if (dwTrackPos) break;
ntracks = *((WORD *)(lpStream+dwMemPos));
dwTrackPos = dwMemPos+2;
break;
// II: Instruments
case 0x4949:
ninstruments = lpStream[dwMemPos];
dwPos = dwMemPos+1;
for (i=0; i<ninstruments; i++)
{
UINT nins = lpStream[dwPos];
if ((nins >= MAX_INSTRUMENTS) || (!nins)) break;
if (m_nInstruments < nins) m_nInstruments = nins;
if (!Headers[nins])
{
UINT note = 12;
if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break;
INSTRUMENTHEADER *penv = Headers[nins];
memset(penv, 0, sizeof(INSTRUMENTHEADER));
memcpy(penv->name, lpStream+dwPos+2, 32);
penv->nGlobalVol = 64;
penv->nPPC = 5*12;
for (j=0; j<lpStream[dwPos+1]; j++)
{
const BYTE *ps = lpStream+dwPos+34+14*j;
while ((note < (UINT)(ps[1]+12)) && (note < 120))
{
penv->NoteMap[note] = note+1;
if (ps[0] < MAX_SAMPLES)
{
int ismp = ps[0];
penv->Keyboard[note] = ps[0];
Ins[ismp].nVolume = ps[2];
Ins[ismp].nPan = ps[4] << 1;
Ins[ismp].nVibType = ps[11];
Ins[ismp].nVibSweep = ps[10];
Ins[ismp].nVibDepth = ps[9];
Ins[ismp].nVibRate = ps[8];
}
penv->nFadeOut = (ps[7] << 8) | ps[6];
if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0;
note++;
}
// Use volume envelope ?
if (ps[3] & 0x80)
{
penv->dwFlags |= ENV_VOLUME;
insvolenv[nins] = (ps[3] & 0x3F) + 1;
}
// Use panning envelope ?
if (ps[5] & 0x80)
{
penv->dwFlags |= ENV_PANNING;
inspanenv[nins] = (ps[5] & 0x3F) + 1;
}
}
}
dwPos += 34 + 14*lpStream[dwPos+1];
}
for (j=1; j<=m_nInstruments; j++) if (!Headers[j])
{
Headers[j] = new INSTRUMENTHEADER;
if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER));
}
break;
// VE: Volume Envelope
case 0x4556:
if ((nvolenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1;
break;
// PE: Panning Envelope
case 0x4550:
if ((npanenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1;
break;
// FE: Pitch Envelope
case 0x4546:
if ((npitchenv = lpStream[dwMemPos]) == 0) break;
if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1;
break;
// IS: Sample Infoblock
case 0x5349:
nsamples = lpStream[dwMemPos];
dwPos = dwMemPos+1;
for (i=0; i<nsamples; i++, dwPos += 59)
{
UINT nins = lpStream[dwPos];
if ((nins >= MAX_SAMPLES) || (!nins)) continue;
if (m_nSamples < nins) m_nSamples = nins;
MODINSTRUMENT *pins = &Ins[nins];
memcpy(m_szNames[nins], lpStream+dwPos+1, 32);
memcpy(pins->name, lpStream+dwPos+33, 8);
pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41));
pins->nLength = *((DWORD *)(lpStream+dwPos+45));
pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49));
pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53));
if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP;
pins->nGlobalVol = 64;
if (lpStream[dwPos+58] & 0x01)
{
pins->uFlags |= CHN_16BIT;
pins->nLength >>= 1;
pins->nLoopStart >>= 1;
pins->nLoopEnd >>= 1;
}
if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP;
smpinfo[nins] = (lpStream[dwPos+58] >> 2) & 3;
}
break;
// SA: Sample Data
case 0x4153:
dwPos = dwMemPos;
for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength))
{
MODINSTRUMENT *pins = &Ins[i];
UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S;
if (!smpinfo[i])
{
dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos);
} else
{
DWORD dwLen = *((DWORD *)(lpStream+dwPos));
dwPos += 4;
if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4))
{
flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8;
ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwLen);
}
dwPos += dwLen;
}
}
break;
}
dwMemPos += blocklen;
}
// Unpack Patterns
if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks))
{
for (UINT ipat=0; ipat<npatterns; ipat++)
{
if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break;
for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks))
{
MODCOMMAND *m = Patterns[ipat] + chn;
UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos);
}
}
}
// Set up envelopes
for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns])
{
INSTRUMENTHEADER *penv = Headers[iIns];
// Setup volume envelope
if ((nvolenv) && (pvolenv) && (insvolenv[iIns]))
{
LPCBYTE pve = pvolenv;
for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns])
{
WORD vtick = 1;
penv->nVolEnv = 15;
for (UINT iv=0; iv<15; iv++)
{
if (iv) vtick += pve[iv*2+1];
penv->VolPoints[iv] = vtick;
penv->VolEnv[iv] = pve[iv*2+2];
if (!pve[iv*2+1])
{
penv->nVolEnv = iv+1;
break;
}
}
penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F;
if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN;
if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP;
penv->nVolLoopStart = pve[32] & 0x0F;
penv->nVolLoopEnd = pve[32] >> 4;
}
}
// Setup panning envelope
if ((npanenv) && (ppanenv) && (inspanenv[iIns]))
{
LPCBYTE ppe = ppanenv;
for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns])
{
WORD vtick = 1;
penv->nPanEnv = 15;
for (UINT iv=0; iv<15; iv++)
{
if (iv) vtick += ppe[iv*2+1];
penv->PanPoints[iv] = vtick;
penv->PanEnv[iv] = ppe[iv*2+2];
if (!ppe[iv*2+1])
{
penv->nPanEnv = iv+1;
break;
}
}
if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN;
if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP;
penv->nPanLoopStart = ppe[32] & 0x0F;
penv->nPanLoopEnd = ppe[32] >> 4;
}
}
}
m_dwSongFlags |= SONG_LINEARSLIDES;
m_nType = MOD_TYPE_MDL;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// MDL Sample Unpacking
// MDL Huffman ReadBits compression
WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n)
//-----------------------------------------------------------------
{
WORD v = (WORD)(bitbuf & ((1 << n) - 1) );
bitbuf >>= n;
bitnum -= n;
if (bitnum <= 24)
{
bitbuf |= (((DWORD)(*ibuf++)) << bitnum);
bitnum += 8;
}
return v;
}