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., 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
factory(Copl * newopl)38 CPlayer *CksmPlayer::factory(Copl *newopl)
39 {
40 return new CksmPlayer(newopl);
41 }
42
load(const char * filename,const CFileProvider & fp)43 bool CksmPlayer::load(const char *filename, const CFileProvider &fp)
44 {
45 binistream *f;
46 int i;
47 char *fn = new char[strlen (filename) + 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);
53 delete[] fn;
54 return false;
55 }
56 AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename);
57
58 // Load instruments from 'insts.dat'
59 strcpy(fn, filename);
60 for(i = strlen(fn) - 1; i >= 0; i--)
61 if(fn[i] == '/' || fn[i] == '\\')
62 break;
63 strcpy(fn + i + 1, "insts.dat");
64 AdPlug_LogWrite("Instruments file: \"%s\"\n", fn);
65 f = fp.open(fn);
66 delete [] fn;
67 if(!f) {
68 AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n");
69 AdPlug_LogWrite("--- CksmPlayer::load ---\n");
70 return false;
71 }
72 loadinsts(f);
73 fp.close(f);
74
75 f = fp.open(filename); if(!f) return false;
76 for(i = 0; i < 16; i++) trinst[i] = f->readInt(1);
77 for(i = 0; i < 16; i++) trquant[i] = f->readInt(1);
78 for(i = 0; i < 16; i++) trchan[i] = f->readInt(1);
79 f->ignore(16);
80 for(i = 0; i < 16; i++) trvol[i] = f->readInt(1);
81 numnotes = f->readInt(2);
82 note = new unsigned long [numnotes];
83 for(i = 0; i < numnotes; i++) note[i] = f->readInt(4);
84 fp.close(f);
85
86 if(!trchan[11]) {
87 drumstat = 0;
88 numchans = 9;
89 } else {
90 drumstat = 32;
91 numchans = 6;
92 }
93
94 rewind(0);
95 AdPlug_LogWrite("--- CksmPlayer::load ---\n");
96 return true;
97 }
98
update()99 bool CksmPlayer::update()
100 {
101 int quanter,chan,drumnum,freq,track,volevel,volval;
102 unsigned int i,j,bufnum;
103 unsigned long temp,templong;
104
105 count++;
106 if (count >= countstop)
107 {
108 bufnum = 0;
109 while (count >= countstop)
110 {
111 templong = note[nownote];
112 track = (int)((templong>>8)&15);
113 if ((templong&192) == 0)
114 {
115 i = 0;
116
117 while ((i < numchans) &&
118 ((chanfreq[i] != (templong&63)) ||
119 (chantrack[i] != ((templong>>8)&15))))
120 i++;
121 if (i < numchans)
122 {
123 databuf[bufnum] = (char)0; bufnum++;
124 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
125 databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++;
126 chanfreq[i] = 0;
127 chanage[i] = 0;
128 }
129 }
130 else
131 {
132 volevel = trvol[track];
133 if ((templong&192) == 128)
134 {
135 volevel -= 4;
136 if (volevel < 0)
137 volevel = 0;
138 }
139 if ((templong&192) == 192)
140 {
141 volevel += 4;
142 if (volevel > 63)
143 volevel = 63;
144 }
145 if (track < 11)
146 {
147 temp = 0;
148 i = numchans;
149 for(j=0;j<numchans;j++)
150 if ((countstop - chanage[j] >= temp) && (chantrack[j] == track))
151 {
152 temp = countstop - chanage[j];
153 i = j;
154 }
155 if (i < numchans)
156 {
157 databuf[bufnum] = (char)0, bufnum++;
158 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
159 databuf[bufnum] = (unsigned char)0; bufnum++;
160 volval = (inst[trinst[track]][1]&192)+(volevel^63);
161 databuf[bufnum] = (char)0, bufnum++;
162 databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++;
163 databuf[bufnum] = (unsigned char)volval; bufnum++;
164 databuf[bufnum] = (char)0, bufnum++;
165 databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++;
166 databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++;
167 databuf[bufnum] = (char)0, bufnum++;
168 databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
169 databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++;
170 chanfreq[i] = templong&63;
171 chanage[i] = countstop;
172 }
173 }
174 else if ((drumstat&32) > 0)
175 {
176 freq = adlibfreq[templong&63];
177 switch(track)
178 {
179 case 11: drumnum = 16; chan = 6; freq -= 2048; break;
180 case 12: drumnum = 8; chan = 7; freq -= 2048; break;
181 case 13: drumnum = 4; chan = 8; break;
182 case 14: drumnum = 2; chan = 8; break;
183 case 15: drumnum = 1; chan = 7; freq -= 2048; break;
184 }
185 databuf[bufnum] = (char)0, bufnum++;
186 databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++;
187 databuf[bufnum] = (unsigned char)(freq&255); bufnum++;
188 databuf[bufnum] = (char)0, bufnum++;
189 databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++;
190 databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++;
191 databuf[bufnum] = (char)0, bufnum++;
192 databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
193 databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++;
194 drumstat |= drumnum;
195 if ((track == 11) || (track == 12) || (track == 14))
196 {
197 volval = (inst[trinst[track]][1]&192)+(volevel^63);
198 databuf[bufnum] = (char)0, bufnum++;
199 databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++;
200 databuf[bufnum] = (unsigned char)(volval); bufnum++;
201 }
202 else
203 {
204 volval = (inst[trinst[track]][6]&192)+(volevel^63);
205 databuf[bufnum] = (char)0, bufnum++;
206 databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++;
207 databuf[bufnum] = (unsigned char)(volval); bufnum++;
208 }
209 databuf[bufnum] = (char)0, bufnum++;
210 databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
211 databuf[bufnum] = (unsigned char)(drumstat); bufnum++;
212 }
213 }
214 nownote++;
215 if (nownote >= numnotes) {
216 nownote = 0;
217 songend = true;
218 }
219 templong = note[nownote];
220 if (nownote == 0)
221 count = (templong>>12)-1;
222 quanter = (240/trquant[(templong>>8)&15]);
223 countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter;
224 }
225 for(i=0;i<bufnum;i+=3)
226 opl->write(databuf[i+1],databuf[i+2]);
227 }
228 return !songend;
229 }
230
rewind(int subsong)231 void CksmPlayer::rewind(int subsong)
232 {
233 unsigned int i,j,k;
234 unsigned char instbuf[11];
235 unsigned long templong;
236
237 songend = false;
238 opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat);
239
240 if (trchan[11] == 1) {
241 for(i=0;i<11;i++)
242 instbuf[i] = inst[trinst[11]][i];
243 instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63);
244 setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
245 for(i=0;i<5;i++)
246 instbuf[i] = inst[trinst[12]][i];
247 for(i=5;i<11;i++)
248 instbuf[i] = inst[trinst[15]][i];
249 instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63);
250 instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63);
251 setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
252 for(i=0;i<5;i++)
253 instbuf[i] = inst[trinst[14]][i];
254 for(i=5;i<11;i++)
255 instbuf[i] = inst[trinst[13]][i];
256 instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63);
257 instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63);
258 setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
259 }
260
261 for(i=0;i<numchans;i++)
262 {
263 chantrack[i] = 0;
264 chanage[i] = 0;
265 }
266 j = 0;
267 for(i=0;i<16;i++)
268 if ((trchan[i] > 0) && (j < numchans))
269 {
270 k = trchan[i];
271 while ((j < numchans) && (k > 0))
272 {
273 chantrack[j] = i;
274 k--;
275 j++;
276 }
277 }
278 for(i=0;i<numchans;i++)
279 {
280 for(j=0;j<11;j++)
281 instbuf[j] = inst[trinst[chantrack[i]]][j];
282 instbuf[1] = ((instbuf[1]&192)|(63-trvol[chantrack[i]]));
283 setinst(i,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
284 chanfreq[i] = 0;
285 }
286 k = 0;
287 templong = *note;
288 count = (templong>>12)-1;
289 countstop = (templong>>12)-1;
290 nownote = 0;
291 }
292
getinstrument(unsigned int n)293 const char * CksmPlayer::getinstrument(unsigned int n)
294 {
295 if(trchan[n])
296 return instname[trinst[n]];
297 else
298 return "";
299 }
300
301 /*** private methods *************************************/
302
loadinsts(binistream * f)303 void CksmPlayer::loadinsts(binistream *f)
304 {
305 int i, j;
306
307 for(i = 0; i < 256; i++) {
308 f->readString(instname[i], 20);
309 for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1);
310 f->ignore(2);
311 }
312 }
313
setinst(int chan,unsigned char v0,unsigned char v1,unsigned char v2,unsigned char v3,unsigned char v4,unsigned char v5,unsigned char v6,unsigned char v7,unsigned char v8,unsigned char v9,unsigned char v10)314 void CksmPlayer::setinst(int chan,
315 unsigned char v0,unsigned char v1,unsigned char v2,
316 unsigned char v3,unsigned char v4,unsigned char v5,
317 unsigned char v6,unsigned char v7,unsigned char v8,
318 unsigned char v9,unsigned char v10)
319 {
320 int offs;
321
322 opl->write(0xa0+chan,0);
323 opl->write(0xb0+chan,0);
324 opl->write(0xc0+chan,v10);
325 offs = op_table[chan];
326 opl->write(0x20+offs,v5);
327 opl->write(0x40+offs,v6);
328 opl->write(0x60+offs,v7);
329 opl->write(0x80+offs,v8);
330 opl->write(0xe0+offs,v9);
331 offs+=3;
332 opl->write(0x20+offs,v0);
333 opl->write(0x40+offs,v1);
334 opl->write(0x60+offs,v2);
335 opl->write(0x80+offs,v3);
336 opl->write(0xe0+offs,v4);
337 }
338