This commit is contained in:
+90
-21
@@ -1,3 +1,10 @@
|
|||||||
|
const EXPECTED_DUMP_LENGTH = 297;
|
||||||
|
const MAX_DUMP_RETRIES = 10;
|
||||||
|
const DUMP_RETRY_DELAY = 150;
|
||||||
|
|
||||||
|
let dumpRetryCount = 0;
|
||||||
|
let dumpRetryTimer = null;
|
||||||
|
|
||||||
let selectedMidiOutput = null;
|
let selectedMidiOutput = null;
|
||||||
let selectedMidiInput = null;
|
let selectedMidiInput = null;
|
||||||
let onLogCallback = null;
|
let onLogCallback = null;
|
||||||
@@ -71,45 +78,107 @@ export const changeMidiInputPort = (portId) => {
|
|||||||
/**
|
/**
|
||||||
* Envoie une requête de "Current Parameter Dump" au microKORG
|
* Envoie une requête de "Current Parameter Dump" au microKORG
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const requestCurrentPatchDump = () => {
|
export const requestCurrentPatchDump = () => {
|
||||||
if (!selectedMidiOutput) return;
|
if (!selectedMidiOutput) return;
|
||||||
|
|
||||||
// Trame officielle de requête de dump de paramètre courant Korg microKORG
|
dumpRetryCount = 0;
|
||||||
|
|
||||||
|
if (dumpRetryTimer) {
|
||||||
|
clearTimeout(dumpRetryTimer);
|
||||||
|
dumpRetryTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCurrentPatchDumpRequest();
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendCurrentPatchDumpRequest = () => {
|
||||||
|
if (!selectedMidiOutput) return;
|
||||||
|
|
||||||
const requestMessage = [
|
const requestMessage = [
|
||||||
0xF0, // Start SysEx
|
0xF0,
|
||||||
0x42, // Korg ID
|
0x42,
|
||||||
0x30, // Canal global 1
|
0x30,
|
||||||
0x58, // microKORG ID
|
0x58,
|
||||||
0x10, // Message de requête (Current Data Dump Request)
|
0x10,
|
||||||
0xF7 // End SysEx
|
0xF7
|
||||||
];
|
];
|
||||||
|
|
||||||
selectedMidiOutput.send(requestMessage);
|
selectedMidiOutput.send(requestMessage);
|
||||||
logMidiActivity('out', '➡️ REQ', requestMessage);
|
|
||||||
|
logMidiActivity(
|
||||||
|
'out',
|
||||||
|
dumpRetryCount === 0 ? '➡️ REQ' : `➡️ RETRY ${dumpRetryCount}`,
|
||||||
|
requestMessage
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupMidiInputListener = (inputPort) => {
|
const setupMidiInputListener = (inputPort) => {
|
||||||
if (selectedMidiInput) selectedMidiInput.onmidimessage = null;
|
if (selectedMidiInput) {
|
||||||
selectedMidiInput = inputPort;
|
selectedMidiInput.onmidimessage = null;
|
||||||
selectedMidiInput.onmidimessage = (event) => {
|
}
|
||||||
const data = event.data;
|
|
||||||
if (data[0] === 0xF8) return; // Ignore l'horloge temporelle F8
|
|
||||||
|
|
||||||
// Analyse : S'agit-il d'une réponse de Dump du microKORG ?
|
selectedMidiInput = inputPort;
|
||||||
// 0xF0 (SysEx), 0x42 (Korg), Canal, 0x58 (microKorg), 0x40 (Current Data Dump)
|
|
||||||
if (data[0] === 0xF0 && data[1] === 0x42 && data[3] === 0x58 && data[4] === 0x40) {
|
selectedMidiInput.onmidimessage = (event) => {
|
||||||
|
const data = new Uint8Array(event.data);
|
||||||
|
|
||||||
|
if (data[0] === 0xF8) return;
|
||||||
|
|
||||||
|
const isCurrentProgramDump =
|
||||||
|
data[0] === 0xF0 &&
|
||||||
|
data[1] === 0x42 &&
|
||||||
|
data[3] === 0x58 &&
|
||||||
|
data[4] === 0x40;
|
||||||
|
|
||||||
|
if (!isCurrentProgramDump) {
|
||||||
logMidiActivity('in', '⬅️ IN ', data);
|
logMidiActivity('in', '⬅️ IN ', data);
|
||||||
if (onPatchReceivedCallback) {
|
|
||||||
// Envoie le tableau de bytes brut à l'application
|
|
||||||
onPatchReceivedCallback(data);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logMidiActivity('in', '⬅️ IN ', data);
|
console.log(
|
||||||
|
`[MIDI] Current dump reçu : ${data.length}/${EXPECTED_DUMP_LENGTH} octets`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.length === EXPECTED_DUMP_LENGTH) {
|
||||||
|
dumpRetryCount = 0;
|
||||||
|
|
||||||
|
if (dumpRetryTimer) {
|
||||||
|
clearTimeout(dumpRetryTimer);
|
||||||
|
dumpRetryTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logMidiActivity('in', '⬅️ DUMP OK', data);
|
||||||
|
|
||||||
|
if (onPatchReceivedCallback) {
|
||||||
|
onPatchReceivedCallback(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logMidiActivity(
|
||||||
|
'in',
|
||||||
|
`⬅️ DUMP ${data.length}/${EXPECTED_DUMP_LENGTH}`,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dumpRetryCount >= MAX_DUMP_RETRIES) {
|
||||||
|
console.error(
|
||||||
|
`[MIDI] abandon après ${MAX_DUMP_RETRIES} tentatives - dernier dump : ${data.length} octets`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dumpRetryCount++;
|
||||||
|
|
||||||
|
dumpRetryTimer = setTimeout(() => {
|
||||||
|
sendCurrentPatchDumpRequest();
|
||||||
|
}, DUMP_RETRY_DELAY);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const sendMicroKorgParam = (parameterId, value) => {
|
export const sendMicroKorgParam = (parameterId, value) => {
|
||||||
if (!selectedMidiOutput) return;
|
if (!selectedMidiOutput) return;
|
||||||
const sysExMessage = [0xF0, 0x42, 0x30, 0x58, 0x41, parameterId, value, 0xF7];
|
const sysExMessage = [0xF0, 0x42, 0x30, 0x58, 0x41, parameterId, value, 0xF7];
|
||||||
|
|||||||
Reference in New Issue
Block a user