Hlavní navigace

Tvorba her pro Atari 2600 v Batari BASICu: standardní kernel a zvuky

5. 5. 2022
Doba čtení: 29 minut

Sdílet

 Autor: Depositphotos
Ve třetí části článku o programování her a dem pro herní konzoli Atari 2600 (VCS) nejprve dokončíme popis standardního kernelu Batari BASICu. Poté si řekneme, jak se na této herní konzoli pracuje se zvuky.

Obsah

1. Tvorba her pro Atari 2600 v Batari BASICu: úkol pro hardcode programátory (3)

2. Hráči (players)

3. Šířka vykreslování hráčů

4. Opakování vykreslení stejného hráče na jednom obrazovém řádku

5. Větší množství objektů ve vykreslované scéně

6. Zobrazení skóre

7. Trik použitý při vykreslení skóre

8. Detekce kolizí podruhé

9. Úplný zdrojový kód demonstračního příkladu

10. Generování zvuků čipem TIA

11. Zvukový subsystém čipu TIA

12. Řídicí registry určené pro nastavení zvuků

13. Tabulka not

14. Jednoduchý zvuk vytvořený v Batari BASICu

15. Změna frekvence tónu modifikací dělitele

16. Zvuky získané zpětnovazebními posuvnými registry

17. Repositář s demonstračními příklady

18. Odkazy na Internetu

1. Tvorba her pro Atari 2600 v Batari BASICu: úkol pro hardcode programátory (3)

Připomeňme si nejdříve základní informace z předchozího článku. Čip TIA v herní konzoli Atari 2600 dokáže zobrazit pouhých šest grafických objektů, k nimž se přidává pozadí realizované konstantní barvou:

# Typ objektu Orig.název Objem paměti Šířka reprezentovaná jedním bitem
1 Pozadí Background 0 bitů ×
2 Hrací plocha Playground 20 bitů 4× základní šířka pixelu
3 Míč Ball 1 bit 1×, 2×, 4×, 8× šířka pixelu
4 Hráč 0 Player 0 8 bitů 1×, 2×, 4× šířka pixelu
5 Střela 0 Missile 0 1 bit 1×, 2×, 4×, 8× šířka pixelu
6 Hráč 1 Player 1 8 bitů 1×, 2×, 4× šířka pixelu
7 Střela 1 Missile 1 1 bit 1×, 2×, 4×, 8× šířka pixelu

Obrázek 1: Screenshot ze hry Spy Hunter.

Ve druhé tabulce jsou vypsány vlastnosti jednotlivých grafických objektů, které bylo možné měnit zápisem vhodných hodnot do řídicích registrů čipu TIA:

# Typ objektu Orig.název Volba barvy Další možnosti
1 Pozadí Background ano ×
2 Hrací plocha Playground pro jedničkové bity opakování či zrcadlení v pravé polovině obrazu
3 Míč Ball = barva hrací plochy posun, relativní posun, vertikální posun o jeden řádek, změna velikosti
4 Hráč 0 Player 0 pro jedničkové bity posun, změna šířky, opakování 2×, 3×
5 Střela 0 Missile 0 = barva hráče 0 -//-
6 Hráč 1 Player 1 pro jedničkové bity posun, změna šířky, opakování 2×, 3×
7 Střela 1 Missile 1 = barva hráče 1 -//-

Obrázek 2: Úvodní obrazovka hry Jungle Hunt s prvním herním prostředím.

2. Hráči (players)

Posledním typem grafických objektů poskytovaných resp. přesněji řečeno vykreslovaných čipem TIA jsou hráči neboli players. Podporováno je vykreslení dvou hráčů označovaných jako player0 a player1. Hráči mohou být, jak již ostatně víme z předchozího článku, širocí osm pixelů a jsou definováni bitovým vzorkem (neboli jedním bajtem). V případě, že se bajt s definicí hráče nebude při vykreslování snímku měnit, bude hráč vykreslen formou vertikálního vzorku, který bude na všech obrazových řádcích totožný. Výška hráče může být v Batari BASICu libovolná a definice jeho bitmapy je realizována ve struktuře nazvané taktéž player0 nebo player1. Nastavovat lze pozici hráčů na obrazovce, barva hráčů je určena registry COLUP0 a COLUP1. A – jak jsme si řekli minule – je možné změnit prioritu zobrazení hráčů (i střel) vůči hernímu poli (playfield).

Podívejme se však nejdříve na velmi jednoduchý demonstrační příklad, v němž je použit hráč, který pochází z jedné varianty slavné hry Space Invaders. Bitmapa definující tvar hráče je zapsána bitovým vzorkem (výška, tedy počet řádků, je proměnný):

   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end

Nastavení pozice hráče na obrazovce se provádí s využitím pseudoproměnných:

  player0x = 80
  player0y = 48

Barva hráče i pozadí se potom nastavuje přímo ve vykreslovací smyčce:

mainloop
    COLUPF = 14
    COLUP0 = $1E
 
    drawscreen
    goto mainloop

Obrázek 3: Scéna vykreslená dnešním prvním demonstračním příkladem.

Podívejme se nyní na úplný zdrojový kód tohoto demonstračního příkladu, který obsahuje i definici herního pole (playfield):

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 80
  player0y = 48
 
mainloop
    COLUPF = 14
    COLUP0 = $1E
 
    drawscreen
    goto mainloop

Pohyb hráče po herním světě se realizuje snadno změnou obsahu pseudoproměnných player0× a player0y, které lze modifikovat například pohybem joysticku:

    if joy0up then player0y = player0y - 1
    if joy0down then player0y = player0y + 1
    if joy0left then player0x = player0x - 1
    if joy0right then player0x = player0x + 1

Tento způsob ovládání hráče je ukázán v dnešním druhém demonstračním příkladu:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 80
  player0y = 48
 
mainloop
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0up then player0y = player0y - 1
    if joy0down then player0y = player0y + 1
    if joy0left then player0x = player0x - 1
    if joy0right then player0x = player0x + 1
 
    drawscreen
    goto mainloop

3. Šířka vykreslování hráčů

Minule jsme si řekli, že šířka střel se nastavuje v horních bitech řídicích registrů nazvaných NUSIZ0 (pro první střelu) a NUSIZ1 (pro střelu druhou). Existují čtyři podporované šířky střel, jak je to ostatně patrné z následující tabulky:

NUSIZ0/NUSIZ1 Stručný popis
$0× střela s šířkou jednoho pixelu
$1× střela s šířkou dvou pixelů
$2× střela s šířkou čtyř pixelů
$3× střela s šířkou osmi pixelů

Spodní čtyři bity slouží k nastavení opakování zobrazení hráčů/střel a taktéž ke zvětšení hráčů ve směru osy x (což je vlastně stejné, jako zvětšení střel). Ovšem hráče je možné zvětšit pouze 2× a 4×, nikoli již 8×:

NUSIZ0/NUSIZ1 Stručný popis
$x0 hráč v základním měřítku
$x5 hráč zvětšený dvojnásobně ve směru osy x
$x7 hráč zvětšený čtyřnásobně ve směru osy x

V tomto demonstračním příkladu je hráč zvětšený 2×:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 80
  player0y = 48
 
mainloop
    NUSIZ0 = $05
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0up then player0y = player0y - 1
    if joy0down then player0y = player0y + 1
    if joy0left then player0x = player0x - 1
    if joy0right then player0x = player0x + 1
 
    drawscreen
    goto mainloop

Obrázek 4: Hráč zvětšený 2×.

v tomto příkladu je zvětšen 4× ve směru osy x a 2× ve směru osy y (opakováním vzorku):

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %01000010
   %10000001
   %10000001
   %01011010
   %01011010
   %11111111
   %11111111
   %11011011
   %11011011
   %01111110
   %01111110
   %00111100
   %00111100
   %00011000
   %00011000
end
 
  player0x = 80
  player0y = 48
 
mainloop
    NUSIZ0 = $07
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0up then player0y = player0y - 1
    if joy0down then player0y = player0y + 1
    if joy0left then player0x = player0x - 1
    if joy0right then player0x = player0x + 1
 
    drawscreen
    goto mainloop

Obrázek 5: Hráč zvětšený 4×.

4. Opakování vykreslení stejného hráče na jednom obrazovém řádku

Popišme si ještě další možné kombinace hodnot uložených v řídicích registrech NUSIZ0 a NUSIZ1. Kromě zvětšení střel a/nebo hráčů lze docílit toho, že se tyto grafické objekty budou na jednom řádku opakovat, a to buď dvakrát či třikrát. Měnit lze i relativní vzdálenost těchto kopií od sebe:

NUSIZ0/NUSIZ1 Stručný popis
$x0 hráč v základním měřítku
$x1 dvojnásobná kopie hráče i střely
$x2 dvojnásobná kopie hráče i střely ve větší vzdálenosti od sebe
$x3 trojnásobná kopie hráče i střely
$x4 dvojnásobná kopie hráče i střely s dvojnásobným zvětšením
$x6 trojnásobná kopie hráče i střely ve větší vzdálenosti od sebe

Změnu způsobu zobrazení hráčů a střel lze realizovat například tlačítkem joysticku, kterým budeme přepínat mezi výše uvedenými stavy, konkrétně mezi hodnotami $00, $01, $02, $03, $04 a $06 (vynecháme tedy stav $05). Proměnná a slouží pro „zpomalení“ změny zobrazení grafických objektů:

    if joy0fire then a = a + 1
 
    rem Zpomaleni zmeny
    if a > 8 then b = b + 1: a = 0
    if b = 5 then b = 6
    if b = 7 then b = 0
    NUSIZ0 = b

Některé možnosti zobrazení toho samého hráče ve scéně:

Obrázek 6: Zopakování hráče na stejném obrazovém řádku.

Obrázek 7: Zopakování hráče na stejném obrazovém řádku.

Obrázek 8: Zopakování hráče na stejném obrazovém řádku.

Úplný zdrojový kód takto upraveného demonstračního příkladu vypadá následovně:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %01000010
   %10000001
   %10000001
   %01011010
   %01011010
   %11111111
   %11111111
   %11011011
   %11011011
   %01111110
   %01111110
   %00111100
   %00111100
   %00011000
   %00011000
end
 
  player0x = 80
  player0y = 48
 
mainloop
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0up then player0y = player0y - 1
    if joy0down then player0y = player0y + 1
    if joy0left then player0x = player0x - 1
    if joy0right then player0x = player0x + 1
    if joy0fire then a = a + 1
 
    rem Zpomaleni zmeny
    if a > 8 then b = b + 1: a = 0
    if b = 5 then b = 6
    if b = 7 then b = 0
    NUSIZ0 = b
 
    drawscreen
    goto mainloop

5. Větší množství objektů ve vykreslované scéně

Standardní kernel implementovaný v jazyce Batari BASIC dokáže současně zobrazit všech šest grafických objektů současně, tedy:

  1. Herní pole (playfield)
  2. Míč (ball) ve stejné barvě jako herní pole
  3. Dvojici hráčů (players)
  4. Dvojici střel (missiles) ve stejné barvě, jako příslušní hráči

Všechny zmíněné objekty s výjimkou herního pole jsou plně polohovatelné, což je ukázáno i v dalším demonstračním příkladu, kde:

  1. Hráči se pohybují v horizontálním směru a odráží se od okrajů obrazovky
  2. Střely se pohybují pod úhlem 45° a taktéž se odráží od okrajů obrazovky
  3. Míč se ovládá prvním joystickem ve všech osmi možných směrech

Herní scéna vypadá následovně:

Obrázek 9: Větší množství objektů ve vykreslované scéně.

Zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players5.bas i pod tímto odstavcem:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
   player1:
   %10100101
   %01011010
   %00100100
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 20
  player0y = 20
 
  player1x = 140
  player1y = 30
 
  missile0x = 80
  missile0y = 40
  missile0height = 4
 
  missile1x = 80
  missile1y = 60
  missile1height = 4
 
  ballx = 80
  bally = 50
  ballheight = 8
 
  rem Posun hrace #1 v horizontalnim smeru
  let a = 1
 
  rem Posun hrace #2 v horizontalnim smeru
  let b = 1
 
  rem Posun strely 0 v horizontalnim i vertikalnim smeru
  let c = 1
  let d = 1
 
  rem Posun strely 1 v horizontalnim i vertikalnim smeru
  let e = 1
  let f = -1
 
mainloop
    rem Sirka strel
    NUSIZ0 = $20
    NUSIZ1 = $20
 
    rem Sirka mice
    CTRLPF = $31
 
    rem Barvy pozadi i hracu
    COLUPF = 14
    COLUP0 = $1E
    COLUP1 = $4E
 
    player0x = player0x + a
    if player0x >= 152 then player0x = 152: a =- 1
    if player0x <= 0 then player0x = 0: a = 1
 
    player1x = player1x + b
    if player1x >= 152 then player1x = 152: b =- 1
    if player1x <= 1 then player1x = 1: b = 1
 
    missile0x = missile0x + c
    if missile0x >= 152 then missile0x = 152: c =- 1
    if missile0x <= 1 then missile0x = 1: c = 1
    missile0y = missile0y + d
    if missile0y >= 80 then missile0y = 80: d =- 1
    if missile0y <= 10 then missile0y = 10: d = 1
 
    missile1x = missile1x + e
    if missile1x >= 152 then missile1x = 152: e =- 1
    if missile1x <= 1 then missile1x = 1: e = 1
    missile1y = missile1y + f
    if missile1y >= 80 then missile1y = 80: f =- 1
    if missile1y <= 10 then missile1y = 10: f = 1
 
    if joy0up then bally = bally - 1
    if joy0down then bally = bally + 1
    if joy0left then ballx = ballx - 1
    if joy0right then ballx = ballx + 1
 
    drawscreen
    goto mainloop

6. Zobrazení skóre

Standardní kernel Batari BASICu podporuje zobrazení skóre v dolní části herní scény. Skóre je celočíselná hodnota s maximálním rozsahem šesti číslic, které lze využít k více účelům. Ve finální hře se pochopitelně může jednat o skutečné skóre, ovšem při vývoji zde je možné zobrazit různé ladicí informace (protože jiný výstup textu není praktický). Podívejme se nyní na způsob zobrazení skóre v dolní části herní scény. Barva skóre je odvozena od obsahu pseudoproměnné scorecolor (barvy PAL nebo NTSC), vlastní obsah je pak uložen v další pseudoproměnné nazvané score:

  scorecolor = $98
 
  rem Pocatecni hodnota score
  score = 0
 
mainloop
    if joy0fire then score = score + 1
     
    drawscreen
    goto mainloop
Poznámka: právě kvůli zobrazení skóre je nutné neustále obnovovat obsahy registrů čipu TIA, protože tyto jsou přepisovány mj. při vykreslení skóre,

Obrázek 10: Postupně se měnící skóre zobrazené v dolní části herní scény.

Obrázek 11: Postupně se měnící skóre zobrazené v dolní části herní scény.

7. Trik použitý při vykreslení skóre

Zajímavé bude zjistit, jakým trikem je vlastně skóre vykresleno. Jedná se totiž o relativně složitý grafický vzor (složitý v kontextu čipu TIA), takže bude vhodné se přiučit, jak kernel dokáže takový vzor vlastně zobrazit:

Obrázek 12: Trik použitý při vykreslení skóre.

Poznámka: vidíme, že se používá dvojice hráčů, přičemž kernel (a ani TIA) nemá dostatek času na změnu tvaru jediného hráče, takže je nutné hráče postupně střídat. Jedná se o trik používaný v mnoha hrách.

8. Detekce kolizí podruhé

Nyní, když víme, jakým způsobem můžeme zobrazit skóre, se můžeme vrátit k příkladu se všemi grafickými objekty, z nichž hráči i střely jsou zobrazeny 3× (pouze u míče nelze tohoto triku docílit):

Obrázek 13: Snímek získaný z dema.

Všechny objekty se ve scéně pohybují a srážejí (dochází tedy ke kolizím). V takovém případě je změněna hodnota skóre, které se zde používá pro ladicí účely:

if collision(missile0, player0) then COLUPF = $38:score = score + 1
if collision(missile0, player1) then COLUPF = $48:score = score + 10
if collision(missile1, player0) then COLUPF = $58:score = score + 100
if collision(missile1, player1) then COLUPF = $68:score = score + 1000
if collision(missile0, missile1) then COLUPF = $78:score = score + 10000
if collision(ball, player0) then COLUP0 = $48:score = score + 100000
if collision(ball, player1) then COLUP1 = $48:score = score + 100000
if collision(ball, missile0) then COLUP0 = $48:score = score + 100000
if collision(ball, missile1) then COLUP1 = $48

I přes relativně velké množství pohybujících se objektů je kód dema po překladu menší než 2kB:

16:43 $ 2600basic.sh collisions_2.bas
Found dasm version: DASM 2.20.14.1
Starting build of collisions_2.bas
batari Basic v1.6-SNAPSHOT (c)2021
2600 Basic compilation complete.
      2368 bytes of ROM space left
 
Complete. (0)
Build complete.

Obrázek 14: Další snímek získaný z dema.

9. Úplný zdrojový kód demonstračního příkladu

Úplný zdrojový kód demonstračního příkladu popsaného v předchozí kapitole je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/score.bas:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
   player1:
   %10100101
   %01011010
   %00100100
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 20
  player0y = 20
 
  player1x = 140
  player1y = 30
 
  missile0x = 80
  missile0y = 40
  missile0height = 4
 
  missile1x = 80
  missile1y = 60
  missile1height = 4
 
  ballx = 80
  bally = 50
  ballheight = 8
 
  rem Posun hrace #1 v horizontalnim smeru
  let a = 1
 
  rem Posun hrace #2 v horizontalnim smeru
  let b = 1
 
  rem Posun strely 0 v horizontalnim i vertikalnim smeru
  let c = 1
  let d = 1
 
  rem Posun strely 1 v horizontalnim i vertikalnim smeru
  let e = 1
  let f = -1
 
mainloop
    rem Sirka strel
    NUSIZ0 = $20
    NUSIZ1 = $20
 
    rem Sirka mice
    CTRLPF = $31
 
    rem Barvy pozadi i hracu
    COLUPF = 14
    COLUP0 = $1E
    COLUP1 = $4E
 
    player0x = player0x + a
    if player0x >= 152 then player0x = 152: a =- 1
    if player0x <= 0 then player0x = 0: a = 1
 
    player1x = player1x + b
    if player1x >= 152 then player1x = 152: b =- 1
    if player1x <= 1 then player1x = 1: b = 1
  
    missile0x = missile0x + c
    if missile0x >= 152 then missile0x = 152: c =- 1
    if missile0x <= 1 then missile0x = 1: c = 1
    missile0y = missile0y + d
    if missile0y >= 80 then missile0y = 80: d =- 1
    if missile0y <= 10 then missile0y = 10: d = 1
 
    missile1x = missile1x + e
    if missile1x >= 152 then missile1x = 152: e =- 1
    if missile1x <= 1 then missile1x = 1: e = 1
    missile1y = missile1y + f
    if missile1y >= 80 then missile1y = 80: f =- 1
    if missile1y <= 10 then missile1y = 10: f = 1
 
    if joy0up then bally = bally - 1
    if joy0down then bally = bally + 1
    if joy0left then ballx = ballx - 1
    if joy0right then ballx = ballx + 1
 
    if collision(missile0, player0) then COLUPF = $38:score = score + 1
    if collision(missile0, player1) then COLUPF = $48:score = score + 10
    if collision(missile1, player0) then COLUPF = $58:score = score + 100
    if collision(missile1, player1) then COLUPF = $68:score = score + 1000
    if collision(missile0, missile1) then COLUPF = $78:score = score + 10000
    if collision(ball, player0) then COLUP0 = $48:score = score + 100000
    if collision(ball, player1) then COLUP1 = $48:score = score + 100000
    if collision(ball, missile0) then COLUP0 = $48:score = score + 100000
    if collision(ball, missile1) then COLUP1 = $48
 
    drawscreen
    goto mainloop

10. Generování zvuků čipem TIA

Ve druhé části dnešního článku si (i když s několika zjednodušeními) popíšeme zvukové možnosti čipu TIA neboli plným jménem Television Interface Adaptor. Připomeňme si (již naposledy), že se jedná o jeden z pouhých tří integrovaných obvodů tvořících ústřední prvky v minulosti velmi populární osmibitové herní konzole Atari 2600 neboli též Atari VCS (k přejmenování došlo společně se vznikem další herní konzole Atari 5200).

Čip TIA se kromě generování grafického obrazu, což bylo téma předchozího textu, stará i o zvukovou syntézu. Ta je z dnešního pohledu dosti zvláštní. Na jednu stranu je způsob zvukové syntézy velmi jednoduchý a v některých ohledech připomíná způsob zvukové syntézy použité o několik let později v čipu POKEY v osmibitových domácích mikropočítačích Atari (ale i v relativně velkém množství herních automatů). Jednoduchost spočívá v možnosti generování pouze obdélníkových signálů (pravidelných popř. sice nepravidelných, ale periodických), jejichž amplituda může být nastavena na hodnoty 0–15 (řídí se tedy čtyřmi bity řídicího registru resp. dvojice řídicích registrů).

Na druhou stranu však způsob interního zapojení posuvných registrů se zpětnou vazbou nabízí poměrně velké množství kombinací, které vlastně nenajdeme ani u čipu POKEY, který je jinak možné v oblasti generování zvuků a hudby považovat za nástupce čipu TIA (totéž platí o GTIA, ovšem v oblasti grafiky). TIA se tak stále používá v některých aplikacích chiptune, samozřejmě vedle dalších čipů (POKEY, pochopitelně SID, Texas Instruments SN76489, Texas Instruments SN76496, SN76477 a Ricoh 2A03/2A07 z NESu).

Vzhledem k tomu, že se čip TIA stará jak o vytváření video signálu, tak i pro syntézu zvuků a hudby, je v něm několik modulů společných pro oba jinak rozličné subsystémy. Zejména se to týká způsobu generování základního hodinového signálu (přesněji řečeno dvojice signálů), které vstupují do zvukového systému a od jejichž frekvence se odvíjí i frekvence přehrávaných tónů. Podrobnosti budou uvedeny v navazující kapitole.

11. Zvukový subsystém čipu TIA

Základem všech signálů řídicích celou herní konzoli Atari 2600 je oscilátor, který u NTSC varianty této konzole generuje hodinový signál o frekvenci 3,579545 MHz a u PAL varianty poněkud nižší frekvenci 3,546894 MHz (což mimochodem znamená, že některé hry běží poněkud odlišnou rychlostí v závislosti na použité televizní normě). Tento základní signál se nazývá pixel clock (v některých dokumentech též color clock), protože kromě dalších činností řídí i generování pixelů na obrazových řádcích (262 řádků a necelých 60 snímků za sekundu u normy NTSC, 312 řádků a necelých 50 snímků za sekundu u normy PAL). Současně se tento signál dělí třemi a výsledek o frekvencích 1,193182 MHz (NTSC) popř. 1,182298 MHz (PAL) slouží jako hlavní řídicí hodinový signál mikroprocesoru MOS 6507. Z tohoto důvodu se tento signál nazývá CPU clock a proto se dočteme, že hodinová frekvence konzole Atari 2600 je 1,19 MHz, což ovšem platí jen pro NTSC variantu.

Oba dva výše zmíněné signály, tj. jak pixel clock, tak i CPU clock, jsou dále děleny konstantou 114 použitou mj. video subsystémem pro vykreslení jednoho obrazového řádku (mimochodem: 114×2=228, což je celkový počet pixelů + overscanu). Současně však takto vydělené signály vstupují i do audio subsystému, který nás zajímá nyní. Jejich frekvence je rovna, jak lze snadno vypočítat, 31399 Hz a 10466 Hz pro systém NTSC a 31113 Hz a 10371 Hz pro systém PAL. V původních originálních materiálech je ovšem jen lakonicky napsáno „na vstupu audio systému je signál o frekvenci přibližně 30 kHz“, což je nepřesné a může se to negativně projevit při volbě konstant při přehrávání not („rozladění“). Proto mějte při čtení dalšího textu na paměti, že vstupními frekvencemi zvukového subsystému je dvojice 31399/10466 nebo 31113/10371 Hz.

TIA

Obrázek 15: Zvukový subsystém čipu TIA.

12. Řídicí registry určené pro nastavení zvuků

V případě integrovaného obvodu TIA jsou programátorům k dispozici dva na sobě nezávislé programovatelné zvukové kanály. Každý z těchto kanálů je řízen trojicí řídicích registrů, celkem tedy může programátor modifikovat (pouze) šest řídicích registrů. Tyto registry mají názvy AUDF0, AUDF1, AUDC0, AUDC1, AUDV0 a AUDV1. Vzhledem k tomu, že možnosti obou zvukových kanálů jsou totožné (všechny obvody zvukového subsystému jsou za děličkou vstupních signálů zdvojeny), budeme v dalším textu popisovat pouze kanál první, který je řízený trojicí registrů AUDF0, AUDC0 a AUDV0. Náhradou 0 za 1 pak bude totéž platit i pro druhý zvukový kanál.

První řídicí registr zvukového kanálu (AUDF0), přesněji řečeno pět bitů tohoto registru, určuje konstantu 1 až 32 použitou při dělení vstupní frekvence. Buď se použije frekvence pixel_clock/114 nebo CPU_clock/114. Výsledkem tohoto vydělení je obdélníkový signál o frekvenci přibližně 1 kHz až 30 kHz (popř. 300 Hz až 10 kHz, ovšem opět jen přibližně), který je přiváděn do dvojice konfigurovatelných posuvných registrů (LFSR) se zpětnou vazbou. První registr má délku pěti bitů, druhý délku čtyř bitů, ovšem je možné je spojit do jediného registru o délce devíti bitů (viz další text).

Tyto dva posuvné registry slouží jak pro generování čistého obdélníkového signálu, tak i pro vytváření šumu (noise generator) s různou charakteristikou. Konfigurace (způsob zapojení) obou posuvných registrů je řízena registrem AUDC0, přičemž význam mají pouze čtyři spodní bity. Jednotlivé kombinace určují jak zdroj signálu (tedy, jak již víme pixel_clock/114 či CPU_clock/114), tak i způsob zapojení zpětných vazeb v obou posuvných registrech.

Jedna z kombinací umožňuje generovat konstantní signál o hodnotě 1, což je výhodné, protože je možné zvuk jednoduše samplovat rychlou změnou obsahu registru AUDV0 (ovšem většinou je toto řešení poměrně náročné na CPU cykly). Další dvě kombinace přepínají pětibitový posuvný registr do režimu, v němž se stále opakuje sekvence 0101010…, tj. posuvný registr zde slouží jako dělička vstupní frekvence dvěma (popř. šesti, protože CPU_clock=pixel_clock/3). Právě tento režim se používal při přehrávání čistých tónů (ovšem rozladěných).

Další dostupný režim taktéž používá posuvný registr, tentokrát ovšem takovým způsobem, že se vstupní signál dělí hodnotou 31. Opakuje se v něm totiž sekvence 31 bitů, z nichž 13 sousedních bitů je nulových, zbytek jedničkových (to, že počet jedniček a nul není zcela totožný, se projeví ve výsledném zvuku jen nepatrně). Opět platí, že CPU_clock má třetinovou frekvenci, takže v oficiálních materiálech se hovoří o dělení konstantou 93; ve skutečnosti tato „magická“ konstanta odpovídá výpočtu 3×31.

Další režimy již využívají oba posuvné registry pro tvorbu šumu. Pokud je použit jen čtyřbitový registr, je perioda opakování pouze 15 bitů, což je opět možné využít pro generování tónů, ovšem zkreslených. Podobně při použití pětibitového LFSR s periodou opakování 31. Spojením obou dvou registrů za sebe se generuje šum o periodě 511 bitů (podobného efektu lze mimochodem docílit i u čipu POKEY).

Nejsložitější je režim, v němž pětibitový LFSR řídil čtyřbitový LFSR: pokud se na výstupu prvního LFSR objeví jednička, provede se posun i ve čtyřbitovém LFSR; v opačném případě se druhý LFSR ignoruje. Výsledkem je pseudonáhodný signál s periodou 15×31=465 bitů (další „magická“ hodnota, která není v původních materiálech nijak vysvětlena a musela být až mnohem později vydedukována ze schémat čipu TIA).

Poznámka: se čtyřbitovým, pětibitovým i devítibitovým posuvným registrem se setkáme i v čipu POKEY, což není náhoda (ostatně i z teorie LFSR vychází, že například osmibitový posuvný registr vyžaduje mnohem složitější zapojení zpětné vazby, než registr sedmibitový nebo devítibitový, Výhodné délky jsou 2–7 bitů, 9–11 bitů, 15 bitů a 17 bitů). LFSR ale nalezneme i v dalších zvukových čipech.

Příklad posuvného registru se zpětnou vazbou:

       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 +---> | 1| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| -> Output
 |     +--+--+--+--+--+--+--+--+--+--+--+--+-++--+--+-++
 |                                 ______  0 |        |
 |                             0  /     //---+        |
 +-------------------------------( XOR ((  0          |
                                  \_____\\------------+
TIA

Obrázek 16: Princip práce čtyřbitového poly čítače generujícího binární pseudonáhodný šum.

Výsledný signál, nezávisle na tom, zda se jedná o čistý obdélníkový průběh či o šum, je následně zesílen 1 až šestnáctkrát na základě hodnoty posledního řídicího registru (AUDV0, AUDV1). Interně se nejedná o nic složitého – čtyři bity, resp. přesněji řečeno čtyři logické úrovně, jsou přivedeny na jednoduchou odporovou síť se čtyřmi rezistory o hodnotách 3k7, 7k5, 15k a 30k (takže se vlastně nejedná o zesílení, ale naopak o konfigurovatelné zeslabení). Výsledné napětí, které na rezistorech vznikne, je vyvedeno na výstupní pin čipu TIA (ten tedy musí obsahovat dva piny s analogovým zvukovým výstupem, každý zvukový kanál má vyhrazen jeden pin).

Zvuk generovaný čipem TIA je možné poměrně jednoduše rozeznat od zvuku dalších herních konzolí nebo domácích mikropočítačů, už jen z toho důvodu, že prakticky všechny noty jsou kvůli velmi krátkému čítači, který je použitý pro dělení vstupní frekvence, rozladěny. Avšak i přesto pro TIA dodnes vznikají různá více či méně vážně míněná hudební díla, a to včetně poměrně úspěšných pokusů o čtyřbitový sampling (což ovšem vyžaduje použití „supercartridgí“ s dostatečně velkou EPROM, protože interní RAM o kapacitě celých 128 bajtů je samozřejmě pro tyto účely nepoužitelná).

13. Tabulka not

Pro přehrávání „čistých“ tónů, tedy použití obdélníkového signálu (a nikoli výstupu ze zpětnovazebních posuvných registrů), se používají režimy 4 a 5 (totožné) a 12 a 13 (taktéž totožné, ovšem s třetinovou frekvencí; důvody viz výše). Převod mezi hodnotami zapisovanými do registrů AUDF0 a AUDF1 a notami byl získán z informací dostupných na adrese https://www.biglist.com/lis­ts/stella/archives/199704/msg00007­.html. U každé noty je navíc uveden rozdíl v centech oproti čisté notě (zhruba platí, že rozdíl o více než deset centů je velmi dobře rozeznatelný; hudba v podání čipu TIA je tedy prakticky vždy rozladěna.

Tato tabulka platí pro režimy 4 a 5, tedy pro základní obdélníkový signál získaný děličkou základní frekvence hodnotami 0 až 31:

Hodnota Nota Rozdíl (cent)
00 × ×
01 B ?
02 E ?
03 B ?
04 G ?
05 E ?
06 C# ?
07 B ?
08 A ?
09 G ?
10 F +50
11 E –20
12 D 0
13 C# +20
14 C –5
15 B –15
16 A# –20
17 A –20
18 G# –15
19 G 0
20 F# +15
21 F +40
22 F –50
23 E –20
24 D# +15
25 D +50
26 D –20
27 C# +20
28 C# –50
29 C 0
30 B +50
31 B –15

Následující tabulka platí pro režimy 12 a 13, které mají 3× nižší frekvenci (pro stejné hodnoty) v porovnání s režimy 4 a 5:

Hodnota Nota Rozdíl (cent)
00 A –20?
01 E –40?
02 A –20
03 E –10?
04 C 0?
05 A –40
06 F# +10
07 E –20
08 D –20
09 C 0
10 A# +30
11 A –20
12 G +50
13 F# +20
14 F 0?
15 E –20
16 D# –20
17 D –20
18 C# –15
19 C 0
20 B +15
21 A# +32
22 A# –50
23 A –20
24 G# +10
25 G +50
26 G –25
27 F# +15
28 F# –50
29 F 0
30 E +50
31 E –20

14. Jednoduchý zvuk vytvořený v Batari BASICu

Vyzkoušejme si nyní vygenerovat si jednoduchý zvuk. K tomuto účelu postačuje nastavit trojici řídicích registrů, například pro první zvukový kanál:

  rem Hlasitost
  AUDV0 = 15
 
  rem Tvar zvukove vlny
  AUDC0 = 4
 
  rem Frekvence: A4
  AUDF0 = 11

V demonstračním příkladu bude zvuk zapínán stiskem tlačítka joysticku. Jak to ovšem provést? Po stisku tlačítka se nastaví hlasitost na 15, po puštění se sníží zpět na nulu. Navíc zapnutí zvuku způsobí změnu barvy hráče (ostatně proto je hráč vůbec zobrazen):

if joy0fire then COLUP0 = $48:AUDV0 = 15
if !joy0fire then AUDV0 = 0

Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:

  playfield:
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 ................................
 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
end
 
   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 20
  player0y = 20
 
  rem Hlasitost
  AUDV0 = 0
 
  rem Tvar zvukove vlny
  AUDC0 = 4
 
  rem Frekvence: A4
  AUDF0 = 11
 
mainloop
    rem Barvy pozadi i hrace
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0fire then COLUP0 = $48:AUDV0 = 15
    if !joy0fire then AUDV0 = 0
 
    drawscreen
    goto mainloop

15. Změna frekvence tónu modifikací dělitele

V dalším příkladu je možné frekvenci zvuku měnit pohybem joysticku doleva a doprava. Vzhledem k tomu, že obsah řídicích registrů není možné číst, použijeme pomocnou proměnnou f pro uložení dělitele v rozsahu 0 až 31, kterou následně přiřadíme do registru AUDF0:

if joy0left && f > 0 then f = f - 1
if joy0right && f < 31 then f = f + 1
 
AUDF0 = f

Dělitel je zobrazen jako skóre a navíc je hráč posunut, takže jeho horizontální pozice odpovídá zvolené frekvenci generovaného tónu:

player0x = 20 + f*4
score = f + 0
Poznámka: trik f+0 zajistí, že se skóre zobrazí korektně a nikoli jako ASCII hodnota nuly (což je asi chyba Batari BASICu).

Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:

   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  player0x = 20 + 11
  player0y = 20
 
  scorecolor = $98
 
  rem Pocatecni hodnota score
  score = 11
 
  rem Hlasitost
  AUDV0 = 15
 
  rem Tvar zvukove vlny
  AUDC0 = 4
 
  rem Frekvence
  f = 11
  AUDF0 = f
 
mainloop
    rem Barvy pozadi i hrace
    COLUPF = 14
    COLUP0 = $1E
 
    if joy0left && f > 0 then f = f - 1
    if joy0right && f < 31 then f = f + 1
 
    AUDF0 = f
    player0x = 20 + f*4
    score = f + 0
 
    drawscreen
    goto mainloop

16. Zvuky získané zpětnovazebními posuvnými registry

V dnešním posledním demonstračním příkladu je možné joystickem měnit nejenom frekvenci tónu, ale i způsob zapojení zpětnovazebních posuvných registrů (což jsou hodnoty 0 až 15 zapisované do registru AUDC0, z nichž některé mají totožný význam a další naopak vedou k tomu, že se neozve žádný tón):

if joy0left && f > 0 then f = f - 1:score = score - 1
if joy0right && f < 31 then f = f + 1:score = score + 1
 
if joy0up && s > 0 then s = s - 1:score = score - 1000
if joy0down && s < 15 then s = s + 1:score = score + 1000
 
AUDF0 = f
AUDC0 = s

Vybrané hodnoty (dělitel i zapojení posuvných registrů) se zobrazí jak v ukazateli skóre, tak i horizontální pozicí obou hráčů:

Cloud 22 temata

player0x = 20 + f*4
player1x = 20 + s*4
Poznámka: využíváme zde tedy omezené možnosti herní konzole Atari 2600 pro ladění, resp. přesněji řečeno pro zobrazení stavu konzole/hry.

Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:

   player0:
   %01000010
   %10000001
   %01011010
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
   player1:
   %10100101
   %01011010
   %00100100
   %11111111
   %11011011
   %01111110
   %00111100
   %00011000
end
 
  rem Hlasitost
  AUDV0 = 15
 
  rem Tvar zvukove vlny
  s = 0
  AUDC0 = s
 
  rem Frekvence
  f = 11
  AUDF0 = f
 
  player0x = 20 + f * 4
  player0y = 20
 
  player1x = 20 + s * 4
  player1y = 40
 
  scorecolor = $98
 
  rem Pocatecni hodnota score
  score = 0 + f
 
mainloop
    rem Barva pozadi i hracu
    COLUPF = 14
    COLUP1 = $4E
 
    if joy0left && f > 0 then f = f - 1:score = score - 1
    if joy0right && f < 31 then f = f + 1:score = score + 1
 
    if joy0up && s > 0 then s = s - 1:score = score - 1000
    if joy0down && s < 15 then s = s + 1:score = score + 1000
 
    AUDF0 = f
    AUDC0 = s
 
    player0x = 20 + f*4
    player1x = 20 + s*4
 
    drawscreen
    goto mainloop

17. Repositář s demonstračními příklady

Všechny předminule, minule i dnes popisované demonstrační příklady určené pro překlad Batari-BASICem byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:

# Příklad Stručný popis Adresa
1 playfield1.bas zobrazení herního pole, bez smyčky kernelu https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/playfield1.bas
2 playfield2.bas ukázka smyčky kernelu https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/playfield2.bas
3 playfield3.bas změna barvy herního pole mimo smyčku https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/playfield3.bas
4 playfield4.bas změna barvy herního pole uvnitř smyčky https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/playfield4.bas
5 playfield5.bas postupná změna barvy herního pole https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/playfield5.bas
6 missile1.bas zobrazení střely nad herním polem https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile1.bas
7 missile2.bas pohyb střelou pomocí joysticku https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile2.bas
8 missile3.bas změna barvy střely tlačítkem joysticku https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile3.bas
9 missile4.bas předchozí demonstrační příklad, ale s čísly řádků https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile4.bas
     
10 missile5.bas zobrazení dvojice střel https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile5.bas
11 missile6.bas střely s dvojnásobnou šířkou https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile6.bas
12 missile7.bas střely se čtyřnásobnou šířkou https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile7.bas
13 missile8.bas střely s osminásobnou šířkou https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile8.bas
14 missile9.bas střely překrývající herní pole https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile9.bas
15 missile_A.bas herní pole překrývající střely https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile_A.bas
16 missile_B.bas vzájemný překryv střel https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/missile_B.bas
17 players1.bas zobrazení hráče https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players1.bas
18 players2.bas posun hráče joystickem https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players2.bas
19 players3.bas hráč s dvojnásobnou šířkou https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players3.bas
20 players4.bas hráč se čtyřnásobnou šířkou https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players4.bas
21 players5.bas oba hráči, obě střely i míč v jediné scéně https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players5.bas
22 collisions1.bas kolize mezi různými typy grafických objektů https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/collisions1.bas
23 collisions2.bas kolize mezi různými typy grafických objektů https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/collisions2.bas
24 score.bas zobrazení skóre s ladicími informacemi https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/score.bas
25 players_repeat1.bas zobrazení hráče v několika kopiích https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/players_repeat1.bas
26 ball.bas míč pohybující se ve scéně https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/ball.bas
27 summary2.bas shrnutí – relativně složité demo využívajících necelé 2kB ROM https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/summary2.bas
     
28 score1.bas zobrazení postupně se měnícího skóre https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/score.bas
29 sound_note.bas přehrání čistého tónu https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/sound_note.bas
30 sound_frequency.bas změna frekvence tónu pohybem joysticku https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/sound_frequency.bas
31 sound_noise.bas změna frekvence tónu i tvaru vlny pohybem joysticku https://github.com/tisnik/8bit-fame/blob/master/batari-Basic/sound_noise.bas

18. Odkazy na Internetu

  1. STELLA PROGRAMMER'S GUIDE
    https://alienbill.com/2600/101/doc­s/stella.html
  2. Batari BASIC GitHub repositář
    https://github.com/batari-Basic/batari-Basic
  3. Programming Tutorial
    https://atariage.com/forum­s/topic/111938-programming-tutorial/
  4. batari Basic Commands
    https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html
  5. About batari Basic
    https://bataribasic.com/
  6. Rationale
    https://bataribasic.com/ra­tionale.html
  7. Games That Push The Limits of the Atari 2600
    https://www.youtube.com/wat­ch?v=zM0IsWdIc_g
  8. Vývojové nástroje používané v dobách osmibitových mikropočítačů
    https://www.root.cz/clanky/vyvojove-nastroje-pouzivane-v-dobach-osmibitovych-mikropocitacu/
  9. Programovací jazyky používané na platformě osmibitových domácích mikropočítačů Atari
    https://www.root.cz/clanky/pro­gramovaci-jazyky-pouzivane-na-platforme-osmibitovych-domacich-mikropocitacu-atari/
  10. Programovací jazyky používané na platformě osmibitových domácích mikropočítačů Atari (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyky-pouzivane-na-platforme-osmibitovych-domacich-mikropocitacu-atari-2/
  11. Barvové palety čipu TIA
    http://www.qotile.net/mini­dig/docs/tia_color.html
  12. Crazy Limit Pushing Games From the Last Years of the Atari 2600!
    https://www.youtube.com/wat­ch?v=ADy1F8v59YU
  13. Atari 2600 VCS Top 100 Games Hits (past week)
    http://www.atarimania.com/top-atari-atari-2600-vcs-_G2_7.html
  14. Tobikomi – The Sound Of Thunder [Atari TIA Chip]
    https://www.youtube.com/watch?v=j0w-IZ6nAMQ
  15. TIA Visual Objects
    https://github.com/jigo2600/ji­go2600/blob/master/doc/TI­A_Visual_Objects.md
  16. TIA Sound
    https://github.com/jigo2600/ji­go2600/blob/master/doc/TI­A_Sound.md
  17. How To Make An Atari Game
    https://www.youtube.com/wat­ch?v=Ww3her2zk_I
  18. Let's Make an Atari 2600 Game! – Part 1
    https://www.youtube.com/wat­ch?v=Iqo_oARxjEg
  19. Let's Make an Atari 2600 Game! – Part 2
    https://www.youtube.com/wat­ch?v=hFFQjwFbzV8
  20. Let's Make an Atari 2600 Game! – Part 3
    https://www.youtube.com/wat­ch?v=lZ0AL6jCBXY
  21. Let's Make an Atari 2600 Game! Part 4 – Title screens and challenges
    https://www.youtube.com/watch?v=-G2kmsmqk-E
  22. Let's Make an Atari 2600 Game! Part 5 – Sound
    https://www.youtube.com/wat­ch?v=9rX2eo20×q8
  23. Let's Make an Atari 2600 game! 6 – Realtime RPG combat
    https://www.youtube.com/wat­ch?v=alRGuQ9gjRA
  24. Let's Make an Atari 2600 Game! Part 7 – Monsters
    https://www.youtube.com/wat­ch?v=vaAlYC_8YSA
  25. Let's Make an Atari 2600 Game! Part 8 – 3D Engine
    https://www.youtube.com/wat­ch?v=c1dPY1ROZe4
  26. Let's Make an Atari 2600 Game – Part 9 – Homemade cartridge
    https://www.youtube.com/wat­ch?v=xKlMohF_9Cc
  27. Bird Poop! – Atari 2600 Homebrew – batari Basic
    https://www.youtube.com/watch?v=-m4gKis0vBg
  28. DP Interviews: Bob Whitehead (By Scott Stilphen)
    http://www.digitpress.com/li­brary/interviews/interview_bob_whi­tehead.html
  29. The dasm macro assembler
    http://dasm-dillon.sourceforge.net/
  30. Official home of dasm, a versatile macro assembler
    https://dasm-assembler.github.io/
  31. Dokumentace k DASMu
    https://raw.githubusercontent.com/dasm-assembler/dasm/master/docs/dasm.pdf
  32. Atari Programming Workshop Chapter links
    http://atariage.com/forum­s/viewtopic.php?t=47479
  33. Various Development Kits
    http://devkits.handheldmuseum.com/
  34. Classic Console Development
    http://sebastianmihai.com/ccd/
  35. Atari 2600 development – Snappy (batari basic)
    http://sebastianmihai.com/ma­in.php?t=47
  36. Atari VCS (Atari 2600) – fotografie
    http://oldcomputers.net/atari-vcs.html
  37. History of Consoles: Atari VCS/2600 (1977)
    http://gamester81.com/history-of-consoles-atari-vcs2600–1977/
  38. Iag Bogost: Racing the Beam
    http://www.bogost.com/book­s/video_computer_system.shtml
  39. Atari 2600 Programming Tutorial
    http://www.randomterrain.com/atari-2600-memories-tutorial-andrew-davie-01.html
  40. Atari 2600 Development Cartridge *Super Deluxe*~!
    http://jazz-disassemblies.blogspot.cz/2013/09/atari-2600-development-cartridge-super.html
  41. Atari „Alpine“ Devkit (pro Atari Jaguar)
    http://justclaws.atari.or­g/devcats/hardware/ataridev­.htm
  42. 6502 compatible assembler and emulator in javascript
    http://www.6502asm.com/
  43. Atari 2600 Programming
    http://atariage.com/2600/programming/
  44. Retrozone – Brand new original homebrew games by current programmers
    http://www.retrousb.com/in­dex.php?cPath=30
  45. ATARI VCS/2600 TIA CHIPS
    http://www.ataricompendium­.com/faq/vcs_tia/vcs_tia.html
  46. Elena, New programming language for the ZX Spectrum Next
    https://www.vintageisthene­wold.com/elena-new-programming-language-for-the-zx-spectrum-next
  47. ZX Spectrum development with modern tools
    http://www.breakintoprogram­.co.uk/software_developmen­t/zx-spectrum-development-with-modern-tools
  48. Z80 Development Toolchain
    http://www.breakintoprogram­.co.uk/computers/zx-spectrum/assembly-language/z80-development-toolchain
  49. Space Invaders Sprite Sheet
    https://www.deviantart.com/go­operblooper22/art/Space-Invaders-Sprite-Sheet-135338373
  50. [stella] PRECISE 2600 sound chart
    https://www.biglist.com/lis­ts/stella/archives/199704/msg00007­.html
  51. [stella] Frequency and Waveform Guide
    https://www.biglist.com/lis­ts/stella/archives/199706/msg00048­.html

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.