Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
[submodule "bin/sokol-tools-bin"]
path = bin/sokol-tools-bin
url = https://github.com/floooh/sokol-tools-bin.git
[submodule "3rd/miniaudio"]
path = 3rd/miniaudio
url = https://github.com/mackron/miniaudio.git
1 change: 1 addition & 0 deletions 3rd/miniaudio
Submodule miniaudio added at 9634be
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ all : $(BIN)/$(APPNAME)

3RDINC=-I3rd
YOGAINC=-I3rd/yoga
MINIAUDIOINC=-I3rd/miniaudio

LUAINC=-I3rd/lua
LUASRC:=$(wildcard 3rd/lua/*.c 3rd/lua/*.h)
Expand Down Expand Up @@ -125,7 +126,7 @@ $(BUILD)/soluna_entry.o : src/entry.c src/version.h
$(COMPILE_C) $(LUAINC) $(3RDINC) -DSOLUNA_HASH_VERSION=\"$(VERSION)\"

$(BUILD)/soluna_%.o : src/%.c
$(COMPILE_C) $(LUAINC) $(3RDINC) $(SHADERINC) $(YOGAINC) $(ZLIBINC)
$(COMPILE_C) $(LUAINC) $(3RDINC) $(SHADERINC) $(YOGAINC) $(ZLIBINC) $(MINIAUDIOINC)

$(BUILD)/platform_%.o : src/platform/windows/%.c
$(COMPILE_C) $(LUAINC) $(3RDINC) $(SHADERINC) $(YOGAINC) $(ZLIBINC) -Isrc
Expand Down
3 changes: 3 additions & 0 deletions asset/sounds.dl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--
name : bloop
filename : asset/sounds/bloop_x.wav
Binary file added asset/sounds/bloop_x.wav
Binary file not shown.
4 changes: 3 additions & 1 deletion clibs/soluna/make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ lm:source_set "soluna_src" {
includes = {
"build",
"src",
"3rd/lua",
"3rd",
"3rd/lua",
"3rd/yoga",
"3rd/zlib",
"3rd/miniaudio",
},
clang = {
sources = lm.os == "macos" and {
Expand All @@ -52,6 +53,7 @@ lm:source_set "soluna_src" {
"-x objective-c",
},
frameworks = lm.os == "macos" and {
"AudioToolbox",
"IOKit",
"CoreText",
"CoreFoundation",
Expand Down
2 changes: 1 addition & 1 deletion make.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ lm:conf {
},
},
emcc = {
c = "c11",
c = "gnu11",
flags = {
"-Wall",
"-pthread",
Expand Down
215 changes: 215 additions & 0 deletions src/audio.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
#include <lua.h>
#include <lauxlib.h>

#include "zipreader.h"

#define MA_NO_WIN32_FILEIO
#define MA_NO_MP3
#define MA_NO_FLAC
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"

FILE * fopen_utf8(const char *filename, const char *mode);

static ma_result
vfs_open_local(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) {
FILE* pFileStd;
const char* pOpenModeStr;

MA_ASSERT(pFilePath != NULL);
MA_ASSERT(openMode != 0);
MA_ASSERT(pFile != NULL);

(void)pVFS;

if ((openMode & MA_OPEN_MODE_READ) != 0) {
if ((openMode & MA_OPEN_MODE_WRITE) != 0) {
pOpenModeStr = "r+";
} else {
pOpenModeStr = "rb";
}
} else {
pOpenModeStr = "wb";
}

pFileStd = fopen_utf8(pFilePath, pOpenModeStr);

if (pFileStd == NULL) {
return MA_ERROR;
}

*pFile = pFileStd;

return MA_SUCCESS;
}

struct custom_vfs {
ma_default_vfs base;
struct zipreader_name *zipnames;
};

struct custom_engine {
struct ma_engine engine;
struct ma_resource_manager rm;
struct custom_vfs vfs;
};

static ma_result
zr_open(ma_vfs* pVFS, const char* pFilePath, ma_uint32 openMode, ma_vfs_file* pFile) {
struct custom_vfs *vfs = (struct custom_vfs *)pVFS;
if (openMode != MA_OPEN_MODE_READ)
return MA_NOT_IMPLEMENTED;
zipreader_file zf = zipreader_open(vfs->zipnames, pFilePath);
if (zf == NULL) {
return MA_ERROR;
}
*pFile = (ma_vfs_file)zf;
return MA_SUCCESS;
}

static ma_result
zr_close(ma_vfs* pVFS, ma_vfs_file file) {
(void)pVFS;
zipreader_close((zipreader_file)file);
return MA_SUCCESS;
}

static ma_result
zr_read(ma_vfs* pVFS, ma_vfs_file file, void* pDst, size_t sizeInBytes, size_t* pBytesRead) {
(void)pVFS;
int bytes = (int)sizeInBytes;
if (bytes!= sizeInBytes || bytes < 0)
return MA_OUT_OF_RANGE;
int rd = zipreader_read((zipreader_file)file, pDst, bytes);
if (rd < 0)
return MA_IO_ERROR;
*pBytesRead = rd;
return MA_SUCCESS;
}

static ma_result
zr_seek(ma_vfs* pVFS, ma_vfs_file file, ma_int64 offset, ma_seek_origin origin) {
(void)pVFS;
int whence;
switch (origin) {
case ma_seek_origin_start :
whence = SEEK_SET;
break;
case ma_seek_origin_current :
whence = SEEK_CUR;
break;
case ma_seek_origin_end :
whence = SEEK_END;
break;
default :
return MA_INVALID_ARGS;
}
if (zipreader_seek((zipreader_file)file, offset, whence) != 0) {
return MA_ERROR;
}
return MA_SUCCESS;
}

static ma_result
zr_tell(ma_vfs* pVFS, ma_vfs_file file, ma_int64* pCursor) {
(void)pVFS;
*pCursor = zipreader_tell((zipreader_file)file);
if (*pCursor < 0)
return MA_ERROR;
return MA_SUCCESS;
}

static ma_result
zr_info(ma_vfs* pVFS, ma_vfs_file file, ma_file_info* pInfo) {
(void)pVFS;
pInfo->sizeInBytes = zipreader_size((zipreader_file)file);
return MA_SUCCESS;
}

static int
laudio_init(lua_State *L) {
lua_settop(L, 1);
struct custom_engine *e = (struct custom_engine *)lua_newuserdatauv(L, sizeof(*e), 1);

ma_default_vfs_init(&e->vfs.base, NULL);
e->vfs.base.cb.onOpen = vfs_open_local;
e->vfs.zipnames = NULL;

if (lua_isuserdata(L, 1)) {
e->vfs.zipnames = lua_touserdata(L, 1);
e->vfs.base.cb.onOpen = zr_open;
e->vfs.base.cb.onOpenW = NULL;
e->vfs.base.cb.onClose = zr_close;
e->vfs.base.cb.onRead = zr_read;
e->vfs.base.cb.onWrite = NULL;
e->vfs.base.cb.onSeek = zr_seek;
e->vfs.base.cb.onTell = zr_tell;
e->vfs.base.cb.onInfo = zr_info;
lua_pushvalue(L, 1);
lua_setiuservalue(L, -2, 1);
}

ma_resource_manager_config config = ma_resource_manager_config_init();
config.pVFS = &e->vfs;

ma_result r = ma_resource_manager_init(&config, &e->rm);
if (r != MA_SUCCESS) {
return luaL_error(L, "ma_resource_manager_init() error : %s", ma_result_description(r));
}

ma_engine_config ec = ma_engine_config_init();
ec.pResourceManager = &e->rm;
r = ma_engine_init(&ec, &e->engine);
if (r != MA_SUCCESS) {
return luaL_error(L, "ma_engine_init() error : %s", ma_result_description(r));
}
lua_pushlightuserdata(L, (void *)e);

return 2;
}

static int
laudio_deinit(lua_State *L) {
luaL_checktype(L, 1, LUA_TUSERDATA);
ma_engine *engine = (ma_engine *)lua_touserdata(L, 1);
ma_engine_uninit(engine);

return 0;
}

/*
// todo : call ma_sound_init_from_file()

static int
laudio_load(lua_State *L) {
return 0;
}

static int
laudio_unload(lua_State *L) {
return 0;
}
*/

static int
laudio_play(lua_State *L) {
luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
ma_engine *engine = (ma_engine *)lua_touserdata(L, 1);
const char *filename = luaL_checkstring(L, 2);

ma_engine_play_sound(engine, filename, NULL);
return 0;
}

int
luaopen_soluna_audio(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "init", laudio_init },
{ "deinit", laudio_deinit },
{ "play", laudio_play },
{ NULL, NULL },
};
luaL_newlib(L, l);
return 1;
}
2 changes: 2 additions & 0 deletions src/embedlua.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "util.lua.h"
#include "coroutine.lua.h"
#include "packageloader.lua.h"
#include "audio.lua.h"

#include "lua.h"
#include "lauxlib.h"
Expand Down Expand Up @@ -84,6 +85,7 @@ luaopen_embedsource(lua_State *L) {
REG_SOURCE(render)
REG_SOURCE(gamepad)
REG_SOURCE(settings)
REG_SOURCE(audio)
lua_setfield(L, -2, "service");

lua_newtable(L); // data list
Expand Down
4 changes: 4 additions & 0 deletions src/lualib/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ function api.start(app)
name = "loader",
unique = true,
},
{
name = "audio",
unique = true,
},
},
}
end
Expand Down
13 changes: 13 additions & 0 deletions src/lualib/soluna.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ function soluna.load_sprites(filename)
return sprites
end


local audio_service, audio_sounds

function soluna.load_sounds(filename)
audio_service = audio_service or ltask.uniqueservice "audio"
audio_sounds = ltask.call(audio_service, "init", filename)
return audio_sounds
end

function soluna.play_sound(name)
ltask.send(audio_service, true, audio_sounds[name])
end

function soluna.preload(spr)
local loader = ltask.uniqueservice "loader"
if #spr == 0 then
Expand Down
2 changes: 2 additions & 0 deletions src/luamods.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ int luaopen_url(lua_State *L);
int luaopen_skynet_crypt(lua_State *L);
int luaopen_zip(lua_State *L);
int luaopen_extlua(lua_State *L);
int luaopen_soluna_audio(lua_State *L);

void soluna_embed(lua_State* L) {
static const luaL_Reg modules[] = {
Expand Down Expand Up @@ -69,6 +70,7 @@ void soluna_embed(lua_State* L) {
{ "soluna.crypt", luaopen_skynet_crypt },
{ "soluna.zip", luaopen_zip },
{ "soluna.extlua", luaopen_extlua },
{ "soluna.audio", luaopen_soluna_audio },
{ NULL, NULL },
};

Expand Down
Loading
Loading