patch-1.3.9 linux/drivers/sound/midi_synth.c

Next file: linux/drivers/sound/midi_synth.h
Previous file: linux/drivers/sound/midi_ctrl.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
@@ -27,6 +27,9 @@
  *
  */
 
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
 #include "sound_config.h"
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
@@ -40,6 +43,61 @@
 static int      midi2synth[MAX_MIDI_DEV];
 static unsigned char prev_out_status[MAX_MIDI_DEV];
 
+#define STORE(cmd) \
+{ \
+  int len; \
+  unsigned char obuf[8]; \
+  cmd; \
+  seq_input_event(obuf, len); \
+}
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+void
+do_midi_msg (int synthno, unsigned char *msg, int mlen)
+{
+  switch (msg[0] & 0xf0)
+    {
+    case 0x90:
+      if (msg[2] != 0)
+	{
+	  STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+	  break;
+	}
+      msg[2] = 64;
+
+    case 0x80:
+      STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xA0:
+      STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xB0:
+      STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f,
+			  msg[1], msg[2]));
+      break;
+
+    case 0xC0:
+      STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xD0:
+      STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xE0:
+      STORE (SEQ_BENDER (synthno, msg[0] & 0x0f,
+			 (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
+      break;
+
+    default:
+      /* printk ("MPU: Unknown midi channel message %02x\n", msg[0]); */
+    }
+}
+
 static void
 midi_outc (int midi_dev, int data)
 {
@@ -69,25 +127,118 @@
 static int
 prefix_cmd (int midi_dev, unsigned char status)
 {
-  if (midi_devs[midi_dev]->prefix_cmd == NULL)
+  if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
     return 1;
 
   return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
 }
 
 static void
-midi_synth_input (int dev, unsigned char data)
+midi_synth_input (int orig_dev, unsigned char data)
 {
-  int             orig_dev;
+  int             dev;
+  struct midi_input_info *inc;
+
+  static unsigned char len_tab[] =	/* # of data bytes following a status
+					 */
+  {
+    2,				/* 8x */
+    2,				/* 9x */
+    2,				/* Ax */
+    2,				/* Bx */
+    1,				/* Cx */
+    1,				/* Dx */
+    2,				/* Ex */
+    0				/* Fx */
+  };
 
-  if (dev < 0 || dev > num_synths)
+  if (orig_dev < 0 || orig_dev > num_midis)
     return;
 
   if (data == 0xfe)		/* Ignore active sensing */
     return;
 
-  orig_dev = midi2synth[dev];
+  dev = midi2synth[orig_dev];
+  inc = &midi_devs[orig_dev]->in_info;
 
+  switch (inc->m_state)
+    {
+    case MST_INIT:
+      if (data & 0x80)		/* MIDI status byte */
+	{
+	  if ((data & 0xf0) == 0xf0)	/* Common message */
+	    {
+	      switch (data)
+		{
+		case 0xf0:	/* Sysex */
+		  inc->m_state = MST_SYSEX;
+		  break;	/* Sysex */
+
+		case 0xf1:	/* MTC quarter frame */
+		case 0xf3:	/* Song select */
+		  inc->m_state = MST_DATA;
+		  inc->m_ptr = 1;
+		  inc->m_left = 1;
+		  inc->m_buf[0] = data;
+		  break;
+
+		case 0xf2:	/* Song position pointer */
+		  inc->m_state = MST_DATA;
+		  inc->m_ptr = 1;
+		  inc->m_left = 2;
+		  inc->m_buf[0] = data;
+		  break;
+
+		default:
+		  inc->m_buf[0] = data;
+		  inc->m_ptr = 1;
+		  do_midi_msg (dev, inc->m_buf, inc->m_ptr);
+		  inc->m_ptr = 0;
+		  inc->m_left = 0;
+		}
+	    }
+	  else
+	    {
+	      inc->m_state = MST_DATA;
+	      inc->m_ptr = 1;
+	      inc->m_left = len_tab[(data >> 4) - 8];
+	      inc->m_buf[0] = inc->m_prev_status = data;
+	    }
+	}
+      else if (inc->m_prev_status & 0x80)	/* Ignore if no previous status (yet) */
+	{			/* Data byte (use running status) */
+	  inc->m_state = MST_DATA;
+	  inc->m_ptr = 2;
+	  inc->m_left = len_tab[(data >> 4) - 8] - 1;
+	  inc->m_buf[0] = inc->m_prev_status;
+	  inc->m_buf[1] = data;
+	}
+      break;			/* MST_INIT */
+
+    case MST_DATA:
+      inc->m_buf[inc->m_ptr++] = data;
+      if (--inc->m_left <= 0)
+	{
+	  inc->m_state = MST_INIT;
+	  do_midi_msg (dev, inc->m_buf, inc->m_ptr);
+	  inc->m_ptr = 0;
+	}
+      break;			/* MST_DATA */
+
+    case MST_SYSEX:
+      if (data == 0xf7)		/* Sysex end */
+	{
+	  inc->m_state = MST_INIT;
+	  inc->m_left = 0;
+	  inc->m_ptr = 0;
+	}
+      break;			/* MST_SYSEX */
+
+    default:
+      printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
+	      (int) data);
+      inc->m_state = MST_INIT;
+    }
 }
 
 static void
@@ -155,9 +306,9 @@
       if (msg == 0x90)		/*
 				 * Running status = Note on
 				 */
-	midi_outc (orig_dev, 0);/*
-					 * Note on with velocity 0 == note
-					 * off
+	midi_outc (orig_dev, 0);	/*
+					   * Note on with velocity 0 == note
+					   * off
 					 */
       else
 	midi_outc (orig_dev, velocity);
@@ -261,6 +412,8 @@
 {
   int             orig_dev = synth_devs[dev]->midi_dev;
   int             err;
+  unsigned long   flags;
+  struct midi_input_info *inc;
 
   if (orig_dev < 0 || orig_dev > num_midis)
     return RET_ERROR (ENXIO);
@@ -272,6 +425,16 @@
 				  midi_synth_input, midi_synth_output)) < 0)
     return err;
 
+  inc = &midi_devs[orig_dev]->in_info;
+
+  DISABLE_INTR (flags);
+  inc->m_busy = 0;
+  inc->m_state = MST_INIT;
+  inc->m_ptr = 0;
+  inc->m_left = 0;
+  inc->m_prev_status = 0x00;
+  RESTORE_INTR (flags);
+
   return 1;
 }
 
@@ -281,8 +444,8 @@
   int             orig_dev = synth_devs[dev]->midi_dev;
 
   /*
- * Shut up the synths by sending just single active sensing message.
- */
+     * Shut up the synths by sending just single active sensing message.
+   */
   midi_devs[orig_dev]->putc (orig_dev, 0xfe);
 
   midi_devs[orig_dev]->close (orig_dev);
@@ -303,6 +466,7 @@
   int             i;
   unsigned long   left, src_offs, eox_seen = 0;
   int             first_byte = 1;
+  int             hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
 
   if (!prefix_cmd (orig_dev, 0xf0))
     return 0;
@@ -313,20 +477,20 @@
       return RET_ERROR (EINVAL);
     }
 
-  if (count < sizeof (struct sysex_info))
+  if (count < hdr_size)
     {
       printk ("MIDI Error: Patch header too short\n");
       return RET_ERROR (EINVAL);
     }
 
-  count -= sizeof (struct sysex_info);
+  count -= hdr_size;
 
   /*
    * Copy the header from user space but ignore the first bytes which have
    * been transferred already.
    */
 
-  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
+  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs);
 
   if (count < sysex.len)
     {
@@ -344,21 +508,20 @@
     {
       unsigned char   data;
 
-      GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
+      GET_BYTE_FROM_USER (data, addr, hdr_size + i);
 
-      if (first_byte && data != 0xf0)
-	midi_outc (orig_dev, 0xf0);	/* Sysex start */
+      eox_seen = (i > 0 && data & 0x80);	/* End of sysex */
 
-      eox_seen = (data == 0xf7);/*
-					 * Last byte was end of sysex
-					 */
+      if (eox_seen && data != 0xf7)
+	data = 0xf7;
 
       if (i == 0)
 	{
-	  if (data != 0xf0)	/*
-				 * Sysex start
-				 */
-	    return RET_ERROR (EINVAL);
+	  if (data != 0xf0)
+	    {
+	      printk ("Error: Sysex start missing\n");
+	      return RET_ERROR (EINVAL);
+	    }
 	}
 
       while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
@@ -406,6 +569,7 @@
     }
   else if (!prefix_cmd (orig_dev, pressure))
     return;
+
   midi_outc (orig_dev, pressure);
 }
 
@@ -458,7 +622,8 @@
   prev_chn = prev_out_status[orig_dev] & 0x0f;
 
   if (msg != 0xd0 || prev_chn != channel)	/*
-						 * * Test for running status  */
+						 * Test for running status
+						 */
     {
       if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
 	return;
@@ -469,6 +634,11 @@
 
   midi_outc (orig_dev, value & 0x7f);
   midi_outc (orig_dev, (value >> 7) & 0x7f);
+}
+
+void
+midi_synth_setup_voice (int dev, int voice, int channel)
+{
 }
 
 #endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this