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 }