[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [fluid-dev] Some questions about Midi playback
From: |
Sebastien Frippiat |
Subject: |
Re: [fluid-dev] Some questions about Midi playback |
Date: |
Thu, 29 Jun 2006 14:05:29 +0200 |
User-agent: |
Mozilla Thunderbird 1.0.7-1.4.1 (X11/20050929) |
Hi.
It's me... again :-)
Support for a Midi event callback function has been improved (now uses
specified user data) and a new function (fluid_player_is_playing) has
been added to return wheter the player is currently playing a Midi file
or not.
You'll find the patch file attached to this message. Intructions are the
same as in my previous message.
Regards,
Sebastien
diff -r -u fluidsynth-1.0.7/include/fluidsynth/midi.h
fluidsynth-1.0.7-new/include/fluidsynth/midi.h
--- fluidsynth-1.0.7/include/fluidsynth/midi.h Tue Mar 11 17:57:01 2003
+++ fluidsynth-1.0.7-new/include/fluidsynth/midi.h Thu Jun 29 10:35:04 2006
@@ -47,7 +47,6 @@
FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t* evt);
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int
val);
-
/* Generic callback function for MIDI events.
* Will be used between
* - MIDI driver and MIDI router
@@ -126,6 +125,63 @@
FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t* player, int loop);
FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t* player, int
tempo);
FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t* player, int bpm);
+
+
+/** \brief Set a multiplier value to be applied to all tempo events
+ *
+ * \param player Pointer to player to be modified
+ * \param multiplier Multiplier to be applied :
+ * - multiplier in ]0,1] : increase tempo
+ * - multiplier o, ]1,oo] : decrease tempo
+ * \return One of these :
+ * - 0 on success
+ * - -1 if multiplier is <= 0
+ */
+FLUIDSYNTH_API int fluid_player_set_tempo_multiplier(fluid_player_t* player,
float multiplier);
+
+/** \brief Set a multiplier value to be applied to all velocities specified in
NOTE_ON events
+ *
+ * \param player Pointer to player to be modified
+ * \param multiplier Multiplier to be applied, must be in ]0,1] (can only
decrease velocity)
+ * \return One of these :
+ * - 0 on success
+ * - -1 if multiplier is not in ]0,1]
+ */
+FLUIDSYNTH_API int fluid_player_set_velocity_multiplier(fluid_player_t*
player, float multiplier);
+
+/** \brief Set a callback to be called each time a Midi event is generated
+ *
+ * \param player Pointer to player to be modified
+ * \param callback Pointer to callback function
+ * \param data Data to be passed to the callback function
+ * \return Always 0
+ *
+ * The callback function should return 0 if it wants the FluidSynth
synthetizer to play the sound and
+ * it should return -1 if it wants to inhibit the FluidSynth synthetizer. For
example, in the first case,
+ * it can be used as a logger and in the other one it can be used to process
the Midi events by yourself
+ * and send them to a Midi device).
+ *
+ * Here is a sample callback function which inhibits the FluidSynth software
synthetizer and output
+ * Midi events to a Midi device (pMidiOStream is a PortMidi output stream) :
+ * <PRE>
+ int myCallback (void* data, fluid_midi_event_t* event)
+ {
+ Pm_WriteShort(pMidiOStream, 0, Pm_Message(event->type |
event->channel, event->param1, event->param2));
+ return -1;
+ }
+ </PRE>
+ */
+ FLUIDSYNTH_API int fluid_player_set_midi_event_callback(fluid_player_t*
player, handle_midi_event_func_t callback, void* data);
+
+/** \brief Tell if the player is currently playing
+ *
+ * \param player Pointer to player to be checked
+ * \return One of these :
+ * - 1 if the player is currently playing a Midi file
+ * - 0 otherwise
+ */
+FLUIDSYNTH_API int fluid_player_is_playing(fluid_player_t* player);
+
#ifdef __cplusplus
}
Only in fluidsynth-1.0.7-new/include/fluidsynth: mididefs.h
diff -r -u fluidsynth-1.0.7/src/fluid_midi.c
fluidsynth-1.0.7-new/src/fluid_midi.c
--- fluidsynth-1.0.7/src/fluid_midi.c Mon Mar 29 12:05:17 2004
+++ fluidsynth-1.0.7-new/src/fluid_midi.c Thu Jun 29 10:31:58 2006
@@ -1072,6 +1072,14 @@
player->send_program_change = 1;
player->miditempo = 480000;
player->deltatime = 4.0;
+
+ player->tempo_multiplier = 1.0f;
+ player->tempo_last_multiplier = 1.0f;
+ player->tempo_last_value = player->miditempo;
+ player->velocity_multiplier = 1.0f;
+ player->midi_event_callback = NULL;
+ player->midi_event_callback_data = NULL;
+
return player;
}
@@ -1107,9 +1115,46 @@
player->send_program_change = 1;
player->miditempo = 480000;
player->deltatime = 4.0;
+
return 0;
}
+int fluid_player_set_tempo_multiplier(fluid_player_t* player, float multiplier)
+{
+ if (multiplier < 0) {
+ return -1;
+ }
+
+ player->tempo_multiplier = multiplier;
+
+ return 0;
+}
+
+int fluid_player_set_velocity_multiplier(fluid_player_t* player, float
multiplier)
+{
+ if ((multiplier < 0) || (multiplier > 1)) {
+ return -1;
+ }
+
+ player->velocity_multiplier = multiplier;
+
+ return 0;
+}
+
+int fluid_player_set_midi_event_callback(fluid_player_t* player,
handle_midi_event_func_t callback, void* data)
+{
+ player->midi_event_callback = callback;
+ player->midi_event_callback_data = data;
+
+ return 0;
+}
+
+int fluid_player_is_playing(fluid_player_t* player)
+{
+ return (player->status == FLUID_PLAYER_PLAYING);
+}
+
+
/*
* fluid_player_add_track
*/
@@ -1487,37 +1532,77 @@
*/
int fluid_midi_send_event(fluid_synth_t* synth, fluid_player_t* player,
fluid_midi_event_t* event)
{
+ fluid_midi_event_t callbackEvent;
+
+ /* handle tempo multiplier modification */
+ if (player != NULL) {
+ if (player->tempo_last_multiplier != player->tempo_multiplier) {
+ if (player->midi_event_callback != NULL) {
+ memcpy(&callbackEvent, event, sizeof(fluid_midi_event_t));
+ callbackEvent.type = MIDI_SET_TEMPO;
+ callbackEvent.channel = 0;
+ callbackEvent.param1 == player->tempo_last_value *
player->tempo_multiplier;
+ callbackEvent.param2 = 0;
+ player->midi_event_callback(player->midi_event_callback_data,
&callbackEvent);
+ }
+ if (fluid_player_set_midi_tempo(player, player->tempo_last_value *
player->tempo_multiplier) != FLUID_OK) {
+ return FLUID_FAILED;
+ }
+ player->tempo_last_multiplier = player->tempo_multiplier;
+ }
+
+ memcpy(&callbackEvent, event, sizeof(fluid_midi_event_t));
+ }
+
+ /* handle event */
switch (event->type) {
case NOTE_ON:
- if (fluid_synth_noteon(synth, event->channel, event->param1,
event->param2) != FLUID_OK) {
- return FLUID_FAILED;
+ callbackEvent.param2 *= player->velocity_multiplier;
+ if ((player->midi_event_callback != NULL) &&
(player->midi_event_callback(player->midi_event_callback_data, &callbackEvent)
== 0)) {
+ if (fluid_synth_noteon(synth, event->channel, event->param1,
event->param2 * player->velocity_multiplier) != FLUID_OK) {
+ return FLUID_FAILED;
+ }
}
break;
case NOTE_OFF:
- if (fluid_synth_noteoff(synth, event->channel, event->param1)
!= FLUID_OK) {
- return FLUID_FAILED;
+ if ((player->midi_event_callback != NULL) &&
(player->midi_event_callback(player->midi_event_callback_data, &callbackEvent)
== 0)) {
+ if (fluid_synth_noteoff(synth, event->channel, event->param1)
!= FLUID_OK) {
+ return FLUID_FAILED;
+ }
}
break;
case CONTROL_CHANGE:
- if (fluid_synth_cc(synth, event->channel, event->param1,
event->param2) != FLUID_OK) {
- return FLUID_FAILED;
+ if ((player->midi_event_callback != NULL) &&
(player->midi_event_callback(player->midi_event_callback_data, &callbackEvent)
== 0)) {
+ if (fluid_synth_cc(synth, event->channel, event->param1,
event->param2) != FLUID_OK) {
+ return FLUID_FAILED;
+ }
}
break;
case MIDI_SET_TEMPO:
if (player != NULL) {
- if (fluid_player_set_midi_tempo(player, event->param1)
!= FLUID_OK) {
- return FLUID_FAILED;
+ callbackEvent.param1 *= player->tempo_multiplier;
+ if (player->midi_event_callback != NULL) {
+
player->midi_event_callback(player->midi_event_callback_data, &callbackEvent);
+ }
+ if (fluid_player_set_midi_tempo(player, event->param1 *
player->tempo_multiplier) != FLUID_OK) {
+ return FLUID_FAILED;
}
+ player->tempo_last_value = event->param1;
+ player->tempo_last_multiplier =
player->tempo_multiplier;
}
break;
case PROGRAM_CHANGE:
- if (fluid_synth_program_change(synth, event->channel,
event->param1) != FLUID_OK) {
- return FLUID_FAILED;
+ if ((player->midi_event_callback != NULL) &&
(player->midi_event_callback(player->midi_event_callback_data, &callbackEvent)
== 0)) {
+ if (fluid_synth_program_change(synth, event->channel,
event->param1) != FLUID_OK) {
+ return FLUID_FAILED;
+ }
}
break;
case PITCH_BEND:
- if (fluid_synth_pitch_bend(synth, event->channel,
event->param1) != FLUID_OK) {
- return FLUID_FAILED;
+ if ((player->midi_event_callback != NULL) &&
(player->midi_event_callback(player->midi_event_callback_data, &callbackEvent)
== 0)) {
+ if (fluid_synth_pitch_bend(synth, event->channel,
event->param1) != FLUID_OK) {
+ return FLUID_FAILED;
+ }
}
break;
default:
diff -r -u fluidsynth-1.0.7/src/fluid_midi.h
fluidsynth-1.0.7-new/src/fluid_midi.h
--- fluidsynth-1.0.7/src/fluid_midi.h Mon Mar 29 12:05:18 2004
+++ fluidsynth-1.0.7-new/src/fluid_midi.h Mon Jun 26 16:26:32 2006
@@ -251,6 +251,14 @@
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec
per midi-clock. bravo! */
double deltatime; /* milliseconds per midi tick. depends on
set-tempo */
unsigned int division;
+
+ float tempo_multiplier; /* all tempo events will be multiplied by this one
(if > 1, will slow down the play) */
+ float tempo_last_multiplier;
+ float tempo_last_value;
+ float velocity_multiplier;/* all velocities will be multiplied by this one
(must be in ]0,1]) */
+
+ handle_midi_event_func_t midi_event_callback; /* customized function for
handling Midi events */
+ void* midi_event_callback_data; /* data to be passed to
customized function */
};
int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);