ff2e24546085bbc1402763651a2a4b68d269dd75
[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                 chan[i] = 0;
84             }
85
86         audio_state = 0;
87     }
88 }
89
90 void audio_bind(int i, int c, const char *filename)
91 {
92     strncpy(name[i], filename, MAXSTR);
93     chan[i] = c;
94 }
95
96 void audio_play(int i, float v)
97 {
98     if (audio_state == 1 && buff[i])
99     {
100         Mix_VolumeChunk(buff[i], (int) (v * MIX_MAX_VOLUME));
101         Mix_PlayChannel(chan[i], buff[i], 0);
102     }
103 }
104
105 /*---------------------------------------------------------------------------*/
106
107 void audio_music_play(const char *filename)
108 {
109     if (audio_state)
110     {
111         audio_music_stop();
112
113         if ((config_get_d(CONFIG_MUSIC_VOLUME) > 0) &&
114             (song = Mix_LoadMUS(config_data(filename))))
115         {
116             Mix_PlayMusic(song, -1);
117             strcpy(curr_bgm, filename);
118         }
119     }
120 }
121
122 void audio_music_queue(const char *filename)
123 {
124     if (audio_state)
125     {
126         if (strlen(curr_bgm) == 0 || strcmp(filename, curr_bgm) != 0)
127         {
128             Mix_VolumeMusic(0);
129             fade_volume = 0.0f;
130
131             audio_music_play(filename);
132             strcpy(curr_bgm, filename);
133
134             Mix_PauseMusic();
135         }
136     }
137 }
138
139 void audio_music_stop(void)
140 {
141     if (audio_state)
142     {
143         if (Mix_PlayingMusic())
144             Mix_HaltMusic();
145
146         if (song)
147             Mix_FreeMusic(song);
148
149         song = NULL;
150     }
151 }
152
153 /*---------------------------------------------------------------------------*/
154 /*
155  * SDL_mixer already provides music fading.  Unfortunately, it halts playback
156  * at the end of a fade.  We need to be able to fade music back in from the
157  * point where it stopped.  So, we reinvent this wheel.
158  */
159
160 void audio_timer(float dt)
161 {
162     if (audio_state)
163     {
164         if (fade_rate > 0.0f || fade_rate < 0.0f)
165             fade_volume += dt / fade_rate;
166
167         if (fade_volume < 0.0f)
168         {
169             fade_volume = 0.0f;
170
171             if (strlen(next_bgm) == 0)
172             {
173                 fade_rate = 0.0f;
174                 if (Mix_PlayingMusic())
175                     Mix_PauseMusic();
176             }
177             else
178             {
179                 fade_rate = -fade_rate;
180                 audio_music_queue(next_bgm);
181             }
182         }
183
184         if (fade_volume > 1.0f)
185         {
186             fade_rate   = 0.0f;
187             fade_volume = 1.0f;
188         }
189
190         if (Mix_PausedMusic() && fade_rate > 0.0f)
191             Mix_ResumeMusic();
192
193         if (Mix_PlayingMusic())
194             Mix_VolumeMusic(config_get_d(CONFIG_MUSIC_VOLUME) *
195                             (int) (fade_volume * MIX_MAX_VOLUME) / 10);
196     }
197 }
198
199 void audio_music_fade_out(float t)
200 {
201     fade_rate = -t;
202     strcpy(next_bgm, "");
203 }
204
205 void audio_music_fade_in(float t)
206 {
207     fade_rate = +t;
208     strcpy(next_bgm, "");
209 }
210
211 void audio_music_fade_to(float t, const char *filename)
212 {
213     if (fade_volume > 0)
214     {
215         if (strlen(curr_bgm) == 0 || strcmp(filename, curr_bgm) != 0)
216         {
217             strcpy(next_bgm, filename);
218             fade_rate = -t;
219         }
220         else fade_rate = t;
221     }
222     else
223     {
224         audio_music_queue(filename);
225         audio_music_fade_in(t);
226     }
227 }
228
229 void audio_volume(int s, int m)
230 {
231     if (audio_state)
232     {
233         Mix_Volume(-1, s * MIX_MAX_VOLUME / 10);
234         Mix_VolumeMusic(m * MIX_MAX_VOLUME / 10);
235     }
236 }
237
238 /*---------------------------------------------------------------------------*/