diff options
author | Colin Fletcher <colin.m.fletcher@googlemail.com> | 2014-02-24 18:11:48 +0000 |
---|---|---|
committer | Colin Fletcher <colin.m.fletcher@googlemail.com> | 2014-02-24 18:11:48 +0000 |
commit | 57077093b706c5938f9fd70f70d031cae2c59217 (patch) | |
tree | a4adfba29ac589479ad1b3a5888d6e6cf0ba9c60 /libs | |
parent | a643c9fdc08f98c7750a2474004a75e143077be9 (diff) | |
parent | ce4d125d1fd91bb3cdf82319dcce53abb35afcca (diff) |
Merge branch 'master' into export-dialog
Diffstat (limited to 'libs')
28 files changed, 263 insertions, 159 deletions
diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc index c97d624440..132be2e1c6 100644 --- a/libs/ardour/amp.cc +++ b/libs/ardour/amp.cc @@ -372,19 +372,9 @@ Amp::inc_gain (gain_t factor, void *src) } void -Amp::set_gain (gain_t val, void *src) +Amp::set_gain (gain_t val, void *) { - val = min (val, max_gain_coefficient); - - if (src != _gain_control.get()) { - _gain_control->set_value (val); - // bit twisty, this will come back and call us again - // (this keeps control in sync with reality) - return; - } - - _gain_control->set_double (val); - _session.set_dirty(); + _gain_control->set_value (val); } XMLNode& @@ -414,13 +404,8 @@ Amp::set_state (const XMLNode& node, int version) void Amp::GainControl::set_value (double val) { - if (val > max_gain_coefficient) { - val = max_gain_coefficient; - } - - _amp->set_gain (val, this); - - AutomationControl::set_value(val); + AutomationControl::set_value (min (val, (double) max_gain_coefficient)); + _amp->session().set_dirty (); } double diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h index c356ed82b9..aaad961abb 100644 --- a/libs/ardour/ardour/audio_buffer.h +++ b/libs/ardour/ardour/audio_buffer.h @@ -62,7 +62,7 @@ public: assert(&src != this); assert(_capacity > 0); assert(src.type() == DataType::AUDIO); - assert(len <= _capacity); + assert(dst_offset + len <= _capacity); assert( src_offset <= ((framecnt_t) src.capacity()-len)); memcpy(_data + dst_offset, ((const AudioBuffer&)src).data() + src_offset, sizeof(Sample) * len); if (dst_offset == 0 && src_offset == 0 && len == _capacity) { @@ -173,7 +173,6 @@ public: void set_data (Sample* data, size_t size) { assert(!_owns_data); // prevent leaks _capacity = size; - _size = size; _data = data; _silent = false; _written = false; @@ -185,8 +184,6 @@ public: */ void resize (size_t nframes); - bool empty() const { return _size == 0; } - const Sample* data (framecnt_t offset = 0) const { assert(offset <= _capacity); return _data + offset; @@ -198,7 +195,7 @@ public: return _data + offset; } - bool check_silence (pframes_t, bool, pframes_t&) const; + bool check_silence (pframes_t, pframes_t&) const; void prepare () { _written = false; _silent = false; } bool written() const { return _written; } diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h index 0d0f5d3758..87f7a90fc3 100644 --- a/libs/ardour/ardour/buffer.h +++ b/libs/ardour/ardour/buffer.h @@ -46,16 +46,9 @@ public: /** 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. */ + /** Maximum capacity of buffer. */ size_t capacity() const { return _capacity; } - /** Amount of valid data in buffer. Use this over capacity almost always. */ - size_t size() const { return _size; } - - /** Return true if the buffer contains no data, false otherwise */ - virtual bool empty() const { return _size == 0; } - /** Type of this buffer. * Based on this you can static cast a Buffer* to the desired type. */ DataType type() const { return _type; } @@ -80,12 +73,11 @@ public: protected: Buffer(DataType type) - : _type(type), _capacity(0), _size(0), _silent (true) + : _type(type), _capacity(0), _silent (true) {} DataType _type; pframes_t _capacity; - pframes_t _size; bool _silent; }; diff --git a/libs/ardour/ardour/file_source.h b/libs/ardour/ardour/file_source.h index 5898d04f0a..3d9c8c623f 100644 --- a/libs/ardour/ardour/file_source.h +++ b/libs/ardour/ardour/file_source.h @@ -74,6 +74,7 @@ public: void inc_use_count (); bool removable () const; + bool is_stub () const; const std::string& origin() const { return _origin; } diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h index 781396a598..c67eef178a 100644 --- a/libs/ardour/ardour/midi_buffer.h +++ b/libs/ardour/ardour/midi_buffer.h @@ -48,6 +48,8 @@ public: uint8_t* reserve(TimeType time, size_t size); void resize(size_t); + size_t size() const { return _size; } + bool empty() const { return _size == 0; } bool merge_in_place(const MidiBuffer &other); @@ -159,6 +161,7 @@ private: friend class iterator_base< const MidiBuffer, const Evoral::MIDIEvent<TimeType> >; uint8_t* _data; ///< timestamp, event, timestamp, event, ... + pframes_t _size; }; diff --git a/libs/ardour/ardour/vestige/aeffectx.h b/libs/ardour/ardour/vestige/aeffectx.h index bd2e3a1479..4007ecf5ef 100644 --- a/libs/ardour/ardour/vestige/aeffectx.h +++ b/libs/ardour/ardour/vestige/aeffectx.h @@ -270,8 +270,6 @@ typedef struct _VstTimeInfo } VstTimeInfo; -typedef struct _VstTimeInfo VstTimeInfo; - typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); #endif diff --git a/libs/ardour/audio_buffer.cc b/libs/ardour/audio_buffer.cc index aa4f64755a..de2c1ddf00 100644 --- a/libs/ardour/audio_buffer.cc +++ b/libs/ardour/audio_buffer.cc @@ -57,12 +57,6 @@ AudioBuffer::resize (size_t size) if (_data && size < _capacity) { /* buffer is already large enough */ - - if (size < _size) { - /* truncate */ - _size = size; - } - return; } @@ -71,14 +65,13 @@ AudioBuffer::resize (size_t size) cache_aligned_malloc ((void**) &_data, sizeof (Sample) * size); _capacity = size; - _size = 0; _silent = false; } bool -AudioBuffer::check_silence (pframes_t nframes, bool wholebuffer, pframes_t& n) const +AudioBuffer::check_silence (pframes_t nframes, pframes_t& n) const { - for (n = 0; (wholebuffer || n < _size) && n < nframes; ++n) { + for (n = 0; n < nframes; ++n) { if (_data[n] != Sample (0)) { return false; } diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc index 2586a14b58..355b0176ce 100644 --- a/libs/ardour/automation_control.cc +++ b/libs/ardour/automation_control.cc @@ -117,15 +117,23 @@ AutomationControl::set_automation_style (AutoStyle as) void AutomationControl::start_touch(double when) { - set_touching (true); - alist()->start_touch(when); - AutomationWatch::instance().add_automation_watch (shared_from_this()); + if (!touching()) { + if (alist()->automation_state() == Touch) { + alist()->start_touch (when); + AutomationWatch::instance().add_automation_watch (shared_from_this()); + } + set_touching (true); + } } void AutomationControl::stop_touch(bool mark, double when) { - set_touching (false); - alist()->stop_touch (mark, when); - AutomationWatch::instance().remove_automation_watch (shared_from_this()); + if (touching()) { + set_touching (false); + if (alist()->automation_state() == Touch) { + alist()->stop_touch (mark, when); + AutomationWatch::instance().remove_automation_watch (shared_from_this()); + } + } } diff --git a/libs/ardour/automation_watch.cc b/libs/ardour/automation_watch.cc index 16e10c95f9..87ac08abc2 100644 --- a/libs/ardour/automation_watch.cc +++ b/libs/ardour/automation_watch.cc @@ -122,7 +122,7 @@ AutomationWatch::timer () for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) { if ((*aw)->alist()->automation_write()) { - (*aw)->list()->add (time, (*aw)->user_double()); + (*aw)->list()->add (time, (*aw)->user_double(), true); } } } diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index 4a392a8145..8c12d44e51 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -397,7 +397,7 @@ Delivery::reset_panner () if (panners_legal) { if (!_no_panner_reset) { - if (_panshell && _role != Insert) { + if (_panshell && _role != Insert && _role != Listen) { _panshell->configure_io (ChanCount (DataType::AUDIO, pans_required()), ChanCount (DataType::AUDIO, pan_outs())); } } diff --git a/libs/ardour/export_channel.cc b/libs/ardour/export_channel.cc index c67f33bb91..0e029a01f7 100644 --- a/libs/ardour/export_channel.cc +++ b/libs/ardour/export_channel.cc @@ -239,7 +239,7 @@ RouteExportChannel::read (Sample const *& data, framecnt_t frames) const { assert(processor); AudioBuffer const & buffer = processor->get_capture_buffers().get_audio (channel); - assert (frames <= (framecnt_t) buffer.size()); + assert (frames <= (framecnt_t) buffer.capacity()); data = buffer.data(); } diff --git a/libs/ardour/file_source.cc b/libs/ardour/file_source.cc index 0921498186..c6f3a9cd5d 100644 --- a/libs/ardour/file_source.cc +++ b/libs/ardour/file_source.cc @@ -101,7 +101,7 @@ FileSource::removable () const { bool r = ((_flags & Removable) && ((_flags & RemoveAtDestroy) || - ((_flags & RemovableIfEmpty) && empty() == 0))); + ((_flags & RemovableIfEmpty) && empty()))); return r; } @@ -589,3 +589,21 @@ FileSource::inc_use_count () Source::inc_use_count (); } +bool +FileSource::is_stub () const +{ + if (!empty()) { + return false; + } + + if (!removable()) { + return false; + } + + if (Glib::file_test (_path, Glib::FILE_TEST_EXISTS)) { + return false; + } + + return true; +} + diff --git a/libs/ardour/internal_send.cc b/libs/ardour/internal_send.cc index 1d4e18d06e..17a3ca1f42 100644 --- a/libs/ardour/internal_send.cc +++ b/libs/ardour/internal_send.cc @@ -129,7 +129,7 @@ InternalSend::run (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame // we have to copy the input, because we may alter the buffers with the amp // in-place, which a send must never do. - if (_panshell && !_panshell->bypassed()) { + if (_panshell && !_panshell->bypassed() && role() != Listen) { _panshell->run (bufs, mixbufs, start_frame, end_frame, nframes); } else { if (role() == Listen) { diff --git a/libs/ardour/lv2_evbuf.c b/libs/ardour/lv2_evbuf.c index 8942d19a9b..f0e62d9b65 100644 --- a/libs/ardour/lv2_evbuf.c +++ b/libs/ardour/lv2_evbuf.c @@ -203,7 +203,7 @@ lv2_evbuf_get(LV2_Evbuf_Iterator iter, switch (iter.evbuf->type) { case LV2_EVBUF_EVENT: ebuf = &iter.evbuf->buf.event; - ev = (LV2_Event*)ebuf->data + iter.offset; + ev = (LV2_Event*)((char*)ebuf->data + iter.offset); *frames = ev->frames; *subframes = ev->subframes; *type = ev->type; diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index f2689bf998..2f90017498 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -464,39 +464,31 @@ PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end } } else { - if (has_no_audio_inputs()) { + uint32_t in = input_streams ().n_audio (); + uint32_t out = output_streams().n_audio (); + + if (has_no_audio_inputs() || in == 0) { /* silence all (audio) outputs. Should really declick * at the transitions of "active" */ - uint32_t out = output_streams().n_audio (); - for (uint32_t n = 0; n < out; ++n) { bufs.get_audio (n).silence (nframes); } - bufs.count().set_audio (out); - - } else { - - /* does this need to be done with MIDI? it appears not */ + } else if (out > in) { - uint32_t in = input_streams ().n_audio (); - uint32_t out = output_streams().n_audio (); + /* not active, but something has make up for any channel count increase */ - if (out > in) { - - /* not active, but something has make up for any channel count increase */ - - // TODO: option round-robin (n % in) or silence additional buffers ?? - for (uint32_t n = in; n < out; ++n) { - bufs.get_audio(n).read_from(bufs.get_audio(in - 1), nframes); - } + // TODO: option round-robin (n % in) or silence additional buffers ?? + // for now , simply replicate last buffer + for (uint32_t n = in; n < out; ++n) { + bufs.get_audio(n).read_from(bufs.get_audio(in - 1), nframes); } - - bufs.count().set_audio (out); } + + bufs.count().set_audio (out); } _active = _pending_active; diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc index 90522a7e06..df1b7fc441 100644 --- a/libs/ardour/plugin_manager.cc +++ b/libs/ardour/plugin_manager.cc @@ -646,7 +646,9 @@ PluginManager::lxvst_refresh () } if (lxvst_path.length() == 0) { - lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst"; + lxvst_path = "/usr/local/lib64/lxvst:/usr/local/lib/lxvst:/usr/lib64/lxvst:/usr/lib/lxvst:" + "/usr/local/lib64/linux_vst:/usr/local/lib/linux_vst:/usr/lib64/linux_vst:/usr/lib/linux_vst:" + "/usr/lib/vst:/usr/local/lib/vst"; } lxvst_discover_from_path (lxvst_path); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 9e649362ee..71af69fdee 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -419,6 +419,9 @@ Route::process_output_buffers (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick, bool gain_automation_ok) { + /* Caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK); assert(lm.locked()); @@ -1382,7 +1385,16 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream { // TODO once the export point can be configured properly, do something smarter here if (processor == _capturing_processor) { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock (), Glib::Threads::NOT_LOCK); + if (need_process_lock) { + lx.acquire(); + } + _capturing_processor.reset(); + + if (need_process_lock) { + lx.release(); + } } /* these can never be removed */ @@ -1402,7 +1414,12 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream if (need_process_lock) { lx.acquire(); } - Glib::Threads::RWLock::WriterLock lm (_processor_lock); + + /* Caller must hold process lock */ + assert (!AudioEngine::instance()->process_lock().trylock()); + + Glib::Threads::RWLock::WriterLock lm (_processor_lock); // XXX deadlock after export + ProcessorState pstate (this); ProcessorList::iterator i; @@ -3062,6 +3079,7 @@ Route::set_meter_point (MeterPoint p, bool force) bool meter_was_visible_to_user = _meter->display_to_user (); { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::RWLock::WriterLock lm (_processor_lock); maybe_note_meter_position (); @@ -3147,12 +3165,16 @@ Route::listen_position_changed () boost::shared_ptr<CapturingProcessor> Route::add_export_point() { + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); if (!_capturing_processor) { + lm.release(); + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + Glib::Threads::RWLock::WriterLock lw (_processor_lock); _capturing_processor.reset (new CapturingProcessor (_session)); _capturing_processor->activate (); - configure_processors (0); + configure_processors_unlocked (0); } @@ -4132,7 +4154,7 @@ Route::non_realtime_locate (framepos_t pos) { //Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - Glib::Threads::RWLock::WriterLock lm (_processor_lock); + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->transport_located (pos); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index f3ad9d66dd..ffbe55afbf 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -136,13 +136,21 @@ Session::pre_engine_init (string fullpath) /* discover canonical fullpath */ char buf[PATH_MAX+1]; - if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) { - error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg; - destroy (); - throw failed_constructor(); - } - _path = string(buf); + if (!realpath (fullpath.c_str(), buf)) { + if (errno == ENOENT) { + /* fullpath does not exist yet, so realpath() returned + * ENOENT. Just use it as-is + */ + _path = fullpath; + } else { + error << string_compose(_("Could not use path %1 (%2)"), buf, strerror(errno)) << endmsg; + destroy (); + throw failed_constructor(); + } + } else { + _path = string(buf); + } /* we require _path to end with a dir separator */ @@ -2692,19 +2700,23 @@ Session::cleanup_sources (CleanupReport& rep) ++tmp; if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) { - if (playlists->source_use_count (fs) != 0) { - all_sources.insert (fs->path()); - } else { - /* we might not remove this source from disk, because it may be used - by other snapshots, but its not being used in this version - so lets get rid of it now, along with any representative regions - in the region list. - */ + if (!fs->is_stub()) { - RegionFactory::remove_regions_using_source (i->second); - sources.erase (i); - } + if (playlists->source_use_count (fs) != 0) { + all_sources.insert (fs->path()); + } else { + + /* we might not remove this source from disk, because it may be used + by other snapshots, but its not being used in this version + so lets get rid of it now, along with any representative regions + in the region list. + */ + + RegionFactory::remove_regions_using_source (i->second); + sources.erase (i); + } + } } i = tmp; diff --git a/libs/evoral/evoral/ControlList.hpp b/libs/evoral/evoral/ControlList.hpp index 967e08d619..5f1a8d3a75 100644 --- a/libs/evoral/evoral/ControlList.hpp +++ b/libs/evoral/evoral/ControlList.hpp @@ -115,7 +115,7 @@ public: virtual bool clamp_value (double& /*when*/, double& /*value*/) const { return true; } - virtual void add (double when, double value); + virtual void add (double when, double value, bool with_guards=true); void fast_simple_add (double when, double value); void erase_range (double start, double end); diff --git a/libs/evoral/src/Control.cpp b/libs/evoral/src/Control.cpp index bb272ea8b3..480d027ccc 100644 --- a/libs/evoral/src/Control.cpp +++ b/libs/evoral/src/Control.cpp @@ -17,6 +17,9 @@ */ #include <iostream> + +#include "pbd/stacktrace.h" + #include "evoral/Control.hpp" #include "evoral/ControlList.hpp" @@ -49,9 +52,13 @@ void Control::set_double (double value, double frame, bool to_list) { _user_value = value; + + /* if we're in a write pass, the automation watcher will determine the + values and add them to the list, so we we don't need to bother. + */ - if (to_list) { - _list->add (frame, value); + if (to_list && !_list->in_write_pass()) { + _list->add (frame, value, false); } } diff --git a/libs/evoral/src/ControlList.cpp b/libs/evoral/src/ControlList.cpp index a095daa135..f34bfa3faf 100644 --- a/libs/evoral/src/ControlList.cpp +++ b/libs/evoral/src/ControlList.cpp @@ -342,21 +342,25 @@ ControlList::start_write_pass (double when) { Glib::Threads::Mutex::Lock lm (_lock); + DEBUG_TRACE (DEBUG::ControlList, string_compose ("%1: setup write pass @ %2\n", this, when)); + new_write_pass = true; did_write_during_pass = false; insert_position = when; - + /* leave the insert iterator invalid, so that we will do the lookup of where it should be in a "lazy" way - deferring it until we actually add the first point (which may never happen). */ - + unlocked_invalidate_insert_iterator (); } void ControlList::write_pass_finished (double /*when*/) { + DEBUG_TRACE (DEBUG::ControlList, "write pass finished\n"); + if (did_write_during_pass) { thin (); did_write_during_pass = false; @@ -367,7 +371,9 @@ ControlList::write_pass_finished (double /*when*/) void ControlList::set_in_write_pass (bool yn, bool add_point, double when) -{ +{ + DEBUG_TRACE (DEBUG::ControlList, string_compose ("now in write pass @ %1, add point ? %2\n", when, add_point)); + _in_write_pass = yn; if (yn && add_point) { @@ -381,8 +387,6 @@ ControlList::add_guard_point (double when) ControlEvent cp (when, 0.0); most_recent_insert_iterator = lower_bound (_events.begin(), _events.end(), &cp, time_comparator); - DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 ADD GUARD POINT @ %2looked up insert iterator for new write pass\n", this, when)); - double eval_value = unlocked_eval (insert_position); if (most_recent_insert_iterator == _events.end()) { @@ -437,7 +441,7 @@ ControlList::in_write_pass () const } void -ControlList::add (double when, double value) +ControlList::add (double when, double value, bool with_guards) { /* this is for making changes from some kind of user interface or control surface (GUI, MIDI, OSC etc) @@ -447,8 +451,8 @@ ControlList::add (double when, double value) return; } - DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 add %2 at %3 w/erase = %4 at end ? %5\n", - this, value, when, _in_write_pass, (most_recent_insert_iterator == _events.end()))); + DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 add %2 at %3 w/erase = %4 (new ? %6) at end ? %5\n", + this, value, when, _in_write_pass, (most_recent_insert_iterator == _events.end()), new_write_pass)); { Glib::Threads::Mutex::Lock lm (_lock); ControlEvent cp (when, 0.0f); @@ -460,7 +464,7 @@ ControlList::add (double when, double value) * add an "anchor" point there. */ - if (when > 1) { + if (when >= 1) { _events.insert (_events.end(), new ControlEvent (0, _default_value)); DEBUG_TRACE (DEBUG::ControlList, string_compose ("@%1 added default value %2 at zero\n", this, _default_value)); } @@ -468,8 +472,10 @@ ControlList::add (double when, double value) if (_in_write_pass && new_write_pass) { - add_guard_point (insert_position); - did_write_during_pass = true; + if (with_guards) { + add_guard_point (insert_position); + did_write_during_pass = true; + } } else if (most_recent_insert_iterator == _events.end() || when > (*most_recent_insert_iterator)->when) { @@ -492,7 +498,7 @@ ControlList::add (double when, double value) ++most_recent_insert_iterator; } - if (most_recent_insert_iterator != _events.end()) { + if (with_guards && most_recent_insert_iterator != _events.end()) { if ((*most_recent_insert_iterator)->when - when > 64) { /* next control point is some * distance from where our new @@ -631,7 +637,7 @@ ControlList::add (double when, double value) } } - if (most_recent_insert_iterator != _events.end()) { + if (with_guards && most_recent_insert_iterator != _events.end()) { if ((*most_recent_insert_iterator)->when - when > 64) { /* next control point is some * distance from where our new @@ -1729,7 +1735,7 @@ ControlList::dump (ostream& o) /* NOT LOCKED ... for debugging only */ for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) { - o << (*x)->value << " @ " << (*x)->when << endl; + o << (*x)->value << " @ " << (uint64_t) (*x)->when << endl; } } diff --git a/libs/panners/vbap/vbap.cc b/libs/panners/vbap/vbap.cc index 8c1390832f..ea2d26fb31 100644 --- a/libs/panners/vbap/vbap.cc +++ b/libs/panners/vbap/vbap.cc @@ -403,7 +403,7 @@ VBAPanner::describe_parameter (Evoral::Parameter p) { switch (p.type()) { case PanAzimuthAutomation: - return _("Direction"); + return _("Azimuth"); case PanWidthAutomation: return _("Width"); case PanElevationAutomation: diff --git a/libs/panners/vbap/vbap_speakers.cc b/libs/panners/vbap/vbap_speakers.cc index 313fe7a5cd..4c662a8c6d 100644 --- a/libs/panners/vbap/vbap_speakers.cc +++ b/libs/panners/vbap/vbap_speakers.cc @@ -115,27 +115,36 @@ VBAPSpeakers::choose_speaker_triplets(struct ls_triplet_chain **ls_triplets) int i,j,k,l,table_size; int n_speakers = _speakers.size (); - int connections[n_speakers][n_speakers]; - float distance_table[((n_speakers * (n_speakers - 1)) / 2)]; - int distance_table_i[((n_speakers * (n_speakers - 1)) / 2)]; - int distance_table_j[((n_speakers * (n_speakers - 1)) / 2)]; - float distance; - struct ls_triplet_chain *trip_ptr, *prev, *tmp_ptr; if (n_speakers == 0) { return; } + /* variable length arrays arrived in C99, became optional in C11, and + are only planned for C++14. Use alloca which is functionally + identical (but uglier to read). + */ + int* connections = (int*) alloca (sizeof (int) * n_speakers * n_speakers); + float* distance_table = (float *) alloca (sizeof (float) * ((n_speakers * (n_speakers - 1)) / 2)); + int* distance_table_i = (int *) alloca (sizeof (int) * ((n_speakers * (n_speakers - 1)) / 2)); + int* distance_table_j = (int *) alloca (sizeof (int) * ((n_speakers * (n_speakers - 1)) / 2)); + float distance; + struct ls_triplet_chain *trip_ptr, *prev, *tmp_ptr; + + for (i = 0; i < n_speakers * n_speakers; i++) { + connections[i] = 0; + } + for (i = 0; i < n_speakers; i++) { for (j = i+1; j < n_speakers; j++) { for(k = j+1; k < n_speakers; k++) { if (vol_p_side_lgth(i, j, k, _speakers) > MIN_VOL_P_SIDE_LGTH) { - connections[i][j]=1; - connections[j][i]=1; - connections[i][k]=1; - connections[k][i]=1; - connections[j][k]=1; - connections[k][j]=1; + connections[(i*n_speakers)+j]=1; + connections[(j*n_speakers)+i]=1; + connections[(i*n_speakers)+k]=1; + connections[(k*n_speakers)+i]=1; + connections[(j*n_speakers)+k]=1; + connections[(k*n_speakers)+j]=1; add_ldsp_triplet(i,j,k,ls_triplets); } } @@ -150,7 +159,7 @@ VBAPSpeakers::choose_speaker_triplets(struct ls_triplet_chain **ls_triplets) for (i = 0;i < n_speakers; i++) { for (j = i+1; j < n_speakers; j++) { - if (connections[i][j] == 1) { + if (connections[(i*n_speakers)+j] == 1) { distance = fabs(vec_angle(_speakers[i].coords(),_speakers[j].coords())); k=0; while(distance_table[k] < distance) { @@ -175,13 +184,13 @@ VBAPSpeakers::choose_speaker_triplets(struct ls_triplet_chain **ls_triplets) for (i = 0; i < table_size; i++) { int fst_ls = distance_table_i[i]; int sec_ls = distance_table_j[i]; - if (connections[fst_ls][sec_ls] == 1) { + if (connections[(fst_ls*n_speakers)+sec_ls] == 1) { for (j = 0; j < n_speakers; j++) { for (k = j+1; k < n_speakers; k++) { if ((j != fst_ls) && (k != sec_ls) && (k != fst_ls) && (j != sec_ls)) { if (lines_intersect(fst_ls, sec_ls, j, k) == 1){ - connections[j][k] = 0; - connections[k][j] = 0; + connections[(j*n_speakers)+k] = 0; + connections[(k*n_speakers)+j] = 0; } } } @@ -197,9 +206,9 @@ VBAPSpeakers::choose_speaker_triplets(struct ls_triplet_chain **ls_triplets) i = trip_ptr->ls_nos[0]; j = trip_ptr->ls_nos[1]; k = trip_ptr->ls_nos[2]; - if (connections[i][j] == 0 || - connections[i][k] == 0 || - connections[j][k] == 0 || + if (connections[(i*n_speakers)+j] == 0 || + connections[(i*n_speakers)+k] == 0 || + connections[(j*n_speakers)+k] == 0 || any_ls_inside_triplet(i,j,k) == 1 ){ if (prev != 0) { prev->next = trip_ptr->next; @@ -526,19 +535,23 @@ VBAPSpeakers::choose_speaker_pairs (){ matrices and stores the data to a global array */ const int n_speakers = _speakers.size(); - const double AZIMUTH_DELTA_THRESHOLD_DEGREES = (180.0/M_PI) * (M_PI - 0.175); - int sorted_speakers[n_speakers]; - bool exists[n_speakers]; - double inverse_matrix[n_speakers][4]; - int expected_pairs = 0; - int pair; - int speaker; - if (n_speakers == 0) { return; } + const double AZIMUTH_DELTA_THRESHOLD_DEGREES = (180.0/M_PI) * (M_PI - 0.175); + /* variable length arrays arrived in C99, became optional in C11, and + are only planned for C++14. Use alloca which is functionally + identical (but uglier to read). + */ + int* sorted_speakers = (int*) alloca (sizeof (int) * n_speakers); + bool* exists = (bool*) alloca (sizeof(bool) * n_speakers); + double* inverse_matrix = (double*) alloca (sizeof (double) * n_speakers * 4); + int expected_pairs = 0; + int pair; + int speaker; + for (speaker = 0; speaker < n_speakers; ++speaker) { exists[speaker] = false; } @@ -553,7 +566,7 @@ VBAPSpeakers::choose_speaker_pairs (){ _speakers[sorted_speakers[speaker]].angles().azi) <= AZIMUTH_DELTA_THRESHOLD_DEGREES) { if (calc_2D_inv_tmatrix( _speakers[sorted_speakers[speaker]].angles().azi, _speakers[sorted_speakers[speaker+1]].angles().azi, - inverse_matrix[speaker]) != 0){ + &inverse_matrix[4 * speaker]) != 0){ exists[speaker] = true; expected_pairs++; } @@ -564,7 +577,7 @@ VBAPSpeakers::choose_speaker_pairs (){ +_speakers[sorted_speakers[0]].angles().azi) <= AZIMUTH_DELTA_THRESHOLD_DEGREES) { if (calc_2D_inv_tmatrix(_speakers[sorted_speakers[n_speakers-1]].angles().azi, _speakers[sorted_speakers[0]].angles().azi, - inverse_matrix[n_speakers-1]) != 0) { + &inverse_matrix[4*(n_speakers-1)]) != 0) { exists[n_speakers-1] = true; expected_pairs++; } @@ -582,10 +595,10 @@ VBAPSpeakers::choose_speaker_pairs (){ for (speaker = 0; speaker < n_speakers - 1; speaker++) { if (exists[speaker]) { - _matrices[pair][0] = inverse_matrix[speaker][0]; - _matrices[pair][1] = inverse_matrix[speaker][1]; - _matrices[pair][2] = inverse_matrix[speaker][2]; - _matrices[pair][3] = inverse_matrix[speaker][3]; + _matrices[pair][0] = inverse_matrix[(speaker*4)+0]; + _matrices[pair][1] = inverse_matrix[(speaker*4)+1]; + _matrices[pair][2] = inverse_matrix[(speaker*4)+2]; + _matrices[pair][3] = inverse_matrix[(speaker*4)+3]; _speaker_tuples[pair][0] = sorted_speakers[speaker]; _speaker_tuples[pair][1] = sorted_speakers[speaker+1]; @@ -595,10 +608,10 @@ VBAPSpeakers::choose_speaker_pairs (){ } if (exists[n_speakers-1]) { - _matrices[pair][0] = inverse_matrix[speaker][0]; - _matrices[pair][1] = inverse_matrix[speaker][1]; - _matrices[pair][2] = inverse_matrix[speaker][2]; - _matrices[pair][3] = inverse_matrix[speaker][3]; + _matrices[pair][0] = inverse_matrix[(speaker*4)+0]; + _matrices[pair][1] = inverse_matrix[(speaker*4)+1]; + _matrices[pair][2] = inverse_matrix[(speaker*4)+2]; + _matrices[pair][3] = inverse_matrix[(speaker*4)+3]; _speaker_tuples[pair][0] = sorted_speakers[n_speakers-1]; _speaker_tuples[pair][1] = sorted_speakers[0]; diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index e9bef5a9b0..fc1491d9e8 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -345,7 +345,9 @@ MackieControlProtocol::switch_banks (uint32_t initial, bool force) if (_current_initial_bank <= sorted.size()) { - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available routes %3\n", _current_initial_bank, strip_cnt, sorted.size())); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2, available routes %3 on %4 surfaces\n", + _current_initial_bank, strip_cnt, sorted.size(), + surfaces.size())); // link routes to strips @@ -521,11 +523,23 @@ MackieControlProtocol::update_global_led (int id, LedState ls) } } +void +MackieControlProtocol::device_ready () +{ + /* this is not required to be called, but for devices which do + * handshaking, it can be called once the device has verified the + * connection. + */ + + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device ready init (active=%1)\n", active())); + update_surfaces (); +} + // send messages to surface to set controls to correct values void MackieControlProtocol::update_surfaces() { - DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::update_surfaces() init\n"); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::update_surfaces() init (active=%1)\n", active())); if (!active()) { return; } diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index e1a71a2460..fc965d868b 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -119,6 +119,8 @@ class MackieControlProtocol const Mackie::DeviceInfo& device_info() const { return _device_info; } Mackie::DeviceProfile& device_profile() { return _device_profile; } + void device_ready (); + int set_active (bool yn); int set_device (const std::string&); void set_profile (const std::string&); diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc index ef4447d900..1893e31b8d 100644 --- a/libs/surfaces/mackie/strip.cc +++ b/libs/surfaces/mackie/strip.cc @@ -627,12 +627,21 @@ Strip::do_parameter_display (AutomationType type, float val) } void +Strip::handle_fader_touch (Fader& fader, bool touch_on) +{ + if (touch_on) { + fader.start_touch (_surface->mcp().transport_frame()); + } else { + fader.stop_touch (_surface->mcp().transport_frame(), false); + } +} + +void Strip::handle_fader (Fader& fader, float position) { DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader to %1\n", position)); fader.set_value (position); - fader.start_touch (_surface->mcp().transport_frame()); queue_display_reset (2000); // must echo bytes back to slider now, because diff --git a/libs/surfaces/mackie/strip.h b/libs/surfaces/mackie/strip.h index 225783d0fe..c330e0e54d 100644 --- a/libs/surfaces/mackie/strip.h +++ b/libs/surfaces/mackie/strip.h @@ -61,6 +61,7 @@ public: void handle_button (Button&, ButtonState bs); void handle_fader (Fader&, float position); + void handle_fader_touch (Fader&, bool touch_on); void handle_pot (Pot&, float delta); void periodic (uint64_t now_usecs); diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 694c73b1bc..09c5fff051 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -369,7 +369,7 @@ Surface::connect_to_signals () p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2)); /* Button messages are NoteOn */ p->note_on.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2)); - /* Button messages are NoteOn. libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */ + /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */ p->note_off.connect_same_thread (*this, boost::bind (&Surface::handle_midi_note_on_message, this, _1, _2)); /* Fader messages are Pitchbend */ uint32_t i; @@ -386,7 +386,7 @@ Surface::connect_to_signals () void Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uint32_t fader_id) { - /* Pitchbend messages are fader messages. Nothing in the data we get + /* Pitchbend messages are fader position messages. Nothing in the data we get * from the MIDI::Parser conveys the fader ID, which was given by the * channel ID in the status byte. * @@ -394,7 +394,6 @@ Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uin * when we connected to the per-channel pitchbend events. */ - DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_pitchbend_message on port %3, fader = %1 value = %2\n", fader_id, pb, _number)); @@ -429,6 +428,28 @@ Surface::handle_midi_note_on_message (MIDI::Parser &, MIDI::EventTwoBytes* ev) turn_it_on (); } + /* fader touch sense is given by "buttons" 0xe..0xe7 and 0xe8 for the + * master. + */ + + if (ev->note_number >= 0xE0 && ev->note_number <= 0xE8) { + Fader* fader = faders[ev->note_number]; + + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface: fader touch message, fader = %1\n", fader)); + + if (fader) { + + Strip* strip = dynamic_cast<Strip*> (&fader->group()); + + if (ev->velocity > 64) { + strip->handle_fader_touch (*fader, true); + } else { + strip->handle_fader_touch (*fader, false); + } + } + return; + } + Button* button = buttons[ev->note_number]; if (button) { @@ -516,8 +537,10 @@ Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count LCP: Connection Challenge */ if (bytes[4] == 0x10 || bytes[4] == 0x11) { + DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device connection challenge\n"); write_sysex (host_connection_query (bytes)); } else { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mackie Control Device ready, current status = %1\n", _active)); if (!_active) { turn_it_on (); } @@ -525,6 +548,7 @@ Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count break; case 0x03: /* LCP Connection Confirmation */ + DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device confirms connection, ardour replies\n"); if (bytes[4] == 0x10 || bytes[4] == 0x11) { write_sysex (host_connection_confirmation (bytes)); _active = true; @@ -532,6 +556,7 @@ Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count break; case 0x04: /* LCP: Confirmation Denied */ + DEBUG_TRACE (DEBUG::MackieControl, "Logic Control Device denies connection\n"); _active = false; break; default: @@ -610,6 +635,8 @@ Surface::turn_it_on () _active = true; + _mcp.device_ready (); + for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) { (*s)->notify_all (); } @@ -739,6 +766,8 @@ Surface::map_routes (const vector<boost::shared_ptr<Route> >& routes) vector<boost::shared_ptr<Route> >::const_iterator r; Strips::iterator s = strips.begin(); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Mapping %1 routes", routes.size())); + for (r = routes.begin(); r != routes.end() && s != strips.end(); ++s) { /* don't try to assign routes to a locked strip. it won't |