View Full Version : [Libreria] Audio
Sapete una libreria audio per C che mi consente di creare un suono dandogli dei dati ( lunghezza , ampiezza , ecc ) ???
Pf aiutatemi :help:
Sapete una libreria audio per C che mi consente di creare un suono dandogli dei dati ( lunghezza , ampiezza , ecc ) ???Personalmente non so se ne esistono di librerie che fanno quello che chiedi.
Partiamo dall'inizio: tu cosa devi fare di preciso??? Devi "sintetizzare" un'onda sinusoidale conoscendone la sua frequenza e ampiezza??
Sapete una libreria audio per C che mi consente di creare un suono dandogli dei dati ( lunghezza , ampiezza , ecc ) ???
Pf aiutatemi :help:
OpenAL?
EDIT: mmmh, forse non fa al caso tuo, se la necessità è solo quella di generare un suono.
Sapete una libreria audio per C che mi consente di creare un suono dandogli dei dati ( lunghezza , ampiezza , ecc ) ???
Pf aiutatemi :help:
Scaricati questa:
questo è il progetto free [tool di sviluppo visual studio net 2003]:
http://www.twork.it/public/oki/guetbook.asp
questo è l'help online
http://www.twork.it/public/oki/oki.htm
è la mia libreria del sound, o meglio, per creare il proprio engine del sound, fatta sopratutto per i videogame, ma è utile per fare qualsiasi cosa. Da come scrivi penso ti sia utile anche per quello che vuoi fare tu.
Devi aver installate le directx
Il codice è free (per scopi non commerciali)
E' anche incluso nella firma.
Questo è l'articolo messo su codeproject:
http://www.codeproject.com/useritems/Oki.asp
In inglese
Il problema della riproduzione di una onda sonora (dati i suoi parametri) si può suddividere in due parti:
- calcolo dei campioni audio
- invio dei campioni ad un dispositivo audio per la riproduzione
Il primo punto lo si risolve con delle semplici operazioni matematiche. Il secondo punto lo si risolve utilizzando delle apposite librerie o API di sistema per riprodurre campioni audio.
Vediamo il primo punto in dettaglio. Per calcolare i campioni si può usare la nota funzione trigonometrica del seno:
f(x) = A * sin (omega * x + phi)
dove omega è 2*pi*f ovvero la pulsazione.
(nel post non si riesce a mettere i simboli speciali, ma si dovrebbe capire)
Visto che non sono un matematico, traduciamo questa cruda formula in un codice "C": nell'esempio verranno generati i primi 1000 campioni a 16 bit di un'onda sinusoidale di frequenza 440 Hz (il "La") usando una frequenza di campionamento di 44100 Hz.
#include <math.h>
...
double freq = 440;
double sampling = 44100;
double omega;
unsigned short campione;
int x;
omega = 2 * M_PI * freq / sampling;
for (x=0; x<1000; x++)
{
campione = (unsigned short) 32768 + 32767 * sin (omega * x);
....
}
L'ampiezza dell'onda, nell'esempio, è la massima possibile su 16 bit.
Sapete una libreria audio per C che mi consente di creare un suono dandogli dei dati ( lunghezza , ampiezza , ecc ) ???
Pf aiutatemi :help:
con questo puoi aiutarti, nei calcoli, la lib serve per generare audio.
Se vuoi generare un onda puoi fare i calcoli aiutandoti con questa chiamata:
frequenza vale per default 22050
hz settalo a 100
lVolumeSound va da 0 a -10000
lBalance va da -10000 a 10000 0 il sound è riprodotto al centro delle casse
long TUO_maxRPM=18000; //fino a 200000 frequency xp
SoundPlay_Sound(n, true, lVolumeSound, ((frequenza*
hz)/(long)TUO_maxRPM), lBalance);
ora con lVolumeSound, frequenza*
hz, lBalance con questi valori, modificabili da te puoi ottenere i dati da usare nel tuo grafico per generare le onde (inoltre con le chiamate 3D sound puoi generare altri tipi di onde tipo il passaggio da una cassa all'altra o il sound che sale o scende su uno specifico altoparlante ).
Tutto questo usando la lib che ti genera i sounds (in quanto la funzione chiamata (come quella sopra l'ho fatta void e non ritorna nessun valore)).
Se invece hai programmato routine con il sound fatto da te allora usa ciò che ti ha detto andbin.
tomminno
10-10-2006, 00:01
#include <math.h>
...
double freq = 440;
double sampling = 44100;
double omega;
unsigned short campione;
int x;
omega = 2 * M_PI * freq / sampling;
for (x=0; x<1000; x++)
{
campione = (unsigned short) 32768 + 32767 * sin (omega * x);
....
}
L'ampiezza dell'onda, nell'esempio, è la massima possibile su 16 bit.
Manca un pò di dithering per mascherare il rumore che crei troncando un double in uno short e qui comincia il difficile, ci si accontenta di una TPDF o si vuole arrivare ad un noise shaping?
Sempre che lo scopo sia di lavorare con l'audio, se invece ci si accontenta di una banale riproduzione un semplicissimo cast va più che bene.
Riprendendo il discorso fatto da andbin, normalmente per emettere un suono ti basta riempire un buffer contenente i valori campionati dell'onda da riprodurre (i campioni appunto) ed inviare tale buffer al driver della scheda audio.
Facendo l'esempio di linux, il cui classico driver OSS prevede l'uso del device /dev/dsp come un normale file su cui fare una "write" (o una read), ti basterà fare questo (l'algoritmo è simile a quello postato da andbin, ma con qualche importante correzione per generare un'onda sinusoidale senza distorsioni):
#define SAMPLE_RATE 48000
int fd_out;
...
void write_sine (void)
{
short buf[SAMPLE_RATE];
unsigned short ampiezza;
double frequenza = 220; /* Nota: La */
double omega; /* Pulsazione */
int x;
omega = 2 * M_PI * frequenza / SAMPLE_RATE;
ampiezza = 20000;
for (x = 0; x < SAMPLE_RATE ; x++)
{
buf[x] = (short)(ampiezza * (sin (omega * x)));
}
if (write (fd_out, buf, sizeof (buf)) != sizeof (buf))
{
perror ("Errore in scrittura sul dispositivo");
exit (-1);
}
}
Come puoi notare, calcolo i campioni di un seno a frequenza 220 Hz (ricordiamo che la funzione sin() calcola valori con argomento in radianti) e ne metto i valori in un buffer, il quale poi viene scritto semplicemente sul dispositivo.
Nel caso di linux, usando il driver OSS (ALSA è compatibile al 100% con questo driver), basta aprire il dispositivo /dev/dsp con una classica open:
fd_out = open ("/dev/dsp", O_WRONLY, 0);
controllare il device con chiamate "ioctl()" sul file descriptor (ne bastano un paio per impostare numero di canali e bit di campionamento), e poi scrivere con una write (come visto nell'estratto di codice precedente) sul file descriptor aperto, proprio come fosse un normale file.
Nel caso di Windows, i passaggi sono gli stessi per campionare l'onda, poi per scrivere il buffer sulla scheda audio devi ottenerne l'handle, appoggiandoti all'API che astrae il driver, ma sostanzialmente l'output è simile al caso linux (le funzioni per aprire un device come la scheda audio penso le trovi su MSDN).
EDIT: Ho calcolato i campioni uno ad uno con la funzione sin(), ma normalmente, per ragioni di efficienza, si usa una "wave table", ossia un buffer con valori precalcolati di un'onda ad una data frequenza, e si riempe il buffer di destinazione leggendo la wave table ed inserendo nel buffer di destinazione tali valori (in base al sampling rate ovviamente).
Il codice che ho postato io non è certamente perfetto. Avrei dovuto ad esempio mettere le parentesi
campione = (unsigned short) (32768 + 32767 * sin (omega * x));
anche se non era comunque questo il problema maggiore e non avrebbe cambiato il calcolo.
Non sono esperto (magari ....) della teoria dei segnali. Comunque è risaputo che la quantizzazione di un segnale porta inevitabilmente ad avere un errore di quantizzazione. Si ha cioè una distorsione del segnale.
Il segnale generato dal mio programma quindi non è più composto solo da una unica frequenza fondamentale di 440 Hz ma contiene anche delle armoniche superiori dovute all'errore di quantizzazione.
Le soluzioni per ridurre l'errore di quantizzazione, ci sono. Un metodo ad esempio è il dithering, accennato da tomminno. Se ben ricordo (ma dovrei documentarmi meglio) consiste nell'aggiungere al segnale un rumore casuale, tale per cui sulla media si riesce a correggere, in parte, l'errore (se non è corretto, non sparatemi :D ).
Comunque, qui si va nella parte un po' più complessa della teoria dei segnali ... e che purtroppo non conosco molto bene o affatto. :(
ma con qualche importante correzione per generare un'onda sinusoidale senza distorsioniE .... quali sarebbero 'ste correzioni?? :stordita:
L'errore di quantizzazione non lo risolvi cambiando nomi alle variabili o aggiungendo qualche parentesi al mio codice.
E .... quali sarebbero 'ste correzioni?? :stordita:
L'errore di quantizzazione non lo risolvi cambiando nomi alle variabili o aggiungendo qualche parentesi al mio codice.
Non parlavo di errori di quantizzazione :) Semplicemente nel codice da te postato, oltre alle parentesi di cui accenavi prima, l'ampiezza della forma d'onda era troppo elevata (generava disturbi), l'onda era traslata sull'asse y così da non permettere anche valori negativi (senza una particolare ragione, a meno di usare unsigned short int come campione... - tra l'altro traslare troppo "verso l'alto" la forma d'onda genera un disturbo), e fondamentalmente non hai previsto un buffer dove mettere i campioni, dal momento che mandare i singoli campioni al dispositivo non genera l'effetto desiderato.
Ovviamente ho provato il tuo codice, ma il segnale generato non era continuo, bensì molto distorto.
EDIT: E' importante che il buffer che contiene i campioni debba essere grande quanto il sampling scelto, per evitare che i gruppi di campioni nel tempo T non siano tra loro "allineati".
EDIT: Seguendo sempre il codice postato prima, si possono fare interessanti esperimenti. Ad esempio, se non si predispone un buffer per i campioni di dimensioni almeno doppie della frequenza dell'onda, si potrà apprezzare il cosiddetto fenomeno di aliasing (dal momento che in questo modo risulta che la frequenza di campionamento non è almeno il doppio della banda del segnale - per quanto la banda di un segnale sinusoidale è formato da due impulsi - e si viola quindi il criterio di Nyqist del campionamento per segnali a banda limitata). Provate ad esempio a settare la frequenza a 880 e SAMPLE_RATE a 300: l'aliasing sarà ben udibile.
Semplicemente nel codice da te postato, oltre alle parentesi di cui accenavi prima, l'ampiezza della forma d'onda era troppo elevata (generava disturbi), l'onda era traslata sull'asse y così da non permettere anche valori negativiVero, ma il mio era un semplice esempio. In quel momento (quando l'ho scritto) non mi ricordavo nemmeno se i valori PCM i driver audio, in genere, li vogliono segnati o non segnati. Poi proprio adesso sono andato a vedere su MSDN e in effetti il formato dei dati è "segnato". ;)
e fondamentalmente non hai previsto un buffer dove mettere i campioni, dal momento che mandare i singoli campioni al dispositivo non genera l'effetto desiderato.Perché era un esempio. :rolleyes: :muro: :muro:
Ovviamente ho provato il tuo codice, ma il segnale generato non era continuo, bensì molto distorto.Beh, non so come l'hai provato ma comunque appena avrò un attimo di tempo proverò su Windows con le funzioni waveOutXXX per riprodurre 'sta benedetta sinusoide. ;)
EDIT: E' importante che il buffer che contiene i campioni debba essere grande quanto il sampling scelto, per evitare che i gruppi di campioni nel tempo T non siano tra loro "allineati".Beh, no alt. Dipende da come usi il buffer e da come procedi con i calcoli!
Nel mio sorgente c'è una variabile 'x' che indica il campione da generare.
Se la frequenza di campionamento è 44100 e tu usi un buffer di 44100 campioni mi sta bene ma se poi finito il buffer ricominci rimettendo la x a 0, no!
In pratica la 'x' deve sempre andare avanti. L'indice nel buffer può, ovviamente, ripartire da 0. Ma in quel caso non ci fregherebbe nulla che il buffer sia grande quanto il sampling scelto!!
Perché era un esempio. :rolleyes: :muro: :muro:
Non per fare polemica, ma il buffer è molto importante, altrimenti il dispositivo non ha un riferimento temporale per il segnale. Altrimenti il sample rate a cosa lo riferisci?
Beh, non so come l'hai provato ma comunque appena avrò un attimo di tempo proverò su Windows con le funzioni waveOutXXX per riprodurre 'sta benedetta sinusoide. ;)
Provato su linux con un semplice programma C, se sei interessato lo posto volentieri (tra l'altro può essere preso come un semplice esempio per usare il sistema sonoro OSS su linux - per quanto è scoraggiato dal moment che occupa il device mentre la maggior parte dei programmi usa ALSA per emettere suoni su più canali).
Beh, no alt. Dipende da come usi il buffer e da come procedi con i calcoli!
Nel mio sorgente c'è una variabile 'x' che indica il campione da generare.
Se la frequenza di campionamento è 44100 e tu usi un buffer di 44100 campioni mi sta bene ma se poi finito il buffer ricominci rimettendo la x a 0, no!
In pratica la 'x' deve sempre andare avanti. L'indice nel buffer può, ovviamente, ripartire da 0. Ma in quel caso non ci fregherebbe nulla che il buffer sia grande quanto il sampling scelto!!
No attenzione! Il buffer è molto importante, come detto prima. Infatti vai a riferire il sampling proprio sul buffer, prorpio per dare un riferimento temporale alla scheda audio. I campioni audio infatti si mandano alla scheda con dei buffer, non inviando singoli campioni (il che non avrebbe appunto senso). Non è importante il valore di x in sè, bensi il suo valore riferito al buffer (che per la scheda audio rappresenta il riferimento temporale del segnale).
EDIT: mi sembra importante indicare che, mandando direttamente i campioni alla scheda (un buffer uguale a 1 insomma) non si sente alcun suono, per i motivi detti prima. La prova sul tuo codice che mi chiedevi prima l'ho fatta sempre con il programma C di cui parlavo, ma sempre considerando un buffer.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.