117 lines
3.2 KiB
C
117 lines
3.2 KiB
C
#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 == -1)
|
|
return JS_EXCEPTION;
|
|
|
|
if (!data)
|
|
return JS_ThrowReferenceError(js, "invalid WAV data");
|
|
|
|
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 == -1)
|
|
return JS_EXCEPTION;
|
|
|
|
if (!data)
|
|
return JS_ThrowReferenceError(js, "invalid WAV data");
|
|
|
|
drwav wav;
|
|
if (!drwav_init_memory(&wav, data, len, NULL))
|
|
return JS_ThrowReferenceError(js, "invalid WAV data");
|
|
|
|
size_t pcm_bytes;
|
|
// Calculate size for float output (channels * sizeof(float))
|
|
size_t bytes_per_frame = wav.channels * sizeof(float);
|
|
if (wav.totalPCMFrameCount > SIZE_MAX / bytes_per_frame) {
|
|
drwav_uninit(&wav);
|
|
return JS_ThrowRangeError(js, "WAV data too large");
|
|
}
|
|
pcm_bytes = (size_t)(wav.totalPCMFrameCount * bytes_per_frame);
|
|
|
|
float *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_f32(&wav, wav.totalPCMFrameCount, pcm);
|
|
|
|
size_t bytes_read = 0;
|
|
if (pcm_bytes > 0) {
|
|
bytes_read = (size_t)(frames_read * bytes_per_frame);
|
|
}
|
|
|
|
JSValue result = wav_make_info(js, &wav);
|
|
// Update format info to reflect f32
|
|
JS_SetPropertyStr(js, result, "format", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, result, "bytes_per_frame", JS_NewInt32(js, (int)bytes_per_frame));
|
|
|
|
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)
|