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 if (isset ($b['ret'])) {
42 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
47 if (count ($doc) == 0) {
48 fwrite (STDERR, "Failed to read luadoc.json\n");
52 ################################################################################
53 ## Global result variables
54 ################################################################################
56 $classlist = array ();
57 $constlist = array ();
60 ################################################################################
61 ## Pre-process the data, collect functions, parse arguments, cross reference
62 ################################################################################
65 ################################################################################
66 # some internal helper functions first
72 function my_die ($msg) {
73 fwrite (STDERR, $msg."\n");
77 ##function ptr_strip ($ctype) {
78 # # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
79 # # -> std::list<ARDOUR::Route>
80 # $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
81 # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
84 function arg2lua ($argtype, $flags = 0) {
88 # LuaBridge abstracts C++ references
89 $flags |= preg_match ('/&$/', $argtype);
90 $arg = preg_replace ('/&$/', '', $argtype);
91 $arg = preg_replace ('/ $/', '', $arg);
93 # filter out basic types
94 $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'short', 'long', 'unsigned int', 'unsigned short', 'unsigned long', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
95 if (in_array ($arg, $builtin)) {
96 return array ($arg => $flags);
99 # check Class declarations first
100 foreach (array_merge ($classes, $consts) as $b) {
101 if ($b['ldec'] == $arg) {
102 return array ($b['lua'] => $flags);
106 # strip class pointers -- TODO Check C'tor for given class
107 $arg = preg_replace ('/[&*]*$/', '', $argtype);
108 foreach (array_merge ($classes, $consts) as $b) {
109 if ($b['ldec'] == $arg) {
110 return array ($b['lua'] => $flags);
114 return array ($argtype => ($flags | 4));
116 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
120 function stripclass ($classname, $name) {
122 if (strpos ($name, $classname) !== 0) {
123 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
125 return substr ($name, strlen ($classname));
128 function datatype ($decl) {
129 # TODO handle spaces in type. Works because
130 # we don't yet have templated types (with_space <here >)
131 return substr ($decl, 0, strrpos ($decl, ' '));
134 function luafn2class ($lua) {
135 return substr ($lua, 0, strrpos ($lua, ':'));
138 function luafn2name ($lua) {
139 $fn = strrpos ($lua, ':');
140 if ($fn !== 0 && strlen($lua) > $fn + 1) {
141 return substr ($lua, $fn + 1);
143 my_die ('invalid class prefix: '. $name);
147 function checkclass ($b) {
149 if (!isset ($classlist[luafn2class ($b['lua'])])) {
150 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
154 # parse functions argument list to lua-names
155 function decl2args ($decl) {
156 $start = strrpos ($decl, '(');
157 $end = strrpos ($decl, ')');
158 $args = substr ($decl, $start + 1, $end - $start - 1);
159 $arglist = preg_split ('/, */', $args);
161 foreach ($arglist as $a) {
162 if (empty ($a)) { continue; }
163 $rv[] = arg2lua ($a);
168 function canonical_ctor ($b) {
170 if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
171 $lc = luafn2class ($b['lua']);
172 $cn = str_replace (':', '::', $lc);
173 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
174 $rv = $cn . '::'. $fn . $matches[2];
179 function canonical_decl ($b) {
182 # match clang's declatation format
183 if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
184 if (strpos ($b['type'], 'Free Function') !== false) {
185 $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
187 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
188 $rv = $matches[1] . $fn . '(';
189 $arglist = preg_split ('/, */', $matches[2]);
191 foreach ($arglist as $a) {
192 if (!$first) { $rv .= ', '; }; $first = false;
193 if (empty ($a)) { continue; }
194 $a = preg_replace ('/([^>]) >/', '$1>', $a);
195 $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
196 $a = preg_replace ('/([^ ])&/', '$1 &', $a);
197 $a = str_replace ('vector', 'std::vector', $a);
198 $a = str_replace ('std::string', 'string', $a);
199 $a = str_replace ('string const', 'const string', $a);
200 $a = str_replace ('string', 'std::string', $a);
208 ################################################################################
209 # step 1: build class indices
211 foreach ($doc as $b) {
212 if (strpos ($b['type'], "[C] ") === 0) {
214 $classlist[$b['lua']] = $b;
215 if (strpos ($b['type'], 'Pointer Class') === false) {
216 $classdecl[$b['ldec']] = $b;
221 foreach ($classes as $c) {
222 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
223 if (isset ($c['parent'])) {
224 if (isset ($classdecl[$c['parent']])) {
225 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
227 my_die ('unknown parent class: ' . print_r ($c, true));
232 # step 2: extract constants/enum
233 foreach ($doc as $b) {
234 switch ($b['type']) {
235 case "Constant/Enum":
236 case "Constant/Enum Member":
237 if (strpos ($b['ldec'], '::') === false) {
238 # for extern c enums, use the Lua Namespace
239 $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
241 $ns = str_replace ('::', ':', $b['ldec']);
242 $constlist[$ns][] = $b;
252 # step 3: process functions
253 foreach ($doc as $b) {
254 switch ($b['type']) {
256 case "Weak/Shared Pointer Constructor":
258 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
259 'name' => luafn2class ($b['lua']),
260 'args' => decl2args ($b['ldec']),
261 'cand' => canonical_ctor ($b)
266 $classlist[luafn2class ($b['lua'])]['props'][] = array (
268 'ret' => arg2lua (datatype ($b['ldec']))
273 $classlist[luafn2class ($b['lua'])]['data'][] = array (
275 'ret' => arg2lua (datatype ($b['ldec']))
278 case "Static C Function":
280 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
281 # special case ARDOUR:DataType convenience c'tor
283 $ret = array (luafn2class ($b['lua']) => 0);
284 $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
286 my_die ('unhandled Static C: ' . print_r($b, true));
288 $classlist[luafn2class ($b['lua'])]['func'][] = array (
299 # we required C functions to be in a class namespace
300 case "Ext C Function":
302 $args = array (array ('--lua--' => 0));
303 $ret = array ('...' => 0);
304 $ns = luafn2class ($b['lua']);
305 $cls = $classlist[$ns];
306 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
307 # std::vector, std::list types
308 switch (stripclass($ns, $b['lua'])) {
310 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
311 $args = array (arg2lua ($templ[1], 2));
312 $ret = array ('LuaTable' => 0);
316 $ret = array ('LuaIter' => 0);
320 $ret = array ('LuaTable' => 0);
325 } else if (strpos ($cls['type'], ' Array') !== false) {
326 # catches C:FloatArray, C:IntArray
327 $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
328 switch (stripclass($ns, $b['lua'])) {
331 $ret = array ('LuaMetaTable' => 0);
335 $ret = array ('LuaTable' => 0);
338 $args = array (array ('LuaTable {'.$templ.'}' => 0));
339 $ret = array ('void' => 0);
345 $classlist[luafn2class ($b['lua'])]['func'][] = array (
352 'cand' => canonical_decl ($b)
355 case "Free C Function":
356 $funclist[luafn2class ($b['lua'])][] = array (
363 'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
366 case "Free Function":
367 case "Free Function RefReturn":
368 $funclist[luafn2class ($b['lua'])][] = array (
371 'args' => decl2args ($b['ldec']),
372 'ret' => arg2lua ($b['ret']),
373 'ref' => (strpos ($b['type'], "RefReturn") !== false),
374 'cand' => canonical_decl ($b)
377 case "Member Function":
378 case "Member Function RefReturn":
379 case "Member Pointer Function":
380 case "Weak/Shared Pointer Function":
381 case "Weak/Shared Pointer Function RefReturn":
382 case "Weak/Shared Null Check":
383 case "Static Member Function":
385 $classlist[luafn2class ($b['lua'])]['func'][] = array (
388 'args' => decl2args ($b['ldec']),
389 'ret' => arg2lua ($b['ret']),
390 'ref' => (strpos ($b['type'], "RefReturn") !== false),
391 'cand' => canonical_decl ($b)
395 case "Weak/Shared Pointer Cast":
397 $classlist[luafn2class ($b['lua'])]['cast'][] = array (
400 'args' => decl2args ($b['ldec']),
401 'ret' => arg2lua ($b['ret']),
402 'ref' => (strpos ($b['type'], "RefReturn") !== false),
403 'cand' => canonical_decl ($b)
406 case "Constant/Enum":
407 case "Constant/Enum Member":
408 # already handled -> $consts
411 if (strpos ($b['type'], "[C] ") !== 0) {
412 my_die ('unhandled type: ' . $b['type']);
419 # step 4: collect/group/sort
421 # step 4a: unify weak/shared Ptr classes
422 foreach ($classlist as $ns => $cl) {
423 if (strpos ($cl['type'], ' Array') !== false) {
424 $classlist[$ns]['arr'] = true;
425 $classlist[$ns]['cdecl'] = $cl['decl'];
428 foreach ($classes as $c) {
429 if ($c['lua'] == $ns) {
430 if (strpos ($c['type'], 'Pointer Class') !== false) {
431 $classlist[$ns]['ptr'] = true;
432 $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
435 $classlist[$ns]['cdecl'] = $c['decl'];
441 # step4b: sanity check
442 foreach ($classlist as $ns => $cl) {
443 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
444 my_die ('missing parent class: ' . print_r ($cl, true));
448 # step 4c: merge free functions into classlist
449 foreach ($funclist as $ns => $fl) {
450 if (isset ($classlist[$ns])) {
451 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
453 $classlist[$ns]['func'] = $fl;
454 $classlist[$ns]['free'] = true;
457 # step 4d: order to chaos
458 # no array_multisort() here, sub-types are sorted after merging parents
462 ################################################################################
463 ################################################################################
464 ################################################################################
467 #### -- split here -- ####
469 # from here on, only $classlist and $constlist arrays are relevant.
470 # we also pull in C++ header annotation from doxygen to $api
473 # read documentation from doxygen
474 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
476 foreach (json_decode ($json, true) as $a) {
477 if (!isset ($a['decl'])) { continue; }
478 if (empty ($a['decl'])) { continue; }
479 $canon = str_replace (' *', '*', $a['decl']);
483 # keep track of found/missing doc
487 # retrive a value from $api
488 function doxydoc ($canonical_declaration) {
492 if (isset ($api[$canonical_declaration])) {
494 return $api[$canonical_declaration]['doc'];
496 // remove template namespace e.g.
497 // "ARDOUR::Track::bounceable(boost::shared_ptr<ARDOUR::Processor>"
498 // "ARDOUR::Track::bounceable(boost::shared_ptr<Processor>"
499 $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration);
500 if (isset ($api[$cn])) {
502 return $api[$cn]['doc'];
504 #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG
510 ################################################################################
512 ################################################################################
515 ################################################################################
519 # constructors, enums (constants) use a dot. (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
520 function ctorname ($name) {
521 return htmlentities (str_replace (':', '.', $name));
524 # strip class prefix (e.g "Evoral:MidiEvent:channel" -> "channel")
525 function shortname ($name) {
526 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
529 # retrieve variable name from array["VARNAME"] => FLAGS
530 function varname ($a) {
531 return array_keys ($a)[0];
534 # recusively collect class parents (derived classes)
535 function traverse_parent ($ns, &$inherited) {
538 if (isset ($classlist[$ns]['luaparent'])) {
539 $parents = array_unique ($classlist[$ns]['luaparent']);
541 foreach ($parents as $p) {
542 if (!empty ($rv)) { $rv .= ', '; }
543 $rv .= typelink ($p);
544 $inherited[$p] = $classlist[$p];
545 traverse_parent ($p, $inherited);
551 # create a cross-reference to a type (class or enum)
552 # *all* <a> links are generated here, currently anchors on a single page.
553 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
556 if (isset($classlist[$a]['free'])) {
557 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
558 } else if (in_array ($a, array_keys ($classlist))) {
559 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
560 } else if (in_array ($a, array_keys ($constlist))) {
561 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
563 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
567 # output format function arguments
568 function format_args ($args) {
569 $rv = '<span class="functionargs"> (';
571 foreach ($args as $a) {
572 if (!$first) { $rv .= ', '; }; $first = false;
573 $flags = $a[varname ($a)];
575 $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
577 elseif ($flags & 1) {
578 $rv .= typelink (varname ($a), true, 'em', '', '&');
581 $rv .= typelink (varname ($a), true, 'em');
588 # format doxygen documentation for class-definition
589 function format_doxyclass ($cl) {
591 if (isset ($cl['decl'])) {
592 $doc = doxydoc ($cl['decl']);
594 $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
600 # format doxygen documentation for class-members
601 function format_doxydoc ($f) {
603 if (isset ($f['cand'])) {
604 $doc = doxydoc ($f['cand']);
606 $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
607 $rv.= '</div></td></tr>'.NL;
608 } else if (0) { # debug
609 $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
610 $rv.= '</td></tr>'.NL;
616 # usort() callback for class-members
617 function name_sort_cb ($a, $b) {
618 return strcmp ($a['name'], $b['name']);
621 # main output function for every class
622 function format_class_members ($ns, $cl, &$dups) {
624 # print contructor - if any
625 if (isset ($cl['ctor'])) {
626 usort ($cl['ctor'], 'name_sort_cb');
627 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
628 foreach ($cl['ctor'] as $f) {
629 $rv.= ' <tr><td class="def">ℂ</td><td class="decl">';
630 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
631 $rv.= format_args ($f['args']);
632 $rv.= '</td><td class="fill"></td></tr>'.NL;
633 # doxygen documentation (may be empty)
634 $rv.= format_doxydoc($f);
638 # strip duplicates (inherited or derived methods)
639 # e.g AudioTrack -> Track -> Route -> SessionObject -> Stateful
640 # all 5 have "isnil()"
642 if (isset ($cl['func'])) {
643 foreach ($cl['func'] as $f) {
644 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
649 # print methods - if any
650 if (count ($nondups) > 0) {
651 usort ($nondups, 'name_sort_cb');
652 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
653 foreach ($nondups as $f) {
654 $dups[] = stripclass ($ns, $f['name']);
656 $rv.= ' <tr><td class="def">';
657 if ($f['ref'] && isset ($f['ext'])) {
658 # external C functions
659 $rv.= '<em>'.varname ($f['ret']).'</em>';
660 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
661 # void functions with reference args
662 $rv.= '<em>LuaTable</em>(...)';
663 } elseif ($f['ref']) {
664 # functions with reference args and return value
665 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
667 # normal class members
668 $rv.= typelink (varname ($f['ret']), true, 'em');
670 # function declaration and arguments
671 $rv.= '</td><td class="decl">';
672 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
673 $rv.= format_args ($f['args']);
674 $rv.= '</td><td class="fill"></td></tr>'.NL;
675 # doxygen documentation (may be empty)
676 $rv.= format_doxydoc($f);
679 # print cast - if any
680 if (isset ($cl['cast'])) {
681 usort ($cl['cast'], 'name_sort_cb');
682 $rv.= ' <tr><th colspan="3">Cast</th></tr>'.NL;
683 foreach ($cl['cast'] as $f) {
684 $rv.= ' <tr><td class="def">';
685 $rv.= typelink (varname ($f['ret']), true, 'em');
686 # function declaration and arguments
687 $rv.= '</td><td class="decl">';
688 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
689 $rv.= format_args ($f['args']);
690 $rv.= '</td><td class="fill"></td></tr>'.NL;
691 # doxygen documentation (may be empty)
692 $rv.= format_doxydoc($f);
696 # print properties - if any
697 if (isset ($cl['props'])) {
698 usort ($cl['props'], 'name_sort_cb');
699 $rv.= ' <tr><th colspan="3">Properties</th></tr>'.NL;
700 foreach ($cl['props'] as $f) {
701 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
702 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
703 $rv.= '</td><td class="fill"></td></tr>'.NL;
707 # print data members - if any
708 if (isset ($cl['data'])) {
709 usort ($cl['data'], 'name_sort_cb');
710 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
711 foreach ($cl['data'] as $f) {
712 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
713 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
714 $rv.= '</td><td class="fill"></td></tr>'.NL;
721 ################################################################################
727 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
729 <title>Ardour Lua Bindings</title>
730 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
731 <style type="text/css">
732 div.header { text-align:center; }
733 div.header h2 { margin:0; }
734 div.header p { margin:.25em; text-align:center; }
735 div.luafooter { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
736 #luaref { max-width:60em; margin: 1em auto; }
738 #luaref h2 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
739 #luaref h3.cls { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
740 #luaref h3.cls abbr { text-decoration:none; cursor:default; }
741 #luaref h4.cls { margin:1em 0 0 0; }
742 #luaref h3.class { background-color: #aaee66; }
743 #luaref h3.enum { background-color: #aaaaaa; }
744 #luaref h3.pointerclass { background-color: #eeaa66; }
745 #luaref h3.array { background-color: #66aaee; }
746 #luaref h3.opaque { background-color: #6666aa; }
747 #luaref p { text-align: justify; }
748 #luaref p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
749 #luaref ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
750 #luaref div.clear { clear:both; }
751 #luaref p.classinfo { margin: .25em 0; }
752 #luaref div.code { width:80%; margin:.5em auto; }
753 #luaref div.code div { width:45%; }
754 #luaref div.code pre { line-height: 1.2em; margin: .25em 0; }
755 #luaref div.code samp { color: green; font-weight: bold; background-color: #eee; }
756 #luaref div.classdox { padding: .1em 1em; }
757 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
758 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
759 #luaref div.classdox { padding: .1em 1em; }
760 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
761 #luaref table.classmembers { width: 100%; }
762 #luaref table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
763 #luaref table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap; }
764 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
765 #luaref table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
766 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
767 #luaref table.classmembers td.doc p { margin: .5em 0; }
768 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
769 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
770 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
771 #luaref table.classmembers td.doc dt { font-style: italic; }
772 #luaref table.classmembers td.fill { width: 99%; }
773 #luaref table.classmembers span.em { font-style: italic; }
774 #luaref span.functionname abbr { text-decoration:none; cursor:default; }
779 <h2>Ardour Lua Bindings</h2>
781 <a href="#h_classes">Class Documentation</a>
783 <a href="#h_enum">Enum/Constants</a>
785 <a href="#h_index">Index</a>
789 <!-- #### SNIP #### !-->
799 title: Class Reference
803 This documentation is far from complete may be inaccurate and subject to change.
814 ################################################################################
815 # some general documentation -- should really go elsehere
819 <h2 id="h_intro">Overview</h2>
821 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
822 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
825 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
826 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
827 <?=typelink('LuaSignal:Set')?> etc.
830 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
832 <h3>Short introduction to Ardour classes</h3>
834 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
835 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
836 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
837 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
840 Operations are performed on objects. One gets a reference to an object and then calls a method.
841 e.g <code>obj = Session:route_by_name("Audio") obj:set_name("Guitar")</code>.
844 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 explicily 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.
847 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 inhertis from both Stateful and Destructible.
850 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:
851 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
853 <h3>Pass by Reference</h3>
855 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
856 All parameters passed to a C++ method which uses references are returned as Lua Table.
857 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
861 <div style="float:left;">C++
863 <pre><code class="cxx">void set_ref (int& var, long& val)
865 printf ("%d %ld\n", var, val);
872 <div style="float:right;">Lua
874 <pre><code class="lua">local var = 0;
875 ref = set_ref (var, 2);
876 -- output from C++ printf()
877 </code><samp class="lua">0 2</samp><code>
878 -- var is still 0 here
879 print (ref[1], ref[2])
880 </code><samp class="lua">5 7</samp></pre>
884 <div class="clear"></div>
886 <div style="float:left;">
888 <pre><code class="cxx">int set_ref2 (int &var, std::string unused)
896 <div style="float:right;">
897 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
898 print (rv, ref[1], ref[2])
899 </code><samp class="lua">3 5 hello</samp></pre>
902 <div class="clear"></div>
904 <h3>Pointer Classes</h3>
906 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
907 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
908 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
911 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
912 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.
915 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
916 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
917 may not be able to find the given plugin and hence cannot create an object.
920 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
921 The object may vanish at any time.
922 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
923 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
926 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
927 Below they're inidicated in orange and have an arrow to indicate the pointer type.
928 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.
934 #################################
935 # Main output function -- Classes
937 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
938 foreach ($classlist as $ns => $cl) {
940 $tbl = format_class_members ($ns, $cl, $dups);
942 # format class title - depending on type
944 # classes with no members (no ctor, no methods, no data)
945 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h3>'.NL;
947 else if (isset ($classlist[$ns]['free'])) {
948 # free functions (no class)
949 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h3>'.NL;
951 else if (isset ($classlist[$ns]['arr'])) {
953 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h3>'.NL;
955 else if (isset ($classlist[$ns]['ptr'])) {
957 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h3>'.NL;
961 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h3>'.NL;
964 # show original C++ declaration
965 if (isset ($cl['cdecl'])) {
966 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['cdecl']).'</p>'.NL;
969 # print class inheritance (direct parent *name* only)
970 $inherited = array ();
971 $isa = traverse_parent ($ns, $inherited);
973 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
975 echo '<div class="clear"></div>'.NL;
978 # class documentation (if any)
979 echo format_doxyclass ($cl);
981 # member documentation
983 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;
985 echo '<table class="classmembers">'.NL;
990 # traverse parent classes (all inherited members)
991 foreach ($inherited as $pns => $pcl) {
992 $tbl = format_class_members ($pns, $pcl, $dups);
994 echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
995 echo '<table class="classmembers">'.NL;
1002 ####################
1003 # Enum and Constants
1005 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
1006 foreach ($constlist as $ns => $cs) {
1007 echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h3>'.NL;
1008 echo '<ul class="enum">'.NL;
1009 foreach ($cs as $c) {
1010 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
1015 ######################
1016 # Index of all classes
1018 echo '<h2 id="h_index" >Class Index</h2>'.NL;
1019 echo '<ul class="classindex">'.NL;
1020 foreach ($classlist as $ns => $cl) {
1021 echo '<li>'.typelink($ns).'</li>'.NL;
1026 # see how far there is still to go...
1027 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
1028 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
1032 <div class="luafooter">Ardour <?=$ardourversion?> - <?=date('r')?></div>
1036 echo '<!-- #### SNIP #### !-->'.NL;