1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 //
26 // ID Engine
27 // ID_SD.c - Sound Manager for Wolfenstein 3D
28 // v1.3 (revised for **********, screwed with for Blake Stone)
29 // By Jason Blochowiak
30 //
31
32 //
33 // This module handles dealing with generating sound on the appropriate
34 // hardware
35 //
36 // Depends on: User Mgr (for parm checking)
37 //
38 // Globals:
39 // For User Mgr:
40 // SoundSourcePresent - Sound Source thingie present?
41 // SoundBlasterPresent - SoundBlaster card present?
42 // AdLibPresent - AdLib card present?
43 // SoundMode - What device is used for sound effects
44 // (Use SM_SetSoundMode() to set)
45 // MusicMode - What device is used for music
46 // (Use SM_SetMusicMode() to set)
47 // DigiMode - What device is used for digitized sound effects
48 // (Use SM_SetDigiDevice() to set)
49 //
50 // For Cache Mgr:
51 // NeedsDigitized - load digitized sounds?
52 // NeedsMusic - load music?
53 //
54
55
56 #include "id_sd.h"
57 #include "3d_def.h"
58 #include "bstone_audio_mixer.h"
59 #include "bstone_memory_binary_reader.h"
60
61 extern uint16_t sdStartPCSounds;
62 extern uint16_t sdStartALSounds;
63 extern int16_t sdLastSound;
64 extern int16_t DigiMap[];
65
66
67 // Global variables
68 bool sd_has_audio = false;
69 bool sd_is_sound_enabled = false;
70 bool sd_is_music_enabled = false;
71 std::atomic<uint32_t> TimeCount;
72
73 uint8_t** SoundTable;
74
75 // Internal variables
76 static bool SD_Started;
77 bool nextsoundpos;
78
79 uint16_t* DigiList;
80
81 // AdLib variables
82 bool sqActive;
83 uint16_t* sqHack;
84 uint16_t sqHackLen;
85 bool sqPlayedOnce;
86
87 // Internal routines
88
89 // BBi
90 static int music_index = -1;
91 static bstone::AudioMixer mixer;
92
93 int sd_sfx_volume = ::sd_default_sfx_volume;
94 int sd_music_volume = ::sd_default_music_volume;
95
96 //
97 // Stuff for digitized sounds
98 //
99
SDL_SetupDigi()100 void SDL_SetupDigi()
101 {
102 const uint16_t* p;
103 int pg;
104 int i;
105
106 p = static_cast<const uint16_t*>(PM_GetPage(ChunksInFile - 1));
107 pg = PMSoundStart;
108 for (i = 0; i < static_cast<int>(PMPageSize / (2 * 2)); ++i) {
109 if (pg >= ChunksInFile - 1) {
110 break;
111 }
112 pg += (bstone::Endian::le(p[1]) + (PMPageSize - 1)) / PMPageSize;
113 p += 2;
114 }
115 DigiList = new uint16_t[i * 2];
116
117 const uint16_t* src_list = static_cast<const uint16_t*>(
118 ::PM_GetPage(ChunksInFile - 1));
119
120 bstone::Endian::le(src_list, i * 2, DigiList);
121
122 for (i = 0; i < sdLastSound; i++) {
123 DigiMap[i] = -1;
124 }
125 }
126
127 ///////////////////////////////////////////////////////////////////////////
128 //
129 // SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
130 // emulating an AdLib) present
131 //
132 ///////////////////////////////////////////////////////////////////////////
SDL_DetectAdLib()133 static bool SDL_DetectAdLib()
134 {
135 return true;
136 }
137
138 ////////////////////////////////////////////////////////////////////////////
139 //
140 // SDL_ShutDevice() - turns off whatever device was being used for sound fx
141 //
142 ////////////////////////////////////////////////////////////////////////////
SDL_ShutDevice()143 static void SDL_ShutDevice()
144 {
145 sd_is_sound_enabled = false;
146 }
147
148 ///////////////////////////////////////////////////////////////////////////
149 //
150 // SDL_StartDevice() - turns on whatever device is to be used for sound fx
151 //
152 ///////////////////////////////////////////////////////////////////////////
SDL_StartDevice()153 static void SDL_StartDevice()
154 {
155 }
156
SD_EnableSound(bool enable)157 bool SD_EnableSound(
158 bool enable)
159 {
160 ::SD_StopSound();
161
162 if (enable && !::sd_has_audio) {
163 enable = false;
164 }
165
166 auto table_offset = (enable ? ::sdStartALSounds : sdStartPCSounds);
167
168 if (::sd_is_sound_enabled != enable) {
169 ::SDL_ShutDevice();
170 ::sd_is_sound_enabled = enable;
171 ::SoundTable = &::audiosegs[table_offset];
172 ::SDL_StartDevice();
173 }
174
175 return enable;
176 }
177
SD_EnableMusic(bool enable)178 bool SD_EnableMusic(
179 bool enable)
180 {
181 ::SD_MusicOff();
182
183 ::sd_is_music_enabled = enable;
184
185 return enable;
186 }
187
SD_Startup()188 void SD_Startup()
189 {
190 if (SD_Started) {
191 return;
192 }
193
194 TimeCount = 0;
195
196 ::SD_EnableSound(false);
197 ::SD_EnableMusic(false);
198
199 ::sd_has_audio = ::SDL_DetectAdLib();
200
201 if (::sd_has_audio) {
202 auto&& snd_rate_string = ::g_args.get_option_value("snd_rate");
203
204 auto snd_rate = 0;
205
206 if (!bstone::StringHelper::lexical_cast(
207 snd_rate_string,
208 snd_rate))
209 {
210 snd_rate = 0;
211 }
212
213 auto&& snd_mix_size_string =
214 ::g_args.get_option_value("snd_mix_size");
215
216 auto snd_mix_size = 0;
217
218 if (!bstone::StringHelper::lexical_cast(
219 snd_mix_size_string,
220 snd_mix_size))
221 {
222 snd_mix_size = 0;
223 }
224
225 mixer.initialize(snd_rate, snd_mix_size);
226 } else {
227 mixer.uninitialize();
228 }
229
230 ::SDL_SetupDigi();
231
232 ::SD_Started = true;
233 }
234
SD_Shutdown()235 void SD_Shutdown()
236 {
237 if (!SD_Started) {
238 return;
239 }
240
241 mixer.uninitialize();
242
243 // Free music data
244 for (int i = 0; i < LASTMUSIC; ++i) {
245 delete [] static_cast<uint8_t*>(::audiosegs[STARTMUSIC + i]);
246 }
247
248 SD_Started = false;
249 }
250
251 ///////////////////////////////////////////////////////////////////////////
252 //
253 // SD_SoundPlaying() - returns the sound number that's playing, or 0 if
254 // no sound is playing
255 //
256 ///////////////////////////////////////////////////////////////////////////
SD_SoundPlaying()257 bool SD_SoundPlaying()
258 {
259 if (::sd_is_sound_enabled) {
260 return ::mixer.is_any_sfx_playing();
261 } else {
262 return false;
263 }
264 }
265
266 ///////////////////////////////////////////////////////////////////////////
267 //
268 // SD_StopSound() - if a sound is playing, stops it
269 //
270 ///////////////////////////////////////////////////////////////////////////
SD_StopSound()271 void SD_StopSound()
272 {
273 ::mixer.stop_all_sfx();
274 }
275
276 ///////////////////////////////////////////////////////////////////////////
277 //
278 // SD_WaitSoundDone() - waits until the current sound is done playing
279 //
280 ///////////////////////////////////////////////////////////////////////////
SD_WaitSoundDone()281 void SD_WaitSoundDone()
282 {
283 while (::SD_SoundPlaying()) {
284 ::sys_default_sleep_for();
285 }
286 }
287
288 ///////////////////////////////////////////////////////////////////////////
289 //
290 // SD_MusicOn() - turns on the sequencer
291 //
292 ///////////////////////////////////////////////////////////////////////////
SD_MusicOn()293 void SD_MusicOn()
294 {
295 ::sqActive = true;
296 ::mixer.play_adlib_music(music_index, sqHack, sqHackLen);
297 }
298
299 ///////////////////////////////////////////////////////////////////////////
300 //
301 // SD_MusicOff() - turns off the sequencer and any playing notes
302 //
303 ///////////////////////////////////////////////////////////////////////////
SD_MusicOff()304 void SD_MusicOff()
305 {
306 ::sqActive = false;
307 ::mixer.stop_music();
308 }
309
310 ///////////////////////////////////////////////////////////////////////////
311 //
312 // SD_StartMusic() - starts playing the music pointed to
313 //
314 ///////////////////////////////////////////////////////////////////////////
SD_StartMusic(int index)315 void SD_StartMusic(
316 int index)
317 {
318 ::SD_MusicOff();
319
320 ::sqPlayedOnce = false;
321
322 if (::sd_is_music_enabled) {
323 ::music_index = index;
324
325 auto music_data = reinterpret_cast<uint16_t*>(
326 ::audiosegs[STARTMUSIC + index]);
327
328 auto length = bstone::Endian::le(music_data[0]) + 2;
329
330 ::sqHack = music_data;
331 ::sqHackLen = static_cast<uint16_t>(length);
332
333 ::SD_MusicOn();
334 } else {
335 ::sqPlayedOnce = true;
336 }
337 }
338
339 // BBi
sd_play_sound(int sound_index,const void * actor,bstone::ActorType actor_type,bstone::ActorChannel actor_channel)340 void sd_play_sound(
341 int sound_index,
342 const void* actor,
343 bstone::ActorType actor_type,
344 bstone::ActorChannel actor_channel)
345 {
346 if (sound_index < 0) {
347 return;
348 }
349
350 if (!SoundTable) {
351 return;
352 }
353
354 int actor_index = -1;
355
356 if (actor) {
357 switch (actor_type) {
358 case bstone::AT_ACTOR:
359 actor_index = static_cast<int>(
360 static_cast<const objtype*>(actor) - objlist);
361 break;
362
363 case bstone::AT_DOOR:
364 actor_index = static_cast<int>(
365 static_cast<const doorobj_t*>(actor) - doorobjlist);
366 break;
367
368 default:
369 return;
370 }
371 }
372
373 const SoundCommon* sound = reinterpret_cast<SoundCommon*>(
374 SoundTable[sound_index]);
375
376 if (!sound) {
377 return;
378 }
379
380 if (::sd_is_sound_enabled && !sound) {
381 ::Quit("Uncached sound.");
382 }
383
384 int priority = bstone::Endian::le(sound->priority);
385
386 int digi_index = DigiMap[sound_index];
387
388 if (digi_index != -1) {
389 int digi_page = DigiList[(2 * digi_index) + 0];
390 int digi_length = DigiList[(2 * digi_index) + 1];
391 const void* digi_data = ::PM_GetSoundPage(digi_page);
392
393 mixer.play_pcm_sound(digi_index, priority, digi_data, digi_length,
394 actor_index, actor_type, actor_channel);
395
396 return;
397 }
398
399 if (!::sd_is_sound_enabled) {
400 return;
401 }
402
403 int data_size = audiostarts[sdStartALSounds + sound_index + 1] -
404 audiostarts[sdStartALSounds + sound_index];
405
406 mixer.play_adlib_sound(sound_index, priority, sound, data_size,
407 actor_index, actor_type, actor_channel);
408 }
409
sd_play_actor_sound(int sound_index,const objtype * actor,bstone::ActorChannel actor_channel)410 void sd_play_actor_sound(
411 int sound_index,
412 const objtype* actor,
413 bstone::ActorChannel actor_channel)
414 {
415 sd_play_sound(
416 sound_index,
417 actor,
418 bstone::AT_ACTOR,
419 actor_channel);
420 }
421
sd_play_player_sound(int sound_index,bstone::ActorChannel actor_channel)422 void sd_play_player_sound(
423 int sound_index,
424 bstone::ActorChannel actor_channel)
425 {
426 sd_play_sound(
427 sound_index,
428 player,
429 bstone::AT_ACTOR,
430 actor_channel);
431 }
432
sd_play_door_sound(int sound_index,const doorobj_t * door)433 void sd_play_door_sound(
434 int sound_index,
435 const doorobj_t* door)
436 {
437 sd_play_sound(
438 sound_index,
439 door,
440 bstone::AT_DOOR,
441 bstone::AC_VOICE);
442 }
443
sd_play_wall_sound(int sound_index)444 void sd_play_wall_sound(
445 int sound_index)
446 {
447 sd_play_sound(
448 sound_index,
449 nullptr,
450 bstone::AT_WALL,
451 bstone::AC_VOICE);
452 }
453
sd_update_positions()454 void sd_update_positions()
455 {
456 mixer.update_positions();
457 }
458
sd_is_player_channel_playing(bstone::ActorChannel channel)459 bool sd_is_player_channel_playing(
460 bstone::ActorChannel channel)
461 {
462 return mixer.is_player_channel_playing(channel);
463 }
464
sd_set_sfx_volume(int volume)465 void sd_set_sfx_volume(
466 int volume)
467 {
468 if (volume < ::sd_min_volume) {
469 volume = ::sd_min_volume;
470 }
471
472 if (volume > ::sd_max_volume) {
473 volume = ::sd_max_volume;
474 }
475
476 mixer.set_sfx_volume(static_cast<float>(volume) / ::sd_max_volume);
477 }
478
sd_set_music_volume(int volume)479 void sd_set_music_volume(
480 int volume)
481 {
482 if (volume < ::sd_min_volume) {
483 volume = ::sd_min_volume;
484 }
485
486 if (volume > ::sd_max_volume) {
487 volume = ::sd_max_volume;
488 }
489
490 mixer.set_music_volume(static_cast<float>(volume) / ::sd_max_volume);
491 }
492
sd_mute(bool mute)493 void sd_mute(
494 bool mute)
495 {
496 ::mixer.set_mute(mute);
497 }
498 // BBi
499