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:
@@ -9,9 +9,17 @@
|
||||
#include "RenderJob.h"
|
||||
#include "NativeInstrumentEngine.h"
|
||||
|
||||
// sheredom/json.h (public domain, vendored with the VST3 SDK) is header-only
|
||||
// and needed for SF2/SFZ render even without the VST3 SDK — include it directly.
|
||||
// sheredom/json.h (public domain) is header-only and needed for SF2/SFZ render
|
||||
// even without the VST3 SDK. Vendored copy: native_bridge/include/sheredom_json.h
|
||||
// (the pinned VST3 SDK v3.8.1 has no moduleinfo/json.h); fall back to the SDK
|
||||
// copy when a newer checkout provides it.
|
||||
#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"
|
||||
#else
|
||||
#error "sheredom/json.h not found — vendored copy at native_bridge/include/sheredom_json.h"
|
||||
#endif
|
||||
#ifdef HAVE_VST3SDK
|
||||
#include "public.sdk/source/vst/vstpresetfile.h"
|
||||
#include "public.sdk/source/common/memorystream.h"
|
||||
@@ -75,7 +83,10 @@ int64_t memberInt(const json_object_s* o, const char* key, int64_t def) {
|
||||
return memberNumber(o, key, d) ? (int64_t)d : 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);
|
||||
@@ -91,12 +102,12 @@ void writeWavHeader(std::ofstream& f, uint32_t sampleRate) {
|
||||
f.write("WAVE", 4);
|
||||
f.write("fmt ", 4);
|
||||
writeU32(f, 16); // fmt chunk size
|
||||
writeU16(f, 1); // PCM
|
||||
writeU16(f, 3); // IEEE float
|
||||
writeU16(f, 2); // stereo
|
||||
writeU32(f, sampleRate);
|
||||
writeU32(f, sampleRate * 4); // byte rate
|
||||
writeU16(f, 4); // block align
|
||||
writeU16(f, 16); // bits per sample
|
||||
writeU32(f, sampleRate * 8); // byte rate = sr * 2ch * 4B
|
||||
writeU16(f, 8); // block align
|
||||
writeU16(f, 32); // bits per sample
|
||||
f.write("data", 4);
|
||||
writeU32(f, 0); // patched in finishWav
|
||||
}
|
||||
@@ -108,14 +119,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