import { Genre, SectionType } from '@/types/audio'; export interface SongSection { type: SectionType; bars: number; instruments: { drums: { active: boolean; volume: number }; bass: { active: boolean; volume: number }; brass: { active: boolean; volume: number }; piano: { active: boolean; volume: number }; chords: { active: boolean; volume: number }; ambient: { active: boolean; volume: number }; }; } export interface SongStructure { sections: SongSection[]; totalBars: number; } // Genre-specific section configurations const sectionConfigs: Record = { intro: { instruments: { drums: { active: false, volume: 0 }, bass: { active: false, volume: 0 }, brass: { active: false, volume: 0 }, piano: { active: true, volume: 0.3 }, chords: { active: true, volume: 0.4 }, ambient: { active: true, volume: 0.6 }, }, }, verse: { instruments: { drums: { active: true, volume: 0.6 }, bass: { active: true, volume: 0.5 }, brass: { active: false, volume: 0 }, piano: { active: true, volume: 0.4 }, chords: { active: true, volume: 0.5 }, ambient: { active: true, volume: 0.4 }, }, }, bridge: { instruments: { drums: { active: true, volume: 0.4 }, bass: { active: true, volume: 0.4 }, brass: { active: true, volume: 0.3 }, piano: { active: false, volume: 0 }, chords: { active: true, volume: 0.6 }, ambient: { active: true, volume: 0.5 }, }, }, chorus: { instruments: { drums: { active: true, volume: 0.8 }, bass: { active: true, volume: 0.7 }, brass: { active: true, volume: 0.5 }, piano: { active: true, volume: 0.5 }, chords: { active: true, volume: 0.7 }, ambient: { active: true, volume: 0.3 }, }, }, outro: { instruments: { drums: { active: true, volume: 0.3 }, bass: { active: true, volume: 0.3 }, brass: { active: false, volume: 0 }, piano: { active: true, volume: 0.4 }, chords: { active: true, volume: 0.5 }, ambient: { active: true, volume: 0.7 }, }, }, }; // Generate song structure based on duration (in minutes) export function generateSongStructure(durationMinutes: number, bpm: number, genre: Genre): SongStructure { // Calculate total bars based on duration and BPM // 4 beats per bar, so bars = (minutes * bpm) / 4 const totalBars = Math.floor((durationMinutes * bpm) / 4); // Create a standard song structure that fits within the total bars const sections: SongSection[] = []; if (durationMinutes === 1) { // Short format: Intro -> Verse -> Chorus -> Outro const introBars = Math.floor(totalBars * 0.15); const verseBars = Math.floor(totalBars * 0.35); const chorusBars = Math.floor(totalBars * 0.35); const outroBars = totalBars - introBars - verseBars - chorusBars; sections.push({ type: 'intro', bars: introBars, instruments: { ...sectionConfigs.intro.instruments } }); sections.push({ type: 'verse', bars: verseBars, instruments: { ...sectionConfigs.verse.instruments } }); sections.push({ type: 'chorus', bars: chorusBars, instruments: { ...sectionConfigs.chorus.instruments } }); sections.push({ type: 'outro', bars: outroBars, instruments: { ...sectionConfigs.outro.instruments } }); } else if (durationMinutes === 2) { // Medium format: Intro -> Verse -> Bridge -> Chorus -> Outro const introBars = Math.floor(totalBars * 0.1); const verse1Bars = Math.floor(totalBars * 0.25); const bridgeBars = Math.floor(totalBars * 0.15); const chorusBars = Math.floor(totalBars * 0.35); const outroBars = totalBars - introBars - verse1Bars - bridgeBars - chorusBars; sections.push({ type: 'intro', bars: introBars, instruments: { ...sectionConfigs.intro.instruments } }); sections.push({ type: 'verse', bars: verse1Bars, instruments: { ...sectionConfigs.verse.instruments } }); sections.push({ type: 'bridge', bars: bridgeBars, instruments: { ...sectionConfigs.bridge.instruments } }); sections.push({ type: 'chorus', bars: chorusBars, instruments: { ...sectionConfigs.chorus.instruments } }); sections.push({ type: 'outro', bars: outroBars, instruments: { ...sectionConfigs.outro.instruments } }); } else { // Full format (3+ mins): Intro -> Verse -> Chorus -> Verse -> Bridge -> Chorus -> Outro const introBars = Math.floor(totalBars * 0.08); const verse1Bars = Math.floor(totalBars * 0.18); const chorus1Bars = Math.floor(totalBars * 0.18); const verse2Bars = Math.floor(totalBars * 0.15); const bridgeBars = Math.floor(totalBars * 0.12); const chorus2Bars = Math.floor(totalBars * 0.18); const outroBars = totalBars - introBars - verse1Bars - chorus1Bars - verse2Bars - bridgeBars - chorus2Bars; sections.push({ type: 'intro', bars: introBars, instruments: { ...sectionConfigs.intro.instruments } }); sections.push({ type: 'verse', bars: verse1Bars, instruments: { ...sectionConfigs.verse.instruments } }); sections.push({ type: 'chorus', bars: chorus1Bars, instruments: { ...sectionConfigs.chorus.instruments } }); sections.push({ type: 'verse', bars: verse2Bars, instruments: { ...sectionConfigs.verse.instruments } }); sections.push({ type: 'bridge', bars: bridgeBars, instruments: { ...sectionConfigs.bridge.instruments } }); sections.push({ type: 'chorus', bars: chorus2Bars, instruments: { ...sectionConfigs.chorus.instruments } }); sections.push({ type: 'outro', bars: outroBars, instruments: { ...sectionConfigs.outro.instruments } }); } // Apply genre-specific modifications applyGenreModifications(sections, genre); return { sections, totalBars }; } function applyGenreModifications(sections: SongSection[], genre: Genre): void { switch (genre) { case 'trap': // Trap: heavier bass, more brass in chorus sections.forEach(section => { if (section.instruments.bass.active) { section.instruments.bass.volume = Math.min(1, section.instruments.bass.volume * 1.3); } if (section.type === 'chorus') { section.instruments.brass.volume = Math.min(1, section.instruments.brass.volume * 1.2); } }); break; case 'classical': // Classical: more piano and chords, less drums sections.forEach(section => { section.instruments.piano.active = true; section.instruments.piano.volume = Math.min(1, section.instruments.piano.volume * 1.3); section.instruments.drums.volume *= 0.7; section.instruments.brass.active = true; section.instruments.brass.volume = Math.min(1, section.instruments.brass.volume + 0.2); }); break; case 'pop': // Pop: balanced, catchy, more emphasis on chorus sections.forEach(section => { if (section.type === 'chorus') { Object.keys(section.instruments).forEach(key => { const inst = section.instruments[key as keyof typeof section.instruments]; inst.volume = Math.min(1, inst.volume * 1.1); }); } }); break; case 'hiphop': default: // Hip hop: heavy drums and bass, soulful samples sections.forEach(section => { if (section.type === 'verse' || section.type === 'chorus') { section.instruments.drums.volume = Math.min(1, section.instruments.drums.volume * 1.1); section.instruments.bass.volume = Math.min(1, section.instruments.bass.volume * 1.1); } }); break; } } // Calculate timing for each section in seconds export function calculateSectionTimings(structure: SongStructure, bpm: number): { startTime: number; endTime: number; section: SongSection }[] { const secondsPerBar = (60 / bpm) * 4; // 4 beats per bar let currentTime = 0; return structure.sections.map(section => { const startTime = currentTime; const duration = section.bars * secondsPerBar; currentTime += duration; return { startTime, endTime: currentTime, section, }; }); }