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)
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 ***********************************************************************/
15 #include <fc_config.h>
20 #ifdef SDL2_PLAIN_INCLUDE
22 #include <SDL_mixer.h>
23 #else /* SDL2_PLAIN_INCLUDE */
25 #include <SDL2/SDL_mixer.h>
26 #endif /* SDL2_PLAIN_INCLUDE */
35 #include "audio_sdl.h"
42 /* Sounds don't sound good on Windows unless the buffer size is 4k,
43 * but this seems to cause strange behaviour on other systems,
44 * such as a delay before playing the sound. */
45 #ifdef FREECIV_MSWINDOWS
46 const size_t buf_size
= 4096;
48 const size_t buf_size
= 1024;
51 static Mix_Music
*mus
= NULL
;
52 static struct sample samples
[MIX_CHANNELS
];
53 static double sdl_audio_volume
;
55 /**************************************************************************
57 **************************************************************************/
58 static void sdl_audio_set_volume(double volume
)
60 Mix_VolumeMusic(volume
* MIX_MAX_VOLUME
);
61 Mix_Volume(-1, volume
* MIX_MAX_VOLUME
);
62 sdl_audio_volume
= volume
;
65 /**************************************************************************
67 **************************************************************************/
68 static double sdl_audio_get_volume(void)
70 return sdl_audio_volume
;
73 /**************************************************************************
75 **************************************************************************/
76 static bool sdl_audio_play(const char *const tag
, const char *const fullpath
,
77 bool repeat
, audio_finished_callback cb
)
80 Mix_Chunk
*wave
= NULL
;
92 mus
= Mix_LoadMUS(fullpath
);
94 log_error("Can't open file \"%s\"", fullpath
);
98 Mix_PlayMusic(mus
, -1); /* -1 means loop forever */
100 Mix_PlayMusic(mus
, 0);
101 Mix_HookMusicFinished(cb
);
103 log_verbose("Playing file \"%s\" on music channel", fullpath
);
104 /* in case we did a sdl_audio_stop() recently; add volume controls later */
105 Mix_VolumeMusic(MIX_MAX_VOLUME
);
109 /* see if we can cache on this one */
110 for (j
= 0; j
< MIX_CHANNELS
; j
++) {
111 if (samples
[j
].tag
&& (strcmp(samples
[j
].tag
, tag
) == 0)) {
112 log_debug("Playing file \"%s\" from cache (slot %d)", fullpath
, j
);
113 i
= Mix_PlayChannel(-1, samples
[j
].wave
, 0);
119 wave
= Mix_LoadWAV(fullpath
);
121 log_error("Can't open file \"%s\"", fullpath
);
124 /* play sound sample on first available channel, returns -1 if no
126 i
= Mix_PlayChannel(-1, wave
, 0);
128 log_verbose("No available sound channel to play %s.", tag
);
132 log_verbose("Playing file \"%s\" on channel %d", fullpath
, i
);
133 /* free previous sample on this channel. it will by definition no
134 longer be playing by the time we get here */
135 if (samples
[i
].wave
) {
136 Mix_FreeChunk(samples
[i
].wave
);
137 samples
[i
].wave
= NULL
;
139 /* remember for cacheing */
140 samples
[i
].wave
= wave
;
141 samples
[i
].tag
= tag
;
147 /**************************************************************************
149 **************************************************************************/
150 static void sdl_audio_stop(void)
152 /* fade out over 2 sec */
153 Mix_FadeOutMusic(2000);
156 /**************************************************************************
157 Wait for audio to die on all channels.
158 WARNING: If a channel is looping, it will NEVER exit! Always call
160 **************************************************************************/
161 static void sdl_audio_wait(void)
163 while (Mix_Playing(-1) != 0) {
168 /**************************************************************************
169 Quit SDL. If the video is still in use (by gui-sdl), just quit the
172 This will need to be changed if SDL is used elsewhere.
173 **************************************************************************/
174 static void quit_sdl_audio(void)
176 if (SDL_WasInit(SDL_INIT_VIDEO
)) {
177 SDL_QuitSubSystem(SDL_INIT_AUDIO
);
183 /**************************************************************************
184 Init SDL. If the video is already in use (by gui-sdl), just init the
187 This will need to be changed if SDL is used elsewhere.
188 **************************************************************************/
189 static int init_sdl_audio(void)
191 if (SDL_WasInit(SDL_INIT_VIDEO
)) {
192 return SDL_InitSubSystem(SDL_INIT_AUDIO
| SDL_INIT_NOPARACHUTE
);
194 return SDL_Init(SDL_INIT_AUDIO
| SDL_INIT_NOPARACHUTE
);
198 /**************************************************************************
200 **************************************************************************/
201 static void sdl_audio_shutdown(void)
208 /* remove all buffers */
209 for (i
= 0; i
< MIX_CHANNELS
; i
++) {
210 if (samples
[i
].wave
) {
211 Mix_FreeChunk(samples
[i
].wave
);
221 /**************************************************************************
223 **************************************************************************/
224 static bool sdl_audio_init(void)
226 /* Initialize variables */
227 const int audio_rate
= MIX_DEFAULT_FREQUENCY
;
228 const int audio_format
= MIX_DEFAULT_FORMAT
;
229 const int audio_channels
= 2;
232 if (init_sdl_audio() < 0) {
236 if (Mix_OpenAudio(audio_rate
, audio_format
, audio_channels
, buf_size
) < 0) {
237 log_error("Error calling Mix_OpenAudio");
238 /* try something else */
243 Mix_AllocateChannels(MIX_CHANNELS
);
244 for (i
= 0; i
< MIX_CHANNELS
; i
++) {
245 samples
[i
].wave
= NULL
;
247 /* sanity check, for now; add volume controls later */
248 sdl_audio_set_volume(sdl_audio_volume
);
252 /**************************************************************************
253 Initialize. Note that this function is called very early at the
254 client startup. So for example logging isn't available.
255 **************************************************************************/
256 void audio_sdl_init(void)
258 struct audio_plugin self
;
260 sz_strlcpy(self
.name
, "sdl");
261 sz_strlcpy(self
.descr
, "Simple DirectMedia Library (SDL) mixer plugin");
262 self
.init
= sdl_audio_init
;
263 self
.shutdown
= sdl_audio_shutdown
;
264 self
.stop
= sdl_audio_stop
;
265 self
.wait
= sdl_audio_wait
;
266 self
.play
= sdl_audio_play
;
267 self
.set_volume
= sdl_audio_set_volume
;
268 self
.get_volume
= sdl_audio_get_volume
;
269 audio_add_plugin(&self
);
270 sdl_audio_volume
= 1.0;