~ubuntu-branches/ubuntu/oneiric/scummvm/oneiric

« back to all changes in this revision

Viewing changes to audio/midiplayer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mfrom: (21.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20110525190223-4cu1pjjcmc1dgadi
Tags: 1.3.0-1
* New upstream release
  - Fixes FTBFS with ld --as-needed (Closes: #607182)
* Version debhelper build dep for debhelper override support

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ScummVM - Graphic Adventure Engine
 
2
 *
 
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.
 
6
 *
 
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.
 
11
 
 
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.
 
16
 
 
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.
 
20
 *
 
21
 * $URL$
 
22
 * $Id$
 
23
 *
 
24
 */
 
25
 
 
26
#include "audio/midiplayer.h"
 
27
#include "audio/midiparser.h"
 
28
 
 
29
#include "common/config-manager.h"
 
30
 
 
31
namespace Audio {
 
32
 
 
33
MidiPlayer::MidiPlayer() :
 
34
        _driver(0),
 
35
        _parser(0),
 
36
        _midiData(0),
 
37
        _isLooping(false),
 
38
        _isPlaying(false),
 
39
        _masterVolume(0),
 
40
        _nativeMT32(false) {
 
41
 
 
42
        memset(_channelsTable, 0, sizeof(_channelsTable));
 
43
        memset(_channelsVolume, 127, sizeof(_channelsVolume));
 
44
 
 
45
// TODO
 
46
}
 
47
 
 
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.
 
53
        stop();
 
54
 
 
55
        // Unhook & unload the driver
 
56
        if (_driver) {
 
57
                _driver->setTimerCallback(0, 0);
 
58
                _driver->close();
 
59
                delete _driver;
 
60
                _driver = 0;
 
61
        }
 
62
}
 
63
 
 
64
void MidiPlayer::createDriver(int flags) {
 
65
        MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(flags);
 
66
        _nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
 
67
 
 
68
        _driver = MidiDriver::createMidi(dev);
 
69
        assert(_driver);
 
70
        if (_nativeMT32)
 
71
                _driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
 
72
}
 
73
 
 
74
 
 
75
void MidiPlayer::setVolume(int volume) {
 
76
        volume = CLIP(volume, 0, 255);
 
77
        if (_masterVolume == volume)
 
78
                return;
 
79
 
 
80
        Common::StackLock lock(_mutex);
 
81
 
 
82
        _masterVolume = volume;
 
83
        for (int i = 0; i < kNumChannels; ++i) {
 
84
                if (_channelsTable[i]) {
 
85
                        _channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
 
86
                }
 
87
        }
 
88
}
 
89
 
 
90
void MidiPlayer::syncVolume() {
 
91
        int volume = ConfMan.getInt("music_volume");
 
92
        if (ConfMan.getBool("mute")) {
 
93
                volume = -1;
 
94
        }
 
95
        setVolume(volume);
 
96
}
 
97
 
 
98
 
 
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])
 
111
                        return;
 
112
        }
 
113
 
 
114
        sendToChannel(ch, b);
 
115
}
 
116
 
 
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?
 
123
        }
 
124
        if (_channelsTable[ch]) {
 
125
                _channelsTable[ch]->send(b);
 
126
        }
 
127
}
 
128
 
 
129
void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
 
130
        switch (type) {
 
131
        case 0x2F:      // End of Track
 
132
                endOfTrack();
 
133
                break;
 
134
        default:
 
135
                //warning("Unhandled meta event: %02x", type);
 
136
                break;
 
137
        }
 
138
}
 
139
 
 
140
void MidiPlayer::endOfTrack() {
 
141
        if (_isLooping) {
 
142
                assert(_parser);
 
143
                _parser->jumpToTick(0);
 
144
        } else
 
145
                stop();
 
146
}
 
147
 
 
148
void MidiPlayer::timerCallback(void *data) {
 
149
        assert(data);
 
150
        ((MidiPlayer *)data)->onTimer();
 
151
}
 
152
 
 
153
void MidiPlayer::onTimer() {
 
154
        Common::StackLock lock(_mutex);
 
155
 
 
156
        // TODO: Maybe we can replace _isPlaying
 
157
        // by a simple check for "_parser != 0" ?
 
158
 
 
159
        if (_isPlaying && _parser) {
 
160
                _parser->onTimer();
 
161
        }
 
162
}
 
163
 
 
164
 
 
165
void MidiPlayer::stop() {
 
166
        Common::StackLock lock(_mutex);
 
167
 
 
168
        _isPlaying = false;
 
169
        if (_parser) {
 
170
                _parser->unloadMusic();
 
171
 
 
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);
 
177
 
 
178
                delete _parser;
 
179
                _parser = NULL;
 
180
        }
 
181
 
 
182
        free(_midiData);
 
183
        _midiData = 0;
 
184
}
 
185
 
 
186
void MidiPlayer::pause() {
 
187
//      debugC(2, kDraciSoundDebugLevel, "Pausing track %d", _track);
 
188
        _isPlaying = false;
 
189
        setVolume(-1);  // FIXME: This should be 0, shouldn't it?
 
190
}
 
191
 
 
192
void MidiPlayer::resume() {
 
193
//      debugC(2, kDraciSoundDebugLevel, "Resuming track %d", _track);
 
194
        syncVolume();
 
195
        _isPlaying = true;
 
196
}
 
197
 
 
198
} // End of namespace Audio