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 | } |