DEADSOFTWARE

sound: move sound/music configuration to sound driver
[flatwaifu.git] / src / sdlmixer / sound.c
1 #include "glob.h"
2 #include "sound.h"
3 #include "music.h"
4 #include "misc.h" // int2host
5 #include "memory.h" // M_lock M_unlock
6 #include "files.h" // F_findres
7 #include "error.h"
9 #include "SDL.h"
10 #include "SDL_mixer.h"
11 #include <assert.h>
12 #include <string.h>
14 #define TAG_MIX1 0x4d495831
16 #pragma pack(1)
17 typedef struct dmi {
18 Uint32 len; // length [bytes]
19 Uint32 rate; // freq [Hz]
20 Uint32 lstart; // loop start offset [bytes]
21 Uint32 llen; // loop length [bytes]
22 Uint8 data[]; // sound data
23 } dmi;
24 #pragma pack()
26 typedef struct sdlmixer_snd {
27 snd_t base;
28 Mix_Chunk *c;
29 } sdlmixer_snd;
31 static short snd_vol;
33 static int devfreq = MIX_DEFAULT_FREQUENCY;
34 static Uint32 devformat = AUDIO_S16SYS; // MIX_DEFAULT_FORMAT
35 static int devchannels = 1; // MIX_DEFAULT_CHANNELS;
36 static int devchunksize = 1024;
37 static int devchunkchannels = 8;
38 static int devinit;
40 /* music */
42 const cfg_t *MUS_args (void) {
43 return NULL;
44 }
46 const cfg_t *MUS_conf (void) {
47 return NULL;
48 }
50 const menu_t *MUS_menu (void) {
51 return NULL;
52 }
54 void MUS_init (void) {
56 }
58 void MUS_done (void) {
60 }
62 void MUS_start (int time) {
64 }
66 void MUS_stop (void) {
68 }
70 void MUS_volume (int v) {
72 }
74 void MUS_load (char n[8]) {
76 }
78 void MUS_free (void) {
80 }
82 void MUS_update (void) {
84 }
86 /* Sound */
88 static int sound_menu_handler (menu_msg_t *msg, const menu_t *m, void *data, int i) {
89 static int cur;
90 enum { VOLUME, __NUM__ };
91 static const simple_menu_t sm = {
92 GM_BIG, "Sound", NULL,
93 {
94 { "Volume", NULL },
95 }
96 };
97 if (i == VOLUME) {
98 switch (msg->type) {
99 case GM_GETENTRY: return GM_init_int0(msg, GM_SCROLLER, 0, 0, 0);
100 case GM_GETINT: return GM_init_int(msg, snd_vol, 0, 128, 8);
101 case GM_SETINT: S_volume(msg->integer.i); return 1;
104 return simple_menu_handler(msg, i, __NUM__, &sm, &cur);
107 const menu_t *S_menu (void) {
108 static const menu_t m = {
109 NULL, &sound_menu_handler
110 };
111 return &m;
114 const cfg_t *S_args (void) {
115 static const cfg_t args[] = {
116 { "sndvol", &snd_vol, Y_WORD },
117 { NULL, NULL, 0 }
118 };
119 return args;
122 const cfg_t *S_conf (void) {
123 static const cfg_t conf[] = {
124 { "sound_volume", &snd_vol, Y_WORD },
125 { NULL, NULL, 0 }
126 };
127 return conf;
130 void S_init (void) {
131 assert(devinit == 0);
132 logo("S_init: initialize sound\n");
133 if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
134 if (Mix_OpenAudio(devfreq, devformat, devchannels, devchunksize) == 0) {
135 Mix_AllocateChannels(devchunkchannels);
136 devinit = 1;
137 } else {
138 logo("S_init: Mix_OpenAudio: %s\n", Mix_GetError());
139 SDL_QuitSubSystem(SDL_INIT_AUDIO);
141 } else {
142 logo("S_init: SDL_InitSubSytem: %s\n", SDL_GetError());
146 static Mix_Chunk *convert_this (int rate, int sign, const Uint8 *buf, int len) {
147 SDL_AudioCVT cvt;
148 Mix_Chunk *c = NULL;
149 if (SDL_BuildAudioCVT(&cvt, sign ? AUDIO_S8 : AUDIO_U8, 1, rate, devformat, devchannels, devfreq) != -1) {
150 int maxlen = len * cvt.len_mult;
151 Uint8 *maxbuf = malloc(maxlen);
152 if (maxbuf != NULL) {
153 memcpy(maxbuf, buf, len);
154 cvt.buf = maxbuf;
155 cvt.len = len;
156 if (SDL_ConvertAudio(&cvt) == 0) {
157 c = malloc(sizeof(Mix_Chunk));
158 if (c != NULL) {
159 c->allocated = 0;
160 c->abuf = maxbuf;
161 c->alen = len * cvt.len_ratio;
162 c->volume = MIX_MAX_VOLUME;
163 } else {
164 free(maxbuf);
166 } else {
167 free(maxbuf);
171 return c;
174 static sdlmixer_snd *new_sdlmixer_snd (const void *data, dword len, dword rate, dword lstart, dword llen, int sign) {
175 Mix_Chunk *c = NULL;
176 sdlmixer_snd *snd = NULL;
177 c = convert_this(rate, sign, data, len);
178 if (c != NULL) {
179 snd = malloc(sizeof(sdlmixer_snd));
180 if (snd != NULL) {
181 snd->base.tag = TAG_MIX1;
182 snd->c = c;
183 } else {
184 free(c->abuf);
185 free(c);
188 return snd;
191 snd_t *S_get (int id) {
192 void *handle;
193 sdlmixer_snd *snd = NULL;
194 if (devinit) {
195 handle = M_lock(id);
196 if (handle != NULL) {
197 void *data = handle;
198 dword len = F_getreslen(id);
199 dword rate = 11025;
200 dword lstart = 0;
201 dword llen = 0;
202 int sign = 0;
203 if (len > 16) {
204 dmi *hdr = handle;
205 dword hdr_len = int2host(hdr->len);
206 dword hdr_rate = int2host(hdr->rate);
207 dword hdr_lstart = int2host(hdr->lstart);
208 dword hdr_llen = int2host(hdr->llen);
209 if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) {
210 data = hdr->data;
211 len = hdr_len;
212 rate = hdr_rate;
213 lstart = hdr_lstart;
214 llen = hdr_llen;
215 sign = 1;
218 snd = new_sdlmixer_snd(data, len, rate, lstart, llen, sign);
219 M_unlock(handle);
222 return (snd_t*)snd;
225 snd_t *S_load (const char name[8]) {
226 int id = F_findres(name);
227 return S_get(id);
230 void S_free (snd_t *s) {
231 int i;
232 sdlmixer_snd *snd = (sdlmixer_snd*)s;
233 if (snd != NULL) {
234 assert(snd->base.tag == TAG_MIX1);
235 if (devinit) {
236 for (i = 0; i < devchunkchannels; i++) {
237 if (Mix_GetChunk(i) == snd->c) {
238 Mix_HaltChannel(i);
242 free(snd->c->abuf);
243 free(snd->c);
244 free(snd);
248 short S_play (snd_t *s, short c, short v) {
249 short channel = 0;
250 sdlmixer_snd *snd = (sdlmixer_snd*)s;
251 assert(c >= 0 && c <= 8);
252 assert(v >= 0 && v <= 255);
253 if (devinit && snd != NULL) {
254 assert(snd->base.tag == TAG_MIX1);
255 // TODO care about global volume level
256 snd->c->volume = v * MIX_MAX_VOLUME / 255;
257 channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
258 channel = channel == -1 ? 0 : channel + 1;
260 return channel;
263 void S_stop (short c) {
264 assert(c >= 0 && c <= 8);
265 if (devinit && c > 0) {
266 Mix_HaltChannel(c - 1);
270 void S_volume (int v) {
271 snd_vol = min(max(v, 0), 128);
272 if (devinit) {
273 // TODO change relativelly for every channel
274 Mix_Volume(-1, v * MIX_MAX_VOLUME / 128);
278 void S_wait (void) {
279 if (devinit) {
280 while (Mix_Playing(-1) > 0) {
281 SDL_Delay(10);
286 void S_done (void) {
287 if (devinit) {
288 // TODO free memory
289 Mix_AllocateChannels(0);
290 Mix_CloseAudio();
291 SDL_QuitSubSystem(SDL_INIT_AUDIO);