Tone.js/Tone/component/PhaseShiftAllpass.js
2019-08-01 11:48:06 +02:00

145 lines
4.5 KiB
JavaScript

import Tone from "../core/Tone";
import "../core/AudioNode";
/**
* @class Tone.PhaseShiftAllpass is an very efficient implementation of a Hilbert Transform
* using two Allpass filter banks whose outputs have a phase difference of 90°.
* Here the `output[1]` phase is offset by +90° in relation to `output[0]`.
* Coefficients and structure was developed by Olli Niemitalo.
* For more details see: http://yehar.com/blog/?p=368
*
* @extends {Tone.AudioNode}
*/
Tone.PhaseShiftAllpass = function(){
Tone.AudioNode.call(this);
this.createInsOuts(1, 2);
for (var i = 0; i < 2; i++){
this.output[i] = new Tone.Gain();
this.output[i].channelCount = 1;
this.output[i].channelCountMode = "explicit";
}
const allpassBank1Values = [0.6923878, 0.9360654322959, 0.9882295226860, 0.9987488452737];
const allpassBank2Values = [0.4021921162426, 0.8561710882420, 0.9722909545651, 0.9952884791278];
function createAllpassCoefficients(value){
return [[value * value, 0, -1], [1, 0, -(value * value)]];
}
/**
* The first Allpass filter of the first bank
* @type {IIRFilterNode}
* @private
*/
let coefficients = createAllpassCoefficients(allpassBank1Values[0]);
this._firstBankAP0 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The second Allpass filter of the first bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank1Values[1]);
this._firstBankAP1 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The third Allpass filter of the first bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank1Values[2]);
this._firstBankAP2 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The forth Allpass filter of the first bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank1Values[3]);
this._firstBankAP3 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* A IIR filter implementing a delay by one sample used by the first bank
* @type {IIRFilterNode}
* @private
*/
this._oneSampleDelay = Tone.context.createIIRFilter([0.0, 1.0], [1.0, 0.0]);
/**
* The first Allpass filter of the second bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank2Values[0]);
this._secondBankAP0 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The second Allpass filter of the second bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank2Values[1]);
this._secondBankAP1 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The third Allpass filter of the second bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank2Values[2]);
this._secondBankAP2 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
/**
* The forth Allpass filter of the second bank
* @type {IIRFilterNode}
* @private
*/
coefficients = createAllpassCoefficients(allpassBank2Values[3]);
this._secondBankAP3 = Tone.context.createIIRFilter(coefficients[0], coefficients[1]);
// connect Allpass filter banks
Tone.connect(this.input, this._firstBankAP0);
Tone.connect(this.input, this._secondBankAP0);
Tone.connectSeries(this._firstBankAP0, this._firstBankAP1, this._firstBankAP2, this._firstBankAP3, this._oneSampleDelay, this.output[0]);
Tone.connectSeries(this._secondBankAP0, this._secondBankAP1, this._secondBankAP2, this._secondBankAP3, this.output[1]);
};
Tone.extend(Tone.PhaseShiftAllpass, Tone.AudioNode);
/**
* Clean up.
* @return {Tone.PhaseShiftAllpass} this
*/
Tone.PhaseShiftAllpass.prototype.dispose = function(){
this.output[0].dispose();
this.output[0] = null;
this.output[1].dispose();
this.output[1] = null;
Tone.AudioNode.prototype.dispose.call(this);
this._firstBankAP0.disconnect();
this._firstBankAP0 = null;
this._firstBankAP1.disconnect();
this._firstBankAP1 = null;
this._firstBankAP2.disconnect();
this._firstBankAP2 = null;
this._firstBankAP3.disconnect();
this._firstBankAP3 = null;
this._secondBankAP0.disconnect();
this._secondBankAP0 = null;
this._secondBankAP1.disconnect();
this._secondBankAP1 = null;
this._secondBankAP2.disconnect();
this._secondBankAP2 = null;
this._secondBankAP3.disconnect();
this._secondBankAP3 = null;
this._oneSampleDelay.disconnect();
this._oneSampleDelay = null;
return this;
};
export default Tone.PhaseShiftAllpass;