DEADSOFTWARE

map: move map loading to separate file
[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 short snd_vol; // public 0..128
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 short mus_vol;
43 char music_random;
44 int music_time;
45 int music_fade;
47 void S_initmusic (void) {
49 }
51 void S_donemusic (void) {
53 }
55 void S_startmusic (int time) {
57 }
59 void S_stopmusic (void) {
61 }
63 void S_volumemusic (int v) {
65 }
67 void F_loadmus (char n[8]) {
69 }
71 void F_freemus (void) {
73 }
75 void S_updatemusic (void) {
77 }
79 /* Sound */
81 void S_init (void) {
82 assert(devinit == 0);
83 logo("S_init: initialize sound\n");
84 if (SDL_InitSubSystem(SDL_INIT_AUDIO) == 0) {
85 if (Mix_OpenAudio(devfreq, devformat, devchannels, devchunksize) == 0) {
86 Mix_AllocateChannels(devchunkchannels);
87 devinit = 1;
88 } else {
89 logo("S_init: Mix_OpenAudio: %s\n", Mix_GetError());
90 SDL_QuitSubSystem(SDL_INIT_AUDIO);
91 }
92 } else {
93 logo("S_init: SDL_InitSubSytem: %s\n", SDL_GetError());
94 }
95 }
97 static Mix_Chunk *convert_this (int rate, int sign, const Uint8 *buf, int len) {
98 SDL_AudioCVT cvt;
99 Mix_Chunk *c = NULL;
100 if (SDL_BuildAudioCVT(&cvt, sign ? AUDIO_S8 : AUDIO_U8, 1, rate, devformat, devchannels, devfreq) != -1) {
101 int maxlen = len * cvt.len_mult;
102 Uint8 *maxbuf = malloc(maxlen);
103 if (maxbuf != NULL) {
104 memcpy(maxbuf, buf, len);
105 cvt.buf = maxbuf;
106 cvt.len = len;
107 if (SDL_ConvertAudio(&cvt) == 0) {
108 c = malloc(sizeof(Mix_Chunk));
109 if (c != NULL) {
110 c->allocated = 0;
111 c->abuf = maxbuf;
112 c->alen = len * cvt.len_ratio;
113 c->volume = MIX_MAX_VOLUME;
114 } else {
115 free(maxbuf);
117 } else {
118 free(maxbuf);
122 return c;
125 static sdlmixer_snd *new_sdlmixer_snd (const void *data, dword len, dword rate, dword lstart, dword llen, int sign) {
126 Mix_Chunk *c = NULL;
127 sdlmixer_snd *snd = NULL;
128 c = convert_this(rate, sign, data, len);
129 if (c != NULL) {
130 snd = malloc(sizeof(sdlmixer_snd));
131 if (snd != NULL) {
132 snd->base.tag = TAG_MIX1;
133 snd->c = c;
134 } else {
135 free(c->abuf);
136 free(c);
139 return snd;
142 snd_t *S_get (int id) {
143 void *handle;
144 sdlmixer_snd *snd = NULL;
145 if (devinit) {
146 handle = M_lock(id);
147 if (handle != NULL) {
148 void *data = handle;
149 dword len = F_getreslen(id);
150 dword rate = 11025;
151 dword lstart = 0;
152 dword llen = 0;
153 int sign = 0;
154 if (len > 16) {
155 dmi *hdr = handle;
156 dword hdr_len = int2host(hdr->len);
157 dword hdr_rate = int2host(hdr->rate);
158 dword hdr_lstart = int2host(hdr->lstart);
159 dword hdr_llen = int2host(hdr->llen);
160 if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) {
161 data = hdr->data;
162 len = hdr_len;
163 rate = hdr_rate;
164 lstart = hdr_lstart;
165 llen = hdr_llen;
166 sign = 1;
169 snd = new_sdlmixer_snd(data, len, rate, lstart, llen, sign);
170 M_unlock(handle);
173 return (snd_t*)snd;
176 snd_t *S_load (const char name[8]) {
177 int id = F_findres(name);
178 return S_get(id);
181 void S_free (snd_t *s) {
182 int i;
183 sdlmixer_snd *snd = (sdlmixer_snd*)s;
184 if (snd != NULL) {
185 assert(snd->base.tag == TAG_MIX1);
186 if (devinit) {
187 for (i = 0; i < devchunkchannels; i++) {
188 if (Mix_GetChunk(i) == snd->c) {
189 Mix_HaltChannel(i);
193 free(snd->c->abuf);
194 free(snd->c);
195 free(snd);
199 short S_play (snd_t *s, short c, short v) {
200 short channel = 0;
201 sdlmixer_snd *snd = (sdlmixer_snd*)s;
202 assert(c >= 0 && c <= 8);
203 assert(v >= 0 && v <= 255);
204 if (devinit && snd != NULL) {
205 assert(snd->base.tag == TAG_MIX1);
206 // TODO care about global volume level
207 snd->c->volume = v * MIX_MAX_VOLUME / 255;
208 channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
209 channel = channel == -1 ? 0 : channel + 1;
211 return channel;
214 void S_stop (short c) {
215 assert(c >= 0 && c <= 8);
216 if (devinit && c > 0) {
217 Mix_HaltChannel(c - 1);
221 void S_volume (int v) {
222 snd_vol = min(max(v, 0), 128);
223 if (devinit) {
224 // TODO change relativelly for every channel
225 Mix_Volume(-1, v * MIX_MAX_VOLUME / 128);
229 void S_wait (void) {
230 if (devinit) {
231 while (Mix_Playing(-1) > 0) {
232 SDL_Delay(10);
237 void S_done (void) {
238 if (devinit) {
239 // TODO free memory
240 Mix_AllocateChannels(0);
241 Mix_CloseAudio();
242 SDL_QuitSubSystem(SDL_INIT_AUDIO);