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 #include "ultima/ultima4/sound/music.h"
24 #include "ultima/ultima4/sound/sound.h"
25 #include "ultima/ultima4/core/config.h"
26 #include "ultima/ultima4/core/settings.h"
27 #include "ultima/ultima4/core/utils.h"
28 #include "ultima/ultima4/events/event_handler.h"
29 #include "ultima/ultima4/game/context.h"
30 #include "ultima/ultima4/map/location.h"
31 #include "ultima/ultima4/ultima4.h"
32 #include "ultima/shared/core/file.h"
33 #include "audio/decoders/mp3.h"
34 #include "audio/mods/mod_xm_s3m.h"
35 #include "audio/midiparser.h"
36
37 namespace Ultima {
38 namespace Ultima4 {
39
40 Music *g_music;
41
Music(Audio::Mixer * mixer)42 Music::Music(Audio::Mixer *mixer) :
43 Audio::MidiPlayer(), _mixer(mixer), _introMid(TOWNS) {
44 g_music = this;
45 Audio::MidiPlayer::createDriver();
46
47 int ret = _driver->open();
48 if (ret == 0) {
49 if (_nativeMT32)
50 _driver->sendMT32Reset();
51 else
52 _driver->sendGMReset();
53
54 _driver->setTimerCallback(this, &timerCallback);
55 }
56
57
58 _filenames.reserve(MAX);
59 _filenames.push_back(""); // filename for MUSIC_NONE;
60
61 /*
62 * load music track filenames from xml config file
63 */
64 const Config *config = Config::getInstance();
65
66 Std::vector<ConfigElement> musicConfs = config->getElement("music").getChildren();
67 Std::vector<ConfigElement>::const_iterator i = musicConfs.begin();
68 Std::vector<ConfigElement>::const_iterator theEnd = musicConfs.end();
69 for (; i != theEnd; ++i) {
70 if (i->getName() != "track")
71 continue;
72
73 _filenames.push_back(i->getString("file"));
74 }
75 }
76
~Music()77 Music::~Music() {
78 stop();
79 g_music = nullptr;
80 }
81
sendToChannel(byte channel,uint32 b)82 void Music::sendToChannel(byte channel, uint32 b) {
83 if (!_channelsTable[channel]) {
84 _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
85 // If a new channel is allocated during the playback, make sure
86 // its volume is correctly initialized.
87 if (_channelsTable[channel])
88 _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
89 }
90
91 if (_channelsTable[channel])
92 _channelsTable[channel]->send(b);
93 }
94
playMusic(Type music)95 void Music::playMusic(Type music) {
96 playMusic(_filenames[music]);
97 }
98
playMapMusic()99 void Music::playMapMusic() {
100 playMusic(g_context->_location->_map->_music);
101 }
102
playMusic(const Common::String & filename)103 void Music::playMusic(const Common::String &filename) {
104 stop();
105
106 // First try opening the file with whatever filename is provided
107 if (startMusic(filename))
108 return;
109
110 // TODO: Since the player doesn't yet support xu4 .it files,
111 // try starting the file with other extensions - which some have
112 const char *const EXTENSIONS[2] = { ".mp3", ".mid" };
113 for (int idx = 0; idx < 2; ++idx) {
114 size_t dotIndex = filename.findLastOf('.');
115 Common::String fname = (dotIndex != Common::String::npos) ?
116 Common::String(filename.c_str(), dotIndex) + EXTENSIONS[idx] :
117 filename + EXTENSIONS[idx];
118 if (startMusic(fname))
119 return;
120 }
121
122 // At this point, we couldn't open the given music file
123 warning("No support for playing music file - %s", filename.c_str());
124 }
125
startMusic(const Common::String & filename)126 bool Music::startMusic(const Common::String &filename) {
127 Common::File musicFile;
128 if (!musicFile.open(Common::String::format("data/mid/%s", filename.c_str())))
129 // No such file exists
130 return false;
131
132 #ifdef USE_MAD
133 if (filename.hasSuffixIgnoreCase(".mp3")) {
134 Audio::SeekableAudioStream *audioStream = Audio::makeMP3Stream(
135 musicFile.readStream(musicFile.size()), DisposeAfterUse::YES);
136 _mixer->playStream(Audio::Mixer::kMusicSoundType,
137 &_soundHandle, audioStream);
138 return true;
139
140 } else
141 #endif
142 if (filename.hasSuffixIgnoreCase(".mid")) {
143 // Load MIDI resource data
144 int midiMusicSize = musicFile.size();
145 free(_midiData);
146 _midiData = (byte *)malloc(midiMusicSize);
147 musicFile.read(_midiData, midiMusicSize);
148 musicFile.close();
149
150 MidiParser *parser = MidiParser::createParser_SMF();
151 if (parser->loadMusic(_midiData, midiMusicSize)) {
152 parser->setTrack(0);
153 parser->setMidiDriver(this);
154 parser->setTimerRate(_driver->getBaseTempo());
155 parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
156
157 _parser = parser;
158
159 syncVolume();
160
161 _isLooping = false;
162 _isPlaying = true;
163 return true;
164 } else {
165 delete parser;
166 return false;
167 }
168 } else {
169 return false;
170 }
171 }
172
stop()173 void Music::stop() {
174 _mixer->stopHandle(_soundHandle);
175 Audio::MidiPlayer::stop();
176 }
177
introSwitch(int n)178 void Music::introSwitch(int n) {
179 if (n > NONE &&n < MAX) {
180 _introMid = static_cast<Type>(n);
181 intro();
182 }
183 }
184
185 } // End of namespace Ultima4
186 } // End of namespace Ultima
187