xref: /openbmc/linux/sound/core/seq/seq_midi_event.c (revision ef965ad5)
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 <linux/slab.h>
231da177e4SLinus Torvalds #include <linux/errno.h>
241da177e4SLinus Torvalds #include <linux/string.h>
25da155d5bSPaul Gortmaker #include <linux/module.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 }
1379c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_new);
1381da177e4SLinus Torvalds 
139c7e0b5bfSTakashi Iwai void snd_midi_event_free(struct snd_midi_event *dev)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	if (dev != NULL) {
1421da177e4SLinus Torvalds 		kfree(dev->buf);
1431da177e4SLinus Torvalds 		kfree(dev);
1441da177e4SLinus Torvalds 	}
1451da177e4SLinus Torvalds }
1469c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_free);
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds /*
1491da177e4SLinus Torvalds  * initialize record
1501da177e4SLinus Torvalds  */
151c7e0b5bfSTakashi Iwai static inline void reset_encode(struct snd_midi_event *dev)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	dev->read = 0;
1541da177e4SLinus Torvalds 	dev->qlen = 0;
155394d0516SClemens Ladisch 	dev->type = ST_INVALID;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
158c7e0b5bfSTakashi Iwai void snd_midi_event_reset_encode(struct snd_midi_event *dev)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	unsigned long flags;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1631da177e4SLinus Torvalds 	reset_encode(dev);
1641da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1651da177e4SLinus Torvalds }
1669c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_reset_encode);
1671da177e4SLinus Torvalds 
168c7e0b5bfSTakashi Iwai void snd_midi_event_reset_decode(struct snd_midi_event *dev)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds 	unsigned long flags;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
1731da177e4SLinus Torvalds 	dev->lastcmd = 0xff;
1741da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
1751da177e4SLinus Torvalds }
1769c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_reset_decode);
1771da177e4SLinus Torvalds 
178123992f7SAdrian Bunk #if 0
179c7e0b5bfSTakashi Iwai void snd_midi_event_init(struct snd_midi_event *dev)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	snd_midi_event_reset_encode(dev);
1821da177e4SLinus Torvalds 	snd_midi_event_reset_decode(dev);
1831da177e4SLinus Torvalds }
184123992f7SAdrian Bunk #endif  /*  0  */
1851da177e4SLinus Torvalds 
186c7e0b5bfSTakashi Iwai void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds 	dev->nostat = on ? 1 : 0;
1891da177e4SLinus Torvalds }
1909c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_no_status);
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds /*
1931da177e4SLinus Torvalds  * resize buffer
1941da177e4SLinus Torvalds  */
195123992f7SAdrian Bunk #if 0
196c7e0b5bfSTakashi Iwai int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	unsigned char *new_buf, *old_buf;
1991da177e4SLinus Torvalds 	unsigned long flags;
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	if (bufsize == dev->bufsize)
2021da177e4SLinus Torvalds 		return 0;
2031da177e4SLinus Torvalds 	new_buf = kmalloc(bufsize, GFP_KERNEL);
2041da177e4SLinus Torvalds 	if (new_buf == NULL)
2051da177e4SLinus Torvalds 		return -ENOMEM;
2061da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
2071da177e4SLinus Torvalds 	old_buf = dev->buf;
2081da177e4SLinus Torvalds 	dev->buf = new_buf;
2091da177e4SLinus Torvalds 	dev->bufsize = bufsize;
2101da177e4SLinus Torvalds 	reset_encode(dev);
2111da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
2121da177e4SLinus Torvalds 	kfree(old_buf);
2131da177e4SLinus Torvalds 	return 0;
2141da177e4SLinus Torvalds }
215123992f7SAdrian Bunk #endif  /*  0  */
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds /*
2181da177e4SLinus Torvalds  *  read one byte and encode to sequencer event:
219ef965ad5STakashi Iwai  *  return true if MIDI bytes are encoded to an event
220ef965ad5STakashi Iwai  *         false data is not finished
2211da177e4SLinus Torvalds  */
222ef965ad5STakashi Iwai bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
223c7e0b5bfSTakashi Iwai 				struct snd_seq_event *ev)
2241da177e4SLinus Torvalds {
225ef965ad5STakashi Iwai 	bool rc = false;
2261da177e4SLinus Torvalds 	unsigned long flags;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	if (c >= MIDI_CMD_COMMON_CLOCK) {
2291da177e4SLinus Torvalds 		/* real-time event */
2301da177e4SLinus Torvalds 		ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
2311da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2321da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
2330e75182cSClemens Ladisch 		return ev->type != SNDRV_SEQ_EVENT_NONE;
2341da177e4SLinus Torvalds 	}
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 	spin_lock_irqsave(&dev->lock, flags);
237bf8c1382SClemens Ladisch 	if ((c & 0x80) &&
238bf8c1382SClemens Ladisch 	    (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) {
239bf8c1382SClemens Ladisch 		/* new command */
240bf8c1382SClemens Ladisch 		dev->buf[0] = c;
241bf8c1382SClemens Ladisch 		if ((c & 0xf0) == 0xf0) /* system messages */
242bf8c1382SClemens Ladisch 			dev->type = (c & 0x0f) + ST_SPECIAL;
243bf8c1382SClemens Ladisch 		else
244bf8c1382SClemens Ladisch 			dev->type = (c >> 4) & 0x07;
245bf8c1382SClemens Ladisch 		dev->read = 1;
246bf8c1382SClemens Ladisch 		dev->qlen = status_event[dev->type].qlen;
247bf8c1382SClemens Ladisch 	} else {
2481da177e4SLinus Torvalds 		if (dev->qlen > 0) {
2491da177e4SLinus Torvalds 			/* rest of command */
2501da177e4SLinus Torvalds 			dev->buf[dev->read++] = c;
2511da177e4SLinus Torvalds 			if (dev->type != ST_SYSEX)
2521da177e4SLinus Torvalds 				dev->qlen--;
2531da177e4SLinus Torvalds 		} else {
254bf8c1382SClemens Ladisch 			/* running status */
255bf8c1382SClemens Ladisch 			dev->buf[1] = c;
2561da177e4SLinus Torvalds 			dev->qlen = status_event[dev->type].qlen - 1;
257bf8c1382SClemens Ladisch 			dev->read = 2;
2581da177e4SLinus Torvalds 		}
2591da177e4SLinus Torvalds 	}
2601da177e4SLinus Torvalds 	if (dev->qlen == 0) {
2611da177e4SLinus Torvalds 		ev->type = status_event[dev->type].event;
2621da177e4SLinus Torvalds 		ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2631da177e4SLinus Torvalds 		ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
2641da177e4SLinus Torvalds 		if (status_event[dev->type].encode) /* set data values */
2651da177e4SLinus Torvalds 			status_event[dev->type].encode(dev, ev);
2660b664f72SClemens Ladisch 		if (dev->type >= ST_SPECIAL)
2670b664f72SClemens Ladisch 			dev->type = ST_INVALID;
268ef965ad5STakashi Iwai 		rc = true;
2691da177e4SLinus Torvalds 	} else 	if (dev->type == ST_SYSEX) {
2701da177e4SLinus Torvalds 		if (c == MIDI_CMD_COMMON_SYSEX_END ||
2711da177e4SLinus Torvalds 		    dev->read >= dev->bufsize) {
2721da177e4SLinus Torvalds 			ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
2731da177e4SLinus Torvalds 			ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
2741da177e4SLinus Torvalds 			ev->type = SNDRV_SEQ_EVENT_SYSEX;
2751da177e4SLinus Torvalds 			ev->data.ext.len = dev->read;
2761da177e4SLinus Torvalds 			ev->data.ext.ptr = dev->buf;
2771da177e4SLinus Torvalds 			if (c != MIDI_CMD_COMMON_SYSEX_END)
2781da177e4SLinus Torvalds 				dev->read = 0; /* continue to parse */
2791da177e4SLinus Torvalds 			else
2801da177e4SLinus Torvalds 				reset_encode(dev); /* all parsed */
281ef965ad5STakashi Iwai 			rc = true;
2821da177e4SLinus Torvalds 		}
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	spin_unlock_irqrestore(&dev->lock, flags);
2861da177e4SLinus Torvalds 	return rc;
2871da177e4SLinus Torvalds }
2889c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_encode_byte);
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds /* encode note event */
291c7e0b5bfSTakashi Iwai static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds 	ev->data.note.channel = dev->buf[0] & 0x0f;
2941da177e4SLinus Torvalds 	ev->data.note.note = dev->buf[1];
2951da177e4SLinus Torvalds 	ev->data.note.velocity = dev->buf[2];
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds /* encode one parameter controls */
299c7e0b5bfSTakashi Iwai static void one_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3001da177e4SLinus Torvalds {
3011da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3021da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds /* encode pitch wheel change */
306c7e0b5bfSTakashi Iwai static void pitchbend_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3071da177e4SLinus Torvalds {
3081da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3091da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
3101da177e4SLinus Torvalds }
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds /* encode midi control change */
313c7e0b5bfSTakashi Iwai static void two_param_ctrl_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3141da177e4SLinus Torvalds {
3151da177e4SLinus Torvalds 	ev->data.control.channel = dev->buf[0] & 0x0f;
3161da177e4SLinus Torvalds 	ev->data.control.param = dev->buf[1];
3171da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[2];
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds /* encode one parameter value*/
321c7e0b5bfSTakashi Iwai static void one_param_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	ev->data.control.value = dev->buf[1];
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds /* encode song position */
327c7e0b5bfSTakashi Iwai static void songpos_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
3281da177e4SLinus Torvalds {
3291da177e4SLinus Torvalds 	ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds /*
3331da177e4SLinus Torvalds  * decode from a sequencer event to midi bytes
3341da177e4SLinus Torvalds  * return the size of decoded midi events
3351da177e4SLinus Torvalds  */
336c7e0b5bfSTakashi Iwai long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long count,
337c7e0b5bfSTakashi Iwai 			   struct snd_seq_event *ev)
3381da177e4SLinus Torvalds {
3391da177e4SLinus Torvalds 	unsigned int cmd, type;
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 	if (ev->type == SNDRV_SEQ_EVENT_NONE)
3421da177e4SLinus Torvalds 		return -ENOENT;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(status_event); type++) {
3451da177e4SLinus Torvalds 		if (ev->type == status_event[type].event)
3461da177e4SLinus Torvalds 			goto __found;
3471da177e4SLinus Torvalds 	}
3481da177e4SLinus Torvalds 	for (type = 0; type < ARRAY_SIZE(extra_event); type++) {
3491da177e4SLinus Torvalds 		if (ev->type == extra_event[type].event)
3501da177e4SLinus Torvalds 			return extra_event[type].decode(dev, buf, count, ev);
3511da177e4SLinus Torvalds 	}
3521da177e4SLinus Torvalds 	return -ENOENT;
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds       __found:
3551da177e4SLinus Torvalds 	if (type >= ST_SPECIAL)
3561da177e4SLinus Torvalds 		cmd = 0xf0 + (type - ST_SPECIAL);
3571da177e4SLinus Torvalds 	else
3581da177e4SLinus Torvalds 		/* data.note.channel and data.control.channel is identical */
3591da177e4SLinus Torvalds 		cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f);
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 	if (cmd == MIDI_CMD_COMMON_SYSEX) {
3631da177e4SLinus Torvalds 		snd_midi_event_reset_decode(dev);
3641da177e4SLinus Torvalds 		return snd_seq_expand_var_event(ev, count, buf, 1, 0);
3651da177e4SLinus Torvalds 	} else {
3661da177e4SLinus Torvalds 		int qlen;
3671da177e4SLinus Torvalds 		unsigned char xbuf[4];
3681da177e4SLinus Torvalds 		unsigned long flags;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 		spin_lock_irqsave(&dev->lock, flags);
3711da177e4SLinus Torvalds 		if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) {
3721da177e4SLinus Torvalds 			dev->lastcmd = cmd;
3731da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
3741da177e4SLinus Torvalds 			xbuf[0] = cmd;
3751da177e4SLinus Torvalds 			if (status_event[type].decode)
3761da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 1);
3771da177e4SLinus Torvalds 			qlen = status_event[type].qlen + 1;
3781da177e4SLinus Torvalds 		} else {
3791da177e4SLinus Torvalds 			spin_unlock_irqrestore(&dev->lock, flags);
3801da177e4SLinus Torvalds 			if (status_event[type].decode)
3811da177e4SLinus Torvalds 				status_event[type].decode(ev, xbuf + 0);
3821da177e4SLinus Torvalds 			qlen = status_event[type].qlen;
3831da177e4SLinus Torvalds 		}
3841da177e4SLinus Torvalds 		if (count < qlen)
3851da177e4SLinus Torvalds 			return -ENOMEM;
3861da177e4SLinus Torvalds 		memcpy(buf, xbuf, qlen);
3871da177e4SLinus Torvalds 		return qlen;
3881da177e4SLinus Torvalds 	}
3891da177e4SLinus Torvalds }
3909c8ddd10STakashi Iwai EXPORT_SYMBOL(snd_midi_event_decode);
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds /* decode note event */
394c7e0b5bfSTakashi Iwai static void note_decode(struct snd_seq_event *ev, unsigned char *buf)
3951da177e4SLinus Torvalds {
3961da177e4SLinus Torvalds 	buf[0] = ev->data.note.note & 0x7f;
3971da177e4SLinus Torvalds 	buf[1] = ev->data.note.velocity & 0x7f;
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds /* decode one parameter controls */
401c7e0b5bfSTakashi Iwai static void one_param_decode(struct snd_seq_event *ev, unsigned char *buf)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds /* decode pitch wheel change */
407c7e0b5bfSTakashi Iwai static void pitchbend_decode(struct snd_seq_event *ev, unsigned char *buf)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	int value = ev->data.control.value + 8192;
4101da177e4SLinus Torvalds 	buf[0] = value & 0x7f;
4111da177e4SLinus Torvalds 	buf[1] = (value >> 7) & 0x7f;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds /* decode midi control change */
415c7e0b5bfSTakashi Iwai static void two_param_decode(struct snd_seq_event *ev, unsigned char *buf)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	buf[0] = ev->data.control.param & 0x7f;
4181da177e4SLinus Torvalds 	buf[1] = ev->data.control.value & 0x7f;
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds /* decode song position */
422c7e0b5bfSTakashi Iwai static void songpos_decode(struct snd_seq_event *ev, unsigned char *buf)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds 	buf[0] = ev->data.control.value & 0x7f;
4251da177e4SLinus Torvalds 	buf[1] = (ev->data.control.value >> 7) & 0x7f;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds /* decode 14bit control */
429c7e0b5bfSTakashi Iwai static int extra_decode_ctrl14(struct snd_midi_event *dev, unsigned char *buf,
430c7e0b5bfSTakashi Iwai 			       int count, struct snd_seq_event *ev)
4311da177e4SLinus Torvalds {
4321da177e4SLinus Torvalds 	unsigned char cmd;
4331da177e4SLinus Torvalds 	int idx = 0;
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
4361da177e4SLinus Torvalds 	if (ev->data.control.param < 0x20) {
4371da177e4SLinus Torvalds 		if (count < 4)
4381da177e4SLinus Torvalds 			return -ENOMEM;
4391da177e4SLinus Torvalds 		if (dev->nostat && count < 6)
4401da177e4SLinus Torvalds 			return -ENOMEM;
4411da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
4421da177e4SLinus Torvalds 			if (count < 5)
4431da177e4SLinus Torvalds 				return -ENOMEM;
4441da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4451da177e4SLinus Torvalds 		}
4461da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param;
4471da177e4SLinus Torvalds 		buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
4481da177e4SLinus Torvalds 		if (dev->nostat)
4491da177e4SLinus Torvalds 			buf[idx++] = cmd;
4501da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param + 0x20;
4511da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4521da177e4SLinus Torvalds 	} else {
4531da177e4SLinus Torvalds 		if (count < 2)
4541da177e4SLinus Torvalds 			return -ENOMEM;
4551da177e4SLinus Torvalds 		if (cmd != dev->lastcmd || dev->nostat) {
4561da177e4SLinus Torvalds 			if (count < 3)
4571da177e4SLinus Torvalds 				return -ENOMEM;
4581da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
4591da177e4SLinus Torvalds 		}
4601da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.param & 0x7f;
4611da177e4SLinus Torvalds 		buf[idx++] = ev->data.control.value & 0x7f;
4621da177e4SLinus Torvalds 	}
4631da177e4SLinus Torvalds 	return idx;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds /* decode reg/nonreg param */
467c7e0b5bfSTakashi Iwai static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
468c7e0b5bfSTakashi Iwai 			     int count, struct snd_seq_event *ev)
4691da177e4SLinus Torvalds {
4701da177e4SLinus Torvalds 	unsigned char cmd;
4711da177e4SLinus Torvalds 	char *cbytes;
4721da177e4SLinus Torvalds 	static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
4731da177e4SLinus Torvalds 				       MIDI_CTL_NONREG_PARM_NUM_LSB,
4741da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4751da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
4761da177e4SLinus Torvalds 	static char cbytes_rpn[4] =  { MIDI_CTL_REGIST_PARM_NUM_MSB,
4771da177e4SLinus Torvalds 				       MIDI_CTL_REGIST_PARM_NUM_LSB,
4781da177e4SLinus Torvalds 				       MIDI_CTL_MSB_DATA_ENTRY,
4791da177e4SLinus Torvalds 				       MIDI_CTL_LSB_DATA_ENTRY };
4801da177e4SLinus Torvalds 	unsigned char bytes[4];
4811da177e4SLinus Torvalds 	int idx = 0, i;
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds 	if (count < 8)
4841da177e4SLinus Torvalds 		return -ENOMEM;
4851da177e4SLinus Torvalds 	if (dev->nostat && count < 12)
4861da177e4SLinus Torvalds 		return -ENOMEM;
4871da177e4SLinus Torvalds 	cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
4886423f9eaSClemens Ladisch 	bytes[0] = (ev->data.control.param & 0x3f80) >> 7;
4896423f9eaSClemens Ladisch 	bytes[1] = ev->data.control.param & 0x007f;
4906423f9eaSClemens Ladisch 	bytes[2] = (ev->data.control.value & 0x3f80) >> 7;
4916423f9eaSClemens Ladisch 	bytes[3] = ev->data.control.value & 0x007f;
4921da177e4SLinus Torvalds 	if (cmd != dev->lastcmd && !dev->nostat) {
4931da177e4SLinus Torvalds 		if (count < 9)
4941da177e4SLinus Torvalds 			return -ENOMEM;
4951da177e4SLinus Torvalds 		buf[idx++] = dev->lastcmd = cmd;
4961da177e4SLinus Torvalds 	}
4971da177e4SLinus Torvalds 	cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
4981da177e4SLinus Torvalds 	for (i = 0; i < 4; i++) {
4991da177e4SLinus Torvalds 		if (dev->nostat)
5001da177e4SLinus Torvalds 			buf[idx++] = dev->lastcmd = cmd;
5011da177e4SLinus Torvalds 		buf[idx++] = cbytes[i];
5021da177e4SLinus Torvalds 		buf[idx++] = bytes[i];
5031da177e4SLinus Torvalds 	}
5041da177e4SLinus Torvalds 	return idx;
5051da177e4SLinus Torvalds }
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds static int __init alsa_seq_midi_event_init(void)
5081da177e4SLinus Torvalds {
5091da177e4SLinus Torvalds 	return 0;
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds static void __exit alsa_seq_midi_event_exit(void)
5131da177e4SLinus Torvalds {
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds module_init(alsa_seq_midi_event_init)
5171da177e4SLinus Torvalds module_exit(alsa_seq_midi_event_exit)
518