|
359
|
1 /*
|
|
|
2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
|
|
|
3 * Copyright (C) 1999 - 2003 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 * ksm.cpp - KSM Player for AdPlug by Simon Peter <dn.tlp@gmx.net>
|
|
|
20 */
|
|
|
21
|
|
|
22 #include <string.h>
|
|
|
23
|
|
|
24 #include "ksm.h"
|
|
|
25 #include "debug.h"
|
|
|
26
|
|
|
27 const unsigned int CksmPlayer::adlibfreq[63] = {
|
|
|
28 0,
|
|
|
29 2390,2411,2434,2456,2480,2506,2533,2562,2592,2625,2659,2695,
|
|
|
30 3414,3435,3458,3480,3504,3530,3557,3586,3616,3649,3683,3719,
|
|
|
31 4438,4459,4482,4504,4528,4554,4581,4610,4640,4673,4707,4743,
|
|
|
32 5462,5483,5506,5528,5552,5578,5605,5634,5664,5697,5731,5767,
|
|
|
33 6486,6507,6530,6552,6576,6602,6629,6658,6688,6721,6755,6791,
|
|
|
34 7510};
|
|
|
35
|
|
|
36 /*** public methods **************************************/
|
|
|
37
|
|
|
38 CPlayer *CksmPlayer::factory(Copl *newopl)
|
|
|
39 {
|
|
|
40 return new CksmPlayer(newopl);
|
|
|
41 }
|
|
|
42
|
|
|
43 bool CksmPlayer::load(const std::string &filename, const CFileProvider &fp)
|
|
|
44 {
|
|
|
45 binistream *f;
|
|
|
46 int i;
|
|
|
47 char *fn = new char[filename.length() + 9];
|
|
|
48
|
|
|
49 // file validation section
|
|
|
50 if(!fp.extension(filename, ".ksm")) {
|
|
|
51 AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' "
|
|
|
52 "extension! Rejected!\n", filename.c_str());
|
|
|
53 return false;
|
|
|
54 }
|
|
|
55 AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str());
|
|
|
56
|
|
|
57 // Load instruments from 'insts.dat'
|
|
|
58 strcpy(fn, filename.c_str());
|
|
|
59 for(i = strlen(fn) - 1; i >= 0; i--)
|
|
|
60 if(fn[i] == '/' || fn[i] == '\\')
|
|
|
61 break;
|
|
|
62 strcpy(fn + i + 1, "insts.dat");
|
|
|
63 AdPlug_LogWrite("Instruments file: \"%s\"\n", fn);
|
|
|
64 f = fp.open(fn);
|
|
|
65 delete [] fn;
|
|
|
66 if(!f) {
|
|
|
67 AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n");
|
|
|
68 AdPlug_LogWrite("--- CksmPlayer::load ---\n");
|
|
|
69 return false;
|
|
|
70 }
|
|
|
71 loadinsts(f);
|
|
|
72 fp.close(f);
|
|
|
73
|
|
|
74 f = fp.open(filename); if(!f) return false;
|
|
|
75 for(i = 0; i < 16; i++) trinst[i] = f->readInt(1);
|
|
|
76 for(i = 0; i < 16; i++) trquant[i] = f->readInt(1);
|
|
|
77 for(i = 0; i < 16; i++) trchan[i] = f->readInt(1);
|
|
|
78 f->ignore(16);
|
|
|
79 for(i = 0; i < 16; i++) trvol[i] = f->readInt(1);
|
|
|
80 numnotes = f->readInt(2);
|
|
|
81 note = new unsigned long [numnotes];
|
|
|
82 for(i = 0; i < numnotes; i++) note[i] = f->readInt(4);
|
|
|
83 fp.close(f);
|
|
|
84
|
|
|
85 if(!trchan[11]) {
|
|
|
86 drumstat = 0;
|
|
|
87 numchans = 9;
|
|
|
88 } else {
|
|
|
89 drumstat = 32;
|
|
|
90 numchans = 6;
|
|
|
91 }
|
|
|
92
|
|
|
93 rewind(0);
|
|
|
94 AdPlug_LogWrite("--- CksmPlayer::load ---\n");
|
|
|
95 return true;
|
|
|
96 }
|
|
|
97
|
|
|
98 bool CksmPlayer::update()
|
|
|
99 {
|
|
|
100 int quanter,chan,drumnum,freq,track,volevel,volval;
|
|
|
101 unsigned int i,j,bufnum;
|
|
|
102 unsigned long temp,templong;
|
|
|
103
|
|
|
104 count++;
|
|
|
105 if (count >= countstop)
|
|
|
106 {
|
|
|
107 bufnum = 0;
|
|
|
108 while (count >= countstop)
|
|
|
109 {
|
|
|
110 templong = note[nownote];
|
|
|
111 track = (int)((templong>>8)&15);
|
|
|
112 if ((templong&192) == 0)
|
|
|
113 {
|
|
|
114 i = 0;
|
|
|
115 while (((chanfreq[i] != (templong&63)) || (chantrack[i] != ((templong>>8)&15))) && (i < numchans))
|
|
|
116 i++;
|
|
|
117 if (i < numchans)
|
|
|
118 {
|
|
|
119 databuf[bufnum] = (char)0; bufnum++;
|
|
|
120 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
|
|
|
121 databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++;
|
|
|
122 chanfreq[i] = 0;
|
|
|
123 chanage[i] = 0;
|
|
|
124 }
|
|
|
125 }
|
|
|
126 else
|
|
|
127 {
|
|
|
128 volevel = trvol[track];
|
|
|
129 if ((templong&192) == 128)
|
|
|
130 {
|
|
|
131 volevel -= 4;
|
|
|
132 if (volevel < 0)
|
|
|
133 volevel = 0;
|
|
|
134 }
|
|
|
135 if ((templong&192) == 192)
|
|
|
136 {
|
|
|
137 volevel += 4;
|
|
|
138 if (volevel > 63)
|
|
|
139 volevel = 63;
|
|
|
140 }
|
|
|
141 if (track < 11)
|
|
|
142 {
|
|
|
143 temp = 0;
|
|
|
144 i = numchans;
|
|
|
145 for(j=0;j<numchans;j++)
|
|
|
146 if ((countstop - chanage[j] >= temp) && (chantrack[j] == track))
|
|
|
147 {
|
|
|
148 temp = countstop - chanage[j];
|
|
|
149 i = j;
|
|
|
150 }
|
|
|
151 if (i < numchans)
|
|
|
152 {
|
|
|
153 databuf[bufnum] = (char)0, bufnum++;
|
|
|
154 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
|
|
|
155 databuf[bufnum] = (unsigned char)0; bufnum++;
|
|
|
156 volval = (inst[trinst[track]][1]&192)+(volevel^63);
|
|
|
157 databuf[bufnum] = (char)0, bufnum++;
|
|
|
158 databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++;
|
|
|
159 databuf[bufnum] = (unsigned char)volval; bufnum++;
|
|
|
160 databuf[bufnum] = (char)0, bufnum++;
|
|
|
161 databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++;
|
|
|
162 databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++;
|
|
|
163 databuf[bufnum] = (char)0, bufnum++;
|
|
|
164 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
|
|
|
165 databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++;
|
|
|
166 chanfreq[i] = templong&63;
|
|
|
167 chanage[i] = countstop;
|
|
|
168 }
|
|
|
169 }
|
|
|
170 else if ((drumstat&32) > 0)
|
|
|
171 {
|
|
|
172 freq = adlibfreq[templong&63];
|
|
|
173 switch(track)
|
|
|
174 {
|
|
|
175 case 11: drumnum = 16; chan = 6; freq -= 2048; break;
|
|
|
176 case 12: drumnum = 8; chan = 7; freq -= 2048; break;
|
|
|
177 case 13: drumnum = 4; chan = 8; break;
|
|
|
178 case 14: drumnum = 2; chan = 8; break;
|
|
|
179 case 15: drumnum = 1; chan = 7; freq -= 2048; break;
|
|
|
180 }
|
|
|
181 databuf[bufnum] = (char)0, bufnum++;
|
|
|
182 databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++;
|
|
|
183 databuf[bufnum] = (unsigned char)(freq&255); bufnum++;
|
|
|
184 databuf[bufnum] = (char)0, bufnum++;
|
|
|
185 databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++;
|
|
|
186 databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++;
|
|
|
187 databuf[bufnum] = (char)0, bufnum++;
|
|
|
188 databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
|
|
|
189 databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++;
|
|
|
190 drumstat |= drumnum;
|
|
|
191 if ((track == 11) || (track == 12) || (track == 14))
|
|
|
192 {
|
|
|
193 volval = (inst[trinst[track]][1]&192)+(volevel^63);
|
|
|
194 databuf[bufnum] = (char)0, bufnum++;
|
|
|
195 databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++;
|
|
|
196 databuf[bufnum] = (unsigned char)(volval); bufnum++;
|
|
|
197 }
|
|
|
198 else
|
|
|
199 {
|
|
|
200 volval = (inst[trinst[track]][6]&192)+(volevel^63);
|
|
|
201 databuf[bufnum] = (char)0, bufnum++;
|
|
|
202 databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++;
|
|
|
203 databuf[bufnum] = (unsigned char)(volval); bufnum++;
|
|
|
204 }
|
|
|
205 databuf[bufnum] = (char)0, bufnum++;
|
|
|
206 databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
|
|
|
207 databuf[bufnum] = (unsigned char)(drumstat); bufnum++;
|
|
|
208 }
|
|
|
209 }
|
|
|
210 nownote++;
|
|
|
211 if (nownote >= numnotes) {
|
|
|
212 nownote = 0;
|
|
|
213 songend = true;
|
|
|
214 }
|
|
|
215 templong = note[nownote];
|
|
|
216 if (nownote == 0)
|
|
|
217 count = (templong>>12)-1;
|
|
|
218 quanter = (240/trquant[(templong>>8)&15]);
|
|
|
219 countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter;
|
|
|
220 }
|
|
|
221 for(i=0;i<bufnum;i+=3)
|
|
|
222 opl->write(databuf[i+1],databuf[i+2]);
|
|
|
223 }
|
|
|
224 return !songend;
|
|
|
225 }
|
|
|
226
|
|
|
227 void CksmPlayer::rewind(int subsong)
|
|
|
228 {
|
|
|
229 unsigned int i,j,k;
|
|
|
230 unsigned char instbuf[11];
|
|
|
231 unsigned long templong;
|
|
|
232
|
|
|
233 songend = false;
|
|
|
234 opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat);
|
|
|
235
|
|
|
236 if (trchan[11] == 1) {
|
|
|
237 for(i=0;i<11;i++)
|
|
|
238 instbuf[i] = inst[trinst[11]][i];
|
|
|
239 instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63);
|
|
|
240 setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
|
|
|
241 for(i=0;i<5;i++)
|
|
|
242 instbuf[i] = inst[trinst[12]][i];
|
|
|
243 for(i=5;i<11;i++)
|
|
|
244 instbuf[i] = inst[trinst[15]][i];
|
|
|
245 instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63);
|
|
|
246 instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63);
|
|
|
247 setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
|
|
|
248 for(i=0;i<5;i++)
|
|
|
249 instbuf[i] = inst[trinst[14]][i];
|
|
|
250 for(i=5;i<11;i++)
|
|
|
251 instbuf[i] = inst[trinst[13]][i];
|
|
|
252 instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63);
|
|
|
253 instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63);
|
|
|
254 setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
|
|
|
255 }
|
|
|
256
|
|
|
257 for(i=0;i<numchans;i++)
|
|
|
258 {
|
|
|
259 chantrack[i] = 0;
|
|
|
260 chanage[i] = 0;
|
|
|
261 }
|
|
|
262 j = 0;
|
|
|
263 for(i=0;i<16;i++)
|
|
|
264 if ((trchan[i] > 0) && (j < numchans))
|
|
|
265 {
|
|
|
266 k = trchan[i];
|
|
|
267 while ((j < numchans) && (k > 0))
|
|
|
268 {
|
|
|
269 chantrack[j] = i;
|
|
|
270 k--;
|
|
|
271 j++;
|
|
|
272 }
|
|
|
273 }
|
|
|
274 for(i=0;i<numchans;i++)
|
|
|
275 {
|
|
|
276 for(j=0;j<11;j++)
|
|
|
277 instbuf[j] = inst[trinst[chantrack[i]]][j];
|
|
|
278 instbuf[1] = ((instbuf[1]&192)|(63-trvol[chantrack[i]]));
|
|
|
279 setinst(i,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
|
|
|
280 chanfreq[i] = 0;
|
|
|
281 }
|
|
|
282 k = 0;
|
|
|
283 templong = *note;
|
|
|
284 count = (templong>>12)-1;
|
|
|
285 countstop = (templong>>12)-1;
|
|
|
286 nownote = 0;
|
|
|
287 }
|
|
|
288
|
|
|
289 std::string CksmPlayer::getinstrument(unsigned int n)
|
|
|
290 {
|
|
|
291 if(trchan[n])
|
|
|
292 return std::string(instname[trinst[n]]);
|
|
|
293 else
|
|
|
294 return std::string();
|
|
|
295 }
|
|
|
296
|
|
|
297 /*** private methods *************************************/
|
|
|
298
|
|
|
299 void CksmPlayer::loadinsts(binistream *f)
|
|
|
300 {
|
|
|
301 int i, j;
|
|
|
302
|
|
|
303 for(i = 0; i < 256; i++) {
|
|
|
304 f->readString(instname[i], 20);
|
|
|
305 for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1);
|
|
|
306 f->ignore(2);
|
|
|
307 }
|
|
|
308 }
|
|
|
309
|
|
|
310 void CksmPlayer::setinst(int chan,
|
|
|
311 unsigned char v0,unsigned char v1,unsigned char v2,
|
|
|
312 unsigned char v3,unsigned char v4,unsigned char v5,
|
|
|
313 unsigned char v6,unsigned char v7,unsigned char v8,
|
|
|
314 unsigned char v9,unsigned char v10)
|
|
|
315 {
|
|
|
316 int offs;
|
|
|
317
|
|
|
318 opl->write(0xa0+chan,0);
|
|
|
319 opl->write(0xb0+chan,0);
|
|
|
320 opl->write(0xc0+chan,v10);
|
|
|
321 offs = op_table[chan];
|
|
|
322 opl->write(0x20+offs,v5);
|
|
|
323 opl->write(0x40+offs,v6);
|
|
|
324 opl->write(0x60+offs,v7);
|
|
|
325 opl->write(0x80+offs,v8);
|
|
|
326 opl->write(0xe0+offs,v9);
|
|
|
327 offs+=3;
|
|
|
328 opl->write(0x20+offs,v0);
|
|
|
329 opl->write(0x40+offs,v1);
|
|
|
330 opl->write(0x60+offs,v2);
|
|
|
331 opl->write(0x80+offs,v3);
|
|
|
332 opl->write(0xe0+offs,v4);
|
|
|
333 }
|