xref: /openbmc/linux/sound/core/seq/seq_midi_event.c (revision c1017a4c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  MIDI byte <-> sequencer event coder
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>,
5c1017a4cSJaroslav Kysela  *                        Jaroslav Kysela <perex@perex.cz>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
91da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
101da177e4SLinus Torvalds  *   (at your option) any later version.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
131da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4SLinus Torvalds  *   GNU General Public License for more details.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
181da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
191da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <sound/driver.h>
231da177e4SLinus Torvalds #include <linux/slab.h>
241da177e4SLinus Torvalds #include <linux/errno.h>
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <sound/core.h>
271da177e4SLinus Torvalds #include <sound/seq_kernel.h>
281da177e4SLinus Torvalds #include <sound/seq_midi_event.h>
291da177e4SLinus Torvalds #include <sound/asoundef.h>
301da177e4SLinus Torvalds 
31c1017a4cSJaroslav Kysela MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
321da177e4SLinus Torvalds MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder");
331da177e4SLinus Torvalds MODULE_LICENSE("GPL");
341da177e4SLinus Torvalds 
35394d0516SClemens Ladisch /* event type, index into status_event[] */
36394d0516SClemens Ladisch /* from 0 to 6 are normal commands (note off, on, etc.) for 0x9?-0xe? */
37394d0516SClemens Ladisch #define ST_INVALID	7
381da177e4SLinus Torvalds #define ST_SPECIAL	8
391da177e4SLinus Torvalds #define ST_SYSEX	ST_SPECIAL
401da177e4SLinus Torvalds /* from 8 to 15 are events for 0xf0-0xf7 */
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds /*
441da177e4SLinus Torvalds  * prototypes
451da177e4SLinus Torvalds  */
46c7e0b5bfSTakashi Iwai static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
47c7e0b5bfSTakashi Iwai static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
48c7e0b5bfSTakashi Iwai static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
49c7e0b5bfSTakashi Iwai static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
50c7e0b5bfSTakashi Iwai static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
51c7e0b5bfSTakashi Iwai static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev);
52c7e0b5bfSTakashi Iwai static void note_decode(struct snd_seq_event *ev, unsigned char *buf);
53c7e0b5bfSTakashi Iwai static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf);
54c7e0b5bfSTakashi Iwai static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf);
55c7e0b5bfSTakashi Iwai static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf);
56c7e0b5bfSTakashi Iwai static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf);
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /*
591da177e4SLinus Torvalds  * event list
601da177e4SLinus Torvalds  */
61c7e0b5bfSTakashi Iwai static struct status_event_list {
621da177e4SLinus Torvalds 	int event;
631da177e4SLinus Torvalds 	int qlen;
64c7e0b5bfSTakashi Iwai 	void (*encode)(struct snd_midi_event *dev, struct snd_seq_event *ev);
65c7e0b5bfSTakashi Iwai 	void (*decode)(struct snd_seq_event *ev, unsigned char *buf);
661da177e4SLinus Torvalds } status_event[] = {
67394d0516SClemens Ladisch 	/* 0x80 - 0xef */
681da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NOTEOFF,	 2, note_event, note_decode},
691da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NOTEON,	 2, note_event, note_decode},
701da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_KEYPRESS,	 2, note_event, note_decode},
711da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTROLLER,	 2, two_param_ctrl_event, two_param_decode},
721da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_PGMCHANGE,	 1, one_param_ctrl_event, one_param_decode},
731da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CHANPRESS,	 1, one_param_ctrl_event, one_param_decode},
741da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_PITCHBEND,	 2, pitchbend_ctrl_event, pitchbend_decode},
75394d0516SClemens Ladisch 	/* invalid */
76bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL},
771da177e4SLinus Torvalds 	/* 0xf0 - 0xff */
781da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SYSEX,		 1, NULL, NULL}, /* sysex: 0xf0 */
791da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_QFRAME,	 1, one_param_event, one_param_decode}, /* 0xf1 */
801da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SONGPOS,	 2, songpos_event, songpos_decode}, /* 0xf2 */
811da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SONGSEL,	 1, one_param_event, one_param_decode}, /* 0xf3 */
82bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf4 */
83bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf5 */
841da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_TUNE_REQUEST,	 0, NULL, NULL}, /* 0xf6 */
85bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf7 */
861da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CLOCK,		 0, NULL, NULL}, /* 0xf8 */
87bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE,		-1, NULL, NULL}, /* 0xf9 */
881da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_START,		 0, NULL, NULL}, /* 0xfa */
891da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTINUE,	 0, NULL, NULL}, /* 0xfb */
901da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_STOP, 		 0, NULL, NULL}, /* 0xfc */
91bf8c1382SClemens Ladisch 	{SNDRV_SEQ_EVENT_NONE, 		-1, NULL, NULL}, /* 0xfd */
921da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_SENSING, 	 0, NULL, NULL}, /* 0xfe */
931da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_RESET, 	 0, NULL, NULL}, /* 0xff */
941da177e4SLinus Torvalds };
951da177e4SLinus Torvalds 
96c7e0b5bfSTakashi Iwai static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf, int len,
97c7e0b5bfSTakashi Iwai 			       struct snd_seq_event *ev);
98c7e0b5bfSTakashi Iwai static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf, int count,
99c7e0b5bfSTakashi Iwai 			     struct snd_seq_event *ev);
1001da177e4SLinus Torvalds 
101c7e0b5bfSTakashi Iwai static struct extra_event_list {
1021da177e4SLinus Torvalds 	int event;
103c7e0b5bfSTakashi Iwai 	int (*decode)(struct snd_midi_event *dev, unsigned char *buf, int len,
104c7e0b5bfSTakashi Iwai 		      struct snd_seq_event *ev);
1051da177e4SLinus Torvalds } extra_event[] = {
1061da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
1071da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
1081da177e4SLinus Torvalds 	{SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
1091da177e4SLinus Torvalds };
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds /*
1121da177e4SLinus Torvalds  *  new/delete record
1131da177e4SLinus Torvalds  */
1141da177e4SLinus Torvalds 
115c7e0b5bfSTakashi Iwai int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev)
1161da177e4SLinus Torvalds {
117c7e0b5bfSTakashi Iwai 	struct snd_midi_event *dev;
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	*rdev = NULL;
120ecca82b4STakashi Iwai 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1211da177e4SLinus Torvalds 	if (dev == NULL)
1221da177e4SLinus Torvalds 		return -ENOMEM;
1231da177e4SLinus Torvalds 	if (bufsize > 0) {
1241da177e4SLinus Torvalds 		dev->buf = kmalloc(bufsize, GFP_KERNEL);
1251da177e4SLinus Torvalds 		if (dev->buf == NULL) {
1261da177e4SLinus Torvalds 			kfree(dev);
1271da177e4SLinus Torvalds 			return -ENOMEM;
1281da177e4SLinus Torvalds 		}
1291da177e4SLinus Torvalds 	}
1301da177e4SLinus Torvalds 	dev->bufsize = bufsize;
1311da177e4SLinus Torvalds 	dev->lastcmd = 0xff;
132394d0516SClemens Ladisch 	dev->type = ST_INVALID;
1331da177e4SLinus Torvalds 	spin_lock_init(&dev->lock);
1341da177e4SLinus Torvalds 	*rdev = dev;
1351da177e4SLinus Torvalds 	return 0;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds 
138c7e0b5bfSTakashi Iwai void snd_midi_event_free(struct snd_midi_event *dev)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	if (dev != NULL) {
1411da177e4SLinus Torvalds 		kfree(dev->buf);
1421da177e4SLinus Torvalds 		kfree(dev);
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /*
1471da177e4SLinus Torvalds  * initialize record
1481da177e4SLinus Torvalds  */
149c7e0b5bfSTakashi Iwai static inline void reset_encode(struct snd_midi_event *dev)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	dev->read = 0;
1521da177e4SLinus Torvalds 	dev->qlen = 0;
153394d0516SClemens Ladisch 	dev->type = ST_INVALID;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds 
156c7e0b5bfSTakashi Iwai void snd_midi_event_reset_encode(struct snd_midi_event *dev)
1571da177e4SLinus Torvalds {
1581da177e4SLinus Torvalds 	unsigned long flags;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1611da177e4SLinus Torvalds 	reset_encode(dev);
1621da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds 
165c7e0b5bfSTakashi Iwai void snd_midi_event_reset_decode(struct snd_midi_event *dev)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds 	unsigned long flags;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1701da177e4SLinus Torvalds 	dev->lastcmd = 0xff;
1711da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
174123992f7SAdrian Bunk #if 0
175c7e0b5bfSTakashi Iwai void snd_midi_event_init(struct snd_midi_event *dev)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	snd_midi_event_reset_encode(dev);
1781da177e4SLinus Torvalds 	snd_midi_event_reset_decode(dev);
1791da177e4SLinus Torvalds }
180123992f7SAdrian Bunk #endif  /*  0  */
1811da177e4SLinus Torvalds 
182c7e0b5bfSTakashi Iwai void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds 	dev->nostat = on ? 1 : 0;
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds /*
1881da177e4SLinus Torvalds  * resize buffer
1891da177e4SLinus Torvalds  */
190123992f7SAdrian Bunk #if 0
191c7e0b5bfSTakashi Iwai int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize)
1921da177e4SLinus Torvalds {
1931da177e4SLinus Torvalds 	unsigned char *new_buf, *old_buf;
1941da177e4SLinus Torvalds 	unsigned long flags;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	if (bufsize == dev->bufsize)
1971da177e4SLinus Torvalds 		return 0;
1981da177e4SLinus Torvalds 	new_buf = kmalloc(bufsize, GFP_KERNEL);
1991da177e4SLinus Torvalds 	if (new_buf == NULL)
2001da177e4SLinus Torvalds 		return -ENOMEM;
2011da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
2021da177e4SLinus Torvalds 	old_buf = dev->buf;
2031da177e4SLinus Torvalds 	dev->buf = new_buf;
2041da177e4SLinus Torvalds 	dev->bufsize = bufsize;
2051da177e4SLinus Torvalds 	reset_encode(dev);
2061da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
2071da177e4SLinus Torvalds 	kfree(old_buf);
2081da177e4SLinus Torvalds 	return 0;
2091da177e4SLinus Torvalds }
210123992f7SAdrian Bunk #endif  /*  0  */
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds /*
2131da177e4SLinus Torvalds  *  read bytes and encode to sequencer event if finished
2141da177e4SLinus Torvalds  *  return the size of encoded bytes
2151da177e4SLinus Torvalds  */
216c7e0b5bfSTakashi Iwai long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count,
217c7e0b5bfSTakashi Iwai 			   struct snd_seq_event *ev)
2181da177e4SLinus Torvalds {
2191da177e4SLinus Torvalds 	long result = 0;
2201da177e4SLinus Torvalds 	int rc;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	ev->type = SNDRV_SEQ_EVENT_NONE;
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 	while (count-- > 0) {
2251da177e4SLinus Torvalds 		rc = snd_midi_event_encode_byte(dev, *buf++, ev);
2261da177e4SLinus Torvalds 		result++;
2271da177e4SLinus Torvalds 		if (rc < 0)
2281da177e4SLinus Torvalds 			return rc;
2291da177e4SLinus Torvalds 		else if (rc > 0)
2301da177e4SLinus Torvalds 			return result;
2311da177e4SLinus Torvalds 	}
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	return result;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds /*
2371da177e4SLinus Torvalds  *  read one byte and encode to sequencer event:
2381da177e4SLinus Torvalds  *  return 1 if MIDI bytes are encoded to an event
2391da177e4SLinus Torvalds  *         0 data is not finished
2401da177e4SLinus Torvalds  *         negative for error
2411da177e4SLinus Torvalds  */
242c7e0b5bfSTakashi Iwai int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
243c7e0b5bfSTakashi Iwai 			       struct snd_seq_event *ev)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	int rc = 0;
2461da177e4SLinus Torvalds 	unsigned long flags;
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	c &= 0xff;
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	if (c >= MIDI_CMD_COMMON_CLOCK) {
2511da177e4SLinus Torvalds 		/* real-time event */
2521da177e4SLinus Torvalds 		ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
2531da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2541da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
2550e75182cSClemens Ladisch 		return ev->type != SNDRV_SEQ_EVENT_NONE;
2561da177e4SLinus Torvalds 	}
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
259bf8c1382SClemens Ladisch 	if ((c & 0x80) &&
260bf8c1382SClemens Ladisch 	    (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
261bf8c1382SClemens Ladisch 		/* new command */
262bf8c1382SClemens Ladisch 		dev->buf[0] = c;
263bf8c1382SClemens Ladisch 		if ((c & 0xf0) == 0xf0) /* system messages */
264bf8c1382SClemens Ladisch 			dev->type = (c & 0x0f) + ST_SPECIAL;
265bf8c1382SClemens Ladisch 		else
266bf8c1382SClemens Ladisch 			dev->type = (c >> 4) & 0x07;
267bf8c1382SClemens Ladisch 		dev->read = 1;
268bf8c1382SClemens Ladisch 		dev->qlen = status_event[dev->type].qlen;
269bf8c1382SClemens Ladisch 	} else {
2701da177e4SLinus Torvalds 		if (dev->qlen > 0) {
2711da177e4SLinus Torvalds 			/* rest of command */
2721da177e4SLinus Torvalds 			dev->buf[dev->read++] = c;
2731da177e4SLinus Torvalds 			if (dev->type != ST_SYSEX)
2741da177e4SLinus Torvalds 				dev->qlen--;
2751da177e4SLinus Torvalds 		} else {
276bf8c1382SClemens Ladisch 			/* running status */
277bf8c1382SClemens Ladisch 			dev->buf[1] = c;
2781da177e4SLinus Torvalds 			dev->qlen = status_event[dev->type].qlen - 1;
279bf8c1382SClemens Ladisch 			dev->read = 2;
2801da177e4SLinus Torvalds 		}
2811da177e4SLinus Torvalds 	}
2821da177e4SLinus Torvalds 	if (dev->qlen == 0) {
2831da177e4SLinus Torvalds 		ev->type = status_event[dev->type].event;
2841da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2851da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
2861da177e4SLinus Torvalds 		if (status_event[dev->type].encode) /* set data values */
2871da177e4SLinus Torvalds 			status_event[dev->type].encode(dev, ev);
2880b664f72SClemens Ladisch 		if (dev->type >= ST_SPECIAL)
2890b664f72SClemens Ladisch 			dev->type = ST_INVALID;
2901da177e4SLinus Torvalds 		rc = 1;
2911da177e4SLinus Torvalds 	} else 	if (dev->type == ST_SYSEX) {
2921da177e4SLinus Torvalds 		if (c == MIDI_CMD_COMMON_SYSEX_END ||
2931da177e4SLinus Torvalds 		    dev->read >= dev->bufsize) {
2941da177e4SLinus Torvalds 			ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2951da177e4SLinus Torvalds 			ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
2961da177e4SLinus Torvalds 			ev->type = SNDRV_SEQ_EVENT_SYSEX;
2971da177e4SLinus Torvalds 			ev->data.ext.len = dev->read;
2981da177e4SLinus Torvalds 			ev->data.ext.ptr = dev->buf;
2991da177e4SLinus Torvalds 			if (c != MIDI_CMD_COMMON_SYSEX_END)
3001da177e4SLinus Torvalds 				dev->read = 0; /* continue to parse */
3011da177e4SLinus Torvalds 			else
3021da177e4SLinus Torvalds 				reset_encode(dev); /* all parsed */
3031da177e4SLinus Torvalds 			rc = 1;
3041da177e4SLinus Torvalds 		}
3051da177e4SLinus Torvalds 	}
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
3081da177e4SLinus Torvalds 	return rc;
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds /* encode note event */
312c7e0b5bfSTakashi Iwai static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds 	ev->data.note.channel = dev->buf[0] & 0x0f;
3151da177e4SLinus Torvalds 	ev->data.note.note = dev->buf[1];
3161da177e4SLinus Torvalds 	ev->data.note.velocity = dev->buf[2];
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds /* encode one parameter controls */
320c7e0b5bfSTakashi Iwai static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3231da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds /* encode pitch wheel change */
327c7e0b5bfSTakashi Iwai static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3281da177e4SLinus Torvalds {
3291da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3301da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds /* encode midi control change */
334c7e0b5bfSTakashi Iwai static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3351da177e4SLinus Torvalds {
3361da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3371da177e4SLinus Torvalds 	ev->data.control.param = dev->buf[1];
3381da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[2];
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds /* encode one parameter value*/
342c7e0b5bfSTakashi Iwai static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds /* encode song position */
348c7e0b5bfSTakashi Iwai static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
3511da177e4SLinus Torvalds }
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds /*
3541da177e4SLinus Torvalds  * decode from a sequencer event to midi bytes
3551da177e4SLinus Torvalds  * return the size of decoded midi events
3561da177e4SLinus Torvalds  */
357c7e0b5bfSTakashi Iwai long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count,
358c7e0b5bfSTakashi Iwai 			   struct snd_seq_event *ev)
3591da177e4SLinus Torvalds {
3601da177e4SLinus Torvalds 	unsigned int cmd, type;
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 	if (ev->type == SNDRV_SEQ_EVENT_NONE)
3631da177e4SLinus Torvalds 		return -ENOENT;
3641da177e4SLinus Torvalds 
3651da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(status_event); type++) {
3661da177e4SLinus Torvalds 		if (ev->type == status_event[type].event)
3671da177e4SLinus Torvalds 			goto __found;
3681da177e4SLinus Torvalds 	}
3691da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(extra_event); type++) {
3701da177e4SLinus Torvalds 		if (ev->type == extra_event[type].event)
3711da177e4SLinus Torvalds 			return extra_event[type].decode(dev, buf, count, ev);
3721da177e4SLinus Torvalds 	}
3731da177e4SLinus Torvalds 	return -ENOENT;
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds       __found:
3761da177e4SLinus Torvalds 	if (type >= ST_SPECIAL)
3771da177e4SLinus Torvalds 		cmd = 0xf0 + (type - ST_SPECIAL);
3781da177e4SLinus Torvalds 	else
3791da177e4SLinus Torvalds 		/* data.note.channel and data.control.channel is identical */
3801da177e4SLinus Torvalds 		cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f);
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	if (cmd == MIDI_CMD_COMMON_SYSEX) {
3841da177e4SLinus Torvalds 		snd_midi_event_reset_decode(dev);
3851da177e4SLinus Torvalds 		return snd_seq_expand_var_event(ev, count, buf, 1, 0);
3861da177e4SLinus Torvalds 	} else {
3871da177e4SLinus Torvalds 		int qlen;
3881da177e4SLinus Torvalds 		unsigned char xbuf[4];
3891da177e4SLinus Torvalds 		unsigned long flags;
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 		spin_lock_irqsave(&dev->lock, flags);
3921da177e4SLinus Torvalds 		if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) {
3931da177e4SLinus Torvalds 			dev->lastcmd = cmd;
3941da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
3951da177e4SLinus Torvalds 			xbuf[0] = cmd;
3961da177e4SLinus Torvalds 			if (status_event[type].decode)
3971da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 1);
3981da177e4SLinus Torvalds 			qlen = status_event[type].qlen + 1;
3991da177e4SLinus Torvalds 		} else {
4001da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
4011da177e4SLinus Torvalds 			if (status_event[type].decode)
4021da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 0);
4031da177e4SLinus Torvalds 			qlen = status_event[type].qlen;
4041da177e4SLinus Torvalds 		}
4051da177e4SLinus Torvalds 		if (count < qlen)
4061da177e4SLinus Torvalds 			return -ENOMEM;
4071da177e4SLinus Torvalds 		memcpy(buf, xbuf, qlen);
4081da177e4SLinus Torvalds 		return qlen;
4091da177e4SLinus Torvalds 	}
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds /* decode note event */
414c7e0b5bfSTakashi Iwai static void note_decode(struct snd_seq_event *ev, unsigned char *buf)
4151da177e4SLinus Torvalds {
4161da177e4SLinus Torvalds 	buf[0] = ev->data.note.note & 0x7f;
4171da177e4SLinus Torvalds 	buf[1] = ev->data.note.velocity & 0x7f;
4181da177e4SLinus Torvalds }
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds /* decode one parameter controls */
421c7e0b5bfSTakashi Iwai static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds /* decode pitch wheel change */
427c7e0b5bfSTakashi Iwai static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf)
4281da177e4SLinus Torvalds {
4291da177e4SLinus Torvalds 	int value = ev->data.control.value + 8192;
4301da177e4SLinus Torvalds 	buf[0] = value & 0x7f;
4311da177e4SLinus Torvalds 	buf[1] = (value >> 7) & 0x7f;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds /* decode midi control change */
435c7e0b5bfSTakashi Iwai static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf)
4361da177e4SLinus Torvalds {
4371da177e4SLinus Torvalds 	buf[0] = ev->data.control.param & 0x7f;
4381da177e4SLinus Torvalds 	buf[1] = ev->data.control.value & 0x7f;
4391da177e4SLinus Torvalds }
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds /* decode song position */
442c7e0b5bfSTakashi Iwai static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf)
4431da177e4SLinus Torvalds {
4441da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
4451da177e4SLinus Torvalds 	buf[1] = (ev->data.control.value >> 7) & 0x7f;
4461da177e4SLinus Torvalds }
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds /* decode 14bit control */
449c7e0b5bfSTakashi Iwai static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf,
450c7e0b5bfSTakashi Iwai 			       int count, struct snd_seq_event *ev)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	unsigned char cmd;
4531da177e4SLinus Torvalds 	int idx = 0;
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
4561da177e4SLinus Torvalds 	if (ev->data.control.param < 0x20) {
4571da177e4SLinus Torvalds 		if (count < 4)
4581da177e4SLinus Torvalds 			return -ENOMEM;
4591da177e4SLinus Torvalds 		if (dev->nostat && count < 6)
4601da177e4SLinus Torvalds 			return -ENOMEM;
4611da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
4621da177e4SLinus Torvalds 			if (count < 5)
4631da177e4SLinus Torvalds 				return -ENOMEM;
4641da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4651da177e4SLinus Torvalds 		}
4661da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param;
4671da177e4SLinus Torvalds 		buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
4681da177e4SLinus Torvalds 		if (dev->nostat)
4691da177e4SLinus Torvalds 			buf[idx++] = cmd;
4701da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param + 0x20;
4711da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4721da177e4SLinus Torvalds 	} else {
4731da177e4SLinus Torvalds 		if (count < 2)
4741da177e4SLinus Torvalds 			return -ENOMEM;
4751da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
4761da177e4SLinus Torvalds 			if (count < 3)
4771da177e4SLinus Torvalds 				return -ENOMEM;
4781da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4791da177e4SLinus Torvalds 		}
4801da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param & 0x7f;
4811da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4821da177e4SLinus Torvalds 	}
4831da177e4SLinus Torvalds 	return idx;
4841da177e4SLinus Torvalds }
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds /* decode reg/nonreg param */
487c7e0b5bfSTakashi Iwai static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
488c7e0b5bfSTakashi Iwai 			     int count, struct snd_seq_event *ev)
4891da177e4SLinus Torvalds {
4901da177e4SLinus Torvalds 	unsigned char cmd;
4911da177e4SLinus Torvalds 	char *cbytes;
4921da177e4SLinus Torvalds 	static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
4931da177e4SLinus Torvalds 				       MIDI_CTL_NONREG_PARM_NUM_LSB,
4941da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4951da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
4961da177e4SLinus Torvalds 	static char cbytes_rpn[4] =  { MIDI_CTL_REGIST_PARM_NUM_MSB,
4971da177e4SLinus Torvalds 				       MIDI_CTL_REGIST_PARM_NUM_LSB,
4981da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4991da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
5001da177e4SLinus Torvalds 	unsigned char bytes[4];
5011da177e4SLinus Torvalds 	int idx = 0, i;
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	if (count < 8)
5041da177e4SLinus Torvalds 		return -ENOMEM;
5051da177e4SLinus Torvalds 	if (dev->nostat && count < 12)
5061da177e4SLinus Torvalds 		return -ENOMEM;
5071da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
5081da177e4SLinus Torvalds 	bytes[0] = ev->data.control.param & 0x007f;
5091da177e4SLinus Torvalds 	bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
5101da177e4SLinus Torvalds 	bytes[2] = ev->data.control.value & 0x007f;
5111da177e4SLinus Torvalds 	bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
5121da177e4SLinus Torvalds 	if (cmd != dev->lastcmd && !dev->nostat) {
5131da177e4SLinus Torvalds 		if (count < 9)
5141da177e4SLinus Torvalds 			return -ENOMEM;
5151da177e4SLinus Torvalds 		buf[idx++] = dev->lastcmd = cmd;
5161da177e4SLinus Torvalds 	}
5171da177e4SLinus Torvalds 	cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
5181da177e4SLinus Torvalds 	for (i = 0; i < 4; i++) {
5191da177e4SLinus Torvalds 		if (dev->nostat)
5201da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
5211da177e4SLinus Torvalds 		buf[idx++] = cbytes[i];
5221da177e4SLinus Torvalds 		buf[idx++] = bytes[i];
5231da177e4SLinus Torvalds 	}
5241da177e4SLinus Torvalds 	return idx;
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds /*
5281da177e4SLinus Torvalds  *  exports
5291da177e4SLinus Torvalds  */
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_new);
5321da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_free);
5331da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_reset_encode);
5341da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_reset_decode);
5351da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_no_status);
5361da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_encode);
5371da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_encode_byte);
5381da177e4SLinus Torvalds EXPORT_SYMBOL(snd_midi_event_decode);
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds static int __init alsa_seq_midi_event_init(void)
5411da177e4SLinus Torvalds {
5421da177e4SLinus Torvalds 	return 0;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds static void __exit alsa_seq_midi_event_exit(void)
5461da177e4SLinus Torvalds {
5471da177e4SLinus Torvalds }
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds module_init(alsa_seq_midi_event_init)
5501da177e4SLinus Torvalds module_exit(alsa_seq_midi_event_exit)
551