Mercurial > audlegacy-plugins
comparison src/Input/adplug/core/bam.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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13389e613d67 |
---|---|
1 /* | |
2 * Adplug - Replayer for many OPL2/OPL3 audio file formats. | |
3 * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al. | |
4 * | |
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. | |
9 * | |
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. | |
14 * | |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 * | |
19 * bam.cpp - Bob's Adlib Music Player, by Simon Peter <dn.tlp@gmx.net> | |
20 * | |
21 * NOTES: | |
22 * In my player, the loop counter is stored with the label. This can be | |
23 * dangerous for some situations (see below), but there shouldn't be any BAM | |
24 * files triggering this situation. | |
25 * | |
26 * From SourceForge Bug #476088: | |
27 * ----------------------------- | |
28 * Using just one loop counter for each label, my player can't | |
29 * handle files that loop twice to the same label (if that's at | |
30 * all possible with BAM). Imagine the following situation: | |
31 * | |
32 * ... [*] ---- [<- *] ---- [<- *] ... | |
33 * ^ ^ ^ ^ ^ ^ ^ | |
34 * | | | | | | | | |
35 * +---|----+-----|-----+-----|----+--- normal song data | |
36 * +----------|-----------|-------- label 1 | |
37 * +-----------+-------- loop points to label 1 | |
38 * | |
39 * both loop points loop to the same label. Storing the loop | |
40 * count with the label would cause chaos with the counter, | |
41 * when the player executes the inner jump. | |
42 * ------------------ | |
43 * Not to worry. my reference implementation of BAM does not | |
44 * support the multiple loop situation you describe, and | |
45 * neither do any BAM-creation programs. Then both loops point | |
46 * to the same label, the inner loop's counter is just allowed | |
47 * to clobber the outer loop's counter. No stack is neccisary. | |
48 */ | |
49 | |
50 #include <string.h> | |
51 #include "bam.h" | |
52 | |
53 const unsigned short CbamPlayer::freq[] = {172,182,193,205,217,230,243,258,274, | |
54 290,307,326,345,365,387,410,435,460,489,517,547,580,614,651,1369,1389,1411, | |
55 1434,1459,1484,1513,1541,1571,1604,1638,1675,2393,2413,2435,2458,2483,2508, | |
56 2537,2565,2595,2628,2662,2699,3417,3437,3459,3482,3507,3532,3561,3589,3619, | |
57 3652,3686,3723,4441,4461,4483,4506,4531,4556,4585,4613,4643,4676,4710,4747, | |
58 5465,5485,5507,5530,5555,5580,5609,5637,5667,5700,5734,5771,6489,6509,6531, | |
59 6554,6579,6604,6633,6661,6691,6724,6758,6795,7513,7533,7555,7578,7603,7628, | |
60 7657,7685,7715,7748,7782,7819,7858,7898,7942,7988,8037,8089,8143,8191,8191, | |
61 8191,8191,8191,8191,8191,8191,8191,8191,8191,8191}; | |
62 | |
63 CPlayer *CbamPlayer::factory(Copl *newopl) | |
64 { | |
65 return new CbamPlayer(newopl); | |
66 } | |
67 | |
68 bool CbamPlayer::load(const std::string &filename, const CFileProvider &fp) | |
69 { | |
70 binistream *f = fp.open(filename); if(!f) return false; | |
71 char id[4]; | |
72 unsigned int i; | |
73 | |
74 size = fp.filesize(f) - 4; // filesize minus header | |
75 f->readString(id, 4); | |
76 if(strncmp(id,"CBMF",4)) { fp.close(f); return false; } | |
77 | |
78 song = new unsigned char [size]; | |
79 for(i = 0; i < size; i++) song[i] = f->readInt(1); | |
80 | |
81 fp.close(f); | |
82 rewind(0); | |
83 return true; | |
84 } | |
85 | |
86 bool CbamPlayer::update() | |
87 { | |
88 unsigned char cmd,c; | |
89 | |
90 if(del) { | |
91 del--; | |
92 return !songend; | |
93 } | |
94 | |
95 if(pos >= size) { // EOF detection | |
96 pos = 0; | |
97 songend = true; | |
98 } | |
99 | |
100 while(song[pos] < 128) { | |
101 cmd = song[pos] & 240; | |
102 c = song[pos] & 15; | |
103 switch(cmd) { | |
104 case 0: // stop song | |
105 pos = 0; | |
106 songend = true; | |
107 break; | |
108 case 16: // start note | |
109 if(c < 9) { | |
110 opl->write(0xa0 + c, freq[song[++pos]] & 255); | |
111 opl->write(0xb0 + c, (freq[song[pos]] >> 8) + 32); | |
112 } else | |
113 pos++; | |
114 pos++; | |
115 break; | |
116 case 32: // stop note | |
117 if(c < 9) | |
118 opl->write(0xb0 + c, 0); | |
119 pos++; | |
120 break; | |
121 case 48: // define instrument | |
122 if(c < 9) { | |
123 opl->write(0x20 + op_table[c],song[pos+1]); | |
124 opl->write(0x23 + op_table[c],song[pos+2]); | |
125 opl->write(0x40 + op_table[c],song[pos+3]); | |
126 opl->write(0x43 + op_table[c],song[pos+4]); | |
127 opl->write(0x60 + op_table[c],song[pos+5]); | |
128 opl->write(0x63 + op_table[c],song[pos+6]); | |
129 opl->write(0x80 + op_table[c],song[pos+7]); | |
130 opl->write(0x83 + op_table[c],song[pos+8]); | |
131 opl->write(0xe0 + op_table[c],song[pos+9]); | |
132 opl->write(0xe3 + op_table[c],song[pos+10]); | |
133 opl->write(0xc0 + c,song[pos+11]); | |
134 } | |
135 pos += 12; | |
136 break; | |
137 case 80: // set label | |
138 label[c].target = ++pos; | |
139 label[c].defined = true; | |
140 break; | |
141 case 96: // jump | |
142 if(label[c].defined) | |
143 switch(song[pos+1]) { | |
144 case 254: // infinite loop | |
145 if(label[c].defined) { | |
146 pos = label[c].target; | |
147 songend = true; | |
148 break; | |
149 } | |
150 // fall through... | |
151 case 255: // chorus | |
152 if(!chorus && label[c].defined) { | |
153 chorus = true; | |
154 gosub = pos + 2; | |
155 pos = label[c].target; | |
156 break; | |
157 } | |
158 // fall through... | |
159 case 0: // end of loop | |
160 pos += 2; | |
161 break; | |
162 default: // finite loop | |
163 if(!label[c].count) { // loop elapsed | |
164 label[c].count = 255; | |
165 pos += 2; | |
166 break; | |
167 } | |
168 if(label[c].count < 255) // loop defined | |
169 label[c].count--; | |
170 else // loop undefined | |
171 label[c].count = song[pos+1] - 1; | |
172 pos = label[c].target; | |
173 break; | |
174 } | |
175 break; | |
176 case 112: // end of chorus | |
177 if(chorus) { | |
178 pos = gosub; | |
179 chorus = false; | |
180 } else | |
181 pos++; | |
182 break; | |
183 default: // reserved command (skip) | |
184 pos++; | |
185 break; | |
186 } | |
187 } | |
188 if(song[pos] >= 128) { // wait | |
189 del = song[pos] - 127; | |
190 pos++; | |
191 } | |
192 return !songend; | |
193 } | |
194 | |
195 void CbamPlayer::rewind(int subsong) | |
196 { | |
197 int i; | |
198 | |
199 pos = 0; songend = false; del = 0; gosub = 0; chorus = false; | |
200 memset(label, 0, sizeof(label)); label[0].defined = true; | |
201 for(i = 0; i < 16; i++) label[i].count = 255; // 255 = undefined | |
202 opl->init(); opl->write(1,32); | |
203 } |