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 # check Class declarations first
106 foreach (array_merge ($classes, $consts) as $b) {
107 if ($b['ldec'] == $arg) {
108 return array ($b['lua'] => $flags);
112 # strip class pointers -- TODO Check C'tor for given class
113 $arg = preg_replace ('/[&*]*$/', '', $argtype);
114 foreach (array_merge ($classes, $consts) as $b) {
115 if ($b['ldec'] == $arg) {
116 return array ($b['lua'] => $flags);
120 return array ($argtype => ($flags | 4));
122 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
126 function stripclass ($classname, $name) {
128 if (strpos ($name, $classname) !== 0) {
129 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
131 return substr ($name, strlen ($classname));
134 function datatype ($decl) {
135 # TODO handle spaces in type. Works because
136 # we don't yet have templated types (with_space <here >)
137 return substr ($decl, 0, strrpos ($decl, ' '));
140 function luafn2class ($lua) {
141 return substr ($lua, 0, strrpos ($lua, ':'));
144 function luafn2name ($lua) {
145 $fn = strrpos ($lua, ':');
146 if ($fn !== 0 && strlen($lua) > $fn + 1) {
147 return substr ($lua, $fn + 1);
149 my_die ('invalid class prefix: '. $name);
153 function checkclass ($b) {
155 if (!isset ($classlist[luafn2class ($b['lua'])])) {
156 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
160 # parse functions argument list to lua-names
161 function decl2args ($decl) {
162 $start = strrpos ($decl, '(');
163 $end = strrpos ($decl, ')');
164 $args = substr ($decl, $start + 1, $end - $start - 1);
165 $arglist = preg_split ('/, */', $args);
167 foreach ($arglist as $a) {
168 if (empty ($a)) { continue; }
169 $rv[] = arg2lua ($a);
174 function canonical_ctor ($b) {
176 if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
177 $lc = luafn2class ($b['lua']);
178 $cn = str_replace (':', '::', $lc);
179 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
180 $rv = $cn . '::'. $fn . $matches[2];
185 function canonical_decl ($b) {
188 # match clang's declatation format
189 if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
190 if (strpos ($b['type'], 'Free Function') !== false) {
191 $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
193 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
194 $rv = $matches[1] . $fn . '(';
195 $arglist = preg_split ('/, */', $matches[2]);
197 foreach ($arglist as $a) {
198 if (!$first) { $rv .= ', '; }; $first = false;
199 if (empty ($a)) { continue; }
200 $a = preg_replace ('/([^>]) >/', '$1>', $a);
201 $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
202 $a = preg_replace ('/([^ ])&/', '$1 &', $a);
203 $a = str_replace ('vector', 'std::vector', $a);
204 $a = str_replace ('std::string', 'string', $a);
205 $a = str_replace ('string const', 'const string', $a);
206 $a = str_replace ('string', 'std::string', $a);
214 ################################################################################
215 # step 1: build class indices
217 foreach ($doc as $b) {
218 if (strpos ($b['type'], "[C] ") === 0) {
220 $classlist[$b['lua']] = $b;
221 if (strpos ($b['type'], 'Pointer Class') === false) {
222 $classdecl[$b['ldec']] = $b;
227 foreach ($classes as $c) {
228 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
229 if (isset ($c['parent'])) {
230 if (isset ($classdecl[$c['parent']])) {
231 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
233 my_die ('unknown parent class: ' . print_r ($c, true));
238 # step 2: extract constants/enum
239 foreach ($doc as $b) {
240 switch ($b['type']) {
241 case "Constant/Enum":
242 case "Constant/Enum Member":
243 if (strpos ($b['ldec'], '::') === false) {
244 # for extern c enums, use the Lua Namespace
245 $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
247 $ns = str_replace ('::', ':', $b['ldec']);
248 $constlist[$ns][] = $b;
258 # step 3: process functions
259 foreach ($doc as $b) {
260 switch ($b['type']) {
262 case "Weak/Shared Pointer Constructor":
264 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
265 'name' => luafn2class ($b['lua']),
266 'args' => decl2args ($b['ldec']),
267 'cand' => canonical_ctor ($b)
272 $classlist[luafn2class ($b['lua'])]['props'][] = array (
274 'ret' => arg2lua (datatype ($b['ldec']))
279 $classlist[luafn2class ($b['lua'])]['data'][] = array (
281 'ret' => arg2lua (datatype ($b['ldec']))
284 case "Static C Function":
286 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
287 # special case ARDOUR:DataType convenience c'tor
289 $ret = array (luafn2class ($b['lua']) => 0);
290 $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
292 my_die ('unhandled Static C: ' . print_r($b, true));
294 $classlist[luafn2class ($b['lua'])]['func'][] = array (
305 # we required C functions to be in a class namespace
306 case "Ext C Function":
308 $args = array (array ('--lua--' => 0));
309 $ret = array ('...' => 0);
310 $ns = luafn2class ($b['lua']);
311 $cls = $classlist[$ns];
312 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
313 # std::vector, std::list types
314 switch (stripclass($ns, $b['lua'])) {
316 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
317 $args = array (arg2lua ($templ[1], 2));
318 $ret = array ('LuaTable' => 0);
322 $ret = array ('LuaIter' => 0);
326 $ret = array ('LuaTable' => 0);
331 } else if (strpos ($cls['type'], ' Array') !== false) {
332 # catches C:FloatArray, C:IntArray
333 $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
334 switch (stripclass($ns, $b['lua'])) {
337 $ret = array ('LuaMetaTable' => 0);
341 $ret = array ('LuaTable' => 0);
344 $args = array (array ('LuaTable {'.$templ.'}' => 0));
345 $ret = array ('void' => 0);
351 $classlist[luafn2class ($b['lua'])]['func'][] = array (
358 'cand' => canonical_decl ($b)
361 case "Free C Function":
362 $funclist[luafn2class ($b['lua'])][] = array (
369 'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
372 case "Free Function":
373 case "Free Function RefReturn":
374 $funclist[luafn2class ($b['lua'])][] = array (
377 'args' => decl2args ($b['ldec']),
378 'ret' => arg2lua ($b['ret']),
379 'ref' => (strpos ($b['type'], "RefReturn") !== false),
380 'cand' => canonical_decl ($b)
383 case "Member Function":
384 case "Member Function RefReturn":
385 case "Member Pointer Function":
386 case "Weak/Shared Pointer Function":
387 case "Weak/Shared Pointer Function RefReturn":
388 case "Weak/Shared Null Check":
389 case "Static Member Function":
391 $classlist[luafn2class ($b['lua'])]['func'][] = array (
394 'args' => decl2args ($b['ldec']),
395 'ret' => arg2lua ($b['ret']),
396 'ref' => (strpos ($b['type'], "RefReturn") !== false),
397 'cand' => canonical_decl ($b)
401 case "Weak/Shared Pointer Cast":
403 $classlist[luafn2class ($b['lua'])]['cast'][] = array (
406 'args' => decl2args ($b['ldec']),
407 'ret' => arg2lua ($b['ret']),
408 'ref' => (strpos ($b['type'], "RefReturn") !== false),
409 'cand' => canonical_decl ($b)
412 case "Constant/Enum":
413 case "Constant/Enum Member":
414 # already handled -> $consts
417 if (strpos ($b['type'], "[C] ") !== 0) {
418 my_die ('unhandled type: ' . $b['type']);
425 # step 4: collect/group/sort
427 # step 4a: unify weak/shared Ptr classes
428 foreach ($classlist as $ns => $cl) {
429 if (strpos ($cl['type'], ' Array') !== false) {
430 $classlist[$ns]['arr'] = true;
431 $classlist[$ns]['cdecl'] = $cl['decl'];
434 foreach ($classes as $c) {
435 if ($c['lua'] == $ns) {
436 if (strpos ($c['type'], 'Pointer Class') !== false) {
437 $classlist[$ns]['ptr'] = true;
438 $classlist[$ns]['cdecl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
441 $classlist[$ns]['cdecl'] = $c['decl'];
447 # step4b: sanity check
448 foreach ($classlist as $ns => $cl) {
449 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
450 my_die ('missing parent class: ' . print_r ($cl, true));
454 # step 4c: merge free functions into classlist
455 foreach ($funclist as $ns => $fl) {
456 if (isset ($classlist[$ns])) {
457 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
459 $classlist[$ns]['func'] = $fl;
460 $classlist[$ns]['free'] = true;
463 # step 4d: order to chaos
464 # no array_multisort() here, sub-types are sorted after merging parents
468 ################################################################################
469 ################################################################################
470 ################################################################################
473 #### -- split here -- ####
475 # from here on, only $classlist and $constlist arrays are relevant.
476 # we also pull in C++ header annotation from doxygen to $api
479 # read documentation from doxygen
480 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
482 foreach (json_decode ($json, true) as $a) {
483 if (!isset ($a['decl'])) { continue; }
484 if (empty ($a['decl'])) { continue; }
485 $canon = str_replace (' *', '*', $a['decl']);
489 # keep track of found/missing doc
493 # retrive a value from $api
494 function doxydoc ($canonical_declaration) {
498 if (isset ($api[$canonical_declaration])) {
500 return $api[$canonical_declaration]['doc'];
502 // remove template namespace e.g.
503 // "ARDOUR::Track::bounceable(boost::shared_ptr<ARDOUR::Processor>"
504 // "ARDOUR::Track::bounceable(boost::shared_ptr<Processor>"
505 $cn = preg_replace ('/<[^>]*::([^>]*)>/', '<$1>', $canonical_declaration);
506 if (isset ($api[$cn])) {
508 return $api[$cn]['doc'];
510 #fwrite (STDERR, $canonical_declaration."\n"); # XXX DEBUG
516 ################################################################################
518 ################################################################################
521 ################################################################################
525 # constructors, enums (constants) use a dot. (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
526 function ctorname ($name) {
527 return htmlentities (str_replace (':', '.', $name));
530 # strip class prefix (e.g "Evoral:MidiEvent:channel" -> "channel")
531 function shortname ($name) {
532 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
535 # retrieve variable name from array["VARNAME"] => FLAGS
536 function varname ($a) {
537 return array_keys ($a)[0];
540 # recusively collect class parents (derived classes)
541 function traverse_parent ($ns, &$inherited) {
544 if (isset ($classlist[$ns]['luaparent'])) {
545 $parents = array_unique ($classlist[$ns]['luaparent']);
547 foreach ($parents as $p) {
548 if (!empty ($rv)) { $rv .= ', '; }
549 $rv .= typelink ($p);
550 $inherited[$p] = $classlist[$p];
551 traverse_parent ($p, $inherited);
557 # create a cross-reference to a type (class or enum)
558 # *all* <a> links are generated here, currently anchors on a single page.
559 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
562 if (isset($classlist[$a]['free'])) {
563 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
564 } else if (in_array ($a, array_keys ($classlist))) {
565 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
566 } else if (in_array ($a, array_keys ($constlist))) {
567 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
569 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
573 # output format function arguments
574 function format_args ($args) {
575 $rv = '<span class="functionargs"> (';
577 foreach ($args as $a) {
578 if (!$first) { $rv .= ', '; }; $first = false;
579 $flags = $a[varname ($a)];
581 $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
583 elseif ($flags & 1) {
584 $rv .= typelink (varname ($a), true, 'em', '', '&');
587 $rv .= typelink (varname ($a), true, 'em');
594 # format doxygen documentation for class-definition
595 function format_doxyclass ($cl) {
597 if (isset ($cl['decl'])) {
598 $doc = doxydoc ($cl['decl']);
600 $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
606 # format doxygen documentation for class-members
607 function format_doxydoc ($f) {
609 if (isset ($f['cand'])) {
610 $doc = doxydoc ($f['cand']);
612 $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
613 $rv.= '</div></td></tr>'.NL;
614 } else if (0) { # debug
615 $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
616 $rv.= '</td></tr>'.NL;
622 # usort() callback for class-members
623 function name_sort_cb ($a, $b) {
624 return strcmp ($a['name'], $b['name']);
627 # main output function for every class
628 function format_class_members ($ns, $cl, &$dups) {
630 # print contructor - if any
631 if (isset ($cl['ctor'])) {
632 usort ($cl['ctor'], 'name_sort_cb');
633 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
634 foreach ($cl['ctor'] as $f) {
635 $rv.= ' <tr><td class="def">ℂ</td><td class="decl">';
636 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
637 $rv.= format_args ($f['args']);
638 $rv.= '</td><td class="fill"></td></tr>'.NL;
639 # doxygen documentation (may be empty)
640 $rv.= format_doxydoc($f);
644 # strip duplicates (inherited or derived methods)
645 # e.g AudioTrack -> Track -> Route -> SessionObject -> Stateful
646 # all 5 have "isnil()"
648 if (isset ($cl['func'])) {
649 foreach ($cl['func'] as $f) {
650 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
655 # print methods - if any
656 if (count ($nondups) > 0) {
657 usort ($nondups, 'name_sort_cb');
658 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
659 foreach ($nondups as $f) {
660 $dups[] = stripclass ($ns, $f['name']);
662 $rv.= ' <tr><td class="def">';
663 if ($f['ref'] && isset ($f['ext'])) {
664 # external C functions
665 $rv.= '<em>'.varname ($f['ret']).'</em>';
666 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
667 # void functions with reference args
668 $rv.= '<em>LuaTable</em>(...)';
669 } elseif ($f['ref']) {
670 # functions with reference args and return value
671 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
673 # normal class members
674 $rv.= typelink (varname ($f['ret']), true, 'em');
676 # function declaration and arguments
677 $rv.= '</td><td class="decl">';
678 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
679 $rv.= format_args ($f['args']);
680 $rv.= '</td><td class="fill"></td></tr>'.NL;
681 # doxygen documentation (may be empty)
682 $rv.= format_doxydoc($f);
685 # print cast - if any
686 if (isset ($cl['cast'])) {
687 usort ($cl['cast'], 'name_sort_cb');
688 $rv.= ' <tr><th colspan="3">Cast</th></tr>'.NL;
689 foreach ($cl['cast'] as $f) {
690 $rv.= ' <tr><td class="def">';
691 $rv.= typelink (varname ($f['ret']), true, 'em');
692 # function declaration and arguments
693 $rv.= '</td><td class="decl">';
694 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
695 $rv.= format_args ($f['args']);
696 $rv.= '</td><td class="fill"></td></tr>'.NL;
697 # doxygen documentation (may be empty)
698 $rv.= format_doxydoc($f);
702 # print properties - if any
703 if (isset ($cl['props'])) {
704 usort ($cl['props'], 'name_sort_cb');
705 $rv.= ' <tr><th colspan="3">Properties</th></tr>'.NL;
706 foreach ($cl['props'] as $f) {
707 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
708 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
709 $rv.= '</td><td class="fill"></td></tr>'.NL;
713 # print data members - if any
714 if (isset ($cl['data'])) {
715 usort ($cl['data'], 'name_sort_cb');
716 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
717 foreach ($cl['data'] as $f) {
718 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
719 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
720 $rv.= '</td><td class="fill"></td></tr>'.NL;
721 $f['cand'] = str_replace (':', '::', $f['name']);
722 $rv.= format_doxydoc($f);
729 ################################################################################
735 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
737 <title>Ardour Lua Bindings</title>
738 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
739 <style type="text/css">
740 div.header { text-align:center; }
741 div.header h2 { margin:0; }
742 div.header p { margin:.25em; text-align:center; }
743 div.luafooter { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
744 #luaref { max-width:60em; margin: 1em auto; }
746 #luaref h2 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
747 #luaref h3.cls { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
748 #luaref h3.cls abbr { text-decoration:none; cursor:default; }
749 #luaref h4.cls { margin:1em 0 0 0; }
750 #luaref h3.class { background-color: #aaee66; }
751 #luaref h3.enum { background-color: #aaaaaa; }
752 #luaref h3.pointerclass { background-color: #eeaa66; }
753 #luaref h3.array { background-color: #66aaee; }
754 #luaref h3.opaque { background-color: #6666aa; }
755 #luaref p { text-align: justify; }
756 #luaref p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
757 #luaref ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
758 #luaref div.clear { clear:both; }
759 #luaref p.classinfo { margin: .25em 0; }
760 #luaref div.code { width:80%; margin:.5em auto; }
761 #luaref div.code div { width:45%; }
762 #luaref div.code pre { line-height: 1.2em; margin: .25em 0; }
763 #luaref div.code samp { color: green; font-weight: bold; background-color: #eee; }
764 #luaref div.classdox { padding: .1em 1em; }
765 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
766 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
767 #luaref div.classdox { padding: .1em 1em; }
768 #luaref div.classdox p { margin: .5em 0 .5em .6em; }
769 #luaref table.classmembers { width: 100%; }
770 #luaref table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
771 #luaref table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap; }
772 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
773 #luaref table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
774 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
775 #luaref table.classmembers td.doc p { margin: .5em 0; }
776 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
777 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
778 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
779 #luaref table.classmembers td.doc dt { font-style: italic; }
780 #luaref table.classmembers td.fill { width: 99%; }
781 #luaref table.classmembers span.em { font-style: italic; }
782 #luaref span.functionname abbr { text-decoration:none; cursor:default; }
787 <h2>Ardour Lua Bindings</h2>
789 <a href="#h_classes">Class Documentation</a>
791 <a href="#h_enum">Enum/Constants</a>
793 <a href="#h_index">Index</a>
797 <!-- #### SNIP #### !-->
807 title: Class Reference
811 This documentation is far from complete may be inaccurate and subject to change.
822 ################################################################################
823 # some general documentation -- should really go elsehere
827 <h2 id="h_intro">Overview</h2>
829 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
830 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
833 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
834 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
835 <?=typelink('LuaSignal:Set')?> etc.
838 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
840 <h3>Short introduction to Ardour classes</h3>
842 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
843 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
844 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
845 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
848 Operations are performed on objects. One gets a reference to an object and then calls a method.
849 e.g <code>obj = Session:route_by_name("Audio") obj:set_name("Guitar")</code>.
852 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.
855 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.
858 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:
859 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
861 <h3>Pass by Reference</h3>
863 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
864 All parameters passed to a C++ method which uses references are returned as Lua Table.
865 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
869 <div style="float:left;">C++
871 <pre><code class="cxx">void set_ref (int& var, long& val)
873 printf ("%d %ld\n", var, val);
880 <div style="float:right;">Lua
882 <pre><code class="lua">local var = 0;
883 ref = set_ref (var, 2);
884 -- output from C++ printf()
885 </code><samp class="lua">0 2</samp><code>
886 -- var is still 0 here
887 print (ref[1], ref[2])
888 </code><samp class="lua">5 7</samp></pre>
892 <div class="clear"></div>
894 <div style="float:left;">
896 <pre><code class="cxx">int set_ref2 (int &var, std::string unused)
904 <div style="float:right;">
905 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
906 print (rv, ref[1], ref[2])
907 </code><samp class="lua">3 5 hello</samp></pre>
910 <div class="clear"></div>
912 <h3>Pointer Classes</h3>
914 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
915 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
916 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
919 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
920 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.
923 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
924 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
925 may not be able to find the given plugin and hence cannot create an object.
928 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
929 The object may vanish at any time.
930 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
931 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
934 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
935 Below they're inidicated in orange and have an arrow to indicate the pointer type.
936 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.
942 #################################
943 # Main output function -- Classes
945 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
946 foreach ($classlist as $ns => $cl) {
948 $tbl = format_class_members ($ns, $cl, $dups);
950 # format class title - depending on type
952 # classes with no members (no ctor, no methods, no data)
953 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h3>'.NL;
955 else if (isset ($classlist[$ns]['free'])) {
956 # free functions (no class)
957 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h3>'.NL;
959 else if (isset ($classlist[$ns]['arr'])) {
961 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h3>'.NL;
963 else if (isset ($classlist[$ns]['ptr'])) {
965 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h3>'.NL;
969 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h3>'.NL;
972 # show original C++ declaration
973 if (isset ($cl['cdecl'])) {
974 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['cdecl']).'</p>'.NL;
977 # print class inheritance (direct parent *name* only)
978 $inherited = array ();
979 $isa = traverse_parent ($ns, $inherited);
981 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
983 echo '<div class="clear"></div>'.NL;
986 # class documentation (if any)
987 echo format_doxyclass ($cl);
989 # member documentation
991 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;
993 echo '<table class="classmembers">'.NL;
998 # traverse parent classes (all inherited members)
999 foreach ($inherited as $pns => $pcl) {
1000 $tbl = format_class_members ($pns, $pcl, $dups);
1001 if (!empty ($tbl)) {
1002 echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
1003 echo '<table class="classmembers">'.NL;
1010 ####################
1011 # Enum and Constants
1013 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
1014 foreach ($constlist as $ns => $cs) {
1015 echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h3>'.NL;
1016 echo '<ul class="enum">'.NL;
1017 foreach ($cs as $c) {
1018 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
1023 ######################
1024 # Index of all classes
1026 echo '<h2 id="h_index" >Class Index</h2>'.NL;
1027 echo '<ul class="classindex">'.NL;
1028 foreach ($classlist as $ns => $cl) {
1029 echo '<li>'.typelink($ns).'</li>'.NL;
1034 # see how far there is still to go...
1035 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
1036 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
1040 <div class="luafooter">Ardour <?=$ardourversion?> - <?=date('r')?></div>
1044 echo '<!-- #### SNIP #### !-->'.NL;