1
(*****************************************************************************
3
Liquidsoap, a programmable audio stream generator.
4
Copyright 2003-2011 Savonet team
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 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 General Public License for more details, fully stated in the COPYING
15
file at the root of the liquidsoap distribution.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*****************************************************************************)
27
type t = Float | Int | Bool
29
let log = Log.make ["LADSPA extension"]
33
let venv = Unix.getenv "LIQ_LADSPA" in
34
venv = "1" || venv = "true"
40
let path = Unix.getenv "LIQ_LADSPA_PATH" in
41
Pcre.split ~pat:":" path
43
| Not_found -> ["/usr/lib/ladspa";"/usr/local/lib/ladspa"]
47
if Descriptor.port_is_boolean d p then Bool
48
else if Descriptor.port_is_integer d p then Int
51
class virtual base ~kind source =
53
inherit operator kind [source] as super
55
method stype = source#stype
57
method remaining = source#remaining
59
method is_ready = source#is_ready
61
method abort_track = source#abort_track
64
class virtual base_nosource ~kind =
68
method stype = Infallible
70
method is_ready = true
72
val mutable must_fail = false
80
(* A plugin is created for each channel. *)
81
class ladspa ~kind (source:source) plugin descr input output params =
83
inherit base ~kind source
86
let p = Plugin.load plugin in
87
let d = Descriptor.descriptor p descr in
88
Array.init ((Frame.type_of_kind kind).Frame.audio)
90
Descriptor.instantiate
92
(Lazy.force Frame.audio_rate)
96
Array.iter Descriptor.activate inst
98
method private get_frame buf =
99
let offset = AFrame.position buf in
101
let b = AFrame.content buf offset in
102
let position = AFrame.position buf in
103
let len = position - offset in
104
for c = 0 to Array.length b - 1 do
105
Descriptor.set_samples inst.(c) len;
106
Descriptor.connect_audio_port inst.(c) input b.(c) offset;
107
Descriptor.connect_audio_port inst.(c) output b.(c) offset;
109
(fun (p,v) -> Descriptor.connect_control_port_in inst.(c) p (v ()))
111
Descriptor.run inst.(c)
115
class ladspa_nosource ~kind plugin descr output params =
117
inherit base_nosource ~kind
120
let p = Plugin.load plugin in
121
let d = Descriptor.descriptor p descr in
122
Array.init ((Frame.type_of_kind kind).Frame.audio)
124
Descriptor.instantiate
126
(Lazy.force Frame.audio_rate)
130
Array.iter Descriptor.activate inst
132
method private get_frame buf =
135
AFrame.add_break buf (AFrame.position buf);
139
let offset = AFrame.position buf in
140
let b = AFrame.content buf offset in
141
let position = AFrame.size () in
142
let len = position - offset in
143
for c = 0 to Array.length b - 1 do
144
Descriptor.set_samples inst.(c) len;
145
Descriptor.connect_audio_port inst.(c) output b.(c) offset;
147
(fun (p,v) -> Descriptor.connect_control_port_in inst.(c) p (v ()))
149
Descriptor.run inst.(c)
151
AFrame.add_break buf position
154
(* The plugin handles stereo streams. *)
155
class ladspa_stereo ~kind (source:source) plugin descr inputs outputs params =
157
inherit base ~kind source
160
let p = Plugin.load plugin in
161
let d = Descriptor.descriptor p descr in
162
Descriptor.instantiate
164
(Lazy.force Frame.audio_rate)
168
Descriptor.activate inst
170
method private get_frame buf =
171
let offset = AFrame.position buf in
173
let b = AFrame.content buf offset in
174
let position = AFrame.position buf in
175
let len = position - offset in
177
(fun (p,v) -> Descriptor.connect_control_port_in inst p (v ()))
179
Descriptor.set_samples inst len;
181
Descriptor.connect_audio_port inst inputs.(c) b.(c) offset;
182
Descriptor.connect_audio_port inst outputs.(c) b.(c) offset;
187
class ladspa_stereo_nosource ~kind plugin descr outputs params =
189
inherit base_nosource ~kind
192
let p = Plugin.load plugin in
193
let d = Descriptor.descriptor p descr in
194
Descriptor.instantiate
196
(Lazy.force Frame.audio_rate)
200
Descriptor.activate inst
202
method private get_frame buf =
205
AFrame.add_break buf (AFrame.position buf);
209
let offset = AFrame.position buf in
210
let b = AFrame.content buf offset in
211
let position = AFrame.size () in
212
let len = position - offset in
214
(fun (p,v) -> Descriptor.connect_control_port_in inst p (v ()))
216
Descriptor.set_samples inst len;
218
Descriptor.connect_audio_port inst outputs.(c) b.(c) offset;
221
AFrame.add_break buf position
227
~pat:"( *\\([^\\)]*\\)| *\\[[^\\]]*\\])"
228
~subst:(fun _ -> "") s
230
let s = Pcre.substitute ~pat:"(\\.+|\\++)" ~subst:(fun _ -> "") s in
231
let s = Pcre.substitute ~pat:" +$" ~subst:(fun _ -> "") s in
232
let s = Pcre.substitute ~pat:"( +|/+|-+)" ~subst:(fun _ -> "_") s in
233
let s = String.lowercase s in
234
(* Identifiers cannot begin with a digit. *)
235
let s = if Pcre.pmatch ~pat:"^[0-9]" s then "_"^s else s in
238
(* List the indexes of control ports. *)
239
let get_control_ports d =
240
let ports = Descriptor.port_count d in
242
for i = 0 to ports - 1 do
243
if Descriptor.port_is_control d i && Descriptor.port_is_input d i then
248
(** When creating operator for LADSPA plugins, we don't know yet at
249
* which samplerate liquidsoap will operate. But the default values and
250
* bounds for LADSPA parameters might depend on the samplerate.
251
* Lacking a better solution, we use the following default samplerate,
252
* potentially creating a mismatch between the doc and the actual
254
let default_samplerate = 44100
256
(* Make a parameter for each control port.
257
* Returns the liquidsoap parameters and the parameters for the plugin. *)
258
let params_of_descr d =
259
let control_ports = get_control_ports d in
264
let t = port_t d p in
266
norm_string (Descriptor.port_name d p),
268
| Float -> Lang.float_getter_t !univ
270
| Bool -> Lang.bool_t
273
Descriptor.port_get_default d
274
~samplerate:default_samplerate p
279
| Float -> Lang.float f
280
| Int -> Lang.int (int_of_float f)
281
| Bool -> Lang.bool (f > 0.))
286
Descriptor.port_get_min d
287
~samplerate:default_samplerate p
290
Descriptor.port_get_max d
291
~samplerate:default_samplerate p
293
if (min, max) = (None, None) then ""
295
let bounds = ref " (" in
301
Printf.sprintf "%s%.6g <= " !bounds f
304
Printf.sprintf "%s%d <= " !bounds
305
(int_of_float (ceil f))
311
!bounds ^ (norm_string (Descriptor.port_name d p));
317
Printf.sprintf "%s <= %.6g" !bounds f
320
Printf.sprintf "%s <= %d" !bounds
328
Some (Descriptor.port_name d p ^ bounds ^ ".")
333
let f v = List.assoc v p in
337
let v = f (norm_string (Descriptor.port_name d p)) in
338
match port_t d p with
339
| Float -> Lang.to_float_getter v
341
let f = float_of_int (Lang.to_int v) in
344
let f = if Lang.to_bool v then 1. else 0. in
352
let register_descr ?(stereo=false) plugin_name descr_n d inputs outputs =
354
Lang.kind_type_of_kind_format ~fresh:1
355
(if stereo then Lang.audio_stereo else Lang.any_fixed)
357
let liq_params, params = params_of_descr d in
359
liq_params@(if inputs = None then [] else ["", Lang.source_t k, None, None])
361
let descr = Printf.sprintf "%s by %s." (Descriptor.name d) (Descriptor.maker d) in
362
Lang.add_operator ("ladspa." ^ norm_string (Descriptor.label d)) liq_params
363
~kind:(Lang.Unconstrained k)
364
~category:Lang.SoundProcessing
368
let f v = List.assoc v p in
371
Some (Lang.to_source (f ""))
375
let params = params p in
379
new ladspa_stereo ~kind
380
(Utils.get_some source)
388
(Utils.get_some source)
396
new ladspa_stereo_nosource ~kind
402
new ladspa_nosource ~kind
409
(** Get input and output ports. *)
410
let get_audio_ports d =
413
let ports = Descriptor.port_count d in
414
for n = 0 to ports - 1 do
415
if Descriptor.port_is_audio d n then
416
if Descriptor.port_is_input d n then
421
Array.of_list (List.rev !i), Array.of_list (List.rev !o)
423
(** Get the input and the output port. Raises [Not_found] if there is not
424
* exactly one output and zero or one input. *)
426
let i, o = get_audio_ports d in
428
if Array.length i = 0 then
430
else if Array.length i = 1 then
436
if Array.length o = 1 then
442
(* Same thing but for stereo I/O. *)
443
let get_stereo_io d =
444
let i, o = get_audio_ports d in
446
if Array.length i = 0 then
448
else if Array.length i = 2 then
454
if Array.length o = 2 then
460
let register_plugin pname =
462
let p = Plugin.load pname in
463
let descr = Descriptor.descriptors p in
467
let i, o = get_io d in
468
register_descr pname n d
470
| Some i -> Some [|i|]
477
(* TODO: handle other number of channels *)
478
let i, o = get_stereo_io d in
479
register_descr ~stereo:true pname n d i o
484
(* TODO: Unloading plugins makes liq segv. Don't do it for now. *)
485
(* Plugin.unload p *)
487
| Plugin.Not_a_plugin -> ()
489
let register_plugins () =
490
let add plugins_dir =
492
let dir = Unix.opendir plugins_dir in
495
let f = Unix.readdir dir in
496
if f <> "." && f <> ".." then
497
register_plugin (plugins_dir ^ "/" ^ f)
500
| End_of_file -> Unix.closedir dir
502
| Unix.Unix_error (e,_,_) ->
503
log#f 4 "Error while loading directory %s: %s"
504
plugins_dir (Unix.error_message e)
506
List.iter add plugin_dirs
509
if ladspa_enable then