Depends on
Streaming support and the Lofty metadata refactor both need to land first. The commands here operate on the PCM stream format from the streaming issue, and the ReplayGain write step uses Lofty for tag I/O.
Manipulation commands
sound trim
Cut audio from the start or end of a stream.
sound decode audio.flac | sound trim --start 5sec --end 10sec | sound play
Rodio already has skip_duration and take_duration on Source. This is mostly just exposing those as a pipeline step.
sound fade
Apply a fade in, fade out, or both.
sound decode audio.flac | sound fade --in 2sec --out 3sec | sound play
Rodio has fade_in. Fade out needs a small custom Source wrapper since Rodio doesn't provide one — multiply sample amplitude by a linearly decreasing envelope over the tail duration. Straightforward enough.
sound amplify
Adjust volume by a fixed factor. This is distinct from the -a flag on sound play because it operates on the stream itself, making it composable with other steps.
sound decode audio.flac | sound amplify 0.5 | sound trim --start 5sec | sound play
sound concat
Combine multiple streams sequentially.
[intro.flac main.flac outro.flac] | each { sound decode $in } | sound concat | sound play
Analysis commands
sound scan
Measure loudness and peak levels of a stream. Returns a record, doesn't play anything.
sound decode audio.flac | sound scan
Example output:
╭──────────────────┬──────────╮
│ integrated_lufs │ -14.2 │
│ loudness_range │ 6.1 │
│ true_peak_dbtp │ -1.3 │
│ track_gain_db │ 1.8 │
╰──────────────────┴──────────╯
Uses the ebur128 crate for EBU R128 loudness measurement, which is the basis for ReplayGain 2.0. The scan consumes the stream so decoding happens before scanning.
sound replaygain
Scans and writes ReplayGain tags back to a file using Lofty. Supports track and album gain modes.
Track gain (per file):
ls *.flac | each { |f|
sound decode $f.name | sound scan | sound replaygain write $f.name
}
Album gain requires a shared loudness reference across all tracks, which is where Nushell's pipeline really helps:
ls *.flac | each { |f|
{ file: $f.name, scan: (sound decode $f.name | sound scan) }
} | sound replaygain album
Album mode collects all per-track measurements, computes integrated loudness across all of them, then writes both per-track and album gain tags to each file.
Tags written:
REPLAYGAIN_TRACK_GAIN
REPLAYGAIN_TRACK_PEAK
REPLAYGAIN_ALBUM_GAIN
REPLAYGAIN_ALBUM_PEAK
These follow the standard names so other players pick them up without any extra configuration.
sound silence
Detect silence spans in a stream and return them as a table. Useful for splitting recordings or trimming padding automatically.
sound decode audio.flac | sound silence --threshold -40db --min-duration 500ms
Example output:
╭───┬────────────┬────────────┬──────────╮
│ # │ start │ end │ duration │
├───┼────────────┼────────────┼──────────┤
│ 0 │ 0ns │ 1sec │ 1sec │
│ 1 │ 3min 22sec │ 3min 25sec │ 3sec │
╰───┴────────────┴────────────┴──────────╯
Applying ReplayGain during playback
Once tags are written, sound play should be able to apply them at playback time:
sound play audio.flac --replaygain track
sound play audio.flac --replaygain album
Reads the appropriate gain tag via Lofty and feeds the computed factor into Rodio's amplify wrapper. The math is just:
gain_factor = 10 ^ (replaygain_db / 20)
New dependencies
ebur128 for loudness measurement. Actively maintained, no significant transitive complexity. Everything else is already present via Rodio and Lofty.
Depends on
Streaming support and the Lofty metadata refactor both need to land first. The commands here operate on the PCM stream format from the streaming issue, and the ReplayGain write step uses Lofty for tag I/O.
Manipulation commands
sound trimCut audio from the start or end of a stream.
Rodio already has
skip_durationandtake_durationonSource. This is mostly just exposing those as a pipeline step.sound fadeApply a fade in, fade out, or both.
Rodio has
fade_in. Fade out needs a small customSourcewrapper since Rodio doesn't provide one — multiply sample amplitude by a linearly decreasing envelope over the tail duration. Straightforward enough.sound amplifyAdjust volume by a fixed factor. This is distinct from the
-aflag onsound playbecause it operates on the stream itself, making it composable with other steps.sound concatCombine multiple streams sequentially.
Analysis commands
sound scanMeasure loudness and peak levels of a stream. Returns a record, doesn't play anything.
Example output:
Uses the
ebur128crate for EBU R128 loudness measurement, which is the basis for ReplayGain 2.0. The scan consumes the stream so decoding happens before scanning.sound replaygainScans and writes ReplayGain tags back to a file using Lofty. Supports track and album gain modes.
Track gain (per file):
Album gain requires a shared loudness reference across all tracks, which is where Nushell's pipeline really helps:
Album mode collects all per-track measurements, computes integrated loudness across all of them, then writes both per-track and album gain tags to each file.
Tags written:
REPLAYGAIN_TRACK_GAINREPLAYGAIN_TRACK_PEAKREPLAYGAIN_ALBUM_GAINREPLAYGAIN_ALBUM_PEAKThese follow the standard names so other players pick them up without any extra configuration.
sound silenceDetect silence spans in a stream and return them as a table. Useful for splitting recordings or trimming padding automatically.
Example output:
Applying ReplayGain during playback
Once tags are written,
sound playshould be able to apply them at playback time:Reads the appropriate gain tag via Lofty and feeds the computed factor into Rodio's
amplifywrapper. The math is just:New dependencies
ebur128for loudness measurement. Actively maintained, no significant transitive complexity. Everything else is already present via Rodio and Lofty.