1 /* DreamChess
2 **
3 ** DreamChess is the legal property of its developers, whose names are too
4 ** numerous to list here. Please refer to the AUTHORS.txt file distributed
5 ** with this source distribution.
6 **
7 ** This program is free software: you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation, either version 3 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "audio.h"
22
23 #ifdef _WIN32
24 #include <direct.h>
25 #else
26 #include <unistd.h>
27 #endif
28
29 #include <SDL.h>
30 #include <SDL_mixer.h>
31
32 #include "debug.h"
33 #include "playlist.h"
34 #include "system_config.h"
35 #include "theme.h"
36
37 static sound_t sounds[AUDIO_SOUNDS] = {{AUDIO_MOVE, "move1.wav"}};
38
39 static audio_music_callback_t music_callback = NULL;
40 static Mix_Music *music = NULL;
41 static playlist_t *playlist;
42 static int next_song;
43 static int have_songs;
44 static playlist_entry_t *current_song;
45 static int have_audio = 0;
46
47 static Mix_Chunk *wav_data[AUDIO_SOUNDS];
48
49 static int sound_volume, music_volume;
50
load_sounds(void)51 static void load_sounds(void) {
52 int i;
53
54 for (i = 0; i < AUDIO_SOUNDS; i++) {
55 DBG_LOG("Loading %s", sounds[i].filename);
56 wav_data[sounds[i].id] = Mix_LoadWAV(sounds[i].filename);
57 if (!wav_data[sounds[i].id]) {
58 DBG_ERROR("Failed to load %s", sounds[i].filename);
59 exit(1);
60 }
61 }
62 }
63
free_sounds(void)64 static void free_sounds(void) {
65 int i;
66
67 for (i = 0; i < AUDIO_SOUNDS; i++)
68 Mix_FreeChunk(wav_data[i]);
69 }
70
music_finished(void)71 static void music_finished(void) {
72 next_song = 1;
73 }
74
audio_init(void)75 void audio_init(void) {
76 music_packs_t *music_packs;
77 int audio_rate = 44100;
78 Uint16 audio_format = AUDIO_S16;
79 int audio_channels = 2;
80 int audio_buffers = 4096;
81 music_pack_t *music_pack;
82 option_t *option;
83
84 music_packs = theme_get_music_packs();
85
86 if (SDL_Init(SDL_INIT_AUDIO) != 0) {
87 DBG_ERROR("SDL audio initialization failed: %s", SDL_GetError());
88 return;
89 }
90
91 if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers)) {
92 DBG_ERROR("Unable to open audio");
93 return;
94 }
95
96 have_audio = 1;
97
98 chdir("sounds");
99 load_sounds();
100 chdir("..");
101
102 Mix_HookMusicFinished(music_finished);
103
104 option = config_get_option("music_volume");
105 audio_set_music_volume(option->selected->index);
106 option = config_get_option("sound_volume");
107 audio_set_sound_volume(option->selected->index);
108
109 playlist = playlist_create();
110 TAILQ_FOREACH(music_pack, music_packs, entries)
111 playlist_add_tracks(playlist, music_pack->dir);
112
113 /* Check for at least two songs */
114 if ((TAILQ_FIRST(playlist) != TAILQ_LAST(playlist, playlist))) {
115 current_song = TAILQ_LAST(playlist, playlist);
116 have_songs = 1;
117 next_song = 1;
118 } else
119 have_songs = 0;
120 }
121
audio_exit(void)122 void audio_exit(void) {
123 if (!have_audio)
124 return;
125
126 Mix_CloseAudio();
127 free_sounds();
128 playlist_destroy(playlist);
129 }
130
audio_poll(int title)131 void audio_poll(int title) {
132 if (!have_audio)
133 return;
134
135 /* Less than two songs or volume off, abort. */
136 if (!have_songs || !music_volume)
137 return;
138
139 /* Start a new song when the previous one is finished. Is also
140 ** triggered when going from the title-screen to in-game and back
141 */
142 if ((next_song == 1) || (!title && (current_song == TAILQ_FIRST(playlist))) ||
143 (title && (current_song != TAILQ_FIRST(playlist)))) {
144 if (title)
145 current_song = TAILQ_FIRST(playlist);
146 else {
147 current_song = TAILQ_NEXT(current_song, entries);
148 if (!current_song) {
149 /* Go to song 2 */
150 current_song = TAILQ_FIRST(playlist);
151 current_song = TAILQ_NEXT(current_song, entries);
152 }
153 }
154
155 next_song = 0;
156
157 if (music)
158 Mix_FreeMusic(music);
159
160 music = Mix_LoadMUS(current_song->filename);
161
162 if (music_callback)
163 music_callback(current_song->title, current_song->artist, current_song->album);
164
165 DBG_LOG("Playing %s", current_song->filename);
166 Mix_PlayMusic(music, 0);
167 }
168 }
169
audio_set_music_callback(audio_music_callback_t callback)170 void audio_set_music_callback(audio_music_callback_t callback) {
171 music_callback = callback;
172 }
173
audio_play_sound(int id)174 void audio_play_sound(int id) {
175 if (!have_audio)
176 return;
177
178 if (sound_volume == 0)
179 return;
180
181 if (Mix_PlayChannel(0, wav_data[id], 0) == -1)
182 DBG_WARN("Failed to play sound %i", id);
183 }
184
audio_set_sound_volume(int vol)185 void audio_set_sound_volume(int vol) {
186 if (!have_audio)
187 return;
188
189 sound_volume = vol * MIX_MAX_VOLUME / AUDIO_MAX_VOL;
190 Mix_Volume(0, sound_volume);
191 }
192
audio_set_music_volume(int vol)193 void audio_set_music_volume(int vol) {
194 if (!have_audio)
195 return;
196
197 int restart = vol && (music_volume == 0);
198 music_volume = vol * MIX_MAX_VOLUME / AUDIO_MAX_VOL;
199 Mix_VolumeMusic(music_volume);
200
201 if (music_volume == 0) {
202 Mix_HaltMusic();
203 } else if (restart) {
204 next_song = 1;
205 }
206 }
207