Lofi_Generator/lib/audio/patterns.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

239 lines
11 KiB
TypeScript

import { DrumPattern, ChordProgression, Genre } from '@/types/audio';
// Genre-specific drum patterns
export const drumPatterns: Record<Genre, DrumPattern[]> = {
hiphop: [
{
kick: [true, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
hihat: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
openhat: [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true],
},
{
kick: [true, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, true],
hihat: [true, true, true, false, true, true, true, false, true, true, true, false, true, true, true, false],
openhat: [false, false, false, true, false, false, false, true, false, false, false, true, false, false, false, false],
},
],
classical: [
{
kick: [true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false],
snare: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
hihat: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
openhat: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
},
{
kick: [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
snare: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
hihat: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
openhat: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false],
},
],
trap: [
{
kick: [true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
hihat: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
openhat: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false],
},
{
kick: [true, false, false, true, false, false, true, false, false, false, true, false, false, true, false, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, true],
hihat: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
openhat: [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true],
},
],
pop: [
{
kick: [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
hihat: [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
openhat: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true],
},
{
kick: [true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false],
snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
hihat: [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
openhat: [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false],
},
],
};
// Genre-specific chord progressions
export const chordProgressions: Record<Genre, ChordProgression[]> = {
hiphop: [
{
name: 'Classic ii-V-I',
chords: [
['D3', 'F3', 'A3', 'C4'],
['G2', 'B2', 'D3', 'F3'],
['C3', 'E3', 'G3', 'B3'],
['C3', 'E3', 'G3', 'B3'],
],
durations: ['2n', '2n', '2n', '2n'],
},
{
name: 'Minor Key Chill',
chords: [
['A2', 'C3', 'E3', 'G3'],
['D3', 'F3', 'A3', 'C4'],
['E2', 'G#2', 'B2', 'D3'],
['A2', 'C3', 'E3', 'G3'],
],
durations: ['2n', '2n', '2n', '2n'],
},
],
classical: [
{
name: 'Romantic',
chords: [
['C3', 'E3', 'G3'],
['F3', 'A3', 'C4'],
['G3', 'B3', 'D4'],
['C3', 'E3', 'G3'],
],
durations: ['1n', '1n', '1n', '1n'],
},
{
name: 'Baroque',
chords: [
['D3', 'F3', 'A3'],
['G2', 'B2', 'D3'],
['C3', 'E3', 'G3'],
['A2', 'C3', 'E3'],
],
durations: ['1n', '1n', '1n', '1n'],
},
],
trap: [
{
name: 'Dark Minor',
chords: [
['A2', 'C3', 'E3'],
['F2', 'A2', 'C3'],
['G2', 'B2', 'D3'],
['E2', 'G#2', 'B2'],
],
durations: ['2n', '2n', '2n', '2n'],
},
{
name: 'Eerie',
chords: [
['D3', 'F3', 'A3'],
['Bb2', 'D3', 'F3'],
['A2', 'C3', 'E3'],
['G2', 'Bb2', 'D3'],
],
durations: ['2n', '2n', '2n', '2n'],
},
],
pop: [
{
name: 'Four Chord Pop',
chords: [
['C3', 'E3', 'G3'],
['G2', 'B2', 'D3'],
['A2', 'C3', 'E3'],
['F2', 'A2', 'C3'],
],
durations: ['1n', '1n', '1n', '1n'],
},
{
name: 'Uplifting',
chords: [
['D3', 'F#3', 'A3'],
['A2', 'C#3', 'E3'],
['B2', 'D3', 'F#3'],
['G2', 'B2', 'D3'],
],
durations: ['1n', '1n', '1n', '1n'],
},
],
};
// Bass patterns by genre
export const bassPatterns: Record<Genre, string[][]> = {
hiphop: [
['C2', null, null, null, 'C2', null, 'G1', null, 'C2', null, null, null, 'E2', null, null, null],
['A1', null, null, 'A1', null, null, 'G1', null, 'A1', null, null, null, 'E1', null, 'G1', null],
],
classical: [
['C2', null, null, null, 'G2', null, null, null, 'C2', null, null, null, 'G2', null, null, null],
['D2', null, null, null, 'A2', null, null, null, 'D2', null, null, null, 'A2', null, null, null],
],
trap: [
['C1', null, null, 'C1', null, null, 'C1', null, null, null, 'G1', null, null, 'C1', null, null],
['A0', null, null, 'A0', null, 'A0', null, null, 'A0', null, null, null, 'E1', null, 'A0', null],
],
pop: [
['C2', null, 'C2', null, 'G2', null, 'G2', null, 'A2', null, 'A2', null, 'F2', null, 'F2', null],
['D2', null, null, 'D2', 'A2', null, null, null, 'B2', null, null, 'B2', 'G2', null, null, null],
],
};
// Brass melody patterns by genre
export const brassPatterns: Record<Genre, string[][]> = {
hiphop: [
['C4', null, null, null, 'E4', null, null, null, 'G4', null, null, null, 'E4', null, null, null],
[null, null, 'D4', null, null, null, 'F4', null, null, null, 'A4', null, null, null, 'G4', null],
],
classical: [
['G4', null, null, null, null, null, null, null, 'E4', null, null, null, null, null, null, null],
['C4', null, null, null, 'D4', null, null, null, 'E4', null, null, null, 'G4', null, null, null],
],
trap: [
['A3', null, null, null, null, null, null, null, 'C4', null, null, null, null, null, null, null],
[null, null, null, null, 'E4', null, null, null, null, null, null, null, 'D4', null, null, null],
],
pop: [
['E4', null, null, null, 'G4', null, null, null, 'A4', null, null, null, 'G4', null, null, null],
['C4', null, 'D4', null, 'E4', null, 'G4', null, 'A4', null, 'G4', null, 'E4', null, 'D4', null],
],
};
// Piano patterns by genre
export const pianoPatterns: Record<Genre, string[][][]> = {
hiphop: [
[['C4', 'E4', 'G4'], null, null, null, ['D4', 'F4', 'A4'], null, null, null, ['E4', 'G4', 'B4'], null, null, null, ['D4', 'F4', 'A4'], null, null, null],
[['A3', 'C4', 'E4'], null, ['A3', 'C4', 'E4'], null, null, null, ['G3', 'B3', 'D4'], null, ['G3', 'B3', 'D4'], null, null, null, ['F3', 'A3', 'C4'], null, null, null],
],
classical: [
[['C4', 'E4', 'G4'], ['E4'], ['G4'], ['C5'], ['G4'], ['E4'], ['C4', 'E4', 'G4'], null, ['D4', 'F4', 'A4'], ['F4'], ['A4'], ['D5'], ['A4'], ['F4'], ['D4', 'F4', 'A4'], null],
[['A3', 'C4', 'E4'], null, ['C4', 'E4'], null, ['A3', 'C4', 'E4'], null, ['C4', 'E4'], null, ['G3', 'B3', 'D4'], null, ['B3', 'D4'], null, ['G3', 'B3', 'D4'], null, null, null],
],
trap: [
[['A3', 'C4', 'E4'], null, null, null, null, null, null, null, ['G3', 'Bb3', 'D4'], null, null, null, null, null, null, null],
[['D4', 'F4', 'A4'], null, null, null, null, null, ['C4', 'E4', 'G4'], null, null, null, null, null, null, null, ['Bb3', 'D4', 'F4'], null],
],
pop: [
[['C4', 'E4', 'G4'], null, ['C4', 'E4', 'G4'], null, ['G3', 'B3', 'D4'], null, ['G3', 'B3', 'D4'], null, ['A3', 'C4', 'E4'], null, ['A3', 'C4', 'E4'], null, ['F3', 'A3', 'C4'], null, ['F3', 'A3', 'C4'], null],
[['D4', 'F#4', 'A4'], null, null, ['D4', 'F#4', 'A4'], ['A3', 'C#4', 'E4'], null, null, ['A3', 'C#4', 'E4'], ['B3', 'D4', 'F#4'], null, null, ['B3', 'D4', 'F#4'], ['G3', 'B3', 'D4'], null, null, null],
],
};
export function getRandomPattern(genre: Genre): DrumPattern {
const patterns = drumPatterns[genre];
return patterns[Math.floor(Math.random() * patterns.length)];
}
export function getRandomProgression(genre: Genre): ChordProgression {
const progressions = chordProgressions[genre];
return progressions[Math.floor(Math.random() * progressions.length)];
}
export function getRandomBassPattern(genre: Genre): (string | null)[] {
const patterns = bassPatterns[genre];
return patterns[Math.floor(Math.random() * patterns.length)];
}
export function getRandomBrassPattern(genre: Genre): (string | null)[] {
const patterns = brassPatterns[genre];
return patterns[Math.floor(Math.random() * patterns.length)];
}
export function getRandomPianoPattern(genre: Genre): (string[] | null)[] {
const patterns = pianoPatterns[genre];
return patterns[Math.floor(Math.random() * patterns.length)];
}