Mixer: Implement basic groups.
This commit is contained in:
parent
d2b2c0808d
commit
5ccc6e7595
|
@ -24,31 +24,45 @@ Jonathan Moore Liles <a href="mailto:male@tuxfamily.org"><male@tuxfamily.org&
|
|||
|
||||
<ul><li><a href="#n:1.1.1.">1.1.1. Display Options</a>
|
||||
|
||||
<li><a href="#n:1.1.2.">1.1.2. Mixer Strips</a>
|
||||
<li><a href="#n:1.1.2.">1.1.2. Mixer Groups</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.2.1.">1.1.2.1. Navigation</a>
|
||||
<ul><li><a href="#n:1.1.2.1.">1.1.2.1. How to Choose Groupings</a>
|
||||
|
||||
<li><a href="#n:1.1.2.2.">1.1.2.2. Control</a>
|
||||
<li><a href="#n:1.1.2.2.">1.1.2.2. Considering JACK Overhead</a>
|
||||
|
||||
<li><a href="#n:1.1.2.3.">1.1.2.3. Signal Chain</a>
|
||||
<li><a href="#n:1.1.2.3.">1.1.2.3. Creating a New Group</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.2.3.1.">1.1.2.3.1. Modules</a>
|
||||
<li><a href="#n:1.1.2.4.">1.1.2.4. Adding a Strip to an Existing Group</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.2.3.1.1.">1.1.2.3.1.1. OSC Control</a>
|
||||
<li><a href="#n:1.1.2.5.">1.1.2.5. Removing a Strip from a Group</a>
|
||||
|
||||
<li><a href="#n:1.1.2.3.1.2.">1.1.2.3.1.2. Manipulation</a>
|
||||
<li><a href="#n:1.1.2.6.">1.1.2.6. Removing a Group</a>
|
||||
|
||||
<li><a href="#n:1.1.2.3.1.3.">1.1.2.3.1.3. Module Parameter Editor</a>
|
||||
</ul><li><a href="#n:1.1.3.">1.1.3. Mixer Strips</a>
|
||||
|
||||
<li><a href="#n:1.1.2.3.1.4.">1.1.2.3.1.4. Controls</a>
|
||||
<ul><li><a href="#n:1.1.3.1.">1.1.3.1. Navigation</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.2.3.1.4.1.">1.1.2.3.1.4.1. Control Voltages</a>
|
||||
<li><a href="#n:1.1.3.2.">1.1.3.2. Control</a>
|
||||
|
||||
</ul><li><a href="#n:1.1.2.3.1.5.">1.1.2.3.1.5. Spatialization </a>
|
||||
<li><a href="#n:1.1.3.3.">1.1.3.3. Signal Chain</a>
|
||||
|
||||
</ul></ul></ul><li><a href="#n:1.1.3.">1.1.3. Projects</a>
|
||||
<ul><li><a href="#n:1.1.3.3.1.">1.1.3.3.1. Modules</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.3.1.">1.1.3.1. JACK I/O</a>
|
||||
<ul><li><a href="#n:1.1.3.3.1.1.">1.1.3.3.1.1. OSC Control</a>
|
||||
|
||||
<li><a href="#n:1.1.3.3.1.2.">1.1.3.3.1.2. Manipulation</a>
|
||||
|
||||
<li><a href="#n:1.1.3.3.1.3.">1.1.3.3.1.3. Module Parameter Editor</a>
|
||||
|
||||
<li><a href="#n:1.1.3.3.1.4.">1.1.3.3.1.4. Controls</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.3.3.1.4.1.">1.1.3.3.1.4.1. Control Voltages</a>
|
||||
|
||||
</ul><li><a href="#n:1.1.3.3.1.5.">1.1.3.3.1.5. Spatialization </a>
|
||||
|
||||
</ul></ul></ul><li><a href="#n:1.1.4.">1.1.4. Projects</a>
|
||||
|
||||
<ul><li><a href="#n:1.1.4.1.">1.1.4.1. JACK I/O</a>
|
||||
|
||||
</ul></ul></ul></ul></ul><hr></div>
|
||||
<h1 id="n:1.">1. User Manual</h1>
|
||||
|
@ -80,7 +94,100 @@ After the project has been created. Hit <tt>a</tt> or choose <tt>Mixer/Add Strip
|
|||
<p>
|
||||
The display options, found in the <tt>Options/Display</tt> submenu may be adjusted to suit your needs. Set the color scheme, widget style, and other graphic options to your liking. These options are global and affect all projects.
|
||||
</p>
|
||||
<h3 id="n:1.1.2.">1.1.2. Mixer Strips</h3>
|
||||
<h3 id="n:1.1.2.">1.1.2. Mixer Groups</h3>
|
||||
<p>
|
||||
Groups serve several purposes. Firstly, they allow for some organization of strips. Groups also allow parallel relationships of mixer strips to be made explicit. This has important performance implications in JACK2. Non Mixer supports an unlimited number of groups, each of which can contain an unlimited number of mixer strips.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.1.">1.1.2.1. How to Choose Groupings</h4>
|
||||
<p>
|
||||
All strips in a group should be completely parallel with no feedback loop connections. A typical group might be named 'Input' and contain all input strips (strips that accept input from Non Timeline and have outputs all connecting to some master bus).
|
||||
</p>
|
||||
<p>
|
||||
To put it another way, if you have 100 inputs strips with identical output configurations (e.g. stereo or B-Format), that all connect to a master bus, then you have a candidate for a group.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.2.">1.1.2.2. Considering JACK Overhead</h4>
|
||||
<p>
|
||||
JACK provides immense flexibility. But, as in most situations, that flexibility comes with a cost. In JACK the cost is a context switch per client. This applies <i>even for many clients which belong to the same process</i>, as in Non Mixer. Various factors go into determining the price of a context switch on any given system. It's not very expensive, but it does add up. It becomes problematic in sessions involving many clients (think 100s), each of which having a small DSP load (often smaller than the cost of JACK's context context switch). JACK <b>could</b> be smart enough to recognize that some clients belong to the same process and could be executed serially without requiring a context switch, but at the time of writing neither JACK1 nor JACK2's scheduling is that smart.
|
||||
</p>
|
||||
<p>
|
||||
If you're mixing a normal song (couple of dozen tracks) at low latency, this overhead will probably account for less than 1% of the total DSP load. If you're mixing an entire orchestra at ultra-low latency, then it might account for a quarter or more of the total DSP load.
|
||||
</p>
|
||||
<p>
|
||||
Groups mitigate this cost by reducing the number of JACK clients required for a mix. Strips in a group will execute serially without context switches or thread synchronization--reducing the total JACK overhead. However, if you have several groups, then they may all by run in parallel by JACK2.
|
||||
</p>
|
||||
<p>
|
||||
<p>
|
||||
To illustrate this point here are some figures from an actual song session including the whole Non suite plus a sampler, a synth and an ambisonics convolution reverb with a total of 13 strips in 4 groups in different configurations on the same system.
|
||||
</p>
|
||||
<p>
|
||||
JACK's DSP load figures are interpreted thus: if at a 2.7ms software latency setting the average time a proces cycle takes to complete is 2.7ms, then the DSP load is 100%. The usable ceiling on DSP load is 80%. This is true for both JACK1 and JACK2. The difference is that JACK2 may use all available CPU cores to execute the graph \(if there are enough clients in parallel signal flow\).
|
||||
</p>
|
||||
<p>
|
||||
32-bit Intel Core2 Duo @1.6Ghz -r 48000 -p 256 -n 2 (5.3ms)
|
||||
</p>
|
||||
<center><div class="fig table"><table border=1>
|
||||
<tr><th>JACK Ver</th><th>Groups</th><th>DSP Load</th></tr>
|
||||
<tr><td>JACK1</td><td>N</td><td>39%</td></tr>
|
||||
<tr><td>JACK1</td><td>Y</td><td>27%</td></tr>
|
||||
<tr><td>JACK2</td><td>N</td><td>24%</td></tr>
|
||||
<tr><td>JACK2</td><td>Y</td><td>31%</td></tr>
|
||||
</table></div></center>
|
||||
<p>
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 256 -n 2 (5.3ms)
|
||||
</p>
|
||||
<center><div class="fig table"><table border=1>
|
||||
<tr><th>JACK Ver</th><th>Groups</th><th>DSP Load</th></tr>
|
||||
<tr><td>JACK1</td><td>N</td><td>28%</td></tr>
|
||||
<tr><td>JACK1</td><td>Y</td><td>12%</td></tr>
|
||||
<tr><td>JACK2</td><td>N</td><td>12%</td></tr>
|
||||
<tr><td>JACK2</td><td>Y</td><td>11%</td></tr>
|
||||
</table></div></center>
|
||||
<p>
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 128 -n 2 (2.7ms)
|
||||
</p>
|
||||
<center><div class="fig table"><table border=1>
|
||||
<tr><th>JACK Ver</th><th>Groups</th><th>DSP Load</th></tr>
|
||||
<tr><td>JACK1</td><td>N</td><td>29%</td></tr>
|
||||
<tr><td>JACK1</td><td>Y</td><td>17%</td></tr>
|
||||
<tr><td>JACK2</td><td>N</td><td>17%</td></tr>
|
||||
<tr><td>JACK2</td><td>Y</td><td>17%</td></tr>
|
||||
</table></div></center>
|
||||
<p>
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 32 -n 2 (0.7ms)
|
||||
</p>
|
||||
<center><div class="fig table"><table border=1>
|
||||
<tr><th>JACK Ver</th><th>Groups</th><th>DSP Load</th></tr>
|
||||
<tr><td>JACK1</td><td>N</td><td>x</td></tr>
|
||||
<tr><td>JACK1</td><td>Y</td><td>x</td></tr>
|
||||
<tr><td>JACK2</td><td>N</td><td>43%</td></tr>
|
||||
<tr><td>JACK2</td><td>Y</td><td>41%</td></tr>
|
||||
</table></div></center>
|
||||
<p>
|
||||
As you can see, for multiprocessor systems, JACK2 clearly has an advantage even without grouping.
|
||||
</p>
|
||||
<p>
|
||||
Of course, results will vary depending on the system and the mix. On the dual core system, performance actually degraded with JACK2 when using groups--this is because the number of parallel flows that JACK2 detected was reduced and the second core was being under utilized. Similarly, the performance of the 8-core AMD system doesn't seem that great even in the ungrouped mode--this is because the DSP load of each individual client is around the same as the cost of the context switching. It's a wash either way (if each strip had more or more complex modules on it, then the ungrouped mode would probably perform better). Since JACK1 cannot take advantage of more than 1 CPU core, there is no benefit to parallelism and grouped mode always outperforms ungrouped mode.
|
||||
</p>
|
||||
<p>
|
||||
So, for maximum capacity the combination of a multicore CPU with JACK2 and mixer groups is best.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.3.">1.1.2.3. Creating a New Group</h4>
|
||||
<p>
|
||||
Groups can be created by selecting the group dropdown on any mixer strip and choosing 'New Group'. A window will popup asking for a group name. Group names must be unique. The group will then be created and the selected strip added to it.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.4.">1.1.2.4. Adding a Strip to an Existing Group</h4>
|
||||
<p>
|
||||
To add a strip to an existing group, simply select a group name from the group dropdown on the strip.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.5.">1.1.2.5. Removing a Strip from a Group</h4>
|
||||
<p>
|
||||
Select '---' from the group dropdown. The strip will be removed from the group and will run in an independent JACK client.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.6.">1.1.2.6. Removing a Group</h4>
|
||||
<p>
|
||||
Groups are destroyed automatically as soon as they contain zero strips.
|
||||
</p>
|
||||
<h3 id="n:1.1.3.">1.1.3. Mixer Strips</h3>
|
||||
<center><div class="fig image"><table id="Fig.1.3" border=1>
|
||||
<caption>
|
||||
<strong>Fig. 1.3.</strong> Mixer Strip
|
||||
|
@ -101,19 +208,19 @@ The fader view comprises a large gain control and digital peak meter indicator.
|
|||
<p>
|
||||
To see how an audio signal traveling through this strip will be processed, switch to its <i>signal</i> view.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.1.">1.1.2.1. Navigation</h4>
|
||||
<h4 id="n:1.1.3.1.">1.1.3.1. Navigation</h4>
|
||||
<p>
|
||||
A strip is focused when you click on it. Focus can be moved among strips with the <tt>Tab</tt> and <tt>Shift-Tab</tt> keys.
|
||||
</p>
|
||||
<h4 id="n:1.1.2.2.">1.1.2.2. Control</h4>
|
||||
<h4 id="n:1.1.3.2.">1.1.3.2. Control</h4>
|
||||
<p>
|
||||
The focused strip can be moved in the display order via the <tt>[</tt> and <tt>]</tt> keys. <tt>Delete</tt> removes a strip (with confirmation dialog). <tt>n</tt> and <tt>w</tt> set the focused strip's width to <i>narrow</i> or <i>wide</i>, respectively, and <tt>f</tt> and <tt>s</tt> switch between <i>fader</i> and <i>signal</i> views. The strip's context menu can be invoked without the mouse by hitting the <tt>Menu</tt> key (assuming your keyboard has one).
|
||||
</p>
|
||||
<h4 id="n:1.1.2.3.">1.1.2.3. Signal Chain</h4>
|
||||
<h4 id="n:1.1.3.3.">1.1.3.3. Signal Chain</h4>
|
||||
<p>
|
||||
The signal chain view of a mixer strip provides a way to view and manipulate the signal processing of a mixer strip.
|
||||
</p>
|
||||
<h5 id="n:1.1.2.3.1.">1.1.2.3.1. Modules</h5>
|
||||
<h5 id="n:1.1.3.3.1.">1.1.3.3.1. Modules</h5>
|
||||
<center><div class="fig image"><table id="Fig.1.4" border=1>
|
||||
<caption>
|
||||
<strong>Fig. 1.4.</strong> Modules
|
||||
|
@ -148,7 +255,7 @@ Non Mixer has several built-in modules. They are:
|
|||
<dt><em>Plugin</em></dt>
|
||||
<dd>Hosts a LADSPA plugin</dd>
|
||||
</dl>
|
||||
<h6 id="n:1.1.2.3.1.1.">1.1.2.3.1.1. OSC Control</h6>
|
||||
<h6 id="n:1.1.3.3.1.1.">1.1.3.3.1.1. OSC Control</h6>
|
||||
<p>
|
||||
The input parameters of all modules are controllable via OSC, regardless of whether the parameter is set as controllable.
|
||||
</p>
|
||||
|
@ -185,7 +292,7 @@ For the second instance of the Gain module on the strip named 'Foo'.
|
|||
<p>
|
||||
Non-DAW accesses these same signals via a more advanced signal routing layer on top of OSC. Any module parameter is easily controlled via Control Sequences in Non-DAW without the need to specify an OSC URL.
|
||||
</p>
|
||||
<h6 id="n:1.1.2.3.1.2.">1.1.2.3.1.2. Manipulation</h6>
|
||||
<h6 id="n:1.1.3.3.1.2.">1.1.3.3.1.2. Manipulation</h6>
|
||||
<p>
|
||||
Left-clicking on a module brings up a Module Parameter Editor window for the selected module.
|
||||
</p>
|
||||
|
@ -201,7 +308,7 @@ Control+Right-clicking on a module causes it to be removed from the chain (modul
|
|||
<p>
|
||||
The focused module may also be controlled via the keyboard. <tt>Menu</tt> brings up the context menu for the focused module. <tt>Space</tt> opens the module parameter editor, <tt>b</tt> toggles the bypassed state, and <tt>Delete</tt> removes the module from the chain (without confirmation!). <tt>Control-X</tt>, <tt>Control-C</tt> and <tt>Control-V</tt>, cut, copy, and paste modules, respectively. Modules may be copied within or across chain boundaries. The normal module I/O constraints also apply to pasted modules.
|
||||
</p>
|
||||
<h6 id="n:1.1.2.3.1.3.">1.1.2.3.1.3. Module Parameter Editor</h6>
|
||||
<h6 id="n:1.1.3.3.1.3.">1.1.3.3.1.3. Module Parameter Editor</h6>
|
||||
<center><div class="fig image"><table id="Fig.1.5" border=1>
|
||||
<caption>
|
||||
<strong>Fig. 1.5.</strong> Module Parameter Editor
|
||||
|
@ -229,7 +336,7 @@ The Module Parameter Editor is used to alter the values of a module's parameters
|
|||
<p>
|
||||
Underneath each control is a bind button. Clicking adds a new control to the chain's <i>Controls</i> view and binds it to the parameter in question. For simplicity, only one control at a time may be bound to a given parameter.
|
||||
</p>
|
||||
<h6 id="n:1.1.2.3.1.4.">1.1.2.3.1.4. Controls</h6>
|
||||
<h6 id="n:1.1.3.3.1.4.">1.1.3.3.1.4. Controls</h6>
|
||||
<center><div class="fig image"><table id="Fig.1.8" border=1>
|
||||
<caption>
|
||||
<strong>Fig. 1.8.</strong> Control View
|
||||
|
@ -248,7 +355,7 @@ events. Hold down the `Ctrl` key while scrolling the mousewheel to
|
|||
achieve finer resolution.
|
||||
</td></table>
|
||||
</div>
|
||||
<h7 id="n:1.1.2.3.1.4.1.">1.1.2.3.1.4.1. Control Voltages</h7>
|
||||
<h7 id="n:1.1.3.3.1.4.1.">1.1.3.3.1.4.1. Control Voltages</h7>
|
||||
<p>
|
||||
The control voltage concept should be familiar to anyone who has experience with analog modular synthesizers. MIDI, while having definite advantages in many respects, multiplexes control data in such a way as to make connecting one MIDI control to a parameter involve a significant inconvenience, usually requiring the adjustment of settings on both ends of the connection in order to separate the control data streams.
|
||||
</p>
|
||||
|
@ -267,7 +374,7 @@ of parameter automation, as LADSPA plugins are incapable of
|
|||
processing Control Voltage signals at full audio resolution anyway.
|
||||
</td></table>
|
||||
</div>
|
||||
<h6 id="n:1.1.2.3.1.5.">1.1.2.3.1.5. Spatialization </h6>
|
||||
<h6 id="n:1.1.3.3.1.5.">1.1.3.3.1.5. Spatialization </h6>
|
||||
<center><div class="fig image"><table id="Fig.1.9" border=1>
|
||||
<caption>
|
||||
<strong>Fig. 1.9.</strong> Spatialization Control on a Strip
|
||||
|
@ -291,7 +398,7 @@ The spatialization control may be visualized as moving the sound source across t
|
|||
<p>
|
||||
The output of the spatializing plugin may be routed into a decoding plugin following it the same strip or, more usefully, the output of a number of Ambisonic panning plugins on different strips may be routed (through JACK) into a single master decoder instance on a final strip.
|
||||
</p>
|
||||
<h3 id="n:1.1.3.">1.1.3. Projects</h3>
|
||||
<h3 id="n:1.1.4.">1.1.4. Projects</h3>
|
||||
<p>
|
||||
A Non-Mixer project is a directory where Non-Mixer keeps the strip settings, project specific settings, and some meta-data. A project is completely self-contained. You can rename a project as simply as:
|
||||
</p>
|
||||
|
@ -299,7 +406,7 @@ A Non-Mixer project is a directory where Non-Mixer keeps the strip settings, pro
|
|||
$ mv Project-A Project-B
|
||||
</pre></td></tr>
|
||||
</table></div>
|
||||
<h4 id="n:1.1.3.1.">1.1.3.1. JACK I/O</h4>
|
||||
<h4 id="n:1.1.4.1.">1.1.4.1. JACK I/O</h4>
|
||||
<p>
|
||||
Each mixer strip is presented as a separate JACK "client". This helps to avoid the necessity of internally duplicating JACK's routing logic and, with JACK2, permits the possibility of parallel execution of mixer strip signal chains.
|
||||
</p>
|
||||
|
|
|
@ -31,6 +31,151 @@
|
|||
to suit your needs. Set the color scheme, widget style, and other graphic
|
||||
options to your liking. These options are global and affect all projects.
|
||||
|
||||
::: Mixer Groups
|
||||
|
||||
Groups serve several purposes. Firstly, they allow for some
|
||||
organization of strips. Groups also allow parallel relationships of
|
||||
mixer strips to be made explicit. This has important performance
|
||||
implications in JACK2. Non Mixer supports an unlimited number of
|
||||
groups, each of which can contain an unlimited number of mixer
|
||||
strips.
|
||||
|
||||
:::: How to Choose Groupings
|
||||
|
||||
All strips in a group should be completely parallel with no feedback
|
||||
loop connections. A typical group might be named 'Input' and contain
|
||||
all input strips (strips that accept input from Non Timeline and
|
||||
have outputs all connecting to some master bus).
|
||||
|
||||
To put it another way, if you have 100 inputs strips with identical
|
||||
output configurations (e.g. stereo or B-Format), that all connect to
|
||||
a master bus, then you have a candidate for a group.
|
||||
|
||||
:::: Considering JACK Overhead
|
||||
|
||||
JACK provides immense flexibility. But, as in most situations, that
|
||||
flexibility comes with a cost. In JACK the cost is a context switch
|
||||
per client. This applies /even for many clients which belong to the
|
||||
same process/, as in Non Mixer. Various factors go into determining
|
||||
the price of a context switch on any given system. It's not very
|
||||
expensive, but it does add up. It becomes problematic in sessions
|
||||
involving many clients (think 100s), each of which having a small
|
||||
DSP load (often smaller than the cost of JACK's context context
|
||||
switch). JACK *could* be smart enough to recognize that some clients
|
||||
belong to the same process and could be executed serially without
|
||||
requiring a context switch, but at the time of writing neither JACK1
|
||||
nor JACK2's scheduling is that smart.
|
||||
|
||||
If you're mixing a normal song (couple of dozen tracks) at low
|
||||
latency, this overhead will probably account for less than 1% of the
|
||||
total DSP load. If you're mixing an entire orchestra at ultra-low
|
||||
latency, then it might account for a quarter or more of the total
|
||||
DSP load.
|
||||
|
||||
Groups mitigate this cost by reducing the number of JACK clients
|
||||
required for a mix. Strips in a group will execute serially without
|
||||
context switches or thread synchronization--reducing the total JACK
|
||||
overhead. However, if you have several groups, then they may all by
|
||||
run in parallel by JACK2.
|
||||
|
||||
A mixer which uses a single JACK client (which is basically the way
|
||||
everything other than Non Mixer has been designed) is not a viable
|
||||
solution by this author's definition, because such a mixer cannot be
|
||||
from/to any other JACK clients without introducing an extra period
|
||||
of latency.
|
||||
|
||||
To illustrate this point here are some figures from an actual song
|
||||
session including the whole Non suite plus a sampler, a synth and an
|
||||
ambisonics convolution reverb with a total of 13 strips in 4 groups
|
||||
in different configurations on the same system.
|
||||
|
||||
JACK's DSP load figures are interpreted thus: if at a 2.7ms software
|
||||
latency setting the average time a proces cycle takes to complete is
|
||||
2.7ms, then the DSP load is 100%. The usable ceiling on DSP load is
|
||||
80%. This is true for both JACK1 and JACK2. The difference is that
|
||||
JACK2 may use all available CPU cores to execute the graph \(if
|
||||
there are enough clients in parallel signal flow\).
|
||||
|
||||
32-bit Intel Core2 Duo @1.6Ghz -r 48000 -p 256 -n 2 (5.3ms)
|
||||
|
||||
[[ JACK Ver, Groups, DSP Load
|
||||
[[ JACK1, N, 39%
|
||||
[[ JACK1, Y, 27%
|
||||
[[ JACK2, N, 24%
|
||||
[[ JACK2, Y, 31%
|
||||
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 256 -n 2 (5.3ms)
|
||||
|
||||
[[ JACK Ver, Groups, DSP Load
|
||||
[[ JACK1, N, 28%
|
||||
[[ JACK1, Y, 12%
|
||||
[[ JACK2, N, 12%
|
||||
[[ JACK2, Y, 11%
|
||||
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 128 -n 2 (2.7ms)
|
||||
|
||||
[[ JACK Ver, Groups, DSP Load
|
||||
[[ JACK1, N, 29%
|
||||
[[ JACK1, Y, 17%
|
||||
[[ JACK2, N, 17%
|
||||
[[ JACK2, Y, 17%
|
||||
|
||||
AMD FX-8350 @ 4.2Ghz 64-bit -r 48000 -p 32 -n 2 (0.7ms)
|
||||
|
||||
[[ JACK Ver, Groups, DSP Load
|
||||
[[ JACK1, N, x
|
||||
[[ JACK1, Y, x
|
||||
[[ JACK2, N, 43%
|
||||
[[ JACK2, Y, 41%
|
||||
|
||||
As you can see, for multiprocessor systems, JACK2 clearly has an
|
||||
advantage even without grouping.
|
||||
|
||||
Of course, results will vary depending on the system and the mix. On
|
||||
the dual core system, performance actually degraded with JACK2 when
|
||||
using groups--this is because the number of parallel flows that
|
||||
JACK2 detected was reduced and the second core was being under
|
||||
utilized. Similarly, the performance of the 8-core AMD system
|
||||
doesn't seem that great even in the ungrouped mode--this is because
|
||||
the DSP load of each individual client is around the same as the
|
||||
cost of the context switching. It's a wash either way (if each strip
|
||||
had more or more complex modules on it, then the ungrouped mode
|
||||
would probably perform better). Since JACK1 cannot take advantage of
|
||||
more than 1 CPU core, there is no benefit to parallelism and grouped
|
||||
mode always outperforms ungrouped mode.
|
||||
|
||||
So, for maximum capacity the combination of a multicore CPU with
|
||||
JACK2 and mixer groups is best.
|
||||
|
||||
# All strips in a group *MUST* have the same output configuration. All
|
||||
# outputs will be mixed together by identity. That is, the 'AUX \(A\)'
|
||||
# outputs of each strip will be mixed together into a single 'AUX \(A\)'
|
||||
# output of the group. A strip within a group whose output
|
||||
# configuration differs from the group configuration will be marked as
|
||||
# invalid and will not be executed.
|
||||
|
||||
:::: Creating a New Group
|
||||
|
||||
Groups can be created by selecting the group dropdown on any mixer
|
||||
strip and choosing 'New Group'. A window will popup asking for a
|
||||
group name. Group names must be unique. The group will then be
|
||||
created and the selected strip added to it.
|
||||
|
||||
:::: Adding a Strip to an Existing Group
|
||||
|
||||
To add a strip to an existing group, simply select a group name from
|
||||
the group dropdown on the strip.
|
||||
|
||||
:::: Removing a Strip from a Group
|
||||
|
||||
Select '---' from the group dropdown. The strip will be removed from
|
||||
the group and will run in an independent JACK client.
|
||||
|
||||
:::: Removing a Group
|
||||
|
||||
Groups are destroyed automatically as soon as they contain zero
|
||||
strips.
|
||||
|
||||
::: Mixer Strips
|
||||
|
||||
/ Mixer Strip
|
||||
|
|
|
@ -122,7 +122,7 @@ AUX_Module::process ( nframes_t nframes )
|
|||
for ( unsigned int i = 0; i < audio_input.size(); ++i )
|
||||
{
|
||||
if ( audio_input[i].connected() )
|
||||
buffer_copy_and_apply_gain_buffer( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), gainbuf, nframes );
|
||||
buffer_copy_and_apply_gain_buffer( (sample_t*)aux_audio_output[i].buffer(), (sample_t*)audio_input[i].buffer(), gainbuf, nframes );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ AUX_Module::process ( nframes_t nframes )
|
|||
for ( unsigned int i = 0; i < audio_input.size(); ++i )
|
||||
{
|
||||
if ( audio_input[i].connected() )
|
||||
buffer_copy_and_apply_gain( (sample_t*)jack_output[i].buffer( nframes ), (sample_t*)audio_input[i].buffer(), nframes, gt );
|
||||
buffer_copy_and_apply_gain( (sample_t*)aux_audio_output[i].buffer(), (sample_t*)audio_input[i].buffer(), nframes, gt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ AUX_Module::process ( nframes_t nframes )
|
|||
for ( unsigned int i = 0; i < audio_input.size(); ++i )
|
||||
{
|
||||
if ( audio_input[i].connected() )
|
||||
buffer_fill_with_silence( (sample_t*)jack_output[i].buffer( nframes ), nframes );
|
||||
buffer_fill_with_silence( (sample_t*)aux_audio_output[i].buffer(), nframes );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,11 +72,11 @@
|
|||
#include "FL/test_press.H"
|
||||
|
||||
#include "debug.h"
|
||||
#include "Engine/Engine.H"
|
||||
#include "Group.H"
|
||||
|
||||
#include "Mixer_Strip.H"
|
||||
#include <dsp.h>
|
||||
|
||||
#include "Mixer.H"
|
||||
extern char *instance_name;
|
||||
|
||||
|
||||
|
@ -87,7 +87,6 @@ Chain::Chain ( ) : Fl_Group( 0, 0, 100, 100, "")
|
|||
|
||||
{
|
||||
_deleting = false;
|
||||
_engine = NULL;
|
||||
|
||||
int X = 0;
|
||||
int Y = 0;
|
||||
|
@ -174,18 +173,23 @@ Chain::~Chain ( )
|
|||
|
||||
_deleting = true;
|
||||
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
for ( unsigned int i = scratch_port.size(); i--; )
|
||||
delete[] (sample_t*)scratch_port[i].buffer();
|
||||
|
||||
/* if we leave this up to FLTK, it will happen after we've
|
||||
already destroyed the engine */
|
||||
already destroyed the client */
|
||||
modules_pack->clear();
|
||||
controls_pack->clear();
|
||||
|
||||
delete _engine;
|
||||
_engine = NULL;
|
||||
client()->unlock();
|
||||
}
|
||||
|
||||
Group *
|
||||
Chain::client ( void )
|
||||
{
|
||||
return strip()->group();
|
||||
}
|
||||
|
||||
|
||||
|
@ -302,7 +306,7 @@ Chain::remove ( Controller_Module *m )
|
|||
{
|
||||
DMESSAGE( "Removing controller module from chain" );
|
||||
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
m->disconnect();
|
||||
|
||||
|
@ -311,7 +315,7 @@ Chain::remove ( Controller_Module *m )
|
|||
|
||||
build_process_queue();
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
@ -340,7 +344,7 @@ Chain::remove ( Module *m )
|
|||
fl_alert( "Can't remove module at this point because the resultant chain is invalid" );
|
||||
}
|
||||
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
strip()->handle_module_removed( m );
|
||||
|
||||
|
@ -348,7 +352,7 @@ Chain::remove ( Module *m )
|
|||
|
||||
configure_ports();
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
}
|
||||
|
||||
/* determine number of output ports, signal if changed. */
|
||||
|
@ -357,7 +361,7 @@ Chain::configure_ports ( void )
|
|||
{
|
||||
int nouts = 0;
|
||||
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
for ( int i = 0; i < modules(); ++i )
|
||||
{
|
||||
|
@ -378,15 +382,15 @@ Chain::configure_ports ( void )
|
|||
for ( unsigned int i = 0; i < req_buffers; ++i )
|
||||
{
|
||||
Module::Port p( NULL, Module::Port::OUTPUT, Module::Port::AUDIO );
|
||||
p.connect_to( new sample_t[engine()->nframes()] );
|
||||
buffer_fill_with_silence( (sample_t*)p.buffer(), engine()->nframes() );
|
||||
p.connect_to( new sample_t[client()->nframes()] );
|
||||
buffer_fill_with_silence( (sample_t*)p.buffer(), client()->nframes() );
|
||||
scratch_port.push_back( p );
|
||||
}
|
||||
}
|
||||
|
||||
build_process_queue();
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
|
||||
parent()->redraw();
|
||||
}
|
||||
|
@ -454,47 +458,40 @@ Chain::maximum_name_length ( void )
|
|||
return JACK::Client::maximum_name_length() - ( strlen( instance_name ) + 1 );
|
||||
}
|
||||
|
||||
void
|
||||
Chain::freeze_ports ( void )
|
||||
{
|
||||
for ( int i = 0; i < modules(); i++ )
|
||||
{
|
||||
Module *m = module(i);
|
||||
m->freeze_ports();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Chain::thaw_ports ( void )
|
||||
{
|
||||
for ( int i = 0; i < modules(); i++ )
|
||||
{
|
||||
Module *m = module(i);
|
||||
m->thaw_ports();
|
||||
}
|
||||
}
|
||||
|
||||
/* rename chain... we have to let our modules know our name has
|
||||
* changed so they can take the appropriate action (in particular the
|
||||
* JACK module). */
|
||||
void
|
||||
Chain::name ( const char *name )
|
||||
{
|
||||
char ename[512];
|
||||
snprintf( ename, sizeof(ename), "%s/%s", instance_name, name );
|
||||
|
||||
if ( ! _engine )
|
||||
{
|
||||
_engine = new Engine( &Chain::process, this );
|
||||
|
||||
engine()->buffer_size_callback( &Chain::buffer_size, this );
|
||||
engine()->port_connect_callback( &Chain::port_connect, this );
|
||||
engine()->sample_rate_changed_callback( &Chain::sample_rate_change, this );
|
||||
|
||||
Module::set_sample_rate( engine()->sample_rate() );
|
||||
|
||||
const char *jack_name = engine()->init( ename );
|
||||
|
||||
if ( ! jack_name )
|
||||
{
|
||||
_engine = NULL;
|
||||
|
||||
fl_alert( "Could not create JACK client. Perhaps the sound device already in use. In any event, now I'll die." );
|
||||
exit( 1 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMESSAGE( "Renaming JACK client from \"%s\" to \"%s\"", _name, ename );
|
||||
|
||||
_name = engine()->name( ename );
|
||||
/* FIXME: discarding the name jack picked is technically wrong! */
|
||||
|
||||
}
|
||||
|
||||
_name = name;
|
||||
|
||||
if ( strip()->group() )
|
||||
{
|
||||
if ( strip()->group()->single() )
|
||||
strip()->group()->name(name);
|
||||
}
|
||||
|
||||
for ( int i = 0; i < modules(); ++i )
|
||||
{
|
||||
module( i )->handle_chain_name_changed();
|
||||
|
@ -522,7 +519,7 @@ Chain::add ( Controller_Module *m )
|
|||
bool
|
||||
Chain::insert ( Module *m, Module *n )
|
||||
{
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
if ( !m )
|
||||
{
|
||||
|
@ -581,7 +578,7 @@ Chain::insert ( Module *m, Module *n )
|
|||
|
||||
configure_ports();
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
|
||||
DMESSAGE( "Module \"%s\" has %i:%i audio and %i:%i control ports",
|
||||
n->name(),
|
||||
|
@ -595,7 +592,7 @@ Chain::insert ( Module *m, Module *n )
|
|||
|
||||
err:
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
|
||||
DMESSAGE( "Insert failed" );
|
||||
|
||||
|
@ -606,13 +603,13 @@ err:
|
|||
void
|
||||
Chain::add_control ( Controller_Module *m )
|
||||
{
|
||||
engine()->lock();
|
||||
client()->lock();
|
||||
|
||||
controls_pack->add( m );
|
||||
|
||||
configure_ports();
|
||||
|
||||
engine()->unlock();
|
||||
client()->unlock();
|
||||
|
||||
controls_pack->redraw();
|
||||
}
|
||||
|
@ -797,15 +794,9 @@ Chain::do_export ( const char *filename )
|
|||
|
||||
|
||||
/**********/
|
||||
/* Engine */
|
||||
/* Client */
|
||||
/**********/
|
||||
|
||||
void
|
||||
Chain::process ( nframes_t nframes, void *v )
|
||||
{
|
||||
((Chain*)v)->process( nframes );
|
||||
}
|
||||
|
||||
void
|
||||
Chain::process ( nframes_t nframes )
|
||||
{
|
||||
|
@ -817,12 +808,6 @@ Chain::process ( nframes_t nframes )
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Chain::buffer_size ( nframes_t nframes, void *v )
|
||||
{
|
||||
((Chain*)v)->buffer_size( nframes );
|
||||
}
|
||||
|
||||
void
|
||||
Chain::buffer_size ( nframes_t nframes )
|
||||
{
|
||||
|
@ -840,12 +825,6 @@ Chain::buffer_size ( nframes_t nframes )
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
Chain::sample_rate_change ( nframes_t nframes, void *v )
|
||||
{
|
||||
return ((Chain*)v)->sample_rate_change( nframes );
|
||||
}
|
||||
|
||||
int
|
||||
Chain::sample_rate_change ( nframes_t nframes )
|
||||
{
|
||||
|
@ -860,12 +839,6 @@ Chain::sample_rate_change ( nframes_t nframes )
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v )
|
||||
{
|
||||
((Chain*)v)->port_connect( a, b, connect );
|
||||
}
|
||||
|
||||
/* handle jack port connection change */
|
||||
void
|
||||
Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect )
|
||||
|
@ -875,8 +848,8 @@ Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect )
|
|||
|
||||
/* this is called from JACK non-RT thread... */
|
||||
|
||||
if ( jack_port_is_mine( engine()->jack_client(), jack_port_by_id( engine()->jack_client(), a ) ) ||
|
||||
jack_port_is_mine( engine()->jack_client(), jack_port_by_id( engine()->jack_client(), b ) ))
|
||||
if ( jack_port_is_mine( client()->jack_client(), jack_port_by_id( client()->jack_client(), a ) ) ||
|
||||
jack_port_is_mine( client()->jack_client(), jack_port_by_id( client()->jack_client(), b ) ))
|
||||
{
|
||||
Fl::awake( Chain::update_connection_status, this );
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
#include <vector>
|
||||
#include <list>
|
||||
#include "Loggable.H"
|
||||
#include "Group.H"
|
||||
|
||||
class Mixer_Strip;
|
||||
class Fl_Flowpack;
|
||||
class Fl_Flip_Button;
|
||||
class Engine;
|
||||
class Controller_Module;
|
||||
|
||||
class Chain : public Fl_Group, public Loggable {
|
||||
|
@ -50,8 +50,6 @@ class Chain : public Fl_Group, public Loggable {
|
|||
|
||||
std::vector <Module::Port> scratch_port;
|
||||
|
||||
Engine *_engine;
|
||||
|
||||
Fl_Callback *_configure_outputs_callback;
|
||||
void *_configure_outputs_userdata;
|
||||
|
||||
|
@ -69,18 +67,6 @@ private:
|
|||
void build_process_queue ( void );
|
||||
void add_to_process_queue ( Module *m );
|
||||
|
||||
static void process ( nframes_t, void * );
|
||||
void process ( nframes_t );
|
||||
|
||||
static void buffer_size ( nframes_t nframes, void *v );
|
||||
void buffer_size ( nframes_t nframes );
|
||||
static int sample_rate_change ( nframes_t nframes, void *v );
|
||||
int sample_rate_change ( nframes_t nframes );
|
||||
|
||||
|
||||
static void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v );
|
||||
void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect );
|
||||
|
||||
static void update_connection_status ( void *v );
|
||||
void update_connection_status ( void );
|
||||
|
||||
|
@ -91,6 +77,11 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect );
|
||||
void buffer_size ( nframes_t nframes );
|
||||
int sample_rate_change ( nframes_t nframes );
|
||||
void process ( nframes_t );
|
||||
|
||||
Chain ( int X, int Y, int W, int H, const char *L = 0 );
|
||||
Chain ( );
|
||||
virtual ~Chain ( );
|
||||
|
@ -140,7 +131,12 @@ public:
|
|||
|
||||
static unsigned int maximum_name_length ( void );
|
||||
|
||||
Engine *engine ( void ) const { return _engine; }
|
||||
Group *client ( void );
|
||||
|
||||
void freeze_ports ( void );
|
||||
void thaw_ports ( void );
|
||||
|
||||
// void client ( Client * );
|
||||
|
||||
LOG_CREATE_FUNC( Chain );
|
||||
};
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "FL/test_press.H"
|
||||
#include "FL/menu_popup.H"
|
||||
|
||||
#include "Engine/Engine.H"
|
||||
#include "Chain.H"
|
||||
#include "OSC/Endpoint.H"
|
||||
|
||||
|
@ -195,40 +194,31 @@ Controller_Module::set ( Log_Entry &e )
|
|||
void
|
||||
Controller_Module::mode ( Mode m )
|
||||
{
|
||||
|
||||
if( mode() != CV && m == CV )
|
||||
{
|
||||
if ( control_output[0].connected() )
|
||||
{
|
||||
chain()->engine()->lock();
|
||||
chain()->client()->lock();
|
||||
|
||||
Port *p = control_output[0].connected_port();
|
||||
|
||||
JACK::Port po( chain()->engine(), JACK::Port::Input, JACK::Port::Audio, p->name(), 0, "CV" );
|
||||
char prefix[512];
|
||||
snprintf( prefix, sizeof(prefix), "CV-%s", p->name() );
|
||||
|
||||
if ( ! po.activate() )
|
||||
{
|
||||
fl_alert( "Could not activate JACK port \"%s\"", po.name() );
|
||||
chain()->engine()->unlock();
|
||||
return;
|
||||
}
|
||||
add_aux_audio_input( prefix, 0 );
|
||||
|
||||
if ( po.valid() )
|
||||
{
|
||||
jack_input.push_back( po );
|
||||
}
|
||||
|
||||
chain()->engine()->unlock();
|
||||
chain()->client()->unlock();
|
||||
}
|
||||
}
|
||||
else if ( mode() == CV && m != CV )
|
||||
{
|
||||
chain()->engine()->lock();
|
||||
chain()->client()->lock();
|
||||
|
||||
jack_input.back().shutdown();
|
||||
jack_input.pop_back();
|
||||
delete aux_audio_input.back().jack_port();
|
||||
|
||||
chain()->engine()->unlock();
|
||||
aux_audio_input.pop_back();
|
||||
|
||||
chain()->client()->unlock();
|
||||
}
|
||||
|
||||
_mode = m ;
|
||||
|
@ -909,7 +899,7 @@ Controller_Module::command_remove ( void )
|
|||
}
|
||||
|
||||
/**********/
|
||||
/* Engine */
|
||||
/* Client */
|
||||
/**********/
|
||||
|
||||
void
|
||||
|
@ -928,7 +918,7 @@ Controller_Module::process ( nframes_t nframes )
|
|||
|
||||
if ( mode() == CV )
|
||||
{
|
||||
f = *((float*)jack_input[0].buffer( nframes ));
|
||||
f = *((float*)aux_audio_input[0].jack_port()->buffer( nframes ));
|
||||
|
||||
const Port *p = control_output[0].connected_port();
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ private:
|
|||
char *generate_osc_path ( void );
|
||||
void change_osc_path ( char *path );
|
||||
|
||||
std::vector<JACK::Port> jack_input;
|
||||
Mode _mode;
|
||||
Type _type;
|
||||
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
|
||||
#include "Engine.H"
|
||||
|
||||
// #include "../Mixer.H" // for process()
|
||||
|
||||
/* This is the home of the JACK process callback */
|
||||
|
||||
// #include "const.h"
|
||||
#include "debug.h"
|
||||
#include "Thread.H"
|
||||
|
||||
|
||||
|
||||
Engine::Engine ( void (*process_callback)(nframes_t nframes, void *), void *user_data ) : _thread( "RT" )
|
||||
{
|
||||
_process_callback = process_callback;
|
||||
_process_callback_user_data = user_data;
|
||||
_buffer_size_callback = 0;
|
||||
_buffers_dropped = 0;
|
||||
_port_connect_callback = 0;
|
||||
_sample_rate_changed_callback = 0;
|
||||
}
|
||||
|
||||
Engine::~Engine ( )
|
||||
{
|
||||
deactivate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Engine::buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void * ), void *user_data )
|
||||
{
|
||||
_buffer_size_callback = buffer_size_callback;
|
||||
_buffer_size_callback_user_data = user_data;
|
||||
}
|
||||
|
||||
void
|
||||
Engine::sample_rate_changed_callback ( int ( *sample_rate_changed_callback ) ( nframes_t, void * ), void *user_data )
|
||||
{
|
||||
_sample_rate_changed_callback = sample_rate_changed_callback;
|
||||
_sample_rate_changed_callback_user_data = user_data;
|
||||
}
|
||||
|
||||
void
|
||||
Engine::port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data )
|
||||
{
|
||||
_port_connect_callback = port_connect_callback;
|
||||
_port_connect_callback_user_data = user_data;
|
||||
}
|
||||
|
||||
/*************/
|
||||
/* Callbacks */
|
||||
/*************/
|
||||
|
||||
/* THREAD: RT */
|
||||
/** This is the jack xrun callback */
|
||||
int
|
||||
Engine::xrun ( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* THREAD: RT */
|
||||
void
|
||||
Engine::freewheel ( bool starting )
|
||||
{
|
||||
if ( starting )
|
||||
DMESSAGE( "entering freewheeling mode" );
|
||||
else
|
||||
DMESSAGE( "leaving freewheeling mode" );
|
||||
}
|
||||
|
||||
/* THREAD: RT (non-RT) */
|
||||
int
|
||||
Engine::buffer_size ( nframes_t nframes )
|
||||
{
|
||||
/* JACK calls this in the RT thread, even though it's a
|
||||
* non-realtime operation. This mucks up our ability to do
|
||||
* THREAD_ASSERT, so just lie and say this is the UI thread... */
|
||||
|
||||
_thread.set( "UI" );
|
||||
|
||||
_buffer_size_callback( nframes, _buffer_size_callback_user_data );
|
||||
|
||||
_thread.set( "RT" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* THREAD: ?? */
|
||||
void
|
||||
Engine::port_connect( jack_port_id_t a, jack_port_id_t b, int connect )
|
||||
{
|
||||
if ( _port_connect_callback )
|
||||
_port_connect_callback( a, b, connect, _port_connect_callback_user_data );
|
||||
}
|
||||
|
||||
|
||||
/* THREAD: RT */
|
||||
int
|
||||
Engine::process ( nframes_t nframes )
|
||||
{
|
||||
/* FIXME: wrong place for this */
|
||||
_thread.set( "RT" );
|
||||
|
||||
if ( ! trylock() )
|
||||
{
|
||||
/* the data structures we need to access here (tracks and
|
||||
* their ports, but not track contents) may be in an
|
||||
* inconsistent state at the moment. Just punt and drop this
|
||||
* buffer. */
|
||||
++_buffers_dropped;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_process_callback(nframes, _process_callback_user_data);
|
||||
|
||||
unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Engine::sample_rate_changed ( nframes_t srate )
|
||||
{
|
||||
if ( _sample_rate_changed_callback )
|
||||
return _sample_rate_changed_callback( srate, _sample_rate_changed_callback_user_data );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TRHEAD: RT */
|
||||
void
|
||||
Engine::thread_init ( void )
|
||||
{
|
||||
_thread.set( "RT" );
|
||||
}
|
||||
|
||||
/* THREAD: RT */
|
||||
void
|
||||
Engine::shutdown ( void )
|
||||
{
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2013 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
/* Free Software Foundation; either version 2 of the License, or (at your */
|
||||
/* option) any later version. */
|
||||
/* */
|
||||
/* This program is distributed in the hope that it will be useful, but WITHOUT */
|
||||
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
|
||||
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
|
||||
/* more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License along */
|
||||
/* with This program; see the file COPYING. If not,write to the Free Software */
|
||||
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
/*******************************************************************************/
|
||||
|
||||
#include <Mixer.H>
|
||||
#include "Group.H"
|
||||
#include "Chain.H"
|
||||
#include "Mixer_Strip.H"
|
||||
#include "Module.H"
|
||||
|
||||
extern char *instance_name;
|
||||
|
||||
Group::Group ( )
|
||||
{
|
||||
_single =false;
|
||||
_name = NULL;
|
||||
}
|
||||
|
||||
Group::Group ( const char *name, bool single ) : Loggable ( !single )
|
||||
{
|
||||
_single = single;
|
||||
_name = strdup(name);
|
||||
|
||||
// this->name( name );
|
||||
|
||||
/* FIXME: handle client creation error */
|
||||
/* if ( ! jack_name ) */
|
||||
/* { */
|
||||
/* _engine = NULL; */
|
||||
|
||||
/* // fl_alert( "Could not create JACK client. Perhaps the sound device already in use. In any event, now I'll die." ); */
|
||||
/* exit( 1 ); */
|
||||
/* // return false; */
|
||||
/* } */
|
||||
}
|
||||
|
||||
Group::~Group ( )
|
||||
{
|
||||
DMESSAGE( "Destroying group" );
|
||||
|
||||
if ( _name )
|
||||
free( _name );
|
||||
|
||||
deactivate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Group::get ( Log_Entry &e ) const
|
||||
{
|
||||
e.add( ":name", name() );
|
||||
}
|
||||
|
||||
void
|
||||
Group::set ( Log_Entry &e )
|
||||
{
|
||||
for ( int i = 0; i < e.size(); ++i )
|
||||
{
|
||||
const char *s, *v;
|
||||
|
||||
e.get( i, &s, &v );
|
||||
|
||||
if ( ! ( strcmp( s, ":name" ) ) )
|
||||
{
|
||||
bool add = false;
|
||||
if (!_name )
|
||||
add = true;
|
||||
|
||||
_name = strdup(v);
|
||||
|
||||
if ( add )
|
||||
mixer->add_group(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************/
|
||||
/* Callbacks */
|
||||
/*************/
|
||||
|
||||
/* THREAD: RT */
|
||||
/** This is the jack xrun callback */
|
||||
int
|
||||
Group::xrun ( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* THREAD: RT */
|
||||
void
|
||||
Group::freewheel ( bool starting )
|
||||
{
|
||||
if ( starting )
|
||||
DMESSAGE( "entering freewheeling mode" );
|
||||
else
|
||||
DMESSAGE( "leaving freewheeling mode" );
|
||||
}
|
||||
|
||||
/* THREAD: RT (non-RT) */
|
||||
int
|
||||
Group::buffer_size ( nframes_t nframes )
|
||||
{
|
||||
/* JACK calls this in the RT thread, even though it's a
|
||||
* non-realtime operation. This mucks up our ability to do
|
||||
* THREAD_ASSERT, so just lie and say this is the UI thread... */
|
||||
|
||||
_thread.set( "UI" );
|
||||
|
||||
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
|
||||
i != strips.end();
|
||||
i++ )
|
||||
{
|
||||
if ( (*i)->chain() )
|
||||
(*i)->chain()->buffer_size(nframes);
|
||||
}
|
||||
|
||||
_thread.set( "RT" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* THREAD: ?? */
|
||||
void
|
||||
Group::port_connect( jack_port_id_t a, jack_port_id_t b, int connect )
|
||||
{
|
||||
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
|
||||
i != strips.end();
|
||||
i++ )
|
||||
{
|
||||
if ( (*i)->chain() )
|
||||
(*i)->chain()->port_connect( a, b, connect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* THREAD: RT */
|
||||
int
|
||||
Group::process ( nframes_t nframes )
|
||||
{
|
||||
/* FIXME: wrong place for this */
|
||||
_thread.set( "RT" );
|
||||
|
||||
if ( ! trylock() )
|
||||
{
|
||||
/* the data structures we need to access here (tracks and
|
||||
* their ports, but not track contents) may be in an
|
||||
* inconsistent state at the moment. Just punt and drop this
|
||||
* buffer. */
|
||||
++_buffers_dropped;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* since feedback loops are forbidden and outputs are
|
||||
* summed, we don't care what order these are processed
|
||||
* in */
|
||||
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
|
||||
i != strips.end();
|
||||
i++ )
|
||||
{
|
||||
if ( (*i)->chain() )
|
||||
(*i)->chain()->process(nframes);
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
Group::sample_rate_changed ( nframes_t srate )
|
||||
{
|
||||
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
|
||||
i != strips.end();
|
||||
i++ )
|
||||
{
|
||||
if ( (*i)->chain() )
|
||||
(*i)->chain()->sample_rate_change(srate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TRHEAD: RT */
|
||||
void
|
||||
Group::thread_init ( void )
|
||||
{
|
||||
_thread.set( "RT" );
|
||||
}
|
||||
|
||||
/* THREAD: RT */
|
||||
void
|
||||
Group::shutdown ( void )
|
||||
{
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* Group interface */
|
||||
/*******************/
|
||||
|
||||
void
|
||||
Group::name ( const char *n )
|
||||
{
|
||||
if ( _name )
|
||||
free( _name );
|
||||
|
||||
char ename[512];
|
||||
|
||||
_name = strdup( n );
|
||||
|
||||
if ( _single )
|
||||
snprintf( ename, sizeof(ename), "%s/%s", instance_name, n );
|
||||
else
|
||||
snprintf( ename, sizeof(ename), "%s (%s)", instance_name, n );
|
||||
|
||||
if ( !active() )
|
||||
{
|
||||
const char *jack_name = Client::init( ename );
|
||||
Module::set_sample_rate( sample_rate() );
|
||||
}
|
||||
else
|
||||
{
|
||||
Client::name( ename );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Group::add ( Mixer_Strip *o )
|
||||
{
|
||||
lock();
|
||||
if ( ! active() )
|
||||
{
|
||||
/* to call init */
|
||||
char *n = strdup(name());
|
||||
name(n);
|
||||
free(n);
|
||||
}
|
||||
if ( o->chain() )
|
||||
o->chain()->thaw_ports();
|
||||
|
||||
strips.push_back(o);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void
|
||||
Group::remove ( Mixer_Strip *o )
|
||||
{
|
||||
lock();
|
||||
strips.remove(o);
|
||||
if ( o->chain() )
|
||||
o->chain()->freeze_ports();
|
||||
if ( strips.size() == 0 && active() )
|
||||
{
|
||||
Client::close();
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
/*******************************************************************************/
|
||||
/* Copyright (C) 2008 Jonathan Moore Liles */
|
||||
/* Copyright (C) 2013 Jonathan Moore Liles */
|
||||
/* */
|
||||
/* This program is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of the GNU General Public License as published by the */
|
||||
|
@ -19,6 +19,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
class Mixer_Strip;
|
||||
|
||||
#include "Mutex.H"
|
||||
|
||||
class Port;
|
||||
|
@ -26,26 +29,18 @@ class Port;
|
|||
#include "JACK/Client.H"
|
||||
|
||||
#include "Thread.H"
|
||||
#include "Loggable.H"
|
||||
|
||||
class Engine : public JACK::Client, public Mutex
|
||||
class Group : public Loggable, public JACK::Client, public Mutex
|
||||
{
|
||||
bool _single;
|
||||
char *_name;
|
||||
|
||||
Thread _thread; /* only used for thread checking */
|
||||
|
||||
int _buffers_dropped; /* buffers dropped because of locking */
|
||||
/* int _buffers_dropped; /\* buffers dropped because of locking *\/ */
|
||||
|
||||
void ( * _process_callback ) ( nframes_t, void * );
|
||||
void *_process_callback_user_data;
|
||||
|
||||
void ( * _buffer_size_callback ) ( nframes_t, void * );
|
||||
void *_buffer_size_callback_user_data;
|
||||
|
||||
int ( * _sample_rate_changed_callback ) ( nframes_t, void * );
|
||||
void *_sample_rate_changed_callback_user_data;
|
||||
|
||||
void ( * _port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void * );
|
||||
void *_port_connect_callback_user_data;
|
||||
|
||||
int sample_rate_changed ( nframes_t srate );
|
||||
void shutdown ( void );
|
||||
int process ( nframes_t nframes );
|
||||
|
@ -54,11 +49,19 @@ class Engine : public JACK::Client, public Mutex
|
|||
int buffer_size ( nframes_t nframes );
|
||||
void thread_init ( void );
|
||||
void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect );
|
||||
Engine ( const Engine &rhs );
|
||||
Engine & operator = ( const Engine &rhs );
|
||||
|
||||
/* not allowed */
|
||||
Group ( const Group &rhs );
|
||||
Group & operator = ( const Group &rhs );
|
||||
|
||||
void request_locate ( nframes_t frame );
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void get ( Log_Entry &e ) const;
|
||||
virtual void set ( Log_Entry &e );
|
||||
|
||||
private:
|
||||
|
||||
friend class Port;
|
||||
|
@ -66,11 +69,28 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
Engine ( void (*process_callback) (nframes_t, void *), void *user_data );
|
||||
~Engine ( );
|
||||
LOG_CREATE_FUNC( Group );
|
||||
|
||||
int nstrips ( void ) const { return strips.size(); }
|
||||
int dropped ( void ) const { return _buffers_dropped; }
|
||||
void buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void * ), void *user_data );
|
||||
void sample_rate_changed_callback ( int ( *sample_rate_changed_callback ) ( nframes_t, void * ), void *user_data );
|
||||
void port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data );
|
||||
|
||||
Group ( );
|
||||
Group ( const char * name, bool single );
|
||||
virtual ~Group ( );
|
||||
|
||||
bool single ( void ) const { return _single; }
|
||||
|
||||
const char * name ( void ) const { return _name; }
|
||||
void name ( const char *n );
|
||||
|
||||
std::list<Mixer_Strip*> strips;
|
||||
|
||||
/* static void process ( nframes_t nframes, void *v ); */
|
||||
/* void process ( nframes_t nframes ); */
|
||||
|
||||
void add (Mixer_Strip*);
|
||||
void remove (Mixer_Strip*);
|
||||
|
||||
/* Engine *engine ( void ) { return _engine; } */
|
||||
};
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
#include "dsp.h"
|
||||
|
||||
#include "Engine/Engine.H"
|
||||
#include "Chain.H"
|
||||
|
||||
#include "JACK_Module.H"
|
||||
|
@ -46,6 +45,9 @@ static Fl_PNG_Image *output_connector_image = NULL;
|
|||
|
||||
extern char *instance_name;
|
||||
|
||||
#include "Mixer.H"
|
||||
#include "Group.H"
|
||||
|
||||
|
||||
static JACK_Module *receptive_to_drop = NULL;
|
||||
|
||||
|
@ -197,18 +199,18 @@ JACK_Module::draw ( void )
|
|||
}
|
||||
|
||||
static std::list<std::string>
|
||||
get_connections_for_ports ( std::vector<JACK::Port> ports )
|
||||
get_connections_for_ports ( std::vector<Module::Port> ports )
|
||||
{
|
||||
std::list<std::string> names;
|
||||
|
||||
for ( unsigned int i = 0; i < ports.size(); ++i )
|
||||
{
|
||||
const char **connections = ports[i].connections();
|
||||
const char **connections = ports[i].jack_port()->connections();
|
||||
|
||||
if ( ! connections )
|
||||
return names;
|
||||
|
||||
bool is_output = ports[i].direction() == JACK::Port::Output;
|
||||
bool is_output = ports[i].jack_port()->direction() == JACK::Port::Output;
|
||||
|
||||
for ( const char **c = connections; *c; c++ )
|
||||
{
|
||||
|
@ -225,6 +227,15 @@ get_connections_for_ports ( std::vector<JACK::Port> ports )
|
|||
strip_name = s;
|
||||
}
|
||||
else
|
||||
if ( 2 == sscanf( *c, "Non-Mixer.%a[^:(] (%a[^:)]):", &client_id, &strip_name ) )
|
||||
{
|
||||
free( client_id );
|
||||
char *s = NULL;
|
||||
asprintf( &s, "%s%s", is_output ? "@r" : "", strip_name );
|
||||
free( strip_name );
|
||||
strip_name = s;
|
||||
}
|
||||
else
|
||||
if ( 2 == sscanf( *c, "Non-Timeline.%a[^:/]:%a[^/]/", &client_id, &strip_name ) )
|
||||
{
|
||||
free( client_id );
|
||||
|
@ -281,8 +292,8 @@ get_connections_for_ports ( std::vector<JACK::Port> ports )
|
|||
void
|
||||
JACK_Module::update_connection_status ( void )
|
||||
{
|
||||
std::list<std::string> output_names = get_connections_for_ports( jack_output );
|
||||
std::list<std::string> input_names = get_connections_for_ports( jack_input );
|
||||
std::list<std::string> output_names = get_connections_for_ports( aux_audio_output );
|
||||
std::list<std::string> input_names = get_connections_for_ports( aux_audio_input );
|
||||
|
||||
connection_display->clear();
|
||||
|
||||
|
@ -349,41 +360,15 @@ JACK_Module::can_support_inputs ( int )
|
|||
|
||||
|
||||
void
|
||||
JACK_Module::remove_jack_outputs ( void )
|
||||
JACK_Module::remove_aux_audio_outputs ( void )
|
||||
{
|
||||
for ( unsigned int i = jack_output.size(); i--; )
|
||||
for ( unsigned int i = aux_audio_output.size(); i--; )
|
||||
{
|
||||
jack_output.back().shutdown();
|
||||
jack_output.pop_back();
|
||||
aux_audio_output.back().jack_port()->shutdown();
|
||||
aux_audio_output.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
JACK_Module::add_jack_output ( const char *prefix, int n )
|
||||
{
|
||||
JACK::Port *po = NULL;
|
||||
|
||||
if ( !prefix )
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Output, JACK::Port::Audio, n );
|
||||
else
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Output, JACK::Port::Audio, prefix, n );
|
||||
|
||||
if ( ! po->activate() )
|
||||
{
|
||||
jack_port_activation_error( po );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( po->valid() )
|
||||
{
|
||||
jack_output.push_back( *po );
|
||||
}
|
||||
|
||||
delete po;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JACK_Module::configure_inputs ( int n )
|
||||
{
|
||||
|
@ -395,33 +380,16 @@ JACK_Module::configure_inputs ( int n )
|
|||
output_connection_handle->show();
|
||||
}
|
||||
|
||||
|
||||
int on = audio_input.size();
|
||||
|
||||
if ( n > on )
|
||||
{
|
||||
for ( int i = on; i < n; ++i )
|
||||
{
|
||||
JACK::Port *po = NULL;
|
||||
|
||||
if ( !_prefix )
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Output, JACK::Port::Audio, i );
|
||||
else
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Output, JACK::Port::Audio, _prefix, i );
|
||||
|
||||
if ( ! po->activate() )
|
||||
{
|
||||
jack_port_activation_error( po );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( po->valid() )
|
||||
if ( add_aux_audio_output(_prefix, i ) )
|
||||
{
|
||||
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
|
||||
jack_output.push_back( *po );
|
||||
}
|
||||
|
||||
delete po;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -430,13 +398,14 @@ JACK_Module::configure_inputs ( int n )
|
|||
{
|
||||
audio_input.back().disconnect();
|
||||
audio_input.pop_back();
|
||||
jack_output.back().shutdown();
|
||||
jack_output.pop_back();
|
||||
aux_audio_output.back().jack_port()->shutdown();
|
||||
delete aux_audio_output.back().jack_port();
|
||||
aux_audio_output.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
_connection_handle_outputs[0][0] = 0;
|
||||
_connection_handle_outputs[0][1] = jack_output.size();
|
||||
_connection_handle_outputs[0][1] = aux_audio_output.size();
|
||||
|
||||
if ( is_default() )
|
||||
control_input[0].control_value_no_callback( n );
|
||||
|
@ -444,12 +413,6 @@ JACK_Module::configure_inputs ( int n )
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JACK_Module::jack_port_activation_error ( JACK::Port *p )
|
||||
{
|
||||
fl_alert( "Could not activate JACK port \"%s\"", p->name() );
|
||||
}
|
||||
|
||||
bool
|
||||
JACK_Module::configure_outputs ( int n )
|
||||
{
|
||||
|
@ -464,26 +427,10 @@ JACK_Module::configure_outputs ( int n )
|
|||
{
|
||||
for ( int i = on; i < n; ++i )
|
||||
{
|
||||
JACK::Port *po = NULL;
|
||||
|
||||
if ( !_prefix )
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Input, JACK::Port::Audio, i );
|
||||
else
|
||||
po = new JACK::Port( chain()->engine(), JACK::Port::Input, JACK::Port::Audio, _prefix, i );
|
||||
|
||||
if ( ! po->activate() )
|
||||
{
|
||||
jack_port_activation_error( po );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( po->valid() )
|
||||
if ( add_aux_audio_input(_prefix, i ) )
|
||||
{
|
||||
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
|
||||
jack_input.push_back( *po );
|
||||
}
|
||||
|
||||
delete po;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -492,8 +439,9 @@ JACK_Module::configure_outputs ( int n )
|
|||
{
|
||||
audio_output.back().disconnect();
|
||||
audio_output.pop_back();
|
||||
jack_input.back().shutdown();
|
||||
jack_input.pop_back();
|
||||
aux_audio_input.back().jack_port()->shutdown();
|
||||
delete aux_audio_input.back().jack_port();
|
||||
aux_audio_input.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -582,10 +530,11 @@ JACK_Module::handle ( int m )
|
|||
s[0] = 0;
|
||||
|
||||
for ( unsigned int i = _connection_handle_outputs[connection_handle][0];
|
||||
i < jack_output.size() && i < _connection_handle_outputs[connection_handle][1]; ++i )
|
||||
i < aux_audio_output.size() && i < _connection_handle_outputs[connection_handle][1]; ++i )
|
||||
{
|
||||
char *s2;
|
||||
asprintf(&s2, "jack.port://%s/%s:%s\r\n", instance_name, chain()->name(), jack_output[i].name() );
|
||||
asprintf(&s2, "jack.port://%s\r\n",
|
||||
aux_audio_output[i].jack_port()->jack_name() );
|
||||
|
||||
s = (char*)realloc( s, strlen( s ) + strlen( s2 ) + 1 );
|
||||
strcat( s, s2 );
|
||||
|
@ -633,7 +582,7 @@ JACK_Module::handle ( int m )
|
|||
if ( this == receptive_to_drop )
|
||||
return 1;
|
||||
|
||||
if ( jack_input.size() )
|
||||
if ( aux_audio_input.size() )
|
||||
{
|
||||
|
||||
receptive_to_drop = this;
|
||||
|
@ -674,11 +623,11 @@ JACK_Module::handle ( int m )
|
|||
text += end;
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < jack_input.size() && i < port_names.size(); i++)
|
||||
for ( unsigned int i = 0; i < aux_audio_input.size() && i < port_names.size(); i++)
|
||||
{
|
||||
const char *pn = port_names[i].c_str();
|
||||
|
||||
JACK::Port *ji = &jack_input[i];
|
||||
JACK::Port *ji = aux_audio_input[i].jack_port();
|
||||
|
||||
if ( ji->connected_to( pn ) )
|
||||
{
|
||||
|
@ -712,17 +661,21 @@ JACK_Module::process ( nframes_t nframes )
|
|||
for ( unsigned int i = 0; i < audio_input.size(); ++i )
|
||||
{
|
||||
if ( audio_input[i].connected() )
|
||||
buffer_copy( (sample_t*)jack_output[i].buffer( nframes ),
|
||||
{
|
||||
buffer_copy( (sample_t*)aux_audio_output[i].jack_port()->buffer(nframes),
|
||||
(sample_t*)audio_input[i].buffer(),
|
||||
nframes );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < audio_output.size(); ++i )
|
||||
{
|
||||
if ( audio_output[i].connected() )
|
||||
{
|
||||
buffer_copy( (sample_t*)audio_output[i].buffer(),
|
||||
(sample_t*)jack_input[i].buffer( nframes ),
|
||||
(sample_t*)aux_audio_input[i].jack_port()->buffer(nframes),
|
||||
nframes );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,11 +42,6 @@ protected:
|
|||
_prefix = strdup( s );
|
||||
}
|
||||
|
||||
std::vector<JACK::Port> jack_input;
|
||||
std::vector<JACK::Port> jack_output;
|
||||
|
||||
static void jack_port_activation_error ( JACK::Port *p );
|
||||
|
||||
Fl_Button * dec_button;
|
||||
Fl_Button * inc_button;
|
||||
Fl_Browser * connection_display;
|
||||
|
@ -76,8 +71,7 @@ public:
|
|||
virtual int handle ( int m );
|
||||
|
||||
virtual int can_support_inputs ( int );
|
||||
bool add_jack_output ( const char *prefix, int n );
|
||||
void remove_jack_outputs ( void );
|
||||
void remove_aux_audio_outputs ( void );
|
||||
virtual bool configure_inputs ( int n );
|
||||
virtual bool configure_outputs ( int n );
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "FL/Fl_Labelpad_Group.H"
|
||||
#include "FL/Fl_Scalepack.H"
|
||||
|
||||
#include "Engine/Engine.H"
|
||||
#include "Chain.H"
|
||||
#include "DPM.H"
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <FL/fl_ask.H>
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/New_Project_Dialog.H>
|
||||
#include "Engine/Engine.H"
|
||||
#include <FL/Fl_Flowpack.H>
|
||||
#include "Project.H"
|
||||
#include <FL/Fl_Menu_Settings.H>
|
||||
|
@ -39,7 +38,7 @@
|
|||
#include <FL/Fl_Value_SliderX.H>
|
||||
#include <Spatialization_Console.H>
|
||||
#include "file.h"
|
||||
|
||||
#include "Group.H"
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
#include <unistd.h>
|
||||
|
@ -60,6 +59,7 @@ extern char *instance_name;
|
|||
|
||||
#include "NSM.H"
|
||||
#include <FL/Fl_Tooltip.H>
|
||||
#include "Chain.H"
|
||||
|
||||
extern NSM_Client *nsm;
|
||||
|
||||
|
@ -499,6 +499,8 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
|
|||
/* Fl_Tooltip::color( fl_color_add_alpha( FL_DARK1, 0 ) ); */
|
||||
// fl_tooltip_docked = 1;
|
||||
|
||||
// _groups.resize(16);
|
||||
|
||||
_rows = 1;
|
||||
_strip_height = 0;
|
||||
box( FL_FLAT_BOX );
|
||||
|
@ -713,6 +715,24 @@ Mixer::~Mixer ( )
|
|||
mixer_strips->clear();
|
||||
}
|
||||
|
||||
void
|
||||
Mixer::add_group ( Group *g )
|
||||
{
|
||||
groups.push_back( g );
|
||||
|
||||
for ( int i = mixer_strips->children(); i--; )
|
||||
((Mixer_Strip*)mixer_strips->child(i))->update_group_choice();
|
||||
}
|
||||
|
||||
void
|
||||
Mixer::remove_group ( Group *g )
|
||||
{
|
||||
groups.remove(g);
|
||||
|
||||
for ( int i = mixer_strips->children(); i--; )
|
||||
((Mixer_Strip*)mixer_strips->child(i))->update_group_choice();
|
||||
}
|
||||
|
||||
void Mixer::resize ( int X, int Y, int W, int H )
|
||||
{
|
||||
Fl_Group::resize( X, Y, W, H );
|
||||
|
@ -755,7 +775,6 @@ Mixer::insert ( Mixer_Strip *ms, Mixer_Strip *before )
|
|||
{
|
||||
// mixer_strips->remove( ms );
|
||||
mixer_strips->insert( *ms, before );
|
||||
|
||||
// scroll->redraw();
|
||||
}
|
||||
void
|
||||
|
@ -796,6 +815,8 @@ void Mixer::remove ( Mixer_Strip *ms )
|
|||
|
||||
mixer_strips->remove( ms );
|
||||
|
||||
ms->group()->remove( ms );
|
||||
|
||||
if ( parent() )
|
||||
parent()->redraw();
|
||||
}
|
||||
|
@ -821,7 +842,7 @@ Mixer::contains ( Mixer_Strip *ms )
|
|||
void
|
||||
Mixer::rows ( int ideal_rows )
|
||||
{
|
||||
int sh;
|
||||
int sh = 0;
|
||||
|
||||
int actual_rows = 1;
|
||||
|
||||
|
@ -919,6 +940,31 @@ Mixer::get_unique_track_name ( const char *name )
|
|||
return strdup( pat );
|
||||
}
|
||||
|
||||
Group *
|
||||
Mixer::group_by_name ( const char *name )
|
||||
{
|
||||
for ( std::list<Group*>::iterator i = groups.begin();
|
||||
i != groups.end();
|
||||
i++ )
|
||||
if ( !strcmp( (*i)->name(), name ))
|
||||
return *i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
Mixer::get_unique_group_name ( const char *name )
|
||||
{
|
||||
char pat[256];
|
||||
|
||||
strcpy( pat, name );
|
||||
|
||||
for ( int i = 1; group_by_name( pat ); ++i )
|
||||
snprintf( pat, sizeof( pat ), "%s.%d", name, i );
|
||||
|
||||
return strdup( pat );
|
||||
}
|
||||
|
||||
void
|
||||
Mixer::handle_dirty ( int d, void *v )
|
||||
{
|
||||
|
@ -939,6 +985,9 @@ Mixer::snapshot ( void )
|
|||
if ( spatialization_console )
|
||||
spatialization_console->log_create();
|
||||
|
||||
for ( std::list<Group*>::iterator i = groups.begin(); i != groups.end(); ++i )
|
||||
(*i)->log_create();
|
||||
|
||||
for ( int i = 0; i < mixer_strips->children(); ++i )
|
||||
((Mixer_Strip*)mixer_strips->child( i ))->log_children();
|
||||
}
|
||||
|
@ -1086,6 +1135,8 @@ Mixer::command_load ( const char *path, const char *display_name )
|
|||
|
||||
load_project_settings();
|
||||
|
||||
Project::close();
|
||||
|
||||
if ( Project::open( path ) )
|
||||
{
|
||||
// fl_alert( "Error opening project specified on commandline: %s", Project::errstr( err ) );
|
||||
|
|
|
@ -34,6 +34,7 @@ class Fl_Menu_Bar;
|
|||
class Spatialization_Console;
|
||||
namespace OSC { class Endpoint; }
|
||||
#include <lo/lo.h>
|
||||
class Group;
|
||||
|
||||
class Mixer : public Fl_Group
|
||||
{
|
||||
|
@ -88,8 +89,17 @@ private:
|
|||
static void update_cb ( void * );
|
||||
void update_cb ( void );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Group * group_by_name ( const char * name );
|
||||
char *get_unique_group_name ( const char *name );
|
||||
|
||||
std::list <Group*> groups;
|
||||
Group *group ( int n );
|
||||
void add_group ( Group *g );
|
||||
void remove_group ( Group *g );
|
||||
|
||||
void update_menu ( void );
|
||||
|
||||
static Spatialization_Console *spatialization_console;
|
||||
|
@ -114,7 +124,6 @@ public:
|
|||
virtual void resize ( int X, int Y, int W, int H );
|
||||
|
||||
void new_strip ( void );
|
||||
void process ( unsigned int nframes );
|
||||
void add ( Mixer_Strip *ms );
|
||||
void remove ( Mixer_Strip *ms );
|
||||
void move_left ( Mixer_Strip *ms );
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include "Project.H"
|
||||
#include "Mixer_Strip.H"
|
||||
#include "Engine/Engine.H"
|
||||
#include <dsp.h>
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
@ -58,6 +57,8 @@
|
|||
#include "FL/test_press.H"
|
||||
#include "FL/menu_popup.H"
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
#include <FL/Fl_Choice.H>
|
||||
#include "Group.H"
|
||||
|
||||
extern Mixer *mixer;
|
||||
|
||||
|
@ -71,6 +72,8 @@ Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
|
|||
|
||||
init();
|
||||
|
||||
_group = new Group(strip_name, true);
|
||||
|
||||
chain( new Chain() );
|
||||
|
||||
_chain->initialize_with_default();
|
||||
|
@ -96,17 +99,17 @@ Mixer_Strip::~Mixer_Strip ( )
|
|||
{
|
||||
DMESSAGE( "Destroying mixer strip" );
|
||||
|
||||
_chain->engine()->lock();
|
||||
// _chain->engine()->lock();
|
||||
|
||||
log_destroy();
|
||||
|
||||
mixer->remove( this );
|
||||
|
||||
/* make sure this gets destroyed before the chain */
|
||||
fader_tab->clear();
|
||||
|
||||
delete _chain;
|
||||
_chain = NULL;
|
||||
|
||||
log_destroy();
|
||||
|
||||
mixer->remove( this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,6 +124,11 @@ Mixer_Strip::get ( Log_Entry &e ) const
|
|||
/* since the default controllers aren't logged, we have to store
|
||||
* this setting as part of the mixer strip */
|
||||
e.add( ":gain_mode", gain_controller->mode() );
|
||||
if ( ! _group->single() )
|
||||
e.add( ":group", _group );
|
||||
else
|
||||
e.add( ":group", (Loggable*)0 );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -154,7 +162,26 @@ Mixer_Strip::set ( Log_Entry &e )
|
|||
{
|
||||
_gain_controller_mode = atoi( v );
|
||||
}
|
||||
else if ( ! strcmp( s, ":group" ) )
|
||||
{
|
||||
int i;
|
||||
sscanf( v, "%X", &i );
|
||||
|
||||
if ( i )
|
||||
{
|
||||
Group *t = (Group*)Loggable::find( i );
|
||||
|
||||
assert( t );
|
||||
|
||||
group( t );
|
||||
}
|
||||
else
|
||||
group( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! _group )
|
||||
group(0);
|
||||
|
||||
if ( ! mixer->contains( this ) )
|
||||
mixer->add( this );
|
||||
|
@ -204,6 +231,8 @@ Mixer_Strip::chain ( Chain *c )
|
|||
c->configure_outputs_callback( configure_outputs, this );
|
||||
c->name( name() );
|
||||
|
||||
/* FIXME: don't hardcode this list of modules */
|
||||
spatialization_controller->chain( c );
|
||||
gain_controller->chain( c );
|
||||
jack_input_controller->chain( c );
|
||||
meter_indicator->chain( c );
|
||||
|
@ -253,12 +282,76 @@ void Mixer_Strip::cb_handle(Fl_Widget* o) {
|
|||
if ( parent() )
|
||||
parent()->parent()->redraw();
|
||||
}
|
||||
else if ( o == group_choice )
|
||||
{
|
||||
// group(group_choice->value());
|
||||
Group *g = NULL;
|
||||
|
||||
if ( group_choice->value() == group_choice->size() - 2 )
|
||||
{
|
||||
/* create a new group */
|
||||
const char *s = fl_input( "Name for Group:" );
|
||||
if ( !s )
|
||||
return;
|
||||
|
||||
char *n = mixer->get_unique_group_name( s );
|
||||
|
||||
g = new Group( n, false );
|
||||
|
||||
free( n );
|
||||
|
||||
mixer->add_group( g );
|
||||
}
|
||||
else
|
||||
{
|
||||
g = (Group*)group_choice->mvalue()->user_data();
|
||||
}
|
||||
|
||||
group(g);
|
||||
}
|
||||
}
|
||||
|
||||
void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
|
||||
((Mixer_Strip*)(v))->cb_handle(o);
|
||||
}
|
||||
|
||||
void
|
||||
Mixer_Strip::group ( Group *g )
|
||||
{
|
||||
if ( !g && _group && _group->single() )
|
||||
return;
|
||||
|
||||
if ( _group )
|
||||
{
|
||||
_group->remove(this);
|
||||
if ( ! _group->nstrips() )
|
||||
{
|
||||
if ( ! _group->single() )
|
||||
mixer->remove_group( _group );
|
||||
|
||||
delete _group;
|
||||
|
||||
_group = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! g )
|
||||
g = new Group(name(), true);
|
||||
|
||||
const Fl_Menu_Item *menu = group_choice->menu();
|
||||
|
||||
for ( unsigned int i = 0; menu[i].text; i++ )
|
||||
if ( menu[i].user_data() == g )
|
||||
group_choice->value( i );
|
||||
|
||||
// group_choice->color( (Fl_Color)n );
|
||||
// group_choice->value( n );
|
||||
|
||||
_group = g;
|
||||
|
||||
g->add(this);
|
||||
}
|
||||
|
||||
void
|
||||
Mixer_Strip::name ( const char *name )
|
||||
{
|
||||
|
@ -375,6 +468,7 @@ Mixer_Strip::init ( )
|
|||
|
||||
_gain_controller_mode = 0;
|
||||
_chain = 0;
|
||||
_group = 0;
|
||||
|
||||
box( FL_FLAT_BOX );
|
||||
labeltype( FL_NO_LABEL );
|
||||
|
@ -433,6 +527,14 @@ Mixer_Strip::init ( )
|
|||
|
||||
o->end();
|
||||
} // Fl_Group* o
|
||||
{ Fl_Choice* o = group_choice = new Fl_Choice(61, 183, 45, 22);
|
||||
o->labeltype(FL_NO_LABEL);
|
||||
o->labelsize(10);
|
||||
o->textsize(10);
|
||||
o->add("---");
|
||||
o->value(0);
|
||||
o->callback( ((Fl_Callback*)cb_handle), this );
|
||||
}
|
||||
{ Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "fader/signal");
|
||||
o->type(1);
|
||||
o->labelsize( 14 );
|
||||
|
@ -519,11 +621,49 @@ Mixer_Strip::init ( )
|
|||
|
||||
size( 96, h() );
|
||||
|
||||
update_group_choice();
|
||||
// redraw();
|
||||
|
||||
// _chain->configure_ports();
|
||||
}
|
||||
|
||||
void
|
||||
Mixer_Strip::update_group_choice ( void )
|
||||
{
|
||||
Fl_Choice *o = group_choice;
|
||||
|
||||
o->clear();
|
||||
o->add( "---" );
|
||||
|
||||
for ( std::list<Group*>::iterator i = mixer->groups.begin(); i != mixer->groups.end(); )
|
||||
{
|
||||
Group *g = *i;
|
||||
|
||||
i++;
|
||||
|
||||
if ( i == mixer->groups.end() )
|
||||
{
|
||||
o->add( g->name(), 0, 0, (void*)g, FL_MENU_DIVIDER );
|
||||
break;
|
||||
}
|
||||
else
|
||||
o->add( g->name(), 0, 0, (void*)g );
|
||||
}
|
||||
|
||||
o->add( "New Group" );
|
||||
|
||||
const Fl_Menu_Item *menu = o->menu();
|
||||
|
||||
if ( ! group() || ( group() && group()->single() ) )
|
||||
o->value(0);
|
||||
else
|
||||
{
|
||||
for ( unsigned int i = 0; menu[i].text; i++ )
|
||||
if ( menu[i].user_data() == group() )
|
||||
o->value( i );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Mixer_Strip::draw ( void )
|
||||
{
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <FL/Fl_Value_Slider.H>
|
||||
#include <FL/Fl_Counter.H>
|
||||
#include <FL/Fl_Progress.H>
|
||||
//#include "Fader.H"
|
||||
#include <JACK/Port.H>
|
||||
|
||||
|
||||
|
@ -48,6 +47,8 @@ class Fl_Flip_Button;
|
|||
class Fl_Input;
|
||||
class Fl_Menu_;
|
||||
class Fl_Menu_Button;
|
||||
class Fl_Choice;
|
||||
class Group;
|
||||
|
||||
class Mixer_Strip : public Fl_Group, public Loggable {
|
||||
|
||||
|
@ -60,6 +61,7 @@ public:
|
|||
virtual ~Mixer_Strip();
|
||||
|
||||
void chain ( Chain *c );
|
||||
Chain *chain ( void ) { return _chain; }
|
||||
|
||||
virtual void log_children ( void ) const;
|
||||
|
||||
|
@ -92,6 +94,7 @@ private:
|
|||
Fl_Flip_Button *tab_button;
|
||||
Fl_Button *close_button;
|
||||
Fl_Input *name_field;
|
||||
Fl_Choice *group_choice;
|
||||
|
||||
Fl_Flowpack *controls_pack;
|
||||
Fl_Group *tab_group;
|
||||
|
@ -100,6 +103,7 @@ private:
|
|||
Fl_Pack *panner_pack;
|
||||
|
||||
Chain *_chain;
|
||||
Group *_group;
|
||||
|
||||
Fl_Box *spatialization_label;
|
||||
Controller_Module *gain_controller;
|
||||
|
@ -141,8 +145,14 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
void update_group_choice ( void );
|
||||
|
||||
Controller_Module *spatializer ( void );
|
||||
|
||||
Group *group ( void ) { return _group;}
|
||||
|
||||
// int group ( void ) const;
|
||||
void group ( Group * );
|
||||
void send_feedback ( void );
|
||||
int number ( void ) const;
|
||||
static bool import_strip ( const char *filename );
|
||||
|
|
|
@ -73,7 +73,7 @@ Module::Module ( ) : Fl_Group( 0, 0, 50, 50, "Unnamed" )
|
|||
|
||||
Module::~Module ( )
|
||||
{
|
||||
/* we assume that the engine for this chain is already locked */
|
||||
/* we assume that the client for this chain is already locked */
|
||||
|
||||
if ( _editor )
|
||||
{
|
||||
|
@ -880,6 +880,21 @@ Module::handle_chain_name_changed ( )
|
|||
|
||||
control_input[i].update_osc_port();
|
||||
}
|
||||
|
||||
if ( ! chain()->strip()->group()->single() )
|
||||
{
|
||||
/* we have to rename our JACK ports... */
|
||||
for ( unsigned int i = 0; i < aux_audio_input.size(); i++ )
|
||||
{
|
||||
aux_audio_input[i].jack_port()->trackname( chain()->name() );
|
||||
aux_audio_input[i].jack_port()->rename();
|
||||
}
|
||||
for ( unsigned int i = 0; i < aux_audio_output.size(); i++ )
|
||||
{
|
||||
aux_audio_output[i].jack_port()->trackname( chain()->name() );
|
||||
aux_audio_output[i].jack_port()->rename();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -964,6 +979,148 @@ Module::handle ( int m )
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*************/
|
||||
/* AUX Ports */
|
||||
/*************/
|
||||
|
||||
|
||||
static char *
|
||||
generate_port_name ( const char *aux, int direction, int n )
|
||||
{
|
||||
char *s;
|
||||
asprintf( &s, "%s%s%s-%i",
|
||||
aux ? aux : "",
|
||||
aux ? "/" : "",
|
||||
direction == JACK::Port::Input ? "in" : "out",
|
||||
n + 1 );
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
jack_port_activation_error ( JACK::Port *p )
|
||||
{
|
||||
fl_alert( "Could not activate JACK port \"%s\"", p->name() );
|
||||
}
|
||||
|
||||
/* freeze/disconnect all jack ports--used when changing groups */
|
||||
void
|
||||
Module::freeze_ports ( void )
|
||||
{
|
||||
// pass it along to our connected Controller_Modules, if any.
|
||||
for ( int i = 0; i < ncontrol_inputs(); ++i )
|
||||
{
|
||||
if ( control_input[i].connected() )
|
||||
control_input[i].connected_port()->module()->freeze_ports();
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < aux_audio_input.size(); ++i )
|
||||
{
|
||||
aux_audio_input[i].jack_port()->freeze();
|
||||
aux_audio_input[i].jack_port()->shutdown();
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < aux_audio_output.size(); ++i )
|
||||
{
|
||||
aux_audio_output[i].jack_port()->freeze();
|
||||
aux_audio_output[i].jack_port()->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/* rename and thaw all jack ports--used when changing groups */
|
||||
void
|
||||
Module::thaw_ports ( void )
|
||||
{
|
||||
// pass it along to our connected Controller_Modules, if any.
|
||||
for ( int i = 0; i < ncontrol_inputs(); ++i )
|
||||
{
|
||||
if ( control_input[i].connected() )
|
||||
control_input[i].connected_port()->module()->thaw_ports();
|
||||
}
|
||||
|
||||
const char *trackname = chain()->strip()->group()->single() ? NULL : chain()->name();
|
||||
|
||||
for ( unsigned int i = 0; i < aux_audio_input.size(); ++i )
|
||||
{
|
||||
/* if we're entering a group we need to add the chain name
|
||||
* prefix and if we're leaving one, we need to remove it */
|
||||
|
||||
aux_audio_input[i].jack_port()->client( chain()->client() );
|
||||
aux_audio_input[i].jack_port()->trackname( trackname );
|
||||
aux_audio_input[i].jack_port()->thaw();
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < aux_audio_output.size(); ++i )
|
||||
{
|
||||
/* if we're entering a group we won't actually be using our
|
||||
* JACK output ports anymore, just mixing into the group outputs */
|
||||
aux_audio_output[i].jack_port()->client( chain()->client() );
|
||||
aux_audio_output[i].jack_port()->trackname( trackname );
|
||||
aux_audio_output[i].jack_port()->thaw();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Module::add_aux_port ( bool input, const char *prefix, int i )
|
||||
{
|
||||
const char *trackname = chain()->strip()->group()->single() ? NULL : chain()->name();
|
||||
|
||||
JACK::Port::direction_e direction = input ? JACK::Port::Input : JACK::Port::Output;
|
||||
|
||||
char *portname = generate_port_name( prefix, direction, i );
|
||||
|
||||
JACK::Port *po = new JACK::Port( chain()->client(), trackname, portname, direction, JACK::Port::Audio );
|
||||
|
||||
free(portname);
|
||||
|
||||
if ( ! po->activate() )
|
||||
{
|
||||
jack_port_activation_error( po );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( po->valid() )
|
||||
{
|
||||
if ( input )
|
||||
{
|
||||
Module::Port mp( (Module*)this, Module::Port::INPUT, Module::Port::AUX_AUDIO );
|
||||
|
||||
mp.jack_port( po );
|
||||
|
||||
aux_audio_input.push_back( mp );
|
||||
}
|
||||
else
|
||||
{
|
||||
Module::Port mp( (Module*)this, Module::Port::OUTPUT, Module::Port::AUX_AUDIO );
|
||||
|
||||
mp.jack_port( po );
|
||||
|
||||
aux_audio_output.push_back( mp );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete po;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Module::add_aux_audio_output( const char *prefix, int i )
|
||||
{
|
||||
return add_aux_port ( false, prefix, i );
|
||||
}
|
||||
|
||||
bool
|
||||
Module::add_aux_audio_input( const char *prefix, int i )
|
||||
{
|
||||
return add_aux_port ( true, prefix, i );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/************/
|
||||
/* Commands */
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
public:
|
||||
|
||||
enum Direction { INPUT, OUTPUT };
|
||||
enum Type { AUDIO, CONTROL };
|
||||
enum Type { AUDIO, CONTROL, AUX_AUDIO };
|
||||
|
||||
/* hints for control ports (specifically control inputs) */
|
||||
struct Hints
|
||||
|
@ -138,6 +138,7 @@ public:
|
|||
_unscaled_signal = 0;
|
||||
_by_number_path = 0;
|
||||
_by_number_number = -1;
|
||||
_jack_port = 0;
|
||||
}
|
||||
|
||||
Port ( const Port& p )
|
||||
|
@ -154,6 +155,7 @@ public:
|
|||
_unscaled_signal = p._unscaled_signal;
|
||||
_by_number_path = 0;
|
||||
_by_number_number = -1;
|
||||
_jack_port = p._jack_port;
|
||||
}
|
||||
|
||||
virtual ~Port ( )
|
||||
|
@ -273,6 +275,9 @@ public:
|
|||
/* FIXME: do something! */
|
||||
}
|
||||
|
||||
void jack_port ( JACK::Port *v ) { _jack_port = v; }
|
||||
JACK::Port *jack_port ( void ) { return _jack_port; }
|
||||
|
||||
private:
|
||||
|
||||
char *generate_osc_path ( void );
|
||||
|
@ -285,7 +290,8 @@ public:
|
|||
void *_buf;
|
||||
nframes_t _nframes;
|
||||
Module *_module;
|
||||
|
||||
/* used for auxilliary I/Os */
|
||||
JACK::Port *_jack_port;
|
||||
|
||||
OSC::Signal *_scaled_signal;
|
||||
OSC::Signal *_unscaled_signal;
|
||||
|
@ -348,6 +354,8 @@ public:
|
|||
std::vector<Port> audio_output;
|
||||
std::vector<Port> control_input;
|
||||
std::vector<Port> control_output;
|
||||
std::vector<Port> aux_audio_input;
|
||||
std::vector<Port> aux_audio_output;
|
||||
|
||||
void add_port ( const Port &p )
|
||||
{
|
||||
|
@ -477,8 +485,16 @@ protected:
|
|||
virtual void get ( Log_Entry &e ) const;
|
||||
virtual void set ( Log_Entry &e );
|
||||
|
||||
bool add_aux_port ( bool input, const char *prefix, int n );
|
||||
|
||||
public:
|
||||
|
||||
void freeze_ports ( void );
|
||||
void thaw_ports ( void );
|
||||
|
||||
bool add_aux_audio_output ( const char *prefix, int n );
|
||||
bool add_aux_audio_input ( const char *prefix, int n );
|
||||
|
||||
static void set_sample_rate ( nframes_t srate ) { _sample_rate = srate; }
|
||||
|
||||
void command_open_parameter_editor();
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#include "LADSPAInfo.h"
|
||||
|
||||
#include "Chain.H"
|
||||
#include "Engine/Engine.H"
|
||||
//#include "Client/Client.H"
|
||||
|
||||
#include <dsp.h>
|
||||
|
||||
|
@ -684,7 +684,7 @@ Plugin_Module::activate ( void )
|
|||
FATAL( "Attempt to activate already active plugin" );
|
||||
|
||||
if ( chain() )
|
||||
chain()->engine()->lock();
|
||||
chain()->client()->lock();
|
||||
|
||||
if ( _idata->descriptor->activate )
|
||||
for ( unsigned int i = 0; i < _idata->handle.size(); ++i )
|
||||
|
@ -693,7 +693,7 @@ Plugin_Module::activate ( void )
|
|||
_bypass = false;
|
||||
|
||||
if ( chain() )
|
||||
chain()->engine()->unlock();
|
||||
chain()->client()->unlock();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -705,7 +705,7 @@ Plugin_Module::deactivate( void )
|
|||
DMESSAGE( "Deactivating plugin \"%s\"", label() );
|
||||
|
||||
if ( chain() )
|
||||
chain()->engine()->lock();
|
||||
chain()->client()->lock();
|
||||
|
||||
_bypass = true;
|
||||
|
||||
|
@ -714,7 +714,7 @@ Plugin_Module::deactivate( void )
|
|||
_idata->descriptor->deactivate( _idata->handle[i] );
|
||||
|
||||
if ( chain() )
|
||||
chain()->engine()->unlock();
|
||||
chain()->client()->unlock();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -743,7 +743,7 @@ Plugin_Module::handle_port_connection_change ( void )
|
|||
|
||||
|
||||
/**********/
|
||||
/* Engine */
|
||||
/* Client */
|
||||
/**********/
|
||||
|
||||
void
|
||||
|
|
|
@ -512,7 +512,7 @@ Spatializer_Module::draw ( void )
|
|||
|
||||
int spacing, offset;
|
||||
|
||||
int ni = jack_output.size();
|
||||
int ni = aux_audio_output.size();
|
||||
|
||||
spacing = h() / ni;
|
||||
offset = spacing / 2;
|
||||
|
@ -566,9 +566,9 @@ Spatializer_Module::process ( nframes_t nframes )
|
|||
|
||||
/* send to late reverb */
|
||||
if ( i == 0 )
|
||||
buffer_copy( (sample_t*)jack_output[0].buffer(nframes), buf, nframes );
|
||||
buffer_copy( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), buf, nframes );
|
||||
else
|
||||
buffer_mix( (sample_t*)jack_output[0].buffer(nframes), buf, nframes );
|
||||
buffer_mix( (sample_t*)aux_audio_output[0].jack_port()->buffer(nframes), buf, nframes );
|
||||
|
||||
/* /\* FIXME: use smoothed value... *\/ */
|
||||
/* buffer_apply_gain( (sample_t*)jack_output[0].buffer(nframes), nframes, 1.0f / sqrt(D) ); */
|
||||
|
@ -606,7 +606,7 @@ Spatializer_Module::process ( nframes_t nframes )
|
|||
|
||||
/* send to early reverb */
|
||||
for ( int i = 4; i--; )
|
||||
buffer_copy( (sample_t*)jack_output[1 + i].buffer(nframes),
|
||||
buffer_copy( (sample_t*)aux_audio_output[1 + i].jack_port()->buffer(nframes),
|
||||
(sample_t*)audio_output[0 + i].buffer(),
|
||||
nframes );
|
||||
|
||||
|
@ -678,7 +678,7 @@ Spatializer_Module::configure_inputs ( int n )
|
|||
|
||||
if ( n == 0 )
|
||||
{
|
||||
remove_jack_outputs();
|
||||
remove_aux_audio_outputs();
|
||||
audio_output.clear();
|
||||
audio_input.clear();
|
||||
}
|
||||
|
@ -692,20 +692,20 @@ Spatializer_Module::configure_inputs ( int n )
|
|||
}
|
||||
}
|
||||
|
||||
if ( jack_output.size() != 5 )
|
||||
if ( aux_audio_output.size() != 5 )
|
||||
{
|
||||
add_jack_output( "late reverb", 0 );
|
||||
add_jack_output( "early reverb", 0 );
|
||||
add_jack_output( "early reverb", 1 );
|
||||
add_jack_output( "early reverb", 2 );
|
||||
add_jack_output( "early reverb", 3 );
|
||||
add_aux_audio_output( "late reverb", 0 );
|
||||
add_aux_audio_output( "early reverb", 0 );
|
||||
add_aux_audio_output( "early reverb", 1 );
|
||||
add_aux_audio_output( "early reverb", 2 );
|
||||
add_aux_audio_output( "early reverb", 3 );
|
||||
}
|
||||
}
|
||||
|
||||
_connection_handle_outputs[0][0] = 0;
|
||||
_connection_handle_outputs[0][1] = 1;
|
||||
_connection_handle_outputs[1][0] = 1;
|
||||
_connection_handle_outputs[1][1] = jack_output.size();
|
||||
_connection_handle_outputs[1][1] = aux_audio_output.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "AUX_Module.H"
|
||||
#include "NSM.H"
|
||||
#include "Spatialization_Console.H"
|
||||
#include "Group.H"
|
||||
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
@ -161,6 +162,7 @@ main ( int argc, char **argv )
|
|||
LOG_REGISTER_CREATE( Controller_Module );
|
||||
LOG_REGISTER_CREATE( AUX_Module );
|
||||
LOG_REGISTER_CREATE( Spatialization_Console );
|
||||
LOG_REGISTER_CREATE( Group );
|
||||
|
||||
signal( SIGPIPE, SIG_IGN );
|
||||
|
||||
|
|
|
@ -529,8 +529,8 @@ create_engine ( void )
|
|||
return false;
|
||||
}
|
||||
|
||||
engine->midi_input_port = new JACK::Port( engine, "midi-in", JACK::Port::Input, JACK::Port::MIDI );
|
||||
engine->midi_output_port = new JACK::Port( engine, "midi-out", JACK::Port::Output, JACK::Port::MIDI );
|
||||
engine->midi_input_port = new JACK::Port( engine, NULL, "midi-in", JACK::Port::Input, JACK::Port::MIDI );
|
||||
engine->midi_output_port = new JACK::Port( engine, NULL, "midi-out", JACK::Port::Output, JACK::Port::MIDI );
|
||||
|
||||
if ( !engine->midi_input_port->activate() )
|
||||
{
|
||||
|
|
|
@ -46,7 +46,6 @@ def build(bld):
|
|||
src/Chain.C
|
||||
src/Controller_Module.C
|
||||
src/DPM.C
|
||||
src/Engine/Engine.C
|
||||
src/Gain_Module.C
|
||||
src/Spatializer_Module.C
|
||||
src/JACK_Module.C
|
||||
|
@ -65,6 +64,7 @@ src/NSM.C
|
|||
src/Panner.C
|
||||
src/Plugin_Module.C
|
||||
src/Project.C
|
||||
src/Group.C
|
||||
src/main.C
|
||||
src/Spatialization_Console.C
|
||||
''',
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace JACK
|
|||
|
||||
Client::Client ( )
|
||||
{
|
||||
_active = false;
|
||||
_freewheeling = false;
|
||||
_zombified = false;
|
||||
_client = NULL;
|
||||
|
@ -43,7 +44,7 @@ namespace JACK
|
|||
|
||||
Client::~Client ( )
|
||||
{
|
||||
jack_client_close( _client );
|
||||
close();
|
||||
}
|
||||
|
||||
/** Tell JACK to stop calling process callback. This MUST be called in
|
||||
|
@ -51,7 +52,10 @@ namespace JACK
|
|||
void
|
||||
Client::deactivate ( )
|
||||
{
|
||||
if ( _active )
|
||||
jack_deactivate( _client );
|
||||
|
||||
_active = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,6 +142,14 @@ namespace JACK
|
|||
return ((Client*)arg)->sample_rate_changed( srate );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Client::activate ( void )
|
||||
{
|
||||
jack_activate( _client );
|
||||
_active = true;
|
||||
}
|
||||
|
||||
/** Connect to JACK using client name /client_name/. Return a static
|
||||
* pointer to actual name as reported by JACK */
|
||||
const char *
|
||||
|
@ -167,15 +179,13 @@ namespace JACK
|
|||
|
||||
jack_on_shutdown( _client, &Client::shutdown, this );
|
||||
|
||||
jack_activate( _client );
|
||||
activate();
|
||||
|
||||
// _sample_rate = frame_rate();
|
||||
|
||||
return jack_get_client_name( _client );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* THREAD: RT */
|
||||
/** enter or leave freehweeling mode */
|
||||
void
|
||||
|
@ -186,6 +196,11 @@ namespace JACK
|
|||
// WARNING( "Unkown error while setting freewheeling mode" );
|
||||
}
|
||||
|
||||
const char *
|
||||
Client::jack_name ( void ) const
|
||||
{
|
||||
return jack_get_client_name( _client );
|
||||
}
|
||||
|
||||
void
|
||||
Client::port_added ( Port *p )
|
||||
|
@ -235,8 +250,13 @@ namespace JACK
|
|||
void
|
||||
Client::close ( void )
|
||||
{
|
||||
jack_deactivate( _client );
|
||||
deactivate();
|
||||
|
||||
if ( _client )
|
||||
{
|
||||
DMESSAGE( "Closing JACK client" );
|
||||
jack_client_close( _client );
|
||||
}
|
||||
|
||||
_client = NULL;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace JACK
|
|||
volatile int _xruns;
|
||||
volatile bool _freewheeling;
|
||||
volatile bool _zombified;
|
||||
volatile bool _active;
|
||||
|
||||
static int sample_rate_changed ( nframes_t srate, void *arg );
|
||||
virtual int sample_rate_changed ( nframes_t srate ) { return 0; }
|
||||
|
@ -73,7 +74,9 @@ namespace JACK
|
|||
|
||||
protected:
|
||||
|
||||
bool active ( void ) const { return _active; }
|
||||
void deactivate ( void );
|
||||
void activate ( void );
|
||||
|
||||
private:
|
||||
|
||||
|
@ -97,6 +100,8 @@ namespace JACK
|
|||
const char * init ( const char *client_name, unsigned int opts = 0 );
|
||||
const char * name ( const char * );
|
||||
|
||||
const char *jack_name ( void ) const;
|
||||
|
||||
void close ( void );
|
||||
nframes_t nframes ( void ) const { return jack_get_buffer_size( _client ); }
|
||||
// float frame_rate ( void ) const { return jack_get_sample_rate( _client ); }
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
namespace JACK
|
||||
{
|
||||
|
||||
static char *name_for_port ( Port::direction_e dir, const char *base, int n, const char *type );
|
||||
/* static char *name_for_port ( Port::direction_e dir, const char *base, int n, const char *type ); */
|
||||
|
||||
int
|
||||
Port::max_name ( void )
|
||||
|
@ -49,8 +49,11 @@ namespace JACK
|
|||
_port = rhs._port;
|
||||
_direction = rhs._direction;
|
||||
_type = rhs._type;
|
||||
_name = NULL;
|
||||
_name = strdup( rhs._name );
|
||||
|
||||
_trackname = NULL;
|
||||
if ( rhs._trackname )
|
||||
_trackname = strdup( rhs._trackname );
|
||||
_client->port_added( this );
|
||||
}
|
||||
|
||||
|
@ -62,6 +65,7 @@ namespace JACK
|
|||
_client = client;
|
||||
_port = port;
|
||||
_name = strdup( jack_port_name( port ) );
|
||||
_trackname = NULL;
|
||||
_direction = ( jack_port_flags( _port ) & JackPortIsOutput ) ? Output : Input;
|
||||
const char *type = jack_port_type( _port );
|
||||
|
||||
|
@ -73,51 +77,55 @@ namespace JACK
|
|||
|
||||
}
|
||||
|
||||
Port::Port ( JACK::Client *client, const char *name, direction_e dir, type_e type )
|
||||
Port::Port ( JACK::Client *client, const char *trackname, const char *name, direction_e dir, type_e type )
|
||||
{
|
||||
_port = 0;
|
||||
_terminal = 0;
|
||||
_name = NULL;
|
||||
_trackname = NULL;
|
||||
_connections = NULL;
|
||||
_client = client;
|
||||
_direction = dir;
|
||||
_type = type;
|
||||
_trackname = NULL;
|
||||
|
||||
if ( trackname )
|
||||
_trackname = strdup( trackname );
|
||||
|
||||
_name = strdup( name );
|
||||
|
||||
_client->port_added( this );
|
||||
|
||||
}
|
||||
|
||||
Port::Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype )
|
||||
{
|
||||
_port = 0;
|
||||
_terminal = 0;
|
||||
_name = NULL;
|
||||
_connections = NULL;
|
||||
_client = client;
|
||||
/* Port::Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype ) */
|
||||
/* { */
|
||||
/* _port = 0; */
|
||||
/* _terminal = 0; */
|
||||
/* _name = NULL; */
|
||||
/* _connections = NULL; */
|
||||
/* _client = client; */
|
||||
|
||||
_name = name_for_port( dir, base, n, subtype );
|
||||
_direction = dir;
|
||||
_type = type;
|
||||
/* _name = name_for_port( dir, base, n, subtype ); */
|
||||
/* _direction = dir; */
|
||||
/* _type = type; */
|
||||
|
||||
_client->port_added( this );
|
||||
}
|
||||
/* _client->port_added( this ); */
|
||||
/* } */
|
||||
|
||||
Port::Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype )
|
||||
{
|
||||
_port = 0;
|
||||
_terminal = 0;
|
||||
_name = NULL;
|
||||
_connections = NULL;
|
||||
_client = client;
|
||||
/* Port::Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype ) */
|
||||
/* { */
|
||||
/* _port = 0; */
|
||||
/* _terminal = 0; */
|
||||
/* _name = NULL; */
|
||||
/* _connections = NULL; */
|
||||
/* _client = client; */
|
||||
|
||||
_name = name_for_port( dir, NULL, n, subtype );
|
||||
_direction = dir;
|
||||
_type = type;
|
||||
/* _name = name_for_port( dir, NULL, n, subtype ); */
|
||||
/* _direction = dir; */
|
||||
/* _type = type; */
|
||||
|
||||
_client->port_added( this );
|
||||
}
|
||||
/* _client->port_added( this ); */
|
||||
/* } */
|
||||
|
||||
Port::~Port ( )
|
||||
{
|
||||
|
@ -128,6 +136,12 @@ namespace JACK
|
|||
free( _name );
|
||||
_name = NULL;
|
||||
}
|
||||
if ( _trackname )
|
||||
{
|
||||
free( _trackname );
|
||||
_trackname = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* sort input before output and then by alpha */
|
||||
|
@ -141,20 +155,20 @@ namespace JACK
|
|||
}
|
||||
|
||||
|
||||
static char *
|
||||
name_for_port ( Port::direction_e dir, const char *base, int n, const char *type )
|
||||
{
|
||||
char *pname;
|
||||
/* static char * */
|
||||
/* name_for_port ( Port::direction_e dir, const char *base, int n, const char *type ) */
|
||||
/* { */
|
||||
/* char *pname; */
|
||||
|
||||
const char *dir_s = dir == Port::Output ? "out" : "in";
|
||||
/* const char *dir_s = dir == Port::Output ? "out" : "in"; */
|
||||
|
||||
if ( type )
|
||||
asprintf( &pname, "%s-%s%s%s-%d", type, base ? base : "", base ? "/" : "", dir_s, n + 1 );
|
||||
else
|
||||
asprintf( &pname, "%s%s%s-%d", base ? base : "", base ? "/" : "", dir_s, n + 1 );
|
||||
/* if ( type ) */
|
||||
/* asprintf( &pname, "%s-%s%s%s-%d", type, base ? base : "", base ? "/" : "", dir_s, n + 1 ); */
|
||||
/* else */
|
||||
/* asprintf( &pname, "%s%s%s-%d", base ? base : "", base ? "/" : "", dir_s, n + 1 ); */
|
||||
|
||||
return pname;
|
||||
}
|
||||
/* return pname; */
|
||||
/* } */
|
||||
|
||||
bool
|
||||
Port::activate ( void )
|
||||
|
@ -171,8 +185,12 @@ namespace JACK
|
|||
if ( _terminal )
|
||||
flags |= JackPortIsTerminal;
|
||||
|
||||
DMESSAGE( "Activating port name %s", _name );
|
||||
_port = jack_port_register( _client->jack_client(), _name,
|
||||
char jackname[max_name()];
|
||||
|
||||
snprintf( jackname, sizeof(jackname), "%s%s%s", _trackname ? _trackname : "", _trackname ? "/" : "", _name );
|
||||
|
||||
DMESSAGE( "Activating port name %s", jackname );
|
||||
_port = jack_port_register( _client->jack_client(), jackname,
|
||||
_type == Audio ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE,
|
||||
flags,
|
||||
0 );
|
||||
|
@ -231,25 +249,39 @@ namespace JACK
|
|||
_port = 0;
|
||||
}
|
||||
|
||||
/** rename port */
|
||||
bool
|
||||
|
||||
void
|
||||
Port::name ( const char *name )
|
||||
{
|
||||
if ( _name )
|
||||
free( _name );
|
||||
|
||||
_name = strdup( name );
|
||||
}
|
||||
|
||||
return 0 == jack_port_set_name( _port, name );
|
||||
void
|
||||
Port::trackname ( const char *trackname )
|
||||
{
|
||||
if ( _trackname )
|
||||
free( _trackname );
|
||||
|
||||
_trackname = NULL;
|
||||
|
||||
if ( trackname )
|
||||
_trackname = strdup( trackname );
|
||||
}
|
||||
|
||||
bool
|
||||
Port::name ( const char *base, int n, const char *type )
|
||||
Port::rename ( void )
|
||||
{
|
||||
char *s = name_for_port( this->direction(), base, n, type );
|
||||
bool b = name( s );
|
||||
free(s);
|
||||
return b;
|
||||
char jackname[max_name()];
|
||||
|
||||
snprintf( jackname, sizeof(jackname), "%s%s%s", _trackname ? _trackname : "", _trackname ? "/" : "", _name );
|
||||
|
||||
if ( _port )
|
||||
return 0 == jack_port_set_name( _port, jackname );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -28,7 +28,9 @@ namespace JACK
|
|||
class Port
|
||||
{
|
||||
jack_port_t *_port;
|
||||
char *_trackname;
|
||||
char *_name;
|
||||
|
||||
JACK::Client *_client;
|
||||
|
||||
/* FIXME: reference count? */
|
||||
|
@ -47,23 +49,27 @@ namespace JACK
|
|||
static int max_name ( void );
|
||||
|
||||
Port ( JACK::Client *client, jack_port_t *port );
|
||||
Port ( JACK::Client *client, const char *name, direction_e dir, type_e type );
|
||||
Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype=0 );
|
||||
Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype=0 );
|
||||
/* Port ( JACK::Client *client, const char *name, direction_e dir, type_e type ); */
|
||||
Port ( JACK::Client *client, const char *trackname, const char *name, direction_e dir, type_e type );
|
||||
/* Port ( JACK::Client *client, direction_e dir, type_e type, const char *base, int n, const char *subtype=0 ); */
|
||||
/* Port ( JACK::Client *client, direction_e dir, type_e type, int n, const char *subtype=0 ); */
|
||||
|
||||
// Port ( );
|
||||
~Port ( );
|
||||
|
||||
Port ( const Port & rhs );
|
||||
|
||||
|
||||
bool valid ( void ) const { return _port; }
|
||||
bool connected ( void ) const { return jack_port_connected( _port ); }
|
||||
direction_e direction ( void ) const { return _direction; }
|
||||
type_e type ( void ) const { return _type; }
|
||||
const char * name ( void ) const { return _name; }
|
||||
bool name ( const char *name );
|
||||
bool name ( const char *base, int n, const char *type=0 );
|
||||
const char * trackname ( void ) const { return _trackname; }
|
||||
void name ( const char *name );
|
||||
void trackname ( const char *trackname );
|
||||
bool rename ( void );
|
||||
const char * jack_name ( void ) const { return jack_port_name( _port ); }
|
||||
// bool name ( const char *base, int n, const char *type=0 );
|
||||
|
||||
nframes_t total_latency ( void ) const;
|
||||
nframes_t latency ( void ) const;
|
||||
|
@ -85,6 +91,8 @@ namespace JACK
|
|||
bool connections ( const char **port_names );
|
||||
void freeze ( void );
|
||||
void thaw ( void );
|
||||
JACK::Client * client ( void ) const { return _client; }
|
||||
void client ( JACK::Client *c ) { _client = c; }
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -169,19 +169,22 @@ void
|
|||
Control_Sequence::update_port_name ( void )
|
||||
{
|
||||
bool needs_activation = false;
|
||||
|
||||
char s[512];
|
||||
snprintf( s, sizeof(s), "%s-cv", name() );
|
||||
|
||||
if ( ! _output )
|
||||
{
|
||||
_output = new JACK::Port( engine, JACK::Port::Output, JACK::Port::Audio, track()->name(), track()->ncontrols(), "cv" );
|
||||
_output = new JACK::Port( engine, track()->name(), s, JACK::Port::Output, JACK::Port::Audio );
|
||||
_output->terminal( true );
|
||||
needs_activation = true;
|
||||
}
|
||||
|
||||
if ( name() )
|
||||
{
|
||||
char n[1024];
|
||||
snprintf( n, sizeof(n), "%s/%s-cv", track()->name(), name() );
|
||||
|
||||
_output->name( n );
|
||||
_output->trackname( track()->name() );
|
||||
_output->name( s );
|
||||
_output->rename();
|
||||
}
|
||||
|
||||
if ( needs_activation )
|
||||
|
|
|
@ -40,6 +40,7 @@ Engine::Engine ( ) : _thread( "RT" )
|
|||
|
||||
Engine::~Engine ( )
|
||||
{
|
||||
DMESSAGE( "Deleting engine" );
|
||||
/* We have to deactivate here in order to avoid our process
|
||||
callback is being invoked after we're already destroyed, but
|
||||
before the base class is */
|
||||
|
|
|
@ -56,7 +56,7 @@ private:
|
|||
public:
|
||||
|
||||
Engine ( );
|
||||
~Engine ( );
|
||||
virtual ~Engine ( );
|
||||
|
||||
int dropped ( void ) const { return _buffers_dropped; }
|
||||
|
||||
|
|
|
@ -53,11 +53,16 @@ void
|
|||
Track::update_port_names ( void )
|
||||
{
|
||||
for ( unsigned int i = 0; i < output.size(); ++i )
|
||||
output[ i ].name( name(), i );
|
||||
{
|
||||
output[ i ].trackname( name() );
|
||||
output[ i ].rename();
|
||||
}
|
||||
|
||||
for ( unsigned int i = 0; i < input.size(); ++i )
|
||||
input[ i ].name( name(), i );
|
||||
|
||||
{
|
||||
input[ i ].trackname( name() );
|
||||
input[ i ].rename();
|
||||
}
|
||||
/* /\* tell any attached control sequences to do the same *\/ */
|
||||
/* for ( int i = control->children(); i-- ) */
|
||||
/* ((Control_Sequence*)control->child( i ))->update_port_names(); */
|
||||
|
@ -86,7 +91,10 @@ Track::configure_outputs ( int n )
|
|||
{
|
||||
for ( int i = on; i < n; ++i )
|
||||
{
|
||||
JACK::Port p( engine, JACK::Port::Output, JACK::Port::Audio, name(), i );
|
||||
char s[512];
|
||||
snprintf( s, sizeof(s), "out-%i", i + 1 );
|
||||
|
||||
JACK::Port p( engine, name(), s, JACK::Port::Output, JACK::Port::Audio );
|
||||
|
||||
p.terminal(true);
|
||||
|
||||
|
@ -141,7 +149,10 @@ Track::configure_inputs ( int n )
|
|||
{
|
||||
for ( int i = on; i < n; ++i )
|
||||
{
|
||||
JACK::Port p( engine, JACK::Port::Input, JACK::Port::Audio, name(), i );
|
||||
char s[512];
|
||||
snprintf( s, sizeof(s), "in-%i", i + 1 );
|
||||
|
||||
JACK::Port p( engine, name(), s, JACK::Port::Input, JACK::Port::Audio );
|
||||
|
||||
p.terminal( true );
|
||||
|
||||
|
|
|
@ -114,7 +114,6 @@ private:
|
|||
void command_configure_channels ( int n );
|
||||
|
||||
void update_port_names ( void );
|
||||
const char *name_for_port( JACK::Port::type_e type, int n );
|
||||
|
||||
Track ( );
|
||||
void init ( void );
|
||||
|
|
|
@ -273,18 +273,18 @@ main ( int argc, char **argv )
|
|||
|
||||
/* cleanup for valgrind's sake */
|
||||
|
||||
if ( engine )
|
||||
{
|
||||
delete engine;
|
||||
engine = NULL;
|
||||
}
|
||||
|
||||
delete timeline;
|
||||
timeline = NULL;
|
||||
|
||||
delete tle;
|
||||
tle = NULL;
|
||||
|
||||
if ( engine )
|
||||
{
|
||||
delete engine;
|
||||
engine = NULL;
|
||||
}
|
||||
|
||||
nsm_free( nsm );
|
||||
nsm = NULL;
|
||||
|
||||
|
|
Loading…
Reference in New Issue