motto: „Víš, že jsme založili kvarteto? Kdo? No přece my tři. Kdo my tři? No já a brácha. Ty máš bráchu? Ne, a proč?“
Tak takhle ne. Budeme opravdu přehrávat čtyři hlasy na jednom jednobitovém výstupu. U mikropočítače PMD-85 se jedná konkrétně o bit PC2 „služebního“ PPI typu MHB8255A.
Dlouho jsem se trápil s variantou se čtyřnásobným převzorkováním a vyčleněním časových slotů pro čtyři původní zvukové kanály. Bylo to super, umělo to pracovat s energií jednotlivých zvukových kanálů (bylo možno simulovat čtyři hladiny hluku, linoucí se z PMD-85) a .. to bylo vlastně vše. Procedura byla extrémně dlouhá, silně závislá na synchronizaci se vzorkováním zvukové karty při běhu v emulátoru, a hlavně – hlavně produkovala parazitní frekvence.
Na Foreveru 2019 mi Busy (https://busy.speccy.cz) poradil, abych použil řešení s mísením zvukových kanálů prostou funkcí OR a doporučil mi rutinu Jána Deáka s názvem ZX10. Osmibitové dělicí konstanty jsem nahradil 16-bitovou přímou digitální syntézou (DDS) a výsledek je dalším evolučním krokem v generování vícehlasé hudby na PMD-85. Rutinu lze beze změny funkčnosti expandovat teoreticky až na 127-hlasovou polyfonii, ovšem frekvenční rastr bude už asi dosti hrubý. Při zvětšení počtu přehrávaných hlasů bude vždy nutno přepočítat generující konstanty tónů a vhodně posunout pozici bitu, budicího reproduktor (to je ta zablokovaná instrukce RAR). Rutina nemá na rozdíl od ZX10 sofistikovaný předkousávač datového toku not, prostě bere, co jí dáte, a to přehraje.
Samotné jádro přehrávače vypadá takto:
; ***************************************** ; procedura generování čtyř souběžných tónů ; ***************************************** sound: push b ; uschovat ukazatel do notového zápisu soundL: xra a ; příprava funkce OR pro slučování soundA: lxi b,0 ; #1 konstanta výšky tónu lxi h,0 ; akumulátor DDS generátoru dad b ; vlastní DDS syntéza shld soundA+4 ; uložit výsledek sbi 0 ; CY = výstup frekvence syntezátoru ; (přetečení nahodí A := 11111111) soundB: lxi b,0 ; #2 konstanta výšky tónu lxi h,0 ; akumulátor DDS generátoru dad b ; vlastní DDS syntéza shld soundB+4 ; uložit výsledek sbi 0 ; CY = výstup frekvence syntezátoru ; (přetečení nahodí A := 1111111x) soundC: lxi b,0 ; #3 konstanta výšky tónu lxi h,0 ; akumulátor DDS generátoru dad b ; vlastní DDS syntéza shld soundC+4 ; uložit výsledek sbi 0 ; CY = výstup frekvence syntezátoru ; (přetečení nahodí A := 111111xx) soundD: lxi b,0 ; #4 konstanta výšky tónu lxi h,0 ; akumulátor DDS generátoru dad b ; vlastní DDS syntéza shld soundD+4 ; uložit výsledek sbi 0 ; CY = výstup frekvence syntezátoru ; (přetečení nahodí A := 111111xx) ;rar ; (posun pro 8-kanálový přehrávač) ani 4 ; OUT = F1 OR F2 OR F3 OR F4 out kbdled ; výstup na reproduktor dcx d ; odpočet délky souzvuku tónů mov a,d ora e jnz soundL pop b ; obnovit ukazatel do notového zápisu ret
Jednodušší to už asi být nemůže. Samotné generování každého jednoho zvukového kanálu (DDS ) se odehrává v šestnáctibitových registrech BC a HL a neovlivňuje obsah 8-bitového registru A. Do registru A se přenáší pouze informace o požadavku na vygenerování pulsu každým ze čtyř generátorů. Že chce daný generátor vyrobit puls, dá vědět pomocí nastavení příznaku CY, který pomocí instrukce „SBI 0“ postoupí tuto informaci právě do registru A. Na konci smyčky se podle obsahu registru A pošle na reproduktor buď logická 0 (žádný kanál negeneruje puls, registr A zůstal nulový) nebo logická 1 (minimálně jeden z kanálů generuje puls, registr A má hodnotu 111111xxb – tedy jednu z hodnot 0FFh/0FEh/0FDh/0FCh).
zdrojový kód demonstračního příkladu s využitím přehrávače VOICE416
Ještě připojím praktickou informaci pro případné zájemce.
Pomocí čítače, připojeného na konektor klávesnice, jsem ověřoval skutečnou generovanou frekvenci zvuku přes všechny oktávy a podle toho nastavil hodnoty generujících konstant. Nakonec se však ukázalo, že je vhodné proměřit a nastavit generující konstanty pouze pro 12 nejnižších použitých tónů (nemusí ležet všechny v rámci jedné oktávy), a generující konstanty všech vyšších tónů již nastavit jako přesné dvojnásobky konstant tónů vždy o oktávu nižších. To je důležité kvůli libozvučnosti oktávových intervalů. To není teoretická rada ale prakticky ověřená zkušenost.
Jakkoliv je rutina technicky schopná přehrávat tóny v rozsahu zhruba 7 oktáv, je tzv. jitter zejména u posledních dvou, tří oktáv značný (tím myslím morbidní). Proto je dobré měřit nějakým čítačem, který měřenou frekvenci průměruje, jinak vám může údaj hodně lítat. Ale kupodivu (moje nezkušené) ucho si to zprůměruje rovněž a subjektivně vnímaná stupnice i v těchto vyšších polohách zní jako plynule rostoucí. Mění se samozřejmě i „barva“ zvuku. Na tom se však podepisuje jak proměnný činitel plnění výsledného obdélníkového signálu, tak i vlastní amplitudová charakteristika použitého akustického měniče (reproduktoru). Pravda ovšem je, že jako hudebník jsem naprostý laik.
Áno. Presne taký zvuk mala muzika, ktorá bola na demonštračnej kazete k Didaktiku M. ;-)