cut

package
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package cut removes time ranges from an audio file.

Range math is kept pure in ranges.go. RangesFromSegments converts SponsorBlock segments into removal ranges, and Render applies the resulting cut in one of three modes:

  • Copy: stream-copy the retained spans and concatenate them. No re-encode, but boundaries snap to packet/frame edges. Some containers, notably raw FLAC, keep a stale duration header after a copy even though the audio is trimmed correctly; accurate mode avoids that.
  • Accurate: trim sample-exactly and re-encode through a -filter_complex graph, so boundaries are exact. Required for a crossfade.
  • Smart (default): copy when no encode is involved, accurate when a transcode, filter, or crossfade is requested.

Cut builds the copy commands and filter graphs; transcode owns ffmpeg execution.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Graph

func Graph(keeps []Range, crossfade, total time.Duration, sink string) string

Graph builds an ffmpeg -filter_complex graph that trims [0:a:0] to the keep ranges and joins the pieces at [sink]. Callers either map [sink] or continue the graph from it, such as appending loudnorm before a final [out].

total is the true media duration: a keep span that reaches it drops its atrim end bound and runs cleanly to EOF instead of relying on a rounded end time.

Each kept span is isolated with atrim and rebased to a zero start with asetpts. When crossfade > 0 and more than one span remains, adjacent spans are joined with acrossfade instead of concat. Graph returns "" when there is nothing to keep.

func OutputDuration

func OutputDuration(keeps []Range, crossfade time.Duration) time.Duration

OutputDuration is the length of the rendered keep ranges. A crossfade overlaps adjacent spans, so it shortens the output by one crossfade per join.

func ValidateCrossfade

func ValidateCrossfade(keeps []Range, d time.Duration) error

ValidateCrossfade checks whether the retained spans can supply the requested overlap. acrossfade consumes d from both sides of each join, so an interior span must be at least 2*d. Rejecting short spans before ffmpeg avoids a successful command that emits no audio.

Types

type Mode

type Mode uint8

Mode selects how a cut is rendered. The facade maps waxtap.CutMode onto these.

const (
	// ModeSmart copies unless the spec needs decoding: an output codec, encode
	// filters, or a crossfade.
	ModeSmart Mode = iota
	// ModeCopy uses stream copy. It cannot transcode, apply filters, or crossfade.
	ModeCopy
	// ModeAccurate decodes, trims sample-exactly, and re-encodes. It requires an
	// output codec, not CodecCopy.
	ModeAccurate
)

func (Mode) String

func (m Mode) String() string

type Range

type Range struct {
	Start time.Duration
	End   time.Duration
}

Range is a half-open [Start, End) time span. End must be greater than Start to describe a non-empty span.

func Keeps

func Keeps(removals []Range, total time.Duration) []Range

Keeps returns the spans to retain: the complement of the (merged) removal ranges within [0, total], in order. It is what the cut filtergraph trims and concatenates. With no effective removals it returns the whole [0, total] span; when the removals cover everything it returns nil. total must be > 0.

func Merge

func Merge(ranges []Range, total time.Duration) []Range

Merge normalizes removal ranges against a known media duration: it clamps each range to [0, total], drops empty ones, sorts by start, and merges overlapping or touching ranges. The result is sorted and disjoint. total must be > 0.

func RangesFromSegments

func RangesFromSegments(segs []sponsorblock.Segment) []Range

RangesFromSegments converts SponsorBlock skip segments into removal ranges. Merge/Keeps handle ordering, clamping, and overlap merging after the media duration is known.

func (Range) Duration

func (r Range) Duration() time.Duration

Duration returns the span length, or zero when the range is empty or inverted.

type Result

type Result struct {
	Output  string        // final output path (empty when Applied is false)
	Removed time.Duration // total audio removed
	Mode    Mode          // effective mode used; Smart is resolved before rendering
	// Applied is false when no ranges remained after clamping/merging, in which
	// case Render writes no output and the caller proceeds with the source
	// unchanged.
	Applied bool
}

Result reports a completed cut.

func Render

func Render(ctx context.Context, r *transcode.Runner, input, output string, spec Spec) (Result, error)

Render applies spec's cut to input and writes the result to output. It probes input to clamp ranges against the real duration, then renders per the resolved mode. Output is staged and atomically renamed on success; failures and cancellation leave output untouched.

When the ranges remove nothing (empty after clamping/merging), Render writes no output and returns Applied=false. When they would remove the entire track it returns ErrIncompatibleSpec.

type Spec

type Spec struct {
	// Remove lists the [Start, End) spans to delete. They are clamped to the
	// probed media duration and merged, so overlaps and out-of-range values are
	// harmless.
	Remove []Range
	// Mode selects copy/accurate/smart rendering.
	Mode Mode
	// Crossfade blends adjacent retained spans over this duration. It is ignored
	// when only one span remains and rejected in copy mode.
	Crossfade time.Duration
	// Encode configures the accurate path. Codec and Bitrate select the output;
	// Filters are appended to the cut graph because ffmpeg cannot combine -af
	// with the -filter_complex graph used for cutting. Render owns
	// FilterComplex. Leave Encode zero for a copy cut.
	Encode transcode.Spec
}

Spec describes a cut.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL