mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 00:27:58 +00:00
converting Channel to ts
This commit is contained in:
parent
68a7bb03ec
commit
28c078dcad
4 changed files with 191 additions and 136 deletions
|
@ -1,136 +0,0 @@
|
||||||
import Tone from "../../core/Tone";
|
|
||||||
import "../PanVol";
|
|
||||||
import "../component/Solo";
|
|
||||||
import "../core/AudioNode";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Tone.Channel provides a channel strip interface with
|
|
||||||
* volume, pan, solo and mute controls.
|
|
||||||
*
|
|
||||||
* @extends {Tone.AudioNode}
|
|
||||||
* @constructor
|
|
||||||
* @param {Decibels} volume The output volume.
|
|
||||||
* @param {AudioRange} pan the initial pan
|
|
||||||
* @example
|
|
||||||
* //pan the incoming signal left and drop the volume
|
|
||||||
* var channel = new Tone.Channel(-0.25, -12);
|
|
||||||
*/
|
|
||||||
Tone.Channel = function(){
|
|
||||||
|
|
||||||
var options = Tone.defaults(arguments, ["volume", "pan"], Tone.PanVol);
|
|
||||||
Tone.AudioNode.call(this, options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The soloing interface
|
|
||||||
* @type {Tone.Solo}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._solo = this.input = new Tone.Solo(options.solo);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The panning and volume node
|
|
||||||
* @type {Tone.PanVol}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._panVol = this.output = new Tone.PanVol({
|
|
||||||
"pan" : options.pan,
|
|
||||||
"volume" : options.volume,
|
|
||||||
"mute" : options.mute
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The L/R panning control.
|
|
||||||
* @type {AudioRange}
|
|
||||||
* @signal
|
|
||||||
*/
|
|
||||||
this.pan = this._panVol.pan;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The volume control in decibels.
|
|
||||||
* @type {Decibels}
|
|
||||||
* @signal
|
|
||||||
*/
|
|
||||||
this.volume = this._panVol.volume;
|
|
||||||
|
|
||||||
this._solo.connect(this._panVol);
|
|
||||||
this._readOnly(["pan", "volume"]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Tone.extend(Tone.Channel, Tone.AudioNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The defaults
|
|
||||||
* @type {Object}
|
|
||||||
* @const
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
Tone.Channel.defaults = {
|
|
||||||
"pan" : 0,
|
|
||||||
"volume" : 0,
|
|
||||||
"mute" : false,
|
|
||||||
"solo" : false
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Solo/unsolo the channel. Soloing is only relative to other
|
|
||||||
* Tone.Channels and Tone.Solos.
|
|
||||||
* @memberOf Tone.Channel#
|
|
||||||
* @name solo
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
Object.defineProperty(Tone.Channel.prototype, "solo", {
|
|
||||||
get : function(){
|
|
||||||
return this._solo.solo;
|
|
||||||
},
|
|
||||||
set : function(solo){
|
|
||||||
this._solo.solo = solo;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the current instance is muted, i.e. another instance is soloed,
|
|
||||||
* or the channel is muted
|
|
||||||
* @memberOf Tone.Channel#
|
|
||||||
* @type {Boolean}
|
|
||||||
* @name muted
|
|
||||||
* @readOnly
|
|
||||||
*/
|
|
||||||
Object.defineProperty(Tone.Channel.prototype, "muted", {
|
|
||||||
get : function(){
|
|
||||||
return this._solo.muted || this.mute;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mute/unmute the volume
|
|
||||||
* @memberOf Tone.Channel#
|
|
||||||
* @name mute
|
|
||||||
* @type {Boolean}
|
|
||||||
*/
|
|
||||||
Object.defineProperty(Tone.Channel.prototype, "mute", {
|
|
||||||
get : function(){
|
|
||||||
return this._panVol.mute;
|
|
||||||
},
|
|
||||||
set : function(mute){
|
|
||||||
this._panVol.mute = mute;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* clean up
|
|
||||||
* @returns {Tone.Channel} this
|
|
||||||
*/
|
|
||||||
Tone.Channel.prototype.dispose = function(){
|
|
||||||
Tone.AudioNode.prototype.dispose.call(this);
|
|
||||||
this._writable(["pan", "volume"]);
|
|
||||||
this._panVol.dispose();
|
|
||||||
this._panVol = null;
|
|
||||||
this.pan = null;
|
|
||||||
this.volume = null;
|
|
||||||
this._solo.dispose();
|
|
||||||
this._solo = null;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Tone.Channel;
|
|
||||||
|
|
65
Tone/component/channel/Channel.test.ts
Normal file
65
Tone/component/channel/Channel.test.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { Channel } from "./Channel";
|
||||||
|
import { BasicTests } from "test/helper/Basic";
|
||||||
|
import { PassAudio } from "test/helper/PassAudio";
|
||||||
|
import { Signal } from "Tone/signal/Signal";
|
||||||
|
import { Offline } from "test/helper/Offline";
|
||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
describe("Channel", () => {
|
||||||
|
|
||||||
|
BasicTests(Channel);
|
||||||
|
|
||||||
|
context("Channel", () => {
|
||||||
|
|
||||||
|
it("can pass volume and panning into the constructor", () => {
|
||||||
|
const channel = new Channel(-10, -1);
|
||||||
|
expect(channel.pan.value).to.be.closeTo(-1, 0.01);
|
||||||
|
expect(channel.volume.value).to.be.closeTo(-10, 0.01);
|
||||||
|
channel.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can pass in an object into the constructor", () => {
|
||||||
|
const channel = new Channel({
|
||||||
|
pan: 1,
|
||||||
|
volume: 6,
|
||||||
|
mute: false,
|
||||||
|
solo: true
|
||||||
|
});
|
||||||
|
expect(channel.pan.value).to.be.closeTo(1, 0.01);
|
||||||
|
expect(channel.volume.value).to.be.closeTo(6, 0.01);
|
||||||
|
expect(channel.mute).to.be.false;
|
||||||
|
expect(channel.solo).to.be.true;
|
||||||
|
channel.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes the incoming signal through", () => {
|
||||||
|
return PassAudio((input) => {
|
||||||
|
const channel = new Channel().toDestination();
|
||||||
|
input.connect(channel);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can mute the input", () => {
|
||||||
|
return Offline(() => {
|
||||||
|
const channel = new Channel(0).toDestination();
|
||||||
|
new Signal(1).connect(channel);
|
||||||
|
channel.mute = true;
|
||||||
|
}).then((buffer) => {
|
||||||
|
expect(buffer.isSilent()).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports itself as muted when either muted or another channel is soloed", () => {
|
||||||
|
const channelA = new Channel();
|
||||||
|
const channelB = new Channel();
|
||||||
|
channelB.solo = true;
|
||||||
|
expect(channelA.muted).to.be.true;
|
||||||
|
expect(channelB.muted).to.be.false;
|
||||||
|
channelB.mute = true;
|
||||||
|
expect(channelA.muted).to.be.true;
|
||||||
|
expect(channelB.muted).to.be.true;
|
||||||
|
channelA.dispose();
|
||||||
|
channelB.dispose();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
123
Tone/component/channel/Channel.ts
Normal file
123
Tone/component/channel/Channel.ts
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import { AudioRange, Decibels } from "../../core/type/Units";
|
||||||
|
import { InputNode, OutputNode, ToneAudioNode, ToneAudioNodeOptions } from "../../core/context/ToneAudioNode";
|
||||||
|
import { optionsFromArguments } from "../../core/util/Defaults";
|
||||||
|
import { Solo } from "./Solo";
|
||||||
|
import { PanVol } from "./PanVol";
|
||||||
|
import { Param } from "../../core/context/Param";
|
||||||
|
import { readOnly } from "../../core/util/Interface";
|
||||||
|
|
||||||
|
export interface ChannelOptions extends ToneAudioNodeOptions {
|
||||||
|
pan: AudioRange;
|
||||||
|
volume: Decibels;
|
||||||
|
solo: boolean;
|
||||||
|
mute: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Channel provides a channel strip interface with volume, pan, solo and mute controls.
|
||||||
|
* See [[PanVol]] and [[Solo]]
|
||||||
|
* @example
|
||||||
|
* import { Channel } from "tone";
|
||||||
|
* // pan the incoming signal left and drop the volume 12db
|
||||||
|
* const channel = new Channel(-0.25, -12);
|
||||||
|
*/
|
||||||
|
export class Channel extends ToneAudioNode<ChannelOptions> {
|
||||||
|
|
||||||
|
readonly name: string = "Channel";
|
||||||
|
|
||||||
|
readonly input: InputNode;
|
||||||
|
readonly output: OutputNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The soloing interface
|
||||||
|
*/
|
||||||
|
private _solo: Solo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The panning and volume node
|
||||||
|
*/
|
||||||
|
private _panVol: PanVol;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The L/R panning control.
|
||||||
|
*/
|
||||||
|
readonly pan: Param<"audioRange">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The volume control in decibels.
|
||||||
|
*/
|
||||||
|
readonly volume: Param<"decibels">;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param volume The output volume.
|
||||||
|
* @param pan the initial pan
|
||||||
|
*/
|
||||||
|
constructor(volume?: Decibels, pan?: AudioRange);
|
||||||
|
constructor(options?: Partial<ChannelOptions>);
|
||||||
|
constructor() {
|
||||||
|
super(optionsFromArguments(Channel.getDefaults(), arguments, ["volume", "pan"]));
|
||||||
|
const options = optionsFromArguments(Channel.getDefaults(), arguments, ["volume", "pan"]);
|
||||||
|
|
||||||
|
this._solo = this.input = new Solo({
|
||||||
|
solo: options.solo,
|
||||||
|
context: this.context,
|
||||||
|
});
|
||||||
|
this._panVol = this.output = new PanVol({
|
||||||
|
context: this.context,
|
||||||
|
pan: options.pan,
|
||||||
|
volume: options.volume,
|
||||||
|
mute: options.mute,
|
||||||
|
});
|
||||||
|
this.pan = this._panVol.pan;
|
||||||
|
this.volume = this._panVol.volume;
|
||||||
|
|
||||||
|
this._solo.connect(this._panVol);
|
||||||
|
readOnly(this, ["pan", "volume"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaults(): ChannelOptions {
|
||||||
|
return Object.assign(ToneAudioNode.getDefaults(), {
|
||||||
|
pan: 0,
|
||||||
|
volume: 0,
|
||||||
|
mute: false,
|
||||||
|
solo: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solo/unsolo the channel. Soloing is only relative to other [[Channels]] and [[Solo]] instances
|
||||||
|
*/
|
||||||
|
get solo(): boolean {
|
||||||
|
return this._solo.solo;
|
||||||
|
}
|
||||||
|
set solo(solo) {
|
||||||
|
this._solo.solo = solo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the current instance is muted, i.e. another instance is soloed,
|
||||||
|
* or the channel is muted
|
||||||
|
*/
|
||||||
|
get muted(): boolean {
|
||||||
|
return this._solo.muted || this.mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mute/unmute the volume
|
||||||
|
*/
|
||||||
|
get mute(): boolean {
|
||||||
|
return this._panVol.mute;
|
||||||
|
}
|
||||||
|
set mute(mute) {
|
||||||
|
this._panVol.mute = mute;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose(): this {
|
||||||
|
super.dispose();
|
||||||
|
this._panVol.dispose();
|
||||||
|
this.pan.dispose();
|
||||||
|
this.volume.dispose();
|
||||||
|
this._solo.dispose();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,11 @@ export * from "./analysis/FFT";
|
||||||
export * from "./analysis/DCMeter";
|
export * from "./analysis/DCMeter";
|
||||||
export * from "./analysis/Waveform";
|
export * from "./analysis/Waveform";
|
||||||
export * from "./analysis/Follower";
|
export * from "./analysis/Follower";
|
||||||
|
export * from "./channel/Channel";
|
||||||
export * from "./channel/CrossFade";
|
export * from "./channel/CrossFade";
|
||||||
export * from "./channel/Merge";
|
export * from "./channel/Merge";
|
||||||
|
export * from "./channel/MidSideMerge";
|
||||||
|
export * from "./channel/MidSideSplit";
|
||||||
export * from "./channel/MultibandSplit";
|
export * from "./channel/MultibandSplit";
|
||||||
export * from "./channel/Panner";
|
export * from "./channel/Panner";
|
||||||
export * from "./channel/PanVol";
|
export * from "./channel/PanVol";
|
||||||
|
|
Loading…
Reference in a new issue