Differenze tra le versioni di "Alsa e Gambas: Registrare messaggi Midi"

Da Gambas-it.org - Wikipedia.
(Ricezione e memorizzazione dei dati Midi)
Riga 3: Riga 3:
 
* attraverso l'utilizzazione di un altro specifico applicativo in C di supporto, come ad esempio ''arecordmidi'', diciamo in modalità ''demone'';
 
* 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.
 
* 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 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.</p>
+
<P>Qui prenderemo in considerazione ovviamente la seconda soluzione.</p>
  
 
===Ricezione e memorizzazione dei dati Midi===
 
===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 [[Alsa_e_Gambas:_Ricezione_senza_funzioni_ALSA|capitolo]], nel percorso: ''"/dev/snd/midiC2D0"''.
+
Di seguito eviteremo di esporre codice esemplificativo, ritenendo che ciascun programmatore possa e debba scegliere le soluzioni algoritmiche che riterrà più opportune e migliori. Riporteremo con proposte di codice soltanto le parti più delicate anche a fini esplicativi di concetti più complessi.
 
+
Sottolineeremo soltanto che nella fase di registrazione dei dati bisognerà individuare, (mediante il ''Timer'', oppure prendendo il tempo dell'orologio interno con la funzione ''Time(Now) |[[#Note|1]]|) il tempo che distanzia il primo evento da un tempo iniziale assoluto, nonché i tempi che distanziano ciascun Messaggio Midi dal precedente.
exStrum As File
 
d As Integer
 
a[2000000, 3] As Byte
 
r As Byte
 
cc As Byte
 
 
bl As Integer
 
ndt As Integer
 
 
''<Font Color= #006400>' per il Tempo Delta:''</font>
 
aa[2000000] As Float
 
tick[1000000] As Integer
 
 
''<Font Color= #006400>' per le variabili contenenti i dati Midi:''</font>
 
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  ''<Font Color= #006400>' Evita di raccogliere l'evento Midi: "Active Sensing"''</font>
 
 
 
    If b > 127 Then
 
    Inc d      ''<Font Color= #006400>' imposta il numero identificativo del blocco di dati e della variabile contenente: anno, mese, giorno, ora:muniti:secondi.millisecondi''</font>
 
    c = (b - 128)
 
    cc = c / 16
 
    c = cc * 16
 
    a[d, 0] = c + 128 + dlMod
 
    aa[d] = Now  ''<Font Color= #006400>' ricava anno, mese, giorno, ora:muniti:secondi.millisecondi del 1° dato di un Messaggio Midi''</font>
 
  Else
 
    Inc r      ''<Font Color= #006400>' imposta il numero (superiore a quello 0) del dato all'interno di un blocco''</font>
 
    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      ''<Font Color= #006400>' conta i blocchi di dati già impostati in fase di intercettazione dei dati dal dispositivo Midi esterno''</font>
 
    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
 
 
  ''<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[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
 
    ''<Font Color= #006400>' k rappresenta il numero di blocchi di dati (1 messaggio Midi)''</font>
 
      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()  ''<Font Color= #006400>' calcola in Tempo Delta''</font>
 
 
Dim hh As Integer
 
 
  For hh = 0 To d
 
    If hh > 0 Then
 
    ''<Font Color= #006400>' ottiene il valore in tick del Tempo Delta mediante il metodo "DateDiff"''</font>
 
    ''<Font Color= #006400>' basandolo sulla durata di un impulso (tick) relativo ad una data risoluzione del PPQN:''</font>
 
      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''===
 
===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|3]]}
+
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|2]]|
 
   
 
   
 
  Public Sub rappr(deTick As Integer)
 
  Public Sub rappr(deTick As Integer)
Riga 163: Riga 52:
 
  '''End'''
 
  '''End'''
  
===Aggiunta dei principali Meta-Eventi Midi===
+
<P>Ora siamo, dunque, pronti per la parte del codice 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>
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() ''<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>
 
  
  
Riga 278: Riga 73:
 
  '''End'''
 
  '''End'''
 
   
 
   
'''Public''' Sub Button2_Click()  ''<Font Color= #006400>' Quindi nella routine spiegata nel precedente paragrafo "Calcolo del Tempo Delta"''</font>
+
[2] 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:
''<Font Color= #006400>' inseriamo le seguenti istruzioni:''</font>
 
 
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
 
 
''<Font Color= #006400>' Quindi ricaviamo i soli millisecondi dai nanosecondi,''</font>
 
''<Font Color= #006400>' e trasformiamo i secondi in millisecondi sommandoci i millisecondi''</font>
 
''<Font Color= #006400>' come precedentemente ottenuti:''</font>
 
  aa[ee] = (Val(sNan[ee]) / 1000000) + (Val(sSec[ee]) * 1000)
 
 
  totaleMillisecondi.Add(hh)
 
  totaleMillisecondi[hh] = aa[ee]
 
 
  tick.Add(hh)
 
 
 
  ....... ''<Font Color= #006400>' ...e così via il seguito''</font>
 
 
 
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''" <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 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>

Versione delle 17:08, 16 lug 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.

Ricezione e memorizzazione dei dati Midi

Di seguito eviteremo di esporre codice esemplificativo, ritenendo che ciascun programmatore possa e debba scegliere le soluzioni algoritmiche che riterrà più opportune e migliori. Riporteremo con proposte di codice soltanto le parti più delicate anche a fini esplicativi di concetti più complessi. Sottolineeremo soltanto che nella fase di registrazione dei dati bisognerà individuare, (mediante il Timer, oppure prendendo il tempo dell'orologio interno con la funzione Time(Now) |1|) il tempo che distanzia il primo evento da un tempo iniziale assoluto, nonché i tempi che distanziano ciascun Messaggio Midi dal precedente.

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. |2|

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

Ora siamo, dunque, pronti per la parte del codice 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

[2] 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