Programování zvukových karet s čipem OPL3 nebo s dvojicí čipů OPL2

29. 10. 2024
Doba čtení: 86 minut

Sdílet

 Autor: Konstantin Lanzet, podle licence: GNU FDL
Ukážeme si ovládání dvojice čipů OPL2 (DualOPL2), jak lze na OPL2 i OPL3 využít polyfonii a taktéž ovládání levého a pravého reproduktoru čipem OPL3, čímž se realizuje triviální stereo.

Obsah

1. Programování zvukových karet s čipem OPL3 nebo s dvojicí čipů OPL2

2. Sound Blaster Pro 1 s konfigurací DualOPL2

3. Přehrání tónu ve vybraném reproduktoru

4. Úplný zdrojový kód dnešního prvního demonstračního příkladu

5. Vícekanálový výstup z OPL2 (až devítihlasová polyfonie)

6. Nastavení not pro osm kanálů

7. Ovládání přehrání not klávesnicí

8. Úplný zdrojový kód dnešního druhého demonstračního příkladu

9. Vylepšení ovládání čipů OPL přes tabulku kláves+akcí: plnohodnotné „klávesy“ v 284 bajtech

10. Úplný zdrojový kód dnešního třetího demonstračního příkladu

11. Čip OPL3 z pohledu programátora

12. Řídicí registry čipu OPL3

13. Stereo výstup

14. Demonstrační příklad: programová změna zvukového výstupu do levého, pravého i obou reproduktorů

15. Nastavení čipu OPL3 do režimu NEkompatibilního s OPL2

16. Demonstrační příklad: funkční programový výběr zvukového výstupu

17. Režim využívající 18 zvukových kanálů

18. Demonstrační příklad: využití většiny zvukových kanálů čipu OPL3

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

20. Odkazy na Internetu

1. Programování zvukových karet s čipem OPL3 nebo s dvojicí čipů OPL2

V předchozím článku jsme si popsali postupný vývoj zvukových karet určených pro IBM PC, které obsahovaly čip OPL2 nebo OPL3. Připomeňme si ve stručnosti, že čipy OPL2, popř. OPL3 se ve světě PC využívaly poměrně dlouho – karty s těmito čipy se vyráběly od roku 1987 minimálně do roku 1996, ovšem různé klony SoundBlasterů byly vyráběny i po roce 1996. Jen zvolna byla FM syntéza nahrazována zvukovými kartami, které pro generování hudby využívaly wave table syntézu.

Dnešní článek bude zaměřen na vlastnosti čipů OPL2 a OPL3 z pohledu programátora. Ukážeme si, jak se ovládala dvojice čipů OPL2 (což bylo meziobdobí mezi kartami s jedním OPL2 na jedné straně a jedním „stereo“ OPL3 na straně druhé), jak lze na OPL2 i OPL3 využít polyfonii a taktéž ovládání levého a pravého reproduktoru čipem OPL3, čímž se pro jednotlivé kanály realizuje velmi triviální „stereo“ (ovšem bez možnosti plynulého panningu).

2. Sound Blaster Pro 1 s konfigurací DualOPL2

Existovaly celkem čtyři různé varianty využití čipů OPL:

  1. Jediný čip OPL2 v první a druhé generaci zvukových karet
  2. Dva čipy OPL2 pro realizaci určité formy stereo výstupu (bez panningu)
  3. Čip OPL3, který opět do určité míry umožňuje stereo výstup
  4. (Speciality typu dvojice OPL3 se čtyřmi výstupními kanály atd.)

Programování jediného čipu OPL2 jsme si již ukázali (a dnes se k němu ještě vrátíme), ovšem zajímavý je druhý způsob využívající dvojici čipů OPL2. Tuto konfiguraci měl Sound Blater Pro (bez dvojky) z roku 1991. Pro FM syntézu se v této kartě využívala dvojice čipů OPL2, přičemž každý čip byl zapojen do jednoho zvukového kanálu. Pokud byl požadovaný monofonní výstup (například z důvodu zpětné kompatibility), musely se buď oba čipy programovat se stejnými hodnotami řídicích registrů, nebo bylo možné použít adresu společnou pro oba čipy (adresní logika na kartě sama zařídila, že se hodnoty registrů zapsaly na oba čipy současně). Nutno dodat, že tento způsob zapojení, který se někdy označuje termínem DualOPL2, je poměrně unikátní právě pro Sound Blaster Pro a vlastně jen málo her dokázalo možnosti dvou OPL2 využít.

Pokud si budete chtít vlastnosti Sound Blasteru Pro 1.0 s Dual OPL2 otestovat v DOSBoxu, je nutné změnit jeho konfiguraci následovně:

sbtype              = sbpro1
sbbase              = 220
irq                 = 7
dma                 = 1
hdma                = 5
sbmixer             = false
sbwarmup            = 100
oplmode             = dualopl2
sb_filter           = off
sb_filter_always_on = false
opl_filter          = on
cms_filter          = on

3. Přehrání tónu ve vybraném reproduktoru

Jak tedy vypadá programové přehrání tónu v levém nebo pravém reproduktoru v případě, že máme kartu v konfiguraci DualOPL2? Z hlediska programátora je to ve skutečnosti poměrně snadno řešitelný problém, protože řídicí registry jednoho čipu OPL2 (levý reproduktor) jsou mapovány na I/O porty 0×220 a 0×221 (výběr registru na prvním portu, zápis nové hodnoty na portu druhém). A pro druhý OPL2 (ten ovládá pravý reproduktor) se jedná o I/O porty 0×222 a 0×223. Pokud se zápis provede přes „AdLibovské“ porty 0×388 a 0×389, dojde k zápisu do obou OPL2.

Připravíme si tedy pomocné konstanty. První dvě budou obsahovat adresy portů pro „levý“ OPL:

; registry karet s cipem OPL2
OPL_ADDRESS equ 0x220
OPL_DATA    equ 0x221

Následují definice offsetů, které použijeme pro výpočet skutečně použitých portů při zápisu („pravý“ OPL má adresy zvýšené o dvojku):

; vyber levelo a praveho reproduktoru
LEFT_SPEAKER  equ 0
RIGHT_SPEAKER equ 2  ; musi byt 2!!!

Zápis hodnot řídicích registrů z tabulky do levého či pravého OPL nepatrně upravíme, a to tak, že před vlastním zápisem nastavíme hodnotu registru BX na 0 nebo 2 (což je kýžený offset od adresy 0×220, resp. 0×221):

        mov  si, tones                   ; zacatek tabulky
        mov  bx, RIGHT_SPEAKER
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2

Subrutina pro zápis do vybraného registru OPL tedy bude vypadat následovně (povšimněte si zvýšení adresy o BX):

perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2
        ; AL - registr
        ; AH - hodnota
        ; BX - výběr levého či pravého OPL (0 nebo 2)
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        add dx, bx
        out dx, al
 
        ; cekani priblizne 3.3 mikrosekundy
        mov cl, 6
.delay1:
        in  al, dx
        loop .delay1
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        add dx, bx
        out dx, al
 
        ; cekani priblizne 23 mikrosekund
        mov cl, 35
.delay2:
        in  al, dx
        loop .delay2
 
        ret
Poznámka: navíc musíme do tabulky s hodnotami řídicích registrů přidat i registr OPL_FEEDBACK, jinak nebude v DOSBoxu výběr levého a pravého reproduktoru plně funkční. Osobně se domnívám, že se jedná spíše o chybu implementace DualOPL2 v DOSBoxu a nikoli o vlastnost reálného Sound Blasteru Pro 1.0 (ovšem tuto kartu nevlastním a novější karty již mají OPL3). Jak již bylo řečeno výše, je DualOPL2 spíše určitá kuriozita, protože ihned po vydání verze 2.0 se přestala 1.0 prodávat (takže ani mnoho her Pro 1.0 nepodporuje):
        db CHANNEL_1 + OPL_FEEDBACK,                   0x00  ; libovolny zapis zpusobi, ze kazdy OPL2 ovlada svuj kanal

4. Úplný zdrojový kód dnešního prvního demonstračního příkladu

V dnešním prvním demonstračním příkladu je ukázáno ovládání dvojice čipů OPL2 tak, jak bylo popsáno v předchozích kapitolách. Změnou zvýrazněného řádku je možné určit, do jakého reproduktoru bude zvuk poslán, tj. jaký OPL2 čip bude použit:

        mov  si, tones                   ; zacatek tabulky
        mov  bx, LEFT_SPEAKER
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2

nebo:

        mov  si, tones                   ; zacatek tabulky
        mov  bx, RIGHT_SPEAKER
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2

Zdrojový kód tohoto příkladu vypadá následovně:

; Prehrani zakladniho tonu na kartach s dvojici cipu OPL2.
; Pojmenovani registru OPL2.
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_table.com sound_dual_opl2.asm
;
; nebo pouze:
;     nasm -o sound_opl2_table.com sound_dual_opl2.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
  
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL2
OPL_ADDRESS equ 0x220
OPL_DATA    equ 0x221
 
; vyber levelo a praveho reproduktoru
LEFT_SPEAKER  equ 0
RIGHT_SPEAKER equ 2  ; musi byt 2!!!
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; vyprazdneni bufferu klavesnice a cekani na klavesu
%macro wait_key 0
        xor     ax, ax
        int     0x16
%endmacro
 
; makro pro zapis do registru OPL2
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_register
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        mov  si, tones                   ; zacatek tabulky
        mov  bx, RIGHT_SPEAKER
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2
 
        wait_key
        exit
 
write_table_to_opl2:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_opl_register
        jmp  write_table_to_opl2         ; muzeme prejit na dalsi registr
 
 
tones:  ; tabulka s tonem pro prvni kanal
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0xF0  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (komorni A = 440 Hz)
        db CHANNEL_1 + OPL_FEEDBACK,                   0x00  ; libovolny zapis zpusobi, ze kazdy OPL2 ovlada svuj kanal
        db CHANNEL_1 + OPL_KEY_ON,                     0x32  ; zapnuti/povoleni zvuku + nastaveni oktavy a vyssich bitu frekvence
        db 0, 0                                              ; zarazka
 
 
perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        add dx, bx
        out dx, al
 
        ; cekani priblizne 3.3 mikrosekundy
        mov cl, 6
.delay1:
        in  al, dx
        loop .delay1
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        add dx, bx
        out dx, al
 
        ; cekani priblizne 23 mikrosekund
        mov cl, 35
.delay2:
        in  al, dx
        loop .delay2
 
        ret

5. Vícekanálový výstup z OPL2 (až devítihlasová polyfonie)

Vraťme se ještě na chvíli k původnímu „jednoduchému“ čipu OPL2. Připomeňme si, že tyto čipy podporovaly celkem devět zvukových kanálů, které jsou na sobě nezávislé – každý kanál je možné individuálně ovládat a nastavovat jeho parametry. A každý kanál je tvořen dvojicí operátorů, které mohou být zapojeny různým způsobem – paralelně (AM modulace) či sériově (FM, resp. fázová modulace). Výsledkem je, že čip OPL2 dokáže přehrávat devět na sobě nezávislých tónů v případě, že není nastaven perkusní režim (což je trošku magie, která si vyžádá samostatný text). Každý kanál má svoji sadu řídicích registrů a vzhledem k tomu, že některé registry jsou určeny pro jednotlivé operátory, je těchto registrů poměrně velké množství.

Registry Platné pro Počet registrů Oficiální jméno
20..35 operátor 18 Amp Mod / Vibrato / EG type / Key Scaling / Multiple
40..55 operátor 18 Key scaling level / Operator output level
60..75 operátor 18 Attack Rate / Decay Rate
80..95 operátor 18 Sustain Level / Release Rate
A0..A8 kanál 9 Frequency (low 8 bits)
B0..B8 kanál 9 Key On / Octave / Frequency (high 2 bits)
C0..C8 kanál 9 Feedback strength / Connection type
E0..F5 kanál 9 Wave Select

Popř. se na celý problém můžeme podívat ze strany: pro nastavení každého kanálu potřebujeme 12 registrů: 4×2 registry pro nastavení operátorů a 4×1 registr pro nastavení vlastnosti celého kanálu. Ovšem některé registry jsou zpočátku vynulovány a my je nebudeme muset měnit (například výběr tvaru signálu nebo způsob zapojení operátorů – ponecháme výchozí hodnoty).

6. Nastavení not pro osm kanálů

Již umíme naprogramovat nastavení registrů jediného kanálu. Připomeňme si, že k tomuto účelu používáme tabulku, která vypadá následovně:

tones:  ; tabulka s tonem pro prvni kanal
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0xF0  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (komorni A = 440 Hz)
 
        db 0, 0                                              ; zarazka

Povšimněte si, že skutečně nenastavujeme všechny registry vypsané v předchozí kapitole, protože to není zcela nutné. Tuto tabulku můžeme triviálně rozšířit i pro další kanály, pouze nesmíme zapomenout na umístění zarážky za poslední hodnotou.

Rozšířená tabulka bude obsahovat pro každý kanál pouze výše uvedené registry (9 bajtů), přičemž registr OPL_KEY_ON budeme ovládat přímo z klávesnice, ze které si tak vytvoříme jednoduché „klávesy“ s osmi na sobě nezávislými notami. Jednotlivé kanály se budu lišit nastavenými frekvencemi (OPL_FREQUENCY_LOW + později OPL_KEY_ON), protože pro prvních osm kanálů postupně nastavíme noty C, D, E, F, G, A, H a vyšší C:

Hodnota pro zápis do registru
Nota Frekvence
C 261.1 0×0ae
D 293.7 0×181
E 329.6 0×1b0
F 349.2 0×1ca
G 392.0 0×202
A 440.0 0×241
H 493.9 0×287
C 523.3 0×2ae

V tabulce s hodnotami registrů můžeme nastavit spodních osm bitů hodnoty z posledního sloupce tabulky, a to pro osm kanálů (devátý není použit):

        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
        db CHANNEL_2 + OPL_FREQUENCY_LOW,              0x81  ; frekvence zvuku (D)
        db CHANNEL_3 + OPL_FREQUENCY_LOW,              0xb0  ; frekvence zvuku (E)
        db CHANNEL_4 + OPL_FREQUENCY_LOW,              0xca  ; frekvence zvuku (F)
        db CHANNEL_5 + OPL_FREQUENCY_LOW,              0x02  ; frekvence zvuku (G)
        db CHANNEL_6 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (A)
        db CHANNEL_7 + OPL_FREQUENCY_LOW,              0x87  ; frekvence zvuku (B)
        db CHANNEL_8 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)

Horní bity hodnoty se nastavují v registrech OPL_KEY_ON, které budeme měnit při stisku či naopak uvolnění klávesy.

7. Ovládání přehrání not klávesnicí

Nyní musíme implementovat „klávesy“, konkrétně začátek přehrání či naopak zastavení přehrávání noty při stisku/uvolnění kláves 1 až 8 na PC klávesnici (samozřejmě si však můžete vybrat i odlišné klávesy). Nejprve přečteme kód stisknuté/uvolněné klávesy, což již známe z předchozího článku:

        in  al, PPI_PORT_A               ; cteni stisknute klavesy

Dále si vytvoříme pomocná makra, která zareagují na stisk či uvolnění klávesy. Makrům se předá kód klávesy, index registru OPL, který se má změnit, a hodnota tohoto regsitru:

%macro on_key_press 3
        cmp al, %1                   ; test na stisk klavesy
        jne %%not_pressed            ; neni stisknuta -> preskok
        write_opl_register %2, %3    ; povoleni KEY ON bitu
        jmp .opak
    %%not_pressed:
%endmacro
 
%macro on_key_release 3
        cmp al, 0x80 + %1            ; test na uvolneni klavesy
        jne %%not_released           ; neni uvolnena -> preskok
        write_opl_register %2, %3    ; zakaz KEY ON bitu
        jmp .opak
    %%not_released:
%endmacro

Vlastní realizace „kláves“ vypadá sice vypadá velmi jednoduše (a taktéž ve skutečnosti jednoduchá je), ovšem výsledný strojový kód bude postupně narůstat kvůli expanzi maker:

        on_key_press   KEY_1, CHANNEL_1 + OPL_KEY_ON, 0b00101110
        on_key_release KEY_1, CHANNEL_1 + OPL_KEY_ON, 0b00001110
        on_key_press   KEY_2, CHANNEL_2 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_2, CHANNEL_2 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_3, CHANNEL_3 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_3, CHANNEL_3 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_4, CHANNEL_4 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_4, CHANNEL_4 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_5, CHANNEL_5 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_5, CHANNEL_5 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_6, CHANNEL_6 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_6, CHANNEL_6 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_7, CHANNEL_7 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_7, CHANNEL_7 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_8, CHANNEL_8 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_8, CHANNEL_8 + OPL_KEY_ON, 0b00010010

8. Úplný zdrojový kód dnešního druhého demonstračního příkladu

Ukažme si nyní úplný zdrojový kód dnešního druhého demonstračního příkladu, který po svém spuštění reaguje na klávesy 1..8 a na základě kombinace stisku těchto kláves povoluje či zakazuje zvukové kanály 1..8 bitem KEY_ON. Jak bylo popsáno výše, je možné přehrát více not:

; Prehrani zakladniho tonu na kartach s cipem OPL2.
; Pojmenovani registru OPL2.
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_table.com sound_opl2_multichannel.asm
;
; nebo pouze:
;     nasm -o sound_opl2_table.com sound_opl2_multichannel.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
  
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL2
OPL_ADDRESS equ 0x388
OPL_DATA    equ 0x389
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
; registry PPI
PPI_PORT_A equ 0x60
PPI_PORT_B equ 0x61
 
; kody klaves
KEY_ESC     equ 0x01
KEY_SPACE   equ 0x39
KEY_RELEASE equ 0x80
KEY_1       equ 0x02
KEY_2       equ 0x03
KEY_3       equ 0x04
KEY_4       equ 0x05
KEY_5       equ 0x06
KEY_6       equ 0x07
KEY_7       equ 0x08
KEY_8       equ 0x09
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; makro pro zapis do registru OPL2
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_register
%endmacro
 
%macro on_key_press 3
        cmp al, %1                   ; test na stisk klavesy
        jne %%not_pressed            ; neni stisknuta -> preskok
        write_opl_register %2, %3    ; povoleni KEY ON bitu
        jmp .opak
    %%not_pressed:
%endmacro
 
%macro on_key_release 3
        cmp al, 0x80 + %1            ; test na uvolneni klavesy
        jne %%not_released           ; neni uvolnena -> preskok
        write_opl_register %2, %3    ; zakaz KEY ON bitu
        jmp .opak
    %%not_released:
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        mov  si, tones                   ; zacatek tabulky
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2
 
        in  al, PPI_PORT_B               ; port B s rizenim zarizeni
        or  al, 0b1000000                ; nastaveni bitu cislo 7 na jednicku
        out PPI_PORT_B, al               ; zapis zpet na port B
 
.opak:
        in  al, PPI_PORT_A               ; cteni stisknute klavesy
 
        on_key_press   KEY_1, CHANNEL_1 + OPL_KEY_ON, 0b00101110
        on_key_release KEY_1, CHANNEL_1 + OPL_KEY_ON, 0b00001110
        on_key_press   KEY_2, CHANNEL_2 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_2, CHANNEL_2 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_3, CHANNEL_3 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_3, CHANNEL_3 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_4, CHANNEL_4 + OPL_KEY_ON, 0b00110001
        on_key_release KEY_4, CHANNEL_4 + OPL_KEY_ON, 0b00010001
        on_key_press   KEY_5, CHANNEL_5 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_5, CHANNEL_5 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_6, CHANNEL_6 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_6, CHANNEL_6 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_7, CHANNEL_7 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_7, CHANNEL_7 + OPL_KEY_ON, 0b00010010
        on_key_press   KEY_8, CHANNEL_8 + OPL_KEY_ON, 0b00110010
        on_key_release KEY_8, CHANNEL_8 + OPL_KEY_ON, 0b00010010
 
        cmp al, KEY_ESC                  ; test stisknute klavesy ESC
        jne .opak                        ; neni stisknuta? -> zkusme znovu
        exit
 
 
write_table_to_opl2:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_opl_register
        jmp  write_table_to_opl2         ; muzeme prejit na dalsi registr
 
 
tones:  ; tabulka s tony pro osm kanalu
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db CHANNEL_2_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_2_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_2_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_2_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_2_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_2_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_2 + OPL_FREQUENCY_LOW,              0x81  ; frekvence zvuku (D)
 
        db CHANNEL_3_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_3_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_3_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_3_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_3_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_3_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_3 + OPL_FREQUENCY_LOW,              0xb0  ; frekvence zvuku (E)
 
        db CHANNEL_4_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_4_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_4_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_4_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_4_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_4_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_4 + OPL_FREQUENCY_LOW,              0xca  ; frekvence zvuku (F)
 
        db CHANNEL_5_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_5_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_5_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_5_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_5_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_5_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_5 + OPL_FREQUENCY_LOW,              0x02  ; frekvence zvuku (G)
 
        db CHANNEL_6_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_6_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_6_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_6_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_6_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_6_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_6 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (A)
 
        db CHANNEL_7_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_7_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_7_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_7_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_7_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_7_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_7 + OPL_FREQUENCY_LOW,              0x87  ; frekvence zvuku (B)
 
        db CHANNEL_8_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_8_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_8_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_8_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_8_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_8_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_8 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db 0, 0                                              ; zarazka
 
 
perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        ; cekani priblizne 3.3 mikrosekundy
        mov cl, 6
.delay1:
        in  al, dx
        loop .delay1
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        out dx, al
 
        ; cekani priblizne 23 mikrosekund
        mov cl, 35
.delay2:
        in  al, dx
        loop .delay2
 
        ret

9. Vylepšení ovládání čipů OPL přes tabulku kláves+akcí: plnohodnotné „klávesy“ v 284 bajtech

Předchozí demonstrační příklad je sice plně funkční, ale po překladu získáme program typu COM, který má velikost 422 bajtů. To je poměrně hodně (i když asi ne z dnešního pohledu). Pokusme se tedy nahradit volání maker spíše tabulkou, v níž bude zapsána jak událost, na kterou reagujeme (stisk/uvolnění klávesy), tak i potřebná změna OPL. Samozřejmě opět nesmíme zapomenout na „zarážku“ na konci tabulky:

key_actions:
        db KEY_1,             CHANNEL_1 + OPL_KEY_ON, 0b00101110
        db KEY_1+KEY_RELEASE, CHANNEL_1 + OPL_KEY_ON, 0b00001110
        db KEY_2,             CHANNEL_2 + OPL_KEY_ON, 0b00110001
        db KEY_2+KEY_RELEASE, CHANNEL_2 + OPL_KEY_ON, 0b00010001
        db KEY_3,             CHANNEL_3 + OPL_KEY_ON, 0b00110001
        db KEY_3+KEY_RELEASE, CHANNEL_3 + OPL_KEY_ON, 0b00010001
        db KEY_4,             CHANNEL_4 + OPL_KEY_ON, 0b00110001
        db KEY_4+KEY_RELEASE, CHANNEL_4 + OPL_KEY_ON, 0b00010001
        db KEY_5,             CHANNEL_5 + OPL_KEY_ON, 0b00110010
        db KEY_5+KEY_RELEASE, CHANNEL_5 + OPL_KEY_ON, 0b00010010
        db KEY_6,             CHANNEL_6 + OPL_KEY_ON, 0b00110010
        db KEY_6+KEY_RELEASE, CHANNEL_6 + OPL_KEY_ON, 0b00010010
        db KEY_7,             CHANNEL_7 + OPL_KEY_ON, 0b00110010
        db KEY_7+KEY_RELEASE, CHANNEL_7 + OPL_KEY_ON, 0b00010010
        db KEY_8,             CHANNEL_8 + OPL_KEY_ON, 0b00110010
        db KEY_8+KEY_RELEASE, CHANNEL_8 + OPL_KEY_ON, 0b00010010
        db 0, 0                                              ; zarazka

Postupné porovnání přečteného kódu klávesy a vyvolání příslušné akce lze realizovat následující programovou smyčkou (tu by navíc ještě bylo možné optimalizovat jinou alokací registrů):

.opak:
        in  al, PPI_PORT_A               ; cteni stisknute klavesy
        cmp al, KEY_ESC                  ; test na stisk ESC
        je  .exit                        ; pokud stisknuta, konec programu
 
        mov ah, al                       ; kod klavesy do registru AH pro dalsi pouziti
        mov si, key_actions              ; tabulka akci pri stisku ci uvolneni klavesy
 
.next_key:
        lodsb                            ; nacist kod klavesy z tabulky
        or  al, al                       ; test na nulu (zarazka)
        jz  .opak                        ; nic jsme jiz nenasli -> cteni klavesy pres port
 
        cmp ah, al                       ; nasli jsme kod klavesy, ktery zname?
        jne .try_next_key
        lodsb                            ; adresa OPL registru
        mov ah, al
        lodsb                            ; hodnota OPL registru
        xchg ah, al                      ; vtipne jsme si prohodili parametry subrutiny write_opl_register
        call perform_write_to_opl_register
        jmp .next_key                    ; zkusit dalsi klavesu
.try_next_key:
        add si, 2                        ; preskocit adresu registru + jeho hodnotu
        jmp .next_key

Výsledkem jsou plnohodnotné „klávesy“ realizované programem o velikosti 284 bajtů, ve kterém je navíc možné individuálně měnit zvuk každého kanálu (noty).

10. Úplný zdrojový kód dnešního třetího demonstračního příkladu

Upravený a do určité míry optimalizovaný příklad s realizací „kláves“ na IBM PC bude vypadat následovně. Jak jsme si již řekli v předchozí kapitoly, bude výsledný program nejenom kratší, ale i poněkud přehlednější:

; Prehrani zakladniho tonu na kartach s cipem OPL2.
; Pojmenovani registru OPL2.
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_table.com sound_opl2_multichannel.asm
;
; nebo pouze:
;     nasm -o sound_opl2_table.com sound_opl2_multichannel.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
 
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL2
OPL_ADDRESS equ 0x388
OPL_DATA    equ 0x389
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
; registry PPI
PPI_PORT_A equ 0x60
PPI_PORT_B equ 0x61
 
; kody klaves
KEY_ESC     equ 0x01
KEY_SPACE   equ 0x39
KEY_RELEASE equ 0x80
KEY_1       equ 0x02
KEY_2       equ 0x03
KEY_3       equ 0x04
KEY_4       equ 0x05
KEY_5       equ 0x06
KEY_6       equ 0x07
KEY_7       equ 0x08
KEY_8       equ 0x09
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; makro pro zapis do registru OPL2
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_register
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        mov  si, tones                   ; zacatek tabulky
        call write_table_to_opl2         ; zapis obsahu tabulky do OPL2
 
        in  al, PPI_PORT_B               ; port B s rizenim zarizeni
        or  al, 0b1000000                ; nastaveni bitu cislo 7 na jednicku
        out PPI_PORT_B, al               ; zapis zpet na port B
 
.opak:
        in  al, PPI_PORT_A               ; cteni stisknute klavesy
        cmp al, KEY_ESC                  ; test na stisk ESC
        je  .exit                        ; pokud stisknuta, konec programu
 
        mov ah, al                       ; kod klavesy do registru AH pro dalsi pouziti
        mov si, key_actions              ; tabulka akci pri stisku ci uvolneni klavesy
 
.next_key:
        lodsb                            ; nacist kod klavesy z tabulky
        or  al, al                       ; test na nulu (zarazka)
        jz  .opak                        ; nic jsme jiz nenasli -> cteni klavesy pres port
 
        cmp ah, al                       ; nasli jsme kod klavesy, ktery zname?
        jne .try_next_key
        lodsb                            ; adresa OPL registru
        mov ah, al
        lodsb                            ; hodnota OPL registru
        xchg ah, al                      ; vtipne jsme si prohodili parametry subrutiny write_opl_register
        call perform_write_to_opl_register
        jmp .next_key                    ; zkusit dalsi klavesu
.try_next_key:
        add si, 2                        ; preskocit adresu registru + jeho hodnotu
        jmp .next_key
 
.exit:
        exit
 
 
write_table_to_opl2:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_opl_register
        jmp  write_table_to_opl2         ; muzeme prejit na dalsi registr
 
 
key_actions:
        db KEY_1,             CHANNEL_1 + OPL_KEY_ON, 0b00101110
        db KEY_1+KEY_RELEASE, CHANNEL_1 + OPL_KEY_ON, 0b00001110
        db KEY_2,             CHANNEL_2 + OPL_KEY_ON, 0b00110001
        db KEY_2+KEY_RELEASE, CHANNEL_2 + OPL_KEY_ON, 0b00010001
        db KEY_3,             CHANNEL_3 + OPL_KEY_ON, 0b00110001
        db KEY_3+KEY_RELEASE, CHANNEL_3 + OPL_KEY_ON, 0b00010001
        db KEY_4,             CHANNEL_4 + OPL_KEY_ON, 0b00110001
        db KEY_4+KEY_RELEASE, CHANNEL_4 + OPL_KEY_ON, 0b00010001
        db KEY_5,             CHANNEL_5 + OPL_KEY_ON, 0b00110010
        db KEY_5+KEY_RELEASE, CHANNEL_5 + OPL_KEY_ON, 0b00010010
        db KEY_6,             CHANNEL_6 + OPL_KEY_ON, 0b00110010
        db KEY_6+KEY_RELEASE, CHANNEL_6 + OPL_KEY_ON, 0b00010010
        db KEY_7,             CHANNEL_7 + OPL_KEY_ON, 0b00110010
        db KEY_7+KEY_RELEASE, CHANNEL_7 + OPL_KEY_ON, 0b00010010
        db KEY_8,             CHANNEL_8 + OPL_KEY_ON, 0b00110010
        db KEY_8+KEY_RELEASE, CHANNEL_8 + OPL_KEY_ON, 0b00010010
        db 0, 0                                              ; zarazka
 
 
tones:  ; tabulka s tony pro osm kanalu
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db CHANNEL_2_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_2_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_2_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_2_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_2_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_2_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_2 + OPL_FREQUENCY_LOW,              0x81  ; frekvence zvuku (D)
 
        db CHANNEL_3_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_3_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_3_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_3_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_3_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_3_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_3 + OPL_FREQUENCY_LOW,              0xb0  ; frekvence zvuku (E)
 
        db CHANNEL_4_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_4_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_4_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_4_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_4_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_4_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_4 + OPL_FREQUENCY_LOW,              0xca  ; frekvence zvuku (F)
 
        db CHANNEL_5_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_5_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_5_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_5_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_5_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_5_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_5 + OPL_FREQUENCY_LOW,              0x02  ; frekvence zvuku (G)
 
        db CHANNEL_6_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_6_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_6_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_6_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_6_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_6_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_6 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (A)
 
        db CHANNEL_7_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_7_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_7_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_7_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_7_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_7_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_7 + OPL_FREQUENCY_LOW,              0x87  ; frekvence zvuku (B)
 
        db CHANNEL_8_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_8_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_8_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_8_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_8_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_8_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_8 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db 0, 0                                              ; zarazka
 
 
perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        ; cekani priblizne 3.3 mikrosekundy
        mov cl, 6
.delay1:
        in  al, dx
        loop .delay1
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        out dx, al
 
        ; cekani priblizne 23 mikrosekund
        mov cl, 35
.delay2:
        in  al, dx
        loop .delay2
 
        ret

11. Čip OPL3 z pohledu programátora

Nyní se konečně dostáváme k popisu čipu OPL3. Oproti výše popsanému čipu YM 3812 došlo k několika podstatným úpravám. Především se zvýšil celkový počet operátorů z osmnácti na 36, do jednoho kanálu je možné zapojit až čtyři operátory, místo čtyř typů signálů na vstupech operátorů je k dispozici osm typů (včetně obdélníkového signálu a logaritmicky zkresleného signálu pilového) a na výstup čipu je možné zapojit dvojici D/A převodníků a vytvářet tak stereo hudbu – ve skutečnosti však není možné plynule nastavovat přechod mezi levým a pravým reproduktorem (panning), lze pouze zvolit, zda je výstup z nějakého hudebního kanálu přehráván na levém, pravém či obou reproduktorech.

Vzhledem ke zvýšenému počtu operátorů se zvýšil i počet interních registrů. Z tohoto důvodu jsou místo jedné registrové sady použity sady dvě, což znamená, že místo dvou adres mapovaných do I/O prostoru (index a data) jsou použity adresy čtyři.

Zatímco u čipu YM 3812 bylo možné operátory v jednom kanálu zapojit pouze do dvou konfigurací (AM či FM), lze u čipu YMF 262 použít mnohem větší počet kombinací, kterými se budeme podrobněji zabývat příště. Existují tři možnosti konfigurace: 18 kanálů, z nichž každý obsahuje dva operátory, 15 melodických kanálů se dvěma operátory společně s pěti kanály pracujícími v perkusním režimu a konečně 6 kanálů se čtyřmi operátory (zbytek jsou buď dvouoperátorové kanály nebo kanály pracující v perkusním režimu).

V konfiguraci čtyřoperátorového kanálu vždy jeden z operátorů (původní modulátor) obsahuje zpětnou vazbu, i když v řídicích registrech je možné nastavit úroveň zpětné vazby pro všechny operátory – u tří čtvrtin operátorů nemá tedy obsah příslušného řídicího registru vliv na generovaný tón.

12. Řídicí registry čipu OPL3

Registrů čipu OPL3 je více než 256 a tudíž jsou pro jejich adresování+zápis použity čtyři I/O porty – vždy dva pro výběr registru a dva pro zápis dat do zvoleného registru. Dolních 256 registrů je ovládáno přes porty 0×220 a 0×221, horních pak přes porty 0×222 a 0×223:

Registr/registry Dolní registry Horní registry
01 Test LSI / Enable waveform control dtto
02 Timer 1 data dtto
03 Timer 2 data dtto
04 Timer control flags konfigurace zvukových kanálů (2 operátory, 4 operátory, …)
05 nemá význam kompatibilita s OPL2: ano/ne
08 Speech synthesis mode / Keyboard split note select pravděpodobně bez významu
20..35 Amp Mod / Vibrato / EG type / Key Scaling / Multiple dtto pro horních 18 operátorů
40..55 Key scaling level / Operator output level dtto pro horních 18 operátorů
60..75 Attack Rate / Decay Rate dtto pro horních 18 operátorů
80..95 Sustain Level / Release Rate dtto pro horních 18 operátorů
A0..A8 Frequency (low 8 bits) dtto pro horních 9 kanálů
B0..B8 Key On / Octave / Frequency (high 2 bits) dtto pro horních 9 kanálů
BD AM depth / Vibrato depth / Rhythm control nemá význam
C0..C8 Feedback strength / Connection type dtto pro horních 9 kanálů
E0..F5 Wave Select dtto pro horních 18 operátorů
Poznámka: povšimněte si, že dolní a horní registry, které se přímo nevztahují k operátorům nebo kanálům, mají obecně odlišný význam. Taktéž stojí za povšimnutí, že dolní registry jsou prakticky plně kompatibilní s OPL2 (bylo přidáno jen několik nových bitů).

13. Stereo výstup

Z předchozího textu je pravděpodobně patrné, že čip OPL 3 nabízí mnohem více možností při vytváření zvuků, než původní OPL 2. Ovšem mnoho vývojářů nedokázalo všechny možnosti syntézy v tomto režimu využít – z tohoto důvodu se velmi často setkáme s tím, že je použita „dvouoperátorová“ syntéza a čip YMF 262 je tak vlastně degradován na stereo verzi původního čipu YM 3812 s dvojnásobným množstvím hudebních kanálů (osmnáct kanálů namísto devíti).

Na chvíli se zastavme právě u stereo výstupu. Do registrů OPL_FEEDBACK na adresách C0..C8 byly přidány dva bity, které určují, do jakého reproduktoru má být daný kanál vysílán – zvolit je možné libovolnou kombinaci levý+pravý (nebo i žádný). Tento registr má nyní tuto strukturu:

   7     6     5     4     3     2     1     0
+-----+-----+-----+-----+-----+-----+-----+-----+
| ch. | ch. |  R  |  L  |    Feedback     | Alg |
| D   | C   | out | out |                 |     |
+-----+-----+-----+-----+-----+-----+-----+-----+

Bity 7 a 6 volí výstupní kanály C a D (záleží na způsobu zapojení D/A převodníku).

Hodnotami bitů 5 a 4 se volí výstup do levého a/nebo pravého reproduktoru. Právě tyto bity budeme měnit.

Bity 3–1 nastavují sílu zpětné vazby, přičemž 0 znamená, že se zpětná vazba neuplatní a 7 znamená, že zpětnovazební signál má nejvyšší váhu.

Nultým bitem se volí způsob vzájemného propojení obou operátorů. FM (resp. přesněji řečeno PM) modulace je použita ve chvíli, kdy je tento bit nulový. Pokud je nastavený na jedničku, bude každý z operátorů pracovat nezávisle jako zdroj tónu (sinusovka nebo její varianty).

14. Demonstrační příklad: programová změna zvukového výstupu do levého, pravého i obou reproduktorů

Zkusme nyní jediný tón (konkrétně notu A) přehrát postupně v levém reproduktoru, potom v reproduktoru pravém a nakonec v obou reproduktorech. Měla by nám k tomu stačit tato sekvence maker, v nichž měníme bity 5 a 4 registru OPL_FEEDBACK pro první kanál:

; levy reproduktor
write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00010000
wait_key
 
; pravy reproduktor
write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00100000
wait_key
 
; oba reproduktory
write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00110000
wait_key
Poznámka: při zápisu do OPL3 již není nutné používat zpožďovací smyčky, takže je v programech již nenajdete.

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

; Prehrani zakladniho tonu na kartach s cipem OPL3.
; Prepinani vystupu na pravy a/nebo levy reproduktor.
; Pojmenovani registru OPL3.
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_stereo1.com sound_opl3_stereo_1.asm
;
; nebo pouze:
;     nasm -o sound_opl2_stereo1.com sound_opl3_stereo_1.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
  
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL3
OPL_ADDRESS           equ 0x220
OPL_DATA              equ 0x221
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
OPL3_MODE_ENABLE      equ 0x05  ; vyssi port!!!
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; vyprazdneni bufferu klavesnice a cekani na klavesu
%macro wait_key 0
        xor     ax, ax
        int     0x16
%endmacro
 
; makro pro zapis do registru OPL2 nebo OPL3
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_register
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        mov  si, tone1                   ; zacatek tabulky
        call write_table_to_opl3         ; zapis obsahu tabulky do OPL2
 
        ; levy reproduktor
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00010000
        wait_key
 
        ; pravy reproduktor
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00100000
        wait_key
 
        ; oba reproduktory
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00110000
        wait_key
 
        exit
 
write_table_to_opl3:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_opl_register
        jmp  write_table_to_opl3         ; muzeme prejit na dalsi registr
 
 
tone1:  ; tabulka s tonem pro prvni kanal
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0xF0  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_1 + OPL_FREQUENCY_LOW,   0x41  ; frekvence zvuku (komorni A = 440 Hz)
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_KEY_ON,                     0x32  ; zapnuti/povoleni zvuku + nastaveni oktavy a vyssich bitu frekvence
        db 0, 0                                              ; zarazka
 
 
perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2 nebo OPL3
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        out dx, al
 
        ret

15. Nastavení čipu OPL3 do režimu NEkompatibilního s OPL2

Pokud demonstrační příklad z předchozí kapitoly přeložíme a spustíme, snadno zjistíme, že přepínání mezi reproduktory ve skutečnosti nefunguje. Proč tomu tak je? Čip OPL3 je po resetu nastaven do režimu kompatibilního s OPL2, v němž nemají vyšší bity registru OPL_FEEDBACK žádný zvláštní význam a tudíž jsou v kompatibilním režimu zcela ignorovány. Přepnutí do režimu NEkompatibilního s OPL2 je snadné – musíme nastavit nejnižší bit registru OPL3_MODE_ENABLE. Ten je – opět z důvodu zpětné kompatibility – umístěn mezi horních 256 řídicích registrů, takže ho kód určený pro původní OPL2 nemůže omylem přepsat.

Vypnutí režimu kompatibility:

        write_opl_high_register OPL3_MODE_ENABLE, 1

Využíváme zde tuto konstantu:

OPL3_MODE_ENABLE      equ 0x05  ; vyssi port!!!

A následující makro:

; makro pro zapis do "vyssiho" registru OPL3
%macro write_opl_high_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_high_register
%endmacro

16. Demonstrační příklad: funkční programový výběr zvukového výstupu

Následuje úplný zdrojový kód programu, který bude notu A postupně přehrávat v levém, potom v pravém a posléze v obou reproduktorech:

; Prehrani zakladniho tonu na kartach s cipem OPL3.
; Prepnuti do rezimu OPL3.
; Prepinani vystupu na pravy a/nebo levy reproduktor.
; Pojmenovani registru OPL3.
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_stereo1.com sound_opl3_stereo_2.asm
;
; nebo pouze:
;     nasm -o sound_opl2_stereo1.com sound_opl3_stereo_2.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
 
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL3
OPL_ADDRESS           equ 0x220
OPL_DATA              equ 0x221
OPL_HIGH_ADDRESS      equ 0x222
OPL_HIGH_DATA         equ 0x223
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
OPL3_MODE_ENABLE      equ 0x05  ; vyssi port!!!
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; vyprazdneni bufferu klavesnice a cekani na klavesu
%macro wait_key 0
        xor     ax, ax
        int     0x16
%endmacro
 
; makro pro zapis do registru OPL2 nebo OPL3
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_register
%endmacro
 
; makro pro zapis do "vyssiho" registru OPL3
%macro write_opl_high_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_opl_high_register
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        write_opl_high_register OPL3_MODE_ENABLE, 1
 
        mov  si, tone1                   ; zacatek tabulky
        call write_table_to_opl3         ; zapis obsahu tabulky do OPL2
 
        ; levy reproduktor
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00010000
        wait_key
 
        ; pravy reproduktor
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00100000
        wait_key
 
        ; oba reproduktory
        write_opl_register CHANNEL_1 + OPL_FEEDBACK, 0b00110000
        wait_key
 
        exit
 
write_table_to_opl3:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_opl_register
        jmp  write_table_to_opl3         ; muzeme prejit na dalsi registr
 
 
tone1:  ; tabulka s tonem pro prvni kanal
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0xF0  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_1 + OPL_FREQUENCY_LOW,   0x41  ; frekvence zvuku (komorni A = 440 Hz)
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_KEY_ON,                     0x32  ; zapnuti/povoleni zvuku + nastaveni oktavy a vyssich bitu frekvence
        db 0, 0                                              ; zarazka
 
 
perform_write_to_opl_register:
        ; zapis do vybraneho registru OPL2 nebo OPL3
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        out dx, al
 
        ret
 
 
perform_write_to_opl_high_register:
        ; zapis do vybraneho "vyssiho" registru OPL3
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_HIGH_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        mov al, ah                 ; zapis hodnoty do vybraneho registru
        mov dx, OPL_HIGH_DATA
        out dx, al
 
        ret

17. Režim využívající 18 zvukových kanálů

Zvukové kanály čipu OPL3 mohou být nakonfigurovány čtyřmi různými způsoby:

  1. Osmnáct melodických kanálů, z nichž každý je tvořen dvěma operátory (jakoby bychom měli dva čipy OPL2)
  2. Patnáct melodických kanálů, z nichž každý je tvořen dvěma operátory + 5 kanálů pro perkusní nástroje (činely atd.)
  3. Až šest melodických kanálů, z nichž každý je tvořen čtyřmi operátory + minimálně šest kanálů tvořených dvěma operátory (čtyřoperátorové kanály lze povolovat individuálně)
  4. Až šest melodických kanálů, z nichž každý je tvořen čtyřmi operátory + tři kanály tvořené dvěma operátory + 5 kanálů pro perkusní nástroje (čtyřoperátorové kanály lze povolovat individuálně)

Prozatím využijeme první zmíněnou konfiguraci, tj. osmnáct melodických zvukových kanálů, přičemž zvuk v každém kanálu je tvořen dvěma operátory zapojenými buď v režimu AM syntézy či FM (PM) syntézy. Z těchto osmnácti kanálů využijeme celkem 16 kanálů – osm pro přehrání not v jedné oktávě, dalších osm pro přehrání stejných not, ovšem s mnohem větší mírou distorze FM syntézou. Všechny relevantní registry těchto šestnácti kanálů jsou v demonstračním příkladu (viz další kapitolu) uloženy v příslušných dvou tabulkách (pro „nižší“ kanály a pro kanály „vyšší“). A další tabulka obsahuje vazbu mezi stiskem/uvolněním klávesy a změnou OPL registru KEY_ON.

bitcoin_skoleni

Poznámka: na další tři možné konfigurace čipu OPL3 se podíváme příště – právě v nich totiž OPL3 vyniká nad svým předchůdcem OPL2.

18. Demonstrační příklad: využití většiny zvukových kanálů čipu OPL3

Ukažme si nyní upravené „klávesy“, které dokážou přehrát dvě stupnice. První z nich se řídí klávesami 1–8 (první řada), druhá pak klávesami Q-I (druhá řada). Při přehrávání mohou nastat problémy kvůli ghostingu kláves, což je ovšem pro program ovládaný 18 klávesami prakticky neopravitelná vada. Zdrojový kód je sice poměrně dlouhý (25kB), ale výsledkem je .COM soubor o velikosti pouhých 550 bajtů, což stále není špatné (program navíc vůbec není optimalizován na velikost):

; Klavesami 1-8 lze prehrat noty z jedne oktavy (i soucasne).
; klavesami Q-I se prehraji noty s jinym zabarvenim.
; Kratsi varianta s tabulkou operaci, ktere se maji provest pri stisku klavesy.
; Pojmenovani registru OPL3.
; Zapisy do "dolnich" i "hornich" registru OPL3
;
;
; preklad pomoci:
;     nasm -f bin -o sound_opl2_table.com sound_opl3_multichannel.asm
;
; nebo pouze:
;     nasm -o sound_opl2_table.com sound_opl3_multichannel.asm
 
;-----------------------------------------------------------------------------
 
BITS 16         ; 16bitovy vystup pro DOS
CPU 8086        ; specifikace pouziteho instrukcniho souboru
 
 
;-----------------------------------------------------------------------------
 
; registry karet s cipem OPL2
OPL_ADDRESS           equ 0x388
OPL_DATA              equ 0x389
OPL_HIGH_ADDRESS      equ 0x222
OPL_HIGH_DATA         equ 0x223
 
; skupiny registru
LOW_REGISTER          equ 0
HIGH_REGISTER         equ 1
 
; ridici registry OPL2
OPL_TEST_LSI          equ 0x01
OPL_TIMER_1           equ 0x02
OPL_TIMER_2           equ 0x03
OPL_TIMER_CTRL        equ 0x04
OPL_KBSPLIT           equ 0x08
OPL_AMP_VIBRATO_EG    equ 0x20
OPL_LEVEL             equ 0x40
OPL_ATTACK_DECAY      equ 0x60
OPL_SUSTAIN_RELEASE   equ 0x80
OPL_FREQUENCY_LOW     equ 0xa0
OPL_KEY_ON            equ 0xb0
OPL_AM_VIBRATO_RHYTHM equ 0xbd
OPL_FEEDBACK          equ 0xc0
OPL_WAVE_SELECT       equ 0xe0
OPL3_MODE_ENABLE      equ 0x05  ; vyssi port!!!
 
; indexy kanalu
CHANNEL_1 equ 0
CHANNEL_2 equ 1
CHANNEL_3 equ 2
CHANNEL_4 equ 3
CHANNEL_5 equ 4
CHANNEL_6 equ 5
CHANNEL_7 equ 6
CHANNEL_8 equ 7
CHANNEL_9 equ 8
 
; offsety pro jednotlive operatory
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
;  Operator 1    00  01  02  08  09  0A  10  11  12
;  Operator 2    03  04  05  0B  0C  0D  13  14  15
; --------------------------------------------------
;  Channel        1   2   3   4   5   6   7   8   9
CHANNEL_1_OPERATOR_1 equ 0x00
CHANNEL_1_OPERATOR_2 equ 0x03
CHANNEL_2_OPERATOR_1 equ 0x01
CHANNEL_2_OPERATOR_2 equ 0x04
CHANNEL_3_OPERATOR_1 equ 0x02
CHANNEL_3_OPERATOR_2 equ 0x05
CHANNEL_4_OPERATOR_1 equ 0x08
CHANNEL_4_OPERATOR_2 equ 0x0b
CHANNEL_5_OPERATOR_1 equ 0x09
CHANNEL_5_OPERATOR_2 equ 0x0c
CHANNEL_6_OPERATOR_1 equ 0x0a
CHANNEL_6_OPERATOR_2 equ 0x0d
CHANNEL_7_OPERATOR_1 equ 0x10
CHANNEL_7_OPERATOR_2 equ 0x13
CHANNEL_8_OPERATOR_1 equ 0x11
CHANNEL_8_OPERATOR_2 equ 0x14
CHANNEL_9_OPERATOR_1 equ 0x12
CHANNEL_9_OPERATOR_2 equ 0x15
 
; registry PPI
PPI_PORT_A equ 0x60
PPI_PORT_B equ 0x61
 
; kody klaves
KEY_ESC     equ 0x01
KEY_SPACE   equ 0x39
KEY_RELEASE equ 0x80
KEY_1       equ 0x02
KEY_2       equ 0x03
KEY_3       equ 0x04
KEY_4       equ 0x05
KEY_5       equ 0x06
KEY_6       equ 0x07
KEY_7       equ 0x08
KEY_8       equ 0x09
KEY_Q       equ 0x10
KEY_W       equ 0x11
KEY_E       equ 0x12
KEY_R       equ 0x13
KEY_T       equ 0x14
KEY_Y       equ 0x15
KEY_U       equ 0x16
KEY_I       equ 0x17
 
;-----------------------------------------------------------------------------
 
; ukonceni procesu a navrat do DOSu
%macro exit 0
        ret
%endmacro
 
; makro pro zapis do registru OPL2
%macro write_opl_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_low_opl_register
%endmacro
 
; makro pro zapis do "vyssiho" registru OPL3
%macro write_opl_high_register 2
        mov     al, %1
        mov     ah, %2
        call    perform_write_to_high_opl_register
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        push cs
        pop  ds                          ; DS==CS
 
        write_opl_high_register OPL3_MODE_ENABLE, 1
 
        mov  si, tones_1                  ; zacatek tabulky
        call write_table_to_low_registers ; zapis obsahu tabulky do OPL3
 
        mov  si, tones_2                   ; zacatek tabulky
        call write_table_to_high_registers ; zapis obsahu tabulky do OPL3
 
        in  al, PPI_PORT_B               ; port B s rizenim zarizeni
        or  al, 0b1000000                ; nastaveni bitu cislo 7 na jednicku
        out PPI_PORT_B, al               ; zapis zpet na port B
 
.opak:
        in  al, PPI_PORT_A               ; cteni stisknute klavesy
        cmp al, KEY_ESC                  ; test na stisk ESC
        je  .exit                        ; pokud stisknuta, konec programu
 
        mov ah, al                       ; kod klavesy do registru AH pro dalsi pouziti
        mov si, key_actions              ; tabulka akci pri stisku ci uvolneni klavesy
 
.next_key:
        lodsb                            ; nacist kod klavesy z tabulky
        or  al, al                       ; test na nulu (zarazka)
        jz  .opak                        ; nic jsme jiz nenasli -> cteni klavesy pres port
 
        cmp ah, al                       ; nasli jsme kod klavesy, ktery zname?
        jne .try_next_key
        lodsb                            ; horni nebo dolni registr?
        add al, al                       ; ZF -> dolni registry, jinak horni
        lodsb                            ; adresa OPL registru
        mov ah, al
        lodsb                            ; hodnota OPL registru
        xchg ah, al                      ; vtipne jsme si prohodili parametry subrutiny write_opl_register
        jnz .high_register
        call perform_write_to_low_opl_register
        jmp .next_key                    ; zkusit dalsi klavesu
.high_register:
        call perform_write_to_high_opl_register
        jmp .next_key                    ; zkusit dalsi klavesu
.try_next_key:
        add si, 3                        ; preskocit typ a adresu registru + jeho hodnotu
        jmp .next_key
 
.exit:
        exit
 
 
write_table_to_low_registers:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_low_opl_register
        jmp  write_table_to_low_registers ; muzeme prejit na dalsi registr
 
 
write_table_to_high_registers:
        lodsb                            ; nacist bajt z tabulky (cislo registru)
        or  al, al                       ; test na nulu
        jnz .write_register
        ret                              ; dosahli jsme konce tabulky
.write_register:
        mov ah, al
        lodsb                            ; nacist dalsi bajt z tabulky (hodnota registru)
        xchg al, ah                      ; podprogram vyzaduje opacne poradi AL, AH
        call perform_write_to_high_opl_register
        jmp  write_table_to_high_registers ; muzeme prejit na dalsi registr
 
 
key_actions:
        ; prvni rada klaves
        db KEY_1,             LOW_REGISTER,  CHANNEL_1 + OPL_KEY_ON, 0b00101110
        db KEY_1+KEY_RELEASE, LOW_REGISTER,  CHANNEL_1 + OPL_KEY_ON, 0b00001110
        db KEY_2,             LOW_REGISTER,  CHANNEL_2 + OPL_KEY_ON, 0b00110001
        db KEY_2+KEY_RELEASE, LOW_REGISTER,  CHANNEL_2 + OPL_KEY_ON, 0b00010001
        db KEY_3,             LOW_REGISTER,  CHANNEL_3 + OPL_KEY_ON, 0b00110001
        db KEY_3+KEY_RELEASE, LOW_REGISTER,  CHANNEL_3 + OPL_KEY_ON, 0b00010001
        db KEY_4,             LOW_REGISTER,  CHANNEL_4 + OPL_KEY_ON, 0b00110001
        db KEY_4+KEY_RELEASE, LOW_REGISTER,  CHANNEL_4 + OPL_KEY_ON, 0b00010001
        db KEY_5,             LOW_REGISTER,  CHANNEL_5 + OPL_KEY_ON, 0b00110010
        db KEY_5+KEY_RELEASE, LOW_REGISTER,  CHANNEL_5 + OPL_KEY_ON, 0b00010010
        db KEY_6,             LOW_REGISTER,  CHANNEL_6 + OPL_KEY_ON, 0b00110010
        db KEY_6+KEY_RELEASE, LOW_REGISTER,  CHANNEL_6 + OPL_KEY_ON, 0b00010010
        db KEY_7,             LOW_REGISTER,  CHANNEL_7 + OPL_KEY_ON, 0b00110010
        db KEY_7+KEY_RELEASE, LOW_REGISTER,  CHANNEL_7 + OPL_KEY_ON, 0b00010010
        db KEY_8,             LOW_REGISTER,  CHANNEL_8 + OPL_KEY_ON, 0b00110010
        db KEY_8+KEY_RELEASE, LOW_REGISTER,  CHANNEL_8 + OPL_KEY_ON, 0b00010010
 
        ; druha rada klaves
        db KEY_Q,             HIGH_REGISTER, CHANNEL_1 + OPL_KEY_ON, 0b00101110
        db KEY_Q+KEY_RELEASE, HIGH_REGISTER, CHANNEL_1 + OPL_KEY_ON, 0b00001110
        db KEY_W,             HIGH_REGISTER, CHANNEL_2 + OPL_KEY_ON, 0b00110001
        db KEY_W+KEY_RELEASE, HIGH_REGISTER, CHANNEL_2 + OPL_KEY_ON, 0b00010001
        db KEY_E,             HIGH_REGISTER, CHANNEL_3 + OPL_KEY_ON, 0b00110001
        db KEY_E+KEY_RELEASE, HIGH_REGISTER, CHANNEL_3 + OPL_KEY_ON, 0b00010001
        db KEY_R,             HIGH_REGISTER, CHANNEL_4 + OPL_KEY_ON, 0b00110001
        db KEY_R+KEY_RELEASE, HIGH_REGISTER, CHANNEL_4 + OPL_KEY_ON, 0b00010001
        db KEY_T,             HIGH_REGISTER, CHANNEL_5 + OPL_KEY_ON, 0b00110010
        db KEY_T+KEY_RELEASE, HIGH_REGISTER, CHANNEL_5 + OPL_KEY_ON, 0b00010010
        db KEY_Y,             HIGH_REGISTER, CHANNEL_6 + OPL_KEY_ON, 0b00110010
        db KEY_Y+KEY_RELEASE, HIGH_REGISTER, CHANNEL_6 + OPL_KEY_ON, 0b00010010
        db KEY_U,             HIGH_REGISTER, CHANNEL_7 + OPL_KEY_ON, 0b00110010
        db KEY_U+KEY_RELEASE, HIGH_REGISTER, CHANNEL_7 + OPL_KEY_ON, 0b00010010
        db KEY_I,             HIGH_REGISTER, CHANNEL_8 + OPL_KEY_ON, 0b00110010
        db KEY_I+KEY_RELEASE, HIGH_REGISTER, CHANNEL_8 + OPL_KEY_ON, 0b00010010
 
        db 0, 0                                              ; zarazka
 
 
tones_1:  ; tabulka s tony pro osm kanalu
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db CHANNEL_2_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_2_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_2_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_2_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_2_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_2_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_2 + OPL_FREQUENCY_LOW,              0x81  ; frekvence zvuku (D)
 
        db CHANNEL_3_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_3_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_3_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_3_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_3_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_3_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_3 + OPL_FREQUENCY_LOW,              0xb0  ; frekvence zvuku (E)
 
        db CHANNEL_4_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_4_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_4_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_4_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_4_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_4_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_4 + OPL_FREQUENCY_LOW,              0xca  ; frekvence zvuku (F)
 
        db CHANNEL_5_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_5_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_5_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_5_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_5_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_5_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_5 + OPL_FREQUENCY_LOW,              0x02  ; frekvence zvuku (G)
 
        db CHANNEL_6_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_6_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_6_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_6_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_6_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_6_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_6 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (A)
 
        db CHANNEL_7_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_7_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_7_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_7_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_7_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_7_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_7 + OPL_FREQUENCY_LOW,              0x87  ; frekvence zvuku (B)
 
        db CHANNEL_8_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_1 + OPL_LEVEL,           0x10  ; uroven vystupu 40 dB
        db CHANNEL_8_OPERATOR_1 + OPL_ATTACK_DECAY,    0x55  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_8_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro modulator
        db CHANNEL_8_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_8_OPERATOR_2 + OPL_ATTACK_DECAY,    0xF0  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_8_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_8 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db 0, 0                                              ; zarazka
 
tones_2:  ; tabulka s tony pro osm kanalu
        db CHANNEL_1_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_1_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_1_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_1_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_1_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_1_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_1_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_1 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db CHANNEL_2_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_2_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_2_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_2_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_2_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_2_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_2_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_2 + OPL_FREQUENCY_LOW,              0x81  ; frekvence zvuku (D)
 
        db CHANNEL_3_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_3_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_3_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_3_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_3_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_3_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_3_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_3 + OPL_FREQUENCY_LOW,              0xb0  ; frekvence zvuku (E)
 
        db CHANNEL_4_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_4_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_4_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_4_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_4_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_4_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_4_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_4 + OPL_FREQUENCY_LOW,              0xca  ; frekvence zvuku (F)
 
        db CHANNEL_5_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_5_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_5_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_5_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_5_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_5_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_5_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_5 + OPL_FREQUENCY_LOW,              0x02  ; frekvence zvuku (G)
 
        db CHANNEL_6_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_6_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_6_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_6_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_6_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_6_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_6_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_6 + OPL_FREQUENCY_LOW,              0x41  ; frekvence zvuku (A)
 
        db CHANNEL_7_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_7_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_7_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_7_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_7_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_7_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_7_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_7 + OPL_FREQUENCY_LOW,              0x87  ; frekvence zvuku (B)
 
        db CHANNEL_8_OPERATOR_1 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni modulatoru: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_1 + OPL_LEVEL,           0x00  ; uroven vystupu 40 dB
        db CHANNEL_8_OPERATOR_1 + OPL_ATTACK_DECAY,    0x41  ; modulator: rychly nastup zvuku + pomale doznivani
        db CHANNEL_8_OPERATOR_1 + OPL_SUSTAIN_RELEASE, 0x7f  ; urovne sustain a release pro modulator
        db CHANNEL_8_OPERATOR_2 + OPL_AMP_VIBRATO_EG,  0x01  ; nastaveni nosne: nasobeni frekvence jednickou
        db CHANNEL_8_OPERATOR_2 + OPL_LEVEL,           0x00  ; nastaveni urovne vystupu nosne na 47 dB
        db CHANNEL_8_OPERATOR_2 + OPL_ATTACK_DECAY,    0xa2  ; nosna: rychly nastup + pomale doznivani
        db CHANNEL_8_OPERATOR_2 + OPL_SUSTAIN_RELEASE, 0x77  ; urovne sustain a release pro nosnou
        db CHANNEL_8 + OPL_FREQUENCY_LOW,              0xae  ; frekvence zvuku (C)
 
        db 0, 0                                              ; zarazka
 
 
perform_write_to_low_opl_register:
        ; zapis do vybraneho registru OPL3
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        mov al, ah            ; zapis hodnoty do vybraneho registru
        mov dx, OPL_DATA
        out dx, al
 
        ret
 
 
perform_write_to_high_opl_register:
        ; zapis do vybraneho "vyssiho" registru OPL3
        ; AL - registr
        ; AH - hodnota
        mov dx, OPL_HIGH_ADDRESS   ; vyber registru pro modifikaci
        out dx, al
 
        mov al, ah                 ; zapis hodnoty do vybraneho registru
        mov dx, OPL_HIGH_DATA
        out dx, al
 
        ret

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

Demonstrační příklady napsané v assembleru, které jsou určené pro překlad s využitím assembleru NASM, byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Jednotlivé demonstrační 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 hello.asm program typu „Hello world“ naprogramovaný v assembleru pro systém DOS https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello.asm
2 hello_shorter.asm kratší varianta výskoku z procesu zpět do DOSu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_shorter.asm
3 hello_wait.asm čekání na stisk klávesy https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_wait.asm
4 hello_macros.asm realizace jednotlivých částí programu makrem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_macros.asm
       
5 gfx4_putpixel.asm vykreslení pixelu v grafickém režimu 4 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_putpixel.asm
6 gfx6_putpixel.asm vykreslení pixelu v grafickém režimu 6 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel.asm
7 gfx4_line.asm vykreslení úsečky v grafickém režimu 4 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_line.asm
8 gfx6_line.asm vykreslení úsečky v grafickém režimu 6 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_line.asm
       
9 gfx6_fill1.asm vyplnění obrazovky v grafickém režimu, základní varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill1.asm
10 gfx6_fill2.asm vyplnění obrazovky v grafickém režimu, varianta s instrukcí LOOP https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill2.asm
11 gfx6_fill3.asm vyplnění obrazovky instrukcí REP STOSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill3.asm
12 gfx6_fill4.asm vyplnění obrazovky, synchronizace vykreslování s paprskem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill4.asm
       
13 gfx4_image1.asm vykreslení rastrového obrázku získaného z binárních dat, základní varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image1.asm
14 gfx4_image2.asm varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image2.asm
15 gfx4_image3.asm varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSW https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image3.asm
16 gfx4_image4.asm korektní vykreslení všech sudých řádků bitmapy https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image4.asm
17 gfx4_image5.asm korektní vykreslení všech sudých i lichých řádků bitmapy https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image5.asm
       
18 gfx4_image6.asm nastavení barvové palety před vykreslením obrázku https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image6.asm
19 gfx4_image7.asm nastavení barvové palety před vykreslením obrázku, snížená intenzita barev https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image7.asm
20 gfx4_image8.asm postupná změna barvy pozadí https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image8.asm
       
21 gfx6_putpixel1.asm vykreslení pixelu, základní varianta se 16bitovým násobením https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel1.asm
22 gfx6_putpixel2.asm vykreslení pixelu, varianta s osmibitovým násobením https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel2.asm
23 gfx6_putpixel3.asm vykreslení pixelu, varianta bez násobení https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel3.asm
24 gfx6_putpixel4.asm vykreslení pixelu přes obrázek, nekorektní chování (přepis obrázku) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel4.asm
25 gfx6_putpixel5.asm vykreslení pixelu přes obrázek, korektní varianta pro bílé pixely https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel5.asm
       
26 cga_text_mode1.asm standardní textový režim s rozlišením 40×25 znaků https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode1.asm
27 cga_text_mode3.asm standardní textový režim s rozlišením 80×25 znaků https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode3.asm
28 cga_text_mode_intensity.asm změna významu nejvyššího bitu atributového bajtu: vyšší intenzita namísto blikání https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_intensity.asm
29 cga_text_mode_cursor.asm změna tvaru textového kurzoru https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_cursor.asm
30 cga_text_gfx1.asm zobrazení „rastrové mřížky“: pseudografický režim 160×25 pixelů (interně textový režim) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_gfx1.asm
31 cga_text_mode_char_height.asm změna výšky znaků https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_char_height.asm
32 cga_text_160×100.asm grafický režim 160×100 se šestnácti barvami (interně upravený textový režim) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_160×100.asm
       
33 hercules_text_mode1.asm využití standardního textového režimu společně s kartou Hercules https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode1.asm
34 hercules_text_mode2.asm zákaz blikání v textových režimech https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode2.asm
35 hercules_turn_off.asm vypnutí generování video signálu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_turn_off.asm
36 hercules_gfx_mode1.asm přepnutí karty Hercules do grafického režimu (základní varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode1.asm
37 hercules_gfx_mode2.asm přepnutí karty Hercules do grafického režimu (vylepšená varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode2.asm
38 hercules_putpixel.asm subrutina pro vykreslení jediného pixelu na kartě Hercules https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_putpixel.asm
       
39 ega_text_mode_80×25.asm standardní textový režim 80×25 znaků na kartě EGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×25.asm
40 ega_text_mode_80×43.asm zobrazení 43 textových řádků na kartě EGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×43.asm
41 ega_gfx_mode_320×200.asm přepnutí do grafického režimu 320×200 pixelů se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_320×200.asm
42 ega_gfx_mode_640×200.asm přepnutí do grafického režimu 640×200 pixelů se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×200.asm
43 ega_gfx_mode_640×350.asm přepnutí do grafického režimu 640×350 pixelů se čtyřmi nebo šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×350.asm
44 ega_gfx_mode_bitplanes1.asm ovládání zápisu do bitových rovin v planárních grafických režimech (základní způsob) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes1.asm
45 ega_gfx_mode_bitplanes2.asm ovládání zápisu do bitových rovin v planárních grafických režimech (rychlejší způsob) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes2.asm
       
46 ega_320×200_putpixel.asm vykreslení pixelu v grafickém režimu 320×200 pixelů se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_320×200_putpixel.asm
47 ega_640×350_putpixel.asm vykreslení pixelu v grafickém režimu 640×350 pixelů se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_640×350_putpixel.asm
       
48 ega_standard_font.asm použití standardního fontu grafické karty EGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_standard_font.asm
49 ega_custom_font.asm načtení vlastního fontu s jeho zobrazením https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_custom_font.asm
       
50 ega_palette1.asm změna barvové palety (všech 16 barev) v grafickém režimu 320×200 se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette1.asm
51 ega_palette2.asm změna barvové palety (všech 16 barev) v grafickém režimu 640×350 se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette2.asm
52 ega_palette3.asm změna všech barev v barvové paletě s využitím programové smyčky https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette3.asm
53 ega_palette4.asm změna všech barev, včetně barvy okraje, v barvové paletě voláním funkce BIOSu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette4.asm
       
54 vga_text_mode_80×25.asm standardní textový režim 80×25 znaků na kartě VGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_80×25.asm
55 vga_text_mode_80×50.asm zobrazení 50 a taktéž 28 textových řádků na kartě VGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_80×50.asm
56 vga_text_mode_intensity1.asm změna chování atributového bitu pro blikání (nebezpečná varianta změny registrů) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_intensity1.asm
57 vga_text_mode_intensity2.asm změna chování atributového bitu pro blikání (bezpečnější varianta změny registrů) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_intensity2.asm
58 vga_text_mode_9th_column.asm modifikace způsobu zobrazení devátého sloupce ve znakových režimech (720 pixelů na řádku) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_9th_column.asm
59 vga_text_mode_cursor_shape.asm změna tvaru textového kurzoru na grafické kartě VGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_cursor_shape.asm
60 vga_text_mode_custom_font.asm načtení vlastního fontu s jeho zobrazením https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_custom_font.asm
       
61 vga_gfx_mode_640×480.asm přepnutí do grafického režimu 640×480 pixelů se šestnácti barvami, vykreslení vzorků https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_640×480.asm
62 vga_gfx_mode_320×200.asm přepnutí do grafického režimu 320×200 pixelů s 256 barvami, vykreslení vzorků https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_320×200.asm
63 vga_gfx_mode_palette.asm změna všech barev v barvové paletě grafické karty VGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_palette.asm
64 vga_gfx_mode_dac1.asm využití DAC (neočekávané výsledky) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac1.asm
65 vga_gfx_mode_dac2.asm využití DAC (očekávané výsledky) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac2.asm
       
66 vga_640×480_putpixel.asm realizace algoritmu pro vykreslení pixelu v grafickém režimu 640×480 pixelů se šestnácti barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_640×480_putpixel.asm
67 vga_320×200_putpixel1.asm realizace algoritmu pro vykreslení pixelu v grafickém režimu 320×200 s 256 barvami (základní varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_putpixel1.asm
68 vga_320×200_putpixel2.asm realizace algoritmu pro vykreslení pixelu v grafickém režimu 320×200 s 256 barvami (rychlejší varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_putpixel2.asm
       
69 vga_gfx_mode_dac3.asm přímé využití DAC v grafickém režimu 13h https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac3.asm
       
70 vga_gfx_mode_unchained_step1.asm zobrazení barevných pruhů v režimu 13h https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step1.asm
71 vga_gfx_mode_unchained_step2.asm vypnutí zřetězení bitových rovin a změna způsobu adresování pixelů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step2.asm
72 vga_gfx_mode_unchained_step3.asm vykreslení barevných pruhů do vybraných bitových rovin https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step3.asm
       
73 vga_gfx_mode_320×400.asm nestandardní grafický režim s rozlišením 320×400 pixelů a 256 barvami https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_320×400.asm
74 vga_320×200_image.asm zobrazení rastrového obrázku ve standardním grafickém režimu 320×200 pixelů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image.asm
75 vga_320×200_unchained_image1.asm zobrazení rastrového obrázku v režimu s nezřetězenými rovinami (nekorektní řešení) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_unchained_image1.asm
76 vga_320×200_unchained_image2.asm zobrazení rastrového obrázku v režimu s nezřetězenými rovinami (korektní řešení) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_unchained_image2.asm
77 vga_320×400_unchained_image.asm zobrazení rastrového obrázku v nestandardním režimu 320×400 pixelů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_unchained_image.asm
       
78 vga_vertical_scroll1.asm vertikální scrolling na kartě VGA v režimu s rozlišením 320×200 pixelů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_vertical_scroll1.asm
79 vga_vertical_scroll2.asm vertikální scrolling na kartě VGA v režimu s rozlišením 320×400 pixelů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_vertical_scroll2.asm
80 vga_split_screen1.asm režim split-screen a scrolling, nefunční varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_split_screen1.asm
81 vga_split_screen2.asm režim split-screen a scrolling, plně funkční varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_split_screen2.asm
82 vga_horizontal_scroll1.asm horizontální scrolling bez rozšíření počtu pixelů na virtuálním řádku https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll1.asm
83 vga_horizontal_scroll2.asm horizontální scrolling s rozšířením počtu pixelů na virtuálním řádku https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll2.asm
84 vga_horizontal_scroll3.asm jemný horizontální scrolling s rozšířením počtu pixelů na virtuálním řádku https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll3.asm
       
85 vga_320×240_image.asm nastavení grafického režimu Mode-X, načtení a vykreslení obrázku, scrolling https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×240_image.asm
       
86 io.asm knihovna maker pro I/O operace https://github.com/tisnik/8bit-fame/blob/master/pc-dos/io.asm
87 vga_lib.asm knihovna maker a podprogramů pro programování karty VGA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_lib.asm
88 vga_320×240_lib.asm nastavení grafického režimu Mode-X, tentokrát knihovními funkcemi https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×240_lib.asm
       
89 vga_bitblt1.asm první (naivní) implementace operace BitBLT https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt1.asm
90 vga_bitblt2.asm operace BitBLT s výběrem bitových rovin pro zápis https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt2.asm
91 vga_bitblt3.asm operace BitBLT s výběrem bitových rovin pro čtení i zápis https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt3.asm
92 vga_bitblt4.asm korektní BitBLT pro 16barevný režim, realizace makry https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt4.asm
93 vga_bitblt5.asm korektní BitBLT pro 16barevný režim, realizace podprogramem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt5.asm
       
94 vga_bitblt_rotate.asm zápisový režim s rotací bajtu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt_rotate.asm
95 vga_bitblt_fast.asm rychlá korektní 32bitová operace typu BitBLT https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt_fast.asm
96 vga_320×400_bitblt1.asm přenos obrázku v režimu 320×400 operací BitBLT (neúplná varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_bitblt1.asm
97 vga_320×400_bitblt2.asm přenos obrázku v režimu 320×400 operací BitBLT (úplná varianta) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_bitblt2.asm
98 vga_write_modes1.asm volitelné zápisové režimy grafické karty VGA, zápis bez úpravy latche https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes1.asm
99 vga_write_modes2.asm volitelné zápisové režimy grafické karty VGA, zápis s modifikací latche https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes2.asm
100 vga_write_modes3.asm volitelné zápisové režimy grafické karty VGA, cílená modifikace latche vzorkem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes3.asm
       
101 instruction_jump.asm použití instrukce JMP https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jump.asm
102 instruction_jnz.asm použití instrukce JNZ pro realizaci programové smyčky https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jnz.asm
103 instruction_jz_jmp.asm použití instrukcí JZ a JMP pro realizaci programové smyčky https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jz_jmp.asm
104 instruction_loop.asm použití instrukce LOOP pro realizaci programové smyčky https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_loop.asm
       
105 instruction_template.asm šablona všech následujících demonstračních příkladů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_template.asm
106 instruction_print_hex.asm tisk osmibitové hexadecimální hodnoty https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_print_hex.asm
107 instruction_xlat.asm využití instrukce XLAT pro získání tisknutelné hexadecimální cifry https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_xlat.asm
       
108 instruction_daa.asm operace součtu s využitím binární i BCD aritmetiky https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_daa.asm
109 instruction_daa_sub.asm instrukce DAA po provedení operace rozdílu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_daa_sub.asm
110 instruction_das.asm instrukce DAS po provedení operace rozdílu https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_das.asm
111 instruction_aaa.asm korekce výsledku na jedinou BCD cifru operací AAA https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_aaa.asm
112 instruction_mul.asm ukázka výpočtu součinu dvou osmibitových hodnot https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_mul.asm
113 instruction_aam.asm BCD korekce po výpočtu součinu instrukcí AAM https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_aam.asm
       
114 instruction_stosb.asm blokový zápis dat instrukcí STOSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_stosb.asm
115 instruction_rep_stosb.asm opakované provádění instrukce STOSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_rep_stosb.asm
116 instruction_lodsb.asm čtení dat instrukcí LODSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_lodsb.asm
117 instruction_movsb.asm přenos jednoho bajtu instrukcí MOVSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_movsb.asm
118 instruction_rep_movsb.asm blokový přenos po bajtech instrukcí MOVSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_rep_movsb.asm
119 instruction_rep_scas.asm vyhledávání v řetězci instrukcí SCAS https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_rep_scas.asm
       
120 vga_320×200_image_0B.asm výsledek blokového přenosu ve chvíli, kdy je CX=0 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_0B.asm
121 vga_320×200_image_64kB.asm výsledek blokového přenosu ve chvíli, kdy je CX=0×ffff https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_64kB.asm
122 vga_320×200_image_movsb.asm blokový přenos v rámci obrazové paměti instrukcí REP MOVSB https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_movsb.asm
123 vga_320×200_image_movsw.asm blokový přenos v rámci obrazové paměti instrukcí REP MOVSW https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_movsw.asm
124 vga_320×200_image_movsd.asm blokový přenos v rámci obrazové paměti instrukcí REP MOVSD https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_movsd.asm
125 vga_320×200_image_movsb_forward.asm blokový přenos překrývajících se bloků paměti (zvyšující se adresy) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_mov­sb_forward.asm
126 vga_320×200_image_movsb_backward1.asm blokový přenos překrývajících se bloků paměti (snižující se adresy, nekorektní nastavení) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_mov­sb_backward1.asm
127 vga_320×200_image_movsb_backward2.asm blokový přenos překrývajících se bloků paměti (snižující se adresy, korektní nastavení) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image_mov­sb_backward2.asm
       
128 sound_bell.asm přehrání zvuku pomocí tisku ASCII znaku BELL https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_bell.asm
129 sound_beep.asm přehrání zvuku o zadané frekvenci na PC Speakeru https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_beep.asm
130 sound_play_pitch.asm přehrání zvuku o zadané frekvenci na PC Speakeru, použití maker https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_play_pitch.asm
       
131 sound_opl2_basic.asm přehrání komorního A na OPL2 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl2_basic.asm
132 sound_opl2_table.asm přehrání komorního A na OPL2, použití tabulky s hodnotami registrů https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl2_table.asm
       
133 sound_opl2_table2.asm přepis tabulky s obsahy registrů pro přehrání komorního A https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl2_table2.asm
134 sound_key_on.asm přímé ovládání bitu KEY ON mezerníkem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_key_on.asm
135 sound_adsr.asm nastavení obálky pro tón přehrávaný prvním kanálem https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_adsr.asm
136 sound_modulation.asm řízení frekvence modulátoru klávesami 1 a 0 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_modulation.asm
       
137 keyboard_basic.asm přímá práce s klávesnicí IBM PC https://github.com/tisnik/8bit-fame/blob/master/pc-dos/keyboard_basic.asm
       
138 sound_stereo_opl2.asm stereo zvuk v konfiguraci DualOPL2 https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_stereo_opl2.asm
139 sound_opl2_multichannel.asm vícekanálový zvuk na OPL2 (klávesy), delší varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl2_multichannel.asm
140 sound_opl2_multichannel2.asm vícekanálový zvuk na OPL2 (klávesy), kratší varianta https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl2_multichannel2.asm
141 sound_opl3_stereo1.asm stereo výstup na OPL3 (v kompatibilním režimu) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl3_stereo1.asm
142 sound_opl3_stereo2.asm stereo výstup na OPL3 (v režimu OPL3) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl3_stereo2.asm
143 sound_opl3_multichannel.asm vícekanálový zvuk na OPL3 (klávesy) https://github.com/tisnik/8bit-fame/blob/master/pc-dos/sound_opl3_multichannel.asm

20. Odkazy na Internetu

  1. The Intel 8088 Architecture and Instruction Set
    https://people.ece.ubc.ca/~ed­c/464/lectures/lec4.pdf
  2. x86 Opcode Structure and Instruction Overview
    https://pnx.tf/files/x86_op­code_structure_and_instruc­tion_overview.pdf
  3. x86 instruction listings (Wikipedia)
    https://en.wikipedia.org/wi­ki/X86_instruction_listin­gs
  4. x86 assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/X86_assembly_language
  5. Intel Assembler (Cheat sheet)
    http://www.jegerlehner.ch/in­tel/IntelCodeTable.pdf
  6. 25 Microchips That Shook the World
    https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world
  7. Chip Hall of Fame: MOS Technology 6502 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor
  8. Chip Hall of Fame: Intel 8088 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-intel-8088-microprocessor
  9. Jak se zrodil procesor?
    https://www.root.cz/clanky/jak-se-zrodil-procesor/
  10. Apple II History Home
    http://apple2history.org/
  11. The 8086/8088 Primer
    https://www.stevemorse.or­g/8086/index.html
  12. flat assembler: Assembly language resources
    https://flatassembler.net/
  13. FASM na Wikipedii
    https://en.wikipedia.org/wiki/FASM
  14. Fresh IDE FASM inside
    https://fresh.flatassembler.net/
  15. MS-DOS Version 4.0 Programmer's Reference
    https://www.pcjs.org/docu­ments/books/mspl13/msdos/dos­ref40/
  16. INT 21 – DOS Function Dispatcher (DOS)
    https://www.stanislavs.or­g/helppc/int21.html
  17. DOS API (Wikipedia)
    https://en.wikipedia.org/wiki/DOS_API
  18. Bit banging
    https://en.wikipedia.org/wi­ki/Bit_banging
  19. IBM Basic assembly language and successors (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Basic_assembly_lan­guage_and_successors
  20. X86 Assembly/Bootloaders
    https://en.wikibooks.org/wi­ki/X86_Assembly/Bootloaders
  21. Počátky grafiky na PC: grafické karty CGA a Hercules
    https://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/
  22. Co mají společného Commodore PET/4000, BBC Micro, Amstrad CPC i grafické karty MDA, CGA a Hercules?
    https://www.root.cz/clanky/co-maji-spolecneho-commodore-pet-4000-bbc-micro-amstrad-cpc-i-graficke-karty-mda-cga-a-hercules/
  23. Karta EGA: první použitelná barevná grafika na PC
    https://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/
  24. RGB Classic Games
    https://www.classicdosgames.com/
  25. Turbo Assembler (Wikipedia)
    https://en.wikipedia.org/wi­ki/Turbo_Assembler
  26. Microsoft Macro Assembler
    https://en.wikipedia.org/wi­ki/Microsoft_Macro_Assembler
  27. IBM Personal Computer (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Personal_Computer
  28. Intel 8251
    https://en.wikipedia.org/wi­ki/Intel_8251
  29. Intel 8253
    https://en.wikipedia.org/wi­ki/Intel_8253
  30. Intel 8255
    https://en.wikipedia.org/wi­ki/Intel_8255
  31. Intel 8257
    https://en.wikipedia.org/wi­ki/Intel_8257
  32. Intel 8259
    https://en.wikipedia.org/wi­ki/Intel_8259
  33. Support/peripheral/other chips – 6800 family
    http://www.cpu-world.com/Support/6800.html
  34. Motorola 6845
    http://en.wikipedia.org/wi­ki/Motorola_6845
  35. The 6845 Cathode Ray Tube Controller (CRTC)
    http://www.tinyvga.com/6845
  36. CRTC operation
    http://www.6502.org/users/an­dre/hwinfo/crtc/crtc.html
  37. 6845 – Motorola CRT Controller
    https://stanislavs.org/hel­ppc/6845.html
  38. The 6845 Cathode Ray Tube Controller (CRTC)
    http://www.tinyvga.com/6845
  39. Motorola 6845 and bitwise graphics
    https://retrocomputing.stac­kexchange.com/questions/10996/mo­torola-6845-and-bitwise-graphics
  40. IBM Monochrome Display Adapter
    http://en.wikipedia.org/wi­ki/Monochrome_Display_Adap­ter
  41. Color Graphics Adapter
    http://en.wikipedia.org/wi­ki/Color_Graphics_Adapter
  42. Color Graphics Adapter and the Brown color in IBM 5153 Color Display
    https://www.aceinnova.com/en/e­lectronics/cga-and-the-brown-color-in-ibm-5153-color-display/
  43. The Modern Retrocomputer: An Arduino Driven 6845 CRT Controller
    https://hackaday.com/2017/05/14/the-modern-retrocomputer-an-arduino-driven-6845-crt-controller/
  44. flat assembler: Assembly language resources
    https://flatassembler.net/
  45. FASM na Wikipedii
    https://en.wikipedia.org/wiki/FASM
  46. Fresh IDE FASM inside
    https://fresh.flatassembler.net/
  47. MS-DOS Version 4.0 Programmer's Reference
    https://www.pcjs.org/docu­ments/books/mspl13/msdos/dos­ref40/
  48. INT 21 – DOS Function Dispatcher (DOS)
    https://www.stanislavs.or­g/helppc/int21.html
  49. DOS API (Wikipedia)
    https://en.wikipedia.org/wiki/DOS_API
  50. IBM Basic assembly language and successors (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Basic_assembly_lan­guage_and_successors
  51. X86 Assembly/Arithmetic
    https://en.wikibooks.org/wi­ki/X86_Assembly/Arithmetic
  52. Art of Assembly – Arithmetic Instructions
    http://oopweb.com/Assembly/Do­cuments/ArtOfAssembly/Volu­me/Chapter6/CH06–2.html
  53. ASM Flags
    http://www.cavestory.org/gu­ides/csasm/guide/asm_flag­s.html
  54. Status Register
    https://en.wikipedia.org/wi­ki/Status_register
  55. Linux assemblers: A comparison of GAS and NASM
    http://www.ibm.com/develo­perworks/library/l-gas-nasm/index.html
  56. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  57. Is it worthwhile to learn x86 assembly language today?
    https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1
  58. Why Learn Assembly Language?
    http://www.codeproject.com/Ar­ticles/89460/Why-Learn-Assembly-Language
  59. Is Assembly still relevant?
    http://programmers.stackex­change.com/questions/95836/is-assembly-still-relevant
  60. Why Learning Assembly Language Is Still a Good Idea
    http://www.onlamp.com/pub/a/on­lamp/2004/05/06/writegreat­code.html
  61. Assembly language today
    http://beust.com/weblog/2004/06/23/as­sembly-language-today/
  62. Assembler: Význam assembleru dnes
    http://www.builder.cz/rubri­ky/assembler/vyznam-assembleru-dnes-155960cz
  63. Programming from the Ground Up Book – Summary
    http://savannah.nongnu.or­g/projects/pgubook/
  64. DOSBox
    https://www.dosbox.com/
  65. The C Programming Language
    https://en.wikipedia.org/wi­ki/The_C_Programming_Langu­age
  66. Hercules Graphics Card (HCG)
    https://en.wikipedia.org/wi­ki/Hercules_Graphics_Card
  67. Complete 8086 instruction set
    https://content.ctcd.edu/cou­rses/cosc2325/m22/docs/emu8086in­s.pdf
  68. Complete 8086 instruction set
    https://yassinebridi.github.io/asm-docs/8086_instruction_set.html
  69. 8088 MPH by Hornet + CRTC + DESiRE (final version)
    https://www.youtube.com/wat­ch?v=hNRO7lno_DM
  70. Area 5150 by CRTC & Hornet (Party Version) / IBM PC+CGA Demo, Hardware Capture
    https://www.youtube.com/wat­ch?v=fWDxdoRTZPc
  71. 80×86 Integer Instruction Set Timings (8088 – Pentium)
    http://aturing.umcs.maine­.edu/~meadow/courses/cos335/80×86-Integer-Instruction-Set-Clocks.pdf
  72. Colour Graphics Adapter: Notes
    https://www.seasip.info/Vin­tagePC/cga.html
  73. Restoring A Vintage CGA Card With Homebrew HASL
    https://hackaday.com/2024/06/12/res­toring-a-vintage-cga-card-with-homebrew-hasl/
  74. Demoing An 8088
    https://hackaday.com/2015/04/10/de­moing-an-8088/
  75. Video Memory Layouts
    http://www.techhelpmanual.com/89-video_memory_layouts.html
  76. Screen Attributes
    http://www.techhelpmanual.com/87-screen_attributes.html
  77. IBM PC Family – BIOS Video Modes
    https://www.minuszerodegre­es.net/video/bios_video_mo­des.htm
  78. EGA Functions
    https://cosmodoc.org/topics/ega-functions/#the-hierarchy-of-the-ega
  79. Why the EGA can only use 16 of its 64 colours in 200-line modes
    https://www.reenigne.org/blog/why-the-ega-can-only-use-16-of-its-64-colours-in-200-line-modes/
  80. How 16 colors saved PC gaming – the story of EGA graphics
    https://www.custompc.com/retro-tech/ega-graphics
  81. List of 16-bit computer color palettes
    https://en.wikipedia.org/wi­ki/List_of16-bit_computer_color_palettes
  82. Why were those colors chosen to be the default palette for 256-color VGA?
    https://retrocomputing.stac­kexchange.com/questions/27994/why-were-those-colors-chosen-to-be-the-default-palette-for-256-color-vga
  83. VGA Color Palettes
    https://www.fountainware.com/EX­PL/vga_color_palettes.htm
  84. Hardware Level VGA and SVGA Video Programming Information Page
    http://www.osdever.net/Fre­eVGA/vga/vga.htm
  85. Hardware Level VGA and SVGA Video Programming Information Page – sequencer
    http://www.osdever.net/Fre­eVGA/vga/seqreg.htm
  86. VGA Basics
    http://www.brackeen.com/vga/ba­sics.html
  87. Introduction to VGA Mode ‚X‘
    https://web.archive.org/web/20160414072210/htt­p://fly.srk.fer.hr/GDM/ar­ticles/vgamodex/vgamx1.html
  88. VGA Mode-X
    https://web.archive.org/web/20070123192523/htt­p://www.gamedev.net/referen­ce/articles/article356.asp
  89. Mode-X: 256-Color VGA Magic
    https://downloads.gamedev­.net/pdf/gpbb/gpbb47.pdf
  90. Instruction Format in 8086 Microprocessor
    https://www.includehelp.com/embedded-system/instruction-format-in-8086-microprocessor.aspx
  91. How to use „AND,“ „OR,“ and „XOR“ modes for VGA Drawing
    https://retrocomputing.stac­kexchange.com/questions/21936/how-to-use-and-or-and-xor-modes-for-vga-drawing
  92. VGA Hardware
    https://wiki.osdev.org/VGA_Hardware
  93. Programmer's Guide to Yamaha YMF 262/OPL3 FM Music Synthesizer
    https://moddingwiki.shika­di.net/wiki/OPL_chip
  94. Does anybody understand how OPL2 percussion mode works?
    https://forum.vcfed.org/in­dex.php?threads/does-anybody-understand-how-opl2-percussion-mode-works.60925/
  95. Yamaha YMF262 OPL3 music – MoonDriver for OPL3 DEMO [Oscilloscope View]
    https://www.youtube.com/watch?v=a7I-QmrkAak
  96. Yamaha OPL vs OPL2 vs OPL3 comparison
    https://www.youtube.com/wat­ch?v=5knetge5Gs0
  97. OPL3 Music Crockett's Theme
    https://www.youtube.com/wat­ch?v=HXS008pkgSQ
  98. Bad Apple (Adlib Tracker – OPL3)
    https://www.youtube.com/wat­ch?v=2lEPH6Y3Luo
  99. FM Synthesis Chips, Codecs and DACs
    https://www.dosdays.co.uk/to­pics/fm_synthesizers.php
  100. The Zen Challenge – YMF262 OPL3 Original (For an upcoming game)
    https://www.youtube.com/wat­ch?v=6JlFIFz1CFY
  101. [adlib tracker II techno music – opl3] orbit around alpha andromedae I
    https://www.youtube.com/wat­ch?v=YqxJCu_WFuA
  102. [adlib tracker 2 music – opl3 techno] hybridisation process on procyon-ii
    https://www.youtube.com/wat­ch?v=daSV5mN0sJ4
  103. Hyper Duel – Black Rain (YMF262 OPL3 Cover)
    https://www.youtube.com/wat­ch?v=pu_mzRRq8Ho
  104. IBM 5155–5160 Technical Reference
    https://www.minuszerodegre­es.net/manuals/IBM/IBM_5155_5160_Techni­cal_Reference_6280089_MAR86­.pdf
  105. a ymf262/opl3+pc speaker thing i made
    https://www.youtube.com/watch?v=E-Mx0lEmnZ0
  106. [OPL3] Like a Thunder
    https://www.youtube.com/wat­ch?v=MHf06AGr8SU
  107. (PC SPEAKER) bad apple
    https://www.youtube.com/wat­ch?v=LezmKIIHyUg
  108. Powering devices from PC parallel port
    http://www.epanorama.net/cir­cuits/lptpower.html
  109. Magic Mushroom (demo pro PC s DOSem)
    http://www.crossfire-designs.de/download/articles/sou­ndcards//mushroom.rar
  110. Píseň Magic Mushroom – originál
    http://www.crossfire-designs.de/download/articles/sou­ndcards/speaker_mushroom_con­verted.mp3
  111. Píseň Magic Mushroom – hráno na PC Speakeru
    http://www.crossfire-designs.de/download/articles/sou­ndcards/speaker_mushroom_spe­aker.mp3
  112. Pulse Width Modulation (PWM) Simulation Example
    http://decibel.ni.com/content/docs/DOC-4599
  113. Resistor/Pulse Width Modulation DAC
    http://www.k9spud.com/trax­mod/pwmdac.php
  114. Class D Amplifier
    http://en.wikipedia.org/wi­ki/Electronic_amplifier#Clas­s_D
  115. Covox Speech Thing / Disney Sound Source (1986)
    http://www.crossfire-designs.de/index.php?lang=en&what=ar­ticles&name=showarticle.htm&ar­ticle=soundcards/&page=5
  116. Covox Digital-Analog Converter (Rusky, obsahuje schémata)
    http://phantom.sannata.ru/kon­kurs/netskater002.shtml
  117. PC-GPE on the Web
    http://bespin.org/~qz/pc-gpe/
  118. Keyboard Synthesizer
    http://www.solarnavigator­.net/music/instruments/ke­yboards.htm
  119. FMS – Fully Modular Synthesizer
    http://fmsynth.sourceforge.net/
  120. Javasynth
    http://javasynth.sourceforge.net/
  121. Software Sound Synthesis & Music Composition Packages
    http://www.linux-sound.org/swss.html
  122. Mx44.1 Download Page (software synthesizer for linux)
    http://hem.passagen.se/ja_linux/
  123. Software synthesizer
    http://en.wikipedia.org/wi­ki/Software_synthesizer
  124. Frequency modulation synthesis
    http://en.wikipedia.org/wi­ki/Frequency_modulation_syn­thesis
  125. Yamaha DX7
    http://en.wikipedia.org/wi­ki/Yamaha_DX7
  126. Wave of the Future
    http://www.wired.com/wired/ar­chive/2.03/waveguides_pr.html
  127. Analog synthesizer
    http://en.wikipedia.org/wi­ki/Analog_synthesizer
  128. Minimoog
    http://en.wikipedia.org/wiki/Minimoog
  129. Moog synthesizer
    http://en.wikipedia.org/wi­ki/Moog_synthesizer
  130. Tutorial for Frequency Modulation Synthesis
    http://www.sfu.ca/~truax/fmtut.html
  131. An Introduction To FM
    http://ccrma.stanford.edu/sof­tware/snd/snd/fm.html
  132. John Chowning
    http://en.wikipedia.org/wi­ki/John_Chowning
  133. I'm Impressed, Adlib Music is AMAZING!
    https://www.youtube.com/wat­ch?v=PJNjQYp1ras
  134. Milinda- Diode Milliampere ( OPL3 )
    https://www.youtube.com/wat­ch?v=oNhazT5HG0E
ikonka

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.