*/
if(!defined('DOKU_INC')) die();
class helper_plugin_ladspa extends DokuWiki_Plugin {
/**
* Constructor
*/
function helper_plugin_ladspa() {
;
}
/**
* return some info
*/
function getInfo(){
return array(
'author' => 'Robin Gareus',
'email' => 'robin@gareus.org',
'date' => '2008-12-29',
'name' => 'ladspa',
'desc' => 'ladspa info (helper)',
'url' => 'http://mir.dnsalias.com/wiki/dokuladspa',
);
}
function getMethods(){
$result = array();
// TODO
return $result;
}
//// functions calling 'ladspa-sdk' tools via shell to gather information /////
/** call `listplugins` to query LADSPA .so lib filenames.
* @return array of filenames
*/
/*private */function get_so() {
$rv=array();
$lp=`listplugins | grep -e ".so:\$"`;
foreach (split(':',$lp) as $so) {
$fn=trim($so);
if(!empty($fn)) $rv[]=array('fn' => $fn);
}
return $rv;
}
/** call `analyseplugin` to get info from LADSPA .so lib.
*
* @param $so string the filename of the .so library
* @return array of plugins
*/
/*private */function get_ap($so) {
$lp=`analyseplugin "$so"`;
return $this->parse_ap($lp, $so);
}
/*private */function get_all() {
$plugins=array();
$sos=get_so();
usort($sos , 'cmp_fn');
foreach ($sos as &$so) {
$p=get_ap($so['fn']);
$so['contains']=count($p);
$plugins = array_merge($plugins,$p); # XXX this, alas, re-orders numberic keys.
}
// save $so and $plugins
//
//$f =fopen($datafn, "w");
//if ($f) {fwrite($f, serialize(array('sos'=>$sos, 'plugins' => $plugins))); fclose($f);}
return $plugins;
}
//// parser for `analyseplugin` output ////
/** parse output from `analyseplugin`
*
* @param $lp string (requires trailing empty line)
* @return array of plugins
*/
function parse_ap($lp, $so="??") {
$analysepluginmap = array (
"Plugin Name: " => 'Name',
"Plugin Label: " => 'Label',
"Plugin Unique ID: " => 'UniqueID',
"Maker: " => 'Maker',
"Copyright: " => 'Copyright',
"Must Run Real-Time: " => 'PropertyRealTime',
"Has activate() Function: " => 'customTypeActivate',
"Has deativate() Function: " => 'customTypeDeactivate', ## typo in `analyseplugin`
"Has deactivate() Function: " => 'customTypeDeactivate',
"Has run_adding() Function: " => 'customTypeRunAdding',
"Environment: " => 'customEnvironment',
"ERROR: " => '', # TODO
"Ports:" => 'Ports',
"This plugin cannot use in-place processing. It will not work with all hosts."
=> 'PropertyInplace',
);
# Notes from ladspa.h
#define LADSPA_PROPERTY_REALTIME 0x1
#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2
#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4
#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME)
#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN)
#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE)
$rv=array();
$p=false;
$state=0;
foreach (split("\n", $lp) as $l) {
$l=trim($l);
if (empty($l)) { // new plugin
if (is_array($p) && !empty($p['UniqueID'])) {
$this->process_plugin($p);
$p['so']=$so;
$rv[$p['UniqueID']]=$p;
}
$p=array();
$state=0;
continue;
}
if ($state==1) { // 'Ports'
$p['Ports'][]=$this->parse_port($l);
continue;
}
// now check for patterns in analysepluginmap
$key=false;
$pattern='';
foreach ($analysepluginmap as $pt=> $k) {
if (strncmp($l,$pt,strlen($pt))==0) {
$key=$k;
$pattern=$pt;
break;
}
}
// TODO parser "Errors"
if (!empty($key)) {
$v=substr($l, strlen($pattern));
switch ($key) {
case 'Ports':
$state=1;
$p['Ports'][]=$this->parse_port($v);
break;
case 'customTypeDeactivate':
$p['Capabilities']|=trim($v)=='Yes'?2:0;
break;
case 'customTypeActivate':
$p['Capabilities']|=trim($v)=='Yes'?1:0;
break;
case 'customTypeRunAdding':
$p['Capabilities']|=trim($v)=='Yes'?4:0;
break;
case 'PropertyRealTime':
$p['Properties']|=trim($v)=='Yes'?1:0;
break;
case 'PropertyInplace':
$p['Properties']|=2;
break;
case 'customEnvironment':
$p['Properties']|=trim($v)=='Normal'?0:4;
break;
default:
$p[$k] = trim($v," \t\n\r\0\0x0B\"");
break;
}
} /* end found/parse pattern */
} /* end foreach line */
return $rv;
}
/** parse a "Port" line from `analyseplugin`.
* @param $line string - line alike:
*
"Band 3 Freq [Hz]" input, control, 200 to 1000, default 400
* @returns array
*/
/*private */function parse_port($line) {
if (!preg_match('/"([^"]*)" ([^,]*), (.*)$/', $line, $m)) {
echo "invalid port data\n";
return array();
}
$param=$m[3];
$s=split(',', $param);
$p = array(
'name' => $m[1],
'io' => $m[2],
'type' => $s[0],
);
# "Sections" input, control, 1 to 30, integer
# "Release Time (s)" input, control, 0 to ..., default 0
# "Bandwidth (Hz)" input, control, 0.0001*srate to 0.45*srate, default 0.0067082*srate, logarithmic
# "Filter" input, control, toggled, default 0
if ($s[0]=='control') {
if (trim($s[1])=='toggled') {
$p['min'] = 0;
$p['max'] = 1;
$p['toggled'] = true;
$p['default'] = floatval(str_replace("default ",'',trim($s[2]))); // skip "default "
return($p);
}
$mm=split(' ', trim($s[1])); // " to "
$p['min'] = floatval($mm[0]);
if (strpos($mm[0],'srate')!==false)
$p['min'] *= 48000.0;
if (strpos($mm[0],'...')!==false)
$p['min'] = -110000000; // XXX
$p['max'] = floatval($mm[2]);
if (strpos($mm[2],'srate')!==false)
$p['max'] *= 48000.0;
if (strpos($mm[2],'...')!==false)
$p['max'] = 110000000; // XXX
$p['default'] = floatval(str_replace("default ",'',trim($s[2]))); // skip "default "
if (strpos($s[2],'srate')!=false)
$p['default'] = floatval(48000.0*$p['default']);
if (strpos($param,'integer')!=false) {
$p['integer'] = true;
}
if (strpos($param,'logarithmic')!=false) {
$p['logscale'] = true;
}
if ($p['default'] < $p['min']) $p['default']= $p['min'];
if ($p['default'] > $p['max']) $p['default']= $p['max'];
}
return $p;
}
/** post-process data gathered from `analyseplugin` before using/saving it.
* this function basically counts the available ports by type.
*/
/*private */function process_plugin(&$plugin) {
$portcounters=array('audio_in' => 0, 'audio_out' => 0, 'control_in' => 0, 'control_out' => 0);
$controlports=array();
foreach ($plugin['Ports'] as $p) {
if ($p['io'] == 'input') {
if ($p['type'] == 'control') {
$portcounters['control_in']++;
$controlports[]=$p;
} else if ($p['type'] == 'audio') {
$portcounters['audio_in']++;
}
} else if ($p['io'] == 'output') {
if ($p['type'] == 'control') {
$portcounters['control_out']++;
$controlports[]=$p;
} else if ($p['type'] == 'audio') {
$portcounters['audio_out']++;
}
}
}
$plugin['controlports'] = $controlports;
$plugin['portcounters'] = $portcounters;
}
//// sort plugins helpers ////
function cmp_fn($a, $b) {
return strcmp(basename($a['fn']), basename($b['fn']));
}
function cmp_chnin($a, $b) {
$va=$a['portcounters']['audio_in'];
$vb=$b['portcounters']['audio_in'];
if ($va==$vb) return 0;
return ($va > $vb);
}
function cmp_chnout($a, $b) {
$va=$a['portcounters']['audio_out'];
$vb=$b['portcounters']['audio_out'];
if ($va==$vb) return 0;
return ($va > $vb);
}
function cmp_label($a, $b) {
$va=$a['Label'];
$vb=$b['Label'];
return strcmp($va, $vb);
}
function cmp_control($a, $b) {
$va=count($a['controlports']);
$vb=count($b['controlports']);
if ($va==$vb) return 0;
return ($va > $vb);
}
//// output functions ////
/*private */function _ht($txt) {
# TODO: obfuscate email addresses here ?! /@([^ ])\./
# TODO: no duplicate © s/^(C)//
return htmlentities($txt);
}
/*private */function _st($t, $max=16) {
$txt='???';
if (!empty($t) && strlen($t)<=$max) {$txt=$t;}
else if (!empty($t)) { $txt=substr($t,0,$max).'..';}
return $this->_ht($txt);
}
/*private */function fmt_val ($v) {
if (abs($v)>=110000000) { return (($v<0?'−':'').'∞');}
if (abs($v)>=1000000) { return (intval($v/100000)/10.0).'M';}
else if (abs($v)>=1000) { return (intval($v/100)/10.0).'K';}
else if (abs($v)>=10) { return (intval($v*10.0)/10.0);}
else { return (intval($v*100.0)/100.0);}
}
/*private */function render_flags($plugin) {
$rv='';
if ($plugin['Properties']&0x1) $rv.=' [RT]';
if ($plugin['Properties']&0x2) $rv.=' [IP]';
if ($plugin['Properties']&0x4) $rv.=' [rt]';
#if ($plugin['Properties']&0x4) $rv.=' []';
if ($plugin['Capabilities']&0x1) $rv.=' [A]';
if ($plugin['Capabilities']&0x2) $rv.=' [D]';
if ($plugin['Capabilities']&0x4) $rv.=' [R]';
return ($rv);
}
function render_legend() {
$rv='';
$rv.='';
$rv.='
'; // first line
$rv.='linear';
$rv.=' | ';
$rv.='logscale';
$rv.=' | ';
$rv.='integer Controlls';
$rv.='
'; // 2nd line
$rv.='Ouput Ports';
$rv.=' || ';
$rv.='Parameter';
$rv.=' | ';
$rv.='Value';
$rv.='
'; // 2nd line
#$rv.='Use mouse-over to view the full titles
or long parameters indictated by "..".';
$rv.='use mouse-over to reveal ".." contd. titles.';
$rv.='
';
return ($rv);
}
function render_list($plugins) {
$rv='';
$rv.="\n";
foreach ($plugins as $plugin) {
$rv.="- \n";
$rv.="";
$rv.=' '.$this->_st($plugin['Label'],48).'';
$rv.=' ('.$this->_st($plugin['UniqueID']).')';
$rv.=' '.$this->_st($plugin['Name'],48).''."\n";
$rv.=' audio: '.$plugin['portcounters']['audio_in'].'/'.$plugin['portcounters']['audio_out'].'';
$rv.=' ctrl: '.$plugin['portcounters']['control_in'].'/'.$plugin['portcounters']['control_out'].'';
$rv.=' ';
$rv.=$this->render_flags($plugin);
$rv.="
\n";
}
$rv.="
\n";
return ($rv);
}
function render_ladspa($plugin) {
$rv='';
// prepare data
$portcounters=$plugin['portcounters'];
$controlports=$plugin['controlports'];
// format it
$rv.='';
$rv.='';
$rv.='
';
$rv.=' '.$this->_st($plugin['Label']).'';
$rv.=' '.$this->_st($plugin['Name']).''."\n";
$rv.='
';
$rv.='
';
$rv.='
'; // pluginbody
$rv.='
audio
in:'.$portcounters['audio_in'].'
';
$rv.='
audio
out:'.$portcounters['audio_out'].'
';
$rv.='
';
$rv.='
'; // ctrl top-line
$rv.=' ctrl in:'.$portcounters['control_in'].'';
$rv.=' / out:'.$portcounters['control_out'].'';
$rv.='
';
$rv.='
'; // ctrl 2nd line
$rv.=$this->render_flags($plugin);
$rv.='
';
$tot=count($controlports);
$i=0; $halfway=ceil($tot/2.0);
if ($tot>1)
$rv.='
';
else
$rv.='
';
foreach ($controlports as $c) {
$rv.='
'."\n";
if ($c['io'] == 'input')
$rv.='
'.$this->_st($c['name']).''."
\n";
else
$rv.='
'.$this->_st($c['name']).''."
\n";
if ($c['logscale']==true) { // log
if ($c['min']==0) {
$w=log($c['max']);
if ($w<=0) $w=0; else $w= 100.0 * log($c['default']) / $w;
} else if ($c['max']==0) {
$w=-1*log($c['min']);
if ($w<=0) $w=0; else $w= 100.0 * (log($c['default'])+log($c['min'])) / $w; ## verify
} else {
$w=log($c['max'])-log($c['min']);
if ($w<=0) $w=0; else $w= 100.0 * (log($c['default'])-log($c['min'])) / $w;
}
} else { // linear
$w=$c['max']-$c['min'];
if ($w<=0) $w=0; else $w= 100.0 * ($c['default']-$c['min']) / $w;
}
$rv.='
'."\n";
$rv.='
'."\n";
$i++;
if ($tot>1 && $i==$halfway) {
$rv.='
';
}
}
$rv.='
'."\n"; // col
if (1) {
$rv.=' '."\n";
}
$rv.='
';
$rv.='
'."\n"; //mainbox
$rv.='
'; // pluginbody
$rv.='
'; // wrapper
return $rv;
}
}
//Setup VIM: ex: et sw=2 ts=2 enc=utf-8 :