View Issue Details

IDProjectCategoryView StatusLast Update
0001068ardourfeaturespublic2020-04-19 20:12
Reporterb0ef Assigned Topaul  
PrioritynormalSeverityfeatureReproducibilityN/A
Status closedResolutionfixed 
Summary0001068: [PATCH] Mono Switch
DescriptionA 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.
TagsNo tags attached.

Activities

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)
 {

mono-2 (15,334 bytes)   

cth103

2007-03-06 16:29

administrator   ~0003517

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?

nowhiskey

2007-03-06 16:39

reporter   ~0003518

can you give a short howto about applying the patch please?

cheers,
doc

cth103

2007-03-06 16:48

administrator   ~0003520

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

nowhiskey

2007-03-06 20:21

reporter   ~0003523

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

cth103

2007-03-06 23:47

administrator   ~0003525

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

b0ef

2007-03-07 04:16

reporter   ~0003526

Works fine;). Really excellent. Thanks

seablade

2009-07-05 03:11

manager   ~0006292

Carl did you ever apply this patch to svn?

cth103

2009-07-09 09:40

administrator   ~0006410

I didn't ever apply this. It is quite intrusive code-wise so I wanted to run it past Paul.

nettings

2009-08-31 20:18

manager   ~0006620

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...

paul

2009-10-01 15:41

administrator   ~0006664

i like the idea but its too featureful for 2.X. i'd be happy to see a 3.0 version of the patch.

cth103

2009-10-19 14:46

administrator   ~0006721

This has been implemented in 3.0, rev. 5797.

system

2020-04-19 20:12

developer   ~0021465

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.

Issue History

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