DEADSOFTWARE

sound: fix voices in menu
[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>
13 #define TAG_MIX1 0x4d495831
15 #pragma pack(1)
16 typedef struct dmi {
17 Uint32 len; // length [bytes]
18 Uint32 rate; // freq [Hz]
19 Uint32 lstart; // loop start offset [bytes]
20 Uint32 llen; // loop length [bytes]
21 Uint8 data[]; // sound data
22 } dmi;
23 #pragma pack()
25 typedef struct sdlmixer_snd {
26 snd_t base;
27 Mix_Chunk *c;
28 } sdlmixer_snd;
30 short snd_vol; // public 0..128
32 static int devfreq = MIX_DEFAULT_FREQUENCY;
33 static Uint32 devformat = AUDIO_S16SYS; // MIX_DEFAULT_FORMAT
34 static int devchannels = 1; // MIX_DEFAULT_CHANNELS;
35 static int devchunksize = 1024;
36 static int devchunkchannels = 8;
37 static int devinit;
39 /* music */
41 short mus_vol;
42 char music_random;
43 int music_time;
44 int music_fade;
46 void S_initmusic (void) {
48 }
50 void S_donemusic (void) {
52 }
54 void S_startmusic (int time) {
56 }
58 void S_stopmusic (void) {
60 }
62 void S_volumemusic (int v) {
64 }
66 void F_loadmus (char n[8]) {
68 }
70 void F_freemus (void) {
72 }
74 void S_updatemusic (void) {
76 }
78 /* Sound */
80 void S_init (void) {
81 assert(devinit == 0);
82 logo("S_init: initialize sound\n");
83 if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
84 if (Mix_OpenAudio(devfreq, devformat, devchannels, devchunksize) == 0) {
85 Mix_AllocateChannels(devchunkchannels);
86 devinit = 1;
87 } else {
88 logo("S_init: Mix_OpenAudio: %s\n", Mix_GetError());
89 SDL_QuitSubSystem(SDL_INIT_AUDIO);
90 }
91 } else {
92 logo("S_init: SDL_InitSubSytem: %s\n", SDL_GetError());
93 }
94 }
96 static Mix_Chunk *convert_this (int rate, int sign, const Uint8 *buf, int len) {
97 SDL_AudioCVT cvt;
98 Mix_Chunk *c = NULL;
99 if (SDL_BuildAudioCVT(&cvt, sign ? AUDIO_S8 : AUDIO_U8, 1, rate, devformat, devchannels, devfreq) != -1) {
100 int maxlen = len * cvt.len_mult;
101 Uint8 *maxbuf = malloc(maxlen);
102 if (maxbuf != NULL) {
103 memcpy(maxbuf, buf, len);
104 cvt.buf = maxbuf;
105 cvt.len = len;
106 if (SDL_ConvertAudio(&cvt) == 0) {
107 c = malloc(sizeof(Mix_Chunk));
108 if (c != NULL) {
109 c->allocated = 0;
110 c->abuf = maxbuf;
111 c->alen = len * cvt.len_ratio;
112 c->volume = MIX_MAX_VOLUME;
113 } else {
114 free(maxbuf);
116 } else {
117 free(maxbuf);
121 return c;
124 static sdlmixer_snd *new_sdlmixer_snd (const void *data, dword len, dword rate, dword lstart, dword llen, int sign) {
125 Mix_Chunk *c = NULL;
126 sdlmixer_snd *snd = NULL;
127 c = convert_this(rate, sign, data, len);
128 if (c != NULL) {
129 snd = malloc(sizeof(sdlmixer_snd));
130 if (snd != NULL) {
131 snd->base.tag = TAG_MIX1;
132 snd->c = c;
133 } else {
134 free(c->abuf);
135 free(c);
138 return snd;
141 snd_t *S_get (int id) {
142 void *handle;
143 sdlmixer_snd *snd = NULL;
144 if (devinit != NULL) {
145 handle = M_lock(id);
146 if (handle != NULL) {
147 void *data = handle;
148 dword len = F_getreslen(id);
149 dword rate = 11025;
150 dword lstart = 0;
151 dword llen = 0;
152 int sign = 0;
153 if (len > 16) {
154 dmi *hdr = handle;
155 dword hdr_len = int2host(hdr->len);
156 dword hdr_rate = int2host(hdr->rate);
157 dword hdr_lstart = int2host(hdr->lstart);
158 dword hdr_llen = int2host(hdr->llen);
159 if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) {
160 data = hdr->data;
161 len = hdr_len;
162 rate = hdr_rate;
163 lstart = hdr_lstart;
164 llen = hdr_llen;
165 sign = 1;
168 snd = new_sdlmixer_snd(data, len, rate, lstart, llen, sign);
169 M_unlock(handle);
172 return (snd_t*)snd;
175 snd_t *S_load (const char name[8]) {
176 int id = F_findres(name);
177 return S_get(id);
180 void S_free (snd_t *s) {
181 int i;
182 sdlmixer_snd *snd = (sdlmixer_snd*)s;
183 if (snd != NULL) {
184 assert(snd->base.tag == TAG_MIX1);
185 if (devinit) {
186 for (i = 0; i < devchunkchannels; i++) {
187 if (Mix_GetChunk(i) == snd->c) {
188 Mix_HaltChannel(i);
192 free(snd->c->abuf);
193 free(snd->c);
194 free(snd);
198 short S_play (snd_t *s, short c, short v) {
199 short channel = 0;
200 sdlmixer_snd *snd = (sdlmixer_snd*)s;
201 assert(c >= 0 && c <= 8);
202 assert(v >= 0 && v <= 255);
203 if (devinit && snd != NULL) {
204 assert(snd->base.tag == TAG_MIX1);
205 // TODO care about global volume level
206 snd->c->volume = v * MIX_MAX_VOLUME / 255;
207 channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
208 channel = channel == -1 ? 0 : channel + 1;
210 return channel;
213 void S_stop (short c) {
214 assert(c >= 0 && c <= 8);
215 if (devinit && c > 0) {
216 Mix_HaltChannel(c - 1);
220 void S_volume (int v) {
221 snd_vol = min(max(v, 0), 128);
222 if (devinit) {
223 // TODO change relativelly for every channel
224 Mix_Volume(-1, v * MIX_MAX_VOLUME / 128);
228 void S_wait (void) {
229 if (devinit) {
230 while (Mix_Playing(-1) > 0) {
231 SDL_Delay(10);
236 void S_done (void) {
237 if (devinit) {
238 // TODO free memory
239 Mix_AllocateChannels(0);
240 Mix_CloseAudio();
241 SDL_QuitSubSystem(SDL_INIT_AUDIO);