diff --git a/extra/audio/engine/engine.factor b/extra/audio/engine/engine.factor index 176fc3c305..8ed461b604 100644 --- a/extra/audio/engine/engine.factor +++ b/extra/audio/engine/engine.factor @@ -56,10 +56,11 @@ M: audio-listener audio-gain gain>> ; inline M: audio-listener audio-velocity velocity>> ; inline M: audio-listener audio-orientation orientation>> ; inline +GENERIC# generate-audio 1 ( generator buffer-size -- c-ptr ) +GENERIC: generator-audio-format ( generator -- channels sample-bits sample-rate ) + TUPLE: audio-engine < disposable { voice-count integer } - { buffer-size integer } - { buffer-count integer } { al-device c-ptr } { al-context c-ptr } al-sources @@ -70,17 +71,24 @@ TUPLE: audio-engine < disposable TUPLE: audio-clip < disposable { audio-engine audio-engine } - { audio audio } source - { loop? boolean } - { al-source integer } - { al-buffers uint-array } - { next-data-offset integer } ; + { al-source integer } ; + +TUPLE: static-audio-clip < audio-clip + { al-buffer integer } ; + +TUPLE: streaming-audio-clip < audio-clip + generator + { buffer-size integer } + { channels integer } + { sample-bits integer } + { sample-rate integer } + { al-buffers uint-array } ; ERROR: audio-device-not-found device-name ; ERROR: audio-context-not-available device-name ; -:: ( device-name voice-count buffer-size buffer-count -- engine ) +:: ( device-name voice-count -- engine ) [ device-name alcOpenDevice :> al-device al-device [ device-name audio-device-not-found ] unless @@ -96,12 +104,10 @@ ERROR: audio-context-not-available device-name ; voice-count >>voice-count al-device >>al-device al-context >>al-context - buffer-size >>buffer-size - buffer-count >>buffer-count ] with-destructors ; : ( -- engine ) - f 16 8192 2 ; + f 16 ; > dup (uint-array) [ alGenSources ] keep ; inline -:: flush-source ( source -- ) - source alSourceStop +:: flush-source ( al-source -- ) + al-source alSourceStop 0 c: :> dummy-buffer - source AL_BUFFERS_PROCESSED get-source-param [ - source 1 dummy-buffer alSourceUnqueueBuffers - ] times ; + al-source AL_BUFFERS_PROCESSED get-source-param [ + al-source 1 dummy-buffer alSourceUnqueueBuffers + ] times + al-source AL_BUFFER 0 alSourcei ; : free-sources ( sources -- ) [ length ] keep alDeleteSources ; inline @@ -148,37 +155,13 @@ ERROR: audio-context-not-available device-name ; audio-clip [ size + ] change-next-data-offset drop ; inline :: queue-clip-buffer ( audio-clip al-buffer -- ) - audio-clip audio-engine>> :> audio-engine - audio-engine buffer-size>> :> buffer-size - audio-clip audio>> :> audio - audio-clip next-data-offset>> :> next-data-offset - audio size>> next-data-offset - :> remaining-audio + audio-clip al-source>> :> al-source + audio-clip generator>> :> generator + audio-clip buffer-size>> :> buffer-size + generator buffer-size generate-audio :> data - { - { [ remaining-audio 0 <= ] [ - audio-clip loop?>> [ - audio-clip 0 >>next-data-offset - al-buffer queue-clip-buffer - ] when - ] } - { [ remaining-audio buffer-size < ] [ - audio-clip loop?>> [ - audio data>> - [ next-data-offset swap remaining-audio ] - [ buffer-size remaining-audio - ] bi append :> data - audio-clip al-buffer audio data buffer-size (queue-clip-buffer) - - audio-clip [ audio size>> mod ] change-next-data-offset drop - ] [ - next-data-offset audio data>> :> data - audio-clip al-buffer audio data remaining-audio (queue-clip-buffer) - ] if - ] } - [ - next-data-offset audio data>> :> data - audio-clip al-buffer audio data buffer-size (queue-clip-buffer) - ] - } cond ; + al-buffer audio-clip openal-format data size audio-clip sample-rate>> alBufferData + al-source 1 al-buffer c: alSourceQueueBuffers ; : update-listener ( audio-engine -- ) listener>> { @@ -198,18 +181,24 @@ ERROR: audio-context-not-available device-name ; [ AL_ROLLOFF_FACTOR swap audio-rolloff alSourcef ] } 2cleave ; -:: update-audio-clip ( audio-clip -- ) - audio-clip update-source - audio-clip al-source>> :> al-source - 0 c: :> buffer* +GENERIC: (update-audio-clip) ( audio-clip -- ) - al-source AL_SOURCE_STATE get-source-param AL_STOPPED = - [ audio-clip dispose ] [ - al-source AL_BUFFERS_PROCESSED get-source-param [ - al-source 1 buffer* alSourceUnqueueBuffers - audio-clip buffer* c:*uint queue-clip-buffer - ] times - ] if ; +M: static-audio-clip (update-audio-clip) + drop ; + +M:: streaming-audio-clip (update-audio-clip) ( audio-clip -- ) + audio-clip al-source>> :> al-source + 0 c: :> buffer + al-source AL_BUFFERS_PROCESSED get-source-param [ + al-source 1 buffer alSourceUnqueueBuffers + audio-clip buffer c:*uint queue-clip-buffer + ] times ; + +: update-audio-clip ( audio-clip -- ) + [ update-source ] [ + dup al-source>> AL_SOURCE_STATE get-source-param AL_STOPPED = + [ dispose ] [ (update-audio-clip) ] if + ] bi ; : clip-al-sources ( clips -- length sources ) [ length ] [ [ al-source>> ] uint-array{ } map-as ] bi ; @@ -261,33 +250,59 @@ M: audio-engine dispose* [ [ alcCloseDevice* ] when* f ] change-al-device drop ; -:: (audio-clip) ( audio-engine audio source loop? -- audio-clip/f ) +:: ( audio-engine audio source loop? -- audio-clip/f ) + audio-engine get-available-source :> al-source + + al-source [ + 1 0 c: [ alGenBuffers ] keep c:*uint :> al-buffer + al-buffer audio { [ openal-format ] [ data>> ] [ size>> ] [ sample-rate>> ] } cleave + alBufferData + + al-source AL_BUFFER al-buffer alSourcei + al-source AL_LOOPING loop? c:>c-bool alSourcei + + static-audio-clip new-disposable + audio-engine >>audio-engine + source >>source + al-source >>al-source + al-buffer >>al-buffer :> clip + clip audio-engine clips>> push + clip + ] [ f ] if ; + +:: ( audio-engine source generator buffer-size buffer-count -- audio-clip/f ) audio-engine get-available-source :> al-source al-source [ - audio-engine buffer-count>> :> buffer-count buffer-count dup (uint-array) [ alGenBuffers ] keep :> al-buffers + generator generator-audio-format :> ( channels sample-bits sample-rate ) audio-clip new-disposable audio-engine >>audio-engine - audio >>audio source >>source - loop? >>loop? al-source >>al-source + generator >>generator + buffer-size >>buffer-size + channels >>channels + sample-bits >>sample-bits + sample-rate >>sample-rate al-buffers >>al-buffers - 0 >>next-data-offset :> clip al-buffers [ clip swap queue-clip-buffer ] each clip audio-engine clips>> push - clip ] [ f ] if ; M: audio-clip dispose* - { - [ al-source>> flush-source ] - [ al-buffers>> [ length ] keep alDeleteBuffers ] - [ dup audio-engine>> clips>> remove! drop ] - } cleave ; + [ audio-engine>> clips>> remove! drop ] + [ al-source>> flush-source ] bi ; + +M: static-audio-clip dispose* + [ call-next-method ] + [ [ 1 ] dip al-buffer>> alDeleteBuffers ] bi ; + +M: streaming-audio-clip dispose* + [ call-next-method ] + [ al-buffers>> [ length ] keep alDeleteBuffers ] bi ; : play-clip ( audio-clip -- ) [ update-source ] @@ -297,8 +312,11 @@ M: audio-clip dispose* [ [ update-source ] each ] [ clip-al-sources alSourcePlayv ] bi ; -: ( audio-engine audio source loop? -- audio-clip/f ) - (audio-clip) dup play-clip ; +: play-static-audio-clip ( audio-engine source audio loop? -- audio-clip/f ) + dup [ play-clip ] when* ; + +: play-streaming-audio-clip ( audio-engine source generator buffer-size buffer-count -- audio-clip/f ) + dup [ play-clip ] when* ; : pause-clip ( audio-clip -- ) al-source>> alSourcePause ;