Returns (i.e. sidechains).

And lo, upon the revision of our hoarde 5061, was the last Big Feature
committed to Three Poino, who, now more than ever, lurks imposingly on
the sidelines, heir to the throne, and eventual ruler of the realm.
His eventual succession all but guaranteed, only time and the number
of heads that must roll remain mysteries.


git-svn-id: svn://localhost/ardour2/branches/3.0@5061 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2009-05-07 17:31:18 +00:00
parent 80c8866303
commit 2c231282ba
25 changed files with 775 additions and 192 deletions

View File

@ -424,6 +424,7 @@
; (gtk_accel_path "<Actions>/redirectmenu/newinsert" "")
; (gtk_accel_path "<Actions>/redirectmenu/newplugin" "")
; (gtk_accel_path "<Actions>/redirectmenu/newsend" "")
; (gtk_accel_path "<Actions>/redirectmenu/newreturn" "")
; (gtk_accel_path "<Actions>/redirectmenu/paste" "")
; (gtk_accel_path "<Actions>/redirectmenu/rename" "")
; (gtk_accel_path "<Actions>/redirectmenu/selectall" "")

View File

@ -354,6 +354,7 @@
<menuitem action='newplugin'/>
<menuitem action='newinsert'/>
<menuitem action='newsend'/>
<menuitem action='newreturn'/>
<separator/>
<menuitem action='clear'/>
<separator/>

View File

@ -607,6 +607,7 @@
<menuitem action='newplugin'/>
<menuitem action='newinsert'/>
<menuitem action='newsend'/>
<menuitem action='newreturn'/>
<separator/>
<menuitem action='clear'/>
<separator/>
@ -663,6 +664,7 @@
<menuitem action='newplugin'/>
<menuitem action='newinsert'/>
<menuitem action='newsend'/>
<menuitem action='newreturn'/>
<separator/>
<menuitem action='clear'/>
<separator/>

View File

@ -129,6 +129,7 @@
; (gtk_accel_path "<Actions>/Editor/EditSelectRegionOptions" "")
(gtk_accel_path "<Actions>/Editor/crop" "c")
; (gtk_accel_path "<Actions>/redirectmenu/newsend" "")
; (gtk_accel_path "<Actions>/redirectmenu/newreturn" "")
; (gtk_accel_path "<Actions>/Editor/ToggleGeneric MIDISurfaceSubMenu" "")
; (gtk_accel_path "<Actions>/Editor/MeterFalloff" "")
; (gtk_accel_path "<Actions>/RegionList/rlRemove" "")

View File

@ -439,6 +439,7 @@
; (gtk_accel_path "<Actions>/Editor/playhead-to-range-end" "")
; (gtk_accel_path "<Actions>/Editor/EditSelectRegionOptions" "")
; (gtk_accel_path "<Actions>/redirectmenu/newsend" "")
; (gtk_accel_path "<Actions>/redirectmenu/newreturn" "")
; (gtk_accel_path "<Actions>/Editor/ToggleGeneric MIDISurfaceSubMenu" "")
; (gtk_accel_path "<Actions>/Editor/MeterFalloff" "")
; (gtk_accel_path "<Actions>/RegionList/rlRemove" "")

View File

@ -47,23 +47,26 @@
#include "ardour/plugin_insert.h"
#include "ardour/port_insert.h"
#include "ardour/profile.h"
#include "ardour/return.h"
#include "ardour/route.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour_ui.h"
#include "ardour_dialog.h"
#include "public_editor.h"
#include "processor_box.h"
#include "keyboard.h"
#include "plugin_selector.h"
#include "route_processor_selection.h"
#include "mixer_ui.h"
#include "actions.h"
#include "plugin_ui.h"
#include "io_selector.h"
#include "utils.h"
#include "ardour_dialog.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "io_selector.h"
#include "keyboard.h"
#include "mixer_ui.h"
#include "plugin_selector.h"
#include "plugin_ui.h"
#include "processor_box.h"
#include "public_editor.h"
#include "return_ui.h"
#include "route_processor_selection.h"
#include "send_ui.h"
#include "utils.h"
#include "i18n.h"
@ -216,6 +219,7 @@ void
ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
{
boost::shared_ptr<Send> send;
boost::shared_ptr<Return> retrn;
boost::shared_ptr<PortInsert> port_insert;
if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
@ -226,6 +230,10 @@ ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
send->set_gui (0);
delete sui;
} else if ((retrn = boost::dynamic_pointer_cast<Return> (processor)) != 0) {
ReturnUIWindow *rui = reinterpret_cast<ReturnUIWindow*> (retrn->get_gui());
retrn->set_gui (0);
delete rui;
}
}
@ -495,20 +503,13 @@ void
ProcessorBox::choose_send ()
{
boost::shared_ptr<Send> send (new Send (_session));
//send->set_default_type(_route->default_type());
ChanCount outs;
/* make an educated guess at the initial number of outputs for the send */
if (_session.master_out()) {
outs = _session.master_out()->n_outputs();
} else {
outs = _route->n_outputs();
}
ChanCount outs = (_session.master_out())
? _session.master_out()->n_outputs()
: _route->n_outputs();
/* XXX need processor lock on route */
try {
send->io()->ensure_io (ChanCount::ZERO, outs, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) {
@ -516,23 +517,17 @@ ProcessorBox::choose_send ()
return;
}
/* let the user adjust the output setup (number and connections) before passing
it along to the Route
*/
/* let the user adjust the IO setup before creation */
IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
ios->show_all ();
/* bit of a hack; keep a shared_ptr to send around so that it doesn't get deleted while
/* keep a reference to the send so it doesn't get deleted while
the IOSelectorWindow is doing its stuff */
_send_being_created = send;
boost::shared_ptr<Processor> r = boost::static_pointer_cast<Processor>(send);
_processor_being_created = send;
ios->selector().Finished.connect (bind (
mem_fun(*this, &ProcessorBox::send_io_finished),
boost::weak_ptr<Processor>(r), ios));
boost::weak_ptr<Processor>(send), ios));
}
void
@ -540,8 +535,65 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
{
boost::shared_ptr<Processor> processor (weak_processor.lock());
/* now we can lose the dummy shared_ptr */
_send_being_created.reset ();
/* drop our temporary reference to the new send */
_processor_being_created.reset ();
if (!processor) {
return;
}
switch (r) {
case IOSelector::Cancelled:
// processor will go away when all shared_ptrs to it vanish
break;
case IOSelector::Accepted:
_route->add_processor (processor, 0, 0, _placement);
if (Profile->get_sae()) {
processor->activate ();
}
break;
}
delete_when_idle (ios);
}
void
ProcessorBox::choose_return ()
{
boost::shared_ptr<Return> retrn (new Return (_session));
/* assume user just wants a single audio input (sidechain) by default */
ChanCount ins(DataType::AUDIO, 1);
/* XXX need processor lock on route */
try {
retrn->io()->ensure_io (ins, ChanCount::ZERO, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) {
error << string_compose (_("Cannot set up new return: %1"), err.what()) << endmsg;
return;
}
/* let the user adjust the IO setup before creation */
IOSelectorWindow *ios = new IOSelectorWindow (_session, retrn->io(), true, true);
ios->show_all ();
/* keep a reference to the send so it doesn't get deleted while
the IOSelectorWindow is doing its stuff */
_processor_being_created = retrn;
ios->selector().Finished.connect (bind (
mem_fun(*this, &ProcessorBox::return_io_finished),
boost::weak_ptr<Processor>(retrn), ios));
}
void
ProcessorBox::return_io_finished (IOSelector::Result r, boost::weak_ptr<Processor> weak_processor, IOSelectorWindow* ios)
{
boost::shared_ptr<Processor> processor (weak_processor.lock());
/* drop our temporary reference to the new return */
_processor_being_created.reset ();
if (!processor) {
return;
@ -1067,6 +1119,7 @@ void
ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
{
boost::shared_ptr<Send> send;
boost::shared_ptr<Return> retrn;
boost::shared_ptr<PluginInsert> plugin_insert;
boost::shared_ptr<PortInsert> port_insert;
Window* gidget = 0;
@ -1103,6 +1156,32 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
}
gidget = send_ui;
} else if ((retrn = boost::dynamic_pointer_cast<Return> (processor)) != 0) {
if (!_session.engine().connected()) {
return;
}
boost::shared_ptr<Return> retrn = boost::dynamic_pointer_cast<Return> (processor);
ReturnUIWindow *return_ui;
if (retrn->get_gui() == 0) {
return_ui = new ReturnUIWindow (retrn, _session);
WindowTitle title(Glib::get_application_name());
title += retrn->name();
return_ui->set_title (title.get_string());
send->set_gui (return_ui);
} else {
return_ui = reinterpret_cast<ReturnUIWindow *> (retrn->get_gui());
}
gidget = return_ui;
} else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
@ -1194,6 +1273,9 @@ ProcessorBox::register_actions ()
act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),
sigc::ptr_fun (ProcessorBox::rb_choose_send));
ActionManager::jack_sensitive_actions.push_back (act);
act = ActionManager::register_action (popup_act_grp, X_("newreturn"), _("New Return ..."),
sigc::ptr_fun (ProcessorBox::rb_choose_return));
ActionManager::jack_sensitive_actions.push_back (act);
ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),
sigc::ptr_fun (ProcessorBox::rb_clear));
@ -1267,6 +1349,15 @@ ProcessorBox::rb_choose_send ()
_current_processor_box->choose_send ();
}
void
ProcessorBox::rb_choose_return ()
{
if (_current_processor_box == 0) {
return;
}
_current_processor_box->choose_return ();
}
void
ProcessorBox::rb_clear ()
{

View File

@ -94,8 +94,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
bool ab_direction;
std::vector<sigc::connection> connections;
/// a send that is in the process of creation
boost::shared_ptr<ARDOUR::Send> _send_being_created;
boost::shared_ptr<ARDOUR::Processor> _processor_being_created;
ARDOUR::Placement _placement;
@ -147,6 +146,8 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
void choose_send ();
void send_io_finished (IOSelector::Result, boost::weak_ptr<ARDOUR::Processor>, IOSelectorWindow*);
void choose_return ();
void return_io_finished (IOSelector::Result, boost::weak_ptr<ARDOUR::Processor>, IOSelectorWindow*);
void choose_insert ();
void choose_plugin ();
void use_plugins (const SelectedPlugins&);
@ -209,6 +210,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
static void rb_choose_plugin ();
static void rb_choose_insert ();
static void rb_choose_send ();
static void rb_choose_return ();
static void rb_clear ();
static void rb_cut ();
static void rb_copy ();

133
gtk2_ardour/return_ui.cc Normal file
View File

@ -0,0 +1,133 @@
/*
Copyright (C) 2002 Paul Davis
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gtkmm2ext/doi.h>
#include "ardour/io.h"
#include "ardour/return.h"
#include "utils.h"
#include "return_ui.h"
#include "io_selector.h"
#include "ardour_ui.h"
#include "gui_thread.h"
using namespace ARDOUR;
using namespace PBD;
ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
: _return (r)
, _session (se)
, _gpm (se)
{
_gpm.set_io (r->io());
_hbox.pack_start (_gpm, true, true);
set_name ("ReturnUIFrame");
_vbox.set_spacing (5);
_vbox.set_border_width (5);
_vbox.pack_start (_hbox, false, false, false);
io = manage (new IOSelector (se, r->io(), true));
pack_start (_vbox, false, false);
pack_start (*io, true, true);
show_all ();
//_return->set_metering (true);
_return->io()->input_changed.connect (mem_fun (*this, &ReturnUI::ins_changed));
//_return->io()->output_changed.connect (mem_fun (*this, &ReturnUI::outs_changed));
_gpm.setup_meters ();
_gpm.set_fader_name ("ReturnUIFrame");
// screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::update));
fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::fast_update));
}
ReturnUI::~ReturnUI ()
{
//_return->set_metering (false);
/* XXX not clear that we need to do this */
screen_update_connection.disconnect();
fast_screen_update_connection.disconnect();
}
void
ReturnUI::ins_changed (IOChange change, void* ignored)
{
ENSURE_GUI_THREAD(bind (mem_fun (*this, &ReturnUI::ins_changed), change, ignored));
if (change & ConfigurationChanged) {
_gpm.setup_meters ();
}
}
void
ReturnUI::update ()
{
}
void
ReturnUI::fast_update ()
{
if (Config->get_meter_falloff() > 0.0f) {
_gpm.update_meters ();
}
}
ReturnUIWindow::ReturnUIWindow (boost::shared_ptr<Return> s, Session& ss)
: ArdourDialog (string("Ardour: return ") + s->name())
{
ui = new ReturnUI (s, ss);
hpacker.pack_start (*ui, true, true);
get_vbox()->set_border_width (5);
get_vbox()->pack_start (hpacker);
set_name ("ReturnUIWindow");
going_away_connection = s->GoingAway.connect (
mem_fun (*this, &ReturnUIWindow::return_going_away));
signal_delete_event().connect (bind (
ptr_fun (just_hide_it),
reinterpret_cast<Window *> (this)));
}
ReturnUIWindow::~ReturnUIWindow ()
{
delete ui;
}
void
ReturnUIWindow::return_going_away ()
{
ENSURE_GUI_THREAD (mem_fun (*this, &ReturnUIWindow::return_going_away));
delete_when_idle (this);
going_away_connection.disconnect ();
}

77
gtk2_ardour/return_ui.h Normal file
View File

@ -0,0 +1,77 @@
/*
Copyright (C) 2002 Paul Davis
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_gtk_return_ui_h__
#define __ardour_gtk_return_ui_h__
#include "gain_meter.h"
#include "panner_ui.h"
#include "ardour_dialog.h"
namespace ARDOUR {
class Return;
class Session;
class IOProcessor;
}
class IOSelector;
class ReturnUI : public Gtk::HBox
{
public:
ReturnUI (boost::shared_ptr<ARDOUR::Return>, ARDOUR::Session&);
~ReturnUI();
void update ();
void fast_update ();
IOSelector* io;
boost::shared_ptr<ARDOUR::Return>& retrn() { return _return; }
private:
boost::shared_ptr<ARDOUR::Return> _return;
ARDOUR::Session& _session;
GainMeter _gpm;
Gtk::VBox _vbox;
Gtk::VBox _hbox;
sigc::connection screen_update_connection;
sigc::connection fast_screen_update_connection;
void ins_changed (ARDOUR::IOChange, void*);
};
class ReturnUIWindow : public ArdourDialog
{
public:
ReturnUIWindow(boost::shared_ptr<ARDOUR::Return>, ARDOUR::Session&);
~ReturnUIWindow();
ReturnUI* ui;
private:
Gtk::HBox hpacker;
void return_going_away ();
sigc::connection going_away_connection;
};
#endif /* __ardour_gtk_return_ui_h__ */

View File

@ -26,29 +26,31 @@
#include <gtkmm2ext/stop_signal.h>
#include <gtkmm2ext/window_title.h>
#include "ardour/ardour.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audio_track.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
#include "ardour/plugin_manager.h"
#include "ardour/port_insert.h"
#include "ardour/return.h"
#include "ardour/route.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour/session.h"
#include "ardour/session_route.h"
#include "ardour/audio_diskstream.h"
#include "ardour/plugin.h"
#include "ardour/plugin_manager.h"
#include "ardour/ardour.h"
#include "ardour/session.h"
#include "ardour/route.h"
#include "ardour/audio_track.h"
#include "ardour/send.h"
#include "ardour/plugin_insert.h"
#include "ardour/port_insert.h"
#include "route_params_ui.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "io_selector.h"
#include "keyboard.h"
#include "mixer_strip.h"
#include "plugin_selector.h"
#include "ardour_ui.h"
#include "plugin_ui.h"
#include "io_selector.h"
#include "return_ui.h"
#include "route_params_ui.h"
#include "send_ui.h"
#include "utils.h"
#include "gui_thread.h"
#include "i18n.h"
@ -559,6 +561,7 @@ RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert,
}
boost::shared_ptr<Send> send;
boost::shared_ptr<Return> retrn;
boost::shared_ptr<PluginInsert> plugin_insert;
boost::shared_ptr<PortInsert> port_insert;
@ -568,35 +571,66 @@ RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert,
if (place == PreFader) {
cleanup_pre_view();
_pre_plugin_conn = send->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_going_away), insert));
_pre_plugin_conn = send->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_pre_view = send_ui;
pre_redir_hpane.add2 (*_active_pre_view);
pre_redir_hpane.show_all();
}
else {
} else {
cleanup_post_view();
_post_plugin_conn = send->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_going_away), insert));
_post_plugin_conn = send->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_post_view = send_ui;
post_redir_hpane.add2 (*_active_post_view);
post_redir_hpane.show_all();
}
} else if ((retrn = boost::dynamic_pointer_cast<Return> (insert)) != 0) {
ReturnUI *return_ui = new ReturnUI (retrn, *session);
if (place == PreFader) {
cleanup_pre_view();
_pre_plugin_conn = retrn->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_pre_view = return_ui;
pre_redir_hpane.add2 (*_active_pre_view);
pre_redir_hpane.show_all();
} else {
cleanup_post_view();
_post_plugin_conn = retrn->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_post_view = return_ui;
post_redir_hpane.add2 (*_active_post_view);
post_redir_hpane.show_all();
}
} else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (insert)) != 0) {
GenericPluginUI *plugin_ui = new GenericPluginUI (plugin_insert, true);
if (place == PreFader) {
cleanup_pre_view();
_pre_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PreFader));
_pre_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::plugin_going_away),
PreFader));
plugin_ui->start_updating (0);
_active_pre_view = plugin_ui;
pre_redir_hpane.pack2 (*_active_pre_view);
pre_redir_hpane.show_all();
}
else {
} else {
cleanup_post_view();
_post_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PostFader));
_post_plugin_conn = plugin_insert->plugin()->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::plugin_going_away),
PostFader));
plugin_ui->start_updating (0);
_active_post_view = plugin_ui;
post_redir_hpane.pack2 (*_active_post_view);
@ -609,15 +643,18 @@ RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert,
if (place == PreFader) {
cleanup_pre_view();
_pre_plugin_conn = port_insert->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_going_away), insert));
_pre_plugin_conn = port_insert->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_pre_view = portinsert_ui;
pre_redir_hpane.pack2 (*_active_pre_view);
portinsert_ui->redisplay();
pre_redir_hpane.show_all();
}
else {
} else {
cleanup_post_view();
_post_plugin_conn = port_insert->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_going_away), insert));
_post_plugin_conn = port_insert->GoingAway.connect (bind (
mem_fun(*this, &RouteParams_UI::redirect_going_away),
insert));
_active_post_view = portinsert_ui;
post_redir_hpane.pack2 (*_active_post_view);
portinsert_ui->redisplay();

View File

@ -34,24 +34,24 @@ using namespace PBD;
SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
: _send (s)
, _session (se)
, gpm (se)
, panners (se)
, _gpm (se)
, _panners (se)
{
panners.set_io (s->io());
gpm.set_io (s->io());
_panners.set_io (s->io());
_gpm.set_io (s->io());
hbox.pack_start (gpm, true, true);
_hbox.pack_start (_gpm, true, true);
set_name ("SendUIFrame");
vbox.set_spacing (5);
vbox.set_border_width (5);
_vbox.set_spacing (5);
_vbox.set_border_width (5);
vbox.pack_start (hbox, false, false, false);
vbox.pack_start (panners, false,false);
_vbox.pack_start (_hbox, false, false, false);
_vbox.pack_start (_panners, false,false);
io = manage (new IOSelector (se, s->io(), true));
pack_start (vbox, false, false);
pack_start (_vbox, false, false);
pack_start (*io, true, true);
@ -62,14 +62,16 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
_send->io()->input_changed.connect (mem_fun (*this, &SendUI::ins_changed));
_send->io()->output_changed.connect (mem_fun (*this, &SendUI::outs_changed));
panners.set_width (Wide);
panners.setup_pan ();
_panners.set_width (Wide);
_panners.setup_pan ();
gpm.setup_meters ();
gpm.set_fader_name ("SendUIFrame");
_gpm.setup_meters ();
_gpm.set_fader_name ("SendUIFrame");
// screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun (*this, &SendUI::update));
fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &SendUI::fast_update));
// screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (
// mem_fun (*this, &SendUI::update));
fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
mem_fun (*this, &SendUI::fast_update));
}
SendUI::~SendUI ()
@ -87,7 +89,7 @@ SendUI::ins_changed (IOChange change, void* ignored)
{
ENSURE_GUI_THREAD(bind (mem_fun (*this, &SendUI::ins_changed), change, ignored));
if (change & ConfigurationChanged) {
panners.setup_pan ();
_panners.setup_pan ();
}
}
@ -96,8 +98,8 @@ SendUI::outs_changed (IOChange change, void* ignored)
{
ENSURE_GUI_THREAD(bind (mem_fun (*this, &SendUI::outs_changed), change, ignored));
if (change & ConfigurationChanged) {
panners.setup_pan ();
gpm.setup_meters ();
_panners.setup_pan ();
_gpm.setup_meters ();
}
}
@ -110,7 +112,7 @@ void
SendUI::fast_update ()
{
if (Config->get_meter_falloff() > 0.0f) {
gpm.update_meters ();
_gpm.update_meters ();
}
}
@ -126,9 +128,12 @@ SendUIWindow::SendUIWindow (boost::shared_ptr<Send> s, Session& ss)
set_name ("SendUIWindow");
going_away_connection = s->GoingAway.connect (mem_fun (*this, &SendUIWindow::send_going_away));
going_away_connection = s->GoingAway.connect (
mem_fun (*this, &SendUIWindow::send_going_away));
signal_delete_event().connect (bind (ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
signal_delete_event().connect (bind (
ptr_fun (just_hide_it),
reinterpret_cast<Window *> (this)));
}
SendUIWindow::~SendUIWindow ()

View File

@ -47,11 +47,11 @@ class SendUI : public Gtk::HBox
private:
boost::shared_ptr<ARDOUR::Send> _send;
ARDOUR::Session& _session;
GainMeter gpm;
PannerUI panners;
Gtk::VBox vbox;
Gtk::VBox hbox;
ARDOUR::Session& _session;
GainMeter _gpm;
PannerUI _panners;
Gtk::VBox _vbox;
Gtk::VBox _hbox;
sigc::connection screen_update_connection;
sigc::connection fast_screen_update_connection;
@ -66,7 +66,7 @@ class SendUIWindow : public ArdourDialog
SendUIWindow(boost::shared_ptr<ARDOUR::Send>, ARDOUR::Session&);
~SendUIWindow();
SendUI* ui;
SendUI* ui;
private:
Gtk::HBox hpacker;

View File

@ -182,6 +182,7 @@ def build(bld):
region_gain_line.cc
region_selection.cc
region_view.cc
return_ui.cc
rhythm_ferret.cc
route_params_ui.cc
route_processor_selection.cc

View File

@ -106,6 +106,14 @@ public:
return ( (*this > other) || (*this == other) );
}
ChanCount operator+(const ChanCount& other) const {
ChanCount ret;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
ret.set(*t, get(*t) + other.get(*t));
}
return ret;
}
static ChanCount min(const ChanCount& a, const ChanCount& b) {
ChanCount ret;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {

View File

@ -102,7 +102,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
virtual void silence (nframes_t);
void collect_input (BufferSet& bufs, nframes_t nframes);
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
void deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
void just_meter_input (nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
@ -214,7 +214,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent
static sigc::signal<int> ConnectingLegal;
/// raised when the number of input or output ports changes
static sigc::signal<void,ChanCount> PortCountChanged;
static sigc::signal<int> PortsCreated;
static sigc::signal<void,nframes_t> CycleStart;
static void update_meters();

View File

@ -54,9 +54,6 @@ class PortInsert : public IOProcessor
nframes_t signal_latency() const;
ChanCount output_streams() const;
ChanCount input_streams() const;
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);

View File

@ -0,0 +1,71 @@
/*
Copyright (C) 2009 Paul Davis
Author: Dave Robillard
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_return_h__
#define __ardour_return_h__
#include <sigc++/signal.h>
#include <string>
#include "pbd/stateful.h"
#include "ardour/ardour.h"
#include "ardour/audioengine.h"
#include "ardour/io_processor.h"
namespace ARDOUR {
class Return : public IOProcessor
{
public:
Return (Session&);
Return (Session&, const XMLNode&);
virtual ~Return ();
uint32_t bit_slot() const { return _bitslot; }
void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
void activate() {}
void deactivate () {}
XMLNode& state(bool full);
XMLNode& get_state(void);
int set_state(const XMLNode& node);
uint32_t pans_required() const { return _configured_input.n_audio(); }
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
static uint32_t how_many_sends();
static void make_unique (XMLNode &, Session &);
private:
/* disallow copy construction */
Return (const Return&);
uint32_t _bitslot;
};
} // namespace ARDOUR
#endif /* __ardour_return_h__ */

View File

@ -38,10 +38,7 @@ class Send : public IOProcessor
Send (Session&, const XMLNode&);
virtual ~Send ();
uint32_t bit_slot() const { return bitslot; }
ChanCount output_streams() const;
ChanCount input_streams () const;
uint32_t bit_slot() const { return _bitslot; }
void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
@ -55,7 +52,6 @@ class Send : public IOProcessor
int set_state(const XMLNode& node);
uint32_t pans_required() const { return _configured_input.n_audio(); }
void expect_inputs (const ChanCount&);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
@ -68,8 +64,7 @@ class Send : public IOProcessor
Send (const Send&);
bool _metering;
ChanCount expected_inputs;
uint32_t bitslot;
uint32_t _bitslot;
};
} // namespace ARDOUR

View File

@ -101,6 +101,7 @@ class Port;
class PortInsert;
class Processor;
class Region;
class Return;
class Route;
class RouteGroup;
class SMFSource;
@ -764,8 +765,10 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
}
uint32_t next_send_id();
uint32_t next_return_id();
uint32_t next_insert_id();
void mark_send_id (uint32_t);
void mark_return_id (uint32_t);
void mark_insert_id (uint32_t);
/* s/w "RAID" management */
@ -1566,7 +1569,9 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
list<PortInsert *> _port_inserts;
list<PluginInsert *> _plugin_inserts;
list<Send *> _sends;
list<Return *> _returns;
boost::dynamic_bitset<uint32_t> send_bitset;
boost::dynamic_bitset<uint32_t> return_bitset;
boost::dynamic_bitset<uint32_t> insert_bitset;
uint32_t send_cnt;
uint32_t insert_cnt;

View File

@ -74,7 +74,6 @@ sigc::signal<int> IO::ConnectingLegal;
sigc::signal<int> IO::PortsLegal;
sigc::signal<int> IO::PannersLegal;
sigc::signal<void,ChanCount> IO::PortCountChanged;
sigc::signal<int> IO::PortsCreated;
sigc::signal<void,nframes_t> IO::CycleStart;
Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
@ -290,24 +289,31 @@ IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
}
void
IO::collect_input (BufferSet& outs, nframes_t nframes)
IO::collect_input (BufferSet& outs, nframes_t nframes, ChanCount offset)
{
assert(outs.available() >= n_inputs());
if (n_inputs() == ChanCount::ZERO)
if (n_inputs() == ChanCount::ZERO) {
return;
}
outs.set_count(n_inputs());
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
PortSet::iterator i = _inputs.begin(*t);
BufferSet::iterator o = outs.begin(*t);
PortSet::iterator e = _inputs.end (*t);
for (PortSet::iterator i = _inputs.begin(*t); i != e; ++i, ++o) {
cerr << (*t).to_string() << endl;
for (uint32_t off = 0; off < offset.get(*t); ++off, ++o) {
if (o == outs.end(*t)) {
continue;
}
}
for ( ; i != _inputs.end(*t); ++i, ++o) {
Buffer& b (i->get_buffer (nframes));
o->read_from (b, nframes);
}
}
}
@ -795,7 +801,8 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
{
Port* input_port = 0;
bool changed = false;
_configured_inputs = count;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
@ -867,14 +874,14 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
in = ChanCount::min (_input_maximum, in);
out = ChanCount::min (_output_maximum, out);
_configured_inputs = in;
_configured_outputs = out;
if (in == n_inputs() && out == n_outputs() && !clear) {
return 0;
}
_configured_inputs = in;
_configured_outputs = out;
{
BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm (io_lock);
@ -1034,6 +1041,8 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
Port* output_port = 0;
bool changed = false;
bool need_pan_reset = false;
_configured_outputs = count;
if (n_outputs() != count) {
need_pan_reset = true;
@ -1708,7 +1717,6 @@ IO::create_ports (const XMLNode& node)
set_deferred_state ();
PortsCreated();
return 0;
}

View File

@ -162,23 +162,7 @@ PortInsert::signal_latency() const
bool
PortInsert::configure_io (ChanCount in, ChanCount out)
{
/* do not allow configuration to be changed outside the range of
the last request config. or something like that.
*/
/* this is a bit odd:
the number of inputs we are required to handle corresponds
to the number of output ports we need.
the number of outputs we are required to have corresponds
to the number of input ports we need.
*/
/*_io->set_output_maximum (in);
_io->set_output_minimum (in);
_io->set_input_maximum (out);
_io->set_input_minimum (out);*/
/* for an insert, processor input corresponds to IO output, and vice versa */
if (_io->ensure_io (out, in, false, this) != 0) {
return false;
@ -187,21 +171,10 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
return Processor::configure_io (in, out);
}
ChanCount
PortInsert::output_streams() const
{
return _io->n_inputs ();
}
ChanCount
PortInsert::input_streams() const
{
return _io->n_outputs ();
}
bool
PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
out = in;
return true;
}

164
libs/ardour/return.cc Normal file
View File

@ -0,0 +1,164 @@
/*
Copyright (C) 2000 Paul Davis
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include "pbd/xml++.h"
#include "ardour/return.h"
#include "ardour/session.h"
#include "ardour/port.h"
#include "ardour/audio_port.h"
#include "ardour/buffer_set.h"
#include "ardour/meter.h"
#include "ardour/panner.h"
#include "ardour/io.h"
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
Return::Return (Session& s)
: IOProcessor (s, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
{
ProcessorCreated (this); /* EMIT SIGNAL */
}
Return::Return (Session& s, const XMLNode& node)
: IOProcessor (s, "return")
{
if (set_state (node)) {
throw failed_constructor();
}
ProcessorCreated (this); /* EMIT SIGNAL */
}
Return::~Return ()
{
GoingAway ();
}
XMLNode&
Return::get_state(void)
{
return state (true);
}
XMLNode&
Return::state(bool full)
{
XMLNode& node = IOProcessor::state(full);
char buf[32];
node.add_property ("type", "return");
snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot);
node.add_property ("bitslot", buf);
return node;
}
int
Return::set_state(const XMLNode& node)
{
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
const XMLProperty* prop;
if ((prop = node.property ("bitslot")) == 0) {
_bitslot = _session.next_return_id();
} else {
sscanf (prop->value().c_str(), "%" PRIu32, &_bitslot);
_session.mark_return_id (_bitslot);
}
const XMLNode* insert_node = &node;
/* Return has regular IO automation (gain, pan) */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "IOProcessor") {
insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) {
// _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
}
}
IOProcessor::set_state (*insert_node);
return 0;
}
void
Return::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
{
if (active()) {
_io->collect_input (bufs, nframes, _configured_input);
bufs.set_count(_configured_output);
}
}
bool
Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
out = in + _io->n_inputs();
return true;
}
bool
Return::configure_io (ChanCount in, ChanCount out)
{
if (out != in + _io->n_inputs()) {
return false;
}
// Ensure there are enough buffers (since we add some)
if (_session.get_scratch_buffers(in).count() < out) {
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::PortCountChanged(out);
}
Processor::configure_io(in, out);
return true;
}
/** Set up the XML description of a return so that its name is unique.
* @param state XML return state.
* @param session Session.
*/
void
Return::make_unique (XMLNode &state, Session &session)
{
uint32_t const bitslot = session.next_return_id() + 1;
char buf[32];
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
state.property("bitslot")->set_value (buf);
std::string const name = string_compose (_("return %1"), bitslot);
state.property("name")->set_value (name);
XMLNode* io = state.child ("IO");
if (io) {
io->property("name")->set_value (name);
}
}

View File

@ -36,7 +36,7 @@ using namespace ARDOUR;
using namespace PBD;
Send::Send (Session& s)
: IOProcessor (s, string_compose (_("send %1"), (bitslot = s.next_send_id()) + 1))
: IOProcessor (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1))
{
_metering = false;
ProcessorCreated (this); /* EMIT SIGNAL */
@ -71,7 +71,7 @@ Send::state(bool full)
XMLNode& node = IOProcessor::state(full);
char buf[32];
node.add_property ("type", "send");
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
snprintf (buf, sizeof (buf), "%" PRIu32, _bitslot);
node.add_property ("bitslot", buf);
return node;
@ -85,10 +85,10 @@ Send::set_state(const XMLNode& node)
const XMLProperty* prop;
if ((prop = node.property ("bitslot")) == 0) {
bitslot = _session.next_send_id();
_bitslot = _session.next_send_id();
} else {
sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
_session.mark_send_id (bitslot);
sscanf (prop->value().c_str(), "%" PRIu32, &_bitslot);
_session.mark_send_id (_bitslot);
}
const XMLNode* insert_node = &node;
@ -113,15 +113,7 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
{
if (active()) {
// we have to copy the input, because IO::deliver_output may alter the buffers
// in-place, which a send must never do.
BufferSet& sendbufs = _session.get_mix_buffers(bufs.count());
sendbufs.read_from(bufs, nframes);
assert(sendbufs.count() == bufs.count());
_io->deliver_output (sendbufs, start_frame, end_frame, nframes);
_io->deliver_output (bufs, start_frame, end_frame, nframes);
if (_metering) {
if (_io->effective_gain() == 0) {
@ -152,26 +144,27 @@ Send::set_metering (bool yn)
}
bool
Send::can_support_io_configuration (const ChanCount& in, ChanCount& out_is_ignored) const
Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{
if (_io->input_maximum() == ChanCount::INFINITE && _io->output_maximum() == ChanCount::INFINITE) {
if (_io->input_maximum() == ChanCount::INFINITE
&& _io->output_maximum() == ChanCount::INFINITE) {
/* not configured yet */
/* not configured yet, we can support anything */
return 1; /* we can support anything the first time we're asked */
out = in;
return true; /* we can support anything the first time we're asked */
} else {
/* the "input" config for a port insert corresponds to how
many output ports it will have.
*/
/* for a send, processor input corresponds to IO output */
if (_io->output_maximum() == in) {
return 1;
out = in;
return true;
}
}
return -1;
return false;
}
bool
@ -198,32 +191,6 @@ Send::configure_io (ChanCount in, ChanCount out)
return true;
}
ChanCount
Send::output_streams() const
{
// this method reflects the idea that from the perspective of the Route's ProcessorList,
// a send is just a passthrough. that doesn't match what the Send actually does with its
// data, but since what it does is invisible to the Route, it appears to be a passthrough.
return _configured_input;
}
ChanCount
Send::input_streams() const
{
return _configured_input;
}
void
Send::expect_inputs (const ChanCount& expected)
{
if (expected != expected_inputs) {
expected_inputs = expected;
_io->reset_panner ();
}
}
/** Set up the XML description of a send so that its name is unique.
* @param state XML send state.
* @param session Session.

View File

@ -72,6 +72,7 @@
#include "ardour/processor.h"
#include "ardour/recent_sessions.h"
#include "ardour/region_factory.h"
#include "ardour/return.h"
#include "ardour/route_group.h"
#include "ardour/send.h"
#include "ardour/session.h"
@ -3666,6 +3667,7 @@ void
Session::add_processor (Processor* processor)
{
Send* send;
Return* retrn;
PortInsert* port_insert;
PluginInsert* plugin_insert;
@ -3675,6 +3677,8 @@ Session::add_processor (Processor* processor)
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
_sends.insert (_sends.begin(), send);
} else if ((retrn = dynamic_cast<Return *> (processor)) != 0) {
_returns.insert (_returns.begin(), retrn);
} else {
fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/
@ -3689,6 +3693,7 @@ void
Session::remove_processor (Processor* processor)
{
Send* send;
Return* retrn;
PortInsert* port_insert;
PluginInsert* plugin_insert;
@ -3706,6 +3711,12 @@ Session::remove_processor (Processor* processor)
send_bitset[send->bit_slot()] = false;
_sends.erase (x);
}
} else if ((retrn = dynamic_cast<Return *> (processor)) != 0) {
list<Return*>::iterator x = find (_returns.begin(), _returns.end(), retrn);
if (x != _returns.end()) {
return_bitset[send->bit_slot()] = false;
_returns.erase (x);
}
} else {
fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
/*NOTREACHED*/
@ -3884,6 +3895,26 @@ Session::next_send_id ()
}
}
uint32_t
Session::next_return_id ()
{
/* this doesn't really loop forever. just think about it */
while (true) {
for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < return_bitset.size(); ++n) {
if (!return_bitset[n]) {
return_bitset[n] = true;
return n;
}
}
/* none available, so resize and try again */
return_bitset.resize (return_bitset.size() + 16, false);
}
}
void
Session::mark_send_id (uint32_t id)
{
@ -3896,6 +3927,18 @@ Session::mark_send_id (uint32_t id)
send_bitset[id] = true;
}
void
Session::mark_return_id (uint32_t id)
{
if (id >= return_bitset.size()) {
return_bitset.resize (id+16, false);
}
if (return_bitset[id]) {
warning << string_compose (_("return ID %1 appears to be in use already"), id) << endmsg;
}
return_bitset[id] = true;
}
void
Session::mark_insert_id (uint32_t id)
{

View File

@ -175,6 +175,7 @@ def build(bld):
region.cc
region_factory.cc
resampled_source.cc
return.cc
reverse.cc
route.cc
route_group.cc