2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 * Copyright (C) 1999 - 2007 Simon Peter, <dn.tlp@gmx.net>, et al.
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.
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.
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
19 * Johannes Bjerregaard's JBM Adlib Music Format player for AdPlug
20 * Written by Dennis Lindroos <lindroos@nls.fi>, February-March 2007
21 * - Designed and coded from scratch (only frequency-table taken from MUSIC.BIN)
22 * - The percussion mode is buggy (?) but i'm not good enough to find them
23 * and honestly i think the melodic-mode tunes are much better ;)
25 * This version doesn't use the binstr.h functions (coded with custom func.)
26 * This is my first attempt on writing a musicplayer for AdPlug, and i'm not
27 * coding C++ very often..
29 * Released under the terms of the GNU General Public License.
34 static const unsigned short notetable[96] = {
35 0x0158, 0x016d, 0x0183, 0x019a, 0x01b2, 0x01cc, 0x01e7, 0x0204,
36 0x0223, 0x0244, 0x0266, 0x028b, 0x0558, 0x056d, 0x0583, 0x059a,
37 0x05b2, 0x05cc, 0x05e7, 0x0604, 0x0623, 0x0644, 0x0666, 0x068b,
38 0x0958, 0x096d, 0x0983, 0x099a, 0x09b2, 0x09cc, 0x09e7, 0x0a04,
39 0x0a23, 0x0a44, 0x0a66, 0x0a8b, 0x0d58, 0x0d6d, 0x0d83, 0x0d9a,
40 0x0db2, 0x0dcc, 0x0de7, 0x0e04, 0x0e23, 0x0e44, 0x0e66, 0x0e8b,
41 0x1158, 0x116d, 0x1183, 0x119a, 0x11b2, 0x11cc, 0x11e7, 0x1204,
42 0x1223, 0x1244, 0x1266, 0x128b, 0x1558, 0x156d, 0x1583, 0x159a,
43 0x15b2, 0x15cc, 0x15e7, 0x1604, 0x1623, 0x1644, 0x1666, 0x168b,
44 0x1958, 0x196d, 0x1983, 0x199a, 0x19b2, 0x19cc, 0x19e7, 0x1a04,
45 0x1a23, 0x1a44, 0x1a66, 0x1a8b, 0x1d58, 0x1d6d, 0x1d83, 0x1d9a,
46 0x1db2, 0x1dcc, 0x1de7, 0x1e04, 0x1e23, 0x1e44, 0x1e66, 0x1e8b
49 static const unsigned char percmx_tab[4] = { 0x14, 0x12, 0x15, 0x11 };
50 static const unsigned char perchn_tab[5] = { 6, 7, 8, 8, 7 };
51 static unsigned char percmaskoff[5] = { 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
52 static unsigned char percmaskon[5] = { 0x10, 0x08, 0x04, 0x02, 0x01 };
54 static inline unsigned short GET_WORD(unsigned char *b, int x)
56 return ((unsigned short)(b[x+1] << 8) | b[x]);
59 /*** public methods *************************************/
61 CPlayer *CjbmPlayer::factory(Copl *newopl)
63 return new CjbmPlayer(newopl);
66 bool CjbmPlayer::load(const std::string &filename, const CFileProvider &fp)
68 binistream *f = fp.open(filename); if(!f) return false;
69 int filelen = fp.filesize(f);
72 if (!filelen || !fp.extension(filename, ".jbm")) goto loaderr;
74 // Allocate memory buffer m[] and read entire file into it
76 m = new unsigned char[filelen];
77 if (f->readString((char *)m, filelen) != filelen) goto loaderr;
81 // The known .jbm files always seem to start with the number 0x0002
83 if (GET_WORD(m, 0) != 0x0002)
89 timer = 1193810.0 / (i ? i : 0xffff);
91 seqtable = GET_WORD(m, 4);
92 instable = GET_WORD(m, 6);
94 // The flags word has atleast 1 bit, the Adlib's rhythm mode, but
95 // currently we don't support that :(
97 flags = GET_WORD(m, 8);
99 // Instrument datas are directly addressed with m[]
101 inscount = (filelen - instable) >> 4;
103 // Voice' and sequence pointers
106 for (i = 0; i < 11; i++) {
107 voice[i].trkpos = voice[i].trkstart = GET_WORD(m, 10 + (i<<1));
108 if (voice[i].trkpos && voice[i].trkpos < seqcount)
109 seqcount = voice[i].trkpos;
111 seqcount = (seqcount - seqtable) >> 1;
112 sequences = new unsigned short[seqcount];
113 for (i = 0; i < seqcount; i++)
114 sequences[i] = GET_WORD(m, seqtable + (i<<1));
123 bool CjbmPlayer::update()
127 for (c = 0; c < 11; c++) {
128 if (!voice[c].trkpos) // Unused channel
131 if (--voice[c].delay)
134 // Turn current note/percussion off
136 if (voice[c].note&0x7f)
137 opl_noteonoff(c, &voice[c], 0);
139 // Process events until we have a note
141 spos = voice[c].seqpos;
142 while(!voice[c].delay) {
144 case 0xFD: // Set Instrument
145 voice[c].instr = m[spos+1];
146 set_opl_instrument(c, &voice[c]);
149 case 0xFF: // End of Sequence
150 voice[c].seqno = m[++voice[c].trkpos];
151 if (voice[c].seqno == 0xff) {
152 voice[c].trkpos = voice[c].trkstart;
153 voice[c].seqno = m[voice[c].trkpos];
154 //voicemask &= 0x7ff-(1<<c);
155 voicemask &= ~(1<<c);
157 spos = voice[c].seqpos = sequences[voice[c].seqno];
159 default: // Note Event
160 if ((m[spos] & 127) > 95)
163 voice[c].note = m[spos];
164 voice[c].vol = m[spos+1];
166 (m[spos+2] + (m[spos+3]<<8)) + 1;
168 frq = notetable[voice[c].note&127];
169 voice[c].frq[0] = (unsigned char)frq;
170 voice[c].frq[1] = frq >> 8;
174 voice[c].seqpos = spos;
176 // Write new volume to the carrier operator, or percussion
178 if (flags&1 && c > 6)
179 opl->write(0x40 + percmx_tab[c-7], voice[c].vol ^ 0x3f);
181 opl->write(0x43 + op_table[c], voice[c].vol ^ 0x3f);
183 // Write new frequencies and Gate bit
185 opl_noteonoff(c, &voice[c], !(voice[c].note & 0x80));
190 void CjbmPlayer::rewind(int subsong)
196 for (c = 0; c < 11; c++) {
197 voice[c].trkpos = voice[c].trkstart;
199 if (!voice[c].trkpos) continue;
203 voice[c].seqno = m[voice[c].trkpos];
204 voice[c].seqpos = sequences[voice[c].seqno];
211 opl->write(0x01, 32);
213 // Set rhythm mode if flags bit #0 is set
214 // AM and Vibrato are full depths (taken from DosBox RAW output)
215 bdreg = 0xC0 | (flags&1)<<5;
217 opl->write(0xbd, bdreg);
221 voice[7].frq[0] = 0x58; voice[7].frq[1] = 0x09; // XXX
222 voice[8].frq[0] = 0x04; voice[8].frq[1] = 0x0a; // XXX
223 opl_noteonoff(7, &voice[7], 0);
224 opl_noteonoff(8, &voice[8], 0);
231 /*** private methods ************************************/
233 void CjbmPlayer::opl_noteonoff(int channel, JBMVoice *v, bool state)
235 if (flags&1 && channel > 5) {
237 opl->write(0xa0 + perchn_tab[channel-6], voice[channel].frq[0]);
238 opl->write(0xb0 + perchn_tab[channel-6], voice[channel].frq[1]);
240 state ? bdreg | percmaskon[channel-6] :
241 bdreg & percmaskoff[channel-6]);
243 // Melodic mode or Rhythm mode melodic channels
244 opl->write(0xa0 + channel, voice[channel].frq[0]);
245 opl->write(0xb0 + channel,
246 state ? voice[channel].frq[1] | 0x20 :
247 voice[channel].frq[1] & 0x1f);
253 void CjbmPlayer::set_opl_instrument(int channel, JBMVoice *v)
255 short i = instable + (v->instr << 4);
257 // Sanity check on instr number - or we'll be reading outside m[] !
259 if (v->instr >= inscount)
262 // For rhythm mode, multiplexed drums. I don't care about waveforms!
263 if ((flags&1) & (channel > 6)) {
264 opl->write(0x20 + percmx_tab[channel-7], m[i+0]);
265 opl->write(0x40 + percmx_tab[channel-7], m[i+1] ^ 0x3f);
266 opl->write(0x60 + percmx_tab[channel-7], m[i+2]);
267 opl->write(0x80 + percmx_tab[channel-7], m[i+3]);
269 opl->write(0xc0 + perchn_tab[channel-6], m[i+8]&15);
273 // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 1st operator
274 opl->write(0x20 + op_table[channel], m[i+0]);
275 opl->write(0x40 + op_table[channel], m[i+1] ^ 0x3f);
276 opl->write(0x60 + op_table[channel], m[i+2]);
277 opl->write(0x80 + op_table[channel], m[i+3]);
279 // AM/VIB/EG/KSR/FRQMUL, KSL/OUTPUT, ADSR for 2nd operator
280 opl->write(0x23 + op_table[channel], m[i+4]);
281 opl->write(0x43 + op_table[channel], m[i+5] ^ 0x3f);
282 opl->write(0x63 + op_table[channel], m[i+6]);
283 opl->write(0x83 + op_table[channel], m[i+7]);
285 // WAVEFORM for operators
286 opl->write(0xe0 + op_table[channel], (m[i+8]>>4)&3);
287 opl->write(0xe3 + op_table[channel], (m[i+8]>>6)&3);
290 opl->write(0xc0 + channel, m[i+8]&15);