You are on page 1of 3

Uzupełnienie do kursu "InertiaPlayer & ProTracker"

Pewnie to wszyscy wiedzieli, tylko nie Ja, że pomysłodawcą i autorem programu do odtwarzania plików MOD
(MD8) jest Pecuś. Dzięki jego uprzejmości można teraz lepiej wyjaśnic zasadę działania playera.

Dodatkowo jest jeszcze sprawa Epiego i jego NeoTrackera ;), który chwali się że jest szybszy, ciekawe jak? Sample w
Neo zajmują zawsze bank pamięci (16kb), ale wątpie żeby to przyspieszyło samego playera, co najwyżej procedurę
dekodującą pattern, czyli pare cykli, które nijak bądą się miały do całego grania. Epi pochwal się swoimi
osiągnięciami ! :)

Jak ładować do pamięci dane i znajdować odpowiednio dużo miejsca ?

Dostępna pamięć reprezentowana będzie przez tablicę z bitami, każdy bit to strona pamięci. Bit 1 - strona pamięci
zajęta, bit 0 - strona wolna. Oczywiście każdy bit w tablicy to odpowiedni adres w pamięci. Teraz obliczamy ile stron
zajmują dane, np. $150 = 2strony, szukamy w tablicy najmniejszego wolnego obszaru >= 2 i tam załadujemy dane.
Dzięki temu załadujemy więcej sampli i oszczędzimy pamięć. Proste, prawda ?:)

Teraz wróćmy do fragmentu playera, mało zrozumiałego, czyli etykiety "ist_0" itd.

Pecuś rozjaśni obraz:


pmain equ *
bank0 lda #$fe ;bank w którym znajduje się sampl
sta $d301
ist_0 lda #0 ;tego nie rozumiem, bo brak w playerze odwolan do ist_0 itp.
iad0_m adc #0 ;ale sa odwołania do "iad0_m" i "iad0_s"
sta ist_0+1
lda p_0c+1 ;modyfikacja adresu sampla, dodajemy wartosc z tablicy czestotliwosci
...
...

Sprawa jest prosta, jedno słowo wystarczy "ułamek" :)

Jeśli chcesz odtworzyć dźwiek o częstotliwości np. o połowę mniejszej niż wzorcowa, a petla licząca pozycje w samplu
tylko dodaje i nie można sterować częstotliwością jej wywołania, to ile musisz dodawać za każdym obrotem pętli by
osiągnąć o połowę mniejszą częstotliwość (czyli każda próbka odtwarzana jest dwa razy)?

To oczywiste musisz dodać 0,5 - czyli dodajesz ułamek a i tak część po przecinku jest Ci potem niepotrzebna. No ale
dodawać tak trzeba. W przypadku mojego playera $80 zapisane w tej "nieużywanej" komórce, a zera w pozostałych
oznacza właśnie 0,5 tak jak $33 oznacza około 0,2, a dodawanie tej wartości spowoduje pięciokrotnie wolniejsze
odtwarzanie sampla. Poprostu traktujemy 2 bajty jako adres sampla i dodatkowo jeszcze jeden bajt jako ułamkową
część adresu.

Być może ta komórka jest w innym obszarze strony zerowej i nie jest tak że liczba całkowita i ułamek są zapisane
kolejno - ale to wynikało z prób i dodawania pewnych rzeczy po napisaniu wstępnej wersji.

A teraz największe zaskoczenie i ciekawostka. Przy pisaniu tych procedur trzeba było stworzyć tablicę dodawanych
wartości - nazwaną potem niezbyt poprawnie tablicą częstotliwości dźwieku. Zacząłem to liczyć za pomocą programu
w basicu i tabeli częstotliwości kolejnych dźwięków z gamy. Wyliczyłem pierwszą oktawę i rzuciłem okiem na część
kodu playera z Amigi. Tam jest inaczej bo 4 przetworniki mogą grać z niezależnie ustawianymi szybkościami... No ale
do rzeczy - jakież było moje zdziwienie kiedy zauważyłem że tablica, którą zacząłem wyliczać odpowiada
DOKŁADNIE tablicy częstotliwości przetworników w playerze Amigowym przepisanej tylko od końca :) - tak więc
dałem sobie spokój z liczeniem i przewaliłem te tablice z Amigi.

A co do odtwarzania, to player nie gra na JEDNYM generatorze - gra na TRZECH. Poprostu nieliniowość POKEYa
powoduje, że odtwarzanie sampla na jednym generatorze powoduje zniekształcenia sampla granego na drugim - nie
sumuje sie to zwyczajnie - a przy 3 już się nie da słuchać nie mówiąc o 4. Podobno niezły efekt uzyskuje sie przez
ustawienie dźwieku o najwższej możliwej częstotliwości na każdym kanale i sterowanie głośnością (a nie bezpośrednie
sterowanie głośnikiem). Ja poszedłem inną drogą, pomierzyłem napięcia uzyskiwane na wyjściu POKEYa przy
wpisywaniu różnych wartości do generatorów, ułożyłem wyniki liniowo i stworzyłem tablice wpisów dla trzech
generatorów - poczatkowo było na czterech, ale niestety mamy tylko 3 rejestry, a rozkaz ładowania rejestru po drodze
zakłócał dźwiek.

Uff... Na AIM wrzuciłem kiedyś źrodła playera i konwertera, ale ja nie komentowałem ich zbyt dobrze (słynna etykieta
SPRDAL - osnaczająca oczywiście "Sprawdzaj Dalej" :) - poza tym to nie jest ostatnia wersja, a chyba nawet jedna z
pierwszych - polecam zdisasemblowanie wersji z Intel Oudside. A to ładowanie na DOSa to nie zabezpieczenie -
poprostu miało chodzić na 64kb, więc potrzebna była maksymalna ciągła pamięć, stąd loader z CHAOSa w środku i
tak niskie ładowanie. A zabezpieczenienie było dlatego, że jak dałem do testowania w Bajtku wersje niezabezpieczoną
to za tydzień krążyła już po giełdzie (a nie miała jeszcze niezależnej głośności kanałów i zapętleń końcówek sampli). 

Pozdro. Pecuś.
pmain equ *
bank0 lda #$fe ;bank w którym znajduje się sampl
sta $d301

ist_0 lda #0 ;to już rozumiem bo Pecuś wytłumaczył :)


iad0_m adc #0 ;modyfikacja wartości w "iad0_m" i "iad0_s"
sta ist_0+1

lda p_0c+1 ;modyfikacja adresu sampla, dodajemy wartosc z tablicy czestotliwosci


iad0_s adc #0 ;mlodszy bajt adresu
sta p_0c+1
bcc p_0c
inc p_0c+2 ;starszy bajt adresu
lda p_0c+2 ;sprawdzenie czy to już koniec sampla
ien0_s cmp #0
bcc p_0c

ire0_m lda #0 ;ustawienie nowego adresu poczatkowego sampla


sta p_0c+1 ;czyli petla sampla
ire0_s lda #0
sta p_0c+2
jmp bank1

p_0c ldx $ffff ;wartość sampla


ivol10 lda $d800,x ;tablica głośności
ch0 sta $d600 ;graj, jeśli urzadzeniem jest POKEY to będzie adres $d200

bank1 ........... nastepny kanal itd.

Sprawa głośności sampla. Nie ma szybszego sposobu niż:

ldx $ffff ;wartość sampla (bajt)


lda $d800,x ;tablica głośności - modyfikowany adres
sta $d600 ;graj, jeśli urzadzeniem jest POKEY to będzie adres $d200

MOD ma 64-o stopniową skalę głośności, ale na potrzeby Atari wystarczająca jest 32 stopniowa skala, zajmuje o
połowe mniej miejsca :), jak wyliczyć tablice? Wartości w samplu są z zakresu <0,255>, więc te wartości będą
skalowane przez tablice głośności. 256 wartości przez 32 głośności = 8, czyli co 8 jednostek będzie zmieniała się
głośność.

Czyli mamy głośności tak naprawdę 0,8,16,32 ... 256, np. glośność =8 oznacza że w 256 wartościach naszej tablicy
głośności musimy zmieścić wartości z zakresu 0..8, głośność =48 oznacza, że w 256 wartościach są liczby z zakresu
0..48 itd. Dla głośności =0, wszystkie wartości w tablicy będą =0, czyż nie jest to oczywiste :D Chyba już rozumiecie
że skalujemy w ten sposób wartości sampla :)

Oto programik w stylu Turbo Pascala, wyliczający tablice głośności:

uses crt;

var z,i,skala:integer; {deklaracje zmiennych INTEGER-całkowite}


co_ile_stopni:integer;
x:real; {zmienna typu rzeczywistego, dla ułamków}
v:byte; {byte}

begin
clrscr; {czyścimy ekran}
co_ile_stopni:=8; {czyli 256wartości przez 32 stopniowa}
{skale głośności = 8}
for skala:=1 to 32 do begin
z:=skala*co_ile_stopni; {obliczamy zakres}
x:=z/256; {obliczamy wartość kroku, aby wszystkie}
{elementy zmieściły się w 256 bajtach}
for i:=0 to 255 do begin
v:=round(i*x); {liczymy zaokrąglając wartości}
write(v,','); {wypisujemy na ekran, albo do pliku}
end;
end;

end. {koniec przykładu}

Dla każdej głośności będzie więc 256 bajtowa tablica. 32*256 = 8192bajtów zajmą wszystkie tablice. Normalnie w
Inertii taka tablica siedzi sobie w dodatkowym banku, i dopiero gdy jest potrzebna przepisywana jest pod ROM,
$d800...

Pytanie za 100punktów

Czy da się przyspieszyć player? Jakieś sugestie co do jego przyspieszenia? Pamiętajcie tylko, że cały kod mieści się
na stronie zerowej.

A może tak przydałby się player grający 256 bajtowymi samplami, do tego wibracje i inne efekty z MOD-a, tak żeby
można było stworzyć chiptunes. Takiego 256bajtowego sampla możnaby było sobie samemu edytować, nadać mu
kształt trójkąta, fali czy czegoś innego, tak aby wydobyć dźwięki np. podobne do SIDa. Jak myślicie, można na takim
256 bajtowym sampelku coś zrobić ??

Player dla 256bajtowych próbek byłby szybszy, a mógłby wyglądać tak:


pmain equ *

ist_0 lda #0 ;to już rozumiem bo Pecuś wytłumaczył :)


iad0_m adc #0 ;modyfikacja wartości w "iad0_m" i "iad0_s"
sta ist_0+1

lda p_0c+1 ;modyfikacja adresu sampla, dodajemy wartosc z tablicy czestotliwosci


iad0_s adc #0 ;mlodszy bajt adresu
sta p_0c+1
bcc p_0c
ien0_s cmp #0 ;test dlugosci
bcc p_0c

ire0_m lda #0 ;ustawienie nowego adresu (mlodszy) poczatkowego sampla


sta p_0c+1 ;czyli petla sampla
jmp kanal2

p_0c ldx $ffff ;wartość sampla


ivol10 lda $d800,x ;tablica głośności
ch0 sta $d600 ;graj, jeśli urzadzeniem jest POKEY to będzie adres $d200

kanal2 ........... nastepny kanal itd.

Sample nie musiałyby znajdować się w dodatkowych bankach, zawsze miałyby 256bajtów, sprawdzany byłby tylko
młodszy bajt adresu. Dzięki takiej oszczędności cykli możnaby do playera dorzucić procedurki odpowiedzialne za
inne fx-y niż Volume. Chyba w ten sposób działa SoftSynth, jeśli ktoś zna działanie SoftSytnha od "kuchni" chętnie
posłucham. Przydałby się jeszcze dokładny opis z implementacją efektów dźwiękowych z MOD-a, ktoś chętny??

You might also like