Removed silencing of gtk warning logs from gtk3.22-client.
[freeciv.git] / client / audio_sdl.c
blob5dd5c570810abe59a997ebad3fcda026618e095c
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <string.h>
20 #ifdef SDL2_PLAIN_INCLUDE
21 #include <SDL.h>
22 #include <SDL_mixer.h>
23 #elif AUDIO_SDL1_2
24 /* SDL */
25 #include <SDL/SDL.h>
26 #include <SDL/SDL_mixer.h>
27 #else /* AUDIO_SDL1_2 */
28 /* SDL2 */
29 #include <SDL2/SDL.h>
30 #include <SDL2/SDL_mixer.h>
31 #endif /* AUDIO_SDL1_2 */
33 /* utility */
34 #include "log.h"
35 #include "support.h"
37 /* client */
38 #include "audio.h"
40 #include "audio_sdl.h"
42 struct sample {
43 Mix_Chunk *wave;
44 const char *tag;
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 WIN32_NATIVE
51 const size_t buf_size = 4096;
52 #else
53 const size_t buf_size = 1024;
54 #endif
56 static Mix_Music *mus = NULL;
57 static struct sample samples[MIX_CHANNELS];
58 static double sdl_audio_volume;
60 /**************************************************************************
61 Set the volume.
62 **************************************************************************/
63 static void sdl_audio_set_volume(double volume)
65 Mix_VolumeMusic(volume * MIX_MAX_VOLUME);
66 Mix_Volume(-1, volume * MIX_MAX_VOLUME);
67 sdl_audio_volume = volume;
70 /**************************************************************************
71 Get the volume.
72 **************************************************************************/
73 static double sdl_audio_get_volume(void)
75 return sdl_audio_volume;
78 /**************************************************************************
79 Play sound
80 **************************************************************************/
81 static bool sdl_audio_play(const char *const tag, const char *const fullpath,
82 bool repeat, audio_finished_callback cb)
84 int i, j;
85 Mix_Chunk *wave = NULL;
87 if (!fullpath) {
88 return FALSE;
91 if (repeat) {
92 /* unload previous */
93 Mix_HaltMusic();
94 Mix_FreeMusic(mus);
96 /* load music file */
97 mus = Mix_LoadMUS(fullpath);
98 if (mus == NULL) {
99 log_error("Can't open file \"%s\"", fullpath);
102 if (cb == NULL) {
103 Mix_PlayMusic(mus, -1); /* -1 means loop forever */
104 } else {
105 Mix_PlayMusic(mus, 0);
106 Mix_HookMusicFinished(cb);
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(MIX_MAX_VOLUME);
112 } else {
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 i = Mix_PlayChannel(-1, samples[j].wave, 0);
119 return TRUE;
121 } /* guess not */
123 /* load wave */
124 wave = Mix_LoadWAV(fullpath);
125 if (wave == NULL) {
126 log_error("Can't open file \"%s\"", fullpath);
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;
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;
144 /* remember for cacheing */
145 samples[i].wave = wave;
146 samples[i].tag = tag;
149 return TRUE;
152 /**************************************************************************
153 Stop music
154 **************************************************************************/
155 static void sdl_audio_stop(void)
157 /* fade out over 2 sec */
158 Mix_FadeOutMusic(2000);
161 /**************************************************************************
162 Wait for audio to die on all channels.
163 WARNING: If a channel is looping, it will NEVER exit! Always call
164 music_stop() first!
165 **************************************************************************/
166 static void sdl_audio_wait(void)
168 while (Mix_Playing(-1) != 0) {
169 SDL_Delay(100);
173 /**************************************************************************
174 Quit SDL. If the video is still in use (by gui-sdl), just quit the
175 subsystem.
177 This will need to be changed if SDL is used elsewhere.
178 **************************************************************************/
179 static void quit_sdl_audio(void)
181 if (SDL_WasInit(SDL_INIT_VIDEO)) {
182 SDL_QuitSubSystem(SDL_INIT_AUDIO);
183 } else {
184 SDL_Quit();
188 /**************************************************************************
189 Init SDL. If the video is already in use (by gui-sdl), just init the
190 subsystem.
192 This will need to be changed if SDL is used elsewhere.
193 **************************************************************************/
194 static int init_sdl_audio(void)
196 if (SDL_WasInit(SDL_INIT_VIDEO)) {
197 return SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
198 } else {
199 return SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);
203 /**************************************************************************
204 Clean up.
205 **************************************************************************/
206 static void sdl_audio_shutdown(void)
208 int i;
210 sdl_audio_stop();
211 sdl_audio_wait();
213 /* remove all buffers */
214 for (i = 0; i < MIX_CHANNELS; i++) {
215 if (samples[i].wave) {
216 Mix_FreeChunk(samples[i].wave);
219 Mix_HaltMusic();
220 Mix_FreeMusic(mus);
222 Mix_CloseAudio();
223 quit_sdl_audio();
226 /**************************************************************************
227 Initialize.
228 **************************************************************************/
229 static bool sdl_audio_init(void)
231 /* Initialize variables */
232 const int audio_rate = MIX_DEFAULT_FREQUENCY;
233 const int audio_format = MIX_DEFAULT_FORMAT;
234 const int audio_channels = 2;
235 int i;
237 if (init_sdl_audio() < 0) {
238 return FALSE;
241 if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, buf_size) < 0) {
242 log_error("Error calling Mix_OpenAudio");
243 /* try something else */
244 quit_sdl_audio();
245 return FALSE;
248 Mix_AllocateChannels(MIX_CHANNELS);
249 for (i = 0; i < MIX_CHANNELS; i++) {
250 samples[i].wave = NULL;
252 /* sanity check, for now; add volume controls later */
253 sdl_audio_set_volume(sdl_audio_volume);
254 return TRUE;
257 /**************************************************************************
258 Initialize. Note that this function is called very early at the
259 client startup. So for example logging isn't available.
260 **************************************************************************/
261 void audio_sdl_init(void)
263 struct audio_plugin self;
265 sz_strlcpy(self.name, "sdl");
266 sz_strlcpy(self.descr, "Simple DirectMedia Library (SDL) mixer plugin");
267 self.init = sdl_audio_init;
268 self.shutdown = sdl_audio_shutdown;
269 self.stop = sdl_audio_stop;
270 self.wait = sdl_audio_wait;
271 self.play = sdl_audio_play;
272 self.set_volume = sdl_audio_set_volume;
273 self.get_volume = sdl_audio_get_volume;
274 audio_add_plugin(&self);
275 sdl_audio_volume = 1.0;