1 /*****************************************************************************
2 * fluidsynth.c: Software MIDI synthesizer using libfluidsynth
3 *****************************************************************************
4 * Copyright © 2007 Rémi Denis-Courmont
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_codec.h>
28 #include <vlc_dialog.h>
31 #if defined( _POSIX_VERSION ) && !defined(__ANDROID__)
35 /* On Win32, we link statically */
37 # define FLUIDSYNTH_NOT_A_DLL
40 #ifndef HAVE_FLUIDLITE_H
41 #include <fluidsynth.h>
43 #include <fluidlite.h>
46 #define SOUNDFONT_TEXT N_("SoundFont file")
47 #define SOUNDFONT_LONGTEXT N_( \
48 "SoundFont file to use for software synthesis." )
50 #define CHORUS_TEXT N_("Chorus")
52 #define GAIN_TEXT N_("Synthesis gain")
53 #define GAIN_LONGTEXT N_("This gain is applied to synthesis output. " \
54 "High values may cause saturation when many notes are played at a time." )
56 #define POLYPHONY_TEXT N_("Polyphony")
57 #define POLYPHONY_LONGTEXT N_( \
58 "The polyphony defines how many voices can be played at a time. " \
59 "Larger values require more processing power.")
61 #define REVERB_TEXT N_("Reverb")
63 #define SAMPLE_RATE_TEXT N_("Sample rate")
65 static int Open (vlc_object_t
*);
66 static void Close (vlc_object_t
*);
69 set_description (N_("FluidSynth MIDI synthesizer"))
70 set_capability ("audio decoder", 100)
71 set_shortname (N_("FluidSynth"))
72 set_category (CAT_INPUT
)
73 set_subcategory (SUBCAT_INPUT_ACODEC
)
74 set_callbacks (Open
, Close
)
75 add_loadfile("soundfont", "", SOUNDFONT_TEXT
, SOUNDFONT_LONGTEXT
)
76 add_bool ("synth-chorus", true, CHORUS_TEXT
, CHORUS_TEXT
, false)
77 add_float ("synth-gain", .5, GAIN_TEXT
, GAIN_LONGTEXT
, false)
78 change_float_range (0., 10.)
79 add_integer ("synth-polyphony", 256,
80 POLYPHONY_TEXT
, POLYPHONY_LONGTEXT
, false)
81 change_integer_range (1, 65535)
82 add_bool ("synth-reverb", true, REVERB_TEXT
, REVERB_TEXT
, true)
83 add_integer ("synth-sample-rate", 44100,
84 SAMPLE_RATE_TEXT
, SAMPLE_RATE_TEXT
, true)
85 change_integer_range (22050, 96000)
91 fluid_settings_t
*settings
;
98 static int DecodeBlock (decoder_t
*p_dec
, block_t
*p_block
);
99 static void Flush (decoder_t
*);
101 static int Open (vlc_object_t
*p_this
)
103 decoder_t
*p_dec
= (decoder_t
*)p_this
;
105 if (p_dec
->fmt_in
.i_codec
!= VLC_CODEC_MIDI
)
108 decoder_sys_t
*p_sys
= malloc (sizeof (*p_sys
));
109 if (unlikely(p_sys
== NULL
))
112 p_sys
->settings
= new_fluid_settings ();
113 p_sys
->synth
= new_fluid_synth (p_sys
->settings
);
114 p_sys
->soundfont
= -1;
116 char *font_path
= var_InheritString (p_this
, "soundfont");
117 if (font_path
!= NULL
)
119 msg_Dbg (p_this
, "loading sound fonts file %s", font_path
);
120 p_sys
->soundfont
= fluid_synth_sfload (p_sys
->synth
, font_path
, 1);
121 if (p_sys
->soundfont
== -1)
122 msg_Err (p_this
, "cannot load sound fonts file %s", font_path
);
125 #if defined( _POSIX_VERSION ) && !defined(__ANDROID__)
130 glob("/usr/share/sounds/sf2/*.sf2", GLOB_NOESCAPE
, NULL
, &gl
);
131 glob("/usr/share/soundfonts/*.sf2", GLOB_NOESCAPE
| GLOB_APPEND
, NULL
,
134 for (size_t i
= 0; i
< gl
.gl_pathc
; i
++)
136 const char *path
= gl
.gl_pathv
[i
];
138 msg_Dbg (p_this
, "loading sound fonts file %s", path
);
139 p_sys
->soundfont
= fluid_synth_sfload (p_sys
->synth
, path
, 1);
140 if (p_sys
->soundfont
!= -1)
141 break; /* it worked! */
142 msg_Err (p_this
, "cannot load sound fonts file %s", path
);
148 if (p_sys
->soundfont
== -1)
150 msg_Err (p_this
, "sound font file required for synthesis");
151 vlc_dialog_display_error (p_this
, _("MIDI synthesis not set up"),
152 _("A sound font file (.SF2) is required for MIDI synthesis.\n"
153 "Please install a sound font and configure it "
154 "from the VLC preferences "
155 "(Input / Codecs > Audio codecs > FluidSynth).\n"));
156 delete_fluid_synth (p_sys
->synth
);
157 delete_fluid_settings (p_sys
->settings
);
162 fluid_synth_set_chorus_on (p_sys
->synth
,
163 var_InheritBool (p_this
, "synth-chorus"));
164 fluid_synth_set_gain (p_sys
->synth
,
165 var_InheritFloat (p_this
, "synth-gain"));
166 fluid_synth_set_polyphony (p_sys
->synth
,
167 var_InheritInteger (p_this
, "synth-polyphony"));
168 fluid_synth_set_reverb_on (p_sys
->synth
,
169 var_InheritBool (p_this
, "synth-reverb"));
171 p_dec
->fmt_out
.audio
.i_rate
=
172 var_InheritInteger (p_this
, "synth-sample-rate");;
173 fluid_synth_set_sample_rate (p_sys
->synth
, p_dec
->fmt_out
.audio
.i_rate
);
174 p_dec
->fmt_out
.audio
.i_channels
= 2;
175 p_dec
->fmt_out
.audio
.i_physical_channels
= AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
;
176 p_dec
->fmt_out
.i_codec
= VLC_CODEC_FL32
;
177 p_dec
->fmt_out
.audio
.i_bitspersample
= 32;
178 date_Init (&p_sys
->end_date
, p_dec
->fmt_out
.audio
.i_rate
, 1);
180 p_dec
->p_sys
= p_sys
;
181 p_dec
->pf_decode
= DecodeBlock
;
182 p_dec
->pf_flush
= Flush
;
187 static void Close (vlc_object_t
*p_this
)
189 decoder_sys_t
*p_sys
= ((decoder_t
*)p_this
)->p_sys
;
191 fluid_synth_sfunload (p_sys
->synth
, p_sys
->soundfont
, 1);
192 delete_fluid_synth (p_sys
->synth
);
193 delete_fluid_settings (p_sys
->settings
);
197 static void Flush (decoder_t
*p_dec
)
199 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
201 date_Set (&p_sys
->end_date
, VLC_TICK_INVALID
);
202 //fluid_synth_system_reset (p_sys->synth);
203 fluid_synth_program_reset (p_sys
->synth
);
204 for (unsigned channel
= 0; channel
< 16; channel
++)
205 for (unsigned note
= 0; note
< 128; note
++)
206 fluid_synth_noteoff (p_sys
->synth
, channel
, note
);
209 static int DecodeBlock (decoder_t
*p_dec
, block_t
*p_block
)
211 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
212 block_t
*p_out
= NULL
;
214 if (p_block
== NULL
) /* No Drain */
215 return VLCDEC_SUCCESS
;
217 if (p_block
->i_flags
& (BLOCK_FLAG_DISCONTINUITY
|BLOCK_FLAG_CORRUPTED
))
220 if (p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
222 block_Release(p_block
);
223 return VLCDEC_SUCCESS
;
227 if (p_block
->i_pts
!= VLC_TICK_INVALID
228 && date_Get(&p_sys
->end_date
) == VLC_TICK_INVALID
)
229 date_Set (&p_sys
->end_date
, p_block
->i_pts
);
231 if (p_block
->i_pts
< date_Get (&p_sys
->end_date
))
233 msg_Warn (p_dec
, "MIDI message in the past?");
237 if (p_block
->i_buffer
< 1)
240 uint8_t event
= p_block
->p_buffer
[0];
241 uint8_t channel
= p_block
->p_buffer
[0] & 0xf;
248 if (p_block
->p_buffer
[p_block
->i_buffer
- 1] != 0xF7)
251 msg_Warn (p_dec
, "fragmented SysEx not implemented");
254 fluid_synth_sysex (p_sys
->synth
, (char *)p_block
->p_buffer
+ 1,
255 p_block
->i_buffer
- 2, NULL
, NULL
, NULL
, 0);
258 fluid_synth_system_reset (p_sys
->synth
);
262 uint8_t p1
= (p_block
->i_buffer
> 1) ? (p_block
->p_buffer
[1] & 0x7f) : 0;
263 uint8_t p2
= (p_block
->i_buffer
> 2) ? (p_block
->p_buffer
[2] & 0x7f) : 0;
265 switch (event
& 0xF0)
268 fluid_synth_noteoff (p_sys
->synth
, channel
, p1
);
271 fluid_synth_noteon (p_sys
->synth
, channel
, p1
, p2
);
273 #if (FLUIDSYNTH_VERSION_MAJOR >= 2)
275 fluid_synth_key_pressure (p_sys
->synth
, channel
, p1
, p2
);
279 fluid_synth_cc (p_sys
->synth
, channel
, p1
, p2
);
282 fluid_synth_program_change (p_sys
->synth
, channel
, p1
);
285 fluid_synth_channel_pressure (p_sys
->synth
, channel
, p1
);
288 fluid_synth_pitch_bend (p_sys
->synth
, channel
, (p2
<< 7) | p1
);
293 (p_block
->i_pts
- date_Get (&p_sys
->end_date
)) * 441 / 10000;
297 if (decoder_UpdateAudioFormat (p_dec
))
299 p_out
= decoder_NewAudioBuffer (p_dec
, samples
);
303 p_out
->i_pts
= date_Get (&p_sys
->end_date
);
304 p_out
->i_length
= date_Increment (&p_sys
->end_date
, samples
)
306 fluid_synth_write_float (p_sys
->synth
, samples
, p_out
->p_buffer
, 0, 2,
307 p_out
->p_buffer
, 1, 2);
309 block_Release (p_block
);
311 decoder_QueueAudio (p_dec
, p_out
);
312 return VLCDEC_SUCCESS
;