summaryrefslogtreecommitdiff
path: root/muse2/doc/html/single/developer_docs/developer_docs.html
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/doc/html/single/developer_docs/developer_docs.html')
-rw-r--r--muse2/doc/html/single/developer_docs/developer_docs.html1745
1 files changed, 1745 insertions, 0 deletions
diff --git a/muse2/doc/html/single/developer_docs/developer_docs.html b/muse2/doc/html/single/developer_docs/developer_docs.html
new file mode 100644
index 00000000..9cf45e45
--- /dev/null
+++ b/muse2/doc/html/single/developer_docs/developer_docs.html
@@ -0,0 +1,1745 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<!--Converted with LaTeX2HTML 2008 (1.71)
+original version by: Nikos Drakos, CBLU, University of Leeds
+* revised and updated by: Marcus Hennecke, Ross Moore, Herb Swan
+* with significant contributions from:
+ Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
+<HTML>
+<HEAD>
+<TITLE>MusE Documentation</TITLE>
+<META NAME="description" CONTENT="MusE Documentation">
+<META NAME="keywords" CONTENT="developer_docs">
+<META NAME="resource-type" CONTENT="document">
+<META NAME="distribution" CONTENT="global">
+
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+<META NAME="Generator" CONTENT="LaTeX2HTML v2008">
+<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
+
+<LINK REL="STYLESHEET" HREF="developer_docs.css">
+
+</HEAD>
+
+<BODY >
+<BR>
+
+<H2><A NAME="SECTION00100000000000000000">
+Contents</A>
+</H2>
+<!--Table of Contents-->
+
+<UL CLASS="TofC">
+<LI><A NAME="tex2html22"
+ HREF="developer_docs.html#SECTION00200000000000000000">Internals - how it works</A>
+<UL>
+<LI><A NAME="tex2html23"
+ HREF="developer_docs.html#SECTION00210000000000000000">User interface programming</A>
+<LI><A NAME="tex2html24"
+ HREF="developer_docs.html#SECTION00220000000000000000">Configuration</A>
+<LI><A NAME="tex2html25"
+ HREF="developer_docs.html#SECTION00230000000000000000">User controls and automation</A>
+<UL>
+<LI><A NAME="tex2html26"
+ HREF="developer_docs.html#SECTION00231000000000000000">Handling user input</A>
+</UL>
+</UL>
+<BR>
+<LI><A NAME="tex2html27"
+ HREF="developer_docs.html#SECTION00300000000000000000">Design decisions</A>
+<UL>
+<LI><A NAME="tex2html28"
+ HREF="developer_docs.html#SECTION00310000000000000000">Automation</A>
+</UL>
+<BR>
+<LI><A NAME="tex2html29"
+ HREF="developer_docs.html#SECTION00400000000000000000">Feature requests</A>
+<UL>
+<LI><A NAME="tex2html30"
+ HREF="developer_docs.html#SECTION00410000000000000000">Per-Part automation and more on automation</A>
+<LI><A NAME="tex2html31"
+ HREF="developer_docs.html#SECTION00420000000000000000">Pre-Rendering tracks</A>
+<UL>
+<LI><A NAME="tex2html32"
+ HREF="developer_docs.html#SECTION00421000000000000000">The feature</A>
+<LI><A NAME="tex2html33"
+ HREF="developer_docs.html#SECTION00422000000000000000">Use cases</A>
+<LI><A NAME="tex2html34"
+ HREF="developer_docs.html#SECTION00423000000000000000">Possible scenarios</A>
+<LI><A NAME="tex2html35"
+ HREF="developer_docs.html#SECTION00424000000000000000">Extensions</A>
+</UL>
+<LI><A NAME="tex2html36"
+ HREF="developer_docs.html#SECTION00430000000000000000">Slotted editors</A>
+<LI><A NAME="tex2html37"
+ HREF="developer_docs.html#SECTION00440000000000000000">Controller master values</A>
+<LI><A NAME="tex2html38"
+ HREF="developer_docs.html#SECTION00450000000000000000">Enabled-indicator while recording</A>
+<LI><A NAME="tex2html39"
+ HREF="developer_docs.html#SECTION00460000000000000000">Linear automation editing</A>
+<LI><A NAME="tex2html40"
+ HREF="developer_docs.html#SECTION00470000000000000000">Symbolic names for MIDI ports</A>
+</UL></UL>
+<!--End of Table of Contents-->
+<H1><A NAME="SECTION00200000000000000000">
+Internals - how it works</A>
+</H1>
+This chapter explains how MusE is built internally, and is meant
+to be an aid for developers wanting to quickly start up with MusE.
+For details on <SPAN CLASS="textit">why</SPAN> stuff is done please refer to the following
+chapter.
+
+<P>
+
+<H1><A NAME="SECTION00210000000000000000">
+User interface programming</A>
+</H1>
+We use the QT Toolkit for GUI- and other programming. The <SPAN CLASS="textit">QT-Assistant</SPAN>
+is an important tool for getting help. Almost everything can be looked
+up there.
+
+<P>
+GUIs can be either be hardcoded (see <TT>fterfirsta`a=95 _ `a=58 :
+ `a&gt;64
+ `a&lt;91 aaa
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>rranger.cpp</TT> for an example)
+or can be created using <SPAN CLASS="textit">QT-Designer</SPAN> (see the dialogs under
+<TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>idgets/function_dialogs/</TT> for mostly cleanly-written examples).
+Don't forget to add your <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>pp</TT>, <TT>fterfirsth`h=95 _ `h=58 :
+ `h&gt;64
+ `h&lt;91 hhh
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>></TT> and <TT>fterfirstu`u=95 _ `u=58 :
+ `u&gt;64
+ `u&lt;91 uuu
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>i</TT> files to the
+corresponding sections in the <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>MakeLists.txt</TT>!
+
+<P>
+Additionally, MusE offers some custom widgets, like menu title items etc.
+Following, there will be a small, unordered list about custom widgets:
+
+<UL>
+<LI><TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGui::MenuTitleItem</TT>: Provides a title-bar in a <TT>fterfirstQ`Q=95 _ `Q=58 :
+ `Q&gt;64
+ `Q&lt;91 QQQ
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>Menu</TT>.
+<BR>
+Usage: <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>omeMenu-&gt;addAction(new MusEGui::MenuTitleItem(tr("fnord"), someMenu));</TT>
+<BR>
+Defined in <TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>idgets/menutitleitem.h</TT>.
+</LI>
+<LI><TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGui::PopupMenu</TT>: Provides a <TT>fterfirstQ`Q=95 _ `Q=58 :
+ `Q&gt;64
+ `Q&lt;91 QQQ
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>Menu</TT>-like menu which
+ can stay open after the user checks a checkable action.
+<BR>
+Usage: just create a <TT>fterfirstn`n=95 _ `n=58 :
+ `n&gt;64
+ `n&lt;91 nnn
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ew PopupMenu( true|false )</TT> instead of
+ a <TT>fterfirstn`n=95 _ `n=58 :
+ `n&gt;64
+ `n&lt;91 nnn
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ew QMenu()</TT>. (<TT>fterfirstt`t=95 _ `t=58 :
+ `t&gt;64
+ `t&lt;91 ttt
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>rue</TT> means 'stay open')
+<BR>
+Defined in <TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>idgets/popupmenu.h</TT>.
+</LI>
+</UL>
+
+<P>
+
+<H1><A NAME="SECTION00220000000000000000"></A> <A NAME="portconfig_sucks"></A>
+<BR>
+Configuration
+</H1>
+Configuration is a bit pesky in MusE in its current state. If you get
+confused by reading this chapter, that's a sign of a sane mind.
+
+<P>
+There are three kinds of configuration items:
+
+<UL>
+<LI>(1) Global configuration, like coloring schemes, plugin categories, MDI-ness settings
+</LI>
+<LI>(2) Per-Song configuration, like whether to show or hide certain track types in the arranger
+</LI>
+<LI>(3) Something in between, like MIDI port settings etc. They obviously actually are
+ global configuration issues (or ought to be), but also obviously must be stored
+ in the song file for portability. (This problem could possibly be solved by
+ the feature proposal in <A HREF="#symbolic_ports">3.7</A>.
+</LI>
+</UL>
+
+<P>
+
+<H4><A NAME="SECTION00220010000000000000">
+Reading configuration</A>
+</H4>
+<TT>fterfirstv`v=95 _ `v=58 :
+ `v&gt;64
+ `v&lt;91 vvv
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>oid MusECore::readConfiguration(Xml&amp;, bool, bool)</TT> in
+<TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>onf.cpp</TT> is the central point
+of reading configuration. It is called when MusE is started first
+(by <TT>fterfirstb`b=95 _ `b=58 :
+ `b&gt;64
+ `b&lt;91 bbb
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ool MusECore::readConfiguration()</TT>), and also when a
+song is loaded.
+<BR>It can be instructed whether to read MIDI ports (3), global configuration
+and MIDI ports (1+3). Per-Song configuration is always read (2).
+
+<P>
+When adding new configuration items and thus altering <TT>fterfirstr`r=95 _ `r=58 :
+ `r&gt;64
+ `r&lt;91 rrr
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>eadConfiguration()</TT>,
+you must take care to place your item into the correct section. The code is
+divided into the following sections:
+
+<UL>
+<LI>Global and/or per-song configuration (3)
+</LI>
+<LI>Global configuration (1)
+</LI>
+<LI>Code for skipping obsolete entries
+</LI>
+</UL>
+
+<P>
+The sections are divided by comments (they contain <TT>--</TT>, so just
+search for them). Please do not just remove code for reading obsolete entries,
+but always add an appropriate entry to the 'skipping' section in order to
+prevent error messages when reading old configs.
+
+<P>
+
+<H4><A NAME="SECTION00220020000000000000">
+Writing configuration</A>
+</H4>
+Global configuration is written using the
+<TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGui::MusE::writeGlobalConfiguration()</TT> functions, while
+per-song-config is written by <TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGui::MusE::writeConfiguration()</TT>
+(notice the missing <TT>fterfirstG`G=95 _ `G=58 :
+ `G&gt;64
+ `G&lt;91 GGG
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>lobal</TT>; both implemented in <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>onf.cpp</TT>).
+
+<P>
+<TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>riteConfiguration</TT> is actually just a subset of the code in
+<TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>riteGlobalConfiguration</TT>. <SPAN CLASS="textbf">Duplicate code!</SPAN>
+<P>
+
+<H4><A NAME="SECTION00220030000000000000">
+Song state</A>
+</H4>
+Additionally to per-song configuration, there is the song's state.
+This contains "the song", that is all tracks, parts and note events,
+together with information about the currently opened windows, their
+position, size, settings and so on. Adding new items here is actually
+pretty painless: Configuration is read and written using
+<TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usECore::Song::read</TT> and <TT>fterfirst:`:=95 _ `:=58 :
+ `:&gt;64
+ `:&lt;91 :::
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>:write</TT>, both implemented in
+<TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ongfile.cpp</TT>. There are no caveats.
+
+<P>
+
+<H4><A NAME="SECTION00220040000000000000">
+How to add new items</A>
+</H4>
+When adding global configuration items, then add them into the second
+block ("global configuration") in <TT>fterfirstr`r=95 _ `r=58 :
+ `r&gt;64
+ `r&lt;91 rrr
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>eadConfiguration</TT> and into
+<TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>riteGlobalConfiguration</TT>.
+
+<P>
+When adding just-per-song items, better don't bother to touch the
+"configuration" code and just add it to the song's state (there might
+be rare exceptions).
+
+<P>
+When adding global configuration items, make sure you add them into the
+correct section of <TT>fterfirstr`r=95 _ `r=58 :
+ `r&gt;64
+ `r&lt;91 rrr
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>eadConfiguration</TT>, and into <TT>fterfirstw`w=95 _ `w=58 :
+ `w&gt;64
+ `w&lt;91 www
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>riteGlobalConfiguration</TT>.
+
+<P>
+
+<H1><A NAME="SECTION00230000000000000000">
+User controls and automation</A>
+</H1>
+
+<H2><A NAME="SECTION00231000000000000000">
+Handling user input</A>
+</H2>
+
+<H3><A NAME="SECTION00231100000000000000">
+Plugins and synthesizers</A>
+</H3>
+
+<H4><A NAME="SECTION00231110000000000000">
+Overview</A>
+</H4>
+When the user launches a plugin's GUI, either a MusE-window with
+the relevant controls is shown, or the native GUI is launched. MusE
+will communicate with this native GUI through OSC (Open Sound Control).
+The relevant classes are <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginGui</TT>, <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginIBase</TT>
+(in <TT>fterfirstp`p=95 _ `p=58 :
+ `p&gt;64
+ `p&lt;91 ppp
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>lugin.h</TT>) and <TT>fterfirstO`O=95 _ `O=58 :
+ `O&gt;64
+ `O&lt;91 OOO
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>scIF</TT> (in <TT>fterfirsto`o=95 _ `o=58 :
+ `o&gt;64
+ `o&lt;91 ooo
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>sc.h</TT>).
+
+<P>
+If the user changes a GUI element, first the corresponding control is
+disabled, making MusE not steadily update it through automation
+while the user operates it. Then MusE will update the plugin's parameter
+value, and also record the new value. When appropriate, the controller
+is enabled again.
+
+<P>
+
+<H4><A NAME="SECTION00231120000000000000">
+Processing the input, recording</A>
+</H4>
+Upon operating a slider, <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginIBase::setParam</TT> is called,
+which usually writes the control change into the ringbuffer
+<TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::_controlFifo</TT>. (<TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::apply()</TT>,
+<TT>fterfirstD`D=95 _ `D=58 :
+ `D&gt;64
+ `D&lt;91 DDD
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ssiSynthIF::getData()</TT> will read this ringbuffer and
+do the processing accordingly). Furthermore, <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::recordAutomation</TT>
+is called, which either directly modifies the controller lists or writes
+the change into a "to be recorded"-list (<TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::_recEvents</TT>)
+(depending on whether the song is stopped or played).
+
+<P>
+The <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::_recEvents</TT> list consists of <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlRecVal</TT>
+items (see <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trl.h</TT>), which hold the following data:
+
+<UL>
+<LI>the frame where the change occurred
+</LI>
+<LI>the value
+</LI>
+<LI>the type, which can be <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_START</TT>, <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_VAL</TT> or <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_STOP</TT>.
+ <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_VAL</TT> are written by every <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>udioTrack::recordAutomation</TT>
+ call, <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_START</TT> and <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_STOP</TT> are generated by
+ <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::startAutoRecord</TT> and <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>topAutoRecord</TT>, respectively.
+</LI>
+<LI>and the id of the controller which is affected
+</LI>
+</UL>
+It is processed when the song is stopped. The call path for this is:
+<TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::stopRolling</TT> calls <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::processAutomationEvents</TT>
+calls <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::processAutomationEvents</TT>.
+This function removes the old events from the track's controller list
+and replaces them with the new events from <TT>fterfirst_`_=95 _ `_=58 :
+ `_&gt;64
+ `_&lt;91 ___
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>recEvents</TT>. In
+<TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_WRITE</TT> mode, just all controller events within the recorded
+range are erased; in <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_TOUCH</TT> mode, the <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_START</TT>
+and <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>RVT_STOP</TT> types of the <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlRecVal</TT> events are used
+to determine the range(s) which should be wiped.
+
+<P>
+
+<H4><A NAME="SECTION00231130000000000000">
+How it's stored</A>
+</H4>
+Automation data is kept in <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::_controller</TT>, which is a <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlListList</TT>, that is, a list of <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT>s, that is, a list of lists of
+controller-objects which hold the control points of the automation graph.
+The <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT> also stores whether the list is meant discrete
+(a new control point results in a value-jump) or continuous (a new control
+point results in the value slowly sloping to the new value).
+Furthermore, it stores a <TT>fterfirst_`_=95 _ `_=58 :
+ `_&gt;64
+ `_&lt;91 ___
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>curVal</TT> (accessed by <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>urVal()</TT>),
+which holds the currently active value, which can be different from the
+actually stored value because of user interaction. This value is also
+used when there is no stored automation data.
+
+<P>
+<TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::addController</TT> and <TT>fterfirstr`r=95 _ `r=58 :
+ `r&gt;64
+ `r&lt;91 rrr
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>emoveController</TT> are used to add/remove whole controller types; the most important functions which
+access <TT>fterfirst_`_=95 _ `_=58 :
+ `_&gt;64
+ `_&lt;91 ___
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>controller</TT> are:
+
+<UL>
+<LI><TT>fterfirstp`p=95 _ `p=58 :
+ `p&gt;64
+ `p&lt;91 ppp
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>rocessAutomationEvents</TT>, <TT>fterfirstr`r=95 _ `r=58 :
+ `r&gt;64
+ `r&lt;91 rrr
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ecordAutomation</TT>,
+ <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>tartAutoRecord</TT>, <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>topAutoRecord</TT>: see above.
+</LI>
+<LI><TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>eekPrevACEvent</TT>, <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>eekNextACEvent</TT>, <TT>fterfirste`e=95 _ `e=58 :
+ `e&gt;64
+ `e&lt;91 eee
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>raseACEvent</TT>,
+ <TT>fterfirste`e=95 _ `e=58 :
+ `e&gt;64
+ `e&lt;91 eee
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>raseRangeACEvents</TT>, <TT>fterfirsta`a=95 _ `a=58 :
+ `a&gt;64
+ `a&lt;91 aaa
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ddACEvent</TT>, <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>hangeACEvent</TT>,
+ which do the obvious
+</LI>
+<LI><TT>fterfirstp`p=95 _ `p=58 :
+ `p&gt;64
+ `p&lt;91 ppp
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginCtrlVal</TT>, <TT>fterfirsts`s=95 _ `s=58 :
+ `s&gt;64
+ `s&lt;91 sss
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>etPluginCtrlVal</TT>: the first
+ returns the current value according to the <TT>fterfirst_`_=95 _ `_=58 :
+ `_&gt;64
+ `_&lt;91 ___
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>controller</TT>
+ list, the second only sets the <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>urVal</TT>, but does not
+ insert any events.
+</LI>
+</UL>
+
+<P>
+Whenever a <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT> has been manipulated,
+<TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGlobal::song-&gt;controllerChange(Track*)</TT> shall be called,
+which emits the <TT>fterfirstM`M=95 _ `M=58 :
+ `M&gt;64
+ `M&lt;91 MMM
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>usEGlobal::song-&gt;controllerChanged(Track*)</TT>
+signal in order to inform any parts of MusE about the change (currently,
+only the arranger's part canvas utilizes this).
+
+<P>
+
+<H4><A NAME="SECTION00231140000000000000">
+Enabling and disabling controllers</A>
+</H4>
+Disabling the controller is both dependent from the current automation
+mode and from whether the GUI is native or not.
+In <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_WRITE</TT> mode, once a slider is touched (for MusE-GUIs) or
+once a OSC control change is received (for native GUIs), the control
+is disabled until the song is stopped or seeked.
+
+<P>
+In <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_TOUCH</TT> (and currently (r1492) <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_READ</TT>, but
+that's to be fixed) mode, once a MusE-GUI's slider is pressed down, the
+corresponding control is disabled. Once the slider is released, the
+control is re-enabled again. Checkboxes remain in "disabled" mode,
+however they only affect the recorded automation until the last toggle
+of the checkbox. (Example: start the song, toggle the checkbox, toggle
+it again, wait 10 seconds, stop the song. This will NOT overwrite the
+last 10 seconds of automation data, but everything between the first
+and the last toggle.). For native GUIs, this is a bit tricky, because
+we don't have direct access to the GUI widgets. That is, we have no
+way to find out whether the user doesn't touch a control at all, or
+whether he has it held down, but just doesn't operate it. The current
+behaviour for native GUIs is to behave like in <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_WRITE</TT> mode.
+
+<P>
+The responsible functions are: <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::oscControl</TT> and
+<TT>fterfirstD`D=95 _ `D=58 :
+ `D&gt;64
+ `D&lt;91 DDD
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ssiSynthIF::oscControl</TT> for handling native GUIs,
+<TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::ctrlPressed</TT> and <TT>fterfirstc`c=95 _ `c=58 :
+ `c&gt;64
+ `c&lt;91 ccc
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlReleased</TT> for MusE
+default GUIs and <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::guiParamPressed</TT>,
+<TT>fterfirstg`g=95 _ `g=58 :
+ `g&gt;64
+ `g&lt;91 ggg
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>uiParamReleased</TT>, <TT>fterfirstg`g=95 _ `g=58 :
+ `g&gt;64
+ `g&lt;91 ggg
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>uiSliderPressed</TT> and
+<TT>fterfirstg`g=95 _ `g=58 :
+ `g&gt;64
+ `g&lt;91 ggg
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>uiSliderReleased</TT> for MusE GUIs read from a UI file;
+<TT>fterfirstg`g=95 _ `g=58 :
+ `g&gt;64
+ `g&lt;91 ggg
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>uiSlider*</TT> obviously handle sliders, while <TT>fterfirstg`g=95 _ `g=58 :
+ `g&gt;64
+ `g&lt;91 ggg
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>uiParam*</TT>
+handle everything else which is not a slider. They call
+<TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::enableController</TT> to enable/disable it.
+
+<P>
+Furthermore, on every song stop or seek, <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::enableAllControllers</TT>
+is called, which re-enables all controllers again. The call paths for
+this are:
+
+<UL>
+<LI>For stop: <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::stopRolling</TT> calls
+ <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::processAutomationEvents</TT> calls
+ <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::clearRecAutomation</TT> calls
+ <TT>fterfirstT`T=95 _ `T=58 :
+ `T&gt;64
+ `T&lt;91 TTT
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>rack::clearRecAutomation</TT> calls
+ <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::enableAllControllers</TT>
+</LI>
+<LI>For seek: <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udio::seek</TT> sends a message ("<TT>fterfirstG`G=95 _ `G=58 :
+ `G&gt;64
+ `G&lt;91 GGG
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>></TT>") to
+ <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::seqSignal</TT> which calls
+ <TT>fterfirstS`S=95 _ `S=58 :
+ `S&gt;64
+ `S&lt;91 SSS
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>ong::clearRecAutomation</TT> which calls
+ <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::enableAllControllers</TT>
+</LI>
+</UL>
+
+<P>
+
+<H1><A NAME="SECTION00300000000000000000">
+Design decisions</A>
+</H1>
+
+<H1><A NAME="SECTION00310000000000000000">
+Automation</A>
+</H1>
+As of revision 1490, automation is handled in two ways: User-generated
+(live) automation data (generated by the user moving sliders while playing)
+is fed into <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::_controlFifo</TT>. Automation data is kept
+in <TT>fterfirstA`A=95 _ `A=58 :
+ `A&gt;64
+ `A&lt;91 AAA
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>udioTrack::_controller</TT>, which is a <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlListList</TT>,
+that is, a list of <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT>s, that is, a list of lists of
+controller-objects which hold the control points of the automation graph.
+The <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT> also stores whether the list is meant discrete
+(a new control point results in a value-jump) or continous (a new control
+point results in the value slowly sloping to the new value).
+
+<P>
+While <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::_controlFifo</TT> can be queried very quickly and
+thus is processed with a very high resolution (only limited by the
+minimum control period setting), the automation value are expensive to
+query, and are only processed once in an audio <SPAN CLASS="textit">driver</SPAN> period.
+This might lead to noticeable jumps in value.
+
+<P>
+This could possibly be solved in two ways:
+
+<H4><A NAME="SECTION00310010000000000000">
+Maintaining a slave control list</A>
+</H4>
+This approach would maintain a fully redundant slave control list,
+similar to <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::_controlFifo</TT>. This list must be updated
+every time any automation-related thing is changed, and shall contain
+every controller change as a tuple of controller number and value.
+This could be processed in the same loop as <TT>fterfirstP`P=95 _ `P=58 :
+ `P&gt;64
+ `P&lt;91 PPP
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>luginI::_controlFifo</TT>,
+making it comfortable to implement; furthermore, it allows to cleanly
+offer automation-settings at other places in future (such as storing
+automation data in parts or similar).
+
+<P>
+
+<H4><A NAME="SECTION00310020000000000000">
+Holding iterators</A>
+</H4>
+We also could hold a list of iterators of the single <TT>fterfirstC`C=95 _ `C=58 :
+ `C&gt;64
+ `C&lt;91 CCC
+
+ <`<=95 _ `<=58 :
+ `<&gt;64
+ `<&lt;91 <<<
+
+ c@amelhyph<269>>trlList</TT>s.
+This would also cause low CPU usage, because usually, the iterators only
+need to be incremented once. However, it is pretty complex to implement,
+because the iterators may become totally wrong (because of a seek in the
+song), and we must iterate through a whole list of iterators.
+
+<P>
+
+<H4><A NAME="SECTION00310030000000000000">
+Just use the current data access functions</A>
+</H4>
+By just using the current functions for accessing automation data,
+we might get a quick-and-dirty solution, which however wastes way too
+much CPU ressources. This is because on <SPAN CLASS="textit">every single frame</SPAN>, we
+need to do a binary search on multiple controller lists.
+
+<P>
+
+<H1><A NAME="SECTION00400000000000000000">
+Feature requests</A>
+</H1>
+
+<H1><A NAME="SECTION00410000000000000000">
+Per-Part automation and more on automation</A>
+</H1> Automation shall be undo-able. Automation shall reside in parts which
+are exchangeable, clonable etc (like the MIDI- and Wave-Parts).
+Global per-synth/per-audiotrack automation shall also be available, but
+this can also be implemented as special case of part automation (one
+long part).
+
+<P>
+
+<H1><A NAME="SECTION00420000000000000000">
+Pre-Rendering tracks</A>
+</H1>
+
+<H2><A NAME="SECTION00421000000000000000">
+The feature</A>
+</H2>
+All tracks shall be able to be "pre-renderable". Pre-rendering shall
+be "layered". Pre-rendering shall act like a transparent audio cache:
+Audio data is (redundantly) stored, wasting memory in order to save CPU.
+
+<P>
+That is: Each track owns one or more wave-recordings of the length of
+the song. If the user calls "pre-render" on a track, then this track
+is played quasi-solo (see below), and the raw audio data is recorded
+and stored in the "layer 0" wave recording. If the user has any effects
+set up to be applied, then each effect is applied on a different layer
+(creating layer 1, layer 2 etc).
+
+<P>
+This means, that also MIDI and drum tracks can have effects (which
+usually only operate on audio, but we HAVE audio data because of this
+prerendering).
+
+<P>
+Furthermore, MusE by default does not send MIDI events to the synthesizers
+but instead just plays back the last layer of the prerecording (for
+MIDI tracks), or does not pipe the audio data through the whole plugin
+chain (causing cpu usage), but instead just plays back the last layer.
+The hearable result shall be the same.
+
+<P>
+Once the user changes any parameter (automation data or plugins for
+wave tracks, MIDI events or effect plugin stuff for MIDI tracks),
+then MusE shall generate the sound for this particular track in the
+"old" way (send MIDI data to synthes, or pipe audio data through plugins).
+(So that the user will not even notice that MusE actually pre-renderered
+stuff.) Either MusE automatically records this while playback (if possible)
+or prompts the user to accordingly set up his cabling and then record
+it. Or (temporarily) disables prerecording for this track, falling back
+to the plain old way of generating sound.
+
+<P>
+<SPAN CLASS="textit">Quasi-solo</SPAN> means: For wave tracks, just solo the track. For MIDI
+tracks, mute all tracks which are not on the same synth (channel?),
+and mute all <SPAN CLASS="textit">note</SPAN> events which are not on the quasi-soloed track.
+This causes MusE to still play any controller events from different
+tracks, because they might have effects on the quasi-soloed track. (You
+can have notes on channel 1 on one track and controller stuff on channel
+1 on another track; then you would need quasi-solo to get proper results.)
+
+<P>
+
+<H2><A NAME="SECTION00422000000000000000">
+Use cases</A>
+</H2>
+
+<H4><A NAME="SECTION00422010000000000000">
+Saving CPU</A>
+</H4>
+On slow systems, this is neccessary for songs with lots of, or demanding
+(or both) soft synthes / plugins. Even if the synth or plugin is so
+demanding that your system is not able to produce sound in real-time,
+then with this feature you'll be able to use the synth (this will make
+editing pretty laggish, because for a change you need to re-render at
+least a part before you can listen to it, but better than being unable
+to use the synth at all!)
+
+<P>
+
+<H4><A NAME="SECTION00422020000000000000">
+Exporting as audio project</A>
+</H4>
+Using pre-rendering on all tracks, you easily can export your project
+as multi-track audio file (for use with Ardour or similar DAWs).
+Just take the last layer of each track, and write the raw audio data
+into the file, and you're done. (Maybe we are even able to write down
+the raw-raw layer0 audio data plus information about used plugins and
+settings etc..?)
+
+<P>
+
+<H4><A NAME="SECTION00422030000000000000">
+Mobile audio workstations</A>
+</H4>
+You might want to work a bit on your audio projects on your notebook
+while you're not at home, not having access to your hardware synthesizers.
+Using this feature, you could have pre-recorded the stuff in your studio
+before, and now can at least fiddle around with the non-hw-synth-dependent
+parts of your song, while still having your <SPAN CLASS="textit">full</SPAN> song with you.
+
+<P>
+
+<H4><A NAME="SECTION00422040000000000000">
+Applying effects on MIDI tracks</A>
+</H4>
+If you have many physical audio inputs, you might already be able to
+apply effect chains on MIDI tracks, by wiring the synthes' audio
+outputs to your soundcard's inputs, and applying the effects on
+dedicated input tracks you have to create. This requires you to have
+expensive hardware, and is pretty complicated, because you need one
+additional track per MIDI synth.
+
+<P>
+This feature allows you to apply effects on single MIDI tracks, and not
+only on full MIDI synthes, and doesn't require you to be have that
+many physical audio inputs (you need to manually replug your synthes,
+however).
+
+<P>
+
+<H2><A NAME="SECTION00423000000000000000">
+Possible scenarios</A>
+</H2>
+
+<H4><A NAME="SECTION00423010000000000000">
+Setting it up</A>
+</H4>
+Create a wave track, MusE will allow you to set or unset prerendering
+for every plugin in the plugin rack (recording the actual track is
+useless because it would be a plain copy).
+Create a MIDI track, MusE will ask you on which physical audio input
+your synth is connected. Setting up multiple synthes on one physical
+audio in is allowed, see below.
+
+<P>
+
+<H4><A NAME="SECTION00423020000000000000">
+Pre-rendering stuff</A>
+</H4>
+When the user presses the "pre-render" button, all tracks which have
+been changed since their last pre-rendering will be re-rendered.
+If you have multiple hardware synthes set up as they were connected
+to one physical audio input port, MusE will prompt you to first plug
+the proper cable in.
+
+<P>
+
+<H4><A NAME="SECTION00423030000000000000">
+Making changes</A>
+</H4>
+Change a note in a MIDI part, move or delete a part or change automation
+parameters. MusE will temporarily disable the pre-rendered information
+and instead generate the sound via sending out MIDI events, piping stuff
+through effect chains or similar. If you play back the whole song, or
+if you manually trigger a re-rendering of a track via the context menu,
+MusE will play back the stuff, record it again and re-enable the
+pre-rendered information.
+
+<P>
+
+<H2><A NAME="SECTION00424000000000000000">
+Extensions</A>
+</H2>
+
+<H4><A NAME="SECTION00424010000000000000">
+Automatic discovery of physical audio connections</A>
+</H4>
+The user plugs all (or only some) synthes' audio outs into the available
+audio inputs, then runs automatic discovery. This will send MIDI events
+to each synthesizer, and look on which audio in there's activity. Then
+it will assume that the synthesizer is connected to that particular
+audio in. Audio ins which show activity before any MIDI events were
+sent are not considered, as they're probably connected to microphones
+or other noise-generating non-synthes.
+
+<P>
+
+<H4><A NAME="SECTION00424020000000000000">
+Audio export</A>
+</H4>
+As described in the Use cases, MusE can allow you to export your song
+in some multitrack audio format.
+
+<P>
+
+<H4><A NAME="SECTION00424030000000000000">
+Cheap/Faked changes</A>
+</H4>
+For expensive or unavailable synthes, changing the Volume midi controller,
+the Pan controller or similar "easy" controllers will not trigger a
+complete re-rendering, but instead "fake" the change, by changing
+the volume data directly on the recorded wave. This might require some
+learning and might even get pretty complicated.
+
+<P>
+
+<H4><A NAME="SECTION00424040000000000000">
+Intelligent re-recording</A>
+</H4>
+For tiny changes, MusE shall only re-render the relevant part. If you
+change some MIDI notes, then begin re-recording shortly before the
+changes, and end re-recording as soon as the recorded stuff doesn't
+differ to much from the stuff coming from the synth. Then properly
+blend the old recording with the updated part.
+
+<P>
+
+<H1><A NAME="SECTION00430000000000000000">
+Slotted editors</A>
+</H1>
+Currently, MusE has the pianoroll editor, drum editor, score editor,
+then the controller editor which is inside the pianoroll/drum editor.
+All these editors have a very similar concept: the "time axis" is
+vertical and (almost) linear, they handle parts, and events are
+manipulated similarly.
+
+<P>
+A unified editor shall be created which allows you to combine different
+kinds of editors in one window, properly aligned against each other.
+These "different kinds of editors" shall be handled as "slots"; one
+unified editor window consists of:
+
+<UL>
+<LI>A menu bar, containing stuff suitable for the complete window,
+ which might include window name, MDI-ness etc.
+</LI>
+<LI>A toolbar which contains controls suitable for every single slot.
+</LI>
+<LI>A container with one or more slots; the slots can be scrolled in
+ y-direction if there are multipe slots.
+</LI>
+<LI>A time-scrollbar with zoom
+</LI>
+</UL>
+
+<P>
+Each slot contains the following:
+
+<UL>
+<LI>A menu button, button box or control panel for setting up this
+ particular slot. This could contain "note head colors", "show
+ a transposing instrument" etc for score edit slots, "event
+ rectangle color", "grid size" and "snap to grid" for pianoroll/
+ drum editors.
+</LI>
+<LI>The actual canvas
+</LI>
+<LI>A y-direction scroll bar, possibly with zoom control (for
+ pianoroll editor)
+</LI>
+</UL>
+
+<P>
+The main window does not show its scroll bar if there is only one slot,
+because the slot's scrollbar is sufficient then.
+
+<P>
+Slots can be added, destroyed, moved around, maybe even merged (if the
+slot types allow it); basically, you can compare them with the staves
+in the score editor.
+
+<P>
+The slots shall align against each other, that is, if a score editor
+slot displays a key change with lots of accidentials, then all other
+slots shall either also display the key change (if they're score slots)
+or display a gap. Events which happen at the same time shall be at the
+same x-coordinate, regardless which slot they are.
+
+<P>
+
+<H1><A NAME="SECTION00440000000000000000">
+Controller master values</A>
+</H1>
+All controllers (MIDI-controllers and also automation controllers)
+shall have one set of "master values" which allow you to set a gain and
+a bias. Instead of the actual set value, <!-- MATH
+ $\textrm{value} * \textrm{bias}
++ textrm{bias}$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="180" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
+ SRC="img1.png"
+ ALT="$\textrm{value} * \textrm{bias}
++ textrm{bias}$"></SPAN> shall be sent to the MIDI device / the plugin. For
+controllers like "pan", the unbiased values shall be transformed, that
+is, a pan of 64, with <!-- MATH
+ $\textrm{bias}=2$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="61" HEIGHT="15" ALIGN="BOTTOM" BORDER="0"
+ SRC="img2.png"
+ ALT="$\textrm{bias}=2$"></SPAN> and <!-- MATH
+ $\textrm{gain}=0.5$
+ -->
+<SPAN CLASS="MATH"><IMG
+ WIDTH="75" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
+ SRC="img3.png"
+ ALT="$\textrm{gain}=0.5$"></SPAN>, shall
+be transformed to 66 (because 64 is actually 0, while 0 is actually -64).
+These values shall be set in the arranger and whereever the actual
+controller/automation values can be edited.
+
+<P>
+
+<H1><A NAME="SECTION00450000000000000000">
+Enabled-indicator while recording</A>
+</H1>
+The MusE-plugin-GUIs shall display a small LED displaying whether a
+controller is currently enabled or disabled. By clicking this LED, the
+enabled state shall be switched.
+
+<P>
+Furthermore, there shall be a dedicated window which only lets you switch
+enabled/disabled states. This will be useful when using external GUIs
+or the MIDI-controller-to-automation feature, to re-enable a controller
+when in <TT>fterfirstA`A=95 _ `A=58 : A
+ <`<=95 _ `<=58 : <
+ u@nderscorehyph<271>>UTO_TOUCH</TT> mode.
+
+<P>
+
+<H1><A NAME="SECTION00460000000000000000">
+Linear automation editing</A>
+</H1>
+While holding some modifier key (like shift), operating the MusE-native-
+GUI sliders shall only generate control points when clicking and when
+releasing the slider. This will result in linear graphs for continous
+controllers, and in large steps for discrete controllers (which is in
+particular useful for stuff like "which low/high-pass filter type to use").
+
+<P>
+Maybe make this behaviour default for discrete controllers?
+
+<P>
+
+<H1><A NAME="SECTION00470000000000000000"></A> <A NAME="symbolic_ports"></A>
+<BR>
+Symbolic names for MIDI ports
+</H1>
+MIDI ports shall have a user-defined symbolic name (like "Korg" or "Yamaha DX 7").
+The mapping between these symbolic names and the hardware port (like
+"ALSA midi out port") is stored in the global configuration.
+
+<P>
+Song files only specify the symbolic names as the ports associated with
+their tracks. No information about physical devices/port names, but only
+symbolic names are stored in the song file.
+
+<P>
+This resolves the issues mentioned in <A HREF="#portconfig_sucks">1.2</A>, and also
+allows the user to share his pieces with other people: They would only
+have to set up that symbolic-to-hardware mapping once (collisions are
+unlikely, because an equal symbolic name should usually mean the same
+device) and are happy, instead of having to re-map <SPAN CLASS="textit">every</SPAN> port
+for <SPAN CLASS="textit">every</SPAN> song.
+
+<P>
+<BR><HR>
+
+</BODY>
+</HTML>