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