feat: implemented drag-n-drop to import KGOne generated audio/MIDI file feature
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { KGCommand } from '../KGCommand';
|
||||
import { KGCore } from '../../KGCore';
|
||||
import { KGMidiRegion } from '../../region/KGMidiRegion';
|
||||
import { KGMidiNote } from '../../midi/KGMidiNote';
|
||||
import { generateUniqueId } from '../../../util/miscUtil';
|
||||
import type { RawMidiNote } from '../../../util/midiUtil';
|
||||
|
||||
/**
|
||||
* Command to insert a MIDI clip (from K.G.One generation) into a MIDI track.
|
||||
* All note data is stored so that redo recreates the full region with notes.
|
||||
*/
|
||||
export class ImportMidiClipCommand extends KGCommand {
|
||||
private trackId: string;
|
||||
private trackIndex: number;
|
||||
private regionId: string;
|
||||
private regionName: string;
|
||||
private startBeat: number;
|
||||
private lengthInBeats: number;
|
||||
private rawNotes: RawMidiNote[];
|
||||
private createdRegion: KGMidiRegion | null = null;
|
||||
|
||||
constructor(
|
||||
trackId: string,
|
||||
trackIndex: number,
|
||||
startBeat: number,
|
||||
lengthInBeats: number,
|
||||
rawNotes: RawMidiNote[],
|
||||
regionName?: string,
|
||||
regionId?: string
|
||||
) {
|
||||
super();
|
||||
this.trackId = trackId;
|
||||
this.trackIndex = trackIndex;
|
||||
this.startBeat = startBeat;
|
||||
this.lengthInBeats = lengthInBeats;
|
||||
this.rawNotes = rawNotes;
|
||||
this.regionId = regionId || generateUniqueId('KGMidiRegion');
|
||||
this.regionName = regionName || 'KGOne Clip';
|
||||
}
|
||||
|
||||
execute(): void {
|
||||
const core = KGCore.instance();
|
||||
const currentProject = core.getCurrentProject();
|
||||
const track = currentProject.getTracks().find(t => t.getId().toString() === this.trackId);
|
||||
if (!track) {
|
||||
throw new Error(`Track ${this.trackId} not found`);
|
||||
}
|
||||
|
||||
// Create the region
|
||||
this.createdRegion = new KGMidiRegion(
|
||||
this.regionId,
|
||||
this.trackId,
|
||||
this.trackIndex,
|
||||
this.regionName,
|
||||
this.startBeat,
|
||||
this.lengthInBeats
|
||||
);
|
||||
|
||||
// Populate notes
|
||||
for (const raw of this.rawNotes) {
|
||||
const note = new KGMidiNote(
|
||||
generateUniqueId('KGMidiNote'),
|
||||
raw.startBeat,
|
||||
raw.endBeat,
|
||||
raw.pitch,
|
||||
raw.velocity
|
||||
);
|
||||
this.createdRegion.addNote(note);
|
||||
}
|
||||
|
||||
track.addRegion(this.createdRegion);
|
||||
console.log(`Imported MIDI clip "${this.regionName}" (${this.rawNotes.length} notes) at beat ${this.startBeat}`);
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
const core = KGCore.instance();
|
||||
const currentProject = core.getCurrentProject();
|
||||
const track = currentProject.getTracks().find(t => t.getId().toString() === this.trackId);
|
||||
if (track) {
|
||||
track.removeRegion(this.regionId);
|
||||
}
|
||||
console.log(`Undid MIDI clip import "${this.regionName}"`);
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
return `Import MIDI clip "${this.regionName}"`;
|
||||
}
|
||||
|
||||
getCreatedRegion(): KGMidiRegion | null {
|
||||
return this.createdRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory from bar-based coordinates (common UI pattern).
|
||||
*/
|
||||
static fromBarCoordinates(
|
||||
trackId: string,
|
||||
trackIndex: number,
|
||||
barNumber: number,
|
||||
lengthInBars: number,
|
||||
beatsPerBar: number,
|
||||
rawNotes: RawMidiNote[],
|
||||
regionName?: string,
|
||||
regionId?: string
|
||||
): ImportMidiClipCommand {
|
||||
const startBeat = (barNumber - 1) * beatsPerBar;
|
||||
const lengthInBeats = lengthInBars * beatsPerBar;
|
||||
return new ImportMidiClipCommand(
|
||||
trackId, trackIndex, startBeat, lengthInBeats,
|
||||
rawNotes, regionName, regionId
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user