fix: piano roll và main session play
This commit is contained in:
+34
-12
@@ -4010,7 +4010,7 @@ const DEFAULT_PRESETS = [
|
||||
default_bars: 8,
|
||||
default_bpm: 130,
|
||||
default_scale: "C Minor",
|
||||
system_instruction_template: "You are a professional Epic Orchestral film composer. Create a powerful, dramatic 8-bar intro composition.\nThe required structure to return via the `generate_multitrack_midi` tool consists of 5 tracks:\n1. Strings Ensemble: Plays staccato 16th notes in the low register (C2, G2) driving the rhythm (Ostinato).\n2. Brass Section: Plays the main swelling melodic theme (Horn/Trumpet swells) in the C3-C5 range.\n3. Epic Percussion / Taiko: Hits heavily on beats 1 and 3, featuring a snare roll accent at bars 4 and 8.\n4. Synth Bass/Pad: Holds smooth octave foundation layers (Legato).\n5. Orchestral Drums/Cymbals: Crashes on bar 1 and bar 5.\nEnsure the duration of each track is precisely 8 bars (32 beats).",
|
||||
system_instruction_template: "You are a professional film composer. Create a powerful, dramatic 8-bar orchestral intro. Keep the note density low (e.g. use mostly whole notes, half notes, or quarter notes) and do NOT generate dense 16th notes or complex drum rolls. This is critical to avoid output token limit timeouts. 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). 2. Brass Theme: plays a swelling simple melodic line in the C3-C5 range. 3. Epic Percussion: hits heavily on beats 1 and 3. Ensure the duration is precisely 8 bars (32 beats).",
|
||||
is_user_defined: false,
|
||||
created_at: "2026-07-23T16:00:00Z"
|
||||
},
|
||||
@@ -4022,7 +4022,7 @@ const DEFAULT_PRESETS = [
|
||||
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 `generate_multitrack_midi` function on a track named 'Pop Piano'. Ensure the duration of the track is precisely 4 bars (16 beats).",
|
||||
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 `generate_multitrack_midi` function on a track named 'Pop Piano'. Keep notes simple, using mostly whole/half/quarter notes. Ensure the duration of the track is precisely 4 bars (16 beats).",
|
||||
is_user_defined: false,
|
||||
created_at: "2026-07-23T16:00:00Z"
|
||||
},
|
||||
@@ -4034,7 +4034,7 @@ const DEFAULT_PRESETS = [
|
||||
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 bassline and lead melody. Return MIDI notes via `generate_multitrack_midi` containing:\n1. Synth Bass: driving eighth notes on pitch A1, C2, G1.\n2. Synth Lead: arpeggiated melodic line in high register C4-E5.\nEnsure the duration of each track is precisely 8 bars (32 beats).",
|
||||
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: eighth notes on pitch A1, C2, G1. 2. Synth Lead: simple melodic line in high register C4-E5. Keep notes clean and concise to ensure fast generation.",
|
||||
is_user_defined: false,
|
||||
created_at: "2026-07-23T16:00:00Z"
|
||||
}
|
||||
@@ -4045,7 +4045,14 @@ const AIPresetModal = ({ isOpen, onClose }) => {
|
||||
|
||||
const [presets, setPresets] = React.useState(() => {
|
||||
const local = localStorage.getItem('daw_ai_prompt_presets');
|
||||
return local ? JSON.parse(local) : DEFAULT_PRESETS;
|
||||
if (!local) return DEFAULT_PRESETS;
|
||||
try {
|
||||
const parsed = JSON.parse(local);
|
||||
const userPresets = parsed.filter(p => p.is_user_defined);
|
||||
return [...DEFAULT_PRESETS, ...userPresets];
|
||||
} catch (_) {
|
||||
return DEFAULT_PRESETS;
|
||||
}
|
||||
});
|
||||
|
||||
const [search, setSearch] = React.useState('');
|
||||
@@ -5299,7 +5306,7 @@ const App = () => {
|
||||
const closeInstrumentSelector = () => setInstrumentSelectorTrackId(null);
|
||||
const [synthCategory, setSynthCategory] = useState(null); // 'vst' | 'soundfont'
|
||||
const [selectedSoundFontId, setSelectedSoundFontId] = useState(null);
|
||||
const GM_INSTRUMENTS = [
|
||||
const [sfPresets, setSfPresets] = useState(null); // presets from SoundFont
|
||||
"Acoustic Grand Piano","Bright Acoustic Piano","Electric Grand Piano","Honky-tonk Piano","Electric Piano 1","Electric Piano 2","Harpsichord","Clavi",
|
||||
"Celesta","Glockenspiel","Music Box","Vibraphone","Marimba","Xylophone","Tubular Bells","Dulcimer",
|
||||
"Drawbar Organ","Percussive Organ","Rock Organ","Church Organ","Reed Organ","Accordion","Harmonica","Tango Accordion",
|
||||
@@ -5332,6 +5339,12 @@ const App = () => {
|
||||
setSelectedSoundFontId(instrumentId);
|
||||
setSynthCategory('soundfont');
|
||||
setInstrumentSelectorTrackId(trackId);
|
||||
setSfPresets(null);
|
||||
// Fetch actual presets from the SoundFont
|
||||
const sfIdParam = instrumentId.replace('sf_', '');
|
||||
window.SonicAPI.listSoundfontInstruments(sfIdParam)
|
||||
.then(data => setSfPresets(data.presets || []))
|
||||
.catch(() => setSfPresets([]));
|
||||
} else {
|
||||
setTrackInstrumentWithProgram(trackId, instrumentId, undefined, displayName);
|
||||
}
|
||||
@@ -6610,6 +6623,8 @@ const App = () => {
|
||||
notes: midiItem.notes || [],
|
||||
duration: midiItem.duration || 4,
|
||||
buffer: silentBuffer,
|
||||
instrumentProgram: track.instrumentProgram,
|
||||
instrumentName: track.instrumentName,
|
||||
currentTime: 0,
|
||||
isPlaying: false,
|
||||
selectionStart: null,
|
||||
@@ -14800,14 +14815,21 @@ const App = () => {
|
||||
/*#__PURE__*/React.createElement("button", {
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, selectedSoundFontId),
|
||||
className: "w-full text-left px-3 py-1.5 text-xs rounded bg-zinc-800 hover:bg-zinc-700 text-zinc-400"
|
||||
}, "None (Default Program)"),
|
||||
/*#__PURE__*/React.createElement("div", { className: "grid grid-cols-2 gap-0.5" },
|
||||
GM_INSTRUMENTS.map((name, i) => /*#__PURE__*/React.createElement("button", {
|
||||
key: i,
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, selectedSoundFontId, i, name),
|
||||
className: "text-left px-2 py-1 text-[10px] rounded bg-zinc-800/60 hover:bg-amber-800 text-zinc-300 truncate"
|
||||
}, i + ". " + name))
|
||||
}, "None (Default Program)"),
|
||||
sfPresets === null ? (
|
||||
React.createElement("p", { className: "text-[10px] text-zinc-500 py-2" }, "Loading instruments...")
|
||||
) : sfPresets.length > 0 ? (
|
||||
React.createElement("div", { className: "grid grid-cols-2 gap-0.5" },
|
||||
sfPresets.map((p, i) => React.createElement("button", {
|
||||
key: i,
|
||||
onClick: () => setTrackInstrumentWithProgram(instrumentSelectorTrackId, selectedSoundFontId, p.program, p.name || 'Preset ' + p.program),
|
||||
className: "text-left px-2 py-1 text-[10px] rounded bg-zinc-800/60 hover:bg-amber-800 text-zinc-300 truncate"
|
||||
}, (p.bank || 0) + ":" + p.program + " " + (p.name || 'Preset ' + p.program)))
|
||||
)
|
||||
) : (
|
||||
React.createElement("p", { className: "text-[10px] text-zinc-500 py-2" }, "No presets found.")
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
) : (
|
||||
|
||||
@@ -64,6 +64,7 @@ window.API_BASE_URL = window.API_BASE_URL || window.location.origin;
|
||||
|
||||
listPlugins: () => apiRequest('/api/v1/plugins/available', { method: 'GET' }),
|
||||
listDefaultSoundfonts: () => apiRequest('/api/v1/plugins/default-soundfonts', { method: 'GET' }),
|
||||
listSoundfontInstruments: (sfId) => apiRequest(`/api/v1/plugins/soundfont-instruments/${sfId}`, { method: 'GET' }),
|
||||
renderProject: (projectJson, outputFilename) => apiRequest('/api/v1/plugins/render', { method: 'POST', body: JSON.stringify({ project_json: projectJson, output_filename: outputFilename }) }),
|
||||
uploadSoundFont: async (file) => {
|
||||
const formData = new FormData();
|
||||
|
||||
Reference in New Issue
Block a user