IL LINUX OPEN SOUND SYSTEM         ANTONIO TRINGALI            maggio 1999
ii
Indice1 LA     SCHEDA AUDIO E OSS                                                                                       4 ...
3.6.1 Little e big endian . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42          3...
5 IL MIDI A BASSO LIVELLO                                                                                          106  5....
SommarioQuesto lavoro si propone come tutorial per la programmazione della scheda audiotramite l’Open Sound System (OSS) p...
INTRODUZIONE ALL’OPEN SOUND SYSTEM     All’inizio degli anni ’90 Hannu Savolainen scrisse la prima versione di un driverpe...
• supporto half e full duplex (con apposite schede audio)   • possibilit` di accesso diretto al buffer audio DMA (per appli...
Capitolo 1LA SCHEDA AUDIO E OSS1.1       Modello della scheda audioUna scheda audio ha diverse funzioni: converte i suoni ...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                         1.1. MODELLO DELLA SCHEDA AUDIOaudio senza che sia stato campion...
1.2. L’INTERFACCIA DI PROGRAMMAZIONE DI OSS                                                            CAPITOLO 1. LA SCHE...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                                                           1.2. L’INTERFACCIA DI PROGRAMM...
1.2. L’INTERFACCIA DI PROGRAMMAZIONE DI OSS     CAPITOLO 1. LA SCHEDA AUDIO E OSS                `/dev/midi00 E un’interfa...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                        1.3. INIZIALIZZAZIONE DI OSSdi /dev/sndstat: l’esempio sopra rive...
1.3. INIZIALIZZAZIONE DI OSS                   CAPITOLO 1. LA SCHEDA AUDIO E OSS    Per read() e write() i flag O_NDELAY o ...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                       1.3. INIZIALIZZAZIONE DI OSSEAGAIN La risorsa a cui si ` cercato d...
1.3. INIZIALIZZAZIONE DI OSS                         CAPITOLO 1. LA SCHEDA AUDIO E OSS   Un altro buon accorgimento di pro...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                              1.3. INIZIALIZZAZIONE DI OSS         exit(-1);}int main(){ ...
1.4. SCRITTURA DI CODICE PORTABILE             CAPITOLO 1. LA SCHEDA AUDIO E OSS   Per esempio, se si vuole che il process...
CAPITOLO 1. LA SCHEDA AUDIO E OSS               1.4. SCRITTURA DI CODICE PORTABILE   • Come si vedr` nei successivi Capito...
1.5. ANATOMIA DEL DRIVER                              CAPITOLO 1. LA SCHEDA AUDIO E OSS   • Non si deve usare il full dupl...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                                    1.5. ANATOMIA DEL DRIVERdiminuisce. In pratica ci dev...
1.5. ANATOMIA DEL DRIVER                       CAPITOLO 1. LA SCHEDA AUDIO E OSS   • il driver copia il resto dei dati nel...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                        1.6. SCHEDE AUDIO ISA E PCI   • i campioni richiesti sono copiati...
1.7. FILE SYSTEM E DEVICE FILE                  CAPITOLO 1. LA SCHEDA AUDIO E OSS      di un servizio DMA — e gli interrup...
CAPITOLO 1. LA SCHEDA AUDIO E OSS                             1.8. LE VERSIONI DI OSS    Ad esempio, /dev/midi00 identifica...
1.8. LE VERSIONI DI OSS                CAPITOLO 1. LA SCHEDA AUDIO E OSS   versione = SOUND_VERSION / 100;   release1 = (S...
Capitolo 2IL MIXER E LA GESTIONEDEI CANALI2.1      Descrizione di /dev/mixerNon tutte le schede audio possiedono un mixer:...
2.2. I CANALI DEL MIXER              CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALIdifferenze di comportamento riscontrate d...
CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI              2.2. I CANALI DEL MIXER Nomi dei canali         Bitmask associa...
2.2. I CANALI DEL MIXER             CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI   Se in un programma si effettuano le ass...
CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI              2.2. I CANALI DEL MIXER   Per i canali il controllo si pu` effet...
2.3. LIVELLI DI VOLUME DEI CANALI     CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALIbitmask = SOUND_MASK_CD | SOUND_MASK_MI...
CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI     2.4. DIPENDENZA DALL’HARDWARE   Per estrarre il volume dei canali destro...
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Il Linux OpenSound System
Upcoming SlideShare
Loading in...5
×

Il Linux OpenSound System

323

Published on

Reverse engineering che ho fatto del primo sottosistema audio di Linux nel 1999. Magari a qualcuno può tornare utile per motivi storici. :-)

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
323
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Il Linux OpenSound System

  1. 1. IL LINUX OPEN SOUND SYSTEM ANTONIO TRINGALI maggio 1999
  2. 2. ii
  3. 3. Indice1 LA SCHEDA AUDIO E OSS 4 1.1 Modello della scheda audio . . . . . . . . . . . . . . . . . . . . . . 4 1.2 L’interfaccia di programmazione di OSS . . . . . . . . . . . . . . 6 1.3 Inizializzazione di OSS . . . . . . . . . . . . . . . . . . . . . . . . 9 1.3.1 Gestione degli errori . . . . . . . . . . . . . . . . . . . . . 10 1.3.2 L’exit handler . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.3.3 Il signal handler . . . . . . . . . . . . . . . . . . . . . . . . 13 1.4 Scrittura di codice portabile . . . . . . . . . . . . . . . . . . . . . 14 1.5 Anatomia del driver . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.5.1 Scrittura sul buffer DMA . . . . . . . . . . . . . . . . . . . 17 1.5.2 Lettura dal buffer DMA . . . . . . . . . . . . . . . . . . . 18 1.6 Schede audio ISA e PCI . . . . . . . . . . . . . . . . . . . . . . . 19 1.7 File system e device file . . . . . . . . . . . . . . . . . . . . . . . . 20 1.8 Le versioni di OSS . . . . . . . . . . . . . . . . . . . . . . . . . . 212 IL MIXER E LA GESTIONE DEI CANALI 23 2.1 Descrizione di /dev/mixer . . . . . . . . . . . . . . . . . . . . . . 23 2.2 I canali del mixer . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 2.2.1 Lettura della configurazione . . . . . . . . . . . . . . . . . 26 2.2.2 Selezione del canale da campionare . . . . . . . . . . . . . 27 2.3 Livelli di volume dei canali . . . . . . . . . . . . . . . . . . . . . . 28 2.4 Dipendenza dall’hardware . . . . . . . . . . . . . . . . . . . . . . 29 2.5 Nuove caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . 30 2.6 Esempio di programma . . . . . . . . . . . . . . . . . . . . . . . . 313 CAMPIONAMENTO E RIPRODUZIONE 36 3.1 I device file audio . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.2 Il buffer audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 3.3 Parametri di campionamento . . . . . . . . . . . . . . . . . . . . . 37 3.3.1 Reset dei parametri . . . . . . . . . . . . . . . . . . . . . . 38 3.3.2 Pause nelle operazioni . . . . . . . . . . . . . . . . . . . . 39 3.4 Il campionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 3.5 La riproduzione . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 3.6 Il formato audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 iii
  4. 4. 3.6.1 Little e big endian . . . . . . . . . . . . . . . . . . . . . . 42 3.6.2 La codifica lineare . . . . . . . . . . . . . . . . . . . . . . 43 3.7 Il tempo reale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.7.1 Le capacit` del driver . . . . . a . . . . . . . . . . . . . . . . 45 3.7.2 Gestione del buffer DMA . . . . . . . . . . . . . . . . . . . 46 3.7.3 I/O non bloccante . . . . . . . . . . . . . . . . . . . . . . 48 3.7.4 La sincronizzazione . . . . . . . . . . . . . . . . . . . . . . 52 3.7.5 Accesso diretto al buffer DMA . . . . . . . . . . . . . . . . 53 3.8 Il full duplex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 3.9 Uso di coprocessori . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.10 Nuove caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.11 Esempio di programma . . . . . . . . . . . . . . . . . . . . . . . . 594 SINTETIZZATORI E MIDI 64 4.1 I device file del sequencer . . . . . . . . . . . . . . . . . . . . . . . 64 4.1.1 I chip sintetizzatori . . . . . . . . . . . . . . . . . . . . . . 65 4.1.2 I sintetizzatori MIDI . . . . . . . . . . . . . . . . . . . . . 66 4.2 Il buffer degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . 67 4.3 Lettura della configurazione . . . . . . . . . . . . . . . . . . . . . 69 4.3.1 Parametri generali . . . . . . . . . . . . . . . . . . . . . . 70 4.3.2 Le porte MIDI . . . . . . . . . . . . . . . . . . . . . . . . 71 4.4 Predisposizione dei chip sintetizzatori . . . . . . . . . . . . . . . . 72 4.4.1 Caricamento degli algoritmi FM . . . . . . . . . . . . . . . 73 4.4.2 Caricamento delle patch wavetable . . . . . . . . . . . . . 76 4.4.3 Caricamento delle sysex patch . . . . . . . . . . . . . . . . 81 4.5 La temporizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . 81 4.5.1 La sincronizzazione per /dev/music . . . . . . . . . . . . . 83 4.5.2 La sincronizzazione per /dev/sequencer . . . . . . . . . . . 85 4.6 Output degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . 86 4.6.1 Messaggi di canale . . . . . . . . . . . . . . . . . . . . . . 86 4.6.2 Messaggi di sistema . . . . . . . . . . . . . . . . . . . . . . 89 4.6.3 Controllo della coda degli eventi . . . . . . . . . . . . . . . 91 4.7 Formato degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . 92 4.8 Input degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 4.8.1 Eventi per /dev/music . . . . . . . . . . . . . . . . . . . . 95 4.8.2 Eventi per /dev/sequencer . . . . . . . . . . . . . . . . . . 97 4.9 Nuove caratteristiche . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.9.1 SoftOSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 4.9.2 OSSlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 4.10 Esempio di programma . . . . . . . . . . . . . . . . . . . . . . . . 102 iv
  5. 5. 5 IL MIDI A BASSO LIVELLO 106 5.1 Descrizione dei device file MIDI . . . . . . . . . . . . . . . . . . . 106 5.2 Lettura dalla porta MIDI . . . . . . . . . . . . . . . . . . . . . . . 107 5.3 Scrittura sulla porta MIDI . . . . . . . . . . . . . . . . . . . . . . 109 5.4 Programmazione della MPU–401 . . . . . . . . . . . . . . . . . . 109 5.5 Esempio di programma . . . . . . . . . . . . . . . . . . . . . . . . 110A GENERAL MIDI 121 A.1 Timbri strumentali . . . . . . . . . . . . . . . . . . . . . . . . . . 121 A.2 Timbri delle percussioni . . . . . . . . . . . . . . . . . . . . . . . 125 1
  6. 6. SommarioQuesto lavoro si propone come tutorial per la programmazione della scheda audiotramite l’Open Sound System (OSS) per il sistema operativo Linux, ponendoparticolare enfasi sulle strategie di programmazione pi` opportune per la sintesi uaudio in tempo reale.Capitolo 1 Si introduce un modello “medio” delle varie schede audio presenti sul mercato; dopo sono descritte la visione orientata a UNIX che ne ha OSS (in particolare alla fine descrivendo il funzionamento interno del driver), la sua inizializzazione e la gestione delle uscite da programma e dei segnali in un ambiente multiutente e multiprogrammato, con qualche riferimento alla scrittura di programmi portabiliCapitolo 2 Il mixer gestisce i canali di ingresso/uscita facenti capo alla scheda audio; ` spiegato come scoprire le capacit` di quest’ultima, selezionare i e a canali e regolare i livelli di volume per campionamento e riproduzione `Capitolo 3 E spiegato come campionare da un qualsiasi canale del mixer e ripro- durre i campioni sintetizzati o immagazzinati su un file, eventualmente in maniera non bloccanteCapitolo 4 Ci si occupa della programmazione ad alto livello, cio` in maniera e indipendente dai dispositivi, del chip sintetizzatore interno alla scheda audio e delle porte MIDICapitolo 5 Si tratta della programmazione MIDI a basso livello, cio` a livello e di I/O di byte dei messaggi `Appendice A E riportata una tabella di corrispondenza fra i preset timbrici definiti nello standard General MIDI level 1 e i nomi delle patch wavetable per la Gravis UltraSound
  7. 7. INTRODUZIONE ALL’OPEN SOUND SYSTEM All’inizio degli anni ’90 Hannu Savolainen scrisse la prima versione di un driverper la scheda audio Sound Blaster 1.5 sotto Minix–386; nel 1992 ne fece il portingsotto Linux: era nato il Linux Sound Driver (LSD). Al crescere del numero di versione e delle funzionalit` implementate, nonch´ a eall’aumentare del numero di porting ad altre variet` di UNIX, il driver cambi` a oil nome in VoxWare; sfortunatamente era omonimo della VoxWare Incorporat-ed, quindi per problemi di copyright per un certo periodo rest` il Temporarily oAnonymous Sound Driver (TASD). Poco dopo la 4Front Technologies, con la collaborazione dello stesso HannuSavolainen, svilupp` l’Unix Sound System (USS), avente qualche caratteristica in opi` rispetto al driver freeware e un maggior numero di schede audio supportate; ulo stesso Savolainen continuava indipendentemente a sviluppare il driver freeware(il cui codice sorgente era differente da quello di USS), noto ora come USS/Lite. In ossequio a POSIX e alla gran variet` di sistemi di tipo UNIX al quale ` a estato portato, il nome ` cambiato nuovamente e il driver ` commercializzato dalla e e4Front Technologies come Open Sound System, mentre nella versione freeware` noto come OSS/Free. Di questo Savolainen non mantiene pi` il codice: lae uresponsabilit` ` passata a Alan Cox dagli inizi del 1998. ae D’ora in poi ci si riferir` a questi driver globalmente come OSS, sottinten- adendo che ci` che sar` detto vale per entrambi (evidenziando, ove necessario, o ale differenze); la versione assunta come “riferimento” ` la 3.5.4. A seguire dal eCapitolo 2, la penultima Sezione di ogni Capitolo elenca le differenze di program-mazione introdotte dalla versione 3.6 in poi e l’ultima Sezione ospita un breveprogramma di esempio in C che illustra le caratteristiche di OSS introdotte nelCapitolo stesso. Delle chiamate alla libreria di OSS elencate in soundcard.h, si` scelto di riportare solo quelle pienamente supportate.e OSS ` in pratica il primo tentativo di unificare l’architettura di audio digitale eper UNIX: alle capacit` di campionamento e riproduzione (piuttosto articolate arispetto a quanto prima disponibile per questo ambiente) sono affiancate le possi-bilit` del MIDI, con il supporto dell’audio sincronizzato alla riproduzione video. a`E allo stato attuale un insieme modulare di device driver che garantiscono un’in-terfaccia di programmazione uniforme e compatibile a livello di codice sorgenteper tutte le piattaforme su cui ` stato portato, tanto che per queste ` valido la e equasi totalit` di ci` che ` scritto nel seguito di questo lavoro. a o e Una panoramica generica delle caratteristiche supportate sia dall’OSS com-merciale (OSS/Linux) che da OSS/Free ` la seguente: e • supporto di vari formati audio per i campioni (8 e 16 bit signed e unsigned, 8 bit µ–Law e A-Law, IMA–ADPCM) • supporto di canali stereo e mono • frequenze di campionamento comprese tra 4kHz e 48kHz 2
  8. 8. • supporto half e full duplex (con apposite schede audio) • possibilit` di accesso diretto al buffer audio DMA (per applicazioni con a richieste temporali pi` stringenti, come i giochi) u • possibilit` di accesso indipendente dall’hardware a MIDI e a sintetizzatori a FM o wavetable sulla scheda audio • caricamento delle patch in maniera indipendente dall’hardware • supporto per SMPTE/MTC • supporto per UART di tipo MP–401, Sound Blaster MIDI e XG MIDI • supporto di IBM/Motorola PowerPC (bus ISA e PCI), 386/486/Pentium (bus ISA, EISA e PCI), Sun SPARC e DEC Alpha/AXP (bus ISA e PCI) Rispetto a OSS/Free, OSS/Linux ha in pi` le seguenti caratteristiche: u • supporto diretto dello standard PnP (senza dover inizializzare precedente- mente le schede con il comando isapnp) • supporto di un maggior numero di schede audio • non si deve ricompilare il kernel ad ogni cambio di configurazione o driver (questo ` un modulo separato) e • supporto delle schede Sound Blaster 16/32/64/AWE in full duplex • supporto delle patch wavetable E–mu SoundFont 2.0 • librerie DirectAudio per l’accesso diretto ai chip sintetizzatori FM e alle porte MIDIsi ` scelto di non trattare gli ultimi due punti, in quanto di interesse marginale eper la sintesi in tempo reale. CONVENZIONI TIPOGRAFICHEPer tutto il testo sono seguite per le parole le seguenti convenzioni: corsivo indica una sigla o un termine tecnico rilevante introdotto per la primavolta neretto indica un identificatore o una variabile (con specificato il tipo) perl’interfaccia di programmazione di OSS o di Linux spaziatura fissa indica una parola chiave appartenente alla libreria diOSS o codice sorgente di esempio; se le parole sono contenute tra parentesi an-golate, come ad esempio per <valore>, si intende che il programmatore debbasostituirvi un adeguato valore numerico 3
  9. 9. Capitolo 1LA SCHEDA AUDIO E OSS1.1 Modello della scheda audioUna scheda audio ha diverse funzioni: converte i suoni immagazzinati nel sistema(ad esempio, su file) dalla forma digitale all’analogica affinch´ li si possa udire eo registrare, converte da opportuni canali di ingresso (Line–In1 , microfono, CDaudio) i segnali da analogico a digitale affinch´ possano essere immagazzinati o emanipolati dal computer, pu` consentire essa stessa di creare nuovi suoni tramite oeventuali sintetizzatori interni. Secondo le specifiche MPC2 deve anche essere dotata di una porta MIDI perch´ eil computer possa controllare strumenti musicali o sintetizzatori esterni con talicapacit`, invece di generare da s´ i suoni. Il PC diventa in pratica un sequencer, a ecio` un direttore d’orchestra allo stato solido; virtualmente non ` pi` di una e e umemoria e un sistema di messaggi dalla e alla strumentistica, con capacit` di aediting. L’OSS cerca di offrire una visione idealizzata della scheda audio al program-matore, nascondendo le differenze tecniche fra le varie schede presenti sul mercato;essa pu` essere vista come un mixer, di cui il programmatore (il Disc Jockey) ha opossibilit` di controllare ogni canale3 . a Per la riproduzione (conversione D/A) la sorgente ` da file (brano digitaliz- ezato o MIDI) o i campioni sono creati con un opportuno algoritmo di sintesi, daCD audio4 (il segnale ` semplicemente spedito alla sezione analogica della scheda e 1` E un ingresso con livelli simili a quelli d’ingresso per un amplificatore HI–FI, utile percampionare il segnale proveniente da un registratore analogico o da un CD player esterni 2 Specifiche rilasciate da Microsoft e Intel nel 1991 per definire una configurazione hardwareminima affinch´ un computer potesse essere definito “multimediale”: si doveva cio` disporre e ealmeno di un PC 386SX/16MHz con 4MB di RAM e 40MB di hard disk, una VGA a colori, unmouse, una scheda audio e un CD–ROM player 3 Indipendentemente o meno dagli altri; relativamente alle capacit` della scheda audio stessa, acon il programmatore che pu` interrogare OSS sulle capacit` di quest’ultima o a 4 Non ` presa in considerazione la programmazione del drive CD in questo tutorial, solo come esi fa a campionare o riprodurre il segnale che ` presente sull’eventuale canale CD Audio In della escheda audio 4
  10. 10. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.1. MODELLO DELLA SCHEDA AUDIOaudio senza che sia stato campionato prima), da Line–In e da microfono. In cam-pionamento (conversione A/D) si pu` acquisire dagli ingressi CD Audio, Line–In oe microfono o si possono acquisire eventi MIDI. La coppia di convertitori A/D e D/A viene spesso chiamata PCM, DSP,CODEC o ADC/DAC ; nella Tabella seguente sono elencate le massime frequenzedi campionamento5 per le varie generazioni di schede audio che OSS supporta (laminima ` sempre intorno ai 5 kHz); la fc ` generata dividendo l’alta frequenza di e eun oscillatore di riferimento, per cui non ` possibile ottenere tutte le frequenze edell’intervallo: le differenze di qualche percento dovrebbero essere ignorate perch´ esolitamente non avvertibili (OSS cerca di ottenere dalla scheda audio la frequenzapi` vicina a quella richiesta). La risoluzione di campionamento pu` essere di 8 o u o16 bit, in mono o stereo. Generazione Max fc Note 1a 22.05 kHz in riproduzione 11.025 kHz in campionamento 2a 44.1 kHz mono 22.05 kHz stereo 3a 44.1 kHz qualit` audio CD a 48 kHz qualit` DAT a 4a 96 kHz Ultra Hi–Fi Oltre alle succitate possibilit` di sintesi FM6 e di gestione dei dispositivi MI- aDI, alcune schede consentono la wavetable synthesis e la possibilit` di caricare acampioni di uno strumento (patch) in una speciale memoria della scheda stessa. In figura 1.1 ` evidenziata la visione che possiamo dare della nostra scheda eaudio idealizzata come output mixer per quanto riguarda la riproduzione, che bensi conf` alle caratteristiche pi` comuni riscontrabili nelle schede audio attualmente a upresenti sul mercato (1999). In figura 1.2 ` invece schematizzato l’input mixer a ecui fare riferimento per quanto riguarda il campionamento. Infatti dentro una scheda audio possono esserci realmente due mixer che gestis-cono separatamente i casi di campionamento e riproduzione, ma OSS gestisceautomaticamente il passaggio dall’uno all’altro in base ai comandi del program-matore di lettura o scrittura dalla/alla scheda audio. In particolare, se tali attivit` asono implementate dalla scheda audio come mutuamente esclusive ` definita half eduplex, mentre ` definita full duplex se possono aver luogo contemporaneamente. e 5 Alcune vecchie schede permettono di scegliere solo fra frequenze di campionamento fisse:11025 Hz, 22050 Hz, 32000 Hz e 44100 Hz 6` E sfruttata la tecnica degli operatori per produrre pi` voci: i chip “classici” sono lo Yamaha uOPL–2 (a due operatori, nove voci con timbri non realistici) e OPL–3 (a quattro operatori,diciotto voci): aumentando il numero di operatori per voce migliora la qualit` della sintesi a 5
  11. 11. 1.2. L’INTERFACCIA DI PROGRAMMAZIONE DI OSS CAPITOLO 1. LA SCHEDA AUDIO E OSS Memoria del computer o Hard-Disk LINE-OUT ALTOPARLANTI L R L R L R L R L R L R L R STEREO MONO STEREO MONO TREBLE BASS RECORD CD Audio LINE-IN MIC MASTER DAT CD Audio LINE-IN MIC MIDI ON/OFF VOLUME ON/OFF ON/OFF ON/OFF MIDI ON/OFF VOLUME ON/OFF ON/OFF ON/OFF ON/OFF Figura 1.1: Modello come mixer della Figura 1.2: Modello come mixer scheda audio in riproduzione della scheda audio in campiona- mento1.2 L’interfaccia di programmazione di OSSPer gestire il “mixer virtuale” delle figure 1.1 e 1.2 OSS sfrutta la visione orientataal file–system che Linux ha di ogni device 7 . I canali del mixer, campionamentoe riproduzione possono quindi essere gestiti manipolando degli speciali file chesi trovano nella directory /dev tramite le primitive di sistema open(), ioctl(),read(), write() e close(). In figura 1.3 sono evidenziati i device file relativi alla manipolazione dei varicanali per la riproduzione, mentre in figura 1.4 c’` lo schema equivalente per il ecampionamento. Quest’organizzazione ` conveniente, poich´ in tal modo sono schermate sia le e ecomplessit` dell’hardware e del software sottostante (la scheda audio, ma anche ala gestione del DMA, della memoria virtuale e del multitasking), sia le diversit` afra le varie schede audio in commercio. Si pu` ora procedere alla descrizione di ogni device file: o/dev/mixer Questa ` l’interfaccia di accesso alle funzioni del mixer e pu` e o essere un link simbolico a /dev/mixer0; se ` presente un secondo mixer, ci e si riferisce ad esso come /dev/mixer1/dev/dsp Identifica il DSP della scheda (per default con codifica lineare 8 bit unsigned) e pu` essere un link simbolico a /dev/dsp0; in genere ` presente o e 7` E un’interfaccia a un dispositivo hardware (dischi, linee seriali, etc.) o a “entit`” a cui anon corrisponde un vero e proprio dispositivo hardware (memoria di sistema, kernel, etc.); a undevice fisico — come la scheda audio — corrisponde un device driver — come OSS — che hail compito di pilotarlo 6
  12. 12. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.2. L’INTERFACCIA DI PROGRAMMAZIONE DI OSS = Link simbolico OSS driver OSS driver Memoria del computer o Hard-Disk /dev/dsp /dev/dsp0 /dev/dsp1 MIDI in /dev/dsp /dev/dspW /dev/dspW0 /dev/dspW MIDI file (out) /dev/dspW1 /dev/audio /dev/audio /dev/audio0 CD Audio /dev/music /dev/audio1 /dev/sequencer CD Audio /dev/midi00 Memoria del computer /dev/midi01 o Hard-Disk /dev/sndstat /dev/sndstat /dev/midi02 /dev/sndproc Line-In /dev/music /dev/sndproc /dev/midi03 Line-In /dev/sequencer /dev/midi00 /dev/midi01 MIXER MIXER /dev/midi02 /dev/midi03 Mic Mic /dev/mixer /dev/mixer0 /dev/mixer /dev/mixer0 /dev/mixer1 /dev/mixer1 Figura 1.3: Visione della scheda au- Figura 1.4: Visione della scheda dio in riproduzione che OSS d` al audio in campionamento che OSS a programmatore d` al programmatore a anche /dev/dsp1, che pu` identificare un secondo DSP o lo stesso con una o diversa funzione/dev/dspW Se presente (dipende dalla versione di OSS), si riferisce al DSP con codifica lineare 16 bit signed e little endian8 ; pu` essere un link simbolico o a /dev/dspW0 ed eventualmente ` presente anche /dev/dspW1 e `/dev/audio E presente per limitata compatibilit` con le workstation Sun (non a sono supportati cambiamenti da 8 kHz/mono/8 bit) e utilizza la codifica µ–Law9 ; ` disponibile in mutua esclusione con /dev/dsp e generalmente ` e e un link a /dev/audio0, potendo essere presente anche /dev/audio1/dev/music Permette di accedere al sintetizzatore interno alla scheda audio e alle porte MIDI in maniera indipendente dal dispositivo (sono trattati allo stesso modo dal punto di vista dell’interfaccia di programmazione), con modalit` di temporizzazione piuttosto articolate; pu` essere presente il link a o simbolico ad esso /dev/sequencer2 (obsoleto) `/dev/sequencer E un device file a pi` basso livello di /dev/music, rispetto al u quale ha capacit` limitate di temporizzazione, sincronizzazione e gestione a automatica del chip sintetizzatore interno alla scheda audio 8 Little endian e big endian si riferiscono a come sono conservati i campioni in memoria dallaCPU: per il primo l’indirizzo del dato corrisponde all’indirizzo del byte meno significativo (Intel,Alpha), per il secondo al byte pi` significativo (Motorola, Sparc, PowerPC, HP–PA) u 9 Un campione a 12 o 16 bit ` compresso logaritmicamente a 8 bit: OSS in riproduzione enon effettua l’operazione opposta, ma converte in un campione a 8 bit lineare prima di inviareal device audio (sono introdotti un overhead per il calcolo e della distorsione); ` un formato ederivante dalla tecnologia telefonica digitale 7
  13. 13. 1.2. L’INTERFACCIA DI PROGRAMMAZIONE DI OSS CAPITOLO 1. LA SCHEDA AUDIO E OSS `/dev/midi00 E un’interfaccia a basso livello al canale MIDI, orientata ai carat- teri come tty (raw mode) e indirizzata ad applicazioni che non richiedono una sincronizzazione in tempo reale come i sequencer (pu` essere usata o per inviare sysex, per caricare campioni sugli strumenti o per effettuare il dump dei canali); se presenti, possono essere gestite altre porte MIDI con /dev/midi01, /dev/midi02 e /dev/midi03/dev/sndproc Rappresenta l’interfaccia interna di accesso a un eventuale co- processore presente sulla scheda audio; pu` essere una soluzione tempo- o ranea, da eliminare in seguito/dev/sndstat Questo, a differenza degli altri, ` un device file a sola lettura: e stampa informazioni diagnostiche riguardo la configurazione di OSS in for- ma leggibile agli umani, ma se ne sconsiglia l’utilizzo da parte dei programmi perch` in futuro il formato delle informazioni da esso fornite potrebbe cam- e biare; non ci si far` pi` riferimento d’ora in poi. L’output ha una sezione a u per ogni categoria di dispositivi, e questi sono numerati nell’ordine in cui il driver li inizializza (che non ` fisso, per cui ` meglio non fare assunzioni a e e priori); un esempio del suo utilizzo ` il seguente: e ~>cat /dev/sndstat Sound Driver:3.5.4-960630 Kernel: Linux papo 2.0.32 #1 Wed Nov 19 00:46:45 EST 1997 i486 Config options: 0 Installed drivers: Card config: Audio devices: 0: Sound Blaster 16 (4.13) Synth devices: 0: Yamaha OPL-3 Midi devices: Timers: 0: System clock Mixers: 0: Sound Blaster OSS consente di avere pi` schede audio installate nel computer, il che si utraduce in un maggior numero di device file indirizzabili, elencati nell’output 8
  14. 14. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.3. INIZIALIZZAZIONE DI OSSdi /dev/sndstat: l’esempio sopra rivela che il computer ha solo /dev/dsp0,ma in generale con pi` DSP li si potrebbe indirizzare operando su /dev/dspn; uanalogamente per il mixer su /dev/mixern, etc.1.3 Inizializzazione di OSSIl minimo insieme di header file da includere ` rappresentato da stdio.h (per le efunzioni di libreria tipo printf() e perror()), unistd.h, fcntl.h (per open(),ioctl(), read(), write() e close()) e sys/soundcard.h (le definizioni vere eproprie per la libreria di OSS). Adesso si riporter` uno scheletro di codice C per l’apertura di un device file di aOSS (nell’esempio ` /dev/dsp, ma potrebbe essere /dev/mixer, . . . ); nei succes- esivi Capitoli lo si dar` come sottinteso man mano che si introducono le primitive aper una gestione vieppi` sofisticata della scheda audio. u#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/soundcard.h>int main(){ int dspfd; /* File descriptor per /dev/dsp */ dspfd = open("/dev/dsp", O_WRONLY); /* Apre il device */ if (dspfd == -1) { perror("/dev/dsp"); /* Gestione errore */ exit(-1); } /* Qui ci puo’ andare tutto il codice per sfruttare il */ /* device file, con le ioctl() necessarie a configurare */ /* il driver poste prima delle read() o write() */ close(dspfd); /* Chiusura del device file */ return 0;} Il secondo argomento di open() ` la modalit` di accesso al device file, che nel e acaso di OSS pu` essere una fra le seguenti: oO RDONLY Accesso in sola lettura (read() o ioctl())O WRONLY Accesso in sola scrittura (write() o ioctl())O RDWR Accesso in lettura/scrittura (read(), write() o ioctl()) 9
  15. 15. 1.3. INIZIALIZZAZIONE DI OSS CAPITOLO 1. LA SCHEDA AUDIO E OSS Per read() e write() i flag O_NDELAY o O_NONBLOCK, affinch´ le operazioni di eI/O sul device file non blocchino il processo chiamante, non hanno effetto: se ilprocesso effettua una read() e i campioni richiesti non sono ancora disponibili,questo viene messo in wait finch´ l’operazione ` completata (analogamente con e euna write(), se il buffer del driver non ha spazio sufficiente per i campioni chesi vogliono riprodurre). Per la open() il funzionamento ` sempre del tipo O_NDELAY; se fallisce il efile descriptor ` posto uguale a -1 e la macro errno ` impostata a un oppor- e etuno valore (questa ` messa a disposizione del programmatore per mezzo di e#include <errno.h>).1.3.1 Gestione degli erroriI codici di errore pi` comuni riportati da errno sono i seguenti: uENOENT Il device file che si ` tentato di aprire non ` presente in /dev e eENODEV Esiste il device file in /dev, ma il driver non ` stato caricato dal e kernel (si pu` controllare con cat /dev/sndstat o dmesg | more) oENOSPC Esiste il device file in /dev, ma il driver non ` stato in grado di e allocare la memoria per il buffer DMA tramite sound_mem_init() durante il boot del sistema; il modulo del driver dovrebbe essere uno dei primi ad esser caricato dal kernel, in modo da garantire tale operazione anche in caso di poca memoria installataENXIO Esiste il device file in /dev e il driver ` presente nel kernel, ma non e esiste il dispositivo hardware che si tenta di indirizzare (ad esempio, perch´ e la configurazione del driver non corrisponde all’hardware audio)EINVAL Uno degli argomenti della chiamata a una funzione non ha un valore validoEBADF Il file descriptor non si riferisce a un device file aperto, una read() ` e stata rivolta a un device file aperto con O_WRONLY o una write() ` stata e rivolta a un device file aperto con O_RDONLYEBUSY Solo un processo alla volta pu` gestire /dev/dspn e /dev/audion, per o cui si verifica se un altro processo (anche appartenente allo stesso utente) tenta di accedervi (si verifica anche se l’IRQ o il canale DMA sono occupati); pu` essere gestito dal programma tentando di riaprire il device file che ha o causato l’errore dopo qualche tempo, ma non ` garantito che esso divenga e mai disponibile `EINTR E ritornato da read() o write() qualora queste siano risultate bloccan- ti e durante lo stato di wait il processo utente abbia ricevuto un signal() 10
  16. 16. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.3. INIZIALIZZAZIONE DI OSSEAGAIN La risorsa a cui si ` cercato di accedere ` temporaneamente non e e disponibile (ad esempio, si ` cercato di scrivere su un buffer pieno o leggere e da un buffer vuoto con il device file aperto in O_NONBLOCK)EACCES Per i device /dev/dspn e /dev/audion l’accesso ` consentito solo al e root (a meno che il sistema sia stato configurato in altro modo), e questo errore si verifica se un utente normale cerca di accedere a tali device file; questa ` una misura di sicurezza per impedire che, ad esempio, qualora il e computer sia connesso in rete e abbia un microfono qualcuno possa ascoltare remotamente le conversazioni che si svolgono nella stanza ove si trova il computer Un error handler un po’ pi` sofisticato potrebbe rassomigliare a: uif ((dspfd = open("/dev/dsp2", O_WRONLY)) == -1) { switch (errno) { case ENOENT: perror("/dev/dsp2"); exit(-1); case EBUSY: close(dspfd); /* Aspetta un po’ per riaprire */ sleep(10); if (dspfd = open("/dev/dsp2", O_WRONLY)) == -1) { perror("/dev/dsp2"); exit(-1); } break; default: perror("Altro tipo di errore"); fprintf(stderr, "Errore numero: %dn", errno); exit(-1); }} Per quanto invece riguarda il seguito di questo lavoro, si demander` la gestione adegli errori a una semplice routine del tipo:void errore(const char *msgerr){ perror(msgerr); exit(-1);} Sarebbe corretto mettere un error handler non solo dopo una open(), ma an-che dopo read() o write() per verificare se siano stati letti o scritti il numerocorretto di byte; tuttavia nella sintesi in tempo reale ci` tende a rappresentare ocicli di CPU sprecati. Invece dopo una ioctl() conviene controllare quasi ob-bligatoriamente il valore ritornato dal driver nell’ultimo dei suoi argomenti, pervedere cosa si riesce a ottenere rispetto a quanto richiesto dal programmatore. 11
  17. 17. 1.3. INIZIALIZZAZIONE DI OSS CAPITOLO 1. LA SCHEDA AUDIO E OSS Un altro buon accorgimento di programmazione ` di installare un exit handler ee/o un signal handler subito dopo una open() riuscita: il primo pu` essere utile o 10per operazioni di routine alla chiusura del programma (regolare o in seguito aexit()), il secondo pu` gestire i segnali impostati da altri processi, dal kernel oo dal processo stesso. Per una dettagliata descrizione di questi argomenti siveda [10].1.3.2 L’exit handlerUn exit handler richiede la funzione di libreria atexit(), disponibile in segui-to a #include <stdlib.h>. Essa registra le funzioni di tipo void f() date inargomento come exit handler (max 32), venendo richiamate nell’ordine inversorispetto a quello con cui sono state registrate; atexit() restituisce 0 se la regis-trazione ` stata possibile, altrimenti -1 con errno==ENOMEM (memoria insufficiente eper aggiungere la funzione). Nell’esempio seguente si dimostra l’utilizzo di atexit() chiudendo un devicefile all’uscita dal programma (anche se ci` non ` strettamente necessario per o equanto prima affermato):#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <sys/soundcard.h>int dspfd; /* Variabile globale */void Messaggio() /* Chiamata per prima */{ puts("Premi <Invio> per chiudere /dev/dsp..."); getchar();}void ChiudiTutto() /* Chiamata per ultima */{ close(dspfd); puts("Fine del programma");}void errore(const char *msgerr) /* Gestione degli errori */{ perror(msgerr); 10 Linux svuota i buffer di I/O e chiude automaticamente i device file rimasti eventualmenteaperti prima che il processo termini, tramite librerie a livello utente o tramite kernel 12
  18. 18. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.3. INIZIALIZZAZIONE DI OSS exit(-1);}int main(){ if ((dspfd = open("/dev/dsp", O_RDONLY)) == -1) errore("/dev/dsp"); if (atexit(ChiudiTutto) == -1) /* Registrata per prima */ errore("ChiudiTutto()"); if (atexit(Messaggio) == -1) /* Registrata per ultima */ errore("Messaggio()"); return 0; /* Uscita dal programma */} L’exit handler ` richiamato in seguito ad exit(), abort()11 , return o alla econsegna di un segnale la cui azione di default ` di uccidere il processo; l’output edel programma sarebbe:Premi <Invio> per chiudere /dev/dsp...Fine del programma Per evitare la chiamata all’exit handler lo standard POSIX.1 (1990) prevede_exit(), che inoltre evita lo svuotamento dei buffer prima della chiusura dei file.1.3.3 Il signal handlerUn signal handler funziona in modo molto simile ad un exit handler: previo#include <signal.h>, si usa la funzione di libreria signal() per registrare dellefunzioni (non di libreria) che hanno il compito di reagire a segnali provenienti daaltri processi o dallo stesso processo12 (rispettivamente generati tramite le funzionidi libreria kill() e raise()). In signum.h sono definiti una trentina di segnali che si conformano ad ANSI,POSIX, System V e BSD 4.2, per i quali esistono delle disposizioni di default(ci` equivale a signal(<segnale>, SIG_DFL)); se si vuole ignorare un partico- olare segnale si pu` porre nel codice signal(<segnale>, SIG_IGN). La signal() oritorna il valore precedente del signal handler o SIG_ERR se si verifica un errore. 11 Viene impostato un segnale SIGABRT al processo chiamante: non ` ignorabile o bloccabile eda un signal handler 12 Un segnale ` definibile come un’interruzione asincrona software nel flusso di un processo: eesso ` “impostato” dal processo che lo genera ed ` “consegnato” al processo che lo riceve; il e emodo in cui quest’ultimo reagisce al segnale si chiama “disposizione” 13
  19. 19. 1.4. SCRITTURA DI CODICE PORTABILE CAPITOLO 1. LA SCHEDA AUDIO E OSS Per esempio, se si vuole che il processo reagisca a un segnale di interruzione(SIGINT) e a un segnale di terminazione del programma (SIGTERM) con unadisposizione diversa dalla predefinita, all’inizio di main() si potr` porre: asignal(SIGINT, SignalHandler); /* Le funzioni possono essere */signal(SIGTERM, SignalHandler); /* uguali o diverse */ove SignalHandler ` una funzione del tipo: evoid SignalHandler(int segnale) /* Il segnale invocante */{ /* e’ passato all’handler */ switch (segnale) { case SIGINT: case SIGTERM: puts("SIGINT o SIGTERM"); exit(0); default: }}il processo relativo termina se da shell di comando si digita kill -s SIGINT <PID>o kill -s SIGTERM <PID>, ove <PID> ` l’identificatore del processo (visualizz- eabile tramite il comando ps). Sono da tenere presenti i seguenti fatti: • non possono essere variate le disposizioni di SIGKILL e SIGSTOP (signal() ritorna EINVAL) • il comportamento di un programma ` indefinito se sono ignorati SIGFPE, e SIGILL o SIGSEGV • ignorare il segnale derivante dalla divisione intera per zero ha un compor- tamento indefinito, che potrebbe condurre a un blocco del computer • per certi segnali la disposizione di default implica la terminazione del pro- cesso e il salvataggio dell’area dati e heap in un file core a fini di debug; altri provocano la semplice terminazione del processo o sono ignorati • a differenza di BSD, Linux non ridispone il signal handler a SIG_DFL dopo la consegna di un segnale Si veda man 7 signal per una dettagliata descrizione dei segnali e della lorodisposizione di default, e in ogni caso [10] per una gestione pi` sofisticata. u1.4 Scrittura di codice portabileDi seguito sono elencati alcuni consigli per la scrittura di programmi che sianoportabili sotto i vari sistemi operativi per cui sia stato portato anche OSS: 14
  20. 20. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.4. SCRITTURA DI CODICE PORTABILE • Come si vedr` nei successivi Capitoli, conviene usare delle specifiche macro a per impostare dei parametri, ad esempio del mixer, tramite ioctl() (queste schermano i dettagli dell’implementazione dei parametri per le future ver- sioni del driver); in particolare bisognerebbe controllare se ` adeguato il e valore ritornato nell’ultimo argomento (per le chiamate che lo prevedono) ` • E meglio riferirsi a un link simbolico per un device piuttosto che utilizzare un riferimento assoluto, ad esempio usando /dev/dsp al posto di /dev/dsp0; ci` d` flessibilit` all’utente per poter far puntare i link simbolici ad altri o a a device file, se questi garantiscono migliori risultati (i programmi dovrebbero sfruttare i nomi “veri” solo se resi facilmente configurabili) • Non bisogna sfruttare delle caratteristiche non documentate (in quanto obsolete — scompariranno in futuro — o non ancora ben testate) • L’appesantimento di un programma con caratteristiche al di fuori dell’essen- ziale o con “trucchi” pu` compromettere la compatibilit` del codice con le o a future versioni del driver • Se si utilizza la risoluzione a 16 bit bisogna fare attenzione che la CPU memorizzi i campioni come il DSP della scheda audio, cio` coincida per e entrambi la codifica big endian o little endian; in tal senso bisogna evitare di accedere ai campioni a 16 bit ciecamente come signed short • Non bisogna fidarsi delle impostazioni di default di un device (anche perch` e potrebbero essere state modificate da un precedente processo); ad esempio, anche se il default per /dev/dsp ` 8 kHz/8 bit unsigned/mono, molte schede e non supportano la frequenza di campionamento di 8 kHz e si corre il rischio di ottenere solo rumore con le future schede audio a 24 bit; analogamente, non bisogna assumere per /dev/sequencer il clock di default di 100 Hz (Linux/Alpha ha un clock di 1024 Hz), mentre non ci sono valori di de- fault per /dev/music (bisogna sempre impostare per primi i parametri di temporizzazione) • Non si devono scrivere programmi che funzionano solo a 16 bit, poich´ molte e schede vecchie sono a 8 bit: campioni da 16 bit riprodotti su queste danno luogo solo a rumore ad alto volume • Non si deve dare per scontato che per ogni scheda audio ci sia /dev/mixer (non lo possiedono le pi` vecchie, o quelle non ancora pienamente support- u ate, o le schede audio completamente digitali); non tutti i mixer hanno un controllo di master volume (ma se ce l’hanno bisogna tenere presente che questo influenza il volume di tutti i canali), inoltre si deve sempre testare la presenza di un canale prima di cercare di indirizzarlo (ad esempio, non tutte le schede possiedono un sintetizzatore interno e/o una porta MIDI) 15
  21. 21. 1.5. ANATOMIA DEL DRIVER CAPITOLO 1. LA SCHEDA AUDIO E OSS • Non si deve usare il full duplex senza prima controllare che la scheda audio supporti tale modalit`a • I device audio non devono essere tenuti aperti quando non sono richiesti, altrimenti altri programmi non vi possono accedere; in tal senso un pro- gramma dovrebbe gestire flessibilmente le situazioni di EBUSY, ad esempio riprovando ad accedere dopo qualche tempo al device file1.5 Anatomia del driverOSS sfrutta il Direct Memory Access (DMA) per trasferire i campioni dalla schedaaudio a un’opportuna area di RAM e viceversa: questa in genere non coincidecon il buffer del processo che li elabora, per cui il driver deve copiare i campionidal/al buffer DMA a/da quest’ultimo13 . Nei PC–compatibili della copia se ne occupa la CPU, dal momendo che ilDMA Controller (DMAC) compatibile Intel 8237 ha dei pesanti limiti: non pu` oeffettuare copie fra le porte di I/O o fra memoria e memoria; inoltre il bufferDMA deve risiedere al di sotto dei primi 16 MB di RAM per le schede audioISA (non per le PCI), poich´ questo ` il limite di indirizzamento del bus, e deve e eessere un blocco di memoria non frammentato che inizia e finisce nella stessapagina DMA. Quest’ultima ha dimensione di 64 kB per i canali 0÷3 a 8 bit e128 kB per i canali 5÷7 a 16 bit: ci` rende difficile usare direttamente il buffer olocale del processo come buffer DMA con le schede ISA e pi` di 16 MB, poich´ u edovrebbe risiedere al di sotto del limite dei 16 MB; tuttavia i nuovi controller nelleperiferiche bypassano l’Intel 8237 completamente (fly–by), per cui in particolaricondizioni si pu` arrivare a mappare il buffer DMA all’interno dell’area dati del oprocesso (ci` ` sempre possibile con le schede PCI). oe L’elaborazione dei campioni da parte del processo deve avvenire almeno unpo’ pi` velocemente del ritmo al quale il DMAC trasferisce i campioni, affinch´ u enon ci siano pause in fase di campionamento o riproduzione. Se ci` si verifica obisogner` usare una frequenza di campionamento inferiore all’attuale, o usare un aformato audio pi` “compatto” per i campioni, in modo da ridurre la quantit` di u abyte trasferiti dal DMAC. Linux ha il “problema” di essere multiutente e multiprogrammato, per cuii processi competono per l’utilizzo della CPU e un processo a pi` alta pri- uorit` potrebbe porre il processo che sfrutta i servizi di OSS in stato di wait aper diversi ms: in tal modo il tempo che questo ha per elaborare i campioni 13 Alcune schede possono auto–iniziare il trasferimento senza attendere risposta dal driver,usando il DMAC in modalit` auto–restart (ci` non ` supportato da tutti i sistemi operativi, ad a o eesempio da BSD) 16
  22. 22. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.5. ANATOMIA DEL DRIVERdiminuisce. In pratica ci deve essere abbastanza spazio nel buffer DMA pergarantire l’operativit` per il tempo di wait14 . a OSS gestisce il buffer DMA con la tecnica del multi–buffering: in praticaquesto ` diviso in frammenti di uguale dimensione, per default calcolata dal driver ein modo tale che la latenza15 sia attorno a 0.5s per la riproduzione e attorno a 0.1sper il campionamento. In tal modo ` possibile aumentare la dimensione del buffer esenza influire sulla latenza stessa poich´ il DMAC lavora solo su un frammento eper volta, mentre l’applicazione legge o scrive sul resto del buffer. memoria wait Scheda audio Kernel Processo 1111 0000 DMAC 1111 0000 bus ISA o PCI OSS buffer audio driver read() o write() buffer DMA Figura 1.5: Schema di utilizzo del multi–buffering1.5.1 Scrittura sul buffer DMAIn fase di riproduzione, quando il programma chiama write() per la prima voltadopo l’apertura del device, si verificano i seguenti eventi: • il driver programma la scheda audio con i parametri di campionamento predisposti (risoluzione, numero di canali e frequenza) • di default ` calcolata la dimensione adeguata per un frammento, se tramite e un’opportuna chiamata ioctl() non se ne ` stabilita un’altra e • viene iniziato il riempimento del primo frammento del buffer con i dati passati dalla write() • se il primo frammento ` stato riempito completamente, il DMAC ne inizia e il trasferimento alla scheda audio 14 Alcune schede dispongono di RAM locale per la riproduzione, ma prima che questa possaavvenire i campioni devono esservi trasferiti (per la Gravis UltraSound ci sono 256 kB percanale, ovvero sono “coperti” 2.9 s di suono continuo in modalit` 16 bit/stereo/44.1 kHz) a 15 La latenza ` il tempo che il processo deve aspettare per avere accesso a un frammento ein campionamento o perch´ questo venga suonato in riproduzione quando il buffer ` pieno; e eessa dipende dal data rate, che ` la quantit` di dati che il DMAC deve trasferire nell’unit` di e a atempo (per esempio, con un campionamento 16 bit/stereo/44.1 kHz il data rate ` 2 · 2 · 44.1 = e176.4 kB/s), nonch´ dalla dimensione del frammento e 17
  23. 23. 1.5. ANATOMIA DEL DRIVER CAPITOLO 1. LA SCHEDA AUDIO E OSS • il driver copia il resto dei dati nel buffer, eventualmente riempiendo altri frammenti; se tutti i frammenti del buffer sono stati riempiti il processo relativo al programma che ha chiamato la write() ` messo in stato di wait e finch´ non ` libero almeno un frammento (condizione di overrun) e e Alle successive chiamate di write() i dati sono immagazzinati nel buffersecondo la disponibilit` di frammenti liberi. a L’overrun si verifica normalmente per un processo che scriva i campioni nelbuffer pi` velocemente di quanto vengano riprodotti. Se al contrario il processo u` leggermente pi` lento a scrivere i campioni rispetto alla velocit` con la qualee u asono riprodotti si verifica la condizione di underrun, per uno dei seguenti motivi: • l’applicazione ` troppo lenta nell’elaborazione dei campioni (perch´ la CPU e e ` troppo lenta rispetto al data rate richiesto o ci sono troppi processi in e esecuzione che competono per la CPU) • ci sono leggere variazioni nel tempo di CPU ricevuto (un’applicazione gen- eralmente ben funzionante pu` occasionalmente andare in underrun) o • l’applicazione tenta di lavorare troppo in tempo reale (frammenti pi` piccoli u decrescono la latenza, tuttavia bisogna sempre scrivere altri campioni prima che il buffer si svuoti) Un underrun provoca in genere un difetto udibile nel segnale riprodotto: pu`oessere una breve pausa, un “click” o la ripetizione di una parte del segnale(looping); se quest’ultima si verifica con frequenza uniforme si avvertir` un tono asovrapposto al segnale riprodotto, con frequenza pari a quella con cui si verifical’underrun.1.5.2 Lettura dal buffer DMAIn fase di campionamento, quando il programma chiama read() per la primavolta dopo l’apertura del device, si verificano i seguenti eventi: • il driver programma la scheda audio con i parametri di campionamento predisposti (risoluzione, numero di canali e frequenza) • di default ` calcolata la dimensione adeguata per un frammento, se tramite e un’opportuna chiamata ioctl() non se ne ` stabilita un’altra e • sono attivati il processo di campionamento da parte della scheda audio e il trasferimento dei campioni nel primo frammento del buffer • il processo ` messo in wait finch´ non ` riempito un numero di frammenti e e e che forniscono globalmente una quantit` di campioni maggiore o uguale a a quella richiesta 18
  24. 24. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.6. SCHEDE AUDIO ISA E PCI • i campioni richiesti sono copiati nel buffer del processo; gli eventuali cam- pioni in pi` rimangono nel buffer DMA u Le read() successive funzionano come sopra, senza che sia necessario ripredis-porre la scheda audio. Un overrun in campionamento si verifica se il buffer ` completamente riempito: ein tal caso gli ulteriori campioni sono scartati; le ragioni per cui si verifica sonosimili a quelle per cui si verifica in riproduzione.1.6 Schede audio ISA e PCIL’approccio seguito in questo lavoro ` di essere il pi` indipendenti possibile dal- e ul’hardware, in modo da poter creare dei programmi che girino su ogni piattaformaper cui ` stato portato OSS con tutt’al pi` una semplice ricompilata del codice e usorgente. Tuttavia si vogliono elencare i motivi per i quali le schede audio PCIsono superiori alle schede audio ISA (al di l` della qualit` audio); al momento in a acui si scrive (1999) la quasi totalit` delle schede audio in commercio sono PCI, ma afino a un anno fa erano quasi tutte ISA: un musicista professionista dovrebbe pren-dere in considerazione l’acquisto di una scheda audio PCI, anche se attualmenteOSS non supporta del tutto le nuove caratteristiche, come l’audio 3D. Si elencheranno ora le differenze fra ISA e PCI pertinenti le schede audio: • Il bus ISA ha un clock nominale di 8 MHz, il che darebbe un throughput teorico di 16 MB/s; in realt`, a causa di overhead vari nella gestione dei seg- a nali, nonch´ il fatto che sono richiesti due cicli di clock per il trasferimento e dei dati, il throughput si aggira attorno ai 5 MB/s. Se si guarda la quantit` a di dati da trasferire per una scheda che campiona a 16 bit/stereo/44.1 kHz (circa 176 kB/s) questo throughput appare adeguato, ma si pu` verificare o che il DMA blocchi l’accesso della CPU al bus durante il trasferimento dei campioni o se la richiesta d’interrupt ` occupata (con ISA le IRQ non sono e condivisibili), il che pu` causare click nel suono in sistemi pesantemente o caricati. La capacit` di indirizzamento massima per ISA ` di 16 MB, per a e cui sono difficilmente applicabili le tecniche di allocazione del buffer DMA nel buffer del processo, che dovrebbe risiedere al di sotto di tale limite anche per sistemi con pi` RAM. Pu` inoltre risultare difficile la configurazione di u o una scheda audio, soprattutto con OSS/Free se ` PnP.e • Le specifiche PCI 2.1 consentono un clock sul bus fino a 66 MHz, con un throughput teorico di 264 MB/s, mentre in pratica ci si aggira intorno ai 108 MB/s; con un clock sul bus di 33 MHz questi valori si dimezzano. Gli interrupt sono condivisibili, per cui con la tecnica dell’interrupt binding, se si verificano pi` interrupt contemporaneamente, questi vengono raggrup- u pati e serviti in base alla priorit` (e Linux distingue fra fast interrupt — a quelli che richiedono un salvataggio del contesto parziale, come la richiesta 19
  25. 25. 1.7. FILE SYSTEM E DEVICE FILE CAPITOLO 1. LA SCHEDA AUDIO E OSS di un servizio DMA — e gli interrupt normali, con salvataggio completo del contesto — riducendo in tal modo l’overhead). Il PCI consente il busmas- tering multiplo (con due busmaster), ovvero due arbitri nella gestione del bus, il che si traduce nell’accesso contemporaneo di CPU e DMA al bus se le aree di memoria interessate non coincidono; l’indirizzamento ` a 32 bit, e per cui sono applicabili le tecniche di allocazione del buffer DMA nel buffer ` del processo. E inoltre pi` semplice la configurazione delle periferiche PCI, u in quanto dopo il boot queste negoziano fra loro, in pratica autoallocandosi. Queste ed altre considerazioni, come la tendenza delle nuove schede audioad incrementare la frequenza di campionamento, spingono a concludere che unascheda audio PCI pu` risultare fino a dieci volte pi` efficiente di una scheda ISA. o u1.7 File system e device fileCome si ` avuto occasione di affermare precedentemente, OSS ` un driver che e efornisce al programmatore la possibilit` di gestire audio e MIDI tramite opportuni adevice file inseriti nella struttura dell’albero monolitico del file system di Linux.Ogni device file ` caratterizzato da un major number e da un minor number : il eprimo ` utilizzato come indice in una tabella del kernel per identificare il tipo edi driver che deve gestire un dispositivo hardware, il secondo ` passato al driver estesso per identificare l’unit` su cui agire (classe del device). a In Linux il major number per OSS ` 14, ma per altri sistemi operativi potrebbe eessere diverso. Il minor number pu` essere codificato tramite un solo byte: in otal caso, come da figura 1.6, i quattro bit meno significativi identificano la classedel dispositivo, mentre i quattro bit pi` significativi identificano un dispositivo uall’interno di una stessa classe; ne consegue che ci possono essere fino a sedicidispositivi dello stesso tipo per ogni classe. Tipo device Classe mixer 0 sequencer 1 midi 2 7 4 3 0 dsp 3 num. device classe audio 4 dspW 5 1 byte sndstat 6 riservato 7 music 8 sndproc 9 Figura 1.6: Codifica del minor number di un device file di OSS 20
  26. 26. CAPITOLO 1. LA SCHEDA AUDIO E OSS 1.8. LE VERSIONI DI OSS Ad esempio, /dev/midi00 identifica il primo dispositivo di classe 2 (MIDI),per cui ` il numero del device ` 0: ci` implica che il minor number per il device file e e orelativo ` 0x02 (2 in decimale). Analogamente per /dev/midi01 il minor number eper il device file relativo sar` 0x12 (18 in decimale), per /dev/midi02 sar` 0x22 a a(34 in decimale) e per /dev/midi03 sar` 0x32 (50 in decimale). a Anche se nelle odierne distribuzioni di Linux non ci dovrebbero essere problemidel genere, se un device file dovesse mancare ` possibile crearlo effettuando il login ecome root e dando il seguente comando:mknod -m <permessi> <nome device file> c 14 <classe del device>ad esempio, il nome del device file potrebbe essere /dev/music e la classe sarebbe 8;<permessi> ` un numero ottale che predispone i permessi di accesso al file, che epu` essere posto pari a 666 per accesso in lettura/scrittura da parte di tutti gli outenti (vedere man chmod).1.8 Le versioni di OSSIl riconoscimento della versione di OSS in uso varia secondo che si stia utilizzandouna versione precedente o successiva alla 3.6. Ad esempio, la versione 3.5.4 disoundcard.h definisce le seguenti macro:#define SOUND_VERSION 350#define UNIX_SOUND_SYSTEMmentre nella versione 3.8.2 sono definite le seguenti altre macro:#define SOUND_VERSION 0x030802#define OPEN_SOUND_SYSTEMSOUND_VERSION contiene il numero di versione, con formato che varia secondo chesia definito UNIX_SOUND_SYSTEM o OPEN_SOUND_SYSTEM. Dalla versione 3.6 in poi ` possibile usare il seguente frammento di codice, che einterroga direttamente il driver per ricavare il numero di versione (` pi` affidabile e uche ricavarlo da SOUND_VERSION):int versione;if (ioctl(dspfd, OSS_GETVERSION, &versione) == -1) { /* Versione precedente alla 3.6: errno==EINVAL */} Il seguente frammento di codice ricava i numeri di versione e release indipen-dentemente dalla versione di OSS utilizzata:int versione, release1, release2, tmpver;#ifdef UNIX_SOUND_SYSTEM 21
  27. 27. 1.8. LE VERSIONI DI OSS CAPITOLO 1. LA SCHEDA AUDIO E OSS versione = SOUND_VERSION / 100; release1 = (SOUND_VERSION - versione*100) / 10; release2 = SOUND_VERSION - versione*100 - release1*10;#else /* e’ definito OPEN_SOUND_SYSTEM */ if (ioctl(dspfd, OSS_GETVERSION, &tmpver) == -1) errore("OSS_GETVERSION"); versione = (tmpver & 0x00ff0000) >> 16; release1 = (tmpver & 0x0000ff00) >> 8; release2 = tmpver & 0x000000ff;#endif 22
  28. 28. Capitolo 2IL MIXER E LA GESTIONEDEI CANALI2.1 Descrizione di /dev/mixerNon tutte le schede audio possiedono un mixer: nella fattispecie possono nonaverlo le schede pi` vecchie, quelle non ancora pienamente supportate, quelle uprofessionali e le completamente digitali. Anche se il mixer ` mancante si pu` e osempre aprire /dev/mixer, ma un’eventuale ioctl() ritorna errno==ENXIO. Nella Sezione 1.3 si ` fornito uno scheletro di codice C per l’apertura e la echiusura di un device file; si ` scritto che fra la open() e la close() di questo eci possono essere delle read(), write() o ioctl(). /dev/mixer ` un device file eatipico, in quanto non accetta operazioni di read() o write() e l’unica primitivautilizzabile ` ioctl(): infatti il mixer svolge solo un lavoro di gestione dei canali ecambiando la configurazione della scheda audio, praticamente non impiegandorisorse di calcolo per operare. A differenza di /dev/dsp e /dev/audio, pi` di un processo alla volta pu` u oaprire /dev/mixer; generalmente si usa O_RDONLY come argomento di open().Le modifiche effettuate alla configurazione del mixer permangono anche dopola chiusura dell’ultimo processo modificante, fino a quando un eventuale altroprocesso non effettuer` nuovi cambiamenti o fino al reboot del computer. All’atto adel boot ` il kernel che si occupa di configurare la scheda audio con dei valori edi default ragionevoli, ma che non dovrebbero comunque essere dati per scontatiper non creare programmi inaffidabili. Solo per il primo mixer, l’uso delle ioctl() per /dev/mixer su questo o su unaltro device di OSS sono equivalenti: ad esempio, se si ` aperto /dev/sequencer ` e einutile aprire anche /dev/mixer per variare la configurazione della scheda audio,basta usare gli ioctl() che si sarebbero utilizzati col secondo direttamente colprimo. ` E importante verificare le capacit` del mixer prima di usarne i canali, in mo- ado da creare programmi che siano portabili per quasi tutte le schede audio. Le 23
  29. 29. 2.2. I CANALI DEL MIXER CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALIdifferenze di comportamento riscontrate dovrebbero essere indicate nella docu-mentazione, evitando descrizioni troppo specifiche nei confronti dei canali, chepossono avere caratteristiche diverse con schede diverse.2.2 I canali del mixerPer i canali del mixer ci si pu` rifare alla metafora delle figure 1.1 e 1.2, per cui oun canale identifica la classe del dispositivo (CD, microfono, . . . ) che a questo` connesso; il programmatore pu` effettuarne la selezione per la riproduzione oe oil campionamento, regolandone il livello di volume (se il dispositivo ` stereo ci esono due livelli di volume indipendentemente controllabili, il che consente di real-izzare il balance). Il volume principale pu` essere mancante (Gravis UltraSound, oMicrosoft Sound System). Sono definiti SOUND_MIXER_NRDEVICES canali, a cui ` associato un numero da e0 a SOUND_MIXER_NRDEVICES-1; un programma non dovrebbe cercare di accederea numeri di canale superiori a quest’ultimo. OSS mette a disposizione del programmatore dei nomi simbolici per ognicanale; quelli definiti in soundcard.h versione 3.5.4 si trovano nella tabella dellaprossima pagina. Ad ogni canale ` associato un int, nella cui rappresentazione in binario (bit- emask ) ` posto a 1 il bit di posizione corrispondente al numero del canale; le ebitmask sono utili con i comandi di gestione della configurazione del mixer. Sempre in soundcard.h sono definiti dei nomi simbolici da dare ai canalitramite le macro:#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", "Line1", "Line2", "Line3"}#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", "line1", "line2", "line3"}la differenza fra i due ` che il primo formato ` adatto per la stampa dei nomi a e evideo quali etichette dei canali, mentre del secondo formato ` pi` adatto l’utilizzo e uquando i nomi dei device audio sono forniti sulla riga di comando di una shell. 24
  30. 30. CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI 2.2. I CANALI DEL MIXER Nomi dei canali Bitmask associate Descrizione SOUND_MIXER_VOLUME SOUND_MASK_VOLUME Livello volume principale SOUND_MIXER_BASS SOUND_MASK_BASS Regolazione toni bassi principale SOUND_MIXER_TREBLE SOUND_MASK_TREBLE Regolazione toni acuti principale SOUND_MIXER_SYNTH SOUND_MASK_SYNTH Livello di uscita sintetizzatore interno (FM, wavetable); per alcune schede ne controlla anche il livello di campionamento SOUND_MIXER_PCM SOUND_MASK_PCM Livello di uscita di /dev/dsp e /dev/audio SOUND_MIXER_SPEAKER SOUND_MASK_SPEAKER Livello di uscita del segnale all’altoparlantino nel PC (se connesso alla scheda audio); su altre schede pu` essere un o generico ingresso mono con qualche altra funzione SOUND_MIXER_LINE SOUND_MASK_LINE Livello di ingresso per Line–In SOUND_MIXER_MIC SOUND_MASK_MIC Livello del segnale microfonico in campionamento o inviato a cuffie e Line–Out; qualche volta il microfono non ` connesso a questo canale, ma e a un line level input della scheda SOUND_MIXER_CD SOUND_MASK_CD Livello del CD Audio–In SOUND_MIXER_IMIX SOUND_MASK_IMIX Recording monitor campionamento; durante tale fase, su alcune schede controlla il volume delle cuffie SOUND_MIXER_ALTPCM SOUND_MASK_ALTPCM Livello di un DSP secondario; nella Pro Audio Spectrum 16 ` il canale e dell’emulazione della Sound Blaster SOUND_MIXER_RECLEV SOUND_MASK_RECLEV Livello di campionamento per tutti i canali (nella Sound Blaster 16 si hanno solo quattro livelli possibili) SOUND_MIXER_IGAIN SOUND_MASK_IGAIN Livello di guadagno di ingresso SOUND_MIXER_OGAIN SOUND_MASK_OGAIN Livello di guadagno di uscita SOUND_MIXER_LINE1 SOUND_MASK_LINE1 Canale generico 1 (aux1); i codec AD1848 e compatibili hanno tre line level input a cui diversi costruttori assegnano funzioni diverse, per cui tali nomi si usano quando il significato preciso di un canale fisico ` sconosciuto e SOUND_MIXER_LINE2 SOUND_MASK_LINE2 Canale generico 2 (aux2) SOUND_MIXER_LINE3 SOUND_MASK_LINE3 Canale generico 3 (line) 25
  31. 31. 2.2. I CANALI DEL MIXER CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI Se in un programma si effettuano le assegnazioni:const char *nome_canale[] = SOUND_DEVICE_LABELS;const char *nome_cmline[] = SOUND_DEVICE_NAMES;allora, ad esempio, nome_canale[SOUND_MIXER_CD] corrisponde a “CD ”, men-tre nome_cmline[SOUND_MIXER_CD] corrisponde a “cd”. Il mixer consente la selezione dei canali da cui effettuare il campionamento,che per buona parte delle schede avviene in mutua esclusione. Il canale di default dopo il boot ` quello del microfono, ma non dovrebbe eessere dato per scontato, poich´ il driver non altera le predisposizioni del mixer ea meno di un comando da programma; un qualche altro processo dopo il bootpotrebbe averle modificate, con tali modifiche che permangono anche dopo la suaterminazione. L’insieme di canali disponibili non ` fisso, ma dipende dalla scheda audio; si epu` verificare che ai canali dello stesso chip mixer costruttori diversi assegnino ofunzioni diverse, per cui bisogner` verificarne caso per caso il reale significato. a Sarebbe meglio non includere funzionalit` di mixer nei programmi se si vuole ala massima portabilit` del proprio codice, demandandole a programmi specializ- azati per le varie schede audio. Nel caso si volesse realizzare un tale programmamixer bisogna ben documentare le sue capacit` se ` sviluppato per una precisa a escheda, altrimenti ` meglio evitare di essere troppo specifici nella documentazione eper non trarre in inganno gli utenti: potrebbero credere che la propria schedaaudio sia diversa da come ` realmente, basandosi su ci` che il programma fa e ovedere.2.2.1 Lettura della configurazioneCome ` stato visto sopra, converrebbe effettuare il controllo sia delle capacit` e adella scheda audio che dell’esistenza o meno dei canali di interesse prima di in-traprendere qualsiasi altra azione; un’operazione di ioctl() fallita (ad esempio,perch´ il canale non esiste) ritorna -1 e errno==EINVAL. e Per effettuare la lettura della configurazione dei canali del mixer il codice ` esimile per tutti i comandi a disposizione:int bitmask;if (ioctl(mixfd, SOUND_MIXER_READ_****, &bitmask) == -1) { /* Il mixer e’ mancante - errno==ENXIO */}ove SOUND_MIXER_READ_**** ` l’identificatore del comando di lettura che ritorna ein bitmask una maschera di bit; questa pu` essere esaminata per determinare le ocapacit` di un canale o del mixer in base al comando dato. a 26
  32. 32. CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI 2.2. I CANALI DEL MIXER Per i canali il controllo si pu` effettuare con: oif (bitmask & (1 << numero_canale)) { /* Il canale possiede la capacita’ in esame */}ove numero_canale ` un intero tra 0 e SOUND_MIXER_NRDEVICES-1 o il nome emnemonico del canale; al posto di (1 << numero_canale) si pu` utilizzare di- orettamente la bitmask ad esso associata. I comandi a disposizione per la lettura della configurazione sono: Comandi Richiesta a OSS SOUND_MIXER_READ_DEVMASK Quali canali sono presenti? SOUND_MIXER_READ_STEREODEVS Quali canali sono stereo? SOUND_MIXER_READ_RECMASK Quali sono i canali campionabili? SOUND_MIXER_READ_RECSRC Qual ` il canale campionabile attivo? e SOUND_MIXER_READ_CAPS Si pu` campionare solo un canale per volta? o Con l’ultimo comando si testa se si possono campionare i canali solo in mutuaesclusione; il controllo si effettua con:if (bitmask & SOUND_CAP_EXCL_INPUT) { /* Campionamento solo in mutua esclusione */} La differenza fra SOUND_MIXER_READ_RECMASK e SOUND_MIXER_READ_RECSRC` che il primo comando ritorna una bitmask con un bit a 1 per ogni canale perecui la scheda audio possiede la capacit` di campionamento, mentre il secondo aritorna una bitmask con un bit a 1 per ogni canale attualmente selezionato peril campionamento (se questo ` possibile in mutua esclusione solo un bit in tutta ela bitmask pu` essere a 1). o2.2.2 Selezione del canale da campionarePer selezionare il canale da cui campionare basta il seguente frammento di codice:int bitmask = SOUND_MASK_****;if (ioctl(mixfd, SOUND_MIXER_WRITE_RECSRC, &bitmask) == -1) { /* Non c’e’ il mixer o il canale */ /* errno==ENXIO oppure EINVAL */}ove SOUND_MASK_**** ` la bitmask associata al canale desiderato. e Nel caso fosse possibile campionare da pi` canali contemporaneamente, li si useleziona ponendo in bitmask un OR aritmetico delle bitmask associate ai canali;ad esempio, per selezionare il campionamento simultaneo da CD e da microfono: 27
  33. 33. 2.3. LIVELLI DI VOLUME DEI CANALI CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALIbitmask = SOUND_MASK_CD | SOUND_MASK_MIC; Se nessun bit ` posto a 1 (bitmask==0x00000000), il driver seleziona il canale edel microfono.2.3 Livelli di volume dei canaliLe schede audio rappresentano il livello di un canale con un numero di bit vari-abile: 3, 8 e anche 16 bit. L’architettura di OSS svincola il programmatore dallaconoscenza dei livelli assoluti di volume introducendo una rappresentazione inpercentuale: il volume di un canale pu` variare fra 0 (spento) e 100 (massimo); ose il canale ` stereo si hanno due di queste percentuali, che possono essere uguali eo meno per realizzare il balance. Per leggere il livello attuale di volume per un canale si sfrutta il seguenteframmento di codice:int volume;if ((ioctl(mixfd, MIXER_READ(numero_canale), &volume) == -1) { /* Non c’e’ il mixer o il canale */ /* errno==ENXIO oppure EINVAL */}ove numero_canale ` un numero compreso tra 0 e SOUND_MIXER_NRDEVICES-1, eoppure il nome mnemonico del canale. Al posto di MIXER_READ(numero_canale)si pu` utilizzare anche SOUND_MIXER_READ_****, con **** nome del canale; ad oesempio, per il microfono ` SOUND_MIXER_READ_MIC. e Il volume ` codificato come in figura 2.1: se il dispositivo ` stereo la codifica dei e ecanali destro e sinistro si trova nella parola meno significativa di volume (interoa 32 bit); i 16 bit della parola pi` significativa sono indefiniti e dovrebbero essere uignorati. Nel byte pi` significativo della LSW c’` il volume del canale destro, nel u ebyte meno significativo il volume del canale sinistro; per i canali mono ` valido esolo il byte meno significativo, essendo l’MSB posto uguale all’LSB dal driver. 31 16 15 8 7 0 XXXXXXXX Destro Sinistro MSW MSB LSB (da ignorare) LSW Figura 2.1: Rappresentazione del volume di un canale stereo 28
  34. 34. CAPITOLO 2. IL MIXER E LA GESTIONE DEI CANALI 2.4. DIPENDENZA DALL’HARDWARE Per estrarre il volume dei canali destro e sinistro si possono sfruttare leseguenti linee di codice:int volume, vol_sinistro, vol_destro;vol_sinistro = volume & 0x000000ff;vol_destro = (volume & 0x0000ff00) >> 8; Inversamente, per costituire una parola di volume:int volume;volume = (vol_destro << 8) | vol_sinistro; Per cambiare il volume si utilizza il seguente frammento di codice:int volume = <valore>;if ((ioctl(fd, MIXER_WRITE(numero_canale), &volume) == -1) { /* Non c’e’ il mixer o il canale */ /* errno==ENXIO oppure EINVAL */}ove numero_canale ` un numero compreso tra 0 e SOUND_MIXER_NRDEVICES-1, eoppure il nome mnemonico del canale. Al posto di MIXER_WRITE(numero_canale)si pu` utilizzare anche SOUND_MIXER_WRITE_****, con **** nome del canale; ad oesempio, per il CD ` SOUND_MIXER_WRITE_CD. e Dopo il cambiamento bisognerebbe verificare se il livello ritornato in volumerisulta di proprio gradimento, dal momento che ` di solito pi` piccolo di quanto e urichiesto; sequenze di scrittura/lettura ripetute (senza cambiare tale variabile) `possono portare al suo azzeramento. E conveniente effettuare la predisposizionedel volume durante l’inizializzazione del programma, ignorando poi il volumeritornato in seguito.2.4 Dipendenza dall’hardwarePer ottenere dal mixer il nome della scheda audio si pu` utilizzare il seguente oframmento di codice:mixer_info info;if ((ioctl(fd, SOUND_MIXER_INFO, &info) == -1) { /* Non c’e’ il mixer - errno==ENXIO */}ove mixer_info ` una struct cos` composta: e ıchar id[16 ] identificatore della scheda audio (in genere un paio di caratteri)char name[32 ] nome per esteso della scheda Ecco un output di esempio per SOUND_MIXER_INFO con una scheda SoundBlaster 16:SBSound Blaster 29

×