diff --git a/Makefile b/Makefile
index ca6979a..c969b94 100644
--- a/Makefile
+++ b/Makefile
@@ -49,0 +50,12 @@ LIBS=	-lm -lpthread
+# use ALSA Sequencer MIDI interface
+CFLAGS+= -DHAVE_ASEQ
+LIBS+= -lasound
+
+# JACKify
+CFLAGS+= -DHAVE_JACK
+LIBS+= -ljack
+
+# Do not use libsamplerate (experimental).
+#CFLAGS+= -DHAVE_SRC
+#LIBS+= -lsamplerate
+
diff --git a/main.c b/main.c
index 8735e5c..807e0d9 100644
--- a/main.c
+++ b/main.c
@@ -122,0 +123,166 @@ static void setAudioDevice (char * s) {
+#ifdef HAVE_JACK
+#include <jack/jack.h>
+
+jack_client_t *j_client = NULL;
+jack_port_t **j_output_port; 
+jack_default_audio_sample_t **j_output_bufferptrs; // 
+jack_default_audio_sample_t bufJ [2][BUFFER_SIZE_SAMPLES];
+
+jack_nframes_t jack_splrate=44100;
+jack_nframes_t jack_fragsize=128;
+
+
+/* when jack shuts down... */
+void jack_shutdown_callback(void *arg) {
+  fprintf(stderr,"jack server shut us down.\n");
+  jack_deactivate(j_client);
+  j_client=NULL;
+}
+
+int jack_srate_callback(jack_nframes_t nframes, void *arg) {
+  jack_splrate= nframes;
+  return(0); 
+}
+
+int jack_bufsiz_callback(jack_nframes_t nframes, void *arg) {
+  jack_fragsize= nframes;
+  return(0); 
+}
+#ifdef HAVE_SRC
+#include<samplerate.h>
+#include<math.h>
+#endif
+
+int jack_audio_callback (jack_nframes_t nframes, void *arg) {
+  jack_default_audio_sample_t **out = j_output_bufferptrs; 
+  int i,s;
+  //jack_nframes_t my_tot_latency = 0;
+
+  for (i=0;i<audio_channels;i++) {
+  	//jack_nframes_t my_latency = jack_port_get_total_latency(j_client,j_output_port[i]);
+  	//if (my_latency > my_tot_latency) my_tot_latency = my_latency;
+  	out[i] = jack_port_get_buffer (j_output_port[i], nframes);
+  	//memset(out[i],0, sizeof (jack_default_audio_sample_t) * nframes);
+  }
+
+  static unsigned char * obuf;
+  static int boffset = BUFFER_SIZE_SAMPLES;
+
+  float m_fResampleRatio = (float) jack_splrate / (float)SampleRateD;
+#ifndef HAVE_SRC
+  static int info =0;
+#if 1 
+  if (!info) { 
+    info=1;
+    printf ("JACK: integer resampling factor: %f\nJACK: suggest: osc.tuning=%f\n",
+      floorf(m_fResampleRatio+.5),
+      440.0/m_fResampleRatio*floorf(m_fResampleRatio+.5));
+  }
+  m_fResampleRatio = floorf(m_fResampleRatio+.5);
+# endif
+#endif
+
+  jack_nframes_t out_off = 0; 
+
+  while (out_off < nframes) {
+    int remain_src = BUFFER_SIZE_SAMPLES - boffset;
+    int remain_dst = nframes - out_off;
+    if (remain_src <= 0)  {
+      boffset = 0; remain_src+=BUFFER_SIZE_SAMPLES;
+      // generate sound
+      oscGenerateFragment (bufA, BUFFER_SIZE_SAMPLES);
+      obuf = preamp (bufA, bufB, BUFFER_SIZE_SAMPLES);
+      obuf = reverb (obuf, bufB, BUFFER_SIZE_SAMPLES);
+      whirlProc (obuf, bufC, BUFFER_SIZE_SAMPLES);
+
+      // convert interlaced channels
+      float nfactor =  1.0 / ((float) 0x8000);
+      for (s=0;s<BUFFER_SIZE_SAMPLES;s++)
+	for (i=0;i<audio_channels;i++) 
+	//bufJ[i][s]= (((jack_default_audio_sample_t)(((signed short*)bufA)[s]))/32768.0);
+	//bufJ[i][s]= ((((signed short*)obuf)[s]))/32768.0;
+	  bufJ[i][s]= ((jack_default_audio_sample_t)(((signed short*)bufC)[audio_channels*s+i]))*nfactor;
+    }
+
+    jack_nframes_t nread = (jack_nframes_t) ceilf((float)remain_dst / m_fResampleRatio);
+    if (nread > remain_src) nread = remain_src;
+    jack_nframes_t nwrite = (jack_nframes_t) floorf((float)nread * m_fResampleRatio);
+    //printf("DEBUG %i %i %f\n", nread, nwrite, m_fResampleRatio);
+#ifdef HAVE_SRC 
+    SRC_DATA src_data;
+    src_data.input_frames  = nread;
+    src_data.output_frames = nwrite;
+    src_data.end_of_input  = 0;
+    src_data.src_ratio     = m_fResampleRatio;
+    src_data.input_frames_used = 0;
+    src_data.output_frames_gen = 0;
+
+    for (i=0;i< audio_channels; i++ ) {
+      src_data.data_in       = &(bufJ[i][boffset]);
+      src_data.data_out      = &(out[i][out_off]);
+      src_simple (&src_data, SRC_SINC_FASTEST, 1) ;
+      //src_simple (&src_data, SRC_SINC_MEDIUM_QUALITY, 1) ;
+      //src_simple (&src_data, SRC_ZERO_ORDER_HOLD, 1) ;
+      //src_simple (&src_data, SRC_LINEAR, 1) ;
+      //src_simple (&src_data, SRC_SINC_BEST_QUALITY, 1) ;
+    }
+    out_off+=src_data.output_frames_gen;
+    boffset+=src_data.input_frames_used;
+#else
+    assert (m_fResampleRatio == 2.0 || m_fResampleRatio==1.0 || m_fResampleRatio==4.0 || m_fResampleRatio==3.0);
+    int r,stride = (int) rintf(m_fResampleRatio);
+
+    for (i=0;i< audio_channels; i++ ) {
+      for (s=0;s<nread;s++) {
+	for (r=0;r<stride;r++)
+	  out[i][out_off+r+stride*s] = bufJ[i][boffset+s];
+      }
+    }
+    out_off+=stride*nread;
+    boffset+=nread;
+#endif
+  }
+  return(0);
+}
+
+int open_jack(void) {
+  int i;
+  i = 0;
+  do {
+    char jackid[16];
+    snprintf(jackid,16,"beatrix-%i",i);
+    j_client = jack_client_open (jackid, JackUseExactName, NULL);
+  } while (j_client == 0 && i++<16);
+
+  if (!j_client) {
+    fprintf(stderr, "could not connect to jack.\n");
+    return(1);
+  }	
+  audio_channels=audio_channels_requested;
+  audio_format = audio_format_requested;
+
+  jack_on_shutdown (j_client, jack_shutdown_callback, NULL);
+  jack_set_process_callback(j_client,jack_audio_callback,NULL);
+  jack_set_sample_rate_callback (j_client, jack_srate_callback, NULL);
+  jack_set_buffer_size_callback (j_client, jack_bufsiz_callback, NULL);
+
+  j_output_port= calloc(audio_channels,sizeof(jack_port_t*));
+  j_output_bufferptrs = calloc(audio_channels,sizeof(jack_default_audio_sample_t*));
+
+  for (i=0;i<audio_channels;i++) {
+    char channelid[16];
+    snprintf(channelid,16,"output-%i",i);
+    j_output_port[i] = jack_port_register (j_client, channelid, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+    if (!j_output_port[i]) {
+      fprintf(stderr, "no more jack ports available.\n");
+      jack_client_close (j_client);
+      return(1);
+    }
+  }
+  jack_srate_callback(jack_get_sample_rate(j_client),NULL); // init j_srate
+  jack_bufsiz_callback(jack_get_buffer_size(j_client),NULL); // init j_bufsiz & alloc
+
+  return(0);
+}
+#endif
+
@@ -129,0 +296,7 @@ static void initAudio () {
+#ifdef HAVE_JACK
+  if (open_jack()) {
+    perror ("could not connect to JACK.");
+    exit(1);
+  }
+#else /* NO JACK - OSS */
+
@@ -211,0 +385 @@ static void initAudio () {
+#endif /* NO JACK = OSS */
@@ -408,0 +583,2 @@ static void Usage () {
+  printf ("-R <rate>  set samplerate for synth. default 22050.\n");
+  printf ("           jack-sr must be a multiple of this.\n");
@@ -455,0 +632,3 @@ int main (int argc, char * argv []) {
+      else if (!strcmp (av, "-R")) {
+	state = 2;
+      }
@@ -479,0 +659,6 @@ int main (int argc, char * argv []) {
+    else if (state == 2) {
+      SampleRateI = atoi (av);
+      SampleRateD = (double) SampleRateI;
+      printf(" beatrix internal samplerate: %.1f SPS\n",SampleRateD);
+      state = 0;
+    }
@@ -541,0 +727,4 @@ int main (int argc, char * argv []) {
+# ifdef HAVE_ASEQ
+  if (!aseq_open(NULL))
+    k= pthread_create(&t_midi, NULL, aseq_run, NULL); 
+# else
@@ -542,0 +732 @@ int main (int argc, char * argv []) {
+# endif
@@ -595,0 +786,6 @@ int main (int argc, char * argv []) {
+#ifdef HAVE_JACK
+      jack_activate(j_client);
+      while (j_client)
+	sleep (1); // jack callback is doing this:
+      return(0);
+#else
@@ -629,0 +826 @@ int main (int argc, char * argv []) {
+#endif
@@ -636,0 +834,2 @@ int main (int argc, char * argv []) {
+
+/* vi:set ts=8 sts=2 sw=2: */
diff --git a/midi.c b/midi.c
index b4b807b..07ffaf8 100644
--- a/midi.c
+++ b/midi.c
@@ -1060,0 +1061,138 @@ void * MIDIInReader (void * arg) {
+
+
+#ifdef HAVE_ASEQ
+#include <alsa/asoundlib.h>
+// getpid()
+#include <sys/types.h>
+#include <unistd.h>
+
+snd_seq_t *seq= NULL;
+int aseq_stop=0; // only modify in main thread.
+
+void aseq_close(void) {
+  if(!seq) return;
+  printf("closing alsa midi...");
+  snd_seq_close(seq);
+  seq=NULL;
+}
+
+#if 0
+inline void midi_close(void) {
+  if(!seq) return;
+  aseq_stop=1;
+  sleep(1);
+  //pthread_join(t_midi,NULL);
+  aseq_close();
+}
+#endif
+
+int aseq_open(char *port_name) {
+  int err=0;
+  snd_seq_addr_t port;
+  char seq_name[32];
+  snprintf(seq_name,32,"beatrix-%i",(int) getpid());
+
+  if (seq) return (-1);
+
+  if ((err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_INPUT, 0)) <0 ) {
+    fprintf(stderr,"cannot open alsa sequencer: %s\n", snd_strerror(err));
+    seq=NULL;
+    return(-1);
+  }
+
+  if ((err = snd_seq_set_client_name(seq, seq_name)) <0 ) {
+    fprintf(stderr,"cannot set client name: %s\n", snd_strerror(err));
+    aseq_close();
+    return(-1);
+  }
+
+  if ((err = snd_seq_create_simple_port(seq, "in", 
+    	SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE, 
+    	SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION)) < 0) {
+    fprintf(stderr,"cannot create port: %s\n", snd_strerror(err));
+    aseq_close();
+    return(-1);
+  }
+
+  if (port_name) {
+    err = snd_seq_parse_address(seq, &port, port_name);
+    if (err < 0) {
+      fprintf(stderr,"Cannot find port %s - %s\n", port_name, snd_strerror(err));
+    }
+    err = snd_seq_connect_from(seq, 0, port.client, port.port);
+    if (err < 0) {
+      fprintf(stderr,"Cannot connect from port %d:%d - %s\n", port.client, port.port, snd_strerror(err));
+    }
+  }
+
+  snd_seq_nonblock(seq, 1);
+
+  /* Load the tables */
+
+  loadControllerTable ();
+  loadKeyTableA ();
+  loadKeyTableB ();
+  loadKeyTableC ();
+  loadStatusTable ();
+
+  return(0);
+}
+
+void process_seq_event(const snd_seq_event_t *ev) {
+  // see "snd_seq_event_type" file:///usr/share/doc/libasound2-doc/html/group___seq_events.html
+  switch(ev->type) {
+    case SND_SEQ_EVENT_NOTEON:
+      //printf("DEBUG KEY on %i %i\n",ev->data.note.channel, ev->data.note.note);
+      if (ev->data.note.velocity > 0){
+          keyTable = (unsigned char *) statusTable[MIDI_NOTEON|ev->data.note.channel].handback;
+          oscKeyOn (keyTable[ev->data.note.note]);
+          break;
+      }
+    case SND_SEQ_EVENT_NOTEOFF:
+      //printf("DEBUG KEY off %i %i\n",ev->data.note.channel, ev->data.note.note);
+      keyTable = (unsigned char *) statusTable[MIDI_NOTEOFF|ev->data.note.channel].handback;
+      oscKeyOff (keyTable[ev->data.note.note]);
+      break;
+    case SND_SEQ_EVENT_PGMCHANGE:
+      printf("DEBUG Programchange %i\n",ev->data.control.value);
+      installProgram(ev->data.control.value);	
+      break;
+    case SND_SEQ_EVENT_CONTROLLER:
+      printf("DEBUG Controller [%i] %i -> %i\n",ev->data.control.channel, ev->data.control.param, ev->data.control.value);
+      ctrlvec = (void (**) (unsigned char)) statusTable[MIDI_CTL_CHANGE|ev->data.control.channel].handback;
+      (ctrlvec[ev->data.control.param])(ev->data.control.value);
+      break;
+    case SND_SEQ_EVENT_SENSING:
+      break;
+    default:
+      printf("unhandled midi event: %i\n", ev->type);
+      assert(1);
+      break;
+  }
+}
+
+void *aseq_run(void *arg) {
+  int err;
+  int npfds = 0;
+  struct pollfd *pfds;
+
+  npfds = snd_seq_poll_descriptors_count(seq, POLLIN);
+  pfds = alloca(sizeof(*pfds) * npfds);
+  for (;;) {
+    snd_seq_poll_descriptors(seq, pfds, npfds, POLLIN);
+    if (poll(pfds, npfds, 1) < 0) break;
+    do {
+      snd_seq_event_t *event;
+      err = snd_seq_event_input(seq, &event);
+      if (err < 0) break;
+      if (event) process_seq_event(event);
+    } while (err > 0);
+    if (aseq_stop) break;
+  }
+  pthread_exit(NULL);
+  return (NULL);
+}
+
+#endif
+
+/* vi:set ts=8 sts=2 sw=2: */
diff --git a/midi.h b/midi.h
index deb7cbf..3e37ae5 100644
--- a/midi.h
+++ b/midi.h
@@ -44,0 +45,5 @@ extern void * MIDIInReader (void * arg);
+#ifdef HAVE_ASEQ
+extern void *aseq_run(void *arg);
+extern int aseq_open(char *port_name);
+#endif
+
