Mercurial > audlegacy-plugins
view src/adplug/core/bam.cxx @ 1888:d72fb4c70037
SHARED_SUFFIX should be PLUGIN_SUFFIX.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Wed, 26 Sep 2007 11:24:57 -0500 |
parents | 4709ce4e209e |
children |
line wrap: on
line source
/* * Adplug - Replayer for many OPL2/OPL3 audio file formats. * Copyright (C) 1999 - 2003 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 * * bam.cpp - Bob's Adlib Music Player, by Simon Peter <dn.tlp@gmx.net> * * NOTES: * In my player, the loop counter is stored with the label. This can be * dangerous for some situations (see below), but there shouldn't be any BAM * files triggering this situation. * * From SourceForge Bug #476088: * ----------------------------- * Using just one loop counter for each label, my player can't * handle files that loop twice to the same label (if that's at * all possible with BAM). Imagine the following situation: * * ... [*] ---- [<- *] ---- [<- *] ... * ^ ^ ^ ^ ^ ^ ^ * | | | | | | | * +---|----+-----|-----+-----|----+--- normal song data * +----------|-----------|-------- label 1 * +-----------+-------- loop points to label 1 * * both loop points loop to the same label. Storing the loop * count with the label would cause chaos with the counter, * when the player executes the inner jump. * ------------------ * Not to worry. my reference implementation of BAM does not * support the multiple loop situation you describe, and * neither do any BAM-creation programs. Then both loops point * to the same label, the inner loop's counter is just allowed * to clobber the outer loop's counter. No stack is neccisary. */ #include <string.h> #include "bam.h" const unsigned short CbamPlayer::freq[] = { 172, 182, 193, 205, 217, 230, 243, 258, 274, 290, 307, 326, 345, 365, 387, 410, 435, 460, 489, 517, 547, 580, 614, 651, 1369, 1389, 1411, 1434, 1459, 1484, 1513, 1541, 1571, 1604, 1638, 1675, 2393, 2413, 2435, 2458, 2483, 2508, 2537, 2565, 2595, 2628, 2662, 2699, 3417, 3437, 3459, 3482, 3507, 3532, 3561, 3589, 3619, 3652, 3686, 3723, 4441, 4461, 4483, 4506, 4531, 4556, 4585, 4613, 4643, 4676, 4710, 4747, 5465, 5485, 5507, 5530, 5555, 5580, 5609, 5637, 5667, 5700, 5734, 5771, 6489, 6509, 6531, 6554, 6579, 6604, 6633, 6661, 6691, 6724, 6758, 6795, 7513, 7533, 7555, 7578, 7603, 7628, 7657, 7685, 7715, 7748, 7782, 7819, 7858, 7898, 7942, 7988, 8037, 8089, 8143, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191, 8191 }; CPlayer * CbamPlayer::factory (Copl * newopl) { return new CbamPlayer (newopl); } bool CbamPlayer::load (VFSFile * fd, const CFileProvider & fp) { binistream *f = fp.open (fd); if (!f) return false; char id[4]; unsigned int i; size = fp.filesize (f) - 4; // filesize minus header f->readString (id, 4); if (strncmp (id, "CBMF", 4)) { fp.close (f); return false; } song = new unsigned char[size]; for (i = 0; i < size; i++) song[i] = f->readInt (1); fp.close (f); rewind (0); return true; } bool CbamPlayer::update () { unsigned char cmd, c; if (del) { del--; return !songend; } if (pos >= size) { // EOF detection pos = 0; songend = true; } while (song[pos] < 128) { cmd = song[pos] & 240; c = song[pos] & 15; switch (cmd) { case 0: // stop song pos = 0; songend = true; break; case 16: // start note if (c < 9) { opl->write (0xa0 + c, freq[song[++pos]] & 255); opl->write (0xb0 + c, (freq[song[pos]] >> 8) + 32); } else pos++; pos++; break; case 32: // stop note if (c < 9) opl->write (0xb0 + c, 0); pos++; break; case 48: // define instrument if (c < 9) { opl->write (0x20 + op_table[c], song[pos + 1]); opl->write (0x23 + op_table[c], song[pos + 2]); opl->write (0x40 + op_table[c], song[pos + 3]); opl->write (0x43 + op_table[c], song[pos + 4]); opl->write (0x60 + op_table[c], song[pos + 5]); opl->write (0x63 + op_table[c], song[pos + 6]); opl->write (0x80 + op_table[c], song[pos + 7]); opl->write (0x83 + op_table[c], song[pos + 8]); opl->write (0xe0 + op_table[c], song[pos + 9]); opl->write (0xe3 + op_table[c], song[pos + 10]); opl->write (0xc0 + c, song[pos + 11]); } pos += 12; break; case 80: // set label label[c].target = ++pos; label[c].defined = true; break; case 96: // jump if (label[c].defined) switch (song[pos + 1]) { case 254: // infinite loop if (label[c].defined) { pos = label[c].target; songend = true; break; } // fall through... case 255: // chorus if (!chorus && label[c].defined) { chorus = true; gosub = pos + 2; pos = label[c].target; break; } // fall through... case 0: // end of loop pos += 2; break; default: // finite loop if (!label[c].count) { // loop elapsed label[c].count = 255; pos += 2; break; } if (label[c].count < 255) // loop defined label[c].count--; else // loop undefined label[c].count = song[pos + 1] - 1; pos = label[c].target; break; } break; case 112: // end of chorus if (chorus) { pos = gosub; chorus = false; } else pos++; break; default: // reserved command (skip) pos++; break; } } if (song[pos] >= 128) { // wait del = song[pos] - 127; pos++; } return !songend; } void CbamPlayer::rewind (int subsong) { int i; pos = 0; songend = false; del = 0; gosub = 0; chorus = false; memset (label, 0, sizeof (label)); label[0].defined = true; for (i = 0; i < 16; i++) label[i].count = 255; // 255 = undefined opl->init (); opl->write (1, 32); }