fix redrawing of canvas with an optimized build

Best guess right now is that optimization does something bad when ceil() is called twice on a very large dbl-precision number,
which results in a zero (empty) redraw area. Without the removal of the redundant ceil & floor functions, no expose events
would be delivered to the canvas in an optimized build during drags (and maybe more).
This commit is contained in:
Paul Davis
2013-12-23 15:35:49 -05:00
41 changed files with 619 additions and 262 deletions

View File

@@ -3569,7 +3569,8 @@ ARDOUR_UI::add_video (Gtk::Window* float_window)
if (!transcode_video_dialog->get_audiofile().empty()) {
editor->embed_audio_from_video(
transcode_video_dialog->get_audiofile(),
video_timeline->get_offset()
video_timeline->get_offset(),
(transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
);
}
switch (transcode_video_dialog->import_option()) {

View File

@@ -186,6 +186,11 @@ ARDOUR_UI::set_session (Session *s)
update_format ();
if (meter_box.get_parent()) {
transport_tearoff_hbox.remove (meter_box);
transport_tearoff_hbox.remove (editor_meter_peak_display);
}
if (editor_meter) {
meter_box.remove(*editor_meter);
delete editor_meter;
@@ -222,15 +227,8 @@ ARDOUR_UI::set_session (Session *s)
transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
meter_box.show();
editor_meter_peak_display.show();
} else if (meter_box.get_parent()) {
transport_tearoff_hbox.remove (meter_box);
transport_tearoff_hbox.remove (editor_meter_peak_display);
}
} else if (meter_box.get_parent()) {
transport_tearoff_hbox.remove (meter_box);
transport_tearoff_hbox.remove (editor_meter_peak_display);
}
}
}
int

View File

@@ -403,14 +403,19 @@ ARDOUR_UI::parameter_changed (std::string p)
ArdourCanvas::WaveView::set_global_gradient_depth (config()->get_waveform_gradient_depth());
} else if (p == "show-editor-meter") {
bool show = Config->get_show_editor_meter();
if (editor_meter && show) {
transport_tearoff_hbox.pack_start (meter_box, false, false);
transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
meter_box.show();
editor_meter_peak_display.show();
} else if (editor_meter && !show && meter_box.get_parent()) {
transport_tearoff_hbox.remove (meter_box);
transport_tearoff_hbox.remove (editor_meter_peak_display);
if (editor_meter) {
if (meter_box.get_parent()) {
transport_tearoff_hbox.remove (meter_box);
transport_tearoff_hbox.remove (editor_meter_peak_display);
}
if (show) {
transport_tearoff_hbox.pack_start (meter_box, false, false);
transport_tearoff_hbox.pack_start (editor_meter_peak_display, false, false);
meter_box.show();
editor_meter_peak_display.show();
}
}
}
}

View File

@@ -1415,7 +1415,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void toggle_video_timeline_locked ();
void set_video_timeline_locked (const bool);
void queue_visual_videotimeline_update ();
void embed_audio_from_video (std::string, framepos_t n = 0);
void embed_audio_from_video (std::string, framepos_t n = 0, bool lock_position_to_video = true);
PBD::Signal0<void> EditorFreeze;
PBD::Signal0<void> EditorThaw;

View File

@@ -80,13 +80,10 @@ Editor::toggle_video_timeline_locked ()
}
void
Editor::embed_audio_from_video (std::string path, framepos_t n)
Editor::embed_audio_from_video (std::string path, framepos_t n, bool lock_position_to_video)
{
vector<std::string> paths;
paths.push_back(path);
#if 0
do_import (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, n);
#else
current_interthread_info = &import_status;
import_status.current = 1;
import_status.total = paths.size ();
@@ -98,13 +95,14 @@ Editor::embed_audio_from_video (std::string path, framepos_t n)
boost::shared_ptr<ARDOUR::Track> track;
bool ok = (import_sndfiles (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, n, 1, 1, track, false) == 0);
if (ok && track) {
boost::shared_ptr<ARDOUR::Playlist> pl = track->playlist();
pl->find_next_region(n, ARDOUR::End, 0)->set_video_locked(true);
if (lock_position_to_video) {
boost::shared_ptr<ARDOUR::Playlist> pl = track->playlist();
pl->find_next_region(n, ARDOUR::End, 0)->set_video_locked(true);
}
_session->save_state ("");
}
import_status.all_done = true;
#endif
unlink(path.c_str());
}

View File

@@ -157,6 +157,8 @@ LevelMeterBase::update_meters ()
(*i).meter->set (meter_deflect_ppm (peak + meter_lineup(0)));
} else if (meter_type == MeterVU) {
(*i).meter->set (meter_deflect_vu (peak + vu_standard() + meter_lineup(0)));
} else if (meter_type == MeterK12) {
(*i).meter->set (meter_deflect_k (peak, 12), meter_deflect_k(_meter->meter_level(n, MeterPeak), 12));
} else if (meter_type == MeterK14) {
(*i).meter->set (meter_deflect_k (peak, 14), meter_deflect_k(_meter->meter_level(n, MeterPeak), 14));
} else if (meter_type == MeterK20) {
@@ -320,6 +322,17 @@ LevelMeterBase::setup_meters (int len, int initial_width, int thin_width)
c[6] = c[7] = 0xffff00ff;
c[8] = c[9] = 0xff0000ff;
break;
case MeterK12:
stp[0] = 115.0 * meter_deflect_k(-32, 12); //-20
stp[1] = 115.0 * meter_deflect_k(-12, 12); // 0
stp[2] = 115.0 * meter_deflect_k(-10, 12); // +2
stp[3] = 115.0 * meter_deflect_k( -8, 12); // +4
c[0] = c[1] = 0x008800ff;
c[2] = c[3] = 0x00ff00ff;
c[4] = c[5] = 0xffff00ff;
c[6] = c[7] = 0xffff00ff;
c[8] = c[9] = 0xff0000ff;
break;
case MeterIEC2BBC:
c[0] = c[1] = c[2] = c[3] = c[4] = c[5] = c[6] = c[7] = c[8] = c[9] =
ARDOUR_UI::config()->color_by_name ("meter color BBC");

View File

@@ -101,6 +101,9 @@ ArdourMeter::meter_type_string (ARDOUR::MeterType mt)
case MeterK14:
return _("K14");
break;
case MeterK12:
return _("K12");
break;
case MeterVU:
return _("VU");
break;
@@ -199,6 +202,16 @@ static inline float mtr_col_and_fract(
}
fraction = meter_deflect_k (val, 14);
break;
case MeterK12:
if (val >= -8.0) {
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); // red
} else if (val >= -12.0) {
cairo_set_source_rgb (cr, 0.8, 0.8, 0.0); // yellow
} else {
cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); // green
}
fraction = meter_deflect_k (val, 12);
break;
}
return fraction;
}
@@ -226,6 +239,7 @@ static void set_bg_color(Gtk::Widget& w, cairo_t* cr, MeterType type) {
case MeterIEC1NOR:
case MeterIEC2BBC:
case MeterIEC2EBU:
case MeterK12:
case MeterK14:
case MeterK20:
if (rgba_p_from_style("meterstripPPM", &r, &g, &b, "bg")) {
@@ -334,6 +348,20 @@ meter_render_ticks (Gtk::Widget& w, MeterType type, vector<ARDOUR::DataType> typ
case DataType::AUDIO:
switch (type) {
case MeterK12:
points.insert (std::pair<float,float>(-52.0f, 1.0));
points.insert (std::pair<float,float>(-42.0f, 1.0));
points.insert (std::pair<float,float>(-32.0f, 1.0));
points.insert (std::pair<float,float>(-22.0f, 1.0));
points.insert (std::pair<float,float>(-18.0f, 1.0));
points.insert (std::pair<float,float>(-15.0f, 1.0));
points.insert (std::pair<float,float>(-12.0f, 1.0));
points.insert (std::pair<float,float>( -9.0f, 1.0));
points.insert (std::pair<float,float>( -8.0f, 0.8));
points.insert (std::pair<float,float>( -6.0f, 1.0));
points.insert (std::pair<float,float>( -3.0f, 1.0));
points.insert (std::pair<float,float>( 0.0f, 1.0));
break;
case MeterK14:
points.insert (std::pair<float,float>(-54.0f, 1.0));
points.insert (std::pair<float,float>(-44.0f, 1.0));
@@ -645,6 +673,20 @@ meter_render_metrics (Gtk::Widget& w, MeterType type, vector<DataType> types)
case DataType::AUDIO:
layout->set_attributes (audio_font_attributes);
switch (type) {
case MeterK12:
overlay_midi = 0;
points.insert (std::pair<float,string>(-52.0f, "-40"));
points.insert (std::pair<float,string>(-42.0f, "-30"));
points.insert (std::pair<float,string>(-32.0f, "-20"));
points.insert (std::pair<float,string>(-22.0f, "-10"));
points.insert (std::pair<float,string>(-18.0f, "-6"));
points.insert (std::pair<float,string>(-15.0f, "-3"));
points.insert (std::pair<float,string>(-12.0f, " 0"));
points.insert (std::pair<float,string>( -9.0f, "+3"));
points.insert (std::pair<float,string>( -6.0f, "+6"));
points.insert (std::pair<float,string>( -3.0f, "+9"));
points.insert (std::pair<float,string>( 0.0f, "+12"));
break;
case MeterK14:
overlay_midi = 0;
points.insert (std::pair<float,string>(-54.0f, "-40"));
@@ -903,6 +945,9 @@ meter_render_metrics (Gtk::Widget& w, MeterType type, vector<DataType> types)
case MeterK14:
layout->set_text("K14");
break;
case MeterK12:
layout->set_text("K12");
break;
default:
case MeterPeak:
case MeterKrms:

View File

@@ -562,6 +562,7 @@ MeterStrip::update_background(MeterType type)
case MeterIEC1NOR:
case MeterIEC2BBC:
case MeterIEC2EBU:
case MeterK12:
case MeterK14:
case MeterK20:
mtr_container.set_name ("meterstripPPM");
@@ -747,6 +748,7 @@ MeterStrip::popup_level_meter_menu (GdkEventButton* ev)
add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK20), MeterK20);
add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK14), MeterK14);
add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterK12), MeterK12);
add_level_meter_type_item (items, group, ArdourMeter::meter_type_string(MeterVU), MeterVU);
MeterType cmt = _route->meter_type();

View File

@@ -2141,6 +2141,7 @@ MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
int _strip_type;

View File

@@ -438,7 +438,7 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
ardour->add_bundle (ltc);
}
/* Ardour's surfaces */
/* Ardour's control surfaces */
ControlProtocolManager& m = ControlProtocolManager::instance ();
for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {

View File

@@ -295,7 +295,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi
virtual void set_xjadeo_sensitive (bool onoff) = 0;
virtual int get_videotl_bar_height () const = 0;
virtual void set_video_timeline_height (const int h) = 0;
virtual void embed_audio_from_video (std::string, framepos_t n = 0) = 0;
virtual void embed_audio_from_video (std::string, framepos_t n = 0, bool lock_position_to_video = true) = 0;
virtual void export_video (bool range = false) = 0;
virtual RouteTimeAxisView* get_route_view_by_route_id (const PBD::ID& id) const = 0;

View File

@@ -648,6 +648,7 @@ class ControlSurfacesOptions : public OptionEditorBox
public:
ControlSurfacesOptions (Gtk::Window& parent)
: _parent (parent)
, _ignore_view_change (0)
{
_store = ListStore::create (_model);
_view.set_model (_store);
@@ -700,9 +701,14 @@ private:
void protocol_status_changed (ControlProtocolInfo* cpi) {
/* find the row */
TreeModel::Children rows = _store->children();
for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
string n = ((*x)[_model.name]);
if ((*x)[_model.protocol_info] == cpi) {
_ignore_view_change++;
(*x)[_model.enabled] = (cpi->protocol || cpi->requested);
_ignore_view_change--;
break;
}
}
@@ -712,6 +718,10 @@ private:
{
TreeModel::Row r = *i;
if (_ignore_view_change) {
return;
}
ControlProtocolInfo* cpi = r[_model.protocol_info];
if (!cpi) {
return;
@@ -720,22 +730,23 @@ private:
bool const was_enabled = (cpi->protocol != 0);
bool const is_enabled = r[_model.enabled];
if (was_enabled != is_enabled) {
if (!was_enabled) {
ControlProtocolManager::instance().instantiate (*cpi);
ControlProtocolManager::instance().activate (*cpi);
} else {
Gtk::Window* win = r[_model.editor];
if (win) {
win->hide ();
}
ControlProtocolManager::instance().teardown (*cpi);
ControlProtocolManager::instance().deactivate (*cpi);
if (win) {
delete win;
r[_model.editor] = 0;
}
r[_model.editor] = 0;
cpi->requested = false;
}
}
@@ -805,6 +816,7 @@ private:
TreeView _view;
Gtk::Window& _parent;
PBD::ScopedConnection protocol_status_connection;
uint32_t _ignore_view_change;
};
class VideoTimelineOptions : public OptionEditorBox

View File

@@ -357,14 +357,17 @@ def build(bld):
if bld.is_defined('WINDOWS_VST_SUPPORT'):
# If we require VST support we build a stub main() and the FST library
# here using winegcc, and link it to the GTK front-end library
obj = bld(features = 'cxx c cxxprogram wine')
obj.source = '''
../libs/fst/fst.c
../libs/fst/fstinfofile.c
../libs/fst/vsti.c
../libs/fst/vstwin.c
../vst/winmain.c
'''
obj = bld (features = 'cxx c cxxprogram wine')
obj.source = (
'../libs/fst/fst.c',
'../libs/fst/fstinfofile.c',
'../libs/fst/vsti.c',
'../libs/fst/vstwin.c',
'../vst/winmain.c',
)
#
# XXX do we really need to explicitly link to all of these for the wine executable?
#
obj.use = [ 'libpbd',
'libmidipp',
'libardour',
@@ -390,19 +393,22 @@ def build(bld):
obj.target = 'gtk2_ardour'
else:
# just the normal executable version of the GTK GUI
obj = bld(features = 'cxx c cxxprogram')
obj = bld (features = 'cxx c cxxprogram')
obj.source = gtk2_ardour_sources
obj.target = 'ardour-' + bld.env['VERSION']
obj.includes = ['.']
obj.use = [ 'libpbd',
'libardour',
'libardour_cp',
'libtimecode',
'libmidipp',
'libgtk2_ardour',
'libgtkmm2ext',
'libcanvas',
]
# at this point, "obj" refers to either the normal native executable
# OR the shared library built for use with wine on linux.
obj.use = [ 'libpbd',
'libardour',
'libardour_cp',
'libtimecode',
'libmidipp',
'libgtkmm2ext',
'libcanvas',
]
# continue with setup of obj, which could be a shared library
# or an executable.
@@ -415,7 +421,7 @@ def build(bld):
if bld.is_defined('USE_EXTERNAL_LIBS'):
obj.uselib += ' TAGLIB'
else:
obj.use.append('libtaglib')
obj.use += ('libtaglib')
if sys.platform == 'darwin':
obj.uselib += ' AUDIOUNITS OSX GTKOSX'
obj.use += ' libappleutility'

View File

@@ -65,8 +65,8 @@ class ControlProtocolManager : public PBD::Stateful, public ARDOUR::SessionHandl
void load_mandatory_protocols ();
void midi_connectivity_established ();
ControlProtocol* instantiate (ControlProtocolInfo&);
int teardown (ControlProtocolInfo&);
int activate (ControlProtocolInfo&);
int deactivate (ControlProtocolInfo&);
std::list<ControlProtocolInfo*> control_protocol_info;
@@ -89,6 +89,8 @@ class ControlProtocolManager : public PBD::Stateful, public ARDOUR::SessionHandl
int control_protocol_discover (std::string path);
ControlProtocolDescriptor* get_descriptor (std::string path);
ControlProtocolInfo* cpi_by_name (std::string);
ControlProtocol* instantiate (ControlProtocolInfo&);
int teardown (ControlProtocolInfo&);
};
} // namespace

View File

@@ -183,12 +183,14 @@ class Slave {
class ISlaveSessionProxy {
public:
virtual ~ISlaveSessionProxy() {}
virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); }
virtual framecnt_t frame_rate() const { return 0; }
virtual framepos_t audible_frame () const { return 0; }
virtual framepos_t transport_frame () const { return 0; }
virtual pframes_t frames_since_cycle_start () const { return 0; }
virtual framepos_t frame_time () const { return 0; }
virtual TempoMap& tempo_map() const { return *((TempoMap *) 0); }
virtual framecnt_t frame_rate() const { return 0; }
virtual pframes_t frames_per_cycle() const { return 0; }
virtual framepos_t audible_frame () const { return 0; }
virtual framepos_t transport_frame () const { return 0; }
virtual pframes_t frames_since_cycle_start () const { return 0; }
virtual pframes_t sample_time_at_cycle_start() const { return 0; }
virtual framepos_t frame_time () const { return 0; }
virtual void request_locate (framepos_t /*frame*/, bool with_roll = false) {
(void) with_roll;
@@ -204,12 +206,14 @@ class SlaveSessionProxy : public ISlaveSessionProxy {
public:
SlaveSessionProxy(Session &s) : session(s) {}
TempoMap& tempo_map() const;
framecnt_t frame_rate() const;
framepos_t audible_frame () const;
framepos_t transport_frame () const;
pframes_t frames_since_cycle_start () const;
framepos_t frame_time () const;
TempoMap& tempo_map() const;
framecnt_t frame_rate() const;
pframes_t frames_per_cycle() const;
framepos_t audible_frame () const;
framepos_t transport_frame () const;
pframes_t frames_since_cycle_start () const;
pframes_t sample_time_at_cycle_start() const;
framepos_t frame_time () const;
void request_locate (framepos_t frame, bool with_roll = false);
void request_transport_speed (double speed);

View File

@@ -187,7 +187,8 @@ namespace ARDOUR {
MeterIEC1NOR = 0x080,
MeterIEC2BBC = 0x100,
MeterIEC2EBU = 0x200,
MeterVU = 0x400
MeterVU = 0x400,
MeterK12 = 0x800
};
enum TrackMode {

View File

@@ -72,26 +72,54 @@ ControlProtocolManager::set_session (Session* s)
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
if ((*i)->requested || (*i)->mandatory) {
instantiate (**i);
(*i)->requested = false;
if ((*i)->protocol) {
if ((*i)->state) {
(*i)->protocol->set_state (*(*i)->state, Stateful::loading_state_version);
} else {
/* guarantee a call to
set_state() whether we have
existing state or not
*/
(*i)->protocol->set_state (XMLNode(""), Stateful::loading_state_version);
}
}
(void) activate (**i);
}
}
}
}
int
ControlProtocolManager::activate (ControlProtocolInfo& cpi)
{
ControlProtocol* cp;
cpi.requested = true;
if ((cp = instantiate (cpi)) == 0) {
return -1;
}
/* we split the set_state() and set_active() operations so that
protocols that need state to configure themselves (e.g. "What device
is connected, or supposed to be connected?") can get it before
actually starting any interaction.
*/
if (cpi.state) {
/* force this by tweaking the internals of the state
* XMLNode. Ugh.
*/
cp->set_state (*cpi.state, Stateful::loading_state_version);
} else {
/* guarantee a call to
set_state() whether we have
existing state or not
*/
cp->set_state (XMLNode(""), Stateful::loading_state_version);
}
cp->set_active (true);
return 0;
}
int
ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
{
cpi.requested = false;
return teardown (cpi);
}
void
ControlProtocolManager::session_going_away()
{
@@ -163,6 +191,12 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
if (cpi.mandatory) {
return 0;
}
/* save current state */
delete cpi.state;
cpi.state = new XMLNode (cpi.protocol->get_state());
cpi.state->add_property (X_("active"), "no");
cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
@@ -177,8 +211,6 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
}
cpi.protocol = 0;
delete cpi.state;
cpi.state = 0;
dlclose (cpi.descriptor->module);
ProtocolStatusChange (&cpi);
@@ -379,22 +411,21 @@ ControlProtocolManager::get_state ()
for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
XMLNode * child;
if ((*i)->protocol) {
child = &((*i)->protocol->get_state());
child->add_property (X_("active"), "yes");
// should we update (*i)->state here? probably.
root->add_child_nocopy (*child);
XMLNode& child_state ((*i)->protocol->get_state());
child_state.add_property (X_("active"), "yes");
root->add_child_nocopy (child_state);
} else if ((*i)->state) {
// keep ownership clear
root->add_child_copy (*(*i)->state);
XMLNode* child_state = new XMLNode (*(*i)->state);
child_state->add_property (X_("active"), "no");
root->add_child_nocopy (*child_state);
} else {
child = new XMLNode (X_("Protocol"));
child->add_property (X_("name"), (*i)->name);
child->add_property (X_("active"), "no");
root->add_child_nocopy (*child);
XMLNode* child_state = new XMLNode (X_("Protocol"));
child_state->add_property (X_("name"), (*i)->name);
child_state->add_property (X_("active"), "no");
root->add_child_nocopy (*child_state);
}
}
return *root;

View File

@@ -179,6 +179,7 @@ setup_enum_writer ()
REGISTER_ENUM (MeterKrms);
REGISTER_ENUM (MeterK20);
REGISTER_ENUM (MeterK14);
REGISTER_ENUM (MeterK12);
REGISTER_ENUM (MeterIEC1DIN);
REGISTER_ENUM (MeterIEC1NOR);
REGISTER_ENUM (MeterIEC2BBC);

View File

@@ -108,7 +108,7 @@ PeakMeter::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_fr
// Meter audio in to the rest of the peaks
for (uint32_t i = 0; i < n_audio; ++i, ++n) {
_peak_signal[n] = compute_peak (bufs.get_audio(i).data(), nframes, _peak_signal[n]);
if (_meter_type & (MeterKrms | MeterK20 | MeterK14)) {
if (_meter_type & (MeterKrms | MeterK20 | MeterK14 | MeterK12)) {
_kmeter[i]->process(bufs.get_audio(i).data(), nframes);
}
if (_meter_type & (MeterIEC1DIN | MeterIEC1NOR)) {
@@ -288,7 +288,7 @@ PeakMeter::meter ()
/* 0.01f ^= 100 Hz update rate */
const float midi_meter_falloff = Config->get_meter_falloff() * 0.01f;
/* kmeters: 24dB / 2 sec */
const float audio_meter_falloff = (_meter_type & (MeterK20 | MeterK14)) ? 0.12f : midi_meter_falloff;
const float audio_meter_falloff = (_meter_type & (MeterK20 | MeterK14 | MeterK12)) ? 0.12f : midi_meter_falloff;
for (size_t n = 0; n < limit; ++n) {
@@ -345,6 +345,7 @@ PeakMeter::meter_level(uint32_t n, MeterType type) {
case MeterKrms:
case MeterK20:
case MeterK14:
case MeterK12:
{
const uint32_t n_midi = current_meters.n_midi();
if (CHECKSIZE(_kmeter)) {
@@ -404,7 +405,7 @@ PeakMeter::set_type(MeterType t)
_meter_type = t;
if (t & (MeterKrms | MeterK20 | MeterK14)) {
if (t & (MeterKrms | MeterK20 | MeterK14 | MeterK12)) {
const size_t n_audio = current_meters.n_audio();
for (size_t n = 0; n < n_audio; ++n) {
_kmeter[n]->reset();

View File

@@ -45,7 +45,7 @@ using namespace PBD;
MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn)
: ppqn (ppqn)
, bandwidth (10.0 / 60.0) // 1 BpM = 1 / 60 Hz
, bandwidth (2.0 / 60.0) // 1 BpM = 1 / 60 Hz
{
session = (ISlaveSessionProxy *) new SlaveSessionProxy(s);
rebind (p);
@@ -55,7 +55,7 @@ MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn)
MIDIClock_Slave::MIDIClock_Slave (ISlaveSessionProxy* session_proxy, int ppqn)
: session(session_proxy)
, ppqn (ppqn)
, bandwidth (10.0 / 60.0) // 1 BpM = 1 / 60 Hz
, bandwidth (2.0 / 60.0) // 1 BpM = 1 / 60 Hz
{
reset ();
}
@@ -123,6 +123,8 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, framepos_t timestamp)
return;
}
pframes_t cycle_offset = timestamp - session->sample_time_at_cycle_start();
calculate_one_ppqn_in_frames_at(should_be_position);
framepos_t elapsed_since_start = timestamp - first_timestamp;
@@ -134,6 +136,8 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, framepos_t timestamp)
first_timestamp = timestamp;
elapsed_since_start = should_be_position;
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("first clock message after start received @ %1\n", timestamp));
// calculate filter coefficients
calculate_filter_coefficients();
@@ -153,7 +157,7 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, framepos_t timestamp)
// we use session->transport_frame() instead of t1 here
// because t1 is used to calculate the transport speed,
// so the loop will compensate for accumulating rounding errors
error = (double(should_be_position) - double(session->transport_frame()));
error = (double(should_be_position) - (double(session->transport_frame()) + double(cycle_offset)));
e = error / double(session->frame_rate());
current_delta = error;
@@ -163,21 +167,23 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, framepos_t timestamp)
e2 += c * e;
}
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock #%1 @ %2 arrived %3 (theoretical) audible %4 transport %5 error %6 "
"read delta %7 should-be delta %8 t1-t0 %9 t0 %10 t1 %11 framerate %12 appspeed %13\n",
midi_clock_count,
elapsed_since_start,
should_be_position,
session->audible_frame(),
session->transport_frame(),
error,
timestamp - last_timestamp,
one_ppqn_in_frames,
(t1 -t0) * session->frame_rate(),
t0 * session->frame_rate(),
t1 * session->frame_rate(),
session->frame_rate(),
((t1 - t0) * session->frame_rate()) / one_ppqn_in_frames));
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("clock #%1 @ %2 should-be %3 transport %4 error %5 appspeed %6 "
"read-delta %7 should-be delta %8 t1-t0 %9 t0 %10 t1 %11 framerate %12 engine %13\n",
midi_clock_count, // #
elapsed_since_start, // @
should_be_position, // should-be
session->transport_frame(), // transport
error, // error
((t1 - t0) * session->frame_rate()) / one_ppqn_in_frames, // appspeed
timestamp - last_timestamp, // read delta
one_ppqn_in_frames, // should-be delta
(t1 - t0) * session->frame_rate(), // t1-t0
t0 * session->frame_rate(), // t0
t1 * session->frame_rate(), // t1
session->frame_rate(), // framerate
session->frame_time()
));
last_timestamp = timestamp;
}
@@ -185,7 +191,7 @@ MIDIClock_Slave::update_midi_clock (Parser& /*parser*/, framepos_t timestamp)
void
MIDIClock_Slave::start (Parser& /*parser*/, framepos_t timestamp)
{
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave got start message at time %1 engine time %2\n", timestamp, session->frame_time()));
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave got start message at time %1 engine time %2 transport_frame %3\n", timestamp, session->frame_time(), session->transport_frame()));
if (!_started) {
reset();
@@ -200,6 +206,8 @@ MIDIClock_Slave::start (Parser& /*parser*/, framepos_t timestamp)
void
MIDIClock_Slave::reset ()
{
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MidiClock_Slave reset(): calculated filter bandwidth is %1 for period size %2\n", bandwidth, session->frames_per_cycle()));
should_be_position = session->transport_frame();
last_timestamp = 0;
@@ -345,7 +353,7 @@ MIDIClock_Slave::speed_and_position (double& speed, framepos_t& pos)
pos = should_be_position;
}
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: %1 & %2 <-> %3 (transport)\n", speed, pos, session->transport_frame()));
DEBUG_TRACE (DEBUG::MidiClock, string_compose ("speed_and_position: speed %1 should-be %2 transport %3 \n", speed, pos, session->transport_frame()));
return true;
}

View File

@@ -61,6 +61,8 @@ MidiControlUI::do_request (MidiUIRequest* req)
{
if (req->type == Quit) {
BaseUI::quit ();
} else if (req->type == CallSlot) {
req->the_slot ();
}
}

View File

@@ -35,6 +35,12 @@ SlaveSessionProxy::frame_rate() const
return session.frame_rate();
}
pframes_t
SlaveSessionProxy::frames_per_cycle() const
{
return session.engine().samples_per_cycle();
}
framepos_t
SlaveSessionProxy::audible_frame() const
{
@@ -53,6 +59,13 @@ SlaveSessionProxy::frames_since_cycle_start() const
return session.engine().samples_since_cycle_start();
}
pframes_t
SlaveSessionProxy::sample_time_at_cycle_start() const
{
return session.engine().sample_time_at_cycle_start();
}
framepos_t
SlaveSessionProxy::frame_time() const
{

View File

@@ -106,6 +106,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (1.0);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES * cubic.speed()), result);
for (int i = 0; i < NUM_SAMPLES; i += INTERVAL) {
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
@@ -116,6 +117,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (0.5);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES * cubic.speed()), result);
for (int i = 0; i < NUM_SAMPLES; i += (INTERVAL / cubic.speed() +0.5)) {
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
@@ -126,6 +128,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (0.2);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES * cubic.speed()), result);
// cout << "\nSpeed: 0.02";
@@ -133,6 +136,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (0.02);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES * cubic.speed()), result);
/* This one fails due too error accumulation
@@ -150,6 +154,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (2.0);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES / 2, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES / 2, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES / 2 * cubic.speed()), result);
for (int i = 0; i < NUM_SAMPLES / 2; i += (INTERVAL / cubic.speed() +0.5)) {
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);
@@ -159,6 +164,7 @@ InterpolationTest::cubicInterpolationTest ()
cubic.set_speed (10.0);
cubic.set_target_speed (cubic.speed());
result = cubic.interpolate (0, NUM_SAMPLES / 10, input, output);
CPPUNIT_ASSERT_EQUAL (result, cubic.interpolate (0, NUM_SAMPLES / 10, NULL, NULL));
CPPUNIT_ASSERT_EQUAL ((framecnt_t)(NUM_SAMPLES / 10 * cubic.speed()), result);
for (int i = 0; i < NUM_SAMPLES / 10; i += (INTERVAL / cubic.speed() +0.5)) {
CPPUNIT_ASSERT_EQUAL (1.0f, output[i]);

View File

@@ -86,16 +86,18 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
boost::optional<Rect> draw = root_bbox->intersection (area);
if (draw) {
// context->rectangle (area.x0, area.y0, area.x1 - area.x0, area.y1 - area.y0);
// context->set_source_rgba (1.0, 0, 0, 1.0);
// context->fill ();
/* there's a common area between the root and the requested
area, so render it.
*/
_root.render (*draw, context);
// This outlines the rect being rendered, after it has been drawn.
// context->rectangle (draw->x0, draw->y0, draw->x1 - draw->x0, draw->y1 - draw->y0);
// context->set_source_rgba (1.0, 0, 0, 1.0);
// context->stroke ();
}
}
@@ -704,7 +706,7 @@ void
GtkCanvas::request_redraw (Rect const & request)
{
Rect area = canvas_to_window (request);
queue_draw_area (floor (area.x0), floor (area.y0), ceil (area.width()), ceil (area.height()));
queue_draw_area (area.x0, area.y0, area.width(), area.height());
}
/** Called to request that we try to get a particular size for ourselves.

View File

@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
/* LV2 */
#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
@@ -56,6 +57,7 @@ typedef struct {
double SampleRateD;
void *synth;
bool xmas;
} RSynth;
/* main LV2 */
@@ -98,6 +100,16 @@ instantiate(const LV2_Descriptor* descriptor,
self->synth = synth_alloc();
synth_init(self->synth, rate);
struct tm date;
time_t now;
time(&now);
localtime_r(&now, &date);
if (getenv("ITSXMAS") || (date.tm_mon == 11 /*dec*/ && date.tm_mday == 25)) {
printf("reasonable synth.lv2 says: happy holidays!\n");
self->xmas = true;
}
return (LV2_Handle)self;
}
@@ -146,7 +158,11 @@ run(LV2_Handle handle, uint32_t n_samples)
written = synth_sound(self->synth, written, ev->time.frames, audio);
}
/* send midi message to synth */
synth_parse_midi(self->synth, (const uint8_t*)(ev+1), ev->body.size);
if (self->xmas) {
synth_parse_xmas(self->synth, (const uint8_t*)(ev+1), ev->body.size);
} else {
synth_parse_midi(self->synth, (const uint8_t*)(ev+1), ev->body.size);
}
}
ev = (LV2_Atom_Event const*) // lv2_atom_sequence_next()
((const uint8_t*)ev + sizeof(LV2_Atom_Event) + ((ev->body.size + 7) & ~7));

View File

@@ -71,6 +71,7 @@ typedef struct _RSSynthChannel {
float adsr_amp[128];
float phase[128]; // various use, zero'ed on note-on
int8_t miditable[128]; // internal, note-on/off velocity
int8_t midimsgs [128]; // internal, note-off + on in same cycle
ADSRcfg adsr;
void (*synthesize) (struct _RSSynthChannel* sc,
const uint8_t note, const float vol, const float pc,
@@ -89,6 +90,8 @@ typedef struct {
float kcgain;
float kcfilt;
double rate;
uint32_t xmas_on;
uint32_t xmas_off;
} RSSynthesizer;
@@ -216,8 +219,10 @@ static void process_key (void *synth,
RSSynthesizer* rs = (RSSynthesizer*)synth;
RSSynthChannel* sc = &rs->sc[chn];
const int8_t vel = sc->miditable[note];
const int8_t msg = sc->midimsgs[note];
const float vol = /* master_volume */ 0.25 * fabsf(vel) / 127.0;
const float phase = sc->phase[note];
sc->midimsgs[note] = 0;
if (phase == -10 && vel > 0) {
// new note on
@@ -230,7 +235,7 @@ static void process_key (void *synth,
}
else if (phase >= -1.0 && phase <= 1.0 && vel > 0) {
// sustain note or re-start note while adsr in progress:
if (sc->adsr_cnt[note] > sc->adsr.off[1]) {
if (sc->adsr_cnt[note] > sc->adsr.off[1] || msg == 3) {
// x-fade to attack
sc->adsr_amp[note] = adsr_env(sc, note);
sc->adsr_cnt[note] = 0;
@@ -305,6 +310,7 @@ static void synth_reset_channel(RSSynthChannel* sc) {
sc->adsr_amp[k] = 0;
sc->phase[k] = -10;
sc->miditable[k] = 0;
sc->midimsgs[k] = 0;
}
sc->keycomp = 0;
}
@@ -336,10 +342,12 @@ static void synth_process_midi_event(void *synth, struct rmidi_event_t *ev) {
RSSynthesizer* rs = (RSSynthesizer*)synth;
switch(ev->type) {
case NOTE_ON:
rs->sc[ev->channel].midimsgs[ev->d.tone.note] |= 1;
if (rs->sc[ev->channel].miditable[ev->d.tone.note] <= 0)
rs->sc[ev->channel].miditable[ev->d.tone.note] = ev->d.tone.velocity;
break;
case NOTE_OFF:
rs->sc[ev->channel].midimsgs[ev->d.tone.note] |= 2;
if (rs->sc[ev->channel].miditable[ev->d.tone.note] > 0)
rs->sc[ev->channel].miditable[ev->d.tone.note] *= -1.0;
break;
@@ -446,6 +454,44 @@ static void synth_parse_midi(void *synth, const uint8_t *data, const size_t size
synth_process_midi_event(synth, &ev);
}
static const uint8_t jingle[] = { 71 ,71 ,71 ,71 ,71 ,71 ,71 ,74 ,67 ,69 ,71 ,72 ,72 ,72 ,72 ,72 ,71 ,71 ,71 ,71 ,71 ,69 ,69 ,71 ,69 ,74 ,71 ,71 ,71 ,71 ,71 ,71 ,71 ,74 ,67 ,69 ,71 ,72 ,72 ,72 ,72 ,72 ,71 ,71 ,71 ,71 ,74 ,74 ,72 ,69 ,67 ,62 ,62 ,71 ,69 ,67 ,62 ,62 ,62 ,62 ,71 ,69 ,67 ,64 ,64 ,64 ,72 ,71 ,69 ,66 ,74 ,76 ,74 ,72 ,69 ,71 ,62 ,62 ,71 ,69 ,67 ,62 ,62 ,62 ,62 ,71 ,69 ,67 ,64 ,64 ,64 ,72 ,71 ,69 ,74 ,74 ,74 ,74 ,76 ,74 ,72 ,69 ,67 ,74 ,71 ,71 ,71 ,71 ,71 ,71 ,71 ,74 ,67 ,69 ,71 ,72 ,72 ,72 ,72 ,72 ,71 ,71 ,71 ,71 ,71 ,69 ,69 ,71 ,69 ,74 ,71 ,71 ,71 ,71 ,71 ,71 ,71 ,74 ,67 ,69 ,71 ,72 ,72 ,72 ,72 ,72 ,71 ,71 ,71 ,71 ,74 ,74 ,72 ,69 ,67 };
static void synth_parse_xmas(void *synth, const uint8_t *data, const size_t size) {
RSSynthesizer* rs = (RSSynthesizer*)synth;
if (size < 2 || size > 3) return;
// All messages need to be 3 bytes; except program-changes: 2bytes.
if (size == 2 && (data[0] & 0xf0) != 0xC0) return;
struct rmidi_event_t ev;
ev.channel = data[0]&0x0f;
switch (data[0] & 0xf0) {
case 0x80:
ev.type=NOTE_OFF;
ev.d.tone.note=jingle[rs->xmas_off++];
ev.d.tone.velocity=data[2]&0x7f;
if (rs->xmas_off >= sizeof(jingle)) rs->xmas_off = 0;
break;
case 0x90:
ev.type=NOTE_ON;
ev.d.tone.note=jingle[rs->xmas_on++];
ev.d.tone.velocity=data[2]&0x7f;
if (rs->xmas_on >= sizeof(jingle)) rs->xmas_on = 0;
break;
case 0xB0:
ev.type=CONTROL_CHANGE;
ev.d.control.param=data[1]&0x7f;
ev.d.control.value=data[2]&0x7f;
break;
case 0xC0:
ev.type=PROGRAM_CHANGE;
ev.d.control.value=data[1]&0x7f;
break;
default:
return;
}
synth_process_midi_event(synth, &ev);
}
/**
* initialize the synth
* This should be called after synth_alloc()
@@ -461,7 +507,7 @@ static void synth_init(void *synth, double rate) {
const float tuning = 440;
int c,k;
for (k=0; k < 128; k++) {
rs->freqs[k] = (2.0 * tuning / 32.0f) * powf(2, (k - 9.0) / 12.0) / rate;
rs->freqs[k] = (tuning / 32.0f) * powf(2, (k - 9.0) / 12.0) / rate;
assert(rs->freqs[k] < M_PI/2); // otherwise spatialization may phase out..
}
rs->kcfilt = 12.0 / rate;
@@ -470,6 +516,8 @@ static void synth_init(void *synth, double rate) {
for (c=0; c < 16; c++) {
synth_load(&rs->sc[c], rate, &synthesize_sineP, &piano_adsr);
}
rs->xmas_on = 0;
rs->xmas_off = 0;
}
/**

View File

@@ -53,6 +53,8 @@ PBD::Signal0<void> ControlProtocol::ClearRouteSelection;
PBD::Signal0<void> ControlProtocol::StepTracksDown;
PBD::Signal0<void> ControlProtocol::StepTracksUp;
const std::string ControlProtocol::state_node_name ("Protocol");
ControlProtocol::ControlProtocol (Session& s, string str)
: BasicUI (s)
, _name (str)
@@ -64,6 +66,13 @@ ControlProtocol::~ControlProtocol ()
{
}
int
ControlProtocol::set_active (bool yn)
{
_active = yn;
return 0;
}
void
ControlProtocol::next_track (uint32_t initial_id)
{
@@ -356,5 +365,15 @@ ControlProtocol:: route_get_name (uint32_t table_index)
list<boost::shared_ptr<Bundle> >
ControlProtocol::bundles ()
{
return list<boost::shared_ptr<Bundle> > ();
return list<boost::shared_ptr<Bundle> > ();
}
XMLNode&
ControlProtocol::get_state ()
{
XMLNode* node = new XMLNode (state_node_name);
node->add_property ("name", _name);
return *node;
}

View File

@@ -47,8 +47,8 @@ class ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList,
std::string name() const { return _name; }
virtual int set_active (bool yn) = 0;
bool get_active() const { return _active; }
virtual int set_active (bool yn);
bool active() const { return _active; }
virtual int set_feedback (bool /*yn*/) { return 0; }
virtual bool get_feedback () const { return false; }
@@ -133,16 +133,19 @@ class ControlProtocol : public PBD::Stateful, public PBD::ScopedConnectionList,
virtual void* get_gui() const { return 0; }
virtual void tear_down_gui() { }
XMLNode& get_state ();
static const std::string state_node_name;
protected:
std::vector<boost::shared_ptr<ARDOUR::Route> > route_table;
std::string _name;
bool _active;
void next_track (uint32_t initial_id);
void prev_track (uint32_t initial_id);
private:
ControlProtocol (const ControlProtocol&); /* noncopyable */
bool _active;
};
extern "C" {

View File

@@ -1921,9 +1921,7 @@ TranzportControlProtocol::print_noretry (int row, int col, const char *text)
XMLNode&
TranzportControlProtocol::get_state ()
{
XMLNode* node = new XMLNode (X_("Protocol"));
node->add_property (X_("name"), _name);
return *node;
return ControlProtocol::get_state();
}
int

View File

@@ -80,16 +80,14 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
Controllable::CreateBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::create_binding, this, _1, _2, _3));
Controllable::DeleteBinding.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::delete_binding, this, _1));
Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
#if 0
/* XXXX SOMETHING GOES WRONG HERE (april 2012) - STILL DEBUGGING */
/* this signal is emitted by the process() callback, and if
* send_feedback() is going to do anything, it should do it in the
* context of the process() callback itself.
*/
Session::SendFeedback.connect_same_thread (*this, boost::bind (&GenericMidiControlProtocol::send_feedback, this));
#endif
//Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::send_feedback, this), midi_ui_context());;
/* this one is cross-thread */
Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&GenericMidiControlProtocol::reset_controllables, this), midi_ui_context());
@@ -466,23 +464,22 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos,
XMLNode&
GenericMidiControlProtocol::get_state ()
{
XMLNode* node = new XMLNode ("Protocol");
XMLNode& node (ControlProtocol::get_state());
char buf[32];
node->add_property (X_("name"), _name);
node->add_property (X_("feedback"), do_feedback ? "1" : "0");
node.add_property (X_("feedback"), do_feedback ? "1" : "0");
snprintf (buf, sizeof (buf), "%" PRIu64, _feedback_interval);
node->add_property (X_("feedback_interval"), buf);
node.add_property (X_("feedback_interval"), buf);
snprintf (buf, sizeof (buf), "%d", _threshold);
node->add_property (X_("threshold"), buf);
node.add_property (X_("threshold"), buf);
if (!_current_binding.empty()) {
node->add_property ("binding", _current_binding);
node.add_property ("binding", _current_binding);
}
XMLNode* children = new XMLNode (X_("Controls"));
node->add_child_nocopy (*children);
node.add_child_nocopy (*children);
Glib::Threads::Mutex::Lock lm2 (controllables_lock);
for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
@@ -497,7 +494,7 @@ GenericMidiControlProtocol::get_state ()
}
}
return *node;
return node;
}
int

View File

@@ -453,8 +453,6 @@ MackieControlProtocolGUI::action_changed (const Glib::ustring &sPath, const Glib
return;
}
cerr << "Changed to " << i->first << " aka " << i->second << endl;
Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (i->second.c_str());
if (act) {
@@ -504,8 +502,6 @@ MackieControlProtocolGUI::surface_combo_changed ()
/* update ipMIDI field */
cerr << "New device called " << _cp.device_info().name() << " with ipMIDI ? " << _cp.device_info().uses_ipmidi() << endl;
ipmidi_base_port_spinner.set_sensitive (_cp.device_info().uses_ipmidi());
}
@@ -522,7 +518,6 @@ MackieControlProtocolGUI::profile_combo_changed ()
void
MackieControlProtocolGUI::ipmidi_spinner_changed ()
{
cerr << "Set IP MIDI base to " << ipmidi_base_port_spinner.get_value() << endl;
_cp.set_ipmidi_base ((int16_t) lrintf (ipmidi_base_port_spinner.get_value()));
}

View File

@@ -96,8 +96,6 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, AbstractUI<MackieControlUIRequest> ("mackie")
, _current_initial_bank (0)
, _timecode_type (ARDOUR::AnyTime::BBT)
, _input_bundle (new ARDOUR::Bundle (_("Mackie Control In"), true))
, _output_bundle (new ARDOUR::Bundle (_("Mackie Control Out"), false))
, _gui (0)
, _zoom_mode (false)
, _scrub_mode (false)
@@ -109,6 +107,8 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, needs_ipmidi_restart (false)
, _metering_active (true)
, _initialized (false)
, _surfaces_state (0)
, _surfaces_version (0)
{
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
@@ -132,7 +132,7 @@ MackieControlProtocol::~MackieControlProtocol()
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol tear_down_gui ()\n");
tear_down_gui ();
_active = false;
delete _surfaces_state;
/* stop event loop */
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol BaseUI::quit ()\n");
@@ -383,7 +383,7 @@ MackieControlProtocol::set_active (bool yn)
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active init with yn: '%1'\n", yn));
if (yn == _active) {
if (yn == active()) {
return 0;
}
@@ -397,7 +397,6 @@ MackieControlProtocol::set_active (bool yn)
return -1;
}
connect_session_signals ();
_active = true;
update_surfaces ();
/* set up periodic task for metering and automation
@@ -411,10 +410,11 @@ MackieControlProtocol::set_active (bool yn)
BaseUI::quit ();
close ();
_active = false;
}
ControlProtocol::set_active (yn);
DEBUG_TRACE (DEBUG::MackieControl, string_compose("MackieControlProtocol::set_active done with yn: '%1'\n", yn));
return 0;
@@ -423,7 +423,7 @@ MackieControlProtocol::set_active (bool yn)
bool
MackieControlProtocol::periodic ()
{
if (!_active) {
if (!active()) {
return false;
}
@@ -526,7 +526,7 @@ void
MackieControlProtocol::update_surfaces()
{
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::update_surfaces() init\n");
if (!_active) {
if (!active()) {
return;
}
@@ -609,34 +609,36 @@ MackieControlProtocol::set_profile (const string& profile_name)
}
int
MackieControlProtocol::set_device (const string& device_name, bool allow_activation)
MackieControlProtocol::set_device_info (const string& device_name)
{
map<string,DeviceInfo>::iterator d = DeviceInfo::device_info.find (device_name);
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("new device chosen %1, activation allowed ? %2\n",
device_name, allow_activation));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("new device chosen %1\n", device_name));
if (d == DeviceInfo::device_info.end()) {
return -1;
}
if (_active) {
clear_ports ();
clear_surfaces ();
}
_device_info = d->second;
if (allow_activation) {
set_active (true);
} else {
if (_active) {
if (create_surfaces ()) {
return -1;
}
switch_banks (0, true);
}
return 0;
}
int
MackieControlProtocol::set_device (const string& device_name)
{
if (set_device_info (device_name)) {
return -1;
}
clear_surfaces ();
if (create_surfaces ()) {
return -1;
}
switch_banks (0, true);
return 0;
}
@@ -665,6 +667,10 @@ MackieControlProtocol::create_surfaces ()
return -1;
}
if (_surfaces_state) {
surface->set_state (*_surfaces_state, _surfaces_version);
}
{
Glib::Threads::Mutex::Lock lm (surfaces_lock);
surfaces.push_back (surface);
@@ -681,6 +687,10 @@ MackieControlProtocol::create_surfaces ()
stype = ext;
if (!_device_info.uses_ipmidi()) {
_input_bundle.reset (new ARDOUR::Bundle (_("Mackie Control In"), true));
_output_bundle.reset (new ARDOUR::Bundle (_("Mackie Control Out"), false));
_input_bundle->add_channel (
surface->port().input_port().name(),
ARDOUR::DataType::MIDI,
@@ -692,6 +702,16 @@ MackieControlProtocol::create_surfaces ()
ARDOUR::DataType::MIDI,
session->engine().make_port_name_non_relative (surface->port().output_port().name())
);
session->BundleAdded (_input_bundle);
session->BundleAdded (_output_bundle);
} else {
_input_bundle.reset ((ARDOUR::Bundle*) 0);
_output_bundle.reset ((ARDOUR::Bundle*) 0);
session->BundleRemoved (_input_bundle);
session->BundleRemoved (_output_bundle);
}
int fd;
@@ -716,9 +736,6 @@ MackieControlProtocol::create_surfaces ()
void
MackieControlProtocol::close()
{
clear_ports ();
port_connections.drop_connections ();
session_connections.drop_connections ();
route_connections.drop_connections ();
periodic_connection.disconnect ();
@@ -729,38 +746,42 @@ MackieControlProtocol::close()
XMLNode&
MackieControlProtocol::get_state()
{
XMLNode& node (ControlProtocol::get_state());
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state init\n");
char buf[16];
// add name of protocol
XMLNode* node = new XMLNode (X_("Protocol"));
node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
// add current bank
snprintf (buf, sizeof (buf), "%d", _current_initial_bank);
node->add_property (X_("bank"), buf);
node.add_property (X_("bank"), buf);
// ipMIDI base port (possibly not used)
snprintf (buf, sizeof (buf), "%d", _ipmidi_base);
node->add_property (X_("ipmidi-base"), buf);
node.add_property (X_("ipmidi-base"), buf);
node->add_property (X_("device-profile"), _device_profile.name());
node->add_property (X_("device-name"), _device_info.name());
node.add_property (X_("device-profile"), _device_profile.name());
node.add_property (X_("device-name"), _device_info.name());
XMLNode* snode = new XMLNode (X_("Surfaces"));
for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
snode->add_child_nocopy ((*s)->get_state());
}
node.add_child_nocopy (*snode);
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state done\n");
return *node;
return node;
}
int
MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
MackieControlProtocol::set_state (const XMLNode & node, int version)
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", _active));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", active()));
int retval = 0;
const XMLProperty* prop;
uint32_t bank = 0;
bool active = _active;
if ((prop = node.property (X_("ipmidi-base"))) != 0) {
set_ipmidi_base (atoi (prop->value()));
@@ -771,24 +792,26 @@ MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
bank = atoi (prop->value());
}
if ((prop = node.property (X_("active"))) != 0) {
active = string_is_affirmative (prop->value());
}
if ((prop = node.property (X_("device-name"))) != 0) {
set_device (prop->value(), false);
set_device_info (prop->value());
}
if ((prop = node.property (X_("device-profile"))) != 0) {
set_profile (prop->value());
}
XMLNode* snode = node.child (X_("Surfaces"));
delete _surfaces_state;
_surfaces_state = 0;
set_active (active);
if (_active) {
switch_banks (bank, true);
if (snode) {
_surfaces_state = new XMLNode (*snode);
_surfaces_version = version;
}
switch_banks (bank, true);
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::set_state done\n");
return retval;
@@ -1035,8 +1058,12 @@ list<boost::shared_ptr<ARDOUR::Bundle> >
MackieControlProtocol::bundles ()
{
list<boost::shared_ptr<ARDOUR::Bundle> > b;
b.push_back (_input_bundle);
b.push_back (_output_bundle);
if (_input_bundle) {
b.push_back (_input_bundle);
b.push_back (_output_bundle);
}
return b;
}
@@ -1259,8 +1286,10 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
void
MackieControlProtocol::clear_ports ()
{
_input_bundle->remove_channels ();
_output_bundle->remove_channels ();
if (_input_bundle) {
_input_bundle->remove_channels ();
_output_bundle->remove_channels ();
}
for (PortSources::iterator i = port_sources.begin(); i != port_sources.end(); ++i) {
g_source_destroy (*i);
@@ -1581,7 +1610,7 @@ MackieControlProtocol::set_ipmidi_base (int16_t portnum)
to restart.
*/
if (_active && _device_info.uses_ipmidi()) {
if (active() && _device_info.uses_ipmidi()) {
needs_ipmidi_restart = true;
}
}
@@ -1589,7 +1618,6 @@ MackieControlProtocol::set_ipmidi_base (int16_t portnum)
int
MackieControlProtocol::ipmidi_restart ()
{
clear_ports ();
clear_surfaces ();
if (create_surfaces ()) {
return -1;
@@ -1602,6 +1630,7 @@ MackieControlProtocol::ipmidi_restart ()
void
MackieControlProtocol::clear_surfaces ()
{
clear_ports ();
Glib::Threads::Mutex::Lock lm (surfaces_lock);
surfaces.clear ();
}

View File

@@ -120,7 +120,7 @@ class MackieControlProtocol
Mackie::DeviceProfile& device_profile() { return _device_profile; }
int set_active (bool yn);
int set_device (const std::string&, bool allow_activation = true);
int set_device (const std::string&);
void set_profile (const std::string&);
FlipMode flip_mode () const { return _flip_mode; }
@@ -262,7 +262,6 @@ class MackieControlProtocol
uint32_t _current_initial_bank;
PBD::ScopedConnectionList audio_engine_connections;
PBD::ScopedConnectionList session_connections;
PBD::ScopedConnectionList port_connections;
PBD::ScopedConnectionList route_connections;
PBD::ScopedConnectionList gui_connections;
// timer for two quick marker left presses
@@ -288,8 +287,9 @@ class MackieControlProtocol
bool needs_ipmidi_restart;
bool _metering_active;
bool _initialized;
ARDOUR::RouteNotificationList _last_selected_routes;
XMLNode* _surfaces_state;
int _surfaces_version;
int create_surfaces ();
bool periodic();
@@ -303,7 +303,8 @@ class MackieControlProtocol
void _gui_track_selection_changed (ARDOUR::RouteNotificationList*, bool save_list);
int ipmidi_restart ();
void initialize ();
int set_device_info (const std::string& device_name);
/* BUTTON HANDLING */
typedef std::set<uint32_t> DownButtonList;

View File

@@ -141,6 +141,39 @@ Surface::~Surface ()
DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface done\n");
}
XMLNode&
Surface::get_state()
{
char buf[64];
snprintf (buf, sizeof (buf), X_("surface-%u"), _number);
XMLNode* node = new XMLNode (buf);
node->add_child_nocopy (_port->get_state());
return *node;
}
int
Surface::set_state (const XMLNode& node, int version)
{
char buf[64];
snprintf (buf, sizeof (buf), X_("surface-%u"), _number);
XMLNode* mynode = node.child (buf);
if (!mynode) {
return 0;
}
XMLNode* portnode = mynode->child (X_("Port"));
if (portnode) {
if (_port->set_state (*portnode, version)) {
return -1;
}
}
return 0;
}
const MidiByteArray&
Surface::sysex_hdr() const
{
@@ -588,12 +621,6 @@ Surface::turn_it_on ()
}
}
void
Surface::handle_port_inactive (SurfacePort*)
{
_active = false;
}
void
Surface::write_sysex (const MidiByteArray & mba)
{

View File

@@ -3,6 +3,7 @@
#include <stdint.h>
#include "pbd/xml++.h"
#include "midi++/types.h"
#include "control_protocol/types.h"
@@ -92,9 +93,6 @@ public:
/// unless it's already connected
void connect_to_signals ();
/// notification from a MackiePort that it's now inactive
void handle_port_inactive(Mackie::SurfacePort *);
/// write a sysex message
void write_sysex (const MidiByteArray& mba);
void write_sysex (MIDI::byte msg);
@@ -149,6 +147,9 @@ public:
void notify_metering_state_changed();
void turn_it_on ();
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
protected:
private:

View File

@@ -51,11 +51,12 @@ using namespace ARDOUR;
SurfacePort::SurfacePort (Surface& s)
: _surface (&s)
{
if (_surface->mcp().device_info().uses_ipmidi()) {
_input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number());
_output_port = _input_port;
} else {
_async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, string_compose (_("%1 in"), _surface->name()), true);
_async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, string_compose (_("%1 out"), _surface->name()), true);
@@ -70,23 +71,73 @@ SurfacePort::SurfacePort (Surface& s)
SurfacePort::~SurfacePort()
{
if (_surface->mcp().device_info().uses_ipmidi()) {
if (dynamic_cast<MIDI::IPMIDIPort*>(_input_port)) {
delete _input_port;
} else {
if (_async_in) {
AudioEngine::instance()->unregister_port (_async_in);
_async_in.reset ();
_async_in.reset ((ARDOUR::Port*) 0);
}
if (_async_out) {
_output_port->drain (10000);
AudioEngine::instance()->unregister_port (_async_out);
_async_out.reset ();
_async_out.reset ((ARDOUR::Port*) 0);
}
}
}
XMLNode&
SurfacePort::get_state ()
{
XMLNode* node = new XMLNode (X_("Port"));
if (dynamic_cast<MIDI::IPMIDIPort*>(_input_port)) {
/* no state required for IPMidi ports */
return *node;
}
XMLNode* child;
child = new XMLNode (X_("Input"));
child->add_child_nocopy (_async_in->get_state());
node->add_child_nocopy (*child);
child = new XMLNode (X_("Output"));
child->add_child_nocopy (_async_out->get_state());
node->add_child_nocopy (*child);
return *node;
}
int
SurfacePort::set_state (const XMLNode& node, int version)
{
if (dynamic_cast<MIDI::IPMIDIPort*>(_input_port)) {
return 0;
}
XMLNode* child;
if ((child = node.child (X_("Input"))) != 0) {
XMLNode* portnode = child->child (Port::state_node_name.c_str());
if (portnode) {
_async_in->set_state (*portnode, version);
}
}
if ((child = node.child (X_("Output"))) != 0) {
XMLNode* portnode = child->child (Port::state_node_name.c_str());
if (portnode) {
_async_out->set_state (*portnode, version);
}
}
return 0;
}
// wrapper for one day when strerror_r is working properly
string fetch_errmsg (int error_number)
{

View File

@@ -50,15 +50,18 @@ class Surface;
class SurfacePort
{
public:
SurfacePort (Mackie::Surface&);
virtual ~SurfacePort();
/// an easier way to output bytes via midi
int write (const MidiByteArray&);
SurfacePort (Mackie::Surface&);
virtual ~SurfacePort();
/// an easier way to output bytes via midi
int write (const MidiByteArray&);
MIDI::Port& input_port() const { return *_input_port; }
MIDI::Port& output_port() const { return *_output_port; }
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
protected:
private:

View File

@@ -30,6 +30,7 @@
#include <glibmm/miscutils.h>
#include <pbd/convert.h>
#include <pbd/pthread_utils.h>
#include <pbd/file_utils.h>
#include <pbd/failed_constructor.h>
@@ -71,22 +72,20 @@ static void error_callback(int, const char *, const char *)
#endif
OSC::OSC (Session& s, uint32_t port)
: ControlProtocol (s, "OSC")
: ControlProtocol (s, X_("Open Sound Control (OSC)"))
, AbstractUI<OSCUIRequest> ("osc")
, local_server (0)
, remote_server (0)
, _port(port)
, _ok (true)
, _shutdown (false)
, _osc_server (0)
, _osc_unix_server (0)
, _namespace_root ("/ardour")
, _send_route_changes (true)
{
_instance = this;
_shutdown = false;
_osc_server = 0;
_osc_unix_server = 0;
_namespace_root = "/ardour";
_send_route_changes = true;
/* glibmm hack */
local_server = 0;
remote_server = 0;
// "Application Hooks"
session_loaded (s);
session->Exported.connect (*this, MISSING_INVALIDATOR, boost::bind (&OSC::session_exported, this, _1, _2), this);
}
@@ -113,11 +112,21 @@ OSC::do_request (OSCUIRequest* req)
int
OSC::set_active (bool yn)
{
if (yn) {
return start ();
} else {
return stop ();
if (yn != active()) {
if (yn) {
if (start ()) {
return -1;
}
} else {
if (stop ()) {
return -1;
}
}
}
return ControlProtocol::set_active (yn);
}
bool
@@ -1059,16 +1068,26 @@ OSC::route_plugin_parameter_print (int rid, int piid, int par)
XMLNode&
OSC::get_state ()
{
XMLNode* node = new XMLNode ("Protocol");
XMLNode& node (ControlProtocol::get_state());
node->add_property (X_("name"), "Open Sound Control (OSC)");
node->add_property (X_("feedback"), _send_route_changes ? "1" : "0");
return *node;
node.add_property (X_("feedback"), _send_route_changes ? "1" : "0");
return node;
}
int
OSC::set_state (const XMLNode&, int /*version*/)
OSC::set_state (const XMLNode& node, int /*version*/)
{
const XMLProperty* prop = node.property (X_("feedback"));
if (prop) {
if (PBD::string_is_affirmative (prop->value())) {
_send_route_changes = true;
} else {
_send_route_changes = false;
}
} else {
/* leave it alone */
}
return 0;
}

View File

@@ -50,9 +50,7 @@ using namespace PBD;
XMLNode&
TranzportControlProtocol::get_state ()
{
XMLNode* node = new XMLNode (X_("Protocol"));
node->add_property (X_("name"), _name);
return *node;
return ControlProtocol::get_state();
}
int

View File

@@ -65,7 +65,8 @@ WiimoteControlProtocol::set_active (bool yn)
DEBUG_TRACE (DEBUG::WiimoteControl, string_compose ("WiimoteControlProtocol::set_active init with yn: '%1'\n", yn));
/* do nothing if the active state is not changing */
if (yn == _active) {
if (yn == active()) {
return 0;
}
@@ -77,8 +78,7 @@ WiimoteControlProtocol::set_active (bool yn)
result = stop ();
}
/* remember new active state */
_active = yn;
ControlProtocol::set_active (yn);
DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::set_active done\n");
@@ -88,10 +88,9 @@ WiimoteControlProtocol::set_active (bool yn)
XMLNode&
WiimoteControlProtocol::get_state ()
{
XMLNode *node = new XMLNode ("Protocol");
node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
node->add_property (X_("feedback"), "0");
return *node;
XMLNode& node (ControlProtocol::get_state());
node.add_property (X_("feedback"), "0");
return node;
}
int

View File

@@ -369,6 +369,8 @@ if ($html) {
$boilerplate_header = <<END_HEADER;
\\documentclass[10pt,landscape]{article}
%\\documentclass[10pt,landscape,a4paper]{article}
%\\documentclass[10pt,landscape,letterpaper]{article}
\\usepackage{multicol}
\\usepackage{calc}
\\usepackage{ifthen}
@@ -387,7 +389,7 @@ $boilerplate_header = <<END_HEADER;
% if using A4 paper. (This probably isnott strictly necessary.)
% If using another size paper, use default 1cm margins.
\\ifthenelse{\\lengthtest { \\paperwidth = 11in}}
{ \\geometry{top=.5in,left=1in,right=0in,bottom=.5in} }
{ \\geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} }
{\\ifthenelse{ \\lengthtest{ \\paperwidth = 297mm}}
{\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
{\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
@@ -431,12 +433,11 @@ $boilerplate_footer = <<END_FOOTER;
\\rule{0.3\\linewidth}{0.25pt}
\\scriptsize
Copyright \\copyright\\ 2009 ardour.org
Copyright \\copyright\\ 2013 ardour.org
% Should change this to be date of file, not current date.
%\\verb!$Revision: 1.13 $, $Date: 2008/05/29 06:11:56 $.!
http://ardour.org/manual
http://manual.ardour.org
\\end{multicols}
\\end{document}