Mercurial > audlegacy-plugins
comparison src/adplug/core/msc.cxx @ 12:3da1b8942b8b trunk
[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author | nenolod |
---|---|
date | Mon, 18 Sep 2006 03:14:20 -0700 |
parents | src/Input/adplug/core/msc.cxx@13389e613d67 |
children | cae46214b8bf |
comparison
equal
deleted
inserted
replaced
11:cff1d04026ae | 12:3da1b8942b8b |
---|---|
1 /* | |
2 * Adplug - Replayer for many OPL2/OPL3 audio file formats. | |
3 * Copyright (C) 1999 - 2006 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 * msc.c - MSC Player by Lubomir Bulej (pallas@kadan.cz) | |
20 */ | |
21 | |
22 #include <stdio.h> | |
23 | |
24 #include "msc.h" | |
25 #include "debug.h" | |
26 | |
27 const unsigned char CmscPlayer::msc_signature [MSC_SIGN_LEN] = { | |
28 'C', 'e', 'r', 'e', 's', ' ', '\x13', ' ', | |
29 'M', 'S', 'C', 'p', 'l', 'a', 'y', ' ' }; | |
30 | |
31 /*** public methods *************************************/ | |
32 | |
33 CPlayer *CmscPlayer::factory (Copl * newopl) | |
34 { | |
35 return new CmscPlayer (newopl); | |
36 } | |
37 | |
38 CmscPlayer::CmscPlayer(Copl * newopl) : CPlayer (newopl) | |
39 { | |
40 desc = NULL; | |
41 msc_data = NULL; | |
42 raw_data = NULL; | |
43 nr_blocks = 0; | |
44 } | |
45 | |
46 CmscPlayer::~CmscPlayer() | |
47 { | |
48 if (raw_data != NULL) | |
49 delete [] raw_data; | |
50 | |
51 if (msc_data != NULL) { | |
52 // free compressed blocks | |
53 for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { | |
54 if (msc_data [blk_num].mb_data != NULL) | |
55 delete [] msc_data [blk_num].mb_data; | |
56 } | |
57 | |
58 delete [] msc_data; | |
59 } | |
60 | |
61 if (desc != NULL) | |
62 delete [] desc; | |
63 } | |
64 | |
65 bool CmscPlayer::load(const std::string & filename, const CFileProvider & fp) | |
66 { | |
67 binistream * bf; | |
68 msc_header hdr; | |
69 | |
70 // open and validate the file | |
71 bf = fp.open (filename); | |
72 if (! bf) | |
73 return false; | |
74 | |
75 if (! load_header (bf, & hdr)) { | |
76 fp.close (bf); | |
77 return false; | |
78 } | |
79 | |
80 // get stuff from the header | |
81 version = hdr.mh_ver; | |
82 timer_div = hdr.mh_timer; | |
83 nr_blocks = hdr.mh_nr_blocks; | |
84 block_len = hdr.mh_block_len; | |
85 | |
86 if (! nr_blocks) { | |
87 fp.close (bf); | |
88 return false; | |
89 } | |
90 | |
91 // load compressed data blocks | |
92 msc_data = new msc_block [nr_blocks]; | |
93 raw_data = new u8 [block_len]; | |
94 | |
95 for (int blk_num = 0; blk_num < nr_blocks; blk_num++) { | |
96 msc_block blk; | |
97 | |
98 blk.mb_length = bf->readInt (2); | |
99 blk.mb_data = new u8 [blk.mb_length]; | |
100 for (int oct_num = 0; oct_num < blk.mb_length; oct_num++) { | |
101 blk.mb_data [oct_num] = bf->readInt (1); | |
102 } | |
103 | |
104 msc_data [blk_num] = blk; | |
105 } | |
106 | |
107 // clean up & initialize | |
108 fp.close (bf); | |
109 rewind (0); | |
110 | |
111 return true; | |
112 } | |
113 | |
114 bool CmscPlayer::update() | |
115 { | |
116 // output data | |
117 while (! delay) { | |
118 u8 cmnd; | |
119 u8 data; | |
120 | |
121 // decode data | |
122 if (! decode_octet (& cmnd)) | |
123 return false; | |
124 | |
125 if (! decode_octet (& data)) | |
126 return false; | |
127 | |
128 // check for special commands | |
129 switch (cmnd) { | |
130 | |
131 // delay | |
132 case 0xff: | |
133 delay = 1 + (u8) (data - 1); | |
134 break; | |
135 | |
136 // play command & data | |
137 default: | |
138 opl->write (cmnd, data); | |
139 | |
140 } // command switch | |
141 } // play pass | |
142 | |
143 | |
144 // count delays | |
145 if (delay) | |
146 delay--; | |
147 | |
148 // advance player position | |
149 play_pos++; | |
150 return true; | |
151 } | |
152 | |
153 void CmscPlayer::rewind(int subsong) | |
154 { | |
155 // reset state | |
156 dec_prefix = 0; | |
157 block_num = 0; | |
158 block_pos = 0; | |
159 play_pos = 0; | |
160 raw_pos = 0; | |
161 delay = 0; | |
162 | |
163 // init the OPL chip and go to OPL2 mode | |
164 opl->init(); | |
165 opl->write(1, 32); | |
166 } | |
167 | |
168 float CmscPlayer::getrefresh() | |
169 { | |
170 // PC timer oscillator frequency / wait register | |
171 return 1193180 / (float) (timer_div ? timer_div : 0xffff); | |
172 } | |
173 | |
174 std::string CmscPlayer::gettype() | |
175 { | |
176 char vstr [40]; | |
177 | |
178 sprintf(vstr, "AdLib MSCplay (version %d)", version); | |
179 return std::string (vstr); | |
180 } | |
181 | |
182 /*** private methods *************************************/ | |
183 | |
184 bool CmscPlayer::load_header(binistream * bf, msc_header * hdr) | |
185 { | |
186 // check signature | |
187 bf->readString ((char *) hdr->mh_sign, sizeof (hdr->mh_sign)); | |
188 if (memcmp (msc_signature, hdr->mh_sign, MSC_SIGN_LEN) != 0) | |
189 return false; | |
190 | |
191 // check version | |
192 hdr->mh_ver = bf->readInt (2); | |
193 if (hdr->mh_ver != 0) | |
194 return false; | |
195 | |
196 bf->readString ((char *) hdr->mh_desc, sizeof (hdr->mh_desc)); | |
197 hdr->mh_timer = bf->readInt (2); | |
198 hdr->mh_nr_blocks = bf->readInt (2); | |
199 hdr->mh_block_len = bf->readInt (2); | |
200 return true; | |
201 } | |
202 | |
203 bool CmscPlayer::decode_octet(u8 * output) | |
204 { | |
205 msc_block blk; // compressed data block | |
206 | |
207 if (block_num >= nr_blocks) | |
208 return false; | |
209 | |
210 blk = msc_data [block_num]; | |
211 while (1) { | |
212 u8 octet; // decoded octet | |
213 u8 len_corr; // length correction | |
214 | |
215 // advance to next block if necessary | |
216 if (block_pos >= blk.mb_length && dec_len == 0) { | |
217 block_num++; | |
218 if (block_num >= nr_blocks) | |
219 return false; | |
220 | |
221 blk = msc_data [block_num]; | |
222 block_pos = 0; | |
223 raw_pos = 0; | |
224 } | |
225 | |
226 // decode the compressed music data | |
227 switch (dec_prefix) { | |
228 | |
229 // decode prefix | |
230 case 155: | |
231 case 175: | |
232 octet = blk.mb_data [block_pos++]; | |
233 if (octet == 0) { | |
234 // invalid prefix, output original | |
235 octet = dec_prefix; | |
236 dec_prefix = 0; | |
237 break; | |
238 } | |
239 | |
240 // isolate length and distance | |
241 dec_len = (octet & 0x0F); | |
242 len_corr = 2; | |
243 | |
244 dec_dist = (octet & 0xF0) >> 4; | |
245 if (dec_prefix == 155) | |
246 dec_dist++; | |
247 | |
248 // next decode step for respective prefix type | |
249 dec_prefix++; | |
250 continue; | |
251 | |
252 | |
253 // check for extended length | |
254 case 156: | |
255 if (dec_len == 15) | |
256 dec_len += blk.mb_data [block_pos++]; | |
257 | |
258 // add length correction and go for copy mode | |
259 dec_len += len_corr; | |
260 dec_prefix = 255; | |
261 continue; | |
262 | |
263 | |
264 // get extended distance | |
265 case 176: | |
266 dec_dist += 17 + 16 * blk.mb_data [block_pos++]; | |
267 len_corr = 3; | |
268 | |
269 // check for extended length | |
270 dec_prefix = 156; | |
271 continue; | |
272 | |
273 | |
274 // prefix copy mode | |
275 case 255: | |
276 if((int)raw_pos >= dec_dist) | |
277 octet = raw_data [raw_pos - dec_dist]; | |
278 else { | |
279 AdPlug_LogWrite("error! read before raw_data buffer.\n"); | |
280 octet = 0; | |
281 } | |
282 | |
283 dec_len--; | |
284 if (dec_len == 0) { | |
285 // back to normal mode | |
286 dec_prefix = 0; | |
287 } | |
288 | |
289 break; | |
290 | |
291 | |
292 // normal mode | |
293 default: | |
294 octet = blk.mb_data [block_pos++]; | |
295 if (octet == 155 || octet == 175) { | |
296 // it's a prefix, restart | |
297 dec_prefix = octet; | |
298 continue; | |
299 } | |
300 } // prefix switch | |
301 | |
302 | |
303 // output the octet | |
304 if (output != NULL) | |
305 *output = octet; | |
306 | |
307 raw_data [raw_pos++] = octet; | |
308 break; | |
309 }; // decode pass | |
310 | |
311 return true; | |
312 } |