Tonejs / Tone.js

A Web Audio framework for making interactive music in the browser.
https://tonejs.github.io
MIT License
13.37k stars 976 forks source link

Tone.Channel `send` and `receive` #1157

Closed stevebarakat closed 4 months ago

stevebarakat commented 1 year ago

When using a Tone.Channel's send and receive, is there a way to unsend? Similar to how connect and disconnect work?

jdanford commented 1 year ago

Channel.send() creates and returns a new Gain node, so it looks like calling .dispose() on that node will do the trick

stevebarakat commented 1 year ago

Yes, but I don't want to dispose it. I want to disconnect it so I can send it to a different channel.

With connect and disconnect you can connect a channel to a reverb then disconnect it from the reverb and connect it to a delay. That can be done on the fly, while the transport is playing. If I try to do that with send, I end up with the reverb and delay because there is no way to disconnect the reverb. Is there a way to re-create that node after it's disposed?

jdanford commented 1 year ago

Is there a reason you can't disconnect the returned node and call Channel.send() again with a different destination? I don't get the impression creating the Gain nodes is particularly expensive, or is there another issue?

Anyway, here's the whole method, so if you really want to reuse the returned node from the first send() call then you can disconnect it and connect it to the other bus, but that involves a private method so it's not best to rely on that.

send(name: string, volume: Decibels = 0): Gain<"decibels"> {
    const bus = this._getBus(name);
    const sendKnob = new Gain({
        context: this.context,
        units: "decibels",
        gain: volume,
    });
    this.connect(sendKnob);
    sendKnob.connect(bus);
    return sendKnob;
}
stevebarakat commented 1 year ago

@jdanford Do you mean doing channel.send.disconnect()?

jdanford commented 1 year ago

If you absolutely have to use the same node, something like this:

const sendNode = channel.send("reverb");
sendNode.disconnect();
const bus = channel._getBus("delay");
sendNode.connect(bus);

But if you don't want to rely on private methods that might change, this should do the trick:

const reverbSend = channel.send("reverb");
reverbSend.dispose();
const delaySend = channel.send("delay");
stevebarakat commented 1 year ago

Okay. I'll give that a shot and update you with the results. Thanks for the help!

stevebarakat commented 1 year ago

@jdanford When I try to do that I get a TypeScript error about dispose not being a property of reverbSend. Maybe I'm doing it wrong? I made a sandbox - https://stackblitz.com/edit/github-pxbyoa?file=src/components/Channels/ChannelStrip.tsx

jdanford commented 1 year ago

Okay so I don't have any experience with channels myself, I'm just reading the docs/code, but AFAICT they're for when your code is more spread out and you can't refer directly to other nodes. If you want to use channels, I think it would be something like this:

const reverb = new Reverb(3).toDestination();
const delay = new FeedbackDelay(5).toDestination();

const reverbChannel = new Channel({ volume: 0 });
const delayChannel = new Channel({ volume: 0 });

reverbChannel.connect(reverb);
delayChannel.connect(delay);

// assigns channel name, only needs to be called once
reverbChannel.receive("reverb");
delayChannel.receive("delay");

// keep this in state, a ref, etc.
let sendNode: GainNode | null = null;

// send to reverb
sendNode = channel.send("reverb"); 

// adjust send amount
sendNode.gain.value = 0.5;

// unsend to reverb, send to delay
sendNode.dispose();
sendNode = channel.send("delay");

// send nowhere
sendNode.dispose();
sendNode = null;
stevebarakat commented 1 year ago

Okay. I'll give that a shot. Thanks!