summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--API.md147
-rw-r--r--README.md2
-rw-r--r--ReiLua_API.lua128
-rw-r--r--changelog3
-rw-r--r--devnotes3
-rw-r--r--examples/audio_stream_effects/main.lua100
-rw-r--r--examples/resources/clib/.gitignore1
-rw-r--r--examples/resources/clib/audioProcess.c100
-rw-r--r--examples/resources/music/Juhani Junkala [Retro Game Music Pack] Title Screen.oggbin0 -> 268705 bytes
-rw-r--r--examples/resources/music/LICENCE2
-rw-r--r--include/audio.h21
-rw-r--r--include/lua_core.h3
-rw-r--r--src/audio.c306
-rw-r--r--src/core.c6
-rw-r--r--src/lua_core.c84
15 files changed, 901 insertions, 5 deletions
diff --git a/API.md b/API.md
index 2d46f87..08a3b40 100644
--- a/API.md
+++ b/API.md
@@ -9401,6 +9401,14 @@ Set pan for a sound (0.5 is center)
---
+> stream = RL.GetSoundStream( Sound sound )
+
+Get sound audio stream. Return as lightuserdata
+
+- Success return AudioStream
+
+---
+
> RL.WaveFormat( Wave wave, int sampleRate, int sampleSize, int channels )
Convert wave data to desired format
@@ -9555,6 +9563,145 @@ Get current music time played (in seconds)
---
+> stream = RL.GetMusicStream( Music music )
+
+Get music audio stream. Return as lightuserdata
+
+- Success return AudioStream
+
+---
+
+## Audio - AudioStream management functions
+
+---
+
+> audioStream = RL.LoadAudioStream( int sampleRate, int sampleSize, int channels )
+
+Load audio stream (to stream raw audio pcm data)
+
+- Success return AudioStream
+
+---
+
+> isValid = RL.IsAudioStreamValid( AudioStream stream )
+
+Checks if an audio stream is valid (buffers initialized)
+
+- Success return bool
+
+---
+
+> RL.UnloadAudioStream( AudioStream stream )
+
+Unload audio stream and free memory
+
+---
+
+> RL.UpdateAudioStream( AudioStream stream, Buffer data, int frameCount )
+
+Update audio stream buffers with data
+
+---
+
+> isProcessed = RL.IsAudioStreamProcessed( AudioStream stream )
+
+Check if any audio stream buffers requires refill
+
+- Success return bool
+
+---
+
+> RL.PlayAudioStream( AudioStream stream )
+
+Play audio stream
+
+---
+
+> RL.PauseAudioStream( AudioStream stream )
+
+Pause audio stream
+
+---
+
+> RL.ResumeAudioStream( AudioStream stream )
+
+Resume audio stream
+
+---
+
+> isPlaying = RL.IsAudioStreamPlaying( AudioStream stream )
+
+Check if audio stream is playing
+
+- Success return bool
+
+---
+
+> RL.StopAudioStream( AudioStream stream )
+
+Stop audio stream
+
+---
+
+> RL.SetAudioStreamVolume( AudioStream stream, float volume )
+
+Set volume for audio stream (1.0 is max level)
+
+---
+
+> RL.SetAudioStreamPitch( AudioStream stream, float pitch )
+
+Set pitch for audio stream (1.0 is base level)
+
+---
+
+> RL.SetAudioStreamPan( AudioStream stream, float pan )
+
+Set pan for audio stream (0.5 is centered)
+
+---
+
+> RL.SetAudioStreamBufferSizeDefault( int size )
+
+Default size for new audio streams
+
+---
+
+> RL.SetAudioStreamCallback( AudioStream stream, AudioCallback callback )
+
+Audio thread callback to request new data.
+AudioCallback should be lightuserdata function pointer
+
+---
+
+> RL.AttachAudioStreamProcessor( AudioStream stream, AudioCallback processor )
+
+Attach audio stream processor to stream, receives the samples as 'float'.
+AudioCallback should be lightuserdata function pointer
+
+---
+
+> RL.DetachAudioStreamProcessor( AudioStream stream, AudioCallback processor )
+
+Detach audio stream processor from stream.
+AudioCallback should be lightuserdata function pointer
+
+---
+
+> RL.AttachAudioMixedProcessor( AudioCallback processor )
+
+Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'.
+AudioCallback should be lightuserdata function pointer
+
+---
+
+> RL.DetachAudioMixedProcessor( AudioCallback processor )
+
+Detach audio stream processor from the entire audio pipeline.
+AudioCallback should be lightuserdata function pointer
+
+---
+
## Math - Utils
---
diff --git a/README.md b/README.md
index 1f5772a..3615ebc 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,6 @@ List of some MISSING features that are planned to be included. For specific func
* Core
* VR stereo config functions for VR simulator
-* Audio
- * AudioStream management functions
## Roadmap
diff --git a/ReiLua_API.lua b/ReiLua_API.lua
index e5640d6..99e1c7a 100644
--- a/ReiLua_API.lua
+++ b/ReiLua_API.lua
@@ -5823,6 +5823,12 @@ function RL.SetSoundPitch( sound, pitch ) end
---@return any RL.SetSoundPan
function RL.SetSoundPan( sound, pan ) end
+---Get sound audio stream. Return as lightuserdata
+---- Success return AudioStream
+---@param sound any
+---@return any stream
+function RL.GetSoundStream( sound ) end
+
---Convert wave data to desired format
---@param wave any
---@param sampleRate integer
@@ -5955,6 +5961,128 @@ function RL.GetMusicTimeLength( music ) end
---@return any timePlayed
function RL.GetMusicTimePlayed( music ) end
+---Get music audio stream. Return as lightuserdata
+---- Success return AudioStream
+---@param music any
+---@return any stream
+function RL.GetMusicStream( music ) end
+
+-- Audio - AudioStream management functions
+
+---Load audio stream (to stream raw audio pcm data)
+---- Success return AudioStream
+---@param sampleRate integer
+---@param sampleSize integer
+---@param channels integer
+---@return any audioStream
+function RL.LoadAudioStream( sampleRate, sampleSize, channels ) end
+
+---Checks if an audio stream is valid (buffers initialized)
+---- Success return bool
+---@param stream any
+---@return any isValid
+function RL.IsAudioStreamValid( stream ) end
+
+---Unload audio stream and free memory
+---@param stream any
+---@return any RL.UnloadAudioStream
+function RL.UnloadAudioStream( stream ) end
+
+---Update audio stream buffers with data
+---@param stream any
+---@param data any
+---@param frameCount integer
+---@return any RL.UpdateAudioStream
+function RL.UpdateAudioStream( stream, data, frameCount ) end
+
+---Check if any audio stream buffers requires refill
+---- Success return bool
+---@param stream any
+---@return any isProcessed
+function RL.IsAudioStreamProcessed( stream ) end
+
+---Play audio stream
+---@param stream any
+---@return any RL.PlayAudioStream
+function RL.PlayAudioStream( stream ) end
+
+---Pause audio stream
+---@param stream any
+---@return any RL.PauseAudioStream
+function RL.PauseAudioStream( stream ) end
+
+---Resume audio stream
+---@param stream any
+---@return any RL.ResumeAudioStream
+function RL.ResumeAudioStream( stream ) end
+
+---Check if audio stream is playing
+---- Success return bool
+---@param stream any
+---@return any isPlaying
+function RL.IsAudioStreamPlaying( stream ) end
+
+---Stop audio stream
+---@param stream any
+---@return any RL.StopAudioStream
+function RL.StopAudioStream( stream ) end
+
+---Set volume for audio stream (1.0 is max level)
+---@param stream any
+---@param volume number
+---@return any RL.SetAudioStreamVolume
+function RL.SetAudioStreamVolume( stream, volume ) end
+
+---Set pitch for audio stream (1.0 is base level)
+---@param stream any
+---@param pitch number
+---@return any RL.SetAudioStreamPitch
+function RL.SetAudioStreamPitch( stream, pitch ) end
+
+---Set pan for audio stream (0.5 is centered)
+---@param stream any
+---@param pan number
+---@return any RL.SetAudioStreamPan
+function RL.SetAudioStreamPan( stream, pan ) end
+
+---Default size for new audio streams
+---@param size integer
+---@return any RL.SetAudioStreamBufferSizeDefault
+function RL.SetAudioStreamBufferSizeDefault( size ) end
+
+---Audio thread callback to request new data.
+---AudioCallback should be lightuserdata function pointer
+---@param stream any
+---@param callback any
+---@return any RL.SetAudioStreamCallback
+function RL.SetAudioStreamCallback( stream, callback ) end
+
+---Attach audio stream processor to stream, receives the samples as 'float'.
+---AudioCallback should be lightuserdata function pointer
+---@param stream any
+---@param processor any
+---@return any RL.AttachAudioStreamProcessor
+function RL.AttachAudioStreamProcessor( stream, processor ) end
+
+---Detach audio stream processor from stream.
+---AudioCallback should be lightuserdata function pointer
+---@param stream any
+---@param processor any
+---@return any RL.DetachAudioStreamProcessor
+function RL.DetachAudioStreamProcessor( stream, processor ) end
+
+---Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'.
+---AudioCallback should be lightuserdata function pointer
+---@param processor any
+---@return any RL.AttachAudioMixedProcessor
+function RL.AttachAudioMixedProcessor( processor ) end
+
+---Detach audio stream processor from the entire audio pipeline.
+---AudioCallback should be lightuserdata function pointer
+---@param processor any
+---@return any RL.DetachAudioMixedProcessor
+function RL.DetachAudioMixedProcessor( processor ) end
+
-- Math - Utils
---Round float value
diff --git a/changelog b/changelog
index 4e7c33c..27f0d4c 100644
--- a/changelog
+++ b/changelog
@@ -56,6 +56,9 @@ DETAILED CHANGES:
- ADDED: MeasureTextBoxed.
- CHANGE: DrawTextBoxedEx to DrawTextBoxed.
- CHANGE: DrawMeshInstanced takes transforms as Buffer. Much better performance.
+ - ADDED: AudioStream management functions.
+ - ADDED: GetSoundStream and GetMusicStream.
+ - ADDED: Audio stream effects example.
------------------------------------------------------------------------
Release: ReiLua version 0.8.0 Using Raylib 5.0 and Forked Raygui 4.0
diff --git a/devnotes b/devnotes
index ffc82c5..4fa0023 100644
--- a/devnotes
+++ b/devnotes
@@ -11,8 +11,6 @@ Backlog {
* Text input not working on gui. Could this be Raylib issue?
* Haptic functions.
* SDL3 GPU?
- * Audio
- * AudioStream.
* Models
* Material mapType range checks.
* Mesh bone weight management?
@@ -27,6 +25,7 @@ Bugs {
}
Notes {
+ * WARNING: BREAKING CHANGE: LoadFontData() has been redesigned! https://github.com/raysan5/raylib/commit/29ce5d8aa9d261eba395e24437e08c6bd744616e
}
Needs Testing {
diff --git a/examples/audio_stream_effects/main.lua b/examples/audio_stream_effects/main.lua
new file mode 100644
index 0000000..575a5ce
--- /dev/null
+++ b/examples/audio_stream_effects/main.lua
@@ -0,0 +1,100 @@
+-- Based on raylib audio_stream_effects example
+
+package.path = package.path..";"..RL.GetBasePath().."../resources/lib/?.lua"
+package.cpath = package.cpath..";"..RL.GetBasePath().."../resources/clib/?.so"
+
+Vector2 = require( "vector2" )
+Rect = require( "rectangle" )
+
+-- NOTE! You have to compile the C lib containing the effects in resources/clib/audioProcess.c
+-- Implementing audio processors in Lua would probably be too slow.
+AudioProcess = require( "audioProcess" )
+
+local music = nil
+local rect = Rect:new()
+local rect2 = Rect:new()
+local effectLPF = nil
+local effectDelay = nil
+local enableEffectLPF = false
+local enableEffectDelay = false
+
+function RL.init()
+ RL.SetWindowTitle( "Audio stream effects" )
+ RL.SetWindowState( RL.FLAG_VSYNC_HINT )
+ RL.InitAudioDevice()
+
+ music = RL.LoadMusicStream( RL.GetBasePath().."../resources/music/Juhani Junkala [Retro Game Music Pack] Title Screen.ogg" )
+
+ RL.PlayMusicStream( music )
+
+ AudioProcess.init()
+ effectLPF = AudioProcess.AudioProcessEffectLPF()
+ effectDelay = AudioProcess.AudioProcessEffectDelay()
+
+ local winSize = Vector2:newT( RL.GetScreenSize() )
+ local barWidth = 256
+
+ rect:set(
+ winSize.x / 2 - barWidth / 2,
+ winSize.y / 2 - 5,
+ barWidth,
+ 10
+ )
+ rect2:setR( rect )
+end
+
+function RL.update( delta )
+ RL.UpdateMusicStream( music )
+
+ -- Add/Remove effect: lowpass filter
+ if RL.IsKeyPressed( RL.KEY_F ) then
+ local stream = RL.GetMusicStream( music )
+ enableEffectLPF = not enableEffectLPF
+
+ if enableEffectLPF then
+ RL.AttachAudioStreamProcessor( stream, effectLPF )
+ -- RL.AttachAudioMixedProcessor( effectLPF )
+ else
+ RL.DetachAudioStreamProcessor( stream, effectLPF )
+ -- RL.DetachAudioMixedProcessor( effectLPF )
+ end
+ end
+
+ -- Add/Remove effect: delay
+ if RL.IsKeyPressed( RL.KEY_D ) then
+ local stream = RL.GetMusicStream( music )
+ enableEffectDelay = not enableEffectDelay
+
+ if enableEffectDelay then
+ RL.AttachAudioStreamProcessor( stream, effectDelay )
+ -- RL.AttachAudioMixedProcessor( effectDelay )
+ else
+ RL.DetachAudioStreamProcessor( stream, effectDelay )
+ -- RL.DetachAudioMixedProcessor( effectDelay )
+ end
+ end
+end
+
+function RL.draw()
+ local musicLen = RL.GetMusicTimeLength( music )
+ local musicPos = RL.GetMusicTimePlayed( music )
+
+ RL.ClearBackground( RL.RAYWHITE )
+
+ RL.DrawText(
+ "PRESS F TO TOGGLE LPF EFFECT "..( enableEffectLPF and "ON" or "OFF" ),
+ Vector2:temp( rect.x - 80, rect.y - 80 ), 20, RL.GRAY
+ )
+ RL.DrawText(
+ "PRESS D TO TOGGLE DELAY EFFECT "..( enableEffectDelay and "ON" or "OFF" ),
+ Vector2:temp( rect.x - 90, rect.y - 40 ), 20, RL.GRAY
+ )
+
+ RL.DrawRectangleLines( rect + Rect:temp( 0, -1, 1, 1 ), RL.BLACK )
+ rect2.width = musicPos / musicLen * rect.width
+ RL.DrawRectangle( rect2, RL.RED )
+end
+
+function RL.exit()
+ AudioProcess.free()
+end
diff --git a/examples/resources/clib/.gitignore b/examples/resources/clib/.gitignore
new file mode 100644
index 0000000..f1fe8d1
--- /dev/null
+++ b/examples/resources/clib/.gitignore
@@ -0,0 +1 @@
+*.so \ No newline at end of file
diff --git a/examples/resources/clib/audioProcess.c b/examples/resources/clib/audioProcess.c
new file mode 100644
index 0000000..ad18117
--- /dev/null
+++ b/examples/resources/clib/audioProcess.c
@@ -0,0 +1,100 @@
+/* Based on raylib audio_stream_effects example */
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* gcc audioProcess.c -shared -o audioProcess.so -fPIC -llua */
+
+// Audio effect: lowpass filter
+void AudioProcessEffectLPF(void *buffer, unsigned int frames)
+{
+ static float low[2] = { 0.0f, 0.0f };
+ static const float cutoff = 70.0f / 44100.0f; // 70 Hz lowpass filter
+ const float k = cutoff / (cutoff + 0.1591549431f); // RC filter formula
+
+ // Converts the buffer data before using it
+ float *bufferData = (float *)buffer;
+ for (unsigned int i = 0; i < frames*2; i += 2)
+ {
+ const float l = bufferData[i];
+ const float r = bufferData[i + 1];
+
+ low[0] += k * (l - low[0]);
+ low[1] += k * (r - low[1]);
+ bufferData[i] = low[0];
+ bufferData[i + 1] = low[1];
+ }
+}
+
+static float *delayBuffer = NULL;
+static unsigned int delayBufferSize = 0;
+static unsigned int delayReadIndex = 2;
+static unsigned int delayWriteIndex = 0;
+
+// Audio effect: delay
+static void AudioProcessEffectDelay(void *buffer, unsigned int frames)
+{
+ for (unsigned int i = 0; i < frames*2; i += 2)
+ {
+ float leftDelay = delayBuffer[delayReadIndex++]; // ERROR: Reading buffer -> WHY??? Maybe thread related???
+ float rightDelay = delayBuffer[delayReadIndex++];
+
+ if (delayReadIndex == delayBufferSize) delayReadIndex = 0;
+
+ ((float *)buffer)[i] = 0.5f*((float *)buffer)[i] + 0.5f*leftDelay;
+ ((float *)buffer)[i + 1] = 0.5f*((float *)buffer)[i + 1] + 0.5f*rightDelay;
+
+ delayBuffer[delayWriteIndex++] = ((float *)buffer)[i];
+ delayBuffer[delayWriteIndex++] = ((float *)buffer)[i + 1];
+ if (delayWriteIndex == delayBufferSize) delayWriteIndex = 0;
+ }
+}
+
+/* API. */
+
+static int apInit( lua_State* L ) {
+ // Allocate buffer for the delay effect
+ delayBufferSize = 48000*2; // 1 second delay (device sampleRate*channels)
+ delayBuffer = (float *)calloc(delayBufferSize, sizeof(float));
+
+ return 0;
+}
+
+static int getAudioProcessEffectLPF( lua_State* L ) {
+ lua_pushlightuserdata( L, AudioProcessEffectLPF );
+
+ return 1;
+}
+
+static int getAudioProcessEffectDelay( lua_State* L ) {
+ lua_pushlightuserdata( L, AudioProcessEffectDelay );
+
+ return 1;
+}
+
+static int apFree( lua_State* L ) {
+ free(delayBuffer); // Free delay buffer
+
+ return 0;
+}
+
+static const luaL_Reg audioProcess[] = {
+ { "init", apInit },
+ { "AudioProcessEffectLPF", getAudioProcessEffectLPF },
+ { "AudioProcessEffectDelay", getAudioProcessEffectDelay },
+ { "free", apFree },
+ { NULL, NULL } // sentinel.
+};
+
+int luaopen_audioProcess(lua_State *L) {
+#if LUA_VERSION_NUM <= 501
+ luaL_openlib( L, "audioProcess", audioProcess, 0 );
+#else
+ luaL_newlib( L, audioProcess );
+#endif
+ return 1;
+}
diff --git a/examples/resources/music/Juhani Junkala [Retro Game Music Pack] Title Screen.ogg b/examples/resources/music/Juhani Junkala [Retro Game Music Pack] Title Screen.ogg
new file mode 100644
index 0000000..755ddfb
--- /dev/null
+++ b/examples/resources/music/Juhani Junkala [Retro Game Music Pack] Title Screen.ogg
Binary files differ
diff --git a/examples/resources/music/LICENCE b/examples/resources/music/LICENCE
new file mode 100644
index 0000000..7b94830
--- /dev/null
+++ b/examples/resources/music/LICENCE
@@ -0,0 +1,2 @@
+Resource Author Licence Source Edits
+Juhani Junkala [Retro Game Music Pack] Title Screen Juhani Junkala CC0 https://opengameart.org/content/5-chiptunes-action
diff --git a/include/audio.h b/include/audio.h
index 6589db7..939bdf9 100644
--- a/include/audio.h
+++ b/include/audio.h
@@ -52,3 +52,24 @@ int laudioSetMusicLooping( lua_State* L );
int laudioGetMusicLooping( lua_State* L );
int laudioGetMusicTimeLength( lua_State* L );
int laudioGetMusicTimePlayed( lua_State* L );
+int laudioGetMusicStream( lua_State* L );
+/* Audio - AudioStream management functions. */
+int laudioLoadAudioStream( lua_State* L );
+int laudioIsAudioStreamValid( lua_State* L );
+int laudioUnloadAudioStream( lua_State* L );
+int laudioUpdateAudioStream( lua_State* L );
+int laudioIsAudioStreamProcessed( lua_State* L );
+int laudioPlayAudioStream( lua_State* L );
+int laudioPauseAudioStream( lua_State* L );
+int laudioResumeAudioStream( lua_State* L );
+int laudioIsAudioStreamPlaying( lua_State* L );
+int laudioStopAudioStream( lua_State* L );
+int laudioSetAudioStreamVolume( lua_State* L );
+int laudioSetAudioStreamPitch( lua_State* L );
+int laudioSetAudioStreamPan( lua_State* L );
+int laudioSetAudioStreamBufferSizeDefault( lua_State* L );
+int laudioSetAudioStreamCallback( lua_State* L );
+int laudioAttachAudioStreamProcessor( lua_State* L );
+int laudioDetachAudioStreamProcessor( lua_State* L );
+int laudioAttachAudioMixedProcessor( lua_State* L );
+int laudioDetachAudioMixedProcessor( lua_State* L );
diff --git a/include/lua_core.h b/include/lua_core.h
index 405f054..8204b49 100644
--- a/include/lua_core.h
+++ b/include/lua_core.h
@@ -87,6 +87,7 @@ REILUAPI GlyphInfo* uluaGetGlyphInfo( lua_State* L, int index );
REILUAPI Wave* uluaGetWave( lua_State* L, int index );
REILUAPI Sound* uluaGetSound( lua_State* L, int index );
REILUAPI Music* uluaGetMusic( lua_State* L, int index );
+REILUAPI AudioStream* uluaGetAudioStream( lua_State* L, int index );
REILUAPI Light* uluaGetLight( lua_State* L, int index );
REILUAPI Material* uluaGetMaterial( lua_State* L, int index );
REILUAPI Model* uluaGetModel( lua_State* L, int index );
@@ -123,6 +124,7 @@ REILUAPI void uluaPushWave( lua_State* L, Wave wave );
REILUAPI void uluaPushSound( lua_State* L, Sound sound );
REILUAPI void uluaPushSoundAlias( lua_State* L, Sound alias );
REILUAPI void uluaPushMusic( lua_State* L, Music music );
+REILUAPI void uluaPushAudioStream( lua_State* L, AudioStream stream );
REILUAPI void uluaPushLight( lua_State* L, Light light );
REILUAPI void uluaPushMaterial( lua_State* L, Material material );
REILUAPI void uluaPushMesh( lua_State* L, Mesh mesh );
@@ -143,6 +145,7 @@ void uluaUnloadWave( Wave* wave );
void uluaUnloadSound( Sound* sound );
void uluaUnloadSoundAlias( Sound* sound );
void uluaUnloadMusic( Music* music );
+void uluaUnloadAudioStream( AudioStream* stream );
void uluaUnloadMaterial( Material* material, bool freeAll );
void uluaUnloadMesh( Mesh* mesh );
void uluaUnloadModel( Model* model );
diff --git a/src/audio.c b/src/audio.c
index 47e71ef..d07f806 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -387,6 +387,21 @@ int laudioSetSoundPan( lua_State* L ) {
}
/*
+> stream = RL.GetSoundStream( Sound sound )
+
+Get sound audio stream. Return as lightuserdata
+
+- Success return AudioStream
+*/
+int laudioGetSoundStream( lua_State* L ) {
+ Sound* sound = uluaGetSound( L, 1 );
+
+ lua_pushlightuserdata( L, &sound->stream );
+
+ return 1;
+}
+
+/*
> RL.WaveFormat( Wave wave, int sampleRate, int sampleSize, int channels )
Convert wave data to desired format
@@ -716,3 +731,294 @@ int laudioGetMusicTimePlayed( lua_State* L ) {
return 1;
}
+
+static float arr[10] = {};
+
+/*
+> stream = RL.GetMusicStream( Music music )
+
+Get music audio stream. Return as lightuserdata
+
+- Success return AudioStream
+*/
+int laudioGetMusicStream( lua_State* L ) {
+ Music* music = uluaGetMusic( L, 1 );
+
+ lua_pushlightuserdata( L, &music->stream );
+
+ return 1;
+}
+
+/*
+## Audio - AudioStream management functions
+*/
+
+/*
+> audioStream = RL.LoadAudioStream( int sampleRate, int sampleSize, int channels )
+
+Load audio stream (to stream raw audio pcm data)
+
+- Success return AudioStream
+*/
+int laudioLoadAudioStream( lua_State* L ) {
+ int sampleRate = luaL_checkinteger( L, 1 );
+ int sampleSize = luaL_checkinteger( L, 2 );
+ int channels = luaL_checkinteger( L, 3 );
+
+ uluaPushAudioStream( L, LoadAudioStream( sampleRate, sampleSize, channels ) );
+
+ return 1;
+}
+
+/*
+> isValid = RL.IsAudioStreamValid( AudioStream stream )
+
+Checks if an audio stream is valid (buffers initialized)
+
+- Success return bool
+*/
+int laudioIsAudioStreamValid( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ lua_pushboolean( L, IsAudioStreamValid( *stream ) );
+
+ return 1;
+}
+
+/*
+> RL.UnloadAudioStream( AudioStream stream )
+
+Unload audio stream and free memory
+*/
+int laudioUnloadAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ uluaUnloadAudioStream( stream );
+
+ return 0;
+}
+
+/*
+> RL.UpdateAudioStream( AudioStream stream, Buffer data, int frameCount )
+
+Update audio stream buffers with data
+*/
+int laudioUpdateAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ Buffer* buffer = uluaGetBuffer( L, 2 );
+ int frameCount = luaL_checkinteger( L, 3 );
+
+ UpdateAudioStream( *stream, buffer->data, frameCount );
+
+ return 0;
+}
+
+/*
+> isProcessed = RL.IsAudioStreamProcessed( AudioStream stream )
+
+Check if any audio stream buffers requires refill
+
+- Success return bool
+*/
+int laudioIsAudioStreamProcessed( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ lua_pushboolean( L, IsAudioStreamProcessed( *stream ) );
+
+ return 1;
+}
+
+/*
+> RL.PlayAudioStream( AudioStream stream )
+
+Play audio stream
+*/
+int laudioPlayAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ PlayAudioStream( *stream );
+
+ return 0;
+}
+
+/*
+> RL.PauseAudioStream( AudioStream stream )
+
+Pause audio stream
+*/
+int laudioPauseAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ PauseAudioStream( *stream );
+
+ return 0;
+}
+
+/*
+> RL.ResumeAudioStream( AudioStream stream )
+
+Resume audio stream
+*/
+int laudioResumeAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ ResumeAudioStream( *stream );
+
+ return 0;
+}
+
+/*
+> isPlaying = RL.IsAudioStreamPlaying( AudioStream stream )
+
+Check if audio stream is playing
+
+- Success return bool
+*/
+int laudioIsAudioStreamPlaying( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ lua_pushboolean( L, IsAudioStreamPlaying( *stream ) );
+
+ return 1;
+}
+
+/*
+> RL.StopAudioStream( AudioStream stream )
+
+Stop audio stream
+*/
+int laudioStopAudioStream( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+
+ StopAudioStream( *stream );
+
+ return 0;
+}
+
+/*
+> RL.SetAudioStreamVolume( AudioStream stream, float volume )
+
+Set volume for audio stream (1.0 is max level)
+*/
+int laudioSetAudioStreamVolume( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ float volume = luaL_checknumber( L, 2 );
+
+ SetAudioStreamVolume( *stream, volume );
+
+ return 0;
+}
+
+/*
+> RL.SetAudioStreamPitch( AudioStream stream, float pitch )
+
+Set pitch for audio stream (1.0 is base level)
+*/
+int laudioSetAudioStreamPitch( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ float pitch = luaL_checknumber( L, 2 );
+
+ SetAudioStreamPitch( *stream, pitch );
+
+ return 0;
+}
+
+/*
+> RL.SetAudioStreamPan( AudioStream stream, float pan )
+
+Set pan for audio stream (0.5 is centered)
+*/
+int laudioSetAudioStreamPan( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ float pan = luaL_checknumber( L, 2 );
+
+ SetAudioStreamPan( *stream, pan );
+
+ return 0;
+}
+
+/*
+> RL.SetAudioStreamBufferSizeDefault( int size )
+
+Default size for new audio streams
+*/
+int laudioSetAudioStreamBufferSizeDefault( lua_State* L ) {
+ int size = luaL_checkinteger( L, 1 );
+
+ SetAudioStreamBufferSizeDefault( size );
+
+ return 0;
+}
+
+/*
+> RL.SetAudioStreamCallback( AudioStream stream, AudioCallback callback )
+
+Audio thread callback to request new data.
+AudioCallback should be lightuserdata function pointer
+*/
+int laudioSetAudioStreamCallback( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ AudioCallback callback = lua_touserdata( L, 2 );
+
+ SetAudioStreamCallback( *stream, callback );
+
+ return 0;
+}
+
+/*
+> RL.AttachAudioStreamProcessor( AudioStream stream, AudioCallback processor )
+
+Attach audio stream processor to stream, receives the samples as 'float'.
+AudioCallback should be lightuserdata function pointer
+*/
+int laudioAttachAudioStreamProcessor( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ AudioCallback processor = lua_touserdata( L, 2 );
+
+ AttachAudioStreamProcessor( *stream, processor );
+
+ return 0;
+}
+
+/*
+> RL.DetachAudioStreamProcessor( AudioStream stream, AudioCallback processor )
+
+Detach audio stream processor from stream.
+AudioCallback should be lightuserdata function pointer
+*/
+int laudioDetachAudioStreamProcessor( lua_State* L ) {
+ AudioStream* stream = uluaGetAudioStream( L, 1 );
+ AudioCallback processor = lua_touserdata( L, 2 );
+
+ DetachAudioStreamProcessor( *stream, processor );
+
+ return 0;
+}
+
+/*
+> RL.AttachAudioMixedProcessor( AudioCallback processor )
+
+Attach audio stream processor to the entire audio pipeline, receives the samples as 'float'.
+AudioCallback should be lightuserdata function pointer
+*/
+int laudioAttachAudioMixedProcessor( lua_State* L ) {
+ AudioCallback processor = lua_touserdata( L, 1 );
+
+ AttachAudioMixedProcessor( processor );
+
+ return 0;
+}
+
+/*
+> RL.DetachAudioMixedProcessor( AudioCallback processor )
+
+Detach audio stream processor from the entire audio pipeline.
+AudioCallback should be lightuserdata function pointer
+*/
+int laudioDetachAudioMixedProcessor( lua_State* L ) {
+ AudioCallback processor = lua_touserdata( L, 1 );
+
+ DetachAudioMixedProcessor( processor );
+
+ return 0;
+}
diff --git a/src/core.c b/src/core.c
index 4cbd551..cd9c9c0 100644
--- a/src/core.c
+++ b/src/core.c
@@ -3821,7 +3821,11 @@ int lcoreSetBufferData( lua_State* L ) {
int len = uluaGetTableLen( L, 3 );
- if ( position < 0 || buffer->size / getBufferElementSize( buffer ) <= ( position + len - 1 ) ) {
+ // printf( "buffer->size %d len %d position %d element size %d\n", buffer->size, len, position, getBufferElementSize( buffer ) );
+ // printf( "Kissa %d %d\n", buffer->size / getBufferElementSize( buffer ), position + len - 1 );
+
+ // if ( position < 0 || buffer->size / getBufferElementSize( buffer ) <= ( position + len - 1 ) ) {
+ if ( position < 0 || ( ( buffer->size / getBufferElementSize( buffer ) ) <= ( position + len - 1 ) ) ) {
TraceLog( state->logLevelInvalid, "SetBufferData. position %d out of bounds", position );
return 0;
}
diff --git a/src/lua_core.c b/src/lua_core.c
index c4afe80..1a46a5b 100644
--- a/src/lua_core.c
+++ b/src/lua_core.c
@@ -254,6 +254,25 @@ static void defineMusic() {
lua_setfield( L, -2, "__gc" );
}
+ /* AudioStream. */
+static int gcAudioStream( lua_State* L ) {
+ if ( state->gcUnload ) {
+ AudioStream* stream = luaL_checkudata( L, 1, "AudioStream" );
+ uluaUnloadAudioStream( stream );
+ }
+ return 0;
+}
+
+static void defineAudioStream() {
+ lua_State* L = state->luaState;
+
+ luaL_newmetatable( L, "AudioStream" );
+ lua_pushvalue( L, -1 );
+ lua_setfield( L, -2, "__index" );
+ lua_pushcfunction( L, gcAudioStream );
+ lua_setfield( L, -2, "__gc" );
+}
+
/* Light. */
static void defineLight() {
lua_State* L = state->luaState;
@@ -1341,6 +1360,7 @@ bool luaInit( int argn, const char** argc ) {
defineSound();
defineSoundAlias();
defineMusic();
+ defineAudioStream();
defineLight();
defineMaterial();
defineMesh();
@@ -2319,6 +2339,27 @@ void luaRegister() {
assingGlobalFunction( "GetMusicLooping", laudioGetMusicLooping );
assingGlobalFunction( "GetMusicTimeLength", laudioGetMusicTimeLength );
assingGlobalFunction( "GetMusicTimePlayed", laudioGetMusicTimePlayed );
+ assingGlobalFunction( "GetMusicStream", laudioGetMusicStream );
+ /* AudioStream management functions. */
+ assingGlobalFunction( "LoadAudioStream", laudioLoadAudioStream );
+ assingGlobalFunction( "IsAudioStreamValid", laudioIsAudioStreamValid );
+ assingGlobalFunction( "UnloadAudioStream", laudioUnloadAudioStream );
+ assingGlobalFunction( "UpdateAudioStream", laudioUpdateAudioStream );
+ assingGlobalFunction( "IsAudioStreamProcessed", laudioIsAudioStreamProcessed );
+ assingGlobalFunction( "PlayAudioStream", laudioPlayAudioStream );
+ assingGlobalFunction( "PauseAudioStream", laudioPauseAudioStream );
+ assingGlobalFunction( "ResumeAudioStream", laudioResumeAudioStream );
+ assingGlobalFunction( "IsAudioStreamPlaying", laudioIsAudioStreamPlaying );
+ assingGlobalFunction( "StopAudioStream", laudioStopAudioStream );
+ assingGlobalFunction( "SetAudioStreamVolume", laudioSetAudioStreamVolume );
+ assingGlobalFunction( "SetAudioStreamPitch", laudioSetAudioStreamPitch );
+ assingGlobalFunction( "SetAudioStreamPan", laudioSetAudioStreamPan );
+ assingGlobalFunction( "SetAudioStreamBufferSizeDefault", laudioSetAudioStreamBufferSizeDefault );
+ assingGlobalFunction( "SetAudioStreamCallback", laudioSetAudioStreamCallback );
+ assingGlobalFunction( "AttachAudioStreamProcessor", laudioAttachAudioStreamProcessor );
+ assingGlobalFunction( "DetachAudioStreamProcessor", laudioDetachAudioStreamProcessor );
+ assingGlobalFunction( "AttachAudioMixedProcessor", laudioAttachAudioMixedProcessor );
+ assingGlobalFunction( "DetachAudioMixedProcessor", laudioDetachAudioMixedProcessor );
/* Math. */
/* Utils. */
@@ -3735,6 +3776,36 @@ Music* uluaGetMusic( lua_State* L, int index ) {
}
}
+AudioStream* uluaGetAudioStream( lua_State* L, int index ) {
+ switch ( lua_type( L, index ) ) {
+ case LUA_TLIGHTUSERDATA:
+ return (AudioStream*)lua_touserdata( L, index );
+ case LUA_TTABLE:
+ int t = index, i = 0;
+ lua_pushnil( L );
+ while ( lua_next( L, t ) != 0 ) {
+ if ( TextIsEqual( "audioStream", lua_tostring( L, -2 ) ) ) {
+ AudioStream* stream = NULL;
+ if ( lua_islightuserdata( L, lua_gettop( L ) ) ) {
+ stream = lua_touserdata( L, lua_gettop( L ) );
+ }
+ else {
+ stream = luaL_checkudata( L, lua_gettop( L ), "AudioStream" );
+ }
+ lua_pop( L, 2 ); /* Pops also the string. */
+ return stream;
+ }
+ else {
+ lua_pop( L, 1 );
+ }
+ i++;
+ }
+ /* Don't brake here, we want to get error from default if not found. */
+ default:
+ return luaL_checkudata( L, index, "AudioStream" );
+ }
+}
+
Light* uluaGetLight( lua_State* L, int index ) {
switch ( lua_type( L, index ) ) {
case LUA_TLIGHTUSERDATA:
@@ -4238,6 +4309,13 @@ void uluaPushMusic( lua_State* L, Music music ) {
luaL_setmetatable( L, "Music" );
}
+void uluaPushAudioStream( lua_State* L, AudioStream stream ) {
+ AudioStream* streamP = lua_newuserdata( L, sizeof( AudioStream ) );
+ *streamP = stream;
+ luaCallLoad( "AudioStream", streamP );
+ luaL_setmetatable( L, "AudioStream" );
+}
+
void uluaPushLight( lua_State* L, Light light ) {
Light* lightP = lua_newuserdata( L, sizeof( Light ) );
*lightP = light;
@@ -4361,6 +4439,12 @@ void uluaUnloadMusic( Music* music ) {
memset( music, 0, sizeof( Music ) );
}
+void uluaUnloadAudioStream( AudioStream* stream ) {
+ luaCallUnload( "AudioStream", stream );
+ UnloadAudioStream( *stream );
+ memset( stream, 0, sizeof( AudioStream ) );
+}
+
void uluaUnloadMaterial( Material* material, bool freeAll ) {
luaCallUnload( "Material", material );
if ( freeAll ) {