midi_synth.c
来自「linux 内核源代码」· C语言 代码 · 共 715 行 · 第 1/2 页
C
715 行
/* * sound/oss/midi_synth.c * * High level midi sequencer manager for dumb MIDI interfaces. *//* * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. *//* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) * Andrew Veliath : fixed running status in MIDI input state machine */#define USE_SEQ_MACROS#define USE_SIMPLE_MACROS#include "sound_config.h"#define _MIDI_SYNTH_C_#include "midi_synth.h"static int midi2synth[MAX_MIDI_DEV];static int sysex_state[MAX_MIDI_DEV] ={0};static unsigned char prev_out_status[MAX_MIDI_DEV];#define STORE(cmd) \{ \ int len; \ unsigned char obuf[8]; \ cmd; \ seq_input_event(obuf, len); \}#define _seqbuf obuf#define _seqbufptr 0#define _SEQ_ADVBUF(x) len=xvoiddo_midi_msg(int synthno, unsigned char *msg, int mlen){ switch (msg[0] & 0xf0) { case 0x90: if (msg[2] != 0) { STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); break; } msg[2] = 64; case 0x80: STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2])); break; case 0xA0: STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2])); break; case 0xB0: STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, msg[1], msg[2])); break; case 0xC0: STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1])); break; case 0xD0: STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1])); break; case 0xE0: STORE(SEQ_BENDER(synthno, msg[0] & 0x0f, (msg[1] & 0x7f) | ((msg[2] & 0x7f) << 7))); break; default: /* printk( "MPU: Unknown midi channel message %02x\n", msg[0]); */ ; }}EXPORT_SYMBOL(do_midi_msg);static voidmidi_outc(int midi_dev, int data){ int timeout; for (timeout = 0; timeout < 3200; timeout++) if (midi_devs[midi_dev]->outputc(midi_dev, (unsigned char) (data & 0xff))) { if (data & 0x80) /* * Status byte */ prev_out_status[midi_dev] = (unsigned char) (data & 0xff); /* * Store for running status */ return; /* * Mission complete */ } /* * Sorry! No space on buffers. */ printk("Midi send timed out\n");}static intprefix_cmd(int midi_dev, unsigned char status){ if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) return 1; return midi_devs[midi_dev]->prefix_cmd(midi_dev, status);}static voidmidi_synth_input(int orig_dev, unsigned char data){ int dev; struct midi_input_info *inc; static unsigned char len_tab[] = /* # of data bytes following a status */ { 2, /* 8x */ 2, /* 9x */ 2, /* Ax */ 2, /* Bx */ 1, /* Cx */ 1, /* Dx */ 2, /* Ex */ 0 /* Fx */ }; if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) return; if (data == 0xfe) /* Ignore active sensing */ return; dev = midi2synth[orig_dev]; inc = &midi_devs[orig_dev]->in_info; switch (inc->m_state) { case MST_INIT: if (data & 0x80) /* MIDI status byte */ { if ((data & 0xf0) == 0xf0) /* Common message */ { switch (data) { case 0xf0: /* Sysex */ inc->m_state = MST_SYSEX; break; /* Sysex */ case 0xf1: /* MTC quarter frame */ case 0xf3: /* Song select */ inc->m_state = MST_DATA; inc->m_ptr = 1; inc->m_left = 1; inc->m_buf[0] = data; break; case 0xf2: /* Song position pointer */ inc->m_state = MST_DATA; inc->m_ptr = 1; inc->m_left = 2; inc->m_buf[0] = data; break; default: inc->m_buf[0] = data; inc->m_ptr = 1; do_midi_msg(dev, inc->m_buf, inc->m_ptr); inc->m_ptr = 0; inc->m_left = 0; } } else { inc->m_state = MST_DATA; inc->m_ptr = 1; inc->m_left = len_tab[(data >> 4) - 8]; inc->m_buf[0] = inc->m_prev_status = data; } } else if (inc->m_prev_status & 0x80) { /* Data byte (use running status) */ inc->m_ptr = 2; inc->m_buf[1] = data; inc->m_buf[0] = inc->m_prev_status; inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1; if (inc->m_left > 0) inc->m_state = MST_DATA; /* Not done yet */ else { inc->m_state = MST_INIT; do_midi_msg(dev, inc->m_buf, inc->m_ptr); inc->m_ptr = 0; } } break; /* MST_INIT */ case MST_DATA: inc->m_buf[inc->m_ptr++] = data; if (--inc->m_left <= 0) { inc->m_state = MST_INIT; do_midi_msg(dev, inc->m_buf, inc->m_ptr); inc->m_ptr = 0; } break; /* MST_DATA */ case MST_SYSEX: if (data == 0xf7) /* Sysex end */ { inc->m_state = MST_INIT; inc->m_left = 0; inc->m_ptr = 0; } break; /* MST_SYSEX */ default: printk("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, (int) data); inc->m_state = MST_INIT; }}static voidleave_sysex(int dev){ int orig_dev = synth_devs[dev]->midi_dev; int timeout = 0; if (!sysex_state[dev]) return; sysex_state[dev] = 0; while (!midi_devs[orig_dev]->outputc(orig_dev, 0xf7) && timeout < 1000) timeout++; sysex_state[dev] = 0;}static voidmidi_synth_output(int dev){ /* * Currently NOP */}int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg){ /* * int orig_dev = synth_devs[dev]->midi_dev; */ switch (cmd) { case SNDCTL_SYNTH_INFO: if (__copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info))) return -EFAULT; return 0; case SNDCTL_SYNTH_MEMAVL: return 0x7fffffff; default: return -EINVAL; }}EXPORT_SYMBOL(midi_synth_ioctl);intmidi_synth_kill_note(int dev, int channel, int note, int velocity){ int orig_dev = synth_devs[dev]->midi_dev; int msg, chn; if (note < 0 || note > 127) return 0; if (channel < 0 || channel > 15) return 0; if (velocity < 0) velocity = 0; if (velocity > 127) velocity = 127; leave_sysex(dev); msg = prev_out_status[orig_dev] & 0xf0; chn = prev_out_status[orig_dev] & 0x0f; if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) { /* * Use running status */ if (!prefix_cmd(orig_dev, note)) return 0; midi_outc(orig_dev, note); if (msg == 0x90) /* * Running status = Note on */ midi_outc(orig_dev, 0); /* * Note on with velocity 0 == note * off */ else midi_outc(orig_dev, velocity); } else { if (velocity == 64) { if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f))) return 0; midi_outc(orig_dev, 0x90 | (channel & 0x0f)); /* * Note on */ midi_outc(orig_dev, note); midi_outc(orig_dev, 0); /* * Zero G */ } else { if (!prefix_cmd(orig_dev, 0x80 | (channel & 0x0f))) return 0; midi_outc(orig_dev, 0x80 | (channel & 0x0f)); /* * Note off */ midi_outc(orig_dev, note); midi_outc(orig_dev, velocity); } } return 0;}EXPORT_SYMBOL(midi_synth_kill_note);intmidi_synth_set_instr(int dev, int channel, int instr_no){ int orig_dev = synth_devs[dev]->midi_dev; if (instr_no < 0 || instr_no > 127) instr_no = 0; if (channel < 0 || channel > 15) return 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?