Audio files¶
kudio.core.io
¶
Audio file I/O: path resolution, loading and saving of wave files.
Classes:
| Name | Description |
|---|---|
AudioInfo |
What a file is, before you decide whether to load it. |
ConvertResult |
What |
LoadAudio |
Iterate over the |
Functions:
| Name | Description |
|---|---|
check_path |
Return |
check_file |
Normalize an output wave path: force the |
check_input |
Recursively collect |
file_load |
Load a wave file; returns |
audio_info |
Describe an audio file (or an in-memory waveform) without interpreting it. |
load_wave |
Load one wave file or a list of them into |
load_waves |
Convert every |
save_wave |
Write wave to an audio file via soundfile. |
copy_waves |
Copy wave files into directory path and return where they went. |
convert_folder |
Resample / re-encode / trim / normalise every |
AudioInfo
dataclass
¶
AudioInfo(
sr: int,
channels: int,
frames: int,
duration: float,
peak: Optional[float],
path: Optional[Path] = None,
subtype: Optional[str] = None,
format: Optional[str] = None,
)
What a file is, before you decide whether to load it.
duration is in seconds and peak is the largest absolute sample:
nan when some samples are not finite, None when it was not
measured (peak=False).
subtype / format are soundfile's ('PCM_16', 'WAV') and are
None when the info was taken from an array rather than a file.
ConvertResult
dataclass
¶
What convert_folder did. failed is (path, reason) pairs.
LoadAudio
¶
Iterate over the .wav files found (recursively) in a directory,
collected the way check_input collects them.
Source code in kudio/core/io.py
check_path
¶
Return path if it is free (or exist_ok), otherwise an incremented
variant, e.g. runs/exp -> runs/exp2, runs/exp3 ...
Source code in kudio/core/io.py
check_file
¶
Normalize an output wave path: force the .wav suffix, create parent
directories, and (optionally) rename to avoid overwriting an existing file.
A folder becomes <folder>/unknown.wav. A path ending in a separator is
taken as a folder even before it exists: Path drops the trailing
slash, so "newdir/" would otherwise come back as newdir.wav.
Source code in kudio/core/io.py
check_input
¶
Recursively collect .wav files from input.
input may be a file path, a directory, a .txt file containing one
path per line, or a (nested) list/tuple of any of those.
Returns (right_list, wrong_list) where right_list holds resolved
.wav paths and wrong_list everything that could not be resolved.
The suffix test ignores case, so a recorder's ZOOM0001.WAV counts
whether it is named directly, listed, or found in a folder -- and a folder
collects the same files on Windows as on Linux, where a plain
rglob("*.wav") would not. A .txt list is read as UTF-8 (a BOM is
fine), and relative paths in it resolve against the working directory.
Source code in kudio/core/io.py
file_load
¶
Load a wave file; returns (waveform float32, sample_rate).
sr=None keeps the file's native sample rate and reads through
soundfile alone. A requested sr resamples through librosa.
Multi-channel audio (mono=False) comes back channels last, shaped
(frames, channels) -- the layout soundfile uses and the one
kudio.loudness expects. A mono file stays 1-D with mono=False;
it does not become (frames, 1).
Raises:
| Type | Description |
|---|---|
ValueError
|
for an sr that is not a positive rate. That is a mistake in the call, so it is not dressed up as a bad file. |
AudioIOError
|
when the file cannot be read. |
Source code in kudio/core/io.py
resample
¶
Resample a waveform already in memory.
The in-memory counterpart of file_load(..., sr=target_sr), which can
only resample on the way in from disk. Returns y untouched when the rates
already match, so it is safe to call unconditionally.
A (frames, channels) array is resampled along its frames, the layout
file_load returns. Integer input comes back in its own dtype,
rounded and clipped to its range rather than truncated.
Source code in kudio/core/io.py
audio_info
¶
audio_info(
source: Union[PathLike, ndarray],
sr: Optional[int] = None,
peak: bool = True,
) -> AudioInfo
Describe an audio file (or an in-memory waveform) without interpreting it.
The header alone answers rate, channels, frames and duration, so
peak=False never touches the samples and stays instant on a large file.
The default reads them, because every caller so far wanted the peak too.
An array needs its sr passed in — a waveform does not carry one — and is
read channels last, matching file_load.
Source code in kudio/core/io.py
load_wave
¶
load_wave(
wave: Any, num: Optional[int] = None
) -> Union[Tuple[ndarray, int], List[Tuple[ndarray, int]]]
Load one wave file or a list of them into (waveform, sr) tuples.
Source code in kudio/core/io.py
load_waves
¶
load_waves(
wave: Any,
use_pool: bool = False,
std_len: bool = False,
core_: int = 8,
) -> Union[
List[Tuple[ndarray, int]],
Tuple[List[ndarray], int, int],
]
Convert every .wav in wave (see check_input) to waveform data.
Returns a list of (np.ndarray, int). With std_len=True returns
(waves_2d, sr, min_len) where every waveform is truncated to the
shortest length (all files must share one sample rate).
Source code in kudio/core/io.py
save_wave
¶
save_wave(
path: PathLike,
wave: ndarray,
sr: int,
d_sample: Optional[int] = None,
subtype: str = "PCM_16",
) -> None
Write wave to an audio file via soundfile.
The container follows the extension, the way soundfile picks it: a
.wav path writes WAV, .flac writes FLAC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
subtype
|
str
|
soundfile subtype — |
'PCM_16'
|
d_sample
|
Optional[int]
|
optional resample rate before writing. Integer input is scaled by its own type's full scale, the way soundfile
reads such a file back: int16 by A fixed-point subtype clips anything beyond ±1.0 to full scale, and every
|
None
|
Raises:
| Type | Description |
|---|---|
AudioIOError
|
if any sample is NaN or inf, before anything is
written or any folder created. Neither subtype family survives one:
|
Source code in kudio/core/io.py
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | |
copy_waves
¶
Copy wave files into directory path and return where they went.
Note the order: the destination comes first. wave_ is anything
check_input accepts -- a file, a folder, a .txt list, or a list
of those. Files land flat in path; a name already taken there gets a free
one (check_file), so two talkers' sx133.wav both arrive.
Source code in kudio/core/io.py
convert_folder
¶
convert_folder(
src: Any,
dst: PathLike,
*,
sr: Optional[int] = None,
mono: bool = True,
subtype: str = "PCM_16",
trim_db: Optional[float] = None,
peak: Optional[float] = None,
lufs: Optional[float] = None,
overwrite: bool = False,
progress: Optional[
Callable[[int, int, Path], None]
] = None,
on_error: str = "collect",
root: Optional[PathLike] = None,
) -> ConvertResult
Resample / re-encode / trim / normalise every .wav file under src.
src is anything check_input accepts — a folder, a file, a .txt
manifest, or a list of those. The output mirrors the input's directory
structure below dst, so two files with the same name in different
subfolders do not collide. A folder is mirrored from itself; a list or a
manifest from the deepest folder its files share, or from root.
>>> kudio.convert_folder("raw/", "16k/", sr=16000, lufs=-23.0)
ConvertResult(written=412, total=412, ...)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trim_db
|
Optional[float]
|
|
None
|
peak
|
Optional[float]
|
peak-normalise target (e.g. |
None
|
lufs
|
Optional[float]
|
loudness-normalise target in LUFS (e.g. |
None
|
overwrite
|
bool
|
by default an existing output is renamed rather than
replaced ( |
False
|
progress
|
Optional[Callable[[int, int, Path], None]]
|
optional |
None
|
on_error
|
str
|
|
'collect'
|
root
|
Optional[PathLike]
|
the folder the output layout is measured from. Every input has to be inside it. |
None
|
Source code in kudio/core/io.py
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | |
kudio.core.manager
¶
In-memory registry of loaded/recorded audio clips used by the GUI.
Classes:
| Name | Description |
|---|---|
AudioDataManager |
Keyed store of audio clips: |
AudioDataManager
¶
Keyed store of audio clips: {name: {dir, wave, sr, ch}}.
wave is a list with one waveform per channel.
Methods:
| Name | Description |
|---|---|
add_local_file |
Load dir into the manager as a mono downmix ( |
Source code in kudio/core/manager.py
add_local_file
¶
Load dir into the manager as a mono downmix (ch 1), whatever
set_params says, so save_all writes it back as mono.
Any format soundfile reads is fine.