Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sound/pcm/feeder_matrix.c
| Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
| #include "snd_fxdiv_gen.h" | #include "snd_fxdiv_gen.h" | ||||
| #endif | #endif | ||||
| #define FEEDMATRIX_RESERVOIR (SND_CHN_MAX * PCM_32_BPS) | #define FEEDMATRIX_RESERVOIR (SND_CHN_MAX * PCM_32_BPS) | ||||
| #define SND_CHN_T_EOF 0x00e0fe0f | #define SND_CHN_T_EOF 0x00e0fe0f | ||||
| #define SND_CHN_T_NULL 0x0e0e0e0e | #define SND_CHN_T_NULL 0x0e0e0e0e | ||||
| struct feed_matrix_info; | |||||
| typedef void (*feed_matrix_t)(struct feed_matrix_info *, uint8_t *, | |||||
| uint8_t *, uint32_t); | |||||
| struct feed_matrix_info { | struct feed_matrix_info { | ||||
| uint32_t fmt; | |||||
| uint32_t bps; | uint32_t bps; | ||||
| uint32_t ialign, oalign; | uint32_t ialign, oalign; | ||||
| uint32_t in, out; | uint32_t in, out; | ||||
| feed_matrix_t apply; | |||||
| struct { | struct { | ||||
| int chn[SND_CHN_T_MAX + 1]; | int chn[SND_CHN_T_MAX + 1]; | ||||
| int mul, shift; | int mul, shift; | ||||
| } matrix[SND_CHN_T_MAX + 1]; | } matrix[SND_CHN_T_MAX + 1]; | ||||
| uint8_t reservoir[FEEDMATRIX_RESERVOIR]; | uint8_t reservoir[FEEDMATRIX_RESERVOIR]; | ||||
| }; | }; | ||||
| static struct pcmchan_matrix feeder_matrix_maps[SND_CHN_MATRIX_MAX] = { | static struct pcmchan_matrix feeder_matrix_maps[SND_CHN_MATRIX_MAX] = { | ||||
| Show All 29 Lines | |||||
| #else | #else | ||||
| #define FEEDMATRIX_CLIP_CHECK(v, BIT) do { \ | #define FEEDMATRIX_CLIP_CHECK(v, BIT) do { \ | ||||
| if ((v) < PCM_S##BIT##_MIN || (v) > PCM_S##BIT##_MAX) \ | if ((v) < PCM_S##BIT##_MIN || (v) > PCM_S##BIT##_MAX) \ | ||||
| errx(1, "\n\n%s(): Sample clipping: %jd\n", \ | errx(1, "\n\n%s(): Sample clipping: %jd\n", \ | ||||
| __func__, (intmax_t)(v)); \ | __func__, (intmax_t)(v)); \ | ||||
| } while (0) | } while (0) | ||||
| #endif | #endif | ||||
| #define FEEDMATRIX_DECLARE(SIGN, BIT, ENDIAN) \ | __always_inline static void | ||||
| static void \ | feed_matrix_apply(struct feed_matrix_info *info, uint8_t *src, uint8_t *dst, | ||||
| feed_matrix_##SIGN##BIT##ENDIAN(struct feed_matrix_info *info, \ | uint32_t count, const uint32_t fmt) | ||||
| uint8_t *src, uint8_t *dst, uint32_t count) \ | { | ||||
| { \ | intpcm64_t accum; | ||||
| intpcm64_t accum; \ | intpcm_t v; | ||||
| intpcm_t v; \ | int i, j; | ||||
| int i, j; \ | |||||
| \ | do { | ||||
| do { \ | for (i = 0; info->matrix[i].chn[0] != SND_CHN_T_EOF; i++) { | ||||
| for (i = 0; info->matrix[i].chn[0] != SND_CHN_T_EOF; \ | if (info->matrix[i].chn[0] == SND_CHN_T_NULL) { | ||||
| i++) { \ | pcm_sample_write(dst, 0, fmt); | ||||
| if (info->matrix[i].chn[0] == SND_CHN_T_NULL) { \ | dst += info->bps; | ||||
| pcm_sample_write(dst, 0, \ | continue; | ||||
| AFMT_##SIGN##BIT##_##ENDIAN); \ | } else if (info->matrix[i].chn[1] == SND_CHN_T_EOF) { | ||||
| dst += PCM_##BIT##_BPS; \ | v = pcm_sample_read(src + | ||||
| continue; \ | info->matrix[i].chn[0], fmt); | ||||
| } else if (info->matrix[i].chn[1] == \ | pcm_sample_write(dst, v, fmt); | ||||
| SND_CHN_T_EOF) { \ | dst += info->bps; | ||||
| v = pcm_sample_read( \ | continue; | ||||
| src + info->matrix[i].chn[0], \ | |||||
| AFMT_##SIGN##BIT##_##ENDIAN); \ | |||||
| pcm_sample_write(dst, v, \ | |||||
| AFMT_##SIGN##BIT##_##ENDIAN); \ | |||||
| dst += PCM_##BIT##_BPS; \ | |||||
| continue; \ | |||||
| } \ | |||||
| \ | |||||
| accum = 0; \ | |||||
| for (j = 0; \ | |||||
| info->matrix[i].chn[j] != SND_CHN_T_EOF; \ | |||||
| j++) { \ | |||||
| v = pcm_sample_read( \ | |||||
| src + info->matrix[i].chn[j], \ | |||||
| AFMT_##SIGN##BIT##_##ENDIAN); \ | |||||
| accum += v; \ | |||||
| } \ | |||||
| \ | |||||
| accum = (accum * info->matrix[i].mul) >> \ | |||||
| info->matrix[i].shift; \ | |||||
| \ | |||||
| FEEDMATRIX_CLIP_CHECK(accum, BIT); \ | |||||
| \ | |||||
| v = (accum > PCM_S##BIT##_MAX) ? \ | |||||
| PCM_S##BIT##_MAX : \ | |||||
| ((accum < PCM_S##BIT##_MIN) ? \ | |||||
| PCM_S##BIT##_MIN : \ | |||||
| accum); \ | |||||
| pcm_sample_write(dst, v, \ | |||||
| AFMT_##SIGN##BIT##_##ENDIAN); \ | |||||
| dst += PCM_##BIT##_BPS; \ | |||||
| } \ | |||||
| src += info->ialign; \ | |||||
| } while (--count != 0); \ | |||||
| } | } | ||||
| #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) | accum = 0; | ||||
| FEEDMATRIX_DECLARE(S, 16, LE) | for (j = 0; info->matrix[i].chn[j] != SND_CHN_T_EOF; | ||||
| FEEDMATRIX_DECLARE(S, 32, LE) | j++) { | ||||
| #endif | v = pcm_sample_read(src + | ||||
| #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) | info->matrix[i].chn[j], fmt); | ||||
| FEEDMATRIX_DECLARE(S, 16, BE) | accum += v; | ||||
| FEEDMATRIX_DECLARE(S, 32, BE) | |||||
| #endif | |||||
| #ifdef SND_FEEDER_MULTIFORMAT | |||||
| FEEDMATRIX_DECLARE(S, 8, NE) | |||||
| FEEDMATRIX_DECLARE(S, 24, LE) | |||||
| FEEDMATRIX_DECLARE(S, 24, BE) | |||||
| FEEDMATRIX_DECLARE(U, 8, NE) | |||||
| FEEDMATRIX_DECLARE(U, 16, LE) | |||||
| FEEDMATRIX_DECLARE(U, 24, LE) | |||||
| FEEDMATRIX_DECLARE(U, 32, LE) | |||||
| FEEDMATRIX_DECLARE(U, 16, BE) | |||||
| FEEDMATRIX_DECLARE(U, 24, BE) | |||||
| FEEDMATRIX_DECLARE(U, 32, BE) | |||||
| #endif | |||||
| #define FEEDMATRIX_ENTRY(SIGN, BIT, ENDIAN) \ | |||||
| { \ | |||||
| AFMT_##SIGN##BIT##_##ENDIAN, \ | |||||
| feed_matrix_##SIGN##BIT##ENDIAN \ | |||||
| } | } | ||||
| static const struct { | accum = (accum * info->matrix[i].mul) >> | ||||
| uint32_t format; | info->matrix[i].shift; | ||||
| feed_matrix_t apply; | |||||
| } feed_matrix_tab[] = { | |||||
| #if BYTE_ORDER == LITTLE_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) | |||||
| FEEDMATRIX_ENTRY(S, 16, LE), | |||||
| FEEDMATRIX_ENTRY(S, 32, LE), | |||||
| #endif | |||||
| #if BYTE_ORDER == BIG_ENDIAN || defined(SND_FEEDER_MULTIFORMAT) | |||||
| FEEDMATRIX_ENTRY(S, 16, BE), | |||||
| FEEDMATRIX_ENTRY(S, 32, BE), | |||||
| #endif | |||||
| #ifdef SND_FEEDER_MULTIFORMAT | |||||
| FEEDMATRIX_ENTRY(S, 8, NE), | |||||
| FEEDMATRIX_ENTRY(S, 24, LE), | |||||
| FEEDMATRIX_ENTRY(S, 24, BE), | |||||
| FEEDMATRIX_ENTRY(U, 8, NE), | |||||
| FEEDMATRIX_ENTRY(U, 16, LE), | |||||
| FEEDMATRIX_ENTRY(U, 24, LE), | |||||
| FEEDMATRIX_ENTRY(U, 32, LE), | |||||
| FEEDMATRIX_ENTRY(U, 16, BE), | |||||
| FEEDMATRIX_ENTRY(U, 24, BE), | |||||
| FEEDMATRIX_ENTRY(U, 32, BE) | |||||
| #endif | |||||
| }; | |||||
| FEEDMATRIX_CLIP_CHECK(accum, AFMT_BIT(fmt)); | |||||
| switch (AFMT_BIT(fmt)) { | |||||
| case 8: | |||||
| v = PCM_CLAMP_S8(v); | |||||
| break; | |||||
| case 16: | |||||
| v = PCM_CLAMP_S16(v); | |||||
| break; | |||||
| case 24: | |||||
| v = PCM_CLAMP_S24(v); | |||||
| break; | |||||
| case 32: | |||||
| v = PCM_CLAMP_S32(v); | |||||
| break; | |||||
| } | |||||
| pcm_sample_write(dst, v, fmt); | |||||
| dst += info->bps; | |||||
| } | |||||
| src += info->ialign; | |||||
| } while (--count != 0); | |||||
| } | |||||
| static void | static void | ||||
| feed_matrix_reset(struct feed_matrix_info *info) | feed_matrix_reset(struct feed_matrix_info *info) | ||||
| { | { | ||||
| uint32_t i, j; | uint32_t i, j; | ||||
| for (i = 0; i < nitems(info->matrix); i++) { | for (i = 0; i < nitems(info->matrix); i++) { | ||||
| for (j = 0; | for (j = 0; | ||||
| j < (sizeof(info->matrix[i].chn) / | j < (sizeof(info->matrix[i].chn) / | ||||
| ▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | #endif | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| feed_matrix_init(struct pcm_feeder *f) | feed_matrix_init(struct pcm_feeder *f) | ||||
| { | { | ||||
| struct feed_matrix_info *info; | struct feed_matrix_info *info; | ||||
| struct pcmchan_matrix *m_in, *m_out; | struct pcmchan_matrix *m_in, *m_out; | ||||
| uint32_t i; | |||||
| int ret; | int ret; | ||||
| if (AFMT_ENCODING(f->desc->in) != AFMT_ENCODING(f->desc->out)) | if (AFMT_ENCODING(f->desc->in) != AFMT_ENCODING(f->desc->out)) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO); | info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT | M_ZERO); | ||||
| if (info == NULL) | if (info == NULL) | ||||
| return (ENOMEM); | return (ENOMEM); | ||||
| info->in = f->desc->in; | info->in = f->desc->in; | ||||
| info->out = f->desc->out; | info->out = f->desc->out; | ||||
| info->fmt = AFMT_ENCODING(info->in); | |||||
| info->bps = AFMT_BPS(info->in); | info->bps = AFMT_BPS(info->in); | ||||
| info->ialign = AFMT_ALIGN(info->in); | info->ialign = AFMT_ALIGN(info->in); | ||||
| info->oalign = AFMT_ALIGN(info->out); | info->oalign = AFMT_ALIGN(info->out); | ||||
| info->apply = NULL; | |||||
| for (i = 0; info->apply == NULL && | |||||
| i < (sizeof(feed_matrix_tab) / sizeof(feed_matrix_tab[0])); i++) { | |||||
| if (AFMT_ENCODING(info->in) == feed_matrix_tab[i].format) | |||||
| info->apply = feed_matrix_tab[i].apply; | |||||
| } | |||||
| if (info->apply == NULL) { | |||||
| #ifdef FEEDMATRIX_GENERIC | |||||
| info->apply = feed_matrix_apply_generic; | |||||
| #else | |||||
| free(info, M_DEVBUF); | |||||
| return (EINVAL); | |||||
| #endif | |||||
| } | |||||
| m_in = feeder_matrix_format_map(info->in); | m_in = feeder_matrix_format_map(info->in); | ||||
| m_out = feeder_matrix_format_map(info->out); | m_out = feeder_matrix_format_map(info->out); | ||||
| ret = feed_matrix_setup(info, m_in, m_out); | ret = feed_matrix_setup(info, m_in, m_out); | ||||
| if (ret != 0) { | if (ret != 0) { | ||||
| free(info, M_DEVBUF); | free(info, M_DEVBUF); | ||||
| return (ret); | return (ret); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (count < inmax) { | ||||
| src = dst + count - j; | src = dst + count - j; | ||||
| } | } | ||||
| j = SND_FXDIV(FEEDER_FEED(f->source, c, src, j, source), | j = SND_FXDIV(FEEDER_FEED(f->source, c, src, j, source), | ||||
| info->ialign); | info->ialign); | ||||
| if (j == 0) | if (j == 0) | ||||
| break; | break; | ||||
| info->apply(info, src, dst, j); | /* Optimize some common formats. */ | ||||
| switch (info->fmt) { | |||||
| case AFMT_S16_NE: | |||||
| feed_matrix_apply(info, src, dst, j, AFMT_S16_NE); | |||||
| break; | |||||
| case AFMT_S24_NE: | |||||
| feed_matrix_apply(info, src, dst, j, AFMT_S24_NE); | |||||
| break; | |||||
| case AFMT_S32_NE: | |||||
| feed_matrix_apply(info, src, dst, j, AFMT_S32_NE); | |||||
| break; | |||||
| default: | |||||
| feed_matrix_apply(info, src, dst, j, info->fmt); | |||||
| break; | |||||
| } | |||||
markj: Why can't this entire switch statement just be `feed_matrix_apply(info, src, dst, j, info->fmt)… | |||||
Done Inline ActionsThere is related discussion in D48032 christos: There is related discussion in D48032 | |||||
| j *= info->oalign; | j *= info->oalign; | ||||
| dst += j; | dst += j; | ||||
| count -= j; | count -= j; | ||||
| } while (count != 0); | } while (count != 0); | ||||
| return (dst - b); | return (dst - b); | ||||
| ▲ Show 20 Lines • Show All 305 Lines • Show Last 20 Lines | |||||
Why can't this entire switch statement just be feed_matrix_apply(info, src, dst, j, info->fmt);?