summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audio_port.h12
-rw-r--r--libs/ardour/ardour/port.h22
-rw-r--r--libs/ardour/ardour/session.h7
-rw-r--r--libs/ardour/audio_port.cc69
-rw-r--r--libs/ardour/audioengine.cc23
-rw-r--r--libs/ardour/midi_port.cc19
-rw-r--r--libs/ardour/port.cc55
-rw-r--r--libs/ardour/port_manager.cc3
-rw-r--r--libs/ardour/session.cc1
-rw-r--r--libs/ardour/wscript1
10 files changed, 185 insertions, 27 deletions
diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h
index 384de3ef5d..4224a88d55 100644
--- a/libs/ardour/ardour/audio_port.h
+++ b/libs/ardour/ardour/audio_port.h
@@ -21,6 +21,8 @@
#ifndef __ardour_audio_port_h__
#define __ardour_audio_port_h__
+#include "zita-resampler/vmresampler.h"
+
#include "ardour/port.h"
#include "ardour/audio_buffer.h"
@@ -49,12 +51,14 @@ class LIBARDOUR_API AudioPort : public Port
friend class PortManager;
AudioPort (std::string const &, PortFlags);
- /* special access for PortManager only (hah, C++) */
- Sample* engine_get_whole_audio_buffer ();
+ /* special access for PortManager only (hah, C++) */
+ Sample* engine_get_whole_audio_buffer ();
private:
- AudioBuffer* _buffer;
- bool _buf_valid;
+ AudioBuffer* _buffer;
+ ArdourZita::VMResampler _src;
+ Sample* _data;
+ bool _buf_valid;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index e59df0cb03..18d56dd8df 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -106,7 +106,7 @@ public:
void set_private_latency_range (LatencyRange& range, bool playback);
const LatencyRange& private_latency_range (bool playback) const;
- void set_public_latency_range (LatencyRange& range, bool playback) const;
+ void set_public_latency_range (LatencyRange const& range, bool playback) const;
LatencyRange public_latency_range (bool playback) const;
virtual void reset ();
@@ -121,15 +121,16 @@ public:
virtual void realtime_locate () {}
bool physically_connected () const;
+ bool externally_connected () const;
PBD::Signal1<void,bool> MonitorInputChanged;
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
static PBD::Signal0<void> PortDrop;
static PBD::Signal0<void> PortSignalDrop;
- static void set_cycle_samplecnt (pframes_t n) {
- _cycle_nframes = n;
- }
+ static void set_speed_ratio (double s);
+ static void set_cycle_samplecnt (pframes_t n);
+
static samplecnt_t port_offset() { return _global_port_buffer_offset; }
static void set_global_port_buffer_offset (pframes_t off) {
_global_port_buffer_offset = off;
@@ -145,21 +146,26 @@ public:
static std::string state_node_name;
+ static pframes_t cycle_nframes () { return _cycle_nframes; }
+
protected:
Port (std::string const &, DataType, PortFlags);
- PortEngine::PortHandle _port_handle;
+ PortEngine::PortHandle _port_handle;
- static bool _connecting_blocked;
- static pframes_t _global_port_buffer_offset; /* access only from process() tree */
+ static bool _connecting_blocked;
static pframes_t _cycle_nframes; /* access only from process() tree */
- samplecnt_t _port_buffer_offset; /* access only from process() tree */
+ static pframes_t _global_port_buffer_offset; /* access only from process() tree */
+ samplecnt_t _port_buffer_offset; /* access only from process() tree */
LatencyRange _private_playback_latency;
LatencyRange _private_capture_latency;
+ static double _speed_ratio;
+ static const uint32_t _resampler_quality; /* also latency of the resampler */
+
private:
std::string _name; ///< port short name
PortFlags _flags; ///< flags
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index db3f345db6..b0e133f4c6 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -728,6 +728,12 @@ public:
bool synced_to_mtc () const { return config.get_external_sync() && Config->get_sync_source() == MTC && g_atomic_int_get (const_cast<gint*>(&_mtc_active)); }
bool synced_to_ltc () const { return config.get_external_sync() && Config->get_sync_source() == LTC && g_atomic_int_get (const_cast<gint*>(&_ltc_active)); }
+ double engine_speed() const { return _engine_speed; }
+ double actual_speed() const {
+ if (_transport_speed > 0) return _engine_speed;
+ if (_transport_speed < 0) return - _engine_speed;
+ return 0;
+ }
double transport_speed() const { return _count_in_samples > 0 ? 0. : _transport_speed; }
bool transport_stopped() const { return _transport_speed == 0.0; }
bool transport_rolling() const { return _transport_speed != 0.0 && _count_in_samples == 0 && _remaining_latency_preroll == 0; }
@@ -1255,6 +1261,7 @@ private:
samplecnt_t _remaining_latency_preroll;
// varispeed playback
+ double _engine_speed;
double _transport_speed;
double _default_transport_speed;
double _last_transport_speed;
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
index 70943e35a3..a9d41afce2 100644
--- a/libs/ardour/audio_port.cc
+++ b/libs/ardour/audio_port.cc
@@ -18,6 +18,7 @@
#include <cassert>
+#include "pbd/malign.h"
#include "pbd/stacktrace.h"
#include "ardour/audio_buffer.h"
@@ -36,10 +37,14 @@ AudioPort::AudioPort (const std::string& name, PortFlags flags)
, _buffer (new AudioBuffer (0))
{
assert (name.find_first_of (':') == string::npos);
+ cache_aligned_malloc ((void**) &_data, sizeof (Sample) * 8192);
+ _src.setup (_resampler_quality);
+ _src.set_rrfilt (10);
}
AudioPort::~AudioPort ()
{
+ cache_aligned_free (_data);
delete _buffer;
}
@@ -47,11 +52,32 @@ void
AudioPort::cycle_start (pframes_t nframes)
{
/* caller must hold process lock */
-
- Port::cycle_start (nframes);
+ Port::cycle_start (nframes);
if (sends_output()) {
_buffer->prepare ();
+ } else if (!externally_connected ()) {
+ /* ardour internal port, just silence input, don't resample */
+ // TODO reset resampler only once
+ _src.reset ();
+ memset (_data, 0, _cycle_nframes * sizeof (float));
+ } else {
+ _src.inp_data = (float*)port_engine.get_buffer (_port_handle, nframes);
+ _src.inp_count = nframes;
+ _src.out_count = _cycle_nframes;
+ _src.set_rratio (_cycle_nframes / (double)nframes);
+ _src.out_data = _data;
+ _src.process ();
+#ifndef NDEBUG
+ if (_src.inp_count != 0 || _src.out_count != 0) {
+ printf ("AudioPort::cycle_start x-flow: %d/%d\n", _src.inp_count, _src.out_count);
+ }
+#endif
+ while (_src.out_count > 0) {
+ *_src.out_data = _src.out_data[-1];
+ ++_src.out_data;
+ --_src.out_count;
+ }
}
}
@@ -66,6 +92,33 @@ AudioPort::cycle_end (pframes_t nframes)
_buffer->silence (nframes);
}
}
+
+ if (sends_output() && _port_handle) {
+
+ if (!externally_connected ()) {
+ /* ardour internal port, data goes nowhere, skip resampling */
+ // TODO reset resampler only once
+ _src.reset ();
+ return;
+ }
+
+ _src.inp_count = _cycle_nframes;
+ _src.out_count = nframes;
+ _src.set_rratio (nframes / (double)_cycle_nframes);
+ _src.inp_data = _data;
+ _src.out_data = (float*)port_engine.get_buffer (_port_handle, nframes);
+ _src.process ();
+#ifndef NDEBUG
+ if (_src.inp_count != 0 || _src.out_count != 0) {
+ printf ("AudioPort::cycle_end x-flow: %d/%d\n", _src.inp_count, _src.out_count);
+ }
+#endif
+ while (_src.out_count > 0) {
+ *_src.out_data = _src.out_data[-1];
+ ++_src.out_data;
+ --_src.out_count;
+ }
+ }
}
void
@@ -78,8 +131,12 @@ AudioPort::get_audio_buffer (pframes_t nframes)
{
/* caller must hold process lock */
assert (_port_handle);
- _buffer->set_data ((Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes) +
- _global_port_buffer_offset + _port_buffer_offset, nframes);
+ if (!externally_connected ()) {
+ _buffer->set_data ((Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes) +
+ _global_port_buffer_offset + _port_buffer_offset, nframes);
+ } else {
+ _buffer->set_data (&_data[_global_port_buffer_offset + _port_buffer_offset], nframes);
+ }
return *_buffer;
}
@@ -90,7 +147,3 @@ AudioPort::engine_get_whole_audio_buffer ()
assert (_port_handle);
return (Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes);
}
-
-
-
-
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 03c13e38fd..da512cc51d 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -190,6 +190,7 @@ int
AudioEngine::process_callback (pframes_t nframes)
{
Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
+ Port::set_speed_ratio (1.0);
PT_TIMING_REF;
PT_TIMING_CHECK (1);
@@ -357,6 +358,14 @@ AudioEngine::process_callback (pframes_t nframes)
return 0;
}
+ if (!_freewheeling || Freewheel.empty()) {
+ // run a list of slaves here
+ // - multiple slaves (ow_many_dsp_threads() in paralell)
+ // - session can pick one (ask for position & speed)
+ // - GUI can display all
+ Port::set_speed_ratio (_session->engine_speed ());
+ }
+
/* tell all relevant objects that we're starting a new cycle */
InternalSend::CycleStart (nframes);
@@ -373,7 +382,19 @@ AudioEngine::process_callback (pframes_t nframes)
if (_freewheeling && !Freewheel.empty()) {
Freewheel (nframes);
} else {
- _session->process (nframes);
+ if (Port::cycle_nframes () <= nframes) {
+ _session->process (Port::cycle_nframes ());
+ } else {
+ pframes_t remain = Port::cycle_nframes ();
+ while (remain > 0) {
+ pframes_t nf = std::min (remain, nframes);
+ _session->process (nf);
+ remain -= nf;
+ if (remain > 0) {
+ split_cycle (nf);
+ }
+ }
+ }
}
if (_freewheeling) {
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index a6553b7fb6..24dc994535 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -138,9 +138,15 @@ MidiPort::get_midi_buffer (pframes_t nframes)
continue;
}
+ timestamp = floor (timestamp * _speed_ratio);
+
/* check that the event is in the acceptable time range */
if ((timestamp < (_global_port_buffer_offset + _port_buffer_offset)) ||
(timestamp >= (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
+ // XXX this is normal after a split cycles:
+ // The engine buffer contains the data for the complete cycle, but
+ // only the part after _global_port_buffer_offset is needed.
+#ifndef NDEBUG
cerr << "Dropping incoming MIDI at time " << timestamp << "; offset="
<< _global_port_buffer_offset << " limit="
<< (_global_port_buffer_offset + _port_buffer_offset + nframes)
@@ -148,9 +154,14 @@ MidiPort::get_midi_buffer (pframes_t nframes)
<< " + " << _port_buffer_offset
<< " + " << nframes
<< ")\n";
+#endif
continue;
}
+ /* adjust timestamp to match current cycle */
+ timestamp -= _global_port_buffer_offset + _port_buffer_offset;
+ assert (timestamp >= 0 && timestamp < nframes);
+
if ((buf[0] & 0xF0) == 0x90 && buf[2] == 0) {
/* normalize note on with velocity 0 to proper note off */
uint8_t ev[3];
@@ -196,19 +207,20 @@ MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when)
for (uint8_t channel = 0; channel <= 0xF; channel++) {
uint8_t ev[3] = { ((uint8_t) (MIDI_CMD_CONTROL | channel)), MIDI_CTL_SUSTAIN, 0 };
+ pframes_t tme = floor (when / _speed_ratio);
/* we need to send all notes off AND turn the
* sustain/damper pedal off to handle synths
* that prioritize sustain over AllNotesOff
*/
- if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
+ if (port_engine.midi_event_put (port_buffer, tme, ev, 3) != 0) {
cerr << "failed to deliver sustain-zero on channel " << (int)channel << " on port " << name() << endl;
}
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
- if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
+ if (port_engine.midi_event_put (port_buffer, tme, ev, 3) != 0) {
cerr << "failed to deliver ALL NOTES OFF on channel " << (int)channel << " on port " << name() << endl;
}
}
@@ -279,7 +291,8 @@ MidiPort::flush_buffers (pframes_t nframes)
assert (ev.time() < (nframes + _global_port_buffer_offset));
if (ev.time() >= _global_port_buffer_offset) {
- if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time() + _port_buffer_offset, ev.buffer(), ev.size()) != 0) {
+ pframes_t tme = floor ((ev.time() + _port_buffer_offset) / _speed_ratio);
+ if (port_engine.midi_event_put (port_buffer, tme, ev.buffer(), ev.size()) != 0) {
cerr << "write failed, dropped event, time "
<< ev.time() << " + " << _port_buffer_offset
<< " > " << _global_port_buffer_offset << endl;
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index 81290aa021..b469194ea5 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -43,7 +43,9 @@ PBD::Signal0<void> Port::PortSignalDrop;
bool Port::_connecting_blocked = false;
pframes_t Port::_global_port_buffer_offset = 0;
pframes_t Port::_cycle_nframes = 0;
+double Port::_speed_ratio = 1.0;
std::string Port::state_node_name = X_("Port");
+const uint32_t Port::_resampler_quality = 12;
/* a handy define to shorten what would otherwise be a needlessly verbose
* repeated phrase
@@ -350,7 +352,7 @@ Port::increment_port_buffer_offset (pframes_t nframes)
}
void
-Port::set_public_latency_range (LatencyRange& range, bool playback) const
+Port::set_public_latency_range (LatencyRange const& range, bool playback) const
{
/* this sets the visible latency that the rest of the port system
sees. because we do latency compensation, all (most) of our visible
@@ -363,7 +365,16 @@ Port::set_public_latency_range (LatencyRange& range, bool playback) const
(playback ? "PLAYBACK" : "CAPTURE")));;
if (_port_handle) {
- port_engine.set_latency_range (_port_handle, playback, range);
+ LatencyRange r (range);
+ if (externally_connected ()) {
+#if 0
+ r.min *= _speed_ratio;
+ r.max *= _speed_ratio;
+#endif
+ r.min += (_resampler_quality - 1);
+ r.max += (_resampler_quality - 1);
+ }
+ port_engine.set_latency_range (_port_handle, playback, r);
}
}
@@ -419,6 +430,14 @@ Port::public_latency_range (bool /*playback*/) const
if (_port_handle) {
r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
+ if (externally_connected ()) {
+#if 0
+ r.min /= _speed_ratio;
+ r.max /= _speed_ratio;
+#endif
+ r.min += (_resampler_quality - 1);
+ r.max += (_resampler_quality - 1);
+ }
DEBUG_TRACE (DEBUG::Latency, string_compose (
"GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
@@ -458,6 +477,14 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const
if (remote_port) {
lr = port_engine.get_latency_range (remote_port, playback);
+ if (externally_connected ()) {
+#if 0
+ lr.min /= _speed_ratio;
+ lr.max /= _speed_ratio;
+#endif
+ lr.min += (_resampler_quality - 1);
+ lr.max += (_resampler_quality - 1);
+ }
DEBUG_TRACE (DEBUG::Latency, string_compose (
"\t%1 <-> %2 : latter has latency range %3 .. %4\n",
@@ -564,6 +591,19 @@ Port::physically_connected () const
return port_engine.physically_connected (_port_handle);
}
+bool
+Port::externally_connected () const
+{
+ if (!_port_handle) {
+ return false;
+ }
+
+ // TODO: When used with JACK, check if this port
+ // is connected to any non-ardour ports.
+
+ return port_engine.physically_connected (_port_handle);
+}
+
XMLNode&
Port::get_state () const
{
@@ -621,3 +661,14 @@ Port::set_state (const XMLNode& node, int)
return 0;
}
+
+/*static*/ void
+Port::set_speed_ratio (double s) {
+ /* see VMResampler::set_rratio() for min/max range */
+ _speed_ratio = std::min (16.0, std::max (0.5, s));
+}
+
+/*static*/ void
+Port::set_cycle_samplecnt (pframes_t n) {
+ _cycle_nframes = floor (n * _speed_ratio);
+}
diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc
index dfc1c64421..6d3336cabb 100644
--- a/libs/ardour/port_manager.cc
+++ b/libs/ardour/port_manager.cc
@@ -749,10 +749,11 @@ void
PortManager::cycle_start (pframes_t nframes)
{
Port::set_global_port_buffer_offset (0);
- Port::set_cycle_samplecnt (nframes);
+ Port::set_cycle_samplecnt (nframes);
_cycle_ports = ports.reader ();
+ // TODO parallelize
for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) {
p->second->cycle_start (nframes);
}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index aad0fefdd9..0bfc5d97ca 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -187,6 +187,7 @@ Session::Session (AudioEngine &eng,
, _slave (0)
, _silent (false)
, _remaining_latency_preroll (0)
+ , _engine_speed (1.0)
, _transport_speed (0)
, _default_transport_speed (1.0)
, _last_transport_speed (0)
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index df28255d5e..1604803884 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -396,6 +396,7 @@ def build(bld):
'libaudiographer',
'libtemporal',
'liblua',
+ 'zita-resampler',
]
if bld.env['build_target'] != 'mingw':
obj.uselib += ['DL']