// Add or remove rows from the pattern. bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits) //------------------------------------------------------------------------- { CSoundFile &sndFile = GetSoundFile(); ModCommand *newPattern; if(enforceFormatLimits) { const CModSpecifications& specs = sndFile.GetModSpecifications(); if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) return false; } else { if(newRowCount > MAX_PATTERN_ROWS || newRowCount < 1) return false; } if(m_ModCommands == nullptr || newRowCount == m_Rows || (newPattern = AllocatePattern(newRowCount, GetNumChannels())) == nullptr) { return false; } // Copy over pattern data memcpy(newPattern, m_ModCommands, GetNumChannels() * std::min(m_Rows, newRowCount) * sizeof(ModCommand)); FreePattern(m_ModCommands); m_ModCommands = newPattern; m_Rows = newRowCount; return true; }
bool CPattern::Expand() //--------------------- { const ROWINDEX newRows = m_Rows * 2; const CHANNELINDEX nChns = GetNumChannels(); ModCommand *newPattern; if(!m_ModCommands || newRows > GetSoundFile().GetModSpecifications().patternRowsMax || (newPattern = AllocatePattern(newRows, nChns)) == nullptr) { return false; } for(ROWINDEX y = 0; y < m_Rows; y++) { memcpy(newPattern + y * 2 * nChns, m_ModCommands + y * nChns, nChns * sizeof(ModCommand)); } FreePattern(m_ModCommands); m_ModCommands = newPattern; m_Rows = newRows; return true; }
bool CPattern::AllocatePattern(ROWINDEX rows) //------------------------------------------- { ModCommand *m = m_ModCommands; if(m != nullptr && rows == GetNumRows()) { // Re-use allocated memory ClearCommands(); m_ModCommands = nullptr; } else { m = AllocatePattern(rows, GetNumChannels()); if(m == nullptr) { return false; } } Deallocate(); m_ModCommands = m; m_Rows = rows; return true; }
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 CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength) //----------------------------------------------------------- { PSMCHUNK *pfh = (PSMCHUNK *)lpStream; DWORD dwMemPos, dwSongPos; // DWORD smpnames[MAX_SAMPLES]; DWORD patptrs[MAX_PATTERNS]; BYTE samplemap[MAX_SAMPLES]; UINT nPatterns; // Swap chunk swap_PSMCHUNK(pfh); // Chunk0: "PSM ",filesize,"FILE" if (dwMemLength < 256) return FALSE; if (pfh->id == PSM_ID_OLD) { #ifdef PSM_LOG Log("Old PSM format not supported\n"); #endif return FALSE; } if ((pfh->id != PSM_ID_NEW) || (pfh->len+12 > dwMemLength) || (pfh->listid != IFFID_FILE)) return FALSE; m_nType = MOD_TYPE_PSM; m_nChannels = 16; m_nSamples = 0; nPatterns = 0; dwMemPos = 12; dwSongPos = 0; for (UINT iChPan=0; iChPan<16; iChPan++) { UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40; ChnSettings[iChPan].nPan = pan; } while (dwMemPos+8 < dwMemLength) { PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); swap_PSMCHUNK(pchunk); if ((pchunk->len >= dwMemLength - 8) || (dwMemPos + pchunk->len + 8 > dwMemLength)) break; dwMemPos += 8; PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); ULONG len = pchunk->len; if (len) switch(pchunk->id) { // "TITL": Song title case IFFID_TITL: if (!pdata[0]) { pdata++; len--; } memcpy(m_szNames[0], pdata, (len>31) ? 31 : len); m_szNames[0][31] = 0; break; // "PBOD": Pattern case IFFID_PBOD: if ((len >= 12) && (nPatterns < MAX_PATTERNS)) { patptrs[nPatterns++] = dwMemPos-8; } break; // "SONG": Song description case IFFID_SONG: if ((len >= sizeof(PSMSONGHDR)+8) && (!dwSongPos)) { dwSongPos = dwMemPos - 8; } break; // "DSMP": Sample Data case IFFID_DSMP: if ((len >= sizeof(PSMSAMPLE)) && (m_nSamples+1 < MAX_SAMPLES)) { m_nSamples++; MODINSTRUMENT *pins = &Ins[m_nSamples]; PSMSAMPLE *psmp = (PSMSAMPLE *)pdata; swap_PSMSAMPLE(psmp); // smpnames[m_nSamples] = psmp->smpid; memcpy(m_szNames[m_nSamples], psmp->samplename, 31); m_szNames[m_nSamples][31] = 0; samplemap[m_nSamples-1] = (BYTE)m_nSamples; // Init sample pins->nGlobalVol = 0x40; pins->nC4Speed = psmp->samplerate; pins->nLength = psmp->length; pins->nLoopStart = psmp->loopstart; pins->nLoopEnd = psmp->loopend; pins->nPan = 128; pins->nVolume = (psmp->defvol+1) * 2; pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0; if (pins->nLoopStart > 0) pins->nLoopStart--; // Point to sample data pdata += 0x60; len -= 0x60; // Load sample data if ((pins->nLength > 3) && (len > 3)) { ReadSample(pins, RS_PCM8D, (LPCSTR)pdata, len); } else { pins->nLength = 0; } } break; #if 0 default: { CHAR s[8], s2[64]; *(DWORD *)s = pchunk->id; s[4] = 0; wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk->len, dwMemPos); OutputDebugString(s2); } #endif } dwMemPos += pchunk->len; } // Step #1: convert song structure PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8); if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE; m_nChannels = pSong->channels; // Valid song header -> convert attached chunks { DWORD dwSongEnd = dwSongPos + 8 + *(DWORD *)(lpStream+dwSongPos+4); dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR) while (dwMemPos + 8 < dwSongEnd) { PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); swap_PSMCHUNK(pchunk); dwMemPos += 8; if ((pchunk->len > dwSongEnd) || (dwMemPos + pchunk->len > dwSongEnd)) break; PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); ULONG len = pchunk->len; switch(pchunk->id) { case IFFID_OPLH: if (len >= 0x20) { UINT pos = len - 3; while (pos > 5) { BOOL bFound = FALSE; pos -= 5; DWORD dwName = *(DWORD *)(pdata+pos); for (UINT i=0; i<nPatterns; i++) { DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name; if (dwName == dwPatName) { bFound = TRUE; break; } } if ((!bFound) && (pdata[pos+1] > 0) && (pdata[pos+1] <= 0x10) && (pdata[pos+3] > 0x40) && (pdata[pos+3] < 0xC0)) { m_nDefaultSpeed = pdata[pos+1]; m_nDefaultTempo = pdata[pos+3]; break; } } UINT iOrd = 0; while ((pos+5<len) && (iOrd < MAX_ORDERS)) { DWORD dwName = *(DWORD *)(pdata+pos); for (UINT i=0; i<nPatterns; i++) { DWORD dwPatName = ((PSMPATTERN *)(lpStream+patptrs[i]+8))->name; if (dwName == dwPatName) { Order[iOrd++] = i; break; } } pos += 5; } } break; } dwMemPos += pchunk->len; } } // Step #2: convert patterns for (UINT nPat=0; nPat<nPatterns; nPat++) { PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8); swap_PSMPATTERN(pPsmPat); ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12; UINT nRows = pPsmPat->rows; if (len > pPsmPat->size) len = pPsmPat->size; if ((nRows < 64) || (nRows > 256)) nRows = 64; PatternSize[nPat] = nRows; if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break; MODCOMMAND *m = Patterns[nPat]; BYTE *p = pPsmPat->data; UINT pos = 0; UINT row = 0; UINT oldch = 0; // BOOL bNewRow = FALSE; #ifdef PSM_LOG Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream)); #endif while ((row < nRows) && (pos+1 < len)) { UINT flags = p[pos++]; UINT ch = p[pos++]; #ifdef PSM_LOG //Log("flags+ch: %02X.%02X\n", flags, ch); #endif if (((flags & 0xf0) == 0x10) && (ch <= oldch) /*&& (!bNewRow)*/) { if ((pos+1<len) && (!(p[pos] & 0x0f)) && (p[pos+1] < m_nChannels)) { #ifdef PSM_LOG //if (!nPat) Log("Continuing on new row\n"); #endif row++; m += m_nChannels; oldch = ch; continue; } } if ((pos >= len) || (row >= nRows)) break; if (!(flags & 0xf0)) { #ifdef PSM_LOG //if (!nPat) Log("EOR(%d): %02X.%02X\n", row, p[pos], p[pos+1]); #endif row++; m += m_nChannels; // bNewRow = TRUE; oldch = ch; continue; } // bNewRow = FALSE; if (ch >= m_nChannels) { #ifdef PSM_LOG if (!nPat) Log("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch); #endif ch = 0; } // Note + Instr if ((flags & 0x40) && (pos+1 < len)) { UINT note = p[pos++]; UINT nins = p[pos++]; #ifdef PSM_LOG //if (!nPat) Log("note+ins: %02X.%02X\n", note, nins); if ((!nPat) && (nins >= m_nSamples)) Log("WARNING: invalid instrument number (%d)\n", nins); #endif if ((note) && (note < 0x80)) note = (note>>4)*12+(note&0x0f)+12+1; m[ch].instr = samplemap[nins]; m[ch].note = note; } // Volume if ((flags & 0x20) && (pos < len)) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = p[pos++] / 2; } // Effect if ((flags & 0x10) && (pos+1 < len)) { UINT command = p[pos++]; UINT param = p[pos++]; // Convert effects switch(command) { // 01: fine volslide up case 0x01: command = CMD_VOLUMESLIDE; param |= 0x0f; break; // 04: fine volslide down case 0x04: command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0; break; // 0C: portamento up case 0x0C: command = CMD_PORTAMENTOUP; param = (param+1)/2; break; // 0E: portamento down case 0x0E: command = CMD_PORTAMENTODOWN; param = (param+1)/2; break; // 33: Position Jump case 0x33: command = CMD_POSITIONJUMP; break; // 34: Pattern break case 0x34: command = CMD_PATTERNBREAK; break; // 3D: speed case 0x3D: command = CMD_SPEED; break; // 3E: tempo case 0x3E: command = CMD_TEMPO; break; // Unknown default: #ifdef PSM_LOG Log("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param); #endif command = param = 0; } m[ch].command = (BYTE)command; m[ch].param = (BYTE)param; } oldch = ch; }
BOOL CSoundFile::ReadDMF(const BYTE *lpStream, DWORD dwMemLength) //--------------------------------------------------------------- { const DMFHEADER *pfh = (DMFHEADER *)lpStream; DMFINFO *psi; DMFSEQU *sequ; DWORD dwMemPos; BYTE infobyte[32]; BYTE smplflags[MAX_SAMPLES], hasSMPI = 0; if((!lpStream) || (dwMemLength < 1024)) return FALSE; if((pfh->id != 0x464d4444) || (!pfh->version) || (pfh->version & 0xF0)) return FALSE; dwMemPos = 66; memcpy(m_szNames[0], pfh->songname, 30); m_szNames[0][30] = 0; m_nType = MOD_TYPE_DMF; m_nChannels = 0; #ifdef DMFLOG Log("DMF version %d: \"%s\": %d bytes (0x%04X)\n", pfh->version, m_szNames[0], dwMemLength, dwMemLength); #endif while(dwMemPos + 7 < dwMemLength) { DWORD id = *((LPDWORD)(lpStream + dwMemPos)); switch(id) { // "INFO" case 0x4f464e49: // "CMSG" case 0x47534d43: psi = (DMFINFO *)(lpStream + dwMemPos); if(id == 0x47534d43) dwMemPos++; if((psi->infosize > dwMemLength) || (psi->infosize + dwMemPos + 8 > dwMemLength)) goto dmfexit; if((psi->infosize >= 8) && (!m_lpszSongComments)) { m_lpszSongComments = new char[psi->infosize]; // changed from CHAR if(m_lpszSongComments) { for(UINT i = 0; i < psi->infosize - 1; i++) { CHAR c = lpStream[dwMemPos + 8 + i]; if((i % 40) == 39) m_lpszSongComments[i] = 0x0d; else m_lpszSongComments[i] = (c < ' ') ? ' ' : c; } m_lpszSongComments[psi->infosize - 1] = 0; } } dwMemPos += psi->infosize + 8 - 1; break; // "SEQU" case 0x55514553: sequ = (DMFSEQU *)(lpStream + dwMemPos); if((sequ->seqsize >= dwMemLength) || (dwMemPos + sequ->seqsize + 12 > dwMemLength)) goto dmfexit; { UINT nseq = sequ->seqsize >> 1; if(nseq >= MAX_ORDERS - 1) nseq = MAX_ORDERS - 1; if(sequ->loopstart < nseq) m_nRestartPos = sequ->loopstart; for(UINT i = 0; i < nseq; i++) Order[i] = (BYTE)sequ->sequ[i]; } dwMemPos += sequ->seqsize + 8; break; // "PATT" case 0x54544150: if(!m_nChannels) { DMFPATT *patt = (DMFPATT *)(lpStream + dwMemPos); UINT numpat; DWORD dwPos = dwMemPos + 11; if((patt->patsize >= dwMemLength) || (dwMemPos + patt->patsize + 8 > dwMemLength)) goto dmfexit; numpat = patt->numpat; if(numpat > MAX_PATTERNS) numpat = MAX_PATTERNS; m_nChannels = patt->tracks; if(m_nChannels < patt->firstpatinfo) m_nChannels = patt->firstpatinfo; if(m_nChannels > 32) m_nChannels = 32; if(m_nChannels < 4) m_nChannels = 4; for(UINT npat = 0; npat < numpat; npat++) { DMFTRACK *pt = (DMFTRACK *)(lpStream + dwPos); #ifdef DMFLOG Log("Pattern #%d: %d tracks, %d rows\n", npat, pt->tracks, pt->ticks); #endif UINT tracks = pt->tracks; if(tracks > 32) tracks = 32; UINT ticks = pt->ticks; if(ticks > 256) ticks = 256; if(ticks < 16) ticks = 16; dwPos += 8; if((pt->jmpsize >= dwMemLength) || (dwPos + pt->jmpsize + 4 >= dwMemLength)) break; PatternSize[npat] = (WORD)ticks; MODCOMMAND *m = AllocatePattern(PatternSize[npat], m_nChannels); if(!m) goto dmfexit; Patterns[npat] = m; DWORD d = dwPos; dwPos += pt->jmpsize; UINT ttype = 1; UINT tempo = 125; UINT glbinfobyte = 0; UINT pbeat = (pt->beat & 0xf0) ? pt->beat >> 4 : 8; BOOL tempochange = (pt->beat & 0xf0) ? TRUE : FALSE; memset(infobyte, 0, sizeof(infobyte)); for(UINT row = 0; row < ticks; row++) { MODCOMMAND *p = &m[row * m_nChannels]; // Parse track global effects if(!glbinfobyte) { BYTE info = lpStream[d++]; BYTE infoval = 0; if((info & 0x80) && (d < dwPos)) glbinfobyte = lpStream[d++]; info &= 0x7f; if((info) && (d < dwPos)) infoval = lpStream[d++]; switch(info) { case 1: ttype = 0; tempo = infoval; tempochange = TRUE; break; case 2: ttype = 1; tempo = infoval; tempochange = TRUE; break; case 3: pbeat = infoval >> 4; tempochange = ttype; break; #ifdef DMFLOG default: if(info) Log("GLB: %02X.%02X\n", info, infoval); #endif } } else glbinfobyte--; // Parse channels for(UINT i = 0; i < tracks; i++) if(!infobyte[i]) { MODCOMMAND cmd = {0, 0, 0, 0, 0, 0}; BYTE info = lpStream[d++]; if(info & 0x80) infobyte[i] = lpStream[d++]; // Instrument if(info & 0x40) cmd.instr = lpStream[d++]; // Note if(info & 0x20) { cmd.note = lpStream[d++]; if((cmd.note) && (cmd.note < 0xfe)) cmd.note &= 0x7f; if((cmd.note) && (cmd.note < 128)) cmd.note += 24; } // Volume if(info & 0x10) { cmd.volcmd = VOLCMD_VOLUME; cmd.vol = (lpStream[d++] + 3) >> 2; } // Effect 1 if(info & 0x08) { BYTE efx = lpStream[d++]; BYTE eval = lpStream[d++]; switch(efx) { // 1: Key Off case 1: if(!cmd.note) cmd.note = 0xFE; break; // 2: Set Loop // 4: Sample Delay case 4: if(eval & 0xe0) { cmd.command = CMD_S3MCMDEX; cmd.param = (eval >> 5) | 0xD0; } break; // 5: Retrig case 5: if(eval & 0xe0) { cmd.command = CMD_RETRIG; cmd.param = (eval >> 5); } break; // 6: Offset case 6: cmd.command = CMD_OFFSET; cmd.param = eval; break; #ifdef DMFLOG default: Log("FX1: %02X.%02X\n", efx, eval); #endif }
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 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::ReadWav(const BYTE *lpStream, DWORD dwMemLength) //--------------------------------------------------------------- { DWORD dwMemPos = 0; WAVEFILEHEADER *phdr = (WAVEFILEHEADER *)lpStream; WAVEFORMATHEADER *pfmt = (WAVEFORMATHEADER *)(lpStream + sizeof(WAVEFILEHEADER)); if ((!lpStream) || (dwMemLength < (DWORD)sizeof(WAVEFILEHEADER))) return FALSE; if ((phdr->id_RIFF != IFFID_RIFF) || (phdr->id_WAVE != IFFID_WAVE) || (pfmt->id_fmt != IFFID_fmt)) return FALSE; dwMemPos = sizeof(WAVEFILEHEADER) + 8 + pfmt->hdrlen; if ((dwMemPos + 8 >= dwMemLength) || ((pfmt->format != WAVE_FORMAT_PCM) && (pfmt->format != WAVE_FORMAT_EXTENSIBLE)) || (pfmt->channels > 4) || (!pfmt->channels) || (!pfmt->freqHz) || (pfmt->bitspersample & 7) || (pfmt->bitspersample < 8) || (pfmt->bitspersample > 32)) return FALSE; WAVEDATAHEADER *pdata; for (;;) { pdata = (WAVEDATAHEADER *)(lpStream + dwMemPos); if (pdata->id_data == IFFID_data) break; dwMemPos += pdata->length + 8; if (dwMemPos + 8 >= dwMemLength) return FALSE; } m_nType = MOD_TYPE_WAV; m_nSamples = 0; m_nInstruments = 0; m_nChannels = 4; m_nDefaultSpeed = 8; m_nDefaultTempo = 125; m_dwSongFlags |= SONG_LINEARSLIDES; // For no resampling Order[0] = 0; Order[1] = 0xFF; PatternSize[0] = PatternSize[1] = 64; if ((Patterns[0] = AllocatePattern(64, 4)) == NULL) return TRUE; if ((Patterns[1] = AllocatePattern(64, 4)) == NULL) return TRUE; UINT samplesize = (pfmt->channels * pfmt->bitspersample) >> 3; UINT len = pdata->length, bytelen; if (dwMemPos + len > dwMemLength - 8) len = dwMemLength - dwMemPos - 8; len /= samplesize; bytelen = len; if (pfmt->bitspersample >= 16) bytelen *= 2; if (len > MAX_SAMPLE_LENGTH) len = MAX_SAMPLE_LENGTH; if (!len) return TRUE; // Setting up module length DWORD dwTime = ((len * 50) / pfmt->freqHz) + 1; DWORD framesperrow = (dwTime + 63) / 63; if (framesperrow < 4) framesperrow = 4; UINT norders = 1; while (framesperrow >= 0x20) { Order[norders++] = 1; Order[norders] = 0xFF; framesperrow = (dwTime + (64 * norders - 1)) / (64 * norders); if (norders >= MAX_ORDERS-1) break; } m_nDefaultSpeed = framesperrow; for (UINT iChn=0; iChn<4; iChn++) { ChnSettings[iChn].nPan = (iChn & 1) ? 256 : 0; ChnSettings[iChn].nVolume = 64; ChnSettings[iChn].dwFlags = 0; } // Setting up speed command MODCOMMAND *pcmd = Patterns[0]; pcmd[0].command = CMD_SPEED; pcmd[0].param = (BYTE)m_nDefaultSpeed; pcmd[0].note = 5*12+1; pcmd[0].instr = 1; pcmd[1].note = pcmd[0].note; pcmd[1].instr = pcmd[0].instr; m_nSamples = pfmt->channels; // Support for Multichannel Wave for (UINT nChn=0; nChn<m_nSamples; nChn++) { MODINSTRUMENT *pins = &Ins[nChn+1]; pcmd[nChn].note = pcmd[0].note; pcmd[nChn].instr = (BYTE)(nChn+1); pins->nLength = len; pins->nC4Speed = pfmt->freqHz; pins->nVolume = 256; pins->nPan = 128; pins->nGlobalVol = 64; pins->uFlags = (WORD)((pfmt->bitspersample >= 16) ? CHN_16BIT : 0); pins->uFlags |= CHN_PANNING; if (m_nSamples > 1) { switch(nChn) { case 0: pins->nPan = 0; break; case 1: pins->nPan = 256; break; case 2: pins->nPan = (WORD)((m_nSamples == 3) ? 128 : 64); pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; case 3: pins->nPan = 192; pcmd[nChn].command = CMD_S3MCMDEX; pcmd[nChn].param = 0x91; break; default: pins->nPan = 128; break; } } if ((pins->pSample = AllocateSample(bytelen+8)) == NULL) return TRUE; if (pfmt->bitspersample >= 16) { int slsize = pfmt->bitspersample >> 3; signed short *p = (signed short *)pins->pSample; signed char *psrc = (signed char *)(lpStream+dwMemPos+8+nChn*slsize+slsize-2); for (UINT i=0; i<len; i++) { p[i] = *((signed short *)psrc); psrc += samplesize; } p[len+1] = p[len] = p[len-1]; } else {