Czasy delta w plikach MIDI

Po układzie ym2149 i komunikacji z zewnętrznym modułem MIDI, przyszedł czas na zmierzenie się z czasami delta, które są niezbędne do odgrywania sekwencji w plikach MIDI. W ramach przypomnienia, czas delta to relatywny czas w odniesieniu do poprzedniego zdarzenia w sekwencji. Mając tą wartość wiemy w jakim okresie czasu muszą być wysłane odpowiednie zdarzenia. np. z sekwencera do urządzenia midi (nuta włączona, wyłączona, zmiana instrumentu etc..).
Po lekturze specyfikacji formatu plików MIDI [typ 0,1,2] powstaje pytanie – jak długo trwa jednostka czasu delta i jak zaimplementować wysyłanie danych midi i zmianę tempa? Ok, najpierw musimy wiedzieć co interesującego związanego z tempem może zostać znalezione w pliku MID. Są dwie rzeczy:

1) Podział czasu (time division) w “MThd” zbitce (0x4D546864), wskazuje ilość tyknięć zegara w jednej ćwierć nucie (PPQN – pulses per quaternote). I jest to po prostu rozdzielczość w jakiej pulsy są zliczane w ćwierć nucie, która ma skończony okres (będzie o tym później). Więc jeżeli mamy podział czasu 96 PPQN, to oznacza to, że 96 tych tyknięć odmieża trwanie jednej ćwierć nuty.
Muzycy na przykład mierzą tempo w liczbach ćwierć nut na minutę (po prostu ilość ćwierć nut, która może być wyzwolona w jednej minucie co jakiś interwał), w komputerach i innych urządzeniach śledzenie czasu musi się odbywać w inny sposób. Podział czasu może być też zakodowany w formacie SMPTE, ale jest on rzadko spotykany i nie będę go tutaj opisywał..

2)Wartość “Ustaw tempo”(Set tempo), która zawiera ilość mikrosekund na ćwierć nutę. Może się znajdować w meta zdarzeniu ścieżki – fragment “MTrk” (0x4D54726B)

Jeżeli mamy te informacje możemy obliczyć częstotliwość z jaką występuje jedno tyknięcie zegara :

MSPM – mikrosekundy na minutę = 60 000 000
BPM – uderzenia na minutę
MPQN – mikrosekundy na ćwierćnutę
BPM = MSPM / MPQN 
MPQN = MSPM / BPM

Jeżeli mamy 120 BPM (standardowe, domyślne tempo) to okres ćwierć nuty jest:

MPQN=60 000 000/120 BPM = 500 000 mikrosekund

Następnym krokiem jest obliczenie częstotliwości tyknięcia zegara, gdy mamy okres ćwierć nuty reszta jest łatwa:

1 tyknięcie=MPQN/1000000/PPQN=500 000/1000000/96 PPQN = ~0,005208333333 Hz…

Z dwoma rzeczami powyżej programujemy tyknięcie z częstotliwością ~0,005208333333 Hz, e.g. dla rozdzielczości 96PPQN będzie 96 tyknięć tworzących trwanie ćwierć nuty (96 * 1 tyknięcie = 96 * 0,005208333333 Hz = 500 000 mikrosekund = 0,5s).

Teraz możemy, rozwiązać sprawę translacji czasu delta na czas rzeczywisty. Poniżej są trzy przykładowe wartości tempa:

Tempo 1 Tempo 2 Tempo 3
BPM 120 130 130
PPQN 120 120 96
MPQN 500000 461538 461538
QLS 0,5 0,4615 0,46
TDPS 0,0041666667 0,0038461500 0,0048076875

BPM – to uderzenia na minutę 60 000 000/MPQN
PPQN – pulsy na ćwierć nutę, rozdzielczość z pliku MIDI
MPQN – mikrosekundy na ćwierć nutę lub inaczej czas trwania ćwierć nuty, zakres 0-8355711 mikrosekund (zgodnie ze specyfikacją formatu)
QLS – sekund na ćwierć nutę (MPQN/1000000)
TDPS – sekund na tyknięcie (QLS/PPQN)

I tutaj tłumaczymy każdą wartość delta do czasu rzeczywistego dla tych trzech temp. Wszystkie zdarzenia są wyzwalane relatywnie do ostatniego zdarzenia. Tak więc pierwsze zdarzenia będą z delta 0, potem będzie potrzeba 15 tyknięć do wyzwolenia następnego zdarzenia, a potem musi minąć 45 tyknięć (w stosunku do zdarzenia poprzedniego) zanim będzie miało miejsce następne zdarzenie.
Jak nietrudno zauważyć kolumna z akumulowaną deltą odzwierciedla absolutną linię czasu zdarzeń.

Żeby otrzymać interesujący nas czas rzeczywisty w jakim zdarzenie ma nastąpić mnożymy TDPS*zakumulowana delta. Rezultaty są przedstawione w trzech kolumnach poniżej dla każdego z temp.
Jeżeli ktoś chce zobaczyć jak będą wyglądały inne tempa przygotowałem prosty arkusz w OpenOffice Calc, więc każdy może pozmieniać wartości i zobaczyć jaki mają skutek.

Tempo 1 Tempo 2 Tempo 3
lp zakumulowana delta delta delta [s] delta [s] delta [s]
1 0 0 0,00 0,00 0,00
2 15 15 0,06 0,06 0,07
3 60 45 0,25 0,23 0,29
4 70 10 0,29 0,27 0,34
5 90 20 0,38 0,35 0,43
6 100 10 0,42 0,38 0,48
7 120 20 0,50 0,46 0,58
8 135 15 0,56 0,52 0,65
9 180 45 0,75 0,69 0,87
10 195 15 0,81 0,75 0,94
11 240 45 1,00 0,92 1,15
12 250 10 1,04 0,96 1,20
13 270 20 1,13 1,04 1,30
14 280 10 1,17 1,08 1,35
15 300 20 1,25 1,15 1,44
16 315 15 1,31 1,21 1,51
17 360 45 1,50 1,38 1,73
18 480 120 2,00 1,85 2,31
19 555 75 2,31 2,13 2,67
20 570 15 2,38 2,19 2,74
21 615 45 2,56 2,37 2,96
22 630 15 2,63 2,42 3,03
23 675 45 2,81 2,60 3,25
24 735 60 3,06 2,83 3,53
25 765 30 3,19 2,94 3,68
26 780 15 3,25 3,00 3,75
27 795 15 3,31 3,06 3,82
28 810 15 3,38 3,12 3,89
29 855 45 3,56 3,29 4,11
30 955 100 3,98 3,67 4,59
31 975 20 4,06 3,75 4,69
32 990 15 4,13 3,81 4,76
33 1005 15 4,19 3,87 4,83
34 1020 15 4,25 3,92 4,90
35 1035 15 4,31 3,98 4,98
36 1155 120 4,81 4,44 5,55

Tak więc, żeby odtworzyć sekwencję z pliku MIDI typ 0 (dla uproszczenia tylko jedna ścieżka) inkrementujemy naszą deltę delta co okres TDPS. Sprawdzamy deltę aktualnego zdarzenia w sekwencji. Jeżeli delta zdarzenia jest równa ilości zliczonych tyknięć wyzwalamy zdarzenie, resetujemi licznik tyknięć i przechodzimy do następnego zdarzenia w sekwencji. W przeciwnym wypadku inkrementujemy licznik tyknięć i ponownie sprawdzamy deltę aktualnego zdarzenia.
Dla wielu ścieżek musimy utrzymywać jeden licznik tyknięć na ścieżkę i iterować przez wszystkie aktualne zdarzenia ścieżki.

Drugą opcją byłoby wyzwalanie zdarzeń zgodnie z obliczoną wcześniej linią czasową (bazującą na zakumulowanej delcie), ale obsługa byłaby skomplikowana dla plików wielościeżkowych.



Wpisy według miesięcy