]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug-2.2.1/src/d00.cpp
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / adplug-2.2.1 / src / d00.cpp
1 /*
2  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3  * Copyright (C) 1999 - 2008 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
199   // song handling
200   for(c=0;c<9;c++)
201     if(version < 3 ? channel[c].del : channel[c].del <= 0x7f) {
202       if(version == 4)  // v4: hard restart SR
203         if(channel[c].del == inst[channel[c].inst].timer)
204           if(channel[c].nextnote)
205             opl->write(0x83 + op_table[c], inst[channel[c].inst].sr);
206       if(version < 3)
207         channel[c].del--;
208       else
209         if(channel[c].speed)
210           channel[c].del += channel[c].speed;
211         else {
212           channel[c].seqend = 1;
213           continue;
214         }
215     } else {
216       if(channel[c].speed) {
217         if(version < 3)
218           channel[c].del = channel[c].speed;
219         else {
220           channel[c].del &= 0x7f;
221           channel[c].del += channel[c].speed;
222         }
223       } else {
224         channel[c].seqend = 1;
225         continue;
226       }
227       if(channel[c].rhcnt) {    // process pending REST/HOLD events
228         channel[c].rhcnt--;
229         continue;
230       }
231     readorder:  // process arrangement (orderlist)
232       ord = LE_WORD(&channel[c].order[channel[c].ordpos]);
233       switch(ord) {
234       case 0xfffe: channel[c].seqend = 1; continue;     // end of arrangement stream
235       case 0xffff:              // jump to order
236         channel[c].ordpos = LE_WORD(&channel[c].order[channel[c].ordpos + 1]);
237         channel[c].seqend = 1;
238         goto readorder;
239       default:
240         if(ord >= 0x9000) {     // set speed
241           channel[c].speed = ord & 0xff;
242           ord = LE_WORD(&channel[c].order[channel[c].ordpos - 1]);
243           channel[c].ordpos++;
244         } else
245           if(ord >= 0x8000) {   // transpose track
246             channel[c].transpose = ord & 0xff;
247             if(ord & 0x100)
248               channel[c].transpose = -channel[c].transpose;
249             ord = LE_WORD(&channel[c].order[++channel[c].ordpos]);
250           }
251         patt = (unsigned short *)((char *)filedata + LE_WORD(&seqptr[ord]));
252         break;
253       }
254     channel[c].fxflag = 0;
255     readseq:    // process sequence (pattern)
256       if(!version)      // v0: always initialize rhcnt
257         channel[c].rhcnt = channel[c].irhcnt;
258       pattpos = LE_WORD(&patt[channel[c].pattpos]);
259       if(pattpos == 0xffff) {   // pattern ended?
260         channel[c].pattpos = 0;
261         channel[c].ordpos++;
262         goto readorder;
263       }
264       cnt = HIBYTE(pattpos);
265       note = LOBYTE(pattpos);
266       fx = pattpos >> 12;
267       fxop = pattpos & 0x0fff;
268       channel[c].pattpos++; pattpos = LE_WORD(&patt[channel[c].pattpos]);
269       channel[c].nextnote = LOBYTE(pattpos) & 0x7f;
270       if(version ? cnt < 0x40 : !fx) {  // note event
271         switch(note) {
272         case 0:                                         // REST event
273         case 0x80:
274           if(!note || version) {
275             channel[c].key = 0;
276             setfreq(c);
277           }
278           // fall through...
279         case 0x7e:                                      // HOLD event
280           if(version)
281             channel[c].rhcnt = cnt;
282           channel[c].nextnote = 0;
283           break;
284         default:                                        // play note
285           // restart fx
286           if(!(channel[c].fxflag & 1))
287             channel[c].vibdepth = 0;
288           if(!(channel[c].fxflag & 2))
289             channel[c].slideval = channel[c].slide = 0;
290
291           if(version) { // note handling for v1 and above
292             if(note > 0x80)     // locked note (no channel transpose)
293               note -= 0x80;
294             else                        // unlocked note
295               note += channel[c].transpose;
296             channel[c].note = note;     // remember note for SpFX
297
298             if(channel[c].ispfx != 0xffff && cnt < 0x20) {      // reset SpFX
299               channel[c].spfx = channel[c].ispfx;
300               if(LE_WORD(&spfx[channel[c].spfx].instnr) & 0x8000)       // locked frequency
301                 note = spfx[channel[c].spfx].halfnote;
302               else                                                                                              // unlocked frequency
303                 note += spfx[channel[c].spfx].halfnote;
304               channel[c].inst = LE_WORD(&spfx[channel[c].spfx].instnr) & 0xfff;
305               channel[c].fxdel = spfx[channel[c].spfx].duration;
306               if(spfx[channel[c].spfx].modlev != 0xff)
307                 channel[c].modvol = spfx[channel[c].spfx].modlev;
308               else
309                 channel[c].modvol = inst[channel[c].inst].data[7] & 63;
310             }
311
312             if(channel[c].ilevpuls != 0xff && cnt < 0x20) {     // reset LevelPuls
313               channel[c].levpuls = channel[c].ilevpuls;
314               channel[c].fxdel = levpuls[channel[c].levpuls].duration;
315               channel[c].frameskip = inst[channel[c].inst].timer;
316               if(levpuls[channel[c].levpuls].level != 0xff)
317                 channel[c].modvol = levpuls[channel[c].levpuls].level;
318               else
319                 channel[c].modvol = inst[channel[c].inst].data[7] & 63;
320             }
321
322             channel[c].freq = notetable[note%12] + ((note/12) << 10);
323             if(cnt < 0x20)      // normal note
324               playnote(c);
325             else {                      // tienote
326               setfreq(c);
327               cnt -= 0x20;      // make count proper
328             }
329             channel[c].rhcnt = cnt;
330           } else {      // note handling for v0
331             if(cnt < 2) // unlocked note
332               note += channel[c].transpose;
333             channel[c].note = note;
334
335             channel[c].freq = notetable[note%12] + ((note/12) << 10);
336             if(cnt == 1)        // tienote
337               setfreq(c);
338             else                        // normal note
339               playnote(c);
340           }
341           break;
342         }
343         continue;       // event is complete
344       } else {          // effect event
345         switch(fx) {
346         case 6:         // Cut/Stop Voice
347           buf = channel[c].inst;
348           channel[c].inst = 0;
349           playnote(c);
350           channel[c].inst = buf;
351           channel[c].rhcnt = fxop;
352           continue;     // no note follows this event
353         case 7:         // Vibrato
354           channel[c].vibspeed = fxop & 0xff;
355           channel[c].vibdepth = fxop >> 8;
356           channel[c].trigger = fxop >> 9;
357           channel[c].fxflag |= 1;
358           break;
359         case 8:         // v0: Duration
360           if(!version)
361             channel[c].irhcnt = fxop;
362           break;
363         case 9:         // New Level
364           channel[c].vol = fxop & 63;
365           if(channel[c].vol + channel[c].cvol < 63)     // apply channel volume
366             channel[c].vol += channel[c].cvol;
367           else
368             channel[c].vol = 63;
369           setvolume(c);
370           break;
371         case 0xb:       // v4: Set SpFX
372           if(version == 4)
373             channel[c].ispfx = fxop;
374           break;
375         case 0xc:       // Set Instrument
376           channel[c].ispfx = 0xffff;
377           channel[c].spfx = 0xffff;
378           channel[c].inst = fxop;
379           channel[c].modvol = inst[fxop].data[7] & 63;
380           if(version < 3 && version && inst[fxop].tunelev)      // Set LevelPuls
381             channel[c].ilevpuls = inst[fxop].tunelev - 1;
382           else {
383             channel[c].ilevpuls = 0xff;
384             channel[c].levpuls = 0xff;
385           }
386           break;
387         case 0xd:       // Slide up
388           channel[c].slide = fxop;
389           channel[c].fxflag |= 2;
390           break;
391         case 0xe:       // Slide down
392           channel[c].slide = -fxop;
393           channel[c].fxflag |= 2;
394           break;
395         }
396         goto readseq;   // event is incomplete, note follows
397       }
398     }
399
400   for(c=0;c<9;c++)
401     if(channel[c].seqend)
402       trackend++;
403   if(trackend == 9)
404     songend = 1;
405
406   return !songend;
407 }
408
409 void Cd00Player::rewind(int subsong)
410 {
411   struct Stpoin {
412     unsigned short ptr[9];
413     unsigned char volume[9],dummy[5];
414   } *tpoin;
415   int i;
416
417   if(subsong == -1) subsong = cursubsong;
418
419   if(version > 1) {     // do nothing if subsong > number of subsongs
420     if(subsong >= header->subsongs)
421       return;
422   } else
423     if(subsong >= header1->subsongs)
424       return;
425
426   memset(channel,0,sizeof(channel));
427   if(version > 1)
428     tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header->tpoin));
429   else
430     tpoin = (struct Stpoin *)((char *)filedata + LE_WORD(&header1->tpoin));
431   for(i=0;i<9;i++) {
432     if(LE_WORD(&tpoin[subsong].ptr[i])) {       // track enabled
433       channel[i].speed = LE_WORD((unsigned short *)
434                                  ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i])));
435       channel[i].order = (unsigned short *)
436         ((char *)filedata + LE_WORD(&tpoin[subsong].ptr[i]) + 2);
437     } else {                                    // track disabled
438       channel[i].speed = 0;
439       channel[i].order = 0;
440     }
441     channel[i].ispfx = 0xffff; channel[i].spfx = 0xffff;        // no SpFX
442     channel[i].ilevpuls = 0xff; channel[i].levpuls = 0xff;      // no LevelPuls
443     channel[i].cvol = tpoin[subsong].volume[i] & 0x7f;  // our player may savely ignore bit 7
444     channel[i].vol = channel[i].cvol;                   // initialize volume
445   }
446   songend = 0;
447   opl->init(); opl->write(1,32);        // reset OPL chip
448   cursubsong = subsong;
449 }
450
451 std::string Cd00Player::gettype()
452 {
453   char  tmpstr[40];
454
455   sprintf(tmpstr,"EdLib packed (version %d)",version > 1 ? header->version : header1->version);
456   return std::string(tmpstr);
457 }
458
459 float Cd00Player::getrefresh()
460 {
461   if(version > 1)
462     return header->speed;
463   else
464     return header1->speed;
465 }
466
467 unsigned int Cd00Player::getsubsongs()
468 {
469   if(version <= 1)      // return number of subsongs
470     return header1->subsongs;
471   else
472     return header->subsongs;
473 }
474
475 /*** private methods *************************************/
476
477 void Cd00Player::setvolume(unsigned char chan)
478 {
479   unsigned char op = op_table[chan];
480   unsigned short        insnr = channel[chan].inst;
481
482   opl->write(0x43 + op,(int)(63-((63-(inst[insnr].data[2] & 63))/63.0)*(63-channel[chan].vol)) +
483              (inst[insnr].data[2] & 192));
484   if(inst[insnr].data[10] & 1)
485     opl->write(0x40 + op,(int)(63-((63-channel[chan].modvol)/63.0)*(63-channel[chan].vol)) +
486                (inst[insnr].data[7] & 192));
487   else
488     opl->write(0x40 + op,channel[chan].modvol + (inst[insnr].data[7] & 192));
489 }
490
491 void Cd00Player::setfreq(unsigned char chan)
492 {
493   unsigned short freq = channel[chan].freq;
494
495   if(version == 4)      // v4: apply instrument finetune
496     freq += inst[channel[chan].inst].tunelev;
497
498   freq += channel[chan].slideval;
499   opl->write(0xa0 + chan, freq & 255);
500   if(channel[chan].key)
501     opl->write(0xb0 + chan, ((freq >> 8) & 31) | 32);
502   else
503     opl->write(0xb0 + chan, (freq >> 8) & 31);
504 }
505
506 void Cd00Player::setinst(unsigned char chan)
507 {
508   unsigned char op = op_table[chan];
509   unsigned short        insnr = channel[chan].inst;
510
511   // set instrument data
512   opl->write(0x63 + op, inst[insnr].data[0]);
513   opl->write(0x83 + op, inst[insnr].data[1]);
514   opl->write(0x23 + op, inst[insnr].data[3]);
515   opl->write(0xe3 + op, inst[insnr].data[4]);
516   opl->write(0x60 + op, inst[insnr].data[5]);
517   opl->write(0x80 + op, inst[insnr].data[6]);
518   opl->write(0x20 + op, inst[insnr].data[8]);
519   opl->write(0xe0 + op, inst[insnr].data[9]);
520   if(version)
521     opl->write(0xc0 + chan, inst[insnr].data[10]);
522   else
523     opl->write(0xc0 + chan, (inst[insnr].data[10] << 1) + (inst[insnr].tunelev & 1));
524 }
525
526 void Cd00Player::playnote(unsigned char chan)
527 {
528   // set misc vars & play
529   opl->write(0xb0 + chan, 0);   // stop old note
530   setinst(chan);
531   channel[chan].key = 1;
532   setfreq(chan);
533   setvolume(chan);
534 }
535
536 void Cd00Player::vibrato(unsigned char chan)
537 {
538   if(!channel[chan].vibdepth)
539     return;
540
541   if(channel[chan].trigger)
542     channel[chan].trigger--;
543   else {
544     channel[chan].trigger = channel[chan].vibdepth;
545     channel[chan].vibspeed = -channel[chan].vibspeed;
546   }
547   channel[chan].freq += channel[chan].vibspeed;
548   setfreq(chan);
549 }