Freeciv-3.3: /fast/freeciv/nightly/main/client/audio_sdl.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
audio_sdl.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <string.h>
19
20#ifdef AUDIO_SDL3
21#include <SDL3/SDL.h>
22#include <SDL3_mixer/SDL_mixer.h>
23#else
24#ifdef SDL2_PLAIN_INCLUDE
25#include <SDL.h>
26#include <SDL_mixer.h>
27#else /* SDL2_PLAIN_INCLUDE */
28#include <SDL2/SDL.h>
29#include <SDL2/SDL_mixer.h>
30#endif /* SDL2_PLAIN_INCLUDE */
31#endif /* AUDIO_SDL3 */
32
33/* utility */
34#include "log.h"
35#include "support.h"
36
37/* client */
38#include "audio.h"
39
40#include "audio_sdl.h"
41
42 struct sample {
43 Mix_Chunk *wave;
44 const char *tag;
45};
46
47/* Sounds don't sound good on Windows unless the buffer size is 4k,
48 * but this seems to cause strange behaviour on other systems,
49 * such as a delay before playing the sound. */
50#ifdef FREECIV_MSWINDOWS
51const size_t buf_size = 4096;
52#else
53 const size_t buf_size = 1024;
54#endif
55
56 static Mix_Music *mus = NULL;
57 static struct sample samples[MIX_CHANNELS];
58 static double sdl_audio_volume;
59
60/**********************************************************************/
63 static void sdl_audio_set_volume(double volume)
64{
65 Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
66 Mix_Volume(-1, volume * MIX_MAX_VOLUME);
67 sdl_audio_volume = volume;
68}
69
70/**********************************************************************/
73 static double sdl_audio_get_volume(void)
74{
75 return sdl_audio_volume;
76}
77
78/**********************************************************************/
81 static bool sdl_audio_play(const char *const tag, const char *const fullpath,
82 bool repeat, audio_finished_callback cb)
83{
84 int i, j;
85 Mix_Chunk *wave = NULL;
86
87 if (!fullpath) {
88 return FALSE;
89 }
90
91 if (repeat) {
92 /* unload previous */
93 Mix_HaltMusic();
94 Mix_FreeMusic(mus);
95
96 /* load music file */
97 mus = Mix_LoadMUS(fullpath);
98 if (mus == NULL) {
99 log_error("Can't open file \"%s\"", fullpath);
100 }
101
102 if (cb == NULL) {
103 Mix_PlayMusic(mus, -1); /* -1 means loop forever */
104 } else {
105 Mix_PlayMusic(mus, 0);
106 Mix_HookMusicFinished(cb);
107 }
108 log_verbose("Playing file \"%s\" on music channel", fullpath);
109 /* in case we did a sdl_audio_stop() recently; add volume controls later */
110 Mix_VolumeMusic(sdl_audio_volume * MIX_MAX_VOLUME);
111
112 } else {
113
114 /* see if we can cache on this one */
115 for (j = 0; j < MIX_CHANNELS; j++) {
116 if (samples[j].tag && (strcmp(samples[j].tag, tag) == 0)) {
117 log_debug("Playing file \"%s\" from cache (slot %d)", fullpath, j);
118 Mix_PlayChannel(-1, samples[j].wave, 0);
119 return TRUE;
120 }
121 } /* guess not */
122
123 /* load wave */
124 wave = Mix_LoadWAV(fullpath);
125 if (wave == NULL) {
126 log_error("Can't open file \"%s\"", fullpath);
127 }
128
129 /* play sound sample on first available channel, returns -1 if no
130 channel found */
131 i = Mix_PlayChannel(-1, wave, 0);
132 if (i < 0) {
133 log_verbose("No available sound channel to play %s.", tag);
134 Mix_FreeChunk(wave);
135 return FALSE;
136 }
137 log_verbose("Playing file \"%s\" on channel %d", fullpath, i);
138 /* free previous sample on this channel. it will by definition no
139 longer be playing by the time we get here */
140 if (samples[i].wave) {
141 Mix_FreeChunk(samples[i].wave);
142 samples[i].wave = NULL;
143 }
144 /* remember for caching */
145 samples[i].wave = wave;
146 samples[i].tag = tag;
147
148 }
149 return TRUE;
150}
151
152/**********************************************************************/
155 static void sdl_audio_pause(void)
156{
157 Mix_PauseMusic();
158}
159
160/**********************************************************************/
163 static void sdl_audio_resume(void)
164{
165 Mix_ResumeMusic();
166}
167
168/**********************************************************************/
171 static void sdl_audio_stop(void)
172{
173 /* Fade out over 2 sec */
174 Mix_FadeOutMusic(2000);
175}
176
177/**********************************************************************/
182 static void sdl_audio_wait(void)
183{
184 while (Mix_Playing(-1) != 0) {
185 SDL_Delay(100);
186 }
187}
188
189/**********************************************************************/
195 static void quit_sdl_audio(void)
196{
197 if (SDL_WasInit(SDL_INIT_VIDEO)) {
198 SDL_QuitSubSystem(SDL_INIT_AUDIO);
199 } else {
200 SDL_Quit();
201 }
202}
203
204/**********************************************************************/
210 static int init_sdl_audio(void)
211{
212#ifdef AUDIO_SDL3
213 return SDL_Init(SDL_INIT_AUDIO);
214#else /* AUDIO_SDL3 */
215 SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "medium");
216
217 if (SDL_WasInit(SDL_INIT_VIDEO)) {
218 return SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
219 } else {
220 return SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
221 }
222#endif /* AUDIO_SDL3 */
223}
224
225/**********************************************************************/
228 static void sdl_audio_shutdown(struct audio_plugin *self)
229{
230 int i;
231
232 self->initialized = FALSE;
233
234 sdl_audio_stop();
235 sdl_audio_wait();
236
237 /* Remove all buffers */
238 for (i = 0; i < MIX_CHANNELS; i++) {
239 if (samples[i].wave) {
240 Mix_FreeChunk(samples[i].wave);
241 }
242 }
243 Mix_HaltMusic();
244 Mix_FreeMusic(mus);
245
246 Mix_CloseAudio();
247 quit_sdl_audio();
248}
249
250/**********************************************************************/
253 static bool sdl_audio_init(struct audio_plugin *self)
254{
255 int i;
256
257 if (init_sdl_audio() < 0) {
258 return FALSE;
259 }
260
261#ifdef AUDIO_SDL3
262 if (Mix_OpenAudio(0, NULL) < 0) {
263#else /* AUDIO_SDL3 */
264 /* Initialize variables */
265 const int audio_rate = MIX_DEFAULT_FREQUENCY;
266 const int audio_format = MIX_DEFAULT_FORMAT;
267 const int audio_channels = 2;
268
269 if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, buf_size) < 0) {
270#endif /* AUDIO_SDL3 */
271 log_error("Error calling Mix_OpenAudio");
272
273 /* Try something else */
274 quit_sdl_audio();
275 return FALSE;
276 }
277
278 Mix_AllocateChannels(MIX_CHANNELS);
279 for (i = 0; i < MIX_CHANNELS; i++) {
280 samples[i].wave = NULL;
281 }
282
283 /* Sanity check, for now; add volume controls later */
284 sdl_audio_set_volume(sdl_audio_volume);
285
286 self->initialized = TRUE;
287
288 return TRUE;
289}
290
291/**********************************************************************/
295 void audio_sdl_init(void)
296{
297 struct audio_plugin self;
298
299 sz_strlcpy(self.name, "sdl");
300 sz_strlcpy(self.descr, "Simple DirectMedia Library (SDL) mixer plugin");
301 self.initialized = FALSE;
302 self.init = sdl_audio_init;
303 self.shutdown = sdl_audio_shutdown;
304 self.stop = sdl_audio_stop;
305 self.wait = sdl_audio_wait;
306 self.play = sdl_audio_play;
307 self.pause = sdl_audio_pause;
308 self.resume = sdl_audio_resume;
309 self.set_volume = sdl_audio_set_volume;
310 self.get_volume = sdl_audio_get_volume;
311 audio_add_plugin(&self);
312 sdl_audio_volume = 1.0;
313}
audio_add_plugin
void audio_add_plugin(struct audio_plugin *p)
Definition audio.c:136
audio.h
audio_finished_callback
void(* audio_finished_callback)(void)
Definition audio.h:28
sdl_audio_shutdown
static void sdl_audio_shutdown(struct audio_plugin *self)
Definition audio_sdl.c:228
audio_sdl_init
void audio_sdl_init(void)
Definition audio_sdl.c:295
sdl_audio_wait
static void sdl_audio_wait(void)
Definition audio_sdl.c:182
quit_sdl_audio
static void quit_sdl_audio(void)
Definition audio_sdl.c:195
sdl_audio_set_volume
static void sdl_audio_set_volume(double volume)
Definition audio_sdl.c:63
sdl_audio_play
static bool sdl_audio_play(const char *const tag, const char *const fullpath, bool repeat, audio_finished_callback cb)
Definition audio_sdl.c:81
sdl_audio_resume
static void sdl_audio_resume(void)
Definition audio_sdl.c:163
samples
static struct sample samples[MIX_CHANNELS]
Definition audio_sdl.c:57
sdl_audio_volume
static double sdl_audio_volume
Definition audio_sdl.c:58
sdl_audio_init
static bool sdl_audio_init(struct audio_plugin *self)
Definition audio_sdl.c:253
init_sdl_audio
static int init_sdl_audio(void)
Definition audio_sdl.c:210
mus
static Mix_Music * mus
Definition audio_sdl.c:56
buf_size
const size_t buf_size
Definition audio_sdl.c:53
sdl_audio_pause
static void sdl_audio_pause(void)
Definition audio_sdl.c:155
sdl_audio_stop
static void sdl_audio_stop(void)
Definition audio_sdl.c:171
sdl_audio_get_volume
static double sdl_audio_get_volume(void)
Definition audio_sdl.c:73
audio_sdl.h
self
static struct ai_type * self
Definition classicai.c:46
incite_cost
char * incite_cost
Definition comments.c:74
log.h
log_verbose
#define log_verbose(message,...)
Definition log.h:109
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
ai_type::name
char name[MAX_LEN_NAME]
Definition ai.h:51
audio_plugin
Definition audio.h:30
sample
Definition audio_sdl.c:42
sample::wave
Mix_Chunk * wave
Definition audio_sdl.c:43
sample::tag
const char * tag
Definition audio_sdl.c:44
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47