Lofi_Generator/lib/audio/brassEngine.ts
Avery Felts 0f17775f3f Add multi-genre support and expanded instrument options
- Add 4 genres: Hip Hop, Classical, Trap, Pop with unique patterns
- Add new instrument layers: Bass, Brass, Piano
- Each layer now has 4 instrument variations to choose from
- Add genre-specific drum patterns, chord progressions, and melodies
- Add duration control (1-10 minutes)
- Rename app to "Beat Generator" with modern gradient header
- Redesign UI with 2-column instrument grid layout
- Add color-coded accent for each instrument section

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

121 lines
3.0 KiB
TypeScript

import * as Tone from 'tone';
import { BrassType, Genre } from '@/types/audio';
import { getRandomBrassPattern } from './patterns';
export class BrassEngine {
private synth: Tone.Synth | null = null;
private sequence: Tone.Sequence | null = null;
private pattern: (string | null)[];
private output: Tone.Gain;
private filter: Tone.Filter;
private reverb: Tone.Reverb;
private currentType: BrassType = 'trumpet';
private genre: Genre = 'hiphop';
constructor(destination: Tone.InputNode) {
this.output = new Tone.Gain(0.4);
this.filter = new Tone.Filter({
frequency: 3000,
type: 'lowpass',
rolloff: -12,
});
this.reverb = new Tone.Reverb({
decay: 2,
wet: 0.3,
});
this.filter.connect(this.reverb);
this.reverb.connect(this.output);
this.output.connect(destination);
this.pattern = getRandomBrassPattern(this.genre);
this.createSynth('trumpet');
}
private createSynth(type: BrassType): void {
if (this.synth) {
this.synth.dispose();
}
const configs: Record<BrassType, Partial<Tone.SynthOptions>> = {
trumpet: {
oscillator: { type: 'sawtooth' },
envelope: { attack: 0.05, decay: 0.2, sustain: 0.6, release: 0.3 },
},
horn: {
oscillator: { type: 'sine' },
envelope: { attack: 0.1, decay: 0.3, sustain: 0.7, release: 0.5 },
},
'synth-brass': {
oscillator: { type: 'fatsawtooth', spread: 20, count: 3 } as Tone.OmniOscillatorOptions,
envelope: { attack: 0.02, decay: 0.3, sustain: 0.5, release: 0.2 },
},
orchestra: {
oscillator: { type: 'sawtooth' },
envelope: { attack: 0.15, decay: 0.4, sustain: 0.8, release: 0.6 },
},
};
this.synth = new Tone.Synth(configs[type]);
this.synth.volume.value = -8;
this.synth.connect(this.filter);
this.currentType = type;
}
setInstrument(type: BrassType): void {
this.createSynth(type);
}
setGenre(genre: Genre): void {
this.genre = genre;
this.pattern = getRandomBrassPattern(genre);
if (this.sequence) {
this.createSequence();
}
}
createSequence(): void {
if (this.sequence) {
this.sequence.dispose();
}
const steps = Array.from({ length: 16 }, (_, i) => i);
this.sequence = new Tone.Sequence(
(time, step) => {
const note = this.pattern[step];
if (note && this.synth) {
this.synth.triggerAttackRelease(note, '8n', time, 0.6);
}
},
steps,
'16n'
);
this.sequence.start(0);
}
randomize(): void {
this.pattern = getRandomBrassPattern(this.genre);
if (this.sequence) {
this.createSequence();
}
}
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);
}
dispose(): void {
this.sequence?.dispose();
this.synth?.dispose();
this.filter.dispose();
this.reverb.dispose();
this.output.dispose();
}
}