diff --git a/src/Makefile.am b/src/Makefile.am
index ce576bd..8116491 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
 
 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..bd4c09a 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,141 @@ 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 last_tme=0.0;
+    double samplerate = snd_get_samplerate();
+    const double onem = 0.9;
+    double drift = 0.0;
+    while ((j < npoints)) {
+
+	double tme = bv->v_plot->pl_scale->v_realdata[j] * samplerate;
+
+        for (v = bv; v ; v = v->v_link2) {
+	    if (!(i<=tme || ( abs(drift)< 1.0 && !(tme - last_tme < onem))))
+	    	continue;
+            if (v->v_length <= j) {
+	    	snd_send(0.0);
+	    } else {
+                if (isreal(v)) 
+	    	    snd_send(v->v_realdata[j]);
+		else
+	    	    snd_send(realpart(&v->v_compdata[j]));
+	    }
+        }
+#ifdef SND_DEBUG
+	printf ("debug: %d %d %f - f:%f d:%f\n",
+			j, i, tme, drift, tme-(double)i );
+	if (j>0 && tme - last_tme > 1.5) {
+	    printf ("Warning: large timestep - missing %f sample(s) @pos:%i\n",
+			(tme - last_tme -1.0), (int) rint(tme));
+	}
+	if (i>=tme && ( abs(drift)< 1.0 && !(tme - last_tme < onem))) {
+	    printf ("Warning: small timestep - accepted %f sample(s) @pos:%i\n",
+			(tme - last_tme -1.0), (int) rint(tme));
+	}
+#endif
+
+	if (i<tme || ( abs(drift)< 1.0 && !(tme - last_tme < onem))) {
+	    drift+=1.0-(tme - last_tme);
+	    last_tme=tme;
+	    i++;
+	} 
+#ifdef SND_DEBUG
+	else printf (" SKIPPED ^^^^^^^^^^\n");
+#endif
+        j++;
+    }
+    snd_close();
+    printf ("wrote %i audio-samples from %i data-points\n",i,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;
+
+    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;
+		default:
+		    printf("Warning: unknown argument\n");
+	    }
+            tfree(copypath);
+            wl = wl->wl_next;
+        }
+
+    if (file) 
+        snd_configure(file, srate, fmt, mult, off);
+    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..55b52e6
--- /dev/null
+++ b/src/frontend/sndprint.c
@@ -0,0 +1,174 @@
+#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  //////////////////////////////////
+
+void * outfile;
+void (*p_close)(void*);
+void *(*p_open)(char*, int);
+int  (*p_write)(void*, float);
+
+char *filename = NULL;
+
+void snd_configure(char *fn, int srate, int fmt, double mult, double off ){
+  if (filename) free(filename);
+  filename=strdup(fn);
+
+  o_samplerate = srate;
+  o_mult = mult;
+  o_off = off;
+  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) {
+  if (!filename) snd_configure("spice.wav", 48000.0, o_sndfmt, o_mult, o_off);
+  outfile = p_open (filename, nchannel);
+}
+
+void snd_send(float out) {
+  float val = o_off + out * o_mult;
+  // TODO min/max statistics here ??
+  p_write (outfile, val);
+}
+
+void snd_close(void) {
+  p_close(outfile);
+  //free(filename); filename=NULL;
+}
+
+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..e5cad21
--- /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);
+void snd_init(int);
+void snd_close(void);
+void snd_send(float);
+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..90cebd4
--- /dev/null
+++ b/src/spicelib/devices/vsrc/vsjack.c
@@ -0,0 +1,139 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+/////// SNDFILE ///////
+#include <stdlib.h>
+#include <math.h>
+#include <sndfile.h>
+#include <jack/jack.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
+jack_nframes_t m_samplerate[MAX_D]; //< samplerate of source
+jack_nframes_t m_frames[MAX_D]; //< duration of source in frames
+float *(interleaved[MAX_D]); //< internal soundfile buffer
+jack_nframes_t ilb_start[MAX_D]; //< first sample in buffer 
+jack_nframes_t ilb_end[MAX_D]; //< last sample in buffer
+#ifdef DEBUG_SAMPLESKIP
+jack_nframes_t prev[MAX_D]; //< last timestamp for debugging jumps
+#endif
+
+void vsjack_initialize(void) {
+	int d;
+	for (d=0;d<MAX_D;d++) {
+		m_sndfile[d]=NULL;
+		interleaved[d]=NULL;
+		sources[d]=NULL;
+#ifdef DEBUG_SAMPLESKIP
+		prev[d]=0;
+#endif
+	}
+	sources[0]=strdup("/tmp/test.wav");
+	sources[1]=strdup("/tmp/test1.wav");
+}
+
+void realloc_sf (int d, jack_nframes_t buffersize) {
+	if (interleaved[d]) free(interleaved[d]);
+	interleaved[d] = (float *) calloc(m_channels[d]*buffersize, sizeof(float));
+}
+
+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] = (jack_nframes_t) sfinfo.frames;
+    realloc_sf(d, VS_BUFSIZ);
+    return (0);
+}
+
+void load_buffer(int d, jack_nframes_t sample) {
+    sf_seek( m_sndfile[d], sample, SEEK_SET );
+    ilb_start[d] = sample;
+    jack_nframes_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");
+    }
+}
+
+double get_value(int d, jack_nframes_t sample, int channel) {
+    // 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 for jack:%i.\n",d);
+	return (0.0); // nan ?
+    }
+
+    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]));
+}
+
+
+/*
+ * "public" functions
+ */
+
+double vsjack_get_value (int d, double time, double time_offset, int channel) {
+    assert (d>=0 && d< MAX_D );
+    if (m_sndfile[d] == NULL) return (0.0); // FIXME
+    jack_nframes_t sample = (jack_nframes_t) 
+	    rint((time+time_offset)*((double)m_samplerate[d]));
+#ifdef DEBUG_SAMPLESKIP
+    if (sample-prev[d] > 1) printf("skipped sample on input.\n");
+    if (prev[d] != sample) prev[d]=sample;
+#endif
+    double value = get_value(d, sample, 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..2d5d80b
--- /dev/null
+++ b/src/spicelib/devices/vsrc/vsjack.h
@@ -0,0 +1,4 @@
+
+double vsjack_get_value (int, double, double, int);
+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..86a3995 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]));
+			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..f5bbace 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!=5) 
+		fprintf(stderr, "Warning! invalid jack args: %i\nFormat: jack(id v_off v_mult t_off channel)",value->v.numValue);
+	    vsjack_open((int) rint(here->VSRCcoeffs[0]));
+            break;
         case VSRC_SINE:
             here->VSRCfunctionType = SINE;
             here->VSRCfuncTGiven = TRUE;
