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::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]); } } }
bool CSoundFile::ReadDIGI(FileReader &file, ModLoadingFlags loadFlags) //-------------------------------------------------------------------- { file.Rewind(); DIGIFileHeader fileHeader; if(!file.ReadConvertEndianness(fileHeader) || memcmp(fileHeader.signature, "DIGI Booster module\0", 20) || !fileHeader.numChannels || fileHeader.numChannels > 8 || fileHeader.lastOrdIndex > 127) { return false; } else if(loadFlags == onlyVerifyHeader) { return true; } // Globals InitializeGlobals(); InitializeChannels(); m_nType = MOD_TYPE_DIGI; m_nChannels = fileHeader.numChannels; m_nSamples = 31; m_nSamplePreAmp = 256 / m_nChannels; madeWithTracker = mpt::String::Print("Digi Booster %1.%2", fileHeader.versionInt >> 4, fileHeader.versionInt & 0x0F); Order.ReadFromArray(fileHeader.orders, fileHeader.lastOrdIndex + 1); // Read sample headers for(SAMPLEINDEX smp = 0; smp < 31; smp++) { ModSample &sample = Samples[smp + 1]; sample.Initialize(MOD_TYPE_MOD); sample.nLength = fileHeader.smpLength[smp]; sample.nLoopStart = fileHeader.smpLoopStart[smp]; sample.nLoopEnd = sample.nLoopStart + fileHeader.smpLoopLength[smp]; if(fileHeader.smpLoopLength[smp]) { sample.uFlags.set(CHN_LOOP); } sample.SanitizeLoops(); sample.nVolume = std::min(fileHeader.smpVolume[smp], uint8(64)) * 4; sample.nFineTune = MOD2XMFineTune(fileHeader.smpFinetune[smp]); } // Read song + sample names file.ReadString<mpt::String::maybeNullTerminated>(songName, 32); for(SAMPLEINDEX smp = 1; smp <= 31; smp++) { file.ReadString<mpt::String::maybeNullTerminated>(m_szNames[smp], 30); } for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPatIndex; pat++) { FileReader patternChunk; if(fileHeader.packEnable) { patternChunk = file.ReadChunk(file.ReadUint16BE()); } else { patternChunk = file.ReadChunk(4 * 64 * GetNumChannels()); } if(!(loadFlags & loadPatternData) || Patterns.Insert(pat, 64)) { continue; } if(fileHeader.packEnable) { std::vector<uint8> eventMask; patternChunk.ReadVector(eventMask, 64); // Compressed patterns are stored in row-major order... for(ROWINDEX row = 0; row < 64; row++) { PatternRow patRow = Patterns[pat].GetRow(row); uint8 bit = 0x80; for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, bit >>= 1) { if(eventMask[row] & bit) { ModCommand &m = patRow[chn]; ReadDIGIPatternEntry(patternChunk, m, *this); } } } } else { // ...but uncompressed patterns are stored in column-major order. WTF! for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
static int CSoundFile_ReadAsylum(CSoundFile * that, const uint8_t * lpStream, uint32_t dwMemLength) { uint32_t dwMemPos; unsigned numorders; unsigned numpats; unsigned numsamples; unsigned i; unsigned iPat; 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 0; } that->m_nType = MOD_TYPE_AMF0; that->m_nChannels = 8; that->m_nInstruments = 0; that->m_nSamples = 31; that->m_nDefaultTempo = 125; that->m_nDefaultSpeed = 6; for (i = 0; i < MAX_ORDERS; i++) { that->Order[i] = (i < numorders) ? lpStream[dwMemPos + i] : 0xFF; // FIXME: no optimal code } dwMemPos = 294; // ??? for (i = 0; i < numsamples; i++) { MODINSTRUMENT *psmp = &that->Ins[i + 1]; memcpy(that->m_szNames[i + 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 = *((uint32_t *) (lpStream + dwMemPos + 25)); psmp->nLoopStart = *((uint32_t *) (lpStream + dwMemPos + 29)); psmp->nLoopEnd = psmp->nLoopStart + *((uint32_t *) (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) && (i > 31)) { that->m_nSamples = i + 1; } dwMemPos += 37; } for (iPat = 0; iPat < numpats; iPat++) { MODCOMMAND *p = CSoundFile_AllocatePattern(64, that->m_nChannels); const uint8_t *pin; if (!p) { break; } that->Patterns[iPat] = p; that->PatternSize[iPat] = 64; pin = lpStream + dwMemPos; for (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; } CSoundFile_ConvertModCommand(that, p); pin += 4; p++; } dwMemPos += 64 * 32; } // Read samples for (i = 0; i < that->m_nSamples; i++) { MODINSTRUMENT *psmp = &that->Ins[i + 1]; if (psmp->nLength) { dwMemPos += CSoundFile_ReadSample(that,psmp, RS_PCM8S, (const char *)(lpStream + dwMemPos), dwMemLength); } } return 1; }