Mercurial > audlegacy-plugins
comparison src/modplug/load_psm.cxx @ 2337:107c1fed3d92
Port Schism modplug core.
author | "Tony Vroon <chainsaw@gentoo.org>" |
---|---|
date | Thu, 24 Jan 2008 12:05:59 +0000 |
parents | 6907fc39b53f |
children |
comparison
equal
deleted
inserted
replaced
2336:ad45d65e9ae7 | 2337:107c1fed3d92 |
---|---|
77 | 77 |
78 BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength) | 78 BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength) |
79 //----------------------------------------------------------- | 79 //----------------------------------------------------------- |
80 { | 80 { |
81 PSMCHUNK *pfh = (PSMCHUNK *)lpStream; | 81 PSMCHUNK *pfh = (PSMCHUNK *)lpStream; |
82 PSMCHUNK pfh_swap; | |
83 DWORD dwMemPos, dwSongPos; | 82 DWORD dwMemPos, dwSongPos; |
84 DWORD smpnames[MAX_SAMPLES]; | 83 DWORD smpnames[MAX_SAMPLES]; |
85 DWORD patptrs[MAX_PATTERNS]; | 84 DWORD patptrs[MAX_PATTERNS]; |
86 BYTE samplemap[MAX_SAMPLES]; | 85 BYTE samplemap[MAX_SAMPLES]; |
87 UINT nPatterns; | 86 UINT nPatterns; |
88 | 87 |
89 pfh_swap.id = bswapLE32(pfh->id); | |
90 pfh_swap.len = bswapLE32(pfh->len); | |
91 pfh_swap.listid = bswapLE32(pfh->listid); | |
92 | |
93 // Chunk0: "PSM ",filesize,"FILE" | 88 // Chunk0: "PSM ",filesize,"FILE" |
94 if (dwMemLength < 256) return FALSE; | 89 if (dwMemLength < 256) return FALSE; |
95 if (pfh_swap.id == PSM_ID_OLD) | 90 if (bswapLE32(pfh->id) == PSM_ID_OLD) |
96 { | 91 { |
97 #ifdef PSM_LOG | 92 #ifdef PSM_LOG |
98 Log("Old PSM format not supported\n"); | 93 printf("Old PSM format not supported\n"); |
99 #endif | 94 #endif |
100 return FALSE; | 95 return FALSE; |
101 } | 96 } |
102 if ((pfh_swap.id != PSM_ID_NEW) || (pfh_swap.len+12 > dwMemLength) || (pfh_swap.listid != IFFID_FILE)) return FALSE; | 97 if ((bswapLE32(pfh->id) != PSM_ID_NEW) |
98 || (bswapLE32(pfh->len)+12 > dwMemLength) | |
99 || (bswapLE32(pfh->listid) != IFFID_FILE)) return FALSE; | |
103 m_nType = MOD_TYPE_PSM; | 100 m_nType = MOD_TYPE_PSM; |
104 m_nChannels = 16; | 101 m_nChannels = 16; |
105 m_nSamples = 0; | 102 m_nSamples = 0; |
106 nPatterns = 0; | 103 nPatterns = 0; |
107 dwMemPos = 12; | 104 dwMemPos = 12; |
109 for (UINT iChPan=0; iChPan<16; iChPan++) | 106 for (UINT iChPan=0; iChPan<16; iChPan++) |
110 { | 107 { |
111 UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40; | 108 UINT pan = (((iChPan & 3) == 1) || ((iChPan&3)==2)) ? 0xC0 : 0x40; |
112 ChnSettings[iChPan].nPan = pan; | 109 ChnSettings[iChPan].nPan = pan; |
113 } | 110 } |
111 m_szNames[0][0]=0; | |
114 while (dwMemPos+8 < dwMemLength) | 112 while (dwMemPos+8 < dwMemLength) |
115 { | 113 { |
116 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); | 114 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); |
117 | 115 if ((bswapLE32(pchunk->len) >= dwMemLength - 8) |
118 pchunk->id = bswapLE32(pchunk->id); | 116 || (dwMemPos + bswapLE32(pchunk->len) + 8 > dwMemLength)) break; |
119 pchunk->len = bswapLE32(pchunk->len); | |
120 pchunk->listid = bswapLE32(pchunk->listid); | |
121 | |
122 if ((pchunk->len >= dwMemLength - 8) || (dwMemPos + pchunk->len + 8 > dwMemLength)) break; | |
123 dwMemPos += 8; | 117 dwMemPos += 8; |
124 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); | 118 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); |
125 ULONG len = pchunk->len; | 119 ULONG len = bswapLE32(pchunk->len); |
126 if (len) switch(pchunk->id) | 120 if (len) switch(bswapLE32(pchunk->id)) |
127 { | 121 { |
128 // "TITL": Song title | 122 // "TITL": Song title |
129 case IFFID_TITL: | 123 case IFFID_TITL: |
130 if (!pdata[0]) { pdata++; len--; } | 124 if (!pdata[0]) { pdata++; len--; } |
131 memcpy(m_szNames[0], pdata, (len>31) ? 31 : len); | 125 memcpy(m_szNames[0], pdata, (len>31) ? 31 : len); |
150 if ((len >= sizeof(PSMSAMPLE)) && (m_nSamples+1 < MAX_SAMPLES)) | 144 if ((len >= sizeof(PSMSAMPLE)) && (m_nSamples+1 < MAX_SAMPLES)) |
151 { | 145 { |
152 m_nSamples++; | 146 m_nSamples++; |
153 MODINSTRUMENT *pins = &Ins[m_nSamples]; | 147 MODINSTRUMENT *pins = &Ins[m_nSamples]; |
154 PSMSAMPLE *psmp = (PSMSAMPLE *)pdata; | 148 PSMSAMPLE *psmp = (PSMSAMPLE *)pdata; |
155 | 149 smpnames[m_nSamples] = bswapLE32(psmp->smpid); |
156 psmp->smpid = bswapLE32(psmp->smpid); | |
157 psmp->length = bswapLE32(psmp->length); | |
158 psmp->loopstart = bswapLE32(psmp->loopstart); | |
159 psmp->loopend = bswapLE32(psmp->loopend); | |
160 psmp->samplerate = bswapLE32(psmp->samplerate); | |
161 | |
162 smpnames[m_nSamples] = psmp->smpid; | |
163 memcpy(m_szNames[m_nSamples], psmp->samplename, 31); | 150 memcpy(m_szNames[m_nSamples], psmp->samplename, 31); |
164 m_szNames[m_nSamples][31] = 0; | 151 m_szNames[m_nSamples][31] = 0; |
165 samplemap[m_nSamples-1] = (BYTE)m_nSamples; | 152 samplemap[m_nSamples-1] = (BYTE)m_nSamples; |
166 // Init sample | 153 // Init sample |
167 pins->nGlobalVol = 0x40; | 154 pins->nGlobalVol = 0x40; |
168 pins->nC4Speed = psmp->samplerate; | 155 pins->nC4Speed = bswapLE32(psmp->samplerate); |
169 pins->nLength = psmp->length; | 156 pins->nLength = bswapLE32(psmp->length); |
170 pins->nLoopStart = psmp->loopstart; | 157 pins->nLoopStart = bswapLE32(psmp->loopstart); |
171 pins->nLoopEnd = psmp->loopend; | 158 pins->nLoopEnd = bswapLE32(psmp->loopend); |
172 pins->nPan = 128; | 159 pins->nPan = 128; |
173 pins->nVolume = (psmp->defvol+1) * 2; | 160 pins->nVolume = (psmp->defvol+1) * 2; |
174 pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0; | 161 pins->uFlags = (psmp->flags & 0x80) ? CHN_LOOP : 0; |
175 if (pins->nLoopStart > 0) pins->nLoopStart--; | 162 if (pins->nLoopStart > 0) pins->nLoopStart--; |
176 // Point to sample data | 163 // Point to sample data |
195 wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk->len, dwMemPos); | 182 wsprintf(s2, "%s: %4d bytes @ %4d\n", s, pchunk->len, dwMemPos); |
196 OutputDebugString(s2); | 183 OutputDebugString(s2); |
197 } | 184 } |
198 #endif | 185 #endif |
199 } | 186 } |
200 dwMemPos += pchunk->len; | 187 dwMemPos += bswapLE32(pchunk->len); |
201 } | 188 } |
202 // Step #1: convert song structure | 189 // Step #1: convert song structure |
203 PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8); | 190 PSMSONGHDR *pSong = (PSMSONGHDR *)(lpStream+dwSongPos+8); |
204 if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE; | 191 if ((!dwSongPos) || (pSong->channels < 2) || (pSong->channels > 32)) return TRUE; |
205 m_nChannels = pSong->channels; | 192 m_nChannels = pSong->channels; |
208 DWORD dwSongEnd = dwSongPos + 8 + *(DWORD *)(lpStream+dwSongPos+4); | 195 DWORD dwSongEnd = dwSongPos + 8 + *(DWORD *)(lpStream+dwSongPos+4); |
209 dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR) | 196 dwMemPos = dwSongPos + 8 + 11; // sizeof(PSMCHUNK)+sizeof(PSMSONGHDR) |
210 while (dwMemPos + 8 < dwSongEnd) | 197 while (dwMemPos + 8 < dwSongEnd) |
211 { | 198 { |
212 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); | 199 PSMCHUNK *pchunk = (PSMCHUNK *)(lpStream+dwMemPos); |
213 | |
214 pchunk->id = bswapLE32(pchunk->id); | |
215 pchunk->len = bswapLE32(pchunk->len); | |
216 pchunk->listid = bswapLE32(pchunk->listid); | |
217 | |
218 dwMemPos += 8; | 200 dwMemPos += 8; |
219 if ((pchunk->len > dwSongEnd) || (dwMemPos + pchunk->len > dwSongEnd)) break; | 201 if ((bswapLE32(pchunk->len) > dwSongEnd) |
202 || (dwMemPos + bswapLE32(pchunk->len) > dwSongEnd)) break; | |
220 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); | 203 PUCHAR pdata = (PUCHAR)(lpStream+dwMemPos); |
221 ULONG len = pchunk->len; | 204 ULONG len = bswapLE32(pchunk->len); |
222 switch(pchunk->id) | 205 switch(bswapLE32(pchunk->id)) |
223 { | 206 { |
224 case IFFID_OPLH: | 207 case IFFID_OPLH: |
225 if (len >= 0x20) | 208 if (len >= 0x20) |
226 { | 209 { |
227 UINT pos = len - 3; | 210 UINT pos = len - 3; |
263 pos += 5; | 246 pos += 5; |
264 } | 247 } |
265 } | 248 } |
266 break; | 249 break; |
267 } | 250 } |
268 dwMemPos += pchunk->len; | 251 dwMemPos += bswapLE32(pchunk->len); |
269 } | 252 } |
270 } | 253 } |
271 | 254 |
272 // Step #2: convert patterns | 255 // Step #2: convert patterns |
273 for (UINT nPat=0; nPat<nPatterns; nPat++) | 256 for (UINT nPat=0; nPat<nPatterns; nPat++) |
274 { | 257 { |
275 PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8); | 258 PSMPATTERN *pPsmPat = (PSMPATTERN *)(lpStream+patptrs[nPat]+8); |
276 | 259 ULONG len = bswapLE32(*(DWORD *)(lpStream+patptrs[nPat]+4)) - 12; |
277 pPsmPat->size = bswapLE32(pPsmPat->size); | 260 UINT nRows = bswapLE16(pPsmPat->rows); |
278 pPsmPat->name = bswapLE32(pPsmPat->name); | 261 if (len > bswapLE32(pPsmPat->size)) len = bswapLE32(pPsmPat->size); |
279 pPsmPat->rows = bswapLE16(pPsmPat->rows); | |
280 | |
281 ULONG len = *(DWORD *)(lpStream+patptrs[nPat]+4) - 12; | |
282 UINT nRows = pPsmPat->rows; | |
283 if (len > pPsmPat->size) len = pPsmPat->size; | |
284 if ((nRows < 64) || (nRows > 256)) nRows = 64; | 262 if ((nRows < 64) || (nRows > 256)) nRows = 64; |
285 PatternSize[nPat] = nRows; | 263 PatternSize[nPat] = nRows; |
264 PatternAllocSize[nPat] = nRows; | |
286 if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break; | 265 if ((Patterns[nPat] = AllocatePattern(nRows, m_nChannels)) == NULL) break; |
287 MODCOMMAND *m = Patterns[nPat]; | 266 MODCOMMAND *m = Patterns[nPat]; |
267 MODCOMMAND *sp, dummy; | |
288 BYTE *p = pPsmPat->data; | 268 BYTE *p = pPsmPat->data; |
289 UINT pos = 0; | 269 UINT pos = 0; |
290 UINT row = 0; | 270 UINT row = 0; |
291 UINT oldch = 0; | 271 UINT rowlim; |
292 BOOL bNewRow = FALSE; | |
293 #ifdef PSM_LOG | 272 #ifdef PSM_LOG |
294 Log("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream)); | 273 //printf("Pattern %d at offset 0x%04X\n", nPat, (DWORD)(p - (BYTE *)lpStream)); |
295 #endif | 274 #endif |
275 rowlim = bswapLE16(pPsmPat->reserved1)-2; | |
296 while ((row < nRows) && (pos+1 < len)) | 276 while ((row < nRows) && (pos+1 < len)) |
297 { | 277 { |
298 UINT flags = p[pos++]; | 278 UINT flags, ch; |
299 UINT ch = p[pos++]; | 279 if ((pos+1) >= rowlim) { |
300 | 280 pos = rowlim; |
301 #ifdef PSM_LOG | 281 rowlim = (((int)p[pos+1])<<8) |
302 //Log("flags+ch: %02X.%02X\n", flags, ch); | 282 | ((int)p[pos+0]); |
303 #endif | 283 m += m_nChannels; |
304 if (((flags & 0xf0) == 0x10) && (ch <= oldch) /*&& (!bNewRow)*/) | 284 row++; |
285 rowlim += pos; | |
286 pos += 2; | |
287 } | |
288 flags = p[pos++]; | |
289 ch = p[pos++]; | |
290 if (ch >= m_nChannels) { | |
291 #ifdef PSM_LOG | |
292 printf("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch); | |
293 #endif | |
294 sp = &dummy; | |
295 } else { | |
296 sp = &m[ch]; | |
297 } | |
298 // Note + Instr | |
299 if ((flags & 0x80) && (pos+1 < len)) | |
305 { | 300 { |
306 if ((pos+1<len) && (!(p[pos] & 0x0f)) && (p[pos+1] < m_nChannels)) | 301 UINT note = p[pos++]; |
307 { | 302 note = (note>>4)*12+(note&0x0f)+12+1; |
308 #ifdef PSM_LOG | 303 if (note > 0x80) note = 0; |
309 //if (!nPat) Log("Continuing on new row\n"); | 304 sp->note = note; |
310 #endif | 305 } |
311 row++; | |
312 m += m_nChannels; | |
313 oldch = ch; | |
314 continue; | |
315 } | |
316 } | |
317 if ((pos >= len) || (row >= nRows)) break; | |
318 if (!(flags & 0xf0)) | |
319 { | |
320 #ifdef PSM_LOG | |
321 //if (!nPat) Log("EOR(%d): %02X.%02X\n", row, p[pos], p[pos+1]); | |
322 #endif | |
323 row++; | |
324 m += m_nChannels; | |
325 bNewRow = TRUE; | |
326 oldch = ch; | |
327 continue; | |
328 } | |
329 bNewRow = FALSE; | |
330 if (ch >= m_nChannels) | |
331 { | |
332 #ifdef PSM_LOG | |
333 if (!nPat) Log("Invalid channel row=%d (0x%02X.0x%02X)\n", row, flags, ch); | |
334 #endif | |
335 ch = 0; | |
336 } | |
337 // Note + Instr | |
338 if ((flags & 0x40) && (pos+1 < len)) | 306 if ((flags & 0x40) && (pos+1 < len)) |
339 { | 307 { |
340 UINT note = p[pos++]; | |
341 UINT nins = p[pos++]; | 308 UINT nins = p[pos++]; |
342 #ifdef PSM_LOG | 309 #ifdef PSM_LOG |
343 //if (!nPat) Log("note+ins: %02X.%02X\n", note, nins); | 310 if ((!nPat) && (nins >= m_nSamples)) printf("WARNING: invalid instrument number (%d)\n", nins); |
344 if ((!nPat) && (nins >= m_nSamples)) Log("WARNING: invalid instrument number (%d)\n", nins); | |
345 #endif | 311 #endif |
346 if ((note) && (note < 0x80)) note = (note>>4)*12+(note&0x0f)+12+1; | 312 sp->instr = samplemap[nins]; |
347 m[ch].instr = samplemap[nins]; | |
348 m[ch].note = note; | |
349 } | 313 } |
350 // Volume | 314 // Volume |
351 if ((flags & 0x20) && (pos < len)) | 315 if ((flags & 0x20) && (pos < len)) |
352 { | 316 { |
353 m[ch].volcmd = VOLCMD_VOLUME; | 317 sp->volcmd = VOLCMD_VOLUME; |
354 m[ch].vol = p[pos++] / 2; | 318 sp->vol = p[pos++] / 2; |
355 } | 319 } |
356 // Effect | 320 // Effect |
357 if ((flags & 0x10) && (pos+1 < len)) | 321 if ((flags & 0x10) && (pos+1 < len)) |
358 { | 322 { |
359 UINT command = p[pos++]; | 323 UINT command = p[pos++]; |
360 UINT param = p[pos++]; | 324 UINT param = p[pos++]; |
361 // Convert effects | 325 // Convert effects |
362 switch(command) | 326 switch(command & 0x3F) |
363 { | 327 { |
364 // 01: fine volslide up | 328 // 01: fine volslide up |
365 case 0x01: command = CMD_VOLUMESLIDE; param |= 0x0f; break; | 329 case 0x01: |
366 // 04: fine volslide down | 330 #if PSM_LOG |
367 case 0x04: command = CMD_VOLUMESLIDE; param>>=4; param |= 0xf0; break; | 331 printf("fvup command pat=%d row=%d ch=%d %02x %02x\n", |
332 nPat, | |
333 row,1+ch, | |
334 command, param); | |
335 #endif | |
336 #if 0 | |
337 if (!sp->volcmd) { | |
338 sp->volcmd = VOLCMD_FINEVOLUP; | |
339 sp->vol = (param >> 1) & 0xF; | |
340 command = CMD_PORTAMENTOUP; | |
341 param>>=4; param |= 0xf0; | |
342 if (param == 240) param=241; | |
343 } else { | |
344 #endif | |
345 command = CMD_VOLUMESLIDE; | |
346 param |= 0x0f; | |
347 if (param == 15) param=31; | |
348 break; | |
349 // 02: volslide up | |
350 case 0x02: command = CMD_VOLUMESLIDE; param>>=1; param<<=4; break; | |
351 // 03: fine volslide down | |
352 case 0x03: | |
353 #if PSM_LOG | |
354 printf("fvdown command pat=%d row=%d ch=%d %02x %02x\n", | |
355 nPat, | |
356 row,1+ch, | |
357 command, param); | |
358 #endif | |
359 #if 0 | |
360 if (!sp->volcmd) { | |
361 sp->volcmd = VOLCMD_FINEVOLDOWN; | |
362 sp->vol = (param >> 2) & 0xF; | |
363 if (!sp->vol) sp->vol = 1; | |
364 command = CMD_PORTAMENTODOWN; | |
365 } | |
366 #endif | |
367 command = CMD_VOLUMESLIDE; | |
368 param>>=4; param |= 0xf0; | |
369 if (param == 240) param=241; | |
370 break; | |
371 // 04: volslide down | |
372 case 0x04: command = CMD_VOLUMESLIDE; param>>=1; break; | |
368 // 0C: portamento up | 373 // 0C: portamento up |
369 case 0x0C: command = CMD_PORTAMENTOUP; param = (param+1)/2; break; | 374 case 0x0C: command = CMD_PORTAMENTOUP; param = (param+1)/2; break; |
370 // 0E: portamento down | 375 // 0E: portamento down |
371 case 0x0E: command = CMD_PORTAMENTODOWN; param = (param+1)/2; break; | 376 case 0x0E: command = CMD_PORTAMENTODOWN; param = (param+1)/2; break; |
377 // 0F: tone portamento | |
378 case 0x0F: command = CMD_TONEPORTAMENTO; param = param/4; break; | |
379 // 15: vibrato | |
380 case 0x15: command = CMD_VIBRATO; break; | |
381 // 29: wtf | |
382 case 0x29: pos += 2; break; | |
383 // 2A: retrig | |
384 case 0x2A: command = CMD_RETRIG; break; | |
372 // 33: Position Jump | 385 // 33: Position Jump |
373 case 0x33: command = CMD_POSITIONJUMP; break; | 386 case 0x33: command = CMD_POSITIONJUMP; break; |
374 // 34: Pattern break | 387 // 34: Pattern break |
375 case 0x34: command = CMD_PATTERNBREAK; break; | 388 case 0x34: command = CMD_PATTERNBREAK; break; |
376 // 3D: speed | 389 // 3D: speed |
377 case 0x3D: command = CMD_SPEED; break; | 390 case 0x3D: command = CMD_SPEED; |
391 if (!row && !nPat) | |
392 m_nDefaultSpeed = param; | |
393 break; | |
378 // 3E: tempo | 394 // 3E: tempo |
379 case 0x3E: command = CMD_TEMPO; break; | 395 case 0x3E: command = CMD_TEMPO; |
396 if (!row && !nPat) | |
397 m_nDefaultTempo = param; | |
398 break; | |
380 // Unknown | 399 // Unknown |
381 default: | 400 default: |
382 #ifdef PSM_LOG | 401 #ifdef PSM_LOG |
383 Log("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param); | 402 printf("Unknown PSM effect pat=%d row=%d ch=%d: %02X.%02X\n", nPat, row, ch, command, param); |
384 #endif | 403 #endif |
385 command = param = 0; | 404 command = param = 0; |
386 } | 405 } |
387 m[ch].command = (BYTE)command; | 406 sp->command = (BYTE)command; |
388 m[ch].param = (BYTE)param; | 407 sp->param = (BYTE)param; |
389 } | 408 } |
390 oldch = ch; | |
391 } | 409 } |
392 #ifdef PSM_LOG | 410 #ifdef PSM_LOG |
393 if (pos < len) | 411 if (pos < len) |
394 { | 412 { |
395 Log("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos); | 413 // printf("Pattern %d: %d/%d[%d] rows (%d bytes) -> %d bytes left\n", nPat, row, nRows, pPsmPat->rows, pPsmPat->size, len-pos); |
396 } | 414 } |
397 #endif | 415 #endif |
398 } | 416 } |
399 | 417 |
400 // Done (finally!) | 418 // Done (finally!) |