Artykuły

    Kurs Assemblera cz. 6

    Tematem tego wydania kursu jest InertiaPlayer & ProTracker. Na początek trochę historii, czyli jak doszło do powstania Inertii, a potem ProTrackera.

    Wszystko zaczęło się od wydania przez Mirage pakietu z playerem plików MD8. Były to zmodyfikowane pliki MOD, tzn. sample 8-bitowe przekonwertowane na 4-bit, oraz zmiany w trackach itp. Wszystie te zmiany miały przyspieszyć odgrywanie i skrócić rozmiar w stosunku do oryginalnego pliku MOD. Zaowocowało to wzrostem zużytych dyskietek 5i1/4 i niemożnością pochwalenia się swoją twórczością przed użytkownikami Amig, PC, ST. Profi jako zapalony muzykant, dotąd tylko CMC, później MPT zapragnął nie tylko dokonywać konwersji MOD->MD8, ale stworzyć w końcu coś swojego.

    Sam engin playera, sposób regulacji głośności sampla, schemat odczyty pliku MD8 otrzymaliśmy od Marka Goderskiego, autora opisu systemu SpartaDosX. Ten bardzo ciekawski człowiek postawił sobie za cel disasemblacje playera i przyjrzenia mu się z bliska. Sam program był zabezpieczony, ładował się w niskie obszary normalnie nachodząc na DOS, dodatkowo był eorowany kilka razy. Autorom bardzo zależało by nikt nie zajrzał do źródełka ;). Dzięki odpowiedniej wersji Sparty, zostawiającej dużo miejsca dla programów, swoich disasemblerów i innych narzędzi pod Sparte, udało się Markowi zdisasemblować player i zrozumieć jego działanie. Tak wyedukowani przez niego i wzbogaceni źródełkami w formacie jedynie słusznym czyli QA (obecnie X-Asm), zaczęliśmy tworzyć Inertie, tzn. Profi zaczął tworzyć, potem doszła niezdrowa konkurencja z mojej strony, tzn. jak on stworzył wersje np. X, to ja coś poprawiałem i wychodziła wersja Y. Podobnie było w przypadku Visage, on zaczął, ale że nie miał procedur kompresji, dekompresji to ja skończyłem. Może dlatego Profi potem odwrócił się od Madtemu, a może to przez dziewczynę.

    Wracając do tematu, mieliśmy playera co prawdza tylko MD8, ale nie było jeszcze 8-bitowego przetwornika. Na horyzoncie pojawił się jednak Psychol, który oprócz masy innych wynalazków militarnych jak żelazko rozpylające gaz wpadł na pomysł zwiększenia możliwości dźwiękowych Atarka przez 8-bitowy przetwornik. Ekipa Madteamu zebrała się w ciemnym pokoiku Psychola, by usłyszeć nową zabawkę. Na początku był tylko 1 kanał. Psychol napisał sobie program do odtwarzania sampli, by potem męczyć sąsiadów telefonami i odtwarzanymi z Atari dziwnymi tekstami. Zrobił też automatyczną sekretarkę, która odtwarzała nagrany tekst, a potem zapisywala ileś KB rozmowy.

    Pojawiły się inne pomysły na zastosowanie wynalazku, w tym czasie mieliśmy już źródła playera MD8, wiedzieliśmy że tak naprawdę gra on na jednym kanale, wartość wpisywana do rejestru była wyliczana jako suma wszystkich kanałów. Taki sposób miał wyeliminować zagłuszanie się jednego kanału przez drugi (pewnie chodzi o interferencje). Profi wziął się z zapałem do pracy i tak narodziła się późniejsza Inertia. Aktualnie wczytywała jeszcze MD8 ale odtwarzała już na 8-bitowym przetworniku, jakby go nazwać ... Covoxie ;) Efekt odgrywania sumy 4 kanałów na 1 przetworniku był mało zadowalający, były duże zniekształcenia, zbyt wyraźnie było to słychać. Tak więc żeby dużo nie kombinować trzeba dorzucić następne 3 kanały. I tak dzięki współpracy Psychola i Profiego zaczął wyłaniać się coraz to bardziej dopracowany kształt playera. Pojawiły się też sugestie aby przyspieszyć player przez sprzętową regulacje głośności, ale Psychol stwierdził, że skomplikowałoby to zbytnio całego Atarowskiego Covoxa. Tak więc pozostaliśmy przy metodzie zastosowanej w MD8, odpowiednio tylko modyfikując tablice głośności, ze wzoru którego już nie pamiętam.

    Natomiast ProTracker był naturalnym rozwinięciem Inertii, który miał zaspokoić ambicje twórcze Profiego. Był to największy jego projekt, projekt jak najbardziej udany i skończony. Przedtem był jeszcze nigdy nie pokazany ogółowi sampler i odtwarzacz sampli w zbajerowanym przez Rockego środowisku graficznym, z graficznym equilizerem, z zaznaczaniem fragmentów sampla i wszystkich z tym związanych bajerów.

    Inertia Player v3.7

    Nie jest to wersja Inertii Profiego, ale nie powinna się wiele różnić od jego wersji 3.7 (może kiedyś zdarzy się cud, Profi zajrzy tutaj i dorzuci coś do tego ogródka). Operacje I/O ze stacją dysków odbywają się bez udziału DOSu. Tak więc Pinokiowi się to nie spodoba ;)

    Tak jak w przypadku ProTrackera jeśli ktoś będzie chciał cokolwiek modyfikować, niech to będzie zorganizowane. Jeden człowiek, czy grupa czuwa nad projektem, inni pomagają. Żeby nie było tak, że nagle pojawi się 100 wersji różniących się autorem ;)

    Pare ogólnych uwag na temat działania. Dla przyspieszenia działania playera jest on umieszczony na stronie 0. Całość w sumie zajmuje 3 strony pamięci, od $0000-$02ff i nie ma wpływu na stos, stos jest nieużywany, ponieważ wyłączone są wszelkie przerwania. Normalnie kod playera umieszczony jest gdzieś w pamięci i dopiero gdy jest potrzebny przepisywany jest na strone 0 i dalej. Oczywiście zawartość strony 0 musi zostać zachowana, a po skończeniu odgrywania jest odtwarzana jej zawartość.

    W celu przyspieszenia odgrywania sampli, sprawdzany jest tylko starszy bajt ich adresu. Sposób ten wymaga aby sample były odpowiednio umieszczone w pamięci, tzn. młodszy bajt adresu ostatniego bajtu sampla jest równy 0. Jak to osiągngąć? Długość sampla jest reprezentowana przez liczbe stron, tzn. dla długości sampla $1578 mamy $15+1 stron. W jednym banku pamięci zmieścimy $40 stron. Najwięcej stron zmieścimy w pamięci głównej, będzie tutaj najdłuższy z sampli. Jeśli będziemy korzystali z DOSu tej pamięci będzie mniej.

    Podczas odtwarzania sampli wyłączone są wszystkie przerwania. Synchronizacja odbywa się przez wywołanie procedury odgrywającej sample N razy. Ta procedura znajduje się właśnie na stronie zerowej pamięci. Potem następuje skok do procedury odczytującej pattern, modyfikacja adresów w playerze i znowu skok na strone zerową. Player za każdym razem kiedy wpisuje wartości do 4 kanałów musi zajmować tyle samo cykli zegara. Im dokładniej będzie to zrealizowane tym lepszej jakości otrzymamy dźwięk. Dokładniej częstotliwość odtwarzania mierzył Psychol oscyloskopem i jakimś swoim elektronicznym urządzeniem. Zliczało ono odwołania do strony pamięci z rejestrami Covoxa.

    Przykład odtworzenia sampla na 1 kanale w playerze Inertia. Pętla ma stałą długość deklarowaną w stałej VBL, tutaj $d8 i ma ona wpływ na tempo. Jakakolwiek zmiana w playerze, zmieniająca liczbe cykli spowoduje zmianę tej wartości.

    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 
    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.
    

    Na końcu tej pętli występuje już tylko:

    p_e    dey             ;zmniejszamy wartość Y i pętlimy się dalej
           beq pat
           jmp pmain
    
    
    * -----------------
    * requests
    
    
    pat    ldy #vbl        ;odświeżamy zawartość rejestru Y
           dec cnts        ;licznik długości patternu
           beq pre
           jmp pmain
    
    pre    lda #0          ;tutaj zaczyna się procedura dekodowania patternu
           sta patend
           lda #$fe
           sta $d301
    
    *---------------------------
    * track  0
    

    Normalnie w pliku ASM wygląda to inaczej ponieważ wszyskie rozkazy "lda" "sta" "inc" musiały zostać zapisane w formie "dta b(lda),b(value)", dlaczego? Spójrzmy na taki przykład:

    
     org $0000
     lda bajt
     bajt dta b(0,1,2,3,4,5)
    

    Po kompilacji otrzymamy:

    X-Assembler 2.5.2 by Fox/Taquart
    Source: G:\!Atari\inne\_profi\it37\xxx.asm
        1				                 opt h+
        2				                 org $0000
        3
        4 0000                         main
        5 FFFF> 0000-000B> AD 06 +     lda bajt        ;rozkaz $AD nie dotyczy strony zerowej 
        6 0003 AE 07 00                ldx bajt+1      ;tutaj też zamiast na 2-óch bajtów mamy 3-y
        7
        8 0006 00 01 02 03 04 05  bajt dta b(0,1,2,3,4,5)

    Dopiero jeśli tablica "bajt" wystąpiłaby przed programem, kompilator skompilowałby to z rozkazami strony zerowej.

    X-Assembler 2.5.2 by Fox/Taquart
    Source: G:\!Atari\inne\_profi\it37\xxx.asm
        1                              opt h+
        2                              org $0000
        3
        4 FFFF> 0000-0009> 00 01 +     bajt dta b(0,1,2,3,4,5)
        5
        6 0006                         main
        7 0006 A5 00                   lda bajt        ;mamy 2-bajty
        8 0008 A6 01                   ldx bajt+1      ;tutaj też czyli to musi dotyczyć strony zerowej
        9
    

    Uruchomienie Inertii, kompilacja pliku "IT37.ASM":

          opt h+
          org $8000          ;załadowanie tablic głośności 
          ins 'mod8.tab'
    	
          org $7000          ;załadowanie skompliowanego playera
          ins 'play37.obx'
          org $2000          ;załadowanie skompilowanej Inertii
          ins 'mod37.obx'
    
          org $600
    
    start ldx #18
          ldy #0
    s     lda $2000,y      ;przepisanie Inertii pod adres $0700
    d     sta $0700,y
          dey
          bne s
          inc s+2
          inc d+2
          dex
          bne s
          jmp $0700        ;i uruchomienie
          run start
    

    Uruchamiamy plik "IT37.OBX" i możemy już używać Inertii. W przypadku emulatora wystarczy że w napędzie 1 będzie dyskietka z plikami MOD, a program możemy uruchomić przez "ALT+X".

    ProTracker v1.5

    Dysponuje tylko kopią v1.5, nie jestem pewien czy były nowsze, wiem że w stosunku do Inertii player ma niższą częstotliwość odtwarzania oraz mniej efektów. Ostatnia z Inertii miała coś więcej niż 3 komendy występujące w ProTrackerze. Aktualnie przyglądając się kodowi programu można zauważyć że w QA zabrakło miejsca na etykiety i większość skoków Profi zapisywał w postaci "*+nn", co nie sprzyja przejrzystości programu. Jakiekolwiek modyfikacja muszą być przeprowadzane ostrożnie, ale są możliwe bo Profi nie optymalizował zbytnio trackera.

    Oczywiście jeśli ktokolwiek będzie coś poprawiał powinien udostępnić to ogółowi i powinno to być ujednolicone, tzn. jest jedna osoba która wprowadza modyfikacje, czyli czuwa nad projektem, a nie kildadziesiąt poprawia i kilkadziesiąt wersji się pojawia. Większość osób jest już dorosłych więc nie powinno być problemów ze zrozumieniem tej zasady.

    Pierwsza modyfikacja dotyczy procedur zmiany oktawy. Widać że zaremowane znakiem ";" instrukcje w podprogramie "_dn" powtarzają się w podprogramie "_up". Dzięki takiej optymalizacji zwolniliśmy troche pamięci.

    _up      lda okt   ;podnies oktawe 1 wyzej
             cmp #2
             beq _up1
             inc okt
             inc okt
    _oktShow ldx okt
             lda oktawa,x
             sta _e1+9
             inx
             lda oktawa,x
             sta _e1+10
             inx
             lda oktawa,x
             sta _e1+11
             jsr _pr
    _up1     jsr cl_k
             rts
    
    _dn      lda okt   ;opusc oktawe nizej
             beq _up1
             dec okt
             dec okt
     
    ; ldx okt
    ; lda oktawa,x
    ; sta _e1+9
    ; inx
    ; lda oktawa,x
    ; sta _e1+10
    ; inx
    ; lda oktawa,x
    ; sta _e1+11
    ; jsr _pr
    ; jsr cl_k
    ; rts
             jmp _oktShow
    

    "_e1+9" "_e1+10" "_e1+11" to adresy pamięci obrazu, czyli miejsca w których pojawiają się napisy reprezentujące oktawe, np. "1:2" "2:3"

    Poniższa modyfikacja optymalizuje szybkość działania, oszczędzamy 2 cykle zegara.

    Oryginalnie wyglądało to tak:

     _p0rom ldx #0   
    _pp1    lda TempBuffer,x    
            tay

    A po modyfikacji tak:

     _p0rom ldx #0   _pp1
            ldy TempBuffer,x     
            ; tay    
            lda ZeroPage,x   
            sta TempBuffer,x   
            tya   
            sta ZeroPage,x   
            inx   
            cpx #$d8   
            bne _pp1   
            rts

    Zadaniem tej procedury jest przed każdym odegraniem czegokolwiek przepisanie procedur znajdujących się w "TempBuffer" na stronę zerową, a dane znajdujące się na stronie zerowej przepisać do "TempBuffer". Te procedury to skompilowany player, w sumie $d8 bajtów.

    Podobnie można postępować w przypadku pozostałych procedur, np. główna rozdzielnia obsługująca klawisze "KEYBD". Oto jej fragment:

    keybd jsr wait
          lda 764
          cmp #231
          bne *+5
          jmp _exit   ;opusc program
          cmp #173
          bne *+5
          jmp _trans  ;transpozycja
          cmp #150
          bne *+5
          jmp _exchg  ;zmiana instrumentu
          cmp #71
          bne *+5
          jmp inc_p   ;zwieksz nr. patternu
          cmp #70
          bne *+5
          jmp dec_p   ;zmniejsz nr.patternu
          cmp #15
          bne *+5
          jmp dn_p    ;przes. w dol patt.
          cmp #14
          bne *+5
          ...
          ...
          ...
          itd.
    

    Można przyspieszyć działanie kosztem pamięci, np. kosztem 512 bajtów, pierwsze 256 bajtów to młodsze adresy procedur, ostatnie 256 bajtów to starsze adresy procedur. Numer określający kod naciśniętego klawisza z 764 byłby indeksem do naszej tablicy. Bierzemy młodszy, starszy modyfikujemy adres w pamięci i JMP, np.

    Sposób najszybszy:

    keybd     jsr wait
              ldy 764
              lda lAdr,y         ;4 cykle
              sta _jmpAdr+1      ;4
              lda hAdr,y         ;4
              sta _jmpAdr+2      ;4
    _jmpAdr   jmp $ffff          ;3
                                 ;Razem 15 cykli
    
    

    Sposób zajmujący więcej cykli zegara, ale najkrótszy. Adresy w tablicy muszą być zmniejszone o 1. Wykorzystana jest właściwośc instrukcji "RTS", która zdejmuje ze stosu pomniejszony o 1 adres powrotny i tam skacze.

    keybd jsr wait
          ldy 764
          lda hAdr,y         ;4 cykle
          pha                ;3
          lda lAdr,y         ;4
          pha                ;3
          rts                ;6
                             ;Razem 20 cykli
    

    Uwaga: Niektóre obszary są deklarowane na "sztywno". Należy dokładnie zapoznać się z mapą pamięci jaką wykorzystuje ProTracker zanim zaczniemy jakieś drastyczne zmiany. W pliku "ADRESY.ASM" znajdują się deklaracje etykiet.

    Pierwsze zmiany jakie bym proponował to zamiana skokow "*+nn" na odpowiadające im etykiety.

    Główne procedury:

    • _VOLMV procedura wywoływana jest przed odegraniem całego MOD-a lub patternu. Przepisuje tablice głośności z ostatniego banku pamięci (spod adresu $4000 pod adres $d800 32-strony pamięci, ostatnią stronę powiela $f700 na $f800).
    • LOA_MOD procedura wczytująca plik MOD, patterny pod $c600, nagłówek pliku MOD to 1084 bajty
    • PMAIN integralna część playera, tutaj następuje dekodowanie patternu dla każdego tracka i modyfikacja adresów playera.
    • IO operacje wejścia/wyjścia
    • FUNC2 procedury odczytu sampla z nagłówkiem 27-bajtowym
    • ORDERS procedury obsługi edycji okna "ORDER"
    • XCHG procedury obsługi "wymiany instrumentu na inny"
    • TRANS procedury obsługi "transpozycji"
    • FUNCTION pozostałe procedury związane z edycja tracku, patternu itp.
    • MOVE przepisuje tablice głośności do ostatniego banku pamięci, jeśli wybrane urządzenie to POKEY to modyfikuje tablice, jeśli COVOX to modyfikuje program i zamiast "lsr @" wstawia rozkazy "nop" wtedy tablica nie zostaje zmodyfikowana. Tablice "TIDL" oraz "TID2" zostają przepisane odpowiedio pod "AdrTidl" oraz "AdrTid2".
    • TIDL tablice nut - częstotliwosci dla sampli, wartość z tablicy dodawana jest do adresu sampla
    • TID2 tablica nut uzywana podczas edycji do odtwarzania pojedyńczych sampli
    • SELECT stąd startuje cały program, rozpoznanie pamięci dodatkowej, wybór urządzenia Pokey lub Covox

    Główne pliki:

    • TS.FNT zestaw znaków dla ProTrackera, ładowane pod adres $2000
    • VOLUME.TAB tablica głośności, ładowana pod adres $8800
    • PM.ASM źródło playera, w osobnym pliku bo nie można załadować bezpośrednio do pamięci czegokowiek tak długiego na strone 0.

    Sposób kompilacji głównego pliku TR.ASM:

    • Najpierw kompilujemy plik "_PMAIN.ASM" bez nagłówka (opt h-). Powstały plik "_PMAIN.OBX" zostanie wykorzystane podczas kompilacji "TR.ASM"
    • Kompliujemy plik "TR.ASM". Na samym początku występuje kompilacja pliku "PM.ASM" bez generowania nagłówka i pliku wynikowego "opt h-o-". Jest to konieczny zabieg, który umożliwia pozostałej części programu poznanie adresów występujących w playerze. Odwołania do nich będą kompilowane jako odwołania do strony zerowej. Plik "_PMAIN.OBX" to tak naprawde skompilowany plik "PM.ASM".

    Komentarze gości atari.area

    Momencik, uaktualniam...  

    Nie jesteś zalogowany. Tylko zarejestrowani i zalogowani użytkownicy mog± dodawać komentarze.

Lotharek.pl
Retronics
Silly Venture
Last Party 2025
Lost Party 2025

Szukaj

Wyszukiwarka przeszukuje zasoby atari.area, atariki oraz forum.

Twoliner

Momencik, uaktualniam...  .

Pamiętaj, żeby linki do Twolinera dodawać wyłącznie po skróceniu za pomocą serwisu tiny.pl. Jeśli coś Ciebie ominęło - skorzystaj z archiwum.

Network

konto

Nie jesteś zalogowany. Zaloguj się lub załóż konto

forum

Artykuły

Wywiady

Allegro

Jako, że Allegro.pl jest bardzo często odwiedzanym serwisem przez Atarowców, umiejscowiłem poniżej wyszukiwarkę produktów związanych z naszym kochanym Atari. Chcesz coś kupić - wystarczy wpisać w okienko poniżej.


Wystarczy wpisac czego szukamy i po chwili znajdujemy sie juz na Allegro.pl.