Limiter
Turns 48 kHz interleaved stereo 32-bit float audio into 16-bit PCM at a volume, through a look-ahead peak limiter, so audio that would pass full scale is turned down smoothly instead of clipped.
- A non-finite sample (Inf or NaN) becomes 0 before anything else.
- The volume, from 0 to 4, multiplies each sample. A change ramps linearly over 20 ms (960 frames), carried across calls of any size; a volume set before the first frame applies at once.
- The limiter links both channels and looks 5 ms (240 frames) ahead. It keeps every sample within a per-sign ceiling, +32767/32768 for positive samples and -1.0 for negative ones, the values that scale to exactly 32767 and -32768. A reduction ramps in over the look-ahead, no frame's gain is ever above the gain that frame needs, and the gain rises back along a straight line over 50 ms to exactly 1.
- Each sample is then scaled by 32768 and rounded. A clamp to the 16-bit range backs that up; it never engages,
and
clampCountcounts it for tests.
Audio that never passes the ceiling after the volume comes out bit for bit as a plain conversion would give it,
only 240 frames late. process holds those frames back, so it returns fewer frames than it takes until the
look-ahead is full, and flush returns them at the end, so as many frames leave as entered.
Summary
Properties
Limiter.volume :: numberLimiter.gain :: numberLimiter.clampCount :: numberLimiter.flushed :: booleanLimiter.heldFrames :: numberLimiter.LOOKAHEAD_FRAMES :: numberLimiter.heard :: booleanLimiter.rampFrom :: numberLimiter.rampTo :: numberLimiter.rampPosition :: numberLimiter.delayLeft :: { number }Limiter.delayRight :: { number }Limiter.delayRequired :: { number }Limiter.delayIndex :: numberLimiter.enteredFrames :: numberLimiter.minimumFrames :: { number }Limiter.minimumGains :: { number }Limiter.minimumFirst :: numberLimiter.minimumCount :: numberLimiter.window :: { number }Limiter.windowIndex :: numberLimiter.windowSum :: numberLimiter.windowReduced :: numberLimiter.releaseFrom :: numberLimiter.releasePosition :: numberProperties
Section titled “Properties”volume
Section titled “volume”The volume setVolume last set, from 0 to 4; 1 until then.
The limiter's gain on the last frame that left, from 0 to 1: exactly 1 while nothing is reduced.
clampCount
Section titled “clampCount”How many samples the backstop clamp has changed; for tests, since the limiter keeps it at 0.
flushed
Section titled “flushed”Whether flush has run, after which process raises.
heldFrames
Section titled “heldFrames”The frames that entered and have not left yet, up to the 240-frame look-ahead.
LOOKAHEAD_FRAMES
Section titled “LOOKAHEAD_FRAMES”The look-ahead in frames, 240 (5 ms at 48 kHz), on the module: output is late by exactly this much.
Whether a frame has been taken at some volume. Until one has, a new volume applies at once.
rampFrom
Section titled “rampFrom”The volume gain the current ramp started from.
rampTo
Section titled “rampTo”The volume the current ramp ends at.
rampPosition
Section titled “rampPosition”The frames of the current ramp taken so far, up to 960, where the gain is exactly rampTo.
delayLeft
Section titled “delayLeft”The left samples of the held frames, after the volume, in a ring of 240 slots.
delayRight
Section titled “delayRight”The right samples of the held frames, after the volume, in a ring of 240 slots.
delayRequired
Section titled “delayRequired”The gain each held frame needs to stay within the ceiling, in a ring of 240 slots.
delayIndex
Section titled “delayIndex”The slot the next frame enters: once 240 frames are held, the slot of the frame that leaves.
enteredFrames
Section titled “enteredFrames”The frames taken in so far, counting the silence flush adds; the next frame's number.
minimumFrames
Section titled “minimumFrames”The frame numbers of the candidates for the lowest required gain among the last 241 frames, in a ring of 241 slots, oldest first.
minimumGains
Section titled “minimumGains”The required gains of those candidates, strictly rising, so the first is the lowest.
minimumFirst
Section titled “minimumFirst”The slot of the first candidate.
minimumCount
Section titled “minimumCount”How many candidates the ring holds.
window
Section titled “window”The lowest required gain in each of the last 240 windows of 241 frames, one window ending at each frame taken, in a ring of 240 slots. It starts full of 1s, for the windows that end before the audio.
windowIndex
Section titled “windowIndex”The slot of the oldest entry in window, which the next one replaces.
windowSum
Section titled “windowSum”The running sum of window.
windowReduced
Section titled “windowReduced”How many entries of window are below 1. While none are, the sum is exactly 240 and the attack gain exactly 1.
releaseFrom
Section titled “releaseFrom”The gain the current release rises from.
releasePosition
Section titled “releasePosition”The frames into the current release, up to 2400, where the release line reaches exactly 1.
Methods
Section titled “Methods”setVolume
Section titled “setVolume”Limiter : setVolume ( volume ) -> ()
Sets the volume, a number from 0 to 4, where 1 leaves the audio as it is. A change ramps linearly over the next 20 ms of frames taken; a volume set before the first frame applies at once.
Raises volume must be a number from 0 to 4 for a number outside that range, through checkVolume, keeping the old
volume. Callers that take a volume from users check its type first, as Decoder.checkVolume does.
Parameters
| volume: number |
process
Section titled “process”Limiter : process ( floats , frames ) -> buffer
Takes frames frames of 48 kHz interleaved stereo 32-bit float samples from floats and returns the frames that
leave, as interleaved stereo 16-bit little-endian PCM. The limiter holds the last 240 frames back, so the result is
shorter than the input until that many have entered; blocks of any size give the same audio.
Raises limiter has been flushed after flush, and frames must be a whole number from 0 to <count>, the frames the buffer holds when frames is negative, fractional or more than the buffer holds; a raise changes nothing.
Parameters
| floats: buffer | |
| frames: number |
Returns
| buffer |
framesNeeded
Section titled “framesNeeded”Limiter : framesNeeded ( outputFrames ) -> number
The frames process must take to return outputFrames: that many, plus the part of the look-ahead not yet held,
so the first call takes 240 more than it returns.
Limiter : flush ( ) -> buffer
Returns the frames still held, as 16-bit PCM, at the end of the audio, and only those: as many frames leave in all as entered, however few that is. They leave as if the audio had gone on in silence. A second call returns an empty buffer.
Returns
| buffer |
Functions
Section titled “Functions”checkVolume
Section titled “checkVolume”Limiter . checkVolume ( volume ) -> ()
Raises volume must be a number from 0 to 4 unless volume is in that range; NaN and Inf fail too. It owns the
range and the message: setVolume uses it, and so does Decoder.checkVolume, which checks the type of a volume
that users hand in before it gets here.
Parameters
| volume: number |
Limiter . new ( ) -> Limiter
Creates a limiter at volume 1 that has taken nothing yet.
Returns
| Limiter |