Differenze tra le versioni di "Conoscere la durata di un file Midi con le sole risorse di Gambas"
(17 versioni intermedie di uno stesso utente non sono mostrate) | |||
Riga 1: | Riga 1: | ||
− | Il procedimento, seguito per ottenere la durata in secondi di un file Midi | + | Il procedimento, seguito per ottenere la durata in secondi di un file Midi deve tenere in debita considerazione la circostanza che all'interno di un brano musicale possono insistere una o più variazioni del ''tempo metronomico''. La durata del file Midi rappresenta così la somma delle singole durate determinate dagli eventuali cambi del ''tempo metronomico'' all'interno del file Midi. |
Ciò richiede innanzitutto la conoscenza dei seguenti elementi: | Ciò richiede innanzitutto la conoscenza dei seguenti elementi: | ||
* ''tempo metronomico'': movimenti (battute) per minuto (bpm), che si otterrà a sua volta dallo specifico Meta-evento FF 51; | * ''tempo metronomico'': movimenti (battute) per minuto (bpm), che si otterrà a sua volta dallo specifico Meta-evento FF 51; | ||
− | * ''tick reali'' dell'intera traccia Midi più grande, ossia la quantità di ''tick'' ottenuti dalle somme dei ''Tempi Delta'' ( | + | * ''tick reali'' dell'intera traccia Midi più grande, ossia la quantità di ''tick'' ottenuti dalle somme dei ''Tempi Delta'' (quest'ultimi convertiti ciascuno dal proprio formato ''a lunghezza variabile'', nel quale sono espressi nel file Midi) fra ogni evento Midi e quello immediatamente successivo; |
− | * ''risoluzione del Tempo Delta'' (TΔ). | + | * ''risoluzione del Tempo Delta'' (TΔ), espressa in ordine ''Big-Endian'' nel 13° e nel 14° byte del file Midi. |
− | Pertanto, per ciascun "tratto" parziale di durata devono essere ottenuti il ''tempo metronomico'' (bpm), leggendolo dall'apposito Meta-evento FF 51, e i ''tick'' reali. Da | + | Pertanto, per ciascun "tratto" parziale di durata devono essere ottenuti il ''tempo metronomico'' (bpm), leggendolo dall'apposito Meta-evento FF 51, e i ''tick'' reali. Da tali elementi, considerando anche la risoluzione del ''Tempo Delta'' (TΔ), si otterrà per ogni "tratto" la durata in secondi, adottando la seguente formula: |
((60 / bpm) / risoluzione_TΔ) * tick_reali = secondi | ((60 / bpm) / risoluzione_TΔ) * tick_reali = secondi | ||
− | Successivamente bisogna ricavare anche il ''tempo metronomico'' e la quantità di ''tick'' reali maggiore fra le tracce (MTrk), e da questi due elementi, unitamente alla costante risoluzione del ''Tempo Delta'', si otterrà la durata in secondi del "tratto finale" (per "tratto finale" qui intendiamo la quantità di ''Tempo Delta'' compresa fra l'ultimo Meta-evento FF 51 e il Meta-evento di chiusura | + | Successivamente bisogna ricavare anche il ''tempo metronomico'' e la quantità di ''tick'' reali maggiore fra le tracce (MTrk), e da questi due elementi, unitamente alla costante risoluzione del ''Tempo Delta'', si otterrà la durata in secondi del "tratto finale" (per "tratto finale" qui intendiamo la quantità di ''Tempo Delta'' compresa fra l'ultimo Meta-evento FF 51 e il Meta-evento di chiusura FF 2F 00 della traccia avente la quantità maggiore di tick rispetto alle altre). |
− | In ogni caso va ricordato che il valore predefinito del ''tempo metronomico'' è pari a 120 bpm. | + | In ogni caso va ricordato che il valore <SPAN Style="text-decoration:underline">predefinito</span> del ''tempo metronomico'' è pari a 120 bpm. |
Si potrà avere dunque, ad esempio, una situazione di questo genere: | Si potrà avere dunque, ad esempio, una situazione di questo genere: | ||
− | 0------FF51--------FF51----------FF51-------------- | + | 0------FF51--------FF51----------FF51--------------FF2F00 (Traccia Midi di maggiore durata) |
| 120 bmp1 bmp2 | bmp3 | | | 120 bmp1 bmp2 | bmp3 | | ||
|______|___________|_____________|_________________| | |______|___________|_____________|_________________| | ||
Riga 42: | Riga 42: | ||
− | Dunque, per conoscere la durata di un | + | Dunque, per conoscere la durata di un file Midi mediante le sole risorse di Gambas, è possibile utilizzare un codice come il seguente, nel quale si otterranno anche le durate delle singole tracce ''MTrk'' presenti nel file ed alcune generiche informazioni: |
'''Public''' Sub Main() | '''Public''' Sub Main() | ||
Riga 54: | Riga 54: | ||
Dim f, durata As Float | Dim f, durata As Float | ||
− | + | fileMidi = "<FONT Color=gray>''/percorso/del/file.mid''</font>" | |
− | + | Print "File Midi: "; fileMidi | |
− | + | ||
− | + | fl = Open fileMidi For Read | |
− | + | If IsNull(fl) Then Error.Raise("Impossibile aprire il file !") | |
− | + | ||
− | + | Read #fl, s, 4 | |
− | + | If s <> "MThd" Then Error.Raise("Il file non è uno standard Midi !") | |
− | + | Print "Dimensione: "; Lof(fl); " byte" | |
− | + | Seek #fl, 9 | |
− | + | Read #fl, c | |
− | + | Print "Tipo file: "; c | |
− | + | Read #fl, tr | |
− | + | Print "Numero tracce: "; Format(tr, "###") | |
− | + | Read #fl, td | |
− | + | td = Rol(td, 8) | |
− | + | Print "Risoluzione TΔ: "; Format(td, "###") | |
− | + | Avanza(fl, 8) | |
− | + | ||
− | + | bpm = 120 | |
− | + | ||
− | + | Repeat | |
− | + | tot = 0 | |
− | + | Do | |
− | + | tot += legge_var(fl) | |
− | + | Read #fl, b | |
− | + | If b And 128 Then <FONT Color=gray>' ''Status running''</font> | |
− | + | cmd = b | |
− | + | If b < &F1 Then ultimo = cmd | |
− | + | av = 2 | |
− | + | Else | |
− | + | cmd = ultimo | |
− | + | av = 1 | |
− | + | Endif | |
− | + | tipocmd = Shr(cmd, 4) | |
− | + | Select Case tipocmd | |
− | + | Case 8 To 11 | |
− | + | Avanza(fl, av) | |
− | + | Case 12 To 13 | |
− | + | Avanza(fl, 1) | |
− | + | Case 14 | |
− | + | Avanza(fl, av) | |
− | + | Case 15 | |
− | + | If b = &F0 Then <FONT Color=gray>' ''Evento SysEx''</font> | |
− | + | Repeat | |
− | + | b = Read #fl As Byte | |
− | + | Until b = &F7 | |
− | + | Else | |
− | + | Read #fl, b | |
− | + | Select Case b | |
− | + | Case &51 | |
− | + | durata += DurataParziale(bpm, td, tot) | |
− | + | tratto1 += tot | |
− | + | tot = 0 | |
− | + | Avanza(fl, 1) | |
− | + | hbpm = 0 | |
− | + | For c = 2 To 0 Step -1 | |
− | + | Read #fl, n | |
− | + | hbpm += Shl(CInt(n), 8 * c) | |
− | + | Next | |
− | + | bpm = 60000000 / hbpm | |
− | + | Case &2F | |
− | + | mx = Max(mx, tot) | |
− | + | Exit | |
− | + | Case Else | |
− | + | Read #fl, b | |
− | + | Avanza(fl, b) | |
− | + | End Select | |
− | + | Endif | |
− | + | End Select | |
− | + | Loop | |
− | + | Dec tr | |
− | + | If tr > 0 Then Avanza(fl, 9) | |
− | + | Until tr = 0 | |
− | + | ||
− | + | fl.Close | |
− | + | ||
− | + | f = DurataParziale(bpm, td, Max(mx, tratto1) - tratto1) | |
− | + | ||
− | + | Print "\nDURATA: \e[31m\e[1m"; CStr(Time(0, 0, 0, (f + durata) * 1000)); "\e[0m" | |
− | + | ||
'''End''' | '''End''' | ||
Riga 142: | Riga 142: | ||
Dim b, n As Byte | Dim b, n As Byte | ||
− | + | For b = 1 To av | |
− | + | Read #mf, n | |
− | + | Next | |
− | + | ||
'''End''' | '''End''' | ||
− | '''Private''' Function legge_var(mf As File) As Integer <FONT Color=gray>''Legge un numero a lunghezza-variabile (Tempo Delta)''</font> | + | '''Private''' Function legge_var(mf As File) As Integer <FONT Color=gray>' ''Legge un numero a lunghezza-variabile (Tempo Delta)''</font> |
− | + | Dim vl As Integer | |
− | + | Dim c As Byte | |
Repeat | Repeat |
Versione attuale delle 17:27, 12 giu 2021
Il procedimento, seguito per ottenere la durata in secondi di un file Midi deve tenere in debita considerazione la circostanza che all'interno di un brano musicale possono insistere una o più variazioni del tempo metronomico. La durata del file Midi rappresenta così la somma delle singole durate determinate dagli eventuali cambi del tempo metronomico all'interno del file Midi.
Ciò richiede innanzitutto la conoscenza dei seguenti elementi:
- tempo metronomico: movimenti (battute) per minuto (bpm), che si otterrà a sua volta dallo specifico Meta-evento FF 51;
- tick reali dell'intera traccia Midi più grande, ossia la quantità di tick ottenuti dalle somme dei Tempi Delta (quest'ultimi convertiti ciascuno dal proprio formato a lunghezza variabile, nel quale sono espressi nel file Midi) fra ogni evento Midi e quello immediatamente successivo;
- risoluzione del Tempo Delta (TΔ), espressa in ordine Big-Endian nel 13° e nel 14° byte del file Midi.
Pertanto, per ciascun "tratto" parziale di durata devono essere ottenuti il tempo metronomico (bpm), leggendolo dall'apposito Meta-evento FF 51, e i tick reali. Da tali elementi, considerando anche la risoluzione del Tempo Delta (TΔ), si otterrà per ogni "tratto" la durata in secondi, adottando la seguente formula:
((60 / bpm) / risoluzione_TΔ) * tick_reali = secondi
Successivamente bisogna ricavare anche il tempo metronomico e la quantità di tick reali maggiore fra le tracce (MTrk), e da questi due elementi, unitamente alla costante risoluzione del Tempo Delta, si otterrà la durata in secondi del "tratto finale" (per "tratto finale" qui intendiamo la quantità di Tempo Delta compresa fra l'ultimo Meta-evento FF 51 e il Meta-evento di chiusura FF 2F 00 della traccia avente la quantità maggiore di tick rispetto alle altre).
In ogni caso va ricordato che il valore predefinito del tempo metronomico è pari a 120 bpm.
Si potrà avere dunque, ad esempio, una situazione di questo genere:
0------FF51--------FF51----------FF51--------------FF2F00 (Traccia Midi di maggiore durata) | 120 bmp1 bmp2 | bmp3 | |______|___________|_____________|_________________| tratto iniziale durata tratto finale |__________________________________________________| Durata totale del file Midi
In altri termini si procederà a:
1) estrarre il numero dei tick reali compresi fra l'inizio assoluto delle tracce Midi (punto TΔ = 0) e l'ulimo Meta-evento FF 51, ossia fino all'ultimo Tempo Delta precedente l'ultimo Meta-evento FF 51): "1° tratto" della durata del file Midi. Questo andrà ottenuto estraendo i tick reali per ogni tratto compreso tra i vari Meta-eventi FF 51 del "1° tratto".
2) estrarre il numero dei tick reali più grande fra le tracce esistenti del file Midi. Ciò significa che si dovrà ottenere il numero di tick reali della traccia che dura di più.
3) ottenere i tick reali del "tratto finale" più lungo fra le tracce esistenti, sottraendo i tick reali del "tratto iniziale" (punto 1) ai tick reali della traccia più duratura (punto 2).
4) convertire in secondi separatamente i tick reali di ciascun tratto costituente il "tratto iniziale".
5) convertire in secondi i tick reali del "tratto finale".
6) sommare i valori temporali, espressi in secondi, dei singoli tratti (punto 4) costituenti il "tratto iniziale" della durata del file Midi.
Esempio pratico:
a) 77959 tick reali della traccia più duratura;
b) 52992 tick reali del "tratto iniziale";
c) 77952 - 52992 = 24960 tick reali del "tratto finale" più lungo fra le tracce esistenti;
d) conversione in secondi di ciascun singolo tratto costituente il "tratto iniziale" della durata del file Midi;
e) secondi_tratto_iniziale + secondi_tratto_finale = durata effettiva del file Midi
Dunque, per conoscere la durata di un file Midi mediante le sole risorse di Gambas, è possibile utilizzare un codice come il seguente, nel quale si otterranno anche le durate delle singole tracce MTrk presenti nel file ed alcune generiche informazioni:
Public Sub Main() Dim fl As File Dim fileMidi, s As String Dim hbpm, tot, mx, tratto1 As Integer Dim td, bpm, c As Short Dim tr, b, n, av As Byte Dim cmd, tipocmd, ultimo As Byte Dim f, durata As Float fileMidi = "/percorso/del/file.mid" Print "File Midi: "; fileMidi fl = Open fileMidi For Read If IsNull(fl) Then Error.Raise("Impossibile aprire il file !") Read #fl, s, 4 If s <> "MThd" Then Error.Raise("Il file non è uno standard Midi !") Print "Dimensione: "; Lof(fl); " byte" Seek #fl, 9 Read #fl, c Print "Tipo file: "; c Read #fl, tr Print "Numero tracce: "; Format(tr, "###") Read #fl, td td = Rol(td, 8) Print "Risoluzione TΔ: "; Format(td, "###") Avanza(fl, 8) bpm = 120 Repeat tot = 0 Do tot += legge_var(fl) Read #fl, b If b And 128 Then ' Status running cmd = b If b < &F1 Then ultimo = cmd av = 2 Else cmd = ultimo av = 1 Endif tipocmd = Shr(cmd, 4) Select Case tipocmd Case 8 To 11 Avanza(fl, av) Case 12 To 13 Avanza(fl, 1) Case 14 Avanza(fl, av) Case 15 If b = &F0 Then ' Evento SysEx Repeat b = Read #fl As Byte Until b = &F7 Else Read #fl, b Select Case b Case &51 durata += DurataParziale(bpm, td, tot) tratto1 += tot tot = 0 Avanza(fl, 1) hbpm = 0 For c = 2 To 0 Step -1 Read #fl, n hbpm += Shl(CInt(n), 8 * c) Next bpm = 60000000 / hbpm Case &2F mx = Max(mx, tot) Exit Case Else Read #fl, b Avanza(fl, b) End Select Endif End Select Loop Dec tr If tr > 0 Then Avanza(fl, 9) Until tr = 0 fl.Close f = DurataParziale(bpm, td, Max(mx, tratto1) - tratto1) Print "\nDURATA: \e[31m\e[1m"; CStr(Time(0, 0, 0, (f + durata) * 1000)); "\e[0m" End Private Procedure Avanza(mf As File, av As Byte) Dim b, n As Byte For b = 1 To av Read #mf, n Next End Private Function legge_var(mf As File) As Integer ' Legge un numero a lunghezza-variabile (Tempo Delta) Dim vl As Integer Dim c As Byte Repeat Read #mf, c vl = Shl(vl, 7) Or (c And 127) Until Not (c And 128) Return vl End Private Function DurataParziale(bpm As Integer, del As Short, par As Integer) As Float Return CFloat((((60000000 / bpm) / del) * par) / 1000000) End