aboutsummaryrefslogtreecommitdiff
path: root/audio/midiplayer.cpp
diff options
context:
space:
mode:
authorMax Horn2011-03-24 16:33:17 +0100
committerMax Horn2011-03-24 16:46:46 +0100
commite9570c3a4b18984669bd17ba4c80c98c77f3f6f1 (patch)
tree9463b682bc1cd883df7b17db4978b5e4817ef927 /audio/midiplayer.cpp
parent2d4dff8cb46dbe249e5e7918aa50f6adfc5cf6ea (diff)
downloadscummvm-rg350-e9570c3a4b18984669bd17ba4c80c98c77f3f6f1.tar.gz
scummvm-rg350-e9570c3a4b18984669bd17ba4c80c98c77f3f6f1.tar.bz2
scummvm-rg350-e9570c3a4b18984669bd17ba4c80c98c77f3f6f1.zip
AUDIO: Added Audio::MidiPlayer class
This code is currently not complete, but contains enough code to allow several engines to switch their pseudo MidiDrivers to be based on this class, greatly reducing code duplication.
Diffstat (limited to 'audio/midiplayer.cpp')
-rw-r--r--audio/midiplayer.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/audio/midiplayer.cpp b/audio/midiplayer.cpp
new file mode 100644
index 0000000000..12d03d73f8
--- /dev/null
+++ b/audio/midiplayer.cpp
@@ -0,0 +1,172 @@
+/* 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