diff options
author | Matthew Hoops | 2011-05-31 14:16:29 -0400 |
---|---|---|
committer | Matthew Hoops | 2011-05-31 14:16:29 -0400 |
commit | aa49b38c5a8032586cb94fc4ca07149eecabe64a (patch) | |
tree | ea5c7617f8c482c8cf4141b728b3ccff5a7f84c7 /audio | |
parent | d3ea9ab2a9334747eb445c1b45aa30cb17ffdf1b (diff) | |
parent | c86a6c466fabe31fbf36363aa8d0ac8ea6001b9f (diff) | |
download | scummvm-rg350-aa49b38c5a8032586cb94fc4ca07149eecabe64a.tar.gz scummvm-rg350-aa49b38c5a8032586cb94fc4ca07149eecabe64a.tar.bz2 scummvm-rg350-aa49b38c5a8032586cb94fc4ca07149eecabe64a.zip |
Merge remote branch 'upstream/master' into t7g-ios
Conflicts:
engines/groovie/script.cpp
Diffstat (limited to 'audio')
107 files changed, 1970 insertions, 1716 deletions
diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp index 0cfbabf53b..547aa77526 100644 --- a/audio/audiostream.cpp +++ b/audio/audiostream.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/debug.h" diff --git a/audio/audiostream.h b/audio/audiostream.h index 22de21cb34..0ffaa241ce 100644 --- a/audio/audiostream.h +++ b/audio/audiostream.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_AUDIOSTREAM_H diff --git a/audio/decoders/adpcm.cpp b/audio/decoders/adpcm.cpp index a9284973d5..d28ed222a5 100644 --- a/audio/decoders/adpcm.cpp +++ b/audio/decoders/adpcm.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/stream.h" diff --git a/audio/decoders/adpcm.h b/audio/decoders/adpcm.h index 10344101e2..1dd4d510df 100644 --- a/audio/decoders/adpcm.h +++ b/audio/decoders/adpcm.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/adpcm_intern.h b/audio/decoders/adpcm_intern.h index f875bd88c7..c9f894fb84 100644 --- a/audio/decoders/adpcm_intern.h +++ b/audio/decoders/adpcm_intern.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/aiff.cpp b/audio/decoders/aiff.cpp index 957fb13638..f3b0dfb559 100644 --- a/audio/decoders/aiff.cpp +++ b/audio/decoders/aiff.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/decoders/aiff.h b/audio/decoders/aiff.h index dddbffb520..558a018f57 100644 --- a/audio/decoders/aiff.h +++ b/audio/decoders/aiff.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/flac.cpp b/audio/decoders/flac.cpp index fe15877ac6..d06a7b9c0e 100644 --- a/audio/decoders/flac.cpp +++ b/audio/decoders/flac.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Disable symbol overrides for FILE as that is used in FLAC headers @@ -306,7 +303,7 @@ int FLACStream::readBuffer(int16 *buffer, const int numSamples) { const uint numChannels = getChannels(); if (numChannels == 0) { - warning("FLACStream: Stream not successfully initialised, cant playback"); + warning("FLACStream: Stream not successfully initialized, cant playback"); return -1; // streaminfo wasnt read! } diff --git a/audio/decoders/flac.h b/audio/decoders/flac.h index 69222f22a1..3182b26425 100644 --- a/audio/decoders/flac.h +++ b/audio/decoders/flac.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/iff_sound.cpp b/audio/decoders/iff_sound.cpp index 8efe017e75..4efdce0338 100644 --- a/audio/decoders/iff_sound.cpp +++ b/audio/decoders/iff_sound.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/decoders/iff_sound.h" diff --git a/audio/decoders/iff_sound.h b/audio/decoders/iff_sound.h index 4d26b32e71..b266e629a1 100644 --- a/audio/decoders/iff_sound.h +++ b/audio/decoders/iff_sound.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/mac_snd.cpp b/audio/decoders/mac_snd.cpp index fc69988860..43253a9ddf 100644 --- a/audio/decoders/mac_snd.cpp +++ b/audio/decoders/mac_snd.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/decoders/mac_snd.h b/audio/decoders/mac_snd.h index bf6331a265..cbbd82bbe0 100644 --- a/audio/decoders/mac_snd.h +++ b/audio/decoders/mac_snd.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/mp3.cpp b/audio/decoders/mp3.cpp index 91bd49873a..8d7f006ec7 100644 --- a/audio/decoders/mp3.cpp +++ b/audio/decoders/mp3.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/decoders/mp3.h" diff --git a/audio/decoders/mp3.h b/audio/decoders/mp3.h index d3a5b70d45..86ddc599ea 100644 --- a/audio/decoders/mp3.h +++ b/audio/decoders/mp3.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp index dbce8d2447..a178c363b5 100644 --- a/audio/decoders/qdm2.cpp +++ b/audio/decoders/qdm2.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Based off ffmpeg's QDM2 decoder diff --git a/audio/decoders/qdm2.h b/audio/decoders/qdm2.h index 6988623dcb..c0ec647bfd 100644 --- a/audio/decoders/qdm2.h +++ b/audio/decoders/qdm2.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Only compile if Mohawk is enabled or if we're building dynamic modules diff --git a/audio/decoders/qdm2data.h b/audio/decoders/qdm2data.h index cfe1a3d10e..d92bc0ff80 100644 --- a/audio/decoders/qdm2data.h +++ b/audio/decoders/qdm2data.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef AUDIO_QDM2DATA_H diff --git a/audio/decoders/raw.cpp b/audio/decoders/raw.cpp index cf787f9b12..4789fd0f36 100644 --- a/audio/decoders/raw.cpp +++ b/audio/decoders/raw.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/endian.h" diff --git a/audio/decoders/raw.h b/audio/decoders/raw.h index 23ed02182d..5a7897b688 100644 --- a/audio/decoders/raw.h +++ b/audio/decoders/raw.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_RAW_H diff --git a/audio/decoders/vag.cpp b/audio/decoders/vag.cpp index 2c3a36202a..10ef69708c 100644 --- a/audio/decoders/vag.cpp +++ b/audio/decoders/vag.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/decoders/vag.h" diff --git a/audio/decoders/vag.h b/audio/decoders/vag.h index 4adc1d3dde..b80fbdb98f 100644 --- a/audio/decoders/vag.h +++ b/audio/decoders/vag.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/voc.cpp b/audio/decoders/voc.cpp index 9c2dc4f337..74ea4440a1 100644 --- a/audio/decoders/voc.cpp +++ b/audio/decoders/voc.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/debug.h" diff --git a/audio/decoders/voc.h b/audio/decoders/voc.h index 38250dcf7a..8bc6dcf46f 100644 --- a/audio/decoders/voc.h +++ b/audio/decoders/voc.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/decoders/vorbis.cpp b/audio/decoders/vorbis.cpp index 63f7ba8207..2724dd1f02 100644 --- a/audio/decoders/vorbis.cpp +++ b/audio/decoders/vorbis.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Disable symbol overrides for FILE and fseek as those are used in the diff --git a/audio/decoders/vorbis.h b/audio/decoders/vorbis.h index 51d0b82d5f..e3d989e9b8 100644 --- a/audio/decoders/vorbis.h +++ b/audio/decoders/vorbis.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** @@ -36,6 +33,7 @@ * - scumm * - sword1 * - sword2 + * - sword25 * - touche * - tucker */ diff --git a/audio/decoders/wave.cpp b/audio/decoders/wave.cpp index a64874887a..3cf4566d0c 100644 --- a/audio/decoders/wave.cpp +++ b/audio/decoders/wave.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/debug.h" diff --git a/audio/decoders/wave.h b/audio/decoders/wave.h index 33c3e798a0..6a34bc175a 100644 --- a/audio/decoders/wave.h +++ b/audio/decoders/wave.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp index 5952a987a7..a24c2a533c 100644 --- a/audio/fmopl.cpp +++ b/audio/fmopl.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "audio/fmopl.h" diff --git a/audio/fmopl.h b/audio/fmopl.h index 33235f3545..b88325a52e 100644 --- a/audio/fmopl.h +++ b/audio/fmopl.h @@ -17,16 +17,16 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_FMOPL_H #define SOUND_FMOPL_H #include "common/scummsys.h" -#include "common/str.h" + +namespace Common { +class String; +} namespace OPL { diff --git a/audio/mididrv.cpp b/audio/mididrv.cpp index 6cc3366847..7beb76352c 100644 --- a/audio/mididrv.cpp +++ b/audio/mididrv.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/config-manager.h" diff --git a/audio/mididrv.h b/audio/mididrv.h index c6c5179051..7369cab26b 100644 --- a/audio/mididrv.h +++ b/audio/mididrv.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MIDIDRV_H diff --git a/audio/midiparser.cpp b/audio/midiparser.cpp index a1399d0c30..943a6067a4 100644 --- a/audio/midiparser.cpp +++ b/audio/midiparser.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/midiparser.h" diff --git a/audio/midiparser.h b/audio/midiparser.h index 24f2ba7963..9dff4b54ba 100644 --- a/audio/midiparser.h +++ b/audio/midiparser.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /// \brief Declarations related to the MidiParser class diff --git a/audio/midiparser_smf.cpp b/audio/midiparser_smf.cpp index 8ead95de4c..e883471b54 100644 --- a/audio/midiparser_smf.cpp +++ b/audio/midiparser_smf.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/midiparser.h" diff --git a/audio/midiparser_xmidi.cpp b/audio/midiparser_xmidi.cpp index 1146084cde..7c3cf102d1 100644 --- a/audio/midiparser_xmidi.cpp +++ b/audio/midiparser_xmidi.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/midiparser.h" @@ -240,7 +237,7 @@ bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) { pos += 4; _num_tracks = 1; } else if (memcmp(pos, "XDIR", 4)) { - // Not an XMIDI that we recognise + // Not an XMIDI that we recognize warning("Expected 'XDIR' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]); return false; } else { diff --git a/audio/midiplayer.cpp b/audio/midiplayer.cpp index f4a13a0438..7fab02a5be 100644 --- a/audio/midiplayer.cpp +++ b/audio/midiplayer.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/midiplayer.h" diff --git a/audio/midiplayer.h b/audio/midiplayer.h index 0cf373d646..e1da0bfb79 100644 --- a/audio/midiplayer.h +++ b/audio/midiplayer.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MIDIPLAYER_H diff --git a/audio/mixer.cpp b/audio/mixer.cpp index 4d23487e71..fb4fffb8d8 100644 --- a/audio/mixer.cpp +++ b/audio/mixer.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/util.h" @@ -260,6 +257,8 @@ int MixerImpl::mixCallback(byte *samples, uint len) { Common::StackLock lock(_mutex); int16 *buf = (int16 *)samples; + // we store stereo, 16-bit samples + assert(len % 4 == 0); len >>= 2; // Since the mixer callback has been called, the mixer must be ready... diff --git a/audio/mixer.h b/audio/mixer.h index 5802abdd6b..1fbe265488 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MIXER_H diff --git a/audio/mixer_intern.h b/audio/mixer_intern.h index d7764e50d9..a04eb55c5b 100644 --- a/audio/mixer_intern.h +++ b/audio/mixer_intern.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MIXER_INTERN_H @@ -129,6 +126,8 @@ public: * the backend (e.g. from an audio mixing thread). All the actual mixing * work is done from here. * + * @param samples Sample buffer, in which stereo 16-bit samples will be stored. + * @param len Length of the provided buffer to fill (in bytes, should be divisible by 4). * @return number of sample pairs processed (which can still be silence!) */ int mixCallback(byte *samples, uint len); diff --git a/audio/mods/infogrames.cpp b/audio/mods/infogrames.cpp index 8bfffeacb6..5b4d39fe49 100644 --- a/audio/mods/infogrames.cpp +++ b/audio/mods/infogrames.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/mods/infogrames.h" diff --git a/audio/mods/infogrames.h b/audio/mods/infogrames.h index 9787210e82..307a26d4e1 100644 --- a/audio/mods/infogrames.h +++ b/audio/mods/infogrames.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/mods/maxtrax.cpp b/audio/mods/maxtrax.cpp index 0738966dab..953bb8f8d2 100644 --- a/audio/mods/maxtrax.cpp +++ b/audio/mods/maxtrax.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/scummsys.h" diff --git a/audio/mods/maxtrax.h b/audio/mods/maxtrax.h index 2f890afe2d..bef6669d2a 100644 --- a/audio/mods/maxtrax.h +++ b/audio/mods/maxtrax.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // see if all engines using this class are DISABLED diff --git a/audio/mods/module.cpp b/audio/mods/module.cpp index 987b17bc8d..8d09671d26 100644 --- a/audio/mods/module.cpp +++ b/audio/mods/module.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/mods/module.h" diff --git a/audio/mods/module.h b/audio/mods/module.h index c9b72bd2d6..a57a89225e 100644 --- a/audio/mods/module.h +++ b/audio/mods/module.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MODS_MODULE_H diff --git a/audio/mods/paula.cpp b/audio/mods/paula.cpp index ef841ac9bf..4b49d6e750 100644 --- a/audio/mods/paula.cpp +++ b/audio/mods/paula.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/mods/paula.h" diff --git a/audio/mods/paula.h b/audio/mods/paula.h index f6f159d5a6..cd797f51cb 100644 --- a/audio/mods/paula.h +++ b/audio/mods/paula.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MODS_PAULA_H diff --git a/audio/mods/protracker.cpp b/audio/mods/protracker.cpp index f781920505..084b0edf9a 100644 --- a/audio/mods/protracker.cpp +++ b/audio/mods/protracker.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/mods/protracker.h" diff --git a/audio/mods/protracker.h b/audio/mods/protracker.h index fa9895b81f..15f708d801 100644 --- a/audio/mods/protracker.h +++ b/audio/mods/protracker.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/mods/rjp1.cpp b/audio/mods/rjp1.cpp index eaa99e6928..45c6caa106 100644 --- a/audio/mods/rjp1.cpp +++ b/audio/mods/rjp1.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/debug.h" diff --git a/audio/mods/rjp1.h b/audio/mods/rjp1.h index e3cb0b853d..232b1926e9 100644 --- a/audio/mods/rjp1.h +++ b/audio/mods/rjp1.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/mods/soundfx.cpp b/audio/mods/soundfx.cpp index 44fdd65986..767d1ce9c8 100644 --- a/audio/mods/soundfx.cpp +++ b/audio/mods/soundfx.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/endian.h" diff --git a/audio/mods/soundfx.h b/audio/mods/soundfx.h index 9dd5240160..48ccff2da6 100644 --- a/audio/mods/soundfx.h +++ b/audio/mods/soundfx.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /** diff --git a/audio/mods/tfmx.cpp b/audio/mods/tfmx.cpp index f7cfc50c10..a89da78af1 100644 --- a/audio/mods/tfmx.cpp +++ b/audio/mods/tfmx.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "common/scummsys.h" @@ -335,7 +332,7 @@ void Tfmx::macroRun(ChannelContext &channel) { channel.vibLength = macroPtr[1]; channel.vibCount = macroPtr[1] / 2; channel.vibDelta = macroPtr[3]; - // TODO: Perhaps a bug, vibValue could be left uninitialised + // TODO: Perhaps a bug, vibValue could be left uninitialized if (!channel.portaDelta) { channel.period = channel.refPeriod; channel.vibValue = 0; @@ -703,7 +700,7 @@ void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, channel.relVol = param2 >> 4; channel.fineTune = (int8)param3; - // TODO: the point where the channel gets initialised varies with the games, needs more research. + // TODO: the point where the channel gets initialized varies with the games, needs more research. initMacroProgramm(channel); channel.keyUp = false; // key down = playing a Note diff --git a/audio/mods/tfmx.h b/audio/mods/tfmx.h index 1930487eb8..2b07e2e660 100644 --- a/audio/mods/tfmx.h +++ b/audio/mods/tfmx.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // see if all engines using this class are DISABLED diff --git a/audio/module.mk b/audio/module.mk index 545a55c23b..46cb9944e1 100644 --- a/audio/module.mk +++ b/audio/module.mk @@ -42,10 +42,11 @@ MODULE_OBJS := \ softsynth/opl/mame.o \ softsynth/fmtowns_pc98/towns_audio.o \ softsynth/fmtowns_pc98/towns_euphony.o \ + softsynth/fmtowns_pc98/towns_midi.o \ softsynth/fmtowns_pc98/towns_pc98_driver.o \ softsynth/fmtowns_pc98/towns_pc98_fmsynth.o \ + softsynth/fmtowns_pc98/towns_pc98_plugins.o \ softsynth/appleiigs.o \ - softsynth/ym2612.o \ softsynth/fluidsynth.o \ softsynth/mt32.o \ softsynth/eas.o \ diff --git a/audio/mpu401.cpp b/audio/mpu401.cpp index 4834772c07..caad945258 100644 --- a/audio/mpu401.cpp +++ b/audio/mpu401.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "audio/mpu401.h" diff --git a/audio/mpu401.h b/audio/mpu401.h index 5f1a5108ac..15728a6d97 100644 --- a/audio/mpu401.h +++ b/audio/mpu401.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_MPU401_H diff --git a/audio/musicplugin.cpp b/audio/musicplugin.cpp index eb28d2f4c9..7c77c3455c 100644 --- a/audio/musicplugin.cpp +++ b/audio/musicplugin.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/musicplugin.h" diff --git a/audio/musicplugin.h b/audio/musicplugin.h index 53a2ae426d..2a25962b87 100644 --- a/audio/musicplugin.h +++ b/audio/musicplugin.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_MUSICPLUGIN_H diff --git a/audio/null.cpp b/audio/null.cpp index 2066a6d048..36c894aa7c 100644 --- a/audio/null.cpp +++ b/audio/null.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "common/error.h" diff --git a/audio/null.h b/audio/null.h index 8570d4d293..97c7c8cc93 100644 --- a/audio/null.h +++ b/audio/null.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_NULL_H diff --git a/audio/rate.cpp b/audio/rate.cpp index fd52503b8c..83abd6150b 100644 --- a/audio/rate.cpp +++ b/audio/rate.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/rate.h b/audio/rate.h index af37994d02..72bcbf48c5 100644 --- a/audio/rate.h +++ b/audio/rate.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_RATE_H diff --git a/audio/rate_arm.cpp b/audio/rate_arm.cpp index 1eb55d0dc3..433a7d3423 100644 --- a/audio/rate_arm.cpp +++ b/audio/rate_arm.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/rate_arm_asm.s b/audio/rate_arm_asm.s index 9431ae0649..d86d96267e 100644 --- a/audio/rate_arm_asm.s +++ b/audio/rate_arm_asm.s @@ -18,9 +18,6 @@ @ along with this program@ if not, write to the Free Software @ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @ -@ $URL$ -@ $Id$ -@ @ @author Robin Watts (robin@wss.co.uk) @ @ This file, together with rate_arm.cpp, provides an ARM optimised version diff --git a/audio/softsynth/adlib.cpp b/audio/softsynth/adlib.cpp index 9fec74c9d6..60de8fad60 100644 --- a/audio/softsynth/adlib.cpp +++ b/audio/softsynth/adlib.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "audio/softsynth/emumidi.h" diff --git a/audio/softsynth/appleiigs.cpp b/audio/softsynth/appleiigs.cpp index 80159c79ce..6ee70d1202 100644 --- a/audio/softsynth/appleiigs.cpp +++ b/audio/softsynth/appleiigs.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * -* $URL$ -* $Id$ -* */ #include "audio/null.h" diff --git a/audio/softsynth/cms.cpp b/audio/softsynth/cms.cpp index fcc15f127e..67eacd1a41 100644 --- a/audio/softsynth/cms.cpp +++ b/audio/softsynth/cms.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "audio/softsynth/cms.h" diff --git a/audio/softsynth/cms.h b/audio/softsynth/cms.h index d5bb7f0a42..48064746a8 100644 --- a/audio/softsynth/cms.h +++ b/audio/softsynth/cms.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_SOFTSYNTH_CMS_H diff --git a/audio/softsynth/eas.cpp b/audio/softsynth/eas.cpp index 7d17655d20..d829e3b39a 100644 --- a/audio/softsynth/eas.cpp +++ b/audio/softsynth/eas.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "common/scummsys.h" diff --git a/audio/softsynth/emumidi.h b/audio/softsynth/emumidi.h index 190b70c392..f3d7645f87 100644 --- a/audio/softsynth/emumidi.h +++ b/audio/softsynth/emumidi.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_SOFTSYNTH_EMUMIDI_H diff --git a/audio/softsynth/fluidsynth.cpp b/audio/softsynth/fluidsynth.cpp index a4877a4ec1..2451336784 100644 --- a/audio/softsynth/fluidsynth.cpp +++ b/audio/softsynth/fluidsynth.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "common/scummsys.h" diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.cpp b/audio/softsynth/fmtowns_pc98/towns_audio.cpp index 7b6658ab3a..786e3ee1d2 100644 --- a/audio/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_audio.cpp @@ -18,19 +18,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/softsynth/fmtowns_pc98/towns_audio.h" +#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" + #include "common/endian.h" #include "common/util.h" +#include "common/textconsole.h" #include "backends/audiocd/audiocd.h" class TownsAudio_PcmChannel { -friend class TownsAudioInterface; +friend class TownsAudioInterfaceInternal; public: TownsAudio_PcmChannel(); ~TownsAudio_PcmChannel(); @@ -80,7 +80,7 @@ private: }; class TownsAudio_WaveTable { -friend class TownsAudioInterface; +friend class TownsAudioInterfaceInternal; public: TownsAudio_WaveTable(); ~TownsAudio_WaveTable(); @@ -101,14 +101,170 @@ private: int8 *data; }; -TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), +class TownsAudioInterfaceInternal : public TownsPC98_FmSynth { +public: + TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false); + ~TownsAudioInterfaceInternal(); + + static TownsAudioInterfaceInternal *addNewRef(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false); + static void releaseRef(TownsAudioInterface *owner); + + bool init(); + + int callback(int command, ...); + int processCommand(int command, va_list &args); + + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); + // Defines the channels used as sound effect channels for the purpose of ScummVM GUI volume control. + // The first 6 bits are the 6 fm channels. The next 8 bits are pcm channels. + void setSoundEffectChanMask(int mask); + +private: + bool assignPluginDriver(TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false); + void removePluginDriver(TownsAudioInterface *owner); + + void nextTickEx(int32 *buffer, uint32 bufferSize); + + void timerCallbackA(); + void timerCallbackB(); + + typedef int (TownsAudioInterfaceInternal::*TownsAudioIntfCallback)(va_list &); + const TownsAudioIntfCallback *_intfOpcodes; + + int intf_reset(va_list &args); + int intf_keyOn(va_list &args); + int intf_keyOff(va_list &args); + int intf_setPanPos(va_list &args); + int intf_setInstrument(va_list &args); + int intf_loadInstrument(va_list &args); + int intf_setPitch(va_list &args); + int intf_setLevel(va_list &args); + int intf_chanOff(va_list &args); + int intf_writeReg(va_list &args); + int intf_writeRegBuffer(va_list &args); + int intf_readRegBuffer(va_list &args); + int intf_setTimerA(va_list &args); + int intf_setTimerB(va_list &args); + int intf_enableTimerA(va_list &args); + int intf_enableTimerB(va_list &args); + int intf_loadSamples(va_list &args); + int intf_reserveEffectChannels(va_list &args); + int intf_loadWaveTable(va_list &args); + int intf_unloadWaveTable(va_list &args); + int intf_pcmPlayEffect(va_list &args); + int intf_pcmChanOff(va_list &args); + int intf_pcmEffectPlaying(va_list &args); + int intf_fmKeyOn(va_list &args); + int intf_fmKeyOff(va_list &args); + int intf_fmSetPanPos(va_list &args); + int intf_fmSetInstrument(va_list &args); + int intf_fmLoadInstrument(va_list &args); + int intf_fmSetPitch(va_list &args); + int intf_fmSetLevel(va_list &args); + int intf_fmReset(va_list &args); + int intf_setOutputVolume(va_list &args); + int intf_resetOutputVolume(va_list &args); + int intf_getOutputVolume(va_list &args); + int intf_setOutputMute(va_list &args); + int intf_cdaToggle(va_list &args); + int intf_getOutputVolume2(va_list &args); + int intf_getOutputMute(va_list &args); + int intf_pcmUpdateEnvelopeGenerator(va_list &args); + + int intf_notImpl(va_list &args); + + void fmReset(); + int fmKeyOn(int chan, int note, int velo); + int fmKeyOff(int chan); + int fmChanOff(int chan); + int fmSetPanPos(int chan, int mode); + int fmSetInstrument(int chan, int instrId); + int fmLoadInstrument(int instrId, const uint8 *data); + int fmSetPitch(int chan, int pitch); + int fmSetLevel(int chan, int lvl); + + void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value); + + uint8 _fmChanPlaying; + uint8 _fmChanNote[6]; + int16 _fmChanPitch[6]; + + uint8 *_fmSaveReg[2]; + uint8 *_fmInstruments; + + void pcmReset(); + int pcmKeyOn(int chan, int note, int velo); + int pcmKeyOff(int chan); + int pcmChanOff(int chan); + int pcmSetPanPos(int chan, int mode); + int pcmSetInstrument(int chan, int instrId); + int pcmLoadInstrument(int instrId, const uint8 *data); + int pcmSetPitch(int chan, int pitch); + int pcmSetLevel(int chan, int lvl); + void pcmUpdateEnvelopeGenerator(int chan); + + TownsAudio_PcmChannel *_pcmChan; + uint8 _pcmChanOut; + uint8 _pcmChanReserved; + uint8 _pcmChanKeyPressed; + uint8 _pcmChanEffectPlaying; + uint8 _pcmChanKeyPlaying; + + uint8 _pcmChanNote[8]; + uint8 _pcmChanVelo[8]; + uint8 _pcmChanLevel[8]; + + uint8 _numReservedChannels; + uint8 *_pcmInstruments; + + TownsAudio_WaveTable *_waveTables; + uint8 _numWaveTables; + uint32 _waveTablesTotalDataSize; + + void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); + + void updateOutputVolume(); + void updateOutputVolumeInternal(); + uint8 _outputVolumeFlags; + uint8 _outputLevel[16]; + uint8 _outputMute[16]; + bool _updateOutputVol; + + const float _baserate; + uint32 _timerBase; + uint32 _tickLength; + uint32 _timer; + + uint16 _musicVolume; + uint16 _sfxVolume; + int _pcmSfxChanMask; + + TownsAudioInterfacePluginDriver *_drv; + void *_drvOwner; + bool _ready; + + static TownsAudioInterfaceInternal *_refInstance; + static int _refCount; + + static const uint8 _chanFlags[]; + static const uint16 _frequency[]; + static const uint8 _carrier[]; + static const uint8 _fmDefaultInstrument[]; + static const uint16 _pcmPhase1[]; + static const uint16 _pcmPhase2[]; +}; + +TownsAudioInterfaceInternal::TownsAudioInterfaceInternal(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) : + TownsPC98_FmSynth(mixer, kTypeTowns, externalMutexHandling), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _drvOwner(owner), _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), - _outputVolumeFlags(0), _outputMuteFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0), - _pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _ready(false) { + _outputVolumeFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0), + _pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _fmChanPlaying(0), + _numReservedChannels(0), _numWaveTables(0), _updateOutputVol(false), _ready(false) { -#define INTCB(x) &TownsAudioInterface::intf_##x +#define INTCB(x) &TownsAudioInterfaceInternal::intf_##x static const TownsAudioIntfCallback intfCb[] = { // 0 INTCB(reset), @@ -197,14 +353,14 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac INTCB(setOutputVolume), // 68 INTCB(resetOutputVolume), - INTCB(notImpl), - INTCB(updateOutputVolume), + INTCB(getOutputVolume), + INTCB(setOutputMute), INTCB(notImpl), // 72 INTCB(notImpl), INTCB(cdaToggle), - INTCB(notImpl), - INTCB(notImpl), + INTCB(getOutputVolume2), + INTCB(getOutputMute), // 76 INTCB(notImpl), INTCB(notImpl), @@ -219,16 +375,24 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac _intfOpcodes = intfCb; memset(_fmSaveReg, 0, sizeof(_fmSaveReg)); + memset(_fmChanNote, 0, sizeof(_fmChanNote)); + memset(_fmChanPitch, 0, sizeof(_fmChanPitch)); + memset(_pcmChanNote, 0, sizeof(_pcmChanNote)); + memset(_pcmChanVelo, 0, sizeof(_pcmChanVelo)); + memset(_pcmChanLevel, 0, sizeof(_pcmChanLevel)); memset(_outputLevel, 0, sizeof(_outputLevel)); + memset(_outputMute, 0, sizeof(_outputMute)); _timerBase = (uint32)(_baserate * 1000000.0f); _tickLength = 2 * _timerBase; } -TownsAudioInterface::~TownsAudioInterface() { +TownsAudioInterfaceInternal::~TownsAudioInterfaceInternal() { _ready = false; deinit(); + Common::StackLock lock(_mutex); + delete[] _fmSaveReg[0]; delete[] _fmSaveReg[1]; delete[] _fmInstruments; @@ -237,7 +401,34 @@ TownsAudioInterface::~TownsAudioInterface() { delete[] _pcmChan; } -bool TownsAudioInterface::init() { +TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::addNewRef(Audio::Mixer *mixer, TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) { + _refCount++; + if (_refCount == 1 && _refInstance == 0) + _refInstance = new TownsAudioInterfaceInternal(mixer, owner, driver, externalMutexHandling); + else if (_refCount < 2 || _refInstance == 0) + error("TownsAudioInterfaceInternal::addNewRef(): Internal reference management failure"); + else if (!_refInstance->assignPluginDriver(owner, driver, externalMutexHandling)) + error("TownsAudioInterfaceInternal::addNewRef(): Plugin driver conflict"); + + return _refInstance; +} + +void TownsAudioInterfaceInternal::releaseRef(TownsAudioInterface *owner) { + if (!_refCount) + return; + + _refCount--; + + if (_refCount) { + if (_refInstance) + _refInstance->removePluginDriver(owner); + } else { + delete _refInstance; + _refInstance = 0; + } +} + +bool TownsAudioInterfaceInternal::init() { if (_ready) return true; @@ -261,44 +452,79 @@ bool TownsAudioInterface::init() { return true; } -int TownsAudioInterface::callback(int command, ...) { +int TownsAudioInterfaceInternal::callback(int command, ...) { if (!_ready) return 1; va_list args; va_start(args, command); - if (command > 81) { - va_end(args); - return 4; - } + int res = processCommand(command, args); + + va_end(args); + return res; +} + +int TownsAudioInterfaceInternal::processCommand(int command, va_list &args) { + if (!_ready) + return 1; + if (command < 0 || command > 81) + return 4; + + Common::StackLock lock(_mutex); int res = (this->*_intfOpcodes[command])(args); - va_end(args); return res; } -void TownsAudioInterface::setMusicVolume(int volume) { +void TownsAudioInterfaceInternal::setMusicVolume(int volume) { _musicVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume); setVolumeIntern(_musicVolume, _sfxVolume); } -void TownsAudioInterface::setSoundEffectVolume(int volume) { +void TownsAudioInterfaceInternal::setSoundEffectVolume(int volume) { _sfxVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume); setVolumeIntern(_musicVolume, _sfxVolume); } -void TownsAudioInterface::setSoundEffectChanMask(int mask) { +void TownsAudioInterfaceInternal::setSoundEffectChanMask(int mask) { _pcmSfxChanMask = mask >> 6; mask &= 0x3f; setVolumeChannelMasks(~mask, mask); } -void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { +bool TownsAudioInterfaceInternal::assignPluginDriver(TownsAudioInterface *owner, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) { + if (_refCount <= 1) + return true; + + if (_drv) { + if (driver && driver != _drv) + return false; + } else { + Common::StackLock lock(_mutex); + _drv = driver; + _drvOwner = owner; + _externalMutex = externalMutexHandling; + } + + return true; +} + +void TownsAudioInterfaceInternal::removePluginDriver(TownsAudioInterface *owner) { + if (_drvOwner == owner) { + Common::StackLock lock(_mutex); + _drv = 0; + } +} + +void TownsAudioInterfaceInternal::nextTickEx(int32 *buffer, uint32 bufferSize) { if (!_ready) return; + if (_updateOutputVol) + updateOutputVolumeInternal(); + for (uint32 i = 0; i < bufferSize; i++) { _timer += _tickLength; while (_timer > 0x514767) { @@ -346,14 +572,12 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { } } -void TownsAudioInterface::timerCallbackA() { - Common::StackLock lock(_mutex); +void TownsAudioInterfaceInternal::timerCallbackA() { if (_drv && _ready) _drv->timerCallback(0); } -void TownsAudioInterface::timerCallbackB() { - Common::StackLock lock(_mutex); +void TownsAudioInterfaceInternal::timerCallbackB() { if (_ready) { if (_drv) _drv->timerCallback(1); @@ -361,62 +585,62 @@ void TownsAudioInterface::timerCallbackB() { } } -int TownsAudioInterface::intf_reset(va_list &args) { +int TownsAudioInterfaceInternal::intf_reset(va_list &args) { fmReset(); pcmReset(); callback(68); return 0; } -int TownsAudioInterface::intf_keyOn(va_list &args) { +int TownsAudioInterfaceInternal::intf_keyOn(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo); } -int TownsAudioInterface::intf_keyOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_keyOff(va_list &args) { int chan = va_arg(args, int); return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan); } -int TownsAudioInterface::intf_setPanPos(va_list &args) { +int TownsAudioInterfaceInternal::intf_setPanPos(va_list &args) { int chan = va_arg(args, int); int mode = va_arg(args, int); return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode); } -int TownsAudioInterface::intf_setInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_setInstrument(va_list &args) { int chan = va_arg(args, int); int instrId = va_arg(args, int); return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId); } -int TownsAudioInterface::intf_loadInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadInstrument(va_list &args) { int chanType = va_arg(args, int); int instrId = va_arg(args, int); uint8 *instrData = va_arg(args, uint8 *); return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData); } -int TownsAudioInterface::intf_setPitch(va_list &args) { +int TownsAudioInterfaceInternal::intf_setPitch(va_list &args) { int chan = va_arg(args, int); int16 pitch = (int16)(va_arg(args, int) & 0xffff); return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch); } -int TownsAudioInterface::intf_setLevel(va_list &args) { +int TownsAudioInterfaceInternal::intf_setLevel(va_list &args) { int chan = va_arg(args, int); int lvl = va_arg(args, int); return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl); } -int TownsAudioInterface::intf_chanOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_chanOff(va_list &args) { int chan = va_arg(args, int); return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan); } -int TownsAudioInterface::intf_writeReg(va_list &args) { +int TownsAudioInterfaceInternal::intf_writeReg(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); int val = va_arg(args, int); @@ -427,7 +651,7 @@ int TownsAudioInterface::intf_writeReg(va_list &args) { return 0; } -int TownsAudioInterface::intf_writeRegBuffer(va_list &args) { +int TownsAudioInterfaceInternal::intf_writeRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); int val = va_arg(args, int); @@ -439,7 +663,7 @@ int TownsAudioInterface::intf_writeRegBuffer(va_list &args) { return 0; } -int TownsAudioInterface::intf_readRegBuffer(va_list &args) { +int TownsAudioInterfaceInternal::intf_readRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); uint8 *dst = va_arg(args, uint8 *); @@ -452,7 +676,7 @@ int TownsAudioInterface::intf_readRegBuffer(va_list &args) { return 0; } -int TownsAudioInterface::intf_setTimerA(va_list &args) { +int TownsAudioInterfaceInternal::intf_setTimerA(va_list &args) { int enable = va_arg(args, int); int tempo = va_arg(args, int); @@ -467,7 +691,7 @@ int TownsAudioInterface::intf_setTimerA(va_list &args) { return 0; } -int TownsAudioInterface::intf_setTimerB(va_list &args) { +int TownsAudioInterfaceInternal::intf_setTimerB(va_list &args) { int enable = va_arg(args, int); int tempo = va_arg(args, int); @@ -481,17 +705,17 @@ int TownsAudioInterface::intf_setTimerB(va_list &args) { return 0; } -int TownsAudioInterface::intf_enableTimerA(va_list &args) { +int TownsAudioInterfaceInternal::intf_enableTimerA(va_list &args) { bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15); return 0; } -int TownsAudioInterface::intf_enableTimerB(va_list &args) { +int TownsAudioInterfaceInternal::intf_enableTimerB(va_list &args) { bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a); return 0; } -int TownsAudioInterface::intf_loadSamples(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadSamples(va_list &args) { uint32 dest = va_arg(args, uint32); int size = va_arg(args, int); uint8 *src = va_arg(args, uint8*); @@ -514,7 +738,7 @@ int TownsAudioInterface::intf_loadSamples(va_list &args) { return 0; } -int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { +int TownsAudioInterfaceInternal::intf_reserveEffectChannels(va_list &args) { int numChan = va_arg(args, int); if (numChan > 8) return 3; @@ -546,7 +770,7 @@ int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { return 0; } -int TownsAudioInterface::intf_loadWaveTable(va_list &args) { +int TownsAudioInterfaceInternal::intf_loadWaveTable(va_list &args) { uint8 *data = va_arg(args, uint8 *); if (_numWaveTables > 127) return 3; @@ -573,7 +797,7 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) { return 0; } -int TownsAudioInterface::intf_unloadWaveTable(va_list &args) { +int TownsAudioInterfaceInternal::intf_unloadWaveTable(va_list &args) { int id = va_arg(args, int); if (id == -1) { @@ -600,7 +824,7 @@ int TownsAudioInterface::intf_unloadWaveTable(va_list &args) { return 0; } -int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmPlayEffect(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); @@ -650,13 +874,13 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { return 0; } -int TownsAudioInterface::intf_pcmChanOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmChanOff(va_list &args) { int chan = va_arg(args, int); pcmChanOff(chan); return 0; } -int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) { +int TownsAudioInterfaceInternal::intf_pcmEffectPlaying(va_list &args) { int chan = va_arg(args, int); if (chan < 0x40 || chan > 0x47) return 1; @@ -664,54 +888,54 @@ int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) { return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0; } -int TownsAudioInterface::intf_fmKeyOn(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmKeyOn(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); return fmKeyOn(chan, note, velo); } -int TownsAudioInterface::intf_fmKeyOff(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmKeyOff(va_list &args) { int chan = va_arg(args, int); return fmKeyOff(chan); } -int TownsAudioInterface::intf_fmSetPanPos(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetPanPos(va_list &args) { int chan = va_arg(args, int); int mode = va_arg(args, int); return fmSetPanPos(chan, mode); } -int TownsAudioInterface::intf_fmSetInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetInstrument(va_list &args) { int chan = va_arg(args, int); int instrId = va_arg(args, int); return fmSetInstrument(chan, instrId); } -int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmLoadInstrument(va_list &args) { int instrId = va_arg(args, int); uint8 *instrData = va_arg(args, uint8 *); return fmLoadInstrument(instrId, instrData); } -int TownsAudioInterface::intf_fmSetPitch(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetPitch(va_list &args) { int chan = va_arg(args, int); uint16 freq = va_arg(args, int) & 0xffff; return fmSetPitch(chan, freq); } -int TownsAudioInterface::intf_fmSetLevel(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmSetLevel(va_list &args) { int chan = va_arg(args, int); int lvl = va_arg(args, int); return fmSetLevel(chan, lvl); } -int TownsAudioInterface::intf_fmReset(va_list &args) { +int TownsAudioInterfaceInternal::intf_fmReset(va_list &args) { fmReset(); return 0; } -int TownsAudioInterface::intf_setOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_setOutputVolume(va_list &args) { int chanType = va_arg(args, int); int left = va_arg(args, int); int right = va_arg(args, int); @@ -727,18 +951,20 @@ int TownsAudioInterface::intf_setOutputVolume(va_list &args) { left = (left & 0x7e) >> 1; right = (right & 0x7e) >> 1; - if (chan) + if (chan == 12) _outputVolumeFlags |= flags[chanType]; else _outputVolumeFlags &= ~flags[chanType]; if (chanType > 1) { _outputLevel[chan + chanType] = left; + _outputMute[chan + chanType] = 0; } else { if (chanType == 0) chan -= 8; _outputLevel[chan] = left; _outputLevel[chan + 1] = right; + _outputMute[chan] = _outputMute[chan + 1] = 0; } updateOutputVolume(); @@ -746,38 +972,87 @@ int TownsAudioInterface::intf_setOutputVolume(va_list &args) { return 0; } -int TownsAudioInterface::intf_resetOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_resetOutputVolume(va_list &args) { memset(_outputLevel, 0, sizeof(_outputLevel)); - _outputMuteFlags = 0; _outputVolumeFlags = 0; updateOutputVolume(); return 0; } -int TownsAudioInterface::intf_updateOutputVolume(va_list &args) { +int TownsAudioInterfaceInternal::intf_getOutputVolume(va_list &args) { + int chanType = va_arg(args, int); + int *left = va_arg(args, int*); + int *right = va_arg(args, int*); + + uint8 chan = (chanType & 0x40) ? 8 : 12; + chanType &= 3; + + if (chanType > 1) { + *left = _outputLevel[chan + chanType] & 0x3f; + } else { + if (chanType == 0) + chan -= 8; + *left = _outputLevel[chan] & 0x3f; + *right = _outputLevel[chan + 1] & 0x3f; + } + + return 0; +} + +int TownsAudioInterfaceInternal::intf_setOutputMute(va_list &args) { int flags = va_arg(args, int); - _outputMuteFlags = flags & 3; + _outputVolumeFlags = flags; + uint8 mute = flags & 3; + uint8 f = flags & 0xff; + + memset(_outputMute, 1, 8); + if (mute & 2) + memset(&_outputMute[12], 1, 4); + if (mute & 1) + memset(&_outputMute[8], 1, 4); + + _outputMute[(f < 0x80) ? 11 : 15] = 0; + f += f; + _outputMute[(f < 0x80) ? 10 : 14] = 0; + f += f; + _outputMute[(f < 0x80) ? 8 : 12] = 0; + f += f; + _outputMute[(f < 0x80) ? 9 : 13] = 0; + f += f; + _outputMute[(f < 0x80) ? 0 : 4] = 0; + f += f; + _outputMute[(f < 0x80) ? 1 : 5] = 0; + f += f; + updateOutputVolume(); return 0; } -int TownsAudioInterface::intf_cdaToggle(va_list &args) { +int TownsAudioInterfaceInternal::intf_cdaToggle(va_list &args) { //int mode = va_arg(args, int); //_unkMask = mode ? 0x7f : 0x3f; return 0; } -int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { +int TownsAudioInterfaceInternal::intf_getOutputVolume2(va_list &args) { + return 0; +} + +int TownsAudioInterfaceInternal::intf_getOutputMute (va_list &args) { + return 0; +} + +int TownsAudioInterfaceInternal::intf_pcmUpdateEnvelopeGenerator(va_list &args) { for (int i = 0; i < 8; i++) pcmUpdateEnvelopeGenerator(i); return 0; } -int TownsAudioInterface::intf_notImpl(va_list &args) { +int TownsAudioInterfaceInternal::intf_notImpl(va_list &args) { return 4; } -void TownsAudioInterface::fmReset() { +void TownsAudioInterfaceInternal::fmReset() { TownsPC98_FmSynth::reset(); _fmChanPlaying = 0; @@ -805,7 +1080,7 @@ void TownsAudioInterface::fmReset() { } } -int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { +int TownsAudioInterfaceInternal::fmKeyOn(int chan, int note, int velo) { if (chan > 5) return 1; if (note < 12 || note > 107 || (velo & 0x80)) @@ -885,7 +1160,7 @@ int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { return 0; } -int TownsAudioInterface::fmKeyOff(int chan) { +int TownsAudioInterfaceInternal::fmKeyOff(int chan) { if (chan > 5) return 1; _fmChanPlaying &= ~_chanFlags[chan]; @@ -895,7 +1170,7 @@ int TownsAudioInterface::fmKeyOff(int chan) { return 0; } -int TownsAudioInterface::fmChanOff(int chan) { +int TownsAudioInterfaceInternal::fmChanOff(int chan) { if (chan > 5) return 1; _fmChanPlaying &= ~_chanFlags[chan]; @@ -913,7 +1188,7 @@ int TownsAudioInterface::fmChanOff(int chan) { return 0; } -int TownsAudioInterface::fmSetPanPos(int chan, int value) { +int TownsAudioInterfaceInternal::fmSetPanPos(int chan, int value) { if (chan > 5) return 1; @@ -932,7 +1207,7 @@ int TownsAudioInterface::fmSetPanPos(int chan, int value) { return 0; } -int TownsAudioInterface::fmSetInstrument(int chan, int instrId) { +int TownsAudioInterfaceInternal::fmSetInstrument(int chan, int instrId) { if (chan > 5) return 1; if (instrId > 127) @@ -976,7 +1251,7 @@ int TownsAudioInterface::fmSetInstrument(int chan, int instrId) { return 0; } -int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) { +int TownsAudioInterfaceInternal::fmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 127) return 3; assert(data); @@ -984,7 +1259,7 @@ int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) { return 0; } -int TownsAudioInterface::fmSetPitch(int chan, int pitch) { +int TownsAudioInterfaceInternal::fmSetPitch(int chan, int pitch) { if (chan > 5) return 1; @@ -1071,7 +1346,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { return 0; } -int TownsAudioInterface::fmSetLevel(int chan, int lvl) { +int TownsAudioInterfaceInternal::fmSetLevel(int chan, int lvl) { if (chan > 5) return 1; if (lvl > 127) @@ -1094,12 +1369,12 @@ int TownsAudioInterface::fmSetLevel(int chan, int lvl) { return 0; } -void TownsAudioInterface::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { +void TownsAudioInterfaceInternal::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { _fmSaveReg[part][regAddress] = value; writeReg(part, regAddress, value); } -void TownsAudioInterface::pcmReset() { +void TownsAudioInterfaceInternal::pcmReset() { _pcmChanOut = 0; _pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0; _numReservedChannels = 0; @@ -1127,7 +1402,7 @@ void TownsAudioInterface::pcmReset() { } } -int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { +int TownsAudioInterfaceInternal::pcmKeyOn(int chan, int note, int velo) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1198,7 +1473,7 @@ int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { return 0; } -int TownsAudioInterface::pcmKeyOff(int chan) { +int TownsAudioInterfaceInternal::pcmKeyOff(int chan) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1208,7 +1483,7 @@ int TownsAudioInterface::pcmKeyOff(int chan) { return 0; } -int TownsAudioInterface::pcmChanOff(int chan) { +int TownsAudioInterfaceInternal::pcmChanOff(int chan) { if (chan < 0x40 || chan > 0x47) return 1; @@ -1222,7 +1497,7 @@ int TownsAudioInterface::pcmChanOff(int chan) { return 0; } -int TownsAudioInterface::pcmSetPanPos(int chan, int mode) { +int TownsAudioInterfaceInternal::pcmSetPanPos(int chan, int mode) { if (chan > 0x47) return 1; if (mode & 0x80) @@ -1245,7 +1520,7 @@ int TownsAudioInterface::pcmSetPanPos(int chan, int mode) { return 0; } -int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) { +int TownsAudioInterfaceInternal::pcmSetInstrument(int chan, int instrId) { if (chan > 0x47) return 1; if (instrId > 31) @@ -1255,7 +1530,7 @@ int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) { return 0; } -int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) { +int TownsAudioInterfaceInternal::pcmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 31) return 3; assert(data); @@ -1263,7 +1538,7 @@ int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) { return 0; } -int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { +int TownsAudioInterfaceInternal::pcmSetPitch(int chan, int pitch) { if (chan > 0x47) return 1; @@ -1293,7 +1568,7 @@ int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { return 0; } -int TownsAudioInterface::pcmSetLevel(int chan, int lvl) { +int TownsAudioInterfaceInternal::pcmSetLevel(int chan, int lvl) { if (chan > 0x47) return 1; @@ -1322,7 +1597,7 @@ int TownsAudioInterface::pcmSetLevel(int chan, int lvl) { return 0; } -void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) { +void TownsAudioInterfaceInternal::pcmUpdateEnvelopeGenerator(int chan) { TownsAudio_PcmChannel *p = &_pcmChan[chan]; if (!p->envCurrentLevel) { _pcmChanKeyPlaying &= ~_chanFlags[chan]; @@ -1364,7 +1639,7 @@ void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) { p->velo = (p->envCurrentLevel >> 8) << 1; } -void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { +void TownsAudioInterfaceInternal::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { int8 diff = p->note - w->baseNote; uint16 r = w->rate + w->rateOffs; uint16 bl = 0; @@ -1393,45 +1668,60 @@ void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_ p->step = (s * p->stepPitch) >> 14; } -void TownsAudioInterface::updateOutputVolume() { +void TownsAudioInterfaceInternal::updateOutputVolume() { + // Avoid calls to g_system->getAudioCDManager() functions from the main thread + // since this can cause mutex lockups. + _updateOutputVol = true; +} + +void TownsAudioInterfaceInternal::updateOutputVolumeInternal() { + if (!_ready) + return; + // FM Towns seems to support volumes of 0 - 63 for each channel. // We recalculate sane values for our 0 to 255 volume range and // balance values for our -128 to 127 volume range // CD-AUDIO - uint32 maxVol = MAX(_outputLevel[12], _outputLevel[13]); + uint32 maxVol = MAX(_outputLevel[12] * (_outputMute[12] ^ 1), _outputLevel[13] * (_outputMute[13] ^ 1)); int volume = (int)(((float)(maxVol * 255) / 63.0f)); - int balance = maxVol ? (int)( ( ((int)_outputLevel[13] - _outputLevel[12]) * 127) / (float)maxVol) : 0; + int balance = maxVol ? (int)( ( ((int)_outputLevel[13] * (_outputMute[13] ^ 1) - _outputLevel[12] * (_outputMute[12] ^ 1)) * 127) / (float)maxVol) : 0; g_system->getAudioCDManager()->setVolume(volume); g_system->getAudioCDManager()->setBalance(balance); + + _updateOutputVol = false; } -const uint8 TownsAudioInterface::_chanFlags[] = { +TownsAudioInterfaceInternal *TownsAudioInterfaceInternal::_refInstance = 0; + +int TownsAudioInterfaceInternal::_refCount = 0; + +const uint8 TownsAudioInterfaceInternal::_chanFlags[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; -const uint16 TownsAudioInterface::_frequency[] = { +const uint16 TownsAudioInterfaceInternal::_frequency[] = { 0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0 }; -const uint8 TownsAudioInterface::_carrier[] = { +const uint8 TownsAudioInterfaceInternal::_carrier[] = { 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0 }; -const uint8 TownsAudioInterface::_fmDefaultInstrument[] = { +const uint8 TownsAudioInterfaceInternal::_fmDefaultInstrument[] = { 0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01, 0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08, 0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -const uint16 TownsAudioInterface::_pcmPhase1[] = { +const uint16 TownsAudioInterfaceInternal::_pcmPhase1[] = { 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 }; -const uint16 TownsAudioInterface::_pcmPhase2[] = { +const uint16 TownsAudioInterfaceInternal::_pcmPhase2[] = { 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC }; @@ -1582,3 +1872,37 @@ void TownsAudio_WaveTable::clear() { data = 0; } +TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling) { + _intf = TownsAudioInterfaceInternal::addNewRef(mixer, this, driver, externalMutexHandling); +} + +TownsAudioInterface::~TownsAudioInterface() { + TownsAudioInterfaceInternal::releaseRef(this); + _intf = 0; +} + +bool TownsAudioInterface::init() { + return _intf->init(); +} + +int TownsAudioInterface::callback(int command, ...) { + va_list args; + va_start(args, command); + + int res = _intf->processCommand(command, args); + + va_end(args); + return res; +} + +void TownsAudioInterface::setMusicVolume(int volume) { + _intf->setMusicVolume(volume); +} + +void TownsAudioInterface::setSoundEffectVolume(int volume) { + _intf->setSoundEffectVolume(volume); +} + +void TownsAudioInterface::setSoundEffectChanMask(int mask) { + _intf->setSoundEffectChanMask(mask); +} diff --git a/audio/softsynth/fmtowns_pc98/towns_audio.h b/audio/softsynth/fmtowns_pc98/towns_audio.h index 2819ab2d57..4af888f009 100644 --- a/audio/softsynth/fmtowns_pc98/towns_audio.h +++ b/audio/softsynth/fmtowns_pc98/towns_audio.h @@ -18,15 +18,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef TOWNS_AUDIO_H #define TOWNS_AUDIO_H -#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +#include "audio/mixer.h" + +class TownsAudioInterfaceInternal; class TownsAudioInterfacePluginDriver { public: @@ -34,12 +33,9 @@ public: virtual void timerCallback(int timerId) = 0; }; -class TownsAudio_PcmChannel; -class TownsAudio_WaveTable; - -class TownsAudioInterface : public TownsPC98_FmSynth { +class TownsAudioInterface { public: - TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); + TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver, bool externalMutexHandling = false); ~TownsAudioInterface(); bool init(); @@ -53,126 +49,7 @@ public: void setSoundEffectChanMask(int mask); private: - void nextTickEx(int32 *buffer, uint32 bufferSize); - - void timerCallbackA(); - void timerCallbackB(); - - typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list &); - const TownsAudioIntfCallback *_intfOpcodes; - - int intf_reset(va_list &args); - int intf_keyOn(va_list &args); - int intf_keyOff(va_list &args); - int intf_setPanPos(va_list &args); - int intf_setInstrument(va_list &args); - int intf_loadInstrument(va_list &args); - int intf_setPitch(va_list &args); - int intf_setLevel(va_list &args); - int intf_chanOff(va_list &args); - int intf_writeReg(va_list &args); - int intf_writeRegBuffer(va_list &args); - int intf_readRegBuffer(va_list &args); - int intf_setTimerA(va_list &args); - int intf_setTimerB(va_list &args); - int intf_enableTimerA(va_list &args); - int intf_enableTimerB(va_list &args); - int intf_loadSamples(va_list &args); - int intf_reserveEffectChannels(va_list &args); - int intf_loadWaveTable(va_list &args); - int intf_unloadWaveTable(va_list &args); - int intf_pcmPlayEffect(va_list &args); - int intf_pcmChanOff(va_list &args); - int intf_pcmEffectPlaying(va_list &args); - int intf_fmKeyOn(va_list &args); - int intf_fmKeyOff(va_list &args); - int intf_fmSetPanPos(va_list &args); - int intf_fmSetInstrument(va_list &args); - int intf_fmLoadInstrument(va_list &args); - int intf_fmSetPitch(va_list &args); - int intf_fmSetLevel(va_list &args); - int intf_fmReset(va_list &args); - int intf_setOutputVolume(va_list &args); - int intf_resetOutputVolume(va_list &args); - int intf_updateOutputVolume(va_list &args); - int intf_cdaToggle(va_list &args); - int intf_pcmUpdateEnvelopeGenerator(va_list &args); - - int intf_notImpl(va_list &args); - - void fmReset(); - int fmKeyOn(int chan, int note, int velo); - int fmKeyOff(int chan); - int fmChanOff(int chan); - int fmSetPanPos(int chan, int mode); - int fmSetInstrument(int chan, int instrId); - int fmLoadInstrument(int instrId, const uint8 *data); - int fmSetPitch(int chan, int pitch); - int fmSetLevel(int chan, int lvl); - - void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value); - - uint8 _fmChanPlaying; - uint8 _fmChanNote[6]; - int16 _fmChanPitch[6]; - - uint8 *_fmSaveReg[2]; - uint8 *_fmInstruments; - - void pcmReset(); - int pcmKeyOn(int chan, int note, int velo); - int pcmKeyOff(int chan); - int pcmChanOff(int chan); - int pcmSetPanPos(int chan, int mode); - int pcmSetInstrument(int chan, int instrId); - int pcmLoadInstrument(int instrId, const uint8 *data); - int pcmSetPitch(int chan, int pitch); - int pcmSetLevel(int chan, int lvl); - void pcmUpdateEnvelopeGenerator(int chan); - - TownsAudio_PcmChannel *_pcmChan; - uint8 _pcmChanOut; - uint8 _pcmChanReserved; - uint8 _pcmChanKeyPressed; - uint8 _pcmChanEffectPlaying; - uint8 _pcmChanKeyPlaying; - - uint8 _pcmChanNote[8]; - uint8 _pcmChanVelo[8]; - uint8 _pcmChanLevel[8]; - - uint8 _numReservedChannels; - uint8 *_pcmInstruments; - - TownsAudio_WaveTable *_waveTables; - uint8 _numWaveTables; - uint32 _waveTablesTotalDataSize; - - void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); - - void updateOutputVolume(); - uint8 _outputVolumeFlags; - uint8 _outputLevel[16]; - uint8 _outputMuteFlags; - - const float _baserate; - uint32 _timerBase; - uint32 _tickLength; - uint32 _timer; - - uint16 _musicVolume; - uint16 _sfxVolume; - int _pcmSfxChanMask; - - TownsAudioInterfacePluginDriver *_drv; - bool _ready; - - static const uint8 _chanFlags[]; - static const uint16 _frequency[]; - static const uint8 _carrier[]; - static const uint8 _fmDefaultInstrument[]; - static const uint16 _pcmPhase1[]; - static const uint16 _pcmPhase2[]; + TownsAudioInterfaceInternal *_intf; }; #endif diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp index cd3a348b85..bc2c88b236 100644 --- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/softsynth/fmtowns_pc98/towns_euphony.h" @@ -31,7 +28,8 @@ TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0), _assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0), _tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0), - _tempoControlMode(0) { + _tempoControlMode(0), _timerSetting(0), _tempoDiff(0), _timeStampBase(0), _elapsedEvents(0), _loop(false), + _endOfTrack(false), _suspendParsing(false), _musicTrackSize(0) { _para[0] = _para[1] = 0; _intf = new TownsAudioInterface(mixer, this); resetTempo(); @@ -84,7 +82,7 @@ void TownsEuphonyDriver::reset() { _intf->callback(0); _intf->callback(74); - _intf->callback(70); + _intf->callback(70, 0); _intf->callback(75, 3); setTimerA(true, 1); @@ -223,21 +221,21 @@ void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) { _intf->callback(67, mode, volLeft, volRight); } -int TownsEuphonyDriver::chanEnable(int tableEntry, int val) { +int TownsEuphonyDriver::configChan_enable(int tableEntry, int val) { if (tableEntry > 31) return 3; _tEnable[tableEntry] = val; return 0; } -int TownsEuphonyDriver::chanMode(int tableEntry, int val) { +int TownsEuphonyDriver::configChan_setMode(int tableEntry, int val) { if (tableEntry > 31) return 3; _tMode[tableEntry] = val; return 0; } -int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) { +int TownsEuphonyDriver::configChan_remap(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val < 16) @@ -245,7 +243,7 @@ int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) { return 0; } -int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) { +int TownsEuphonyDriver::configChan_adjustVolume(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) @@ -253,7 +251,7 @@ int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) { return 0; } -int TownsEuphonyDriver::chanNoteShift(int tableEntry, int val) { +int TownsEuphonyDriver::configChan_setTranspose(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) @@ -675,8 +673,8 @@ bool TownsEuphonyDriver::evtSetupNote() { uint8 velo = _musicPos[5]; sendEvent(mode, evt); - sendEvent(mode, applyNoteShift(note)); - sendEvent(mode, applyVolumeShift(velo)); + sendEvent(mode, applyTranspose(note)); + sendEvent(mode, applyVolumeAdjust(velo)); jumpNextLoop(); if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) @@ -715,7 +713,7 @@ bool TownsEuphonyDriver::evtPolyphonicAftertouch() { uint8 mode = _tMode[_musicPos[1]]; sendEvent(mode, evt); - sendEvent(mode, applyNoteShift(_musicPos[4])); + sendEvent(mode, applyTranspose(_musicPos[4])); sendEvent(mode, _musicPos[5]); return false; @@ -783,7 +781,7 @@ bool TownsEuphonyDriver::evtModeOrdrChange() { return false; } -uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) { +uint8 TownsEuphonyDriver::applyTranspose(uint8 in) { int out = _tTranspose[_musicPos[1]]; if (!out) return in; @@ -798,7 +796,7 @@ uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) { return out & 0xff; } -uint8 TownsEuphonyDriver::applyVolumeShift(uint8 in) { +uint8 TownsEuphonyDriver::applyVolumeAdjust(uint8 in) { int out = _tLevel[_musicPos[1]]; out += (in & 0x7f); out = CLIP(out, 1, 127); diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h index dc40373913..6b30bfb7f5 100644 --- a/audio/softsynth/fmtowns_pc98/towns_euphony.h +++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef TOWNS_EUP_H @@ -58,11 +55,11 @@ public: void setOutputVolume(int chanType, int volLeft, int volRight); - int chanEnable(int tableEntry, int val); - int chanMode(int tableEntry, int val); - int chanOrdr(int tableEntry, int val); - int chanVolumeShift(int tableEntry, int val); - int chanNoteShift(int tableEntry, int val); + int configChan_enable(int tableEntry, int val); + int configChan_setMode(int tableEntry, int val); + int configChan_remap(int tableEntry, int val); + int configChan_adjustVolume(int tableEntry, int val); + int configChan_setTranspose(int tableEntry, int val); int assignChannel(int chan, int tableEntry); @@ -114,8 +111,8 @@ private: return false; } - uint8 applyNoteShift(uint8 in); - uint8 applyVolumeShift(uint8 in); + uint8 applyTranspose(uint8 in); + uint8 applyVolumeAdjust(uint8 in); void sendNoteOff(); void sendNoteOn(); diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp new file mode 100644 index 0000000000..4617b0555c --- /dev/null +++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp @@ -0,0 +1,1043 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "audio/softsynth/fmtowns_pc98/towns_midi.h" +#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +#include "common/textconsole.h" +#include "common/system.h" + +class TownsMidiOutputChannel { +friend class TownsMidiInputChannel; +public: + TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanId); + ~TownsMidiOutputChannel(); + + void noteOn(uint8 msb, uint16 lsb); + void noteOnPitchBend(uint8 msb, uint16 lsb); + void setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara); + void setupEffects(int index, uint8 flags, const uint8 *effectData); + void setModWheel(uint8 value); + + void connect(TownsMidiInputChannel *chan); + void disconnect(); + + bool update(); + + enum CheckPriorityStatus { + kDisconnected = -2, + kHighPriority = -1 + }; + + int checkPriority(int pri); + +private: + struct EffectEnvelope { + uint8 state; + int32 currentLevel; + int32 duration; + int32 maxLevel; + int32 startLevel; + uint8 loop; + uint8 stateTargetLevels[4]; + uint8 stateModWheelLevels[4]; + int8 modWheelSensitivity; + int8 modWheelState; + int8 modWheelLast; + uint16 numSteps; + uint32 stepCounter; + int32 incrPerStep; + int8 dir; + uint32 incrPerStepRem; + uint32 incrCountRem; + } *_effectEnvelopes; + + struct EffectDef { + int32 phase; + uint8 type; + uint8 useModWheel; + uint8 loopRefresh; + EffectEnvelope *s; + } *_effectDefs; + + void startEffect(EffectEnvelope *s, const uint8 *effectData); + void updateEffectGenerator(EffectEnvelope *s, EffectDef *d); + int advanceEffectEnvelope(EffectEnvelope *s, EffectDef *d); + void initNextEnvelopeState(EffectEnvelope *s); + int16 getEffectStartLevel(uint8 type); + int getEffectModLevel(int lvl, int mod); + + void keyOn(); + void keyOff(); + void keyOnSetFreq(uint16 frq); + void out(uint8 reg, uint8 val); + + TownsMidiInputChannel *_in; + TownsMidiOutputChannel *_prev; + TownsMidiOutputChannel *_next; + uint8 _adjustModTl; + uint8 _chan; + uint8 _note; + uint8 _operator2Tl; + uint8 _operator1Tl; + uint8 _sustainNoteOff; + int16 _duration; + + uint16 _freq; + int16 _freqAdjust; + + MidiDriver_TOWNS *_driver; + + static const uint8 _chanMap[]; + static const uint8 _chanMap2[]; + static const uint8 _effectDefaults[]; + static const uint16 _effectEnvStepTable[]; + static const uint8 _freqMSB[]; + static const uint16 _freqLSB[]; +}; + +class TownsMidiInputChannel : public MidiChannel { +friend class TownsMidiOutputChannel; +public: + TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex); + ~TownsMidiInputChannel(); + + MidiDriver *device() { return _driver; } + byte getNumber() { return _chanIndex; } + bool allocate(); + void release(); + + void send(uint32 b); + + void noteOff(byte note); + void noteOn(byte note, byte velocity); + void programChange(byte program); + void pitchBend(int16 bend); + void controlChange(byte control, byte value); + void pitchBendFactor(byte value); + void priority(byte value); + void sysEx_customInstrument(uint32 type, const byte *instr); + +private: + void controlModulationWheel(byte value); + void controlVolume(byte value); + void controlPanPos(byte value); + void controlSustain(byte value); + + void releasePedal(); + + TownsMidiOutputChannel *_out; + + uint8 *_instrument; + uint8 _prg; + uint8 _chanIndex; + uint8 _effectLevel; + uint8 _priority; + uint8 _ctrlVolume; + uint8 _tl; + uint8 _pan; + uint8 _panEff; + uint8 _percS; + int8 _transpose; + uint8 _fld_1f; + int8 _detune; + int8 _modWheel; + uint8 _sustain; + uint8 _pitchBendFactor; + int16 _pitchBend; + uint16 _freqLSB; + + bool _allocated; + + MidiDriver_TOWNS *_driver; + + static const uint8 _programAdjustLevel[]; +}; + +class TownsMidiChanState { +public: + TownsMidiChanState(); + ~TownsMidiChanState() {} + uint8 get(uint8 type); + + uint8 unk1; + uint8 mulAmsFms; + uint8 tl; + uint8 attDec; + uint8 sus; + uint8 fgAlg; + uint8 unk2; +}; + +TownsMidiChanState::TownsMidiChanState() { + unk1 = mulAmsFms = tl = attDec = sus = fgAlg = unk2 = 0; +} + +uint8 TownsMidiChanState::get(uint8 type) { + switch (type) { + case 0: + return unk1; + case 1: + return mulAmsFms; + case 2: + return tl; + case 3: + return attDec; + case 4: + return sus; + case 5: + return fgAlg; + case 6: + return unk2; + default: + break; + } + return 0; +} + +TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex), + _in(0), _prev(0), _next(0), _adjustModTl(0), _operator2Tl(0), _note(0), _operator1Tl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) { + _effectEnvelopes = new EffectEnvelope[2]; + _effectDefs = new EffectDef[2]; + + memset(_effectEnvelopes, 0, 2 * sizeof(EffectEnvelope)); + memset(_effectDefs, 0, 2 * sizeof(EffectDef)); + _effectDefs[0].s = &_effectEnvelopes[1]; + _effectDefs[1].s = &_effectEnvelopes[0]; +} + +TownsMidiOutputChannel::~TownsMidiOutputChannel() { + delete[] _effectEnvelopes; + delete[] _effectDefs; +} + +void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) { + _freq = (msb << 7) + lsb; + _freqAdjust = 0; + keyOnSetFreq(_freq); +} + +void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) { + _freq = (msb << 7) + lsb; + keyOnSetFreq(_freq + _freqAdjust); +} + +void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara) { + // This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7), + // since it is just a modified AdLib driver. It also uses AdLib programs. + // There are no FM-TOWNS specific programs. This is the reason for the low quality of the FM-TOWNS + // music (unsuitable data is just forced into the wrong audio device). + + static const uint8 mul[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 }; + uint8 chan = _chanMap[_chan]; + + uint8 mulAmsFms1 = _driver->_chanState[chan].mulAmsFms = data[0]; + uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - mLevelPara; + uint8 attDec1 = _driver->_chanState[chan].attDec = ~data[2]; + uint8 sus1 = _driver->_chanState[chan].sus = ~data[3]; + _driver->_chanState[chan].unk2 = data[4]; + chan += 3; + + out(0x30, mul[mulAmsFms1 & 0x0f]); + out(0x40, (tl1 & 0x3f) + 15); + out(0x50, ((attDec1 >> 4) << 1) | ((attDec1 >> 4) & 1)); + out(0x60, ((attDec1 << 1) | (attDec1 & 1)) & 0x1f); + out(0x70, (mulAmsFms1 & 0x20) ^ 0x20 ? (((sus1 & 0x0f) << 1) | 1) : 0); + out(0x80, sus1); + + uint8 mulAmsFms2 = _driver->_chanState[chan].mulAmsFms = data[5]; + uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - tLevelPara; + uint8 attDec2 = _driver->_chanState[chan].attDec = ~data[7]; + uint8 sus2 = _driver->_chanState[chan].sus = ~data[8]; + _driver->_chanState[chan].unk2 = data[9]; + + uint8 mul2 = mul[mulAmsFms2 & 0x0f]; + tl2 = (tl2 & 0x3f) + 15; + uint8 ar2 = ((attDec2 >> 4) << 1) | ((attDec2 >> 4) & 1); + uint8 dec2 = ((attDec2 << 1) | (attDec2 & 1)) & 0x1f; + uint8 sus2r = (mulAmsFms2 & 0x20) ^ 0x20 ? (((sus2 & 0x0f) << 1) | 1) : 0; + + for (int i = 4; i < 16; i += 4) { + out(0x30 + i, mul2); + out(0x40 + i, tl2); + out(0x50 + i, ar2); + out(0x60 + i, dec2); + out(0x70 + i, sus2r); + out(0x80 + i, sus2); + } + + _driver->_chanState[chan].fgAlg = data[10]; + + uint8 alg = 5 + 2 * (data[10] & 1); + uint8 fb = 4 * (data[10] & 0x0e); + out(0xb0, fb | alg); + uint8 t = mulAmsFms1 | mulAmsFms2; + out(0xb4, (0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5))); +} + +void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) { + uint16 effectMaxLevel[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F }; + uint8 effectType[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 }; + + EffectEnvelope *s = &_effectEnvelopes[index]; + EffectDef *d = &_effectDefs[index]; + + d->phase = 0; + d->useModWheel = flags & 0x40; + s->loop = flags & 0x20; + d->loopRefresh = flags & 0x10; + d->type = effectType[flags & 0x0f]; + s->maxLevel = effectMaxLevel[flags & 0x0f]; + s->modWheelSensitivity = 31; + s->modWheelState = d->useModWheel ? _in->_modWheel >> 2 : 31; + + switch (d->type) { + case 0: + s->startLevel = _operator2Tl; + break; + case 13: + s->startLevel = _operator1Tl; + break; + case 30: + s->startLevel = 31; + d->s->modWheelState = 0; + break; + case 31: + s->startLevel = 0; + d->s->modWheelSensitivity = 0; + break; + default: + s->startLevel = getEffectStartLevel(d->type); + break; + } + + startEffect(s, effectData); +} + +void TownsMidiOutputChannel::setModWheel(uint8 value) { + if (_effectEnvelopes[0].state != kEnvReady && _effectDefs[0].type) + _effectEnvelopes[0].modWheelState = value >> 2; + + if (_effectEnvelopes[1].state != kEnvReady && _effectDefs[1].type) + _effectEnvelopes[1].modWheelState = value >> 2; +} + +void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) { + if (!chan) + return; + + _in = chan; + _next = chan->_out; + _prev = 0; + chan->_out = this; + if (_next) + _next->_prev = this; +} + +void TownsMidiOutputChannel::disconnect() { + keyOff(); + + TownsMidiOutputChannel *p = _prev; + TownsMidiOutputChannel *n = _next; + + if (n) + n->_prev = p; + if (p) + p->_next = n; + else + _in->_out = n; + _in = 0; +} + +bool TownsMidiOutputChannel::update() { + if (!_in) + return false; + + if (_duration) { + _duration -= 17; + if (_duration <= 0) { + disconnect(); + return true; + } + } + + for (int i = 0; i < 2; i++) { + if (_effectEnvelopes[i].state != kEnvReady) + updateEffectGenerator(&_effectEnvelopes[i], &_effectDefs[i]); + } + + return false; +} + +int TownsMidiOutputChannel::checkPriority(int pri) { + if (!_in) + return kDisconnected; + + if (!_next && pri >= _in->_priority) + return _in->_priority; + + return kHighPriority; +} + +void TownsMidiOutputChannel::startEffect(EffectEnvelope *s, const uint8 *effectData) { + s->state = kEnvAttacking; + s->currentLevel = 0; + s->modWheelLast = 31; + s->duration = effectData[0] * 63; + s->stateTargetLevels[0] = effectData[1]; + s->stateTargetLevels[1] = effectData[3]; + s->stateTargetLevels[2] = effectData[5]; + s->stateTargetLevels[3] = effectData[6]; + s->stateModWheelLevels[0] = effectData[2]; + s->stateModWheelLevels[1] = effectData[4]; + s->stateModWheelLevels[2] = 0; + s->stateModWheelLevels[3] = effectData[7]; + initNextEnvelopeState(s); +} + +void TownsMidiOutputChannel::updateEffectGenerator(EffectEnvelope *s, EffectDef *d) { + uint8 f = advanceEffectEnvelope(s, d); + + if (f & 1) { + switch (d->type) { + case 0: + _operator2Tl = s->startLevel + d->phase; + break; + case 13: + _operator1Tl = s->startLevel + d->phase; + break; + case 30: + d->s->modWheelState = d->phase; + break; + case 31: + d->s->modWheelSensitivity = d->phase; + break; + default: + break; + } + } + + if (f & 2) { + if (d->loopRefresh) + keyOn(); + } +} + +int TownsMidiOutputChannel::advanceEffectEnvelope(EffectEnvelope *s, EffectDef *d) { + if (s->duration) { + s->duration -= 17; + if (s->duration <= 0) { + s->state = kEnvReady; + return 0; + } + } + + int32 t = s->currentLevel + s->incrPerStep; + + s->incrCountRem += s->incrPerStepRem; + if (s->incrCountRem >= s->numSteps) { + s->incrCountRem -= s->numSteps; + t += s->dir; + } + + int retFlags = 0; + + if (t != s->currentLevel || (s->modWheelState != s->modWheelLast)) { + s->currentLevel = t; + s->modWheelLast = s->modWheelState; + t = getEffectModLevel(t, s->modWheelState); + if (t != d->phase) + d->phase = t; + retFlags |= 1; + } + + if (--s->stepCounter) + return retFlags; + + if (++s->state > kEnvReleasing) { + if (!s->loop) { + s->state = kEnvReady; + return retFlags; + } + s->state = kEnvAttacking; + retFlags |= 2; + } + + initNextEnvelopeState(s); + + return retFlags; +} + +void TownsMidiOutputChannel::initNextEnvelopeState(EffectEnvelope *s) { + uint8 v = s->stateTargetLevels[s->state - 1]; + int32 e = _effectEnvStepTable[_driver->_operatorLevelTable[((v & 0x7f) << 5) + s->modWheelSensitivity]]; + + if (v & 0x80) + e = _driver->randomValue(e); + + if (!e) + e = 1; + + s->numSteps = s->stepCounter = e; + int32 d = 0; + + if (s->state != kEnvSustaining) { + v = s->stateModWheelLevels[s->state - 1]; + e = getEffectModLevel(s->maxLevel, (v & 0x7f) - 31); + + if (v & 0x80) + e = _driver->randomValue(e); + + if (e + s->startLevel > s->maxLevel) { + e = s->maxLevel - s->startLevel; + } else { + if (e + s->startLevel < 0) + e = -s->startLevel; + } + + d = e - s->currentLevel; + } + + s->incrPerStep = d / s->numSteps; + s->dir = (d < 0) ? -1 : 1; + d *= s->dir; + s->incrPerStepRem = d % s->numSteps; + s->incrCountRem = 0; +} + +int16 TownsMidiOutputChannel::getEffectStartLevel(uint8 type) { + uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan); + + if (type == 28) + return 15; + else if (type == 29) + return 383; + else if (type > 29) + return 0; + else if (type > 12) + type -= 13; + + const uint8 *def = &_effectDefaults[type << 2]; + uint8 res = (_driver->_chanState[chan].get(def[0] >> 5) & def[2]) >> def[1]; + if (def[3]) + res = def[3] - res; + + return res; +} + +int TownsMidiOutputChannel::getEffectModLevel(int lvl, int mod) { + if (mod == 0) + return 0; + + if (mod == 31) + return lvl; + + if (lvl > 63 || lvl < -63) + return ((lvl + 1) * mod) >> 5; + + if (mod < 0) { + if (lvl < 0) + return _driver->_operatorLevelTable[((-lvl) << 5) - mod]; + else + return -_driver->_operatorLevelTable[(lvl << 5) - mod]; + } else { + if (lvl < 0) + return -_driver->_operatorLevelTable[((-lvl) << 5) + mod]; + else + return _driver->_operatorLevelTable[((-lvl) << 5) + mod]; + } + + return 0; +} + +void TownsMidiOutputChannel::keyOn() { + out(0x28, 0x30); +} + +void TownsMidiOutputChannel::keyOff() { + out(0x28, 0); +} + +void TownsMidiOutputChannel::keyOnSetFreq(uint16 frq) { + uint16 note = (frq << 1) >> 8; + frq = (_freqMSB[note] << 11) | _freqLSB[note] ; + out(0xa4, frq >> 8); + out(0xa0, frq & 0xff); + //out(0x28, 0x00); + out(0x28, 0x30); +} + +void TownsMidiOutputChannel::out(uint8 reg, uint8 val) { + static const uint8 chanRegOffs[] = { 0, 1, 2, 0, 1, 2 }; + static const uint8 keyValOffs[] = { 0, 1, 2, 4, 5, 6 }; + + if (reg == 0x28) + val = (val & 0xf0) | keyValOffs[_chan]; + if (reg < 0x30) + _driver->_intf->callback(17, 0, reg, val); + else + _driver->_intf->callback(17, _chan / 3, (reg & ~3) | chanRegOffs[_chan], val); +} + +const uint8 TownsMidiOutputChannel::_chanMap[] = { + 0, 1, 2, 8, 9, 10 +}; + +const uint8 TownsMidiOutputChannel::_chanMap2[] = { + 3, 4, 5, 11, 12, 13 +}; + +const uint8 TownsMidiOutputChannel::_effectDefaults[] = { + 0x40, 0x00, 0x3F, 0x3F, 0xE0, 0x02, 0x00, 0x00, 0x40, 0x06, 0xC0, 0x00, + 0x20, 0x00, 0x0F, 0x00, 0x60, 0x04, 0xF0, 0x0F, 0x60, 0x00, 0x0F, 0x0F, + 0x80, 0x04, 0xF0, 0x0F, 0x80, 0x00, 0x0F, 0x0F, 0xE0, 0x00, 0x03, 0x00, + 0x20, 0x07, 0x80, 0x00, 0x20, 0x06, 0x40, 0x00, 0x20, 0x05, 0x20, 0x00, + 0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00 +}; + +const uint16 TownsMidiOutputChannel::_effectEnvStepTable[] = { + 0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + 0x000A, 0x000C, 0x000E, 0x0010, 0x0012, 0x0015, 0x0018, 0x001E, + 0x0024, 0x0032, 0x0040, 0x0052, 0x0064, 0x0088, 0x00A0, 0x00C0, + 0x00F0, 0x0114, 0x0154, 0x01CC, 0x0258, 0x035C, 0x04B0, 0x0640 +}; + +const uint8 TownsMidiOutputChannel::_freqMSB[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x80, 0x81, 0x83, 0x85, + 0x87, 0x88, 0x8A, 0x8C, 0x8E, 0x8F, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A, + 0x9C, 0x9E, 0x9F, 0xA1, 0xA3, 0xA5, 0xA6, 0xA8, 0xAA, 0xAC, 0xAD, 0xAF, + 0xB1, 0xB3, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBD, 0xBF, 0xC1, 0xC3, 0xC4, + 0xC6, 0xC8, 0xCA, 0xCB, 0xCD, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, + 0xDB, 0xDD, 0xDF, 0xE1, 0xE2, 0xE4, 0xE6, 0xE8, 0xE9, 0xEB, 0xED, 0xEF +}; + +const uint16 TownsMidiOutputChannel::_freqLSB[] = { + 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, + 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x02D6, 0x0301, 0x032F, + 0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E, + 0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403, + 0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F, + 0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E, + 0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403, + 0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F, + 0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E, + 0x055B, 0x02D6, 0x0301, 0x032F, 0x0360, 0x0393, 0x03C9, 0x0403, + 0x0440, 0x0481, 0x04C6, 0x050E, 0x055B, 0x02D6, 0x0301, 0x032F, + 0x0360, 0x0393, 0x03C9, 0x0403, 0x0440, 0x0481, 0x04C6, 0x050E, + 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, + 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, + 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, + 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B +}; + +TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _out(0), _prg(0), _chanIndex(chanIndex), + _effectLevel(0), _priority(0), _ctrlVolume(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0), + _fld_1f(0), _detune(0), _modWheel(0), _allocated(false) { + _instrument = new uint8[30]; + memset(_instrument, 0, 30); +} + +TownsMidiInputChannel::~TownsMidiInputChannel() { + delete[] _instrument; +} + +bool TownsMidiInputChannel::allocate() { + if (_allocated) + return false; + _allocated = true; + return true; +} + +void TownsMidiInputChannel::release() { + _allocated = false; +} + +void TownsMidiInputChannel::send(uint32 b) { + _driver->send(b | _chanIndex); +} + +void TownsMidiInputChannel::noteOff(byte note) { + if (!_out) + return; + + for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) { + if (oc->_note != note) + continue; + + if (_sustain) + oc->_sustainNoteOff = 1; + else + oc->disconnect(); + } +} + +void TownsMidiInputChannel::noteOn(byte note, byte velocity) { + TownsMidiOutputChannel *oc = _driver->allocateOutputChannel(_priority); + + if (!oc) + return; + + oc->connect(this); + + oc->_adjustModTl = _instrument[10] & 1; + oc->_note = note; + oc->_sustainNoteOff = 0; + oc->_duration = _instrument[29] * 63; + + oc->_operator1Tl = (_instrument[1] & 0x3f) + _driver->_operatorLevelTable[((velocity >> 1) << 5) + (_instrument[4] >> 2)]; + if (oc->_operator1Tl > 63) + oc->_operator1Tl = 63; + + oc->_operator2Tl = (_instrument[6] & 0x3f) + _driver->_operatorLevelTable[((velocity >> 1) << 5) + (_instrument[9] >> 2)]; + if (oc->_operator2Tl > 63) + oc->_operator2Tl = 63; + + oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_operatorLevelTable[(_tl >> 2) + (oc->_operator1Tl << 5)]] : oc->_operator1Tl, _programAdjustLevel[_driver->_operatorLevelTable[(_tl >> 2) + (oc->_operator2Tl << 5)]]); + oc->noteOn(note + _transpose, _freqLSB); + + if (_instrument[11] & 0x80) + oc->setupEffects(0, _instrument[11], &_instrument[12]); + else + oc->_effectEnvelopes[0].state = kEnvReady; + + if (_instrument[20] & 0x80) + oc->setupEffects(1, _instrument[20], &_instrument[21]); + else + oc->_effectEnvelopes[1].state = kEnvReady; +} + +void TownsMidiInputChannel::programChange(byte program) { + // Not implemented (The loading and assignment of programs + // is handled externally by the SCUMM engine. The programs + // get sent via sysEx_customInstrument.) +} + +void TownsMidiInputChannel::pitchBend(int16 bend) { + _pitchBend = bend; + _freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune; + for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) + oc->noteOnPitchBend(oc->_note + oc->_in->_transpose, _freqLSB); +} + +void TownsMidiInputChannel::controlChange(byte control, byte value) { + switch (control) { + case 1: + controlModulationWheel(value); + break; + case 7: + controlVolume(value); + break; + case 10: + controlPanPos(value); + break; + case 64: + controlSustain(value); + break; + case 123: + while (_out) + _out->disconnect(); + break; + default: + break; + } +} + +void TownsMidiInputChannel::pitchBendFactor(byte value) { + _pitchBendFactor = value; + _freqLSB = ((_pitchBend * _pitchBendFactor) >> 6) + _detune; + for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) + oc->noteOnPitchBend(oc->_note + oc->_in->_transpose, _freqLSB); +} + +void TownsMidiInputChannel::priority(byte value) { + _priority = value; +} + +void TownsMidiInputChannel::sysEx_customInstrument(uint32 type, const byte *instr) { + memcpy(_instrument, instr, 30); +} + +void TownsMidiInputChannel::controlModulationWheel(byte value) { + _modWheel = value; + for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) + oc->setModWheel(value); +} + +void TownsMidiInputChannel::controlVolume(byte value) { + /* This is all done inside the imuse code + uint16 v1 = _ctrlVolume + 1; + uint16 v2 = value; + if (_chanIndex != 16) { + _ctrlVolume = value; + v2 = _player->getEffectiveVolume(); + } + _tl = (v1 * v2) >> 7;*/ + + _tl = value; +} + +void TownsMidiInputChannel::controlPanPos(byte value) { + // not implemented +} + +void TownsMidiInputChannel::controlSustain(byte value) { + _sustain = value; + if (!value) + releasePedal(); +} + +void TownsMidiInputChannel::releasePedal() { + for (TownsMidiOutputChannel *oc = _out; oc; oc = oc->_next) { + if (oc->_sustainNoteOff) + oc->disconnect(); + } +} + +const uint8 TownsMidiInputChannel::_programAdjustLevel[] = { + 0x00, 0x04, 0x07, 0x0B, 0x0D, 0x10, 0x12, 0x14, + 0x16, 0x18, 0x1A, 0x1B, 0x1D, 0x1E, 0x1F, 0x21, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2A, 0x2B, 0x2C, 0x2C, 0x2D, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x31, 0x32, 0x33, 0x33, 0x34, 0x35, + 0x35, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, + 0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3C, + 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F +}; + +MidiDriver_TOWNS::MidiDriver_TOWNS(Audio::Mixer *mixer) : _timerProc(0), _timerProcPara(0), _channels(0), _out(0), + _chanState(0), _operatorLevelTable(0), _tickCounter1(0), _tickCounter2(0), _rand(1), _allocCurPos(0), _isOpen(false) { + // We set exteral mutex handling to true, since this driver is only suitable for use with the SCUMM engine + // which has its own mutex. This causes lockups which cannot always be avoided. + _intf = new TownsAudioInterface(mixer, this, true); + + _channels = new TownsMidiInputChannel*[32]; + for (int i = 0; i < 32; i++) + _channels[i] = new TownsMidiInputChannel(this, i > 8 ? (i + 1) : i); + + _out = new TownsMidiOutputChannel*[6]; + for (int i = 0; i < 6; i++) + _out[i] = new TownsMidiOutputChannel(this, i); + + _chanState = new TownsMidiChanState[32]; + + _operatorLevelTable = new uint8[2048]; + for (int i = 0; i < 64; i++) { + for (int ii = 0; ii < 32; ii++) + _operatorLevelTable[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff; + } + for (int i = 0; i < 64; i++) + _operatorLevelTable[i << 5] = 0; +} + +MidiDriver_TOWNS::~MidiDriver_TOWNS() { + close(); + delete _intf; + + if (_channels) { + for (int i = 0; i < 32; i++) + delete _channels[i]; + delete[] _channels; + } + _channels = 0; + + if (_out) { + for (int i = 0; i < 6; i++) + delete _out[i]; + delete[] _out; + } + _out = 0; + + delete[] _chanState; + _chanState = 0; + delete[] _operatorLevelTable; + _operatorLevelTable = 0; +} + +int MidiDriver_TOWNS::open() { + if (_isOpen) + return MERR_ALREADY_OPEN; + + if (!_intf->init()) + return MERR_CANNOT_CONNECT; + + _intf->callback(0); + + _intf->callback(21, 255, 1); + _intf->callback(21, 0, 1); + _intf->callback(22, 255, 221); + + _intf->callback(33, 8); + _intf->setSoundEffectChanMask(~0x3f); + + _allocCurPos = 0; + + _isOpen = true; + + return 0; +} + +void MidiDriver_TOWNS::close() { + if (!_isOpen) + return; + + _isOpen = false; + + setTimerCallback(0, 0); + g_system->delayMillis(20); +} + +void MidiDriver_TOWNS::send(uint32 b) { + if (!_isOpen) + return; + + byte param2 = (b >> 16) & 0xFF; + byte param1 = (b >> 8) & 0xFF; + byte cmd = b & 0xF0; + + TownsMidiInputChannel *c = _channels[b & 0x0F]; + + switch (cmd) { + case 0x80: + c->noteOff(param1); + break; + case 0x90: + if (param2) + c->noteOn(param1, param2); + else + c->noteOff(param1); + break; + case 0xB0: + c->controlChange(param1, param2); + break; + case 0xC0: + c->programChange(param1); + break; + case 0xE0: + c->pitchBend((param1 | (param2 << 7)) - 0x2000); + break; + case 0xF0: + warning("MidiDriver_TOWNS: Receiving SysEx command on a send() call"); + break; + + default: + break; + } +} + +void MidiDriver_TOWNS::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { + _timerProc = timer_proc; + _timerProcPara = timer_param; +} + +uint32 MidiDriver_TOWNS::getBaseTempo() { + return 10080; +} + +MidiChannel *MidiDriver_TOWNS::allocateChannel() { + if (!_isOpen) + return 0; + + for (int i = 0; i < 32; ++i) { + TownsMidiInputChannel *chan = _channels[i]; + if (chan->allocate()) + return chan; + } + + return 0; +} + +MidiChannel *MidiDriver_TOWNS::getPercussionChannel() { + return 0; +} + +void MidiDriver_TOWNS::timerCallback(int timerId) { + if (!_isOpen) + return; + + switch (timerId) { + case 1: + updateParser(); + updateOutputChannels(); + + /*_tickCounter1 += 10000; + while (_tickCounter1 >= 4167) { + _tickCounter1 -= 4167; + unkUpdate(); + }*/ + break; + default: + break; + } +} + +void MidiDriver_TOWNS::updateParser() { + if (_timerProc) + _timerProc(_timerProcPara); +} + +void MidiDriver_TOWNS::updateOutputChannels() { + _tickCounter2 += 10000; + while (_tickCounter2 >= 16667) { + _tickCounter2 -= 16667; + for (int i = 0; i < 6; i++) { + if (_out[i]->update()) + return; + } + } +} + +TownsMidiOutputChannel *MidiDriver_TOWNS::allocateOutputChannel(uint8 pri) { + TownsMidiOutputChannel *res = 0; + + for (int i = 0; i < 6; i++) { + if (++_allocCurPos == 6) + _allocCurPos = 0; + + int s = _out[_allocCurPos]->checkPriority(pri); + if (s == TownsMidiOutputChannel::kDisconnected) + return _out[_allocCurPos]; + + if (s != TownsMidiOutputChannel::kHighPriority) { + pri = s; + res = _out[_allocCurPos]; + } + } + + if (res) + res->disconnect(); + + return res; +} + +int MidiDriver_TOWNS::randomValue(int para) { + _rand = (_rand & 1) ? (_rand >> 1) ^ 0xb8 : (_rand >> 1); + return (_rand * para) >> 8; +} diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h new file mode 100644 index 0000000000..a98bb1b59c --- /dev/null +++ b/audio/softsynth/fmtowns_pc98/towns_midi.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef TOWNS_MIDI_H +#define TOWNS_MIDI_H + +#include "audio/softsynth/fmtowns_pc98/towns_audio.h" +#include "audio/mididrv.h" + + +class TownsMidiOutputChannel; +class TownsMidiInputChannel; +class TownsMidiChanState; + +class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver { +friend class TownsMidiInputChannel; +friend class TownsMidiOutputChannel; +public: + MidiDriver_TOWNS(Audio::Mixer *mixer); + ~MidiDriver_TOWNS(); + + int open(); + bool isOpen() const { return _isOpen; } + void close(); + + void send(uint32 b); + + void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc); + + uint32 getBaseTempo(); + MidiChannel *allocateChannel(); + MidiChannel *getPercussionChannel(); + + void timerCallback(int timerId); + +private: + void updateParser(); + void updateOutputChannels(); + + TownsMidiOutputChannel *allocateOutputChannel(uint8 pri); + + int randomValue(int para); + + TownsMidiInputChannel **_channels; + TownsMidiOutputChannel **_out; + TownsMidiChanState *_chanState; + + Common::TimerManager::TimerProc _timerProc; + void *_timerProcPara; + + TownsAudioInterface *_intf; + + uint32 _tickCounter1; + uint32 _tickCounter2; + uint8 _allocCurPos; + uint8 _rand; + + bool _isOpen; + + uint8 *_operatorLevelTable; +}; + +#endif + diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp index a551276ab1..49fe97caf1 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/softsynth/fmtowns_pc98/towns_pc98_driver.h" @@ -1057,6 +1054,8 @@ TownsPC98_AudioDriver::~TownsPC98_AudioDriver() { _ready = false; deinit(); + Common::StackLock lock(_mutex); + if (_channels) { for (int i = 0; i < _numChan; i++) delete _channels[i]; @@ -1239,7 +1238,6 @@ void TownsPC98_AudioDriver::fadeStep() { if (!_musicPlaying) return; - Common::StackLock lock(_mutex); for (int j = 0; j < _numChan; j++) { if (_updateChannelsFlag & _channels[j]->_idFlag) _channels[j]->fadeStep(); @@ -1264,37 +1262,30 @@ void TownsPC98_AudioDriver::fadeStep() { } } -void TownsPC98_AudioDriver::timerCallbackB() { - _sfxOffs = 0; - - if (_musicPlaying) { - _musicTickCounter++; - - for (int i = 0; i < _numChan; i++) { - if (_updateChannelsFlag & _channels[i]->_idFlag) { - _channels[i]->processEvents(); - _channels[i]->processFrequency(); - } - } +void TownsPC98_AudioDriver::pause() { + _musicPlaying = false; +} + +void TownsPC98_AudioDriver::cont() { + _musicPlaying = true; +} - for (int i = 0; i < _numSSG; i++) { - if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { - _ssgChannels[i]->processEvents(); - _ssgChannels[i]->processFrequency(); - } - } +bool TownsPC98_AudioDriver::looping() { + return _looping == _updateChannelsFlag ? true : false; +} -#ifndef DISABLE_PC98_RHYTHM_CHANNEL - if (_hasPercussion) - if (_updateRhythmFlag & _rhythmChannel->_idFlag) - _rhythmChannel->processEvents(); -#endif - } +bool TownsPC98_AudioDriver::musicPlaying() { + return _musicPlaying; +} - toggleRegProtection(false); +void TownsPC98_AudioDriver::setMusicVolume(int volume) { + _musicVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); +} - if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) - _musicPlaying = false; +void TownsPC98_AudioDriver::setSoundEffectVolume(int volume) { + _sfxVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); } void TownsPC98_AudioDriver::timerCallbackA() { @@ -1322,15 +1313,37 @@ void TownsPC98_AudioDriver::timerCallbackA() { } } -void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { - writeReg(0, 0x26, tempo); - writeReg(0, 0x27, 0x33); -} +void TownsPC98_AudioDriver::timerCallbackB() { + _sfxOffs = 0; -void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { - writeReg(0, 0x24, tempo & 0xff); - writeReg(0, 0x25, tempo >> 8); - writeReg(0, 0x27, 0x33); + if (_musicPlaying) { + _musicTickCounter++; + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + for (int i = 0; i < _numSSG; i++) { + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + +#ifndef DISABLE_PC98_RHYTHM_CHANNEL + if (_hasPercussion) + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->processEvents(); +#endif + } + + toggleRegProtection(false); + + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) + _musicPlaying = false; } void TownsPC98_AudioDriver::startSoundEffect() { @@ -1353,6 +1366,16 @@ void TownsPC98_AudioDriver::startSoundEffect() { _sfxData = 0; } +void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { + writeReg(0, 0x26, tempo); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { + writeReg(0, 0x24, tempo & 0xff); + writeReg(0, 0x25, tempo >> 8); + writeReg(0, 0x27, 0x33); +} const uint8 TownsPC98_AudioDriver::_drvTables[] = { // channel presets 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h index 1227e2626a..ff58482227 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef TOWNS_PC98_AUDIODRIVER_H @@ -53,33 +50,19 @@ public: void fadeStep(); - void pause() { - _musicPlaying = false; - } - void cont() { - _musicPlaying = true; - } + void pause(); + void cont(); - void timerCallbackB(); + bool looping(); + bool musicPlaying(); + + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); + +private: void timerCallbackA(); + void timerCallbackB(); - bool looping() { - return _looping == _updateChannelsFlag ? true : false; - } - bool musicPlaying() { - return _musicPlaying; - } - - void setMusicVolume(int volume) { - _musicVolume = volume; - setVolumeIntern(_musicVolume, _sfxVolume); - } - void setSoundEffectVolume(int volume) { - _sfxVolume = volume; - setVolumeIntern(_musicVolume, _sfxVolume); - } - -protected: void startSoundEffect(); void setMusicTempo(uint8 tempo); diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 9d3751a0cc..63007ba93c 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" @@ -42,45 +39,22 @@ public: void recalculateRates(); void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); - void feedbackLevel(int32 level) { - _feedbackLevel = level ? level + 6 : 0; - } - void detune(int value) { - _detn = &_detnTbl[value << 5]; - } - void multiple(uint32 value) { - _multiple = value ? (value << 1) : 1; - } - void attackRate(uint32 value) { - _specifiedAttackRate = value; - } + void feedbackLevel(int32 level); + void detune(int value); + void multiple(uint32 value); + void attackRate(uint32 value); bool scaleRate(uint8 value); - void decayRate(uint32 value) { - _specifiedDecayRate = value; - recalculateRates(); - } - void sustainRate(uint32 value) { - _specifiedSustainRate = value; - recalculateRates(); - } - void sustainLevel(uint32 value) { - _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; - } - void releaseRate(uint32 value) { - _specifiedReleaseRate = value; - recalculateRates(); - } - void totalLevel(uint32 value) { - _totalLevel = value << 3; - } - void ampModulation(bool enable) { - _ampMod = enable; - } + void decayRate(uint32 value); + void sustainRate(uint32 value); + void sustainLevel(uint32 value); + void releaseRate(uint32 value); + void totalLevel(uint32 value); + void ampModulation(bool enable); void reset(); protected: EnvelopeState _state; - bool _playing; + bool _holdKey; uint32 _feedbackLevel; uint32 _multiple; uint32 _totalLevel; @@ -125,7 +99,7 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con _rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2), _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0), - _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), + _sustainLevel(0), _phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0), _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) { fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0; @@ -134,19 +108,19 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con } void TownsPC98_FmSynthOperator::keyOn() { - if (_playing) + if (_holdKey) return; - _playing = true; + _holdKey = true; _state = kEnvAttacking; _phase = 0; } void TownsPC98_FmSynthOperator::keyOff() { - if (!_playing) + if (!_holdKey) return; - _playing = false; + _holdKey = false; if (_state != kEnvReady) _state = kEnvReleasing; } @@ -202,39 +176,42 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3 int32 targetLevel = 0; EnvelopeState nextState = kEnvReady; - switch (_state) { - case kEnvReady: - return; - case kEnvAttacking: - targetLevel = 0; - nextState = kEnvDecaying; - if ((_specifiedAttackRate << 1) + _keyScale2 < 64) { - targetTime = (1 << fs_a.shift) - 1; - levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + for (bool loop = true; loop;) { + switch (_state) { + case kEnvReady: + return; + case kEnvAttacking: + targetLevel = 0; + nextState = _sustainLevel ? kEnvDecaying : kEnvSustaining; + if ((_specifiedAttackRate << 1) + _keyScale2 < 62) { + targetTime = (1 << fs_a.shift) - 1; + levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + } else { + _currentLevel = targetLevel; + _state = nextState; + continue; + } + break; + case kEnvDecaying: + targetTime = (1 << fs_d.shift) - 1; + nextState = kEnvSustaining; + targetLevel = _sustainLevel; + levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; + break; + case kEnvSustaining: + targetTime = (1 << fs_s.shift) - 1; + nextState = kEnvSustaining; + targetLevel = 1023; + levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; + break; + case kEnvReleasing: + targetTime = (1 << fs_r.shift) - 1; + nextState = kEnvReady; + targetLevel = 1023; + levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; break; - } else { - _currentLevel = targetLevel; - _state = nextState; } - // Fall through - case kEnvDecaying: - targetTime = (1 << fs_d.shift) - 1; - nextState = kEnvSustaining; - targetLevel = _sustainLevel; - levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; - break; - case kEnvSustaining: - targetTime = (1 << fs_s.shift) - 1; - nextState = kEnvSustaining; - targetLevel = 1023; - levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; - break; - case kEnvReleasing: - targetTime = (1 << fs_r.shift) - 1; - nextState = kEnvReady; - targetLevel = 1023; - levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; - break; + loop = false; } if (!(_tickCount & targetTime)) { @@ -275,6 +252,63 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3 out += *o; } +void TownsPC98_FmSynthOperator::feedbackLevel(int32 level) { + _feedbackLevel = level ? level + 6 : 0; +} + +void TownsPC98_FmSynthOperator::detune(int value) { + _detn = &_detnTbl[value << 5]; +} + +void TownsPC98_FmSynthOperator::multiple(uint32 value) { + _multiple = value ? (value << 1) : 1; +} + +void TownsPC98_FmSynthOperator::attackRate(uint32 value) { + _specifiedAttackRate = value; +} + +bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) { + value = 3 - value; + if (_keyScale1 != value) { + _keyScale1 = value; + return true; + } + + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + return false; +} + +void TownsPC98_FmSynthOperator::decayRate(uint32 value) { + _specifiedDecayRate = value; + recalculateRates(); +} + +void TownsPC98_FmSynthOperator::sustainRate(uint32 value) { + _specifiedSustainRate = value; + recalculateRates(); + } + +void TownsPC98_FmSynthOperator::sustainLevel(uint32 value) { + _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; +} + +void TownsPC98_FmSynthOperator::releaseRate(uint32 value) { + _specifiedReleaseRate = value; + recalculateRates(); +} + +void TownsPC98_FmSynthOperator::totalLevel(uint32 value) { + _totalLevel = value << 3; +} + +void TownsPC98_FmSynthOperator::ampModulation(bool enable) { + _ampMod = enable; +} + void TownsPC98_FmSynthOperator::reset() { keyOff(); _timer = 0; @@ -295,20 +329,6 @@ void TownsPC98_FmSynthOperator::reset() { ampModulation(false); } -bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) { - value = 3 - value; - if (_keyScale1 != value) { - _keyScale1 = value; - return true; - } - - int k = _keyScale2; - int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; - fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; - fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; - return false; -} - class TownsPC98_FmSynthSquareSineSource { public: TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt); @@ -633,7 +653,8 @@ void TownsPC98_FmSynthSquareSineSource::updateRegs() { #ifndef DISABLE_PC98_RHYTHM_CHANNEL TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt) : - _rtt(rtt), _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { + _rtt(rtt), _tickLength(timerbase * 2), _timer(0), _totalLevel(0), _volMaskA(0), _volMaskB(0), + _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume), _ready(false) { memset(_rhChan, 0, sizeof(RhtChannel) * 6); _reg = new uint8 *[40]; @@ -830,7 +851,7 @@ void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) { } #endif // DISABLE_PC98_RHYTHM_CHANNEL -TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : +TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type, bool externalMutexHandling) : _mixer(mixer), _chanInternal(0), _ssg(0), #ifndef DISABLE_PC98_RHYTHM_CHANNEL @@ -841,7 +862,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), _rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()), _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), - _regProtectionFlag(false), _ready(false) { + _regProtectionFlag(false), _externalMutex(externalMutexHandling), _ready(false) { memset(&_timers[0], 0, sizeof(ChipTimer)); memset(&_timers[1], 0, sizeof(ChipTimer)); @@ -854,6 +875,8 @@ TownsPC98_FmSynth::~TownsPC98_FmSynth() { if (_ready) deinit(); + Common::StackLock lock(_mutex); + delete _ssg; #ifndef DISABLE_PC98_RHYTHM_CHANNEL delete _prc; @@ -934,10 +957,10 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { if (_regProtectionFlag || !_ready) return; - static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; - Common::StackLock lock(_mutex); + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; + uint8 h = regAddress & 0xf0; uint8 l = (regAddress & 0x0f); @@ -1084,6 +1107,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { if (l == 0) { c->frqTemp = (c->frqTemp & 0xff00) | value; c->updateEnvelopeParameters = true; + c->fmIndex = (c->frqTemp >> 4 & 0x7f); for (int i = 0; i < 4; i++) co[i]->frequency(c->frqTemp); } else if (l == 4) { @@ -1118,21 +1142,37 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { } int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock lock(_mutex); - memset(buffer, 0, sizeof(int16) * numSamples); int32 *tmp = new int32[numSamples]; int32 *tmpStart = tmp; memset(tmp, 0, sizeof(int32) * numSamples); int32 samplesLeft = numSamples >> 1; + bool locked = false; + if (_ready) { + _mutex.lock(); + locked = true; + } + while (_ready && samplesLeft) { int32 render = samplesLeft; for (int i = 0; i < 2; i++) { if (_timers[i].enabled && _timers[i].cb) { if (!_timers[i].smpTillCb) { + + if (locked && _externalMutex) { + _mutex.unlock(); + locked = false; + } + (this->*_timers[i].cb)(); + + if (!locked && _externalMutex) { + _mutex.lock(); + locked = true; + } + _timers[i].smpTillCb = _timers[i].smpPerCb; _timers[i].smpTillCbRem += _timers[i].smpPerCbRem; @@ -1175,16 +1215,37 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { tmp += (render << 1); } + if (locked) + _mutex.unlock(); + delete[] tmpStart; + return numSamples; } +bool TownsPC98_FmSynth::isStereo() const { + return true; +} + +bool TownsPC98_FmSynth::endOfData() const { + return false; +} + +int TownsPC98_FmSynth::getRate() const { + return _mixer->getOutputRate(); +} + void TownsPC98_FmSynth::deinit() { _ready = false; _mixer->stopHandle(_soundHandle); + Common::StackLock lock(_mutex); _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback; } +void TownsPC98_FmSynth::toggleRegProtection(bool prot) { + _regProtectionFlag = prot; +} + uint8 TownsPC98_FmSynth::readSSGStatus() { return _ssg->chanEnable(); } @@ -1220,7 +1281,7 @@ void TownsPC98_FmSynth::generateTables() { WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018); WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018); memset(_oprRates, 0x90, 32); - memset(_oprRates + 96, 0x80, 32); + memset(&_oprRates[96], 0x80, 32); uint8 *dst = (uint8 *)_oprRates + 40; for (int i = 0; i < 40; i += 4) WRITE_BE_UINT32(dst + i, 0x00081018); @@ -1277,8 +1338,8 @@ void TownsPC98_FmSynth::generateTables() { uint8 *dtt = new uint8[128]; memset(dtt, 0, 36); - memset(dtt + 36, 1, 8); - memcpy(dtt + 44, _detSrc, 84); + memset(&dtt[36], 1, 8); + memcpy(&dtt[44], _detSrc, 84); delete[] _oprDetune; _oprDetune = new int32[256]; diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index 2b916b2cdc..4f81fa9a5c 100644 --- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef TOWNS_PC98_FMSYNTH_H @@ -47,7 +44,7 @@ class TownsPC98_FmSynthPercussionSource; #endif enum EnvelopeState { - kEnvReady, + kEnvReady = 0, kEnvAttacking, kEnvDecaying, kEnvSustaining, @@ -62,7 +59,7 @@ public: kType86 }; - TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type); + TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type, bool externalMutexHandling = false); virtual ~TownsPC98_FmSynth(); virtual bool init(); @@ -72,15 +69,9 @@ public: // AudioStream interface int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { - return true; - } - bool endOfData() const { - return false; - } - int getRate() const { - return _mixer->getOutputRate(); - } + bool isStereo() const; + bool endOfData() const; + int getRate() const; protected: void deinit(); @@ -89,17 +80,15 @@ protected: // additional output that has to be inserted into the buffer. virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {} - void toggleRegProtection(bool prot) { - _regProtectionFlag = prot; - } + void toggleRegProtection(bool prot); uint8 readSSGStatus(); virtual void timerCallbackA() = 0; virtual void timerCallbackB() = 0; - // The audio driver can store and apply two different audio settings + // The audio driver can store and apply two different volume settings // (usually for music and sound effects). The channel mask will determine - // which channels get effected by the setting. The first bits will be + // which channels get effected by which setting. The first bits will be // the normal fm channels, the next bits the ssg channels and the final // bit the rhythm channel. void setVolumeIntern(int volA, int volB); @@ -110,6 +99,8 @@ protected: const bool _hasPercussion; Common::Mutex _mutex; + bool _externalMutex; + private: void generateTables(); void nextTick(int32 *buffer, uint32 bufferSize); @@ -127,6 +118,7 @@ private: } uint16 frqTemp; + uint8 fmIndex; bool enableLeft; bool enableRight; bool updateEnvelopeParameters; diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp new file mode 100644 index 0000000000..194bfc41f9 --- /dev/null +++ b/audio/softsynth/fmtowns_pc98/towns_pc98_plugins.cpp @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "audio/softsynth/fmtowns_pc98/towns_midi.h" +#include "audio/musicplugin.h" +#include "common/translation.h" +#include "common/error.h" +#include "common/system.h" + + +class TownsEmuMusicPlugin : public MusicPluginObject { +public: + const char *getName() const { + return _s("FM-Towns Audio"); + } + + const char *getId() const { + return "towns"; + } + + MusicDevices getDevices() const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; +}; + +MusicDevices TownsEmuMusicPlugin::getDevices() const { + MusicDevices devices; + devices.push_back(MusicDevice(this, "", MT_TOWNS)); + return devices; +} + +Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { + *mididriver = new MidiDriver_TOWNS(g_system->getMixer()); + return Common::kNoError; +} + +class PC98EmuMusicPlugin : public MusicPluginObject { +public: + const char *getName() const { + return _s("PC-98 Audio"); + } + + const char *getId() const { + return "pc98"; + } + + MusicDevices getDevices() const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; +}; + +MusicDevices PC98EmuMusicPlugin::getDevices() const { + MusicDevices devices; + devices.push_back(MusicDevice(this, "", MT_PC98)); + return devices; +} + +Common::Error PC98EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { + //*mididriver = /**/ + return Common::kNoError; +} + +//#if PLUGIN_ENABLED_DYNAMIC(TOWNS) + //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); + //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); + REGISTER_PLUGIN_STATIC(PC98, PLUGIN_TYPE_MUSIC, PC98EmuMusicPlugin); +//#endif diff --git a/audio/softsynth/mt32.cpp b/audio/softsynth/mt32.cpp index 5371be60b3..27a5a629c4 100644 --- a/audio/softsynth/mt32.cpp +++ b/audio/softsynth/mt32.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #include "common/scummsys.h" @@ -66,7 +63,7 @@ protected: void generateSamples(int16 *buf, int len); public: - bool _initialising; + bool _initializing; MidiDriver_MT32(Audio::Mixer *mixer); virtual ~MidiDriver_MT32(); @@ -218,7 +215,7 @@ static MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Em } static void MT32_PrintDebug(void *userData, const char *fmt, va_list list) { - if (((MidiDriver_MT32 *)userData)->_initialising) { + if (((MidiDriver_MT32 *)userData)->_initializing) { char buf[512]; vsnprintf(buf, 512, fmt, list); @@ -242,7 +239,7 @@ static int MT32_Report(void *userData, MT32Emu::ReportType type, const void *rep error("Failed to load MT32_PCM.ROM"); break; case MT32Emu::ReportType_progressInit: - if (((MidiDriver_MT32 *)userData)->_initialising) { + if (((MidiDriver_MT32 *)userData)->_initializing) { drawProgress(*((const float *)reportData)); return eatSystemEvents(); } @@ -286,7 +283,7 @@ MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixe // at rates other than 32KHz, thus we produce data at 32KHz and // rely on Mixer to convert. _outputRate = 32000; //_mixer->getOutputRate(); - _initialising = false; + _initializing = false; } MidiDriver_MT32::~MidiDriver_MT32() { @@ -327,11 +324,11 @@ int MidiDriver_MT32::open() { g_system->getPaletteManager()->setPalette(dummy_palette, 0, 3); } - _initialising = true; - drawMessage(-1, _s("Initialising MT-32 Emulator")); + _initializing = true; + drawMessage(-1, _s("Initializing MT-32 Emulator")); if (!_synth->open(prop)) return MERR_DEVICE_NOT_AVAILABLE; - _initialising = false; + _initializing = false; if (screenFormat.bytesPerPixel > 1) g_system->fillScreen(screenFormat.RGBToColor(0, 0, 0)); diff --git a/audio/softsynth/mt32/freeverb.cpp b/audio/softsynth/mt32/freeverb.cpp index c62d4f2cf3..67f065c20e 100644 --- a/audio/softsynth/mt32/freeverb.cpp +++ b/audio/softsynth/mt32/freeverb.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Comb filter implementation diff --git a/audio/softsynth/mt32/freeverb.h b/audio/softsynth/mt32/freeverb.h index 8310aca3e3..39ae463970 100644 --- a/audio/softsynth/mt32/freeverb.h +++ b/audio/softsynth/mt32/freeverb.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ // Macro for killing denormalled numbers diff --git a/audio/softsynth/mt32/partial.cpp b/audio/softsynth/mt32/partial.cpp index 5ba9ef6145..c4f2e94ebe 100644 --- a/audio/softsynth/mt32/partial.cpp +++ b/audio/softsynth/mt32/partial.cpp @@ -28,7 +28,7 @@ #if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built -// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide +// on a newer OS X release on an older one. And Solaris 8 doesn't provide // powf, floorf, fabsf etc. at all. // Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in // libstdc++. math/stubs.o should be empty, but it comes with a symbol for @@ -164,7 +164,7 @@ void Partial::startPartial(dpoly *usePoly, const PatchCache *useCache, Partial * structurePosition = patchCache->structurePosition; play = true; - initKeyFollow(poly->freqnum); // Initialises noteVal, filtVal and realVal + initKeyFollow(poly->freqnum); // Initializes noteVal, filtVal and realVal #if MT32EMU_ACCURATENOTES == 0 noteLookup = &synth->tables.noteLookups[noteVal - LOWEST_NOTE]; #else diff --git a/audio/softsynth/mt32/synth.cpp b/audio/softsynth/mt32/synth.cpp index 112527cc71..322b864b6e 100644 --- a/audio/softsynth/mt32/synth.cpp +++ b/audio/softsynth/mt32/synth.cpp @@ -34,7 +34,7 @@ #if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built -// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide +// on a newer OS X release on an older one. And Solaris 8 doesn't provide // powf, floorf, fabsf etc. at all. // Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in // libstdc++. math/stubs.o should be empty, but it comes with a symbol for @@ -426,36 +426,36 @@ bool Synth::open(SynthProperties &useProp) { } } - printDebug("Initialising Timbre Bank A"); + printDebug("Initializing Timbre Bank A"); if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0)) { return false; } - printDebug("Initialising Timbre Bank B"); + printDebug("Initializing Timbre Bank B"); if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 64)) { return false; } - printDebug("Initialising Timbre Bank R"); + printDebug("Initializing Timbre Bank R"); if (!initRhythmTimbres(controlROMMap->timbreRMap, controlROMMap->timbreRCount)) { return false; } - printDebug("Initialising Timbre Bank M"); - // CM-64 seems to initialise all bytes in this bank to 0. + printDebug("Initializing Timbre Bank M"); + // CM-64 seems to initialize all bytes in this bank to 0. memset(&mt32ram.timbres[128], 0, sizeof (mt32ram.timbres[128]) * 64); partialManager = new PartialManager(this); pcmWaves = new PCMWaveEntry[controlROMMap->pcmCount]; - printDebug("Initialising PCM List"); + printDebug("Initializing PCM List"); initPCMList(controlROMMap->pcmTable, controlROMMap->pcmCount); - printDebug("Initialising Rhythm Temp"); + printDebug("Initializing Rhythm Temp"); memcpy(mt32ram.rhythmSettings, &controlROMData[controlROMMap->rhythmSettings], controlROMMap->rhythmSettingsCount * 4); - printDebug("Initialising Patches"); + printDebug("Initializing Patches"); for (Bit8u i = 0; i < 128; i++) { PatchParam *patch = &mt32ram.patches[i]; patch->timbreGroup = i / 64; @@ -468,9 +468,9 @@ bool Synth::open(SynthProperties &useProp) { patch->dummy = 0; } - printDebug("Initialising System"); + printDebug("Initializing System"); // The MT-32 manual claims that "Standard pitch" is 442Hz. - mt32ram.system.masterTune = 0x40; // Confirmed on CM-64 as 0x4A, but SCUMM games use 0x40 and we don't want to initialise twice + mt32ram.system.masterTune = 0x40; // Confirmed on CM-64 as 0x4A, but SCUMM games use 0x40 and we don't want to initialize twice mt32ram.system.reverbMode = 0; // Confirmed mt32ram.system.reverbTime = 5; // Confirmed mt32ram.system.reverbLevel = 3; // Confirmed @@ -792,7 +792,7 @@ void Synth::writeSysex(unsigned char device, const Bit8u *sysex, Bit32u len) { for (;;) { // Find the appropriate memory region int regionNum; - const MemoryRegion *region = NULL; // Initialised to please compiler + const MemoryRegion *region = NULL; // Initialized to please compiler for (regionNum = 0; regionNum < NUM_REGIONS; regionNum++) { region = &memoryRegions[regionNum]; if (region->contains(addr)) { diff --git a/audio/softsynth/mt32/synth.h b/audio/softsynth/mt32/synth.h index edda446287..0ef2c9d135 100644 --- a/audio/softsynth/mt32/synth.h +++ b/audio/softsynth/mt32/synth.h @@ -263,7 +263,7 @@ public: Synth(); ~Synth(); - // Used to initialise the MT-32. Must be called before any other function. + // Used to initialize the MT-32. Must be called before any other function. // Returns true if initialization was sucessful, otherwise returns false. bool open(SynthProperties &useProp); diff --git a/audio/softsynth/mt32/tables.cpp b/audio/softsynth/mt32/tables.cpp index eba4d2a520..9fdb595467 100644 --- a/audio/softsynth/mt32/tables.cpp +++ b/audio/softsynth/mt32/tables.cpp @@ -19,6 +19,10 @@ * IN THE SOFTWARE. */ + +// FIXME: Avoid using rand +#define FORBIDDEN_SYMBOL_EXCEPTION_rand + #include <stdlib.h> #include <string.h> #include <math.h> @@ -28,7 +32,7 @@ #if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__) // Older versions of Mac OS X didn't supply a powf function, so using it // will cause a binary incompatibility when trying to run a binary built -// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide +// on a newer OS X release on an older one. And Solaris 8 doesn't provide // powf, floorf, fabsf etc. at all. // Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in // libstdc++. math/stubs.o should be empty, but it comes with a symbol for @@ -199,7 +203,7 @@ void Tables::initEnvelopes(float samplerate) { void Tables::initMT32ConstantTables(Synth *synth) { int lf; - synth->printDebug("Initialising Pitch Tables"); + synth->printDebug("Initializing Pitch Tables"); for (lf = -108; lf <= 108; lf++) { tvfKeyfollowMult[lf + 108] = (int)(256 * powf(2.0f, (float)(lf / 24.0f))); //synth->printDebug("KT %d = %d", f, keytable[f+108]); @@ -664,7 +668,7 @@ bool Tables::initNotes(Synth *synth, PCMWaveEntry *pcmWaves, float rate, float m bool abort = false; synth->report(ReportType_progressInit, &progress); for (int f = LOWEST_NOTE; f <= HIGHEST_NOTE; f++) { - synth->printDebug("Initialising note %s%d", NoteNames[f % 12], (f / 12) - 2); + synth->printDebug("Initializing note %s%d", NoteNames[f % 12], (f / 12) - 2); NoteLookup *noteLookup = ¬eLookups[f - LOWEST_NOTE]; file = initNote(synth, noteLookup, (float)f, rate, masterTune, pcmWaves, file); progress = (f - LOWEST_NOTE + 1) / (float)NUM_NOTES; @@ -719,12 +723,12 @@ void Tables::freeNotes() { } } } - initialisedMasterTune = 0.0f; + initializedMasterTune = 0.0f; } Tables::Tables() { - initialisedSampleRate = 0.0f; - initialisedMasterTune = 0.0f; + initializedSampleRate = 0.0f; + initializedMasterTune = 0.0f; memset(¬eLookups, 0, sizeof(noteLookups)); } @@ -733,23 +737,23 @@ bool Tables::init(Synth *synth, PCMWaveEntry *pcmWaves, float sampleRate, float synth->printDebug("Bad sampleRate (%f <= 0.0f)", (double)sampleRate); return false; } - if (initialisedSampleRate == 0.0f) { + if (initializedSampleRate == 0.0f) { initMT32ConstantTables(synth); } - if (initialisedSampleRate != sampleRate) { + if (initializedSampleRate != sampleRate) { initFiltCoeff(sampleRate); initEnvelopes(sampleRate); for (int key = 12; key <= 108; key++) { initDep(&keyLookups[key - 12], (float)key); } } - if (initialisedSampleRate != sampleRate || initialisedMasterTune != masterTune) { + if (initializedSampleRate != sampleRate || initializedMasterTune != masterTune) { freeNotes(); if (!initNotes(synth, pcmWaves, sampleRate, masterTune)) { return false; } - initialisedSampleRate = sampleRate; - initialisedMasterTune = masterTune; + initializedSampleRate = sampleRate; + initializedMasterTune = masterTune; } return true; } diff --git a/audio/softsynth/mt32/tables.h b/audio/softsynth/mt32/tables.h index d9af5114b2..9950323e7b 100644 --- a/audio/softsynth/mt32/tables.h +++ b/audio/softsynth/mt32/tables.h @@ -69,8 +69,8 @@ struct KeyLookup { }; class Tables { - float initialisedSampleRate; - float initialisedMasterTune; + float initializedSampleRate; + float initializedMasterTune; void initMT32ConstantTables(Synth *synth); static Bit16s clampWF(Synth *synth, const char *n, float ampVal, double input); static File *initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div2, File *file); diff --git a/audio/softsynth/opl/dosbox.cpp b/audio/softsynth/opl/dosbox.cpp index 7a494d70ec..e039845b8f 100644 --- a/audio/softsynth/opl/dosbox.cpp +++ b/audio/softsynth/opl/dosbox.cpp @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ /* diff --git a/audio/softsynth/opl/dosbox.h b/audio/softsynth/opl/dosbox.h index 1e92c7f7c9..125dde8aec 100644 --- a/audio/softsynth/opl/dosbox.h +++ b/audio/softsynth/opl/dosbox.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ /* diff --git a/audio/softsynth/opl/mame.cpp b/audio/softsynth/opl/mame.cpp index 5d790f924f..9cc35971eb 100644 --- a/audio/softsynth/opl/mame.cpp +++ b/audio/softsynth/opl/mame.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * * LGPL licensed version of MAMEs fmopl (V0.37a modified) by * Tatsuyuki Satoh. Included from LGPL'ed AdPlug. */ @@ -549,7 +546,7 @@ inline void OPL_CALC_RH(FM_OPL *OPL, OPL_CH *CH) { // but EG_STEP = 96.0/EG_ENT, and WHITE_NOISE_db=6.0. So, that's equivalent to // int(OPL->rnd.getRandomBit() * EG_ENT/16). We know that EG_ENT is 4096, or 1024, // or 128, so we can safely avoid any FP ops. - int whitenoise = OPL->rnd.getRandomBit() * (EG_ENT>>4); + int whitenoise = OPL->rnd->getRandomBit() * (EG_ENT>>4); int tone8; @@ -1129,6 +1126,15 @@ FM_OPL *OPLCreate(int type, int clock, int rate) { OPL->rate = rate; OPL->max_ch = max_ch; + // Init the random source. Note: We use a fixed name for it here. + // So if multiple FM_OPL objects exist in parallel, then their + // random sources will have an equal name. At least in the + // current EventRecorder implementation, this causes no problems; + // but this is probably not guaranteed. + // Alas, it does not seem worthwhile to bother much with this + // at the time, so I am leaving it as it is. + OPL->rnd = new Common::RandomSource("mame"); + /* init grobal tables */ OPL_initalize(OPL); @@ -1137,9 +1143,10 @@ FM_OPL *OPLCreate(int type, int clock, int rate) { return OPL; } -/* ---------- Destroy one of vietual YM3812 ---------- */ +/* ---------- Destroy one of virtual YM3812 ---------- */ void OPLDestroy(FM_OPL *OPL) { OPL_UnLockTable(); + delete OPL->rnd; free(OPL); } diff --git a/audio/softsynth/opl/mame.h b/audio/softsynth/opl/mame.h index 4314aa6dba..803ca897e7 100644 --- a/audio/softsynth/opl/mame.h +++ b/audio/softsynth/opl/mame.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * * LGPL licensed version of MAMEs fmopl (V0.37a modified) by * Tatsuyuki Satoh. Included from LGPL'ed AdPlug. */ @@ -150,7 +147,7 @@ typedef struct fm_opl_f { OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ int UpdateParam; /* stream update parameter */ - Common::RandomSource rnd; + Common::RandomSource *rnd; } FM_OPL; /* ---------- Generic interface section ---------- */ diff --git a/audio/softsynth/pcspk.cpp b/audio/softsynth/pcspk.cpp index 947c142b73..66af968463 100644 --- a/audio/softsynth/pcspk.cpp +++ b/audio/softsynth/pcspk.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * -* $URL$ -* $Id$ -* */ #include "audio/softsynth/pcspk.h" diff --git a/audio/softsynth/pcspk.h b/audio/softsynth/pcspk.h index 8f01fa852b..3641400b1f 100644 --- a/audio/softsynth/pcspk.h +++ b/audio/softsynth/pcspk.h @@ -17,9 +17,6 @@ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ */ #ifndef SOUND_SOFTSYNTH_PCSPK_H diff --git a/audio/softsynth/sid.cpp b/audio/softsynth/sid.cpp index 40dc50e972..4b8f783ef4 100644 --- a/audio/softsynth/sid.cpp +++ b/audio/softsynth/sid.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/softsynth/sid.h b/audio/softsynth/sid.h index d6e402dc3b..a015242844 100644 --- a/audio/softsynth/sid.h +++ b/audio/softsynth/sid.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/softsynth/wave6581.cpp b/audio/softsynth/wave6581.cpp index d1ddad1623..63e08fb113 100644 --- a/audio/softsynth/wave6581.cpp +++ b/audio/softsynth/wave6581.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ /* diff --git a/audio/softsynth/ym2612.cpp b/audio/softsynth/ym2612.cpp deleted file mode 100644 index 162c92f05a..0000000000 --- a/audio/softsynth/ym2612.cpp +++ /dev/null @@ -1,793 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#include <math.h> - -#include "audio/softsynth/ym2612.h" -#include "common/util.h" -#include "audio/musicplugin.h" -#include "common/error.h" -#include "common/system.h" -#include "common/textconsole.h" -#include "common/translation.h" -#include "common/types.h" - -//////////////////////////////////////// -// -// Miscellaneous -// -//////////////////////////////////////// - -static int *sintbl = 0; -static int *powtbl = 0; -static int *frequencyTable = 0; -static int *keycodeTable = 0; -static int *keyscaleTable = 0; -static int *attackOut = 0; - - -//////////////////////////////////////// -// -// Operator2612 implementation -// -//////////////////////////////////////// - -Operator2612::Operator2612 (Voice2612 *owner) : - _owner (owner), - _state (_s_ready), - _currentLevel ((int32)0x7f << 15), - _phase (0), - _lastOutput (0), - _feedbackLevel (0), - _detune (0), - _multiple (1), - _keyScale (0), - _specifiedTotalLevel (127), - _specifiedAttackRate (0), - _specifiedDecayRate (0), - _specifiedSustainRate (0), - _specifiedReleaseRate (15) { - velocity(0); -} - -Operator2612::~Operator2612() -{ } - -void Operator2612::velocity(int velo) { - _velocity = velo; - _totalLevel = ((int32)_specifiedTotalLevel << 15) + - ((int32)(127-_velocity) << 13); - _sustainLevel = ((int32)_specifiedSustainLevel << 17); -} - -void Operator2612::feedbackLevel(int level) { - _feedbackLevel = level; -} - -void Operator2612::setInstrument(byte const *instrument) { - _detune = (instrument[8] >> 4) & 7; - _multiple = instrument[8] & 15; - _specifiedTotalLevel = instrument[12] & 127; - _keyScale = (instrument[16] >> 6) & 3; - _specifiedAttackRate = instrument[16] & 31; - _specifiedDecayRate = instrument[20] & 31; - _specifiedSustainRate = instrument[24] & 31; - _specifiedSustainLevel = (instrument[28] >> 4) & 15; - _specifiedReleaseRate = instrument[28] & 15; - _state = _s_ready; - velocity(_velocity); -} - -void Operator2612::keyOn() { - _state = _s_attacking; - _tickCount = 0; - _phase = 0; - _currentLevel = ((int32)0x7f << 15); -} - -void Operator2612::keyOff() { - if (_state != _s_ready) - _state = _s_releasing; -} - -void Operator2612::frequency(int freq) { - double value; // Use for intermediate computations to avoid int64 arithmetic - int r; - - _frequency = freq / _owner->_rate; - - r = _specifiedAttackRate; - if (r != 0) { - r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); - if (r >= 64) - r = 63; - } - - r = 63 - r; - if (_specifiedTotalLevel >= 128) - value = 0; - else { - value = powtbl[(r&3) << 7]; - value *= 1 << (r >> 2); - value *= 41; - value /= 1 << (15 + 5); - value *= 127 - _specifiedTotalLevel; - value /= 127; - } - _attackTime = (int32) value; // 1 ?? == (1 << 12) - if (_attackTime > 0) - _attackTime = (1 << (12+10)) / (_owner->_rate * _attackTime); - - r = _specifiedDecayRate; - if (r != 0) { - r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); - if (r >= 64) - r = 63; - } - value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31; - _decayRate = (int32) value / _owner->_rate; - - r = _specifiedSustainRate; - if (r != 0) { - r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); - if (r >= 64) - r = 63; - } - value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31; - _sustainRate = (int32) value / _owner->_rate; - - r = _specifiedReleaseRate; - if (r != 0) { - r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not - r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); - // KS - if (r >= 64) - r = 63; - } - value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31; - _releaseRate = (int32) value / _owner->_rate; -} - -void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) { - if (_state == _s_ready) - return; - if (_state == _s_attacking && _attackTime <= 0) { - _currentLevel = 0; - _state = _s_decaying; - } - - int32 levelIncrement = 0; - int32 target = 0; - State next_state = _s_ready; - const int32 zero_level = ((int32)0x7f << 15); - const int phaseIncrement = (_multiple > 0) ? (_frequency * _multiple) : (_frequency / 2); - - int32 output = _lastOutput; - int32 level = _currentLevel + _totalLevel; - - while (buflen) { - switch (_state) { - case _s_ready: - return; - case _s_attacking: - next_state = _s_attacking; - break; - case _s_decaying: - levelIncrement = _decayRate; - target = _sustainLevel + _totalLevel; - next_state = _s_sustaining; - break; - case _s_sustaining: - levelIncrement = _sustainRate; - target = zero_level + _totalLevel; - next_state = _s_ready; - break; - case _s_releasing: - levelIncrement = _releaseRate; - target = zero_level + _totalLevel; - next_state = _s_ready; - break; - } - - bool switching = false; - do { - if (next_state == _s_attacking) { - // Attack phase - ++_tickCount; - int i = (int) (_tickCount * _attackTime); - if (i >= 1024) { - level = _totalLevel; - _state = _s_decaying; - switching = true; - } else { - level = (attackOut[i] << (31 - 8 - 16)) + _totalLevel; - } - } else { - // Decay, Sustain and Release phases - level += levelIncrement; - if (level >= target) { - level = target; - _state = next_state; - switching = true; - } - } - - if (level < zero_level) { - int phaseShift = *phasebuf >> 2; - if (_feedbackLevel) - phaseShift += (output << (_feedbackLevel - 1)) / 1024; - output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff]; - output >>= (level >> 18); - // Here is the original code, which requires 64-bit ints -// output *= powtbl[511 - ((level>>25)&511)]; -// output >>= 16; -// output >>= 1; - // And here's our 32-bit trick for doing it. (Props to Fingolfin!) - // Result varies from original code by max of 1. -// int powVal = powtbl[511 - ((level>>9)&511)]; -// int outputHI = output / 256; -// int powHI = powVal / 256; -// output = (outputHI * powHI) / 2 + (outputHI * (powVal % 256) + powHI * (output % 256)) / 512; - // And here's the even faster code. - // Result varies from original code by max of 8. - output = ((output >> 4) * (powtbl[511-((level>>9)&511)] >> 3)) / 1024; - - _phase += phaseIncrement; - _phase &= 0x3ffff; - } else - output = 0; - - *outbuf += output; - --buflen; - ++phasebuf; - ++outbuf; - } while (buflen && !switching); - } - _lastOutput = output; - _currentLevel = level - _totalLevel; -} - -//////////////////////////////////////// -// -// Voice2612 implementation -// -//////////////////////////////////////// - -Voice2612::Voice2612() { - next = 0; - _control7 = 127; - _note = 40; - _frequency = 440; - _frequencyOffs = 0x2000; - _algorithm = 7; - - _buffer = 0; - _buflen = 0; - - int i; - for (i = 0; i < ARRAYSIZE(_opr); ++i) - _opr[i] = new Operator2612 (this); - velocity(0); -} - -Voice2612::~Voice2612() { - int i; - for (i = 0; i < ARRAYSIZE(_opr); ++i) - delete _opr[i]; - free(_buffer); -} - -void Voice2612::velocity(int velo) { - _velocity = velo; -#if 0 - int v = (velo * _control7) >> 7; -#else - int v = velo + (_control7 - 127) * 4; -#endif - bool iscarrier[8][4] = { - { false, false, false, true, }, //0 - { false, false, false, true, }, //1 - { false, false, false, true, }, //2 - { false, false, false, true, }, //3 - { false, true, false, true, }, //4 - { false, true, true, true, }, //5 - { false, true, true, true, }, //6 - { true, true, true, true, }, //7 - }; - int opr; - for (opr = 0; opr < 4; opr++) - if (iscarrier[_algorithm][opr]) - _opr[opr]->velocity(v); - else - _opr[opr]->velocity(127); -} - -void Voice2612::setControlParameter(int control, int value) { - switch (control) { - case 7: - _control7 = value; - velocity(_velocity); - break; - case 123: - // All notes off - noteOff(_note); - }; -} - -void Voice2612::setInstrument(byte const *instrument) { - if (instrument == NULL) - return; - - _algorithm = instrument[32] & 7; - _opr[0]->feedbackLevel((instrument[32] >> 3) & 7); - _opr[1]->feedbackLevel(0); - _opr[2]->feedbackLevel(0); - _opr[3]->feedbackLevel(0); - _opr[0]->setInstrument(instrument + 0); - _opr[1]->setInstrument(instrument + 2); - _opr[2]->setInstrument(instrument + 1); - _opr[3]->setInstrument(instrument + 3); -} - -void Voice2612::nextTick(int *outbuf, int buflen) { - if (_velocity == 0) - return; - - if (_buflen < buflen) { - free(_buffer); - _buflen = buflen; - _buffer = (int *) malloc(sizeof(int) * buflen * 2); - } - - int *buf1 = _buffer; - int *buf2 = _buffer + buflen; - memset(_buffer, 0, sizeof(int) * buflen * 2); - - switch (_algorithm) { - case 0: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf2, buf1, buflen); - memset (buf2, 0, sizeof (int) * buflen); - _opr[2]->nextTick(buf1, buf2, buflen); - _opr[3]->nextTick(buf2, outbuf, buflen); - break; - case 1: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf1, buf2, buflen); - _opr[2]->nextTick(buf2, buf1, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - case 2: - _opr[1]->nextTick(buf1, buf2, buflen); - _opr[2]->nextTick(buf2, buf1, buflen); - memset(buf2, 0, sizeof(int) * buflen); - _opr[0]->nextTick(buf2, buf1, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - case 3: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf2, buf1, buflen); - memset(buf2, 0, sizeof(int) * buflen); - _opr[2]->nextTick(buf2, buf1, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - case 4: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf2, outbuf, buflen); - _opr[2]->nextTick(buf1, buf1, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - case 5: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf2, outbuf, buflen); - _opr[2]->nextTick(buf2, outbuf, buflen); - _opr[3]->nextTick(buf2, outbuf, buflen); - break; - case 6: - _opr[0]->nextTick(buf1, buf2, buflen); - _opr[1]->nextTick(buf2, outbuf, buflen); - _opr[2]->nextTick(buf1, outbuf, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - case 7: - _opr[0]->nextTick(buf1, outbuf, buflen); - _opr[1]->nextTick(buf1, outbuf, buflen); - _opr[2]->nextTick(buf1, outbuf, buflen); - _opr[3]->nextTick(buf1, outbuf, buflen); - break; - }; -} - -void Voice2612::noteOn(int n, int onVelo) { - _note = n; - velocity(onVelo); - recalculateFrequency(); - int i; - for (i = 0; i < ARRAYSIZE(_opr); i++) - _opr[i]->keyOn(); -} - -bool Voice2612::noteOff(int note) { - if (_note != note) - return false; - int i; - for (i = 0; i < ARRAYSIZE(_opr); i++) - _opr[i]->keyOff(); - return true; -} - -void Voice2612::pitchBend(int value) { - _frequencyOffs = value; - recalculateFrequency(); -} - -void Voice2612::recalculateFrequency() { - // - // - // - int32 basefreq = frequencyTable[_note]; - int cfreq = frequencyTable[_note - (_note % 12)]; - int oct = _note / 12; - int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq); - fnum += _frequencyOffs - 0x2000; - if (fnum < 0x2000) { - fnum += 0x2000; - oct--; - } - if (fnum >= 0x4000) { - fnum -= 0x2000; - oct++; - } - - // - _frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8); - - int i; - for (i = 0; i < ARRAYSIZE(_opr); i++) - _opr[i]->frequency(_frequency); -} - -//////////////////////////////////////// -// -// MidiChannel_YM2612 -// -//////////////////////////////////////// - -MidiChannel_YM2612::MidiChannel_YM2612() { - _voices = 0; - _next_voice = 0; -} - -MidiChannel_YM2612::~MidiChannel_YM2612() { - removeAllVoices(); -} - -void MidiChannel_YM2612::removeAllVoices() { - if (!_voices) - return; - Voice2612 *last, *voice = _voices; - for (; voice; voice = last) { - last = voice->next; - delete voice; - } - _voices = _next_voice = 0; -} - -void MidiChannel_YM2612::noteOn(byte note, byte onVelo) { - if (!_voices) - return; - _next_voice = _next_voice ? _next_voice : _voices; - _next_voice->noteOn(note, onVelo); - _next_voice = _next_voice->next; -} - -void MidiChannel_YM2612::noteOff(byte note) { - if (!_voices) - return; - if (_next_voice == _voices) - _next_voice = 0; - Voice2612 *voice = _next_voice; - do { - if (!voice) - voice = _voices; - if (voice->noteOff(note)) { - _next_voice = voice; - break; - } - voice = voice->next; - } while (voice != _next_voice); -} - -void MidiChannel_YM2612::controlChange(byte control, byte value) { - // - if (control == 121) { - // Reset controller - removeAllVoices(); - } else { - Voice2612 *voice = _voices; - for (; voice; voice = voice->next) - voice->setControlParameter(control, value); - } -} - -void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst) { - if (type != 'EUP ') - return; - Voice2612 *voice = new Voice2612; - voice->next = _voices; - _voices = voice; - voice->_rate = _rate; - voice->setInstrument(fmInst); -} - -void MidiChannel_YM2612::pitchBend(int16 value) { - // - Voice2612 *voice = _voices; - for (; voice; voice = voice->next) - voice->pitchBend(value); -} - -void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) { - Voice2612 *voice = _voices; - for (; voice; voice = voice->next) - voice->nextTick(outbuf, buflen); -} - -void MidiChannel_YM2612::rate(uint16 r) { - _rate = r; - Voice2612 *voice = _voices; - for (; voice; voice = voice->next) - voice->_rate = r; -} - -//////////////////////////////////////// -// -// MidiDriver_YM2612 -// -//////////////////////////////////////// - -MidiDriver_YM2612::MidiDriver_YM2612(Audio::Mixer *mixer) - : MidiDriver_Emulated(mixer) { - _next_voice = 0; - - createLookupTables(); - _volume = 256; - int i; - for (i = 0; i < ARRAYSIZE(_channel); i++) - _channel[i] = new MidiChannel_YM2612; - rate(getRate()); -} - -MidiDriver_YM2612::~MidiDriver_YM2612() { - int i; - for (i = 0; i < ARRAYSIZE(_channel); i++) - delete _channel[i]; - removeLookupTables(); -} - -int MidiDriver_YM2612::open() { - if (_isOpen) - return MERR_ALREADY_OPEN; - - MidiDriver_Emulated::open(); - - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); - return 0; -} - -void MidiDriver_YM2612::close() { - if (!_isOpen) - return; - _isOpen = false; - - _mixer->stopHandle(_mixerSoundHandle); -} - -void MidiDriver_YM2612::send(uint32 b) { - send(b & 0xF, b & 0xFFFFFFF0); -} - -void MidiDriver_YM2612::send(byte chan, uint32 b) { - //byte param3 = (byte) ((b >> 24) & 0xFF); - byte param2 = (byte) ((b >> 16) & 0xFF); - byte param1 = (byte) ((b >> 8) & 0xFF); - byte cmd = (byte) (b & 0xF0); - if (chan > ARRAYSIZE(_channel)) - return; - - switch (cmd) { - case 0x80:// Note Off - _channel[chan]->noteOff(param1); - break; - case 0x90: // Note On - _channel[chan]->noteOn(param1, param2); - break; - case 0xA0: // Aftertouch - break; // Not supported. - case 0xB0: // Control Change - _channel[chan]->controlChange(param1, param2); - break; - case 0xC0: // Program Change - _channel[chan]->programChange(param1); - break; - case 0xD0: // Channel Pressure - break; // Not supported. - case 0xE0: // Pitch Bend - _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000); - break; - case 0xF0: // SysEx - // We should never get here! SysEx information has to be - // sent via high-level semantic methods. - warning("MidiDriver_YM2612: Receiving SysEx command on a send() call"); - break; - - default: - warning("MidiDriver_YM2612: Unknown send() command 0x%02X", cmd); - } -} - -void MidiDriver_YM2612::sysEx(const byte *msg, uint16 length) { - if (msg[0] != 0x7C || msg[1] >= ARRAYSIZE(_channel)) - return; - _channel[msg[1]]->sysEx_customInstrument('EUP ', &msg[2]); -} - -void MidiDriver_YM2612::generateSamples(int16 *data, int len) { - memset(data, 0, 2 * sizeof(int16) * len); - nextTick(data, len); -} - -void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) { - int *buf0 = (int *)buf1; - - int i; - for (i = 0; i < ARRAYSIZE(_channel); i++) - _channel[i]->nextTick(buf0, buflen); - - for (i = 0; i < buflen; ++i) - buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff; -} - -void MidiDriver_YM2612::rate(uint16 r) -{ - int i; - for (i = 0; i < ARRAYSIZE(_channel); i++) - _channel[i]->rate(r); -} - -void MidiDriver_YM2612::createLookupTables() { - { - int i; - sintbl = new int [2048]; - for (i = 0; i < 2048; i++) - sintbl[i] = (int)(0xffff * sin(i/2048.0 * 2.0 * M_PI)); - } - - { - int i; - powtbl = new int [1025]; - for (i = 0; i <= 1024; i++) - powtbl[i] = (int)(0x10000 * pow(2.0, (i - 512) / 512.0)); - } - - { - int i; - int block; - - static int fnum[] = { - 0x026a, 0x028f, 0x02b6, 0x02df, - 0x030b, 0x0339, 0x036a, 0x039e, - 0x03d5, 0x0410, 0x044e, 0x048f, - }; - - // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0)) - // - frequencyTable = new int [120]; - for (block = -1; block < 9; block++) { - for (i = 0; i < 12; i++) { - double freq = fnum[i] * (166400.0 / 3) * pow(2.0, block-21); - frequencyTable[(block+1)*12+i] = (int)(256.0 * freq); - } - } - - keycodeTable = new int [120]; - // detune - for (block = -1; block < 9; block++) { - for (i = 0; i < 12; i++) { - // see p.204 - int f8 = (fnum[i] >> 7) & 1; - int f9 = (fnum[i] >> 8) & 1; - int f10 = (fnum[i] >> 9) & 1; - int f11 = (fnum[i] >> 10) & 1; - int n4 = f11; - int n3 = (f11&(f10|f9|f8)) | (~f11&f10&f9&f8); - int note = n4*2 + n3; - // see p.207 - keycodeTable[(block+1)*12+i] = block*4 + note; - } - } - } - - { - int freq; - keyscaleTable = new int [8192]; - keyscaleTable[0] = 0; - for (freq = 1; freq < 8192; freq++) { - keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1; - // 8368[Hz] (o9c) - } - } - - { - int i; - attackOut = new int [1024]; - for (i = 0; i < 1024; i++) - attackOut[i] = (int)(((0x7fff+0x03a5)*30.0) / (30.0+i)) - 0x03a5; - } -} - -void MidiDriver_YM2612::removeLookupTables() { - delete[] sintbl; - delete[] powtbl; - delete[] frequencyTable; - delete[] keycodeTable; - delete[] keyscaleTable; - delete[] attackOut; - sintbl = powtbl = frequencyTable = keycodeTable = keyscaleTable = attackOut = 0; -} - - -// Plugin interface - -class TownsEmuMusicPlugin : public MusicPluginObject { -public: - const char *getName() const { - return _s("FM Towns Emulator"); - } - - const char *getId() const { - return "towns"; - } - - MusicDevices getDevices() const; - Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; -}; - -MusicDevices TownsEmuMusicPlugin::getDevices() const { - MusicDevices devices; - devices.push_back(MusicDevice(this, "", MT_TOWNS)); - return devices; -} - -Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { - *mididriver = new MidiDriver_YM2612(g_system->getMixer()); - - return Common::kNoError; -} - -//#if PLUGIN_ENABLED_DYNAMIC(TOWNS) - //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); -//#else - REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); -//#endif diff --git a/audio/softsynth/ym2612.h b/audio/softsynth/ym2612.h deleted file mode 100644 index f652b2d9e4..0000000000 --- a/audio/softsynth/ym2612.h +++ /dev/null @@ -1,179 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef SOUND_SOFTSYNTH_Y2612_H -#define SOUND_SOFTSYNTH_Y2612_H - -#include "common/scummsys.h" - -#include "audio/softsynth/emumidi.h" - -//////////////////////////////////////// -// -// Class declarations -// -//////////////////////////////////////// - -class Voice2612; -class Operator2612 { -protected: - Voice2612 *_owner; - enum State { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing }; - State _state; - int32 _currentLevel; - int _frequency; - uint32 _phase; - int _lastOutput; - int _feedbackLevel; - int _detune; - int _multiple; - int32 _totalLevel; - int _keyScale; - int _velocity; - int _specifiedTotalLevel; - int _specifiedAttackRate; - int _specifiedDecayRate; - int _specifiedSustainLevel; - int _specifiedSustainRate; - int _specifiedReleaseRate; - int _tickCount; - int _attackTime; - int32 _decayRate; - int32 _sustainLevel; - int32 _sustainRate; - int32 _releaseRate; - -public: - Operator2612 (Voice2612 *owner); - ~Operator2612(); - void feedbackLevel(int level); - void setInstrument(byte const *instrument); - void velocity(int velo); - void keyOn(); - void keyOff(); - void frequency(int freq); - void nextTick(const int *phaseShift, int *outbuf, int buflen); - bool inUse() { return (_state != _s_ready); } -}; - -class Voice2612 { -public: - Voice2612 *next; - uint16 _rate; - -protected: - Operator2612 *_opr[4]; - int _velocity; - int _control7; - int _note; - int _frequencyOffs; - int _frequency; - int _algorithm; - - int *_buffer; - int _buflen; - -public: - Voice2612(); - ~Voice2612(); - void setControlParameter(int control, int value); - void setInstrument(byte const *instrument); - void velocity(int velo); - void nextTick(int *outbuf, int buflen); - void noteOn(int n, int onVelo); - bool noteOff(int note); - void pitchBend(int value); - void recalculateFrequency(); -}; - -class MidiChannel_YM2612 : public MidiChannel { -protected: - uint16 _rate; - Voice2612 *_voices; - Voice2612 *_next_voice; - -public: - void removeAllVoices(); - void nextTick(int *outbuf, int buflen); - void rate(uint16 r); - -public: - MidiChannel_YM2612(); - virtual ~MidiChannel_YM2612(); - - // MidiChannel interface - MidiDriver *device() { return 0; } - byte getNumber() { return 0; } - void release() { } - void send(uint32 b) { } - void noteOff(byte note); - void noteOn(byte note, byte onVelo); - void programChange(byte program) { } - void pitchBend(int16 value); - void controlChange(byte control, byte value); - void pitchBendFactor(byte value) { } - void sysEx_customInstrument(uint32 type, const byte *instr); -}; - -class MidiDriver_YM2612 : public MidiDriver_Emulated { -protected: - MidiChannel_YM2612 *_channel[16]; - - int _next_voice; - int _volume; - -protected: - void nextTick(int16 *buf1, int buflen); - int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; } - void rate(uint16 r); - - void generateSamples(int16 *buf, int len); - -public: - MidiDriver_YM2612(Audio::Mixer *mixer); - virtual ~MidiDriver_YM2612(); - - static void createLookupTables(); - static void removeLookupTables(); - - int open(); - void close(); - void send(uint32 b); - void send(byte channel, uint32 b); // Supports higher than channel 15 - uint32 property(int prop, uint32 param) { return 0; } - - void setPitchBendRange(byte channel, uint range) { } - void sysEx(const byte *msg, uint16 length); - - MidiChannel *allocateChannel() { return 0; } - MidiChannel *getPercussionChannel() { return 0; } - - - // AudioStream API - bool isStereo() const { return true; } - int getRate() const { return _mixer->getOutputRate(); } -}; - -#endif - diff --git a/audio/timestamp.cpp b/audio/timestamp.cpp index cdc5bc3a02..69b47d1628 100644 --- a/audio/timestamp.cpp +++ b/audio/timestamp.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #include "audio/timestamp.h" diff --git a/audio/timestamp.h b/audio/timestamp.h index 4130793fc8..ef095a2106 100644 --- a/audio/timestamp.h +++ b/audio/timestamp.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL$ - * $Id$ - * */ #ifndef SOUND_TIMESTAMP_H |