📄 seq_midi_emul.c
字号:
ops->control(drv, control, chan); break; }}/* * initialize the MIDI status */voidsnd_midi_channel_set_clear(snd_midi_channel_set_t *chset){ int i; chset->midi_mode = SNDRV_MIDI_MODE_GM; chset->gs_master_volume = 127; for (i = 0; i < chset->max_channels; i++) { snd_midi_channel_t *chan = chset->channels + i; memset(chan->note, 0, sizeof(chan->note)); chan->midi_aftertouch = 0; chan->midi_pressure = 0; chan->midi_program = 0; chan->midi_pitchbend = 0; snd_midi_reset_controllers(chan); chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */ chan->gm_rpn_fine_tuning = 0; chan->gm_rpn_coarse_tuning = 0; if (i == 9) chan->drum_channel = 1; else chan->drum_channel = 0; }}/* * Process a rpn message. */static voidrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset){ int type; int val; if (chset->midi_mode != SNDRV_MIDI_MODE_NONE) { type = (chan->control[MIDI_CTL_REGIST_PARM_NUM_MSB] << 8) | chan->control[MIDI_CTL_REGIST_PARM_NUM_LSB]; val = (chan->control[MIDI_CTL_MSB_DATA_ENTRY] << 7) | chan->control[MIDI_CTL_LSB_DATA_ENTRY]; switch (type) { case 0x0000: /* Pitch bend sensitivity */ /* MSB only / 1 semitone per 128 */ chan->gm_rpn_pitch_bend_range = val; break; case 0x0001: /* fine tuning: */ /* MSB/LSB, 8192=center, 100/8192 cent step */ chan->gm_rpn_fine_tuning = val - 8192; break; case 0x0002: /* coarse tuning */ /* MSB only / 8192=center, 1 semitone per 128 */ chan->gm_rpn_coarse_tuning = val - 8192; break; case 0x7F7F: /* "lock-in" RPN */ /* ignored */ break; } } /* should call nrpn or rpn callback here.. */}/* * Process an nrpn message. */static voidnrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset){ /* parse XG NRPNs here if possible */ if (ops->nrpn) ops->nrpn(drv, chan, chset);}/* * convert channel parameter in GS sysex */static intget_channel(unsigned char cmd){ int p = cmd & 0x0f; if (p == 0) p = 9; else if (p < 10) p--; return p;}/* * Process a sysex message. */static voidsysex(snd_midi_op_t *ops, void *private, unsigned char *buf, int len, snd_midi_channel_set_t *chset){ /* GM on */ static unsigned char gm_on_macro[] = { 0x7e,0x7f,0x09,0x01, }; /* XG on */ static unsigned char xg_on_macro[] = { 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00, }; /* GS prefix * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off * reverb mode: XX=0x01, YY=0x30, ZZ=0-7 * chorus mode: XX=0x01, YY=0x38, ZZ=0-7 * master vol: XX=0x00, YY=0x04, ZZ=0-127 */ static unsigned char gs_pfx_macro[] = { 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/ }; int parsed = SNDRV_MIDI_SYSEX_NOT_PARSED; if (len <= 0 || buf[0] != 0xf0) return; /* skip first byte */ buf++; len--; /* GM on */ if (len >= (int)sizeof(gm_on_macro) && memcmp(buf, gm_on_macro, sizeof(gm_on_macro)) == 0) { if (chset->midi_mode != SNDRV_MIDI_MODE_GS && chset->midi_mode != SNDRV_MIDI_MODE_XG) { chset->midi_mode = SNDRV_MIDI_MODE_GM; reset_all_channels(chset); parsed = SNDRV_MIDI_SYSEX_GM_ON; } } /* GS macros */ else if (len >= 8 && memcmp(buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) { if (chset->midi_mode != SNDRV_MIDI_MODE_GS && chset->midi_mode != SNDRV_MIDI_MODE_XG) chset->midi_mode = SNDRV_MIDI_MODE_GS; if (buf[5] == 0x00 && buf[6] == 0x7f && buf[7] == 0x00) { /* GS reset */ parsed = SNDRV_MIDI_SYSEX_GS_RESET; reset_all_channels(chset); } else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x15) { /* drum pattern */ int p = get_channel(buf[5]); if (p < chset->max_channels) { parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL; if (buf[7]) chset->channels[p].drum_channel = 1; else chset->channels[p].drum_channel = 0; } } else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x21) { /* program */ int p = get_channel(buf[5]); if (p < chset->max_channels && ! chset->channels[p].drum_channel) { parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL; chset->channels[p].midi_program = buf[7]; } } else if (buf[5] == 0x01 && buf[6] == 0x30) { /* reverb mode */ parsed = SNDRV_MIDI_SYSEX_GS_REVERB_MODE; chset->gs_reverb_mode = buf[7]; } else if (buf[5] == 0x01 && buf[6] == 0x38) { /* chorus mode */ parsed = SNDRV_MIDI_SYSEX_GS_CHORUS_MODE; chset->gs_chorus_mode = buf[7]; } else if (buf[5] == 0x00 && buf[6] == 0x04) { /* master volume */ parsed = SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME; chset->gs_master_volume = buf[7]; } } /* XG on */ else if (len >= (int)sizeof(xg_on_macro) && memcmp(buf, xg_on_macro, sizeof(xg_on_macro)) == 0) { int i; chset->midi_mode = SNDRV_MIDI_MODE_XG; parsed = SNDRV_MIDI_SYSEX_XG_ON; /* reset CC#0 for drums */ for (i = 0; i < chset->max_channels; i++) { if (chset->channels[i].drum_channel) chset->channels[i].control[MIDI_CTL_MSB_BANK] = 127; else chset->channels[i].control[MIDI_CTL_MSB_BANK] = 0; } } if (ops->sysex) ops->sysex(private, buf - 1, len + 1, parsed, chset);}/* * all sound off */static voidall_sounds_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan){ int n; if (! ops->note_terminate) return; for (n = 0; n < 128; n++) { if (chan->note[n]) { ops->note_terminate(drv, n, chan); chan->note[n] = 0; } }}/* * all notes off */static voidall_notes_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan){ int n; if (! ops->note_off) return; for (n = 0; n < 128; n++) { if (chan->note[n] == SNDRV_MIDI_NOTE_ON) note_off(ops, drv, chan, n, 0); }}/* * Initialise a single midi channel control block. */static void snd_midi_channel_init(snd_midi_channel_t *p, int n){ if (p == NULL) return; memset(p, 0, sizeof(snd_midi_channel_t)); p->private = NULL; p->number = n; snd_midi_reset_controllers(p); p->gm_rpn_pitch_bend_range = 256; /* 2 semitones */ p->gm_rpn_fine_tuning = 0; p->gm_rpn_coarse_tuning = 0; if (n == 9) p->drum_channel = 1; /* Default ch 10 as drums */}/* * Allocate and initialise a set of midi channel control blocks. */static snd_midi_channel_t *snd_midi_channel_init_set(int n){ snd_midi_channel_t *chan; int i; chan = kmalloc(n * sizeof(snd_midi_channel_t), GFP_KERNEL); if (chan) { for (i = 0; i < n; i++) snd_midi_channel_init(chan+i, i); } return chan;}/* * reset all midi channels */static voidreset_all_channels(snd_midi_channel_set_t *chset){ int ch; for (ch = 0; ch < chset->max_channels; ch++) { snd_midi_channel_t *chan = chset->channels + ch; snd_midi_reset_controllers(chan); chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */ chan->gm_rpn_fine_tuning = 0; chan->gm_rpn_coarse_tuning = 0; if (ch == 9) chan->drum_channel = 1; else chan->drum_channel = 0; }}/* * Allocate and initialise a midi channel set. */snd_midi_channel_set_t *snd_midi_channel_alloc_set(int n){ snd_midi_channel_set_t *chset; chset = kmalloc(sizeof(*chset), GFP_KERNEL); if (chset) { chset->channels = snd_midi_channel_init_set(n); chset->private_data = NULL; chset->max_channels = n; } return chset;}/* * Reset the midi controllers on a particular channel to default values. */static void snd_midi_reset_controllers(snd_midi_channel_t *chan){ memset(chan->control, 0, sizeof(chan->control)); chan->gm_volume = 127; chan->gm_expression = 127; chan->gm_pan = 64;}/* * Free a midi channel set. */void snd_midi_channel_free_set(snd_midi_channel_set_t *chset){ if (chset == NULL) return; kfree(chset->channels); kfree(chset);}static int __init alsa_seq_midi_emul_init(void){ return 0;}static void __exit alsa_seq_midi_emul_exit(void){}module_init(alsa_seq_midi_emul_init)module_exit(alsa_seq_midi_emul_exit)EXPORT_SYMBOL(snd_midi_process_event);EXPORT_SYMBOL(snd_midi_channel_set_clear);EXPORT_SYMBOL(snd_midi_channel_alloc_set);EXPORT_SYMBOL(snd_midi_channel_free_set);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -