5 ## generate doc/luadoc.json.gz (lua binding doc)
6 # ./waf configure --luadoc ....
8 # ./gtk2_ardour/arluadoc > doc/luadoc.json.gz
10 ## generate doc/ardourapi.json.gz (ardour header doxygen doc)
11 # cd ../../tools/doxy2json
15 ## format HTML (using this scripterl)
16 # php tools/fmt-luadoc.php > /tmp/luadoc.html
19 $options = getopt("m");
20 if (isset ($options['m'])) {
21 $HTMLOUTPUT = false; ## set to false to output ardour-manual
23 $HTMLOUTPUT = true; ## set to false to output ardour-manual
26 ################################################################################
27 ################################################################################
29 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz'));
32 foreach (json_decode ($json, true) as $b) {
33 if (!isset ($b['type'])) {
34 if (isset ($b['version'])) { $ardourversion = $b['version']; }
38 $b ['lua'] = preg_replace ('/:_end/', ':end', $b ['lua']);
39 $b ['lua'] = preg_replace ('/:_type/', ':type', $b ['lua']);
40 $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl']));
41 $b ['ldec'] = preg_replace ('/_VampHost::/', '', $b['ldec']);
42 $b ['decl'] = preg_replace ('/_VampHost::/', '', $b['decl']);
43 if (isset ($b['ret'])) {
44 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
45 $b['ret'] = preg_replace ('/_VampHost::/', '', $b['ret']);
47 if (isset ($b['parent'])) {
48 $b ['parent'] = preg_replace ('/_VampHost::/', '', $b['parent']);
53 if (count ($doc) == 0) {
54 fwrite (STDERR, "Failed to read luadoc.json\n");
58 ################################################################################
59 ## Global result variables
60 ################################################################################
62 $classlist = array ();
63 $constlist = array ();
66 ################################################################################
67 ## Pre-process the data, collect functions, parse arguments, cross reference
68 ################################################################################
71 ################################################################################
72 # some internal helper functions first
78 function my_die ($msg) {
79 fwrite (STDERR, $msg."\n");
83 ##function ptr_strip ($ctype) {
84 # # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
85 # # -> std::list<ARDOUR::Route>
86 # $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
87 # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
90 function arg2lua ($argtype, $flags = 0) {
94 # LuaBridge abstracts C++ references
95 $flags |= preg_match ('/&$/', $argtype);
96 $arg = preg_replace ('/&$/', '', $argtype);
97 $arg = preg_replace ('/ $/', '', $arg);
99 # filter out basic types
100 $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'short', 'long', 'unsigned int', 'unsigned short', 'unsigned long', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
101 if (in_array ($arg, $builtin)) {
102 return array ($arg => $flags);
105 if ($arg == 'luabridge::LuaRef') {
106 return array ('Lua-Function' => $flags | 4);
108 if ($arg == 'LTC_TV_STANDARD') {
109 $arg = 'ARDOUR::DSP::LTC_TV_STANDARD';
112 # check Class declarations first
113 foreach (array_merge ($classes, $consts) as $b) {
114 if ($b['ldec'] == $arg) {
115 return array ($b['lua'] => $flags);
119 # strip class pointers -- TODO Check C'tor for given class
120 $arg = preg_replace ('/[&*]*$/', '', $argtype);
121 foreach (array_merge ($classes, $consts) as $b) {
122 if ($b['ldec'] == $arg) {
123 return array ($b['lua'] => $flags);
127 return array ($argtype => ($flags | 4));
129 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
133 function stripclass ($classname, $name) {
135 if (strpos ($name, $classname) !== 0) {
136 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
138 return substr ($name, strlen ($classname));
141 function datatype ($decl) {
142 # TODO handle spaces in type. Works because
143 # we don't yet have templated types (with_space <here >)
144 return substr ($decl, 0, strrpos ($decl, ' '));
147 function luafn2class ($lua) {
148 return substr ($lua, 0, strrpos ($lua, ':'));
151 function luafn2name ($lua) {
152 $fn = strrpos ($lua, ':');
153 if ($fn !== 0 && strlen($lua) > $fn + 1) {
154 return substr ($lua, $fn + 1);
156 my_die ('invalid class prefix: '. $name);
160 function checkclass ($b) {
162 if (!isset ($classlist[luafn2class ($b['lua'])])) {
163 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
167 # parse functions argument list to lua-names
168 function decl2args ($decl) {
169 $start = strrpos ($decl, '(');
170 $end = strrpos ($decl, ')');
171 $args = substr ($decl, $start + 1, $end - $start - 1);
172 $arglist = preg_split ('/, */', $args);
174 foreach ($arglist as $a) {
175 if (empty ($a)) { continue; }
176 $rv[] = arg2lua ($a);
181 function canonical_ctor ($b) {
183 if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
184 $lc = luafn2class ($b['lua']);
185 $cn = str_replace (':', '::', $lc);
186 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
187 $rv = $cn . '::'. $fn . $matches[2];
192 function canonical_decl ($b) {
195 # match clang's declatation format
196 if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
197 if (strpos ($b['type'], 'Free Function') !== false) {
198 $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
200 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
201 $rv = $matches[1] . $fn . '(';
202 $arglist = preg_split ('/, */', $matches[2]);
204 foreach ($arglist as $a) {
205 if (!$first) { $rv .= ', '; }; $first = false;
206 if (empty ($a)) { continue; }
207 $a = preg_replace ('/([^>]) >/', '$1>', $a);
208 $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
209 $a = preg_replace ('/([^ ])&/', '$1 &', $a);
210 $a = preg_replace ('/std::vector<([^>]*)> const/', 'const std::vector<$1>', $a);
211 $a = str_replace ('std::vector', 'vector', $a);
212 $a = str_replace ('vector', 'std::vector', $a);
213 $a = str_replace ('std::string', 'string', $a);
214 $a = str_replace ('string const', 'const string', $a);
215 $a = str_replace ('string', 'std::string', $a);
223 ################################################################################
224 # step 1: build class indices
226 foreach ($doc as $b) {
227 if (strpos ($b['type'], "[C] ") === 0) {
229 $classlist[$b['lua']] = $b;
230 if (strpos ($b['type'], 'Pointer Class') === false) {
231 $classdecl[$b['ldec']] = $b;
236 foreach ($classes as $c) {
237 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
238 if (isset ($c['parent'])) {
239 if (isset ($classdecl[$c['parent']])) {
240 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
242 my_die ('unknown parent class: ' . print_r ($c, true));
247 # step 2: extract constants/enum
248 foreach ($doc as $b) {
249 switch ($b['type']) {
250 case "Constant/Enum":
251 case "Constant/Enum Member":
252 if (strpos ($b['ldec'], '::') === false) {
253 # for extern c enums, use the Lua Namespace
254 $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
256 $ns = str_replace ('::', ':', $b['ldec']);
257 $constlist[$ns][] = $b;
267 # step 3: process functions
268 foreach ($doc as $b) {
269 switch ($b['type']) {
271 case "Weak/Shared Pointer Constructor":
273 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
274 'name' => luafn2class ($b['lua']),
275 'args' => decl2args ($b['ldec']),
276 'cand' => canonical_ctor ($b),
280 case "Weak/Shared Pointer NIL Constructor":
282 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
283 'name' => luafn2class ($b['lua']),
284 'args' => decl2args ($b['ldec']),
285 'cand' => canonical_ctor ($b),
291 $classlist[luafn2class ($b['lua'])]['props'][] = array (
293 'ret' => arg2lua (datatype ($b['ldec']))
298 $classlist[luafn2class ($b['lua'])]['data'][] = array (
300 'ret' => arg2lua (datatype ($b['ldec']))
303 case "Static C Function":
305 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
306 # special case ARDOUR:DataType convenience c'tor
308 $ret = array (luafn2class ($b['lua']) => 0);
309 $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
311 my_die ('unhandled Static C: ' . print_r($b, true));
313 $classlist[luafn2class ($b['lua'])]['func'][] = array (
324 # we required C functions to be in a class namespace
325 case "Ext C Function":
327 $args = array (array ('--lua--' => 0));
328 $ret = array ('...' => 0);
329 $ns = luafn2class ($b['lua']);
330 $cls = $classlist[$ns];
331 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
332 # std::vector, std::list types
333 switch (stripclass($ns, $b['lua'])) {
335 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
336 $args = array (arg2lua ($templ[1], 2));
337 $ret = array ('LuaTable' => 0);
341 $ret = array ('LuaIter' => 0);
345 $ret = array ('LuaTable' => 0);
350 } else if (strpos ($cls['type'], ' Array') !== false) {
351 # catches C:FloatArray, C:IntArray
352 $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
353 switch (stripclass($ns, $b['lua'])) {
356 $ret = array ('LuaMetaTable' => 0);
360 $ret = array ('LuaTable' => 0);
363 $args = array (array ('LuaTable {'.$templ.'}' => 0));
364 $ret = array ('void' => 0);
370 $classlist[luafn2class ($b['lua'])]['func'][] = array (
377 'cand' => canonical_decl ($b)
380 case "Free C Function":
381 $funclist[luafn2class ($b['lua'])][] = array (
388 'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
391 case "Free Function":
392 case "Free Function RefReturn":
393 $funclist[luafn2class ($b['lua'])][] = array (
396 'args' => decl2args ($b['ldec']),
397 'ret' => arg2lua ($b['ret']),
398 'ref' => (strpos ($b['type'], "RefReturn") !== false),
399 'cand' => canonical_decl ($b)
402 case "Member Function":
403 case "Member Function RefReturn":
404 case "Member Pointer Function":
405 case "Weak/Shared Pointer Function":
406 case "Weak/Shared Pointer Function RefReturn":
407 case "Weak/Shared Null Check":
408 case "Static Member Function":
410 $classlist[luafn2class ($b['lua'])]['func'][] = array (
413 'args' => decl2args ($b['ldec']),
414 'ret' => arg2lua ($b['ret']),
415 'ref' => (strpos ($b['type'], "RefReturn") !== false),
416 'cand' => canonical_decl ($b)
420 case "Weak/Shared Pointer Cast":
422 $classlist[luafn2class ($b['lua'])]['cast'][] = array (
425 'args' => decl2args ($b['ldec']),
426 'ret' => arg2lua ($b['ret']),
427 'ref' => (strpos ($b['type'], "RefReturn") !== false),
428 'cand' => canonical_decl ($b)
431 case "Constant/Enum":
432 case "Constant/Enum Member":
433 # already handled -> $consts
436 if (strpos ($b['type'], "[C] ") !== 0) {
437 my_die ('unhandled type: ' . $b['type']);
444 # step 4: collect/group/sort
446 # step 4a: unify weak/shared Ptr classes
447 foreach ($classlist as $ns => $cl) {
448 if (strpos ($cl['type'], ' Array') !== false) {
449 $classlist[$ns]['arr'] = true;
450 $classlist[$ns]['cdecl'] = $cl['decl'];
453 foreach ($classes as $c) {
454 if ($c['lua'] == $ns) {
455 if (strpos ($c['type'], 'Pointer Class') !== false) {
456 $classlist[$ns]['ptr'] = true;
457 $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
460 $classlist[$ns]['cdecl'] = $c['decl'];
466 # step4b: sanity check
467 foreach ($classlist as $ns => $cl) {
468 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
469 my_die ('missing parent class: ' . print_r ($cl, true));
473 # step 4c: merge free functions into classlist
474 foreach ($funclist as $ns => $fl) {
475 if (isset ($classlist[$ns])) {
476 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
478 $classlist[$ns]['func'] = $fl;
479 $classlist[$ns]['free'] = true;
482 # step 4d: order to chaos
483 # no array_multisort() here, sub-types are sorted after merging parents
487 ################################################################################
488 ################################################################################
489 ################################################################################
492 #### -- split here -- ####
494 # from here on, only $classlist and $constlist arrays are relevant.
495 # we also pull in C++ header annotation from doxygen to $api
498 # read documentation from doxygen
499 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
501 foreach (json_decode ($json, true) as $a) {
502 if (!isset ($a['decl'])) { continue; }
503 if (empty ($a['decl'])) { continue; }
504 $canon = str_replace (' *', '*', $a['decl']);
508 # keep track of found/missing doc
512 # retrive a value from $api
513 function doxydoc ($canonical_declaration) {
517 if (isset ($api[$canonical_declaration])) {
519 return $api[$canonical_declaration]['doc'];
521 // remove template namespace e.g.
522 // "ARDOUR::Track::bounceable(boost::shared_ptr<ARDOUR::Processor>"
523 // "ARDOUR::Track::bounceable(boost::shared_ptr<Processor>"
524 $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration);
525 if (isset ($api[$cn])) {
527 return $api[$cn]['doc'];
529 #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG
535 ################################################################################
537 ################################################################################
540 ################################################################################
544 # constructors, enums (constants) use a dot. (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
545 function ctorname ($name) {
546 return htmlentities (str_replace (':', '.', $name));
549 # strip class prefix (e.g "Evoral:MidiEvent:channel" -> "channel")
550 function shortname ($name) {
551 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
554 # retrieve variable name from array["VARNAME"] => FLAGS
555 function varname ($a) {
556 return array_keys ($a)[0];
559 # recusively collect class parents (derived classes)
560 function traverse_parent ($ns, &$inherited) {
563 if (isset ($classlist[$ns]['luaparent'])) {
564 $parents = array_unique ($classlist[$ns]['luaparent']);
566 foreach ($parents as $p) {
567 if (!empty ($rv)) { $rv .= ', '; }
568 if ($p == $ns) { continue; }
569 $rv .= typelink ($p);
570 $inherited[$p] = $classlist[$p];
571 traverse_parent ($p, $inherited);
577 # create a cross-reference to a type (class or enum)
578 # *all* <a> links are generated here, currently anchors on a single page.
579 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
582 if (isset($classlist[$a]['free'])) {
583 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
584 } else if (in_array ($a, array_keys ($classlist))) {
585 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
586 } else if (in_array ($a, array_keys ($constlist))) {
587 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
589 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
593 # output format function arguments
594 function format_args ($args) {
595 $rv = '<span class="functionargs"> (';
597 foreach ($args as $a) {
598 if (!$first) { $rv .= ', '; }; $first = false;
599 $flags = $a[varname ($a)];
601 $rv .= '<span>'.varname ($a).'</span>';
603 else if ($flags & 2) {
604 $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
606 elseif ($flags & 1) {
607 $rv .= typelink (varname ($a), true, 'em', '', '&');
610 $rv .= typelink (varname ($a), true, 'em');
617 # format doxygen documentation for class-definition
618 function format_doxyclass ($cl) {
620 if (isset ($cl['decl'])) {
621 $doc = doxydoc ($cl['decl']);
623 $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
629 # format doxygen documentation for class-members
630 function format_doxydoc ($f) {
632 if (isset ($f['cand'])) {
633 $doc = doxydoc ($f['cand']);
635 $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
636 $rv.= '</div></td></tr>'.NL;
637 } else if (0) { # debug
638 $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
639 $rv.= '</td></tr>'.NL;
645 # usort() callback for class-members
646 function name_sort_cb ($a, $b) {
647 return strcmp ($a['name'], $b['name']);
650 # main output function for every class
651 function format_class_members ($ns, $cl, &$dups) {
653 # print contructor - if any
654 if (isset ($cl['ctor'])) {
655 usort ($cl['ctor'], 'name_sort_cb');
656 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
657 foreach ($cl['ctor'] as $f) {
660 $rv.= '<td class="def"><abbr title="Nil Pointer Constructor">ℵ</abbr></td>';
662 $rv.= '<td class="def">ℂ</td>';
664 $rv.= '<td class="decl">';
665 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
666 $rv.= format_args ($f['args']);
667 $rv.= '</td><td class="fill"></td></tr>'.NL;
668 # doxygen documentation (may be empty)
669 $rv.= format_doxydoc($f);
673 # strip duplicates (inherited or derived methods)
674 # e.g AudioTrack -> Track -> Route -> SessionObject -> Stateful
675 # all 5 have "isnil()"
677 if (isset ($cl['func'])) {
678 foreach ($cl['func'] as $f) {
679 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
684 # print methods - if any
685 if (count ($nondups) > 0) {
686 usort ($nondups, 'name_sort_cb');
687 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
688 foreach ($nondups as $f) {
689 $dups[] = stripclass ($ns, $f['name']);
691 $rv.= ' <tr><td class="def">';
692 if ($f['ref'] && isset ($f['ext'])) {
693 # external C functions
694 $rv.= '<em>'.varname ($f['ret']).'</em>';
695 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
696 # void functions with reference args
697 $rv.= '<em>LuaTable</em>(...)';
698 } elseif ($f['ref']) {
699 # functions with reference args and return value
700 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
702 # normal class members
703 $rv.= typelink (varname ($f['ret']), true, 'em');
705 # function declaration and arguments
706 $rv.= '</td><td class="decl">';
707 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
708 $rv.= format_args ($f['args']);
709 $rv.= '</td><td class="fill"></td></tr>'.NL;
710 # doxygen documentation (may be empty)
711 $rv.= format_doxydoc($f);
714 # print cast - if any
715 if (isset ($cl['cast'])) {
716 usort ($cl['cast'], 'name_sort_cb');
717 $rv.= ' <tr><th colspan="3">Cast</th></tr>'.NL;
718 foreach ($cl['cast'] as $f) {
719 $rv.= ' <tr><td class="def">';
720 $rv.= typelink (varname ($f['ret']), true, 'em');
721 # function declaration and arguments
722 $rv.= '</td><td class="decl">';
723 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
724 $rv.= format_args ($f['args']);
725 $rv.= '</td><td class="fill"></td></tr>'.NL;
726 # doxygen documentation (may be empty)
727 $rv.= format_doxydoc($f);
731 # print properties - if any
732 if (isset ($cl['props'])) {
733 usort ($cl['props'], 'name_sort_cb');
734 $rv.= ' <tr><th colspan="3">Properties</th></tr>'.NL;
735 foreach ($cl['props'] as $f) {
736 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
737 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
738 $rv.= '</td><td class="fill"></td></tr>'.NL;
742 # print data members - if any
743 if (isset ($cl['data'])) {
744 usort ($cl['data'], 'name_sort_cb');
745 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
746 foreach ($cl['data'] as $f) {
747 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
748 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
749 $rv.= '</td><td class="fill"></td></tr>'.NL;
750 $f['cand'] = str_replace (':', '::', $f['name']);
751 $rv.= format_doxydoc($f);
758 ################################################################################
764 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
766 <title>Ardour Lua Bindings</title>
767 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
768 <style type="text/css">
769 div.header { text-align:center; }
770 div.header h2 { margin:0; }
771 div.header p { margin:.25em; text-align:center; }
772 div.luafooter { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
773 #luaref { max-width:60em; margin: 1em auto; }
775 #luaref h2 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
776 #luaref h3.cls { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
777 #luaref h3.cls abbr { text-decoration:none; cursor:default; }
778 #luaref h4.cls { margin:1em 0 0 0; }
779 #luaref h3.class { background-color: #aaee66; }
780 #luaref h3.enum { background-color: #aaaaaa; }
781 #luaref h3.pointerclass { background-color: #eeaa66; }
782 #luaref h3.array { background-color: #66aaee; }
783 #luaref h3.opaque { background-color: #6666aa; }
784 #luaref p { text-align: justify; }
785 #luaref p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
786 #luaref ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
787 #luaref div.clear { clear:both; }
788 #luaref p.classinfo { margin: .25em 0; }
789 #luaref div.code { width:80%; margin:.5em auto; }
790 #luaref div.code div { width:45%; }
791 #luaref div.code pre { line-height: 1.2em; margin: .25em 0; }
792 #luaref div.code samp { color: green; font-weight: bold; background-color: #eee; }
793 #luaref div.classdox { padding: .1em 1em; }
794 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
795 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
796 #luaref div.classdox { padding: .1em 1em; }
797 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
798 #luaref table.classmembers { width: 100%; }
799 #luaref table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
800 #luaref table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap; }
801 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
802 #luaref table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
803 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
804 #luaref table.classmembers td.doc p { margin: .5em 0; }
805 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
806 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
807 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
808 #luaref table.classmembers td.doc dt { font-style: italic; }
809 #luaref table.classmembers td.fill { width: 99%; }
810 #luaref table.classmembers span.em { font-style: italic; }
811 #luaref span.functionname abbr { text-decoration:none; cursor:default; }
812 #luaref table.classmembers td.def abbr { text-decoration:none; cursor:default; }
817 <h2>Ardour Lua Bindings</h2>
819 <a href="#h_classes">Class Documentation</a>
821 <a href="#h_enum">Enum/Constants</a>
823 <a href="#h_index">Index</a>
827 <!-- #### SNIP #### !-->
836 This documentation is far from complete may be inaccurate and subject to change.
847 ################################################################################
848 # some general documentation -- should really go elsehere
852 <h2 id="h_intro">Overview</h2>
854 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
855 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
858 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
859 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
860 <?=typelink('LuaSignal:Set')?> etc.
863 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
865 <h3>Short introduction to Ardour classes</h3>
867 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
868 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
869 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
870 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
873 Operations are performed on objects. One gets a reference to an object and then calls a method.
874 e.g <code>obj = Session:route_by_name("Audio") obj:set_name("Guitar")</code>.
877 Lua automatically follows C++ class inheritance. e.g one can directly call all SessionObject and Route methods on Track object. However lua does not automatically promote objects. A Route object which just happens to be a Track needs to be explicitly cast to a Track. Methods for casts are provided with each class. Note that the cast may fail and return a <em>nil</em> reference.
880 Likewise multiple inheritance is a <a href="http://www.lua.org/pil/16.3.html">non-trivial issue</a> in Lua. To avoid performance penalties involved with lookups, explicit casts are required in this case. One example is <?=typelink('ARDOUR:SessionObject')?> which is-a StatefulDestructible which inherits from both Stateful and Destructible.
883 Object lifetimes are managed by the Session. Most Objects cannot be directly created, but one asks the Session to create or destroy them. This is mainly due to realtime constrains:
884 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
886 <h3>Pass by Reference</h3>
888 Since Lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
889 All parameters passed to a C++ method which uses references are returned as Lua Table.
890 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
894 <div style="float:left;">C++
896 <pre><code class="cxx">void set_ref (int& var, long& val)
898 printf ("%d %ld\n", var, val);
905 <div style="float:right;">Lua
907 <pre><code class="lua">local var = 0;
908 ref = set_ref (var, 2);
909 -- output from C++ printf()
910 </code><samp class="lua">0 2</samp><code>
911 -- var is still 0 here
912 print (ref[1], ref[2])
913 </code><samp class="lua">5 7</samp></pre>
917 <div class="clear"></div>
919 <div style="float:left;">
921 <pre><code class="cxx">int set_ref2 (int &var, std::string unused)
929 <div style="float:right;">
930 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
931 print (rv, ref[1], ref[2])
932 </code><samp class="lua">3 5 hello</samp></pre>
935 <div class="clear"></div>
937 <h3>Pointer Classes</h3>
939 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
940 The Lua bindings provide a complete abstraction of this. There are no pointers in Lua.
941 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but Lua functions operate on it like it was a class instance.
944 <code>shared_ptr</code> are reference counted. Once assigned to a Lua variable, the C++ object will be kept and remains valid.
945 It is good practice to assign references to Lua <code>local</code> variables or reset the variable to <code>nil</code> to drop the ref.
948 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
949 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
950 may not be able to find the given plugin and hence cannot create an object.
953 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
954 The object may vanish at any time.
955 If Lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
956 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
959 From the Lua side of things there is no distinction between weak and shared pointers. They behave identically.
960 Below they're indicated in orange and have an arrow to indicate the pointer type.
961 Pointer Classes cannot be created in Lua scripts. It always requires a call to C++ to create the Object and obtain a reference to it.
967 #################################
968 # Main output function -- Classes
970 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
971 foreach ($classlist as $ns => $cl) {
973 $tbl = format_class_members ($ns, $cl, $dups);
975 # format class title - depending on type
977 # classes with no members (no ctor, no methods, no data)
978 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h3>'.NL;
980 else if (isset ($classlist[$ns]['free'])) {
981 # free functions (no class)
982 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h3>'.NL;
984 else if (isset ($classlist[$ns]['arr'])) {
986 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h3>'.NL;
988 else if (isset ($classlist[$ns]['ptr'])) {
990 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h3>'.NL;
994 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h3>'.NL;
997 # show original C++ declaration
998 if (isset ($cl['cdecl'])) {
999 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['cdecl']).'</p>'.NL;
1002 # print class inheritance (direct parent *name* only)
1003 $inherited = array ();
1004 $isa = traverse_parent ($ns, $inherited);
1005 if (!empty ($isa)) {
1006 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
1008 echo '<div class="clear"></div>'.NL;
1011 # class documentation (if any)
1012 echo format_doxyclass ($cl);
1014 # member documentation
1016 echo '<p class="classinfo">This class object is only used indirectly as return-value and function-parameter. It provides no methods by itself.</p>'.NL;
1018 echo '<table class="classmembers">'.NL;
1020 echo ' </table>'.NL;
1023 # traverse parent classes (all inherited members)
1024 foreach ($inherited as $pns => $pcl) {
1025 $tbl = format_class_members ($pns, $pcl, $dups);
1026 if (!empty ($tbl)) {
1027 echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
1028 echo '<table class="classmembers">'.NL;
1035 ####################
1036 # Enum and Constants
1038 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
1039 foreach ($constlist as $ns => $cs) {
1040 echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h3>'.NL;
1041 echo '<ul class="enum">'.NL;
1042 foreach ($cs as $c) {
1043 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
1048 ######################
1049 # Index of all classes
1051 echo '<h2 id="h_index" >Class Index</h2>'.NL;
1052 echo '<ul class="classindex">'.NL;
1053 foreach ($classlist as $ns => $cl) {
1054 echo '<li>'.typelink($ns).'</li>'.NL;
1059 # see how far there is still to go...
1060 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
1061 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
1065 <div class="luafooter">Ardour <?=$ardourversion?> - <?=date('r')?></div>
1069 echo '<!-- #### SNIP #### !-->'.NL;