diff --git a/src/Makefile.am b/src/Makefile.am
index ce576bd..328fe3e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -200,6 +200,6 @@ ngspice.idx: makeidx
 
 INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices @X_CFLAGS@
 
-LIBS = @LIBS@ @X_LIBS@ @X_PRE_LIBS@ @X_EXTRA_LIBS@
+LIBS = @LIBS@ @X_LIBS@ @X_PRE_LIBS@ @X_EXTRA_LIBS@ -lsndfile -lsamplerate
 
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am
index 340de98..5d238af 100644
--- a/src/frontend/Makefile.am
+++ b/src/frontend/Makefile.am
@@ -73,6 +73,8 @@ libfte_a_SOURCES = \
 	quote.h		\
 	streams.h	\
 	streams.c	\
+	sndprint.c	\
+	sndprint.h	\
 	terminal.c	\
 	terminal.h	\
 	variable.c	\
diff --git a/src/frontend/commands.c b/src/frontend/commands.c
index eb34f7c..54d5e61 100644
--- a/src/frontend/commands.c
+++ b/src/frontend/commands.c
@@ -169,6 +169,14 @@ struct comm spcp_coms[] = {
       { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS,
       (void (*)()) NULL,
       "varname ... : Undefine vectors." } ,
+    { "sndprint", com_sndprint, FALSE, FALSE, TRUE,
+      { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
+      arg_print,
+      "[col] expr ... : Print vector values." } ,
+    { "sndparam", com_sndparam, FALSE, FALSE, TRUE,
+      { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS,
+      arg_load,
+      "file samplerate : set sndprint parameters." } ,
     { "print", com_print, FALSE, FALSE, TRUE,
       { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
       arg_print,
@@ -560,6 +568,14 @@ struct comm nutcp_coms[] = {
       { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS,
       (void (*)()) NULL,
       "varname ... : Undefine vectors." } ,
+    { "sndprint", com_sndprint, FALSE, FALSE, TRUE,
+      { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
+      arg_print,
+      "[col] expr ... : Print vector values." } ,
+    { "sndparam", com_sndparam, FALSE, FALSE, TRUE,
+      { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS,
+      arg_load,
+      "file samplerate : set sndprint parameters." } ,
     { "print", com_print, FALSE, FALSE, TRUE,
       { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
       arg_print,
diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c
index d283df5..1c61669 100644
--- a/src/frontend/dotcards.c
+++ b/src/frontend/dotcards.c
@@ -101,7 +101,8 @@ ft_savedotargs(void)
 	else
 	    isaplot = 0;
 
-        if (isaplot || ciprefix(".print", s)) {
+        if (isaplot || ciprefix(".print", s) || 
+	    ciprefix(".sndparam", s) || ciprefix(".sndprint", s) ) {
             (void) gettok(&s);
             name = gettok(&s);
 
@@ -287,6 +288,41 @@ ft_cktcoms(bool terse)
                     fprintf(cp_err, "Error: .print: no %s analysis found.\n",
 			    plottype);
             }
+        } else if (eq(command->wl_word, ".sndparam")) {
+            if (terse) {
+                fprintf(cp_out, 
+			".sndparam line ignored since rawfile was produced.\n");
+            } else {
+		com_sndparam(command->wl_next);
+	    }
+        } else if (eq(command->wl_word, ".sndprint")) {
+            if (terse) {
+                fprintf(cp_out, 
+			".sndprint line ignored since rawfile was produced.\n");
+            } else {
+                command = command->wl_next;
+                if (!command) {
+                    fprintf(cp_err, "Error: bad line %s\n", coms->wl_word);
+                    coms = coms->wl_next;
+                    continue;
+                }
+                plottype = command->wl_word;
+                command = command->wl_next;
+                fixdotprint(command);
+                twl.wl_next = command;
+		found = 0;
+		for (pl = plot_list; pl; pl = pl->pl_next) {
+		    if (ciprefix(plottype, pl->pl_typename)) {
+			plot_cur = pl;
+			com_sndprint(&twl);
+			fprintf(cp_out, "\n");
+			found = 1;
+		    }
+		}
+                if (!found)
+                    fprintf(cp_err, "Error: .sndprint: no %s analysis found.\n",
+			    plottype);
+            }
         } else if (eq(command->wl_word, ".plot")) {
             if (terse) {
                 fprintf(cp_out, 
diff --git a/src/frontend/inp.c b/src/frontend/inp.c
index 64aabf6..73f811e 100644
--- a/src/frontend/inp.c
+++ b/src/frontend/inp.c
@@ -442,6 +442,8 @@ inp_spsource(FILE *fp, bool comfile, char *filename)
 		    || ciprefix(".four", s)
 		    || eq(s, ".plot")
 		    || eq(s, ".print")
+		    || eq(s, ".sndprint")
+		    || eq(s, ".sndparam")
 		    || eq(s, ".save")
 		    || eq(s, ".op")
 		    || eq(s, ".tf"))
diff --git a/src/frontend/nutinp.c b/src/frontend/nutinp.c
index fa6989b..995a4eb 100644
--- a/src/frontend/nutinp.c
+++ b/src/frontend/nutinp.c
@@ -144,6 +144,8 @@ inp_nutsource(FILE *fp, bool comfile, char *filename)
                 if (eq(s, ".width") || ciprefix(".four", s) ||
                         eq(s, ".plot") || 
                         eq(s, ".print") ||
+                        eq(s, ".sndprint") ||
+                        eq(s, ".sndparam") ||
                         eq(s, ".save")) {
                     if (end) {
                         end->wl_next = alloc(struct wordlist);
diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c
index 4a8ac6f..dc59f45 100644
--- a/src/frontend/postcoms.c
+++ b/src/frontend/postcoms.c
@@ -18,6 +18,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
 #include "postcoms.h"
 #include "quote.h"
 #include "variable.h"
+#include "sndprint.h"
 #include "parser/complete.h" /* va: throwaway */
 
 /* static declarations */
@@ -327,6 +328,120 @@ done:
     return;
 }
 
+/* tweaked version of print - write sound-files
+ */
+
+void
+com_sndprint(wordlist *wl)
+{
+    struct dvec *v, *lv = NULL, *bv, *vecs = NULL;
+    int i, j, npoints;
+    struct pnode *nn;
+    int ngood;
+
+    if (wl == NULL)
+        return;
+    if (eq(wl->wl_word, "col")) {
+        wl = wl->wl_next;
+    } else if (eq(wl->wl_word, "line")) {
+        wl = wl->wl_next;
+    }
+
+    ngood = 0;
+    for (nn = ft_getpnames(wl, TRUE); nn; nn = nn->pn_next) {
+        if (!(v = ft_evaluate(nn)))
+	    continue;
+	if (!vecs)
+	    vecs = lv = v;
+	else
+	    lv->v_link2 = v;
+	for (lv = v; lv->v_link2; lv = lv->v_link2)
+	    ;
+	ngood += 1;
+    }
+
+    if (!ngood) return;
+
+    snd_init(ngood);
+    bv = vecs;
+
+    i = j = 0;
+    npoints = 0;
+    for (v = bv; v ; v = v->v_link2)
+        if (v->v_length > npoints)
+            npoints = v->v_length;
+    double samplerate = snd_get_samplerate();
+    while ((j < npoints)) {
+
+	double tme = bv->v_plot->pl_scale->v_realdata[j] * samplerate;
+	int c =0;
+        for (v = bv; v ; v = v->v_link2) {
+            if (v->v_length <= j) {
+	    	i+= snd_send(tme, c, 0.0);
+	    } else {
+                if (isreal(v)) 
+	    	    i+= snd_send(tme, c, v->v_realdata[j]);
+		else
+	    	    i+= snd_send(tme, c, realpart(&v->v_compdata[j]));
+	    }
+	    c++;
+        }
+        j++;
+    }
+    snd_close();
+    printf ("wrote %i audio-samples from %i data-points\n",i/ngood,j);
+    /* Get rid of the vectors. */
+    return;
+}
+
+/* Configure sndprint. */
+
+void
+com_sndparam(wordlist *wl)
+{
+    char *copypath;
+    int i=0;
+    char *file = NULL;
+    int srate = 48000;
+    int fmt=-1;
+    double mult = 1.0;
+    double off = 0.0;
+    int oversampling = 64.0;
+
+    while (wl) {
+            copypath=cp_unquote(wl->wl_word);
+	    switch (++i){
+	    	case 1:
+		    file = strdup(copypath); 
+		    break;
+		case 2:
+		    srate = atoi(copypath);	
+		    break;
+		case 3:
+		    fmt = snd_format(copypath);	
+		    break;
+		case 4:
+		    mult = atof(copypath);	
+		    break;
+		case 5:
+		    off = atof(copypath);	
+		    break;
+		case 6:
+		    oversampling = atoi(copypath);	
+		    break;
+		default:
+		    printf("Warning: unknown argument\n");
+	    }
+            tfree(copypath);
+            wl = wl->wl_next;
+        }
+
+    if (file) 
+        snd_configure(file, srate, fmt, mult, off, oversampling);
+    return;
+}
+
+
 /* Write out some data. write filename expr ... Some cleverness here is
  * required.  If the user mentions a few vectors from various plots,
  * probably he means for them to be written out seperate plots.  In any
diff --git a/src/frontend/postcoms.h b/src/frontend/postcoms.h
index 6703cc4..57573b8 100644
--- a/src/frontend/postcoms.h
+++ b/src/frontend/postcoms.h
@@ -10,6 +10,8 @@ void com_let(wordlist *wl);
 void com_unlet(wordlist *wl);
 void com_load(wordlist *wl);
 void com_print(wordlist *wl);
+void com_sndprint(wordlist *wl);
+void com_sndparam(wordlist *wl);
 void com_write(wordlist *wl);
 void com_transpose(wordlist *wl);
 void com_setscale(wordlist *wl);
diff --git a/src/frontend/sndprint.c b/src/frontend/sndprint.c
new file mode 100644
index 0000000..0a24b82
--- /dev/null
+++ b/src/frontend/sndprint.c
@@ -0,0 +1,307 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sndfile.h>
+#include <string.h>
+#include <math.h>
+#include <inttypes.h>
+#include <config.h>
+#include "sndprint.h"
+
+
+int o_samplerate = 48000;
+int o_sndfmt = (SF_FORMAT_WAV | SF_FORMAT_PCM_24);
+float o_mult = 1.0;
+float o_off = 0.0;
+
+//////////////////////////////////   aliki  //////////////////////////////////
+
+#define HDRSIZE 256
+
+void * my_open_aliki(char *fn, int nchannel) {
+  char p[HDRSIZE];
+  FILE	*aldfile;
+  if ((aldfile = fopen (fn, "w")) == 0) {
+    printf ("Error: Not able to open output file '%s'\n", fn);
+    exit (1);
+  }
+
+  strcpy (p, "aliki");
+  p [6] = p [7] = 0;
+  *(uint32_t *)(p +  8) = 2; //_vers
+  *(uint32_t *)(p + 12) = nchannel; // _type;
+  *(uint32_t *)(p + 16) = o_samplerate; //_rate_n;
+  *(uint32_t *)(p + 20) = 1; //_rate_d;
+  *(uint32_t *)(p + 24) = 486239; //_n_fram;
+  *(uint32_t *)(p + 28) = 1; // _n_sect;
+  *(uint32_t *)(p + 32) = 0; // _tref_i;
+  *(uint32_t *)(p + 36) = 0; // _tref_n;
+  *(uint32_t *)(p + 40) = 1; // _tref_d;
+  *(uint32_t *)(p + 44) = 0; // _bits;
+
+  memset (p + 48, 0, HDRSIZE - 48);
+  if (fwrite (p, 1, HDRSIZE, aldfile) != HDRSIZE) {
+    printf ("Error: Not able to write aliki header to '%s'\n", fn);
+    fclose (aldfile);
+    exit(1);
+  }
+  return ((void*) aldfile);
+}
+
+int my_write_aliki(void *d, float val) {
+  return(fwrite(&val, sizeof (float), 1, (FILE*) d));
+}
+
+void my_close_aliki(void *d) {
+  fclose((FILE*) d);
+}
+
+//////////////////////////////////  sndfile //////////////////////////////////
+
+typedef struct {
+  SNDFILE *outfile ;
+  int sf_channels;
+  int sf_bptr;
+  float *sf_buf;
+} SSFILE;
+
+void * my_open_sf(char *fn, int nchannel) {
+
+  SSFILE *d = calloc(1,sizeof(SSFILE));
+  SF_INFO sfinfo ;
+
+  sfinfo.samplerate = o_samplerate;
+  sfinfo.channels = nchannel;
+  sfinfo.frames = 0;
+  sfinfo.format = o_sndfmt;
+
+  d->sf_channels = nchannel;
+  d->sf_bptr = 0;
+  d->sf_buf=calloc(nchannel, sizeof(float));
+
+  if ((d->outfile = sf_open (fn, SFM_WRITE, &sfinfo)) == NULL) {
+    printf ("Error: Not able to open output file '%s'\n", fn);
+    exit (1) ;
+  }
+
+#if 1
+  sf_command (d->outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) ;
+  sf_command (d->outfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ;
+#endif
+
+  return ((void*)d);
+}
+
+int my_write_sf(void *d, float val) {
+  SSFILE *p= (SSFILE*) d;
+  p->sf_buf[p->sf_bptr++] =val;
+  if (p->sf_bptr >= p->sf_channels) {
+    sf_writef_float (p->outfile, p->sf_buf, 1);
+    p->sf_bptr=0;
+  }
+  return (1);
+}
+
+void my_close_sf(void *d) {
+  sf_close(((SSFILE*)d)->outfile);
+  free(((SSFILE*)d)->sf_buf);
+  free((SSFILE*)d);
+}
+
+
+
+//////////////////////////////////   spice  //////////////////////////////////
+
+typedef struct SP_BUF {
+  double tme;
+  double *val;
+} SP_BUF;
+
+void (*p_close)(void*);
+void *(*p_open)(char*, int);
+int  (*p_write)(void*, float);
+void * outfile;
+uint32_t sample;
+int sp_nchannel;
+#define SP_MAX (2)
+SP_BUF *sp_buf;
+char *filename = NULL;
+
+#define HAVE_SRC
+
+#ifndef HAVE_SRC
+#define OVERSAMPLING (1.0)
+#else
+#include <samplerate.h>
+#define OBUFSIZE 256
+int oversampling = 64;
+#define OVERSAMPLING ((double) oversampling)
+SRC_STATE *rabbit;
+int rabbit_err;
+float *interleaved; 
+float *resampled; 
+int iptr = 0;
+
+int resample_wrapper (void *d, float val) {
+  interleaved[iptr++] = val;
+  size_t ibufsize = sp_nchannel * OBUFSIZE * OVERSAMPLING;
+  size_t obufsize = sp_nchannel * OBUFSIZE ;
+  if (iptr ==  ibufsize) {
+
+    SRC_DATA src_data;
+    src_data.data_in = interleaved;
+    src_data.data_out = resampled;
+    src_data.input_frames  = iptr/sp_nchannel;
+    src_data.output_frames = OBUFSIZE;
+    src_data.end_of_input  = 0;
+    src_data.src_ratio     =  1.0/OVERSAMPLING;
+    src_data.input_frames_used = 0;
+    src_data.output_frames_gen = 0;
+  
+    //printf ("the rabbit says: %s\n", src_strerror(
+    src_process(rabbit, &src_data);
+    //));
+
+    if (src_data.output_frames_gen *sp_nchannel != obufsize) {
+      printf ("resample warning: out %li != %i\n", src_data.output_frames_gen*sp_nchannel,  obufsize);
+    }
+
+    if (src_data.input_frames_used *sp_nchannel != iptr) {
+      printf ("resample warning: in: %li != %i\n", src_data.input_frames_used*sp_nchannel, iptr);
+    }
+
+    int i;
+    for (i=0; i< src_data.output_frames_gen*sp_nchannel; i++) 
+      p_write (d, resampled[i]);
+
+    iptr=0;
+    return (src_data.output_frames_gen*sp_nchannel);
+  }
+  return (0);
+}
+
+#endif
+
+void snd_configure(char *fn, int srate, int fmt, double mult, double off, int os ){
+  if (filename) free(filename);
+  filename=strdup(fn);
+
+  o_samplerate = srate;
+  o_mult = mult;
+  o_off = off;
+  oversampling = os;
+  if (fmt!=0) {
+    p_close = &my_close_sf;
+    p_open = &my_open_sf;
+    p_write = &my_write_sf;
+    o_sndfmt=(fmt>0)?fmt:(SF_FORMAT_WAV | SF_FORMAT_PCM_24);
+    printf("info: opened snd file '%s'\n",filename);
+  } else {
+    p_close = &my_close_aliki;
+    p_open = &my_open_aliki;
+    p_write = &my_write_aliki;
+    printf("info: opened aliki file '%s'\n",filename);
+  }
+}
+
+int snd_format(char *fmt) {
+  int f = atoi(fmt);
+  if (!strcmp(fmt, "wav")) f= (SF_FORMAT_WAV | SF_FORMAT_PCM_24);
+  if (!strcmp(fmt, "wav16")) f= (SF_FORMAT_WAV | SF_FORMAT_PCM_16);
+  if (!strcmp(fmt, "wav24")) f= (SF_FORMAT_WAV | SF_FORMAT_PCM_24);
+  if (!strcmp(fmt, "wav32")) f= (SF_FORMAT_WAV | SF_FORMAT_PCM_32);
+  if (!strcmp(fmt, "aiff")) f= (SF_FORMAT_AIFF | SF_FORMAT_PCM_16);
+  if (!strcmp(fmt, "aliki")) f= 0;
+  return (f);
+}
+
+void snd_init(int nchannel) {
+  int i;
+  if (!filename) snd_configure("spice.wav", 48000.0, o_sndfmt, o_mult, o_off, oversampling);
+  outfile = p_open (filename, nchannel);
+  sp_nchannel = nchannel;
+  sp_buf = calloc(nchannel, sizeof(SP_BUF));
+  for (i=0; i< SP_MAX; i++){
+    sp_buf[i].tme=0.0;
+    sp_buf[i].val = calloc(nchannel, sizeof(float));
+  }
+  sample=0;
+#ifdef HAVE_SRC
+  interleaved=calloc(nchannel*OBUFSIZE*OVERSAMPLING, sizeof(float));
+  resampled=calloc(nchannel*OBUFSIZE, sizeof(float));
+  rabbit=src_new(SRC_SINC_BEST_QUALITY, nchannel, &rabbit_err);
+  src_set_ratio(rabbit, 1.0/OVERSAMPLING);
+  src_reset(rabbit);
+#endif
+}
+
+int snd_send(double tme, int c, double out) {
+  int i;
+  int rv =0;
+  if (c==0) for (i=SP_MAX-1; i>0; i--) {
+    memcpy(&(sp_buf[i]), &(sp_buf[i-1]), sizeof(SP_BUF));
+  }
+  sp_buf[0].tme=tme * OVERSAMPLING;
+  sp_buf[0].val[c]=out;
+#ifdef SND_DEBUG
+  printf ("INFO : c:%i tme:%f fsmp:%i val:%f\n", c, tme, sample,out); 
+#endif
+
+  if ( (sample) < ceil(tme * OVERSAMPLING) ) {
+    if (!(sp_buf[0].tme > sample)) printf ("error 1 %f !> %i\n",sp_buf[0].tme,sample);
+    if ( (sp_buf[1].tme > sample)) printf ("error 2 %f !< %i\n",sp_buf[1].tme,sample);
+#if 1 // DEBUG
+    if ((sp_buf[0].tme - sample) > 1.0) printf ("error 3 large timestep: dv/dt=%f dt:%f dv:%f\n",
+      (sp_buf[0].val[c] - sp_buf[1].val[c]) / (sp_buf[0].tme - sample) ,
+      (sp_buf[0].tme - sample), ( sp_buf[0].val[c] - sp_buf[1].val[c]) );
+#endif
+
+    // linear
+    double p = (sp_buf[0].tme - sample ) / (sp_buf[0].tme - sp_buf[1].tme);
+    double val = sp_buf[0].val[c] - p * ( sp_buf[0].val[c] - sp_buf[1].val[c] );
+#ifdef SND_DEBUG
+    printf ("DEBUG: writing c:%i p:%f*[%f - %f] v:%f\n",c,p,sp_buf[0].val[c], sp_buf[1].val[c], val);
+#endif
+
+#ifdef HAVE_SRC
+    rv = resample_wrapper (outfile, o_off + val * o_mult);
+#else
+    p_write(outfile, o_off + val * o_mult);
+    if (c==(sp_nchannel-1)) rv =1;
+#endif
+    if (c==(sp_nchannel-1)) sample ++;
+
+  } else {
+#ifdef SND_DEBUG
+    printf(" ^^^^^^^^^ SKIPPED ^^^^^^^^^\n");
+#endif
+  }
+  return (rv);
+}
+
+void snd_close(void) {
+#ifdef HAVE_SRC
+  while (!resample_wrapper(outfile, 0.0)); // flush buffer.
+#endif
+  p_close(outfile);
+  free(filename); filename=NULL;
+#ifdef HAVE_SRC
+  free (interleaved);
+  free (resampled);
+#endif
+  /*
+  int i;
+  for (i=0; i< SP_MAX; i++){ 
+    free (sp_buf[i].val);
+    sp_buf[i].val=NULL;
+  }
+  */
+  free (sp_buf);
+}
+
+double snd_get_samplerate(void) { 
+  return ((double) o_samplerate);
+}
+
+/* vi:set ts=8 sts=2 sw=2: */
+
diff --git a/src/frontend/sndprint.h b/src/frontend/sndprint.h
new file mode 100644
index 0000000..b9bfa3a
--- /dev/null
+++ b/src/frontend/sndprint.h
@@ -0,0 +1,11 @@
+#ifndef _SPICE_SNDFILE_H
+#define _SPICE_SNDFILE_H
+
+void snd_configure(char*, int, int, double, double, int);
+void snd_init(int);
+void snd_close(void);
+int snd_send(double, int, double);
+int snd_format(char*);
+double snd_get_samplerate(void);
+
+#endif
diff --git a/src/include/fteext.h b/src/include/fteext.h
index ef34514..c2776c3 100644
--- a/src/include/fteext.h
+++ b/src/include/fteext.h
@@ -382,6 +382,8 @@ extern void com_let();
 extern void com_unlet();
 extern void com_load();
 extern void com_print();
+extern void com_sndprint();
+extern void com_sndparam();
 extern void com_write();
 extern void com_destroy();
 extern void com_splot();
diff --git a/src/spicelib/devices/vsrc/Makefile.am b/src/spicelib/devices/vsrc/Makefile.am
index 92ece97..d17e97d 100644
--- a/src/spicelib/devices/vsrc/Makefile.am
+++ b/src/spicelib/devices/vsrc/Makefile.am
@@ -21,7 +21,9 @@ libvsrc_a_SOURCES = 	\
 	vsrcpzld.c	\
 	vsrcpzs.c	\
 	vsrcset.c	\
-	vsrctemp.c
+	vsrctemp.c	\
+	vsjack.c	\
+	vsjack.h
 
 
 
diff --git a/src/spicelib/devices/vsrc/vsjack.c b/src/spicelib/devices/vsrc/vsjack.c
new file mode 100644
index 0000000..0b54744
--- /dev/null
+++ b/src/spicelib/devices/vsrc/vsjack.c
@@ -0,0 +1,218 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+/////// SNDFILE ///////
+#include <stdlib.h>
+#include <math.h>
+#include <sndfile.h>
+#include <inttypes.h>
+#define VS_BUFSIZ 1024
+
+#define MAX_D 6 
+char *(sources[MAX_D]);
+
+SNDFILE * m_sndfile[MAX_D]; 
+int m_channels[MAX_D]; //< number of channles in src-file
+uint32_t m_samplerate[MAX_D]; //< samplerate of source
+uint32_t m_frames[MAX_D]; //< duration of source in frames
+float *(interleaved[MAX_D]); //< internal soundfile buffer
+uint32_t ilb_start[MAX_D]; //< first sample in buffer 
+uint32_t ilb_end[MAX_D]; //< last sample in buffer
+
+#define HAVE_SRC
+
+#ifdef HAVE_SRC
+#include <samplerate.h>
+double src_ratio=64.0;
+#define SRC_RATIO src_ratio
+SRC_STATE *rabbit[MAX_D];
+int rabbit_err[MAX_D];
+float *(resampled[MAX_D]); //< internal soundfile buffer
+#endif
+
+void vsjack_initialize(void) {
+	int d;
+	for (d=0;d<MAX_D;d++) {
+		m_sndfile[d]=NULL;
+		interleaved[d]=NULL;
+#ifdef HAVE_SRC
+		resampled[d]=NULL;
+#endif
+		sources[d]=NULL;
+	}
+	sources[0]=strdup("/tmp/test.wav");
+	sources[1]=strdup("/tmp/test1.wav");
+}
+
+void realloc_sf (int d, uint32_t buffersize) {
+	if (interleaved[d]) free(interleaved[d]);
+	interleaved[d] = (float *) calloc(m_channels[d]*buffersize, sizeof(float));
+}
+
+#ifdef HAVE_SRC
+void realloc_src (int d, uint32_t buffersize) {
+	if (resampled[d]) free(resampled[d]);
+	resampled[d] = (float *) calloc(m_channels[d]*buffersize, sizeof(float));
+}
+#endif
+
+#if 0
+void closefile_sf(int d) {
+    if (!m_sndfile[d]) return;
+    sf_close(m_sndfile[d]);
+#ifdef HAVE_SRC
+    src_delete(rabbit[d]);
+#endif
+    m_sndfile[d]=NULL; 
+}
+#endif
+
+int openfile_sf (int d, char *filename) {
+    SF_INFO sfinfo;
+    if (!m_sndfile[d]) sf_close(m_sndfile[d]);
+    printf("opening file '%s' for id:%i\n",filename, d);
+    m_sndfile[d] = sf_open( filename, SFM_READ, &sfinfo );	
+    ilb_end[d]=ilb_start[d]=0;
+    
+    if ( SF_ERR_NO_ERROR != sf_error( m_sndfile[d] ) ) {
+	fprintf(stderr, "This is not a sndfile supported audio file format\n");
+	return (-1);
+    }
+    if ( sfinfo.frames==0 ) {
+	fprintf(stderr, "This is an empty audio file\n" );
+	return (-1);
+    }
+    m_channels[d] = sfinfo.channels;
+    m_samplerate[d] = sfinfo.samplerate;
+    m_frames[d] = (uint32_t) sfinfo.frames;
+    realloc_sf(d, VS_BUFSIZ);
+#ifdef HAVE_SRC
+    realloc_src(d, VS_BUFSIZ*SRC_RATIO);
+    rabbit[d]=src_new(SRC_SINC_BEST_QUALITY, m_channels[d], &(rabbit_err[d]));
+    src_set_ratio(rabbit[d], SRC_RATIO);
+    src_reset(rabbit[d]);
+#endif
+    return (0);
+}
+
+void load_buffer(int d, uint32_t sample) {
+    sf_seek( m_sndfile[d], sample, SEEK_SET );
+    ilb_start[d] = sample;
+    uint32_t nframes;
+    if ((nframes=sf_readf_float(m_sndfile[d], (interleaved[d]), VS_BUFSIZ))>0) {
+	ilb_end[d] = ilb_start[d] + nframes; 
+    } else {
+	ilb_end[d] = ilb_start[d];
+	printf ("Decoder error.\n");
+    }
+#ifdef HAVE_SRC
+    SRC_DATA src_data;
+    src_data.data_in = interleaved[d];
+    src_data.data_out = resampled[d];
+    src_data.input_frames  = VS_BUFSIZ;
+    src_data.output_frames = VS_BUFSIZ*SRC_RATIO;
+    src_data.end_of_input  = ((ilb_end[d]-ilb_start[d]) < VS_BUFSIZ);
+    src_data.src_ratio     =  SRC_RATIO;
+    src_data.input_frames_used = 0;
+    src_data.output_frames_gen = 0;
+
+    src_process(rabbit[d], &src_data);
+#endif
+}
+
+double get_value(int d, double time, int channel) {
+    uint32_t sample = (uint32_t) floor(time*((double)m_samplerate[d]));
+
+    // TODO: print EOF warning (once). FIXME move to load_buffer
+    if (sample > m_frames[d] ) return (0.0);
+
+    if (sample < ilb_start[d] || sample >= ilb_end[d]) 
+	load_buffer(d, sample);
+
+    if (sample < ilb_start[d] || sample >= ilb_end[d]) {
+	printf ("no such value buffered for file:%i.\n",d);
+	return (0.0); // nan ?
+    }
+
+#ifdef HAVE_SRC
+    int offset = floor((sample - ilb_start[d])*SRC_RATIO);
+    if (offset > VS_BUFSIZ*SRC_RATIO || offset < 0) {
+	printf ("value not in buffer:%i.\n",d);
+	return (0.0); // nan ?
+    }
+    float val = ((float *)(resampled[d]))[m_channels[d]*offset+channel];
+#   if 0 // DEBUG 
+#   define SQUARE(A) ((A)*(A))
+    static double stride =0;
+    static double last =0;
+    static double deviation =0;
+    static int dev_cnt = 0;
+    if (channel == 0) {
+	stride += (SRC_RATIO*time*((double)m_samplerate[d])) - last;
+	last = (SRC_RATIO*time*((double)m_samplerate[d]));
+	deviation += SQUARE((SRC_RATIO*time*((double)m_samplerate[d])) - floor(SRC_RATIO*time*((double)m_samplerate[d])));
+	dev_cnt ++;
+	if ((dev_cnt%(12000))==0) 
+	    printf ("read time dev= %f - stride= %f\n", sqrt(deviation/(double)dev_cnt), stride/(double)dev_cnt);
+    }
+#   endif 
+# if 0 // zero order hold.
+    return((double)val);
+# else
+    // linear interpolation
+    float val1 = ((float *)(resampled[d]))[(m_channels[d]*(offset+1))+channel];
+    double diff = (SRC_RATIO*time*((double)m_samplerate[d])) -
+		  floor(SRC_RATIO*time*((double)m_samplerate[d]));
+    double rv = ((double)val)*(1.0-diff) + ((double)val1)*diff;
+    return(rv);
+# endif
+
+#else // no upsampling.
+
+    int offset = sample - ilb_start[d];
+    if (offset > VS_BUFSIZ || offset < 0) {
+	printf ("value not in buffer:%i.\n",d);
+	return (0.0); // nan ?
+    }
+    return((double)(((float *)(interleaved[d]))[m_channels[d]*offset+channel]));
+#endif
+}
+
+
+/*
+ * "public" functions
+ */
+
+double vsjack_get_value (int d, double time, double time_offset, int channel, double oversampling) {
+    assert (d>=0 && d< MAX_D );
+    if (m_sndfile[d] == NULL) return (0.0); // FIXME
+    if (oversampling > 0) src_ratio = oversampling;
+
+    double value = get_value(d, time+time_offset, channel);
+    return (value);
+}
+
+void vsjack_set_file (int d , char *fn) {
+    assert (d>=0 && d< MAX_D );
+    if (sources[d] != NULL) free (sources[d]);
+    sources[d] = strdup(fn);
+}
+
+int vsjack_open (int d) {
+    static int initialized =0;
+    if (!initialized) {
+	initialized=1;
+	vsjack_initialize();
+    }
+    if (d==-1) return -1;// initialize only
+    assert (d>=0 && d< MAX_D );
+    assert (sources[d]!=NULL);
+    if (openfile_sf(d, sources[d])) {
+	printf ("could not open '%s'\n", sources[d]);
+	exit (1);
+    }
+    return (d);
+}
+
+/* vi:set ts=8 sts=4 sw=4: */
diff --git a/src/spicelib/devices/vsrc/vsjack.h b/src/spicelib/devices/vsrc/vsjack.h
new file mode 100644
index 0000000..fe151a6
--- /dev/null
+++ b/src/spicelib/devices/vsrc/vsjack.h
@@ -0,0 +1,4 @@
+
+double vsjack_get_value (int, double, double, int, double);
+int vsjack_open (int);
+void vsjack_set_file (int, char*);
diff --git a/src/spicelib/devices/vsrc/vsrc.c b/src/spicelib/devices/vsrc/vsrc.c
index c73da4d..67e1cc4 100644
--- a/src/spicelib/devices/vsrc/vsrc.c
+++ b/src/spicelib/devices/vsrc/vsrc.c
@@ -17,6 +17,8 @@ IFparm VSRCpTable[] = { /* parameters */
  IP ("sine",    VSRC_SINE,      IF_REALVEC,"Sinusoidal source description"),
  IP ("sin",     VSRC_SINE,      IF_REALVEC,"Sinusoidal source description"),
  IP ("exp",     VSRC_EXP,       IF_REALVEC,"Exponential source description"),
+ IP ("snd",     VSRC_SOUND,     IF_REALVEC,"External sound source parameters"),
+ OPU("file",    VSRC_FILE,      IF_STRING, "External sound source filename"),
  IP ("pwl",     VSRC_PWL,       IF_REALVEC,"Piecewise linear description"),
  IP ("sffm",    VSRC_SFFM,      IF_REALVEC,"Single freq. FM descripton"),
  IP ("am",      VSRC_AM,        IF_REALVEC,"Amplitude modulation descripton"),
diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c
index ac0edc5..8e88e08 100644
--- a/src/spicelib/devices/vsrc/vsrcacct.c
+++ b/src/spicelib/devices/vsrc/vsrcacct.c
@@ -149,6 +149,10 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
                     /* no  breakpoints (yet) */
                 }
                 break;
+                case SOUND: {
+                    /* no  breakpoints (yet) */
+                }
+                break;
                 case EXP: {
                     /* no  breakpoints (yet) */
                 }
diff --git a/src/spicelib/devices/vsrc/vsrcask.c b/src/spicelib/devices/vsrc/vsrcask.c
index 639709e..875ce1d 100644
--- a/src/spicelib/devices/vsrc/vsrcask.c
+++ b/src/spicelib/devices/vsrc/vsrcask.c
@@ -39,6 +39,7 @@ VSRCask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, IFvalue *
             value->rValue = here->VSRCacPhase;
             return (OK);
         case VSRC_PULSE:
+        case VSRC_SOUND:
         case VSRC_SINE:
         case VSRC_EXP:
         case VSRC_PWL:
diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h
index 28c836b..0d21607 100644
--- a/src/spicelib/devices/vsrc/vsrcdefs.h
+++ b/src/spicelib/devices/vsrc/vsrcdefs.h
@@ -89,6 +89,7 @@ typedef struct sVSRCmodel {
 #define SFFM 4
 #define PWL 5
 #define AM 6
+#define SOUND 7
 #endif /*PULSE*/
 
 /* device parameters */
@@ -115,6 +116,8 @@ typedef struct sVSRCmodel {
 #define VSRC_D_F2 21
 
 #define VSRC_AM 22
+#define VSRC_SOUND 23
+#define VSRC_FILE 24
 
 /* model parameters */
 
diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c
index e173a8f..f16ee3b 100644
--- a/src/spicelib/devices/vsrc/vsrcload.c
+++ b/src/spicelib/devices/vsrc/vsrcload.c
@@ -10,6 +10,7 @@ Modified: 2000 AlansFixes
 #include "trandefs.h"
 #include "sperror.h"
 #include "suffix.h"
+#include "vsjack.h"
 
 #ifdef XSPICE_EXP
 /* gtri - begin - wbk - modify for supply ramping option */
@@ -121,6 +122,12 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt)
                 }
                 break;
 
+                case SOUND: {
+			value=here->VSRCcoeffs[2] * vsjack_get_value((int) here->VSRCcoeffs[0], time, (int) here->VSRCcoeffs[3], rint(here->VSRCcoeffs[4]), rint(here->VSRCcoeffs[5]));
+			value+=here->VSRCcoeffs[1];
+		}
+		break;
+
                 case SINE: {
 		
 		    double VO, VA, FREQ, TD, THETA;
diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c
index c59c354..2658242 100644
--- a/src/spicelib/devices/vsrc/vsrcpar.c
+++ b/src/spicelib/devices/vsrc/vsrcpar.c
@@ -11,6 +11,7 @@ Modified: 2000 AlansFixes
 #include "ifsim.h"
 #include "sperror.h"
 #include "suffix.h"
+#include "vsjack.h"
 
 
 /* ARGSUSED */
@@ -19,6 +20,7 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
 {
     int i;
     VSRCinstance *here = (VSRCinstance *)inst;
+    static char *jfile = NULL;
     switch(param) {
         case VSRC_DC:
             here->VSRCdcValue = value->rValue;
@@ -56,6 +58,24 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
             here->VSRCfunctionOrder = value->v.numValue;
             here->VSRCcoeffsGiven = TRUE;
             break;
+        case VSRC_FILE:
+	    jfile=strdup(value->sValue);
+            break;
+        case VSRC_SOUND:
+            here->VSRCfunctionType = SOUND;
+            here->VSRCfuncTGiven = TRUE;
+            here->VSRCcoeffs = value->v.vec.rVec;
+            here->VSRCcoeffsGiven = TRUE;
+	    vsjack_open(-1); // initialize
+	    if (jfile) {
+		vsjack_set_file((int) rint(here->VSRCcoeffs[0]), jfile);
+		free(jfile);
+		jfile=NULL;
+	    }
+	    if (value->v.numValue!=6) 
+		fprintf(stderr, "Warning! invalid jack args: %i\nFormat: jack(id v_off v_mult t_off channel oversampling)",value->v.numValue);
+	    vsjack_open((int) rint(here->VSRCcoeffs[0]));
+            break;
         case VSRC_SINE:
             here->VSRCfunctionType = SINE;
             here->VSRCfuncTGiven = TRUE;
