#ifndef _SYS_MIDIIO_H_
#define _SYS_MIDIIO_H_
#include <machine/endian_machdep.h>
#include <sys/ioccom.h>
typedef struct {
unsigned char cmd;
char nr_args, nr_returns;
unsigned char data[30];
} mpu_command_rec;
#define MIDI_PRETIME _IOWR('m', 0, int)
#define MIDI_MPUMODE _IOWR('m', 1, int)
#define MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec)
#define MIDI_ACK 0xfe
#define SEQUENCER_RESET _IO ('Q', 0)
#define SEQUENCER_SYNC _IO ('Q', 1)
#define SEQUENCER_INFO _IOWR('Q', 2, struct synth_info)
#define SEQUENCER_CTRLRATE _IOWR('Q', 3, int)
#define SEQUENCER_GETOUTCOUNT _IOR ('Q', 4, int)
#define SEQUENCER_GETINCOUNT _IOR ('Q', 5, int)
#define SEQUENCER_RESETSAMPLES _IOW ('Q', 9, int)
#define SEQUENCER_NRSYNTHS _IOR ('Q',10, int)
#define SEQUENCER_NRMIDIS _IOR ('Q',11, int)
#define SEQUENCER_THRESHOLD _IOW ('Q',13, int)
#define SEQUENCER_MEMAVL _IOWR('Q',14, int)
#define SEQUENCER_PANIC _IO ('Q',17)
#define SEQUENCER_OUTOFBAND _IOW ('Q',18, struct seq_event_rec)
#define SEQUENCER_GETTIME _IOR ('Q',19, int)
#if 0
typedef struct synth_control {
int devno;
char data[4000];
} synth_control;
typedef struct remove_sample {
int devno;
int bankno;
int instrno;
} remove_sample;
#endif
#define CMDSIZE 8
typedef struct seq_event_rec {
u_char arr[CMDSIZE];
} seq_event_rec;
struct synth_info {
char name[30];
int device;
int synth_type;
#define SYNTH_TYPE_FM 0
#define SYNTH_TYPE_SAMPLE 1
#define SYNTH_TYPE_MIDI 2
int synth_subtype;
#define SYNTH_SUB_FM_TYPE_ADLIB 0x00
#define SYNTH_SUB_FM_TYPE_OPL3 0x01
#define SYNTH_SUB_MIDI_TYPE_MPU401 0x401
#define SYNTH_SUB_SAMPLE_TYPE_BASIC 0x10
#define SYNTH_SUB_SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC
int nr_voices;
int instr_bank_size;
u_int capabilities;
#define SYNTH_CAP_OPL3 0x00000002
#define SYNTH_CAP_INPUT 0x00000004
};
#define SEQUENCER_TMR_TIMEBASE _IOWR('T', 1, int)
#define SEQUENCER_TMR_START _IO ('T', 2)
#define SEQUENCER_TMR_STOP _IO ('T', 3)
#define SEQUENCER_TMR_CONTINUE _IO ('T', 4)
#define SEQUENCER_TMR_TEMPO _IOWR('T', 5, int)
#define SEQUENCER_TMR_SOURCE _IOWR('T', 6, int)
# define SEQUENCER_TMR_INTERNAL 0x00000001
#if 0
# define SEQUENCER_TMR_EXTERNAL 0x00000002
# define SEQUENCER_TMR_MODE_MIDI 0x00000010
# define SEQUENCER_TMR_MODE_FSK 0x00000020
# define SEQUENCER_TMR_MODE_CLS 0x00000040
# define SEQUENCER_TMR_MODE_SMPTE 0x00000080
#endif
#define SEQUENCER_TMR_METRONOME _IOW ('T', 7, int)
#define SEQUENCER_TMR_SELECT _IOW ('T', 8, int)
#define MIDI_CTRL_BANK_SELECT_MSB 0
#define MIDI_CTRL_MODULATION_MSB 1
#define MIDI_CTRL_BREATH_MSB 2
#define MIDI_CTRL_FOOT_MSB 4
#define MIDI_CTRL_PORTAMENTO_TIME_MSB 5
#define MIDI_CTRL_DATA_ENTRY_MSB 6
#define MIDI_CTRL_CHANNEL_VOLUME_MSB 7
#define MIDI_CTRL_BALANCE_MSB 8
#define MIDI_CTRL_PAN_MSB 10
#define MIDI_CTRL_EXPRESSION_MSB 11
#define MIDI_CTRL_EFFECT_1_MSB 12
#define MIDI_CTRL_EFFECT_2_MSB 13
#define MIDI_CTRL_GENERAL_PURPOSE_1_MSB 16
#define MIDI_CTRL_GENERAL_PURPOSE_2_MSB 17
#define MIDI_CTRL_GENERAL_PURPOSE_3_MSB 18
#define MIDI_CTRL_GENERAL_PURPOSE_4_MSB 19
#define MIDI_CTRL_BANK_SELECT_LSB 32
#define MIDI_CTRL_MODULATION_LSB 33
#define MIDI_CTRL_BREATH_LSB 34
#define MIDI_CTRL_FOOT_LSB 36
#define MIDI_CTRL_PORTAMENTO_TIME_LSB 37
#define MIDI_CTRL_DATA_ENTRY_LSB 38
#define MIDI_CTRL_CHANNEL_VOLUME_LSB 39
#define MIDI_CTRL_BALANCE_LSB 40
#define MIDI_CTRL_PAN_LSB 42
#define MIDI_CTRL_EXPRESSION_LSB 43
#define MIDI_CTRL_EFFECT_1_LSB 44
#define MIDI_CTRL_EFFECT_2_LSB 45
#define MIDI_CTRL_GENERAL_PURPOSE_1_LSB 48
#define MIDI_CTRL_GENERAL_PURPOSE_2_LSB 49
#define MIDI_CTRL_GENERAL_PURPOSE_3_LSB 50
#define MIDI_CTRL_GENERAL_PURPOSE_4_LSB 51
#define MIDI_CTRL_HOLD_1 64
#define MIDI_CTRL_PORTAMENTO 65
#define MIDI_CTRL_SOSTENUTO 66
#define MIDI_CTRL_SOFT_PEDAL 67
#define MIDI_CTRL_LEGATO 68
#define MIDI_CTRL_HOLD_2 69
#define MIDI_CTRL_SOUND_VARIATION 70
#define MIDI_CTRL_HARMONIC_INTENSITY 71
#define MIDI_CTRL_RELEASE_TIME 72
#define MIDI_CTRL_ATTACK_TIME 73
#define MIDI_CTRL_BRIGHTNESS 74
#define MIDI_CTRL_DECAY_TIME 75
#define MIDI_CTRL_VIBRATO_RATE 76
#define MIDI_CTRL_VIBRATO_DEPTH 77
#define MIDI_CTRL_VIBRATO_DELAY 78
#define MIDI_CTRL_VIBRATO_DECAY MIDI_CTRL_VIBRATO_DELAY
#define MIDI_CTRL_SOUND_10 79
#define MIDI_CTRL_GENERAL_PURPOSE_5 80
#define MIDI_CTRL_GENERAL_PURPOSE_6 81
#define MIDI_CTRL_GENERAL_PURPOSE_7 82
#define MIDI_CTRL_GENERAL_PURPOSE_8 83
#define MIDI_CTRL_PORTAMENTO_CONTROL 84
#define MIDI_CTRL_EFFECT_DEPTH_1 91
#define MIDI_CTRL_EFFECT_DEPTH_2 92
#define MIDI_CTRL_EFFECT_DEPTH_3 93
#define MIDI_CTRL_EFFECT_DEPTH_4 94
#define MIDI_CTRL_EFFECT_DEPTH_5 95
#define MIDI_CTRL_RPN_INCREMENT 96
#define MIDI_CTRL_RPN_DECREMENT 97
#define MIDI_CTRL_NRPN_LSB 98
#define MIDI_CTRL_NRPN_MSB 99
#define MIDI_CTRL_RPN_LSB 100
#define MIDI_CTRL_RPN_MSB 101
#define MIDI_CTRL_SOUND_OFF 120
#define MIDI_CTRL_RESET 121
#define MIDI_CTRL_LOCAL 122
#define MIDI_CTRL_NOTES_OFF 123
#define MIDI_CTRL_ALLOFF MIDI_CTRL_NOTES_OFF
#define MIDI_CTRL_OMNI_OFF 124
#define MIDI_CTRL_OMNI_ON 125
#define MIDI_CTRL_POLY_OFF 126
#define MIDI_CTRL_POLY_ON 127
#define MIDI_BEND_NEUTRAL (1<<13)
#define MIDI_RPN_PITCH_BEND_SENSITIVITY 0
#define MIDI_RPN_CHANNEL_FINE_TUNING 1
#define MIDI_RPN_CHANNEL_COARSE_TUNING 2
#define MIDI_RPN_TUNING_PROGRAM_CHANGE 3
#define MIDI_RPN_TUNING_BANK_SELECT 4
#define MIDI_RPN_MODULATION_DEPTH_RANGE 5
#define MIDI_NOTEOFF 0x80
#define MIDI_NOTEON 0x90
#define MIDI_KEY_PRESSURE 0xA0
#define MIDI_CTL_CHANGE 0xB0
#define MIDI_PGM_CHANGE 0xC0
#define MIDI_CHN_PRESSURE 0xD0
#define MIDI_PITCH_BEND 0xE0
#define MIDI_SYSTEM_PREFIX 0xF0
#define MIDI_IS_STATUS(d) ((d) >= 0x80)
#define MIDI_IS_COMMON(d) ((d) >= 0xf0)
#define MIDI_SYSEX_START 0xF0
#define MIDI_SYSEX_END 0xF7
#define MIDI_GET_STATUS(d) ((d) & 0xf0)
#define MIDI_GET_CHAN(d) ((d) & 0x0f)
#define MIDI_HALF_VEL 64
#define SEQ_LOCAL 0x80
#define SEQ_TIMING 0x81
#define SEQ_CHN_COMMON 0x92
#define SEQ_CHN_VOICE 0x93
#define SEQ_SYSEX 0x94
#define SEQ_FULLSIZE 0xfd
#define SEQ_MK_CHN_VOICE(e, unit, cmd, chan, key, vel) (\
(e)->arr[0] = SEQ_CHN_VOICE, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
(e)->arr[3] = (chan), (e)->arr[4] = (key), (e)->arr[5] = (vel),\
(e)->arr[6] = 0, (e)->arr[7] = 0)
#define SEQ_MK_CHN_COMMON(e, unit, cmd, chan, p1, p2, w14) (\
(e)->arr[0] = SEQ_CHN_COMMON, (e)->arr[1] = (unit), (e)->arr[2] = (cmd),\
(e)->arr[3] = (chan), (e)->arr[4] = (p1), (e)->arr[5] = (p2),\
*(short*)&(e)->arr[6] = (w14))
#if _BYTE_ORDER == _BIG_ENDIAN
#define SEQ_PATCHKEY(id) (0xfd00|id)
#else
#define SEQ_PATCHKEY(id) ((id<<8)|0xfd)
#endif
struct sysex_info {
uint16_t key;
#define SEQ_SYSEX_PATCH SEQ_PATCHKEY(0x05)
#define SEQ_MAUI_PATCH SEQ_PATCHKEY(0x06)
int16_t device_no;
int32_t len;
u_char data[1];
};
#define SEQ_SYSEX_HDRSIZE ((u_long)((struct sysex_info *)0)->data)
typedef unsigned char sbi_instr_data[32];
struct sbi_instrument {
uint16_t key;
#define SBI_FM_PATCH SEQ_PATCHKEY(0x01)
#define SBI_OPL3_PATCH SEQ_PATCHKEY(0x03)
int16_t device;
int32_t channel;
sbi_instr_data operators;
};
#define TMR_RESET 0
#define TMR_WAIT_REL 1
#define TMR_WAIT_ABS 2
#define TMR_STOP 3
#define TMR_START 4
#define TMR_CONTINUE 5
#define TMR_TEMPO 6
#define TMR_ECHO 8
#define TMR_CLOCK 9
#define TMR_SPP 10
#define TMR_TIMESIG 11
#define SEQOLD_CMDSIZE 4
#define SEQOLD_NOTEOFF 0
#define SEQOLD_NOTEON 1
#define SEQOLD_WAIT TMR_WAIT_ABS
#define SEQOLD_PGMCHANGE 3
#define SEQOLD_SYNCTIMER TMR_START
#define SEQOLD_MIDIPUTC 5
#define SEQOLD_ECHO TMR_ECHO
#define SEQOLD_AFTERTOUCH 9
#define SEQOLD_CONTROLLER 10
#define SEQOLD_PRIVATE 0xfe
#define SEQOLD_EXTENDED 0xff
typedef int32_t midipitch_t;
#define MIDIPITCH_FROM_KEY(k) ((k)<<14)
#define MIDIPITCH_TO_KEY(mp) (((mp)+(1<<13))>>14)
#define MIDIPITCH_MAX (MIDIPITCH_FROM_KEY(128)-2)
#define MIDIPITCH_OCTAVE 196608
#define MIDIPITCH_SEMITONE 16384
#define MIDIPITCH_CENT 164
typedef uint32_t midihz18_t;
#define MIDIHZ18_TO_HZ(h18) ((h18)>>18)
#ifndef _KERNEL
#include <math.h>
#define MIDIPITCH_TO_FRKEY(mp) (scalbn((mp),-14))
#define MIDIPITCH_FROM_FRKEY(frk) ((midipitch_t)round(scalbn((frk),14)))
#define MIDIHZ18_TO_FRHZ(h18) (scalbn((h18),-18))
#define MIDIHZ18_FROM_FRHZ(frh) ((midihz18_t)round(scalbn((frh),18)))
#define MIDIPITCH_TO_FRHZ(mp) (440*pow(2,(MIDIPITCH_TO_FRKEY((mp))-69)/12))
#define MIDIPITCH_FROM_FRHZ(fhz) \
MIDIPITCH_FROM_FRKEY(69+12*log((fhz)/440)/log(2))
#define MIDIPITCH_TO_HZ18(mp) MIDIHZ18_FROM_FRHZ(MIDIPITCH_TO_FRHZ((mp)))
#define MIDIPITCH_FROM_HZ18(h18) MIDIPITCH_FROM_FRHZ(MIDIHZ18_TO_FRHZ((h18)))
#else
extern midihz18_t midisyn_mp2hz18(midipitch_t);
#define MIDIPITCH_TO_HZ18(mp) (midisyn_mp2hz18((mp)))
#endif
typedef union {
#define _EVT_HDR \
uint8_t tag
_EVT_HDR;
#define _LOCAL_HDR \
_EVT_HDR; \
uint8_t op
struct { _LOCAL_HDR; } local;
struct {
_LOCAL_HDR;
uint16_t _zero;
uint32_t devmask;
} l_startaudio;
#define _TIMING_HDR \
_LOCAL_HDR; \
uint16_t _zeroh
struct { _TIMING_HDR; } timing;
struct {
_TIMING_HDR;
uint32_t divisions;
} t_WAIT_REL, t_WAIT_ABS;
struct {
_TIMING_HDR;
uint32_t _zero;
} t_STOP, t_START, t_CONTINUE, t_RESET;
struct {
_TIMING_HDR;
uint32_t bpm;
} t_TEMPO;
struct {
_TIMING_HDR;
uint32_t cookie;
} t_ECHO;
struct {
_TIMING_HDR;
uint32_t midibeat;
} t_SPP;
struct {
_TIMING_HDR;
#if _BYTE_ORDER == _BIG_ENDIAN
uint8_t numerator;
uint8_t lg2denom;
uint8_t clks_per_click;
uint8_t dsq_per_24clks;
#elif _BYTE_ORDER == _LITTLE_ENDIAN
uint8_t dsq_per_24clks;
uint8_t clks_per_click;
uint8_t lg2denom;
uint8_t numerator;
#else
#error "unexpected _BYTE_ORDER"
#endif
} t_TIMESIG;
struct {
_TIMING_HDR;
uint32_t signature;
} t_osscompat_timesig;
#define _COMMON_HDR \
_EVT_HDR; \
uint8_t device; \
uint8_t op; \
uint8_t channel
struct { _COMMON_HDR; } common;
struct {
_COMMON_HDR;
uint8_t controller;
uint8_t _zero;
uint16_t value;
} c_CTL_CHANGE;
struct {
_COMMON_HDR;
uint8_t program;
uint8_t _zero0;
uint16_t _zero1;
} c_PGM_CHANGE;
struct {
_COMMON_HDR;
uint8_t pressure;
uint8_t _zero0;
uint16_t _zero1;
} c_CHN_PRESSURE;
struct {
_COMMON_HDR;
uint8_t _zero0;
uint8_t _zero1;
uint16_t value;
} c_PITCH_BEND;
#define _VOICE_HDR \
_COMMON_HDR; \
uint8_t key
struct { _VOICE_HDR; } voice;
struct {
_VOICE_HDR;
uint8_t velocity;
uint16_t _zero;
} c_NOTEOFF, c_NOTEON;
struct {
_VOICE_HDR;
uint8_t pressure;
uint16_t _zero;
} c_KEY_PRESSURE;
struct {
_EVT_HDR;
uint8_t device;
uint8_t buffer[6];
} sysex;
struct {
_EVT_HDR;
uint8_t device;
uint8_t status;
uint8_t data[2];
} system;
struct {
_EVT_HDR;
uint8_t byte;
uint8_t device;
uint8_t _zero0;
uint32_t _zero1;
} putc;
struct {
_EVT_HDR;
uint8_t byte[7];
} unknown;
#undef _VOICE_HDR
#undef _COMMON_HDR
#undef _TIMING_HDR
#undef _LOCAL_HDR
#undef _EVT_HDR
} __packed seq_event_t;
#define _SEQ_TAG_NOTEOFF SEQ_CHN_VOICE
#define _SEQ_TAG_NOTEON SEQ_CHN_VOICE
#define _SEQ_TAG_KEY_PRESSURE SEQ_CHN_VOICE
#define _SEQ_TAG_CTL_CHANGE SEQ_CHN_COMMON
#define _SEQ_TAG_PGM_CHANGE SEQ_CHN_COMMON
#define _SEQ_TAG_CHN_PRESSURE SEQ_CHN_COMMON
#define _SEQ_TAG_PITCH_BEND SEQ_CHN_COMMON
#if __STDC_VERSION__ >= 199901L
#define SEQ_MK_EVENT(_member,_tag,...) \
(seq_event_t){ ._member = { .tag = (_tag), __VA_ARGS__ } }
#define SEQ_MK_TIMING(_op,...) \
SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, __VA_ARGS__)
#define SEQ_MK_CHN(_op,...) \
SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, __VA_ARGS__)
#define SEQ_MK_SYSEX(_dev,...) \
SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), \
.buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, __VA_ARGS__})
#else
#define SEQ_MK_EVENT(_member,_tag,_args...) \
(seq_event_t){ ._member = { .tag = (_tag), _args } }
#define SEQ_MK_TIMING(_op,_args...) \
SEQ_MK_EVENT(t_##_op, SEQ_TIMING, .op = TMR_##_op, _args)
#define SEQ_MK_CHN(_op,_args...) \
SEQ_MK_EVENT(c_##_op, _SEQ_TAG_##_op, .op = MIDI_##_op, _args)
#define SEQ_MK_SYSEX(_dev,_args...) \
SEQ_MK_EVENT(sysex, 0x94, .device=(_dev), \
.buffer={0xff, 0xff, 0xff, 0xff, 0xff, 0xff, _args})
#endif
#if 0
#include <fcntl.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
int i;
int fd;
seq_event_t e;
fd = open("/dev/music", O_RDWR);
write(fd, &SEQ_MK_TIMING(START), sizeof (seq_event_t));
read(fd, &e, sizeof e);
switch ( e.tag ) {
case SEQ_CHN_VOICE:
switch ( e.voice.op ) {
case MIDI_NOTEON:
printf("Note on, dev=%d chn=%d key=%d vel=%d\n",
e.c_NOTEON.device, e.c_NOTEON.channel,
e.c_NOTEON.key, e.c_NOTEON.velocity);
}
}
e = SEQ_MK_TIMING(START);
e = SEQ_MK_TIMING(STOP);
e = SEQ_MK_TIMING(CONTINUE);
e = SEQ_MK_TIMING(WAIT_ABS, .divisions=192);
e = SEQ_MK_TIMING(WAIT_REL, .divisions=192);
e = SEQ_MK_TIMING(TEMPO, .bpm=84);
e = SEQ_MK_TIMING(ECHO, .cookie=0xfeedface);
e = SEQ_MK_TIMING(SPP, .midibeat=128);
e = SEQ_MK_TIMING(TIMESIG, .numerator=4, .lg2denom=2,
.clks_per_click=24, .dsq_per_24clks=8);
e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
.clks_per_click=72, .dsq_per_24clks=4);
e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
.clks_per_click=24, .dsq_per_24clks=12);
e = SEQ_MK_TIMING(TIMESIG, .numerator=6, .lg2denom=3,
.clks_per_click=36, .dsq_per_24clks=8);
e = SEQ_MK_CHN(NOTEON, .device=1, .channel=0, .key=60, .velocity=64);
e = SEQ_MK_CHN(NOTEOFF, .device=1, .channel=0, .key=60, .velocity=64);
e = SEQ_MK_CHN(KEY_PRESSURE, .device=1, .channel=0, .key=60,
.pressure=64);
e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
.controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192);
e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
.controller=MIDI_CTRL_EXPRESSION_MSB, .value=8192>>7);
e = SEQ_MK_CHN(CTL_CHANGE, .device=1, .channel=0,
.controller=MIDI_CTRL_EXPRESSION_LSB, .value=8192&0x7f);
e = SEQ_MK_CHN(PGM_CHANGE, .device=1, .channel=0, .program=51);
e = SEQ_MK_CHN(CHN_PRESSURE, .device=1, .channel=0, .pressure=64);
e = SEQ_MK_CHN(PITCH_BEND, .device=1, .channel=0, .value=8192);
e = SEQ_MK_SYSEX(1,[0]=MIDI_SYSEX_START,1,2,MIDI_SYSEX_END);
e = SEQ_MK_SYSEX(1);
for ( i = 0; i < 3; ++ i )
e.sysex.buffer[i] = i;
e = SEQ_MK_EVENT(putc, SEQOLD_MIDIPUTC, .device=1, .byte=42);
printf("confirm event size: %d (should be 8)\n", sizeof (seq_event_t));
return 0;
}
#endif
#endif