Browse Source

[0.93.6] ALSA support for 24-bit cards

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@602 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
joq 21 years ago
parent
commit
d8b7e48d32
5 changed files with 264 additions and 35 deletions
  1. +1
    -1
      configure.in
  2. +58
    -34
      drivers/alsa/alsa_driver.c
  3. +8
    -0
      drivers/alsa/alsa_driver.h
  4. +190
    -0
      drivers/alsa/memops.c
  5. +7
    -0
      drivers/alsa/memops.h

+ 1
- 1
configure.in View File

@@ -15,7 +15,7 @@ dnl changes are made
dnl ---
JACK_MAJOR_VERSION=0
JACK_MINOR_VERSION=93
JACK_MICRO_VERSION=5
JACK_MICRO_VERSION=6

dnl ---
dnl HOWTO: updating the jack protocal version


+ 58
- 34
drivers/alsa/alsa_driver.c View File

@@ -243,6 +243,35 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
}
break;

case 3:
if (driver->playback_interleaved) {
driver->channel_copy = memcpy_interleave_d24_s24;
} else {
driver->channel_copy = memcpy_fake;
}

switch (driver->dither) {
case Rectangular:
printf("Rectangular dithering at 16 bits\n");
driver->write_via_copy = sample_move_dither_rect_d24u24_sS;
break;

case Triangular:
printf("Triangular dithering at 16 bits\n");
driver->write_via_copy = sample_move_dither_tri_d24u24_sS;
break;

case Shaped:
printf("Noise-shaped dithering at 16 bits\n");
driver->write_via_copy = sample_move_dither_shaped_d24u24_sS;
break;

default:
driver->write_via_copy = sample_move_d24u24_sS;
break;
}
break;

case 4:
if (driver->playback_interleaved) {
driver->channel_copy = memcpy_interleave_d32_s32;
@@ -280,6 +309,9 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver)
case 2:
driver->read_via_copy = sample_move_dS_s16;
break;
case 3:
driver->read_via_copy = sample_move_dS_s24u24;
break;
case 4:
driver->read_via_copy = sample_move_dS_s32u24;
break;
@@ -294,8 +326,17 @@ alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name,
snd_pcm_sw_params_t *sw_params,
unsigned long *nchns,unsigned long sample_width)
{
int err;
int err, format;
snd_pcm_uframes_t stop_th;
static struct {
char Name[16];
snd_pcm_format_t format;
} formats[] = {
{"32bit", SND_PCM_FORMAT_S32},
{"24bit", SND_PCM_FORMAT_S24_3},
{"16bit", SND_PCM_FORMAT_S16},
};
#define NOFORMATS (sizeof(formats)/sizeof(formats[0]))
if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
jack_error ("ALSA: no playback configurations available (%s)",
@@ -323,44 +364,25 @@ alsa_driver_configure_stream (alsa_driver_t *driver, char *device_name,
return -1;
}
}

if (sample_width == 4) {

if ((err = snd_pcm_hw_params_set_format (
handle, hw_params, SND_PCM_FORMAT_S32)) < 0) {
jack_error("Couldn't open %s for 32bit samples "
"trying 16bit instead", device_name);
if ((err = snd_pcm_hw_params_set_format (
handle, hw_params, SND_PCM_FORMAT_S16))
< 0) {
jack_error ("Sorry. The audio interface \"%s\""
"doesn't support either of the two"
" hardware sample formats that "
"JACK can use.",
device_name);
return -1;
}
}

} else {

if ((err = snd_pcm_hw_params_set_format (
handle, hw_params, SND_PCM_FORMAT_S16)) < 0) {
jack_error("Couldn't open %s for 16bit samples trying"
" 32bit instead",device_name);
if ((err = snd_pcm_hw_params_set_format (
handle, hw_params, SND_PCM_FORMAT_S32))
< 0) {
format = sample_width == 4 ? 0 : NOFORMATS - 1;
while (1) {
if ((err = snd_pcm_hw_params_set_format (handle, hw_params, formats[format].format)) < 0) {
int failed_format = format;
if (sample_width == 4 ? format++ < NOFORMATS - 1 : format-- > 0) {
jack_error ("Couldn't open %s for %s samples"
" trying %s instead", device_name, formats[failed_format].Name, formats[format].Name);
} else {
jack_error ("Sorry. The audio interface \"%s\""
"doesn't support either of the two"
" hardware sample formats that "
"JACK can use.",
" doesn't support any of the"
" hardware sample formats that"
" JACK's alsa-driver can use.",
device_name);
return -1;
}
}
}
} else
break;
}

if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params,
driver->frame_rate, 0))
@@ -674,6 +696,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver,
if (driver->playback_handle) {
switch (driver->playback_sample_format) {
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S24_3:
case SND_PCM_FORMAT_S16_LE:
case SND_PCM_FORMAT_S32_BE:
case SND_PCM_FORMAT_S16_BE:
@@ -689,6 +712,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver,
if (driver->capture_handle) {
switch (driver->capture_sample_format) {
case SND_PCM_FORMAT_S32_LE:
case SND_PCM_FORMAT_S24_3:
case SND_PCM_FORMAT_S16_LE:
case SND_PCM_FORMAT_S32_BE:
case SND_PCM_FORMAT_S16_BE:


+ 8
- 0
drivers/alsa/alsa_driver.h View File

@@ -25,6 +25,14 @@
#define ALSA_PCM_OLD_SW_PARAMS_API
#include <alsa/asoundlib.h>

#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SND_PCM_FORMAT_S24_3 SND_PCM_FORMAT_S24_3LE
#elif __BYTE_ORDER == __BIG_ENDIAN
#define SND_PCM_FORMAT_S24_3 SND_PCM_FORMAT_S24_3BE
#endif



#include <jack/types.h>
#include <jack/hardware.h>
#include <jack/driver.h>


+ 190
- 0
drivers/alsa/memops.c View File

@@ -181,6 +181,163 @@ void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_
state->idx = idx;
}

void sample_move_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)

{
long long y;

while (nsamples--) {
y = (long long)(*src * SAMPLE_MAX_24BIT);

if (y > (INT_MAX >> 8 )) {
y = (INT_MAX >> 8);
} else if (y < (INT_MIN >> 8 )) {
y = (INT_MIN >> 8 );
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy (dst, &y, 3);
#elif __BYTE_ORDER == __BIG_ENDIAN
memcpy (dst, (char *)&y + 5, 3);
#endif
dst += dst_skip;
src++;
}
}

void sample_move_dS_s24u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip)
{
/* ALERT: signed sign-extension portability !!! */

while (nsamples--) {
int x;
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy((char*)&x + 1, src, 3);
#elif __BYTE_ORDER == __BIG_ENDIAN
memcpy(&x, src, 3);
#endif
x >>= 8;
*dst = x / SAMPLE_MAX_24BIT;
dst++;
src += src_skip;
}
}

void sample_move_dither_rect_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)

{
/* ALERT: signed sign-extension portability !!! */
jack_default_audio_sample_t x;
long long y;

while (nsamples--) {
x = *src * SAMPLE_MAX_16BIT;
x -= (float)fast_rand() / (float)INT_MAX;
y = (long long)f_round(x);

y <<= 8;

if (y > (INT_MAX >> 8)) {
y = (INT_MAX >> 8);
} else if (y < (INT_MIN >> 8)) {
y = (INT_MIN >> 8);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy (dst, &y, 3);
#elif __BYTE_ORDER == __BIG_ENDIAN
memcpy (dst, (char *)&y + 5, 3);
#endif

dst += dst_skip;
src++;
}
}

void sample_move_dither_tri_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
{
jack_default_audio_sample_t x;
float r;
float rm1 = state->rm1;
long long y;

while (nsamples--) {
x = *src * (float)SAMPLE_MAX_16BIT;
r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f;
x += r - rm1;
rm1 = r;
y = (long long)f_round(x);

y <<= 8;

if (y > (INT_MAX >> 8)) {
y = (INT_MAX >> 8);
} else if (y < (INT_MIN >> 8)) {
y = (INT_MIN >> 8);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy (dst, &y, 3);
#elif __BYTE_ORDER == __BIG_ENDIAN
memcpy (dst, (char *)&y + 5, 3);
#endif

dst += dst_skip;
src++;
}
state->rm1 = rm1;
}

void sample_move_dither_shaped_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
{
jack_default_audio_sample_t x;
jack_default_audio_sample_t xe; /* the innput sample - filtered error */
jack_default_audio_sample_t xp; /* x' */
float r;
float rm1 = state->rm1;
unsigned int idx = state->idx;
long long y;

while (nsamples--) {
x = *src * (float)SAMPLE_MAX_16BIT;
r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f;
/* Filter the error with Lipshitz's minimally audible FIR:
[2.033 -2.165 1.959 -1.590 0.6149] */
xe = x
- state->e[idx] * 2.033f
+ state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f
- state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f
+ state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f
- state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f;
xp = xe + r - rm1;
rm1 = r;

/* This could be some inline asm on x86 */
y = (long long)f_round(xp);

/* Intrinsic z^-1 delay */
idx = (idx + 1) & DITHER_BUF_MASK;
state->e[idx] = y - xe;

y <<= 8;

if (y > (INT_MAX >> 8)) {
y = (INT_MAX >> 8);
} else if (y < (INT_MIN >> 8)) {
y = (INT_MIN >> 8);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
memcpy (dst, &y, 3);
#elif __BYTE_ORDER == __BIG_ENDIAN
memcpy (dst, (char *)&y + 5, 3);
#endif

dst += dst_skip;
src++;
}
state->rm1 = rm1;
state->idx = idx;
}

void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
{
@@ -368,6 +525,13 @@ void memset_interleave (char *dst, char val, unsigned long bytes,
bytes -= 4;
}
break;
default:
while (bytes) {
memset(dst, val, unit_bytes);
dst += skip_bytes;
bytes -= unit_bytes;
}
break;
}
}

@@ -434,6 +598,19 @@ merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes,
}
}

void
merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes,
unsigned long dst_skip_bytes, unsigned long src_skip_bytes)
{
while (src_bytes) {
int acc = (*(int *)dst & 0xFFFFFF) + (*(int *)src & 0xFFFFFF);
memcpy(dst, &acc, 3);
dst += dst_skip_bytes;
src += src_skip_bytes;
src_bytes -= 3;
}
}

void
memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes,
unsigned long dst_skip_bytes, unsigned long src_skip_bytes)
@@ -446,6 +623,19 @@ memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes,
}
}

void
memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes,
unsigned long dst_skip_bytes, unsigned long src_skip_bytes)

{
while (src_bytes) {
memcpy(dst, src, 3);
dst += dst_skip_bytes;
src += src_skip_bytes;
src_bytes -= 3;
}
}

void
memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes,
unsigned long dst_skip_bytes, unsigned long src_skip_bytes)


+ 7
- 0
drivers/alsa/memops.h View File

@@ -42,16 +42,21 @@ typedef struct {


void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);

void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_rect_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_tri_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_shaped_d24u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);

void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
void sample_move_dS_s24u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);

void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
@@ -79,9 +84,11 @@ void memset_interleave (char *dst, char val, unsigned long bytes,
void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar);

void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);
void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);
void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);

void merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);
void merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);
void merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes);

void merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar);


Loading…
Cancel
Save