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!)