-rw-r--r-- | core/multimedia/opieplayer/modplug/load_amf.cpp | 2 | ||||
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_ams.cpp | 2 | ||||
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_mdl.cpp | 2 |
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 @@ -117,515 +117,515 @@ BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength) 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; } |