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 "twine/audio/music.h"
24 #include "audio/audiostream.h"
25 #include "audio/midiparser.h"
26 #include "audio/midiplayer.h"
27 #include "backends/audiocd/audiocd.h"
28 #include "common/debug.h"
29 #include "common/system.h"
30 #include "common/textconsole.h"
31 #include "twine/detection.h"
32 #include "twine/resources/hqr.h"
33 #include "twine/resources/resources.h"
34 #include "twine/twine.h"
35
36 namespace TwinE {
37
38 /** MP3 music folder */
39 #define MUSIC_FOLDER "music"
40 /**
41 * LBA1 default number of tracks
42 * <pre>
43 * TRACK 01 MODE1/2352
44 * INDEX 01 00:00:00
45 * TRACK 02 AUDIO
46 * INDEX 01 10:47:52
47 * TRACK 03 AUDIO
48 * INDEX 01 14:02:01
49 * TRACK 04 AUDIO
50 * INDEX 01 17:02:19
51 * TRACK 05 AUDIO
52 * INDEX 01 19:34:45
53 * TRACK 06 AUDIO
54 * INDEX 01 22:22:34
55 * TRACK 07 AUDIO
56 * INDEX 01 25:09:32
57 * TRACK 08 AUDIO
58 * INDEX 01 26:47:72
59 * TRACK 09 AUDIO
60 * INDEX 01 30:29:07
61 * TRACK 10 AUDIO
62 * INDEX 01 32:04:62
63 * </pre>
64 */
65 #define NUM_CD_TRACKS 10
66
TwinEMidiPlayer(TwinEEngine * engine)67 TwinEMidiPlayer::TwinEMidiPlayer(TwinEEngine* engine) : _engine(engine) {
68 MidiPlayer::createDriver();
69
70 int ret = _driver->open();
71 if (ret == 0) {
72 if (_nativeMT32) {
73 _driver->sendMT32Reset();
74 } else {
75 _driver->sendGMReset();
76 }
77 _driver->setTimerCallback(this, &timerCallback);
78 }
79 }
80
play(byte * buf,int size,bool loop)81 void TwinEMidiPlayer::play(byte *buf, int size, bool loop) {
82 if (_parser == nullptr) {
83 if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
84 _parser = MidiParser::createParser_XMIDI();
85 } else {
86 _parser = MidiParser::createParser_SMF();
87 }
88 }
89
90 if (!_parser->loadMusic(buf, size)) {
91 warning("Failed to load midi music");
92 return;
93 }
94 _parser->setTrack(0);
95 _parser->setMidiDriver(this);
96 _parser->setTimerRate(_driver->getBaseTempo());
97 _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
98
99 syncVolume();
100
101 _isLooping = loop;
102 _isPlaying = true;
103 }
104
Music(TwinEEngine * engine)105 Music::Music(TwinEEngine *engine) : _engine(engine), _midiPlayer(engine) {
106 }
107
musicVolume(int32 volume)108 void Music::musicVolume(int32 volume) {
109 _engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
110 _midiPlayer.setVolume(volume);
111 }
112
musicFadeIn()113 void Music::musicFadeIn() {
114 int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
115 // TODO implement fade in
116 musicVolume(volume);
117 }
118
musicFadeOut()119 void Music::musicFadeOut() {
120 int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
121 // TODO implement fade out
122 musicVolume(volume);
123 }
124
playTrackMusicCd(int32 track)125 bool Music::playTrackMusicCd(int32 track) {
126 if (!_engine->_cfgfile.UseCD) {
127 return false;
128 }
129 AudioCDManager *cdrom = g_system->getAudioCDManager();
130 if (_engine->isDotEmuEnhanced()) {
131 track += 1;
132 }
133 return cdrom->play(track, 1, 0, 0);
134 }
135
stopTrackMusicCd()136 void Music::stopTrackMusicCd() {
137 AudioCDManager *cdrom = g_system->getAudioCDManager();
138 cdrom->stop();
139 }
140
playTrackMusic(int32 track)141 bool Music::playTrackMusic(int32 track) {
142 if (track == -1) {
143 stopMusic();
144 return true;
145 }
146 if (!_engine->_cfgfile.Sound) {
147 return false;
148 }
149
150 if (track == currentMusic) {
151 return true;
152 }
153
154 stopMusic();
155 if (playTrackMusicCd(track)) {
156 currentMusic = track;
157 debug("Play cd music track %i", track);
158 return true;
159 }
160 if (playMidiMusic(track)) {
161 currentMusic = track;
162 debug("Play midi music track %i", track);
163 return true;
164 }
165 warning("Failed to play track %i", track);
166 return false;
167 }
168
stopTrackMusic()169 void Music::stopTrackMusic() {
170 if (!_engine->_cfgfile.Sound) {
171 return;
172 }
173
174 musicFadeOut();
175 stopTrackMusicCd();
176 }
177
playMidiMusic(int32 midiIdx,int32 loop)178 bool Music::playMidiMusic(int32 midiIdx, int32 loop) {
179 if (!_engine->_cfgfile.Sound || _engine->_cfgfile.MidiType == MIDIFILE_NONE) {
180 debug("midi disabled - skip playing %i", midiIdx);
181 return false;
182 }
183
184 if (midiIdx == currentMusic) {
185 debug("already playing %i", midiIdx);
186 return true;
187 }
188
189 stopMusic();
190 currentMusic = midiIdx;
191
192 const char *filename;
193 if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
194 filename = Resources::HQR_MIDI_MI_DOS_FILE;
195 } else {
196 filename = Resources::HQR_MIDI_MI_WIN_FILE;
197 }
198
199 if (midiPtr) {
200 musicFadeOut();
201 stopMidiMusic();
202 }
203
204 if (_engine->_gameFlags & TF_DOTEMU_ENHANCED) {
205 const Common::String &trackName = Common::String::format("lba1-%02i", midiIdx + 1);
206 Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
207 if (stream != nullptr) {
208 const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
209 _engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
210 Audio::makeLoopingAudioStream(stream, loop), volume);
211 return true;
212 }
213 }
214
215 int32 midiSize = HQR::getAllocEntry(&midiPtr, filename, midiIdx);
216 if (midiSize == 0) {
217 debug("Could not find midi file for index %i", midiIdx);
218 return false;
219 }
220 debug("Play midi file for index %i", midiIdx);
221 _midiPlayer.play(midiPtr, midiSize, loop == 0 || loop > 1);
222 return true;
223 }
224
stopMidiMusic()225 void Music::stopMidiMusic() {
226 if (_engine->_gameFlags & TF_DOTEMU_ENHANCED) {
227 _engine->_system->getMixer()->stopHandle(_midiHandle);
228 }
229
230 _midiPlayer.stop();
231 free(midiPtr);
232 midiPtr = nullptr;
233 }
234
initCdrom()235 bool Music::initCdrom() {
236 AudioCDManager* cdrom = g_system->getAudioCDManager();
237 _engine->_cfgfile.UseCD = cdrom->open();
238 return _engine->_cfgfile.UseCD;
239 }
240
stopMusic()241 void Music::stopMusic() {
242 stopTrackMusic();
243 stopMidiMusic();
244 currentMusic = -1;
245 }
246
247 } // namespace TwinE
248