diff options
author | Carl Hetherington <carl@carlh.net> | 2009-10-19 14:46:15 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2009-10-19 14:46:15 +0000 |
commit | 7b94110c545415af8437fc6631e7663ebb5c28f3 (patch) | |
tree | 2862ba08b5a30ba632293b399fb6fcd356a14f80 | |
parent | 16e993e51490bd6082869f7ca4783d56e7bd8bcd (diff) |
Add mono switch to mixer strips (mantis 1068)
git-svn-id: svn://localhost/ardour2/branches/3.0@5797 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r-- | gtk2_ardour/ardour3_ui_dark.rc.in | 1 | ||||
-rw-r--r-- | gtk2_ardour/ardour3_ui_dark_sae.rc.in | 1 | ||||
-rw-r--r-- | gtk2_ardour/ardour3_ui_light.rc.in | 1 | ||||
-rw-r--r-- | gtk2_ardour/ardour3_ui_light_sae.rc.in | 1 | ||||
-rw-r--r-- | gtk2_ardour/mixer_strip.cc | 11 | ||||
-rw-r--r-- | gtk2_ardour/mixer_strip.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/panner_ui.cc | 11 | ||||
-rw-r--r-- | gtk2_ardour/panner_ui.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/panner.h | 40 | ||||
-rw-r--r-- | libs/ardour/panner.cc | 106 |
10 files changed, 149 insertions, 27 deletions
diff --git a/gtk2_ardour/ardour3_ui_dark.rc.in b/gtk2_ardour/ardour3_ui_dark.rc.in index ec4d61dfd3..7fd11df4f3 100644 --- a/gtk2_ardour/ardour3_ui_dark.rc.in +++ b/gtk2_ardour/ardour3_ui_dark.rc.in @@ -1357,6 +1357,7 @@ widget "*MixerGroupButton" style:highest "very_small_button" widget "*MixerGroupButtonLabel" style:highest "very_small_button" widget "*MixerCommentButton" style:highest "very_small_button" widget "*MixerCommentButton*" style:highest "very_small_button" +widget "*MixerMonoButton*" style:highest "very_small_button" widget "*EditGroupButton" style:highest "very_small_button" widget "*EditGroupButtonLabel" style:highest "very_small_button" widget "*TransportButton" style:highest "transport_rec_button" diff --git a/gtk2_ardour/ardour3_ui_dark_sae.rc.in b/gtk2_ardour/ardour3_ui_dark_sae.rc.in index cefd45cbd0..1cb58e3285 100644 --- a/gtk2_ardour/ardour3_ui_dark_sae.rc.in +++ b/gtk2_ardour/ardour3_ui_dark_sae.rc.in @@ -1306,6 +1306,7 @@ widget "*MixerGroupButton" style:highest "very_small_button" widget "*MixerGroupButtonLabel" style:highest "very_small_button" widget "*MixerCommentButton" style:highest "very_small_button" widget "*MixerCommentButton*" style:highest "very_small_button" +widget "*MixerMonoButton*" style:highest "very_small_button" widget "*EditGroupButton" style:highest "very_small_button" widget "*EditGroupButtonLabel" style:highest "very_small_button" widget "*TransportButton" style:highest "transport_rec_button" diff --git a/gtk2_ardour/ardour3_ui_light.rc.in b/gtk2_ardour/ardour3_ui_light.rc.in index 5176556ba8..62b107ce76 100644 --- a/gtk2_ardour/ardour3_ui_light.rc.in +++ b/gtk2_ardour/ardour3_ui_light.rc.in @@ -1310,6 +1310,7 @@ widget "*MixerGroupButton" style:highest "very_small_button" widget "*MixerGroupButtonLabel" style:highest "very_small_button" widget "*MixerCommentButton" style:highest "very_small_button" widget "*MixerCommentButton*" style:highest "very_small_button" +widget "*MixerMonoButton*" style:highest "very_small_button" widget "*EditGroupButton" style:highest "very_small_button" widget "*EditGroupButtonLabel" style:highest "very_small_button" widget "*TransportButton" style:highest "transport_rec_button" diff --git a/gtk2_ardour/ardour3_ui_light_sae.rc.in b/gtk2_ardour/ardour3_ui_light_sae.rc.in index d41ac4fb97..c1b10a40be 100644 --- a/gtk2_ardour/ardour3_ui_light_sae.rc.in +++ b/gtk2_ardour/ardour3_ui_light_sae.rc.in @@ -1310,6 +1310,7 @@ widget "*MixerGroupButton" style:highest "very_small_button" widget "*MixerGroupButtonLabel" style:highest "very_small_button" widget "*MixerCommentButton" style:highest "very_small_button" widget "*MixerCommentButton*" style:highest "very_small_button" +widget "*MixerMonoButton*" style:highest "very_small_button" widget "*EditGroupButton" style:highest "very_small_button" widget "*EditGroupButtonLabel" style:highest "very_small_button" widget "*TransportButton" style:highest "transport_rec_button" diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 17761798c2..10e6999d05 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -81,6 +81,7 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer) , processor_box (sess, mx.plugin_selector(), mx.selection(), this, in_mixer) , gpm (sess) , panners (sess) + , _mono_button (_("Mono")) , button_table (3, 2) , middle_button_table (1, 2) , bottom_button_table (1, 2) @@ -236,6 +237,7 @@ MixerStrip::init () if (!is_midi_track()) { 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); @@ -387,6 +389,9 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt) name_label.set_text (_route->name()); } + _mono_button.set_name ("MixerMonoButton"); + _mono_button.signal_clicked().connect (mem_fun (*this, &MixerStrip::mono_button_clicked)); + switch (_route->meter_point()) { case MeterInput: meter_point_label.set_text (_("input")); @@ -1782,3 +1787,9 @@ MixerStrip::on_leave_notify_event (GdkEventCrossing* ev) return false; } + +void +MixerStrip::mono_button_clicked () +{ + panners.set_mono (_mono_button.get_active ()); +} diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index afacd4a328..c83c260845 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -142,6 +142,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox ProcessorBox processor_box; GainMeter gpm; PannerUI panners; + Gtk::ToggleButton _mono_button; Gtk::Table button_table; Gtk::Table middle_button_table; @@ -176,6 +177,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox 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; diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 31403220fe..a643e1b318 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -708,7 +708,7 @@ PannerUI::update_pan_bars (bool only_if_aplay) void PannerUI::update_pan_sensitive () { - bool sensitive = !(_panner->automation_state() & Play); + bool const sensitive = !(_panner->mono()) && !(_panner->automation_state() & Play); switch (_panner->nouts()) { case 0: @@ -890,3 +890,12 @@ PannerUI::_astyle_string (AutoStyle style, bool shrt) return (shrt ? _("Abs") : _("Abs")); } } + +void +PannerUI::set_mono (bool yn) +{ + _panner->set_mono (yn); + update_pan_sensitive (); +} + + diff --git a/gtk2_ardour/panner_ui.h b/gtk2_ardour/panner_ui.h index 724b8b86e7..bebffec6c0 100644 --- a/gtk2_ardour/panner_ui.h +++ b/gtk2_ardour/panner_ui.h @@ -74,6 +74,8 @@ class PannerUI : public Gtk::HBox void set_meter_strip_name (std::string name); boost::shared_ptr<PBD::Controllable> get_controllable(); + void set_mono (bool); + private: friend class MixerStrip; diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 86cd486113..7ea37e9974 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -49,6 +49,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful void set_muted (bool yn); bool muted() const { return _muted; } + void set_mono (bool); void set_position (float x, bool link_call = false); void set_position (float x, float y, bool link_call = false); @@ -62,11 +63,22 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful 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 (AudioBuffer &, BufferSet &, gain_t, nframes_t); + void distribute_automated (AudioBuffer &, BufferSet &, nframes_t, nframes_t, nframes_t, pan_t **); + /* the basic StreamPanner API */ - virtual void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) = 0; - virtual void distribute_automated (AudioBuffer& src, BufferSet& obufs, - nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers) = 0; + /** + * Pan some input samples to a number of output buffers. + * + * @param src Input buffer. + * @param obufs Output buffers (one per panner output). + * @param gain_coeff Gain coefficient to apply to output samples. + * @param nframes Numbner of frames in the input. + */ + virtual void do_distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) = 0; + virtual void do_distribute_automated (AudioBuffer& src, BufferSet& obufs, + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers) = 0; boost::shared_ptr<AutomationControl> pan_control() { return _control; } @@ -99,6 +111,7 @@ class StreamPanner : public sigc::trackable, public PBD::Stateful float effective_z; bool _muted; + bool _mono; boost::shared_ptr<AutomationControl> _control; @@ -113,12 +126,12 @@ class BaseStereoPanner : public StreamPanner ~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 (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); + void do_distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); /* old school automation loading */ @@ -139,8 +152,8 @@ class EqualPowerStereoPanner : public BaseStereoPanner EqualPowerStereoPanner (Panner&, Evoral::Parameter param); ~EqualPowerStereoPanner (); - void distribute_automated (AudioBuffer& src, BufferSet& obufs, - nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); + void do_distribute_automated (AudioBuffer& src, BufferSet& obufs, + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); void get_current_coefficients (pan_t*) const; void get_desired_coefficients (pan_t*) const; @@ -162,9 +175,9 @@ class Multi2dPanner : public StreamPanner Multi2dPanner (Panner& parent, Evoral::Parameter); ~Multi2dPanner (); - void distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); - void distribute_automated (AudioBuffer& src, BufferSet& obufs, - nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); + void do_distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes); + void do_distribute_automated (AudioBuffer& src, BufferSet& obufs, + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers); static StreamPanner* factory (Panner&, Evoral::Parameter); static std::string name; @@ -182,6 +195,8 @@ class Multi2dPanner : public StreamPanner }; +///< Class to pan from some number of inputs to some number of outputs + class Panner : public SessionObject, public AutomatableControls { public: @@ -219,6 +234,8 @@ public: bool bypassed() const { return _bypassed; } void set_bypassed (bool yn); + bool mono () const { return _mono; } + void set_mono (bool); StreamPanner* add (); void remove (uint32_t which); @@ -295,10 +312,11 @@ public: Panner (Panner const &); void distribute_no_automation(BufferSet& src, BufferSet& dest, nframes_t nframes, gain_t gain_coeff); - std::vector<StreamPanner*> _streampanners; + std::vector<StreamPanner*> _streampanners; ///< one StreamPanner per input uint32_t current_outs; bool _linked; bool _bypassed; + bool _mono; LinkDirection _link_direction; static float current_automation_version_number; diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index a867130b51..6c8dc153bb 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -80,6 +80,7 @@ StreamPanner::StreamPanner (Panner& p, Evoral::Parameter param) assert(param.type() != NullAutomation); _muted = false; + _mono = false; _control = boost::dynamic_pointer_cast<AutomationControl>( parent.control( param, true ) ); @@ -93,6 +94,15 @@ StreamPanner::~StreamPanner () } void +StreamPanner::set_mono (bool yn) +{ + if (yn != _mono) { + _mono = yn; + StateChanged (); + } +} + +void Panner::PanControllable::set_value (float val) { panner.streampanner(parameter().id()).set_position (direct_control_to_pan (val)); @@ -180,6 +190,39 @@ StreamPanner::add_state (XMLNode& node) node.add_property (X_("muted"), (muted() ? "yes" : "no")); } +void +StreamPanner::distribute (AudioBuffer& src, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) +{ + if (_mono) { + /* we're in mono mode, so just pan the input to all outputs equally */ + int const N = parent.nouts (); + for (int i = 0; i < N; ++i) { + mix_buffers_with_gain (obufs.get_audio(i).data(), src.data(), nframes, gain_coeff); + } + } else { + /* normal mode, call the `real' distribute method */ + do_distribute (src, obufs, gain_coeff, nframes); + } +} + +void +StreamPanner::distribute_automated (AudioBuffer& src, BufferSet& 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 */ + int const N = parent.nouts (); + for (int i = 0; i < N; ++i) { + mix_buffers_with_gain (obufs.get_audio(i).data(), src.data(), nframes, 1.0); + } + } else { + /* normal mode, call the `real' distribute method */ + do_distribute_automated (src, obufs, start, end, nframes, buffers); + } + +} + + /*---------------------------------------------------------------------- */ BaseStereoPanner::BaseStereoPanner (Panner& p, Evoral::Parameter param) @@ -225,7 +268,7 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) } void -BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) +BaseStereoPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) { assert(obufs.count().n_audio() == 2); @@ -245,9 +288,10 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain if (fabsf ((delta = (left - desired_left))) > 0.002) { // about 1 degree of arc - /* interpolate over 64 frames or nframes, whichever is smaller */ + /* we've 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); + nframes_t const limit = min ((nframes_t)64, nframes); nframes_t n; delta = -(delta / (float) (limit)); @@ -258,6 +302,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain 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; mix_buffers_with_gain (dst+n,src+n,nframes-n,pan); @@ -271,6 +317,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain if (pan != 0.0f) { + /* pan is 1 but also not 0, so we must do it "properly" */ + mix_buffers_with_gain(dst,src,nframes,pan); /* mark that we wrote into the buffer */ @@ -281,6 +329,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain } else { + /* pan is 1 so we can just copy the input samples straight in */ + mix_buffers_no_gain(dst,src,nframes); /* mark that we wrote into the buffer */ @@ -295,9 +345,10 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain 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); + nframes_t const limit = min ((nframes_t)64, nframes); nframes_t n; delta = -(delta / (float) (limit)); @@ -308,6 +359,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain 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; mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); @@ -323,6 +376,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain if (pan != 0.0f) { + /* pan is not 1 but also not 0, so we must do it "properly" */ + mix_buffers_with_gain(dst,src,nframes,pan); /* XXX it would be nice to mark the buffer as written to */ @@ -330,6 +385,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain } else { + /* pan is 1 so we can just copy the input samples straight in */ + mix_buffers_no_gain(dst,src,nframes); /* XXX it would be nice to mark the buffer as written to */ @@ -358,9 +415,9 @@ void 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. */ @@ -383,9 +440,9 @@ EqualPowerStereoPanner::update () } void -EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& obufs, - nframes_t start, nframes_t end, nframes_t nframes, - pan_t** buffers) +EqualPowerStereoPanner::do_distribute_automated (AudioBuffer& srcbuf, BufferSet& obufs, + nframes_t start, nframes_t end, nframes_t nframes, + pan_t** buffers) { assert(obufs.count().n_audio() == 2); @@ -398,7 +455,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob if (!_control->list()->curve().rt_safe_get_vector (start, end, buffers[0], nframes)) { /* fallback */ if (!_muted) { - distribute (srcbuf, obufs, 1.0, nframes); + do_distribute (srcbuf, obufs, 1.0, nframes); } return; } @@ -563,7 +620,7 @@ Multi2dPanner::update () } void -Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) +Multi2dPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) { Sample* dst; pan_t pan; @@ -623,9 +680,9 @@ Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co } void -Multi2dPanner::distribute_automated (AudioBuffer& /*src*/, BufferSet& /*obufs*/, - nframes_t /*start*/, nframes_t /*end*/, nframes_t /*nframes*/, - pan_t** /*buffers*/) +Multi2dPanner::do_distribute_automated (AudioBuffer& /*src*/, BufferSet& /*obufs*/, + nframes_t /*start*/, nframes_t /*end*/, nframes_t /*nframes*/, + pan_t** /*buffers*/) { if (_muted) { return; @@ -823,6 +880,12 @@ Panner::reset_streampanner (uint32_t which) } } +/** + * 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) { @@ -1557,3 +1620,16 @@ Panner::load () return 0; } + +void +Panner::set_mono (bool yn) +{ + if (yn != _mono) { + _mono = yn; + StateChanged (); + } + + for (vector<StreamPanner*>::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { + (*i)->set_mono (yn); + } +} |