2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 * Copyright (C) 1999 - 2006 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 * msc.c - MSC Player by Lubomir Bulej (pallas@kadan.cz)
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', ' ' };
32 /*** public methods *************************************/
34 CPlayer *CmscPlayer::factory (Copl * newopl)
36 return new CmscPlayer (newopl);
39 CmscPlayer::CmscPlayer(Copl * newopl) : CPlayer (newopl)
47 CmscPlayer::~CmscPlayer()
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;
66 bool CmscPlayer::load(const std::string & filename, const CFileProvider & fp)
71 // open and validate the file
72 bf = fp.open (filename);
76 if (! load_header (bf, & hdr)) {
81 // get stuff from the header
83 timer_div = hdr.mh_timer;
84 nr_blocks = hdr.mh_nr_blocks;
85 block_len = hdr.mh_block_len;
92 // load compressed data blocks
93 msc_data = new msc_block [nr_blocks];
94 raw_data = new u8 [block_len];
96 for (int blk_num = 0; blk_num < nr_blocks; blk_num++) {
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);
105 msc_data [blk_num] = blk;
108 // clean up & initialize
115 bool CmscPlayer::update()
123 if (! decode_octet (& cmnd))
126 if (! decode_octet (& data))
129 // check for special commands
134 delay = 1 + (u8) (data - 1);
137 // play command & data
139 opl->write (cmnd, data);
149 // advance player position
154 void CmscPlayer::rewind(int subsong)
164 // init the OPL chip and go to OPL2 mode
169 float CmscPlayer::getrefresh()
171 // PC timer oscillator frequency / wait register
172 return 1193180 / (float) (timer_div ? timer_div : 0xffff);
175 std::string CmscPlayer::gettype()
179 sprintf(vstr, "AdLib MSCplay (version %d)", version);
180 return std::string (vstr);
183 /*** private methods *************************************/
185 bool CmscPlayer::load_header(binistream * bf, msc_header * hdr)
188 bf->readString ((char *) hdr->mh_sign, sizeof (hdr->mh_sign));
189 if (memcmp (msc_signature, hdr->mh_sign, MSC_SIGN_LEN) != 0)
193 hdr->mh_ver = bf->readInt (2);
194 if (hdr->mh_ver != 0)
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);
204 bool CmscPlayer::decode_octet(u8 * output)
206 msc_block blk; // compressed data block
208 if (block_num >= nr_blocks)
211 blk = msc_data [block_num];
213 u8 octet; // decoded octet
214 u8 len_corr; // length correction
216 // advance to next block if necessary
217 if (block_pos >= blk.mb_length && dec_len == 0) {
219 if (block_num >= nr_blocks)
222 blk = msc_data [block_num];
227 // decode the compressed music data
228 switch (dec_prefix) {
233 octet = blk.mb_data [block_pos++];
235 // invalid prefix, output original
241 // isolate length and distance
242 dec_len = (octet & 0x0F);
245 dec_dist = (octet & 0xF0) >> 4;
246 if (dec_prefix == 155)
249 // next decode step for respective prefix type
254 // check for extended length
257 dec_len += blk.mb_data [block_pos++];
259 // add length correction and go for copy mode
265 // get extended distance
267 dec_dist += 17 + 16 * blk.mb_data [block_pos++];
270 // check for extended length
277 if((int)raw_pos >= dec_dist)
278 octet = raw_data [raw_pos - dec_dist];
280 AdPlug_LogWrite("error! read before raw_data buffer.\n");
286 // back to normal mode
295 octet = blk.mb_data [block_pos++];
296 if (octet == 155 || octet == 175) {
297 // it's a prefix, restart
308 raw_data [raw_pos++] = octet;