diff options
Diffstat (limited to 'backends/midi/mt32.cpp')
-rw-r--r-- | backends/midi/mt32.cpp | 486 |
1 files changed, 0 insertions, 486 deletions
diff --git a/backends/midi/mt32.cpp b/backends/midi/mt32.cpp deleted file mode 100644 index 8bf3807603..0000000000 --- a/backends/midi/mt32.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001-2004 The ScummVM project - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Header$ - */ - -#include "stdafx.h" -#include "common/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" - -#include "graphics/font.h" -#include "graphics/surface.h" - -class MidiChannel_MT32 : public MidiChannel_MPU401 { - void effectLevel(byte value) { } - void chorusLevel(byte value) { } -}; - -class MidiDriver_MT32 : public MidiDriver_Emulated { -private: - PlayingSoundHandle _handle; - MidiChannel_MT32 _midiChannels[16]; - uint16 _channelMask; - MT32Emu::Synth *_synth; - - int _outputRate; - -protected: - void generateSamples(int16 *buf, int len); - -public: - bool _initialising; - - MidiDriver_MT32(SoundMixer *mixer); - virtual ~MidiDriver_MT32(); - - int open(); - void close(); - void send(uint32 b); - void setPitchBendRange (byte channel, uint range); - 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 *in, size_t size) { - return file.read(in, size); - } - bool readLine(char *in, size_t size) { - return file.gets(in, size) != NULL; - } - bool readBit8u(MT32Emu::Bit8u *in) { - byte b = file.readByte(); - if (file.eof()) - return false; - *in = b; - return true; - } - size_t write(const void *in, size_t size) { - return file.write(in, size); - } - bool writeBit8u(MT32Emu::Bit8u out) { - file.writeByte(out); - return !file.ioFailed(); - } - bool isEOF() { - return file.eof(); - } -}; - -static int eatSystemEvents() { - OSystem::Event event; - while (g_system->pollEvent(event)) { - switch (event.type) { - case OSystem::EVENT_QUIT: - return 1; - default: - break; - } - } - return 0; -} - -static void drawProgress(float progress) { - Graphics::Surface surf; - uint32 borderColor = 0x2; - uint32 fillColor = 0x4; - surf.w = g_system->getWidth() / 7 * 5; - surf.h = Graphics::g_scummfont.getFontHeight(); - int x = g_system->getWidth() / 7; - int y = g_system->getHeight() / 2 - surf.h / 2; - surf.pitch = surf.w; - surf.bytesPerPixel = 1; - surf.pixels = calloc(surf.w, surf.h); - Common::Rect r(surf.w, surf.h); - surf.frameRect(r, borderColor); - r.grow(-1); - r.right = r.left + (uint16)(r.width() * progress); - surf.fillRect(r, fillColor); - g_system->copyRectToScreen((byte *)surf.pixels, surf.pitch, x, y, surf.w, surf.h); - g_system->updateScreen(); - free(surf.pixels); -} - -static void drawMessage(int offset, const Common::String &text) { - const Graphics::Font &font(Graphics::g_scummfont); - Graphics::Surface surf; - uint32 color = 0x2; - surf.w = g_system->getWidth(); - surf.h = font.getFontHeight(); - surf.pitch = surf.w; - surf.bytesPerPixel = 1; - surf.pixels = calloc(surf.w, surf.h); - font.drawString(&surf, text, 0, 0, surf.w, color, Graphics::kTextAlignCenter); - int y = g_system->getHeight() / 2 - font.getFontHeight() / 2 + offset * (font.getFontHeight() + 1); - g_system->copyRectToScreen((byte *)surf.pixels, surf.pitch, 0, y, surf.w, surf.h); - g_system->updateScreen(); - free(surf.pixels); -} - -static 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; -} - -static void MT32_PrintDebug(void *userData, const char *fmt, va_list list) { - char buf[512]; - if (((MidiDriver_MT32 *)userData)->_initialising) { - vsprintf(buf, fmt, list); - buf[70] = 0; // Truncate to a reasonable length - drawMessage(1, buf); - } - //vdebug(0, fmt, list); // FIXME: Use a higher debug level -} - -static int MT32_Report(void *userData, MT32Emu::ReportType type, const void *reportData) { - switch(type) { - case MT32Emu::ReportType_lcdMessage: - g_system->displayMessageOnOSD((const char *)reportData); - break; - case MT32Emu::ReportType_errorControlROM: - error("Failed to load MT32_CONTROL.ROM"); - break; - case MT32Emu::ReportType_errorPCMROM: - error("Failed to load MT32_PCM.ROM"); - break; - case MT32Emu::ReportType_progressInit: - if (((MidiDriver_MT32 *)userData)->_initialising) { - drawProgress(*((const float *)reportData)); - return eatSystemEvents(); - } - break; - default: - break; - } - return 0; -} - -//////////////////////////////////////// -// -// MidiDriver_MT32 -// -//////////////////////////////////////// - -MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer) : MidiDriver_Emulated(mixer) { - _channelMask = 0xFFFF; // Permit all 16 channels by default - uint i; - for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) { - _midiChannels[i].init(this, i); - } - _synth = NULL; - // A higher baseFreq reduces the length used in generateSamples(), - // and means that the timer callback will be called more often. - // That results in more accurate timing. - _baseFreq = 10000; - // Unfortunately bugs in the emulator cause inaccurate tuning - // at rates other than 32KHz, thus we produce data at 32KHz and - // rely on SoundMixer to convert. - _outputRate = 32000; //_mixer->getOutputRate(); - _initialising = false; -} - -MidiDriver_MT32::~MidiDriver_MT32() { - if (_synth != NULL) - delete _synth; -} - -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.useDefaultReverb = false; - prop.reverbType = 0; - prop.reverbTime = 5; - prop.reverbLevel = 3; - prop.userData = this; - prop.printDebug = MT32_PrintDebug; - prop.report = MT32_Report; - prop.openFile = MT32_OpenFile; - _synth = new MT32Emu::Synth(); - _initialising = true; - const byte dummy_palette[] = { - 0, 0, 0, 0, - 0, 0, 171, 0, - 0, 171, 0, 0, - 0, 171, 171, 0, - 171, 0, 0, 0 - }; - - g_system->setPalette(dummy_palette, 0, 5); - drawMessage(-1, "Initialising MT-32 Emulator"); - if (!_synth->open(prop)) - return MERR_DEVICE_NOT_AVAILABLE; - _initialising = false; - g_system->clearScreen(); - g_system->updateScreen(); - _mixer->playInputStream(&_handle, this, false, -1, 255, 0, false, true); - return 0; -} - -void MidiDriver_MT32::send(uint32 b) { - _synth->playMsg(b); -} - -void MidiDriver_MT32::setPitchBendRange(byte channel, uint range) { - if (range > 24) { - printf("setPitchBendRange() called with range > 24: %d", range); - } - byte benderRangeSysex[9]; - benderRangeSysex[0] = 0x41; // Roland - benderRangeSysex[1] = channel; - benderRangeSysex[2] = 0x16; // MT-32 - benderRangeSysex[3] = 0x12; // Write - benderRangeSysex[4] = 0x00; - benderRangeSysex[5] = 0x00; - benderRangeSysex[6] = 0x04; - benderRangeSysex[7] = (byte)range; - benderRangeSysex[8] = MT32Emu::Synth::calcSysexChecksum(&benderRangeSysex[4], 4, 0); - sysEx(benderRangeSysex, 9); -} - -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 player callback handler - setTimerCallback(NULL, NULL); - // Detach the mixer callback handler - _mixer->stopHandle(_handle); - - _synth->close(); - delete _synth; - _synth = NULL; -} - -void MidiDriver_MT32::generateSamples(int16 *data, int len) { - _synth->render(data, len); -} - -uint32 MidiDriver_MT32::property(int prop, uint32 param) { - switch (prop) { - case PROP_CHANNEL_MASK: - _channelMask = param & 0xFFFF; - return 1; - } - - return 0; -} - -MidiChannel *MidiDriver_MT32::allocateChannel() { - MidiChannel_MT32 *chan; - uint i; - - for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) { - if (i == 9 || !(_channelMask & (1 << i))) - continue; - chan = &_midiChannels[i]; - if (chan->allocate()) { - return chan; - } - } - return NULL; -} - -MidiChannel *MidiDriver_MT32::getPercussionChannel() { - return &_midiChannels[9]; -} - -// This code should be used when calling the timer callback from the mixer thread is undesirable. -// Note that it results in less accurate timing. -#if 0 -class MidiEvent_MT32 { -public: - MidiEvent_MT32 *_next; - uint32 _msg; // 0xFFFFFFFF indicates a sysex message - byte *_data; - uint32 _len; - - MidiEvent_MT32(uint32 msg, byte *data, uint32 len) { - _msg = msg; - if (len > 0) { - _data = new byte[len]; - memcpy(_data, data, len); - } - _len = len; - _next = NULL; - } - - MidiEvent_MT32() { - if (_len > 0) - delete _data; - } -}; - -class MidiDriver_ThreadedMT32 : public MidiDriver_MT32 { -private: - OSystem::MutexRef _eventMutex; - MidiEvent_MT32 *_events; - Timer::TimerProc _timer_proc; - - void pushMidiEvent(MidiEvent_MT32 *event); - MidiEvent_MT32 *popMidiEvent(); - -protected: - void send(uint32 b); - void sysEx(byte *msg, uint16 length); - -public: - MidiDriver_ThreadedMT32(SoundMixer *mixer); - virtual ~MidiDriver_ThreadedMT32(); - - void onTimer(); - void close(); - void setTimerCallback(void *timer_param, Timer::TimerProc timer_proc); -}; - - -MidiDriver_ThreadedMT32::MidiDriver_ThreadedMT32(SoundMixer *mixer) : MidiDriver_MT32(mixer) { - _eventMutex = g_system->createMutex(); - _events = NULL; - _timer_proc = NULL; -} - -MidiDriver_ThreadedMT32::~MidiDriver_ThreadedMT32() { - g_system->deleteMutex(_eventMutex); -} - -void MidiDriver_ThreadedMT32::close() { - MidiDriver_MT32::close(); - while ((popMidiEvent() != NULL)) { - // Just eat any leftover events - } -} - -void MidiDriver_ThreadedMT32::setTimerCallback(void *timer_param, Timer::TimerProc timer_proc) { - if (!_timer_proc || !timer_proc) { - if (_timer_proc) - g_timer->removeTimerProc(_timer_proc); - _timer_proc = timer_proc; - if (timer_proc) - g_timer->installTimerProc(timer_proc, getBaseTempo(), timer_param); - } -} - -void MidiDriver_ThreadedMT32::pushMidiEvent(MidiEvent_MT32 *event) { - g_system->lockMutex(_eventMutex); - if (_events == NULL) { - _events = event; - } else { - MidiEvent_MT32 *last = _events; - while (last->_next != NULL) - last = last->_next; - last->_next = event; - } - g_system->unlockMutex(_eventMutex); -} - -MidiEvent_MT32 *MidiDriver_ThreadedMT32::popMidiEvent() { - MidiEvent_MT32 *event; - g_system->lockMutex(_eventMutex); - event = _events; - if (event != NULL) - _events = event->_next; - g_system->unlockMutex(_eventMutex); - return event; -} - -void MidiDriver_ThreadedMT32::send(uint32 b) { - MidiEvent_MT32 *event = new MidiEvent_MT32(b, NULL, 0); - pushMidiEvent(event); -} - -void MidiDriver_ThreadedMT32::sysEx(byte *msg, uint16 length) { - MidiEvent_MT32 *event = new MidiEvent_MT32(0xFFFFFFFF, msg, length); - pushMidiEvent(event); -} - -void MidiDriver_ThreadedMT32::onTimer() { - MidiEvent_MT32 *event; - while ((event = popMidiEvent()) != NULL) { - if (event->_msg == 0xFFFFFFFF) { - MidiDriver_MT32::sysEx(event->_data, event->_len); - } else { - MidiDriver_MT32::send(event->_msg); - } - delete event; - } -} -#endif - -//////////////////////////////////////// -// -// 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 |