2006-03-20 17:12:09 +00:00
|
|
|
/*
|
2014-06-01 17:55:23 +00:00
|
|
|
* Portions of this file are copyright Rebirth contributors and licensed as
|
|
|
|
* described in COPYING.txt.
|
|
|
|
* Portions of this file are copyright Parallax Software and licensed
|
|
|
|
* according to the Parallax license below.
|
|
|
|
* See COPYING.txt for license details.
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
|
|
|
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
|
|
|
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
|
|
|
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
|
|
|
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
|
|
|
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
|
|
|
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
|
|
|
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
|
|
|
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
|
|
|
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Include file for sound hardware.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-04-02 02:36:55 +00:00
|
|
|
#pragma once
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2018-07-28 23:22:58 +00:00
|
|
|
#include <SDL_version.h>
|
2017-06-25 20:46:03 +00:00
|
|
|
#include <type_traits>
|
2006-03-20 17:12:09 +00:00
|
|
|
#include "pstypes.h"
|
|
|
|
#include "vecmat.h"
|
|
|
|
|
2012-11-11 22:12:51 +00:00
|
|
|
#ifdef __cplusplus
|
2015-04-02 02:36:55 +00:00
|
|
|
#include "dxxsconf.h"
|
2016-03-19 19:08:10 +00:00
|
|
|
#include "dsx-ns.h"
|
2015-10-10 03:44:14 +00:00
|
|
|
#include "fwd-object.h"
|
2015-10-10 03:44:14 +00:00
|
|
|
#include "fwd-segment.h"
|
2020-05-02 21:18:42 +00:00
|
|
|
#include <utility>
|
2012-11-11 22:12:51 +00:00
|
|
|
|
2016-01-09 16:38:15 +00:00
|
|
|
#ifdef dsx
|
2016-07-15 03:43:02 +00:00
|
|
|
namespace dcx {
|
2015-12-13 18:00:48 +00:00
|
|
|
|
2014-12-14 05:22:59 +00:00
|
|
|
struct sound_object;
|
2020-05-31 23:04:25 +00:00
|
|
|
extern int digi_volume;
|
2016-07-15 03:43:02 +00:00
|
|
|
|
2020-12-19 16:13:26 +00:00
|
|
|
enum class sound_stack : uint8_t
|
|
|
|
{
|
|
|
|
allow_stacking,
|
|
|
|
cancel_previous,
|
|
|
|
};
|
|
|
|
|
2016-07-15 03:43:02 +00:00
|
|
|
}
|
|
|
|
namespace dsx {
|
2013-12-22 22:03:07 +00:00
|
|
|
struct digi_sound
|
|
|
|
{
|
2008-04-06 20:23:28 +00:00
|
|
|
int bits;
|
|
|
|
int freq;
|
2006-03-20 17:12:09 +00:00
|
|
|
int length;
|
2016-07-14 01:59:02 +00:00
|
|
|
uint8_t * data;
|
2013-12-22 22:03:07 +00:00
|
|
|
};
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
extern int digi_get_settings();
|
|
|
|
extern int digi_init();
|
2014-12-11 02:34:32 +00:00
|
|
|
#ifndef RELEASE
|
2006-03-20 17:12:09 +00:00
|
|
|
extern void digi_reset();
|
2014-12-11 02:34:32 +00:00
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
extern void digi_close();
|
|
|
|
|
|
|
|
// Volume is max at F1_0.
|
|
|
|
extern void digi_play_sample( int sndnum, fix max_volume );
|
|
|
|
extern void digi_play_sample_once( int sndnum, fix max_volume );
|
2015-11-26 02:56:55 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
|
2018-05-13 03:14:34 +00:00
|
|
|
void digi_link_sound_to_object(unsigned soundnum, vcobjptridx_t objnum, uint8_t forever, fix max_volume, sound_stack once);
|
2019-03-03 00:31:09 +00:00
|
|
|
void digi_kill_sound_linked_to_segment(vmsegidx_t segnum, unsigned sidenum, int soundnum);
|
|
|
|
void digi_link_sound_to_pos(unsigned soundnum, vcsegptridx_t segnum, unsigned sidenum, const vms_vector &pos, int forever, fix max_volume);
|
2006-03-20 17:12:09 +00:00
|
|
|
// Same as above, but you pass the max distance sound can be heard. The old way uses f1_0*256 for max_distance.
|
2018-05-13 03:14:34 +00:00
|
|
|
void digi_link_sound_to_object2(unsigned soundnum, vcobjptridx_t objnum, uint8_t forever, fix max_volume, sound_stack once, vm_distance max_distance);
|
|
|
|
void digi_link_sound_to_object3(unsigned soundnum, vcobjptridx_t objnum, uint8_t forever, fix max_volume, sound_stack once, vm_distance max_distance, int loop_start, int loop_end);
|
2015-11-26 02:56:55 +00:00
|
|
|
void digi_kill_sound_linked_to_object(vcobjptridx_t);
|
|
|
|
#endif
|
2006-03-20 17:12:09 +00:00
|
|
|
|
2015-12-04 03:36:31 +00:00
|
|
|
void digi_play_sample_3d(int soundno, int angle, int volume); // Volume from 0-0x7fff
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
extern void digi_init_sounds();
|
|
|
|
extern void digi_sync_sounds();
|
|
|
|
|
|
|
|
extern void digi_set_digi_volume( int dvolume );
|
|
|
|
|
|
|
|
extern void digi_pause_digi_sounds();
|
|
|
|
extern void digi_resume_digi_sounds();
|
|
|
|
|
|
|
|
extern int digi_xlat_sound(int soundno);
|
|
|
|
|
|
|
|
extern void digi_stop_sound( int channel );
|
|
|
|
|
|
|
|
// Volume 0-F1_0
|
2016-07-16 16:52:04 +00:00
|
|
|
constexpr sound_object *sound_object_none = nullptr;
|
2014-12-14 05:22:59 +00:00
|
|
|
int digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, sound_object *);
|
2006-03-20 17:12:09 +00:00
|
|
|
|
|
|
|
// Stops all sounds that are playing
|
|
|
|
void digi_stop_all_channels();
|
|
|
|
|
2010-06-14 08:13:16 +00:00
|
|
|
void digi_stop_digi_sounds();
|
|
|
|
|
2006-03-20 17:12:09 +00:00
|
|
|
extern void digi_end_sound( int channel );
|
|
|
|
extern void digi_set_channel_pan( int channel, int pan );
|
|
|
|
extern void digi_set_channel_volume( int channel, int volume );
|
|
|
|
extern int digi_is_channel_playing(int channel);
|
|
|
|
|
|
|
|
extern void digi_play_sample_looping( int soundno, fix max_volume,int loop_start, int loop_end );
|
|
|
|
extern void digi_change_looping_volume( fix volume );
|
|
|
|
extern void digi_stop_looping_sound();
|
|
|
|
|
|
|
|
// Plays a queued voice sound.
|
|
|
|
extern void digi_start_sound_queued( short soundnum, fix volume );
|
|
|
|
|
2007-09-18 13:37:39 +00:00
|
|
|
// Following declarations are for the runtime switching system
|
|
|
|
|
|
|
|
#define SAMPLE_RATE_11K 11025
|
|
|
|
#define SAMPLE_RATE_22K 22050
|
|
|
|
#define SAMPLE_RATE_44K 44100
|
|
|
|
|
|
|
|
#define SDLMIXER_SYSTEM 1
|
|
|
|
#define SDLAUDIO_SYSTEM 2
|
|
|
|
|
2010-06-14 08:13:16 +00:00
|
|
|
#define MUSIC_TYPE_NONE 0
|
|
|
|
#define MUSIC_TYPE_BUILTIN 1
|
2019-10-24 17:39:08 +00:00
|
|
|
#if DXX_USE_SDL_REDBOOK_AUDIO
|
2010-06-14 08:13:16 +00:00
|
|
|
#define MUSIC_TYPE_REDBOOK 2
|
2018-07-28 23:22:58 +00:00
|
|
|
#endif
|
2010-06-14 08:13:16 +00:00
|
|
|
#define MUSIC_TYPE_CUSTOM 3
|
|
|
|
|
2007-09-21 19:06:05 +00:00
|
|
|
#define SOUND_MAX_VOLUME F1_0 / 2
|
2007-09-18 13:37:39 +00:00
|
|
|
|
2015-11-26 02:56:54 +00:00
|
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
2007-09-18 13:37:39 +00:00
|
|
|
extern int digi_sample_rate;
|
2015-11-26 02:56:54 +00:00
|
|
|
#endif
|
Backport D2's Dont_start_sound_objects to D1
Descent 2 has a hack, present as far back as I can trace, that
suppresses starting sounds during level load. The original reason was
not recorded, but this hack has the useful side effect that it avoids
using uninitialized data when set_sound_sources tries to use a Viewer
that has not been reset for the objects of the new level.
Descent 1 lacks this hack, so an invalid Viewer is used, which may
trigger a valptridx trap if the undefined data has an invalid segment
number, and could cause memory corruption in builds which do not
validate the segment index. The valptridx trap:
```
terminate called after throwing an instance of 'valptridx<dcx::segment>::index_range_exception'
what(): similar/main/digiobj.cpp:389: invalid index used in array subscript: base=(nil) size=9000 index=65021
```
The backtrace leading to the trap:
```
d1x::digi_link_sound_common (viewer=..., so=..., pos=..., forever=<optimized out>, max_volume=<optimized out>, max_distance=..., soundnum=42, segnum=...) at similar/main/digiobj.cpp:389
0x00005555555a4e2d in d1x::digi_link_sound_to_pos2 (vcobjptr=..., max_distance=..., max_volume=32768, forever=1, pos=..., sidenum=4, segnum=..., org_soundnum=121) at similar/main/digiobj.cpp:483
d1x::digi_link_sound_to_pos (soundnum=soundnum@entry=121, segnum=..., sidenum=sidenum@entry=4, pos=..., forever=forever@entry=1, max_volume=32768) at similar/main/digiobj.cpp:490
0x00005555555c140d in d1x::set_sound_sources (vcsegptridx=..., vcvertptr=...) at similar/main/gameseq.cpp:817
d1x::LoadLevel (level_num=<optimized out>, page_in_textures=1) at similar/main/gameseq.cpp:1022
0x00005555555c2654 in d1x::StartNewLevelSub (level_num=-1, page_in_textures=<optimized out>) at similar/main/gameseq.cpp:1865
```
Backport this hack into Descent 1. Ultimately, the hack should go away
and data should be loaded in an order that does not access undefined
memory.
Reported-by: Spacecpp <https://github.com/dxx-rebirth/dxx-rebirth/issues/463>
2019-10-26 23:13:14 +00:00
|
|
|
extern int Dont_start_sound_objects;
|
2012-11-11 00:14:30 +00:00
|
|
|
extern int SoundQ_channel;
|
2015-11-26 02:56:56 +00:00
|
|
|
void digi_select_system();
|
2010-06-14 08:13:16 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
// Windows native-MIDI stuff.
|
|
|
|
void digi_win32_set_midi_volume( int mvolume );
|
2013-06-08 22:24:17 +00:00
|
|
|
int digi_win32_play_midi_song(const char * filename, int loop );
|
2010-11-28 15:49:40 +00:00
|
|
|
void digi_win32_pause_midi_song();
|
|
|
|
void digi_win32_resume_midi_song();
|
2011-07-15 08:43:03 +00:00
|
|
|
void digi_win32_stop_midi_song();
|
2010-06-14 08:13:16 +00:00
|
|
|
#endif
|
2014-12-14 05:22:59 +00:00
|
|
|
void digi_end_soundobj(sound_object &);
|
2012-11-11 00:14:30 +00:00
|
|
|
void SoundQ_end();
|
2016-07-15 03:43:02 +00:00
|
|
|
#ifndef NDEBUG
|
2012-11-11 00:14:30 +00:00
|
|
|
int verify_sound_channel_free( int channel );
|
2016-07-15 03:43:02 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-12-19 16:13:26 +00:00
|
|
|
namespace dsx {
|
2007-09-18 13:37:39 +00:00
|
|
|
|
2015-04-02 02:36:55 +00:00
|
|
|
class RAIIdigi_sound
|
|
|
|
{
|
2017-06-25 20:46:03 +00:00
|
|
|
static constexpr auto invalid_channel = std::integral_constant<int, -1>{};
|
2019-04-28 00:53:40 +00:00
|
|
|
int channel = invalid_channel;
|
2015-04-02 02:36:55 +00:00
|
|
|
static void stop(int channel)
|
|
|
|
{
|
|
|
|
if (channel != invalid_channel)
|
|
|
|
digi_stop_sound(channel);
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
~RAIIdigi_sound()
|
|
|
|
{
|
|
|
|
stop(channel);
|
|
|
|
}
|
|
|
|
void reset(int c = invalid_channel)
|
|
|
|
{
|
2020-05-02 21:18:42 +00:00
|
|
|
stop(std::exchange(channel, c));
|
2015-04-02 02:36:55 +00:00
|
|
|
}
|
|
|
|
operator int() const = delete;
|
|
|
|
explicit operator bool() const
|
|
|
|
{
|
|
|
|
return channel != invalid_channel;
|
|
|
|
}
|
|
|
|
};
|
2015-12-13 18:00:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|