Endianness problem with snd-usb-audio on powerpc / quick and dirty patch

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

Endianness problem with snd-usb-audio on powerpc / quick and dirty patch

Jan Jockusch
Hello jackd developers,

first of all: don't apply these patches, just read them!
They did fix my problem, but they are destructive and render jackd unusable on little-endian machines. I did it this way simply because I'm not into jack development and I don't know the proper way to solve this issue. I hope one of you does.

My problem: Using jackd on a powerpc linux machine (G4 Cube) with a USB interface (M-Audio MobilePre) worked with OSS emulation (for some reason, in the latest release, it doesn't anymore), but always failed in ALSA mode with "unsupported audio format".

The first patch shows why: 16bit is mapped to the machine's native signed 16 Bit format (SND_PCM_FORMAT_S16 is defined as SND_PCM_FORMAT_S16_LE or SND_PCM_FORMAT_S16_BE depending on CPU architecture). Sadly, the USB device doesn't (or can't) necessarily follow the CPU architecture.

My (stupid) solution: In my (very underinformed) view this means that byte swapping needs to be done by the jack server. Hence the second patch, which adds byte swapping to some (not all!) of the memops. I am perfectly aware of the brute-force-and-ignorance character that this approach has. I post these patches only to give a clearer view of the nature of the problem.

If anyone knows how to fix this issue properly, I would greatly appreciate your help. You can also point me in the right direction, and I'll do the dirty work (implementing and testing) and re-submit some  more useful patches. If my approach seems vaguely right, and you want me to make a cleaner (switchable) patch, please notify.

Thanks for an awesome and very useful software package! Jack and the zoo of applications around it are really the biggest reason for my new interest in digital music making. Keep up the good work!

Greetings from Germany,

Ján Jockusch


PS: This is a re-post because I didn't use the proper FROM email address. Sorry, no experience...


*** drivers/alsa/alsa_driver.c.orig 2005-11-01 17:20:08.000000000 +0100
--- drivers/alsa/alsa_driver.c 2005-11-01 17:20:22.000000000 +0100
***************
*** 335,341 ****
  } formats[] = {
  {"32bit", SND_PCM_FORMAT_S32},
  {"24bit", SND_PCM_FORMAT_S24_3},
! {"16bit", SND_PCM_FORMAT_S16},
  };
  #define NOFORMATS (sizeof(formats)/sizeof(formats[0]))
 
--- 335,341 ----
  } formats[] = {
  {"32bit", SND_PCM_FORMAT_S32},
  {"24bit", SND_PCM_FORMAT_S24_3},
! {"16bit", SND_PCM_FORMAT_S16_LE},
  };
  #define NOFORMATS (sizeof(formats)/sizeof(formats[0]))
 


*** drivers/alsa/memops.c.orig 2005-11-02 20:26:19.000000000 +0100
--- drivers/alsa/memops.c 2005-11-02 20:26:26.000000000 +0100
***************
*** 36,41 ****
--- 36,48 ----
  #define SAMPLE_MAX_24BIT  8388608.0f
  #define SAMPLE_MAX_16BIT  32768.0f
 
+
+ inline unsigned int swap_bytes(unsigned int);
+ inline unsigned int swap_bytes(unsigned int w) {
+   return ((w&0xff)<<8)|((w>>8)&0xff);
+ }
+
+
  #define f_round(f) lrintf(f)
 
  /* Linear Congruential noise generator. From the music-dsp list
***************
*** 341,359 ****
  void sample_move_d16_sS (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) {
! *((short *)dst) = SHRT_MAX;
  } else if (tmp < SHRT_MIN) {
! *((short *)dst) = SHRT_MIN;
  } else {
! *((short *) dst) = (short) tmp;
  }
  dst += dst_skip;
  src++;
  }
--- 348,369 ----
  void sample_move_d16_sS (char *dst,  jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state)
 
  {
! int      tmp;
! short    swp;
 
  /* ALERT: signed sign-extension portability !!! */
 
  while (nsamples--) {
  tmp = f_round(*src * SAMPLE_MAX_16BIT);
  if (tmp > SHRT_MAX) {
! swp = SHRT_MAX;
  } else if (tmp < SHRT_MIN) {
! swp = SHRT_MIN;
  } else {
! swp = (short)tmp;
  }
+                 /* XXX Byte-swapping: necessary on BE systems. */
+ (*(short *)dst) = swap_bytes(swp);
  dst += dst_skip;
  src++;
  }
***************
*** 364,381 ****
  {
  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) {
! *((short *)dst) = SHRT_MAX;
  } else if (tmp < SHRT_MIN) {
! *((short *)dst) = SHRT_MIN;
  } else {
! *((short *) dst) = (short)tmp;
  }
  dst += dst_skip;
  src++;
  }
--- 374,395 ----
  {
  jack_default_audio_sample_t val;
  int      tmp;
+ short    swp;
 
  while (nsamples--) {
  val = *src * (float)SAMPLE_MAX_16BIT;
  val -= (float)fast_rand() / (float)INT_MAX;
  tmp = f_round(val);
  if (tmp > SHRT_MAX) {
! swp = SHRT_MAX;
  } else if (tmp < SHRT_MIN) {
! swp = SHRT_MIN;
  } else {
! swp = (short)tmp;
  }
+                 /* XXX Byte-swapping: necessary on BE systems. */
+ (*(short *)dst) = swap_bytes(swp);
+
  dst += dst_skip;
  src++;
  }
***************
*** 388,393 ****
--- 402,408 ----
  float    r;
  float    rm1 = state->rm1;
  int      y;
+         short    swp;
 
  while (nsamples--) {
  x = *src * (float)SAMPLE_MAX_16BIT;
***************
*** 397,408 ****
  y = f_round(x);
 
  if (y > SHRT_MAX) {
! *((short *)dst) = SHRT_MAX;
  } else if (y < SHRT_MIN) {
! *((short *)dst) = SHRT_MIN;
  } else {
! *((short *) dst) = (short)y;
  }
 
  dst += dst_skip;
  src++;
--- 412,425 ----
  y = f_round(x);
 
  if (y > SHRT_MAX) {
! swp = SHRT_MAX;
  } else if (y < SHRT_MIN) {
! swp = SHRT_MIN;
  } else {
! swp = (short)y;
  }
+                 /* XXX Byte-swapping: necessary on BE systems. */
+ (*(short *)dst) = swap_bytes(swp);
 
  dst += dst_skip;
  src++;
***************
*** 420,425 ****
--- 437,443 ----
  float        rm1 = state->rm1;
  unsigned int idx = state->idx;
  int          y;
+         short        swp;
 
  while (nsamples--) {
  x = *src * (float)SAMPLE_MAX_16BIT;
***************
*** 443,454 ****
  state->e[idx] = y - xe;
 
  if (y > SHRT_MAX) {
! *((short *)dst) = SHRT_MAX;
  } else if (y < SHRT_MIN) {
! *((short *)dst) = SHRT_MIN;
  } else {
! *((short *) dst) = (short)y;
  }
  dst += dst_skip;
  src++;
  }
--- 461,474 ----
  state->e[idx] = y - xe;
 
  if (y > SHRT_MAX) {
! swp = SHRT_MAX;
  } else if (y < SHRT_MIN) {
! swp = SHRT_MIN;
  } else {
! swp = (short)y;
  }
+                 /* XXX Byte-swapping: necessary on BE systems. */
+ (*(short *)dst) = swap_bytes(swp);
  dst += dst_skip;
  src++;
  }
***************
*** 461,467 ****
  {
  /* ALERT: signed sign-extension portability !!! */
  while (nsamples--) {
! *dst = (*((short *) src)) / SAMPLE_MAX_16BIT;
  dst++;
  src += src_skip;
  }
--- 481,490 ----
  {
  /* ALERT: signed sign-extension portability !!! */
  while (nsamples--) {
!        /* XXX Byte-swapping: Necessary on BE systems. */
! *dst = ((short)swap_bytes(*((short *) src))) / SAMPLE_MAX_16BIT;
!
!
  dst++;
  src += src_skip;
  }
***************
*** 483,488 ****
--- 506,512 ----
  } else {
  *((short *) dst) += val;
  }
+
  dst += dst_skip;
  src++;
  }
***************
*** 545,550 ****
--- 569,575 ----
  void
  memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar)
  {
+         /* XXX Byte-swapping: Not necessary here, I hope... */
  memcpy (dst, src, src_bytes);
  }
 
***************
*** 579,585 ****
 
  {
  while (src_bytes) {
! *((short *) dst) += *((short *) src);
  dst += dst_skip_bytes;
  src += src_skip_bytes;
  src_bytes -= 2;
--- 604,610 ----
 
  {
  while (src_bytes) {
!        *((short *) dst) += *((short *) src);
  dst += dst_skip_bytes;
  src += src_skip_bytes;
  src_bytes -= 2;
***************
*** 616,621 ****
--- 641,647 ----
    unsigned long dst_skip_bytes, unsigned long src_skip_bytes)
  {
  while (src_bytes) {
+        /* XXX Byte-swapping: not necessary here. */
  *((short *) dst) = *((short *) src);
  dst += dst_skip_bytes;
  src += src_skip_bytes;