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);
109 # check Class declarations first
110 foreach (array_merge ($classes, $consts) as $b) {
111 if ($b['ldec'] == $arg) {
112 return array ($b['lua'] => $flags);
116 # strip class pointers -- TODO Check C'tor for given class
117 $arg = preg_replace ('/[&*]*$/', '', $argtype);
118 foreach (array_merge ($classes, $consts) as $b) {
119 if ($b['ldec'] == $arg) {
120 return array ($b['lua'] => $flags);
124 return array ($argtype => ($flags | 4));
126 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
130 function stripclass ($classname, $name) {
132 if (strpos ($name, $classname) !== 0) {
133 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
135 return substr ($name, strlen ($classname));
138 function datatype ($decl) {
139 # TODO handle spaces in type. Works because
140 # we don't yet have templated types (with_space <here >)
141 return substr ($decl, 0, strrpos ($decl, ' '));
144 function luafn2class ($lua) {
145 return substr ($lua, 0, strrpos ($lua, ':'));
148 function luafn2name ($lua) {
149 $fn = strrpos ($lua, ':');
150 if ($fn !== 0 && strlen($lua) > $fn + 1) {
151 return substr ($lua, $fn + 1);
153 my_die ('invalid class prefix: '. $name);
157 function checkclass ($b) {
159 if (!isset ($classlist[luafn2class ($b['lua'])])) {
160 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
164 # parse functions argument list to lua-names
165 function decl2args ($decl) {
166 $start = strrpos ($decl, '(');
167 $end = strrpos ($decl, ')');
168 $args = substr ($decl, $start + 1, $end - $start - 1);
169 $arglist = preg_split ('/, */', $args);
171 foreach ($arglist as $a) {
172 if (empty ($a)) { continue; }
173 $rv[] = arg2lua ($a);
178 function canonical_ctor ($b) {
180 if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
181 $lc = luafn2class ($b['lua']);
182 $cn = str_replace (':', '::', $lc);
183 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
184 $rv = $cn . '::'. $fn . $matches[2];
189 function canonical_decl ($b) {
192 # match clang's declatation format
193 if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
194 if (strpos ($b['type'], 'Free Function') !== false) {
195 $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
197 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
198 $rv = $matches[1] . $fn . '(';
199 $arglist = preg_split ('/, */', $matches[2]);
201 foreach ($arglist as $a) {
202 if (!$first) { $rv .= ', '; }; $first = false;
203 if (empty ($a)) { continue; }
204 $a = preg_replace ('/([^>]) >/', '$1>', $a);
205 $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
206 $a = preg_replace ('/([^ ])&/', '$1 &', $a);
207 $a = preg_replace ('/std::vector<([^>]*)> const/', 'const std::vector<$1>', $a);
208 $a = str_replace ('std::vector', 'vector', $a);
209 $a = str_replace ('vector', 'std::vector', $a);
210 $a = str_replace ('std::string', 'string', $a);
211 $a = str_replace ('string const', 'const string', $a);
212 $a = str_replace ('string', 'std::string', $a);
220 ################################################################################
221 # step 1: build class indices
223 foreach ($doc as $b) {
224 if (strpos ($b['type'], "[C] ") === 0) {
226 $classlist[$b['lua']] = $b;
227 if (strpos ($b['type'], 'Pointer Class') === false) {
228 $classdecl[$b['ldec']] = $b;
233 foreach ($classes as $c) {
234 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
235 if (isset ($c['parent'])) {
236 if (isset ($classdecl[$c['parent']])) {
237 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
239 my_die ('unknown parent class: ' . print_r ($c, true));
244 # step 2: extract constants/enum
245 foreach ($doc as $b) {
246 switch ($b['type']) {
247 case "Constant/Enum":
248 case "Constant/Enum Member":
249 if (strpos ($b['ldec'], '::') === false) {
250 # for extern c enums, use the Lua Namespace
251 $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
253 $ns = str_replace ('::', ':', $b['ldec']);
254 $constlist[$ns][] = $b;
264 # step 3: process functions
265 foreach ($doc as $b) {
266 switch ($b['type']) {
268 case "Weak/Shared Pointer Constructor":
270 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
271 'name' => luafn2class ($b['lua']),
272 'args' => decl2args ($b['ldec']),
273 'cand' => canonical_ctor ($b),
277 case "Weak/Shared Pointer NIL Constructor":
279 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
280 'name' => luafn2class ($b['lua']),
281 'args' => decl2args ($b['ldec']),
282 'cand' => canonical_ctor ($b),
288 $classlist[luafn2class ($b['lua'])]['props'][] = array (
290 'ret' => arg2lua (datatype ($b['ldec']))
295 $classlist[luafn2class ($b['lua'])]['data'][] = array (
297 'ret' => arg2lua (datatype ($b['ldec']))
300 case "Static C Function":
302 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
303 # special case ARDOUR:DataType convenience c'tor
305 $ret = array (luafn2class ($b['lua']) => 0);
306 $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
308 my_die ('unhandled Static C: ' . print_r($b, true));
310 $classlist[luafn2class ($b['lua'])]['func'][] = array (
321 # we required C functions to be in a class namespace
322 case "Ext C Function":
324 $args = array (array ('--lua--' => 0));
325 $ret = array ('...' => 0);
326 $ns = luafn2class ($b['lua']);
327 $cls = $classlist[$ns];
328 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
329 # std::vector, std::list types
330 switch (stripclass($ns, $b['lua'])) {
332 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
333 $args = array (arg2lua ($templ[1], 2));
334 $ret = array ('LuaTable' => 0);
338 $ret = array ('LuaIter' => 0);
342 $ret = array ('LuaTable' => 0);
347 } else if (strpos ($cls['type'], ' Array') !== false) {
348 # catches C:FloatArray, C:IntArray
349 $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
350 switch (stripclass($ns, $b['lua'])) {
353 $ret = array ('LuaMetaTable' => 0);
357 $ret = array ('LuaTable' => 0);
360 $args = array (array ('LuaTable {'.$templ.'}' => 0));
361 $ret = array ('void' => 0);
367 $classlist[luafn2class ($b['lua'])]['func'][] = array (
374 'cand' => canonical_decl ($b)
377 case "Free C Function":
378 $funclist[luafn2class ($b['lua'])][] = array (
385 'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
388 case "Free Function":
389 case "Free Function RefReturn":
390 $funclist[luafn2class ($b['lua'])][] = array (
393 'args' => decl2args ($b['ldec']),
394 'ret' => arg2lua ($b['ret']),
395 'ref' => (strpos ($b['type'], "RefReturn") !== false),
396 'cand' => canonical_decl ($b)
399 case "Member Function":
400 case "Member Function RefReturn":
401 case "Member Pointer Function":
402 case "Weak/Shared Pointer Function":
403 case "Weak/Shared Pointer Function RefReturn":
404 case "Weak/Shared Null Check":
405 case "Static Member Function":
407 $classlist[luafn2class ($b['lua'])]['func'][] = array (
410 'args' => decl2args ($b['ldec']),
411 'ret' => arg2lua ($b['ret']),
412 'ref' => (strpos ($b['type'], "RefReturn") !== false),
413 'cand' => canonical_decl ($b)
417 case "Weak/Shared Pointer Cast":
419 $classlist[luafn2class ($b['lua'])]['cast'][] = array (
422 'args' => decl2args ($b['ldec']),
423 'ret' => arg2lua ($b['ret']),
424 'ref' => (strpos ($b['type'], "RefReturn") !== false),
425 'cand' => canonical_decl ($b)
428 case "Constant/Enum":
429 case "Constant/Enum Member":
430 # already handled -> $consts
433 if (strpos ($b['type'], "[C] ") !== 0) {
434 my_die ('unhandled type: ' . $b['type']);
441 # step 4: collect/group/sort
443 # step 4a: unify weak/shared Ptr classes
444 foreach ($classlist as $ns => $cl) {
445 if (strpos ($cl['type'], ' Array') !== false) {
446 $classlist[$ns]['arr'] = true;
447 $classlist[$ns]['cdecl'] = $cl['decl'];
450 foreach ($classes as $c) {
451 if ($c['lua'] == $ns) {
452 if (strpos ($c['type'], 'Pointer Class') !== false) {
453 $classlist[$ns]['ptr'] = true;
454 $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
457 $classlist[$ns]['cdecl'] = $c['decl'];
463 # step4b: sanity check
464 foreach ($classlist as $ns => $cl) {
465 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
466 my_die ('missing parent class: ' . print_r ($cl, true));
470 # step 4c: merge free functions into classlist
471 foreach ($funclist as $ns => $fl) {
472 if (isset ($classlist[$ns])) {
473 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
475 $classlist[$ns]['func'] = $fl;
476 $classlist[$ns]['free'] = true;
479 # step 4d: order to chaos
480 # no array_multisort() here, sub-types are sorted after merging parents
484 ################################################################################
485 ################################################################################
486 ################################################################################
489 #### -- split here -- ####
491 # from here on, only $classlist and $constlist arrays are relevant.
492 # we also pull in C++ header annotation from doxygen to $api
495 # read documentation from doxygen
496 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
498 foreach (json_decode ($json, true) as $a) {
499 if (!isset ($a['decl'])) { continue; }
500 if (empty ($a['decl'])) { continue; }
501 $canon = str_replace (' *', '*', $a['decl']);
505 # keep track of found/missing doc
509 # retrive a value from $api
510 function doxydoc ($canonical_declaration) {
514 if (isset ($api[$canonical_declaration])) {
516 return $api[$canonical_declaration]['doc'];
518 // remove template namespace e.g.
519 // "ARDOUR::Track::bounceable(boost::shared_ptr<ARDOUR::Processor>"
520 // "ARDOUR::Track::bounceable(boost::shared_ptr<Processor>"
521 $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration);
522 if (isset ($api[$cn])) {
524 return $api[$cn]['doc'];
526 #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG
532 ################################################################################
534 ################################################################################
537 ################################################################################
541 # constructors, enums (constants) use a dot. (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
542 function ctorname ($name) {
543 return htmlentities (str_replace (':', '.', $name));
546 # strip class prefix (e.g "Evoral:MidiEvent:channel" -> "channel")
547 function shortname ($name) {
548 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
551 # retrieve variable name from array["VARNAME"] => FLAGS
552 function varname ($a) {
553 return array_keys ($a)[0];
556 # recusively collect class parents (derived classes)
557 function traverse_parent ($ns, &$inherited) {
560 if (isset ($classlist[$ns]['luaparent'])) {
561 $parents = array_unique ($classlist[$ns]['luaparent']);
563 foreach ($parents as $p) {
564 if (!empty ($rv)) { $rv .= ', '; }
565 if ($p == $ns) { continue; }
566 $rv .= typelink ($p);
567 $inherited[$p] = $classlist[$p];
568 traverse_parent ($p, $inherited);
574 # create a cross-reference to a type (class or enum)
575 # *all* <a> links are generated here, currently anchors on a single page.
576 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
579 if (isset($classlist[$a]['free'])) {
580 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
581 } else if (in_array ($a, array_keys ($classlist))) {
582 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
583 } else if (in_array ($a, array_keys ($constlist))) {
584 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
586 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
590 # output format function arguments
591 function format_args ($args) {
592 $rv = '<span class="functionargs"> (';
594 foreach ($args as $a) {
595 if (!$first) { $rv .= ', '; }; $first = false;
596 $flags = $a[varname ($a)];
598 $rv .= '<span>'.varname ($a).'</span>';
600 else if ($flags & 2) {
601 $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
603 elseif ($flags & 1) {
604 $rv .= typelink (varname ($a), true, 'em', '', '&');
607 $rv .= typelink (varname ($a), true, 'em');
614 # format doxygen documentation for class-definition
615 function format_doxyclass ($cl) {
617 if (isset ($cl['decl'])) {
618 $doc = doxydoc ($cl['decl']);
620 $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
626 # format doxygen documentation for class-members
627 function format_doxydoc ($f) {
629 if (isset ($f['cand'])) {
630 $doc = doxydoc ($f['cand']);
632 $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
633 $rv.= '</div></td></tr>'.NL;
634 } else if (0) { # debug
635 $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
636 $rv.= '</td></tr>'.NL;
642 # usort() callback for class-members
643 function name_sort_cb ($a, $b) {
644 return strcmp ($a['name'], $b['name']);
647 # main output function for every class
648 function format_class_members ($ns, $cl, &$dups) {
650 # print contructor - if any
651 if (isset ($cl['ctor'])) {
652 usort ($cl['ctor'], 'name_sort_cb');
653 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
654 foreach ($cl['ctor'] as $f) {
657 $rv.= '<td class="def"><abbr title="Nil Pointer Constructor">ℵ</abbr></td>';
659 $rv.= '<td class="def">ℂ</td>';
661 $rv.= '<td class="decl">';
662 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
663 $rv.= format_args ($f['args']);
664 $rv.= '</td><td class="fill"></td></tr>'.NL;
665 # doxygen documentation (may be empty)
666 $rv.= format_doxydoc($f);
670 # strip duplicates (inherited or derived methods)
671 # e.g AudioTrack -> Track -> Route -> SessionObject -> Stateful
672 # all 5 have "isnil()"
674 if (isset ($cl['func'])) {
675 foreach ($cl['func'] as $f) {
676 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
681 # print methods - if any
682 if (count ($nondups) > 0) {
683 usort ($nondups, 'name_sort_cb');
684 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
685 foreach ($nondups as $f) {
686 $dups[] = stripclass ($ns, $f['name']);
688 $rv.= ' <tr><td class="def">';
689 if ($f['ref'] && isset ($f['ext'])) {
690 # external C functions
691 $rv.= '<em>'.varname ($f['ret']).'</em>';
692 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
693 # void functions with reference args
694 $rv.= '<em>LuaTable</em>(...)';
695 } elseif ($f['ref']) {
696 # functions with reference args and return value
697 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
699 # normal class members
700 $rv.= typelink (varname ($f['ret']), true, 'em');
702 # function declaration and arguments
703 $rv.= '</td><td class="decl">';
704 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
705 $rv.= format_args ($f['args']);
706 $rv.= '</td><td class="fill"></td></tr>'.NL;
707 # doxygen documentation (may be empty)
708 $rv.= format_doxydoc($f);
711 # print cast - if any
712 if (isset ($cl['cast'])) {
713 usort ($cl['cast'], 'name_sort_cb');
714 $rv.= ' <tr><th colspan="3">Cast</th></tr>'.NL;
715 foreach ($cl['cast'] as $f) {
716 $rv.= ' <tr><td class="def">';
717 $rv.= typelink (varname ($f['ret']), true, 'em');
718 # function declaration and arguments
719 $rv.= '</td><td class="decl">';
720 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
721 $rv.= format_args ($f['args']);
722 $rv.= '</td><td class="fill"></td></tr>'.NL;
723 # doxygen documentation (may be empty)
724 $rv.= format_doxydoc($f);
728 # print properties - if any
729 if (isset ($cl['props'])) {
730 usort ($cl['props'], 'name_sort_cb');
731 $rv.= ' <tr><th colspan="3">Properties</th></tr>'.NL;
732 foreach ($cl['props'] as $f) {
733 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
734 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
735 $rv.= '</td><td class="fill"></td></tr>'.NL;
739 # print data members - if any
740 if (isset ($cl['data'])) {
741 usort ($cl['data'], 'name_sort_cb');
742 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
743 foreach ($cl['data'] as $f) {
744 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
745 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
746 $rv.= '</td><td class="fill"></td></tr>'.NL;
747 $f['cand'] = str_replace (':', '::', $f['name']);
748 $rv.= format_doxydoc($f);
755 ################################################################################
761 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
763 <title>Ardour Lua Bindings</title>
764 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
765 <style type="text/css">
766 div.header { text-align:center; }
767 div.header h2 { margin:0; }
768 div.header p { margin:.25em; text-align:center; }
769 div.luafooter { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
770 #luaref { max-width:60em; margin: 1em auto; }
772 #luaref h2 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
773 #luaref h3.cls { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
774 #luaref h3.cls abbr { text-decoration:none; cursor:default; }
775 #luaref h4.cls { margin:1em 0 0 0; }
776 #luaref h3.class { background-color: #aaee66; }
777 #luaref h3.enum { background-color: #aaaaaa; }
778 #luaref h3.pointerclass { background-color: #eeaa66; }
779 #luaref h3.array { background-color: #66aaee; }
780 #luaref h3.opaque { background-color: #6666aa; }
781 #luaref p { text-align: justify; }
782 #luaref p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
783 #luaref ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
784 #luaref div.clear { clear:both; }
785 #luaref p.classinfo { margin: .25em 0; }
786 #luaref div.code { width:80%; margin:.5em auto; }
787 #luaref div.code div { width:45%; }
788 #luaref div.code pre { line-height: 1.2em; margin: .25em 0; }
789 #luaref div.code samp { color: green; font-weight: bold; background-color: #eee; }
790 #luaref div.classdox { padding: .1em 1em; }
791 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
792 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
793 #luaref div.classdox { padding: .1em 1em; }
794 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
795 #luaref table.classmembers { width: 100%; }
796 #luaref table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
797 #luaref table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap; }
798 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
799 #luaref table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
800 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
801 #luaref table.classmembers td.doc p { margin: .5em 0; }
802 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
803 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
804 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
805 #luaref table.classmembers td.doc dt { font-style: italic; }
806 #luaref table.classmembers td.fill { width: 99%; }
807 #luaref table.classmembers span.em { font-style: italic; }
808 #luaref span.functionname abbr { text-decoration:none; cursor:default; }
809 #luaref table.classmembers td.def abbr { text-decoration:none; cursor:default; }
814 <h2>Ardour Lua Bindings</h2>
816 <a href="#h_classes">Class Documentation</a>
818 <a href="#h_enum">Enum/Constants</a>
820 <a href="#h_index">Index</a>
824 <!-- #### SNIP #### !-->
833 This documentation is far from complete may be inaccurate and subject to change.
844 ################################################################################
845 # some general documentation -- should really go elsehere
849 <h2 id="h_intro">Overview</h2>
851 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
852 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
855 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
856 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
857 <?=typelink('LuaSignal:Set')?> etc.
860 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
862 <h3>Short introduction to Ardour classes</h3>
864 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
865 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
866 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
867 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
870 Operations are performed on objects. One gets a reference to an object and then calls a method.
871 e.g <code>obj = Session:route_by_name("Audio") obj:set_name("Guitar")</code>.
874 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.
877 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.
880 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:
881 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
883 <h3>Pass by Reference</h3>
885 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
886 All parameters passed to a C++ method which uses references are returned as Lua Table.
887 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
891 <div style="float:left;">C++
893 <pre><code class="cxx">void set_ref (int& var, long& val)
895 printf ("%d %ld\n", var, val);
902 <div style="float:right;">Lua
904 <pre><code class="lua">local var = 0;
905 ref = set_ref (var, 2);
906 -- output from C++ printf()
907 </code><samp class="lua">0 2</samp><code>
908 -- var is still 0 here
909 print (ref[1], ref[2])
910 </code><samp class="lua">5 7</samp></pre>
914 <div class="clear"></div>
916 <div style="float:left;">
918 <pre><code class="cxx">int set_ref2 (int &var, std::string unused)
926 <div style="float:right;">
927 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
928 print (rv, ref[1], ref[2])
929 </code><samp class="lua">3 5 hello</samp></pre>
932 <div class="clear"></div>
934 <h3>Pointer Classes</h3>
936 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
937 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
938 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
941 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
942 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.
945 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
946 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
947 may not be able to find the given plugin and hence cannot create an object.
950 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
951 The object may vanish at any time.
952 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
953 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
956 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
957 Below they're inidicated in orange and have an arrow to indicate the pointer type.
958 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.
964 #################################
965 # Main output function -- Classes
967 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
968 foreach ($classlist as $ns => $cl) {
970 $tbl = format_class_members ($ns, $cl, $dups);
972 # format class title - depending on type
974 # classes with no members (no ctor, no methods, no data)
975 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h3>'.NL;
977 else if (isset ($classlist[$ns]['free'])) {
978 # free functions (no class)
979 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h3>'.NL;
981 else if (isset ($classlist[$ns]['arr'])) {
983 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h3>'.NL;
985 else if (isset ($classlist[$ns]['ptr'])) {
987 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h3>'.NL;
991 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h3>'.NL;
994 # show original C++ declaration
995 if (isset ($cl['cdecl'])) {
996 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['cdecl']).'</p>'.NL;
999 # print class inheritance (direct parent *name* only)
1000 $inherited = array ();
1001 $isa = traverse_parent ($ns, $inherited);
1002 if (!empty ($isa)) {
1003 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
1005 echo '<div class="clear"></div>'.NL;
1008 # class documentation (if any)
1009 echo format_doxyclass ($cl);
1011 # member documentation
1013 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;
1015 echo '<table class="classmembers">'.NL;
1017 echo ' </table>'.NL;
1020 # traverse parent classes (all inherited members)
1021 foreach ($inherited as $pns => $pcl) {
1022 $tbl = format_class_members ($pns, $pcl, $dups);
1023 if (!empty ($tbl)) {
1024 echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
1025 echo '<table class="classmembers">'.NL;
1032 ####################
1033 # Enum and Constants
1035 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
1036 foreach ($constlist as $ns => $cs) {
1037 echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h3>'.NL;
1038 echo '<ul class="enum">'.NL;
1039 foreach ($cs as $c) {
1040 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
1045 ######################
1046 # Index of all classes
1048 echo '<h2 id="h_index" >Class Index</h2>'.NL;
1049 echo '<ul class="classindex">'.NL;
1050 foreach ($classlist as $ns => $cl) {
1051 echo '<li>'.typelink($ns).'</li>'.NL;
1056 # see how far there is still to go...
1057 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
1058 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
1062 <div class="luafooter">Ardour <?=$ardourversion?> - <?=date('r')?></div>
1066 echo '<!-- #### SNIP #### !-->'.NL;