Umberto Salsi
2017-09-06 15:38:49 UTC
Per un simulatore di volo, devo cambiare la frequenza del suono di sfondo
del motore. Per esempio, ho campionato il suono del motore a 8000 Hz full
power, e per riprodurre il suono col motore al 50% RPM devo riprodurre
il suono a 4000 Hz.
Con la libreria ALSA su Linux (Salckware 14.2, 64 bits) uso la
funzione snd_pcm_set_params(), ma introduce un fastidioso click ad ogni
cambiamento, come prova il programmino qui sotto.
C'è un altro modo per cambiare la frequenza senza dover ricorrere a un
ricampionamento in software?
Per la cronaca, il simulatore di volo in questione è acm-5.0-ico disponibile
nella home page del mio sito.
Ciao,
___
/_|_\ Umberto Salsi
\/_\/ www.icosaedro.it
/*
* pitchchange.c - compile and execute with:
* gcc pitchchange.c -o pitchchange.exe -lasound && ./pitchchange.exe
*/
#include <stdlib.h>
#include <assert.h>
#include <alsa/asoundlib.h>
static void setRate(snd_pcm_t *pcm, int rate)
{
printf("now playing at %d Hz\n", rate);
assert( snd_pcm_set_params(pcm, SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1, /* channels */
rate, /* Hz */
1, /* allow alsa-lib sw resampler (what is it, though?) */
100000 /* latency (us) - ??? */
) == 0 );
}
int main(void)
{
/* Generate square wave, 1 B/frame, 256 frames/period, 16 periods total: */
unsigned char wave[4*1024];
int amplitude = 5;
int i;
for (i = 0; i < sizeof(wave); i++)
wave[i] = (i & 0x80) ? 128 + amplitude : 128 - amplitude;
/* Open audio device: */
snd_pcm_t *pcm;
assert( snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0) == 0 );
/* Play the square wave at increasing rates. */
int rate = 6000;
setRate(pcm, rate);
while(1){
/* Play the sample using current rate: */
int avail_frames = sizeof(wave);
while( avail_frames > 0 ){
int wrote_frames = snd_pcm_writei(pcm,
wave + sizeof(wave) - avail_frames, avail_frames);
assert( wrote_frames >= 0 );
if (wrote_frames > 0 )
avail_frames -= wrote_frames;
}
/* Change the playback rate a bit: */
rate += 100;
if( rate > 8000 )
rate = 6000;
setRate(pcm, rate); // <-- comment out this line to get rid of the click
}
}
// The end.
del motore. Per esempio, ho campionato il suono del motore a 8000 Hz full
power, e per riprodurre il suono col motore al 50% RPM devo riprodurre
il suono a 4000 Hz.
Con la libreria ALSA su Linux (Salckware 14.2, 64 bits) uso la
funzione snd_pcm_set_params(), ma introduce un fastidioso click ad ogni
cambiamento, come prova il programmino qui sotto.
C'è un altro modo per cambiare la frequenza senza dover ricorrere a un
ricampionamento in software?
Per la cronaca, il simulatore di volo in questione è acm-5.0-ico disponibile
nella home page del mio sito.
Ciao,
___
/_|_\ Umberto Salsi
\/_\/ www.icosaedro.it
/*
* pitchchange.c - compile and execute with:
* gcc pitchchange.c -o pitchchange.exe -lasound && ./pitchchange.exe
*/
#include <stdlib.h>
#include <assert.h>
#include <alsa/asoundlib.h>
static void setRate(snd_pcm_t *pcm, int rate)
{
printf("now playing at %d Hz\n", rate);
assert( snd_pcm_set_params(pcm, SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1, /* channels */
rate, /* Hz */
1, /* allow alsa-lib sw resampler (what is it, though?) */
100000 /* latency (us) - ??? */
) == 0 );
}
int main(void)
{
/* Generate square wave, 1 B/frame, 256 frames/period, 16 periods total: */
unsigned char wave[4*1024];
int amplitude = 5;
int i;
for (i = 0; i < sizeof(wave); i++)
wave[i] = (i & 0x80) ? 128 + amplitude : 128 - amplitude;
/* Open audio device: */
snd_pcm_t *pcm;
assert( snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0) == 0 );
/* Play the square wave at increasing rates. */
int rate = 6000;
setRate(pcm, rate);
while(1){
/* Play the sample using current rate: */
int avail_frames = sizeof(wave);
while( avail_frames > 0 ){
int wrote_frames = snd_pcm_writei(pcm,
wave + sizeof(wave) - avail_frames, avail_frames);
assert( wrote_frames >= 0 );
if (wrote_frames > 0 )
avail_frames -= wrote_frames;
}
/* Change the playback rate a bit: */
rate += 100;
if( rate > 8000 )
rate = 6000;
setRate(pcm, rate); // <-- comment out this line to get rid of the click
}
}
// The end.