diff options
author | Travis Howell | 2003-08-14 02:30:54 +0000 |
---|---|---|
committer | Travis Howell | 2003-08-14 02:30:54 +0000 |
commit | 90f77843ad0de45bfae377afab58de0cccb4c3b4 (patch) | |
tree | 5bdc1bb5ee5a90185fb841369b1d6e72b1af9df1 /scumm | |
parent | cd40c899b2da2b9f0bf857946ac74be119b90bd6 (diff) | |
download | scummvm-rg350-90f77843ad0de45bfae377afab58de0cccb4c3b4.tar.gz scummvm-rg350-90f77843ad0de45bfae377afab58de0cccb4c3b4.tar.bz2 scummvm-rg350-90f77843ad0de45bfae377afab58de0cccb4c3b4.zip |
v1 maniac sound player
svn-id: r9676
Diffstat (limited to 'scumm')
-rw-r--r-- | scumm/player_v1.cpp | 279 | ||||
-rw-r--r-- | scumm/player_v1.h | 63 |
2 files changed, 342 insertions, 0 deletions
diff --git a/scumm/player_v1.cpp b/scumm/player_v1.cpp new file mode 100644 index 0000000000..5bee75ca80 --- /dev/null +++ b/scumm/player_v1.cpp @@ -0,0 +1,279 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#include "stdafx.h" +#include "common/engine.h" +#include "player_v1.h" +#include "scumm.h" +#include "sound/mixer.h" + +#define TIMER_BASE_FREQ 1193000 +#define FIXP_SHIFT 16 + +//////////////////////////////////////// +// +// V1 PC-Speaker player +// +//////////////////////////////////////// + + +Player_V1::Player_V1(Scumm *scumm) : Player_V2(scumm) { + /* pcjr not yet supported */ + set_pcjr(false); + + _freq_current = 0; +} + +Player_V1::~Player_V1() { +} + +void Player_V1::chainSound(int nr, byte *data) { + int offset = _pcjr ? READ_LE_UINT16(data+4) : 6; + + current_nr = nr; + current_data = data; + _next_cmd = data + (_pcjr ? offset + 2 : offset + 4); + _repeat_ptr = _next_cmd; + _music_timer = 0; + + debug(4, "Chaining new sound %d", nr); + parse_chunk(); +} + +void Player_V1::startSound(int nr, byte *data) { + mutex_up(); + + int offset = _pcjr ? READ_LE_UINT16(data+4) : 6; + int cprio = current_data ? *(current_data + offset) & 0x7f : 0; + int prio = *(data + _header_len) & 0x7f; + int nprio = next_data ? *(next_data + _header_len) & 0x7f : 0; + + int restartable = *(data + _header_len) & 0x80; + + if (!current_nr || cprio <= prio) { + int tnr = current_nr; + int tprio = cprio; + byte *tdata = current_data; + + chainSound(nr, data); + nr = tnr; + prio = tprio; + data = tdata; + restartable = data ? *(data + _header_len) & 0x80 : 0; + } + + if (!current_nr) { + nr = 0; + next_nr = 0; + next_data = 0; + } + + if (nr != current_nr + && restartable + && (!next_nr + || nprio <= prio)) { + + next_nr = nr; + next_data = data; + } + + mutex_down(); +} + +void Player_V1::restartSound() { + if (*(current_data + _header_len) & 0x80) { + /* current sound is restartable */ + chainSound(current_nr, current_data); + } else { + chainNextSound(); + } +} + +int Player_V1::getMusicTimer() const { + return _music_timer; +} + +void Player_V1::parse_chunk() { + set_mplex(3000); + _forced_level = 0; + + parse_again: + _chunk_type = READ_LE_UINT16(_next_cmd); + debug(4, "parse_chunk: sound %d, offset %4x, chunk %x", + current_nr, _next_cmd - current_data, _chunk_type); + + _next_cmd += 2; + switch (_chunk_type) { + case 0xffff: + current_nr = 0; + current_data = 0; + _freq_current = 0; + chainNextSound(); + break; + case 0xfffe: + _repeat_ptr = _next_cmd; + goto parse_again; + + case 0xfffd: + _next_cmd = _repeat_ptr; + goto parse_again; + + case 0xfffc: + /* handle reset. We don't need this don't we? */ + goto parse_again; + + case 0: + _time_left = 1; + set_mplex(READ_LE_UINT16(_next_cmd)); + _next_cmd += 2; + break; + case 1: + set_mplex(READ_LE_UINT16(_next_cmd)); + _freq_start = READ_LE_UINT16(_next_cmd + 2); + _freq_end = READ_LE_UINT16(_next_cmd + 4); + _freq_delta = READ_LE_UINT16(_next_cmd + 6); + _repeat_ctr = READ_LE_UINT16(_next_cmd + 8); + _freq_current = _freq_start; + _next_cmd += 10; + debug(4, "chunk 1: mplex %d, freq %d -> %d step %d x %d", + _mplex, _freq_start, _freq_end, _freq_delta, _repeat_ctr); + break; + case 2: + _freq_start = READ_LE_UINT16(_next_cmd); + _freq_end = READ_LE_UINT16(_next_cmd + 2); + _freq_delta = READ_LE_UINT16(_next_cmd + 4); + _freq_current = 0; + _next_cmd += 6; + debug(4, "chunk 2: %d -> %d step %d", + _freq_start, _freq_end, _freq_delta); + break; + case 3: + _freq_start = READ_LE_UINT16(_next_cmd); + _freq_end = READ_LE_UINT16(_next_cmd + 2); + _freq_delta = READ_LE_UINT16(_next_cmd + 4); + _freq_current = 0; + _next_cmd += 6; + debug(4, "chunk 3: %d -> %d step %d", + _freq_start, _freq_end, _freq_delta); + break; + } +} + +void Player_V1::next_speaker_cmd() { + uint16 lsr; + switch (_chunk_type) { + case 0: + if (--_time_left) + return; + _time_left = READ_LE_UINT16(_next_cmd); + _next_cmd += 2; + if (_time_left == 0xfffb) { + /* handle 0xfffb?? */ + _time_left = READ_LE_UINT16(_next_cmd); + _next_cmd += 2; + } + debug(4, "next_speaker_cmd: chunk %d, offset %4x: notelen %d", + _chunk_type, _next_cmd - 2 - current_data, _time_left); + + if (_time_left == 0) { + parse_chunk(); + } else { + _freq_current = READ_LE_UINT16(_next_cmd); + _next_cmd += 2; + debug(4, "freq_current: %d", _freq_current); + } + break; + + case 1: + _freq_current = (_freq_current + _freq_delta) & 0xffff; + if (_freq_current == _freq_end) { + if (!--_repeat_ctr) + parse_chunk(); + _freq_current = _freq_start; + } + break; + + case 2: + _freq_start = (_freq_start + _freq_delta) & 0xffff; + if (_freq_start == _freq_end) { + parse_chunk(); + } + set_mplex(_freq_start); + _forced_level ^= 1; + break; + case 3: + _freq_start = (_freq_start + _freq_delta) & 0xffff; + if (_freq_start == _freq_end) { + parse_chunk(); + } + lsr = _random_lsr + 0x9248; + lsr = (lsr >> 3) | (lsr << 13); + _random_lsr = lsr; + set_mplex((_freq_start & lsr) | 0x180); + _forced_level ^= 1; + break; + } +} + +void Player_V1::set_mplex (uint mplex) { + if (mplex == 0) + mplex = 65536; + _mplex = mplex; + _tick_len = (_sample_rate << FIXP_SHIFT) + / (TIMER_BASE_FREQ / mplex); +} + +void Player_V1::do_mix (int16 *data, uint len) { + mutex_up(); + uint step; + + do { + step = len; + if (step > (_next_tick >> FIXP_SHIFT)) + step = (_next_tick >> FIXP_SHIFT); + generateSpkSamples(data, step); + data += step; + _next_tick -= step << FIXP_SHIFT; + + if (!(_next_tick >> FIXP_SHIFT)) { + _next_tick += _tick_len; + next_speaker_cmd(); + } + } while (len -= step); + mutex_down(); +} + +void Player_V1::generateSpkSamples(int16 *data, uint len) { + uint i; + + memset (data, 0, sizeof(int16) * len); + if (_freq_current == 0) { + if (_forced_level) { + for (i = 0; i < len; i++) { + data[i] = _volumetable[0]; + } + } else if (!_level) { + return; + } + } else { + squareGenerator(0, _freq_current, 0, 0, data, len); + } + lowPassFilter(data, len); +} diff --git a/scumm/player_v1.h b/scumm/player_v1.h new file mode 100644 index 0000000000..66d10c907c --- /dev/null +++ b/scumm/player_v1.h @@ -0,0 +1,63 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef PLAYER_V1_H +#define PLAYER_V1_H + +#include "player_v2.h" + +class Player_V1 : public Player_V2 { +public: + Player_V1(Scumm *scumm); + ~Player_V1(); + + void startSound(int nr, byte *data); + int getMusicTimer() const; + +protected: + void restartSound(); + void next_speaker_cmd(ChannelInfo *channel); + void chainSound(int nr, byte *data); + + void do_mix (int16 *buf, uint len); + + void set_mplex(uint mplex); + void parse_chunk(); + void next_speaker_cmd(); + void generateSpkSamples(int16 *data, uint len); + +private: + byte *_next_cmd; + byte *_repeat_ptr; + uint _chunk_type; + uint _time_left; + uint _mplex; + uint _freq_start; + uint _freq_end; + uint _freq_delta; + uint _repeat_ctr; + uint _freq_current; + uint _forced_level; + uint16 _random_lsr; +}; + +#endif |