]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug/src/dro2.cpp
wwww~
[16.git] / 16 / adplug / adplug / src / dro2.cpp
1 /*
2  * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3  * Copyright (C) 1999 - 2007 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  * dro2.cpp - DOSBox Raw OPL v2.0 player by Adam Nielsen <malvineous@shikadi.net>
20  */
21
22 #include <cstring>
23 #include <stdio.h>
24
25 #include "dro2.h"
26
27 CPlayer *Cdro2Player::factory(Copl *newopl)
28 {
29   return new Cdro2Player(newopl);
30 }
31
32 Cdro2Player::Cdro2Player(Copl *newopl) :
33         CPlayer(newopl),
34         piConvTable(NULL),
35         data(0)
36 {
37 }
38
39 Cdro2Player::~Cdro2Player()
40 {
41         if (this->data) delete[] this->data;
42         if (this->piConvTable) delete[] this->piConvTable;
43 }
44
45 bool Cdro2Player::load(const std::string &filename, const CFileProvider &fp)
46 {
47         binistream *f = fp.open(filename);
48         if (!f) return false;
49
50         char id[8];
51         f->readString(id, 8);
52         if (strncmp(id, "DBRAWOPL", 8)) {
53                 fp.close(f);
54                 return false;
55         }
56         int version = f->readInt(4);
57         if (version != 0x2) {
58                 fp.close(f);
59                 return false;
60         }
61
62         this->iLength = f->readInt(4) * 2; // stored in file as number of byte pairs
63         f->ignore(4);   // Length in milliseconds
64         f->ignore(1);   /// OPL type (0 == OPL2, 1 == Dual OPL2, 2 == OPL3)
65         int iFormat = f->readInt(1);
66         if (iFormat != 0) {
67                 fp.close(f);
68                 return false;
69         }
70         int iCompression = f->readInt(1);
71         if (iCompression != 0) {
72                 fp.close(f);
73                 return false;
74         }
75         this->iCmdDelayS = f->readInt(1);
76         this->iCmdDelayL = f->readInt(1);
77         this->iConvTableLen = f->readInt(1);
78
79         this->piConvTable = new uint8_t[this->iConvTableLen];
80         f->readString((char *)this->piConvTable, this->iConvTableLen);
81
82         this->data = new uint8_t[this->iLength];
83         f->readString((char *)this->data, this->iLength);
84
85         fp.close(f);
86         rewind(0);
87
88         return true;
89 }
90
91 bool Cdro2Player::update()
92 {
93         while (this->iPos < this->iLength) {
94                 int iIndex = this->data[this->iPos++];
95                 int iValue = this->data[this->iPos++];
96
97                 // Short delay
98                 if (iIndex == this->iCmdDelayS) {
99                         this->iDelay = iValue + 1;
100                         return true;
101
102                 // Long delay
103                 } else if (iIndex == this->iCmdDelayL) {
104                         this->iDelay = (iValue + 1) << 8;
105                         return true;
106
107                 // Normal write
108                 } else {
109                         if (iIndex & 0x80) {
110                                 // High bit means use second chip in dual-OPL2 config
111                                 this->opl->setchip(1);
112                           iIndex &= 0x7F;
113                         } else {
114                           this->opl->setchip(0);
115                         }
116                         if (iIndex > this->iConvTableLen) {
117                                 printf("DRO2: Error - index beyond end of codemap table!  Corrupted .dro?\n");
118                                 return false; // EOF
119                         }
120                         int iReg = this->piConvTable[iIndex];
121                         this->opl->write(iReg, iValue);
122                 }
123
124         }
125
126         // This won't result in endless-play using Adplay, but IMHO that code belongs
127         // in Adplay itself, not here.
128   return this->iPos < this->iLength;
129 }
130
131 void Cdro2Player::rewind(int subsong)
132 {
133         this->iDelay = 0;
134         this->iPos = 0;
135   opl->init(); 
136 }
137
138 float Cdro2Player::getrefresh()
139 {
140         if (this->iDelay > 0) return 1000.0 / this->iDelay;
141         else return 1000.0;
142 }