1
/* ScummVM - Graphic Adventure Engine
3
* ScummVM is the legal property of its developers, whose names
4
* are too numerous to list here. Please refer to the COPYRIGHT
5
* file distributed with this source distribution.
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public License
9
* as published by the Free Software Foundation; either version 2
10
* of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26
#include "audio/midiplayer.h"
27
#include "audio/midiparser.h"
29
#include "common/config-manager.h"
33
MidiPlayer::MidiPlayer() :
42
memset(_channelsTable, 0, sizeof(_channelsTable));
43
memset(_channelsVolume, 127, sizeof(_channelsVolume));
48
MidiPlayer::~MidiPlayer() {
49
// FIXME/TODO: In some engines, stop() was called first;
50
// in others, _driver->setTimerCallback(NULL, NULL) came first.
51
// Hopefully, this make no real difference, but we should
52
// watch out for regressions.
55
// Unhook & unload the driver
57
_driver->setTimerCallback(0, 0);
64
void MidiPlayer::createDriver(int flags) {
65
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(flags);
66
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
68
_driver = MidiDriver::createMidi(dev);
71
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
75
void MidiPlayer::setVolume(int volume) {
76
volume = CLIP(volume, 0, 255);
77
if (_masterVolume == volume)
80
Common::StackLock lock(_mutex);
82
_masterVolume = volume;
83
for (int i = 0; i < kNumChannels; ++i) {
84
if (_channelsTable[i]) {
85
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
90
void MidiPlayer::syncVolume() {
91
int volume = ConfMan.getInt("music_volume");
92
if (ConfMan.getBool("mute")) {
99
void MidiPlayer::send(uint32 b) {
100
byte ch = (byte)(b & 0x0F);
101
if ((b & 0xFFF0) == 0x07B0) {
102
// Adjust volume changes by master volume
103
byte volume = (byte)((b >> 16) & 0x7F);
104
_channelsVolume[ch] = volume;
105
volume = volume * _masterVolume / 255;
106
b = (b & 0xFF00FFFF) | (volume << 16);
107
} else if ((b & 0xFFF0) == 0x007BB0) {
108
// Only respond to All Notes Off if this channel
109
// has currently been allocated
110
if (!_channelsTable[ch])
114
sendToChannel(ch, b);
117
void MidiPlayer::sendToChannel(byte ch, uint32 b) {
118
if (!_channelsTable[ch]) {
119
_channelsTable[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
120
// TODO: Some engines overload this method to insert code at this
121
// point which calls the channel's volume() method.
122
// Does this make sense, and should we maybe do it in general?
124
if (_channelsTable[ch]) {
125
_channelsTable[ch]->send(b);
129
void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
131
case 0x2F: // End of Track
135
//warning("Unhandled meta event: %02x", type);
140
void MidiPlayer::endOfTrack() {
143
_parser->jumpToTick(0);
148
void MidiPlayer::timerCallback(void *data) {
150
((MidiPlayer *)data)->onTimer();
153
void MidiPlayer::onTimer() {
154
Common::StackLock lock(_mutex);
156
// TODO: Maybe we can replace _isPlaying
157
// by a simple check for "_parser != 0" ?
159
if (_isPlaying && _parser) {
165
void MidiPlayer::stop() {
166
Common::StackLock lock(_mutex);
170
_parser->unloadMusic();
172
// FIXME/TODO: The MidiParser destructor calls allNotesOff()
173
// but unloadMusic also does. To suppress double notes-off,
174
// we reset the midi driver of _parser before deleting it.
175
// This smells very fishy, in any case.
176
_parser->setMidiDriver(0);
186
void MidiPlayer::pause() {
187
// debugC(2, kDraciSoundDebugLevel, "Pausing track %d", _track);
189
setVolume(-1); // FIXME: This should be 0, shouldn't it?
192
void MidiPlayer::resume() {
193
// debugC(2, kDraciSoundDebugLevel, "Resuming track %d", _track);
198
} // End of namespace Audio