DEADSOFTWARE

sound: separate and rewrite
[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 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 };
23 #pragma pack()
25 struct sound {
26 snd_t base;
27 Mix_Chunk *c;
28 };
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 }
90 } else {
91 logo("S_init: SDL_InitSubSytem: %s\n", SDL_GetError());
92 }
93 }
95 static Mix_Chunk *convert_this (int rate, const Uint8 *buf, int len) {
96 SDL_AudioCVT cvt;
97 Mix_Chunk *c = NULL;
98 if (SDL_BuildAudioCVT(&cvt, AUDIO_S8, 1, rate, devformat, devchannels, devfreq) != -1) {
99 int maxlen = len * cvt.len_mult;
100 Uint8 *maxbuf = malloc(maxlen);
101 if (maxbuf != NULL) {
102 memcpy(maxbuf, buf, len);
103 cvt.buf = maxbuf;
104 cvt.len = len;
105 if (SDL_ConvertAudio(&cvt) == 0) {
106 c = malloc(sizeof(Mix_Chunk));
107 if (c != NULL) {
108 c->allocated = 0;
109 c->abuf = maxbuf;
110 c->alen = len * cvt.len_ratio;
111 c->volume = MIX_MAX_VOLUME;
112 } else {
113 free(maxbuf);
115 } else {
116 free(maxbuf);
120 return c;
123 // TODO load raw sounds with voices
125 snd_t *S_get (int id) {
126 if (!devinit) {
127 return NULL;
129 struct dmi *snd = M_lock(id);
130 struct sound *res = NULL;
131 if (snd != NULL) {
132 int rlen = F_getreslen(id);
133 if (rlen > 16) {
134 Uint32 len = int2host(snd->len);
135 Uint32 rate = int2host(snd->rate);
136 Uint32 lstart = int2host(snd->lstart);
137 Uint32 llen = int2host(snd->llen);
138 if (len <= rlen - 8 && lstart + llen <= rlen - 16) {
139 Mix_Chunk *c = convert_this(rate, snd->data, len);
140 if (c != NULL) {
141 res = malloc(sizeof(struct sound));
142 if (res != NULL) {
143 res->base.tag = TAG_MIX1;
144 res->c = c;
145 // TODO loops
146 } else {
147 free(c);
150 } else {
151 logo("S_get(%i): invalid header {len=%u:rate=%u:lstart=%u:llen=%u:rlen=%i}\n", id, len, rate, lstart, llen, rlen);
153 } else {
154 logo("S_load(%i): too short\n", id);
156 M_unlock(snd);
157 } else {
158 logo("S_load(%i): not found\n", id);
160 return (snd_t*)res;
163 snd_t *S_load (const char name[8]) {
164 int id = F_findres(name);
165 return S_get(id);
168 short S_play (snd_t *s, short c, short v) {
169 assert(c >= 0 && c <= 8);
170 assert(v >= 0 && v <= 255);
171 short channel = 0;
172 if (devinit) {
173 if (s) {
174 struct sound *snd = (struct sound *)s;
175 assert(snd->base.tag == TAG_MIX1);
176 // TODO care about global volume level
177 snd->c->volume = v * MIX_MAX_VOLUME / 255;
178 channel = Mix_PlayChannel(c <= 0 ? -1 : c - 1, snd->c, 0);
179 channel = channel == -1 ? 0 : channel + 1;
182 return channel;
185 void S_stop (short c) {
186 assert(c >= 0 && c <= 8);
187 if (devinit) {
188 if (c > 0) {
189 Mix_HaltChannel(c - 1);
194 void S_volume (int v) {
195 snd_vol = min(max(v, 0), 128);
196 if (devinit) {
197 // TODO change relativelly for every channel
198 Mix_Volume(-1, v * MIX_MAX_VOLUME / 128);
202 void S_wait (void) {
203 if (devinit) {
204 while (Mix_Playing(-1) > 0) {
205 SDL_Delay(10);
210 void S_done (void) {
211 if (devinit) {
212 // TODO free memory
213 Mix_AllocateChannels(0);
214 Mix_CloseAudio();
215 SDL_QuitSubSystem(SDL_INIT_AUDIO);