Fixed an issue where the chan array was cleared during audio_free,
[neverball] / share / audio.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <SDL.h>
16 #include <SDL_mixer.h>
17 #include <string.h>
18
19 #include "config.h"
20 #include "audio.h"
21
22 /*---------------------------------------------------------------------------*/
23
24 static int audio_state = 0;
25
26 static char       name[MAXSND][MAXSTR];
27 static int        chan[MAXSND];
28 static Mix_Chunk *buff[MAXSND];
29 static Mix_Music *song;
30
31 static char  curr_bgm[MAXSTR];
32 static char  next_bgm[MAXSTR];
33
34 static float fade_volume = 1.0f;
35 static float fade_rate   = 0.0f;
36
37 /*---------------------------------------------------------------------------*/
38
39 void audio_init(void)
40 {
41     int r = config_get_d(CONFIG_AUDIO_RATE);
42     int b = config_get_d(CONFIG_AUDIO_BUFF);
43     int i;
44
45     memset(curr_bgm, 0, MAXSTR);
46     memset(next_bgm, 0, MAXSTR);
47
48     if (audio_state == 0)
49     {
50         if (Mix_OpenAudio(r, MIX_DEFAULT_FORMAT, 2, b) == 0)
51         {
52             for (i = 0; i < MAXSND; i++)
53                 if (chan[i])
54                     buff[i] = Mix_LoadWAV(config_data(name[i]));
55
56             audio_state = 1;
57
58             audio_volume(config_get_d(CONFIG_SOUND_VOLUME),
59                          config_get_d(CONFIG_MUSIC_VOLUME));
60         }
61         else
62         {
63             fprintf(stderr, _("Sound disabled\n"));
64             audio_state = 0;
65         }
66     }
67 }
68
69 void audio_free(void)
70 {
71     int i;
72
73     if (audio_state == 1)
74     {
75         Mix_CloseAudio();
76
77         for (i = 0; i < MAXSND; i++)
78             if (buff[i])
79             {
80                 Mix_FreeChunk(buff[i]);
81
82                 buff[i] = NULL;
83             }
84
85         audio_state = 0;
86     }
87 }
88
89 void audio_bind(int i, int c, const char *filename)
90 {
91     strncpy(name[i], filename, MAXSTR);
92     chan[i] = c;
93 }
94
95 void audio_play(int i, float v)
96 {
97     if (audio_state == 1 && buff[i])
98     {
99         Mix_VolumeChunk(buff[i], (int) (v * MIX_MAX_VOLUME));
100         Mix_PlayChannel(chan[i], buff[i], 0);
101     }
102 }
103
104 /*---------------------------------------------------------------------------*/
105
106 void audio_music_play(const char *filename)
107 {
108     if (audio_state)
109     {
110         audio_music_stop();
111
112         if ((config_get_d(CONFIG_MUSIC_VOLUME) > 0) &&
113             (song = Mix_LoadMUS(config_data(filename))))
114         {
115             Mix_PlayMusic(song, -1);
116             strcpy(curr_bgm, filename);
117         }
118     }
119 }
120
121 void audio_music_queue(const char *filename)
122 {
123     if (audio_state)
124     {
125         if (strlen(curr_bgm) == 0 || strcmp(filename, curr_bgm) != 0)
126         {
127             Mix_VolumeMusic(0);
128             fade_volume = 0.0f;
129
130             audio_music_play(filename);
131             strcpy(curr_bgm, filename);
132
133             Mix_PauseMusic();
134         }
135     }
136 }
137
138 void audio_music_stop(void)
139 {
140     if (audio_state)
141     {
142         if (Mix_PlayingMusic())
143             Mix_HaltMusic();
144
145         if (song)
146             Mix_FreeMusic(song);
147
148         song = NULL;
149     }
150 }
151
152 /*---------------------------------------------------------------------------*/
153 /*
154  * SDL_mixer already provides music fading.  Unfortunately, it halts playback
155  * at the end of a fade.  We need to be able to fade music back in from the
156  * point where it stopped.  So, we reinvent this wheel.
157  */
158
159 void audio_timer(float dt)
160 {
161     if (audio_state)
162     {
163         if (fade_rate > 0.0f || fade_rate < 0.0f)
164             fade_volume += dt / fade_rate;
165
166         if (fade_volume < 0.0f)
167         {
168             fade_volume = 0.0f;
169
170             if (strlen(next_bgm) == 0)
171             {
172                 fade_rate = 0.0f;
173                 if (Mix_PlayingMusic())
174                     Mix_PauseMusic();
175             }
176             else
177             {
178                 fade_rate = -fade_rate;
179                 audio_music_queue(next_bgm);
180             }
181         }
182
183         if (fade_volume > 1.0f)
184         {
185             fade_rate   = 0.0f;
186             fade_volume = 1.0f;
187         }
188
189         if (Mix_PausedMusic() && fade_rate > 0.0f)
190             Mix_ResumeMusic();
191
192         if (Mix_PlayingMusic())
193             Mix_VolumeMusic(config_get_d(CONFIG_MUSIC_VOLUME) *
194                             (int) (fade_volume * MIX_MAX_VOLUME) / 10);
195     }
196 }
197
198 void audio_music_fade_out(float t)
199 {
200     fade_rate = -t;
201     strcpy(next_bgm, "");
202 }
203
204 void audio_music_fade_in(float t)
205 {
206     fade_rate = +t;
207     strcpy(next_bgm, "");
208 }
209
210 void audio_music_fade_to(float t, const char *filename)
211 {
212     if (fade_volume > 0)
213     {
214         if (strlen(curr_bgm) == 0 || strcmp(filename, curr_bgm) != 0)
215         {
216             strcpy(next_bgm, filename);
217             fade_rate = -t;
218         }
219         else fade_rate = t;
220     }
221     else
222     {
223         audio_music_queue(filename);
224         audio_music_fade_in(t);
225     }
226 }
227
228 void audio_volume(int s, int m)
229 {
230     if (audio_state)
231     {
232         Mix_Volume(-1, s * MIX_MAX_VOLUME / 10);
233         Mix_VolumeMusic(m * MIX_MAX_VOLUME / 10);
234     }
235 }
236
237 /*---------------------------------------------------------------------------*/