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