audio working from soloud -> sdl3
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
This commit is contained in:
@@ -16,6 +16,7 @@ audio.pcm = function pcm(file)
|
||||
file = res.find_sound(file);
|
||||
if (!file) throw new Error(`Could not findfile ${file}`);
|
||||
if (pcms[file]) return pcms[file];
|
||||
var bytes = io.slurpbytes(file)
|
||||
var newpcm = soloud.load_wav_mem(io.slurpbytes(file));
|
||||
pcms[file] = newpcm;
|
||||
return newpcm;
|
||||
@@ -73,4 +74,33 @@ audio.music = function music(file, fade = 0.5) {
|
||||
};
|
||||
audio.music[doc.sym] = `Play the given music file, with an optional cross fade. The song will loop. When this is invoked again, the previous music is replaced.`
|
||||
|
||||
var ss = use('sdl_audio')
|
||||
|
||||
var feeder = ss.open_stream("playback")
|
||||
|
||||
feeder.set_format({format:"f32", channels:2,samplerate:44100})
|
||||
|
||||
feeder.resume()
|
||||
|
||||
var FRAMES = 1024
|
||||
var CHANNELS = 2
|
||||
var BYTES_PER_F = 4
|
||||
var SAMPLES = FRAMES * CHANNELS
|
||||
var CHUNK_BYTES = FRAMES * CHANNELS * BYTES_PER_F
|
||||
|
||||
var mixview = new Float32Array(FRAMES*CHANNELS)
|
||||
var mixbuf = mixview.buffer
|
||||
|
||||
function pump()
|
||||
{
|
||||
if (feeder.queued() < CHUNK_BYTES*3) {
|
||||
var mm = soloud.mix(FRAMES)
|
||||
feeder.put(mm)
|
||||
}
|
||||
|
||||
$_.delay(pump, 1/240)
|
||||
}
|
||||
|
||||
pump()
|
||||
|
||||
return audio;
|
||||
|
||||
201
source/jsffi.c
201
source/jsffi.c
@@ -33,6 +33,8 @@
|
||||
#include "qjs_soloud.h"
|
||||
#include "qjs_qr.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
void gui_input(SDL_Event *e);
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -3135,15 +3137,48 @@ static const JSCFunctionListEntry js_renderer_ctx_funcs[] = {
|
||||
MIST_FUNC_DEF(renderer, make_sprite_mesh, 2),
|
||||
};
|
||||
|
||||
static const struct { const char *s; SDL_AudioFormat f; } fmt_lut[] = {
|
||||
{ "u8", SDL_AUDIO_U8 }, /* Unsigned 8-bit */
|
||||
{ "s8", SDL_AUDIO_S8 }, /* Signed 8-bit */
|
||||
{ "s16", SDL_AUDIO_S16 }, /* Signed 16-bit, host endian */
|
||||
{ "s32", SDL_AUDIO_S32 }, /* Signed 32-bit, host endian */
|
||||
{ "f32", SDL_AUDIO_F32 } /* Float 32-bit, host endian */
|
||||
};
|
||||
|
||||
static int format_str_to_enum(const char *f, SDL_AudioFormat *out)
|
||||
{
|
||||
struct { const char *s; SDL_AudioFormat f; } map[] = {
|
||||
{"u8", SDL_AUDIO_U8 }, {"s16", SDL_AUDIO_S16},
|
||||
{"s32", SDL_AUDIO_S32}, {"f32", SDL_AUDIO_F32}
|
||||
};
|
||||
for (size_t i=0;i<countof(map);++i)
|
||||
if (!strcmp(f,map[i].s)) { *out = map[i].f; return 1; }
|
||||
return 0;
|
||||
struct { const char *s; SDL_AudioFormat f; } map[] = {
|
||||
{"u8", SDL_AUDIO_U8 }, {"s16", SDL_AUDIO_S16},
|
||||
{"s32", SDL_AUDIO_S32}, {"f32", SDL_AUDIO_F32}
|
||||
};
|
||||
for (size_t i=0;i<countof(map);++i)
|
||||
if (!strcmp(f,map[i].s)) { *out = map[i].f; return 1; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *fmt2str(SDL_AudioFormat f)
|
||||
{
|
||||
for (size_t i = 0; i < countof(fmt_lut); ++i)
|
||||
if (fmt_lut[i].f == f) return fmt_lut[i].s;
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static JSValue audiospec2js(JSContext *js, const SDL_AudioSpec *spec)
|
||||
{
|
||||
JSValue o = JS_NewObject(js);
|
||||
|
||||
/* stringify format (u8/s16/s32/f32) */
|
||||
JS_SetPropertyStr(js, o, "format",
|
||||
JS_NewString(js, fmt2str(spec->format)));
|
||||
|
||||
JS_SetPropertyStr(js, o, "channels",
|
||||
JS_NewInt32(js, spec->channels));
|
||||
|
||||
JS_SetPropertyStr(js, o, "samplerate",
|
||||
JS_NewInt32(js, spec->freq));
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
static SDL_AudioSpec js2audiospec(JSContext *js, JSValue obj)
|
||||
@@ -3198,9 +3233,14 @@ JSC_CCALL(sdl_audio_open_stream,
|
||||
if (type)
|
||||
JS_FreeCString(js, type);
|
||||
|
||||
// SDL_AudioSpec want = js2audiospec(js, argv[1]);
|
||||
|
||||
SDL_AudioStream *st = SDL_OpenAudioDeviceStream(devid, NULL, NULL, NULL);
|
||||
SDL_AudioStream *st;
|
||||
|
||||
if (JS_IsUndefined(argv[1]))
|
||||
st = SDL_OpenAudioDeviceStream(devid, NULL, NULL, NULL);
|
||||
else {
|
||||
SDL_AudioSpec want = js2audiospec(js, argv[1]);
|
||||
st = SDL_OpenAudioDeviceStream(devid, &want, NULL, NULL);
|
||||
}
|
||||
|
||||
if (!st)
|
||||
return JS_ThrowInternalError(js, "open failed: %s", SDL_GetError());
|
||||
@@ -3214,6 +3254,145 @@ static const JSCFunctionListEntry js_sdl_audio_funcs[] = {
|
||||
MIST_FUNC_DEF(sdl_audio, open_stream, 2),
|
||||
};
|
||||
|
||||
JSC_CCALL(sdl_audiostream_get_format,
|
||||
SDL_AudioStream *as = js2SDL_AudioStream(js, self);
|
||||
SDL_AudioSpec src;
|
||||
SDL_AudioSpec dst;
|
||||
SDL_GetAudioStreamFormat(as, &src, &dst);
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "src", audiospec2js(js, &src));
|
||||
JS_SetPropertyStr(js, obj, "dst", audiospec2js(js, &dst));
|
||||
return obj;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_set_format,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
const SDL_AudioSpec *src_ptr=NULL,*dst_ptr=NULL;
|
||||
SDL_AudioSpec src={0},dst={0};
|
||||
|
||||
if(argc>0&&!JS_IsUndefined(argv[0])){
|
||||
src=js2audiospec(js,argv[0]);
|
||||
src_ptr=&src;
|
||||
}
|
||||
if(argc>1&&!JS_IsUndefined(argv[1])){
|
||||
dst=js2audiospec(js,argv[1]);
|
||||
dst_ptr=&dst;
|
||||
}
|
||||
|
||||
if(!SDL_SetAudioStreamFormat(as,src_ptr,dst_ptr))
|
||||
return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_resume,
|
||||
SDL_AudioStream *as = js2SDL_AudioStream(js,self);
|
||||
if (!SDL_ResumeAudioStreamDevice(as))
|
||||
return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_clear,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
if (!SDL_ClearAudioStream(as))
|
||||
return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_flush,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
if(!SDL_FlushAudioStream(as))
|
||||
return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_available,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
Sint64 n = SDL_GetAudioStreamAvailable(as);
|
||||
if(n<0) return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
return JS_NewInt64(js,n);
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_queued,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
Sint64 n = SDL_GetAudioStreamQueued(as);
|
||||
if(n<0) return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
return JS_NewInt64(js,n);
|
||||
)
|
||||
|
||||
/* ---------- data IO ---------------------------------------------------- */
|
||||
JSC_CCALL(sdl_audiostream_put,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
size_t len;
|
||||
void *buf = JS_GetArrayBuffer(js, &len, argv[0]);
|
||||
if (!buf)
|
||||
return JS_ThrowInternalError(js, "Requires array buffer.");
|
||||
|
||||
if (!SDL_PutAudioStreamData(as,buf,len))
|
||||
return JS_ThrowInternalError(js, "%s", SDL_GetError());
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_get,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
int want;
|
||||
JS_ToInt32(js,&want,argv[0]);
|
||||
void *data = malloc(want);
|
||||
int got = SDL_GetAudioStreamData(as, data, want);
|
||||
|
||||
if (got<0) {
|
||||
free(data);
|
||||
return JS_ThrowInternalError(js,"%s",SDL_GetError());
|
||||
}
|
||||
|
||||
JSValue ab = JS_NewArrayBufferCopy(js, data, got);
|
||||
free(data);
|
||||
|
||||
return ab;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_get_gain,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
return JS_NewFloat64(js,SDL_GetAudioStreamGain(as));
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_set_gain,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
double g; JS_ToFloat64(js,&g,argv[0]);
|
||||
SDL_SetAudioStreamGain(as,(float)g);
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_get_freq_ratio,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
return JS_NewFloat64(js,SDL_GetAudioStreamFrequencyRatio(as));
|
||||
)
|
||||
|
||||
JSC_CCALL(sdl_audiostream_set_freq_ratio,
|
||||
SDL_AudioStream *as=js2SDL_AudioStream(js,self);
|
||||
double r; JS_ToFloat64(js,&r,argv[0]);
|
||||
SDL_SetAudioStreamFrequencyRatio(as,(float)r);
|
||||
return JS_UNDEFINED;
|
||||
)
|
||||
|
||||
/* ---------- JS export list -------------------------------------------- */
|
||||
static const JSCFunctionListEntry js_SDL_AudioStream_funcs[] = {
|
||||
MIST_FUNC_DEF(sdl_audiostream, get_format, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, set_format, 2),
|
||||
MIST_FUNC_DEF(sdl_audiostream, resume, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, clear, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, flush, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, available, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, queued, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, put, 1),
|
||||
MIST_FUNC_DEF(sdl_audiostream, get, 1),
|
||||
MIST_FUNC_DEF(sdl_audiostream, set_gain, 1),
|
||||
MIST_FUNC_DEF(sdl_audiostream, get_gain, 0),
|
||||
MIST_FUNC_DEF(sdl_audiostream, set_freq_ratio, 1),
|
||||
MIST_FUNC_DEF(sdl_audiostream, get_freq_ratio, 0),
|
||||
};
|
||||
|
||||
// GPU API
|
||||
JSC_CCALL(gpu_claim_window,
|
||||
SDL_GPUDevice *gpu = js2SDL_GPUDevice(js,self);
|
||||
@@ -7264,6 +7443,8 @@ void ffi_load(JSContext *js)
|
||||
QJSCLASSPREP_NO_FUNCS(SDL_Cursor)
|
||||
QJSCLASSPREP_FUNCS(SDL_Camera)
|
||||
|
||||
QJSCLASSPREP_FUNCS(SDL_AudioStream)
|
||||
|
||||
QJSCLASSPREP_FUNCS(renderer_ctx)
|
||||
|
||||
QJSCLASSPREP_FUNCS(SDL_GPUDevice)
|
||||
|
||||
@@ -325,7 +325,9 @@ void set_actor_state(prosperon_rt *actor)
|
||||
void actor_turn(prosperon_rt *actor, int greedy)
|
||||
{
|
||||
SDL_LockMutex(actor->turn);
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCFiberEnter(actor->id);
|
||||
#endif
|
||||
|
||||
SDL_LockMutex(actor->msg_mutex);
|
||||
actor->state = ACTOR_RUNNING;
|
||||
@@ -412,13 +414,17 @@ void actor_turn(prosperon_rt *actor, int greedy)
|
||||
goto EVENT;
|
||||
|
||||
END:
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCFiberLeave(actor->id);
|
||||
#endif
|
||||
SDL_UnlockMutex(actor->turn);
|
||||
set_actor_state(actor);
|
||||
return;
|
||||
|
||||
KILL:
|
||||
TracyCFiberLeave(actor->id);
|
||||
#ifdef TRACY_ENABLE
|
||||
TracyCFiberLeave(actor->id);
|
||||
#endif
|
||||
SDL_UnlockMutex(actor->turn);
|
||||
actor_free(actor);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
#include <tracy/TracyC.h>
|
||||
#ifdef TRACY_ENABLE
|
||||
#include <tracy/TracyC.h>
|
||||
#else
|
||||
/* Provide harmless stubs when Tracy is not in use so the rest of the code
|
||||
can still call the hooks unconditionally. */
|
||||
#define TracyCAllocN(ptr, size, name) ((void)0)
|
||||
#define TracyCFreeN(ptr, name) ((void)0)
|
||||
#define TracyCFiberEnter(name) ((void)0)
|
||||
#define TracyCFiberLeave(name) ((void)0)
|
||||
#endif
|
||||
|
||||
#define MIST_CFUNC_DEF(name, length, func1, props) { name, props, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ JSCLASS(Bus, Bus_destroy)
|
||||
static JSValue js_soloud_make(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
soloud = Soloud_create();
|
||||
Soloud_initEx(soloud, SOLOUD_CLIP_ROUNDOFF, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO);
|
||||
Soloud_initEx(soloud, SOLOUD_CLIP_ROUNDOFF, SOLOUD_NULLDRIVER, 44100, SOLOUD_AUTO, 2);
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "channels", JS_NewFloat64(js, Soloud_getBackendChannels(soloud)));
|
||||
JS_SetPropertyStr(js, obj, "samplerate", JS_NewFloat64(js, Soloud_getBackendSamplerate(soloud)));
|
||||
@@ -93,10 +93,11 @@ static JSValue js_soloud_play(JSContext *js, JSValue self, int argc, JSValue *ar
|
||||
|
||||
static JSValue js_soloud_mix(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
{
|
||||
size_t len;
|
||||
void *data = JS_GetArrayBuffer(js, &len, argv[0]);
|
||||
Soloud_mix(soloud, data, js2number(js,argv[1]));
|
||||
return JS_UNDEFINED;
|
||||
int req;
|
||||
JS_ToInt32(js, &req, argv[0]);
|
||||
float *buf = malloc(2*req*sizeof(float));
|
||||
Soloud_mix(soloud, buf, req);
|
||||
return JS_NewArrayBufferCopy(js, buf, 2*req*sizeof(float));
|
||||
}
|
||||
|
||||
// Create a voice from a WAV file
|
||||
|
||||
@@ -64,12 +64,8 @@ function loop()
|
||||
}
|
||||
|
||||
var sound = use('sound')
|
||||
prosperon.myguy = sound.play("test.mp3")
|
||||
|
||||
var ss = use('sdl_audio')
|
||||
console.log(ss.drivers())
|
||||
console.log(ss.devices())
|
||||
|
||||
var feeder = ss.open_stream("playback", {format: "f32", channels:2, freq:48000})
|
||||
//prosperon.myguy = sound.play('test.mp3')
|
||||
|
||||
loop()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user