Mercurial > audlegacy-plugins
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); +}