Meter each track and the song, and limit the output at -1 dBFS (#359)
A song could clip at the output without anyone noticing: a track and a sound item at +12 dB each add up to +24 dB. The Song tab now shows how loud each track and the whole song are, and a fixed limiter behind the master keeps every sample under -1 dBFS in the editor and in the game. - Each track head has a stereo meter up its right edge. The head is 190 px wide instead of 176. - Out sits in the corner above the heads, with the loudest peak since Play in dB. In the tab header it made the row too wide for a 1280 px window, and the inspector lost its fields. - The meters read AnalyserNodes beside the buses, one per side after a channel splitter, so a peak panned hard is not halved. They are tapped only while the song plays and its tab is shown. - A clip lamp lights past 0 dBFS and stays through Stop. The next Play or a click on the meter puts it out. - The meter of a track that mute or solo keeps from being heard is grey. - Music always plays through a bus of its own, with or without a sound FX. That bus is what Out measures. - The limiter is the one from #326 and needs the FX worklet. Until that is loaded the master goes straight out. - It is 5 ms late. latency() counts that in, so the playhead and the alignment of a recorded take follow it. - Unit tests build SoundLibrary without the limiter, as their wiring checks follow every node of a voice. - Out shows "-inf" while nothing was loud. The UI font has no infinity sign, which the font test found. Tests: - Unit meter-view 8 new, sound-library 112 (2 new), 3 counter-tests each red - e2e 65 (melektaus-atx): ALL PASSED, 55 checks (3 new). Out wrote +16.6 dB, behind the limiter the loudest sample was 0.8913 - Gate (melektaus-atx): 272 files, 4209 tests, one red in the font test. Fixed after it, then the font and meter tests ran green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dc666016db
commit
490fcba88f
12 files changed
+810
-137
No files matched your search
@@ -44,6 +44,20 @@ export function songHooks({ state, editor }: HookContext) {
|
||||
clock: () => soundLibrary.clock(),
|
||||
stats: () => soundLibrary.stats(),
|
||||
buses: () => soundLibrary.busLevels(),
|
||||
/** The level meters (#359): each track's by its id and Out, in dB, and how many buses are tapped. */
|
||||
meters: () => {
|
||||
const asset = findAssetOf(state.project, songEditor.currentAssetId, 'song');
|
||||
return {
|
||||
tracks: Object.fromEntries((asset?.tracks ?? []).map((t) => [t.id, timeline.meterOf(t.id)])),
|
||||
out: timeline.outShown(),
|
||||
metered: soundLibrary.metered(),
|
||||
};
|
||||
},
|
||||
/** The loudest sample on each side behind the limiter at the output, null without it. */
|
||||
guard: () => soundLibrary.guardPeaks(),
|
||||
latency: () => soundLibrary.latency(),
|
||||
meterAt: (track: number) => timeline.meterPoint(track),
|
||||
outAt: () => timeline.outPoint(),
|
||||
/** Timeline or Routing (#350), and where their switches are. */
|
||||
shown: () => songEditor.view,
|
||||
viewAt: (view: 'timeline' | 'routing') =>
|
||||
|
||||
Reference in new issue
Block a user