View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001068 | ardour | features | public | 2005-09-07 21:37 | 2020-04-19 20:12 |
| Reporter | b0ef | Assigned To | paul | ||
| Priority | normal | Severity | feature | Reproducibility | N/A |
| Status | closed | Resolution | fixed | ||
| Summary | 0001068: [PATCH] Mono Switch | ||||
| Description | A nice way to implement the mono switch per track and on the master is to have a way to quickly click the pan into mono position.. .. and back again. | ||||
| Tags | No tags attached. | ||||
|
2007-03-06 16:29
|
mono-2 (15,334 bytes)
Index: gtk2_ardour/mixer_strip.cc
===================================================================
--- gtk2_ardour/mixer_strip.cc (revision 1560)
+++ gtk2_ardour/mixer_strip.cc (working copy)
@@ -89,6 +89,7 @@
post_redirect_box (PostFader, sess, rt, mx.plugin_selector(), mx.selection(), in_mixer),
gpm (_route, sess),
panners (_route, sess),
+ mono_button (_("Mono")),
button_table (3, 2),
middle_button_table (1, 2),
bottom_button_table (1, 2),
@@ -215,6 +216,9 @@
name_label.set_text (_route->name());
}
+ mono_button.set_name ("MixerMonoButton");
+ mono_button.signal_clicked().connect (mem_fun(*this, &MixerStrip::mono_button_clicked));
+
group_button.add (group_label);
group_button.set_name ("MixerGroupButton");
group_label.set_name ("MixerGroupButtonLabel");
@@ -256,6 +260,7 @@
global_vpacker.pack_start (bottom_button_table,Gtk::PACK_SHRINK);
global_vpacker.pack_start (post_redirect_box, true, true);
global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
+ global_vpacker.pack_start (mono_button, Gtk::PACK_SHRINK);
global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
global_vpacker.pack_start (comment_button, Gtk::PACK_SHRINK);
@@ -1219,3 +1224,8 @@
gpm.setup_meters ();
}
+void
+MixerStrip::mono_button_clicked ()
+{
+ panners.set_mono (mono_button.get_active ());
+}
Index: gtk2_ardour/panner_ui.h
===================================================================
--- gtk2_ardour/panner_ui.h (revision 1560)
+++ gtk2_ardour/panner_ui.h (working copy)
@@ -69,6 +69,8 @@
void set_meter_strip_name (string name);
+ void set_mono (bool yn);
+
private:
friend class MixerStrip;
boost::shared_ptr<ARDOUR::IO> _io;
Index: gtk2_ardour/panner_ui.cc
===================================================================
--- gtk2_ardour/panner_ui.cc (revision 1560)
+++ gtk2_ardour/panner_ui.cc (working copy)
@@ -604,7 +604,7 @@
void
PannerUI::update_pan_sensitive ()
{
- bool sensitive = !(_io->panner().automation_state() & Play);
+ const bool sensitive = !(_io->panner().mono()) && !(_io->panner().automation_state() & Play);
switch (_io->n_outputs()) {
case 0:
@@ -777,3 +777,10 @@
return (shrt ? _("Abs") : _("Abs"));
}
}
+
+void
+PannerUI::set_mono (bool yn)
+{
+ _io->panner().set_mono (yn);
+ update_pan_sensitive ();
+}
Index: gtk2_ardour/mixer_strip.h
===================================================================
--- gtk2_ardour/mixer_strip.h (revision 1560)
+++ gtk2_ardour/mixer_strip.h (working copy)
@@ -123,6 +123,7 @@
RedirectBox post_redirect_box;
GainMeter gpm;
PannerUI panners;
+ Gtk::ToggleButton mono_button;
Gtk::Table button_table;
Gtk::Table middle_button_table;
@@ -157,6 +158,7 @@
void comment_editor_done_editing();
void setup_comment_editor ();
void comment_button_clicked ();
+ void mono_button_clicked ();
Gtk::Button group_button;
Gtk::Label group_label;
Property changes on: libs/fst
___________________________________________________________________
Name: svn:ignore
+ *.zip
vstsdk2.3
Index: libs/ardour/ardour/panner.h
===================================================================
--- libs/ardour/ardour/panner.h (revision 1560)
+++ libs/ardour/ardour/panner.h (working copy)
@@ -48,6 +48,7 @@
void set_muted (bool yn);
bool muted() const { return _muted; }
+ void set_mono (bool yn);
void set_position (float x, bool link_call = false);
void set_position (float x, float y, bool link_call = false);
@@ -61,10 +62,22 @@
void get_effective_position (float& xpos, float& ypos) const { xpos = effective_x; ypos = effective_y; }
void get_effective_position (float& xpos, float& ypos, float& zpos) const { xpos = effective_x; ypos = effective_y; zpos = effective_z; }
+ void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes);
+ void distribute_automated (Sample* src, Sample** obufs,
+ nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
+
/* the basic panner API */
- virtual void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes) = 0;
- virtual void distribute_automated (Sample* src, Sample** obufs,
+ /**
+ * Pan some input samples to a number of output buffers.
+ *
+ * \param src Input samples
+ * \param obufs Output buffers (one per panner output)
+ * \param gain_coeff Gain coefficient to apply to output samples.
+ * \param nframes Number of frames in the input
+ */
+ virtual void do_distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes) = 0;
+ virtual void do_distribute_automated (Sample* src, Sample** obufs,
nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers) = 0;
/* automation */
@@ -111,6 +124,7 @@
float effective_z;
bool _muted;
+ bool _mono;
struct PanControllable : public PBD::Controllable {
PanControllable (std::string name, StreamPanner& p) : Controllable (name), panner (p) {}
@@ -135,12 +149,12 @@
~BaseStereoPanner ();
/* this class just leaves the pan law itself to be defined
- by the update(), distribute_automated()
+ by the update(), do_distribute_automated()
methods. derived classes also need a factory method
and a type name. See EqualPowerStereoPanner as an example.
*/
- void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes);
+ void do_distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes);
void snapshot (nframes_t now);
void transport_stopped (nframes_t frame);
@@ -170,7 +184,7 @@
EqualPowerStereoPanner (Panner&);
~EqualPowerStereoPanner ();
- void distribute_automated (Sample* src, Sample** obufs,
+ void do_distribute_automated (Sample* src, Sample** obufs,
nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
void get_current_coefficients (pan_t*) const;
@@ -204,8 +218,8 @@
Curve& automation() { return _automation; }
- void distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes);
- void distribute_automated (Sample* src, Sample** obufs,
+ void do_distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes);
+ void do_distribute_automated (Sample* src, Sample** obufs,
nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers);
static StreamPanner* factory (Panner&);
@@ -224,6 +238,14 @@
void update ();
};
+
+/// Class to pan from some number of inputs to some number of outputs
+
+/**
+ * Panner is derived from std::vector, and contains one StreamPanner* per input.
+ * It also has a number of outputs which are defined by Output structs.
+ */
+
class Panner : public std::vector<StreamPanner*>, public Stateful, public sigc::trackable
{
public:
@@ -243,6 +265,8 @@
bool bypassed() const { return _bypassed; }
void set_bypassed (bool yn);
+ bool mono() const { return _mono; }
+ void set_mono (bool yn);
StreamPanner* add ();
void remove (uint32_t which);
@@ -267,7 +291,7 @@
sigc::signal<void> Changed;
static bool equivalent (pan_t a, pan_t b) {
- return fabsf (a - b) < 0.002; // about 1 degree of arc for a stereo panner
+ return fabsf (a - b) < 0.002; // about 1 degree of arc for a stereo panner
}
void move_output (uint32_t, float x, float y);
@@ -307,6 +331,7 @@
uint32_t current_outs;
bool _linked;
bool _bypassed;
+ bool _mono;
LinkDirection _link_direction;
static float current_automation_version_number;
Index: libs/ardour/panner.cc
===================================================================
--- libs/ardour/panner.cc (revision 1560)
+++ libs/ardour/panner.cc (working copy)
@@ -70,6 +70,7 @@
_control (X_("panner"), *this)
{
_muted = false;
+ _mono = false;
parent.session().add_controllable (&_control);
@@ -118,6 +119,15 @@
}
void
+StreamPanner::set_mono (bool yn)
+{
+ if (yn != _mono) {
+ _mono = yn;
+ StateChanged ();
+ }
+}
+
+void
StreamPanner::set_position (float xpos, bool link_call)
{
if (!link_call && parent.linked()) {
@@ -183,6 +193,38 @@
node.add_property (X_("muted"), (muted() ? "yes" : "no"));
}
+void
+StreamPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
+{
+ if (_mono) {
+ /* we're in mono mode, so just pan the input to all outputs equally */
+ const int N = parent.nouts ();
+ for (int i = 0; i < N; ++i) {
+ Session::mix_buffers_with_gain (obufs[i], src, nframes, gain_coeff);
+ }
+ } else {
+ /* normal mode, call the `real' distribute method */
+ do_distribute (src, obufs, gain_coeff, nframes);
+ }
+}
+
+void
+StreamPanner::distribute_automated (Sample* src, Sample** obufs,
+ nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers)
+{
+ if (_mono) {
+ /* we're in mono mode, so just pan the input to all outputs equally */
+ const int N = parent.nouts ();
+ for (int i = 0; i < N; ++i) {
+ Session::mix_buffers_with_gain (obufs[i], src, nframes, 1.0);
+ }
+ } else {
+ /* normal mode, call the `real' distribute method */
+ do_distribute_automated (src, obufs, start, end, nframes, buffers);
+ }
+
+}
+
/*---------------------------------------------------------------------- */
BaseStereoPanner::BaseStereoPanner (Panner& p)
@@ -264,8 +306,9 @@
return 0;
}
+
void
-BaseStereoPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
+BaseStereoPanner::do_distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
{
pan_t delta;
Sample* dst;
@@ -281,9 +324,10 @@
if (fabsf ((delta = (left - desired_left))) > 0.002) { // about 1 degree of arc
- /* interpolate over 64 frames or nframes, whichever is smaller */
+ /* we're moving the pan by an appreciable amount, so we must
+ interpolate over 64 frames or nframes, whichever is smaller */
- nframes_t limit = min ((nframes_t)64, nframes);
+ const nframes_t limit = min ((nframes_t)64, nframes);
nframes_t n;
delta = -(delta / (float) (limit));
@@ -293,6 +337,8 @@
left = left_interp + 0.9 * (left - left_interp);
dst[n] += src[n] * left * gain_coeff;
}
+
+ /* then pan the rest of the buffer, no need for interpolation for this bit */
pan = left * gain_coeff;
@@ -306,6 +352,8 @@
if ((pan = (left * gain_coeff)) != 1.0f) {
if (pan != 0.0f) {
+
+ /* pan is not 1 but also not 0, so we must do it "properly" */
Session::mix_buffers_with_gain(dst,src,nframes,pan);
@@ -316,6 +364,8 @@
}
} else {
+
+ /* pan is 1 so we can just copy the input samples straight in */
Session::mix_buffers_no_gain(dst,src,nframes);
@@ -328,12 +378,13 @@
/* RIGHT */
dst = obufs[1];
-
+
if (fabsf ((delta = (right - desired_right))) > 0.002) { // about 1 degree of arc
- /* interpolate over 64 frames or nframes, whichever is smaller */
+ /* we're moving the pan by an appreciable amount, so we must
+ interpolate over 64 frames or nframes, whichever is smaller */
- nframes_t limit = min ((nframes_t)64, nframes);
+ const nframes_t limit = min ((nframes_t)64, nframes);
nframes_t n;
delta = -(delta / (float) (limit));
@@ -344,6 +395,8 @@
dst[n] += src[n] * right * gain_coeff;
}
+ /* then pan the rest of the buffer, no need for interpolation for this bit */
+
pan = right * gain_coeff;
Session::mix_buffers_with_gain(dst+n,src+n,nframes-n,pan);
@@ -359,6 +412,8 @@
if (pan != 0.0f) {
+ /* pan is not 1 but also not 0, so we must do it "properly" */
+
Session::mix_buffers_with_gain(dst,src,nframes,pan);
/* XXX it would be nice to mark the buffer as written to */
@@ -366,6 +421,8 @@
} else {
+ /* pan is 1 so we can just copy the input samples straight in */
+
Session::mix_buffers_no_gain(dst,src,nframes);
/* XXX it would be nice to mark the buffer as written to */
@@ -394,9 +451,9 @@
EqualPowerStereoPanner::update ()
{
/* it would be very nice to split this out into a virtual function
- that can be accessed from BaseStereoPanner and used in distribute_automated().
+ that can be accessed from BaseStereoPanner and used in do_distribute_automated().
- but the place where its used in distribute_automated() is a tight inner loop,
+ but the place where its used in do_distribute_automated() is a tight inner loop,
and making "nframes" virtual function calls to compute values is an absurd
overhead.
*/
@@ -418,7 +475,7 @@
}
void
-EqualPowerStereoPanner::distribute_automated (Sample* src, Sample** obufs,
+EqualPowerStereoPanner::do_distribute_automated (Sample* src, Sample** obufs,
nframes_t start, nframes_t end, nframes_t nframes,
pan_t** buffers)
{
@@ -430,7 +487,7 @@
if (!_automation.rt_safe_get_vector (start, end, buffers[0], nframes)) {
/* fallback */
if (!_muted) {
- distribute (src, obufs, 1.0, nframes);
+ do_distribute (src, obufs, 1.0, nframes);
}
return;
}
@@ -620,7 +677,7 @@
}
void
-Multi2dPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
+Multi2dPanner::do_distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nframes_t nframes)
{
Sample* dst;
pan_t pan;
@@ -691,9 +748,9 @@
}
void
-Multi2dPanner::distribute_automated (Sample* src, Sample** obufs,
- nframes_t start, nframes_t end, nframes_t nframes,
- pan_t** buffers)
+Multi2dPanner::do_distribute_automated (Sample* src, Sample** obufs,
+ nframes_t start, nframes_t end, nframes_t nframes,
+ pan_t** buffers)
{
if (_muted) {
return;
@@ -813,7 +870,27 @@
}
}
+void
+Panner::set_mono (bool yn)
+{
+ if (yn != _mono) {
+ _mono = yn;
+ StateChanged ();
+ }
+ for (iterator i = begin(); i != end(); ++i) {
+ (*i)->set_mono (yn);
+ }
+}
+
+
+/**
+ * Reset the panner with a given number of outs and panners (and hence inputs)
+ *
+ * \param nouts Number of outputs.
+ * \param npans Number of panners.
+ */
+
void
Panner::reset (uint32_t nouts, uint32_t npans)
{
@@ -824,6 +901,7 @@
return;
}
+ /* clear panners vector */
n = size();
clear ();
@@ -831,6 +909,7 @@
changed = true;
}
+ /* clear outputs vector */
n = outputs.size();
outputs.clear ();
@@ -838,6 +917,7 @@
changed = true;
}
+ /* decide how we pan based on the number of outputs */
switch (nouts) {
case 0:
break;
@@ -849,8 +929,7 @@
/*NOTREACHED*/
break;
- case 2:
- /* line */
+ case 2: // line
outputs.push_back (Output (0, 0));
outputs.push_back (Output (1.0, 0));
Index: libs/ardour/mix.cc
===================================================================
--- libs/ardour/mix.cc (revision 1560)
+++ libs/ardour/mix.cc (working copy)
@@ -97,6 +97,17 @@
buf[i] *= gain;
}
+
+/**
+ * Apply some gain to a set of source samples and then add them to the current
+ * contents of a destination buffer.
+ *
+ * \param dst Destination buffer.
+ * \param src Source samples.
+ * \param nframes Number of frames.
+ * \param gain Gain to apply to source samples.
+ */
+
void
mix_buffers_with_gain (ARDOUR::Sample *dst, ARDOUR::Sample *src, nframes_t nframes, float gain)
{
|
|
|
Attached is a patch against SVN to implement a mono switch. Would you like to give it a try and let me know what you think? |
|
|
can you give a short howto about applying the patch please? cheers, doc |
|
|
Hi doc, Copy the attached file into the top level of the ardour source tree (ie in ardour2/ if you've checked out from svn). Then in that directory type patch -p0 < mono-2 This should have applied the patch to your source tree, so then you can just build as normal. Let me know if you have any problems! Carl |
|
|
hi cth, thanks for the advice - no problem@all, looks like a new feature?? it is actually very good, cause with this, i can prove in a very fast way, if a track (including some fx's) or the hole mix is mono-compatible! another question: will this patch eventually make my sources unusable at the next svn-update? if yes, is there a way to clean up the source? cheers, doc |
|
|
svn update should work around the patch (for a while...) but if you want to remove it you can either do patch -p0 -R < patch_file to reverse the effect of the patch, or just do svn status to find the files that are modified (marked with M) and then for each one do svn revert file to change the file back to the one in SVN. Cheers Carl |
|
|
Works fine;). Really excellent. Thanks |
|
|
Carl did you ever apply this patch to svn? |
|
|
I didn't ever apply this. It is quite intrusive code-wise so I wanted to run it past Paul. |
|
|
looks like this hasn't ever been reviewed... paul, can you comment on this? the patch will very likely not apply any more (haven't even tried), but the general idea seems worth while... |
|
|
i like the idea but its too featureful for 2.X. i'd be happy to see a 3.0 version of the patch. |
|
|
This has been implemented in 3.0, rev. 5797. |
|
|
Issue has been closed automatically, by Trigger Close Plugin. Feel free to re-open with additional information if you think the issue is not resolved. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2005-09-07 21:37 | b0ef | New Issue | |
| 2007-03-06 16:29 | cth103 | File Added: mono-2 | |
| 2007-03-06 16:29 | cth103 | Note Added: 0003517 | |
| 2007-03-06 16:39 | nowhiskey | Note Added: 0003518 | |
| 2007-03-06 16:48 | cth103 | Note Added: 0003520 | |
| 2007-03-06 17:48 | taybin | Status | new => feedback |
| 2007-03-06 20:21 | nowhiskey | Note Added: 0003523 | |
| 2007-03-06 23:47 | cth103 | Note Added: 0003525 | |
| 2007-03-07 04:16 | b0ef | Note Added: 0003526 | |
| 2009-07-05 03:11 | seablade | Note Added: 0006292 | |
| 2009-07-09 09:40 | cth103 | Note Added: 0006410 | |
| 2009-08-31 20:18 | nettings | cost | => 0.00 |
| 2009-08-31 20:18 | nettings | Note Added: 0006620 | |
| 2009-08-31 20:18 | nettings | Assigned To | => paul |
| 2009-08-31 20:18 | nettings | Status | feedback => acknowledged |
| 2009-08-31 20:18 | nettings | Summary | Mono Switch => [PATCH] Mono Switch |
| 2009-10-01 15:41 | paul | Note Added: 0006664 | |
| 2009-10-19 14:46 | cth103 | Note Added: 0006721 | |
| 2009-10-19 14:46 | cth103 | Status | acknowledged => resolved |
| 2009-10-19 14:46 | cth103 | Fixed in Version | => SVN 3.0 |
| 2009-10-19 14:46 | cth103 | Resolution | open => fixed |
| 2020-04-19 20:12 | system | Note Added: 0021465 | |
| 2020-04-19 20:12 | system | Status | resolved => closed |