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:
Następnym krokiem jest obliczenie częstotliwości tyknięcia zegara, gdy mamy okres ćwierć nuty reszta jest łatwa:
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.

