audio processing
This commit is contained in:
12645
audio/dr_flac.h
Normal file
12645
audio/dr_flac.h
Normal file
File diff suppressed because it is too large
Load Diff
5374
audio/dr_mp3.h
Normal file
5374
audio/dr_mp3.h
Normal file
File diff suppressed because it is too large
Load Diff
9009
audio/dr_wav.h
Normal file
9009
audio/dr_wav.h
Normal file
File diff suppressed because it is too large
Load Diff
2
audio/dsp.c
Normal file
2
audio/dsp.c
Normal file
@@ -0,0 +1,2 @@
|
||||
// dsp.c
|
||||
|
||||
102
audio/flac.c
Normal file
102
audio/flac.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "cell.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
#include "dr_flac.h"
|
||||
|
||||
static int flac_calc_size(drflac *flac, drflac_uint64 frames, size_t *out_bytes)
|
||||
{
|
||||
if (!flac || !out_bytes)
|
||||
return -1;
|
||||
|
||||
if (flac->channels == 0)
|
||||
return -1;
|
||||
|
||||
size_t bytes_per_frame = (size_t)flac->channels * sizeof(drflac_int32);
|
||||
if (frames > SIZE_MAX / bytes_per_frame)
|
||||
return -1;
|
||||
|
||||
*out_bytes = (size_t)(frames * bytes_per_frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static JSValue flac_make_info(JSContext *js, drflac *flac)
|
||||
{
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "channels", JS_NewInt32(js, flac->channels));
|
||||
JS_SetPropertyStr(js, obj, "sample_rate", JS_NewInt32(js, flac->sampleRate));
|
||||
JS_SetPropertyStr(js, obj, "bits_per_sample", JS_NewInt32(js, flac->bitsPerSample));
|
||||
JS_SetPropertyStr(js, obj, "total_pcm_frames", JS_NewFloat64(js, (double)flac->totalPCMFrameCount));
|
||||
JS_SetPropertyStr(js, obj, "decoded_bytes_per_frame",
|
||||
JS_NewInt32(js, (int)((size_t)flac->channels * sizeof(drflac_int32))));
|
||||
JS_SetPropertyStr(js, obj, "format", JS_NewString(js, "s32"));
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSC_CCALL(flac_info,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "flac.info expects a blob");
|
||||
|
||||
drflac *flac = drflac_open_memory(data, len, NULL);
|
||||
if (!flac)
|
||||
return JS_ThrowReferenceError(js, "invalid FLAC data");
|
||||
|
||||
JSValue info = flac_make_info(js, flac);
|
||||
drflac_close(flac);
|
||||
return info;
|
||||
)
|
||||
|
||||
JSC_CCALL(flac_decode,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "flac.decode expects a blob");
|
||||
|
||||
drflac *flac = drflac_open_memory(data, len, NULL);
|
||||
if (!flac)
|
||||
return JS_ThrowReferenceError(js, "invalid FLAC data");
|
||||
|
||||
size_t pcm_bytes;
|
||||
if (flac_calc_size(flac, flac->totalPCMFrameCount, &pcm_bytes) != 0) {
|
||||
drflac_close(flac);
|
||||
return JS_ThrowRangeError(js, "FLAC data too large to decode");
|
||||
}
|
||||
|
||||
drflac_int32 *pcm = NULL;
|
||||
if (pcm_bytes > 0) {
|
||||
pcm = malloc(pcm_bytes);
|
||||
if (!pcm) {
|
||||
drflac_close(flac);
|
||||
return JS_ThrowOutOfMemory(js);
|
||||
}
|
||||
}
|
||||
|
||||
drflac_uint64 frames_read = 0;
|
||||
if (pcm_bytes > 0)
|
||||
frames_read = drflac_read_pcm_frames_s32(flac, flac->totalPCMFrameCount, pcm);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
if (pcm_bytes > 0)
|
||||
bytes_read = (size_t)(frames_read * flac->channels * sizeof(drflac_int32));
|
||||
|
||||
JSValue result = flac_make_info(js, flac);
|
||||
JSValue blob = js_new_blob_stoned_copy(js, pcm, bytes_read);
|
||||
JS_SetPropertyStr(js, result, "pcm", blob);
|
||||
free(pcm);
|
||||
drflac_close(flac);
|
||||
return result;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_flac_funcs[] = {
|
||||
MIST_FUNC_DEF(flac, info, 1),
|
||||
MIST_FUNC_DEF(flac, decode, 1)
|
||||
};
|
||||
|
||||
CELL_USE_FUNCS(js_flac_funcs)
|
||||
|
||||
|
||||
|
||||
|
||||
91
audio/mp3.c
Normal file
91
audio/mp3.c
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "cell.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DR_MP3_IMPLEMENTATION
|
||||
#include "dr_mp3.h"
|
||||
|
||||
static JSValue mp3_make_info(JSContext *js, drmp3_uint32 channels, drmp3_uint32 sample_rate, drmp3_uint64 frames)
|
||||
{
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "channels", JS_NewInt32(js, channels));
|
||||
JS_SetPropertyStr(js, obj, "sample_rate", JS_NewInt32(js, sample_rate));
|
||||
JS_SetPropertyStr(js, obj, "bits_per_sample", JS_NewInt32(js, 16));
|
||||
|
||||
double total_frames = frames == DRMP3_UINT64_MAX ? -1.0 : (double)frames;
|
||||
JS_SetPropertyStr(js, obj, "total_pcm_frames", JS_NewFloat64(js, total_frames));
|
||||
JS_SetPropertyStr(js, obj, "decoded_bytes_per_frame",
|
||||
JS_NewInt32(js, (int)((size_t)channels * sizeof(drmp3_int16))));
|
||||
JS_SetPropertyStr(js, obj, "format", JS_NewString(js, "s16"));
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSC_CCALL(mp3_info,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "mp3.info expects a blob");
|
||||
|
||||
drmp3 mp3;
|
||||
if (!drmp3_init_memory(&mp3, data, len, NULL))
|
||||
return JS_ThrowReferenceError(js, "invalid MP3 data");
|
||||
|
||||
drmp3_uint32 channels = mp3.channels;
|
||||
drmp3_uint32 sample_rate = mp3.sampleRate;
|
||||
drmp3_uint64 frames = mp3.totalPCMFrameCount;
|
||||
if (frames == DRMP3_UINT64_MAX)
|
||||
frames = drmp3_get_pcm_frame_count(&mp3);
|
||||
|
||||
JSValue info = mp3_make_info(js, channels, sample_rate, frames);
|
||||
drmp3_uninit(&mp3);
|
||||
return info;
|
||||
)
|
||||
|
||||
static int mp3_calc_bytes(drmp3_uint32 channels, drmp3_uint64 frames, size_t *out_bytes)
|
||||
{
|
||||
if (!out_bytes || channels == 0)
|
||||
return -1;
|
||||
|
||||
size_t bytes_per_frame = (size_t)channels * sizeof(drmp3_int16);
|
||||
if (frames > SIZE_MAX / bytes_per_frame)
|
||||
return -1;
|
||||
|
||||
*out_bytes = (size_t)(frames * bytes_per_frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSC_CCALL(mp3_decode,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "mp3.decode expects a blob");
|
||||
|
||||
drmp3_config config;
|
||||
drmp3_uint64 frames = 0;
|
||||
drmp3_int16 *pcm = drmp3_open_memory_and_read_pcm_frames_s16(data, len, &config, &frames, NULL);
|
||||
if (!pcm)
|
||||
return JS_ThrowReferenceError(js, "failed to decode MP3 data");
|
||||
|
||||
size_t total_bytes;
|
||||
if (mp3_calc_bytes(config.channels, frames, &total_bytes) != 0) {
|
||||
drmp3_free(pcm, NULL);
|
||||
return JS_ThrowRangeError(js, "MP3 output too large");
|
||||
}
|
||||
|
||||
JSValue result = mp3_make_info(js, config.channels, config.sampleRate, frames);
|
||||
JSValue blob = js_new_blob_stoned_copy(js, pcm, total_bytes);
|
||||
JS_SetPropertyStr(js, result, "pcm", blob);
|
||||
drmp3_free(pcm, NULL);
|
||||
return result;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_mp3_funcs[] = {
|
||||
MIST_FUNC_DEF(mp3, info, 1),
|
||||
MIST_FUNC_DEF(mp3, decode, 1)
|
||||
};
|
||||
|
||||
CELL_USE_FUNCS(js_mp3_funcs)
|
||||
|
||||
|
||||
|
||||
|
||||
104
audio/wav.c
Normal file
104
audio/wav.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "cell.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#include "dr_wav.h"
|
||||
|
||||
static int wav_calc_size(drwav *wav, drwav_uint64 frames, size_t *out_bytes)
|
||||
{
|
||||
if (!wav || !out_bytes)
|
||||
return -1;
|
||||
|
||||
size_t bytes_per_frame = drwav_get_bytes_per_pcm_frame(wav);
|
||||
if (bytes_per_frame == 0)
|
||||
return -1;
|
||||
|
||||
if (frames > SIZE_MAX / bytes_per_frame)
|
||||
return -1;
|
||||
|
||||
*out_bytes = (size_t)(frames * bytes_per_frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static JSValue wav_make_info(JSContext *js, drwav *wav)
|
||||
{
|
||||
JSValue obj = JS_NewObject(js);
|
||||
JS_SetPropertyStr(js, obj, "channels", JS_NewInt32(js, wav->channels));
|
||||
JS_SetPropertyStr(js, obj, "sample_rate", JS_NewInt32(js, wav->sampleRate));
|
||||
JS_SetPropertyStr(js, obj, "bits_per_sample", JS_NewInt32(js, wav->bitsPerSample));
|
||||
JS_SetPropertyStr(js, obj, "format_tag", JS_NewInt32(js, wav->translatedFormatTag));
|
||||
JS_SetPropertyStr(js, obj, "total_pcm_frames", JS_NewFloat64(js, (double)wav->totalPCMFrameCount));
|
||||
JS_SetPropertyStr(js, obj, "bytes_per_frame", JS_NewInt32(js, (int)drwav_get_bytes_per_pcm_frame(wav)));
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSC_CCALL(wav_info,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "wav.info expects a blob");
|
||||
|
||||
drwav wav;
|
||||
if (!drwav_init_memory(&wav, data, len, NULL))
|
||||
return JS_ThrowReferenceError(js, "invalid WAV data");
|
||||
|
||||
JSValue info = wav_make_info(js, &wav);
|
||||
drwav_uninit(&wav);
|
||||
return info;
|
||||
)
|
||||
|
||||
JSC_CCALL(wav_decode,
|
||||
size_t len;
|
||||
void *data = js_get_blob_data(js, &len, argv[0]);
|
||||
if (!data)
|
||||
return JS_ThrowTypeError(js, "wav.decode expects a blob");
|
||||
|
||||
drwav wav;
|
||||
if (!drwav_init_memory(&wav, data, len, NULL))
|
||||
return JS_ThrowReferenceError(js, "invalid WAV data");
|
||||
|
||||
size_t pcm_bytes;
|
||||
if (wav_calc_size(&wav, wav.totalPCMFrameCount, &pcm_bytes) != 0) {
|
||||
drwav_uninit(&wav);
|
||||
return JS_ThrowRangeError(js, "WAV data too large");
|
||||
}
|
||||
|
||||
void *pcm = NULL;
|
||||
if (pcm_bytes > 0) {
|
||||
pcm = malloc(pcm_bytes);
|
||||
if (!pcm) {
|
||||
drwav_uninit(&wav);
|
||||
return JS_ThrowOutOfMemory(js);
|
||||
}
|
||||
}
|
||||
|
||||
drwav_uint64 frames_read = 0;
|
||||
if (pcm_bytes > 0)
|
||||
frames_read = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pcm);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
if (pcm_bytes > 0) {
|
||||
size_t bytes_per_frame = drwav_get_bytes_per_pcm_frame(&wav);
|
||||
bytes_read = (size_t)(frames_read * bytes_per_frame);
|
||||
}
|
||||
|
||||
JSValue result = wav_make_info(js, &wav);
|
||||
if (pcm_bytes > 0) {
|
||||
JSValue blob = js_new_blob_stoned_copy(js, pcm, bytes_read);
|
||||
JS_SetPropertyStr(js, result, "pcm", blob);
|
||||
free(pcm);
|
||||
} else {
|
||||
JS_SetPropertyStr(js, result, "pcm", js_new_blob_stoned_copy(js, NULL, 0));
|
||||
}
|
||||
|
||||
drwav_uninit(&wav);
|
||||
return result;
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_wav_funcs[] = {
|
||||
MIST_FUNC_DEF(wav, info, 1),
|
||||
MIST_FUNC_DEF(wav, decode, 1)
|
||||
};
|
||||
|
||||
CELL_USE_FUNCS(js_wav_funcs)
|
||||
1
camera.c
1
camera.c
@@ -1,7 +1,6 @@
|
||||
#include "sdl.h"
|
||||
#include "cell.h"
|
||||
#include "stb_ds.h"
|
||||
#include "qjs_actor.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ static void render_frame(plm_t *mpeg, plm_frame_t *frame, void *d) {
|
||||
JSValue ret = JS_Call(ds->js, cb, JS_NULL, 1, s);
|
||||
JS_FreeValue(ds->js,cb);
|
||||
free(rgb);
|
||||
uncaught_exception(ds->js,ret);
|
||||
// TODO: raise exception
|
||||
}
|
||||
|
||||
JSC_CCALL(os_make_video,
|
||||
|
||||
@@ -109,7 +109,7 @@ function decode_image(bytes, ext)
|
||||
|
||||
function create_image(path){
|
||||
try{
|
||||
def bytes = io.slurpbytes(path);
|
||||
def bytes = io.slurp(path);
|
||||
|
||||
let raw = decode_image(bytes, path.ext());
|
||||
|
||||
@@ -378,7 +378,7 @@ graphics.get_font = function get_font(path) {
|
||||
var fontstr = `${fullpath}.${size}`
|
||||
if (fontcache[fontstr]) return fontcache[fontstr]
|
||||
|
||||
var data = io.slurpbytes(fullpath)
|
||||
var data = io.slurp(fullpath)
|
||||
var font = new staef.font(data, size)
|
||||
|
||||
fontcache[fontstr] = font
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "cell.h"
|
||||
#include "stb_ds.h"
|
||||
#include "qjs_actor.h"
|
||||
#include "wota.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "cell.h"
|
||||
#include "qjs_actor.h"
|
||||
|
||||
#include "prosperon.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
8
sound.cm
8
sound.cm
@@ -1,10 +1,10 @@
|
||||
var soloud = use('soloud')
|
||||
var tween = use('prosperon/tween')
|
||||
var io = use('cellfs')
|
||||
var res = use('resources')
|
||||
var doc = use('doc')
|
||||
|
||||
soloud.init()
|
||||
var wav = use('audio/wav')
|
||||
var mp3 = use('audio/mp3')
|
||||
var flac = use('audio/flac')
|
||||
|
||||
var audio = {}
|
||||
var pcms = {}
|
||||
@@ -16,7 +16,7 @@ var voices = []
|
||||
audio.pcm = function pcm(file) {
|
||||
file = res.find_sound(file); if (!file) return
|
||||
if (pcms[file]) return pcms[file]
|
||||
var buf = io.slurpbytes(file)
|
||||
var buf = io.slurp(file)
|
||||
return pcms[file] = soloud.load_wav_mem(buf)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user