Normalize Linux audio pipeline to lossless Float32 (skill: lossless-audio-compliance)
- native bridge WAV writers: 16-bit PCM truncation -> IEEE Float32 (fmt 3, bit-exact) - vendor sheredom_json.h (vst3sdk 3.8.1 lacks moduleinfo/json.h) - Dockerfile: drop nonexistent sfizz tag v1.2.3 - Python sf.write -> subtype=FLOAT everywhere - resample_poly -> kaiser(16) window (>=130dB stopband) - audio_editor._write_wav_lossless(): FLOAT passthrough, TPDF dither only for 8/16/24-bit final exports - app.jsx WAV encoders: Float32 default, TPDF dither for integer depths, fix 24-bit - tests: lossless compliance gate (null test < -140dBFS, float32 format) 9/9 pass - TASKS_WINDOWS_AUDIO_NORMALIZE.md: Windows-side remaining tasks
This commit is contained in:
@@ -11,7 +11,12 @@
|
||||
// buffers copied directly (setChannelBuffers is unusable: prepare() owns them).
|
||||
#include "RenderFxJob.h"
|
||||
|
||||
// sheredom/json.h (public domain) — vendored copy; SDK copy as fallback.
|
||||
#if __has_include("sheredom_json.h")
|
||||
#include "sheredom_json.h"
|
||||
#elif __has_include("vst3sdk/public.sdk/source/vst/moduleinfo/json.h")
|
||||
#include "vst3sdk/public.sdk/source/vst/moduleinfo/json.h"
|
||||
#endif
|
||||
#ifdef HAVE_VST3SDK
|
||||
#include "public.sdk/source/vst/hosting/module.h"
|
||||
#include "public.sdk/source/vst/hosting/hostclasses.h"
|
||||
@@ -92,7 +97,10 @@ bool memberBool(const json_object_s* o, const char* key, bool def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
// --- WAV writer (stdlib only, 16-bit PCM stereo, little-endian) --------------
|
||||
// --- WAV writer (stdlib only, IEEE Float32 stereo, little-endian) ------------
|
||||
// Lossless: keeps the full float32 render buffer bit-exact. No PCM truncation
|
||||
// and no dither here — dither/quantization belongs ONLY to a final export
|
||||
// stage (lossless-audio-compliance skill, Rules 4 & 7). Format tag 3.
|
||||
void writeU16(std::ofstream& f, uint16_t v) {
|
||||
char b[2] = { (char)(v & 0xFF), (char)((v >> 8) & 0xFF) };
|
||||
f.write(b, 2);
|
||||
@@ -108,12 +116,12 @@ void writeWavHeader(std::ofstream& f, uint32_t sampleRate) {
|
||||
f.write("WAVE", 4);
|
||||
f.write("fmt ", 4);
|
||||
writeU32(f, 16);
|
||||
writeU16(f, 1);
|
||||
writeU16(f, 3); // IEEE float
|
||||
writeU16(f, 2);
|
||||
writeU32(f, sampleRate);
|
||||
writeU32(f, sampleRate * 4);
|
||||
writeU16(f, 4);
|
||||
writeU16(f, 16);
|
||||
writeU32(f, sampleRate * 8); // byte rate = sr * 2ch * 4B
|
||||
writeU16(f, 8);
|
||||
writeU16(f, 32);
|
||||
f.write("data", 4);
|
||||
writeU32(f, 0);
|
||||
}
|
||||
@@ -125,14 +133,10 @@ void finishWav(std::ofstream& f, uint64_t dataBytes) {
|
||||
f.flush();
|
||||
}
|
||||
void writeFrames(std::ofstream& f, const float* L, const float* R, uint32_t n) {
|
||||
// IEEE float32 little-endian, bit-exact: no clamp, no quantization.
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
auto cl = [](float v) -> int {
|
||||
if (v > 1.0f) v = 1.0f;
|
||||
else if (v < -1.0f) v = -1.0f;
|
||||
return (int)(v * 32767.0f);
|
||||
};
|
||||
writeU16(f, (uint16_t)cl(L[i]));
|
||||
writeU16(f, (uint16_t)cl(R[i]));
|
||||
f.write(reinterpret_cast<const char*>(&L[i]), 4);
|
||||
f.write(reinterpret_cast<const char*>(&R[i]), 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user