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:
2026-08-18 11:50:26 +07:00
parent c382afe2a6
commit a2f93138be
18 changed files with 3842 additions and 72 deletions
+16 -12
View File
@@ -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);
}
}