import Tone from 'tone' import output from './output' import { clamp, choice } from './util' const SPEED_OF_SOUND = 0.0029154519 // ms/m const farReverb = new Tone.Freeverb({ roomSize: 0.5, dampening: 6000, }).connect(output) const nearReverb = new Tone.Freeverb({ roomSize: 0.2, dampening: 12000, }).connect(output) function db_per_meter(distance){ return 1+20*(Math.log(1/distance)/Math.log(10)) } function db_to_percentage(db){ return Math.pow(10, db/10) } class Hall { constructor(props) { let speakers = this.speakers = [] let gain, gainEl let delay, delayEl, z for (let i = 0; i < props.speakers; i++) { speakers.push(new Speaker({ speakers: props.speakers, length: props.length, i: i, })) } } getSpeaker(i){ if (i < 1 && i !== 0) { i *= this.speakers.length } return this.speakers[Math.floor(i) % this.speakers.length] } play(sound, i, freq, pan, time){ const speaker = this.getSpeaker(i) sound.play(freq, time || 0, pan < 0.5 ? speaker.panLeft : speaker.panRight) return speaker } } class Speaker { constructor(props){ this.z = props.length * (props.i + 0.5) / props.speakers this.x = 3 this.input = new Tone.Gain() this.panLeft = new Tone.Panner3D() this.panLeft.updatePosition({ position: { x: this.x, y: 0, z: this.z } }) this.panRight = new Tone.Panner3D() this.panRight.updatePosition({ position: { x: -this.x, y: 0, z: this.z } }) this.dryOutput = new Tone.Gain () this.nearOutput = new Tone.Gain () this.farOutput = new Tone.Gain () this.panLeft.connect(this.dryOutput) this.panLeft.connect(this.nearOutput) this.panLeft.connect(this.farOutput) this.panRight.connect(this.dryOutput) this.panRight.connect(this.nearOutput) this.panRight.connect(this.farOutput) this.input.connect(this.dryOutput) this.input.connect(this.nearOutput) this.input.connect(this.farOutput) this.dryOutput.connect(output) this.nearOutput.connect(nearReverb) this.farOutput.connect(farReverb) reposition(props) } reposition(props){ const reverb_z = props.length * (1 + ((props.i + 0.5) / props.speakers)) const z_db = db_per_meter(z) const reverb_db = db_per_meter(reverb_z) this.z = z this.pan = Math.atan(3/this.z) this.panLeft.pan.value = -this.pan this.panRight.pan.value = this.pan this.gain = db_to_percentage(z_db + 8) this.reverbGain = db_to_percentage(reverb_db + 15) this.delay = z * SPEED_OF_SOUND console.log(z, this.gain.toFixed(4), this.reverbGain.toFixed(4), this.pan) this.dryOutput.gain.value = this.gain this.wetOutput.gain.value = this.reverbGain } } export { Hall, Speaker }