int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) { int src_endian, dst_endian, sign, src_width, dst_width; sign = (snd_pcm_format_signed(src_format) != snd_pcm_format_signed(dst_format)); #ifdef SND_LITTLE_ENDIAN src_endian = snd_pcm_format_big_endian(src_format); dst_endian = snd_pcm_format_big_endian(dst_format); #else src_endian = snd_pcm_format_little_endian(src_format); dst_endian = snd_pcm_format_little_endian(dst_format); #endif if (src_endian < 0) src_endian = 0; if (dst_endian < 0) dst_endian = 0; src_width = snd_pcm_format_width(src_format) / 8 - 1; dst_width = snd_pcm_format_width(dst_format) / 8 - 1; return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian; }
int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) { int sign, width, pwidth, endian; sign = (snd_pcm_format_signed(src_format) != snd_pcm_format_signed(dst_format)); #ifdef SND_LITTLE_ENDIAN endian = snd_pcm_format_big_endian(src_format); #else endian = snd_pcm_format_little_endian(src_format); #endif if (endian < 0) endian = 0; pwidth = snd_pcm_format_physical_width(src_format); width = snd_pcm_format_width(src_format); if (pwidth == 24) { switch (width) { case 24: width = 0; break; case 20: width = 1; break; case 18: default: width = 2; break; } return width * 4 + endian * 2 + sign + 16; } else { width = width / 8 - 1; return width * 4 + endian * 2 + sign; } }
/** * \brief Return endian info for a PCM sample format * \param format Format * \return 0 swapped, 1 CPU endian, a negative error code if endian independent */ int snd_pcm_format_cpu_endian(snd_pcm_format_t format) { #ifdef SNDRV_LITTLE_ENDIAN return snd_pcm_format_little_endian(format); #else return snd_pcm_format_big_endian(format); #endif }
int snd_pcm_lfloat_get_s32_index(snd_pcm_format_t format) { int width, endian; switch (format) { case SND_PCM_FORMAT_FLOAT_LE: case SND_PCM_FORMAT_FLOAT_BE: width = 32; break; case SND_PCM_FORMAT_FLOAT64_LE: case SND_PCM_FORMAT_FLOAT64_BE: width = 64; break; default: return -EINVAL; } #ifdef SND_LITTLE_ENDIAN endian = snd_pcm_format_big_endian(format); #else endian = snd_pcm_format_little_endian(format); #endif return ((width / 32)-1) * 2 + endian; }
// returns 1 if successful // enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, int* sampleSizeInBytes, int* significantBits, int* isSigned, int* isBigEndian, int* enc) { *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8; *significantBits = snd_pcm_format_width(alsaFormat); // defaults *enc = 0; // PCM *isSigned = (snd_pcm_format_signed(alsaFormat) > 0); *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0); // non-PCM formats if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes; } else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes; } else if (snd_pcm_format_linear(alsaFormat) < 1) { return 0; } return (*sampleSizeInBytes > 0); }
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; }
/* * pdacf_pcm_prepare - prepare callback for playback and capture */ static int pdacf_pcm_prepare(struct snd_pcm_substream *subs) { struct snd_pdacf *chip = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; u16 val, nval, aval; if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) return -EBUSY; chip->pcm_channels = runtime->channels; chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0; #ifdef SNDRV_LITTLE_ENDIAN chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0; #else chip->pcm_swab = chip->pcm_little; #endif if (snd_pcm_format_unsigned(runtime->format)) chip->pcm_xor = 0x80008000; if (pdacf_pcm_clear_sram(chip) < 0) return -EIO; val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1); switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_BE: break; default: /* 24-bit */ nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; break; } aval = 0; chip->pcm_sample = 4; switch (runtime->format) { case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_BE: aval = AK4117_DIF_16R; chip->pcm_frame = 2; chip->pcm_sample = 2; break; case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_3BE: chip->pcm_sample = 3; /* fall through */ default: /* 24-bit */ aval = AK4117_DIF_24R; chip->pcm_frame = 3; chip->pcm_xor &= 0xffff0000; break; } if (val != nval) { snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval); pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval); } val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); val &= ~(PDAUDIOCF_IRQLVLEN1); val |= PDAUDIOCF_IRQLVLEN0; pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); chip->pcm_size = runtime->buffer_size; chip->pcm_period = runtime->period_size; chip->pcm_area = runtime->dma_area; return 0; }
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) { // 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; }