Differenze tra le versioni di "Alsa e Gambas: Registrare messaggi Midi"
(→Ricezione e memorizzazione dei dati Midi) |
(→Ricezione e memorizzazione dei dati Midi) |
||
Riga 11: | Riga 11: | ||
d As Integer | d As Integer | ||
a[2000000, 3] As Byte | a[2000000, 3] As Byte | ||
− | |||
r As Byte | r As Byte | ||
cc As Byte | cc As Byte | ||
Riga 32: | Riga 31: | ||
jk As Integer | jk As Integer | ||
+ | bpm As Integer = 120 | ||
numeratore As Byte = 4 | numeratore As Byte = 4 | ||
denomSpin As Integer = 4 | denomSpin As Integer = 4 |
Versione delle 06:22, 1 gen 2012
In questa pagina tratteremo del caso in cui vengono ricevuti in entrata dati Midi e memorizzati, al fine di creare al termine un file Midi (.mid).
Possiamo pensare di effettuare la registrazione dei dati Midi in entrata:
- attraverso l'utilizzazione di un altro specifico applicativo in C di supporto, come ad esempio arecordmidi, diciamo in modalità demone;
- oppure mediante la realizzazione in Gambas di apposito algoritmo, come parte del nostro applicativo appositamente dedicata o come applicativo a se stante.
Qui prenderemo in considerazione ovviamente la seconda soluzione. Per ottenere il risultato finale, come per ogni altro caso, si potrà seguire il percorso che si preferisce ed utilizzare, dunque, le funzioni e le istruzioni ritenute più opportune. Appresso proponiamo una soluzione fra le molte possibili, sottolineando e ponendo in rilievo soprattutto i passaggi più importanti da considerare particolarmente.
Indice
Ricezione e memorizzazione dei dati Midi
L'esempio, che faremo per esporre l'argomento, prevede la ricezione di dati Midi provenienti da un dispositivo esterno, per esempio una tastiera, senza uso delle funzioni esterne di ALSA, bensì mediante l'intercettazione dei dati del dispositivo dal file device presente, come già abbiamo avuto modo di imparare in altro capitolo, nel percorso: "/dev/snd/midiC2D0".
exStrum As File d As Integer a[2000000, 3] As Byte r As Byte cc As Byte bl As Integer ndt As Integer ' per il Tempo Delta: aa[2000000] As Float tick[1000000] As Integer ' per le variabili contenenti i dati Midi: blocco[1000000] As String bloccoTD[1000000] As String totDati As Integer ggg[4] As Byte s[4] As Byte tdk As Integer jk As Integer bpm As Integer = 120 numeratore As Byte = 4 denomSpin As Integer = 4 denominatore As Byte = 2 alterazioni As Byte = 0 modo As Byte = 0 Public Sub Form_Open() SpinBox1.Visible = False SpinBox2.Visible = False ComboBox1.Visible = False Label1.Visible = False exStrum = Open "/dev/snd/midiC2D0" For Read Watch End Public Sub File_Read() Dim b As Byte Read #exStrum, b If b = 254 Then Return ' Evita di raccogliere l'evento Midi: "Active Sensing" If b > 127 Then Inc d ' imposta il numero identificativo del blocco di dati e della variabile contenente: anno, mese, giorno, ora:muniti:secondi.millisecondi c = (b - 128) cc = c / 16 c = cc * 16 a[d, 0] = c + 128 + dlMod aa[d] = Now ' ricava anno, mese, giorno, ora:muniti:secondi.millisecondi del 1° dato di un Messaggio Midi Else Inc r ' imposta il numero (superiore a quello 0) del dato all'interno di un blocco a[d, r] = b Endif End
Creare blocchi di dati
Una volta ricevuti tutti i dati dalla tastiera Midi esterna, con un tasto procederemo a calcolare innanzitutto quanti dati sono stati ricevuti, successivamente creeremo dei blocch contenenti 3 dati Midi. Tali blocchi rappresentano ciascuno un Messaggio Midi.
Public Sub Button1_Click() Dim k As Integer Dim numPr, j As Byte For k = 1 To d ' conta i blocchi di dati già impostati in fase di intercettazione dei dati dal dispositivo Midi esterno If (a[k, 0] > 127 And a[k, 0] < 192) Or a[k, 0] > 223 Then numPr = 2 Endif If a[k, 0] > 191 And a[k, 0] < 224 Then numPr = 1 Endif ' muta tutti gli eventuali messaggi Midi NoteON con Velocità = 0 (90 nn 00) ' in corrispondenti e coerenti NoteOFF (80 nn 00): If a[k, 2] = 0 And (a[k, 0] > 143 And a[k, 0] < 160) Then a[k, 0] = a[k, 0] - 16 Endif For j = 0 To numPr ' k rappresenta il numero di blocchi di dati (1 messaggio Midi) blocco[k] = blocco[k] & Chr(a[k, j]) Inc totDati Next Next End
Calcolo del Tempo Delta
Creati i blocchi contenenti i dati di ciascun Messaggio Midi, possiamo passare ad individuare ed impostare il Tempo Delta che separa ciascun blocco (Messaggio Midi).
Public Sub Button2_Click() ' calcola in Tempo Delta Dim hh As Integer For hh = 0 To d If hh > 0 Then ' ottiene il valore in tick del Tempo Delta mediante il metodo "DateDiff" ' basandolo sulla durata di un impulso (tick) relativo ad una data risoluzione del PPQN: tick[hh] = DateDiff(aa[hh - 1], aa[hh], gb.Millisecond) / (((60000000 / bpm) / 384) / 1000) rappr(tick[hh]) Endif Next End
Creare i valori per il Tempo Delta
Come abbiamo già avuto modo di vedere nella pagina "Ricevere dati da uno Standard Midi File", il Tempo Delta con valore superiore a 127 viene definito non con il suo valore reale, bensì con una sua rappresentazione. Pertanto, nel file Midi non avremo i valori reali dei Midi tick superiori al valore 127, tenuto conto della risoluzione per nota da 1/4 del Tempo Delta presente nell'Header Chunk, bensì una loro rappresentazione esadecimale.{3}
Public Sub rappr(deTick As Integer) Dim dT As Integer Dim aaa, bbb, ddd, eee, hhh As Integer Dim fff As Byte dT = deTick bbb = dT Mod 128 ddd = CInt(dT / 128) ggg[hhh] = bbb While ddd > 0 eee = ddd Mod 128 fff = eee Or 128 ddd = CInt(ddd / 128) Inc hhh ggg[hhh] = fff Wend For aaa = hhh To 0 Step -1 Inc tdk s[aaa] = ggg[aaa] bloccoTD[jk] = bloccoTD[jk] & Chr(s[aaa]) ' bloccoTD è la variabile riempita dal valore del Tempo Delta Next ' pulisce la variabile "s" For aaa = hhh To 0 Step -1 s[aaa] = 0 Next Inc jk End
Aggiunta dei principali Meta-Eventi Midi
Anche a scopo didattico aggiungeremo un'altra traccia nel file Midi, la cosiddetta: traccia del Tempo, nella quale porremo i dati relativi ai Meta-eventi della Suddivisione della Misura, del Tempo metronomico e della Tonalità della Scala musicale del brano.
Public Sub Button3_Click() ' immette valore del tempo metronomico bpm = InputBox("Immetti bpm:") End Public Sub Button4_Click() ' immette valori della suddivisione della misura SpinBox1.Visible = True SpinBox2.Visible = True End Public Sub SpinBox1_Change() ' idem numeratore = SpinBox1.Value End Public Sub SpinBox2_Change() ' idem denomSpin = SpinBox2.Value denominatore = Log(denomSpin) / Log(2) End Public Sub Button5_Click() ' immette i valori della tonalità della Scala ComboBox1.Visible = True ComboBox1.Text = "Do M" alterazioni = 0 Label1.Visible = True Label1.Text = "relativa di La m" End Public Sub ComboBox1_Change() ' idem Select Case ComboBox1.Text Case "Do# M" alterazioni = 7 Label1.Text = "relativa di La# m" Case "Fa# M" alterazioni = 6 Label1.Text = "relativa di Re# m" Case "Si M" alterazioni = 5 Label1.Text = "relativa di Sol# m" Case "Mi M" alterazioni = 4 Label1.Text = "relativa di Do# m" Case "La M" alterazioni = 3 Label1.Text = "relativa di Fa# m" Case "Re M" alterazioni = 2 Label1.Text = "relativa di Si m" Case "Sol M" alterazioni = 1 Label1.Text = "relativa di Mi m" Case "Do M" alterazioni = 0 Label1.Text = "relativa di La m" Case "Fa M" alterazioni = -1 Label1.Text = "relativa di Re m" Case "Sib M" alterazioni = -2 Label1.Text = "relativa di Sol m" Case "Mib M" alterazioni = -3 Label1.Text = "relativa di Do m" Case "Lab M" alterazioni = -4 Label1.Text = "relativa di Fa m" Case "Reb M" alterazioni = -5 Label1.Text = "relativa di Sib m" Case "Solb M" alterazioni = -6 Label1.Text = "relativa di Mib m" Case "Dob M" alterazioni = -7 Label1.Text = "relativa di Lab m" End Select End
Ora siamo, dunque, pronti per l'ultima routine, quella che raggrupperà le istruzioni per la realizzazione dell'ultima fase: la costruzione del file standard Midi .mid, che esporremo nel seguente capitolo: "Salvataggio dei dati Midi", ed al quale rimandiamo.
Note
[1] Potremmo anche utilizzare:
- il comando bash "Date":
sSec[1000000] As String sNan[1000000] As String aa[1000000] As Long Public Sub ......() ....... ' qui le istruzioni per intercettare i dati Midi Shell "date +%s" To sSec[dd] ' esprime i secondi dal 01.01.1970 Shell "date +%N" To sNan[dd] ' esprime i nanosecondi in un secondo Inc dd End Public Sub Button2_Click() ' Quindi nella routine spiegata nel precedente paragrafo "Calcolo del Tempo Delta" ' inseriamo le seguenti istruzioni: Dim ee As Integer Dim tick As New Integer[] Dim hh As Integer For ee = 0 To dd Step 3 If ee = dd Then Return ' Quindi ricaviamo i soli millisecondi dai nanosecondi, ' e trasformiamo i secondi in millisecondi sommandoci i millisecondi ' come precedentemente ottenuti: aa[ee] = (Val(sNan[ee]) / 1000000) + (Val(sSec[ee]) * 1000) totaleMillisecondi.Add(hh) totaleMillisecondi[hh] = aa[ee] tick.Add(hh) ....... ' ...e così via il seguito
oppure
- un algoritmo con Timer.
[2] Ricordiamo che la viariabile aa[] è di tipo Float.
[3] Dunque, prima ancora di poter scrivere, ossia di salvare, un file Midi dovremo - fra l'altro - individuare l'algoritmo per trasformare i valori decimali "reali" superiori a 127 del Tempo Delta (ossia del numero dei Midi tick, tenuto conto - ripetiamo - della risoluzione per nota da 1/4 presente nell'Header Chunk) nella loro rappresentazione esadecimale:
Public g[4] As Byte ' la variabile " g " è un array che conterrà i valori esadecimali costituenti la rappresentazione esadecimale dei Midi tick Public h As Integer ' la variabile " h " conterrà la quantità di byte che costituiscono la rappresentazione esadecimale dei Midi tick Public Sub Button2_Click() Dim a, b, c, d, e As Integer Dim rob As Byte h = 0 a = ...' la variabile " a " raccoglie il valore reale decimale dei Midi tick: b = a Mod 128 d = CInt(a / 128) g[h] = b While d > 0 e = d Mod 128 rob = e Or 128 d = CInt(d / 128) Inc h g[h] = rob Wend For a = h To 0 Step -1 g[a] = Hex$(g[a], 2) ' facciamo mostrare distintamente a scopo didattico ciascun valore della "rappresentazione" esadecimale del valore dei Midi tick: Print g[a] Next End