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 "kyra/sound/sound_intern.h"
24 #include "kyra/resource/resource.h"
25
26 #include "audio/softsynth/fmtowns_pc98/towns_pc98_driver.h"
27
28 #include "common/config-manager.h"
29
30 #include "backends/audiocd/audiocd.h"
31
32 #include "audio/audiostream.h"
33 #include "audio/decoders/raw.h"
34
35 namespace Kyra {
36
SoundTownsPC98_v2(KyraEngine_v1 * vm,Audio::Mixer * mixer)37 SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
38 Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false), _currentResourceSet(0) {
39 memset(&_resInfo, 0, sizeof(_resInfo));
40 }
41
~SoundTownsPC98_v2()42 SoundTownsPC98_v2::~SoundTownsPC98_v2() {
43 delete[] _musicTrackData;
44 delete[] _sfxTrackData;
45 delete _driver;
46 for (int i = 0; i < 3; i++)
47 initAudioResourceInfo(i, 0);
48 }
49
init()50 bool SoundTownsPC98_v2::init() {
51 _driver = new TownsPC98_AudioDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ?
52 TownsPC98_AudioDriver::kType86 : TownsPC98_AudioDriver::kTypeTowns);
53
54 if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
55 if (_resInfo[_currentResourceSet])
56 if (_resInfo[_currentResourceSet]->cdaTableSize) {
57 if (!_vm->existExtractedCDAudioFiles()
58 && !_vm->isDataAndCDAudioReadFromSameCD()) {
59 _vm->warnMissingExtractedCDAudio();
60 }
61 }
62
63 // Initialize CD for audio
64 bool hasRealCD = g_system->getAudioCDManager()->open();
65
66 // FIXME: While checking for 'track1.XXX(X)' looks like
67 // a good idea, we should definitely not be doing this
68 // here. Basically our filenaming scheme could change
69 // or we could add support for other audio formats. Also
70 // this misses the possibility that we play the tracks
71 // right off CD. So we should find another way to
72 // check if we have access to CD audio.
73 Resource *r = _vm->resource();
74 if (_musicEnabled &&
75 (hasRealCD || r->exists("track1.mp3") || r->exists("track1.ogg") || r->exists("track1.flac") || r->exists("track1.fla")
76 || r->exists("track01.mp3") || r->exists("track01.ogg") || r->exists("track01.flac") || r->exists("track01.fla")))
77 _musicEnabled = 2;
78 else
79 _musicEnabled = 1;
80 _useFmSfx = false;
81
82 } else {
83 _useFmSfx = true;
84 }
85
86 bool reslt = _driver->init();
87 updateVolumeSettings();
88 return reslt;
89 }
90
initAudioResourceInfo(int set,void * info)91 void SoundTownsPC98_v2::initAudioResourceInfo(int set, void *info) {
92 if (set >= kMusicIntro && set <= kMusicFinale) {
93 delete _resInfo[set];
94 _resInfo[set] = info ? new SoundResourceInfo_TownsPC98V2(*(SoundResourceInfo_TownsPC98V2*)info) : 0;
95 }
96 }
97
selectAudioResourceSet(int set)98 void SoundTownsPC98_v2::selectAudioResourceSet(int set) {
99 if (set >= kMusicIntro && set <= kMusicFinale) {
100 if (_resInfo[set])
101 _currentResourceSet = set;
102 }
103 }
104
hasSoundFile(uint file) const105 bool SoundTownsPC98_v2::hasSoundFile(uint file) const {
106 if (file < res()->fileListSize)
107 return (res()->fileList[file] != 0);
108 return false;
109 }
110
loadSoundFile(Common::String file)111 void SoundTownsPC98_v2::loadSoundFile(Common::String file) {
112 delete[] _sfxTrackData;
113 _sfxTrackData = _vm->resource()->fileData(file.c_str(), 0);
114 }
115
process()116 void SoundTownsPC98_v2::process() {
117 g_system->getAudioCDManager()->update();
118 }
119
playTrack(uint8 track)120 void SoundTownsPC98_v2::playTrack(uint8 track) {
121 if (track == _lastTrack && _musicEnabled)
122 return;
123
124 int trackNum = -1;
125 if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
126 for (uint i = 0; i < res()->cdaTableSize; i++) {
127 if (track == (uint8)READ_LE_UINT16(&res()->cdaTable[i * 2])) {
128 trackNum = (int)READ_LE_UINT16(&res()->cdaTable[i * 2 + 1]) - 1;
129 break;
130 }
131 }
132 }
133
134 beginFadeOut();
135
136 Common::String musicFile = res()->pattern ? Common::String::format(res()->pattern, track) : (res()->fileList ? res()->fileList[track] : 0);
137 if (musicFile.empty())
138 return;
139
140 delete[] _musicTrackData;
141
142 _musicTrackData = _vm->resource()->fileData(musicFile.c_str(), 0);
143 _driver->loadMusicData(_musicTrackData, true);
144
145 if (_musicEnabled == 2 && trackNum != -1) {
146 g_system->getAudioCDManager()->play(trackNum+1, _driver->looping() ? -1 : 1, 0, 0);
147 g_system->getAudioCDManager()->update();
148 } else if (_musicEnabled) {
149 _driver->cont();
150 }
151
152 _lastTrack = track;
153 }
154
haltTrack()155 void SoundTownsPC98_v2::haltTrack() {
156 _lastTrack = -1;
157 g_system->getAudioCDManager()->stop();
158 g_system->getAudioCDManager()->update();
159 _driver->reset();
160 }
161
beginFadeOut()162 void SoundTownsPC98_v2::beginFadeOut() {
163 if (!_driver->musicPlaying())
164 return;
165
166 for (int i = 0; i < 20; i++) {
167 _driver->fadeStep();
168 _vm->delay(32);
169 }
170
171 haltTrack();
172 }
173
voicePlay(const char * file,Audio::SoundHandle * handle,uint8 volume,uint8 priority,bool)174 int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool) {
175 static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
176 static const char patternHOF[] = "%s.PCM";
177 static const char patternLOL[] = "%s.VOC";
178
179 int h = 0;
180 if (_currentSFX) {
181 while (h < kNumChannelHandles && _mixer->isSoundHandleActive(_soundChannels[h].handle))
182 h++;
183
184 if (h >= kNumChannelHandles) {
185 h = 0;
186 while (h < kNumChannelHandles && _soundChannels[h].priority > priority)
187 ++h;
188 if (h < kNumChannelHandles)
189 voiceStop(&_soundChannels[h].handle);
190 }
191
192 if (h >= kNumChannelHandles)
193 return 0;
194 }
195
196 Common::String fileName = Common::String::format( _vm->game() == GI_LOL ? patternLOL : patternHOF, file);
197
198 uint8 *data = _vm->resource()->fileData(fileName.c_str(), 0);
199 uint8 *src = data;
200 if (!src)
201 return 0;
202
203 uint16 sfxRate = rates[READ_LE_UINT16(src)];
204 src += 2;
205 bool compressed = (READ_LE_UINT16(src) & 1) ? true : false;
206 src += 2;
207 uint32 outsize = READ_LE_UINT32(src);
208 uint8 *sfx = (uint8 *)malloc(outsize);
209 uint8 *dst = sfx;
210 src += 4;
211
212 if (compressed) {
213 for (uint32 i = outsize; i;) {
214 uint8 cnt = *src++;
215 if (cnt & 0x80) {
216 cnt &= 0x7F;
217 memset(dst, *src++, cnt);
218 } else {
219 memcpy(dst, src, cnt);
220 src += cnt;
221 }
222 dst += cnt;
223 i -= cnt;
224 }
225 } else {
226 memcpy(dst, src, outsize);
227 }
228
229 for (uint32 i = 0; i < outsize; i++) {
230 uint8 cmd = sfx[i];
231 if (cmd & 0x80) {
232 cmd = ~cmd;
233 } else {
234 cmd |= 0x80;
235 if (cmd == 0xFF)
236 cmd--;
237 }
238 if (cmd < 0x80)
239 cmd = 0x80 - cmd;
240 sfx[i] = cmd;
241 }
242
243 _currentSFX = Audio::makeRawStream(sfx, outsize, sfxRate * 10, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN);
244 _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h].handle, _currentSFX, -1, volume);
245 _soundChannels[h].priority = priority;
246 if (handle)
247 *handle = _soundChannels[h].handle;
248
249 delete[] data;
250 return 1;
251 }
252
playSoundEffect(uint16 track,uint8)253 void SoundTownsPC98_v2::playSoundEffect(uint16 track, uint8) {
254 if (!_useFmSfx || !_sfxTrackData)
255 return;
256
257 _driver->loadSoundEffectData(_sfxTrackData, track);
258 }
259
updateVolumeSettings()260 void SoundTownsPC98_v2::updateVolumeSettings() {
261 if (!_driver)
262 return;
263
264 bool mute = false;
265 if (ConfMan.hasKey("mute"))
266 mute = ConfMan.getBool("mute");
267
268 _driver->setMusicVolume((mute ? 0 : ConfMan.getInt("music_volume")));
269 _driver->setSoundEffectVolume((mute ? 0 : ConfMan.getInt("sfx_volume")));
270 }
271
272 } // End of namespace Kyra
273
274