static snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format, const snd_pcm_format_mask_t *format_mask) { int w, w1, u, e; snd_pcm_format_t f; snd_pcm_format_mask_t lin = { SND_PCM_FMTBIT_LINEAR }; snd_pcm_format_mask_t fl = { #ifdef BUILD_PCM_PLUGIN_LFLOAT SND_PCM_FMTBIT_FLOAT #else { 0 } #endif }; if (snd_pcm_format_mask_test(format_mask, format)) return format; if (!snd_pcm_format_mask_test(&lin, format) && !snd_pcm_format_mask_test(&fl, format)) { unsigned int i; switch (format) { #ifdef BUILD_PCM_PLUGIN_MULAW case SND_PCM_FORMAT_MU_LAW: #endif #ifdef BUILD_PCM_PLUGIN_ALAW case SND_PCM_FORMAT_A_LAW: #endif #ifdef BUILD_PCM_PLUGIN_ADPCM case SND_PCM_FORMAT_IMA_ADPCM: #endif for (i = 0; i < sizeof(linear_preferred_formats) / sizeof(linear_preferred_formats[0]); ++i) { snd_pcm_format_t f = linear_preferred_formats[i]; if (snd_pcm_format_mask_test(format_mask, f)) return f; } /* Fall through */ default: return SND_PCM_FORMAT_UNKNOWN; } } snd_mask_intersect(&lin, format_mask); snd_mask_intersect(&fl, format_mask); if (snd_mask_empty(&lin) && snd_mask_empty(&fl)) { #ifdef BUILD_PCM_NONLINEAR unsigned int i; for (i = 0; i < sizeof(nonlinear_preferred_formats) / sizeof(nonlinear_preferred_formats[0]); ++i) { snd_pcm_format_t f = nonlinear_preferred_formats[i]; if (snd_pcm_format_mask_test(format_mask, f)) return f; } #endif return SND_PCM_FORMAT_UNKNOWN; } #ifdef BUILD_PCM_PLUGIN_LFLOAT if (snd_pcm_format_float(format)) { if (snd_pcm_format_mask_test(&fl, format)) { unsigned int i; for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) { snd_pcm_format_t f = float_preferred_formats[i]; if (snd_pcm_format_mask_test(format_mask, f)) return f; } } w = 32; u = 0; e = snd_pcm_format_big_endian(format); } else #endif if (snd_mask_empty(&lin)) { #ifdef BUILD_PCM_PLUGIN_LFLOAT unsigned int i; for (i = 0; i < sizeof(float_preferred_formats) / sizeof(float_preferred_formats[0]); ++i) { snd_pcm_format_t f = float_preferred_formats[i]; if (snd_pcm_format_mask_test(format_mask, f)) return f; } #endif return SND_PCM_FORMAT_UNKNOWN; } else { w = snd_pcm_format_width(format); u = snd_pcm_format_unsigned(format); e = snd_pcm_format_big_endian(format); } for (w1 = w; w1 <= 32; w1++) { f = check_linear_format(format_mask, w1, u, e); if (f != SND_PCM_FORMAT_UNKNOWN) return f; } for (w1 = w - 1; w1 > 0; w1--) { f = check_linear_format(format_mask, w1, u, e); if (f != SND_PCM_FORMAT_UNKNOWN) return f; } return SND_PCM_FORMAT_UNKNOWN; }
static void *dev_thread(void *arg) { int ret, frames, i, j, shift, bits, isfloat; int sample_bytes; uint32_t (*puller)(unsigned char **, int); S32 sample; double scale; snd_pcm_format_t format; int avail; //float *fpt, *fbuf; float fsample; unsigned char *buffer, *pt; buffer = (unsigned char *)malloc(blocksize * CHANNELS * sizeof(float)); //fbuf = (float *)malloc(blocksize * CHANNELS); snd_pcm_prepare(handle); bits = snd_pcm_hw_params_get_sbits(hparams); sample_bytes = bits / 8; snd_pcm_hw_params_get_format(hparams, &format); if ((isfloat = snd_pcm_format_float(format))) scale = 1.0; else scale = pow(2.0 , 1 - bits); logmsg("1/scale %f [%d]\n", 1.0 / scale, bits); running = 1; if (snd_pcm_format_big_endian(format) == 1) puller = bepull; else puller = lepull; shift = 8 * (sizeof(uint32_t) - sample_bytes); ret = snd_pcm_readi(handle, buffer, blocksize); // prime pump if (scount > 0) sfile = fopen("/tmp/sample.raw", "w"); while (running) { if ((ret = snd_pcm_wait(handle, 1000)) < 0) { if (ret == -EPIPE) logmsg("wait: xrun\n"); else if (ret == -ESTRPIPE) logmsg("wait: suspend\n"); else logmsg("poll failed %s\n", strerror(errno)); continue; } avail = snd_pcm_avail_update(handle); if (avail < 0) { if (avail == -EPIPE) logmsg("an xrun occurred\n"); else logmsg("weird avail %d\n", avail); break; } if (avail > blocksize) avail = blocksize; frames = snd_pcm_readi(handle, (void *)buffer, avail); if (frames < 0) { logmsg("read failed %s\n", snd_strerror(frames)); } else if (frames != avail) { logmsg("wanted %d got %d\n", avail, frames); } pt = buffer; //fpt = fbuf; for (i = 0; i < frames; i++) { for (j = 0; j < CHANNELS; j++) { sample.u = (*puller)(&pt, sample_bytes); if (isfloat) fsample = sample.f; else { if (shift) sample.s = (sample.s << shift) >> shift; fsample = sample.s * scale; } if (scount > 0) { scount--; fprintf(sfile, "%10d, %1.8f\n", sample.s, fsample); if (scount == 0) fclose(sfile); } push_ringbuf(rbuf, fsample); } } } free(buffer); //free(fbuf); snd_pcm_drain(handle); snd_pcm_close(handle); handle = NULL; return NULL; }
static void *dev_thread(void *arg) { // capture thread: keep reading and ring-buffering till told to quit int ret, frames, i, j, shift, bits, isfloat; int sample_bytes; uint32_t (*puller)(unsigned char **, int); S32 sample; double scale; snd_pcm_format_t format; int avail; sample_t fsample; unsigned char *buffer, *pt; ALSA_CARD *card; card = (ALSA_CARD *)arg; log_msg("ALSA: recv from %s '%s'\n", card->device, card->name); buffer = (unsigned char *)malloc(card->blocksize * QMX_CHANNELS * sizeof(float)); snd_pcm_prepare(card->handle); bits = snd_pcm_hw_params_get_sbits(card->hparams); sample_bytes = bits / 8; snd_pcm_hw_params_get_format(card->hparams, &format); if ((isfloat = snd_pcm_format_float(format))) scale = 1.0; else scale = pow(2.0 , 1 - bits); log_msg("ALSA: 1/scale %f [%d]\n", 1.0 / scale, bits); card->running = 1; card->ringbuf = jack_ringbuffer_create(sizeof(sample_t) * RB_SECS * sampling_rate * QMX_CHANNELS + 0.5); if (snd_pcm_format_big_endian(format) == 1) puller = bepull; else puller = lepull; shift = 8 * (sizeof(uint32_t) - sample_bytes); ret = snd_pcm_readi(card->handle, buffer, card->blocksize); // prime pump while (card->running) { if ((ret = snd_pcm_wait(card->handle, 1000)) < 0) { if (ret == -EPIPE) { log_msg("ALSA: wait: EPIPE, recover...\n"); try_recover(card, ret, buffer); } else if (ret == -ESTRPIPE) { log_msg("ALSA: wait: ESTRPIPE, recover...\n"); try_recover(card, ret, buffer); } else log_msg("ALSA: poll failed %s\n", strerror(errno)); continue; } else if (ret == 0) { log_msg("ALSA: card timeout...\n"); continue; } avail = snd_pcm_avail_update(card->handle); if (avail < 0) { if (avail == -EPIPE) { log_msg("ALSA: avail_update: EPIPE, recover...\n"); try_recover(card, avail, buffer); continue; } else { log_msg("ALSA: weird avail %d\n", avail); break; } } if (avail > card->blocksize) avail = card->blocksize; frames = snd_pcm_readi(card->handle, (void *)buffer, avail); if (frames < 0) { log_msg("ALSA: read failed %s\n", snd_strerror(frames)); } else if (frames != avail) { log_msg("ALSA: wanted %d got %d\n", avail, frames); } pt = buffer; for (i = 0; i < frames; i++) { for (j = 0; j < QMX_CHANNELS; j++) { sample.u = (*puller)(&pt, sample_bytes); if (isfloat) fsample = sample.f; else { if (shift) sample.s = (sample.s << shift) >> shift; fsample = sample.s * scale; } jack_ringbuffer_write(card->ringbuf, (const char *)&fsample, sizeof(sample_t)); } } } free(buffer); log_msg("ALSA: stopped %s '%s'\n", card->device, card->name); snd_pcm_drain(card->handle); return NULL; }