diff options
Diffstat (limited to 'engines/sky/music/mt32music.cpp')
-rw-r--r-- | engines/sky/music/mt32music.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/engines/sky/music/mt32music.cpp b/engines/sky/music/mt32music.cpp new file mode 100644 index 0000000000..a6bcbf4d05 --- /dev/null +++ b/engines/sky/music/mt32music.cpp @@ -0,0 +1,169 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "sky/music/mt32music.h" +#include "sky/music/gmchannel.h" +#include "common/util.h" +#include "common/system.h" +#include "sound/mididrv.h" + +namespace Sky { + +void MT32Music::passTimerFunc(void *param) { + + ((MT32Music*)param)->timerCall(); +} + +MT32Music::MT32Music(MidiDriver *pMidiDrv, Disk *pDisk) + : MusicBase(pDisk) { + + _driverFileBase = 60200; + _midiDrv = pMidiDrv; + int midiRes = _midiDrv->open(); + if (midiRes != 0) + error("Can't open midi device. Errorcode: %d",midiRes); + _timerCount = 0; + _midiDrv->setTimerCallback(this, passTimerFunc); +} + +MT32Music::~MT32Music(void) { + + _midiDrv->close(); + _midiDrv->setTimerCallback(NULL, NULL); + delete _midiDrv; +} + +void MT32Music::timerCall(void) { + _timerCount += _midiDrv->getBaseTempo(); + if (_timerCount > (1000000 / 50)) { + // call pollMusic() 50 times per second + _timerCount -= 1000000 / 50; + if (_musicData != NULL) + pollMusic(); + } +} + +void MT32Music::setVolume(uint8 volume) { + uint8 sysEx[10] = "\x41\x10\x16\x12\x10\x00\x16\x00\x00"; + _musicVolume = volume; + sysEx[7] = (volume > 100) ? 100 : volume; + sysEx[8] = 0x00; + for (uint8 cnt = 4; cnt < 8; cnt++) + sysEx[8] -= sysEx[cnt]; + sysEx[8] &= 0x7F; + _midiDrv->sysEx(sysEx, 9); +} + +void MT32Music::setupPointers(void) { + + _musicDataLoc = (_musicData[0x7DD] << 8) | _musicData[0x7DC]; + _sysExSequence = ((_musicData[0x7E1] << 8) | _musicData[0x7E0]) + _musicData; +} + +void MT32Music::setupChannels(uint8 *channelData) { + + _numberOfChannels = channelData[0]; + channelData++; + for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) { + uint16 chDataStart = ((channelData[(cnt << 1) | 1] << 8) | channelData[cnt << 1]) + _musicDataLoc; + _channels[cnt] = new GmChannel(_musicData, chDataStart, _midiDrv, NULL, NULL); + _channels[cnt]->updateVolume(_musicVolume); + } +} + +bool MT32Music::processPatchSysEx(uint8 *sysExData) { + + uint8 sysExBuf[15]; + uint8 crc = 0; + if (sysExData[0] & 0x80) + return false; + + // decompress data from stream + sysExBuf[0] = 0x41; sysExBuf[1] = 0x10; sysExBuf[2] = 0x16; sysExBuf[3] = 0x12; sysExBuf[4] = 0x5; + sysExBuf[5] = sysExData[0] >> 4; // patch offset part 1 + sysExBuf[6] = (sysExData[0] & 0xF) << 3; // patch offset part 2 + sysExBuf[7] = sysExData[1] >> 6; // timbre group + sysExBuf[8] = sysExData[1] & 0x3F; // timbre num + sysExBuf[9] = sysExData[2] & 0x3F; // key shift + sysExBuf[10] = sysExData[3] & 0x7F; // fine tune + sysExBuf[11] = sysExData[4] & 0x7F; // bender range + sysExBuf[12] = sysExData[2] >> 6; // assign mode + sysExBuf[13] = sysExData[3] >> 7; // reverb switch + for (uint8 cnt = 4; cnt < 14; cnt++) + crc -= sysExBuf[cnt]; + sysExBuf[14] = crc & 0x7F; // crc + _midiDrv->sysEx(sysExBuf, 15); + g_system->delayMillis(5); + return true; +} + +void MT32Music::startDriver(void) { + + // setup timbres and patches using SysEx data + uint8* sysExData = _sysExSequence; + uint8 timbreNum = sysExData[0]; + uint8 cnt, crc; + sysExData++; + uint8 sendBuf[256]; + uint8 len; + sendBuf[0] = 0x41; sendBuf[1] = 0x10; sendBuf[2] = 0x16; sendBuf[3] = 0x12; + for (cnt = 0; cnt < timbreNum; cnt++) { + len = 7; + crc = 0; + // Timbre address + sendBuf[4] = 0x8 | (sysExData[0] >> 6); + sendBuf[5] = (sysExData[0] & 0x3F) << 1; + sendBuf[6] = 0xA; + sysExData++; + crc -= sendBuf[4] + sendBuf[5] + sendBuf[6]; + uint8 dataLen = sysExData[0]; + sysExData++; + // Timbre data: + do { + uint8 rlVal = 1; + uint8 codeVal = sysExData[0]; + sysExData++; + + if (codeVal & 0x80) { + codeVal &= 0x7F; + rlVal = sysExData[0]; + sysExData++; + dataLen--; + } + for (uint8 cnt2 = 0; cnt2 < rlVal; cnt2++) { + sendBuf[len] = codeVal; + len++; + crc -= codeVal; + } + dataLen--; + } while (dataLen > 0); + sendBuf[len] = crc & 0x7F; + len++; + _midiDrv->sysEx(sendBuf, len); + g_system->delayMillis (5); + } + + while (processPatchSysEx(sysExData)) + sysExData += 5; +} + +} // End of namespace Sky |