Differenze tra le versioni di "Apertura del subsistema PCM in modalità Registrazione"
Riga 320: | Riga 320: | ||
percorsoTmp = Temp("filegrezzo") | percorsoTmp = Temp("filegrezzo") | ||
datigrezzi = Open percorsoTmp For Create | datigrezzi = Open percorsoTmp For Create | ||
− | |||
− | |||
− | |||
<FONT color=gray>' ''Imposta la frequenza di campionamento a 44100 hertz:''</font> | <FONT color=gray>' ''Imposta la frequenza di campionamento a 44100 hertz:''</font> |
Versione delle 16:45, 4 gen 2014
Per aprire il sub-sistema PCM di ALSA in modalità "Registrazione" bisognerà dotarsi di un handle specifico e diverso da quello relativo alla modalità in Riproduzione.
Si utilizzerà come parametro stream, che rappresenta la direzione del flusso dei dati audio, della funzione snd_pcm_open il valore espresso dalla costante di ALSA: SND_PCM_STREAM_CAPTURE.
Pertanto l'apertura del dispositivo PCM di ALSA avverrà in modo simile a quella effettuata la Riproduzione audio.
Si dichiarerà all'inizio la libreria specifica di ALSA:
Library "libasound:2"
Bisognerà dichiarare ed instanziare alcuni valori e tipi di dati come i seguenti:
Private handle As Pointer Private device As String = "default" Private Const SND_PCM_STREAM_CAPTURE As Byte = 1
ai quali vanno aggiunti il tipo di formato di campionamento ed il tipo di accesso.
Si dichiarerà con Extern la funzione specifica per l'apertura del sub-sistema PCM di ALSA:
Private Extern snd_pcm_open(handleP As Pointer, nome As String, flusso As Integer, mode As Integer) As Integer
e potremo, quindi, in subroutine richiamare detta funzione per l'uso:
err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_CAPTURE, 0)
Impostazioni generali
Le altre impostazioni sono simili alle impostazioni viste per la modalità in Riproduzione.
Funzione per la registrazione dei dati
Useremo la funzione snd_pcm_readi per un accesso di tipo "interleaved". Tale funzione legge dall'handle del dispositivo PCM di ALSA un numero di dati, indicato dal suo terzo argomento, e li scrive nella variabile buffer che rappresenta il suo secondo argomento.
Ovviamente tale funzione andrà preventivamente dichiarata con la funzione Extern, e potrà essere così espressa in routine:
snd_pcm_readi(handle, buffer, numframes)
Anche in questo caso bisognerà far sì che l'applicazione chiami la funzione di registrazione prima che il buffer di acquisizione della scheda audio sia completamente riempito. Altrimenti ci sarà un sovraccarico del buffer, e verrà sollevato un corrispondente errore di overrun.
Esempi pratici di registrazione audio
Vediamo di seguito un esempio completo per la registrazione di 13 secondi di dati audio con frequenza di campionamento a 44100 hertz, risoluzione a 16 bit e 2 canali:
Private percorsoTmp As String Library "libasound:2" Private Const SND_PCM_STREAM_CAPTURE As Byte = 1 Private Const SND_PCM_FORMAT_S16_LE As Byte = 2 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3 ' int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) Private Extern snd_pcm_open(handleP As Pointer, nome As String, flusso As Integer, mode As Integer) As Integer ' int snd_pcm_hw_params_malloc (snd_pcm_hw_params_t **ptr) Private Extern snd_pcm_hw_params_malloc(ptr As Pointer) As Integer ' int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) Private Extern snd_pcm_hw_params_any(pcmP As Pointer, ptrP As Pointer) As Integer ' int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access) Private Extern snd_pcm_hw_params_set_access(pcmP As Pointer, ptrP As Pointer, accesso As Integer) As Integer ' int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val) Private Extern snd_pcm_hw_params_set_format(pcmP As Pointer, ptrP As Pointer, valformat As Integer) As Integer ' int snd_pcm_hw_params_set_channels_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val) Private Extern snd_pcm_hw_params_set_channels(pcmP As Pointer, ptrP As Pointer, valP As Pointer) As Integer ' int snd_pcm_hw_params_set_frequenza_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) Private Extern snd_pcm_hw_params_set_rate_near(pcmP As Pointer, ptrP As Pointer, valP As Pointer, dirP As Pointer) As Integer ' int snd_pcm_hw_params_set_period_size_near(snd_pcm_t * pcm, snd_pcm_hw_params_t * params, snd_pcm_uframes_t * val, int * dir) Private Extern snd_pcm_hw_params_set_period_size_near(pcmP As Pointer, ptrP As Pointer, valP As Pointer, dirP As Pointer) As Integer ' int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) Private Extern snd_pcm_hw_params(pcmP As Pointer, ptrP As Pointer) As Integer ' int snd_pcm_hw_params_get_period_size(const snd_pcm_hw_params_t * params, snd_pcm_uframes_t * val, int * dir) Private Extern snd_pcm_hw_params_get_period_size(ptrP As Pointer, valP As Pointer, dirP As Pointer) As Integer ' int snd_pcm_hw_params_get_period_time(const snd_pcm_hw_params_t * params, snd_pcm_uframes_t * val, int * dir) Private Extern snd_pcm_hw_params_get_period_time(ptrP As Pointer, valP As Pointer, dirP As Pointer) As Integer ' snd_pcm_sframes_t snd_pcm_readi (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) Private Extern snd_pcm_readi(pcm As Pointer, buffS As Short[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim handle As Pointer Dim device As String = "default" Dim err, fc, dr, cicli As Integer Dim params As Pointer Dim buffer As New Short[128] Dim frames, b As Byte Dim datigrezzi As File ' Creiamo il file che ospiterà i dati grezzi audio registrati dall'applicativo: percorsoTmp = Temp("filegrezzo") datigrezzi = Open percorsoTmp For Create datigrezzi.Close datigrezzi = Open percorsoTmp For Write Append '''''''''''''''''''''''''''''''''''''''' ' Apre il sub-sistema PCM di ALSA per la registrazione: err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_CAPTURE, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) ' Alloca un oggetto di parametri hardware: snd_pcm_hw_params_malloc(VarPtr(params)) ' Imposta valori predefiniti: snd_pcm_hw_params_any(handle, params) ' == Imposta i parametri prescelti == ' Imposta la modalità "Interleaved": snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) ' Imposta il formato di campionamento a 16-bit little-endian: snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE) ' Imposta il numero di canali a 2 (stereo): snd_pcm_hw_params_set_channels(handle, params, 2) ' Imposta la frequenza di campionamento a 44100 hertz: fc = 44100 snd_pcm_hw_params_set_rate_near(handle, params, VarPtr(fc), VarPtr(dr)) ' Imposta la dimensione del periodo a 32 frame: frames = 32 snd_pcm_hw_params_set_period_size_near(handle, params, VarPtr(frames), VarPtr(dr)) ' Scrive i parametri nel dispositivo PCM: err = snd_pcm_hw_params(handle, params) If err < 0 Then Error.Raise("unable to set hw parameters: " & snd_strerror(err)) ' Usa un buffer di dimensioni sufficenti per contenere un periodo: snd_pcm_hw_params_get_period_size(params, VarPtr(frames), VarPtr(dr)) ' Imposta il ciclo per tot secondi: snd_pcm_hw_params_get_period_time(params, VarPtr(frames), VarPtr(dr)) cicli = 400000000 / fc While cicli > 0 Dec cicli ' Registra i dati nel buffer: err = snd_pcm_readi(handle, buffer, 128 / SizeOf(gb.Short)) If err < 0 Then Error.Raise("Errore nella registrazione dei dati audio: " & snd_strerror(err)) ' Scrive il file contenente i dati grezzi wav: For b = 0 To buffer.Max Write #datigrezzi, buffer[b] As Short Next Wend ' Va in chiusura: datigrezzi.Close snd_pcm_close(handle) crea_file() buffer.Clear() End Private Procedure crea_file() ' Genera il file WAV finale ' Impostiamo il blocco iniziale generico del file WAV: Dim blocco1 As String = "RIFF" & Chr(0) & Chr(0) & Chr(0) & Chr(0) & "WAVEfmt" & Chr(&20) & Chr(&10) & Chr(0) & Chr(0) & Chr(0) & Chr(1) & Chr(0) & Chr(2) & Chr(0) & Chr(&44) & Chr(&AC) & Chr(0) & Chr(0) & Chr(&10) & Chr(&B1) & Chr(2) & Chr(0) & Chr(4) & Chr(0) & Chr(&10) & Chr(0) & Chr(&64) & Chr(&61) & Chr(&74) & Chr(&61) ' Per generare il file WAV finale, eseguibile, uniamo i dati del blocco iniziale ai dati grezzi registrati: File.Save("/tmp/FileFINALE.wav", blocco1 & File.Load(percorsoTmp)) End
Un altro esempio più breve e semplice, come il precedente con frequenza di campionamento a 44100 hertz, risoluzione a 16 bit e 2 canali:
Private percorsoTmp As String Library "libasound:2" Private Const SND_PCM_STREAM_CAPTURE As Byte = 1 Private Const SND_PCM_FORMAT_S16_LE As Byte = 2 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3 ' int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) Private Extern snd_pcm_open(handleP As Pointer, nome As String, flusso As Integer, mode As Integer) As Integer ' int snd_pcm_set_params(snd_pcm_t * pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned Int latency) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso As Integer, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer ' snd_pcm_sframes_t snd_pcm_readi (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) Private Extern snd_pcm_readi(pcm As Pointer, buffS As Short[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Main() Dim handle As Pointer Dim device As String = "default" Dim err, fc, cicli As Integer Dim buffer As New Short[128] Dim b As Byte Dim datigrezzi As File ' Creiamo il file che ospiterà i dati grezzi audio registrati dall'applicativo: percorsoTmp = Temp("filegrezzo") datigrezzi = Open percorsoTmp For Create datigrezzi.Close datigrezzi = Open percorsoTmp For Write Append ' Imposta la frequenza di campionamento a 44100 hertz: fc = 44100 ' Apre il sub-sistema PCM di ALSA per la registrazione: err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_CAPTURE, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) ' Imposta i parametri del sub-sistema PCM di ALSA per la registrazione: err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 2, fc, 1, 0) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) cicli = 400000000 / fc While cicli > 0 Dec cicli ' Registra i dati nel buffer: err = snd_pcm_readi(handle, buffer, 128 / SizeOf(gb.Short)) If err < 0 Then Error.Raise("Errore nella registrazione dei dati audio: " & snd_strerror(err)) ' Scrive il file contenente i dati grezzi wav: For b = 0 To buffer.Max Write #datigrezzi, buffer[b] As Short Next Wend ' Va in chiusura: datigrezzi.Close snd_pcm_close(handle) crea_file() buffer.Clear() End Private Procedure crea_file() ' Genera il file WAV finale ' Impostiamo il blocco iniziale generico del file WAV: Dim blocco1 As String = "RIFF" & Chr(0) & Chr(0) & Chr(0) & Chr(0) & "WAVEfmt" & Chr(&20) & Chr(&10) & Chr(0) & Chr(0) & Chr(0) & Chr(1) & Chr(0) & Chr(2) & Chr(0) & Chr(&44) & Chr(&AC) & Chr(0) & Chr(0) & Chr(&10) & Chr(&B1) & Chr(2) & Chr(0) & Chr(4) & Chr(0) & Chr(&10) & Chr(0) & Chr(&64) & Chr(&61) & Chr(&74) & Chr(&61) ' Per generare il file WAV finale, eseguibile, uniamo i dati del blocco iniziale ai dati grezzi registrati: File.Save("/tmp/FileFINALE.wav", blocco1 & File.Load(percorsoTmp)) End
In quest'altro esempio si avrà la possibilità, premendo su un Button posto sul Form, di avviare la registrazione, e premendo su un altro Button di interromperla. Successivamente ripremendo sul primo Button di avviare una nuova registrazione e così via:
Private percorsoTmp As String Private cicli As Boolean Library "libasound:2" Private Const SND_PCM_STREAM_CAPTURE As Byte = 1 Private Const SND_PCM_FORMAT_S16_LE As Byte = 2 Private Const SND_PCM_ACCESS_RW_INTERLEAVED As Byte = 3 ' int snd_pcm_open(snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode) Private Extern snd_pcm_open(handleP As Pointer, nome As String, flusso As Integer, mode As Integer) As Integer ' int snd_pcm_set_params(snd_pcm_t * pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned Int latency) Private Extern snd_pcm_set_params(pcm As Pointer, formatInt As Integer, accesso As Integer, channels As Integer, rate As Integer, soft_resample As Integer, latency As Integer) As Integer ' snd_pcm_sframes_t snd_pcm_readi (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) Private Extern snd_pcm_readi(pcm As Pointer, buffS As Short[], sInt As Integer) As Integer ' const char * snd_strerror (int errnum) Private Extern snd_strerror(errnum As Integer) As String ' snd_pcm_close(snd_pcm_t *pcm) Private Extern snd_pcm_close(pcm As Pointer) Public Sub Button1_Click() Dim handle As Pointer Dim device As String = "default" Dim err, fc As Integer Dim datigrezzi As File Dim canali As Byte Dim buffer As New Short[128] Dim vettGrezzi As New Short[] ' Creiamo il file che ospiterà i dati grezzi audio registrati dall'applicativo: percorsoTmp = Temp("filegrezzo") datigrezzi = Open percorsoTmp For Create ' Imposta la frequenza di campionamento a 44100 hertz: fc = 44100 ' Imposta il numero di canali: canali = 2 ' Apre il sub-sistema PCM di ALSA per la registrazione: err = snd_pcm_open(VarPtr(handle), device, SND_PCM_STREAM_CAPTURE, 0) If err < 0 Then Error.Raise("Errore nell'apertura del sub-sistema PCM: " & snd_strerror(err)) ' Imposta i parametri del sub-sistema PCM di ALSA per la registrazione: err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, canali, fc, 1, 0) If err < 0 Then Error.Raise("Errore nell'impostazione dei parametri del sub-sistema PCM: " & snd_strerror(err)) cicli = True While cicli ' Avvia un ciclo infinito per la registrazione ' Registra i dati nel buffer: err = snd_pcm_readi(handle, buffer, 128 / SizeOf(gb.Short)) If err < 0 Then Error.Raise("Errore nella registrazione dei dati audio: " & snd_strerror(err)) ' Scrive i dati, appena prima registrati, nel vettore per la successiva creazione del file di dati grezzi audio: vettGrezzi.Insert(buffer, vettGrezzi.Count) ' Una brevissima attesa consente di agire sugli oggetti posti sul Form del programma: Wait 0.001 Wend ' Scrive i dati grezzi nell'apposito file temporaneo creato: vettGrezzi.Write(datigrezzi, 0, vettGrezzi.Count) ' Va in chiusura: datigrezzi.Close snd_pcm_close(handle) crea_file() buffer.Clear() vettGrezzi.Clear() End Private Procedure crea_file() Dim blocco1 As String = "RIFF" & Chr(0) & Chr(0) & Chr(0) & Chr(0) & "WAVEfmt" & Chr(&20) & Chr(&10) & Chr(0) & Chr(0) & Chr(0) & Chr(1) & Chr(0) & Chr(2) & Chr(0) & Chr(&44) & Chr(&AC) & Chr(0) & Chr(0) & Chr(&10) & Chr(&B1) & Chr(2) & Chr(0) & Chr(4) & Chr(0) & Chr(&10) & Chr(0) & Chr(&64) & Chr(&61) & Chr(&74) & Chr(&61) File.Save("/tmp/FINALE.wav", blocco1 & File.Load(percorsoTmp)) End Public Sub Button2_Click() cicli = False End