const PromptTemplateManager = (function() { const DEFAULT_PRESETS = [ { id: "preset_epic_orchestra_intro", name: "Epic Orchestra Intro (8 Bars)", keywords: ["epic orchestra", "epic orchestral", "hoành tráng", "nhạc phim epic"], category: "Orchestral / Film Score", default_bars: 8, default_bpm: 130, default_scale: "C Minor", system_instruction_template: "You are a professional film composer. Create a powerful, dramatic 8-bar orchestral intro. Write notes continuously across all 8 bars (from beat 0.0 to 32.0) for every track. Use whole notes, half notes, or quarter notes to maintain a clean layout without overloading the sequence. The required structure to return via the `generate_multitrack_midi` tool consists of 3 tracks: 1. Strings: plays smooth legato chord changes (one chord per 1 or 2 bars continuously). 2. Brass Theme: plays a swelling simple melodic line in the C3-C5 range spanning all 8 bars. 3. Epic Percussion: hits heavily on beats 1 and 3 throughout the entire 8 bars.", is_user_defined: false, is_favorite: false, created_at: "2026-07-23T16:00:00Z" }, { id: "preset_pop_piano_chords", name: "Pop Piano Chords (4 Bars)", keywords: ["pop piano", "piano chords", "ballad piano", "hợp âm piano"], category: "Pop / Ballad", default_bars: 4, default_bpm: 90, default_scale: "C Major", system_instruction_template: "You are a professional Pop Piano player. Generate a beautiful 4-bar piano chord progression (e.g. C - G - Am - F) with pleasant chord voicing and simple accompaniment. Return the MIDI notes via the `generate_multitrack_midi` function on a track named 'Pop Piano'. Write notes continuously across all 4 bars (from beat 0.0 to 16.0). Use whole/half/quarter notes continuously to ensure every bar has piano chords playing.", is_user_defined: false, is_favorite: false, created_at: "2026-07-23T16:00:00Z" }, { id: "preset_cyberpunk_synth", name: "Cyberpunk Synthwave (8 Bars)", keywords: ["cyberpunk synth", "synthwave", "cyberpunk", "futuristic synth"], category: "Electronic / Synthwave", default_bars: 8, default_bpm: 120, default_scale: "A Minor", system_instruction_template: "You are a Synthwave producer. Generate a driving 8-bar cyberpunk synth theme. Return MIDI notes via `generate_multitrack_midi` containing: 1. Synth Bass: plays eighth notes on pitch A1, C2, G1 continuously across all 8 bars (from beat 0.0 to 32.0). 2. Synth Lead: plays a simple, melodic line in the high register (C4-E5) continuously across all 8 bars (from beat 0.0 to 32.0).", is_user_defined: false, is_favorite: false, created_at: "2026-07-23T16:00:00Z" }, // ── Rearrange & Variation Scenarios ── { id: "preset_rearrange_arpeggio", name: "Arpeggio Variation", keywords: ["arpeggio", "arp", "broken chord", "arpeggiate"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Rearrange the source MIDI notes into an arpeggiated variation. Subdivide sustained chord notes into sequential 0.25-beat arpeggiated steps with octave/triad jumps. Create a driving, shimmering sequence while preserving the underlying chord progression.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_harmonies", name: "Add 3rd/4th Harmonies", keywords: ["harmony", "harmonize", "harmonies", "3rd", "duet", "chord voicing"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Add parallel harmonizing notes to the source melody. For each source pitch P, insert notes at P+3 or P+4 (Major/Minor 3rds) at the same start_beat. Create a richer, fuller texture resembling two instruments playing in duet.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_syncopation", name: "Syncopation / Off-beat", keywords: ["syncopation", "syncopate", "syncopated", "off-beat", "off beat", "funk", "latin"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Apply syncopation to the source melody. Shift start_beat alignment off strong beats (0.0, 1.0, 2.0, 3.0) onto off-beats (0.5, 1.5, 2.5, 3.5). Preserve the core melodic outline while creating a rhythmic, syncopated feel.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_walking_bass", name: "Walking Bass Line", keywords: ["walking bass", "bassline", "walking"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Transform the source melody into a walking bass line. Lower pitches to bass register (36-48 range). Build continuous quarter-note steps following the chord outline. Create an improvisational walking bassline matching the original chord progression.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_jazz", name: "Jazz Swing Rearrangement", keywords: ["jazz", "swing", "jazz swing", "bebop"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional Jazz arranger. Rearrange the source melody into a rhythmic Jazz Swing style. Apply: off-beat syncopation, 7th/9th chord extensions, swung eighth notes (triplet feel), and rhythmic variations while preserving the core melodic outline.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_synthwave", name: "Synthwave / 80s Style", keywords: ["synthwave", "80s", "retro", "synth wave", "retrowave", "outrun"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "A Minor", system_instruction_template: "You are a Synthwave producer. Transform the source melody into an 80s Synthwave style. Apply: driving 8th-note bass arpeggios, analog synth lead with portamento, pulsating chord pads, and octave jumps in the bass.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_cinematic", name: "Cinematic Orchestral", keywords: ["cinematic", "orchestral", "epic", "film score", "symphonic", "hollywood"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 130, default_scale: "C Minor", system_instruction_template: "You are a cinematic composer. Transform the source melody into a dramatic Cinematic Orchestral arrangement. Apply: swelling dynamics, brass stabs on downbeats, string ostinato patterns, taiko percussion hits. Layer multiple octaves for epic width.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_simplify", name: "Simplify / Strip Down", keywords: ["simplify", "minimal", "strip down", "sparse", "reduce"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Simplify the source melody: keep only downbeat notes (start_beat at 0.0, 1.0, 2.0, 3.0). Strip out embellishments, passing tones, and grace notes. Reduce chord voicings to root and 5th only.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" }, { id: "preset_rearrange_chromatic", name: "Passing Tones & Chromaticism", keywords: ["passing tone", "chromatic", "chromaticism", "smooth", "approach note"], category: "Rearrange / Variation", default_bars: 8, default_bpm: 120, default_scale: "C Major", system_instruction_template: "You are a professional arranger. Add passing tones and chromatic approach notes to the source melody. Insert half-step and whole-step approach notes targeting chord tones on strong beats. Smooth out the melodic progression while preserving the harmonic framework.", is_user_defined: false, is_favorite: false, created_at: "2026-07-28T11:00:00Z" } ]; const STORAGE_KEY = 'daw_ai_prompt_presets'; function PromptTemplateManager() { this.presets = []; this.loadPresets(); } PromptTemplateManager.prototype.loadPresets = function() { try { const localData = localStorage.getItem(STORAGE_KEY); if (localData) { const parsed = JSON.parse(localData); const userPresets = parsed.filter(p => p.is_user_defined); this.presets = [...DEFAULT_PRESETS, ...userPresets]; } else { this.presets = [...DEFAULT_PRESETS]; this.savePresets(); } } catch (_) { this.presets = [...DEFAULT_PRESETS]; } }; PromptTemplateManager.prototype.savePresets = function() { const userData = this.presets.filter(p => p.is_user_defined); localStorage.setItem(STORAGE_KEY, JSON.stringify(userData)); }; PromptTemplateManager.prototype.getPresets = function() { return this.presets; }; PromptTemplateManager.prototype.matchPreset = function(userQuery) { if (!userQuery) return null; const queryLower = userQuery.toLowerCase(); let bestMatch = null; let bestScore = 0; for (const preset of this.presets) { for (const kw of preset.keywords) { const kwLower = kw.toLowerCase(); if (queryLower === kwLower) { if (3 > bestScore) { bestScore = 3; bestMatch = { preset, score: 3 }; } } else if (queryLower.includes(kwLower)) { if (2 > bestScore) { bestScore = 2; bestMatch = { preset, score: 2 }; } } else if (kwLower.includes(queryLower)) { if (1 > bestScore) { bestScore = 1; bestMatch = { preset, score: 1 }; } } } } return bestMatch; }; PromptTemplateManager.prototype.saveUserPreset = function(presetObject) { const index = this.presets.findIndex(p => p.id === presetObject.id); if (index >= 0) { this.presets[index] = presetObject; } else { this.presets.push(presetObject); } this.savePresets(); }; PromptTemplateManager.prototype.deletePreset = function(id) { this.presets = this.presets.filter(p => p.id !== id); this.savePresets(); }; PromptTemplateManager.prototype.getContextualSuggestions = function(hasSelectedItem) { if (hasSelectedItem) { return this.presets.filter(p => p.category === 'Rearrange / Variation' || p.is_favorite); } else { return this.presets.filter(p => p.category !== 'Rearrange / Variation'); } }; PromptTemplateManager.prototype.toggleFavorite = function(id) { const preset = this.presets.find(p => p.id === id); if (preset) { preset.is_favorite = !preset.is_favorite; if (preset.is_user_defined) { this.savePresets(); } } }; return PromptTemplateManager; })(); window.PromptTemplateManager = PromptTemplateManager; window.DEFAULT_PRESETS = (new PromptTemplateManager()).getPresets();