Something's odd here...
I'm trying to de-interleave the stereo output from sfront
into discrete channel buffers suitable for jack. Everything's
fine when number of channels = 1; but when it's 2, it seems
that I get the left channel in both outputs. I've confirmed
that the left and right outputs are different when running
with oss audio output instead of jack.

I have a buffer called tempbuf, which contains nframes channel-interleaved
sample frames. Call it tempbuf. e.g.:

long nframes;
long nsamples = nframes * ASYS_OCHAN;  
/* ASYS_OCHAN is the number of channels */

float* tempbuf = (float*) calloc(nsamples, sizeof(float));


next, I set up an array of buffers into which I want to put
the deinterleaved output:

float* obuf[ASYS_OCHAN];

for(i=0; i < ASYS_OCHAN; i++) {
        obuf[i] = (float*) calloc(nframes, sizeof(float));
        /* actually I use jack_port_get_buffer() instead of calloc... */
        /* and actually there are various typedefs in use, not float */
}


That's all fine, as far as I can tell. Now here's the de-interleaving
code:


for(i=0; i < nsamples; i++) {
        obuf[i % ASYS_OCHAN][i / ASYS_OCHAN] = tempbuf[i];
}


The effect this *should* have (when ASYS_OCHAN = 2):

obuf[0][0] = tempbuf[0]
obuf[1][0] = tempbuf[1]
obuf[0][1] = tempbuf[2]
obuf[1][1] = tempbuf[3]
obuf[0][2] = tempbuf[4]
obuf[1][2] = tempbuf[5]
...



... but I'm hearing the left output on both channels.
Have I made some silly mistake in the de-interleaving?
Any other ideas on what I could've done wrong?
Complete actual code attached if anyone wants to see more
context...

-- 

Paul Winkler
home:  http://www.slinkp.com
"Muppet Labs, where the future is made - today!"
/*   TO TO:
 - do asys_isetup and asys_iosetup.

 - FIgure out why 2-channel output is working but sounds
   totally fucked up.


 - buffer size change:
 jack_get_buffer_size() can be called ONLY before client activation
 to find out current max buffer size.
 While running, if jack changes buffer size, it calls function registered
 with jack_set_buffer_size_callback.
 On the sfront side:
 asys_orun's 2nd argument is a pointer to long whose value represents
 the max number of sample periods available.

Hmm, I'm not sure I need to register a function with jack;
 looks like sfront can handle any buffer size at any time
 (as  long as it is a multiple of the number of channels).
*/


/*
#    Sfront, a SAOL to C translator    
#    This file: jackd audio driver for sfront
#    copyright (c) 2002 Paul M. Winkler, Brooklyn, NY
#                  www.slinkp.com
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Maintainer: Paul Winkler   www.slinkp.com 
*/


/* includes needed for JACK */
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <jack/jack.h>
/* include <glib.h> */

/* defines needed by sfront */
#define ASYSN_JACK_DEBUG          1   /* debugging printouts */
#define ASYSN_JACK_SLEEPMS      5   /* exit interval */

/* declarations needed for jack */
jack_port_t *asysn_jack_input_port[ASYS_ICHAN] ;
jack_port_t *asysn_jack_output_port[ASYS_OCHAN];
jack_client_t *asysn_jack_client;

/* declarations needed for sfront */
volatile int asysn_jack_proc_status;  /* used to signal status */

/* my own stuff */
char asysn_jack_client_name[256] = "SAOL Test Client";
int asysn_jack_srate_was_called = 0;
int asysn_jack_oports_connected = 0;
int asysn_jack_iports_connected = 0;

void asysn_jack_print_usage(void);

void asysn_jack_print_usage(void) {
  fprintf(stderr, "Usage: ... write useful blahblah here\n");
}


/* callback functions used by jack in various scenarios */
/** OUTPUT ONLY **/
#if defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT)
int asysn_jack_process (jack_nframes_t nframes, void * arg )
     /* cast arg to pointer to whatever I need. */
{
  /* OUTPUT ONLY */
  /* vars. copied from portaudio driver....
     but this is my jack process() function, which only gets 
     a nframes & a pointer-to-void argument.
  */
  long nsamples = (long) nframes * ASYS_OCHAN;
  long oremaining = nsamples ;
  long optr = 0;
  long osize;
  jack_default_audio_sample_t* obuf[ASYS_OCHAN];
  ASYS_OTYPE* tempbuf;
  int i, j;
  
  if (asysn_jack_srate_was_called >1) {
    /* force jack to remove this client as per PBD message on jackit-devel 
       on 4/24/02 (thread: "stereo?")
    */
    printf("uh-oh... called srate again, and we can't handle it\n");
    return 1;
  }

  /* printf("calling process...\n"); */
  /* Get memory buffers associated with the jack output ports. */
  for (i=0; i< ASYS_OCHAN; i++) { 
    obuf[i] = (jack_default_audio_sample_t *) 
      jack_port_get_buffer(asysn_jack_output_port[i], 
			   nframes);
  }
  /* sfront wants one interleaved buffer, so we need a separate one for that */
  tempbuf = (ASYS_OTYPE *) calloc(nsamples, sizeof(ASYS_OTYPE));
  
  /* Keep running while result is not ASYS_EXIT */
  while ((asysn_jack_proc_status == ASYS_DONE) && (oremaining > 0)) {
    osize = oremaining;
    /* WHITE NOISE TEST */
    /* output should be random between -0.5 and 0.5 */ 
    /* for(; optr < osize;  optr++) {
       tempbuf[optr]= ((float) rand()) / RAND_MAX - 0.5; 
       }
    */

    /*      asys_orun is defined by sfront */
    /*      According to the sfront manual, it "writes at most  */
    /*      the next *osize channel-interleaved sample values */
    /*      into the buffer". */

    /* remember that asys_orun will leave osize set to the
       actual number of samples that it wrote! */
    asysn_jack_proc_status =asys_orun(tempbuf, &osize);
    
    oremaining -= osize;

    //if (oremaining == 0) {
    //  printf("wrote: %d\n", osize);
    //}
    //else {
    //printf("remaining: %d written: %d\n", oremaining, osize);
      // we didn't write into the whole buffer! why not?
      // look at what portaudio driver does here.
      // I think it fills the rest with zeroes...
    //}

    /* DE-INTERLEAVE */
    for(i=0; i < nsamples; i++) {
      // cast is probably a no-op but can't hurt.
      obuf[i%ASYS_OCHAN][i/ASYS_OCHAN] = 
	(jack_default_audio_sample_t) tempbuf[i];
    }
    free(tempbuf);

  } 
  return 0;
}
#endif


/** INPUT ONLY **/
#if defined(ASYS_HASINPUT) && !defined(ASYS_HASOUTPUT)
int asysn_jack_process (jack_nframes_t nframes, void * arg)
{
  /* INPUT ONLY */
  printf("I");
  return 0;
}
#endif


/** INPUT AND OUTPUT **/
#if defined(ASYS_HASINPUT) && defined(ASYS_HASOUTPUT)
int asysn_jack_process (jack_nframes_t nframes, void *arg)
{
  /* INPUT AND OUTPUT*/
  printf("IO");
  return 0;
}
#endif

/* FUNCTIONS to REGISTER WITH JACK */

int asysn_jack_bufsize(jack_nframes_t nframes, void *arg) {
  /* looks like this gets called once when we start up. */
  printf("can I set buffer size in an sfront program?\n");
  return 0;
}

int asysn_jack_srate (jack_nframes_t nframes, void *arg) {
  /* looks like this gets called once when we start up. */
  printf("Can't adjust srate at runtime in an sfront program.\n");
  // set a flag which will force us to be removed by jackd
  asysn_jack_srate_was_called++;
  return 1;
}

void asysn_jack_shutdown(void *arg)
{
  // called if jack every shuts down or decides to stop me
  jack_client_close(asysn_jack_client);
  exit (1);
}

/* SFRONT INITIALIZATION FUNCTIONS */
/* These are called ONCE at program startup. */

/** OUTPUT ONLY **/
#if defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT)
int asys_osetup(long srate, long ochannels,
                long osample, char * oname, long toption) 
{
  char outchan_name[256];
  int i, j;

  /* connect as client to jack server */
  if ((asysn_jack_client = jack_client_new (asysn_jack_client_name)) == 0) {
    fprintf( stderr, "could not connect... jack not running?\n");
    return ASYS_ERROR;
  }
  
  /* register asysn_jack_process() with jack.
     will be called whenever jack decides there's work to do.
  */
  jack_set_process_callback(asysn_jack_client, asysn_jack_process, 0);

  /* register bufsize() with jack, to be called when max. nframes
     will change 
  */
  jack_set_buffer_size_callback(asysn_jack_client, asysn_jack_bufsize, 0);

  /* register srate() as function for jack to call when sampling
     rate changes
  */
  jack_set_sample_rate_callback (asysn_jack_client, asysn_jack_srate, 0);

  /* register  for anytime we get disconnected,
     i.e. jack shuts down or stops calling asysn_jack_client
  */
  jack_on_shutdown(asysn_jack_client, asysn_jack_shutdown, 0);

  /* print sampling rate at startup */
  printf("jack sampling rate: %lu\n", jack_get_sample_rate(asysn_jack_client));
  printf("OK ");
  /* create ports */
  printf("creating output port(s)\n");
  for(i=0; i < ASYS_OCHAN; i++) {
  	asysn_jack_output_port[i] = jack_port_register(asysn_jack_client, 
		      "output",
		      JACK_DEFAULT_AUDIO_TYPE, 
		      JackPortIsOutput, 0);
  }
  /* tell jack asysn_jack_client is ready */
  if (jack_activate (asysn_jack_client)) {
    fprintf(stderr, "can't activate client!\n");
    return ASYS_ERROR;
  }
  else
    printf("client activated OK\n");
  /* now we can connect ports */
/*    if (jack_connect (asysn_jack_client, "alsa_pcm:in_1",  */
/*  		    jack_port_name(asysn_jack_input_port))) { */
/*      fprintf(stderr, "can't get input ports!\n"); */
/*    } */

  /* PROCESS COMMAND-LINE ARGS */
  for(i=1; i < asys_argc; i++) {
    /* connect to requested output ports */
    if(! strcmp(asys_argv[i], "-asys_jack_out")) {
      if (((i + 1) >= asys_argc)) { //  || (strncmp(asys_argv[i+1], "-", 1))) {
	asysn_jack_print_usage();
	return ASYS_ERROR;
      }
      for(j=i+1; j < asys_argc && strncmp(asys_argv[j], "-", 1); j++) {
	if (j-i > ASYS_OCHAN) {
	  fprintf(stderr, 
		  "Too many out channels requested! %s can only do %d\n", 
		  asys_argv[0], ASYS_OCHAN);
	  return ASYS_ERROR;
	}
	if (jack_connect (asysn_jack_client,
 			  jack_port_name(asysn_jack_output_port[j-(i+1)]),
			  asys_argv[j])) {
	  fprintf(stderr, "can't get output ports!\n");
	  fprintf(stderr, "failed trying to connect output %d to %s\n", 
		  j - (i+1),
		  asys_argv[j]);
	  return ASYS_ERROR;
	}
	asysn_jack_oports_connected++;
      }
    } 
    /* connect to requested input ports */
    else if (! strcmp(asys_argv[i], "-asys_jack_in")) {
    }
  }
  /* connect remaining output ports to alsa client by default */
  /* ... whoops, what if user explicitly used one already? Forget it. */
/*    for(i=asysn_jack_oports_connected; i < ASYS_OCHAN; i++) { */
/*      sprintf(outchan_name, "alsa_pcm:out_%d", i + 1); */
/*      if (jack_connect (asysn_jack_client,  */
/*  		      jack_port_name(asysn_jack_output_port[i]),  */
/*  		      outchan_name)) { */
/*        fprintf(stderr, "can't get output port %d!\n", i); */
/*        return ASYS_ERROR; */
/*      } */
/*    } */
  if (asysn_jack_oports_connected != ASYS_OCHAN) {
    fprintf(stderr, "Oops! You've connected %d out channels and you need %d.\n",
	    asysn_jack_oports_connected, ASYS_OCHAN);
    return ASYS_ERROR;
  }
  printf("asys_osetup is all done!\n");
  /* all is well */
  return ASYS_DONE;
}
#endif

/**************** END OF SETUP **************************/

/*******  shutdowns called in various scenarios *******/

#if defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT)
void asys_oshutdown(void) {
  printf("running asys_oshutdown.\n");
};
#endif

#if defined(ASYS_HASINPUT) && !defined(ASYS_HASOUTPUT)
void asys_ishutdown(void) {
  printf("running asys_ishutdown.\n");
}
#endif

#if defined(ASYS_HASINPUT) && defined(ASYS_HASOUTPUT)
void asys_ioshutdown(void) {
  printf("running asys_ioshutdown.\n");
}
#endif

/***** active audio main - works for all I/O types, I hope ************/
/* Called once by sfront app. *after* setup; when it terminates, we're done. 
   and we run asys_[io]shutdown. 

*/

void asys_main(void) {
  int i=0;
  printf("Started asys_main...\n");
  asysn_jack_proc_status = ASYS_DONE;

  /* Run until ASYS_EXIT... */
  while (asysn_jack_proc_status == ASYS_DONE) {
    /*printf("now in main loop %d\n", i);
      i++;*/
    usleep(ASYSN_JACK_SLEEPMS * 1000); // doesn't seem to matter
  }
  jack_client_close(asysn_jack_client);
  /* return(0); */
}



Reply via email to