jackd and m-audio audiophile usb solution

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

jackd and m-audio audiophile usb solution

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

Hi,
attached (hopefully the list doesn't eat attachments) is a proof of
concept solution (playback only) that gets jackd working with the
m-audio audiophile usb audio and midi interface.

In short, the interface is big endian. I didn't look too deep in the non
interleaved operating mode as there are too many problems and I did need
a quick playback solution. In non interleaved mode jackd operates at 32
bits which is the physical width reported by alsa. Nevertheless the
interface seems to need contigous 24 bits... - I switched to interleaved
mode which is simpler.

In interleaved mode there are quite some overwrite bugs in memops.c that
should be corrected. And for the m-audio interface big endianess is
required.

If somebody wants to develop a permanent solution feel free to contact
me for tests.
--
Andreas Steinmetz                       SPAMmers use [hidden email]

--- 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-20 20:57:16.000000000 +0200
@@ -352,9 +352,9 @@
  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},
+ {"32bit", SND_PCM_FORMAT_S32_BE},
+ {"24bit", SND_PCM_FORMAT_S24_3BE},
+ {"16bit", SND_PCM_FORMAT_S16_BE},
  };
 #define NOFORMATS (sizeof(formats)/sizeof(formats[0]))
 
@@ -372,11 +372,11 @@
  }
 
  if ((err = snd_pcm_hw_params_set_access (
-     handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+     handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED))
     < 0) {
  if ((err = snd_pcm_hw_params_set_access (
      handle, hw_params,
-     SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
+     SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0) {
  jack_error ("ALSA: mmap-based access is not possible"
     " for the %s "
     "stream of this audio interface",
--- 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-20 21:52:29.000000000 +0200
@@ -53,16 +53,20 @@
 
 {
         long long y;
+ int z;
 
  while (nsamples--) {
  y = (long long)(*src * SAMPLE_MAX_24BIT) << 8;
  if (y > INT_MAX) {
- *((int *) dst) = INT_MAX;
+ z = INT_MAX;
  } else if (y < INT_MIN) {
- *((int *) dst) = INT_MIN;
+ z = INT_MIN;
  } else {
- *((int *) dst) = (int)y;
+ z = (int)y;
  }
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
  dst += dst_skip;
  src++;
  }
@@ -85,6 +89,7 @@
  /* ALERT: signed sign-extension portability !!! */
  jack_default_audio_sample_t  x;
  long long y;
+ int z;
 
  while (nsamples--) {
  x = *src * SAMPLE_MAX_16BIT;
@@ -92,12 +97,15 @@
  y = (long long)f_round(x);
  y <<= 16;
  if (y > INT_MAX) {
- *((int *) dst) = INT_MAX;
+ z = INT_MAX;
  } else if (y < INT_MIN) {
- *((int *) dst) = INT_MIN;
+ z = INT_MIN;
  } else {
- *((int *) dst) = (int)y;
+ z = (int)y;
  }
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
  dst += dst_skip;
  src++;
  }
@@ -110,6 +118,7 @@
  float     r;
  float     rm1 = state->rm1;
  long long y;
+ int z;
 
  while (nsamples--) {
  x = *src * (float)SAMPLE_MAX_16BIT;
@@ -120,12 +129,15 @@
  y <<= 16;
 
  if (y > INT_MAX) {
- *((int *) dst) = INT_MAX;
+ z = INT_MAX;
  } else if (y < INT_MIN) {
- *((int *) dst) = INT_MIN;
+ z = INT_MIN;
  } else {
- *((int *) dst) = (int)y;
+ z = (int)y;
  }
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
 
  dst += dst_skip;
  src++;
@@ -143,6 +155,7 @@
  float        rm1 = state->rm1;
  unsigned int idx = state->idx;
  long long    y;
+ int z;
 
  while (nsamples--) {
  x = *src * (float)SAMPLE_MAX_16BIT;
@@ -168,12 +181,15 @@
  y <<= 16;
 
  if (y > INT_MAX) {
- *((int *) dst) = INT_MAX;
+ z = INT_MAX;
  } else if (y < INT_MIN) {
- *((int *) dst) = INT_MIN;
+ z = INT_MIN;
  } else {
- *((int *) dst) = y;
+ z = y;
  }
+ dst[0]=(char)(z>>24);
+ dst[1]=(char)(z>>16);
+ dst[2]=(char)(z>>8);
  dst += dst_skip;
  src++;
  }
Reply | Threaded
Open this post in threaded view
|

Re: jackd and m-audio audiophile usb solution

Lee Revell
On Sat, 2005-08-20 at 22:19 +0200, Andreas Steinmetz wrote:
> [please cc me on replies, I'm not subscribed]
>
> Hi,
> attached (hopefully the list doesn't eat attachments) is a proof of
> concept solution (playback only) that gets jackd working with the
> m-audio audiophile usb audio and midi interface.

This seems like the wrong solution, why don't you just use plughw:x and
let ALSA do the conversion for you?

Lee



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: jackd and m-audio audiophile usb solution

Andreas Steinmetz
Lee Revell wrote:

> On Sat, 2005-08-20 at 22:19 +0200, Andreas Steinmetz wrote:
>
>>[please cc me on replies, I'm not subscribed]
>>
>>Hi,
>>attached (hopefully the list doesn't eat attachments) is a proof of
>>concept solution (playback only) that gets jackd working with the
>>m-audio audiophile usb audio and midi interface.
>
>
> This seems like the wrong solution, why don't you just use plughw:x and
> let ALSA do the conversion for you?
>
> Lee
>
I tried :-(
Now here comes what I'm using together with the patch:

From /etc/asound.conf:

pcm.m-audio
{
   type plug
   slave.pcm "hw:1,1"
}

ctl.m-audio
{
   type hw
   card 1
}

And now the jackd command line:

/usr/bin/jackd -R -P20 -dalsa -dm-audio -r48000 -p64 -n3 -P -o2

Without the patch all I can get is terrible noise. Wrong endian. To make
the problem a bit more clear I attach a patch against the alsa-libs pcm
test utility. I can get the audio interface to work in all test cases
only with this patch applied.

As you can see from the patch the simple alsa interfaces work without
any problem, the plug layer does the endian conversion. All mmap access,
however, requires proper endian conversion by the caller. And that is,
why jackd doesn't work right out of the box with this audio interface.
--
Andreas Steinmetz                       SPAMmers use [hidden email]

--- /usr/src/64/alsa-lib-1.0.9/test/pcm.c 2005-04-12 14:09:59.000000000 +0200
+++ pcm.c 2005-08-20 18:57:09.000000000 +0200
@@ -8,12 +8,11 @@
 #include <sched.h>
 #include <errno.h>
 #include <getopt.h>
-#include "../include/asoundlib.h"
+#include "alsa/asoundlib.h"
 #include <sys/time.h>
 #include <math.h>
 
 char *device = "plughw:0,0"; /* playback device */
-snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */
 unsigned int rate = 44100; /* stream rate */
 unsigned int channels = 1; /* count of channels */
 unsigned int buffer_time = 500000; /* ring buffer length in us */
@@ -28,7 +27,8 @@
 
 static void generate_sine(const snd_pcm_channel_area_t *areas,
   snd_pcm_uframes_t offset,
-  int count, double *_phase)
+  int count, double *_phase,
+  int swap)
 {
  static double max_phase = 2. * M_PI;
  double phase = *_phase;
@@ -58,7 +58,8 @@
  res = sin(phase) * 32767;
  ires = res;
  for (chn = 0; chn < channels; chn++) {
- *samples[chn] = ires;
+ if(swap)*samples[chn] = ((ires>>8)&0xff)|(ires<<8);
+ else *samples[chn] = ires;
  samples[chn] += steps[chn];
  }
  phase += step;
@@ -70,7 +71,8 @@
 
 static int set_hwparams(snd_pcm_t *handle,
  snd_pcm_hw_params_t *params,
- snd_pcm_access_t access)
+ snd_pcm_access_t access,
+ snd_pcm_format_t format)
 {
  unsigned int rrate;
  int err, dir;
@@ -222,7 +224,7 @@
  int err, cptr;
 
  while (1) {
- generate_sine(areas, 0, period_size, &phase);
+ generate_sine(areas, 0, period_size, &phase, 0);
  ptr = samples;
  cptr = period_size;
  while (cptr > 0) {
@@ -305,7 +307,7 @@
  }
  }
 
- generate_sine(areas, 0, period_size, &phase);
+ generate_sine(areas, 0, period_size, &phase, 0);
  ptr = samples;
  cptr = period_size;
  while (cptr > 0) {
@@ -366,7 +368,7 @@
 
  avail = snd_pcm_avail_update(handle);
  while (avail >= period_size) {
- generate_sine(areas, 0, period_size, &data->phase);
+ generate_sine(areas, 0, period_size, &data->phase, 0);
  err = snd_pcm_writei(handle, samples, period_size);
  if (err < 0) {
  printf("Initial write error: %s\n", snd_strerror(err));
@@ -397,7 +399,7 @@
  exit(EXIT_FAILURE);
  }
  for (count = 0; count < 2; count++) {
- generate_sine(areas, 0, period_size, &data.phase);
+ generate_sine(areas, 0, period_size, &data.phase, 0);
  err = snd_pcm_writei(handle, samples, period_size);
  if (err < 0) {
  printf("Initial write error: %s\n", snd_strerror(err));
@@ -485,7 +487,7 @@
  }
  first = 1;
  }
- generate_sine(my_areas, offset, frames, &data->phase);
+ generate_sine(my_areas, offset, frames, &data->phase, 1);
  commitres = snd_pcm_mmap_commit(handle, offset, frames);
  if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
  if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
@@ -529,7 +531,7 @@
  exit(EXIT_FAILURE);
  }
  }
- generate_sine(my_areas, offset, frames, &data.phase);
+ generate_sine(my_areas, offset, frames, &data.phase, 1);
  commitres = snd_pcm_mmap_commit(handle, offset, frames);
  if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
  if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
@@ -625,7 +627,7 @@
  }
  first = 1;
  }
- generate_sine(my_areas, offset, frames, &phase);
+ generate_sine(my_areas, offset, frames, &phase, 1);
  commitres = snd_pcm_mmap_commit(handle, offset, frames);
  if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
  if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
@@ -652,7 +654,7 @@
  int err, cptr;
 
  while (1) {
- generate_sine(areas, 0, period_size, &phase);
+ generate_sine(areas, 0, period_size, &phase, 1);
  ptr = samples;
  cptr = period_size;
  while (cptr > 0) {
@@ -682,17 +684,18 @@
  int (*transfer_loop)(snd_pcm_t *handle,
      signed short *samples,
      snd_pcm_channel_area_t *areas);
+ snd_pcm_format_t format;
 };
 
 static struct transfer_method transfer_methods[] = {
- { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop },
- { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop },
- { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop },
- { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop },
- { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop },
- { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop },
- { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop },
- { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL }
+ { "write", SND_PCM_ACCESS_RW_INTERLEAVED, write_loop, SND_PCM_FORMAT_S16_LE},
+ { "write_and_poll", SND_PCM_ACCESS_RW_INTERLEAVED, write_and_poll_loop, SND_PCM_FORMAT_S16_LE},
+ { "async", SND_PCM_ACCESS_RW_INTERLEAVED, async_loop, SND_PCM_FORMAT_S16_LE},
+ { "async_direct", SND_PCM_ACCESS_MMAP_INTERLEAVED, async_direct_loop, SND_PCM_FORMAT_S16_BE},
+ { "direct_interleaved", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_loop ,SND_PCM_FORMAT_S16_BE},
+ { "direct_noninterleaved", SND_PCM_ACCESS_MMAP_NONINTERLEAVED, direct_loop ,SND_PCM_FORMAT_S16_BE},
+ { "direct_write", SND_PCM_ACCESS_MMAP_INTERLEAVED, direct_write_loop, SND_PCM_FORMAT_S16_BE},
+ { NULL, SND_PCM_ACCESS_RW_INTERLEAVED, NULL, SND_PCM_FORMAT_S16_LE}
 };
 
 static void help(void)
@@ -816,7 +819,7 @@
  }
 
  printf("Playback device is %s\n", device);
- printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
+ printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(transfer_methods[method].format), channels);
  printf("Sine wave rate is %.4fHz\n", freq);
  printf("Using transfer method: %s\n", transfer_methods[method].name);
 
@@ -825,7 +828,7 @@
  return 0;
  }
 
- if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access)) < 0) {
+ if ((err = set_hwparams(handle, hwparams, transfer_methods[method].access, transfer_methods[method].format)) < 0) {
  printf("Setting of hwparams failed: %s\n", snd_strerror(err));
  exit(EXIT_FAILURE);
  }
@@ -837,7 +840,7 @@
  if (verbose > 0)
  snd_pcm_dump(handle, output);
 
- samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
+ samples = malloc((period_size * channels * snd_pcm_format_width(transfer_methods[method].format)) / 8);
  if (samples == NULL) {
  printf("No enough memory\n");
  exit(EXIT_FAILURE);