fluid-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[fluid-dev] Would it be possible to add these three functions from a 200


From: Graham Goode
Subject: [fluid-dev] Would it be possible to add these three functions from a 2006 patch to the latest fluidsynth trunk?
Date: Fri, 18 Jan 2013 21:11:20 +0200

Hi Guys,

I'm looking at doing some PortAudio / Native Jack builds of fluidsynth
for Miditzer (main code from 2006/2007) but their fluidsynth.dll
contains the following patch, which was added in order to use an
in-app MIDI file player.

I have just found this in an archive, so have not even attempted
anything with it yet.

Would anyone else be able to look at it, and what are the chances of
being able to add this to 1.1.7?

Kind regards,
GrahamG


Re: [fluid-dev] Some questions about Midi playback
From:   Sebastien Frippiat
Subject:        Re: [fluid-dev] Some questions about Midi playback
Date:   Mon, 26 Jun 2006 14:27:16 +0200
User-agent:     Mozilla Thunderbird 1.0.7-1.4.1 (X11/20050929)

Hi again !

I finally managed to do what I wanted to do without too much trouble.
I know it is not the main purpose of fluidsynth but as I don't think
of my modifications are a ugly hack, I post my code here. In fact, it
add three functions : - fluid_player_set_tempo_multiplier : multiply
all received tempo by a specified multiplier (useful for accelerating
/ slowing down music playback) - fluid_player_set_velocity_multiplier
: multiply all notes velocities by a specified multiplier (useful for
decreasing volume) - fluid_player_set_midi_event_callback : call a
specified callback function on any Midi event and that function can
specify whether FluidSynth must forward the event to the synthesizer


I wrote the first two functions last week and I posted the code on the
mailing list. For a quick explanation, I needed these functions to be
able to play some sort of adaptive music (like with DirectMusic for
those who know it).


The last one is in fact to redirect the Midi events to a real Midi
device. There seems to be something planned/ (?) in FluidSynth about
routers which would allow to apply filters to Midi events. However,
like said in the docs, it is only used for Midi inputs (and not Midi
file playback). With my modification, if you specify a callback and
tell FluidSynth to forward the event to the synthesizer, you'll be
able to provide feedback to the user of your application (add events
to log, show visual feedback like notes being played...). I personnaly
used it to prevent FluidSynth playing the Midi file and processed the
event myself. It allows me to load a .mid file and to play it without
having to take care of timing as fluidsynth already do it.


Even if it is not the main purpose of this lib, I do think that my
code is quite clean (I also wrote the Doxygen documentation to the
functions) and that it could be useful to some other people. Anyway,
whether you want it or not... here it is, attached to my post.


You need to copy the patch file into the fluidsynth directory and run
"patch -u -i fluidsynth_modifs.patch -p 1". Then copy the mididefs.h
file in the include/fluidsynth.h directory. I had to add it because
the _fluid_midi_event_t was defined in src/fluid_midi.h but not in
include/fluidsynth/midi.h and it was not accessible to users of the
library.


Thanks for your advices,
Sebastien Frippiat

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      Mon Jun 26 12:49:59 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,52 @@
 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
+  * \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);

 #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       Mon Jun 26 12:49:59 2006
@@ -1072,6 +1072,13 @@
        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;
+
        return player;
 }

@@ -1107,9 +1114,39 @@
        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)
+{
+  player->midi_event_callback = callback;
+
+  return 0;
+}
+
 /*
  * fluid_player_add_track
  */
@@ -1487,37 +1524,69 @@
  */
 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 (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(NULL, &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(NULL, &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(NULL, &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(NULL, &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(NULL, &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(NULL, &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 12:49:59 2006
@@ -251,6 +251,13 @@
   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 */
 };

 int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);

/* FluidSynth - A Software Synthesizer
 *
 * Copyright (C) 2003  Peter Hanappe and others.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307, USA
 */

/*
   This file should be included by anyone willing to use a callback function
   to handle Midi events.
*/

#ifndef _FLUIDSYNTH_MIDIDEFS_H
#define _FLUIDSYNTH_MIDIDEFS_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * fluid_midi_event_t
 */
struct _fluid_midi_event_t {
  fluid_midi_event_t* next;  /* Don't use it, it will dissappear. Used in midi
tracks.  */
  unsigned int dtime;       /* Delay (ticks) between this and previous event.
midi tracks. */
  unsigned char type;       /* MIDI event type */
  unsigned char channel;    /* MIDI channel */
  unsigned int param1;      /* First parameter */
  unsigned int param2;      /* Second parameter */
};

#ifdef __cplusplus
}
#endif

#endif /* _FLUIDSYNTH_MIDIDEFS_H */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]