WIP
This commit is contained in:
parent
34ac200437
commit
39b0160064
136 changed files with 7129 additions and 1950 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { appConfig } from '../config';
|
||||
import { clamp } from '../utils/clamp';
|
||||
import { GardenAudioConfig, GardenAudioVibeProfile } from './garden-audio-config';
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ export class GardenAudioGraph {
|
|||
private delayNode: DelayNode | null = null;
|
||||
private delayFeedback: GainNode | null = null;
|
||||
private delayOutput: GainNode | null = null;
|
||||
private hasUnlocked = false;
|
||||
|
||||
public constructor(private readonly config: GardenAudioConfig) {}
|
||||
|
||||
|
|
@ -50,6 +52,26 @@ export class GardenAudioGraph {
|
|||
return context;
|
||||
}
|
||||
|
||||
// iOS WebKit (Safari + Chrome iOS) only fully unlocks audio output once
|
||||
// a buffer source has been started inside a user-gesture handler. Calling
|
||||
// resume() alone leaves the context "running" but silent.
|
||||
public unlock(): void {
|
||||
if (!this.context || this.hasUnlocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
const buffer = this.context.createBuffer(
|
||||
1,
|
||||
appConfig.audioEngine.graph.unlockBufferLength,
|
||||
appConfig.audioEngine.graph.unlockSampleRate
|
||||
);
|
||||
const source = this.context.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.connect(this.context.destination);
|
||||
source.start(0);
|
||||
this.hasUnlocked = true;
|
||||
}
|
||||
|
||||
public setMasterGain(targetGain: number, timeConstantSeconds: number): void {
|
||||
if (!this.context || !this.masterGain) {
|
||||
return;
|
||||
|
|
@ -70,7 +92,7 @@ export class GardenAudioGraph {
|
|||
this.delayNode.delayTime.setTargetAtTime(
|
||||
this.config.delay.timeSeconds * profile.delayTimeMultiplier,
|
||||
this.context.currentTime,
|
||||
0.12
|
||||
appConfig.audioEngine.graph.delayTimeRampSeconds
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -83,17 +105,22 @@ export class GardenAudioGraph {
|
|||
this.delayNode.delayTime.setTargetAtTime(
|
||||
this.config.delay.timeSeconds * profile.delayTimeMultiplier,
|
||||
now,
|
||||
0.12
|
||||
appConfig.audioEngine.graph.delayTimeRampSeconds
|
||||
);
|
||||
this.delayFeedback.gain.setTargetAtTime(
|
||||
this.config.delay.enabled
|
||||
? clamp(this.config.delay.feedback + activity * 0.08, 0.04, 0.32)
|
||||
: 0,
|
||||
clamp(
|
||||
this.config.delay.feedback +
|
||||
activity * appConfig.audioEngine.graph.delayActivityFeedbackWeight,
|
||||
appConfig.audioEngine.graph.delayFeedbackMin,
|
||||
appConfig.audioEngine.graph.delayFeedbackMax
|
||||
),
|
||||
now,
|
||||
this.config.updateRampSeconds
|
||||
);
|
||||
this.delayOutput.gain.setTargetAtTime(
|
||||
this.config.delay.enabled ? this.config.delay.wetGain * (0.65 + activity * 0.5) : 0,
|
||||
this.config.delay.wetGain *
|
||||
(appConfig.audioEngine.graph.delayOutputBase +
|
||||
activity * appConfig.audioEngine.graph.delayOutputActivityWeight),
|
||||
now,
|
||||
this.config.updateRampSeconds
|
||||
);
|
||||
|
|
@ -106,7 +133,11 @@ export class GardenAudioGraph {
|
|||
}
|
||||
|
||||
if (this.masterGain && context.state !== 'closed') {
|
||||
this.masterGain.gain.setTargetAtTime(0.0001, context.currentTime, 0.015);
|
||||
this.masterGain.gain.setTargetAtTime(
|
||||
appConfig.audioEngine.graph.closeGain,
|
||||
context.currentTime,
|
||||
appConfig.audioEngine.graph.closeRampSeconds
|
||||
);
|
||||
}
|
||||
|
||||
this.clearNodes();
|
||||
|
|
@ -123,8 +154,8 @@ export class GardenAudioGraph {
|
|||
const delayOutput = context.createGain();
|
||||
|
||||
delayNode.delayTime.value = this.config.delay.timeSeconds;
|
||||
delayFeedback.gain.value = this.config.delay.enabled ? this.config.delay.feedback : 0;
|
||||
delayOutput.gain.value = this.config.delay.enabled ? this.config.delay.wetGain : 0;
|
||||
delayFeedback.gain.value = this.config.delay.feedback;
|
||||
delayOutput.gain.value = this.config.delay.wetGain;
|
||||
|
||||
delayInput.connect(delayNode);
|
||||
delayNode.connect(delayFeedback);
|
||||
|
|
@ -140,7 +171,7 @@ export class GardenAudioGraph {
|
|||
|
||||
private createBuses(context: AudioContext, masterGain: GainNode): void {
|
||||
this.eventBus = context.createGain();
|
||||
this.eventBus.gain.value = 1;
|
||||
this.eventBus.gain.value = appConfig.audioEngine.graph.eventBusGain;
|
||||
this.eventBus.connect(masterGain);
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +180,10 @@ export class GardenAudioGraph {
|
|||
const data = buffer.getChannelData(0);
|
||||
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
data[index] = Math.random() * 2 - 1;
|
||||
data[index] =
|
||||
appConfig.audioEngine.graph.noiseMin +
|
||||
Math.random() *
|
||||
(appConfig.audioEngine.graph.noiseMax - appConfig.audioEngine.graph.noiseMin);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
|
|
@ -164,5 +198,6 @@ export class GardenAudioGraph {
|
|||
this.delayNode = null;
|
||||
this.delayFeedback = null;
|
||||
this.delayOutput = null;
|
||||
this.hasUnlocked = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue