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