naev 0.10.4
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 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 al_checkErr();
490 break;
491
492 default:
493#if DEBUGGING
494 al_checkHandleError( err, __func__, __LINE__ );
495#endif /* DEBUGGING */
496 return -1;
497 }
498 return 0;
499}
500
509static int audioL_new( lua_State *L )
510{
511 LuaAudio_t la;
512 LuaFile_t *lf;
513 double master;
514 int stream;
515 const char *name;
516 SDL_RWops *rw;
517
518 /* First parameter. */
519 if (lua_isstring(L,1))
520 name = lua_tostring(L,1);
521 else if (lua_isfile(L,1)) {
522 lf = lua_tofile(L,1);
523 name = lf->path;
524 }
525 else
526 NLUA_INVALID_PARAMETER(L);
527
528 /* Second parameter. */
529 if (lua_isnoneornil(L,2)) {
530 stream = 0;
531 }
532 else {
533 const char *type = luaL_optstring(L,2,"static");
534 if (strcmp(type,"static")==0)
535 stream = 0;
536 else if (strcmp(type,"stream")==0)
537 stream = 1;
538 else
539 NLUA_INVALID_PARAMETER(L);
540 }
541
542 memset( &la, 0, sizeof(LuaAudio_t) );
543 if (sound_disabled) {
544 la.nocleanup = 1; /* Not initialized so no need to clean up. */
545 lua_pushaudio(L, la);
546 return 1;
547 }
548 rw = PHYSFSRWOPS_openRead( name );
549 if (rw==NULL)
550 NLUA_ERROR(L,"Unable to open '%s'", name );
551#if DEBUGGING
552 la.name = strdup( name );
553#endif /* DEBUGGING */
554
555 soundLock();
556 audio_genSource( &la.source );
557
558 /* Deal with stream. */
559 if (!stream) {
560 la.type = LUA_AUDIO_STATIC;
561 la.buf = malloc( sizeof(LuaBuffer_t) );
562 la.buf->refcount = 1;
563 sound_al_buffer( &la.buf->buffer, rw, name );
564
565 /* Attach buffer. */
566 alSourcei( la.source, AL_BUFFER, la.buf->buffer );
567
568 /* Clean up. */
569 SDL_RWclose( rw );
570 }
571 else {
572 vorbis_comment *vc;
573 ALfloat track_gain_db, track_peak;
574 char *tag;
575
576 la.type = LUA_AUDIO_STREAM;
577 /* ov_clear will close rw for us. */
578 if (ov_open_callbacks( rw, &la.stream, NULL, 0, sound_al_ovcall ) < 0) {
579 SDL_RWclose( rw );
580 NLUA_ERROR(L,_("Audio '%s' does not appear to be a Vorbis bitstream."), name );
581 }
582 la.info = ov_info( &la.stream, -1 );
583
584 /* Replaygain information. */
585 vc = ov_comment( &la.stream, -1 );
586 track_gain_db = 0.;
587 track_peak = 1.;
588 if ((tag = vorbis_comment_query(vc, "replaygain_track_gain", 0)))
589 track_gain_db = atof(tag);
590 if ((tag = vorbis_comment_query(vc, "replaygain_track_peak", 0)))
591 track_peak = atof(tag);
592 la.rg_scale_factor = pow(10.0, (track_gain_db + RG_PREAMP_DB)/20.0);
593 la.rg_max_scale = 1.0 / track_peak;
594
595 /* Set the format */
596 if (la.info->channels == 1)
597 la.format = AL_FORMAT_MONO16;
598 else
599 la.format = AL_FORMAT_STEREO16;
600
601 la.active = 0;
602 la.lock = SDL_CreateMutex();
603 la.cond = SDL_CreateCond();
604 alGenBuffers( 2, la.stream_buffers );
605 /* Buffers get queued later. */
606 }
607
608 /* Defaults. */
609 la.volume = 1.;
610 master = sound_getVolumeLog();
611 alSourcef( la.source, AL_GAIN, master );
612 /* The behaviour of sources depends on whether or not they are mono or
613 * stereo. In the case they are stereo, no position stuff is actually
614 * done. However, if they are mono, they are played with absolute
615 * position and the sound heard depends on the listener. We can disable
616 * this by setting AL_SOURCE_RELATIVE which puts the listener always at
617 * the origin, and then setting the source at the same origin. It should
618 * be noted that depending on the sound model this can be bad if it is
619 * not bounded. */
620 alSourcei( la.source, AL_SOURCE_RELATIVE, AL_TRUE );
621 alSource3f( la.source, AL_POSITION, 0., 0., 0. );
622 al_checkErr();
623 soundUnlock();
624
625 lua_pushaudio(L, la);
626 return 1;
627}
628
629void audio_clone( LuaAudio_t *la, const LuaAudio_t *source )
630{
631 double master;
632
633 memset( la, 0, sizeof(LuaAudio_t) );
634 if (sound_disabled) {
635 la->nocleanup = 1;
636 return;
637 }
638
639 soundLock();
640 audio_genSource( &la->source );
641
642 switch (source->type) {
643 case LUA_AUDIO_STATIC:
644 /* Attach source buffer. */
645 la->buf = source->buf;
646 la->buf->refcount++;
647
648 /* Attach buffer. */
649 alSourcei( la->source, AL_BUFFER, la->buf->buffer );
650 break;
651
652 case LUA_AUDIO_STREAM:
653 WARN(_("Unimplemented"));
654 break;
655
656 case LUA_AUDIO_NULL:
657 break;
658 }
659 la->type = source->type;
660
661 /* TODO this should probably set the same parameters as the original source
662 * being cloned to be truly compatible with Love2D. */
663 /* Defaults. */
664 master = sound_getVolumeLog();
665 alSourcef( la->source, AL_GAIN, master );
666 la->volume = 1.;
667 /* See note in audioL_new */
668 alSourcei( la->source, AL_SOURCE_RELATIVE, AL_TRUE );
669 alSource3f( la->source, AL_POSITION, 0., 0., 0. );
670 al_checkErr();
671 soundUnlock();
672}
673
681static int audioL_clone( lua_State *L )
682{
683 LuaAudio_t la;
684 LuaAudio_t *source = luaL_checkaudio(L,1);
685
686 audio_clone( &la, source );
687
688 lua_pushaudio(L, la);
689 return 1;
690}
691
699static int audioL_play( lua_State *L )
700{
701 LuaAudio_t *la = luaL_checkaudio(L,1);
702 if (sound_disabled)
703 return 0;
704
705 if ((la->type == LUA_AUDIO_STREAM) && (la->th == NULL)) {
706 int ret = 0;
707 ALint alstate;
708 soundLock();
709 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
710 while (alstate < 2) {
711 ret = stream_loadBuffer( la, la->stream_buffers[ la->active ] );
712 if (ret < 0)
713 break;
714 alSourceQueueBuffers( la->source, 1, &la->stream_buffers[ la->active ] );
715 la->active = 1-la->active;
716 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
717 }
718 if (ret == 0)
719 la->th = SDL_CreateThread( stream_thread, "stream_thread", la );
720 }
721 else
722 soundLock();
723 alSourcePlay( la->source );
724 al_checkErr();
725 soundUnlock();
726
727 lua_pushboolean(L,1);
728 return 1;
729}
730
738static int audioL_pause( lua_State *L )
739{
740 LuaAudio_t *la = luaL_checkaudio(L,1);
741 if (sound_disabled)
742 return 0;
743 soundLock();
744 alSourcePause( la->source );
745 al_checkErr();
746 soundUnlock();
747 return 0;
748}
749
757static int audioL_isPaused( lua_State *L )
758{
759 return audioL_isState( L, AL_PAUSED );
760}
761
768static int audioL_stop( lua_State *L )
769{
770 ALint alstate;
771 ALuint removed[2];
772 LuaAudio_t *la = luaL_checkaudio(L,1);
773 if (sound_disabled)
774 return 0;
775
776 soundLock();
777 switch (la->type) {
778 case LUA_AUDIO_NULL:
779 break;
780 case LUA_AUDIO_STATIC:
781 alSourceStop( la->source );
782 break;
783
784 case LUA_AUDIO_STREAM:
785 /* Kill the thread first. */
786 if (la->th != NULL) {
787 la->active = -1;
788 if (SDL_CondWaitTimeout( la->cond, sound_lock, 3000 ) == SDL_MUTEX_TIMEDOUT)
789#if DEBUGGING
790 WARN(_("Timed out while waiting for audio thread of '%s' to finish!"), la->name);
791#else /* DEBUGGING */
792 WARN(_("Timed out while waiting for audio thread to finish!"));
793#endif /* DEBUGGING */
794 }
795 la->th = NULL;
796
797 /* Stopping a source will make all buffers become processed. */
798 alSourceStop( la->source );
799
800 /* Unqueue the buffers. */
801 alGetSourcei( la->source, AL_BUFFERS_PROCESSED, &alstate );
802 alSourceUnqueueBuffers( la->source, alstate, removed );
803
804 /* Seek the stream to the beginning. */
805 SDL_mutexP( la->lock );
806 ov_pcm_seek( &la->stream, 0 );
807 SDL_mutexV( la->lock );
808 break;
809 }
810 al_checkErr();
811 soundUnlock();
812 return 0;
813}
814
822static int audioL_isStopped( lua_State *L )
823{
824 return audioL_isState( L, AL_STOPPED );
825}
826
833static int audioL_rewind( lua_State *L )
834{
835 LuaAudio_t *la = luaL_checkaudio(L,1);
836 if (sound_disabled)
837 return 0;
838
839 switch (la->source) {
840 case LUA_AUDIO_STATIC:
841 soundLock();
842 alSourceRewind( la->source );
843 al_checkErr();
844 soundUnlock();
845 break;
846 case LUA_AUDIO_STREAM:
847 SDL_mutexP( la->lock );
848 ov_raw_seek( &la->stream, 0 );
849 SDL_mutexV( la->lock );
850 break;
851 case LUA_AUDIO_NULL:
852 break;
853 }
854 return 0;
855}
856
865static int audioL_seek( lua_State *L )
866{
867 LuaAudio_t *la = luaL_checkaudio(L,1);
868 double offset = luaL_checknumber(L,2);
869 const char *unit = luaL_optstring(L,3,"seconds");
870 int seconds = 1;
871
872 if (strcmp(unit,"samples")==0)
873 seconds = 0;
874 else if (strcmp(unit,"seconds")!=0)
875 NLUA_ERROR(L, _("Unknown seek source '%s'! Should be either 'seconds' or 'samples'!"), unit );
876
877 if (sound_disabled)
878 return 0;
879
880 switch (la->type) {
881 case LUA_AUDIO_STATIC:
882 soundLock();
883 if (seconds)
884 alSourcef( la->source, AL_SEC_OFFSET, offset );
885 else
886 alSourcef( la->source, AL_SAMPLE_OFFSET, offset );
887 al_checkErr();
888 soundUnlock();
889 break;
890
891 case LUA_AUDIO_STREAM:
892 SDL_mutexP( la->lock );
893 if (seconds)
894 ov_time_seek( &la->stream, offset );
895 else
896 ov_pcm_seek( &la->stream, offset );
897 SDL_mutexV( la->lock );
898 /* TODO force a reset of the buffers. */
899 break;
900
901 case LUA_AUDIO_NULL:
902 break;
903 }
904 return 0;
905}
906
915static int audioL_tell( lua_State *L )
916{
917 LuaAudio_t *la = luaL_checkaudio(L,1);
918 const char *unit = luaL_optstring(L,2,"seconds");
919 double offset = -1.;
920 float aloffset;
921 int seconds = 1;
922
923 if (strcmp(unit,"samples")==0)
924 seconds = 0;
925 else if (strcmp(unit,"seconds")!=0)
926 NLUA_ERROR(L, _("Unknown seek source '%s'! Should be either 'seconds' or 'samples'!"), unit );
927
928 if (sound_disabled) {
929 lua_pushnumber(L, -1.);
930 return 1;
931 }
932
933 switch (la->type) {
934 case LUA_AUDIO_STATIC:
935 soundLock();
936 if (seconds)
937 alGetSourcef( la->source, AL_SEC_OFFSET, &aloffset );
938 else
939 alGetSourcef( la->source, AL_SAMPLE_OFFSET, &aloffset );
940 offset = aloffset;
941 al_checkErr();
942 soundUnlock();
943 break;
944
945 case LUA_AUDIO_STREAM:
946 SDL_mutexP( la->lock );
947 if (seconds)
948 offset = ov_time_tell( &la->stream );
949 else
950 offset = ov_pcm_tell( &la->stream );
951 SDL_mutexV( la->lock );
952 break;
953
954 case LUA_AUDIO_NULL:
955 break;
956 }
957
958 lua_pushnumber(L, offset);
959 return 1;
960}
961
970static int audioL_getDuration( lua_State *L )
971{
972 LuaAudio_t *la = luaL_checkaudio(L,1);
973 const char *unit = luaL_optstring(L,2,"seconds");
974 float duration = -1.;
975 int seconds = 1;
976 ALint bytes, channels, bits, samples;
977 ALuint buffer;
978
979 if (strcmp(unit,"samples")==0)
980 seconds = 0;
981 else if (strcmp(unit,"seconds")!=0)
982 NLUA_ERROR(L, _("Unknown duration source '%s'! Should be either 'seconds' or 'samples'!"), unit );
983
984 if (sound_disabled) {
985 lua_pushnumber(L, -1.);
986 return 1;
987 }
988
989 switch (la->type) {
990 case LUA_AUDIO_STATIC:
991 soundLock();
992 buffer = la->buf->buffer;
993 alGetBufferi( buffer, AL_SIZE, &bytes );
994 alGetBufferi( buffer, AL_CHANNELS, &channels );
995 alGetBufferi( buffer, AL_BITS, &bits );
996
997 samples = bytes * 8 / (channels * bits);
998
999 if (seconds) {
1000 ALint freq;
1001 alGetBufferi( buffer, AL_FREQUENCY, &freq );
1002 duration = (float) samples / (float) freq;
1003 }
1004 else
1005 duration = samples;
1006 al_checkErr();
1007 soundUnlock();
1008 break;
1009
1010 case LUA_AUDIO_STREAM:
1011 SDL_mutexP( la->lock );
1012 if (seconds)
1013 duration = ov_time_total( &la->stream, -1 );
1014 else
1015 duration = ov_pcm_total( &la->stream, -1 );
1016 SDL_mutexV( la->lock );
1017 break;
1018
1019 case LUA_AUDIO_NULL:
1020 break;
1021 }
1022
1023 lua_pushnumber(L, duration);
1024 return 1;
1025}
1026
1035static int audioL_setVolume( lua_State *L )
1036{
1037 LuaAudio_t *la = luaL_checkaudio(L,1);
1038 double volume = CLAMP( 0.0, 1.0, luaL_checknumber(L,2) );
1039 int ignorevol = lua_toboolean(L,3);
1040 if (sound_disabled)
1041 return 0;
1042
1043 soundLock();
1044 if (ignorevol)
1045 alSourcef( la->source, AL_GAIN, volume );
1046 else {
1047 double master = sound_getVolumeLog();
1048 alSourcef( la->source, AL_GAIN, master * volume );
1049 }
1050 al_checkErr();
1051 soundUnlock();
1052 la->volume = volume;
1053 return 0;
1054}
1055
1063static int audioL_getVolume( lua_State *L )
1064{
1065 double volume;
1066 if (sound_disabled)
1067 volume = 0.;
1068 else if (lua_gettop(L) > 0)
1069 volume = luaL_checkaudio(L,1)->volume;
1070 else
1071 volume = sound_getVolume();
1072 lua_pushnumber(L, volume);
1073 return 1;
1074}
1075
1082static int audioL_setRelative( lua_State *L )
1083{
1084 LuaAudio_t *la = luaL_checkaudio(L,1);
1085 if (sound_disabled)
1086 return 0;
1087
1088 soundLock();
1089 alSourcei( la->source, AL_SOURCE_RELATIVE, lua_toboolean(L,2) );
1090 al_checkErr();
1091 soundUnlock();
1092 return 0;
1093}
1094
1104static int audioL_setPosition( lua_State *L )
1105{
1106 ALfloat pos[3];
1107 LuaAudio_t *la = luaL_checkaudio(L,1);
1108 if (sound_disabled)
1109 return 0;
1110
1111 pos[0] = luaL_optnumber(L,2,0.);
1112 pos[1] = luaL_optnumber(L,3,0.);
1113 pos[2] = luaL_optnumber(L,4,0.);
1114
1115 soundLock();
1116 alSourcefv( la->source, AL_POSITION, pos );
1117 al_checkErr();
1118 soundUnlock();
1119 return 0;
1120}
1121
1131static int audioL_getPosition( lua_State *L )
1132{
1133 ALfloat pos[3];
1134 LuaAudio_t *la = luaL_checkaudio(L,1);
1135 if (sound_disabled) {
1136 lua_pushnumber(L,0.);
1137 lua_pushnumber(L,0.);
1138 lua_pushnumber(L,0.);
1139 return 0;
1140 }
1141
1142 soundLock();
1143 alGetSource3f( la->source, AL_POSITION, &pos[0], &pos[1], &pos[2] );
1144 al_checkErr();
1145 soundUnlock();
1146
1147 lua_pushnumber(L,pos[0]);
1148 lua_pushnumber(L,pos[1]);
1149 lua_pushnumber(L,pos[2]);
1150 return 3;
1151}
1152
1162static int audioL_setVelocity( lua_State *L )
1163{
1164 ALfloat vel[3];
1165 LuaAudio_t *la = luaL_checkaudio(L,1);
1166 if (sound_disabled)
1167 return 0;
1168
1169 vel[0] = luaL_optnumber(L,2,0.);
1170 vel[1] = luaL_optnumber(L,3,0.);
1171 vel[2] = luaL_optnumber(L,4,0.);
1172
1173 soundLock();
1174 alSourcefv( la->source, AL_VELOCITY, vel );
1175 al_checkErr();
1176 soundUnlock();
1177 return 0;
1178}
1179
1189static int audioL_getVelocity( lua_State *L )
1190{
1191 ALfloat vel[3];
1192 LuaAudio_t *la = luaL_checkaudio(L,1);
1193 if (sound_disabled) {
1194 lua_pushnumber(L,0.);
1195 lua_pushnumber(L,0.);
1196 lua_pushnumber(L,0.);
1197 return 0;
1198 }
1199
1200 soundLock();
1201 alGetSource3f( la->source, AL_VELOCITY, &vel[0], &vel[1], &vel[2] );
1202 al_checkErr();
1203 soundUnlock();
1204
1205 lua_pushnumber(L,vel[0]);
1206 lua_pushnumber(L,vel[1]);
1207 lua_pushnumber(L,vel[2]);
1208 return 3;
1209}
1210
1218static int audioL_setLooping( lua_State *L )
1219{
1220 LuaAudio_t *la = luaL_checkaudio(L,1);
1221 int b = lua_toboolean(L,2);
1222 if (sound_disabled)
1223 return 0;
1224 soundLock();
1225 alSourcei( la->source, AL_LOOPING, b );
1226 al_checkErr();
1227 soundUnlock();
1228 return 0;
1229}
1230
1238static int audioL_isLooping( lua_State *L )
1239{
1240 return audioL_isBool( L, AL_LOOPING );
1241}
1242
1250static int audioL_setPitch( lua_State *L )
1251{
1252 LuaAudio_t *la = luaL_checkaudio(L,1);
1253 double pitch = luaL_checknumber(L,2);
1254 if (sound_disabled)
1255 return 0;
1256 soundLock();
1257 alSourcef( la->source, AL_PITCH, pitch );
1258 al_checkErr();
1259 soundUnlock();
1260 return 0;
1261}
1262
1270static int audioL_getPitch( lua_State *L )
1271{
1272 LuaAudio_t *la = luaL_checkaudio(L,1);
1273 float p = 1.0;
1274 if (!sound_disabled) {
1275 soundLock();
1276 alGetSourcef( la->source, AL_PITCH, &p );
1277 al_checkErr();
1278 soundUnlock();
1279 }
1280 lua_pushnumber(L,p);
1281 return 1;
1282}
1283
1298static int audioL_soundPlay( lua_State *L )
1299{
1300 const char *name;
1301 vec2 *pos, *vel, vel0;
1302 int dopos;
1303
1304 /* Flag wether to use sound_playPos or sound_play. */
1305 dopos = 0;
1306
1307 /* Handle parameters. */
1308 name = luaL_checkstring(L,1);
1309 if (lua_gettop(L) > 1) {
1310 dopos = 1;
1311 pos = luaL_checkvector(L,2);
1312 if (lua_gettop(L) > 2) {
1313 vel = luaL_checkvector(L,3);
1314 }
1315 else {
1316 vectnull( &vel0 );
1317 vel = &vel0;
1318 }
1319 }
1320
1321 if (dopos)
1322 sound_playPos( sound_get(name), pos->x, pos->y, vel->x, vel->y );
1323 else
1324 sound_play( sound_get(name) );
1325
1326 return 0;
1327}
1328
1336static int audioL_setAttenuationDistances( lua_State *L )
1337{
1338 LuaAudio_t *la = luaL_checkaudio(L,1);
1339 double ref = luaL_checknumber(L,2);
1340 double max = luaL_checknumber(L,3);
1341 if (sound_disabled)
1342 return 0;
1343 soundLock();
1344 alSourcef( la->source, AL_REFERENCE_DISTANCE, ref );
1345 alSourcef( la->source, AL_MAX_DISTANCE, max );
1346 al_checkErr();
1347 soundUnlock();
1348 return 0;
1349}
1350
1358static int audioL_getAttenuationDistances( lua_State *L )
1359{
1360 ALfloat ref, max;
1361 LuaAudio_t *la = luaL_checkaudio(L,1);
1362 if (sound_disabled) {
1363 lua_pushnumber(L,0.);
1364 lua_pushnumber(L,0.);
1365 return 2;
1366 }
1367 soundLock();
1368 alGetSourcef( la->source, AL_REFERENCE_DISTANCE, &ref );
1369 alGetSourcef( la->source, AL_MAX_DISTANCE, &max );
1370 al_checkErr();
1371 soundUnlock();
1372 lua_pushnumber( L, ref );
1373 lua_pushnumber( L, max );
1374 return 2;
1375}
1376
1383static int audioL_setRolloff( lua_State *L )
1384{
1385 LuaAudio_t *la = luaL_checkaudio(L,1);
1386 double rolloff = luaL_checknumber(L,2);
1387 if (sound_disabled)
1388 return 0;
1389 soundLock();
1390 alSourcef( la->source, AL_ROLLOFF_FACTOR, rolloff );
1391 al_checkErr();
1392 soundUnlock();
1393 return 0;
1394}
1395
1402static int audioL_getRolloff( lua_State *L )
1403{
1404 ALfloat rolloff;
1405 LuaAudio_t *la = luaL_checkaudio(L,1);
1406 if (sound_disabled) {
1407 lua_pushnumber(L,0.);
1408 return 1;
1409 }
1410 soundLock();
1411 alGetSourcef( la->source, AL_ROLLOFF_FACTOR, &rolloff);
1412 al_checkErr();
1413 soundUnlock();
1414 lua_pushnumber( L, rolloff );
1415 return 1;
1416}
1417
1418static void efx_setnum( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1419 lua_getfield(L,pos,name);
1420 if (!lua_isnil(L,-1))
1421 nalEffectf( effect, param, luaL_checknumber(L,-1) );
1422 lua_pop(L,1);
1423}
1424static void efx_setint( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1425 lua_getfield(L,pos,name);
1426 if (!lua_isnil(L,-1))
1427 nalEffecti( effect, param, luaL_checkinteger(L,-1) );
1428 lua_pop(L,1);
1429}
1430static void efx_setbool( lua_State *L, int pos, ALuint effect, const char *name, ALuint param ) {
1431 lua_getfield(L,pos,name);
1432 if (!lua_isnil(L,-1))
1433 nalEffecti( effect, param, lua_toboolean(L,-1) ? AL_TRUE : AL_FALSE );
1434 lua_pop(L,1);
1435}
1436static int audioL_setEffectGlobal( lua_State *L )
1437{
1438 const char *name = luaL_checkstring(L,1);
1439 ALuint effect, slot;
1440 const char *type;
1441 double volume;
1442 LuaAudioEfx_t *lae;
1443 const int p = 2;
1444
1445 /* Get the type. */
1446 lua_getfield(L,p,"type");
1447 type = luaL_checkstring(L,-1);
1448 lua_pop(L,1);
1449
1450 /* Get the volume. */
1451 lua_getfield(L,p,"volume");
1452 if (lua_isnil(L,-1))
1453 volume = -1.;
1454 else
1455 volume = luaL_checknumber(L,-1);
1456 lua_pop(L,1);
1457
1458 soundLock();
1459
1460 /* Find or add to array as necessary. */
1461 if (lua_efx == NULL)
1463 lae = NULL;
1464 for (int i=0; i<array_size(lua_efx); i++) {
1465 if (strcmp(name,lua_efx[i].name)==0) {
1466 lae = &lua_efx[i];
1467 break;
1468 }
1469 }
1470 if (lae == NULL) {
1471 lae = &array_grow( &lua_efx );
1472 nalGenEffects(1, &effect);
1473 nalGenAuxiliaryEffectSlots( 1, &slot );
1474 lae->name = strdup( name );
1475 lae->effect = effect;
1476 lae->slot = slot;
1477 }
1478 else {
1479 effect = lae->effect;
1480 slot = lae->slot;
1481 }
1482
1483 /* Handle types. */
1484 if (strcmp(type,"reverb")==0) {
1485 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
1486
1487 efx_setnum( L, p, effect, "density", AL_REVERB_DENSITY ); /* 0.0 to 1.0 (1.0) */
1488 efx_setnum( L, p, effect, "diffusion", AL_REVERB_DIFFUSION ); /* 0.0 to 1.0 (1.0) */
1489 efx_setnum( L, p, effect, "gain", AL_REVERB_GAIN ); /* 0.0 to 1.0 (0.32) */
1490 efx_setnum( L, p, effect, "highgain", AL_REVERB_GAINHF ); /* 0.0 to 1.0 (0.89) */
1491 efx_setnum( L, p, effect, "decaytime", AL_REVERB_DECAY_TIME ); /* 0.1 to 20.0 (1.49) */
1492 efx_setnum( L, p, effect, "decayhighratio", AL_REVERB_DECAY_HFRATIO ); /* 0.1 to 2.0 (0.83) */
1493 efx_setnum( L, p, effect, "earlygain", AL_REVERB_REFLECTIONS_GAIN ); /* 0.0 to 3.16 (0.05) */
1494 efx_setnum( L, p, effect, "earlydelay", AL_REVERB_REFLECTIONS_DELAY ); /* 0.0 to 0.3 (0.007) */
1495 efx_setnum( L, p, effect, "lategain", AL_REVERB_LATE_REVERB_GAIN ); /* 0.0 to 10.0 (1.26) */
1496 efx_setnum( L, p, effect, "latedelay", AL_REVERB_LATE_REVERB_DELAY ); /* 0.0 to 0.1 (0.011) */
1497 efx_setnum( L, p, effect, "roomrolloff", AL_REVERB_ROOM_ROLLOFF_FACTOR ); /* 0.0 to 10.0 (0.0) */
1498 efx_setnum( L, p, effect, "airabsorption", AL_REVERB_AIR_ABSORPTION_GAINHF ); /* 0.892 to 1.0 (0.994) */
1499 efx_setbool( L, p, effect, "highlimit", AL_REVERB_DECAY_HFLIMIT ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1500 }
1501 else if (strcmp(type,"distortion")==0) {
1502 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION);
1503
1504 efx_setnum( L, p, effect, "gain", AL_DISTORTION_GAIN ); /* 0.01 to 1.0 (0.2) */
1505 efx_setnum( L, p, effect, "edge", AL_DISTORTION_EDGE ); /* 0.0 to 1.0 (0.05) */
1506 efx_setnum( L, p, effect, "lowcut", AL_DISTORTION_LOWPASS_CUTOFF ); /* 80.0 to 24000.0 (8000.0) */
1507 efx_setnum( L, p, effect, "center", AL_DISTORTION_EQCENTER ); /* 80.0 to 24000.0 (3600.0) */
1508 efx_setnum( L, p, effect, "bandwidth", AL_DISTORTION_EQBANDWIDTH ); /* 80.0 to 24000.0 (3600.0) */
1509 }
1510 else if (strcmp(type,"chorus")==0) {
1511 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS);
1512
1513 efx_setint( L, p, effect, "waveform", AL_CHORUS_WAVEFORM ); /* 0=sin, 1=triangle (1) */
1514 efx_setint( L, p, effect, "phase", AL_CHORUS_PHASE ); /* -180 to 180 (90) */
1515 efx_setnum( L, p, effect, "rate", AL_CHORUS_RATE ); /* 0.0 to 10.0 (1.1) */
1516 efx_setnum( L, p, effect, "depth", AL_CHORUS_DEPTH ); /* 0.0 to 1.0 (0.1) */
1517 efx_setnum( L, p, effect, "feedback", AL_CHORUS_FEEDBACK ); /* -1.0 to 1.0 (0.25) */
1518 efx_setnum( L, p, effect, "delay", AL_CHORUS_DELAY ); /* 0.0 to 0.016 (0.016) */
1519 }
1520 else if (strcmp(type,"compressor")==0) {
1521 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR);
1522
1523 efx_setbool( L, p, effect, "enable", AL_COMPRESSOR_ONOFF ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1524 }
1525 else if (strcmp(type,"echo")==0) {
1526 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO);
1527
1528 efx_setnum( L, p, effect, "delay", AL_ECHO_DELAY ); /* 0.0 to 0.207 (0.1) */
1529 efx_setnum( L, p, effect, "tapdelay", AL_ECHO_LRDELAY ); /* 0.0 to 0.404 (0.1) */
1530 efx_setnum( L, p, effect, "damping", AL_ECHO_DAMPING ); /* 0.0 to 0.99 (0.5) */
1531 efx_setnum( L, p, effect, "feedback", AL_ECHO_FEEDBACK ); /* 0.0 to 1.0 (0.5) */
1532 efx_setnum( L, p, effect, "spread", AL_ECHO_SPREAD ); /* -1.0 to 1.0 (-1.0) */
1533 }
1534 else if (strcmp(type,"ringmodulator")==0) {
1535 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR);
1536
1537 efx_setnum( L, p, effect, "frequency", AL_RING_MODULATOR_FREQUENCY ); /* 0.0 to 8000.0 (440.0) */
1538 efx_setnum( L, p, effect, "highcut", AL_RING_MODULATOR_HIGHPASS_CUTOFF ); /* 0.0 to 24000.0 (800.0) */
1539 efx_setint( L, p, effect, "waveform", AL_RING_MODULATOR_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square) (0 (sin)) */
1540 }
1541 else if (strcmp(type,"equalizer")==0) {
1542 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER);
1543
1544 efx_setnum( L, p, effect, "lowgain", AL_EQUALIZER_LOW_GAIN ); /* 0.126 to 7.943 (1.0) */
1545 efx_setnum( L, p, effect, "lowcut", AL_EQUALIZER_LOW_CUTOFF ); /* 50.0 to 800.0 (200.0) */
1546 efx_setnum( L, p, effect, "lowmidgain", AL_EQUALIZER_MID1_GAIN ); /* 0.126 to 7.943 (1.0) */
1547 efx_setnum( L, p, effect, "lowmidfrequency", AL_EQUALIZER_MID1_CENTER ); /* 200.0 to 3000.0 (500.0) */
1548 efx_setnum( L, p, effect, "lowmidbandwidth", AL_EQUALIZER_MID1_WIDTH ); /* 0.01 to 1.0 (1.0) */
1549 efx_setnum( L, p, effect, "highmidgain", AL_EQUALIZER_MID2_GAIN ); /* 0.126 to 7.943 (1.0) */
1550 efx_setnum( L, p, effect, "highmidfrequency", AL_EQUALIZER_MID2_CENTER ); /* 1000.0 to 8000.0 (3000.0) */
1551 efx_setnum( L, p, effect, "highmidbandwidth", AL_EQUALIZER_MID2_WIDTH ); /* 0.01 to 1.0 (1.0) */
1552 efx_setnum( L, p, effect, "highgain", AL_EQUALIZER_HIGH_GAIN ); /* 0.126 to 7.943 (1.0) */
1553 efx_setnum( L, p, effect, "highcut", AL_EQUALIZER_HIGH_CUTOFF ); /* 4000.0 to 16000.0 (6000.0) */
1554 }
1555 else if (strcmp(type,"pitchshifter")==0) {
1556 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER);
1557
1558 efx_setint( L, p, effect, "tunecoarse", AL_PITCH_SHIFTER_COARSE_TUNE ); /* -12 to 12 (12) */
1559 efx_setint( L, p, effect, "tunefine'", AL_PITCH_SHIFTER_FINE_TUNE ); /* -50 to 50 (0) */
1560 }
1561 else if (strcmp(type,"vocalmorpher")==0) {
1562 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER);
1563
1564 efx_setint( L, p, effect, "phonemea", AL_VOCAL_MORPHER_PHONEMEA ); /* 0 to 29 (0 ("A")) */
1565 efx_setint( L, p, effect, "phonemeb", AL_VOCAL_MORPHER_PHONEMEB ); /* 0 to 29 (10 ("ER")) */
1566 efx_setint( L, p, effect, "tunecoarsea", AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING ); /* -24 to 24 (0) */
1567 efx_setint( L, p, effect, "tunecoarseb", AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING ); /* -24 to 24 (0) */
1568 efx_setint( L, p, effect, "waveform", AL_VOCAL_MORPHER_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square) (0 (sin)) */
1569 efx_setnum( L, p, effect, "rate", AL_VOCAL_MORPHER_RATE ); /* 0.0 to 10.0 (1.41) */
1570 }
1571 else if (strcmp(type,"flanger")==0) {
1572 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FLANGER);
1573
1574 efx_setint( L, p, effect, "waveform", AL_FLANGER_WAVEFORM ); /* 0 (sin), 1 (triangle) (1 (triangle)) */
1575 efx_setnum( L, p, effect, "phase", AL_FLANGER_PHASE ); /* -180 to 180 (0) */
1576 efx_setnum( L, p, effect, "rate", AL_FLANGER_RATE ); /* 0.0 to 10.0 (0.27) */
1577 efx_setnum( L, p, effect, "depth", AL_FLANGER_DEPTH ); /* 0.0 to 1.0 (1.0) */
1578 efx_setnum( L, p, effect, "feedback", AL_FLANGER_FEEDBACK ); /* -1.0 to 1.0 (-0.5) */
1579 efx_setnum( L, p, effect, "delay", AL_FLANGER_DELAY ); /* 0.0 to 0.004 (0.002) */
1580 }
1581 else if (strcmp(type,"frequencyshifter")==0) {
1582 nalEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER);
1583
1584 efx_setnum( L, p, effect, "frequency", AL_FREQUENCY_SHIFTER_FREQUENCY ); /* 0.0 to 24000.0 (0.0) */
1585 efx_setint( L, p, effect, "leftdirection", AL_FREQUENCY_SHIFTER_LEFT_DIRECTION ); /* 0 (down), 1 (up), 2 (off) (0 (down)) */
1586 efx_setint( L, p, effect, "rightdirection", AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION ); /* 0 (down), 1 (up), 2 (off) (0 (down)) */
1587 }
1588 else {
1589 soundUnlock();
1590 NLUA_ERROR(L, _("Usupported audio effect type '%s'!"), type);
1591 }
1592
1593 if (volume > 0.)
1594 nalAuxiliaryEffectSlotf( slot, AL_EFFECTSLOT_GAIN, volume );
1595 nalAuxiliaryEffectSloti( slot, AL_EFFECTSLOT_EFFECT, effect );
1596
1597 al_checkErr();
1598 soundUnlock();
1599
1600 return 0;
1601}
1602
1603static LuaAudioEfx_t *audio_getEffectByName( const char *name )
1604{
1605 for (int i=0; i<array_size(lua_efx); i++)
1606 if (strcmp(name,lua_efx[i].name)==0)
1607 return &lua_efx[i];
1608 WARN(_("Unknown audio effect '%s'!"), name);
1609 return NULL;
1610}
1611
1623static int audioL_setEffect( lua_State *L )
1624{
1625 if (al_info.efx == AL_FALSE) {
1626 lua_pushboolean(L,1);
1627 return 1;
1628 }
1629
1630 /* Creating new effect. */
1631 if (!lua_isaudio(L,1))
1632 return audioL_setEffectGlobal(L);
1633
1634 LuaAudio_t *la = luaL_checkaudio(L,1);
1635 const char *name = luaL_checkstring(L,2);
1636 int enable = (lua_isnoneornil(L,3)) ? 1 : lua_toboolean(L,3);
1637
1638 soundLock();
1639 if (enable) {
1640 LuaAudioEfx_t *lae = audio_getEffectByName( name );
1641 if (lae == NULL) {
1642 soundUnlock();
1643 return 0;
1644 }
1645 /* TODO allow more effect slots. */
1646 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, lae->slot, 0, AL_FILTER_NULL );
1647 }
1648 else
1649 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL );
1650
1651 al_checkErr();
1652 soundUnlock();
1653
1654 lua_pushboolean(L,1);
1655 return 1;
1656}
1657
1664static int audioL_setGlobalEffect( lua_State *L )
1665{
1666 LuaAudioEfx_t *lae;
1667 const char *name = luaL_optstring(L,1,NULL);
1668
1669 if (sound_disabled)
1670 return 0;
1671
1672 if (al_info.efx == AL_FALSE)
1673 return 0;
1674
1675 /* Disable. */
1676 if (name==NULL) {
1677 soundLock();
1678 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL );
1679 al_checkErr();
1680 soundUnlock();
1681 return 0;
1682 }
1683
1684 /* Try to set it. */
1685 lae = audio_getEffectByName( name );
1686 if (lae == NULL)
1687 return 0;
1688
1689 /* Set the effect. */
1690 soundLock();
1691 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT, lae->effect );
1692 al_checkErr();
1693 soundUnlock();
1694 return 0;
1695}
1696
1704static int audioL_setGlobalAirAbsorption( lua_State *L )
1705{
1706 double speed = luaL_optnumber( L, 1, 3433. );
1707 double absorption = luaL_optnumber( L, 2, -1. );
1708
1709 if (sound_disabled)
1710 return 0;
1711
1712 soundLock();
1713 alSpeedOfSound( speed );
1714 if (absorption > 0.)
1715 sound_setAbsorption( absorption );
1716 al_checkErr();
1717 soundUnlock();
1718 return 0;
1719}
1720
1729static int audioL_setGlobaDopplerFactor( lua_State *L )
1730{
1731 if (sound_disabled)
1732 return 0;
1733
1734 soundLock();
1735 alDopplerFactor( luaL_checknumber(L,1) );
1736 al_checkErr();
1737 soundUnlock();
1738 return 0;
1739}
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.
Definition: nlua_audio.c:1298
static int audioL_clone(lua_State *L)
Clones an existing audio source.
Definition: nlua_audio.c:681
static int audioL_setGlobaDopplerFactor(lua_State *L)
Sets the doppler effect factor.
Definition: nlua_audio.c:1729
static int audioL_setRelative(lua_State *L)
Sets whether a source is relative or not.
Definition: nlua_audio.c:1082
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:738
static int audioL_setEffect(lua_State *L)
Sets effect stuff, behaves different if the first parameter is a source or not.
Definition: nlua_audio.c:1623
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.
Definition: nlua_audio.c:1704
static int audioL_setGlobalEffect(lua_State *L)
Sets a global effect. Will overwrite whatever was set. Does not affect sources created in Lua.
Definition: nlua_audio.c:1664
static int audioL_isLooping(lua_State *L)
Gets the looping state of a source.
Definition: nlua_audio.c:1238
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:865
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.
Definition: nlua_audio.c:1189
static int audioL_setVolume(lua_State *L)
Sets the volume of a source.
Definition: nlua_audio.c:1035
static int audioL_getRolloff(lua_State *L)
Gets the rolloff factor.
Definition: nlua_audio.c:1402
static int audioL_rewind(lua_State *L)
Rewinds a source.
Definition: nlua_audio.c:833
static int audioL_play(lua_State *L)
Plays a source.
Definition: nlua_audio.c:699
static int audioL_setRolloff(lua_State *L)
Sets the rollof factor.
Definition: nlua_audio.c:1383
static int audioL_setLooping(lua_State *L)
Sets a source to be looping or not.
Definition: nlua_audio.c:1218
static int audioL_setPosition(lua_State *L)
Sets the position of a source.
Definition: nlua_audio.c:1104
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:970
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:757
#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.
Definition: nlua_audio.c:1358
static int audioL_tell(lua_State *L)
Gets the position of a source.
Definition: nlua_audio.c:915
static int audioL_setPitch(lua_State *L)
Sets the pitch of a source.
Definition: nlua_audio.c:1250
static int audioL_getVolume(lua_State *L)
Gets the volume of a source.
Definition: nlua_audio.c:1063
static int audioL_new(lua_State *L)
Creates a new audio source.
Definition: nlua_audio.c:509
static int audioL_getPosition(lua_State *L)
Gets the position of a source.
Definition: nlua_audio.c:1131
static int audioL_isStopped(lua_State *L)
Checks to see if a source is stopped.
Definition: nlua_audio.c:822
static int audioL_getPitch(lua_State *L)
Gets the pitch of a source.
Definition: nlua_audio.c:1270
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.
Definition: nlua_audio.c:1336
static int audioL_setVelocity(lua_State *L)
Sets the velocity of a source.
Definition: nlua_audio.c:1162
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:768
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:84
int lua_isfile(lua_State *L, int ind)
Checks to see if ind is a file.
Definition: nlua_file.c:124
vec2 * luaL_checkvector(lua_State *L, int ind)
Gets vector at index making sure type is valid.
Definition: nlua_vec2.c:124
double sound_getVolumeLog(void)
Gets the current sound volume (logarithmic).
Definition: sound.c:1306
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
Definition: sound.c:2012
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition: sound.c:1293
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:835
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition: sound.c:764
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:797
Handles the OpenAL effects that have been set up Lua side.
Definition: nlua_audio.c:38
char * name
Definition: nlua_audio.c:39
ALuint slot
Definition: nlua_audio.c:41
ALuint effect
Definition: nlua_audio.c:40
LuaBuffer_t * buf
Definition: nlua_audio.h:39
OggVorbis_File stream
Definition: nlua_audio.h:43
SDL_Thread * th
Definition: nlua_audio.h:50
SDL_mutex * lock
Definition: nlua_audio.h:41
int nocleanup
Definition: nlua_audio.h:34
ALfloat rg_max_scale
Definition: nlua_audio.h:47
LuaAudioType_t type
Definition: nlua_audio.h:33
double volume
Definition: nlua_audio.h:37
SDL_cond * cond
Definition: nlua_audio.h:51
ALenum format
Definition: nlua_audio.h:45
ALuint stream_buffers[2]
Definition: nlua_audio.h:48
ALuint source
Definition: nlua_audio.h:35
vorbis_info * info
Definition: nlua_audio.h:44
ALfloat rg_scale_factor
Definition: nlua_audio.h:46
int active
Definition: nlua_audio.h:49
ALuint buffer
Definition: nlua_audio.h:25
int refcount
Definition: nlua_audio.h:26
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