Juha Niemimäki
AHI-ohjelmoinnin alkeet

Ajankohtaiset

Boogien palsta

Boogie

Star Wreck -spesiaali

Eletään tylsää tulevaisuutta

Tohtori AivoTurmio

Ohjelmointia: AHI, MorphOS, Tinygl

Juha Niemimäki, Ilkka Lehtoranta, J-P Jokela

0xAA - Codex Alpe Adria 2005

Sami Ylönen

Kun PCisti Amigaan ryhtyi

Tero Säärelä

Videokaappari käytettynä?

Jarmo Piippo

Johdanto
Alkuaikoina Amigan äänikorteille ei ollut yhteistä ohjelmointirajapintaa, vaan ääntä tuotettiin käyttäen äänikorttien omia API-ratkaisuja. Martin Blom kehitti AHI-järjestelmän, josta muodostui de facto -ratkaisu äänikorttien tukemiseen Amiga-ympäristöissä. AHI-järjestelmä on laite (Device), joka tuottaa ääntä AHI-ajureiden avulla.

Tällä hetkellä AHI:sta on julkaistu versio 6.0 (rc4). AHI-websivu löytyy osoitteesta: http://www.lysator.liu.se/(dl)/~lcs/ahi.html.

Sovellusohjelmoijan kannalta AHI-järjestelmää voi ohjelmoida kahden erillisen rajapinnan kautta. Mielestäni helpompi tapa on käyttää korkean tason rajapintaa, toiselta nimeltään laiterajapintaa. Monipuolisempaan ohjelmointiin on tarjolla matalan tason rajapinta, tunnettu myös funktiorajapintana.

Tämä juttu havainnollistaa vain laiterajapinnan käyttöä äänen toistamiseen. AHI SDK:n mukana tulevia esimerkkejä seuraamalla pääsee kyllä jyvälle myös funktiorajapinnasta sekä äänen digitoimisesta.
Alustus- ja lopetustoimet
Käytännössä AHI on laite, joka täytyy avata, ennen kuin sitä voidaan käyttää. Avattaessa tarvitaan IO-pyyntö (jota varten tarvitaan viestiportti), laitteen nimi sekä toivottu laiteyksikkö (unit). On huomattavaa, että Exec-kirjaston OpenDevice-kutsu palauttaa 0:n, mikäli laitteen avaus onnistuu. AHINAME ja AHI_DEFAULT_UNIT on määritelty otsikkotiedostossa devices/ahi.h. AHINAME on "ahi.device" ja AHI_DEFAULT_UNIT 0.

Laitteen sulkeminen tapahtuu välittämällä kelvollinen IO-pyyntö Exec-kirjaston CloseDevice-kutsulle. Ennen laitteen sulkemista tulee keskeyttää mahdolliset käynnissä olevat IO-pyynnöt tai odottaa, että ne on käsitelty. Tästä lisää myöhemmin ohjelmaesimerkissä 3.

Esimerkki resurssien varaamisesta ja vapauttamisesta:

Esimerkki 1.c
AHI:n tietotyypit ja AHIRequest
AHI käyttää "Fixed"-tyyppiä liukulukutyyppien sijasta kuvaamaan äänenvoimakkuutta ja panorointiasetuksia. Fixed-tyypissä sekä kokonais- että desimaaliosat ovat 16-bittisiä numeroita. Seuraava taulukko on kopioitu suoraan AHI-dokumentaatiosta:

Decimal Fixed
1.0 0x00010000
0.5 0x00008000
0.25 0x00004000
0 0x00000000
-0.25 0xffffc000
-0.5 0xffff8000
-1.0 0xffff0000

Äänen panoroinnista sen verran, että 0 tarkoittaa äänen olevan kokonaan vasemmalla stereokanavalla, 0.5 keskellä ja 1.0 kokonaan oikealla stereokanavalla. Tämä ilmaistaan siis Fixed-tyyppisellä numerolla (0x0=vasemmalla, 0x8000=keskellä ja 0x10000 oikealla). AHI-dokumentaation mukaan negatiiviset panorointiarvot muokkaavat äänen surround-tyyppiseksi, mutta en ole kokeillut tätä käytännössä.

Äänenvoimakkuusarvo on myös Fixed-tyyppiä, väliltä 0x0 ... 0x10000. AHI-dokumentaation mukaan negatiivinen äänenvoimakkuus soittaa ääninäytteen takaperin.

Ohessa on devices/ahi.h:sta ryöstetty kuvaus AHIRequestista. AHIRequest on siis laajennettu IO-pyyntö, jota käytetään AHI-ohjelmoinnissa. Äänen toistamisen kannalta meitä kiinnostavat viisi alinta jäsenmuuttujaa. ahir_Volume ja ahir_Position -muuttujien on käyttö tulikin jo puolivahingossa kuvattua kahdessa aikaisemmassa kappaleessa, joten käsitellään nyt loputkin tarvittavat.

ahir_Frequency on ääninäytteen taajuus hertseinä.

ahir_Link-muuttujaa tarvitaan, mikäli halutaan käyttää kaksoispuskurointia peräkkäisten ääninäytteiden toistoon. Käytännössä esim. MOD- tai MP3-playerit vaativat tämän muuttujan käyttämistä. Ideana on siis käyttää kahta äänipuskuria ja kahta IO-pyyntöä, joita vuorotellaan siten, että toista puskuria soitettaessa täytetään toinen puskuri uudella datalla. Asetetaan NULL:ksi, jos kaksoispuskurointia ei tarvita (esim. soitettaessa yksinkertainen äänitehoste).

Näiden lisäksi tarvitsemme tavallisesta IO-pyynnöstä muuttujat:

ahir_Std.io_Command: asetamme CMD_WRITE:ksi ääntä toistettaessa.

ahir_Std.io_Length: äänipuskurin koko tavuina.

ahir_Std.io_Data: äänipuskurin osoite.
Yksittäisen ääninäytteen soitto
Tässä generoidaan pätkä siniaaltoa ja soitetaan 8-bittisenä monoäänenä lähettämällä IO-pyyntö Exec-kirjaston DoIO-kutsun avulla. DoIO-Kutsu odottaa niin kauan että IO-pyyntö on täytetty, toisin sanoen ohjelman suoritus pysähtyy hetkeksi.

Esimerkki 2.c
Kaksoispuskurointi: yksinkertainen Ogg Vorbis -soitin
Tämä esimerkki käyttää libVorbisFile-kirjastoa hyväkseen purkaakseen Ogg Vorbis -dataa. Käsitykseni mukaan VorbisFile.library löytyy MorphOSille, mutta AmigaOS 4 -käyttäjät linkkaavat ohjelmaan staattisen version libVorbisFile-kirjastosta, jonka pitäisi tulla AmigaOS 4 SDK:n mukana.

Soitto-ohjelma ottaa yhden komentoriviparametrin ja ilman isompia hienosteluja yrittää tulkita sitä Ogg Vorbis -tiedostona. Ov_-alkuiset kutsut kuuluvat siis libVorbisFile-kirjastoon. Ohjelman suoritus lakkaa jos musiikki loppuu tai käyttäjä painaa Control-C:tä. Ohjelma olettaa datan olevan 16-bittistä stereoääntä.

Kaksoispuskurointia varten tarvittiin siis - yllättäen - kaksi datapuskuria ja kaksi IO-pyyntöä. Toinen IO-pyyntö on ensimmäisen kopio. Joka silmukan suorituskerralla otetaan ei-aktiivinen puskuri ja ei-aktiivinen IO-pyyntö käyttöön, puretaan Ogg Vorbis -dataa 4096 tavua, yhdistetään aktiivinen IO-pyyntö edelliseen ja lähetetään aktiivinen pyyntö Exec-kirjaston SendIO-kutsulla maailmalle.

Koodi pyrkii kiertämään harmillisen kaksoispuskurointiongelman, joka ilmenee joissakin tapauksissa ainakin AmigaOS 4:n AHI-versiossa. Yksinkertaisesti tarkistetaan, päättyikö edellinen IO-pyyntö ennenkuin siihen voitiin yhdistää seuraava, jos näin kävi, aloitetaan kaksoispuskurointi uudelleen.

Lisätietoa Ogg Vorbis-formaatista: http://www.vorbis.com/faq/

Esimerkki 3.c
Loppusanat
Lisätietoa löytyy AHI SDK:n dokumentaatiosta sekä esimerkkiohjelmista.

Muita työkaluja äänen tuottamiseen Amiga-ympäristössä ovat esimerkiksi Simple DirectMedia Layer (SDL) -kirjasto sekä SDL_Mixer. SDL ja sen tukikirjastot ovat loistava valinta alustariippumattomaan (ääni)ohjelmointiin. Lisätietoja: http://www.libsdl.org

PS. AmigaOS 4 -käyttäjien kannattaa huomioida, että funktiorajapintaa käytettäessä on pyydettävä IAHI-rajapinta systeemiltä, ennen kuin AHI:n funktioita voidaan kutsua.

Esimerkki:

struct AHIIFace * IAHI;
// olettaa, että AHI device on avattu ensiksi normaalisti
IAHI = (struct AHIIFace *) GetInterface( (struct Library *) AHIio->ahir_Std.io_Device, "main", 1, NULL );

...koodia...

// suljetaan IAHI
DropInterface( (struct Interface *) IAHI );

// nyt voidaan sulkea ahi.device

Sivun alkuun