*/ 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.=' [rt]'; 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"; 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.=' ('.$this->_st($plugin['UniqueID']).')'; $rv.=' by'.$this->_st($plugin['Maker']).''; $rv.=' ©'.$this->_st($plugin['Copyright']).''."\n"; $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.='
'; else $rv.=' output">'."\n"; $rv.='
 
'."\n"; $rv.='
'; $rv.=' '.$this->fmt_val($c['min']).' ≤'."\n"; $rv.=' ('.$this->fmt_val($c['default']).')'."\n"; $rv.=' ≤ '.$this->fmt_val($c['max']).''."\n"; $rv.='
'."\n"; $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 :