Hi Matt, Many thanks for taking the time to look at this and get a 'working patch' for the 104 SVN revision.
I'm hoping that someone can either work out how to add these functions to the re-factored code, or can add something similar to the re-factored code provide and example of how to use those re-factored functions to get a similar result. Kind regards, GrahamG On 1/19/13, Matt Giuca <matt.gi...@gmail.com> wrote: > 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 <j...@newmarch.name> 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 >> > fluid-dev@nongnu.org >> > 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 j.newma...@boxhill.edu.au >> E j...@newmarch.name >> >> _______________________________________________ >> fluid-dev mailing list >> fluid-dev@nongnu.org >> https://lists.nongnu.org/mailman/listinfo/fluid-dev >> >> > _______________________________________________ fluid-dev mailing list fluid-dev@nongnu.org https://lists.nongnu.org/mailman/listinfo/fluid-dev