fluid-dev
[Top][All Lists]
Advanced

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

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


From: Matt Giuca
Subject: Re: [fluid-dev] Would it be possible to add these three functions from a 2006 patch to the latest fluidsynth trunk?
Date: Sat, 19 Jan 2013 13:27:52 +1100

I took a look at this patch (Sebastien's original one, not Jan's). The news isn't good for merging it into the current HEAD. The main part of the patch is about updating a function called fluid_midi_send_event in src/fluid_midi.c (now src/midi/fluid_midi.c). The problem is that that function no longer exists. That has all been refactored and now the MIDI events are processed at file load time in fluid_midi_file_read_event. I haven't done a lot of understanding about how the old and new code relates to one another, and I don't have any more time this weekend to look at it.

If anyone is interested, at least I've made it possible to apply the patch cleanly to the old version of the code. For some reason, Sebastien pasted the patch into an email instead of attaching it, and it was word-wrapped to hell. It also messed up the tabs and spaces so that it cannot be applied by patch. Finally, note that Graham pasted an older version of the patch. Sebastien followed up his email a few days later with a revised patch with more features (http://lists.gnu.org/archive/html/fluid-dev/2006-06/msg00016.html).

So what I am attaching is Sebastien's second patch, with:
- Word wrapping fixed.
- Indentation fixed so it matches the code as it was at the time.
- Other minor formatting blemishes removed.
- The new file he added (mididefs.h) included in the patch itself.

This patch applies cleanly against SVN revision 104 (the latest version at the time he wrote his patch). Of course, it does not apply cleanly against a modern version of FluidSynth, and that's the challenge...


On Sat, Jan 19, 2013 at 12:24 PM, Jan Newmarch <address@hidden> wrote:
I posted a ticket to ask for similar functionality last month, but it
hasn't been picked up so far. It uses the new 1.1.6 filtering mechanism
but adds in Text/Lyric events which are what the posting below seems to
want too.

The ticket runs:

Karaoke files contain Lyric or Text meta-events in addition to the other
MIDI events. Playing such files in a Karaoke system requires that all of
the lyrics are available to the karaoke application at the start of the
song and the Lyric/Text events need to be captured at the time they are
"played". I suggest two changes to make this possible:

a) Add an event handler that is called on completion of file loading:

typedef int (*handle_onload_func_t)(void* data, fluid_player_t* player);

int fluid_player_set_onload_callback(fluid_player_t* player,
                     handle_onload_func_t handler, void* handler_data);

This will expose the player _after_ it has loaded a file so that its
parsed MIDI file data can be examined.

b) Add code to fluid_midi.c to handle Text/Lyric events and send them
from the sequencer to the MIDI synthesizer. NOTE: the default
synthesizer fluid_synth_handle_midi_event() is NOT changed so will
continue to ignore such events. Only if a custom event handler is
installed will these events be seen (see example below).
I have working code for this (including appropriate garbage collection)
and have attached a patch file, against 1.1.6.

An example showing how this could work is attached. It is based on
file_player.c from the API documentation

On Fri, 2013-01-18 at 21:11 +0200, Graham Goode wrote:
> 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 */
>
> _______________________________________________
> fluid-dev mailing list
> address@hidden
> https://lists.nongnu.org/mailman/listinfo/fluid-dev

--
Dr Jan Newmarch
Head of Higher Education (ICT)

P 61 3 9286 9971
M +61 4 0117 0509
F 61 3 9286 9100
W www.boxhill.edu.au
W jan.newmarch.name
E address@hidden
E address@hidden

_______________________________________________
fluid-dev mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/fluid-dev


Attachment: adaptive-fixed.patch
Description: Binary data


reply via email to

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