@hlysine/piano
Version:
Web Audio instrument using Salamander Grand Piano samples
78 lines (65 loc) • 1.76 kB
text/typescript
import { ToneAudioBuffers, ToneBufferSource } from 'tone'
import { PianoComponent, PianoComponentOptions } from './Component'
import { randomBetween } from './Util'
export class Pedal extends PianoComponent {
private _downTime: number = Infinity
private _currentSound: ToneBufferSource = null
private _buffers: ToneAudioBuffers
constructor(options: PianoComponentOptions) {
super(options)
this._downTime = Infinity
}
protected _internalLoad(): Promise<void> {
return new Promise((success) => {
this._buffers = new ToneAudioBuffers({
down1: 'pedalD1.mp3',
down2: 'pedalD2.mp3',
up1: 'pedalU1.mp3',
up2: 'pedalU2.mp3',
}, success, this.samples)
})
}
/**
* Squash the current playing sound
*/
private _squash(time: number): void {
if (this._currentSound && this._currentSound.state !== 'stopped') {
this._currentSound.stop(time)
}
this._currentSound = null
}
private _playSample(time: number, dir: 'down' | 'up'): void {
if (this._enabled) {
this._currentSound = new ToneBufferSource({
url: this._buffers.get(`${dir}${Math.random() > 0.5 ? 1 : 2}`),
context: this.context,
curve: 'exponential',
fadeIn: 0.05,
fadeOut: 0.1,
}).connect(this.output)
this._currentSound.start(time, randomBetween(0, 0.01), undefined, 0.1 * randomBetween(0.5, 1))
}
}
/**
* Put the pedal down
*/
down(time: number): void {
this._squash(time)
this._downTime = time
this._playSample(time, 'down')
}
/**
* Put the pedal up
*/
up(time: number): void {
this._squash(time)
this._downTime = Infinity
this._playSample(time, 'up')
}
/**
* Indicates if the pedal is down at the given time
*/
isDown(time: number): boolean {
return time > this._downTime
}
}