Fix audio; save qoa and wav; separate out idea of pcm and playable sound
This commit is contained in:
parent
8465fb53f7
commit
39511e0d3b
2
Makefile
2
Makefile
|
@ -20,7 +20,7 @@ STEAMAPI =
|
||||||
LDFLAGS += -lstdc++
|
LDFLAGS += -lstdc++
|
||||||
|
|
||||||
ifeq ($(CROSS)$(CC), emcc)
|
ifeq ($(CROSS)$(CC), emcc)
|
||||||
LDFLAGS += --shell-file shell.html --closure 1
|
LDFLAGS += --shell-file shell.html --embed-file ld56@/ #--closure 1
|
||||||
CPPFLAGS += -Wbad-function-cast -Wcast-function-type -sSTACK_SIZE=1MB -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=128MB -pthread -s USE_PTHREADS=1
|
CPPFLAGS += -Wbad-function-cast -Wcast-function-type -sSTACK_SIZE=1MB -sALLOW_MEMORY_GROWTH -sINITIAL_MEMORY=128MB -pthread -s USE_PTHREADS=1
|
||||||
NDEBUG = 1
|
NDEBUG = 1
|
||||||
ARCH:= wasm
|
ARCH:= wasm
|
||||||
|
|
|
@ -233,6 +233,7 @@ var pipe_shaders = new WeakMap();
|
||||||
render.use_shader = function use_shader(shader, pipeline) {
|
render.use_shader = function use_shader(shader, pipeline) {
|
||||||
pipeline ??= base_pipeline;
|
pipeline ??= base_pipeline;
|
||||||
if (typeof shader === "string") shader = make_shader(shader);
|
if (typeof shader === "string") shader = make_shader(shader);
|
||||||
|
if (cur.shader === shader) return;
|
||||||
|
|
||||||
if (!pipe_shaders.has(shader)) pipe_shaders.set(shader, new WeakMap());
|
if (!pipe_shaders.has(shader)) pipe_shaders.set(shader, new WeakMap());
|
||||||
var shader_pipelines = pipe_shaders.get(shader);
|
var shader_pipelines = pipe_shaders.get(shader);
|
||||||
|
@ -570,14 +571,13 @@ function shader_apply_material(shader, material = {}, old = {}) {
|
||||||
// Creates a binding object for a given mesh and shader
|
// Creates a binding object for a given mesh and shader
|
||||||
var bcache = new WeakMap();
|
var bcache = new WeakMap();
|
||||||
function sg_bind(mesh, ssbo) {
|
function sg_bind(mesh, ssbo) {
|
||||||
/* if (cur.bind && cur.mesh === mesh && cur.ssbo === ssbo) {
|
if (cur.bind && cur.mesh === mesh && cur.ssbo === ssbo) {
|
||||||
cur.bind.ssbo = [ssbo];
|
cur.bind.ssbo = [ssbo];
|
||||||
cur.bind.images = cur.images;
|
cur.bind.images = cur.images;
|
||||||
cur.bind.samplers = cur.samplers;
|
cur.bind.samplers = cur.samplers;
|
||||||
console.info(json.encode(cur.bind));
|
|
||||||
render.setbind(cur.bind);
|
render.setbind(cur.bind);
|
||||||
return;
|
return;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/* if (bcache.has(cur.shader) && bcache.get(cur.shader).has(mesh)) {
|
/* if (bcache.has(cur.shader) && bcache.get(cur.shader).has(mesh)) {
|
||||||
cur.bind = bcache.get(cur.shader).get(mesh);
|
cur.bind = bcache.get(cur.shader).get(mesh);
|
||||||
|
@ -870,7 +870,7 @@ render.rectangle = function render_rectangle(lowerleft, upperright, color, shade
|
||||||
|
|
||||||
queued_shader = shader;
|
queued_shader = shader;
|
||||||
queued_pipe = pipe;
|
queued_pipe = pipe;
|
||||||
flush_poly();
|
check_flush(flush_poly);
|
||||||
};
|
};
|
||||||
|
|
||||||
render.rect = function(rect, color, shader, pipe)
|
render.rect = function(rect, color, shader, pipe)
|
||||||
|
@ -1053,9 +1053,6 @@ render.image = function image(image, pos, scale, rotation = 0, color = Color.whi
|
||||||
e.image = image;
|
e.image = image;
|
||||||
e.shade = color;
|
e.shade = color;
|
||||||
|
|
||||||
flush_img();
|
|
||||||
lasttex = undefined;
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
var bb = {};
|
var bb = {};
|
||||||
bb.b = pos.y;
|
bb.b = pos.y;
|
||||||
|
|
|
@ -5,18 +5,29 @@ Object.readonly(audio, "channels");
|
||||||
Object.readonly(audio, "buffer_frames");
|
Object.readonly(audio, "buffer_frames");
|
||||||
|
|
||||||
var sources = [];
|
var sources = [];
|
||||||
|
var pcms = {};
|
||||||
|
|
||||||
|
audio.pcm = function(file)
|
||||||
|
{
|
||||||
|
file = Resources.find_sound(file);
|
||||||
|
if (!file) return;
|
||||||
|
if (pcms[file]) return pcms[file];
|
||||||
|
|
||||||
|
var newpcm = os.make_pcm(file);
|
||||||
|
if (!newpcm) return;
|
||||||
|
pcms[file] = newpcm;
|
||||||
|
newpcm.format(audio.samplerate, audio.channels);
|
||||||
|
return newpcm;
|
||||||
|
}
|
||||||
|
|
||||||
audio.play = function (file, bus = audio.bus.master) {
|
audio.play = function (file, bus = audio.bus.master) {
|
||||||
var filename = file;
|
var pcm = audio.pcm(file);
|
||||||
file = Resources.find_sound(file);
|
if (!pcm) return;
|
||||||
if (!file) {
|
var src = audio.dsp.source(pcm);
|
||||||
console.error(`Cannot play sound ${file}: does not exist.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var src = audio.dsp.source(file);
|
|
||||||
src.plugin(bus);
|
src.plugin(bus);
|
||||||
src.guid = prosperon.guid();
|
src.guid = prosperon.guid();
|
||||||
src.name = file;
|
src.name = file;
|
||||||
|
src._pcm = pcm;
|
||||||
src.type = "source";
|
src.type = "source";
|
||||||
sources.push(src);
|
sources.push(src);
|
||||||
return src;
|
return src;
|
||||||
|
@ -57,7 +68,6 @@ audio.dsp.mix().__proto__.imgui = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
audio.cry = function (file, bus = audio.bus.sfx) {
|
audio.cry = function (file, bus = audio.bus.sfx) {
|
||||||
file = Resources.find_sound(file);
|
|
||||||
var player = audio.play(file, bus);
|
var player = audio.play(file, bus);
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
player.ended = function () {
|
player.ended = function () {
|
||||||
|
@ -86,7 +96,7 @@ audio.music = function (file, fade = 0.5) {
|
||||||
if (song) song.volume = 0;
|
if (song) song.volume = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
file = Resources.find_sound(file);
|
|
||||||
if (!fade) {
|
if (!fade) {
|
||||||
song = audio.play(file, audio.bus.music);
|
song = audio.play(file, audio.bus.music);
|
||||||
song.loop = true;
|
song.loop = true;
|
||||||
|
|
|
@ -13,7 +13,7 @@ void vert()
|
||||||
void frag()
|
void frag()
|
||||||
{
|
{
|
||||||
color = texture(sampler2D(diffuse,smp), uv);
|
color = texture(sampler2D(diffuse,smp), uv);
|
||||||
if (color.a != 0) discard;
|
if (color.a == 0) discard;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ QJSCLASS(gameobject)
|
||||||
QJSCLASS(transform)
|
QJSCLASS(transform)
|
||||||
QJSCLASS(dsp_node)
|
QJSCLASS(dsp_node)
|
||||||
QJSCLASS(texture)
|
QJSCLASS(texture)
|
||||||
|
QJSCLASS(pcm)
|
||||||
QJSCLASS(font)
|
QJSCLASS(font)
|
||||||
QJSCLASS(warp_gravity)
|
QJSCLASS(warp_gravity)
|
||||||
QJSCLASS(warp_damp)
|
QJSCLASS(warp_damp)
|
||||||
|
@ -1127,7 +1128,7 @@ JSC_CCALL(render_make_particle_ssbo,
|
||||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||||
.size = size+desc.size,
|
.size = size+desc.size,
|
||||||
.usage = SG_USAGE_STREAM,
|
.usage = SG_USAGE_STREAM,
|
||||||
.label = "transform buffer"
|
.label = "particle ssbo buffer"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1166,7 +1167,7 @@ JSC_CCALL(render_make_sprite_ssbo,
|
||||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||||
.size = size+desc.size,
|
.size = size+desc.size,
|
||||||
.usage = SG_USAGE_STREAM,
|
.usage = SG_USAGE_STREAM,
|
||||||
.label = "transform buffer"
|
.label = "sprite ssbo buffer"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1995,8 +1996,6 @@ JSValue js_io_chmod(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSC_SCALL(io_save_qoa, save_qoa(str))
|
|
||||||
|
|
||||||
JSC_SCALL(io_pack_start, pack_start(str))
|
JSC_SCALL(io_pack_start, pack_start(str))
|
||||||
JSC_SCALL(io_pack_add, pack_add(str))
|
JSC_SCALL(io_pack_add, pack_add(str))
|
||||||
JSC_CCALL(io_pack_end, pack_end())
|
JSC_CCALL(io_pack_end, pack_end())
|
||||||
|
@ -2018,7 +2017,6 @@ static const JSCFunctionListEntry js_io_funcs[] = {
|
||||||
MIST_FUNC_DEF(io, slurp, 1),
|
MIST_FUNC_DEF(io, slurp, 1),
|
||||||
MIST_FUNC_DEF(io, slurpbytes, 1),
|
MIST_FUNC_DEF(io, slurpbytes, 1),
|
||||||
MIST_FUNC_DEF(io, slurpwrite, 2),
|
MIST_FUNC_DEF(io, slurpwrite, 2),
|
||||||
MIST_FUNC_DEF(io, save_qoa,1),
|
|
||||||
MIST_FUNC_DEF(io, pack_start, 1),
|
MIST_FUNC_DEF(io, pack_start, 1),
|
||||||
MIST_FUNC_DEF(io, pack_add, 1),
|
MIST_FUNC_DEF(io, pack_add, 1),
|
||||||
MIST_FUNC_DEF(io, pack_end, 0),
|
MIST_FUNC_DEF(io, pack_end, 0),
|
||||||
|
@ -2253,17 +2251,39 @@ static const JSCFunctionListEntry js_dsp_node_funcs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
JSC_GETSET(sound, loop, boolean)
|
JSC_GETSET(sound, loop, boolean)
|
||||||
JSC_GETSET(sound, timescale, number)
|
|
||||||
JSC_GETSET(sound, frame, number)
|
JSC_GETSET(sound, frame, number)
|
||||||
JSC_CCALL(sound_frames, return number2js(js2sound(self)->data->frames))
|
JSC_CCALL(sound_frames, return number2js(js2sound(self)->data->frames))
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_sound_funcs[] = {
|
static const JSCFunctionListEntry js_sound_funcs[] = {
|
||||||
CGETSET_ADD(sound, loop),
|
CGETSET_ADD(sound, loop),
|
||||||
CGETSET_ADD(sound, timescale),
|
|
||||||
CGETSET_ADD(sound, frame),
|
CGETSET_ADD(sound, frame),
|
||||||
MIST_FUNC_DEF(sound, frames, 0),
|
MIST_FUNC_DEF(sound, frames, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
JSC_GET(pcm, ch, number)
|
||||||
|
JSC_GET(pcm, samplerate, number)
|
||||||
|
JSC_GET(pcm, frames, number)
|
||||||
|
JSC_CCALL(pcm_format,
|
||||||
|
pcm_format(js2pcm(self), js2number(argv[0]), js2number(argv[1]));
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(pcm_save_qoa,
|
||||||
|
save_qoa(str, js2pcm(self));
|
||||||
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(pcm_save_wav,
|
||||||
|
save_wav(str, js2pcm(self));
|
||||||
|
)
|
||||||
|
|
||||||
|
static const JSCFunctionListEntry js_pcm_funcs[] = {
|
||||||
|
MIST_GET(pcm, ch),
|
||||||
|
MIST_GET(pcm, samplerate),
|
||||||
|
MIST_GET(pcm, frames),
|
||||||
|
MIST_FUNC_DEF(pcm, format, 2),
|
||||||
|
MIST_FUNC_DEF(pcm, save_qoa, 1),
|
||||||
|
MIST_FUNC_DEF(pcm, save_wav, 1)
|
||||||
|
};
|
||||||
|
|
||||||
static JSValue js_window_get_fullscreen(JSContext *js, JSValue self) { return boolean2js(js2window(self)->fullscreen); }
|
static JSValue js_window_get_fullscreen(JSContext *js, JSValue self) { return boolean2js(js2window(self)->fullscreen); }
|
||||||
static JSValue js_window_set_fullscreen(JSContext *js, JSValue self, JSValue v) { window_setfullscreen(js2window(self), js2boolean(v)); return JS_UNDEFINED; }
|
static JSValue js_window_set_fullscreen(JSContext *js, JSValue self, JSValue v) { window_setfullscreen(js2window(self), js2boolean(v)); return JS_UNDEFINED; }
|
||||||
|
|
||||||
|
@ -2663,8 +2683,8 @@ JSC_CCALL(dspsound_delay,
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(dspsound_fwd_delay, return dsp_node2js(dsp_fwd_delay(js2number(argv[0]), js2number(argv[1]))))
|
JSC_CCALL(dspsound_fwd_delay, return dsp_node2js(dsp_fwd_delay(js2number(argv[0]), js2number(argv[1]))))
|
||||||
JSC_SCALL(dspsound_source,
|
JSC_CCALL(dspsound_source,
|
||||||
ret = dsp_node2js(dsp_source(str));
|
ret = dsp_node2js(dsp_source(js2pcm(argv[0])));
|
||||||
JS_SetPrototype(js, ret, sound_proto);
|
JS_SetPrototype(js, ret, sound_proto);
|
||||||
)
|
)
|
||||||
JSC_CCALL(dspsound_mix, return dsp_node2js(make_node(NULL,NULL,NULL)))
|
JSC_CCALL(dspsound_mix, return dsp_node2js(make_node(NULL,NULL,NULL)))
|
||||||
|
@ -3332,6 +3352,10 @@ JSC_SCALL(os_make_texture,
|
||||||
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
JS_SetPropertyStr(js, ret, "path", JS_DupValue(js,argv[0]));
|
||||||
)
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(os_make_pcm,
|
||||||
|
ret = pcm2js(make_pcm(str));
|
||||||
|
)
|
||||||
|
|
||||||
JSC_SCALL(os_make_aseprite,
|
JSC_SCALL(os_make_aseprite,
|
||||||
|
|
||||||
)
|
)
|
||||||
|
@ -3629,6 +3653,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||||
MIST_FUNC_DEF(os, make_poly2d, 2),
|
MIST_FUNC_DEF(os, make_poly2d, 2),
|
||||||
MIST_FUNC_DEF(os, make_seg2d, 1),
|
MIST_FUNC_DEF(os, make_seg2d, 1),
|
||||||
MIST_FUNC_DEF(os, make_texture, 1),
|
MIST_FUNC_DEF(os, make_texture, 1),
|
||||||
|
MIST_FUNC_DEF(os, make_pcm, 1),
|
||||||
MIST_FUNC_DEF(os, texture_swap, 2),
|
MIST_FUNC_DEF(os, texture_swap, 2),
|
||||||
MIST_FUNC_DEF(os, make_tex_data, 3),
|
MIST_FUNC_DEF(os, make_tex_data, 3),
|
||||||
MIST_FUNC_DEF(os, make_font, 2),
|
MIST_FUNC_DEF(os, make_font, 2),
|
||||||
|
@ -3691,6 +3716,7 @@ void ffi_load() {
|
||||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||||
QJSCLASSPREP_FUNCS(warp_damp);
|
QJSCLASSPREP_FUNCS(warp_damp);
|
||||||
QJSCLASSPREP_FUNCS(texture);
|
QJSCLASSPREP_FUNCS(texture);
|
||||||
|
QJSCLASSPREP_FUNCS(pcm);
|
||||||
QJSCLASSPREP_FUNCS(font);
|
QJSCLASSPREP_FUNCS(font);
|
||||||
QJSCLASSPREP_FUNCS(cpConstraint);
|
QJSCLASSPREP_FUNCS(cpConstraint);
|
||||||
QJSCLASSPREP_FUNCS(window);
|
QJSCLASSPREP_FUNCS(window);
|
||||||
|
|
|
@ -366,22 +366,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
), bytes, &p);
|
), bytes, &p);
|
||||||
|
|
||||||
|
|
||||||
for (int c = 0; c < channels; c++) {
|
for (unsigned int c = 0; c < channels; c++) {
|
||||||
/* If the weights have grown too large, reset them to 0. This may happen
|
|
||||||
with certain high-frequency sounds. This is a last resort and will
|
|
||||||
introduce quite a bit of noise, but should at least prevent pops/clicks */
|
|
||||||
int weights_sum =
|
|
||||||
qoa->lms[c].weights[0] * qoa->lms[c].weights[0] +
|
|
||||||
qoa->lms[c].weights[1] * qoa->lms[c].weights[1] +
|
|
||||||
qoa->lms[c].weights[2] * qoa->lms[c].weights[2] +
|
|
||||||
qoa->lms[c].weights[3] * qoa->lms[c].weights[3];
|
|
||||||
if (weights_sum > 0x2fffffff) {
|
|
||||||
qoa->lms[c].weights[0] = 0;
|
|
||||||
qoa->lms[c].weights[1] = 0;
|
|
||||||
qoa->lms[c].weights[2] = 0;
|
|
||||||
qoa->lms[c].weights[3] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the current LMS state */
|
/* Write the current LMS state */
|
||||||
qoa_uint64_t weights = 0;
|
qoa_uint64_t weights = 0;
|
||||||
qoa_uint64_t history = 0;
|
qoa_uint64_t history = 0;
|
||||||
|
@ -395,9 +380,9 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
|
|
||||||
/* We encode all samples with the channels interleaved on a slice level.
|
/* We encode all samples with the channels interleaved on a slice level.
|
||||||
E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/
|
E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/
|
||||||
for (int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) {
|
for (unsigned int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) {
|
||||||
|
|
||||||
for (int c = 0; c < channels; c++) {
|
for (unsigned int c = 0; c < channels; c++) {
|
||||||
int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
|
int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
|
||||||
int slice_start = sample_index * channels + c;
|
int slice_start = sample_index * channels + c;
|
||||||
int slice_end = (sample_index + slice_len) * channels + c;
|
int slice_end = (sample_index + slice_len) * channels + c;
|
||||||
|
@ -405,10 +390,13 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
/* Brute for search for the best scalefactor. Just go through all
|
/* Brute for search for the best scalefactor. Just go through all
|
||||||
16 scalefactors, encode all samples for the current slice and
|
16 scalefactors, encode all samples for the current slice and
|
||||||
meassure the total squared error. */
|
meassure the total squared error. */
|
||||||
|
qoa_uint64_t best_rank = -1;
|
||||||
|
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||||
qoa_uint64_t best_error = -1;
|
qoa_uint64_t best_error = -1;
|
||||||
qoa_uint64_t best_slice;
|
#endif
|
||||||
|
qoa_uint64_t best_slice = 0;
|
||||||
qoa_lms_t best_lms;
|
qoa_lms_t best_lms;
|
||||||
int best_scalefactor;
|
int best_scalefactor = 0;
|
||||||
|
|
||||||
for (int sfi = 0; sfi < 16; sfi++) {
|
for (int sfi = 0; sfi < 16; sfi++) {
|
||||||
/* There is a strong correlation between the scalefactors of
|
/* There is a strong correlation between the scalefactors of
|
||||||
|
@ -421,7 +409,10 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
state when encoding. */
|
state when encoding. */
|
||||||
qoa_lms_t lms = qoa->lms[c];
|
qoa_lms_t lms = qoa->lms[c];
|
||||||
qoa_uint64_t slice = scalefactor;
|
qoa_uint64_t slice = scalefactor;
|
||||||
|
qoa_uint64_t current_rank = 0;
|
||||||
|
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||||
qoa_uint64_t current_error = 0;
|
qoa_uint64_t current_error = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
for (int si = slice_start; si < slice_end; si += channels) {
|
for (int si = slice_start; si < slice_end; si += channels) {
|
||||||
int sample = sample_data[si];
|
int sample = sample_data[si];
|
||||||
|
@ -434,9 +425,27 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
||||||
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
||||||
|
|
||||||
|
|
||||||
|
/* If the weights have grown too large, we introduce a penalty
|
||||||
|
here. This prevents pops/clicks in certain problem cases */
|
||||||
|
int weights_penalty = ((
|
||||||
|
lms.weights[0] * lms.weights[0] +
|
||||||
|
lms.weights[1] * lms.weights[1] +
|
||||||
|
lms.weights[2] * lms.weights[2] +
|
||||||
|
lms.weights[3] * lms.weights[3]
|
||||||
|
) >> 18) - 0x8ff;
|
||||||
|
if (weights_penalty < 0) {
|
||||||
|
weights_penalty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
long long error = (sample - reconstructed);
|
long long error = (sample - reconstructed);
|
||||||
current_error += error * error;
|
qoa_uint64_t error_sq = error * error;
|
||||||
if (current_error > best_error) {
|
|
||||||
|
current_rank += error_sq + weights_penalty * weights_penalty;
|
||||||
|
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||||
|
current_error += error_sq;
|
||||||
|
#endif
|
||||||
|
if (current_rank > best_rank) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +453,11 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
||||||
slice = (slice << 3) | quantized;
|
slice = (slice << 3) | quantized;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_error < best_error) {
|
if (current_rank < best_rank) {
|
||||||
|
best_rank = current_rank;
|
||||||
|
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||||
best_error = current_error;
|
best_error = current_error;
|
||||||
|
#endif
|
||||||
best_slice = slice;
|
best_slice = slice;
|
||||||
best_lms = lms;
|
best_lms = lms;
|
||||||
best_scalefactor = scalefactor;
|
best_scalefactor = scalefactor;
|
||||||
|
@ -490,7 +502,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len)
|
||||||
|
|
||||||
unsigned char *bytes = QOA_MALLOC(encoded_size);
|
unsigned char *bytes = QOA_MALLOC(encoded_size);
|
||||||
|
|
||||||
for (int c = 0; c < qoa->channels; c++) {
|
for (unsigned int c = 0; c < qoa->channels; c++) {
|
||||||
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
||||||
prediction of the first few ms of a file. */
|
prediction of the first few ms of a file. */
|
||||||
qoa->lms[c].weights[0] = 0;
|
qoa->lms[c].weights[0] = 0;
|
||||||
|
@ -513,7 +525,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int frame_len = QOA_FRAME_LEN;
|
int frame_len = QOA_FRAME_LEN;
|
||||||
for (int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) {
|
for (unsigned int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) {
|
||||||
frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index);
|
frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index);
|
||||||
const short *frame_samples = sample_data + sample_index * qoa->channels;
|
const short *frame_samples = sample_data + sample_index * qoa->channels;
|
||||||
unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p);
|
unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p);
|
||||||
|
@ -576,14 +588,14 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa
|
||||||
|
|
||||||
/* Read and verify the frame header */
|
/* Read and verify the frame header */
|
||||||
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
|
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
|
||||||
int channels = (frame_header >> 56) & 0x0000ff;
|
unsigned int channels = (frame_header >> 56) & 0x0000ff;
|
||||||
int samplerate = (frame_header >> 32) & 0xffffff;
|
unsigned int samplerate = (frame_header >> 32) & 0xffffff;
|
||||||
int samples = (frame_header >> 16) & 0x00ffff;
|
unsigned int samples = (frame_header >> 16) & 0x00ffff;
|
||||||
int frame_size = (frame_header ) & 0x00ffff;
|
unsigned int frame_size = (frame_header ) & 0x00ffff;
|
||||||
|
|
||||||
int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels;
|
unsigned int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels;
|
||||||
int num_slices = data_size / 8;
|
unsigned int num_slices = data_size / 8;
|
||||||
int max_total_samples = num_slices * QOA_SLICE_LEN;
|
unsigned int max_total_samples = num_slices * QOA_SLICE_LEN;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
channels != qoa->channels ||
|
channels != qoa->channels ||
|
||||||
|
@ -596,7 +608,7 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa
|
||||||
|
|
||||||
|
|
||||||
/* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */
|
/* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */
|
||||||
for (int c = 0; c < channels; c++) {
|
for (unsigned int c = 0; c < channels; c++) {
|
||||||
qoa_uint64_t history = qoa_read_u64(bytes, &p);
|
qoa_uint64_t history = qoa_read_u64(bytes, &p);
|
||||||
qoa_uint64_t weights = qoa_read_u64(bytes, &p);
|
qoa_uint64_t weights = qoa_read_u64(bytes, &p);
|
||||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||||
|
@ -609,17 +621,19 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa
|
||||||
|
|
||||||
|
|
||||||
/* Decode all slices for all channels in this frame */
|
/* Decode all slices for all channels in this frame */
|
||||||
for (int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) {
|
for (unsigned int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) {
|
||||||
for (int c = 0; c < channels; c++) {
|
for (unsigned int c = 0; c < channels; c++) {
|
||||||
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
|
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
|
||||||
|
|
||||||
int scalefactor = (slice >> 60) & 0xf;
|
int scalefactor = (slice >> 60) & 0xf;
|
||||||
|
slice <<= 4;
|
||||||
|
|
||||||
int slice_start = sample_index * channels + c;
|
int slice_start = sample_index * channels + c;
|
||||||
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
|
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
|
||||||
|
|
||||||
for (int si = slice_start; si < slice_end; si += channels) {
|
for (int si = slice_start; si < slice_end; si += channels) {
|
||||||
int predicted = qoa_lms_predict(&qoa->lms[c]);
|
int predicted = qoa_lms_predict(&qoa->lms[c]);
|
||||||
int quantized = (slice >> 57) & 0x7;
|
int quantized = (slice >> 61) & 0x7;
|
||||||
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
||||||
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
||||||
|
|
||||||
|
|
|
@ -49,15 +49,19 @@ void *zipbuf;
|
||||||
|
|
||||||
sfetch_handle_t game_h;
|
sfetch_handle_t game_h;
|
||||||
|
|
||||||
|
#define MAXGAMESIZE 15*1024*1024
|
||||||
|
|
||||||
static void response_cb(const sfetch_response_t *r)
|
static void response_cb(const sfetch_response_t *r)
|
||||||
{
|
{
|
||||||
if (r->fetched) {
|
if (r->fetched) {
|
||||||
|
YughInfo("FINISHED FETCH\n");
|
||||||
zipbuf = malloc(r->data.size);
|
zipbuf = malloc(r->data.size);
|
||||||
memcpy(zipbuf, r->data.ptr, r->data.size);
|
memcpy(zipbuf, r->data.ptr, r->data.size);
|
||||||
mz_zip_reader_init_mem(&game_cdb, zipbuf, r->data.size,0);
|
mz_zip_reader_init_mem(&game_cdb, zipbuf, r->data.size,0);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (r->finished) {
|
if (r->finished) {
|
||||||
|
YughInfo("FINISHED RESPONSE\n");
|
||||||
LOADED_GAME = 1;
|
LOADED_GAME = 1;
|
||||||
void *buf = sfetch_unbind_buffer(r->handle);
|
void *buf = sfetch_unbind_buffer(r->handle);
|
||||||
free(buf);
|
free(buf);
|
||||||
|
@ -78,13 +82,14 @@ void resources_init() {
|
||||||
mz_zip_reader_init_mem(&corecdb, core_cdb, core_cdb_len, 0);
|
mz_zip_reader_init_mem(&corecdb, core_cdb, core_cdb_len, 0);
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
gamebuf = malloc(8*1024*1024);
|
gamebuf = malloc(MAXGAMESIZE);
|
||||||
|
YughInfo("GRABBING GAME.ZIP\n");
|
||||||
game_h = sfetch_send(&(sfetch_request_t){
|
game_h = sfetch_send(&(sfetch_request_t){
|
||||||
.path="game.zip",
|
.path="game.zip",
|
||||||
.callback = response_cb,
|
.callback = response_cb,
|
||||||
.buffer = {
|
.buffer = {
|
||||||
.ptr = gamebuf,
|
.ptr = gamebuf,
|
||||||
.size = 8*1024*1024
|
.size = MAXGAMESIZE
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -336,29 +336,6 @@ dsp_node *dsp_pitchshift(float octaves)
|
||||||
return make_node(oct, filter_pitchshift, NULL);
|
return make_node(oct, filter_pitchshift, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timescale
|
|
||||||
{
|
|
||||||
float rate;
|
|
||||||
SRC_STATE *src;
|
|
||||||
};
|
|
||||||
|
|
||||||
static long *src_cb(struct timescale *ts, float **data)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void filter_timescale(struct timescale *ts, soundbyte *buffer, int frames)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
dsp_node *dsp_timescale(float scale)
|
|
||||||
{
|
|
||||||
struct timescale *ts = malloc(sizeof(*ts));
|
|
||||||
ts->rate = scale;
|
|
||||||
ts->src = src_callback_new(src_cb, SRC_SINC_FASTEST, scale, NULL, ts);
|
|
||||||
return make_node(ts, filter_timescale, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
soundbyte iir_filter(struct dsp_iir iir, soundbyte val)
|
soundbyte iir_filter(struct dsp_iir iir, soundbyte val)
|
||||||
{
|
{
|
||||||
iir.y[0] = 0.0;
|
iir.y[0] = 0.0;
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
#include "samplerate.h"
|
|
||||||
|
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
|
@ -31,7 +29,6 @@ pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
||||||
#define TML_IMPLEMENTATION
|
#define TML_IMPLEMENTATION
|
||||||
#include "tml.h"
|
#include "tml.h"
|
||||||
|
|
||||||
#define DR_WAV_NO_STDIO
|
|
||||||
#define DR_WAV_IMPLEMENTATION
|
#define DR_WAV_IMPLEMENTATION
|
||||||
#include "dr_wav.h"
|
#include "dr_wav.h"
|
||||||
|
|
||||||
|
@ -48,17 +45,23 @@ pthread_mutex_t soundrun = PTHREAD_MUTEX_INITIALIZER;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NQOA
|
#ifndef NQOA
|
||||||
#define QOA_NO_STDIO
|
|
||||||
#define QOA_IMPLEMENTATION
|
#define QOA_IMPLEMENTATION
|
||||||
#include "qoa.h"
|
#include "qoa.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct {
|
void short_to_float_array(const short *in, float *out, int frames, int channels)
|
||||||
char *key;
|
{
|
||||||
struct wav *value;
|
for (int i = 0; i < frames * channels; i++)
|
||||||
} *wavhash = NULL;
|
out[i] = (float)in[i] / 32768.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void change_channels(struct wav *w, int ch) {
|
void float_to_short_array(float *in, short *out, int frames, int channels)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < frames*channels; i++)
|
||||||
|
out[i] = (float)in[i]*32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
void change_channels(struct pcm *w, int ch) {
|
||||||
if (w->ch == ch) return;
|
if (w->ch == ch) return;
|
||||||
soundbyte *data = w->data;
|
soundbyte *data = w->data;
|
||||||
int samples = ch * w->frames;
|
int samples = ch * w->frames;
|
||||||
|
@ -81,26 +84,30 @@ void change_channels(struct wav *w, int ch) {
|
||||||
w->data = new;
|
w->data = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resample(soundbyte *in, soundbyte *out, int in_frames, int out_frames, int channels)
|
void resample_pcm(soundbyte *in, soundbyte *out, int in_frames, int out_frames, int channels)
|
||||||
{
|
{
|
||||||
float ratio = (float)in_frames / out_frames;
|
float ratio = (float)in_frames / out_frames;
|
||||||
SRC_DATA ssrc;
|
for (int i = 0; i < out_frames; i++) {
|
||||||
ssrc.data_in = in;
|
// Find the position in the input buffer.
|
||||||
ssrc.data_out = out;
|
float in_pos = i * ratio;
|
||||||
ssrc.input_frames = in_frames;
|
int in_index = (int)in_pos; // Get the integer part of the position.
|
||||||
ssrc.output_frames = out_frames;
|
float frac = in_pos - in_index; // Get the fractional part for interpolation.
|
||||||
ssrc.src_ratio = ratio;
|
|
||||||
int err = src_simple(&ssrc, SRC_LINEAR, channels);
|
for (int ch = 0; ch < channels; ch++) {
|
||||||
if (err)
|
// Linear interpolation between two input samples.
|
||||||
YughError("Resampling error code %d: %s", err, src_strerror(err));
|
soundbyte sample1 = in[in_index * channels + ch];
|
||||||
|
soundbyte sample2 = in[(in_index + 1) * channels + ch];
|
||||||
|
out[i * channels + ch] = (soundbyte)((1.0f - frac) * sample1 + frac * sample2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void change_samplerate(struct wav *w, int rate) {
|
void change_samplerate(struct pcm *w, int rate) {
|
||||||
if (rate == w->samplerate) return;
|
if (rate == w->samplerate) return;
|
||||||
float ratio = (float)rate / w->samplerate;
|
float ratio = (float)rate / w->samplerate;
|
||||||
int outframes = w->frames * ratio;
|
int outframes = w->frames * ratio;
|
||||||
soundbyte *resampled = malloc(w->ch*outframes*sizeof(soundbyte));
|
soundbyte *resampled = malloc(w->ch*outframes*sizeof(soundbyte));
|
||||||
resample(w->data, resampled, w->frames, outframes, w->ch);
|
resample_pcm(w->data, resampled, w->frames, outframes, w->ch);
|
||||||
free(w->data);
|
free(w->data);
|
||||||
|
|
||||||
w->data = resampled;
|
w->data = resampled;
|
||||||
|
@ -143,30 +150,8 @@ void sound_init() {
|
||||||
BUF_FRAMES = saudio_buffer_frames();
|
BUF_FRAMES = saudio_buffer_frames();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
struct pcm *make_pcm(const char *wav) {
|
||||||
int channels;
|
if (!wav) return NULL;
|
||||||
int samplerate;
|
|
||||||
void *f;
|
|
||||||
} stream;
|
|
||||||
|
|
||||||
void mp3_filter(stream *mp3, soundbyte *buffer, int frames)
|
|
||||||
{
|
|
||||||
if (mp3->samplerate == SAMPLERATE) {
|
|
||||||
drmp3_read_pcm_frames_f32(mp3->f, frames, buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int in_frames = (float)mp3->samplerate/SAMPLERATE;
|
|
||||||
soundbyte *decode = malloc(sizeof(*decode)*in_frames*mp3->channels);
|
|
||||||
drmp3_read_pcm_frames_f32(mp3->f, in_frames, decode);
|
|
||||||
resample(decode, buffer, in_frames, frames, CHANNELS);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct wav *make_sound(const char *wav) {
|
|
||||||
int index = shgeti(wavhash, wav);
|
|
||||||
if (index != -1)
|
|
||||||
return wavhash[index].value;
|
|
||||||
|
|
||||||
char *ext = strrchr(wav, '.')+1;
|
char *ext = strrchr(wav, '.')+1;
|
||||||
|
|
||||||
if(!ext) {
|
if(!ext) {
|
||||||
|
@ -174,14 +159,15 @@ struct wav *make_sound(const char *wav) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wav *mwav = malloc(sizeof(*mwav));
|
|
||||||
size_t rawlen;
|
size_t rawlen;
|
||||||
void *raw = slurp_file(wav, &rawlen);
|
void *raw = slurp_file(wav, &rawlen);
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
YughError("Could not find file %s.", wav);
|
YughWarn("Could not find file %s.", wav);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pcm *mwav = malloc(sizeof(*mwav));
|
||||||
|
|
||||||
if (!strcmp(ext, "wav"))
|
if (!strcmp(ext, "wav"))
|
||||||
mwav->data = drwav_open_memory_and_read_pcm_frames_f32(raw, rawlen, &mwav->ch, &mwav->samplerate, &mwav->frames, NULL);
|
mwav->data = drwav_open_memory_and_read_pcm_frames_f32(raw, rawlen, &mwav->ch, &mwav->samplerate, &mwav->frames, NULL);
|
||||||
else if (!strcmp(ext, "flac")) {
|
else if (!strcmp(ext, "flac")) {
|
||||||
|
@ -207,9 +193,9 @@ struct wav *make_sound(const char *wav) {
|
||||||
short *qoa_data = qoa_decode(raw, rawlen, &qoa);
|
short *qoa_data = qoa_decode(raw, rawlen, &qoa);
|
||||||
mwav->ch = qoa.channels;
|
mwav->ch = qoa.channels;
|
||||||
mwav->samplerate = qoa.samplerate;
|
mwav->samplerate = qoa.samplerate;
|
||||||
mwav->frames = qoa.samples;
|
mwav->frames = qoa.samples/mwav->ch;
|
||||||
mwav->data = malloc(sizeof(soundbyte) * mwav->frames * mwav->ch);
|
mwav->data = malloc(sizeof(soundbyte) * mwav->frames * mwav->ch);
|
||||||
src_short_to_float_array(qoa_data, mwav->data, mwav->frames*mwav->ch);
|
short_to_float_array(qoa_data, mwav->data, mwav->frames,mwav->ch);
|
||||||
free(qoa_data);
|
free(qoa_data);
|
||||||
#else
|
#else
|
||||||
YughWarn("Could not load %s because Primum was built without QOA support.", wav);
|
YughWarn("Could not load %s because Primum was built without QOA support.", wav);
|
||||||
|
@ -222,38 +208,47 @@ struct wav *make_sound(const char *wav) {
|
||||||
}
|
}
|
||||||
free(raw);
|
free(raw);
|
||||||
|
|
||||||
change_samplerate(mwav, SAMPLERATE);
|
|
||||||
change_channels(mwav, CHANNELS);
|
|
||||||
|
|
||||||
if (shlen(wavhash) == 0) sh_new_arena(wavhash);
|
|
||||||
shput(wavhash, wav, mwav);
|
|
||||||
|
|
||||||
return mwav;
|
return mwav;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_qoa(char *file)
|
void pcm_format(pcm *pcm, int samplerate, int channels)
|
||||||
{
|
{
|
||||||
wav *wav = make_sound(file);
|
change_samplerate(pcm, samplerate);
|
||||||
qoa_desc q;
|
change_channels(pcm, channels);
|
||||||
q.channels = wav->ch;
|
|
||||||
q.samples = wav->frames;
|
|
||||||
q.samplerate = wav->samplerate;
|
|
||||||
unsigned int len;
|
|
||||||
void *raw = qoa_encode(wav->data, &q, &len);
|
|
||||||
|
|
||||||
file = str_replace_ext(file, ".qoa");
|
|
||||||
slurp_write(raw, file, len);
|
|
||||||
free(raw);
|
|
||||||
free_sound(wav);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_sound(const char *wav) {
|
void save_qoa(char *file, pcm *pcm)
|
||||||
struct wav *w = shget(wavhash, wav);
|
{
|
||||||
if (w == NULL) return;
|
qoa_desc q;
|
||||||
|
short *out = malloc(sizeof(short)*pcm->ch*pcm->frames);
|
||||||
|
float_to_short_array(pcm->data, out, pcm->frames, pcm->ch);
|
||||||
|
q.channels = pcm->ch;
|
||||||
|
q.samples = pcm->frames;
|
||||||
|
q.samplerate = pcm->samplerate;
|
||||||
|
int encoded = qoa_write(file, out, &q);
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
|
||||||
free(w->data);
|
void save_wav(char *file, pcm *pcm)
|
||||||
free(w);
|
{
|
||||||
shdel(wavhash, wav);
|
drwav wav;
|
||||||
|
drwav_data_format fmt = {0};
|
||||||
|
fmt.format = DR_WAVE_FORMAT_PCM;
|
||||||
|
fmt.channels = pcm->ch;
|
||||||
|
fmt.sampleRate = pcm->samplerate;
|
||||||
|
fmt.bitsPerSample = 32;
|
||||||
|
drwav_int32 *out = malloc(sizeof(*out)*pcm->ch*pcm->frames);
|
||||||
|
drwav_f32_to_s32(out, pcm->data, pcm->frames*pcm->ch);
|
||||||
|
drwav_init_file_write_sequential_pcm_frames(&wav, file, &fmt, pcm->frames, NULL);
|
||||||
|
drwav_write_pcm_frames(&wav, pcm->frames, out);
|
||||||
|
drwav_uninit(&wav);
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcm_free(pcm *pcm)
|
||||||
|
{
|
||||||
|
free(pcm->data);
|
||||||
|
free(pcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
||||||
|
@ -265,11 +260,6 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
||||||
else
|
else
|
||||||
end = 1;
|
end = 1;
|
||||||
|
|
||||||
if (s->timescale != 1) {
|
|
||||||
src_callback_read(s->src, s->timescale, frames, buf);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
soundbyte *in = s->data->data;
|
soundbyte *in = s->data->data;
|
||||||
|
|
||||||
for (int i = 0; i < frames; i++) {
|
for (int i = 0; i < frames; i++) {
|
||||||
|
@ -287,26 +277,16 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
|
||||||
|
|
||||||
void free_source(struct sound *s)
|
void free_source(struct sound *s)
|
||||||
{
|
{
|
||||||
src_delete(s->src);
|
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long src_cb(struct sound *s, float **data)
|
struct dsp_node *dsp_source(pcm *pcm)
|
||||||
{
|
|
||||||
long needed = BUF_FRAMES/s->timescale;
|
|
||||||
*data = s->data->data+s->frame;
|
|
||||||
s->frame += needed;
|
|
||||||
return needed;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dsp_node *dsp_source(const char *path)
|
|
||||||
{
|
{
|
||||||
|
if (!pcm) return NULL;
|
||||||
struct sound *self = malloc(sizeof(*self));
|
struct sound *self = malloc(sizeof(*self));
|
||||||
self->frame = 0;
|
self->frame = 0;
|
||||||
self->data = make_sound(path);
|
self->data = pcm;
|
||||||
self->loop = false;
|
self->loop = false;
|
||||||
self->src = src_callback_new(src_cb, SRC_SINC_MEDIUM_QUALITY, 2, NULL, self);
|
|
||||||
self->timescale = 1;
|
|
||||||
dsp_node *n = make_node(self, sound_fillbuf, free_source);
|
dsp_node *n = make_node(self, sound_fillbuf, free_source);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
@ -315,16 +295,6 @@ int sound_finished(const struct sound *s) {
|
||||||
return s->frame == s->data->frames;
|
return s->frame == s->data->frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mp3 make_music(const char *mp3) {
|
|
||||||
// drmp3 new;
|
|
||||||
// if (!drmp3_init_file(&new, mp3, NULL)) {
|
|
||||||
// YughError("Could not open mp3 file %s.", mp3);
|
|
||||||
// }
|
|
||||||
|
|
||||||
struct mp3 newmp3 = {};
|
|
||||||
return newmp3;
|
|
||||||
}
|
|
||||||
|
|
||||||
float short2db(short val) {
|
float short2db(short val) {
|
||||||
return 20 * log10(abs(val) / SHRT_MAX);
|
return 20 * log10(abs(val) / SHRT_MAX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define SOUND_H
|
#define SOUND_H
|
||||||
|
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
#include "samplerate.h"
|
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
|
|
||||||
typedef float soundbyte;
|
typedef float soundbyte;
|
||||||
|
@ -13,39 +12,32 @@ struct dsp_node;
|
||||||
/* A bookmark into a wav, actually playing the sound */
|
/* A bookmark into a wav, actually playing the sound */
|
||||||
typedef struct sound {
|
typedef struct sound {
|
||||||
unsigned int frame; /* Pointing to the current frame on the wav */
|
unsigned int frame; /* Pointing to the current frame on the wav */
|
||||||
struct wav *data;
|
struct pcm *data;
|
||||||
int loop;
|
int loop;
|
||||||
float timescale;
|
|
||||||
SRC_STATE *src;
|
|
||||||
} sound;
|
} sound;
|
||||||
|
|
||||||
/* Represents a sound file source, fulled loaded*/
|
/* Represents a sound file source, fulled loaded*/
|
||||||
typedef struct wav {
|
typedef struct pcm {
|
||||||
unsigned int ch;
|
unsigned int ch;
|
||||||
unsigned int samplerate;
|
unsigned int samplerate;
|
||||||
unsigned long long frames;
|
unsigned long long frames;
|
||||||
soundbyte *data;
|
soundbyte *data;
|
||||||
} wav;
|
} pcm;
|
||||||
|
|
||||||
/* Represents a sound file stream */
|
|
||||||
typedef struct mp3 {
|
|
||||||
|
|
||||||
} mp3;
|
|
||||||
|
|
||||||
void sound_init();
|
void sound_init();
|
||||||
void audio_open(const char *device);
|
void audio_open(const char *device);
|
||||||
void audio_close();
|
void audio_close();
|
||||||
|
|
||||||
struct wav *make_sound(const char *wav);
|
struct pcm *make_pcm(const char *file);
|
||||||
void free_sound(const char *wav);
|
void pcm_free(pcm *pcm);
|
||||||
void wav_norm_gain(struct wav *w, double lv);
|
void pcm_norm_gain(struct pcm *w, double lv);
|
||||||
struct dsp_node *dsp_source(const char *path);
|
void pcm_format(pcm *pcm, int samplerate, int channels);
|
||||||
|
|
||||||
|
struct dsp_node *dsp_source(pcm *pcm);
|
||||||
struct dsp_node *dsp_mod(const char *path);
|
struct dsp_node *dsp_mod(const char *path);
|
||||||
|
|
||||||
int sound_finished(const struct sound *s);
|
int sound_finished(const struct sound *s);
|
||||||
|
|
||||||
struct mp3 make_mp3(const char *mp3);
|
|
||||||
|
|
||||||
float short2db(short val);
|
float short2db(short val);
|
||||||
short db2short(float db);
|
short db2short(float db);
|
||||||
short short_gain(short val, float db);
|
short short_gain(short val, float db);
|
||||||
|
@ -56,6 +48,7 @@ float db2float(float db);
|
||||||
float pct2db(float pct);
|
float pct2db(float pct);
|
||||||
float pct2mult(float pct);
|
float pct2mult(float pct);
|
||||||
|
|
||||||
void save_qoa(char *file);
|
void save_qoa(char *file, pcm *pcm);
|
||||||
|
void save_wav(char *file, pcm *pcm);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
/*
|
|
||||||
** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** This code is released under 2-clause BSD license. Please see the
|
|
||||||
** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
** API documentation is available here:
|
|
||||||
** http://libsndfile.github.io/libsamplerate/api.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SAMPLERATE_H
|
|
||||||
#define SAMPLERATE_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
/* Opaque data type SRC_STATE. */
|
|
||||||
typedef struct SRC_STATE_tag SRC_STATE ;
|
|
||||||
|
|
||||||
/* SRC_DATA is used to pass data to src_simple() and src_process(). */
|
|
||||||
typedef struct
|
|
||||||
{ const float *data_in ;
|
|
||||||
float *data_out ;
|
|
||||||
|
|
||||||
long input_frames, output_frames ;
|
|
||||||
long input_frames_used, output_frames_gen ;
|
|
||||||
|
|
||||||
int end_of_input ;
|
|
||||||
|
|
||||||
double src_ratio ;
|
|
||||||
} SRC_DATA ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** User supplied callback function type for use with src_callback_new()
|
|
||||||
** and src_callback_read(). First parameter is the same pointer that was
|
|
||||||
** passed into src_callback_new(). Second parameter is pointer to a
|
|
||||||
** pointer. The user supplied callback function must modify *data to
|
|
||||||
** point to the start of the user supplied float array. The user supplied
|
|
||||||
** function must return the number of frames that **data points to.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef long (*src_callback_t) (void *cb_data, float **data) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Standard initialisation function : return an anonymous pointer to the
|
|
||||||
** internal state of the converter. Choose a converter from the enums below.
|
|
||||||
** Error returned in *error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SRC_STATE* src_new (int converter_type, int channels, int *error) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Clone a handle : return an anonymous pointer to a new converter
|
|
||||||
** containing the same internal state as orig. Error returned in *error.
|
|
||||||
*/
|
|
||||||
SRC_STATE* src_clone (SRC_STATE* orig, int *error) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Initilisation for callback based API : return an anonymous pointer to the
|
|
||||||
** internal state of the converter. Choose a converter from the enums below.
|
|
||||||
** The cb_data pointer can point to any data or be set to NULL. Whatever the
|
|
||||||
** value, when processing, user supplied function "func" gets called with
|
|
||||||
** cb_data as first parameter.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SRC_STATE* src_callback_new (src_callback_t func, int converter_type, int channels,
|
|
||||||
int *error, void* cb_data) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Cleanup all internal allocations.
|
|
||||||
** Always returns NULL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SRC_STATE* src_delete (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Standard processing function.
|
|
||||||
** Returns non zero on error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_process (SRC_STATE *state, SRC_DATA *data) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Callback based processing function. Read up to frames worth of data from
|
|
||||||
** the converter int *data and return frames read or -1 on error.
|
|
||||||
*/
|
|
||||||
long src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Simple interface for performing a single conversion from input buffer to
|
|
||||||
** output buffer at a fixed conversion ratio.
|
|
||||||
** Simple interface does not require initialisation as it can only operate on
|
|
||||||
** a single buffer worth of audio.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_simple (SRC_DATA *data, int converter_type, int channels) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This library contains a number of different sample rate converters,
|
|
||||||
** numbered 0 through N.
|
|
||||||
**
|
|
||||||
** Return a string giving either a name or a more full description of each
|
|
||||||
** sample rate converter or NULL if no sample rate converter exists for
|
|
||||||
** the given value. The converters are sequentially numbered from 0 to N.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const char *src_get_name (int converter_type) ;
|
|
||||||
const char *src_get_description (int converter_type) ;
|
|
||||||
const char *src_get_version (void) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Set a new SRC ratio. This allows step responses
|
|
||||||
** in the conversion ratio.
|
|
||||||
** Returns non zero on error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_set_ratio (SRC_STATE *state, double new_ratio) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Get the current channel count.
|
|
||||||
** Returns negative on error, positive channel count otherwise
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_get_channels (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Reset the internal SRC state.
|
|
||||||
** Does not modify the quality settings.
|
|
||||||
** Does not free any memory allocations.
|
|
||||||
** Returns non zero on error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_reset (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return TRUE if ratio is a valid conversion ratio, FALSE
|
|
||||||
** otherwise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_is_valid_ratio (double ratio) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Return an error number.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int src_error (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Convert the error number into a string.
|
|
||||||
*/
|
|
||||||
const char* src_strerror (int error) ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** The following enums can be used to set the interpolator type
|
|
||||||
** using the function src_set_converter().
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SRC_SINC_BEST_QUALITY = 0,
|
|
||||||
SRC_SINC_MEDIUM_QUALITY = 1,
|
|
||||||
SRC_SINC_FASTEST = 2,
|
|
||||||
SRC_ZERO_ORDER_HOLD = 3,
|
|
||||||
SRC_LINEAR = 4,
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Extra helper functions for converting from short to float and
|
|
||||||
** back again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void src_short_to_float_array (const short *in, float *out, int len) ;
|
|
||||||
void src_float_to_short_array (const float *in, short *out, int len) ;
|
|
||||||
|
|
||||||
void src_int_to_float_array (const int *in, float *out, int len) ;
|
|
||||||
void src_float_to_int_array (const float *in, int *out, int len) ;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
} /* extern "C" */
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* SAMPLERATE_H */
|
|
||||||
|
|
218
source/engine/thirdparty/libsamplerate/src/common.h
vendored
218
source/engine/thirdparty/libsamplerate/src/common.h
vendored
|
@ -1,218 +0,0 @@
|
||||||
/*
|
|
||||||
** Copyright (c) 2002-2021, Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** This code is released under 2-clause BSD license. Please see the
|
|
||||||
** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef COMMON_H_INCLUDED
|
|
||||||
#define COMMON_H_INCLUDED
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#ifdef HAVE_STDBOOL_H
|
|
||||||
#include <stdbool.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAVE_IMMINTRIN_H
|
|
||||||
#include <immintrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Uncomment to enable specific converters */
|
|
||||||
//#define ENABLE_SINC_BEST_CONVERTER
|
|
||||||
//#define ENABLE_SINC_FAST_CONVERTER
|
|
||||||
//#define ENABLE_SINC_MEDIUM_CONVERTER
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_VISIBILITY
|
|
||||||
#define LIBSAMPLERATE_DLL_PRIVATE __attribute__ ((visibility ("hidden")))
|
|
||||||
#elif defined (__APPLE__)
|
|
||||||
#define LIBSAMPLERATE_DLL_PRIVATE __private_extern__
|
|
||||||
#else
|
|
||||||
#define LIBSAMPLERATE_DLL_PRIVATE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SRC_MAX_RATIO 256
|
|
||||||
#define SRC_MAX_RATIO_STR "256"
|
|
||||||
|
|
||||||
#define SRC_MIN_RATIO_DIFF (1e-20)
|
|
||||||
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0])))
|
|
||||||
#define OFFSETOF(type,member) ((int) (&((type*) 0)->member))
|
|
||||||
|
|
||||||
#define MAKE_MAGIC(a,b,c,d,e,f) ((a) + ((b) << 4) + ((c) << 8) + ((d) << 12) + ((e) << 16) + ((f) << 20))
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Inspiration : http://sourcefrog.net/weblog/software/languages/C/unused.html
|
|
||||||
*/
|
|
||||||
#ifdef UNUSED
|
|
||||||
#elif defined (__GNUC__)
|
|
||||||
# define UNUSED(x) UNUSED_ ## x __attribute__ ((unused))
|
|
||||||
#elif defined (__LCLINT__)
|
|
||||||
# define UNUSED(x) /*@unused@*/ x
|
|
||||||
#else
|
|
||||||
# define UNUSED(x) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
# define WARN_UNUSED __attribute__ ((warn_unused_result))
|
|
||||||
#else
|
|
||||||
# define WARN_UNUSED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "samplerate.h"
|
|
||||||
|
|
||||||
enum
|
|
||||||
{ SRC_FALSE = 0,
|
|
||||||
SRC_TRUE = 1,
|
|
||||||
} ;
|
|
||||||
|
|
||||||
enum SRC_MODE
|
|
||||||
{
|
|
||||||
SRC_MODE_PROCESS = 0,
|
|
||||||
SRC_MODE_CALLBACK = 1
|
|
||||||
} ;
|
|
||||||
|
|
||||||
typedef enum SRC_ERROR
|
|
||||||
{
|
|
||||||
SRC_ERR_NO_ERROR = 0,
|
|
||||||
|
|
||||||
SRC_ERR_MALLOC_FAILED,
|
|
||||||
SRC_ERR_BAD_STATE,
|
|
||||||
SRC_ERR_BAD_DATA,
|
|
||||||
SRC_ERR_BAD_DATA_PTR,
|
|
||||||
SRC_ERR_NO_PRIVATE,
|
|
||||||
SRC_ERR_BAD_SRC_RATIO,
|
|
||||||
SRC_ERR_BAD_PROC_PTR,
|
|
||||||
SRC_ERR_SHIFT_BITS,
|
|
||||||
SRC_ERR_FILTER_LEN,
|
|
||||||
SRC_ERR_BAD_CONVERTER,
|
|
||||||
SRC_ERR_BAD_CHANNEL_COUNT,
|
|
||||||
SRC_ERR_SINC_BAD_BUFFER_LEN,
|
|
||||||
SRC_ERR_SIZE_INCOMPATIBILITY,
|
|
||||||
SRC_ERR_BAD_PRIV_PTR,
|
|
||||||
SRC_ERR_BAD_SINC_STATE,
|
|
||||||
SRC_ERR_DATA_OVERLAP,
|
|
||||||
SRC_ERR_BAD_CALLBACK,
|
|
||||||
SRC_ERR_BAD_MODE,
|
|
||||||
SRC_ERR_NULL_CALLBACK,
|
|
||||||
SRC_ERR_NO_VARIABLE_RATIO,
|
|
||||||
SRC_ERR_SINC_PREPARE_DATA_BAD_LEN,
|
|
||||||
SRC_ERR_BAD_INTERNAL_STATE,
|
|
||||||
|
|
||||||
/* This must be the last error number. */
|
|
||||||
SRC_ERR_MAX_ERROR
|
|
||||||
} SRC_ERROR ;
|
|
||||||
|
|
||||||
typedef struct SRC_STATE_VT_tag
|
|
||||||
{
|
|
||||||
/* Varispeed process function. */
|
|
||||||
SRC_ERROR (*vari_process) (SRC_STATE *state, SRC_DATA *data) ;
|
|
||||||
|
|
||||||
/* Constant speed process function. */
|
|
||||||
SRC_ERROR (*const_process) (SRC_STATE *state, SRC_DATA *data) ;
|
|
||||||
|
|
||||||
/* State reset. */
|
|
||||||
void (*reset) (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/* State clone. */
|
|
||||||
SRC_STATE *(*copy) (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/* State close. */
|
|
||||||
void (*close) (SRC_STATE *state) ;
|
|
||||||
} SRC_STATE_VT ;
|
|
||||||
|
|
||||||
struct SRC_STATE_tag
|
|
||||||
{
|
|
||||||
SRC_STATE_VT *vt ;
|
|
||||||
|
|
||||||
double last_ratio, last_position ;
|
|
||||||
|
|
||||||
SRC_ERROR error ;
|
|
||||||
int channels ;
|
|
||||||
|
|
||||||
/* SRC_MODE_PROCESS or SRC_MODE_CALLBACK */
|
|
||||||
enum SRC_MODE mode ;
|
|
||||||
|
|
||||||
/* Data specific to SRC_MODE_CALLBACK. */
|
|
||||||
src_callback_t callback_func ;
|
|
||||||
void *user_callback_data ;
|
|
||||||
long saved_frames ;
|
|
||||||
const float *saved_data ;
|
|
||||||
|
|
||||||
/* Pointer to data to converter specific data. */
|
|
||||||
void *private_data ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* In src_sinc.c */
|
|
||||||
const char* sinc_get_name (int src_enum) ;
|
|
||||||
const char* sinc_get_description (int src_enum) ;
|
|
||||||
|
|
||||||
SRC_STATE *sinc_state_new (int converter_type, int channels, SRC_ERROR *error) ;
|
|
||||||
|
|
||||||
/* In src_linear.c */
|
|
||||||
const char* linear_get_name (int src_enum) ;
|
|
||||||
const char* linear_get_description (int src_enum) ;
|
|
||||||
|
|
||||||
SRC_STATE *linear_state_new (int channels, SRC_ERROR *error) ;
|
|
||||||
|
|
||||||
/* In src_zoh.c */
|
|
||||||
const char* zoh_get_name (int src_enum) ;
|
|
||||||
const char* zoh_get_description (int src_enum) ;
|
|
||||||
|
|
||||||
SRC_STATE *zoh_state_new (int channels, SRC_ERROR *error) ;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
|
||||||
** SIMD optimized math functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline int psf_lrintf (float x)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_IMMINTRIN_H
|
|
||||||
return _mm_cvtss_si32 (_mm_load_ss (&x)) ;
|
|
||||||
#else
|
|
||||||
return lrintf (x) ;
|
|
||||||
#endif
|
|
||||||
} /* psf_lrintf */
|
|
||||||
|
|
||||||
static inline int psf_lrint (double x)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_IMMINTRIN_H
|
|
||||||
return _mm_cvtsd_si32 (_mm_load_sd (&x)) ;
|
|
||||||
#else
|
|
||||||
return lrint (x) ;
|
|
||||||
#endif
|
|
||||||
} /* psf_lrint */
|
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
|
||||||
** Common static inline functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline double
|
|
||||||
fmod_one (double x)
|
|
||||||
{ double res ;
|
|
||||||
|
|
||||||
res = x - psf_lrint (x) ;
|
|
||||||
if (res < 0.0)
|
|
||||||
return res + 1.0 ;
|
|
||||||
|
|
||||||
return res ;
|
|
||||||
} /* fmod_one */
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
is_bad_src_ratio (double ratio)
|
|
||||||
{ return (ratio < (1.0 / SRC_MAX_RATIO) || ratio > (1.0 * SRC_MAX_RATIO)) ;
|
|
||||||
} /* is_bad_src_ratio */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* COMMON_H_INCLUDED */
|
|
||||||
|
|
172
source/engine/thirdparty/libsamplerate/src/config.h
vendored
172
source/engine/thirdparty/libsamplerate/src/config.h
vendored
|
@ -1,172 +0,0 @@
|
||||||
/* src/config.h. Generated from config.h.in by configure. */
|
|
||||||
/* src/config.h.in. Generated from configure.ac by autoheader. */
|
|
||||||
|
|
||||||
/* Define if building universal (internal helper macro) */
|
|
||||||
/* #undef AC_APPLE_UNIVERSAL_BUILD */
|
|
||||||
|
|
||||||
/* Host processor clips on negative float to int conversion. */
|
|
||||||
#define CPU_CLIPS_NEGATIVE 0
|
|
||||||
|
|
||||||
/* Host processor clips on positive float to int conversion. */
|
|
||||||
#define CPU_CLIPS_POSITIVE 0
|
|
||||||
|
|
||||||
/* Host processor is big endian. */
|
|
||||||
#define CPU_IS_BIG_ENDIAN 0
|
|
||||||
|
|
||||||
/* Host processor is little endian. */
|
|
||||||
#define CPU_IS_LITTLE_ENDIAN 1
|
|
||||||
|
|
||||||
/* Enable sinc best converter. */
|
|
||||||
#define ENABLE_SINC_BEST_CONVERTER 0
|
|
||||||
|
|
||||||
/* Enable sinc fast converter. */
|
|
||||||
#define ENABLE_SINC_FAST_CONVERTER 0
|
|
||||||
|
|
||||||
/* Enable sinc balanced converter. */
|
|
||||||
#define ENABLE_SINC_MEDIUM_CONVERTER 0
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `alarm' function. */
|
|
||||||
#define HAVE_ALARM 1
|
|
||||||
|
|
||||||
/* Set to 1 if you have alsa */
|
|
||||||
#define HAVE_ALSA 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `calloc' function. */
|
|
||||||
#define HAVE_CALLOC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `ceil' function. */
|
|
||||||
/* #undef HAVE_CEIL */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
|
||||||
#define HAVE_DLFCN_H 1
|
|
||||||
|
|
||||||
/* Set to 1 if you have fftw3 */
|
|
||||||
/* #undef HAVE_FFTW3 */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `floor' function. */
|
|
||||||
/* #undef HAVE_FLOOR */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `fmod' function. */
|
|
||||||
/* #undef HAVE_FMOD */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `free' function. */
|
|
||||||
#define HAVE_FREE 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <immintrin.h> header file. */
|
|
||||||
/* #undef HAVE_IMMINTRIN_H */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
||||||
#define HAVE_INTTYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `lrint' function. */
|
|
||||||
/* #undef HAVE_LRINT */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `lrintf' function. */
|
|
||||||
/* #undef HAVE_LRINTF */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `malloc' function. */
|
|
||||||
#define HAVE_MALLOC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `memcpy' function. */
|
|
||||||
#define HAVE_MEMCPY 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `memmove' function. */
|
|
||||||
#define HAVE_MEMMOVE 1
|
|
||||||
|
|
||||||
/* Define if you have signal SIGALRM. */
|
|
||||||
#define HAVE_SIGALRM 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `signal' function. */
|
|
||||||
#define HAVE_SIGNAL 1
|
|
||||||
|
|
||||||
/* Set to 1 if you have libsndfile */
|
|
||||||
/* #undef HAVE_SNDFILE */
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdbool.h> header file. */
|
|
||||||
#define HAVE_STDBOOL_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
|
||||||
#define HAVE_STDINT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdio.h> header file. */
|
|
||||||
#define HAVE_STDIO_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
||||||
#define HAVE_STDLIB_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
|
||||||
#define HAVE_STRINGS_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <string.h> header file. */
|
|
||||||
#define HAVE_STRING_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
||||||
#define HAVE_SYS_STAT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/times.h> header file. */
|
|
||||||
#define HAVE_SYS_TIMES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
||||||
#define HAVE_SYS_TYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
|
||||||
#define HAVE_UNISTD_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if the compiler supports simple visibility declarations. */
|
|
||||||
#define HAVE_VISIBILITY 1
|
|
||||||
|
|
||||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
|
||||||
#define LT_OBJDIR ".libs/"
|
|
||||||
|
|
||||||
/* Name of package */
|
|
||||||
#define PACKAGE "libsamplerate"
|
|
||||||
|
|
||||||
/* Define to the address where bug reports for this package should be sent. */
|
|
||||||
#define PACKAGE_BUGREPORT "erikd@mega-nerd.com"
|
|
||||||
|
|
||||||
/* Define to the full name of this package. */
|
|
||||||
#define PACKAGE_NAME "libsamplerate"
|
|
||||||
|
|
||||||
/* Define to the full name and version of this package. */
|
|
||||||
#define PACKAGE_STRING "libsamplerate 0.2.2"
|
|
||||||
|
|
||||||
/* Define to the one symbol short name of this package. */
|
|
||||||
#define PACKAGE_TARNAME "libsamplerate"
|
|
||||||
|
|
||||||
/* Define to the home page for this package. */
|
|
||||||
#define PACKAGE_URL "https://github.com/libsndfile/libsamplerate/"
|
|
||||||
|
|
||||||
/* Define to the version of this package. */
|
|
||||||
#define PACKAGE_VERSION "0.2.2"
|
|
||||||
|
|
||||||
/* The size of `double', as computed by sizeof. */
|
|
||||||
#define SIZEOF_DOUBLE 8
|
|
||||||
|
|
||||||
/* The size of `float', as computed by sizeof. */
|
|
||||||
#define SIZEOF_FLOAT 4
|
|
||||||
|
|
||||||
/* The size of `int', as computed by sizeof. */
|
|
||||||
#define SIZEOF_INT 4
|
|
||||||
|
|
||||||
/* The size of `long', as computed by sizeof. */
|
|
||||||
#define SIZEOF_LONG 8
|
|
||||||
|
|
||||||
/* Define to 1 if all of the C90 standard headers exist (not just the ones
|
|
||||||
required in a freestanding environment). This macro is provided for
|
|
||||||
backward compatibility; new code need not use it. */
|
|
||||||
#define STDC_HEADERS 1
|
|
||||||
|
|
||||||
/* Version number of package */
|
|
||||||
#define VERSION "0.2.2"
|
|
||||||
|
|
||||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
|
||||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
|
||||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
|
||||||
# if defined __BIG_ENDIAN__
|
|
||||||
# define WORDS_BIGENDIAN 1
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# ifndef WORDS_BIGENDIAN
|
|
||||||
/* # undef WORDS_BIGENDIAN */
|
|
||||||
# endif
|
|
||||||
#endif
|
|
|
@ -1,524 +0,0 @@
|
||||||
/*
|
|
||||||
** Copyright (c) 2002-2016, Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** This code is released under 2-clause BSD license. Please see the
|
|
||||||
** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "samplerate.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
static SRC_STATE *psrc_set_converter (int converter_type, int channels, int *error) ;
|
|
||||||
|
|
||||||
|
|
||||||
SRC_STATE *
|
|
||||||
src_new (int converter_type, int channels, int *error)
|
|
||||||
{
|
|
||||||
return psrc_set_converter (converter_type, channels, error) ;
|
|
||||||
} /* src_new */
|
|
||||||
|
|
||||||
SRC_STATE*
|
|
||||||
src_clone (SRC_STATE* orig, int *error)
|
|
||||||
{
|
|
||||||
if (!orig)
|
|
||||||
{
|
|
||||||
if (error)
|
|
||||||
*error = SRC_ERR_BAD_STATE ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
if (error)
|
|
||||||
*error = SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
SRC_STATE *state = orig->vt->copy (orig) ;
|
|
||||||
if (!state)
|
|
||||||
if (error)
|
|
||||||
*error = SRC_ERR_MALLOC_FAILED ;
|
|
||||||
|
|
||||||
return state ;
|
|
||||||
}
|
|
||||||
|
|
||||||
SRC_STATE*
|
|
||||||
src_callback_new (src_callback_t func, int converter_type, int channels, int *error, void* cb_data)
|
|
||||||
{ SRC_STATE *state ;
|
|
||||||
|
|
||||||
if (func == NULL)
|
|
||||||
{ if (error)
|
|
||||||
*error = SRC_ERR_BAD_CALLBACK ;
|
|
||||||
return NULL ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
if (error != NULL)
|
|
||||||
*error = 0 ;
|
|
||||||
|
|
||||||
if ((state = src_new (converter_type, channels, error)) == NULL)
|
|
||||||
return NULL ;
|
|
||||||
|
|
||||||
src_reset (state) ;
|
|
||||||
|
|
||||||
state->mode = SRC_MODE_CALLBACK ;
|
|
||||||
state->callback_func = func ;
|
|
||||||
state->user_callback_data = cb_data ;
|
|
||||||
|
|
||||||
return state ;
|
|
||||||
} /* src_callback_new */
|
|
||||||
|
|
||||||
SRC_STATE *
|
|
||||||
src_delete (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
if (state)
|
|
||||||
state->vt->close (state) ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* src_state */
|
|
||||||
|
|
||||||
int
|
|
||||||
src_process (SRC_STATE *state, SRC_DATA *data)
|
|
||||||
{
|
|
||||||
int error ;
|
|
||||||
|
|
||||||
if (state == NULL)
|
|
||||||
return SRC_ERR_BAD_STATE ;
|
|
||||||
|
|
||||||
if (state->mode != SRC_MODE_PROCESS)
|
|
||||||
return SRC_ERR_BAD_MODE ;
|
|
||||||
|
|
||||||
/* Check for valid SRC_DATA first. */
|
|
||||||
if (data == NULL)
|
|
||||||
return SRC_ERR_BAD_DATA ;
|
|
||||||
|
|
||||||
/* And that data_in and data_out are valid. */
|
|
||||||
if ((data->data_in == NULL && data->input_frames > 0)
|
|
||||||
|| (data->data_out == NULL && data->output_frames > 0))
|
|
||||||
return SRC_ERR_BAD_DATA_PTR ;
|
|
||||||
|
|
||||||
/* Check src_ratio is in range. */
|
|
||||||
if (is_bad_src_ratio (data->src_ratio))
|
|
||||||
return SRC_ERR_BAD_SRC_RATIO ;
|
|
||||||
|
|
||||||
if (data->input_frames < 0)
|
|
||||||
data->input_frames = 0 ;
|
|
||||||
if (data->output_frames < 0)
|
|
||||||
data->output_frames = 0 ;
|
|
||||||
|
|
||||||
if (data->data_in < data->data_out)
|
|
||||||
{ if (data->data_in + data->input_frames * state->channels > data->data_out)
|
|
||||||
{ /*-printf ("\n\ndata_in: %p data_out: %p\n",
|
|
||||||
(void*) (data->data_in + data->input_frames * psrc->channels), (void*) data->data_out) ;-*/
|
|
||||||
return SRC_ERR_DATA_OVERLAP ;
|
|
||||||
} ;
|
|
||||||
}
|
|
||||||
else if (data->data_out + data->output_frames * state->channels > data->data_in)
|
|
||||||
{ /*-printf ("\n\ndata_in : %p ouput frames: %ld data_out: %p\n", (void*) data->data_in, data->output_frames, (void*) data->data_out) ;
|
|
||||||
|
|
||||||
printf ("data_out: %p (%p) data_in: %p\n", (void*) data->data_out,
|
|
||||||
(void*) (data->data_out + data->input_frames * psrc->channels), (void*) data->data_in) ;-*/
|
|
||||||
return SRC_ERR_DATA_OVERLAP ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Set the input and output counts to zero. */
|
|
||||||
data->input_frames_used = 0 ;
|
|
||||||
data->output_frames_gen = 0 ;
|
|
||||||
|
|
||||||
/* Special case for when last_ratio has not been set. */
|
|
||||||
if (state->last_ratio < (1.0 / SRC_MAX_RATIO))
|
|
||||||
state->last_ratio = data->src_ratio ;
|
|
||||||
|
|
||||||
/* Now process. */
|
|
||||||
if (fabs (state->last_ratio - data->src_ratio) < 1e-15)
|
|
||||||
error = state->vt->const_process (state, data) ;
|
|
||||||
else
|
|
||||||
error = state->vt->vari_process (state, data) ;
|
|
||||||
|
|
||||||
return error ;
|
|
||||||
} /* src_process */
|
|
||||||
|
|
||||||
long
|
|
||||||
src_callback_read (SRC_STATE *state, double src_ratio, long frames, float *data)
|
|
||||||
{
|
|
||||||
SRC_DATA src_data ;
|
|
||||||
|
|
||||||
long output_frames_gen ;
|
|
||||||
int error = 0 ;
|
|
||||||
|
|
||||||
if (state == NULL)
|
|
||||||
return 0 ;
|
|
||||||
|
|
||||||
if (frames <= 0)
|
|
||||||
return 0 ;
|
|
||||||
|
|
||||||
if (state->mode != SRC_MODE_CALLBACK)
|
|
||||||
{ state->error = SRC_ERR_BAD_MODE ;
|
|
||||||
return 0 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
if (state->callback_func == NULL)
|
|
||||||
{ state->error = SRC_ERR_NULL_CALLBACK ;
|
|
||||||
return 0 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
memset (&src_data, 0, sizeof (src_data)) ;
|
|
||||||
|
|
||||||
/* Check src_ratio is in range. */
|
|
||||||
if (is_bad_src_ratio (src_ratio))
|
|
||||||
{ state->error = SRC_ERR_BAD_SRC_RATIO ;
|
|
||||||
return 0 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Switch modes temporarily. */
|
|
||||||
src_data.src_ratio = src_ratio ;
|
|
||||||
src_data.data_out = data ;
|
|
||||||
src_data.output_frames = frames ;
|
|
||||||
|
|
||||||
src_data.data_in = state->saved_data ;
|
|
||||||
src_data.input_frames = state->saved_frames ;
|
|
||||||
|
|
||||||
output_frames_gen = 0 ;
|
|
||||||
while (output_frames_gen < frames)
|
|
||||||
{ /* Use a dummy array for the case where the callback function
|
|
||||||
** returns without setting the ptr.
|
|
||||||
*/
|
|
||||||
float dummy [1] ;
|
|
||||||
|
|
||||||
if (src_data.input_frames == 0)
|
|
||||||
{ float *ptr = dummy ;
|
|
||||||
|
|
||||||
src_data.input_frames = state->callback_func (state->user_callback_data, &ptr) ;
|
|
||||||
src_data.data_in = ptr ;
|
|
||||||
|
|
||||||
if (src_data.input_frames == 0)
|
|
||||||
src_data.end_of_input = 1 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Now call process function. However, we need to set the mode
|
|
||||||
** to SRC_MODE_PROCESS first and when we return set it back to
|
|
||||||
** SRC_MODE_CALLBACK.
|
|
||||||
*/
|
|
||||||
state->mode = SRC_MODE_PROCESS ;
|
|
||||||
error = src_process (state, &src_data) ;
|
|
||||||
state->mode = SRC_MODE_CALLBACK ;
|
|
||||||
|
|
||||||
if (error != 0)
|
|
||||||
break ;
|
|
||||||
|
|
||||||
src_data.data_in += src_data.input_frames_used * state->channels ;
|
|
||||||
src_data.input_frames -= src_data.input_frames_used ;
|
|
||||||
|
|
||||||
src_data.data_out += src_data.output_frames_gen * state->channels ;
|
|
||||||
src_data.output_frames -= src_data.output_frames_gen ;
|
|
||||||
|
|
||||||
output_frames_gen += src_data.output_frames_gen ;
|
|
||||||
|
|
||||||
if (src_data.end_of_input == SRC_TRUE && src_data.output_frames_gen == 0)
|
|
||||||
break ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
state->saved_data = src_data.data_in ;
|
|
||||||
state->saved_frames = src_data.input_frames ;
|
|
||||||
|
|
||||||
if (error != 0)
|
|
||||||
{ state->error = (SRC_ERROR) error ;
|
|
||||||
return 0 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
return output_frames_gen ;
|
|
||||||
} /* src_callback_read */
|
|
||||||
|
|
||||||
/*==========================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
src_set_ratio (SRC_STATE *state, double new_ratio)
|
|
||||||
{
|
|
||||||
if (state == NULL)
|
|
||||||
return SRC_ERR_BAD_STATE ;
|
|
||||||
|
|
||||||
if (is_bad_src_ratio (new_ratio))
|
|
||||||
return SRC_ERR_BAD_SRC_RATIO ;
|
|
||||||
|
|
||||||
state->last_ratio = new_ratio ;
|
|
||||||
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
} /* src_set_ratio */
|
|
||||||
|
|
||||||
int
|
|
||||||
src_get_channels (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
if (state == NULL)
|
|
||||||
return -SRC_ERR_BAD_STATE ;
|
|
||||||
|
|
||||||
return state->channels ;
|
|
||||||
} /* src_get_channels */
|
|
||||||
|
|
||||||
int
|
|
||||||
src_reset (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
if (state == NULL)
|
|
||||||
return SRC_ERR_BAD_STATE ;
|
|
||||||
|
|
||||||
state->vt->reset (state) ;
|
|
||||||
|
|
||||||
state->last_position = 0.0 ;
|
|
||||||
state->last_ratio = 0.0 ;
|
|
||||||
|
|
||||||
state->saved_data = NULL ;
|
|
||||||
state->saved_frames = 0 ;
|
|
||||||
|
|
||||||
state->error = SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
} /* src_reset */
|
|
||||||
|
|
||||||
/*==============================================================================
|
|
||||||
** Control functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const char *
|
|
||||||
src_get_name (int converter_type)
|
|
||||||
{ const char *desc ;
|
|
||||||
|
|
||||||
if ((desc = sinc_get_name (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
if ((desc = zoh_get_name (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
if ((desc = linear_get_name (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* src_get_name */
|
|
||||||
|
|
||||||
const char *
|
|
||||||
src_get_description (int converter_type)
|
|
||||||
{ const char *desc ;
|
|
||||||
|
|
||||||
if ((desc = sinc_get_description (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
if ((desc = zoh_get_description (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
if ((desc = linear_get_description (converter_type)) != NULL)
|
|
||||||
return desc ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* src_get_description */
|
|
||||||
|
|
||||||
const char *
|
|
||||||
src_get_version (void)
|
|
||||||
{ return "VERSION";//PACKAGE "-" VERSION " (c) 2002-2008 Erik de Castro Lopo" ;
|
|
||||||
} /* src_get_version */
|
|
||||||
|
|
||||||
int
|
|
||||||
src_is_valid_ratio (double ratio)
|
|
||||||
{
|
|
||||||
if (is_bad_src_ratio (ratio))
|
|
||||||
return SRC_FALSE ;
|
|
||||||
|
|
||||||
return SRC_TRUE ;
|
|
||||||
} /* src_is_valid_ratio */
|
|
||||||
|
|
||||||
/*==============================================================================
|
|
||||||
** Error reporting functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
src_error (SRC_STATE *state)
|
|
||||||
{ if (state)
|
|
||||||
return state->error ;
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
} /* src_error */
|
|
||||||
|
|
||||||
const char*
|
|
||||||
src_strerror (int error)
|
|
||||||
{
|
|
||||||
switch (error)
|
|
||||||
{ case SRC_ERR_NO_ERROR :
|
|
||||||
return "No error." ;
|
|
||||||
case SRC_ERR_MALLOC_FAILED :
|
|
||||||
return "Malloc failed." ;
|
|
||||||
case SRC_ERR_BAD_STATE :
|
|
||||||
return "SRC_STATE pointer is NULL." ;
|
|
||||||
case SRC_ERR_BAD_DATA :
|
|
||||||
return "SRC_DATA pointer is NULL." ;
|
|
||||||
case SRC_ERR_BAD_DATA_PTR :
|
|
||||||
return "SRC_DATA->data_out or SRC_DATA->data_in is NULL." ;
|
|
||||||
case SRC_ERR_NO_PRIVATE :
|
|
||||||
return "Internal error. No private data." ;
|
|
||||||
|
|
||||||
case SRC_ERR_BAD_SRC_RATIO :
|
|
||||||
return "SRC ratio outside [1/" SRC_MAX_RATIO_STR ", " SRC_MAX_RATIO_STR "] range." ;
|
|
||||||
|
|
||||||
case SRC_ERR_BAD_SINC_STATE :
|
|
||||||
return "src_process() called without reset after end_of_input." ;
|
|
||||||
case SRC_ERR_BAD_PROC_PTR :
|
|
||||||
return "Internal error. No process pointer." ;
|
|
||||||
case SRC_ERR_SHIFT_BITS :
|
|
||||||
return "Internal error. SHIFT_BITS too large." ;
|
|
||||||
case SRC_ERR_FILTER_LEN :
|
|
||||||
return "Internal error. Filter length too large." ;
|
|
||||||
case SRC_ERR_BAD_CONVERTER :
|
|
||||||
return "Bad converter number." ;
|
|
||||||
case SRC_ERR_BAD_CHANNEL_COUNT :
|
|
||||||
return "Channel count must be >= 1." ;
|
|
||||||
case SRC_ERR_SINC_BAD_BUFFER_LEN :
|
|
||||||
return "Internal error. Bad buffer length. Please report this." ;
|
|
||||||
case SRC_ERR_SIZE_INCOMPATIBILITY :
|
|
||||||
return "Internal error. Input data / internal buffer size difference. Please report this." ;
|
|
||||||
case SRC_ERR_BAD_PRIV_PTR :
|
|
||||||
return "Internal error. Private pointer is NULL. Please report this." ;
|
|
||||||
case SRC_ERR_DATA_OVERLAP :
|
|
||||||
return "Input and output data arrays overlap." ;
|
|
||||||
case SRC_ERR_BAD_CALLBACK :
|
|
||||||
return "Supplied callback function pointer is NULL." ;
|
|
||||||
case SRC_ERR_BAD_MODE :
|
|
||||||
return "Calling mode differs from initialisation mode (ie process v callback)." ;
|
|
||||||
case SRC_ERR_NULL_CALLBACK :
|
|
||||||
return "Callback function pointer is NULL in src_callback_read ()." ;
|
|
||||||
case SRC_ERR_NO_VARIABLE_RATIO :
|
|
||||||
return "This converter only allows constant conversion ratios." ;
|
|
||||||
case SRC_ERR_SINC_PREPARE_DATA_BAD_LEN :
|
|
||||||
return "Internal error : Bad length in prepare_data ()." ;
|
|
||||||
case SRC_ERR_BAD_INTERNAL_STATE :
|
|
||||||
return "Error : Someone is trampling on my internal state." ;
|
|
||||||
|
|
||||||
case SRC_ERR_MAX_ERROR :
|
|
||||||
return "Placeholder. No error defined for this error number." ;
|
|
||||||
|
|
||||||
default : break ;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* src_strerror */
|
|
||||||
|
|
||||||
/*==============================================================================
|
|
||||||
** Simple interface for performing a single conversion from input buffer to
|
|
||||||
** output buffer at a fixed conversion ratio.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
src_simple (SRC_DATA *src_data, int converter, int channels)
|
|
||||||
{ SRC_STATE *src_state ;
|
|
||||||
int error ;
|
|
||||||
|
|
||||||
if ((src_state = src_new (converter, channels, &error)) == NULL)
|
|
||||||
return error ;
|
|
||||||
|
|
||||||
src_data->end_of_input = 1 ; /* Only one buffer worth of input. */
|
|
||||||
|
|
||||||
error = src_process (src_state, src_data) ;
|
|
||||||
|
|
||||||
src_delete (src_state) ;
|
|
||||||
|
|
||||||
return error ;
|
|
||||||
} /* src_simple */
|
|
||||||
|
|
||||||
void
|
|
||||||
src_short_to_float_array (const short *in, float *out, int len)
|
|
||||||
{
|
|
||||||
for (int i = 0 ; i < len ; i++)
|
|
||||||
{ out [i] = (float) (in [i] / ((float)0x8000)) ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
return ;
|
|
||||||
} /* src_short_to_float_array */
|
|
||||||
|
|
||||||
void
|
|
||||||
src_float_to_short_array (const float *in, short *out, int len)
|
|
||||||
{
|
|
||||||
for (int i = 0 ; i < len ; i++)
|
|
||||||
{ float scaled_value ;
|
|
||||||
scaled_value = in [i] * 32768.f ;
|
|
||||||
if (scaled_value >= 32767.f)
|
|
||||||
out [i] = 32767 ;
|
|
||||||
else if (scaled_value <= -32768.f)
|
|
||||||
out [i] = -32768 ;
|
|
||||||
else
|
|
||||||
out [i] = (short) (psf_lrintf (scaled_value)) ;
|
|
||||||
}
|
|
||||||
} /* src_float_to_short_array */
|
|
||||||
|
|
||||||
void
|
|
||||||
src_int_to_float_array (const int *in, float *out, int len)
|
|
||||||
{
|
|
||||||
for (int i = 0 ; i < len ; i++)
|
|
||||||
{ out [i] = (float) (in [i] / (8.0 * 0x10000000)) ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
return ;
|
|
||||||
} /* src_int_to_float_array */
|
|
||||||
|
|
||||||
void
|
|
||||||
src_float_to_int_array (const float *in, int *out, int len)
|
|
||||||
{ double scaled_value ;
|
|
||||||
|
|
||||||
for (int i = 0 ; i < len ; i++)
|
|
||||||
{ scaled_value = in [i] * (8.0 * 0x10000000) ;
|
|
||||||
#if CPU_CLIPS_POSITIVE == 0
|
|
||||||
if (scaled_value >= (1.0 * 0x7FFFFFFF))
|
|
||||||
{ out [i] = 0x7fffffff ;
|
|
||||||
continue ;
|
|
||||||
} ;
|
|
||||||
#endif
|
|
||||||
#if CPU_CLIPS_NEGATIVE == 0
|
|
||||||
if (scaled_value <= (-8.0 * 0x10000000))
|
|
||||||
{ out [i] = -1 - 0x7fffffff ;
|
|
||||||
continue ;
|
|
||||||
} ;
|
|
||||||
#endif
|
|
||||||
out [i] = (int) psf_lrint (scaled_value) ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
} /* src_float_to_int_array */
|
|
||||||
|
|
||||||
/*==============================================================================
|
|
||||||
** Private functions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static SRC_STATE *
|
|
||||||
psrc_set_converter (int converter_type, int channels, int *error)
|
|
||||||
{
|
|
||||||
SRC_ERROR temp_error;
|
|
||||||
SRC_STATE *state ;
|
|
||||||
switch (converter_type)
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_SINC_BEST_CONVERTER
|
|
||||||
case SRC_SINC_BEST_QUALITY :
|
|
||||||
state = sinc_state_new (converter_type, channels, &temp_error) ;
|
|
||||||
break ;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_SINC_MEDIUM_CONVERTER
|
|
||||||
case SRC_SINC_MEDIUM_QUALITY :
|
|
||||||
state = sinc_state_new (converter_type, channels, &temp_error) ;
|
|
||||||
break ;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_SINC_FAST_CONVERTER
|
|
||||||
case SRC_SINC_FASTEST :
|
|
||||||
state = sinc_state_new (converter_type, channels, &temp_error) ;
|
|
||||||
break ;
|
|
||||||
#endif
|
|
||||||
case SRC_ZERO_ORDER_HOLD :
|
|
||||||
state = zoh_state_new (channels, &temp_error) ;
|
|
||||||
break ;
|
|
||||||
case SRC_LINEAR :
|
|
||||||
state = linear_state_new (channels, &temp_error) ;
|
|
||||||
break ;
|
|
||||||
default :
|
|
||||||
temp_error = SRC_ERR_BAD_CONVERTER ;
|
|
||||||
state = NULL ;
|
|
||||||
break ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
*error = (int) temp_error ;
|
|
||||||
|
|
||||||
return state ;
|
|
||||||
} /* psrc_set_converter */
|
|
||||||
|
|
|
@ -1,297 +0,0 @@
|
||||||
/*
|
|
||||||
** Copyright (c) 2002-2021, Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** This code is released under 2-clause BSD license. Please see the
|
|
||||||
** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
static SRC_ERROR linear_vari_process (SRC_STATE *state, SRC_DATA *data) ;
|
|
||||||
static void linear_reset (SRC_STATE *state) ;
|
|
||||||
static SRC_STATE *linear_copy (SRC_STATE *state) ;
|
|
||||||
static void linear_close (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*========================================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define LINEAR_MAGIC_MARKER MAKE_MAGIC ('l', 'i', 'n', 'e', 'a', 'r')
|
|
||||||
|
|
||||||
#define SRC_DEBUG 0
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{ int linear_magic_marker ;
|
|
||||||
int dirty ;
|
|
||||||
long in_count, in_used ;
|
|
||||||
long out_count, out_gen ;
|
|
||||||
float *last_value ;
|
|
||||||
} LINEAR_DATA ;
|
|
||||||
|
|
||||||
static SRC_STATE_VT linear_state_vt =
|
|
||||||
{
|
|
||||||
linear_vari_process,
|
|
||||||
linear_vari_process,
|
|
||||||
linear_reset,
|
|
||||||
linear_copy,
|
|
||||||
linear_close
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static SRC_ERROR
|
|
||||||
linear_vari_process (SRC_STATE *state, SRC_DATA *data)
|
|
||||||
{ LINEAR_DATA *priv ;
|
|
||||||
double src_ratio, input_index, rem ;
|
|
||||||
int ch ;
|
|
||||||
|
|
||||||
if (data->input_frames <= 0)
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
if (state->private_data == NULL)
|
|
||||||
return SRC_ERR_NO_PRIVATE ;
|
|
||||||
|
|
||||||
priv = (LINEAR_DATA*) state->private_data ;
|
|
||||||
|
|
||||||
if (!priv->dirty)
|
|
||||||
{ /* If we have just been reset, set the last_value data. */
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
priv->last_value [ch] = data->data_in [ch] ;
|
|
||||||
priv->dirty = 1 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
priv->in_count = data->input_frames * state->channels ;
|
|
||||||
priv->out_count = data->output_frames * state->channels ;
|
|
||||||
priv->in_used = priv->out_gen = 0 ;
|
|
||||||
|
|
||||||
src_ratio = state->last_ratio ;
|
|
||||||
|
|
||||||
if (is_bad_src_ratio (src_ratio))
|
|
||||||
return SRC_ERR_BAD_INTERNAL_STATE ;
|
|
||||||
|
|
||||||
input_index = state->last_position ;
|
|
||||||
|
|
||||||
/* Calculate samples before first sample in input array. */
|
|
||||||
while (input_index < 1.0 && priv->out_gen < priv->out_count)
|
|
||||||
{
|
|
||||||
if (priv->in_used + state->channels * (1.0 + input_index) >= priv->in_count)
|
|
||||||
break ;
|
|
||||||
|
|
||||||
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
|
|
||||||
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
|
|
||||||
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
{ data->data_out [priv->out_gen] = (float) (priv->last_value [ch] + input_index *
|
|
||||||
((double) data->data_in [ch] - priv->last_value [ch])) ;
|
|
||||||
priv->out_gen ++ ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Figure out the next index. */
|
|
||||||
input_index += 1.0 / src_ratio ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
rem = fmod_one (input_index) ;
|
|
||||||
priv->in_used += state->channels * psf_lrint (input_index - rem) ;
|
|
||||||
input_index = rem ;
|
|
||||||
|
|
||||||
/* Main processing loop. */
|
|
||||||
while (priv->out_gen < priv->out_count && priv->in_used + state->channels * input_index < priv->in_count)
|
|
||||||
{
|
|
||||||
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
|
|
||||||
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
|
|
||||||
|
|
||||||
#if SRC_DEBUG
|
|
||||||
if (priv->in_used < state->channels && input_index < 1.0)
|
|
||||||
{ printf ("Whoops!!!! in_used : %ld channels : %d input_index : %f\n", priv->in_used, state->channels, input_index) ;
|
|
||||||
exit (1) ;
|
|
||||||
} ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
{ data->data_out [priv->out_gen] = (float) (data->data_in [priv->in_used - state->channels + ch] + input_index *
|
|
||||||
((double) data->data_in [priv->in_used + ch] - data->data_in [priv->in_used - state->channels + ch])) ;
|
|
||||||
priv->out_gen ++ ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Figure out the next index. */
|
|
||||||
input_index += 1.0 / src_ratio ;
|
|
||||||
rem = fmod_one (input_index) ;
|
|
||||||
|
|
||||||
priv->in_used += state->channels * psf_lrint (input_index - rem) ;
|
|
||||||
input_index = rem ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
if (priv->in_used > priv->in_count)
|
|
||||||
{ input_index += (priv->in_used - priv->in_count) / state->channels ;
|
|
||||||
priv->in_used = priv->in_count ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
state->last_position = input_index ;
|
|
||||||
|
|
||||||
if (priv->in_used > 0)
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
priv->last_value [ch] = data->data_in [priv->in_used - state->channels + ch] ;
|
|
||||||
|
|
||||||
/* Save current ratio rather then target ratio. */
|
|
||||||
state->last_ratio = src_ratio ;
|
|
||||||
|
|
||||||
data->input_frames_used = priv->in_used / state->channels ;
|
|
||||||
data->output_frames_gen = priv->out_gen / state->channels ;
|
|
||||||
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
} /* linear_vari_process */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE const char*
|
|
||||||
linear_get_name (int src_enum)
|
|
||||||
{
|
|
||||||
if (src_enum == SRC_LINEAR)
|
|
||||||
return "Linear Interpolator" ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* linear_get_name */
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE const char*
|
|
||||||
linear_get_description (int src_enum)
|
|
||||||
{
|
|
||||||
if (src_enum == SRC_LINEAR)
|
|
||||||
return "Linear interpolator, very fast, poor quality." ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* linear_get_descrition */
|
|
||||||
|
|
||||||
static LINEAR_DATA *
|
|
||||||
linear_data_new (int channels)
|
|
||||||
{
|
|
||||||
assert (channels > 0) ;
|
|
||||||
|
|
||||||
LINEAR_DATA *priv = (LINEAR_DATA *) calloc (1, sizeof (LINEAR_DATA)) ;
|
|
||||||
if (priv)
|
|
||||||
{
|
|
||||||
priv->linear_magic_marker = LINEAR_MAGIC_MARKER ;
|
|
||||||
priv->last_value = (float *) calloc (channels, sizeof (float)) ;
|
|
||||||
if (!priv->last_value)
|
|
||||||
{
|
|
||||||
free (priv) ;
|
|
||||||
priv = NULL ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return priv ;
|
|
||||||
}
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE SRC_STATE *
|
|
||||||
linear_state_new (int channels, SRC_ERROR *error)
|
|
||||||
{
|
|
||||||
assert (channels > 0) ;
|
|
||||||
assert (error != NULL) ;
|
|
||||||
|
|
||||||
SRC_STATE *state = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
|
|
||||||
if (!state)
|
|
||||||
{
|
|
||||||
*error = SRC_ERR_MALLOC_FAILED ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->channels = channels ;
|
|
||||||
state->mode = SRC_MODE_PROCESS ;
|
|
||||||
|
|
||||||
state->private_data = linear_data_new (state->channels) ;
|
|
||||||
if (!state->private_data)
|
|
||||||
{
|
|
||||||
free (state) ;
|
|
||||||
*error = SRC_ERR_MALLOC_FAILED ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->vt = &linear_state_vt ;
|
|
||||||
|
|
||||||
linear_reset (state) ;
|
|
||||||
|
|
||||||
*error = SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
return state ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===================================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
linear_reset (SRC_STATE *state)
|
|
||||||
{ LINEAR_DATA *priv = NULL ;
|
|
||||||
|
|
||||||
priv = (LINEAR_DATA*) state->private_data ;
|
|
||||||
if (priv == NULL)
|
|
||||||
return ;
|
|
||||||
|
|
||||||
priv->dirty = 0 ;
|
|
||||||
memset (priv->last_value, 0, sizeof (priv->last_value [0]) * state->channels) ;
|
|
||||||
|
|
||||||
return ;
|
|
||||||
} /* linear_reset */
|
|
||||||
|
|
||||||
SRC_STATE *
|
|
||||||
linear_copy (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
assert (state != NULL) ;
|
|
||||||
|
|
||||||
if (state->private_data == NULL)
|
|
||||||
return NULL ;
|
|
||||||
|
|
||||||
SRC_STATE *to = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
|
|
||||||
if (!to)
|
|
||||||
return NULL ;
|
|
||||||
memcpy (to, state, sizeof (SRC_STATE)) ;
|
|
||||||
|
|
||||||
LINEAR_DATA* from_priv = (LINEAR_DATA*) state->private_data ;
|
|
||||||
LINEAR_DATA *to_priv = (LINEAR_DATA *) calloc (1, sizeof (LINEAR_DATA)) ;
|
|
||||||
if (!to_priv)
|
|
||||||
{
|
|
||||||
free (to) ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (to_priv, from_priv, sizeof (LINEAR_DATA)) ;
|
|
||||||
to_priv->last_value = (float *) malloc (sizeof (float) * state->channels) ;
|
|
||||||
if (!to_priv->last_value)
|
|
||||||
{
|
|
||||||
free (to) ;
|
|
||||||
free (to_priv) ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
memcpy (to_priv->last_value, from_priv->last_value, sizeof (float) * state->channels) ;
|
|
||||||
|
|
||||||
to->private_data = to_priv ;
|
|
||||||
|
|
||||||
return to ;
|
|
||||||
} /* linear_copy */
|
|
||||||
|
|
||||||
static void
|
|
||||||
linear_close (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
if (state)
|
|
||||||
{
|
|
||||||
LINEAR_DATA *linear = (LINEAR_DATA *) state->private_data ;
|
|
||||||
if (linear)
|
|
||||||
{
|
|
||||||
if (linear->last_value)
|
|
||||||
{
|
|
||||||
free (linear->last_value) ;
|
|
||||||
linear->last_value = NULL ;
|
|
||||||
}
|
|
||||||
free (linear) ;
|
|
||||||
linear = NULL ;
|
|
||||||
}
|
|
||||||
free (state) ;
|
|
||||||
state = NULL ;
|
|
||||||
}
|
|
||||||
} /* linear_close */
|
|
1248
source/engine/thirdparty/libsamplerate/src/src_sinc.c
vendored
1248
source/engine/thirdparty/libsamplerate/src/src_sinc.c
vendored
File diff suppressed because it is too large
Load diff
286
source/engine/thirdparty/libsamplerate/src/src_zoh.c
vendored
286
source/engine/thirdparty/libsamplerate/src/src_zoh.c
vendored
|
@ -1,286 +0,0 @@
|
||||||
/*
|
|
||||||
** Copyright (c) 2002-2021, Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
||||||
** All rights reserved.
|
|
||||||
**
|
|
||||||
** This code is released under 2-clause BSD license. Please see the
|
|
||||||
** file at : https://github.com/libsndfile/libsamplerate/blob/master/COPYING
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
static SRC_ERROR zoh_vari_process (SRC_STATE *state, SRC_DATA *data) ;
|
|
||||||
static void zoh_reset (SRC_STATE *state) ;
|
|
||||||
static SRC_STATE *zoh_copy (SRC_STATE *state) ;
|
|
||||||
static void zoh_close (SRC_STATE *state) ;
|
|
||||||
|
|
||||||
/*========================================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ZOH_MAGIC_MARKER MAKE_MAGIC ('s', 'r', 'c', 'z', 'o', 'h')
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{ int zoh_magic_marker ;
|
|
||||||
int dirty ;
|
|
||||||
long in_count, in_used ;
|
|
||||||
long out_count, out_gen ;
|
|
||||||
float *last_value ;
|
|
||||||
} ZOH_DATA ;
|
|
||||||
|
|
||||||
static SRC_STATE_VT zoh_state_vt =
|
|
||||||
{
|
|
||||||
zoh_vari_process,
|
|
||||||
zoh_vari_process,
|
|
||||||
zoh_reset,
|
|
||||||
zoh_copy,
|
|
||||||
zoh_close
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static SRC_ERROR
|
|
||||||
zoh_vari_process (SRC_STATE *state, SRC_DATA *data)
|
|
||||||
{ ZOH_DATA *priv ;
|
|
||||||
double src_ratio, input_index, rem ;
|
|
||||||
int ch ;
|
|
||||||
|
|
||||||
if (data->input_frames <= 0)
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
if (state->private_data == NULL)
|
|
||||||
return SRC_ERR_NO_PRIVATE ;
|
|
||||||
|
|
||||||
priv = (ZOH_DATA*) state->private_data ;
|
|
||||||
|
|
||||||
if (!priv->dirty)
|
|
||||||
{ /* If we have just been reset, set the last_value data. */
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
priv->last_value [ch] = data->data_in [ch] ;
|
|
||||||
priv->dirty = 1 ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
priv->in_count = data->input_frames * state->channels ;
|
|
||||||
priv->out_count = data->output_frames * state->channels ;
|
|
||||||
priv->in_used = priv->out_gen = 0 ;
|
|
||||||
|
|
||||||
src_ratio = state->last_ratio ;
|
|
||||||
|
|
||||||
if (is_bad_src_ratio (src_ratio))
|
|
||||||
return SRC_ERR_BAD_INTERNAL_STATE ;
|
|
||||||
|
|
||||||
input_index = state->last_position ;
|
|
||||||
|
|
||||||
/* Calculate samples before first sample in input array. */
|
|
||||||
while (input_index < 1.0 && priv->out_gen < priv->out_count)
|
|
||||||
{
|
|
||||||
if (priv->in_used + state->channels * input_index >= priv->in_count)
|
|
||||||
break ;
|
|
||||||
|
|
||||||
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
|
|
||||||
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
|
|
||||||
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
{ data->data_out [priv->out_gen] = priv->last_value [ch] ;
|
|
||||||
priv->out_gen ++ ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Figure out the next index. */
|
|
||||||
input_index += 1.0 / src_ratio ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
rem = fmod_one (input_index) ;
|
|
||||||
priv->in_used += state->channels * psf_lrint (input_index - rem) ;
|
|
||||||
input_index = rem ;
|
|
||||||
|
|
||||||
/* Main processing loop. */
|
|
||||||
while (priv->out_gen < priv->out_count && priv->in_used + state->channels * input_index <= priv->in_count)
|
|
||||||
{
|
|
||||||
if (priv->out_count > 0 && fabs (state->last_ratio - data->src_ratio) > SRC_MIN_RATIO_DIFF)
|
|
||||||
src_ratio = state->last_ratio + priv->out_gen * (data->src_ratio - state->last_ratio) / priv->out_count ;
|
|
||||||
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
{ data->data_out [priv->out_gen] = data->data_in [priv->in_used - state->channels + ch] ;
|
|
||||||
priv->out_gen ++ ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
/* Figure out the next index. */
|
|
||||||
input_index += 1.0 / src_ratio ;
|
|
||||||
rem = fmod_one (input_index) ;
|
|
||||||
|
|
||||||
priv->in_used += state->channels * psf_lrint (input_index - rem) ;
|
|
||||||
input_index = rem ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
if (priv->in_used > priv->in_count)
|
|
||||||
{ input_index += (priv->in_used - priv->in_count) / state->channels ;
|
|
||||||
priv->in_used = priv->in_count ;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
state->last_position = input_index ;
|
|
||||||
|
|
||||||
if (priv->in_used > 0)
|
|
||||||
for (ch = 0 ; ch < state->channels ; ch++)
|
|
||||||
priv->last_value [ch] = data->data_in [priv->in_used - state->channels + ch] ;
|
|
||||||
|
|
||||||
/* Save current ratio rather then target ratio. */
|
|
||||||
state->last_ratio = src_ratio ;
|
|
||||||
|
|
||||||
data->input_frames_used = priv->in_used / state->channels ;
|
|
||||||
data->output_frames_gen = priv->out_gen / state->channels ;
|
|
||||||
|
|
||||||
return SRC_ERR_NO_ERROR ;
|
|
||||||
} /* zoh_vari_process */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE const char*
|
|
||||||
zoh_get_name (int src_enum)
|
|
||||||
{
|
|
||||||
if (src_enum == SRC_ZERO_ORDER_HOLD)
|
|
||||||
return "ZOH Interpolator" ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* zoh_get_name */
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE const char*
|
|
||||||
zoh_get_description (int src_enum)
|
|
||||||
{
|
|
||||||
if (src_enum == SRC_ZERO_ORDER_HOLD)
|
|
||||||
return "Zero order hold interpolator, very fast, poor quality." ;
|
|
||||||
|
|
||||||
return NULL ;
|
|
||||||
} /* zoh_get_descrition */
|
|
||||||
|
|
||||||
static ZOH_DATA *
|
|
||||||
zoh_data_new (int channels)
|
|
||||||
{
|
|
||||||
assert (channels > 0) ;
|
|
||||||
|
|
||||||
ZOH_DATA *priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ;
|
|
||||||
if (priv)
|
|
||||||
{
|
|
||||||
priv->zoh_magic_marker = ZOH_MAGIC_MARKER ;
|
|
||||||
priv->last_value = (float *) calloc (channels, sizeof (float)) ;
|
|
||||||
if (!priv->last_value)
|
|
||||||
{
|
|
||||||
free (priv) ;
|
|
||||||
priv = NULL ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return priv ;
|
|
||||||
}
|
|
||||||
|
|
||||||
LIBSAMPLERATE_DLL_PRIVATE SRC_STATE *
|
|
||||||
zoh_state_new (int channels, SRC_ERROR *error)
|
|
||||||
{
|
|
||||||
assert (channels > 0) ;
|
|
||||||
assert (error != NULL) ;
|
|
||||||
|
|
||||||
SRC_STATE *state = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
|
|
||||||
if (!state)
|
|
||||||
{
|
|
||||||
*error = SRC_ERR_MALLOC_FAILED ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->channels = channels ;
|
|
||||||
state->mode = SRC_MODE_PROCESS ;
|
|
||||||
|
|
||||||
state->private_data = zoh_data_new (state->channels) ;
|
|
||||||
if (!state->private_data)
|
|
||||||
{
|
|
||||||
free (state) ;
|
|
||||||
*error = SRC_ERR_MALLOC_FAILED ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->vt = &zoh_state_vt ;
|
|
||||||
|
|
||||||
zoh_reset (state) ;
|
|
||||||
|
|
||||||
*error = SRC_ERR_NO_ERROR ;
|
|
||||||
|
|
||||||
return state ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*===================================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
zoh_reset (SRC_STATE *state)
|
|
||||||
{ ZOH_DATA *priv ;
|
|
||||||
|
|
||||||
priv = (ZOH_DATA*) state->private_data ;
|
|
||||||
if (priv == NULL)
|
|
||||||
return ;
|
|
||||||
|
|
||||||
priv->dirty = 0 ;
|
|
||||||
memset (priv->last_value, 0, sizeof (float) * state->channels) ;
|
|
||||||
|
|
||||||
return ;
|
|
||||||
} /* zoh_reset */
|
|
||||||
|
|
||||||
static SRC_STATE *
|
|
||||||
zoh_copy (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
assert (state != NULL) ;
|
|
||||||
|
|
||||||
if (state->private_data == NULL)
|
|
||||||
return NULL ;
|
|
||||||
|
|
||||||
SRC_STATE *to = (SRC_STATE *) calloc (1, sizeof (SRC_STATE)) ;
|
|
||||||
if (!to)
|
|
||||||
return NULL ;
|
|
||||||
memcpy (to, state, sizeof (SRC_STATE)) ;
|
|
||||||
|
|
||||||
ZOH_DATA* from_priv = (ZOH_DATA*) state->private_data ;
|
|
||||||
ZOH_DATA *to_priv = (ZOH_DATA *) calloc (1, sizeof (ZOH_DATA)) ;
|
|
||||||
if (!to_priv)
|
|
||||||
{
|
|
||||||
free (to) ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy (to_priv, from_priv, sizeof (ZOH_DATA)) ;
|
|
||||||
to_priv->last_value = (float *) malloc (sizeof (float) * state->channels) ;
|
|
||||||
if (!to_priv->last_value)
|
|
||||||
{
|
|
||||||
free (to) ;
|
|
||||||
free (to_priv) ;
|
|
||||||
return NULL ;
|
|
||||||
}
|
|
||||||
memcpy (to_priv->last_value, from_priv->last_value, sizeof (float) * state->channels) ;
|
|
||||||
|
|
||||||
to->private_data = to_priv ;
|
|
||||||
|
|
||||||
return to ;
|
|
||||||
} /* zoh_copy */
|
|
||||||
|
|
||||||
static void
|
|
||||||
zoh_close (SRC_STATE *state)
|
|
||||||
{
|
|
||||||
if (state)
|
|
||||||
{
|
|
||||||
ZOH_DATA *zoh = (ZOH_DATA *) state->private_data ;
|
|
||||||
if (zoh)
|
|
||||||
{
|
|
||||||
if (zoh->last_value)
|
|
||||||
{
|
|
||||||
free (zoh->last_value) ;
|
|
||||||
zoh->last_value = NULL ;
|
|
||||||
}
|
|
||||||
free (zoh) ;
|
|
||||||
zoh = NULL ;
|
|
||||||
}
|
|
||||||
free (state) ;
|
|
||||||
state = NULL ;
|
|
||||||
}
|
|
||||||
} /* zoh_close */
|
|
Loading…
Reference in a new issue