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; // 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; }
bool module_renderer::ReadDSM(const uint8_t * const lpStream, const uint32_t dwMemLength) //----------------------------------------------------------------------- { DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream; DSMSONG *psong; uint32_t dwMemPos; UINT nPat, nSmp; if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF) || (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024) || (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG) || (pfh->song_len > dwMemLength)) return false; psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER)); dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len; m_nType = MOD_TYPE_DSM; m_nChannels = psong->numtrk; if (m_nChannels < 1) m_nChannels = 1; if (m_nChannels > 16) m_nChannels = 16; m_nSamples = psong->numsmp; if (m_nSamples > MAX_SAMPLES) m_nSamples = MAX_SAMPLES; m_nDefaultSpeed = psong->speed; m_nDefaultTempo = psong->bpm; m_nDefaultGlobalVolume = psong->globalvol << 2; if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > MAX_GLOBAL_VOLUME)) m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME; m_nSamplePreAmp = psong->mastervol & 0x7F; Order.ReadAsByte(psong->orders, psong->numord, sizeof(psong->orders)); for (UINT iPan=0; iPan<16; iPan++) { ChnSettings[iPan].nPan = 0x80; if (psong->panpos[iPan] <= 0x80) { ChnSettings[iPan].nPan = psong->panpos[iPan] << 1; } } assign_without_padding(this->song_name, psong->songname, 28); nPat = 0; nSmp = 1; while (dwMemPos < dwMemLength - 8) { DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos); DSMSAMPLE *pSmp = (DSMSAMPLE *)(lpStream+dwMemPos); // Reading Patterns if (ppatt->id_PATT == DSMID_PATT) { dwMemPos += 8; if (dwMemPos + ppatt->patt_len >= dwMemLength) break; uint32_t dwPos = dwMemPos; dwMemPos += ppatt->patt_len; if(Patterns.Insert(nPat, 64)) break; modplug::tracker::modevent_t *m = Patterns[nPat]; UINT row = 0; while ((row < 64) && (dwPos + 2 <= dwMemPos)) { UINT flag = lpStream[dwPos++]; if (flag) { UINT ch = (flag & 0x0F) % m_nChannels; if (flag & 0x80) { UINT note = lpStream[dwPos++]; if (note) { if (note <= 12*9) note += 12; m[ch].note = (uint8_t)note; } } if (flag & 0x40) { m[ch].instr = lpStream[dwPos++]; } if (flag & 0x20) { m[ch].volcmd = VolCmdVol; m[ch].vol = lpStream[dwPos++]; } if (flag & 0x10) { UINT command = lpStream[dwPos++]; UINT param = lpStream[dwPos++]; switch(command) { // 4-bit Panning case 0x08: switch(param & 0xF0) { case 0x00: param <<= 4; break; case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break; case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break; case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break; case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break; default: command = 0; } break; // Portamentos case 0x11: case 0x12: command &= 0x0F; break; // 3D Sound (?) case 0x13: command = 'X' - 55; param = 0x91; break; default: // Volume + Offset (?) command = ((command & 0xF0) == 0x20) ? 0x09 : 0; } //XXXih: gross! m[ch].command = (modplug::tracker::cmd_t) command; m[ch].param = (uint8_t)param; if (command) ConvertModCommand(&m[ch]); } } else { m += m_nChannels; row++; } } nPat++; } else // Reading Samples if ((nSmp <= m_nSamples) && (pSmp->id_INST == DSMID_INST)) { if (dwMemPos + pSmp->inst_len >= dwMemLength - 8) break; uint32_t dwPos = dwMemPos + sizeof(DSMSAMPLE); dwMemPos += 8 + pSmp->inst_len; memcpy(m_szNames[nSmp], pSmp->samplename, 28); SpaceToNullStringFixed<28>(m_szNames[nSmp]); modsample_t *psmp = &Samples[nSmp]; memcpy(psmp->legacy_filename, pSmp->filename, 13); SpaceToNullStringFixed<13>(psmp->legacy_filename); psmp->global_volume = 64; psmp->c5_samplerate = pSmp->c2spd; psmp->flags = (uint16_t)((pSmp->flags & 1) ? CHN_LOOP : 0); psmp->length = pSmp->length; psmp->loop_start = pSmp->loopstart; psmp->loop_end = pSmp->loopend; psmp->default_volume = (uint16_t)(pSmp->volume << 2); if (psmp->default_volume > 256) psmp->default_volume = 256; UINT smptype = (pSmp->flags & 2) ? RS_PCM8S : RS_PCM8U; ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos); nSmp++; } else { break; } } return true; }
BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength) //----------------------------------------------------------- { DSMFILEHEADER *pfh = (DSMFILEHEADER *)lpStream; DSMSONG *psong; DWORD dwMemPos; UINT nPat, nSmp; if ((!lpStream) || (dwMemLength < 1024) || (pfh->id_RIFF != DSMID_RIFF) || (pfh->riff_len + 8 > dwMemLength) || (pfh->riff_len < 1024) || (pfh->id_DSMF != DSMID_DSMF) || (pfh->id_SONG != DSMID_SONG) || (pfh->song_len > dwMemLength)) return FALSE; psong = (DSMSONG *)(lpStream + sizeof(DSMFILEHEADER)); dwMemPos = sizeof(DSMFILEHEADER) + pfh->song_len; m_nType = MOD_TYPE_DSM; m_nChannels = psong->numtrk; if (m_nChannels < 4) m_nChannels = 4; if (m_nChannels > 16) m_nChannels = 16; m_nSamples = psong->numsmp; if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES - 1; m_nDefaultSpeed = psong->speed; m_nDefaultTempo = psong->bpm; m_nDefaultGlobalVolume = psong->globalvol << 2; if ((!m_nDefaultGlobalVolume) || (m_nDefaultGlobalVolume > 256)) m_nDefaultGlobalVolume = 256; m_nSongPreAmp = psong->mastervol & 0x7F; for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++) { Order[iOrd] = (BYTE)((iOrd < psong->numord) ? psong->orders[iOrd] : 0xFF); } for (UINT iPan=0; iPan<16; iPan++) { ChnSettings[iPan].nPan = 0x80; if (psong->panpos[iPan] <= 0x80) { ChnSettings[iPan].nPan = psong->panpos[iPan] << 1; } } memcpy(m_szNames[0], psong->songname, 28); nPat = 0; nSmp = 1; while (dwMemPos < dwMemLength - 8) { DSMPATT *ppatt = (DSMPATT *)(lpStream + dwMemPos); DSMINST *pins = (DSMINST *)(lpStream+dwMemPos); // Reading Patterns if (ppatt->id_PATT == DSMID_PATT) { dwMemPos += 8; if (dwMemPos + ppatt->patt_len >= dwMemLength) break; DWORD dwPos = dwMemPos; dwMemPos += ppatt->patt_len; MODCOMMAND *m = AllocatePattern(64, m_nChannels); if (!m) break; PatternSize[nPat] = 64; Patterns[nPat] = m; UINT row = 0; while ((row < 64) && (dwPos + 2 <= dwMemPos)) { UINT flag = lpStream[dwPos++]; if (flag) { UINT ch = (flag & 0x0F) % m_nChannels; if (flag & 0x80) { UINT note = lpStream[dwPos++]; if (note) { if (note <= 12*9) note += 12; m[ch].note = (BYTE)note; } } if (flag & 0x40) { m[ch].instr = lpStream[dwPos++]; } if (flag & 0x20) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = lpStream[dwPos++]; } if (flag & 0x10) { UINT command = lpStream[dwPos++]; UINT param = lpStream[dwPos++]; switch(command) { // 4-bit Panning case 0x08: switch(param & 0xF0) { case 0x00: param <<= 4; break; case 0x10: command = 0x0A; param = (param & 0x0F) << 4; break; case 0x20: command = 0x0E; param = (param & 0x0F) | 0xA0; break; case 0x30: command = 0x0E; param = (param & 0x0F) | 0x10; break; case 0x40: command = 0x0E; param = (param & 0x0F) | 0x20; break; default: command = 0; } break; // Portamentos case 0x11: case 0x12: command &= 0x0F; break; // 3D Sound (?) case 0x13: command = 'X' - 55; param = 0x91; break; default: // Volume + Offset (?) command = ((command & 0xF0) == 0x20) ? 0x09 : 0; } m[ch].command = (BYTE)command; m[ch].param = (BYTE)param; if (command) ConvertModCommand(&m[ch]); } } else { m += m_nChannels; row++; } } nPat++; } else // Reading Samples if ((nSmp <= m_nSamples) && (pins->id_INST == DSMID_INST)) { if (dwMemPos + pins->inst_len >= dwMemLength - 8) break; DWORD dwPos = dwMemPos + sizeof(DSMINST); dwMemPos += 8 + pins->inst_len; memcpy(m_szNames[nSmp], pins->samplename, 28); MODINSTRUMENT *psmp = &Ins[nSmp]; memcpy(psmp->name, pins->filename, 13); psmp->nGlobalVol = 64; psmp->nC4Speed = pins->c2spd; psmp->uFlags = (WORD)((pins->flags & 1) ? CHN_LOOP : 0); psmp->nLength = pins->length; psmp->nLoopStart = pins->loopstart; psmp->nLoopEnd = pins->loopend; psmp->nVolume = (WORD)(pins->volume << 2); if (psmp->nVolume > 256) psmp->nVolume = 256; UINT smptype = (pins->flags & 2) ? RS_PCM8S : RS_PCM8U; ReadSample(psmp, smptype, (LPCSTR)(lpStream+dwPos), dwMemLength - dwPos); nSmp++; } else { break; } } return TRUE; }
BOOL CSoundFile::ReadXM(const BYTE *lpStream, DWORD dwMemLength) //-------------------------------------------------------------- { XMSAMPLEHEADER xmsh; XMSAMPLESTRUCT xmss; DWORD dwMemPos, dwHdrSize; WORD norders=0, restartpos=0, channels=0, patterns=0, instruments=0; WORD xmflags=0, deftempo=125, defspeed=6; BOOL InstUsed[256]; BYTE channels_used[MAX_CHANNELS]; BYTE pattern_map[256]; BOOL samples_used[MAX_SAMPLES]; UINT unused_samples; tagXMFILEHEADER xmhead; m_nChannels = 0; if ((!lpStream) || (dwMemLength < 0x200)) return FALSE; if (strncmp((LPCSTR)lpStream, "Extended Module:", 16)) return FALSE; memcpy(m_szNames[0], lpStream+17, 20); xmhead = *(tagXMFILEHEADER *)(lpStream+60); dwHdrSize = bswapLE32(xmhead.size); norders = bswapLE16(xmhead.norder); if ((!norders) || (norders > MAX_ORDERS)) return FALSE; restartpos = bswapLE16(xmhead.restartpos); channels = bswapLE16(xmhead.channels); if ((!channels) || (channels > 64)) return FALSE; m_nType = MOD_TYPE_XM; m_nMinPeriod = 27; m_nMaxPeriod = 54784; m_nChannels = channels; if (restartpos < norders) m_nRestartPos = restartpos; patterns = bswapLE16(xmhead.patterns); if (patterns > 256) patterns = 256; instruments = bswapLE16(xmhead.instruments); if (instruments >= MAX_INSTRUMENTS) instruments = MAX_INSTRUMENTS-1; m_nInstruments = instruments; m_nSamples = 0; xmflags = bswapLE16(xmhead.flags); if (xmflags & 1) m_dwSongFlags |= SONG_LINEARSLIDES; if (xmflags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE; defspeed = bswapLE16(xmhead.speed); deftempo = bswapLE16(xmhead.tempo); if ((deftempo >= 32) && (deftempo < 256)) m_nDefaultTempo = deftempo; if ((defspeed > 0) && (defspeed < 40)) m_nDefaultSpeed = defspeed; memcpy(Order, lpStream+80, norders); memset(InstUsed, 0, sizeof(InstUsed)); if (patterns > MAX_PATTERNS) { UINT i, j; for (i=0; i<norders; i++) { if (Order[i] < patterns) InstUsed[Order[i]] = TRUE; } j = 0; for (i=0; i<256; i++) { if (InstUsed[i]) pattern_map[i] = j++; } for (i=0; i<256; i++) { if (!InstUsed[i]) { pattern_map[i] = (j < MAX_PATTERNS) ? j : 0xFE; j++; } } for (i=0; i<norders; i++) { Order[i] = pattern_map[Order[i]]; } } else { for (UINT i=0; i<256; i++) pattern_map[i] = i; } memset(InstUsed, 0, sizeof(InstUsed)); dwMemPos = dwHdrSize + 60; if (dwMemPos + 8 >= dwMemLength) return TRUE; // Reading patterns memset(channels_used, 0, sizeof(channels_used)); for (UINT ipat=0; ipat<patterns; ipat++) { UINT ipatmap = pattern_map[ipat]; DWORD dwSize = 0; WORD rows=64, packsize=0; dwSize = bswapLE32(loadDWORD(lpStream+dwMemPos)); while ((dwMemPos + dwSize >= dwMemLength) || (dwSize & 0xFFFFFF00)) { if (dwMemPos + 4 >= dwMemLength) break; dwMemPos++; dwSize = bswapLE32(loadDWORD(lpStream+dwMemPos)); } rows = bswapLE16(loadWORD(lpStream+dwMemPos+5)); if ((!rows) || (rows > 256)) rows = 64; packsize = bswapLE16(loadWORD(lpStream+dwMemPos+7)); if (dwMemPos + dwSize + 4 > dwMemLength) return TRUE; dwMemPos += dwSize; if (dwMemPos + packsize + 4 > dwMemLength) return TRUE; MODCOMMAND *p; if (ipatmap < MAX_PATTERNS) { PatternSize[ipatmap] = rows; if ((Patterns[ipatmap] = AllocatePattern(rows, m_nChannels)) == NULL) return TRUE; if (!packsize) continue; p = Patterns[ipatmap]; } else p = NULL; const BYTE *src = lpStream+dwMemPos; UINT j=0; for (UINT row=0; row<rows; row++) { for (UINT chn=0; chn<m_nChannels; chn++) { if ((p) && (j < packsize)) { BYTE b = src[j++]; UINT vol = 0; if (b & 0x80) { if (b & 1) p->note = src[j++]; if (b & 2) p->instr = src[j++]; if (b & 4) vol = src[j++]; if (b & 8) p->command = src[j++]; if (b & 16) p->param = src[j++]; } else { p->note = b; p->instr = src[j++]; vol = src[j++]; p->command = src[j++]; p->param = src[j++]; } if (p->note == 97) p->note = 0xFF; else if ((p->note) && (p->note < 97)) p->note += 12; if (p->note) channels_used[chn] = 1; if (p->command | p->param) ConvertModCommand(p); if (p->instr == 0xff) p->instr = 0; if (p->instr) InstUsed[p->instr] = TRUE; if ((vol >= 0x10) && (vol <= 0x50)) { p->volcmd = VOLCMD_VOLUME; p->vol = vol - 0x10; } else if (vol >= 0x60) { UINT v = vol & 0xF0; vol &= 0x0F; p->vol = vol; switch(v) { // 60-6F: Volume Slide Down case 0x60: p->volcmd = VOLCMD_VOLSLIDEDOWN; break; // 70-7F: Volume Slide Up: case 0x70: p->volcmd = VOLCMD_VOLSLIDEUP; break; // 80-8F: Fine Volume Slide Down case 0x80: p->volcmd = VOLCMD_FINEVOLDOWN; break; // 90-9F: Fine Volume Slide Up case 0x90: p->volcmd = VOLCMD_FINEVOLUP; break; // A0-AF: Set Vibrato Speed case 0xA0: p->volcmd = VOLCMD_VIBRATOSPEED; break; // B0-BF: Vibrato case 0xB0: p->volcmd = VOLCMD_VIBRATO; break; // C0-CF: Set Panning case 0xC0: p->volcmd = VOLCMD_PANNING; p->vol = (vol << 2) + 2; break; // D0-DF: Panning Slide Left case 0xD0: p->volcmd = VOLCMD_PANSLIDELEFT; break; // E0-EF: Panning Slide Right case 0xE0: p->volcmd = VOLCMD_PANSLIDERIGHT; break; // F0-FF: Tone Portamento case 0xF0: p->volcmd = VOLCMD_TONEPORTAMENTO; break; } } p++; } else if (j < packsize) { BYTE b = src[j++]; if (b & 0x80) { if (b & 1) j++; if (b & 2) j++; if (b & 4) j++; if (b & 8) j++; if (b & 16) j++; } else j += 4; } else break; } } dwMemPos += packsize; } // Wrong offset check while (dwMemPos + 4 < dwMemLength) { DWORD d = bswapLE32(loadDWORD(lpStream+dwMemPos)); if (d < 0x300) break; dwMemPos++; } memset(samples_used, 0, sizeof(samples_used)); unused_samples = 0; // Reading instruments for (UINT iIns=1; iIns<=instruments; iIns++) { XMINSTRUMENTHEADER *pih; BYTE flags[32]; DWORD samplesize[32]; UINT samplemap[32]; WORD nsamples; if (dwMemPos + sizeof(XMINSTRUMENTHEADER) >= dwMemLength) return TRUE; pih = (XMINSTRUMENTHEADER *)(lpStream+dwMemPos); if (dwMemPos + bswapLE32(pih->size) > dwMemLength) return TRUE; if ((Headers[iIns] = new INSTRUMENTHEADER) == NULL) continue; memset(Headers[iIns], 0, sizeof(INSTRUMENTHEADER)); memcpy(Headers[iIns]->name, pih->name, 22); if ((nsamples = pih->samples) > 0) { if (dwMemPos + sizeof(XMSAMPLEHEADER) > dwMemLength) return TRUE; memcpy(&xmsh, lpStream+dwMemPos+sizeof(XMINSTRUMENTHEADER), sizeof(XMSAMPLEHEADER)); xmsh.shsize = bswapLE32(xmsh.shsize); for (int i = 0; i < 24; ++i) { xmsh.venv[i] = bswapLE16(xmsh.venv[i]); xmsh.penv[i] = bswapLE16(xmsh.penv[i]); } xmsh.volfade = bswapLE16(xmsh.volfade); xmsh.res = bswapLE16(xmsh.res); dwMemPos += bswapLE32(pih->size); } else { if (bswapLE32(pih->size)) dwMemPos += bswapLE32(pih->size); else dwMemPos += sizeof(XMINSTRUMENTHEADER); continue; } memset(samplemap, 0, sizeof(samplemap)); if (nsamples > 32) return TRUE; UINT newsamples = m_nSamples; for (UINT nmap=0; nmap<nsamples; nmap++) { UINT n = m_nSamples+nmap+1; if (n >= MAX_SAMPLES) { n = m_nSamples; while (n > 0) { if (!Ins[n].pSample) { for (UINT xmapchk=0; xmapchk < nmap; xmapchk++) { if (samplemap[xmapchk] == n) goto alreadymapped; } for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs]) { INSTRUMENTHEADER *pks = Headers[clrs]; for (UINT ks=0; ks<128; ks++) { if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0; } } break; } alreadymapped: n--; } #ifndef MODPLUG_FASTSOUNDLIB // Damn! more than 200 samples: look for duplicates if (!n) { if (!unused_samples) { unused_samples = DetectUnusedSamples(samples_used); if (!unused_samples) unused_samples = 0xFFFF; } if ((unused_samples) && (unused_samples != 0xFFFF)) { for (UINT iext=m_nSamples; iext>=1; iext--) if (!samples_used[iext]) { unused_samples--; samples_used[iext] = TRUE; DestroySample(iext); n = iext; for (UINT mapchk=0; mapchk<nmap; mapchk++) { if (samplemap[mapchk] == n) samplemap[mapchk] = 0; } for (UINT clrs=1; clrs<iIns; clrs++) if (Headers[clrs]) { INSTRUMENTHEADER *pks = Headers[clrs]; for (UINT ks=0; ks<128; ks++) { if (pks->Keyboard[ks] == n) pks->Keyboard[ks] = 0; } } memset(&Ins[n], 0, sizeof(Ins[0])); break; } } } #endif // MODPLUG_FASTSOUNDLIB } if (newsamples < n) newsamples = n; samplemap[nmap] = n; } m_nSamples = newsamples; // Reading Volume Envelope INSTRUMENTHEADER *penv = Headers[iIns]; penv->nMidiProgram = pih->type; penv->nFadeOut = xmsh.volfade; penv->nPan = 128; penv->nPPC = 5*12; if (xmsh.vtype & 1) penv->dwFlags |= ENV_VOLUME; if (xmsh.vtype & 2) penv->dwFlags |= ENV_VOLSUSTAIN; if (xmsh.vtype & 4) penv->dwFlags |= ENV_VOLLOOP; if (xmsh.ptype & 1) penv->dwFlags |= ENV_PANNING; if (xmsh.ptype & 2) penv->dwFlags |= ENV_PANSUSTAIN; if (xmsh.ptype & 4) penv->dwFlags |= ENV_PANLOOP; if (xmsh.vnum > 12) xmsh.vnum = 12; if (xmsh.pnum > 12) xmsh.pnum = 12; penv->nVolEnv = xmsh.vnum; if (!xmsh.vnum) penv->dwFlags &= ~ENV_VOLUME; if (!xmsh.pnum) penv->dwFlags &= ~ENV_PANNING; penv->nPanEnv = xmsh.pnum; penv->nVolSustainBegin = penv->nVolSustainEnd = xmsh.vsustain; if (xmsh.vsustain >= 12) penv->dwFlags &= ~ENV_VOLSUSTAIN; penv->nVolLoopStart = xmsh.vloops; penv->nVolLoopEnd = xmsh.vloope; if (penv->nVolLoopEnd >= 12) penv->nVolLoopEnd = 0; if (penv->nVolLoopStart >= penv->nVolLoopEnd) penv->dwFlags &= ~ENV_VOLLOOP; penv->nPanSustainBegin = penv->nPanSustainEnd = xmsh.psustain; if (xmsh.psustain >= 12) penv->dwFlags &= ~ENV_PANSUSTAIN; penv->nPanLoopStart = xmsh.ploops; penv->nPanLoopEnd = xmsh.ploope; if (penv->nPanLoopEnd >= 12) penv->nPanLoopEnd = 0; if (penv->nPanLoopStart >= penv->nPanLoopEnd) penv->dwFlags &= ~ENV_PANLOOP; penv->nGlobalVol = 64; for (UINT ienv=0; ienv<12; ienv++) { penv->VolPoints[ienv] = (WORD)xmsh.venv[ienv*2]; penv->VolEnv[ienv] = (BYTE)xmsh.venv[ienv*2+1]; penv->PanPoints[ienv] = (WORD)xmsh.penv[ienv*2]; penv->PanEnv[ienv] = (BYTE)xmsh.penv[ienv*2+1]; if (ienv) { if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) { penv->VolPoints[ienv] &= 0xFF; penv->VolPoints[ienv] += penv->VolPoints[ienv-1] & 0xFF00; if (penv->VolPoints[ienv] < penv->VolPoints[ienv-1]) penv->VolPoints[ienv] += 0x100; } if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) { penv->PanPoints[ienv] &= 0xFF; penv->PanPoints[ienv] += penv->PanPoints[ienv-1] & 0xFF00; if (penv->PanPoints[ienv] < penv->PanPoints[ienv-1]) penv->PanPoints[ienv] += 0x100; } } } for (UINT j=0; j<96; j++) { penv->NoteMap[j+12] = j+1+12; if (xmsh.snum[j] < nsamples) penv->Keyboard[j+12] = samplemap[xmsh.snum[j]]; } // Reading samples for (UINT ins=0; ins<nsamples; ins++) { if ((dwMemPos + sizeof(xmss) > dwMemLength) || (dwMemPos + xmsh.shsize > dwMemLength)) return TRUE; memcpy(&xmss, lpStream+dwMemPos, sizeof(xmss)); xmss.samplen = bswapLE32(xmss.samplen); xmss.loopstart = bswapLE32(xmss.loopstart); xmss.looplen = bswapLE32(xmss.looplen); dwMemPos += xmsh.shsize; flags[ins] = (xmss.type & 0x10) ? RS_PCM16D : RS_PCM8D; if (xmss.type & 0x20) flags[ins] = (xmss.type & 0x10) ? RS_STPCM16D : RS_STPCM8D; samplesize[ins] = xmss.samplen; if (!samplemap[ins]) continue; if (xmss.type & 0x10) { xmss.looplen >>= 1; xmss.loopstart >>= 1; xmss.samplen >>= 1; } if (xmss.type & 0x20) { xmss.looplen >>= 1; xmss.loopstart >>= 1; xmss.samplen >>= 1; } if (xmss.samplen > MAX_SAMPLE_LENGTH) xmss.samplen = MAX_SAMPLE_LENGTH; if (xmss.loopstart >= xmss.samplen) xmss.type &= ~3; xmss.looplen += xmss.loopstart; if (xmss.looplen > xmss.samplen) xmss.looplen = xmss.samplen; if (!xmss.looplen) xmss.type &= ~3; UINT imapsmp = samplemap[ins]; memcpy(m_szNames[imapsmp], xmss.name, 22); m_szNames[imapsmp][22] = 0; MODINSTRUMENT *pins = &Ins[imapsmp]; pins->nLength = (xmss.samplen > MAX_SAMPLE_LENGTH) ? MAX_SAMPLE_LENGTH : xmss.samplen; pins->nLoopStart = xmss.loopstart; pins->nLoopEnd = xmss.looplen; if (pins->nLoopEnd > pins->nLength) pins->nLoopEnd = pins->nLength; if (pins->nLoopStart >= pins->nLoopEnd) { pins->nLoopStart = pins->nLoopEnd = 0; } if (xmss.type & 3) pins->uFlags |= CHN_LOOP; if (xmss.type & 2) pins->uFlags |= CHN_PINGPONGLOOP; pins->nVolume = xmss.vol << 2; if (pins->nVolume > 256) pins->nVolume = 256; pins->nGlobalVol = 64; if ((xmss.res == 0xAD) && (!(xmss.type & 0x30))) { flags[ins] = RS_ADPCM4; samplesize[ins] = (samplesize[ins]+1)/2 + 16; } pins->nFineTune = xmss.finetune; pins->RelativeTone = (int)xmss.relnote; pins->nPan = xmss.pan; pins->uFlags |= CHN_PANNING; pins->nVibType = xmsh.vibtype; pins->nVibSweep = xmsh.vibsweep; pins->nVibDepth = xmsh.vibdepth; pins->nVibRate = xmsh.vibrate; memcpy(pins->name, xmss.name, 22); pins->name[21] = 0; }
bool module_renderer::ReadAMS(const uint8_t * const lpStream, const uint32_t dwMemLength) //----------------------------------------------------------------------- { uint8_t pkinf[MAX_SAMPLES]; AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream; uint32_t dwMemPos; UINT tmp, tmp2; if ((!lpStream) || (dwMemLength < 126)) 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) >= 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); modsample_t *pSmp = &Samples[nSmp]; pSmp->length = psh->length; pSmp->loop_start = psh->loopstart; pSmp->loop_end = psh->loopend; pSmp->global_volume = 64; pSmp->default_volume = psh->volume << 1; pSmp->c5_samplerate = psh->samplerate; pSmp->default_pan = (psh->finetune_and_pan & 0xF0); if (pSmp->default_pan < 0x80) pSmp->default_pan += 0x10; pSmp->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F); pSmp->flags = (psh->infobyte & 0x80) ? CHN_16BIT : 0; if ((pSmp->loop_end <= pSmp->length) && (pSmp->loop_start+4 <= pSmp->loop_end)) pSmp->flags |= CHN_LOOP; pkinf[nSmp] = psh->infobyte; } // Read Song Name if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; if (dwMemPos + tmp + 1 >= dwMemLength) return true; tmp2 = (tmp < 32) ? tmp : 31; if (tmp2) assign_without_padding(this->song_name, reinterpret_cast<const char *>(lpStream + dwMemPos), tmp2); this->song_name.erase(tmp2); 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); SpaceToNullStringFixed(m_szNames[sNam], tmp2); dwMemPos += tmp; } // Read Channel names for (UINT cNam=0; cNam<m_nChannels; cNam++) { if (dwMemPos + 32 >= dwMemLength) return true; uint8_t chnnamlen = lpStream[dwMemPos++]; if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME)) { memcpy(ChnSettings[cNam].szName, lpStream + dwMemPos, chnnamlen); SpaceToNullStringFixed(ChnSettings[cNam].szName, chnnamlen); } dwMemPos += chnnamlen; } // Read Pattern Names for (UINT pNam = 0; pNam < pfh->patterns; pNam++) { if (dwMemPos + 1 >= dwMemLength) return true; tmp = lpStream[dwMemPos++]; tmp2 = bad_min(tmp, MAX_PATTERNNAME - 1); // not counting null char if (dwMemPos + tmp >= dwMemLength) return true; Patterns.Insert(pNam, 64); // Create pattern now, so that the name won't be overwritten later. if(tmp2) { Patterns[pNam].SetName((char *)(lpStream + dwMemPos), tmp2 + 1); } dwMemPos += tmp; } // Read Song Comments tmp = *((uint16_t *)(lpStream+dwMemPos)); dwMemPos += 2; if (dwMemPos + tmp >= dwMemLength) return true; if (tmp) { ReadMessage(lpStream + dwMemPos, tmp, leCR, &Convert_AMS_Text_Chars); } dwMemPos += tmp; // Read Order List Order.resize(pfh->orders, Order.GetInvalidPatIndex()); for (UINT iOrd=0; iOrd < pfh->orders; iOrd++, dwMemPos += 2) { Order[iOrd] = (modplug::tracker::patternindex_t)*((uint16_t *)(lpStream + dwMemPos)); } // Read Patterns for (UINT iPat=0; iPat<pfh->patterns; iPat++) { if (dwMemPos + 4 >= dwMemLength) return true; UINT len = *((uint32_t *)(lpStream + dwMemPos)); dwMemPos += 4; if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return true; // Pattern has been inserted when reading pattern names modplug::tracker::modevent_t* m = Patterns[iPat]; if (!m) return true; const uint8_t *p = lpStream + dwMemPos; UINT row = 0, i = 0; while ((row < Patterns[iPat].GetNumRows()) && (i+2 < len)) { uint8_t b0 = p[i++]; uint8_t b1 = p[i++]; uint8_t 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 = VolCmdVol; m[ch].vol = b1 & 0x3F; } } else { b2 = p[i++]; if (ch < m_nChannels) { UINT cmd = b1 & 0x3F; if (cmd == 0x0C) { m[ch].volcmd = VolCmdVol; m[ch].vol = b2 >> 1; } else if (cmd == 0x0E) { if (!m[ch].command) { UINT command = CmdS3mCmdEx; UINT param = b2; switch(param & 0xF0) { case 0x00: if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break; case 0x10: command = CmdPortaUp; param |= 0xF0; break; case 0x20: command = CmdPortaDown; 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 = CmdRetrig; param &= 0x0F; break; case 0xA0: if (param & 0x0F) { command = CmdVolSlide; param = (param << 4) | 0x0F; } else command=param=0; break; case 0xB0: if (param & 0x0F) { command = CmdVolSlide; param |= 0xF0; } else command=param=0; break; } //XXXih: gross m[ch].command = (modplug::tracker::cmd_t) command; m[ch].param = param; } } else { //XXXih: gross m[ch].command = (modplug::tracker::cmd_t) cmd; m[ch].param = b2; ConvertModCommand(&m[ch]); } } }