Fondere insieme due file MIDI: differenze tra le versioni
Vai alla navigazione
Vai alla ricerca
(Creata pagina con 'Per fondere (mischiare) due file MIDI con le sole funzioni di Gambas, potrà essere utilizzato il seguente codice: '''Public''' Sub Main() Dim s1, s2, ss2, nt$, file_fina...') |
Nessun oggetto della modifica |
||
| (14 versioni intermedie di uno stesso utente non sono mostrate) | |||
| Riga 1: | Riga 1: | ||
Mostriamo di seguito un codice, sufficientemente commentato, per fondere (mischiare) due file Midi con le sole funzioni di Gambas. | |||
Va precisato che <SPAN Style="text-decoration:underline>la dinamica e modalità dell'esecuzione di un file Midi potrà essere influenzata in modo particolare da diverso [https://www.gambas-it.org/wiki/index.php/La_struttura_di_un_file_Midi#Il_tipo_di_file_Midi tipo di file Midi], da diversa [https://www.gambas-it.org/wiki/index.php/La_struttura_di_un_file_Midi#La_risoluzione_del_Tempo_Delta risoluzione del Tempo-Delta] e dagli eventuali ''[https://www.gambas-it.org/wiki/index.php/La_struttura_di_un_file_Midi#I_Meta-eventi Meta-eventi]'' contenuti nell'altro file Midi</span>. Pertanto si suggerisce di usare il seguente codice con due file Midi, dei quali almeno uno appartenga al tipo '''1''' di file Midi, e che posseggano medesima risoluzione del Tempo-Delta, nonché medesimo valore del ''Meta-evento'' relativo al Tempo metronomico. | |||
Public Sub Main() | |||
Dim s1, s2, | Dim s1, s2, mtrk1, mtrk2, file_finale As String | ||
Dim nt1, nt2 As Byte | Dim nt1, nt2 As Byte | ||
s1 = File.Load("<FONT color=darkgreen>''/percorso/del/'''primo'''/file.mid''</font>") | |||
s2 = File.Load("<FONT color=darkgreen>''/percorso/del/'''secondo'''/file.mid''</font>") | |||
<FONT color=gray>' ''Innanzitutto verifica se almeno uno dei due file appartenga al tipo "1" di file Midi:''</font> | |||
If Asc(s1[9, 1]) + Asc(s2[9, 1]) == 0 Then Error.Raise("Nessuno dei due file appartiene al tipo '1' di file Midi !") | |||
<FONT color=gray>' ''Assicura che il 10° byte del Blocco d'intestazione del file Midi possegga il valore relativo al tipo "1" di file Midi.'' | |||
' ''Assegna il valore "1" mediante la funzione "MkByte()", affinché sia assegnata precisamente la rappresentazione in memoria del valore 1 e non quella ASCII (che in memoria risulta essere &31). Si potrebbe usare in alternativa anche la funzione "'''Chr()'''".''</font> | |||
Mid(s1, 10, 1) = MkByte(1) | |||
<FONT color=gray>' ''Individua il numero di tracce presenti nel primo file:''</font> | |||
nt1 = Asc(s1[11, 1]) <FONT color=gray>' ''...oppure anche:'' '''Byte@(s1[11, 1])''', che in questo caso è usata per restituire un risultato opposto a quello della funzione "MkByte()"</font> | |||
<FONT color=gray>' ''Individua il numero di tracce presenti nel secondo file:''</font> | |||
nt2 = Asc(s2[11, 1]) <FONT color=gray>' ''...oppure anche:'' '''Byte@(s2[11, 1])''', che in questo caso è usata per restituire un risultato opposto a quello della funzione "MkByte()"</font> | |||
<FONT color=gray>' ''Raccoglie del 1° file Midi solo il valore della risoluzione del Tempo-Delta e la parte delle tracce "MTrk":''</font> | |||
mtrk1 = s1[12, s1.Len] | |||
<FONT color=gray>' ''Raccoglie del 2° file Midi solo la parte delle tracce "MTrk":''</font> | |||
mtrk2 = s2[14, s2.Len] | |||
<FONT color=gray>' '' | |||
<FONT color=gray>' ''Estrae e confronta il tempo metronomico dal primo blocco di tracce.'' | |||
' ''Tenere comunque in considerazione che secondo lo standard MIDI, se un file non contiene esplicitamente il meta-evento 0xFF 0x51 ("Set Tempo"), il tempo metronomico predefinito è uguale a 500.000 microsecondi per quarto di nota, cioè 120 bpm.'' | |||
' ''Pertanto, se il parser non trova il meta-evento Set Tempo, esso assume tempo = 500000 microsecondi.''</font> | |||
tempo1 = TrovaTempoMetronomico(mtrk1) | |||
tempo2 = TrovaTempoMetronomico(mtrk2) | |||
If tempo1 <> tempo2 Then | |||
Print "\e[31m\e[1mATTENZIONE: i due file hanno tempi metronomici differenti!\e[0m\n" | |||
Endif | |||
file_finale = s1[0, 11] & MkByte(nt1 + nt2) & mtrk1 & mtrk2 | |||
File.Save("/tmp/nuovo.mid", file_finale) | |||
End | |||
<FONT color=gray>' ''Funzione per trovare il meta-evento 0xFF 0x51 (Set Tempo)''</font> | |||
Private Function TrovaTempoMetronomico(mtrk As String) As Integer | |||
Dim i As Integer = 0 | |||
Dim tempo As Integer | |||
Dim delta, vlqLen As Integer | |||
While i < mtrk.Len - 5 | |||
<FONT color=gray>' ''Legge delta-time:''</font> | |||
delta = LeggiVLQ(mtrk, i, vlqLen) | |||
i += vlqLen | |||
If Asc(mtrk[i]) = &HFF Then | |||
If Asc(mtrk[i + 1]) = &H51 And Asc(mtrk[i + 2]) = 3 Then | |||
tempo = Asc(mtrk[i + 3]) * 65536 + Asc(mtrk[i + 4]) * 256 + Asc(mtrk[i + 5]) | |||
Return tempo | |||
Else | |||
<FONT color=gray>' ''Salta meta-evento generico:''</font> | |||
Dim metaLen As Integer | |||
metaLen = LeggiVLQ(mtrk, i + 2, vlqLen) | |||
i += 2 + vlqLen + metaLen | |||
Endif | |||
Else If Asc(mtrk[i]) >= &H80 And Asc(mtrk[i]) <= &HEF Then | |||
<FONT color=gray>' ''Evento MIDI standard: salta 2 o 3 byte in base al tipo:''</font> | |||
Dim evType As Integer = Asc(mtrk[i]) \ 16 | |||
Select Case evType | |||
Case 8 To 11 | |||
i += 3 | |||
Case 12, 13 | |||
i += 2 | |||
Case 14 | |||
i += 3 | |||
Case Else | |||
i += 1 ' fallback | |||
End Select | |||
Else | |||
<FONT color=gray>' ''SysEx o byte non riconosciuto:''</font> | |||
i += 1 | |||
Endif | |||
Wend | |||
<FONT color=gray>' ''Se non trovato, ritorna valore di default (120 bpm = 500.000 μs):''</font> | |||
Return 500000 | |||
End | |||
<FONT color=gray>' ''Funzione per leggere VLQ(Variable Length Quantity)da posizione 'start'''</font> | |||
Private Function LeggiVLQ(dat As String, start As Integer, ByRef nbytes As Integer) As Integer | |||
Dim val As Integer = 0 | |||
Dim b As Integer | |||
nbytes = 0 | |||
Repeat | |||
b = Asc(dat[start + nbytes]) | |||
val = (val * 128) Or (b And &H7F) | |||
Inc nbytes | |||
Until (b And &H80) = 0 Or nbytes > 4 | |||
Return val | |||
End | |||
Versione attuale delle 15:14, 26 lug 2025
Mostriamo di seguito un codice, sufficientemente commentato, per fondere (mischiare) due file Midi con le sole funzioni di Gambas.
Va precisato che la dinamica e modalità dell'esecuzione di un file Midi potrà essere influenzata in modo particolare da diverso tipo di file Midi, da diversa risoluzione del Tempo-Delta e dagli eventuali Meta-eventi contenuti nell'altro file Midi. Pertanto si suggerisce di usare il seguente codice con due file Midi, dei quali almeno uno appartenga al tipo 1 di file Midi, e che posseggano medesima risoluzione del Tempo-Delta, nonché medesimo valore del Meta-evento relativo al Tempo metronomico.
Public Sub Main()
Dim s1, s2, mtrk1, mtrk2, file_finale As String
Dim nt1, nt2 As Byte
s1 = File.Load("/percorso/del/primo/file.mid")
s2 = File.Load("/percorso/del/secondo/file.mid")
' Innanzitutto verifica se almeno uno dei due file appartenga al tipo "1" di file Midi:
If Asc(s1[9, 1]) + Asc(s2[9, 1]) == 0 Then Error.Raise("Nessuno dei due file appartiene al tipo '1' di file Midi !")
' Assicura che il 10° byte del Blocco d'intestazione del file Midi possegga il valore relativo al tipo "1" di file Midi.
' Assegna il valore "1" mediante la funzione "MkByte()", affinché sia assegnata precisamente la rappresentazione in memoria del valore 1 e non quella ASCII (che in memoria risulta essere &31). Si potrebbe usare in alternativa anche la funzione "Chr()".
Mid(s1, 10, 1) = MkByte(1)
' Individua il numero di tracce presenti nel primo file:
nt1 = Asc(s1[11, 1]) ' ...oppure anche: Byte@(s1[11, 1]), che in questo caso è usata per restituire un risultato opposto a quello della funzione "MkByte()"
' Individua il numero di tracce presenti nel secondo file:
nt2 = Asc(s2[11, 1]) ' ...oppure anche: Byte@(s2[11, 1]), che in questo caso è usata per restituire un risultato opposto a quello della funzione "MkByte()"
' Raccoglie del 1° file Midi solo il valore della risoluzione del Tempo-Delta e la parte delle tracce "MTrk":
mtrk1 = s1[12, s1.Len]
' Raccoglie del 2° file Midi solo la parte delle tracce "MTrk":
mtrk2 = s2[14, s2.Len]
' Estrae e confronta il tempo metronomico dal primo blocco di tracce.
' Tenere comunque in considerazione che secondo lo standard MIDI, se un file non contiene esplicitamente il meta-evento 0xFF 0x51 ("Set Tempo"), il tempo metronomico predefinito è uguale a 500.000 microsecondi per quarto di nota, cioè 120 bpm.
' Pertanto, se il parser non trova il meta-evento Set Tempo, esso assume tempo = 500000 microsecondi.
tempo1 = TrovaTempoMetronomico(mtrk1)
tempo2 = TrovaTempoMetronomico(mtrk2)
If tempo1 <> tempo2 Then
Print "\e[31m\e[1mATTENZIONE: i due file hanno tempi metronomici differenti!\e[0m\n"
Endif
file_finale = s1[0, 11] & MkByte(nt1 + nt2) & mtrk1 & mtrk2
File.Save("/tmp/nuovo.mid", file_finale)
End
' Funzione per trovare il meta-evento 0xFF 0x51 (Set Tempo)
Private Function TrovaTempoMetronomico(mtrk As String) As Integer
Dim i As Integer = 0
Dim tempo As Integer
Dim delta, vlqLen As Integer
While i < mtrk.Len - 5
' Legge delta-time:
delta = LeggiVLQ(mtrk, i, vlqLen)
i += vlqLen
If Asc(mtrk[i]) = &HFF Then
If Asc(mtrk[i + 1]) = &H51 And Asc(mtrk[i + 2]) = 3 Then
tempo = Asc(mtrk[i + 3]) * 65536 + Asc(mtrk[i + 4]) * 256 + Asc(mtrk[i + 5])
Return tempo
Else
' Salta meta-evento generico:
Dim metaLen As Integer
metaLen = LeggiVLQ(mtrk, i + 2, vlqLen)
i += 2 + vlqLen + metaLen
Endif
Else If Asc(mtrk[i]) >= &H80 And Asc(mtrk[i]) <= &HEF Then
' Evento MIDI standard: salta 2 o 3 byte in base al tipo:
Dim evType As Integer = Asc(mtrk[i]) \ 16
Select Case evType
Case 8 To 11
i += 3
Case 12, 13
i += 2
Case 14
i += 3
Case Else
i += 1 ' fallback
End Select
Else
' SysEx o byte non riconosciuto:
i += 1
Endif
Wend
' Se non trovato, ritorna valore di default (120 bpm = 500.000 μs):
Return 500000
End
' Funzione per leggere VLQ(Variable Length Quantity)da posizione 'start'
Private Function LeggiVLQ(dat As String, start As Integer, ByRef nbytes As Integer) As Integer
Dim val As Integer = 0
Dim b As Integer
nbytes = 0
Repeat
b = Asc(dat[start + nbytes])
val = (val * 128) Or (b And &H7F)
Inc nbytes
Until (b And &H80) = 0 Or nbytes > 4
Return val
End