naev 0.11.5
nlua_audio.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <lauxlib.h>
11#include "physfsrwops.h"
12
13#include "naev.h"
16#include "nlua_audio.h"
17
18#include "AL/efx.h"
19#include "AL/efx-presets.h"
20
21#include "conf.h"
22#include "array.h"
23#include "nlua_vec2.h"
24#include "nluadef.h"
25#include "nlua_file.h"
26#include "nstring.h"
27#include "sound.h"
28#include "nopenal.h"
29
33#define RG_PREAMP_DB 0.0
34
38typedef struct LuaAudioEfx_s {
39 char *name;
40 ALuint effect;
41 ALuint slot;
43
47static LuaAudioEfx_t *lua_efx = NULL;
48
49static int stream_thread( void *la_data );
50static int stream_loadBuffer( LuaAudio_t *la, ALuint buffer );
51static void rg_filter( float **pcm, long channels, long samples, void *filter_param );
52static int audio_genSource( ALuint *source );
53
54/* Audio methods. */
55static int audioL_gc( lua_State *L );
56static int audioL_eq( lua_State *L );
57static int audioL_new( lua_State *L );
58static int audioL_clone( lua_State *L );
59static int audioL_play( lua_State *L );
60static int audioL_pause( lua_State *L );
61static int audioL_isPaused( lua_State *L );
62static int audioL_stop( lua_State *L );
63static int audioL_isStopped( lua_State *L );
64static int audioL_rewind( lua_State *L );
65static int audioL_seek( lua_State *L );
66static int audioL_tell( lua_State *L );
67static int audioL_getDuration( lua_State *L );
68static int audioL_setVolume( lua_State *L );
69static int audioL_getVolume( lua_State *L );
70static int audioL_setRelative( lua_State *L );
71static int audioL_setPosition( lua_State *L );
72static int audioL_getPosition( lua_State *L );
73static int audioL_setVelocity( lua_State *L );
74static int audioL_getVelocity( lua_State *L );
75static int audioL_setLooping( lua_State *L );
76static int audioL_isLooping( lua_State *L );
77static int audioL_setPitch( lua_State *L );
78static int audioL_getPitch( lua_State *L );
79static int audioL_setAttenuationDistances( lua_State *L );
80static int audioL_getAttenuationDistances( lua_State *L );
81static int audioL_setRolloff( lua_State *L );
82static int audioL_getRolloff( lua_State *L );
83static int audioL_setEffect( lua_State *L );
84static int audioL_setGlobalEffect( lua_State *L );
85static int audioL_setGlobalAirAbsorption( lua_State *L );
86static int audioL_setGlobaDopplerFactor( lua_State *L );
87/* Deprecated stuff. */
88static int audioL_soundPlay( lua_State *L ); /* Obsolete API, to get rid of. */
89static const luaL_Reg audioL_methods[] = {
90 { "__gc", audioL_gc },
91 { "__eq", audioL_eq },
92 { "new", audioL_new },
93 { "clone", audioL_clone },
94 { "play", audioL_play },
95 { "pause", audioL_pause },
96 { "isPaused", audioL_isPaused },
97 { "stop", audioL_stop },
98 { "isStopped", audioL_isStopped },
99 { "rewind", audioL_rewind },
100 { "seek", audioL_seek },
101 { "tell", audioL_tell },
102 { "getDuration", audioL_getDuration },
103 { "setVolume", audioL_setVolume },
104 { "getVolume", audioL_getVolume },
105 { "setRelative", audioL_setRelative },
106 { "setPosition", audioL_setPosition },
107 { "getPosition", audioL_getPosition },
108 { "setVelocity", audioL_setVelocity },
109 { "getVelocity", audioL_getVelocity },
110 { "setLooping", audioL_setLooping },
111 { "isLooping", audioL_isLooping },
112 { "setPitch", audioL_setPitch },
113 { "getPitch", audioL_getPitch },
114 { "setAttenuationDistances", audioL_setAttenuationDistances },
115 { "getAttenuationDistances", audioL_getAttenuationDistances },
116 { "setRolloff", audioL_setRolloff },
117 { "getRolloff", audioL_getRolloff },
118 { "setEffect", audioL_setEffect },
119 { "setGlobalEffect", audioL_setGlobalEffect },
120 { "setGlobalAirAbsorption", audioL_setGlobalAirAbsorption },
121 { "setGlobalDopplerFactor", audioL_setGlobaDopplerFactor },
122 /* Deprecated. */
123 { "soundPlay", audioL_soundPlay }, /* Old API */
124 {0,0}
125};
127static int stream_thread( void *la_data )
128{
129 LuaAudio_t *la = (LuaAudio_t*) la_data;
130
131 while (1) {
132 ALint alstate;
133 ALuint removed;
134
135 soundLock();
136
137 /* Case finished. */
138 if (la->active < 0) {
139 la->th = NULL;
140 SDL_CondBroadcast( la->cond );
141 alSourceStop( la->source );
142 soundUnlock();
143 return 0;
144 }
145
146 alGetSourcei( la->source, AL_BUFFERS_PROCESSED, &alstate );
147 if (alstate > 0) {
148 int ret;
149 /* Refill active buffer */
150 alSourceUnqueueBuffers( la->source, 1, &removed );
151 ret = stream_loadBuffer( la, la->stream_buffers[ la->active ] );
152 if ((la->active < 0) || (ret < 0)) {
153 /* stream_loadBuffer unlocks the sound lock internally, which can
154 * lead to the thread being gc'd and having active = -1. We have to
155 * add a check here to not mess around with stuff. */
156 la->th = NULL;
157 SDL_CondBroadcast( la->cond );
158 alSourceStop( la->source );
159 soundUnlock();
160 return 0;
161 }
162 else {
163 alSourceQueueBuffers( la->source, 1, &la->stream_buffers[ la->active ] );
164 la->active = 1 - la->active;
165 }
166 }
167 al_checkErr(); /* XXX - good or bad idea to log from the thread? */
168 soundUnlock();
169
170 SDL_Delay(10);
171 }
172}
173
179static int stream_loadBuffer( LuaAudio_t *la, ALuint buffer )
180{
181 int ret;
182 size_t size;
183 char buf[ 32 * 1024 ];
184
185 soundUnlock();
186 ret = 0;
187 size = 0;
188 while (size < sizeof(buf)) { /* file up the entire data buffer */
189 int section, result;
190
191 SDL_mutexP( la->lock );
192 result = ov_read_filter(
193 &la->stream, /* stream */
194 &buf[size], /* data */
195 sizeof(buf) - size, /* amount to read */
196 (SDL_BYTEORDER == SDL_BIG_ENDIAN),
197 2, /* 16 bit */
198 1, /* signed */
199 &section, /* current bitstream */
200 rg_filter, /* filter function */
201 la ); /* filter parameter */
202 SDL_mutexV( la->lock );
203
204 /* End of file. */
205 if (result == 0) {
206 if (size == 0) {
207 return -2;
208 }
209 ret = 1;
210 break;
211 }
212 /* Hole error. */
213 else if (result == OV_HOLE) {
214 WARN(_("OGG: Vorbis hole detected in music!"));
215 return 0;
216 }
217 /* Bad link error. */
218 else if (result == OV_EBADLINK) {
219 WARN(_("OGG: Invalid stream section or corrupt link in music!"));
220 return -1;
221 }
222
223 size += result;
224 }
225 soundLock();
226
227 /* load the buffer up */
228 alBufferData( buffer, la->format, buf, size, la->info->rate );
229 al_checkErr();
230
231 return ret;
232}
233
242static void rg_filter( float **pcm, long channels, long samples, void *filter_param )
243{
244 const LuaAudio_t *param = filter_param;
245 float scale_factor = param->rg_scale_factor;
246 float max_scale = param->rg_max_scale;
247
248 /* Apply the gain, and any limiting necessary */
249 if (scale_factor > max_scale) {
250 for (int i=0; i < channels; i++)
251 for (int j=0; j < samples; j++) {
252 float cur_sample = pcm[i][j] * scale_factor;
253 /*
254 * This is essentially the scaled hard-limiting algorithm
255 * It looks like the soft-knee to me
256 * I haven't found a better limiting algorithm yet...
257 */
258 if (cur_sample < -0.5)
259 cur_sample = tanh((cur_sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
260 else if (cur_sample > 0.5)
261 cur_sample = tanh((cur_sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
262 pcm[i][j] = cur_sample;
263 }
264 }
265 else if (scale_factor > 0.0)
266 for (int i=0; i < channels; i++)
267 for (int j=0; j < samples; j++)
268 pcm[i][j] *= scale_factor;
269}
270
274static int audioL_isBool( lua_State *L, ALenum param )
275{
276 LuaAudio_t *la = luaL_checkaudio(L,1);
277 int b = 1;
278 if (!sound_disabled) {
279 soundLock();
280 alGetSourcei( la->source, param, &b );
281 al_checkErr();
282 soundUnlock();
283 }
284 lua_pushboolean(L,b);
285 return 1;
286}
287
291static int audioL_isState( lua_State *L, ALenum state )
292{
293 LuaAudio_t *la = luaL_checkaudio(L,1);
294 int s = AL_STOPPED;
295 if (!sound_disabled) {
296 soundLock();
297 alGetSourcei( la->source, AL_SOURCE_STATE, &s );
298 al_checkErr();
299 soundUnlock();
300 }
301 lua_pushboolean(L, s==state );
302 return 1;
303}
304
311int nlua_loadAudio( nlua_env env )
312{
313 nlua_register(env, AUDIO_METATABLE, audioL_methods, 1);
314 return 0;
315}
316
324LuaAudio_t* lua_toaudio( lua_State *L, int ind )
325{
326 return (LuaAudio_t*) lua_touserdata(L,ind);
327}
335LuaAudio_t* luaL_checkaudio( lua_State *L, int ind )
336{
337 if (lua_isaudio(L,ind))
338 return lua_toaudio(L,ind);
339 luaL_typerror(L, ind, AUDIO_METATABLE);
340 return NULL;
341}
349LuaAudio_t* lua_pushaudio( lua_State *L, LuaAudio_t audio )
350{
351 LuaAudio_t *la = (LuaAudio_t*) lua_newuserdata(L, sizeof(LuaAudio_t));
352 *la = audio;
353 luaL_getmetatable(L, AUDIO_METATABLE);
354 lua_setmetatable(L, -2);
355 return la;
356}
364int lua_isaudio( lua_State *L, int ind )
365{
366 int ret;
367
368 if (lua_getmetatable(L,ind)==0)
369 return 0;
370 lua_getfield(L, LUA_REGISTRYINDEX, AUDIO_METATABLE);
371
372 ret = 0;
373 if (lua_rawequal(L, -1, -2)) /* does it have the correct mt? */
374 ret = 1;
375
376 lua_pop(L, 2); /* remove both metatables */
377 return ret;
378}
379
380void audio_cleanup( LuaAudio_t *la )
381{
382 if ((la==NULL) || (la->nocleanup))
383 return;
384
385 switch (la->type) {
386 case LUA_AUDIO_NULL:
387 break;
388 case LUA_AUDIO_STATIC:
389 soundLock();
390 if (alIsSource( la->source )==AL_TRUE)
391 alDeleteSources( 1, &la->source );
392 /* Check if buffers need freeing. */
393 if (la->buf != NULL) {
394 la->buf->refcount--;
395 if (la->buf->refcount <= 0) {
396 alDeleteBuffers( 1, &la->buf->buffer );
397 free( la->buf );
398 }
399 }
400 al_checkErr();
401 soundUnlock();
402 break;
403
404 case LUA_AUDIO_STREAM:
405 soundLock();
406 if (la->th != NULL) {
407 la->active = -1;
408 if (SDL_CondWaitTimeout( la->cond, sound_lock, 3000 ) == SDL_MUTEX_TIMEDOUT)
409#if DEBUGGING
410 WARN(_("Timed out while waiting for audio thread of '%s' to finish!"), la->name);
411#else /* DEBUGGING */
412 WARN(_("Timed out while waiting for audio thread to finish!"));
413#endif /* DEBUGGING */
414 }
415 if (alIsSource( la->source )==AL_TRUE)
416 alDeleteSources( 1, &la->source );
417 if (alIsBuffer( la->stream_buffers[0] )==AL_TRUE)
418 alDeleteBuffers( 2, la->stream_buffers );
419 if (la->cond != NULL)
420 SDL_DestroyCond( la->cond );
421 if (la->lock != NULL)
422 SDL_DestroyMutex( la->lock );
423 ov_clear( &la->stream );
424 al_checkErr();
425 soundUnlock();
426 break;
427 }
428
429#if DEBUGGING
430 free(la->name);
431#endif /* DEBUGGING */
432}
433
445static int audioL_gc( lua_State *L )
446{
447 LuaAudio_t *la = luaL_checkaudio(L,1);
448 audio_cleanup( la );
449 return 0;
450}
451
460static int audioL_eq( lua_State *L )
461{
462 LuaAudio_t *a1, *a2;
463 a1 = luaL_checkaudio(L,1);
464 a2 = luaL_checkaudio(L,2);
465 lua_pushboolean( L, (memcmp( a1, a2, sizeof(LuaAudio_t) )==0) );
466 return 1;
467}
468
472static int audio_genSource( ALuint *source )
473{
474 ALenum err;
475 alGenSources( 1, source );
476 if (alIsSource(*source)==AL_TRUE)
477 return 0;
478 err = alGetError();
479 switch (err) {
480 case AL_NO_ERROR:
481 break;
482 case AL_OUT_OF_MEMORY:
483 /* Assume that we need to collect audio stuff. */
484 soundUnlock();
485 lua_gc( naevL, LUA_GCCOLLECT, 0 );
486 soundLock();
487 /* Try to create source again. */
488 alGenSources( 1, source );
489 if (alIsSource(*source)==AL_TRUE)
490 return 0;
491 al_checkErr();
492 break;
493
494 default:
495#if DEBUGGING
496 al_checkHandleError( err, __func__, __LINE__ );
497#endif /* DEBUGGING */
498 break;
499 }
500 return -1;
501}
502
511static int audioL_new( lua_State *L )
512{
513 LuaAudio_t la;
514 LuaFile_t *lf;
515 double master;
516 int stream;
517 const char *name;
518 SDL_RWops *rw;
519
520 /* First parameter. */
521 if (lua_isstring(L,1))
522 name = lua_tostring(L,1);
523 else if (lua_isfile(L,1)) {
524 lf = lua_tofile(L,1);
525 name = lf->path;
526 }
527 else
528 NLUA_INVALID_PARAMETER(L,1);
529
530 /* Second parameter. */
531 if (lua_isnoneornil(L,2)) {
532 stream = 0;
533 }
534 else {
535 const char *type = luaL_optstring(L,2,"static");
536 if (strcmp(type,"static")==0)
537 stream = 0;
538 else if (strcmp(type,"stream")==0)
539 stream = 1;
540 else
541 NLUA_INVALID_PARAMETER(L,2);
542 }
543
544 memset( &la, 0, sizeof(LuaAudio_t) );
545 if (sound_disabled) {
546 la.nocleanup = 1; /* Not initialized so no need to clean up. */
547 lua_pushaudio(L, la);
548 return 1;
549 }
550 rw = PHYSFSRWOPS_openRead( name );
551 if (rw==NULL)
552 return NLUA_ERROR(L,"Unable to open '%s'", name );
553#if DEBUGGING
554 la.name = strdup( name );
555#endif /* DEBUGGING */
556
557 soundLock();
558 la.ok = audio_genSource( &la.source );
559 if (la.ok) {
560 SDL_RWclose( rw ); /* Clean up. */
561 la.nocleanup = 1; /* Not initialized so no need to clean up. */
562 lua_pushaudio(L, la);
563 return 1;
564 }
565
566 /* Deal with stream. */
567 if (!stream) {
568 la.type = LUA_AUDIO_STATIC;
569 la.buf = malloc( sizeof(LuaBuffer_t) );
570 la.buf->refcount = 1;
571 sound_al_buffer( &la.buf->buffer, rw, name );
572
573 /* Attach buffer. */
574 alSourcei( la.source, AL_BUFFER, la.buf->buffer );
575
576 /* Clean up. */
577 SDL_RWclose( rw );
578 }
579 else {
580 vorbis_comment *vc;
581 ALfloat track_gain_db, track_peak;
582 char *tag;
583
584 la.type = LUA_AUDIO_STREAM;
585 /* ov_clear will close rw for us. */
586 if (ov_open_callbacks( rw, &la.stream, NULL, 0, sound_al_ovcall ) < 0) {
587 SDL_RWclose( rw );
588 return NLUA_ERROR(L,_("Audio '%s' does not appear to be a Vorbis bitstream."), name );
589 }
590 la.info = ov_info( &la.stream, -1 );
591
592 /* Replaygain information. */
593 vc = ov_comment( &la.stream, -1 );
594 track_gain_db = 0.;
595 track_peak = 1.;
596 if ((tag = vorbis_comment_query(vc, "replaygain_track_gain", 0)))
597 track_gain_db = atof(tag);
598 if ((tag = vorbis_comment_query(vc, "replaygain_track_peak", 0)))
599 track_peak = atof(tag);
600 la.rg_scale_factor = pow(10.0, (track_gain_db + RG_PREAMP_DB)/20.0);
601 la.rg_max_scale = 1.0 / track_peak;
602
603 /* Set the format */
604 if (la.info->channels == 1)
605 la.format = AL_FORMAT_MONO16;
606 else
607 la.format = AL_FORMAT_STEREO16;
608
609 la.active = 0;
610 la.lock = SDL_CreateMutex();
611 la.cond = SDL_CreateCond();
612 alGenBuffers( 2, la.stream_buffers );
613 /* Buffers get queued later. */
614 }
615
616 /* Defaults. */
617 la.volume = 1.;
618 master = sound_getVolumeLog();
619 alSourcef( la.source, AL_GAIN, master );
620 /* The behaviour of sources depends on whether or not they are mono or
621 * stereo. In the case they are stereo, no position stuff is actually
622 * done. However, if they are mono, they are played with absolute
623 * position and the sound heard depends on the listener. We can disable
624 * this by setting AL_SOURCE_RELATIVE which puts the listener always at
625 * the origin, and then setting the source at the same origin. It should
626 * be noted that depending on the sound model this can be bad if it is
627 * not bounded. */
628 alSourcei( la.source, AL_SOURCE_RELATIVE, AL_TRUE );
629 alSource3f( la.source, AL_POSITION, 0., 0., 0. );
630 al_checkErr();
631 soundUnlock();
632
633 lua_pushaudio(L, la);
634 return 1;
635}
636
637void audio_clone( LuaAudio_t *la, const LuaAudio_t *source )
638{
639 double master;
640
641 memset( la, 0, sizeof(LuaAudio_t) );
642 if (sound_disabled || source->ok) {
643 la->nocleanup = 1;
644 return;
645 }
646
647 soundLock();
648 la->ok = audio_genSource( &la->source );
649 if (la->ok) {
650 la->nocleanup = 1;
651 return;
652 }
653
654 switch (source->type) {
655 case LUA_AUDIO_STATIC:
656 /* Attach source buffer. */
657 la->buf = source->buf;
658 la->buf->refcount++;
659
660 /* Attach buffer. */
661 alSourcei( la->source, AL_BUFFER, la->buf->buffer );
662 break;
663
664 case LUA_AUDIO_STREAM:
665 WARN(_("Unimplemented"));
666 break;
667
668 case LUA_AUDIO_NULL:
669 break;
670 }
671 la->type = source->type;
672
673 /* TODO this should probably set the same parameters as the original source
674 * being cloned to be truly compatible with Love2D. */
675 /* Defaults. */
676 master = sound_getVolumeLog();
677 alSourcef( la->source, AL_GAIN, master * source->volume );
678 la->volume = source->volume;
679 /* See note in audioL_new */
680 alSourcei( la->source, AL_SOURCE_RELATIVE, AL_TRUE );
681 alSource3f( la->source, AL_POSITION, 0., 0., 0. );
682 al_checkErr();
683 soundUnlock();
684}
685
693static int audioL_clone( lua_State *L )
694{
695 LuaAudio_t la;
696 const LuaAudio_t *source = luaL_checkaudio(L,1);
697 audio_clone( &la, source );
698 lua_pushaudio(L, la);
699 return 1;
700}
701
709static int audioL_play( lua_State *L )
710{
711 LuaAudio_t *la = luaL_checkaudio(L,1);
712 if (sound_disabled || la->ok)
713 return 0;
714
715 if ((la->type == LUA_AUDIO_STREAM) && (la->th == NULL)) {
716 int ret = 0;
717 ALint alstate;
718 soundLock();
719 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
720 while (alstate < 2) {
721 ret = stream_loadBuffer( la, la->stream_buffers[ la->active ] );
722 if (ret < 0)
723 break;
724 alSourceQueueBuffers( la->source, 1, &la->stream_buffers[ la->active ] );
725 la->active = 1-la->active;
726 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
727 }
728 if (ret == 0)
729 la->th = SDL_CreateThread( stream_thread, "stream_thread", la );
730 }
731 else
732 soundLock();
733 alSourcePlay( la->source );
734 al_checkErr();
735 soundUnlock();
736
737 lua_pushboolean(L,1);
738 return 1;
739}
740
748static int audioL_pause( lua_State *L )
749{
750 LuaAudio_t *la = luaL_checkaudio(L,1);
751 if (sound_disabled || la->ok)
752 return 0;
753 soundLock();
754 alSourcePause( la->source );
755 al_checkErr();
756 soundUnlock();
757 return 0;
758}
759
767static int audioL_isPaused( lua_State *L )
768{
769 return audioL_isState( L, AL_PAUSED );
770}
771
778static int audioL_stop( lua_State *L )
779{
780 ALint alstate;
781 ALuint removed[2];
782 LuaAudio_t *la = luaL_checkaudio(L,1);
783 if (sound_disabled || la->ok)
784 return 0;
785
786 soundLock();
787 switch (la->type) {
788 case LUA_AUDIO_NULL:
789 break;
790 case LUA_AUDIO_STATIC:
791 alSourceStop( la->source );
792 break;
793
794 case LUA_AUDIO_STREAM:
795 /* Kill the thread first. */
796 if (la->th != NULL) {
797 la->active = -1;
798 if (SDL_CondWaitTimeout( la->cond, sound_lock, 3000 ) == SDL_MUTEX_TIMEDOUT)
799#if DEBUGGING
800 WARN(_("Timed out while waiting for audio thread of '%s' to finish!"), la->name);
801#else /* DEBUGGING */
802 WARN(_("Timed out while waiting for audio thread to finish!"));
803#endif /* DEBUGGING */
804 }
805 la->th = NULL;
806
807 /* Stopping a source will make all buffers become processed. */
808 alSourceStop( la->source );
809
810 /* Unqueue the buffers. */
811 alGetSourcei( la->source, AL_BUFFERS_PROCESSED, &alstate );
812 alSourceUnqueueBuffers( la->source, alstate, removed );
813
814 /* Seek the stream to the beginning. */
815 SDL_mutexP( la->lock );
816 ov_pcm_seek( &la->stream, 0 );
817 SDL_mutexV( la->lock );
818 break;
819 }
820 al_checkErr();
821 soundUnlock();
822 return 0;
823}
824
832static int audioL_isStopped( lua_State *L )
833{
834 return audioL_isState( L, AL_STOPPED );
835}
836
843static int audioL_rewind( lua_State *L )
844{
845 LuaAudio_t *la = luaL_checkaudio(L,1);
846 if (sound_disabled || la->ok)
847 return 0;
848
849 switch (la->source) {
850 case LUA_AUDIO_STATIC:
851 soundLock();
852 alSourceRewind( la->source );
853 al_checkErr();
854 soundUnlock();
855 break;
856 case LUA_AUDIO_STREAM:
857 SDL_mutexP( la->lock );
858 ov_raw_seek( &la->stream, 0 );
859 SDL_mutexV( la->lock );
860 break;
861 case LUA_AUDIO_NULL:
862 break;
863 }
864 return 0;
865}
866
875static int audioL_seek( lua_State *L )
876{
877 LuaAudio_t *la = luaL_checkaudio(L,1);
878 double offset = luaL_checknumber(L,2);
879 const char *unit = luaL_optstring(L,3,"seconds");
880 int seconds = 1;
881
882 if (strcmp(unit,"samples")==0)
883 seconds = 0;
884 else if (strcmp(unit,"seconds")!=0)
885 return NLUA_ERROR(L, _("Unknown seek source '%s'! Should be either 'seconds' or 'samples'!"), unit );
886
887 if (sound_disabled || la->ok)
888 return 0;
889
890 switch (la->type) {
891 case LUA_AUDIO_STATIC:
892 soundLock();
893 if (seconds)
894 alSourcef( la->source, AL_SEC_OFFSET, offset );
895 else
896 alSourcef( la->source, AL_SAMPLE_OFFSET, offset );
897 al_checkErr();
898 soundUnlock();
899 break;
900
901 case LUA_AUDIO_STREAM:
902 SDL_mutexP( la->lock );
903 if (seconds)
904 ov_time_seek( &la->stream, offset );
905 else
906 ov_pcm_seek( &la->stream, offset );
907 SDL_mutexV( la->lock );
908 /* TODO force a reset of the buffers. */
909 break;
910
911 case LUA_AUDIO_NULL:
912 break;
913 }
914 return 0;
915}
916
925static int audioL_tell( lua_State *L )
926{
927 LuaAudio_t *la = luaL_checkaudio(L,1);
928 const char *unit = luaL_optstring(L,2,"seconds");
929 double offset = -1.;
930 float aloffset;
931 int seconds = 1;
932
933 if (strcmp(unit,"samples")==0)
934 seconds = 0;
935 else if (strcmp(unit,"seconds")!=0)
936 return NLUA_ERROR(L, _("Unknown seek source '%s'! Should be either 'seconds' or 'samples'!"), unit );
937
938 if (sound_disabled || la->ok) {
939 lua_pushnumber(L, -1.);
940 return 1;
941 }
942
943 switch (la->type) {
944 case LUA_AUDIO_STATIC:
945 soundLock();
946 if (seconds)
947 alGetSourcef( la->source, AL_SEC_OFFSET, &aloffset );
948 else
949 alGetSourcef( la->source, AL_SAMPLE_OFFSET, &aloffset );
950 offset = aloffset;
951 al_checkErr();
952 soundUnlock();
953 break;
954
955 case LUA_AUDIO_STREAM:
956 SDL_mutexP( la->lock );
957 if (seconds)
958 offset = ov_time_tell( &la->stream );
959 else
960 offset = ov_pcm_tell( &la->stream );
961 SDL_mutexV( la->lock );
962 break;
963
964 case LUA_AUDIO_NULL:
965 break;
966 }
967
968 lua_pushnumber(L, offset);
969 return 1;
970}
971
980static int audioL_getDuration( lua_State *L )
981{
982 LuaAudio_t *la = luaL_checkaudio(L,1);
983 const char *unit = luaL_optstring(L,2,"seconds");
984 float duration = -1.;
985 int seconds = 1;
986 ALint bytes, channels, bits, samples;
987 ALuint buffer;
988
989 if (strcmp(unit,"samples")==0)
990 seconds = 0;
991 else if (strcmp(unit,"seconds")!=0)
992 return NLUA_ERROR(L, _("Unknown duration source '%s'! Should be either 'seconds' or 'samples'!"), unit );
993
994 if (sound_disabled || la->ok) {
995 lua_pushnumber(L, -1.);
996 return 1;
997 }
998
999 switch (la->type) {
1000 case LUA_AUDIO_STATIC:
1001 soundLock();
1002 buffer = la->buf->buffer;
1003 alGetBufferi( buffer, AL_SIZE, &bytes );
1004 alGetBufferi( buffer, AL_CHANNELS, &channels );
1005 alGetBufferi( buffer, AL_BITS, &bits );
1006
1007 samples = bytes * 8 / (channels * bits);
1008
1009 if (seconds) {
1010 ALint freq;
1011 alGetBufferi( buffer, AL_FREQUENCY, &freq );
1012 duration = (float) samples / (float) freq;
1013 }
1014 else
1015 duration = samples;
1016 al_checkErr();
1017 soundUnlock();
1018 break;
1019
1020 case LUA_AUDIO_STREAM:
1021 SDL_mutexP( la->lock );
1022 if (seconds)
1023 duration = ov_time_total( &la->stream, -1 );
1024 else
1025 duration = ov_pcm_total( &la->stream, -1 );
1026 SDL_mutexV( la->lock );
1027 break;
1028
1029 case LUA_AUDIO_NULL:
1030 break;
1031 }
1032
1033 lua_pushnumber(L, duration);
1034 return 1;
1035}
1036
1045static int audioL_setVolume( lua_State *L )
1046{
1047 LuaAudio_t *la = luaL_checkaudio(L,1);
1048 double volume = CLAMP( 0.0, 1.0, luaL_checknumber(L,2) );
1049 int ignorevol = lua_toboolean(L,3);
1050 if (sound_disabled || la->ok)
1051 return 0;
1052
1053 soundLock();
1054 if (ignorevol)
1055 alSourcef( la->source, AL_GAIN, volume );
1056 else {
1057 double master = sound_getVolumeLog();
1058 alSourcef( la->source, AL_GAIN, master * volume );
1059 }
1060 al_checkErr();
1061 soundUnlock();
1062 la->volume = volume;
1063 return 0;
1064}
1065
1073static int audioL_getVolume( lua_State *L )
1074{
1075 double volume;
1076 if (sound_disabled)
1077 volume = 0.;
1078 else if (lua_gettop(L) > 0)
1079 volume = luaL_checkaudio(L,1)->volume;
1080 else
1081 volume = sound_getVolume();
1082 lua_pushnumber(L, volume);
1083 return 1;
1084}
1085
1092static int audioL_setRelative( lua_State *L )
1093{
1094 LuaAudio_t *la = luaL_checkaudio(L,1);
1095 if (sound_disabled || la->ok)
1096 return 0;
1097
1098 soundLock();
1099 alSourcei( la->source, AL_SOURCE_RELATIVE, lua_toboolean(L,2) );
1100 al_checkErr();
1101 soundUnlock();
1102 return 0;
1103}
1104
1114static int audioL_setPosition( lua_State *L )
1115{
1116 ALfloat pos[3];
1117 LuaAudio_t *la = luaL_checkaudio(L,1);
1118 if (sound_disabled || la->ok)
1119 return 0;
1120
1121 pos[0] = luaL_optnumber(L,2,0.);
1122 pos[1] = luaL_optnumber(L,3,0.);
1123 pos[2] = luaL_optnumber(L,4,0.);
1124
1125 soundLock();
1126 alSourcefv( la->source, AL_POSITION, pos );
1127 al_checkErr();
1128 soundUnlock();
1129 return 0;
1130}
1131
1141static int audioL_getPosition( lua_State *L )
1142{
1143 ALfloat pos[3];
1144 LuaAudio_t *la = luaL_checkaudio(L,1);
1145 if (sound_disabled || la->ok) {
1146 lua_pushnumber(L,0.);
1147 lua_pushnumber(L,0.);
1148 lua_pushnumber(L,0.);
1149 return 0;
1150 }
1151
1152 soundLock();
1153 alGetSource3f( la->source, AL_POSITION, &pos[0], &pos[1], &pos[2] );
1154 al_checkErr();
1155 soundUnlock();
1156
1157 lua_pushnumber(L,pos[0]);
1158 lua_pushnumber(L,pos[1]);
1159 lua_pushnumber(L,pos[2]);
1160 return 3;
1161}
1162
1172static int audioL_setVelocity( lua_State *L )
1173{
1174 ALfloat vel[3];
1175 LuaAudio_t *la = luaL_checkaudio(L,1);
1176 if (sound_disabled || la->ok)
1177 return 0;
1178
1179 vel[0] = luaL_optnumber(L,2,0.);
1180 vel[1] = luaL_optnumber(L,3,0.);
1181 vel[2] = luaL_optnumber(L,4,0.);
1182
1183 soundLock();
1184 alSourcefv( la->source, AL_VELOCITY, vel );
1185 al_checkErr();
1186 soundUnlock();
1187 return 0;
1188}
1189
1199static int audioL_getVelocity( lua_State *L )
1200{
1201 ALfloat vel[3];
1202 LuaAudio_t *la = luaL_checkaudio(L,1);
1203 if (sound_disabled || la->ok) {
1204 lua_pushnumber(L,0.);
1205 lua_pushnumber(L,0.);
1206 lua_pushnumber(L,0.);
1207 return 0;
1208 }
1209
1210 soundLock();
1211 alGetSource3f( la->source, AL_VELOCITY, &vel[0], &vel[1], &vel[2] );
1212 al_checkErr();
1213 soundUnlock();
1214
1215 lua_pushnumber(L,vel[0]);
1216 lua_pushnumber(L,vel[1]);
1217 lua_pushnumber(L,vel[2]);
1218 return 3;
1219}
1220
1228static int audioL_setLooping( lua_State *L )
1229{
1230 LuaAudio_t *la = luaL_checkaudio(L,1);
1231 int b = lua_toboolean(L,2);
1232 if (sound_disabled || la->ok)
1233 return 0;
1234 soundLock();
1235 alSourcei( la->source, AL_LOOPING, b );
1236 al_checkErr();
1237 soundUnlock();
1238 return 0;
1239}
1240
1248static int audioL_isLooping( lua_State *L )
1249{
1250 return audioL_isBool( L, AL_LOOPING );
1251}
1252
1260static int audioL_setPitch( lua_State *L )
1261{
1262 LuaAudio_t *la = luaL_checkaudio(L,1);
1263 double pitch = luaL_checknumber(L,2);
1264 if (sound_disabled || la->ok)
1265 return 0;
1266 soundLock();
1267 alSourcef( la->source, AL_PITCH, pitch );
1268 al_checkErr();
1269 soundUnlock();
1270 return 0;
1271}
1272
1280static int audioL_getPitch( lua_State *L )
1281{
1282 LuaAudio_t *la = luaL_checkaudio(L,1);
1283 float p = 1.0;
1284 if (!sound_disabled && !la->ok) {
1285 soundLock();
1286 alGetSourcef( la->source, AL_PITCH, &p );
1287 al_checkErr();
1288 soundUnlock();
1289 }
1290 lua_pushnumber(L,p);
1291 return 1;
1292}
1293
1308static int audioL_soundPlay( lua_State *L )
1309{
1310 const char *name;
1311 vec2 *pos, *vel, vel0;
1312 int dopos;
1313
1314 /* Flag wether to use sound_playPos or sound_play. */
1315 dopos = 0;
1316
1317 /* Handle parameters. */
1318 name = luaL_checkstring(L,1);
1319 if (lua_gettop(L) > 1) {
1320 dopos = 1;
1321 pos = luaL_checkvector(L,2);
1322 if (lua_gettop(L) > 2) {
1323 vel = luaL_checkvector(L,3);
1324 }
1325 else {
1326 vectnull( &vel0 );
1327 vel = &vel0;
1328 }
1329 }
1330
1331 if (dopos)
1332 sound_playPos( sound_get(name), pos->x, pos->y, vel->x, vel->y );
1333 else
1334 sound_play( sound_get(name) );
1335
1336 return 0;
1337}
1338
1346static int audioL_setAttenuationDistances( lua_State *L )
1347{
1348 LuaAudio_t *la = luaL_checkaudio(L,1);
1349 double ref = luaL_checknumber(L,2);
1350 double max = luaL_checknumber(L,3);
1351 if (sound_disabled || la->ok)
1352 return 0;
1353 soundLock();
1354 alSourcef( la->source, AL_REFERENCE_DISTANCE, ref );
1355 alSourcef( la->source, AL_MAX_DISTANCE, max );
1356 al_checkErr();
1357 soundUnlock();
1358 return 0;
1359}
1360
1368static int audioL_getAttenuationDistances( lua_State *L )
1369{
1370 ALfloat ref, max;
1371 LuaAudio_t *la = luaL_checkaudio(L,1);
1372 if (sound_disabled || la->ok) {
1373 lua_pushnumber(L,0.);
1374 lua_pushnumber(L,0.);
1375 return 2;
1376 }
1377 soundLock();
1378 alGetSourcef( la->source, AL_REFERENCE_DISTANCE, &ref );
1379 alGetSourcef( la->source, AL_MAX_DISTANCE, &max );
1380 al_checkErr();
1381 soundUnlock();
1382 lua_pushnumber( L, ref );
1383 lua_pushnumber( L, max );
1384 return 2;
1385}
1386
1393static int audioL_setRolloff( lua_State *L )
1394{
1395 LuaAudio_t *la = luaL_checkaudio(L,1);
1396 double rolloff = luaL_checknumber(L,2);
1397 if (sound_disabled || la->ok)
1398 return 0;
1399 soundLock();
1400 alSourcef( la->source, AL_ROLLOFF_FACTOR, rolloff );
1401 al_checkErr();
1402 soundUnlock();
1403 return 0;
1404}
1405
1412static int audioL_getRolloff( lua_State *L )
1413{
1414 ALfloat rolloff;
1415 LuaAudio_t *la = luaL_checkaudio(L,1);
1416 if (sound_disabled || la->ok) {
1417 lua_pushnumber(L,0.);
1418 return 1;
1419 }
1420 soundLock();
1421 alGetSourcef( la->source, AL_ROLLOFF_FACTOR, &rolloff);
1422 al_checkErr();
1423 soundUnlock();
1424 lua_pushnumber( L, rolloff );
1425 return 1;
1426}
1427
1428static void efx_setnum( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1429 lua_getfield(L,pos,name);
1430 if (!lua_isnil(L,-1))
1431 nalEffectf( effect, param, luaL_checknumber(L,-1) );
1432 lua_pop(L,1);
1433}
1434static void efx_setint( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1435 lua_getfield(L,pos,name);
1436 if (!lua_isnil(L,-1))
1437 nalEffecti( effect, param, luaL_checkinteger(L,-1) );
1438 lua_pop(L,1);
1439}
1440static void efx_setbool( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1441 lua_getfield(L,pos,name);
1442 if (!lua_isnil(L,-1))
1443 nalEffecti( effect, param, lua_toboolean(L,-1) ? AL_TRUE : AL_FALSE );
1444 lua_pop(L,1);
1445}
1446static int audioL_setEffectGlobal( lua_State *L )
1447{
1448 const char *name = luaL_checkstring(L,1);
1449 ALuint effect, slot;
1450 const char *type;
1451 double volume;
1452 LuaAudioEfx_t *lae;
1453 const int p = 2;
1454
1455 /* Get the type. */
1456 lua_getfield(L,p,"type");
1457 type = luaL_checkstring(L,-1);
1458 lua_pop(L,1);
1459
1460 /* Get the volume. */
1461 lua_getfield(L,p,"volume");
1462 if (lua_isnil(L,-1))
1463 volume = -1.;
1464 else
1465 volume = luaL_checknumber(L,-1);
1466 lua_pop(L,1);
1467
1468 soundLock();
1469
1470 /* Find or add to array as necessary. */
1471 if (lua_efx == NULL)
1473 lae = NULL;
1474 for (int i=0; i<array_size(lua_efx); i++) {
1475 if (strcmp(name,lua_efx[i].name)==0) {
1476 lae = &lua_efx[i];
1477 break;
1478 }
1479 }
1480 if (lae == NULL) {
1481 lae = &array_grow( &lua_efx );
1482 nalGenEffects(1, &effect);
1483 nalGenAuxiliaryEffectSlots( 1, &slot );
1484 lae->name = strdup( name );
1485 lae->effect = effect;
1486 lae->slot = slot;
1487 }
1488 else {
1489 effect = lae->effect;
1490 slot = lae->slot;
1491 }
1492
1493 /* Handle types. */
1494 if (strcmp(type,"reverb")==0) {
1495 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
1496
1497 efx_setnum( L, p, effect, "density", AL_REVERB_DENSITY ); /* 0.0 to 1.0 (1.0) */
1498 efx_setnum( L, p, effect, "diffusion", AL_REVERB_DIFFUSION ); /* 0.0 to 1.0 (1.0) */
1499 efx_setnum( L, p, effect, "gain", AL_REVERB_GAIN ); /* 0.0 to 1.0 (0.32) */
1500 efx_setnum( L, p, effect, "highgain", AL_REVERB_GAINHF ); /* 0.0 to 1.0 (0.89) */
1501 efx_setnum( L, p, effect, "decaytime", AL_REVERB_DECAY_TIME ); /* 0.1 to 20.0 (1.49) */
1502 efx_setnum( L, p, effect, "decayhighratio", AL_REVERB_DECAY_HFRATIO ); /* 0.1 to 2.0 (0.83) */
1503 efx_setnum( L, p, effect, "earlygain", AL_REVERB_REFLECTIONS_GAIN ); /* 0.0 to 3.16 (0.05) */
1504 efx_setnum( L, p, effect, "earlydelay", AL_REVERB_REFLECTIONS_DELAY ); /* 0.0 to 0.3 (0.007) */
1505 efx_setnum( L, p, effect, "lategain", AL_REVERB_LATE_REVERB_GAIN ); /* 0.0 to 10.0 (1.26) */
1506 efx_setnum( L, p, effect, "latedelay", AL_REVERB_LATE_REVERB_DELAY ); /* 0.0 to 0.1 (0.011) */
1507 efx_setnum( L, p, effect, "roomrolloff", AL_REVERB_ROOM_ROLLOFF_FACTOR ); /* 0.0 to 10.0 (0.0) */
1508 efx_setnum( L, p, effect, "airabsorption", AL_REVERB_AIR_ABSORPTION_GAINHF ); /* 0.892 to 1.0 (0.994) */
1509 efx_setbool( L, p, effect, "highlimit", AL_REVERB_DECAY_HFLIMIT ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1510 }
1511 else if (strcmp(type,"distortion")==0) {
1512 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION);
1513
1514 efx_setnum( L, p, effect, "gain", AL_DISTORTION_GAIN ); /* 0.01 to 1.0 (0.2) */
1515 efx_setnum( L, p, effect, "edge", AL_DISTORTION_EDGE ); /* 0.0 to 1.0 (0.05) */
1516 efx_setnum( L, p, effect, "lowcut", AL_DISTORTION_LOWPASS_CUTOFF ); /* 80.0 to 24000.0 (8000.0) */
1517 efx_setnum( L, p, effect, "center", AL_DISTORTION_EQCENTER ); /* 80.0 to 24000.0 (3600.0) */
1518 efx_setnum( L, p, effect, "bandwidth", AL_DISTORTION_EQBANDWIDTH ); /* 80.0 to 24000.0 (3600.0) */
1519 }
1520 else if (strcmp(type,"chorus")==0) {
1521 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS);
1522
1523 efx_setint( L, p, effect, "waveform", AL_CHORUS_WAVEFORM ); /* 0=sin, 1=triangle (1) */
1524 efx_setint( L, p, effect, "phase", AL_CHORUS_PHASE ); /* -180 to 180 (90) */
1525 efx_setnum( L, p, effect, "rate", AL_CHORUS_RATE ); /* 0.0 to 10.0 (1.1) */
1526 efx_setnum( L, p, effect, "depth", AL_CHORUS_DEPTH ); /* 0.0 to 1.0 (0.1) */
1527 efx_setnum( L, p, effect, "feedback", AL_CHORUS_FEEDBACK ); /* -1.0 to 1.0 (0.25) */
1528 efx_setnum( L, p, effect, "delay", AL_CHORUS_DELAY ); /* 0.0 to 0.016 (0.016) */
1529 }
1530 else if (strcmp(type,"compressor")==0) {
1531 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR);
1532
1533 efx_setbool( L, p, effect, "enable", AL_COMPRESSOR_ONOFF ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1534 }
1535 else if (strcmp(type,"echo")==0) {
1536 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO);
1537
1538 efx_setnum( L, p, effect, "delay", AL_ECHO_DELAY ); /* 0.0 to 0.207 (0.1) */
1539 efx_setnum( L, p, effect, "tapdelay", AL_ECHO_LRDELAY ); /* 0.0 to 0.404 (0.1) */
1540 efx_setnum( L, p, effect, "damping", AL_ECHO_DAMPING ); /* 0.0 to 0.99 (0.5) */
1541 efx_setnum( L, p, effect, "feedback", AL_ECHO_FEEDBACK ); /* 0.0 to 1.0 (0.5) */
1542 efx_setnum( L, p, effect, "spread", AL_ECHO_SPREAD ); /* -1.0 to 1.0 (-1.0) */
1543 }
1544 else if (strcmp(type,"ringmodulator")==0) {
1545 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR);
1546
1547 efx_setnum( L, p, effect, "frequency", AL_RING_MODULATOR_FREQUENCY ); /* 0.0 to 8000.0 (440.0) */
1548 efx_setnum( L, p, effect, "highcut", AL_RING_MODULATOR_HIGHPASS_CUTOFF ); /* 0.0 to 24000.0 (800.0) */
1549 efx_setint( L, p, effect, "waveform", AL_RING_MODULATOR_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square) (0 (sin)) */
1550 }
1551 else if (strcmp(type,"equalizer")==0) {
1552 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER);
1553
1554 efx_setnum( L, p, effect, "lowgain", AL_EQUALIZER_LOW_GAIN ); /* 0.126 to 7.943 (1.0) */
1555 efx_setnum( L, p, effect, "lowcut", AL_EQUALIZER_LOW_CUTOFF ); /* 50.0 to 800.0 (200.0) */
1556 efx_setnum( L, p, effect, "lowmidgain", AL_EQUALIZER_MID1_GAIN ); /* 0.126 to 7.943 (1.0) */
1557 efx_setnum( L, p, effect, "lowmidfrequency", AL_EQUALIZER_MID1_CENTER ); /* 200.0 to 3000.0 (500.0) */
1558 efx_setnum( L, p, effect, "lowmidbandwidth", AL_EQUALIZER_MID1_WIDTH ); /* 0.01 to 1.0 (1.0) */
1559 efx_setnum( L, p, effect, "highmidgain", AL_EQUALIZER_MID2_GAIN ); /* 0.126 to 7.943 (1.0) */
1560 efx_setnum( L, p, effect, "highmidfrequency", AL_EQUALIZER_MID2_CENTER ); /* 1000.0 to 8000.0 (3000.0) */
1561 efx_setnum( L, p, effect, "highmidbandwidth", AL_EQUALIZER_MID2_WIDTH ); /* 0.01 to 1.0 (1.0) */
1562 efx_setnum( L, p, effect, "highgain", AL_EQUALIZER_HIGH_GAIN ); /* 0.126 to 7.943 (1.0) */
1563 efx_setnum( L, p, effect, "highcut", AL_EQUALIZER_HIGH_CUTOFF ); /* 4000.0 to 16000.0 (6000.0) */
1564 }
1565 else if (strcmp(type,"pitchshifter")==0) {
1566 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER);
1567
1568 efx_setint( L, p, effect, "tunecoarse", AL_PITCH_SHIFTER_COARSE_TUNE ); /* -12 to 12 (12) */
1569 efx_setint( L, p, effect, "tunefine'", AL_PITCH_SHIFTER_FINE_TUNE ); /* -50 to 50 (0) */
1570 }
1571 else if (strcmp(type,"vocalmorpher")==0) {
1572 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER);
1573
1574 efx_setint( L, p, effect, "phonemea", AL_VOCAL_MORPHER_PHONEMEA ); /* 0 to 29 (0 ("A")) */
1575 efx_setint( L, p, effect, "phonemeb", AL_VOCAL_MORPHER_PHONEMEB ); /* 0 to 29 (10 ("ER")) */
1576 efx_setint( L, p, effect, "tunecoarsea", AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING ); /* -24 to 24 (0) */
1577 efx_setint( L, p, effect, "tunecoarseb", AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING ); /* -24 to 24 (0) */
1578 efx_setint( L, p, effect, "waveform", AL_VOCAL_MORPHER_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square) (0 (sin)) */
1579 efx_setnum( L, p, effect, "rate", AL_VOCAL_MORPHER_RATE ); /* 0.0 to 10.0 (1.41) */
1580 }
1581 else if (strcmp(type,"flanger")==0) {
1582 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FLANGER);
1583
1584 efx_setint( L, p, effect, "waveform", AL_FLANGER_WAVEFORM ); /* 0 (sin), 1 (triangle) (1 (triangle)) */
1585 efx_setnum( L, p, effect, "phase", AL_FLANGER_PHASE ); /* -180 to 180 (0) */
1586 efx_setnum( L, p, effect, "rate", AL_FLANGER_RATE ); /* 0.0 to 10.0 (0.27) */
1587 efx_setnum( L, p, effect, "depth", AL_FLANGER_DEPTH ); /* 0.0 to 1.0 (1.0) */
1588 efx_setnum( L, p, effect, "feedback", AL_FLANGER_FEEDBACK ); /* -1.0 to 1.0 (-0.5) */
1589 efx_setnum( L, p, effect, "delay", AL_FLANGER_DELAY ); /* 0.0 to 0.004 (0.002) */
1590 }
1591 else if (strcmp(type,"frequencyshifter")==0) {
1592 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER);
1593
1594 efx_setnum( L, p, effect, "frequency", AL_FREQUENCY_SHIFTER_FREQUENCY ); /* 0.0 to 24000.0 (0.0) */
1595 efx_setint( L, p, effect, "leftdirection", AL_FREQUENCY_SHIFTER_LEFT_DIRECTION ); /* 0 (down), 1 (up), 2 (off) (0 (down)) */
1596 efx_setint( L, p, effect, "rightdirection", AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION ); /* 0 (down), 1 (up), 2 (off) (0 (down)) */
1597 }
1598 else {
1599 soundUnlock();
1600 return NLUA_ERROR(L, _("Usupported audio effect type '%s'!"), type);
1601 }
1602
1603 if (volume > 0.)
1604 nalAuxiliaryEffectSlotf( slot, AL_EFFECTSLOT_GAIN, volume );
1605 nalAuxiliaryEffectSloti( slot, AL_EFFECTSLOT_EFFECT, effect );
1606
1607 al_checkErr();
1608 soundUnlock();
1609
1610 return 0;
1611}
1612
1613static LuaAudioEfx_t *audio_getEffectByName( const char *name )
1614{
1615 for (int i=0; i<array_size(lua_efx); i++)
1616 if (strcmp(name,lua_efx[i].name)==0)
1617 return &lua_efx[i];
1618 WARN(_("Unknown audio effect '%s'!"), name);
1619 return NULL;
1620}
1621
1633static int audioL_setEffect( lua_State *L )
1634{
1635 if (al_info.efx == AL_FALSE) {
1636 lua_pushboolean(L,1);
1637 return 1;
1638 }
1639
1640 /* Creating new effect. */
1641 if (!lua_isaudio(L,1))
1642 return audioL_setEffectGlobal(L);
1643
1644 LuaAudio_t *la = luaL_checkaudio(L,1);
1645 const char *name = luaL_checkstring(L,2);
1646 int enable = (lua_isnoneornil(L,3)) ? 1 : lua_toboolean(L,3);
1647
1648 soundLock();
1649 if (enable) {
1650 LuaAudioEfx_t *lae = audio_getEffectByName( name );
1651 if (lae == NULL) {
1652 soundUnlock();
1653 return 0;
1654 }
1655 /* TODO allow more effect slots. */
1656 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, lae->slot, 0, AL_FILTER_NULL );
1657 }
1658 else
1659 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL );
1660
1661 al_checkErr();
1662 soundUnlock();
1663
1664 lua_pushboolean(L,1);
1665 return 1;
1666}
1667
1674static int audioL_setGlobalEffect( lua_State *L )
1675{
1676 LuaAudioEfx_t *lae;
1677 const char *name = luaL_optstring(L,1,NULL);
1678
1679 if (sound_disabled)
1680 return 0;
1681
1682 if (al_info.efx == AL_FALSE)
1683 return 0;
1684
1685 /* Disable. */
1686 if (name==NULL) {
1687 soundLock();
1688 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL );
1689 al_checkErr();
1690 soundUnlock();
1691 return 0;
1692 }
1693
1694 /* Try to set it. */
1695 lae = audio_getEffectByName( name );
1696 if (lae == NULL)
1697 return 0;
1698
1699 /* Set the effect. */
1700 soundLock();
1701 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT, lae->effect );
1702 al_checkErr();
1703 soundUnlock();
1704 return 0;
1705}
1706
1714static int audioL_setGlobalAirAbsorption( lua_State *L )
1715{
1716 double speed = luaL_optnumber( L, 1, 3433. );
1717 double absorption = luaL_optnumber( L, 2, -1. );
1718
1719 if (sound_disabled)
1720 return 0;
1721
1722 soundLock();
1723 alSpeedOfSound( speed );
1724 if (absorption > 0.)
1725 sound_setAbsorption( absorption );
1726 al_checkErr();
1727 soundUnlock();
1728 return 0;
1729}
1730
1739static int audioL_setGlobaDopplerFactor( lua_State *L )
1740{
1741 if (sound_disabled)
1742 return 0;
1743
1744 soundLock();
1745 alDopplerFactor( luaL_checknumber(L,1) );
1746 al_checkErr();
1747 soundUnlock();
1748 return 0;
1749}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
Header file with generic functions and naev-specifics.
#define CLAMP(a, b, x)
Definition naev.h:41
static int audioL_soundPlay(lua_State *L)
Plays a sound.
static int audioL_clone(lua_State *L)
Clones an existing audio source.
Definition nlua_audio.c:693
static int audioL_setGlobaDopplerFactor(lua_State *L)
Sets the doppler effect factor.
static int audioL_setRelative(lua_State *L)
Sets whether a source is relative or not.
static const luaL_Reg audioL_methods[]
Definition nlua_audio.c:89
static int audioL_pause(lua_State *L)
Pauses a source.
Definition nlua_audio.c:748
static int audioL_setEffect(lua_State *L)
Sets effect stuff, behaves different if the first parameter is a source or not.
static int audio_genSource(ALuint *source)
Tries to generate a single openal source, running GC if necessary.
Definition nlua_audio.c:472
static int audioL_setGlobalAirAbsorption(lua_State *L)
Allows setting the speed of sound and air absorption.
static int audioL_setGlobalEffect(lua_State *L)
Sets a global effect. Will overwrite whatever was set. Does not affect sources created in Lua.
static int audioL_isLooping(lua_State *L)
Gets the looping state of a source.
LuaAudio_t * lua_toaudio(lua_State *L, int ind)
Gets audio at index.
Definition nlua_audio.c:324
static int audioL_seek(lua_State *L)
Seeks a source.
Definition nlua_audio.c:875
LuaAudio_t * lua_pushaudio(lua_State *L, LuaAudio_t audio)
Pushes a audio on the stack.
Definition nlua_audio.c:349
static int audioL_getVelocity(lua_State *L)
Gets the velocity of a source.
static int audioL_setVolume(lua_State *L)
Sets the volume of a source.
static int audioL_getRolloff(lua_State *L)
Gets the rolloff factor.
static int audioL_rewind(lua_State *L)
Rewinds a source.
Definition nlua_audio.c:843
static int audioL_play(lua_State *L)
Plays a source.
Definition nlua_audio.c:709
static int audioL_setRolloff(lua_State *L)
Sets the rollof factor.
static int audioL_setLooping(lua_State *L)
Sets a source to be looping or not.
static int audioL_setPosition(lua_State *L)
Sets the position of a source.
static int audioL_isState(lua_State *L, ALenum state)
Checks to see the state of the source.
Definition nlua_audio.c:291
static int stream_loadBuffer(LuaAudio_t *la, ALuint buffer)
Loads a buffer.
Definition nlua_audio.c:179
int lua_isaudio(lua_State *L, int ind)
Checks to see if ind is a audio.
Definition nlua_audio.c:364
static int audioL_getDuration(lua_State *L)
Gets the length of a source.
Definition nlua_audio.c:980
static LuaAudioEfx_t * lua_efx
List of effects handled by Lua. These are persistent throughout game runtime.
Definition nlua_audio.c:47
static int audioL_isPaused(lua_State *L)
Checks to see if a source is paused.
Definition nlua_audio.c:767
#define RG_PREAMP_DB
Default pre-amp in dB.
Definition nlua_audio.c:33
LuaAudio_t * luaL_checkaudio(lua_State *L, int ind)
Gets audio at index or raises error if there is no audio at index.
Definition nlua_audio.c:335
static void rg_filter(float **pcm, long channels, long samples, void *filter_param)
This is the filter function for the decoded Ogg Vorbis stream.
Definition nlua_audio.c:242
static int audioL_getAttenuationDistances(lua_State *L)
Gets the attenuation distances for the audio source. Set to 0. if audio is disabled.
static int audioL_tell(lua_State *L)
Gets the position of a source.
Definition nlua_audio.c:925
static int audioL_setPitch(lua_State *L)
Sets the pitch of a source.
static int audioL_getVolume(lua_State *L)
Gets the volume of a source.
static int audioL_new(lua_State *L)
Creates a new audio source.
Definition nlua_audio.c:511
static int audioL_getPosition(lua_State *L)
Gets the position of a source.
static int audioL_isStopped(lua_State *L)
Checks to see if a source is stopped.
Definition nlua_audio.c:832
static int audioL_getPitch(lua_State *L)
Gets the pitch of a source.
static int audioL_gc(lua_State *L)
Lua bindings to interact with audio.
Definition nlua_audio.c:445
static int audioL_setAttenuationDistances(lua_State *L)
Sets the attenuation distances for the audio source.
static int audioL_setVelocity(lua_State *L)
Sets the velocity of a source.
int nlua_loadAudio(nlua_env env)
Loads the audio library.
Definition nlua_audio.c:311
static int audioL_stop(lua_State *L)
Stops a source.
Definition nlua_audio.c:778
static int audioL_isBool(lua_State *L, ALenum param)
Checks to see a boolean property of a source.
Definition nlua_audio.c:274
static int audioL_eq(lua_State *L)
Compares two audios to see if they are the same.
Definition nlua_audio.c:460
LuaFile_t * lua_tofile(lua_State *L, int ind)
Lua bindings to interact with files.
Definition nlua_file.c:86
int lua_isfile(lua_State *L, int ind)
Checks to see if ind is a file.
Definition nlua_file.c:126
vec2 * luaL_checkvector(lua_State *L, int ind)
Gets vector at index making sure type is valid.
Definition nlua_vec2.c:130
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
Definition sound.c:1295
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
Definition sound.c:2001
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1282
int sound_disabled
Definition sound.c:133
SDL_mutex * sound_lock
Definition sound.c:167
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
Definition sound.c:827
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:756
ALuint sound_efx_directSlot
Definition sound.c:194
alInfo_t al_info
Definition sound.c:178
ov_callbacks sound_al_ovcall
Definition sound.c:275
int sound_play(int sound)
Plays the sound in the first available channel.
Definition sound.c:789
Handles the OpenAL effects that have been set up Lua side.
Definition nlua_audio.c:38
ALuint effect
Definition nlua_audio.c:40
LuaBuffer_t * buf
Definition nlua_audio.h:40
OggVorbis_File stream
Definition nlua_audio.h:44
SDL_Thread * th
Definition nlua_audio.h:51
SDL_mutex * lock
Definition nlua_audio.h:42
int nocleanup
Definition nlua_audio.h:35
ALfloat rg_max_scale
Definition nlua_audio.h:48
LuaAudioType_t type
Definition nlua_audio.h:34
double volume
Definition nlua_audio.h:38
SDL_cond * cond
Definition nlua_audio.h:52
ALenum format
Definition nlua_audio.h:46
ALuint stream_buffers[2]
Definition nlua_audio.h:49
ALuint source
Definition nlua_audio.h:36
vorbis_info * info
Definition nlua_audio.h:45
ALfloat rg_scale_factor
Definition nlua_audio.h:47
ALuint buffer
Definition nlua_audio.h:25
Wrapper to files.
Definition nlua_file.h:17
char path[PATH_MAX]
Definition nlua_file.h:18
ALint efx
Definition sound.h:43
Represents a 2d vector.
Definition vec2.h:32
double y
Definition vec2.h:34
double x
Definition vec2.h:33