Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
/*
8
 * Digital audio support
9
 * Library-independent stub for dynamic selection of sound system
10
 */
11
 
12
#include "dxxerror.h"
13
#include "vecmat.h"
14
#include "piggy.h"
15
#include "config.h"
16
#include "digi.h"
17
#include "sounds.h"
18
#include "console.h"
19
#include "rbaudio.h"
20
#include "jukebox.h"
21
#include "args.h"
22
#include <stdlib.h>
23
#include <stdio.h>
24
#include <string.h>
25
#include <digi.h>
26
#include <digi_audio.h>
27
 
28
#if DXX_USE_SDLMIXER
29
#include <digi_mixer.h>
30
#include <SDL_mixer.h>
31
#endif
32
#ifdef _WIN32
33
#include "hmp.h"
34
#endif
35
 
36
namespace dcx {
37
 
38
int digi_volume = SOUND_MAX_VOLUME;
39
 
40
/* The values for these three defines are arbitrary and can be changed,
41
 * provided that they remain unique with respect to each other.
42
 */
43
#define DXX_STS_MIXER_WITH_POINTER      0
44
#define DXX_STS_MIXER_WITH_COPY 1
45
#define DXX_STS_NO_MIXER        2
46
 
47
#if DXX_USE_SDLMIXER
48
#ifndef DXX_SOUND_TABLE_STYLE
49
#ifdef __PIE__
50
/* PIE -> paranoid checks
51
 * No PIE -> prefer speed
52
 */
53
#define DXX_SOUND_TABLE_STYLE   DXX_STS_MIXER_WITH_POINTER
54
#else
55
#define DXX_SOUND_TABLE_STYLE   DXX_STS_MIXER_WITH_COPY
56
#endif
57
#endif
58
#else
59
#define DXX_SOUND_TABLE_STYLE   DXX_STS_NO_MIXER
60
#endif
61
 
62
/* Sound system function pointers */
63
 
64
namespace {
65
 
66
struct sound_function_table_t
67
{
68
        int  (*init)();
69
        void (*close)();
70
#ifndef RELEASE
71
        void (*reset)();
72
#endif
73
        void (*set_channel_volume)(int, int);
74
        void (*set_channel_pan)(int, int);
75
        int  (*start_sound)(short, fix, int, int, int, int, sound_object *);
76
        void (*stop_sound)(int);
77
        void (*end_sound)(int);
78
        int  (*is_channel_playing)(int);
79
        void (*stop_all_channels)();
80
        void (*set_digi_volume)(int);
81
};
82
 
83
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
84
[[noreturn]]
85
__attribute_cold
86
void report_invalid_table()
87
{
88
        /* Out of line due to length of generated code */
89
        throw std::logic_error("invalid sound table pointer");
90
}
91
#endif
92
 
93
}
94
 
95
}
96
 
97
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
98
namespace dsx
99
#else
100
namespace dcx
101
#endif
102
{
103
 
104
namespace {
105
 
106
class sound_function_pointers_t
107
{
108
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_COPY
109
        sound_function_table_t table;
110
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
111
        const sound_function_table_t *table;
112
#endif
113
public:
114
        inline const sound_function_table_t *operator->();
115
        inline sound_function_pointers_t &operator=(const sound_function_table_t &t);
116
};
117
 
118
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_COPY
119
const sound_function_table_t *sound_function_pointers_t::operator->()
120
{
121
        return &table;
122
}
123
 
124
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &t)
125
{
126
        table = t;
127
        return *this;
128
}
129
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
130
 
131
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &t)
132
{
133
        table = &t;
134
        /* Trap bad initial assignment */
135
        operator->();
136
        return *this;
137
}
138
#elif DXX_SOUND_TABLE_STYLE == DXX_STS_NO_MIXER
139
const sound_function_table_t *sound_function_pointers_t::operator->()
140
{
141
        return &digi_audio_table;
142
}
143
 
144
sound_function_pointers_t &sound_function_pointers_t::operator=(const sound_function_table_t &)
145
{
146
        return *this;
147
}
148
#endif
149
 
150
}
151
 
152
static sound_function_pointers_t fptr;
153
 
154
}
155
 
156
namespace dsx {
157
 
158
namespace {
159
 
160
        /* Some of the functions are in dsx, so the definition and
161
         * initializer must be in dsx.
162
         */
163
#if DXX_USE_SDLMIXER
164
constexpr sound_function_table_t digi_mixer_table{
165
        &digi_mixer_init,
166
        &digi_mixer_close,
167
#ifndef RELEASE
168
        &digi_mixer_reset,
169
#endif
170
        &digi_mixer_set_channel_volume,
171
        &digi_mixer_set_channel_pan,
172
        &digi_mixer_start_sound,
173
        &digi_mixer_stop_sound,
174
        &digi_mixer_end_sound,
175
        &digi_mixer_is_channel_playing,
176
        &digi_mixer_stop_all_channels,
177
        &digi_mixer_set_digi_volume,
178
};
179
#endif
180
 
181
constexpr sound_function_table_t digi_audio_table{
182
        &digi_audio_init,
183
        &digi_audio_close,
184
#ifndef RELEASE
185
        &digi_audio_reset,
186
#endif
187
        &digi_audio_set_channel_volume,
188
        &digi_audio_set_channel_pan,
189
        &digi_audio_start_sound,
190
        &digi_audio_stop_sound,
191
        &digi_audio_end_sound,
192
        &digi_audio_is_channel_playing,
193
        &digi_audio_stop_all_channels,
194
        &digi_audio_set_digi_volume,
195
};
196
 
197
#if DXX_SOUND_TABLE_STYLE == DXX_STS_MIXER_WITH_POINTER
198
const sound_function_table_t *sound_function_pointers_t::operator->()
199
{
200
        if (table != &digi_audio_table && table != &digi_mixer_table)
201
                report_invalid_table();
202
        return table;
203
}
204
#endif
205
 
206
}
207
 
208
void digi_select_system()
209
{
210
#if DXX_USE_SDLMIXER
211
        if (!CGameArg.SndDisableSdlMixer)
212
        {
213
                const auto vl = Mix_Linked_Version();
214
                con_printf(CON_NORMAL, "Using SDL_mixer library v%u.%u.%u", vl->major, vl->minor, vl->patch);
215
                fptr = digi_mixer_table;
216
                return;
217
        }
218
#endif
219
        con_puts(CON_NORMAL,"Using plain old SDL audio");
220
                fptr = digi_audio_table;
221
}
222
 
223
/* Common digi functions */
224
#if defined(DXX_BUILD_DESCENT_I)
225
int digi_sample_rate = SAMPLE_RATE_11K;
226
#endif
227
 
228
/* Stub functions */
229
 
230
int  digi_init()
231
{
232
        digi_init_sounds();
233
        return fptr->init();
234
}
235
 
236
void digi_close() { fptr->close(); }
237
#ifndef RELEASE
238
void digi_reset() { fptr->reset(); }
239
#endif
240
 
241
void digi_set_channel_volume(int channel, int volume) { fptr->set_channel_volume(channel, volume); }
242
void digi_set_channel_pan(int channel, int pan) { fptr->set_channel_pan(channel, pan); }
243
 
244
int  digi_start_sound(short soundnum, fix volume, int pan, int looping, int loop_start, int loop_end, sound_object *soundobj)
245
{
246
        return fptr->start_sound(soundnum, volume, pan, looping, loop_start, loop_end, soundobj);
247
}
248
 
249
void digi_stop_sound(int channel) { fptr->stop_sound(channel); }
250
void digi_end_sound(int channel) { fptr->end_sound(channel); }
251
 
252
int  digi_is_channel_playing(int channel) { return fptr->is_channel_playing(channel); }
253
void digi_stop_all_channels() { fptr->stop_all_channels(); }
254
void digi_set_digi_volume(int dvolume) { fptr->set_digi_volume(dvolume); }
255
 
256
#ifdef _WIN32
257
// Windows native-MIDI stuff.
258
static uint8_t digi_win32_midi_song_playing;
259
static uint8_t already_playing;
260
static std::unique_ptr<hmp_file> cur_hmp;
261
 
262
void digi_win32_set_midi_volume( int mvolume )
263
{
264
        hmp_setvolume(cur_hmp.get(), mvolume*MIDI_VOLUME_SCALE/8);
265
}
266
 
267
int digi_win32_play_midi_song( const char * filename, int loop )
268
{
269
        if (!already_playing)
270
        {
271
                hmp_reset();
272
                already_playing = 1;
273
        }
274
        digi_win32_stop_midi_song();
275
 
276
        if (filename == NULL)
277
                return 0;
278
 
279
        if ((cur_hmp = hmp_open(filename)))
280
        {
281
                /*
282
                 * FIXME: to be implemented as soon as we have some kind or checksum function - replacement for ugly hack in hmp.c for descent.hmp
283
                 * if (***filesize check*** && ***CRC32 or MD5 check***)
284
                 *      (((*cur_hmp).trks)[1]).data[6] = 0x6C;
285
                 */
286
                if (hmp_play(cur_hmp.get(),loop) != 0)
287
                        return 0;       // error
288
                digi_win32_midi_song_playing = 1;
289
                digi_win32_set_midi_volume(GameCfg.MusicVolume);
290
                return 1;
291
        }
292
 
293
        return 0;
294
}
295
 
296
void digi_win32_pause_midi_song()
297
{
298
        hmp_pause(cur_hmp.get());
299
}
300
 
301
void digi_win32_resume_midi_song()
302
{
303
        hmp_resume(cur_hmp.get());
304
}
305
 
306
void digi_win32_stop_midi_song()
307
{
308
        if (!digi_win32_midi_song_playing)
309
                return;
310
        digi_win32_midi_song_playing = 0;
311
        cur_hmp.reset();
312
        hmp_reset();
313
}
314
#endif
315
 
316
}