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