
autor: mayonez
Ostatnimi czasy wśród programów muzycznych na naszą kochaną maszynkę króluje niewątpliwie "Music Protracker v.2.4" zwany w skrócie MPT. Mimo kilku wkurzających wad, jest to dobry program, przewyższający swoimi możliwościami brzmieniowymi CMC. Niestety w momencie wypuszczenia tego programu grupa "Slight" poza instrukcją obsługi nie udostępniła opisu formatu plików obsługiwanych przez ten program. Zdegustowany tym faktem, "pogrzebałem" nieco w muzyczkach z MPT i ostatecznie "rozgryzłem" ten format. Poniżej znajduje się dokładny opis formatu plików z MPT v2.4. Format ten opisuję na ramach "Energy Zine", gdyż zdaję sobie sprawę z tego, że większość scenowców nie zna tego formatu. Znajomość formatu MPT może zaowocować powstaniem na scenie różnych konwerterów itp.
Równocześnie zdaję sobie sprawę z tego, że okres panowania MPT na scenie minie wraz z pojawieniem się nowych, doskonalszych programów muzycznych, wykorzystujących drugiego Pokeya. Upłynie jednak jeszcze trochę wody w klozecie, zanim takowe programy ujrzą światło dzienne. (Od redakcji: w czasie pisania tego artykułu autor nie miał jeszcze pojęcia o istnieniu TMC.)
Póki co, musimy zadowolić się i tak dobrym MPT, który stał się już swoistym standardem na Scenie. No, ale dość już przynudzania. Przejdźmy do rzeczy.
MPT v2.4 file format:
1. Struktura pliku. Nagłówek
offset
od - do - opis
(HEX)
$0000-$003F - adresy brzmień (LSB/MSB) (32 słowa). Bajty $00, $00 w tej tablicy oznaczają, że dane brzmienie jest puste
$0040-$00BF- adresy patternów (LSB/MSB) (64 słowa). Bajty $00, $00 w tej tablicy oznaczają, że dany pattern jest pusty
$00C0-$01BF - cztery tablice częstotliwości (64 bajty każda)
$01C0-$01C3 - młodsze bajty adresów tracków
$01C4-$01C7 - starsze bajty adresów tracków
$01C8-$01C8 - długość patternów (wartości - $10, $20, $30 lub $40)
$01C9-$01C9 - tempo utworu
$01CA-? - dane tracku #1, dane tracku #2, dane tracku #3, dane tracku #4
Ilość danych dla jednego tracku zależy od różnicy pomiędzy adresami sąsiednich tracków
?-? - dane brzmień
?-? - dane patternów
2. Dane brzmień.
Brzmienie ma długość 48 bajtów, jeśli nie jest puste.
Pierwsze 32 bajty układają się w pary:
BG PN.. (x16)
gdzie:
B - barwa dzwięku - 4 bity (starsze)
G - głośność dźwięku - 4 bity (młodsze)
P - numery parametrów akcentów pomnożone przez 2 (drugi rząd) - 4 bity (starsze)
N - numery akcentów (pierwszy rząd) - 4 bity (młodsze)
następne 8 bajtów to parametry sterujące instrumentem (pierwszy rząd z lewej)
kolejne 8 bajtów to parametry akcentów (drugi rząd z lewej)
3. Dane Patternów.
bajt (N) działanie
wartość
w zakresie:
$01-$3E - granie nuty (a raczej półtonu) o numerze N (np. 1=C-1, 2=C#1, 3=D-1)
$40-$5F - zmień brzmienie na numer równy N-$40
$80-$BE - ustaw ilość odstępów pomiędzy nutami na N-$80
działa dopiero po odegraniu nuty (od momentu wystąpienia rozkazu pierwszy odstęp pojawia się za nutą)
Jeśli zaraz za tym bajtem (kodem) występuje bajt równy $FE następuje ustawienie pustych pozycji w patternie. Ilość tych pozycji wynosi N-$7F. W tym przypadku puste pozycje pojawią się od razu, w momencie wystąpienia bajtu $FE, np. ciąg bajtów:
$83 $FE $41 $81 $01 $03 $01 $05
| | | | | | | |
| | | | --numery półtonów
| | | |
| | | 1 odstęp pomiędzy nutami
| | |
| | ustaw brzmienie #1
----
|
4 puste pozycje na początku patternu
reprezentuje pattern:
--- --
--- --
--- --
--- --
C-1 01
--- --
D-1 01
--- --
C-1 01
--- --
E-1 01
--- --
Pominięto głośność brzmień.
$C0-$CF - ustaw głośność nut na równą N-$C0
$D0-$DF - ustaw tempo grania na równe N-$D0
$Ex - koniec patternu (x - dowolne 4 bity)
UWAGA !!! - MPT v2.4 zapisuje w pliku patterny w ten sposób, że zawsze mają stałą długość, równą ustawionej w nagłówku. Następuje to poprzez dodanie na końcu patternu rozkazu tworzącego puste pozycje, tak aby każdy pattern miał identyczną liczbę pozycji.
UWAGA #2 !!!
Wpisując dane w trackach w MPT należy zwrócić uwagę na to, aby rozkaz skoku lub rozkaz zatrzymania utworu (odpowiednio $FF i $FE) znajdowały się na ścieżce numer 0, a wartości na pozostałych ścieżkach były równe 0. W przeciwnym wypadku MPT błędnie obliczy adresy brzmień i patternów podczas zapisywana pliku. Muzyczka zapisana w ten sposób będzie się poprawnie wczytywała do MPT, natomiast podczas odgrywania tejże muzyczki za pomocą jakiegoś playera usłyszymy tylko bulgoty albo ciszę.
MODUŁ SAMPLI z MPT v2.4
UWAGA !!! - TO NIE JEST PLIK BINARNY (DOSOWY)
od-do opis
00-0F - starsze bajty adresów początku sampli
0F-1F - starsze bajty adresów końca sampli (zwiększone o 1)
1F-? - Dane sampli
UWAGA !!! - adresy sampli w nagłówku zaczynają się nie od $0000, ale od $9000 (adres bufora na sample w MPT)
Tak, i to na tyle. Mam nadzieję, że przedstawiony powyżej opis formatu plików MPT przyda się komuś.
Plik do ściągnięcia:
mpt24s.zip
IRQ Loader

autor: jaskier
Czołem towarzysze. Tak jak
obiecywaliśmy w naszym magazynie
znajdziecie wiele pożytecznych informacji i
programów, które mogą się przydać przy
tworzeniu własnych programów użytkowych
oraz dem. W tym artykule akurat znajduje
się coś pożytecznego dla twórców dem.
Proces ładowania, to w demach
newralgiczne miejsce. Chciałoby się ten
czas wykorzystać, podobnie jak w demach
na C64, na jakieś efekty. Niestety
standardowa procedura na to nie pozwala.
Zajmuje po prostu cały czas procesora,
chociaż przez większość czasu oczekuje w
pętli na ustawienie się jakiś znaczników.
O tym, że można inaczej, przekonują
nas przykłady takich dem jak Overmind.
Podczas ładowania pokazują się tam efekty,
gdyż cała procedura ładowania realizuje
się w przerwaniach IRQ. Podobnie jest w
przypadku magazynu Energy. Ponieważ zaś
nigdy nie robimy tajemnic z naszych
rozwiązań (pod warunkiem, że sami
wykorzystaliśmy je już dużo wcześniej), więc
postanowiliśmy przedstawić tutaj nasz
sposób.
Za źródło niech posłuży nam
loader użyty w Energy #1 do ładowania
intra. Znajduje się on tam w trzech
pierwszych sektorach dysku. Wszystkie
inne używane przez nas IRQ-loadery są w
istocie bardzo podobne do tego. A zatem
zaczynamy.
Loader przystosowany jest na
sektory po 128 bajtów. Plik zaś zapisany
jest w sektorach o strukturze DOS-owej
(ostatnie 3 bajty sektora nie stanowią
danych pliku). Sam plik zaś również ma
strukturę DOS-ową. Ponadto, ponieważ nie
używamy systemu, więc absolutnie się nim
nie przejmujemy wyłączając ROM i używając
dolnej części strony zerowej. Ponieważ
dysk na którym ten loader miał być
nagrany był całkowicie w formacie
DOS-owym, więc musiałem dokonać paru
karkołomnych sztuczek, aby loader zmieścił
się w tych wyznaczonych 3 sektorach.
Zmniejsza to czytelność programu. Trudno.
Autorem IRQ-SIO jest Electron, zaś
cołości loadera Jaskier.
* IRQ-SIO Loader
bufor equ $680 ; 128 bajtów na dane odczytane z sektora.
dcb equ 0 ; 4 bajtowy bufora na dane wysyłane do stacji dysków.
; Jest to kolejno:
; -bajt identyfikujący urządzenie. Każde
; urządzenie: D1,D2,D3,D4,P1,P2,R1 itd. ma
; własny kod.
; -kod operacji. Dokładnie taki sam jak w operacjach SIO.
; -numer sektora. Młodszy i starszy bajt.
cksum equ 4 ; używane do liczenia sumy kontrolnej zarówno przy
; wysyłaniu komendy do stacji, jak i przy odbiorze.
xdone equ 5 ; stan loadera:
; 0 - odczytywane są dane bloku,
; 1-4 - odczytywany jest nagłówek bloku.
lindex equ 6 ; stan przy wysyłaniu komendy do stacji:
; 0-3 - wysyłanie tablicy dcb,
; 4 - wysyłanie sumy kontrolnej,
; 5 - wywołanie przerwania końca transmisji.
stcnt equ 7 ; stan przy odczycie sektora:
; $fe - odczytany został pierwszy bajt od
; stacji. Jeśli jest to wartość $41, to znaczy,
; że stacja prawidłowo odebrała komendę.
; $ff - drugi bajt. Jeśli jest to $43, to znaczy,
; że sektor na dysku został prawidłowo
; odczytany. Przystępujemy do transmisji.
; 0-127 - dane sektora.
; 128 - bajt sumy kontrolnej.
adr equ 8 ; adres początku bloku.
end equ 10 ; adres końca bloku.
org $500
loader dta b(0),b(3),a(loader),a(4)
start sei
cld
jsr del ; skok do procedury przygotowującej stację do wysłania komendy
stx $d40e ; w X jest 0
stx $d400
lda #$fe
sta $d301
lda #$52 ; komenda odczytu sektora
sta dcb+1
lda #4 ; numer pierwszego sektora
sta dcb+2 ; odczywywanego pliku
lda #$28 ; ustawiamy częstotliwość zegara
sta $d204
sta $d208
stx $d206
stx dcb+3
inx ; najpierw będziemy odczytywać
stx xdone ; nagłówek bloku
lda irq
sta $ffff
jsr set ; rozpoczęcie wysyłania komendy
cli
bne * ; a tu każdy może wsadzić nawet
; wektorówkę (jeśli potrafi)
; P.S. ten rozkaz BNE oznacza tyle co JMP
init jmp ($2e2); plik może mieć inity
del lda #$34 ; informujemy stację, że coś do
sta $d303 ; niej będziemy wysyłać
ldx #0 ; ustawienie licznika wysyłanych
stx lindex ; bajtów
inx ; czekamy trochę, aż stacja
bne *-1 ; przetrawi fakt, że coś od
rts ; niej chcemy. Niestety nie
; można skrócić tej pętli, gdyż niektóre
; stacje są bardzo powolne np. Tygrys Turbo
set lda #$23 ; ustawiamy POKEY-a do
sta $d20f ; transmisji (zapisu)
lda #$10 ; przerwanie zapisu
sta $d20e
lda #$31 ; wysyłamy pierwszy bajt do
sta $d20d ; stacji
sta cksum ; zliczamy sumę kontrolną
rts rts
* przerwanie zapisu danych *
irq2 cmp #$20 ; czy to aby na pewno do mnie?
bne irq3 ; do przerwania koca transmisji
lsr @ ; ustawiamy na nowo przerwanie
sta $d20e ; do zapisu
inc lindex
ldx lindex
cpx #4 ; czy nadal wysyłamy komendę?
bcs oi1
lda dcb,x
sta $d20d ; wysyłamy komendę
clc ; zliczamy sumę
adc cksum
adc #0
sta cksum
bcc irqend ; kończymy przerwanie (bcc=jmp)
oi1 bne oi2
lda cksum ; wysyłamy sumę kontrolną
sta $d20d
irqend pla ; kończymy przerwanie
tax
pla
rti
oi2 lsr @ ; ustawiamy przerwanie koca
sta $d20e ; transmisji
bne irqend ; (bne=jmp)
* przerwanie końca transmisji *
irq3 lda #$13 ; ustawiamy POKEY-a do
sta $d20f ; transmisji (odczytu)
sta $d20a ; to nie jest ustawianie generatora liczb losowych :-)
; W trybie zapisu ten rejestr pełni funkcję
; resetu złącza szeregowego. Jeśli nastąpił
; błąd transmisji to musimy złącze resetować,
; a skoro tak, to dlaczego nie robić tego
; po prostu zawsze? P.S. wsadzana wartość
; nie mają znaczenia (podobnie jak przy $d01e).
lda #$20 ; przerwanie odczytu
sta $d20e
lda #$3c ; informujemy stację, że coś
sta $d303 ; będziemy od niej odbierać
lda #$fe ; zerowanie licznika
sta stcnt ; odbieranych bajtów
lda #0 ; i sumy kontrolnej
sta cksum
beq irqend ; (beq=jmp)
* główne przerwanie *
irq pha
txa
pha
ldx #0
lda $d20e ; sprawdzamy jakie nastąpiło przerwanie (bity przy odbiorze są
; negacją tych wsadzanych do tej komórki)
stx $d20e ; zerowanie rejestru, aby mógł wskazywać kolejne przerwania
and #$30
cmp #$10
bne irq2
* przerwanie odczytu *
asl @ ; ustawiamy na nowo przerwanie
sta $d20e
lda $d20f ; pobieramy status błędu
sta $d20a ; kasujemy status błędu
bpl error ; skasowany bit najwyższy i 6-ty
and #$20 ; informują, że nastąpił błąd
beq error
ldx stcnt ; czy pobieramy teraz dane
bmi getsum ; sektora? (X=0-127)
lda $d20d ; pobieramy bajt
sta bufor,x ; i do bufora
clc ; zliczmy sumę kontrolną
adc cksum
adc #0
sta cksum
inc stcnt ; powiększamy ilość
pla ; odczytanych bajtów
tax
pla
rti
getsum cpx #$80; czy przesyłana jest
beq ii1 ; suma kontrolna?
inc stcnt ; jak nie, to powiększ ilość
lda $d20d ; przeczytanych bajtów i
cmp #$41 ; sprawdź, czy bajt statusu
beq endirq ; wysłanego przez stację
cmp #$43 ; wskazuje, że wszystko O.K.
beq endirq
error jsr del ; jeśli nastąpił błąd, to
jsr set ; odczytaj sektor jeszcze raz
endirq pla ; koniec przerwania
tax
pla
rti
ii1 lda $d20d ; sprawdzamy sumę kontrolną
sbc cksum ; jeśli wszystko O.K., to dane
bne error ; z bufora przepisujemy
* loader właściwy *
tax zerujemy ; licznik odebranych bajtów
stx lindex
lda bufor+$7e ; który następny
sta dcb+2 ; sektor odczytać?
lda bufor+$7d
and #3
sta dcb+3
ora dcb+2 ; jeśli zerowy, to znak, że to
beq l7 ; koniec pliku
lda #$34 ; jeśli jednak będziemy jeszcze
sta $d303 ; odczytywać dane, to
; przygotowujemy stację na zapis komendy
; (czas trwania przepisywania danych będzie
; tą pętlą służyć wyczekaniu, aż stacja
; załapie o co chodzi).
l7 sta l8+1 ; l8+1 to bajt, który mówi nam
; czy będziemy jeszcze odczytywać sektory
tya ; zachowujemy dodatkowo Y
pha
l1 lda bufor,x
ldy xdone ; jaki jest stan loadera
beq l2 ; 0 = odczytujemy dane
sta adr-1,y ; nie zero? to znak, że jest
; to adres bloku
lda rts ; adres nie był tam ustawiony
sta $2e3 ; to procesor napotka RTS
inc xdone ; zwiększ stan loadera
cpy #2 ; czy przesłany został cały
bne l4 ; adres początku bloku?
lda adr ; sprawdź, czy nie wynosi on
and adr+1 ; $ffff, jeśli tak, to znaczy, że
eor #$ff ; jest to tylko informacja, że
bne l3 ; ten plik jest binarny
lda #1 ; przeczytaj adres jeszcze raz
bne l6 ; (bne=jmp)
l4 tya
sec
sbc #4 ; sprawdź, czy przeczytany już
bne l3 ; został cały nagłówek
l6 sta xdone ; jeśli tak, to odczytujemy
jmp l3 ; dane bloku
l2 sta (adr),y ; umieszczamy bajt
lda adr ; sprawdzamy, czy to już
cmp end ; cały blok
lda adr+1
sbc end+1
bcc l5
inc xdone ; jeśli tak, to przystępujemy
; na nowo do czytania nagłówka
stx cksum X ; może nam się przydać
jsr init ; po przeczytaniu całego bloku
; robimy skok po $2e2. Standardowo ustawiany jest tam
; skok pod rozkaz RTS.
ldx cksum ; bierzemy X z powrotem
l5 inc adr ; następny bajt wsadzimy w
bne l3 ; następną komórkę
inc adr+1
l3 inx
cpx bufor+$7f ; sprawdzamy, czy tylko tyle bajtów w tym sektorze należy do pliku
bcc l1 ; jeśli nie, to odczytujemy następny
pla ; pobieramy Y z powrotem
tay
l8 lda #10 ; jeśli to był ostatni sektor pliku, to tutaj jest #0
beq *+5 ; a wówczas...
jmp error+3 ; odczyt następnego sektora
jmp ($2e0) ; uruchamiamy program
end
No i tak to wygląda. Może na początku
jest to nieco skomplikowane, ale po bliższym
przyjrzeniu się, każdy powienien wszystko
zrozumieć. Aby było łatwiej, wyjaśnię może
dokładniej procedurę odczytu i zapisu:
Proces zapisu bajtu do stacji
polega na tym, że bajt wysyłany wsadzamy
do komórki $d20d, a przerwanie zapisu
następuje PO wysłaniu tego bajtu do stacji.
Tak więc pierwszy bajt wsadzamy poza
przerwaniem, drugi w przerwaniu
informującym, że pierwszy bajt został
wysłany itd. W przerwaniu informującym, że
wysłana została suma kontrolna (która
zawsze jest wysyłana na końcu wysyłanego
bloku danych) ustawiamy jako następne
przerwanie zakończenia transmisji (w
domyśle zapisu, gdyż tylko wtedy to
przerwanie jest wykorzystywane).
Proces odczytu jest trochę prostszy.
Przerwanie odczytu wywoływane jest tutaj
zawsze po odczytaniu bajtu ze stacji. W
przerwaniu właśnie ten bajt odczytujemy z
komórki $d20d. Po odczytaniu wszystkich
bajtów odczytujemy sumę kontrolną. Należy
przy tym uważać gdyż bajty statusu stacji,
wysyłane przez nią dla potwierdzenia, że
dostała i zrozumiała komendę, nie są do
sumy kontrolnej wliczane.
A teraz po kolei w punktach proces
odczytu sektora:
1) Wysłanie 4 bajtów komendy + suma.
2) Natychmiast po tym, stacja wysyła nam
bajt $41, który informuje nas, że stacja
zrozumiała komendę.
3) Teraz następuje chwila przerwy. Stacja
musi zakręcić dyskiem i odczytać sektor.
4) Jeśli sektor na dysku był
prawidłowy, stacja wysyła nam bajt $43
który informuje nas, że wszystko O.K. i
zaraz nam wyśle dane.
5) Odbieramy 128+1 (256+1 lub 512+1
-zależnie gęstości dyskietki) bajtów danych
sektora z sumą kontrolną.
6) Koniec transmisji sektora.
A teraz dla aktywnych zapis:
1) 4+1 bajtów -komenda + suma.
2) Natychmiast po tym stacja wysyła nam
$41, że zrozumiała komendę.
3) Wysyłamy 128+1 (256+1 lub 512+1
-zależnie od gęstości dyskietki) bajtów
danych sektora z sumą kontrolną. Ponieważ
stacja jest przygotowana na to, nie musimy
dawać takiej długiej pętli po umieszczeniu
#$34 w komórce $d303.
4) Teraz następuje chwila przerwy. Stacja
zakręci dyskiem i zapisze sektor.
5) Odbieramy bajt $43, który oznacza,
że sektor został prawidłowo odebrany i
zapisany.
6) Koniec transmisji.
I co? Nadal jest to takie trudne?
Jak zapewne zauważyliście w Energy
#1 jest więcej niż jeden IRQ-loader. Drugi
uruchamiany jest po intrze podczas
ładowania całego magazynu.
Jego cechą
charakterystyczną jest to, że oprócz
muzyczki na dwóch kanałach, odgrywane są
tam na dwóch kanałach sample. Wbrew
pozorom jest to bardzo prymitywny efekt.
Zauważcie bowiem, że do operacji
zapisu-odczytu używane są faktycznie
generatory 3 i 4 POKEY-a, ale tylko i
wyłącznie dla ustalenia częstotliwości
transmisji. Ich głośność do tego nic nie
wnosi, a tylko tyle potrzeba, aby sample
mogły grać.
Dodatkowo mamy jeszcze jedno
ułatwienie. Po wsadzeniu wartości $34 do
komórki $d303 nie musimy robić takiej
długiej pętli oczekując na to, aż stacja
załapie, że chcemy do niej coś wysłać. Po
prostu w tym czasie wywołujemy player.
Drobne problemy nastręczyć może
procedura odgrywania sampli. Nie możemy
jej przerywać na nazbyt długo, bo sample
zaczną źle brzmieć, a procedura
przepisująca bufor do pamięci trwa
naprawdę sporo.
Rozwiązanie jest proste.
Ta procedura nie będzie znajdować się w
przerwaniu, ale w normalnym programie, do
którego skaczemy po ustawieniu się
znacznika, że cały sektor został
przeczytany, a w jej środek wsadzamy
drugą procedurę odgrywania sampli. Całość
działa w sposób następujący.
Przepisanie jednego bajtu z bufora, odegranie sampla,
przepisanie bajtu z bufora, odegranie
sampla itd.
Trzecim typem loadera użytym w
Energy #1 jest loader ładujący artykuły.
Wbrew pozorom nie jest on identyczny z
loaderem przedstawionym w tym artykule.
Ktoś spostrzegawczy zauważył zapewne, że
podczas działania tego loadera na ekranie
znajduje się logos w pięciu kolorach. A
skoro tych kolorów jest pięć, to znaczy, że
jest na fontach. A skoro ten logos jest
duży, to znaczy, że są 2 generatory
znaków. A skoro są 2 generatory, to
znaczy, że gdzieś w środku jest przerwanie
NMI. A skoro jest przerwanie NMI, to nie
może być przerwań IRQ, gdyż mają one
tę właściwość, że mogą opóźnić odebranie
NMI. A zatem całość musi być poza
przerwaniami IRQ.
Niby niemożliwe, ale
zauważmy, że tak naprawdę, to przerwania
potrzebne są nam tylko do tego, aby
dowiedzieć się kiedy odebrać następny bajt
ze stacji, albo go do niej wysłać. Tego zaś
możemy dowiedzieć się z komórki $d20e. Bity
w niej są bowiem kasowane właśnie przy
wystąpieniu danego przerwania. Loader
jest dość podobny do tego
przedstawionego tutaj. Różnice polegają na
tym, że nie ma rozkazu CLI, a procedury w
przerwaniach są przeniesione do głównego
programu i dodana jest procedurka
śledząca komórkę $d20e i w zależności od
niej skacząca do odpowiednich procedur.
I to by było na tyle, jeśli chodzi o
własne procedury obsługi stacji. W
następnym numerze postaramy się
rozszerzyć ten temat o procedury obsługi
w różnych systemach turbo oraz (jeśli uda
nam się namówić na to Foxa) procedury dla
stacji Karin.
Jaskier/Taquart

autor: dracon
Format zapisu KOALI MICROILUSTRATORA (PIC) jest obok MICropaintera, najpopularniejszym standardem zapisu grafiki na 8-bitowych komputerach Atari.
Dotychcasz ukazało się kilka artykułów na temat tegoż formatu zapisu (m.in. w MEGAZINIE i ABBUC MAG), jednak w pierwszym przypadku informacje te były niekompletne, zaś w drugim były pewne przekłamania i nieścisłości . Poza tym być może nie wszyscy mają te magazyny...
W tym artykule chciałbym opisać POPRAWNĄ budowę pliku KOALI, a w szczególności jego nagłówka (jako że właśnie o nim były podane błędne informacje), opierając się na wiadomościach z dwóch powyższych Ľródeł oraz własnych spostrzeżeniach.
Format zapisu KOALI MICROILUSTRATORA powstał w 1983 roku w firmie Koala Ware. W tej lub lekko zmodyfikowanej wersji jest (był) także używany na innych komputerach, np. C64, Apple (!). Format ten rozpoznaje większość trybów graficznych oraz różne wielkości ekranu. Na Atari używa jednak (standardowo) tylko trybu gfx #15 z rozdzielczością ekranu 160x192 piksele.
Początek pliku w formacie KOALI to specjalny nagłówek, w którym zawarte są najważniejsze informacje o obrazku, tzn. jego szerokość, wysokość, kolory, itd.
W tym miejscu pozwolę sobie zaprezentować dokładny opis wszystkich bajtów nagłówka pliku PIC:
OFFSET=0 (4-bajty)
Nazwa: Identyfikator formatu KOALI
Opis: Oznaczenie formatu Koali. Jest tu zawsze 255,128,201,199.
OFFSET=4 (2-bajty)
Nazwa: headln
Opis: Podaje długość nagłówka (tu miejsce jest w 2 bajtach), ale
zwykle jest wartość=27, tzn. tyle bajtów ma nagłówek (27=$1b)
OFFSET=6 (1-bajt)
Nazwa: revision
Opis: Nr wersji programu względnie formatu obrazka.
Normalnie jest to wartość=$01.
OFFSET=7 (1-bajt)
Nazwa: typcprs
Opis: Rodzaj kompresji:
0 = nieskompresowane
1 = kompresja pionowa
2 = kompresja pozioma
OFFSET=8 (1-bajt)
Nazwa: antic-mode
Opis: Podaje tryb grafiki obrazka wg trybów ANTIC-a.
OFFSET=9 (2-bajty)
Nazwa: scrwidth
Opis: Szerokość obrazu w bajtach. Zwykle jest tutaj wartość = 40.
OFFSET=11 (2-bajty)
Nazwa: scrheight
Opis: Wysokość obrazu w bajtach. Zwykle jest tutaj wartość = 192.
OFFSET=13 (5-bajtów)
Nazwa: scrheight
Opis: Kolory obrazka - nagrywane w takiej kolejnośći jak w pamięci, 708..712.
OFFSET=18 (2-bajty)
Nazwa: picln
Opis: Ogólna długość (samego, bez nagłówka) obrazka w bajtach.
OFFSET=20 (2-bajty)
Nazwa: unused
Opis: Zawsze wynosi 0.
To jeszcze nie wszystko o nagłówku... Od adresu OFFSET+22 są 4 komórki zarezerwowane na tekst dla tytułu rysunku, autora i pozostałych uwag. Każda taka komórka tekstowa może mieć maksymalnie 40 znaków i musi być zakończona kodem EOL ($9b, #155 dec). Oczywiście żaden program nie używa tych komórek "tekstowych". Dlatego znaleĽć można tutaj normalnie wartość 155 powtórzoną cztery razy. Wpisując w to miejsce jakiś tekst trzeba go zakończyć EOL'em i zwiększyć odpowiednio długość nagłówka w komórce "headln" (tzn. podać nową wartość długości nagłówka, liczonej razem z "komentarzem").
Nagłówek kończy tzw. "spare byte" (zapasowy bajt). Wynosi on zazwyczaj 162 ($a2), chociaż popularny XL-Art, nagrywając w kompresji Koali wstawia tu wartość $a5.
Jest sporo do skomentowania odnośnie powyższej rozpiski nagłówka Koali.
Wg Bewesofta mogą być ładowane pliki z tylko częścią ekranu - ponoć oryginalny program KOALA M. potrafi je wczytać... Pozycja i rozmiar tzw. "okna", czyli części "scrwidth" i "scrheight". Te 4 bajty określają: początkową pozycję X (w bajtach, a nie w pikselach !), końcową pozycję X obrazu (pierwszą pozycją PO obrazku), początkową pozycję Y obrazu i końcową pozycję Y.
Kolory nagrywane są w kolejności takiej jak w pamięci (708-712), czyli w kolejne bajty od OFFSET+13 jest nagrywanych pięć wartości. Wszystkie kolory można dowolnie ustawić w jakimś programie graficznym i ich wartości pojawią się w komórkach "colors" nagłówka KOALI. Jedynie może być problem z ustawieniem koloru inwersji ($2c7), który to można zmienić tylko w edytorach do logosowania grafiki... Ale to nieistotne, gdyż inwersja ważna jest tylko w grafice znakowej...
W każdym razie wartość, jaką można zwykle zastać (dla koloru rejestru $2c7) w nagłówku KOALI, to albo $00, albo $46...
W użyciu może być jeden z trzech typów kompresji (7 bajt nagłówka) - wartość $00 oznacza brak kompresji w obrazku, czyli, że reszta pliku (po nagłówku) zawiera tylko samą pamięć ekranu.
Wartość $01 jest najczęściej używaną metodą. Oznacza ona spakowane dane, które zostaną umieszczone na ekranie w "pionowym" uporządkowaniu: najpierw bajty w liniach parzystych 0,2,4,6, itd. potem bajty w liniach nieparzystych 1,2,5,7 itd. Po rzędach "idą" w ten sam sposób kolumny ekranu.
Metoda $02 również zawiera spakowane dane, ale będą one umieszczone na ekranie tak samo jak w metodzie $00 (poziomo).
Bajt 20-ty z nagłówka (nazwany "unused") został słusznie przeznaczony przez twórców formatu na przyszłe użycie. Pozwoliło to Hermesowi (autorowi viewera "ShowPIC v2.0") bardzo pożytecznie wykorzystać pierwszy bajt z pary "unused". Mianowicie został on użyty do przechowywania informacji dla GTIA o jej trzech dodatkowych trybach (tj. gfx #09, ,#10, #11). Pozwala to na wczytywanie skompresowanej grafiki również w w/w trybach graficznych, co oczywiście zaoszczędza miejsce na dysku... Oto jak zostało to zorganizowane...
Dwa najmłodsze bity pierwszego nieużywanego bajtu "unused" zawierają informację o powyższych trybach graficznych w następującej kolejności:
00 = zwykły tryb Antica (gfx #08)
01 = 16 jasności tego samego koloru (gfx #09)
10 = 9 dowolnych kolorów z palety 256 (gfx #10)
11 = 16 kolorów o jednakowej jasności (gfx #11)
Pozostałe bity z tego bajtu oraz drugi wolny bajt są przez viewer "ShowPIC v2.0" nieużywane. Powyższe wykorzystanie bajtu "unused" jest nazwane przez jego pomysłodawcę jako "PIC v2". Idea Hermesa jest zaiste genialna, lecz do tej pory spotkałem się z jej zastosowaniem tylko w "ShowPIC v2.0"... Warto byłoby ją upowszechnić...
Dużym problemem jest to, że większość tzw. Viewerów, Showerów, czy loaderów (programów odtwarzających format KOALI) potrafi ładować pliki PIC tylko ze standardową długością nagłówka, wynoszącą $1b (27) bajtów. Tymczasem, nagłówek może być teoretycznie zmienny, np. gdy dodasz jeszcze komentarz do obrazka od komórki OFFSET+22 !!! Więcej, większość loaderów odczytuje z nagłówka tylko jedną rzecz - dane kolorów !!! Zauważył to już Bewesoft... Taki sposób działania tych programów można wytłumaczyć tylko jednym: LENISTWEM autorów tychże programików...
Jeśli zechcesz sobie np.dodać komentarz do rysunku, umieszczając go w nagłówku pliku, w odpowiednim miejscu, wiedz, iż na palcach można będzie policzyć programy, które to poprawnie odtworzą... Z przeprowadzonych przez mnie testów wynikło, że uda Ci się to tylko w:
- loaderze BeweSofta z ABBUC Magazine
- ShowPIC v2.0 Hermesa
- oryginalnym KOALA MICROILUSTRATOR
(te trzy powyższe programy można ogólnie spokojnie uznać za najlepsze - dotąd - loadery dla formatu Koali)...
Z "eliminacji" odpadły natomiast loadery KOALI w takich programach, jak: GRAPH VIEW z CrisisSoft, GRAPH.COM Souseda, XL-Art, RAMbrandt (!), BIT CONVERTER Bartmana oraz paru innych, o których akurat zapomniałem.
Problem "olewania" sobie wartości z nagłówka wynika również z innej, bardziej praktycznej (od wstawiania komentarzy do obrazków) rzeczy - przykładowo XL-Art przy zapisie PIC-a "zapomina" o zapisaniu w nagłówku Koali informacji o długości samego obrazka (nie wstawia nic do bajtów "picln" w nagłówku obrazka).
Jako że większość "loaderów" również nie sprawdza bajtu "picln", wszystko jest OK... do czasu, aż napotkasz jakiś program, którego twórca spodziewał się, że są jeszcze dobrze napisane procedury obsługi kompresji KOALI i... w tymże programie nie zapomniał o tym bajcie... Wtedy zaczynają się kłopoty, bo program sprawdzający np. bajt "picln", po prostu (od razu) nie wczyta takiego PIC-a, który nie ma tam żadnej wartości (czyli "picln" = $00,$00). Po sprawdzeniu braku odpowiedniej wartości w nagłówku po prostu przerwie odczyt... Do tej pory spotkałem się z dwoma takimi przypadkami - w niezłym programie graficznym (dla trybu gfx #15) "Pixel Artist De Luxe v1.3" (swoją drogą jest on niezły dla posiadaczy tabliczki graficznej...) oraz w basicowym programie do wydruku obrazków "PICPRINT", zamieszczonym w jednym z wydań zinu "OHAUG"... Obydwa programy "buntowały się", gdy chciałem wczytać jakiś PIC z XL-Art, ale przyczyna okazała się prozaiczna - brak tego jednego, jedynego bajtu, na który zwracały uwagę... Zatem aby do nich wczytać taki obrazek, należy wpisać do jego nagłówka odpowiednią wartość w bajtach "picln" za pomocą jakiegoś monitora (dyskowego)... Można też wczytać obrazek w postaci MIC do "Pixela..." i tam zgrać go jako PIC. Zostanie on zapisany w rzadziej spotykanej poziomej kompresji... Na szczęście nie będzie już kłopotów z ładowaniem tak "przerobionego" obrazka w drugą stronę, tzn. w np. XL-Art, bo on bajty "picln", jak już wcześniej wspominałem, ignoruje.
Wypadałoby na koniec podać jednak budowę samej kompresji KOALI... Oto, jak to mniej więcej wygląda...
Same dane obrazka (tzw. mapa bitowa) są skompresowane prostym algorytmem RLE (redukcja powtarzających się elementów). Kiedy np. pięć razy, jeden za drugim wystąpi w obrazku wartość "0", nagrane zostaną jako "5x0". Obrazek jest umieszczony w poszczególnych blokach. Są dwa typy bloków użytych w kompresji KOALI:
Dane niespakowane. Pierwszy bajt (jako znacznik) ma ustawiony bit 7 (#128 dec), reszta tego samego bajtu stanowi długość bloku danych (maksymalnie 127 bajtów). Jeśli ta długość wynosi zero, to jest wtedy jeszcze o dwa bajty więcej - informują one o aktualnej długości (2-bajtowa wartość, więc będzie DOSYĆ długi niespakowany blok !). Następnymi bajtami są już same niespakowane dane.
Dane spakowane. Pierwszy bajt w takim bloku ma wyzerowany siódmy bit, reszta zaś jest długośćią bloku - tak samo, jak opisana wyżej. Tu jest tylko jeden bajt danych, który wypełni swą wartością wszystkie bajty w bloku. Po prostu informuje on o tym jaka wartość jest skompresowana, a ze znacznika (pierwszego bajtu w bloku, informującego o statusie i długości całego bloku) wynika, ile razy trzeba go powtórzyć. Tu także może wystąpić długi, spakowany (tym razem) blok składający się z 3 bajtów "informujących" i jednego bajtu danych - zasada jest podobna jak w bloku niespakowanym.
To byłoby na tyle w temacie budowy pliku w formacie KOALI MICROILUSTRATORA. Mimo, że efektywność kompresji w oferowany przez KOALĘ sposób jest raczej kiepska (szczególnie przy dużych skomplikowanych obrazkach), to zapis PIC jest bardzo popularny, zapewne głównie przez prostotę jego realizacji (format podobny do PIC stosuje np. edytor CIN, Trzmiel, RGB Shower, czy XL-Paint...). Jakby jednak na to nie patrzeć, (prawie) zawsze obrazek trochę się skróci i raczej w wyjątkowych przypadkach opłaca się trzymać plik MIC zamiast PIC-a.
Mam nadzieję, że zamieszczone tu informacje przydadzą się szczególnie koderom, spośród których może ktoś wreszcie napisze przeglądanie obrazków w kilku(nastu) formatach graficznych (np. PIC, PIC v2, GED, CIN, DigiPaint, RGB, INT...).
Specjalnie dla Was "produkował się"...
-Dracon-