Subsections
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 fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginGui, fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginIBase
(in fterfirstp`p=95 _ `p=58 :
`p>64
`p<91 ppp
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>lugin.h) and fterfirstO`O=95 _ `O=58 :
`O>64
`O<91 OOO
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>scIF (in fterfirsto`o=95 _ `o=58 :
`o>64
`o<91 ooo
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>sc.h).
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.
Upon operating a slider, fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginIBase::setParam is called,
which usually writes the control change into the ringbuffer
fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::_controlFifo. (fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::apply(),
fterfirstD`D=95 _ `D=58 :
`D>64
`D<91 DDD
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ssiSynthIF::getData() will read this ringbuffer and
do the processing accordingly). Furthermore, fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::recordAutomation
is called, which either directly modifies the controller lists or writes
the change into a "to be recorded"-list (fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::_recEvents)
(depending on whether the song is stopped or played).
The fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::_recEvents list consists of fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlRecVal
items (see fterfirstc`c=95 _ `c=58 :
`c>64
`c<91 ccc
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trl.h), which hold the following data:
- the frame where the change occurred
- the value
- the type, which can be fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_START, fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_VAL or fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_STOP.
fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_VAL are written by every fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>udioTrack::recordAutomation
call, fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_START and fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_STOP are generated by
fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::startAutoRecord and fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>topAutoRecord, respectively.
- and the id of the controller which is affected
It is processed when the song is stopped. The call path for this is:
fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::stopRolling calls fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::processAutomationEvents
calls fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::processAutomationEvents.
This function removes the old events from the track's controller list
and replaces them with the new events from fterfirst_`_=95 _ `_=58 :
`_>64
`_<91 ___
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>recEvents. In
fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_WRITE mode, just all controller events within the recorded
range are erased; in fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_TOUCH mode, the fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_START
and fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>RVT_STOP types of the fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlRecVal events are used
to determine the range(s) which should be wiped.
Automation data is kept in fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::_controller, which is a fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlListList, that is, a list of fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlLists, that is, a list of lists of
controller-objects which hold the control points of the automation graph.
The fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlList 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 fterfirst_`_=95 _ `_=58 :
`_>64
`_<91 ___
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>curVal (accessed by fterfirstc`c=95 _ `c=58 :
`c>64
`c<91 ccc
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>urVal()),
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.
fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udioTrack::addController and fterfirstr`r=95 _ `r=58 :
`r>64
`r<91 rrr
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>emoveController are used to add/remove whole controller types; the most important functions which
access fterfirst_`_=95 _ `_=58 :
`_>64
`_<91 ___
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>controller are:
- fterfirstp`p=95 _ `p=58 :
`p>64
`p<91 ppp
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>rocessAutomationEvents, fterfirstr`r=95 _ `r=58 :
`r>64
`r<91 rrr
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ecordAutomation,
fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>tartAutoRecord, fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>topAutoRecord: see above.
- fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>eekPrevACEvent, fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>eekNextACEvent, fterfirste`e=95 _ `e=58 :
`e>64
`e<91 eee
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>raseACEvent,
fterfirste`e=95 _ `e=58 :
`e>64
`e<91 eee
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>raseRangeACEvents, fterfirsta`a=95 _ `a=58 :
`a>64
`a<91 aaa
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ddACEvent, fterfirstc`c=95 _ `c=58 :
`c>64
`c<91 ccc
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>hangeACEvent,
which do the obvious
- fterfirstp`p=95 _ `p=58 :
`p>64
`p<91 ppp
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginCtrlVal, fterfirsts`s=95 _ `s=58 :
`s>64
`s<91 sss
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>etPluginCtrlVal: the first
returns the current value according to the fterfirst_`_=95 _ `_=58 :
`_>64
`_<91 ___
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>controller
list, the second only sets the fterfirstc`c=95 _ `c=58 :
`c>64
`c<91 ccc
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>urVal, but does not
insert any events.
Whenever a fterfirstC`C=95 _ `C=58 :
`C>64
`C<91 CCC
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlList has been manipulated,
fterfirstM`M=95 _ `M=58 :
`M>64
`M<91 MMM
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>usEGlobal::song->controllerChange(Track*) shall be called,
which emits the fterfirstM`M=95 _ `M=58 :
`M>64
`M<91 MMM
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>usEGlobal::song->controllerChanged(Track*)
signal in order to inform any parts of MusE about the change (currently,
only the arranger's part canvas utilizes this).
Disabling the controller is both dependent from the current automation
mode and from whether the GUI is native or not.
In fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_WRITE 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.
In fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_TOUCH (and currently (r1492) fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_READ, 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 fterfirstA`A=95 _ `A=58 : A
<`<=95 _ `<=58 : <
u@nderscorehyph<271>>UTO_WRITE mode.
The responsible functions are: fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::oscControl and
fterfirstD`D=95 _ `D=58 :
`D>64
`D<91 DDD
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ssiSynthIF::oscControl for handling native GUIs,
fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::ctrlPressed and fterfirstc`c=95 _ `c=58 :
`c>64
`c<91 ccc
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>trlReleased for MusE
default GUIs and fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::guiParamPressed,
fterfirstg`g=95 _ `g=58 :
`g>64
`g<91 ggg
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>uiParamReleased, fterfirstg`g=95 _ `g=58 :
`g>64
`g<91 ggg
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>uiSliderPressed and
fterfirstg`g=95 _ `g=58 :
`g>64
`g<91 ggg
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>uiSliderReleased for MusE GUIs read from a UI file;
fterfirstg`g=95 _ `g=58 :
`g>64
`g<91 ggg
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>uiSlider* obviously handle sliders, while fterfirstg`g=95 _ `g=58 :
`g>64
`g<91 ggg
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>uiParam*
handle everything else which is not a slider. They call
fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::enableController to enable/disable it.
Furthermore, on every song stop or seek, fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::enableAllControllers
is called, which re-enables all controllers again. The call paths for
this are:
- For stop: fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::stopRolling calls
fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::processAutomationEvents calls
fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::clearRecAutomation calls
fterfirstT`T=95 _ `T=58 :
`T>64
`T<91 TTT
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>rack::clearRecAutomation calls
fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::enableAllControllers
- For seek: fterfirstA`A=95 _ `A=58 :
`A>64
`A<91 AAA
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>udio::seek sends a message ("fterfirstG`G=95 _ `G=58 :
`G>64
`G<91 GGG
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>") to
fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::seqSignal which calls
fterfirstS`S=95 _ `S=58 :
`S>64
`S<91 SSS
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>ong::clearRecAutomation which calls
fterfirstP`P=95 _ `P=58 :
`P>64
`P<91 PPP
<`<=95 _ `<=58 :
`<>64
`<<91 <<<
c@amelhyph<269>>luginI::enableAllControllers