diff src/Input/adplug/core/ksm.cxx @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Input/adplug/core/ksm.cxx	Mon Sep 18 01:11:49 2006 -0700
@@ -0,0 +1,336 @@
+/*
+ * Adplug - Replayer for many OPL2/OPL3 audio file formats.
+ * Copyright (C) 1999 - 2006 Simon Peter, <dn.tlp@gmx.net>, et al.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * ksm.cpp - KSM Player for AdPlug by Simon Peter <dn.tlp@gmx.net>
+ */
+
+#include <string.h>
+
+#include "ksm.h"
+#include "debug.h"
+
+const unsigned int CksmPlayer::adlibfreq[63] = {
+	0,
+	2390,2411,2434,2456,2480,2506,2533,2562,2592,2625,2659,2695,
+	3414,3435,3458,3480,3504,3530,3557,3586,3616,3649,3683,3719,
+	4438,4459,4482,4504,4528,4554,4581,4610,4640,4673,4707,4743,
+	5462,5483,5506,5528,5552,5578,5605,5634,5664,5697,5731,5767,
+	6486,6507,6530,6552,6576,6602,6629,6658,6688,6721,6755,6791,
+	7510};
+
+/*** public methods **************************************/
+
+CPlayer *CksmPlayer::factory(Copl *newopl)
+{
+  return new CksmPlayer(newopl);
+}
+
+bool CksmPlayer::load(const std::string &filename, const CFileProvider &fp)
+{
+  binistream	*f;
+  int		i;
+  char		*fn = new char[filename.length() + 9];
+
+  // file validation section
+  if(!fp.extension(filename, ".ksm")) {
+    AdPlug_LogWrite("CksmPlayer::load(,\"%s\"): File doesn't have '.ksm' "
+		    "extension! Rejected!\n", filename.c_str());
+    return false;
+  }
+  AdPlug_LogWrite("*** CksmPlayer::load(,\"%s\") ***\n", filename.c_str());
+
+  // Load instruments from 'insts.dat'
+  strcpy(fn, filename.c_str());
+  for(i = strlen(fn) - 1; i >= 0; i--)
+    if(fn[i] == '/' || fn[i] == '\\')
+      break;
+  strcpy(fn + i + 1, "insts.dat");
+  AdPlug_LogWrite("Instruments file: \"%s\"\n", fn);
+  f = fp.open(fn);
+  delete [] fn;
+  if(!f) {
+    AdPlug_LogWrite("Couldn't open instruments file! Aborting!\n");
+    AdPlug_LogWrite("--- CksmPlayer::load ---\n");
+    return false;
+  }
+  loadinsts(f);
+  fp.close(f);
+
+  f = fp.open(filename); if(!f) return false;
+  for(i = 0; i < 16; i++) trinst[i] = f->readInt(1);
+  for(i = 0; i < 16; i++) trquant[i] = f->readInt(1);
+  for(i = 0; i < 16; i++) trchan[i] = f->readInt(1);
+  f->ignore(16);
+  for(i = 0; i < 16; i++) trvol[i] = f->readInt(1);
+  numnotes = f->readInt(2);
+  note = new unsigned long [numnotes];
+  for(i = 0; i < numnotes; i++) note[i] = f->readInt(4);
+  fp.close(f);
+
+  if(!trchan[11]) {
+    drumstat = 0;
+    numchans = 9;
+  } else {
+    drumstat = 32;
+    numchans = 6;
+  }
+
+  rewind(0);
+  AdPlug_LogWrite("--- CksmPlayer::load ---\n");
+  return true;
+}
+
+bool CksmPlayer::update()
+{
+  int quanter,chan,drumnum,freq,track,volevel,volval;
+	unsigned int i,j,bufnum;
+	unsigned long temp,templong;
+
+	count++;
+	if (count >= countstop)
+	{
+		bufnum = 0;
+		while (count >= countstop)
+		{
+			templong = note[nownote];
+			track = (int)((templong>>8)&15);
+			if ((templong&192) == 0)
+			{
+				i = 0;
+
+	      while ((i < numchans) &&
+		     ((chanfreq[i] != (templong&63)) ||
+		      (chantrack[i] != ((templong>>8)&15))))
+					i++;
+				if (i < numchans)
+				{
+					databuf[bufnum] = (char)0; bufnum++;
+					databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
+					databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)&223); bufnum++;
+					chanfreq[i] = 0;
+					chanage[i] = 0;
+				}
+			}
+			else
+			{
+				volevel = trvol[track];
+				if ((templong&192) == 128)
+				{
+					volevel -= 4;
+					if (volevel < 0)
+						volevel = 0;
+				}
+				if ((templong&192) == 192)
+				{
+					volevel += 4;
+					if (volevel > 63)
+						volevel = 63;
+				}
+				if (track < 11)
+				{
+					temp = 0;
+					i = numchans;
+					for(j=0;j<numchans;j++)
+						if ((countstop - chanage[j] >= temp) && (chantrack[j] == track))
+						{
+							temp = countstop - chanage[j];
+							i = j;
+						}
+					if (i < numchans)
+					{
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
+						databuf[bufnum] = (unsigned char)0; bufnum++;
+						volval = (inst[trinst[track]][1]&192)+(volevel^63);
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0x40+op_table[i]+3); bufnum++;
+						databuf[bufnum] = (unsigned char)volval; bufnum++;
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0xa0+i); bufnum++;
+						databuf[bufnum] = (unsigned char)(adlibfreq[templong&63]&255); bufnum++;
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0xb0+i); bufnum++;
+						databuf[bufnum] = (unsigned char)((adlibfreq[templong&63]>>8)|32); bufnum++;
+						chanfreq[i] = templong&63;
+						chanage[i] = countstop;
+					}
+				}
+				else if ((drumstat&32) > 0)
+				{
+					freq = adlibfreq[templong&63];
+					switch(track)
+					{
+						case 11: drumnum = 16; chan = 6; freq -= 2048; break;
+						case 12: drumnum = 8; chan = 7; freq -= 2048; break;
+						case 13: drumnum = 4; chan = 8; break;
+						case 14: drumnum = 2; chan = 8; break;
+						case 15: drumnum = 1; chan = 7; freq -= 2048; break;
+					}
+					databuf[bufnum] = (char)0, bufnum++;
+					databuf[bufnum] = (unsigned char)(0xa0+chan); bufnum++;
+					databuf[bufnum] = (unsigned char)(freq&255); bufnum++;
+					databuf[bufnum] = (char)0, bufnum++;
+					databuf[bufnum] = (unsigned char)(0xb0+chan); bufnum++;
+					databuf[bufnum] = (unsigned char)((freq>>8)&223); bufnum++;
+					databuf[bufnum] = (char)0, bufnum++;
+					databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
+					databuf[bufnum] = (unsigned char)(drumstat&(255-drumnum)); bufnum++;
+					drumstat |= drumnum;
+					if ((track == 11) || (track == 12) || (track == 14))
+					{
+						volval = (inst[trinst[track]][1]&192)+(volevel^63);
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0x40+op_table[chan]+3); bufnum++;
+						databuf[bufnum] = (unsigned char)(volval); bufnum++;
+					}
+					else
+					{
+						volval = (inst[trinst[track]][6]&192)+(volevel^63);
+						databuf[bufnum] = (char)0, bufnum++;
+						databuf[bufnum] = (unsigned char)(0x40+op_table[chan]); bufnum++;
+						databuf[bufnum] = (unsigned char)(volval); bufnum++;
+					}
+					databuf[bufnum] = (char)0, bufnum++;
+					databuf[bufnum] = (unsigned char)(0xbd); bufnum++;
+					databuf[bufnum] = (unsigned char)(drumstat); bufnum++;
+				}
+			}
+			nownote++;
+			if (nownote >= numnotes) {
+				nownote = 0;
+				songend = true;
+			}
+			templong = note[nownote];
+			if (nownote == 0)
+				count = (templong>>12)-1;
+			quanter = (240/trquant[(templong>>8)&15]);
+			countstop = (((templong>>12)+(quanter>>1)) / quanter) * quanter;
+		}
+		for(i=0;i<bufnum;i+=3)
+			opl->write(databuf[i+1],databuf[i+2]);
+	}
+	return !songend;
+}
+
+void CksmPlayer::rewind(int subsong)
+{
+	unsigned int i,j,k;
+	unsigned char instbuf[11];
+	unsigned long templong;
+
+	songend = false;
+	opl->init(); opl->write(1,32); opl->write(4,0); opl->write(8,0); opl->write(0xbd,drumstat);
+
+	if (trchan[11] == 1) {
+	  for(i=0;i<11;i++)
+	    instbuf[i] = inst[trinst[11]][i];
+	  instbuf[1] = ((instbuf[1]&192)|(trvol[11])^63);
+	  setinst(6,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
+	  for(i=0;i<5;i++)
+	    instbuf[i] = inst[trinst[12]][i];
+	  for(i=5;i<11;i++)
+	    instbuf[i] = inst[trinst[15]][i];
+	  instbuf[1] = ((instbuf[1]&192)|(trvol[12])^63);
+	  instbuf[6] = ((instbuf[6]&192)|(trvol[15])^63);
+	  setinst(7,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
+	  for(i=0;i<5;i++)
+	    instbuf[i] = inst[trinst[14]][i];
+	  for(i=5;i<11;i++)
+	    instbuf[i] = inst[trinst[13]][i];
+	  instbuf[1] = ((instbuf[1]&192)|(trvol[14])^63);
+	  instbuf[6] = ((instbuf[6]&192)|(trvol[13])^63);
+	  setinst(8,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
+	}
+
+	for(i=0;i<numchans;i++)
+	{
+		chantrack[i] = 0;
+		chanage[i] = 0;
+	}
+	j = 0;
+	for(i=0;i<16;i++)
+		if ((trchan[i] > 0) && (j < numchans))
+		{
+			k = trchan[i];
+			while ((j < numchans) && (k > 0))
+			{
+				chantrack[j] = i;
+				k--;
+				j++;
+			}
+		}
+	for(i=0;i<numchans;i++)
+	{
+		for(j=0;j<11;j++)
+			instbuf[j] = inst[trinst[chantrack[i]]][j];
+		instbuf[1] = ((instbuf[1]&192)|(63-trvol[chantrack[i]]));
+		setinst(i,instbuf[0],instbuf[1],instbuf[2],instbuf[3],instbuf[4],instbuf[5],instbuf[6],instbuf[7],instbuf[8],instbuf[9],instbuf[10]);
+		chanfreq[i] = 0;
+	}
+	k = 0;
+	templong = *note;
+	count = (templong>>12)-1;
+	countstop = (templong>>12)-1;
+	nownote = 0;
+}
+
+std::string CksmPlayer::getinstrument(unsigned int n)
+{
+	if(trchan[n])
+		return std::string(instname[trinst[n]]);
+	else
+		return std::string();
+}
+
+/*** private methods *************************************/
+
+void CksmPlayer::loadinsts(binistream *f)
+{
+  int i, j;
+
+  for(i = 0; i < 256; i++) {
+    f->readString(instname[i], 20);
+    for(j = 0; j < 11; j++) inst[i][j] = f->readInt(1);
+    f->ignore(2);
+  }
+}
+
+void CksmPlayer::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)
+{
+	int offs;
+
+	opl->write(0xa0+chan,0);
+	opl->write(0xb0+chan,0);
+	opl->write(0xc0+chan,v10);
+	offs = op_table[chan];
+	opl->write(0x20+offs,v5);
+	opl->write(0x40+offs,v6);
+	opl->write(0x60+offs,v7);
+	opl->write(0x80+offs,v8);
+	opl->write(0xe0+offs,v9);
+	offs+=3;
+	opl->write(0x20+offs,v0);
+	opl->write(0x40+offs,v1);
+	opl->write(0x60+offs,v2);
+	opl->write(0x80+offs,v3);
+	opl->write(0xe0+offs,v4);
+}