summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/SConscript16
-rw-r--r--gtk2_ardour/analysis_window.cc6
-rwxr-xr-xgtk2_ardour/ardbg2
-rw-r--r--gtk2_ardour/au_pluginui.cc (renamed from au_pluginui.cc)10
-rw-r--r--gtk2_ardour/audio_region_view.cc38
-rw-r--r--gtk2_ardour/audio_region_view.h1
-rw-r--r--gtk2_ardour/automation_line.cc7
-rw-r--r--gtk2_ardour/crossfade_edit.cc2
-rw-r--r--gtk2_ardour/editor_export_audio.cc12
-rw-r--r--gtk2_ardour/ladspa_pluginui.cc759
-rw-r--r--gtk2_ardour/midi_region_view.cc113
-rw-r--r--gtk2_ardour/midi_region_view.h84
-rw-r--r--gtk2_ardour/new_session_dialog.cc23
-rw-r--r--gtk2_ardour/plugin_selector.cc53
-rw-r--r--gtk2_ardour/plugin_selector.h4
-rw-r--r--gtk2_ardour/plugin_ui.cc706
-rw-r--r--gtk2_ardour/plugin_ui.h12
-rw-r--r--gtk2_ardour/public_editor.h3
-rw-r--r--gtk2_ardour/redirect_box.cc71
-rw-r--r--gtk2_ardour/region_view.cc12
-rw-r--r--gtk2_ardour/region_view.h4
-rw-r--r--gtk2_ardour/tape_region_view.cc2
-rw-r--r--libs/ardour/SConscript6
-rw-r--r--libs/ardour/ardour/audio_diskstream.h9
-rw-r--r--libs/ardour/ardour/audio_port.h110
-rw-r--r--libs/ardour/ardour/audio_track.h2
-rw-r--r--libs/ardour/ardour/audio_unit.h2
-rw-r--r--libs/ardour/ardour/audioengine.h14
-rw-r--r--libs/ardour/ardour/audioplaylist.h2
-rw-r--r--libs/ardour/ardour/audioregion.h36
-rw-r--r--libs/ardour/ardour/audiosource.h24
-rw-r--r--libs/ardour/ardour/buffer.h103
-rw-r--r--libs/ardour/ardour/chan_count.h81
-rw-r--r--libs/ardour/ardour/coreaudiosource.h4
-rw-r--r--libs/ardour/ardour/crossfade.h2
-rw-r--r--libs/ardour/ardour/data_type.h80
-rw-r--r--libs/ardour/ardour/destructive_filesource.h4
-rw-r--r--libs/ardour/ardour/diskstream.h10
-rw-r--r--libs/ardour/ardour/insert.h5
-rw-r--r--libs/ardour/ardour/io.h62
-rw-r--r--libs/ardour/ardour/midi_diskstream.h69
-rw-r--r--libs/ardour/ardour/midi_playlist.h4
-rw-r--r--libs/ardour/ardour/midi_port.h72
-rw-r--r--libs/ardour/ardour/midi_region.h93
-rw-r--r--libs/ardour/ardour/midi_source.h30
-rw-r--r--libs/ardour/ardour/midi_track.h7
-rw-r--r--libs/ardour/ardour/plugin.h13
-rw-r--r--libs/ardour/ardour/port.h125
-rw-r--r--libs/ardour/ardour/port_set.h151
-rw-r--r--libs/ardour/ardour/region.h61
-rw-r--r--libs/ardour/ardour/route.h2
-rw-r--r--libs/ardour/ardour/session.h14
-rw-r--r--libs/ardour/ardour/smf_source.h9
-rw-r--r--libs/ardour/ardour/sndfilesource.h4
-rw-r--r--libs/ardour/ardour/source.h10
-rw-r--r--libs/ardour/ardour/types.h13
-rw-r--r--libs/ardour/ardour/vst_plugin.h2
-rw-r--r--libs/ardour/audio_diskstream.cc45
-rw-r--r--libs/ardour/audio_playlist.cc6
-rw-r--r--libs/ardour/audio_port.cc67
-rw-r--r--libs/ardour/audio_track.cc12
-rw-r--r--libs/ardour/audio_unit.cc2
-rw-r--r--libs/ardour/audioengine.cc70
-rw-r--r--libs/ardour/audioregion.cc322
-rw-r--r--libs/ardour/audiosource.cc35
-rw-r--r--libs/ardour/buffer.cc107
-rw-r--r--libs/ardour/configuration.cc2
-rw-r--r--libs/ardour/coreaudiosource.cc2
-rw-r--r--libs/ardour/crossfade.cc6
-rw-r--r--libs/ardour/destructive_filesource.cc12
-rw-r--r--libs/ardour/diskstream.cc8
-rw-r--r--libs/ardour/import.cc7
-rw-r--r--libs/ardour/insert.cc56
-rw-r--r--libs/ardour/io.cc301
-rw-r--r--libs/ardour/midi_diskstream.cc807
-rw-r--r--libs/ardour/midi_playlist.cc62
-rw-r--r--libs/ardour/midi_port.cc102
-rw-r--r--libs/ardour/midi_region.cc431
-rw-r--r--libs/ardour/midi_source.cc32
-rw-r--r--libs/ardour/midi_track.cc11
-rw-r--r--libs/ardour/panner.cc4
-rw-r--r--libs/ardour/plugin.cc8
-rw-r--r--libs/ardour/plugin_manager.cc4
-rw-r--r--libs/ardour/port.cc12
-rw-r--r--libs/ardour/port_set.cc111
-rw-r--r--libs/ardour/region.cc392
-rw-r--r--libs/ardour/reverse.cc11
-rw-r--r--libs/ardour/route.cc9
-rw-r--r--libs/ardour/send.cc3
-rw-r--r--libs/ardour/session.cc133
-rw-r--r--libs/ardour/session_command.cc22
-rw-r--r--libs/ardour/session_export.cc9
-rw-r--r--libs/ardour/session_state.cc14
-rw-r--r--libs/ardour/session_timefx.cc13
-rw-r--r--libs/ardour/smf_source.cc23
-rw-r--r--libs/ardour/sndfilesource.cc4
-rw-r--r--libs/ardour/source.cc8
-rw-r--r--libs/ardour/track.cc6
-rw-r--r--libs/pbd/pbd/memento_command.h16
99 files changed, 4056 insertions, 2426 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index 2d59be1b5e..857ed4b8e1 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -57,14 +57,13 @@ if gtkardour['FFT_ANALYSIS']:
gtkardour.Merge ([libraries['fftw3f']])
gtkardour.Append(CCFLAGS='-DFFT_ANALYSIS')
-if gtkardour['COREAUDIO']:
- gtkardour.Append(CCFLAGS='-DHAVE_COREAUDIO')
- gtkardour.Merge([libraries['appleutility']])
-
skipped_files=Split("""
connection_editor.cc
""")
+coreaudio_files=Split("""
+au_pluginui.cc
+""")
gtkardour_files=Split("""
about.cc
@@ -142,6 +141,7 @@ imageframe_time_axis_view.cc
imageframe_view.cc
io_selector.cc
keyboard.cc
+ladspa_pluginui.cc
location_ui.cc
main.cc
marker.cc
@@ -188,7 +188,6 @@ visual_time_axis.cc
waveview.cc
""")
-
fft_analysis_files=Split("""
analysis_window.cc
fft_graph.cc
@@ -214,7 +213,12 @@ vst_files = [ 'vst_pluginui.cc' ]
if env['VST']:
extra_sources += vst_files
gtkardour.Append (CCFLAGS="-DVST_SUPPORT", CPPPATH="#libs/fst")
-
+
+if gtkardour['COREAUDIO']:
+ extra_sources += coreaudio_files
+ gtkardour.Append(CCFLAGS='-DHAVE_COREAUDIO')
+ gtkardour.Merge([libraries['appleutility']])
+
if env['FFT_ANALYSIS']:
extra_sources += fft_analysis_files
diff --git a/gtk2_ardour/analysis_window.cc b/gtk2_ardour/analysis_window.cc
index f742afd727..24c6cc4fb8 100644
--- a/gtk2_ardour/analysis_window.cc
+++ b/gtk2_ardour/analysis_window.cc
@@ -221,7 +221,6 @@ AnalysisWindow::analyze_data (Gtk::Button *button)
Sample *buf = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
Sample *mixbuf = (Sample *) malloc(sizeof(Sample) * fft_graph.windowSize());
float *gain = (float *) malloc(sizeof(float) * fft_graph.windowSize());
- char *work = (char *) malloc(sizeof(char) * fft_graph.windowSize());
Selection s = PublicEditor::instance().get_selection();
TimeSelection ts = s.time;
@@ -261,7 +260,7 @@ AnalysisWindow::analyze_data (Gtk::Button *button)
n = (*j).length() - i;
}
- n = pl->read(buf, mixbuf, gain, work, (*j).start + i, n);
+ n = pl->read(buf, mixbuf, gain, (*j).start + i, n);
if ( n < fft_graph.windowSize()) {
for (int j = n; j < fft_graph.windowSize(); j++) {
@@ -301,7 +300,7 @@ AnalysisWindow::analyze_data (Gtk::Button *button)
n = arv->region().length() - i;
}
- n = arv->audio_region().read_at(buf, mixbuf, gain, work, arv->region().position() + i, n);
+ n = arv->audio_region().read_at(buf, mixbuf, gain, arv->region().position() + i, n);
if ( n < fft_graph.windowSize()) {
for (int j = n; j < fft_graph.windowSize(); j++) {
@@ -331,7 +330,6 @@ AnalysisWindow::analyze_data (Gtk::Button *button)
free(buf);
free(mixbuf);
- free(work);
track_list_ready = true;
} /* end lock */
diff --git a/gtk2_ardour/ardbg b/gtk2_ardour/ardbg
index 267fdbae73..9d3f5bf6c7 100755
--- a/gtk2_ardour/ardbg
+++ b/gtk2_ardour/ardbg
@@ -1,3 +1,3 @@
#!/bin/sh
source ardev_common.sh
-exec gdb ./ardour.bin
+exec gdb ./ardour.bin "$*"
diff --git a/au_pluginui.cc b/gtk2_ardour/au_pluginui.cc
index cbf493a629..3e0e7e4874 100644
--- a/au_pluginui.cc
+++ b/gtk2_ardour/au_pluginui.cc
@@ -26,9 +26,7 @@
using namespace ARDOUR;
using namespace PBD;
-AUPluginUI::AUPluginUI (boost::shared_ptr<PluginInsert> pi, boost::shared_ptr<AUPlugin> ap)
- : PlugUIBase (pi),
- au (ap)
+AUPluginUI::AUPluginUI (ARDOUR::AudioEngine& engine, boost::shared_ptr<PluginInsert> ap)
{
info << "AUPluginUI created" << endmsg;
}
@@ -37,9 +35,3 @@ AUPluginUI::~AUPluginUI ()
{
// nothing to do here - plugin destructor destroys the GUI
}
-
-int
-AUPluginUI::get_preferred_height ()
-{
- return -1;
-}
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index dff2300529..f675bf9eed 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -314,6 +314,34 @@ AudioRegionView::region_scale_amplitude_changed ()
}
void
+AudioRegionView::region_renamed ()
+{
+ // FIXME: ugly duplication with RegionView...
+
+ string str;
+
+ if (_region.locked()) {
+ str += '>';
+ str += _region.name();
+ str += '<';
+ } else {
+ str = _region.name();
+ }
+
+ // ... because of this
+ if (audio_region().speed_mismatch (trackview.session().frame_rate())) {
+ str = string ("*") + str;
+ }
+
+ if (_region.muted()) {
+ str = string ("!") + str;
+ }
+
+ set_item_name (str, this);
+ set_name_text (str);
+}
+
+void
AudioRegionView::region_resized (Change what_changed)
{
RegionView::region_resized(what_changed);
@@ -375,16 +403,12 @@ AudioRegionView::region_muted ()
}
}
-
void
AudioRegionView::set_height (gdouble height)
{
- uint32_t wcnt = waves.size();
-
- // FIXME: ick
- TimeAxisViewItem::set_height (height - 2);
+ RegionView::set_height(height);
- _height = height;
+ uint32_t wcnt = waves.size();
for (uint32_t n=0; n < wcnt; ++n) {
gdouble ht;
@@ -759,7 +783,7 @@ AudioRegionView::create_waves ()
wave_caches.push_back (WaveView::create_cache ());
if (wait_for_data) {
- if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
+ if (audio_region().audio_source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
create_one_wave (n, true);
} else {
create_zero_line = false;
diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h
index 29b3f9d904..e9172dec97 100644
--- a/gtk2_ardour/audio_region_view.h
+++ b/gtk2_ardour/audio_region_view.h
@@ -145,6 +145,7 @@ class AudioRegionView : public RegionView
void region_moved (void *);
void region_muted ();
void region_scale_amplitude_changed ();
+ void region_renamed ();
void create_waves ();
void create_one_wave (uint32_t, bool);
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc
index 5c09ddd49b..f3e30c4523 100644
--- a/gtk2_ardour/automation_line.cc
+++ b/gtk2_ardour/automation_line.cc
@@ -1270,13 +1270,14 @@ AutomationLine::hide_all_but_selected_control_points ()
XMLNode &AutomationLine::get_state(void)
{
- // TODO
- return alist.get_state();
+ XMLNode *node = new XMLNode("AutomationLine");
+ node->add_child_nocopy(alist.get_state());
+ return *node;
}
int AutomationLine::set_state(const XMLNode &node)
{
// TODO
- alist.set_state(node);
+ //alist.set_state(node);
return 0;
}
diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc
index b2967dc4a9..c56f51fcfa 100644
--- a/gtk2_ardour/crossfade_edit.cc
+++ b/gtk2_ardour/crossfade_edit.cc
@@ -1035,7 +1035,7 @@ CrossfadeEditor::make_waves (AudioRegion& region, WhichFade which)
gdouble yoff = n * ht;
- if (region.source(n).peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), &region, which), peaks_ready_connection)) {
+ if (region.audio_source(n).peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), &region, which), peaks_ready_connection)) {
WaveView* waveview = new WaveView (*(canvas->root()));
diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc
index 7e26ba37b2..70c4863fd3 100644
--- a/gtk2_ardour/editor_export_audio.cc
+++ b/gtk2_ardour/editor_export_audio.cc
@@ -163,7 +163,6 @@ Editor::write_region (string path, AudioRegion& region)
jack_nframes_t to_read;
Sample buf[chunk_size];
gain_t gain_buffer[chunk_size];
- char workbuf[chunk_size *4];
jack_nframes_t pos;
char s[PATH_MAX+1];
uint32_t cnt;
@@ -235,11 +234,11 @@ Editor::write_region (string path, AudioRegion& region)
fs = (*src);
- if (region.read_at (buf, buf, gain_buffer, workbuf, pos, this_time) != this_time) {
+ if (region.read_at (buf, buf, gain_buffer, pos, this_time) != this_time) {
break;
}
- if (fs->write (buf, this_time, workbuf) != this_time) {
+ if (fs->write (buf, this_time) != this_time) {
error << "" << endmsg;
goto error_out;
}
@@ -310,7 +309,6 @@ Editor::write_audio_range (AudioPlaylist& playlist, uint32_t channels, list<Audi
jack_nframes_t nframes;
Sample buf[chunk_size];
gain_t gain_buffer[chunk_size];
- char workbuf[chunk_size*4];
jack_nframes_t pos;
char s[PATH_MAX+1];
uint32_t cnt;
@@ -368,11 +366,11 @@ Editor::write_audio_range (AudioPlaylist& playlist, uint32_t channels, list<Audi
fs = sources[n];
- if (playlist.read (buf, buf, gain_buffer, workbuf, pos, this_time, n) != this_time) {
+ if (playlist.read (buf, buf, gain_buffer, pos, this_time, n) != this_time) {
break;
}
- if (fs->write (buf, this_time, workbuf) != this_time) {
+ if (fs->write (buf, this_time) != this_time) {
goto error_out;
}
}
@@ -398,7 +396,7 @@ Editor::write_audio_range (AudioPlaylist& playlist, uint32_t channels, list<Audi
for (uint32_t n=0; n < channels; ++n) {
fs = sources[n];
- if (fs->write (buf, this_time, workbuf) != this_time) {
+ if (fs->write (buf, this_time) != this_time) {
goto error_out;
}
}
diff --git a/gtk2_ardour/ladspa_pluginui.cc b/gtk2_ardour/ladspa_pluginui.cc
new file mode 100644
index 0000000000..22b860900a
--- /dev/null
+++ b/gtk2_ardour/ladspa_pluginui.cc
@@ -0,0 +1,759 @@
+/*
+ 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 <climits>
+#include <cerrno>
+#include <cmath>
+#include <string>
+
+#include <pbd/stl_delete.h>
+#include <pbd/xml++.h>
+#include <pbd/failed_constructor.h>
+
+#include <gtkmm2ext/click_box.h>
+#include <gtkmm2ext/fastmeter.h>
+#include <gtkmm2ext/barcontroller.h>
+#include <gtkmm2ext/utils.h>
+#include <gtkmm2ext/doi.h>
+#include <gtkmm2ext/slider_controller.h>
+
+#include <midi++/manager.h>
+
+#include <ardour/audioengine.h>
+#include <ardour/plugin.h>
+#include <ardour/insert.h>
+#include <ardour/ladspa_plugin.h>
+
+#include <lrdf.h>
+
+#include "ardour_ui.h"
+#include "prompter.h"
+#include "plugin_ui.h"
+#include "utils.h"
+#include "gui_thread.h"
+
+#include "i18n.h"
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace sigc;
+
+LadspaPluginUI::LadspaPluginUI (AudioEngine &engine, boost::shared_ptr<PluginInsert> pi, bool scrollable)
+ : PlugUIBase (pi),
+ engine(engine),
+ button_table (initial_button_rows, initial_button_cols),
+ output_table (initial_output_rows, initial_output_cols),
+ hAdjustment(0.0, 0.0, 0.0),
+ vAdjustment(0.0, 0.0, 0.0),
+ scroller_view(hAdjustment, vAdjustment),
+ automation_menu (0),
+ is_scrollable(scrollable)
+{
+ set_name ("PluginEditor");
+ set_border_width (10);
+ set_homogeneous (false);
+
+ settings_box.set_homogeneous (false);
+
+ HBox* constraint_hbox = manage (new HBox);
+ HBox* smaller_hbox = manage (new HBox);
+ Label* combo_label = manage (new Label (_("<span size=\"large\">Presets</span>")));
+ combo_label->set_use_markup (true);
+
+ smaller_hbox->pack_start (*combo_label, false, false, 10);
+ smaller_hbox->pack_start (combo, false, false);
+ smaller_hbox->pack_start (save_button, false, false);
+
+ constraint_hbox->set_spacing (5);
+ constraint_hbox->pack_start (*smaller_hbox, true, false);
+ constraint_hbox->pack_end (bypass_button, false, false);
+
+ settings_box.pack_end (*constraint_hbox, false, false);
+
+ pack_start (settings_box, false, false);
+
+ if ( is_scrollable ) {
+ scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+ scroller.set_name ("PluginEditor");
+ scroller_view.set_name("PluginEditor");
+ scroller_view.add (hpacker);
+ scroller.add (scroller_view);
+
+ pack_start (scroller, true, true);
+
+ }
+ else {
+ pack_start (hpacker, false, false);
+ }
+
+ insert->active_changed.connect (mem_fun(*this, &LadspaPluginUI::redirect_active_changed));
+ bypass_button.set_active (!insert->active());
+
+ build (engine);
+}
+
+LadspaPluginUI::~LadspaPluginUI ()
+{
+ if (output_controls.size() > 0) {
+ screen_update_connection.disconnect();
+ }
+}
+
+void
+LadspaPluginUI::build (AudioEngine &engine)
+
+{
+ guint32 i = 0;
+ guint32 x = 0;
+ Frame* frame;
+ Frame* bt_frame;
+ VBox* box;
+ int output_row, output_col;
+ int button_row, button_col;
+ int output_rows, output_cols;
+ int button_rows, button_cols;
+ guint32 n_ins=0, n_outs = 0;
+
+ prefheight = 30;
+ hpacker.set_spacing (10);
+
+ output_rows = initial_output_rows;
+ output_cols = initial_output_cols;
+ button_rows = initial_button_rows;
+ button_cols = initial_button_cols;
+ output_row = 0;
+ button_row = 0;
+ output_col = 0;
+ button_col = 0;
+
+ button_table.set_homogeneous (false);
+ button_table.set_row_spacings (2);
+ button_table.set_col_spacings (2);
+ output_table.set_homogeneous (true);
+ output_table.set_row_spacings (2);
+ output_table.set_col_spacings (2);
+ button_table.set_border_width (5);
+ output_table.set_border_width (5);
+
+ hpacker.set_border_width (10);
+
+ bt_frame = manage (new Frame);
+ bt_frame->set_name ("BaseFrame");
+ bt_frame->add (button_table);
+ hpacker.pack_start(*bt_frame, true, true);
+
+ box = manage (new VBox);
+ box->set_border_width (5);
+ box->set_spacing (1);
+
+ frame = manage (new Frame);
+ frame->set_name ("BaseFrame");
+ frame->set_label (_("Controls"));
+ frame->add (*box);
+ hpacker.pack_start(*frame, true, true);
+
+ /* find all ports. build control elements for all appropriate control ports */
+
+ for (i = 0; i < plugin->parameter_count(); ++i) {
+
+ if (plugin->parameter_is_control (i)) {
+
+ /* Don't show latency control ports */
+
+ if (plugin->describe_parameter (i) == X_("latency")) {
+ continue;
+ }
+
+ ControlUI* cui;
+
+ /* if we are scrollable, just use one long column */
+
+ if (!is_scrollable) {
+ if (x++ > 7){
+ frame = manage (new Frame);
+ frame->set_name ("BaseFrame");
+ box = manage (new VBox);
+
+ box->set_border_width (5);
+ box->set_spacing (1);
+
+ frame->add (*box);
+ hpacker.pack_start(*frame,true,true);
+
+ x = 0;
+ }
+ }
+
+ if ((cui = build_control_ui (engine, i, plugin->get_nth_control (i))) == 0) {
+ error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg;
+ continue;
+ }
+
+ if (cui->control || cui->clickbox || cui->combo) {
+
+ box->pack_start (*cui, false, false);
+
+ } else if (cui->button) {
+
+ if (button_row == button_rows) {
+ button_row = 0;
+ if (++button_col == button_cols) {
+ button_cols += 2;
+ button_table.resize (button_rows, button_cols);
+ }
+ }
+
+ button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1,
+ FILL|EXPAND, FILL);
+ button_row++;
+
+ } else if (cui->display) {
+
+ output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
+ FILL|EXPAND, FILL);
+
+ // TODO: The meters should be divided into multiple rows
+
+ if (++output_col == output_cols) {
+ output_cols ++;
+ output_table.resize (output_rows, output_cols);
+ }
+
+ /* old code, which divides meters into
+ * columns first, rows later. New code divides into one row
+
+ if (output_row == output_rows) {
+ output_row = 0;
+ if (++output_col == output_cols) {
+ output_cols += 2;
+ output_table.resize (output_rows, output_cols);
+ }
+ }
+
+ output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
+ FILL|EXPAND, FILL);
+
+ output_row++;
+ */
+ }
+
+ /* HACK: ideally the preferred height would be queried from
+ the complete hpacker, but I can't seem to get that
+ information in time, so this is an estimation
+ */
+
+ prefheight += 30;
+
+ }
+ }
+
+ n_ins = plugin->get_info()->n_inputs;
+ n_outs = plugin->get_info()->n_outputs;
+
+ if (box->children().empty()) {
+ hpacker.remove (*frame);
+ }
+
+ if (button_table.children().empty()) {
+ hpacker.remove (*bt_frame);
+ }
+
+ if (!output_table.children().empty()) {
+ frame = manage (new Frame);
+ frame->set_name ("BaseFrame");
+ frame->add (output_table);
+ hpacker.pack_end (*frame, true, true);
+ }
+
+ output_update ();
+
+ output_table.show_all ();
+ button_table.show_all ();
+}
+
+LadspaPluginUI::ControlUI::ControlUI ()
+ : automate_button (X_("")) // force creation of a label
+{
+ automate_button.set_name ("PluginAutomateButton");
+ ARDOUR_UI::instance()->tooltips().set_tip (automate_button,
+ _("Automation control"));
+
+ /* don't fix the height, it messes up the bar controllers */
+
+ set_size_request_to_display_given_text (automate_button, X_("lngnuf"), 2, 2);
+
+ ignore_change = 0;
+ display = 0;
+ button = 0;
+ control = 0;
+ clickbox = 0;
+ adjustment = 0;
+ meterinfo = 0;
+}
+
+LadspaPluginUI::ControlUI::~ControlUI()
+{
+ if (adjustment) {
+ delete adjustment;
+ }
+
+ if (meterinfo) {
+ delete meterinfo->meter;
+ delete meterinfo;
+ }
+}
+
+void
+LadspaPluginUI::automation_state_changed (ControlUI* cui)
+{
+ /* update button label */
+
+ switch (insert->get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) {
+ case Off:
+ cui->automate_button.set_label (_("Off"));
+ break;
+ case Play:
+ cui->automate_button.set_label (_("Play"));
+ break;
+ case Write:
+ cui->automate_button.set_label (_("Write"));
+ break;
+ case Touch:
+ cui->automate_button.set_label (_("Touch"));
+ break;
+ default:
+ cui->automate_button.set_label (_("???"));
+ break;
+ }
+}
+
+
+static void integer_printer (char buf[32], Adjustment &adj, void *arg)
+{
+ snprintf (buf, 32, "%.0f", adj.get_value());
+}
+
+void
+LadspaPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param)
+{
+ plugin->print_parameter (param, buf, len);
+}
+
+LadspaPluginUI::ControlUI*
+LadspaPluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Controllable* mcontrol)
+
+{
+ ControlUI* control_ui;
+ Plugin::ParameterDescriptor desc;
+
+ plugin->get_parameter_descriptor (port_index, desc);
+
+ control_ui = manage (new ControlUI ());
+ control_ui->adjustment = 0;
+ control_ui->combo = 0;
+ control_ui->combo_map = 0;
+ control_ui->port_index = port_index;
+ control_ui->update_pending = false;
+ control_ui->label.set_text (desc.label);
+ control_ui->label.set_alignment (0.0, 0.5);
+ control_ui->label.set_name ("PluginParameterLabel");
+
+ control_ui->set_spacing (5);
+
+ if (plugin->parameter_is_input (port_index)) {
+
+ boost::shared_ptr<LadspaPlugin> lp;
+
+ if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
+
+ lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index);
+
+ if (defaults && defaults->count > 0) {
+
+ control_ui->combo = new Gtk::ComboBoxText;
+ //control_ui->combo->set_value_in_list(true, false);
+ set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui));
+ control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_combo_changed), control_ui));
+ plugin->ParameterChanged.connect (bind (mem_fun (*this, &LadspaPluginUI::parameter_changed), control_ui));
+ control_ui->pack_start(control_ui->label, true, true);
+ control_ui->pack_start(*control_ui->combo, false, true);
+
+ update_control_display(control_ui);
+
+ lrdf_free_setting_values(defaults);
+ return control_ui;
+ }
+ }
+
+ if (desc.toggled) {
+
+ /* Build a button */
+
+ control_ui->button = manage (new ToggleButton ());
+ control_ui->button->set_name ("PluginEditorButton");
+ control_ui->button->set_size_request (20, 20);
+
+ control_ui->pack_start (control_ui->label, true, true);
+ control_ui->pack_start (*control_ui->button, false, true);
+ control_ui->pack_start (control_ui->automate_button, false, false);
+
+ control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::control_port_toggled), control_ui));
+
+ if(plugin->get_parameter (port_index) == 1){
+ control_ui->button->set_active(true);
+ }
+
+ return control_ui;
+ }
+
+ control_ui->adjustment = new Adjustment (0, 0, 0, 0, 0);
+
+ /* XXX this code is not right yet, because it doesn't handle
+ the absence of bounds in any sensible fashion.
+ */
+
+ control_ui->adjustment->set_lower (desc.lower);
+ control_ui->adjustment->set_upper (desc.upper);
+
+ control_ui->logarithmic = desc.logarithmic;
+ if (control_ui->logarithmic) {
+ if (control_ui->adjustment->get_lower() == 0.0) {
+ control_ui->adjustment->set_lower (control_ui->adjustment->get_upper()/10000);
+ }
+ control_ui->adjustment->set_upper (log(control_ui->adjustment->get_upper()));
+ control_ui->adjustment->set_lower (log(control_ui->adjustment->get_lower()));
+ }
+
+ float delta = desc.upper - desc.lower;
+
+ control_ui->adjustment->set_page_size (delta/100.0);
+ control_ui->adjustment->set_step_increment (desc.step);
+ control_ui->adjustment->set_page_increment (desc.largestep);
+
+ if (desc.integer_step) {
+ control_ui->clickbox = new ClickBox (control_ui->adjustment, "PluginUIClickBox");
+ Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2);
+ control_ui->clickbox->set_print_func (integer_printer, 0);
+ } else {
+ sigc::slot<void,char*,uint32_t> pslot = sigc::bind (mem_fun(*this, &LadspaPluginUI::print_parameter), (uint32_t) port_index);
+
+ control_ui->control = new BarController (*control_ui->adjustment, *mcontrol, pslot);
+ // should really match the height of the text in the automation button+label
+ control_ui->control->set_size_request (200, 22);
+ control_ui->control->set_name (X_("PluginSlider"));
+ control_ui->control->set_style (BarController::LeftToRight);
+ control_ui->control->set_use_parent (true);
+
+ control_ui->control->StartGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::start_touch), control_ui));
+ control_ui->control->StopGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::stop_touch), control_ui));
+
+ }
+
+ if (control_ui->logarithmic) {
+ control_ui->adjustment->set_value(log(plugin->get_parameter(port_index)));
+ } else{
+ control_ui->adjustment->set_value(plugin->get_parameter(port_index));
+ }
+
+ /* XXX memory leak: SliderController not destroyed by ControlUI
+ destructor, and manage() reports object hierarchy
+ ambiguity.
+ */
+
+ control_ui->pack_start (control_ui->label, true, true);
+ if (desc.integer_step) {
+ control_ui->pack_start (*control_ui->clickbox, false, false);
+ } else {
+ control_ui->pack_start (*control_ui->control, false, false);
+ }
+
+ control_ui->pack_start (control_ui->automate_button, false, false);
+ control_ui->adjustment->signal_value_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_adjustment_changed), control_ui));
+ control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::astate_clicked), control_ui, (uint32_t) port_index));
+
+ automation_state_changed (control_ui);
+
+ plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui));
+ insert->automation_list (port_index).automation_state_changed.connect
+ (bind (mem_fun(*this, &LadspaPluginUI::automation_state_changed), control_ui));
+
+ } else if (plugin->parameter_is_output (port_index)) {
+
+ control_ui->display = manage (new EventBox);
+ control_ui->display->set_name ("ParameterValueDisplay");
+
+ control_ui->display_label = manage (new Label);
+
+ control_ui->display_label->set_name ("ParameterValueDisplay");
+
+ control_ui->display->add (*control_ui->display_label);
+ Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->display, "-99,99", 2, 2);
+
+ control_ui->display->show_all ();
+
+ /* set up a meter */
+ /* TODO: only make a meter if the port is Hinted for it */
+
+ MeterInfo * info = new MeterInfo(port_index);
+ control_ui->meterinfo = info;
+
+ info->meter = new FastMeter (5, 100, FastMeter::Vertical);
+
+ info->min_unbound = desc.min_unbound;
+ info->max_unbound = desc.max_unbound;
+
+ info->min = desc.lower;
+ info->max = desc.upper;
+
+ control_ui->vbox = manage (new VBox);
+ control_ui->hbox = manage (new HBox);
+
+ control_ui->label.set_angle(90);
+ control_ui->hbox->pack_start (control_ui->label, false, false);
+ control_ui->hbox->pack_start (*info->meter, false, false);
+
+ control_ui->vbox->pack_start (*control_ui->hbox, false, false);
+
+ control_ui->vbox->pack_start (*control_ui->display, false, false);
+
+ control_ui->pack_start (*control_ui->vbox);
+
+ control_ui->meterinfo->meter->show_all();
+ control_ui->meterinfo->packed = true;
+
+ output_controls.push_back (control_ui);
+ }
+
+ plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui));
+ return control_ui;
+}
+
+void
+LadspaPluginUI::start_touch (LadspaPluginUI::ControlUI* cui)
+{
+ insert->automation_list (cui->port_index).start_touch ();
+}
+
+void
+LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui)
+{
+ insert->automation_list (cui->port_index).stop_touch ();
+}
+
+void
+LadspaPluginUI::astate_clicked (ControlUI* cui, uint32_t port)
+{
+ using namespace Menu_Helpers;
+
+ if (automation_menu == 0) {
+ automation_menu = manage (new Menu);
+ automation_menu->set_name ("ArdourContextMenu");
+ }
+
+ MenuList& items (automation_menu->items());
+
+ items.clear ();
+ items.push_back (MenuElem (_("Off"),
+ bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Off, cui)));
+ items.push_back (MenuElem (_("Play"),
+ bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Play, cui)));
+ items.push_back (MenuElem (_("Write"),
+ bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Write, cui)));
+ items.push_back (MenuElem (_("Touch"),
+ bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Touch, cui)));
+
+ automation_menu->popup (1, 0);
+}
+
+void
+LadspaPluginUI::set_automation_state (AutoState state, ControlUI* cui)
+{
+ insert->set_port_automation_state (cui->port_index, state);
+}
+
+void
+LadspaPluginUI::control_adjustment_changed (ControlUI* cui)
+{
+ if (cui->ignore_change) {
+ return;
+ }
+
+ double value = cui->adjustment->get_value();
+
+ if (cui->logarithmic) {
+ value = exp(value);
+ }
+
+ insert->set_parameter (cui->port_index, (float) value);
+}
+
+void
+LadspaPluginUI::parameter_changed (uint32_t abs_port_id, float val, ControlUI* cui)
+{
+ if (cui->port_index == abs_port_id) {
+ if (!cui->update_pending) {
+ cui->update_pending = true;
+ Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &LadspaPluginUI::update_control_display), cui));
+ }
+ }
+}
+
+void
+LadspaPluginUI::update_control_display (ControlUI* cui)
+{
+ /* XXX how do we handle logarithmic stuff here ? */
+
+ cui->update_pending = false;
+
+ float val = plugin->get_parameter (cui->port_index);
+
+ cui->ignore_change++;
+ if (cui->combo) {
+ std::map<string,float>::iterator it;
+ for (it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) {
+ if (it->second == val) {
+ cui->combo->set_active_text(it->first);
+ break;
+ }
+ }
+ } else if (cui->adjustment == 0) {
+
+ if (val > 0.5) {
+ cui->button->set_active (true);
+ } else {
+ cui->button->set_active (false);
+ }
+
+ } else {
+ if (cui->logarithmic) {
+ val = log(val);
+ }
+ if (val != cui->adjustment->get_value()) {
+ cui->adjustment->set_value (val);
+ }
+ }
+ cui->ignore_change--;
+}
+
+void
+LadspaPluginUI::control_port_toggled (ControlUI* cui)
+{
+ if (!cui->ignore_change) {
+ insert->set_parameter (cui->port_index, cui->button->get_active());
+ }
+}
+
+void
+LadspaPluginUI::control_combo_changed (ControlUI* cui)
+{
+ if (!cui->ignore_change) {
+ string value = cui->combo->get_active_text();
+ std::map<string,float> mapping = *cui->combo_map;
+ insert->set_parameter (cui->port_index, mapping[value]);
+ }
+
+}
+
+void
+LadspaPluginUI::redirect_active_changed (Redirect* r, void* src)
+{
+ ENSURE_GUI_THREAD(bind (mem_fun(*this, &LadspaPluginUI::redirect_active_changed), r, src));
+
+ bypass_button.set_active (!r->active());
+}
+
+bool
+LadspaPluginUI::start_updating (GdkEventAny* ignored)
+{
+ if (output_controls.size() > 0 ) {
+ screen_update_connection.disconnect();
+ screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
+ (mem_fun(*this, &LadspaPluginUI::output_update));
+ }
+ return false;
+}
+
+bool
+LadspaPluginUI::stop_updating (GdkEventAny* ignored)
+{
+ if (output_controls.size() > 0 ) {
+ screen_update_connection.disconnect();
+ }
+ return false;
+}
+
+void
+LadspaPluginUI::output_update ()
+{
+ for (vector<ControlUI*>::iterator i = output_controls.begin(); i != output_controls.end(); ++i) {
+ float val = plugin->get_parameter ((*i)->port_index);
+ char buf[32];
+ snprintf (buf, sizeof(buf), "%.2f", val);
+ (*i)->display_label->set_text (buf);
+
+ /* autoscaling for the meter */
+ if ((*i)->meterinfo && (*i)->meterinfo->packed) {
+
+ if (val < (*i)->meterinfo->min) {
+ if ((*i)->meterinfo->min_unbound)
+ (*i)->meterinfo->min = val;
+ else
+ val = (*i)->meterinfo->min;
+ }
+
+ if (val > (*i)->meterinfo->max) {
+ if ((*i)->meterinfo->max_unbound)
+ (*i)->meterinfo->max = val;
+ else
+ val = (*i)->meterinfo->max;
+ }
+
+ if ((*i)->meterinfo->max > (*i)->meterinfo->min ) {
+ float lval = (val - (*i)->meterinfo->min) / ((*i)->meterinfo->max - (*i)->meterinfo->min) ;
+ (*i)->meterinfo->meter->set (lval );
+ }
+ }
+ }
+}
+
+vector<string>
+LadspaPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
+{
+ vector<string> enums;
+ boost::shared_ptr<LadspaPlugin> lp = boost::dynamic_pointer_cast<LadspaPlugin> (plugin);
+
+ cui->combo_map = new std::map<string, float>;
+ lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index);
+ if (defaults) {
+ for (uint32_t i = 0; i < defaults->count; ++i) {
+ enums.push_back(defaults->items[i].label);
+ pair<string, float> newpair;
+ newpair.first = defaults->items[i].label;
+ newpair.second = defaults->items[i].value;
+ cui->combo_map->insert(newpair);
+ }
+
+ lrdf_free_setting_values(defaults);
+ }
+
+ return enums;
+}
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
new file mode 100644
index 0000000000..d716a5605a
--- /dev/null
+++ b/gtk2_ardour/midi_region_view.cc
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2001-2006 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 <cmath>
+#include <cassert>
+#include <algorithm>
+
+#include <gtkmm.h>
+
+#include <gtkmm2ext/gtk_ui.h>
+
+#include <ardour/playlist.h>
+#include <ardour/midi_region.h>
+#include <ardour/midi_source.h>
+#include <ardour/midi_diskstream.h>
+
+#include "streamview.h"
+#include "midi_region_view.h"
+#include "midi_time_axis.h"
+#include "simplerect.h"
+#include "simpleline.h"
+#include "public_editor.h"
+//#include "midi_region_editor.h"
+#include "ghostregion.h"
+#include "midi_time_axis.h"
+#include "utils.h"
+#include "rgb_macros.h"
+#include "gui_thread.h"
+
+#include "i18n.h"
+
+using namespace sigc;
+using namespace ARDOUR;
+using namespace PBD;
+using namespace Editing;
+using namespace ArdourCanvas;
+
+MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, MidiRegion& r, double spu,
+ Gdk::Color& basic_color)
+ : RegionView (parent, tv, r, spu, basic_color)
+{
+}
+
+MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, MidiRegion& r, double spu,
+ Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
+ : RegionView (parent, tv, r, spu, basic_color, visibility)
+{
+}
+
+void
+MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
+{
+ // FIXME: Some redundancy here with RegionView::init. Need to figure out
+ // where order is important and where it isn't...
+
+ RegionView::init(basic_color, wfd);
+
+ compute_colors (basic_color);
+
+ reset_width_dependent_items ((double) _region.length() / samples_per_unit);
+
+ set_height (trackview.height);
+
+ region_muted ();
+ region_resized (BoundsChanged);
+ region_locked ();
+
+ _region.StateChanged.connect (mem_fun(*this, &MidiRegionView::region_changed));
+
+ set_colors ();
+}
+
+MidiRegionView::~MidiRegionView ()
+{
+ in_destructor = true;
+
+ RegionViewGoingAway (this); /* EMIT_SIGNAL */
+}
+
+ARDOUR::MidiRegion&
+MidiRegionView::midi_region() const
+{
+ // "Guaranteed" to succeed...
+ return dynamic_cast<MidiRegion&>(_region);
+}
+
+void
+MidiRegionView::show_region_editor ()
+{
+ cerr << "No MIDI region editor." << endl;
+}
+
+GhostRegion*
+MidiRegionView::add_ghost (AutomationTimeAxisView& atv)
+{
+ return NULL;
+}
+
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
new file mode 100644
index 0000000000..3161d0eb05
--- /dev/null
+++ b/gtk2_ardour/midi_region_view.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2006 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 __gtk_ardour_midi_region_view_h__
+#define __gtk_ardour_midi_region_view_h__
+
+#include <vector>
+
+#include <libgnomecanvasmm.h>
+#include <libgnomecanvasmm/polygon.h>
+#include <sigc++/signal.h>
+#include <ardour/midi_region.h>
+
+#include "region_view.h"
+#include "route_time_axis.h"
+#include "time_axis_view_item.h"
+#include "automation_line.h"
+#include "enums.h"
+#include "canvas.h"
+#include "color.h"
+
+namespace ARDOUR {
+ class MidiRegion;
+};
+
+class MidiTimeAxisView;
+class GhostRegion;
+class AutomationTimeAxisView;
+
+class MidiRegionView : public RegionView
+{
+ public:
+ MidiRegionView (ArdourCanvas::Group *,
+ RouteTimeAxisView&,
+ ARDOUR::MidiRegion&,
+ double initial_samples_per_unit,
+ Gdk::Color& basic_color);
+
+ ~MidiRegionView ();
+
+ virtual void init (Gdk::Color& base_color, bool wait_for_data = false);
+
+ ARDOUR::MidiRegion& midi_region() const;
+
+ void show_region_editor ();
+
+ GhostRegion* add_ghost (AutomationTimeAxisView&);
+
+ protected:
+
+ /* this constructor allows derived types
+ to specify their visibility requirements
+ to the TimeAxisViewItem parent class
+ */
+
+ MidiRegionView (ArdourCanvas::Group *,
+ RouteTimeAxisView&,
+ ARDOUR::MidiRegion&,
+ double samples_per_unit,
+ Gdk::Color& basic_color,
+ TimeAxisViewItem::Visibility);
+
+ void region_moved (void *);
+
+ void set_flags (XMLNode *);
+ void store_flags ();
+};
+
+#endif /* __gtk_ardour_midi_region_view_h__ */
diff --git a/gtk2_ardour/new_session_dialog.cc b/gtk2_ardour/new_session_dialog.cc
index 47a2b2b6d3..993db62d59 100644
--- a/gtk2_ardour/new_session_dialog.cc
+++ b/gtk2_ardour/new_session_dialog.cc
@@ -141,15 +141,17 @@ NewSessionDialog::NewSessionDialog()
advanced_table->attach(*m_control_bus_channel_count, 1, 2, 2, 3, Gtk::AttachOptions(), Gtk::AttachOptions(), 0, 0);
advanced_table->attach(*m_master_bus_channel_count, 1, 2, 1, 2, Gtk::AttachOptions(), Gtk::AttachOptions(), 0, 0);
advanced_table->attach(*m_create_master_bus, 0, 1, 1, 2, Gtk::FILL, Gtk::AttachOptions(), 0, 0);
+
m_connect_inputs->set_flags(Gtk::CAN_FOCUS);
m_connect_inputs->set_relief(Gtk::RELIEF_NORMAL);
m_connect_inputs->set_mode(true);
- m_connect_inputs->set_active(false);
+ m_connect_inputs->set_active(true);
m_connect_inputs->set_border_width(0);
+
m_limit_input_ports->set_flags(Gtk::CAN_FOCUS);
m_limit_input_ports->set_relief(Gtk::RELIEF_NORMAL);
m_limit_input_ports->set_mode(true);
- m_limit_input_ports->set_sensitive(false);
+ m_limit_input_ports->set_sensitive(true);
m_limit_input_ports->set_border_width(0);
m_input_limit_count->set_flags(Gtk::CAN_FOCUS);
m_input_limit_count->set_update_policy(Gtk::UPDATE_ALWAYS);
@@ -157,6 +159,7 @@ NewSessionDialog::NewSessionDialog()
m_input_limit_count->set_digits(0);
m_input_limit_count->set_wrap(false);
m_input_limit_count->set_sensitive(false);
+
input_port_limit_hbox->pack_start(*m_limit_input_ports, Gtk::PACK_SHRINK, 6);
input_port_limit_hbox->pack_start(*m_input_limit_count, Gtk::PACK_EXPAND_PADDING, 0);
input_port_vbox->pack_start(*m_connect_inputs, Gtk::PACK_SHRINK, 0);
@@ -177,12 +180,12 @@ NewSessionDialog::NewSessionDialog()
m_connect_outputs->set_flags(Gtk::CAN_FOCUS);
m_connect_outputs->set_relief(Gtk::RELIEF_NORMAL);
m_connect_outputs->set_mode(true);
- m_connect_outputs->set_active(false);
+ m_connect_outputs->set_active(true);
m_connect_outputs->set_border_width(0);
m_limit_output_ports->set_flags(Gtk::CAN_FOCUS);
m_limit_output_ports->set_relief(Gtk::RELIEF_NORMAL);
m_limit_output_ports->set_mode(true);
- m_limit_output_ports->set_sensitive(false);
+ m_limit_output_ports->set_sensitive(true);
m_limit_output_ports->set_border_width(0);
m_output_limit_count->set_flags(Gtk::CAN_FOCUS);
m_output_limit_count->set_update_policy(Gtk::UPDATE_ALWAYS);
@@ -597,12 +600,24 @@ void
NewSessionDialog::connect_inputs_clicked ()
{
m_limit_input_ports->set_sensitive(m_connect_inputs->get_active());
+
+ if (m_connect_inputs->get_active() && m_limit_input_ports->get_active()) {
+ m_input_limit_count->set_sensitive(true);
+ } else {
+ m_input_limit_count->set_sensitive(false);
+ }
}
void
NewSessionDialog::connect_outputs_clicked ()
{
m_limit_output_ports->set_sensitive(m_connect_outputs->get_active());
+
+ if (m_connect_outputs->get_active() && m_limit_output_ports->get_active()) {
+ m_output_limit_count->set_sensitive(true);
+ } else {
+ m_output_limit_count->set_sensitive(false);
+ }
}
void
diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc
index e0a62b177f..6c72767b11 100644
--- a/gtk2_ardour/plugin_selector.cc
+++ b/gtk2_ardour/plugin_selector.cc
@@ -49,7 +49,7 @@ PluginSelector::PluginSelector (PluginManager *mgr)
manager = mgr;
session = 0;
- current_selection = PluginInfo::LADSPA;
+ current_selection = ARDOUR::LADSPA;
lmodel = Gtk::ListStore::create(lcols);
ladspa_display.set_model (lmodel);
@@ -141,6 +141,7 @@ PluginSelector::PluginSelector (PluginManager *mgr)
set_response_sensitive (RESPONSE_APPLY, false);
get_vbox()->pack_start (*table);
+ // Notebook tab order must be the same in here as in set_correct_focus()
using namespace Gtk::Notebook_Helpers;
notebook.pages().push_back (TabElem (lscroller, _("LADSPA")));
@@ -161,6 +162,7 @@ PluginSelector::PluginSelector (PluginManager *mgr)
ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed));
+ ladspa_display.grab_focus();
#ifdef VST_SUPPORT
if (Config->get_use_vst()) {
@@ -188,6 +190,43 @@ PluginSelector::PluginSelector (PluginManager *mgr)
#ifdef HAVE_COREAUDIO
au_refiller ();
#endif
+
+ signal_show().connect (mem_fun (*this, &PluginSelector::set_correct_focus));
+}
+
+/**
+ * Makes sure keyboard focus is always in the plugin list
+ * of the selected notebook tab.
+ **/
+void
+PluginSelector::set_correct_focus()
+{
+ int cp = notebook.get_current_page();
+
+ if (cp == 0) {
+ ladspa_display.grab_focus();
+ return;
+ }
+
+#ifdef VST_SUPPORT
+ if (Config->get_use_vst()) {
+ cp--;
+
+ if (cp == 0) {
+ vst_display.grab_focus();
+ return;
+ }
+ }
+#endif
+
+#ifdef HAVE_COREAUDIO
+ cp--;
+
+ if (cp == 0) {
+ au_display.grab_focus();
+ return;
+ }
+#endif
}
void
@@ -286,7 +325,7 @@ PluginSelector::vst_display_selection_changed()
btn_add->set_sensitive (false);
}
- current_selection = PluginInfo::VST;
+ current_selection = ARDOUR::VST;
}
#endif //VST_SUPPORT
@@ -332,7 +371,7 @@ PluginSelector::au_display_selection_changed()
btn_add->set_sensitive (false);
}
- current_selection = PluginInfo::AudioUnit;
+ current_selection = ARDOUR::AudioUnit;
}
#endif //HAVE_COREAUDIO
@@ -361,19 +400,19 @@ PluginSelector::btn_add_clicked()
Gtk::TreeModel::Row row;
switch (current_selection) {
- case PluginInfo::LADSPA:
+ case ARDOUR::LADSPA:
row = *(ladspa_display.get_selection()->get_selected());
name = row[lcols.name];
pi = row[lcols.plugin];
break;
- case PluginInfo::VST:
+ case ARDOUR::VST:
#ifdef VST_SUPPORT
row = *(vst_display.get_selection()->get_selected());
name = row[vcols.name];
pi = row[vcols.plugin];
#endif
break;
- case PluginInfo::AudioUnit:
+ case ARDOUR::AudioUnit:
#ifdef HAVE_COREAUDIO
row = *(au_display.get_selection()->get_selected());
name = row[aucols.name];
@@ -426,7 +465,7 @@ PluginSelector::ladspa_display_selection_changed()
btn_add->set_sensitive (false);
}
- current_selection = PluginInfo::LADSPA;
+ current_selection = ARDOUR::LADSPA;
}
void
diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h
index 583506972a..d71203131c 100644
--- a/gtk2_ardour/plugin_selector.h
+++ b/gtk2_ardour/plugin_selector.h
@@ -50,7 +50,7 @@ class PluginSelector : public ArdourDialog
Gtk::ScrolledWindow auscroller; // AudioUnit
Gtk::ScrolledWindow ascroller; // Added plugins
- ARDOUR::PluginInfo::Type current_selection;
+ ARDOUR::PluginType current_selection;
// page 1
struct LadspaColumns : public Gtk::TreeModel::ColumnRecord {
@@ -147,6 +147,8 @@ class PluginSelector : public ArdourDialog
void btn_apply_clicked();
void use_plugin (ARDOUR::PluginInfoPtr);
void cleanup ();
+
+ void set_correct_focus();
};
#endif // __ardour_plugin_selector_h__
diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc
index edc94864f2..f9db649737 100644
--- a/gtk2_ardour/plugin_ui.cc
+++ b/gtk2_ardour/plugin_ui.cc
@@ -27,6 +27,7 @@
#include <pbd/xml++.h>
#include <pbd/failed_constructor.h>
+#include <gtkmm/widget.h>
#include <gtkmm2ext/click_box.h>
#include <gtkmm2ext/fastmeter.h>
#include <gtkmm2ext/barcontroller.h>
@@ -51,6 +52,7 @@
#include "plugin_ui.h"
#include "utils.h"
#include "gui_thread.h"
+#include "public_editor.h"
#include "i18n.h"
@@ -111,626 +113,22 @@ PluginUIWindow::PluginUIWindow (AudioEngine &engine, boost::shared_ptr<PluginIns
if (h > 600) h = 600;
set_default_size (450, h);
}
-}
-
-PluginUIWindow::~PluginUIWindow ()
-{
-}
-
-LadspaPluginUI::LadspaPluginUI (AudioEngine &engine, boost::shared_ptr<PluginInsert> pi, bool scrollable)
- : PlugUIBase (pi),
- engine(engine),
- button_table (initial_button_rows, initial_button_cols),
- output_table (initial_output_rows, initial_output_cols),
- hAdjustment(0.0, 0.0, 0.0),
- vAdjustment(0.0, 0.0, 0.0),
- scroller_view(hAdjustment, vAdjustment),
- automation_menu (0),
- is_scrollable(scrollable)
-{
- set_name ("PluginEditor");
- set_border_width (10);
- set_homogeneous (false);
-
- settings_box.set_homogeneous (false);
-
- HBox* constraint_hbox = manage (new HBox);
- HBox* smaller_hbox = manage (new HBox);
- Label* combo_label = manage (new Label (_("<span size=\"large\">Presets</span>")));
- combo_label->set_use_markup (true);
-
- smaller_hbox->pack_start (*combo_label, false, false, 10);
- smaller_hbox->pack_start (combo, false, false);
- smaller_hbox->pack_start (save_button, false, false);
-
- constraint_hbox->set_spacing (5);
- constraint_hbox->pack_start (*smaller_hbox, true, false);
- constraint_hbox->pack_end (bypass_button, false, false);
-
- settings_box.pack_end (*constraint_hbox, false, false);
-
- pack_start (settings_box, false, false);
-
- if ( is_scrollable ) {
- scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
- scroller.set_name ("PluginEditor");
- scroller_view.set_name("PluginEditor");
- scroller_view.add (hpacker);
- scroller.add (scroller_view);
-
- pack_start (scroller, true, true);
-
- }
- else {
- pack_start (hpacker, false, false);
- }
-
- insert->active_changed.connect (mem_fun(*this, &LadspaPluginUI::redirect_active_changed));
- bypass_button.set_active (!insert->active());
-
- build (engine);
-}
-
-LadspaPluginUI::~LadspaPluginUI ()
-{
- if (output_controls.size() > 0) {
- screen_update_connection.disconnect();
- }
-}
-
-void
-LadspaPluginUI::build (AudioEngine &engine)
-
-{
- guint32 i = 0;
- guint32 x = 0;
- Frame* frame;
- Frame* bt_frame;
- VBox* box;
- int output_row, output_col;
- int button_row, button_col;
- int output_rows, output_cols;
- int button_rows, button_cols;
- guint32 n_ins=0, n_outs = 0;
-
- prefheight = 30;
- hpacker.set_spacing (10);
-
- output_rows = initial_output_rows;
- output_cols = initial_output_cols;
- button_rows = initial_button_rows;
- button_cols = initial_button_cols;
- output_row = 0;
- button_row = 0;
- output_col = 0;
- button_col = 0;
-
- button_table.set_homogeneous (false);
- button_table.set_row_spacings (2);
- button_table.set_col_spacings (2);
- output_table.set_homogeneous (true);
- output_table.set_row_spacings (2);
- output_table.set_col_spacings (2);
- button_table.set_border_width (5);
- output_table.set_border_width (5);
-
- hpacker.set_border_width (10);
-
- bt_frame = manage (new Frame);
- bt_frame->set_name ("BaseFrame");
- bt_frame->add (button_table);
- hpacker.pack_start(*bt_frame, true, true);
-
- box = manage (new VBox);
- box->set_border_width (5);
- box->set_spacing (1);
-
- frame = manage (new Frame);
- frame->set_name ("BaseFrame");
- frame->set_label (_("Controls"));
- frame->add (*box);
- hpacker.pack_start(*frame, true, true);
-
- /* find all ports. build control elements for all appropriate control ports */
-
- for (i = 0; i < plugin->parameter_count(); ++i) {
-
- if (plugin->parameter_is_control (i)) {
-
- /* Don't show latency control ports */
-
- if (plugin->describe_parameter (i) == X_("latency")) {
- continue;
- }
-
- ControlUI* cui;
-
- /* if we are scrollable, just use one long column */
-
- if (!is_scrollable) {
- if (x++ > 7){
- frame = manage (new Frame);
- frame->set_name ("BaseFrame");
- box = manage (new VBox);
-
- box->set_border_width (5);
- box->set_spacing (1);
-
- frame->add (*box);
- hpacker.pack_start(*frame,true,true);
-
- x = 0;
- }
- }
-
- if ((cui = build_control_ui (engine, i, plugin->get_nth_control (i))) == 0) {
- error << string_compose(_("Plugin Editor: could not build control element for port %1"), i) << endmsg;
- continue;
- }
-
- if (cui->control || cui->clickbox || cui->combo) {
-
- box->pack_start (*cui, false, false);
-
- } else if (cui->button) {
-
- if (button_row == button_rows) {
- button_row = 0;
- if (++button_col == button_cols) {
- button_cols += 2;
- button_table.resize (button_rows, button_cols);
- }
- }
-
- button_table.attach (*cui, button_col, button_col + 1, button_row, button_row+1,
- FILL|EXPAND, FILL);
- button_row++;
-
- } else if (cui->display) {
-
- output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
- FILL|EXPAND, FILL);
-
- // TODO: The meters should be divided into multiple rows
-
- if (++output_col == output_cols) {
- output_cols ++;
- output_table.resize (output_rows, output_cols);
- }
-
- /* old code, which divides meters into
- * columns first, rows later. New code divides into one row
-
- if (output_row == output_rows) {
- output_row = 0;
- if (++output_col == output_cols) {
- output_cols += 2;
- output_table.resize (output_rows, output_cols);
- }
- }
-
- output_table.attach (*cui, output_col, output_col + 1, output_row, output_row+1,
- FILL|EXPAND, FILL);
-
- output_row++;
- */
- }
-
- /* HACK: ideally the preferred height would be queried from
- the complete hpacker, but I can't seem to get that
- information in time, so this is an estimation
- */
-
- prefheight += 30;
-
- }
- }
-
- n_ins = plugin->get_info()->n_inputs;
- n_outs = plugin->get_info()->n_outputs;
-
- if (box->children().empty()) {
- hpacker.remove (*frame);
- }
-
- if (button_table.children().empty()) {
- hpacker.remove (*bt_frame);
- }
-
- if (!output_table.children().empty()) {
- frame = manage (new Frame);
- frame->set_name ("BaseFrame");
- frame->add (output_table);
- hpacker.pack_end (*frame, true, true);
- }
-
- output_update ();
-
- output_table.show_all ();
- button_table.show_all ();
-}
-
-LadspaPluginUI::ControlUI::ControlUI ()
- : automate_button (X_("")) // force creation of a label
-{
- automate_button.set_name ("PluginAutomateButton");
- ARDOUR_UI::instance()->tooltips().set_tip (automate_button,
- _("Automation control"));
-
- /* don't fix the height, it messes up the bar controllers */
-
- set_size_request_to_display_given_text (automate_button, X_("lngnuf"), 2, 2);
-
- ignore_change = 0;
- display = 0;
- button = 0;
- control = 0;
- clickbox = 0;
- adjustment = 0;
- meterinfo = 0;
-}
-
-LadspaPluginUI::ControlUI::~ControlUI()
-{
- if (adjustment) {
- delete adjustment;
- }
-
- if (meterinfo) {
- delete meterinfo->meter;
- delete meterinfo;
- }
-}
-
-void
-LadspaPluginUI::automation_state_changed (ControlUI* cui)
-{
- /* update button label */
-
- switch (insert->get_port_automation_state (cui->port_index) & (Off|Play|Touch|Write)) {
- case Off:
- cui->automate_button.set_label (_("Off"));
- break;
- case Play:
- cui->automate_button.set_label (_("Play"));
- break;
- case Write:
- cui->automate_button.set_label (_("Write"));
- break;
- case Touch:
- cui->automate_button.set_label (_("Touch"));
- break;
- default:
- cui->automate_button.set_label (_("???"));
- break;
- }
-}
-
-
-static void integer_printer (char buf[32], Adjustment &adj, void *arg)
-{
- snprintf (buf, 32, "%.0f", adj.get_value());
-}
-
-void
-LadspaPluginUI::print_parameter (char *buf, uint32_t len, uint32_t param)
-{
- plugin->print_parameter (param, buf, len);
-}
-
-LadspaPluginUI::ControlUI*
-LadspaPluginUI::build_control_ui (AudioEngine &engine, guint32 port_index, PBD::Controllable* mcontrol)
-
-{
- ControlUI* control_ui;
- Plugin::ParameterDescriptor desc;
-
- plugin->get_parameter_descriptor (port_index, desc);
-
- control_ui = manage (new ControlUI ());
- control_ui->adjustment = 0;
- control_ui->combo = 0;
- control_ui->combo_map = 0;
- control_ui->port_index = port_index;
- control_ui->update_pending = false;
- control_ui->label.set_text (desc.label);
- control_ui->label.set_alignment (0.0, 0.5);
- control_ui->label.set_name ("PluginParameterLabel");
-
- control_ui->set_spacing (5);
-
- if (plugin->parameter_is_input (port_index)) {
-
- boost::shared_ptr<LadspaPlugin> lp;
-
- if ((lp = boost::dynamic_pointer_cast<LadspaPlugin>(plugin)) != 0) {
-
- lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index);
-
- if (defaults && defaults->count > 0) {
-
- control_ui->combo = new Gtk::ComboBoxText;
- //control_ui->combo->set_value_in_list(true, false);
- set_popdown_strings (*control_ui->combo, setup_scale_values(port_index, control_ui));
- control_ui->combo->signal_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_combo_changed), control_ui));
- plugin->ParameterChanged.connect (bind (mem_fun (*this, &LadspaPluginUI::parameter_changed), control_ui));
- control_ui->pack_start(control_ui->label, true, true);
- control_ui->pack_start(*control_ui->combo, false, true);
-
- update_control_display(control_ui);
-
- lrdf_free_setting_values(defaults);
- return control_ui;
- }
- }
-
- if (desc.toggled) {
-
- /* Build a button */
-
- control_ui->button = manage (new ToggleButton ());
- control_ui->button->set_name ("PluginEditorButton");
- control_ui->button->set_size_request (20, 20);
-
- control_ui->pack_start (control_ui->label, true, true);
- control_ui->pack_start (*control_ui->button, false, true);
- control_ui->pack_start (control_ui->automate_button, false, false);
-
- control_ui->button->signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::control_port_toggled), control_ui));
-
- if(plugin->get_parameter (port_index) == 1){
- control_ui->button->set_active(true);
- }
-
- return control_ui;
- }
-
- control_ui->adjustment = new Adjustment (0, 0, 0, 0, 0);
-
- /* XXX this code is not right yet, because it doesn't handle
- the absence of bounds in any sensible fashion.
- */
-
- control_ui->adjustment->set_lower (desc.lower);
- control_ui->adjustment->set_upper (desc.upper);
-
- control_ui->logarithmic = desc.logarithmic;
- if (control_ui->logarithmic) {
- if (control_ui->adjustment->get_lower() == 0.0) {
- control_ui->adjustment->set_lower (control_ui->adjustment->get_upper()/10000);
- }
- control_ui->adjustment->set_upper (log(control_ui->adjustment->get_upper()));
- control_ui->adjustment->set_lower (log(control_ui->adjustment->get_lower()));
- }
-
- float delta = desc.upper - desc.lower;
-
- control_ui->adjustment->set_page_size (delta/100.0);
- control_ui->adjustment->set_step_increment (desc.step);
- control_ui->adjustment->set_page_increment (desc.largestep);
-
- if (desc.integer_step) {
- control_ui->clickbox = new ClickBox (control_ui->adjustment, "PluginUIClickBox");
- Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->clickbox, "g9999999", 2, 2);
- control_ui->clickbox->set_print_func (integer_printer, 0);
- } else {
- sigc::slot<void,char*,uint32_t> pslot = sigc::bind (mem_fun(*this, &LadspaPluginUI::print_parameter), (uint32_t) port_index);
-
- control_ui->control = new BarController (*control_ui->adjustment, *mcontrol, pslot);
- // should really match the height of the text in the automation button+label
- control_ui->control->set_size_request (200, 22);
- control_ui->control->set_name (X_("PluginSlider"));
- control_ui->control->set_style (BarController::LeftToRight);
- control_ui->control->set_use_parent (true);
-
- control_ui->control->StartGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::start_touch), control_ui));
- control_ui->control->StopGesture.connect (bind (mem_fun(*this, &LadspaPluginUI::stop_touch), control_ui));
-
- }
-
- if (control_ui->logarithmic) {
- control_ui->adjustment->set_value(log(plugin->get_parameter(port_index)));
- } else{
- control_ui->adjustment->set_value(plugin->get_parameter(port_index));
- }
-
- /* XXX memory leak: SliderController not destroyed by ControlUI
- destructor, and manage() reports object hierarchy
- ambiguity.
- */
-
- control_ui->pack_start (control_ui->label, true, true);
- if (desc.integer_step) {
- control_ui->pack_start (*control_ui->clickbox, false, false);
- } else {
- control_ui->pack_start (*control_ui->control, false, false);
- }
-
- control_ui->pack_start (control_ui->automate_button, false, false);
- control_ui->adjustment->signal_value_changed().connect (bind (mem_fun(*this, &LadspaPluginUI::control_adjustment_changed), control_ui));
- control_ui->automate_button.signal_clicked().connect (bind (mem_fun(*this, &LadspaPluginUI::astate_clicked), control_ui, (uint32_t) port_index));
-
- automation_state_changed (control_ui);
-
- plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui));
- insert->automation_list (port_index).automation_state_changed.connect
- (bind (mem_fun(*this, &LadspaPluginUI::automation_state_changed), control_ui));
-
- } else if (plugin->parameter_is_output (port_index)) {
-
- control_ui->display = manage (new EventBox);
- control_ui->display->set_name ("ParameterValueDisplay");
-
- control_ui->display_label = manage (new Label);
-
- control_ui->display_label->set_name ("ParameterValueDisplay");
-
- control_ui->display->add (*control_ui->display_label);
- Gtkmm2ext::set_size_request_to_display_given_text (*control_ui->display, "-99,99", 2, 2);
- control_ui->display->show_all ();
-
- /* set up a meter */
- /* TODO: only make a meter if the port is Hinted for it */
-
- MeterInfo * info = new MeterInfo(port_index);
- control_ui->meterinfo = info;
-
- info->meter = new FastMeter (5, 100, FastMeter::Vertical);
-
- info->min_unbound = desc.min_unbound;
- info->max_unbound = desc.max_unbound;
-
- info->min = desc.lower;
- info->max = desc.upper;
-
- control_ui->vbox = manage (new VBox);
- control_ui->hbox = manage (new HBox);
-
- control_ui->label.set_angle(90);
- control_ui->hbox->pack_start (control_ui->label, false, false);
- control_ui->hbox->pack_start (*info->meter, false, false);
-
- control_ui->vbox->pack_start (*control_ui->hbox, false, false);
-
- control_ui->vbox->pack_start (*control_ui->display, false, false);
-
- control_ui->pack_start (*control_ui->vbox);
-
- control_ui->meterinfo->meter->show_all();
- control_ui->meterinfo->packed = true;
-
- output_controls.push_back (control_ui);
- }
-
- plugin->ParameterChanged.connect (bind (mem_fun(*this, &LadspaPluginUI::parameter_changed), control_ui));
- return control_ui;
-}
-
-void
-LadspaPluginUI::start_touch (LadspaPluginUI::ControlUI* cui)
-{
- insert->automation_list (cui->port_index).start_touch ();
-}
-
-void
-LadspaPluginUI::stop_touch (LadspaPluginUI::ControlUI* cui)
-{
- insert->automation_list (cui->port_index).stop_touch ();
-}
-
-void
-LadspaPluginUI::astate_clicked (ControlUI* cui, uint32_t port)
-{
- using namespace Menu_Helpers;
-
- if (automation_menu == 0) {
- automation_menu = manage (new Menu);
- automation_menu->set_name ("ArdourContextMenu");
- }
-
- MenuList& items (automation_menu->items());
-
- items.clear ();
- items.push_back (MenuElem (_("Off"),
- bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Off, cui)));
- items.push_back (MenuElem (_("Play"),
- bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Play, cui)));
- items.push_back (MenuElem (_("Write"),
- bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Write, cui)));
- items.push_back (MenuElem (_("Touch"),
- bind (mem_fun(*this, &LadspaPluginUI::set_automation_state), (AutoState) Touch, cui)));
-
- automation_menu->popup (1, 0);
-}
-
-void
-LadspaPluginUI::set_automation_state (AutoState state, ControlUI* cui)
-{
- insert->set_port_automation_state (cui->port_index, state);
-}
-
-void
-LadspaPluginUI::control_adjustment_changed (ControlUI* cui)
-{
- if (cui->ignore_change) {
- return;
- }
-
- double value = cui->adjustment->get_value();
-
- if (cui->logarithmic) {
- value = exp(value);
- }
-
- insert->set_parameter (cui->port_index, (float) value);
-}
-
-void
-LadspaPluginUI::parameter_changed (uint32_t abs_port_id, float val, ControlUI* cui)
-{
- if (cui->port_index == abs_port_id) {
- if (!cui->update_pending) {
- cui->update_pending = true;
- Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &LadspaPluginUI::update_control_display), cui));
- }
- }
}
-void
-LadspaPluginUI::update_control_display (ControlUI* cui)
+PluginUIWindow::~PluginUIWindow ()
{
- /* XXX how do we handle logarithmic stuff here ? */
-
- cui->update_pending = false;
-
- float val = plugin->get_parameter (cui->port_index);
-
- cui->ignore_change++;
- if (cui->combo) {
- std::map<string,float>::iterator it;
- for (it = cui->combo_map->begin(); it != cui->combo_map->end(); ++it) {
- if (it->second == val) {
- cui->combo->set_active_text(it->first);
- break;
- }
- }
- } else if (cui->adjustment == 0) {
-
- if (val > 0.5) {
- cui->button->set_active (true);
- } else {
- cui->button->set_active (false);
- }
-
- } else {
- if (cui->logarithmic) {
- val = log(val);
- }
- if (val != cui->adjustment->get_value()) {
- cui->adjustment->set_value (val);
- }
- }
- cui->ignore_change--;
}
-
-void
-LadspaPluginUI::control_port_toggled (ControlUI* cui)
+bool
+PluginUIWindow::on_key_press_event (GdkEventKey* event)
{
- if (!cui->ignore_change) {
- insert->set_parameter (cui->port_index, cui->button->get_active());
- }
+ return PublicEditor::instance().on_key_press_event(event);
}
-void
-LadspaPluginUI::control_combo_changed (ControlUI* cui)
+bool
+PluginUIWindow::on_key_release_event (GdkEventKey* event)
{
- if (!cui->ignore_change) {
- string value = cui->combo->get_active_text();
- std::map<string,float> mapping = *cui->combo_map;
- insert->set_parameter (cui->port_index, mapping[value]);
- }
-
+ return PublicEditor::instance().on_key_release_event(event);
}
void
@@ -742,91 +140,6 @@ PluginUIWindow::plugin_going_away (ARDOUR::Redirect* ignored)
delete_when_idle (this);
}
-void
-LadspaPluginUI::redirect_active_changed (Redirect* r, void* src)
-{
- ENSURE_GUI_THREAD(bind (mem_fun(*this, &LadspaPluginUI::redirect_active_changed), r, src));
-
- bypass_button.set_active (!r->active());
-}
-
-bool
-LadspaPluginUI::start_updating (GdkEventAny* ignored)
-{
- if (output_controls.size() > 0 ) {
- screen_update_connection.disconnect();
- screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect
- (mem_fun(*this, &LadspaPluginUI::output_update));
- }
- return false;
-}
-
-bool
-LadspaPluginUI::stop_updating (GdkEventAny* ignored)
-{
- if (output_controls.size() > 0 ) {
- screen_update_connection.disconnect();
- }
- return false;
-}
-
-void
-LadspaPluginUI::output_update ()
-{
- for (vector<ControlUI*>::iterator i = output_controls.begin(); i != output_controls.end(); ++i) {
- float val = plugin->get_parameter ((*i)->port_index);
- char buf[32];
- snprintf (buf, sizeof(buf), "%.2f", val);
- (*i)->display_label->set_text (buf);
-
- /* autoscaling for the meter */
- if ((*i)->meterinfo && (*i)->meterinfo->packed) {
-
- if (val < (*i)->meterinfo->min) {
- if ((*i)->meterinfo->min_unbound)
- (*i)->meterinfo->min = val;
- else
- val = (*i)->meterinfo->min;
- }
-
- if (val > (*i)->meterinfo->max) {
- if ((*i)->meterinfo->max_unbound)
- (*i)->meterinfo->max = val;
- else
- val = (*i)->meterinfo->max;
- }
-
- if ((*i)->meterinfo->max > (*i)->meterinfo->min ) {
- float lval = (val - (*i)->meterinfo->min) / ((*i)->meterinfo->max - (*i)->meterinfo->min) ;
- (*i)->meterinfo->meter->set (lval );
- }
- }
- }
-}
-
-vector<string>
-LadspaPluginUI::setup_scale_values(guint32 port_index, ControlUI* cui)
-{
- vector<string> enums;
- boost::shared_ptr<LadspaPlugin> lp = boost::dynamic_pointer_cast<LadspaPlugin> (plugin);
-
- cui->combo_map = new std::map<string, float>;
- lrdf_defaults* defaults = lrdf_get_scale_values(lp->unique_id(), port_index);
- if (defaults) {
- for (uint32_t i = 0; i < defaults->count; ++i) {
- enums.push_back(defaults->items[i].label);
- pair<string, float> newpair;
- newpair.first = defaults->items[i].label;
- newpair.second = defaults->items[i].value;
- cui->combo_map->insert(newpair);
- }
-
- lrdf_free_setting_values(defaults);
- }
-
- return enums;
-}
-
PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
: insert (pi),
plugin (insert->plugin()),
@@ -893,4 +206,3 @@ PlugUIBase::bypass_toggled ()
insert->set_active (!x, this);
}
}
-
diff --git a/gtk2_ardour/plugin_ui.h b/gtk2_ardour/plugin_ui.h
index dc1e61887b..acd22294dd 100644
--- a/gtk2_ardour/plugin_ui.h
+++ b/gtk2_ardour/plugin_ui.h
@@ -203,13 +203,15 @@ class PluginUIWindow : public ArdourDialog
PlugUIBase& pluginui() { return *_pluginui; }
void resize_preferred();
+
+ virtual bool on_key_press_event (GdkEventKey*);
+ virtual bool on_key_release_event (GdkEventKey*);
private:
PlugUIBase* _pluginui;
void plugin_going_away (ARDOUR::Redirect*);
};
-
#ifdef VST_SUPPORT
class VSTPluginUI : public PlugUIBase, public Gtk::VBox
{
@@ -235,16 +237,12 @@ class VSTPluginUI : public PlugUIBase, public Gtk::VBox
#endif // VST_SUPPORT
#ifdef HAVE_COREAUDIO
-class AUPluginUI : public PlugUIBase
+class AUPluginUI
{
public:
- AUPluginUI (boost::shared_ptr<ARDOUR::PluginInsert>, boost::shared_ptr<ARDOUR::AUPlugin>);
+ AUPluginUI (ARDOUR::AudioEngine&, boost::shared_ptr<ARDOUR::PluginInsert>);
~AUPluginUI ();
- gint get_preferred_height ();
- bool start_updating(GdkEventAny*) {return false;}
- bool stop_updating(GdkEventAny*) {return false;}
-
private:
boost::shared_ptr<ARDOUR::AUPlugin> au;
};
diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h
index aa30a828a8..cb3d62f625 100644
--- a/gtk2_ardour/public_editor.h
+++ b/gtk2_ardour/public_editor.h
@@ -31,6 +31,7 @@ namespace Gtk {
class Editor;
class TimeAxisViewItem;
class TimeAxisView;
+class PluginUIWindow;
class PluginSelector;
class PlaylistSelector;
class XMLNode;
@@ -172,6 +173,8 @@ class PublicEditor : public Gtk::Window, public Stateful {
virtual bool canvas_markerview_end_handle_event(GdkEvent* event, ArdourCanvas::Item*,MarkerView*) = 0;
static PublicEditor* _instance;
+
+ friend class PluginUIWindow;
};
#endif // __gtk_ardour_public_editor_h__
diff --git a/gtk2_ardour/redirect_box.cc b/gtk2_ardour/redirect_box.cc
index 74198265d9..ddb9e85ca2 100644
--- a/gtk2_ardour/redirect_box.cc
+++ b/gtk2_ardour/redirect_box.cc
@@ -957,44 +957,61 @@ RedirectBox::edit_redirect (boost::shared_ptr<Redirect> redirect)
if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (insert)) != 0) {
- PluginUIWindow *plugin_ui;
+ ARDOUR::PluginType type = plugin_insert->type();
+
+ if (type == ARDOUR::LADSPA || type == ARDOUR::VST) {
+ PluginUIWindow *plugin_ui;
- if (plugin_insert->get_gui() == 0) {
+ if (plugin_insert->get_gui() == 0) {
- string title;
- string maker = plugin_insert->plugin()->maker();
- string::size_type email_pos;
+ string title;
+ string maker = plugin_insert->plugin()->maker();
+ string::size_type email_pos;
- if ((email_pos = maker.find_first_of ('<')) != string::npos) {
- maker = maker.substr (0, email_pos - 1);
- }
+ if ((email_pos = maker.find_first_of ('<')) != string::npos) {
+ maker = maker.substr (0, email_pos - 1);
+ }
- if (maker.length() > 32) {
- maker = maker.substr (0, 32);
- maker += " ...";
- }
+ if (maker.length() > 32) {
+ maker = maker.substr (0, 32);
+ maker += " ...";
+ }
- title = string_compose(_("ardour: %1: %2 (by %3)"), _route->name(), plugin_insert->name(), maker);
+ title = string_compose(_("ardour: %1: %2 (by %3)"), _route->name(), plugin_insert->name(), maker);
+
+ plugin_ui = new PluginUIWindow (_session.engine(), plugin_insert);
+ if (_owner_is_mixer) {
+ ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui);
+ } else {
+ ARDOUR_UI::instance()->the_editor().ensure_float (*plugin_ui);
+ }
+ plugin_ui->set_title (title);
+ plugin_insert->set_gui (plugin_ui);
- plugin_ui = new PluginUIWindow (_session.engine(), plugin_insert);
- if (_owner_is_mixer) {
- ARDOUR_UI::instance()->the_mixer()->ensure_float (*plugin_ui);
} else {
- ARDOUR_UI::instance()->the_editor().ensure_float (*plugin_ui);
+ plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
}
- plugin_ui->set_title (title);
- plugin_insert->set_gui (plugin_ui);
-
- } else {
- plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
- }
- if (plugin_ui->is_visible()) {
- plugin_ui->get_window()->raise ();
+ if (plugin_ui->is_visible()) {
+ plugin_ui->get_window()->raise ();
+ } else {
+ plugin_ui->show_all ();
+ }
+#ifdef HAVE_COREAUDIO
+ } else if (type == ARDOUR::AudioUnit) {
+ AUPluginUI* plugin_ui;
+ if (plugin_insert->get_gui() == 0) {
+ plugin_ui = new AUPluginUI (_session.engine(), plugin_insert);
+ } else {
+ plugin_ui = reinterpret_cast<AUPluginUI*> (plugin_insert->get_gui());
+ }
+
+ // raise window, somehow
+#endif
} else {
- plugin_ui->show_all ();
+ warning << "Unsupported plugin sent to RedirectBox::edit_redirect()" << endmsg;
+ return;
}
-
} else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (insert)) != 0) {
if (!_session.engine().connected()) {
diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc
index 0fff2e5d7b..db8f345574 100644
--- a/gtk2_ardour/region_view.cc
+++ b/gtk2_ardour/region_view.cc
@@ -250,6 +250,14 @@ RegionView::reset_width_dependent_items (double pixel_width)
}
void
+RegionView::set_height (gdouble height)
+{
+ TimeAxisViewItem::set_height (height - 2);
+
+ _height = height;
+}
+
+void
RegionView::region_layered ()
{
RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*>(&get_time_axis_view());
@@ -393,10 +401,6 @@ RegionView::region_renamed ()
str = _region.name();
}
- if (_region.speed_mismatch (trackview.session().frame_rate())) {
- str = string ("*") + str;
- }
-
if (_region.muted()) {
str = string ("!") + str;
}
diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h
index d2d2c22760..beb4f10d54 100644
--- a/gtk2_ardour/region_view.h
+++ b/gtk2_ardour/region_view.h
@@ -56,7 +56,7 @@ class RegionView : public TimeAxisViewItem
bool is_valid() const { return valid; }
void set_valid (bool yn) { valid = yn; }
- virtual void set_height (double) = 0;
+ virtual void set_height (double);
virtual void set_samples_per_unit (double);
virtual bool set_duration (jack_nframes_t, void*);
@@ -121,7 +121,7 @@ class RegionView : public TimeAxisViewItem
void region_locked ();
void region_opacity ();
void region_layered ();
- void region_renamed ();
+ virtual void region_renamed ();
void region_sync_changed ();
static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*);
diff --git a/gtk2_ardour/tape_region_view.cc b/gtk2_ardour/tape_region_view.cc
index bd5ce8af02..4110ad7d98 100644
--- a/gtk2_ardour/tape_region_view.cc
+++ b/gtk2_ardour/tape_region_view.cc
@@ -68,7 +68,7 @@ TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw)
/* every time the wave data changes and peaks are ready, redraw */
for (uint32_t n = 0; n < audio_region().n_channels(); ++n) {
- audio_region().source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n));
+ audio_region().audio_source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n));
}
}
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index feb93ec293..7230a0622b 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -34,6 +34,11 @@ audio_library.cc
audio_playlist.cc
audio_track.cc
audioengine.cc
+port.cc
+audio_port.cc
+midi_port.cc
+port_set.cc
+buffer.cc
audiofilesource.cc
audiofilter.cc
audioregion.cc
@@ -72,7 +77,6 @@ playlist.cc
playlist_factory.cc
plugin.cc
plugin_manager.cc
-port.cc
recent_sessions.cc
redirect.cc
region.cc
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index e2dfc5fd0c..0cc2079d8e 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -211,11 +211,11 @@ class AudioDiskstream : public Diskstream
/* The two central butler operations */
int do_flush (Session::RunContext context, bool force = false);
- int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, _conversion_buffer); }
+ int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer); }
int do_refill_with_alloc();
- int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf,
+ int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
jack_nframes_t& start, jack_nframes_t cnt,
ChannelInfo& channel_info, int channel, bool reversed);
@@ -251,10 +251,9 @@ class AudioDiskstream : public Diskstream
static size_t _working_buffers_size;
static Sample* _mixdown_buffer;
static gain_t* _gain_buffer;
- static char* _conversion_buffer;
- // Uh, /really/ private? (death to friend classes)
- int _do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf);
+ // Uh, /really/ private? (there should probably be less friends of Diskstream)
+ int _do_refill (Sample *mixdown_buffer, float *gain_buffer);
std::vector<AudioFileSource*> capturing_sources;
diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h
new file mode 100644
index 0000000000..1eab294028
--- /dev/null
+++ b/libs/ardour/ardour/audio_port.h
@@ -0,0 +1,110 @@
+/*
+ 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.
+
+ $Id: port.h 712 2006-07-28 01:08:57Z drobilla $
+*/
+
+#ifndef __ardour_audio_port_h__
+#define __ardour_audio_port_h__
+
+#include <sigc++/signal.h>
+#include <pbd/failed_constructor.h>
+#include <ardour/ardour.h>
+#include <jack/jack.h>
+#include <ardour/port.h>
+#include <ardour/buffer.h>
+
+namespace ARDOUR {
+
+class AudioEngine;
+
+class AudioPort : public Port {
+ public:
+ virtual ~AudioPort() {
+ free (_port);
+ }
+
+ void cycle_start(jack_nframes_t nframes);
+ void cycle_end();
+
+ DataType type() const { return DataType(DataType::AUDIO); }
+
+ Buffer& get_buffer () {
+ return _buffer;
+ }
+
+ AudioBuffer& get_audio_buffer() {
+ return _buffer;
+ }
+
+ void reset_overs () {
+ _short_overs = 0;
+ _long_overs = 0;
+ _overlen = 0;
+ }
+
+ void reset_peak_meter () {
+ _peak = 0;
+ }
+
+ void reset_meters () {
+ reset_peak_meter ();
+ reset_overs ();
+ }
+
+ float peak_db() const { return _peak_db; }
+ jack_default_audio_sample_t peak() const { return _peak; }
+
+ uint32_t short_overs () const { return _short_overs; }
+ uint32_t long_overs () const { return _long_overs; }
+
+ static void set_short_over_length (jack_nframes_t);
+ static void set_long_over_length (jack_nframes_t);
+
+ /** Assumes that the port is an audio output port */
+ void silence (jack_nframes_t nframes, jack_nframes_t offset) {
+ if (!_silent) {
+ _buffer.clear(offset);
+ if (offset == 0 && nframes == _buffer.capacity()) {
+ _silent = true;
+ }
+ }
+ }
+
+ protected:
+ friend class AudioEngine;
+
+ AudioPort (jack_port_t *port);
+ void reset ();
+
+ /* engine isn't supposed to access below here */
+
+ AudioBuffer _buffer;
+
+ jack_nframes_t _overlen;
+ jack_default_audio_sample_t _peak;
+ float _peak_db;
+ uint32_t _short_overs;
+ uint32_t _long_overs;
+
+ static jack_nframes_t _long_over_length;
+ static jack_nframes_t _short_over_length;
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_audio_port_h__ */
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index 15b99297c8..9892179085 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -51,7 +51,7 @@ class AudioTrack : public Track
int use_diskstream (string name);
int use_diskstream (const PBD::ID& id);
- int export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame);
+ int export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t nframes, jack_nframes_t end_frame);
void freeze (InterThreadInfo&);
void unfreeze ();
diff --git a/libs/ardour/ardour/audio_unit.h b/libs/ardour/ardour/audio_unit.h
index 1c8d6cbc2d..348a8ff863 100644
--- a/libs/ardour/ardour/audio_unit.h
+++ b/libs/ardour/ardour/audio_unit.h
@@ -96,6 +96,8 @@ class AUPlugin : public ARDOUR::Plugin
std::vector<std::pair<uint32_t, uint32_t> > parameter_map;
};
+typedef boost::shared_ptr<AUPlugin> AUPluginPtr;
+
class AUPluginInfo : public PluginInfo {
public:
AUPluginInfo () { };
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index e7500fc7a2..72989abb59 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -119,21 +119,19 @@ class AudioEngine : public sigc::trackable
uint32_t n_physical_outputs () const;
uint32_t n_physical_inputs () const;
- std::string get_nth_physical_output (uint32_t n) {
- return get_nth_physical (n, JackPortIsInput);
+ std::string get_nth_physical_output (DataType type, uint32_t n) {
+ return get_nth_physical (type, n, JackPortIsInput);
}
- std::string get_nth_physical_input (uint32_t n) {
- return get_nth_physical (n, JackPortIsOutput);
+ std::string get_nth_physical_input (DataType type, uint32_t n) {
+ return get_nth_physical (type, n, JackPortIsOutput);
}
jack_nframes_t get_port_total_latency (const Port&);
void update_total_latencies ();
- /* the caller may not delete the object pointed to by
- the return value
+ /** Caller may not delete the object pointed to by the return value
*/
-
Port *get_port_by_name (const std::string& name, bool keep = true);
enum TransportState {
@@ -219,7 +217,7 @@ class AudioEngine : public sigc::trackable
PortConnections port_connections;
void remove_connections_for (Port*);
- std::string get_nth_physical (uint32_t which, int flags);
+ std::string get_nth_physical (DataType type, uint32_t n, int flags);
static int _xrun_callback (void *arg);
static int _graph_order_callback (void *arg);
diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h
index 5a77067f8f..bd76c30289 100644
--- a/libs/ardour/ardour/audioplaylist.h
+++ b/libs/ardour/ardour/audioplaylist.h
@@ -60,7 +60,7 @@ class AudioPlaylist : public ARDOUR::Playlist
void clear (bool with_delete = false, bool with_save = true);
- jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
+ jack_nframes_t read (Sample *dst, Sample *mixdown, float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
int set_state (const XMLNode&);
UndoAction get_memento() const;
diff --git a/libs/ardour/ardour/audioregion.h b/libs/ardour/ardour/audioregion.h
index 683e946713..fd2cc8d2f1 100644
--- a/libs/ardour/ardour/audioregion.h
+++ b/libs/ardour/ardour/audioregion.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2001 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -57,8 +57,6 @@ struct AudioRegionState : public RegionState
class AudioRegion : public Region
{
public:
- typedef vector<AudioSource *> SourceList;
-
static Change FadeInChanged;
static Change FadeOutChanged;
static Change FadeInActiveChanged;
@@ -76,26 +74,18 @@ class AudioRegion : public Region
AudioRegion (SourceList &, const XMLNode&);
~AudioRegion();
- bool source_equivalent (const Region&) const;
-
bool speed_mismatch (float) const;
- void lock_sources ();
- void unlock_sources ();
- AudioSource& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; }
+ AudioSource& audio_source (uint32_t n=0) const;
- void set_scale_amplitude (gain_t);
+ void set_scale_amplitude (gain_t);
gain_t scale_amplitude() const { return _scale_amplitude; }
void normalize_to (float target_in_dB = 0.0f);
- uint32_t n_channels() { return sources.size(); }
- vector<string> master_source_names();
-
bool envelope_active () const { return _flags & Region::EnvelopeActive; }
bool fade_in_active () const { return _flags & Region::FadeIn; }
bool fade_out_active () const { return _flags & Region::FadeOut; }
- bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); }
Curve& fade_in() { return _fade_in; }
Curve& fade_out() { return _fade_out; }
@@ -106,13 +96,12 @@ class AudioRegion : public Region
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buf,
- float *gain_buf, char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
+ float *gain_buf, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
- jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buf,
- float *gain_buf, char * workbuf,
+ jack_nframes_t master_read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf,
jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const;
XMLNode& state (bool);
@@ -152,8 +141,6 @@ class AudioRegion : public Region
int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&);
- Region* get_parent();
-
/* xfade/fade interactions */
void suspend_fade_in ();
@@ -177,28 +164,17 @@ class AudioRegion : public Region
void recompute_gain_at_start ();
jack_nframes_t _read_at (const SourceList&, Sample *buf, Sample *mixdown_buffer,
- float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
+ float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
- bool verify_start (jack_nframes_t position);
- bool verify_length (jack_nframes_t position);
- bool verify_start_mutable (jack_nframes_t& start);
- bool verify_start_and_length (jack_nframes_t start, jack_nframes_t length);
void recompute_at_start ();
void recompute_at_end ();
void envelope_changed (Change);
- void source_deleted (Source*);
-
- SourceList sources;
-
- /** Used when timefx are applied, so we can always use the original source. */
- SourceList master_sources;
-
mutable Curve _fade_in;
FadeShape _fade_in_shape;
mutable Curve _fade_out;
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 35158a24e7..4af857c1d6 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -50,24 +50,11 @@ class AudioSource : public Source
AudioSource (string name);
AudioSource (const XMLNode&);
virtual ~AudioSource ();
-
- /* one could argue that this should belong to Source, but other data types
- generally do not come with a model of "offset along an audio timeline"
- so its here in AudioSource for now.
- */
-
- virtual jack_nframes_t natural_position() const { return 0; }
- /* returns the number of items in this `audio_source' */
-
- virtual jack_nframes_t length() const {
- return _length;
- }
-
virtual jack_nframes_t available_peaks (double zoom) const;
- virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const;
- virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt, char * workbuf);
+ virtual jack_nframes_t read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
+ virtual jack_nframes_t write (Sample *src, jack_nframes_t cnt);
virtual float sample_rate () const = 0;
@@ -111,7 +98,6 @@ class AudioSource : public Source
bool _peaks_built;
mutable Glib::Mutex _lock;
- jack_nframes_t _length;
bool next_peak_clear_should_notify;
string peakpath;
string _captured_for;
@@ -124,13 +110,11 @@ class AudioSource : public Source
int do_build_peak (jack_nframes_t, jack_nframes_t);
- virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const = 0;
- virtual jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf) = 0;
+ virtual jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const = 0;
+ virtual jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt) = 0;
virtual string peak_path(string audio_path) = 0;
virtual string old_peak_path(string audio_path) = 0;
- void update_length (jack_nframes_t pos, jack_nframes_t cnt);
-
static pthread_t peak_thread;
static bool have_peak_thread;
static void* peak_thread_work(void*);
diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h
index 1321f6c107..981d941de7 100644
--- a/libs/ardour/ardour/buffer.h
+++ b/libs/ardour/ardour/buffer.h
@@ -19,19 +19,15 @@
#ifndef __ardour_buffer_h__
#define __ardour_buffer_h__
-#define _XOPEN_SOURCE 600
-#include <cstdlib> // for posix_memalign
+#include <cstdlib>
#include <cassert>
+#include <iostream>
#include <ardour/types.h>
#include <ardour/data_type.h>
namespace ARDOUR {
-/* Yes, this is a bit of a mess right now. I'll clean it up when everything
- * using it works out.. */
-
-
/** A buffer of recordable/playable data.
*
* This is a datatype-agnostic base class for all buffers (there are no
@@ -44,12 +40,11 @@ namespace ARDOUR {
class Buffer
{
public:
- Buffer(DataType type, size_t capacity)
- : _type(type), _capacity(capacity), _size(0)
- {}
-
virtual ~Buffer() {}
+ /** Factory function */
+ static Buffer* create(DataType type, size_t capacity);
+
/** Maximum capacity of buffer.
* Note in some cases the entire buffer may not contain valid data, use size. */
size_t capacity() const { return _capacity; }
@@ -61,10 +56,24 @@ public:
* Based on this you can static cast a Buffer* to the desired type. */
DataType type() const { return _type; }
+ /** Clear (eg zero, or empty) buffer starting at TIME @a offset */
+ virtual void clear(jack_nframes_t offset = 0) = 0;
+
+ virtual void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t len) = 0;
+
protected:
+ Buffer(DataType type, size_t capacity)
+ : _type(type), _capacity(capacity), _size(0)
+ {}
+
DataType _type;
size_t _capacity;
size_t _size;
+
+private:
+ // Prevent copies (undefined)
+ Buffer(const Buffer& copy);
+ void operator=(const Buffer& other);
};
@@ -75,28 +84,51 @@ protected:
class AudioBuffer : public Buffer
{
public:
- AudioBuffer(size_t capacity)
- : Buffer(DataType::AUDIO, capacity)
- , _data(NULL)
+ AudioBuffer(size_t capacity);
+
+ ~AudioBuffer();
+
+ void clear(jack_nframes_t offset=0) { memset(_data + offset, 0, sizeof (Sample) * _capacity); }
+
+ /** Copy @a len frames starting at @a offset, from the start of @a src */
+ void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t len)
+ {
+ assert(src.type() == _type == DataType::AUDIO);
+ assert(offset + len <= _capacity);
+ memcpy(_data + offset, ((AudioBuffer&)src).data(len, offset), sizeof(Sample) * len);
+ }
+
+ /** Copy @a len frames starting at @a offset, from the start of @a src */
+ void write(const Sample* src, jack_nframes_t offset, jack_nframes_t len)
+ {
+ assert(offset + len <= _capacity);
+ memcpy(_data + offset, src, sizeof(Sample) * len);
+ }
+
+ /** Set the data contained by this buffer manually (for setting directly to jack buffer).
+ *
+ * Constructor MUST have been passed capacity=0 or this will die (to prevent mem leaks).
+ */
+ void set_data(Sample* data, size_t size)
{
- _size = capacity; // For audio buffers, size = capacity (always)
-#ifdef NO_POSIX_MEMALIGN
- _data = (Sample *) malloc(sizeof(Sample) * capacity);
-#else
- posix_memalign((void**)_data, 16, sizeof(Sample) * capacity);
-#endif
- assert(_data);
- memset(_data, 0, sizeof(Sample) * capacity);
+ assert(!_owns_data); // prevent leaks
+ _capacity = size;
+ _size = size;
+ _data = data;
}
- const Sample* data() const { return _data; }
- Sample* data() { return _data; }
+ const Sample* data(jack_nframes_t nframes, jack_nframes_t offset=0) const
+ { assert(offset + nframes <= _capacity); return _data + offset; }
+
+ Sample* data(jack_nframes_t nframes, jack_nframes_t offset=0)
+ { assert(offset + nframes <= _capacity); return _data + offset; }
private:
// These are undefined (prevent copies)
AudioBuffer(const AudioBuffer& copy);
AudioBuffer& operator=(const AudioBuffer& copy);
+ bool _owns_data;
Sample* _data; ///< Actual buffer contents
};
@@ -106,19 +138,16 @@ private:
class MidiBuffer : public Buffer
{
public:
- MidiBuffer(size_t capacity)
- : Buffer(DataType::MIDI, capacity)
- , _data(NULL)
- {
- _size = capacity; // For audio buffers, size = capacity (always)
-#ifdef NO_POSIX_MEMALIGN
- _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity);
-#else
- posix_memalign((void**)_data, 16, sizeof(RawMidi) * capacity);
-#endif
- assert(_data);
- memset(_data, 0, sizeof(RawMidi) * capacity);
- }
+ MidiBuffer(size_t capacity);
+
+ ~MidiBuffer();
+
+ // FIXME: clear events starting at offset
+ void clear(jack_nframes_t offset=0) { assert(offset == 0); _size = 0; }
+
+ void write(const Buffer& src, jack_nframes_t offset, jack_nframes_t nframes);
+
+ void set_size(size_t size) { _size = size; }
const RawMidi* data() const { return _data; }
RawMidi* data() { return _data; }
@@ -128,10 +157,10 @@ private:
MidiBuffer(const MidiBuffer& copy);
MidiBuffer& operator=(const MidiBuffer& copy);
+ bool _owns_data;
RawMidi* _data; ///< Actual buffer contents
};
-
} // namespace ARDOUR
#endif // __ardour_buffer_h__
diff --git a/libs/ardour/ardour/chan_count.h b/libs/ardour/ardour/chan_count.h
new file mode 100644
index 0000000000..2ef49793d1
--- /dev/null
+++ b/libs/ardour/ardour/chan_count.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2006 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.
+
+ $Id: insert.cc 712 2006-07-28 01:08:57Z drobilla $
+*/
+
+#ifndef __ardour_chan_count_h__
+#define __ardour_chan_count_h__
+
+#include <ardour/data_type.h>
+
+namespace ARDOUR {
+
+
+class ChanCount {
+public:
+ ChanCount() { reset(); }
+
+ // Convenience constructor for making single-typed streams (stereo, mono, etc)
+ ChanCount(DataType type, size_t channels)
+ {
+ reset();
+ set_count(type, channels);
+ }
+
+ void reset()
+ {
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ _counts[(*t).to_index()] = 0;
+ }
+ }
+
+ void set_count(DataType type, size_t count) { _counts[type.to_index()] = count; }
+ size_t get_count(DataType type) const { return _counts[type.to_index()]; }
+
+ size_t get_total_count() const
+ {
+ size_t ret = 0;
+ for (size_t i=0; i < DataType::num_types; ++i)
+ ret += _counts[i];
+
+ return ret;
+ }
+
+ bool operator==(const ChanCount& other) const
+ {
+ for (size_t i=0; i < DataType::num_types; ++i)
+ if (_counts[i] != other._counts[i])
+ return false;
+
+ return true;
+ }
+
+ bool operator!=(const ChanCount& other) const
+ {
+ return ! (*this == other);
+ }
+
+private:
+ size_t _counts[DataType::num_types];
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_chan_count_h__
+
diff --git a/libs/ardour/ardour/coreaudiosource.h b/libs/ardour/ardour/coreaudiosource.h
index ba9f122fc9..cf25c466ee 100644
--- a/libs/ardour/ardour/coreaudiosource.h
+++ b/libs/ardour/ardour/coreaudiosource.h
@@ -38,9 +38,9 @@ class CoreAudioSource : public AudioFileSource {
void set_header_timeline_position () {};
protected:
- jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const;
+ jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
- jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf)
+ jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt)
{ return 0; }
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index ebafa0e8cc..aea7b31852 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -92,7 +92,7 @@ class Crossfade : public Stateful, public StateManager
ARDOUR::AudioRegion& out() const { return *_out; }
jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
- float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
+ float *gain_buffer, jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0);
diff --git a/libs/ardour/ardour/data_type.h b/libs/ardour/ardour/data_type.h
index d49ed108cd..cbb88afccf 100644
--- a/libs/ardour/ardour/data_type.h
+++ b/libs/ardour/ardour/data_type.h
@@ -19,54 +19,112 @@
#ifndef __ardour_data_type_h__
#define __ardour_data_type_h__
+#include <string>
+#include <ardour/data_type.h>
#include <jack/jack.h>
namespace ARDOUR {
+
+/** A type of Data Ardour is capable of processing.
+ *
+ * The majority of this class is dedicated to conversion to and from various
+ * other type representations, simple comparison between then, etc. This code
+ * is deliberately 'ugly' so other code doesn't have to be.
+ */
class DataType
{
public:
+ /// WARNING: make REALLY sure you don't mess up indexes if you change this
enum Symbol {
NIL = 0,
AUDIO,
MIDI
};
+
+ /** Number of types (not including NIL).
+ * WARNING: make sure this matches Symbol!
+ */
+ static const size_t num_types = 2;
+
+
+ /** Helper for collections that store typed things by index (BufferSet, PortList).
+ * Guaranteed to be a valid index from 0 to (the number of available types - 1),
+ * because NIL is not included. No, this isn't pretty - purely for speed.
+ * See DataType::to_index().
+ */
+ inline static size_t symbol_index(const Symbol symbol)
+ { return (size_t)symbol - 1; }
DataType(const Symbol& symbol)
: _symbol(symbol)
{}
- /** Construct from a string (Used for loading from XML) */
- DataType(const string& str) {
+ /** Construct from a string (Used for loading from XML and Ports)
+ * The string can be as in an XML file (eg "audio" or "midi"), or a
+ * Jack type string (from jack_port_type) */
+ DataType(const std::string& str) {
if (str == "audio")
_symbol = AUDIO;
- //else if (str == "midi")
- // _symbol = MIDI;
+ else if (str == JACK_DEFAULT_AUDIO_TYPE)
+ _symbol = AUDIO;
+ else if (str == "midi")
+ _symbol = MIDI;
+ else if (str == JACK_DEFAULT_MIDI_TYPE)
+ _symbol = MIDI;
else
_symbol = NIL;
}
- bool operator==(const Symbol symbol) { return _symbol == symbol; }
- bool operator!=(const Symbol symbol) { return _symbol != symbol; }
-
/** Get the Jack type this DataType corresponds to */
- const char* to_jack_type() {
+ const char* to_jack_type() const {
switch (_symbol) {
case AUDIO: return JACK_DEFAULT_AUDIO_TYPE;
- //case MIDI: return JACK_DEFAULT_MIDI_TYPE;
+ case MIDI: return JACK_DEFAULT_MIDI_TYPE;
default: return "";
}
}
/** Inverse of the from-string constructor */
- const char* to_string() {
+ const char* to_string() const {
switch (_symbol) {
case AUDIO: return "audio";
- //case MIDI: return "midi";
+ case MIDI: return "midi";
default: return "unknown"; // reeeally shouldn't ever happen
}
}
+ Symbol to_symbol() const { return _symbol; }
+ inline size_t to_index() const { return symbol_index(_symbol); }
+
+ /** DataType iterator, for writing generic loops that iterate over all
+ * available types.
+ */
+ class iterator {
+ public:
+
+ iterator(size_t index) : _index(index) {}
+
+ DataType operator*() { return DataType((Symbol)_index); }
+ iterator& operator++() { ++_index; return *this; } // yes, prefix only
+ bool operator==(const iterator& other) { return (_index == other._index); }
+ bool operator!=(const iterator& other) { return (_index != other._index); }
+
+ private:
+ friend class DataType;
+
+ size_t _index;
+ };
+
+ static iterator begin() { return iterator(1); }
+ static iterator end() { return iterator(num_types+1); }
+
+ bool operator==(const Symbol symbol) { return (_symbol == symbol); }
+ bool operator!=(const Symbol symbol) { return (_symbol != symbol); }
+
+ bool operator==(const DataType other) { return (_symbol == other._symbol); }
+ bool operator!=(const DataType other) { return (_symbol != other._symbol); }
+
private:
Symbol _symbol;
};
diff --git a/libs/ardour/ardour/destructive_filesource.h b/libs/ardour/ardour/destructive_filesource.h
index 5b773898c3..fb2a3be47b 100644
--- a/libs/ardour/ardour/destructive_filesource.h
+++ b/libs/ardour/ardour/destructive_filesource.h
@@ -49,7 +49,7 @@ class DestructiveFileSource : public SndFileSource {
static void setup_standard_crossfades (jack_nframes_t sample_rate);
protected:
- jack_nframes_t write_unlocked (Sample *src, jack_nframes_t cnt, char * workbuf);
+ jack_nframes_t write_unlocked (Sample *src, jack_nframes_t cnt);
virtual void handle_header_position_change ();
@@ -65,7 +65,7 @@ class DestructiveFileSource : public SndFileSource {
Sample* xfade_buf;
void init ();
- jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir, char * workbuf);
+ jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir);
void set_timeline_position (jack_nframes_t);
};
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index ebce516d8b..08dea4fb27 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -69,9 +69,9 @@ class Diskstream : public Stateful, public sigc::trackable
ARDOUR::IO* io() const { return _io; }
void set_io (ARDOUR::IO& io);
- virtual Diskstream& ref() { _refcnt++; return *this; }
- void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
- uint32_t refcnt() const { return _refcnt; }
+ Diskstream& ref() { _refcnt++; return *this; }
+ void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
+ uint32_t refcnt() const { return _refcnt; }
virtual float playback_buffer_load() const = 0;
virtual float capture_buffer_load() const = 0;
@@ -117,8 +117,8 @@ class Diskstream : public Stateful, public sigc::trackable
uint32_t n_channels() { return _n_channels; }
- static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
- static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; }
+ static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
+ static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; }
/* Stateful */
virtual XMLNode& get_state(void) = 0;
diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h
index a4c4439942..c81d4e5761 100644
--- a/libs/ardour/ardour/insert.h
+++ b/libs/ardour/ardour/insert.h
@@ -29,6 +29,7 @@
#include <ardour/ardour.h>
#include <ardour/redirect.h>
#include <ardour/plugin_state.h>
+#include <ardour/types.h>
class XMLNode;
@@ -39,8 +40,8 @@ namespace MIDI {
namespace ARDOUR {
class Session;
-class Plugin;
class Route;
+class Plugin;
class Insert : public Redirect
{
@@ -149,6 +150,8 @@ class PluginInsert : public Insert
}
}
+ PluginType type ();
+
string describe_parameter (uint32_t);
jack_nframes_t latency();
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index b116a58b97..818916f185 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -40,6 +40,7 @@
#include <ardour/curve.h>
#include <ardour/types.h>
#include <ardour/data_type.h>
+#include <ardour/port_set.h>
using std::string;
using std::vector;
@@ -50,9 +51,11 @@ namespace ARDOUR {
class Session;
class AudioEngine;
-class Port;
class Connection;
class Panner;
+class Port;
+class AudioPort;
+class MidiPort;
/** A collection of input and output ports with connections.
*
@@ -139,23 +142,28 @@ class IO : public Stateful, public ARDOUR::StateManager
void set_port_latency (jack_nframes_t);
Port *output (uint32_t n) const {
- if (n < _noutputs) {
- return _outputs[n];
+ if (n < _outputs.num_ports()) {
+ return _outputs.port(n);
} else {
return 0;
}
}
Port *input (uint32_t n) const {
- if (n < _ninputs) {
- return _inputs[n];
+ if (n < _inputs.num_ports()) {
+ return _inputs.port(n);
} else {
return 0;
}
}
- uint32_t n_inputs () const { return _ninputs; }
- uint32_t n_outputs () const { return _noutputs; }
+ AudioPort* audio_input(uint32_t n) const;
+ AudioPort* audio_output(uint32_t n) const;
+ MidiPort* midi_input(uint32_t n) const;
+ MidiPort* midi_output(uint32_t n) const;
+
+ uint32_t n_inputs () const { return _inputs.num_ports(); }
+ uint32_t n_outputs () const { return _outputs.num_ports(); }
sigc::signal<void,IOChange,void*> input_changed;
sigc::signal<void,IOChange,void*> output_changed;
@@ -195,7 +203,7 @@ class IO : public Stateful, public ARDOUR::StateManager
/* Peak metering */
float peak_input_power (uint32_t n) {
- if (n < std::max (_ninputs, _noutputs)) {
+ if (n < std::max (n_inputs(), n_outputs())) {
return _visible_peak_power[n];
} else {
return minus_infinity();
@@ -269,30 +277,30 @@ public:
mutable Glib::Mutex io_lock;
protected:
- Session& _session;
- Panner* _panner;
- gain_t _gain;
- gain_t _effective_gain;
- gain_t _desired_gain;
- Glib::Mutex declick_lock;
- vector<Port*> _outputs;
- vector<Port*> _inputs;
- vector<float> _peak_power;
- vector<float> _visible_peak_power;
- string _name;
- Connection* _input_connection;
- Connection* _output_connection;
- PBD::ID _id;
- bool no_panner_reset;
- XMLNode* deferred_state;
- DataType _default_type;
+ Session& _session;
+ Panner* _panner;
+ gain_t _gain;
+ gain_t _effective_gain;
+ gain_t _desired_gain;
+ Glib::Mutex declick_lock;
+ PortSet _outputs;
+ PortSet _inputs;
+ vector<float> _peak_power;
+ vector<float> _visible_peak_power;
+ string _name;
+ Connection* _input_connection;
+ Connection* _output_connection;
+ PBD::ID _id;
+ bool no_panner_reset;
+ XMLNode* deferred_state;
+ DataType _default_type;
virtual void set_deferred_state() {}
void reset_peak_meters();
void reset_panner ();
- virtual uint32_t pans_required() const { return _ninputs; }
+ virtual uint32_t pans_required() const { return n_inputs(); }
static void apply_declick (vector<Sample*>&, uint32_t nbufs, jack_nframes_t nframes,
gain_t initial, gain_t target, bool invert_polarity);
@@ -339,8 +347,6 @@ public:
private:
- uint32_t _ninputs;
- uint32_t _noutputs;
/* are these the best variable names ever, or what? */
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 7877bfaf1c..a048cf4021 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -24,6 +24,7 @@
#include <sigc++/signal.h>
#include <cmath>
+#include <cassert>
#include <string>
#include <queue>
#include <map>
@@ -61,27 +62,20 @@ class MidiDiskstream : public Diskstream
MidiDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable);
MidiDiskstream (Session &, const XMLNode&);
- void set_io (ARDOUR::IO& io);
-
- MidiDiskstream& ref() { _refcnt++; return *this; }
- //void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
- //uint32_t refcnt() const { return _refcnt; }
-
float playback_buffer_load() const;
float capture_buffer_load() const;
-
- //void set_align_style (AlignStyle);
- //void set_persistent_align_style (AlignStyle);
+
+ RawMidi* playback_buffer () { return _current_playback_buffer; }
+ RawMidi* capture_buffer () { return _current_capture_buffer; }
void set_record_enabled (bool yn);
- //void set_speed (double);
+
+ MidiPlaylist* midi_playlist () { return dynamic_cast<MidiPlaylist*>(_playlist); }
int use_playlist (Playlist *);
int use_new_playlist ();
int use_copy_playlist ();
- Playlist *playlist () { return _playlist; }
-
/* stateful */
XMLNode& get_state(void);
@@ -89,8 +83,6 @@ class MidiDiskstream : public Diskstream
void monitor_input (bool);
- //void handle_input_change (IOChange, void *src);
-
protected:
friend class Session;
@@ -108,12 +100,8 @@ class MidiDiskstream : public Diskstream
void reset_write_sources (bool, bool force = false);
void non_realtime_input_change ();
- uint32_t read_data_count() const { return _read_data_count; }
- uint32_t write_data_count() const { return _write_data_count; }
-
protected:
- friend class Auditioner;
- int seek (jack_nframes_t which_sample, bool complete_refill = false);
+ int seek (jack_nframes_t which_sample, bool complete_refill = false);
protected:
friend class MidiTrack;
@@ -126,30 +114,17 @@ class MidiDiskstream : public Diskstream
/* use unref() to destroy a diskstream */
~MidiDiskstream();
- MidiPlaylist* _playlist;
-
- /*Tthe two central butler operations */
- int do_flush (Session::RunContext context, bool force = false) { return 0; }
- int do_refill () { return 0; }
+ /* The two central butler operations */
+ int do_flush (Session::RunContext context, bool force = false);
+ int do_refill ();
- int do_refill_with_alloc() { return 0; }
-
- int read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
-
- /* XXX fix this redundancy ... */
+ int do_refill_with_alloc();
- //void playlist_changed (Change);
- //void playlist_modified ();
- void playlist_deleted (Playlist*);
+ int read (RawMidi* buf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
void finish_capture (bool rec_monitors_input);
void transport_stopped (struct tm&, time_t, bool abort);
- struct CaptureInfo {
- uint32_t start;
- uint32_t frames;
- };
-
void init (Diskstream::Flag);
int use_new_write_source (uint32_t n=0);
@@ -158,9 +133,6 @@ class MidiDiskstream : public Diskstream
void allocate_temporary_buffers ();
- //bool realtime_set_speed (double, bool global_change);
- void non_realtime_set_speed ();
-
int use_pending_capture_data (XMLNode& node);
void get_input_sources ();
@@ -169,8 +141,21 @@ class MidiDiskstream : public Diskstream
void setup_destructive_playlist ();
void use_destructive_playlist ();
- std::list<Region*> _last_capture_regions;
- std::vector<SMFSource*> _capturing_sources;
+ void engage_record_enable ();
+ void disengage_record_enable ();
+
+ // FIXME: This is basically a single ChannelInfo.. abstractify that concept?
+ RingBufferNPT<RawMidi>* _playback_buf;
+ RingBufferNPT<RawMidi>* _capture_buf;
+ RawMidi* _current_playback_buffer;
+ RawMidi* _current_capture_buffer;
+ RawMidi* _playback_wrap_buffer;
+ RawMidi* _capture_wrap_buffer;
+ MidiPort* _source_port;
+ SMFSource* _write_source; ///< aka capturing source
+ RingBufferNPT<CaptureTransition>* _capture_transition_buf;
+ RingBufferNPT<RawMidi>::rw_vector _playback_vector;
+ RingBufferNPT<RawMidi>::rw_vector _capture_vector;
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h
index da3a72a3fd..51cb00822e 100644
--- a/libs/ardour/ardour/midi_playlist.h
+++ b/libs/ardour/ardour/midi_playlist.h
@@ -55,8 +55,8 @@ public:
MidiPlaylist (const MidiPlaylist&, jack_nframes_t start, jack_nframes_t cnt,
string name, bool hidden = false);
- jack_nframes_t read (unsigned char *dst, unsigned char *mixdown,
- char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
+ jack_nframes_t read (RawMidi *dst, RawMidi *mixdown,
+ jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
int set_state (const XMLNode&);
UndoAction get_memento() const;
diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h
new file mode 100644
index 0000000000..9b1092f300
--- /dev/null
+++ b/libs/ardour/ardour/midi_port.h
@@ -0,0 +1,72 @@
+/*
+ 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.
+
+ $Id: port.h 712 2006-07-28 01:08:57Z drobilla $
+*/
+
+#ifndef __ardour_midi_port_h__
+#define __ardour_midi_port_h__
+
+#include <sigc++/signal.h>
+#include <pbd/failed_constructor.h>
+#include <ardour/ardour.h>
+#include <jack/jack.h>
+#include <jack/midiport.h>
+#include <ardour/port.h>
+#include <ardour/buffer.h>
+
+namespace ARDOUR {
+
+class MidiEngine;
+
+class MidiPort : public Port {
+ public:
+ virtual ~MidiPort();
+
+ DataType type() const { return DataType(DataType::MIDI); }
+
+ MidiBuffer& get_buffer() {
+ assert(_nframes_this_cycle > 0);
+ return *_buffer;
+ }
+
+ void cycle_start(jack_nframes_t nframes);
+ void cycle_end();
+
+ size_t capacity() { return _buffer->capacity(); }
+ size_t size() { return _buffer->size(); }
+
+ /** Assumes that the port is an output port */
+ void silence (jack_nframes_t nframes, jack_nframes_t offset) {
+ // FIXME: silence starting at offset..
+ _buffer->clear();
+ }
+
+ protected:
+ friend class AudioEngine;
+
+ MidiPort (jack_port_t *port);
+
+ /* engine isn't supposed to access below here */
+
+ MidiBuffer* _buffer;
+ jack_nframes_t _nframes_this_cycle;
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_midi_port_h__ */
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index ec47a91b95..f68c0ba3ca 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -1,6 +1,5 @@
/*
- Copyright (C) 2006 Paul Davis
- Written by Dave Robillard, 2006
+ Copyright (C) 2000-2006 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
@@ -15,6 +14,8 @@
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.
+
+ $Id: midiregion.h 733 2006-08-01 17:19:38Z drobilla $
*/
#ifndef __ardour_midi_region_h__
@@ -27,6 +28,8 @@
#include <ardour/ardour.h>
#include <ardour/region.h>
+#include <ardour/gain.h>
+#include <ardour/logcurve.h>
#include <ardour/export.h>
class XMLNode;
@@ -39,17 +42,9 @@ class Session;
class MidiFilter;
class MidiSource;
-struct MidiRegionState : public RegionState
-{
- MidiRegionState (std::string why);
-
-};
-
class MidiRegion : public Region
{
public:
- typedef vector<MidiSource *> SourceList;
-
MidiRegion (MidiSource&, jack_nframes_t start, jack_nframes_t length, bool announce = true);
MidiRegion (MidiSource&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
MidiRegion (SourceList &, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
@@ -59,83 +54,43 @@ class MidiRegion : public Region
MidiRegion (SourceList &, const XMLNode&);
~MidiRegion();
- bool source_equivalent (const Region&) const;
-
- bool speed_mismatch (float) const;
-
- void lock_sources ();
- void unlock_sources ();
- MidiSource& source (uint32_t n=0) const { if (n < sources.size()) return *sources[n]; else return *sources[0]; }
-
- uint32_t n_channels() { return sources.size(); }
- vector<string> master_source_names();
-
- bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); }
-
- virtual jack_nframes_t read_at (unsigned char *buf, unsigned char *mixdown_buffer,
- char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
- uint32_t chan_n = 0,
- jack_nframes_t read_frames = 0,
- jack_nframes_t skip_frames = 0) const;
+ MidiSource& midi_source (uint32_t n=0) const;
- jack_nframes_t master_read_at (unsigned char *buf, unsigned char *mixdown_buffer,
- char * workbuf, jack_nframes_t position, jack_nframes_t cnt, uint32_t chan_n=0) const;
+ jack_nframes_t read_at (RawMidi* out, RawMidi* mix,
+ jack_nframes_t position,
+ jack_nframes_t cnt,
+ uint32_t chan_n = 0,
+ jack_nframes_t read_frames = 0,
+ jack_nframes_t skip_frames = 0) const;
+ jack_nframes_t master_read_at (RawMidi* buf, RawMidi* mix,
+ jack_nframes_t position,
+ jack_nframes_t cnt,
+ uint32_t chan_n=0) const;
XMLNode& state (bool);
- XMLNode& get_state ();
int set_state (const XMLNode&);
- enum FadeShape {
- Linear,
- Fast,
- Slow,
- LogA,
- LogB,
-
- };
-
int separate_by_channel (ARDOUR::Session&, vector<MidiRegion*>&) const;
- uint32_t read_data_count() const { return _read_data_count; }
-
- ARDOUR::Playlist* playlist() const { return _playlist; }
-
UndoAction get_memento() const;
- /* export */
-
- //int exportme (ARDOUR::Session&, ARDOUR::AudioExportSpecification&);
-
- Region* get_parent();
-
private:
friend class Playlist;
private:
- SourceList sources;
- SourceList master_sources; /* used when timefx are applied, so
- we can always use the original
- source.
- */
StateManager::State* state_factory (std::string why) const;
Change restore_state (StateManager::State&);
- jack_nframes_t _read_at (const SourceList&, unsigned char *buf, unsigned char *mixdown_buffer,
- char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
- uint32_t chan_n = 0,
- jack_nframes_t read_frames = 0,
- jack_nframes_t skip_frames = 0) const;
-
- bool verify_start (jack_nframes_t position);
- bool verify_length (jack_nframes_t position);
- bool verify_start_mutable (jack_nframes_t& start);
- bool verify_start_and_length (jack_nframes_t start, jack_nframes_t length);
-
- void recompute_at_start() {}
- void recompute_at_end() {}
+ jack_nframes_t _read_at (const SourceList&, RawMidi *buf,
+ jack_nframes_t position,
+ jack_nframes_t cnt,
+ uint32_t chan_n = 0,
+ jack_nframes_t read_frames = 0,
+ jack_nframes_t skip_frames = 0) const;
- void source_deleted (Source*);
+ void recompute_at_start ();
+ void recompute_at_end ();
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h
index 8e4da44082..1c00289003 100644
--- a/libs/ardour/ardour/midi_source.h
+++ b/libs/ardour/ardour/midi_source.h
@@ -45,23 +45,16 @@ class MidiSource : public Source
MidiSource (const XMLNode&);
virtual ~MidiSource ();
- /* returns the number of items in this `midi_source' */
-
- // Applicable to MIDI? With what unit? [DR]
- virtual jack_nframes_t length() const {
- return _length;
- }
-
- virtual jack_nframes_t read (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const;
- virtual jack_nframes_t write (unsigned char *src, jack_nframes_t cnt, char * workbuf);
+ virtual jack_nframes_t read (RawMidi *dst, jack_nframes_t start, jack_nframes_t cnt) const;
+ virtual jack_nframes_t write (RawMidi *src, jack_nframes_t cnt);
virtual void mark_for_remove() = 0;
virtual void mark_streaming_write_completed () {}
- void set_captured_for (string str) { _captured_for = str; }
string captured_for() const { return _captured_for; }
+ void set_captured_for (string str) { _captured_for = str; }
- uint32_t read_data_count() const { return _read_data_count; }
+ uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
static sigc::signal<void,MidiSource*> MidiSourceCreated;
@@ -73,16 +66,13 @@ class MidiSource : public Source
int set_state (const XMLNode&);
protected:
- jack_nframes_t _length;
- string _captured_for;
-
- mutable uint32_t _read_data_count; // modified in read()
- mutable uint32_t _write_data_count; // modified in write()
-
- virtual jack_nframes_t read_unlocked (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const = 0;
- virtual jack_nframes_t write_unlocked (unsigned char *dst, jack_nframes_t cnt, char * workbuf) = 0;
+ virtual jack_nframes_t read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cn) const = 0;
+ virtual jack_nframes_t write_unlocked (RawMidi* dst, jack_nframes_t cnt) = 0;
- void update_length (jack_nframes_t pos, jack_nframes_t cnt);
+ mutable Glib::Mutex _lock;
+ string _captured_for;
+ mutable uint32_t _read_data_count; ///< modified in read()
+ mutable uint32_t _write_data_count; ///< modified in write()
private:
bool file_changed (string path);
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 185e840ec9..4b942c7a21 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -48,6 +48,11 @@ public:
int silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t offset, bool can_record, bool rec_monitors_input);
+ void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
+ jack_nframes_t start_frame, jack_nframes_t end_frame,
+ jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
+ bool meter);
+
void set_record_enable (bool yn, void *src);
MidiDiskstream& midi_diskstream() const;
@@ -59,7 +64,7 @@ public:
void set_latency_delay (jack_nframes_t);
- int export_stuff (vector<unsigned char*>& buffers, char * workbuf, uint32_t nbufs,
+ int export_stuff (vector<unsigned char*>& buffers, uint32_t nbufs,
jack_nframes_t nframes, jack_nframes_t end_frame);
void freeze (InterThreadInfo&);
diff --git a/libs/ardour/ardour/plugin.h b/libs/ardour/ardour/plugin.h
index 6b11a975ca..e5a81f1ef9 100644
--- a/libs/ardour/ardour/plugin.h
+++ b/libs/ardour/ardour/plugin.h
@@ -47,27 +47,22 @@ class AudioEngine;
class Session;
class Plugin;
+
typedef boost::shared_ptr<Plugin> PluginPtr;
class PluginInfo {
public:
- enum Type {
- AudioUnit,
- LADSPA,
- VST
- };
-
PluginInfo () { }
PluginInfo (const PluginInfo &o)
: name(o.name), n_inputs(o.n_inputs), n_outputs(o.n_outputs),
unique_id(o.unique_id), path (o.path), index(o.index) {}
virtual ~PluginInfo () { }
-
+
string name;
string category;
uint32_t n_inputs;
uint32_t n_outputs;
- Type type;
+ ARDOUR::PluginType type;
long unique_id;
@@ -187,7 +182,7 @@ class Plugin : public Stateful, public sigc::trackable
vector<PortControllable*> controls;
};
-PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, PluginInfo::Type);
+PluginPtr find_plugin(ARDOUR::Session&, string name, long unique_id, ARDOUR::PluginType);
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index 86c99cb7e3..cf36f95b87 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -24,34 +24,32 @@
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
+#include <ardour/data_type.h>
#include <jack/jack.h>
namespace ARDOUR {
class AudioEngine;
+class Buffer;
+/** Abstract base for all outside ports (eg Jack ports)
+ */
class Port : public sigc::trackable {
public:
virtual ~Port() {
free (_port);
}
- Sample *get_buffer (jack_nframes_t nframes) {
- if (_flags & JackPortIsOutput) {
- return _buffer;
- } else {
- return (Sample *) jack_port_get_buffer (_port, nframes);
- }
- }
+ virtual DataType type() const = 0;
+
+ virtual void cycle_start(jack_nframes_t nframes) {}
+ virtual void cycle_end() {}
+
+ virtual Buffer& get_buffer() = 0;
+
+ /** Silence/Empty the port, output ports only */
+ virtual void silence (jack_nframes_t nframes, jack_nframes_t offset) = 0;
- void reset_buffer () {
- if (_flags & JackPortIsOutput) {
- _buffer = (Sample *) jack_port_get_buffer (_port, 0);
- } else {
- _buffer = 0; /* catch illegal attempts to use it */
- }
- _silent = false;
- }
std::string name() {
return _name;
@@ -71,10 +69,6 @@ class Port : public sigc::trackable {
return jack_port_is_mine (client, _port);
}
- const char* type() const {
- return _type.c_str();
- }
-
int connected () const {
return jack_port_connected (_port);
}
@@ -87,38 +81,6 @@ class Port : public sigc::trackable {
return jack_port_get_connections (_port);
}
- void reset_overs () {
- _short_overs = 0;
- _long_overs = 0;
- _overlen = 0;
- }
-
- void reset_peak_meter () {
- _peak = 0;
- }
-
- void reset_meters () {
- reset_peak_meter ();
- reset_overs ();
- }
-
- void enable_metering() {
- _metering++;
- }
-
- void disable_metering () {
- if (_metering) { _metering--; }
- }
-
- float peak_db() const { return _peak_db; }
- jack_default_audio_sample_t peak() const { return _peak; }
-
- uint32_t short_overs () const { return _short_overs; }
- uint32_t long_overs () const { return _long_overs; }
-
- static void set_short_over_length (jack_nframes_t);
- static void set_long_over_length (jack_nframes_t);
-
bool receives_input() const {
return _flags & JackPortIsInput;
}
@@ -134,6 +96,14 @@ class Port : public sigc::trackable {
bool can_monitor () const {
return _flags & JackPortCanMonitor;
}
+
+ void enable_metering() {
+ _metering++;
+ }
+
+ void disable_metering () {
+ if (_metering) { _metering--; }
+ }
void ensure_monitor_input (bool yn) {
jack_port_request_monitor (_port, yn);
@@ -151,60 +121,35 @@ class Port : public sigc::trackable {
jack_port_set_latency (_port, nframes);
}
- sigc::signal<void,bool> MonitorInputChanged;
- sigc::signal<void,bool> ClockSyncChanged;
-
bool is_silent() const { return _silent; }
- /** Assumes that the port is an audio output port */
- void silence (jack_nframes_t nframes, jack_nframes_t offset) {
- if (!_silent) {
- memset (_buffer + offset, 0, sizeof (Sample) * nframes);
- if (offset == 0) {
- /* XXX this isn't really true, but i am not sure
- how to set this correctly. we really just
- want to set it true when the entire port
- buffer has been overrwritten.
- */
- _silent = true;
- }
- }
- }
-
void mark_silence (bool yn) {
_silent = yn;
}
+
+ sigc::signal<void,bool> MonitorInputChanged;
+ sigc::signal<void,bool> ClockSyncChanged;
- private:
+ protected:
friend class AudioEngine;
Port (jack_port_t *port);
- void reset ();
- /* engine isn't supposed to below here */
-
- Sample *_buffer;
-
- /* cache these 3 from JACK so that we can
- access them for reconnecting.
- */
+ virtual void reset ();
+
+ /* engine isn't supposed to access below here */
+ /* cache these 3 from JACK so we can access them for reconnecting */
JackPortFlags _flags;
std::string _type;
std::string _name;
- bool _last_monitor : 1;
- bool _silent : 1;
- jack_port_t *_port;
- jack_nframes_t _overlen;
- jack_default_audio_sample_t _peak;
- float _peak_db;
- uint32_t _short_overs;
- uint32_t _long_overs;
- unsigned short _metering;
-
- static jack_nframes_t _long_over_length;
- static jack_nframes_t _short_over_length;
+ jack_port_t* _port;
+
+ unsigned short _metering;
+
+ bool _last_monitor : 1;
+ bool _silent : 1;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/port_set.h b/libs/ardour/ardour/port_set.h
new file mode 100644
index 0000000000..f8975325a0
--- /dev/null
+++ b/libs/ardour/ardour/port_set.h
@@ -0,0 +1,151 @@
+/*
+ Copyright (C) 2006 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_port_set_h__
+#define __ardour_port_set_h__
+
+#include <vector>
+#include <ardour/port.h>
+#include <ardour/audio_port.h>
+#include <ardour/midi_port.h>
+#include <ardour/chan_count.h>
+
+namespace ARDOUR {
+
+
+/** An ordered list of Ports, possibly of various types.
+ *
+ * This allows access to all the ports as a list, ignoring type, or accessing
+ * the nth port of a given type. Note that port(n) and nth_audio_port(n) may
+ * NOT return the same port.
+ */
+class PortSet {
+public:
+ PortSet();
+
+ size_t num_ports() const;
+ size_t num_ports(DataType type) const { return _ports[type.to_index()].size(); }
+
+ void add_port(Port* port);
+
+ Port* port(size_t index) const;
+
+ Port* nth_port_of_type(DataType type, size_t n) const;
+
+ AudioPort* nth_audio_port(size_t n) const;
+
+ MidiPort* nth_midi_port(size_t n) const;
+
+ bool contains(const Port* port) const;
+
+ /** Remove all ports from the PortSet. Ports are not deregistered with
+ * the engine, it's the caller's responsibility to not leak here!
+ */
+ void clear() { _ports.clear(); }
+
+ const ChanCount& chan_count() const { return _chan_count; }
+
+ bool empty() const { return (_chan_count.get_total_count() == 0); }
+
+ // ITERATORS
+
+ // obviously these iterators will need to get more clever
+ // experimental phase, it's the interface that counts right now
+
+ class iterator {
+ public:
+
+ Port* operator*() { return _list.port(_index); }
+ iterator& operator++() { ++_index; return *this; } // yes, prefix only
+ bool operator==(const iterator& other) { return (_index == other._index); }
+ bool operator!=(const iterator& other) { return (_index != other._index); }
+
+ private:
+ friend class PortSet;
+
+ iterator(PortSet& list, size_t index) : _list(list), _index(index) {}
+
+ PortSet& _list;
+ size_t _index;
+ };
+
+ iterator begin() { return iterator(*this, 0); }
+ iterator end() { return iterator(*this, _chan_count.get_total_count()); }
+
+ class const_iterator {
+ public:
+
+ const Port* operator*() { return _list.port(_index); }
+ const_iterator& operator++() { ++_index; return *this; } // yes, prefix only
+ bool operator==(const const_iterator& other) { return (_index == other._index); }
+ bool operator!=(const const_iterator& other) { return (_index != other._index); }
+
+ private:
+ friend class PortSet;
+
+ const_iterator(const PortSet& list, size_t index) : _list(list), _index(index) {}
+
+ const PortSet& _list;
+ size_t _index;
+ };
+
+ const_iterator begin() const { return const_iterator(*this, 0); }
+ const_iterator end() const { return const_iterator(*this, _chan_count.get_total_count()); }
+
+
+
+ class audio_iterator {
+ public:
+
+ AudioPort* operator*() { return _list.nth_audio_port(_index); }
+ audio_iterator& operator++() { ++_index; return *this; } // yes, prefix only
+ bool operator==(const audio_iterator& other) { return (_index == other._index); }
+ bool operator!=(const audio_iterator& other) { return (_index != other._index); }
+
+ private:
+ friend class PortSet;
+
+ audio_iterator(PortSet& list, size_t index) : _list(list), _index(index) {}
+
+ PortSet& _list;
+ size_t _index;
+ };
+
+ audio_iterator audio_begin() { return audio_iterator(*this, 0); }
+ audio_iterator audio_end() { return audio_iterator(*this, _chan_count.get_count(DataType::AUDIO)); }
+
+
+
+
+private:
+ // Prevent copies (undefined)
+ PortSet(const PortSet& copy);
+ void operator=(const PortSet& other);
+
+ typedef std::vector<Port*> PortVec;
+
+ // Vector of vectors, indexed by DataType::to_index()
+ std::vector<PortVec> _ports;
+
+ ChanCount _chan_count;
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_port_set_h__
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 3773a3b893..c0ff8be607 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -21,6 +21,8 @@
#ifndef __ardour_region_h__
#define __ardour_region_h__
+#include <vector>
+
#include <pbd/undo.h>
#include <ardour/ardour.h>
@@ -56,6 +58,8 @@ struct RegionState : public StateManager::State
class Region : public Stateful, public StateManager
{
public:
+ typedef std::vector<Source *> SourceList;
+
enum Flag {
Muted = 0x1,
Opaque = 0x2,
@@ -89,11 +93,15 @@ class Region : public Stateful, public StateManager
static Change LayerChanged;
static Change HiddenChanged;
- Region (jack_nframes_t start, jack_nframes_t length,
+ Region (Source& src, jack_nframes_t start, jack_nframes_t length,
+ const string& name, layer_t = 0, Flag flags = DefaultFlags);
+ Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length,
+ const string& name, layer_t = 0, Flag flags = DefaultFlags);
+ Region (const Region&, jack_nframes_t start, jack_nframes_t length,
const string& name, layer_t = 0, Flag flags = DefaultFlags);
- Region (const Region&, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t = 0, Flag flags = DefaultFlags);
Region (const Region&);
- Region (const XMLNode&);
+ Region (SourceList& srcs, const XMLNode&);
+ Region (Source& src, const XMLNode&);
virtual ~Region();
const PBD::ID& id() const { return _id; }
@@ -118,13 +126,14 @@ class Region : public Stateful, public StateManager
jack_nframes_t first_frame() const { return _position; }
jack_nframes_t last_frame() const { return _position + _length - 1; }
+ Flag flags() const { return _flags; }
bool hidden() const { return _flags & Hidden; }
bool muted() const { return _flags & Muted; }
bool opaque () const { return _flags & Opaque; }
bool locked() const { return _flags & Locked; }
bool automatic() const { return _flags & Automatic; }
bool whole_file() const { return _flags & WholeFile ; }
- Flag flags() const { return _flags; }
+ bool captured() const { return !(_flags & (Region::Flag (Region::Import|Region::External))); }
virtual bool should_save_state () const { return !(_flags & DoNotSaveState); };
@@ -143,10 +152,8 @@ class Region : public Stateful, public StateManager
bool size_equivalent (const Region&) const;
bool overlap_equivalent (const Region&) const;
bool region_list_equivalent (const Region&) const;
- virtual bool source_equivalent (const Region&) const = 0;
+ bool source_equivalent (const Region&) const;
- virtual bool speed_mismatch (float) const = 0;
-
/* EDITING OPERATIONS */
void set_length (jack_nframes_t, void *src);
@@ -184,8 +191,15 @@ class Region : public Stateful, public StateManager
void set_playlist (ARDOUR::Playlist*);
- virtual void lock_sources () {}
- virtual void unlock_sources () {}
+ void lock_sources ();
+ void unlock_sources ();
+ void source_deleted (Source*);
+
+ Source& source (uint32_t n=0) const { return *_sources[ (n < _sources.size()) ? n : 0 ]; }
+ uint32_t n_channels() const { return _sources.size(); }
+
+ std::vector<string> master_source_names();
+
/* serialization */
@@ -205,7 +219,7 @@ class Region : public Stateful, public StateManager
static sigc::signal<void,Region*> CheckNewRegion;
- virtual Region* get_parent() = 0;
+ Region* get_parent();
uint64_t last_layer_op() const { return _last_layer_op; }
void set_last_layer_op (uint64_t when);
@@ -228,29 +242,32 @@ class Region : public Stateful, public StateManager
void maybe_uncopy ();
void first_edit ();
- virtual bool verify_start (jack_nframes_t) = 0;
- virtual bool verify_start_and_length (jack_nframes_t, jack_nframes_t) = 0;
- virtual bool verify_start_mutable (jack_nframes_t&_start) = 0;
- virtual bool verify_length (jack_nframes_t) = 0;
+ bool verify_start (jack_nframes_t);
+ bool verify_start_and_length (jack_nframes_t, jack_nframes_t);
+ bool verify_start_mutable (jack_nframes_t&_start);
+ bool verify_length (jack_nframes_t);
virtual void recompute_at_start () = 0;
virtual void recompute_at_end () = 0;
-
+
+ PBD::ID _id;
+ string _name;
+ Flag _flags;
jack_nframes_t _start;
jack_nframes_t _length;
jack_nframes_t _position;
- Flag _flags;
jack_nframes_t _sync_position;
layer_t _layer;
- string _name;
mutable RegionEditState _first_edit;
int _frozen;
- Glib::Mutex lock;
- PBD::ID _id;
+ mutable uint32_t _read_data_count; ///< modified in read()
+ Change _pending_changed;
+ uint64_t _last_layer_op; ///< timestamp
+ Glib::Mutex _lock;
ARDOUR::Playlist* _playlist;
- mutable uint32_t _read_data_count; // modified in read()
- Change pending_changed;
- uint64_t _last_layer_op; // timestamp
+ SourceList _sources;
+ /** Used when timefx are applied, so we can always use the original source */
+ SourceList _master_sources;
};
} /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index d1db818e40..493a5e7bc0 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -304,7 +304,7 @@ class Route : public IO
void passthru (jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter_inputs);
- void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
+ virtual void process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
jack_nframes_t start_frame, jack_nframes_t end_frame,
jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
bool meter);
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 6eb025f076..7331cbb5db 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -76,7 +76,9 @@ class AudioSource;
class Diskstream;
class AudioDiskstream;
+class MidiDiskstream;
class AudioFileSource;
+class MidiSource;
class Auditioner;
class Insert;
class Send;
@@ -274,6 +276,7 @@ class Session : public sigc::trackable, public Stateful
static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive);
static string peak_path_from_audio_path (string);
string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive);
+ string midi_path_from_name (string);
void process (jack_nframes_t nframes);
@@ -635,7 +638,7 @@ class Session : public sigc::trackable, public Stateful
string new_region_name (string);
string path_from_region_name (string name, string identifier);
- AudioRegion* find_whole_file_parent (AudioRegion&);
+ Region* find_whole_file_parent (Region& child);
void find_equivalent_playlist_regions (Region&, std::vector<Region*>& result);
AudioRegion *XMLRegionFactory (const XMLNode&, bool full);
@@ -704,6 +707,8 @@ class Session : public sigc::trackable, public Stateful
AudioFileSource *create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive);
+ MidiSource *create_midi_source_for_session (ARDOUR::MidiDiskstream&);
+
Source *source_by_id (const PBD::ID&);
/* playlist management */
@@ -745,8 +750,7 @@ class Session : public sigc::trackable, public Stateful
/* flattening stuff */
- int write_one_audio_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<AudioSource*>&,
- InterThreadInfo& wot);
+ int write_one_audio_track (AudioTrack&, jack_nframes_t start, jack_nframes_t cnt, bool overwrite, vector<Source*>&, InterThreadInfo& wot);
int freeze (InterThreadInfo&);
/* session-wide solo/mute/rec-enable */
@@ -853,6 +857,7 @@ class Session : public sigc::trackable, public Stateful
}
// these commands are implemented in libs/ardour/session_command.cc
+ Command *memento_command_factory(XMLNode *n);
class GlobalSoloStateCommand : public Command
{
GlobalRouteBooleanState before, after;
@@ -987,8 +992,6 @@ class Session : public sigc::trackable, public Stateful
ExportContext
};
- char * conversion_buffer(RunContext context) { return _conversion_buffers[context]; }
-
/* VST support */
static long vst_callback (AEffect* effect,
@@ -1072,7 +1075,6 @@ class Session : public sigc::trackable, public Stateful
vector<Sample *> _passthru_buffers;
vector<Sample *> _silent_buffers;
vector<Sample *> _send_buffers;
- map<RunContext,char*> _conversion_buffers;
jack_nframes_t current_block_size;
jack_nframes_t _worst_output_latency;
jack_nframes_t _worst_input_latency;
diff --git a/libs/ardour/ardour/smf_source.h b/libs/ardour/ardour/smf_source.h
index 00f8cb26de..83bc47d7d3 100644
--- a/libs/ardour/ardour/smf_source.h
+++ b/libs/ardour/ardour/smf_source.h
@@ -41,7 +41,7 @@ class SMFSource : public MidiSource {
};
/** Constructor for existing external-to-session files */
- SMFSource (std::string path, Flag flags);
+ SMFSource (std::string path, Flag flags = Flag(0));
/* Constructor for existing in-session files */
SMFSource (const XMLNode&);
@@ -55,8 +55,8 @@ class SMFSource : public MidiSource {
void set_allow_remove_if_empty (bool yn);
void mark_for_remove();
- virtual int update_header (jack_nframes_t when, struct tm&, time_t) = 0;
- virtual int flush_header () = 0;
+ int update_header (jack_nframes_t when, struct tm&, time_t);
+ int flush_header ();
int move_to_trash (const string trash_dir_name);
@@ -76,6 +76,9 @@ class SMFSource : public MidiSource {
int init (string idstr, bool must_exist);
+ jack_nframes_t read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cn) const;
+ jack_nframes_t write_unlocked (RawMidi* dst, jack_nframes_t cnt);
+
bool find (std::string path, bool must_exist, bool& is_new);
bool removable() const;
bool writable() const { return _flags & Writable; }
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 4764339451..ab3e61eb29 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -56,8 +56,8 @@ class SndFileSource : public AudioFileSource {
protected:
void set_header_timeline_position ();
- jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const;
- jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt, char * workbuf);
+ jack_nframes_t read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const;
+ jack_nframes_t write_unlocked (Sample *dst, jack_nframes_t cnt);
jack_nframes_t write_float (Sample* data, jack_nframes_t pos, jack_nframes_t cnt);
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index f57ea79854..dc1e93f8f2 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -46,9 +46,16 @@ class Source : public Stateful, public sigc::trackable
uint32_t use_cnt() const { return _use_cnt; }
void use ();
void release ();
+
+ virtual void mark_for_remove() = 0;
time_t timestamp() const { return _timestamp; }
void stamp (time_t when) { _timestamp = when; }
+
+ /** @return the number of items in this source */
+ jack_nframes_t length() const { return _length; }
+
+ virtual jack_nframes_t natural_position() const { return 0; }
XMLNode& get_state ();
int set_state (const XMLNode&);
@@ -56,9 +63,12 @@ class Source : public Stateful, public sigc::trackable
sigc::signal<void,Source *> GoingAway;
protected:
+ void update_length (jack_nframes_t pos, jack_nframes_t cnt);
+
string _name;
uint32_t _use_cnt;
time_t _timestamp;
+ jack_nframes_t _length;
private:
PBD::ID _id;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index c30c103d3f..00833f6547 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -29,6 +29,7 @@
#include <inttypes.h>
#include <jack/types.h>
+#include <jack/midiport.h>
#include <control_protocol/smpte.h>
#include <pbd/id.h>
@@ -49,7 +50,7 @@ namespace ARDOUR {
typedef uint32_t layer_t;
typedef uint64_t microseconds_t;
- typedef unsigned char RawMidi;
+ typedef jack_midi_event_t RawMidi;
enum IOChange {
NoChange = 0,
@@ -245,7 +246,14 @@ namespace ARDOUR {
PeakDatum min;
PeakDatum max;
};
-}
+
+ enum PluginType {
+ AudioUnit,
+ LADSPA,
+ VST
+ };
+
+} // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
std::istream& operator>>(std::istream& o, ARDOUR::HeaderFormat& sf);
@@ -256,7 +264,6 @@ session_frame_to_track_frame (jack_nframes_t session_frame, double speed)
return (jack_nframes_t)( (double)session_frame * speed );
}
-
static inline jack_nframes_t
track_frame_to_session_frame (jack_nframes_t track_frame, double speed)
{
diff --git a/libs/ardour/ardour/vst_plugin.h b/libs/ardour/ardour/vst_plugin.h
index 5253da7b0a..4fb5b0babb 100644
--- a/libs/ardour/ardour/vst_plugin.h
+++ b/libs/ardour/ardour/vst_plugin.h
@@ -113,6 +113,8 @@ class VSTPluginInfo : public PluginInfo
PluginPtr load (Session& session);
};
+typedef boost::shared_ptr<VSTPluginInfo> VSTPluginInfoPtr;
+
} // namespace ARDOUR
#endif /* __ardour_vst_plugin_h__ */
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 7d2a2103bb..1b9d7d339d 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -47,6 +47,7 @@
#include <ardour/audioplaylist.h>
#include <ardour/cycle_timer.h>
#include <ardour/audioregion.h>
+#include <ardour/audio_port.h>
#include "i18n.h"
#include <locale.h>
@@ -58,7 +59,6 @@ using namespace PBD;
size_t AudioDiskstream::_working_buffers_size = 0;
Sample* AudioDiskstream::_mixdown_buffer = 0;
gain_t* AudioDiskstream::_gain_buffer = 0;
-char* AudioDiskstream::_conversion_buffer = 0;
AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
: Diskstream(sess, name, flag)
@@ -188,7 +188,6 @@ AudioDiskstream::allocate_working_buffers()
_working_buffers_size = disk_io_frames();
_mixdown_buffer = new Sample[_working_buffers_size];
_gain_buffer = new gain_t[_working_buffers_size];
- _conversion_buffer = new char[_working_buffers_size * 4];
}
void
@@ -196,11 +195,9 @@ AudioDiskstream::free_working_buffers()
{
delete _mixdown_buffer;
delete _gain_buffer;
- delete _conversion_buffer;
_working_buffers_size = 0;
_mixdown_buffer = 0;
_gain_buffer = 0;
- _conversion_buffer = 0;
}
void
@@ -668,7 +665,11 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes
rec_offset
*/
- memcpy (chan.current_capture_buffer, _io->input(n)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (Sample) * rec_nframes);
+ AudioPort* const ap = _io->audio_input(n);
+ assert(ap);
+ assert(rec_nframes <= ap->get_audio_buffer().capacity());
+
+ memcpy (chan.current_capture_buffer, ap->get_audio_buffer().data(rec_nframes, offset + rec_offset), sizeof (Sample) * rec_nframes);
} else {
@@ -679,7 +680,10 @@ AudioDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes
goto out;
}
- Sample* buf = _io->input (n)->get_buffer (nframes) + offset;
+ AudioPort* const ap = _io->audio_input(n);
+ assert(ap);
+
+ Sample* buf = ap->get_audio_buffer().data(nframes, offset);
jack_nframes_t first = chan.capture_vector.len[0];
memcpy (chan.capture_wrap_buffer, buf, sizeof (Sample) * first);
@@ -895,7 +899,6 @@ AudioDiskstream::overwrite_existing_buffers ()
{
Sample* mixdown_buffer;
float* gain_buffer;
- char * workbuf;
int ret = -1;
bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
@@ -906,7 +909,6 @@ AudioDiskstream::overwrite_existing_buffers ()
mixdown_buffer = new Sample[size];
gain_buffer = new float[size];
- workbuf = new char[size*4];
/* reduce size so that we can fill the buffer correctly. */
size--;
@@ -932,8 +934,7 @@ AudioDiskstream::overwrite_existing_buffers ()
jack_nframes_t to_read = size - overwrite_offset;
- if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, workbuf,
- start, to_read, *chan, n, reversed)) {
+ if (read ((*chan).playback_buf->buffer() + overwrite_offset, mixdown_buffer, gain_buffer, start, to_read, *chan, n, reversed)) {
error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
_id, size, playback_sample) << endmsg;
goto out;
@@ -943,7 +944,7 @@ AudioDiskstream::overwrite_existing_buffers ()
cnt -= to_read;
- if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer, workbuf,
+ if (read ((*chan).playback_buf->buffer(), mixdown_buffer, gain_buffer,
start, cnt, *chan, n, reversed)) {
error << string_compose(_("AudioDiskstream %1: when refilling, cannot read %2 from playlist at frame %3"),
_id, size, playback_sample) << endmsg;
@@ -958,7 +959,6 @@ AudioDiskstream::overwrite_existing_buffers ()
pending_overwrite = false;
delete [] gain_buffer;
delete [] mixdown_buffer;
- delete [] workbuf;
return ret;
}
@@ -1022,7 +1022,7 @@ AudioDiskstream::internal_playback_seek (jack_nframes_t distance)
}
int
-AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt,
+AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, jack_nframes_t& start, jack_nframes_t cnt,
ChannelInfo& channel_info, int channel, bool reversed)
{
jack_nframes_t this_read = 0;
@@ -1079,7 +1079,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
this_read = min(cnt,this_read);
- if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) {
+ if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) {
error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read,
start) << endmsg;
return -1;
@@ -1117,19 +1117,17 @@ AudioDiskstream::do_refill_with_alloc()
{
Sample* mix_buf = new Sample[disk_io_chunk_frames];
float* gain_buf = new float[disk_io_chunk_frames];
- char* work_buf = new char[disk_io_chunk_frames * 4];
- int ret = _do_refill(mix_buf, gain_buf, work_buf);
+ int ret = _do_refill(mix_buf, gain_buf);
delete [] mix_buf;
delete [] gain_buf;
- delete [] work_buf;
return ret;
}
int
-AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf)
+AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer)
{
int32_t ret = 0;
jack_nframes_t to_read;
@@ -1143,7 +1141,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char *
assert(mixdown_buffer);
assert(gain_buffer);
- assert(workbuf);
channels.front().playback_buf->get_write_vector (&vector);
@@ -1284,7 +1281,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char *
if (to_read) {
- if (read (buf1, mixdown_buffer, gain_buffer, workbuf, file_frame_tmp, to_read, chan, chan_n, reversed)) {
+ if (read (buf1, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) {
ret = -1;
goto out;
}
@@ -1302,7 +1299,7 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char *
so read some or all of vector.len[1] as well.
*/
- if (read (buf2, mixdown_buffer, gain_buffer, workbuf, file_frame_tmp, to_read, chan, chan_n, reversed)) {
+ if (read (buf2, mixdown_buffer, gain_buffer, file_frame_tmp, to_read, chan, chan_n, reversed)) {
ret = -1;
goto out;
}
@@ -1336,8 +1333,6 @@ AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char *
int
AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
{
- char* workbuf = _session.conversion_buffer(context);
-
uint32_t to_write;
int32_t ret = 0;
RingBufferNPT<Sample>::rw_vector vector;
@@ -1427,7 +1422,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
}
}
- if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write, workbuf) != to_write) {
+ if ((!(*chan).write_source) || (*chan).write_source->write (vector.buf[0], to_write) != to_write) {
error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
}
@@ -1444,7 +1439,7 @@ AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
to_write = min ((jack_nframes_t)(disk_io_chunk_frames - to_write), (jack_nframes_t) vector.len[1]);
- if ((*chan).write_source->write (vector.buf[1], to_write, workbuf) != to_write) {
+ if ((*chan).write_source->write (vector.buf[1], to_write) != to_write) {
error << string_compose(_("AudioDiskstream %1: cannot write to disk"), _id) << endmsg;
return -1;
}
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index 93d380679d..328c9b25f5 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -177,7 +177,7 @@ struct RegionSortByLayer {
};
jack_nframes_t
-AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t start,
+AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t start,
jack_nframes_t cnt, unsigned chan_n)
{
jack_nframes_t ret = cnt;
@@ -250,12 +250,12 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, ch
for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) {
AudioRegion* const ar = dynamic_cast<AudioRegion*>(*i);
assert(ar);
- ar->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames);
+ ar->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n, read_frames, skip_frames);
_read_data_count += ar->read_data_count();
}
for (vector<Crossfade*>::iterator i = x.begin(); i != x.end(); ++i) {
- (*i)->read_at (buf, mixdown_buffer, gain_buffer, workbuf, start, cnt, chan_n);
+ (*i)->read_at (buf, mixdown_buffer, gain_buffer, start, cnt, chan_n);
/* don't JACK up _read_data_count, since its the same data as we just
read from the regions, and the OS should handle that for us.
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
new file mode 100644
index 0000000000..1eee96a54e
--- /dev/null
+++ b/libs/ardour/audio_port.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2006 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 <cassert>
+#include <ardour/audio_port.h>
+#include <ardour/data_type.h>
+
+using namespace ARDOUR;
+using namespace std;
+
+jack_nframes_t AudioPort::_short_over_length = 2;
+jack_nframes_t AudioPort::_long_over_length = 10;
+
+AudioPort::AudioPort(jack_port_t* p)
+ : Port(p)
+ , _buffer(0)
+{
+ DataType dt(_type);
+ assert(dt == DataType::AUDIO);
+
+ reset();
+}
+
+void
+AudioPort::reset()
+{
+ Port::reset();
+ if (_flags & JackPortIsOutput) {
+ _buffer.clear();
+ _silent = true;
+ }
+
+ _metering = 0;
+ reset_meters ();
+}
+
+void
+AudioPort::cycle_start (jack_nframes_t nframes)
+{
+ if (_flags & JackPortIsOutput) {
+ // FIXME: do nothing, we can cache the value (but capacity needs to be set)
+ _buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes);
+ } else {
+ _buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes);
+ }
+}
+
+void
+AudioPort::cycle_end()
+{
+ // whatever...
+}
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 78af23e3df..409b0e560f 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -627,7 +627,7 @@ AudioTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jac
}
int
-AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
+AudioTrack::export_stuff (vector<Sample*>& buffers, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
{
gain_t gain_automation[nframes];
gain_t gain_buffer[nframes];
@@ -645,7 +645,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu
AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(diskstream.playlist());
assert(apl);
- if (apl->read (buffers[0], mix_buffer, gain_buffer, workbuf, start, nframes) != nframes) {
+ if (apl->read (buffers[0], mix_buffer, gain_buffer, start, nframes) != nframes) {
return -1;
}
@@ -655,7 +655,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu
++bi;
for (; bi != buffers.end(); ++bi, ++n) {
if (n < diskstream.n_channels()) {
- if (apl->read ((*bi), mix_buffer, gain_buffer, workbuf, start, nframes, n) != nframes) {
+ if (apl->read ((*bi), mix_buffer, gain_buffer, start, nframes, n) != nframes) {
return -1;
}
b = (*bi);
@@ -730,7 +730,7 @@ AudioTrack::export_stuff (vector<Sample*>& buffers, char * workbuf, uint32_t nbu
void
AudioTrack::bounce (InterThreadInfo& itt)
{
- vector<AudioSource*> srcs;
+ vector<Source*> srcs;
_session.write_one_audio_track (*this, 0, _session.current_end_frame(), false, srcs, itt);
}
@@ -738,14 +738,14 @@ AudioTrack::bounce (InterThreadInfo& itt)
void
AudioTrack::bounce_range (jack_nframes_t start, jack_nframes_t end, InterThreadInfo& itt)
{
- vector<AudioSource*> srcs;
+ vector<Source*> srcs;
_session.write_one_audio_track (*this, start, end, false, srcs, itt);
}
void
AudioTrack::freeze (InterThreadInfo& itt)
{
- vector<AudioSource*> srcs;
+ vector<Source*> srcs;
string new_playlist_name;
Playlist* new_playlist;
string dir;
diff --git a/libs/ardour/audio_unit.cc b/libs/ardour/audio_unit.cc
index 25c8aeb53b..0a31df40ee 100644
--- a/libs/ardour/audio_unit.cc
+++ b/libs/ardour/audio_unit.cc
@@ -322,7 +322,7 @@ AUPluginInfo::discover ()
AUPluginInfoPtr plug(new AUPluginInfo);
plug->name = AUPluginInfo::get_name (temp);
- plug->type = PluginInfo::AudioUnit;
+ plug->type = ARDOUR::AudioUnit;
plug->n_inputs = 0;
plug->n_outputs = 0;
plug->category = "AudioUnit";
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 982a7c5971..49c7902bb9 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -28,6 +28,8 @@
#include <ardour/audioengine.h>
#include <ardour/buffer.h>
#include <ardour/port.h>
+#include <ardour/audio_port.h>
+#include <ardour/midi_port.h>
#include <ardour/session.h>
#include <ardour/cycle_timer.h>
#include <ardour/utils.h>
@@ -43,9 +45,6 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-jack_nframes_t Port::_short_over_length = 2;
-jack_nframes_t Port::_long_over_length = 10;
-
AudioEngine::AudioEngine (string client_name)
{
session = 0;
@@ -258,6 +257,10 @@ AudioEngine::process_callback (jack_nframes_t nframes)
return 0;
}
+ // Prepare ports (ie read data if necessary)
+ for (Ports::iterator i = ports.begin(); i != ports.end(); ++i)
+ (*i)->cycle_start(nframes);
+
session->process (nframes);
if (!_running) {
@@ -268,6 +271,10 @@ AudioEngine::process_callback (jack_nframes_t nframes)
_processed_frames = next_processed_frames;
return 0;
}
+
+ // Finalize ports (ie write data if necessary)
+ for (Ports::iterator i = ports.begin(); i != ports.end(); ++i)
+ (*i)->cycle_end();
if (last_monitor_check + monitor_check_interval < next_processed_frames) {
for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) {
@@ -405,10 +412,16 @@ AudioEngine::register_input_port (DataType type, const string& portname)
if (p) {
- Port *newport;
- if ((newport = new Port (p)) != 0) {
+ Port* newport = 0;
+
+ if (type == DataType::AUDIO)
+ newport = new AudioPort (p);
+ else if (type == DataType::MIDI)
+ newport = new MidiPort (p);
+
+ if (newport)
ports.insert (ports.begin(), newport);
- }
+
return newport;
} else {
@@ -432,14 +445,22 @@ AudioEngine::register_output_port (DataType type, const string& portname)
}
}
- jack_port_t *p;
-
+ jack_port_t* p = 0;
+
if ((p = jack_port_register (_jack, portname.c_str(),
- type.to_jack_type(), JackPortIsOutput, 0)) != 0) {
- Port *newport = new Port (p);
- ports.insert (ports.begin(), newport);
- return newport;
+ type.to_jack_type(), JackPortIsOutput, 0)) != 0) {
+ Port *newport = NULL;
+
+ if (type == DataType::AUDIO)
+ newport = new AudioPort (p);
+ else if (type == DataType::MIDI)
+ newport = new MidiPort (p);
+
+ if (newport)
+ ports.insert (ports.begin(), newport);
+ return newport;
+
} else {
_process_lock.unlock();
@@ -597,6 +618,9 @@ AudioEngine::frames_per_cycle ()
}
}
+/** Get a port by name.
+ * Note this can return NULL, it will NOT create a port if it is not found (any more).
+ */
Port *
AudioEngine::get_port_by_name (const string& portname, bool keep)
{
@@ -611,25 +635,13 @@ AudioEngine::get_port_by_name (const string& portname, bool keep)
}
}
- /* check to see if we have a Port for this name already */
-
for (Ports::iterator i = ports.begin(); i != ports.end(); ++i) {
if (portname == (*i)->name()) {
return (*i);
}
}
- jack_port_t *p;
-
- if ((p = jack_port_by_name (_jack, portname.c_str())) != 0) {
- Port *newport = new Port (p);
- if (keep && newport->is_mine (_jack)) {
- ports.insert (newport);
- }
- return newport;
- } else {
- return 0;
- }
+ return 0;
}
const char **
@@ -703,12 +715,14 @@ AudioEngine::n_physical_inputs () const
}
string
-AudioEngine::get_nth_physical (uint32_t n, int flag)
+AudioEngine::get_nth_physical (DataType type, uint32_t n, int flag)
{
const char ** ports;
uint32_t i;
string ret;
+ assert(type != DataType::NIL);
+
if (!_running || !_jack) {
if (!_has_run) {
fatal << _("get_nth_physical called before engine was started") << endmsg;
@@ -718,7 +732,7 @@ AudioEngine::get_nth_physical (uint32_t n, int flag)
}
}
- ports = jack_get_ports (_jack, NULL, NULL, JackPortIsPhysical|flag);
+ ports = jack_get_ports (_jack, NULL, type.to_jack_type(), JackPortIsPhysical|flag);
if (ports == 0) {
return "";
@@ -951,7 +965,7 @@ AudioEngine::reconnect_to_jack ()
short_name = long_name.substr (long_name.find_last_of (':') + 1);
- if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type(), (*i)->flags(), 0)) == 0) {
+ if (((*i)->_port = jack_port_register (_jack, short_name.c_str(), (*i)->type().to_jack_type(), (*i)->flags(), 0)) == 0) {
error << string_compose (_("could not reregister %1"), (*i)->name()) << endmsg;
break;
} else {
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 20d1dbfbd6..6b810c04ec 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2001 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -57,25 +57,20 @@ Change AudioRegion::ScaleAmplitudeChanged = ARDOUR::new_change();
Change AudioRegion::EnvelopeChanged = ARDOUR::new_change();
AudioRegionState::AudioRegionState (string why)
- : RegionState (why),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : RegionState (why)
+ , _fade_in (0.0, 2.0, 1.0, false)
+ , _fade_out (0.0, 2.0, 1.0, false)
+ , _envelope (0.0, 2.0, 1.0, false)
{
}
+/** Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, bool announce)
- : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External)),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : Region (src, start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External))
+ , _fade_in (0.0, 2.0, 1.0, false)
+ , _fade_out (0.0, 2.0, 1.0, false)
+ , _envelope (0.0, 2.0, 1.0, false)
{
- /* basic AudioRegion constructor */
-
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
-
_scale_amplitude = 1.0;
set_default_fades ();
@@ -90,18 +85,13 @@ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t
}
}
+/* Basic AudioRegion constructor (one channel) */
AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
- : Region (start, length, name, layer, flags),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : Region (src, start, length, name, layer, flags)
+ , _fade_in (0.0, 2.0, 1.0, false)
+ , _fade_out (0.0, 2.0, 1.0, false)
+ , _envelope (0.0, 2.0, 1.0, false)
{
- /* basic AudioRegion constructor */
-
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
-
_scale_amplitude = 1.0;
set_default_fades ();
@@ -115,20 +105,13 @@ AudioRegion::AudioRegion (AudioSource& src, jack_nframes_t start, jack_nframes_t
}
}
+/* Basic AudioRegion constructor (many channels) */
AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
- : Region (start, length, name, layer, flags),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : Region (srcs, start, length, name, layer, flags)
+ , _fade_in (0.0, 2.0, 1.0, false)
+ , _fade_out (0.0, 2.0, 1.0, false)
+ , _envelope (0.0, 2.0, 1.0, false)
{
- /* basic AudioRegion constructor */
-
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
- sources.push_back (*i);
- master_sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- }
-
_scale_amplitude = 1.0;
set_default_fades ();
@@ -143,29 +126,13 @@ AudioRegion::AudioRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t
}
+/** Create a new AudioRegion, that is part of an existing one */
AudioRegion::AudioRegion (const AudioRegion& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
- : Region (other, offset, length, name, layer, flags),
- _fade_in (other._fade_in),
- _fade_out (other._fade_out),
- _envelope (other._envelope, (double) offset, (double) offset + length)
+ : Region (other, offset, length, name, layer, flags)
+ , _fade_in (other._fade_in)
+ , _fade_out (other._fade_out)
+ , _envelope (other._envelope, (double) offset, (double) offset + length)
{
- /* create a new AudioRegion, that is part of an existing one */
-
- set<AudioSource*> unique_srcs;
-
- for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- unique_srcs.insert (*i);
- }
-
- for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- }
- master_sources.push_back (*i);
- }
-
/* return to default fades if the existing ones are too long */
_fade_in_disabled = 0;
_fade_out_disabled = 0;
@@ -203,28 +170,11 @@ AudioRegion::AudioRegion (const AudioRegion& other, jack_nframes_t offset, jack_
}
AudioRegion::AudioRegion (const AudioRegion &other)
- : Region (other),
- _fade_in (other._fade_in),
- _fade_out (other._fade_out),
- _envelope (other._envelope)
+ : Region (other)
+ , _fade_in (other._fade_in)
+ , _fade_out (other._fade_out)
+ , _envelope (other._envelope)
{
- /* Pure copy constructor */
-
- set<AudioSource*> unique_srcs;
-
- for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- unique_srcs.insert (*i);
- }
-
- for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
- master_sources.push_back (*i);
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- }
- }
-
_scale_amplitude = other._scale_amplitude;
_envelope = other._envelope;
@@ -239,15 +189,11 @@ AudioRegion::AudioRegion (const AudioRegion &other)
}
AudioRegion::AudioRegion (AudioSource& src, const XMLNode& node)
- : Region (node),
- _fade_in (0.0, 2.0, 1.0, false),
- _fade_out (0.0, 2.0, 1.0, false),
- _envelope (0.0, 2.0, 1.0, false)
+ : Region (src, node)
+ , _fade_in (0.0, 2.0, 1.0, false)
+ , _fade_out (0.0, 2.0, 1.0, false)
+ , _envelope (0.0, 2.0, 1.0, false)
{
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
-
set_default_fades ();
if (set_state (node)) {
@@ -262,26 +208,11 @@ AudioRegion::AudioRegion (AudioSource& src, const XMLNode& node)
}
AudioRegion::AudioRegion (SourceList& srcs, const XMLNode& node)
- : Region (node),
+ : Region (srcs, node),
_fade_in (0.0, 2.0, 1.0, false),
_fade_out (0.0, 2.0, 1.0, false),
_envelope (0.0, 2.0, 1.0, false)
{
- set<AudioSource*> unique_srcs;
-
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- unique_srcs.insert (*i);
- }
-
- for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
- master_sources.push_back (*i);
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &AudioRegion::source_deleted));
- }
- }
-
set_default_fades ();
_scale_amplitude = 1.0;
@@ -383,48 +314,6 @@ AudioRegion::get_memento() const
return sigc::bind (mem_fun (*(const_cast<AudioRegion *> (this)), &StateManager::use_state), _current_state_id);
}
-bool
-AudioRegion::verify_length (jack_nframes_t len)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (_start > sources[n]->length() - len) {
- return false;
- }
- }
- return true;
-}
-
-bool
-AudioRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (new_length > sources[n]->length() - new_start) {
- return false;
- }
- }
- return true;
-}
-bool
-AudioRegion::verify_start (jack_nframes_t pos)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (pos > sources[n]->length() - _length) {
- return false;
- }
- }
- return true;
-}
-
-bool
-AudioRegion::verify_start_mutable (jack_nframes_t& new_start)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (new_start > sources[n]->length() - _length) {
- new_start = sources[n]->length() - _length;
- }
- }
- return true;
-}
void
AudioRegion::set_envelope_active (bool yn)
{
@@ -448,11 +337,11 @@ AudioRegion::set_envelope_active (bool yn)
jack_nframes_t
AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t offset, jack_nframes_t cnt, uint32_t chan_n, double samples_per_unit) const
{
- if (chan_n >= sources.size()) {
+ if (chan_n >= _sources.size()) {
return 0;
}
- if (sources[chan_n]->read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
+ if (audio_source(chan_n).read_peaks (buf, npeaks, offset, cnt, samples_per_unit)) {
return 0;
} else {
if (_scale_amplitude != 1.0) {
@@ -466,22 +355,22 @@ AudioRegion::read_peaks (PeakData *buf, jack_nframes_t npeaks, jack_nframes_t of
}
jack_nframes_t
-AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position,
+AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position,
jack_nframes_t cnt,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
- return _read_at (sources, buf, mixdown_buffer, gain_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames);
+ return _read_at (_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, read_frames, skip_frames);
}
jack_nframes_t
-AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf, jack_nframes_t position,
+AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, jack_nframes_t position,
jack_nframes_t cnt, uint32_t chan_n) const
{
- return _read_at (master_sources, buf, mixdown_buffer, gain_buffer, workbuf, position, cnt, chan_n, 0, 0);
+ return _read_at (_master_sources, buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
}
jack_nframes_t
-AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer, char * workbuf,
+AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
@@ -491,7 +380,7 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
/* precondition: caller has verified that we cover the desired section */
- if (chan_n >= sources.size()) {
+ if (chan_n >= _sources.size()) {
return 0; /* read nothing */
}
@@ -526,11 +415,12 @@ AudioRegion::_read_at (const SourceList& srcs, Sample *buf, Sample *mixdown_buff
_read_data_count = 0;
- if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) {
+ AudioSource& src = audio_source(chan_n);
+ if (src.read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
- _read_data_count += srcs[chan_n]->read_data_count();
+ _read_data_count += src.read_data_count();
/* fade in */
@@ -647,13 +537,13 @@ AudioRegion::state (bool full)
snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
node.add_property ("scale-gain", buf);
- for (uint32_t n=0; n < sources.size(); ++n) {
+ for (uint32_t n=0; n < _sources.size(); ++n) {
snprintf (buf2, sizeof(buf2), "source-%d", n);
- sources[n]->id().print (buf);
+ _sources[n]->id().print (buf);
node.add_property (buf2, buf);
}
- snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size());
+ snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
node.add_property ("channels", buf);
if (full) {
@@ -1058,7 +948,7 @@ AudioRegion::separate_by_channel (Session& session, vector<AudioRegion*>& v) con
SourceList srcs;
string new_name;
- for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) {
+ for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
srcs.clear ();
srcs.push_back (*i);
@@ -1077,86 +967,6 @@ AudioRegion::separate_by_channel (Session& session, vector<AudioRegion*>& v) con
return 0;
}
-void
-AudioRegion::source_deleted (Source* ignored)
-{
- delete this;
-}
-
-void
-AudioRegion::lock_sources ()
-{
- SourceList::iterator i;
- set<AudioSource*> unique_srcs;
-
- for (i = sources.begin(); i != sources.end(); ++i) {
- unique_srcs.insert (*i);
- (*i)->use ();
- }
-
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->use ();
- }
- }
-}
-
-void
-AudioRegion::unlock_sources ()
-{
- SourceList::iterator i;
- set<AudioSource*> unique_srcs;
-
- for (i = sources.begin(); i != sources.end(); ++i) {
- unique_srcs.insert (*i);
- (*i)->release ();
- }
-
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->release ();
- }
- }
-}
-
-vector<string>
-AudioRegion::master_source_names ()
-{
- SourceList::iterator i;
-
- vector<string> names;
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- names.push_back((*i)->name());
- }
-
- return names;
-}
-
-bool
-AudioRegion::source_equivalent (const Region& o) const
-{
- const AudioRegion* other = dynamic_cast<const AudioRegion*>(&o);
- if (!other)
- return false;
-
- SourceList::const_iterator i;
- SourceList::const_iterator io;
-
- for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) {
- if ((*i)->id() != (*io)->id()) {
- return false;
- }
- }
-
- for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) {
- if ((*i)->id() != (*io)->id()) {
- return false;
- }
- }
-
- return true;
-}
-
int
AudioRegion::apply (AudioFilter& filter)
{
@@ -1170,7 +980,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
jack_nframes_t to_read;
int status = -1;
- spec.channels = sources.size();
+ spec.channels = _sources.size();
if (spec.prepare (blocksize, session.frame_rate())) {
goto out;
@@ -1188,7 +998,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
if (spec.channels == 1) {
- if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) {
+ if (audio_source().read (spec.dataF, _start + spec.pos, to_read) != to_read) {
goto out;
}
@@ -1198,7 +1008,7 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
for (uint32_t chan = 0; chan < spec.channels; ++chan) {
- if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) {
+ if (audio_source(chan).read (buf, _start + spec.pos, to_read) != to_read) {
goto out;
}
@@ -1227,18 +1037,6 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
return status;
}
-Region*
-AudioRegion::get_parent()
-{
- Region* r = 0;
-
- if (_playlist) {
- r = _playlist->session().find_whole_file_parent (*this);
- }
-
- return r;
-}
-
void
AudioRegion::set_scale_amplitude (gain_t g)
{
@@ -1260,7 +1058,6 @@ AudioRegion::normalize_to (float target_dB)
{
const jack_nframes_t blocksize = 64 * 1024;
Sample buf[blocksize];
- char workbuf[blocksize * 4];
jack_nframes_t fpos;
jack_nframes_t fend;
jack_nframes_t to_read;
@@ -1289,7 +1086,7 @@ AudioRegion::normalize_to (float target_dB)
/* read it in */
- if (source (n).read (buf, fpos, to_read, workbuf) != to_read) {
+ if (audio_source (n).read (buf, fpos, to_read) != to_read) {
return;
}
@@ -1372,16 +1169,23 @@ AudioRegion::resume_fade_out ()
bool
AudioRegion::speed_mismatch (float sr) const
{
- if (sources.empty()) {
+ if (_sources.empty()) {
/* impossible, but ... */
return false;
}
- float fsr = sources.front()->sample_rate();
+ float fsr = audio_source().sample_rate();
return fsr != sr;
}
+AudioSource&
+AudioRegion::audio_source (uint32_t n) const
+{
+ // Guaranteed to succeed (use a static cast?)
+ return dynamic_cast<AudioSource&>(source(n));
+}
+
extern "C" {
int region_read_peaks_from_c (void *arg, uint32_t npeaks, uint32_t start, uint32_t cnt, intptr_t data, uint32_t n_chan, double samples_per_unit)
@@ -1397,7 +1201,7 @@ uint32_t region_length_from_c (void *arg)
uint32_t sourcefile_length_from_c (void *arg, double zoom_factor)
{
- return ( (AudioRegion *) arg)->source().available_peaks (zoom_factor) ;
+ return ( (AudioRegion *) arg)->audio_source().available_peaks (zoom_factor) ;
}
} /* extern "C" */
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index bf7a32c885..bf97ef848a 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -379,17 +379,17 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path)
}
jack_nframes_t
-AudioSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
+AudioSource::read (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
{
Glib::Mutex::Lock lm (_lock);
- return read_unlocked (dst, start, cnt, workbuf);
+ return read_unlocked (dst, start, cnt);
}
jack_nframes_t
-AudioSource::write (Sample *dst, jack_nframes_t cnt, char * workbuf)
+AudioSource::write (Sample *dst, jack_nframes_t cnt)
{
Glib::Mutex::Lock lm (_lock);
- return write_unlocked (dst, cnt, workbuf);
+ return write_unlocked (dst, cnt);
}
int
@@ -406,7 +406,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
int ret = -1;
PeakData* staging = 0;
Sample* raw_staging = 0;
- char * workbuf = 0;
int peakfile = -1;
expected_peaks = (cnt / (double) frames_per_peak);
@@ -445,9 +444,8 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
*/
Sample* raw_staging = new Sample[cnt];
- workbuf = new char[cnt*4];
- if (read_unlocked (raw_staging, start, cnt, workbuf) != cnt) {
+ if (read_unlocked (raw_staging, start, cnt) != cnt) {
error << _("cannot read sample data for unscaled peak computation") << endmsg;
return -1;
}
@@ -458,7 +456,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
}
delete [] raw_staging;
- delete [] workbuf;
return 0;
}
@@ -624,7 +621,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
jack_nframes_t nvisual_peaks = 0;
jack_nframes_t chunksize = (jack_nframes_t) min (cnt, (jack_nframes_t) 4096);
raw_staging = new Sample[chunksize];
- workbuf = new char[chunksize *4];
jack_nframes_t frame_pos = start;
double pixel_pos = floor (frame_pos / samples_per_visual_peak);
@@ -640,7 +636,7 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
to_read = min (chunksize, (_length - current_frame));
- if ((frames_read = read_unlocked (raw_staging, current_frame, to_read, workbuf)) == 0) {
+ if ((frames_read = read_unlocked (raw_staging, current_frame, to_read)) == 0) {
error << string_compose(_("AudioSource[%1]: peak read - cannot read %2 samples at offset %3")
, _name, to_read, current_frame)
<< endmsg;
@@ -688,10 +684,6 @@ AudioSource::read_peaks (PeakData *peaks, jack_nframes_t npeaks, jack_nframes_t
delete [] raw_staging;
}
- if (workbuf) {
- delete [] workbuf;
- }
-
return ret;
}
@@ -760,7 +752,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
Sample xmin, xmax;
uint32_t peaki;
PeakData* peakbuf;
- char * workbuf = 0;
jack_nframes_t frames_read;
jack_nframes_t frames_to_read;
off_t first_peak_byte;
@@ -781,8 +772,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
peakbuf = new PeakData[(cnt/frames_per_peak)+1];
peaki = 0;
- workbuf = new char[max(frames_per_peak, cnt) * 4];
-
if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
@@ -794,7 +783,7 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
/* lock for every read */
- if ((frames_read = read (buf, current_frame, frames_to_read, workbuf)) != frames_to_read) {
+ if ((frames_read = read (buf, current_frame, frames_to_read)) != frames_to_read) {
error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
goto out;
}
@@ -831,8 +820,6 @@ AudioSource::do_build_peak (jack_nframes_t first_frame, jack_nframes_t cnt)
if (peakfile >= 0) {
close (peakfile);
}
- if (workbuf)
- delete [] workbuf;
return ret;
}
@@ -889,11 +876,3 @@ AudioSource::available_peaks (double zoom_factor) const
return (end/sizeof(PeakData)) * frames_per_peak;
}
-void
-AudioSource::update_length (jack_nframes_t pos, jack_nframes_t cnt)
-{
- if (pos + cnt > _length) {
- _length = pos+cnt;
- }
-}
-
diff --git a/libs/ardour/buffer.cc b/libs/ardour/buffer.cc
new file mode 100644
index 0000000000..d3791eaed1
--- /dev/null
+++ b/libs/ardour/buffer.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2006 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 <ardour/buffer.h>
+#include <iostream>
+
+namespace ARDOUR {
+
+
+Buffer*
+Buffer::create(DataType type, size_t capacity)
+{
+ if (type == DataType::AUDIO)
+ return new AudioBuffer(capacity);
+ else if (type == DataType::MIDI)
+ return new MidiBuffer(capacity);
+ else
+ return NULL;
+}
+
+
+AudioBuffer::AudioBuffer(size_t capacity)
+ : Buffer(DataType::AUDIO, capacity)
+ , _data(NULL)
+{
+ _size = capacity; // For audio buffers, size = capacity (always)
+ if (capacity > 0) {
+#ifdef NO_POSIX_MEMALIGN
+ _data = (Sample *) malloc(sizeof(Sample) * capacity);
+#else
+ posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
+#endif
+ assert(_data);
+ clear();
+ _owns_data = true;
+ } else {
+ _owns_data = false;
+ }
+}
+
+AudioBuffer::~AudioBuffer()
+{
+ if (_owns_data)
+ free(_data);
+}
+
+// FIXME: mirroring for MIDI buffers?
+MidiBuffer::MidiBuffer(size_t capacity)
+ : Buffer(DataType::MIDI, capacity)
+ , _owns_data(true)
+ , _data(NULL)
+{
+ assert(capacity > 0);
+
+ _size = capacity; // For audio buffers, size = capacity (always)
+#ifdef NO_POSIX_MEMALIGN
+ _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity);
+#else
+ posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity);
+#endif
+ assert(_data);
+ memset(_data, 0, sizeof(RawMidi) * capacity);
+}
+
+MidiBuffer::~MidiBuffer()
+{
+ if (_owns_data)
+ free(_data);
+}
+
+/** Note that offset and nframes refer to sample time, not actual buffer locations */
+void
+MidiBuffer::write(const Buffer& src, jack_nframes_t offset, jack_nframes_t nframes)
+{
+ assert(src.type() == DataType::MIDI);
+ assert(offset == 0);
+ MidiBuffer& msrc = (MidiBuffer&)src;
+ _size = 0;
+ for (size_t i=0; i < msrc.size() && msrc.data()[i].time < nframes; ++i) {
+ assert(i < _capacity);
+ _data[i] = msrc.data()[i];
+ ++_size;
+ }
+ assert(_size == msrc.size());
+
+ if (_size > 0)
+ std::cerr << "MidiBuffer wrote " << _size << " events.\n";
+}
+
+
+} // namespace ARDOUR
+
diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc
index 58da77f933..84c3e3a834 100644
--- a/libs/ardour/configuration.cc
+++ b/libs/ardour/configuration.cc
@@ -236,7 +236,7 @@ Configuration::set_state (const XMLNode& root)
}
}
- AudioDiskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample));
+ Diskstream::set_disk_io_chunk_frames (minimum_disk_io_bytes.get() / sizeof (Sample));
return 0;
}
diff --git a/libs/ardour/coreaudiosource.cc b/libs/ardour/coreaudiosource.cc
index 5e9de225d4..f0fcac14e2 100644
--- a/libs/ardour/coreaudiosource.cc
+++ b/libs/ardour/coreaudiosource.cc
@@ -153,7 +153,7 @@ CoreAudioSource::~CoreAudioSource ()
}
jack_nframes_t
-CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
+CoreAudioSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
{
OSStatus err = noErr;
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index dc4c074844..379c9333b0 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -402,7 +402,7 @@ Crossfade::compute (AudioRegion& a, AudioRegion& b, CrossfadeModel model)
jack_nframes_t
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
- float *gain_buffer, char * workbuf, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n,
+ float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n,
jack_nframes_t read_frames, jack_nframes_t skip_frames)
{
jack_nframes_t offset;
@@ -438,8 +438,8 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
offset = start - _position;
- _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames);
- _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, workbuf, start, to_write, chan_n, read_frames, skip_frames);
+ _out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
+ _in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
float* fiv = new float[to_write];
float* fov = new float[to_write];
diff --git a/libs/ardour/destructive_filesource.cc b/libs/ardour/destructive_filesource.cc
index 43fafff30a..65ca8dae67 100644
--- a/libs/ardour/destructive_filesource.cc
+++ b/libs/ardour/destructive_filesource.cc
@@ -158,7 +158,7 @@ DestructiveFileSource::clear_capture_marks ()
}
jack_nframes_t
-DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in, char * workbuf)
+DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in)
{
jack_nframes_t xfade = min (xfade_frames, cnt);
jack_nframes_t nofade = cnt - xfade;
@@ -272,7 +272,7 @@ DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int fade_in,
}
jack_nframes_t
-DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char * workbuf)
+DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt)
{
jack_nframes_t old_file_pos;
@@ -297,7 +297,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char *
jack_nframes_t ofilepos = file_pos;
// fade in
- if (crossfade (data, subcnt, 1, workbuf) != subcnt) {
+ if (crossfade (data, subcnt, 1) != subcnt) {
return 0;
}
@@ -306,7 +306,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char *
// fade out
subcnt = cnt - subcnt;
- if (crossfade (tmpdata, subcnt, 0, workbuf) != subcnt) {
+ if (crossfade (tmpdata, subcnt, 0) != subcnt) {
return 0;
}
@@ -324,7 +324,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char *
/* move to the correct location place */
file_pos = capture_start_frame;
- if (crossfade (data, cnt, 1, workbuf) != cnt) {
+ if (crossfade (data, cnt, 1) != cnt) {
return 0;
}
@@ -337,7 +337,7 @@ DestructiveFileSource::write_unlocked (Sample* data, jack_nframes_t cnt, char *
_capture_start = false;
_capture_end = false;
- if (crossfade (data, cnt, 0, workbuf) != cnt) {
+ if (crossfade (data, cnt, 0) != cnt) {
return 0;
}
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index 9312de5bf1..b2d481077f 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -19,6 +19,7 @@
*/
#include <fstream>
+#include <cassert>
#include <cstdio>
#include <unistd.h>
#include <cmath>
@@ -55,7 +56,12 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-jack_nframes_t Diskstream::disk_io_chunk_frames = 0;
+/* XXX This goes uninitialized when there is no ~/.ardour2 directory.
+ * I can't figure out why, so this will do for now (just stole the
+ * default from configuration_vars.h). 0 is not a good value for
+ * allocating buffer sizes..
+ */
+jack_nframes_t Diskstream::disk_io_chunk_frames = 1024 * 256;
sigc::signal<void,Diskstream*> Diskstream::DiskstreamCreated;
sigc::signal<void,list<Source*>*> Diskstream::DeleteSources;
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index b70a7bbc9c..c68eb16aae 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -57,7 +57,6 @@ Session::import_audiofile (import_status& status)
SF_INFO info;
float *data = 0;
Sample **channel_data = 0;
- char * workbuf = 0;
long nfiles = 0;
long n;
string basepath;
@@ -156,7 +155,6 @@ Session::import_audiofile (import_status& status)
data = new float[BLOCKSIZE * info.channels];
channel_data = new Sample * [ info.channels ];
- workbuf = new char[BLOCKSIZE * 4];
for (n = 0; n < info.channels; ++n) {
channel_data[n] = new Sample[BLOCKSIZE];
@@ -188,7 +186,7 @@ Session::import_audiofile (import_status& status)
/* flush to disk */
for (chn = 0; chn < info.channels; ++chn) {
- newfiles[chn]->write (channel_data[chn], nread, workbuf);
+ newfiles[chn]->write (channel_data[chn], nread);
}
so_far += nread;
@@ -255,9 +253,6 @@ Session::import_audiofile (import_status& status)
if (data) {
delete [] data;
}
- if (workbuf) {
- delete [] workbuf;
- }
if (channel_data) {
for (n = 0; n < info.channels; ++n) {
diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc
index a057fef931..02d7bf0bb6 100644
--- a/libs/ardour/insert.cc
+++ b/libs/ardour/insert.cc
@@ -30,9 +30,18 @@
#include <ardour/port.h>
#include <ardour/route.h>
#include <ardour/ladspa_plugin.h>
+
+#ifdef VST_SUPPORT
#include <ardour/vst_plugin.h>
+#endif
+
+#ifdef HAVE_COREAUDIO
+#include <ardour/audio_unit.h>
+#endif
+
#include <ardour/audioengine.h>
#include <ardour/session.h>
+#include <ardour/types.h>
#include "i18n.h"
@@ -45,7 +54,6 @@ Insert::Insert(Session& s, Placement p)
{
}
-
Insert::Insert(Session& s, Placement p, int imin, int imax, int omin, int omax)
: Redirect (s, s.next_insert_name(), p, imin, imax, omin, omax)
{
@@ -505,6 +513,9 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
#ifdef VST_SUPPORT
boost::shared_ptr<VSTPlugin> vp;
#endif
+#ifdef HAVE_COREAUDIO
+ boost::shared_ptr<AUPlugin> ap;
+#endif
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
@@ -512,6 +523,10 @@ PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
} else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
#endif
+#ifdef HAVE_COREAUDIO
+ } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
+ return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
+#endif
}
fatal << string_compose (_("programming error: %1"),
@@ -630,7 +645,7 @@ PluginInsert::set_state(const XMLNode& node)
XMLPropertyList plist;
const XMLProperty *prop;
long unique = 0;
- PluginInfo::Type type;
+ ARDOUR::PluginType type;
if ((prop = node.property ("type")) == 0) {
error << _("XML node describing insert is missing the `type' field") << endmsg;
@@ -638,9 +653,9 @@ PluginInsert::set_state(const XMLNode& node)
}
if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
- type = PluginInfo::LADSPA;
+ type = ARDOUR::LADSPA;
} else if (prop->value() == X_("vst")) {
- type = PluginInfo::VST;
+ type = ARDOUR::VST;
} else {
error << string_compose (_("unknown plugin type %1 in plugin insert state"),
prop->value())
@@ -807,6 +822,35 @@ PluginInsert::state_factory (std::string why) const
return state;
}
+ARDOUR::PluginType
+PluginInsert::type ()
+{
+ boost::shared_ptr<LadspaPlugin> lp;
+#ifdef VST_SUPPORT
+ boost::shared_ptr<VSTPlugin> vp;
+#endif
+#ifdef HAVE_COREAUDIO
+ boost::shared_ptr<AUPlugin> ap;
+#endif
+
+ PluginPtr other = plugin ();
+
+ if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
+ return ARDOUR::LADSPA;
+#ifdef VST_SUPPORT
+ } else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
+ return ARDOUR::VST;
+#endif
+#ifdef HAVE_COREAUDIO
+ } else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
+ return ARDOUR::AudioUnit;
+#endif
+ } else {
+ /* NOT REACHED */
+ return (ARDOUR::PluginType) 0;
+ }
+}
+
/***************************************************************
Port inserts: send output to a port, pick up input at a port
***************************************************************/
@@ -869,10 +913,11 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes,
return;
}
- uint32_t n;
+ //uint32_t n;
vector<Port*>::iterator o;
vector<Port*>::iterator i;
+#if 0
/* deliver output */
for (o = _outputs.begin(), n = 0; o != _outputs.end(); ++o, ++n) {
@@ -885,6 +930,7 @@ PortInsert::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes,
for (i = _inputs.begin(), n = 0; i != _inputs.end(); ++i, ++n) {
memcpy (bufs[min(nbufs,n)], (*i)->get_buffer (nframes) + offset, sizeof (Sample) * nframes);
}
+#endif
}
XMLNode&
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 4d2d26f801..9a41d74cee 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -32,6 +32,8 @@
#include <ardour/audioengine.h>
#include <ardour/io.h>
#include <ardour/port.h>
+#include <ardour/audio_port.h>
+#include <ardour/midi_port.h>
#include <ardour/connection.h>
#include <ardour/session.h>
#include <ardour/cycle_timer.h>
@@ -65,12 +67,12 @@ const string IO::state_node_name = "IO";
bool IO::connecting_legal = false;
bool IO::ports_legal = false;
bool IO::panners_legal = false;
-sigc::signal<void> IO::Meter;
-sigc::signal<int> IO::ConnectingLegal;
-sigc::signal<int> IO::PortsLegal;
-sigc::signal<int> IO::PannersLegal;
+sigc::signal<void> IO::Meter;
+sigc::signal<int> IO::ConnectingLegal;
+sigc::signal<int> IO::PortsLegal;
+sigc::signal<int> IO::PannersLegal;
sigc::signal<void,uint32_t> IO::MoreOutputs;
-sigc::signal<int> IO::PortsCreated;
+sigc::signal<int> IO::PortsCreated;
Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
@@ -91,10 +93,12 @@ static double direct_gain_to_control (gain_t gain) {
return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
}
+/*
static bool sort_ports_by_name (Port* a, Port* b)
{
return a->name() < b->name();
}
+*/
/** @param default_type The type of port that will be created by ensure_io
@@ -119,8 +123,6 @@ IO::IO (Session& s, string name,
_input_connection = 0;
_output_connection = 0;
pending_state_node = 0;
- _ninputs = 0;
- _noutputs = 0;
no_panner_reset = false;
deferred_state = 0;
@@ -144,13 +146,12 @@ IO::~IO ()
Glib::Mutex::Lock guard (m_meter_signal_lock);
Glib::Mutex::Lock lm (io_lock);
- vector<Port *>::iterator i;
- for (i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
_session.engine().unregister_port (*i);
}
- for (i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().unregister_port (*i);
}
@@ -162,7 +163,7 @@ IO::silence (jack_nframes_t nframes, jack_nframes_t offset)
{
/* io_lock, not taken: function must be called from Session::process() calltree */
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
(*i)->silence (nframes, offset);
}
}
@@ -227,13 +228,13 @@ IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start,
/* io_lock, not taken: function must be called from Session::process() calltree */
- if (_noutputs == 0) {
+ if (n_outputs() == 0) {
return;
}
- if (_noutputs == 1) {
+ if (n_outputs() == 1) {
- dst = output(0)->get_buffer (nframes) + offset;
+ dst = audio_output(0)->get_audio_buffer().data (nframes, offset);
for (uint32_t n = 0; n < nbufs; ++n) {
if (bufs[n] != dst) {
@@ -246,18 +247,15 @@ IO::pan_automated (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t start,
return;
}
- uint32_t o;
- vector<Port *>::iterator out;
+ uint32_t o = 0;
vector<Sample *>::iterator in;
Panner::iterator pan;
- Sample* obufs[_noutputs];
+ Sample* obufs[n_outputs()];
/* the terrible silence ... */
-
- for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
- obufs[o] = (*out)->get_buffer (nframes) + offset;
- memset (obufs[o], 0, sizeof (Sample) * nframes);
- (*out)->mark_silence (false);
+ for (PortSet::audio_iterator out = _outputs.audio_begin(); out != _outputs.audio_end(); ++out, ++o) {
+ (*out)->silence(nframes, offset);
+ obufs[o] = (*out)->get_audio_buffer().data(nframes, offset);
}
uint32_t n;
@@ -275,7 +273,7 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr
/* io_lock, not taken: function must be called from Session::process() calltree */
- if (_noutputs == 0) {
+ if (n_outputs() == 0) {
return;
}
@@ -288,9 +286,9 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr
return;
}
- if (_noutputs == 1) {
+ if (n_outputs() == 1) {
- dst = output(0)->get_buffer (nframes) + offset;
+ dst = audio_output(0)->get_audio_buffer().data(nframes, offset);
if (gain_coeff == 0.0f) {
@@ -314,7 +312,7 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr
}
}
- output(0)->mark_silence (false);
+ audio_output(0)->mark_silence (false);
} else {
@@ -336,24 +334,23 @@ IO::pan (vector<Sample*>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_nfr
}
}
- output(0)->mark_silence (false);
+ audio_output(0)->mark_silence (false);
}
return;
}
- uint32_t o;
- vector<Port *>::iterator out;
+ uint32_t o = 0;
vector<Sample *>::iterator in;
Panner::iterator pan;
- Sample* obufs[_noutputs];
+ Sample* obufs[n_outputs()];
/* the terrible silence ... */
/* XXX this is wasteful but i see no way to avoid it */
- for (out = _outputs.begin(), o = 0; out != _outputs.end(); ++out, ++o) {
- obufs[o] = (*out)->get_buffer (nframes) + offset;
+ for (PortSet::audio_iterator out = _outputs.audio_begin(); out != _outputs.audio_end(); ++out, ++o) {
+ obufs[o] = (*out)->get_audio_buffer().data (nframes, offset);
memset (obufs[o], 0, sizeof (Sample) * nframes);
(*out)->mark_silence (false);
}
@@ -379,7 +376,7 @@ IO::deliver_output (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nfram
{
/* io_lock, not taken: function must be called from Session::process() calltree */
- if (_noutputs == 0) {
+ if (n_outputs() == 0) {
return;
}
@@ -422,7 +419,7 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
{
/* io_lock, not taken: function must be called from Session::process() calltree */
- if (_noutputs == 0) {
+ if (n_outputs() == 0) {
return;
}
@@ -452,14 +449,14 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
Sample* src;
Sample* dst;
uint32_t i;
- vector<Port*>::iterator o;
vector<Sample*> outs;
gain_t actual_gain;
if (dg != _gain) {
/* unlikely condition */
- for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
- outs.push_back ((*o)->get_buffer (nframes) + offset);
+ i = 0;
+ for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) {
+ outs.push_back ((*o)->get_audio_buffer().data (nframes, offset));
}
}
@@ -473,9 +470,10 @@ IO::deliver_output_no_pan (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_
actual_gain = _gain;
}
- for (o = _outputs.begin(), i = 0; o != _outputs.end(); ++o, ++i) {
+ i = 0;
+ for (PortSet::audio_iterator o = _outputs.audio_begin(); o != _outputs.audio_end(); ++o, ++i) {
- dst = (*o)->get_buffer (nframes) + offset;
+ dst = (*o)->get_audio_buffer().data(nframes, offset);
src = bufs[min(nbufs,i)];
if (dg != _gain || actual_gain == 1.0f) {
@@ -506,14 +504,13 @@ IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
{
/* io_lock, not taken: function must be called from Session::process() calltree */
- vector<Port *>::iterator i;
- uint32_t n;
+ uint32_t n = 0;
Sample *last = 0;
/* we require that bufs.size() >= 1 */
- for (n = 0, i = _inputs.begin(); n < nbufs; ++i, ++n) {
- if (i == _inputs.end()) {
+ for (PortSet::audio_iterator i = _inputs.audio_begin(); n < nbufs; ++i, ++n) {
+ if (i == _inputs.audio_end()) {
break;
}
@@ -527,7 +524,7 @@ IO::collect_input (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframe
buffer.
*/
- last = (*i)->get_buffer (nframes+offset) + offset;
+ last = (*i)->get_audio_buffer().data(nframes, offset);
// the dest buffer's offset has already been applied
memcpy (bufs[n], last, sizeof (Sample) * nframes);
}
@@ -588,7 +585,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src)
/* check that our_port is really one of ours */
- if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
+ if ( ! _inputs.contains(our_port)) {
return -1;
}
@@ -624,7 +621,7 @@ IO::connect_input (Port* our_port, string other_port, void* src)
/* check that our_port is really one of ours */
- if (find (_inputs.begin(), _inputs.end(), our_port) == _inputs.end()) {
+ if ( ! _inputs.contains(our_port) ) {
return -1;
}
@@ -656,7 +653,9 @@ IO::disconnect_output (Port* our_port, string other_port, void* src)
{
Glib::Mutex::Lock lm (io_lock);
- if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
+ /* check that our_port is really one of ours */
+
+ if ( ! _outputs.contains(our_port) ) {
return -1;
}
@@ -691,7 +690,7 @@ IO::connect_output (Port* our_port, string other_port, void* src)
/* check that our_port is really one of ours */
- if (find (_outputs.begin(), _outputs.end(), our_port) == _outputs.end()) {
+ if ( ! _outputs.contains(our_port) ) {
return -1;
}
@@ -734,12 +733,14 @@ IO::set_input (Port* other_port, void* src)
return -1;
}
- return connect_input (_inputs.front(), other_port->name(), src);
+ return connect_input (_inputs.port(0), other_port->name(), src);
}
int
IO::remove_output_port (Port* port, void* src)
{
+ throw; // FIXME
+#if 0
IOChange change (NoChange);
{
@@ -753,7 +754,7 @@ IO::remove_output_port (Port* port, void* src)
return -1;
}
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
if (*i == port) {
change = IOChange (change|ConfigurationChanged);
if (port->connected()) {
@@ -781,7 +782,7 @@ IO::remove_output_port (Port* port, void* src)
_session.set_dirty ();
return 0;
}
-
+#endif
return -1;
}
@@ -806,7 +807,7 @@ IO::add_output_port (string destination, void* src, DataType type)
{
Glib::Mutex::Lock lm (io_lock);
- if (_output_maximum >= 0 && (int) _noutputs == _output_maximum) {
+ if (_output_maximum >= 0 && (int) n_outputs() == _output_maximum) {
return -1;
}
@@ -824,15 +825,13 @@ IO::add_output_port (string destination, void* src, DataType type)
return -1;
}
- _outputs.push_back (our_port);
- sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
- ++_noutputs;
+ _outputs.add_port (our_port);
drop_output_connection ();
setup_peak_meters ();
reset_panner ();
}
- MoreOutputs (_noutputs); /* EMIT SIGNAL */
+ MoreOutputs (n_outputs()); /* EMIT SIGNAL */
}
if (destination.length()) {
@@ -844,12 +843,15 @@ IO::add_output_port (string destination, void* src, DataType type)
// pan_changed (src); /* EMIT SIGNAL */
output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
_session.set_dirty ();
+
return 0;
}
int
IO::remove_input_port (Port* port, void* src)
{
+ throw; // FIXME
+#if 0
IOChange change (NoChange);
{
@@ -862,7 +864,7 @@ IO::remove_input_port (Port* port, void* src)
/* sorry, you can't do this */
return -1;
}
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
if (*i == port) {
change = IOChange (change|ConfigurationChanged);
@@ -892,7 +894,7 @@ IO::remove_input_port (Port* port, void* src)
_session.set_dirty ();
return 0;
}
-
+#endif
return -1;
}
@@ -918,7 +920,7 @@ IO::add_input_port (string source, void* src, DataType type)
{
Glib::Mutex::Lock lm (io_lock);
- if (_input_maximum >= 0 && (int) _ninputs == _input_maximum) {
+ if (_input_maximum >= 0 && (int) n_inputs() == _input_maximum) {
return -1;
}
@@ -936,15 +938,13 @@ IO::add_input_port (string source, void* src, DataType type)
return -1;
}
- _inputs.push_back (our_port);
- sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
- ++_ninputs;
+ _inputs.add_port(our_port);
drop_input_connection ();
setup_peak_meters ();
reset_panner ();
}
- MoreOutputs (_ninputs); /* EMIT SIGNAL */
+ MoreOutputs (n_inputs()); /* EMIT SIGNAL */
}
if (source.length()) {
@@ -957,7 +957,7 @@ IO::add_input_port (string source, void* src, DataType type)
// pan_changed (src); /* EMIT SIGNAL */
input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
_session.set_dirty ();
-
+
return 0;
}
@@ -970,14 +970,16 @@ IO::disconnect_inputs (void* src)
{
Glib::Mutex::Lock lm (io_lock);
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
_session.engine().disconnect (*i);
}
drop_input_connection ();
}
}
- input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
+
+ input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
+
return 0;
}
@@ -990,7 +992,7 @@ IO::disconnect_outputs (void* src)
{
Glib::Mutex::Lock lm (io_lock);
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().disconnect (*i);
}
@@ -1000,6 +1002,7 @@ IO::disconnect_outputs (void* src)
output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
_session.set_dirty ();
+
return 0;
}
@@ -1008,21 +1011,22 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
{
Port* input_port;
bool changed = false;
- bool reduced = false;
/* remove unused ports */
- while (_ninputs > n) {
+ while (n_inputs() > n) {
+ throw; // FIXME
+ /*
_session.engine().unregister_port (_inputs.back());
_inputs.pop_back();
_ninputs--;
- reduced = true;
changed = true;
+ */
}
/* create any necessary new ports */
- while (_ninputs < n) {
+ while (n_inputs() < n) {
char buf[64];
@@ -1050,9 +1054,7 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
throw err;
}
- _inputs.push_back (input_port);
- sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
- ++_ninputs;
+ _inputs.add_port (input_port);
changed = true;
}
@@ -1060,14 +1062,14 @@ IO::ensure_inputs_locked (uint32_t n, bool clear, void* src)
drop_input_connection ();
setup_peak_meters ();
reset_panner ();
- MoreOutputs (_ninputs); /* EMIT SIGNAL */
+ MoreOutputs (n_inputs()); /* EMIT SIGNAL */
_session.set_dirty ();
}
if (clear) {
/* disconnect all existing ports so that we get a fresh start */
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
_session.engine().disconnect (*i);
}
}
@@ -1080,8 +1082,6 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
{
bool in_changed = false;
bool out_changed = false;
- bool in_reduced = false;
- bool out_reduced = false;
bool need_pan_reset;
if (_input_maximum >= 0) {
@@ -1092,7 +1092,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
nout = min (_output_maximum, (int) nout);
}
- if (nin == _ninputs && nout == _noutputs && !clear) {
+ if (nin == n_inputs() && nout == n_outputs() && !clear) {
return 0;
}
@@ -1102,7 +1102,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
Port* port;
- if (_noutputs == nout) {
+ if (n_outputs() == nout) {
need_pan_reset = false;
} else {
need_pan_reset = true;
@@ -1110,25 +1110,27 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
/* remove unused ports */
- while (_ninputs > nin) {
+ while (n_inputs() > nin) {
+ throw; // FIXME
+ /*
_session.engine().unregister_port (_inputs.back());
_inputs.pop_back();
_ninputs--;
- in_reduced = true;
- in_changed = true;
+ in_changed = true;*/
}
- while (_noutputs > nout) {
+ while (n_outputs() > nout) {
+ throw; // FIXME
+ /*
_session.engine().unregister_port (_outputs.back());
_outputs.pop_back();
_noutputs--;
- out_reduced = true;
- out_changed = true;
+ out_changed = true;*/
}
/* create any necessary new ports (of the default type) */
- while (_ninputs < nin) {
+ while (n_inputs() < nin) {
char buf[64];
@@ -1155,14 +1157,13 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
throw err;
}
- _inputs.push_back (port);
- ++_ninputs;
+ _inputs.add_port (port);
in_changed = true;
}
/* create any necessary new ports */
- while (_noutputs < nout) {
+ while (n_outputs() < nout) {
char buf[64];
@@ -1188,8 +1189,7 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
throw err;
}
- _outputs.push_back (port);
- ++_noutputs;
+ _outputs.add_port (port);
out_changed = true;
}
@@ -1197,11 +1197,11 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
/* disconnect all existing ports so that we get a fresh start */
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
_session.engine().disconnect (*i);
}
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().disconnect (*i);
}
}
@@ -1213,19 +1213,17 @@ IO::ensure_io (uint32_t nin, uint32_t nout, bool clear, void* src)
}
if (out_changed) {
- sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
drop_output_connection ();
output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
}
if (in_changed) {
- sort (_inputs.begin(), _inputs.end(), sort_ports_by_name);
drop_input_connection ();
input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
}
if (in_changed || out_changed) {
- MoreOutputs (max (_noutputs, _ninputs)); /* EMIT SIGNAL */
+ MoreOutputs (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
_session.set_dirty ();
}
@@ -1240,7 +1238,7 @@ IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
if (_input_maximum >= 0) {
n = min (_input_maximum, (int) n);
- if (n == _ninputs && !clear) {
+ if (n == n_inputs() && !clear) {
return 0;
}
}
@@ -1257,7 +1255,6 @@ IO::ensure_inputs (uint32_t n, bool clear, bool lockit, void* src)
input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
_session.set_dirty ();
}
-
return 0;
}
@@ -1266,10 +1263,9 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
{
Port* output_port;
bool changed = false;
- bool reduced = false;
bool need_pan_reset;
- if (_noutputs == n) {
+ if (n_outputs() == n) {
need_pan_reset = false;
} else {
need_pan_reset = true;
@@ -1277,18 +1273,19 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
/* remove unused ports */
- while (_noutputs > n) {
-
+ while (n_outputs() > n) {
+ throw; // FIXME
+ /*
_session.engine().unregister_port (_outputs.back());
_outputs.pop_back();
_noutputs--;
- reduced = true;
changed = true;
+ */
}
/* create any necessary new ports */
- while (_noutputs < n) {
+ while (n_outputs() < n) {
char buf[64];
@@ -1305,9 +1302,7 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
return -1;
}
- _outputs.push_back (output_port);
- sort (_outputs.begin(), _outputs.end(), sort_ports_by_name);
- ++_noutputs;
+ _outputs.add_port (output_port);
changed = true;
setup_peak_meters ();
@@ -1318,14 +1313,14 @@ IO::ensure_outputs_locked (uint32_t n, bool clear, void* src)
if (changed) {
drop_output_connection ();
- MoreOutputs (_noutputs); /* EMIT SIGNAL */
+ MoreOutputs (n_outputs()); /* EMIT SIGNAL */
_session.set_dirty ();
}
if (clear) {
/* disconnect all existing ports so that we get a fresh start */
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
_session.engine().disconnect (*i);
}
}
@@ -1340,7 +1335,7 @@ IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
if (_output_maximum >= 0) {
n = min (_output_maximum, (int) n);
- if (n == _noutputs && !clear) {
+ if (n == n_outputs() && !clear) {
return 0;
}
}
@@ -1358,7 +1353,6 @@ IO::ensure_outputs (uint32_t n, bool clear, bool lockit, void* src)
if (changed) {
output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
}
-
return 0;
}
@@ -1377,7 +1371,7 @@ IO::reset_panner ()
{
if (panners_legal) {
if (!no_panner_reset) {
- _panner->reset (_noutputs, pans_required());
+ _panner->reset (n_outputs(), pans_required());
}
} else {
panner_legal_c.disconnect ();
@@ -1388,7 +1382,7 @@ IO::reset_panner ()
int
IO::panners_became_legal ()
{
- _panner->reset (_noutputs, pans_required());
+ _panner->reset (n_outputs(), pans_required());
_panner->load (); // automation
panner_legal_c.disconnect ();
return 0;
@@ -1442,7 +1436,7 @@ IO::state (bool full_state)
}
if (need_ins) {
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
const char **connections = (*i)->get_connections();
@@ -1479,7 +1473,7 @@ IO::state (bool full_state)
if (need_outs) {
str = "";
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
const char **connections = (*i)->get_connections();
@@ -1957,13 +1951,13 @@ IO::set_name (string name, void* src)
return 0;
}
- for (vector<Port *>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
string current_name = (*i)->short_name();
current_name.replace (current_name.find (_name), _name.length(), name);
(*i)->set_name (current_name);
}
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
string current_name = (*i)->short_name();
current_name.replace (current_name.find (_name), _name.length(), name);
(*i)->set_name (current_name);
@@ -2004,7 +1998,7 @@ IO::set_port_latency (jack_nframes_t nframes)
{
Glib::Mutex::Lock lm (io_lock);
- for (vector<Port *>::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
(*i)->set_latency (nframes);
}
}
@@ -2019,7 +2013,7 @@ IO::output_latency () const
/* io lock not taken - must be protected by other means */
- for (vector<Port *>::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
max_latency = latency;
}
@@ -2038,7 +2032,7 @@ IO::input_latency () const
/* io lock not taken - must be protected by other means */
- for (vector<Port *>::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
if ((latency = _session.engine().get_port_total_latency (*(*i))) > max_latency) {
max_latency = latency;
}
@@ -2073,13 +2067,13 @@ IO::use_input_connection (Connection& c, void* src)
for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
- if (!_inputs[n]->connected_to ((*i))) {
+ if (!_inputs.port(n)->connected_to ((*i))) {
/* clear any existing connections */
- _session.engine().disconnect (_inputs[n]);
+ _session.engine().disconnect (_inputs.port(n));
- } else if (_inputs[n]->connected() > 1) {
+ } else if (_inputs.port(n)->connected() > 1) {
/* OK, it is connected to the port we want,
but its also connected to other ports.
@@ -2090,7 +2084,7 @@ IO::use_input_connection (Connection& c, void* src)
the one we want.
*/
- _session.engine().disconnect (_inputs[n]);
+ _session.engine().disconnect (_inputs.port(n));
}
}
@@ -2103,9 +2097,9 @@ IO::use_input_connection (Connection& c, void* src)
for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
- if (!_inputs[n]->connected_to ((*i))) {
+ if (!_inputs.port(n)->connected_to ((*i))) {
- if (_session.engine().connect (*i, _inputs[n]->name())) {
+ if (_session.engine().connect (*i, _inputs.port(n)->name())) {
return -1;
}
}
@@ -2152,13 +2146,13 @@ IO::use_output_connection (Connection& c, void* src)
for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
- if (!_outputs[n]->connected_to ((*i))) {
+ if (!_outputs.port(n)->connected_to ((*i))) {
/* clear any existing connections */
- _session.engine().disconnect (_outputs[n]);
+ _session.engine().disconnect (_outputs.port(n));
- } else if (_outputs[n]->connected() > 1) {
+ } else if (_outputs.port(n)->connected() > 1) {
/* OK, it is connected to the port we want,
but its also connected to other ports.
@@ -2169,7 +2163,7 @@ IO::use_output_connection (Connection& c, void* src)
the one we want.
*/
- _session.engine().disconnect (_outputs[n]);
+ _session.engine().disconnect (_outputs.port(n));
}
}
}
@@ -2182,9 +2176,9 @@ IO::use_output_connection (Connection& c, void* src)
for (Connection::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) {
- if (!_outputs[n]->connected_to ((*i))) {
+ if (!_outputs.port(n)->connected_to ((*i))) {
- if (_session.engine().connect (_outputs[n]->name(), *i)) {
+ if (_session.engine().connect (_outputs.port(n)->name(), *i)) {
return -1;
}
}
@@ -2285,7 +2279,7 @@ IO::GainControllable::get_value (void) const
void
IO::reset_peak_meters ()
{
- uint32_t limit = max (_ninputs, _noutputs);
+ uint32_t limit = max (n_inputs(), n_outputs());
for (uint32_t i = 0; i < limit; ++i) {
_peak_power[i] = 0;
@@ -2295,7 +2289,7 @@ IO::reset_peak_meters ()
void
IO::setup_peak_meters ()
{
- uint32_t limit = max (_ninputs, _noutputs);
+ uint32_t limit = max (n_inputs(), n_outputs());
while (_peak_power.size() < limit) {
_peak_power.push_back (0);
@@ -2342,7 +2336,7 @@ void
IO::meter ()
{
Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
- uint32_t limit = max (_ninputs, _noutputs);
+ uint32_t limit = max (n_inputs(), n_outputs());
for (uint32_t n = 0; n < limit; ++n) {
@@ -2648,11 +2642,11 @@ IO::find_input_port_hole ()
for (n = 1; n < UINT_MAX; ++n) {
char buf[jack_port_name_size()];
- vector<Port*>::iterator i;
+ PortSet::iterator i = _inputs.begin();
snprintf (buf, jack_port_name_size(), _("%s/in %u"), _name.c_str(), n);
- for (i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for ( ; i != _inputs.end(); ++i) {
if ((*i)->short_name() == buf) {
break;
}
@@ -2678,11 +2672,11 @@ IO::find_output_port_hole ()
for (n = 1; n < UINT_MAX; ++n) {
char buf[jack_port_name_size()];
- vector<Port*>::iterator i;
+ PortSet::iterator i = _outputs.begin();
snprintf (buf, jack_port_name_size(), _("%s/out %u"), _name.c_str(), n);
- for (i = _outputs.begin(); i != _outputs.end(); ++i) {
+ for ( ; i != _outputs.end(); ++i) {
if ((*i)->short_name() == buf) {
break;
}
@@ -2695,3 +2689,28 @@ IO::find_output_port_hole ()
return n;
}
+
+AudioPort*
+IO::audio_input(uint32_t n) const
+{
+ return dynamic_cast<AudioPort*>(input(n));
+}
+
+AudioPort*
+IO::audio_output(uint32_t n) const
+{
+ return dynamic_cast<AudioPort*>(output(n));
+}
+
+MidiPort*
+IO::midi_input(uint32_t n) const
+{
+ return dynamic_cast<MidiPort*>(input(n));
+}
+
+MidiPort*
+IO::midi_output(uint32_t n) const
+{
+ return dynamic_cast<MidiPort*>(output(n));
+}
+
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index a43e5e9024..8722c65a5f 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -47,6 +47,7 @@
#include <ardour/midi_playlist.h>
#include <ardour/cycle_timer.h>
#include <ardour/midi_region.h>
+#include <ardour/midi_port.h>
#include "i18n.h"
#include <locale.h>
@@ -57,7 +58,15 @@ using namespace PBD;
MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
: Diskstream(sess, name, flag)
- , _playlist(NULL)
+ , _playback_buf(0)
+ , _capture_buf(0)
+ , _current_playback_buffer(0)
+ , _current_capture_buffer(0)
+ , _playback_wrap_buffer(0)
+ , _capture_wrap_buffer(0)
+ , _source_port(0)
+ , _write_source(0)
+ , _capture_transition_buf(0)
{
/* prevent any write sources from being created */
@@ -73,7 +82,15 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
: Diskstream(sess, node)
- , _playlist(NULL)
+ , _playback_buf(0)
+ , _capture_buf(0)
+ , _current_playback_buffer(0)
+ , _current_capture_buffer(0)
+ , _playback_wrap_buffer(0)
+ , _capture_wrap_buffer(0)
+ , _source_port(0)
+ , _write_source(0)
+ , _capture_transition_buf(0)
{
in_set_state = true;
init (Recordable);
@@ -105,42 +122,105 @@ MidiDiskstream::init (Diskstream::Flag f)
set_block_size (_session.get_block_size());
allocate_temporary_buffers ();
- /* FIXME: this is now done before the above. OK? */
- /*pending_overwrite = false;
- overwrite_frame = 0;
- overwrite_queued = false;
- input_change_pending = NoChange;*/
-
+ _playback_wrap_buffer = new RawMidi[wrap_buffer_size];
+ _capture_wrap_buffer = new RawMidi[wrap_buffer_size];
+ _playback_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size());
+ _capture_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size());
+ _capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
+
_n_channels = 1;
}
MidiDiskstream::~MidiDiskstream ()
{
Glib::Mutex::Lock lm (state_lock);
-
- if (_playlist)
- _playlist->unref ();
}
-/*
-void
-MidiDiskstream::handle_input_change (IOChange change, void *src)
-{
- Glib::Mutex::Lock lm (state_lock);
- if (!(input_change_pending & change)) {
- input_change_pending = IOChange (input_change_pending|change);
- _session.request_input_change_handling ();
- }
-}
-*/
void
MidiDiskstream::non_realtime_input_change ()
{
+ {
+ Glib::Mutex::Lock lm (state_lock);
+
+ if (input_change_pending == NoChange) {
+ return;
+ }
+
+ if (input_change_pending & ConfigurationChanged) {
+
+ assert(_io->n_inputs() == _n_channels);
+ }
+
+ get_input_sources ();
+ set_capture_offset ();
+
+ if (first_input_change) {
+ set_align_style (_persistent_alignment_style);
+ first_input_change = false;
+ } else {
+ set_align_style_from_io ();
+ }
+
+ input_change_pending = NoChange;
+ }
+
+ /* reset capture files */
+
+ reset_write_sources (false);
+
+ /* now refill channel buffers */
+
+ if (speed() != 1.0f || speed() != -1.0f) {
+ seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()));
+ }
+ else {
+ seek (_session.transport_frame());
+ }
}
void
MidiDiskstream::get_input_sources ()
{
+#if 0
+ if (_io->n_inputs() == 0) {
+ cerr << "MidiDiskstream NO INPUTS?\n";
+ return;
+ } else {
+ cerr << "INPUTS!\n";
+ }
+
+ // FIXME this is weird and really different from AudioDiskstream
+
+ assert(_io->n_inputs() == 1);
+ assert(_io->midi_input(0));
+ _source_port = _io->midi_input(0);
+
+ const char **connections = _io->input(0)->get_connections ();
+
+ if (connections == 0 || connections[0] == 0) {
+
+ if (_source_port) {
+ // _source_port->disable_metering ();
+ }
+
+ _source_port = 0;
+
+ } else {
+ _source_port = dynamic_cast<MidiPort*>(
+ _session.engine().get_port_by_name (connections[0]));
+ assert(_source_port);
+ }
+
+ if (_source_port) {
+ cerr << "SOURCE PORT!\n";
+ } else {
+ cerr << "NO SOURCE PORT?!\n";
+ }
+
+ if (connections) {
+ free (connections);
+ }
+#endif
}
int
@@ -167,42 +247,7 @@ MidiDiskstream::use_playlist (Playlist* playlist)
{
assert(dynamic_cast<MidiPlaylist*>(playlist));
- {
- Glib::Mutex::Lock lm (state_lock);
-
- if (playlist == _playlist) {
- return 0;
- }
-
- plstate_connection.disconnect();
- plmod_connection.disconnect ();
- plgone_connection.disconnect ();
-
- if (_playlist) {
- _playlist->unref();
- }
-
- _playlist = dynamic_cast<MidiPlaylist*>(playlist);
- _playlist->ref();
-
- if (!in_set_state && recordable()) {
- reset_write_sources (false);
- }
-
- plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &MidiDiskstream::playlist_changed));
- plmod_connection = _playlist->Modified.connect (mem_fun (*this, &MidiDiskstream::playlist_modified));
- plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &MidiDiskstream::playlist_deleted));
- }
-
- if (!overwrite_queued) {
- _session.request_overwrite_buffer (this);
- overwrite_queued = true;
- }
-
- PlaylistChanged (); /* EMIT SIGNAL */
- _session.set_dirty ();
-
- return 0;
+ return Diskstream::use_playlist(playlist);
}
int
@@ -246,7 +291,7 @@ MidiDiskstream::use_copy_playlist ()
newname = Playlist::bump_name (_playlist->name(), _session);
- if ((playlist = new MidiPlaylist (*_playlist, newname)) != 0) {
+ if ((playlist = new MidiPlaylist (*midi_playlist(), newname)) != 0) {
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
} else {
@@ -254,26 +299,18 @@ MidiDiskstream::use_copy_playlist ()
}
}
-
-void
-MidiDiskstream::playlist_deleted (Playlist* pl)
-{
- /* this catches an ordering issue with session destruction. playlists
- are destroyed before diskstreams. we have to invalidate any handles
- we have to the playlist.
- */
-
- _playlist = 0;
-}
-
-
void
MidiDiskstream::setup_destructive_playlist ()
{
+ Region::SourceList srcs;
+
+ srcs.push_back (_write_source);
/* a single full-sized region */
- //MidiRegion* region = new MidiRegion (srcs, 0, max_frames, _name);
- //_playlist->add_region (*region, 0);
+ cerr << "Setup MIDI DS using " << srcs.front()->natural_position () << endl;
+
+ MidiRegion* region = new MidiRegion (srcs, 0, max_frames, _name);
+ _playlist->add_region (*region, srcs.front()->natural_position());
}
void
@@ -296,48 +333,431 @@ MidiDiskstream::use_destructive_playlist ()
delete rl;
+ assert(region->n_channels() == 1);
+ _write_source = dynamic_cast<SMFSource*>(&region->source (0));
+ assert(_write_source);
+ _write_source->set_allow_remove_if_empty (false);
+
/* the source list will never be reset for a destructive track */
}
void
-MidiDiskstream::set_io (IO& io)
+MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record)
{
- _io = &io;
- set_align_style_from_io ();
-}
+ // FIXME: waaay too much code to duplicate (AudioDiskstream)
+
+ int possibly_recording;
+ int rolling;
+ int change;
+ const int transport_rolling = 0x4;
+ const int track_rec_enabled = 0x2;
+ const int global_rec_enabled = 0x1;
+
+ /* merge together the 3 factors that affect record status, and compute
+ what has changed.
+ */
-void
-MidiDiskstream::non_realtime_set_speed ()
-{
- if (_buffer_reallocation_required)
- {
- Glib::Mutex::Lock lm (state_lock);
- allocate_temporary_buffers ();
+ rolling = _session.transport_speed() != 0.0f;
+ possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
+ change = possibly_recording ^ last_possibly_recording;
- _buffer_reallocation_required = false;
+ if (possibly_recording == last_possibly_recording) {
+ return;
}
- if (_seek_required) {
- if (speed() != 1.0f || speed() != -1.0f) {
- seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
+ /* change state */
+
+ /* if per-track or global rec-enable turned on while the other was already on, we've started recording */
+
+ if ((change & track_rec_enabled) && record_enabled() && (!(change & global_rec_enabled) && can_record) ||
+ ((change & global_rec_enabled) && can_record && (!(change & track_rec_enabled) && record_enabled()))) {
+
+ /* starting to record: compute first+last frames */
+
+ first_recordable_frame = transport_frame + _capture_offset;
+ last_recordable_frame = max_frames;
+ capture_start_frame = transport_frame;
+
+ if (!(last_possibly_recording & transport_rolling) && (possibly_recording & transport_rolling)) {
+
+ /* was stopped, now rolling (and recording) */
+
+ if (_alignment_style == ExistingMaterial) {
+ first_recordable_frame += _session.worst_output_latency();
+ } else {
+ first_recordable_frame += _roll_delay;
+ }
+
+ } else {
+
+ /* was rolling, but record state changed */
+
+ if (_alignment_style == ExistingMaterial) {
+
+
+ if (!_session.get_punch_in()) {
+
+ /* manual punch in happens at the correct transport frame
+ because the user hit a button. but to get alignment correct
+ we have to back up the position of the new region to the
+ appropriate spot given the roll delay.
+ */
+
+ capture_start_frame -= _roll_delay;
+
+ /* XXX paul notes (august 2005): i don't know why
+ this is needed.
+ */
+
+ first_recordable_frame += _capture_offset;
+
+ } else {
+
+ /* autopunch toggles recording at the precise
+ transport frame, and then the DS waits
+ to start recording for a time that depends
+ on the output latency.
+ */
+
+ first_recordable_frame += _session.worst_output_latency();
+ }
+
+ } else {
+
+ if (_session.get_punch_in()) {
+ first_recordable_frame += _roll_delay;
+ } else {
+ capture_start_frame -= _roll_delay;
+ }
+ }
+
}
- else {
- seek (_session.transport_frame(), true);
+
+ if (_flags & Recordable) {
+ RingBufferNPT<CaptureTransition>::rw_vector transvec;
+ _capture_transition_buf->get_write_vector(&transvec);
+
+ if (transvec.len[0] > 0) {
+ transvec.buf[0]->type = CaptureStart;
+ transvec.buf[0]->capture_val = capture_start_frame;
+ _capture_transition_buf->increment_write_ptr(1);
+ } else {
+ // bad!
+ fatal << X_("programming error: capture_transition_buf is full on rec start! inconceivable!")
+ << endmsg;
+ }
}
- _seek_required = false;
+ } else if (!record_enabled() || !can_record) {
+
+ /* stop recording */
+
+ last_recordable_frame = transport_frame + _capture_offset;
+
+ if (_alignment_style == ExistingMaterial) {
+ last_recordable_frame += _session.worst_output_latency();
+ } else {
+ last_recordable_frame += _roll_delay;
+ }
}
-}
-void
-MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record)
-{
+ last_possibly_recording = possibly_recording;
}
int
MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes, jack_nframes_t offset, bool can_record, bool rec_monitors_input)
{
- return 0;
+ // FIXME: waay too much code to duplicate (AudioDiskstream::process)
+ int ret = -1;
+ jack_nframes_t rec_offset = 0;
+ jack_nframes_t rec_nframes = 0;
+ bool nominally_recording;
+ bool re = record_enabled ();
+ bool collect_playback = false;
+
+ _current_capture_buffer = 0;
+ _current_playback_buffer = 0;
+
+ /* if we've already processed the frames corresponding to this call,
+ just return. this allows multiple routes that are taking input
+ from this diskstream to call our ::process() method, but have
+ this stuff only happen once. more commonly, it allows both
+ the AudioTrack that is using this AudioDiskstream *and* the Session
+ to call process() without problems.
+ */
+
+ if (_processed) {
+ return 0;
+ }
+
+ check_record_status (transport_frame, nframes, can_record);
+
+ nominally_recording = (can_record && re);
+
+ if (nframes == 0) {
+ _processed = true;
+ return 0;
+ }
+
+ /* This lock is held until the end of AudioDiskstream::commit, so these two functions
+ must always be called as a pair. The only exception is if this function
+ returns a non-zero value, in which case, ::commit should not be called.
+ */
+
+ // If we can't take the state lock return.
+ if (!state_lock.trylock()) {
+ return 1;
+ }
+
+ adjust_capture_position = 0;
+
+ if (nominally_recording || (_session.get_record_enabled() && _session.get_punch_in())) {
+ OverlapType ot;
+
+ ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
+
+ switch (ot) {
+ case OverlapNone:
+ rec_nframes = 0;
+ break;
+
+ case OverlapInternal:
+ /* ---------- recrange
+ |---| transrange
+ */
+ rec_nframes = nframes;
+ rec_offset = 0;
+ break;
+
+ case OverlapStart:
+ /* |--------| recrange
+ -----| transrange
+ */
+ rec_nframes = transport_frame + nframes - first_recordable_frame;
+ if (rec_nframes) {
+ rec_offset = first_recordable_frame - transport_frame;
+ }
+ break;
+
+ case OverlapEnd:
+ /* |--------| recrange
+ |-------- transrange
+ */
+ rec_nframes = last_recordable_frame - transport_frame;
+ rec_offset = 0;
+ break;
+
+ case OverlapExternal:
+ /* |--------| recrange
+ -------------- transrange
+ */
+ rec_nframes = last_recordable_frame - last_recordable_frame;
+ rec_offset = first_recordable_frame - transport_frame;
+ break;
+ }
+
+ if (rec_nframes && !was_recording) {
+ capture_captured = 0;
+ was_recording = true;
+ }
+ }
+
+
+ if (can_record && !_last_capture_regions.empty()) {
+ _last_capture_regions.clear ();
+ }
+
+ if (nominally_recording || rec_nframes) {
+ _capture_buf->get_write_vector (&_capture_vector);
+
+ if (rec_nframes <= _capture_vector.len[0]) {
+
+ _current_capture_buffer = _capture_vector.buf[0];
+
+ /* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use
+ rec_offset
+ */
+
+ // FIXME: midi buffer size?
+
+ // FIXME: reading from a MIDI port is different, can't just memcpy
+ //memcpy (_current_capture_buffer, _io->input(0)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (RawMidi) * rec_nframes);
+ assert(_source_port);
+ for (size_t i=0; i < _source_port->size(); ++i) {
+ cerr << "DISKSTREAM GOT EVENT " << i << "!!\n";
+ }
+
+ if (_source_port->size() == 0)
+ cerr << "No events :/ (1)\n";
+
+
+ } else {
+
+ jack_nframes_t total = _capture_vector.len[0] + _capture_vector.len[1];
+
+ if (rec_nframes > total) {
+ cerr << "DiskOverrun\n";
+ //DiskOverrun (); // FIXME
+ goto out;
+ }
+
+ // FIXME (see above)
+ //RawMidi* buf = _io->input (0)->get_buffer (nframes) + offset;
+ assert(_source_port);
+ for (size_t i=0; i < _source_port->size(); ++i) {
+ cerr << "DISKSTREAM GOT EVENT " << i << "!!\n";
+ }
+ if (_source_port->size() == 0)
+ cerr << "No events :/ (2)\n";
+ RawMidi* buf = NULL; // FIXME FIXME FIXME (make it compile)
+ assert(false);
+ jack_nframes_t first = _capture_vector.len[0];
+
+ memcpy (_capture_wrap_buffer, buf, sizeof (RawMidi) * first);
+ memcpy (_capture_vector.buf[0], buf, sizeof (RawMidi) * first);
+ memcpy (_capture_wrap_buffer+first, buf + first, sizeof (RawMidi) * (rec_nframes - first));
+ memcpy (_capture_vector.buf[1], buf + first, sizeof (RawMidi) * (rec_nframes - first));
+
+ _current_capture_buffer = _capture_wrap_buffer;
+ }
+ } else {
+
+ if (was_recording) {
+ finish_capture (rec_monitors_input);
+ }
+
+ }
+
+ if (rec_nframes) {
+
+ /* data will be written to disk */
+
+ if (rec_nframes == nframes && rec_offset == 0) {
+
+ _current_playback_buffer = _current_capture_buffer;
+ playback_distance = nframes;
+
+ } else {
+
+
+ /* we can't use the capture buffer as the playback buffer, because
+ we recorded only a part of the current process' cycle data
+ for capture.
+ */
+
+ collect_playback = true;
+ }
+
+ adjust_capture_position = rec_nframes;
+
+ } else if (nominally_recording) {
+
+ /* can't do actual capture yet - waiting for latency effects to finish before we start*/
+
+ _current_playback_buffer = _current_capture_buffer;
+
+ playback_distance = nframes;
+
+ } else {
+
+ collect_playback = true;
+ }
+
+ if (collect_playback) {
+
+ /* we're doing playback */
+
+ jack_nframes_t necessary_samples;
+
+ /* no varispeed playback if we're recording, because the output .... TBD */
+
+ if (rec_nframes == 0 && _actual_speed != 1.0f) {
+ necessary_samples = (jack_nframes_t) floor ((nframes * fabs (_actual_speed))) + 1;
+ } else {
+ necessary_samples = nframes;
+ }
+
+ _playback_buf->get_read_vector (&_playback_vector);
+
+ if (necessary_samples <= _playback_vector.len[0]) {
+
+ _current_playback_buffer = _playback_vector.buf[0];
+
+ } else {
+ jack_nframes_t total = _playback_vector.len[0] + _playback_vector.len[1];
+
+ if (necessary_samples > total) {
+ cerr << "DiskUnderrun\n";
+ //DiskUnderrun (); // FIXME
+ goto out;
+
+ } else {
+
+ memcpy (_playback_wrap_buffer, _playback_vector.buf[0],
+ _playback_vector.len[0] * sizeof (RawMidi));
+ memcpy (_playback_wrap_buffer + _playback_vector.len[0], _playback_vector.buf[1],
+ (necessary_samples - _playback_vector.len[0]) * sizeof (RawMidi));
+
+ _current_playback_buffer = _playback_wrap_buffer;
+ }
+ }
+
+#if 0
+ if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) {
+
+ uint64_t phase = last_phase;
+ jack_nframes_t i = 0;
+
+ // Linearly interpolate into the alt buffer
+ // using 40.24 fixp maths (swh)
+
+ for (c = channels.begin(); c != channels.end(); ++c) {
+
+ float fr;
+ ChannelInfo& chan (*c);
+
+ i = 0;
+ phase = last_phase;
+
+ for (jack_nframes_t outsample = 0; outsample < nframes; ++outsample) {
+ i = phase >> 24;
+ fr = (phase & 0xFFFFFF) / 16777216.0f;
+ chan.speed_buffer[outsample] =
+ chan._current_playback_buffer[i] * (1.0f - fr) +
+ chan._current_playback_buffer[i+1] * fr;
+ phase += phi;
+ }
+
+ chan._current_playback_buffer = chan.speed_buffer;
+ }
+
+ playback_distance = i + 1;
+ last_phase = (phase & 0xFFFFFF);
+
+ } else {
+ playback_distance = nframes;
+ }
+#endif
+
+ playback_distance = nframes;
+
+ }
+
+ ret = 0;
+
+ out:
+ _processed = true;
+
+ if (ret) {
+
+ /* we're exiting with failure, so ::commit will not
+ be called. unlock the state lock.
+ */
+
+ state_lock.unlock();
+ }
+
+ return ret;
}
bool
@@ -382,23 +802,39 @@ MidiDiskstream::internal_playback_seek (jack_nframes_t distance)
}
int
-MidiDiskstream::read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed)
+MidiDiskstream::read (RawMidi* buf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed)
{
return 0;
}
-/*
+
int
-MidiDiskstream::do_refill (RawMidi* mixdown_buffer, float* gain_buffer, char * workbuf)
+MidiDiskstream::do_refill_with_alloc ()
{
return 0;
-}
+}
int
-MidiDiskstream::do_flush (char * workbuf, bool force_flush)
+MidiDiskstream::do_refill ()
{
return 0;
}
-*/
+
+/** Flush pending data to disk.
+ *
+ * Important note: this function will write *AT MOST* disk_io_chunk_frames
+ * of data to disk. it will never write more than that. If it writes that
+ * much and there is more than that waiting to be written, it will return 1,
+ * otherwise 0 on success or -1 on failure.
+ *
+ * If there is less than disk_io_chunk_frames to be written, no data will be
+ * written at all unless @a force_flush is true.
+ */
+int
+MidiDiskstream::do_flush (Session::RunContext context, bool force_flush)
+{
+ return 0;
+}
+
void
MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture)
{
@@ -412,6 +848,63 @@ MidiDiskstream::finish_capture (bool rec_monitors_input)
void
MidiDiskstream::set_record_enabled (bool yn)
{
+ if (!recordable() || !_session.record_enabling_legal()) {
+ return;
+ }
+
+ /* can't rec-enable in destructive mode if transport is before start */
+
+ if (destructive() && yn && _session.transport_frame() < _session.current_start_frame()) {
+ return;
+ }
+
+ if (yn && _source_port == 0) {
+
+ /* pick up connections not initiated *from* the IO object
+ we're associated with.
+ */
+
+ get_input_sources ();
+ }
+
+ /* yes, i know that this not proof against race conditions, but its
+ good enough. i think.
+ */
+
+ if (record_enabled() != yn) {
+ if (yn) {
+ engage_record_enable ();
+ } else {
+ disengage_record_enable ();
+ }
+ }
+}
+
+void
+MidiDiskstream::engage_record_enable ()
+{
+ bool rolling = _session.transport_speed() != 0.0f;
+
+ g_atomic_int_set (&_record_enabled, 1);
+
+ if (Config->get_use_hardware_monitoring() && _source_port) {
+ _source_port->request_monitor_input (!(_session.get_auto_input() && rolling));
+ }
+
+ RecordEnableChanged (); /* EMIT SIGNAL */
+}
+
+void
+MidiDiskstream::disengage_record_enable ()
+{
+ g_atomic_int_set (&_record_enabled, 0);
+ if (Config->get_use_hardware_monitoring()) {
+ if (_source_port) {
+ _source_port->request_monitor_input (false);
+ }
+ }
+
+ RecordEnableChanged (); /* EMIT SIGNAL */
}
XMLNode&
@@ -433,16 +926,14 @@ MidiDiskstream::get_state ()
id().print(buf);
node->add_property("id", buf);
- if (!_capturing_sources.empty() && _session.get_record_enabled()) {
+ if (_write_source && _session.get_record_enabled()) {
XMLNode* cs_child = new XMLNode (X_("CapturingSources"));
XMLNode* cs_grandchild;
- for (vector<SMFSource*>::iterator i = _capturing_sources.begin(); i != _capturing_sources.end(); ++i) {
- cs_grandchild = new XMLNode (X_("file"));
- cs_grandchild->add_property (X_("path"), (*i)->path());
- cs_child->add_child_nocopy (*cs_grandchild);
- }
+ cs_grandchild = new XMLNode (X_("file"));
+ cs_grandchild->add_property (X_("path"), _write_source->path());
+ cs_child->add_child_nocopy (*cs_grandchild);
/* store the location where capture will start */
@@ -545,7 +1036,8 @@ MidiDiskstream::set_state (const XMLNode& node)
/* make sure this is clear before we do anything else */
- _capturing_sources.clear ();
+ // FIXME?
+ //_capturing_source = 0;
/* write sources are handled when we handle the input set
up of the IO that owns this DS (::non_realtime_input_change())
@@ -559,17 +1051,85 @@ MidiDiskstream::set_state (const XMLNode& node)
int
MidiDiskstream::use_new_write_source (uint32_t n)
{
+ if (!recordable()) {
+ return 1;
+ }
+
+ assert(n == 0);
+
+ if (_write_source) {
+
+ if (SMFSource::is_empty (_write_source->path())) {
+ _write_source->mark_for_remove ();
+ _write_source->release();
+ delete _write_source;
+ } else {
+ _write_source->release();
+ _write_source = 0;
+ }
+ }
+
+ try {
+ _write_source = dynamic_cast<SMFSource*>(_session.create_midi_source_for_session (*this));
+ if (!_write_source) {
+ throw failed_constructor();
+ }
+ }
+
+ catch (failed_constructor &err) {
+ error << string_compose (_("%1:%2 new capture file not initialized correctly"), _name, n) << endmsg;
+ _write_source = 0;
+ return -1;
+ }
+
+ _write_source->use ();
+
+ /* do not remove destructive files even if they are empty */
+
+ _write_source->set_allow_remove_if_empty (!destructive());
+
return 0;
}
void
MidiDiskstream::reset_write_sources (bool mark_write_complete, bool force)
{
+ if (!recordable()) {
+ return;
+ }
+
+ if (!destructive()) {
+
+ if (_write_source && mark_write_complete) {
+ _write_source->mark_streaming_write_completed ();
+ }
+ use_new_write_source ();
+
+ } else {
+ if (_write_source == 0) {
+ use_new_write_source ();
+ }
+ }
+
+ if (destructive()) {
+
+ /* we now have all our write sources set up, so create the
+ playlist's single region.
+ */
+
+ if (_playlist->empty()) {
+ setup_destructive_playlist ();
+ }
+ }
}
int
MidiDiskstream::rename_write_sources ()
{
+ if (_write_source != 0) {
+ _write_source->set_name (_name, destructive());
+ /* XXX what to do if this fails ? */
+ }
return 0;
}
@@ -586,24 +1146,47 @@ MidiDiskstream::allocate_temporary_buffers ()
void
MidiDiskstream::monitor_input (bool yn)
{
+ if (_source_port)
+ _source_port->request_monitor_input (yn);
+ else
+ cerr << "MidiDiskstream NO SOURCE PORT TO MONITOR\n";
}
void
MidiDiskstream::set_align_style_from_io ()
{
+ bool have_physical = false;
+
+ if (_io == 0) {
+ return;
+ }
+
+ get_input_sources ();
+
+ if (_source_port && _source_port->flags() & JackPortIsPhysical) {
+ have_physical = true;
+ }
+
+ if (have_physical) {
+ set_align_style (ExistingMaterial);
+ } else {
+ set_align_style (CaptureTime);
+ }
}
float
MidiDiskstream::playback_buffer_load () const
{
- return 0;
+ return (float) ((double) _playback_buf->read_space()/
+ (double) _playback_buf->bufsize());
}
float
MidiDiskstream::capture_buffer_load () const
{
- return 0;
+ return (float) ((double) _capture_buf->write_space()/
+ (double) _capture_buf->bufsize());
}
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index 007856e3a7..db28c06f17 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -164,71 +164,43 @@ struct RegionSortByLayer
}
};
+/** FIXME: semantics of return value? */
jack_nframes_t
-MidiPlaylist::read (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t start,
+MidiPlaylist::read (RawMidi *buf, RawMidi *mixdown_buffer, jack_nframes_t start,
jack_nframes_t cnt, unsigned chan_n)
{
- jack_nframes_t ret = cnt;
- jack_nframes_t end;
- jack_nframes_t read_frames;
- jack_nframes_t skip_frames;
-
- /* optimizing this memset() away involves a lot of conditionals
- that may well cause more of a hit due to cache misses
- and related stuff than just doing this here.
-
- it would be great if someone could measure this
- at some point.
-
- one way or another, parts of the requested area
- that are not written to by Region::region_at()
- for all Regions that cover the area need to be
- zeroed.
- */
-
- memset (buf, 0, sizeof (unsigned char) * cnt);
-
/* this function is never called from a realtime thread, so
its OK to block (for short intervals).
*/
Glib::Mutex::Lock rm (region_lock);
- end = start + cnt - 1;
+ jack_nframes_t ret = 0;
+ jack_nframes_t end = start + cnt - 1;
+ jack_nframes_t read_frames = 0;
+ jack_nframes_t skip_frames = 0;
- read_frames = 0;
- skip_frames = 0;
_read_data_count = 0;
- map<uint32_t,vector<Region*> > relevant_regions;
- vector<uint32_t> relevant_layers;
+ vector<MidiRegion*> regs; // relevent regions overlapping start <--> end
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
- if ((*i)->coverage (start, end) != OverlapNone) {
-
- relevant_regions[(*i)->layer()].push_back (*i);
- relevant_layers.push_back ((*i)->layer());
+ MidiRegion* const mr = dynamic_cast<MidiRegion*>(*i);
+ if (mr && mr->coverage (start, end) != OverlapNone) {
+ regs.push_back(mr);
}
}
- // RegionSortByLayer layer_cmp;
- // relevant_regions.sort (layer_cmp);
-
-
- for (vector<uint32_t>::iterator l = relevant_layers.begin(); l != relevant_layers.end(); ++l) {
-
- // FIXME: Should be vector<MidiRegion*>
- vector<Region*>& r (relevant_regions[*l]);
-
- for (vector<Region*>::iterator i = r.begin(); i != r.end(); ++i) {
- MidiRegion* const mr = dynamic_cast<MidiRegion*>(*i);
- assert(mr);
- mr->read_at (buf, mixdown_buffer, workbuf, start, cnt, chan_n, read_frames, skip_frames);
- _read_data_count += mr->read_data_count();
- }
+ RegionSortByLayer layer_cmp;
+ sort(regs.begin(), regs.end(), layer_cmp);
+ for (vector<MidiRegion*>::iterator i = regs.begin(); i != regs.end(); ++i) {
+ (*i)->read_at (buf, mixdown_buffer, start, cnt, chan_n, read_frames, skip_frames);
+ ret += (*i)->read_data_count();
}
+ _read_data_count += ret;
+
return ret;
}
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
new file mode 100644
index 0000000000..e785710b01
--- /dev/null
+++ b/libs/ardour/midi_port.cc
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2006 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 <cassert>
+#include <ardour/midi_port.h>
+#include <ardour/data_type.h>
+#include <iostream>
+
+using namespace ARDOUR;
+using namespace std;
+
+MidiPort::MidiPort(jack_port_t* p)
+ : Port(p)
+ , _buffer(NULL)
+ , _nframes_this_cycle(0)
+{
+ DataType dt(_type);
+ assert(dt == DataType::MIDI);
+
+ reset();
+
+ _buffer = new MidiBuffer(4096); // FIXME FIXME FIXME
+}
+
+
+MidiPort::~MidiPort()
+{
+ delete _buffer;
+}
+
+void
+MidiPort::cycle_start (jack_nframes_t nframes)
+{
+ _nframes_this_cycle = nframes;
+
+ if (_flags & JackPortIsOutput) {
+ _buffer->set_size(0);
+ return;
+ }
+
+ // We're an input - copy Jack events to internal buffer
+
+ void* jack_buffer = jack_port_get_buffer(_port, nframes);
+
+ const jack_nframes_t event_count
+ = jack_midi_port_get_info(jack_buffer, nframes)->event_count;
+
+ assert(event_count < _buffer->capacity());
+
+ for (jack_nframes_t i=0; i < event_count; ++i) {
+ jack_midi_event_t* const ev = &_buffer->data()[i];
+ jack_midi_event_get(ev, jack_buffer, i, nframes);
+
+ // Convert note ons with velocity 0 to proper note offs
+ // FIXME: Jack MIDI should guarantee this - does it?
+ //if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0)
+ // ev->buffer[0] = MIDI_CMD_NOTE_OFF;
+ }
+
+ _buffer->set_size(event_count);
+
+ if (_buffer->size() > 0)
+ cerr << "MIDIPort got " << event_count << " events." << endl;
+}
+
+void
+MidiPort::cycle_end()
+{
+ if (_flags & JackPortIsInput) {
+ _nframes_this_cycle = 0; // catch any oopses
+ return;
+ }
+
+ // We're an output - copy events from internal buffer to Jack buffer
+
+ void* jack_buffer = jack_port_get_buffer(_port, _nframes_this_cycle);
+
+ const jack_nframes_t event_count = _buffer->size();
+
+ jack_midi_clear_buffer(jack_buffer, _nframes_this_cycle);
+ for (jack_nframes_t i=0; i < event_count; ++i) {
+ const jack_midi_event_t& ev = _buffer->data()[i];
+ jack_midi_event_write(jack_buffer, ev.time, ev.buffer, ev.size, _nframes_this_cycle);
+ }
+
+ _nframes_this_cycle = 0; // catch oopses
+}
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index d78506c1fc..0902337030 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -1,6 +1,5 @@
/*
- Copyright (C) 2006 Paul Davis
- Written by Dave Robillard, 2006
+ Copyright (C) 2000-2006 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
@@ -15,6 +14,8 @@
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.
+
+ $Id: midiregion.cc 746 2006-08-02 02:44:23Z drobilla $
*/
#include <cmath>
@@ -37,6 +38,7 @@
#include <ardour/dB.h>
#include <ardour/playlist.h>
#include <ardour/midi_source.h>
+#include <ardour/types.h>
#include "i18n.h"
#include <locale.h>
@@ -44,20 +46,10 @@
using namespace std;
using namespace ARDOUR;
-MidiRegionState::MidiRegionState (string why)
- : RegionState (why)
-{
-}
-
+/** Basic MidiRegion constructor (one channel) */
MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, bool announce)
- : Region (start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External))
+ : Region (src, start, length, PBD::basename_nosuffix(src.name()), 0, Region::Flag(Region::DefaultFlags|Region::External))
{
- /* basic MidiRegion constructor */
-
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
-
save_state ("initial state");
if (announce) {
@@ -65,15 +57,10 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le
}
}
+/* Basic MidiRegion constructor (one channel) */
MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
- : Region (start, length, name, layer, flags)
+ : Region (src, start, length, name, layer, flags)
{
- /* basic MidiRegion constructor */
-
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
-
save_state ("initial state");
if (announce) {
@@ -81,75 +68,40 @@ MidiRegion::MidiRegion (MidiSource& src, jack_nframes_t start, jack_nframes_t le
}
}
+/* Basic MidiRegion constructor (many channels) */
MidiRegion::MidiRegion (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
- : Region (start, length, name, layer, flags)
+ : Region (srcs, start, length, name, layer, flags)
{
- /* basic MidiRegion constructor */
-#if 0
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
- sources.push_back (*i);
- master_sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- }
-
-{
- /* create a new MidiRegion, that is part of an existing one */
-
- set<MidiSource*> unique_srcs;
+ save_state ("initial state");
- for (SourceList::const_iterator i= other.sources.begin(); i != other.sources.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- unique_srcs.insert (*i);
+ if (announce) {
+ CheckNewRegion (this); /* EMIT SIGNAL */
}
+}
- for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- }
- master_sources.push_back (*i);
- }
+/** Create a new MidiRegion, that is part of an existing one */
+MidiRegion::MidiRegion (const MidiRegion& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags, bool announce)
+ : Region (other, offset, length, name, layer, flags)
+{
save_state ("initial state");
if (announce) {
CheckNewRegion (this); /* EMIT SIGNAL */
}
-#endif
}
MidiRegion::MidiRegion (const MidiRegion &other)
: Region (other)
{
- /* Pure copy constructor */
-
- set<MidiSource*> unique_srcs;
-
- for (SourceList::const_iterator i = other.sources.begin(); i != other.sources.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- unique_srcs.insert (*i);
- }
-
- for (SourceList::const_iterator i = other.master_sources.begin(); i != other.master_sources.end(); ++i) {
- master_sources.push_back (*i);
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- }
- }
-
save_state ("initial state");
/* NOTE: no CheckNewRegion signal emitted here. This is the copy constructor */
}
MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node)
- : Region (node)
+ : Region (src, node)
{
- sources.push_back (&src);
- master_sources.push_back (&src);
- src.GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
-
if (set_state (node)) {
throw failed_constructor();
}
@@ -160,25 +112,8 @@ MidiRegion::MidiRegion (MidiSource& src, const XMLNode& node)
}
MidiRegion::MidiRegion (SourceList& srcs, const XMLNode& node)
- : Region (node)
+ : Region (srcs, node)
{
- /* basic MidiRegion constructor */
-
- set<MidiSource*> unique_srcs;
-
- for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
- sources.push_back (*i);
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- unique_srcs.insert (*i);
- }
-
- for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
- master_sources.push_back (*i);
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
- }
- }
-
if (set_state (node)) {
throw failed_constructor();
}
@@ -196,7 +131,7 @@ MidiRegion::~MidiRegion ()
StateManager::State*
MidiRegion::state_factory (std::string why) const
{
- MidiRegionState* state = new MidiRegionState (why);
+ RegionState* state = new RegionState (why);
Region::store_state (*state);
@@ -206,8 +141,7 @@ MidiRegion::state_factory (std::string why) const
Change
MidiRegion::restore_state (StateManager::State& sstate)
{
- MidiRegionState* state = dynamic_cast<MidiRegionState*> (&sstate);
-
+ RegionState* state = dynamic_cast<RegionState*> (&sstate);
Change what_changed = Region::restore_and_return_flags (*state);
if (_flags != Flag (state->_flags)) {
@@ -215,11 +149,8 @@ MidiRegion::restore_state (StateManager::State& sstate)
//uint32_t old_flags = _flags;
_flags = Flag (state->_flags);
-
}
- /* XXX need a way to test stored state versus current for envelopes */
-
what_changed = Change (what_changed);
return what_changed;
@@ -231,66 +162,23 @@ MidiRegion::get_memento() const
return sigc::bind (mem_fun (*(const_cast<MidiRegion *> (this)), &StateManager::use_state), _current_state_id);
}
-bool
-MidiRegion::verify_length (jack_nframes_t len)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (_start > sources[n]->length() - len) {
- return false;
- }
- }
- return true;
-}
-
-bool
-MidiRegion::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (new_length > sources[n]->length() - new_start) {
- return false;
- }
- }
- return true;
-}
-bool
-MidiRegion::verify_start (jack_nframes_t pos)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (pos > sources[n]->length() - _length) {
- return false;
- }
- }
- return true;
-}
-
-bool
-MidiRegion::verify_start_mutable (jack_nframes_t& new_start)
-{
- for (uint32_t n=0; n < sources.size(); ++n) {
- if (new_start > sources[n]->length() - _length) {
- new_start = sources[n]->length() - _length;
- }
- }
- return true;
-}
-
jack_nframes_t
-MidiRegion::read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position,
+MidiRegion::read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position,
jack_nframes_t cnt,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
- return _read_at (sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, read_frames, skip_frames);
+ return _read_at (_sources, out, position, cnt, chan_n, read_frames, skip_frames);
}
jack_nframes_t
-MidiRegion::master_read_at (unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf, jack_nframes_t position,
+MidiRegion::master_read_at (RawMidi *out, RawMidi* mix_buf, jack_nframes_t position,
jack_nframes_t cnt, uint32_t chan_n) const
{
- return _read_at (master_sources, buf, mixdown_buffer, workbuf, position, cnt, chan_n, 0, 0);
+ return _read_at (_master_sources, out, position, cnt, chan_n, 0, 0);
}
jack_nframes_t
-MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char *mixdown_buffer, char * workbuf,
+MidiRegion::_read_at (const SourceList& srcs, RawMidi *buf,
jack_nframes_t position, jack_nframes_t cnt,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
@@ -300,9 +188,7 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char
/* precondition: caller has verified that we cover the desired section */
- if (chan_n >= sources.size()) {
- return 0; /* read nothing */
- }
+ assert(chan_n == 0);
if (position < _position) {
internal_offset = 0;
@@ -322,12 +208,8 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char
return 0; /* read nothing */
}
- if (opaque()) {
- /* overwrite whatever is there */
- mixdown_buffer = buf + buf_offset;
- } else {
- mixdown_buffer += buf_offset;
- }
+ // FIXME: non-opaque MIDI regions not yet supported
+ assert(opaque());
if (muted()) {
return 0; /* read nothing */
@@ -335,39 +217,21 @@ MidiRegion::_read_at (const SourceList& srcs, unsigned char *buf, unsigned char
_read_data_count = 0;
- if (srcs[chan_n]->read (mixdown_buffer, _start + internal_offset, to_read, workbuf) != to_read) {
+ MidiSource& src = midi_source(chan_n);
+ if (src.read (buf, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
- _read_data_count += srcs[chan_n]->read_data_count();
-
- if (!opaque()) {
+ _read_data_count += src.read_data_count();
- /* gack. the things we do for users.
- */
-
- buf += buf_offset;
-
- for (jack_nframes_t n = 0; n < to_read; ++n) {
- buf[n] += mixdown_buffer[n];
- }
- }
-
return to_read;
}
XMLNode&
-MidiRegion::get_state ()
-{
- return state (true);
-}
-
-XMLNode&
MidiRegion::state (bool full)
{
XMLNode& node (Region::state (full));
-#if 0
-//XMLNode *child;
+ XMLNode *child;
char buf[64];
char buf2[64];
LocaleGuard lg (X_("POSIX"));
@@ -375,19 +239,25 @@ MidiRegion::state (bool full)
snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
node.add_property ("flags", buf);
- for (uint32_t n=0; n < sources.size(); ++n) {
+ for (uint32_t n=0; n < _sources.size(); ++n) {
snprintf (buf2, sizeof(buf2), "source-%d", n);
- snprintf (buf, sizeof(buf), "%" PRIu64, sources[n]->id());
+ _sources[n]->id().print (buf);
node.add_property (buf2, buf);
}
- snprintf (buf, sizeof (buf), "%u", (uint32_t) sources.size());
+ snprintf (buf, sizeof (buf), "%u", (uint32_t) _sources.size());
node.add_property ("channels", buf);
+ child = node.add_child ("Envelope");
+
+ if ( ! full) {
+ child->add_property ("default", "yes");
+ }
+
if (full && _extra_xml) {
node.add_child_copy (*_extra_xml);
}
-#endif
+
return node;
}
@@ -402,31 +272,51 @@ MidiRegion::set_state (const XMLNode& node)
if ((prop = node.property ("flags")) != 0) {
_flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
-
- _flags = Flag (_flags & ~Region::LeftOfSplit);
- _flags = Flag (_flags & ~Region::RightOfSplit);
}
- /* Now find envelope description and other misc child items */
-
+ /* Now find child items */
for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
XMLNode *child;
//XMLProperty *prop;
child = (*niter);
+
+ /** Hello, children */
}
return 0;
}
+void
+MidiRegion::recompute_at_end ()
+{
+ /* our length has changed
+ * (non destructively) "chop" notes that pass the end boundary, to
+ * prevent stuck notes.
+ */
+}
+
+void
+MidiRegion::recompute_at_start ()
+{
+ /* as above, but the shift was from the front
+ * maybe bump currently active note's note-ons up so they sound here?
+ * that could be undesireable in certain situations though.. maybe
+ * remove the note entirely, including it's note off? something needs to
+ * be done to keep the played MIDI sane to avoid messing up voices of
+ * polyhonic things etc........
+ */
+}
+
int
MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const
{
+#if 0
SourceList srcs;
string new_name;
- for (SourceList::const_iterator i = master_sources.begin(); i != master_sources.end(); ++i) {
+ for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
srcs.clear ();
srcs.push_back (*i);
@@ -441,185 +331,14 @@ MidiRegion::separate_by_channel (Session& session, vector<MidiRegion*>& v) const
v.push_back (new MidiRegion (srcs, _start, _length, new_name, _layer, _flags));
}
-
- return 0;
-}
-
-void
-MidiRegion::source_deleted (Source* ignored)
-{
- delete this;
-}
-
-void
-MidiRegion::lock_sources ()
-{
- SourceList::iterator i;
- set<MidiSource*> unique_srcs;
-
- for (i = sources.begin(); i != sources.end(); ++i) {
- unique_srcs.insert (*i);
- (*i)->use ();
- }
-
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->use ();
- }
- }
-}
-
-void
-MidiRegion::unlock_sources ()
-{
- SourceList::iterator i;
- set<MidiSource*> unique_srcs;
-
- for (i = sources.begin(); i != sources.end(); ++i) {
- unique_srcs.insert (*i);
- (*i)->release ();
- }
-
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- if (unique_srcs.find (*i) == unique_srcs.end()) {
- (*i)->release ();
- }
- }
-}
-
-vector<string>
-MidiRegion::master_source_names ()
-{
- SourceList::iterator i;
-
- vector<string> names;
- for (i = master_sources.begin(); i != master_sources.end(); ++i) {
- names.push_back((*i)->name());
- }
-
- return names;
-}
-
-bool
-MidiRegion::source_equivalent (const Region& o) const
-{
- const MidiRegion* other = dynamic_cast<const MidiRegion*>(&o);
- if (!other)
- return false;
-
- SourceList::const_iterator i;
- SourceList::const_iterator io;
-
- for (i = sources.begin(), io = other->sources.begin(); i != sources.end() && io != other->sources.end(); ++i, ++io) {
- if ((*i)->id() != (*io)->id()) {
- return false;
- }
- }
-
- for (i = master_sources.begin(), io = other->master_sources.begin(); i != master_sources.end() && io != other->master_sources.end(); ++i, ++io) {
- if ((*i)->id() != (*io)->id()) {
- return false;
- }
- }
-
- return true;
-}
-
-#if 0
-int
-MidiRegion::exportme (Session& session, AudioExportSpecification& spec)
-{
- const jack_nframes_t blocksize = 4096;
- jack_nframes_t to_read;
- int status = -1;
-
- spec.channels = sources.size();
-
- if (spec.prepare (blocksize, session.frame_rate())) {
- goto out;
- }
-
- spec.pos = 0;
- spec.total_frames = _length;
-
- while (spec.pos < _length && !spec.stop) {
-
-
- /* step 1: interleave */
-
- to_read = min (_length - spec.pos, blocksize);
-
- if (spec.channels == 1) {
-
- if (sources.front()->read (spec.dataF, _start + spec.pos, to_read, 0) != to_read) {
- goto out;
- }
-
- } else {
-
- Sample buf[blocksize];
-
- for (uint32_t chan = 0; chan < spec.channels; ++chan) {
-
- if (sources[chan]->read (buf, _start + spec.pos, to_read, 0) != to_read) {
- goto out;
- }
-
- for (jack_nframes_t x = 0; x < to_read; ++x) {
- spec.dataF[chan+(x*spec.channels)] = buf[x];
- }
- }
- }
-
- if (spec.process (to_read)) {
- goto out;
- }
-
- spec.pos += to_read;
- spec.progress = (double) spec.pos /_length;
-
- }
-
- status = 0;
-
- out:
- spec.running = false;
- spec.status = status;
- spec.clear();
-
- return status;
-}
-#endif
-
-Region*
-MidiRegion::get_parent()
-{
-#if 0
- Region* r = 0;
-
- if (_playlist) {
- r = _playlist->session().find_whole_file_parent (*this);
- }
-
- return r;
#endif
- return NULL;
+ return -1;
}
-
-bool
-MidiRegion::speed_mismatch (float sr) const
+MidiSource&
+MidiRegion::midi_source (uint32_t n) const
{
-#if 0
- if (sources.empty()) {
- /* impossible, but ... */
- return false;
- }
-
- float fsr = sources.front()->sample_rate();
-
- return fsr == sr;
-#endif
- return false;
+ // Guaranteed to succeed (use a static cast?)
+ return dynamic_cast<MidiSource&>(source(n));
}
diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc
index f9fc8dd8ec..4cda0f6ebd 100644
--- a/libs/ardour/midi_source.cc
+++ b/libs/ardour/midi_source.cc
@@ -90,44 +90,26 @@ MidiSource::set_state (const XMLNode& node)
}
jack_nframes_t
-MidiSource::read (unsigned char *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
+MidiSource::read (RawMidi* dst, jack_nframes_t start, jack_nframes_t cnt) const
{
- //Glib::Mutex::Lock lm (_lock);
- //return read_unlocked (dst, start, cnt, workbuf);
- return 0;
+ Glib::Mutex::Lock lm (_lock);
+ return read_unlocked (dst, start, cnt);
}
jack_nframes_t
-MidiSource::write (unsigned char *dst, jack_nframes_t cnt, char * workbuf)
+MidiSource::write (RawMidi* dst, jack_nframes_t cnt)
{
- //Glib::Mutex::Lock lm (_lock);
- //return write_unlocked (dst, cnt, workbuf);
- return 0;
+ Glib::Mutex::Lock lm (_lock);
+ return write_unlocked (dst, cnt);
}
-
bool
MidiSource::file_changed (string path)
{
struct stat stat_file;
- //struct stat stat_peak;
int e1 = stat (path.c_str(), &stat_file);
- //int e2 = stat (peak_path(path).c_str(), &stat_peak);
- if (!e1){//&& !e2 && stat_file.st_mtime > stat_peak.st_mtime){
- return true;
- } else {
- return false;
- }
-}
-
-
-void
-MidiSource::update_length (jack_nframes_t pos, jack_nframes_t cnt)
-{
- if (pos + cnt > _length) {
- _length = pos+cnt;
- }
+ return ( !e1 );
}
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index f37ba9f190..93eba11a30 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -507,6 +507,15 @@ MidiTrack::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack
return midi_diskstream().process (_session.transport_frame() + offset, nframes, offset, can_record, rec_monitors_input);
}
+void
+MidiTrack::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
+ jack_nframes_t start_frame, jack_nframes_t end_frame,
+ jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
+ bool meter)
+{
+ // Do nothing (just bypass the Route version to avoid flaming death)
+}
+
int
MidiTrack::set_name (string str, void *src)
{
@@ -530,7 +539,7 @@ MidiTrack::set_name (string str, void *src)
}
int
-MidiTrack::export_stuff (vector<unsigned char*>& buffers, char * workbuf, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
+MidiTrack::export_stuff (vector<unsigned char*>& buffers, uint32_t nbufs, jack_nframes_t start, jack_nframes_t nframes)
{
return 0;
}
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index 8336c4697c..f866b5ae10 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -1258,10 +1258,10 @@ Panner::set_state (const XMLNode& node)
float x, y;
prop = (*niter)->property (X_("x"));
- sscanf (prop->value().c_str(), "%.12g", &x);
+ sscanf (prop->value().c_str(), "%g", &x);
prop = (*niter)->property (X_("y"));
- sscanf (prop->value().c_str(), "%.12g", &y);
+ sscanf (prop->value().c_str(), "%g", &y);
outputs.push_back (Output (x, y));
}
diff --git a/libs/ardour/plugin.cc b/libs/ardour/plugin.cc
index 8ea95b8903..bedc32a0b3 100644
--- a/libs/ardour/plugin.cc
+++ b/libs/ardour/plugin.cc
@@ -244,25 +244,25 @@ Plugin::save_preset (string name, string domain)
}
PluginPtr
-ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginInfo::Type type)
+ARDOUR::find_plugin(Session& session, string name, long unique_id, PluginType type)
{
PluginManager *mgr = PluginManager::the_manager();
PluginInfoList plugs;
switch (type) {
- case PluginInfo::LADSPA:
+ case ARDOUR::LADSPA:
plugs = mgr->ladspa_plugin_info();
break;
#ifdef VST_SUPPORT
- case PluginInfo::VST:
+ case ARDOUR::VST:
plugs = mgr->vst_plugin_info();
unique_id = 0; // VST plugins don't have a unique id.
break;
#endif
#ifdef HAVE_COREAUDIO
- case PluginInfo::AudioUnit:
+ case ARDOUR::AudioUnit:
plugs = AUPluginInfo::discover ();
unique_id = 0; // Neither do AU.
break;
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index 2a753617e8..5b3a4658a8 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -254,7 +254,7 @@ PluginManager::ladspa_discover (string path)
info->index = i;
info->n_inputs = 0;
info->n_outputs = 0;
- info->type = PluginInfo::LADSPA;
+ info->type = ARDOUR::LADSPA;
info->unique_id = descriptor->UniqueID;
for (uint32_t n=0; n < descriptor->PortCount; ++n) {
@@ -397,7 +397,7 @@ PluginManager::vst_discover (string path)
info->index = 0;
info->n_inputs = finfo->numInputs;
info->n_outputs = finfo->numOutputs;
- info->type = PluginInfo::VST;
+ info->type = ARDOUR::VST;
_vst_plugin_info.push_back (info);
fst_free_info (finfo);
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index 7ec0d5a05a..5f8b454f0f 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2002 Paul Davis
+ Copyright (C) 2002-2006 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
@@ -18,13 +18,16 @@
$Id$
*/
-#include "ardour/port.h"
+#include <ardour/port.h>
using namespace ARDOUR;
using namespace std;
Port::Port (jack_port_t *p)
: _port (p)
+ , _metering(0)
+ , _last_monitor(false)
+ , _silent(false)
{
if (_port == 0) {
throw failed_constructor();
@@ -40,13 +43,8 @@ Port::Port (jack_port_t *p)
void
Port::reset ()
{
- reset_buffer ();
-
_last_monitor = false;
_silent = false;
- _metering = 0;
-
- reset_meters ();
}
int
diff --git a/libs/ardour/port_set.cc b/libs/ardour/port_set.cc
new file mode 100644
index 0000000000..22fb032c09
--- /dev/null
+++ b/libs/ardour/port_set.cc
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2006 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 <ardour/port_set.h>
+
+namespace ARDOUR {
+
+PortSet::PortSet()
+{
+ for (size_t i=0; i < DataType::num_types; ++i)
+ _ports.push_back( PortVec() );
+}
+
+static bool sort_ports_by_name (Port* a, Port* b)
+{
+ return (a->name() < b->name());
+}
+
+void
+PortSet::add_port(Port* port)
+{
+ const size_t list_index = port->type().to_index();
+ assert(list_index < _ports.size());
+
+ PortVec& v = _ports[list_index];
+
+ v.push_back(port);
+ sort(v.begin(), v.end(), sort_ports_by_name);
+
+ _chan_count.set_count(port->type(), _chan_count.get_count(port->type()) + 1);
+
+ assert(_chan_count.get_count(port->type()) == _ports[port->type().to_index()].size());
+}
+
+
+/** Get the total number of ports (of all types) in the PortSet
+ */
+size_t
+PortSet::num_ports() const
+{
+ size_t ret = 0;
+
+ for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l)
+ ret += (*l).size();
+
+ return ret;
+}
+
+bool
+PortSet::contains(const Port* port) const
+{
+ for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l)
+ if (find((*l).begin(), (*l).end(), port) != (*l).end())
+ return true;
+
+ return false;
+}
+
+Port*
+PortSet::port(size_t n) const
+{
+ // This is awesome
+
+ size_t size_so_far = 0;
+
+ for (std::vector<PortVec>::const_iterator l = _ports.begin(); l != _ports.end(); ++l) {
+ if (n < size_so_far + (*l).size())
+ return (*l)[n - size_so_far];
+ else
+ size_so_far += (*l).size();
+ }
+
+ return NULL; // n out of range
+}
+
+Port*
+PortSet::nth_port_of_type(DataType type, size_t n) const
+{
+ const PortVec& v = _ports[type.to_index()];
+ assert(n < v.size());
+ return v[n];
+}
+
+AudioPort*
+PortSet::nth_audio_port(size_t n) const
+{
+ return dynamic_cast<AudioPort*>(nth_port_of_type(DataType::AUDIO, n));
+}
+
+MidiPort*
+PortSet::nth_midi_port(size_t n) const
+{
+ return dynamic_cast<MidiPort*>(nth_port_of_type(DataType::MIDI, n));
+}
+
+} // namepace ARDOUR
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 037c844324..03a4d1d2a3 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -32,6 +32,7 @@
#include <ardour/region.h>
#include <ardour/playlist.h>
#include <ardour/session.h>
+#include <ardour/source.h>
#include "i18n.h"
@@ -49,63 +50,124 @@ Change Region::HiddenChanged = ARDOUR::new_change ();
sigc::signal<void,Region *> Region::CheckNewRegion;
-Region::Region (jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
+/** Basic Region constructor (single source) */
+Region::Region (Source& src, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
+ : _name(name)
+ , _flags(flags)
+ , _start(start)
+ , _length(length)
+ , _position(0)
+ , _sync_position(_start)
+ , _layer(layer)
+ , _first_edit(EditChangesNothing)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change (0))
+ , _last_layer_op(0)
+ , _playlist(0)
{
- /* basic Region constructor */
+ _current_state_id = 0;
+
+ _sources.push_back (&src);
+ _master_sources.push_back (&src);
+ src.GoingAway.connect (mem_fun (*this, &Region::source_deleted));
- _flags = flags;
- _playlist = 0;
- _read_data_count = 0;
- _frozen = 0;
- pending_changed = Change (0);
+ assert(_sources.size() > 0);
+}
- _name = name;
- _start = start;
- _sync_position = _start;
- _length = length;
- _position = 0;
- _layer = layer;
+/** Basic Region constructor (many sources) */
+Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, const string& name, layer_t layer, Region::Flag flags)
+ : _name(name)
+ , _flags(flags)
+ , _start(start)
+ , _length(length)
+ , _position(0)
+ , _sync_position(_start)
+ , _layer(layer)
+ , _first_edit(EditChangesNothing)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change (0))
+ , _last_layer_op(0)
+ , _playlist(0)
+{
_current_state_id = 0;
- _read_data_count = 0;
- _first_edit = EditChangesNothing;
- _last_layer_op = 0;
+
+ set<Source*> unique_srcs;
+
+ for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
+ _sources.push_back (*i);
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ unique_srcs.insert (*i);
+ }
+
+ for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+ _master_sources.push_back (*i);
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ }
+ }
+
+ assert(_sources.size() > 0);
}
+/** Create a new Region from part of an existing one */
Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
+ : _name(name)
+ , _flags(Flag(flags & ~(Locked|WholeFile|Hidden)))
+ , _start(other._start + offset)
+ , _length(length)
+ , _position(0)
+ , _sync_position(_start)
+ , _layer(layer)
+ , _first_edit(EditChangesNothing)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change (0))
+ , _last_layer_op(0)
+ , _playlist(0)
{
- /* create a new Region from part of an existing one */
+ _current_state_id = 0;
+
+ if (other._sync_position < offset)
+ _sync_position = other._sync_position;
- _frozen = 0;
- pending_changed = Change (0);
- _playlist = 0;
- _read_data_count = 0;
+ set<Source*> unique_srcs;
- _start = other._start + offset;
- if (other._sync_position < offset) {
- _sync_position = other._sync_position;
- } else {
- _sync_position = _start;
+ for (SourceList::const_iterator i= other._sources.begin(); i != other._sources.end(); ++i) {
+ _sources.push_back (*i);
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ unique_srcs.insert (*i);
}
- _length = length;
- _name = name;
- _position = 0;
- _layer = layer;
- _flags = Flag (flags & ~(Locked|WholeFile|Hidden));
- _current_state_id = 0;
- _first_edit = EditChangesNothing;
- _last_layer_op = 0;
+
+ for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ }
+ _master_sources.push_back (*i);
+ }
+
+ assert(_sources.size() > 0);
}
+/** Pure copy constructor */
Region::Region (const Region &other)
+ : _name(other._name)
+ , _flags(Flag(other._flags & ~Locked))
+ , _start(other._start)
+ , _length(other._length)
+ , _position(other._position)
+ , _sync_position(other._sync_position)
+ , _layer(other._layer)
+ , _first_edit(EditChangesID)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change(0))
+ , _last_layer_op(other._last_layer_op)
+ , _playlist(0)
{
- /* Pure copy constructor */
-
- _frozen = 0;
- pending_changed = Change (0);
- _playlist = 0;
- _read_data_count = 0;
-
- _first_edit = EditChangesID;
+ _current_state_id = 0;
+
other._first_edit = EditChangesName;
if (other._extra_xml) {
@@ -114,36 +176,88 @@ Region::Region (const Region &other)
_extra_xml = 0;
}
- _start = other._start;
- _sync_position = other._sync_position;
- _length = other._length;
- _name = other._name;
- _position = other._position;
- _layer = other._layer;
- _flags = Flag (other._flags & ~Locked);
+ set<Source*> unique_srcs;
+
+ for (SourceList::const_iterator i = other._sources.begin(); i != other._sources.end(); ++i) {
+ _sources.push_back (*i);
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ unique_srcs.insert (*i);
+ }
+
+ for (SourceList::const_iterator i = other._master_sources.begin(); i != other._master_sources.end(); ++i) {
+ _master_sources.push_back (*i);
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ }
+ }
+
+ assert(_sources.size() > 0);
+}
+
+Region::Region (SourceList& srcs, const XMLNode& node)
+ : _name(X_("error: XML did not reset this"))
+ , _flags(Flag(0))
+ , _start(0)
+ , _length(0)
+ , _position(0)
+ , _sync_position(_start)
+ , _layer(0)
+ , _first_edit(EditChangesNothing)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change(0))
+ , _last_layer_op(0)
+ , _playlist(0)
+
+{
+ set<Source*> unique_srcs;
+
+ for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
+ _sources.push_back (*i);
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ unique_srcs.insert (*i);
+ }
+
+ for (SourceList::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+ _master_sources.push_back (*i);
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->GoingAway.connect (mem_fun (*this, &Region::source_deleted));
+ }
+ }
+
_current_state_id = 0;
- _last_layer_op = other._last_layer_op;
-}
-
-Region::Region (const XMLNode& node)
-{
- _frozen = 0;
- pending_changed = Change (0);
- _playlist = 0;
- _read_data_count = 0;
- _start = 0;
- _sync_position = _start;
- _length = 0;
- _name = X_("error: XML did not reset this");
- _position = 0;
- _layer = 0;
- _flags = Flag (0);
+
+ if (set_state (node)) {
+ throw failed_constructor();
+ }
+
+ assert(_sources.size() > 0);
+}
+
+Region::Region (Source& src, const XMLNode& node)
+ : _name(X_("error: XML did not reset this"))
+ , _flags(Flag(0))
+ , _start(0)
+ , _length(0)
+ , _position(0)
+ , _sync_position(_start)
+ , _layer(0)
+ , _first_edit(EditChangesNothing)
+ , _frozen(0)
+ , _read_data_count(0)
+ , _pending_changed(Change(0))
+ , _last_layer_op(0)
+ , _playlist(0)
+{
+ _sources.push_back (&src);
+
_current_state_id = 0;
- _first_edit = EditChangesNothing;
if (set_state (node)) {
throw failed_constructor();
}
+
+ assert(_sources.size() > 0);
}
Region::~Region ()
@@ -175,7 +289,7 @@ Region::restore_and_return_flags (RegionState& state)
Change what_changed = Change (0);
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
if (_start != state._start) {
what_changed = Change (what_changed|StartChanged);
@@ -944,15 +1058,15 @@ Region::thaw (const string& why)
Change what_changed = Change (0);
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
if (_frozen && --_frozen > 0) {
return;
}
- if (pending_changed) {
- what_changed = pending_changed;
- pending_changed = Change (0);
+ if (_pending_changed) {
+ what_changed = _pending_changed;
+ _pending_changed = Change (0);
}
}
@@ -975,9 +1089,9 @@ void
Region::send_change (Change what_changed)
{
{
- Glib::Mutex::Lock lm (lock);
+ Glib::Mutex::Lock lm (_lock);
if (_frozen) {
- pending_changed = Change (pending_changed|what_changed);
+ _pending_changed = Change (_pending_changed|what_changed);
return;
}
}
@@ -1017,3 +1131,135 @@ Region::region_list_equivalent (const Region& other) const
{
return size_equivalent (other) && source_equivalent (other) && _name == other._name;
}
+
+void
+Region::source_deleted (Source* ignored)
+{
+ delete this;
+}
+
+void
+Region::lock_sources ()
+{
+ SourceList::iterator i;
+ set<Source*> unique_srcs;
+
+ for (i = _sources.begin(); i != _sources.end(); ++i) {
+ unique_srcs.insert (*i);
+ (*i)->use ();
+ }
+
+ for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->use ();
+ }
+ }
+}
+
+void
+Region::unlock_sources ()
+{
+ SourceList::iterator i;
+ set<Source*> unique_srcs;
+
+ for (i = _sources.begin(); i != _sources.end(); ++i) {
+ unique_srcs.insert (*i);
+ (*i)->release ();
+ }
+
+ for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
+ if (unique_srcs.find (*i) == unique_srcs.end()) {
+ (*i)->release ();
+ }
+ }
+}
+
+vector<string>
+Region::master_source_names ()
+{
+ SourceList::iterator i;
+
+ vector<string> names;
+ for (i = _master_sources.begin(); i != _master_sources.end(); ++i) {
+ names.push_back((*i)->name());
+ }
+
+ return names;
+}
+
+bool
+Region::source_equivalent (const Region& other) const
+{
+ SourceList::const_iterator i;
+ SourceList::const_iterator io;
+
+ for (i = _sources.begin(), io = other._sources.begin(); i != _sources.end() && io != other._sources.end(); ++i, ++io) {
+ if ((*i)->id() != (*io)->id()) {
+ return false;
+ }
+ }
+
+ for (i = _master_sources.begin(), io = other._master_sources.begin(); i != _master_sources.end() && io != other._master_sources.end(); ++i, ++io) {
+ if ((*i)->id() != (*io)->id()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+Region::verify_length (jack_nframes_t len)
+{
+ for (uint32_t n=0; n < _sources.size(); ++n) {
+ if (_start > _sources[n]->length() - len) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+Region::verify_start_and_length (jack_nframes_t new_start, jack_nframes_t new_length)
+{
+ for (uint32_t n=0; n < _sources.size(); ++n) {
+ if (new_length > _sources[n]->length() - new_start) {
+ return false;
+ }
+ }
+ return true;
+}
+bool
+Region::verify_start (jack_nframes_t pos)
+{
+ for (uint32_t n=0; n < _sources.size(); ++n) {
+ if (pos > _sources[n]->length() - _length) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+Region::verify_start_mutable (jack_nframes_t& new_start)
+{
+ for (uint32_t n=0; n < _sources.size(); ++n) {
+ if (new_start > _sources[n]->length() - _length) {
+ new_start = _sources[n]->length() - _length;
+ }
+ }
+ return true;
+}
+
+Region*
+Region::get_parent()
+{
+ Region* r = 0;
+
+ if (_playlist) {
+ r = _playlist->session().find_whole_file_parent (*this);
+ }
+
+ return r;
+}
+
diff --git a/libs/ardour/reverse.cc b/libs/ardour/reverse.cc
index 13dd531bac..b981ff0722 100644
--- a/libs/ardour/reverse.cc
+++ b/libs/ardour/reverse.cc
@@ -49,7 +49,6 @@ Reverse::run (AudioRegion& region)
AudioRegion::SourceList::iterator si;
const jack_nframes_t blocksize = 256 * 1048;
Sample buf[blocksize];
- char * workbuf = 0;;
jack_nframes_t fpos;
jack_nframes_t fend;
jack_nframes_t fstart;
@@ -62,8 +61,6 @@ Reverse::run (AudioRegion& region)
goto out;
}
- workbuf = new char[blocksize * 4];
-
fend = region.start() + region.length();
fstart = region.start();
@@ -82,10 +79,11 @@ Reverse::run (AudioRegion& region)
uint32_t n;
for (n = 0, si = nsrcs.begin(); n < region.n_channels(); ++n, ++si) {
+ AudioSource* const asrc = dynamic_cast<AudioSource*>(*si);
/* read it in */
- if (region.source (n).read (buf, fpos, to_read, workbuf) != to_read) {
+ if (region.audio_source (n).read (buf, fpos, to_read) != to_read) {
goto out;
}
@@ -97,7 +95,7 @@ Reverse::run (AudioRegion& region)
/* write it out */
- if ((*si)->write (buf, to_read, workbuf) != to_read) {
+ if (asrc->write (buf, to_read) != to_read) {
goto out;
}
}
@@ -123,9 +121,6 @@ Reverse::run (AudioRegion& region)
delete *si;
}
}
- if (workbuf) {
- delete [] workbuf;
- }
return ret;
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 58647be439..be0ec61a8d 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -37,6 +37,7 @@
#include <ardour/cycle_timer.h>
#include <ardour/route_group.h>
#include <ardour/port.h>
+#include <ardour/audio_port.h>
#include <ardour/ladspa_plugin.h>
#include <ardour/panner.h>
#include <ardour/dB.h>
@@ -220,6 +221,9 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
bool meter)
{
+ // This is definitely very audio-only for now
+ assert(_default_type == DataType::AUDIO);
+
uint32_t n;
RedirectList::iterator i;
bool post_fader_work = false;
@@ -650,7 +654,7 @@ Route::process_output_buffers (vector<Sample*>& bufs, uint32_t nbufs,
} else {
uint32_t no = n_outputs();
for (n = 0; n < no; ++n) {
- _peak_power[n] = Session::compute_peak (output(n)->get_buffer (nframes) + offset, nframes, _peak_power[n]);
+ _peak_power[n] = Session::compute_peak (audio_output(n)->get_audio_buffer ().data(nframes, offset), nframes, _peak_power[n]);
}
}
}
@@ -663,7 +667,6 @@ Route::n_process_buffers ()
}
void
-
Route::passthru (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter_first)
{
vector<Sample*>& bufs = _session.get_passthru_buffers();
@@ -2110,7 +2113,7 @@ Route::silent_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nfr
void
Route::toggle_monitor_input ()
{
- for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
(*i)->request_monitor_input(!(*i)->monitoring_input());
}
}
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index 2b72fb9bdb..fbbedf7953 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -25,6 +25,7 @@
#include <ardour/send.h>
#include <ardour/session.h>
#include <ardour/port.h>
+#include <ardour/audio_port.h>
#include "i18n.h"
@@ -133,7 +134,7 @@ Send::run (vector<Sample *>& bufs, uint32_t nbufs, jack_nframes_t nframes, jack_
} else {
for (n = 0; n < no; ++n) {
- _peak_power[n] = Session::compute_peak (output(n)->get_buffer(nframes) + offset, nframes, _peak_power[n]);
+ _peak_power[n] = Session::compute_peak (audio_output(n)->get_audio_buffer().data(nframes, offset), nframes, _peak_power[n]);
}
}
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index bfcb69572a..6dd6216242 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -401,10 +401,6 @@ Session::~Session ()
free(*i);
}
- for (map<RunContext,char*>::iterator i = _conversion_buffers.begin(); i != _conversion_buffers.end(); ++i) {
- delete [] (i->second);
- }
-
AudioDiskstream::free_working_buffers();
#undef TRACK_DESTRUCTION
@@ -605,12 +601,7 @@ Session::when_engine_running ()
/* default state for Click */
- // FIXME: there's no JackPortIsAudio flag or anything like that, so this is _bad_.
- // we need a get_nth_physical_audio_output or similar, but the existing one just
- // deals with strings :/
-
- first_physical_output = _engine.get_nth_physical_output (0);
- cerr << "FIXME: click type" << endl;
+ first_physical_output = _engine.get_nth_physical_output (DataType::AUDIO, 0);
if (first_physical_output.length()) {
if (_click_io->add_output_port (first_physical_output, this)) {
@@ -662,7 +653,7 @@ Session::when_engine_running ()
Connection* c = new OutputConnection (buf, true);
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_output (np));
+ c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
add_connection (c);
}
@@ -674,7 +665,7 @@ Session::when_engine_running ()
Connection* c = new InputConnection (buf, true);
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_input (np));
+ c->add_connection (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
add_connection (c);
}
@@ -689,8 +680,8 @@ Session::when_engine_running ()
c->add_port ();
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_output (np));
- c->add_connection (1, _engine.get_nth_physical_output (np+1));
+ c->add_connection (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+ c->add_connection (1, _engine.get_nth_physical_output (DataType::AUDIO, np+1));
add_connection (c);
}
@@ -703,8 +694,8 @@ Session::when_engine_running ()
c->add_port ();
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_input (np));
- c->add_connection (1, _engine.get_nth_physical_input (np+1));
+ c->add_connection (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+ c->add_connection (1, _engine.get_nth_physical_input (DataType::AUDIO, np+1));
add_connection (c);
}
@@ -737,7 +728,7 @@ Session::when_engine_running ()
}
n = 0;
while ((int) _master_out->n_outputs() < _master_out->output_maximum()) {
- if (_master_out->add_output_port (_engine.get_nth_physical_output (n), this, DataType::AUDIO)) {
+ if (_master_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this, DataType::AUDIO)) {
error << _("cannot setup master outputs")
<< endmsg;
break;
@@ -828,7 +819,7 @@ Session::hookup_io ()
}
n = 0;
while ((int) _control_out->n_outputs() < _control_out->output_maximum()) {
- if (_control_out->add_output_port (_engine.get_nth_physical_output (n), this)) {
+ if (_control_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this)) {
error << _("cannot set up master outputs")
<< endmsg;
break;
@@ -1937,7 +1928,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = "";
if (input_auto_connect & AutoConnectPhysical) {
- port = _engine.get_nth_physical_input ((channels_used+x)%nphysical_in);
+ port = _engine.get_nth_physical_input (DataType::AUDIO, (channels_used+x)%nphysical_in);
}
if (port.length() && track->connect_input (track->input (x), port, this)) {
@@ -1951,7 +1942,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = "";
if (nphysical_out && (output_auto_connect & AutoConnectPhysical)) {
- port = _engine.get_nth_physical_output ((channels_used+x)%nphysical_out);
+ port = _engine.get_nth_physical_output (DataType::AUDIO, (channels_used+x)%nphysical_out);
} else if (output_auto_connect & AutoConnectMaster) {
if (_master_out) {
port = _master_out->input (x%_master_out->n_inputs())->name();
@@ -2032,7 +2023,7 @@ Session::new_audio_route (int input_channels, int output_channels)
port = "";
if (input_auto_connect & AutoConnectPhysical) {
- port = _engine.get_nth_physical_input ((n+x)%n_physical_inputs);
+ port = _engine.get_nth_physical_input (DataType::AUDIO, (n+x)%n_physical_inputs);
}
if (port.length() && bus->connect_input (bus->input (x), port, this)) {
@@ -2045,7 +2036,7 @@ Session::new_audio_route (int input_channels, int output_channels)
port = "";
if (output_auto_connect & AutoConnectPhysical) {
- port = _engine.get_nth_physical_input ((n+x)%n_physical_outputs);
+ port = _engine.get_nth_physical_input (DataType::AUDIO, (n+x)%n_physical_outputs);
} else if (output_auto_connect & AutoConnectMaster) {
if (_master_out) {
port = _master_out->input (x%_master_out->n_inputs())->name();
@@ -2747,8 +2738,8 @@ Session::remove_region (Region* region)
}
}
-AudioRegion*
-Session::find_whole_file_parent (AudioRegion& child)
+Region*
+Session::find_whole_file_parent (Region& child)
{
AudioRegionList::iterator i;
AudioRegion* region;
@@ -3162,6 +3153,79 @@ Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bo
}
}
+string
+Session::midi_path_from_name (string name)
+{
+ string spath;
+ uint32_t cnt;
+ char buf[PATH_MAX+1];
+ const uint32_t limit = 10000;
+ string legalized;
+
+ buf[0] = '\0';
+ legalized = legalize_for_path (name);
+
+ /* find a "version" of the file name that doesn't exist in
+ any of the possible directories.
+ */
+
+ for (cnt = 1; cnt <= limit; ++cnt) {
+
+ vector<space_and_path>::iterator i;
+ uint32_t existing = 0;
+
+ for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+
+ // FIXME: different directory from audio?
+ spath = (*i).path + sound_dir_name + "/" + legalized;
+
+ snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt);
+
+ if (access (buf, F_OK) == 0) {
+ existing++;
+ }
+ }
+
+ if (existing == 0) {
+ break;
+ }
+
+ if (cnt > limit) {
+ error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg;
+ throw failed_constructor();
+ }
+ }
+
+ /* we now have a unique name for the file, but figure out where to
+ actually put it.
+ */
+
+ string foo = buf;
+
+ // FIXME: different directory than audio?
+ spath = discover_best_sound_dir ();
+
+ string::size_type pos = foo.find_last_of ('/');
+
+ if (pos == string::npos) {
+ spath += foo;
+ } else {
+ spath += foo.substr (pos + 1);
+ }
+
+ return spath;
+}
+
+MidiSource *
+Session::create_midi_source_for_session (MidiDiskstream& ds)
+{
+ string spath = midi_path_from_name (ds.name());
+
+ /* this might throw failed_constructor(), which is OK */
+ return new SMFSource (spath);
+}
+
+
/* Playlist management */
Playlist *
@@ -3789,7 +3853,7 @@ Session::freeze (InterThreadInfo& itt)
int
Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nframes_t len,
- bool overwrite, vector<AudioSource*>& srcs, InterThreadInfo& itt)
+ bool overwrite, vector<Source*>& srcs, InterThreadInfo& itt)
{
int ret = -1;
Playlist* playlist;
@@ -3802,7 +3866,6 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
jack_nframes_t this_chunk;
jack_nframes_t to_do;
vector<Sample*> buffers;
- char * workbuf = 0;
// any bigger than this seems to cause stack overflows in called functions
const jack_nframes_t chunk_size = (128 * 1024)/4;
@@ -3872,22 +3935,20 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
buffers.push_back (b);
}
- workbuf = new char[chunk_size * 4];
-
while (to_do && !itt.cancel) {
this_chunk = min (to_do, chunk_size);
- if (track.export_stuff (buffers, workbuf, nchans, start, this_chunk)) {
+ if (track.export_stuff (buffers, nchans, start, this_chunk)) {
goto out;
}
uint32_t n = 0;
- for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
+ for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) {
AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src);
if (afs) {
- if (afs->write (buffers[n], this_chunk, workbuf) != this_chunk) {
+ if (afs->write (buffers[n], this_chunk) != this_chunk) {
goto out;
}
}
@@ -3907,7 +3968,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
time (&now);
xnow = localtime (&now);
- for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+ for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src);
if (afs) {
afs->update_header (position, *xnow, now);
@@ -3916,7 +3977,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
/* build peakfile for new source */
- for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+ for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src);
if (afs) {
afs->build_peaks ();
@@ -3928,7 +3989,7 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
out:
if (ret) {
- for (vector<AudioSource*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+ for (vector<Source*>::iterator src=srcs.begin(); src != srcs.end(); ++src) {
AudioFileSource* afs = dynamic_cast<AudioFileSource*>(*src);
if (afs) {
afs->mark_for_remove ();
@@ -3941,10 +4002,6 @@ Session::write_one_audio_track (AudioTrack& track, jack_nframes_t start, jack_nf
free(*i);
}
- if (workbuf) {
- delete [] workbuf;
- }
-
g_atomic_int_set (&processing_prohibited, 0);
itt.done = true;
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index 9a43de55de..1b8d6b3718 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -1,7 +1,29 @@
#include <ardour/session.h>
#include <ardour/route.h>
+#include <pbd/memento_command.h>
+#include <ardour/diskstream.h>
namespace ARDOUR {
+
+Command *Session::memento_command_factory(XMLNode *n)
+{
+ PBD::ID id;
+ XMLNode *before, *after;
+ //void *obj;
+
+ /* get obj_id */
+
+ /* get before and/or after */
+
+ /* get an object by id by trial and error, and use it to construct an
+ * appropriate memento command */
+ // e.g.
+ if (Diskstream *obj = diskstream_by_id(id))
+ return new MementoCommand<Diskstream>(*obj, *before, *after);
+ // etc.
+ return 0;
+}
+
// solo
Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src)
: sess(sess), src(src)
diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc
index b39c4f2218..c5449d3e06 100644
--- a/libs/ardour/session_export.cc
+++ b/libs/ardour/session_export.cc
@@ -46,6 +46,7 @@
#include <ardour/export.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/port.h>
+#include <ardour/audio_port.h>
#include <ardour/audioengine.h>
#include <ardour/audio_diskstream.h>
#include <ardour/panner.h>
@@ -604,8 +605,12 @@ Session::process_export (jack_nframes_t nframes, AudioExportSpecification* spec)
/* OK, this port's output is supposed to appear on this channel
*/
- Port* port = (*t).first;
- Sample* port_buffer = port->get_buffer (nframes);
+ AudioPort* const port = dynamic_cast<AudioPort*>((*t).first);
+ if (port == 0) {
+ cerr << "FIXME: Non-audio export" << endl;
+ continue;
+ }
+ Sample* port_buffer = port->get_audio_buffer().data(nframes);
/* now interleave the data from the channel into the float buffer */
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index bb319511b7..a235375ed1 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -194,9 +194,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
xfade_model = ShortCrossfade;
destructive_index = 0;
- /* allocate conversion buffers */
- _conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4];
- _conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4];
AudioDiskstream::allocate_working_buffers();
/* default short fade = 15ms */
@@ -628,15 +625,16 @@ Session::load_diskstreams (const XMLNode& node)
clist = node.children();
for (citer = clist.begin(); citer != clist.end(); ++citer) {
- Diskstream* dstream = NULL;
+ Diskstream* dstream = 0;
try {
- if ((*citer)->name() == "AudioDiskstream") {
+ /* diskstreams added automatically by DiskstreamCreated handler */
+ if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
dstream = new AudioDiskstream (*this, **citer);
- /* added automatically by DiskstreamCreated handler */
- } else {
- assert((*citer)->name() == "MidiDiskstream");
+ } else if ((*citer)->name() == "MidiDiskstream") {
dstream = new MidiDiskstream (*this, **citer);
+ } else {
+ error << _("Session: unknown diskstream type in XML") << endmsg;
}
}
diff --git a/libs/ardour/session_timefx.cc b/libs/ardour/session_timefx.cc
index 7eec1e578b..82fd25ddb2 100644
--- a/libs/ardour/session_timefx.cc
+++ b/libs/ardour/session_timefx.cc
@@ -96,10 +96,15 @@ Session::tempoize_region (TimeStretchRequest& tsr)
for (uint32_t i = 0; i < sources.size(); ++i) {
gain_t gain_buffer[bufsize];
Sample buffer[bufsize];
- char workbuf[bufsize*4];
jack_nframes_t pos = 0;
jack_nframes_t this_read = 0;
+ AudioSource* const asrc = dynamic_cast<AudioSource*>(sources[i]);
+ if (!asrc) {
+ cerr << "FIXME: TimeFX for non-audio" << endl;
+ continue;
+ }
+
st.clear();
while (tsr.running && pos < tsr.region->length()) {
jack_nframes_t this_time;
@@ -110,7 +115,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
not the ones currently in use, in case it's already been
subject to timefx. */
- if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, workbuf, pos + tsr.region->position(), this_time)) != this_time) {
+ if ((this_read = tsr.region->master_read_at (buffer, buffer, gain_buffer, pos + tsr.region->position(), this_time)) != this_time) {
error << string_compose (_("tempoize: error reading data from %1"), sources[i]->name()) << endmsg;
goto out;
}
@@ -123,7 +128,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
st.putSamples (buffer, this_read);
while ((this_read = st.receiveSamples (buffer, bufsize)) > 0 && tsr.running) {
- if (sources[i]->write (buffer, this_read, workbuf) != this_read) {
+ if (asrc->write (buffer, this_read) != this_read) {
error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
goto out;
}
@@ -135,7 +140,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
}
while (tsr.running && (this_read = st.receiveSamples (buffer, bufsize)) > 0) {
- if (sources[i]->write (buffer, this_read, workbuf) != this_read) {
+ if (asrc->write (buffer, this_read) != this_read) {
error << string_compose (_("error writing tempo-adjusted data to %1"), sources[i]->name()) << endmsg;
goto out;
}
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index 10cf7ab335..86e2e8a9aa 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -103,6 +103,29 @@ SMFSource::init (string pathstr, bool must_exist)
return 0;
}
+int
+SMFSource::update_header (jack_nframes_t when, struct tm&, time_t)
+{
+ return 0;
+}
+
+int
+SMFSource::flush_header ()
+{
+ return 0;
+}
+
+jack_nframes_t
+SMFSource::read_unlocked (RawMidi* dst, jack_nframes_t start, jack_nframes_t cnt) const
+{
+ return 0;
+}
+
+jack_nframes_t
+SMFSource::write_unlocked (RawMidi* dst, jack_nframes_t cnt)
+{
+ return 0;
+}
XMLNode&
SMFSource::get_state ()
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 5936f62570..b487d4e3a3 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -292,7 +292,7 @@ SndFileSource::sample_rate () const
}
jack_nframes_t
-SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt, char * workbuf) const
+SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t cnt) const
{
int32_t nread;
float *ptr;
@@ -367,7 +367,7 @@ SndFileSource::read_unlocked (Sample *dst, jack_nframes_t start, jack_nframes_t
}
jack_nframes_t
-SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt, char * workbuf)
+SndFileSource::write_unlocked (Sample *data, jack_nframes_t cnt)
{
if (!writable()) {
return 0;
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index eebc64d463..e5aba19d2c 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -117,3 +117,11 @@ Source::release ()
if (_use_cnt) --_use_cnt;
}
+void
+Source::update_length (jack_nframes_t pos, jack_nframes_t cnt)
+{
+ if (pos + cnt > _length) {
+ _length = pos+cnt;
+ }
+}
+
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index f81ef9de4d..49578a7d04 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -88,7 +88,7 @@ Track::get_template ()
void
Track::toggle_monitor_input ()
{
- for (vector<Port*>::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
(*i)->request_monitor_input(!(*i)->monitoring_input());
}
}
@@ -152,8 +152,8 @@ bool
Track::can_record()
{
bool will_record = true;
- for (size_t i = 0; i < _inputs.size() && will_record; i++) {
- if (!_inputs[i]->connected())
+ for (PortSet::iterator i = _inputs.begin(); i != _inputs.end() && will_record; ++i) {
+ if (!(*i)->connected())
will_record = false;
}
diff --git a/libs/pbd/pbd/memento_command.h b/libs/pbd/pbd/memento_command.h
index 46c724e9ea..122dcb4c86 100644
--- a/libs/pbd/pbd/memento_command.h
+++ b/libs/pbd/pbd/memento_command.h
@@ -24,6 +24,7 @@
#include <pbd/command.h>
#include <pbd/xml++.h>
#include <sigc++/slot.h>
+#include <typeinfo>
/** This command class is initialized with before and after mementos
* (from Stateful::get_state()), so undo becomes restoring the before
@@ -33,6 +34,7 @@ template <class obj_T>
class MementoCommand : public Command
{
public:
+ MementoCommand(XMLNode &state);
MementoCommand(obj_T &obj,
XMLNode &before,
XMLNode &after
@@ -44,11 +46,11 @@ class MementoCommand : public Command
{
XMLNode *node = new XMLNode("MementoCommand");
node->add_property("obj_id", obj.id().to_s());
- node->add_child_nocopy(before);
- node->add_child_nocopy(after);
+ node->add_property("type_name", typeid(obj).name());
+ node->add_child_copy(before);
+ node->add_child_copy(after);
return *node;
}
- // TODO does this need a copy constructor?
protected:
obj_T &obj;
XMLNode &before, &after;
@@ -58,6 +60,7 @@ template <class obj_T>
class MementoUndoCommand : public Command
{
public:
+ MementoUndoCommand(XMLNode &state);
MementoUndoCommand(obj_T &obj,
XMLNode &before)
: obj(obj), before(before) {}
@@ -67,7 +70,8 @@ public:
{
XMLNode *node = new XMLNode("MementoUndoCommand");
node->add_property("obj_id", obj.id().to_s());
- node->add_child_nocopy(before);
+ node->add_property("type_name", typeid(obj).name());
+ node->add_child_copy(before);
return *node;
}
protected:
@@ -79,6 +83,7 @@ template <class obj_T>
class MementoRedoCommand : public Command
{
public:
+ MementoRedoCommand(XMLNode &state);
MementoRedoCommand(obj_T &obj,
XMLNode &after)
: obj(obj), after(after) {}
@@ -88,7 +93,8 @@ public:
{
XMLNode *node = new XMLNode("MementoRedoCommand");
node->add_property("obj_id", obj.id().to_s());
- node->add_child_nocopy(after);
+ node->add_property("type_name", typeid(obj).name());
+ node->add_child_copy(after);
return *node;
}
protected: