[PATCH] support byte swapped devices like the m-audio audiophile usb

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] support byte swapped devices like the m-audio audiophile usb

Andreas Steinmetz
[please cc me on replies, I'm not subscribed]

The attached patch allows usage of byte swapped devices like the m-audio
audiophile usb with jackd.

The patch is tested with the audiophile usb for playback and capture as
well as with an onboard iec958 playback only device that doesn't require
the patch.

Some reasoning why it is not a good idea to point to plughw: in case of
jackd for byte swapped devices:

1. Jackd uses alsa's mmapped I/O for efficiency. Mmapped I/O bypasses
   alsa's plug layer so alsa does no endianess conversion. Thus using
   a byte swapped device with jackd is impossible without this patch.

2. If jackd accesses a plug device alsa grants I/O formats that would
   be converted by the plug layer. These formats can differ in physical
   width from the actual hw format (e.g. S32_LE for the plug layer
   when the actual device accepts only S24_3BE). Mmapped alsa I/O
   expects the format as required by the actual device so there is
   most probably a format and/or data width mismatch.

Some hints for m-audio audiophile usb users:

The alsa device layout is a bit strange. Assuming that the device is
card 1, then:

hw:1,0 is iec958 for capture and analogue/headphone for playback
hw:1,1 is analogue for capture and iec958 for playback

I did never test analogue capture as I don't need it.

To use e.g. capture and playback at 48000Hz sampling rate on the iec958
interface use a jackd command line like the following after applying the
attached patch:

jackd -R -P20 -dalsa -r48000 -p64 -n4 -D -Chw:1,0 -Phw:1,1 -i2 -o2
--
Andreas Steinmetz                       SPAMmers use [hidden email]

diff -rNup jack-audio-connection-kit-0.100.0.orig/drivers/alsa/alsa_driver.c jack-audio-connection-kit-0.100.0/drivers/alsa/alsa_driver.c
--- jack-audio-connection-kit-0.100.0.orig/drivers/alsa/alsa_driver.c 2005-05-12 16:57:58.000000000 +0200
+++ jack-audio-connection-kit-0.100.0/drivers/alsa/alsa_driver.c 2005-08-22 20:00:50.000000000 +0200
@@ -239,22 +239,28 @@ alsa_driver_setup_io_function_pointers (
  switch (driver->dither) {
  case Rectangular:
  printf("Rectangular dithering at 16 bits\n");
- driver->write_via_copy = sample_move_dither_rect_d16_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_rect_d16_sSs:
+ sample_move_dither_rect_d16_sS;
  break;
 
  case Triangular:
  printf("Triangular dithering at 16 bits\n");
- driver->write_via_copy = sample_move_dither_tri_d16_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_tri_d16_sSs:
+ sample_move_dither_tri_d16_sS;
  break;
 
  case Shaped:
  printf("Noise-shaped dithering at 16 bits\n");
- driver->write_via_copy =
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_shaped_d16_sSs:
  sample_move_dither_shaped_d16_sS;
  break;
 
  default:
- driver->write_via_copy = sample_move_d16_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d16_sSs : sample_move_d16_sS;
  break;
  }
  break;
@@ -269,22 +275,28 @@ alsa_driver_setup_io_function_pointers (
  switch (driver->dither) {
  case Rectangular:
  printf("Rectangular dithering at 16 bits\n");
- driver->write_via_copy = sample_move_dither_rect_d24_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_rect_d24_sSs:
+ sample_move_dither_rect_d24_sS;
  break;
 
  case Triangular:
  printf("Triangular dithering at 16 bits\n");
- driver->write_via_copy = sample_move_dither_tri_d24_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_tri_d24_sSs:
+ sample_move_dither_tri_d24_sS;
  break;
 
  case Shaped:
  printf("Noise-shaped dithering at 16 bits\n");
- driver->write_via_copy =
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_shaped_d24_sSs:
  sample_move_dither_shaped_d24_sS;
  break;
 
  default:
- driver->write_via_copy = sample_move_d24_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d24_sSs : sample_move_d24_sS;
  break;
  }
  break;
@@ -299,24 +311,28 @@ alsa_driver_setup_io_function_pointers (
  switch (driver->dither) {
  case Rectangular:
  printf("Rectangular dithering at 16 bits\n");
- driver->write_via_copy =
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_rect_d32u24_sSs:
  sample_move_dither_rect_d32u24_sS;
  break;
 
  case Triangular:
  printf("Triangular dithering at 16 bits\n");
- driver->write_via_copy =
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_tri_d32u24_sSs:
  sample_move_dither_tri_d32u24_sS;
  break;
 
  case Shaped:
  printf("Noise-shaped dithering at 16 bits\n");
- driver->write_via_copy =
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_shaped_d32u24_sSs:
  sample_move_dither_shaped_d32u24_sS;
  break;
 
  default:
- driver->write_via_copy = sample_move_d32u24_sS;
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d32u24_sSs : sample_move_d32u24_sS;
  break;
  }
  break;
@@ -324,13 +340,16 @@ alsa_driver_setup_io_function_pointers (
 
  switch (driver->capture_sample_bytes) {
  case 2:
- driver->read_via_copy = sample_move_dS_s16;
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s16s : sample_move_dS_s16;
  break;
  case 3:
- driver->read_via_copy = sample_move_dS_s24;
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s24s : sample_move_dS_s24;
  break;
  case 4:
- driver->read_via_copy = sample_move_dS_s32u24;
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s32u24s : sample_move_dS_s32u24;
  break;
  }
 }
@@ -351,10 +370,14 @@ alsa_driver_configure_stream (alsa_drive
  static struct {
  char Name[16];
  snd_pcm_format_t format;
+ int swapped;
  } formats[] = {
- {"32bit", SND_PCM_FORMAT_S32},
- {"24bit", SND_PCM_FORMAT_S24_3},
- {"16bit", SND_PCM_FORMAT_S16},
+ {"32bit little", SND_PCM_FORMAT_S32_LE, IS_LE},
+ {"32bit big", SND_PCM_FORMAT_S32_BE, IS_BE},
+ {"24bit little", SND_PCM_FORMAT_S24_3LE, IS_LE},
+ {"24bit big", SND_PCM_FORMAT_S24_3BE, IS_BE},
+ {"16bit little", SND_PCM_FORMAT_S16_LE, IS_LE},
+ {"16bit big", SND_PCM_FORMAT_S16_LE, IS_BE},
  };
 #define NOFORMATS (sizeof(formats)/sizeof(formats[0]))
 
@@ -393,8 +416,8 @@ alsa_driver_configure_stream (alsa_drive
  if ((sample_width == 4
      ? format++ < NOFORMATS - 1
      : format-- > 0)) {
- jack_error ("Note: audio device %s doesn't support a %s sample format"
-    " so JACK will try a %s format instead", device_name,
+ jack_error ("Note: audio device %s doesn't support a %s endian sample format"
+    " so JACK will try a %s endian format instead", device_name,
     formats[failed_format].Name,
     formats[format].Name);
  } else {
@@ -405,8 +428,10 @@ alsa_driver_configure_stream (alsa_drive
     device_name);
  return -1;
  }
- } else
+ } else {
+ driver->quirk_bswap = formats[format].swapped;
  break;
+ }
  }
 
  frame_rate = driver->frame_rate ;
@@ -727,7 +752,8 @@ alsa_driver_set_parameters (alsa_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_S24_3LE:
+ case SND_PCM_FORMAT_S24_3BE:
  case SND_PCM_FORMAT_S16_LE:
  case SND_PCM_FORMAT_S32_BE:
  case SND_PCM_FORMAT_S16_BE:
@@ -743,7 +769,8 @@ alsa_driver_set_parameters (alsa_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_S24_3LE:
+ case SND_PCM_FORMAT_S24_3BE:
  case SND_PCM_FORMAT_S16_LE:
  case SND_PCM_FORMAT_S32_BE:
  case SND_PCM_FORMAT_S16_BE:
@@ -2011,6 +2038,8 @@ alsa_driver_new (char *name, char *playb
  driver->dither = dither;
  driver->soft_mode = soft_mode;
 
+ driver->quirk_bswap = 0;
+
  pthread_mutex_init (&driver->clock_sync_lock, 0);
  driver->clock_sync_listeners = 0;
 
diff -rNup jack-audio-connection-kit-0.100.0.orig/drivers/alsa/alsa_driver.h jack-audio-connection-kit-0.100.0/drivers/alsa/alsa_driver.h
--- jack-audio-connection-kit-0.100.0.orig/drivers/alsa/alsa_driver.h 2005-05-03 15:31:47.000000000 +0200
+++ jack-audio-connection-kit-0.100.0/drivers/alsa/alsa_driver.h 2005-08-22 20:02:36.000000000 +0200
@@ -25,9 +25,11 @@
 #include <jack/bitset.h>
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
- #define SND_PCM_FORMAT_S24_3 SND_PCM_FORMAT_S24_3LE
+#define IS_LE 0
+#define IS_BE 1
 #elif __BYTE_ORDER == __BIG_ENDIAN
- #define SND_PCM_FORMAT_S24_3 SND_PCM_FORMAT_S24_3BE
+#define IS_LE 1
+#define IS_BE 0
 #endif
 
 
@@ -131,6 +133,7 @@ typedef struct _alsa_driver {
     char has_clock_sync_reporting : 1;
     char has_hw_monitoring : 1;
     char has_hw_metering : 1;
+    char quirk_bswap : 1;
 
     int running;
     int run;
diff -rNup jack-audio-connection-kit-0.100.0.orig/drivers/alsa/memops.c jack-audio-connection-kit-0.100.0/drivers/alsa/memops.c
--- jack-audio-connection-kit-0.100.0.orig/drivers/alsa/memops.c 2004-03-25 20:31:50.000000000 +0100
+++ jack-audio-connection-kit-0.100.0/drivers/alsa/memops.c 2005-08-22 20:33:22.000000000 +0200
@@ -49,6 +49,37 @@ inline unsigned int fast_rand() {
  return seed;
 }
 
+void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
+
+{
+        long long y;
+ int z;
+
+ while (nsamples--) {
+ y = (long long)(*src * SAMPLE_MAX_24BIT) << 8;
+ if (y > INT_MAX) {
+ z = INT_MAX;
+ } else if (y < INT_MIN) {
+ z = INT_MIN;
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
+ dst[3]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+ dst[3]=(char)(z>>24);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -68,6 +99,35 @@ void sample_move_d32u24_sS (char *dst, j
  }
 }
 
+void sample_move_dS_s32u24s (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
+ x = (unsigned char)(src[0]);
+ x <<= 8;
+ x |= (unsigned char)(src[1]);
+ x <<= 8;
+ x |= (unsigned char)(src[2]);
+ x <<= 8;
+ x |= (unsigned char)(src[3]);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ x = (unsigned char)(src[3]);
+ x <<= 8;
+ x |= (unsigned char)(src[2]);
+ x <<= 8;
+ x |= (unsigned char)(src[1]);
+ x <<= 8;
+ x |= (unsigned char)(src[0]);
+#endif
+ *dst = (x >> 8) / SAMPLE_MAX_24BIT;
+ dst++;
+ src += src_skip;
+ }
+}
+
 void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip)
 {
  /* ALERT: signed sign-extension portability !!! */
@@ -79,6 +139,42 @@ void sample_move_dS_s32u24 (jack_default
  }
 }
 
+void sample_move_dither_rect_d32u24_sSs (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;
+ int z;
+
+ while (nsamples--) {
+ x = *src * SAMPLE_MAX_16BIT;
+ x -= (float)fast_rand() / (float)INT_MAX;
+ y = (long long)f_round(x);
+ y <<= 16;
+ if (y > INT_MAX) {
+ z = INT_MAX;
+ } else if (y < INT_MIN) {
+ z = INT_MIN;
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
+ dst[3]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+ dst[3]=(char)(z>>24);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 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)
 
 {
@@ -103,6 +199,47 @@ void sample_move_dither_rect_d32u24_sS (
  }
 }
 
+void sample_move_dither_tri_d32u24_sSs (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;
+ int z;
+
+ 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 <<= 16;
+
+ if (y > INT_MAX) {
+ z = INT_MAX;
+ } else if (y < INT_MIN) {
+ z = INT_MIN;
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
+ dst[3]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+ dst[3]=(char)(z>>24);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+}
+
 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)
 
 {
@@ -133,6 +270,66 @@ void sample_move_dither_tri_d32u24_sS (c
  state->rm1 = rm1;
 }
 
+void sample_move_dither_shaped_d32u24_sSs (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;
+ int z;
+
+ 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 <<= 16;
+
+ if (y > INT_MAX) {
+ z = INT_MAX;
+ } else if (y < INT_MIN) {
+ z = INT_MIN;
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
+ dst[3]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+ dst[3]=(char)(z>>24);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+ state->idx = idx;
+}
+
 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)
 
 {
@@ -181,6 +378,36 @@ void sample_move_dither_shaped_d32u24_sS
  state->idx = idx;
 }
 
+void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
+
+{
+        long long y;
+ int z;
+
+ while (nsamples--) {
+ y = (long long)(*src * SAMPLE_MAX_24BIT);
+
+ if (y > (INT_MAX >> 8 )) {
+ z = (INT_MAX >> 8);
+ } else if (y < (INT_MIN >> 8 )) {
+ z = (INT_MIN >> 8 );
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>16);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -204,6 +431,33 @@ void sample_move_d24_sS (char *dst, jack
  }
 }
 
+void sample_move_dS_s24s (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
+ x = (unsigned char)(src[0]);
+ x <<= 8;
+ x |= (unsigned char)(src[1]);
+ x <<= 8;
+ x |= (unsigned char)(src[2]);
+ x <<= 8;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ x = (unsigned char)(src[2]);
+ x <<= 8;
+ x |= (unsigned char)(src[1]);
+ x <<= 8;
+ x |= (unsigned char)(src[0]);
+ x <<= 8;
+#endif
+ *dst = (x >> 8) / SAMPLE_MAX_24BIT;
+ dst++;
+ src += src_skip;
+ }
+}
+
 void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip)
 {
  /* ALERT: signed sign-extension portability !!! */
@@ -222,6 +476,42 @@ void sample_move_dS_s24 (jack_default_au
  }
 }
 
+void sample_move_dither_rect_d24_sSs (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;
+ int z;
+
+ 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)) {
+ z = (INT_MAX >> 8);
+ } else if (y < (INT_MIN >> 8)) {
+ z = (INT_MIN >> 8);
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>16);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -252,6 +542,46 @@ void sample_move_dither_rect_d24_sS (cha
  }
 }
 
+void sample_move_dither_tri_d24_sSs (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;
+ int z;
+
+ 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)) {
+ z = (INT_MAX >> 8);
+ } else if (y < (INT_MIN >> 8)) {
+ z = (INT_MIN >> 8);
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>16);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+}
+
 void sample_move_dither_tri_d24_sS (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -286,6 +616,64 @@ void sample_move_dither_tri_d24_sS (char
  state->rm1 = rm1;
 }
 
+void sample_move_dither_shaped_d24_sSs (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;
+ int z;
+
+ 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)) {
+ z = (INT_MAX >> 8);
+ } else if (y < (INT_MIN >> 8)) {
+ z = (INT_MIN >> 8);
+ } else {
+ z = (int)y;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(z>>16);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(z);
+ dst[1]=(char)(z>>8);
+ dst[2]=(char)(z>>16);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+ state->idx = idx;
+}
+
 void sample_move_dither_shaped_d24_sS (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -338,6 +726,32 @@ void sample_move_dither_shaped_d24_sS (c
  state->idx = idx;
 }
 
+void sample_move_d16_sSs (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
+
+{
+ int tmp;
+
+ /* ALERT: signed sign-extension portability !!! */
+
+ while (nsamples--) {
+ tmp = f_round(*src * SAMPLE_MAX_16BIT);
+ if (tmp > SHRT_MAX) {
+ tmp = SHRT_MAX;
+ } else if (tmp < SHRT_MIN) {
+ tmp = SHRT_MIN;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(tmp>>8);
+ dst[1]=(char)(tmp);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(tmp);
+ dst[1]=(char)(tmp>>8);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 void sample_move_d16_sS (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
 {
@@ -359,6 +773,33 @@ void sample_move_d16_sS (char *dst,  jac
  }
 }
 
+void sample_move_dither_rect_d16_sSs (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
+
+{
+ jack_default_audio_sample_t val;
+ int      tmp;
+
+ while (nsamples--) {
+ val = *src * (float)SAMPLE_MAX_16BIT;
+ val -= (float)fast_rand() / (float)INT_MAX;
+ tmp = f_round(val);
+ if (tmp > SHRT_MAX) {
+ tmp = SHRT_MAX;
+ } else if (tmp < SHRT_MIN) {
+ tmp = SHRT_MIN;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(tmp>>8);
+ dst[1]=(char)(tmp);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(tmp);
+ dst[1]=(char)(tmp>>8);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+}
+
 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)
 
 {
@@ -381,6 +822,39 @@ void sample_move_dither_rect_d16_sS (cha
  }
 }
 
+void sample_move_dither_tri_d16_sSs (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;
+ int      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 = f_round(x);
+
+ if (y > SHRT_MAX) {
+ y = SHRT_MAX;
+ } else if (y < SHRT_MIN) {
+ y = SHRT_MIN;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(y>>8);
+ dst[1]=(char)(y);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(y);
+ dst[1]=(char)(y>>8);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+}
+
 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)
 
 {
@@ -410,6 +884,57 @@ void sample_move_dither_tri_d16_sS (char
  state->rm1 = rm1;
 }
 
+void sample_move_dither_shaped_d16_sSs (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;
+ int          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 = f_round(xp);
+
+ /* Intrinsic z^-1 delay */
+ idx = (idx + 1) & DITHER_BUF_MASK;
+ state->e[idx] = y - xe;
+
+ if (y > SHRT_MAX) {
+ y = SHRT_MAX;
+ } else if (y < SHRT_MIN) {
+ y = SHRT_MIN;
+ }
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ dst[0]=(char)(y>>8);
+ dst[1]=(char)(y);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ dst[0]=(char)(y);
+ dst[1]=(char)(y>>8);
+#endif
+ dst += dst_skip;
+ src++;
+ }
+ state->rm1 = rm1;
+ state->idx = idx;
+}
+
 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)
 
 {
@@ -456,6 +981,28 @@ void sample_move_dither_shaped_d16_sS (c
  state->idx = idx;
 }
 
+void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip)
+
+{
+ short z;
+
+ /* ALERT: signed sign-extension portability !!! */
+ while (nsamples--) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ z = (unsigned char)(src[0]);
+ z <<= 8;
+ z |= (unsigned char)(src[1]);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ z = (unsigned char)(src[1]);
+ z <<= 8;
+ z |= (unsigned char)(src[0]);
+#endif
+ *dst = z / SAMPLE_MAX_16BIT;
+ dst++;
+ src += src_skip;
+ }
+}
+
 void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip)
 
 {
diff -rNup jack-audio-connection-kit-0.100.0.orig/jack/memops.h jack-audio-connection-kit-0.100.0/jack/memops.h
--- jack-audio-connection-kit-0.100.0.orig/jack/memops.h 2004-03-25 20:31:50.000000000 +0100
+++ jack-audio-connection-kit-0.100.0/jack/memops.h 2005-08-21 15:17:22.000000000 +0200
@@ -41,22 +41,37 @@ typedef struct {
 } dither_state_t;
 
 
+void sample_move_d32u24_sSs          (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
 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_d24_sSs             (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
 void sample_move_d24_sS              (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
+void sample_move_d16_sSs             (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_d24_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_d24_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_d24_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_dither_rect_d32u24_sSs   (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_sSs    (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_sSs (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_d24_sSs      (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
+void sample_move_dither_rect_d24_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_d24_sSs       (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
+void sample_move_dither_tri_d24_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_d24_sSs    (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state);
+void sample_move_dither_shaped_d24_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_sSs      (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_sSs       (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_sSs    (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_s32u24s          (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
 void sample_move_dS_s32u24           (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
+void sample_move_dS_s24s             (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
 void sample_move_dS_s24              (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip);
+void sample_move_dS_s16s             (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);