/* 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 "audio/midiplayer.h" #include "audio/midiparser.h" #include "common/config-manager.h" namespace Audio { MidiPlayer::MidiPlayer() : _driver(0), _parser(0), _isLooping(false), _isPlaying(false), _masterVolume(0), _nativeMT32(false) { memset(_channelsTable, 0, sizeof(_channelsTable)); memset(_channelsVolume, 127, sizeof(_channelsVolume)); // TODO } MidiPlayer::~MidiPlayer() { // TODO } void MidiPlayer::setVolume(int volume) { volume = CLIP(volume, 0, 255); if (_masterVolume == volume) return; Common::StackLock lock(_mutex); _masterVolume = volume; for (int i = 0; i < kNumChannels; ++i) { if (_channelsTable[i]) { _channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255); } } } void MidiPlayer::syncVolume() { int volume = ConfMan.getInt("music_volume"); if (ConfMan.getBool("mute")) { volume = -1; } setVolume(volume); } void MidiPlayer::send(uint32 b) { byte channel = (byte)(b & 0x0F); if ((b & 0xFFF0) == 0x07B0) { // Adjust volume changes by master volume byte volume = (byte)((b >> 16) & 0x7F); _channelsVolume[channel] = volume; volume = volume * _masterVolume / 255; b = (b & 0xFF00FFFF) | (volume << 16); } else if ((b & 0xFFF0) == 0x007BB0) { // Only respond to All Notes Off if this channel // has currently been allocated if (!_channelsTable[channel]) return; } sendToChannel(channel, b); } void MidiPlayer::sendToChannel(byte channel, uint32 b) { if (!_channelsTable[channel]) { _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); // TODO: Some engines overload this method to insert code at this // point which calls the channel's volume() method. // Does this make sense, and should we maybe do it in general? } if (_channelsTable[channel]) _channelsTable[channel]->send(b); } void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) { switch (type) { case 0x2F: // End of Track endOfTrack(); break; default: //warning("Unhandled meta event: %02x", type); break; } } void MidiPlayer::endOfTrack() { if (_isLooping) { assert(_parser); _parser->jumpToTick(0); } else stop(); } #if 0 void MidiPlayer::onTimer(void *data) { assert(data); ((MidiPlayer *)data)->onTimer(); } void MidiPlayer::onTimer() { Common::StackLock lock(_mutex); // FIXME: There are various alternatives for this function: #if 0 if (_parser) { _parser->onTimer(); } #elif 0 if (_isPlaying) { assert(_parser); _parser->onTimer(); } #endif } #endif void MidiPlayer::stop() { Common::StackLock lock(_mutex); _isPlaying = false; if (_parser) { _parser->unloadMusic(); _parser = NULL; } } void MidiPlayer::pause() { // debugC(2, kDraciSoundDebugLevel, "Pausing track %d", _track); setVolume(-1); // FIXME: This should be 0, shouldn't it? _isPlaying = false; } void MidiPlayer::resume() { // debugC(2, kDraciSoundDebugLevel, "Resuming track %d", _track); syncVolume(); _isPlaying = true; } } // End of namespace Audio