Mercurial > audlegacy-plugins
view src/adplug/core/ksm.cxx @ 3063:6a6a731fdaf8
crossfade-ng: More sane defaults.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 24 Apr 2009 06:24:24 -0500 |
parents | f27d73fb0bcd |
children |
line wrap: on
line source
/* * 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 (VFSFile * fd, const CFileProvider & fp) { binistream *f; int i; std::string filename (fd->uri); 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); VFSFile *instfd = aud_vfs_fopen (fn, "rb"); f = fp.open (instfd); 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); aud_vfs_fclose (instfd); f = fp.open (fd); 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 = 0, drumnum = 0, 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); }