xref: /netbsd/sys/sys/midiio.h (revision 74422c2f)
1*74422c2fSdholland /*	$NetBSD: midiio.h,v 1.16 2015/09/06 06:01:02 dholland Exp $	*/
248bae9eeSaugustss 
367dbe5edSchristos /*-
448bae9eeSaugustss  * Copyright (c) 1998 The NetBSD Foundation, Inc.
548bae9eeSaugustss  * All rights reserved.
648bae9eeSaugustss  *
767dbe5edSchristos  * This code is derived from software contributed to The NetBSD Foundation
8710af634Schap  * by Lennart Augustsson (augustss@NetBSD.org) and (native API structures
9710af634Schap  * and macros) Chapman Flack (chap@NetBSD.org).
1048bae9eeSaugustss  *
1148bae9eeSaugustss  * Redistribution and use in source and binary forms, with or without
1248bae9eeSaugustss  * modification, are permitted provided that the following conditions
1348bae9eeSaugustss  * are met:
1448bae9eeSaugustss  * 1. Redistributions of source code must retain the above copyright
1548bae9eeSaugustss  *    notice, this list of conditions and the following disclaimer.
1648bae9eeSaugustss  * 2. Redistributions in binary form must reproduce the above copyright
1748bae9eeSaugustss  *    notice, this list of conditions and the following disclaimer in the
1848bae9eeSaugustss  *    documentation and/or other materials provided with the distribution.
1948bae9eeSaugustss  *
2048bae9eeSaugustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2148bae9eeSaugustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2248bae9eeSaugustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2367dbe5edSchristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2467dbe5edSchristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2548bae9eeSaugustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2648bae9eeSaugustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2748bae9eeSaugustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2848bae9eeSaugustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2948bae9eeSaugustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3048bae9eeSaugustss  * POSSIBILITY OF SUCH DAMAGE.
3148bae9eeSaugustss  */
3248bae9eeSaugustss 
3348bae9eeSaugustss #ifndef _SYS_MIDIIO_H_
3448bae9eeSaugustss #define _SYS_MIDIIO_H_
3548bae9eeSaugustss 
3648bae9eeSaugustss /*
37710af634Schap  * The API defined here produces events compatible with the OSS MIDI API at
38710af634Schap  * the binary level.
3948bae9eeSaugustss  */
4048bae9eeSaugustss 
414c58d3d9Sbjh21 #include <machine/endian_machdep.h>
42*74422c2fSdholland #include <sys/ioccom.h>
4348bae9eeSaugustss 
4448bae9eeSaugustss /*
4548bae9eeSaugustss  * ioctl() commands for /dev/midi##
46710af634Schap  * XXX is directly frobbing an MPU401 even supported? isn't it just run
47710af634Schap  * in UART mode?
4848bae9eeSaugustss  */
4948bae9eeSaugustss typedef struct {
5048bae9eeSaugustss 	unsigned	char cmd;
5148bae9eeSaugustss 	char		nr_args, nr_returns;
5248bae9eeSaugustss 	unsigned char	data[30];
5348bae9eeSaugustss } mpu_command_rec;
5448bae9eeSaugustss 
5548bae9eeSaugustss #define MIDI_PRETIME		_IOWR('m', 0, int)
5648bae9eeSaugustss #define MIDI_MPUMODE		_IOWR('m', 1, int)
5748bae9eeSaugustss #define MIDI_MPUCMD		_IOWR('m', 2, mpu_command_rec)
5848bae9eeSaugustss 
5948bae9eeSaugustss 
6048bae9eeSaugustss /* The MPU401 command acknowledge and active sense command */
6148bae9eeSaugustss #define MIDI_ACK	0xfe
6248bae9eeSaugustss 
6348bae9eeSaugustss 
6448bae9eeSaugustss /* Sequencer */
6548bae9eeSaugustss #define SEQUENCER_RESET			_IO  ('Q', 0)
6648bae9eeSaugustss #define SEQUENCER_SYNC			_IO  ('Q', 1)
6748bae9eeSaugustss #define SEQUENCER_INFO			_IOWR('Q', 2, struct synth_info)
6848bae9eeSaugustss #define SEQUENCER_CTRLRATE		_IOWR('Q', 3, int)
6948bae9eeSaugustss #define SEQUENCER_GETOUTCOUNT		_IOR ('Q', 4, int)
7048bae9eeSaugustss #define SEQUENCER_GETINCOUNT		_IOR ('Q', 5, int)
7148bae9eeSaugustss /*#define SEQUENCER_PERCMODE		_IOW ('Q', 6, int)*/
7248bae9eeSaugustss /*#define SEQUENCER_TESTMIDI		_IOW ('Q', 8, int)*/
7327c5df27Saugustss #define SEQUENCER_RESETSAMPLES		_IOW ('Q', 9, int)
74710af634Schap /*
75710af634Schap  * The sequencer at present makes no distinction between a 'synth' and a 'midi'.
76710af634Schap  * This is actually a cleaner layering than OSS: devices that are onboard
77710af634Schap  * synths just attach midi(4) via midisyn and present an ordinary MIDI face to
78710af634Schap  * the system. At present the same number is returned for NRSYNTHS and NRMIDIS
79710af634Schap  * but don't believe both, or you'll think you have twice as many devices as
80710af634Schap  * you really have. The MIDI_INFO ioctl isn't implemented; use SEQUENCER_INFO
81710af634Schap  * (which corresponds to OSS's SYNTH_INFO) to get information on any kind of
82710af634Schap  * device, though the struct synth_info it uses has some members that only
83710af634Schap  * pertain to synths (and get filled in with fixed, probably wrong values,
84710af634Schap  * anyway).
85710af634Schap  */
8648bae9eeSaugustss #define SEQUENCER_NRSYNTHS		_IOR ('Q',10, int)
8748bae9eeSaugustss #define SEQUENCER_NRMIDIS		_IOR ('Q',11, int)
8848bae9eeSaugustss /*#define SEQUENCER_MIDI_INFO		_IOWR('Q',12, struct midi_info)*/
8948bae9eeSaugustss #define SEQUENCER_THRESHOLD		_IOW ('Q',13, int)
9048bae9eeSaugustss #define SEQUENCER_MEMAVL		_IOWR('Q',14, int)
9148bae9eeSaugustss /*#define SEQUENCER_FM_4OP_ENABLE		_IOW ('Q',15, int)*/
9248bae9eeSaugustss #define SEQUENCER_PANIC			_IO  ('Q',17)
9348bae9eeSaugustss #define SEQUENCER_OUTOFBAND		_IOW ('Q',18, struct seq_event_rec)
9448bae9eeSaugustss #define SEQUENCER_GETTIME		_IOR ('Q',19, int)
9548bae9eeSaugustss /*#define SEQUENCER_ID			_IOWR('Q',20, struct synth_info)*/
9648bae9eeSaugustss /*#define SEQUENCER_CONTROL		_IOWR('Q',21, struct synth_control)*/
9748bae9eeSaugustss /*#define SEQUENCER_REMOVESAMPLE		_IOWR('Q',22, struct remove_sample)*/
9848bae9eeSaugustss 
9948bae9eeSaugustss #if 0
10048bae9eeSaugustss typedef struct synth_control {
10148bae9eeSaugustss 	int	devno;		/* Synthesizer # */
10248bae9eeSaugustss 	char	data[4000];	/* Device specific command/data record */
10348bae9eeSaugustss } synth_control;
10448bae9eeSaugustss 
10548bae9eeSaugustss typedef struct remove_sample {
10648bae9eeSaugustss 	int	devno;		/* Synthesizer # */
10748bae9eeSaugustss 	int	bankno;		/* MIDI bank # (0=General MIDI) */
10848bae9eeSaugustss 	int	instrno;	/* MIDI instrument number */
10948bae9eeSaugustss } remove_sample;
11048bae9eeSaugustss #endif
11148bae9eeSaugustss 
11248bae9eeSaugustss #define CMDSIZE 8
11348bae9eeSaugustss typedef struct seq_event_rec {
11448bae9eeSaugustss 	u_char	arr[CMDSIZE];
11548bae9eeSaugustss } seq_event_rec;
11648bae9eeSaugustss 
11748bae9eeSaugustss struct synth_info {
11848bae9eeSaugustss 	char	name[30];
11948bae9eeSaugustss 	int	device;
12048bae9eeSaugustss 	int	synth_type;
12148bae9eeSaugustss #define SYNTH_TYPE_FM			0
12248bae9eeSaugustss #define SYNTH_TYPE_SAMPLE		1
12348bae9eeSaugustss #define SYNTH_TYPE_MIDI			2
12448bae9eeSaugustss 
12548bae9eeSaugustss 	int	synth_subtype;
12648bae9eeSaugustss #define SYNTH_SUB_FM_TYPE_ADLIB		0x00
12748bae9eeSaugustss #define SYNTH_SUB_FM_TYPE_OPL3		0x01
12848bae9eeSaugustss #define SYNTH_SUB_MIDI_TYPE_MPU401	0x401
12948bae9eeSaugustss 
13048bae9eeSaugustss #define SYNTH_SUB_SAMPLE_TYPE_BASIC	0x10
13148bae9eeSaugustss #define SYNTH_SUB_SAMPLE_TYPE_GUS	SAMPLE_TYPE_BASIC
13248bae9eeSaugustss 
13348bae9eeSaugustss 	int	nr_voices;
13448bae9eeSaugustss 	int	instr_bank_size;
13548bae9eeSaugustss 	u_int	capabilities;
13648bae9eeSaugustss #define SYNTH_CAP_OPL3			0x00000002
13748bae9eeSaugustss #define SYNTH_CAP_INPUT			0x00000004
13848bae9eeSaugustss };
13948bae9eeSaugustss 
14048bae9eeSaugustss /* Sequencer timer */
14148bae9eeSaugustss #define SEQUENCER_TMR_TIMEBASE		_IOWR('T', 1, int)
14248bae9eeSaugustss #define SEQUENCER_TMR_START		_IO  ('T', 2)
14348bae9eeSaugustss #define SEQUENCER_TMR_STOP		_IO  ('T', 3)
14448bae9eeSaugustss #define SEQUENCER_TMR_CONTINUE		_IO  ('T', 4)
14548bae9eeSaugustss #define SEQUENCER_TMR_TEMPO		_IOWR('T', 5, int)
14648bae9eeSaugustss #define SEQUENCER_TMR_SOURCE		_IOWR('T', 6, int)
14748bae9eeSaugustss #  define SEQUENCER_TMR_INTERNAL	0x00000001
14848bae9eeSaugustss #if 0
14948bae9eeSaugustss #  define SEQUENCER_TMR_EXTERNAL	0x00000002
15048bae9eeSaugustss #  define SEQUENCER_TMR_MODE_MIDI	0x00000010
15148bae9eeSaugustss #  define SEQUENCER_TMR_MODE_FSK	0x00000020
15248bae9eeSaugustss #  define SEQUENCER_TMR_MODE_CLS	0x00000040
15348bae9eeSaugustss #  define SEQUENCER_TMR_MODE_SMPTE	0x00000080
15448bae9eeSaugustss #endif
15548bae9eeSaugustss #define SEQUENCER_TMR_METRONOME		_IOW ('T', 7, int)
15648bae9eeSaugustss #define SEQUENCER_TMR_SELECT		_IOW ('T', 8, int)
15748bae9eeSaugustss 
15848bae9eeSaugustss 
1594ad7b15dSitohy #define MIDI_CTRL_BANK_SELECT_MSB	0
1604ad7b15dSitohy #define MIDI_CTRL_MODULATION_MSB	1
1614ad7b15dSitohy #define MIDI_CTRL_BREATH_MSB		2
1624ad7b15dSitohy #define MIDI_CTRL_FOOT_MSB		4
1634ad7b15dSitohy #define MIDI_CTRL_PORTAMENTO_TIME_MSB	5
1644ad7b15dSitohy #define MIDI_CTRL_DATA_ENTRY_MSB	6
1654ad7b15dSitohy #define MIDI_CTRL_CHANNEL_VOLUME_MSB	7
1664ad7b15dSitohy #define MIDI_CTRL_BALANCE_MSB		8
1674ad7b15dSitohy #define MIDI_CTRL_PAN_MSB		10
1684ad7b15dSitohy #define MIDI_CTRL_EXPRESSION_MSB	11
169710af634Schap #define MIDI_CTRL_EFFECT_1_MSB		12
170710af634Schap #define MIDI_CTRL_EFFECT_2_MSB		13
1714ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_1_MSB	16
1724ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_2_MSB	17
1734ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_3_MSB	18
1744ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_4_MSB	19
1754ad7b15dSitohy #define MIDI_CTRL_BANK_SELECT_LSB	32
1764ad7b15dSitohy #define MIDI_CTRL_MODULATION_LSB	33
1774ad7b15dSitohy #define MIDI_CTRL_BREATH_LSB		34
1784ad7b15dSitohy #define MIDI_CTRL_FOOT_LSB		36
1794ad7b15dSitohy #define MIDI_CTRL_PORTAMENTO_TIME_LSB	37
1804ad7b15dSitohy #define MIDI_CTRL_DATA_ENTRY_LSB	38
1814ad7b15dSitohy #define MIDI_CTRL_CHANNEL_VOLUME_LSB	39
1824ad7b15dSitohy #define MIDI_CTRL_BALANCE_LSB		40
1834ad7b15dSitohy #define MIDI_CTRL_PAN_LSB		42
1844ad7b15dSitohy #define MIDI_CTRL_EXPRESSION_LSB	43
185710af634Schap #define MIDI_CTRL_EFFECT_1_LSB		44
186710af634Schap #define MIDI_CTRL_EFFECT_2_LSB		45
1874ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_1_LSB	48
1884ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_2_LSB	49
1894ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_3_LSB	50
1904ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_4_LSB	51
1914ad7b15dSitohy #define MIDI_CTRL_HOLD_1		64
1924ad7b15dSitohy #define MIDI_CTRL_PORTAMENTO		65
1934ad7b15dSitohy #define MIDI_CTRL_SOSTENUTO		66
1944ad7b15dSitohy #define MIDI_CTRL_SOFT_PEDAL		67
195710af634Schap #define MIDI_CTRL_LEGATO		68
1964ad7b15dSitohy #define MIDI_CTRL_HOLD_2		69
1974ad7b15dSitohy #define MIDI_CTRL_SOUND_VARIATION	70
1984ad7b15dSitohy #define MIDI_CTRL_HARMONIC_INTENSITY	71
1994ad7b15dSitohy #define MIDI_CTRL_RELEASE_TIME		72
2004ad7b15dSitohy #define MIDI_CTRL_ATTACK_TIME		73
2014ad7b15dSitohy #define MIDI_CTRL_BRIGHTNESS		74
2024ad7b15dSitohy #define MIDI_CTRL_DECAY_TIME		75
2034ad7b15dSitohy #define MIDI_CTRL_VIBRATO_RATE		76
2044ad7b15dSitohy #define MIDI_CTRL_VIBRATO_DEPTH		77
205710af634Schap #define MIDI_CTRL_VIBRATO_DELAY		78
206710af634Schap #define MIDI_CTRL_VIBRATO_DECAY		MIDI_CTRL_VIBRATO_DELAY /*deprecated*/
207710af634Schap #define MIDI_CTRL_SOUND_10		79
2084ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_5	80
2094ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_6	81
2104ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_7	82
2114ad7b15dSitohy #define MIDI_CTRL_GENERAL_PURPOSE_8	83
2124ad7b15dSitohy #define MIDI_CTRL_PORTAMENTO_CONTROL	84
2134ad7b15dSitohy #define MIDI_CTRL_EFFECT_DEPTH_1	91
2144ad7b15dSitohy #define MIDI_CTRL_EFFECT_DEPTH_2	92
2154ad7b15dSitohy #define MIDI_CTRL_EFFECT_DEPTH_3	93
2164ad7b15dSitohy #define MIDI_CTRL_EFFECT_DEPTH_4	94
2174ad7b15dSitohy #define MIDI_CTRL_EFFECT_DEPTH_5	95
2184ad7b15dSitohy #define MIDI_CTRL_RPN_INCREMENT		96
2194ad7b15dSitohy #define MIDI_CTRL_RPN_DECREMENT		97
2204ad7b15dSitohy #define MIDI_CTRL_NRPN_LSB		98
2214ad7b15dSitohy #define MIDI_CTRL_NRPN_MSB		99
2224ad7b15dSitohy #define MIDI_CTRL_RPN_LSB		100
2234ad7b15dSitohy #define MIDI_CTRL_RPN_MSB		101
2244ad7b15dSitohy #define MIDI_CTRL_SOUND_OFF		120
22548bae9eeSaugustss #define MIDI_CTRL_RESET			121
226710af634Schap #define MIDI_CTRL_LOCAL			122
227710af634Schap #define MIDI_CTRL_NOTES_OFF		123
228710af634Schap #define MIDI_CTRL_ALLOFF		MIDI_CTRL_NOTES_OFF /*deprecated*/
229710af634Schap #define MIDI_CTRL_OMNI_OFF		124
230710af634Schap #define MIDI_CTRL_OMNI_ON		125
231710af634Schap #define MIDI_CTRL_POLY_OFF		126
232710af634Schap #define MIDI_CTRL_POLY_ON		127
2334ad7b15dSitohy 
23448bae9eeSaugustss #define MIDI_BEND_NEUTRAL	(1<<13)
23548bae9eeSaugustss 
236710af634Schap #define MIDI_RPN_PITCH_BEND_SENSITIVITY	0
237710af634Schap #define MIDI_RPN_CHANNEL_FINE_TUNING	1
238710af634Schap #define MIDI_RPN_CHANNEL_COARSE_TUNING	2
239710af634Schap #define MIDI_RPN_TUNING_PROGRAM_CHANGE	3
240710af634Schap #define MIDI_RPN_TUNING_BANK_SELECT	4
241710af634Schap #define MIDI_RPN_MODULATION_DEPTH_RANGE	5
242710af634Schap 
24348bae9eeSaugustss #define MIDI_NOTEOFF		0x80
24448bae9eeSaugustss #define MIDI_NOTEON		0x90
24548bae9eeSaugustss #define MIDI_KEY_PRESSURE	0xA0
24648bae9eeSaugustss #define MIDI_CTL_CHANGE		0xB0
24748bae9eeSaugustss #define MIDI_PGM_CHANGE		0xC0
24848bae9eeSaugustss #define MIDI_CHN_PRESSURE	0xD0
24948bae9eeSaugustss #define MIDI_PITCH_BEND		0xE0
25048bae9eeSaugustss #define MIDI_SYSTEM_PREFIX	0xF0
25148bae9eeSaugustss 
25248bae9eeSaugustss #define MIDI_IS_STATUS(d) ((d) >= 0x80)
25348bae9eeSaugustss #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
25448bae9eeSaugustss 
25548bae9eeSaugustss #define MIDI_SYSEX_START	0xF0
25648bae9eeSaugustss #define MIDI_SYSEX_END		0xF7
25748bae9eeSaugustss 
25848bae9eeSaugustss #define MIDI_GET_STATUS(d) ((d) & 0xf0)
25948bae9eeSaugustss #define MIDI_GET_CHAN(d) ((d) & 0x0f)
26048bae9eeSaugustss 
26148bae9eeSaugustss #define MIDI_HALF_VEL 64
26248bae9eeSaugustss 
26348bae9eeSaugustss #define SEQ_LOCAL		0x80
26448bae9eeSaugustss #define SEQ_TIMING		0x81
26548bae9eeSaugustss #define SEQ_CHN_COMMON		0x92
26648bae9eeSaugustss #define SEQ_CHN_VOICE		0x93
267b7dab0b3Saugustss #define SEQ_SYSEX		0x94
26848bae9eeSaugustss #define SEQ_FULLSIZE		0xfd
26948bae9eeSaugustss 
27048bae9eeSaugustss #define SEQ_MK_CHN_VOICE(e, unit, cmd, chan, key, vel) (\
27148bae9eeSaugustss     (e)->arr[0] = SEQ_CHN_VOICE, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
27248bae9eeSaugustss     (e)->arr[3] = (chan), (e)->arr[4] = (key), (e)->arr[5] = (vel),\
27348bae9eeSaugustss     (e)->arr[6] = 0, (e)->arr[7] = 0)
27448bae9eeSaugustss #define SEQ_MK_CHN_COMMON(e, unit, cmd, chan, p1, p2, w14) (\
27533a864eeSaugustss     (e)->arr[0] = SEQ_CHN_COMMON, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
27648bae9eeSaugustss     (e)->arr[3] = (chan), (e)->arr[4] = (p1), (e)->arr[5] = (p2),\
27748bae9eeSaugustss     *(short*)&(e)->arr[6] = (w14))
27848bae9eeSaugustss 
2794c58d3d9Sbjh21 #if _BYTE_ORDER == _BIG_ENDIAN
280331bfdf5Saugustss /* big endian */
28148bae9eeSaugustss #define SEQ_PATCHKEY(id) (0xfd00|id)
282331bfdf5Saugustss #else
283331bfdf5Saugustss /* little endian */
284331bfdf5Saugustss #define SEQ_PATCHKEY(id) ((id<<8)|0xfd)
28548bae9eeSaugustss #endif
28648bae9eeSaugustss struct sysex_info {
287144515ceSperry 	uint16_t	key;	/* Use SYSEX_PATCH or MAUI_PATCH here */
28848bae9eeSaugustss #define SEQ_SYSEX_PATCH	SEQ_PATCHKEY(0x05)
28948bae9eeSaugustss #define SEQ_MAUI_PATCH	SEQ_PATCHKEY(0x06)
29048bae9eeSaugustss 	int16_t	device_no;	/* Synthesizer number */
29148bae9eeSaugustss 	int32_t	len;		/* Size of the sysex data in bytes */
29248bae9eeSaugustss 	u_char	data[1];	/* Sysex data starts here */
29348bae9eeSaugustss };
29448bae9eeSaugustss #define SEQ_SYSEX_HDRSIZE ((u_long)((struct sysex_info *)0)->data)
29548bae9eeSaugustss 
29648bae9eeSaugustss typedef unsigned char sbi_instr_data[32];
29748bae9eeSaugustss struct sbi_instrument {
298144515ceSperry 	uint16_t key;	/* FM_PATCH or OPL3_PATCH */
29927c5df27Saugustss #define SBI_FM_PATCH	SEQ_PATCHKEY(0x01)
30027c5df27Saugustss #define SBI_OPL3_PATCH	SEQ_PATCHKEY(0x03)
30148bae9eeSaugustss 	int16_t		device;
30248bae9eeSaugustss 	int32_t		channel;
30348bae9eeSaugustss 	sbi_instr_data	operators;
30448bae9eeSaugustss };
30548bae9eeSaugustss 
306710af634Schap #define TMR_RESET		0	/* beware: not an OSS event */
30748bae9eeSaugustss #define TMR_WAIT_REL		1	/* Time relative to the prev time */
30848bae9eeSaugustss #define TMR_WAIT_ABS		2	/* Absolute time since TMR_START */
30948bae9eeSaugustss #define TMR_STOP		3
31048bae9eeSaugustss #define TMR_START		4
31148bae9eeSaugustss #define TMR_CONTINUE		5
31248bae9eeSaugustss #define TMR_TEMPO		6
31348bae9eeSaugustss #define TMR_ECHO		8
31448bae9eeSaugustss #define TMR_CLOCK		9	/* MIDI clock */
31548bae9eeSaugustss #define TMR_SPP			10	/* Song position pointer */
31648bae9eeSaugustss #define TMR_TIMESIG		11	/* Time signature */
31748bae9eeSaugustss 
31848bae9eeSaugustss /* Old sequencer definitions */
31948bae9eeSaugustss #define SEQOLD_CMDSIZE 4
32048bae9eeSaugustss 
32148bae9eeSaugustss #define SEQOLD_NOTEOFF		0
32248bae9eeSaugustss #define SEQOLD_NOTEON		1
32348bae9eeSaugustss #define SEQOLD_WAIT		TMR_WAIT_ABS
32448bae9eeSaugustss #define SEQOLD_PGMCHANGE	3
32548bae9eeSaugustss #define SEQOLD_SYNCTIMER	TMR_START
32648bae9eeSaugustss #define SEQOLD_MIDIPUTC		5
32748bae9eeSaugustss #define SEQOLD_ECHO		TMR_ECHO
32848bae9eeSaugustss #define SEQOLD_AFTERTOUCH	9
32948bae9eeSaugustss #define SEQOLD_CONTROLLER	10
33048bae9eeSaugustss #define SEQOLD_PRIVATE		0xfe
33148bae9eeSaugustss #define SEQOLD_EXTENDED		0xff
33248bae9eeSaugustss 
333710af634Schap /*
334710af634Schap  * The 'midipitch' data type, used in the kernel between the midisyn layer and
335710af634Schap  * onboard synth drivers, and in userland as parameters to the MIDI Tuning Spec
336710af634Schap  * (RP-012) universal-system-exclusive messages. It is a MIDI key number shifted
337710af634Schap  * left to accommodate 14 bit sub-semitone resolution. In this representation,
338710af634Schap  * tuning and bending adjustments are simple addition and subtraction.
339710af634Schap  */
340710af634Schap typedef int32_t midipitch_t;
341710af634Schap 
342710af634Schap /*
343710af634Schap  * Nominal conversions between midipitches and key numbers. (Beware that these
344710af634Schap  * are the nominal, standard correspondences, but whole point of the MIDI Tuning
345710af634Schap  * Spec is that you can set things up so the hardware might render key N at
346710af634Schap  * actual pitch MIDIPITCH_FROM_KEY(N)+c for some correction c.)
347710af634Schap  */
348710af634Schap #define MIDIPITCH_FROM_KEY(k) ((k)<<14)
349710af634Schap #define MIDIPITCH_TO_KEY(mp) (((mp)+(1<<13))>>14)
350710af634Schap 
351710af634Schap #define MIDIPITCH_MAX (MIDIPITCH_FROM_KEY(128)-2) /* ...(128)-1 is reserved */
352710af634Schap #define MIDIPITCH_OCTAVE  196608
353710af634Schap #define MIDIPITCH_SEMITONE 16384
354710af634Schap #define MIDIPITCH_CENT       164 /* this, regrettably, is inexact. */
355710af634Schap 
356710af634Schap /*
357710af634Schap  * For rendering, convert a midipitch (after all tuning adjustments) to Hz.
358710af634Schap  * The conversion is DEFINED as MIDI key 69.00000 (A) === 440 Hz equal tempered
359710af634Schap  * always. Alternate tunings are obtained by adjusting midipitches.
360710af634Schap  *
361710af634Schap  * The midihz18_t (Hz shifted left for 18-bit sub-Hz resolution) covers the
362710af634Schap  * full midipitch range without losing 21-bit precision, as the lowest midipitch
363710af634Schap  * is ~8 Hz (~3 bits left of radix point, 18 right) and for the highest the
364710af634Schap  * result still fits in a uint32.
365710af634Schap  */
366710af634Schap typedef uint32_t midihz18_t;
367710af634Schap 
368710af634Schap #define MIDIHZ18_TO_HZ(h18) ((h18)>>18) /* truncates! ok for dbg msgs maybe */
369710af634Schap 
370710af634Schap #ifndef _KERNEL
371710af634Schap /*
372710af634Schap  * With floating point in userland, can also manipulate midipitches as
373710af634Schap  * floating-point fractional MIDI key numbers (tuning adjustments are still
374710af634Schap  * additive), and hz18 as fractional Hz (adjustments don't add in this form).
375710af634Schap  */
376710af634Schap #include <math.h>
377710af634Schap #define MIDIPITCH_TO_FRKEY(mp) (scalbn((mp),-14))
378710af634Schap #define MIDIPITCH_FROM_FRKEY(frk) ((midipitch_t)round(scalbn((frk),14)))
379710af634Schap #define MIDIHZ18_TO_FRHZ(h18) (scalbn((h18),-18))
380710af634Schap #define MIDIHZ18_FROM_FRHZ(frh) ((midihz18_t)round(scalbn((frh),18)))
381710af634Schap 
382710af634Schap #define MIDIPITCH_TO_FRHZ(mp) (440*pow(2,(MIDIPITCH_TO_FRKEY((mp))-69)/12))
383710af634Schap #define MIDIPITCH_FROM_FRHZ(fhz) \
384710af634Schap                                MIDIPITCH_FROM_FRKEY(69+12*log((fhz)/440)/log(2))
385710af634Schap #define MIDIPITCH_TO_HZ18(mp) MIDIHZ18_FROM_FRHZ(MIDIPITCH_TO_FRHZ((mp)))
386710af634Schap #define MIDIPITCH_FROM_HZ18(h18) MIDIPITCH_FROM_FRHZ(MIDIHZ18_TO_FRHZ((h18)))
387710af634Schap 
388710af634Schap #else /* no fp in kernel; only an accurate to-hz18 conversion is implemented */
389710af634Schap 
390710af634Schap extern midihz18_t midisyn_mp2hz18(midipitch_t);
391710af634Schap #define MIDIPITCH_TO_HZ18(mp) (midisyn_mp2hz18((mp)))
392710af634Schap 
393710af634Schap #endif /* _KERNEL */
394710af634Schap 
395710af634Schap 
396710af634Schap /*
397710af634Schap  * A native API for the /dev/music sequencer device follows. The event
398710af634Schap  * structures are OSS events at the level of bytes, but for developing or
399710af634Schap  * porting applications some macros and documentation are needed to generate
400710af634Schap  * and dissect the events; here they are. For porting existing OSS applications,
401710af634Schap  * sys/soundcard.h can be extended to supply the usual OSS macros, defining them
402710af634Schap  * in terms of these.
403710af634Schap  */
404710af634Schap 
405710af634Schap /*
406710af634Schap  * TODO: determine OSS compatible structures for TMR_RESET and TMR_CLOCK,
407710af634Schap  *       OSS values of EV_SYSTEM, SNDCTL_SEQ_ACTSENSE_ENABLE,
408710af634Schap  *       SNDCTL_SEQ_TIMING_ENABLE, and SNDCTL_SEQ_RT_ENABLE.
409710af634Schap  * (TMR_RESET may be a NetBSD extension: it is generated in sequencer.c and
410710af634Schap  * has no args. To be corrected if a different definition is found anywhere.)
411710af634Schap  */
412710af634Schap typedef union {
413710af634Schap 
414710af634Schap #define _EVT_HDR \
415710af634Schap 	uint8_t tag
416710af634Schap 
417710af634Schap 	_EVT_HDR;
418710af634Schap 
419710af634Schap #define _LOCAL_HDR \
420710af634Schap 	_EVT_HDR; \
421710af634Schap 	uint8_t op
422710af634Schap 
423710af634Schap 	struct { _LOCAL_HDR; } local;
424710af634Schap 
425710af634Schap 	struct {
426710af634Schap 		_LOCAL_HDR;
427710af634Schap 		uint16_t _zero;
428710af634Schap 		uint32_t devmask;
429710af634Schap 	} l_startaudio;
430710af634Schap 
431710af634Schap /* define a constructor for local evts - someday when we support any */
432710af634Schap 
433710af634Schap #define _TIMING_HDR \
434710af634Schap 	_LOCAL_HDR; \
435710af634Schap 	uint16_t _zeroh
436710af634Schap 	struct { _TIMING_HDR; } timing;
437710af634Schap 
438710af634Schap 	struct {
439710af634Schap 		_TIMING_HDR;
440710af634Schap 		uint32_t divisions;
441710af634Schap 	} t_WAIT_REL, t_WAIT_ABS;
442710af634Schap 
443710af634Schap 	struct {
444710af634Schap 		_TIMING_HDR;
445710af634Schap 		uint32_t _zero;
446710af634Schap 	} t_STOP, t_START, t_CONTINUE, t_RESET;
447710af634Schap 
448710af634Schap 	struct {
449710af634Schap 		_TIMING_HDR;
450710af634Schap 		uint32_t bpm; /* unambiguously, (MIDI clocks/minute)/24 */
451710af634Schap 	} t_TEMPO;
452710af634Schap 
453710af634Schap 	struct {
454710af634Schap 		_TIMING_HDR;
455710af634Schap 		uint32_t cookie;
456710af634Schap 	} t_ECHO;
457710af634Schap 
458710af634Schap 	struct {
459710af634Schap 		_TIMING_HDR;
460710af634Schap 		uint32_t midibeat; /* in low 14 bits; midibeat: 6 MIDI clocks */
461710af634Schap 	} t_SPP;
462710af634Schap 
463710af634Schap 	struct {
464710af634Schap 		_TIMING_HDR;
465710af634Schap #if _BYTE_ORDER == _BIG_ENDIAN
466710af634Schap 		uint8_t numerator;
467710af634Schap 		uint8_t lg2denom;
468710af634Schap 		uint8_t clks_per_click;
469710af634Schap 		uint8_t dsq_per_24clks;
470710af634Schap #elif _BYTE_ORDER == _LITTLE_ENDIAN
471710af634Schap 		uint8_t dsq_per_24clks;
472710af634Schap 		uint8_t clks_per_click;
473710af634Schap 		uint8_t lg2denom;
474710af634Schap 		uint8_t numerator;
475710af634Schap #else
476710af634Schap #error "unexpected _BYTE_ORDER"
477710af634Schap #endif
478710af634Schap 	} t_TIMESIG;
479710af634Schap 
480710af634Schap 	struct { /* use this only to implement OSS compatibility macro */
481710af634Schap 		_TIMING_HDR;
482710af634Schap 		uint32_t signature;
483710af634Schap 	} t_osscompat_timesig;
484710af634Schap 
485710af634Schap 
486710af634Schap #define _COMMON_HDR \
487710af634Schap 	_EVT_HDR; \
488710af634Schap 	uint8_t device; \
489710af634Schap 	uint8_t op; \
490710af634Schap 	uint8_t channel
491710af634Schap 
492710af634Schap 	struct { _COMMON_HDR; } common;
493710af634Schap 
494710af634Schap 	struct {
495710af634Schap 		_COMMON_HDR;
496710af634Schap 		uint8_t controller;
497710af634Schap 		uint8_t _zero;
498710af634Schap 		uint16_t value;
499710af634Schap 	} c_CTL_CHANGE;
500710af634Schap 
501710af634Schap 	struct {
502710af634Schap 		_COMMON_HDR;
503710af634Schap 		uint8_t program;
504710af634Schap 		uint8_t _zero0;
505710af634Schap 		uint16_t _zero1;
506710af634Schap 	} c_PGM_CHANGE;
507710af634Schap 
508710af634Schap 	struct {
509710af634Schap 		_COMMON_HDR;
510710af634Schap 		uint8_t pressure;
511710af634Schap 		uint8_t _zero0;
512710af634Schap 		uint16_t _zero1;
513710af634Schap 	} c_CHN_PRESSURE;
514710af634Schap 
515710af634Schap 	struct {
516710af634Schap 		_COMMON_HDR;
517710af634Schap 		uint8_t _zero0;
518710af634Schap 		uint8_t _zero1;
519710af634Schap 		uint16_t value;
520710af634Schap 	} c_PITCH_BEND;
521710af634Schap 
522710af634Schap #define _VOICE_HDR \
523710af634Schap 	_COMMON_HDR; \
524710af634Schap 	uint8_t key
525710af634Schap 
526710af634Schap 	struct { _VOICE_HDR; }  voice;
527710af634Schap 
528710af634Schap 	struct {
529710af634Schap 		_VOICE_HDR;
530710af634Schap 		uint8_t velocity;
531710af634Schap 		uint16_t _zero;
532710af634Schap 	} c_NOTEOFF, c_NOTEON;
533710af634Schap 
534710af634Schap 	struct {
535710af634Schap 		_VOICE_HDR;
536710af634Schap 		uint8_t pressure;
537710af634Schap 		uint16_t _zero;
538710af634Schap 	} c_KEY_PRESSURE;
539710af634Schap 
540710af634Schap 	struct {
541710af634Schap 		_EVT_HDR;
542710af634Schap 		uint8_t device;
543710af634Schap 		uint8_t buffer[6];
544710af634Schap 	} sysex;
545710af634Schap 
546710af634Schap 	struct {
547710af634Schap 		_EVT_HDR;
548710af634Schap 		uint8_t device;
549710af634Schap 		uint8_t status;
550710af634Schap 		uint8_t data[2];
551710af634Schap 	} system;
552710af634Schap 
553710af634Schap 	struct {
554710af634Schap 		_EVT_HDR;
555710af634Schap 		uint8_t byte;
556710af634Schap 		uint8_t device;
557710af634Schap 		uint8_t _zero0;
558710af634Schap 		uint32_t _zero1;
559710af634Schap 	} putc; /* a seqold event that's still needed at times, ugly as 'tis */
560710af634Schap 
561710af634Schap 	struct {
562710af634Schap 		_EVT_HDR;
563710af634Schap 		uint8_t byte[7];
564710af634Schap 	} unknown; /* for debug/display */
565710af634Schap 
566710af634Schap #undef _VOICE_HDR
567710af634Schap #undef _COMMON_HDR
568710af634Schap #undef _TIMING_HDR
569710af634Schap #undef _LOCAL_HDR
570710af634Schap #undef _EVT_HDR
571710af634Schap 
572710af634Schap } __packed seq_event_t;
573710af634Schap 
574710af634Schap #define _SEQ_TAG_NOTEOFF	SEQ_CHN_VOICE
575710af634Schap #define _SEQ_TAG_NOTEON 	SEQ_CHN_VOICE
576710af634Schap #define _SEQ_TAG_KEY_PRESSURE	SEQ_CHN_VOICE
577710af634Schap 
578710af634Schap #define _SEQ_TAG_CTL_CHANGE	SEQ_CHN_COMMON
579710af634Schap #define _SEQ_TAG_PGM_CHANGE	SEQ_CHN_COMMON
580710af634Schap #define _SEQ_TAG_CHN_PRESSURE	SEQ_CHN_COMMON
581710af634Schap #define _SEQ_TAG_PITCH_BEND	SEQ_CHN_COMMON
582710af634Schap 
583710af634Schap #if __STDC_VERSION__ >= 199901L
584710af634Schap 
585710af634Schap #define SEQ_MK_EVENT(_member,_tag,...)					\
586710af634Schap (seq_event_t){ ._member = { .tag = (_tag), __VA_ARGS__ } }
587710af634Schap 
588710af634Schap #define SEQ_MK_TIMING(_op,...)						\
589710af634Schap SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, __VA_ARGS__)
590710af634Schap 
591710af634Schap #define SEQ_MK_CHN(_op,...)						\
592710af634Schap SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, __VA_ARGS__)
593710af634Schap 
594710af634Schap #define SEQ_MK_SYSEX(_dev,...)						\
595710af634Schap SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), 				\
596710af634Schap              .buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, __VA_ARGS__})
597710af634Schap 
598710af634Schap #else /* assume gcc 2.95.3 */
599710af634Schap 
600710af634Schap #define SEQ_MK_EVENT(_member,_tag,_args...)				\
601710af634Schap (seq_event_t){ ._member = { .tag = (_tag), _args } }
602710af634Schap 
603710af634Schap #define SEQ_MK_TIMING(_op,_args...)						\
604710af634Schap SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, _args)
605710af634Schap 
606710af634Schap #define SEQ_MK_CHN(_op,_args...)					\
607710af634Schap SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, _args)
608710af634Schap 
609710af634Schap #define SEQ_MK_SYSEX(_dev,_args...)						\
610710af634Schap SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), 				\
611710af634Schap              .buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, _args})
612710af634Schap 
613710af634Schap #endif /* c99 vs. gcc 2.95.3 */
614710af634Schap 
615710af634Schap #if 0
616710af634Schap #include <fcntl.h>
617710af634Schap #include <stdio.h>
618710af634Schap int
619710af634Schap main(int argc, char **argv)
620710af634Schap {
621710af634Schap 	int i;
622710af634Schap 	int fd;
623710af634Schap 	seq_event_t e;
624710af634Schap 
625710af634Schap 	/* simple usage example (add a buffer to reduce syscall overhead) */
626710af634Schap 	fd = open("/dev/music", O_RDWR);
627710af634Schap 	write(fd, &SEQ_MK_TIMING(START), sizeof (seq_event_t));
628710af634Schap 
629710af634Schap 	read(fd, &e, sizeof e);
630710af634Schap 	switch ( e.tag ) {
631710af634Schap 	case SEQ_CHN_VOICE:
632710af634Schap 		switch ( e.voice.op ) {
633710af634Schap 		case MIDI_NOTEON:
634710af634Schap 			printf("Note on, dev=%d chn=%d key=%d vel=%d\n",
635710af634Schap 			    e.c_NOTEON.device, e.c_NOTEON.channel,
636710af634Schap 			    e.c_NOTEON.key, e.c_NOTEON.velocity);
637710af634Schap 		}
638710af634Schap 	}
639710af634Schap 
640710af634Schap 	/* all the macros: */
641710af634Schap 	e = SEQ_MK_TIMING(START);
642710af634Schap 	e = SEQ_MK_TIMING(STOP);
643710af634Schap 	e = SEQ_MK_TIMING(CONTINUE);
644710af634Schap 	/*
645710af634Schap 	 * Wait until the specified number of divisions from the timer start
646710af634Schap 	 * (abs) or the preceding event (rel). The number of divisions to a
647710af634Schap 	 * beat or to a MIDI clock is determined by the timebase (set by
648710af634Schap 	 * ioctl). The tempo is expressed in beats per minute, where a beat
649710af634Schap 	 * is always 24 MIDI clocks (and usually equated to a quarter note,
650710af634Schap 	 * but that can be changed with timesig)--that is, tempo is
651710af634Schap 	 * (MIDI clocks per minute)/24. The timebase is the number of divisions
652710af634Schap 	 * in a beat--that is, the number of divisions that make up 24 MIDI
653710af634Schap 	 * clocks--so the timebase is 24*(divisions per MIDI clock). The MThd
654710af634Schap 	 * header in a SMF gives the 'natural' timebase for the file; if the
655710af634Schap 	 * timebase is set accordingly, then the delay values appearing in the
656710af634Schap 	 * tracks are in terms of divisions, and can be used as WAIT_REL
657710af634Schap 	 * arguments without modification.
658710af634Schap 	 */
659710af634Schap 	e = SEQ_MK_TIMING(WAIT_ABS, .divisions=192);
660710af634Schap 	e = SEQ_MK_TIMING(WAIT_REL, .divisions=192);
661710af634Schap 	/*
662710af634Schap 	 * The 'beat' in bpm is 24 MIDI clocks (usually a quarter note but
663710af634Schap 	 * changeable with timesig).
664710af634Schap 	 */
665710af634Schap 	e = SEQ_MK_TIMING(TEMPO, .bpm=84);
666710af634Schap 	/*
667710af634Schap 	 * An ECHO event on output appears on input at the appointed time; the
668710af634Schap 	 * cookie can be anything of interest to the application. Can be used
669710af634Schap 	 * in schemes to get some control over latency.
670710af634Schap 	 */
671710af634Schap 	e = SEQ_MK_TIMING(ECHO, .cookie=0xfeedface);
672710af634Schap 	/*
673710af634Schap 	 * A midibeat is smaller than a beat. It is six MIDI clocks, or a fourth
674710af634Schap 	 * of a beat, or a sixteenth note if the beat is a quarter. SPP is a
675710af634Schap 	 * request to position at the requested midibeat from the start of the
676710af634Schap 	 * sequence. [sequencer does not at present implement SPP]
677710af634Schap 	 */
678710af634Schap 	e = SEQ_MK_TIMING(SPP, .midibeat=128);
679710af634Schap 	/*
680710af634Schap 	 * numerator and lg2denom describe the time signature as it would
681710af634Schap 	 * appear on a staff, where lg2denom of 0,1,2,3... corresponds to
682710af634Schap 	 * denominator of 1,2,4,8... respectively. So the example below
683710af634Schap 	 * corresponds to 4/4. dsq_per_24clks defines the relationship of
684710af634Schap 	 * MIDI clocks to note values, by specifying the number of
685710af634Schap 	 * demisemiquavers (32nd notes) represented by 24 MIDI clocks.
686710af634Schap 	 * The default is 8 demisemiquavers, or a quarter note.
687710af634Schap 	 * clks_per_click can configure a metronome (for example, the MPU401
688710af634Schap 	 * had such a feature in intelligent mode) to click every so many
689710af634Schap 	 * MIDI clocks. The 24 in this example would give a click every quarter
690710af634Schap 	 * note. [sequencer does not at present implement TIMESIG]
691710af634Schap 	 */
692710af634Schap 	e = SEQ_MK_TIMING(TIMESIG, .numerator=4, .lg2denom=2,
693710af634Schap 	                           .clks_per_click=24, .dsq_per_24clks=8);
694710af634Schap 	/*
695710af634Schap 	 * This example declares 6/8 time where the beat (24 clocks) is the
696710af634Schap 	 * eighth note, but the metronome clicks every dotted quarter (twice
697710af634Schap 	 * per measure):
698710af634Schap 	 */
699710af634Schap 	e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
700710af634Schap 	                           .clks_per_click=72, .dsq_per_24clks=4);
701710af634Schap 	/*
702710af634Schap 	 * An alternate declaration for 6/8 where the beat (24 clocks) is now
703710af634Schap 	 * the dotted quarter and corresponds to the metronome click:
704710af634Schap 	 */
705710af634Schap 	e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
706710af634Schap 	                           .clks_per_click=24, .dsq_per_24clks=12);
707710af634Schap 	/*
708710af634Schap 	 * It would also be possible to keep the default correspondence of
709710af634Schap 	 * 24 clocks to the quarter note (8 dsq), and still click the metronome
710710af634Schap 	 * each dotted quarter:
711710af634Schap 	 */
712710af634Schap 	e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
713710af634Schap 	                           .clks_per_click=36, .dsq_per_24clks=8);
714710af634Schap 
715710af634Schap 	e = SEQ_MK_CHN(NOTEON,  .device=1, .channel=0, .key=60, .velocity=64);
716710af634Schap 	e = SEQ_MK_CHN(NOTEOFF, .device=1, .channel=0, .key=60, .velocity=64);
717710af634Schap 	e = SEQ_MK_CHN(KEY_PRESSURE, .device=1, .channel=0, .key=60,
718710af634Schap 	                             .pressure=64);
719710af634Schap 
720710af634Schap 	/*
721710af634Schap 	 * sequencer does not at present implement CTL_CHANGE well. The API
722710af634Schap 	 * provides for a 14-bit value where you give the controller index
723710af634Schap 	 * of the controller MSB and sequencer will split the 14-bit value to
724710af634Schap 	 * the controller MSB and LSB for you--but it doesn't; it ignores the
725710af634Schap 	 * high bits of value and writes the low bits whether you have specified
726710af634Schap 	 * MSB or LSB. That would not be hard to fix but for the fact that OSS
727710af634Schap 	 * itself seems to suffer from the same mixup (and its behavior differs
728710af634Schap 	 * with whether the underlying device is an onboard synth or a MIDI
729710af634Schap 	 * link!) so there is surely a lot of code that relies on it being
730710af634Schap 	 * broken :(.
731710af634Schap 	 * (Note: as the OSS developers have ceased development of the
732710af634Schap 	 * /dev/music API as of OSS4, it would be possible given a complete
733710af634Schap 	 * list of the events defined in OSS4 to add some new ones for native
734710af634Schap 	 * use without fear of future conflict, such as a better ctl_change.)
735710af634Schap 	 */
736710af634Schap 	e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
737710af634Schap 	               .controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192);/*XX*/
738710af634Schap 	/*
739710af634Schap 	 * The way you really have to do it:
740710af634Schap 	 */
741710af634Schap 	e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
742710af634Schap 	               .controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192>>7);
743710af634Schap 	e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
744710af634Schap 	               .controller=MIDI_CTRL_EXPRESSION_LSB, .value=8192&0x7f);
745710af634Schap 
746710af634Schap 	e = SEQ_MK_CHN(PGM_CHANGE,   .device=1, .channel=0, .program=51);
747710af634Schap 	e = SEQ_MK_CHN(CHN_PRESSURE, .device=1, .channel=0, .pressure=64);
748710af634Schap 	e = SEQ_MK_CHN(PITCH_BEND,   .device=1, .channel=0, .value=8192);
749710af634Schap 
750710af634Schap 	/*
751710af634Schap 	 * A SYSEX event carries up to six bytes of a system exclusive message.
752710af634Schap 	 * The first such message must begin with MIDI_SYSEX_START (0xf0), the
753710af634Schap 	 * last must end with MIDI_SYSEX_END (0xf7), and only the last may carry
754710af634Schap 	 * fewer than 6 bytes. To supply message bytes in the macro, you must
755710af634Schap 	 * prefix the first with [0]= as shown. The macro's first argument is
756710af634Schap 	 * the device.
757710af634Schap 	 */
758710af634Schap 	e = SEQ_MK_SYSEX(1,[0]=MIDI_SYSEX_START,1,2,MIDI_SYSEX_END);
759710af634Schap 	/*
760710af634Schap 	 * In some cases it may be easier to use the macro only to initialize
761710af634Schap 	 * the event, and fill in the message bytes later. The code that fills
762710af634Schap 	 * in the message does not need to store 0xff following the SYSEX_END.
763710af634Schap 	 */
764710af634Schap 	e = SEQ_MK_SYSEX(1);
765710af634Schap 	for ( i = 0; i < 3; ++ i )
766710af634Schap 		e.sysex.buffer[i] = i;
767710af634Schap 	/*
768710af634Schap 	 * It would be nice to think the old /dev/sequencer MIDIPUTC event
769710af634Schap 	 * obsolete, but it is still needed (absent any better API) by any MIDI
770710af634Schap 	 * file player that will implement the ESCAPED events that may occur in
771710af634Schap 	 * SMF. Sorry. Here's how to use it:
772710af634Schap 	 */
773710af634Schap 	e = SEQ_MK_EVENT(putc, SEQOLD_MIDIPUTC, .device=1, .byte=42);
774710af634Schap 
775710af634Schap 	printf("confirm event size: %d (should be 8)\n", sizeof (seq_event_t));
776710af634Schap 	return 0;
777710af634Schap }
778710af634Schap #endif /* 0 */
779710af634Schap 
78048bae9eeSaugustss #endif /* !_SYS_MIDIIO_H_ */
781