Lofi_Generator/lib/audio/ambientLayer.ts
Avery Felts 5ed84192d5 Implement lofi hip hop generator with Tone.js
- Set up Next.js project with shadcn/ui and Tailwind CSS
- Created audio engine with MembraneSynth drums, FMSynth chords, and ambient noise layers
- Implemented 16-step drum sequencer with boom bap patterns
- Added jazz chord progressions (ii-V-I, minor key, neo soul)
- Built React hook for audio state management
- Created UI components: transport controls, volume sliders, layer mixer, beat visualizer
- Applied lofi-themed dark color scheme with oklch colors

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 17:29:28 -07:00

98 lines
2.4 KiB
TypeScript

import * as Tone from 'tone';
export class AmbientLayer {
private rainNoise: Tone.Noise;
private vinylNoise: Tone.Noise;
private rainFilter: Tone.Filter;
private vinylFilter: Tone.Filter;
private rainGain: Tone.Gain;
private vinylGain: Tone.Gain;
private output: Tone.Gain;
private lfo: Tone.LFO;
constructor(destination: Tone.InputNode) {
this.output = new Tone.Gain(0.4);
// Rain sound - filtered pink noise
this.rainNoise = new Tone.Noise('pink');
this.rainFilter = new Tone.Filter({
frequency: 3000,
type: 'lowpass',
rolloff: -24,
});
this.rainGain = new Tone.Gain(0.15);
// Vinyl crackle - filtered brown noise with modulation
this.vinylNoise = new Tone.Noise('brown');
this.vinylFilter = new Tone.Filter({
frequency: 1500,
type: 'bandpass',
Q: 2,
});
this.vinylGain = new Tone.Gain(0.1);
// LFO for subtle rain intensity variation
this.lfo = new Tone.LFO({
frequency: 0.1,
min: 0.1,
max: 0.2,
});
this.lfo.connect(this.rainGain.gain);
// Chain rain: noise -> filter -> gain -> output
this.rainNoise.connect(this.rainFilter);
this.rainFilter.connect(this.rainGain);
this.rainGain.connect(this.output);
// Chain vinyl: noise -> filter -> gain -> output
this.vinylNoise.connect(this.vinylFilter);
this.vinylFilter.connect(this.vinylGain);
this.vinylGain.connect(this.output);
// Output to destination
this.output.connect(destination);
}
start(): void {
this.rainNoise.start();
this.vinylNoise.start();
this.lfo.start();
}
stop(): void {
this.rainNoise.stop();
this.vinylNoise.stop();
this.lfo.stop();
}
setVolume(volume: number): void {
this.output.gain.rampTo(volume, 0.1);
}
mute(muted: boolean): void {
this.output.gain.rampTo(muted ? 0 : 0.4, 0.1);
}
setRainIntensity(intensity: number): void {
this.rainGain.gain.rampTo(intensity * 0.2, 0.5);
}
setVinylIntensity(intensity: number): void {
this.vinylGain.gain.rampTo(intensity * 0.15, 0.5);
}
dispose(): void {
this.rainNoise.stop();
this.vinylNoise.stop();
this.lfo.stop();
this.rainNoise.dispose();
this.vinylNoise.dispose();
this.rainFilter.dispose();
this.vinylFilter.dispose();
this.rainGain.dispose();
this.vinylGain.dispose();
this.lfo.dispose();
this.output.dispose();
}
}