1 /*****************************************************************************
2 * fluidsynth.c: Software MIDI synthetizer using libfluidsynth
3 *****************************************************************************
4 * Copyright © 2007 Rémi Denis-Courmont
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
29 #include <vlc_codec.h>
31 #include <vlc_dialog.h>
32 #include <vlc_charset.h>
34 /* On Win32, we link statically */
36 # define FLUIDSYNTH_NOT_A_DLL
39 #include <fluidsynth.h>
41 #if (FLUIDSYNTH_VERSION_MAJOR < 1) \
42 || (FLUIDSYNTH_VERSION_MAJOR == 1 && FLUIDSYNTH_VERSION_MINOR < 1)
43 # define FLUID_FAILED (-1)
44 # define fluid_synth_sysex(synth, ptr, len, d, e, f, g) (FLUID_FAILED)
45 # define fluid_synth_system_reset(synth) (FLUID_FAILED)
46 # define fluid_synth_channel_pressure(synth, channel, p) (FLUID_FAILED)
49 #define SOUNDFONT_TEXT N_("Sound fonts (required)")
50 #define SOUNDFONT_LONGTEXT N_( \
51 "A sound fonts file is required for software synthesis." )
53 static int Open (vlc_object_t
*);
54 static void Close (vlc_object_t
*);
57 set_description (N_("FluidSynth MIDI synthetizer"))
58 set_capability ("decoder", 100)
59 set_shortname (N_("FluidSynth"))
60 set_category (CAT_INPUT
)
61 set_subcategory (SUBCAT_INPUT_ACODEC
)
62 set_callbacks (Open
, Close
)
63 add_file ("soundfont", "", NULL
,
64 SOUNDFONT_TEXT
, SOUNDFONT_LONGTEXT
, false);
70 fluid_settings_t
*settings
;
78 static aout_buffer_t
*DecodeBlock (decoder_t
*p_dec
, block_t
**pp_block
);
81 static int Open (vlc_object_t
*p_this
)
83 decoder_t
*p_dec
= (decoder_t
*)p_this
;
86 if (p_dec
->fmt_in
.i_codec
!= VLC_CODEC_MIDI
)
89 char *font_path
= var_InheritString (p_this
, "soundfont");
90 if (font_path
== NULL
)
92 msg_Err (p_this
, "sound font file required for synthesis");
93 dialog_Fatal (p_this
, _("MIDI synthesis not set up"),
94 _("A sound font file (.SF2) is required for MIDI synthesis.\n"
95 "Please install a sound font and configure it "
96 "from the VLC preferences (Codecs / Audio / FluidSynth).\n"));
100 p_dec
->pf_decode_audio
= DecodeBlock
;
101 p_sys
= p_dec
->p_sys
= malloc (sizeof (*p_sys
));
108 p_sys
->settings
= new_fluid_settings ();
109 p_sys
->synth
= new_fluid_synth (p_sys
->settings
);
110 /* FIXME: I bet this is not thread-safe */
111 const char *lpath
= ToLocale (font_path
);
112 p_sys
->soundfont
= fluid_synth_sfload (p_sys
->synth
, font_path
, 1);
114 if (p_sys
->soundfont
== -1)
116 msg_Err (p_this
, "cannot load sound fonts file %s", font_path
);
118 dialog_Fatal (p_this
, _("MIDI synthesis not set up"),
119 _("The specified sound font file (%s) is incorrect.\n"
120 "Please install a valid sound font and reconfigure it "
121 "from the VLC preferences (Codecs / Audio / FluidSynth).\n"),
128 p_dec
->fmt_out
.i_cat
= AUDIO_ES
;
129 p_dec
->fmt_out
.audio
.i_rate
= 44100;
130 p_dec
->fmt_out
.audio
.i_channels
= 2;
131 p_dec
->fmt_out
.audio
.i_original_channels
=
132 p_dec
->fmt_out
.audio
.i_physical_channels
=
133 AOUT_CHAN_LEFT
| AOUT_CHAN_RIGHT
;
136 p_dec
->fmt_out
.i_codec
= VLC_CODEC_FL32
;
137 p_dec
->fmt_out
.audio
.i_bitspersample
= 32;
138 p_sys
->fixed
= false;
142 p_dec
->fmt_out
.i_codec
= VLC_CODEC_S16N
;
143 p_dec
->fmt_out
.audio
.i_bitspersample
= 16;
146 date_Init (&p_sys
->end_date
, p_dec
->fmt_out
.audio
.i_rate
, 1);
147 date_Set (&p_sys
->end_date
, 0);
153 static void Close (vlc_object_t
*p_this
)
155 decoder_sys_t
*p_sys
= ((decoder_t
*)p_this
)->p_sys
;
157 if (p_sys
->soundfont
!= -1)
158 fluid_synth_sfunload (p_sys
->synth
, p_sys
->soundfont
, 1);
159 delete_fluid_synth (p_sys
->synth
);
160 delete_fluid_settings (p_sys
->settings
);
165 static aout_buffer_t
*DecodeBlock (decoder_t
*p_dec
, block_t
**pp_block
)
168 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
169 aout_buffer_t
*p_out
= NULL
;
171 if (pp_block
== NULL
)
178 if (p_block
->i_pts
> VLC_TS_INVALID
&& !date_Get (&p_sys
->end_date
))
179 date_Set (&p_sys
->end_date
, p_block
->i_pts
);
181 if (p_block
->i_pts
< date_Get (&p_sys
->end_date
))
183 msg_Warn (p_dec
, "MIDI message in the past?");
187 if (p_block
->i_buffer
< 1)
190 uint8_t event
= p_block
->p_buffer
[0];
191 uint8_t channel
= p_block
->p_buffer
[0] & 0xf;
198 if (p_block
->p_buffer
[p_block
->i_buffer
- 1] != 0xF7)
201 msg_Warn (p_dec
, "fragmented SysEx not implemented");
204 fluid_synth_sysex (p_sys
->synth
, (char *)p_block
->p_buffer
+ 1,
205 p_block
->i_buffer
- 2, NULL
, NULL
, NULL
, 0);
208 fluid_synth_system_reset (p_sys
->synth
);
212 uint8_t p1
= (p_block
->i_buffer
> 1) ? (p_block
->p_buffer
[1] & 0x7f) : 0;
213 uint8_t p2
= (p_block
->i_buffer
> 2) ? (p_block
->p_buffer
[2] & 0x7f) : 0;
215 switch (event
& 0xF0)
218 fluid_synth_noteoff (p_sys
->synth
, channel
, p1
);
221 fluid_synth_noteon (p_sys
->synth
, channel
, p1
, p2
);
223 /*case 0xA0: note aftertouch not implemented */
225 fluid_synth_cc (p_sys
->synth
, channel
, p1
, p2
);
228 fluid_synth_program_change (p_sys
->synth
, channel
, p1
);
231 fluid_synth_channel_pressure (p_sys
->synth
, channel
, p1
);
234 fluid_synth_pitch_bend (p_sys
->synth
, channel
, (p2
<< 7) | p1
);
239 (p_block
->i_pts
- date_Get (&p_sys
->end_date
)) * 441 / 10000;
243 p_out
= decoder_NewAudioBuffer (p_dec
, samples
);
247 p_out
->i_pts
= date_Get (&p_sys
->end_date
);
248 p_out
->i_length
= date_Increment (&p_sys
->end_date
, samples
)
251 fluid_synth_write_float (p_sys
->synth
, samples
,
252 p_out
->p_buffer
, 0, 2,
253 p_out
->p_buffer
, 1, 2);
255 fluid_synth_write_s16 (p_sys
->synth
, samples
,
256 (int16_t *)p_out
->p_buffer
, 0, 2,
257 (int16_t *)p_out
->p_buffer
, 1, 2);
259 block_Release (p_block
);