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)
|
||||
Reference in New Issue
Block a user