Zvuk na osmibitovém počítači Enterprise

Ovládání zvuku v IS -BASICu, použití služeb operačního systému EXOS a přístup na porty DPC čipu Dave.

Zvukový čip Dave obsažený v Enterprise je specifický čip, který nebyl použit v žádném jiném počítači.
Neslouží jen ke tvorbě zvuků (tři kanály tónové, jeden šumový, se stereo váhou, filtrem, distorzí a ring modulací tónu, se zabudovanými D/A převodníky schopnými softwarově přehrávat samply), ale slouží i ke správě paměti.

Přistupuje se na něj, vedle příkazů IS-Basicu pro tvorbu zvuku, buď přímo pomocí portů, nebo pomocí ovladače.

Jaké je možné použít pro tvorbu zvuku příkazy IS Basicu?

Výstup zvuku se děje jednak na zabudovaný reproduktorek, jednak na stereo výstup, ke kterému lze připojit sluchátka nebo stereo zesilovač.
Pokud chcete poslouchat stereo výstup, a chcete vypnout zabudovaný reproduktorek, použijte buď příkaz SET SPEAKER OFF, nebo shift+F7.

Zvuk samotný se generuej za použití dvou příkazů: SOUND a ENVELOPE. příkazem SOUND se charakterizuje a spouští samotný zvuk, ENVELOPE definuje jeho obálku.
Malý příklad:
SOUND PITCH 40, LEFT 127, RIGHT 191, DURATION 200, ENVELOPE 10
PITCH je výška v půltónech od 0 do 127. Malému c odpovídá hodnota 37, pokud není parametr PITCH uveden, použije se hodnota 37.
LEFT a RIGHT určuje hlasitost levého a pravého kanálu 0-254. Nula je ticho. 255 ruší obálku a přehrává stálým tónem.
DURATION je trvání v padesátinách sekundy, zde tedy 4 sekundy (200/50=4).
ENVELOPE vybírá obálku, uživatelem definovatelné obálky jsou 0-254.

Obálku lze definovat například takto:
ENVELOPE NUMBER 10; 2, 8, 63, 50; 0, 24, -16, 100; -5, 47, -39, 50
Čtveřice čísel definuje klouzavou změnu výšky během trvání tónu (zde se v první fázi zvýší postupně o dva půltóny), změnu hlasitosti pro levý a pak pro pravý kanál -63..+63 (-63 ztiší až do ticha, +63 na maximální hlasitost) a dobu trvání fáze v padesátinách sekundy  (zde je tedy čtyřsekundová obálka se sekundovou první fází, dvousekundovou druhou fází a sekundovou třetí fází).
Obálka může mít teoreticky až 255 fází.
Kromě doby trvání jsou hodnoty pro změnu výšky a hlasitosti relativní.
Do definice obálky lze vložit slovo RELEASE, za kterým se definují fáze, které se mají použít pro doznívání tónu. Pokud zadává DURATION v příkazu SOUND kratší dobu, než na kolik je definována obálka, nestihnou se tak přehrát všechny fáze a při uplynutí vymezené doby se skočí na fáze obálky definované za klíčovým slovem RELEASE.

V příkazu SOUND lze dále použít parametr INTERRUPT, který způsobí, že se usekne právě přehrávaný zvuk, vyprázdní fronta tónů a začne se hned přehrávat zvuk, který má parametr INTERRUPT v sobě uveden. ovlivňnuje jen zvuk “svého” kanálu a ostatní kanály nechává znít podle jejich zadání.

Pokud chcete přehrát tón určitým kanálem, přidejte parametr SOURCE s hodnotou 0-3 (0-2 jsou tónové kanály 3 je šumový kanál).

Když už zadáváte tóny do tří různých front (pro každý kanál) a chcete, aby spustily současně, přidejte parametr SYNC, pro všechny 3 kanály použijte SYNC 2 (tedy “čekej, než se načtou další dva zvuky čekající na synchronizaci”).

Příkaz CLEAR QUEUE s parametrem 0-3 umlčí příslušný kanál a vyprázdní jeho frontu.

Defaultně jsou buffery nastaveny pro obálky do 20 fází. Pokud chete použít obálky delší, musíte zavřít kanál zařízení “SOUND:”, který se interně používá k jeho programování, nastavit buffery a pak kanál znovu otevřít. Takto:
CLOSE #103: SET SOUND BUFFER <počet fází obálky>: OPEN #103:”SOUND:”

Posledním parametrem, který lze použít ve spojení s příkazem SOUND, je STYLE v rozsahu 0-255.
Je trochu složitější, protože vychází ze skládání bitů pro řídící registry kanálů, ale v jednoduchosti:
16 – nízná distorze
32 – střední distorze
48 – vysoká distorze
64 – hi-pass filtr. Jako zdroj frekvence se bere pro kanál 0 kanál 1, pro kanál 1 kanál 2, pro kanál 2 šumový kanál (3) a pro šumový kanál je to ještě jinak.
128 – ring modulace, na kanálu 0 kanálem 2, na kanálu 1 kanálem 3 a na kanálu 2 kanálem 0
Pro dosažení kombinace efektů se hodnoty sčítají.

Styl na šumovém kanálu (3):
1, 2, 3 – místo 31.75 kHz použít jako zdroj frekvence kanál 0, 1 nebo 2
4, 8, 12 – místo 17bitového polynomiálního čítače použít 15bitový, 11bitový nebo 9bitový
16 – nahradit 7bitový polynomiální čítač 17bitovým
32 – lo-pass filtr, jako zdroj frekvence se bere kanál 2
64 – hi-pass filtr, jako zdroj frekvence se bere kanál 0
128 – ring modulace tónem kanálu 1
Pro dosažení kombinace efektů se hodnoty sčítají.

Tolik by v krátkosti bylo o používání zvuku na Enterprise z IS-Basicu.

Než se pustíme do popisu portů, podívejme se ještě na ovladač systému EXOS.

EXOS se zařízeními komunikuje pomocí kanálů, do kterých se posílají příslušné povely a případně se z nich čtou příchozí data.
EXOS umožňuje otevřít pro zvukové zařízení “SOUND:” jeden kanál, do kanálu lze pouze zapisovat, nejde z něj číst.

Zápisy do kanálu se udržuje fronta zvuků pro všechny čtyři kanály, v RAM je vyčleněn buffer o 25 pozicích pro každý kanál.
Podobně jako fronta zvuků existuje i fronta obálek.
Obálky jsou o hodnotách 0-255, kdy nula je ticho a ostatní hodnoty ovlivňují průběh frekvencí (pitch) a amplitudy pro levý a pravý audiokanál, hodnota 255 je bez změny frekvence a hlasitosti stálým tónem.
Velikost této fronty se definuje v systémové proměnné BUF_SND ještě před otevřením kanálu. Buffer lze použít pro kombinace různého počtu obálek o různé délce, například pro jednu obálku s dvaceti fázemi nebo pro dvacet obálek po jedné fázi. Obecně může mít obálka 1-40 fází.
Fáze obálky je definována čtyřmi hodnotami:
PD – phase duration (trvání jedné fáze v padesátinách sekundy, 16 bitů),
CP – change pitch (změna frekvence během celé fáze v 1/512 půltónu, 16 bitů signed -32768..+32767),
CL – change left (změna hlasitosti levého kanálu během celé fáze, 8 bitů signed -63..+63) a
CR (change right, změna hlasitosti pravého kanálu).
Zdůrazňuji, že do změn hodnot se zapisuje celková výsledná změna, ne velikost změny za jedno přerušení. ovladač si velikost kroku interpoluje ze zadaných hodnot sám, na což používá pro větší přesnost interní 14bitový čítač.

Zápis obálky se provádí pomocí ESC sekvence do “SOUND:” kanálu:
esc E <číslo tvaru obálky 0..254> <počet fází, 8 bitů> <číslo release fáze, která ovlivňuje doznívání po ukončení noty, 225 je bez doznívání>  [ <CP> <CL> <CR> <PD>] *
Ještě jednou přehledně:
esc E <en> <ep> <er> [ <cp> <cl> <cr> <pd> ]*
Při zapsání obálky se nejprve z fronty vyřadí stará obálka a pak zapíše nová. Pokud se tedy nová obálka nevejde, je stará obálka ztracena.

Nejjednodušeji se generuje systémové pípnutí (ASCII kód BELL). Stačí tento kód (CHR$ 7) poslat do kanálu zařízení “VIDEO:” nebo “SOUND:”. Toto pípnutí používá kanál 2, pokud je obsazen jiným tónem, pípnutí se neozve.

Pro zadání zvuku se používá tato ESC sekvence:
esc S <obálka – 255 je stálý tón bez obálky, 8 bitů> <počáteční pitch v 1/512 půltónu, v šumovém kanálu se ignoruje, 16 bitů> <hlasitost levého kanálu 0..255> <hlasitost pravého kanálu 0..255> <styl tónu – 0 je čistý tón nebo bílý šum, jinak u šumu se bajt posílá do registru pro trvání zvuku a u tónu horní čtyři bity do ovládacích bitů v registru frekvence daného kanálu, ovlivňujících filtraci, distorzi a modulaci, 8 bitů> <kanál – 0, 1  2 jsou tónové kanály, 3 je šumový, 8 bitů> <trvání v padesátinách sekundy, 16 bitů> <flagbyte – 8 bitů, b0..b1 SYNC synchronizace zvuku, b2..b6 mají být v nule, b7 nastavený přebije tóny ve frontě, se shozeným se čeká na jejich dohrání>
ještě jedndou přehledně:
esc S <env> <p> <vl> <vr> <sty> <ch> <d> <f>

Pokud není nastaven bit 7 ve flagbyte, který způsobí smazání fronty, zařazuje se zvuk na její konec. Pokud se nevejde, postupuje s epodle nastavení proměnné WAIT_SND – v nule se čeká, až bude ve frontě místo a zvuk se do ní zařadí (provádění programu je během čekání pozastaveno, lze zastavit klávesou STOP), při nenulové hodnotě se vrací chybový kód .SQFUL.

Co se týče synchronizace, hodnota SYNC slouží k tomu, aby mohly tóny ve více kanálech začít hrát současně, i když se programátorovi časování rozjede. Synnchronizace se zadává jako dvojbitová hodnota. Ovladač si udržuje čítač synchronizace SYNC_COUNT, který je normálně nulový.
Když se zvuk ve frontě dostane na řadu, při nulové synchronizační hodnotě se prostě začně normálně přehrávat.
Pokud je SYNC nenulový, zadrží se tón ve frontě, při nulovém SYNC_COUNT se do SYNC_COUNT hodnota SYNC přenese, pokud je SYNC_COUNT nenulový, dekrementuje se (tedy vždy, kdy dorazí nový tón s nenulovým SYNC) a při dosažení nuly spustí současně všechny pozdržené tóny.
Čili pokud chceme spustit současně tři tóny, uložíme je každý do jiného kanálu se SYNC nastaveným na 2 (o jedna méně, než je počet tónů). Je pak jedno, který tón dorazí jako první, ovladač zařídí čekání na další dva synchronizované (tedy s nenulovým SYNC) tóny.

Kanál přijímá ještě následující řídící kódy:
ctrl+Z – vyprázdní všechny fronty
esc Z <číslo kanálu> – vyprázdní frontu daného kanálu (0, 1 a 2 tónové kanály, 3 kanál šumový)
ctrl+X – vyprázdní frontu obálek
ctrl+G – už byl uváděn, jde o signál BELL který zahraje gong na kanálu 2

Zvláštním zvukem je pípnutí klávesnice, které si obsluhuje sám ovladač klávesnice v obsluze přerušení a nelze ho proto vyvolat systémovou službou EXOSu. Pípnutí probíhá na kanálu 0 a neovlivňuje jinak zvuk, který kanál případně přehrává. Pípnutí trvá setinu sekundy (půl televizního snímku) a je tvořeno procesorem softwarově s využitím D/A převodníku.

Registry čipu Dave využívá i obsluha magnetofonu pro časování. Zvukový ovladač ovšem v každém přerušení nnasatvuje všech 16 zvukových registrů, ne jen ty, které vyžadují změnu hodnoty, takže k obnovení původních hodnot dojde po použití magnetofonu velmi brzy.

Opusťme teď zabudovaný ovladač pro tvorbu zvuků a podívejme se na DPC Dave z hlediska hardware.
DPC zajišťuje:
zvukový generátor (jak už víme, 3 kanály tónové a 1 šumový),
stránkování paměti (až 4 MB),
dekódování aders pro zabudovanou RAM, ROM a cartridge port,
systém přerušení včetně 1 Hz hodin, programovatelného časovače a dvou přerušovacích vstupů,
reset pro Z80 a dynamické RAM,
I/O handshake pro externí oktálové latche a trojstavové buffery,
systémové hodiny 1 MHz,
generátor WAIT signálu pro Z80.

DPC má 22 registrů, z toho 17 pouze zapisovatelných. 16 pouze zapisovatelných registrů slouží tvorbě zvuku, čtyři registry pro management paměti jsou pro zápis i čtení, jeden registr pro obsluhu přerušení je pro zápis i čtení, jeden registr pouze pro čtení nastavuje konfiguraci systému.

Rozsah tónových generátorů je 30 Hz až 125 kHz, tón lze modifikovat distorzí (pomocí polynomiálních čítačů, které lze nastavit na 4, 5 nebo 7 bitů, sedmibitový může být zaměněn za čítač proměnné délky 17/15/11/9 bitů), hi-pass filtrem řízeným frekvencí jiného kanálu, nebo ring modulací.
Šumový kanál je realizován 17bitovým polynomiálním čítačem 31 kHz generujícím pseudobílý šum, zdroj frekvence jde odebírat i z tónových kanálů nebo jde čítač redukovat na 15/11/9 bitů nebo vyměnit za 7bitový polynomiální čítač. Výsledný šum lze upravovat hi-pass a lo-pass filtrem a ring modulací, řízenými frekvencí některého z tónových kanálů.

Kanály procházejí dvěma obvody pro ovládání hlasitosti pro levou a pravou stranu řízenými šestibitovými registry, které se multiplexují na 6bitový D/A převodník (realizovaný externí odporovou sítí). Levý nebo pravý kanál tedy lze přepnout na 6bitový D/A převodník, přehrávající hodnoty posílané na hlasitostní registr kanálu 0 (tento způsob je použit třeba v rutině pro ozvučení stisku klávesy).
Přepínání zajišťují dva bity v ovládacím registru, další tři bity jsou použity na synchronizaci tónů.

Management paměti sestává ze čtyř registrů, ovládajících piny A14-A21 při výběru registru pomocí A14′, A15′ a volících tak 256×16 kB paměťových stránek.
Při BREQ jsou tyto výstupy ve třetím stavu.

Přerušení jsou čtyři: 1 Hz přerušení pro systémové hodiny, přepínatelné přerušení 50 Hz / 1 kHz nebo frekvence tónových kanálů 0 nebo 1, a dva vnější vstupy přerušení. Každé přerušení lze povolit nebo resetovat jeho latch, vše společně na osmibitovém registru.

Registr pro konfiguraci systému volí mezi 16k a 64k RAMkami, 8/12 MHz kmitočtem a nastavuje WAITy pro procesor (žádné, jen při opcode fetch cyklu, nebo při všech přístupech do paměti). Při přístupu do VideoRAM se ale WAIT negeneruje.

Jak bylo uvedeno, Dave generuje i signál pro výběr ROM, cartridge, VideoRAM a video I/O. Na RSTO se posílá reset, jak při zapnutí počítače, tak při vstupu na RSTI, generuje 1 ms puls synchronizovaný se sestupnou hranou M1, aby se zabránilo ztrátám dat v RAM. RSTO pro externí zařízení vyžaduje invertor 74ALS04.

Nyní k jednotlivým registrům, nejprve pro obsluhu zvuku:

R0 (W, #A0)
b7-b0 nižší byte 12bitové frekvence tónového kanálu 0

R1 (W #A1)
b3-b0 vyšší nibble 12bitové frekvence tónového kanálu 0, f=125000/(n+1) Hz
b5, b4 00 čistý tón, 01 4bitová distorze, 10 5bitová distorze, 11 7bitová distorze
b6 1=povolení hi-pass filtru s frekvencí kanálu 1
b7 1=povolení ring modulace tónem kanálu 2

R2 (W, #A2)
b7-b0 nižší byte 12bitové frekvence tónového kanálu 1

R3 (W, #A3)
b3-b0 vyšší nibble 12bitové frekvence tónového kanálu 1, f=125000/(n+1) Hz
b5, b4 00 čistý tón, 01 4bitová distorze, 10 5bitová distorze, 11 7bitová distorze
b6 1=povolení hi-pass filtru s frekvencí kanálu 2
b7 1=povolení ring modulace frekvencí šumového kanálu

R4 (W, #A4)
b7-b0 nižší byte 12bitové frekvence tónového kanálu 2

R5 (W, #A5)
b3-b0 vyšší nibble 12bitové frekvence tónového kanálu 2, f=125000/(n+1) Hz
b5, b4 00 čistý tón, 01 4bitová distorze, 10 5bitová distorze, 11 7bitová distorze
b6 1=povolení hi-pass filtru s frekvencí šumového kanálu
b7 1=povolení ring modulace tónem kanálu 0

R6 (W, #A6)
b1, b0 výběr frekvence šumového kanálu:: 00 31.25 kHz, 01 tónový kanál 0, 10 tónový kanál 1, 11 tónový kanál 2
b3, b2 délka polynomiálního čítače: 00 17 bitů, 01 15 bitů, 10 11 bitů, 11 9 bitů
b4 1=prohození 17bitového a 7bitového čítače
b5 1=povolení lo-pass filtru pro šum s frekvencí tónového kanálu 2
b6 1=povolení hi-pass filtru pro šum s frekvencí tónového kanálu 0
b7 1=povolení ring modulace tónem kanálu 1

R7 (W, #A7)
b0 synchronizace tónového kanálu 0 (1 zdržet, 0 pustit)
b1 synchronizace tónového kanálu 1
b2 synchronizace tónového kanálu 2
b3 1=přepnutí levého kanálu na D/A, výstupní hodnoty se zapisují do registru R8
b4 1=přepnutí pravého kanálu na D/A, výstupní hodnoty se zapisují do registru R12
b6, b5 přerušení: 00 1 kHz, 01 50 Hz, 10 tónový generátor 0, 11 tónový generátor 1
b7 nepoužit

R8 (W, #A8)
b5-b0 hlasitost levé složky tónového kanálu 0 nebo D/A hodnota pro levý kanál (při R7 b3=1)
b6, b7 nepoužit

R9 (W, #A9)
b5-b0 hlasitost levé složky tónového kanálu 1
b6, b7 nepoužit

R10 (W, #AA)
b5-b0 hlasitost levé složky tónového kanálu 2
b6, b7 nepoužit

R11 (W, #AB)
b5-b0 hlasitost levé složky šumového kanálu
b6, b7 nepoužit

R12 (W, #AC)
b5-b0 hlasitost pravé složky tónového kanálu 0 nebo D/A hodnota pro pravý kanál (při R7 b3=1)
b6, b7 nepoužit

R13 (W, #AD)
b5-b0 hlasitost pravé složky tónového kanálu 1
b6, b7 nepoužit

R14 (W, #AE)
b5-b0 hlasitost pravé složky tónového kanálu 2
b6, b7 nepoužit

R15 (W, #AF)
b5-b0 hlasitost pravé složky šumového kanálu
b6, b7 nepoužit

Nyní ostatní registry čipu DPC Dave:

R16 (R/W, #B0)
b7-b0 výběr stránky paměti na A14-A21 při A15′, A14’=00

R17 (R/W, #B1)
b7-b0 výběr stránky paměti na A14-A21 při A15′, A14’=01

R18 (R/W, #B2)
b7-b0 výběr stránky paměti na A14-A21 při A15′, A14’=10

R19 (R/W, #B3)
b7-b0 výběr stránky paměti na A14-A21 při A15′, A14’=11

R20 (W, #B4)
b0 1=povolení přerušení 1 kHz / 50 Hz / tónového generátoru
b1 1=reset latche přerušení 1 kHz / 50 Hz / tónového generátoru
b2 1=povolení přerušení 1 Hz
b3 1=reset latche přerušení 1 Hz
b4 1=povolení přerušení INT1
b5 1=reset latche přerušení INT1
b6 1=povolení přerušení INT2
b7 1=rewset latche přerušení INT2

R20 (R, #B4)
b0 1=dělič 1 kHz / 50 Hz / tónový generátor (f int/2 čtvercového průběhu)
b1 1=nastaven latch od 1 kHz / 50 Hz / tónového generátoru
b2 1=dělič 1 Hz (0.5 Hz čtvercového průběhu)
b3 1=nastaven latch 1 Hz
b4 vstupní pin INT1 (aktuální stav)
b5 1=nastaven latch INT1
b6 vstupní pin INT2 (aktuální stav)
b7 1=nastaven latch INT2

R21 (W, #B5)
strobe aktivní v nule na WR0

R21 (R, #B5)
strobe aktivní v nule na RD0

R22 (W, #B6)
strobe aktivní v nule na WR1

R22 (R, #B6)
strobe aktivní v nule na RD1

R23 (W, #B7)
strobe aktivní v nule na WR2

R23 (R, #B7)
strobe aktivní v nule na RD2

R31 (W, #BF)
b0 zabudovaná RAM 0=64k, 1=16k
b1 frekvence vstupních hodin 0=8 MHz, 1=12 MHz
b3, b2 00=WAIT při všech přístupěch do paměti (kromě VideoRAM), 01=WAIT při M1(kromě VideoRAM), 10 a 11 bez WAITu

Výstup selectů:
VIO – v nule při přístupu na #80-#8F (používá IORQ, RD, WR)
ROM – v nule při přístupu do stránek 0-3 (0-#FFFF) (používá RD)
CART – v nule při přístupu do stránek 4-7 (#10000-#1FFFF) (používá RD, WR)
VRAM – v nule při přístupu do stránek #FC-#FF (#3F0000-#3FFFFF) při R31 b0=0, nebo v nule při přístuupu jinam než do ROM nebo cartridge (#20000-#3FFFF) při R31 b0=1 (používá MREQ, RD, WR)