naev 0.12.5
nlua_audio.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "physfsrwops.h"
11#include <lauxlib.h>
12
13#include "naev.h"
15
16#include "nlua_audio.h"
17
18#include "AL/efx.h"
19
20#include "array.h"
21#include "nlua_file.h"
22#include "nlua_vec2.h"
23#include "nluadef.h"
24#include "nopenal.h"
25#include "ntracing.h"
26#include "sound.h"
27
31typedef struct LuaAudioEfx_s {
32 char *name;
33 ALuint effect;
34 ALuint slot;
36
41static LuaAudioEfx_t *lua_efx = NULL;
42
43static int stream_thread( void *la_data );
44static int stream_loadBuffer( LuaAudio_t *la, ALuint buffer );
45static int audio_genSource( ALuint *source );
46
47/* Audio methods. */
48static int audioL_tostring( lua_State *L );
49static int audioL_gc( lua_State *L );
50static int audioL_eq( lua_State *L );
51static int audioL_new( lua_State *L );
52static int audioL_clone( lua_State *L );
53static int audioL_play( lua_State *L );
54static int audioL_pause( lua_State *L );
55static int audioL_isPaused( lua_State *L );
56static int audioL_stop( lua_State *L );
57static int audioL_isStopped( lua_State *L );
58static int audioL_rewind( lua_State *L );
59static int audioL_seek( lua_State *L );
60static int audioL_tell( lua_State *L );
61static int audioL_getDuration( lua_State *L );
62static int audioL_setVolume( lua_State *L );
63static int audioL_getVolume( lua_State *L );
64static int audioL_setRelative( lua_State *L );
65static int audioL_setPosition( lua_State *L );
66static int audioL_getPosition( lua_State *L );
67static int audioL_setVelocity( lua_State *L );
68static int audioL_getVelocity( lua_State *L );
69static int audioL_setLooping( lua_State *L );
70static int audioL_isLooping( lua_State *L );
71static int audioL_setPitch( lua_State *L );
72static int audioL_getPitch( lua_State *L );
73static int audioL_setAttenuationDistances( lua_State *L );
74static int audioL_getAttenuationDistances( lua_State *L );
75static int audioL_setRolloff( lua_State *L );
76static int audioL_getRolloff( lua_State *L );
77static int audioL_setEffect( lua_State *L );
78static int audioL_setGlobalEffect( lua_State *L );
79static int audioL_setGlobalAirAbsorption( lua_State *L );
80static int audioL_setGlobaDopplerFactor( lua_State *L );
81/* Deprecated stuff. */
82static int audioL_soundPlay( lua_State *L ); /* Obsolete API, to get rid of. */
83
84static const luaL_Reg audioL_methods[] = {
85 { "__tostring", audioL_tostring },
86 { "__gc", audioL_gc },
87 { "__eq", audioL_eq },
88 { "new", audioL_new },
89 { "clone", audioL_clone },
90 { "play", audioL_play },
91 { "pause", audioL_pause },
92 { "isPaused", audioL_isPaused },
93 { "stop", audioL_stop },
94 { "isStopped", audioL_isStopped },
95 { "rewind", audioL_rewind },
96 { "seek", audioL_seek },
97 { "tell", audioL_tell },
98 { "getDuration", audioL_getDuration },
99 { "setVolume", audioL_setVolume },
100 { "getVolume", audioL_getVolume },
101 { "setRelative", audioL_setRelative },
102 { "setPosition", audioL_setPosition },
103 { "getPosition", audioL_getPosition },
104 { "setVelocity", audioL_setVelocity },
105 { "getVelocity", audioL_getVelocity },
106 { "setLooping", audioL_setLooping },
107 { "isLooping", audioL_isLooping },
108 { "setPitch", audioL_setPitch },
109 { "getPitch", audioL_getPitch },
110 { "setAttenuationDistances", audioL_setAttenuationDistances },
111 { "getAttenuationDistances", audioL_getAttenuationDistances },
112 { "setRolloff", audioL_setRolloff },
113 { "getRolloff", audioL_getRolloff },
114 { "setEffect", audioL_setEffect },
115 { "setGlobalEffect", audioL_setGlobalEffect },
116 { "setGlobalAirAbsorption", audioL_setGlobalAirAbsorption },
117 { "setGlobalDopplerFactor", audioL_setGlobaDopplerFactor },
118 /* Deprecated. */
119 { "soundPlay", audioL_soundPlay }, /* Old API */
120 { 0, 0 } };
121
122static int stream_thread( void *la_data )
123{
124 LuaAudio_t *la = (LuaAudio_t *)la_data;
125
126 while ( 1 ) {
127 ALint alstate;
128 ALuint removed;
129
130 soundLock();
131
132 /* Case finished. */
133 if ( la->active < 0 ) {
134 la->th = NULL;
135 SDL_CondBroadcast( la->cond );
136 alSourceStop( la->source );
137 soundUnlock();
138 return 0;
139 }
140
141 alGetSourcei( la->source, AL_BUFFERS_PROCESSED, &alstate );
142 if ( alstate > 0 ) {
143 int ret;
144 /* Refill active buffer */
145 alSourceUnqueueBuffers( la->source, 1, &removed );
146 ret = stream_loadBuffer( la, la->stream_buffers[la->active] );
147 if ( ( la->active < 0 ) || ( ret < 0 ) ) {
148 /* stream_loadBuffer unlocks the sound lock internally, which can
149 * lead to the thread being gc'd and having active = -1. We have to
150 * add a check here to not mess around with stuff. */
151 la->th = NULL;
152 SDL_CondBroadcast( la->cond );
153 alSourceStop( la->source );
154 soundUnlock();
155 return 0;
156 } else {
157 alSourceQueueBuffers( la->source, 1,
158 &la->stream_buffers[la->active] );
159 la->active = 1 - la->active;
160 }
161 }
162 al_checkErr(); /* XXX - good or bad idea to log from the thread? */
163 soundUnlock();
164
165 SDL_Delay( 10 );
166 }
167}
168
174static int stream_loadBuffer( LuaAudio_t *la, ALuint buffer )
175{
176 int ret;
177 size_t size;
178 char buf[32 * 1024];
179
180 soundUnlock();
181 ret = 0;
182 size = 0;
183 while ( size < sizeof( buf ) ) { /* file up the entire data buffer */
184 int section, result;
185 rg_filter_param_t param = {
186 .rg_scale_factor = la->rg_scale_factor,
187 .rg_max_scale = la->rg_max_scale,
188 };
189
190 SDL_mutexP( la->lock );
191 result =
192 ov_read_filter( &la->stream, /* stream */
193 &buf[size], /* data */
194 sizeof( buf ) - size, /* amount to read */
195 ( SDL_BYTEORDER == SDL_BIG_ENDIAN ), 2, /* 16 bit */
196 1, /* signed */
197 &section, /* current bitstream */
198 rg_filter, /* filter function */
199 &param ); /* filter parameter */
200 SDL_mutexV( la->lock );
201
202 /* End of file. */
203 if ( result == 0 ) {
204 if ( size == 0 ) {
205 return -2;
206 }
207 ret = 1;
208 break;
209 }
210 /* Hole error. */
211 else if ( result == OV_HOLE ) {
212 WARN( _( "OGG: Vorbis hole detected in music!" ) );
213 return 0;
214 }
215 /* Bad link error. */
216 else if ( result == OV_EBADLINK ) {
217 WARN( _( "OGG: Invalid stream section or corrupt link in music!" ) );
218 return -1;
219 }
220
221 size += result;
222 }
223 soundLock();
224
225 /* load the buffer up */
226 alBufferData( buffer, la->format, buf, size, la->info->rate );
227 al_checkErr();
228
229 return ret;
230}
231
235static int audioL_isBool( lua_State *L, ALenum param )
236{
237 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
238 int b = 1;
239 if ( !sound_disabled ) {
240 soundLock();
241 alGetSourcei( la->source, param, &b );
242 al_checkErr();
243 soundUnlock();
244 }
245 lua_pushboolean( L, b );
246 return 1;
247}
248
252static int audioL_isState( lua_State *L, ALenum state )
253{
254 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
255 int s = AL_STOPPED;
256 if ( !sound_disabled ) {
257 soundLock();
258 alGetSourcei( la->source, AL_SOURCE_STATE, &s );
259 al_checkErr();
260 soundUnlock();
261 }
262 lua_pushboolean( L, s == state );
263 return 1;
264}
265
272int nlua_loadAudio( nlua_env env )
273{
274 nlua_register( env, AUDIO_METATABLE, audioL_methods, 1 );
275 return 0;
276}
277
285LuaAudio_t *lua_toaudio( lua_State *L, int ind )
286{
287 return (LuaAudio_t *)lua_touserdata( L, ind );
288}
289
296LuaAudio_t *luaL_checkaudio( lua_State *L, int ind )
297{
298 if ( lua_isaudio( L, ind ) )
299 return lua_toaudio( L, ind );
300 luaL_typerror( L, ind, AUDIO_METATABLE );
301 return NULL;
302}
303
310LuaAudio_t *lua_pushaudio( lua_State *L, LuaAudio_t audio )
311{
312 LuaAudio_t *la = (LuaAudio_t *)lua_newuserdata( L, sizeof( LuaAudio_t ) );
313 *la = audio;
314 luaL_getmetatable( L, AUDIO_METATABLE );
315 lua_setmetatable( L, -2 );
316 return la;
317}
318
325int lua_isaudio( lua_State *L, int ind )
326{
327 int ret;
328
329 if ( lua_getmetatable( L, ind ) == 0 )
330 return 0;
331 lua_getfield( L, LUA_REGISTRYINDEX, AUDIO_METATABLE );
332
333 ret = 0;
334 if ( lua_rawequal( L, -1, -2 ) ) /* does it have the correct mt? */
335 ret = 1;
336
337 lua_pop( L, 2 ); /* remove both metatables */
338 return ret;
339}
340
341void audio_cleanup( LuaAudio_t *la )
342{
343 if ( ( la == NULL ) || ( la->nocleanup ) )
344 return;
345
346 switch ( la->type ) {
347 case LUA_AUDIO_NULL:
348 break;
349 case LUA_AUDIO_STATIC:
350 soundLock();
351 if ( alIsSource( la->source ) == AL_TRUE )
352 alDeleteSources( 1, &la->source );
353 /* Check if buffers need freeing. */
354 if ( la->buf != NULL ) {
355 la->buf->refcount--;
356 if ( la->buf->refcount <= 0 ) {
357 alDeleteBuffers( 1, &la->buf->buffer );
358 nfree( la->buf );
359 }
360 }
361 al_checkErr();
362 soundUnlock();
363 break;
364
365 case LUA_AUDIO_STREAM:
366 soundLock();
367 if ( la->th != NULL ) {
368 la->active = -1;
369 if ( SDL_CondWaitTimeout( la->cond, sound_lock, 3000 ) ==
370 SDL_MUTEX_TIMEDOUT )
371 WARN( _( "Timed out while waiting for audio thread of '%s' to "
372 "finish!" ),
373 la->name );
374 }
375 if ( alIsSource( la->source ) == AL_TRUE )
376 alDeleteSources( 1, &la->source );
377 if ( alIsBuffer( la->stream_buffers[0] ) == AL_TRUE )
378 alDeleteBuffers( 2, la->stream_buffers );
379 if ( la->cond != NULL )
380 SDL_DestroyCond( la->cond );
381 if ( la->lock != NULL )
382 SDL_DestroyMutex( la->lock );
383 ov_clear( &la->stream );
384 al_checkErr();
385 soundUnlock();
386 break;
387 }
388
389 free( la->name );
390}
391
404static int audioL_tostring( lua_State *L )
405{
406 char buf[STRMAX_SHORT];
407 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
408 snprintf( buf, sizeof( buf ), "Audio( %s )", la->name );
409 lua_pushstring( L, buf );
410 return 1;
411}
412
418static int audioL_gc( lua_State *L )
419{
420 LuaAudio_t *la = luaL_checkaudio( L, 1 );
421 audio_cleanup( la );
422 return 0;
423}
424
433static int audioL_eq( lua_State *L )
434{
435 LuaAudio_t *a1, *a2;
436 a1 = luaL_checkaudio( L, 1 );
437 a2 = luaL_checkaudio( L, 2 );
438 lua_pushboolean( L, ( memcmp( a1, a2, sizeof( LuaAudio_t ) ) == 0 ) );
439 return 1;
440}
441
445static int audio_genSource( ALuint *source )
446{
447 ALenum err;
448 alGenSources( 1, source );
449 if ( alIsSource( *source ) == AL_TRUE )
450 return 0;
451 err = alGetError();
452 switch ( err ) {
453 case AL_NO_ERROR:
454 break;
455 case AL_OUT_OF_MEMORY:
456 /* Assume that we need to collect audio stuff. */
457 soundUnlock();
458 lua_gc( naevL, LUA_GCCOLLECT, 0 );
459 soundLock();
460 /* Try to create source again. */
461 alGenSources( 1, source );
462 if ( alIsSource( *source ) == AL_TRUE )
463 return 0;
464 al_checkErr();
465 break;
466
467 default:
468#if DEBUGGING
469 al_checkHandleError( err, __func__, __LINE__ );
470#endif /* DEBUGGING */
471 break;
472 }
473 return -1;
474}
475
485static int audioL_new( lua_State *L )
486{
487 LuaAudio_t la;
488 LuaFile_t *lf;
489 double master;
490 int stream;
491 const char *name;
492 SDL_RWops *rw;
493
494 /* First parameter. */
495 if ( lua_isstring( L, 1 ) )
496 name = lua_tostring( L, 1 );
497 else if ( lua_isfile( L, 1 ) ) {
498 lf = lua_tofile( L, 1 );
499 name = lf->path;
500 } else
501 NLUA_INVALID_PARAMETER( L, 1 );
502
503 /* Second parameter. */
504 if ( lua_isnoneornil( L, 2 ) ) {
505 stream = 0;
506 } else {
507 const char *type = luaL_optstring( L, 2, "static" );
508 if ( strcmp( type, "static" ) == 0 )
509 stream = 0;
510 else if ( strcmp( type, "stream" ) == 0 )
511 stream = 1;
512 else
513 NLUA_INVALID_PARAMETER( L, 2 );
514 }
515
516 memset( &la, 0, sizeof( LuaAudio_t ) );
517 if ( sound_disabled ) {
518 la.nocleanup = 1; /* Not initialized so no need to clean up. */
519 lua_pushaudio( L, la );
520 return 1;
521 }
522 rw = PHYSFSRWOPS_openRead( name );
523 if ( rw == NULL )
524 return NLUA_ERROR( L, "Unable to open '%s'", name );
525 la.name = strdup( name );
526
527 soundLock();
528 la.ok = audio_genSource( &la.source );
529 if ( la.ok ) {
530 SDL_RWclose( rw ); /* Clean up. */
531 la.nocleanup = 1; /* Not initialized so no need to clean up. */
532 lua_pushaudio( L, la );
533 return 1;
534 }
535
536 /* Deal with stream. */
537 if ( !stream ) {
538 la.type = LUA_AUDIO_STATIC;
539 la.buf = nmalloc( sizeof( LuaBuffer_t ) );
540 la.buf->refcount = 1;
541 sound_al_buffer( &la.buf->buffer, rw, name );
542
543 /* Attach buffer. */
544 alSourcei( la.source, AL_BUFFER, la.buf->buffer );
545
546 /* Clean up. */
547 SDL_RWclose( rw );
548 } else {
549 vorbis_comment *vc;
550 ALfloat track_gain_db, track_peak;
551 char *tag;
552
553 la.type = LUA_AUDIO_STREAM;
554 /* ov_clear will close rw for us. */
555 if ( ov_open_callbacks( rw, &la.stream, NULL, 0, sound_al_ovcall ) < 0 ) {
556 SDL_RWclose( rw );
557 return NLUA_ERROR(
558 L, _( "Audio '%s' does not appear to be a Vorbis bitstream." ),
559 name );
560 }
561 la.info = ov_info( &la.stream, -1 );
562
563 /* Replaygain information. */
564 vc = ov_comment( &la.stream, -1 );
565 track_gain_db = 0.;
566 track_peak = 1.;
567 if ( ( tag = vorbis_comment_query( vc, "replaygain_track_gain", 0 ) ) )
568 track_gain_db = atof( tag );
569 if ( ( tag = vorbis_comment_query( vc, "replaygain_track_peak", 0 ) ) )
570 track_peak = atof( tag );
571 la.rg_scale_factor = pow( 10.0, ( track_gain_db + RG_PREAMP_DB ) / 20.0 );
572 la.rg_max_scale = 1.0 / track_peak;
573
574 /* Set the format */
575 if ( la.info->channels == 1 )
576 la.format = AL_FORMAT_MONO16;
577 else
578 la.format = AL_FORMAT_STEREO16;
579
580 la.active = 0;
581 la.lock = SDL_CreateMutex();
582 la.cond = SDL_CreateCond();
583 alGenBuffers( 2, la.stream_buffers );
584 /* Buffers get queued later. */
585 }
586
587 /* Defaults. */
588 la.volume = 1.;
589 master = sound_getVolumeLog();
590 alSourcef( la.source, AL_GAIN, master );
591 /* The behaviour of sources depends on whether or not they are mono or
592 * stereo. In the case they are stereo, no position stuff is actually
593 * done. However, if they are mono, they are played with absolute
594 * position and the sound heard depends on the listener. We can disable
595 * this by setting AL_SOURCE_RELATIVE which puts the listener always at
596 * the origin, and then setting the source at the same origin. It should
597 * be noted that depending on the sound model this can be bad if it is
598 * not bounded. */
599 alSourcei( la.source, AL_SOURCE_RELATIVE, AL_TRUE );
600 alSource3f( la.source, AL_POSITION, 0., 0., 0. );
601 al_checkErr();
602 soundUnlock();
603
604 lua_pushaudio( L, la );
605 return 1;
606}
607
608void audio_clone( LuaAudio_t *la, const LuaAudio_t *source )
609{
610 double master;
611
612 memset( la, 0, sizeof( LuaAudio_t ) );
613 if ( sound_disabled || source->ok ) {
614 la->nocleanup = 1;
615 return;
616 }
617
618 soundLock();
619 la->ok = audio_genSource( &la->source );
620 if ( la->ok ) {
621 la->nocleanup = 1;
622 return;
623 }
624
625 switch ( source->type ) {
626 case LUA_AUDIO_STATIC:
627 /* Attach source buffer. */
628 la->buf = source->buf;
629 la->buf->refcount++;
630
631 /* Attach buffer. */
632 alSourcei( la->source, AL_BUFFER, la->buf->buffer );
633 break;
634
635 case LUA_AUDIO_STREAM:
636 WARN( _( "Unimplemented" ) );
637 break;
638
639 case LUA_AUDIO_NULL:
640 break;
641 }
642 la->type = source->type;
643
644 /* TODO this should probably set the same parameters as the original source
645 * being cloned to be truly compatible with Love2D. */
646 /* Defaults. */
647 master = sound_getVolumeLog();
648 alSourcef( la->source, AL_GAIN, master * source->volume );
649 la->volume = source->volume;
650 /* See note in audioL_new */
651 alSourcei( la->source, AL_SOURCE_RELATIVE, AL_TRUE );
652 alSource3f( la->source, AL_POSITION, 0., 0., 0. );
653 al_checkErr();
654 soundUnlock();
655}
656
664static int audioL_clone( lua_State *L )
665{
666 LuaAudio_t la;
667 const LuaAudio_t *source = luaL_checkaudio( L, 1 );
668 audio_clone( &la, source );
669 lua_pushaudio( L, la );
670 return 1;
671}
672
680static int audioL_play( lua_State *L )
681{
682 LuaAudio_t *la = luaL_checkaudio( L, 1 );
683 if ( sound_disabled || la->ok )
684 return 0;
685
686 if ( ( la->type == LUA_AUDIO_STREAM ) && ( la->th == NULL ) ) {
687 int ret = 0;
688 ALint alstate;
689 soundLock();
690 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
691 while ( alstate < 2 ) {
692 ret = stream_loadBuffer( la, la->stream_buffers[la->active] );
693 if ( ret < 0 )
694 break;
695 alSourceQueueBuffers( la->source, 1, &la->stream_buffers[la->active] );
696 la->active = 1 - la->active;
697 alGetSourcei( la->source, AL_BUFFERS_QUEUED, &alstate );
698 }
699 if ( ret == 0 )
700 la->th = SDL_CreateThread( stream_thread, "stream_thread", la );
701 } else
702 soundLock();
703 alSourcePlay( la->source );
704 al_checkErr();
705 soundUnlock();
706
707 lua_pushboolean( L, 1 );
708 return 1;
709}
710
718static int audioL_pause( lua_State *L )
719{
720 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
721 if ( sound_disabled || la->ok )
722 return 0;
723 soundLock();
724 alSourcePause( la->source );
725 al_checkErr();
726 soundUnlock();
727 return 0;
728}
729
737static int audioL_isPaused( lua_State *L )
738{
739 return audioL_isState( L, AL_PAUSED );
740}
741
748static int audioL_stop( lua_State *L )
749{
750 ALint alstate;
751 ALuint removed[2];
752 LuaAudio_t *la = luaL_checkaudio( L, 1 );
753 if ( sound_disabled || la->ok )
754 return 0;
755
756 soundLock();
757 switch ( la->type ) {
758 case LUA_AUDIO_NULL:
759 break;
760 case LUA_AUDIO_STATIC:
761 alSourceStop( la->source );
762 break;
763
764 case LUA_AUDIO_STREAM:
765 /* Kill the thread first. */
766 if ( la->th != NULL ) {
767 la->active = -1;
768 if ( SDL_CondWaitTimeout( la->cond, sound_lock, 3000 ) ==
769 SDL_MUTEX_TIMEDOUT )
770 WARN( _( "Timed out while waiting for audio thread of '%s' to "
771 "finish!" ),
772 la->name );
773 }
774 la->th = NULL;
775
776 /* Stopping a source will make all buffers become processed. */
777 alSourceStop( la->source );
778
779 /* Unqueue the buffers. */
780 alGetSourcei( la->source, AL_BUFFERS_PROCESSED, &alstate );
781 alSourceUnqueueBuffers( la->source, alstate, removed );
782
783 /* Seek the stream to the beginning. */
784 SDL_mutexP( la->lock );
785 ov_pcm_seek( &la->stream, 0 );
786 SDL_mutexV( la->lock );
787 break;
788 }
789 al_checkErr();
790 soundUnlock();
791 return 0;
792}
793
801static int audioL_isStopped( lua_State *L )
802{
803 return audioL_isState( L, AL_STOPPED );
804}
805
812static int audioL_rewind( lua_State *L )
813{
814 LuaAudio_t *la = luaL_checkaudio( L, 1 );
815 if ( sound_disabled || la->ok )
816 return 0;
817
818 switch ( la->source ) {
819 case LUA_AUDIO_STATIC:
820 soundLock();
821 alSourceRewind( la->source );
822 al_checkErr();
823 soundUnlock();
824 break;
825 case LUA_AUDIO_STREAM:
826 SDL_mutexP( la->lock );
827 ov_raw_seek( &la->stream, 0 );
828 SDL_mutexV( la->lock );
829 break;
830 case LUA_AUDIO_NULL:
831 break;
832 }
833 return 0;
834}
835
845static int audioL_seek( lua_State *L )
846{
847 LuaAudio_t *la = luaL_checkaudio( L, 1 );
848 double offset = luaL_checknumber( L, 2 );
849 const char *unit = luaL_optstring( L, 3, "seconds" );
850 int seconds = 1;
851
852 if ( strcmp( unit, "samples" ) == 0 )
853 seconds = 0;
854 else if ( strcmp( unit, "seconds" ) != 0 )
855 return NLUA_ERROR( L,
856 _( "Unknown seek source '%s'! Should be either "
857 "'seconds' or 'samples'!" ),
858 unit );
859
860 if ( sound_disabled || la->ok )
861 return 0;
862
863 switch ( la->type ) {
864 case LUA_AUDIO_STATIC:
865 soundLock();
866 if ( seconds )
867 alSourcef( la->source, AL_SEC_OFFSET, offset );
868 else
869 alSourcef( la->source, AL_SAMPLE_OFFSET, offset );
870 al_checkErr();
871 soundUnlock();
872 break;
873
874 case LUA_AUDIO_STREAM:
875 SDL_mutexP( la->lock );
876 if ( seconds )
877 ov_time_seek( &la->stream, offset );
878 else
879 ov_pcm_seek( &la->stream, offset );
880 SDL_mutexV( la->lock );
881 /* TODO force a reset of the buffers. */
882 break;
883
884 case LUA_AUDIO_NULL:
885 break;
886 }
887 return 0;
888}
889
899static int audioL_tell( lua_State *L )
900{
901 LuaAudio_t *la = luaL_checkaudio( L, 1 );
902 const char *unit = luaL_optstring( L, 2, "seconds" );
903 double offset = -1.;
904 float aloffset;
905 int seconds = 1;
906
907 if ( strcmp( unit, "samples" ) == 0 )
908 seconds = 0;
909 else if ( strcmp( unit, "seconds" ) != 0 )
910 return NLUA_ERROR( L,
911 _( "Unknown seek source '%s'! Should be either "
912 "'seconds' or 'samples'!" ),
913 unit );
914
915 if ( sound_disabled || la->ok ) {
916 lua_pushnumber( L, -1. );
917 return 1;
918 }
919
920 switch ( la->type ) {
921 case LUA_AUDIO_STATIC:
922 soundLock();
923 if ( seconds )
924 alGetSourcef( la->source, AL_SEC_OFFSET, &aloffset );
925 else
926 alGetSourcef( la->source, AL_SAMPLE_OFFSET, &aloffset );
927 offset = aloffset;
928 al_checkErr();
929 soundUnlock();
930 break;
931
932 case LUA_AUDIO_STREAM:
933 SDL_mutexP( la->lock );
934 if ( seconds )
935 offset = ov_time_tell( &la->stream );
936 else
937 offset = ov_pcm_tell( &la->stream );
938 SDL_mutexV( la->lock );
939 break;
940
941 case LUA_AUDIO_NULL:
942 break;
943 }
944
945 lua_pushnumber( L, offset );
946 return 1;
947}
948
958static int audioL_getDuration( lua_State *L )
959{
960 LuaAudio_t *la = luaL_checkaudio( L, 1 );
961 const char *unit = luaL_optstring( L, 2, "seconds" );
962 float duration = -1.;
963 int seconds = 1;
964 ALint bytes, channels, bits, samples;
965 ALuint buffer;
966
967 if ( strcmp( unit, "samples" ) == 0 )
968 seconds = 0;
969 else if ( strcmp( unit, "seconds" ) != 0 )
970 return NLUA_ERROR( L,
971 _( "Unknown duration source '%s'! Should be either "
972 "'seconds' or 'samples'!" ),
973 unit );
974
975 if ( sound_disabled || la->ok ) {
976 lua_pushnumber( L, -1. );
977 return 1;
978 }
979
980 switch ( la->type ) {
981 case LUA_AUDIO_STATIC:
982 soundLock();
983 buffer = la->buf->buffer;
984 alGetBufferi( buffer, AL_SIZE, &bytes );
985 alGetBufferi( buffer, AL_CHANNELS, &channels );
986 alGetBufferi( buffer, AL_BITS, &bits );
987
988 samples = bytes * 8 / ( channels * bits );
989
990 if ( seconds ) {
991 ALint freq;
992 alGetBufferi( buffer, AL_FREQUENCY, &freq );
993 duration = (float)samples / (float)freq;
994 } else
995 duration = samples;
996 al_checkErr();
997 soundUnlock();
998 break;
999
1000 case LUA_AUDIO_STREAM:
1001 SDL_mutexP( la->lock );
1002 if ( seconds )
1003 duration = ov_time_total( &la->stream, -1 );
1004 else
1005 duration = ov_pcm_total( &la->stream, -1 );
1006 SDL_mutexV( la->lock );
1007 break;
1008
1009 case LUA_AUDIO_NULL:
1010 break;
1011 }
1012
1013 lua_pushnumber( L, duration );
1014 return 1;
1015}
1016
1026static int audioL_setVolume( lua_State *L )
1027{
1028 LuaAudio_t *la = luaL_checkaudio( L, 1 );
1029 double volume = CLAMP( 0.0, 1.0, luaL_checknumber( L, 2 ) );
1030 int ignorevol = lua_toboolean( L, 3 );
1031 if ( sound_disabled || la->ok )
1032 return 0;
1033
1034 soundLock();
1035 if ( ignorevol )
1036 alSourcef( la->source, AL_GAIN, volume );
1037 else {
1038 double master = sound_getVolumeLog();
1039 alSourcef( la->source, AL_GAIN, master * volume );
1040 }
1041 al_checkErr();
1042 soundUnlock();
1043 la->volume = volume;
1044 return 0;
1045}
1046
1054static int audioL_getVolume( lua_State *L )
1055{
1056 double volume;
1057 if ( sound_disabled )
1058 volume = 0.;
1059 else if ( lua_gettop( L ) > 0 )
1060 volume = luaL_checkaudio( L, 1 )->volume;
1061 else
1062 volume = sound_getVolume();
1063 lua_pushnumber( L, volume );
1064 return 1;
1065}
1066
1074static int audioL_setRelative( lua_State *L )
1075{
1076 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1077 if ( sound_disabled || la->ok )
1078 return 0;
1079
1080 soundLock();
1081 alSourcei( la->source, AL_SOURCE_RELATIVE, lua_toboolean( L, 2 ) );
1082 al_checkErr();
1083 soundUnlock();
1084 return 0;
1085}
1086
1096static int audioL_setPosition( lua_State *L )
1097{
1098 ALfloat pos[3];
1099 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1100 if ( sound_disabled || la->ok )
1101 return 0;
1102
1103 pos[0] = luaL_optnumber( L, 2, 0. );
1104 pos[1] = luaL_optnumber( L, 3, 0. );
1105 pos[2] = luaL_optnumber( L, 4, 0. );
1106
1107 soundLock();
1108 alSourcefv( la->source, AL_POSITION, pos );
1109 al_checkErr();
1110 soundUnlock();
1111 return 0;
1112}
1113
1123static int audioL_getPosition( lua_State *L )
1124{
1125 ALfloat pos[3];
1126 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1127 if ( sound_disabled || la->ok ) {
1128 lua_pushnumber( L, 0. );
1129 lua_pushnumber( L, 0. );
1130 lua_pushnumber( L, 0. );
1131 return 0;
1132 }
1133
1134 soundLock();
1135 alGetSource3f( la->source, AL_POSITION, &pos[0], &pos[1], &pos[2] );
1136 al_checkErr();
1137 soundUnlock();
1138
1139 lua_pushnumber( L, pos[0] );
1140 lua_pushnumber( L, pos[1] );
1141 lua_pushnumber( L, pos[2] );
1142 return 3;
1143}
1144
1154static int audioL_setVelocity( lua_State *L )
1155{
1156 ALfloat vel[3];
1157 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1158 if ( sound_disabled || la->ok )
1159 return 0;
1160
1161 vel[0] = luaL_optnumber( L, 2, 0. );
1162 vel[1] = luaL_optnumber( L, 3, 0. );
1163 vel[2] = luaL_optnumber( L, 4, 0. );
1164
1165 soundLock();
1166 alSourcefv( la->source, AL_VELOCITY, vel );
1167 al_checkErr();
1168 soundUnlock();
1169 return 0;
1170}
1171
1181static int audioL_getVelocity( lua_State *L )
1182{
1183 ALfloat vel[3];
1184 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1185 if ( sound_disabled || la->ok ) {
1186 lua_pushnumber( L, 0. );
1187 lua_pushnumber( L, 0. );
1188 lua_pushnumber( L, 0. );
1189 return 0;
1190 }
1191
1192 soundLock();
1193 alGetSource3f( la->source, AL_VELOCITY, &vel[0], &vel[1], &vel[2] );
1194 al_checkErr();
1195 soundUnlock();
1196
1197 lua_pushnumber( L, vel[0] );
1198 lua_pushnumber( L, vel[1] );
1199 lua_pushnumber( L, vel[2] );
1200 return 3;
1201}
1202
1211static int audioL_setLooping( lua_State *L )
1212{
1213 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1214 int b = lua_toboolean( L, 2 );
1215 if ( sound_disabled || la->ok )
1216 return 0;
1217 soundLock();
1218 alSourcei( la->source, AL_LOOPING, b );
1219 al_checkErr();
1220 soundUnlock();
1221 return 0;
1222}
1223
1231static int audioL_isLooping( lua_State *L )
1232{
1233 return audioL_isBool( L, AL_LOOPING );
1234}
1235
1243static int audioL_setPitch( lua_State *L )
1244{
1245 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1246 double pitch = luaL_checknumber( L, 2 );
1247 if ( sound_disabled || la->ok )
1248 return 0;
1249 soundLock();
1250 alSourcef( la->source, AL_PITCH, pitch );
1251 al_checkErr();
1252 soundUnlock();
1253 return 0;
1254}
1255
1263static int audioL_getPitch( lua_State *L )
1264{
1265 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1266 float p = 1.0;
1267 if ( !sound_disabled && !la->ok ) {
1268 soundLock();
1269 alGetSourcef( la->source, AL_PITCH, &p );
1270 al_checkErr();
1271 soundUnlock();
1272 }
1273 lua_pushnumber( L, p );
1274 return 1;
1275}
1276
1292static int audioL_soundPlay( lua_State *L )
1293{
1294 const char *name;
1295 vec2 *pos, *vel, vel0;
1296 int dopos;
1297
1298 /* Flag whether to use sound_playPos or sound_play. */
1299 dopos = 0;
1300
1301 /* Handle parameters. */
1302 name = luaL_checkstring( L, 1 );
1303 if ( lua_gettop( L ) > 1 ) {
1304 dopos = 1;
1305 pos = luaL_checkvector( L, 2 );
1306 if ( lua_gettop( L ) > 2 ) {
1307 vel = luaL_checkvector( L, 3 );
1308 } else {
1309 vectnull( &vel0 );
1310 vel = &vel0;
1311 }
1312 }
1313
1314 if ( dopos )
1315 sound_playPos( sound_get( name ), pos->x, pos->y, vel->x, vel->y );
1316 else
1317 sound_play( sound_get( name ) );
1318
1319 return 0;
1320}
1321
1329static int audioL_setAttenuationDistances( lua_State *L )
1330{
1331 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1332 double ref = luaL_checknumber( L, 2 );
1333 double max = luaL_checknumber( L, 3 );
1334 if ( sound_disabled || la->ok )
1335 return 0;
1336 soundLock();
1337 alSourcef( la->source, AL_REFERENCE_DISTANCE, ref );
1338 alSourcef( la->source, AL_MAX_DISTANCE, max );
1339 al_checkErr();
1340 soundUnlock();
1341 return 0;
1342}
1343
1352static int audioL_getAttenuationDistances( lua_State *L )
1353{
1354 ALfloat ref, max;
1355 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1356 if ( sound_disabled || la->ok ) {
1357 lua_pushnumber( L, 0. );
1358 lua_pushnumber( L, 0. );
1359 return 2;
1360 }
1361 soundLock();
1362 alGetSourcef( la->source, AL_REFERENCE_DISTANCE, &ref );
1363 alGetSourcef( la->source, AL_MAX_DISTANCE, &max );
1364 al_checkErr();
1365 soundUnlock();
1366 lua_pushnumber( L, ref );
1367 lua_pushnumber( L, max );
1368 return 2;
1369}
1370
1377static int audioL_setRolloff( lua_State *L )
1378{
1379 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1380 double rolloff = luaL_checknumber( L, 2 );
1381 if ( sound_disabled || la->ok )
1382 return 0;
1383 soundLock();
1384 alSourcef( la->source, AL_ROLLOFF_FACTOR, rolloff );
1385 al_checkErr();
1386 soundUnlock();
1387 return 0;
1388}
1389
1396static int audioL_getRolloff( lua_State *L )
1397{
1398 ALfloat rolloff;
1399 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1400 if ( sound_disabled || la->ok ) {
1401 lua_pushnumber( L, 0. );
1402 return 1;
1403 }
1404 soundLock();
1405 alGetSourcef( la->source, AL_ROLLOFF_FACTOR, &rolloff );
1406 al_checkErr();
1407 soundUnlock();
1408 lua_pushnumber( L, rolloff );
1409 return 1;
1410}
1411
1412static void efx_setnum( lua_State *L, int pos, ALuint effect, const char *name,
1413 ALuint param )
1414{
1415 lua_getfield( L, pos, name );
1416 if ( !lua_isnil( L, -1 ) )
1417 nalEffectf( effect, param, luaL_checknumber( L, -1 ) );
1418 lua_pop( L, 1 );
1419}
1420static void efx_setint( lua_State *L, int pos, ALuint effect, const char *name,
1421 ALuint param )
1422{
1423 lua_getfield( L, pos, name );
1424 if ( !lua_isnil( L, -1 ) )
1425 nalEffecti( effect, param, luaL_checkinteger( L, -1 ) );
1426 lua_pop( L, 1 );
1427}
1428static void efx_setbool( lua_State *L, int pos, ALuint effect, const char *name,
1429 ALuint param )
1430{
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 } else {
1478 effect = lae->effect;
1479 slot = lae->slot;
1480 }
1481
1482 /* Handle types. */
1483 if ( strcmp( type, "reverb" ) == 0 ) {
1484 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB );
1485
1486 efx_setnum( L, p, effect, "density",
1487 AL_REVERB_DENSITY ); /* 0.0 to 1.0 (1.0) */
1488 efx_setnum( L, p, effect, "diffusion",
1489 AL_REVERB_DIFFUSION ); /* 0.0 to 1.0 (1.0) */
1490 efx_setnum( L, p, effect, "gain",
1491 AL_REVERB_GAIN ); /* 0.0 to 1.0 (0.32) */
1492 efx_setnum( L, p, effect, "highgain",
1493 AL_REVERB_GAINHF ); /* 0.0 to 1.0 (0.89) */
1494 efx_setnum( L, p, effect, "decaytime",
1495 AL_REVERB_DECAY_TIME ); /* 0.1 to 20.0 (1.49) */
1496 efx_setnum( L, p, effect, "decayhighratio",
1497 AL_REVERB_DECAY_HFRATIO ); /* 0.1 to 2.0 (0.83) */
1498 efx_setnum( L, p, effect, "earlygain",
1499 AL_REVERB_REFLECTIONS_GAIN ); /* 0.0 to 3.16 (0.05) */
1500 efx_setnum( L, p, effect, "earlydelay",
1501 AL_REVERB_REFLECTIONS_DELAY ); /* 0.0 to 0.3 (0.007) */
1502 efx_setnum( L, p, effect, "lategain",
1503 AL_REVERB_LATE_REVERB_GAIN ); /* 0.0 to 10.0 (1.26) */
1504 efx_setnum( L, p, effect, "latedelay",
1505 AL_REVERB_LATE_REVERB_DELAY ); /* 0.0 to 0.1 (0.011) */
1506 efx_setnum( L, p, effect, "roomrolloff",
1507 AL_REVERB_ROOM_ROLLOFF_FACTOR ); /* 0.0 to 10.0 (0.0) */
1508 efx_setnum( L, p, effect, "airabsorption",
1509 AL_REVERB_AIR_ABSORPTION_GAINHF ); /* 0.892 to 1.0 (0.994) */
1510 efx_setbool(
1511 L, p, effect, "highlimit",
1512 AL_REVERB_DECAY_HFLIMIT ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1513 } else if ( strcmp( type, "distortion" ) == 0 ) {
1514 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION );
1515
1516 efx_setnum( L, p, effect, "gain",
1517 AL_DISTORTION_GAIN ); /* 0.01 to 1.0 (0.2) */
1518 efx_setnum( L, p, effect, "edge",
1519 AL_DISTORTION_EDGE ); /* 0.0 to 1.0 (0.05) */
1520 efx_setnum( L, p, effect, "lowcut",
1521 AL_DISTORTION_LOWPASS_CUTOFF ); /* 80.0 to 24000.0 (8000.0) */
1522 efx_setnum( L, p, effect, "center",
1523 AL_DISTORTION_EQCENTER ); /* 80.0 to 24000.0 (3600.0) */
1524 efx_setnum( L, p, effect, "bandwidth",
1525 AL_DISTORTION_EQBANDWIDTH ); /* 80.0 to 24000.0 (3600.0) */
1526 } else if ( strcmp( type, "chorus" ) == 0 ) {
1527 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS );
1528
1529 efx_setint( L, p, effect, "waveform",
1530 AL_CHORUS_WAVEFORM ); /* 0=sin, 1=triangle (1) */
1531 efx_setint( L, p, effect, "phase",
1532 AL_CHORUS_PHASE ); /* -180 to 180 (90) */
1533 efx_setnum( L, p, effect, "rate",
1534 AL_CHORUS_RATE ); /* 0.0 to 10.0 (1.1) */
1535 efx_setnum( L, p, effect, "depth",
1536 AL_CHORUS_DEPTH ); /* 0.0 to 1.0 (0.1) */
1537 efx_setnum( L, p, effect, "feedback",
1538 AL_CHORUS_FEEDBACK ); /* -1.0 to 1.0 (0.25) */
1539 efx_setnum( L, p, effect, "delay",
1540 AL_CHORUS_DELAY ); /* 0.0 to 0.016 (0.016) */
1541 } else if ( strcmp( type, "compressor" ) == 0 ) {
1542 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR );
1543
1544 efx_setbool( L, p, effect, "enable",
1545 AL_COMPRESSOR_ONOFF ); /* AL_FALSE or AL_TRUE (AL_TRUE) */
1546 } else if ( strcmp( type, "echo" ) == 0 ) {
1547 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO );
1548
1549 efx_setnum( L, p, effect, "delay",
1550 AL_ECHO_DELAY ); /* 0.0 to 0.207 (0.1) */
1551 efx_setnum( L, p, effect, "tapdelay",
1552 AL_ECHO_LRDELAY ); /* 0.0 to 0.404 (0.1) */
1553 efx_setnum( L, p, effect, "damping",
1554 AL_ECHO_DAMPING ); /* 0.0 to 0.99 (0.5) */
1555 efx_setnum( L, p, effect, "feedback",
1556 AL_ECHO_FEEDBACK ); /* 0.0 to 1.0 (0.5) */
1557 efx_setnum( L, p, effect, "spread",
1558 AL_ECHO_SPREAD ); /* -1.0 to 1.0 (-1.0) */
1559 } else if ( strcmp( type, "ringmodulator" ) == 0 ) {
1560 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR );
1561
1562 efx_setnum( L, p, effect, "frequency",
1563 AL_RING_MODULATOR_FREQUENCY ); /* 0.0 to 8000.0 (440.0) */
1564 efx_setnum(
1565 L, p, effect, "highcut",
1566 AL_RING_MODULATOR_HIGHPASS_CUTOFF ); /* 0.0 to 24000.0 (800.0) */
1567 efx_setint( L, p, effect, "waveform",
1568 AL_RING_MODULATOR_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square)
1569 (0 (sin)) */
1570 } else if ( strcmp( type, "equalizer" ) == 0 ) {
1571 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER );
1572
1573 efx_setnum( L, p, effect, "lowgain",
1574 AL_EQUALIZER_LOW_GAIN ); /* 0.126 to 7.943 (1.0) */
1575 efx_setnum( L, p, effect, "lowcut",
1576 AL_EQUALIZER_LOW_CUTOFF ); /* 50.0 to 800.0 (200.0) */
1577 efx_setnum( L, p, effect, "lowmidgain",
1578 AL_EQUALIZER_MID1_GAIN ); /* 0.126 to 7.943 (1.0) */
1579 efx_setnum( L, p, effect, "lowmidfrequency",
1580 AL_EQUALIZER_MID1_CENTER ); /* 200.0 to 3000.0 (500.0) */
1581 efx_setnum( L, p, effect, "lowmidbandwidth",
1582 AL_EQUALIZER_MID1_WIDTH ); /* 0.01 to 1.0 (1.0) */
1583 efx_setnum( L, p, effect, "highmidgain",
1584 AL_EQUALIZER_MID2_GAIN ); /* 0.126 to 7.943 (1.0) */
1585 efx_setnum( L, p, effect, "highmidfrequency",
1586 AL_EQUALIZER_MID2_CENTER ); /* 1000.0 to 8000.0 (3000.0) */
1587 efx_setnum( L, p, effect, "highmidbandwidth",
1588 AL_EQUALIZER_MID2_WIDTH ); /* 0.01 to 1.0 (1.0) */
1589 efx_setnum( L, p, effect, "highgain",
1590 AL_EQUALIZER_HIGH_GAIN ); /* 0.126 to 7.943 (1.0) */
1591 efx_setnum( L, p, effect, "highcut",
1592 AL_EQUALIZER_HIGH_CUTOFF ); /* 4000.0 to 16000.0 (6000.0) */
1593 } else if ( strcmp( type, "pitchshifter" ) == 0 ) {
1594 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER );
1595
1596 efx_setint( L, p, effect, "tunecoarse",
1597 AL_PITCH_SHIFTER_COARSE_TUNE ); /* -12 to 12 (12) */
1598 efx_setint( L, p, effect, "tunefine'",
1599 AL_PITCH_SHIFTER_FINE_TUNE ); /* -50 to 50 (0) */
1600 } else if ( strcmp( type, "vocalmorpher" ) == 0 ) {
1601 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER );
1602
1603 efx_setint( L, p, effect, "phonemea",
1604 AL_VOCAL_MORPHER_PHONEMEA ); /* 0 to 29 (0 ("A")) */
1605 efx_setint( L, p, effect, "phonemeb",
1606 AL_VOCAL_MORPHER_PHONEMEB ); /* 0 to 29 (10 ("ER")) */
1607 efx_setint( L, p, effect, "tunecoarsea",
1608 AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING ); /* -24 to 24 (0) */
1609 efx_setint( L, p, effect, "tunecoarseb",
1610 AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING ); /* -24 to 24 (0) */
1611 efx_setint( L, p, effect, "waveform",
1612 AL_VOCAL_MORPHER_WAVEFORM ); /* 0 (sin), 1 (saw), 2 (square)
1613 (0 (sin)) */
1614 efx_setnum( L, p, effect, "rate",
1615 AL_VOCAL_MORPHER_RATE ); /* 0.0 to 10.0 (1.41) */
1616 } else if ( strcmp( type, "flanger" ) == 0 ) {
1617 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_FLANGER );
1618
1619 efx_setint(
1620 L, p, effect, "waveform",
1621 AL_FLANGER_WAVEFORM ); /* 0 (sin), 1 (triangle) (1 (triangle)) */
1622 efx_setnum( L, p, effect, "phase",
1623 AL_FLANGER_PHASE ); /* -180 to 180 (0) */
1624 efx_setnum( L, p, effect, "rate",
1625 AL_FLANGER_RATE ); /* 0.0 to 10.0 (0.27) */
1626 efx_setnum( L, p, effect, "depth",
1627 AL_FLANGER_DEPTH ); /* 0.0 to 1.0 (1.0) */
1628 efx_setnum( L, p, effect, "feedback",
1629 AL_FLANGER_FEEDBACK ); /* -1.0 to 1.0 (-0.5) */
1630 efx_setnum( L, p, effect, "delay",
1631 AL_FLANGER_DELAY ); /* 0.0 to 0.004 (0.002) */
1632 } else if ( strcmp( type, "frequencyshifter" ) == 0 ) {
1633 nalEffecti( effect, AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER );
1634
1635 efx_setnum( L, p, effect, "frequency",
1636 AL_FREQUENCY_SHIFTER_FREQUENCY ); /* 0.0 to 24000.0 (0.0) */
1637 efx_setint( L, p, effect, "leftdirection",
1638 AL_FREQUENCY_SHIFTER_LEFT_DIRECTION ); /* 0 (down), 1 (up), 2
1639 (off) (0 (down)) */
1640 efx_setint( L, p, effect, "rightdirection",
1641 AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION ); /* 0 (down), 1 (up), 2
1642 (off) (0 (down)) */
1643 } else {
1644 soundUnlock();
1645 return NLUA_ERROR( L, _( "Unsupported audio effect type '%s'!" ), type );
1646 }
1647
1648 if ( volume > 0. )
1649 nalAuxiliaryEffectSlotf( slot, AL_EFFECTSLOT_GAIN, volume );
1650 nalAuxiliaryEffectSloti( slot, AL_EFFECTSLOT_EFFECT, effect );
1651
1652 al_checkErr();
1653 soundUnlock();
1654
1655 return 0;
1656}
1657
1658static LuaAudioEfx_t *audio_getEffectByName( const char *name )
1659{
1660 for ( int i = 0; i < array_size( lua_efx ); i++ )
1661 if ( strcmp( name, lua_efx[i].name ) == 0 )
1662 return &lua_efx[i];
1663 WARN( _( "Unknown audio effect '%s'!" ), name );
1664 return NULL;
1665}
1666
1681static int audioL_setEffect( lua_State *L )
1682{
1683 if ( al_info.efx == AL_FALSE ) {
1684 lua_pushboolean( L, 1 );
1685 return 1;
1686 }
1687
1688 /* Creating new effect. */
1689 if ( !lua_isaudio( L, 1 ) )
1690 return audioL_setEffectGlobal( L );
1691
1692 const LuaAudio_t *la = luaL_checkaudio( L, 1 );
1693 const char *name = luaL_checkstring( L, 2 );
1694 int enable = ( lua_isnoneornil( L, 3 ) ) ? 1 : lua_toboolean( L, 3 );
1695
1696 soundLock();
1697 if ( enable ) {
1698 const LuaAudioEfx_t *lae = audio_getEffectByName( name );
1699 if ( lae == NULL ) {
1700 soundUnlock();
1701 return 0;
1702 }
1703 /* TODO allow more effect slots. */
1704 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, lae->slot, 0,
1705 AL_FILTER_NULL );
1706 } else
1707 alSource3i( la->source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0,
1708 AL_FILTER_NULL );
1709
1710 al_checkErr();
1711 soundUnlock();
1712
1713 lua_pushboolean( L, 1 );
1714 return 1;
1715}
1716
1724static int audioL_setGlobalEffect( lua_State *L )
1725{
1726 LuaAudioEfx_t *lae;
1727 const char *name = luaL_optstring( L, 1, NULL );
1728
1729 if ( sound_disabled )
1730 return 0;
1731
1732 if ( al_info.efx == AL_FALSE )
1733 return 0;
1734
1735 /* Disable. */
1736 if ( name == NULL ) {
1737 soundLock();
1738 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT,
1739 AL_EFFECT_NULL );
1740 al_checkErr();
1741 soundUnlock();
1742 return 0;
1743 }
1744
1745 /* Try to set it. */
1746 lae = audio_getEffectByName( name );
1747 if ( lae == NULL )
1748 return 0;
1749
1750 /* Set the effect. */
1751 soundLock();
1752 nalAuxiliaryEffectSloti( sound_efx_directSlot, AL_EFFECTSLOT_EFFECT,
1753 lae->effect );
1754 al_checkErr();
1755 soundUnlock();
1756 return 0;
1757}
1758
1767static int audioL_setGlobalAirAbsorption( lua_State *L )
1768{
1769 double speed = luaL_optnumber( L, 1, 3433. );
1770 double absorption = luaL_optnumber( L, 2, -1. );
1771
1772 if ( sound_disabled )
1773 return 0;
1774
1775 soundLock();
1776 alSpeedOfSound( speed );
1777 if ( absorption > 0. )
1778 sound_setAbsorption( absorption );
1779 al_checkErr();
1780 soundUnlock();
1781 return 0;
1782}
1783
1793static int audioL_setGlobaDopplerFactor( lua_State *L )
1794{
1795 if ( sound_disabled )
1796 return 0;
1797
1798 soundLock();
1799 alDopplerFactor( luaL_checknumber( L, 1 ) );
1800 al_checkErr();
1801 soundUnlock();
1802 return 0;
1803}
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:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#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
lua_State * naevL
Definition nlua.c:54
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:664
static int audioL_tostring(lua_State *L)
Lua bindings to interact with audio.
Definition nlua_audio.c:404
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:84
static int audioL_pause(lua_State *L)
Pauses a source.
Definition nlua_audio.c:718
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:445
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:285
static int audioL_seek(lua_State *L)
Seeks a source.
Definition nlua_audio.c:845
LuaAudio_t * lua_pushaudio(lua_State *L, LuaAudio_t audio)
Pushes a audio on the stack.
Definition nlua_audio.c:310
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:812
static int audioL_play(lua_State *L)
Plays a source.
Definition nlua_audio.c:680
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:252
static int stream_loadBuffer(LuaAudio_t *la, ALuint buffer)
Loads a buffer.
Definition nlua_audio.c:174
int lua_isaudio(lua_State *L, int ind)
Checks to see if ind is a audio.
Definition nlua_audio.c:325
static int audioL_getDuration(lua_State *L)
Gets the length of a source.
Definition nlua_audio.c:958
static LuaAudioEfx_t * lua_efx
List of effects handled by Lua. These are persistent throughout game runtime.
Definition nlua_audio.c:41
static int audioL_isPaused(lua_State *L)
Checks to see if a source is paused.
Definition nlua_audio.c:737
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:296
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:899
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:485
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:801
static int audioL_getPitch(lua_State *L)
Gets the pitch of a source.
static int audioL_gc(lua_State *L)
Frees a audio.
Definition nlua_audio.c:418
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:272
static int audioL_stop(lua_State *L)
Stops a source.
Definition nlua_audio.c:748
static int audioL_isBool(lua_State *L, ALenum param)
Checks to see a boolean property of a source.
Definition nlua_audio.c:235
static int audioL_eq(lua_State *L)
Compares two audios to see if they are the same.
Definition nlua_audio.c:433
LuaFile_t * lua_tofile(lua_State *L, int ind)
Lua bindings to interact with files.
Definition nlua_file.c:83
int lua_isfile(lua_State *L, int ind)
Checks to see if ind is a file.
Definition nlua_file.c:123
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:1304
int sound_al_buffer(ALuint *buf, SDL_RWops *rw, const char *name)
Loads the sound.
Definition sound.c:2083
void rg_filter(float **pcm, long channels, long samples, void *filter_param)
This is the filter function for the decoded Ogg Vorbis stream.
Definition sound.c:1965
double sound_getVolume(void)
Gets the current sound volume (linear).
Definition sound.c:1291
int sound_disabled
Definition sound.c:130
SDL_mutex * sound_lock
Definition sound.c:164
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
Definition sound.c:832
int sound_get(const char *name)
Gets the buffer to sound of name.
Definition sound.c:761
ALuint sound_efx_directSlot
Definition sound.c:192
alInfo_t al_info
Definition sound.c:176
ov_callbacks sound_al_ovcall
Definition sound.c:274
int sound_play(int sound)
Plays the sound in the first available channel.
Definition sound.c:794
Handles the OpenAL effects that have been set up Lua side.
Definition nlua_audio.c:31
ALuint effect
Definition nlua_audio.c:33
LuaBuffer_t * buf
Definition nlua_audio.h:36
OggVorbis_File stream
Definition nlua_audio.h:41
SDL_Thread * th
Definition nlua_audio.h:49
SDL_mutex * lock
Definition nlua_audio.h:39
int nocleanup
Definition nlua_audio.h:31
ALfloat rg_max_scale
Definition nlua_audio.h:46
LuaAudioType_t type
Definition nlua_audio.h:30
double volume
Definition nlua_audio.h:34
SDL_cond * cond
Definition nlua_audio.h:50
ALenum format
Definition nlua_audio.h:43
char * name
Definition nlua_audio.h:28
ALuint stream_buffers[2]
Definition nlua_audio.h:47
ALuint source
Definition nlua_audio.h:32
vorbis_info * info
Definition nlua_audio.h:42
ALfloat rg_scale_factor
Definition nlua_audio.h:44
ALuint buffer
Definition nlua_audio.h:23
Wrapper to files.
Definition nlua_file.h:19
char path[PATH_MAX]
Definition nlua_file.h:20
Represents a 2d vector.
Definition vec2.h:45
double y
Definition vec2.h:47
double x
Definition vec2.h:46