Non ho programmato MIDI da anni, ma la tua idea fondamentale è molto solida (niente giochi di parole).
Il MIDI è un flusso di "eventi" (o "messaggi"), due dei quali fondamentali sono "note on" e "note off" che portano con sé il numero della nota (0 = C cinque ottave sotto la C centrale, attraverso 127 = G cinque ottave sopra la G sopra la metà C, in semitoni). Questi eventi portano un numero di "velocità" su tastiere sensibili alla velocità ("sensibile al tocco"), con una forza di (hai indovinato) tra 0 e 127.
Tra velocità, accordi e pedali, penso che potresti trovare un'interfaccia di "digitazione" abbastanza buona per la tastiera del piano. Gli accordi in particolare potrebbero essere una tecnica molto potente - come ho già detto nei commenti, è per questo che gli stenografi di rango e file possono utilizzare una macchina stenotipica per tenere il passo con le persone che parlano per ore di fila, quando anche i dattilografi di alto livello non vorrebbero ' essere in grado per un certo periodo di tempo tramite normali tastiere in stile macchina da scrivere. Come per la stenografia automatica, avresti bisogno di un "dizionario" dei significati degli accordi e delle sequenze degli accordi. (Puoi dire che lavoravo sul lato software della stenografia della macchina?)
Per fare questo, i pezzi fondamentali sono:
- Ricezione dell'ingresso MIDI. Non provare a farlo da solo, usa una libreria. Modifica : Apparentemente, l'API Java Sound supporta il MIDI , inclusa la ricezione di eventi dai controller MIDI. Freddo. Questa pagina può anche essere utile.
- Conversione di tali dati nelle sequenze di tasti che si desidera inviare, ad esempio tramite il dizionario che ho menzionato sopra.
- Emissione dei tasti sul computer.
Per essere ampiamente compatibile con il software, dovresti scriverlo come un driver di dispositivo tastiera. Questo è un plug-in per il sistema operativo che funge da sorgente per gli eventi della tastiera, parlando con l'hardware sottostante (nel tuo caso, la tastiera del piano). Per Windows e Linux, probabilmente vorrai usare C per questo.
Tuttavia, poiché stai solo generando sequenze di tasti (non provando a intercettarli, cosa che stavo provando a fare anni fa), potresti essere in grado di utilizzare qualsiasi funzione del sistema operativo per inviare sequenze di tasti artificiali. Windows ha un'interfaccia per farlo (probabilmente diversi, quello a cui sto pensando è SendInput
ma so che esiste un'interfaccia "journal" che fa qualcosa di simile), e sono sicuro che anche altri sistemi operativi lo fanno. Potrebbe essere sufficiente per i tuoi scopi - è da dove cominciare, perché il percorso del driver del dispositivo sarà imbarazzante e probabilmente dovresti usare una lingua diversa da quella di Java. (Sono un grande fan di Java, ma le interfacce utilizzate dai sistemi operativi per comunicare con i driver di dispositivo tendono a essere più facilmente consumate tramite C e simili.)
Aggiornamento : ulteriori informazioni sul "dizionario" degli accordi per i tasti:
Fondamentalmente, il dizionario è un trie (grazie, @Adam) che cerchiamo con la corrispondenza del prefisso più lungo. Dettagli:
Nella stenografia della macchina, lo stenografo scrive premendo contemporaneamente più tasti sulla macchina dello stenotipo, quindi rilasciandoli tutti. Lo chiamano "colpo" della tastiera; è come suonare un accordo al pianoforte. I tratti frequenti (ma non sempre) corrispondono a una sillaba della lingua parlata. Come le sillabe, a volte un tratto (accordo) ha un significato tutto suo, altre volte ha solo un significato combinato con i seguenti tratti. (Pensa "bene" contro "bene" seguito da "ciao"). Sebbene saranno fortemente influenzati dalla scuola in cui hanno studiato, ogni stenografo avrà il proprio "dizionario" di ciò che i colpi usano per significare cosa, un dizionario che affineranno continuamente nel corso della loro vita lavorativa. Il dizionario avrà voci in cui la parte stenografica ("steno", in breve) è lunga un tratto o più tratti. Spesso ci saranno più voci con lo stesso tratto iniziale che si differenziano per la loro lunghezza e per i tratti successivi. Ad esempio (e non userò il vero steno qui, solo i segnaposto), potrebbero esserci queste voci:
A = alfa
A / B = alfabeto
A / B / C = alfabetico
A / C = aria condizionata
B = ape
B / C = perché
C = mare
D = cane
D / D = Dee Dee
(Quelle lettere non sono pensate per essere note musicali, solo pennarelli astratti.)
Nota che A
avvia più voci e nota anche come il modo in cui traduci un C
tratto dipende dal fatto che tu abbia precedentemente visto un A
, a B
o che inizi di nuovo.
Si noti inoltre che (sebbene non mostrato nel piccolo esempio sopra), potrebbero esserci più modi per "riprodurre" la stessa parola o frase, anziché solo una. Gli stenografi lo fanno per rendere più semplice il passaggio da una parola precedente alla successiva a seconda della posizione della mano. C'è un'ovvia analogia con la musica lì, e potresti usarla per rendere il tuo flusso di battitura più simile alla musica, al fine di impedire che ciò influisca negativamente sul tuo piano e massimizzare la probabilità che ciò aiuti effettivamente con l'RSI.
Quando traduciamo steno in testo standard, usiamo di nuovo una ricerca con "prefisso più lungo": l'algoritmo di traduzione inizia con il primo tratto mai scritto e cerca le voci che iniziano con quel tratto. Se c'è solo una voce, ed è lunga una traccia, allora possiamo dire con certezza "questa è la voce da usare", produrre il testo corrispondente e ricominciare da capo con la traccia successiva. Ma più probabilmente, quel tratto inizia più voci di varie lunghezze. Quindi guardiamo il prossimo tratto e vediamo se ci sono voci che iniziano con quei due tratti in ordine; e così via fino a quando non avremo una partita.
Quindi, con il dizionario sopra, supponiamo di aver visto questa sequenza:
ACBBCABCABD
Ecco come lo tradurremmo:
A
è l'inizio di tre voci di diversa lunghezza; guarda il prossimo colpo:C
A/C
corrisponde a una sola voce; uscita "aria condizionata" e ricominciare da capo con il colpo successivo:B
B
inizia due voci; guarda il prossimo colpo:B
B/B
non inizia nulla; prende la corrispondenza precedente più lunga ( B
) e produce quella ("ape")
- Avendo output
B
= "ape", abbiamo ancora un B
tratto nel nostro buffer. Inizia due voci, quindi guarda il prossimo tratto:C
B/C
corrisponde a una voce; output "because" e ricominciare con il prossimo tratto:A
A
inizia tre voci; guarda il prossimo colpo:B
A/B
inizia due voci; guarda il prossimo colpo:C
A/B/C
corrisponde solo a una voce; output "alfabetico" e ricominciare con il colpo successivo:A
A
inizia tre voci; guarda il prossimo colpo:B
A/B
inizia due voci; guarda il prossimo colpo:D
A/B/D
non corrisponde a nulla, quindi prendi la corrispondenza precedente più lunga ( A/B
) e usala per generare "alfabeto". Questo ci lascia D
ancora nel buffer.
D
inizia due voci, quindi normalmente guarderemmo il tratto successivo, ma abbiamo elaborato tutti i tratti, quindi consideriamolo in isolamento. In isolamento, si traduce come "cane" in modo che output.
Aspetti di quanto sopra da notare:
- Hai un buffer di tratti che hai letto ma che non hai ancora tradotto.
- Devi sempre abbinare il maggior numero di tratti a una singola voce che puoi.
A/B
dovrebbe essere tradotto come "alfabeto", non "alfa" e "ape".
- (Non mostrato sopra) Potresti avere sequenze di tratti che non puoi tradurre, perché non corrispondono a nulla nel dizionario. (Le persone di Steno usano il nome "untranslate" - ad esempio, con il nostro dizionario, i tratti
E
sarebbero un "untranslate".)
- (Non mostrato sopra) Alcune teorie di steno consentono allo stesso insieme di colpi di significare più di una cosa, in base a un contesto più ampio. La gente di Steno chiama questi "conflitti". Probabilmente vorrai impedirli nel tuo progetto, e infatti quando steno era tradotta manualmente dallo stenografo, i conflitti andavano bene perché sapevano proprio da dove nella frase erano la scelta giusta, ma con l'ascesa della traduzione automatica, sorsero teorie prive di conflitti per evitare di dover passare attraverso il testo tradotto risultante e "risolvere" i conflitti.
- Tradurre in tempo reale (cosa che faresti) significa che se ricevi una corrispondenza parziale, ti consigliamo di tenerlo in attesa durante l'accordo successivo, ma probabilmente fino a un timeout, a quel punto traduci ciò che hai nel buffer nel miglior modo possibile. (O forse non vuoi un timeout; è la tua chiamata.)
- Probabilmente è meglio avere un ictus che dice "ignora il precedente"
- Probabilmente è meglio avere un tratto che dice "cancella completamente il buffer senza emettere nulla"