#include <sys/time.h>
#include <regex.h>
+#include <glibmm.h>
+
#include "dummy_audiobackend.h"
+
#include "pbd/error.h"
+#include "ardour/port_manager.h"
#include "i18n.h"
using namespace ARDOUR;
static std::string s_instance_name;
size_t DummyAudioBackend::_max_buffer_size = 8192;
-DummyAudioBackend::DummyAudioBackend (AudioEngine& e)
- : AudioBackend (e)
+DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
+ : AudioBackend (e, info)
, _running (false)
, _freewheeling (false)
, _samplerate (48000)
, _dsp_load (0)
, _n_inputs (0)
, _n_outputs (0)
+ , _n_midi_inputs (0)
+ , _n_midi_outputs (0)
, _systemic_input_latency (0)
, _systemic_output_latency (0)
, _processed_samples (0)
+ , _port_change_flag (false)
{
_instance_name = s_instance_name;
+ pthread_mutex_init (&_port_callback_mutex, 0);
}
DummyAudioBackend::~DummyAudioBackend ()
{
+ pthread_mutex_destroy (&_port_callback_mutex);
}
/* AUDIOBACKEND API */
DummyAudioBackend::enumerate_midi_options () const
{
std::vector<std::string> m;
- m.push_back (_("None"));
+ m.push_back (_("1 in, 1 out"));
+ m.push_back (_("2 in, 2 out"));
+ m.push_back (_("8 in, 8 out"));
return m;
}
int
-DummyAudioBackend::set_midi_option (const std::string&)
+DummyAudioBackend::set_midi_option (const std::string& opt)
{
- return -1;
+ if (opt == _("1 in, 1 out")) {
+ _n_midi_inputs = _n_midi_outputs = 1;
+ }
+ else if (opt == _("2 in, 2 out")) {
+ _n_midi_inputs = _n_midi_outputs = 2;
+ }
+ else if (opt == _("8 in, 8 out")) {
+ _n_midi_inputs = _n_midi_outputs = 8;
+ }
+ else {
+ _n_midi_inputs = _n_midi_outputs = 0;
+ }
+ return 0;
}
std::string
DummyAudioBackend::midi_option () const
{
- return "";
+ return ""; // TODO
}
/* State Control */
return -1;
}
+ engine.sample_rate_change (_samplerate);
+ engine.buffer_size_change (_samples_per_period);
+
if (engine.reestablish_ports ()) {
PBD::error << _("DummyAudioBackend: Could not re-establish ports.") << endmsg;
stop ();
}
engine.reconnect_ports ();
+ _port_change_flag = false;
if (pthread_create (&_main_thread, NULL, pthread_process, this)) {
PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
}
int timeout = 5000;
- while (!_running && --timeout > 0) { usleep (1000); }
+ while (!_running && --timeout > 0) { Glib::usleep (1000); }
if (timeout == 0 || !_running) {
PBD::error << _("DummyAudioBackend: failed to start process thread.") << endmsg;
{
void *status;
if (!_running) {
- return -1;
+ return 0;
}
_running = false;
{
switch (t) {
case DataType::AUDIO:
- return _max_buffer_size * sizeof(Sample);
+ return _samples_per_period * sizeof(Sample);
case DataType::MIDI:
return _max_buffer_size; // XXX not really limited
}
if (pthread_create (&thread_id, &attr, dummy_process_thread, td)) {
PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
+ pthread_attr_destroy (&attr);
return -1;
}
+ pthread_attr_destroy (&attr);
_threads.push_back (thread_id);
return 0;
{
for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
{
-#ifdef COMPILER_MINGW
- if (*i == GetCurrentThread ()) {
- return true;
- }
-#else // pthreads
if (pthread_equal (*i, pthread_self ()) != 0) {
return true;
}
-#endif
}
return false;
}
void
DummyAudioBackend::update_latencies ()
{
+ // trigger latency callback in RT thread (locked graph)
+ port_connect_add_remove_callback();
}
/* PORTENGINE API */
DummyPort* port = NULL;
switch (type) {
case DataType::AUDIO:
- port = new DummyAudioPort (name, flags);
+ port = new DummyAudioPort (*this, name, flags);
break;
case DataType::MIDI:
- port = new DummyMidiPort (name, flags);
+ port = new DummyMidiPort (*this, name, flags);
break;
default:
PBD::error << _("DummyBackend::register_port: Invalid Data Type.") << endmsg;
const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
const int a_out = _n_outputs > 0 ? _n_outputs : 8;
- const int m_ins = 2; // TODO
- const int m_out = 2;
+ const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
+ const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
/* audio ports */
lr.min = lr.max = _samples_per_period + _systemic_input_latency;
snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
if (!p) return -1;
- set_latency_range (p, false, lr);
+ set_latency_range (p, true, lr);
}
/* midi ports */
snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
if (!p) return -1;
- set_latency_range (p, false, lr);
+ set_latency_range (p, true, lr);
}
-
return 0;
}
uint32_t
DummyAudioBackend::get_midi_event_count (void* port_buffer)
{
- assert (port_buffer && _running);
+ assert (port_buffer);
return static_cast<DummyMidiBuffer*>(port_buffer)->size ();
}
void
DummyAudioBackend::midi_clear (void* port_buffer)
{
- assert (port_buffer && _running);
+ assert (port_buffer);
DummyMidiBuffer * buf = static_cast<DummyMidiBuffer*>(port_buffer);
assert (buf);
buf->clear ();
{
for (size_t i = 0; i < _ports.size (); ++i) {
DummyPort* port = _ports[i];
- if ((port->type () == type) && port->is_output () && port->is_physical ()) {
+ if ((port->type () == type) && port->is_input () && port->is_physical ()) {
port_names.push_back (port->name ());
}
}
{
for (size_t i = 0; i < _ports.size (); ++i) {
DummyPort* port = _ports[i];
- if ((port->type () == type) && port->is_input () && port->is_physical ()) {
+ if ((port->type () == type) && port->is_output () && port->is_physical ()) {
port_names.push_back (port->name ());
}
}
void*
DummyAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
{
- assert (port && _running);
+ assert (port);
assert (valid_port (port));
return static_cast<DummyPort*>(port)->get_buffer (nframes);
}
_running = true;
_processed_samples = 0;
- struct timeval clock1, clock2;
- ::gettimeofday (&clock1, NULL);
+ manager.registration_callback();
+ manager.graph_order_callback();
+
+ uint64_t clock1, clock2;
+ clock1 = g_get_monotonic_time();
while (_running) {
if (engine.process_callback (_samples_per_period)) {
return 0;
}
_processed_samples += _samples_per_period;
if (!_freewheeling) {
- ::gettimeofday (&clock2, NULL);
- const int elapsed_time = (clock2.tv_sec - clock1.tv_sec) * 1000000 + (clock2.tv_usec - clock1.tv_usec);
- const int nomial_time = 1000000 * _samples_per_period / _samplerate;
+ clock2 = g_get_monotonic_time();
+ const int64_t elapsed_time = clock2 - clock1;
+ const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
_dsp_load = elapsed_time / (float) nomial_time;
if (elapsed_time < nomial_time) {
- ::usleep (nomial_time - elapsed_time);
+ Glib::usleep (nomial_time - elapsed_time);
} else {
- ::usleep (100); // don't hog cpu
+ Glib::usleep (100); // don't hog cpu
}
} else {
_dsp_load = 1.0;
- ::usleep (100); // don't hog cpu
+ Glib::usleep (100); // don't hog cpu
+ }
+ clock1 = g_get_monotonic_time();
+
+ bool connections_changed = false;
+ bool ports_changed = false;
+ if (!pthread_mutex_trylock (&_port_callback_mutex)) {
+ if (_port_change_flag) {
+ ports_changed = true;
+ _port_change_flag = false;
+ }
+ if (!_port_connection_queue.empty ()) {
+ connections_changed = true;
+ }
+ while (!_port_connection_queue.empty ()) {
+ PortConnectData *c = _port_connection_queue.back ();
+ manager.connect_callback (c->a, c->b, c->c);
+ _port_connection_queue.pop_back ();
+ delete c;
+ }
+ pthread_mutex_unlock (&_port_callback_mutex);
+ }
+ if (ports_changed) {
+ manager.registration_callback();
+ }
+ if (connections_changed) {
+ manager.graph_order_callback();
+ }
+ if (connections_changed || ports_changed) {
+ engine.latency_callback(false);
+ engine.latency_callback(true);
}
- ::gettimeofday (&clock1, NULL);
+
}
_running = false;
return 0;
static boost::shared_ptr<DummyAudioBackend> _instance;
+static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
+static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
+static int deinstantiate ();
+static bool already_configured ();
+
+static ARDOUR::AudioBackendInfo _descriptor = {
+ "Dummy",
+ instantiate,
+ deinstantiate,
+ backend_factory,
+ already_configured,
+};
+
static boost::shared_ptr<AudioBackend>
backend_factory (AudioEngine& e)
{
if (!_instance) {
- _instance.reset (new DummyAudioBackend (e));
+ _instance.reset (new DummyAudioBackend (e, _descriptor));
}
return _instance;
}
return false;
}
-static ARDOUR::AudioBackendInfo _descriptor = {
- "Dummy",
- instantiate,
- deinstantiate,
- backend_factory,
- already_configured,
-};
-
extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
{
return &_descriptor;
/******************************************************************************/
-DummyPort::DummyPort (const std::string& name, PortFlags flags)
- : _name (name)
+DummyPort::DummyPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
+ : _dummy_backend (b)
+ , _name (name)
, _flags (flags)
{
_capture_latency_range.min = 0;
_capture_latency_range.max = 0;
_playback_latency_range.min = 0;
_playback_latency_range.max = 0;
+ _dummy_backend.port_connect_add_remove_callback();
}
DummyPort::~DummyPort () {
disconnect_all ();
+ _dummy_backend.port_connect_add_remove_callback();
}
_connections.push_back (port);
if (callback) {
port->_connect (this, false);
+ _dummy_backend.port_connect_callback (name(), port->name(), true);
}
}
if (callback) {
port->_disconnect (this, false);
+ _dummy_backend.port_connect_callback (name(), port->name(), false);
}
}
{
while (!_connections.empty ()) {
_connections.back ()->_disconnect (this, false);
+ _dummy_backend.port_connect_callback (name(), _connections.back ()->name(), false);
_connections.pop_back ();
}
}
/******************************************************************************/
-DummyAudioPort::DummyAudioPort (const std::string& name, PortFlags flags)
- : DummyPort (name, flags)
+DummyAudioPort::DummyAudioPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
+ : DummyPort (b, name, flags)
{
memset (_buffer, 0, sizeof (_buffer));
}
}
-DummyMidiPort::DummyMidiPort (const std::string& name, PortFlags flags)
- : DummyPort (name, flags)
+DummyMidiPort::DummyMidiPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
+ : DummyPort (b, name, flags)
{
_buffer.clear ();
}
DummyMidiPort::~DummyMidiPort () { }
+struct MidiEventSorter {
+ bool operator() (const boost::shared_ptr<DummyMidiEvent>& a, const boost::shared_ptr<DummyMidiEvent>& b) {
+ return *a < *b;
+ }
+};
+
void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
{
if (is_input ()) {
_buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
}
}
- std::sort (_buffer.begin (), _buffer.end ());
+ std::sort (_buffer.begin (), _buffer.end (), MidiEventSorter());
} else if (is_output () && is_physical () && is_terminal()) {
_buffer.clear ();
}