|
|
(36 versioni intermedie di uno stesso utente non sono mostrate) |
Riga 1: |
Riga 1: |
− | 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).
| + | #REDIRECT [[ALSA_e_Gambas_-_Registrare_messaggi_Midi]] |
− | <BR>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.
| |
− | <P>Qui prenderemo in considerazione ovviamente la seconda soluzione. Per ottenenre 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.</p>
| |
− | | |
− | ===Ricezione e memorizzazione dei dati Midi===
| |
− | L'esempio, che faremo per esporre l'argomento, prevede la ricezione di dati Midi (per semplicità terremo conto solo dei messaggi NoteON e NoteOFF) 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 [[Alsa_e_Gambas:_Ricezione_senza_funzioni_ALSA|capitolo]], nel percorso: ''"/dev/snd/midiC2D0"''.
| |
− | | |
− | exStrum As File
| |
− | d As Integer
| |
− | a As New Byte[]
| |
− | aa As New Float[]
| |
− | dd As Integer
| |
− | bpm As Integer = 120
| |
− |
| |
− | f As Integer
| |
− | bl As Integer
| |
− | ndt As Integer
| |
− |
| |
− | tick As New Byte[]
| |
− | totaleMillisecondi As New Long[]
| |
− |
| |
− | ggg[4] As Byte
| |
− | s[4] As Byte
| |
− | tdk As Integer
| |
− | jk As Integer
| |
− |
| |
− | 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 ''<Font Color= #006400>' Evita di raccogliere l'evento Midi: "Active Sensing"''</font>
| |
− |
| |
− |
| |
− | a.Add(d)
| |
− | a[d] = b
| |
− |
| |
− | Inc d
| |
− |
| |
− | f = d - 1
| |
− |
| |
− | ''<Font Color= #006400>' ricava anno, mese, giorno, ora:muniti:secondi.millisecondi di ciascun evento:''</font>
| |
− | ''<Font Color= #006400>' serviranno per determinare il Tempo Delta di ciascuno di essi.''</font>
| |
− | aa.Add(dd)
| |
− | aa[dd] = Now
| |
− | Inc dd
| |
− |
| |
− | '''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 (NoteON oppure NoteOFF).
| |
− | | |
− | '''Public''' Sub Button1_Click()
| |
− |
| |
− | Dim k, j, n As Integer
| |
− |
| |
− |
| |
− | For k = 0 To (d - 1) / 3 ''<Font Color= #006400>'.../3 perché ogni messaggio Midi è formato da 3 dati''</font>
| |
− |
| |
− | ''<Font Color= #006400>' muta tutti gli eventuali messaggi Midi NoteON con Velocità = 0 (90 nn 00)''</font>
| |
− | ''<Font Color= #006400>' in corrispondenti e coerenti NoteOFF (80 nn 00):''</font>
| |
− | If a[n] = 144 And a[n + 2] = 0 Then
| |
− | a[n] = 128
| |
− | Endif
| |
− |
| |
− | n = n + 3
| |
− |
| |
− | For j = 0 To 2
| |
− | blocco.Add(bl) ''<Font Color= #006400>' bl rappresenta il numero di blocchi da 3 dati (1 messaggio Midi)''</font>
| |
− | blocco[bl] = blocco[bl] & Chr(a[ndt])
| |
− |
| |
− | Inc ndt
| |
− | Next
| |
− |
| |
− | Inc bl
| |
− |
| |
− | 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() ''<Font Color= #006400>' calcola in Tempo Delta''</font>
| |
− |
| |
− | Dim ee As Integer
| |
− | Dim tick As New Integer[]
| |
− | Dim hh As Integer
| |
− | Dim intero As Long
| |
− | Dim frazione As Integer
| |
− |
| |
− | For ee = 0 To dd Step 3 ''<Font Color= #006400>' Ogni tre dati (i 3 dati di ciascun Messaggio Midi: NoteON e NoteOFF)...''</font>
| |
− | If ee = dd Then Return
| |
− | ''<Font Color= #006400>' restituisce i millisecondi trascorsi dalla "data Gambas" fino a ieri:''</font>
| |
− | intero = (Fix(CFloat(aa[ee])) * 86400000)
| |
− |
| |
− | ''<Font Color= #006400>' restituisce i millisecondi dalla mezzanotte del giorno attuale''</font>
| |
− | ''<Font Color= #006400>' sino al presente attimo:''</font>
| |
− | frazione = (Fix(Frac(CFloat(aa[ee])) * 100000000))
| |
− |
| |
− | totaleMillisecondi.Add(hh)
| |
− | totaleMillisecondi[hh] = intero + frazione
| |
− |
| |
− | tick.Add(hh)
| |
− | If hh > 0 Then
| |
− |
| |
− | ''<Font Color= #006400>' procede ad ottenere il valore in tick del Tempo Delta''</font>
| |
− | ''<Font Color= #006400>' basandolo sulla durata di un impulso (tick) relativo ad una data risoluzione del PPQN:''</font>
| |
− | tick[hh] = (totaleMillisecondi[hh] - totaleMillisecondi[hh - 1]) / (((60000000 / bpm) / 384) / 1000)
| |
− |
| |
− | ''<Font Color= #006400>' corregge lo sfalzamento dell'orologio (in questo nostro caso di 157 ms)''</font>
| |
− | tick[hh] = tick[hh] - ((tick[hh] * 157) / 1000)
| |
− |
| |
− | ''<Font Color= #006400>' chiama la subroutine per la conversione e creazione del Tempo Delta in tick''</font>
| |
− | rappr(tick[hh])
| |
− |
| |
− | Endif
| |
− |
| |
− | Inc hh
| |
− |
| |
− | Next
| |
− |
| |
− | '''End'''
| |
− | | |
− | ===Creare i valori per il ''Tempo Delta''===
| |
− | Come abbiamo già avuto modo di vedere nella pagina "[[Alsa_e_Gambas:_Ricevere_dati_da_smf#Il_Tempo_Delta_come_dato_a_lunghezza_variabile|''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.{[[#Note|1]]}
| |
− |
| |
− | 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]) ''<Font Color= #006400>' bloccoTD è la variabile riempita dal valore del Tempo Delta''</font>
| |
− | Next
| |
− |
| |
− | ''<Font Color= #006400>' pulisce la variabile "s"''</font>
| |
− | 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 ''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() ''<Font Color= #006400>' immette valore del tempo metronomico''</font>
| |
− |
| |
− | bpm = InputBox("Immetti bpm:")
| |
− |
| |
− | '''End'''
| |
− |
| |
− | '''Public''' Sub Button4_Click() ''<Font Color= #006400>' immette valori della suddivisione della misura''</font>
| |
− |
| |
− | SpinBox1.Visible = True
| |
− | SpinBox2.Visible = True
| |
− |
| |
− | '''End'''
| |
− |
| |
− | '''Public''' Sub SpinBox1_Change() ''<Font Color= #006400>' idem''</font>
| |
− |
| |
− | numeratore = SpinBox1.Value
| |
− |
| |
− | '''End'''
| |
− |
| |
− | '''Public''' Sub SpinBox2_Change() ''<Font Color= #006400>' idem''</font>
| |
− |
| |
− | denomSpin = SpinBox2.Value
| |
− |
| |
− | denominatore = Log(denomSpin) / Log(2)
| |
− |
| |
− | '''End'''
| |
− |
| |
− |
| |
− | '''Public''' Sub Button5_Click() ''<Font Color= #006400>' immette i valori della tonalità della Scala''</font>
| |
− |
| |
− | ComboBox1.Visible = True
| |
− | ComboBox1.Text = "Do M"
| |
− | alterazioni = 0
| |
− | Label1.Visible = True
| |
− | Label1.Text = "relativa di La m"
| |
− |
| |
− | '''End'''
| |
− |
| |
− | '''Public''' Sub ComboBox1_Change() ''<Font Color= #006400>' idem''</font>
| |
− |
| |
− | 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'''
| |
− | | |
− | | |
− | <P>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: "[[Alsa_e_Gambas:_Salvataggio_dei_dati|''Salvataggio dei dati Midi'']]", ed al quale rimandiamo.</p>
| |
− | | |
− | ==Note==
| |
− | [1] 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''" <SPAN style="text-decoration:underline">superiori a 127</span> 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 ''<Font Color= #006400>' la variabile " g " è un array che conterrà i valori esadecimali costituenti la rappresentazione esadecimale dei Midi ''tick''</font>
| |
− | Public h As Integer ''<Font Color= #006400>' la variabile " h " conterrà la quantità di byte che costituiscono la rappresentazione esadecimale dei Midi ''tick''</font>
| |
− |
| |
− | '''Public''' Sub Button2_Click()
| |
− |
| |
− | Dim a, b, c, d, e As Integer
| |
− | Dim rob As Byte
| |
− |
| |
− | h = 0
| |
− |
| |
− | a = ...''<Font Color= #006400>' la variabile " a " raccoglie il valore reale decimale dei Midi ''tick'':</font>
| |
− |
| |
− | 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)
| |
− | ''<Font Color= #006400>' facciamo mostrare distintamente a scopo didattico ciascun valore della "rappresentazione" esadecimale del valore dei Midi ''tick'':</font>
| |
− | Print g[a]
| |
− | Next
| |
− |
| |
− | '''End'''
| |