DEADSOFTWARE

73d36a42968a46e87f3548c900257a0dd84635a8
[flatwaifu.git] / src / openal / sound.c
1 #include "sound.h"
2 #include "music.h"
4 #include "files.h" // F_findres F_getreslen
5 #include "memory.h" // M_lock M_unlock
6 #include "misc.h" // int2host
7 #include "error.h" // logo
9 #ifdef __APPLE__
10 # include <OpenAL/al.h>
11 # include <OpenAL/alc.h>
12 #else
13 # include <AL/al.h>
14 # include <AL/alc.h>
15 #endif
17 #include "SDL.h" // SDL_BuildAudioCVT SDL_ConvertAudio
18 #include <assert.h>
19 #include <stdlib.h> // malloc
20 #include <string.h> // memcpy
22 #define TAG_OAL1 0x4F414C31
23 #define MAX_CHANNELS 8
25 #pragma pack(1)
26 typedef struct dmi {
27 dword len;
28 dword rate;
29 dword lstart;
30 dword llen;
31 byte data[];
32 } dmi;
33 #pragma pack()
35 typedef struct openal_snd {
36 snd_t base;
37 ALuint buffer;
38 } openal_snd;
40 typedef struct openal_channel {
41 ALuint source;
42 } openal_channel;
44 short snd_vol;
45 short mus_vol;
46 char music_random;
47 int music_time;
48 int music_fade;
50 static ALCdevice *device;
51 static ALCcontext *context;
52 static ALuint sources[MAX_CHANNELS];
54 /* Music */
56 void S_initmusic (void) {
58 }
60 void S_donemusic (void) {
62 }
64 void S_startmusic (int time) {
66 }
68 void S_stopmusic (void) {
70 }
72 void S_volumemusic (int v) {
74 }
76 void F_loadmus (char n[8]) {
78 }
80 void F_freemus (void) {
82 }
84 void S_updatemusic (void) {
86 }
88 /* Sound */
90 static void convert_this_ext (Uint32 src_format, int src_chan, int src_rate, Uint32 dst_format, int dst_chan, int dst_rate, const void *buf, int len, void **maxbuf, int *maxlen) {
91 SDL_AudioCVT cvt;
92 *maxlen = 0;
93 *maxbuf = NULL;
94 if (SDL_BuildAudioCVT(&cvt, src_format, src_chan, src_rate, dst_format, dst_chan, dst_rate) != -1) {
95 *maxlen = len * cvt.len_mult;
96 *maxbuf = malloc(*maxlen);
97 if (*maxbuf != NULL) {
98 memcpy(*maxbuf, buf, len);
99 cvt.buf = *maxbuf;
100 cvt.len = len;
101 if (SDL_ConvertAudio(&cvt) == 0) {
102 *maxlen = len * cvt.len_ratio;
103 } else {
104 free(*maxbuf);
105 *maxbuf = NULL;
106 *maxlen = 0;
112 static openal_snd *new_openal_snd (const void *data, dword len, dword rate, dword lstart, dword llen, int sign) {
113 assert(data);
114 ALuint buffer = 0;
115 openal_snd *snd = NULL;
116 void *newdata = NULL;
117 int newlen = 0;
118 // for some reason 8bit formats makes psshshshsh
119 // TODO do this without SDL
120 convert_this_ext(sign ? AUDIO_S8 : AUDIO_U8, 1, rate, AUDIO_S16SYS, 1, rate, data, len, &newdata, &newlen);
121 if (newdata != NULL) {
122 alGenBuffers(1, &buffer);
123 if (alGetError() == AL_NO_ERROR) {
124 alBufferData(buffer, AL_FORMAT_MONO16, newdata, newlen, rate);
125 if (alGetError() == AL_NO_ERROR) {
126 snd = malloc(sizeof(openal_snd));
127 if (snd != NULL) {
128 snd->base.tag = TAG_OAL1;
129 snd->buffer = buffer;
130 // TODO loops
131 } else {
132 alDeleteBuffers(1, &buffer);
134 } else {
135 alDeleteBuffers(1, &buffer);
138 free(newdata);
140 return snd;
143 snd_t *S_get (int id) {
144 void *handle;
145 openal_snd *snd = NULL;
146 if (context != NULL) {
147 handle = M_lock(id);
148 if (handle != NULL) {
149 void *data = handle;
150 dword len = F_getreslen(id);
151 dword rate = 11025;
152 dword lstart = 0;
153 dword llen = 0;
154 int sign = 0;
155 if (len > 16) {
156 dmi *hdr = handle;
157 dword hdr_len = int2host(hdr->len);
158 dword hdr_rate = int2host(hdr->rate);
159 dword hdr_lstart = int2host(hdr->lstart);
160 dword hdr_llen = int2host(hdr->llen);
161 if (hdr_len <= len - 8 && hdr_lstart + hdr_llen <= len - 16) {
162 data = hdr->data;
163 len = hdr_len;
164 rate = hdr_rate;
165 lstart = hdr_lstart;
166 llen = hdr_llen;
167 sign = 1;
170 snd = new_openal_snd(data, len, rate, lstart, llen, sign);
171 M_unlock(handle);
174 return (snd_t*)snd;
177 snd_t *S_load (const char name[8]) {
178 return S_get(F_findres(name));
181 void S_free (snd_t *s) {
182 int i;
183 ALint h;
184 openal_snd *snd = (openal_snd*)s;
185 if (snd != NULL) {
186 assert(snd->base.tag == TAG_OAL1);
187 if (context != NULL) {
188 for (i = 0; i < MAX_CHANNELS; i++) {
189 alGetSourcei(sources[i], AL_BUFFER, &h);
190 if (h == snd->buffer) {
191 alSourceStop(sources[i]);
192 alSourcei(sources[i], AL_BUFFER, 0);
195 alDeleteBuffers(1, &snd->buffer);
196 assert(alGetError() == AL_NO_ERROR);
198 snd->base.tag = 0;
199 free(s);
203 void S_init (void) {
204 assert(device == NULL && context == NULL);
205 const ALCint attrs[] = {ALC_MONO_SOURCES, MAX_CHANNELS, 0};
206 device = alcOpenDevice(NULL);
207 if (device != NULL) {
208 context = alcCreateContext(device, attrs);
209 if (context != NULL) {
210 if (alcMakeContextCurrent(context)) {
211 alGenSources(MAX_CHANNELS, sources);
212 if (alGetError() == AL_NO_ERROR) {
213 alListenerf(AL_GAIN, 1);
214 alListener3f(AL_POSITION, 0, 0, 0);
215 alListener3f(AL_VELOCITY, 0, 0, 0);
216 } else {
217 logo("S_init: unable to create OpenAL sources\n");
218 alcDestroyContext(context);
219 alcCloseDevice(device);
220 context = NULL;
221 device = NULL;
223 } else {
224 logo("S_init: unable to make OpenAL context current\n");
225 alcDestroyContext(context);
226 alcCloseDevice(device);
227 context = NULL;
228 device = NULL;
230 } else {
231 logo("S_init: unable to create OpenAL context\n");
232 alcCloseDevice(device);
233 device = NULL;
235 } else {
236 logo("S_init: unable to open OpenAL device\n");
240 void S_done (void) {
241 if (context != NULL) {
242 alcMakeContextCurrent(NULL);
243 alcDestroyContext(context);
244 alcCloseDevice(device);
246 context = NULL;
247 device = NULL;
250 short S_play (snd_t *s, short c, short v) {
251 assert(c >= 0 && c <= MAX_CHANNELS);
252 assert(v >= 0 && v < 256);
253 ALuint source;
254 ALint state;
255 int channel;
256 if (context != NULL && s != NULL) {
257 openal_snd *snd = (openal_snd*)s;
258 assert(snd->base.tag == TAG_OAL1);
259 if (c == 0) {
260 for (channel = 0; channel < MAX_CHANNELS; channel++) {
261 state = AL_PLAYING;
262 alGetSourcei(sources[channel], AL_SOURCE_STATE, &state);
263 if (state == AL_STOPPED || state == AL_INITIAL) {
264 break; // !!!
267 } else {
268 channel = c - 1;
270 if (channel < MAX_CHANNELS) {
271 source = sources[channel];
272 alSourceStop(source);
273 alSourcei(source, AL_BUFFER, snd->buffer);
274 alSourcef(source, AL_PITCH, 1);
275 alSourcef(source, AL_GAIN, v / 255.0);
276 alSource3f(source, AL_POSITION, 0, 0, 0);
277 alSource3f(source, AL_VELOCITY, 0, 0, 0);
278 alSourcei(source, AL_LOOPING, AL_FALSE);
279 alSourcePlay(source);
282 return 0;
285 void S_stop (short c) {
286 assert(c >= 0 && c <= MAX_CHANNELS);
287 if (context != NULL) {
288 if (c != 0) {
289 alSourceStop(sources[c - 1]);
294 void S_volume (int v) {
295 assert(v >= 0 && v <= 128);
296 snd_vol = v;
297 if (context != NULL) {
298 alListenerf(AL_GAIN, v / 128.0);
302 void S_wait (void) {
303 int i;
304 ALint state;
305 if (context != NULL) {
306 for (i = 0; i < MAX_CHANNELS; i++) {
307 do {
308 state = AL_STOPPED;
309 alGetSourcei(sources[i], AL_SOURCE_STATE, &state);
310 } while (state == AL_PLAYING);