audiotree.sources¶
- exception AudioReadError(message: str, file_path: str)¶
One audio file could not be read.
Raised by the dataset loaders in place of whatever the decoding stack threw, so that a corrupt file in a large corpus always names itself. The original exception is kept as
__cause__and the path asfile_path.The wrapping exists because the underlying exception frequently does not identify the file.
soundfileputs the path in its message, but a truncated header sendslibrosadown itsaudioreadfallback, which surfaces anEOFErroror anaudioread.exceptions.NoBackendErrorwhosestr()is empty – a blank traceback line at the end of a multi-hour run.Note
On Windows, holding one of these keeps the offending file open. The traceback references librosa’s
audioreadfallback frames, which hold a file handle, and Windows will not delete or replace an open file. It matters only if you accumulate errors rather than handling them – collecterr.file_pathandstr(err)and let the exception go, or callgc.collect()after dropping it (exception and traceback reference each other, so refcounting alone does not free it).- Variables:
file_path – The file that could not be read.
- class WindowConfig(duration: float = 1.0, hop: float | None = None, alpha: float = 1.0, jitter: bool = True, lufs_cache: str | None = None, lufs_cutoff: float = -40.0, lufs_window_sec: float | None = None)¶
Windowing knobs for length-aware sampling, bundled for reuse.
Pass an instance as
window=tocreate_balanced_audio_dataset()to build every file-based group withcreate_windowed_audio_dataset()instead of the default one-excerpt-per-file behavior. The fields mirror that function’s windowing arguments (sample_rate/monostay on the dataset call so a single value applies across groups).- Variables:
duration (float) – Length in seconds of each excerpt.
hop (float | None) – Stride in seconds between natural windows at
alpha == 1; defaults toduration(non-overlapping) when None.alpha (float) – Length power for slots-per-file (0 = uniform per file, 1 = proportional to length).
jitter (bool) – Randomize each draw’s offset within its slot’s stride.
lufs_cache (str | None) – Optional path to a cache from
build_window_lufs_cache()for build-time saliency filtering.lufs_cutoff (float) – Minimum per-window LUFS to keep a slot (when filtering).
lufs_window_sec (float | None) – Analysis window of the loudness cache; taken from the cache when
lufs_cacheis given.
- class WindowLufsCache(lufs: dict[str, ndarray], durations: dict[str, float] | None, lufs_window_sec: float, sample_rate: int | None, mono: bool, file_sizes: dict[str, int] | None = None)¶
A loaded windowed-loudness cache (see
load_window_lufs()).- Variables:
lufs (dict[str, numpy.ndarray]) – Mapping from filepath to its 1-D per-window LUFS array.
durations (dict[str, float] | None) – Mapping from filepath to duration in seconds, or
Noneif durations were not stored.lufs_window_sec (float) – The analysis window length the cache was built with.
sample_rate (int | None) – The sample rate the loudness was measured at (
Noneif native rates were used).mono (bool) – Whether channels were averaged to mono before measuring.
file_sizes (dict[str, int] | None) – Mapping from filepath to its byte size when the cache was built, or
Nonefor caches written before sizes were recorded. Used to detect a file re-rendered in place, whose cached durations and loudness would otherwise silently describe audio that no longer exists. (A rewrite that keeps the byte size identical is not detectable this way.)
- build_window_lufs_cache(filepaths: List[str], lufs_window_sec: float, out_dir: str | Path, *, sample_rate: int | None = 44100, mono: bool = True, durations: Mapping[str, float] | None = None) Path¶
Compute and persist a windowed-loudness cache in one preprocessing pass.
Convenience wrapper that runs
precompute_window_lufs(), scans durations (viascan_durations()unlessdurationsis given), and writes both toout_dirwithsave_window_lufs(). Run this once offline, then passlufs_cache=out_dirtocreate_windowed_audio_dataset().- Parameters:
filepaths – Audio file paths to analyze.
lufs_window_sec – Analysis window length in seconds.
out_dir – Directory to write the cache into.
sample_rate – If given, resample every file to this rate before analysis.
mono – If True, average channels to mono before analysis.
durations – Optional precomputed durations; scanned from headers if None.
- Returns:
The cache directory as a
Path.
- create_audio_dataset(sources: str | Path | List[str | Path] | None = None, filepaths: List[str | Path] | None = None, *, shuffle: bool = True, num_epochs: int | None = 1, shuffle_seed: int = 0, excerpt_seed: int | None = None, sample_rate: int = 44100, mono: bool = True, duration: float = 1.0, pad_mode: Literal['constant', 'edge', 'reflect', 'symmetric', 'wrap'] | None = 'constant', extensions: List[str] | None = None, excerpt: ExcerptConfig = ExcerptConfig(strategy='random', num_tries=8, lufs_cutoff=-40.0, search='uniform', on_failure='keep'), source: str | None = None, channels: int | None = None, on_read_error: Literal['raise', 'skip', 'warn'] = 'raise') MapDataset¶
Create a simple MapDataset from audio files.
This function creates a grain MapDataset that loads audio files from one or more directories. Unlike create_balanced_audio_dataset, this treats all files equally without balancing across groups.
- Parameters:
sources – A directory path, file path, or glob pattern (e.g.
"/data/*/mixture.wav"), or a list of them, containing audio files. Each entry may be astror aPath. Seefind_audio_files()for how each entry is resolved. Mutually exclusive withfilepaths— provide exactly one.filepaths – An explicit list of audio file paths to use instead of searching
sources. Mutually exclusive withsources— provide exactly one. Useful for custom splits (e.g. train/val) over a single directory without reorganizing it on disk. The given order is preserved (then shuffled ifshuffle=True).shuffle – Whether to shuffle files.
num_epochs – How many passes over the corpus the dataset yields.
Nonerepeats forever – what training wants – and makeslen(ds)reportsys.maxsize, grain’s spelling of “infinite”. An integern >= 1yields exactlynpasses, solen(ds)isntimes the file count;0or a negative count raises. Defaults to a single finite pass.shuffle_seed – Random seed for shuffling file order. The stream grain shuffles with is derived from this value, not used verbatim; see
excerpt_seed.excerpt_seed – Random seed for excerpt selection (random_map). If None, defaults to
shuffle_seed. The shuffle and excerpt streams are taken from two different draws of onenumpy.random.SeedSequence, so the file order and the excerpt offsets stay independent even when one seed feeds both. Use different values to create datasets that visit files in the same order but load different random excerpts.sample_rate – Target sample rate for audio files.
mono – Whether to convert audio to mono.
duration – Duration in seconds to load from each file.
pad_mode – Padding mode for files shorter than duration (numpy.pad modes). Options: “constant” (zeros), “edge” (repeat edge), “reflect” (mirror), “symmetric” (mirror with edge), “wrap” (circular), or None (no padding).
extensions – List of audio file extensions to search for. Defaults to [“.wav”, “.flac”].
excerpt – Which part of each file to take; see
ExcerptConfig. Defaults to a uniformly random offset.source – Optional source group name (e.g., “music”, “speech”) stored as provenance (
metadata["source"], read back via thesourceproperty). If None, nosourceprovenance is recorded.channels – Expected channel count of every file, so that a mixed-channel corpus fails at load time with the offending filename instead of at batch time with a shape error. Ignored when
mono=True(everything is one channel then). When None, the count is taken from the header of the first file, which makes the odd stereo file in a mono corpus (or vice versa) name itself.on_read_error –
What to do when one file cannot be read – truncated, zero-byte, unreadable by this process. In a 100k-file corpus a single such file otherwise ends a multi-hour run.
"raise"(default): raiseAudioReadError, which always names the path even when the underlying decoder error does not."warn": drop the item (the loader returnsNone, which grain skips at iteration) and emit aUserWarningnaming the file and the original error."skip": drop the item without warning, for a corpus already known to contain junk.
Dropping uses grain’s own convention: a
Noneelement passes through latermapstages untouched andto_iter_dataset()skips it, so batches stay full of real audio. Note that under a non-raising policyds[i]can therefore returnNonefor a broken file; iterate viato_iter_dataset()(or guard forNone) rather than assuming every index yields an item.
- Returns:
A grain.MapDataset that loads audio files using random_map for proper RNG seeding.
Example
Create a couple of short
.wavfiles in a temporary directory to load from:>>> import os, tempfile >>> import numpy as np >>> import soundfile >>> data_dir = tempfile.mkdtemp() >>> for i in range(2): ... soundfile.write( ... os.path.join(data_dir, f"clip_{i}.wav"), ... np.zeros((44100, 1), dtype=np.float32), ... 44100, ... )
Load all files from the directory. Each item is a single-example
AudioTreeshaped(Batch, Channels, Samples):>>> ds = create_audio_dataset(sources=data_dir, sample_rate=44100, duration=1.0) >>> len(ds) 2 >>> ds[0].waveform.shape (1, 1, 44100)
Training dataset (shuffled, repeating forever):
>>> train_ds = create_audio_dataset( ... sources=data_dir, ... shuffle=True, ... num_epochs=None, ... sample_rate=44100, ... duration=1.0, ... )
Validation dataset (deterministic, a single pass):
>>> val_ds = create_audio_dataset( ... sources=data_dir, ... shuffle=False, ... num_epochs=1, ... sample_rate=44100, ... duration=1.0, ... ) >>> len(val_ds) 2
Any finite number of passes, which a boolean could not express:
>>> len(create_audio_dataset(sources=data_dir, num_epochs=3)) 6
Two datasets that visit files in the same order but load different random excerpts (same
shuffle_seed, differentexcerpt_seed):>>> ds1 = create_audio_dataset(sources=data_dir, shuffle_seed=42, excerpt_seed=100) >>> ds2 = create_audio_dataset(sources=data_dir, shuffle_seed=42, excerpt_seed=200)
- create_balanced_audio_dataset(sources: Mapping[str, str | Path | List[str | Path]] | None = None, weights: Mapping[str, float] | None = None, datasets: Mapping[str, MapDataset] | None = None, *, shuffle: bool = True, num_epochs: int | None = None, shuffle_seed: int = 0, excerpt_seed: int | None = None, sample_rate: int = 44100, mono: bool = True, duration: float | None = None, pad_mode: Literal['constant', 'edge', 'reflect', 'symmetric', 'wrap'] | None = 'constant', extensions: List[str] | None = None, excerpt: ExcerptConfig = ExcerptConfig(strategy='random', num_tries=8, lufs_cutoff=-40.0, search='uniform', on_failure='keep'), window: WindowConfig | None = None, channels: int | None = None, on_read_error: Literal['raise', 'skip', 'warn'] = 'raise') MapDataset¶
Create a balanced MapDataset from multiple audio groups and/or pre-constructed datasets.
This function creates a grain MapDataset that samples from multiple sources with specified weights. Sources can be either audio file directories or pre-constructed grain MapDatasets. It uses grain’s random_map for excerpt loading, ensuring infinite variety in RNG seeds even when files are repeated.
- Parameters:
sources – Optional dictionary mapping group names to directories (or globs, or lists of them, as
strorPath) of audio files. At least one of sources or datasets must be non-empty.weights – Optional dictionary mapping group names to sampling weights. Weights are normalized to sum to 1.0. Groups not in the dict default to weight 1.0. If None, all groups are weighted equally. Every key must name a group in sources or datasets; an unknown key raises rather than silently leaving its intended group at 1.0. Every weight must be a finite number greater than zero – to disable a group, omit it from sources/datasets instead of weighting it 0.
datasets – Optional dictionary mapping group names to pre-constructed grain MapDatasets. These datasets will be mixed with file-based sources. Useful for combining different data sources or including pre-processed datasets. Each item of a pre-built dataset is stamped with
source=its group name (overwriting anysourceit already carried); a missingfilepathis filled with empty strings and a missingoffsetwithNaN, so every item exposes the same provenance schema as the file-based groups and the two collate together underAudioTree.batch(). IMPORTANT: Pre-constructed datasets MUST already be repeated (call .repeat() before passing them) to ensure infinite sampling. If a finite dataset is passed, grain.MapDataset.mix will truncate the mixed output to the shortest dataset length.shuffle – Whether to shuffle files within each file-based group. Set to False for deterministic iteration (e.g., pre-rendering). Does not affect pre-constructed datasets.
num_epochs – How many passes each file-based group makes before it runs dry.
None(the default) repeats every group forever, which is what balanced mixing normally wants:grain.MapDataset.mixtruncates its output to the shortest input, so any finite group caps the whole mixture. An integern >= 1gives each groupnpasses and therefore a finite mixture bounded by the smallest of them;0or a negative count raises. Note the default differs fromcreate_audio_dataset()’s single pass – there one pass over the corpus is exactly one epoch, whereas here a finite group silently truncates every other group.shuffle_seed – Random seed for shuffling file order. Each group’s own seed is derived from this and the group’s name, so adding or reordering groups leaves the other groups’ streams untouched.
excerpt_seed – Random seed for excerpt selection (random_map). If None, defaults to shuffle_seed. Derived per group the same way, and kept independent of the shuffle stream even when the two base seeds are equal.
sample_rate – Target sample rate for audio files (only applies to file-based sources).
mono – Whether to convert audio to mono (only applies to file-based sources, 0 or 1).
duration – Duration in seconds to load from each file (only applies to file-based sources). Defaults to 1.0. Mutually exclusive with
window, which carries its ownduration.pad_mode – Padding mode for files shorter than duration (only applies to file-based sources). Options: “constant” (zeros), “edge” (repeat edge), “reflect” (mirror), “symmetric” (mirror with edge), “wrap” (circular), or None (no padding).
extensions – List of audio file extensions to search for (only applies to file-based sources).
excerpt – Which part of each file to take; see
ExcerptConfig. Defaults to a uniformly random offset. Only applies to file-based sources.window – Optional
WindowConfig. When given, each file-based group is built withcreate_windowed_audio_dataset()(length-aware, evenly-covering window sampling) instead of one excerpt per file, using the group’sduration/alpha/etc. from the params and the sharedsample_rate/mono/pad_modehere. The groupweightsstill balance across groups, composing multiplicatively with the within-group length weighting. Mutually exclusive with a customizedexcerptand withduration.channels – Expected channel count of every file (only applies to file-based sources built without
window); seecreate_audio_dataset(). When None (andmono=False), one file is probed and the count is applied to every group, so two internally-consistent groups that disagree with each other fail at load time with a filename instead of at batch time with a shape error.on_read_error – What to do when one file cannot be read; see
create_audio_dataset(). Applies to every file-based group (and, likechannels, is not supported alongsidewindow). Pre-constructeddatasetskeep whatever policy they were built with – mixing a"raise"dataset with a"skip"one produces items with different extras keys, whichAudioTree.batch()cannot collate.
- Returns:
A grain.MapDataset that interleaves items from source groups according to the specified weights – infinite unless
num_epochsis an integer or a finite dataset was passed indatasets.
Example
Set up two small groups of
.wavfiles in temporary directories:>>> import os, tempfile >>> import numpy as np >>> import soundfile >>> speech_dir, music_dir = tempfile.mkdtemp(), tempfile.mkdtemp() >>> for d in (speech_dir, music_dir): ... for i in range(2): ... soundfile.write( ... os.path.join(d, f"{i}.wav"), ... np.zeros((44100, 1), dtype=np.float32), ... 44100, ... )
Equal weighting (the default). The returned dataset is infinite, so index it directly rather than calling
len:>>> ds = create_balanced_audio_dataset( ... sources={"speech": [speech_dir], "music": [music_dir]}, ... sample_rate=44100, ... duration=1.0, ... ) >>> ds[0].waveform.shape (1, 1, 44100)
Custom weights (70% speech, 30% music):
>>> ds = create_balanced_audio_dataset( ... sources={"speech": [speech_dir], "music": [music_dir]}, ... weights={"speech": 0.7, "music": 0.3}, ... sample_rate=44100, ... duration=1.0, ... )
For pre-rendering (deterministic, no shuffle):
>>> ds = create_balanced_audio_dataset( ... sources={"speech": [speech_dir], "music": [music_dir]}, ... weights={"speech": 0.5, "music": 0.5}, ... shuffle=False, ... shuffle_seed=42, ... sample_rate=44100, ... duration=1.0, ... )
Mix file sources with a pre-constructed (already repeated) dataset:
>>> preprocessed_ds = create_audio_dataset(sources=music_dir, num_epochs=None) >>> ds = create_balanced_audio_dataset( ... sources={"speech": [speech_dir]}, ... datasets={"preprocessed": preprocessed_ds}, ... weights={"speech": 0.7, "preprocessed": 0.3}, ... )
- create_windowed_audio_dataset(sources: List[str] | str | None = None, filepaths: List[str] | None = None, *, duration: float = 1.0, hop: float | None = None, alpha: float = 1.0, jitter: bool = True, durations: Mapping[str, float] | None = None, lufs_cache: str | Path | None = None, lufs_per_file: Mapping[str, ndarray] | None = None, lufs_window_sec: float | None = None, lufs_cutoff: float = -40.0, shuffle: bool = True, num_epochs: int | None = 1, shuffle_seed: int = 0, excerpt_seed: int | None = None, sample_rate: int = 44100, mono: bool = True, pad_mode: Literal['constant', 'edge', 'reflect', 'symmetric', 'wrap'] | None = 'constant', extensions: List[str] | None = None, source: str | None = None) MapDataset¶
Create a length-aware, evenly-covering MapDataset of audio windows.
Unlike
create_audio_dataset()(one random excerpt per file per epoch), this tiles every file intom_islots withm_iproportional tolength ** alpha, flattens all slots into one globally shuffled index, and draws a jittered excerpt from each. The result samples long files more often than short ones (tunable viaalpha), covers each file evenly, and keeps batches diverse because grain scatters any one file’s slots across the epoch.- Parameters:
sources – A directory path, file path, or glob pattern (e.g.
"/data/*/mixture.wav"), or a list of them. Seefind_audio_files()for how each entry is resolved. Mutually exclusive withfilepaths– provide exactly one.filepaths – An explicit list of audio file paths. Mutually exclusive with
sources.duration – Length in seconds of each excerpt.
hop – Stride in seconds between natural windows at
alpha == 1. Defaults toduration(non-overlapping).alpha – Length power for slots-per-file (
0= uniform per file,1= proportional to length). See the module docstring.jitter – If True, randomize each draw’s offset within its slot’s stride so coverage spans the whole file and excerpts never repeat across epochs.
durations – Optional precomputed
{filepath: seconds}cache (seescan_durations()). If None, durations are scanned from headers (or taken fromlufs_cacheif it stored them).lufs_cache – Optional path to an on-disk cache written by
build_window_lufs_cache(). When given, its per-file LUFS arrays, analysis window, and durations are loaded and used for build-time saliency filtering (overridable by the explicitlufs_per_file/lufs_window_sec/durationsargs).lufs_per_file – Optional precomputed per-file windowed-LUFS arrays (see
precompute_window_lufs()). If given, slots whose center is belowlufs_cutoffare dropped at build time. If None and nolufs_cache(the default), no loudness filtering is done – assume curated data.lufs_window_sec – Analysis window of
lufs_per_filein seconds. Required whenlufs_per_fileis given without alufs_cache.lufs_cutoff – Minimum per-window LUFS to keep a slot.
shuffle – Whether to globally shuffle slots (required for batch diversity).
num_epochs – How many passes over the slot index the dataset yields.
Nonerepeats forever (training); an integern >= 1yields exactlynpasses;0or a negative count raises. Defaults to a single finite pass, which covers every slot exactly once.shuffle_seed – Seed for the global slot shuffle. Derived, not used verbatim; see
excerpt_seed.excerpt_seed – Seed for jitter. Defaults to
shuffle_seed. The shuffle and jitter streams come from two different draws of onenumpy.random.SeedSequence, so slot order and jitter offsets stay independent even when a single seed feeds both.sample_rate – Target sample rate for loaded audio.
mono – Whether to convert audio to mono.
pad_mode – Padding mode for files shorter than
duration(numpy.pad modes), or None to not pad.extensions – Audio extensions to search when using
sources.source – Optional source group name stored as provenance.
- Returns:
A grain.MapDataset over audio windows.
- find_audio_files(sources: str | Path | List[str | Path], extensions: List[str] | None = None) List[str]¶
Find audio files under one or more directories or glob patterns.
Each entry in
sourcesmay be a directory, an individual file, or a glob pattern (any entry containing*,?, or[...]). A directory is searched recursively; a glob is expanded, with each match then treated as a directory (searched recursively) or a file.**is supported for recursive glob matching, e.g."/data/**/mixture.wav".Hidden files and directories (names starting with
., such as.git) are skipped when recursing into directories; glob patterns follow the usual shell rule that*does not match a leading.. In every case a file is only kept if its extension is inextensions. The returned paths are sorted and de-duplicated, so the order is deterministic across machines and filesystems — important for reproducible shuffling.A source that matches nothing (a typo, an unmounted drive, an extension that is not in
extensions) shrinks the corpus without failing, so each such source raises aUserWarningnaming it.- Parameters:
sources – A path or glob pattern, or a list of them. Each may be a
Pathorstrnaming a directory (searched recursively) or a file, or a glob pattern such as"/mnt/d/musdb18hq/train/*/mixture.wav".extensions – File extensions to match (e.g.
[".wav", ".flac"]). Defaults to[".wav", ".flac"].
- Returns:
A sorted, de-duplicated list of matching file paths.
- load_window_lufs(cache_dir: str | Path) WindowLufsCache¶
Load a windowed-loudness cache written by
save_window_lufs().- Parameters:
cache_dir – Directory containing
lufs.bagzandmanifest.json.- Returns:
A
WindowLufsCachewith the per-file LUFS arrays, optional durations, and the analysis window length.- Raises:
ValueError – If the manifest is missing required keys or malformed – checked before the bagz file is opened, so a truncated or hand-edited manifest names itself instead of dying on a raw
KeyError.
- precompute_window_lufs(filepaths: List[str], lufs_window_sec: float, *, sample_rate: int | None = 44100, mono: bool = True) dict[str, ndarray]¶
Compute a per-file windowed-LUFS array for build-time saliency filtering.
Each value is the integrated loudness (LUFS, ITU-R BS.1770) of one non-overlapping
lufs_window_secwindow, measured on the CPU with the upstreamloudnesslibrary (loudness.integrated_loudness, the same kernelAudioTree.replace_lufs()uses for NumPy waveforms). This is a one-time offline pass that runs entirely on the CPU – it performs no JAX/GPU computation – so it is safe to run before forking grain workers and keeps the data-source layer free of GPU work. Files are processed serially in a single pass; there is no cross-file parallelism.The arrays are ragged (length scales with file duration); files shorter than one window get an empty array, which downstream filtering treats as “keep”. The result is suitable for passing as
lufs_per_file=tocreate_windowed_audio_dataset(); usebuild_window_lufs_cache()to compute and persist it to disk (bagz) in one pass.The
sample_rateandmonodefaults match those ofcreate_windowed_audio_dataset(), so by default the loudness reflects exactly the audio the model trains on; pass matching values if you change the dataset’s. Files are normalized per these (resample tosample_rate, average to mono);sample_rate=Nonekeeps each file’s native rate. Windows are measured independently, so files need not share a shape.TODO: very long files are read fully into RAM before windowing; segment-read them if hour-plus files strain memory.
- Parameters:
filepaths – Audio file paths to analyze.
lufs_window_sec – Analysis window length in seconds (independent of the training
duration). Should be at least 0.4s for a valid LUFS measurement.sample_rate – Resample every file to this rate before analysis, or None to keep each file’s native rate. Defaults to the dataset’s
sample_rate.mono – If True (the dataset default), average channels to mono first.
- Returns:
A mapping from filepath to a 1-D
float32array of per-window LUFS.
- save_window_lufs(out_dir: str | Path, lufs_per_file: Mapping[str, ndarray], *, lufs_window_sec: float, durations: Mapping[str, float] | None = None, sample_rate: int | None = None, mono: bool = True) Path¶
Persist a windowed-loudness cache to
out_diras bagz + JSON manifest.The ragged per-file LUFS arrays are stored as one
float32record each in a singlelufs.bagzfile (no padding), in the order oflufs_per_file. Amanifest.jsonrecords the filepaths (parallel to the bagz records), the analysis window, optional durations, thesample_rate/monothe loudness was measured at (so the dataset can verify the cache matches the audio it loads), and each file’s byte size, so a file re-rendered in place after the build is refused at dataset construction rather than silently keeping stale durations and loudness. A rewrite that keeps the byte size identical is not detectable this way (seeWindowLufsCache).- Parameters:
out_dir – Directory to write the cache into (created if missing).
lufs_per_file – Mapping from filepath to its per-window LUFS array.
lufs_window_sec – Analysis window length the arrays were computed with.
durations – Optional mapping from filepath to duration in seconds; stored so the cache can also supply
durations=to the dataset.sample_rate – The sample rate the loudness was measured at (
Noneif native). Stored for the dataset’s consistency check.mono – Whether channels were averaged to mono before measuring.
- Returns:
The cache directory as a
Path.
- scan_durations(filepaths: List[str]) dict[str, float]¶
Read each file’s duration in seconds from its header (no decode).
soundfile.inforeads only the container header, so this is cheap enough to run over tens of thousands of files. Persist the result (e.g. JSON/NPZ) and pass it back asdurations=to skip the scan on subsequent runs; the slot index is a pure function of these durations, soalpha/hop/durationcan be retuned without re-reading any headers.- Parameters:
filepaths – Audio file paths to inspect.
- Returns:
A mapping from filepath to duration in seconds.