Programowanie: Odtwarzanie sampli
From Atariki
Komputery Atari poza wbudowanym POKEY-em dysponują kilkoma rozszerzeniami pozwalającymi na generowanie sampli. Poza SoundBoard-em który potrafi odgrywać sample samodzielnie, wszystkie dostępne rozwiązania wymagają zaangażowania procesora, w związku z czym często ich wykorzystanie np. w grach jest mocno ograniczone.
Warto pamiętać, że częstotliwość syntezy sampli jest uzależniona od zegara taktującego CPU, a więc od systemu TV (PAL/SECAM/NTSC) w jakim pracuje komputer.
Spis treści |
POKEY
Odtwarzanie sampli możliwe jest poprzez zastosowanie różnych technik, które pozwalają na osiągnięcie różnej jakości dźwięku.
PCM
Pulse-Code Modulation jest podstawową techniką generowania sampli i polega na bezpośrednim sterowaniu wychyleniem membrany głośnika w dowolnym rejestrze AUDCx.
4-bit
Technika ta w podstawowym wariancie pozwala na uzyskanie sampli o 4-bitowej jakości.
Włączenie trybu bezpośredniego sterowania membraną odbywa się przez ustawienie bitu 4. Bity odpowiadające za głośność (0..3) odpowiadają wtedy za wychylenie membrany: $0 - bez wychylenia, $F - maksymalne wychylenie.
$F : == $E : == $D : == $C : == $B : == $A : == $9 : == $8 : == $7 : == $6 : == $5 : == $4 : == $3 : == $2 : == $1 : == $0 +==------------------------------
Liniowy przetwornik DAC (w odróżnieniu od przetwornika zastosowanego np. w PSG) powoduje, że nie jest potrzebne dodatkowe przetwarzanie wartości sampla.
Mając więc w młodszej połówce akumulatora wartość próbki wystarczy:
ora #$10 sta AUDCx
Jeśli próbka znajduje się w starszej połówce akumulatora można:
sec ror ror ror ror sta AUDCx
co można nieco zoptymalizować za pomocą tablicy konwersji (kiedy przykładowy sample znajduje się w górnej połówce rejestru indeksowego X)
lda convtabh,x sta AUDCx ... convtabh: :256 .byte (# >> 4) | $10
Jeśli z jakichś powodów nie można użyć akumulatora a dysponujemy próbką w młodszej połówce rejestru indeksowego (w poniższym przykładzie X) można zastosować analogiczną metodę:
ldy convtabl,x sty AUDCx ... convtabl: :256 .byte (# & $F) | $10
Aby zyskać pewność, że procedura zawsze będzie się wykonywać stałą liczbę cykli należy tablice umieścić na początku strony.
W ten sposób można grać niezależnie 4 sample na 4 kanałach POKEY-a. Należy jednak pamiętać, że przy sumowaniu wyjść ze wszystkich kanałów DAC zachowuje się nieliniowo i sample mogą być zniekształcone.
5.5-bit
Technika została zastosowana przez Pecusia w SoundTracker Player w celu podniesienia jakości odtwarzanych sampli przez redukcję nieliniowości DAC związanej z sumowaniem kanałów. Mając więc 8-bitową próbkę można (prawie w jednej chwili) ustawić wartości w 3 kanałach POKEY-a a nie tylko w jednym:
ldy convtab3,x lda convtab1,x pha lda convtab2,x tax pla sta AUDC1 stx AUDC2 sty AUDC3
Zapis czwartego kanału jakkolwiek możliwy, wprowadza jednak mocne zniekształcenia więc poprzestano na trzech co pozwala uzyskać 46 możliwych wartości - stąd też nazwa "PCM 5.5" (log246=5,5236).
Same tablice konwersji sampla zostały przez Pecusia dobrane eksperymentalnie:
convtab1: :4 .byte $10 :4 .byte $10 :4 .byte $11 :4 .byte $11 :4 .byte $11 :4 .byte $12 :4 .byte $11 :4 .byte $12 :4 .byte $13 :4 .byte $12 :4 .byte $14 :4 .byte $13 :4 .byte $14 :4 .byte $13 :4 .byte $15 :4 .byte $14 :4 .byte $15 :4 .byte $13 :4 .byte $16 :4 .byte $14 :4 .byte $15 :4 .byte $15 :4 .byte $18 :4 .byte $16 :4 .byte $18 :4 .byte $16 :4 .byte $19 :4 .byte $17 :4 .byte $1A :4 .byte $15 :4 .byte $1C :4 .byte $17 :4 .byte $1D :4 .byte $17 :4 .byte $19 :4 .byte $17 :4 .byte $1C :4 .byte $1B :4 .byte $18 :4 .byte $1E :4 .byte $1A :4 .byte $19 :4 .byte $1B :4 .byte $1C :4 .byte $1C :4 .byte $1B :4 .byte $1F :4 .byte $1D :4 .byte $1C :4 .byte $1C :4 .byte $1C :4 .byte $1B :4 .byte $1D :4 .byte $1C :4 .byte $1D :4 .byte $1C :4 .byte $1B :4 .byte $1D :4 .byte $1F :4 .byte $1E :4 .byte $1E :4 .byte $1F :4 .byte $1F :4 .byte $1F convtab2: :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $11 :4 .byte $11 :4 .byte $11 :4 .byte $11 :4 .byte $10 :4 .byte $11 :4 .byte $11 :4 .byte $12 :4 .byte $11 :4 .byte $12 :4 .byte $11 :4 .byte $13 :4 .byte $11 :4 .byte $12 :4 .byte $13 :4 .byte $14 :4 .byte $11 :4 .byte $12 :4 .byte $12 :4 .byte $13 :4 .byte $12 :4 .byte $14 :4 .byte $12 :4 .byte $15 :4 .byte $11 :4 .byte $14 :4 .byte $11 :4 .byte $15 :4 .byte $15 :4 .byte $16 :4 .byte $12 :4 .byte $15 :4 .byte $15 :4 .byte $12 :4 .byte $18 :4 .byte $16 :4 .byte $16 :4 .byte $18 :4 .byte $15 :4 .byte $17 :4 .byte $15 :4 .byte $1A :4 .byte $1A :4 .byte $1B :4 .byte $1B :4 .byte $1A :4 .byte $18 :4 .byte $1A :4 .byte $1D :4 .byte $1B :4 .byte $1B :4 .byte $1B :4 .byte $1E :4 .byte $1E :4 .byte $1E :4 .byte $1D :4 .byte $1E :4 .byte $1F convtab3: :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $10 :4 .byte $11 :4 .byte $12 :4 .byte $11 :4 .byte $12 :4 .byte $11 :4 .byte $10 :4 .byte $10 :4 .byte $12 :4 .byte $10 :4 .byte $12 :4 .byte $10 :4 .byte $11 :4 .byte $10 :4 .byte $13 :4 .byte $10 :4 .byte $13 :4 .byte $10 :4 .byte $13 :4 .byte $11 :4 .byte $13 :4 .byte $12 :4 .byte $11 :4 .byte $14 :4 .byte $12 :4 .byte $10 :4 .byte $14 :4 .byte $13 :4 .byte $10 :4 .byte $14 :4 .byte $14 :4 .byte $13 :4 .byte $10 :4 .byte $12 :4 .byte $12 :4 .byte $13 :4 .byte $16 :4 .byte $17 :4 .byte $17 :4 .byte $14 :4 .byte $18 :4 .byte $1B :4 .byte $1A :4 .byte $17 :4 .byte $19 :4 .byte $1B :4 .byte $1D :4 .byte $1E :4 .byte $1F
Przy odtwarzaniu sampli tą techniką zajęte są 3 kanały POKEY-a, więc można odtwarzać tylko jeden sample na jednym POKEY-u (tym samym miksowanie sampli musi być zrobione programowo). Kanał 4 może być wykorzystany do generowania sampli PCM 4-bit lub jako zwykły generator dźwięku (rejestr AUDCTL można dowolnie konfigurować, rejestry AUDF3 i AUDF4 mogą być połączone w parę, a rejestrem głośności ustala się głośność dźwięku; co więcej wybierając np. kanały 1, 3 i 4 do odtwarzania sampla można użyć pary kanałów 1+2 do generowania dźwięku, a 3+4 do sterowania filtrem).
PWM (6-bit i -7-bit)
Generowanie sampli techniką Pulse-Width Modulation zostało opisane przez NRV w wątku https://atariage.com/forums/topic/278463-pwm-experiments/. Pozwala ona na uzyskanie sampli o 6-bitowej lub prawie 7-bitowej jakości zależnie od częstotliwości syntezy.
Trick polega na generowaniu za pomocą kanału 1 fali prostokątnej o zadanej szerokości pulsu co pozwala uzyskać n poziomów głośności pomiędzy 0 a ustawieniem rejestru AUDC. Okres fali powinien być ustawiony poza granicą słyszalności.
W najprostszym przypadku wykorzystuje się okres generowania pojedynczej linii skanningowej obrazu (114 cykli zegarowych), ze względu na łatwość synchronizacji syntezy za pomocą rejestru WSYNC. Generowana fala ma wtedy częstotliwość 15556,553 Hz, co może powodować słyszalny wysoki pisk (zwłaszcza u młodszych osób).
Konfiguracja POKEY-a polega na połączeniu dwóch kanałów w 16-bitowy i ustawieniu okresu fali na czas dłuższy niż linia skanningowa.
lda #%01010000 sta AUDCTL lda #$FF ;okres fali 65535+7 cykli sta AUDF1 sta AUDF2 lda #$AF sta AUDC1 lda #$10 sta AUDC2
Poprzez sterowanie wartością młodszej połówki dzielnika częstotliwości odbywa się ustalenie wypełnienia fali.
Zapis 8-bitowej próbki dostępnej w X odbywa się cyklicznie co linię skanningową poprzez:
lda convtab,x sta WSYNC sta AUDF1 sta STIMER convtab: :256 .byte #*113/255
Zapis do STIMER powoduje restart dzielników częstotliwości i ustawienie wewnętrznego wyjścia AUDIO 1 i 2 w stan wysoki. Mimo, że generatory połączone są w parę, to po odliczeniu AUDF1 do zera wyjście AUDIO tegoż generatora zostanie przestawione w stan niski, po czym licznik będzie kontynuował odliczanie okresu 256 taktów zegara ponieważ generatory są połączone w parę, a okres generatora 16-bitowego jest większy niż 256 cykli. W międzyczasie program dokona ponownego ustawienia AUDF1 i zrestartuje dzielniki co spowoduje generowanie fali od nowa.
Regulacja głośności tak generowanego sampla odbywa się przez zapis wartości do AUDC1.
Ze względu na to, że w ten sposób można ustawić jedynie 114 poziomów ze 128, technika ta nazywana jest czasem "PWM -7-bits". W praktyce używa się 100 poziomów ponieważ minimalna szerokość pulsu PWM wynosi 7 cykli.
Przyjmując wyższą częstotliwość syntezy można pozbyć się uciążliwego pisku kosztem jednak jakości bitowej sampla. Przykładowo zakładając okres 72 cykli (24631,208 Hz) otrzymujemy 64 poziomy głośności i 6-bitową jakość sampli - stąd w tym wariancie spotyka się określenie "PWM 6-bits".
Zapis 8-bitowej próbki dostępnej w X odbywa się cyklicznie poprzez:
lda convtab,x sta AUDF1 sta STIMER convtab: :256 .byte #*63/255
Zamiast synchronizacji z linią skanningową należy w tym przypadku zastosować zwykłą pętlę lub synchronizację z przerwaniami TIMER4.
Przy użyciu tej techniki można odtwarzać dwa sample na jednym POKEY-u (para kanałów 3 i 4 będzie się zachowywać analogicznie - należy jedynie pamiętać, że generowany przebieg jest odwrócony w fazie o 180 stopni, a więc wartość wypełnienia powinna być odjęta od wartości maksymalnej). Kanały 2 i 4 można wykorzystać do generowania sampli PCM 4-bit.
PDM (8-bit)
Ta technika opisana przez kool kitty89 w wątku https://atariage.com/forums/topic/244946-using-pulse-density-modulation-for-8-bit-pcm a zaimplementowana przez Xuel-a nazwana została Pulse Density Modulation i pozwala na uzyskanie sampli o ośmiobitowej jakości na standardowym POKEY-u.
Sztuczka polega na generowaniu górnej połówki sampla za pomocą PCM na kanale 3 POKEY-a, a dolnej za pomocą głośności fali o stałym wypełnieniu 1/16 i częstotliwości poza zakresem słyszalności (110840,437 Hz) skonfigurowanej na kanale 1 co powoduje uzyskanie pośredniego wychylenia membrany pomiędzy stanami $0 a $1.
$F :== == $E : $D : $C : $B : $A : $9 : $8 : == == $7 : $6 : $5 : $4 : $3 : $2 : $1 : $0 +--==============================--==============================--==============================--============================== 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
Do działania wymagana jest jednorazowa konfiguracja POKEY-a pozwalająca na ciągłe generowanie fali o wypełnieniu 1/16 na kanale 1:
lda #%01100100 ;1.77MHz dla #1 i #3, filtr w #1 sterowany przez #3 sta AUDCTL ldx #7-4 ;teoretycznie 16-4 ldy #9-4 ;teoretycznie 17-4 stx AUDF1 sty AUDF3 sta STIMER stx AUDF3
Obydwa generatory ustawione są na ten sam okres (x), lecz fala w kanale 3 generowana jest z offsettem 2 cykli (y) względem kanału 1. Ponieważ włączony jest filtr powoduje to generowanie szpilki z ustalonym okresem.
x x x x x :======= : =:===== : ======= ======= ======= == #AUDF1 : : x : : x x x x +-------=:=====-:-----=:=====-------=======-------=======-------======= y : : x : x x x :========: :======: ======= ======= ======= #AUDF3 : : x : : x x x x +--------:======:------:=======-------=======-------=======-------======= : : : : : :======: ======= ======= ======= LATCH : : : : +--------:======:------:=======-------=======-------=======-------======= : : : #AUDF1 : : == == == == == == == == == XOR : : : : LATCH +--------:=====-:=====-:=====--=====--=====--=====--=====--=====--=====--
Na wyjściu generatora 1 pojawia się wynik będący rezultatem operacji XOR między wewnętrznym rejestrem (LATCH) układu zawierającym stan wewnętrznego wyjścia AUDF1 próbkowany przy każdym przepełnieniu generatora 3 a aktualnym wewnętrznym wyjściem generatora AUDF1.
Teoretycznie wyliczone wartości generowały spory szum. W praktyce okazało się że najlepsze efekty daje konfiguracja fali o wypełnieniu 1/7.
Zapis 8-bitowej próbki dostępnej w X odbywa się poprzez:
ldy convtabh,x lda convtabl,x sty AUDC3 sta AUDC1 convtabl: :256 .byte (# & $F) | $A0 convtabh: :256 .byte (# >> 4) | $10
Przy użyciu tej techniki można odtwarzać dwa sample na jednym POKEY-u (ponieważ para kanałów 2 i 4 będzie się zachowywać identycznie).
COVOX
Covox udostępnia 4 8-bitowe liniowe przetworniki DAC, więc zapis 8-bitowego sampla odbywa się poprzez zapis rejestru odpowiadającemu wybranemu kanałowi.
W większości rozwiązań kanał 1 i 4 mapowany jest do lewego wyjścia audio, a 2 i 3 do prawego (jak miało to miejsce na Amidze).
Wyjątkiem jest SimpleStereo, gdzie do lewego wyjścia audio zostały zamapowane kanały 1 i 2, a do prawego kanały 3 i 4.
SimCOVOX
SimCovox pozwala na użycie pojedynczego liniowego 8-bitowego przetwornika DAC (więc odgrywanie kilku kanałów wymaga programowego miksowania).
Wersja podłączana przez złącze joysticków ogranicza częstotliwość syntezy do około 16 kHz ze względu na zabezpieczenia na liniach układu PIA mające chronić przed przepięciami.
Wersja zintegrowana z IDE Plus jest tej wady pozbawiona.