#include "cell.h" #include #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)