diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e5afe0a615cd75bfe84eb0fb22a13c46a1479cd5 Binary files /dev/null and b/.DS_Store differ diff --git a/DEFAULT_HF_MODEL_REPO b/DEFAULT_HF_MODEL_REPO new file mode 100644 index 0000000000000000000000000000000000000000..1d528404e175da8ddf687ea43078b714380bfdbe --- /dev/null +++ b/DEFAULT_HF_MODEL_REPO @@ -0,0 +1 @@ +hugggof/vampnet \ No newline at end of file diff --git a/DEFAULT_MODEL b/DEFAULT_MODEL new file mode 100644 index 0000000000000000000000000000000000000000..4ad96d51599fb734101f6229f6c1a8a509bd6255 --- /dev/null +++ b/DEFAULT_MODEL @@ -0,0 +1 @@ +default diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..53e66ea3e16109c82c94b12b859fdb7ca1c2ee81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Hugo Flores García and Prem Seetharaman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index ee58e7b5f9cbe09881e6d1ac5b1de557831454bd..15bdce924d5ca7ece14b185088f1bf040d4f6dee 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,249 @@ --- -title: Vampnet Music HARP V3 -emoji: 🐢 -colorFrom: red -colorTo: yellow +title: salad bowl (vampnet) +emoji: 🥗 +colorFrom: yellow +colorTo: green sdk: gradio -sdk_version: 5.42.0 +sdk_version: 5.23.2 +python_version: 3.11 app_file: app.py pinned: false -short_description: Wrapped VampNet model for HARP3 +license: cc-by-nc-4.0 --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# VampNet + +# Table of contents + +- [setting up](#setting-up) +- [programmatic usage](#programmatic-usage) +- [launching the web app](#launching-the-web-app) +- [training / fine-tuning](#training--fine-tuning) + - [training a model](#training-a-model) + - [debugging training](#debugging-training) + - [fine-tuning](#fine-tuning) +- [exporting your model](#exporting-your-model) +- [unloop](#unloop) +- [token telephone](#token-telephone) +- [a note on argbind](#a-note-on-argbind) +- [take a look at the pretrained models](#take-a-look-at-the-pretrained-models) +- [licensing for pretrained models](#licensing-for-pretrained-models) + +## setting up + +python 3.9-3.11 works well. (for example, using conda) +```bash +conda create -n vampnet python=3.9 +conda activate vampnet +``` + +install VampNet + +```bash +git clone https://github.com/hugofloresgarcia/vampnet.git +pip install -e ./vampnet +``` + +## programmatic usage + +quick start! +```python +import random +import vampnet +import audiotools as at + +# load the default vampnet model +interface = vampnet.interface.Interface.default() + +# list available finetuned models +finetuned_model_choices = interface.available_models() +print(f"available finetuned models: {finetuned_model_choices}") + +# pick a random finetuned model +model_choice = random.choice(finetuned_model_choices) +print(f"choosing model: {model_choice}") + +# load a finetuned model +interface.load_finetuned(model_choice) + +# load an example audio file +signal = at.AudioSignal("assets/example.wav") + +# get the tokens for the audio +codes = interface.encode(signal) + +# build a mask for the audio +mask = interface.build_mask( + codes, signal, + periodic_prompt=7, + upper_codebook_mask=3, +) + +# generate the output tokens +output_tokens = interface.vamp( + codes, mask, return_mask=False, + temperature=1.0, + typical_filtering=True, +) + +# convert them to a signal +output_signal = interface.decode(output_tokens) + +# save the output signal +output_signal.write("scratch/output.wav") +``` + + +# Launching the Web app +You can launch a gradio UI to play with vampnet. + +```bash +python app.py +``` + +# Training / Fine-tuning + +## Training a model + +To train a model, run the following script: + +```bash +python scripts/exp/train.py --args.load conf/vampnet.yml --save_path /path/to/checkpoints +``` + +for multi-gpu training, use torchrun: + +```bash +torchrun --nproc_per_node gpu scripts/exp/train.py --args.load conf/vampnet.yml --save_path path/to/ckpt +``` + +You can edit `conf/vampnet.yml` to change the dataset paths or any training hyperparameters. + +For coarse2fine models, you can use `conf/c2f.yml` as a starting configuration. + +See `python scripts/exp/train.py -h` for a list of options. + +## Debugging training + +To debug training, it's easier to debug with 1 gpu and 0 workers + +```bash +CUDA_VISIBLE_DEVICES=0 python -m pdb scripts/exp/train.py --args.load conf/vampnet.yml --save_path /path/to/checkpoints --num_workers 0 +``` + +# Fine-tuning + +To fine-tune a model, use the script in `scripts/exp/fine_tune.py` + +for an audio folder +```bash +python scripts/exp/fine_tune.py /path/to/audio/folder +``` + +for multiple files +```bash +python scripts/exp/fine_tune.py "/path/to/audio1.mp3 /path/to/audio2/ /path/to/audio3.wav" +``` + +This creates configuration files for a fine tuning train job. The save_paths will be set to `runs//coarse` and `runs//c2f`. + +launch the coarse job: +```bash +python scripts/exp/train.py --args.load conf/generated//coarse.yml +``` + +this will save the coarse model to `runs//coarse/ckpt/best/`. + +launch the c2f job: +```bash +python scripts/exp/train.py --args.load conf/generated//c2f.yml +``` + +# Resuming a Training/Finetuning Job from checkpoint. + +To resume from checkpoint, use the `--resume` flag and the `--save_path` to point to the checkpoint you want to resume from. +```bash +python scripts/exp/train.py --args.load conf/generated/steve/coarse.yml --save_path runs/steve/coarse --resume +``` + +# Exporting your model + +Once your model has been fine-tuned, you can export it to a HuggingFace model. + +In order to use your model in `app.py`, you will need to export it to HuggingFace. + +**NOTE**: In order to export, you will need a [huggingface account](https://huggingface.co/). + +Now, log in to huggingface using the command line: +```bash +huggingface-cli login +``` + +replace the contents of the file named `./DEFAULT_HF_MODEL_REPO` with your `/vampnet`. A model repo will be automatically created for you with `export.py`. The default is `hugggof/vampnet`. + +for example, if my username is `hugggof`, I would run the following command:` +```bash +echo 'hugggof/vampnet' > ./DEFAULT_HF_MODEL_REPO +``` + +Now, run the following command to export your model (replace `` with the name of your model): + +```bash +python scripts/exp/export.py --name --model latest +``` + +Once that's done, your model should appear on the list of available models in the gradio interface. +Simply run `python app.py` and select your model from the dropdown list. + + +# Unloop + +Make sure you have Max installed on your laptop! + +**NOTE**: To run unloop (with a GPU-powered server), you will need to install the vampnet repo in both your local machine and your GPU server. + +## start a vampnet gradio server + +First, **on your GPU server**, run the gradio server: +```bash +python app.py --args.load conf/interface.yml --Interface.device cuda +``` +This will run a vampnet gradio API on your GPU server. Copy the address. It will be something like `https://127.0.0.1:7860/`. + +**IMPORTANT** Make sure that this gradio port (by default `7860`) is forwarded to your local machine, where you have Max installed. + +## start the unloop gradio client +Now, **on your local machine**, run the unloop gradio client. +``` +cd unloop +pip install -r requirements.txt +python client.py --vampnet_url https://127.0.0.1:7860/ # replace with your gradio server address +``` +This will start a gradio client that connects to the gradio server running on your GPU server. + +## start the unloop Max patch +Now, open the unloop Max patch. It's located at `unloop/max/unloop.maxpat`. + +In the tape controls, check the heartbeat (`<3`) to make sure the connection to the local gradio client is working. + +have fun! + +# Token Telephone + +Instructions forthcoming, but the sauce is in `token_telephone/tt.py` + +## A note on argbind +This repository relies on [argbind](https://github.com/pseeth/argbind) to manage CLIs and config files. +Config files are stored in the `conf/` folder. + +### Take a look at the pretrained models +All the pretrained models (trained by hugo) are stored here: https://huggingface.co/hugggof/vampnet + +### Licensing for Pretrained Models: +The weights for the models are licensed [`CC BY-NC-SA 4.0`](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ml). Likewise, any VampNet models fine-tuned on the pretrained models are also licensed [`CC BY-NC-SA 4.0`](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ml). + +Download the pretrained models from [this link](https://zenodo.org/record/8136629). Then, extract the models to the `models/` folder. + + + + diff --git a/TODOS b/TODOS new file mode 100644 index 0000000000000000000000000000000000000000..f2991aa6e833141194249c46334aec35217285c3 --- /dev/null +++ b/TODOS @@ -0,0 +1 @@ +[ ] add sketch2sound finetuning \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..39ec21564a0c7266c8fd35aefbea7943939aca38 --- /dev/null +++ b/app.py @@ -0,0 +1,760 @@ +import spaces +from pathlib import Path +import yaml +import time +import uuid + +import numpy as np +import audiotools as at +import argbind +import shutil +import torch +from datetime import datetime +from pyharp.core import build_endpoint, ModelCard +from pyharp.labels import OutputLabel, LabelList +from pyharp.media.audio import save_audio + +import gradio as gr +from vampnet.interface import Interface, signal_concat +from vampnet import mask as pmask + +device="cpu" +print(f"using device {device}\n"*10) + +interface = Interface.default() +init_model_choice = open("DEFAULT_MODEL").read().strip() + +# load the init model +interface.load_finetuned(init_model_choice) + +def to_output(sig): + return sig.sample_rate, sig.cpu().detach().numpy()[0][0] + +MAX_DURATION_S = 10 +def load_audio(file): + print(file) + if isinstance(file, str): + filepath = file + elif isinstance(file, tuple): + # not a file + sr, samples = file + samples = samples / np.iinfo(samples.dtype).max + return sr, samples + else: + filepath = file.name + sig = at.AudioSignal.salient_excerpt( + filepath, duration=MAX_DURATION_S + ) + sig = at.AudioSignal(filepath) + return to_output(sig) + + +def load_example_audio(): + return load_audio("./assets/example.wav") + +from torch_pitch_shift import pitch_shift, get_fast_shifts +def shift_pitch(signal, interval: int): + signal.samples = pitch_shift( + signal.samples, + shift=interval, + sample_rate=signal.sample_rate + ) + return signal + + +def onsets(sig: at.AudioSignal, hop_length: int): + assert sig.batch_size == 1, "batch size must be 1" + assert sig.num_channels == 1, "mono signals only" + import librosa + onset_frame_idxs = librosa.onset.onset_detect( + y=sig.samples[0][0].detach().cpu().numpy(), sr=sig.sample_rate, + hop_length=hop_length, + backtrack=True, + ) + return onset_frame_idxs + + +@spaces.GPU +def new_vampnet_mask(self, + codes, + onset_idxs, + width: int = 5, + periodic_prompt=2, + upper_codebook_mask=1, + drop_amt: float = 0.1 +): + from vampnet.newmask import mask_and, mask_or, onset_mask, periodic_mask, drop_ones, codebook_mask + mask = mask_and( + periodic_mask(codes, periodic_prompt, 1, random_roll=False), + mask_or( # this re-masks the onsets, according to a periodic schedule + onset_mask(onset_idxs, codes, width=width), + periodic_mask(codes, periodic_prompt, 1, random_roll=False), + ) + ).int() + # make sure the onset idxs themselves are unmasked + # mask = 1 - mask + mask[:, :, onset_idxs] = 0 + mask = mask.cpu() # debug + mask = 1-drop_ones(1-mask, drop_amt) + mask = codebook_mask(mask, upper_codebook_mask) + + + # save mask as txt (ints) + np.savetxt("scratch/rms_mask.txt", mask[0].cpu().numpy(), fmt='%d') + mask = mask.to(self.device) + return mask[:, :, :] + +@spaces.GPU +def mask_preview(periodic_p, n_mask_codebooks, onset_mask_width, dropout): + # make a mask preview + codes = torch.zeros((1, 14, 80)).to(device) + mask = interface.build_mask( + codes, + periodic_prompt=periodic_p, + # onset_mask_width=onset_mask_width, + _dropout=dropout, + upper_codebook_mask=n_mask_codebooks, + ) + # mask = mask.cpu().numpy() + import matplotlib.pyplot as plt + plt.clf() + interface.visualize_codes(mask) + plt.title("mask preview") + plt.savefig("scratch/mask-prev.png") + return "scratch/mask-prev.png" + + +@spaces.GPU +def _vamp_internal( + seed, input_audio, model_choice, + pitch_shift_amt, periodic_p, + n_mask_codebooks, onset_mask_width, + dropout, sampletemp, typical_filtering, + typical_mass, typical_min_tokens, top_p, + sample_cutoff, stretch_factor, sampling_steps, beat_mask_ms, num_feedback_steps, api=False, harp=False + ): + if torch.cuda.is_available(): + device = "cuda" + elif torch.backends.mps.is_available(): + device = "mps" + else: + device = "cpu" + + + print("args!") + print(f"seed: {seed}") + print(f"input_audio: {input_audio}") + print(f"model_choice: {model_choice}") + print(f"pitch_shift_amt: {pitch_shift_amt}") + print(f"periodic_p: {periodic_p}") + print(f"n_mask_codebooks: {n_mask_codebooks}") + print(f"onset_mask_width: {onset_mask_width}") + print(f"dropout: {dropout}") + print(f"sampletemp: {sampletemp}") + print(f"typical_filtering: {typical_filtering}") + print(f"typical_mass: {typical_mass}") + print(f"typical_min_tokens: {typical_min_tokens}") + print(f"top_p: {top_p}") + print(f"sample_cutoff: {sample_cutoff}") + print(f"stretch_factor: {stretch_factor}") + print(f"sampling_steps: {sampling_steps}") + print(f"api: {api}") + print(f"beat_mask_ms: {beat_mask_ms}") + print(f"using device {interface.device}") + print(f"num feedback steps: {num_feedback_steps}") + + + t0 = time.time() + interface.to(device) + print(f"using device {interface.device}") + _seed = seed if seed > 0 else None + if _seed is None: + _seed = int(torch.randint(0, 2**32, (1,)).item()) + at.util.seed(_seed) + + if input_audio is None: + raise gr.Error("no input audio received!") + sr, input_audio = input_audio + input_audio = input_audio / np.iinfo(input_audio.dtype).max + + sig = at.AudioSignal(input_audio, sr).to_mono() + + loudness = sig.loudness() + sig = interface._preprocess(sig) + + # reload the model if necessary + interface.load_finetuned(model_choice) + + if pitch_shift_amt != 0: + sig = shift_pitch(sig, pitch_shift_amt) + + codes = interface.encode(sig) + + # mask = new_vampnet_mask( + # interface, + # codes, + # onset_idxs=onsets(sig, hop_length=interface.codec.hop_length), + # width=onset_mask_width, + # periodic_prompt=periodic_p, + # upper_codebook_mask=n_mask_codebooks, + # drop_amt=dropout + # ).long() + + + mask = interface.build_mask( + codes, + sig=sig, + periodic_prompt=periodic_p, + onset_mask_width=onset_mask_width, + _dropout=dropout, + upper_codebook_mask=n_mask_codebooks, + ) + if beat_mask_ms > 0: + # bm = pmask.mask_or( + # pmask.periodic_mask( + # codes, periodic_p, random_roll=False + # ), + # ) + mask = pmask.mask_and( + mask, interface.make_beat_mask( + sig, after_beat_s=beat_mask_ms/1000., + ) + ) + mask = pmask.codebook_mask(mask, n_mask_codebooks) + np.savetxt("scratch/rms_mask.txt", mask[0].cpu().numpy(), fmt='%d') + + interface.set_chunk_size(10.0) + + # lord help me + if top_p is not None: + if top_p > 0: + pass + else: + top_p = None + + codes, mask_z = interface.vamp( + codes, mask, + batch_size=2, + feedback_steps=num_feedback_steps, + _sampling_steps=sampling_steps, + time_stretch_factor=stretch_factor, + return_mask=True, + temperature=sampletemp, + typical_filtering=typical_filtering, + typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens, + top_p=top_p, + seed=_seed, + sample_cutoff=sample_cutoff, + ) + print(f"vamp took {time.time() - t0} seconds") + + sig = interface.decode(codes) + sig = sig.normalize(loudness) + + import matplotlib.pyplot as plt + plt.clf() + # plt.imshow(mask_z[0].cpu().numpy(), aspect='auto + interface.visualize_codes(mask) + plt.title("actual mask") + plt.savefig("scratch/mask.png") + plt.clf() + + if harp: + return sig + + if not api: + return to_output(sig[0]), to_output(sig[1]), "scratch/mask.png" + else: + return to_output(sig[0]), to_output(sig[1]) + +@spaces.GPU +def vamp(input_audio, + sampletemp, + top_p, + periodic_p, + dropout, + stretch_factor, + onset_mask_width, + typical_filtering, + typical_mass, + typical_min_tokens, + seed, + model_choice, + n_mask_codebooks, + pitch_shift_amt, + sample_cutoff, + sampling_steps, + beat_mask_ms, + num_feedback_steps): + return _vamp_internal( + seed=seed, + input_audio=input_audio, + model_choice=model_choice, + pitch_shift_amt=pitch_shift_amt, + periodic_p=periodic_p, + n_mask_codebooks=n_mask_codebooks, + onset_mask_width=onset_mask_width, + dropout=dropout, + sampletemp=sampletemp, + typical_filtering=typical_filtering, + typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens, + top_p=top_p, + sample_cutoff=sample_cutoff, + stretch_factor=stretch_factor, + sampling_steps=sampling_steps, + beat_mask_ms=beat_mask_ms, + num_feedback_steps=num_feedback_steps, + api=False, + ) + +@spaces.GPU +def api_vamp(input_audio, + sampletemp, top_p, + periodic_p, + dropout, + stretch_factor, + onset_mask_width, + typical_filtering, + typical_mass, + typical_min_tokens, + seed, + model_choice, + n_mask_codebooks, + pitch_shift_amt, + sample_cutoff, + sampling_steps, + beat_mask_ms, num_feedback_steps): + return _vamp_internal( + seed=seed, + input_audio=input_audio, + model_choice=model_choice, + pitch_shift_amt=pitch_shift_amt, + periodic_p=periodic_p, + n_mask_codebooks=n_mask_codebooks, + onset_mask_width=onset_mask_width, + dropout=dropout, + sampletemp=sampletemp, + typical_filtering=typical_filtering, + typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens, + top_p=top_p, + sample_cutoff=sample_cutoff, + stretch_factor=stretch_factor, + sampling_steps=sampling_steps, + beat_mask_ms=beat_mask_ms, + num_feedback_steps=num_feedback_steps, + api=True, + ) + +@spaces.GPU +def harp_vamp(input_audio, sampletemp, periodic_p, dropout, n_mask_codebooks, model_choice, stretch_factor): + sig = at.AudioSignal(input_audio).to_mono() + + input_audio = sig.cpu().detach().numpy()[0][0] + input_audio = input_audio * np.iinfo(np.int16).max + input_audio = input_audio.astype(np.int16) + input_audio = input_audio.reshape(1, -1) + input_audio = (sig.sample_rate, input_audio) + + sig = _vamp_internal( + seed=0, + input_audio=input_audio, + model_choice=model_choice, + pitch_shift_amt=0, + periodic_p=int(periodic_p), + n_mask_codebooks=int(n_mask_codebooks), + onset_mask_width=0, + dropout=dropout, + sampletemp=sampletemp, + typical_filtering=False, + typical_mass=0.15, + typical_min_tokens=1, + top_p=None, + sample_cutoff=1.0, + stretch_factor=stretch_factor, + sampling_steps=36, + beat_mask_ms=int(0), + num_feedback_steps=1, + api=False, + harp=True, + ) + + ll = LabelList() + ll.append(OutputLabel(label='short label', t=0.0, description='longer description')) + return save_audio(sig.detach().cpu()), ll + + +with gr.Blocks() as demo: + with gr.Row(): + with gr.Column(): + manual_audio_upload = gr.File( + label=f"upload some audio (will be randomly trimmed to max of 100s)", + file_types=["audio"] + ) + load_example_audio_button = gr.Button("or load example audio") + + input_audio = gr.Audio( + label="input audio", + interactive=False, + type="numpy", + ) + + # audio_mask = gr.Audio( + # label="audio mask (listen to this to hear the mask hints)", + # interactive=False, + # type="numpy", + # ) + + # connect widgets + load_example_audio_button.click( + fn=load_example_audio, + inputs=[], + outputs=[ input_audio] + ) + + manual_audio_upload.change( + fn=load_audio, + inputs=[manual_audio_upload], + outputs=[ input_audio] + ) + + + # mask settings + with gr.Column(): + with gr.Accordion("manual controls", open=True): + periodic_p = gr.Slider( + label="periodic prompt", + minimum=0, + maximum=13, + step=1, + value=7, + ) + + onset_mask_width = gr.Slider( + label="onset mask width (multiplies with the periodic mask, 1 step ~= 10milliseconds) does not affect mask preview", + minimum=0, + maximum=100, + step=1, + value=0, visible=True + ) + + beat_mask_ms = gr.Slider( + label="beat mask width (milliseconds) does not affect mask preview", + minimum=1, + maximum=200, + step=1, + value=0, + visible=True + ) + + n_mask_codebooks = gr.Slider( + label="compression prompt ", + value=3, + minimum=1, + maximum=14, + step=1, + ) + + dropout = gr.Slider( + label="mask dropout", + minimum=0.0, + maximum=1.0, + step=0.01, + value=0.0 + ) + + num_feedback_steps = gr.Slider( + label="feedback steps (token telephone) -- turn it up for better timbre/rhythm transfer quality, but it's slower!", + minimum=1, + maximum=8, + step=1, + value=1 + ) + + preset_dropdown = gr.Dropdown( + label="preset", + choices=["timbre transfer", "small variation", "small variation (follow beat)", "medium variation", "medium variation (follow beat)", "large variation", "large variation (follow beat)", "unconditional"], + value="medium variation" + ) + def change_preset(preset_dropdown): + if preset_dropdown == "timbre transfer": + periodic_p = 2 + n_mask_codebooks = 1 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms = 0 + elif preset_dropdown == "small variation": + periodic_p = 5 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms = 0 + elif preset_dropdown == "small variation (follow beat)": + periodic_p = 7 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms = 50 + elif preset_dropdown == "medium variation": + periodic_p = 7 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms = 0 + elif preset_dropdown == "medium variation (follow beat)": + periodic_p = 13 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms = 50 + elif preset_dropdown == "large variation": + periodic_p = 13 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.2 + beat_mask_ms = 0 + elif preset_dropdown == "large variation (follow beat)": + periodic_p = 0 + n_mask_codebooks = 4 + onset_mask_width = 0 + dropout = 0.0 + beat_mask_ms=80 + elif preset_dropdown == "unconditional": + periodic_p=0 + n_mask_codebooks=1 + onset_mask_width=0 + dropout=0.0 + return periodic_p, n_mask_codebooks, onset_mask_width, dropout, beat_mask_ms + preset_dropdown.change( + fn=change_preset, + inputs=[preset_dropdown], + outputs=[periodic_p, n_mask_codebooks, onset_mask_width, dropout, beat_mask_ms] + ) + # preset_dropdown.change( + + + maskimg = gr.Image( + label="mask image", + interactive=False, + type="filepath" + ) + + with gr.Accordion("extras ", open=False): + pitch_shift_amt = gr.Slider( + label="pitch shift amount (semitones)", + minimum=-12, + maximum=12, + step=1, + value=0, + ) + + stretch_factor = gr.Slider( + label="time stretch factor", + minimum=0, + maximum=8, + step=1, + value=1, + ) + + + + + with gr.Accordion("sampling settings", open=False): + sampletemp = gr.Slider( + label="sample temperature", + minimum=0.1, + maximum=10.0, + value=1.0, + step=0.001 + ) + + top_p = gr.Slider( + label="top p (0.0 = off)", + minimum=0.0, + maximum=1.0, + value=0.0 + ) + typical_filtering = gr.Checkbox( + label="typical filtering ", + value=True + ) + typical_mass = gr.Slider( + label="typical mass (should probably stay between 0.1 and 0.5)", + minimum=0.01, + maximum=0.99, + value=0.15 + ) + typical_min_tokens = gr.Slider( + label="typical min tokens (should probably stay between 1 and 256)", + minimum=1, + maximum=256, + step=1, + value=64 + ) + sample_cutoff = gr.Slider( + label="sample cutoff", + minimum=0.0, + maximum=0.9, + value=1.0, + step=0.01 + ) + sampling_steps = gr.Slider( + label="sampling steps", + minimum=1, + maximum=128, + step=1, + value=36 + ) + + + + seed = gr.Number( + label="seed (0 for random)", + value=0, + precision=0, + ) + + + # mask settings + with gr.Column(): + + model_choice = gr.Dropdown( + label="model choice", + choices=list(interface.available_models()), + value=init_model_choice, + visible=True + ) + + + vamp_button = gr.Button("generate (vamp)!!!") + + + audio_outs = [] + use_as_input_btns = [] + for i in range(2): + with gr.Column(): + audio_outs.append(gr.Audio( + label=f"output audio {i+1}", + interactive=False, + type="numpy" + )) + use_as_input_btns.append( + gr.Button(f"use as input (feedback)") + ) + + thank_you = gr.Markdown("") + + # download all the outputs + # download = gr.File(type="filepath", label="download outputs") + + + # mask preview change + for widget in ( + periodic_p, n_mask_codebooks, + onset_mask_width, dropout + ): + widget.change( + fn=mask_preview, + inputs=[periodic_p, n_mask_codebooks, + onset_mask_width, dropout], + outputs=[maskimg] + ) + + + _inputs = [ + input_audio, + sampletemp, + top_p, + periodic_p, + dropout, + stretch_factor, + onset_mask_width, + typical_filtering, + typical_mass, + typical_min_tokens, + seed, + model_choice, + n_mask_codebooks, + pitch_shift_amt, + sample_cutoff, + sampling_steps, + beat_mask_ms, + num_feedback_steps + ] + + # connect widgets + vamp_button.click( + fn=vamp, + inputs=_inputs, + outputs=[audio_outs[0], audio_outs[1], maskimg], + ) + + api_vamp_button = gr.Button("api vamp", visible=True) + api_vamp_button.click( + fn=api_vamp, + inputs=[input_audio, + sampletemp, top_p, + periodic_p, + dropout, + stretch_factor, + onset_mask_width, + typical_filtering, + typical_mass, + typical_min_tokens, + seed, + model_choice, + n_mask_codebooks, + pitch_shift_amt, + sample_cutoff, + sampling_steps, + beat_mask_ms, + num_feedback_steps + ], + outputs=[audio_outs[0], audio_outs[1]], + api_name="vamp" + ) + + + #NEW: HARP endpoint (new PyHARP API) + harp_model_card = ModelCard( + name="vampnet", + description="generating audio by filling in the blanks.", + author="hugo flores garcía et al. (descript/northwestern)", + tags=["sound", "generation"] + ) + + harp_input_components = [ + gr.Audio(type="filepath", label="Input Audio").harp_required(True), + gr.Slider(label="Sample Temperature", minimum=0.1, maximum=10.0, value=1.0, step=0.001), + gr.Slider(label="Periodic Prompt", minimum=0, maximum=13, step=1, value=7), + gr.Slider(label="Mask Dropout", minimum=0.0, maximum=1.0, step=0.01, value=0.0), + gr.Slider(label="Compression Prompt", value=3, minimum=1, maximum=14, step=1), + gr.Dropdown(label="Model Choice", choices=list(interface.available_models()), value=init_model_choice), + gr.Slider(label="Time Stretch Factor", minimum=0, maximum=8, step=1, value=1), + ] + + harp_output_components = [ + gr.Audio(type="filepath", label="Generated Audio"), + gr.JSON(label="Generated Labels"), + ] + + harp_app = build_endpoint( + model_card=harp_model_card, + input_components=harp_input_components, + output_components=harp_output_components, + process_fn=harp_vamp + ) + + with gr.Row(): + gr.Markdown("### VST / HARP Plugin Controls") + for comp in harp_app.values(): + comp.render() + +try: + demo.queue() + demo.launch(share=True) +except KeyboardInterrupt: + shutil.rmtree("gradio-outputs", ignore_errors=True) + raise \ No newline at end of file diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 Binary files /dev/null and b/assets/.DS_Store differ diff --git a/conf/c2f.yml b/conf/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..c41fd848e884ba6963c7ceb78fa2eb4b97e9239d --- /dev/null +++ b/conf/c2f.yml @@ -0,0 +1,14 @@ +$include: + - conf/vampnet.yml + +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 + +VampNet.embedding_dim: 1280 +VampNet.n_layers: 16 +VampNet.n_heads: 20 + +AudioDataset.duration: 3.0 + + +AudioDataset.loudness_cutoff: -40.0 diff --git a/conf/generated/cat/c2f.yml b/conf/generated/cat/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..88b558c3dea2cac9d29f916e54d4184d6d815cb0 --- /dev/null +++ b/conf/generated/cat/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/cat/c2f +train/AudioLoader.sources: &id001 +- scratch/cat-audio +val/AudioLoader.sources: *id001 diff --git a/conf/generated/cat/coarse.yml b/conf/generated/cat/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..6e86cbbf19c2ac6fe856439d5a1c5a619b19db71 --- /dev/null +++ b/conf/generated/cat/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/cat/coarse +train/AudioLoader.sources: &id001 +- scratch/cat-audio +val/AudioLoader.sources: *id001 diff --git a/conf/generated/cat/interface.yml b/conf/generated/cat/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..68703a8d6754b297bc3ba18adf626b9f6d9d7aa0 --- /dev/null +++ b/conf/generated/cat/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - scratch/cat-audio +Interface.coarse2fine_ckpt: ./runs/cat/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/cat/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/cat10/c2f.yml b/conf/generated/cat10/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..784198e4322d7d2895e4a7eb4aa3ce3565c0d4fa --- /dev/null +++ b/conf/generated/cat10/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/cat10/c2f +train/AudioLoader.sources: &id001 +- scratch/cat-audio-10s +val/AudioLoader.sources: *id001 diff --git a/conf/generated/cat10/coarse.yml b/conf/generated/cat10/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..29e99a1b23cc015dfb7b16b1b2ea45ed9042b77b --- /dev/null +++ b/conf/generated/cat10/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/cat10/coarse +train/AudioLoader.sources: &id001 +- scratch/cat-audio-10s +val/AudioLoader.sources: *id001 diff --git a/conf/generated/cat10/interface.yml b/conf/generated/cat10/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..79b884de1a36575b09720ff8bd426e234fbf30fb --- /dev/null +++ b/conf/generated/cat10/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - scratch/cat-audio-10s +Interface.coarse2fine_ckpt: ./runs/cat10/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/cat10/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/ivo/c2f.yml b/conf/generated/ivo/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..658deaf085a8a5c7f81c9390403bdf160a692899 --- /dev/null +++ b/conf/generated/ivo/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/ivo/c2f +train/AudioLoader.sources: &id001 +- ./scratch/miguel/ivo/separated +val/AudioLoader.sources: *id001 diff --git a/conf/generated/ivo/coarse.yml b/conf/generated/ivo/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..794764e8e0ca5dd63568cf90414b93a95f211662 --- /dev/null +++ b/conf/generated/ivo/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/ivo/coarse +train/AudioLoader.sources: &id001 +- ./scratch/miguel/ivo/separated +val/AudioLoader.sources: *id001 diff --git a/conf/generated/ivo/interface.yml b/conf/generated/ivo/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..022b03e3c4778f041d9e7214c175b677ac7a66d9 --- /dev/null +++ b/conf/generated/ivo/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - ./scratch/miguel/ivo/separated +Interface.coarse2fine_ckpt: ./runs/ivo/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/ivo/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/lazaro-ros-sep/c2f.yml b/conf/generated/lazaro-ros-sep/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..1978d5f521d3976a3cb38ccf797a8454969ce0ae --- /dev/null +++ b/conf/generated/lazaro-ros-sep/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/lazaro-ros-sep/c2f +train/AudioLoader.sources: &id001 +- ./scratch/miguel/lazaro-ros/separated +val/AudioLoader.sources: *id001 diff --git a/conf/generated/lazaro-ros-sep/coarse.yml b/conf/generated/lazaro-ros-sep/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..4382aab8e4f8372ebbeeac94ad16a9f1b8f100d0 --- /dev/null +++ b/conf/generated/lazaro-ros-sep/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/lazaro-ros-sep/coarse +train/AudioLoader.sources: &id001 +- ./scratch/miguel/lazaro-ros/separated +val/AudioLoader.sources: *id001 diff --git a/conf/generated/lazaro-ros-sep/interface.yml b/conf/generated/lazaro-ros-sep/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..ffa50d884f04f6e2dc9c19e9880b77662888a52f --- /dev/null +++ b/conf/generated/lazaro-ros-sep/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - ./scratch/miguel/lazaro-ros/separated +Interface.coarse2fine_ckpt: ./runs/lazaro-ros-sep/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/lazaro-ros-sep/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/lazaro-ros/c2f.yml b/conf/generated/lazaro-ros/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..7a1ad4e2bdadf2c575305a8e0ce87f0130d100ef --- /dev/null +++ b/conf/generated/lazaro-ros/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/lazaro-ros/c2f +train/AudioLoader.sources: &id001 +- ./scratch/miguel/lazaro-ros +val/AudioLoader.sources: *id001 diff --git a/conf/generated/lazaro-ros/coarse.yml b/conf/generated/lazaro-ros/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..ac6ee41442f201977bd61aedeb7d1ca5ee2c1a77 --- /dev/null +++ b/conf/generated/lazaro-ros/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/lazaro-ros/coarse +train/AudioLoader.sources: &id001 +- ./scratch/miguel/lazaro-ros +val/AudioLoader.sources: *id001 diff --git a/conf/generated/lazaro-ros/interface.yml b/conf/generated/lazaro-ros/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..ce12ea6fb73f2552b2c8a96f41b1551da7c8898d --- /dev/null +++ b/conf/generated/lazaro-ros/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - ./scratch/miguel/lazaro-ros +Interface.coarse2fine_ckpt: ./runs/lazaro-ros/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/lazaro-ros/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/le-poisson-steve/c2f.yml b/conf/generated/le-poisson-steve/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..b1a64035321fd2e0f8bac1ce47fac9ef96cab1f8 --- /dev/null +++ b/conf/generated/le-poisson-steve/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/le-poisson-steve/c2f +train/AudioLoader.sources: &id001 +- scratch/steve +val/AudioLoader.sources: *id001 diff --git a/conf/generated/le-poisson-steve/coarse.yml b/conf/generated/le-poisson-steve/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..80ac1e7707044959245ba91b977aa4ecf0903128 --- /dev/null +++ b/conf/generated/le-poisson-steve/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/le-poisson-steve/coarse +train/AudioLoader.sources: &id001 +- scratch/steve +val/AudioLoader.sources: *id001 diff --git a/conf/generated/le-poisson-steve/interface.yml b/conf/generated/le-poisson-steve/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..79f585be1ae4df6a78f27061fe1fa3758d5221e5 --- /dev/null +++ b/conf/generated/le-poisson-steve/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - scratch/steve +Interface.coarse2fine_ckpt: ./runs/le-poisson-steve/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/le-poisson-steve/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/march-31/c2f.yml b/conf/generated/march-31/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..b2da7f3ac7fbd115f7f65bf04f64a7b8d3585532 --- /dev/null +++ b/conf/generated/march-31/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/march-31/c2f +train/AudioLoader.sources: &id001 +- sound-journal-march-31 +val/AudioLoader.sources: *id001 diff --git a/conf/generated/march-31/coarse.yml b/conf/generated/march-31/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..6264f8db2ce713dcafa4c4eb3efc5715af237709 --- /dev/null +++ b/conf/generated/march-31/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/march-31/coarse +train/AudioLoader.sources: &id001 +- sound-journal-march-31 +val/AudioLoader.sources: *id001 diff --git a/conf/generated/march-31/interface.yml b/conf/generated/march-31/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..cb57ff0365858a52463f60bfa022b34934d8bef4 --- /dev/null +++ b/conf/generated/march-31/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - sound-journal-march-31 +Interface.coarse2fine_ckpt: ./runs/march-31/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/march-31/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/sax-new/c2f.yml b/conf/generated/sax-new/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..50cd305ced9888db0a0565f6b1c48c56430f5ea1 --- /dev/null +++ b/conf/generated/sax-new/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/sax-new/c2f +train/AudioLoader.sources: &id001 +- ./scratch/miguel/saxophone-new/ +val/AudioLoader.sources: *id001 diff --git a/conf/generated/sax-new/coarse.yml b/conf/generated/sax-new/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..f3cd7ab3d0e9962360c51c45d505f7400ec21642 --- /dev/null +++ b/conf/generated/sax-new/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/sax-new/coarse +train/AudioLoader.sources: &id001 +- ./scratch/miguel/saxophone-new/ +val/AudioLoader.sources: *id001 diff --git a/conf/generated/sax-new/interface.yml b/conf/generated/sax-new/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..51ec1a0ff68590071aa960daf29e6075e0cd1307 --- /dev/null +++ b/conf/generated/sax-new/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - ./scratch/miguel/saxophone-new/ +Interface.coarse2fine_ckpt: ./runs/sax-new/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/sax-new/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/generated/saxophone/c2f.yml b/conf/generated/saxophone/c2f.yml new file mode 100644 index 0000000000000000000000000000000000000000..d08109110b7359e973b07d7af458df15bb826983 --- /dev/null +++ b/conf/generated/saxophone/c2f.yml @@ -0,0 +1,15 @@ +$include: +- conf/lora/lora.yml +AudioDataset.duration: 3.0 +AudioDataset.loudness_cutoff: -40.0 +VampNet.embedding_dim: 1280 +VampNet.n_codebooks: 14 +VampNet.n_conditioning_codebooks: 4 +VampNet.n_heads: 20 +VampNet.n_layers: 16 +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/c2f.pth +save_path: ./runs/saxophone/c2f +train/AudioLoader.sources: &id001 +- scratch/sounds +val/AudioLoader.sources: *id001 diff --git a/conf/generated/saxophone/coarse.yml b/conf/generated/saxophone/coarse.yml new file mode 100644 index 0000000000000000000000000000000000000000..c9c6b5e22fa9f133218ea8d6595b7908c0a55530 --- /dev/null +++ b/conf/generated/saxophone/coarse.yml @@ -0,0 +1,8 @@ +$include: +- conf/lora/lora.yml +fine_tune: true +fine_tune_checkpoint: ./models/vampnet/coarse.pth +save_path: ./runs/saxophone/coarse +train/AudioLoader.sources: &id001 +- scratch/sounds +val/AudioLoader.sources: *id001 diff --git a/conf/generated/saxophone/interface.yml b/conf/generated/saxophone/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..02801a8ac6ec6c606e7bccb5a569e3847751e6e3 --- /dev/null +++ b/conf/generated/saxophone/interface.yml @@ -0,0 +1,6 @@ +AudioLoader.sources: +- - scratch/sounds +Interface.coarse2fine_ckpt: ./runs/saxophone/c2f/latest/vampnet/weights.pth +Interface.coarse_ckpt: ./runs/saxophone/coarse/latest/vampnet/weights.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.wavebeat_ckpt: ./models/wavebeat.pth diff --git a/conf/interface.yml b/conf/interface.yml new file mode 100644 index 0000000000000000000000000000000000000000..b574e8991218a2b9ed0822f1771cbf9d43dd1140 --- /dev/null +++ b/conf/interface.yml @@ -0,0 +1,10 @@ +Interface.coarse_ckpt: ./models/vampnet/coarse.pth +Interface.coarse2fine_ckpt: ./models/vampnet/c2f.pth +Interface.codec_ckpt: ./models/vampnet/codec.pth +Interface.coarse_chunk_size_s: 10 +Interface.coarse2fine_chunk_size_s: 3 +Interface.wavebeat_ckpt: ./models/wavebeat.pth + +# AudioLoader.sources: +# - /media/CHONK/null + diff --git a/conf/lora/lora-s2s.yml b/conf/lora/lora-s2s.yml new file mode 100644 index 0000000000000000000000000000000000000000..71e270c4e0e15e52724aa2a8eecc3715688890d9 --- /dev/null +++ b/conf/lora/lora-s2s.yml @@ -0,0 +1,27 @@ +$include: + - conf/vampnet.yml + +fine_tune: True + +train/AudioDataset.n_examples: 100000000 +val/AudioDataset.n_examples: 500 + + +NoamScheduler.warmup: 500 + +batch_size: 7 +num_workers: 7 +save_iters: [2000, 4000, 10000,20000, 40000, 100000] +sample_freq: 2000 +val_freq: 1000 + +AdamW.lr: 0.0001 + +# let's us organize sound classes into folders and choose from those sound classes uniformly +AudioDataset.without_replacement: False +num_iters: 500000 + + +# control signals to use as conditioning. +Sketch2SoundController.ctrl_keys: ['rmsq16',] + diff --git a/conf/lora/lora.yml b/conf/lora/lora.yml new file mode 100644 index 0000000000000000000000000000000000000000..36f1e2c58c8262a481e5c20081777ef7882e0204 --- /dev/null +++ b/conf/lora/lora.yml @@ -0,0 +1,22 @@ +$include: + - conf/vampnet.yml + +fine_tune: True + +train/AudioDataset.n_examples: 100000000 +val/AudioDataset.n_examples: 500 + + +NoamScheduler.warmup: 500 + +batch_size: 7 +num_workers: 7 +save_iters: [2000, 4000, 10000, 20000, 40000, 100000] +sample_freq: 2000 +val_freq: 1000 + +AdamW.lr: 0.0001 + +# let's us organize sound classes into folders and choose from those sound classes uniformly +AudioDataset.without_replacement: False +num_iters: 500000 diff --git a/conf/salad_bowl.yml b/conf/salad_bowl.yml new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/conf/vampnet.yml b/conf/vampnet.yml new file mode 100644 index 0000000000000000000000000000000000000000..7323925f800891ad3e08420bf130d327e21cebf6 --- /dev/null +++ b/conf/vampnet.yml @@ -0,0 +1,49 @@ + +codec_ckpt: ./models/vampnet/codec.pth +save_path: ckpt + +num_iters: 1000000000 +save_iters: [10000, 50000, 100000, 300000, 500000] +val_idx: [0,1,2,3,4,5,6,7,8,9] +sample_freq: 10000 +val_freq: 1000 + +batch_size: 8 +num_workers: 10 + +# Optimization +amp: false + +CrossEntropyLoss.label_smoothing: 0.1 + +AdamW.lr: 0.001 + +NoamScheduler.factor: 2.0 +NoamScheduler.warmup: 10000 + +VampNet.vocab_size: 1024 +VampNet.n_codebooks: 4 +VampNet.n_conditioning_codebooks: 0 +VampNet.r_cond_dim: 0 +VampNet.noise_mode: mask +VampNet.embedding_dim: 1280 +VampNet.n_layers: 20 +VampNet.n_heads: 20 +VampNet.flash_attn: false +VampNet.dropout: 0.1 + +AudioLoader.relative_path: "" +AudioDataset.loudness_cutoff: -30.0 +AudioDataset.without_replacement: true +AudioLoader.shuffle: true + +AudioDataset.duration: 10.0 + +train/AudioDataset.n_examples: 10000000 +train/AudioLoader.sources: + - /media/CHONK/hugo/spotdl/audio-train + +val/AudioDataset.n_examples: 2000 +val/AudioLoader.sources: + - /media/CHONK/hugo/spotdl/audio-val + diff --git a/hello.py b/hello.py new file mode 100644 index 0000000000000000000000000000000000000000..babc91a8e9513c5d3f3729f56b51b231f3455f76 --- /dev/null +++ b/hello.py @@ -0,0 +1,48 @@ +import random +import vampnet +import audiotools as at + +# load the default vampnet model +interface = vampnet.interface.Interface.default() + +# list available finetuned models +finetuned_model_choices = interface.available_models() +print(f"available finetuned models: {finetuned_model_choices}") + +# pick a random finetuned model +model_choice = random.choice(finetuned_model_choices) +print(f"choosing model: {model_choice}") + +# or pick a specific finetuned model +print(f"actually, forcing model: default") +model_choice = "default" + +# load a finetuned model +interface.load_finetuned(model_choice) + +# load an example audio file +signal = at.AudioSignal("assets/example.wav") + +# get the tokens for the audio +codes = interface.encode(signal) + +# build a mask for the audio +mask = interface.build_mask( + codes, signal, + periodic_prompt=13, + upper_codebook_mask=3, +) + +# generate the output tokens +output_tokens = interface.vamp( + codes, mask, return_mask=False, + temperature=1.0, + typical_filtering=False, + debug=True +) + +# convert them to a signal +output_signal = interface.decode(output_tokens) + +# save the output signal +output_signal.write("scratch/output.wav") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..6794e4e5de21beb5665fd0236c20822191b1dd88 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +torch +argbind>=0.3.2 +numpy==1.23 +loralib +wavebeat @ git+https://github.com/hugofloresgarcia/wavebeat +lac @ git+https://github.com/hugofloresgarcia/lac.git +descript-audiotools @ git+https://github.com/hugofloresgarcia/audiotools.git +-e git+https://github.com/audacitorch/pyharp.git@develop#egg=pyharp +torch_pitch_shift +gradio +pydantic==2.10.6 \ No newline at end of file diff --git a/scratch/convert_to_wav.sh b/scratch/convert_to_wav.sh new file mode 100644 index 0000000000000000000000000000000000000000..da569248b968bf3b3d0f24136b278edb6dffefd6 --- /dev/null +++ b/scratch/convert_to_wav.sh @@ -0,0 +1 @@ +for f in *.mp3; do ffmpeg -i "$f" "${f%.mp3}.wav"; done \ No newline at end of file diff --git a/scratch/rms_mask.txt b/scratch/rms_mask.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce4e83223ec8af332729ebb0256f033fe50af6e0 --- /dev/null +++ b/scratch/rms_mask.txt @@ -0,0 +1,14 @@ +0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 +0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 +0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 diff --git a/scratch/separate_folder.sh b/scratch/separate_folder.sh new file mode 100644 index 0000000000000000000000000000000000000000..75c32153cd5ed02b351e205e243d223a1f9e2f90 --- /dev/null +++ b/scratch/separate_folder.sh @@ -0,0 +1 @@ +for f in *.mp3; do demucs "$f" --two-stems=vocals; done diff --git a/scripts/exp/eval.py b/scripts/exp/eval.py new file mode 100644 index 0000000000000000000000000000000000000000..47b4cf4ee1a2dcb72bd6fb9797f22d85c2c7dac9 --- /dev/null +++ b/scripts/exp/eval.py @@ -0,0 +1,110 @@ +from pathlib import Path +import os +from functools import partial + +from frechet_audio_distance import FrechetAudioDistance +import pandas +import argbind +import torch +from tqdm import tqdm + +import audiotools +from audiotools import AudioSignal + +@argbind.bind(without_prefix=True) +def eval( + exp_dir: str = None, + baseline_key: str = "baseline", + audio_ext: str = ".wav", +): + assert exp_dir is not None + exp_dir = Path(exp_dir) + assert exp_dir.exists(), f"exp_dir {exp_dir} does not exist" + + # set up our metrics + # sisdr_loss = audiotools.metrics.distance.SISDRLoss() + # stft_loss = audiotools.metrics.spectral.MultiScaleSTFTLoss() + mel_loss = audiotools.metrics.spectral.MelSpectrogramLoss() + frechet = FrechetAudioDistance( + use_pca=False, + use_activation=False, + verbose=True, + audio_load_worker=4, + ) + frechet.model.to("cuda" if torch.cuda.is_available() else "cpu") + + # figure out what conditions we have + conditions = [d.name for d in exp_dir.iterdir() if d.is_dir()] + + assert baseline_key in conditions, f"baseline_key {baseline_key} not found in {exp_dir}" + conditions.remove(baseline_key) + + print(f"Found {len(conditions)} conditions in {exp_dir}") + print(f"conditions: {conditions}") + + baseline_dir = exp_dir / baseline_key + baseline_files = sorted(list(baseline_dir.glob(f"*{audio_ext}")), key=lambda x: int(x.stem)) + + metrics = [] + for condition in tqdm(conditions): + cond_dir = exp_dir / condition + cond_files = sorted(list(cond_dir.glob(f"*{audio_ext}")), key=lambda x: int(x.stem)) + + print(f"computing fad for {baseline_dir} and {cond_dir}") + frechet_score = frechet.score(baseline_dir, cond_dir) + + # make sure we have the same number of files + num_files = min(len(baseline_files), len(cond_files)) + baseline_files = baseline_files[:num_files] + cond_files = cond_files[:num_files] + assert len(list(baseline_files)) == len(list(cond_files)), f"number of files in {baseline_dir} and {cond_dir} do not match. {len(list(baseline_files))} vs {len(list(cond_files))}" + + def process(baseline_file, cond_file): + # make sure the files match (same name) + assert baseline_file.stem == cond_file.stem, f"baseline file {baseline_file} and cond file {cond_file} do not match" + + # load the files + baseline_sig = AudioSignal(str(baseline_file)) + cond_sig = AudioSignal(str(cond_file)) + + cond_sig.resample(baseline_sig.sample_rate) + cond_sig.truncate_samples(baseline_sig.length) + + # if our condition is inpainting, we need to trim the conditioning off + if "inpaint" in condition: + ctx_amt = float(condition.split("_")[-1]) + ctx_samples = int(ctx_amt * baseline_sig.sample_rate) + print(f"found inpainting condition. trimming off {ctx_samples} samples from {cond_file} and {baseline_file}") + cond_sig.trim(ctx_samples, ctx_samples) + baseline_sig.trim(ctx_samples, ctx_samples) + + return { + # "sisdr": -sisdr_loss(baseline_sig, cond_sig).item(), + # "stft": stft_loss(baseline_sig, cond_sig).item(), + "mel": mel_loss(baseline_sig, cond_sig).item(), + "frechet": frechet_score, + # "visqol": vsq, + "condition": condition, + "file": baseline_file.stem, + } + + print(f"processing {len(baseline_files)} files in {baseline_dir} and {cond_dir}") + metrics.extend(tqdm(map(process, baseline_files, cond_files), total=len(baseline_files))) + + metric_keys = [k for k in metrics[0].keys() if k not in ("condition", "file")] + + + for mk in metric_keys: + stat = pandas.DataFrame(metrics) + stat = stat.groupby(['condition'])[mk].agg(['mean', 'count', 'std']) + stat.to_csv(exp_dir / f"stats-{mk}.csv") + + df = pandas.DataFrame(metrics) + df.to_csv(exp_dir / "metrics-all.csv", index=False) + + +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + eval() \ No newline at end of file diff --git a/scripts/exp/experiment.py b/scripts/exp/experiment.py new file mode 100644 index 0000000000000000000000000000000000000000..0b677137afea10c8151ecfe347db0d22bd152540 --- /dev/null +++ b/scripts/exp/experiment.py @@ -0,0 +1,254 @@ +from pathlib import Path +import random +from typing import List +import tempfile +import subprocess + +import argbind +from tqdm import tqdm +import torch + +from vampnet.interface import Interface +from vampnet import mask as pmask +import audiotools as at + +Interface: Interface = argbind.bind(Interface) + + + +def calculate_bitrate( + interface, num_codebooks, + downsample_factor + ): + bit_width = 10 + sr = interface.codec.sample_rate + hop = interface.codec.hop_size + rate = (sr / hop) * ((bit_width * num_codebooks) / downsample_factor) + return rate + +def baseline(sig, interface): + return interface.preprocess(sig) + +def reconstructed(sig, interface): + return interface.decode( + interface.encode(sig) + ) + +def coarse2fine(sig, interface): + z = interface.encode(sig) + z = z[:, :interface.c2f.n_conditioning_codebooks, :] + + z = interface.coarse_to_fine(z) + return interface.decode(z) + +class CoarseCond: + + def __init__(self, num_conditioning_codebooks, downsample_factor): + self.num_conditioning_codebooks = num_conditioning_codebooks + self.downsample_factor = downsample_factor + + def __call__(self, sig, interface): + z = interface.encode(sig) + mask = pmask.full_mask(z) + mask = pmask.codebook_unmask(mask, self.num_conditioning_codebooks) + mask = pmask.periodic_mask(mask, self.downsample_factor) + + zv = interface.coarse_vamp(z, mask) + zv = interface.coarse_to_fine(zv) + return interface.decode(zv) + +def opus(sig, interface, bitrate=128): + sig = interface.preprocess(sig) + + with tempfile.NamedTemporaryFile(suffix=".wav") as f: + sig.write(f.name) + + opus_name = Path(f.name).with_suffix(".opus") + # convert to opus + cmd = [ + "ffmpeg", "-y", "-i", f.name, + "-c:a", "libopus", + "-b:a", f"{bitrate}", + opus_name + ] + subprocess.run(cmd, check=True) + + # convert back to wav + output_name = Path(f"{f.name}-opus").with_suffix(".wav") + cmd = [ + "ffmpeg", "-y", "-i", opus_name, + output_name + ] + + subprocess.run(cmd, check=True) + + sig = at.AudioSignal( + output_name, + sample_rate=sig.sample_rate + ) + return sig + +def mask_ratio_1_step(ratio=1.0): + def wrapper(sig, interface): + z = interface.encode(sig) + mask = pmask.linear_random(z, ratio) + zv = interface.coarse_vamp( + z, + mask, + sampling_steps=1, + ) + + return interface.decode(zv) + return wrapper + +def num_sampling_steps(num_steps=1): + def wrapper(sig, interface: Interface): + z = interface.encode(sig) + mask = pmask.periodic_mask(z, 16) + zv = interface.coarse_vamp( + z, + mask, + sampling_steps=num_steps, + ) + + zv = interface.coarse_to_fine(zv) + return interface.decode(zv) + return wrapper + +def beat_mask(ctx_time): + def wrapper(sig, interface): + beat_mask = interface.make_beat_mask( + sig, + before_beat_s=ctx_time/2, + after_beat_s=ctx_time/2, + invert=True + ) + + z = interface.encode(sig) + + zv = interface.coarse_vamp( + z, beat_mask + ) + + zv = interface.coarse_to_fine(zv) + return interface.decode(zv) + return wrapper + +def inpaint(ctx_time): + def wrapper(sig, interface: Interface): + z = interface.encode(sig) + mask = pmask.inpaint(z, interface.s2t(ctx_time), interface.s2t(ctx_time)) + + zv = interface.coarse_vamp(z, mask) + zv = interface.coarse_to_fine(zv) + + return interface.decode(zv) + return wrapper + +def token_noise(noise_amt): + def wrapper(sig, interface: Interface): + z = interface.encode(sig) + mask = pmask.random(z, noise_amt) + z = torch.where( + mask, + torch.randint_like(z, 0, interface.coarse.vocab_size), + z + ) + return interface.decode(z) + return wrapper + +EXP_REGISTRY = {} + +EXP_REGISTRY["gen-compression"] = { + "baseline": baseline, + "reconstructed": reconstructed, + "coarse2fine": coarse2fine, + **{ + f"{n}_codebooks_downsampled_{x}x": CoarseCond(num_conditioning_codebooks=n, downsample_factor=x) + for (n, x) in ( + (1, 1), # 1 codebook, no downsampling + (4, 4), # 4 codebooks, downsampled 4x + (4, 16), # 4 codebooks, downsampled 16x + (4, 32), # 4 codebooks, downsampled 16x + ) + }, + **{ + f"token_noise_{x}": mask_ratio_1_step(ratio=x) + for x in [0.25, 0.5, 0.75] + }, + +} + + +EXP_REGISTRY["sampling-steps"] = { + # "codec": reconstructed, + **{f"steps_{n}": num_sampling_steps(n) for n in [1, 4, 12, 36, 64, 72]}, +} + + +EXP_REGISTRY["musical-sampling"] = { + **{f"beat_mask_{t}": beat_mask(t) for t in [0.075]}, + **{f"inpaint_{t}": inpaint(t) for t in [0.5, 1.0,]}, # multiply these by 2 (they go left and right) +} + +@argbind.bind(without_prefix=True) +def main( + sources=[ + "/media/CHONK/hugo/spotdl/val", + ], + output_dir: str = "./samples", + max_excerpts: int = 2000, + exp_type: str = "gen-compression", + seed: int = 0, + ext: str = [".mp3"], + ): + at.util.seed(seed) + interface = Interface() + + output_dir = Path(output_dir) + output_dir.mkdir(exist_ok=True, parents=True) + + from audiotools.data.datasets import AudioLoader, AudioDataset + + loader = AudioLoader(sources=sources, shuffle_state=seed, ext=ext) + dataset = AudioDataset(loader, + sample_rate=interface.codec.sample_rate, + duration=interface.coarse.chunk_size_s, + n_examples=max_excerpts, + without_replacement=True, + ) + + if exp_type in EXP_REGISTRY: + SAMPLE_CONDS = EXP_REGISTRY[exp_type] + else: + raise ValueError(f"Unknown exp_type {exp_type}") + + + indices = list(range(max_excerpts)) + random.shuffle(indices) + for i in tqdm(indices): + # if all our files are already there, skip + done = [] + for name in SAMPLE_CONDS: + o_dir = Path(output_dir) / name + done.append((o_dir / f"{i}.wav").exists()) + if all(done): + continue + + sig = dataset[i]["signal"] + results = { + name: cond(sig, interface).cpu() + for name, cond in SAMPLE_CONDS.items() + } + + for name, sig in results.items(): + o_dir = Path(output_dir) / name + o_dir.mkdir(exist_ok=True, parents=True) + + sig.write(o_dir / f"{i}.wav") + +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + main() diff --git a/scripts/exp/export.py b/scripts/exp/export.py new file mode 100644 index 0000000000000000000000000000000000000000..920e9767a15fce5d7c25b7c84f2f61859579fd9a --- /dev/null +++ b/scripts/exp/export.py @@ -0,0 +1,75 @@ +from pathlib import Path + +import shutil +import argparse +from vampnet import DEFAULT_HF_MODEL_REPO +from huggingface_hub import create_repo, repo_exists, HfApi + + + +parser = argparse.ArgumentParser(description="Export the fine-tuned model to the repo") +parser.add_argument( + "--name", type=str, default="lazaro-ros-sep", + help="name of the fine-tuned model to export" +) +parser.add_argument( + "--model", type=str, default="latest", + help="model version to export. check runs/ for available versions" +) +parser.add_argument( + "--repo", type=str, default=DEFAULT_HF_MODEL_REPO, + help="name of the repo to export to" +) + +args = parser.parse_args() +name = args.name +version = args.model + +## +print(f"~~~~~~~~~~~ vampnet export! ~~~~~~~~~~~~") +print(f"exporting {name} version {version} to {args.repo}\n") + +run_dir = Path(f"runs/{name}") +repo_dir = Path("models/vampnet") + +# create our repo +new_repo = False +if not repo_exists(args.repo): + print(f"repo {args.repo} does not exist, creating it") + print(f"creating a repo at {args.repo}") + create_repo(args.repo) + new_repo = True + +paths = [] +for part in ("coarse", "c2f"): + outdir = repo_dir / "loras" / name + outdir.mkdir(parents=True, exist_ok=True) + outpath = outdir / f"{part}.pth" + path = run_dir / part / version / "vampnet" / "weights.pth" + # path.rename(outpath) + shutil.copy(path, outpath) + paths.append(outpath) + print(f"copied {path} to {outpath}") + +print(f"uploading files to {args.repo}") +# upload files to the repo + +# if it's a new repo, let's add the default models too +if new_repo: + paths.extend([repo_dir / "c2f.pth", repo_dir / "coarse.pth", repo_dir / "codec.pth", repo_dir / "wavebeat.pth"]) + +api = HfApi() + +for path in paths: + path_in_repo = str(path.relative_to(repo_dir)) + print(f"uploading {path} to {args.repo}/{path_in_repo}") + api.upload_file( + path_or_fileobj=path, + path_in_repo=path_in_repo, + repo_id=args.repo, + token=True, + commit_message=f"uploading {path_in_repo}", + ) + + +print("done!!! >::0") \ No newline at end of file diff --git a/scripts/exp/fine_tune.py b/scripts/exp/fine_tune.py new file mode 100644 index 0000000000000000000000000000000000000000..70d83ec89d01f9716d4f496bb834b82d138b9527 --- /dev/null +++ b/scripts/exp/fine_tune.py @@ -0,0 +1,87 @@ +import argbind +from pathlib import Path +import yaml +from typing import List + + + + +"""example output: (yaml) + +""" + +@argbind.bind(without_prefix=True, positional=True) +def fine_tune(audio_files_or_folders: List[str], name: str): + + conf_dir = Path("conf") + assert conf_dir.exists(), "conf directory not found. are you in the vampnet directory?" + + conf_dir = conf_dir / "generated" + conf_dir.mkdir(exist_ok=True) + + finetune_dir = conf_dir / name + finetune_dir.mkdir(exist_ok=True) + + finetune_c2f_conf = { + "$include": ["conf/lora/lora.yml"], + "fine_tune": True, + "train/AudioLoader.sources": audio_files_or_folders, + "val/AudioLoader.sources": audio_files_or_folders, + "VampNet.n_codebooks": 14, + "VampNet.n_conditioning_codebooks": 4, + "VampNet.embedding_dim": 1280, + "VampNet.n_layers": 16, + "VampNet.n_heads": 20, + "AudioDataset.duration": 3.0, + "AudioDataset.loudness_cutoff": -40.0, + "save_path": f"./runs/{name}/c2f", + "fine_tune_checkpoint": "./models/vampnet/c2f.pth" + } + + finetune_coarse_conf = { + "$include": ["conf/lora/lora.yml"], + "fine_tune": True, + "train/AudioLoader.sources": audio_files_or_folders, + "val/AudioLoader.sources": audio_files_or_folders, + "save_path": f"./runs/{name}/coarse", + "fine_tune_checkpoint": "./models/vampnet/coarse.pth" + } + + interface_conf = { + "Interface.coarse_ckpt": f"./runs/{name}/coarse/latest/vampnet/weights.pth", + + "Interface.coarse2fine_ckpt": f"./runs/{name}/c2f/latest/vampnet/weights.pth", + "Interface.wavebeat_ckpt": "./models/wavebeat.pth", + + "Interface.codec_ckpt": "./models/vampnet/codec.pth", + "AudioLoader.sources": [audio_files_or_folders], + } + + # save the confs + with open(finetune_dir / "c2f.yml", "w") as f: + yaml.dump(finetune_c2f_conf, f) + + with open(finetune_dir / "coarse.yml", "w") as f: + yaml.dump(finetune_coarse_conf, f) + + with open(finetune_dir / "interface.yml", "w") as f: + yaml.dump(interface_conf, f) + + + # print(f"generated confs in {finetune_dir}. + # run training jobs with `python scripts/exp/train.py --args.load {finetune_dir}/.yml` ") + + print(f"generated confs in {finetune_dir}.") + print() + print(f"you'll need to run two training jobs, though they can run in parallel on separate GPUs.") + print(f"run the coarse job with \n\tpython scripts/exp/train.py --args.load {finetune_dir}/coarse.yml\n") + print(f"run the c2f job with \n\tpython scripts/exp/train.py --args.load {finetune_dir}/c2f.yml\n") +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + fine_tune() + + + + \ No newline at end of file diff --git a/scripts/exp/train.py b/scripts/exp/train.py new file mode 100644 index 0000000000000000000000000000000000000000..6a3d5134ebd04429f2d74957a4ba83acb8f3adab --- /dev/null +++ b/scripts/exp/train.py @@ -0,0 +1,746 @@ +import os +import sys +import warnings +from pathlib import Path +from typing import Optional +from dataclasses import dataclass + +import argbind +import audiotools as at +import torch +import torch.nn as nn +from audiotools import AudioSignal +from audiotools.data import transforms as tfm +from einops import rearrange +from rich import pretty +from rich.traceback import install +from torch.utils.tensorboard import SummaryWriter + +import vampnet +from vampnet.modules.transformer import VampNet +# from vampnet.control import Sketch2SoundController +from vampnet.util import codebook_unflatten, codebook_flatten +from vampnet import mask as pmask +# from dac.model.dac import DAC +from lac.model.lac import LAC as DAC + +from audiotools.ml.decorators import ( + timer, Tracker, when +) + +import loralib as lora + +import torch._dynamo +torch._dynamo.config.verbose=True + + +# Enable cudnn autotuner to speed up training +# (can be altered by the funcs.seed function) +torch.backends.cudnn.benchmark = bool(int(os.getenv("CUDNN_BENCHMARK", 1))) +# Uncomment to trade memory for speed. + +# Install to make things look nice +warnings.filterwarnings("ignore", category=UserWarning) +pretty.install() +install() + +# optim +Accelerator = argbind.bind(at.ml.Accelerator, without_prefix=True) +CrossEntropyLoss = argbind.bind(nn.CrossEntropyLoss) +AdamW = argbind.bind(torch.optim.AdamW) +NoamScheduler = argbind.bind(vampnet.scheduler.NoamScheduler) + +# transforms +filter_fn = lambda fn: hasattr(fn, "transform") and fn.__qualname__ not in [ + "BaseTransform", + "Compose", + "Choose", +] + +# model +VampNet = argbind.bind(VampNet) + + +# data +AudioLoader = argbind.bind(at.datasets.AudioLoader) +AudioDataset = argbind.bind(at.datasets.AudioDataset, "train", "val") + +IGNORE_INDEX = -100 + +# Sketch2SoundController = argbind.bind(Sketch2SoundController) + + +@argbind.bind("train", "val", without_prefix=True) +def build_transform(): + transform = tfm.Compose( + tfm.VolumeNorm(("const", -24)), + # tfm.PitchShift(), + tfm.RescaleAudio(), + ) + return transform + + +@torch.no_grad() +def apply_transform(transform_fn, batch): + sig: AudioSignal = batch["signal"] + kwargs = batch["transform_args"] + + sig: AudioSignal = transform_fn(sig.clone(), **kwargs) + return sig + + +def build_datasets(args, sample_rate: int): + with argbind.scope(args, "train"): + train_data = AudioDataset( + AudioLoader(), sample_rate, transform=build_transform() + ) + with argbind.scope(args, "val"): + val_data = AudioDataset(AudioLoader(), sample_rate, transform=build_transform()) + return train_data, val_data + + +def rand_float(shape, low, high, rng): + return rng.draw(shape)[:, 0] * (high - low) + low + + +def flip_coin(shape, p, rng): + return rng.draw(shape)[:, 0] < p + + +def num_params_hook(o, p): + return o + f" {p/1e6:<.3f}M params." + + +def add_num_params_repr_hook(model): + import numpy as np + from functools import partial + + for n, m in model.named_modules(): + o = m.extra_repr() + p = sum([np.prod(p.size()) for p in m.parameters()]) + + setattr(m, "extra_repr", partial(num_params_hook, o=o, p=p)) + +def get_controls(state, sig: at.AudioSignal): + # get controls + n_batch = sig.samples.shape[0] + if state.controller is not None: + ctrls = state.controller.extract(sig) + # draw control masks + ctrl_masks = state.controller.random_mask( + ctrls, + r=state.rng.draw(n_batch)[:, 0].to(state.device) + ) + else: + ctrls = None + ctrl_masks = None + + return ctrls, ctrl_masks + + +def generate_z_mask(state, z, vn, n_batch, ctrl_masks=None): + r = state.rng.draw(n_batch)[:, 0].to(state.device) + + mask, ii = state.model.random_mask(z, r) + mask = pmask.codebook_unmask(mask, vn.n_conditioning_codebooks) + + # outpaint? + # if state.outpaint_prob > 0: + # if flip_coin(state.outpaint_prob): + # mask, ctrl_masks = state.build_tria_mask(mask, ctrl_masks) + z_mask = pmask.apply_mask(z, mask, vn.mask_token) + + return z_mask, mask, ii, r, ctrl_masks + +def accuracy( + preds: torch.Tensor, + target: torch.Tensor, + top_k: int = 1, + ignore_index: Optional[int] = None, +) -> torch.Tensor: + # Flatten the predictions and targets to be of shape (batch_size * sequence_length, n_class) + preds = rearrange(preds, "b p s -> (b s) p") + target = rearrange(target, "b s -> (b s)") + + # return torchmetrics.functional.accuracy(preds, target, task='multiclass', top_k=topk, num_classes=preds.shape[-1], ignore_index=ignore_index) + if ignore_index is not None: + # Create a mask for the ignored index + mask = target != ignore_index + # Apply the mask to the target and predictions + preds = preds[mask] + target = target[mask] + + # Get the top-k predicted classes and their indices + _, pred_indices = torch.topk(preds, k=top_k, dim=-1) + + # Determine if the true target is in the top-k predicted classes + correct = torch.sum(torch.eq(pred_indices, target.unsqueeze(1)), dim=1) + + # Calculate the accuracy + accuracy = torch.mean(correct.float()) + + return accuracy + +def _metrics(z_hat, r, target, flat_mask, output): + for r_range in [(0, 0.5), (0.5, 1.0)]: + unmasked_target = target.masked_fill(flat_mask.bool(), IGNORE_INDEX) + masked_target = target.masked_fill(~flat_mask.bool(), IGNORE_INDEX) + + assert target.shape[0] == r.shape[0] + # grab the indices of the r values that are in the range + r_idx = (r >= r_range[0]) & (r < r_range[1]) + + # grab the target and z_hat values that are in the range + r_unmasked_target = unmasked_target[r_idx] + r_masked_target = masked_target[r_idx] + r_z_hat = z_hat[r_idx] + + for topk in (1, 25): + s, e = r_range + tag = f"accuracy-{s}-{e}/top{topk}" + + output[f"{tag}/unmasked"] = accuracy( + preds=r_z_hat, + target=r_unmasked_target, + ignore_index=IGNORE_INDEX, + top_k=topk, + ) + output[f"{tag}/masked"] = accuracy( + preds=r_z_hat, + target=r_masked_target, + ignore_index=IGNORE_INDEX, + top_k=topk, + ) + + +@dataclass +class State: + model: VampNet + codec: DAC + # controller: Sketch2SoundController + controller: Optional[object] + + optimizer: AdamW + scheduler: NoamScheduler + criterion: CrossEntropyLoss + grad_clip_val: float + + rng: torch.quasirandom.SobolEngine + + train_data: AudioDataset + val_data: AudioDataset + + tracker: Tracker + + +@timer() +def train_loop(state: State, batch: dict, accel: Accelerator): + state.model.train() + batch = at.util.prepare_batch(batch, accel.device) + signal = apply_transform(state.train_data.transform, batch) + + output = {} + vn = accel.unwrap(state.model) + with accel.autocast(): + with torch.inference_mode(): + state.codec.to(accel.device) + z = state.codec.encode(signal.samples, signal.sample_rate)["codes"] + z = z[:, : vn.n_codebooks, :] + + n_batch = z.shape[0] + r = state.rng.draw(n_batch)[:, 0].to(accel.device) + + mask = pmask.random(z, r) + mask = pmask.codebook_unmask(mask, vn.n_conditioning_codebooks) + z_mask, mask = pmask.apply_mask(z, mask, vn.mask_token) + + # get controls + ctrls, ctrl_masks = get_controls(state, signal) + + # TODO: KEEP INCORPORATING ZMASK CODE + + z_mask_latent = vn.embedding.from_codes(z_mask, state.codec) + + dtype = torch.bfloat16 if accel.amp else None + with accel.autocast(dtype=dtype): + z_hat = state.model(z_mask_latent) + + target = codebook_flatten( + z[:, vn.n_conditioning_codebooks :, :], + ) + + flat_mask = codebook_flatten( + mask[:, vn.n_conditioning_codebooks :, :], + ) + + # replace target with ignore index for masked tokens + t_masked = target.masked_fill(~flat_mask.bool(), IGNORE_INDEX) + output["loss"] = state.criterion(z_hat, t_masked) + + _metrics( + r=r, + z_hat=z_hat, + target=target, + flat_mask=flat_mask, + output=output, + ) + + + accel.backward(output["loss"]) + + output["other/learning_rate"] = state.optimizer.param_groups[0]["lr"] + output["other/batch_size"] = z.shape[0] + + + accel.scaler.unscale_(state.optimizer) + output["other/grad_norm"] = torch.nn.utils.clip_grad_norm_( + state.model.parameters(), state.grad_clip_val + ) + + accel.step(state.optimizer) + state.optimizer.zero_grad() + + state.scheduler.step() + accel.update() + + + return {k: v for k, v in sorted(output.items())} + +# def get_controls(self, sig: sn.Signal, controller): +# # get controls +# n_batch = sig.wav.shape[0] +# if self.controller is not None: +# ctrls = self.controller.extract(sig) +# # draw control masks +# ctrl_masks = self.controller.random_mask( +# ctrls, +# r=self.rng.draw(n_batch)[:, 0].to(self.device) +# ) +# else: +# ctrls = None +# ctrl_masks = None + +# return ctrls, ctrl_masks + + +@timer() +@torch.no_grad() +def val_loop(state: State, batch: dict, accel: Accelerator): + state.model.eval() + state.codec.eval() + batch = at.util.prepare_batch(batch, accel.device) + signal = apply_transform(state.val_data.transform, batch) + + vn = accel.unwrap(state.model) + z = state.codec.encode(signal.samples, signal.sample_rate)["codes"] + z = z[:, : vn.n_codebooks, :] + + n_batch = z.shape[0] + r = state.rng.draw(n_batch)[:, 0].to(accel.device) + + mask = pmask.random(z, r) + mask = pmask.codebook_unmask(mask, vn.n_conditioning_codebooks) + z_mask, mask = pmask.apply_mask(z, mask, vn.mask_token) + + z_mask_latent = vn.embedding.from_codes(z_mask, state.codec) + + z_hat = state.model(z_mask_latent) + + target = codebook_flatten( + z[:, vn.n_conditioning_codebooks :, :], + ) + + flat_mask = codebook_flatten( + mask[:, vn.n_conditioning_codebooks :, :] + ) + + output = {} + # replace target with ignore index for masked tokens + t_masked = target.masked_fill(~flat_mask.bool(), IGNORE_INDEX) + output["loss"] = state.criterion(z_hat, t_masked) + + _metrics( + r=r, + z_hat=z_hat, + target=target, + flat_mask=flat_mask, + output=output, + ) + + return output + + +def validate(state, val_dataloader, accel): + for batch in val_dataloader: + output = val_loop(state, batch, accel) + # Consolidate state dicts if using ZeroRedundancyOptimizer + if hasattr(state.optimizer, "consolidate_state_dict"): + state.optimizer.consolidate_state_dict() + return output + + +def checkpoint(state, save_iters, save_path, fine_tune): + if accel.local_rank != 0: + state.tracker.print(f"ERROR:Skipping checkpoint on rank {accel.local_rank}") + return + + metadata = {"logs": dict(state.tracker.history)} + + tags = ["latest"] + state.tracker.print(f"Saving to {str(Path('.').absolute())}") + + if state.tracker.step in save_iters: + tags.append(f"{state.tracker.step // 1000}k") + + if state.tracker.is_best("val", "loss"): + state.tracker.print(f"Best model so far") + tags.append("best") + + if fine_tune: + for tag in tags: + # save the lora model + (Path(save_path) / tag).mkdir(parents=True, exist_ok=True) + torch.save( + lora.lora_state_dict(accel.unwrap(state.model)), + f"{save_path}/{tag}/lora.pth" + ) + + for tag in tags: + model_extra = { + "optimizer.pth": state.optimizer.state_dict(), + "scheduler.pth": state.scheduler.state_dict(), + "tracker.pth": state.tracker.state_dict(), + "metadata.pth": metadata, + } + + accel.unwrap(state.model).metadata = metadata + accel.unwrap(state.model).save_to_folder( + f"{save_path}/{tag}", model_extra, package=False + ) + + +def save_sampled(state, z, writer): + num_samples = z.shape[0] + + for i in range(num_samples): + sampled = accel.unwrap(state.model).generate( + codec=state.codec, + time_steps=z.shape[-1], + start_tokens=z[i : i + 1], + ) + sampled.cpu().write_audio_to_tb( + f"sampled/{i}", + writer, + step=state.tracker.step, + plot_fn=None, + ) + + +def save_imputation(state, z, val_idx, writer): + n_prefix = int(z.shape[-1] * 0.25) + n_suffix = int(z.shape[-1] * 0.25) + + vn = accel.unwrap(state.model) + + mask = pmask.inpaint(z, n_prefix, n_suffix) + mask = pmask.codebook_unmask(mask, vn.n_conditioning_codebooks) + z_mask, mask = pmask.apply_mask(z, mask, vn.mask_token) + + imputed_noisy = vn.decode(z_mask, state.codec) + imputed_true = vn.decode(z, state.codec) + + imputed = [] + for i in range(len(z)): + imputed.append( + vn.generate( + codec=state.codec, + time_steps=z.shape[-1], + start_tokens=z[i][None, ...], + mask=mask[i][None, ...], + ) + ) + imputed = AudioSignal.batch(imputed) + + for i in range(len(val_idx)): + imputed_noisy[i].cpu().write_audio_to_tb( + f"inpainted_prompt/{i}", + writer, + step=state.tracker.step, + plot_fn=None, + ) + imputed[i].cpu().write_audio_to_tb( + f"inpainted_middle/{i}", + writer, + step=state.tracker.step, + plot_fn=None, + ) + imputed_true[i].cpu().write_audio_to_tb( + f"reconstructed/{i}", + writer, + step=state.tracker.step, + plot_fn=None, + ) + + +@torch.no_grad() +def save_samples(state: State, val_idx: int, writer: SummaryWriter): + state.model.eval() + state.codec.eval() + vn = accel.unwrap(state.model) + + batch = [state.val_data[i] for i in val_idx] + batch = at.util.prepare_batch(state.val_data.collate(batch), accel.device) + + signal = apply_transform(state.val_data.transform, batch) + + z = state.codec.encode(signal.samples, signal.sample_rate)["codes"] + z = z[:, : vn.n_codebooks, :] + + r = torch.linspace(0.1, 0.95, len(val_idx)).to(accel.device) + + + mask = pmask.random(z, r) + mask = pmask.codebook_unmask(mask, vn.n_conditioning_codebooks) + z_mask, mask = pmask.apply_mask(z, mask, vn.mask_token) + + z_mask_latent = vn.embedding.from_codes(z_mask, state.codec) + + z_hat = state.model(z_mask_latent) + + z_pred = torch.softmax(z_hat, dim=1).argmax(dim=1) + z_pred = codebook_unflatten(z_pred, n_c=vn.n_predict_codebooks) + z_pred = torch.cat([z[:, : vn.n_conditioning_codebooks, :], z_pred], dim=1) + + generated = vn.decode(z_pred, state.codec) + reconstructed = vn.decode(z, state.codec) + masked = vn.decode(z_mask.squeeze(1), state.codec) + + for i in range(generated.batch_size): + audio_dict = { + "original": signal[i], + "masked": masked[i], + "generated": generated[i], + "reconstructed": reconstructed[i], + } + for k, v in audio_dict.items(): + v.cpu().write_audio_to_tb( + f"onestep/_{i}.r={r[i]:0.2f}/{k}", + writer, + step=state.tracker.step, + plot_fn=None, + ) + + save_sampled(state=state, z=z, writer=writer) + save_imputation(state=state, z=z, val_idx=val_idx, writer=writer) + + + +@argbind.bind(without_prefix=True) +def load( + args, + accel: at.ml.Accelerator, + tracker: Tracker, + save_path: str, + resume: bool = False, + tag: str = "latest", + fine_tune_checkpoint: Optional[str] = None, + grad_clip_val: float = 5.0, +) -> State: + codec = DAC.load(args["codec_ckpt"], map_location="cpu") + codec.eval() + + model, v_extra = None, {} + + if args["fine_tune"]: + assert fine_tune_checkpoint is not None, "Must provide a fine-tune checkpoint" + model = torch.compile( + VampNet.load(location=Path(fine_tune_checkpoint), + map_location="cpu", + ) + ) + + if resume: + kwargs = { + "folder": f"{save_path}/{tag}", + "map_location": "cpu", + "package": False, + } + tracker.print(f"Loading checkpoint from {kwargs['folder']}") + if (Path(kwargs["folder"]) / "vampnet").exists(): + model, v_extra = VampNet.load_from_folder(**kwargs) + else: + raise ValueError( + f"Could not find a VampNet checkpoint in {kwargs['folder']}" + ) + + + + + model = torch.compile(VampNet()) if model is None else model + model = accel.prepare_model(model) + + # assert accel.unwrap(model).n_codebooks == codec.quantizer.n_codebooks + assert ( + accel.unwrap(model).vocab_size == codec.quantizer.quantizers[0].codebook_size + ) + + + if accel.world_size > 1: + from torch.distributed.optim import ZeroRedundancyOptimizer + optimizer = ZeroRedundancyOptimizer(model.parameters(), AdamW) + print(f"OPTIMIZER LR is {optimizer.param_groups[0]['lr']}") + else: + optimizer = AdamW(model.parameters()) + + scheduler = NoamScheduler(optimizer, d_model=accel.unwrap(model).embedding_dim) + scheduler.step() + + if "optimizer.pth" in v_extra: + optimizer.load_state_dict(v_extra["optimizer.pth"]) + scheduler.load_state_dict(v_extra["scheduler.pth"]) + if "tracker.pth" in v_extra: + tracker.load_state_dict(v_extra["tracker.pth"]) + + criterion = CrossEntropyLoss() + + sample_rate = codec.sample_rate + + # a better rng for sampling from our schedule + rng = torch.quasirandom.SobolEngine(1, scramble=True, seed=args["seed"]) + + # log a model summary w/ num params + if accel.local_rank == 0: + add_num_params_repr_hook(accel.unwrap(model)) + with open(f"{save_path}/model.txt", "w") as f: + f.write(repr(accel.unwrap(model))) + + # load the datasets + train_data, val_data = build_datasets(args, sample_rate) + + # controller = Sketch2SoundController(sample_rate=sample_rate, hop_length=codec.hop_length) + + return State( + tracker=tracker, + model=model, + codec=codec, + optimizer=optimizer, + scheduler=scheduler, + criterion=criterion, + rng=rng, + train_data=train_data, + val_data=val_data, + grad_clip_val=grad_clip_val, + controller=None, + ) + + +@argbind.bind(without_prefix=True) +def train( + args, + accel: at.ml.Accelerator, + seed: int = 0, + codec_ckpt: str = None, + save_path: str = "ckpt", + num_iters: int = int(1000e6), + save_iters: list = [10000, 50000, 100000, 300000, 500000,], + sample_freq: int = 10000, + val_freq: int = 1000, + batch_size: int = 12, + val_idx: list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + num_workers: int = 10, + fine_tune: bool = False, +): + assert codec_ckpt is not None, "codec_ckpt is required" + + seed = seed + accel.local_rank + at.util.seed(seed) + writer = None + + if accel.local_rank == 0: + writer = SummaryWriter(log_dir=f"{save_path}/logs/") + argbind.dump_args(args, f"{save_path}/args.yml") + + tracker = Tracker( + writer=writer, log_file=f"{save_path}/log.txt", rank=accel.local_rank + ) + + # load the codec model + state: State = load( + args=args, + accel=accel, + tracker=tracker, + save_path=save_path) + print("initialized state.") + state.device = accel.device + + train_dataloader = accel.prepare_dataloader( + state.train_data, + start_idx=state.tracker.step * batch_size, + num_workers=num_workers, + batch_size=batch_size, + collate_fn=state.train_data.collate, + ) + val_dataloader = accel.prepare_dataloader( + state.val_data, + start_idx=0, + num_workers=num_workers, + batch_size=batch_size, + collate_fn=state.val_data.collate, + persistent_workers=num_workers > 0, + ) + print("initialized dataloader.") + + + + if fine_tune: + lora.mark_only_lora_as_trainable(state.model) + print("marked only lora as trainable.") + + # Wrap the functions so that they neatly track in TensorBoard + progress bars + # and only run when specific conditions are met. + global train_loop, val_loop, validate, save_samples, checkpoint + + train_loop = tracker.log("train", "value", history=False)( + tracker.track("train", num_iters, completed=state.tracker.step)(train_loop) + ) + val_loop = tracker.track("val", len(val_dataloader))(val_loop) + validate = tracker.log("val", "mean")(validate) + + save_samples = when(lambda: accel.local_rank == 0)(save_samples) + checkpoint = when(lambda: accel.local_rank == 0)(checkpoint) + + print("starting training loop. model will compile. this will take a while. hold on a sec! go get a coffee!") + with tracker.live: + for tracker.step, batch in enumerate(train_dataloader, start=tracker.step): + train_loop(state, batch, accel) + + last_iter = ( + tracker.step == num_iters - 1 if num_iters is not None else False + ) + + if tracker.step % sample_freq == 0 or last_iter: + save_samples(state, val_idx, writer) + + if tracker.step % val_freq == 0 or last_iter: + validate(state, val_dataloader, accel) + checkpoint( + state=state, + save_iters=save_iters, + save_path=save_path, + fine_tune=fine_tune) + + # Reset validation progress bar, print summary since last validation. + tracker.done("val", f"Iteration {tracker.step}") + + if last_iter: + break + + +if __name__ == "__main__": + args = argbind.parse_args() + args["args.debug"] = int(os.getenv("LOCAL_RANK", 0)) == 0 + with argbind.scope(args): + with Accelerator() as accel: + if accel.local_rank != 0: + sys.tracebacklimit = 0 + train(args, accel) diff --git a/scripts/utils/README.md b/scripts/utils/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9fa13389f47b0432d9e20933bf77dfd9dfcb2aa7 --- /dev/null +++ b/scripts/utils/README.md @@ -0,0 +1,28 @@ +# Scripts + +## process_zip.py + +Some requirements that may not be installed in the docker image: +* argbind +* wav2wav (pip install git+https://github.com/descriptinc/lyrebird-wav2wav.git or `pip install git+https://github.com/descriptinc/lyrebird-wav2wav.git@`) + +### zip folder structure + +The zip folder should have the following internal structure: + +``` +base_folder/ + test_case_1/ + before.wav + test_case_2/ + before.wav + ... + test_case_n/ + before.wav +``` + +Note: There can be issues with the output zip if the input zip folder structure is too deep or too shallow. IF you want/need to use a zip file with a different folder structure, adjust this: +https://github.com/descriptinc/lyrebird-wav2wav/blob/136c923ce19df03876a515ca0ed83854710cfa30/scripts/utils/process_zip.py#L28 + +### Execution +`python process_zip.py -tag ` diff --git a/scripts/utils/gtzan_embeddings.py b/scripts/utils/gtzan_embeddings.py new file mode 100644 index 0000000000000000000000000000000000000000..c72de0498137582f68f6ff319261098000e089fa --- /dev/null +++ b/scripts/utils/gtzan_embeddings.py @@ -0,0 +1,264 @@ +""" +TODO: train a linear probe +usage: + python gtzan_embeddings.py --args.load conf/interface.yml --Interface.device cuda --path_to_gtzan /path/to/gtzan/genres_original --output_dir /path/to/output +""" +from pathlib import Path +from typing import List + +import audiotools as at +from audiotools import AudioSignal +import argbind +import torch +import numpy as np +import zipfile +import json + +from vampnet.interface import Interface +import tqdm + +# bind the Interface to argbind +Interface = argbind.bind(Interface) + +DEBUG = False + +def smart_plotly_export(fig, save_path): + img_format = save_path.split('.')[-1] + if img_format == 'html': + fig.write_html(save_path) + elif img_format == 'bytes': + return fig.to_image(format='png') + #TODO: come back and make this prettier + elif img_format == 'numpy': + import io + from PIL import Image + + def plotly_fig2array(fig): + #convert Plotly fig to an array + fig_bytes = fig.to_image(format="png", width=1200, height=700) + buf = io.BytesIO(fig_bytes) + img = Image.open(buf) + return np.asarray(img) + + return plotly_fig2array(fig) + elif img_format == 'jpeg' or 'png' or 'webp': + fig.write_image(save_path) + else: + raise ValueError("invalid image format") + +def dim_reduce(emb, labels, save_path, n_components=3, method='tsne', title=''): + """ + dimensionality reduction for visualization! + saves an html plotly figure to save_path + parameters: + emb (np.ndarray): the samples to be reduces with shape (samples, features) + labels (list): list of labels for embedding + save_path (str): path where u wanna save ur figure + method (str): umap, tsne, or pca + title (str): title for ur figure + returns: + proj (np.ndarray): projection vector with shape (samples, dimensions) + """ + import pandas as pd + import plotly.express as px + if method == 'umap': + from umap import UMAP + reducer = umap.UMAP(n_components=n_components) + elif method == 'tsne': + from sklearn.manifold import TSNE + reducer = TSNE(n_components=n_components) + elif method == 'pca': + from sklearn.decomposition import PCA + reducer = PCA(n_components=n_components) + else: + raise ValueError + + proj = reducer.fit_transform(emb) + + if n_components == 2: + df = pd.DataFrame(dict( + x=proj[:, 0], + y=proj[:, 1], + instrument=labels + )) + fig = px.scatter(df, x='x', y='y', color='instrument', + title=title+f"_{method}") + + elif n_components == 3: + df = pd.DataFrame(dict( + x=proj[:, 0], + y=proj[:, 1], + z=proj[:, 2], + instrument=labels + )) + fig = px.scatter_3d(df, x='x', y='y', z='z', + color='instrument', + title=title) + else: + raise ValueError("cant plot more than 3 components") + + fig.update_traces(marker=dict(size=6, + line=dict(width=1, + color='DarkSlateGrey')), + selector=dict(mode='markers')) + + return smart_plotly_export(fig, save_path) + + + +# per JukeMIR, we want the emebddings from the middle layer? +def vampnet_embed(sig: AudioSignal, interface: Interface, layer=10): + with torch.inference_mode(): + # preprocess the signal + sig = interface.preprocess(sig) + + # get the coarse vampnet model + vampnet = interface.coarse + + # get the tokens + z = interface.encode(sig)[:, :vampnet.n_codebooks, :] + z_latents = vampnet.embedding.from_codes(z, interface.codec) + + # do a forward pass through the model, get the embeddings + _z, embeddings = vampnet(z_latents, return_activations=True) + # print(f"got embeddings with shape {embeddings.shape}") + # [layer, batch, time, n_dims] + # [20, 1, 600ish, 768] + + + # squeeze batch dim (1 bc layer should be dim 0) + assert embeddings.shape[1] == 1, f"expected batch dim to be 1, got {embeddings.shape[0]}" + embeddings = embeddings.squeeze(1) + + num_layers = embeddings.shape[0] + assert layer < num_layers, f"layer {layer} is out of bounds for model with {num_layers} layers" + + # do meanpooling over the time dimension + embeddings = embeddings.mean(dim=-2) + # [20, 768] + + # return the embeddings + return embeddings + +from dataclasses import dataclass, fields +@dataclass +class Embedding: + genre: str + filename: str + embedding: np.ndarray + + def save(self, path): + """Save the Embedding object to a given path as a zip file.""" + with zipfile.ZipFile(path, 'w') as archive: + + # Save numpy array + with archive.open('embedding.npy', 'w') as f: + np.save(f, self.embedding) + + # Save non-numpy data as json + non_numpy_data = {f.name: getattr(self, f.name) for f in fields(self) if f.name != 'embedding'} + with archive.open('data.json', 'w') as f: + f.write(json.dumps(non_numpy_data).encode('utf-8')) + + @classmethod + def load(cls, path): + """Load the Embedding object from a given zip path.""" + with zipfile.ZipFile(path, 'r') as archive: + + # Load numpy array + with archive.open('embedding.npy') as f: + embedding = np.load(f) + + # Load non-numpy data from json + with archive.open('data.json') as f: + data = json.loads(f.read().decode('utf-8')) + + return cls(embedding=embedding, **data) + + +@argbind.bind(without_prefix=True) +def main( + path_to_gtzan: str = None, + cache_dir: str = "./.gtzan_emb_cache", + output_dir: str = "./gtzan_vampnet_embeddings", + layers: List[int] = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] +): + path_to_gtzan = Path(path_to_gtzan) + assert path_to_gtzan.exists(), f"{path_to_gtzan} does not exist" + + cache_dir = Path(cache_dir) + output_dir = Path(output_dir) + output_dir.mkdir(exist_ok=True, parents=True) + + # load our interface + # argbind will automatically load the default config, + interface = Interface() + + # gtzan should have a folder for each genre, so let's get the list of genres + genres = [Path(x).name for x in path_to_gtzan.iterdir() if x.is_dir()] + print(f"Found {len(genres)} genres") + print(f"genres: {genres}") + + # collect audio files, genres, and embeddings + data = [] + for genre in genres: + audio_files = list(at.util.find_audio(path_to_gtzan / genre)) + print(f"Found {len(audio_files)} audio files for genre {genre}") + + for audio_file in tqdm.tqdm(audio_files, desc=f"embedding genre {genre}"): + # check if we have a cached embedding for this file + cached_path = (cache_dir / f"{genre}_{audio_file.stem}.emb") + if cached_path.exists(): + # if so, load it + if DEBUG: + print(f"loading cached embedding for {cached_path.stem}") + embedding = Embedding.load(cached_path) + else: + try: + sig = AudioSignal(audio_file) + except Exception as e: + print(f"failed to load {audio_file.name} with error {e}") + print(f"skipping {audio_file.name}") + continue + + # gets the embedding + emb = vampnet_embed(sig, interface).cpu().numpy() + + # create an embedding we can save/load + embedding = Embedding( + genre=genre, + filename=audio_file.name, + embedding=emb + ) + + # cache the embeddings + cached_path.parent.mkdir(exist_ok=True, parents=True) + embedding.save(cached_path) + data.append(embedding) + + # now, let's do a dim reduction on the embeddings + # and visualize them. + + # collect a list of embeddings and labels + embeddings = [d.embedding for d in data] + labels = [d.genre for d in data] + + # convert the embeddings to a numpy array + embeddings = np.stack(embeddings) + + # do dimensionality reduction for each layer we're given + for layer in tqdm.tqdm(layers, desc="dim reduction"): + dim_reduce( + embeddings[:, layer, :], labels, + save_path=str(output_dir / f'vampnet-gtzan-layer={layer}.html'), + n_components=2, method='tsne', + title=f'vampnet-gtzan-layer={layer}' + ) + + + + +if __name__ == "__main__": + args = argbind.parse_args() + with argbind.scope(args): + main() \ No newline at end of file diff --git a/scripts/utils/huggingface/push_to_repos.sh b/scripts/utils/huggingface/push_to_repos.sh new file mode 100644 index 0000000000000000000000000000000000000000..fa0a283ee208a5db05d51629fba04717a57a1e80 --- /dev/null +++ b/scripts/utils/huggingface/push_to_repos.sh @@ -0,0 +1,37 @@ +# the (remote repo, model_name) are: +# vampnet-music (default) +# vampnet-percussion (percussion) +# vampnet-choir ()'choir') +# etc for.. +# 'machines' +# 'n64' +# 'opera' +# 'percussion' + +# iterate through remote, model_name pairs: +# and edit the DEFAULT_MODEL file in the repo +# add commit and push to the right remote +# each remote starts with https://huggingface.co/hugggof/{repo_name} + +for repo in vampnet-music vampnet-percussion vampnet-choir vampnet-machines vampnet-n64 vampnet-opera vampnet-percussion +do + echo "repo: $repo" + # get the model name from the repo + model_name=$(echo $repo | cut -d'-' -f2) + # if the model_name is music , set it to default + if [ $model_name == "music" ]; then + model_name="default" + fi + echo "model_name: $model_name" + # remove the DEFAULT_MODEL file + rm DEFAULT_MODEL + # create a new DEFAULT_MODEL file with the model name + echo $model_name > DEFAULT_MODEL + + # commit and push to the right remote + git add DEFAULT_MODEL + git commit -m "update DEFAULT_MODEL to $model_name" + git remote remove $repo + git remote add $repo https://huggingface.co/spaces/hugggof/$repo + git push $repo main +done \ No newline at end of file diff --git a/scripts/utils/plots.py b/scripts/utils/plots.py new file mode 100644 index 0000000000000000000000000000000000000000..955f891505a5d29c0d72d967905e3d62db04f5fa --- /dev/null +++ b/scripts/utils/plots.py @@ -0,0 +1,43 @@ +import matplotlib.pyplot as plt +import seaborn as sns +from pandas.api.types import CategoricalDtype + +def plot_metrics(metrics, condition_to_latex, title, color_palette): + # Add a new column to your dataframe with the latex representation + metrics['condition_latex'] = metrics['condition'].map(condition_to_latex) + + # Order condition_latex as per the condition_to_latex dictionary + cat_type = CategoricalDtype(categories=condition_to_latex.values(), ordered=True) + metrics['condition_latex'] = metrics['condition_latex'].astype(cat_type) + + # Compute mean and std for each condition for each metric + grouped = metrics.groupby('condition_latex')[['mel', 'frechet']].agg(['mean', 'std']) + + fig, axs = plt.subplots(2, 1, figsize=(7, 5.25)) + + # Set the main title for the figure + fig.suptitle(title, fontsize=16) + + # Get color for each bar in the plot + bar_colors = [color_palette[condition] for condition in grouped.index] + + # Plot mel + sns.boxplot(x='condition_latex', y='mel', data=metrics, ax=axs[0], palette=color_palette, showfliers=False) + axs[0].set_ylabel('Mel Spectrogram Loss \u2190') + axs[0].set_xlabel('') # Remove x-axis label + axs[0].set_xticklabels(grouped.index, rotation=0, ha='center') + + # Plot frechet + axs[1].bar(grouped.index, grouped['frechet']['mean'], yerr=grouped['frechet']['std'], color=bar_colors) + axs[1].set_ylabel('FAD \u2190') + axs[1].set_xlabel('') # Remove x-axis label + axs[1].set_xticklabels(grouped.index, rotation=0, ha='center') + + # Adjust the space between plots + plt.subplots_adjust(hspace=0.1) + + # Remove any unnecessary space around the plot + plt.tight_layout(rect=[0, 0, 1, 0.96]) + + # Reduce the space between suptitle and the plot + plt.subplots_adjust(top=0.92) \ No newline at end of file diff --git a/scripts/utils/remove_quiet_files.py b/scripts/utils/remove_quiet_files.py new file mode 100644 index 0000000000000000000000000000000000000000..f557f1574da562203cbdd5334717a699e89196bb --- /dev/null +++ b/scripts/utils/remove_quiet_files.py @@ -0,0 +1,29 @@ +# removes files with loudness below 24db + +from pathlib import Path +import shutil +import audiotools as at +import argbind + +@argbind.bind(without_prefix=True) +def remove_quiet_files( + src_dir: Path = None, + dest_dir: Path = None, + min_loudness: float = -30, +): + # copy src to dest + dest_dir.mkdir(parents=True, exist_ok=True) + shutil.copytree(src_dir, dest_dir, dirs_exist_ok=True) + + audio_files = at.util.find_audio(dest_dir) + for audio_file in audio_files: + sig = at.AudioSignal(audio_file) + if sig.loudness() < min_loudness: + audio_file.unlink() + print(f"removed {audio_file}") + +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + remove_quiet_files() \ No newline at end of file diff --git a/scripts/utils/split.py b/scripts/utils/split.py new file mode 100644 index 0000000000000000000000000000000000000000..e67f6289afb07bc2a68ba59182175203512a281f --- /dev/null +++ b/scripts/utils/split.py @@ -0,0 +1,66 @@ +from pathlib import Path +import random +import shutil +import os +import json + +import argbind +from tqdm import tqdm +from tqdm.contrib.concurrent import thread_map + +from audiotools.core import util + + +@argbind.bind(without_prefix=True) +def train_test_split( + audio_folder: str = ".", + test_size: float = 0.2, + seed: int = 42, +): + print(f"finding audio") + + audio_folder = Path(audio_folder) + audio_files = util.find_audio(audio_folder) + print(f"found {len(audio_files)} audio files") + + # split according to test_size + n_test = int(len(audio_files) * test_size) + n_train = len(audio_files) - n_test + + # shuffle + random.seed(seed) + random.shuffle(audio_files) + + train_files = audio_files[:n_train] + test_files = audio_files[n_train:] + + + print(f"Train files: {len(train_files)}") + print(f"Test files: {len(test_files)}") + continue_ = input("Continue [yn]? ") or "n" + + if continue_ != "y": + return + + for split, files in ( + ("train", train_files), ("test", test_files) + ): + for file in tqdm(files): + out_file = audio_folder.parent / f"{audio_folder.name}-{split}" / Path(file).name + out_file.parent.mkdir(exist_ok=True, parents=True) + try: + os.symlink(file, out_file) + except FileExistsError: + print(f"File {out_file} already exists, skipping") + + # save split as json + with open(Path(audio_folder) / f"{split}.json", "w") as f: + json.dump([str(f) for f in files], f) + + + +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + train_test_split() \ No newline at end of file diff --git a/scripts/utils/split_long_audio_file.py b/scripts/utils/split_long_audio_file.py new file mode 100644 index 0000000000000000000000000000000000000000..8648b2612ebd4f1344357222dff5b430525091c5 --- /dev/null +++ b/scripts/utils/split_long_audio_file.py @@ -0,0 +1,34 @@ +from pathlib import Path +import argbind + +import audiotools as at +import tqdm + + +@argbind.bind(without_prefix=True) +def split_long_audio_file( + file: str = None, + max_chunk_size_s: int = 60*10 +): + file = Path(file) + output_dir = file.parent / file.stem + output_dir.mkdir() + + sig = at.AudioSignal(file) + + # split into chunks + for i, sig in tqdm.tqdm(enumerate(sig.windows( + window_duration=max_chunk_size_s, hop_duration=max_chunk_size_s/2, + preprocess=True)) + ): + sig.write(output_dir / f"{i}.wav") + + print(f"wrote {len(list(output_dir.glob('*.wav')))} files to {output_dir}") + + return output_dir + +if __name__ == "__main__": + args = argbind.parse_args() + + with argbind.scope(args): + split_long_audio_file() \ No newline at end of file diff --git a/scripts/utils/stage.py b/scripts/utils/stage.py new file mode 100644 index 0000000000000000000000000000000000000000..253e1d070ccf3754be01578d22b65136858fa697 --- /dev/null +++ b/scripts/utils/stage.py @@ -0,0 +1,30 @@ +import os +import subprocess +from pathlib import Path + +import argbind +import rich +from audiotools.ml import Experiment + + +@argbind.bind(without_prefix=True) +def run( + run_dir: str = os.getenv("PATH_TO_RUNS", "runs"), + name: str = None, + recent: bool = False, +): + if recent: + paths = sorted(Path(run_dir).iterdir(), key=os.path.getmtime) + paths = [p.name for p in paths if p.is_dir()] + if paths: + name = paths[-1] + + with Experiment(run_dir, name) as exp: + exp.snapshot() + rich.print(f"Created a snapshot of {exp.parent_directory} at {exp.exp_dir}") + + +if __name__ == "__main__": + args = argbind.parse_args() + with argbind.scope(args): + run() diff --git a/scripts/utils/visualize_embeddings.py b/scripts/utils/visualize_embeddings.py new file mode 100644 index 0000000000000000000000000000000000000000..907c5f3adaddd1068eb0af74d2c64dde33d9e36e --- /dev/null +++ b/scripts/utils/visualize_embeddings.py @@ -0,0 +1,265 @@ +""" +TODO: train a linear probe +usage: + python gtzan_embeddings.py --args.load conf/interface.yml --Interface.device cuda --path_to_audio /path/to/audio/labels --output_dir /path/to/output +""" +from pathlib import Path +from typing import List + +import audiotools as at +from audiotools import AudioSignal +import argbind +import torch +import numpy as np +import zipfile +import json + +from vampnet.interface import Interface +import tqdm + +# bind the Interface to argbind +Interface = argbind.bind(Interface) + +DEBUG = False + + +def smart_plotly_export(fig, save_path: Path): + img_format = save_path.suffix[1:] + if img_format == "html": + fig.write_html(save_path) + elif img_format == 'bytes': + return fig.to_image(format='png') + #TODO: come back and make this prettier + elif img_format == 'numpy': + import io + from PIL import Image + + def plotly_fig2array(fig): + #convert Plotly fig to an array + fig_bytes = fig.to_image(format="png", width=1200, height=700) + buf = io.BytesIO(fig_bytes) + img = Image.open(buf) + return np.asarray(img) + + return plotly_fig2array(fig) + elif img_format == 'jpeg' or 'png' or 'webp': + fig.write_image(save_path) + else: + raise ValueError("invalid image format") + + +def dim_reduce(annotated_embeddings, layer, output_dir, n_components=3, method="tsne"): + """ + dimensionality reduction for visualization! + saves an html plotly figure to save_path + parameters: + annotated_embeddings (list): the annotated enmbeddings to be reduced; embeddings have shape (samples, features) + labels (list): list of labels for embedding + save_path (str): path where u wanna save ur figure + method (str): umap, tsne, or pca + title (str): title for ur figure + returns: + proj (np.ndarray): projection vector with shape (samples, dimensions) + """ + import pandas as pd + import plotly.express as px + + fig_name = f"vampnet-embeddings-layer={layer}" + fig_title = f"{fig_name}_{method}" + save_path = (output_dir / fig_name).with_suffix(".html") + + if method == "umap": + from umap import UMAP + reducer = umap.UMAP(n_components=n_components) + elif method == "tsne": + from sklearn.manifold import TSNE + + reducer = TSNE(n_components=n_components) + elif method == "pca": + from sklearn.decomposition import PCA + + reducer = PCA(n_components=n_components) + else: + raise ValueError(f"invalid method: {method}") + + labels = [emb.label for emb in annotated_embeddings] + names = [emb.filename for emb in annotated_embeddings] + embs = [emb.embedding for emb in annotated_embeddings] + embs_at_layer = np.stack(embs)[:, layer, :] + projs = reducer.fit_transform(embs_at_layer) + + df = pd.DataFrame( + { + "label": labels, + "name": names, + "x": projs[:, 0], + "y": projs[:, 1], + } + ) + if n_components == 2: + fig = px.scatter( + df, x="x", y="y", color="label", hover_name="name", title=fig_title, + ) + + elif n_components == 3: + df['z'] = projs[:, 2] + fig = px.scatter_3d( + df, x="x", y="y", z="z", color="label", hover_name="name", title=fig_title + ) + else: + raise ValueError(f"can't plot {n_components} components") + + fig.update_traces( + marker=dict(size=6, line=dict(width=1, color="DarkSlateGrey")), + selector=dict(mode="markers"), + ) + + return smart_plotly_export(fig, save_path) + + + +# per JukeMIR, we want the emebddings from the middle layer? +def vampnet_embed(sig: AudioSignal, interface: Interface, layer=10): + with torch.inference_mode(): + # preprocess the signal + sig = interface.preprocess(sig) + + # get the coarse vampnet model + vampnet = interface.coarse + + # get the tokens + z = interface.encode(sig)[:, :vampnet.n_codebooks, :] + z_latents = vampnet.embedding.from_codes(z, interface.codec) + + # do a forward pass through the model, get the embeddings + _z, embeddings = vampnet(z_latents, return_activations=True) + # print(f"got embeddings with shape {embeddings.shape}") + # [layer, batch, time, n_dims] + # [20, 1, 600ish, 768] + + + # squeeze batch dim (1 bc layer should be dim 0) + assert embeddings.shape[1] == 1, f"expected batch dim to be 1, got {embeddings.shape[0]}" + embeddings = embeddings.squeeze(1) + + num_layers = embeddings.shape[0] + assert layer < num_layers, f"layer {layer} is out of bounds for model with {num_layers} layers" + + # do meanpooling over the time dimension + embeddings = embeddings.mean(dim=-2) + # [20, 768] + + # return the embeddings + return embeddings + +from dataclasses import dataclass, fields +@dataclass +class AnnotatedEmbedding: + label: str + filename: str + embedding: np.ndarray + + def save(self, path): + """Save the Embedding object to a given path as a zip file.""" + with zipfile.ZipFile(path, 'w') as archive: + + # Save numpy array + with archive.open('embedding.npy', 'w') as f: + np.save(f, self.embedding) + + # Save non-numpy data as json + non_numpy_data = {f.name: getattr(self, f.name) for f in fields(self) if f.name != 'embedding'} + with archive.open('data.json', 'w') as f: + f.write(json.dumps(non_numpy_data).encode('utf-8')) + + @classmethod + def load(cls, path): + """Load the Embedding object from a given zip path.""" + with zipfile.ZipFile(path, 'r') as archive: + + # Load numpy array + with archive.open('embedding.npy') as f: + embedding = np.load(f) + + # Load non-numpy data from json + with archive.open('data.json') as f: + data = json.loads(f.read().decode('utf-8')) + + return cls(embedding=embedding, **data) + + +@argbind.bind(without_prefix=True) +def main( + path_to_audio: str = None, + cache_dir: str = "./.emb_cache", + output_dir: str = "./vampnet_embeddings", + layers: List[int] = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19], + method: str = "tsne", + n_components: int = 2, +): + path_to_audio = Path(path_to_audio) + assert path_to_audio.exists(), f"{path_to_audio} does not exist" + + cache_dir = Path(cache_dir) + output_dir = Path(output_dir) + output_dir.mkdir(exist_ok=True, parents=True) + + # load our interface + # argbind will automatically load the default config, + interface = Interface() + + # we expect path_to_audio to consist of a folder for each label, so let's get the list of labels + labels = [Path(x).name for x in path_to_audio.iterdir() if x.is_dir()] + print(f"Found {len(labels)} labels") + print(f"labels: {labels}") + + # collect audio files, labels, and embeddings + annotated_embeddings = [] + for label in labels: + audio_files = list(at.util.find_audio(path_to_audio / label)) + print(f"Found {len(audio_files)} audio files for label {label}") + + for audio_file in tqdm.tqdm(audio_files, desc=f"embedding label {label}"): + # check if we have a cached embedding for this file + cached_path = cache_dir / f"{label}_{audio_file.stem}.emb" + if cached_path.exists(): + # if so, load it + if DEBUG: + print(f"loading cached embedding for {cached_path.stem}") + embedding = AnnotatedEmbedding.load(cached_path) + else: + try: + sig = AudioSignal(audio_file) + except Exception as e: + print(f"failed to load {audio_file.name} with error {e}") + print(f"skipping {audio_file.name}") + continue + + # gets the embedding + emb = vampnet_embed(sig, interface).cpu().numpy() + + # create an embedding we can save/load + embedding = AnnotatedEmbedding( + label=label, filename=audio_file.name, embedding=emb + ) + + # cache the embeddings + cached_path.parent.mkdir(exist_ok=True, parents=True) + embedding.save(cached_path) + annotated_embeddings.append(embedding) + + # now, let's do a dim reduction on the embeddings and visualize them. + for layer in tqdm.tqdm(layers, desc="dim reduction"): + dim_reduce( + annotated_embeddings, + layer, + output_dir=output_dir, + n_components=n_components, + method=method, + ) + + +if __name__ == "__main__": + args = argbind.parse_args() + with argbind.scope(args): + main() diff --git a/scripts/utils/xeno-canto-dl.py b/scripts/utils/xeno-canto-dl.py new file mode 100644 index 0000000000000000000000000000000000000000..89acc822d291bd0a145b656fc62be5209a6f6cfc --- /dev/null +++ b/scripts/utils/xeno-canto-dl.py @@ -0,0 +1,234 @@ +from xenopy import Query + + +SPECIES = [ + "American Robin", + "Northern Cardinal", + "Mourning Dove", + "American Crow", + "Baltimore Oriole", + "Blue Jay", + "Eastern Bluebird", + "House Finch", + "American Goldfinch", + "House Sparrow", + "Song Sparrow", + "Tufted Titmouse", + "White-breasted Nuthatch", + "European Starling", + "American Redstart", + "Red-winged Blackbird", + "Brown-headed Cowbird", + "Common Grackle", + "Boat-tailed Grackle", + "Common Yellowthroat", + "Northern Mockingbird", + "Carolina Wren", + "Eastern Meadowlark", + "Chipping Sparrow", + "Tree Swallow", + "Barn Swallow", + "Cliff Swallow", + "Pine Siskin", + "Indigo Bunting", + "Eastern Towhee", + "Carolina Chickadee", + "Great Crested Flycatcher", + "Eastern Wood-Pewee", + "Ovenbird", + "Northern Flicker", + "Red-eyed Vireo", + "American Woodcock", + "Eastern Phoebe", + "Downy Woodpecker", + "Scarlet Tanager", + "Yellow Warbler", + "White-eyed Vireo", + "Common Loon", + "White-throated Sparrow", + "Yellow-throated Vireo", + "Great Blue Heron", + "Belted Kingfisher", + "Pied-billed Grebe", + "Wild Turkey", + "Wood Thrush", + "Rose-breasted Grosbeak", + "Field Sparrow", + "Hooded Warbler", + "Northern Parula", + "Chestnut-sided Warbler", + "Blue-winged Warbler", + "Red-bellied Woodpecker", + "Yellow-billed Cuckoo", + "Gray Catbird", + "Northern Saw-whet Owl", + "Osprey", + "Common Nighthawk", + "Broad-winged Hawk", + "Black-throated Green Warbler", + "Great Horned Owl", + "Common Raven", + "Barred Owl", + "Canada Warbler", + "Magnolia Warbler", + "Black-and-white Warbler", + "Eastern Kingbird", + "Swainson's Thrush", + "Worm-eating Warbler", + "Prairie Warbler", + "Baltimore Oriole", + "Black-throated Blue Warbler", + "Louisiana Waterthrush", + "Blackburnian Warbler", + "Black-capped Chickadee", + "Cerulean Warbler", + "Red-shouldered Hawk", + "Cooper's Hawk", + "Yellow-throated Warbler", + "Blue-headed Vireo", + "Blackpoll Warbler", + "Ruffed Grouse", + "Kentucky Warbler", + "Hermit Thrush", + "Cedar Waxwing", + "Eastern Screech-Owl", + "Northern Goshawk", + "Green Heron", + "Red-tailed Hawk", + "Black Vulture", + "Hairy Woodpecker", + "Golden-crowned Kinglet", + "Ruby-crowned Kinglet", + "Bicknell's Thrush", + "Blue-gray Gnatcatcher", + "Veery", + "Pileated Woodpecker", + "Purple Finch", + "White-crowned Sparrow", + "Snow Bunting", + "Pine Grosbeak", + "American Tree Sparrow", + "Dark-eyed Junco", + "Snowy Owl", + "White-winged Crossbill", + "Red Crossbill", + "Common Redpoll", + "Northern Shrike", + "Northern Harrier", + "Rough-legged Hawk", + "Long-eared Owl", + "Evening Grosbeak", + "Northern Pintail", + "American Black Duck", + "Mallard", + "Canvasback", + "Redhead", + "Ring-necked Duck", + "Greater Scaup", + "Lesser Scaup", + "Bufflehead", + "Common Goldeneye", + "Hooded Merganser", + "Common Merganser", + "Red-breasted Merganser", + "Ruddy Duck", + "Wood Duck", + "Gadwall", + "American Wigeon", + "Northern Shoveler", + "Green-winged Teal", + "Blue-winged Teal", + "Cinnamon Teal", + "Ringed Teal", + "Cape Teal", + "Northern Fulmar", + "Yellow-billed Loon", + "Red-throated Loon", + "Arctic Loon", + "Pacific Loon", + "Horned Grebe", + "Red-necked Grebe", + "Eared Grebe", + "Western Grebe", + "Clark's Grebe", + "Double-crested Cormorant", + "Pelagic Cormorant", + "Great Cormorant", + "American White Pelican", + "Brown Pelican", + "Brandt's Cormorant", + "Least Bittern", + "Great Egret", + "Snowy Egret", + "Little Blue Heron", + "Tricolored Heron", + "Reddish Egret", + "Black-crowned Night-Heron", + "Yellow-crowned Night-Heron", + "White Ibis", + "Glossy Ibis", + "Roseate Spoonbill", + "Wood Stork", + "Black-bellied Whistling-Duck", + "Fulvous Whistling-Duck", + "Greater White-fronted Goose", + "Snow Goose", + "Ross's Goose", + "Canada Goose", + "Brant", + "Mute Swan", + "Tundra Swan", + "Whooper Swan", + "Sandhill Crane", + "Black-necked Stilt", + "American Avocet", + "Northern Jacana", + "Greater Yellowlegs", + "Lesser Yellowlegs", + "Willet", + "Spotted Sandpiper", + "Upland Sandpiper", + "Whimbrel", + "Long-billed Curlew", + "Marbled Godwit", + "Ruddy Turnstone", + "Red Knot", + "Sanderling", + "Semipalmated Sandpiper", + "Western Sandpiper", + "Least Sandpiper", + "White-rumped Sandpiper", + "Baird's Sandpiper", + "Pectoral Sandpiper", + "Dunlin", + "Buff-breasted Sandpiper", + "Short-billed Dowitcher", + "Long-billed Dowitcher", + "Common Snipe", + "American Woodcock", + "Wilson's Phalarope", + "Red-necked Phalarope", + "Red Phalarope" +] + +from pathlib import Path + +def remove_spaces(s): + return s.replace(" ", "") + +for species in SPECIES: + if Path("/media/CHONK/hugo/xeno-canto-full/" + remove_spaces(species)).exists(): + continue + try: + q = Query( + name=species, q="A", length="10-30", + ) + + # retrieve metadata + metafiles = q.retrieve_meta(verbose=True) + # retrieve recordings + q.retrieve_recordings(multiprocess=True, nproc=10, attempts=10, outdir="/media/CHONK/hugo/xeno-canto-full/") + + except: + print("Failed to download " + species) + continue \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..88d6afb01574861bdcbbc4a6cba74faf0ba31c82 --- /dev/null +++ b/setup.py @@ -0,0 +1,42 @@ +from setuptools import find_packages +from setuptools import setup + +with open("README.md") as f: + long_description = f.read() + +setup( + name="vampnet", + version="0.0.1", + classifiers=[ + "Intended Audience :: Developers", + "Natural Language :: English", + "Programming Language :: Python :: 3.7", + "Topic :: Artistic Software", + "Topic :: Multimedia", + "Topic :: Multimedia :: Sound/Audio", + "Topic :: Multimedia :: Sound/Audio :: Editors", + "Topic :: Software Development :: Libraries", + ], + description="Generative Music Modeling.", + long_description=long_description, + long_description_content_type="text/markdown", + author="Hugo Flores García, Prem Seetharaman", + author_email="hugggofloresgarcia@gmail.com", + url="https://github.com/hugofloresgarcia/vampnet", + license="MIT", + packages=find_packages(), + install_requires=[ + "torch==2.4.1", + "argbind>=0.3.2", + "numpy==1.23", + "wavebeat @ git+https://github.com/hugofloresgarcia/wavebeat", + "lac @ git+https://github.com/hugofloresgarcia/lac.git", + "descript-audiotools @ git+https://github.com/hugofloresgarcia/audiotools.git", + "gradio", + "loralib", + "torch_pitch_shift", + "plotly", + "pydantic==2.10.6", + "spaces", + ], +) diff --git a/token_telephone/tt.py b/token_telephone/tt.py new file mode 100644 index 0000000000000000000000000000000000000000..aa1f8b78cd0cba99f3a7cad05dd974f62991194f --- /dev/null +++ b/token_telephone/tt.py @@ -0,0 +1,618 @@ +from ttutil import hsv_to_rgb, dbg, log, set_debug, pow2db, db2pow +from dataclasses import dataclass, field +import os +from pathlib import Path +import random +import time +from threading import Thread +import gc +gc.disable() + +import sounddevice as sd + +from blessed import Terminal + +import numpy as np +import torch +from einops import rearrange + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~~~~ configs! ~~~~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MAX_LOUDNESS = -20 +MIN_LOUDNESS = -40 +COLS = 40 +ROWS = 13 + +device = 'Scarlett 4i4 4th Gen' +sample_rate = 48000 +num_channels = 4 +blocksize = 16384 + +PROFILE = False +DEBUG = False +DEBUG_NO_VAMPNET = False +set_debug(DEBUG) + +# if DEBUG: +# import gc +# # log when gc start and stops +# gc.set_debug(gc.DEBUG_STATS) + +@dataclass +class LoadState: + t0: float = None + loaded: bool = False + +load_state = LoadState() + +def on_random_color(): + def random_rgb_bg(): + return np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255) + return term.on_color_rgb(*random_rgb_bg()) + +# draw the intro screen before slow imports +def color_tokenize_txt(text: str): + # apply a random bg color to each letter + return "".join(on_random_color()(letter) for letter in text) + +def color_tokenize_words(text: str): + return " ".join(on_random_color()(word) for word in text.split(" ")) + +def draw_intro_screen(): + global load_state + load_state.t0 = time.time() + avg_time = 20 # average loading time + + while not load_state.loaded: + print(term.clear) + print(term.move_xy(0, 1) + term.center(color_tokenize_words("hugo flores garcía"))) + print(term.move_xy(0, 3) + term.center(color_tokenize_words("and"))) + print(term.move_xy(0, 5) + term.center(color_tokenize_words("stephan moore"))) + print(term.move_xy(0, 7) + term.center(color_tokenize_words("present"))) + print(term.move_xy(0, 9) + term.center(term.bold(color_tokenize_txt("token telephone")))) + + # print(term.move_xy(0, 10) + term.center(color_tokenize_txt("loading ")), end="") + # make a little loading bar + elapsed = time.time() - load_state.t0 + num_dots = int((elapsed / avg_time) * 20) + num_spaces = 20 - num_dots + print(term.move_xy(0, 12) + term.center(color_tokenize_words("loading"))) + print(term.move_xy(0, 13) + term.center(color_tokenize_txt(f"[{'.' * num_dots}") + f"{' ' * num_spaces}]")) + time.sleep(0.3) + + log(f"loading took {time.time() - load_state.t0} seconds") + return + +# the program +term = Terminal() + +# draw the intro screen on a background thread +Thread(target=draw_intro_screen).start() + +# disable garbage collection +from audiotools import AudioSignal +from vamp_helper import load_interface, ez_variation + + + +# TODO: +# still some quirks to work around recording time: +# do we wanna stop recording and wait a full cycle before letting people record again? +# how do we wanna balance the volume of a new input vs what's currently gonig on? +# should people have to take turns in between new loops? +# otherwise, we're doing great i think +# we also need to add a crossfade. This means maybe cutting off the last 0.1 seconds of the loop, and the beginning 0.1 +# and use that to crossfade. + +# TODO: do I wanna train a diff model to swap every 2hrs or something? +# how lond does model swapping take? how can I make it faster? + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~~~~ looper ~~~~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +@dataclass +class State: + # looper state + feedback: float = 0.25 + duration: float = 5.0 + record_channel: int = 0 + + loopbuf: np.ndarray = None # the main loop buffer. the token telephone audio is here + looper_in: np.ndarray = None # a buffer that stores the audio that's being recorded + + buf_in: np.ndarray = None # the input block with audio samples in the audio callbac + lookback_buf: np.ndarray = None # stores some lookback audio for when the threshold is passed, to propery capture transients + + recording: bool = False + playing: bool = False + + # ramps + record_ramp_in: bool = False + record_ramp_out: bool = False + + # n_record_layers: int = 2 # number of times we'll record over before clearing + # cur_rec_layer: int = 0 + recording_locked: bool = False + + rec_time: float = 0 + cur_hold_time: float = None + pos: int = 0 + rms_db: float = float("-inf") + + trig_threshold_db = -25 # a more sane default is -20 + hold_seconds = 1.0 + rel_threshold_db = -40 # a more sane default is -30 + + status: str = field(default=None) + + # token telephone configs + z_buf: torch.Tensor = None + input_ready = False + input_channel = 0 + token_telephone_processing: bool = False + num_telephone_chans = 4 + tt_cur_ch = 0 + + def __post_init__(self): + self.loopbuf = np.zeros((num_channels, int(self.duration * sample_rate))) + self.looper_in = np.zeros((1, int(self.duration * sample_rate))) + + # hold 200ms of lookback to account for rising attacks. + num_lookback_samples = max(int(sample_rate * 0.2), int(blocksize)) + log(f"num_lookback_samples {num_lookback_samples} ({num_lookback_samples / sample_rate} seconds)") + self.lookback_buf = np.zeros((1, num_lookback_samples)) + + self.buf_in = np.zeros((num_channels, blocksize)) + + + +def check_if_record(st: State, ain: np.ndarray, on_release_callback=None): + # get our rms value + rms = pow2db(np.sqrt(np.mean(ain**2))) + st.rms_db = rms + + # determine if we should ater the looper state + # if we werent recording and we cross the trigger threshold + # start recording + # if not st.recording and rms > st.trig_threshold_db and not st.recording_locked: + if not st.recording and rms > st.trig_threshold_db and not st.recording_locked: + st.recording = True + st.record_ramp_in = True + + # if we were recording and we cross the release threshold + # begin the hold period + if (st.recording and rms < st.rel_threshold_db) or st.rec_time > (st.duration-st.hold_seconds): + # if we dont have a hold time, set it + if st.cur_hold_time is None: + st.cur_hold_time = time.time() + + # release if we have a hold time and we've held for the required time, + if (time.time() - st.cur_hold_time) > st.hold_seconds: + st.record_ramp_out = True + st.rec_time = 0 + if on_release_callback is not None: + st.input_ready = True + on_release_callback(st) + st.cur_hold_time = None + else: + pass + else: + st.cur_hold_time = None + + +def launch_token_telephone(st: State): + if interface is None: + log("no interface loaded, can't do token telephone!") + time.sleep(10) + return + + # if we're already processing, do nothing + if st.token_telephone_processing: + return + else: + log("starting token telephone!") + Thread(target=do_token_telephone, args=(st,)).start() + + +def do_token_telephone(st: State,): + st.token_telephone_processing = True + while True: + lrc = st.record_channel + t0 = time.time() + cur_ch = st.tt_cur_ch + + # if there was input ready, start back from the top. + if st.input_ready: + log(f"there was input ready, processing!") + # NOTE: hugo, trying something new here. what happens if + # we don't reset the channel when input is ready, + # and instead let it come in anywhere in the cycle? + # st.tt_cur_ch = 0 # uncomment to go back to reality + + # clear the lrc, reset for next record. + st.input_ready = False + + # reocrd the channel that we'll be processing in and lock recording + st.input_channel = cur_ch + st.recording_locked = True + + # first, let's preprocess looper in + sig_looper_in = AudioSignal( + torch.from_numpy(st.looper_in).unsqueeze(0), + sample_rate=sample_rate + ) + sig_loopbuf_curch = AudioSignal( + torch.from_numpy(st.loopbuf[cur_ch:cur_ch+1]).unsqueeze(0), + sample_rate=sample_rate + ) + # make sure looperin matches the midpoint in loudness + ldns_mid = max(sig_loopbuf_curch.loudness(), sig_looper_in.loudness()) + sig_looper_in = sig_looper_in.normalize(ldns_mid) + st.looper_in = sig_looper_in.samples.cpu().numpy().squeeze(0) + + st.loopbuf[cur_ch:cur_ch + 1] = ( + st.looper_in + st.loopbuf[cur_ch:cur_ch+1] * st.feedback + ) + # also lower the volumes of the other channels + for i in range(4): + if i != cur_ch: + st.loopbuf[i:i+1] = st.loopbuf[i:i+1] * 0.5 # -3dB + + st.looper_in = np.zeros_like(st.looper_in) + + loop_input = st.loopbuf[cur_ch:cur_ch+1] + + # ~~~ VAMPNET STUFF ~~~~ + sig = AudioSignal( + torch.from_numpy(loop_input).unsqueeze(0), + sample_rate=sample_rate + ) + input_loudness = sig.loudness() + log(f"INPUT loudness {input_loudness}") + if input_loudness > MAX_LOUDNESS: + log(f"input loudness {input_loudness} is over {MAX_LOUDNESS}!") + sig = sig.normalize(MAX_LOUDNESS) + elif input_loudness < MIN_LOUDNESS: + log(f"input loudness {input_loudness} is under {MIN_LOUDNESS}!") + sig = sig.normalize(MIN_LOUDNESS) + + sig = ez_variation(interface, sig) + sig = sig.resample(sample_rate) + + # notify if we've gone over the loudness + sig = sig.normalize(input_loudness) + outloudness = sig.loudness() + if outloudness > MAX_LOUDNESS: + log(f"out loudness {sig.loudness()} is over {MAX_LOUDNESS}!") + sig = sig.normalize(MAX_LOUDNESS) + elif outloudness < MIN_LOUDNESS: + log(f"out loudness {sig.loudness()} is under {MIN_LOUDNESS}!") + sig = sig.normalize(MIN_LOUDNESS) + + # put it back in the loopbuf + # write to the next channel + # (TODO: instead of trimming to loopbuf.shape[1], maybe we can just have the loopbuf be the right size from init time.) + cur_ch = (cur_ch + 1) % st.num_telephone_chans + st.tt_cur_ch = cur_ch + if False: # HUGO: is there a time where we want feedback? + st.loopbuf[cur_ch:cur_ch+1] = ( + sig.samples.cpu().numpy().squeeze(0)[:, :st.loopbuf.shape[1]] + + st.feedback * st.loopbuf[cur_ch:cur_ch+1] + ) + else: + st.loopbuf[cur_ch:cur_ch+1] = ( + sig.samples.cpu().numpy().squeeze(0)[:, :st.loopbuf.shape[1]] + ) + + log(f"output loudness {sig.loudness()}") + log(f"telephone loop took {time.time() - t0} seconds... next channel {cur_ch}\n\n") + + # if we've made it back to the input channel, we can unlock the recording + log(f"cur_ch {cur_ch} input_channel {st.input_channel}") + if cur_ch == st.input_channel: + st.recording_locked = False + log(f"recording unlocked!") + + + # unlock the recording if we've successfully written to all channels + # if st.recording_locked and cur_ch == 0: + # st.recording_locked = False + # log(f"recording locked {st.recording_locked}") + + st.token_telephone_processing = False + return + +# TODO: since we're using this really high threshold +# we always need to record about 100ms in advance, to catch the beginning of the attacks. + +def looper_process_block(st, block: np.ndarray): + lrc = st.record_channel + + # treat the lookback buffer as a circular buffer + st.lookback_buf = np.roll(st.lookback_buf, block.shape[1], axis=1) + st.lookback_buf[:, -block.shape[1]:] = block[lrc:lrc+1, :] + + + # check if we need to record. + if st.recording: + start_i = (st.pos + block.shape[1]) - st.lookback_buf.shape[1] + end_i = st.pos + st.lookback_buf.shape[1] + + indices = np.take( + np.arange(st.loopbuf.shape[1]), + np.arange(start_i, end_i), + mode="wrap" + ) + _audio_in = st.lookback_buf[:, :] + # ramp in if we need to + if st.record_ramp_in: + _audio_in = _audio_in * np.linspace(0, 1, _audio_in.shape[1]) + st.record_ramp_in=False + + if st.record_ramp_out: + _audio_in = _audio_in * np.linspace(1, 0, _audio_in.shape[1]) + st.record_ramp_out=False + st.recording = False + + st.looper_in[:, indices] = ( + 0.9 * st.looper_in[:, indices] + _audio_in + ) + + # incremement the recording time + st.rec_time += st.lookback_buf.shape[1] / sample_rate + + # check if we need to play + crossfade_samples = int(0.1 * sample_rate) + if st.playing: + play_pos = (st.pos + block.shape[1]) % st.loopbuf.shape[1] # read one buffer ahead + indices = np.arange(play_pos, play_pos + block.shape[1]) + block = st.loopbuf.take(indices, axis=1, mode="wrap")[:, :] # this doesn't have any crossfading. # TODO: this is still not working! + + # if we've recorded more than the loop size + if st.rec_time > st.duration and st.recording: + # play the loop + play_pos = st.pos + block.shape[1] # read one buffer ahead + indices = np.arange(play_pos, play_pos + block.shape[1]) + + block[lrc:lrc] = st.looper_in.take(indices, axis=1, mode="wrap")[:, :] + + # advance looper state + st.pos = (st.pos + block.shape[1]) % st.loopbuf.shape[1] + + return block + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~~~~ drawing ~~~~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +def draw_rms_bar(st, x, y, width, height): + rms_min = -50 + rms_max = -10 + rms = st.rms_db + rms = max(rms, rms_min) + threshold = st.trig_threshold_db + rel_threshold = st.rel_threshold_db + + rms_block = int((rms - rms_min) / (rms_max - rms_min) * height) + threshold_block = (threshold - rms_min) / (rms_max - rms_min) * height + rel_threshold_block = (rel_threshold - rms_min) / (rms_max - rms_min) * height + + # draw the rms curve + for i in range(rms_block, height+4): + with term.location(x+4, y+height-i): + print(term.clear_bol) + for i in range(rms_block): + rms_val = i * (rms_max - rms_min) / height + rms_min + with term.location(x, y+height-2-i): + if i < threshold_block: + print(" " + term.on_green(f"*")) + else: + print(" " + term.on_red(f"*")) + + # at the very bottom of the bar, draw the rms value + with term.location(x, y+height-1): + print(f"{rms:.1f}dB") + # print(f" rms") + + +def draw_looper(st): + x = 0 + y = 0 + width = COLS + height = ROWS + + tt_refresh_every = 0.3 + if not hasattr(draw_looper, "last_draw"): + draw_looper.last_draw = 0 + should_draw = True + else: + should_draw = (time.time() - draw_looper.last_draw) > tt_refresh_every + if should_draw: + draw_looper.last_draw = time.time() + + + draw_rms_bar(st, x, y, width - 10, height) + + if should_draw: + with term.location(width // 2-4, 1): + for i, letter in enumerate("token telephone"): + print(on_random_color()(letter), end="") + + # with term.location(ROWS-2, COLS // 2): + # print(f"status {st.status}!!!") + + + # if we're recording, draw a red unlderlined "rec" sign on the bottom right + # with term.location(width-8, height-1): + # if st.recording: + # print(term.on_red("rec")) + # else: + # print(term.on_gray50("rec")) + + # # if we're playing draw a green underline "play" sign on the bottom right + # with term.location(width-4, height-1): + # if st.playing: + # print(term.on_green("play")) + # else: + # print(term.on_gray50("play")) + + + # draw the timeline at the bottom using --- + with term.location(6, height): + timeline = ["-"] * (width - 12) + playhead = int((st.pos / st.loopbuf.shape[1]) * (width - 12)) + timeline[playhead] = "v" + print("|"+"".join(timeline) + "|") + + + # draw the main message at the very center: + msg_loc = (width // 2, height // 2+1) + _x, _y = msg_loc + if not st.recording: + if not st.recording_locked: + print(term.move_xy(0, _y-1) + term.center("make a sound", width=width+5)) + print(term.move_xy(0, _y+0) + term.center("to", width=width+5)) + print(term.move_xy(0, _y+1) + term.center("record", width=width+5)) + else: + # how many seconds left until we can record again? + # how many more chs do we need to go through before we can record again? + if st.tt_cur_ch < st.input_channel: + chs_remaining = st.input_channel - st.tt_cur_ch + else: + chs_remaining = 4-st.tt_cur_ch + st.input_channel + locked_time_remaining = chs_remaining * st.duration + st.duration - (st.pos / sample_rate) + print(term.move_xy(0, _y-1) + term.center("please wait", width=width+5)) + print(term.move_xy(0, _y+0) + term.center(term.on_green(f"{locked_time_remaining:.1f}s"), width=width+5)) + print(term.move_xy(0, _y+1) + term.center("for your turn :)", width=width+5)) + else: + print(term.move_xy(0, _y-1) + term.center(term.on_red("recording"), width=width+5)) + print(term.move_xy(0, _y+0) + term.center(f"{(st.duration) - st.rec_time:.1f}s left", width=width+5)) + print(term.move_xy(0, _y+1) + term.center("", width=width+5)) + + + # we'll draw channel 0 (1) on the bottom right corner + # channel 1 (2) on the top right corner + # channel 2 (3) on the top left corner + # channel 3 (4) on the bottom left corner + my = 3 # margin + mx = 10 + locations = { + 1: (width - mx, height - my), + 2: (width - mx, 1+my), + 3: (mx, 1+my), + 4: (mx, height - my), + } + for i in range(1, 5): + if should_draw: + if st.tt_cur_ch == i - 1 and st.token_telephone_processing: + x, y = locations[i] + on_random_colors = lambda n: "".join(on_random_color()(" ") for _ in range(n)) + print(term.move_xy(x, y-1) + on_random_colors(5)) + print(term.move_xy(x, y) + on_random_color()(" ") + f" {i} " + on_random_color()(" ")) + print(term.move_xy(x, y+1) + on_random_colors(5)) + else: + # same thing, but a gray instead of random colors + x, y = locations[i] + on_gray_colors = lambda n: "".join(term.on_gray50(" ") for _ in range(n)) + print(term.move_xy(x, y-1) + on_gray_colors(5)) + print(term.move_xy(x, y) + term.on_gray50(" ") + f" {i} " + term.on_gray50(" ")) + print(term.move_xy(x, y+1) + on_gray_colors(5)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# ~~~~~~ live audio ~~~~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +def audio_init(): + sd.default.samplerate = sample_rate + sd.default.device = device + +# ~~~~~~ the main audio callback ~~~~~~~~~ +def callback(st, indata, outdata, frames, _time, status): + t0 = time.time() + lrc = st.record_channel + + if status: + log(f"status is {status}") + st.status = status + + # log dtype, status, frames, time, max min + # log(f"indata {indata.dtype} max {indata.max()} min {indata.min()} {status} {frames} {_time}") + + + ain = rearrange(indata, 't n -> n t', n=num_channels) + + # convert audio to from int32 to float32 + ain = ain.astype(np.float32) / np.iinfo(np.int16).max + buf_in = ain + + # if it's all zeros, we're not recording + # so we can just pass it through + if np.all(buf_in == 0): + st.status = st.status + "no input" + return + + st.buf_in = buf_in + check_if_record( + st, buf_in, + on_release_callback=launch_token_telephone + ) + buf_in = looper_process_block(st, buf_in) + + # pass our st.loopbuf to the output + ain = buf_in + + # convert back to int32 + ain = (ain * np.iinfo(np.int16).max).astype(np.int16) + + outdata[:] = rearrange(ain, 'n t -> t n') + + # log(f"outdata {outdata.dtype} max {outdata.max()} min {outdata.min()} --- took {time.time() - t0} seconds") + + + +if DEBUG_NO_VAMPNET: + interface=None +else: + interface = load_interface(model_choice="opera") + +load_state.loaded = True + +def main(): + if PROFILE: + import yappi + yappi.start() + + try: + audio_init() + st = State() + st.playing = True + + from functools import partial + cb = partial(callback, st) + + with term.fullscreen(), term.cbreak(): + with sd.Stream(channels=num_channels, callback=cb, blocksize=blocksize, prime_output_buffers_using_stream_callback=True, dtype=np.int16): + while True: + with term.hidden_cursor(): + if DEBUG: + time.sleep(100) + else: + draw_looper(st) + + except KeyboardInterrupt: + print(term.clear) + if PROFILE: + yappi.stop() + + # retrieve thread stats by their thread id (given by yappi) + threads = yappi.get_thread_stats() + for thread in threads: + print( + "Function stats for (%s) (%d)" % (thread.name, thread.id) + ) # it is the Thread.__class__.__name__ + yappi.get_func_stats(ctx_id=thread.id).print_all() + +main() \ No newline at end of file diff --git a/token_telephone/ttutil.py b/token_telephone/ttutil.py new file mode 100644 index 0000000000000000000000000000000000000000..37e17946e24834d7f414874885061b5f67fe71f3 --- /dev/null +++ b/token_telephone/ttutil.py @@ -0,0 +1,65 @@ +import logging +from pathlib import Path +ROOT = Path(__file__).parent + +import numpy as np +from queue import Queue + +# make a log file!! +logfile= ROOT / "log.txt" +if logfile.exists(): + logfile.unlink() +logging.basicConfig(filename=logfile, level=logging.INFO, datefmt="%Y-%m-%d %H:%M:%S", format="%(asctime)s | %(levelname)s | %(message)s") + + +def hsv_to_rgb(h, s, v): + # from https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV + c = v * s + h_ = h / 60 + x = c * (1 - abs(h_ % 2 - 1)) + m = v - c + + if h_ < 1: + r, g, b = c, x, 0 + elif h_ < 2: + r, g, b = x, c, 0 + elif h_ < 3: + r, g, b = 0, c, x + elif h_ < 4: + r, g, b = 0, x, c + elif h_ < 5: + r, g, b = x, 0, c + else: + r, g, b = c, 0, x + + return r + m, g + m, b + m + + +def dbg(*args): + print(" ".join(map(str, args))) + + +# we'll want to log on a separate thread +# so that we can log without blocking the main thread + +# make a queue for logging +log_queue = Queue() + +# log to a file instead of the console +def log(msg): + # log_queue.put(msg) + logging.info(msg) + pass + +def set_debug(debug): + if debug: + # print log to console + logging.getLogger().addHandler(logging.StreamHandler()) + + +def pow2db(x): + return 10 * np.log10(x + 1e-6) + + +def db2pow(x): + return 10 ** (x / 10) diff --git a/token_telephone/vamp_helper.py b/token_telephone/vamp_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..9a3feb52fad3eece5231e01e3769e5be51f41e2d --- /dev/null +++ b/token_telephone/vamp_helper.py @@ -0,0 +1,172 @@ +from pathlib import Path +import time +import os +from contextlib import contextmanager +import random + +import numpy as np +import audiotools as at +from audiotools import AudioSignal +import argbind +import shutil +import torch +import yaml + + +from vampnet.interface import Interface, signal_concat +from vampnet import mask as pmask + +from ttutil import log + +# TODO: incorporate discord bot (if mem allows) +# in a separate thread, send audio samples for listening +# and send back the results +# as well as the params for sampling +# also a command that lets you clear the current signal +# if you want to start over + + +device = "cuda" if torch.cuda.is_available() else "cpu" + +VAMPNET_DIR = Path(".").resolve() + +@contextmanager +def chdir(path): + old_dir = os.getcwd() + os.chdir(path) + try: + yield + finally: + os.chdir(old_dir) + +def load_interface(model_choice="default") -> Interface: + with chdir(VAMPNET_DIR): + + + # populate the model choices with any interface.yml files in the generated confs + MODEL_CHOICES = { + "default": { + "Interface.coarse_ckpt": "models/vampnet/coarse.pth", + "Interface.coarse2fine_ckpt": "models/vampnet/c2f.pth", + "Interface.codec_ckpt": "models/vampnet/codec.pth", + } + } + generated_confs = Path("conf/generated") + for conf_file in generated_confs.glob("*/interface.yml"): + with open(conf_file) as f: + _conf = yaml.safe_load(f) + + # check if the coarse, c2f, and codec ckpts exist + # otherwise, dont' add this model choice + if not ( + Path(_conf["Interface.coarse_ckpt"]).exists() and + Path(_conf["Interface.coarse2fine_ckpt"]).exists() and + Path(_conf["Interface.codec_ckpt"]).exists() + ): + continue + + MODEL_CHOICES[conf_file.parent.name] = _conf + + interface = Interface( + device=device, + coarse_ckpt=MODEL_CHOICES[model_choice]["Interface.coarse_ckpt"], + coarse2fine_ckpt=MODEL_CHOICES[model_choice]["Interface.coarse2fine_ckpt"], + codec_ckpt=MODEL_CHOICES[model_choice]["Interface.codec_ckpt"], + ) + + interface.model_choices = MODEL_CHOICES + interface.to("cuda" if torch.cuda.is_available() else "cpu") + return interface + +def load_model(interface: Interface, model_choice: str): + interface.reload( + interface.model_choices[model_choice]["Interface.coarse_ckpt"], + interface.model_choices[model_choice]["Interface.coarse2fine_ckpt"], + ) + +def ez_variation( + interface, + sig: AudioSignal, + seed: int = None, + model_choice: str = None, + ): + t0 = time.time() + + if seed is None: + seed = int(torch.randint(0, 2**32, (1,)).item()) + at.util.seed(seed) + + # reload the model if necessary + if model_choice is not None: + load_model(interface, model_choice) + + # SAMPLING MASK PARAMS, hard code for now, we'll prob want a more preset-ey thing for the actual thin + # we probably honestly just want to oscillate between the same 4 presets + # in a predictable order such that they have a predictable outcome + periodic_p = random.choice([3]) + n_mask_codebooks = 3 + sampletemp = random.choice([1.0,]) + dropout = random.choice([0.0, 0.0]) + + top_p = None # NOTE: top p may be the culprit behind the collapse into single pitches. + + # parameters for the build_mask function + build_mask_kwargs = dict( + rand_mask_intensity=1.0, + prefix_s=0.0, + suffix_s=0.0, + periodic_prompt=int(periodic_p), + periodic_prompt2=int(periodic_p), + periodic_prompt_width=1, + _dropout=dropout, + upper_codebook_mask=int(n_mask_codebooks), + upper_codebook_mask_2=int(n_mask_codebooks), + ) + + # parameters for the vamp function + vamp_kwargs = dict( + temperature=sampletemp, + typical_filtering=True, + typical_mass=0.15, + typical_min_tokens=64, + top_p=top_p, + seed=seed, + sample_cutoff=1.0, + ) + + # save the mask as a txt file + interface.set_chunk_size(10.0) + sig, mask, codes = interface.vamp( + sig, + batch_size=1, + feedback_steps=1, + time_stretch_factor=1, + build_mask_kwargs=build_mask_kwargs, + vamp_kwargs=vamp_kwargs, + return_mask=True, + ) + + log(f"vamp took {time.time() - t0} seconds") + return sig + + + +def main(): + import tqdm + + interface = load_interface() + sig = AudioSignal.excerpt("assets/example.wav", duration=7.0) + sig = interface.preprocess(sig) + sig.write('ttout/in.wav') + insig = sig.clone() + + fdbk_every = 4 + fdbk = 0.5 + + for i in tqdm.tqdm(range(1000)): + sig = ez_variation(interface, sig, model_choice="orchestral") + sig.write(f'ttout/out{i}.wav') + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/unloop/.gitignore b/unloop/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a2ff4ac3f64beb5f57e7d56a314010b670e8d418 --- /dev/null +++ b/unloop/.gitignore @@ -0,0 +1 @@ +.gradio \ No newline at end of file diff --git a/unloop/_.md b/unloop/_.md new file mode 100644 index 0000000000000000000000000000000000000000..bb967b3c44e2793edd696a1370298b1d078cb75c --- /dev/null +++ b/unloop/_.md @@ -0,0 +1,73 @@ +## client side setup +clone +``` +https://github.com/hugofloresgarcia/unsound-objects.git +git checkout unloop +``` + +install +``` +conda create -n unsound python=3.10 +conda activate unsound +pip install -r requirements.txt +``` + +## server side setup +ssh into malleus +``` +ssh bryan@malleus.cs.northwestern.edu -L 7860:localhost:7860 +``` + +then leave the malleus window open and start up a new local window + +(kindly ask hugo to launch the gradio on port 7860) + +you can verify that the gradio is running by opening `http://localhost:7860` on your browser + +## launch the gradio server (vampnet) +you have to run the gradio server running vampnet model. +(on the remote machine) +```bash +conda create -n vampnet python=3.10 +git clone https://github.com/huggingface.co/spaces/hugggof/vampnet-music.git +pip install -e . +CUDA_VISIBLE_DEVICES=0 python app.py +``` + +### launch the gradio server (s2s) +you have to run the gradio server running audit model. + +(on the remote machine) +```bash +conda create -n audit python=3.10 +cd audit +pip install -r requirements.txt +CUDA_VISIBLE_DEVICES=0 python scripts/text2sfx/demo.py ckpts/adobe-soda/checkpoints/seethara/text2sfx/25-02-18-256ch-8s/ --model latest_ema.pth +``` + +or for audit-old +``` +CUDA_VISIBLE_DEVICES=0 python scripts/cdit/demos/voice2sfx.py ckpts/rms-centroid-ppg/latest.pth +``` + +## launch the client (laptop) +then launch the client from your local terminal +``` +python client.py --vampnet_url --s2s_url http://localhost:7860 +``` + +## max setup +Then...make sure you have installed (in Max) +``` +flucoma +``` + +MAKE SURE YOU ARE RUNNING MAX 8. It is not compatible with Max 9. + +Now open up the right max patch `./max/sound-objects.maxpat`. + +### text prompts +NOTE: text prompts are from the list here +https://universalcategorysystem.com/ +https://www.dropbox.com/scl/fo/lw1i20cgsm4edsvj3awn1/AP_ZhzG3LlpfFLbX309FbOU?dl=0&e=1&preview=UCS+v8.2.1+Full+List.xlsx&rlkey=wa2onzo0difpew1nze6odztlp +*** HUGO make an empty 'audio' directory in the repo! *** diff --git a/unloop/client.py b/unloop/client.py new file mode 100644 index 0000000000000000000000000000000000000000..0760f36c07de227bc5277e9c61a7a7a7201e4cbc --- /dev/null +++ b/unloop/client.py @@ -0,0 +1,253 @@ +import time +from pathlib import Path +import shutil +import json + +import argbind +import audiotools as at +from gradio_client import Client, handle_file +from pythonosc.osc_server import ThreadingOSCUDPServer +from pythonosc.udp_client import SimpleUDPClient +from pythonosc.dispatcher import Dispatcher +import torch + +class Timer: + + def __init__(self): + self.times = {} + + def tick(self, name: str): + self.times[name] = time.time() + + def tock(self, name: str): + toc = time.time() - self.times[name] + print(f"{name} took {toc} seconds") + return toc + + def __str__(self): + return str(self.times) + +timer = Timer() + +DOWNLOADS_DIR = ".gradio" + +def clear_file(file): + file = Path(file) + if file.exists(): + file.unlink() + + +class OSCManager: + + def __init__( + self, + ip: str, + s_port: str, + r_port: str, + process_fn: callable, + # param_change_callback: callable = None + ): + self.ip = ip + self.s_port = s_port + self.r_port = r_port + + # register the process_fn + self.process_fn = process_fn + + print(f"will send to {ip}:{s_port}") + self.client = SimpleUDPClient(ip, s_port) + + + def start_server(self,): + dispatcher = Dispatcher() + dispatcher.map("/process", self.process_fn) + + def send_heartbeat(_, *args): + # print("Received heartbeat") + self.client.send_message("/heartbeat", "pong") + + dispatcher.map("/heartbeat", lambda a, *r: send_heartbeat(a, *r)) + + dispatcher.map("/cleanup", lambda a, *r: clear_file(r[0])) + + dispatcher.set_default_handler(lambda a, *r: print(a, r)) + + server = ThreadingOSCUDPServer((self.ip, self.r_port), dispatcher) + print(f"Serving on {server.server_address}") + server.serve_forever() + + def error(self, msg: str): + self.client.send_message("/error", msg) + + def log(self, msg: str): + self.client.send_message("/log", msg) + + +class GradioOSCClient: + + def __init__(self, + ip: str, + s_port: int, r_port: int, + vampnet_url: str = None, # url for vampnet + ): + self.osc_manager = OSCManager( + ip=ip, s_port=s_port, r_port=r_port, + process_fn=self.process, + ) + + self.clients = {} + if vampnet_url is not None: + self.clients["vampnet"] = Client(src=vampnet_url, download_files=DOWNLOADS_DIR) + + assert len(self.clients) > 0, "At least one client must be specified!" + + self.batch_size = 2# TODO: automatically get batch size from client. + + self.osc_manager.log("hello from gradio client!") + + self.inf_idx = 0 + + + def param_changed(self, param_name, new_value): + print(f"Parameter {param_name} changed to {new_value}") + + def vampnet_process(self, address: str, *args): + client = self.clients["vampnet"] + + # query id --- audiofile ---- model_choice --- periodic --- drop --- seed + query_id = args[0] + client_type = args[1] + audio_path = Path(args[2]) + model_choice = args[3] + periodic_p = args[4] + dropout = args[5] + seed = args[6] + looplength_ms = args[7] + typical_filter = args[8] + typical_mass = args[9] + typical_min_tokens = args[10] + upper_codebook_mask = args[11] + onset_mask_width = args[12] + sampling_steps = args[13] + temperature = args[14] + top_p = args[15] + beat_mask_ms = args[16] + num_feedback_steps = args[17] + + if not audio_path.exists(): + print(f"File {audio_path} does not exist") + self.osc_manager.error(f"File {audio_path} does not exist") + return + + sig = at.AudioSignal(audio_path) + sig.to_mono() + sig.sample_rate = 48000 # HOT PATCH (FIXME IN MAX: sample rate is being forced to 48k) + + # grab the looplength only + # TODO: although I added this, + # the max patch is still configured to crop anything past the looplength off + # so we'll have to change that in order to make an effect. + end_sample = int((looplength_ms * sig.sample_rate) / 1000) + + # grab the remainder of the waveform + num_cut_samples = sig.samples.shape[-1] - end_sample + cut_wav = sig.samples[..., -num_cut_samples:] + + sig.samples = sig.samples[..., :end_sample] + # write the file back + sig.write(audio_path) + + timer.tick("predict") + print(f"Processing {address} with args {args}") + # breakpoint() + job = client.submit( + input_audio=handle_file(audio_path), + sampletemp=temperature, + top_p=top_p, + periodic_p=periodic_p, + dropout=dropout, + stretch_factor=1, + onset_mask_width=onset_mask_width, + typical_filtering=bool(typical_filter), + typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens, + seed=seed, + model_choice=model_choice, + n_mask_codebooks=upper_codebook_mask, + pitch_shift_amt=0, + sample_cutoff=1.0, + sampling_steps=sampling_steps, + beat_mask_ms=int(beat_mask_ms), + num_feedback_steps=num_feedback_steps, + api_name="/vamp_1" + ) + + while not job.done(): + time.sleep(0.1) + self.osc_manager.client.send_message("/progress", [query_id, str(job.status().code)]) + + result = job.result() + # audio_file = result + # audio_files = [audio_file] * self.batch_size + audio_files = list(result[:self.batch_size]) + # if each file is missing a .wav at the end, add it + first_audio = audio_files[0] + if not first_audio.endswith(".wav"): + for audio_file in set(audio_files): + if not audio_file.endswith(".wav"): + shutil.move(audio_file, f"{audio_file}.wav") + audio_file = f"{audio_file}.wav" + audio_files = [f"{audio}.wav" for audio in audio_files if not audio.endswith(".wav")] + + for audio_file in audio_files: + # load the file, add the cut samples back + sig = at.AudioSignal(audio_file) + sig.resample(48000) + sig.samples = torch.cat([sig.samples, cut_wav], dim=-1) + sig.write(audio_file) + seed = result[-1] + + timer.tock("predict") + + # send a message that the process is done + self.osc_manager.log(f"query {query_id} has been processed") + self.osc_manager.client.send_message("/process-result", [query_id] + audio_files) + + + def process(self, address: str, *args): + query_id = args[0] + client_type = args[1] + audio_path = Path(args[2]) + + if client_type == "vampnet": + self.vampnet_process(address, *args) + return + elif client_type == "sketch2sound": + self.process_s2s(address, *args) + return + else: + raise ValueError(f"Unknown client type {client_type}") + +def gradio_main( + vampnet_url: str = None +): + system = GradioOSCClient( + vampnet_url=vampnet_url, + ip="127.0.0.1", s_port=8003, r_port=8001, + ) + + system.osc_manager.start_server() + + +if __name__ == "__main__": + try: + gradio_main = argbind.bind(gradio_main, without_prefix=True) + + args = argbind.parse_args() + with argbind.scope(args): + gradio_main() + + except Exception as e: + import shutil + shutil.rmtree(DOWNLOADS_DIR, ignore_errors=True) + raise e \ No newline at end of file diff --git a/unloop/max/choose_from_list.js b/unloop/max/choose_from_list.js new file mode 100644 index 0000000000000000000000000000000000000000..9d4ef205ba4b124a75d9550a2a5572a3fef895cf --- /dev/null +++ b/unloop/max/choose_from_list.js @@ -0,0 +1,7 @@ +subdivs = [0.125, 0.25, 0.5, 1, 2, 4]; +subdivs = subdivs.map(function(x) { return x; }); + +function bang() { + var i = Math.floor(Math.random() * subdivs.length); + outlet(0, subdivs[i]); +} \ No newline at end of file diff --git a/unloop/max/click.maxpat b/unloop/max/click.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..40cee20acb979e361c53813de4ab91d739ecbd4b --- /dev/null +++ b/unloop/max/click.maxpat @@ -0,0 +1,551 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-323", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 129.751264274120331, 104.0, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-321", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 59.239391028881073, 100.0, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-319", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 108.0, 266.418817639350891, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-317", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 129.751264274120331, 135.0, 32.0, 22.0 ], + "text" : "t b b" + } + + } +, { + "box" : { + "id" : "obj-316", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 59.239391028881073, 129.0, 32.0, 22.0 ], + "text" : "t b b" + } + + } +, { + "box" : { + "id" : "obj-311", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 150.735043168067932, 223.683774471282959, 29.5, 22.0 ], + "text" : "600" + } + + } +, { + "box" : { + "id" : "obj-310", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 108.0, 223.683774471282959, 29.5, 22.0 ], + "text" : "400" + } + + } +, { + "box" : { + "id" : "obj-307", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 579.222337603569031, 292.05984354019165, 77.0, 22.0 ], + "text" : "loadmess 80" + } + + } +, { + "box" : { + "id" : "obj-284", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 509.991567671298981, 297.188048720359802, 29.5, 22.0 ], + "text" : "* 8" + } + + } +, { + "box" : { + "id" : "obj-286", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 451.871908962726593, 353.598305702209473, 106.0, 22.0 ], + "text" : "reson~ 1. 100. 10." + } + + } +, { + "box" : { + "id" : "obj-281", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 50.0, 432.230785131454468, 40.0, 22.0 ], + "text" : "*~ 40." + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-279", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 579.222337603569031, 319.410271167755127, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-272", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 380.795777916908264, 300.606852173805237, 29.5, 22.0 ], + "text" : "* 4" + } + + } +, { + "box" : { + "id" : "obj-275", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 322.795777916908264, 356.66199141740799, 106.0, 22.0 ], + "text" : "reson~ 1. 100. 10." + } + + } +, { + "box" : { + "id" : "obj-264", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 247.598402619361877, 300.606852173805237, 29.5, 22.0 ], + "text" : "* 2" + } + + } +, { + "box" : { + "id" : "obj-259", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 189.47874391078949, 356.66199141740799, 106.0, 22.0 ], + "text" : "reson~ 1. 100. 10." + } + + } +, { + "box" : { + "id" : "obj-200", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 50.0, 266.418817639350891, 39.0, 22.0 ], + "text" : "click~" + } + + } +, { + "box" : { + "id" : "obj-4", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 50.0, 356.66199141740799, 106.0, 22.0 ], + "text" : "reson~ 1. 100. 10." + } + + } +, { + "box" : { + "comment" : "1 enables click, 0 disables.", + "id" : "obj-324", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 59.239391028881073, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "bang for beat", + "id" : "obj-325", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 104.239391028881073, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "bang for downbeat", + "id" : "obj-326", + "index" : 3, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 175.239391028881073, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "signal out", + "id" : "obj-327", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 49.999889028881171, 514.23083500000007, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-259", 0 ], + "order" : 1, + "source" : [ "obj-200", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-275", 0 ], + "order" : 0, + "source" : [ "obj-200", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "order" : 2, + "source" : [ "obj-200", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-281", 0 ], + "source" : [ "obj-259", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-259", 2 ], + "source" : [ "obj-264", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-275", 2 ], + "source" : [ "obj-272", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-281", 0 ], + "source" : [ "obj-275", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-259", 3 ], + "order" : 2, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-275", 3 ], + "order" : 1, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-286", 3 ], + "order" : 0, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 3 ], + "order" : 3, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-327", 0 ], + "source" : [ "obj-281", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-286", 2 ], + "source" : [ "obj-284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-281", 0 ], + "source" : [ "obj-286", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-279", 0 ], + "source" : [ "obj-307", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-319", 0 ], + "source" : [ "obj-310", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-319", 0 ], + "source" : [ "obj-311", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-200", 0 ], + "source" : [ "obj-316", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-310", 0 ], + "source" : [ "obj-316", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-200", 0 ], + "source" : [ "obj-317", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-311", 0 ], + "source" : [ "obj-317", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-264", 0 ], + "order" : 2, + "source" : [ "obj-319", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-272", 0 ], + "order" : 1, + "source" : [ "obj-319", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-284", 0 ], + "order" : 0, + "source" : [ "obj-319", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 2 ], + "order" : 3, + "source" : [ "obj-319", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-316", 0 ], + "source" : [ "obj-321", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-317", 0 ], + "source" : [ "obj-323", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-321", 0 ], + "order" : 1, + "source" : [ "obj-324", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-323", 0 ], + "order" : 0, + "source" : [ "obj-324", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-321", 1 ], + "source" : [ "obj-325", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-323", 1 ], + "source" : [ "obj-326", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-281", 0 ], + "source" : [ "obj-4", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/dry-wet.maxpat b/unloop/max/dry-wet.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..41868d75861e9a8e8417878621a6fd008b6710d1 --- /dev/null +++ b/unloop/max/dry-wet.maxpat @@ -0,0 +1,282 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 84.0, 131.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-154", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 163.354036390781403, 177.018632590770721, 39.0, 22.0 ], + "presentation" : 1, + "presentation_rect" : [ 1469.090271848838711, 2039.0, 39.0, 22.0 ], + "text" : "atodb" + } + + } +, { + "box" : { + "id" : "obj-156", + "lastchannelcount" : 0, + "maxclass" : "live.gain~", + "numinlets" : 2, + "numoutlets" : 5, + "outlettype" : [ "signal", "signal", "", "float", "list" ], + "parameter_enable" : 1, + "patching_rect" : [ 133.0, 223.0, 48.0, 136.0 ], + "presentation" : 1, + "presentation_rect" : [ 1469.090271848838711, 2101.0, 48.0, 136.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_longname" : "live.gain~[26]", + "parameter_mmax" : 6.0, + "parameter_mmin" : -70.0, + "parameter_modmode" : 0, + "parameter_shortname" : "live.gain~", + "parameter_type" : 0, + "parameter_unitstyle" : 4 + } + + } +, + "varname" : "live.gain~[1]" + } + + } +, { + "box" : { + "id" : "obj-157", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 163.354036390781403, 140.37267005443573, 29.5, 22.0 ], + "presentation" : 1, + "presentation_rect" : [ 1469.090271848838711, 2009.0, 29.5, 22.0 ], + "text" : "!- 1." + } + + } +, { + "box" : { + "id" : "obj-158", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 61.0, 100.0, 90.0, 22.0 ], + "presentation" : 1, + "presentation_rect" : [ 1397.090271848838711, 1978.0, 94.0, 22.0 ], + "text" : "scale 0. 1. 1. 0." + } + + } +, { + "box" : { + "id" : "obj-160", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 168.944098472595215, 39.0, 22.0 ], + "presentation" : 1, + "presentation_rect" : [ 1386.090271848838711, 2039.0, 39.0, 22.0 ], + "text" : "atodb" + } + + } +, { + "box" : { + "id" : "obj-162", + "lastchannelcount" : 0, + "maxclass" : "live.gain~", + "numinlets" : 2, + "numoutlets" : 5, + "outlettype" : [ "signal", "signal", "", "float", "list" ], + "parameter_enable" : 1, + "patching_rect" : [ 50.0, 223.0, 48.0, 136.0 ], + "presentation" : 1, + "presentation_rect" : [ 1386.090271848838711, 2101.0, 48.0, 136.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_longname" : "live.gain~[25]", + "parameter_mmax" : 6.0, + "parameter_mmin" : -70.0, + "parameter_modmode" : 0, + "parameter_shortname" : "live.gain~", + "parameter_type" : 0, + "parameter_unitstyle" : 4 + } + + } +, + "varname" : "live.gain~" + } + + } +, { + "box" : { + "comment" : "dry", + "id" : "obj-216", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 25.000060151161279, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "mix", + "id" : "obj-223", + "index" : 3, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 313.0, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "wet", + "id" : "obj-227", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 133.0, 44.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-230", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 419.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-156", 0 ], + "source" : [ "obj-154", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-230", 0 ], + "source" : [ "obj-156", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-154", 0 ], + "source" : [ "obj-157", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-157", 0 ], + "order" : 0, + "source" : [ "obj-158", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-160", 0 ], + "order" : 1, + "source" : [ "obj-158", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-162", 0 ], + "source" : [ "obj-160", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-230", 0 ], + "source" : [ "obj-162", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-162", 0 ], + "source" : [ "obj-216", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-158", 0 ], + "source" : [ "obj-223", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-156", 0 ], + "source" : [ "obj-227", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/environ.json b/unloop/max/environ.json new file mode 100644 index 0000000000000000000000000000000000000000..c5cf6b7d9b91716a2ff1ad822401048505e633df --- /dev/null +++ b/unloop/max/environ.json @@ -0,0 +1,391 @@ +{ + "pattrstorage" : { + "name" : "environ", + "slots" : { + "1" : { + "id" : 1, + "data" : { + "live.gain~" : [ -22.080297807457285 ], + "dur_ms[2]" : [ ], + "mc.live.gain~[1]" : [ ], + "dur_ms[1]" : [ ], + "mc.live.gain~" : [ ], + "lfo[1]::lfofreq" : [ 0.01 ], + "lfo[1]::lfomax" : [ 30.0 ], + "lfo[1]::lfomin" : [ 0.1 ], + "lfo[1]::lfosync" : [ 0 ], + "lfo[1]::lfowave" : [ 1 ], + "lfo[1]::toggle" : [ 1 ], + "lfo[3]::lfofreq" : [ 0.5 ], + "lfo[3]::lfomax" : [ 1000.0 ], + "lfo[3]::lfomin" : [ 100.0 ], + "lfo[3]::lfosync" : [ 0 ], + "lfo[3]::lfowave" : [ 5 ], + "lfo[3]::toggle" : [ 1 ], + "patternclock::loop" : [ 512 ], + "patternclock::regen" : [ 0.0 ], + "patternclock::rskip" : [ 0.485826771653543 ], + "patternclock::tempo" : [ "4n" ], + "patternclock::toggle" : [ 1 ], + "patternclock[1]::loop" : [ 512 ], + "patternclock[1]::regen" : [ 0.0 ], + "patternclock[1]::rskip" : [ 0.795275590551181 ], + "patternclock[1]::tempo" : [ "4n" ], + "patternclock[1]::toggle" : [ 1 ], + "basic-seq::seq-key" : [ 60.0 ], + "basic-seq::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[9]::lfofreq" : [ 0.322726627789502 ], + "lfo[9]::lfomax" : [ 60.0 ], + "lfo[9]::lfomin" : [ 50.0 ], + "lfo[9]::lfosync" : [ 0 ], + "lfo[9]::lfowave" : [ 4 ], + "lfo[9]::toggle" : [ 1 ], + "dimensynth-gui::attack" : [ 0.053124792475848 ], + "dimensynth-gui::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui::cwo-sideband" : [ 0.5 ], + "dimensynth-gui::decay" : [ 1115.397287487219273 ], + "dimensynth-gui::freq" : [ 499.999999999999886 ], + "dimensynth-gui::gain" : [ -8.275590551181157 ], + "dimensynth-gui::interp" : [ 0.522283464566928 ], + "dimensynth-gui::outgain" : [ -8.275590551181157 ], + "dimensynth-gui::release" : [ 135.817358126579933 ], + "dimensynth-gui::reson" : [ 0.623385826771653 ], + "dimensynth-gui::sustain" : [ 0.490701756169608 ], + "dimensynth-gui::vibamt" : [ 0.1 ], + "dimensynth-gui::vibfreq" : [ 7.343913385826769 ], + "patternclock[2]::loop" : [ 512 ], + "patternclock[2]::regen" : [ 0.0 ], + "patternclock[2]::rskip" : [ 0.1 ], + "patternclock[2]::tempo" : [ "4n" ], + "patternclock[2]::toggle" : [ 1 ], + "basic-seq[2]::seq-key" : [ 60.0 ], + "basic-seq[2]::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[2]::lfofreq" : [ 0.01 ], + "lfo[2]::lfomax" : [ 60.0 ], + "lfo[2]::lfomin" : [ 50.0 ], + "lfo[2]::lfosync" : [ 0 ], + "lfo[2]::lfowave" : [ 1 ], + "lfo[2]::toggle" : [ 1 ], + "dimensynth-gui[1]::attack" : [ 0.053124792475848 ], + "dimensynth-gui[1]::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui[1]::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui[1]::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui[1]::cwo-sideband" : [ 0.5 ], + "dimensynth-gui[1]::decay" : [ 1115.397287487219273 ], + "dimensynth-gui[1]::freq" : [ 499.999999999999886 ], + "dimensynth-gui[1]::gain" : [ -8.275590551181157 ], + "dimensynth-gui[1]::interp" : [ 0.522283464566928 ], + "dimensynth-gui[1]::outgain" : [ -8.275590551181157 ], + "dimensynth-gui[1]::release" : [ 135.817358126579933 ], + "dimensynth-gui[1]::reson" : [ 0.623385826771653 ], + "dimensynth-gui[1]::sustain" : [ 0.490701756169608 ], + "dimensynth-gui[1]::vibamt" : [ 0.1 ], + "dimensynth-gui[1]::vibfreq" : [ 7.343913385826769 ], + "patternclock[3]::loop" : [ 512 ], + "patternclock[3]::regen" : [ 0.0 ], + "patternclock[3]::rskip" : [ 0.1 ], + "patternclock[3]::tempo" : [ "4n" ], + "patternclock[3]::toggle" : [ 1 ], + "basic-seq[1]::seq-key" : [ 60.0 ], + "basic-seq[1]::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[4]::lfofreq" : [ 0.01 ], + "lfo[4]::lfomax" : [ 60.0 ], + "lfo[4]::lfomin" : [ 50.0 ], + "lfo[4]::lfosync" : [ 0 ], + "lfo[4]::lfowave" : [ 1 ], + "lfo[4]::toggle" : [ 1 ], + "dimensynth-gui[2]::attack" : [ 0.053124792475848 ], + "dimensynth-gui[2]::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui[2]::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui[2]::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui[2]::cwo-sideband" : [ 0.5 ], + "dimensynth-gui[2]::decay" : [ 1115.397287487219273 ], + "dimensynth-gui[2]::freq" : [ 499.999999999999886 ], + "dimensynth-gui[2]::gain" : [ -8.275590551181157 ], + "dimensynth-gui[2]::interp" : [ 0.522283464566928 ], + "dimensynth-gui[2]::outgain" : [ -8.275590551181157 ], + "dimensynth-gui[2]::release" : [ 135.817358126579933 ], + "dimensynth-gui[2]::reson" : [ 0.623385826771653 ], + "dimensynth-gui[2]::sustain" : [ 0.490701756169608 ], + "dimensynth-gui[2]::vibamt" : [ 0.1 ], + "dimensynth-gui[2]::vibfreq" : [ 7.343913385826769 ], + "lfo[5]::lfofreq" : [ 0.01 ], + "lfo[5]::lfomax" : [ 1.0 ], + "lfo[5]::lfomin" : [ 0.0 ], + "lfo[5]::lfosync" : [ 0 ], + "lfo[5]::lfowave" : [ 1 ], + "lfo[5]::toggle" : [ 1 ], + "lfo::lfofreq" : [ ], + "lfo::lfomax" : [ ], + "lfo::lfomin" : [ ], + "lfo::lfosync" : [ ], + "lfo::lfowave" : [ ], + "lfo::toggle" : [ ], + "lfo[11]::lfofreq" : [ ], + "lfo[11]::lfomax" : [ ], + "lfo[11]::lfomin" : [ ], + "lfo[11]::lfosync" : [ ], + "lfo[11]::lfowave" : [ ], + "lfo[11]::toggle" : [ ], + "patternclock[5]::loop" : [ ], + "patternclock[5]::regen" : [ ], + "patternclock[5]::rskip" : [ ], + "patternclock[5]::tempo" : [ ], + "patternclock[5]::toggle" : [ ], + "cakelayer-ui::dur" : [ ], + "cakelayer-ui::env" : [ ], + "cakelayer-ui::number" : [ ], + "cakelayer-ui::number[1]" : [ ], + "cakelayer-ui::pos" : [ ], + "cakelayer-ui::pshift" : [ ], + "cakelayer-ui::spray" : [ ], + "lfo[10]::lfofreq" : [ ], + "lfo[10]::lfomax" : [ ], + "lfo[10]::lfomin" : [ ], + "lfo[10]::lfosync" : [ ], + "lfo[10]::lfowave" : [ ], + "lfo[10]::toggle" : [ ], + "lfo[8]::lfofreq" : [ ], + "lfo[8]::lfomax" : [ ], + "lfo[8]::lfomin" : [ ], + "lfo[8]::lfosync" : [ ], + "lfo[8]::lfowave" : [ ], + "lfo[8]::toggle" : [ ], + "lfo[7]::lfofreq" : [ ], + "lfo[7]::lfomax" : [ ], + "lfo[7]::lfomin" : [ ], + "lfo[7]::lfosync" : [ ], + "lfo[7]::lfowave" : [ ], + "lfo[7]::toggle" : [ ], + "patternclock[4]::loop" : [ ], + "patternclock[4]::regen" : [ ], + "patternclock[4]::rskip" : [ ], + "patternclock[4]::tempo" : [ ], + "patternclock[4]::toggle" : [ ], + "cakelayer-ui[1]::dur" : [ ], + "cakelayer-ui[1]::env" : [ ], + "cakelayer-ui[1]::number" : [ ], + "cakelayer-ui[1]::number[1]" : [ ], + "cakelayer-ui[1]::pos" : [ ], + "cakelayer-ui[1]::pshift" : [ ], + "cakelayer-ui[1]::spray" : [ ], + "lfo[6]::lfofreq" : [ ], + "lfo[6]::lfomax" : [ ], + "lfo[6]::lfomin" : [ ], + "lfo[6]::lfosync" : [ ], + "lfo[6]::lfowave" : [ ], + "lfo[6]::toggle" : [ ], + "lfo[12]::lfofreq" : [ ], + "lfo[12]::lfomax" : [ ], + "lfo[12]::lfomin" : [ ], + "lfo[12]::lfosync" : [ ], + "lfo[12]::lfowave" : [ ], + "lfo[12]::toggle" : [ ], + "lfo[13]::lfofreq" : [ ], + "lfo[13]::lfomax" : [ ], + "lfo[13]::lfomin" : [ ], + "lfo[13]::lfosync" : [ ], + "lfo[13]::lfowave" : [ ], + "lfo[13]::toggle" : [ ] + } + + } +, + "3" : { + "id" : 3, + "data" : { + "live.gain~" : [ -22.080297807457285 ], + "dur_ms[2]" : [ 0.0 ], + "mc.live.gain~[1]" : [ 0.0 ], + "dur_ms[1]" : [ 0.0 ], + "mc.live.gain~" : [ -2.763346551852102 ], + "lfo[1]::lfofreq" : [ 0.322726627789502 ], + "lfo[1]::lfomax" : [ 1.0 ], + "lfo[1]::lfomin" : [ 0.0 ], + "lfo[1]::lfosync" : [ 0 ], + "lfo[1]::lfowave" : [ 4 ], + "lfo[1]::toggle" : [ 1 ], + "lfo[3]::lfofreq" : [ 0.322726627789502 ], + "lfo[3]::lfomax" : [ 800.0 ], + "lfo[3]::lfomin" : [ 200.0 ], + "lfo[3]::lfosync" : [ 0 ], + "lfo[3]::lfowave" : [ 4 ], + "lfo[3]::toggle" : [ 0 ], + "patternclock::loop" : [ 8 ], + "patternclock::regen" : [ 0.0 ], + "patternclock::rskip" : [ 0.194488188976378 ], + "patternclock::tempo" : [ "4n" ], + "patternclock::toggle" : [ 0 ], + "patternclock[1]::loop" : [ 512 ], + "patternclock[1]::regen" : [ 0.0 ], + "patternclock[1]::rskip" : [ 0.493700787401575 ], + "patternclock[1]::tempo" : [ "1n" ], + "patternclock[1]::toggle" : [ 1 ], + "basic-seq::seq-key" : [ 60.0 ], + "basic-seq::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[9]::lfofreq" : [ 0.322726627789502 ], + "lfo[9]::lfomax" : [ 70.0 ], + "lfo[9]::lfomin" : [ 40.0 ], + "lfo[9]::lfosync" : [ 0 ], + "lfo[9]::lfowave" : [ 4 ], + "lfo[9]::toggle" : [ 0 ], + "dimensynth-gui::attack" : [ 10.0 ], + "dimensynth-gui::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui::cwo-sideband" : [ 0.625984251968504 ], + "dimensynth-gui::decay" : [ 113.394636070258258 ], + "dimensynth-gui::freq" : [ 499.999999999999886 ], + "dimensynth-gui::gain" : [ -8.275590551181157 ], + "dimensynth-gui::interp" : [ 0.522283464566928 ], + "dimensynth-gui::outgain" : [ -8.275590551181157 ], + "dimensynth-gui::release" : [ 100.0 ], + "dimensynth-gui::reson" : [ 0.623385826771653 ], + "dimensynth-gui::sustain" : [ 0.619824565649974 ], + "dimensynth-gui::vibamt" : [ 0.1 ], + "dimensynth-gui::vibfreq" : [ 7.343913385826769 ], + "patternclock[2]::loop" : [ 8 ], + "patternclock[2]::regen" : [ 0.0 ], + "patternclock[2]::rskip" : [ 0.283464566929134 ], + "patternclock[2]::tempo" : [ "4n" ], + "patternclock[2]::toggle" : [ 0 ], + "basic-seq[2]::seq-key" : [ 60.0 ], + "basic-seq[2]::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[2]::lfofreq" : [ 0.322726627789502 ], + "lfo[2]::lfomax" : [ 500.0 ], + "lfo[2]::lfomin" : [ 509.0 ], + "lfo[2]::lfosync" : [ 0 ], + "lfo[2]::lfowave" : [ 4 ], + "lfo[2]::toggle" : [ 0 ], + "dimensynth-gui[1]::attack" : [ 10.0 ], + "dimensynth-gui[1]::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui[1]::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui[1]::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui[1]::cwo-sideband" : [ 0.625984251968504 ], + "dimensynth-gui[1]::decay" : [ 189.512213117701407 ], + "dimensynth-gui[1]::freq" : [ 499.999999999999886 ], + "dimensynth-gui[1]::gain" : [ -8.275590551181157 ], + "dimensynth-gui[1]::interp" : [ 0.522283464566928 ], + "dimensynth-gui[1]::outgain" : [ -8.275590551181157 ], + "dimensynth-gui[1]::release" : [ 157.589078697424071 ], + "dimensynth-gui[1]::reson" : [ 0.623385826771653 ], + "dimensynth-gui[1]::sustain" : [ 0.619824565649974 ], + "dimensynth-gui[1]::vibamt" : [ 0.1 ], + "dimensynth-gui[1]::vibfreq" : [ 7.343913385826769 ], + "patternclock[3]::loop" : [ 8 ], + "patternclock[3]::regen" : [ 0.0 ], + "patternclock[3]::rskip" : [ 0.118110236220472 ], + "patternclock[3]::tempo" : [ "4n" ], + "patternclock[3]::toggle" : [ 0 ], + "basic-seq[1]::seq-key" : [ 60.0 ], + "basic-seq[1]::seq-notes" : [ "0 4 2 7 5 9" ], + "lfo[4]::lfofreq" : [ 0.322726627789502 ], + "lfo[4]::lfomax" : [ 50.0 ], + "lfo[4]::lfomin" : [ 50.0 ], + "lfo[4]::lfosync" : [ 0 ], + "lfo[4]::lfowave" : [ 4 ], + "lfo[4]::toggle" : [ 0 ], + "dimensynth-gui[2]::attack" : [ 10.0 ], + "dimensynth-gui[2]::cwo-delay" : [ 155.381300762601285 ], + "dimensynth-gui[2]::cwo-feedback" : [ 0.802913385826772 ], + "dimensynth-gui[2]::cwo-freq" : [ 16.834453468907526 ], + "dimensynth-gui[2]::cwo-sideband" : [ 0.625984251968504 ], + "dimensynth-gui[2]::decay" : [ 58.478874083615899 ], + "dimensynth-gui[2]::freq" : [ 499.999999999999886 ], + "dimensynth-gui[2]::gain" : [ -8.275590551181157 ], + "dimensynth-gui[2]::interp" : [ 0.522283464566928 ], + "dimensynth-gui[2]::outgain" : [ -8.275590551181157 ], + "dimensynth-gui[2]::release" : [ 197.356350725103312 ], + "dimensynth-gui[2]::reson" : [ 0.623385826771653 ], + "dimensynth-gui[2]::sustain" : [ 0.684385970390157 ], + "dimensynth-gui[2]::vibamt" : [ 0.1 ], + "dimensynth-gui[2]::vibfreq" : [ 7.343913385826769 ], + "lfo[5]::lfofreq" : [ 0.322726627789502 ], + "lfo[5]::lfomax" : [ 1.0 ], + "lfo[5]::lfomin" : [ 0.0 ], + "lfo[5]::lfosync" : [ 0 ], + "lfo[5]::lfowave" : [ 4 ], + "lfo[5]::toggle" : [ 1 ], + "lfo::lfofreq" : [ 0.2 ], + "lfo::lfomax" : [ 1.0 ], + "lfo::lfomin" : [ 0.0 ], + "lfo::lfosync" : [ 0 ], + "lfo::lfowave" : [ 2 ], + "lfo::toggle" : [ 0 ], + "lfo[11]::lfofreq" : [ 2.0 ], + "lfo[11]::lfomax" : [ 800.0 ], + "lfo[11]::lfomin" : [ 300.0 ], + "lfo[11]::lfosync" : [ 0 ], + "lfo[11]::lfowave" : [ 5 ], + "lfo[11]::toggle" : [ 0 ], + "patternclock[5]::loop" : [ 512 ], + "patternclock[5]::regen" : [ 0.0 ], + "patternclock[5]::rskip" : [ 0.351968503937008 ], + "patternclock[5]::tempo" : [ "16n" ], + "patternclock[5]::toggle" : [ 1 ], + "cakelayer-ui::dur" : [ 1330.04875022813053 ], + "cakelayer-ui::env" : [ 0.496062992125984 ], + "cakelayer-ui::number" : [ 1330.04875022813053 ], + "cakelayer-ui::number[1]" : [ -12.0 ], + "cakelayer-ui::pos" : [ 0.582597235011068 ], + "cakelayer-ui::pshift" : [ -12.0 ], + "cakelayer-ui::spray" : [ 0.102362204724409 ], + "lfo[10]::lfofreq" : [ 0.2 ], + "lfo[10]::lfomax" : [ 1.0 ], + "lfo[10]::lfomin" : [ 0.0 ], + "lfo[10]::lfosync" : [ 0 ], + "lfo[10]::lfowave" : [ 2 ], + "lfo[10]::toggle" : [ 0 ], + "lfo[8]::lfofreq" : [ 2.0 ], + "lfo[8]::lfomax" : [ 800.0 ], + "lfo[8]::lfomin" : [ 300.0 ], + "lfo[8]::lfosync" : [ 0 ], + "lfo[8]::lfowave" : [ 5 ], + "lfo[8]::toggle" : [ 0 ], + "lfo[7]::lfofreq" : [ 2.0 ], + "lfo[7]::lfomax" : [ 1.0 ], + "lfo[7]::lfomin" : [ 0.0 ], + "lfo[7]::lfosync" : [ 0 ], + "lfo[7]::lfowave" : [ 1 ], + "lfo[7]::toggle" : [ 0 ], + "patternclock[4]::loop" : [ 512 ], + "patternclock[4]::regen" : [ 0.0 ], + "patternclock[4]::rskip" : [ 0.1 ], + "patternclock[4]::tempo" : [ "4n" ], + "patternclock[4]::toggle" : [ 1 ], + "cakelayer-ui[1]::dur" : [ 1191.605441045505586 ], + "cakelayer-ui[1]::env" : [ 0.496062992125984 ], + "cakelayer-ui[1]::number" : [ 1191.605441045505586 ], + "cakelayer-ui[1]::number[1]" : [ 12.0 ], + "cakelayer-ui[1]::pos" : [ 0.839060223709629 ], + "cakelayer-ui[1]::pshift" : [ 12.0 ], + "cakelayer-ui[1]::spray" : [ 0.102362204724409 ], + "lfo[6]::lfofreq" : [ 0.322726627789502 ], + "lfo[6]::lfomax" : [ 2.0 ], + "lfo[6]::lfomin" : [ -2.0 ], + "lfo[6]::lfosync" : [ 0 ], + "lfo[6]::lfowave" : [ 4 ], + "lfo[6]::toggle" : [ 0 ], + "lfo[12]::lfofreq" : [ 0.311365245459736 ], + "lfo[12]::lfomax" : [ 2400.0 ], + "lfo[12]::lfomin" : [ 100.0 ], + "lfo[12]::lfosync" : [ 0 ], + "lfo[12]::lfowave" : [ 4 ], + "lfo[12]::toggle" : [ 0 ], + "lfo[13]::lfofreq" : [ 0.489015340083276 ], + "lfo[13]::lfomax" : [ 1.0 ], + "lfo[13]::lfomin" : [ 0.0 ], + "lfo[13]::lfosync" : [ 0 ], + "lfo[13]::lfowave" : [ 1 ], + "lfo[13]::toggle" : [ 1 ] + } + + } + + } + + } + +} diff --git a/unloop/max/panner-cleat.maxpat b/unloop/max/panner-cleat.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..3e2e949c0ec07b45ed4bf110e9056a5a76e70204 --- /dev/null +++ b/unloop/max/panner-cleat.maxpat @@ -0,0 +1,327 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 0, + "patching_rect" : [ 364.666666666666629, 337.068983197212219, 75.0, 22.0 ], + "text" : "dac~ 1 2 3 4" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 4, + "outlettype" : [ "signal", "signal", "signal", "signal" ], + "patching_rect" : [ 369.0, 305.0, 62.0, 22.0 ], + "text" : "quadpan~" + } + + } +, { + "box" : { + "id" : "obj-211", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 0, + "patching_rect" : [ 112.0, 336.89655339717865, 55.0, 22.0 ], + "text" : "dac~ 1 2" + } + + } +, { + "box" : { + "id" : "obj-200", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 229.5, 225.0, 114.0, 22.0 ], + "text" : "scale 0. 1000. -1. 1." + } + + } +, { + "box" : { + "id" : "obj-198", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 2, + "outlettype" : [ "signal", "signal" ], + "patching_rect" : [ 112.0, 305.0, 50.5, 22.0 ], + "text" : "pan2" + } + + } +, { + "box" : { + "id" : "obj-194", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "float" ], + "patching_rect" : [ 229.5, 174.0, 74.0, 22.0 ], + "text" : "unpack 0. 0." + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-193", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 112.0, 186.0, 92.0, 22.0 ], + "text" : "r panner-choice" + } + + } +, { + "box" : { + "id" : "obj-185", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 3, + "outlettype" : [ "signal", "signal", "signal" ], + "patching_rect" : [ 112.0, 217.0, 49.0, 22.0 ], + "text" : "gate~ 3" + } + + } +, { + "box" : { + "id" : "obj-184", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 0, + "patching_rect" : [ 221.5, 305.0, 59.0, 22.0 ], + "text" : "16panner" + } + + } +, { + "box" : { + "id" : "obj-43", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 229.5, 128.0, 51.0, 22.0 ], + "text" : "route xy" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-213", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 142.0, 76.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-214", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 229.5, 76.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-184", 0 ], + "source" : [ "obj-185", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-198", 0 ], + "source" : [ "obj-185", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-185", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-185", 0 ], + "source" : [ "obj-193", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-184", 2 ], + "order" : 1, + "source" : [ "obj-194", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-184", 1 ], + "order" : 1, + "source" : [ "obj-194", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 2 ], + "order" : 0, + "source" : [ "obj-194", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 1 ], + "order" : 0, + "source" : [ "obj-194", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-200", 0 ], + "order" : 2, + "source" : [ "obj-194", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-211", 1 ], + "source" : [ "obj-198", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-211", 0 ], + "source" : [ "obj-198", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 3 ], + "source" : [ "obj-2", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 2 ], + "source" : [ "obj-2", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 1 ], + "source" : [ "obj-2", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-198", 1 ], + "source" : [ "obj-200", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-185", 1 ], + "source" : [ "obj-213", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-43", 0 ], + "source" : [ "obj-214", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-194", 0 ], + "source" : [ "obj-43", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/pan~.maxpat b/unloop/max/pan~.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..bec960a114b71d17df90d7322a5d9a697bb4f0aa --- /dev/null +++ b/unloop/max/pan~.maxpat @@ -0,0 +1,283 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 664.0, 441.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-2", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 241.0, 273.0, 29.5, 22.0 ], + "text" : "*~" + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 160.0, 273.0, 29.5, 22.0 ], + "text" : "*~" + } + + } +, { + "box" : { + "comment" : "right signal", + "id" : "obj-28", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 241.0, 316.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "left signal", + "id" : "obj-27", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 160.0, 316.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-26", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 160.0, 230.0, 43.0, 22.0 ], + "text" : "cycle~" + } + + } +, { + "box" : { + "id" : "obj-25", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 241.0, 230.0, 43.0, 22.0 ], + "text" : "cycle~" + } + + } +, { + "box" : { + "id" : "obj-24", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 265.0, 182.0, 49.0, 22.0 ], + "text" : "+~ 0.75" + } + + } +, { + "box" : { + "id" : "obj-23", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 184.0, 151.0, 37.0, 22.0 ], + "text" : "*~ #1" + } + + } +, { + "box" : { + "id" : "obj-22", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 184.0, 111.0, 58.0, 22.0 ], + "text" : "sig~ 0.25" + } + + } +, { + "box" : { + "id" : "obj-11", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 183.0, 8.0, 60.0, 20.0 ], + "text" : "pan" + } + + } +, { + "box" : { + "id" : "obj-10", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 124.0, 8.0, 60.0, 20.0 ], + "text" : "audio" + } + + } +, { + "box" : { + "comment" : "pan value (0...1)", + "id" : "obj-8", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 198.0, 33.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "mono audio in", + "id" : "obj-7", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 134.0, 33.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-27", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-28", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-23", 0 ], + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-24", 0 ], + "order" : 0, + "source" : [ "obj-23", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-26", 1 ], + "order" : 1, + "source" : [ "obj-23", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-25", 1 ], + "source" : [ "obj-24", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-25", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-26", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 1 ], + "order" : 1, + "source" : [ "obj-7", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 1 ], + "order" : 0, + "source" : [ "obj-7", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-23", 1 ], + "midpoints" : [ 207.5, 96.0, 252.0, 96.0, 252.0, 147.0, 211.5, 147.0 ], + "source" : [ "obj-8", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/path.maxpat b/unloop/max/path.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..7b8b6bb4de4e276d95e35e5ada8142a2cd71a445 --- /dev/null +++ b/unloop/max/path.maxpat @@ -0,0 +1,698 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 1, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-6", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 464.5, 82.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 464.5, 60.0, 65.0, 22.0 ], + "text" : "route clear" + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 207.000073671340942, 354.0, 119.0, 22.0 ], + "text" : "metro 500 @active 1" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 558.0, 315.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-68", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 462.0, 350.518528401851654, 35.0, 22.0 ], + "text" : "clear" + } + + } +, { + "box" : { + "id" : "obj-173", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 162.0, 522.518528401851654, 29.5, 22.0 ], + "text" : "* 2." + } + + } +, { + "box" : { + "id" : "obj-172", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 230.000073432922363, 522.518528401851654, 29.5, 22.0 ], + "text" : "* 2." + } + + } +, { + "box" : { + "id" : "obj-162", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 142.0, 734.518528401851654, 47.0, 22.0 ], + "text" : "zl.join" + } + + } +, { + "box" : { + "id" : "obj-158", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 162.0, 670.518528401851654, 29.5, 22.0 ], + "text" : "t b l" + } + + } +, { + "box" : { + "id" : "obj-150", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 686.518528401851654, 75.0, 47.0 ], + "text" : "object number (in ambisonics)" + } + + } +, { + "box" : { + "id" : "obj-148", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 142.0, 698.518528401851654, 29.5, 22.0 ], + "text" : "#1" + } + + } +, { + "box" : { + "id" : "obj-137", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 298.0, 262.518528401851654, 98.0, 47.0 ], + "text" : "a lookup table-based panning system" + } + + } +, { + "box" : { + "id" : "obj-136", + "linecount" : 4, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 434.0, 490.518528401851654, 57.0, 60.0 ], + "text" : "interp time between points" + } + + } +, { + "box" : { + "id" : "obj-134", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "", "", "", "" ], + "patching_rect" : [ 514.0, 378.518528401851654, 95.0, 22.0 ], + "saved_object_attributes" : { + "embed" : 0, + "precision" : 6 + } +, + "text" : "coll #1-positions" + } + + } +, { + "box" : { + "id" : "obj-133", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 482.0, 426.518528401851654, 50.0, 22.0 ], + "text" : "41" + } + + } +, { + "box" : { + "id" : "obj-131", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 558.0, 351.0, 41.0, 22.0 ], + "text" : "length" + } + + } +, { + "box" : { + "id" : "obj-119", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 238.000073671340942, 558.518551051616669, 74.0, 22.0 ], + "text" : "pack 0. 500." + } + + } +, { + "box" : { + "id" : "obj-117", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 162.0, 558.518528401851654, 74.0, 22.0 ], + "text" : "pack 0. 500." + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-108", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 378.0, 522.518528401851654, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-106", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 166.00007152557373, 634.51855331659317, 74.0, 22.0 ], + "text" : "pack 0. 0. 0." + } + + } +, { + "box" : { + "id" : "obj-105", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 238.000073671340942, 586.518551886081696, 57.0, 22.0 ], + "text" : "line 0. 20" + } + + } +, { + "box" : { + "id" : "obj-103", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 162.0, 586.518551886081696, 57.0, 22.0 ], + "text" : "line 0. 20" + } + + } +, { + "box" : { + "id" : "obj-102", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "float" ], + "patching_rect" : [ 162.0, 498.518528401851654, 74.0, 22.0 ], + "text" : "unpack 0. 0." + } + + } +, { + "box" : { + "id" : "obj-99", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 142.0, 766.518528401851654, 74.0, 22.0 ], + "text" : "prepend xyz" + } + + } +, { + "box" : { + "id" : "obj-96", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 246.0, 426.518528401851654, 35.0, 22.0 ], + "text" : "open" + } + + } +, { + "box" : { + "id" : "obj-81", + "maxclass" : "newobj", + "numinlets" : 5, + "numoutlets" : 4, + "outlettype" : [ "int", "", "", "int" ], + "patching_rect" : [ 162.0, 426.518528401851654, 65.0, 22.0 ], + "text" : "counter 25" + } + + } +, { + "box" : { + "id" : "obj-77", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "", "", "", "" ], + "patching_rect" : [ 162.0, 467.089956223964691, 95.0, 22.0 ], + "saved_object_attributes" : { + "embed" : 0, + "precision" : 6 + } +, + "text" : "coll #1-positions" + } + + } +, { + "box" : { + "id" : "obj-76", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 162.0, 377.518528401851654, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-74", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "float" ], + "patching_rect" : [ 146.0, 244.755107223987579, 29.5, 22.0 ], + "text" : "t f f" + } + + } +, { + "box" : { + "id" : "obj-72", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 134.0, 306.518528401851654, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-71", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 162.0, 278.518528401851654, 36.0, 22.0 ], + "text" : "> 0.8" + } + + } +, { + "box" : { + "id" : "obj-60", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 146.0, 214.518528401851654, 108.0, 22.0 ], + "text" : "fluid.onsetfeature~" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-90", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 464.5, 10.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-93", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 142.0, 848.518528401851654, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-134", 0 ], + "order" : 1, + "source" : [ "obj-1", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "order" : 0, + "source" : [ "obj-1", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-6", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-172", 0 ], + "source" : [ "obj-102", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-173", 0 ], + "source" : [ "obj-102", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-106", 0 ], + "source" : [ "obj-103", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-106", 1 ], + "source" : [ "obj-105", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-158", 0 ], + "source" : [ "obj-106", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-117", 1 ], + "order" : 1, + "source" : [ "obj-108", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-119", 1 ], + "order" : 0, + "source" : [ "obj-108", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-103", 0 ], + "source" : [ "obj-117", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-105", 0 ], + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-134", 0 ], + "source" : [ "obj-131", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-133", 1 ], + "order" : 0, + "source" : [ "obj-134", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 4 ], + "order" : 1, + "source" : [ "obj-134", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-162", 0 ], + "source" : [ "obj-148", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-148", 0 ], + "source" : [ "obj-158", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-162", 1 ], + "source" : [ "obj-158", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-99", 0 ], + "source" : [ "obj-162", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-119", 0 ], + "source" : [ "obj-172", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-117", 0 ], + "source" : [ "obj-173", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-131", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-76", 0 ], + "source" : [ "obj-3", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-68", 0 ], + "source" : [ "obj-6", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-74", 0 ], + "source" : [ "obj-60", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-134", 0 ], + "source" : [ "obj-68", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-72", 0 ], + "source" : [ "obj-71", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-76", 0 ], + "source" : [ "obj-72", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-71", 0 ], + "source" : [ "obj-74", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-72", 1 ], + "source" : [ "obj-74", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 0 ], + "source" : [ "obj-76", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-102", 0 ], + "source" : [ "obj-77", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-77", 0 ], + "source" : [ "obj-81", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-90", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-77", 0 ], + "source" : [ "obj-96", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-93", 0 ], + "source" : [ "obj-99", 0 ] + } + + } + ], + "originid" : "pat-2332" + } + +} diff --git a/unloop/max/paths.js b/unloop/max/paths.js new file mode 100644 index 0000000000000000000000000000000000000000..b72cc2d0729a24ef6c6f8e6ffbd697b8b929434e --- /dev/null +++ b/unloop/max/paths.js @@ -0,0 +1,109 @@ +var pathModes = ["off", "wander", "circle", "bounce"]; + +// Define state object +var state = { + coords: [], + coordidx: 0, + mode: "off" +}; + +// init with a random +setPath("random"); + +// the space ranges from -1 to 1 in x and y, z must always be 0 +function bang() { + // TODO: emit next xyz coordinate in path + if (state.coords.length > 0) { + outlet(0, state.coords[state.coordidx]); + state.coordidx = (state.coordidx + 1) % state.coords.length; + } + else { + post("no path to follow\n"); + } +} + +function setPath(mode) { + if (pathModes.indexOf(mode) >= 0) { + state.mode = mode; + } + state.mode = mode; + + // generate points for the pathe + if (state.mode == "circle") { + // circle around in a random direction + state.coords = []; + var numPoints = Math.round(Math.random() * 100); + var angle = Math.random() * 2 * Math.PI; + + var direction = Math.random() < 0.5 ? 1 : -1; + for (var i = 0; i < numPoints; i++) { + state.coords.push([Math.cos(angle), Math.sin(angle), 0]); + angle += 2 * Math.PI / numPoints * direction; + } + } + else if (state.mode == "wander") { + // wander around in brownian motion + state.coords = []; + var numPoints = Math.round(Math.random() * 100); + // var x = 0; + // var y = 0; + // pick a random starting point within -1 and 1 + var x = Math.random() * 2 - 1; + var y = Math.random() * 2 - 1; + for (var i = 0; i < numPoints; i++) { + x += Math.random() * 0.2 - 0.1; // TODO: this 0.1 controls wander amt + y += Math.random() * 0.2 - 0.1; + + // clamp to -1 to 1 + x = Math.min(1, Math.max(-1, x)); + y = Math.min(1, Math.max(-1, y)); + state.coords.push([x, y, 0]); + } + } + else if (state.mode == "bounce") { + // bounce around two points + state.coords = []; + var numPoints = 2; + var x = 0; + var y = 0; + + // pick two random quadrants to place the point in + quads = { + 1: [1, 1], + 2: [-1, 1], + 3: [-1, -1], + 4: [1, -1] + } + var quadindices = [1, 2, 3, 4]; + // scramble quadindices + quadindices.sort(function(a, b) { return Math.random() - 0.5; }); + var quadidx1 = quadindices.pop(); + var quadidx2 = quadindices.pop(); + var quad1 = quads[quadidx1]; + var quad2 = quads[quadidx2]; + // post("quad1: " + quad1 + " quad2: " + quad2); + + // pick point 1, a random point in the range (0, 1), then scale by the quad + var x1 = Math.random() * quad1[0]; + var y1 = Math.random() * quad1[1]; + + // pick point 2, a random point in the range (0, 1), then scale by the quad + var x2 = Math.random() * quad2[0]; + var y2 = Math.random() * quad2[1]; + + // generate the path + state.coords.push([x1, y1, 0]); + state.coords.push([x2, y2, 0]); + } + else if (state.mode == "random") { + state.coords = []; + var numPoints = Math.round(Math.random() * 100) + 4; + for (var i = 0; i < numPoints; i++) { + state.coords.push([Math.random() * 2 - 1, Math.random() * 2 - 1, 0]); + } + // post("random now has " + state.coords.length + " points\n"); + } + else { + post("unknown path mode"); + } +} diff --git a/unloop/max/randint.maxpat b/unloop/max/randint.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..70544befd9354cb28c96b784a4f47ac08d04d30e --- /dev/null +++ b/unloop/max/randint.maxpat @@ -0,0 +1,115 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-4", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 56.0, 199.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 56.0, 127.0, 63.0, 22.0 ], + "text" : "random 1." + } + + } +, { + "box" : { + "comment" : "bang for a random number", + "id" : "obj-2", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 56.0, 77.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 56.0, 159.0, 130.0, 22.0 ], + "text" : "scale 0. 1. #1 #2 #3" + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-3", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/randrange.maxpat b/unloop/max/randrange.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..7fd2683faab96bfb3097057064d5bfd2195657cd --- /dev/null +++ b/unloop/max/randrange.maxpat @@ -0,0 +1,117 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-4", + "index" : 0, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 77.0, 218.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 77.0, 177.0, 97.0, 22.0 ], + "text" : "scale 0. 1. #1 #2" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 77.0, 137.0, 63.0, 22.0 ], + "text" : "random 1." + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-1", + "index" : 0, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 77.0, 88.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-3", 0 ] + } + + } + ], + "dependency_cache" : [ ], + "autosave" : 0 + } + +} diff --git a/unloop/max/three-unloops.maxpat b/unloop/max/three-unloops.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..cb5251a7922e80513bd78cd591c7026c3ae79001 --- /dev/null +++ b/unloop/max/three-unloops.maxpat @@ -0,0 +1,728 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 34.0, 87.0, 1612.0, 929.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-18", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1045.0, 739.0, 132.0, 22.0 ], + "presentation_linecount" : 3, + "text" : "text supermetroid" + } + + } +, { + "box" : { + "id" : "obj-17", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 622.0, 739.0, 132.0, 22.0 ], + "presentation_linecount" : 3, + "text" : "text supermetroid" + } + + } +, { + "box" : { + "id" : "obj-16", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 260.0, 739.0, 132.0, 22.0 ], + "text" : "text supermetroid" + } + + } +, { + "box" : { + "id" : "obj-12", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 678.0, 72.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-10", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 809.0, 107.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-6", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1137.0, 138.0, 150.0, 20.0 ], + "text" : "infinite radio mode" + } + + } +, { + "box" : { + "id" : "obj-4", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1025.0, 137.0, 110.0, 22.0 ], + "presentation_linecount" : 2, + "text" : "vampnet periodic 0" + } + + } +, { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "id" : "obj-3", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "unloop-bpatcher.maxpat", + "numinlets" : 2, + "numoutlets" : 2, + "offset" : [ 0.0, 0.0 ], + "outlettype" : [ "signal", "" ], + "patching_rect" : [ 876.0, 243.0, 301.0, 461.0 ], + "viewvisibility" : 1 + } + + } +, { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "id" : "obj-2", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "unloop-bpatcher.maxpat", + "numinlets" : 2, + "numoutlets" : 2, + "offset" : [ 0.0, 0.0 ], + "outlettype" : [ "signal", "" ], + "patching_rect" : [ 463.0, 243.0, 301.0, 461.0 ], + "viewvisibility" : 1 + } + + } +, { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "id" : "obj-1", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "unloop-bpatcher.maxpat", + "numinlets" : 2, + "numoutlets" : 2, + "offset" : [ 0.0, 0.0 ], + "outlettype" : [ "signal", "" ], + "patching_rect" : [ 91.0, 243.0, 301.0, 461.0 ], + "viewvisibility" : 1 + } + + } +, { + "box" : { + "id" : "obj-33", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 478.0, 76.0, 150.0, 20.0 ], + "text" : "play/stop the playhead" + } + + } +, { + "box" : { + "id" : "obj-32", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 634.5, 35.0, 129.0, 33.0 ], + "text" : "record into all bufs simultaneously" + } + + } +, { + "box" : { + "id" : "obj-31", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 773.0, 45.0, 150.0, 47.0 ], + "text" : "start generation \n(make sure client is running!) " + } + + } +, { + "box" : { + "id" : "obj-30", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 985.0, 103.0, 150.0, 20.0 ], + "text" : "choose model option 14" + } + + } +, { + "box" : { + "id" : "obj-28", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 916.0, 102.0, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "id" : "obj-26", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 916.0, 137.0, 101.0, 22.0 ], + "text" : "vampnet model 1" + } + + } +, { + "box" : { + "id" : "obj-21", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 809.0, 143.0, 45.0, 22.0 ], + "text" : "gen $1" + } + + } +, { + "box" : { + "id" : "obj-15", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 678.0, 112.0, 42.0, 22.0 ], + "text" : "rec $1" + } + + } +, { + "box" : { + "id" : "obj-14", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 84.0, 131.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-2", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 31.0, 145.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-1", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 31.0, 20.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-1", 0 ] + } + + } + ], + "originid" : "pat-6" + } +, + "patching_rect" : [ 572.0, 184.0, 44.0, 22.0 ], + "text" : "p pass" + } + + } +, { + "box" : { + "id" : "obj-8", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 534.0, 112.0, 31.0, 22.0 ], + "text" : "stop" + } + + } +, { + "box" : { + "id" : "obj-7", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 500.0, 112.0, 31.0, 22.0 ], + "text" : "play" + } + + } +, { + "box" : { + "id" : "obj-5", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 0, + "patching_rect" : [ 533.0, 750.0, 55.0, 22.0 ], + "text" : "dac~ 1 2" + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-16", 1 ], + "source" : [ "obj-1", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-21", 0 ], + "source" : [ "obj-10", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-15", 0 ], + "source" : [ "obj-12", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "order" : 2, + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "order" : 1, + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "order" : 0, + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-15", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-17", 1 ], + "source" : [ "obj-2", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 1 ], + "order" : 0, + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 0 ], + "order" : 1, + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-21", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-26", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-26", 0 ], + "order" : 1, + "source" : [ "obj-28", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "order" : 0, + "source" : [ "obj-28", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-18", 1 ], + "source" : [ "obj-3", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 1 ], + "source" : [ "obj-3", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-4", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-7", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-8", 0 ] + } + + } + ], + "originid" : "pat-4", + "parameters" : { + "obj-1::obj-1124" : [ "morph", "dry/wet", 0 ], + "obj-1::obj-1125" : [ "level[8]", "level", 0 ], + "obj-1::obj-1128" : [ "gain[4]", "gain", 0 ], + "obj-1::obj-1140" : [ "overdub", "overdub", 0 ], + "obj-1::obj-117" : [ "live.drop", "live.drop", 0 ], + "obj-1::obj-1230" : [ "speed[2]", "speed+", 0 ], + "obj-1::obj-171" : [ "toggle[2]", "toggle[30]", 0 ], + "obj-1::obj-295" : [ "button[1]", "button[1]", 0 ], + "obj-1::obj-316" : [ "toggle[3]", "toggle[3]", 0 ], + "obj-1::obj-424::obj-12" : [ "number[8]", "number[2]", 0 ], + "obj-1::obj-424::obj-13" : [ "number[9]", "number[3]", 0 ], + "obj-1::obj-424::obj-15" : [ "number[2]", "number[2]", 0 ], + "obj-1::obj-424::obj-19" : [ "number[3]", "number[3]", 0 ], + "obj-1::obj-424::obj-20" : [ "number", "number", 0 ], + "obj-1::obj-424::obj-23" : [ "number[4]", "number[3]", 0 ], + "obj-1::obj-424::obj-26" : [ "number[5]", "number[3]", 0 ], + "obj-1::obj-424::obj-28" : [ "number[6]", "number[2]", 0 ], + "obj-1::obj-424::obj-30" : [ "number[7]", "number[2]", 0 ], + "obj-1::obj-424::obj-347" : [ "periodic", "periodic", 0 ], + "obj-1::obj-424::obj-349" : [ "drop", "drop", 0 ], + "obj-1::obj-424::obj-8" : [ "toggle", "toggle", 0 ], + "obj-1::obj-54" : [ "lpf", "lpf", 0 ], + "obj-1::obj-55" : [ "tapelength", "length", 0 ], + "obj-1::obj-76" : [ "hpf", "hpf", 0 ], + "obj-1::obj-91::obj-156" : [ "live.gain~[26]", "live.gain~", 0 ], + "obj-1::obj-91::obj-162" : [ "live.gain~[25]", "live.gain~", 0 ], + "obj-2::obj-1124" : [ "morph[1]", "dry/wet", 0 ], + "obj-2::obj-1125" : [ "level[1]", "level", 0 ], + "obj-2::obj-1128" : [ "gain[5]", "gain", 0 ], + "obj-2::obj-1140" : [ "overdub[1]", "overdub", 0 ], + "obj-2::obj-117" : [ "live.drop[1]", "live.drop", 0 ], + "obj-2::obj-1230" : [ "speed[3]", "speed+", 0 ], + "obj-2::obj-171" : [ "toggle[6]", "toggle[30]", 0 ], + "obj-2::obj-295" : [ "button[2]", "button[1]", 0 ], + "obj-2::obj-316" : [ "toggle[5]", "toggle[3]", 0 ], + "obj-2::obj-424::obj-12" : [ "number[13]", "number[2]", 0 ], + "obj-2::obj-424::obj-13" : [ "number[10]", "number[3]", 0 ], + "obj-2::obj-424::obj-15" : [ "number[18]", "number[2]", 0 ], + "obj-2::obj-424::obj-19" : [ "number[16]", "number[3]", 0 ], + "obj-2::obj-424::obj-20" : [ "number[17]", "number", 0 ], + "obj-2::obj-424::obj-23" : [ "number[15]", "number[3]", 0 ], + "obj-2::obj-424::obj-26" : [ "number[12]", "number[3]", 0 ], + "obj-2::obj-424::obj-28" : [ "number[14]", "number[2]", 0 ], + "obj-2::obj-424::obj-30" : [ "number[11]", "number[2]", 0 ], + "obj-2::obj-424::obj-347" : [ "periodic[1]", "periodic", 0 ], + "obj-2::obj-424::obj-349" : [ "drop[1]", "drop", 0 ], + "obj-2::obj-424::obj-8" : [ "toggle[4]", "toggle", 0 ], + "obj-2::obj-54" : [ "lpf[1]", "lpf", 0 ], + "obj-2::obj-55" : [ "tapelength[1]", "length", 0 ], + "obj-2::obj-76" : [ "hpf[1]", "hpf", 0 ], + "obj-2::obj-91::obj-156" : [ "live.gain~[2]", "live.gain~", 0 ], + "obj-2::obj-91::obj-162" : [ "live.gain~[1]", "live.gain~", 0 ], + "obj-3::obj-1124" : [ "morph[2]", "dry/wet", 0 ], + "obj-3::obj-1125" : [ "level[2]", "level", 0 ], + "obj-3::obj-1128" : [ "gain[6]", "gain", 0 ], + "obj-3::obj-1140" : [ "overdub[2]", "overdub", 0 ], + "obj-3::obj-117" : [ "live.drop[2]", "live.drop", 0 ], + "obj-3::obj-1230" : [ "speed[4]", "speed+", 0 ], + "obj-3::obj-171" : [ "toggle[9]", "toggle[30]", 0 ], + "obj-3::obj-295" : [ "button[3]", "button[1]", 0 ], + "obj-3::obj-316" : [ "toggle[8]", "toggle[3]", 0 ], + "obj-3::obj-424::obj-12" : [ "number[26]", "number[2]", 0 ], + "obj-3::obj-424::obj-13" : [ "number[24]", "number[3]", 0 ], + "obj-3::obj-424::obj-15" : [ "number[21]", "number[2]", 0 ], + "obj-3::obj-424::obj-19" : [ "number[19]", "number[3]", 0 ], + "obj-3::obj-424::obj-20" : [ "number[25]", "number", 0 ], + "obj-3::obj-424::obj-23" : [ "number[23]", "number[3]", 0 ], + "obj-3::obj-424::obj-26" : [ "number[27]", "number[3]", 0 ], + "obj-3::obj-424::obj-28" : [ "number[22]", "number[2]", 0 ], + "obj-3::obj-424::obj-30" : [ "number[20]", "number[2]", 0 ], + "obj-3::obj-424::obj-347" : [ "periodic[2]", "periodic", 0 ], + "obj-3::obj-424::obj-349" : [ "drop[2]", "drop", 0 ], + "obj-3::obj-424::obj-8" : [ "toggle[7]", "toggle", 0 ], + "obj-3::obj-54" : [ "lpf[2]", "lpf", 0 ], + "obj-3::obj-55" : [ "tapelength[2]", "length", 0 ], + "obj-3::obj-76" : [ "hpf[2]", "hpf", 0 ], + "obj-3::obj-91::obj-156" : [ "live.gain~[3]", "live.gain~", 0 ], + "obj-3::obj-91::obj-162" : [ "live.gain~[4]", "live.gain~", 0 ], + "parameterbanks" : { + "0" : { + "index" : 0, + "name" : "", + "parameters" : [ "-", "-", "-", "-", "-", "-", "-", "-" ] + } + + } +, + "parameter_overrides" : { + "obj-2::obj-1124" : { + "parameter_longname" : "morph[1]" + } +, + "obj-2::obj-1125" : { + "parameter_longname" : "level[1]" + } +, + "obj-2::obj-1128" : { + "parameter_longname" : "gain[5]" + } +, + "obj-2::obj-1140" : { + "parameter_longname" : "overdub[1]" + } +, + "obj-2::obj-117" : { + "parameter_longname" : "live.drop[1]" + } +, + "obj-2::obj-1230" : { + "parameter_longname" : "speed[3]" + } +, + "obj-2::obj-424::obj-347" : { + "parameter_longname" : "periodic[1]" + } +, + "obj-2::obj-424::obj-349" : { + "parameter_longname" : "drop[1]" + } +, + "obj-2::obj-54" : { + "parameter_longname" : "lpf[1]" + } +, + "obj-2::obj-55" : { + "parameter_longname" : "tapelength[1]" + } +, + "obj-2::obj-76" : { + "parameter_longname" : "hpf[1]" + } +, + "obj-2::obj-91::obj-156" : { + "parameter_longname" : "live.gain~[2]" + } +, + "obj-2::obj-91::obj-162" : { + "parameter_longname" : "live.gain~[1]" + } +, + "obj-3::obj-1124" : { + "parameter_longname" : "morph[2]" + } +, + "obj-3::obj-1125" : { + "parameter_longname" : "level[2]" + } +, + "obj-3::obj-1128" : { + "parameter_longname" : "gain[6]" + } +, + "obj-3::obj-1140" : { + "parameter_longname" : "overdub[2]" + } +, + "obj-3::obj-117" : { + "parameter_longname" : "live.drop[2]" + } +, + "obj-3::obj-1230" : { + "parameter_longname" : "speed[4]" + } +, + "obj-3::obj-424::obj-347" : { + "parameter_longname" : "periodic[2]" + } +, + "obj-3::obj-424::obj-349" : { + "parameter_longname" : "drop[2]" + } +, + "obj-3::obj-54" : { + "parameter_longname" : "lpf[2]" + } +, + "obj-3::obj-55" : { + "parameter_longname" : "tapelength[2]" + } +, + "obj-3::obj-76" : { + "parameter_longname" : "hpf[2]" + } +, + "obj-3::obj-91::obj-156" : { + "parameter_longname" : "live.gain~[3]" + } +, + "obj-3::obj-91::obj-162" : { + "parameter_longname" : "live.gain~[4]" + } + + } +, + "inherited_shortname" : 1 + } +, + "dependency_cache" : [ { + "name" : "dry-wet.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } +, { + "name" : "unloop-bpatcher.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } +, { + "name" : "vampnet-ui.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } + ], + "autosave" : 0 + } + +} diff --git a/unloop/max/two-gate.maxpat b/unloop/max/two-gate.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..a016a64cc257fce161a543ac7410d91d94931e08 --- /dev/null +++ b/unloop/max/two-gate.maxpat @@ -0,0 +1,184 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-4", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 70.491801261901855, 137.704914093017578, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-3", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 26.229507446289062, 137.704914093017578, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-1", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 70.491801261901855, 28.688523769378662, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-518", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 26.229507446289062, 28.688523769378662, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-517", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 69.672129154205322, 74.590161800384521, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-516", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 69.672129154205322, 106.557374000549316, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-515", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 26.229507446289062, 106.557374000549316, 32.0, 22.0 ], + "text" : "gate" + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-515", 1 ], + "order" : 1, + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-516", 1 ], + "order" : 0, + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-515", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-516", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-516", 0 ], + "source" : [ "obj-517", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-515", 0 ], + "order" : 1, + "source" : [ "obj-518", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-517", 0 ], + "order" : 0, + "source" : [ "obj-518", 0 ] + } + + } + ] + } + +} diff --git a/unloop/max/unloop-bpatcher.maxpat b/unloop/max/unloop-bpatcher.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..41a8c50105697e4b29eacb4adc221ab31a345449 --- /dev/null +++ b/unloop/max/unloop-bpatcher.maxpat @@ -0,0 +1,14251 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 34.0, 87.0, 1612.0, 929.0 ], + "openinpresentation" : 1, + "gridonopen" : 2, + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-116", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5726.0, 2601.0, 92.0, 22.0 ], + "text" : "r #0-vampnet" + } + + } +, { + "box" : { + "id" : "obj-110", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1733.0, 532.0, 94.0, 22.0 ], + "text" : "s #0-vampnet" + } + + } +, { + "box" : { + "id" : "obj-44", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5634.670000000000073, 3806.210000000000036, 100.0, 22.0 ] + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-65", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1990.476171493530273, 3992.666788518428802, 1148.0, 118.0 ], + "text" : "outport" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-62", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1893.1035475730896, 1724.138021469116211, 637.499975681304932, 118.0 ], + "text" : "tape controls" + } + + } +, { + "box" : { + "id" : "obj-33", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 637.0, 580.0, 95.0, 22.0 ], + "text" : "print deprecated" + } + + } +, { + "box" : { + "comment" : "signal", + "id" : "obj-26", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 331.0, 4454.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-331", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 95.666656374931335, 200.0, 114.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 328.176827073097229, 62.430945217609406, 231.333340227603912, 20.0 ], + "text" : "TODO: a mask viz would be amazing!" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-576", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 341.322295129299164, 304.958660781383514, 123.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 242.269274294376373, 267.648158993571997, 18.0, 15.0 ], + "text" : "<3" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-575", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 322.0, 88.0, 93.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 101.670282110571861, 320.822295129299164, 106.508835881948471, 20.0 ], + "text" : "tape controls", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-572", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ -17.0, 57.0, 93.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ -15.108027905225754, 57.145161688327789, 63.0, 20.0 ], + "text" : "dry", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-568", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ -14.0, 18.0, 93.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ -15.108027905225754, 27.693548560142517, 63.0, 20.0 ], + "text" : "wet", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "id" : "obj-548", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 148.0, 40.0, 114.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 328.0, 39.369373738765717, 231.333340227603912, 20.0 ], + "text" : "requires flucoma" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-541", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 718.5, 2548.000075936317444, 113.0, 22.0 ], + "text" : "send~ #0-in-pass" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-574", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 116.666656374931335, 104.545445322990417, 93.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 104.66666978597641, 100.000002980232239, 92.4242342710495, 20.0 ], + "text" : "vampnet", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-539", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4806.896803855895996, 951.724187850952148, 153.0, 22.0 ], + "text" : "s #0-to-loopbuf-duplicate" + } + + } +, { + "box" : { + "id" : "obj-518", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 4806.896803855895996, 913.793151378631592, 130.0, 22.0 ], + "text" : "combine #0 -dreams" + } + + } +, { + "box" : { + "id" : "obj-488", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 4806.896803855895996, 874.137976884841919, 22.0, 22.0 ], + "text" : "t b" + } + + } +, { + "box" : { + "bgcolor" : [ 0.301960784313725, 0.301960784313725, 0.301960784313725, 1.0 ], + "bgcolor2" : [ 0.301960784313725, 0.301960784313725, 0.301960784313725, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_color1" : [ 0.301960784313725, 0.301960784313725, 0.301960784313725, 1.0 ], + "bgfillcolor_color2" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 8.0, + "gradient" : 1, + "id" : "obj-363", + "linecount" : 2, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4806.896803855895996, 837.931078433990479, 61.0, 26.0 ], + "presentation" : 1, + "presentation_rect" : [ 111.696973830461502, 284.49288821965456, 78.0, 17.0 ], + "text" : "copy output to input" + } + + } +, { + "box" : { + "id" : "obj-559", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4168.548416912555695, 595.16129457950592, 104.0, 22.0 ], + "text" : "prepend duplicate" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-562", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4168.548416912555695, 567.741939544677734, 152.0, 22.0 ], + "text" : "r #0-to-dreams-duplicate" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-558", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2683.870986938476562, 1105.5, 154.0, 22.0 ], + "text" : "s #0-to-dreams-duplicate" + } + + } +, { + "box" : { + "id" : "obj-337", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 2267.352931976318359, 539.999982297420502, 83.0, 22.0 ], + "text" : "combine #0" + } + + } +, { + "box" : { + "id" : "obj-517", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5497.333497166633606, 3738.000111401081085, 24.0, 24.0 ] + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-471", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 6098.00018173456192, 3702.666777014732361, 70.0, 22.0 ], + "text" : "loadmess 1" + } + + } +, { + "box" : { + "id" : "obj-450", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 6147.50018322467804, 3820.666780531406403, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-395", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 6148.00018322467804, 3860.666781723499298, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-386", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 6103.333515226840973, 3824.666780650615692, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-377", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 6129.166432857513428, 3738.000111401081085, 192.708325982093811, 47.0 ], + "text" : "immediate (turn this off so that we wait for the end of the loop to replace the old buffer)" + } + + } +, { + "box" : { + "id" : "obj-357", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 6103.333515226840973, 3768.000112295150757, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-322", + "linecount" : 13, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 234.0, 896.0, 114.0, 181.0 ], + "presentation" : 1, + "presentation_linecount" : 6, + "presentation_rect" : [ 639.698169231414795, 718.0, 231.333340227603912, 87.0 ], + "text" : "THINGS TO TRY FOR BETTER SOUND\n- TIMBRE PROMPTS? (TRIA_STYLE)\n- S2S Conditioning\n- KERO KERO BONITO SAXOPHONE TOKENS\n- FINETUNE ON JUST SAX" + } + + } +, { + "box" : { + "id" : "obj-145", + "linecount" : 35, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 42.515714645385742, 1044.0, 125.0, 476.0 ], + "presentation" : 1, + "presentation_linecount" : 26, + "presentation_rect" : [ 1012.71668815612793, 408.092455387115479, 201.0, 355.0 ], + "text" : "HUGO: \n\nNEW workflow:\n- DO I NEED to sync to a clock !?!? figure thit out?!\n- TO SYNC TO A DRUM MACHINE?\n\n- OR DO I just need fixed loops that I can load? \n\n[ ] LAUNCH A TRAINING JOB FOR MUSIC WITHOUT PERCUSSION AND SEE WHAT HAPPENS? \n\n\n- ok, lets prep to jam w/ MIT \n- more guitar // vocal experiments!\n- test jazz model\n- train a model on solo guitar // harmonic instruments\n\n\n \n\n[ ] add beat prompts again!" + } + + } +, { + "box" : { + "id" : "obj-516", + "linecount" : 20, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 55.05618417263031, 778.651747584342957, 112.459530472755432, 275.0 ], + "presentation" : 1, + "presentation_linecount" : 14, + "presentation_rect" : [ 1113.872750043869019, 139.306348085403442, 196.5, 194.0 ], + "text" : "HUGO: \n\n- so it works OK with drums in it!!!\n\n[ ] add undo\n[ ] add save loops that you can bring back\n[ ] operate in feedback mode? \n\nBUT TOO SHORT\n\n- MAKE IT AT LEAST TWO BARS! IDEALLY FOUR\n- CAN YOU MAKE IT" + } + + } +, { + "box" : { + "id" : "obj-509", + "linecount" : 3, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2597.5, 1025.0, 50.0, 49.0 ], + "text" : "#0-loaded-from-file" + } + + } +, { + "box" : { + "id" : "obj-463", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 3, + "outlettype" : [ "bang", "bang", "" ], + "patching_rect" : [ 2401.352931976318359, 980.00002920627594, 44.0, 22.0 ], + "text" : "sel 0 1" + } + + } +, { + "box" : { + "id" : "obj-458", + "linecount" : 13, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2401.352931976318359, 1025.0, 50.0, 183.0 ], + "text" : "\"Macintosh HD:/Users/hugo/projects/research/unloop-2025/mit-visit/loops/oro-seco.wav\"" + } + + } +, { + "box" : { + "id" : "obj-432", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2401.352931976318359, 1055.5, 176.0, 22.0 ], + "text" : "print WRONG_SAMPLE_RATE" + } + + } +, { + "box" : { + "id" : "obj-388", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 2401.352931976318359, 938.666694641113281, 29.5, 22.0 ], + "text" : "==" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-387", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2463.333406746387482, 880.666692912578583, 57.0, 22.0 ], + "text" : "r #0-sr" + } + + } +, { + "box" : { + "id" : "obj-358", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3008.0, 730.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-343", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3008.0, 794.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-338", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 10, + "outlettype" : [ "float", "list", "float", "float", "float", "float", "float", "", "int", "" ], + "patching_rect" : [ 3008.0, 767.0, 113.5, 22.0 ], + "text" : "info~ #0-loop" + } + + } +, { + "box" : { + "id" : "obj-326", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 2401.352931976318359, 880.666692912578583, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-308", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 347.023806214332581, 2839.880925297737122, 29.5, 22.0 ], + "text" : "+~" + } + + } +, { + "box" : { + "id" : "obj-277", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 551.546360850334167, 450.340131759643555, 96.0, 22.0 ], + "text" : "routepass signal" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-513", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1693.0, 611.0, 141.0, 22.0 ], + "text" : "s #0-stop-reset-footsw" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-512", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1637.600024402141571, 580.0, 130.0, 22.0 ], + "text" : "s #0-rec-play-footsw" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-311", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 513.135605454444885, 2601.694977283477783, 73.0, 22.0 ], + "text" : "loadmess 0." + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-303", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 505.978251218795776, 3806.521666526794434, 73.0, 22.0 ], + "text" : "loadmess 1." + } + + } +, { + "box" : { + "id" : "obj-302", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4916.0, 2588.0, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "id" : "obj-261", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4949.0, 2621.5, 41.0, 22.0 ], + "text" : "ctrl $1" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-212", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4916.0, 2554.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-209", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1592.400000000000091, 536.800007998943329, 87.0, 22.0 ], + "text" : "s #0-s2s-ctrl" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-203", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4949.0, 2588.0, 85.0, 22.0 ], + "text" : "r #0-s2s-ctrl" + } + + } +, { + "box" : { + "id" : "obj-189", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1157.021300733089447, 1818.723442196846008, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "id" : "obj-96", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 1157.021300733089447, 1751.489398241043091, 42.0, 22.0 ], + "text" : "edge~" + } + + } +, { + "box" : { + "id" : "obj-100", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1157.021300733089447, 1786.808547914028168, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-102", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 1157.021300733089447, 1718.723440110683441, 49.0, 22.0 ], + "text" : ">~ 0.99" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-104", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 1157.021300733089447, 1683.404290437698364, 136.0, 22.0 ], + "text" : "receive~ #0-loopsync" + } + + } +, { + "box" : { + "id" : "obj-90", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1203.0, 1836.5, 150.0, 33.0 ], + "text" : "loop end should trigger 0 to avoid overdubbing" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-451", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1148.0, 2072.0, 65.0, 22.0 ], + "text" : "s #0-api" + } + + } +, { + "box" : { + "id" : "obj-449", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "int", "int" ], + "patching_rect" : [ 1148.0, 1935.0, 48.0, 22.0 ], + "text" : "change" + } + + } +, { + "box" : { + "id" : "obj-419", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1148.0, 2014.0, 125.0, 22.0 ], + "text" : "play, s2s-ctrl 1, auto 1" + } + + } +, { + "box" : { + "id" : "obj-359", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1323.0, 2014.0, 163.0, 22.0 ], + "text" : "reset, rec 1, initrecord 1, play" + } + + } +, { + "box" : { + "id" : "obj-332", + "linecount" : 7, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1203.0, 1896.0, 150.0, 100.0 ], + "text" : "on 1:\n- reset looper\n- rec 1\n- initrecord 1\n- play\non 0:\n- play (again)" + } + + } +, { + "box" : { + "id" : "obj-330", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 3, + "outlettype" : [ "bang", "bang", "" ], + "patching_rect" : [ 1148.0, 1975.0, 44.0, 22.0 ], + "text" : "sel 0 1" + } + + } +, { + "box" : { + "id" : "obj-329", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1093.0, 1897.0, 50.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 906.936349153518677, 161.271664381027222, 50.0, 20.0 ], + "text" : "sketch", + "textcolor" : [ 0.812167882919312, 0.776836037635803, 0.778279423713684, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "id" : "obj-316", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 1, + "patching_rect" : [ 1148.0, 1893.0, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 920.231145858764648, 143.352590560913086, 24.0, 24.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_enum" : [ "off", "on" ], + "parameter_longname" : "toggle[3]", + "parameter_mmax" : 1, + "parameter_modmode" : 0, + "parameter_shortname" : "toggle[3]", + "parameter_type" : 2 + } + + } +, + "varname" : "toggle[3]" + } + + } +, { + "box" : { + "id" : "obj-132", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1097.0, 170.0, 107.0, 22.0 ], + "text" : "prepend bgfillcolor" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-103", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1097.0, 122.0, 102.0, 22.0 ], + "text" : "r #0-panelcolor" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-99", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1449.0, 572.0, 104.0, 22.0 ], + "text" : "s #0-panelcolor" + } + + } +, { + "box" : { + "id" : "obj-528", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5650.647066056728363, 3213.235232830047607, 142.0, 22.0 ], + "text" : "print #0-reset-loadbufs" + } + + } +, { + "box" : { + "id" : "obj-527", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5610.647066056728363, 3213.235232830047607, 35.0, 22.0 ], + "text" : "clear" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-524", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5610.647066056728363, 3185.350023508071899, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-569", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5372.961456656455994, 3480.686749219894409, 95.0, 22.0 ], + "text" : "s #0-udpsend" + } + + } +, { + "box" : { + "id" : "obj-567", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5504.0, 3185.350023508071899, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "id" : "obj-566", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5397.0, 3185.350023508071899, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "fontsize" : 4.0, + "id" : "obj-565", + "linecount" : 5, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5449.000162392854691, 3381.000100761651993, 72.0, 31.0 ], + "text" : "/Users/hugo/projects/research/unloop-2025/vampnet/unloop/.gradio/4f51a32809338a67935cbc3e18c2f5daa25a038225d81e9166fabe064e5dcfa8/audio.wav" + } + + } +, { + "box" : { + "fontsize" : 4.0, + "id" : "obj-563", + "linecount" : 5, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5373.000160127878189, 3381.000100761651993, 71.0, 31.0 ], + "text" : "/Users/hugo/projects/research/unloop-2025/vampnet/unloop/.gradio/8923603ebd6a82f417dc1cfda8e7ba6e5fb04eaeed9a444af31f46fb55747b55/audio.wav" + } + + } +, { + "box" : { + "id" : "obj-554", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5373.000160127878189, 3426.666768789291382, 101.0, 22.0 ], + "text" : "prepend /cleanup" + } + + } +, { + "box" : { + "id" : "obj-550", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5207.0, 3410.0, 154.0, 47.0 ], + "text" : "send a \"cleanup\" message to the server, so the file can be cleaned up" + } + + } +, { + "box" : { + "id" : "obj-87", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4344.0, 4764.0, 100.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-185", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 86.0, 3881.0, 150.0, 33.0 ], + "text" : "this LPF occassionally throws nan" + } + + } +, { + "box" : { + "id" : "obj-178", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-496", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 187.162156343460083, 93.0, 22.0 ], + "text" : "prepend crop 0." + } + + } +, { + "box" : { + "id" : "obj-495", + "linecount" : 2, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 145.945942878723145, 38.0, 35.0 ], + "text" : "10000." + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-493", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 80.40540337562561, 100.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-169", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 50.000061711074522, 40.000032272445651, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-495", 0 ], + "source" : [ "obj-169", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-495", 1 ], + "order" : 0, + "source" : [ "obj-493", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-495", 0 ], + "order" : 1, + "source" : [ "obj-493", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-496", 0 ], + "source" : [ "obj-495", 0 ] + } + + } + ], + "originid" : "pat-263" + } +, + "patching_rect" : [ 5164.5, 2058.78364634513855, 179.0, 22.0 ], + "text" : "p deprecated-crop-to-looplength" + } + + } +, { + "box" : { + "id" : "obj-561", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 6012.800089597702026, 3876.000115513801575, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-560", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 5535.20008248090744, 3486.400051951408386, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-555", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 0.0, 0.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-467", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 100.0, 98.0, 20.0 ], + "text" : "reset queryid" + } + + } +, { + "box" : { + "id" : "obj-463", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 53.200000047683716, 140.000000596046448, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-458", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 53.200000047683716, 116.800000250339508, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-554", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 53.199819221069447, 222.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-463", 0 ], + "source" : [ "obj-458", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-554", 0 ], + "source" : [ "obj-463", 0 ] + } + + } + ], + "originid" : "pat-265" + } +, + "patching_rect" : [ 5516.000082194805145, 3072.000045776367188, 93.0, 22.0 ], + "text" : "p reset-on-reset" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-544", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 6121.600001990795135, 3456.800051510334015, 66.0, 22.0 ], + "text" : "r #0-text" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-543", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5203.0, 2935.0, 68.0, 22.0 ], + "text" : "s #0-text" + } + + } +, { + "box" : { + "id" : "obj-540", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5739.333504378795624, 4016.000119686126709, 154.0, 33.0 ], + "text" : "retrigger as soon as user hits gen" + } + + } +, { + "box" : { + "id" : "obj-486", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 6052.0, 3951.500058948993683, 154.0, 33.0 ], + "text" : "wait to retrigger until we've consumed our batch" + } + + } +, { + "box" : { + "id" : "obj-485", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "int" ], + "patching_rect" : [ 5625.333500981330872, 4174.000124394893646, 31.0, 22.0 ], + "text" : "t b i" + } + + } +, { + "box" : { + "id" : "obj-484", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5476.000163197517395, 4150.000123679637909, 43.0, 22.0 ], + "text" : "$1-buf" + } + + } +, { + "box" : { + "id" : "obj-464", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 6012.800089597702026, 3956.000058948993683, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-459", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5497.333497166633606, 4268.666793882846832, 107.38255500793457, 33.0 ], + "text" : "current buf to clone" + } + + } +, { + "box" : { + "id" : "obj-437", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5476.000163197517395, 4232.000126123428345, 115.0, 22.0 ], + "text" : "combine #0-buf 1" + } + + } +, { + "box" : { + "id" : "obj-422", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5665.333502173423767, 4140.666790068149567, 151.0, 33.0 ], + "text" : "counter size should match inference batch size" + } + + } +, { + "box" : { + "id" : "obj-415", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 5625.333500981330872, 4118.000122725963593, 29.5, 22.0 ], + "text" : "+ 1" + } + + } +, { + "box" : { + "id" : "obj-379", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5625.333500981330872, 4146.000123560428619, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-346", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5625.333500981330872, 4058.000120937824249, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-336", + "maxclass" : "newobj", + "numinlets" : 5, + "numoutlets" : 4, + "outlettype" : [ "int", "", "", "int" ], + "patching_rect" : [ 5625.333500981330872, 4088.666788518428802, 61.0, 22.0 ], + "text" : "counter 1" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-184", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 439.0, 4305.0, 15.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 238.257570505142212, 408.486547708511353, 26.0, 15.0 ], + "text" : "mute" + } + + } +, { + "box" : { + "id" : "obj-171", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 1, + "patching_rect" : [ 457.0, 4303.0, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 265.850312739610672, 406.611547708511353, 18.75, 18.75 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_enum" : [ "off", "on" ], + "parameter_longname" : "toggle[2]", + "parameter_mmax" : 1, + "parameter_modmode" : 0, + "parameter_shortname" : "toggle[30]", + "parameter_type" : 2 + } + + } +, + "varname" : "toggle[2]" + } + + } +, { + "box" : { + "id" : "obj-148", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 658.333416521549225, 1830.0, 152.0, 47.0 ], + "text" : "connect this to the togle to enable initrecord function upon reset" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-52", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 382.0, 3930.0, 80.0, 22.0 ], + "text" : "loadmess 0.9" + } + + } +, { + "box" : { + "id" : "obj-112", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 648.0, 3848.0, 150.0, 20.0 ], + "text" : "old version of dry/wet" + } + + } +, { + "box" : { + "id" : "obj-91", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 394.0, 3897.0, 48.0, 22.0 ], + "text" : "dry-wet" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-394", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 529.0, 4010.0, 108.0, 22.0 ], + "text" : "send~ #0-mixed" + } + + } +, { + "box" : { + "id" : "obj-390", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 4229.67646598815918, 866.0, 22.0, 22.0 ], + "text" : "t b" + } + + } +, { + "box" : { + "id" : "obj-537", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5526.000164687633514, 2629.333411693572998, 134.0, 22.0 ], + "text" : "prepend looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-538", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5526.000164687633514, 2601.333410859107971, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-530", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 5432.00016188621521, 4351.33346301317215, 31.0, 22.0 ], + "text" : "t b s" + } + + } +, { + "box" : { + "id" : "obj-508", + "linecount" : 5, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2839.0, 643.0, 150.0, 74.0 ], + "text" : "NOTE: ENSURE MAX SIZE OF DUMMY LOOPER STAYS CONSISTENT WITH OTHERS" + } + + } +, { + "box" : { + "id" : "obj-111", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 3549.999873042106628, 731.0, 156.0, 22.0 ], + "text" : "buffer~ #0-dummy 20000" + } + + } +, { + "box" : { + "id" : "obj-494", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3738.499911785125732, 1906.666621208190918, 50.0, 22.0 ], + "text" : "1." + } + + } +, { + "box" : { + "id" : "obj-469", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5257.943884491920471, 2207.476618409156799, 180.000004291534424, 20.0 ], + "text" : "0 is reserved as a \"null\" queryid" + } + + } +, { + "box" : { + "id" : "obj-468", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 5226.16818380355835, 2205.607459545135498, 29.5, 22.0 ], + "text" : "+ 1" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-457", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1490.0, 599.0, 68.0, 22.0 ], + "text" : "s #0-gen" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-478", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 5379.0, 436.000012993812561, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "id" : "obj-507", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5420.512875437736511, 482.905987799167633, 100.0, 22.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-476", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1377.5, 593.0, 73.0, 22.0 ], + "text" : "s #0-sync" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-475", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4338.0, 1628.5, 71.0, 22.0 ], + "text" : "r #0-sync" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-461", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 677.0, 461.156999230384827, 63.0, 22.0 ], + "text" : "r #0-api" + } + + } +, { + "box" : { + "id" : "obj-446", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 620.0, 1881.0, 146.0, 22.0 ], + "text" : "print #0-reset-initrecord" + } + + } +, { + "box" : { + "id" : "obj-445", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2142.857122421264648, 4252.380911827087402, 134.0, 22.0 ], + "text" : "print #0-reset-outport" + } + + } +, { + "box" : { + "id" : "obj-438", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4044.0, 1576.774146556854248, 119.0, 22.0 ], + "text" : "print #0-reset-stop" + } + + } +, { + "box" : { + "id" : "obj-433", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4238.0, 2112.0, 141.0, 22.0 ], + "text" : "print #0-reset-ext-sync" + } + + } +, { + "box" : { + "id" : "obj-429", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 865.161264538764954, 2998.709588050842285, 181.0, 22.0 ], + "text" : "print #0-reset-update-loopsize" + } + + } +, { + "box" : { + "id" : "obj-421", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4461.67646598815918, 659.0, 132.0, 22.0 ], + "text" : "print #0-reset-wetbuf" + } + + } +, { + "box" : { + "id" : "obj-420", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3632.67646598815918, 631.0, 136.0, 22.0 ], + "text" : "print #0-reset-loopbuf" + } + + } +, { + "box" : { + "id" : "obj-371", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "float" ], + "patching_rect" : [ 4323.305485367774963, 894.0, 29.5, 22.0 ], + "text" : "t b f" + } + + } +, { + "box" : { + "id" : "obj-372", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4323.305485367774963, 924.5, 50.0, 22.0 ], + "text" : "10000." + } + + } +, { + "box" : { + "id" : "obj-345", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 0, + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 0.0, 0.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-336", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 100.0, 29.5, 22.0 ], + "text" : "> 0." + } + + } +, { + "box" : { + "id" : "obj-65", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 135.742953062057495, 97.0, 22.0 ], + "text" : "s #0-playstate" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-341", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 49.99992550807201, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-343", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 84.99992550807201, 40.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-65", 0 ], + "source" : [ "obj-336", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-336", 0 ], + "source" : [ "obj-341", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-65", 0 ], + "source" : [ "obj-343", 0 ] + } + + } + ], + "originid" : "pat-269" + } +, + "patching_rect" : [ 3880.0, 1960.0, 97.0, 22.0 ], + "text" : "p send-playstate" + } + + } +, { + "box" : { + "id" : "obj-312", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2100.000110149383545, 1951.724240303039551, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-157", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2100.000110149383545, 1920.689755916595459, 95.0, 22.0 ], + "text" : "r #0-playstate" + } + + } +, { + "box" : { + "id" : "obj-97", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 3, + "outlettype" : [ "bang", "bang", "" ], + "patching_rect" : [ 2100.000110149383545, 2034.482865333557129, 44.0, 22.0 ], + "text" : "sel 0 1" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-367", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 6128.0, 3317.5, 145.0, 22.0 ], + "text" : "r #0-playback-triggered" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-366", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4288.67646598815918, 1897.5, 147.0, 22.0 ], + "text" : "s #0-playback-triggered" + } + + } +, { + "box" : { + "id" : "obj-365", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "int", "bang" ], + "patching_rect" : [ 4276.67646598815918, 1793.5, 32.0, 22.0 ], + "text" : "t 0 b" + } + + } +, { + "box" : { + "id" : "obj-361", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 4288.67646598815918, 1825.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-335", + "linecount" : 4, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 6085.516824245452881, 3374.482527315616608, 150.0, 60.0 ], + "text" : "end of loopsync or playback retrigger, whichever comes first (to support sync)" + } + + } +, { + "box" : { + "id" : "obj-125", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5136.0, 1879.5, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "id" : "obj-351", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3844.0, 1632.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-274", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4276.67646598815918, 1654.5, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "bgcolor" : [ 1.0, 1.0, 1.0, 0.0 ], + "fontsize" : 10.0, + "id" : "obj-270", + "maxclass" : "textbutton", + "mode" : 1, + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "", "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 4276.67646598815918, 1685.5, 50.306480064988136, 18.632936835289001 ], + "presentation" : 1, + "presentation_rect" : [ 810.404564380645752, 245.664721727371216, 27.835049986839294, 18.556699991226196 ], + "text" : "free", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "texton" : "sync", + "textoncolor" : [ 1.0, 1.0, 1.0, 1.0 ] + } + + } +, { + "box" : { + "angle" : 270.0, + "bgcolor" : [ 0.352941176470588, 0.584313725490196, 0.831372549019608, 1.0 ], + "id" : "obj-310", + "maxclass" : "panel", + "mode" : 0, + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4272.67646598815918, 1685.5, 53.354448020458221, 17.65304160118103 ], + "presentation" : 1, + "presentation_rect" : [ 805.202252626419067, 245.664721727371216, 36.082472205162048, 17.869414806365967 ], + "proportion" : 0.5 + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-414", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3892.0, 1836.0, 158.0, 22.0 ], + "text" : "s #0-play-queue-released" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-413", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3952.0, 1800.0, 115.0, 22.0 ], + "text" : "s #0-play-queued" + } + + } +, { + "box" : { + "id" : "obj-393", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 3892.0, 1800.0, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-391", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 3930.000374794006348, 1720.0, 33.0, 22.0 ], + "text" : "== 1" + } + + } +, { + "box" : { + "id" : "obj-392", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3930.000374794006348, 1756.153849601745605, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-382", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 3844.0, 1720.0, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-383", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3844.0, 1756.0, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-373", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4540.67646598815918, 1633.5, 112.459530472755432, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 943.352531433105469, 258.381483793258667, 89.640705943107605, 20.0 ], + "text" : "length" + } + + } +, { + "box" : { + "fontsize" : 50.0, + "id" : "obj-364", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4298.67646598815918, 1517.5, 338.0, 62.0 ], + "text" : "playback sync" + } + + } +, { + "box" : { + "id" : "obj-362", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4236.67646598815918, 1709.5, 112.459530472755432, 20.0 ], + "text" : "1 = sync on" + } + + } +, { + "box" : { + "id" : "obj-352", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4276.67646598815918, 1757.5, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-350", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 4364.67646598815918, 1673.5, 296.0, 22.0 ], + "text" : "metro 1n @active 1 @transport internal @quantize 1n" + } + + } +, { + "box" : { + "bgcolor" : [ 0.231372549019608, 0.243137254901961, 0.223529411764706, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.231372549019608, 0.243137254901961, 0.223529411764706, 1.0 ], + "bgfillcolor_color1" : [ 0.556862745098039, 0.270588235294118, 0.270588235294118, 1.0 ], + "bgfillcolor_color2" : [ 0.163688058058427, 0.163688010157025, 0.163688022674427, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 8.0, + "id" : "obj-327", + "items" : [ "1n", ",", "2n", ",", "4n" ], + "maxclass" : "umenu", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 4612.67646598815918, 1633.5, 74.509806275367737, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 806.936356544494629, 275.722522974014282, 34.364259243011475, 17.0 ] + } + + } +, { + "box" : { + "id" : "obj-306", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4280.67646598815918, 1629.5, 40.812580943107605, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 919.907515048980713, 423.699390649795532, 40.812580943107605, 20.0 ], + "text" : "time" + } + + } +, { + "box" : { + "id" : "obj-262", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 578.0, 1881.0, 29.5, 22.0 ], + "text" : "1" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-47", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 578.0, 1841.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "id" : "obj-334", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1347.0, 1161.0, 134.0, 22.0 ], + "text" : "prepend looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-328", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1347.0, 1198.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-325", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 1484.0, 1109.0, 22.0, 22.0 ], + "text" : "t b" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-320", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1484.0, 1085.0, 145.0, 22.0 ], + "text" : "r #0-get-looplength_ms" + } + + } +, { + "box" : { + "format" : 6, + "id" : "obj-313", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1347.0, 1124.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-273", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1347.0, 1086.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-272", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1325.0, 617.0, 147.0, 22.0 ], + "text" : "s #0-get-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-258", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3609.67646598815918, 919.0, 104.0, 22.0 ], + "text" : "prepend duplicate" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-206", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3725.67646598815918, 975.0, 113.0, 22.0 ], + "text" : "s #0-wetbufmsgs" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-200", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3609.67646598815918, 975.0, 111.0, 22.0 ], + "text" : "s #0-drybufmsgs" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-128", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3609.67646598815918, 875.0, 133.0, 22.0 ], + "text" : "r #0-duplicate-sketch" + } + + } +, { + "box" : { + "id" : "obj-194", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3909.67646598815918, 895.0, 137.0, 22.0 ], + "text" : "prepend sketchbufname" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-181", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3909.67646598815918, 931.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-154", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 3909.67646598815918, 819.0, 22.0, 22.0 ], + "text" : "t b" + } + + } +, { + "box" : { + "id" : "obj-133", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3909.67646598815918, 855.0, 62.0, 22.0 ], + "text" : "1104-loop" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-119", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1269.25, 552.0, 151.0, 22.0 ], + "text" : "s #0-get-sketchbufname" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-43", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3909.67646598815918, 791.0, 149.0, 22.0 ], + "text" : "r #0-get-sketchbufname" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-25", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3941.67646598815918, 819.0, 114.0, 22.0 ], + "text" : "r #0-dry-bufname" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-179", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5088.0, 2480.0, 68.0, 22.0 ], + "text" : "s #0-gen" + } + + } +, { + "box" : { + "id" : "obj-175", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "int", "int" ], + "patching_rect" : [ 5088.0, 2437.5, 29.5, 22.0 ], + "text" : "t 0 i" + } + + } +, { + "box" : { + "id" : "obj-168", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5718.0, 1888.0, 144.0, 47.0 ], + "text" : "TODO: why does setsize erase the contents of the buffer? " + } + + } +, { + "box" : { + "id" : "obj-497", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 5136.0, 1933.5, 31.0, 22.0 ], + "text" : "t s b" + } + + } +, { + "box" : { + "id" : "obj-492", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 5164.5, 2030.0, 31.0, 22.0 ], + "text" : "t b s" + } + + } +, { + "box" : { + "id" : "obj-490", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5500.0, 2517.5, 67.0, 22.0 ], + "save" : [ "#N", "thispatcher", ";", "#Q", "end", ";" ], + "text" : "thispatcher" + } + + } +, { + "box" : { + "id" : "obj-489", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-473", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 112.0, 143.920374631881714, 177.0, 22.0 ], + "text" : "script sendbox s2s-ui hidden $1" + } + + } +, { + "box" : { + "id" : "obj-450", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 112.0, 105.920374631881714, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-448", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 105.920374631881714, 33.0, 22.0 ], + "text" : "== 1" + } + + } +, { + "box" : { + "id" : "obj-441", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 137.920374631881714, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-485", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 39.999999718749905, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-486", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 85.0, 39.999999718749905, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-487", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 225.920409718749852, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-488", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 112.0, 225.920409718749852, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-487", 0 ], + "source" : [ "obj-441", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-441", 0 ], + "order" : 1, + "source" : [ "obj-448", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-450", 0 ], + "order" : 0, + "source" : [ "obj-448", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-473", 0 ], + "source" : [ "obj-450", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-488", 0 ], + "source" : [ "obj-473", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-448", 0 ], + "source" : [ "obj-485", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-441", 1 ], + "source" : [ "obj-486", 0 ] + } + + } + ], + "originid" : "pat-271" + } +, + "patching_rect" : [ 5088.0, 2521.5, 89.0, 22.0 ], + "text" : "p tabselect-s2s" + } + + } +, { + "box" : { + "id" : "obj-479", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 0.0, 0.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-455", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 97.321428120136261, 104.907555639743805, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-454", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 97.321428120136261, 137.943269610404968, 205.0, 22.0 ], + "text" : "script sendbox vampnet-ui hidden $1" + } + + } +, { + "box" : { + "id" : "obj-449", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 104.907555639743805, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-442", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 137.943269610404968, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-475", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.000046253204346, 39.999999906249968, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-476", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 85.000046253204346, 39.999999906249968, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-477", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.000046253204346, 219.943358906250069, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-478", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 97.321335253204779, 219.943358906250069, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-477", 0 ], + "source" : [ "obj-442", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-442", 0 ], + "order" : 1, + "source" : [ "obj-449", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-455", 0 ], + "order" : 0, + "source" : [ "obj-449", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-478", 0 ], + "source" : [ "obj-454", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-454", 0 ], + "source" : [ "obj-455", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-449", 0 ], + "source" : [ "obj-475", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-442", 1 ], + "source" : [ "obj-476", 0 ] + } + + } + ], + "originid" : "pat-273" + } +, + "patching_rect" : [ 5404.0, 2485.5, 117.0, 22.0 ], + "text" : "p tabselect-vampnet" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-447", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5088.0, 2361.5, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "id" : "obj-443", + "maxclass" : "tab", + "mode" : 1, + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 5088.0, 2393.5, 200.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 920.231145858764648, 215.606920480728149, 144.513832475990057, 24.175825357437134 ], + "tabs" : [ "vampnet", "sketch2sound" ] + } + + } +, { + "box" : { + "id" : "obj-436", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5136.0, 1697.5, 111.0, 22.0 ], + "text" : "combine 1 1 in.wav" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-434", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5408.0, 2564.825473785400391, 97.0, 22.0 ], + "text" : "r #0-sketchfile" + } + + } +, { + "box" : { + "id" : "obj-435", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5408.0, 2601.333410859107971, 101.0, 22.0 ], + "text" : "prepend audiofile" + } + + } +, { + "box" : { + "id" : "obj-423", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5218.691548347473145, 2305.607458770275116, 95.0, 22.0 ], + "text" : "prepend queryid" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-418", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5076.0, 2593.5, 97.0, 22.0 ], + "text" : "r #0-sketchfile" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-417", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5250.0, 1909.5, 99.0, 22.0 ], + "text" : "s #0-sketchfile" + } + + } +, { + "box" : { + "id" : "obj-416", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5076.0, 2621.5, 101.0, 22.0 ], + "text" : "prepend audiofile" + } + + } +, { + "box" : { + "id" : "obj-412", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5196.0, 2621.5, 134.0, 22.0 ], + "text" : "prepend looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-254", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5196.0, 2593.5, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-411", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5458.5, 2840.0, 150.0, 20.0 ], + "text" : "vampnet" + } + + } +, { + "box" : { + "id" : "obj-410", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5276.551362454891205, 2935.0, 137.0, 22.0 ], + "text" : "print should-not-be-here" + } + + } +, { + "box" : { + "id" : "obj-409", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 4, + "outlettype" : [ "", "", "", "" ], + "patching_rect" : [ 5088.0, 2897.5, 135.0, 22.0 ], + "text" : "route osc to-auto to-text" + } + + } +, { + "box" : { + "id" : "obj-408", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5120.0, 2805.5, 150.0, 20.0 ], + "text" : "sketch2sound" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-404", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5423.0, 3072.000045776367188, 90.0, 22.0 ], + "text" : "r #0-query-id" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-399", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5334.579397916793823, 2305.607458770275116, 92.0, 22.0 ], + "text" : "s #0-query-id" + } + + } +, { + "box" : { + "id" : "obj-398", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "int", "int" ], + "patching_rect" : [ 5218.691548347473145, 2266.355122625827789, 29.5, 22.0 ], + "text" : "t i i" + } + + } +, { + "box" : { + "id" : "obj-368", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5274.766314268112183, 2241.121477961540222, 62.0, 20.0 ], + "text" : "query id" + } + + } +, { + "box" : { + "id" : "obj-369", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5218.691548347473145, 2240.186898529529572, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-344", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5120.800076305866241, 3501.499998450279236, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-342", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5160.800076901912689, 3605.5, 50.0, 22.0 ], + "text" : "5000." + } + + } +, { + "box" : { + "id" : "obj-339", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "float" ], + "patching_rect" : [ 3180.093127012252808, 879.999999046325684, 29.5, 22.0 ], + "text" : "t b f" + } + + } +, { + "box" : { + "id" : "obj-333", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3148.843128204345703, 936.249996900558472, 50.0, 22.0 ], + "text" : "10000." + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-147", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 629.0, 252.0, 351.0, 118.0 ], + "text" : "inlet" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-315", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5264.0, 1557.5, 71.0, 22.0 ], + "text" : "s #0-play" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-314", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5126.66666666666697, 2935.0, 72.0, 22.0 ], + "text" : "s #0-auto" + } + + } +, { + "box" : { + "fontface" : 0, + "fontsize" : 6.0, + "id" : "obj-309", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5659.0, 3155.200047016143799, 57.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 216.757570505142212, 285.49288821965456, 69.0, 15.0 ], + "text" : "Status.FINISHED", + "textjustification" : 1 + } + + } +, { + "box" : { + "id" : "obj-307", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5712.0, 3125.5, 46.0, 22.0 ], + "text" : "route 0" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-143", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4585.67646598815918, 819.0, 93.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 118.78454178571701, 3.3149174451828, 63.0, 20.0 ], + "text" : "unloop", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ], + "textjustification" : 1 + } + + } +, { + "box" : { + "id" : "obj-304", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 953.125, 636.0, 423.0, 22.0 ], + "text" : "print ERROR_REVERSE_NOT_SUPPORTED_FROM_INLET_YET_PLS_FIX" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-35", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 408.0, 4140.0, 92.0, 22.0 ], + "text" : "send~ #0-out" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-301", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2038.095218658447266, 4280.952340126037598, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-300", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2038.095218658447266, 4252.380911827087402, 83.0, 22.0 ], + "text" : "prepend reset" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-299", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2038.095218658447266, 4219.047578811645508, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "id" : "obj-298", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5148.800076723098755, 3501.499998450279236, 150.0, 47.0 ], + "text" : "reconnect to bang to resize\nbuf to loaded bufsize" + } + + } +, { + "box" : { + "bgcolor" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgcolor2" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.168627450980392, 0.168627450980392, 0.168627450980392, 1.0 ], + "bgfillcolor_color1" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_color2" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 6.0, + "gradient" : 1, + "id" : "obj-280", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 677.0, 427.0, 27.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 264.225312739610672, 433.693548381328583, 22.0, 15.0 ], + "text" : "reset" + } + + } +, { + "box" : { + "id" : "obj-289", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 5988.0, 3385.5, 42.0, 22.0 ], + "text" : "edge~" + } + + } +, { + "box" : { + "id" : "obj-287", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5988.0, 3421.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-271", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 5988.0, 3353.5, 49.0, 22.0 ], + "text" : ">~ 0.99" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-269", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 5988.0, 3317.5, 136.0, 22.0 ], + "text" : "receive~ #0-loopsync" + } + + } +, { + "box" : { + "id" : "obj-188", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5988.0, 3491.20005202293396, 153.0, 22.0 ], + "text" : "text lazaro-ros-sep" + } + + } +, { + "box" : { + "id" : "obj-268", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5564.000082910060883, 3365.600050151348114, 150.0, 33.0 ], + "text" : "left: wait for the first 2\nright: wait for all 4" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-81", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5703.333503305912018, 4054.00012081861496, 93.0, 22.0 ], + "text" : "s #0-retrigger" + } + + } +, { + "box" : { + "id" : "obj-46", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 5703.333503305912018, 4020.66678649187088, 34.0, 22.0 ], + "text" : "sel 1" + } + + } +, { + "box" : { + "id" : "obj-285", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5724.000170588493347, 3852.000114798545837, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-278", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5724.000170588493347, 3824.000113964080811, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-198", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5456.0, 1721.5, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "id" : "obj-253", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 5420.0, 1801.5, 29.5, 22.0 ], + "text" : "!= 1" + } + + } +, { + "box" : { + "id" : "obj-240", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5488.0, 1833.5, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-238", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5420.0, 1833.5, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-213", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5164.5, 1970.0, 62.0, 22.0 ], + "text" : "1104-loop" + } + + } +, { + "box" : { + "id" : "obj-204", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "bang", "bang" ], + "patching_rect" : [ 5136.0, 1625.5, 41.0, 22.0 ], + "text" : "t s b b" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-197", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5520.0, 1833.5, 116.0, 22.0 ], + "text" : "r #0-wet-bufname" + } + + } +, { + "box" : { + "id" : "obj-195", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5488.0, 1865.5, 92.0, 22.0 ], + "text" : "1104-dreams" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-191", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5488.0, 1769.5, 25.0, 33.0 ], + "presentation" : 1, + "presentation_linecount" : 3, + "presentation_rect" : [ 12.051413893699646, 276.333341777324677, 26.0, 33.0 ], + "text" : "feedback?" + } + + } +, { + "box" : { + "id" : "obj-183", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 5456.0, 1769.5, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 34.806633174419403, 283.080203028395772, 19.506277497857809, 19.506277497857809 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-172", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5532.0, 1721.5, 109.0, 22.0 ], + "text" : "r #0-ai-feedback" + } + + } +, { + "box" : { + "id" : "obj-149", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-2", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 102.0, 390.0, 225.0, 22.0 ], + "text" : "send loadbang sendbox color 0.3 0.9 0.1" + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 102.0, 361.0, 227.0, 22.0 ], + "text" : "send loadmess sendbox color 0.3 0.9 0.1" + } + + } +, { + "box" : { + "id" : "obj-33", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 100.0, 189.0, 22.0 ], + "text" : "send print sendbox color 0.8 0 0.8" + } + + } +, { + "box" : { + "id" : "obj-274", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 144.0, 212.0, 22.0 ], + "text" : "send receive~ sendbox color 0.2 0 0.8" + } + + } +, { + "box" : { + "id" : "obj-273", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 70.0, 284.0, 202.0, 22.0 ], + "text" : "send send~ sendbox color 0.8 0. 0.6" + } + + } +, { + "box" : { + "id" : "obj-271", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 66.0, 244.0, 159.0, 22.0 ], + "text" : "send inlet tricolor 0.4 0.9 0.2" + } + + } +, { + "box" : { + "id" : "obj-270", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 78.0, 320.0, 195.0, 22.0 ], + "text" : "send send sendbox color 0.8 0. 0.6" + } + + } +, { + "box" : { + "id" : "obj-269", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 66.0, 192.0, 205.0, 22.0 ], + "text" : "send receive sendbox color 0.2 0 0.8" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-119", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 60.0, 40.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-128", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 57.333496000000196, 402.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "order" : 1, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "order" : 0, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-269", 0 ], + "order" : 5, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "order" : 2, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-271", 0 ], + "order" : 4, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-273", 0 ], + "order" : 3, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-274", 0 ], + "order" : 6, + "source" : [ "obj-119", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-269", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-271", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-273", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-274", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-128", 0 ], + "source" : [ "obj-33", 0 ] + } + + } + ], + "originid" : "pat-275" + } +, + "patching_rect" : [ 5380.0, 512.5, 153.0, 22.0 ], + "text" : "p color-sends-and-receives" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-114", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1044.0, 4325.0, 63.0, 22.0 ], + "text" : "r #0-rec" + } + + } +, { + "box" : { + "id" : "obj-80", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1044.0, 4365.0, 73.0, 22.0 ], + "text" : "prepend rec" + } + + } +, { + "box" : { + "id" : "obj-115", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 630.0, 1997.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-460", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5612.00016725063324, 3824.000113964080811, 66.0, 22.0 ], + "text" : "r #0-gen" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-431", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2175.862183094024658, 2072.413901805877686, 71.0, 22.0 ], + "text" : "s #0-play" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-430", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2100.000110149383545, 2072.413901805877686, 71.0, 22.0 ], + "text" : "s #0-stop" + } + + } +, { + "box" : { + "bgcolor" : [ 0.105882352941176, 0.105882352941176, 0.105882352941176, 0.0 ], + "fontface" : 1, + "fontname" : "Andale Mono Book", + "fontsize" : 12.0, + "id" : "obj-428", + "maxclass" : "textbutton", + "mode" : 1, + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "", "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 2100.000110149383545, 1993.10355281829834, 96.000001072883606, 34.745277211082566 ], + "presentation" : 1, + "presentation_rect" : [ 49.884748458862305, 420.260706223541206, 96.000001072883606, 34.745277211082566 ], + "text" : "play", + "textcolor" : [ 0.494117647058824, 0.494117647058824, 0.494117647058824, 1.0 ], + "texton" : "stop", + "textoncolor" : [ 0.545098039215686, 0.545098039215686, 0.545098039215686, 1.0 ], + "varname" : "recbutton[3]" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-427", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1968.965620517730713, 2044.827693462371826, 65.0, 22.0 ], + "text" : "s #0-rec" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-426", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1968.965620517730713, 1906.896651744842529, 63.0, 22.0 ], + "text" : "r #0-rec" + } + + } +, { + "box" : { + "id" : "obj-177", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1968.965620517730713, 1958.620792388916016, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "bgcolor" : [ 0.105882352941176, 0.105882352941176, 0.105882352941176, 0.0 ], + "fontface" : 1, + "fontname" : "Andale Mono Book", + "fontsize" : 12.0, + "id" : "obj-1127", + "maxclass" : "textbutton", + "mode" : 1, + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "", "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 1968.965620517730713, 1993.10355281829834, 96.000001072883606, 34.745277211082566 ], + "presentation" : 1, + "presentation_rect" : [ 13.745633602142334, 427.3333460688591, 49.341617166996002, 20.599997520446777 ], + "text" : "rec", + "textcolor" : [ 0.494117647058824, 0.494117647058824, 0.494117647058824, 1.0 ], + "texton" : "rec", + "textoncolor" : [ 1.0, 0.015686274509804, 0.015686274509804, 1.0 ], + "varname" : "recbutton" + } + + } +, { + "box" : { + "id" : "obj-440", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 1217.0, 611.0, 67.0, 22.0 ], + "save" : [ "#N", "thispatcher", ";", "#Q", "end", ";" ], + "text" : "thispatcher" + } + + } +, { + "box" : { + "id" : "obj-439", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1217.0, 586.0, 61.0, 22.0 ], + "text" : "hidden $1" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-425", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 754.0, 2181.0, 65.0, 22.0 ], + "text" : "s #0-rec" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-403", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 419.0, 4096.0, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 8.0, + "id" : "obj-401", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 457.92646598815918, 1140.0, 69.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 846.242712020874023, 446.242741584777832, 46.0, 15.0 ], + "text" : "out", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-14", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5988.0, 3540.000052750110626, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 12.0, + "id" : "obj-85", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3444.676450252532959, 929.999997138977051, 102.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 819.07508397102356, 209.248539447784424, 52.0, 20.0 ], + "text" : "sketch", + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ] + } + + } +, { + "box" : { + "id" : "obj-83", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 3844.0, 2004.0, 30.0, 22.0 ], + "text" : "*~ 1" + } + + } +, { + "box" : { + "id" : "obj-77", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3972.0, 1868.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-74", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 5436.0001620054245, 3902.000116288661957, 34.0, 22.0 ], + "text" : "sel 1" + } + + } +, { + "box" : { + "id" : "obj-73", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "int", "int" ], + "patching_rect" : [ 5436.0001620054245, 3873.333448767662048, 112.599937319755554, 22.0 ], + "text" : "t i i i" + } + + } +, { + "box" : { + "id" : "obj-71", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5424.000161647796631, 3952.000117778778076, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-69", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5136.0, 1517.5, 91.0, 22.0 ], + "text" : "r #0-retrigger" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-64", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5604.000167012214661, 3860.000115036964417, 28.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 60.225202552974224, 285.333341777324677, 29.0, 15.0 ], + "text" : "gen" + } + + } +, { + "box" : { + "bgcolor" : [ 0.352941176470588, 0.0, 0.396078431372549, 1.0 ], + "id" : "obj-61", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 5604.000167012214661, 3889.562617182731628, 46.874998211860657, 46.874998211860657 ], + "presentation" : 1, + "presentation_rect" : [ 83.0, 283.173795334994793, 19.319092884659767, 19.319092884659767 ], + "varname" : "toggle" + } + + } +, { + "box" : { + "id" : "obj-49", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 5424.000161647796631, 3778.000112593173981, 32.0, 22.0 ], + "text" : "t b b" + } + + } +, { + "box" : { + "id" : "obj-42", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5624.000167608261108, 4026.666786670684814, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-36", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 6012.800089597702026, 4001.600059628486633, 93.0, 22.0 ], + "text" : "s #0-retrigger" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-84", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5212.800077676773071, 3605.5, 127.0, 22.0 ], + "text" : "s #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-67", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 10, + "outlettype" : [ "float", "list", "float", "float", "float", "float", "float", "", "int", "" ], + "patching_rect" : [ 5128.800076425075531, 3553.499999225139618, 113.5, 22.0 ], + "text" : "info~ #0-buf1" + } + + } +, { + "box" : { + "fontname" : "Laca Text Book", + "fontsize" : 100.0, + "id" : "obj-29", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5240.0, 232.5, 1131.0, 107.0 ], + "text" : "object colors", + "textcolor" : [ 0.0, 0.0, 0.0, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-283", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3036.0, 1572.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-282", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4072.0, 2040.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-281", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5452.99150824546814, 378.632482469081879, 150.0, 33.0 ], + "text" : "color code all sends and receives" + } + + } +, { + "box" : { + "id" : "obj-279", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5380.0, 468.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-276", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4072.0, 2208.0, 99.0, 22.0 ], + "text" : "s #0-to-hidden" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-275", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3704.0, 1600.0, 97.0, 22.0 ], + "text" : "r #0-to-hidden" + } + + } +, { + "box" : { + "id" : "obj-267", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5380.0, 552.5, 57.0, 22.0 ], + "text" : "universal" + } + + } +, { + "box" : { + "id" : "obj-266", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3980.0, 2412.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "id" : "obj-265", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4256.0, 2408.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-264", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4256.0, 2380.666737616062164, 116.0, 22.0 ], + "text" : "r #0-wet-bufname" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-263", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3980.0, 2380.666737616062164, 114.0, 22.0 ], + "text" : "r #0-dry-bufname" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-260", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 3180.0, 1572.0, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-259", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1005.8125, 604.0, 135.0, 22.0 ], + "text" : "s #0-duplicate-sketch" + } + + } +, { + "box" : { + "id" : "obj-255", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5420.0, 1865.5, 62.0, 22.0 ], + "text" : "1104-loop" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-235", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4984.0, 2961.5, 93.0, 22.0 ], + "text" : "r #0-udpsend" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-232", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5672.0, 1821.5, 95.0, 22.0 ], + "text" : "s #0-udpsend" + } + + } +, { + "box" : { + "id" : "obj-230", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5672.0, 1785.5, 63.0, 22.0 ], + "text" : "/heartbeat" + } + + } +, { + "box" : { + "id" : "obj-158", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 5672.0, 1745.5, 69.0, 22.0 ], + "text" : "metro 1000" + } + + } +, { + "box" : { + "fontsize" : 40.0, + "id" : "obj-155", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5652.0, 1557.5, 245.0, 51.0 ], + "presentation" : 1, + "presentation_rect" : [ 595.953713178634644, 31.430945217609406, 245.0, 51.0 ], + "text" : "heartbeat" + } + + } +, { + "box" : { + "id" : "obj-129", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5812.0, 1789.5, 33.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 268.200519740581512, 268.123365994542837, 14.049585998058319, 14.049585998058319 ] + } + + } +, { + "box" : { + "id" : "obj-70", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5812.0, 1749.5, 93.0, 22.0 ], + "text" : "route /heartbeat" + } + + } +, { + "box" : { + "id" : "obj-66", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5812.0, 1713.5, 97.0, 22.0 ], + "text" : "udpreceive 8003" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-32", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5672.0, 1713.5, 70.0, 22.0 ], + "text" : "loadmess 1" + } + + } +, { + "box" : { + "id" : "obj-220", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1145.92646598815918, 1044.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-190", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5136.0, 1805.5, 57.0, 22.0 ], + "text" : "tosymbol" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-160", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5136.0, 1769.5, 68.0, 22.0 ], + "text" : "r #0-cwd" + } + + } +, { + "box" : { + "id" : "obj-156", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5136.0, 1849.5, 227.0, 22.0 ], + "text" : "combine cwd /audio/ file.wav @triggers 2" + } + + } +, { + "box" : { + "id" : "obj-86", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5164.5, 2002.0, 104.0, 22.0 ], + "text" : "prepend duplicate" + } + + } +, { + "box" : { + "id" : "obj-31", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5136.0, 1597.5, 64.0, 22.0 ], + "text" : "pack #0" + } + + } +, { + "box" : { + "id" : "obj-30", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5136.0, 1909.5, 109.0, 22.0 ], + "text" : "prepend writewave" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-28", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5460.0, 1833.5, 114.0, 22.0 ], + "text" : "r #0-dry-bufname" + } + + } +, { + "box" : { + "id" : "obj-27", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 5136.0, 2109.5, 109.0, 22.0 ], + "text" : "buffer~ #0-writer" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-10", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3201.67646598815918, 659.0, 109.0, 22.0 ], + "text" : "r #0-drybufmsgs" + } + + } +, { + "box" : { + "id" : "obj-324", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "bang", "bang", "bang" ], + "patching_rect" : [ 5424.000161647796631, 4016.000119686126709, 42.0, 22.0 ], + "text" : "t b b b" + } + + } +, { + "box" : { + "id" : "obj-323", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5400.666827619075775, 3813.333446979522705, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "id" : "obj-321", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5432.00016188621521, 4274.000127375125885, 63.0, 22.0 ], + "text" : "1104-buf1" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-319", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5444.000162243843079, 4387.333464086055756, 113.0, 22.0 ], + "text" : "s #0-wetbufmsgs" + } + + } +, { + "box" : { + "id" : "obj-318", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5432.00016188621521, 4310.666795134544373, 104.0, 22.0 ], + "text" : "prepend duplicate" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-317", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4305.67646598815918, 675.0, 111.0, 22.0 ], + "text" : "r #0-wetbufmsgs" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-305", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5476.000163197517395, 4112.000122547149658, 85.0, 22.0 ], + "text" : "r #0-patchid" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-297", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5352.000159502029419, 3988.000118851661682, 57.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 919.907515048980713, 548.554872751235962, 24.0, 15.0 ], + "text" : "cue" + } + + } +, { + "box" : { + "hidden" : 1, + "id" : "obj-295", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 5424.000161647796631, 3984.000118732452393, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 947.075143098831177, 548.554872751235962, 14.61988240480423, 14.61988240480423 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_enum" : [ "off", "on" ], + "parameter_longname" : "button[1]", + "parameter_mmax" : 1, + "parameter_modmode" : 0, + "parameter_shortname" : "button[1]", + "parameter_type" : 2 + } + + } +, + "varname" : "button[1]" + } + + } +, { + "box" : { + "id" : "obj-292", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5432.00016188621521, 4072.000121355056763, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-291", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5436.0001620054245, 3813.333446979522705, 29.5, 22.0 ], + "text" : "1" + } + + } +, { + "box" : { + "id" : "obj-288", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5464.000162839889526, 3845.333447933197021, 72.0, 20.0 ], + "text" : "in queue" + } + + } +, { + "box" : { + "id" : "obj-286", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 5436.0001620054245, 3842.000114500522614, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-284", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-1", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 38.0, 381.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-274", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 131.333335757255554, 537.333346366882324, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-275", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 227.333338618278503, 537.333346366882324, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-270", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 131.333335757255554, 458.666677355766296, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-271", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 164.666670083999634, 400.000008940696716, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-272", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 227.333338618278503, 458.666677355766296, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-266", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 282.833339810371399, 322.666673302650452, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-265", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 108.66666841506958, 322.666673302650452, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-255", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 234.000005483627319, 249.333337783813477, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-258", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 234.000005483627319, 158.66666841506958, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-259", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 330.000008344650269, 249.333337783813477, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-260", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 267.333339810371399, 100.0, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-263", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 330.000008344650269, 158.66666841506958, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-235", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 50.0, 252.000004529953003, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-220", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 50.0, 161.333335161209106, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-237", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 146.000002861022949, 252.000004529953003, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-240", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 83.33333432674408, 102.666666746139526, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "id" : "obj-253", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 146.000002861022949, 161.333335161209106, 55.0, 22.0 ], + "text" : "onebang" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-279", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 60.666692997642713, 39.999999749862695, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-280", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 108.666692997642713, 39.999999749862695, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-281", + "index" : 3, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 244.666692997642713, 39.999999749862695, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-282", + "index" : 4, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 292.666692997642713, 39.999999749862695, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-283", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 173.333196997642517, 621.333312749862671, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-235", 0 ], + "source" : [ "obj-220", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-265", 0 ], + "source" : [ "obj-235", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-265", 0 ], + "source" : [ "obj-237", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-220", 1 ], + "source" : [ "obj-240", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-253", 1 ], + "midpoints" : [ 128.83333432674408, 148.333335161209106, 191.500002861022949, 148.333335161209106 ], + "source" : [ "obj-240", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-237", 0 ], + "source" : [ "obj-253", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-266", 0 ], + "source" : [ "obj-255", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-255", 0 ], + "source" : [ "obj-258", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-266", 0 ], + "source" : [ "obj-259", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-258", 1 ], + "source" : [ "obj-260", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-263", 1 ], + "midpoints" : [ 312.833339810371399, 145.66666841506958, 375.500008344650269, 145.66666841506958 ], + "source" : [ "obj-260", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-259", 0 ], + "source" : [ "obj-263", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "order" : 2, + "source" : [ "obj-265", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "order" : 1, + "source" : [ "obj-265", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-271", 0 ], + "order" : 0, + "source" : [ "obj-265", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-271", 1 ], + "order" : 1, + "source" : [ "obj-266", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-272", 0 ], + "order" : 0, + "source" : [ "obj-266", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-274", 0 ], + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 1 ], + "source" : [ "obj-271", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-272", 1 ], + "midpoints" : [ 210.166670083999634, 445.666677355766296, 272.833338618278503, 445.666677355766296 ], + "source" : [ "obj-271", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-275", 0 ], + "source" : [ "obj-272", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-283", 0 ], + "source" : [ "obj-274", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-283", 0 ], + "source" : [ "obj-275", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-220", 0 ], + "order" : 1, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-240", 0 ], + "order" : 0, + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-240", 1 ], + "order" : 1, + "source" : [ "obj-280", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-253", 0 ], + "order" : 0, + "source" : [ "obj-280", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-258", 0 ], + "order" : 1, + "source" : [ "obj-281", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-260", 0 ], + "order" : 0, + "source" : [ "obj-281", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-260", 1 ], + "order" : 1, + "source" : [ "obj-282", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-263", 0 ], + "order" : 0, + "source" : [ "obj-282", 0 ] + } + + } + ], + "originid" : "pat-277" + } +, + "patching_rect" : [ 5480.0, 3338.00009948015213, 325.0, 22.0 ], + "text" : "p wait-4-all-bangs" + } + + } +, { + "box" : { + "id" : "obj-244", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5479.0, 3297.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-247", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5578.785846710205078, 3297.5, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-231", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1113.92646598815918, 1272.0, 150.0, 20.0 ], + "text" : "sample rate " + } + + } +, { + "box" : { + "id" : "obj-228", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 1105.92646598815918, 1300.0, 34.0, 22.0 ], + "text" : "sel 1" + } + + } +, { + "box" : { + "id" : "obj-227", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 769.92646598815918, 1052.0, 97.319182872772217, 20.0 ], + "text" : "patchid" + } + + } +, { + "box" : { + "id" : "obj-225", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 913.92646598815918, 1264.0, 97.319182872772217, 20.0 ], + "text" : "wet bufname" + } + + } +, { + "box" : { + "id" : "obj-223", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 741.92646598815918, 1272.0, 97.319182872772217, 20.0 ], + "text" : "dry bufname" + } + + } +, { + "box" : { + "id" : "obj-217", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5448.0, 3125.5, 98.0, 20.0 ], + "text" : "filter by query id" + } + + } +, { + "box" : { + "id" : "obj-196", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5396.0, 3121.5, 46.0, 22.0 ], + "text" : "route 0" + } + + } +, { + "box" : { + "id" : "obj-192", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5088.0, 2961.5, 101.0, 22.0 ], + "text" : "prepend /process" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-170", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5164.0, 1557.5, 52.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 928.0, 570.520189046859741, 25.0, 15.0 ], + "text" : "proc" + } + + } +, { + "box" : { + "id" : "obj-167", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5226.16818380355835, 2181.308394312858582, 86.0, 22.0 ], + "text" : "random 32768" + } + + } +, { + "box" : { + "id" : "obj-162", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "bang" ], + "patching_rect" : [ 5226.16818380355835, 2145.794375896453857, 32.0, 22.0 ], + "text" : "t b b" + } + + } +, { + "box" : { + "id" : "obj-161", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 5136.0, 1557.5, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 928.0, 581.502847194671631, 24.0, 24.0 ], + "varname" : "button" + } + + } +, { + "box" : { + "id" : "obj-126", + "maxclass" : "newobj", + "numinlets" : 4, + "numoutlets" : 4, + "outlettype" : [ "", "", "", "" ], + "patching_rect" : [ 5396.0, 3033.5, 492.000014662742615, 22.0 ], + "text" : "route /process-result /heartbeat /progress" + } + + } +, { + "box" : { + "id" : "obj-95", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5504.0, 3213.5, 95.0, 22.0 ], + "text" : "prepend replace" + } + + } +, { + "box" : { + "id" : "obj-53", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5396.0, 3213.5, 95.0, 22.0 ], + "text" : "prepend replace" + } + + } +, { + "box" : { + "id" : "obj-41", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 5504.0, 3253.5, 103.0, 22.0 ], + "text" : "buffer~ #0-buf2" + } + + } +, { + "box" : { + "id" : "obj-37", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 5396.0, 3253.5, 103.0, 22.0 ], + "text" : "buffer~ #0-buf1" + } + + } +, { + "box" : { + "id" : "obj-22", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5397.0, 3157.200047016143799, 126.0, 22.0 ], + "text" : "unpack audio1 audio2" + } + + } +, { + "box" : { + "id" : "obj-134", + "linecount" : 5, + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4916.0, 3037.5, 213.0, 76.0 ], + "text" : "/process 132 vampnet /Users/hugo/projects/research/unloop-2025/vampnet/unloop/max/audio/1104in.wav lazaro-ros-sep 0 0. 1958 10000. 0 0.15 64 4 0 32 1. 0.8 0. 1" + } + + } +, { + "box" : { + "id" : "obj-130", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 5396.0, 2997.5, 97.0, 22.0 ], + "text" : "udpreceive 8003" + } + + } +, { + "box" : { + "id" : "obj-101", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5088.0, 3001.5, 135.0, 22.0 ], + "text" : "udpsend localhost 8001" + } + + } +, { + "box" : { + "id" : "obj-976", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-6", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 90.0, 29.5, 22.0 ], + "text" : "." + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-2", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 50.0, 43.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "id" : "obj-40", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 50.0, 138.118452911569193, 31.0, 22.0 ], + "text" : "t s b" + } + + } +, { + "box" : { + "fontname" : "Geneva", + "fontsize" : 9.0, + "id" : "obj-89", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 136.271084070205688, 182.937455843597263, 68.0, 20.0 ], + "text" : "substitute \" \"" + } + + } +, { + "box" : { + "fontname" : "Geneva", + "fontsize" : 9.0, + "id" : "obj-102", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 5, + "outlettype" : [ "", "", "", "", "" ], + "patching_rect" : [ 50.0, 223.83673390580725, 73.0, 20.0 ], + "text" : "regexp ^.+:" + } + + } +, { + "box" : { + "id" : "obj-61", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 98.0, 90.0, 67.0, 22.0 ], + "text" : "loadmess ." + } + + } +, { + "box" : { + "id" : "obj-63", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 182.937455843597263, 77.0, 22.0 ], + "text" : "absolutepath" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-260", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.000007571424931, 303.836728543767549, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-260", 0 ], + "source" : [ "obj-102", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-6", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-63", 0 ], + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-89", 0 ], + "source" : [ "obj-40", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-6", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-61", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-102", 0 ], + "source" : [ "obj-63", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-102", 0 ], + "source" : [ "obj-89", 0 ] + } + + } + ], + "originid" : "pat-279" + } +, + "patching_rect" : [ 1141.92646598815918, 1080.0, 63.53012353181839, 22.0 ], + "text" : "p cwd" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-977", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1141.92646598815918, 1124.0, 71.0, 22.0 ], + "text" : "s #0-cwd" + } + + } +, { + "box" : { + "id" : "obj-978", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1173.92646598815918, 1040.0, 120.0, 20.0 ], + "text" : "current working dir" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-257", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2189.352931976318359, 227.0, 665.647068023681641, 118.0 ], + "text" : "file io" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-256", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2075.0, 443.60000604391098, 160.0, 22.0 ], + "text" : "r #0-io-load-from-input-file" + } + + } +, { + "box" : { + "id" : "obj-252", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "patching_rect" : [ 2393.912964999675751, 780.869539618492126, 31.0, 22.0 ], + "text" : "t s b" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-251", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2549.352931976318359, 843.0, 127.0, 22.0 ], + "text" : "s #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-250", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 2349.352931976318359, 669.0, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "id" : "obj-249", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 10, + "outlettype" : [ "float", "list", "float", "float", "float", "float", "float", "", "int", "" ], + "patching_rect" : [ 2401.352931976318359, 843.0, 113.5, 22.0 ], + "text" : "info~" + } + + } +, { + "box" : { + "id" : "obj-248", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2443.200036406517029, 600.0, 150.0, 33.0 ], + "text" : "LOAD INPUT LOOP FROM FILE" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-246", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 2597.5, 1137.90323394536972, 154.0, 22.0 ], + "text" : "s #0-to-loopbuf-duplicate" + } + + } +, { + "box" : { + "id" : "obj-245", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2389.600035607814789, 736.000010967254639, 136.000004053115845, 22.0 ], + "text" : "#0-loaded-from-file" + } + + } +, { + "box" : { + "id" : "obj-243", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 2349.352931976318359, 579.0, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "id" : "obj-242", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2349.352931976318359, 611.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "id" : "obj-241", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2349.352931976318359, 556.000007629394531, 109.0, 22.0 ], + "text" : "$1-loaded-from-file" + } + + } +, { + "box" : { + "id" : "obj-239", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "", "", "bang" ], + "patching_rect" : [ 2245.352931976318359, 512.000007629394531, 41.0, 22.0 ], + "text" : "t s s b" + } + + } +, { + "box" : { + "id" : "obj-236", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3029.67646598815918, 679.0, 104.0, 22.0 ], + "text" : "prepend duplicate" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-234", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3029.67646598815918, 651.0, 152.0, 22.0 ], + "text" : "r #0-to-loopbuf-duplicate" + } + + } +, { + "box" : { + "id" : "obj-233", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2245.352931976318359, 669.0, 95.0, 22.0 ], + "text" : "prepend replace" + } + + } +, { + "box" : { + "id" : "obj-229", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 2245.352931976318359, 704.800010502338409, 163.0, 22.0 ], + "text" : "buffer~ #0-loaded-from-file" + } + + } +, { + "box" : { + "id" : "obj-218", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1165.92646598815918, 1316.0, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-215", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3409.67646598815918, 663.0, 66.0, 22.0 ], + "text" : "prepend sr" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-216", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3409.67646598815918, 635.0, 57.0, 22.0 ], + "text" : "r #0-sr" + } + + } +, { + "box" : { + "id" : "obj-214", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4229.67646598815918, 679.0, 66.0, 22.0 ], + "text" : "prepend sr" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-210", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4229.67646598815918, 643.0, 57.0, 22.0 ], + "text" : "r #0-sr" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-208", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 700.0, 871.0, 665.647068023681641, 118.0 ], + "text" : "globals" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-202", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1185.92646598815918, 1467.0, 59.0, 22.0 ], + "text" : "s #0-sr" + } + + } +, { + "box" : { + "id" : "obj-199", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1185.92646598815918, 1388.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-193", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "int", "float", "int", "int" ], + "patching_rect" : [ 1165.92646598815918, 1356.0, 61.0, 22.0 ], + "text" : "dspstate~" + } + + } +, { + "box" : { + "id" : "obj-186", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 913.92646598815918, 1092.0, 64.0, 22.0 ], + "text" : "pack #0" + } + + } +, { + "box" : { + "id" : "obj-94", + "linecount" : 4, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4396.0, 2488.0, 150.0, 60.0 ], + "text" : "TODO: here, we prob wanna CROSSFADE (not trapezoid) w/ the beginning of the loop. " + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-205", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 673.553681671619415, 396.0, 90.0, 22.0 ], + "text" : "loadmess reset" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-201", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1164.0, 530.0, 75.0, 22.0 ], + "text" : "s #0-reset" + } + + } +, { + "box" : { + "id" : "obj-182", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4008.0, 1912.0, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-180", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4044.0, 1544.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "id" : "obj-176", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 690.5, 2632.000033676624298, 24.0, 24.0 ] + } + + } +, { + "box" : { + "fontface" : 0, + "fontname" : "Helvetica", + "fontsize" : 10.0, + "id" : "obj-174", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3008.0, 1684.0, 36.0, 16.0 ], + "presentation" : 1, + "presentation_rect" : [ 836.416123151779175, 393.641589403152466, 34.615386307239532, 16.0 ], + "text" : "initr", + "textjustification" : 1 + } + + } +, { + "box" : { + "id" : "obj-173", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 546.0, 1969.0, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 875.144443988800049, 393.641589403152466, 17.333333849906921, 17.333333849906921 ] + } + + } +, { + "box" : { + "decodemode" : 1, + "id" : "obj-117", + "legend" : "drop audio here", + "maxclass" : "live.drop", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "parameter_enable" : 1, + "patching_rect" : [ 2245.352931976318359, 405.60000604391098, 140.0, 60.0 ], + "presentation" : 1, + "presentation_rect" : [ 137.55864229798317, 427.3333460688591, 99.242415487766266, 20.0 ], + "saved_attribute_attributes" : { + "textcolor" : { + "expression" : "themecolor.live_control_text_selection_standby" + } +, + "valueof" : { + "parameter_invisible" : 1, + "parameter_longname" : "live.drop", + "parameter_modmode" : 0, + "parameter_shortname" : "live.drop", + "parameter_type" : 4 + } + + } +, + "textcolor" : [ 0.765878792816128, 0.765878607028534, 0.765878655470994, 1.0 ], + "varname" : "live.drop" + } + + } +, { + "box" : { + "id" : "obj-123", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "signal", "bang" ], + "patching_rect" : [ 466.5, 2720.000033676624298, 48.0, 22.0 ], + "text" : "line~ 0." + } + + } +, { + "box" : { + "id" : "obj-122", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 467.0, 2683.0, 45.0, 22.0 ], + "text" : "$1 100" + } + + } +, { + "box" : { + "id" : "obj-88", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 574.452551662921906, 2868.613123297691345, 29.5, 22.0 ], + "text" : "+~" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-82", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 718.5, 2588.000033676624298, 63.0, 22.0 ], + "text" : "r #0-rec" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-79", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1111.1875, 556.0, 65.0, 22.0 ], + "text" : " s #0-rec" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-72", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 466.5, 2560.000033676624298, 95.0, 22.0 ], + "text" : "r #0-feedback" + } + + } +, { + "box" : { + "id" : "obj-68", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4156.0, 2124.0, 71.0, 22.0 ], + "text" : "outputvalue" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-51", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4156.0, 2088.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-50", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3952.0, 2208.0, 70.0, 22.0 ], + "text" : "loadmess 1" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-48", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4032.0, 2124.0, 115.0, 22.0 ], + "text" : "r #0-use-ext-sync" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-45", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1058.5, 580.0, 117.0, 22.0 ], + "text" : "s #0-use-ext-sync" + } + + } +, { + "box" : { + "id" : "obj-40", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3704.0, 1640.0, 61.0, 22.0 ], + "text" : "hidden $1" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-166", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3333.67646598815918, 807.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-165", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3333.67646598815918, 771.0, 119.0, 22.0 ], + "text" : "prepend loop-loaded" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-164", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3457.67646598815918, 771.0, 111.0, 22.0 ], + "text" : "s #0-loop-loaded" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.8, 1.0 ], + "id" : "obj-163", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1958.0, 634.0, 127.0, 22.0 ], + "text" : "print #0-invalid-msg" + } + + } +, { + "box" : { + "comment" : "signal in, messages in", + "id" : "obj-153", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 545.578226089477539, 391.83673095703125, 30.0, 30.0 ], + "tricolor" : [ 0.4, 0.9, 0.2, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-152", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 757.92646598815918, 1184.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-151", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 757.92646598815918, 1148.0, 95.0, 22.0 ], + "text" : "prepend patchid" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-146", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 900.4375, 604.0, 71.0, 22.0 ], + "text" : "s #0-stop" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-144", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 847.0, 580.0, 71.0, 22.0 ], + "text" : "s #0-play" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-142", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3972.0, 1544.0, 69.0, 22.0 ], + "text" : "r #0-stop" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-141", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3844.0, 1544.0, 69.0, 22.0 ], + "text" : "r #0-play" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-140", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 795.0625, 552.0, 75.0, 22.0 ], + "text" : "s #0-mute" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-139", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 408.0, 4261.0, 73.0, 22.0 ], + "text" : "r #0-mute" + } + + } +, { + "box" : { + "id" : "obj-138", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 408.0, 4336.0, 69.0, 22.0 ], + "text" : "expr 1 - $i1" + } + + } +, { + "box" : { + "id" : "obj-137", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "signal", "bang" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-1116", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ -2.999982486808335, 201.0, 83.0, 22.0 ], + "text" : "loadmess 100" + } + + } +, { + "box" : { + "id" : "obj-1117", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ -2.999982486808335, 231.067960739135742, 50.0, 22.0 ] + } + + } +, { + "box" : { + "id" : "obj-726", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 274.348032159561626, 67.0, 22.0 ], + "text" : "pack 0 100" + } + + } +, { + "box" : { + "id" : "obj-687", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "int", "int" ], + "patching_rect" : [ 134.5, 197.408016485923781, 29.5, 22.0 ], + "text" : "t i i" + } + + } +, { + "box" : { + "id" : "obj-686", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 134.5, 241.408016485923781, 29.5, 22.0 ], + "text" : "!=" + } + + } +, { + "box" : { + "id" : "obj-114", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 102.0, 339.277750202118568, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-115", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "signal", "bang" ], + "patching_rect" : [ 50.0, 308.318857950920574, 71.0, 22.0 ], + "text" : "line~ 1. 100" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-99", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 114.43440451319168, 117.999993066494426, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-100", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.000017513191665, 423.277825066494643, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-101", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 102.000017513191665, 423.277825066494643, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-1117", 0 ], + "source" : [ "obj-1116", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-726", 1 ], + "source" : [ "obj-1117", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-101", 0 ], + "source" : [ "obj-114", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-100", 0 ], + "source" : [ "obj-115", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-114", 0 ], + "source" : [ "obj-115", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-114", 0 ], + "source" : [ "obj-686", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-686", 0 ], + "source" : [ "obj-687", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-686", 1 ], + "source" : [ "obj-687", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-115", 0 ], + "source" : [ "obj-726", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-687", 0 ], + "order" : 0, + "source" : [ "obj-99", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-726", 0 ], + "order" : 1, + "source" : [ "obj-99", 0 ] + } + + } + ], + "originid" : "pat-281" + } +, + "patching_rect" : [ 408.0, 4368.0, 46.0, 22.0 ], + "text" : "p ramp" + } + + } +, { + "box" : { + "id" : "obj-136", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 335.0, 4400.0, 29.5, 22.0 ], + "text" : "*~" + } + + } +, { + "box" : { + "id" : "obj-124", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3568.0, 1912.0, 29.5, 22.0 ], + "text" : "-1." + } + + } +, { + "box" : { + "id" : "obj-121", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 4032.0, 2204.0, 29.5, 22.0 ], + "text" : "+ 1" + } + + } +, { + "box" : { + "id" : "obj-120", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4068.0, 2168.0, 106.97674572467804, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 775.144451379776001, 323.699398040771484, 106.97674572467804, 20.0 ], + "text" : "use external sync" + } + + } +, { + "box" : { + "id" : "obj-118", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 4032.0, 2168.0, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 891.329413890838623, 321.387259483337402, 24.0, 24.0 ] + } + + } +, { + "box" : { + "id" : "obj-113", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 4032.0, 2252.0, 68.0, 22.0 ], + "text" : "selector~ 2" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-106", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3172.0, 1772.0, 127.0, 22.0 ], + "text" : "s #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-63", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3036.0, 1604.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-107", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4412.0, 2396.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontname" : "Laca Text Book", + "fontsize" : 12.0, + "id" : "obj-55", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 3172.0, 1696.0, 40.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 77.384748995304108, 341.322295129299164, 41.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 4500 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "tapelength", + "parameter_mmax" : 10000.0, + "parameter_mmin" : 100.0, + "parameter_modmode" : 0, + "parameter_shortname" : "length", + "parameter_type" : 0, + "parameter_unitstyle" : 2 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "tapelength" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-108", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3180.0, 1647.761135101318359, 45.0, 22.0 ], + "text" : "10000." + } + + } +, { + "box" : { + "id" : "obj-109", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 2, + "outlettype" : [ "signal", "signal" ], + "patching_rect" : [ 3844.0, 2088.0, 251.0, 22.0 ], + "text" : "groove~ #0-dummy @loop 1 @loopinterp 1" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-1223", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3711.66657817363739, 1789.000001907348633, 73.0, 22.0 ], + "text" : "loadmess 0." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 11.595186999999999, + "format" : 6, + "id" : "obj-1224", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3844.0, 1912.0, 44.0, 21.0 ], + "triscale" : 0.9 + } + + } +, { + "box" : { + "id" : "obj-1225", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3972.0, 1912.0, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "bgcolor" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgcolor2" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.670588235294118, 1.0, 0.466666666666667, 1.0 ], + "bgfillcolor_color1" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_color2" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontname" : "Laca Text Book", + "fontsize" : 12.0, + "gradient" : 1, + "id" : "obj-1227", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3972.0, 1588.0, 31.0, 20.0 ], + "text" : "stop", + "textcolor" : [ 0.156862745098039, 0.156862745098039, 0.156862745098039, 1.0 ] + } + + } +, { + "box" : { + "bgcolor" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgcolor2" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.670588235294118, 1.0, 0.466666666666667, 1.0 ], + "bgfillcolor_color1" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_color2" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontname" : "Laca Text Book", + "fontsize" : 12.0, + "gradient" : 1, + "id" : "obj-1228", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3844.0, 1588.0, 31.0, 20.0 ], + "text" : "play", + "textcolor" : [ 0.156862745098039, 0.156862745098039, 0.156862745098039, 1.0 ] + } + + } +, { + "box" : { + "id" : "obj-1229", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3699.999911785125732, 1869.0, 127.0, 22.0 ], + "text" : "expr pow(2\\, ($f1 / 12))" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontname" : "Laca Text Book", + "fontsize" : 12.0, + "id" : "obj-1230", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 3699.999911785125732, 1820.666667819023132, 38.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 136.924700051546097, 341.322295129299164, 36.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "speed[2]", + "parameter_mmax" : 24.0, + "parameter_mmin" : -24.0, + "parameter_modmode" : 0, + "parameter_shortname" : "speed+", + "parameter_type" : 0, + "parameter_units" : "semitones", + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "speed[1]" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1232", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3972.0, 2040.0, 83.0, 22.0 ], + "text" : "r #0-groove" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1233", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3600.0, 1912.0, 89.0, 22.0 ], + "text" : "s #0-reverse" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1241", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 3844.0, 1960.0, 31.0, 22.0 ], + "text" : "sig~" + } + + } +, { + "box" : { + "id" : "obj-1243", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 3568.0, 1864.0, 20.0, 20.0 ] + } + + } +, { + "box" : { + "id" : "obj-98", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 1115.0, 178.0, 640.0, 480.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "id" : "obj-69", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 132.0, 32.0, 22.0 ], + "text" : "mtof" + } + + } +, { + "box" : { + "id" : "obj-55", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 89.0, 110.0, 22.0 ], + "text" : "scale 0. 1. 43. 123." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-35", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 364.0, 173.261003715011611, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-36", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 284.0, 173.261003715011611, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-37", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 173.261003715011611, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-72", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 364.0, 208.761003715011611, 55.0, 23.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-74", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 284.0, 208.761003715011611, 55.0, 23.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-75", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 194.0, 208.761003715011611, 57.0, 23.0 ] + } + + } +, { + "box" : { + "domain" : [ 20.0, 16000.0 ], + "fontface" : 0, + "id" : "obj-81", + "linmarkers" : [ 0.0, 11025.0, 16537.5 ], + "logmarkers" : [ 0.0, 100.0, 1000.0, 10000.0 ], + "maxclass" : "filtergraph~", + "nfilters" : 1, + "numinlets" : 8, + "numoutlets" : 7, + "outlettype" : [ "list", "float", "float", "float", "float", "list", "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 52.0, 245.668089365878586, 360.0, 155.0 ], + "setfilter" : [ 0, 1, 1, 0, 0, 6271.9267578125, 1.047243118286133, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], + "varname" : "filtergraph~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-63", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 663.0, 694.175741758365348, 43.0, 23.0 ], + "text" : "clear" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-40", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 630.607270287147003, 732.675741758365348, 92.0, 23.0 ], + "text" : "biquad~" + } + + } +, { + "box" : { + "attr" : "edit_mode", + "fontface" : 0, + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-41", + "lock" : 1, + "maxclass" : "attrui", + "numinlets" : 1, + "numoutlets" : 1, + "orientation" : 1, + "outlettype" : [ "" ], + "parameter_enable" : 0, + "patching_rect" : [ 50.0, 195.261003715011611, 83.0, 46.0 ], + "text_width" : 83.0 + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-95", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 39.999960758365432, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-96", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 630.607268999999974, 39.999960758365432, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-97", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 630.607268999999974, 815.675741758365348, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-72", 0 ], + "hidden" : 1, + "source" : [ "obj-35", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-74", 0 ], + "hidden" : 1, + "source" : [ "obj-36", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-75", 0 ], + "hidden" : 1, + "source" : [ "obj-37", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-97", 0 ], + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 0 ], + "source" : [ "obj-41", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-69", 0 ], + "source" : [ "obj-55", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-63", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-75", 0 ], + "source" : [ "obj-69", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 7 ], + "source" : [ "obj-72", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 6 ], + "source" : [ "obj-74", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 5 ], + "source" : [ "obj-75", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-35", 0 ], + "hidden" : 1, + "source" : [ "obj-81", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-36", 0 ], + "hidden" : 1, + "source" : [ "obj-81", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-37", 0 ], + "hidden" : 1, + "source" : [ "obj-81", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-81", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-55", 0 ], + "source" : [ "obj-95", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-96", 0 ] + } + + } + ], + "originid" : "pat-283" + } +, + "patching_rect" : [ 382.0, 4010.0, 31.0, 22.0 ], + "text" : "p lpf" + } + + } +, { + "box" : { + "id" : "obj-89", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 59.0, 106.0, 640.0, 480.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-50", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 635.66669225692749, 204.294191221928486, 43.0, 23.0 ], + "text" : "clear" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-51", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 586.66669225692749, 238.701276872795461, 92.0, 23.0 ], + "text" : "biquad~" + } + + } +, { + "box" : { + "id" : "obj-71", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 132.0, 32.0, 22.0 ], + "text" : "mtof" + } + + } +, { + "box" : { + "id" : "obj-73", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 100.0, 110.0, 22.0 ], + "text" : "scale 0. 1. 31. 123." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-42", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 364.0, 180.960900021183988, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-43", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 284.0, 180.960900021183988, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "hidden" : 1, + "id" : "obj-44", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.0, 180.960900021183988, 48.0, 23.0 ], + "text" : "set $1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-45", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 364.0, 216.460900021183988, 55.0, 23.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-46", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 284.0, 216.460900021183988, 55.0, 23.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 13.0, + "format" : 6, + "id" : "obj-47", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 194.0, 216.460900021183988, 57.0, 23.0 ] + } + + } +, { + "box" : { + "domain" : [ 20.0, 16000.0 ], + "fontface" : 0, + "id" : "obj-48", + "linmarkers" : [ 0.0, 11025.0, 16537.5 ], + "logmarkers" : [ 0.0, 100.0, 1000.0, 10000.0 ], + "maxclass" : "filtergraph~", + "nfilters" : 1, + "numinlets" : 8, + "numoutlets" : 7, + "outlettype" : [ "list", "float", "float", "float", "float", "list", "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 52.0, 253.367985672050963, 360.0, 155.0 ], + "setfilter" : [ 0, 2, 1, 0, 0, 48.999427795410156, 0.94879424571991, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ], + "varname" : "filtergraph~[1]" + } + + } +, { + "box" : { + "attr" : "edit_mode", + "fontface" : 0, + "fontname" : "Arial", + "fontsize" : 13.0, + "id" : "obj-52", + "lock" : 1, + "maxclass" : "attrui", + "numinlets" : 1, + "numoutlets" : 1, + "orientation" : 1, + "outlettype" : [ "" ], + "parameter_enable" : 0, + "patching_rect" : [ 50.0, 202.960900021183988, 83.0, 46.0 ], + "text_width" : 83.0 + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-86", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 189.000011571182483, 39.999918775974947, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-87", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 586.666698571182451, 39.999918775974947, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-88", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 586.666698571182451, 476.441813775975334, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-45", 0 ], + "hidden" : 1, + "source" : [ "obj-42", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-46", 0 ], + "hidden" : 1, + "source" : [ "obj-43", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-47", 0 ], + "hidden" : 1, + "source" : [ "obj-44", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-48", 7 ], + "source" : [ "obj-45", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-48", 6 ], + "source" : [ "obj-46", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-48", 5 ], + "source" : [ "obj-47", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-42", 0 ], + "hidden" : 1, + "source" : [ "obj-48", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-43", 0 ], + "hidden" : 1, + "source" : [ "obj-48", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-44", 0 ], + "hidden" : 1, + "source" : [ "obj-48", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-51", 0 ], + "source" : [ "obj-48", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-51", 0 ], + "source" : [ "obj-50", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-88", 0 ], + "source" : [ "obj-51", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-48", 0 ], + "source" : [ "obj-52", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-47", 0 ], + "source" : [ "obj-71", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-71", 0 ], + "source" : [ "obj-73", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-73", 0 ], + "source" : [ "obj-86", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-51", 0 ], + "source" : [ "obj-87", 0 ] + } + + } + ], + "originid" : "pat-285" + } +, + "patching_rect" : [ 339.0, 4076.0, 35.0, 22.0 ], + "text" : "p hpf" + } + + } +, { + "box" : { + "id" : "obj-60", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 438.0, 2225.0, 138.0, 22.0 ], + "text" : "prepend initrecordtoggle" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-16", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 438.0, 2257.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-59", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 880.0, 4409.0, 86.0, 22.0 ], + "text" : "s #0-outport" + } + + } +, { + "box" : { + "id" : "obj-58", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 880.0, 4365.0, 134.0, 22.0 ], + "text" : "prepend looplength_ms" + } + + } +, { + "box" : { + "comment" : "output messages. ", + "id" : "obj-57", + "index" : 2, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1933.333314895629883, 4480.952338218688965, 30.0, 30.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-56", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1933.333314895629883, 4447.61900520324707, 119.0, 22.0 ], + "text" : "receive #0-outport" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-39", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 342.5, 2772.000033676624298, 36.0, 22.0 ], + "text" : "*~ 1." + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-38", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 342.5, 2560.000033676624298, 122.0, 22.0 ], + "text" : "receive~ #0-dream" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-34", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 347.023806214332581, 2913.983120322227478, 126.0, 22.0 ], + "text" : "poke~ #0-dreams 1" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontsize" : 12.0, + "id" : "obj-76", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 331.0, 4023.0, 37.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 200.801057785749435, 379.338821947574615, 36.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "hpf", + "parameter_mmax" : 1.0, + "parameter_modmode" : 0, + "parameter_shortname" : "hpf", + "parameter_type" : 0, + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "hpf" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontsize" : 12.0, + "id" : "obj-54", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 382.0, 3961.0, 37.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 200.801057785749435, 341.322295129299164, 36.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 0.75 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "lpf", + "parameter_mmax" : 1.0, + "parameter_modmode" : 0, + "parameter_shortname" : "lpf", + "parameter_type" : 0, + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "lpf" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-24", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 878.5, 2521.000033676624298, 166.0, 22.0 ], + "text" : "receive~ #0-sped-loopsync" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-23", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4108.0, 2336.0, 153.0, 22.0 ], + "text" : "send~ #0-sped-loopsync" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "format" : 6, + "id" : "obj-226", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1130.5, 2528.000033676624298, 79.0, 22.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "format" : 6, + "id" : "obj-224", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1130.5, 2456.000033676624298, 62.418427000000001, 22.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-222", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "signal", "float" ], + "patching_rect" : [ 1130.5, 2484.000033676624298, 79.0, 22.0 ], + "text" : "mstosamps~" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-221", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1130.5, 2380.000033676624298, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-21", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 741.0, 604.0, 127.0, 22.0 ], + "text" : "s #0-looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-20", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 689.6875, 548.0, 98.0, 22.0 ], + "text" : "s #0-initrecord" + } + + } +, { + "box" : { + "id" : "obj-19", + "maxclass" : "newobj", + "numinlets" : 22, + "numoutlets" : 22, + "outlettype" : [ "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" ], + "patching_rect" : [ 637.0, 504.0, 1189.0, 22.0 ], + "text" : "route voicenum initrecord looplength_ms mute play stop reverse duplicate-sketch use-ext-sync rec reset hidden get-sketchbufname get-looplength_ms sync panelcolor gen s2s-ctrl rec-play-footsw stop-reset-footsw vampnet" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-18", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 472.0, 1927.0, 96.0, 22.0 ], + "text" : "r #0-initrecord" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-17", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4108.0, 2296.0, 123.0, 22.0 ], + "text" : "send~ #0-loopsync" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-15", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 880.0, 4325.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "id" : "obj-11", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 3829.67646598815918, 587.0, 31.0, 22.0 ], + "text" : "t b s" + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 4593.67646598815918, 631.0, 31.0, 22.0 ], + "text" : "t b s" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-13", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 869.92646598815918, 1148.0, 87.0, 22.0 ], + "text" : "s #0-patchid" + } + + } +, { + "box" : { + "id" : "obj-12", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 973.92646598815918, 1148.0, 50.0, 22.0 ], + "text" : "1104" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-9", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 913.92646598815918, 1048.0, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-8", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 769.92646598815918, 1380.0, 116.0, 22.0 ], + "text" : "s #0-dry-bufname" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-7", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 917.92646598815918, 1380.0, 118.0, 22.0 ], + "text" : "s #0-wet-bufname" + } + + } +, { + "box" : { + "id" : "obj-5", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 770.0, 1347.0, 49.0, 22.0 ], + "text" : "$1-loop" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-6", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 769.92646598815918, 1304.0, 85.0, 22.0 ], + "text" : "r #0-patchid" + } + + } +, { + "box" : { + "id" : "obj-4", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 918.0, 1343.0, 66.0, 22.0 ], + "text" : "$1-dreams" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 917.92646598815918, 1304.0, 85.0, 22.0 ], + "text" : "r #0-patchid" + } + + } +, { + "box" : { + "comment" : "groove sync signal in", + "id" : "obj-2", + "index" : 2, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4172.0, 2208.0, 30.0, 30.0 ], + "tricolor" : [ 0.4, 0.9, 0.2, 1.0 ] + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-1295", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 284.0, 3568.0, 1148.0, 118.0 ], + "text" : "channel outputs" + } + + } +, { + "box" : { + "id" : "obj-1273", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 538.0, 2165.0, 29.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "id" : "obj-1274", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 538.0, 2129.0, 22.0, 22.0 ], + "text" : "t b" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-1275", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 438.0, 2165.0, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1281", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 630.0, 1965.0, 69.0, 22.0 ], + "text" : "r #0-play" + } + + } +, { + "box" : { + "id" : "obj-1282", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 598.0, 2025.0, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1284", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 638.0, 2121.0, 32.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1287", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 598.0, 2205.0, 143.0, 22.0 ], + "text" : "s #0-update_loop_size" + } + + } +, { + "box" : { + "id" : "obj-1289", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 598.0, 2061.0, 22.143951000000001, 22.143951000000001 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1290", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 3, + "outlettype" : [ "bang", "bang", "" ], + "patching_rect" : [ 598.0, 2089.0, 330.0, 22.0 ], + "text" : "sel 0 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1294", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 754.0, 2121.0, 22.0, 22.0 ], + "text" : "t 1" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-1272", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 626.751543045043945, 1592.356562614440918, 475.0, 118.0 ], + "text" : "recording" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-1254", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 61.259715800042613, 295.833322048187256, 351.0, 118.0 ], + "text" : "inputs" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-1264", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 184.0, 651.0, 85.0, 22.0 ], + "text" : "send~ #0-in" + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-1265", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 192.0, 435.0, 70.0, 22.0 ], + "text" : "loadmess 1" + } + + } +, { + "box" : { + "id" : "obj-1266", + "maxclass" : "newobj", + "numinlets" : 10, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 184.0, 603.0, 113.5, 22.0 ], + "text" : "selector~ 9 1" + } + + } +, { + "box" : { + "bgcolor" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_color1" : [ 0.301961, 0.301961, 0.301961, 1.0 ], + "bgfillcolor_color2" : [ 0.2, 0.2, 0.2, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 6.0, + "id" : "obj-1267", + "items" : [ "no", "input", ",", "input", 1, ",", "input", 2, ",", "input", 3, ",", "input", 4, ",", "input", 5, ",", "input", 6, ",", "input", 7, ",", "input", 8, ",", "inlet" ], + "maxclass" : "umenu", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 192.0, 499.0, 89.519431600085227, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 18.454465255141258, 323.322295129299164, 39.923953860998154, 15.0 ], + "textcolor" : [ 1.0, 1.0, 1.0, 1.0 ] + } + + } +, { + "box" : { + "id" : "obj-1271", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 8, + "outlettype" : [ "signal", "signal", "signal", "signal", "signal", "signal", "signal", "signal" ], + "patching_rect" : [ 204.0, 543.0, 115.0, 22.0 ], + "text" : "adc~ 1 2 3 4 5 6 7 8" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-1253", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3600.0, 1352.0, 418.548390090465546, 118.0 ], + "text" : "playback" + } + + } +, { + "box" : { + "fontsize" : 100.0, + "id" : "obj-1252", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3289.67646598815918, 339.0, 665.647068023681641, 118.0 ], + "text" : "buffer control" + } + + } +, { + "box" : { + "id" : "obj-1169", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 4032.0, 2336.0, 68.0, 22.0 ], + "text" : "modulo~ 1." + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-1184", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3672.0, 2552.0, 145.0, 22.0 ], + "text" : "s #0-dreams-waveform" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-1185", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3568.0, 2552.0, 101.0, 22.0 ], + "text" : "s #0-waveform" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-1213", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4256.0, 2484.920673429965973, 110.0, 22.0 ], + "text" : "send~ #0-dream" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "id" : "obj-1214", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3980.0, 2484.920673429965973, 98.0, 22.0 ], + "text" : "send~ #0-loop" + } + + } +, { + "box" : { + "id" : "obj-1220", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 4256.0, 2440.0, 174.0, 22.0 ], + "text" : "wave~ #0-dreams 0 20000 1" + } + + } +, { + "box" : { + "id" : "obj-1221", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 3980.0, 2444.0, 157.0, 22.0 ], + "text" : "wave~ #0-loop 0 20000 1" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1247", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3624.0, 2400.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "format" : 6, + "id" : "obj-1248", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 3568.0, 2400.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1249", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 3568.0, 2464.0, 47.0, 22.0 ], + "text" : "* 5000." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1250", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "float" ], + "patching_rect" : [ 3568.0, 2376.0, 83.0, 22.0 ], + "text" : "snapshot~ 10" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1251", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3568.0, 2497.499940454959869, 50.0, 22.0 ], + "text" : "line $1" + } + + } +, { + "box" : { + "channels" : 1, + "id" : "obj-1128", + "lastchannelcount" : 0, + "maxclass" : "live.gain~", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "signal", "", "float", "list" ], + "parameter_enable" : 1, + "patching_rect" : [ 674.5, 2464.000033676624298, 41.0, 136.0 ], + "presentation" : 1, + "presentation_rect" : [ 17.916442185640335, 358.677666068077087, 41.0, 61.0 ], + "saved_attribute_attributes" : { + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_linknames" : 1, + "parameter_longname" : "gain[4]", + "parameter_mmax" : 30.0, + "parameter_mmin" : -70.0, + "parameter_modmode" : 0, + "parameter_shortname" : "gain", + "parameter_type" : 0, + "parameter_unitstyle" : 4 + } + + } +, + "textcolor" : [ 0.67843137254902, 0.698039215686274, 0.76078431372549, 1.0 ], + "varname" : "gain[4]" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1129", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 674.5, 2432.000033676624298, 98.0, 22.0 ], + "text" : "receive~ #0-in" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1130", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 574.5, 2391.666643857955933, 111.0, 22.0 ], + "text" : "receive~ #0-loop" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1133", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1130.5, 2900.000033676624298, 150.0, 20.0 ], + "text" : "set the new loop size" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1134", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 938.5, 2736.000033676624298, 59.108398000000001, 33.0 ], + "text" : "a slight offset..." + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1136", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1134.5, 2932.000033676624298, 141.0, 22.0 ], + "text" : "r #0-update_loop_size" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1139", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 574.5, 2772.000033676624298, 36.0, 22.0 ], + "text" : "*~ 1." + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "annotation" : "", + "appearance" : 1, + "fontsize" : 12.0, + "id" : "obj-1140", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 466.5, 2608.000033676624298, 32.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 136.924700051546097, 379.338821947574615, 50.451828248798847, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 1.0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "overdub", + "parameter_mmax" : 1.0, + "parameter_modmode" : 0, + "parameter_shortname" : "overdub", + "parameter_type" : 0, + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "overdub" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1142", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 898.5, 2648.000033676624298, 87.0, 22.0 ], + "text" : "r #0-reverse" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "format" : 6, + "id" : "obj-1143", + "maxclass" : "flonum", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 1122.5, 3020.000033676624298, 76.088318000000001, 22.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1144", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1182.5, 3088.000033676624298, 127.0, 22.0 ], + "text" : "s #0-looplength_ms" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1145", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1026.5, 2936.000033676624298, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "fontface" : 1, + "fontname" : "Arial", + "fontsize" : 16.0, + "id" : "obj-1146", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 722.619040727615356, 2635.13495922088623, 79.0, 24.0 ], + "text" : "record", + "textcolor" : [ 1.0, 0.0, 0.0, 1.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1147", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 50.0, 94.0, 318.0, 382.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-2", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 149.0, 127.0, 128.0, 47.0 ], + "text" : "wait for audio to fade out (5ms) before shutting off record" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-25", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 206.0, 32.5, 22.0 ], + "text" : "+ 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-22", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 88.0, 157.0, 32.5, 22.0 ], + "text" : "0" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-17", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 88.0, 129.0, 49.0, 22.0 ], + "text" : "delay 5" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-16", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 129.0, 32.5, 22.0 ], + "text" : "1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-14", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 50.0, 100.0, 57.0, 22.0 ], + "text" : "sel 1" + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-45", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 50.0, 40.0, 25.0, 25.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-47", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 286.0, 25.0, 25.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-16", 0 ], + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-17", 0 ], + "source" : [ "obj-14", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-25", 0 ], + "source" : [ "obj-16", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-22", 0 ], + "source" : [ "obj-17", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-25", 0 ], + "midpoints" : [ 97.5, 189.5, 59.5, 189.5 ], + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-47", 0 ], + "source" : [ "obj-25", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-45", 0 ] + } + + } + ], + "originid" : "pat-287" + } +, + "patching_rect" : [ 774.5, 2708.000033676624298, 63.0, 22.0 ], + "text" : "p selector" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1148", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 810.5, 2732.000033676624298, 50.0, 22.0 ], + "text" : "sig~ -1." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1149", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 774.5, 2768.000033676624298, 85.0, 22.0 ], + "text" : "selector~ 2 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1150", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "bang", "" ], + "patching_rect" : [ 898.5, 2676.000033676624298, 52.0, 22.0 ], + "text" : "sel 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1151", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 898.5, 2704.000033676624298, 29.5, 22.0 ], + "text" : "1." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1152", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 934.5, 2704.000033676624298, 29.5, 22.0 ], + "text" : "1." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1153", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1186.5, 2960.000033676624298, 94.0, 20.0 ], + "text" : "wait for fadeout" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1154", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 922.5, 2596.000033676624298, 45.5, 33.0 ], + "text" : "adjust sync" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1155", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 618.5, 2716.000033676624298, 69.0, 20.0 ], + "text" : "remove DC" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1156", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 1134.5, 2960.000033676624298, 49.0, 22.0 ], + "text" : "delay 5" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1157", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 691.0, 2695.0, 34.0, 22.0 ], + "text" : "$1 5" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1158", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 2, + "outlettype" : [ "signal", "bang" ], + "patching_rect" : [ 690.5, 2716.000033676624298, 36.0, 22.0 ], + "text" : "line~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1159", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 674.5, 2744.000033676624298, 36.0, 22.0 ], + "text" : "*~ 0." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1160", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "signal", "float" ], + "patching_rect" : [ 1122.5, 3044.000033676624298, 79.0, 22.0 ], + "text" : "sampstoms~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1161", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1026.5, 2968.000033676624298, 37.0, 22.0 ], + "text" : "reset" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1162", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 4, + "outlettype" : [ "signal", "signal", "float", "float" ], + "patching_rect" : [ 1082.5, 2992.000033676624298, 60.0, 22.0 ], + "text" : "minmax~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1163", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 34.0, 87.0, 152.0, 221.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "comment" : "", + "id" : "obj-4", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 15.0, 153.0, 25.0, 25.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-1", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 15.0, 15.0, 25.0, 25.0 ] + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-27", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 15.0, 122.0, 32.5, 22.0 ], + "text" : "+~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-16", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 28.0, 93.0, 40.0, 22.0 ], + "text" : "*~ -1." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-12", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 28.0, 65.0, 80.0, 22.0 ], + "text" : "onepole~ 20." + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-12", 0 ], + "midpoints" : [ 24.5, 53.0, 37.5, 53.0 ], + "order" : 0, + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-27", 0 ], + "order" : 1, + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-16", 0 ], + "source" : [ "obj-12", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-27", 1 ], + "source" : [ "obj-16", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-27", 0 ] + } + + } + ], + "originid" : "pat-289" + } +, + "patching_rect" : [ 674.5, 2772.000033676624298, 55.0, 22.0 ], + "text" : "p hipass" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1164", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 878.5, 2736.000033676624298, 40.0, 22.0 ], + "text" : "+~ -3." + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1165", + "maxclass" : "newobj", + "numinlets" : 3, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 722.619040727615356, 2913.983120322227478, 132.0, 22.0 ], + "text" : "poke~ #0-loop 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1167", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 878.5, 2608.000033676624298, 44.0, 22.0 ], + "text" : "trunc~" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1168", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 878.5, 2572.000033676624298, 76.0, 22.0 ], + "text" : "*~ 1323000." + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1122", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 599.0, 3862.0, 122.0, 22.0 ], + "text" : "receive~ #0-dream" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1123", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "signal" ], + "patching_rect" : [ 389.0, 3821.0, 111.0, 22.0 ], + "text" : "receive~ #0-loop" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontsize" : 12.0, + "id" : "obj-1124", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 501.0, 3848.0, 32.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 75.696064602583647, 379.338821947574615, 44.377368785440922, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 1.0 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "morph", + "parameter_mmax" : 1.0, + "parameter_modmode" : 0, + "parameter_shortname" : "dry/wet", + "parameter_type" : 0, + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "morph" + } + + } +, { + "box" : { + "channels" : 1, + "fontsize" : 10.0, + "id" : "obj-1125", + "lastchannelcount" : 0, + "maxclass" : "live.gain~", + "numinlets" : 1, + "numoutlets" : 4, + "outlettype" : [ "signal", "", "float", "list" ], + "parameter_enable" : 1, + "patching_rect" : [ 339.0, 4140.0, 51.0, 136.0 ], + "presentation" : 1, + "presentation_rect" : [ 241.883371919393539, 333.884279012680054, 55.0, 67.0 ], + "saved_attribute_attributes" : { + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "level[8]", + "parameter_mmax" : 6.0, + "parameter_mmin" : -70.0, + "parameter_modmode" : 0, + "parameter_shortname" : "level", + "parameter_type" : 0, + "parameter_unitstyle" : 4 + } + + } +, + "textcolor" : [ 0.67843137254902, 0.698039215686274, 0.76078431372549, 1.0 ], + "varname" : "level[8]" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1060", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4205.555485367774963, 811.0, 143.0, 22.0 ], + "text" : "r #0-dreams-waveform" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1061", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4323.305485367774963, 866.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "bgcolor" : [ 0.0, 0.0, 0.0, 1.0 ], + "buffername" : "#0-dreams", + "clipdraw" : 1, + "fontsize" : 4.0, + "gridcolor" : [ 0.423529, 0.423529, 0.423529, 1.0 ], + "id" : "obj-1062", + "ignoreclick" : 1, + "maxclass" : "waveform~", + "numinlets" : 5, + "numoutlets" : 6, + "outlettype" : [ "float", "float", "float", "float", "list", "" ], + "patching_rect" : [ 4205.555485367774963, 968.518502354621887, 490.0, 93.0 ], + "presentation" : 1, + "presentation_rect" : [ 25.55864229798317, 24.193548560142517, 260.925228744745255, 27.0 ], + "selectioncolor" : [ 0.0, 0.0, 0.0, 0.5 ], + "setmode" : 1, + "vticks" : 0, + "waveformcolor" : [ 0.890196078431372, 0.890196078431372, 0.890196078431372, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1063", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3032.17646598815918, 855.0, 99.0, 22.0 ], + "text" : "r #0-waveform" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1064", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3180.093127012252808, 843.0, 125.0, 22.0 ], + "text" : "r #0-looplength_ms" + } + + } +, { + "box" : { + "bgcolor" : [ 0.0, 0.0, 0.0, 1.0 ], + "buffername" : "#0-loop", + "clipdraw" : 1, + "fontsize" : 4.0, + "gridcolor" : [ 0.423529, 0.423529, 0.423529, 1.0 ], + "id" : "obj-1065", + "maxclass" : "waveform~", + "numinlets" : 5, + "numoutlets" : 6, + "outlettype" : [ "float", "float", "float", "float", "list", "" ], + "patching_rect" : [ 3031.093128204345703, 1004.237312078475952, 490.0, 93.0 ], + "presentation" : 1, + "presentation_rect" : [ 25.521256670355797, 55.645161688327789, 261.769065991044044, 23.0 ], + "selectioncolor" : [ 0.0, 0.0, 0.0, 0.5 ], + "setmode" : 1, + "vticks" : 0, + "waveformcolor" : [ 0.890196078431372, 0.890196078431372, 0.890196078431372, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1054", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3829.67646598815918, 559.0, 114.0, 22.0 ], + "text" : "r #0-dry-bufname" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1055", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3829.67646598815918, 619.0, 79.0, 22.0 ], + "text" : "1104-loop" + } + + } +, { + "box" : { + "id" : "obj-1056", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3829.67646598815918, 651.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-1052", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4593.67646598815918, 599.0, 116.0, 22.0 ], + "text" : "r #0-wet-bufname" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-1051", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4593.67646598815918, 663.0, 79.0, 22.0 ], + "text" : "1104-dreams" + } + + } +, { + "box" : { + "id" : "obj-1050", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4593.67646598815918, 699.0, 72.0, 22.0 ], + "text" : "prepend set" + } + + } +, { + "box" : { + "fontname" : "Laca Text Book", + "fontsize" : 100.0, + "id" : "obj-809", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 5164.0, 1381.5, 1131.0, 107.0 ], + "text" : "artificial intelligence", + "textcolor" : [ 0.0, 0.0, 0.0, 1.0 ] + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-779", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3829.67646598815918, 687.0, 101.0, 22.0 ], + "text" : "s #0-waveform" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-780", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3557.67646598815918, 631.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-781", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3625.67646598815918, 691.0, 150.0, 20.0 ], + "text" : "empty buffer for new loop" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-783", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 3201.67646598815918, 731.0, 149.0, 22.0 ], + "text" : "buffer~ #0-loop 20000 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-784", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 3557.67646598815918, 659.0, 168.0, 22.0 ], + "text" : "clear, setsize 20000, sr 48000" + } + + } +, { + "box" : { + "color" : [ 0.8, 0.0, 0.6, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-752", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 4593.67646598815918, 735.0, 145.0, 22.0 ], + "text" : "s #0-dreams-waveform" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-767", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4461.67646598815918, 635.0, 73.0, 22.0 ], + "text" : "r #0-reset" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-768", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "float", "bang" ], + "patching_rect" : [ 4229.67646598815918, 735.0, 167.0, 22.0 ], + "text" : "buffer~ #0-dreams 20000 1" + } + + } +, { + "box" : { + "fontname" : "Arial", + "fontsize" : 12.0, + "id" : "obj-769", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 4461.67646598815918, 687.0, 168.0, 22.0 ], + "text" : "clear, setsize 20000, sr 48000" + } + + } +, { + "box" : { + "angle" : 270.0, + "bgcolor" : [ 0.5, 0.5, 0.5, 1.0 ], + "border" : 4, + "bordercolor" : [ 0.611764705882353, 0.772549019607843, 0.509803921568627, 1.0 ], + "id" : "obj-356", + "maxclass" : "panel", + "mode" : 0, + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1556.0, 223.0, 128.0, 128.0 ], + "presentation" : 1, + "presentation_rect" : [ 0.806451618671417, -0.806451618671417, 300.666675627231598, 91.333336055278778 ], + "proportion" : 0.5 + } + + } +, { + "box" : { + "background" : 1, + "id" : "obj-1245", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 3925.000205874443054, 2029.333284974098206, 67.333334445953369, 20.0 ], + "text" : "dry", + "textjustification" : 1 + } + + } +, { + "box" : { + "bgcolor" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgcolor2" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.070588235294118, 0.070588235294118, 0.070588235294118, 1.0 ], + "bgfillcolor_color1" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgfillcolor_color2" : [ 0.163688058058427, 0.163688010157025, 0.163688022674427, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 10.0, + "gradient" : 1, + "id" : "obj-349", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 1903.448375701904297, 2003.448380947113037, 48.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 74.022680759429932, 428.019327320152229, 48.0, 20.0 ] + } + + } +, { + "box" : { + "bgcolor" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgcolor2" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgfillcolor_angle" : 270.0, + "bgfillcolor_autogradient" : 0.0, + "bgfillcolor_color" : [ 0.070588235294118, 0.070588235294118, 0.070588235294118, 1.0 ], + "bgfillcolor_color1" : [ 0.718066275119781, 0.460343182086945, 0.434341788291931, 1.0 ], + "bgfillcolor_color2" : [ 0.163688058058427, 0.163688010157025, 0.163688022674427, 1.0 ], + "bgfillcolor_proportion" : 0.5, + "bgfillcolor_type" : "color", + "fontsize" : 10.0, + "gradient" : 1, + "id" : "obj-370", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 2200.000115394592285, 1996.551828861236572, 48.0, 20.0 ], + "presentation" : 1, + "presentation_rect" : [ 16.914647728204727, 427.3333460688591, 44.652217090129852, 20.0 ] + } + + } +, { + "box" : { + "angle" : 270.0, + "bgcolor" : [ 0.5, 0.5, 0.5, 1.0 ], + "border" : 4, + "id" : "obj-353", + "maxclass" : "panel", + "mode" : 0, + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1244.0, 219.0, 128.0, 128.0 ], + "presentation" : 1, + "presentation_rect" : [ 4.225304991006851, 315.333342730998993, 293.064514935016632, 141.129033267498016 ], + "proportion" : 0.5 + } + + } +, { + "box" : { + "id" : "obj-474", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 5161.5, 2550.0, 67.0, 22.0 ], + "save" : [ "#N", "thispatcher", ";", "#Q", "end", ";" ], + "text" : "thispatcher" + } + + } +, { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "id" : "obj-424", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "vampnet-ui.maxpat", + "numinlets" : 1, + "numoutlets" : 1, + "offset" : [ 0.0, 0.0 ], + "outlettype" : [ "" ], + "patching_rect" : [ 5408.0, 2666.0, 286.0, 163.0 ], + "presentation" : 1, + "presentation_rect" : [ 15.69696980714798, 115.611564338207245, 270.0, 157.0 ], + "varname" : "vampnet-ui", + "viewvisibility" : 1 + } + + } +, { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "hidden" : 1, + "id" : "obj-406", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "s2s-ui.maxpat", + "numinlets" : 0, + "numoutlets" : 0, + "offset" : [ 0.0, 0.0 ], + "patching_rect" : [ 5084.0, 2677.5, 211.607140839099884, 110.714284658432007 ], + "presentation" : 1, + "presentation_rect" : [ 960.115535974502563, 143.352590560913086, 104.0, 65.0 ], + "varname" : "s2s-ui", + "viewvisibility" : 1 + } + + } +, { + "box" : { + "angle" : 270.0, + "bgcolor" : [ 0.5, 0.5, 0.5, 1.0 ], + "border" : 4, + "bordercolor" : [ 0.670588235294118, 0.509803921568627, 0.772549019607843, 1.0 ], + "id" : "obj-355", + "maxclass" : "panel", + "mode" : 0, + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1092.0, 223.0, 128.0, 128.0 ], + "presentation" : 1, + "presentation_rect" : [ 3.030302762985229, 95.666663378477097, 295.333342134952545, 218.424096316099167 ], + "proportion" : 0.5 + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-4", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-783", 0 ], + "source" : [ "obj-10", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-189", 0 ], + "source" : [ "obj-100", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-96", 0 ], + "source" : [ "obj-102", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-132", 0 ], + "source" : [ "obj-103", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-102", 0 ], + "source" : [ "obj-104", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-752", 0 ], + "order" : 0, + "source" : [ "obj-1050", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-768", 0 ], + "order" : 1, + "source" : [ "obj-1050", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1050", 0 ], + "source" : [ "obj-1051", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-1052", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-11", 0 ], + "source" : [ "obj-1054", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1056", 0 ], + "source" : [ "obj-1055", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-779", 0 ], + "order" : 0, + "source" : [ "obj-1056", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-783", 0 ], + "order" : 1, + "source" : [ "obj-1056", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1062", 0 ], + "order" : 1, + "source" : [ "obj-1060", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-390", 0 ], + "order" : 0, + "source" : [ "obj-1060", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-371", 0 ], + "source" : [ "obj-1061", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1065", 0 ], + "order" : 1, + "source" : [ "obj-1063", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-333", 0 ], + "order" : 0, + "source" : [ "obj-1063", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-339", 0 ], + "source" : [ "obj-1064", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1220", 2 ], + "order" : 0, + "source" : [ "obj-107", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1221", 2 ], + "order" : 1, + "source" : [ "obj-107", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-55", 0 ], + "source" : [ "obj-108", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-113", 1 ], + "source" : [ "obj-109", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1055", 1 ], + "source" : [ "obj-11", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1055", 0 ], + "source" : [ "obj-11", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-91", 1 ], + "source" : [ "obj-1122", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-91", 0 ], + "source" : [ "obj-1123", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-91", 2 ], + "source" : [ "obj-1124", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-136", 0 ], + "source" : [ "obj-1125", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-427", 0 ], + "source" : [ "obj-1127", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1159", 0 ], + "order" : 1, + "source" : [ "obj-1128", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-541", 0 ], + "order" : 0, + "source" : [ "obj-1128", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1128", 0 ], + "source" : [ "obj-1129", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1169", 0 ], + "order" : 2, + "source" : [ "obj-113", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-17", 0 ], + "order" : 1, + "source" : [ "obj-113", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-23", 0 ], + "order" : 0, + "source" : [ "obj-113", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1139", 0 ], + "source" : [ "obj-1130", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1156", 0 ], + "source" : [ "obj-1136", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-88", 0 ], + "source" : [ "obj-1139", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-80", 0 ], + "source" : [ "obj-114", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-122", 0 ], + "source" : [ "obj-1140", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1150", 0 ], + "source" : [ "obj-1142", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1160", 0 ], + "source" : [ "obj-1143", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1161", 0 ], + "source" : [ "obj-1145", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1149", 0 ], + "source" : [ "obj-1147", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1149", 1 ], + "midpoints" : [ 820.0, 2759.695646012798079, 817.0, 2759.695646012798079 ], + "source" : [ "obj-1148", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1165", 1 ], + "order" : 0, + "source" : [ "obj-1149", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-34", 1 ], + "order" : 1, + "source" : [ "obj-1149", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1282", 1 ], + "source" : [ "obj-115", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1151", 0 ], + "source" : [ "obj-1150", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1152", 0 ], + "source" : [ "obj-1150", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1164", 1 ], + "source" : [ "obj-1151", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1164", 1 ], + "midpoints" : [ 944.0, 2726.47097495742355, 909.0, 2726.47097495742355 ], + "source" : [ "obj-1152", 0 ] + } + + } +, { + "patchline" : { + "color" : [ 0.047059, 0.913725, 0.913725, 1.0 ], + "destination" : [ "obj-1162", 0 ], + "midpoints" : [ 1144.0, 2987.891765931518421, 1092.0, 2987.891765931518421 ], + "source" : [ "obj-1156", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1158", 0 ], + "source" : [ "obj-1157", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1159", 1 ], + "source" : [ "obj-1158", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1163", 0 ], + "source" : [ "obj-1159", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-424", 0 ], + "source" : [ "obj-116", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1144", 0 ], + "source" : [ "obj-1160", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1162", 0 ], + "order" : 0, + "source" : [ "obj-1161", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-429", 0 ], + "order" : 1, + "source" : [ "obj-1161", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1143", 0 ], + "source" : [ "obj-1162", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-308", 1 ], + "order" : 1, + "source" : [ "obj-1163", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-88", 1 ], + "order" : 0, + "source" : [ "obj-1163", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1149", 2 ], + "order" : 1, + "source" : [ "obj-1164", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1162", 0 ], + "midpoints" : [ 888.0, 2846.15140893151829, 1092.0, 2846.15140893151829 ], + "order" : 0, + "source" : [ "obj-1164", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1164", 0 ], + "source" : [ "obj-1167", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1167", 0 ], + "source" : [ "obj-1168", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1220", 0 ], + "order" : 0, + "source" : [ "obj-1169", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1221", 0 ], + "order" : 1, + "source" : [ "obj-1169", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1250", 0 ], + "order" : 2, + "source" : [ "obj-1169", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-239", 0 ], + "source" : [ "obj-117", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-121", 0 ], + "order" : 1, + "source" : [ "obj-118", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-276", 0 ], + "order" : 0, + "source" : [ "obj-118", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-113", 0 ], + "source" : [ "obj-121", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-123", 0 ], + "source" : [ "obj-122", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1213", 0 ], + "source" : [ "obj-1220", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1214", 0 ], + "source" : [ "obj-1221", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1230", 0 ], + "source" : [ "obj-1223", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1241", 0 ], + "order" : 1, + "source" : [ "obj-1224", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-345", 0 ], + "order" : 0, + "source" : [ "obj-1224", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1241", 0 ], + "order" : 1, + "source" : [ "obj-1225", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-345", 1 ], + "order" : 0, + "source" : [ "obj-1225", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-77", 0 ], + "source" : [ "obj-1227", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-351", 0 ], + "order" : 1, + "source" : [ "obj-1228", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-392", 1 ], + "order" : 0, + "source" : [ "obj-1228", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1224", 0 ], + "order" : 0, + "source" : [ "obj-1229", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-494", 1 ], + "order" : 1, + "source" : [ "obj-1229", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1139", 1 ], + "order" : 0, + "source" : [ "obj-123", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-39", 1 ], + "order" : 1, + "source" : [ "obj-123", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1229", 0 ], + "source" : [ "obj-1230", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-109", 0 ], + "source" : [ "obj-1232", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-83", 1 ], + "source" : [ "obj-124", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-83", 0 ], + "source" : [ "obj-1241", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1233", 0 ], + "order" : 0, + "source" : [ "obj-1243", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-124", 0 ], + "order" : 1, + "source" : [ "obj-1243", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1249", 1 ], + "source" : [ "obj-1247", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1249", 0 ], + "source" : [ "obj-1248", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1251", 0 ], + "source" : [ "obj-1249", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-30", 0 ], + "source" : [ "obj-125", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-417", 0 ], + "source" : [ "obj-125", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1248", 0 ], + "source" : [ "obj-1250", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1184", 0 ], + "order" : 0, + "source" : [ "obj-1251", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1185", 0 ], + "order" : 1, + "source" : [ "obj-1251", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-196", 0 ], + "source" : [ "obj-126", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-307", 0 ], + "source" : [ "obj-126", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1267", 0 ], + "source" : [ "obj-1265", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1264", 0 ], + "source" : [ "obj-1266", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 0 ], + "source" : [ "obj-1267", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 8 ], + "source" : [ "obj-1271", 7 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 7 ], + "source" : [ "obj-1271", 6 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 6 ], + "source" : [ "obj-1271", 5 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 5 ], + "source" : [ "obj-1271", 4 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 4 ], + "source" : [ "obj-1271", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 3 ], + "source" : [ "obj-1271", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 2 ], + "source" : [ "obj-1271", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 1 ], + "source" : [ "obj-1271", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-173", 0 ], + "order" : 0, + "source" : [ "obj-1273", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-60", 0 ], + "order" : 1, + "source" : [ "obj-1273", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1273", 0 ], + "source" : [ "obj-1274", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-60", 0 ], + "source" : [ "obj-1275", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-258", 0 ], + "source" : [ "obj-128", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-115", 0 ], + "source" : [ "obj-1281", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1289", 0 ], + "source" : [ "obj-1282", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-425", 0 ], + "source" : [ "obj-1284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1290", 0 ], + "source" : [ "obj-1289", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1274", 0 ], + "order" : 2, + "source" : [ "obj-1290", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1284", 0 ], + "order" : 0, + "source" : [ "obj-1290", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1287", 0 ], + "midpoints" : [ 607.5, 2119.705998329811337, 607.5, 2119.705998329811337 ], + "order" : 1, + "source" : [ "obj-1290", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1294", 0 ], + "source" : [ "obj-1290", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-425", 0 ], + "source" : [ "obj-1294", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-126", 0 ], + "source" : [ "obj-130", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-353", 0 ], + "order" : 1, + "source" : [ "obj-132", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-355", 0 ], + "order" : 2, + "source" : [ "obj-132", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-356", 0 ], + "order" : 0, + "source" : [ "obj-132", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-194", 0 ], + "source" : [ "obj-133", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-26", 0 ], + "source" : [ "obj-136", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-136", 1 ], + "source" : [ "obj-137", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-137", 0 ], + "source" : [ "obj-138", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-138", 0 ], + "source" : [ "obj-139", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1228", 0 ], + "source" : [ "obj-141", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1227", 0 ], + "source" : [ "obj-142", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-267", 0 ], + "source" : [ "obj-149", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-58", 0 ], + "source" : [ "obj-15", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-152", 0 ], + "source" : [ "obj-151", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-277", 0 ], + "source" : [ "obj-153", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-133", 0 ], + "source" : [ "obj-154", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-125", 0 ], + "source" : [ "obj-156", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-312", 0 ], + "source" : [ "obj-157", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-230", 0 ], + "source" : [ "obj-158", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-190", 0 ], + "source" : [ "obj-160", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-31", 0 ], + "source" : [ "obj-161", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-167", 0 ], + "source" : [ "obj-162", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-166", 0 ], + "source" : [ "obj-165", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-468", 0 ], + "source" : [ "obj-167", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-138", 0 ], + "source" : [ "obj-171", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-183", 0 ], + "source" : [ "obj-172", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1282", 0 ], + "source" : [ "obj-173", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-179", 0 ], + "source" : [ "obj-175", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-479", 0 ], + "order" : 0, + "source" : [ "obj-175", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-489", 0 ], + "order" : 1, + "source" : [ "obj-175", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1147", 0 ], + "order" : 0, + "source" : [ "obj-176", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1157", 0 ], + "order" : 1, + "source" : [ "obj-176", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1127", 0 ], + "source" : [ "obj-177", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-173", 0 ], + "source" : [ "obj-18", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1227", 0 ], + "order" : 1, + "source" : [ "obj-180", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-438", 0 ], + "order" : 0, + "source" : [ "obj-180", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-109", 0 ], + "source" : [ "obj-182", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-240", 0 ], + "order" : 0, + "source" : [ "obj-183", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-253", 0 ], + "order" : 1, + "source" : [ "obj-183", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-12", 1 ], + "order" : 0, + "source" : [ "obj-186", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-13", 0 ], + "order" : 1, + "source" : [ "obj-186", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-151", 0 ], + "order" : 2, + "source" : [ "obj-186", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-14", 0 ], + "source" : [ "obj-188", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-316", 0 ], + "source" : [ "obj-189", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-110", 0 ], + "source" : [ "obj-19", 20 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-119", 0 ], + "source" : [ "obj-19", 12 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-140", 0 ], + "source" : [ "obj-19", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-144", 0 ], + "source" : [ "obj-19", 4 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-146", 0 ], + "source" : [ "obj-19", 5 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-163", 0 ], + "source" : [ "obj-19", 21 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-20", 0 ], + "source" : [ "obj-19", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-201", 0 ], + "source" : [ "obj-19", 10 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-209", 0 ], + "source" : [ "obj-19", 17 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-21", 0 ], + "source" : [ "obj-19", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-259", 0 ], + "source" : [ "obj-19", 7 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-272", 0 ], + "source" : [ "obj-19", 13 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-304", 0 ], + "source" : [ "obj-19", 6 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-33", 0 ], + "source" : [ "obj-19", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-439", 0 ], + "source" : [ "obj-19", 11 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-45", 0 ], + "source" : [ "obj-19", 8 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-457", 0 ], + "source" : [ "obj-19", 16 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-476", 0 ], + "source" : [ "obj-19", 14 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-512", 0 ], + "source" : [ "obj-19", 18 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-513", 0 ], + "source" : [ "obj-19", 19 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-79", 0 ], + "source" : [ "obj-19", 9 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-99", 0 ], + "source" : [ "obj-19", 15 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-156", 0 ], + "source" : [ "obj-190", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-101", 0 ], + "order" : 1, + "source" : [ "obj-192", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-134", 1 ], + "order" : 0, + "source" : [ "obj-192", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-199", 0 ], + "source" : [ "obj-193", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-228", 0 ], + "source" : [ "obj-193", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-181", 0 ], + "source" : [ "obj-194", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-213", 1 ], + "source" : [ "obj-195", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-22", 0 ], + "source" : [ "obj-196", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-195", 1 ], + "source" : [ "obj-197", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-183", 0 ], + "source" : [ "obj-198", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-202", 0 ], + "source" : [ "obj-199", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-113", 2 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-261", 0 ], + "source" : [ "obj-203", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-213", 0 ], + "source" : [ "obj-204", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-238", 1 ], + "order" : 1, + "source" : [ "obj-204", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-240", 1 ], + "order" : 0, + "source" : [ "obj-204", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-436", 0 ], + "source" : [ "obj-204", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-19", 0 ], + "source" : [ "obj-205", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-214", 0 ], + "source" : [ "obj-210", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-302", 0 ], + "source" : [ "obj-212", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-86", 0 ], + "source" : [ "obj-213", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-768", 0 ], + "source" : [ "obj-214", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-783", 0 ], + "source" : [ "obj-215", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-215", 0 ], + "source" : [ "obj-216", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-193", 0 ], + "source" : [ "obj-218", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-566", 0 ], + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-567", 0 ], + "source" : [ "obj-22", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-976", 0 ], + "source" : [ "obj-220", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-224", 0 ], + "source" : [ "obj-221", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-226", 0 ], + "source" : [ "obj-222", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-222", 0 ], + "source" : [ "obj-224", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1168", 1 ], + "source" : [ "obj-226", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-193", 0 ], + "source" : [ "obj-228", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-245", 0 ], + "source" : [ "obj-229", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-232", 0 ], + "source" : [ "obj-230", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-229", 0 ], + "source" : [ "obj-233", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-236", 0 ], + "source" : [ "obj-234", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-101", 0 ], + "source" : [ "obj-235", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-783", 0 ], + "source" : [ "obj-236", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-255", 0 ], + "source" : [ "obj-238", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-233", 0 ], + "source" : [ "obj-239", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-337", 0 ], + "source" : [ "obj-239", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-458", 1 ], + "source" : [ "obj-239", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1168", 0 ], + "source" : [ "obj-24", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-195", 0 ], + "source" : [ "obj-240", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-243", 0 ], + "source" : [ "obj-241", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-250", 0 ], + "source" : [ "obj-242", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-242", 0 ], + "source" : [ "obj-243", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-245", 1 ], + "source" : [ "obj-243", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-284", 0 ], + "source" : [ "obj-244", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-252", 0 ], + "source" : [ "obj-245", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-284", 1 ], + "source" : [ "obj-247", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-251", 0 ], + "source" : [ "obj-249", 6 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-326", 0 ], + "source" : [ "obj-249", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-133", 1 ], + "source" : [ "obj-25", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-229", 0 ], + "source" : [ "obj-250", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-249", 0 ], + "midpoints" : [ 2370.852931976318359, 693.0, 2418.0, 693.0, 2418.0, 732.0, 2376.0, 732.0, 2376.0, 828.0, 2410.852931976318359, 828.0 ], + "source" : [ "obj-250", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-249", 0 ], + "source" : [ "obj-252", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-509", 1 ], + "source" : [ "obj-252", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-238", 0 ], + "source" : [ "obj-253", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-412", 0 ], + "source" : [ "obj-254", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-213", 1 ], + "source" : [ "obj-255", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-239", 0 ], + "source" : [ "obj-256", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-200", 0 ], + "order" : 1, + "source" : [ "obj-258", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-206", 0 ], + "order" : 0, + "source" : [ "obj-258", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-108", 0 ], + "source" : [ "obj-260", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-266", 0 ], + "source" : [ "obj-263", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-265", 0 ], + "source" : [ "obj-264", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1220", 0 ], + "source" : [ "obj-265", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1221", 0 ], + "source" : [ "obj-266", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-271", 0 ], + "source" : [ "obj-269", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-162", 0 ], + "source" : [ "obj-27", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-352", 0 ], + "order" : 0, + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-382", 0 ], + "order" : 2, + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-391", 0 ], + "order" : 1, + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-289", 0 ], + "source" : [ "obj-271", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-313", 0 ], + "source" : [ "obj-273", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "source" : [ "obj-274", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-40", 0 ], + "source" : [ "obj-275", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1266", 9 ], + "source" : [ "obj-277", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-19", 0 ], + "source" : [ "obj-277", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-285", 0 ], + "source" : [ "obj-278", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-149", 0 ], + "source" : [ "obj-279", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-255", 1 ], + "source" : [ "obj-28", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-19", 0 ], + "source" : [ "obj-280", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-109", 2 ], + "source" : [ "obj-282", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-63", 0 ], + "source" : [ "obj-283", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-386", 1 ], + "order" : 1, + "source" : [ "obj-284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-395", 1 ], + "midpoints" : [ 5489.5, 3372.0, 5550.0, 3372.0, 5550.0, 3471.0, 5973.0, 3471.0, 5973.0, 3789.0, 6170.50018322467804, 3789.0 ], + "order" : 0, + "source" : [ "obj-284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-563", 0 ], + "order" : 3, + "source" : [ "obj-284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-565", 0 ], + "order" : 2, + "source" : [ "obj-284", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-61", 0 ], + "source" : [ "obj-285", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-73", 0 ], + "source" : [ "obj-286", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-188", 0 ], + "order" : 0, + "source" : [ "obj-287", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-49", 0 ], + "order" : 1, + "source" : [ "obj-287", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-287", 0 ], + "source" : [ "obj-289", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-286", 0 ], + "source" : [ "obj-291", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-321", 0 ], + "source" : [ "obj-292", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-324", 0 ], + "source" : [ "obj-295", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-300", 0 ], + "order" : 1, + "source" : [ "obj-299", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-445", 0 ], + "order" : 0, + "source" : [ "obj-299", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1051", 1 ], + "source" : [ "obj-3", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1051", 0 ], + "source" : [ "obj-3", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-497", 0 ], + "source" : [ "obj-30", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-301", 0 ], + "source" : [ "obj-300", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-261", 0 ], + "source" : [ "obj-302", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1124", 0 ], + "source" : [ "obj-303", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-484", 0 ], + "source" : [ "obj-305", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-309", 1 ], + "source" : [ "obj-307", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-34", 0 ], + "source" : [ "obj-308", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-204", 0 ], + "source" : [ "obj-31", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1140", 0 ], + "source" : [ "obj-311", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-428", 0 ], + "source" : [ "obj-312", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-334", 0 ], + "source" : [ "obj-313", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-449", 0 ], + "source" : [ "obj-316", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-768", 0 ], + "source" : [ "obj-317", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-530", 0 ], + "source" : [ "obj-318", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-158", 0 ], + "source" : [ "obj-32", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-325", 0 ], + "source" : [ "obj-320", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-318", 0 ], + "source" : [ "obj-321", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-286", 0 ], + "source" : [ "obj-323", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-292", 1 ], + "source" : [ "obj-324", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-323", 0 ], + "source" : [ "obj-324", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-42", 1 ], + "source" : [ "obj-324", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-313", 0 ], + "source" : [ "obj-325", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-388", 0 ], + "source" : [ "obj-326", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-350", 1 ], + "source" : [ "obj-327", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-359", 0 ], + "source" : [ "obj-330", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-419", 0 ], + "source" : [ "obj-330", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1065", 1 ], + "source" : [ "obj-333", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-328", 0 ], + "source" : [ "obj-334", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-415", 0 ], + "source" : [ "obj-336", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-561", 0 ], + "source" : [ "obj-336", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-241", 0 ], + "source" : [ "obj-337", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-343", 0 ], + "source" : [ "obj-338", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-333", 1 ], + "source" : [ "obj-339", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-333", 0 ], + "source" : [ "obj-339", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-67", 0 ], + "source" : [ "obj-344", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-336", 0 ], + "source" : [ "obj-346", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-352", 1 ], + "source" : [ "obj-350", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-383", 1 ], + "source" : [ "obj-351", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-365", 0 ], + "order" : 0, + "source" : [ "obj-352", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-393", 0 ], + "order" : 1, + "source" : [ "obj-352", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-386", 0 ], + "order" : 1, + "source" : [ "obj-357", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-450", 0 ], + "order" : 0, + "source" : [ "obj-357", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-338", 0 ], + "source" : [ "obj-358", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-451", 0 ], + "source" : [ "obj-359", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-366", 0 ], + "source" : [ "obj-361", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-488", 0 ], + "source" : [ "obj-363", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-109", 0 ], + "source" : [ "obj-365", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-361", 0 ], + "source" : [ "obj-365", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-287", 0 ], + "source" : [ "obj-367", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-398", 0 ], + "source" : [ "obj-369", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-244", 0 ], + "source" : [ "obj-37", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-372", 1 ], + "source" : [ "obj-371", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-372", 0 ], + "source" : [ "obj-371", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1062", 1 ], + "source" : [ "obj-372", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-485", 0 ], + "source" : [ "obj-379", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-39", 0 ], + "source" : [ "obj-38", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-383", 0 ], + "source" : [ "obj-382", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1224", 0 ], + "source" : [ "obj-383", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-464", 0 ], + "order" : 0, + "source" : [ "obj-386", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-517", 0 ], + "order" : 1, + "source" : [ "obj-386", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-388", 1 ], + "source" : [ "obj-387", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-463", 0 ], + "source" : [ "obj-388", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-308", 0 ], + "source" : [ "obj-39", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-372", 0 ], + "source" : [ "obj-390", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-392", 0 ], + "source" : [ "obj-391", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-393", 1 ], + "order" : 1, + "source" : [ "obj-392", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-413", 0 ], + "order" : 0, + "source" : [ "obj-392", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1224", 0 ], + "order" : 1, + "source" : [ "obj-393", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-414", 0 ], + "order" : 0, + "source" : [ "obj-393", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-561", 1 ], + "source" : [ "obj-395", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-399", 0 ], + "source" : [ "obj-398", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-423", 0 ], + "source" : [ "obj-398", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-7", 0 ], + "source" : [ "obj-4", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1230", 0 ], + "order" : 0, + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1243", 0 ], + "order" : 1, + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-55", 0 ], + "order" : 2, + "source" : [ "obj-40", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1125", 0 ], + "source" : [ "obj-403", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-196", 1 ], + "order" : 1, + "source" : [ "obj-404", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-307", 1 ], + "order" : 0, + "source" : [ "obj-404", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-192", 0 ], + "source" : [ "obj-409", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-314", 0 ], + "source" : [ "obj-409", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-410", 0 ], + "source" : [ "obj-409", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-543", 0 ], + "source" : [ "obj-409", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-247", 0 ], + "source" : [ "obj-41", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-379", 0 ], + "source" : [ "obj-415", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-416", 0 ], + "source" : [ "obj-418", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-451", 0 ], + "source" : [ "obj-419", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-346", 0 ], + "source" : [ "obj-42", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-479", 1 ], + "order" : 0, + "source" : [ "obj-423", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-489", 1 ], + "order" : 1, + "source" : [ "obj-423", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-409", 0 ], + "source" : [ "obj-424", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-177", 0 ], + "source" : [ "obj-426", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-97", 0 ], + "source" : [ "obj-428", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-154", 0 ], + "source" : [ "obj-43", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-435", 0 ], + "source" : [ "obj-434", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-424", 0 ], + "source" : [ "obj-435", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-156", 2 ], + "source" : [ "obj-436", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-321", 1 ], + "source" : [ "obj-437", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-440", 0 ], + "source" : [ "obj-439", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-175", 0 ], + "source" : [ "obj-443", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-443", 0 ], + "source" : [ "obj-447", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-330", 0 ], + "source" : [ "obj-449", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-395", 0 ], + "source" : [ "obj-450", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-432", 0 ], + "source" : [ "obj-458", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-81", 0 ], + "source" : [ "obj-46", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-61", 0 ], + "source" : [ "obj-460", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-19", 0 ], + "source" : [ "obj-461", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-458", 0 ], + "source" : [ "obj-463", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-509", 0 ], + "source" : [ "obj-463", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-36", 0 ], + "source" : [ "obj-464", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-369", 0 ], + "source" : [ "obj-468", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-262", 0 ], + "order" : 1, + "source" : [ "obj-47", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-446", 0 ], + "order" : 0, + "source" : [ "obj-47", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-357", 0 ], + "source" : [ "obj-471", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "source" : [ "obj-475", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-279", 0 ], + "source" : [ "obj-478", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-424", 0 ], + "source" : [ "obj-479", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-490", 0 ], + "source" : [ "obj-479", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-118", 0 ], + "source" : [ "obj-48", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-437", 0 ], + "source" : [ "obj-484", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-437", 1 ], + "source" : [ "obj-485", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-437", 0 ], + "source" : [ "obj-485", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-518", 0 ], + "source" : [ "obj-488", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-474", 0 ], + "source" : [ "obj-489", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-291", 0 ], + "source" : [ "obj-49", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-178", 0 ], + "source" : [ "obj-492", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-27", 0 ], + "source" : [ "obj-492", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-213", 0 ], + "source" : [ "obj-497", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-27", 0 ], + "source" : [ "obj-497", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-8", 0 ], + "source" : [ "obj-5", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-113", 0 ], + "source" : [ "obj-50", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-246", 0 ], + "source" : [ "obj-509", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-433", 0 ], + "order" : 0, + "source" : [ "obj-51", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-68", 0 ], + "order" : 1, + "source" : [ "obj-51", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-49", 0 ], + "source" : [ "obj-517", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-539", 0 ], + "source" : [ "obj-518", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-54", 0 ], + "source" : [ "obj-52", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-527", 0 ], + "order" : 1, + "source" : [ "obj-524", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-528", 0 ], + "order" : 0, + "source" : [ "obj-524", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-37", 0 ], + "order" : 1, + "source" : [ "obj-527", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-41", 0 ], + "order" : 0, + "source" : [ "obj-527", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-37", 0 ], + "source" : [ "obj-53", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-319", 0 ], + "source" : [ "obj-530", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-424", 0 ], + "source" : [ "obj-537", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-537", 0 ], + "source" : [ "obj-538", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-98", 0 ], + "source" : [ "obj-54", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-188", 1 ], + "source" : [ "obj-544", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-106", 0 ], + "source" : [ "obj-55", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-569", 0 ], + "source" : [ "obj-554", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-196", 1 ], + "source" : [ "obj-555", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-768", 0 ], + "source" : [ "obj-559", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-57", 0 ], + "source" : [ "obj-56", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-464", 0 ], + "source" : [ "obj-561", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-559", 0 ], + "source" : [ "obj-562", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-554", 0 ], + "source" : [ "obj-563", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-554", 0 ], + "source" : [ "obj-565", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-53", 0 ], + "source" : [ "obj-566", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-563", 1 ], + "source" : [ "obj-566", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-565", 1 ], + "source" : [ "obj-567", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-95", 0 ], + "source" : [ "obj-567", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-59", 0 ], + "source" : [ "obj-58", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-5", 0 ], + "source" : [ "obj-6", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-16", 0 ], + "source" : [ "obj-60", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-42", 0 ], + "order" : 1, + "source" : [ "obj-61", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-46", 0 ], + "order" : 0, + "source" : [ "obj-61", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-71", 0 ], + "order" : 2, + "source" : [ "obj-61", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-55", 0 ], + "source" : [ "obj-63", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-70", 0 ], + "source" : [ "obj-66", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-342", 1 ], + "source" : [ "obj-67", 6 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-118", 0 ], + "source" : [ "obj-68", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-161", 0 ], + "order" : 1, + "source" : [ "obj-69", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-315", 0 ], + "order" : 0, + "source" : [ "obj-69", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-129", 0 ], + "source" : [ "obj-70", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-295", 0 ], + "source" : [ "obj-71", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1140", 0 ], + "source" : [ "obj-72", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-292", 0 ], + "source" : [ "obj-73", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-74", 0 ], + "source" : [ "obj-73", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-71", 1 ], + "source" : [ "obj-74", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-89", 0 ], + "source" : [ "obj-76", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-421", 0 ], + "order" : 1, + "source" : [ "obj-767", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-769", 0 ], + "order" : 0, + "source" : [ "obj-767", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-768", 0 ], + "source" : [ "obj-769", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1225", 0 ], + "order" : 1, + "source" : [ "obj-77", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-182", 0 ], + "order" : 0, + "source" : [ "obj-77", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-420", 0 ], + "order" : 0, + "source" : [ "obj-780", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-784", 0 ], + "order" : 1, + "source" : [ "obj-780", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-164", 0 ], + "order" : 0, + "source" : [ "obj-783", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-165", 0 ], + "order" : 1, + "source" : [ "obj-783", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-111", 0 ], + "order" : 0, + "source" : [ "obj-784", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-783", 0 ], + "order" : 1, + "source" : [ "obj-784", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-59", 0 ], + "source" : [ "obj-80", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-176", 0 ], + "source" : [ "obj-82", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-109", 0 ], + "source" : [ "obj-83", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-492", 0 ], + "source" : [ "obj-86", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1165", 0 ], + "source" : [ "obj-88", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1125", 0 ], + "order" : 1, + "source" : [ "obj-89", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-35", 0 ], + "order" : 0, + "source" : [ "obj-89", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-186", 0 ], + "source" : [ "obj-9", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-394", 0 ], + "order" : 0, + "source" : [ "obj-91", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-98", 1 ], + "order" : 1, + "source" : [ "obj-91", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-41", 0 ], + "source" : [ "obj-95", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-100", 0 ], + "source" : [ "obj-96", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-430", 0 ], + "source" : [ "obj-97", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-431", 0 ], + "source" : [ "obj-97", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-977", 0 ], + "source" : [ "obj-976", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-89", 1 ], + "source" : [ "obj-98", 0 ] + } + + } + ], + "originid" : "pat-261", + "boxgroups" : [ { + "boxes" : [ "obj-349", "obj-428" ] + } +, { + "boxes" : [ "obj-316", "obj-329" ] + } +, { + "boxes" : [ "obj-310", "obj-270" ] + } + ], + "bgcolor" : [ 0.356862745098039, 0.356862745098039, 0.356862745098039, 1.0 ], + "editing_bgcolor" : [ 0.356862745098039, 0.356862745098039, 0.356862745098039, 1.0 ] + } + +} diff --git a/unloop/max/unloop.maxpat b/unloop/max/unloop.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..226ba4455076affa03ef28ee107cabc6c2cad543 --- /dev/null +++ b/unloop/max/unloop.maxpat @@ -0,0 +1,130 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 84.0, 131.0, 1000.0, 780.0 ], + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "bgmode" : 0, + "border" : 0, + "clickthrough" : 0, + "enablehscroll" : 0, + "enablevscroll" : 0, + "id" : "obj-2", + "lockeddragscroll" : 0, + "lockedsize" : 0, + "maxclass" : "bpatcher", + "name" : "unloop-bpatcher.maxpat", + "numinlets" : 2, + "numoutlets" : 2, + "offset" : [ 0.0, 0.0 ], + "outlettype" : [ "signal", "" ], + "patching_rect" : [ 100.0, 68.0, 307.0, 469.0 ], + "viewvisibility" : 1 + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 0, + "patching_rect" : [ 143.0, 616.0, 55.0, 22.0 ], + "text" : "dac~ 1 2" + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-1", 1 ], + "order" : 0, + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "order" : 1, + "source" : [ "obj-2", 0 ] + } + + } + ], + "originid" : "pat-142", + "parameters" : { + "obj-2::obj-1124" : [ "morph", "dry/wet", 0 ], + "obj-2::obj-1125" : [ "level[8]", "level", 0 ], + "obj-2::obj-1128" : [ "gain[4]", "gain", 0 ], + "obj-2::obj-1140" : [ "overdub", "overdub", 0 ], + "obj-2::obj-117" : [ "live.drop", "live.drop", 0 ], + "obj-2::obj-1230" : [ "speed[2]", "speed+", 0 ], + "obj-2::obj-171" : [ "toggle[2]", "toggle[30]", 0 ], + "obj-2::obj-295" : [ "button[1]", "button[1]", 0 ], + "obj-2::obj-316" : [ "toggle[3]", "toggle[3]", 0 ], + "obj-2::obj-424::obj-12" : [ "number[8]", "number[2]", 0 ], + "obj-2::obj-424::obj-13" : [ "number[9]", "number[3]", 0 ], + "obj-2::obj-424::obj-15" : [ "number[2]", "number[2]", 0 ], + "obj-2::obj-424::obj-19" : [ "number[3]", "number[3]", 0 ], + "obj-2::obj-424::obj-20" : [ "number", "number", 0 ], + "obj-2::obj-424::obj-23" : [ "number[4]", "number[3]", 0 ], + "obj-2::obj-424::obj-26" : [ "number[5]", "number[3]", 0 ], + "obj-2::obj-424::obj-28" : [ "number[6]", "number[2]", 0 ], + "obj-2::obj-424::obj-30" : [ "number[7]", "number[2]", 0 ], + "obj-2::obj-424::obj-347" : [ "periodic", "periodic", 0 ], + "obj-2::obj-424::obj-349" : [ "drop", "drop", 0 ], + "obj-2::obj-424::obj-8" : [ "toggle", "toggle", 0 ], + "obj-2::obj-54" : [ "lpf", "lpf", 0 ], + "obj-2::obj-55" : [ "tapelength", "length", 0 ], + "obj-2::obj-76" : [ "hpf", "hpf", 0 ], + "obj-2::obj-91::obj-156" : [ "live.gain~[26]", "live.gain~", 0 ], + "obj-2::obj-91::obj-162" : [ "live.gain~[25]", "live.gain~", 0 ], + "parameterbanks" : { + "0" : { + "index" : 0, + "name" : "", + "parameters" : [ "-", "-", "-", "-", "-", "-", "-", "-" ] + } + + } +, + "inherited_shortname" : 1 + } +, + "dependency_cache" : [ { + "name" : "dry-wet.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } +, { + "name" : "unloop-bpatcher.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } +, { + "name" : "vampnet-ui.maxpat", + "bootpath" : "~/projects/research/unloop-2025/vampnet/unloop/max", + "patcherrelativepath" : ".", + "type" : "JSON", + "implicit" : 1 + } + ], + "autosave" : 0 + } + +} diff --git a/unloop/max/vampnet-ui.maxpat b/unloop/max/vampnet-ui.maxpat new file mode 100644 index 0000000000000000000000000000000000000000..f4b5f7b037e1f20bfa7b9c973d80e868f7c1f399 --- /dev/null +++ b/unloop/max/vampnet-ui.maxpat @@ -0,0 +1,1314 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 9, + "minor" : 0, + "revision" : 5, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 34.0, 87.0, 814.0, 779.0 ], + "openinpresentation" : 1, + "gridsize" : [ 15.0, 15.0 ], + "boxes" : [ { + "box" : { + "fontsize" : 8.0, + "id" : "obj-13", + "maxclass" : "number", + "maximum" : 64, + "minimum" : 1, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1310.734448432922363, 511.55017364025116, 42.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 89.5, 135.0, 42.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 1 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[24]", + "parameter_mmax" : 64.0, + "parameter_mmin" : 1.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[3]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[8]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-14", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1310.734448432922363, 472.547349274158478, 55.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 7.120483428239822, 135.939657211303711, 70.0, 15.0 ], + "text" : "feedback steps" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-4", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1257.333370804786682, 468.047349274158478, 38.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 6.770833075046539, 114.960636019706726, 69.107615292072296, 15.0 ], + "text" : "beat mask ms" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "format" : 6, + "id" : "obj-12", + "maxclass" : "flonum", + "maximum" : 400.0, + "minimum" : 0.0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1258.000037491321564, 506.71401709318161, 40.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 90.5, 113.960636019706726, 40.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[26]", + "parameter_mmax" : 400.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[2]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[7]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "format" : 6, + "id" : "obj-30", + "maxclass" : "flonum", + "maximum" : 1.0, + "minimum" : 0.0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1207.467486619949341, 506.74109160900116, 40.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.601398587226868, 114.829166448116297, 41.258741676807404, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[20]", + "parameter_mmax" : 1.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[2]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[6]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-29", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1209.467486619949341, 468.047349274158478, 38.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 118.229166448116302, 54.0, 15.0 ], + "text" : "top p" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-27", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1165.088787257671356, 468.279552161693573, 38.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 135.229166448116302, 54.0, 15.0 ], + "text" : "temp" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "format" : 6, + "id" : "obj-28", + "maxclass" : "flonum", + "maximum" : 5.0, + "minimum" : 0.0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1165.680503249168396, 506.74109160900116, 40.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.601398587226868, 134.229166448116302, 41.258741676807404, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 1.0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[22]", + "parameter_mmax" : 5.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[2]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[5]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-26", + "maxclass" : "number", + "maximum" : 64, + "minimum" : 8, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1095.275648653507233, 507.086641073226929, 42.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.0, 95.429166448116291, 42.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 32 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[27]", + "parameter_mmax" : 64.0, + "parameter_mmin" : 8.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[3]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[4]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-25", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1107.086672902107239, 463.779552161693573, 55.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 96.229166448116302, 70.0, 15.0 ], + "text" : "num steps" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-23", + "maxclass" : "number", + "maximum" : 1024, + "minimum" : 0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 1037.79533064365387, 507.086641073226929, 42.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.0, 76.0291664481163, 42.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 0 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[23]", + "parameter_mmax" : 1024.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[3]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[3]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-24", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 1037.007929027080536, 463.779552161693573, 55.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 77.229166448116302, 70.0, 15.0 ], + "text" : "onset mask width" + } + + } +, { + "box" : { + "id" : "obj-22", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 779.0, 402.0, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-21", + "linecount" : 3, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 972.0, 425.0, 45.0, 33.0 ], + "presentation" : 1, + "presentation_rect" : [ 6.770833075046539, 94.000002801418304, 92.0, 15.0 ], + "text" : "codebook level mask" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-20", + "maxclass" : "number", + "maximum" : 14, + "minimum" : 1, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 973.0, 507.0, 45.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 85.5, 93.000002801418304, 45.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 4 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[25]", + "parameter_mmax" : 14.0, + "parameter_mmin" : 1.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number", + "parameter_type" : 0 + } + + } +, + "varname" : "number" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-19", + "maxclass" : "number", + "maximum" : 1024, + "minimum" : 0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 906.0, 507.0, 42.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.0, 56.629166448116301, 42.0, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 64 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[19]", + "parameter_mmax" : 1024.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[3]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[2]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-17", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 905.0, 464.0, 55.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 58.229166448116302, 70.0, 15.0 ], + "text" : "typical min tok" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-16", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 842.0, 464.0, 38.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 38.229166448116302, 54.0, 15.0 ], + "text" : "typical mass" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "format" : 6, + "id" : "obj-15", + "maxclass" : "flonum", + "maximum" : 1.0, + "minimum" : 0.0, + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 1, + "patching_rect" : [ 843.0, 502.526752233505249, 40.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.251748234033585, 37.229166448116302, 41.608392030000687, 17.0 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_initial" : [ 0.15 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "number[21]", + "parameter_mmax" : 1.0, + "parameter_modmode" : 3, + "parameter_shortname" : "number[2]", + "parameter_type" : 0 + } + + } +, + "varname" : "number[1]" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-9", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 782.0, 463.965681314468384, 38.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 149.0, 19.229166448116302, 57.0, 15.0 ], + "text" : "typical filter" + } + + } +, { + "box" : { + "id" : "obj-8", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 1, + "patching_rect" : [ 787.0, 501.526752233505249, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 224.251748234033585, 18.729166209697723, 16.000000476837158, 16.000000476837158 ], + "saved_attribute_attributes" : { + "valueof" : { + "parameter_enum" : [ "off", "on" ], + "parameter_initial" : [ 1 ], + "parameter_initial_enable" : 1, + "parameter_longname" : "toggle[7]", + "parameter_mmax" : 1, + "parameter_modmode" : 0, + "parameter_shortname" : "toggle", + "parameter_type" : 2 + } + + } +, + "varname" : "toggle" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "patching_rect" : [ 599.350643634796143, 319.48051643371582, 33.0, 22.0 ], + "text" : "== 0" + } + + } +, { + "box" : { + "id" : "obj-11", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 377.0, 415.740486621856689, 70.0, 22.0 ], + "text" : "loadmess 3" + } + + } +, { + "box" : { + "id" : "obj-10", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 480.931334972381592, 415.740486621856689, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "id" : "obj-7", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 326.666805624961853, 88.0, 335.0, 22.0 ], + "text" : "print #0-VAMPNET_UI_COMMAND_NOT_UNDERSTOOD" + } + + } +, { + "box" : { + "id" : "obj-6", + "maxclass" : "newobj", + "numinlets" : 6, + "numoutlets" : 6, + "outlettype" : [ "", "", "", "", "", "" ], + "patching_rect" : [ 56.666805624961853, 56.64739465713501, 289.0, 22.0 ], + "text" : "route queryid audiofile looplength_ms model periodic" + } + + } +, { + "box" : { + "id" : "obj-5", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 248.091620206832886, 583.206147193908691, 396.183233499526978, 20.0 ], + "text" : "query id --- audiofile ---- model_choice --- periodic --- drop --- seed " + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontsize" : 8.0, + "id" : "obj-349", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 489.313010931015015, 469.465681314468384, 40.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 107.809941202402115, 8.729166448116302, 30.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_initial" : [ 0.0 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "drop[2]", + "parameter_mmax" : 1.0, + "parameter_modmode" : 0, + "parameter_shortname" : "drop", + "parameter_type" : 0, + "parameter_unitstyle" : 1 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "drop" + } + + } +, { + "box" : { + "fontname" : "Andale Mono", + "fontsize" : 8.0, + "id" : "obj-348", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 124.0, 342.465681314468384, 74.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 6.770833075046539, 5.729166448116302, 51.0, 15.0 ], + "text" : "model" + } + + } +, { + "box" : { + "activedialcolor" : [ 0.6, 0.6, 0.6, 1.0 ], + "appearance" : 1, + "fontsize" : 8.0, + "id" : "obj-347", + "maxclass" : "live.dial", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "float" ], + "parameter_enable" : 1, + "patching_rect" : [ 377.0, 462.465681314468384, 55.0, 36.0 ], + "presentation" : 1, + "presentation_rect" : [ 61.770833075046539, 8.729166448116302, 39.0, 36.0 ], + "saved_attribute_attributes" : { + "activedialcolor" : { + "expression" : "" + } +, + "textcolor" : { + "expression" : "" + } +, + "valueof" : { + "parameter_enum" : [ "0", "1", "3", "5", "7", "13", "21", "32", "64" ], + "parameter_initial" : [ 3 ], + "parameter_initial_enable" : 1, + "parameter_linknames" : 1, + "parameter_longname" : "periodic[2]", + "parameter_mmax" : 128.0, + "parameter_modmode" : 0, + "parameter_shortname" : "periodic", + "parameter_type" : 1, + "parameter_unitstyle" : 9 + } + + } +, + "textcolor" : [ 0.847058823529412, 0.819607843137255, 0.819607843137255, 1.0 ], + "varname" : "periodic" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-346", + "items" : [ "default", ",", "supermetroid", ",", "percussion", ",", "machines", ",", "choir", ",", "n64", ",", "opera", ",", "orchestral", ",", "sample-instrument", ",", "xeno-canto", ",", "march-31", ",", "saxophone", ",", "sax-new", ",", "sax-sep", ",", "lazaro-ros", ",", "lazaro-ros-sep", ",", "cat10" ], + "maxclass" : "umenu", + "numinlets" : 1, + "numoutlets" : 3, + "outlettype" : [ "int", "", "" ], + "parameter_enable" : 0, + "patching_rect" : [ 169.0, 364.465681314468384, 100.0, 17.0 ], + "presentation" : 1, + "presentation_rect" : [ 6.88541653752327, 18.229166448116302, 50.770833075046539, 17.0 ] + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 130.057793855667114, 602.0, 89.0, 22.0 ], + "text" : "prepend to-text" + } + + } +, { + "box" : { + "id" : "obj-1", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 602.0, 75.0, 22.0 ], + "text" : "prepend osc" + } + + } +, { + "box" : { + "id" : "obj-367", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "int", "bang" ], + "patching_rect" : [ 56.666805624961853, 137.397974371910095, 29.5, 22.0 ], + "text" : "t i b" + } + + } +, { + "box" : { + "id" : "obj-366", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 599.350643634796143, 252.597400188446045, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-365", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 626.62337064743042, 285.714282989501953, 61.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 103.770833075046539, 50.45833146572113, 26.729166924953461, 15.0 ], + "text" : "lock" + } + + } +, { + "box" : { + "id" : "obj-362", + "maxclass" : "toggle", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "int" ], + "parameter_enable" : 0, + "patching_rect" : [ 599.350643634796143, 283.116880416870117, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 122.310760617256165, 50.59761106967926, 14.61988240480423, 14.61988240480423 ] + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-262", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 169.0, 331.465681314468384, 70.0, 22.0 ], + "text" : "loadmess 0" + } + + } +, { + "box" : { + "id" : "obj-43", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "" ], + "patching_rect" : [ 208.0, 398.465681314468384, 31.0, 22.0 ], + "text" : "t s s" + } + + } +, { + "box" : { + "id" : "obj-274", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 601.526759147644043, 376.335903882980347, 32.0, 22.0 ], + "text" : "gate" + } + + } +, { + "box" : { + "id" : "obj-273", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 601.526759147644043, 443.511481046676636, 86.0, 22.0 ], + "text" : "random 32768" + } + + } +, { + "box" : { + "id" : "obj-272", + "maxclass" : "button", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 601.526759147644043, 413.740486621856689, 24.0, 24.0 ], + "presentation" : 1, + "presentation_rect" : [ 29.0, 50.380436055362225, 15.103658214211464, 15.103658214211464 ] + } + + } +, { + "box" : { + "fontsize" : 7.0, + "id" : "obj-270", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 598.473323822021484, 502.290111064910889, 44.0, 16.0 ], + "presentation" : 1, + "presentation_rect" : [ 47.770833075046539, 49.932265162467957, 51.0, 16.0 ] + } + + } +, { + "box" : { + "color" : [ 0.3, 0.9, 0.1, 1.0 ], + "id" : "obj-200", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 672.51913046836853, 473.282475471496582, 70.0, 22.0 ], + "text" : "loadmess 9" + } + + } +, { + "box" : { + "fontsize" : 8.0, + "id" : "obj-206", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 659.542030334472656, 501.526752233505249, 39.0, 15.0 ], + "presentation" : 1, + "presentation_rect" : [ 6.320590555667877, 50.432265162467957, 32.0, 15.0 ], + "text" : "seed" + } + + } +, { + "box" : { + "color" : [ 0.2, 0.0, 0.8, 1.0 ], + "id" : "obj-258", + "maxclass" : "newobj", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 598.473323822021484, 473.282475471496582, 73.0, 22.0 ], + "text" : "r #0-seed" + } + + } +, { + "box" : { + "id" : "obj-313", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 221.0, 431.465681314468384, 75.0, 22.0 ], + "text" : "prepend text" + } + + } +, { + "box" : { + "id" : "obj-168", + "maxclass" : "newobj", + "numinlets" : 18, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 50.0, 545.0, 453.0, 22.0 ], + "text" : "pack 0 vampnet example.wav default 7 0.1 12345 10000. 1 0.15 64 4 0 36 1. 0. 0. 1" + } + + } +, { + "box" : { + "id" : "obj-157", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ -8.670519590377808, 101.0, 62.0, 20.0 ], + "text" : "query id" + } + + } +, { + "box" : { + "id" : "obj-133", + "maxclass" : "number", + "numinlets" : 1, + "numoutlets" : 2, + "outlettype" : [ "", "bang" ], + "parameter_enable" : 0, + "patching_rect" : [ 56.666805624961853, 100.0, 50.0, 22.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-378", + "index" : 1, + "maxclass" : "inlet", + "numinlets" : 0, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 56.666805624961853, 5.0, 30.0, 30.0 ] + } + + } +, { + "box" : { + "comment" : "", + "id" : "obj-380", + "index" : 1, + "maxclass" : "outlet", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 50.0, 674.0, 30.0, 30.0 ] + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-380", 0 ], + "source" : [ "obj-1", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-349", 0 ], + "source" : [ "obj-10", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-347", 0 ], + "source" : [ "obj-11", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 16 ], + "source" : [ "obj-12", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 17 ], + "source" : [ "obj-13", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-367", 0 ], + "source" : [ "obj-133", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 9 ], + "source" : [ "obj-15", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-1", 0 ], + "source" : [ "obj-168", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 10 ], + "source" : [ "obj-19", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-274", 0 ], + "source" : [ "obj-2", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 11 ], + "source" : [ "obj-20", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "source" : [ "obj-200", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-12", 0 ], + "order" : 1, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-13", 0 ], + "order" : 0, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-15", 0 ], + "order" : 8, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-19", 0 ], + "order" : 7, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-20", 0 ], + "order" : 6, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-23", 0 ], + "order" : 5, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-26", 0 ], + "order" : 4, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-28", 0 ], + "order" : 3, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-30", 0 ], + "order" : 2, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-8", 0 ], + "order" : 9, + "source" : [ "obj-22", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 12 ], + "source" : [ "obj-23", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "source" : [ "obj-258", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 13 ], + "source" : [ "obj-26", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-346", 0 ], + "source" : [ "obj-262", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 6 ], + "source" : [ "obj-270", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-273", 0 ], + "source" : [ "obj-272", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-270", 0 ], + "source" : [ "obj-273", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-272", 0 ], + "source" : [ "obj-274", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 14 ], + "source" : [ "obj-28", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-380", 0 ], + "source" : [ "obj-3", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 15 ], + "source" : [ "obj-30", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "source" : [ "obj-313", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-43", 0 ], + "source" : [ "obj-346", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 4 ], + "source" : [ "obj-347", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 5 ], + "source" : [ "obj-349", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-362", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-362", 0 ], + "source" : [ "obj-366", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 0 ], + "source" : [ "obj-367", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-274", 1 ], + "source" : [ "obj-367", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-6", 0 ], + "source" : [ "obj-378", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 3 ], + "source" : [ "obj-43", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-313", 0 ], + "source" : [ "obj-43", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-133", 0 ], + "source" : [ "obj-6", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 7 ], + "source" : [ "obj-6", 2 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 2 ], + "source" : [ "obj-6", 1 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-346", 0 ], + "source" : [ "obj-6", 3 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-347", 0 ], + "source" : [ "obj-6", 4 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-7", 0 ], + "source" : [ "obj-6", 5 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-168", 8 ], + "source" : [ "obj-8", 0 ] + } + + } + ], + "originid" : "pat-136" + } + +} diff --git a/unloop/requirements.txt b/unloop/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..d31bff8cf638a59ca68dc68904842ca4990c81c8 --- /dev/null +++ b/unloop/requirements.txt @@ -0,0 +1,5 @@ +python-osc +descript-audiotools +tqdm +argbind +gradio-client \ No newline at end of file diff --git a/update-repos.sh b/update-repos.sh new file mode 100644 index 0000000000000000000000000000000000000000..678024588ec646d3feccc59eacd0ac5f5c1d7fb2 --- /dev/null +++ b/update-repos.sh @@ -0,0 +1,11 @@ +# +repos=( "vampnet-music" "vampnet-percussion" "vampnet-n64" "vampnet-birds" "vampnet-choir" "vampnet-machines" "nesquik" "vampnet-opera") +for repo in "${repos[@]}" +do + echo "Updating $repo" + git remote add --fetch $repo https://huggingface.co/spaces/hugggof/$repo + git push --force $repo main +done + +# https://huggingface.co/spaces/hugggof/vampnet-music +# git push --space-percussion main \ No newline at end of file diff --git a/vampnet/__init__.py b/vampnet/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..2a62b66c254aa6ca1eb78a14603ccd5d6941bac3 --- /dev/null +++ b/vampnet/__init__.py @@ -0,0 +1,79 @@ + +from . import modules +from pathlib import Path +from . import scheduler +from .interface import Interface +from .modules.transformer import VampNet + + +__version__ = "0.0.1" + +ROOT = Path(__file__).parent.parent +MODELS_DIR = ROOT / "models" / "vampnet" + +from huggingface_hub import hf_hub_download, HfFileSystem +DEFAULT_HF_MODEL_REPO_DIR = ROOT / "DEFAULT_HF_MODEL_REPO" +DEFAULT_HF_MODEL_REPO = DEFAULT_HF_MODEL_REPO_DIR.read_text().strip() +# DEFAULT_HF_MODEL_REPO = "hugggof/vampnet" +FS = HfFileSystem() + +def download_codec(): + # from dac.model.dac import DAC + from lac.model.lac import LAC as DAC + repo_id = DEFAULT_HF_MODEL_REPO + filename = "codec.pth" + codec_path = hf_hub_download( + repo_id=repo_id, + filename=filename, + subfolder=None, + local_dir=MODELS_DIR + ) + return codec_path + + +def download_default(): + filenames = ["coarse.pth", "c2f.pth", "wavebeat.pth"] + repo_id = DEFAULT_HF_MODEL_REPO + paths = [] + for filename in filenames: + path = f"{MODELS_DIR}/{filename}" + if not Path(path).exists(): + print(f"{path} does not exist, downloading") + FS.download(f"{repo_id}/{filename}", path) + paths.append(path) + + # load the models + return paths[0], paths[1] + + +def download_finetuned(name, repo_id=DEFAULT_HF_MODEL_REPO): + filenames = ["coarse.pth", "c2f.pth"] + paths = [] + for filename in filenames: + path = f"{MODELS_DIR}/loras/{name}/{filename}" + if not Path(path).exists(): + print(f"{path} does not exist, downloading") + FS.download(f"{repo_id}/loras/{name}/{filename}", path) + paths.append(path) + + # load the models + return paths[0], paths[1] + +def list_finetuned(repo_id=DEFAULT_HF_MODEL_REPO): + diritems = FS.listdir(f"{repo_id}/loras") + # iterate through all the names + valid_diritems = [] + for item in diritems: + model_file_items = FS.listdir(item["name"]) + item_names = [item["name"].split("/")[-1] for item in model_file_items] + # check that theres a "c2f.pth" and "coarse.pth" in the items + c2f_exists = "c2f.pth" in item_names + coarse_exists = "coarse.pth" in item_names + if c2f_exists and coarse_exists: + valid_diritems.append(item) + + # get the names of the valid items + names = [item["name"].split("/")[-1] for item in valid_diritems] + return names + + diff --git a/vampnet/beats.py b/vampnet/beats.py new file mode 100644 index 0000000000000000000000000000000000000000..47c293f6782346543511d8cdae0901761dd1615d --- /dev/null +++ b/vampnet/beats.py @@ -0,0 +1,251 @@ +import json +import logging +import warnings +from dataclasses import dataclass +from pathlib import Path +from typing import Any +from typing import List +from typing import Tuple +from typing import Union + +import librosa +import torch +import numpy as np +from audiotools import AudioSignal + + +logging.basicConfig(level=logging.INFO) + +################### +# beat sync utils # +################### + +AGGREGATOR_REGISTRY = { + "mean": np.mean, + "median": np.median, + "max": np.max, + "min": np.min, +} + + +def list_aggregators() -> list: + return list(AGGREGATOR_REGISTRY.keys()) + + +@dataclass +class TimeSegment: + start: float + end: float + + @property + def duration(self): + return self.end - self.start + + def __str__(self) -> str: + return f"{self.start} - {self.end}" + + def find_overlapping_segment( + self, segments: List["TimeSegment"] + ) -> Union["TimeSegment", None]: + """Find the first segment that overlaps with this segment, or None if no segment overlaps""" + for s in segments: + if s.start <= self.start and s.end >= self.end: + return s + return None + + +def mkdir(path: Union[Path, str]) -> Path: + p = Path(path) + p.mkdir(parents=True, exist_ok=True) + return p + + + +################### +# beat data # +################### +@dataclass +class BeatSegment(TimeSegment): + downbeat: bool = False # if there's a downbeat on the start_time + + +class Beats: + def __init__(self, beat_times, downbeat_times): + if isinstance(beat_times, np.ndarray): + beat_times = beat_times.tolist() + if isinstance(downbeat_times, np.ndarray): + downbeat_times = downbeat_times.tolist() + self._beat_times = beat_times + self._downbeat_times = downbeat_times + self._use_downbeats = False + + def use_downbeats(self, use_downbeats: bool = True): + """use downbeats instead of beats when calling beat_times""" + self._use_downbeats = use_downbeats + + def beat_segments(self, signal: AudioSignal) -> List[BeatSegment]: + """ + segments a song into time segments corresponding to beats. + the first segment starts at 0 and ends at the first beat time. + the last segment starts at the last beat time and ends at the end of the song. + """ + beat_times = self._beat_times.copy() + downbeat_times = self._downbeat_times + beat_times.insert(0, 0) + beat_times.append(signal.signal_duration) + + downbeat_ids = np.intersect1d(beat_times, downbeat_times, return_indices=True)[ + 1 + ] + is_downbeat = [ + True if i in downbeat_ids else False for i in range(len(beat_times)) + ] + segments = [ + BeatSegment(start_time, end_time, downbeat) + for start_time, end_time, downbeat in zip( + beat_times[:-1], beat_times[1:], is_downbeat + ) + ] + return segments + + def get_beats(self) -> np.ndarray: + """returns an array of beat times, in seconds + if downbeats is True, returns an array of downbeat times, in seconds + """ + return np.array( + self._downbeat_times if self._use_downbeats else self._beat_times + ) + + @property + def beat_times(self) -> np.ndarray: + """return beat times""" + return np.array(self._beat_times) + + @property + def downbeat_times(self) -> np.ndarray: + """return downbeat times""" + return np.array(self._downbeat_times) + + def beat_times_to_feature_frames( + self, signal: AudioSignal, features: np.ndarray + ) -> np.ndarray: + """convert beat times to frames, given an array of time-varying features""" + beat_times = self.get_beats() + beat_frames = ( + beat_times * signal.sample_rate / signal.signal_length * features.shape[-1] + ).astype(np.int64) + return beat_frames + + def sync_features( + self, feature_frames: np.ndarray, features: np.ndarray, aggregate="median" + ) -> np.ndarray: + """sync features to beats""" + if aggregate not in AGGREGATOR_REGISTRY: + raise ValueError(f"unknown aggregation method {aggregate}") + + return librosa.util.sync( + features, feature_frames, aggregate=AGGREGATOR_REGISTRY[aggregate] + ) + + def to_json(self) -> dict: + """return beats and downbeats as json""" + return { + "beats": self._beat_times, + "downbeats": self._downbeat_times, + "use_downbeats": self._use_downbeats, + } + + @classmethod + def from_dict(cls, data: dict): + """load beats and downbeats from json""" + inst = cls(data["beats"], data["downbeats"]) + inst.use_downbeats(data["use_downbeats"]) + return inst + + def save(self, output_dir: Path): + """save beats and downbeats to json""" + mkdir(output_dir) + with open(output_dir / "beats.json", "w") as f: + json.dump(self.to_json(), f) + + @classmethod + def load(cls, input_dir: Path): + """load beats and downbeats from json""" + beats_file = Path(input_dir) / "beats.json" + with open(beats_file, "r") as f: + data = json.load(f) + return cls.from_dict(data) + + +################### +# beat tracking # +################### + + +class BeatTracker: + def extract_beats(self, signal: AudioSignal) -> Tuple[np.ndarray, np.ndarray]: + """extract beats from an audio signal""" + raise NotImplementedError + + def __call__(self, signal: AudioSignal) -> Beats: + """extract beats from an audio signal + NOTE: if the first beat (and/or downbeat) is detected within the first 100ms of the audio, + it is discarded. This is to avoid empty bins with no beat synced features in the first beat. + Args: + signal (AudioSignal): signal to beat track + Returns: + Tuple[np.ndarray, np.ndarray]: beats and downbeats + """ + beats, downbeats = self.extract_beats(signal) + return Beats(beats, downbeats) + + +class WaveBeat(BeatTracker): + def __init__(self, ckpt_path: str = "checkpoints/wavebeat", device: str = "cpu"): + from wavebeat.dstcn import dsTCNModel + + model = dsTCNModel.load_from_checkpoint(ckpt_path, map_location=torch.device(device)) + model.eval() + + self.device = device + self.model = model + + def extract_beats(self, signal: AudioSignal) -> Tuple[np.ndarray, np.ndarray]: + """returns beat and downbeat times, in seconds""" + # extract beats + self.model.to('cuda' if torch.cuda.is_available() else 'cpu') + beats, downbeats = self.model.predict_beats_from_array( + audio=signal.audio_data.squeeze(0), + sr=signal.sample_rate, + use_gpu=torch.cuda.is_available(), + ) + + return beats, downbeats + + +class MadmomBeats(BeatTracker): + def __init__(self): + raise NotImplementedError + + def extract_beats(self, signal: AudioSignal) -> Tuple[np.ndarray, np.ndarray]: + """returns beat and downbeat times, in seconds""" + pass + + +BEAT_TRACKER_REGISTRY = { + "wavebeat": WaveBeat, + "madmom": MadmomBeats, +} + + +def list_beat_trackers() -> list: + return list(BEAT_TRACKER_REGISTRY.keys()) + + +def load_beat_tracker(beat_tracker: str, **kwargs) -> BeatTracker: + if beat_tracker not in BEAT_TRACKER_REGISTRY: + raise ValueError( + f"Unknown beat tracker {beat_tracker}. Available: {list_beat_trackers()}" + ) + + return BEAT_TRACKER_REGISTRY[beat_tracker](**kwargs) \ No newline at end of file diff --git a/vampnet/control.py b/vampnet/control.py new file mode 100644 index 0000000000000000000000000000000000000000..234a19815864c7fc68a7771e0211d6431558b8c8 --- /dev/null +++ b/vampnet/control.py @@ -0,0 +1,277 @@ +from dataclasses import dataclass +from functools import partial +from typing import Optional + +from torch import nn + +import vampnet.dsp.signal as sn +from vampnet.dsp.signal import Signal +from vampnet.mask import random_along_time +from torch import Tensor +import torch + + +class MedianFilterAugment(nn.Module): + + def __init__(self, + kernel_size: int, + train_min: int = 1, + train_max: int = 20, + ): + super().__init__() + self.kernel_size = kernel_size + self.train_min = train_min + self.train_max = train_max + + def forward(self, x: Tensor) -> Tensor: + if self.training: + sizes = torch.randint( + self.train_min, + self.train_max, + size=(x.shape[0],) + ) + else: + sizes = self.kernel_size + # print(f"median filter sizes: {sizes}") + return sn.median_filter_1d(x, sizes) + +class RMS(nn.Module): + + def __init__(self, + hop_length, + window_length=2048, + n_quantize=None, + sample_rate=44100, + median_filter_size: Optional[int] = None, + train_median_filter_min=1, + train_median_filter_max=15, + ): + super().__init__() + + self.hop_length = hop_length + self.window_length = window_length + self.n_quantize = n_quantize + self.sample_rate = sample_rate + + self.mf = MedianFilterAugment( + kernel_size=median_filter_size, + train_min=train_median_filter_min, + train_max=train_median_filter_max + ) if median_filter_size is not None else None + + @property + def dim(self): + return 1 + + def extract(self, sig: Signal) -> Tensor: + rmsd = sn.rms(sig, + window_length=self.window_length, + hop_length=self.hop_length, + )[:, :, :-1] # TODO: cutting the last frame to match DAC tokens but why :'( + nb, _, _ = rmsd.shape + + if self.n_quantize is not None: + # standardize to 0-1 + rmsd = (rmsd - rmsd.min()) / (rmsd.max() - rmsd.min()) + + # quantize to 128 steps + rmsd = torch.round(rmsd * self.n_quantize) + rmsd = rmsd / self.n_quantize + + if self.mf is not None: + rmsd = self.mf(rmsd) + + return rmsd + + + +class HarmonicChroma(nn.Module): + + def __init__(self, + hop_length: int, window_length: int = 4096, + n_chroma: int = 48, sample_rate: int = 44100, + top_n: int = 0 + ): + super().__init__() + from torchaudio.prototype.transforms import ChromaScale + self.hop_length = hop_length + self.window_length = window_length + self.n_chroma = n_chroma + self.sample_rate = sample_rate + self.top_n = top_n + + # HUGO: this representation, as is, + # encodes timbre information in the chroma + # which is not what we want!!! + # would a median filter help perhaps? + self.chroma = ChromaScale( + sample_rate=self.sample_rate, + n_freqs=self.window_length // 2 + 1, + n_chroma=self.n_chroma, + octwidth=5.0, + ) + + @property + def dim(self): + return self.n_chroma + + def extract(self, sig: Signal) -> Tensor: + from vampnet.dsp.hpss import hpss + self.chroma.to(sig.wav.device) + + # spectrogram + spec = sn.stft(sig, + window_length=self.window_length, + hop_length=self.hop_length + ) + # magnitude + spec = torch.abs(spec) + + # hpss + spec = hpss(spec, kernel_size=51, hard=True)[0] + + # chroma + chroma = self.chroma(spec) + + # get the rms of this spec + rms_d = sn.rms_from_spec( + spec, window_length=self.window_length + ) + + # convert the rms to db + rms_d = 10 * torch.log10(rms_d + 1e-7) + + # make a mask based on the rms < -40 + mask = torch.where(rms_d < -40, torch.zeros_like(rms_d), torch.ones_like(rms_d)) + + # remove anything below 80 (where the fuck did I get this number from?) + chroma = torch.where(chroma < 100, torch.zeros_like(chroma), chroma) + + # Get top 2 values and indices along the -2 dimension + if self.top_n: + _, topk_indices = torch.topk(chroma, self.top_n, dim=-2) + + # Create a mask for the top 2 values + topk_mask = torch.zeros_like(chroma).scatter_(-2, topk_indices, 1.0) + + # Retain only the top 2 values + chroma = chroma * topk_mask + + # apply the mask + chroma = chroma * mask.unsqueeze(-2) + + # Apply softmax along dim=-2 + if self.top_n > 0: + chroma = torch.nn.functional.softmax(chroma, dim=-2) + + # mask out any timesteps whose chroma have all equal values (all 0s before softmax) + # TODO: i did this with chatgpt, there's gott a be a better way + chroma_mean = chroma.mean(dim=-2, keepdim=True) + chroma_diff = torch.abs(chroma - chroma_mean) + equal_mask = torch.all(chroma_diff < 1e-6, dim=-2, keepdim=True) + + # Set chroma values to zero for timesteps with all equal values + chroma = torch.where(equal_mask, torch.zeros_like(chroma), chroma) + + + return chroma[:, 0, :, :-1] # mono only :( FIX ME! + + +# TODO: try harmonic mel? + +CONTROLLERS = { + "rms": RMS, + "rmsq128": partial(RMS, n_quantize=128), + "rmsq16": partial(RMS, n_quantize=16), + "rms-median": partial(RMS, median_filter_size=5), + "rmsq16-median": partial(RMS, n_quantize=16, median_filter_size=3), + "hchroma": HarmonicChroma, + "hchroma-12c-top2": partial(HarmonicChroma, n_chroma=12, top_n=2), # TODO: refactor me. If this works, this should just be named hchroma. + "hchroma-36c-top3": partial(HarmonicChroma, n_chroma=36, top_n=3) # TODO: refactor me. If this works, this should just be named hchroma. +} + +class Sketch2SoundController(nn.Module): + + def __init__( + self, + ctrl_keys: list[str], + hop_length: str, + sample_rate: int, + ): + super().__init__() + + assert all([k in CONTROLLERS for k in ctrl_keys]), f"got an unsupported control key in {ctrl_keys}!\n supported: {CONTROLLERS.keys()}" + + self.hop_length = hop_length + self.ctrl_keys = ctrl_keys + self.sample_rate = sample_rate + + self.controllers = { + k: CONTROLLERS[k](hop_length=hop_length, sample_rate=sample_rate) + for k in self.ctrl_keys + } + + @property + def ctrl_dims(self, ) -> dict[str, int]: + return { + k: controller.dim for k, controller in self.controllers.items() + } + + def extract(self, sig: Signal) -> dict[str, Tensor]: + ctrls = { + k: controller.extract(sig) for k, controller in self.controllers.items() + } + return ctrls + + def random_mask(self, ctrls: dict[str, Tensor], r: float): + masks = {} + for k, ctrl in ctrls.items(): + masks[k] = 1-random_along_time(ctrl, r) + return masks + + def empty_mask(self, ctrls: dict[str, Tensor]): + first_key = next(iter(ctrls)) + mask = torch.zeros_like(ctrls[first_key]) + return {k: mask for k in ctrls} + + +def test_controller(): + controller = Sketch2SoundController( + ctrl_keys=["rms-median", "rms", "rmsq128"], + hop_length=512, + sample_rate=44100 + ) + controller.train() + # sig = sn.read_from_file("assets/example.wav") + # sig = sn.read_from_file("/Users/hugo/Downloads/DCS_SE_FullChoir_ScaleUpDown06_A2_DYN.wav") + # sig = sn.excerpt('/Users/hugo/Downloads/(guitarra - hugo mix) bubararu - tambor negro.wav', offset=0, duration=10) + sig = sn.read_from_file("assets/voice-prompt.wav") + ctrls = controller.extract(sig) + print(f"given sig of shape {sig.wav.shape}, extracted controls: {ctrls}") + + # print the whole thing + # torch.set_printoptions(profile="full") + # print(ctrls["hchroma"][0][0][:, 200:210]) + + # imshow the chroma + import matplotlib.pyplot as plt + + # Define relative heights for the subplots + fig, (ax1, ax2, ax3, ax4) = plt.subplots( + 4, 1, + sharex=True, + ) + + # Display the spectrogram on the top + ax1.imshow(sn.stft(sig, hop_length=512, window_length=2048).abs()[0][0].cpu().log().numpy(), aspect='auto', origin='lower') + # display rms on the bottom + ax2.plot(ctrls["rms-median"][0][0]) + ax3.plot(ctrls["rms"][0][0]) + ax4.plot(ctrls["rmsq128"][0][0]) + + plt.tight_layout() # Ensure proper spacing + plt.savefig("img.png") + + +if __name__ == "__main__": + test_controller() \ No newline at end of file diff --git a/vampnet/interface.py b/vampnet/interface.py new file mode 100644 index 0000000000000000000000000000000000000000..9aa5eb2a3243a701814c9e9bb3d55ed28688eaa0 --- /dev/null +++ b/vampnet/interface.py @@ -0,0 +1,635 @@ +import os +from pathlib import Path +import math +import logging + +import torch +import numpy as np +from audiotools import AudioSignal +import tqdm + +from .modules.transformer import VampNet +from .beats import WaveBeat +from .mask import * + +# from dac.model.dac import DAC +from lac.model.lac import LAC as DAC + + +def signal_concat( + audio_signals: list, +): + audio_data = torch.cat([x.audio_data for x in audio_signals], dim=-1) + + return AudioSignal(audio_data, sample_rate=audio_signals[0].sample_rate) + + +def _load_model( + ckpt: str, + lora_ckpt: str = None, + device: str = "cpu", + chunk_size_s: int = 10, +): + # we need to set strict to False if the model has lora weights to add later + model = VampNet.load(location=Path(ckpt), map_location="cpu", strict=False) + + # load lora weights if needed + if lora_ckpt is not None: + if not Path(lora_ckpt).exists(): + should_cont = input( + f"lora checkpoint {lora_ckpt} does not exist. continue? (y/n) " + ) + if should_cont != "y": + raise Exception("aborting") + else: + model.load_state_dict(torch.load(lora_ckpt, map_location="cpu"), strict=False) + + model.to(device) + model.eval() + model.chunk_size_s = chunk_size_s + return model + + + +class Interface(torch.nn.Module): + def __init__( + self, + coarse_ckpt: str = None, + coarse_lora_ckpt: str = None, + coarse2fine_ckpt: str = None, + coarse2fine_lora_ckpt: str = None, + codec_ckpt: str = None, + wavebeat_ckpt: str = "./models/vampnet/wavebeat.pth", + device: str = "cpu", + coarse_chunk_size_s: int = 10, + coarse2fine_chunk_size_s: int = 3, + compile=True, + ): + super().__init__() + assert codec_ckpt is not None, "must provide a codec checkpoint" + self.codec = DAC.load(Path(codec_ckpt)) + self.codec.eval() + self.codec.to(device) + self.codec_path = Path(codec_ckpt) + + assert coarse_ckpt is not None, "must provide a coarse checkpoint" + self.coarse = _load_model( + ckpt=coarse_ckpt, + lora_ckpt=coarse_lora_ckpt, + device=device, + chunk_size_s=coarse_chunk_size_s, + ) + self.coarse_path = Path(coarse_ckpt) + + # check if we have a coarse2fine ckpt + if coarse2fine_ckpt is not None: + self.c2f_path = Path(coarse2fine_ckpt) + self.c2f = _load_model( + ckpt=coarse2fine_ckpt, + lora_ckpt=coarse2fine_lora_ckpt, + device=device, + chunk_size_s=coarse2fine_chunk_size_s, + ) + else: + self.c2f_path = None + self.c2f = None + + if wavebeat_ckpt is not None: + logging.debug(f"loading wavebeat from {wavebeat_ckpt}") + self.beat_tracker = WaveBeat(wavebeat_ckpt, device=device) + self.beat_tracker.model.to(device) + else: + self.beat_tracker = None + + self.device = device + self.loudness = -24.0 + + if compile: + logging.debug(f"compiling models") + self.coarse = torch.compile(self.coarse) + if self.c2f is not None: + self.c2f = torch.compile(self.c2f) + self.codec = torch.compile(self.codec) + + + @classmethod + def default(cls): + from . import download_codec, download_default + print(f"loading default vampnet") + codec_path = download_codec() + coarse_path, c2f_path = download_default() + + return Interface( + coarse_ckpt=coarse_path, + coarse2fine_ckpt=c2f_path, + codec_ckpt=codec_path, + ) + + @classmethod + def available_models(cls): + from . import list_finetuned + return list_finetuned() + ["default"] + + + def load_finetuned(self, name: str): + assert name in self.available_models(), f"{name} is not a valid model name" + from . import download_finetuned, download_default + if name == "default": + coarse_path, c2f_path = download_default() + else: + coarse_path, c2f_path = download_finetuned(name) + self.reload( + coarse_ckpt=coarse_path, + c2f_ckpt=c2f_path, + ) + + def reload( + self, + coarse_ckpt: str = None, + c2f_ckpt: str = None, + ): + if coarse_ckpt is not None: + # check if we already loaded, if so, don't reload + if self.coarse_path == Path(coarse_ckpt): + logging.debug(f"already loaded {coarse_ckpt}") + else: + self.coarse = _load_model( + ckpt=coarse_ckpt, + device=self.device, + chunk_size_s=self.coarse.chunk_size_s, + ) + self.coarse_path = Path(coarse_ckpt) + logging.debug(f"loaded {coarse_ckpt}") + + if c2f_ckpt is not None: + if self.c2f_path == Path(c2f_ckpt): + logging.debug(f"already loaded {c2f_ckpt}") + else: + self.c2f = _load_model( + ckpt=c2f_ckpt, + device=self.device, + chunk_size_s=self.c2f.chunk_size_s, + ) + self.c2f_path = Path(c2f_ckpt) + logging.debug(f"loaded {c2f_ckpt}") + + def s2t(self, seconds: float): + """seconds to tokens""" + if isinstance(seconds, np.ndarray): + return np.ceil(seconds * self.codec.sample_rate / self.codec.hop_length) + else: + return math.ceil(seconds * self.codec.sample_rate / self.codec.hop_length) + + def s2t2s(self, seconds: float): + """seconds to tokens to seconds""" + return self.t2s(self.s2t(seconds)) + + def t2s(self, tokens: int): + """tokens to seconds""" + return tokens * self.codec.hop_length / self.codec.sample_rate + + def to(self, device): + self.device = device + self.coarse.to(device) + self.codec.to(device) + + if self.c2f is not None: + self.c2f.to(device) + + if self.beat_tracker is not None: + self.beat_tracker.model.to(device) + return self + + def decode(self, z: torch.Tensor): + return self.coarse.decode(z, self.codec) + + def _preprocess(self, signal: AudioSignal): + signal = ( + signal.clone() + .resample(self.codec.sample_rate) + .to_mono() + .normalize(self.loudness) + .ensure_max_of_audio(1.0) + ) + logging.debug(f"length before codec preproc: {signal.samples.shape}") + signal.samples, length = self.codec.preprocess(signal.samples, signal.sample_rate) + logging.debug(f"length after codec preproc: {signal.samples.shape}") + return signal + + @torch.inference_mode() + def encode(self, signal: AudioSignal): + signal = signal.to(self.device) + signal = self._preprocess(signal) + z = self.codec.encode(signal.samples, signal.sample_rate)["codes"] + return z + + def snap_to_beats( + self, + signal: AudioSignal + ): + assert hasattr(self, "beat_tracker"), "No beat tracker loaded" + beats, downbeats = self.beat_tracker.extract_beats(signal) + + # trim the signa around the first beat time + samples_begin = int(beats[0] * signal.sample_rate ) + samples_end = int(beats[-1] * signal.sample_rate) + logging.debug(beats[0]) + signal = signal.clone().trim(samples_begin, signal.length - samples_end) + + return signal + + def make_beat_mask(self, + signal: AudioSignal, + before_beat_s: float = 0.0, + after_beat_s: float = 0.02, + mask_downbeats: bool = True, + mask_upbeats: bool = True, + downbeat_downsample_factor: int = None, + beat_downsample_factor: int = None, + dropout: float = 0.0, + invert: bool = True, + ): + """make a beat synced mask. that is, make a mask that + places 1s at and around the beat, and 0s everywhere else. + """ + assert self.beat_tracker is not None, "No beat tracker loaded" + + + # get the beat times + beats, downbeats = self.beat_tracker.extract_beats(signal) + + # get the beat indices in z + beats_z, downbeats_z = self.s2t(beats), self.s2t(downbeats) + + # remove downbeats from beats + beats_z = torch.tensor(beats_z)[~torch.isin(torch.tensor(beats_z), torch.tensor(downbeats_z))] + beats_z = beats_z.tolist() + downbeats_z = downbeats_z.tolist() + + # make the mask + seq_len = self.s2t(signal.duration) + mask = torch.zeros(seq_len, device=self.device) + + mask_b4 = self.s2t(before_beat_s) + mask_after = self.s2t(after_beat_s) + + if beat_downsample_factor is not None: + if beat_downsample_factor < 1: + raise ValueError("mask_beat_downsample_factor must be >= 1 or None") + else: + beat_downsample_factor = 1 + + if downbeat_downsample_factor is not None: + if downbeat_downsample_factor < 1: + raise ValueError("mask_beat_downsample_factor must be >= 1 or None") + else: + downbeat_downsample_factor = 1 + + beats_z = beats_z[::beat_downsample_factor] + downbeats_z = downbeats_z[::downbeat_downsample_factor] + logging.debug(f"beats_z: {len(beats_z)}") + logging.debug(f"downbeats_z: {len(downbeats_z)}") + + if mask_upbeats: + for beat_idx in beats_z: + _slice = int(beat_idx - mask_b4), int(beat_idx + mask_after) + num_steps = mask[_slice[0]:_slice[1]].shape[0] + _m = torch.ones(num_steps, device=self.device) + _m_mask = torch.bernoulli(_m * (1 - dropout)) + _m = _m * _m_mask.long() + + mask[_slice[0]:_slice[1]] = _m + + if mask_downbeats: + for downbeat_idx in downbeats_z: + _slice = int(downbeat_idx - mask_b4), int(downbeat_idx + mask_after) + num_steps = mask[_slice[0]:_slice[1]].shape[0] + _m = torch.ones(num_steps, device=self.device) + _m_mask = torch.bernoulli(_m * (1 - dropout)) + _m = _m * _m_mask.long() + + mask[_slice[0]:_slice[1]] = _m + + mask = mask.clamp(0, 1) + if invert: + mask = 1 - mask + + mask = mask[None, None, :].bool().long() + if self.c2f is not None: + mask = mask.repeat(1, self.c2f.n_codebooks, 1) + else: + mask = mask.repeat(1, self.coarse.n_codebooks, 1) + return mask + + def set_chunk_size(self, chunk_size_s: float): + self.coarse.chunk_size_s = chunk_size_s + + @torch.inference_mode() + def coarse_to_fine( + self, + z: torch.Tensor, + mask: torch.Tensor = None, + return_mask: bool = False, + **kwargs + ): + assert self.c2f is not None, "No coarse2fine model loaded" + length = z.shape[-1] + chunk_len = self.s2t(self.c2f.chunk_size_s) + n_chunks = math.ceil(z.shape[-1] / chunk_len) + + # zero pad to chunk_len + if length % chunk_len != 0: + pad_len = chunk_len - (length % chunk_len) + z = torch.nn.functional.pad(z, (0, pad_len)) + mask = torch.nn.functional.pad(mask, (0, pad_len), value=1) if mask is not None else None + + n_codebooks_to_append = self.c2f.n_codebooks - z.shape[1] + if n_codebooks_to_append > 0: + z = torch.cat([ + z, + torch.zeros(z.shape[0], n_codebooks_to_append, z.shape[-1]).long().to(self.device) + ], dim=1) + logging.debug(f"appended {n_codebooks_to_append} codebooks to z") + + # set the mask to 0 for all conditioning codebooks + if mask is not None: + mask = mask.clone() + mask[:, :self.c2f.n_conditioning_codebooks, :] = 0 + + fine_z = [] + for i in range(n_chunks): + chunk = z[:, :, i * chunk_len : (i + 1) * chunk_len] + mask_chunk = mask[:, :, i * chunk_len : (i + 1) * chunk_len] if mask is not None else None + + with torch.autocast("cuda", dtype=torch.bfloat16): + chunk = self.c2f.generate( + codec=self.codec, + time_steps=chunk_len, + start_tokens=chunk, + return_signal=False, + mask=mask_chunk, + cfg_guidance=None, + **kwargs + ) + fine_z.append(chunk) + + fine_z = torch.cat(fine_z, dim=-1) + if return_mask: + return fine_z[:, :, :length].clone(), apply_mask(fine_z, mask, self.c2f.mask_token)[0][:, :, :length].clone() + + return fine_z[:, :, :length].clone() + + @torch.inference_mode() + def coarse_vamp( + self, + z, + mask, + return_mask=False, + gen_fn=None, + **kwargs + ): + # coarse z + cz = z[:, : self.coarse.n_codebooks, :].clone() + mask = mask[:, : self.coarse.n_codebooks, :] + # assert cz.shape[-1] <= self.s2t(self.coarse.chunk_size_s), f"the sequence of tokens provided must match the one specified in the coarse chunk size, but got {cz.shape[-1]} and {self.s2t(self.coarse.chunk_size_s)}" + + # cut into chunks, keep the last chunk separate if it's too small + chunk_len = self.s2t(self.coarse.chunk_size_s) + n_chunks = math.ceil(cz.shape[-1] / chunk_len) + last_chunk_len = cz.shape[-1] % chunk_len + + cz_chunks = [] + mask_chunks = [] + for i in range(n_chunks): + chunk = cz[:, :, i * chunk_len : (i + 1) * chunk_len] + mask_chunk = mask[:, :, i * chunk_len : (i + 1) * chunk_len] + + # make sure that the very first and last timestep of each chunk is 0 so that we don't get a weird + # discontinuity when we stitch the chunks back together + # only if there's already a 0 somewhere in the chunk + if torch.any(mask_chunk == 0): + mask_chunk = mask_chunk.clone() + mask_chunk[:, :, 0] = 0 + mask_chunk[:, :, -1] = 0 + + cz_chunks.append(chunk) + mask_chunks.append(mask_chunk) + + # now vamp each chunk + cz_masked_chunks = [] + cz_vamped_chunks = [] + for chunk, mask_chunk in zip(cz_chunks, mask_chunks): + cz_masked_chunk, mask_chunk = apply_mask(chunk, mask_chunk, self.coarse.mask_token) + cz_masked_chunk = cz_masked_chunk[:, : self.coarse.n_codebooks, :] + cz_masked_chunks.append(cz_masked_chunk) + + + gen_fn = gen_fn or self.coarse.generate + with torch.autocast("cuda", dtype=torch.bfloat16): + c_vamp_chunk = gen_fn( + codec=self.codec, + time_steps=chunk_len, + start_tokens=cz_masked_chunk, + return_signal=False, + mask=mask_chunk, + **kwargs + ) + cz_vamped_chunks.append(c_vamp_chunk) + + # stitch the chunks back together + cz_masked = torch.cat(cz_masked_chunks, dim=-1) + c_vamp = torch.cat(cz_vamped_chunks, dim=-1) + + # add the fine codes back in + c_vamp = torch.cat( + [c_vamp, z[:, self.coarse.n_codebooks :, :]], + dim=1 + ) + + if return_mask: + return c_vamp, cz_masked + + return c_vamp + + def build_mask(self, + z: torch.Tensor, + sig: AudioSignal = None, + rand_mask_intensity: float = 1.0, + prefix_s: float = 0.0, + suffix_s: float = 0.0, + periodic_prompt: int = 7, + periodic_prompt_width: int = 1, + onset_mask_width: int = 0, + _dropout: float = 0.0, + upper_codebook_mask: int = 3, + ncc: int = 0, + ): + mask = linear_random(z, rand_mask_intensity) + mask = mask_and( + mask, + inpaint(z, self.s2t(prefix_s), self.s2t(suffix_s)), + ) + + pmask = periodic_mask(z, periodic_prompt, periodic_prompt_width, random_roll=True) + mask = mask_and(mask, pmask) + + if onset_mask_width > 0: + assert sig is not None, f"must provide a signal to use onset mask" + mask = mask_and( + mask, onset_mask( + sig, z, self, + width=onset_mask_width + ) + ) + + mask = dropout(mask, _dropout) + mask = codebook_unmask(mask, ncc) + + mask = codebook_mask(mask, int(upper_codebook_mask), None) + return mask + + def vamp( + self, + codes: torch.Tensor, + mask: torch.Tensor, + batch_size: int = 1, + feedback_steps: int = 1, + time_stretch_factor: int = 1, + return_mask: bool = False, + **kwargs, + ): + z = codes + + # expand z to batch size + z = z.expand(batch_size, -1, -1) + mask = mask.expand(batch_size, -1, -1) + + # stretch mask and z to match the time stretch factor + # we'll add (stretch_factor - 1) mask tokens in between each timestep of z + # and we'll make the mask 1 in all the new slots we added + if time_stretch_factor > 1: + z = z.repeat_interleave(time_stretch_factor, dim=-1) + mask = mask.repeat_interleave(time_stretch_factor, dim=-1) + added_mask = torch.ones_like(mask) + added_mask[:, :, ::time_stretch_factor] = 0 + mask = mask.bool() | added_mask.bool() + mask = mask.long() + + # the forward pass + logging.debug(z.shape) + logging.debug("coarse!") + zv = z + for i in range(feedback_steps): + zv, mask_z = self.coarse_vamp( + zv, + mask=mask, + return_mask=True, + **kwargs) + # roll the mask around a random amount + mask_z = mask_z.roll( + shifts=(i + 1) % feedback_steps, + dims=-1 + ) + + + # add the top codebooks back in + if zv.shape[1] < z.shape[1]: + logging.debug(f"adding {z.shape[1] - zv.shape[1]} codebooks back in") + zv = torch.cat( + [zv, z[:, self.coarse.n_codebooks :, :]], + dim=1 + ) + + # now, coarse2fine + logging.debug(f"coarse2fine!") + zv, fine_zv_mask = self.coarse_to_fine( + zv, + mask=mask, + typical_filtering=True, + _sampling_steps=2, + return_mask=True + ) + mask_z = torch.cat( + [mask_z[:, :self.coarse.n_codebooks, :], fine_zv_mask[:, self.coarse.n_codebooks:, :]], + dim=1 + ) + + z = zv + + if return_mask: + return z, mask_z.cpu(), + else: + return z + + def visualize_codes(self, z: torch.Tensor): + import matplotlib.pyplot as plt + # make sure the figsize is square when imshow is called + fig = plt.figure(figsize=(10, 7)) + # in subplots, plot z[0] and the mask + # set title to "codes" and "mask" + fig.add_subplot(2, 1, 1) + plt.imshow(z[0].cpu().numpy(), aspect='auto', origin='lower', cmap="tab20", interpolation='none') + plt.title("codes") + plt.ylabel("codebook index") + # set the xticks to seconds + + +if __name__ == "__main__": + import audiotools as at + import logging + logger = logging.getLogger() + logger.setLevel(logging.INFO) + torch.set_logging.debugoptions(threshold=10000) + at.util.seed(42) + + interface = Interface( + coarse_ckpt="./models/vampnet/coarse.pth", + coarse2fine_ckpt="./models/vampnet/c2f.pth", + codec_ckpt="./models/vampnet/codec.pth", + device="cuda", + wavebeat_ckpt="./models/wavebeat.pth" + ) + + + sig = at.AudioSignal('assets/example.wav') + + z = interface.encode(sig) + + + mask = interface.build_mask( + z=z, + sig=sig, + rand_mask_intensity=1.0, + prefix_s=0.0, + suffix_s=0.0, + periodic_prompt=7, + periodic_prompt2=7, + periodic_prompt_width=1, + onset_mask_width=5, + _dropout=0.0, + upper_codebook_mask=3, + upper_codebook_mask_2=None, + ncc=0, + ) + + zv, mask_z = interface.coarse_vamp( + z, + mask=mask, + return_mask=True, + gen_fn=interface.coarse.generate + ) + + + use_coarse2fine = True + if use_coarse2fine: + zv = interface.coarse_to_fine(zv, mask=mask) + breakpoint() + + mask = interface.decode(mask_z).cpu() + + sig = interface.decode(zv).cpu() + + + logging.debug("done") + + \ No newline at end of file diff --git a/vampnet/mask.py b/vampnet/mask.py new file mode 100644 index 0000000000000000000000000000000000000000..1f9a09c1368ed8f0210353470dbb7aacc41437e7 --- /dev/null +++ b/vampnet/mask.py @@ -0,0 +1,230 @@ +from typing import Optional + +import torch +from audiotools import AudioSignal + +from .util import scalar_to_batch_tensor + +def _gamma(r): + return (r * torch.pi / 2).cos().clamp(1e-10, 1.0) + +def _invgamma(y): + if not torch.is_tensor(y): + y = torch.tensor(y)[None] + return 2 * y.acos() / torch.pi + +def full_mask(x: torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + return torch.ones_like(x).long() + +def empty_mask(x: torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + return torch.zeros_like(x).long() + +def apply_mask( + x: torch.Tensor, + mask: torch.Tensor, + mask_token: int + ): + assert mask.ndim == 3, "mask must be (batch, n_codebooks, seq), but got {mask.ndim}" + assert mask.shape == x.shape, f"mask must be same shape as x, but got {mask.shape} and {x.shape}" + assert mask.dtype == torch.long, "mask must be long dtype, but got {mask.dtype}" + assert ~torch.any(mask > 1), "mask must be binary" + assert ~torch.any(mask < 0), "mask must be binary" + + fill_x = torch.full_like(x, mask_token) + x = x * (1 - mask) + fill_x * mask + + return x, mask + +def random( + x: torch.Tensor, + r: torch.Tensor +): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device) + + r = _gamma(r)[:, None, None] + probs = torch.ones_like(x) * r + + mask = torch.bernoulli(probs) + mask = mask.round().long() + + return mask + +def linear_random( + x: torch.Tensor, + r: torch.Tensor, +): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device).float() + r = r[:, None, None] + + probs = torch.ones_like(x).to(x.device).float() + # expand to batch and codebook dims + probs = probs.expand(x.shape[0], x.shape[1], -1) + probs = probs * r + + mask = torch.bernoulli(probs) + mask = mask.round().long() + + return mask + +def inpaint(x: torch.Tensor, + n_prefix, + n_suffix, +): + assert n_prefix is not None + assert n_suffix is not None + + mask = full_mask(x) + + # if we have a prefix or suffix, set their mask prob to 0 + if n_prefix > 0: + if not isinstance(n_prefix, torch.Tensor): + n_prefix = scalar_to_batch_tensor(n_prefix, x.shape[0]).to(x.device) + for i, n in enumerate(n_prefix): + if n > 0: + mask[i, :, :n] = 0.0 + if n_suffix > 0: + if not isinstance(n_suffix, torch.Tensor): + n_suffix = scalar_to_batch_tensor(n_suffix, x.shape[0]).to(x.device) + for i, n in enumerate(n_suffix): + if n > 0: + mask[i, :, -n:] = 0.0 + + + return mask + +def periodic_mask(x: torch.Tensor, + period: int,width: int = 1, + random_roll=False, + ): + mask = full_mask(x) + if period == 0: + return mask + + if not isinstance(period, torch.Tensor): + period = scalar_to_batch_tensor(period, x.shape[0]) + for i, factor in enumerate(period): + if factor == 0: + continue + for j in range(mask.shape[-1]): + if j % factor == 0: + # figure out how wide the mask should be + j_start = max(0, j - width // 2 ) + j_end = min(mask.shape[-1] - 1, j + width // 2 ) + 1 + # flip a coin for each position in the mask + j_mask = torch.bernoulli(torch.ones(j_end - j_start)) + assert torch.all(j_mask == 1) + j_fill = torch.ones_like(j_mask) * (1 - j_mask) + assert torch.all(j_fill == 0) + # fill + mask[i, :, j_start:j_end] = j_fill + if random_roll: + # add a random offset to the mask + offset = torch.randint(0, period[0], (1,)) + mask = torch.roll(mask, offset.item(), dims=-1) + + return mask + +def codebook_unmask( + mask: torch.Tensor, + n_conditioning_codebooks: int +): + if n_conditioning_codebooks == None: + return mask + # if we have any conditioning codebooks, set their mask to 0 + mask = mask.clone() + mask[:, :n_conditioning_codebooks, :] = 0 + return mask + +def codebook_mask(mask: torch.Tensor, val1: int, val2: int = None): + mask = mask.clone() + mask[:, val1:, :] = 1 + # val2 = val2 or val1 + # vs = torch.linspace(val1, val2, mask.shape[1]) + # for t, v in enumerate(vs): + # v = int(v) + # mask[:, v:, t] = 1 + + return mask + +def mask_and( + mask1: torch.Tensor, + mask2: torch.Tensor +): + assert mask1.shape == mask2.shape, "masks must be same shape" + return torch.min(mask1, mask2) + +def dropout( + mask: torch.Tensor, + p: float, +): + # instead of the above, mask along the last dimensions + tsteps = mask.shape[-1] + tsteps_to_drop = int(tsteps * p) + tsteps_to_keep = tsteps - tsteps_to_drop + idxs_to_drop = torch.randint(0, tsteps, (tsteps_to_drop,)) + mask = mask.clone() + mask[:, :, idxs_to_drop] = 1 + return mask.long() + + + + +def mask_or( + mask1: torch.Tensor, + mask2: torch.Tensor +): + assert mask1.shape == mask2.shape, f"masks must be same shape, but got {mask1.shape} and {mask2.shape}" + assert mask1.max() <= 1, "mask1 must be binary" + assert mask2.max() <= 1, "mask2 must be binary" + assert mask1.min() >= 0, "mask1 must be binary" + assert mask2.min() >= 0, "mask2 must be binary" + return (mask1 + mask2).clamp(0, 1) + +def time_stretch_mask( + x: torch.Tensor, + stretch_factor: int, +): + assert stretch_factor >= 1, "stretch factor must be >= 1" + c_seq_len = x.shape[-1] + x = x.repeat_interleave(stretch_factor, dim=-1) + + # trim cz to the original length + x = x[:, :, :c_seq_len] + + mask = periodic_mask(x, stretch_factor, width=1) + return mask + +def onset_mask( + sig: AudioSignal, + z: torch.Tensor, + interface, + width: int = 1, +): + import librosa + + onset_frame_idxs = librosa.onset.onset_detect( + y=sig.samples[0][0].detach().cpu().numpy(), sr=sig.sample_rate, + hop_length=interface.codec.hop_length, + backtrack=True, + ) + if len(onset_frame_idxs) == 0: + print("no onsets detected") + print("onset_frame_idxs", onset_frame_idxs) + print("mask shape", z.shape) + + mask = torch.ones_like(z) + for idx in onset_frame_idxs: + mask[:, :, idx-width:idx+width] = 0 + + return mask + + + +if __name__ == "__main__": + sig = AudioSignal("assets/example.wav") diff --git a/vampnet/modules/__init__.py b/vampnet/modules/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..3f4c8c226e42d022c60b620e8f21ccaf4e6a57bd --- /dev/null +++ b/vampnet/modules/__init__.py @@ -0,0 +1,6 @@ +import audiotools + +audiotools.ml.BaseModel.INTERN += ["vampnet.modules.**"] +audiotools.ml.BaseModel.EXTERN += ["einops", "flash_attn.flash_attention", "loralib"] + +from .transformer import VampNet \ No newline at end of file diff --git a/vampnet/modules/activations.py b/vampnet/modules/activations.py new file mode 100644 index 0000000000000000000000000000000000000000..c013c6302d1569e9c1937915a0ee638632071e51 --- /dev/null +++ b/vampnet/modules/activations.py @@ -0,0 +1,55 @@ +import math +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange + + +class NewGELU(nn.Module): + """ + Implementation of the GELU activation function currently in Google BERT repo + (identical to OpenAI GPT). Also see the Gaussian Error Linear Units + paper: https://arxiv.org/abs/1606.08415 + """ + + def forward(self, x): + return ( + 0.5 + * x + * ( + 1.0 + + torch.tanh( + math.sqrt(2.0 / math.pi) * (x + 0.044715 * torch.pow(x, 3.0)) + ) + ) + ) + +class GatedGELU(nn.Module): + def __init__(self): + super().__init__() + self.gelu = NewGELU() + + def forward(self, x, dim: int = -1): + p1, p2 = x.chunk(2, dim=dim) + return p1 * self.gelu(p2) + +class Snake1d(nn.Module): + def __init__(self, channels): + super().__init__() + self.alpha = nn.Parameter(torch.ones(channels)) + + def forward(self, x): + return x + (self.alpha + 1e-9).reciprocal() * torch.sin(self.alpha * x).pow(2) + +def get_activation(name: str = "relu"): + if name == "relu": + return nn.ReLU + elif name == "gelu": + return NewGELU + elif name == "geglu": + return GatedGELU + elif name == "snake": + return Snake1d + else: + raise ValueError(f"Unrecognized activation {name}") \ No newline at end of file diff --git a/vampnet/modules/layers.py b/vampnet/modules/layers.py new file mode 100644 index 0000000000000000000000000000000000000000..0c7df97be3b1726ac210da762c83a25dbd3434c7 --- /dev/null +++ b/vampnet/modules/layers.py @@ -0,0 +1,164 @@ +import time +from typing import Optional +from typing import Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange +from torch.nn.utils import weight_norm + +# Scripting this brings model speed up 1.4x +@torch.jit.script +def snake(x, alpha): + shape = x.shape + x = x.reshape(shape[0], shape[1], -1) + x = x + (alpha + 1e-9).reciprocal() * torch.sin(alpha * x).pow(2) + x = x.reshape(shape) + return x + + +class Snake1d(nn.Module): + def __init__(self, channels): + super().__init__() + self.alpha = nn.Parameter(torch.ones(1, channels, 1)) + + def forward(self, x): + return snake(x, self.alpha) + + +def num_params(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def recurse_children(module, fn): + for child in module.children(): + if isinstance(child, nn.ModuleList): + for c in child: + yield recurse_children(c, fn) + if isinstance(child, nn.ModuleDict): + for c in child.values(): + yield recurse_children(c, fn) + + yield recurse_children(child, fn) + yield fn(child) + + +def WNConv1d(*args, **kwargs): + return weight_norm(nn.Conv1d(*args, **kwargs)) + + +def WNConvTranspose1d(*args, **kwargs): + return weight_norm(nn.ConvTranspose1d(*args, **kwargs)) + + +class SequentialWithFiLM(nn.Module): + """ + handy wrapper for nn.Sequential that allows FiLM layers to be + inserted in between other layers. + """ + + def __init__(self, *layers): + super().__init__() + self.layers = nn.ModuleList(layers) + + @staticmethod + def has_film(module): + mod_has_film = any( + [res for res in recurse_children(module, lambda c: isinstance(c, FiLM))] + ) + return mod_has_film + + def forward(self, x, cond): + for layer in self.layers: + if self.has_film(layer): + x = layer(x, cond) + else: + x = layer(x) + return x + + +class FiLM(nn.Module): + def __init__(self, input_dim: int, output_dim: int): + super().__init__() + + self.input_dim = input_dim + self.output_dim = output_dim + + if input_dim > 0: + self.beta = nn.Linear(input_dim, output_dim) + self.gamma = nn.Linear(input_dim, output_dim) + + def forward(self, x, r): + if self.input_dim == 0: + return x + else: + beta, gamma = self.beta(r), self.gamma(r) + beta, gamma = ( + beta.view(x.size(0), self.output_dim, 1), + gamma.view(x.size(0), self.output_dim, 1), + ) + x = x * (gamma + 1) + beta + return x + + +class CodebookEmbedding(nn.Module): + def __init__( + self, + vocab_size: int, + latent_dim: int, + n_codebooks: int, + emb_dim: int, + special_tokens: Optional[Tuple[str]] = None, + ): + super().__init__() + self.n_codebooks = n_codebooks + self.emb_dim = emb_dim + self.latent_dim = latent_dim + self.vocab_size = vocab_size + + if special_tokens is not None: + for tkn in special_tokens: + self.special = nn.ParameterDict( + { + tkn: nn.Parameter(torch.randn(n_codebooks, self.latent_dim)) + for tkn in special_tokens + } + ) + self.special_idxs = { + tkn: i + vocab_size for i, tkn in enumerate(special_tokens) + } + + self.out_proj = nn.Conv1d(n_codebooks * self.latent_dim, self.emb_dim, 1) + + def from_codes(self, codes: torch.Tensor, codec): + """ + get a sequence of continuous embeddings from a sequence of discrete codes. + unlike it's counterpart in the original VQ-VAE, this function adds for any special tokens + necessary for the language model, like . + """ + n_codebooks = codes.shape[1] + latent = [] + for i in range(n_codebooks): + c = codes[:, i, :] + + lookup_table = codec.quantizer.quantizers[i].codebook.weight + if hasattr(self, "special"): + special_lookup = torch.cat( + [self.special[tkn][i : i + 1] for tkn in self.special], dim=0 + ) + lookup_table = torch.cat([lookup_table, special_lookup], dim=0) + + l = F.embedding(c, lookup_table).transpose(1, 2) + latent.append(l) + + latent = torch.cat(latent, dim=1) + return latent + + def forward(self, latents: torch.Tensor): + """ + project a sequence of latents to a sequence of embeddings + """ + x = self.out_proj(latents) + return x + diff --git a/vampnet/modules/transformer.py b/vampnet/modules/transformer.py new file mode 100644 index 0000000000000000000000000000000000000000..8dd7779a32f21a3d4e74558345d8065e31baab61 --- /dev/null +++ b/vampnet/modules/transformer.py @@ -0,0 +1,1139 @@ +import math +import logging +from typing import Optional, Tuple, Union, List + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor +from einops import rearrange +import loralib as lora +import audiotools as at + +from .activations import get_activation +from .layers import CodebookEmbedding +from .layers import FiLM +from .layers import SequentialWithFiLM +from .layers import WNConv1d +from ..util import scalar_to_batch_tensor, codebook_flatten, codebook_unflatten +from ..mask import _gamma + +LORA_R = 8 + +# def log(t, eps=1e-20): +# return torch.log(t + eps) + + +def gumbel_noise_like(t): + noise = torch.zeros_like(t).uniform_(1e-20, 1) + return -torch.log(-torch.log(noise)) + + +def gumbel_sample(t, temperature=1.0, dim=-1): + return ((t / max(temperature, 1e-10)) + gumbel_noise_like(t)).argmax(dim=dim) + + +class RMSNorm(nn.Module): + def __init__(self, hidden_size: int, eps=1e-6): + super().__init__() + self.weight = nn.Parameter(torch.ones(hidden_size)) + self.var_eps = eps + + def forward(self, x): + """Returns root mean square normalized version of input `x` + # T5 uses a layer_norm which only scales and doesn't shift, which is also known + # as Root Mean Square Layer Normalization https://arxiv.org/abs/1910.07467 + # thus varience is calculated w/o mean and there is no bias + Parameters + ---------- + x : Tensor[B x T x D] + Returns + ------- + Tensor[B x T x D] + """ + var = x.pow(2).mean(-1, keepdim=True) + x = x * torch.rsqrt(var + self.var_eps) + + return self.weight * x + + +class FeedForward(nn.Module): + def __init__( + self, d_model: int = 512, dropout: float = 0.1, activation: str = "geglu" + ): + super().__init__() + factor = 2 if activation == "geglu" else 1 + self.w_1 = lora.Linear(d_model, d_model * 4, bias=False, r=LORA_R) + self.w_2 = lora.Linear(d_model * 4 // factor, d_model, bias=False, r=LORA_R) + self.drop = nn.Dropout(dropout) + self.act = get_activation(activation)() + + def forward(self, x): + """Computes position-wise feed-forward layer + Parameters + ---------- + x : Tensor[B x T x D] + Returns + ------- + Tensor[B x T x D] + """ + x = self.w_1(x) + x = self.act(x) + x = self.drop(x) + x = self.w_2(x) + return x + + +class MultiHeadRelativeAttention(nn.Module): + def __init__( + self, + n_head: int = 8, + d_model: int = 512, + dropout: float = 0.1, + bidirectional: bool = True, + has_relative_attention_bias: bool = True, + attention_num_buckets: int = 32, + attention_max_distance: int = 128, + ): + super().__init__() + d_head = d_model // n_head + self.n_head = n_head + self.d_head = d_head + self.bidirectional = bidirectional + self.has_relative_attention_bias = has_relative_attention_bias + self.attention_num_buckets = attention_num_buckets + self.attention_max_distance = attention_max_distance + + # Create linear query, key, value projections + self.w_qs = lora.Linear(d_model, d_model, bias=False, r=LORA_R) + self.w_ks = nn.Linear(d_model, d_model, bias=False) + self.w_vs = lora.Linear(d_model, d_model, bias=False, r=LORA_R) + + # Create linear final output projection + self.fc = lora.Linear(d_model, d_model, bias=False, r=LORA_R) + + # Dropout for attention output weights + self.dropout = nn.Dropout(dropout) + + # Create relative positional embeddings (if turned on) + if has_relative_attention_bias: + self.relative_attention_bias = nn.Embedding(attention_num_buckets, n_head) + + def _relative_position_bucket(self, relative_position): + """Converts unbounded relative position into bounded set of buckets + with half "exact" buckets (1 position = 1 bucket) and half "log-spaced" + buckets + Parameters + ---------- + relative_position : Tensor[T_q x T_kv] + Relative positions between queries and key_value items + Returns + ------- + Tensor[T_q x T_kv] + Input relative positions converted into buckets + """ + relative_buckets = 0 + num_buckets = self.attention_num_buckets + max_distance = self.attention_max_distance + + # Convert relative position for (-inf, inf) to [0, inf] + # Negative relative positions correspond to past + # Positive relative positions correspond to future + if self.bidirectional: + # use half buckets for each side (past / future) + num_buckets //= 2 + + # Shift the position positions by `num_buckets` to wrap around + # negative positions + relative_buckets += (relative_position > 0).to(torch.long) * num_buckets + relative_position = torch.abs(relative_position) + else: + # If not bidirectional, ignore positive positions and wrap + # negative positions to positive + relative_position = -torch.min( + relative_position, torch.zeros_like(relative_position) + ) + + # Allocate half of the buckets are for exact increments in positions + max_exact = num_buckets // 2 + is_small = relative_position < max_exact + + # The other half of the buckets are for logarithmically bigger bins in + # positions up to `max_distance` + relative_postion_if_large = max_exact + ( + torch.log(relative_position.float() / max_exact) + / math.log(max_distance / max_exact) + * (num_buckets - max_exact) + ).to(torch.long) + + # Clip the max relative position to `num_buckets - 1` + relative_postion_if_large = torch.min( + relative_postion_if_large, + torch.full_like(relative_postion_if_large, num_buckets - 1), + ) + + # Choose relative buckets based on small or large positions + relative_buckets += torch.where( + is_small, relative_position, relative_postion_if_large + ) + + return relative_buckets + + def compute_bias(self, query_length, key_length): + """Computes a position bias scalar for each index in query_length x key_length + Parameters + ---------- + query_length : int + key_length : int + Returns + ------- + Tensor[heads x 1 x T_q x T_kv] + Position bias to be applied on attention logits + """ + + query_position = torch.arange(query_length, dtype=torch.long)[:, None] + key_position = torch.arange(key_length, dtype=torch.long)[None, :] + relative_position = key_position - query_position + + # Convert relative position to buckets + relative_position_bucket = self._relative_position_bucket(relative_position) + relative_position_bucket = relative_position_bucket.to( + self.relative_attention_bias.weight.device + ) + + # Index attention bias values + values = self.relative_attention_bias(relative_position_bucket) + values = rearrange(values, "q k h -> h 1 q k") + + return values + + def forward(self, q, k, v, mask=None, position_bias=None): + """Computes attention over (keys, values) for every timestep in query + Parameters + ---------- + q : Tensor[B x T_q x d_model] + Query vectors + k : Tensor[B x T_kv x d_model] + Key vectors to compute attention over + v : Tensor[B x T_kv x d_model] + Value vectors corresponding to the keys + mask : Tensor[B x T_q x T_kv], optional + position_bias: Tensor[head x 1 x T_q x T_kv] + Returns + ------- + Tensor[B x T_q x d_model] + Outputs after attending (key, value) using queries + """ + # Compute query, key, value projections + q = rearrange(self.w_qs(q), "b l (head k) -> head b l k", head=self.n_head) + k = rearrange(self.w_ks(k), "b t (head k) -> head b t k", head=self.n_head) + v = rearrange(self.w_vs(v), "b t (head k) -> head b t k", head=self.n_head) + + # Compute attention matrix + attn = torch.einsum("hblk,hbtk->hblt", [q, k]) / np.sqrt(q.shape[-1]) + + # Add relative position bias to attention scores + if position_bias is None: + if self.has_relative_attention_bias: + position_bias = self.compute_bias(q.size(-2), k.size(-2)) + else: + position_bias = torch.zeros_like(attn) + attn += position_bias + + # Apply mask to attention scores to prevent looking up invalid locations + if mask is not None: + attn = attn.masked_fill(mask[None] == 0, -1e9) + + # Normalize attention scores and add dropout + attn = torch.softmax(attn, dim=3) + attn = self.dropout(attn) + + # Compute attended outputs (product of attention matrix and values) + output = torch.einsum("hblt,hbtv->hblv", [attn, v]) + output = rearrange(output, "head b l v -> b l (head v)") + output = self.fc(output) + + return output, position_bias + + +class TransformerLayer(nn.Module): + def __init__( + self, + d_model: int = 512, + d_cond: int = 64, + n_heads: int = 8, + bidirectional: bool = True, + is_decoder: bool = False, + has_relative_attention_bias: bool = False, + flash_attn: bool = False, + dropout: float = 0.1, + ): + super().__init__() + # Store args + self.is_decoder = is_decoder + + # Create self-attention layer + self.norm_1 = RMSNorm(d_model) + self.film_1 = FiLM(d_cond, d_model) + self.flash_attn = flash_attn + + if flash_attn: + from flash_attn.flash_attention import FlashMHA + self.self_attn = FlashMHA( + embed_dim=d_model, + num_heads=n_heads, + attention_dropout=dropout, + causal=False, + ) + else: + self.self_attn = MultiHeadRelativeAttention( + n_heads, d_model, dropout, bidirectional, has_relative_attention_bias + ) + + # (Optional) Create cross-attention layer + if is_decoder: + self.norm_2 = RMSNorm(d_model) + self.film_2 = FiLM(d_cond, d_model) + self.cross_attn = MultiHeadRelativeAttention( + n_heads, + d_model, + dropout, + bidirectional=True, + has_relative_attention_bias=False, + ) + + # Create last feed-forward layer + self.norm_3 = RMSNorm(d_model) + self.film_3 = FiLM(d_cond, d_model) + self.feed_forward = FeedForward(d_model=d_model, dropout=dropout) + + # Create dropout + self.dropout = nn.Dropout(dropout) + + def forward( + self, + x, + x_mask, + cond, + src=None, + src_mask=None, + position_bias=None, + encoder_decoder_position_bias=None, + ): + """Computes one transformer layer consisting of self attention, (op) cross attention + and feedforward layer + Parameters + ---------- + x : Tensor[B x T_q x D] + x_mask : Tensor[B x T_q] + src : Tensor[B x T_kv x D], optional + src_mask : Tensor[B x T_kv x D], optional + position_bias : Tensor[heads x B x T_q x T_q], optional + Relative position bias for self attention layer + encoder_decoder_position_bias : Tensor[heads x B x T_q x T_kv], optional + Relative position bias for cross attention layer + Returns + ------- + Tensor[B x T_q x D] + """ + y = self.norm_1(x) + y = self.film_1(y.permute(0, 2, 1), cond).permute(0, 2, 1) + if self.flash_attn: + with torch.autocast(y.device.type, dtype=torch.bfloat16): + y = self.self_attn(y)[0] + else: + y, position_bias = self.self_attn(y, y, y, x_mask, position_bias) + x = x + self.dropout(y) + + if self.is_decoder: + y = self.norm_2(x) + y = self.film_2(y.permute(0, 2, 1), cond).permute(0, 2, 1) + y, encoder_decoder_position_bias = self.cross_attn( + y, src, src, src_mask, encoder_decoder_position_bias + ) + x = x + self.dropout(y) + + y = self.norm_3(x) + y = self.film_3( + y.permute( + 0, + 2, + 1, + ), + cond, + ).permute(0, 2, 1) + y = self.feed_forward(y) + x = x + self.dropout(y) + + return x, position_bias, encoder_decoder_position_bias + + +class TransformerStack(nn.Module): + def __init__( + self, + d_model: int = 512, + d_cond: int = 64, + n_heads: int = 8, + n_layers: int = 8, + last_layer: bool = True, + bidirectional: bool = True, + flash_attn: bool = False, + is_decoder: bool = False, + dropout: float = 0.1, + ): + super().__init__() + # Store args + self.bidirectional = bidirectional + self.is_decoder = is_decoder + + # Create transformer layers + # In T5, relative attention bias is shared by all layers in the stack + self.layers = nn.ModuleList( + [ + TransformerLayer( + d_model, + d_cond, + n_heads, + bidirectional, + is_decoder, + has_relative_attention_bias=True if (i == 0) else False, + flash_attn=flash_attn, + dropout=dropout, + ) + for i in range(n_layers) + ] + ) + + # Perform last normalization + self.norm = RMSNorm(d_model) if last_layer else None + + def subsequent_mask(self, size): + return torch.ones(1, size, size).tril().bool() + + def forward(self, x, x_mask, cond=None, src=None, src_mask=None, + return_activations: bool = False + ): + """Computes a full transformer stack + Parameters + ---------- + x : Tensor[B x T_q x D] + x_mask : Tensor[B x T_q] + src : Tensor[B x T_kv x D], optional + src_mask : Tensor[B x T_kv], optional + Returns + ------- + Tensor[B x T_q x D] + """ + + # Convert `src_mask` to (B x T_q x T_kv) shape for cross attention masking + if self.is_decoder: + src_mask = x_mask.unsqueeze(-1) * src_mask.unsqueeze(-2) + + # Convert `x_mask` to (B x T_q x T_q) shape for self attention masking + x_mask = x_mask.unsqueeze(-2) + if not self.bidirectional: + x_mask = x_mask * self.subsequent_mask(x.size(1)).to(x_mask.device) + + # Initialize position biases + position_bias = None + encoder_decoder_position_bias = None + + # Compute transformer layers + if return_activations: + activations = [] + for layer in self.layers: + x, position_bias, encoder_decoder_position_bias = layer( + x=x, + x_mask=x_mask, + cond=cond, + src=src, + src_mask=src_mask, + position_bias=position_bias, + encoder_decoder_position_bias=encoder_decoder_position_bias, + ) + if return_activations: + activations.append(x.detach()) + + + out = self.norm(x) if self.norm is not None else x + if return_activations: + return out, torch.stack(activations) + else: + return out + +class CFGDropout(nn.Module): + + def __init__(self, p: float = 0.2): + super().__init__() + self.p = p + + def forward(self, x: Tensor): + # dropout along the batch dim + if self.training: + mask = torch.rand(x.shape[0], 1, 1, device=x.device) > self.p + else: + mask = torch.ones(x.shape[0], 1, 1, device=x.device) + return x * mask + +class ControlEncoder(nn.Module): + + def __init__(self, + ctrl_dims: dict[str, int], + embedding_dim: int, + cfg_dropout_prob: float + ): + super().__init__() + self.ctrl_encoders = nn.ModuleDict({ + key: nn.Linear(dim, embedding_dim) + for key, dim in ctrl_dims.items() + }) + + self.cfg_dropout = CFGDropout(p=cfg_dropout_prob) + self.all_dropout = CFGDropout(p=cfg_dropout_prob / 2) + + def forward(self, + embedding: Tensor, # embedding to which we will add ctrls + ctrls: dict[str, Tensor], + ctrl_masks: dict[str, Tensor] + ): + # INPUT: ctrl tensor should be shape (b d n) + + # assert that we got all the right ctrls and ctrl_masks according to the encoders that we have + assert list(sorted(ctrls.keys())) == list(sorted(self.ctrl_encoders.keys())), "ctrls and ctrl_encoders keys do not match" + assert list(sorted(ctrl_masks.keys())) == list(sorted(self.ctrl_encoders.keys())), "ctrl_masks and ctrl_encoders keys do not match" + + out_emb = torch.zeros_like(embedding) + for ck in ctrls: + ctrld = ctrls[ck] + ctrlmask = ctrl_masks[ck] + + assert ctrld.shape[-1] == embedding.shape[-1], "ctrls should match x along time dimension" + assert ctrlmask.ndim == 2, "ctrlmask should be 2d" + assert ctrlmask.shape[-1] == ctrld.shape[-1], "ctrlmask should match ctrld along time dimension" + + # project ctrl with encoder + ctrld = rearrange(ctrld, "b d n -> b n d") + ctrl_emb = self.ctrl_encoders[ck](ctrld) + ctrld = rearrange(ctrld, "b n d -> b d n") + ctrl_emb = rearrange(ctrl_emb, "b n d -> b d n") + + # apply ctrl mask + ctrl_emb = ctrl_emb * ctrlmask[:, None, :] + + # apply cfg dropout + ctrl_emb = self.cfg_dropout(ctrl_emb) + + # add to the out_emb + out_emb = out_emb + ctrl_emb + + # randomly dropout all ctrls + out_emb = self.all_dropout(out_emb) + + return out_emb + +class VampNet(at.ml.BaseModel): + def __init__( + self, + n_heads: int = 20, + n_layers: int = 16, + r_cond_dim: int = 0, + n_codebooks: int = 9, + n_conditioning_codebooks: int = 0, + latent_dim: int = 8, + embedding_dim: int = 1280, + vocab_size: int = 1024, + flash_attn: bool = True, + noise_mode: str = "mask", + dropout: float = 0.1, + ctrl_dims: Optional[dict[str, int]] = None, + cfg_dropout_prob: float = 0.2, + cond_dim: int = 0, + ): + super().__init__() + assert r_cond_dim == 0, f"r_cond_dim must be 0 (not supported), but got {r_cond_dim}" + self.n_heads = n_heads + self.n_layers = n_layers + self.r_cond_dim = r_cond_dim + self.n_codebooks = n_codebooks + self.n_conditioning_codebooks = n_conditioning_codebooks + self.embedding_dim = embedding_dim + self.vocab_size = vocab_size + self.latent_dim = latent_dim + self.flash_attn = flash_attn + self.noise_mode = noise_mode + self.cond_dim = cond_dim + self.r_cond_dim = r_cond_dim + self.dropout = dropout + self.cfg_dropout_prob = cfg_dropout_prob + # self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + assert self.noise_mode == "mask", "deprecated" + + self.embedding = CodebookEmbedding( + latent_dim=latent_dim, + n_codebooks=n_codebooks, + vocab_size=vocab_size, + emb_dim=embedding_dim, + special_tokens=["MASK"], + ) + self.mask_token = self.embedding.special_idxs["MASK"] + + self.transformer = TransformerStack( + d_model=embedding_dim, + d_cond=r_cond_dim, + n_heads=n_heads, + n_layers=n_layers, + last_layer=True, + bidirectional=True, + flash_attn=flash_attn, + is_decoder=False, + dropout=dropout, + ) + + # Add final conv layer + self.n_predict_codebooks = n_codebooks - n_conditioning_codebooks + self.classifier = SequentialWithFiLM( + WNConv1d( + embedding_dim, + vocab_size * self.n_predict_codebooks, + kernel_size=1, + padding="same", + # groups=self.n_predict_codebooks, + ), + ) + + if self.cond_dim > 0: + self.cfg_dropout = CFGDropout(p=cfg_dropout_prob) + + self.ctrl_dims = ctrl_dims + if self.ctrl_dims is not None: + self.ctrl_encoder = ControlEncoder( + ctrl_dims, + embedding_dim=embedding_dim, + cfg_dropout_prob=cfg_dropout_prob + ) + + def forward(self, x, ctrls=None, ctrl_masks=None, return_activations: bool = False): + x = self.embedding(x) + x_mask = torch.ones_like(x, dtype=torch.bool)[:, :1, :].squeeze(1) + + if self.ctrl_dims is not None: + # apply controls + x = x + self.ctrl_encoder(x, ctrls, ctrl_masks) + + x = rearrange(x, "b d n -> b n d") + out = self.transformer(x=x, x_mask=x_mask, return_activations=return_activations) + if return_activations: + out, activations = out + + out = rearrange(out, "b n d -> b d n") + + out = self.classifier(out, None) # no cond here! + + out = rearrange(out, "b (p c) t -> b p (t c)", c=self.n_predict_codebooks) + + if return_activations: + return out, activations + else: + return out + + def r_embed(self, r, max_positions=10000): + if self.r_cond_dim > 0: + dtype = r.dtype + + r = _gamma(r) * max_positions + half_dim = self.r_cond_dim // 2 + + emb = math.log(max_positions) / (half_dim - 1) + emb = torch.arange(half_dim, device=r.device).float().mul(-emb).exp() + + emb = r[:, None] * emb[None, :] + emb = torch.cat([emb.sin(), emb.cos()], dim=1) + + if self.r_cond_dim % 2 == 1: # zero pad + emb = nn.functional.pad(emb, (0, 1), mode="constant") + + return emb.to(dtype) + else: + return r + + @torch.no_grad() + def decode(self, z, codec): + """ + convert a sequence of latents to a signal. + """ + assert z.ndim == 3 + + # remove mask token + z = z.masked_fill(z == self.mask_token, 0) + signal = at.AudioSignal( + codec.decode( + codec.quantizer.from_latents(self.embedding.from_codes(z, codec))[0] + )["audio"], + codec.sample_rate, + ) + + # find where the mask token is and replace it with silence in the audio + for tstep in range(z.shape[-1]): + if torch.all(z[:, :, tstep] == self.mask_token): + sample_idx_0 = tstep * codec.hop_length + sample_idx_1 = sample_idx_0 + codec.hop_length + signal.samples[:, :, sample_idx_0:sample_idx_1] = 0.0 + + return signal + + @torch.inference_mode() + def generate( + self, + codec, + time_steps: int = 300, + _sampling_steps: int = 12, + start_tokens: Optional[torch.Tensor] = None, + temperature: float = 1.0, + mask: Optional[torch.Tensor] = None, + mask_temperature: float = 10.5, + ctrls:dict = None, + ctrl_masks:dict = None, + typical_filtering=True, + typical_mass=0.15, + typical_min_tokens=64, + top_p=None, + seed: int = None, + sample_cutoff: float = 1.0, + return_signal=True, + debug=False, + causal_weight: float = 0.0, + cfg_scale: float = 3.0, + cfg_guidance: float = None, + cond = None # unused + ): + if seed is not None: + at.util.seed(seed) + sampling_steps = _sampling_steps + logging.debug(f"beginning generation with {sampling_steps} steps") + + ##################### + # resolve initial z # + ##################### + z = start_tokens + nb = z.shape[0] + + use_cfg = ctrls is not None + tocfg = lambda x: x.repeat(2, 1, 1) if use_cfg else x + tocfgblank = lambda x: torch.cat([x, torch.zeros_like(x)], dim=0) if use_cfg else x + def fromcfg(x): + if use_cfg: + xcond, xuncond = x.chunk(2) + return xuncond + cfg_scale * (xcond - xuncond) + return x + + z = tocfg(z) + if ctrls is not None: + ctrls = {k: tocfg(v) for k, v in ctrls.items()} + ctrl_masks = {k: tocfgblank(v) for k, v in ctrl_masks.items()} + if cond is not None: + cond = tocfg(cond) + + if z is None: + z = torch.full((1, self.n_codebooks, time_steps), self.mask_token).to( + self.device + ) + + + + ################# + # resolve mask # + ################# + + if mask is None: + mask = torch.ones_like(z).to(self.device).int() + mask[:, : self.n_conditioning_codebooks, :] = 0.0 + if mask.ndim == 2: + mask = mask[:, None, :].repeat(1, z.shape[1], 1) + # init_mask = mask.clone() + + + + ########### + # set up # + ########## + # apply the mask to z + z_masked = z.masked_fill(mask.bool(), self.mask_token) + # logging.debug(f"z_masked: {z_masked}") + + # how many mask tokens to begin with? + num_mask_tokens_at_start = (z_masked == self.mask_token).sum() + + # how many codebooks are we inferring vs conditioning on? + n_infer_codebooks = self.n_codebooks - self.n_conditioning_codebooks + + if cfg_guidance is not None: + # we need to repeat our tensors + z_uncond = torch.full_like(z, self.mask_token) + + z_masked = torch.cat( + (z_masked, z_uncond), dim=0 + ) + z = torch.cat( + (z, z_uncond), dim=0 + ) + mask = torch.cat( + (mask, torch.full_like(mask, 1)), dim=0 + ) + + if debug: + DEBUG_FOLDER = "vampnet-debug" + import matplotlib.pyplot as plt + from pathlib import Path + + Path(DEBUG_FOLDER).mkdir(exist_ok=True) + plt.rcParams['figure.dpi'] = 100 # Default DPI for figures + plt.rcParams['figure.figsize'] = (20, 0.4) # Default size for a 4x2000 grid (2000/100, 4/100) + plt.rcParams['image.interpolation'] = 'nearest' # Ensures no smoothing for imshow + plt.rcParams['image.aspect'] = 'auto' # Maintains proper aspect ratio + plt.rcParams['axes.axisbelow'] = True # Ensures axis is beneath the data (for clarity) + plt.rcParams['axes.xmargin'] = 0 # No extra space around data + plt.rcParams['axes.ymargin'] = 0 # Same for Y-axis + + from functools import partial + plt.imshow = partial(plt.imshow, origin='lower') + + + # save the initial mask + plt.clf() + plt.imshow(mask[0].cpu().numpy()) + plt.savefig(f"{DEBUG_FOLDER}/mask.png") + + # save the initial z_masked + plt.clf() + plt.imshow(z_masked[0].cpu().numpy()) + plt.savefig(f"{DEBUG_FOLDER}/z_masked.png") + + # save the initial z + plt.clf() + plt.imshow(z[0].cpu().numpy()) + plt.savefig(f"{DEBUG_FOLDER}/z.png") + + + ################# + # begin sampling # + ################# + from tqdm import tqdm + for i in range(sampling_steps): + if debug: + # save the mask at step i + # make a folder called step i + STEP_FOLDER = (f"{DEBUG_FOLDER}/step_{i}") + Path(STEP_FOLDER).mkdir(exist_ok=True) + + # our current schedule step + r = scalar_to_batch_tensor( + (i + 1) / sampling_steps, + z.shape[0] + ).to(z.device) + + # get latents + latents = self.embedding.from_codes(z_masked, codec) + + + # infer from latents + # NOTE: this collapses the codebook dimension into the sequence dimension + logits = self.forward(latents) # b, prob, seq + logits = fromcfg(logits) + + if cfg_guidance is not None: + logits_cond, logits_uncond = logits[:nb], logits[nb:] + logits_cond = cfg_guidance * logits_cond + cfg_guidance * (1 - logits_uncond) + + logits = logits.permute(0, 2, 1) # b, seq, prob + b = logits.shape[0] + + sampled_z, selected_probs = sample_from_logits( + logits, sample=( + (i / sampling_steps) <= sample_cutoff + ), + temperature=temperature, + typical_filtering=typical_filtering, typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens, + top_k=None, top_p=top_p, return_probs=True, + ) + + if debug: + # log the selected probs and sampled + plt.clf() + _selected_probs = codebook_unflatten(selected_probs, n_infer_codebooks) + plt.imshow(_selected_probs[0].cpu().numpy(), ) + plt.colorbar() + plt.savefig(f"{STEP_FOLDER}/selected_probs.png") + + plt.clf() + plt.imshow(sampled_z.cpu().numpy()) + plt.savefig(f"{STEP_FOLDER}/sampled_z.png") + + + + # flatten z_masked and mask, so we can deal with the sampling logic + # we'll unflatten them at the end of the loop for the next forward pass + # remove conditioning codebooks, we'll add them back at the end + z_masked = codebook_flatten(z_masked[:, self.n_conditioning_codebooks:, :]) + + mask = (z_masked == self.mask_token).int() + + if debug: + + plt.clf() + # plt.imshow(mask.cpu().numpy()) + _mask = codebook_unflatten(mask, n_infer_codebooks) + plt.imshow(_mask[0].cpu().numpy()) + plt.savefig(f"{STEP_FOLDER}/mask.png") + + # update the mask, remove conditioning codebooks from the mask + # add z back into sampled z where the mask was false + sampled_z = torch.where( + mask.bool(), sampled_z, z_masked + ) + + # ignore any tokens that weren't masked + selected_probs = torch.where( + mask.bool(), selected_probs, torch.inf + ) + + # get the num tokens to mask, according to the schedule + num_to_mask = torch.floor(_gamma(r) * num_mask_tokens_at_start).unsqueeze(1).long() + logging.debug(f"num to mask: {num_to_mask}") + + if i != (sampling_steps - 1): + num_to_mask = torch.maximum( + torch.tensor(1), + torch.minimum( + mask.sum(dim=-1, keepdim=True) - 1, + num_to_mask + ) + ) + + + # get our new mask + mask = mask_by_random_topk( + num_to_mask, selected_probs, mask_temperature * (1-r) + ) + + # update the mask + z_masked = torch.where( + mask.bool(), self.mask_token, sampled_z + ) + + z_masked = codebook_unflatten(z_masked, n_infer_codebooks) + mask = codebook_unflatten(mask, n_infer_codebooks) + + # add conditioning codebooks back to z_masked + z_masked = torch.cat( + (z[:, :self.n_conditioning_codebooks, :], z_masked), dim=1 + ) + + # add conditioning codebooks back to sampled_z + sampled_z = codebook_unflatten(sampled_z, n_infer_codebooks) + sampled_z = torch.cat( + (z[:, :self.n_conditioning_codebooks, :], sampled_z), dim=1 + ) + + if cfg_guidance is not None: + sampled_z = sampled_z[:nb] + + if return_signal: + return self.decode(sampled_z, codec) + else: + return sampled_z + + + + + +def sample_from_logits( + logits, + sample: bool = True, + temperature: float = 1.0, + top_k: int = None, + top_p: float = None, + typical_filtering: bool = False, + typical_mass: float = 0.2, + typical_min_tokens: int = 1, + return_probs: bool = False + ): + """Convenience function to sample from a categorial distribution with input as + unnormalized logits. + + Parameters + ---------- + logits : Tensor[..., vocab_size] + config: SamplingConfig + The set of hyperparameters to be used for sampling + sample : bool, optional + Whether to perform multinomial sampling, by default True + temperature : float, optional + Scaling parameter when multinomial samping, by default 1.0 + top_k : int, optional + Restricts sampling to only `top_k` values acc. to probability, + by default None + top_p : float, optional + Restricts sampling to only those values with cumulative + probability = `top_p`, by default None + + Returns + ------- + Tensor[...] + Sampled tokens + """ + shp = logits.shape[:-1] + + if typical_filtering: + typical_filter(logits, + typical_mass=typical_mass, + typical_min_tokens=typical_min_tokens + ) + + # Apply top_k sampling + if top_k is not None: + v, _ = logits.topk(top_k) + logits[logits < v[..., [-1]]] = -float("inf") + + # Apply top_p (nucleus) sampling + if top_p is not None and top_p < 1.0: + v, sorted_indices = logits.sort(descending=True) + cumulative_probs = v.softmax(dim=-1).cumsum(dim=-1) + + sorted_indices_to_remove = cumulative_probs > top_p + # Right shift indices_to_remove to keep 1st token over threshold + sorted_indices_to_remove = F.pad(sorted_indices_to_remove, (1, 0), value=False)[ + ..., :-1 + ] + + # Compute indices_to_remove in unsorted array + indices_to_remove = sorted_indices_to_remove.scatter( + -1, sorted_indices, sorted_indices_to_remove + ) + + logits[indices_to_remove] = -float("inf") + + # Perform multinomial sampling after normalizing logits + probs = ( + F.softmax(logits / temperature, dim=-1) + if temperature > 0 + else logits.softmax(dim=-1) + ) + token = ( + probs.view(-1, probs.size(-1)).multinomial(1).squeeze(1).view(*shp) + if sample + else logits.argmax(-1) + ) + + if return_probs: + token_probs = probs.take_along_dim(token.unsqueeze(-1), dim=-1).squeeze(-1) + return token, token_probs + else: + return token + + + +def mask_by_random_topk( + num_to_mask: int, + probs: torch.Tensor, + temperature: float = 1.0, + ): + """ + Args: + num_to_mask (int): number of tokens to mask + probs (torch.Tensor): probabilities for each sampled event, shape (batch, seq) + temperature (float, optional): temperature. Defaults to 1.0. + """ + logging.debug(f"masking by random topk") + logging.debug(f"num to mask: {num_to_mask}") + logging.debug(f"probs shape: {probs.shape}") + logging.debug(f"temperature: {temperature}") + logging.debug("") + + noise = gumbel_noise_like(probs) + temperature = temperature.unsqueeze(-1) + confidence = torch.log(probs) + temperature * noise + logging.debug(f"confidence shape: {confidence.shape}") + + sorted_confidence, sorted_idx = confidence.sort(dim=-1) + logging.debug(f"sorted confidence shape: {sorted_confidence.shape}") + logging.debug(f"sorted idx shape: {sorted_idx.shape}") + + # get the cut off threshold, given the mask length + cut_off = torch.take_along_dim( + sorted_confidence, num_to_mask, axis=-1 + ) + logging.debug(f"cut off shape: {cut_off.shape}") + + # mask out the tokens + mask = confidence < cut_off + logging.debug(f"mask shape: {mask.shape}") + + return mask + +def typical_filter( + logits, + typical_mass: float = 0.95, + typical_min_tokens: int = 1,): + nb, nt, _ = logits.shape + x_flat = rearrange(logits, "b t l -> (b t ) l") + x_flat_norm = torch.nn.functional.log_softmax(x_flat, dim=-1) + x_flat_norm_p = torch.exp(x_flat_norm) + entropy = -(x_flat_norm * x_flat_norm_p).nansum(-1, keepdim=True) + + c_flat_shifted = torch.abs((-x_flat_norm) - entropy) + c_flat_sorted, x_flat_indices = torch.sort(c_flat_shifted, descending=False) + x_flat_cumsum = ( + x_flat.gather(-1, x_flat_indices).softmax(dim=-1).cumsum(dim=-1) + ) + + last_ind = (x_flat_cumsum < typical_mass).sum(dim=-1) + sorted_indices_to_remove = c_flat_sorted > c_flat_sorted.gather( + 1, last_ind.view(-1, 1) + ) + if typical_min_tokens > 1: + sorted_indices_to_remove[..., :typical_min_tokens] = 0 + indices_to_remove = sorted_indices_to_remove.scatter( + 1, x_flat_indices, sorted_indices_to_remove + ) + x_flat = x_flat.masked_fill(indices_to_remove, -float("Inf")) + logits = rearrange(x_flat, "(b t) l -> b t l", t=nt) + return logits + + +if __name__ == "__main__": + # import argbind + from .layers import num_params + + VampNet = argbind.bind(VampNet) + + @argbind.bind(without_prefix=True) + def try_model(device: str = "cuda", batch_size: int = 2, seq_len_s: float = 10.0): + seq_len = int(32000 / 512 * seq_len_s) + + model = VampNet().to(device) + + z = torch.randint( + 0, model.vocab_size, size=(batch_size, model.n_codebooks, seq_len) + ).to(device) + + r = torch.zeros(batch_size).to(device) + + z_mask_latent = torch.rand( + batch_size, model.latent_dim * model.n_codebooks, seq_len + ).to(device) + z_hat = model(z_mask_latent) + + pred = z_hat.argmax(dim=1) + pred = model.embedding.unflatten(pred, n_codebooks=model.n_predict_codebooks) + + logging.debug(f"model has {num_params(model)/1e6:<.3f}M parameters") + logging.debug(f"prediction has shape {pred.shape}") + + args = argbind.parse_args() + with argbind.scope(args): + try_model() + + diff --git a/vampnet/newmask.py b/vampnet/newmask.py new file mode 100644 index 0000000000000000000000000000000000000000..e15dd717b2cf00f7ed8e303997b5aa783d790a9d --- /dev/null +++ b/vampnet/newmask.py @@ -0,0 +1,365 @@ +from typing import Optional + +import torch + +from .util import scalar_to_batch_tensor + +def _gamma(r): + return (r * torch.pi / 2).cos().clamp(1e-10, 1.0) + +def _invgamma(y): + if not torch.is_tensor(y): + y = torch.tensor(y)[None] + return 2 * y.acos() / torch.pi + +def full_mask(x: torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + return torch.ones_like(x).int() + +def empty_mask(x: torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + return torch.zeros_like(x).int() + +def apply_mask( + x: torch.Tensor, + mask: torch.Tensor, + mask_token: int + ): + assert mask.ndim == 3, f"mask must be (batch, n_codebooks, seq), but got {mask.ndim}" + assert mask.shape == x.shape, f"mask must be same shape as x, but got {mask.shape} and {x.shape}" + assert mask.dtype == torch.int, f"mask must be int dtype, but got {mask.dtype}" + assert ~torch.any(mask > 1), "mask must be binary" + assert ~torch.any(mask < 0), "mask must be binary" + mask = mask.int() + + fill_x = torch.full_like(x, mask_token) + x = x * (1 - mask) + fill_x * mask + + return x + +def random( + x: torch.Tensor, + r: torch.Tensor +): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device) + + r = _gamma(r)[:, None, None] + probs = torch.ones_like(x) * r + + mask = torch.bernoulli(probs) + mask = mask.round().int() + + return mask, torch.zeros_like(mask).bool() + +def random_along_time(x: torch.Tensor, r: torch.Tensor): + assert x.ndim == 3, "x must be (batch, channel, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device) + + x = x[:, 0, :] + r = _gamma(r)[:, None] + probs = torch.ones_like(x) * r + + mask = torch.bernoulli(probs) + mask = mask.round().int() + + return mask + + +def stemgen_random(x: torch.Tensor, r: torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device) + + # Assuming x is your input tensor and r is the probability for the Bernoulli distribution + nb, nc, nt = x.shape + + # Randomly sample a codebook level to infer for each item in the batch + c = torch.randint(0, nc, (nb,)).to(x.device) + + # Create a mask tensor of the same shape as x, initially filled with ones + mask = torch.ones_like(x).long().to(x.device) + ignore_indices_mask = torch.zeros_like(x).long().to(x.device) + + # Iterate over each item in the batch + for i in range(nb): + # Create the Bernoulli mask for the sampled level + level_mask = torch.bernoulli(torch.ones(nt).to(x.device) * r[i]).long() + + # Apply the mask to the sampled level + mask[i, c[i]] = level_mask + + # All levels below the sampled level are unmasked (zeros) + mask[i, :c[i]] = 0 + ignore_indices_mask[i, :c[i]] = 1 + + # All levels above the sampled level are masked (ones) + mask[i, c[i]+1:] = 1 + ignore_indices_mask[i, c[i]+1:] = 1 + + # save a debug mask to np txt + # import numpy as np + # np.savetxt("mask.txt", mask[0].cpu().numpy(), fmt="%d") + # np.savetxt("ignore_indices_mask.txt", ignore_indices_mask[0].cpu().numpy(), fmt="%d") + + return mask.int(), ignore_indices_mask.bool() + + +def hugo_random(x: torch.Tensor, r:torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device).float() + + r = _gamma(r)[:, None, None] + + nb, nc, nt = x.shape + + probs = torch.ones_like(x) * r + mask = torch.bernoulli(probs) + # alternatively, the mask level could be the cumsum of the mask + mask = mask.round().long().to(x.device) + mask_levels = nc - mask.sum(dim=1) - 1 + + # create a new mask, where all levels below the mask level are masked + # shape (nb, nc, nt) where new_mask[i, CB:, t] = 1, CB = mask_level[i, t] + # mask = mask_levels[:, :, None] > torch.arange(nc)[None, None, :] + mask = (mask_levels[:, None, :] < torch.arange(nc, device=x.device)[None, :, None]).long() + + ignore_levels = mask_levels + 1 + ignore_indices_mask = (ignore_levels[:, None, :] < torch.arange(nc, device=x.device)[None, :, None]).long() + + # for _b in range(nb): + # for _t in range(nt): + # for _c in range(nc): + # if mask[_b, _c, _t] == 1: + # mask[_b, _c:, _t] = 1 + # ignore_indices_mask[_b, _c + 1:, _t] = 1 + # break + + return mask.long(), ignore_indices_mask.bool() + + +def better_cond_random_but_not_working(x: torch.Tensor, r:torch.Tensor): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device).float() + + r = _gamma(r)[:, None, None] + + nb, nc, nt = x.shape + + probs = torch.ones_like(x) * r + mask = torch.bernoulli(probs) + + mask = mask.round().long().to(x.device) + + # there cannot be anything unmasked if there's an masked token + # in the same timestep and below it + for i in range(nb): + for j in range(nc): + for t in range(nt): + if mask[i, j, t] == 1: + mask[i, j:, t] = 1 + break + + # an ignore indices mask, since we can truly only predict one token + # per timestep + ignore_indices = torch.zeros_like(x) + for i in range(nb): + for j in range(nc): + for t in range(nt): + if mask[i, j, t] == 1: + ignore_indices[i, j, t+1:] = 1 + break + return mask.int(), ignore_indices + + +@torch.jit.script_if_tracing +def linear_random( + x: torch.Tensor, + r: torch.Tensor, +): + assert x.ndim == 3, "x must be (batch, n_codebooks, seq)" + if not isinstance(r, torch.Tensor): + r = scalar_to_batch_tensor(r, x.shape[0]).to(x.device).float() + r = r[:, None, None] + + probs = torch.ones_like(x).to(x.device).float() + # expand to batch and codebook dims + probs = probs.expand(x.shape[0], x.shape[1], -1) + probs = probs * r + + mask = torch.bernoulli(probs) + mask = mask.round().int() + + return mask + +@torch.jit.script_if_tracing +def inpaint(x: torch.Tensor, n_prefix: int, n_suffix: int,): + assert n_prefix is not None + assert n_suffix is not None + + mask = full_mask(x) + + # if we have a prefix or suffix, set their mask prob to 0 + if n_prefix > 0: + if not isinstance(n_prefix, torch.Tensor): + n_prefix = scalar_to_batch_tensor(n_prefix, x.shape[0]).to(x.device) + for i, n in enumerate(n_prefix): + if n > 0: + mask[i, :, :n] = 0.0 + if n_suffix > 0: + if not isinstance(n_suffix, torch.Tensor): + n_suffix = scalar_to_batch_tensor(n_suffix, x.shape[0]).to(x.device) + for i, n in enumerate(n_suffix): + if n > 0: + mask[i, :, -n:] = 0.0 + return mask + +@torch.jit.script_if_tracing +def periodic_mask(x: torch.Tensor, period: int, + width: int = 1, random_roll: bool = False,): + mask = full_mask(x) + if period == 0: + return full_mask(x) + + if not isinstance(period, torch.Tensor): + period = scalar_to_batch_tensor(period, x.shape[0]) + if period.ndim == 0: + period = period[None] + + for i, factor in enumerate(period): + if factor == 0: + continue + for j in range(mask.shape[-1]): + if j % factor == 0: + # figure out how wide the mask should be + j_start = max(0, j - width // 2 ) + j_end = min(mask.shape[-1] - 1, j + width // 2 ) + 1 + # flip a coin for each position in the mask + j_mask = torch.bernoulli(torch.ones(j_end - j_start)) + assert torch.all(j_mask == 1) + j_fill = torch.ones_like(j_mask) * (1 - j_mask) + assert torch.all(j_fill == 0) + # fill + mask[i, :, j_start:j_end] = j_fill + + return mask + +def codebook_unmask( + mask: torch.Tensor, + n_conditioning_codebooks: int +): + if n_conditioning_codebooks == None: + return mask + # if we have any conditioning codebooks, set their mask to 0 + mask = mask.clone() + mask[:, :n_conditioning_codebooks, :] = 0 + return mask + +def codebook_mask(mask: torch.Tensor, val1: int, val2: int = None): + mask = mask.clone() + mask[:, val1:, :] = 1 + # val2 = val2 or val1 + # vs = torch.linspace(val1, val2, mask.shape[1]) + # for t, v in enumerate(vs): + # v = int(v) + # mask[:, v:, t] = 1 + + return mask + +@torch.jit.script_if_tracing +def mask_and( + mask1: torch.Tensor, + mask2: torch.Tensor +): + assert mask1.shape == mask2.shape, "masks must be same shape" + return torch.min(mask1, mask2) + +def drop_ones(mask: torch.Tensor, p: float): + oldshp = mask.shape + mask = mask.view(-1) + + # find ones idxs + ones_idxs = torch.where(mask == 1)[0] + # shuffle idxs + ones_idxs_idxs = torch.randperm(len(ones_idxs)) + ones_idxs = ones_idxs[ones_idxs_idxs] + # drop p% of ones + ones_idxs = ones_idxs[:int(len(ones_idxs) * p)] + # set those idxs to 0 + mask[ones_idxs] = 0 + + mask = mask.view(oldshp) + return mask + + +def mask_or( + mask1: torch.Tensor, + mask2: torch.Tensor +): + assert mask1.shape == mask2.shape, f"masks must be same shape, but got {mask1.shape} and {mask2.shape}" + assert mask1.max() <= 1, "mask1 must be binary" + assert mask2.max() <= 1, "mask2 must be binary" + assert mask1.min() >= 0, "mask1 must be binary" + assert mask2.min() >= 0, "mask2 must be binary" + return (mask1 + mask2).clamp(0, 1) + +def time_stretch_mask( + x: torch.Tensor, + stretch_factor: int, +): + assert stretch_factor >= 1, "stretch factor must be >= 1" + c_seq_len = x.shape[-1] + x = x.repeat_interleave(stretch_factor, dim=-1) + + # trim cz to the original length + x = x[:, :, :c_seq_len] + + mask = periodic_mask(x, stretch_factor, width=1) + return mask + +def onset_mask( + onset_frame_idxs: torch.Tensor, + z: torch.Tensor, + width: int = 1, +): + if len(onset_frame_idxs) == 0: + print("no onsets detected") + # print("onset_frame_idxs", onset_frame_idxs) + # print("mask shape", z.shape) + + mask = torch.ones_like(z).int() + for idx in onset_frame_idxs: + mask[:, :, idx-width:idx+width] = 0 + + return mask.int() + +def tria_mask( + codes: torch.Tensor, + min_amt: float = 0.1, + max_amt: float = 0.4, +): + """ + unmasks a prefix of the codes tensor, + in the range provided + """ + + mask = full_mask(codes) + nb, nc, nt = codes.shape + for i in range(nb): + amt = torch.rand(1) * (max_amt - min_amt) + min_amt + amt = int(amt * nt) + mask[i, :, :amt] = 0 + + return mask + + + + + + +if __name__ == "__main__": + sig = AudioSignal("assets/example.wav") diff --git a/vampnet/scheduler.py b/vampnet/scheduler.py new file mode 100644 index 0000000000000000000000000000000000000000..a57108c2af7c974d882b45e092907195ded71c9a --- /dev/null +++ b/vampnet/scheduler.py @@ -0,0 +1,47 @@ +import copy +from typing import List + +import torch + +class NoamScheduler: + """OG scheduler from transformer paper: https://arxiv.org/pdf/1706.03762.pdf + Implementation from Annotated Transformer: https://nlp.seas.harvard.edu/2018/04/03/attention.html + """ + + def __init__( + self, + optimizer: torch.optim.Optimizer, + d_model: int = 512, + factor: float = 1.0, + warmup: int = 4000, + ): + # Store hparams + self.warmup = warmup + self.factor = factor + self.d_model = d_model + + # Initialize variables `lr` and `steps` + self.lr = None + self.steps = 0 + + # Store the optimizer + self.optimizer = optimizer + + def state_dict(self): + return { + key: value for key, value in self.__dict__.items() if key != "optimizer" + } + + def load_state_dict(self, state_dict): + self.__dict__.update(state_dict) + + def step(self): + self.steps += 1 + self.lr = self.factor * ( + self.d_model ** (-0.5) + * min(self.steps ** (-0.5), self.steps * self.warmup ** (-1.5)) + ) + + for p in self.optimizer.param_groups: + p["lr"] = self.lr + diff --git a/vampnet/util.py b/vampnet/util.py new file mode 100644 index 0000000000000000000000000000000000000000..8fbf8fb41f1d2e1c0ad95e959acb5ae8655768f7 --- /dev/null +++ b/vampnet/util.py @@ -0,0 +1,46 @@ +import tqdm + +import torch +from einops import rearrange + +def scalar_to_batch_tensor(x, batch_size): + return torch.tensor(x).repeat(batch_size) + + +def parallelize( + fn, + *iterables, + parallel: str = "thread_map", + **kwargs + ): + if parallel == "thread_map": + from tqdm.contrib.concurrent import thread_map + return thread_map( + fn, + *iterables, + **kwargs + ) + elif parallel == "process_map": + from tqdm.contrib.concurrent import process_map + return process_map( + fn, + *iterables, + **kwargs + ) + elif parallel == "single": + return [fn(x) for x in tqdm.tqdm(*iterables)] + else: + raise ValueError(f"parallel must be one of 'thread_map', 'process_map', 'single', but got {parallel}") + +def codebook_flatten(tokens: torch.Tensor): + """ + flatten a sequence of tokens from (batch, codebook, time) to (batch, codebook * time) + """ + return rearrange(tokens, "b c t -> b (t c)") + +def codebook_unflatten(flat_tokens: torch.Tensor, n_c: int = None): + """ + unflatten a sequence of tokens from (batch, codebook * time) to (batch, codebook, time) + """ + tokens = rearrange(flat_tokens, "b (t c) -> b c t", c=n_c) + return tokens