9e0431b861
Commit3b5b69cb97
changed the logic to store the result of hmp_open into a local that was destroyed at the end of the function. This was incorrect, as destruction of the returned value will immediately halt the music. Revert to the previous behavior, where the result is written to the global `cur_hmp` so that it persists past the end of the function. Reported-by: norbert79 <https://github.com/dxx-rebirth/dxx-rebirth/issues/634> Analyzed-by: AlumiuN <https://github.com/dxx-rebirth/dxx-rebirth/issues/634#issuecomment-1110510761> Proposed-fix-by: AlumiuN <https://github.com/dxx-rebirth/dxx-rebirth/issues/634#issuecomment-1110510761> Fixes:3b5b69cb97
("Improve error reporting for hmp_open / hmp2mid")
303 lines
6.9 KiB
C++
303 lines
6.9 KiB
C++
/*
|
|
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
* terms and a link to the Git history.
|
|
*/
|
|
/*
|
|
* Digital audio support
|
|
* Library-independent stub for dynamic selection of sound system
|
|
*/
|
|
|
|
#include <stdexcept>
|
|
#include "dxxerror.h"
|
|
#include "vecmat.h"
|
|
#include "config.h"
|
|
#include "digi.h"
|
|
#include "sounds.h"
|
|
#include "console.h"
|
|
#include "rbaudio.h"
|
|
#include "args.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <digi.h>
|
|
#include <digi_audio.h>
|
|
|
|
#if DXX_USE_SDLMIXER
|
|
#include <digi_mixer.h>
|
|
#include <SDL_mixer.h>
|
|
#endif
|
|
#ifdef _WIN32
|
|
#include "hmp.h"
|
|
#endif
|
|
|
|
namespace dcx {
|
|
|
|
int digi_volume = SOUND_MAX_VOLUME;
|
|
|
|
/* The values for these three defines are arbitrary and can be changed,
|
|
* provided that they remain unique with respect to each other.
|
|
*/
|
|
#define DXX_STS_MIXER_WITH_POINTER 0
|
|
#define DXX_STS_MIXER_WITH_COPY 1
|
|
#define DXX_STS_NO_MIXER 2
|
|
|
|
#if DXX_USE_SDLMIXER
|
|
#ifndef DXX_SOUND_TABLE_STYLE
|
|
#ifdef __PIE__
|
|
/* PIE -> paranoid checks
|
|
* No PIE -> prefer speed
|
|
*/
|
|
#define DXX_SOUND_TABLE_STYLE DXX_STS_MIXER_WITH_POINTER
|
|
#else
|
|
#define DXX_SOUND_TABLE_STYLE DXX_STS_MIXER_WITH_COPY
|
|
#endif
|
|
#endif
|
|
#else
|
|
#define DXX_SOUND_TABLE_STYLE DXX_STS_NO_MIXER
|
|
#endif
|
|
|
|
/* Sound system function pointers */
|
|
|
|
namespace {
|
|
|
|
struct sound_function_table_t
|
|
{
|
|
int (*init)();
|
|
void (*close)();
|
|
void (*set_channel_volume)(int, int);
|
|
void (*set_channel_pan)(int, sound_pan);
|
|
int (*start_sound)(short, fix, sound_pan, int, int, int, sound_object *);
|
|
void (*stop_sound)(int);
|
|
void (*end_sound)(int);
|
|
int (*is_channel_playing)(int);
|
|
void (*stop_all_channels)();
|
|
void (*set_digi_volume)(int);
|
|
};
|
|
|
|
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
|
|
[[noreturn]]
|
|
__attribute_cold
|
|
void report_invalid_table()
|
|
{
|
|
/* Out of line due to length of generated code */
|
|
throw std::logic_error("invalid sound table pointer");
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if DXX_SOUND_TABLE_STYLE != DXX_STS_MIXER_WITH_COPY
|
|
namespace dsx
|
|
#else
|
|
namespace dcx
|
|
#endif
|
|
{
|
|
|
|
namespace {
|
|
|
|
class sound_function_pointers_t
|
|
{
|
|
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_COPY
|
|
sound_function_table_t table;
|
|
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
|
|
const sound_function_table_t *table;
|
|
#endif
|
|
public:
|
|
inline const sound_function_table_t *operator->();
|
|
inline sound_function_pointers_t &operator=(const sound_function_table_t &t);
|
|
};
|
|
|
|
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_COPY
|
|
const sound_function_table_t *sound_function_pointers_t::operator->()
|
|
{
|
|
return &table;
|
|
}
|
|
|
|
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &t)
|
|
{
|
|
table = t;
|
|
return *this;
|
|
}
|
|
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
|
|
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &t)
|
|
{
|
|
table = &t;
|
|
/* Trap bad initial assignment */
|
|
operator->();
|
|
return *this;
|
|
}
|
|
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_NO_MIXER
|
|
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &)
|
|
{
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
static sound_function_pointers_t fptr;
|
|
|
|
}
|
|
|
|
namespace dsx {
|
|
|
|
namespace {
|
|
|
|
/* Some of the functions are in dsx, so the definition and
|
|
* initializer must be in dsx.
|
|
*/
|
|
#if DXX_USE_SDLMIXER
|
|
constexpr sound_function_table_t digi_mixer_table{
|
|
&digi_mixer_init,
|
|
&digi_mixer_close,
|
|
&digi_mixer_set_channel_volume,
|
|
&digi_mixer_set_channel_pan,
|
|
&digi_mixer_start_sound,
|
|
&digi_mixer_stop_sound,
|
|
&digi_mixer_end_sound,
|
|
&digi_mixer_is_channel_playing,
|
|
&digi_mixer_stop_all_channels,
|
|
&digi_mixer_set_digi_volume,
|
|
};
|
|
#endif
|
|
|
|
constexpr sound_function_table_t digi_audio_table{
|
|
&digi_audio_init,
|
|
&digi_audio_close,
|
|
&digi_audio_set_channel_volume,
|
|
&digi_audio_set_channel_pan,
|
|
&digi_audio_start_sound,
|
|
&digi_audio_stop_sound,
|
|
&digi_audio_end_sound,
|
|
&digi_audio_is_channel_playing,
|
|
&digi_audio_stop_all_channels,
|
|
&digi_audio_set_digi_volume,
|
|
};
|
|
|
|
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
|
|
const sound_function_table_t *sound_function_pointers_t::operator->()
|
|
{
|
|
if (table != &digi_audio_table && table != &digi_mixer_table)
|
|
report_invalid_table();
|
|
return table;
|
|
}
|
|
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_NO_MIXER
|
|
const sound_function_table_t *sound_function_pointers_t::operator->()
|
|
{
|
|
return &digi_audio_table;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void digi_select_system()
|
|
{
|
|
#if DXX_USE_SDLMIXER
|
|
if (!CGameArg.SndDisableSdlMixer)
|
|
{
|
|
const auto vl = Mix_Linked_Version();
|
|
con_printf(CON_NORMAL, "Using SDL_mixer library v%u.%u.%u", vl->major, vl->minor, vl->patch);
|
|
fptr = digi_mixer_table;
|
|
return;
|
|
}
|
|
#endif
|
|
con_puts(CON_NORMAL,"Using plain old SDL audio");
|
|
fptr = digi_audio_table;
|
|
}
|
|
|
|
/* Common digi functions */
|
|
#if defined(DXX_BUILD_DESCENT_I)
|
|
int digi_sample_rate = SAMPLE_RATE_11K;
|
|
#endif
|
|
|
|
/* Stub functions */
|
|
|
|
int digi_init()
|
|
{
|
|
digi_init_sounds();
|
|
return fptr->init();
|
|
}
|
|
|
|
void digi_close() { fptr->close(); }
|
|
|
|
void digi_set_channel_volume(int channel, int volume) { fptr->set_channel_volume(channel, volume); }
|
|
void digi_set_channel_pan(const int channel, const sound_pan pan) { fptr->set_channel_pan(channel, pan); }
|
|
|
|
int digi_start_sound(const short soundnum, const fix volume, const sound_pan pan, const int looping, const int loop_start, const int loop_end, sound_object *const soundobj)
|
|
{
|
|
return fptr->start_sound(soundnum, volume, pan, looping, loop_start, loop_end, soundobj);
|
|
}
|
|
|
|
void digi_stop_sound(int channel) { fptr->stop_sound(channel); }
|
|
void digi_end_sound(int channel) { fptr->end_sound(channel); }
|
|
|
|
int digi_is_channel_playing(int channel) { return fptr->is_channel_playing(channel); }
|
|
void digi_stop_all_channels() { fptr->stop_all_channels(); }
|
|
void digi_set_digi_volume(int dvolume) { fptr->set_digi_volume(dvolume); }
|
|
|
|
#ifdef _WIN32
|
|
// Windows native-MIDI stuff.
|
|
static uint8_t digi_win32_midi_song_playing;
|
|
static uint8_t already_playing;
|
|
static std::unique_ptr<hmp_file> cur_hmp;
|
|
|
|
void digi_win32_set_midi_volume( int mvolume )
|
|
{
|
|
hmp_setvolume(cur_hmp.get(), mvolume*MIDI_VOLUME_SCALE/8);
|
|
}
|
|
|
|
int digi_win32_play_midi_song( const char * filename, int loop )
|
|
{
|
|
if (!already_playing)
|
|
{
|
|
hmp_reset();
|
|
already_playing = 1;
|
|
}
|
|
digi_win32_stop_midi_song();
|
|
|
|
if (filename == NULL)
|
|
return 0;
|
|
|
|
if ((cur_hmp = std::get<0>(hmp_open(filename))))
|
|
{
|
|
/*
|
|
* FIXME: to be implemented as soon as we have some kind or checksum function - replacement for ugly hack in hmp.c for descent.hmp
|
|
* if (***filesize check*** && ***CRC32 or MD5 check***)
|
|
* (((*cur_hmp).trks)[1]).data[6] = 0x6C;
|
|
*/
|
|
if (hmp_play(cur_hmp.get(),loop) != 0)
|
|
return 0; // error
|
|
digi_win32_midi_song_playing = 1;
|
|
digi_win32_set_midi_volume(GameCfg.MusicVolume);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void digi_win32_pause_midi_song()
|
|
{
|
|
hmp_pause(cur_hmp.get());
|
|
}
|
|
|
|
void digi_win32_resume_midi_song()
|
|
{
|
|
hmp_resume(cur_hmp.get());
|
|
}
|
|
|
|
void digi_win32_stop_midi_song()
|
|
{
|
|
if (!digi_win32_midi_song_playing)
|
|
return;
|
|
digi_win32_midi_song_playing = 0;
|
|
cur_hmp.reset();
|
|
hmp_reset();
|
|
}
|
|
#endif
|
|
|
|
}
|