[CELT-dev] adding celt support to netjack some questions.

torbenh at gmx.de torbenh at gmx.de
Tue Nov 25 01:25:03 PST 2008


On Tue, Nov 25, 2008 at 03:14:20AM -0500, Gregory Maxwell wrote:
> On Mon, Nov 24, 2008 at 8:25 PM,  <torbenh at gmx.de> wrote:
> [snip]
> > ok. i overlooked that the minimum rate was 32kHz.
> 
> If you want to play around with it some you can remove the test around
> line 321 in libcelt/modes.c.  The code will currently work down to
> 4kHz or so, but that is far outside of CELT's design target, it does
> not perform well compared to other codecs (such as Speex), and it may
> not work in the future.

i noticed how low i can go with the bitrate, and i am happy :)


> If you find a good application for CELT at lower than 32kHz, I'd love
> hear about it. If you're just looking for lower bandwidths you'll
> probably get the best results using smaller frame sizes.

indeed.

> 
> > for big samplerates i will do the downsampling using libsamplerate then.
> >
> > it already works like a charm.
> > nice work guys :)
> 
> Be sure to account for whatever delay libsamplerate adds.

i am using linear resampling.
but i will keep that in mind (hopefully ;)
i will demand API changes to libsamplerate someday.
i dont think it publishes its latency. 

> > is support for more then 512 sample blocks planned ?
> > i am putting one jack period of data into one packet.
> > so currently it only works with a period of <=512.
> > i could split that myself. but i dont see why the API should not handle
> > bigger blocks. and just hide the splitting to smaller blocks.
> > not sure if this would gain something quality wise.
> 
> I'll let JM comment: I have no opinion on the API related to this.

ok :) well... perhaps i can catch you on irc.

> 
> [snip]
> > the property netjack requires from the codec is that it has fixed
> > in:out ratio. so i guess celt is my only choice. and considering
> > how good this already works. will remain my choice ;)
> 
> If you're just referring to samples in-out per period (VBR is okay)
> then vorbis with some modifications to block switching might also suit
> your application, but I expect JACK users are using -p 1024 or lower,
> and probably most lower than 512? Which does leave you in the CELT
> designed delay range.  FLAC also can give useful compression with very
> small block sizes, though obviously not on the scale of the lossy
> codecs.

its been a long time ago since i looked at ogg and flac.
but at that time, i did not find out, how i could force them to emit
data.
i could only feed them samples, and at some point they would call
the write callback. this is not acceptable.

netjacks main purpose is to transmit uncompressed over gigabit lines.
And it can reliably transmit 128channels with <5ms of latency.
I will not add some magic code, which can handle VBR.


> 
> [snip]
> > thanks for the prompt reply.
> > are you interested in the patch ? i can post it here, if you like.
> 
> I'd like to see it!

ok. i attach it.
you need to run autoconf after applying the patch.
if you are on freenode #xiph tell me.
i would be happy to guide you.

Still need to do some realworld tests on alsa_in.
alsa_out worked ok for a berlin <-> new york connection.

> 
> > i need to fix alsa_in and alsa_out now, because they dont handle the big
> > timing jitter of an internet connection gracefully.
> 
> Oh, until this moment I had believe that netjack was timed purely from
> one end and (accordingly) you wouldn't need jitter buffering.  I now
> see you have a remote audio interface support. You might want to look
> at the speex jitter buffer in -lspeexdsp.

i will have a look.
but the approach i am using in alsa_in and alsa_out works nicely.
although it does not autodetect parameters yet.

but the internet is a new requirement i did not test much.

> I should warn you that delay compensation across the general internet
> is major challenge: If the users are not on the same ISP the delay
> will almost certainly be highly asymmetric, and it may even be
> asymmetric even with a single ISP. You can't measure the delay split
> without an accurate external reference.  I've done testing (using a
> set of trimble thunderbolts as a absolute time reference) and found
> that if you try hard you can sometimes get NTP to do the job (i.e. get
> two internet separate end points into agreement within a couple of
> ms), but usually it doesn't, and when it doesn't you can't tell
> (except via a more accurate clock) you just get wrong results about
> the delay split.

i am using a different approach.
netjack is operating synchronously. as you stated above, i dont need a
jitterbuffer for one ended operation.

alsa_in and alsa_out are playing on the jittering machine.
but delay compensation is happening on the master side.
i recommend routing the signal, which is going to the soundcard of the
master machine to the slave machine. 

this adds even more latency, but at least all signals are in sync.
and alsa_out can play that back.
so jamming using transport synced sequencers is possible.

and the user on the master machine can even play live instruments.
there are still some sync problems when packet loss occurs, but i know
how to solve these, so its just a matter of time.




-- 
torben Hohn
http://galan.sourceforge.net -- The graphical Audio language
-------------- next part --------------
Index: tools/alsa_in.c
===================================================================
--- tools/alsa_in.c	(revision 3118)
+++ tools/alsa_in.c	(working copy)
@@ -56,6 +56,11 @@
 
 int print_counter = 10;
 
+volatile float output_resampling_factor = 0.0;
+volatile int output_new_delay = 0;
+volatile float output_offset = 0.0;
+volatile float output_diff = 0.0;
+
 // Alsa stuff... i dont want to touch this bullshit in the next years.... please...
 
 static int xrun_recovery(snd_pcm_t *handle, int err) {
@@ -239,14 +244,14 @@
     if( delay > (target_delay+max_diff) ) {
 	ALSASAMPLE *tmp = alloca( (delay-target_delay) * sizeof( ALSASAMPLE ) * num_channels ); 
 	snd_pcm_readi( alsa_handle, tmp, delay-target_delay );
-	printf( "delay = %d\n", (int) delay );
+	output_new_delay = (int) delay;
 	delay = target_delay;
 	// XXX: at least set it to that value.
 	current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
     }
     if( delay < (target_delay-max_diff) ) {
 	snd_pcm_rewind( alsa_handle, target_delay - delay );
-	printf( "delay = %d\n", (int) delay );
+	output_new_delay = (int) delay;
 	delay = target_delay;
 	// XXX: at least set it to that value.
 	current_resample_factor = (double) jack_sample_rate / (double) sample_rate;
@@ -269,6 +274,7 @@
 
     double resamp_rate = (double)jack_sample_rate / (double)sample_rate;  // == nframes / alsa_samples.
     double request_samples = nframes / resamp_rate;  //== alsa_samples;
+    //double request_samples = nframes / current_resample_factor;  //== alsa_samples;
 
     double offset = delay - target_delay;
 
@@ -279,11 +285,15 @@
 
     double diff_value =  pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;
     current_resample_factor -= diff_value;
+    current_resample_factor = current_resample_factor < 0.25 ? 0.25 : current_resample_factor;
     rlen = ceil( ((double)nframes) / current_resample_factor )+2;
 
     if( (print_counter--) == 0 ) {
 	print_counter = 10;
-	printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
+	//printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
+	output_resampling_factor = (float) current_resample_factor;
+	output_diff = (float) diff_value;
+	output_offset = (float) offset;
     }
 
     /*
@@ -299,7 +309,7 @@
 again:
     err = snd_pcm_readi(alsa_handle, outbuf, rlen);
     if( err < 0 ) {
-	printf( "err = %d\n", err );
+	//printf( "err = %d\n", err );
 	if (xrun_recovery(alsa_handle, err) < 0) {
 	    //printf("Write error: %s\n", snd_strerror(err));
 	    //exit(EXIT_FAILURE);
@@ -307,7 +317,7 @@
 	goto again;
     }
     if( err != rlen ) {
-	printf( "read = %d\n", rlen );
+	//printf( "read = %d\n", rlen );
     }
 
     /*
@@ -346,7 +356,7 @@
 	put_back_samples = rlen-src.input_frames_used;
 
 	if( src.output_frames_gen != nframes )
-	    printf( "did not fill jack_buffer...\n" );
+	    //printf( "did not fill jack_buffer...\n" );
 
 	src_node = jack_slist_next (src_node);
 	node = jack_slist_next (node);
@@ -558,7 +568,16 @@
 	return 1;
     }
 
-    while(1) sleep(1);
+    while(1) {
+	sleep(1);
+	if( output_new_delay ) {
+	    printf( "delay = %d\n", output_new_delay );
+	    output_new_delay = 0;
+	}
+	printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset );
+	
+    }
+
     jack_client_close (client);
     exit (0);
 }
Index: tools/netsource.c
===================================================================
--- tools/netsource.c	(revision 3118)
+++ tools/netsource.c	(working copy)
@@ -51,6 +51,8 @@
 #include <netjack_packet.h>
 #include <samplerate.h>
 
+#include <celt/celt.h>
+
 JSList *capture_ports = NULL;
 JSList *capture_srcs = NULL;
 int capture_channels = 0;
@@ -110,7 +112,13 @@
             printf( "jack_netsource: cannot register %s port\n", buf);
             break;
         }
-        capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL));
+	if( bitdepth == 1000 ) {
+	    // XXX: memory leak
+	    CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL );
+	    capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) );
+	} else {
+	    capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL));
+	}
         capture_ports = jack_slist_append (capture_ports, port);
     }
 
@@ -139,8 +147,14 @@
             printf ("jack_netsource: cannot register %s port\n", buf);
             break;
         }
+	if( bitdepth == 1000 ) {
+	    // XXX: memory leak
+	    CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL );
+	    playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) );
+	} else {
 	    playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL));
-	    playback_ports = jack_slist_append (playback_ports, port);
+	}
+	playback_ports = jack_slist_append (playback_ports, port);
     }
 
     /* Allocate midi playback channels */
@@ -190,8 +204,13 @@
 int
 process (jack_nframes_t nframes, void *arg)
 {
-    jack_nframes_t net_period = (float) nframes / (float) factor;
+    jack_nframes_t net_period;
 
+    if( bitdepth == 1000 )
+	net_period = factor;
+    else
+	net_period = (float) nframes / (float) factor;
+
     int rx_bufsize =  get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
     int tx_bufsize =  get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);
 
@@ -365,6 +384,7 @@
         "  -f <downsample ratio> - Downsample data in the wire by this factor\n"
         "  -b <bitdepth> - Set transport to use 16bit or 8bit\n"
         "  -m <mtu> - Assume this mtu for the link\n"
+	"  -c <bytes> - Use Celt and encode <bytes> per channel and packet.\n"
         "\n");
 }
 
@@ -396,7 +416,7 @@
     sprintf(client_name, "netsource");
     sprintf(peer_ip, "localhost");
 
-    while ((c = getopt (argc, argv, ":n:s:h:p:C:P:i:o:l:r:f:b:m:")) != -1)
+    while ((c = getopt (argc, argv, ":n:s:h:p:C:P:i:o:l:r:f:b:m:c:")) != -1)
     {
         switch (c)
         {
@@ -442,6 +462,10 @@
             case 'b':
             bitdepth = atoi (optarg);
             break;
+	    case 'c':
+	    bitdepth = 1000;
+	    factor = atoi (optarg);
+	    break;
             case 'm':
             mtu = atoi (optarg);
             break;
Index: tools/alsa_out.c
===================================================================
--- tools/alsa_out.c	(revision 3118)
+++ tools/alsa_out.c	(working copy)
@@ -56,6 +56,11 @@
 
 int print_counter = 10;
 
+volatile float output_resampling_factor = 0.0;
+volatile int output_new_delay = 0;
+volatile float output_offset = 0.0;
+volatile float output_diff = 0.0;
+
 // Alsa stuff... i dont want to touch this bullshit in the next years.... please...
 
 static int xrun_recovery(snd_pcm_t *handle, int err) {
@@ -242,11 +247,9 @@
 
     if( delay > (target_delay+max_diff) ) {
 	snd_pcm_rewind( alsa_handle, delay - target_delay );
-	//snd_pcm_writei( alsa_handle, tmp, target_delay-t_delay );
-	printf( "delay = %d", (int) delay );
+	output_new_delay = (int) delay;
 	snd_pcm_delay( alsa_handle, &delay );
-	printf( "... and delay = %d\n", (int) delay );
-	delay = target_delay;
+	//delay = target_delay;
 	// XXX: at least set it to that value.
 	current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
     }
@@ -254,10 +257,9 @@
 	ALSASAMPLE *tmp = alloca( (target_delay-delay) * sizeof( ALSASAMPLE ) * num_channels ); 
 	memset( tmp, 0, sizeof( ALSASAMPLE ) * num_channels * (target_delay-delay) );
 	snd_pcm_writei( alsa_handle, tmp, target_delay-delay );
-	printf( "delay = %d", (int) delay );
+	output_new_delay = (int) delay;
 	snd_pcm_delay( alsa_handle, &delay );
-	printf( "... and delay = %d\n", (int) delay );
-	delay = target_delay;
+	//delay = target_delay;
 	// XXX: at least set it to that value.
 	current_resample_factor = (double) sample_rate / (double) jack_sample_rate;
     }
@@ -268,6 +270,7 @@
 
     double resamp_rate = (double)jack_sample_rate / (double)sample_rate;  // == nframes / alsa_samples.
     double request_samples = nframes / resamp_rate;  //== alsa_samples;
+    //double request_samples = nframes * current_resample_factor;  //== alsa_samples;
 
     double offset = delay - target_delay;
 
@@ -278,11 +281,15 @@
 
     double diff_value =  pow(current_resample_factor - compute_factor, 3) / (double) catch_factor;
     current_resample_factor -= diff_value;
+    current_resample_factor = current_resample_factor < 0.25 ? 0.25 : current_resample_factor;
     rlen = ceil( ((double)nframes) * current_resample_factor ) + 2;
 
     if( (print_counter--) == 0 ) {
 	print_counter = 10;
-	printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
+	//printf( "res: %f, \tdiff = %f, \toffset = %f \n", (float)current_resample_factor, (float)diff_value, (float) offset );
+	output_resampling_factor = (float) current_resample_factor;
+	output_diff = (float) diff_value;
+	output_offset = (float) offset;
     }
 
     /*
@@ -552,7 +559,15 @@
 	return 1;
     }
 
-    while(1) sleep(1);
+    while(1) {
+	sleep(1);
+	if( output_new_delay ) {
+	    printf( "delay = %d\n", output_new_delay );
+	    output_new_delay = 0;
+	}
+	printf( "res: %f, \tdiff = %f, \toffset = %f \n", output_resampling_factor, output_diff, output_offset );
+	
+    }
     jack_client_close (client);
     exit (0);
 }
Index: configure.ac
===================================================================
--- configure.ac	(revision 3118)
+++ configure.ac	(working copy)
@@ -588,6 +588,16 @@
 	LIBS="$LIBS $SAMPLERATE_LIBS"
 fi
 
+# Celt low-latency audio codec. netjack transmission via internet.
+HAVE_CELT=false
+PKG_CHECK_MODULES(CELT, celt >= 0.5.0,[HAVE_CELT=true], [true])
+if test x$HAVE_CELT = xfalse; then
+             AC_MSG_WARN([*** NetJack will not be built with celt support])
+else
+	CFLAGS="$CFLAGS $CELT_CFLAGS"
+	LIBS="$LIBS $CELT_LIBS"
+fi
+
 # Note: A bug in pkg-config causes problems if the first occurence of
 # PKG_CHECK_MODULES can be disabled. So, if you're going to use
 # PKG_CHECK_MODULES inside a --disable-whatever check, you need to
@@ -745,6 +755,7 @@
 fi
 
 AM_CONDITIONAL(HAVE_SNDFILE, $HAVE_SNDFILE)
+AM_CONDITIONAL(HAVE_CELT, $HAVE_CELT)
 AM_CONDITIONAL(HAVE_SAMPLERATE, $HAVE_SAMPLERATE)
 AM_CONDITIONAL(HAVE_READLINE, $HAVE_READLINE)
 AM_CONDITIONAL(HAVE_DOXYGEN, $HAVE_DOXYGEN)
@@ -809,6 +820,7 @@
 echo \| Build with CoreAudio support.......................... : $HAVE_COREAUDIO
 echo \| Build with PortAudio support.......................... : $HAVE_PA
 echo \| Build with NetJack support............................ : $HAVE_SAMPLERATE
+echo \| Build with Celt support............................... : $HAVE_CELT
 echo \| Build with dynamic buffer size support................ : $buffer_resizing
 echo \| Compiler optimization flags........................... : $JACK_OPT_CFLAGS
 echo \| Compiler full flags................................... : $CFLAGS
Index: drivers/netjack/net_driver.c
===================================================================
--- drivers/netjack/net_driver.c	(revision 3118)
+++ drivers/netjack/net_driver.c	(working copy)
@@ -43,6 +43,8 @@
 
 #include <samplerate.h>
 
+#include <celt/celt.h>
+
 #include "net_driver.h"
 #include "netjack_packet.h"
 
@@ -327,7 +329,14 @@
 
         driver->capture_ports =
             jack_slist_append (driver->capture_ports, port);
-        driver->capture_srcs = jack_slist_append(driver->capture_srcs, src_new(SRC_LINEAR, 1, NULL));
+
+	if( driver->bitdepth == 1000 ) {
+	    // XXX: memory leak
+	    CELTMode *celt_mode = celt_mode_create( driver->sample_rate, 1, driver->period_size, NULL );
+	    driver->capture_srcs = jack_slist_append(driver->capture_srcs, celt_decoder_create( celt_mode ) );
+	} else {
+	    driver->capture_srcs = jack_slist_append(driver->capture_srcs, src_new(SRC_LINEAR, 1, NULL));
+	}
     }
     for (chn = driver->capture_channels_audio; chn < driver->capture_channels; chn++) {
         snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);
@@ -361,7 +370,13 @@
 
         driver->playback_ports =
             jack_slist_append (driver->playback_ports, port);
-        driver->playback_srcs = jack_slist_append(driver->playback_srcs, src_new(SRC_LINEAR, 1, NULL));
+	if( driver->bitdepth == 1000 ) {
+	    // XXX: memory leak
+	    CELTMode *celt_mode = celt_mode_create( driver->sample_rate, 1, driver->period_size, NULL );
+	    driver->playback_srcs = jack_slist_append(driver->playback_srcs, celt_encoder_create( celt_mode ) );
+	} else {
+	    driver->playback_srcs = jack_slist_append(driver->playback_srcs, src_new(SRC_LINEAR, 1, NULL));
+	}
     }
     for (chn = driver->playback_channels_audio; chn < driver->playback_channels; chn++) {
         snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);
@@ -475,7 +490,7 @@
     driver->client = client;
     driver->engine = NULL;
 
-    if ((bitdepth != 0) && (bitdepth != 8) && (bitdepth != 16))
+    if ((bitdepth != 0) && (bitdepth != 8) && (bitdepth != 16) && (bitdepth != 1000))
     {
         jack_info ("Invalid bitdepth: %d (8, 16 or 0 for float) !!!", bitdepth);
         return NULL;
@@ -574,8 +589,15 @@
         (jack_time_t) floor ((((float) driver->period_size) / driver->sample_rate)
                              * 1000000.0f);
 
-    driver->net_period_down = (float) driver->period_size / (float) resample_factor;
-    driver->net_period_up = (float) driver->period_size / (float) resample_factor_up;
+    if( driver->bitdepth == 1000 ) {
+	// celt mode. 
+	// TODO: this is a hack. But i dont want to change the packet header.
+	driver->net_period_down = resample_factor;
+	driver->net_period_up = resample_factor_up;
+    } else {
+	driver->net_period_down = (float) driver->period_size / (float) resample_factor;
+	driver->net_period_up = (float) driver->period_size / (float) resample_factor_up;
+    }
 
     /* TODO: this seems... useles */
     rx_bufsize = sizeof (jacknet_packet_header) + driver->net_period_down * driver->capture_channels * get_sample_size (driver->bitdepth);
@@ -602,7 +624,7 @@
 
     desc = calloc (1, sizeof (jack_driver_desc_t));
     strcpy (desc->name, "net");
-    desc->nparams = 11;
+    desc->nparams = 12;
 
     params = calloc (desc->nparams, sizeof (jack_driver_param_desc_t));
 
@@ -682,6 +704,15 @@
     strcpy (params[i].long_desc, params[i].short_desc);
 
     i++;
+    strcpy (params[i].name, "celt");
+    params[i].character  = 'c';
+    params[i].type       = JackDriverParamUInt;
+    params[i].value.ui   = 0U;
+    strcpy (params[i].short_desc,
+            "sets celt encoding and number of bytes per channel");
+    strcpy (params[i].long_desc, params[i].short_desc);
+
+    i++;
     strcpy (params[i].name, "bit-depth");
     params[i].character  = 'b';
     params[i].type       = JackDriverParamUInt;
@@ -768,6 +799,11 @@
                 bitdepth = param->value.ui;
                 break;
 
+	    case 'c':
+		bitdepth = 1000;
+		resample_factor = param->value.ui;
+		break;
+
             case 't':
                 handle_transport_sync = param->value.ui;
                 break;
Index: drivers/netjack/netjack_packet.c
===================================================================
--- drivers/netjack/netjack_packet.c	(revision 3118)
+++ drivers/netjack/netjack_packet.c	(working copy)
@@ -47,6 +47,8 @@
 
 #include <samplerate.h>
 
+#include <celt/celt.h>
+
 #include "net_driver.h"
 #include "netjack_packet.h"
 
@@ -98,6 +100,8 @@
         return sizeof (int8_t);
     if (bitdepth == 16)
         return sizeof (int16_t);
+    if( bitdepth == 1000 )
+	return sizeof( unsigned char );
     return sizeof (int32_t);
 }
 
@@ -905,6 +909,93 @@
     }
 }
 
+// render functions for celt.
+void
+render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes)
+{
+    channel_t chn = 0;
+    JSList *node = capture_ports;
+    JSList *src_node = capture_srcs;
+
+    unsigned char *packet_bufX = (unsigned char *)packet_payload;
+
+    while (node != NULL)
+    {
+        int i;
+        //uint32_t val;
+        SRC_DATA src;
+
+        jack_port_t *port = (jack_port_t *) node->data;
+        jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes);
+
+        float *floatbuf = alloca (sizeof(float) * net_period_down);
+        const char *portname = jack_port_type (port);
+
+        if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0)
+        {
+            // audio port, decode celt data.
+	    
+	    CELTDecoder *decoder = src_node->data;
+	    celt_decode_float( decoder, packet_bufX, net_period_down, buf );
+	    src_node = jack_slist_next (src_node);
+        }
+        else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0)
+        {
+            // midi port, decode midi events
+            // convert the data buffer to a standard format (uint32_t based)
+            unsigned int buffer_size_uint32 = net_period_down / 2;
+            uint32_t * buffer_uint32 = (uint32_t*) packet_bufX;
+            decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
+        }
+        packet_bufX = (packet_bufX + net_period_down);
+        node = jack_slist_next (node);
+        chn++;
+    }
+}
+
+void
+render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up)
+{
+    channel_t chn = 0;
+    JSList *node = playback_ports;
+    JSList *src_node = playback_srcs;
+
+    unsigned char *packet_bufX = (uint16_t *)packet_payload;
+
+    while (node != NULL)
+    {
+        SRC_DATA src;
+        int i;
+        jack_port_t *port = (jack_port_t *) node->data;
+        jack_default_audio_sample_t* buf = jack_port_get_buffer (port, nframes);
+        const char *portname = jack_port_type (port);
+
+        if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0)
+        {
+            // audio port, encode celt data.
+    
+	    int encoded_bytes;
+	    float *floatbuf = alloca (sizeof(float) * nframes );
+	    memcpy( floatbuf, buf, nframes*sizeof(float) );
+	    CELTEncoder *encoder = src_node->data;
+	    encoded_bytes = celt_encode_float( encoder, floatbuf, NULL, packet_bufX, net_period_up );
+	    if( encoded_bytes != net_period_up )
+		printf( "bah... they are not the same\n" );
+	    src_node = jack_slist_next( src_node );
+        }
+        else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0)
+        {
+            // encode midi events from port to packet
+            // convert the data buffer to a standard format (uint32_t based)
+            unsigned int buffer_size_uint32 = net_period_up / 2;
+            uint32_t * buffer_uint32 = (uint32_t*) packet_bufX;
+            encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf);
+        }
+        packet_bufX = (packet_bufX + net_period_up);
+        node = jack_slist_next (node);
+        chn++;
+    }
+}
 /* Wrapper functions with bitdepth argument... */
 void
 render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes)
@@ -913,6 +1004,8 @@
         render_payload_to_jack_ports_8bit (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
     else if (bitdepth == 16)
         render_payload_to_jack_ports_16bit (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
+    else if (bitdepth == 1000)
+        render_payload_to_jack_ports_celt (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
     else
         render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes);
 }
@@ -924,6 +1017,8 @@
         render_jack_ports_to_payload_8bit (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
     else if (bitdepth == 16)
         render_jack_ports_to_payload_16bit (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
+    else if (bitdepth == 1000)
+        render_jack_ports_to_payload_celt (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
     else
         render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up);
 }


More information about the celt-dev mailing list