- Changed IO's vector<Port*>'s to PortList

- Added new Port classes, code to drive them
- Added PortList, which is a filthy mess ATM (nevermind that, it's the interface that's important at this stage)
- Added ChanCount, though it isn't very thoroughly used yet.  That's the next step....
- Fixed a few bugs relating to loading sessions saved with trunk
- Fixed a few random other bugs

Slowly working towards type agnosticism while keeping all the former code/logic intact is the name of the game here

Warning:  Removing ports is currently (intentionally) broken due solely to laziness.


git-svn-id: svn://localhost/ardour2/branches/midi@786 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2006-08-11 03:24:57 +00:00
parent ab6f1ed9ba
commit 30c08ba655
99 changed files with 4074 additions and 2444 deletions

View File

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

View File

@ -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 */

View File

@ -1,3 +1,3 @@
#!/bin/sh
source ardev_common.sh
exec gdb ./ardour.bin
exec gdb ./ardour.bin "$*"

View File

@ -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;
}

View File

@ -313,6 +313,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)
{
@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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()));

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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__ */

View File

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

View File

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

View File

@ -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__

View File

@ -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)
bool
PluginUIWindow::on_key_press_event (GdkEventKey* event)
{
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);
return PublicEditor::instance().on_key_press_event(event);
}
LadspaPluginUI::~LadspaPluginUI ()
bool
PluginUIWindow::on_key_release_event (GdkEventKey* event)
{
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]);
}
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);
}
}

View File

@ -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;
};

View File

@ -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__

View File

@ -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;
if (plugin_insert->get_gui() == 0) {
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 (maker.length() > 32) {
maker = maker.substr (0, 32);
maker += " ...";
}
ARDOUR::PluginType type = plugin_insert->type();
title = string_compose(_("ardour: %1: %2 (by %3)"), _route->name(), plugin_insert->name(), maker);
if (type == ARDOUR::LADSPA || type == ARDOUR::VST) {
PluginUIWindow *plugin_ui;
if (plugin_insert->get_gui() == 0) {
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 (maker.length() > 32) {
maker = maker.substr (0, 32);
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());
}
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());
}
plugin_ui->set_title (title);
plugin_insert->set_gui (plugin_ui);
// raise window, somehow
#endif
} else {
plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
warning << "Unsupported plugin sent to RedirectBox::edit_redirect()" << endmsg;
return;
}
if (plugin_ui->is_visible()) {
plugin_ui->get_window()->raise ();
} else {
plugin_ui->show_all ();
}
} else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (insert)) != 0) {
if (!_session.engine().connected()) {

View File

@ -249,6 +249,14 @@ RegionView::reset_width_dependent_items (double pixel_width)
_pixel_width = pixel_width;
}
void
RegionView::set_height (gdouble height)
{
TimeAxisViewItem::set_height (height - 2);
_height = height;
}
void
RegionView::region_layered ()
{
@ -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;
}

View File

@ -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*);

View File

@ -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));
}
}

View File

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

View File

@ -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;

View File

@ -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__ */

View File

@ -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 ();

View File

@ -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 () { };

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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*);

View File

@ -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)
{
_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(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);
}
const Sample* data() const { return _data; }
Sample* data() { return _data; }
/** 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)
{
assert(!_owns_data); // prevent leaks
_capacity = size;
_size = size;
_data = 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__

View File

@ -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__

View File

@ -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; }

View File

@ -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);

View File

@ -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;
};

View File

@ -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);
};

View File

@ -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;

View File

@ -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();

View File

@ -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? */

View File

@ -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 do_refill_with_alloc();
int read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
/* XXX fix this redundancy ... */
//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 */

View File

@ -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;

View File

@ -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__ */

View File

@ -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;
MidiSource& midi_source (uint32_t n=0) 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;
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;
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;
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 source_deleted (Source*);
void recompute_at_start ();
void recompute_at_end ();
};
} /* namespace ARDOUR */

View File

@ -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);

View File

@ -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&);

View File

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

View File

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

View File

@ -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__

View File

@ -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 */

View File

@ -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);

View File

@ -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;

View File

@ -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; }

View File

@ -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);

View File

@ -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;

View File

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

View File

@ -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__ */

View File

@ -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;
}

View File

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

67
libs/ardour/audio_port.cc Normal file
View File

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

View File

@ -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;

View File

@ -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";

View File

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

View File

@ -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" */

View File

@ -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;
}
}

107
libs/ardour/buffer.cc Normal file
View File

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

View File

@ -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;
}

View File

@ -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;

View File

@ -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];

View File

@ -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;
}

View File

@ -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;

View File

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

View File

@ -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,12 +513,19 @@ 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));
#ifdef VST_SUPPORT
} 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
}
@ -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&

View File

@ -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));
}

View File

@ -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)
{
_io = &io;
set_align_style_from_io ();
}
void
MidiDiskstream::non_realtime_set_speed ()
{
if (_buffer_reallocation_required)
{
Glib::Mutex::Lock lm (state_lock);
allocate_temporary_buffers ();
_buffer_reallocation_required = false;
}
if (_seek_required) {
if (speed() != 1.0f || speed() != -1.0f) {
seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
}
else {
seek (_session.transport_frame(), true);
}
_seek_required = false;
}
}
void
MidiDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record)
{
// 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.
*/
rolling = _session.transport_speed() != 0.0f;
possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
change = possibly_recording ^ last_possibly_recording;
if (possibly_recording == last_possibly_recording) {
return;
}
/* 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;
}
}
}
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;
}
}
} 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;
}
}
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)
{
return 0;
}
int
MidiDiskstream::do_flush (char * workbuf, bool force_flush)
MidiDiskstream::do_refill_with_alloc ()
{
return 0;
}
*/
int
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());
}

View File

@ -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;
}

102
libs/ardour/midi_port.cc Normal file
View File

@ -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
}

View File

@ -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));
}
save_state ("initial state");
if (announce) {
CheckNewRegion (this); /* EMIT SIGNAL */
}
}
/** 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)
{
/* create a new MidiRegion, that is part of an existing one */
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) {
if (unique_srcs.find (*i) == unique_srcs.end()) {
(*i)->GoingAway.connect (mem_fun (*this, &MidiRegion::source_deleted));
}
master_sources.push_back (*i);
}
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();
_read_data_count += src.read_data_count();
if (!opaque()) {
/* 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));
}

View File

@ -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 );
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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;

View File

@ -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);

View File

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

111
libs/ardour/port_set.cc Normal file
View File

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

View File

@ -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 */
_flags = flags;
_playlist = 0;
_read_data_count = 0;
_frozen = 0;
pending_changed = Change (0);
_name = name;
_start = start;
_sync_position = _start;
_length = length;
_position = 0;
_layer = layer;
_current_state_id = 0;
_read_data_count = 0;
_first_edit = EditChangesNothing;
_last_layer_op = 0;
_sources.push_back (&src);
_master_sources.push_back (&src);
src.GoingAway.connect (mem_fun (*this, &Region::source_deleted));
assert(_sources.size() > 0);
}
Region::Region (const Region& other, jack_nframes_t offset, jack_nframes_t length, const string& name, layer_t layer, Flag flags)
/** 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)
{
/* create a new Region from part of an existing one */
_current_state_id = 0;
set<Source*> unique_srcs;
_frozen = 0;
pending_changed = Change (0);
_playlist = 0;
_read_data_count = 0;
_start = other._start + offset;
if (other._sync_position < offset) {
_sync_position = other._sync_position;
} else {
_sync_position = _start;
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);
}
_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::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);
}
Region::Region (const Region &other)
/** 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)
{
/* Pure copy constructor */
_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;
_first_edit = EditChangesID;
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) {
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)
{
_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);
_current_state_id = 0;
_last_layer_op = other._last_layer_op;
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 (const XMLNode& node)
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)
{
_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);
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;
_first_edit = EditChangesNothing;
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;
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;
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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]);
}
}
}

View File

@ -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;

View File

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

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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 ()

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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: