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: Jan Newmarch
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 12:24:32 +1100

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

Attachment: karaoke_player.c
Description: Text Data

Attachment: fluid.patch
Description: Text Data


reply via email to

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