[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
karaoke_player.c
Description: Text Data
fluid.patch
Description: Text Data