diff options
Diffstat (limited to 'backends/midi/mt32.cpp')
-rw-r--r-- | backends/midi/mt32.cpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/backends/midi/mt32.cpp b/backends/midi/mt32.cpp new file mode 100644 index 0000000000..2931e94c71 --- /dev/null +++ b/backends/midi/mt32.cpp @@ -0,0 +1,243 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2004 The ScummVM project + * + * YM2612 tone generation code written by Tomoaki Hayasaka. + * Used under the terms of the GNU General Public License. + * Adpated to ScummVM by Jamieson Christian. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + */ + +#include "stdafx.h" +#include "common/scummsys.h" + +#ifdef USE_MT32EMU + +#include "backends/midi/mt32/mt32emu.h" + +#include "backends/midi/emumidi.h" +#include "sound/mpu401.h" + +#include "common/util.h" +#include "common/file.h" +#include "common/config-manager.h" + +class MidiDriver_MT32 : public MidiDriver_Emulated { +private: + MidiChannel_MPU401 _midi_channels[16]; + uint16 _channel_mask; + MT32Emu::Synth *_synth; + + int _outputRate; + +protected: + void generate_samples(int16 *buf, int len); + +public: + MidiDriver_MT32(SoundMixer *mixer); + virtual ~MidiDriver_MT32(); + + int open(); + void close(); + void send(uint32 b); + void sysEx(byte *msg, uint16 length); + + uint32 property(int prop, uint32 param); + MidiChannel *allocateChannel(); + MidiChannel *getPercussionChannel(); + + // AudioStream API + bool isStereo() const { return true; } + int getRate() const { return _outputRate; } +}; + +typedef File SFile; + +class MT32File: public MT32Emu::File { + SFile file; +public: + bool open(const char *filename, OpenMode mode) { + SFile::AccessMode accessMode = mode == OpenMode_read ? SFile::kFileReadMode : SFile::kFileWriteMode; + return file.open(filename, accessMode); + } + void close() { + return file.close(); + } + size_t read(void *ptr, size_t size) { + return file.read(ptr, size); + } + bool readLine(char *ptr, size_t size) { + return file.gets(ptr, size) != NULL; + } + size_t write(const void *ptr, size_t size) { + return file.write(ptr, size); + } + int readByte() { + byte b = file.readByte(); + if (file.eof()) + return -1; + return b; + } + bool writeByte(unsigned char out) { + file.writeByte(out); + if (file.ioFailed()) + return false; + return true; + } + bool isEOF() { + return file.eof(); + } +}; + +MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Emu::File::OpenMode mode) { + MT32File *file = new MT32File(); + if (!file->open(filename, mode)) { + delete file; + return NULL; + } + return file; +} + +//////////////////////////////////////// +// +// MidiDriver_MT32 +// +//////////////////////////////////////// + +void report(int type, ...) {} + +MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer) : MidiDriver_Emulated(mixer) { + _channel_mask = 0xFFFF; // Permit all 16 channels by default + uint i; + for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) { + _midi_channels [i].init (this, i); + } + _synth = NULL; + + _baseFreq = 1000; + + _outputRate = 44100; +} + +MidiDriver_MT32::~MidiDriver_MT32() { + if (_synth != NULL) + delete _synth; +} + +static void vdebug(void *data, const char *fmt, va_list list) { + // do nothing here now +} + +int MidiDriver_MT32::open() { + MT32Emu::SynthProperties prop; + + if (_isOpen) + return MERR_ALREADY_OPEN; + + MidiDriver_Emulated::open(); + + memset(&prop, 0, sizeof(prop)); + prop.SampleRate = getRate(); + prop.UseReverb = true; + prop.UseDefault = false; + prop.RevType = 0; + prop.RevTime = 5; + prop.RevLevel = 3; + prop.userData = (void *)1; + prop.printDebug = &vdebug; + prop.openFile = MT32_OpenFile; + _synth = new MT32Emu::Synth(); + if (!_synth->open(prop)) + return MERR_DEVICE_NOT_AVAILABLE; + + _mixer->setupPremix(this); + + return 0; +} + +void MidiDriver_MT32::send(uint32 b) { + _synth->playMsg(b); +} + +void MidiDriver_MT32::sysEx(byte *msg, uint16 length) { + if (msg[0] == 0xf0) { + _synth->playSysex(msg, length); + } else { + _synth->playSysexWithoutFraming(msg, length); + } +} + +void MidiDriver_MT32::close() { + if (!_isOpen) + return; + _isOpen = false; + + // Detach the premix callback handler + _mixer->setupPremix(0); + + _synth->close(); + delete _synth; + _synth = NULL; +} + +void MidiDriver_MT32::generate_samples(int16 *data, int len) { + _synth->render(data, len); +} + +uint32 MidiDriver_MT32::property (int prop, uint32 param) { + switch (prop) { + case PROP_CHANNEL_MASK: + _channel_mask = param & 0xFFFF; + return 1; + } + + return 0; +} + +MidiChannel *MidiDriver_MT32::allocateChannel() { + MidiChannel_MPU401 *chan; + uint i; + + for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) { + if (i == 9 || !(_channel_mask & (1 << i))) + continue; + chan = &_midi_channels[i]; + if (chan->allocate()) { + return chan; + } + } + return NULL; +} + +MidiChannel *MidiDriver_MT32::getPercussionChannel() { + return &_midi_channels [9]; +} + +//////////////////////////////////////// +// +// MidiDriver_MT32 factory +// +//////////////////////////////////////// + +MidiDriver *MidiDriver_MT32_create(SoundMixer *mixer) { + // HACK: It will stay here until engine plugin loader overhaul + if (ConfMan.hasKey("extrapath")) + File::addDefaultDirectory(ConfMan.get("extrapath")); + return new MidiDriver_MT32(mixer); +} + +#endif |