### Initialize an audio batch Source: https://descriptinc.github.io/audiotools/tutorials/transforms.html Example of loading an audio file and creating a batch of signals. ```python from pathlib import Path audio_path = "../../tests/audio/spk/f10_script4_produced.wav" signal = AudioSignal(audio_path, offset=6, duration=5) batch_size = 10 # Make it into a batch signal = AudioSignal.batch([signal.clone() for _ in range(batch_size)]) ``` -------------------------------- ### Initialize Choose transform Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Example of initializing the Choose transform with specific sub-transforms. ```python >>> transforms.Choose(tfm.LowPass(), tfm.HighPass()) ``` -------------------------------- ### Complete Audio Processing Pipeline Example Source: https://descriptinc.github.io/audiotools/_sources/tutorials/transforms.md.txt This example demonstrates a full transform pipeline simulating a room environment, including preprocessing, core processing (room impulse response, background noise, clipping, quantization, low-pass filtering), and postprocessing. It shows how to batch signals, instantiate transforms with data, apply transforms sequentially, and apply transforms conditionally using `filter`. ```python from pathlib import Path audio_path = "../../tests/audio/spk/f10_script4_produced.wav" signal = AudioSignal(audio_path, offset=6, duration=5) batch_size = 10 # Make it into a batch signal = AudioSignal.batch([signal.clone() for _ in range(batch_size)]) # Create each group of transforms preprocess = tfm.VolumeChange(name="pre") process = tfm.Compose( [ tfm.RoomImpulseResponse(sources=["../../tests/audio/ir"]), tfm.BackgroundNoise(sources=["../../tests/audio/nz"]), tfm.ClippingDistortion(), tfm.MuLawQuantization(), tfm.LowPass(prob=0.5), ], name="process", prob=0.9, ) postprocess = tfm.RescaleAudio(name="post") # Create transform transform = tfm.Compose([ preprocess, process, postprocess, ]) # Instantiate transform (passing in signal because # some transforms require data). states = range(batch_size) kwargs = transform.batch_instantiate(states, signal) # Apply pre, process, and post to signal in sequence. output = transform(signal.clone(), **kwargs) # Apply only pre and post to signal in sequence, skipping process. with transform.filter("pre", "post"): target = transform(signal.clone(), **kwargs) audio_dict = make_dict(target, output, kwargs) post.disp(audio_dict, first_column="batch_idx") ``` -------------------------------- ### Example: Loading Slakh Data Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Example code demonstrating how to load and process data from the Slakh dataset using audiotools. ```APIDOC ```python import audiotools as at from pathlib import Path from audiotools import transforms as tfm import numpy as np import torch import glob def build_dataset( sample_rate: int = 16000, duration: float = 10.0, slakh_path: str = "~/.data/slakh/", ): slakh_path = Path(slakh_path).expanduser() # Find the max number of sources in Slakh src_names = [x.name for x in list(slakh_path.glob("**/*.wav")) if "S" in str(x.name)] n_sources = len(list(set(src_names))) loaders = { f"S{i:02d}": at.datasets.AudioLoader( sources=[slakh_path], transform=tfm.Compose( tfm.VolumeNorm(("uniform", -20, -10)), tfm.Silence(prob=0.1), ), ext=[f"S{i:02d}.wav"], ) for i in range(n_sources) } dataset = at.datasets.AudioDataset( loaders=loaders, sample_rate=sample_rate, duration=duration, num_channels=1, aligned=True, transform=tfm.RescaleAudio(), shuffle_loaders=False, ) return dataset, list(loaders.keys()) train_data, sources = build_dataset() dataloader = torch.utils.data.DataLoader( train_data, batch_size=16, num_workers=0, collate_fn=train_data.collate, ) batch = next(iter(dataloader)) for k in sources: src = batch[k] src["transformed"] = train_data.loaders[k].transform( src["signal"].clone(), **src["transform_args"] ) mixture = sum(batch[k]["transformed"] for k in sources) mixture = train_data.transform(mixture, **batch["transform_args"]) # Say a model takes the mix and gives back (n_batch, n_src, n_time). # Construct the targets: targets = at.AudioSignal.batch([batch[k]["transformed"] for k in sources], dim=1) ``` ``` -------------------------------- ### Setup Dummy Data and Configuration Source: https://descriptinc.github.io/audiotools/_sources/tutorials/listening_tests.md.txt Initializes the environment, defines a configuration dataclass, and generates synthetic sine wave audio files in a structured directory. ```python import math import string import tempfile from dataclasses import dataclass from pathlib import Path import gradio as gr import numpy as np import soundfile as sf import rich from audiotools import preference as pr @dataclass class Config: folder: str = None save_path: str = "results.csv" conditions: list = None reference: str = None seed: int = 0 def random_sine(f): fs = 44100 # sampling rate, Hz, must be integer duration = 5.0 # in seconds, may be float # generate samples, note conversion to float32 array volume = 0.1 num_samples = int(fs * duration) samples = volume * np.sin(2 * math.pi * (f / fs) * np.arange(num_samples)) return samples, fs def create_data(path): path = Path(path) hz = [110, 140, 180] for i in range(6): name = f"condition_{string.ascii_lowercase[i]}" for j in range(3): sample_path = path / name / f"sample_{j}.wav" sample_path.parent.mkdir(exist_ok=True, parents=True) audio, sr = random_sine(hz[j] * (2**i)) sf.write(sample_path, audio, sr) config = Config( folder="/tmp/pref/audio/", save_path="/tmp/pref/results.csv", conditions=["condition_a", "condition_b"], reference="condition_c", ) create_data(config.folder) ``` -------------------------------- ### Load Slakh Dataset Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Example of building a dataset from Slakh audio files, configuring loaders with specific transforms, and setting up a PyTorch DataLoader. ```python import audiotools as at from pathlib import Path from audiotools import transforms as tfm import numpy as np import torch import glob def build_dataset( sample_rate: int = 16000, duration: float = 10.0, slakh_path: str = "~/.data/slakh/", ): slakh_path = Path(slakh_path).expanduser() # Find the max number of sources in Slakh src_names = [x.name for x in list(slakh_path.glob("**/*.wav")) if "S" in str(x.name)] n_sources = len(list(set(src_names))) loaders = { f"S{i:02d}": at.datasets.AudioLoader( sources=[slakh_path], transform=tfm.Compose( tfm.VolumeNorm(("uniform", -20, -10)), tfm.Silence(prob=0.1), ), ext=[f"S{i:02d}.wav"], ) for i in range(n_sources) } dataset = at.datasets.AudioDataset( loaders=loaders, sample_rate=sample_rate, duration=duration, num_channels=1, aligned=True, transform=tfm.RescaleAudio(), shuffle_loaders=False, ) return dataset, list(loaders.keys()) train_data, sources = build_dataset() dataloader = torch.utils.data.DataLoader( train_data, batch_size=16, num_workers=0, collate_fn=train_data.collate, ) batch = next(iter(dataloader)) for k in sources: src = batch[k] src["transformed"] = train_data.loaders[k].transform( src["signal"].clone(), **src["transform_args"] ) mixture = sum(batch[k]["transformed"] for k in sources) mixture = train_data.transform(mixture, **batch["transform_args"]) ``` -------------------------------- ### Setup AudioTools Environment Source: https://descriptinc.github.io/audiotools/tutorials/transforms.html Sets up the AudioTools environment by configuring default settings and environment variables. This code should be run once at the beginning of your script. ```python import audiotools from audiotools import AudioSignal from audiotools import post, util, metrics from audiotools.data import preprocess from flatten_dict import flatten import torch import pprint from collections import defaultdict from audiotools import transforms as tfm import os audiotools.core.playback.DEFAULT_EXTENSION = ".mp3" util.DEFAULT_FIG_SIZE = (9, 3) os.environ["PATH_TO_DATA"] = os.path.abspath("../..") pp = pprint.PrettyPrinter() def make_dict(signal_batch, output_batch, kwargs=None): audio_dict = {} kwargs_ = {} if kwargs is not None: kwargs = flatten(kwargs) for k, v in kwargs.items(): if isinstance(v, torch.Tensor): key = ".".join(list(k[-2:])) kwargs_[key] = v for i in range(signal_batch.batch_size): audio_dict[i] = { "input": signal_batch[i], "output": output_batch[i] } for k, v in kwargs_.items(): try: audio_dict[i][k] = v[i].item() except: audio_dict[i][k] = v[i].float().mean() return audio_dict ``` -------------------------------- ### ABX Preference Test Setup Source: https://descriptinc.github.io/audiotools/tutorials/listening_tests.html Sets up a Gradio interface for an ABX preference test. It initializes the player, tracker, and UI elements like sliders and buttons, and defines the logic for processing user responses. ```python import math import string import tempfile from dataclasses import dataclass from pathlib import Path import gradio as gr import numpy as np import soundfile as sf import rich from audiotools import preference as pr @dataclass class Config: folder: str = None save_path: str = "results.csv" conditions: list = None reference: str = None seed: int = 0 def random_sine(f): fs = 44100 # sampling rate, Hz, must be integer duration = 5.0 # in seconds, may be float # generate samples, note conversion to float32 array volume = 0.1 num_samples = int(fs * duration) samples = volume * np.sin(2 * math.pi * (f / fs) * np.arange(num_samples)) return samples, fs def create_data(path): path = Path(path) hz = [110, 140, 180] for i in range(6): name = f"condition_{string.ascii_lowercase[i]}" for j in range(3): sample_path = path / name / f"sample_{j}.wav" sample_path.parent.mkdir(exist_ok=True, parents=True) audio, sr = random_sine(hz[j] * (2**i)) sf.write(sample_path, audio, sr) config = Config( folder="/tmp/pref/audio/", save_path="/tmp/pref/results.csv", conditions=["condition_a", "condition_b"], reference="condition_c", ) create_data(config.folder) with gr.Blocks() as app: save_path = config.save_path samples = gr.State(pr.Samples(config.folder)) reference = config.reference conditions = config.conditions assert len(conditions) == 2, "Preference tests take only two conditions!" player = pr.Player(app) player.create() if reference is not None: player.add("Play Reference") user = pr.create_tracker(app) with gr.Row().style(equal_height=True): for i in range(len(conditions)): x = string.ascii_uppercase[i] player.add(f"Play {x}") rating = gr.Slider(value=50, interactive=True) gr.HTML(pr.slider_abx) def build(user, samples, rating): samples.filter_completed(user, save_path) # Write results to CSV if samples.current > 0: start_idx = 1 if reference is not None else 0 name = samples.names[samples.current - 1] result = {"sample": name, "user": user} result[samples.order[start_idx]] = 100 - rating result[samples.order[start_idx + 1]] = rating pr.save_result(result, save_path) updates, done, pbar = samples.get_next_sample(reference, conditions) return updates + [gr.update(value=50), done, samples, pbar] progress = gr.HTML() begin = gr.Button("Submit", elem_id="start-survey") begin.click( fn=build, inputs=[user, samples, rating], outputs=player.to_list() + [rating, begin, samples, progress], ).then(None, _js=pr.reset_player) # Comment this back in to actually launch the script. # app.launch() ``` -------------------------------- ### Generate and Display Audio Transform Examples Source: https://descriptinc.github.io/audiotools/tutorials/transforms.html This script iterates through all available transforms, applies them to an audio signal with specific parameters, and displays the results along with spectral distances. It requires the `audiotools` library and sample audio files. ```python seed = 0 transforms_to_demo = [] for x in dir(tfm): if hasattr(getattr(tfm, x), "transform"): if x not in ["Compose", "Choose", "Repeat", "RepeatUpTo"]: transforms_to_demo.append(x) audio_path = "../../tests/audio/spk/f10_script4_produced.wav" signal = AudioSignal(audio_path, offset=6, duration=5) signal.metadata["loudness"] = AudioSignal(audio_path).ffmpeg_loudness().item() audio_dict = { "Original": {"audio": signal, "spectral_distance": f"{0.0:1.2f}"} } distance = metrics.spectral.MelSpectrogramLoss() for transform_name in transforms_to_demo: kwargs = {} if transform_name == "BackgroundNoise": kwargs["sources"] = ["../../tests/audio/nz"] if transform_name == "RoomImpulseResponse": kwargs["sources"] = ["../../tests/audio/ir"] if transform_name == "CrossTalk": kwargs["sources"] = ["../../tests/audio/spk"] if "Quantization" in transform_name: kwargs["channels"] = ("choice", [8, 16, 32]) transform_cls = getattr(tfm, transform_name) t = transform_cls(prob=1.0, **kwargs) t_kwargs = t.instantiate(seed, signal) output = t(signal.clone(), **t_kwargs) audio_dict[t.name] = { "audio": output, "spectral_distance": f"{distance(output, signal.clone()).item():1.2f}" } post.disp(audio_dict, first_column="transform") ``` -------------------------------- ### Load MUSDB multitrack data Source: https://descriptinc.github.io/audiotools/_modules/audiotools/data/datasets.html Shows how to configure an AudioDataset for multitrack audio loading using MUSDB as an example. ```python import audiotools as at from pathlib import Path from audiotools import transforms as tfm import numpy as np import torch def build_dataset( sample_rate: int = 44100, duration: float = 5.0, musdb_path: str = "~/.data/musdb/", ): musdb_path = Path(musdb_path).expanduser() loaders = { src: at.datasets.AudioLoader( sources=[musdb_path], transform=tfm.Compose( tfm.VolumeNorm(("uniform", -20, -10)), tfm.Silence(prob=0.1), ), ext=[f"{src}.wav"], ) for src in ["vocals", "bass", "drums", "other"] } dataset = at.datasets.AudioDataset( loaders=loaders, sample_rate=sample_rate, duration=duration, num_channels=1, aligned=True, transform=tfm.RescaleAudio(), shuffle_loaders=True, ) return dataset, list(loaders.keys()) train_data, sources = build_dataset() dataloader = torch.utils.data.DataLoader( train_data, batch_size=16, num_workers=0, collate_fn=train_data.collate, ) batch = next(iter(dataloader)) for k in sources: src = batch[k] src["transformed"] = train_data.loaders[k].transform( src["signal"].clone(), **src["transform_args"] ) ``` -------------------------------- ### Get FFprobe Start Time Offset Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/ffmpeg.html Retrieves the start time offset for the first audio stream in a given file using FFprobe. Returns the offset in seconds as a float. Defaults to 0.0 if no start time is found. ```python import json import shlex import subprocess import tempfile from pathlib import Path import ffmpy import numpy as np import torch [docs]def ffprobe_offset(path): ff = ffmpy.FFprobe( inputs={path: None}, global_options="-show_entries format=start_time:stream=duration,start_time,codec_type,start_pts,time_base -of json -v quiet", ) streams = json.loads(ff.run(stdout=subprocess.PIPE)[0])["streams"] seconds_offset = 0.0 # Get the offset of the first audio stream we find # and return its start time, if it has one. for stream in streams: if stream["codec_type"] == "audio": seconds_offset = stream.get("start_time", 0.0) break return float(seconds_offset) ``` -------------------------------- ### Initialize AudioSignal Objects Source: https://descriptinc.github.io/audiotools/_sources/readme.md.txt Sets up the environment and loads audio files for processing. ```python import torch import audiotools from audiotools import AudioSignal from audiotools import post import rich import matplotlib.pyplot as plt import markdown2 as md from IPython.display import HTML audiotools.core.playback.DEFAULT_EXTENSION = ".mp3" state = audiotools.util.random_state(0) spk = AudioSignal("../tests/audio/spk/f10_script4_produced.wav", offset=5, duration=5) ir = AudioSignal("../tests/audio/ir/h179_Bar_1txts.wav") nz = AudioSignal("../tests/audio/nz/f5_script2_ipad_balcony1_room_tone.wav") ``` -------------------------------- ### ResumableSequentialSampler Class Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html A SequentialSampler that can be resumed from a specified start index. ```APIDOC ## class audiotools.data.datasets.ResumableSequentialSampler ### Description Sequential sampler that can be resumed from a given start index. ### Parameters * **dataset** (_Sized_) – The dataset to sample from. * **start_idx** (_Optional_[_int_], optional) – The index to start sampling from, by default None. ``` -------------------------------- ### Get random state Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/util.html Converts a seed or existing state into a numpy.random.RandomState instance. ```python def random_state(seed: typing.Union[int, np.random.RandomState]): """ Turn seed into a np.random.RandomState instance. Parameters ---------- seed : typing.Union[int, np.random.RandomState] or None If seed is None, return the RandomState singleton used by np.random. If seed is an int, return a new RandomState instance seeded with seed. If seed is already a RandomState instance, return it. Otherwise raise ValueError. Returns ------- np.random.RandomState Random state object. Raises ------ ValueError If seed is not valid, an error is thrown. """ if seed is None or seed is np.random: return np.random.mtrand._rand elif isinstance(seed, (numbers.Integral, np.integer, int)): return np.random.RandomState(seed) elif isinstance(seed, np.random.RandomState): return seed else: raise ValueError( "%r cannot be used to seed a numpy.random.RandomState" " instance" % seed ) ``` -------------------------------- ### Transform Instantiation and Application Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Demonstrates how to instantiate parameters for a transform and then apply the transform to an AudioSignal. ```APIDOC ## POST /api/transforms/instantiate ### Description Instantiates parameters for the transform. ### Method POST ### Endpoint /api/transforms/instantiate ### Parameters #### Request Body - **state** (Optional[RandomState]) - Optional - Description - **signal** (Optional[AudioSignal]) - Optional - Description ### Request Example ```json { "state": null, "signal": null } ``` ### Response #### Success Response (200) - **dict** - Dictionary containing instantiated arguments for every keyword argument to `self._transform`. #### Response Example ```json { "example_arg": "example_value" } ``` ## POST /api/transforms/batch_instantiate ### Description Instantiates parameters for a batch of transforms. ### Method POST ### Endpoint /api/transforms/batch_instantiate ### Parameters #### Request Body - **states** (list, optional) - List of states, by default None - **signal** (AudioSignal, optional) - AudioSignal to pass to the `self.instantiate` section if it is needed for this transform, by default None ### Request Example ```json { "states": [0, 1, 2, 3], "signal": { "audio_path": "path/to/audio.wav", "offset": 10, "duration": 2 } } ``` ### Response #### Success Response (200) - **dict** - Collated dictionary of arguments. #### Response Example ```json { "example_arg_batch": "example_value_batch" } ``` ## POST /api/transforms/apply ### Description Apply the transform to the audio signal, with given keyword arguments. ### Method POST ### Endpoint /api/transforms/apply ### Parameters #### Request Body - **signal** (AudioSignal) - Required - Signal that will be modified by the transforms in-place. - **kwargs** (dict) - Required - Keyword arguments to the specific transforms `self._transform` function. ### Request Example ```json { "signal": { "audio_path": "path/to/audio.wav", "offset": 0, "duration": null }, "kwargs": { "seed": 123, "some_other_arg": "value" } } ``` ### Response #### Success Response (200) - **AudioSignal** - Transformed AudioSignal. #### Response Example ```json { "transformed_audio_path": "path/to/transformed_audio.wav" } ``` ``` -------------------------------- ### Initialize and sample from AudioDataset Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Demonstrates creating an AudioDataset from a list of AudioLoaders and processing the resulting items. ```python >>> from audiotools.data.datasets import AudioLoader >>> from audiotools.data.datasets import AudioDataset >>> from audiotools import transforms as tfm >>> import numpy as np >>> >>> loaders = [ >>> AudioLoader( >>> sources=[f"tests/audio/spk"], >>> transform=tfm.Equalizer(), >>> ext=["wav"], >>> ) >>> for i in range(5) >>> ] >>> >>> dataset = AudioDataset( >>> loaders = loaders, >>> sample_rate = 44100, >>> duration = 1.0, >>> transform = tfm.RescaleAudio(), >>> ) >>> >>> item = dataset[np.random.randint(len(dataset))] >>> >>> for i in range(len(loaders)): >>> item[i]["signal"] = loaders[i].transform( >>> item[i]["signal"], **item[i]["transform_args"] >>> ) >>> item[i]["signal"].widget(i) >>> >>> mix = sum([item[i]["signal"] for i in range(len(loaders))]) >>> mix = dataset.transform(mix, **item["transform_args"]) >>> mix.widget("mix") ``` -------------------------------- ### ResumableDistributedSampler Class Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html A DistributedSampler that can be resumed from a specified start index, useful for distributed training. ```APIDOC ## class audiotools.data.datasets.ResumableDistributedSampler ### Description Distributed sampler that can be resumed from a given start index. ### Parameters * **dataset** (_Sized_) – The dataset to sample from. * **start_idx** (_Optional_[_int_], optional) – The index to start sampling from, by default None. ``` -------------------------------- ### Trimming and truncating audio Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/audio_signal.html Modifies the audio_data tensor by removing samples from the start or end. ```python def trim(self, before: int, after: int): """Trims the audio_data tensor before and after. Parameters ---------- before : int How many samples to trim from beginning. after : int How many samples to trim from end. Returns ------- AudioSignal AudioSignal with trimming applied. """ if after == 0: self.audio_data = self.audio_data[..., before:] else: self.audio_data = self.audio_data[..., before:-after] return self ``` ```python def truncate_samples(self, length_in_samples: int): """Truncate signal to specified length. Parameters ---------- length_in_samples : int Truncate to this many samples. Returns ------- AudioSignal AudioSignal with truncation applied. """ self.audio_data = self.audio_data[..., :length_in_samples] return self ``` -------------------------------- ### Instantiate Transforms with Parameters Source: https://descriptinc.github.io/audiotools/_modules/audiotools/data/transforms.html Illustrates how to instantiate transforms, which prepares them for application by generating necessary parameters. This is typically done before applying transforms to a signal. ```python kwargs = transform.instantiate() ``` -------------------------------- ### Initialize STFT Parameters Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/audio_signal.html Demonstrates creating and assigning STFT parameters to an AudioSignal instance. ```python >>> stft_params = STFTParams(128, 32) >>> signal1 = AudioSignal(torch.randn(44100), 44100, stft_params=stft_params) >>> signal2 = AudioSignal(torch.randn(44100), 44100, stft_params=signal1.stft_params) >>> signal1.stft_params = STFTParams() # Defaults ``` -------------------------------- ### ffprobe_offset Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/ffmpeg.html Retrieves the start time offset of the first audio stream in a file using FFprobe. ```APIDOC ## ffprobe_offset ### Description Uses FFprobe to inspect audio file metadata and return the start time offset of the first audio stream found. ### Parameters #### Arguments - **path** (str) - Required - Path to the audio file. ### Response - **float** - The start time offset in seconds. ``` -------------------------------- ### Initialize audiotools.preference module Source: https://descriptinc.github.io/audiotools/_modules/audiotools/preference.html Imports necessary libraries and modules for preference test creation, including gradio for UI and audio utility functions. ```python ############################################################## ### Tools for creating preference tests (MUSHRA, ABX, etc) ### ############################################################## import copy import csv import random from collections import defaultdict from pathlib import Path from typing import List import gradio as gr from audiotools.core.util import find_audio ################################################################ ``` -------------------------------- ### Initialize AudioTools Environment Source: https://descriptinc.github.io/audiotools/_sources/tutorials/transforms.md.txt Sets up the necessary imports, environment variables, and helper functions for processing audio signals. ```python import audiotools from audiotools import AudioSignal from audiotools import post, util, metrics from audiotools.data import preprocess from flatten_dict import flatten import torch import pprint from collections import defaultdict from audiotools import transforms as tfm import os audiotools.core.playback.DEFAULT_EXTENSION = ".mp3" util.DEFAULT_FIG_SIZE = (9, 3) os.environ["PATH_TO_DATA"] = os.path.abspath("../..") pp = pprint.PrettyPrinter() def make_dict(signal_batch, output_batch, kwargs=None): audio_dict = {} kwargs_ = {} if kwargs is not None: kwargs = flatten(kwargs) for k, v in kwargs.items(): if isinstance(v, torch.Tensor): key = ".".join(list(k[-2:])) kwargs_[key] = v for i in range(signal_batch.batch_size): audio_dict[i] = { "input": signal_batch[i], "output": output_batch[i] } for k, v in kwargs_.items(): try: audio_dict[i][k] = v[i].item() except: audio_dict[i][k] = v[i].float().mean() return audio_dict ``` -------------------------------- ### Nest multiple Compose transforms Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html Example of creating a complex pipeline by nesting multiple Compose transform instances. ```python >>> preprocess = transforms.Compose( >>> tfm.GlobalVolumeNorm(), >>> tfm.CrossTalk(), >>> name="preprocess", >>> ) >>> augment = transforms.Compose( >>> tfm.RoomImpulseResponse(), >>> tfm.BackgroundNoise(), >>> name="augment", >>> ) >>> postprocess = transforms.Compose( >>> tfm.VolumeChange(), >>> tfm.RescaleAudio(), >>> tfm.ShiftPhase(), >>> name="postprocess", >>> ) >>> transform = transforms.Compose(preprocess, augment, postprocess), ``` -------------------------------- ### Handle audio clipping warnings Source: https://descriptinc.github.io/audiotools/tutorials/transforms.html Example of a UserWarning triggered when audio amplitude exceeds 1 during save operations. ```python /Users/prem/sync/lyrebird-audiotools/audiotools/core/audio_signal.py:601: UserWarning: Audio amplitude > 1 clipped when saving warnings.warn("Audio amplitude > 1 clipped when saving") ``` -------------------------------- ### audiotools.core.util.chdir Source: https://descriptinc.github.io/audiotools/source/audiotools.core.html Context manager for switching directories. ```APIDOC ## chdir ### Description Context manager for switching directories to run a function. Useful for when you want to use relative paths to different runs. ### Parameters #### Path Parameters - **newdir** (Union[Path, str]) - Required - Directory to switch to. ``` -------------------------------- ### AudioDataset Class Source: https://descriptinc.github.io/audiotools/source/audiotools.data.html This section details the AudioDataset class, its parameters, and provides examples of its usage for loading and processing audio data. ```APIDOC ## AudioDataset Class ### Description Loads audio from multiple loaders (with associated transforms) for a specified number of samples. Excerpts are drawn randomly of the specified duration, above a specified loudness threshold and are resampled on the fly to the desired sample rate (if it is different from the audio source sample rate). This takes either a single AudioLoader object, a dictionary of AudioLoader objects, or a dictionary of AudioLoader objects. Each AudioLoader is called by the dataset, and the result is placed in the output dictionary. A transform can also be specified for the entire dataset, rather than for each specific loader. This transform can be applied to the output of all the loaders if desired. AudioLoader objects can be specified as aligned, which means the loaders correspond to multitrack audio (e.g. a vocals, bass, drums, and other loader for multitrack music mixtures). ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters * **loaders** (_Union_ _[__AudioLoader_ _,__List_ _[__AudioLoader_ _]__,__Dict_ _[__str_ _,__AudioLoader_ _]__]_) – AudioLoaders to sample audio from. * **sample_rate** (_int_) – Desired sample rate. * **n_examples** (_int_ _,__optional_) – Number of examples (length of dataset), by default 1000 * **duration** (_float_ _,__optional_) – Duration of audio samples, by default 0.5 * **loudness_cutoff** (_float_ _,__optional_) – Loudness cutoff threshold for audio samples, by default -40 * **num_channels** (_int_ _,__optional_) – Number of channels in output audio, by default 1 * **transform** (_Callable_ _,__optional_) – Transform to instantiate alongside each dataset item, by default None * **aligned** (_bool_ _,__optional_) – Whether the loaders should be sampled in an aligned manner (e.g. same offset, duration, and matched file name), by default False * **shuffle_loaders** (_bool_ _,__optional_) – Whether to shuffle the loaders before sampling from them, by default False * **matcher** (_Callable_) – How to match files from adjacent audio lists (e.g. for a multitrack audio loader), by default uses the parent directory of each file. * **without_replacement** (_bool_) – Whether to choose files with or without replacement, by default True. ### Request Example ```python >>> from audiotools.data.datasets import AudioLoader >>> from audiotools.data.datasets import AudioDataset >>> from audiotools import transforms as tfm >>> import numpy as np >>> >>> loaders = [ >>> AudioLoader( >>> sources=[f"tests/audio/spk"], >>> transform=tfm.Equalizer(), >>> ext=["wav"], >>> ) >>> for i in range(5) >>> ] >>> >>> dataset = AudioDataset( >>> loaders = loaders, >>> sample_rate = 44100, >>> duration = 1.0, >>> transform = tfm.RescaleAudio(), >>> ) >>> >>> item = dataset[np.random.randint(len(dataset))] >>> >>> for i in range(len(loaders)): >>> item[i]["signal"] = loaders[i].transform( >>> item[i]["signal"], **item[i]["transform_args"] >>> ) >>> item[i]["signal"].widget(i) >>> >>> mix = sum([item[i]["signal"] for i in range(len(loaders))]) >>> mix = dataset.transform(mix, **item["transform_args"]) >>> mix.widget("mix") ``` ### Response #### Success Response (200) None #### Response Example None ``` ```APIDOC ## Loading MUSDB Multitrack Data ### Description Example of how to load MUSDB multitrack data using `AudioDataset` and `AudioLoader`. ### Method None ### Endpoint None ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```python >>> import audiotools as at >>> from pathlib import Path >>> from audiotools import transforms as tfm >>> import numpy as np >>> import torch >>> >>> def build_dataset( >>> sample_rate: int = 44100, >>> duration: float = 5.0, >>> musdb_path: str = "~/.data/musdb/", >>> ): >>> musdb_path = Path(musdb_path).expanduser() >>> loaders = { >>> src: at.datasets.AudioLoader( >>> sources=[musdb_path], >>> transform=tfm.Compose( >>> tfm.VolumeNorm(("uniform", -20, -10)), >>> tfm.Silence(prob=0.1), >>> ), >>> ext=[f"{src}.wav"], >>> ) >>> for src in ["vocals", "bass", "drums", "other"] >>> } >>> >>> dataset = at.datasets.AudioDataset( >>> loaders=loaders, >>> sample_rate=sample_rate, >>> duration=duration, >>> num_channels=1, >>> aligned=True, >>> transform=tfm.RescaleAudio(), >>> shuffle_loaders=True, >>> ) >>> return dataset, list(loaders.keys()) >>> >>> train_data, sources = build_dataset() >>> dataloader = torch.utils.data.DataLoader( >>> train_data, >>> batch_size=16, >>> ``` ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### Compute STFT Source: https://descriptinc.github.io/audiotools/source/audiotools.core.html Examples for computing the STFT of an audio signal, including basic usage and iterating through different STFT parameters. ```python >>> signal = AudioSignal(torch.randn(44100), 44100) >>> signal.stft() ``` ```python >>> stft_params = [STFTParams(128, 32), STFTParams(512, 128)] >>> for stft_param in stft_params: >>> signal.stft_params = stft_params >>> signal.stft() ``` -------------------------------- ### Instantiate LowPass transform parameters Source: https://descriptinc.github.io/audiotools/_sources/tutorials/transforms.md.txt Demonstrates how to instantiate transform parameters using a random seed or custom distribution settings. ```python from audiotools import transforms as tfm transform = tfm.LowPass() seed = 0 print(transform.instantiate(seed)) ``` ```python transform = tfm.LowPass( cutoff = ("uniform", 4000, 8000) ) print(transform.instantiate(seed)) ``` ```python transform = tfm.LowPass() seed = 0 print(transform.instantiate(seed)) ``` -------------------------------- ### Calculate Time Masking Bounds Source: https://descriptinc.github.io/audiotools/_modules/audiotools/data/transforms.html Calculates the start and end time in seconds for a given center and width relative to signal duration. ```python tmin = max(t_center - (t_width / 2), 0.0) tmax = min(t_center + (t_width / 2), 1.0) tmin_s = signal.signal_duration * tmin tmax_s = signal.signal_duration * tmax return {"tmin_s": tmin_s, "tmax_s": tmax_s} def _transform(self, signal, tmin_s: float, tmax_s: float): return signal.mask_timesteps(tmin_s=tmin_s, tmax_s=tmax_s) ``` -------------------------------- ### Samples Class Initialization Source: https://descriptinc.github.io/audiotools/_modules/audiotools/preference.html Initializes the audio sample collection from a folder, supporting optional shuffling and sample count limiting. ```APIDOC ## Class: Samples ### Description Initializes a collection of audio files from a specified directory. It organizes files by name and condition, and optionally shuffles the sample order. ### Parameters - **folder** (str) - Required - Path to the directory containing audio files. - **shuffle** (bool) - Optional - Whether to shuffle the sample order. Defaults to True. - **n_samples** (int) - Optional - Limit the number of samples to process. ``` -------------------------------- ### GET /get_window Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/audio_signal.html Retrieves a window function for STFT processing, supporting standard scipy windows and custom types like sqrt_hann. ```APIDOC ## GET /get_window ### Description Retrieves a window function for STFT processing. This function is cached for efficiency. ### Parameters #### Query Parameters - **window_type** (str) - Required - Type of window to get (e.g., 'hann', 'sqrt_hann', 'average') - **window_length** (int) - Required - Length of the window - **device** (str) - Required - Device to put window onto (e.g., 'cpu', 'cuda') ### Response #### Success Response (200) - **window** (torch.Tensor) - The requested window as a tensor. ``` -------------------------------- ### Initialize Audio Player Source: https://descriptinc.github.io/audiotools/_sources/tutorials/listening_tests.md.txt Creates a basic Player object within a Gradio Blocks context. ```python with gr.Blocks() as app: player = pr.Player(app) ``` -------------------------------- ### Format Matplotlib Axes for Audio Plots Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/util.html Configures axes, font scaling, and annotations for audio-related plots. Requires matplotlib to be installed. ```python import matplotlib import matplotlib.pyplot as plt if fig_size is None: fig_size = DEFAULT_FIG_SIZE if not format: return if fig is None: fig = plt.gcf() fig.set_size_inches(*fig_size) axs = fig.axes pixels = (fig.get_size_inches() * fig.dpi)[0] font_scale = pixels / BASE_SIZE if format_axes: axs = fig.axes for ax in axs: ymin, _ = ax.get_ylim() xmin, _ = ax.get_xlim() ticks = ax.get_yticks() for t in ticks[2:-1]: t = axs[0].annotate( f"{(t / 1000):2.1f}k", xy=(xmin, t), xycoords="data", xytext=(5, -5), textcoords="offset points", ha="left", va="top", color=font_color, fontsize=12 * font_scale, alpha=0.75, ) ticks = ax.get_xticks()[2:] for t in ticks[:-1]: t = axs[0].annotate( f"{t:2.1f}s", xy=(t, ymin), xycoords="data", xytext=(5, 5), textcoords="offset points", ha="center", va="bottom", color=font_color, fontsize=12 * font_scale, alpha=0.75, ) ax.margins(0, 0) ax.set_axis_off() ax.xaxis.set_major_locator(plt.NullLocator()) ax.yaxis.set_major_locator(plt.NullLocator()) plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0) if title is not None: t = axs[0].annotate( title, xy=(1, 1), xycoords="axes fraction", fontsize=20 * font_scale, xytext=(-5, -5), textcoords="offset points", ha="right", va="top", color="white", ) t.set_bbox(dict(facecolor="black", alpha=0.5, edgecolor="black")) ``` -------------------------------- ### Instantiate LowPass Transform with Distributions Source: https://descriptinc.github.io/audiotools/tutorials/transforms.html Demonstrates initializing the LowPass transform with different distribution types like choice and uniform to sample cutoff frequencies. ```python from audiotools import transforms as tfm transform = tfm.LowPass() seed = 0 print(transform.instantiate(seed)) ``` ```python transform = tfm.LowPass( cutoff = ("uniform", 4000, 8000) ) print(transform.instantiate(seed)) ``` -------------------------------- ### Initialize Player Class Source: https://descriptinc.github.io/audiotools/_modules/audiotools/preference.html Python class for managing the Gradio-based audio player interface and WaveSurfer integration. ```python class Player: def __init__(self, app): self.app = app self.app.load(_js=load_wavesurfer_js) self.app.css = CUSTOM_CSS self.wavs = [] self.position = 0 def create(self): gr.HTML(WAVESURFER, visible=True) gr.Markdown( "Click and drag on the waveform above to select a region for playback. " "Once created, the region can be moved around and resized. " "Clear the regions using the button below. Hit play on one of the buttons below to start!" ) with gr.Row(): clear = gr.Button("Clear region") loop = gr.Button("Looping OFF", elem_id="loop-button") loop.click(None, _js=loop_region) clear.click(None, _js=clear_regions) def add(self, name: str = "Play"): i = self.position self.wavs.append( { "audio": gr.Audio(visible=False), "button": gr.Button(name, elem_classes=["playpause"]), "position": i, } ) self.wavs[-1]["button"].click(None, _js=play(i)) self.position += 1 return self.wavs[-1] def to_list(self): return [x["audio"] for x in self.wavs] ``` -------------------------------- ### Initialize and process an AudioDataset Source: https://descriptinc.github.io/audiotools/_modules/audiotools/data/datasets.html Demonstrates creating an AudioDataset with multiple loaders and applying transforms to the sampled audio. ```python from audiotools.data.datasets import AudioLoader from audiotools.data.datasets import AudioDataset from audiotools import transforms as tfm import numpy as np loaders = [ AudioLoader( sources=[f"tests/audio/spk"], transform=tfm.Equalizer(), ext=["wav"], ) for i in range(5) ] dataset = AudioDataset( loaders = loaders, sample_rate = 44100, duration = 1.0, transform = tfm.RescaleAudio(), ) item = dataset[np.random.randint(len(dataset))] for i in range(len(loaders)): item[i]["signal"] = loaders[i].transform( item[i]["signal"], **item[i]["transform_args"] ) item[i]["signal"].widget(i) mix = sum([item[i]["signal"] for i in range(len(loaders))]) mix = dataset.transform(mix, **item["transform_args"]) mix.widget("mix") ``` -------------------------------- ### Play Audio with ffplay Source: https://descriptinc.github.io/audiotools/_modules/audiotools/core/playback.html Plays an audio signal using ffplay. Requires ffplay to be installed. Writes the audio to a temporary WAV file before playback. ```python tmpfiles = [] with _close_temp_files(tmpfiles): tmp_wav = NamedTemporaryFile(suffix=".wav", delete=False) tmpfiles.append(tmp_wav) self.write(tmp_wav.name) print(self) subprocess.call([ "ffplay", "-nodisp", "-autoexit", "-hide_banner", "-loglevel", "error", tmp_wav.name, ]) return self ```