42#include <acfutils/riff.h>
44#include <acfutils/time.h>
45#include <acfutils/types.h>
46#include <acfutils/wav.h>
50#define WAVE_ID FOURCC("WAVE")
51#define FMT_ID FOURCC("fmt ")
52#define DATA_ID FOURCC("data")
54#define READ_BUFSZ ((1024 * 1024) / sizeof (opus_int16))
56#define WAV_OP_PARAM(al_op, al_param_name, err_ret, ...) \
60 memset(&sav, 0, sizeof (sav)); \
61 if (wav == NULL || wav->alsrc == 0) \
63 VERIFY(ctx_save(wav->alc, &sav)); \
64 al_op(wav->alsrc, al_param_name, __VA_ARGS__); \
65 if ((err = alGetError()) != AL_NO_ERROR) { \
66 logMsg("Error performing " #al_op "(" #al_param_name \
67 ") on WAV %s, error 0x%x.", wav->name, err); \
68 VERIFY(ctx_restore(wav->alc, &sav)); \
71 VERIFY(ctx_restore(wav->alc, &sav)); \
74#define WAV_SET_PARAM(al_op, al_param_name, ...) \
75 WAV_OP_PARAM(al_op, al_param_name, , __VA_ARGS__)
77#define LISTENER_OP_PARAM(al_op, al_param_name, err_ret, ...) \
81 memset(&sav, 0, sizeof (sav)); \
82 VERIFY(ctx_save(alc, &sav)); \
83 al_op(al_param_name, __VA_ARGS__); \
84 if ((err = alGetError()) != AL_NO_ERROR) { \
85 logMsg("Error changing listener param " \
86 #al_param_name ", error 0x%x.", err); \
87 VERIFY(ctx_restore(alc, &sav)); \
90 VERIFY(ctx_restore(alc, &sav)); \
93#define LISTENER_SET_PARAM(al_op, al_param_name, ...) \
94 LISTENER_OP_PARAM(al_op, al_param_name, , __VA_ARGS__)
108ctx_save(alc_t *
alc, alc_t *sav)
115 if (
alc != NULL &&
alc->thr_local)
120 if (
alc != NULL &&
alc->ctx == NULL)
123 sav->ctx = alcGetCurrentContext();
125 if (
alc != NULL && sav->ctx ==
alc->ctx)
128 if (sav->ctx != NULL) {
129 sav->dev = alcGetContextsDevice(sav->ctx);
137 alcMakeContextCurrent(
alc->ctx);
138 if ((err = alcGetError(
alc->dev)) != ALC_NO_ERROR) {
139 logMsg(
"Error switching to my audio context (0x%x)",
149ctx_restore(alc_t *
alc, alc_t *sav)
156 if (
alc != NULL && (
alc->thr_local ||
alc->ctx == NULL))
160 if (
alc != NULL && sav->ctx ==
alc->ctx)
163 if (sav->ctx != NULL) {
164 alcMakeContextCurrent(sav->ctx);
166 if ((err = alcGetError(sav->dev)) != ALC_NO_ERROR) {
167 logMsg(
"Error restoring shared audio context (0x%x)",
177openal_list_output_devs(
size_t *num_p)
182 for (
const char *device = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
183 device != NULL && *device != 0; device += strlen(device) + 1) {
184 devs = realloc(devs, (num + 1) *
sizeof (*devs));
185 devs[num] = strdup(device);
194openal_init(
const char *devname, bool_t shared)
196 return (openal_init2(devname, shared, NULL, B_FALSE));
200openal_init2(
const char *devname, bool_t shared,
const int *attrs,
206 VERIFY(!shared || !thr_local);
211 memset(&sav, 0,
sizeof (sav));
212 if (!thr_local && !ctx_save(NULL, &sav))
216 alc->thr_local = thr_local;
218 if (!shared || sav.ctx == NULL) {
219 ALCdevice *dev = NULL;
220 ALCcontext *ctx = NULL;
223 dev = alcOpenDevice(devname);
225 logMsg(
"Cannot init audio system: device open failed.");
228 (void) ctx_restore(NULL, &sav);
231 ctx = alcCreateContext(dev, attrs);
232 if ((err = alcGetError(dev)) != ALC_NO_ERROR) {
233 logMsg(
"Cannot init audio system: create context "
234 "failed (0x%x)", err);
237 (void) ctx_restore(NULL, &sav);
242 if (!thr_local && shared && sav.ctx == NULL) {
245 alcMakeContextCurrent(sav.ctx);
247 if ((err = alcGetError(sav.dev)) != ALC_NO_ERROR) {
248 logMsg(
"Error installing shared audio context "
258 VERIFY3U(alcSetThreadContext(ctx), ==, ALC_TRUE);
262 if (!thr_local && !ctx_restore(
alc, &sav)) {
264 alcDestroyContext(
alc->ctx);
265 alcCloseDevice(
alc->dev);
275openal_fini(alc_t *
alc)
280 alcSetThreadContext(NULL);
281 if (
alc->dev != NULL) {
282 alcDestroyContext(
alc->ctx);
283 alcCloseDevice(
alc->dev);
289check_audio_fmt(
const wav_fmt_hdr_t *fmt,
const char *filename)
292 if (fmt->datafmt != 1 ||
293 (fmt->n_channels != 1 && fmt->n_channels != 2) ||
294 (fmt->bps != 8 && fmt->bps != 16)) {
295 logMsg(
"Error loading WAV file \"%s\": unsupported audio "
296 "format.", filename);
303wav_gen_al_bufs(
wav_t *wav,
const void *buf,
size_t bufsz,
const char *filename)
306 ALfloat zeroes[3] = { 0.0, 0.0, 0.0 };
309 if (!ctx_save(wav->alc, &sav))
312 alGenBuffers(1, &wav->albuf);
313 if ((err = alGetError()) != AL_NO_ERROR) {
314 logMsg(
"Error loading WAV file %s: alGenBuffers failed (0x%x).",
316 (void) ctx_restore(wav->alc, &sav);
319 if (wav->fmt.bps == 16) {
320 alBufferData(wav->albuf, wav->fmt.n_channels == 2 ?
321 AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, buf, bufsz,
324 alBufferData(wav->albuf, wav->fmt.n_channels == 2 ?
325 AL_FORMAT_STEREO8 : AL_FORMAT_MONO8, buf, bufsz,
329 if ((err = alGetError()) != AL_NO_ERROR) {
330 logMsg(
"Error loading WAV file %s: alBufferData failed (0x%x).",
332 (void) ctx_restore(wav->alc, &sav);
336 alGenSources(1, &wav->alsrc);
337 if ((err = alGetError()) != AL_NO_ERROR) {
338 logMsg(
"Error loading WAV file %s: alGenSources failed (0x%x).",
340 (void) ctx_restore(wav->alc, &sav);
343#define CHECK_ERROR(stmt) \
346 if ((err = alGetError()) != AL_NO_ERROR) { \
347 logMsg("Error loading WAV file %s, \"%s\" failed " \
348 "with error 0x%x", filename, #stmt, err); \
349 alDeleteSources(1, &wav->alsrc); \
350 VERIFY3S(alGetError(), ==, AL_NO_ERROR); \
352 (void) ctx_restore(wav->alc, &sav); \
356 CHECK_ERROR(alSourcei(wav->alsrc, AL_BUFFER, wav->albuf));
357 CHECK_ERROR(alSourcef(wav->alsrc, AL_PITCH, 1.0));
358 CHECK_ERROR(alSourcef(wav->alsrc, AL_GAIN, 1.0));
359 CHECK_ERROR(alSourcei(wav->alsrc, AL_LOOPING, 0));
360 CHECK_ERROR(alSourcefv(wav->alsrc, AL_POSITION, zeroes));
361 CHECK_ERROR(alSourcefv(wav->alsrc, AL_VELOCITY, zeroes));
363 (void) ctx_restore(wav->alc, &sav);
369wav_load_opus(
const char *filename, alc_t *
alc)
373 OggOpusFile *file = op_open_file(filename, &error);
374 const OpusHead *head;
375 unsigned sz = 0, cap = 0;
376 opus_int16 *pcm = NULL;
379 logMsg(
"Error reading OPUS file \"%s\": op_open_file error %d",
383 head = op_head(file, 0);
390 wav->fmt.datafmt = 1;
391 wav->fmt.n_channels = head->channel_count;
392 wav->fmt.srate = 48000;
394 wav->fmt.byte_rate = (wav->fmt.srate * wav->fmt.bps *
395 wav->fmt.n_channels) / 8;
397 if (!check_audio_fmt(&wav->fmt, filename))
407 if (sz + ((wav->fmt.srate * wav->fmt.n_channels) / 8) >= cap) {
409 pcm = realloc(pcm, cap *
sizeof (*pcm));
411 op_read_sz = op_read(file, &pcm[sz], cap - sz, 0);
413 sz += op_read_sz * wav->fmt.n_channels;
417 wav->duration = ((double)((sz - head->pre_skip) /
418 wav->fmt.n_channels)) / wav->fmt.srate;
421 wav_gen_al_bufs(wav, &pcm[head->pre_skip],
422 (sz - head->pre_skip) * sizeof (*pcm), filename);
437wav_load_mp3(
const char *filename, alc_t *
alc)
445 int bytes, n_bytes, audio_bytes;
447 if (contents == NULL) {
448 logMsg(
"Error reading MP3 file \"%s\": %s", filename,
459 bytes = mp3_decode(mp3, contents, len, pcm, &info);
461 logMsg(
"Error decoding MP3 file %s", filename);
467 wav->fmt.datafmt = 1;
468 wav->fmt.n_channels = info.channels;
469 wav->fmt.srate = info.sample_rate;
471 wav->fmt.byte_rate = (wav->fmt.srate * wav->fmt.bps *
472 wav->fmt.n_channels) / 8;
475 while ((n_bytes = mp3_decode(mp3, &contents[bytes], len - bytes,
476 &pcm[audio_bytes /
sizeof (*pcm)], &info)) > 0) {
478 audio_bytes += info.audio_bytes;
481 if (!check_audio_fmt(&wav->fmt, filename)) {
486 wav->duration = ((double)((bytes /
sizeof (*pcm)) /
487 wav->fmt.n_channels)) / wav->fmt.srate;
489 wav_gen_al_bufs(wav, pcm, bytes, filename);
506wav_load_wav(
const char *filename, alc_t *
alc)
512 uint8_t *filebuf = NULL;
516 if ((fp = fopen(filename,
"rb")) == NULL) {
517 logMsg(
"Error loading WAV file \"%s\": can't open file: %s",
518 filename, strerror(errno));
522 fseek(fp, 0, SEEK_END);
524 fseek(fp, 0, SEEK_SET);
533 if ((riff = riff_parse(WAVE_ID, filebuf,
filesz)) == NULL) {
534 logMsg(
"Error loading WAV file \"%s\": file doesn't appear "
535 "to be valid RIFF.", filename);
539 chunk = riff_find_chunk(riff, FMT_ID, 0);
540 if (chunk == NULL || chunk->datasz < sizeof (wav->fmt)) {
541 logMsg(
"Error loading WAV file \"%s\": file missing or "
542 "malformed `fmt ' chunk.", filename);
545 memcpy(&wav->fmt, chunk->data, sizeof (wav->fmt));
547 wav->fmt.datafmt = BSWAP16(wav->fmt.datafmt);
548 wav->fmt.n_channels = BSWAP16(wav->fmt.n_channels);
549 wav->fmt.srate = BSWAP32(wav->fmt.srate);
550 wav->fmt.byte_rate = BSWAP32(wav->fmt.byte_rate);
551 wav->fmt.bps = BSWAP16(wav->fmt.bps);
554 if (!check_audio_fmt(&wav->fmt, filename))
561 sample_sz = (wav->fmt.n_channels * wav->fmt.bps) / 8;
562 chunk = riff_find_chunk(riff, DATA_ID, 0);
563 if (chunk == NULL || (chunk->datasz & (sample_sz - 1)) != 0) {
564 logMsg(
"Error loading WAV file %s: `data' chunk missing or "
565 "contains bad number of samples.", filename);
569 wav->duration = ((double)(chunk->datasz / sample_sz)) / wav->fmt.srate;
572 if (riff->bswap && wav->fmt.bps == 16) {
573 for (uint16_t *s = (uint16_t *)chunk->data;
574 (uint8_t *)s < chunk->data + chunk->datasz;
579 if (!wav_gen_al_bufs(wav, chunk->data, chunk->datasz, filename))
582 riff_free_chunk(riff);
603wav_load(
const char *filename,
const char *descr_name, alc_t *
alc)
605 const char *dot = strrchr(filename,
'.');
610 if (dot != NULL && (strcmp(&dot[1],
"opus") == 0 ||
611 strcmp(&dot[1],
"OPUS") == 0)) {
612 wav = wav_load_opus(filename,
alc);
613 }
else if (dot != NULL && (strcmp(&dot[1],
"mp3") == 0 ||
614 strcmp(&dot[1],
"MP3") == 0)) {
615 wav = wav_load_mp3(filename,
alc);
617 wav = wav_load_wav(filename,
alc);
620 wav->name = strdup(descr_name);
623 wav->cone_outer = 360;
624 wav->cone_inner = 360;
626 wav->max_dist = 1e10;
627 wav->rolloff_fact = 1.0;
646 VERIFY(ctx_save(wav->alc, &sav));
648 if (wav->alsrc != 0) {
649 alSourceStop(wav->alsrc);
650 alDeleteSources(1, &wav->alsrc);
653 alDeleteBuffers(1, &wav->albuf);
654 VERIFY(ctx_restore(wav->alc, &sav));
660wav_set_offset(
wav_t *wav,
float offset_sec)
662 WAV_SET_PARAM(alSourcef, AL_SEC_OFFSET, offset_sec);
666wav_get_offset(
wav_t *wav)
669 WAV_OP_PARAM(alGetSourcef, AL_SEC_OFFSET, 0, &offset);
678wav_set_gain(
wav_t *wav,
float gain)
681 WAV_SET_PARAM(alSourcef, AL_GAIN, gain);
686wav_get_gain(
wav_t *wav)
697wav_set_loop(
wav_t *wav, bool_t loop)
699 WAV_SET_PARAM(alSourcei, AL_LOOPING, loop);
704wav_get_loop(
wav_t *wav)
712wav_set_pitch(
wav_t *wav,
float pitch)
714 WAV_SET_PARAM(alSourcef, AL_PITCH, pitch);
719wav_get_pitch(
wav_t *wav)
729 WAV_SET_PARAM(alSource3f, AL_POSITION, pos.x, pos.y, pos.z);
734wav_get_position(
wav_t *wav)
744 WAV_SET_PARAM(alSource3f, AL_VELOCITY, vel.x, vel.y, vel.z);
749wav_get_velocity(
wav_t *wav)
757wav_set_ref_dist(
wav_t *wav,
double d)
759 WAV_SET_PARAM(alSourcef, AL_REFERENCE_DISTANCE, d);
764wav_get_ref_dist(
wav_t *wav)
768 return (wav->ref_dist);
772wav_set_max_dist(
wav_t *wav,
double d)
774 WAV_SET_PARAM(alSourcef, AL_MAX_DISTANCE, d);
779wav_get_max_dist(
wav_t *wav)
783 return (wav->max_dist);
787wav_set_spatialize(
wav_t *wav, bool_t flag)
789 WAV_SET_PARAM(alSourcei, AL_SOURCE_SPATIALIZE_SOFT, flag);
793wav_set_rolloff_fact(
wav_t *wav,
double r)
795 WAV_SET_PARAM(alSourcef, AL_ROLLOFF_FACTOR, r);
796 wav->rolloff_fact = r;
800wav_get_rolloff_fact(
wav_t *wav)
804 return (wav->rolloff_fact);
810 if (wav != NULL && !
VECT3_EQ(wav->dir, dir)) {
811 WAV_SET_PARAM(alSource3f, AL_DIRECTION, dir.x, dir.y, dir.z);
817wav_set_cone_inner(
wav_t *wav,
double cone_inner)
819 if (wav != NULL && wav->cone_inner != cone_inner) {
820 WAV_SET_PARAM(alSourcef, AL_CONE_INNER_ANGLE, cone_inner);
821 wav->cone_inner = cone_inner;
826wav_set_cone_outer(
wav_t *wav,
double cone_outer)
828 if (wav != NULL && wav->cone_outer != cone_outer) {
829 WAV_SET_PARAM(alSourcef, AL_CONE_OUTER_ANGLE, cone_outer);
830 wav->cone_outer = cone_outer;
835wav_set_gain_outer(
wav_t *wav,
double gain_outer)
837 if (wav != NULL && wav->gain_outer != gain_outer) {
838 WAV_SET_PARAM(alSourcef, AL_CONE_OUTER_GAIN, gain_outer);
839 wav->gain_outer = gain_outer;
844wav_set_gain_outerhf(
wav_t *wav,
double gain_outerhf)
846 WAV_SET_PARAM(alSourcef, AL_CONE_OUTER_GAINHF, gain_outerhf);
850wav_set_stereo_angles(
wav_t *wav,
double a1,
double a2)
852 ALfloat a[] = {a1, a2};
853 WAV_SET_PARAM(alSourcefv, AL_EXT_STEREO_ANGLES, a);
857wav_set_air_absorption_fact(
wav_t *wav,
double fact)
859 WAV_SET_PARAM(alSourcei, AL_AIR_ABSORPTION_FACTOR, fact);
875 VERIFY(ctx_save(wav->alc, &sav));
877 alSourcePlay(wav->alsrc);
878 if ((err = alGetError()) != AL_NO_ERROR) {
879 logMsg(
"Can't play sound: alSourcePlay failed (0x%x).", err);
880 VERIFY(ctx_restore(wav->alc, &sav));
883 wav->play_start = microclock();
885 VERIFY(ctx_restore(wav->alc, &sav));
891wav_is_playing(
wav_t *wav)
893 return (wav != NULL && wav->play_start != 0 && (wav_get_loop(wav) ||
894 USEC2SEC(microclock() - wav->play_start) < wav->duration));
907 if (wav == NULL || wav->alsrc == 0)
910 VERIFY(ctx_save(wav->alc, &sav));
911 alSourceStop(wav->alsrc);
912 if ((err = alGetError()) != AL_NO_ERROR)
913 logMsg(
"Can't stop sound, alSourceStop failed (0x%x).", err);
914 VERIFY(ctx_restore(wav->alc, &sav));
919alc_set_dist_model(alc_t *
alc, ALenum model)
923 alDistanceModel(model);
930 LISTENER_SET_PARAM(alListener3f, AL_POSITION, pos.x, pos.y, pos.z);
934alc_listener_get_pos(alc_t *
alc)
937 LISTENER_OP_PARAM(alGetListener3f, AL_POSITION,
NULL_VECT3, &x, &y, &z);
938 return (
VECT3(x, y, z));
942alc_listener_set_orient(alc_t *
alc,
vect3_t orient)
947 orient.x, 0), orient.z, 2), orient.y, 1);
948 ALfloat v[6] = { at.x, at.y, at.z, up.x, up.y, up.z };
949 LISTENER_SET_PARAM(alListenerfv, AL_ORIENTATION, v);
953alc_listener_set_velocity(alc_t *
alc,
vect3_t vel)
955 LISTENER_SET_PARAM(alListener3f, AL_VELOCITY, vel.x, vel.y, vel.z);
959alc_global_save(alc_t *new_alc)
961 alc_t *old_alc = calloc(1,
sizeof (*old_alc));
963 VERIFY(ctx_save(new_alc, old_alc));
964 VERIFY3P(new_alc->ctx, !=, old_alc->ctx);
970alc_global_restore(alc_t *new_alc, alc_t *old_alc)
972 VERIFY3P(new_alc->ctx, !=, old_alc->ctx);
973 VERIFY(ctx_restore(new_alc, old_alc));
#define VERIFY3P(x, op, y)
#define VERIFY3S(x, op, y)
#define VERIFY3U(x, op, y)
vect3_t vect3_rot(vect3_t v, double angle, unsigned axis)
char * file2str_name(long *len_p, const char *filename)
ssize_t filesz(const char *filename)
static void * safe_calloc(size_t nmemb, size_t size)
static void * safe_malloc(size_t size)