root / lab4 / .minix-src / include / sys / midiio.h @ 13
History | View | Annotate | Download (25.3 KB)
1 | 13 | up20180614 | /* $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 MIDI_CTRL_FOOT_MSB 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 MIDI_CTRL_FOOT_LSB 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_ */ |