summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/canvas-note-event.cc1
-rw-r--r--gtk2_ardour/midi_channel_selector.cc378
-rw-r--r--gtk2_ardour/midi_channel_selector.h60
-rw-r--r--gtk2_ardour/midi_region_view.cc66
-rw-r--r--gtk2_ardour/midi_region_view.h9
-rw-r--r--gtk2_ardour/midi_time_axis.cc96
-rw-r--r--gtk2_ardour/midi_time_axis.h12
-rw-r--r--gtk2_ardour/route_time_axis.cc4
-rw-r--r--libs/ardour/ardour/audio_buffer.h38
-rw-r--r--libs/ardour/ardour/audio_diskstream.h2
-rw-r--r--libs/ardour/ardour/diskstream.h3
-rw-r--r--libs/ardour/ardour/meter.h2
-rw-r--r--libs/ardour/ardour/midi_buffer.h65
-rw-r--r--libs/ardour/ardour/midi_diskstream.h25
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h57
-rw-r--r--libs/ardour/ardour/midi_track.h61
-rw-r--r--libs/ardour/ardour/route.h12
-rw-r--r--libs/ardour/ardour/track.h1
-rw-r--r--libs/ardour/audio_buffer.cc11
-rw-r--r--libs/ardour/audio_diskstream.cc48
-rw-r--r--libs/ardour/audio_track.cc128
-rw-r--r--libs/ardour/meter.cc12
-rw-r--r--libs/ardour/midi_diskstream.cc68
-rw-r--r--libs/ardour/midi_port.cc1
-rw-r--r--libs/ardour/midi_ring_buffer.cc17
-rw-r--r--libs/ardour/midi_track.cc206
-rw-r--r--libs/ardour/return.cc2
-rw-r--r--libs/ardour/route.cc147
-rw-r--r--libs/ardour/send.cc2
-rw-r--r--libs/ardour/session_process.cc2
-rw-r--r--libs/ardour/track.cc27
31 files changed, 1113 insertions, 450 deletions
diff --git a/gtk2_ardour/canvas-note-event.cc b/gtk2_ardour/canvas-note-event.cc
index 94b675b224..867e3cdf1c 100644
--- a/gtk2_ardour/canvas-note-event.cc
+++ b/gtk2_ardour/canvas-note-event.cc
@@ -22,6 +22,7 @@
#include "gtkmm2ext/keyboard.h"
#include "canvas-note-event.h"
+#include "midi_channel_selector.h"
#include "midi_region_view.h"
#include "public_editor.h"
#include "editing_syms.h"
diff --git a/gtk2_ardour/midi_channel_selector.cc b/gtk2_ardour/midi_channel_selector.cc
index 6770f0e60d..aea9d31f03 100644
--- a/gtk2_ardour/midi_channel_selector.cc
+++ b/gtk2_ardour/midi_channel_selector.cc
@@ -19,12 +19,25 @@
#include <algorithm>
#include <sstream>
+#include <gtkmm/separator.h>
+#include <gtkmm/box.h>
+#include <gtkmm/label.h>
+#include <gtkmm/togglebutton.h>
+#include <gtkmm/radiobutton.h>
+#include <gtkmm/table.h>
+
+#include "pbd/compose.h"
+
+#include "gtkmm2ext/gtk_ui.h"
+#include "gtkmm2ext/gui_thread.h"
+
+#include "ardour/midi_track.h"
#include "midi_channel_selector.h"
-#include "gtkmm/separator.h"
-#include "i18n.h"
#include "rgb_macros.h"
+#include "i18n.h"
+
using namespace std;
using namespace Gtk;
using namespace ARDOUR;
@@ -310,3 +323,364 @@ MidiMultipleChannelSelector::invert_selection(void)
mode_changed.emit(_channel_mode, get_selected_channels());
}
+/*-----------------------------------------*/
+
+MidiChannelSelectorWindow::MidiChannelSelectorWindow (boost::shared_ptr<MidiTrack> mt)
+ : ArdourWindow (string_compose (_("MIDI Channel Control for %1"), mt->name()))
+ , track (mt)
+{
+ build ();
+
+ playback_mask_changed ();
+ playback_mode_changed ();
+ capture_mask_changed ();
+ capture_mode_changed ();
+
+ track->PlaybackChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mask_changed, this), gui_context());
+ track->PlaybackChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::playback_mode_changed, this), gui_context());
+ track->CaptureChannelMaskChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mask_changed, this), gui_context());
+ track->CaptureChannelModeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&MidiChannelSelectorWindow::capture_mode_changed, this), gui_context());
+}
+
+MidiChannelSelectorWindow::~MidiChannelSelectorWindow()
+{
+}
+
+void
+MidiChannelSelectorWindow::build ()
+{
+ VBox* vpacker;
+ HBox* capture_mask;
+ HBox* capture_mask_controls;
+ HBox* playback_mask;
+ HBox* playback_mask_controls;
+ Button* b;
+ ToggleButton* tb;
+ Label* l;
+
+ vpacker = manage (new VBox);
+ vpacker->set_spacing (6);
+ vpacker->set_border_width (12);
+
+ l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Capture"))));
+ l->set_use_markup (true);
+ vpacker->pack_start (*l);
+
+ {
+ RadioButtonGroup group;
+
+ capture_all_button = manage (new RadioButton (group, "Record all channels"));
+ vpacker->pack_start (*capture_all_button);
+ capture_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), AllChannels));
+
+ capture_filter_button = manage (new RadioButton (group, "Record only selected channels"));
+ vpacker->pack_start (*capture_filter_button);
+ capture_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), FilterChannels));
+
+ capture_force_button = manage (new RadioButton (group, "Force all channels to a single fixed channel"));
+ vpacker->pack_start (*capture_force_button);
+ capture_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_mode_toggled), ForceChannel));
+ }
+
+ capture_mask = manage (new HBox);
+
+ for (uint32_t n = 0; n < 16; ++n) {
+ char buf[3];
+ snprintf (buf, sizeof (buf), "%d", n+1);
+ tb = manage (new ToggleButton (buf));
+ Gtkmm2ext::UI::instance()->set_tip (*tb, string_compose (_("Click to toggle recording of channel %1"), n+1));
+ capture_buttons.push_back (tb);
+ tb->set_name (X_("MidiChannelSelectorButton"));
+ capture_mask->pack_start (*tb);
+ tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::capture_channel_clicked), n));
+ }
+
+ vpacker->pack_start (*capture_mask);
+
+ capture_mask_controls = manage (new HBox);
+ capture_mask_controls->set_spacing (6);
+
+ b = manage (new Button (_("All")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable recording all channels"));
+ capture_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_capture_mask));
+ b = manage (new Button (_("None")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable recording all channels"));
+ capture_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_capture_mask));
+ b = manage (new Button (_("Invert")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert currently selected recording channels"));
+ capture_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_capture_mask));
+
+ vpacker->pack_start (*capture_mask_controls);
+
+ playback_mask = manage (new HBox);
+
+ l = manage (new Label (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Playback"))));
+ l->set_use_markup (true);
+ vpacker->pack_start (*l);
+
+ {
+ RadioButtonGroup group;
+
+ playback_all_button = manage (new RadioButton (group, "Playback all channels"));
+ vpacker->pack_start (*playback_all_button);
+ playback_all_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), AllChannels));
+
+ playback_filter_button = manage (new RadioButton (group, "Play only selected channels"));
+ vpacker->pack_start (*playback_filter_button);
+ playback_filter_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), FilterChannels));
+
+ playback_force_button = manage (new RadioButton (group, "Use a single fixed channel for all playback"));
+ vpacker->pack_start (*playback_force_button);
+ playback_force_button->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_mode_toggled), ForceChannel));
+ }
+
+ for (uint32_t n = 0; n < 16; ++n) {
+ char buf[3];
+ snprintf (buf, sizeof (buf), "%d", n+1);
+ tb = manage (new ToggleButton (buf));
+ tb->set_name (X_("MidiChannelSelectorButton"));
+ playback_buttons.push_back (tb);
+ playback_mask->pack_start (*tb);
+ tb->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiChannelSelectorWindow::playback_channel_clicked), n));
+ }
+
+ vpacker->pack_start (*playback_mask);
+
+ playback_mask_controls = manage (new HBox);
+ playback_mask_controls->set_spacing (6);
+
+ b = manage (new Button (_("All")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to enable playback of all channels"));
+ playback_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::fill_playback_mask));
+ b = manage (new Button (_("None")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to disable playback of all channels"));
+ playback_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::zero_playback_mask));
+ b = manage (new Button (_("Invert")));
+ Gtkmm2ext::UI::instance()->set_tip (*b, _("Click to invert current selected playback channels"));
+ playback_mask_controls->pack_start (*b);
+ b->signal_clicked().connect (sigc::mem_fun (*this, &MidiChannelSelectorWindow::invert_playback_mask));
+
+ vpacker->pack_start (*playback_mask_controls);
+
+ add (*vpacker);
+}
+
+void
+MidiChannelSelectorWindow::fill_playback_mask ()
+{
+ track->set_playback_channel_mask (0xffff);
+}
+
+void
+MidiChannelSelectorWindow::zero_playback_mask ()
+{
+ track->set_playback_channel_mask (0);
+}
+
+void
+MidiChannelSelectorWindow::invert_playback_mask ()
+{
+ track->set_playback_channel_mask (~track->get_playback_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::fill_capture_mask ()
+{
+ track->set_capture_channel_mask (0xffff);
+}
+
+void
+MidiChannelSelectorWindow::zero_capture_mask ()
+{
+ track->set_capture_channel_mask (0);
+}
+
+void
+MidiChannelSelectorWindow::invert_capture_mask ()
+{
+ track->set_capture_channel_mask (~track->get_capture_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::set_playback_selected_channels (uint16_t mask)
+{
+ for (uint16_t i = 0; i < 16; i++) {
+ playback_buttons[i]->set_active ((1<<i) & mask);
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_capture_selected_channels (uint16_t mask)
+{
+ for (uint16_t i = 0; i < 16; i++) {
+ capture_buttons[i]->set_active ((1<<i) & mask);
+ }
+}
+
+void
+MidiChannelSelectorWindow::playback_mask_changed ()
+{
+ set_playback_selected_channels (track->get_playback_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::capture_mask_changed ()
+{
+ set_capture_selected_channels (track->get_capture_channel_mask());
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_changed ()
+{
+ switch (track->get_playback_channel_mode()) {
+ case AllChannels:
+ playback_all_button->set_active ();
+ break;
+ case FilterChannels:
+ playback_filter_button->set_active ();
+ break;
+ case ForceChannel:
+ playback_force_button->set_active ();
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_changed ()
+{
+ switch (track->get_capture_channel_mode()) {
+ case AllChannels:
+ capture_all_button->set_active ();
+ break;
+ case FilterChannels:
+ capture_filter_button->set_active ();
+ break;
+ case ForceChannel:
+ capture_force_button->set_active ();
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::playback_channel_clicked (uint16_t n)
+{
+ if (playback_buttons[n]->get_active()) {
+ track->set_playback_channel_mask (track->get_playback_channel_mask() | (1<<n));
+ } else {
+ track->set_playback_channel_mask (track->get_playback_channel_mask() & ~(1<<n));
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_channel_clicked (uint16_t n)
+{
+ if (capture_buttons[n]->get_active()) {
+ track->set_capture_channel_mask (track->get_capture_channel_mask() | (1<<n));
+ } else {
+ track->set_capture_channel_mask (track->get_capture_channel_mask() & ~(1<<n));
+ }
+}
+
+void
+MidiChannelSelectorWindow::capture_mode_toggled (ChannelMode mode)
+{
+ /* this is called twice for every radio button change. the first time
+ is for the button/mode that has been turned off, and the second is for the
+ button/mode that has been turned on.
+
+ so we have to check the button state to know what to do.
+ */
+
+ switch (mode) {
+ case AllChannels:
+ if (!capture_all_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (AllChannels, track->get_capture_channel_mask());
+ break;
+ case FilterChannels:
+ if (!capture_filter_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (FilterChannels, track->get_capture_channel_mask());
+ break;
+ case ForceChannel:
+ if (!capture_force_button->get_active()) {
+ return;
+ }
+ track->set_capture_channel_mode (ForceChannel, track->get_capture_channel_mask());
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::playback_mode_toggled (ChannelMode mode)
+{
+ /* this is called twice for every radio button change. the first time
+ is for the button/mode that has been turned off, and the second is for the
+ button/mode that has been turned on.
+
+ so we have to check the button state to know what to do.
+ */
+
+ switch (mode) {
+ case AllChannels:
+ if (!playback_all_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (AllChannels, track->get_playback_channel_mask());
+ break;
+ case FilterChannels:
+ if (!playback_filter_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (FilterChannels, track->get_playback_channel_mask());
+ break;
+ case ForceChannel:
+ if (!playback_force_button->get_active()) {
+ return;
+ }
+ track->set_playback_channel_mode (ForceChannel, track->get_playback_channel_mask());
+ break;
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_channel_colors (const uint32_t new_channel_colors[16])
+{
+ for (uint32_t n = 0; n < 16; ++n) {
+
+ char color_normal[8];
+ char color_active[8];
+
+ snprintf(color_normal, 8, "#%x", UINT_INTERPOLATE(new_channel_colors[n], 0x000000ff, 0.6));
+ snprintf(color_active, 8, "#%x", new_channel_colors[n]);
+
+ playback_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+ playback_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+
+ capture_buttons[n]->modify_bg(STATE_NORMAL, Gdk::Color(color_normal));
+ capture_buttons[n]->modify_bg(STATE_ACTIVE, Gdk::Color(color_active));
+ }
+}
+
+void
+MidiChannelSelectorWindow::set_default_channel_color()
+{
+ for (uint32_t n = 0; n < 16; ++n) {
+ playback_buttons[n]->unset_fg (STATE_NORMAL);
+ playback_buttons[n]->unset_bg (STATE_NORMAL);
+ playback_buttons[n]->unset_fg (STATE_ACTIVE);
+ playback_buttons[n]->unset_bg (STATE_ACTIVE);
+
+ capture_buttons[n]->unset_fg (STATE_NORMAL);
+ capture_buttons[n]->unset_bg (STATE_NORMAL);
+ capture_buttons[n]->unset_fg (STATE_ACTIVE);
+ capture_buttons[n]->unset_bg (STATE_ACTIVE);
+ }
+}
diff --git a/gtk2_ardour/midi_channel_selector.h b/gtk2_ardour/midi_channel_selector.h
index 5764a8d813..f6d3206c31 100644
--- a/gtk2_ardour/midi_channel_selector.h
+++ b/gtk2_ardour/midi_channel_selector.h
@@ -26,11 +26,18 @@
#include "gtkmm/table.h"
#include "gtkmm/button.h"
+#include "gtkmm/radiobutton.h"
#include "gtkmm/label.h"
#include "gtkmm2ext/stateful_button.h"
#include "ardour/types.h"
+#include "ardour_window.h"
+
+namespace ARDOUR {
+ class MidiTrack;
+}
+
class MidiChannelSelector : public Gtk::Table
{
public:
@@ -108,4 +115,57 @@ protected:
Gtk::ToggleButton _force_channel;
};
+class MidiChannelSelectorWindow : public ArdourWindow, public PBD::ScopedConnectionList
+{
+ public:
+ MidiChannelSelectorWindow (boost::shared_ptr<ARDOUR::MidiTrack>);
+ ~MidiChannelSelectorWindow ();
+
+ void set_channel_colors (const uint32_t new_channel_colors[16]);
+ void set_default_channel_color();
+
+ private:
+ boost::shared_ptr<ARDOUR::MidiTrack> track;
+ std::vector<Gtk::ToggleButton*> playback_buttons;
+ std::vector<Gtk::ToggleButton*> capture_buttons;
+
+ Gtk::ToggleButton* playback_all_button;
+ Gtk::ToggleButton* playback_filter_button;
+ Gtk::ToggleButton* playback_force_button;
+ Gtk::ToggleButton* capture_all_button;
+ Gtk::ToggleButton* capture_filter_button;
+ Gtk::ToggleButton* capture_force_button;
+
+ void build();
+ void set_capture_selected_channels (uint16_t);
+ void set_playback_selected_channels (uint16_t);
+
+ void fill_playback_mask ();
+ void zero_playback_mask ();
+ void invert_playback_mask ();
+
+ void fill_capture_mask ();
+ void zero_capture_mask ();
+ void invert_capture_mask ();
+
+ void playback_mask_changed ();
+ void capture_mask_changed ();
+ void playback_mode_changed ();
+ void capture_mode_changed ();
+
+ void playback_channel_clicked (uint16_t);
+ void capture_channel_clicked (uint16_t);
+
+ void playback_all_clicked();
+ void playback_none_clicked();
+ void playback_invert_clicked();
+
+ void capture_all_clicked();
+ void capture_none_clicked();
+ void capture_invert_clicked();
+
+ void capture_mode_toggled (ARDOUR::ChannelMode);
+ void playback_mode_toggled (ARDOUR::ChannelMode);
+};
+
#endif /*__ardour_ui_midi_channel_selector_h__*/
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 81e5cf23e9..d6b6935e11 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -66,6 +66,7 @@
#include "mouse_cursors.h"
#include "note_player.h"
#include "public_editor.h"
+#include "route_time_axis.h"
#include "rgb_macros.h"
#include "selection.h"
#include "simpleline.h"
@@ -89,7 +90,6 @@ PBD::Signal1<void, MidiRegionView *> MidiRegionView::SelectionCleared;
MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color const & basic_color)
: RegionView (parent, tv, r, spu, basic_color)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -116,13 +116,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
-
- MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
- if (time_axis) {
- _last_channel_mode = time_axis->channel_selector().get_channel_mode();
- _last_channel_selection = time_axis->channel_selector().get_selected_channels();
- }
-
Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&MidiRegionView::parameter_changed, this, _1), gui_context());
connect_to_diskstream ();
@@ -133,7 +126,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color,
TimeAxisViewItem::Visibility visibility)
: RegionView (parent, tv, r, spu, basic_color, false, visibility)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -160,12 +152,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
_note_group->raise_to_top();
PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
- MidiTimeAxisView *time_axis = dynamic_cast<MidiTimeAxisView *>(&tv);
- if (time_axis) {
- _last_channel_mode = time_axis->channel_selector().get_channel_mode();
- _last_channel_selection = time_axis->channel_selector().get_selected_channels();
- }
-
connect_to_diskstream ();
SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), boost::bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
@@ -184,7 +170,6 @@ MidiRegionView::parameter_changed (std::string const & p)
MidiRegionView::MidiRegionView (const MidiRegionView& other)
: sigc::trackable(other)
, RegionView (other)
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -219,7 +204,6 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<MidiRegion> region)
: RegionView (other, boost::shared_ptr<Region> (region))
- , _last_channel_selection(0xFFFF)
, _current_range_min(0)
, _current_range_max(0)
, _active_notes(0)
@@ -293,8 +277,10 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
group->raise_to_top();
group->signal_event().connect (sigc::mem_fun (this, &MidiRegionView::canvas_event), false);
- midi_view()->signal_channel_mode_changed().connect(
- sigc::mem_fun(this, &MidiRegionView::midi_channel_mode_changed));
+
+ midi_view()->midi_track()->PlaybackChannelModeChanged.connect (_channel_mode_changed_connection, invalidator (*this),
+ boost::bind (&MidiRegionView::midi_channel_mode_changed, this),
+ gui_context ());
instrument_info().Changed.connect (_instrument_changed_connection, invalidator (*this),
boost::bind (&MidiRegionView::instrument_settings_changed, this), gui_context());
@@ -1214,7 +1200,7 @@ void
MidiRegionView::display_patch_changes ()
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+ uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
for (uint8_t i = 0; i < 16; ++i) {
display_patch_changes_on_channel (i, chn_mask & (1 << i));
@@ -1673,7 +1659,7 @@ MidiRegionView::update_note (CanvasNote* ev, bool update_ghost_regions)
/* outline all edges */
ev->property_outline_what() = (guint32) 0xF;
}
-
+
if (update_ghost_regions) {
for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
@@ -1751,7 +1737,7 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note, bool visible)
event->show_velocity();
}
- event->on_channel_selection_change(_last_channel_selection);
+ event->on_channel_selection_change (get_selected_channels());
_events.push_back(event);
if (visible) {
@@ -3220,20 +3206,21 @@ MidiRegionView::set_frame_color()
}
void
-MidiRegionView::midi_channel_mode_changed(ChannelMode mode, uint16_t mask)
+MidiRegionView::midi_channel_mode_changed ()
{
+ MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ uint16_t mask = mtv->midi_track()->get_playback_channel_mask();
+ ChannelMode mode = mtv->midi_track()->get_playback_channel_mode ();
+
if (mode == ForceChannel) {
mask = 0xFFFF; // Show all notes as active (below)
}
// Update notes for selection
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
- (*i)->on_channel_selection_change(mask);
+ (*i)->on_channel_selection_change (mask);
}
- _last_channel_selection = mask;
- _last_channel_mode = mode;
-
_patch_changes.clear ();
display_patch_changes ();
}
@@ -3399,7 +3386,7 @@ MidiRegionView::goto_next_note (bool add_to_selection)
time_sort_events ();
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+ uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask();
for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
if ((*i)->selected()) {
@@ -3436,7 +3423,7 @@ MidiRegionView::goto_previous_note (bool add_to_selection)
time_sort_events ();
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+ uint16_t const channel_mask = mtv->midi_track()->get_playback_channel_mask ();
for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
if ((*i)->selected()) {
@@ -3562,7 +3549,7 @@ MidiRegionView::maybe_select_by_position (GdkEventButton* ev, double /*x*/, doub
Events e;
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
- uint16_t chn_mask = mtv->channel_selector().get_selected_channels();
+ uint16_t chn_mask = mtv->midi_track()->get_playback_channel_mask();
if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
get_events (e, Evoral::Sequence<Evoral::MusicalTime>::PitchGreaterThanOrEqual, (uint8_t) floor (note), chn_mask);
@@ -3687,8 +3674,8 @@ MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false);
if (ev.is_channel_event()) {
- if (_last_channel_mode == FilterChannels) {
- if (((uint16_t(1) << ev.channel()) & _last_channel_selection) == 0) {
+ if (get_channel_mode() == FilterChannels) {
+ if (((uint16_t(1) << ev.channel()) & get_selected_channels()) == 0) {
continue;
}
}
@@ -3883,3 +3870,18 @@ MidiRegionView::note_button_release ()
delete _note_player;
_note_player = 0;
}
+
+ChannelMode
+MidiRegionView::get_channel_mode () const
+{
+ RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+ return rtav->midi_track()->get_playback_channel_mode();
+}
+
+uint16_t
+MidiRegionView::get_selected_channels () const
+{
+ RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (&trackview);
+ return rtav->midi_track()->get_playback_channel_mask();
+}
+
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 689e0ab2d0..5f374da55c 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -355,7 +355,8 @@ private:
bool canvas_event(GdkEvent* ev);
bool note_canvas_event(GdkEvent* ev);
- void midi_channel_mode_changed(ARDOUR::ChannelMode mode, uint16_t mask);
+ void midi_channel_mode_changed ();
+ PBD::ScopedConnection _channel_mode_changed_connection;
void instrument_settings_changed ();
PBD::ScopedConnection _instrument_changed_connection;
@@ -377,9 +378,6 @@ private:
void show_verbose_cursor (std::string const &, double, double) const;
void show_verbose_cursor (boost::shared_ptr<NoteType>) const;
- ARDOUR::ChannelMode _last_channel_mode;
- uint16_t _last_channel_selection;
-
uint8_t _current_range_min;
uint8_t _current_range_max;
@@ -480,6 +478,9 @@ private:
Gdk::Cursor* pre_press_cursor;
NotePlayer* _note_player;
+
+ ARDOUR::ChannelMode get_channel_mode() const;
+ uint16_t get_selected_channels () const;
};
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 9fe3a77450..6c284fa0a0 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -66,6 +66,7 @@
#include "ghostregion.h"
#include "gui_thread.h"
#include "keyboard.h"
+#include "midi_channel_selector.h"
#include "midi_scroomer.h"
#include "midi_streamview.h"
#include "midi_region_view.h"
@@ -94,8 +95,8 @@ using namespace Gtkmm2ext;
using namespace Editing;
// Minimum height at which a control is displayed
-static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
-static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
+static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 130;
+static const uint32_t KEYBOARD_MIN_HEIGHT = 130;
MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
: AxisView(sess) // virtually inherited
@@ -110,6 +111,7 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& can
, _meter_color_mode_item(0)
, _channel_color_mode_item(0)
, _track_color_mode_item(0)
+ , _channel_selector (0)
, _step_edit_item (0)
, controller_menu (0)
, _step_editor (0)
@@ -246,28 +248,19 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
_midi_controls_box.set_border_width (10);
if (!patch_manager.all_models().empty()) {
- _channel_selector.set_border_width(2);
- _channel_selector.show_all ();
-
- _midi_controls_box.resize(3, 2);
- _midi_controls_box.attach(_channel_selector, 0, 2, 0, 1);
-
- _midi_controls_box.attach(*manage(new HSeparator()), 0, 2, 1, 2);
+ _midi_controls_box.resize(2, 2);
_midnam_model_selector.set_size_request(22, 30);
_midnam_model_selector.set_border_width(2);
_midnam_model_selector.show ();
- _midi_controls_box.attach(_midnam_model_selector, 0, 1, 2, 3);
+ _midi_controls_box.attach(_midnam_model_selector, 0, 1, 0, 1);
_midnam_custom_device_mode_selector.set_size_request(10, 30);
_midnam_custom_device_mode_selector.set_border_width(2);
_midnam_custom_device_mode_selector.show ();
- _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 3, 4);
- } else {
- _midi_controls_box.attach(_channel_selector, 0, 1, 0, 1);
- _channel_selector.show_all ();
- }
+ _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 1, 2);
+ }
model_changed();
custom_device_mode_changed();
@@ -279,19 +272,11 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
controls_vbox.pack_start(_midi_controls_box, false, false);
- // restore channel selector settings
- _channel_selector.set_channel_mode(midi_track()->get_channel_mode(),
- midi_track()->get_channel_mask());
- _channel_selector.mode_changed.connect(
- sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
- _channel_selector.mode_changed.connect(
- sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
-
const string color_mode = gui_property ("color-mode");
if (!color_mode.empty()) {
_color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
- if (_color_mode == ChannelColors) {
- _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ if (_channel_selector && _color_mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
}
}
@@ -334,6 +319,8 @@ MidiTimeAxisView::first_idle ()
MidiTimeAxisView::~MidiTimeAxisView ()
{
+ delete _channel_selector;
+
delete _piano_roll_header;
_piano_roll_header = 0;
@@ -468,11 +455,36 @@ MidiTimeAxisView::append_extra_display_menu_items ()
items.push_back (MenuElem (_("Note Range"), *range_menu));
items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
+ items.push_back (MenuElem (_("Channel Selector"),
+ sigc::mem_fun(*this, &MidiTimeAxisView::toggle_channel_selector)));
+ color_mode_menu = build_color_mode_menu();
+ if (color_mode_menu) {
+ items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
+ }
+
items.push_back (SeparatorElem ());
}
void
+MidiTimeAxisView::toggle_channel_selector ()
+{
+ if (!_channel_selector) {
+ _channel_selector = new MidiChannelSelectorWindow (midi_track());
+
+ if (_color_mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ } else {
+ _channel_selector->set_default_channel_color ();
+ }
+
+ _channel_selector->show_all ();
+ } else {
+ _channel_selector->cycle_visibility ();
+ }
+}
+
+void
MidiTimeAxisView::build_automation_action_menu (bool for_selection)
{
using namespace Menu_Helpers;
@@ -493,7 +505,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
MenuList& automation_items = automation_action_menu->items();
- uint16_t selected_channels = _channel_selector.get_selected_channels();
+ uint16_t selected_channels = midi_track()->get_playback_channel_mask();
if (selected_channels != 0) {
@@ -537,7 +549,7 @@ MidiTimeAxisView::build_automation_action_menu (bool for_selection)
void
MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
{
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
@@ -564,7 +576,7 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
structure if there is more than 1 selected.
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
int chn_cnt = 0;
for (uint8_t chn = 0; chn < 16; chn++) {
@@ -665,7 +677,7 @@ MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl
{
using namespace Menu_Helpers;
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
for (uint8_t chn = 0; chn < 16; chn++) {
if (selected_channels & (0x0001 << chn)) {
@@ -706,7 +718,7 @@ MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_
{
using namespace Menu_Helpers;
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
Menu* chn_menu = manage (new Menu);
MenuList& chn_items (chn_menu->items());
@@ -804,7 +816,7 @@ MidiTimeAxisView::build_controller_menu ()
combination covering the currently selected channels for this track
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
/* count the number of selected channels because we will build a different menu
structure if there is more than 1 selected.
@@ -982,10 +994,12 @@ MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bo
return;
}
- if (mode == ChannelColors) {
- _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
- } else {
- _channel_selector.set_default_channel_color();
+ if (_channel_selector) {
+ if (mode == ChannelColors) {
+ _channel_selector->set_channel_colors(CanvasNoteEvent::midi_channel_colors);
+ } else {
+ _channel_selector->set_default_channel_color();
+ }
}
_color_mode = mode;
@@ -1168,7 +1182,7 @@ MidiTimeAxisView::set_note_selection (uint8_t note)
return;
}
- uint16_t chn_mask = _channel_selector.get_selected_channels();
+ uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1188,7 +1202,7 @@ MidiTimeAxisView::add_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1208,7 +1222,7 @@ MidiTimeAxisView::extend_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1228,7 +1242,7 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
return;
}
- const uint16_t chn_mask = _channel_selector.get_selected_channels();
+ const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
@@ -1272,7 +1286,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
the right ones.
*/
- const uint16_t selected_channels = _channel_selector.get_selected_channels();
+ const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
bool changed = false;
no_redraw = true;
@@ -1392,7 +1406,7 @@ MidiTimeAxisView::stop_step_editing ()
uint8_t
MidiTimeAxisView::get_channel_for_add () const
{
- uint16_t const chn_mask = _channel_selector.get_selected_channels ();
+ uint16_t const chn_mask = midi_track()->get_playback_channel_mask();
int chn_cnt = 0;
uint8_t channel = 0;
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 1f179baca6..e5fccd8c2f 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -39,7 +39,6 @@
#include "route_time_axis.h"
#include "canvas.h"
#include "midi_streamview.h"
-#include "midi_channel_selector.h"
namespace MIDI {
namespace Name {
@@ -62,6 +61,7 @@ class MidiScroomer;
class PianoRollHeader;
class StepEntry;
class StepEditor;
+class MidiChannelSelectorWindow;
class MidiTimeAxisView : public RouteTimeAxisView
{
@@ -92,12 +92,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
void update_range();
- sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed() {
- return _channel_selector.mode_changed;
- }
-
- const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
-
Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
StepEditor* step_editor() { return _step_editor; }
@@ -141,7 +135,7 @@ class MidiTimeAxisView : public RouteTimeAxisView
Gtk::RadioMenuItem* _channel_color_mode_item;
Gtk::RadioMenuItem* _track_color_mode_item;
Gtk::Table _midi_controls_box;
- MidiMultipleChannelSelector _channel_selector;
+ MidiChannelSelectorWindow* _channel_selector;
Gtk::ComboBoxText _midnam_model_selector;
Gtk::ComboBoxText _midnam_custom_device_mode_selector;
@@ -157,6 +151,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
void add_single_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
void add_multi_channel_controller_item (Gtk::Menu_Helpers::MenuList& ctl_items, int ctl, const std::string& name);
void build_controller_menu ();
+ void toggle_channel_selector ();
+ void channel_selector_hidden ();
void set_channel_mode (ARDOUR::ChannelMode, uint16_t);
void set_note_selection (uint8_t note);
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 041cbb59e1..784203bf6f 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -639,10 +639,6 @@ RouteTimeAxisView::build_display_menu ()
items.push_back (MenuElem (_("Mode"), *mode_menu));
}
- color_mode_menu = build_color_mode_menu();
- if (color_mode_menu) {
- items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
- }
items.push_back (SeparatorElem());
diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h
index 5c04a7f43a..42aba607f9 100644
--- a/libs/ardour/ardour/audio_buffer.h
+++ b/libs/ardour/ardour/audio_buffer.h
@@ -46,6 +46,28 @@ public:
}
/** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
+ void read_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(src != 0);
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+ memcpy(_data + dst_offset, src + src_offset, sizeof(Sample) * len);
+ _silent = false;
+ _written = true;
+ }
+
+ void read_from_with_gain (const Sample* src, framecnt_t len, gain_t gain, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(src != 0);
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+ src += src_offset;
+ for (framecnt_t n = 0; n < len; ++n) {
+ _data[dst_offset+n] = src[n] * gain;
+ }
+ _silent = false;
+ _written = true;
+ }
+
+ /** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
void read_from (const Buffer& src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
assert(&src != this);
assert(_capacity > 0);
@@ -82,6 +104,20 @@ public:
_written = true;
}
+ /** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @a dst_offset */
+ void accumulate_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+
+ Sample* const dst_raw = _data + dst_offset;
+ const Sample* const src_raw = src + src_offset;
+
+ mix_buffers_no_gain(dst_raw, src_raw, len);
+
+ _silent = false;
+ _written = true;
+ }
+
/** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @dst_offset
* scaling by @a gain_coeff */
void accumulate_with_gain_from (const AudioBuffer& src, framecnt_t len, gain_t gain_coeff, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
@@ -171,6 +207,8 @@ public:
return _data + offset;
}
+ bool check_silence (pframes_t, pframes_t&) const;
+
void prepare () { _written = false; _silent = false; }
bool written() const { return _written; }
void set_written(bool w) { _written = w; }
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 455e89392b..cbc6b93fe0 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -151,7 +151,7 @@ class AudioDiskstream : public Diskstream
protected:
friend class AudioTrack;
- int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+ int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal);
bool commit (framecnt_t);
private:
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 81eb588d1a..85ca03caff 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -49,6 +49,7 @@ class Source;
class Session;
class Track;
class Location;
+class BufferSet;
/** Parent class for classes which can stream data to and from disk.
* These are used by Tracks to get playback and put recorded data.
@@ -191,7 +192,7 @@ class Diskstream : public SessionObject, public PublicDiskstream
protected:
friend class Track;
- virtual int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &) = 0;
+ virtual int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal) = 0;
virtual bool commit (framecnt_t) = 0;
//private:
diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h
index 773b04f386..eea240f821 100644
--- a/libs/ardour/ardour/meter.h
+++ b/libs/ardour/ardour/meter.h
@@ -44,7 +44,7 @@ class Metering {
*/
class PeakMeter : public Processor {
public:
- PeakMeter(Session& s) : Processor(s, "Meter") {}
+ PeakMeter(Session& s, const std::string& name);
void meter();
void reset ();
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 183ca7eea9..5ef5e4c845 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -55,38 +55,50 @@ public:
template<typename BufferType, typename EventType>
class iterator_base {
public:
- iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o) : buffer(b), offset(o) {}
+ iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o)
+ : buffer(&b), offset(o) {}
+ iterator_base<BufferType, EventType>(const iterator_base<BufferType,EventType>& o)
+ : buffer (o.buffer), offset(o.offset) {}
+
+ inline iterator_base<BufferType,EventType> operator= (const iterator_base<BufferType,EventType>& o) {
+ if (&o != this) {
+ buffer = o.buffer;
+ offset = o.offset;
+ }
+ return *this;
+ }
+
inline EventType operator*() const {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
- *((TimeType*)(buffer._data + offset)),
+ *((TimeType*)(buffer->_data + offset)),
event_size, ev_start);
}
inline EventType operator*() {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
- *((TimeType*)(buffer._data + offset)),
+ *((TimeType*)(buffer->_data + offset)),
event_size, ev_start);
}
inline iterator_base<BufferType, EventType>& operator++() {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
offset += sizeof(TimeType) + event_size;
return *this;
}
inline bool operator!=(const iterator_base<BufferType, EventType>& other) const {
- return (&buffer != &other.buffer) || (offset != other.offset);
+ return (buffer != other.buffer) || (offset != other.offset);
}
inline bool operator==(const iterator_base<BufferType, EventType>& other) const {
- return (&buffer == &other.buffer) && (offset == other.offset);
+ return (buffer == other.buffer) && (offset == other.offset);
}
- BufferType& buffer;
+ BufferType* buffer;
size_t offset;
};
@@ -99,6 +111,41 @@ public:
const_iterator begin() const { return const_iterator(*this, 0); }
const_iterator end() const { return const_iterator(*this, _size); }
+ iterator erase(const iterator& i) {
+ assert (i.buffer == this);
+ uint8_t* ev_start = _data + i.offset + sizeof (TimeType);
+ int event_size = Evoral::midi_event_size (ev_start);
+
+ if (event_size < 0) {
+ /* unknown size, sysex: return end() */
+ return end();
+ }
+
+ size_t total_data_deleted = sizeof(TimeType) + event_size;
+
+ if (i.offset + total_data_deleted >= _size) {
+ _size = 0;
+ return end();
+ }
+
+ /* we need to avoid the temporary malloc that memmove would do,
+ so copy by hand. remember: this is small amounts of data ...
+ */
+ size_t a, b;
+ for (a = i.offset, b = i.offset + total_data_deleted; b < _size; ++b, ++a) {
+ _data[a] = _data[b];
+ }
+
+ _size -= total_data_deleted;
+
+ /* all subsequent iterators are now invalid, and the one we
+ * return should refer to the event we copied, which was after
+ * the one we just erased.
+ */
+
+ return iterator (*this, i.offset);
+ }
+
uint8_t* data() const { return _data; }
/**
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 309c275434..d6ad71863a 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -89,29 +89,6 @@ class MidiDiskstream : public Diskstream
void set_note_mode (NoteMode m);
- uint16_t get_channel_mask() {
- uint16_t playback_mask = _playback_buf->get_channel_mask();
-#ifndef NDEBUG
- uint16_t capture_mask = _capture_buf->get_channel_mask();
- assert(playback_mask == capture_mask);
-#endif
- return playback_mask;
- }
-
- void set_channel_mode(ChannelMode mode, uint16_t mask) {
- _playback_buf->set_channel_mode(mode, mask);
- _capture_buf->set_channel_mode(mode, mask);
- }
-
- ChannelMode get_channel_mode() {
- ChannelMode playback_mode = _playback_buf->get_channel_mode();
-#ifndef NDEBUG
- ChannelMode capture_mode = _capture_buf->get_channel_mode();
- assert(playback_mode == capture_mode);
-#endif
- return playback_mode;
- }
-
/** Emitted when some MIDI data has been received for recording.
* Parameter is the source that it is destined for.
* A caller can get a copy of the data with get_gui_feed_buffer ()
@@ -147,7 +124,7 @@ class MidiDiskstream : public Diskstream
protected:
friend class MidiTrack;
- int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+ int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
bool commit (framecnt_t nframes);
static framecnt_t midi_readahead;
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index b3e532bdbe..d5c9947b9a 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -45,38 +45,16 @@ public:
/** @param size Size in bytes.
*/
MidiRingBuffer(size_t size)
- : Evoral::EventRingBuffer<T>(size)
- , _channel_mask(0x0000FFFF)
- {}
+ : Evoral::EventRingBuffer<T>(size) {}
inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
inline bool read_contents(uint32_t size, uint8_t* buf);
size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false);
- inline uint32_t write(T time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
void dump(std::ostream& dst);
void flush (framepos_t start, framepos_t end);
- /** Set the channel filtering mode.
- * @param mask If mode is FilterChannels, each bit represents a midi channel:
- * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
- * process events whose channel bit is 1.
- * If mode is ForceChannel, mask is simply a channel number which all events will
- * be forced to while reading.
- */
- void set_channel_mode(ChannelMode mode, uint16_t mask) {
- g_atomic_int_set(&_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
- }
-
- ChannelMode get_channel_mode() const {
- return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16);
- }
-
- uint16_t get_channel_mask() const {
- return g_atomic_int_get(&_channel_mask) & 0x0000FFFF;
- }
-
void reset_tracker ();
void loop_resolve (MidiBuffer& dst, framepos_t);
@@ -99,7 +77,6 @@ protected:
}
private:
- volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
MidiStateTracker _tracker;
};
@@ -137,38 +114,6 @@ MidiRingBuffer<T>::read_contents(uint32_t size, uint8_t* buf)
return PBD::RingBufferNPT<uint8_t>::read(buf, size) == size;
}
-template<typename T>
-inline uint32_t
-MidiRingBuffer<T>::write(T time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
-{
- assert(size > 0);
- uint8_t status = buf[0];
-
- // Ignore event if it doesn't match channel filter
- if (is_channel_event(status)) {
- ChannelMode mode = get_channel_mode();
- if (mode == FilterChannels) {
- const uint8_t channel = status & 0x0F;
- if (!(get_channel_mask() & (1L << channel))) {
- return 0;
- }
- } else if (mode == ForceChannel) {
- uint8_t* tmpbuf = (uint8_t*) malloc(size);
- assert(tmpbuf);
- memcpy(tmpbuf, buf, size);
-
- tmpbuf[0] = (tmpbuf[0] & 0xF0) | (get_channel_mask() & 0x0F);
-
- uint32_t bytes_written = Evoral::EventRingBuffer<T>::write(time, type, size, tmpbuf);
- free(tmpbuf);
- return bytes_written;
- }
- }
-
- return Evoral::EventRingBuffer<T>::write(time, type, size, buf);
-}
-
-
} // namespace ARDOUR
#endif // __ardour_midi_ring_buffer_h__
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 8134f5312a..be209bc0f6 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -102,11 +102,39 @@ public:
PBD::Signal1<void,bool> StepEditStatusChange;
boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
- void set_channel_mode (ChannelMode, uint16_t);
- ChannelMode get_channel_mode ();
- uint16_t get_channel_mask ();
+
+ /** Channel filtering mode.
+ * @param mask If mode is FilterChannels, each bit represents a midi channel:
+ * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
+ * process events whose channel bit is 1.
+ * If mode is ForceChannel, mask is simply a channel number which all events will
+ * be forced to while reading.
+ */
+ void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
+ void set_playback_channel_mode (ChannelMode mode, uint16_t mask);
+ void set_playback_channel_mask (uint16_t mask);
+ void set_capture_channel_mask (uint16_t mask);
+
+ ChannelMode get_playback_channel_mode() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16);
+ }
+ uint16_t get_playback_channel_mask() const {
+ return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff;
+ }
+ ChannelMode get_capture_channel_mode() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_capture_channel_mask) & 0xffff0000) >> 16);
+ }
+ uint16_t get_capture_channel_mask() const {
+ return g_atomic_int_get(&_capture_channel_mask) & 0x0000ffff;
+ }
+
boost::shared_ptr<MidiPlaylist> midi_playlist ();
+ PBD::Signal0<void> PlaybackChannelMaskChanged;
+ PBD::Signal0<void> PlaybackChannelModeChanged;
+ PBD::Signal0<void> CaptureChannelMaskChanged;
+ PBD::Signal0<void> CaptureChannelModeChanged;
+
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
@@ -123,6 +151,13 @@ protected:
void act_on_mute ();
private:
+ MidiRingBuffer<framepos_t> _immediate_events;
+ MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
+ NoteMode _note_mode;
+ bool _step_editing;
+ bool _input_active;
+ uint32_t _playback_channel_mask; // 16 bits mode, 16 bits mask
+ uint32_t _capture_channel_mask; // 16 bits mode, 16 bits mask
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
@@ -133,11 +168,6 @@ private:
void set_state_part_two ();
void set_state_part_three ();
- MidiRingBuffer<framepos_t> _immediate_events;
- MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
- NoteMode _note_mode;
- bool _step_editing;
- bool _input_active;
int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool state_changing);
void push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes);
@@ -147,6 +177,21 @@ private:
void track_input_active (IOChange, void*);
void map_input_active (bool);
+
+ void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask);
+
+ void _set_playback_channel_mode(ChannelMode mode, uint16_t mask) {
+ g_atomic_int_set(&_playback_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+ }
+ void _set_playback_channel_mask (uint16_t mask) {
+ g_atomic_int_set(&_playback_channel_mask, (uint32_t(get_playback_channel_mode()) << 16) | uint32_t(mask));
+ }
+ void _set_capture_channel_mode(ChannelMode mode, uint16_t mask) {
+ g_atomic_int_set(&_capture_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+ }
+ void _set_capture_channel_mask (uint16_t mask) {
+ g_atomic_int_set(&_capture_channel_mask, (uint32_t(get_capture_channel_mode()) << 16) | uint32_t(mask));
+ }
};
} /* namespace ARDOUR*/
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 1a42999e6b..c25b6be950 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -436,6 +436,12 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
bool has_external_redirects() const;
+ /* can only be executed by a route for which is_monitor() is true
+ (i.e. the monitor out)
+ */
+ void monitor_run (framepos_t start_frame, framepos_t end_frame,
+ pframes_t nframes, int declick);
+
protected:
friend class Session;
@@ -448,11 +454,13 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
protected:
virtual framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&) { return nframes; }
- void passthru (framepos_t start_frame, framepos_t end_frame,
+ void fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes);
+
+ void passthru (BufferSet&, framepos_t start_frame, framepos_t end_frame,
pframes_t nframes, int declick);
virtual void write_out_of_band_data (BufferSet& /* bufs */, framepos_t /* start_frame */, framepos_t /* end_frame */,
- framecnt_t /* nframes */) {}
+ framecnt_t /* nframes */) {}
virtual void process_output_buffers (BufferSet& bufs,
framepos_t start_frame, framepos_t end_frame,
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index 8493d5e4ae..7159261b51 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -33,6 +33,7 @@ class RouteGroup;
class Source;
class Region;
class Diskstream;
+class IO;
class Track : public Route, public PublicDiskstream
{
diff --git a/libs/ardour/audio_buffer.cc b/libs/ardour/audio_buffer.cc
index 8b2d5c744f..1fd0337dd1 100644
--- a/libs/ardour/audio_buffer.cc
+++ b/libs/ardour/audio_buffer.cc
@@ -67,4 +67,13 @@ AudioBuffer::resize (size_t size)
cache_aligned_malloc ((void**) &_data, sizeof (Sample) * _capacity);
}
-
+bool
+AudioBuffer::check_silence (pframes_t nframes, pframes_t& n) const
+{
+ for (n = 0; n < _size && n < nframes; ++n) {
+ if (_data[n] != Sample (0)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index dc9f427e87..24687c766f 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -408,7 +408,7 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
* that someone can read playback_distance worth of data from.
*/
int
-AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+AudioDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
{
uint32_t n;
boost::shared_ptr<ChannelList> c = channels.reader();
@@ -494,9 +494,9 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
assert(ap);
assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
- Sample *buf = ap->get_audio_buffer (nframes).data (rec_offset);
+ Sample *buf = bufs.get_audio (n).data(rec_offset);
memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes);
-
+
} else {
framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
@@ -509,7 +509,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
boost::shared_ptr<AudioPort> const ap = _io->audio (n);
assert(ap);
- Sample* buf = ap->get_audio_buffer(nframes).data (rec_offset);
+ Sample *buf = bufs.get_audio (n).data(rec_offset);
framecnt_t first = chaninfo->capture_vector.len[0];
memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
@@ -657,6 +657,46 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
_speed = _target_speed;
}
+ if (need_disk_signal) {
+
+ /* copy data over to buffer set */
+
+ size_t n_buffers = bufs.count().n_audio();
+ size_t n_chans = c->size();
+ gain_t scaling = 1.0f;
+
+ if (n_chans > n_buffers) {
+ scaling = ((float) n_buffers)/n_chans;
+ }
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+
+ AudioBuffer& buf (bufs.get_audio (n%n_buffers));
+ ChannelInfo* chaninfo (*chan);
+
+ if (n < n_chans) {
+ if (scaling != 1.0f) {
+ buf.read_from_with_gain (chaninfo->current_playback_buffer, nframes, scaling);
+ } else {
+ buf.read_from (chaninfo->current_playback_buffer, nframes);
+ }
+ } else {
+ if (scaling != 1.0f) {
+ buf.accumulate_with_gain_from (chaninfo->current_playback_buffer, nframes, scaling);
+ } else {
+ buf.accumulate_from (chaninfo->current_playback_buffer, nframes);
+ }
+ }
+ }
+
+ /* leave the MIDI count alone */
+ ChanCount cnt (DataType::AUDIO, n_chans);
+ cnt.set (DataType::MIDI, bufs.count().n_midi());
+ bufs.set_count (cnt);
+
+ /* extra buffers will already be silent, so leave them alone */
+ }
+
return 0;
}
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 90439f46e9..070a7453fb 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -316,8 +316,6 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
return 0;
}
- Sample* b;
- Sample* tmpb;
framepos_t transport_frame;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
@@ -342,7 +340,9 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
to do nothing.
*/
- dret = diskstream->process (transport_frame, 0, playback_distance);
+ BufferSet bufs; /* empty set, no matter - nothing will happen */
+
+ dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
need_butler = diskstream->commit (playback_distance);
return dret;
}
@@ -350,126 +350,22 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
_silent = false;
_amp->apply_gain_automation(false);
- if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
- need_butler = diskstream->commit (playback_distance);
- silence (nframes);
- return dret;
- }
-
- /* special condition applies */
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers ());
+ fill_buffers_with_input (bufs, _input, nframes);
+
if (_meter_point == MeterInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
}
- if (monitoring_state() == MonitoringInput) {
-
- passthru (start_frame, end_frame, nframes, false);
-
- } else if ((b = diskstream->playback_buffer(0)) != 0) {
-
- /*
- XXX is it true that the earlier test on n_outputs()
- means that we can avoid checking it again here? i think
- so, because changing the i/o configuration of an IO
- requires holding the AudioEngine lock, which we hold
- while in the process() tree.
- */
-
-
- /* copy the diskstream data to all output buffers */
-
- size_t limit = input_streams ().n_audio();
- BufferSet& bufs = _session.get_scratch_buffers ();
- const size_t blimit = bufs.count().n_audio();
-
- uint32_t n;
- uint32_t i;
-
- if (limit > blimit) {
-
- /* example case: auditioner configured for stereo output,
- but loaded with an 8 channel file. there are only
- 2 passthrough buffers, but n_process_buffers() will
- return 8.
-
- arbitrary decision: map all channels in the diskstream
- to the outputs available.
- */
-
- float scaling = limit/blimit;
-
- for (i = 0, n = 1; i < blimit; ++i, ++n) {
-
- /* first time through just copy a channel into
- the output buffer.
- */
-
- Sample* bb = bufs.get_audio (i).data();
-
- for (pframes_t xx = 0; xx < nframes; ++xx) {
- bb[xx] = b[xx] * scaling;
- }
-
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
- }
-
- for (;i < limit; ++i, ++n) {
-
- /* for all remaining channels, sum with existing
- data in the output buffers
- */
-
- bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
-
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
-
- }
-
- limit = blimit;
-
- } else {
- for (i = 0, n = 1; i < limit; ++i, ++n) {
- memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
- }
-
- /* try to leave any MIDI buffers alone */
-
- ChanCount chn;
- chn.set_audio (limit);
- chn.set_midi (_input->n_ports().n_midi());
- bufs.set_count (chn);
- }
-
- /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
-
- process_output_buffers (
- bufs, start_frame, end_frame, nframes,
- declick,
- (!diskstream->record_enabled() && _session.transport_rolling())
- );
-
- } else {
- /* problem with the diskstream; just be quiet for a bit */
+ if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
+ need_butler = diskstream->commit (playback_distance);
silence (nframes);
+ return dret;
}
+ process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
+
need_butler = diskstream->commit (playback_distance);
return 0;
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index 3b49c97d27..38c5bb63de 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -19,6 +19,8 @@
#include <algorithm>
#include <cmath>
+#include "pbd/compose.h"
+
#include "ardour/audio_buffer.h"
#include "ardour/buffer_set.h"
#include "ardour/dB.h"
@@ -33,6 +35,12 @@ using namespace ARDOUR;
PBD::Signal0<void> Metering::Meter;
+PeakMeter::PeakMeter (Session& s, const std::string& name)
+ : Processor (s, string_compose ("meter-%1", name))
+{
+}
+
+
/** Get peaks from @a bufs
* Input acceptance is lenient - the first n buffers from @a bufs will
* be metered, where n was set by the last call to setup(), excess meters will
@@ -55,7 +63,9 @@ PeakMeter::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_fr
// Meter MIDI in to the first n_midi peaks
for (uint32_t i = 0; i < n_midi; ++i, ++n) {
float val = 0.0f;
- for (MidiBuffer::iterator e = bufs.get_midi(i).begin(); e != bufs.get_midi(i).end(); ++e) {
+ MidiBuffer& buf (bufs.get_midi(i));
+
+ for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ++e) {
const Evoral::MIDIEvent<framepos_t> ev(*e, false);
if (ev.is_note_on()) {
const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index cf54bef82e..9c11e818ac 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -26,6 +26,7 @@
#include <fcntl.h>
#include <cstdlib>
#include <ctime>
+#include <strings.h> // for ffs(3)
#include <sys/stat.h>
#include <sys/mman.h>
@@ -320,7 +321,7 @@ get_location_times(const Location* location,
}
int
-MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
{
framecnt_t rec_offset = 0;
framecnt_t rec_nframes = 0;
@@ -389,8 +390,11 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
// Pump entire port buffer into the ring buffer (FIXME: split cycles?)
MidiBuffer& buf = sp->get_midi_buffer(nframes);
+ ChannelMode mode = AllChannels; // _track->get_capture_channel_mode ();
+ uint32_t mask = 0xffff; // _track->get_capture_channel_mask ();
+
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
- const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
+ Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
#ifndef NDEBUG
if (DEBUG::MidiIO & PBD::debug_bits) {
const uint8_t* __data = ev.buffer();
@@ -416,8 +420,31 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
probabl be implemented in the source instead of here.
*/
const framecnt_t loop_offset = _num_captured_loops * loop_length;
- _capture_buf->write(transport_frame + loop_offset + ev.time(),
- ev.type(), ev.size(), ev.buffer());
+
+ switch (mode) {
+ case AllChannels:
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ break;
+ case FilterChannels:
+ if (ev.is_channel_event()) {
+ if ((1<<ev.channel()) & mask) {
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ }
+ } else {
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ }
+ break;
+ case ForceChannel:
+ if (ev.is_channel_event()) {
+ ev.set_channel (ffs(mask) - 1);
+ }
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ break;
+ }
}
g_atomic_int_add(&_frames_pending_write, nframes);
@@ -475,6 +502,18 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
}
+ if (need_disk_signal) {
+ /* copy the diskstream data to all output buffers */
+
+ MidiBuffer& mbuf (bufs.get_midi (0));
+ get_playback (mbuf, nframes);
+
+ /* leave the audio count alone */
+ ChanCount cnt (DataType::MIDI, 1);
+ cnt.set (DataType::AUDIO, bufs.count().n_audio());
+ bufs.set_count (cnt);
+ }
+
return 0;
}
@@ -1078,10 +1117,6 @@ MidiDiskstream::get_state ()
char buf[64];
LocaleGuard lg (X_("POSIX"));
- node.add_property("channel-mode", enum_2_string(get_channel_mode()));
- snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
- node.add_property("channel-mask", buf);
-
if (_write_source && _session.get_record_enabled()) {
XMLNode* cs_child = new XMLNode (X_("CapturingSources"));
@@ -1111,7 +1146,6 @@ MidiDiskstream::get_state ()
int
MidiDiskstream::set_state (const XMLNode& node, int version)
{
- const XMLProperty* prop;
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
XMLNode* capture_pending_node = 0;
@@ -1131,26 +1165,10 @@ MidiDiskstream::set_state (const XMLNode& node, int version)
return -1;
}
- ChannelMode channel_mode = AllChannels;
- if ((prop = node.property ("channel-mode")) != 0) {
- channel_mode = ChannelMode (string_2_enum(prop->value(), channel_mode));
- }
-
- unsigned int channel_mask = 0xFFFF;
- if ((prop = node.property ("channel-mask")) != 0) {
- sscanf (prop->value().c_str(), "0x%x", &channel_mask);
- if (channel_mask & (~0xFFFF)) {
- warning << _("MidiDiskstream: XML property channel-mask out of range") << endmsg;
- }
- }
-
-
if (capture_pending_node) {
use_pending_capture_data (*capture_pending_node);
}
- set_channel_mode (channel_mode, channel_mask);
-
in_set_state = false;
return 0;
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 51d364a3d9..72150f8cfc 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -108,7 +108,6 @@ MidiPort::get_midi_buffer (pframes_t nframes)
return *_buffer;
}
-
void
MidiPort::cycle_end (pframes_t /*nframes*/)
{
diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc
index db3a4cb109..e4ae3f3ffe 100644
--- a/libs/ardour/midi_ring_buffer.cc
+++ b/libs/ardour/midi_ring_buffer.cc
@@ -17,6 +17,7 @@
*/
#include "pbd/compose.h"
+#include "pbd/enumwriter.h"
#include "pbd/error.h"
#include "ardour/debug.h"
@@ -81,17 +82,6 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
bool r = this->peek (&status, sizeof(uint8_t));
assert (r); // If this failed, buffer is corrupt, all hope is lost
- // Ignore event if it doesn't match channel filter
- if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
- const uint8_t channel = status & 0x0F;
- if (!(get_channel_mask() & (1L << channel))) {
- DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB skipping event (%3 bytes) due to channel mask (mask = %1 chn = %2)\n",
- get_channel_mask(), (int) channel, ev_size));
- this->increment_read_ptr (ev_size); // Advance read pointer to next event
- continue;
- }
- }
-
/* lets see if we are going to be able to write this event into dst.
*/
uint8_t* write_loc = dst.reserve (ev_time, ev_size);
@@ -130,10 +120,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
} else if (is_note_off(write_loc[0])) {
_tracker.remove (write_loc[1], write_loc[0] & 0xf);
}
-
- if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
- write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
- }
+
++count;
} else {
cerr << "WARNING: error reading event contents from MIDI ring" << endl;
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 65a42836a3..0f1b2b52af 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -17,6 +17,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <strings.h> // for ffs(3)
+
#include "pbd/enumwriter.h"
#include "pbd/convert.h"
#include "evoral/midi_util.h"
@@ -55,6 +57,8 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
, _note_mode(Sustained)
, _step_editing (false)
, _input_active (true)
+ , _playback_channel_mask(0x0000ffff)
+ , _capture_channel_mask(0x0000ffff)
{
}
@@ -158,6 +162,38 @@ MidiTrack::set_state (const XMLNode& node, int version)
set_input_active (string_is_affirmative (prop->value()));
}
+ ChannelMode playback_channel_mode = AllChannels;
+ ChannelMode capture_channel_mode = AllChannels;
+
+ if ((prop = node.property ("playback-channel-mode")) != 0) {
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+ }
+ if ((prop = node.property ("capture-channel-mode")) != 0) {
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), capture_channel_mode));
+ }
+ if ((prop = node.property ("channel-mode")) != 0) {
+ /* 3.0 behaviour where capture and playback modes were not separated */
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+ capture_channel_mode = playback_channel_mode;
+ }
+
+ unsigned int playback_channel_mask = 0xffff;
+ unsigned int capture_channel_mask = 0xffff;
+
+ if ((prop = node.property ("playback-channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+ }
+ if ((prop = node.property ("capture-channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &capture_channel_mask);
+ }
+ if ((prop = node.property ("channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+ capture_channel_mask = playback_channel_mask;
+ }
+
+ set_playback_channel_mode (playback_channel_mode, playback_channel_mask);
+ set_capture_channel_mode (capture_channel_mode, capture_channel_mask);
+
pending_state = const_cast<XMLNode*> (&node);
if (_session.state_of_the_state() & Session::Loading) {
@@ -196,6 +232,13 @@ MidiTrack::state(bool full_state)
root.add_child_nocopy (*freeze_node);
}
+ root.add_property("playback_channel-mode", enum_2_string(get_playback_channel_mode()));
+ root.add_property("capture_channel-mode", enum_2_string(get_capture_channel_mode()));
+ snprintf (buf, sizeof(buf), "0x%x", get_playback_channel_mask());
+ root.add_property("playback-channel-mask", buf);
+ snprintf (buf, sizeof(buf), "0x%x", get_capture_channel_mask());
+ root.add_property("capture-channel-mask", buf);
+
root.add_property ("note-mode", enum_2_string (_note_mode));
root.add_property ("step-editing", (_step_editing ? "yes" : "no"));
root.add_property ("input-active", (_input_active ? "yes" : "no"));
@@ -300,25 +343,36 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
playback distance to zero, thus causing diskstream::commit
to do nothing.
*/
- dret = diskstream->process (transport_frame, 0, playback_distance);
+ BufferSet bufs; /* empty set - is OK, since nothing will happen */
+
+ dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
need_butler = diskstream->commit (playback_distance);
return dret;
}
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ /* filter captured data before the diskstream sees it */
+
+ filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask());
_silent = false;
- if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
+ if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
need_butler = diskstream->commit (playback_distance);
silence (nframes);
return dret;
}
- /* special condition applies */
-
- if (_meter_point == MeterInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
- }
+ /* filter playback data before we do anything else */
+
+ filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ());
if (monitoring_state() == MonitoringInput) {
@@ -334,47 +388,17 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
diskstream->flush_playback (start_frame, end_frame);
- passthru (start_frame, end_frame, nframes, 0);
-
- } else {
-
- /*
- XXX is it true that the earlier test on n_outputs()
- means that we can avoid checking it again here? i think
- so, because changing the i/o configuration of an IO
- requires holding the AudioEngine lock, which we hold
- while in the process() tree.
- */
-
-
- /* copy the diskstream data to all output buffers */
-
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
- MidiBuffer& mbuf (bufs.get_midi (0));
-
- /* we are a MIDI track, so we always start the chain with a
- * single-MIDI-channel diskstream
- */
- ChanCount c;
- c.set_audio (0);
- c.set_midi (1);
- bufs.set_count (c);
-
- assert (nframes > 0);
-
- diskstream->get_playback (mbuf, nframes);
-
- /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
-
- write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-
- /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
+ }
- process_output_buffers (
- bufs, start_frame, end_frame, nframes,
- declick, (!diskstream->record_enabled() && !_session.transport_stopped())
- );
- }
+
+ /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
+
+ write_out_of_band_data (bufs, start_frame, end_frame, nframes);
+
+ /* final argument: don't waste time with automation if we're not recording or rolling */
+
+ process_output_buffers (bufs, start_frame, end_frame, nframes,
+ declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
@@ -457,6 +481,43 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
}
}
+void
+MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask)
+{
+ if (mode == AllChannels) {
+ return;
+ }
+
+ MidiBuffer& buf (bufs.get_midi (0));
+
+ for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
+
+ Evoral::MIDIEvent<framepos_t> ev(*e, false);
+
+ if (ev.is_channel_event()) {
+ switch (mode) {
+ case FilterChannels:
+ if (0 == ((1<<ev.channel()) & mask)) {
+ e = buf.erase (e);
+ } else {
+ ++e;
+ }
+ break;
+ case ForceChannel:
+ ev.set_channel (ffs (mask) - 1);
+ ++e;
+ break;
+ case AllChannels:
+ /* handled by the opening if() */
+ ++e;
+ break;
+ }
+ } else {
+ ++e;
+ }
+ }
+}
+
void
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
{
@@ -637,21 +698,53 @@ MidiTrack::write_source (uint32_t)
}
void
-MidiTrack::set_channel_mode (ChannelMode mode, uint16_t mask)
+MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask)
{
- midi_diskstream()->set_channel_mode (mode, mask);
+ ChannelMode old = get_playback_channel_mode ();
+ uint16_t old_mask = get_playback_channel_mask ();
+
+ if (old != mode || mask != old_mask) {
+ _set_playback_channel_mode (mode, mask);
+ PlaybackChannelModeChanged ();
+ _session.set_dirty ();
+ }
}
-ChannelMode
-MidiTrack::get_channel_mode ()
+void
+MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask)
{
- return midi_diskstream()->get_channel_mode ();
+ ChannelMode old = get_capture_channel_mode ();
+ uint16_t old_mask = get_capture_channel_mask ();
+
+ if (old != mode || mask != old_mask) {
+ _set_capture_channel_mode (mode, mask);
+ CaptureChannelModeChanged ();
+ _session.set_dirty ();
+ }
}
-uint16_t
-MidiTrack::get_channel_mask ()
+void
+MidiTrack::set_playback_channel_mask (uint16_t mask)
{
- return midi_diskstream()->get_channel_mask ();
+ uint16_t old = get_playback_channel_mask();
+
+ if (old != mask) {
+ _set_playback_channel_mask (mask);
+ PlaybackChannelMaskChanged ();
+ _session.set_dirty ();
+ }
+}
+
+void
+MidiTrack::set_capture_channel_mask (uint16_t mask)
+{
+ uint16_t old = get_capture_channel_mask();
+
+ if (old != mask) {
+ _set_capture_channel_mask (mask);
+ CaptureChannelMaskChanged ();
+ _session.set_dirty ();
+ }
}
boost::shared_ptr<MidiPlaylist>
@@ -739,7 +832,7 @@ MidiTrack::act_on_mute ()
if (muted()) {
/* only send messages for channels we are using */
- uint16_t mask = get_channel_mask();
+ uint16_t mask = get_playback_channel_mask();
for (uint8_t channel = 0; channel <= 0xF; channel++) {
@@ -792,3 +885,4 @@ MidiTrack::monitoring_state () const
}
return ms;
}
+
diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc
index 519f3ca494..921be6a53a 100644
--- a/libs/ardour/return.cc
+++ b/libs/ardour/return.cc
@@ -50,7 +50,7 @@ Return::Return (Session& s, bool internal)
/* never muted */
_amp.reset (new Amp (_session));
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, name()));
}
Return::~Return ()
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 1a90553be2..9f933e0a4a 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -37,6 +37,7 @@
#include "ardour/amp.h"
#include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
#include "ardour/audioengine.h"
#include "ardour/buffer.h"
#include "ardour/buffer_set.h"
@@ -46,6 +47,8 @@
#include "ardour/internal_return.h"
#include "ardour/internal_send.h"
#include "ardour/meter.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
#include "ardour/monitor_processor.h"
#include "ardour/pannable.h"
#include "ardour/panner_shell.h"
@@ -139,7 +142,7 @@ Route::init ()
they will be added to _processors by setup_invisible_processors ()
*/
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, _name));
_meter->set_display_to_user (false);
_meter->activate ();
@@ -454,8 +457,8 @@ Route::process_output_buffers (BufferSet& bufs,
on a transition between monitoring states we get a de-clicking gain
change in the _main_outs delivery.
*/
- _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
+ _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
@@ -561,39 +564,26 @@ Route::n_process_buffers ()
}
void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
{
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+ assert (is_monitor());
+ BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+ passthru (bufs, start_frame, end_frame, nframes, declick);
+}
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
_silent = false;
- assert (bufs.available() >= input_streams());
-
- if (_input->n_ports() == ChanCount::ZERO) {
- silence_unlocked (nframes);
- }
-
- bufs.set_count (input_streams());
-
if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
/* control/monitor bus ignores input ports when something is
feeding the listen "stream". data will "arrive" into the
route from the intreturn processor element.
*/
- bufs.silence (nframes, 0);
-
- } else {
-
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- BufferSet::iterator o = bufs.begin(*t);
- PortSet& ports (_input->ports());
-
- for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
- o->read_from (i->get_buffer(nframes), nframes);
- }
- }
+ bufs.silence (nframes, 0);
}
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -2985,6 +2975,7 @@ int
Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
return 0;
}
@@ -2997,6 +2988,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
silence_unlocked (nframes);
return 0;
}
+
if (session_state_changing) {
if (_session.transport_speed() != 0.0f) {
/* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -3012,8 +3004,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
*/
}
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
_amp->apply_gain_automation (false);
- passthru (start_frame, end_frame, nframes, 0);
+ passthru (bufs, start_frame, end_frame, nframes, 0);
return 0;
}
@@ -3043,7 +3043,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
_silent = false;
- passthru (start_frame, end_frame, nframes, declick);
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ passthru (bufs, start_frame, end_frame, nframes, declick);
return 0;
}
@@ -4148,3 +4156,90 @@ Route::non_realtime_locate (framepos_t pos)
}
}
}
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+ size_t n_buffers;
+ size_t i;
+
+ /* MIDI
+ *
+ * We don't currently mix MIDI input together, so we don't need the
+ * complex logic of the audio case.
+ */
+
+ n_buffers = bufs.count().n_midi ();
+
+ for (i = 0; i < n_buffers; ++i) {
+
+ boost::shared_ptr<MidiPort> source_port = io->midi (i);
+ MidiBuffer& buf (bufs.get_midi (i));
+
+ if (source_port) {
+ buf.copy (source_port->get_midi_buffer(nframes));
+ } else {
+ buf.silence (nframes);
+ }
+ }
+
+ /* AUDIO */
+
+ n_buffers = bufs.count().n_audio();
+
+ size_t n_ports = io->n_ports().n_audio();
+ float scaling = 1.0f;
+
+ if (n_ports > n_buffers) {
+ scaling = ((float) n_buffers) / n_ports;
+ }
+
+ for (i = 0; i < n_ports; ++i) {
+
+ /* if there are more ports than buffers, map them onto buffers
+ * in a round-robin fashion
+ */
+
+ boost::shared_ptr<AudioPort> source_port = io->audio (i);
+ AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+
+
+ if (i < n_buffers) {
+
+ /* first time through just copy a channel into
+ the output buffer.
+ */
+
+ buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+ if (scaling != 1.0f) {
+ buf.apply_gain (scaling, nframes);
+ }
+
+ } else {
+
+ /* on subsequent times around, merge data from
+ * the port with what is already there
+ */
+
+ if (scaling != 1.0f) {
+ buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+ } else {
+ buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+ }
+ }
+ }
+
+ /* silence any remaining buffers */
+
+ for (; i < n_buffers; ++i) {
+ AudioBuffer& buf (bufs.get_audio (i));
+ buf.silence (nframes);
+ }
+
+ /* establish the initial setup of the buffer set, reflecting what was
+ copied into it.
+ */
+
+ bufs.set_count (io->n_ports());
+}
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index fb5c6b7b0c..107cf9862b 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -83,7 +83,7 @@ Send::Send (Session& s, boost::shared_ptr<Pannable> p, boost::shared_ptr<MuteMas
boost_debug_shared_ptr_mark_interesting (this, "send");
_amp.reset (new Amp (_session));
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, name()));
add_control (_amp->gain_control ());
}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 9a4fabeb64..cd7daaf185 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -873,7 +873,7 @@ Session::process_audition (pframes_t nframes)
/* if using a monitor section, run it because otherwise we don't hear anything */
if (auditioner->needs_monitor()) {
- _monitor_out->passthru (_transport_frame, _transport_frame + nframes, nframes, false);
+ _monitor_out->monitor_run (_transport_frame, _transport_frame + nframes, nframes, false);
}
/* handle pending events */
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 52a960fce6..1effaa45b8 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -330,16 +330,21 @@ int
Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
return 0;
}
bool can_record = _session.actively_recording ();
+ /* no outputs? nothing to do ... what happens if we have sends etc. ? */
+
if (n_outputs().n_total() == 0) {
return 0;
}
+ /* not active ... do the minimum possible by just outputting silence */
+
if (!_active) {
silence (nframes);
return 0;
@@ -393,14 +398,9 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
}
}
- if (!_have_internal_generator && metering_state() == MeteringInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
- }
-
_amp->apply_gain_automation (false);
/* if have_internal_generator, or .. */
- //_input->process_input (_meter, start_frame, end_frame, nframes);
if (be_silent) {
@@ -408,10 +408,15 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
} else {
- /* we're sending signal, but we may still want to meter the input.
- */
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
- passthru (start_frame, end_frame, nframes, false);
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ passthru (bufs, start_frame, end_frame, nframes, false);
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -447,7 +452,10 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*
silence (nframes);
framecnt_t playback_distance;
- int const dret = _diskstream->process (_session.transport_frame(), nframes, playback_distance);
+
+ BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
+
+ int const dret = _diskstream->process (bufs, _session.transport_frame(), nframes, playback_distance, false);
need_butler = _diskstream->commit (playback_distance);
return dret;
}
@@ -934,3 +942,4 @@ Track::metering_state () const
{
return _diskstream->record_enabled() ? MeteringInput : MeteringRoute;
}
+