Matching a simulated sound to a recording by post-processing#
This directory holds scripts for imposing the frequency-dependent decay of a recorded sheet on a simulated sound, as a quick way to hear how far the loss model is from the real sheet before changing the model itself. The generated audio and figures are not committed.
Files#
analyze.py WAV ...: per-band levels, fitted decay times and the strongest partials of one or more clips.match.py REFERENCE.wav SIMULATED.{wav,f32} OUT: aligns both sounds at their onsets, measures band envelopes on a third-octave grid with a 4096-sample STFT, and writesOUT_decay.wav(the simulation with the recording's per-band decay rates, its own initial balance kept),OUT_envelope.wav(the recording's whole band envelope, balance and decay, imposed on the simulation), and the aligned inputsOUT_reference_aligned.wavandOUT_sim_aligned.wav. All outputs are level-matched on the body of the sound (RMS over 0.1 to 1 s) and the attack is soft-clipped.plot.py OUT: spectrograms of the four clips and band decay curves of the recording against the simulation.modes.ts OUT.bin [key=value ...]andmodes.py OUT.bin OUT.json [fmax]: linearized mode frequencies of the model sheet (all three displacement fields, including the stiffening by the initial bow), for comparing the model's partials with a recording without running the simulator. Any parameter can be overridden, for examplebowAmplitude=0orE=178e9.
match.py takes --bands N to set the number of bands per octave (default 3). Twelfth-octave bands are narrow enough to weight individual partials, which makes the result closer to the recording but says less about the loss model.
The simulated input should be the raw float pressure that steelsim render writes next to the wav (NAME.f32); a 16-bit wav loses the tail of the simulated sound after a few seconds.
Method and its limits#
For each band the recording's decay rate is fitted from 0.15 s until the band comes within 6 dB of its noise floor (estimated from the pre-onset segment and from the end of the recording). A band that reaches the floor within half a second gives only a lower bound on its decay rate, which is used as is; a band that sits at the floor from the start (the lowest bands of the recording, which are within a few decibels of the room noise) carries no information, and the decay rate of the nearest determined band is borrowed. The gain applied to the simulation is the difference of the two decay rates times the time since the onset (decay mode), or the difference of the two envelopes while the recording is above its floor and the extrapolated slope afterwards (envelope mode). The gains are interpolated across STFT bins linearly in log frequency and the sound is resynthesized by inverse STFT.
The procedure changes envelopes, not partial frequencies: the modes of the simulated sheet stay where they are. It also cannot separate the attack from the early ring, so the first 100 ms are scaled like the early ring.