comparison src/adplug/core/d00.cxx @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/adplug/core/d00.cxx@13389e613d67
children cae46214b8bf
comparison
equal deleted inserted replaced
11:cff1d04026ae 12:3da1b8942b8b
1 /*
2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * d00.c - D00 Player by Simon Peter <dn.tlp@gmx.net>
20 *
21 * NOTES:
22 * Sorry for the goto's, but the code looks so much nicer now.
23 * I tried it with while loops but it was just a mess. If you
24 * can come up with a nicer solution, just tell me.
25 *
26 * BUGS:
27 * Hard restart SR is sometimes wrong
28 */
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <inttypes.h>
33
34 #include "debug.h"
35 #include "d00.h"
36
37 #define HIBYTE(val) (val >> 8)
38 #define LOBYTE(val) (val & 0xff)
39
40 static const unsigned short notetable[12] = // D00 note table
41 {340,363,385,408,432,458,485,514,544,577,611,647};
42
43 static inline uint16_t LE_WORD(const uint16_t *val)
44 {
45 const uint8_t *b = (const uint8_t *)val;
46 return (b[1] << 8) + b[0];
47 }
48
49 /*** public methods *************************************/
50
51 CPlayer *Cd00Player::factory(Copl *newopl)
52 {
53 return new Cd00Player(newopl);
54 }
55
56 bool Cd00Player::load(const std::string &filename, const CFileProvider &fp)
57 {
58 binistream *f = fp.open(filename); if(!f) return false;
59 d00header *checkhead;
60 d00header1 *ch;
61 unsigned long filesize;
62 int i,ver1=0;
63 char *str;
64
65 // file validation section
66 checkhead = new d00header;
67 f->readString((char *)checkhead, sizeof(d00header));
68
69 // Check for version 2-4 header
70 if(strncmp(checkhead->id,"JCH\x26\x02\x66",6) || checkhead->type ||
71 !checkhead->subsongs || checkhead->soundcard) {
72 // Check for version 0 or 1 header (and .d00 file extension)
73 delete checkhead;
74 if(!fp.extension(filename, ".d00")) { fp.close(f); return false; }
75 ch = new d00header1;
76 f->seek(0); f->readString((char *)ch, sizeof(d00header1));
77 if(ch->version > 1 || !ch->subsongs)
78 { delete ch; fp.close(f); return false; }
79 delete ch;
80 ver1 = 1;
81 } else
82 delete checkhead;
83
84 AdPlug_LogWrite("Cd00Player::load(f,\"%s\"): %s format D00 file detected!\n",
85 filename.c_str(), ver1 ? "Old" : "New");
86
87 // load section
88 filesize = fp.filesize(f); f->seek(0);
89 filedata = new char [filesize + 1]; // 1 byte is needed for old-style DataInfo block
90 f->readString((char *)filedata, filesize);
91 fp.close(f);
92 if(!ver1) { // version 2 and above
93 header = (struct d00header *)filedata;
94 version = header->version;
95 datainfo = (char *)filedata + LE_WORD(&header->infoptr);
96 inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header->instptr));
97 seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header->seqptr));
98 for(i=31;i>=0;i--) // erase whitespace
99 if(header->songname[i] == ' ')
100 header->songname[i] = '\0';
101 else
102 break;
103 for(i=31;i>=0;i--)
104 if(header->author[i] == ' ')
105 header->author[i] = '\0';
106 else
107 break;
108 } else { // version 1
109 header1 = (struct d00header1 *)filedata;
110 version = header1->version;
111 datainfo = (char *)filedata + LE_WORD(&header1->infoptr);
112 inst = (struct Sinsts *)((char *)filedata + LE_WORD(&header1->instptr));
113 seqptr = (unsigned short *)((char *)filedata + LE_WORD(&header1->seqptr));
114 }
115 switch(version) {
116 case 0:
117 levpuls = 0;
118 spfx = 0;
119 header1->speed = 70; // v0 files default to 70Hz
120 break;
121 case 1:
122 levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header1->lpulptr));
123 spfx = 0;
124 break;
125 case 2:
126 levpuls = (struct Slevpuls *)((char *)filedata + LE_WORD(&header->spfxptr));
127 spfx = 0;
128 break;
129 case 3:
130 spfx = 0;
131 levpuls = 0;
132 break;
133 case 4:
134 spfx = (struct Sspfx *)((char *)filedata + LE_WORD(&header->spfxptr));
135 levpuls = 0;
136 break;
137 }
138 if((str = strstr(datainfo,"\xff\xff")))
139 while((*str == '\xff' || *str == ' ') && str >= datainfo) {
140 *str = '\0'; str--;
141 }
142 else // old-style block
143 memset((char *)filedata+filesize,0,1);
144
145 rewind(0);
146 return true;
147 }
148
149 bool Cd00Player::update()
150 {
151 unsigned char c,cnt,trackend=0,fx,note;
152 unsigned short ord,*patt,buf,fxop,pattpos;
153
154 // effect handling (timer dependant)
155 for(c=0;c<9;c++) {
156 channel[c].slideval += channel[c].slide; setfreq(c); // sliding
157 vibrato(c); // vibrato
158
159 if(channel[c].spfx != 0xffff) { // SpFX
160 if(channel[c].fxdel)
161 channel[c].fxdel--;
162 else {
163 channel[c].spfx = LE_WORD(&spfx[channel[c].spfx].ptr);
164 channel[c].fxdel = spfx[channel[c].spfx].duration;
165 channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff;
166 if(spfx[channel[c].spfx].modlev != 0xff)
167 channel[c].modvol = spfx[channel[c].spfx].modlev;
168 setinst(c);
169 if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency
170 note = spfx[channel[c].spfx].halfnote;
171 else // unlocked frequency
172 note = spfx[channel[c].spfx].halfnote + channel[c].note;
173 channel[c].freq = notetable[note%12] + ((note/12) << 10);
174 setfreq(c);
175 }
176 channel[c].modvol += spfx[channel[c].spfx].modlevadd; channel[c].modvol &= 63;
177 setvolume(c);
178 }
179
180 if(channel[c].levpuls != 0xff) // Levelpuls
181 if(channel[c].frameskip)
182 channel[c].frameskip--;
183 else {
184 channel[c].frameskip = inst[channel[c].inst].timer;
185 if(channel[c].fxdel)
186 channel[c].fxdel--;
187 else {
188 channel[c].levpuls = levpuls[channel[c].levpuls].ptr - 1;
189 channel[c].fxdel = levpuls[channel[c].levpuls].duration;
190 if(levpuls[channel[c].levpuls].level != 0xff)
191 channel[c].modvol = levpuls[channel[c].levpuls].level;
192 }
193 channel[c].modvol += levpuls[channel[c].levpuls].voladd; channel[c].modvol &= 63;
194 setvolume(c);
195 }
196 }
197
198 // song handling
199 for(c=0;c<9;c++)
200 if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) {
201 if(version == 4) // v4: hard restart SR
202 if(channel[c].del == inst[channel[c].inst].timer)
203 if(channel[c].nextnote)
204 opl->write(0x83 + op_table[c], inst[channel[c].inst].sr);
205 if(version < 3)
206 channel[c].del--;
207 else
208 if(channel[c].speed)
209 channel[c].del += channel[c].speed;
210 else {
211 channel[c].seqend = 1;
212 continue;
213 }
214 } else {
215 if(channel[c].speed) {
216 if(version < 3)
217 channel[c].del = channel[c].speed;
218 else {
219 channel[c].del &= 0x7f;
220 channel[c].del += channel[c].speed;
221 }
222 } else {
223 channel[c].seqend = 1;
224 continue;
225 }
226 if(channel[c].rhcnt) { // process pending REST/HOLD events
227 channel[c].rhcnt--;
228 continue;
229 }
230 readorder: // process arrangement (orderlist)
231 ord = LE_WORD(&channel[c].order[channel[c].ordpos]);
232 switch(ord) {
233 case 0xfffe: channel[c].seqend = 1; continue; // end of arrangement stream
234 case 0xffff: // jump to order
235 channel[c].ordpos = LE_WORD(&channel[c].order[channel[c].ordpos + 1]);
236 channel[c].seqend = 1;
237 goto readorder;
238 default:
239 if(ord >= 0x9000) { // set speed
240 channel[c].speed = ord & 0xff;
241 ord = LE_WORD(&channel[c].order[channel[c].ordpos - 1]);
242 channel[c].ordpos++;
243 } else
244 if(ord >= 0x8000) { // transpose track
245 channel[c].transpose = ord & 0xff;
246 if(ord & 0x100)
247 channel[c].transpose = -channel[c].transpose;
248 ord = LE_WORD(&channel[c].order[++channel[c].ordpos]);
249 }
250 patt = (unsigned short *)((char *)filedata + LE_WORD(&seqptr[ord]));
251 break;
252 }
253 readseq: // process sequence (pattern)
254 if(!version) // v0: always initialize rhcnt
255 channel[c].rhcnt = channel[c].irhcnt;
256 pattpos = LE_WORD(&patt[channel[c].pattpos]);
257 if(pattpos == 0xffff) { // pattern ended?
258 channel[c].pattpos = 0;
259 channel[c].ordpos++;
260 goto readorder;
261 }
262 cnt = HIBYTE(pattpos);
263 note = LOBYTE(pattpos);
264 fx = pattpos >> 12;
265 fxop = pattpos & 0x0fff;
266 channel[c].pattpos++; pattpos = LE_WORD(&patt[channel[c].pattpos]);
267 channel[c].nextnote = LOBYTE(pattpos) & 0x7f;
268 if(version ? cnt < 0x40 : !fx) { // note event
269 switch(note) {
270 case 0: // REST event
271 case 0x80:
272 if(!note || version) {
273 channel[c].key = 0;
274 setfreq(c);
275 }
276 // fall through...
277 case 0x7e: // HOLD event
278 if(version)
279 channel[c].rhcnt = cnt;
280 channel[c].nextnote = 0;
281 break;
282 default: // play note
283 // restart fx
284 channel[c].slideval = 0; channel[c].slide = 0; channel[c].vibdepth = 0;
285
286 if(version) { // note handling for v1 and above
287 if(note > 0x80) // locked note (no channel transpose)
288 note -= 0x80;
289 else // unlocked note
290 note += channel[c].transpose;
291 channel[c].note = note; // remember note for SpFX
292
293 if(channel[c].ispfx != 0xffff && cnt < 0x20) { // reset SpFX
294 channel[c].spfx = channel[c].ispfx;
295 if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000) // locked frequency
296 note = spfx[channel[c].spfx].halfnote;
297 else // unlocked frequency
298 note += spfx[channel[c].spfx].halfnote;
299 channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff;
300 channel[c].fxdel = spfx[channel[c].spfx].duration;
301 if(spfx[channel[c].spfx].modlev != 0xff)
302 channel[c].modvol = spfx[channel[c].spfx].modlev;
303 else
304 channel[c].modvol = inst[channel[c].inst].data[7] & 63;
305 }
306
307 if(channel[c].ilevpuls != 0xff && cnt < 0x20) { // reset LevelPuls
308 channel[c].levpuls = channel[c].ilevpuls;
309 channel[c].fxdel = levpuls[channel[c].levpuls].duration;
310 channel[c].frameskip = inst[channel[c].inst].timer;
311 if(levpuls[channel[c].levpuls].level != 0xff)
312 channel[c].modvol = levpuls[channel[c].levpuls].level;
313 else
314 channel[c].modvol = inst[channel[c].inst].data[7] & 63;
315 }
316
317 channel[c].freq = notetable[note%12] + ((note/12) << 10);
318 if(cnt < 0x20) // normal note
319 playnote(c);
320 else { // tienote
321 setfreq(c);
322 cnt -= 0x20; // make count proper
323 }
324 channel[c].rhcnt = cnt;
325 } else { // note handling for v0
326 if(cnt < 2) // unlocked note
327 note += channel[c].transpose;
328 channel[c].note = note;
329
330 channel[c].freq = notetable[note%12] + ((note/12) << 10);
331 if(cnt == 1) // tienote
332 setfreq(c);
333 else // normal note
334 playnote(c);
335 }
336 break;
337 }
338 continue; // event is complete
339 } else { // effect event
340 switch(fx) {
341 case 6: // Cut/Stop Voice
342 buf = channel[c].inst;
343 channel[c].inst = 0;
344 playnote(c);
345 channel[c].inst = buf;
346 channel[c].rhcnt = fxop;
347 continue; // no note follows this event
348 case 7: // Vibrato
349 channel[c].vibspeed = fxop & 0xff;
350 channel[c].vibdepth = fxop >> 8;
351 channel[c].trigger = fxop >> 9;
352 break;
353 case 8: // v0: Duration
354 if(!version)
355 channel[c].irhcnt = fxop;
356 break;
357 case 9: // New Level
358 channel[c].vol = fxop & 63;
359 if(channel[c].vol + channel[c].cvol < 63) // apply channel volume
360 channel[c].vol += channel[c].cvol;
361 else
362 channel[c].vol = 63;
363 setvolume(c);
364 break;
365 case 0xb: // v4: Set SpFX
366 if(version == 4)
367 channel[c].ispfx = fxop;
368 break;
369 case 0xc: // Set Instrument
370 channel[c].ispfx = 0xffff;
371 channel[c].spfx = 0xffff;
372 channel[c].inst = fxop;
373 channel[c].modvol = inst[fxop].data[7] & 63;
374 if(version < 3 && version && inst[fxop].tunelev) // Set LevelPuls
375 channel[c].ilevpuls = inst[fxop].tunelev - 1;
376 else {
377 channel[c].ilevpuls = 0xff;
378 channel[c].levpuls = 0xff;
379 }
380 break;
381 case 0xd: // Slide up
382 channel[c].slide = fxop;
383 break;
384 case 0xe: // Slide down
385 channel[c].slide = -fxop;
386 break;
387 }
388 goto readseq; // event is incomplete, note follows
389 }
390 }
391
392 for(c=0;c<9;c++)
393 if(channel[c].seqend)
394 trackend++;
395 if(trackend == 9)
396 songend = 1;
397
398 return !songend;
399 }
400
401 void Cd00Player::rewind(int subsong)
402 {
403 struct Stpoin {
404 unsigned short ptr[9];
405 unsigned char volume[9],dummy[5];
406 } *tpoin;
407 int i;
408
409 if(version > 1) { // do nothing if subsong > number of subsongs
410 if(subsong >= header->subsongs)
411 return;
412 } else
413 if(subsong >= header1->subsongs)
414 return;
415
416 memset(channel,0,sizeof(channel));
417 if(version > 1)
418 tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header->tpoin));
419 else
420 tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header1->tpoin));
421 for(i=0;i<9;i++) {
422 if(LE_WORD(&tpoin[subsong].ptr[i])) { // track enabled
423 channel[i].speed = LE_WORD((unsigned short *)
424 ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i])));
425 channel[i].order = (unsigned short *)
426 ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]) + 2);
427 } else { // track disabled
428 channel[i].speed = 0;
429 channel[i].order = 0;
430 }
431 channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff; // no SpFX
432 channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff; // no LevelPuls
433 channel[i].cvol = tpoin[subsong].volume[i] & 0x7f; // our player may savely ignore bit 7
434 channel[i].vol = channel[i].cvol; // initialize volume
435 }
436 songend = 0;
437 opl->init(); opl->write(1,32); // reset OPL chip
438 }
439
440 std::string Cd00Player::gettype()
441 {
442 char tmpstr[40];
443
444 sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version);
445 return std::string(tmpstr);
446 }
447
448 float Cd00Player::getrefresh()
449 {
450 if(version > 1)
451 return header->speed;
452 else
453 return header1->speed;
454 }
455
456 unsigned int Cd00Player::getsubsongs()
457 {
458 if(version <= 1) // return number of subsongs
459 return header1->subsongs;
460 else
461 return header->subsongs;
462 }
463
464 /*** private methods *************************************/
465
466 void Cd00Player::setvolume(unsigned char chan)
467 {
468 unsigned char op = op_table[chan];
469 unsigned short insnr = channel[chan].inst;
470
471 opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) +
472 (inst[insnr].data[2] & 192));
473 if(inst[insnr].data[10] & 1)
474 opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) +
475 (inst[insnr].data[7] & 192));
476 else
477 opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192));
478 }
479
480 void Cd00Player::setfreq(unsigned char chan)
481 {
482 unsigned short freq = channel[chan].freq;
483
484 if(version == 4) // v4: apply instrument finetune
485 freq += inst[channel[chan].inst].tunelev;
486
487 freq += channel[chan].slideval;
488 opl->write(0xa0 + chan, freq & 255);
489 if(channel[chan].key)
490 opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32);
491 else
492 opl->write(0xb0 + chan, (freq >> 8) & 31);
493 }
494
495 void Cd00Player::setinst(unsigned char chan)
496 {
497 unsigned char op = op_table[chan];
498 unsigned short insnr = channel[chan].inst;
499
500 // set instrument data
501 opl->write(0x63 + op, inst[insnr].data[0]);
502 opl->write(0x83 + op, inst[insnr].data[1]);
503 opl->write(0x23 + op, inst[insnr].data[3]);
504 opl->write(0xe3 + op, inst[insnr].data[4]);
505 opl->write(0x60 + op, inst[insnr].data[5]);
506 opl->write(0x80 + op, inst[insnr].data[6]);
507 opl->write(0x20 + op, inst[insnr].data[8]);
508 opl->write(0xe0 + op, inst[insnr].data[9]);
509 if(version)
510 opl->write(0xc0 + chan, inst[insnr].data[10]);
511 else
512 opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1));
513 }
514
515 void Cd00Player::playnote(unsigned char chan)
516 {
517 // set misc vars & play
518 opl->write(0xb0 + chan, 0); // stop old note
519 setinst(chan);
520 channel[chan].key = 1;
521 setfreq(chan);
522 setvolume(chan);
523 }
524
525 void Cd00Player::vibrato(unsigned char chan)
526 {
527 if(!channel[chan].vibdepth)
528 return;
529
530 if(channel[chan].trigger)
531 channel[chan].trigger--;
532 else {
533 channel[chan].trigger = channel[chan].vibdepth;
534 channel[chan].vibspeed = -channel[chan].vibspeed;
535 }
536 channel[chan].freq += channel[chan].vibspeed;
537 setfreq(chan);
538 }