/* * fluid_midishare_keyoff_task */ static void fluid_midishare_keyoff_task (long date, short ref, long a1, long a2, long a3) { fluid_midishare_midi_driver_t* dev = (fluid_midishare_midi_driver_t*)MidiGetInfo(ref); fluid_midi_event_t new_event; MidiEvPtr e =(MidiEvPtr)a1; fluid_midi_event_set_type(&new_event, NOTE_OFF); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_pitch(&new_event, Pitch(e)); fluid_midi_event_set_velocity(&new_event, Vel(e)); /* release vel */ /* and send it on its way to the router */ (*dev->driver.handler)(dev->driver.data, &new_event); MidiFreeEv(e); }
/* * Class: org_tritonus_midi_device_fluidsynth_FluidSynthesizer * Method: nReceive * Signature: (IIII)V */ JNIEXPORT void JNICALL Java_org_tritonus_midi_device_fluidsynth_FluidSynthesizer_nReceive (JNIEnv *env, jobject obj, jint command, jint channel, jint data1, jint data2) { fluid_midi_event_t* event; fluid_synth_t* synth = get_synth(env, obj); #ifdef VARIADIC_MACROS out("nReceive: synth: %p, values: %x %d %d %d\n", synth, (int) command, (int) channel, (int) data1, (int) data2); #else if (debug_flag) { fprintf(debug_file, "synth: %p, values: %x %d %d %d\n", synth, (int) command, (int) channel, (int) data1, (int) data2); fflush(debug_file); } #endif if (synth) { event = new_fluid_midi_event(); if (!event) { printf("failed to instantiate fluid_midi_event_t\n"); return; } //printf("2"); fflush(stdout); fluid_midi_event_set_type(event, command); fluid_midi_event_set_channel(event, channel); fluid_midi_event_set_key(event, data1); fluid_midi_event_set_velocity(event, data2); //printf("3"); fflush(stdout); /*printf("values2: %d %d %d %d\n", fluid_midi_event_get_type(event), fluid_midi_event_get_channel(event), fluid_midi_event_get_key(event), fluid_midi_event_get_velocity(event)); fflush(stdout); */ fluid_synth_handle_midi_event(synth, event); //printf("4"); fflush(stdout); delete_fluid_midi_event(event); //printf("5\n"); fflush(stdout); } }
/** * Handle a MIDI event through a MIDI router instance. * @param data MIDI router instance #fluid_midi_router_t, its a void * so that * this function can be used as a callback for other subsystems * (new_fluid_midi_driver() for example). * @param event MIDI event to handle * @return #FLUID_OK on success, #FLUID_FAILED otherwise * * Purpose: The midi router is called for each event, that is received * via the 'physical' midi input. Each event can trigger an arbitrary number * of generated events (one for each rule that matches). * * In default mode, a noteon event is just forwarded to the synth's 'noteon' function, * a 'CC' event to the synth's 'CC' function and so on. * * The router can be used to: * - filter messages (for example: Pass sustain pedal CCs only to selected channels) * - split the keyboard (noteon with notenr < x: to ch 1, >x to ch 2) * - layer sounds (for each noteon received on ch 1, create a noteon on ch1, ch2, ch3,...) * - velocity scaling (for each noteon event, scale the velocity by 1.27 to give DX7 users * a chance) * - velocity switching ("v <=100: Angel Choir; V > 100: Hell's Bells") * - get rid of aftertouch * - ... */ int fluid_midi_router_handle_midi_event (void* data, fluid_midi_event_t* event) { fluid_midi_router_t* router = (fluid_midi_router_t *)data; fluid_midi_router_rule_t **rulep, *rule, *next_rule, *prev_rule = NULL; int event_has_par2 = 0; /* Flag, indicates that current event needs two parameters */ int par1_max = 127; /* Range limit for par1 */ int par2_max = 127; /* Range limit for par2 */ int ret_val = FLUID_OK; int chan; /* Channel of the generated event */ int par1; /* par1 of the generated event */ int par2; int event_par1; int event_par2; fluid_midi_event_t new_event; /* Some keyboards report noteoff through a noteon event with vel=0. * Convert those to noteoff to ease processing. */ if (event->type == NOTE_ON && event->param2 == 0) { event->type = NOTE_OFF; event->param2 = 127; /* Release velocity */ } fluid_mutex_lock (router->rules_mutex); /* ++ lock rules */ /* Depending on the event type, choose the correct list of rules. */ switch (event->type) { case NOTE_ON: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE]; event_has_par2 = 1; break; case NOTE_OFF: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE]; event_has_par2 = 1; break; case CONTROL_CHANGE: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CC]; event_has_par2 = 1; break; case PROGRAM_CHANGE: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PROG_CHANGE]; break; case PITCH_BEND: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PITCH_BEND]; par1_max = 16383; break; case CHANNEL_PRESSURE: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE]; break; case KEY_PRESSURE: rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE]; event_has_par2 = 1; break; case MIDI_SYSTEM_RESET: case MIDI_SYSEX: ret_val = router->event_handler (router->event_handler_data,event); fluid_mutex_unlock (router->rules_mutex); /* -- unlock rules */ return ret_val; default: rulep = NULL; /* Event will not be passed on */ break; } /* Loop over rules in the list, looking for matches for this event. */ for (rule = rulep ? *rulep : NULL; rule; prev_rule = rule, rule = next_rule) { event_par1 = (int)event->param1; event_par2 = (int)event->param2; next_rule = rule->next; /* Rule may get removed from list, so get next here */ /* Channel window */ if (rule->chan_min > rule->chan_max) { /* Inverted rule: Exclude everything between max and min (but not min/max) */ if (event->channel > rule->chan_max && event->channel < rule->chan_min) continue; } else /* Normal rule: Exclude everything < max or > min (but not min/max) */ { if (event->channel > rule->chan_max || event->channel < rule->chan_min) continue; } /* Par 1 window */ if (rule->par1_min > rule->par1_max) { /* Inverted rule: Exclude everything between max and min (but not min/max) */ if (event_par1 > rule->par1_max && event_par1 < rule->par1_min) continue; } else /* Normal rule: Exclude everything < max or > min (but not min/max)*/ { if (event_par1 > rule->par1_max || event_par1 < rule->par1_min) continue; } /* Par 2 window (only applies to event types, which have 2 pars) * For noteoff events, velocity switching doesn't make any sense. * Velocity scaling might be useful, though. */ if (event_has_par2 && event->type != NOTE_OFF) { if (rule->par2_min > rule->par2_max) { /* Inverted rule: Exclude everything between max and min (but not min/max) */ if (event_par2 > rule->par2_max && event_par2 < rule->par2_min) continue; } else /* Normal rule: Exclude everything < max or > min (but not min/max)*/ { if (event_par2 > rule->par2_max || event_par2 < rule->par2_min) continue; } } /* Channel scaling / offset * Note: rule->chan_mul will probably be 0 or 1. If it's 0, input from all * input channels is mapped to the same synth channel. */ chan = (int)((fluid_real_t)event->channel * (fluid_real_t)rule->chan_mul + (fluid_real_t)rule->chan_add + 0.5); /* Par 1 scaling / offset */ par1 = (int)((fluid_real_t)event_par1 * (fluid_real_t)rule->par1_mul + (fluid_real_t)rule->par1_add + 0.5); /* Par 2 scaling / offset, if applicable */ if (event_has_par2) par2 = (int)((fluid_real_t)event_par2 * (fluid_real_t)rule->par2_mul + (fluid_real_t)rule->par2_add + 0.5); else par2 = 0; /* Channel range limiting */ if (chan < 0) chan = 0; else if (chan >= router->nr_midi_channels) chan = router->nr_midi_channels - 1; /* Par1 range limiting */ if (par1 < 0) par1 = 0; else if (par1 > par1_max) par1 = par1_max; /* Par2 range limiting */ if (event_has_par2) { if (par2 < 0) par2 = 0; else if (par2 > par2_max) par2 = par2_max; } /* At this point we have to create an event of event->type on 'chan' with par1 (maybe par2). * We keep track on the state of noteon and sustain pedal events. If the application tries * to delete a rule, it will only be fully removed, if pending noteoff / pedal off events have * arrived. In the meantime while waiting, it will only let through 'negative' events * (noteoff or pedal up). */ if (event->type == NOTE_ON || (event->type == CONTROL_CHANGE && par1 == SUSTAIN_SWITCH && par2 >= 64)) { /* Noteon or sustain pedal down event generated */ if (rule->keys_cc[par1] == 0) { rule->keys_cc[par1] = 1; rule->pending_events++; } } else if (event->type == NOTE_OFF || (event->type == CONTROL_CHANGE && par1 == SUSTAIN_SWITCH && par2 < 64)) { /* Noteoff or sustain pedal up event generated */ if (rule->keys_cc[par1] > 0) { rule->keys_cc[par1] = 0; rule->pending_events--; /* Rule is waiting for negative event to be destroyed? */ if (rule->waiting) { if (rule->pending_events == 0) { /* Remove rule from rule list */ if (prev_rule) prev_rule->next = next_rule; else *rulep = next_rule; /* Add to free list */ rule->next = router->free_rules; router->free_rules = rule; rule = prev_rule; /* Set rule to previous rule, which gets assigned to the next prev_rule value (in for() statement) */ } goto send_event; /* Pass the event to complete the cycle */ } } } /* Rule is still waiting for negative event? (note off or pedal up) */ if (rule->waiting) continue; /* Skip (rule is inactive except for matching negative event) */ send_event: /* At this point it is decided, what is sent to the synth. * Create a new event and make the appropriate call */ fluid_midi_event_set_type (&new_event, event->type); fluid_midi_event_set_channel (&new_event, chan); new_event.param1 = par1; new_event.param2 = par2; /* FIXME - What should be done on failure? For now continue to process events, but return failure to caller. */ if (router->event_handler (router->event_handler_data, &new_event) != FLUID_OK) ret_val = FLUID_FAILED; } fluid_mutex_unlock (router->rules_mutex); /* -- unlock rules */ return ret_val; }
/* * fluid_midishare_midi_driver_receive */ static void fluid_midishare_midi_driver_receive(short ref) { fluid_midishare_midi_driver_t* dev = (fluid_midishare_midi_driver_t*)MidiGetInfo(ref); fluid_midi_event_t new_event; MidiEvPtr e; int count, i; while ((e = MidiGetEv (ref))) { switch (EvType (e)) { case typeNote: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, NOTE_ON); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_pitch(&new_event, Pitch(e)); fluid_midi_event_set_velocity(&new_event, Vel(e)); /* and send it on its way to the router */ (*dev->driver.handler)(dev->driver.data, &new_event); #if defined(MACINTOSH) && defined(MACOS9) MidiTask(dev->upp_task_ptr, MidiGetTime()+Dur(e), ref, (long)e, 0, 0); #else MidiTask(fluid_midishare_keyoff_task, MidiGetTime()+Dur(e), ref, (long)e, 0, 0); #endif /* e gets freed in fluid_midishare_keyoff_task */ continue; case typeKeyOn: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, NOTE_ON); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_pitch(&new_event, Pitch(e)); fluid_midi_event_set_velocity(&new_event, Vel(e)); break; case typeKeyOff: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, NOTE_OFF); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_pitch(&new_event, Pitch(e)); fluid_midi_event_set_velocity(&new_event, Vel(e)); /* release vel */ break; case typeCtrlChange: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, CONTROL_CHANGE); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_control(&new_event, MidiGetField(e,0)); fluid_midi_event_set_value(&new_event, MidiGetField(e,1)); break; case typeProgChange: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, PROGRAM_CHANGE); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_program(&new_event, MidiGetField(e,0)); break; case typePitchWheel: /* Copy the data to fluid_midi_event_t */ fluid_midi_event_set_type(&new_event, PITCH_BEND); fluid_midi_event_set_channel(&new_event, Chan(e)); fluid_midi_event_set_value(&new_event, ((MidiGetField(e,0) + (MidiGetField(e,1) << 7)) - 8192)); break; case typeSysEx: count = MidiCountFields (e); /* Discard empty or too large SYSEX messages */ if (count == 0 || count > FLUID_MIDI_PARSER_MAX_DATA_SIZE) { MidiFreeEv (e); continue; } /* Copy SYSEX data, one byte at a time */ for (i = 0; i < count; i++) dev->sysexbuf[i] = MidiGetField (e, i); fluid_midi_event_set_sysex (&new_event, dev->sysexbuf, count, FALSE); break; default: MidiFreeEv (e); continue; } MidiFreeEv (e); /* Send the MIDI event */ (*dev->driver.handler)(dev->driver.data, &new_event); } }