1 | /* $NetBSD: midiio.h,v 1.16 2015/09/06 06:01:02 dholland Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1998 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (augustss@NetBSD.org) and (native API structures |
9 | * and macros) Chapman Flack (chap@NetBSD.org). |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | #ifndef _SYS_MIDIIO_H_ |
34 | #define _SYS_MIDIIO_H_ |
35 | |
36 | /* |
37 | * The API defined here produces events compatible with the OSS MIDI API at |
38 | * the binary level. |
39 | */ |
40 | |
41 | #include <machine/endian_machdep.h> |
42 | #include <sys/ioccom.h> |
43 | |
44 | /* |
45 | * ioctl() commands for /dev/midi## |
46 | * XXX is directly frobbing an MPU401 even supported? isn't it just run |
47 | * in UART mode? |
48 | */ |
49 | typedef struct { |
50 | unsigned char cmd; |
51 | char nr_args, nr_returns; |
52 | unsigned char data[30]; |
53 | } mpu_command_rec; |
54 | |
55 | #define MIDI_PRETIME _IOWR('m', 0, int) |
56 | #define MIDI_MPUMODE _IOWR('m', 1, int) |
57 | #define MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec) |
58 | |
59 | |
60 | /* The MPU401 command acknowledge and active sense command */ |
61 | #define MIDI_ACK 0xfe |
62 | |
63 | |
64 | /* Sequencer */ |
65 | #define SEQUENCER_RESET _IO ('Q', 0) |
66 | #define SEQUENCER_SYNC _IO ('Q', 1) |
67 | #define SEQUENCER_INFO _IOWR('Q', 2, struct synth_info) |
68 | #define SEQUENCER_CTRLRATE _IOWR('Q', 3, int) |
69 | #define SEQUENCER_GETOUTCOUNT _IOR ('Q', 4, int) |
70 | #define SEQUENCER_GETINCOUNT _IOR ('Q', 5, int) |
71 | /*#define SEQUENCER_PERCMODE _IOW ('Q', 6, int)*/ |
72 | /*#define SEQUENCER_TESTMIDI _IOW ('Q', 8, int)*/ |
73 | #define SEQUENCER_RESETSAMPLES _IOW ('Q', 9, int) |
74 | /* |
75 | * The sequencer at present makes no distinction between a 'synth' and a 'midi'. |
76 | * This is actually a cleaner layering than OSS: devices that are onboard |
77 | * synths just attach midi(4) via midisyn and present an ordinary MIDI face to |
78 | * the system. At present the same number is returned for NRSYNTHS and NRMIDIS |
79 | * but don't believe both, or you'll think you have twice as many devices as |
80 | * you really have. The MIDI_INFO ioctl isn't implemented; use SEQUENCER_INFO |
81 | * (which corresponds to OSS's SYNTH_INFO) to get information on any kind of |
82 | * device, though the struct synth_info it uses has some members that only |
83 | * pertain to synths (and get filled in with fixed, probably wrong values, |
84 | * anyway). |
85 | */ |
86 | #define SEQUENCER_NRSYNTHS _IOR ('Q',10, int) |
87 | #define SEQUENCER_NRMIDIS _IOR ('Q',11, int) |
88 | /*#define SEQUENCER_MIDI_INFO _IOWR('Q',12, struct midi_info)*/ |
89 | #define SEQUENCER_THRESHOLD _IOW ('Q',13, int) |
90 | #define SEQUENCER_MEMAVL _IOWR('Q',14, int) |
91 | /*#define SEQUENCER_FM_4OP_ENABLE _IOW ('Q',15, int)*/ |
92 | #define SEQUENCER_PANIC _IO ('Q',17) |
93 | #define SEQUENCER_OUTOFBAND _IOW ('Q',18, struct seq_event_rec) |
94 | #define SEQUENCER_GETTIME _IOR ('Q',19, int) |
95 | /*#define SEQUENCER_ID _IOWR('Q',20, struct synth_info)*/ |
96 | /*#define SEQUENCER_CONTROL _IOWR('Q',21, struct synth_control)*/ |
97 | /*#define SEQUENCER_REMOVESAMPLE _IOWR('Q',22, struct remove_sample)*/ |
98 | |
99 | #if 0 |
100 | typedef struct synth_control { |
101 | int devno; /* Synthesizer # */ |
102 | char data[4000]; /* Device specific command/data record */ |
103 | } synth_control; |
104 | |
105 | typedef struct remove_sample { |
106 | int devno; /* Synthesizer # */ |
107 | int bankno; /* MIDI bank # (0=General MIDI) */ |
108 | int instrno; /* MIDI instrument number */ |
109 | } remove_sample; |
110 | #endif |
111 | |
112 | #define CMDSIZE 8 |
113 | typedef struct seq_event_rec { |
114 | u_char arr[CMDSIZE]; |
115 | } seq_event_rec; |
116 | |
117 | struct synth_info { |
118 | char name[30]; |
119 | int device; |
120 | int synth_type; |
121 | #define SYNTH_TYPE_FM 0 |
122 | #define SYNTH_TYPE_SAMPLE 1 |
123 | #define SYNTH_TYPE_MIDI 2 |
124 | |
125 | int synth_subtype; |
126 | #define SYNTH_SUB_FM_TYPE_ADLIB 0x00 |
127 | #define SYNTH_SUB_FM_TYPE_OPL3 0x01 |
128 | #define SYNTH_SUB_MIDI_TYPE_MPU401 0x401 |
129 | |
130 | #define SYNTH_SUB_SAMPLE_TYPE_BASIC 0x10 |
131 | #define SYNTH_SUB_SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC |
132 | |
133 | int nr_voices; |
134 | int instr_bank_size; |
135 | u_int capabilities; |
136 | #define SYNTH_CAP_OPL3 0x00000002 |
137 | #define SYNTH_CAP_INPUT 0x00000004 |
138 | }; |
139 | |
140 | /* Sequencer timer */ |
141 | #define SEQUENCER_TMR_TIMEBASE _IOWR('T', 1, int) |
142 | #define SEQUENCER_TMR_START _IO ('T', 2) |
143 | #define SEQUENCER_TMR_STOP _IO ('T', 3) |
144 | #define SEQUENCER_TMR_CONTINUE _IO ('T', 4) |
145 | #define SEQUENCER_TMR_TEMPO _IOWR('T', 5, int) |
146 | #define SEQUENCER_TMR_SOURCE _IOWR('T', 6, int) |
147 | # define SEQUENCER_TMR_INTERNAL 0x00000001 |
148 | #if 0 |
149 | # define SEQUENCER_TMR_EXTERNAL 0x00000002 |
150 | # define SEQUENCER_TMR_MODE_MIDI 0x00000010 |
151 | # define SEQUENCER_TMR_MODE_FSK 0x00000020 |
152 | # define SEQUENCER_TMR_MODE_CLS 0x00000040 |
153 | # define SEQUENCER_TMR_MODE_SMPTE 0x00000080 |
154 | #endif |
155 | #define SEQUENCER_TMR_METRONOME _IOW ('T', 7, int) |
156 | #define SEQUENCER_TMR_SELECT _IOW ('T', 8, int) |
157 | |
158 | |
159 | #define MIDI_CTRL_BANK_SELECT_MSB 0 |
160 | #define MIDI_CTRL_MODULATION_MSB 1 |
161 | #define MIDI_CTRL_BREATH_MSB 2 |
162 | #define 4 |
163 | #define MIDI_CTRL_PORTAMENTO_TIME_MSB 5 |
164 | #define MIDI_CTRL_DATA_ENTRY_MSB 6 |
165 | #define MIDI_CTRL_CHANNEL_VOLUME_MSB 7 |
166 | #define MIDI_CTRL_BALANCE_MSB 8 |
167 | #define MIDI_CTRL_PAN_MSB 10 |
168 | #define MIDI_CTRL_EXPRESSION_MSB 11 |
169 | #define MIDI_CTRL_EFFECT_1_MSB 12 |
170 | #define MIDI_CTRL_EFFECT_2_MSB 13 |
171 | #define MIDI_CTRL_GENERAL_PURPOSE_1_MSB 16 |
172 | #define MIDI_CTRL_GENERAL_PURPOSE_2_MSB 17 |
173 | #define MIDI_CTRL_GENERAL_PURPOSE_3_MSB 18 |
174 | #define MIDI_CTRL_GENERAL_PURPOSE_4_MSB 19 |
175 | #define MIDI_CTRL_BANK_SELECT_LSB 32 |
176 | #define MIDI_CTRL_MODULATION_LSB 33 |
177 | #define MIDI_CTRL_BREATH_LSB 34 |
178 | #define 36 |
179 | #define MIDI_CTRL_PORTAMENTO_TIME_LSB 37 |
180 | #define MIDI_CTRL_DATA_ENTRY_LSB 38 |
181 | #define MIDI_CTRL_CHANNEL_VOLUME_LSB 39 |
182 | #define MIDI_CTRL_BALANCE_LSB 40 |
183 | #define MIDI_CTRL_PAN_LSB 42 |
184 | #define MIDI_CTRL_EXPRESSION_LSB 43 |
185 | #define MIDI_CTRL_EFFECT_1_LSB 44 |
186 | #define MIDI_CTRL_EFFECT_2_LSB 45 |
187 | #define MIDI_CTRL_GENERAL_PURPOSE_1_LSB 48 |
188 | #define MIDI_CTRL_GENERAL_PURPOSE_2_LSB 49 |
189 | #define MIDI_CTRL_GENERAL_PURPOSE_3_LSB 50 |
190 | #define MIDI_CTRL_GENERAL_PURPOSE_4_LSB 51 |
191 | #define MIDI_CTRL_HOLD_1 64 |
192 | #define MIDI_CTRL_PORTAMENTO 65 |
193 | #define MIDI_CTRL_SOSTENUTO 66 |
194 | #define MIDI_CTRL_SOFT_PEDAL 67 |
195 | #define MIDI_CTRL_LEGATO 68 |
196 | #define MIDI_CTRL_HOLD_2 69 |
197 | #define MIDI_CTRL_SOUND_VARIATION 70 |
198 | #define MIDI_CTRL_HARMONIC_INTENSITY 71 |
199 | #define MIDI_CTRL_RELEASE_TIME 72 |
200 | #define MIDI_CTRL_ATTACK_TIME 73 |
201 | #define MIDI_CTRL_BRIGHTNESS 74 |
202 | #define MIDI_CTRL_DECAY_TIME 75 |
203 | #define MIDI_CTRL_VIBRATO_RATE 76 |
204 | #define MIDI_CTRL_VIBRATO_DEPTH 77 |
205 | #define MIDI_CTRL_VIBRATO_DELAY 78 |
206 | #define MIDI_CTRL_VIBRATO_DECAY MIDI_CTRL_VIBRATO_DELAY /*deprecated*/ |
207 | #define MIDI_CTRL_SOUND_10 79 |
208 | #define MIDI_CTRL_GENERAL_PURPOSE_5 80 |
209 | #define MIDI_CTRL_GENERAL_PURPOSE_6 81 |
210 | #define MIDI_CTRL_GENERAL_PURPOSE_7 82 |
211 | #define MIDI_CTRL_GENERAL_PURPOSE_8 83 |
212 | #define MIDI_CTRL_PORTAMENTO_CONTROL 84 |
213 | #define MIDI_CTRL_EFFECT_DEPTH_1 91 |
214 | #define MIDI_CTRL_EFFECT_DEPTH_2 92 |
215 | #define MIDI_CTRL_EFFECT_DEPTH_3 93 |
216 | #define MIDI_CTRL_EFFECT_DEPTH_4 94 |
217 | #define MIDI_CTRL_EFFECT_DEPTH_5 95 |
218 | #define MIDI_CTRL_RPN_INCREMENT 96 |
219 | #define MIDI_CTRL_RPN_DECREMENT 97 |
220 | #define MIDI_CTRL_NRPN_LSB 98 |
221 | #define MIDI_CTRL_NRPN_MSB 99 |
222 | #define MIDI_CTRL_RPN_LSB 100 |
223 | #define MIDI_CTRL_RPN_MSB 101 |
224 | #define MIDI_CTRL_SOUND_OFF 120 |
225 | #define MIDI_CTRL_RESET 121 |
226 | #define MIDI_CTRL_LOCAL 122 |
227 | #define MIDI_CTRL_NOTES_OFF 123 |
228 | #define MIDI_CTRL_ALLOFF MIDI_CTRL_NOTES_OFF /*deprecated*/ |
229 | #define MIDI_CTRL_OMNI_OFF 124 |
230 | #define MIDI_CTRL_OMNI_ON 125 |
231 | #define MIDI_CTRL_POLY_OFF 126 |
232 | #define MIDI_CTRL_POLY_ON 127 |
233 | |
234 | #define MIDI_BEND_NEUTRAL (1<<13) |
235 | |
236 | #define MIDI_RPN_PITCH_BEND_SENSITIVITY 0 |
237 | #define MIDI_RPN_CHANNEL_FINE_TUNING 1 |
238 | #define MIDI_RPN_CHANNEL_COARSE_TUNING 2 |
239 | #define MIDI_RPN_TUNING_PROGRAM_CHANGE 3 |
240 | #define MIDI_RPN_TUNING_BANK_SELECT 4 |
241 | #define MIDI_RPN_MODULATION_DEPTH_RANGE 5 |
242 | |
243 | #define MIDI_NOTEOFF 0x80 |
244 | #define MIDI_NOTEON 0x90 |
245 | #define MIDI_KEY_PRESSURE 0xA0 |
246 | #define MIDI_CTL_CHANGE 0xB0 |
247 | #define MIDI_PGM_CHANGE 0xC0 |
248 | #define MIDI_CHN_PRESSURE 0xD0 |
249 | #define MIDI_PITCH_BEND 0xE0 |
250 | #define MIDI_SYSTEM_PREFIX 0xF0 |
251 | |
252 | #define MIDI_IS_STATUS(d) ((d) >= 0x80) |
253 | #define MIDI_IS_COMMON(d) ((d) >= 0xf0) |
254 | |
255 | #define MIDI_SYSEX_START 0xF0 |
256 | #define MIDI_SYSEX_END 0xF7 |
257 | |
258 | #define MIDI_GET_STATUS(d) ((d) & 0xf0) |
259 | #define MIDI_GET_CHAN(d) ((d) & 0x0f) |
260 | |
261 | #define MIDI_HALF_VEL 64 |
262 | |
263 | #define SEQ_LOCAL 0x80 |
264 | #define SEQ_TIMING 0x81 |
265 | #define SEQ_CHN_COMMON 0x92 |
266 | #define SEQ_CHN_VOICE 0x93 |
267 | #define SEQ_SYSEX 0x94 |
268 | #define SEQ_FULLSIZE 0xfd |
269 | |
270 | #define SEQ_MK_CHN_VOICE(e, unit, cmd, chan, key, vel) (\ |
271 | (e)->arr[0] = SEQ_CHN_VOICE, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\ |
272 | (e)->arr[3] = (chan), (e)->arr[4] = (key), (e)->arr[5] = (vel),\ |
273 | (e)->arr[6] = 0, (e)->arr[7] = 0) |
274 | #define SEQ_MK_CHN_COMMON(e, unit, cmd, chan, p1, p2, w14) (\ |
275 | (e)->arr[0] = SEQ_CHN_COMMON, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\ |
276 | (e)->arr[3] = (chan), (e)->arr[4] = (p1), (e)->arr[5] = (p2),\ |
277 | *(short*)&(e)->arr[6] = (w14)) |
278 | |
279 | #if _BYTE_ORDER == _BIG_ENDIAN |
280 | /* big endian */ |
281 | #define SEQ_PATCHKEY(id) (0xfd00|id) |
282 | #else |
283 | /* little endian */ |
284 | #define SEQ_PATCHKEY(id) ((id<<8)|0xfd) |
285 | #endif |
286 | struct sysex_info { |
287 | uint16_t key; /* Use SYSEX_PATCH or MAUI_PATCH here */ |
288 | #define SEQ_SYSEX_PATCH SEQ_PATCHKEY(0x05) |
289 | #define SEQ_MAUI_PATCH SEQ_PATCHKEY(0x06) |
290 | int16_t device_no; /* Synthesizer number */ |
291 | int32_t len; /* Size of the sysex data in bytes */ |
292 | u_char data[1]; /* Sysex data starts here */ |
293 | }; |
294 | #define SEQ_SYSEX_HDRSIZE ((u_long)((struct sysex_info *)0)->data) |
295 | |
296 | typedef unsigned char sbi_instr_data[32]; |
297 | struct sbi_instrument { |
298 | uint16_t key; /* FM_PATCH or OPL3_PATCH */ |
299 | #define SBI_FM_PATCH SEQ_PATCHKEY(0x01) |
300 | #define SBI_OPL3_PATCH SEQ_PATCHKEY(0x03) |
301 | int16_t device; |
302 | int32_t channel; |
303 | sbi_instr_data operators; |
304 | }; |
305 | |
306 | #define TMR_RESET 0 /* beware: not an OSS event */ |
307 | #define TMR_WAIT_REL 1 /* Time relative to the prev time */ |
308 | #define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ |
309 | #define TMR_STOP 3 |
310 | #define TMR_START 4 |
311 | #define TMR_CONTINUE 5 |
312 | #define TMR_TEMPO 6 |
313 | #define TMR_ECHO 8 |
314 | #define TMR_CLOCK 9 /* MIDI clock */ |
315 | #define TMR_SPP 10 /* Song position pointer */ |
316 | #define TMR_TIMESIG 11 /* Time signature */ |
317 | |
318 | /* Old sequencer definitions */ |
319 | #define SEQOLD_CMDSIZE 4 |
320 | |
321 | #define SEQOLD_NOTEOFF 0 |
322 | #define SEQOLD_NOTEON 1 |
323 | #define SEQOLD_WAIT TMR_WAIT_ABS |
324 | #define SEQOLD_PGMCHANGE 3 |
325 | #define SEQOLD_SYNCTIMER TMR_START |
326 | #define SEQOLD_MIDIPUTC 5 |
327 | #define SEQOLD_ECHO TMR_ECHO |
328 | #define SEQOLD_AFTERTOUCH 9 |
329 | #define SEQOLD_CONTROLLER 10 |
330 | #define SEQOLD_PRIVATE 0xfe |
331 | #define SEQOLD_EXTENDED 0xff |
332 | |
333 | /* |
334 | * The 'midipitch' data type, used in the kernel between the midisyn layer and |
335 | * onboard synth drivers, and in userland as parameters to the MIDI Tuning Spec |
336 | * (RP-012) universal-system-exclusive messages. It is a MIDI key number shifted |
337 | * left to accommodate 14 bit sub-semitone resolution. In this representation, |
338 | * tuning and bending adjustments are simple addition and subtraction. |
339 | */ |
340 | typedef int32_t midipitch_t; |
341 | |
342 | /* |
343 | * Nominal conversions between midipitches and key numbers. (Beware that these |
344 | * are the nominal, standard correspondences, but whole point of the MIDI Tuning |
345 | * Spec is that you can set things up so the hardware might render key N at |
346 | * actual pitch MIDIPITCH_FROM_KEY(N)+c for some correction c.) |
347 | */ |
348 | #define MIDIPITCH_FROM_KEY(k) ((k)<<14) |
349 | #define MIDIPITCH_TO_KEY(mp) (((mp)+(1<<13))>>14) |
350 | |
351 | #define MIDIPITCH_MAX (MIDIPITCH_FROM_KEY(128)-2) /* ...(128)-1 is reserved */ |
352 | #define MIDIPITCH_OCTAVE 196608 |
353 | #define MIDIPITCH_SEMITONE 16384 |
354 | #define MIDIPITCH_CENT 164 /* this, regrettably, is inexact. */ |
355 | |
356 | /* |
357 | * For rendering, convert a midipitch (after all tuning adjustments) to Hz. |
358 | * The conversion is DEFINED as MIDI key 69.00000 (A) === 440 Hz equal tempered |
359 | * always. Alternate tunings are obtained by adjusting midipitches. |
360 | * |
361 | * The midihz18_t (Hz shifted left for 18-bit sub-Hz resolution) covers the |
362 | * full midipitch range without losing 21-bit precision, as the lowest midipitch |
363 | * is ~8 Hz (~3 bits left of radix point, 18 right) and for the highest the |
364 | * result still fits in a uint32. |
365 | */ |
366 | typedef uint32_t midihz18_t; |
367 | |
368 | #define MIDIHZ18_TO_HZ(h18) ((h18)>>18) /* truncates! ok for dbg msgs maybe */ |
369 | |
370 | #ifndef _KERNEL |
371 | /* |
372 | * With floating point in userland, can also manipulate midipitches as |
373 | * floating-point fractional MIDI key numbers (tuning adjustments are still |
374 | * additive), and hz18 as fractional Hz (adjustments don't add in this form). |
375 | */ |
376 | #include <math.h> |
377 | #define MIDIPITCH_TO_FRKEY(mp) (scalbn((mp),-14)) |
378 | #define MIDIPITCH_FROM_FRKEY(frk) ((midipitch_t)round(scalbn((frk),14))) |
379 | #define MIDIHZ18_TO_FRHZ(h18) (scalbn((h18),-18)) |
380 | #define MIDIHZ18_FROM_FRHZ(frh) ((midihz18_t)round(scalbn((frh),18))) |
381 | |
382 | #define MIDIPITCH_TO_FRHZ(mp) (440*pow(2,(MIDIPITCH_TO_FRKEY((mp))-69)/12)) |
383 | #define MIDIPITCH_FROM_FRHZ(fhz) \ |
384 | MIDIPITCH_FROM_FRKEY(69+12*log((fhz)/440)/log(2)) |
385 | #define MIDIPITCH_TO_HZ18(mp) MIDIHZ18_FROM_FRHZ(MIDIPITCH_TO_FRHZ((mp))) |
386 | #define MIDIPITCH_FROM_HZ18(h18) MIDIPITCH_FROM_FRHZ(MIDIHZ18_TO_FRHZ((h18))) |
387 | |
388 | #else /* no fp in kernel; only an accurate to-hz18 conversion is implemented */ |
389 | |
390 | extern midihz18_t midisyn_mp2hz18(midipitch_t); |
391 | #define MIDIPITCH_TO_HZ18(mp) (midisyn_mp2hz18((mp))) |
392 | |
393 | #endif /* _KERNEL */ |
394 | |
395 | |
396 | /* |
397 | * A native API for the /dev/music sequencer device follows. The event |
398 | * structures are OSS events at the level of bytes, but for developing or |
399 | * porting applications some macros and documentation are needed to generate |
400 | * and dissect the events; here they are. For porting existing OSS applications, |
401 | * sys/soundcard.h can be extended to supply the usual OSS macros, defining them |
402 | * in terms of these. |
403 | */ |
404 | |
405 | /* |
406 | * TODO: determine OSS compatible structures for TMR_RESET and TMR_CLOCK, |
407 | * OSS values of EV_SYSTEM, SNDCTL_SEQ_ACTSENSE_ENABLE, |
408 | * SNDCTL_SEQ_TIMING_ENABLE, and SNDCTL_SEQ_RT_ENABLE. |
409 | * (TMR_RESET may be a NetBSD extension: it is generated in sequencer.c and |
410 | * has no args. To be corrected if a different definition is found anywhere.) |
411 | */ |
412 | typedef union { |
413 | |
414 | #define _EVT_HDR \ |
415 | uint8_t tag |
416 | |
417 | _EVT_HDR; |
418 | |
419 | #define _LOCAL_HDR \ |
420 | _EVT_HDR; \ |
421 | uint8_t op |
422 | |
423 | struct { _LOCAL_HDR; } local; |
424 | |
425 | struct { |
426 | _LOCAL_HDR; |
427 | uint16_t _zero; |
428 | uint32_t devmask; |
429 | } l_startaudio; |
430 | |
431 | /* define a constructor for local evts - someday when we support any */ |
432 | |
433 | #define _TIMING_HDR \ |
434 | _LOCAL_HDR; \ |
435 | uint16_t _zeroh |
436 | struct { _TIMING_HDR; } timing; |
437 | |
438 | struct { |
439 | _TIMING_HDR; |
440 | uint32_t divisions; |
441 | } t_WAIT_REL, t_WAIT_ABS; |
442 | |
443 | struct { |
444 | _TIMING_HDR; |
445 | uint32_t _zero; |
446 | } t_STOP, t_START, t_CONTINUE, t_RESET; |
447 | |
448 | struct { |
449 | _TIMING_HDR; |
450 | uint32_t bpm; /* unambiguously, (MIDI clocks/minute)/24 */ |
451 | } t_TEMPO; |
452 | |
453 | struct { |
454 | _TIMING_HDR; |
455 | uint32_t cookie; |
456 | } t_ECHO; |
457 | |
458 | struct { |
459 | _TIMING_HDR; |
460 | uint32_t midibeat; /* in low 14 bits; midibeat: 6 MIDI clocks */ |
461 | } t_SPP; |
462 | |
463 | struct { |
464 | _TIMING_HDR; |
465 | #if _BYTE_ORDER == _BIG_ENDIAN |
466 | uint8_t numerator; |
467 | uint8_t lg2denom; |
468 | uint8_t clks_per_click; |
469 | uint8_t dsq_per_24clks; |
470 | #elif _BYTE_ORDER == _LITTLE_ENDIAN |
471 | uint8_t dsq_per_24clks; |
472 | uint8_t clks_per_click; |
473 | uint8_t lg2denom; |
474 | uint8_t numerator; |
475 | #else |
476 | #error "unexpected _BYTE_ORDER" |
477 | #endif |
478 | } t_TIMESIG; |
479 | |
480 | struct { /* use this only to implement OSS compatibility macro */ |
481 | _TIMING_HDR; |
482 | uint32_t signature; |
483 | } t_osscompat_timesig; |
484 | |
485 | |
486 | #define _COMMON_HDR \ |
487 | _EVT_HDR; \ |
488 | uint8_t device; \ |
489 | uint8_t op; \ |
490 | uint8_t channel |
491 | |
492 | struct { _COMMON_HDR; } common; |
493 | |
494 | struct { |
495 | _COMMON_HDR; |
496 | uint8_t controller; |
497 | uint8_t _zero; |
498 | uint16_t value; |
499 | } c_CTL_CHANGE; |
500 | |
501 | struct { |
502 | _COMMON_HDR; |
503 | uint8_t program; |
504 | uint8_t _zero0; |
505 | uint16_t _zero1; |
506 | } c_PGM_CHANGE; |
507 | |
508 | struct { |
509 | _COMMON_HDR; |
510 | uint8_t pressure; |
511 | uint8_t _zero0; |
512 | uint16_t _zero1; |
513 | } c_CHN_PRESSURE; |
514 | |
515 | struct { |
516 | _COMMON_HDR; |
517 | uint8_t _zero0; |
518 | uint8_t _zero1; |
519 | uint16_t value; |
520 | } c_PITCH_BEND; |
521 | |
522 | #define _VOICE_HDR \ |
523 | _COMMON_HDR; \ |
524 | uint8_t key |
525 | |
526 | struct { _VOICE_HDR; } voice; |
527 | |
528 | struct { |
529 | _VOICE_HDR; |
530 | uint8_t velocity; |
531 | uint16_t _zero; |
532 | } c_NOTEOFF, c_NOTEON; |
533 | |
534 | struct { |
535 | _VOICE_HDR; |
536 | uint8_t pressure; |
537 | uint16_t _zero; |
538 | } c_KEY_PRESSURE; |
539 | |
540 | struct { |
541 | _EVT_HDR; |
542 | uint8_t device; |
543 | uint8_t buffer[6]; |
544 | } sysex; |
545 | |
546 | struct { |
547 | _EVT_HDR; |
548 | uint8_t device; |
549 | uint8_t status; |
550 | uint8_t data[2]; |
551 | } system; |
552 | |
553 | struct { |
554 | _EVT_HDR; |
555 | uint8_t byte; |
556 | uint8_t device; |
557 | uint8_t _zero0; |
558 | uint32_t _zero1; |
559 | } putc; /* a seqold event that's still needed at times, ugly as 'tis */ |
560 | |
561 | struct { |
562 | _EVT_HDR; |
563 | uint8_t byte[7]; |
564 | } unknown; /* for debug/display */ |
565 | |
566 | #undef _VOICE_HDR |
567 | #undef _COMMON_HDR |
568 | #undef _TIMING_HDR |
569 | #undef _LOCAL_HDR |
570 | #undef _EVT_HDR |
571 | |
572 | } __packed seq_event_t; |
573 | |
574 | #define _SEQ_TAG_NOTEOFF SEQ_CHN_VOICE |
575 | #define _SEQ_TAG_NOTEON SEQ_CHN_VOICE |
576 | #define _SEQ_TAG_KEY_PRESSURE SEQ_CHN_VOICE |
577 | |
578 | #define _SEQ_TAG_CTL_CHANGE SEQ_CHN_COMMON |
579 | #define _SEQ_TAG_PGM_CHANGE SEQ_CHN_COMMON |
580 | #define _SEQ_TAG_CHN_PRESSURE SEQ_CHN_COMMON |
581 | #define _SEQ_TAG_PITCH_BEND SEQ_CHN_COMMON |
582 | |
583 | #if __STDC_VERSION__ >= 199901L |
584 | |
585 | #define SEQ_MK_EVENT(_member,_tag,...) \ |
586 | (seq_event_t){ ._member = { .tag = (_tag), __VA_ARGS__ } } |
587 | |
588 | #define SEQ_MK_TIMING(_op,...) \ |
589 | SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, __VA_ARGS__) |
590 | |
591 | #define SEQ_MK_CHN(_op,...) \ |
592 | SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, __VA_ARGS__) |
593 | |
594 | #define SEQ_MK_SYSEX(_dev,...) \ |
595 | SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), \ |
596 | .buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, __VA_ARGS__}) |
597 | |
598 | #else /* assume gcc 2.95.3 */ |
599 | |
600 | #define SEQ_MK_EVENT(_member,_tag,_args...) \ |
601 | (seq_event_t){ ._member = { .tag = (_tag), _args } } |
602 | |
603 | #define SEQ_MK_TIMING(_op,_args...) \ |
604 | SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, _args) |
605 | |
606 | #define SEQ_MK_CHN(_op,_args...) \ |
607 | SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, _args) |
608 | |
609 | #define SEQ_MK_SYSEX(_dev,_args...) \ |
610 | SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), \ |
611 | .buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, _args}) |
612 | |
613 | #endif /* c99 vs. gcc 2.95.3 */ |
614 | |
615 | #if 0 |
616 | #include <fcntl.h> |
617 | #include <stdio.h> |
618 | int |
619 | main(int argc, char **argv) |
620 | { |
621 | int i; |
622 | int fd; |
623 | seq_event_t e; |
624 | |
625 | /* simple usage example (add a buffer to reduce syscall overhead) */ |
626 | fd = open("/dev/music" , O_RDWR); |
627 | write(fd, &SEQ_MK_TIMING(START), sizeof (seq_event_t)); |
628 | |
629 | read(fd, &e, sizeof e); |
630 | switch ( e.tag ) { |
631 | case SEQ_CHN_VOICE: |
632 | switch ( e.voice.op ) { |
633 | case MIDI_NOTEON: |
634 | printf("Note on, dev=%d chn=%d key=%d vel=%d\n" , |
635 | e.c_NOTEON.device, e.c_NOTEON.channel, |
636 | e.c_NOTEON.key, e.c_NOTEON.velocity); |
637 | } |
638 | } |
639 | |
640 | /* all the macros: */ |
641 | e = SEQ_MK_TIMING(START); |
642 | e = SEQ_MK_TIMING(STOP); |
643 | e = SEQ_MK_TIMING(CONTINUE); |
644 | /* |
645 | * Wait until the specified number of divisions from the timer start |
646 | * (abs) or the preceding event (rel). The number of divisions to a |
647 | * beat or to a MIDI clock is determined by the timebase (set by |
648 | * ioctl). The tempo is expressed in beats per minute, where a beat |
649 | * is always 24 MIDI clocks (and usually equated to a quarter note, |
650 | * but that can be changed with timesig)--that is, tempo is |
651 | * (MIDI clocks per minute)/24. The timebase is the number of divisions |
652 | * in a beat--that is, the number of divisions that make up 24 MIDI |
653 | * clocks--so the timebase is 24*(divisions per MIDI clock). The MThd |
654 | * header in a SMF gives the 'natural' timebase for the file; if the |
655 | * timebase is set accordingly, then the delay values appearing in the |
656 | * tracks are in terms of divisions, and can be used as WAIT_REL |
657 | * arguments without modification. |
658 | */ |
659 | e = SEQ_MK_TIMING(WAIT_ABS, .divisions=192); |
660 | e = SEQ_MK_TIMING(WAIT_REL, .divisions=192); |
661 | /* |
662 | * The 'beat' in bpm is 24 MIDI clocks (usually a quarter note but |
663 | * changeable with timesig). |
664 | */ |
665 | e = SEQ_MK_TIMING(TEMPO, .bpm=84); |
666 | /* |
667 | * An ECHO event on output appears on input at the appointed time; the |
668 | * cookie can be anything of interest to the application. Can be used |
669 | * in schemes to get some control over latency. |
670 | */ |
671 | e = SEQ_MK_TIMING(ECHO, .cookie=0xfeedface); |
672 | /* |
673 | * A midibeat is smaller than a beat. It is six MIDI clocks, or a fourth |
674 | * of a beat, or a sixteenth note if the beat is a quarter. SPP is a |
675 | * request to position at the requested midibeat from the start of the |
676 | * sequence. [sequencer does not at present implement SPP] |
677 | */ |
678 | e = SEQ_MK_TIMING(SPP, .midibeat=128); |
679 | /* |
680 | * numerator and lg2denom describe the time signature as it would |
681 | * appear on a staff, where lg2denom of 0,1,2,3... corresponds to |
682 | * denominator of 1,2,4,8... respectively. So the example below |
683 | * corresponds to 4/4. dsq_per_24clks defines the relationship of |
684 | * MIDI clocks to note values, by specifying the number of |
685 | * demisemiquavers (32nd notes) represented by 24 MIDI clocks. |
686 | * The default is 8 demisemiquavers, or a quarter note. |
687 | * clks_per_click can configure a metronome (for example, the MPU401 |
688 | * had such a feature in intelligent mode) to click every so many |
689 | * MIDI clocks. The 24 in this example would give a click every quarter |
690 | * note. [sequencer does not at present implement TIMESIG] |
691 | */ |
692 | e = SEQ_MK_TIMING(TIMESIG, .numerator=4, .lg2denom=2, |
693 | .clks_per_click=24, .dsq_per_24clks=8); |
694 | /* |
695 | * This example declares 6/8 time where the beat (24 clocks) is the |
696 | * eighth note, but the metronome clicks every dotted quarter (twice |
697 | * per measure): |
698 | */ |
699 | e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3, |
700 | .clks_per_click=72, .dsq_per_24clks=4); |
701 | /* |
702 | * An alternate declaration for 6/8 where the beat (24 clocks) is now |
703 | * the dotted quarter and corresponds to the metronome click: |
704 | */ |
705 | e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3, |
706 | .clks_per_click=24, .dsq_per_24clks=12); |
707 | /* |
708 | * It would also be possible to keep the default correspondence of |
709 | * 24 clocks to the quarter note (8 dsq), and still click the metronome |
710 | * each dotted quarter: |
711 | */ |
712 | e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3, |
713 | .clks_per_click=36, .dsq_per_24clks=8); |
714 | |
715 | e = SEQ_MK_CHN(NOTEON, .device=1, .channel=0, .key=60, .velocity=64); |
716 | e = SEQ_MK_CHN(NOTEOFF, .device=1, .channel=0, .key=60, .velocity=64); |
717 | e = SEQ_MK_CHN(KEY_PRESSURE, .device=1, .channel=0, .key=60, |
718 | .pressure=64); |
719 | |
720 | /* |
721 | * sequencer does not at present implement CTL_CHANGE well. The API |
722 | * provides for a 14-bit value where you give the controller index |
723 | * of the controller MSB and sequencer will split the 14-bit value to |
724 | * the controller MSB and LSB for you--but it doesn't; it ignores the |
725 | * high bits of value and writes the low bits whether you have specified |
726 | * MSB or LSB. That would not be hard to fix but for the fact that OSS |
727 | * itself seems to suffer from the same mixup (and its behavior differs |
728 | * with whether the underlying device is an onboard synth or a MIDI |
729 | * link!) so there is surely a lot of code that relies on it being |
730 | * broken :(. |
731 | * (Note: as the OSS developers have ceased development of the |
732 | * /dev/music API as of OSS4, it would be possible given a complete |
733 | * list of the events defined in OSS4 to add some new ones for native |
734 | * use without fear of future conflict, such as a better ctl_change.) |
735 | */ |
736 | e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0, |
737 | .controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192);/*XX*/ |
738 | /* |
739 | * The way you really have to do it: |
740 | */ |
741 | e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0, |
742 | .controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192>>7); |
743 | e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0, |
744 | .controller=MIDI_CTRL_EXPRESSION_LSB, .value=8192&0x7f); |
745 | |
746 | e = SEQ_MK_CHN(PGM_CHANGE, .device=1, .channel=0, .program=51); |
747 | e = SEQ_MK_CHN(CHN_PRESSURE, .device=1, .channel=0, .pressure=64); |
748 | e = SEQ_MK_CHN(PITCH_BEND, .device=1, .channel=0, .value=8192); |
749 | |
750 | /* |
751 | * A SYSEX event carries up to six bytes of a system exclusive message. |
752 | * The first such message must begin with MIDI_SYSEX_START (0xf0), the |
753 | * last must end with MIDI_SYSEX_END (0xf7), and only the last may carry |
754 | * fewer than 6 bytes. To supply message bytes in the macro, you must |
755 | * prefix the first with [0]= as shown. The macro's first argument is |
756 | * the device. |
757 | */ |
758 | e = SEQ_MK_SYSEX(1,[0]=MIDI_SYSEX_START,1,2,MIDI_SYSEX_END); |
759 | /* |
760 | * In some cases it may be easier to use the macro only to initialize |
761 | * the event, and fill in the message bytes later. The code that fills |
762 | * in the message does not need to store 0xff following the SYSEX_END. |
763 | */ |
764 | e = SEQ_MK_SYSEX(1); |
765 | for ( i = 0; i < 3; ++ i ) |
766 | e.sysex.buffer[i] = i; |
767 | /* |
768 | * It would be nice to think the old /dev/sequencer MIDIPUTC event |
769 | * obsolete, but it is still needed (absent any better API) by any MIDI |
770 | * file player that will implement the ESCAPED events that may occur in |
771 | * SMF. Sorry. Here's how to use it: |
772 | */ |
773 | e = SEQ_MK_EVENT(putc, SEQOLD_MIDIPUTC, .device=1, .byte=42); |
774 | |
775 | printf("confirm event size: %d (should be 8)\n" , sizeof (seq_event_t)); |
776 | return 0; |
777 | } |
778 | #endif /* 0 */ |
779 | |
780 | #endif /* !_SYS_MIDIIO_H_ */ |
781 | |