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
10 #include <OpenAL/alc.h>
11 #include <SDL.h> // SDL_BuildAudioCVT SDL_ConvertAudio
13 #include <stdlib.h> // malloc
14 #include <string.h> // memcpy
16 #define TAG_OAL1 0x4F414C31
17 #define MAX_CHANNELS 8
29 typedef struct openal_snd
{
34 typedef struct openal_channel
{
44 static ALCdevice
*device
;
45 static ALCcontext
*context
;
46 static ALuint sources
[MAX_CHANNELS
];
50 void S_initmusic (void) {
54 void S_donemusic (void) {
58 void S_startmusic (int time
) {
62 void S_stopmusic (void) {
66 void S_volumemusic (int v
) {
70 void F_loadmus (char n
[8]) {
74 void F_freemus (void) {
78 void S_updatemusic (void) {
84 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
) {
88 if (SDL_BuildAudioCVT(&cvt
, src_format
, src_chan
, src_rate
, dst_format
, dst_chan
, dst_rate
) != -1) {
89 *maxlen
= len
* cvt
.len_mult
;
90 *maxbuf
= malloc(*maxlen
);
91 if (*maxbuf
!= NULL
) {
92 memcpy(*maxbuf
, buf
, len
);
95 if (SDL_ConvertAudio(&cvt
) == 0) {
96 *maxlen
= len
* cvt
.len_ratio
;
106 static openal_snd
*new_openal_snd (const void *data
, dword len
, dword rate
, dword lstart
, dword llen
, int sign
) {
109 openal_snd
*snd
= NULL
;
110 void *newdata
= NULL
;
112 // for some reason 8bit formats makes psshshshsh
113 // TODO do this without SDL
114 convert_this_ext(sign
? AUDIO_S8
: AUDIO_U8
, 1, rate
, AUDIO_S16SYS
, 1, rate
, data
, len
, &newdata
, &newlen
);
115 if (newdata
!= NULL
) {
116 alGenBuffers(1, &buffer
);
117 if (alGetError() == AL_NO_ERROR
) {
118 alBufferData(buffer
, AL_FORMAT_MONO16
, newdata
, newlen
, rate
);
119 if (alGetError() == AL_NO_ERROR
) {
120 snd
= malloc(sizeof(openal_snd
));
122 snd
->base
.tag
= TAG_OAL1
;
123 snd
->buffer
= buffer
;
126 alDeleteBuffers(1, &buffer
);
129 alDeleteBuffers(1, &buffer
);
137 snd_t
*S_get (int id
) {
139 openal_snd
*snd
= NULL
;
140 if (context
!= NULL
) {
142 if (handle
!= NULL
) {
144 dword len
= F_getreslen(id
);
151 dword hdr_len
= int2host(hdr
->len
);
152 dword hdr_rate
= int2host(hdr
->rate
);
153 dword hdr_lstart
= int2host(hdr
->lstart
);
154 dword hdr_llen
= int2host(hdr
->llen
);
155 if (hdr_len
<= len
- 8 && hdr_lstart
+ hdr_llen
<= len
- 16) {
164 snd
= new_openal_snd(data
, len
, rate
, lstart
, llen
, sign
);
171 snd_t
*S_load (const char name
[8]) {
172 return S_get(F_findres(name
));
175 void S_free (snd_t
*s
) {
178 openal_snd
*snd
= (openal_snd
*)s
;
180 assert(snd
->base
.tag
= TAG_OAL1
);
181 if (context
!= NULL
) {
182 for (i
= 0; i
< MAX_CHANNELS
; i
++) {
183 alGetSourcei(sources
[i
], AL_BUFFER
, &h
);
184 if (h
== snd
->buffer
) {
185 alSourceStop(sources
[i
]);
186 alSourcei(sources
[i
], AL_BUFFER
, 0);
189 alDeleteBuffers(1, &snd
->buffer
);
190 assert(alGetError() == AL_NO_ERROR
);
198 assert(device
== NULL
&& context
== NULL
);
199 const ALCint attrs
[] = {ALC_MONO_SOURCES
, MAX_CHANNELS
, 0};
200 device
= alcOpenDevice(NULL
);
201 if (device
!= NULL
) {
202 context
= alcCreateContext(device
, attrs
);
203 if (context
!= NULL
) {
204 if (alcMakeContextCurrent(context
)) {
205 alGenSources(MAX_CHANNELS
, sources
);
206 if (alGetError() == AL_NO_ERROR
) {
207 alListenerf(AL_GAIN
, 1);
208 alListener3f(AL_POSITION
, 0, 0, 0);
209 alListener3f(AL_VELOCITY
, 0, 0, 0);
211 logo("S_init: unable to create OpenAL sources\n");
212 alcDestroyContext(context
);
213 alcCloseDevice(device
);
218 logo("S_init: unable to make OpenAL context current\n");
219 alcDestroyContext(context
);
220 alcCloseDevice(device
);
225 logo("S_init: unable to create OpenAL context\n");
226 alcCloseDevice(device
);
230 logo("S_init: unable to open OpenAL device\n");
235 if (context
!= NULL
) {
236 alcMakeContextCurrent(NULL
);
237 alcDestroyContext(context
);
238 alcCloseDevice(device
);
244 short S_play (snd_t
*s
, short c
, short v
) {
245 assert(c
>= 0 && c
<= MAX_CHANNELS
);
246 assert(v
>= 0 && v
< 256);
250 if (context
!= NULL
&& s
!= NULL
) {
251 openal_snd
*snd
= (openal_snd
*)s
;
252 assert(snd
->base
.tag
== TAG_OAL1
);
254 for (channel
= 0; channel
< MAX_CHANNELS
; channel
++) {
256 alGetSourcei(sources
[channel
], AL_SOURCE_STATE
, &state
);
257 if (state
== AL_STOPPED
|| state
== AL_INITIAL
) {
264 if (channel
< MAX_CHANNELS
) {
265 source
= sources
[channel
];
266 alSourceStop(source
);
267 alSourcei(source
, AL_BUFFER
, snd
->buffer
);
268 alSourcef(source
, AL_PITCH
, 1);
269 alSourcef(source
, AL_GAIN
, v
/ 255.0);
270 alSource3f(source
, AL_POSITION
, 0, 0, 0);
271 alSource3f(source
, AL_VELOCITY
, 0, 0, 0);
272 alSourcei(source
, AL_LOOPING
, AL_FALSE
);
273 alSourcePlay(source
);
279 void S_stop (short c
) {
280 assert(c
>= 0 && c
<= MAX_CHANNELS
);
281 if (context
!= NULL
) {
283 alSourceStop(sources
[c
- 1]);
288 void S_volume (int v
) {
289 assert(v
>= 0 && v
<= 128);
291 if (context
!= NULL
) {
292 alListenerf(AL_GAIN
, v
/ 128.0);
299 if (context
!= NULL
) {
300 for (i
= 0; i
< MAX_CHANNELS
; i
++) {
303 alGetSourcei(sources
[i
], AL_SOURCE_STATE
, &state
);
304 } while (state
== AL_PLAYING
);