Last active
January 6, 2018 00:00
-
-
Save logue/71233d660cd7bfc6710a9a2ebfa43ab1 to your computer and use it in GitHub Desktop.
AudioContextの勉強のために作った、音にリバーブエフェクトをかけるためのライブラリ。まだ未完成。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file Add reverb effect. | |
* @copyright © 2017,2018 By Logue <http://logue.be/>. | |
* @license MIT | |
* Adapted from https://github.com/web-audio-components/simple-reverb | |
*/ | |
export default class Reverb { | |
private ctx: AudioContext | |
private outputNode: GainNode | |
private wetGainNode: GainNode | |
private dryGainNode: GainNode | |
private convolverNode: ConvolverNode | |
private filterNode: BiquadFilterNode | |
private _cutOff: number | |
private _decay: number | |
private _delay: number | |
private _filterType: BiquadFilterType | |
private _mix: number | |
private _reverse: boolean | |
private _time: number | |
private defaults = { | |
cutOff: 350, | |
decay: 2, | |
delay: 0, | |
filterType: 'lowpass', | |
mix: 0.5, | |
reverse: false, | |
time: 3 | |
}; | |
/** | |
* Add reverb effect. | |
*/ | |
constructor(ctx: AudioContext, options: { | |
cutOff: (number | undefined), | |
decay: (number | undefined), | |
delay: (number | undefined), | |
filterType: (BiquadFilterType | undefined), | |
mix: (number | undefined), | |
reverse: (boolean | undefined), | |
time: (number | undefined) | |
}) { | |
this.ctx = ctx; | |
this.outputNode = this.ctx.createGain(); | |
this.wetGainNode = this.ctx.createGain(); | |
this.dryGainNode = this.ctx.createGain(); | |
this.convolverNode = this.ctx.createConvolver(); | |
this.filterNode = this.ctx.createBiquadFilter(); | |
// エフェクトのかかり方の接続 | |
this.outputNode.connect(this.dryGainNode); | |
this.outputNode.connect(this.wetGainNode); | |
// エフェクトを接続 | |
this.convolverNode.connect(this.filterNode); | |
this.dryGainNode.connect(this.outputNode); | |
this.wetGainNode.connect(this.outputNode); | |
// フィルタを接続 | |
this.filterNode.connect(this.outputNode); | |
// 入力値と初期値をマージする | |
for (let key in this.defaults) { | |
this['_' + key] = (options[key] === undefined) ? | |
this.defaults[key] : options[key]; | |
} | |
// エフェクタに反映 | |
this.dryGainNode.gain.value = this.getDryLevel(this._mix); | |
this.wetGainNode.gain.value = this.getWetLevel(this._mix); | |
this.filterNode.type = this._filterType; | |
this.filterNode.frequency.value = this._cutOff; | |
// インパルス応答を生成 | |
this.BuildImpulse(); | |
} | |
/** | |
* Utility function for building an impulse response | |
* from the module parameters. | |
*/ | |
private BuildImpulse() { | |
const rate: number = this.ctx.sampleRate; | |
const length: number = Math.max(rate * this._time, 1); | |
const delayDuration: number = rate * this._delay; | |
let impulse: AudioBuffer = this.ctx.createBuffer(2, length, rate); | |
let impulseL: Float32Array = new Float32Array(length); | |
let impulseR: Float32Array = new Float32Array(length); | |
for (let i: number = 0; i < length; i++) { | |
let n: number, pow: number; | |
if (i < delayDuration) { | |
// Delay Effect | |
impulseL[i] = 0; | |
impulseR[i] = 0; | |
} else { | |
n = this._reverse ? length - (i - delayDuration) : i - delayDuration; | |
n = this._reverse ? length - i : i; | |
pow = Math.pow(1 - n / length, this._decay); | |
impulseL[i] = (Math.random() * 2 - 1) * pow; | |
impulseR[i] = (Math.random() * 2 - 1) * pow; | |
} | |
n = this._reverse ? length - (i - delayDuration) : i - delayDuration; | |
pow = Math.pow(1 - n / length, this._decay); | |
impulseL[i] = (Math.random() * 2 - 1) * pow; | |
impulseR[i] = (Math.random() * 2 - 1) * pow; | |
} | |
impulse.getChannelData(0).set(impulseL); | |
impulse.getChannelData(1).set(impulseR); | |
console.info('Update impulse responce.'); | |
this.convolverNode.buffer = impulse; | |
} | |
public connect(destinationNode: AudioNode) { | |
console.info('Connect Reverb.'); | |
this.outputNode.connect(destinationNode); | |
} | |
public disconnect(no: number) { | |
console.info('Disconnect Reverb.'); | |
this.outputNode.disconnect(no); | |
} | |
public mix(mix: number) { | |
this._mix = mix; | |
this.dryGainNode.gain.value = this.getDryLevel(mix); | |
this.wetGainNode.gain.value = this.getWetLevel(mix); | |
} | |
public time(time: number) { | |
this._time = time; | |
this.BuildImpulse(); | |
} | |
/** | |
* Impulse response decay rate. | |
*/ | |
public decay(decay: number) { | |
this._decay = decay; | |
this.BuildImpulse(); | |
} | |
/** | |
* Impulse response decay rate. | |
*/ | |
public delay(delay: number) { | |
this._delay = delay; | |
this.BuildImpulse(); | |
} | |
/** | |
* Reverse the impulse response. | |
*/ | |
public reverse(reverse: boolean) { | |
this._reverse = reverse; | |
this.BuildImpulse(); | |
} | |
/** | |
* Cut off frequency. | |
*/ | |
public cutOff(freq: number) { | |
this.filterNode.frequency.value = this._cutOff = freq; | |
} | |
/** | |
* Filter Type. | |
*/ | |
public filterType(type: BiquadFilterType) { | |
this.filterNode.type = this._filterType = type; | |
}; | |
private getDryLevel(value: number): number { | |
if (value > 1 || value < 0) { | |
return 0; | |
} | |
if (value <= 0.5) | |
return 1; | |
return 1 - ((value - 0.5) * 2); | |
}; | |
private getWetLevel(value: number): number { | |
if (value > 1 || value < 0) { | |
return 0; | |
} | |
if (value >= 0.5) | |
return 1; | |
return 1 - ((value - 0.5) * 2); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
インパルス応答(impulse response)のWAVファイルってライセンスがあやふやなのって多いじゃん。
だったら、自分で作っちゃえばいいっしょ。