feat: AI Rearrange Scenario Detection from spec 45_SCENARIAO_AI
- 9 rearrange scenarios with keyword matching (arpeggio, harmonies, syncopation, walking bass, jazz, synthwave, cinematic, simplify, chromatic) - detectRearrangeScenario() maps user prompt to specific technique rules - buildRearrangeMessage auto-injects scenario-specific technique guidance - 9 rearrange presets added to PromptTemplateManager (Rearrange / Variation)
This commit is contained in:
@@ -120,29 +120,111 @@ const AIGateway = (function() {
|
||||
}
|
||||
};
|
||||
|
||||
const REARRANGE_SCENARIOS = [
|
||||
{
|
||||
id: 'arpeggio',
|
||||
keywords: ['arpeggio', 'arp', 'broken chord', 'broken chords', 'shimmering sequence'],
|
||||
description: 'Arpeggio variation',
|
||||
technique: 'Subdivide sustained chord notes (longer than 0.5 beats) into sequential 0.25-beat arpeggiated interval steps using octave/triad jumps. Create a driving, shimmering sequence.'
|
||||
},
|
||||
{
|
||||
id: 'harmonies',
|
||||
keywords: ['harmony', 'harmonize', 'harmonies', '3rd', '3rds', 'duet', 'chord voicing', 'voicing'],
|
||||
description: 'Add parallel harmonies',
|
||||
technique: 'For each source pitch P, insert parallel harmonizing notes at pitch P+3 or P+4 (Major/Minor 3rds) matching the same start_beat. Create richer, fuller texture resembling two instruments playing in duet.'
|
||||
},
|
||||
{
|
||||
id: 'syncopation',
|
||||
keywords: ['syncopation', 'syncopate', 'syncopated', 'off-beat', 'off beat', 'funk', 'latin', 'rnb', 'r&b'],
|
||||
description: 'Syncopation / off-beat feel',
|
||||
technique: '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). Create a rhythmic, syncopated feel.'
|
||||
},
|
||||
{
|
||||
id: 'walking_bass',
|
||||
keywords: ['walking bass', 'bassline', 'bass line', 'walking'],
|
||||
description: 'Walking bass line',
|
||||
technique: 'Lower pitches to bass register (36-48 range). Build continuous quarter-note steps (1.0 beat duration) following the chord outline. Create an improvisational walking bassline.'
|
||||
},
|
||||
{
|
||||
id: 'jazz_swing',
|
||||
keywords: ['jazz', 'swing', 'bebop', 'bop', 'jazz swing'],
|
||||
description: 'Jazz Swing style',
|
||||
technique: 'Apply Jazz Swing characteristics: off-beat syncopation, 7th/9th chord extensions, rhythmic variations, and swung eighth notes (triplet feel). Preserve the core melodic outline while adding jazz harmony.'
|
||||
},
|
||||
{
|
||||
id: 'synthwave',
|
||||
keywords: ['synthwave', '80s', 'retro', 'synth wave', 'outrun', 'retrowave'],
|
||||
description: 'Synthwave / 80s style',
|
||||
technique: 'Transform into 80s Synthwave style: driving 8th-note bass arpeggios, gated reverb snare, analog synth lead with portamento, and pulsating chord pads. Use octave jumps in the bass.'
|
||||
},
|
||||
{
|
||||
id: 'cinematic',
|
||||
keywords: ['cinematic', 'orchestral', 'epic', 'film score', 'movie', 'hollywood', 'symphonic'],
|
||||
description: 'Cinematic Orchestral style',
|
||||
technique: 'Transform into dramatic Cinematic Orchestral style: swelling dynamics, brass stabs on downbeats, string ostinato patterns, taiko percussion hits on strong beats. Layer multiple octaves for epic width.'
|
||||
},
|
||||
{
|
||||
id: 'simplify',
|
||||
keywords: ['simplify', 'minimal', 'strip', 'downbeat', 'reduce', 'sparse'],
|
||||
description: 'Simplify / strip down',
|
||||
technique: 'Keep only the downbeat notes (start_beat at 0.0, 1.0, 2.0, 3.0, etc.). Strip out embellishments, passing tones, and grace notes. Reduce chord voicings to root and 5th only.'
|
||||
},
|
||||
{
|
||||
id: 'passing_tones',
|
||||
keywords: ['passing tone', 'chromatic', 'chromaticism', 'smooth', 'approach note'],
|
||||
description: 'Add passing tones / chromaticism',
|
||||
technique: 'Insert passing tones and chromatic approach notes between chord tones to smooth out the melodic progression. Use half-step and whole-step approach notes targeting chord tones on strong beats.'
|
||||
}
|
||||
];
|
||||
|
||||
function detectRearrangeScenario(prompt) {
|
||||
if (!prompt) return null;
|
||||
const lower = prompt.toLowerCase();
|
||||
const matched = [];
|
||||
for (const sc of REARRANGE_SCENARIOS) {
|
||||
const hits = sc.keywords.filter(kw => lower.includes(kw.toLowerCase()));
|
||||
if (hits.length > 0) {
|
||||
matched.push({ scenario: sc, hitCount: hits.length });
|
||||
}
|
||||
}
|
||||
matched.sort((a, b) => b.hitCount - a.hitCount);
|
||||
return matched.length > 0 ? matched[0].scenario : null;
|
||||
}
|
||||
|
||||
function buildRearrangeMessage(prompt, sourceContext) {
|
||||
const notesJson = JSON.stringify(sourceContext.notes, null, 2);
|
||||
const scenario = detectRearrangeScenario(prompt);
|
||||
const techniqueSection = scenario
|
||||
? `\nDETECTED SCENARIO: ${scenario.description}\nSPECIFIC TECHNIQUE REQUIRED: ${scenario.technique}\n`
|
||||
: '';
|
||||
|
||||
const rules = [
|
||||
'1. Use the rearrange_midi_melody tool to return the rearranged notes.',
|
||||
'2. PRESERVE the core melodic outline and overall structure unless the user explicitly asks for a complete transformation.',
|
||||
'3. Keep the total duration (' + sourceContext.total_beats + ' beats) the same unless user requests a different length.',
|
||||
'4. The rearranged_notes array MUST contain notes with pitch (0-127), start_beat (0.0 to ' + sourceContext.total_beats + '.0), duration_beats, and velocity (0.0-1.0).',
|
||||
'5. Start beats should remain within 0-' + sourceContext.total_beats + ' range.',
|
||||
'6. You may add, remove, or modify notes to achieve the requested style.',
|
||||
'7. ALWAYS return a rearrange_title describing what was created (e.g. "Jazz Swing Variation of Piano Lead").'
|
||||
];
|
||||
|
||||
return [
|
||||
{ role: 'system', content: `You are a professional music arranger. Your task is to rearrange/re-harmonize the provided MIDI notes based on the user's request.
|
||||
{ role: 'system', content: `You are a professional Music Composer & Arranger.
|
||||
|
||||
SOURCE MIDI CONTEXT:
|
||||
- Track: ${sourceContext.track_name}
|
||||
- Item: ${sourceContext.item_name}
|
||||
- Duration: ${sourceContext.duration_bars} bars (${sourceContext.total_beats} beats)
|
||||
- BPM: ${sourceContext.bpm}
|
||||
- Time Signature: 4/4
|
||||
- Total notes: ${sourceContext.total_notes}
|
||||
|
||||
SOURCE NOTES (pitch, note_name, start_beat, duration_beats, velocity):
|
||||
ORIGINAL MELODY NOTES (pitch, note_name, start_beat, duration_beats, velocity):
|
||||
${notesJson}
|
||||
|
||||
RULES:
|
||||
1. Use the rearrange_midi_melody tool to return the rearranged notes.
|
||||
2. PRESERVE the core melodic outline and overall structure unless the user explicitly asks for a complete transformation.
|
||||
3. Keep the total duration (${sourceContext.total_beats} beats) the same unless user requests a different length.
|
||||
4. The rearranged_notes array MUST contain notes with pitch (0-127), start_beat (0.0 to ${sourceContext.total_beats}.0), duration_beats, and velocity (0.0-1.0).
|
||||
5. Start beats should remain within 0-${sourceContext.total_beats} range.
|
||||
6. You may add, remove, or modify notes to achieve the requested style.` },
|
||||
{ role: 'user', content: `User request: ${prompt}\n\nRearrange the source MIDI notes above according to this request. Return the result via the rearrange_midi_melody tool.` }
|
||||
${techniqueSection}
|
||||
STRICT REARRANGE RULES:
|
||||
${rules.join('\n')}` },
|
||||
{ role: 'user', content: `${prompt}\n\nRearrange the source MIDI notes above according to this request. Return the result via the rearrange_midi_melody tool.` }
|
||||
];
|
||||
}
|
||||
|
||||
@@ -362,6 +444,8 @@ Ví dụ: "Hãy chọn và copy từ bar 4 đến bar 12 của track 1 sau đó
|
||||
return {
|
||||
DEFAULT_TOOLS,
|
||||
REARRANGE_TOOL_SPEC,
|
||||
REARRANGE_SCENARIOS,
|
||||
detectRearrangeScenario,
|
||||
buildRearrangeMessage,
|
||||
callLLM,
|
||||
extractFunctionCalls,
|
||||
|
||||
@@ -38,6 +38,124 @@ const PromptTemplateManager = (function() {
|
||||
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"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -539,6 +539,12 @@
|
||||
- **Ghi chú/Test (nếu có):** `npm run build` pass. Ctrl+Click+Drag section/MIDI item → copy đến vị trí mới, item không bị selected.
|
||||
---
|
||||
|
||||
### [2026-07-28 11:02] Task: AI Rearrange Scenario Detection (spec 45_SCENARIAO_AI.md)
|
||||
- **Tóm tắt thay đổi:** Thêm 9 rearrange scenarios vào `aiGateway.js` (arpeggio, harmonies, syncopation, walking bass, jazz swing, synthwave, cinematic, simplify, passing tones) với keyword mapping → `detectRearrangeScenario()`. `buildRearrangeMessage` tự động inject specific technique rules dựa trên scenario detect được. Thêm 9 rearrange presets vào `promptTemplateManager.js` với category "Rearrange / Variation".
|
||||
- **Các file ảnh hưởng:** `app/static/js/services/aiGateway.js`, `app/static/js/services/promptTemplateManager.js`
|
||||
- **Ghi chú/Test (nếu có):** `node --check` pass. `npx babel` compile pass. Preset Manager hiển thị 12 presets (3 cũ + 9 rearrange). Gõ "arpeggio" → AI nhận dạng scenario → inject technique "Subdivide sustained chord notes into 0.25-beat arpeggiated steps".
|
||||
---
|
||||
|
||||
### [2026-07-28 10:52] Task: MIDI Rearrange Feature (spec 41_AIMIDI_FIX.md)
|
||||
- **Tóm tắt thay đổi:** Tạo `midiExtractor.js` — `extractSelectedMIDIContext` trích xuất notes + note names từ selected MIDI item. Thêm `REARRANGE_TOOL_SPEC` + `buildRearrangeMessage` trong `aiGateway.js`. `handleAISend` phát hiện selected MIDI item → dùng rearrange flow riêng (source notes → AI → `rearrange_midi_melody` → A/B track bên dưới source). Handler `rearrangeMidiMelody` tạo track `[AI Rearrange] <title>` + MIDI item ngay dưới source track.
|
||||
- **Các file ảnh hưởng:** `app/static/js/services/midiExtractor.js` (NEW), `app/static/js/services/aiGateway.js`, `app/static/js/services/dawCommandDispatcher.js`, `app/static/js/app.jsx`, `app/templates/index.html`
|
||||
|
||||
Reference in New Issue
Block a user