- 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:
parent
ab6f1ed9ba
commit
30c08ba655
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/sh
|
||||
source ardev_common.sh
|
||||
exec gdb ./ardour.bin
|
||||
exec gdb ./ardour.bin "$*"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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), ®ion, which), peaks_ready_connection)) {
|
||||
if (region.audio_source(n).peaks_ready (bind (mem_fun(*this, &CrossfadeEditor::peaks_ready), ®ion, which), peaks_ready_connection)) {
|
||||
|
||||
WaveView* waveview = new WaveView (*(canvas->root()));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
|
@ -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 ();
|
||||
|
|
|
@ -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 () { };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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__
|
||||
|
|
@ -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; }
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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? */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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...
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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" */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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&
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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*>(®ion->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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue