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 */
22
23 // FIXME: This code is taken from SAGA and needs more work (e.g. setVolume).
24
25 // MIDI and digital music class
26
27 #include "made/music.h"
28 #include "made/redreader.h"
29 #include "made/resource.h"
30
31 #include "audio/midiparser.h"
32 #include "audio/miles.h"
33
34 #include "common/file.h"
35 #include "common/stream.h"
36
37 namespace Made {
38
MusicPlayer(bool milesAudio)39 MusicPlayer::MusicPlayer(bool milesAudio) : _isGM(false),_milesAudioMode(false) {
40 MusicType musicType = MT_INVALID;
41 if (milesAudio) {
42 MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
43 musicType = MidiDriver::getMusicType(dev);
44 Common::SeekableReadStream *adLibInstrumentStream = nullptr;
45 switch (musicType) {
46 case MT_ADLIB:
47 _milesAudioMode = true;
48 if (Common::File::exists("rtzcd.red")) {
49 // Installing Return to Zork produces both a SAMPLE.AD and
50 // a SAMPLE.OPL file, but they are identical. The resource
51 // file appears to only contain SAMPLE.AD.
52 adLibInstrumentStream = RedReader::loadFromRed("rtzcd.red", "SAMPLE.AD");
53 }
54 _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL", adLibInstrumentStream);
55 delete adLibInstrumentStream;
56 break;
57 case MT_MT32:
58 _milesAudioMode = true;
59 _driver = Audio::MidiDriver_Miles_MT32_create("");
60 break;
61 default:
62 _milesAudioMode = false;
63 MidiPlayer::createDriver();
64 break;
65 }
66 } else {
67 MidiPlayer::createDriver();
68 }
69
70 int ret = _driver->open();
71 if (ret == 0) {
72 if (musicType != MT_ADLIB) {
73 if (_nativeMT32)
74 _driver->sendMT32Reset();
75 else
76 _driver->sendGMReset();
77 }
78
79 _driver->setTimerCallback(this, &timerCallback);
80 }
81 }
82
send(uint32 b)83 void MusicPlayer::send(uint32 b) {
84 if (_milesAudioMode) {
85 _driver->send(b);
86 return;
87 }
88
89 if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
90 b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
91 }
92
93 Audio::MidiPlayer::send(b);
94 }
95
playXMIDI(GenericResource * midiResource,MusicFlags flags)96 void MusicPlayer::playXMIDI(GenericResource *midiResource, MusicFlags flags) {
97 Common::StackLock lock(_mutex);
98
99 if (_isPlaying)
100 return;
101
102 stop();
103
104 // Load XMID resource data
105
106 _isGM = true;
107
108 MidiParser *parser = MidiParser::createParser_XMIDI();
109 if (parser->loadMusic(midiResource->getData(), midiResource->getSize())) {
110 parser->setTrack(0);
111 parser->setMidiDriver(this);
112 parser->setTimerRate(_driver->getBaseTempo());
113 parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
114 parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
115
116 _parser = parser;
117
118 setVolume(127);
119
120 _isLooping = flags & MUSIC_LOOP;
121 _isPlaying = true;
122 } else {
123 delete parser;
124 }
125 }
126
playSMF(GenericResource * midiResource,MusicFlags flags)127 void MusicPlayer::playSMF(GenericResource *midiResource, MusicFlags flags) {
128 Common::StackLock lock(_mutex);
129
130 if (_isPlaying)
131 return;
132
133 stop();
134
135 // Load MIDI resource data
136
137 _isGM = true;
138
139 MidiParser *parser = MidiParser::createParser_SMF();
140 if (parser->loadMusic(midiResource->getData(), midiResource->getSize())) {
141 parser->setTrack(0);
142 parser->setMidiDriver(this);
143 parser->setTimerRate(_driver->getBaseTempo());
144 parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
145
146 _parser = parser;
147
148 setVolume(127);
149
150 _isLooping = flags & MUSIC_LOOP;
151 _isPlaying = true;
152 } else {
153 delete parser;
154 }
155 }
156
pause()157 void MusicPlayer::pause() {
158 setVolume(-1);
159 _isPlaying = false;
160 }
161
resume()162 void MusicPlayer::resume() {
163 setVolume(127);
164 _isPlaying = true;
165 }
166
167 } // End of namespace Made
168