new internal port type, round I, plus tiny fix for legalize_for_xml() (also for 2.0-ongoing)

git-svn-id: svn://localhost/ardour2/trunk@2559 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-10-17 16:49:31 +00:00
parent df28e90c67
commit 239ec39da6
18 changed files with 546 additions and 48 deletions

View file

@ -1694,7 +1694,7 @@ static string
legalize_for_xml_node (string str)
{
string::size_type pos;
string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
string legal;
legal = str;

View file

@ -65,6 +65,8 @@ gain.cc
gdither.cc
globals.cc
import.cc
internal_port.cc
internal_audio_port.cc
io.cc
io_processor.cc
jack_port.cc

View file

@ -102,6 +102,12 @@ public:
_silent = false;
}
/** Reallocate the buffer used internally to handle at least @nframes of data
*
* Constructor MUST have been passed capacity!=0 or this will die (to prevent mem leaks).
*/
void resize (size_t nframes);
const Sample* data () const { return _data; }
Sample* data () { return _data; }

View file

@ -35,11 +35,11 @@ class AudioPort : public virtual Port {
public:
DataType type() const { return DataType::AUDIO; }
Buffer& get_buffer () {
virtual Buffer& get_buffer () {
return _buffer;
}
AudioBuffer& get_audio_buffer() {
virtual AudioBuffer& get_audio_buffer() {
return _buffer;
}
@ -70,7 +70,8 @@ class AudioPort : public virtual Port {
protected:
friend class AudioEngine;
AudioPort ();
AudioPort (); // data buffer comes from elsewhere (e.g. JACK)
AudioPort (nframes_t); // data buffer owned by ardour
void reset ();
/* engine isn't supposed to access below here */

View file

@ -42,6 +42,7 @@ namespace ARDOUR {
class Session;
class Port;
class InternalPort;
class AudioEngine : public sigc::trackable
{
@ -113,8 +114,8 @@ class AudioEngine : public sigc::trackable
virtual const char *what() const throw() { return "could not connect to engine backend"; }
};
Port *register_input_port (DataType type, const std::string& portname);
Port *register_output_port (DataType type, const std::string& portname);
Port *register_input_port (PortType, DataType, const std::string& portname);
Port *register_output_port (PortType, DataType, const std::string& portname);
int unregister_port (Port &);
int connect (const std::string& source, const std::string& destination);
@ -219,11 +220,13 @@ class AudioEngine : public sigc::trackable
SerializedRCUManager<Ports> ports;
Port *register_port (DataType type, const std::string& portname, bool input);
Port *register_port (PortType ptype, DataType type, const std::string& portname, bool input);
int process_callback (nframes_t nframes);
void remove_all_ports ();
InternalPort* get_internal_port (const std::string& short_name);
typedef std::pair<std::string,std::string> PortConnection;
typedef std::list<PortConnection> PortConnections;

View file

@ -59,6 +59,13 @@ public:
DataType type() const { return _type; }
bool silent() const { return _silent; }
/** Reallocate the buffer used internally to handle at least @a size_t units of data.
*
* The buffer is not silent after this operation. the @a capacity argument
* passed to the constructor must have been non-zero.
*/
virtual void resize(size_t) = 0;
/** Clear (eg zero, or empty) buffer starting at TIME @a offset */
virtual void silence(nframes_t len, nframes_t offset=0) = 0;

View file

@ -0,0 +1,55 @@
/*
Copyright (C) 2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: port.h 712 2006-07-28 01:08:57Z drobilla $
*/
#ifndef __ardour_internal_audio_port_h__
#define __ardour_internal_audio_port_h__
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/ardour.h>
#include <ardour/internal_port.h>
#include <ardour/audio_port.h>
namespace ARDOUR {
class AudioEngine;
class InternalAudioPort : public AudioPort, public InternalPort {
public:
void cycle_start(nframes_t nframes) {
_buffer.silence (nframes);
}
AudioBuffer& get_audio_buffer();
void set_mixdown_function (void (*func)(const std::list<InternalPort*>&, AudioBuffer&, nframes_t, nframes_t));
void reset ();
protected:
friend class AudioEngine;
InternalAudioPort (const std::string& name, Flags flags);
void (*_mixdown)(const std::list<InternalPort*>&, AudioBuffer&, nframes_t, nframes_t);
static void default_mixdown (const std::list<InternalPort*>&, AudioBuffer&, nframes_t, nframes_t);
};
} // namespace ARDOUR
#endif /* __ardour_internal_audio_port_h__ */

View file

@ -0,0 +1,82 @@
/*
Copyright (C) 2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_internal_port_h__
#define __ardour_internal_port_h__
#include <list>
#include <sigc++/signal.h>
#include <pbd/failed_constructor.h>
#include <ardour/port.h>
namespace ARDOUR {
class AudioEngine;
class Buffer;
/** Abstract class representing internal (ardour<->ardour only) ports
*/
class InternalPort : public virtual Port {
public:
~InternalPort();
std::string short_name();
int set_name (std::string str);
int connected () const;
int reestablish ();
bool connected_to (const std::string& portname) const;
const char ** get_connections () const;
bool monitoring_input () const { return false; }
void ensure_monitor_input (bool yn) {}
void request_monitor_input (bool yn) {}
nframes_t latency () const { return _latency; }
nframes_t total_latency() const { return _latency; }
void set_latency (nframes_t nframes);
static void connect (InternalPort& src, InternalPort& dst);
static void disconnect (InternalPort& a, InternalPort& b);
protected:
friend class AudioEngine;
InternalPort (const std::string&, DataType type, Flags flags);
int disconnect ();
void recompute_total_latency() const;
std::list<InternalPort*> _connections;
nframes_t _latency;
static AudioEngine* engine;
static void set_engine (AudioEngine* e);
};
} // namespace ARDOUR
#endif /* __ardour_internal_port_h__ */

View file

@ -42,6 +42,8 @@ public:
bool push_back(const ARDOUR::MidiEvent& event);
bool push_back(const jack_midi_event_t& event);
Byte* reserve(double time, size_t size);
void resize(size_t);
bool merge(const MidiBuffer& a, const MidiBuffer& b);

View file

@ -379,6 +379,11 @@ namespace ARDOUR {
SrcFastest
};
enum PortType {
Jack,
Internal
};
} // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);

View file

@ -29,19 +29,13 @@ namespace ARDOUR {
AudioBuffer::AudioBuffer(size_t capacity)
: Buffer(DataType::AUDIO, capacity)
, _owns_data(false)
, _data(NULL)
, _owns_data (false)
, _data (0)
{
_size = capacity; // For audio buffers, size = capacity (always)
if (capacity > 0) {
#ifdef NO_POSIX_MEMALIGN
_data = (Sample *) malloc(sizeof(Sample) * capacity);
#else
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * capacity);
#endif
assert(_data);
_owns_data = true;
clear();
if (_capacity) {
_owns_data = true; // prevent resize() from gagging
resize (_capacity);
silence (_capacity);
}
}
@ -51,6 +45,31 @@ AudioBuffer::~AudioBuffer()
free(_data);
}
void
AudioBuffer::resize (size_t size)
{
assert (_owns_data);
if (size < _capacity) {
return;
}
if (_data) {
free (_data);
}
_capacity = size;
_size = size;
_silent = false;
#ifdef NO_POSIX_MEMALIGN
_data = (Sample *) malloc(sizeof(Sample) * _capacity);
#else
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * _capacity);
#endif
_owns_data = true;
}
} // namespace ARDOUR

View file

@ -33,6 +33,13 @@ AudioPort::AudioPort()
reset();
}
AudioPort::AudioPort(nframes_t nframes)
: _buffer (nframes)
{
_type = DataType::AUDIO;
reset();
}
void
AudioPort::reset()
{

View file

@ -32,6 +32,7 @@
#include <ardour/buffer.h>
#include <ardour/port.h>
#include <ardour/jack_audio_port.h>
#include <ardour/internal_audio_port.h>
#include <ardour/jack_midi_port.h>
#include <ardour/session.h>
#include <ardour/cycle_timer.h>
@ -508,17 +509,33 @@ AudioEngine::remove_session ()
}
Port *
AudioEngine::register_port (DataType type, const string& portname, bool input)
AudioEngine::register_port (PortType ptype, DataType dtype, const string& portname, bool input)
{
Port* newport = 0;
try {
if (type == DataType::AUDIO)
newport = new JackAudioPort (portname, (input ? Port::IsInput : Port::IsOutput));
else if (type == DataType::MIDI)
newport = new JackMidiPort (portname, (input ? Port::IsInput : Port::IsOutput));
else
throw unknown_type();
switch (ptype) {
case Jack:
if (dtype == DataType::AUDIO) {
newport = new JackAudioPort (portname, (input ? Port::IsInput : Port::IsOutput));
} else if (dtype == DataType::MIDI) {
newport = new JackMidiPort (portname, (input ? Port::IsInput : Port::IsOutput));
} else {
throw unknown_type();
}
break;
case Internal:
if (dtype == DataType::AUDIO) {
newport = new InternalAudioPort (portname, (input ? Port::IsInput : Port::IsOutput));
} else if (dtype == DataType::MIDI) {
error << _("Internal MIDI ports are not implemented yet!") << endmsg;
throw unknown_type();
} else {
throw unknown_type();
}
break;
}
if (newport != 0) {
RCUWriter<Ports> writer (ports);
@ -535,16 +552,30 @@ AudioEngine::register_port (DataType type, const string& portname, bool input)
}
}
Port *
AudioEngine::register_input_port (DataType type, const string& portname)
InternalPort*
AudioEngine::get_internal_port (const std::string& short_name)
{
return register_port (type, portname, true);
boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
if ((*i)->short_name() == short_name) {
return dynamic_cast<InternalPort*> (*i);
}
}
return 0;
}
Port *
AudioEngine::register_input_port (PortType ptype, DataType type, const string& portname)
{
return register_port (ptype, type, portname, true);
}
Port *
AudioEngine::register_output_port (DataType type, const string& portname)
AudioEngine::register_output_port (PortType ptype, DataType type, const string& portname)
{
return register_port (type, portname, false);
return register_port (ptype, type, portname, false);
}
int
@ -565,7 +596,6 @@ AudioEngine::unregister_port (Port& port)
for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
if ((*i) == &port) {
remove_connections_for (port);
cerr << "eraseing " << (*i)->name() << endl;
delete *i;
ps->erase (i);
break;
@ -581,6 +611,8 @@ AudioEngine::unregister_port (Port& port)
int
AudioEngine::connect (const string& source, const string& destination)
{
int ret;
if (!_running) {
if (!_has_run) {
fatal << _("connect called before engine was started") << endmsg;
@ -589,11 +621,26 @@ AudioEngine::connect (const string& source, const string& destination)
return -1;
}
}
string s = make_port_name_non_relative (source);
string d = make_port_name_non_relative (destination);
if (source.substr (0, 9) == "internal:") {
if (destination.substr (0, 9) == "internal:") {
InternalPort* src = get_internal_port (source);
InternalPort* dst = get_internal_port (destination);
int ret = jack_connect (_jack, s.c_str(), d.c_str());
InternalPort::connect (*src, *dst);
ret = 0;
} else {
ret = -1;
}
} else {
ret = jack_connect (_jack, s.c_str(), d.c_str());
}
if (ret == 0) {
pair<string,string> c (s, d);
@ -614,6 +661,8 @@ AudioEngine::connect (const string& source, const string& destination)
int
AudioEngine::disconnect (const string& source, const string& destination)
{
int ret;
if (!_running) {
if (!_has_run) {
fatal << _("disconnect called before engine was started") << endmsg;
@ -626,7 +675,21 @@ AudioEngine::disconnect (const string& source, const string& destination)
string s = make_port_name_non_relative (source);
string d = make_port_name_non_relative (destination);
int ret = jack_disconnect (_jack, s.c_str(), d.c_str());
if (source.substr (0, 9) == "internal:") {
if (destination.substr (0, 9) == "internal:") {
InternalPort* src = get_internal_port (source);
InternalPort* dst = get_internal_port (destination);
InternalPort::disconnect (*src, *dst);
ret = 0;
} else {
ret = -1;
}
} else {
ret = jack_disconnect (_jack, s.c_str(), d.c_str());
}
if (ret == 0) {
pair<string,string> c (s, d);

View file

@ -0,0 +1,70 @@
/*
Copyright (C) 2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cassert>
#include <ardour/internal_audio_port.h>
#include <ardour/audioengine.h>
using namespace ARDOUR;
using namespace std;
void
InternalAudioPort::default_mixdown (const list<InternalPort*>& ports, AudioBuffer& dest, nframes_t cnt, nframes_t offset)
{
list<InternalPort*>::const_iterator p = ports.begin();
dest.read_from ((dynamic_cast<AudioPort*>(*p))->get_audio_buffer(), cnt, offset);
for (; p != ports.end(); ++p) {
dest.accumulate_from ((dynamic_cast<AudioPort*>(*p))->get_audio_buffer(), cnt, offset);
}
}
InternalAudioPort::InternalAudioPort(const string& name, Flags flgs)
: AudioPort (engine->frames_per_cycle())
, InternalPort (name, DataType::AUDIO, flgs)
{
_mixdown = default_mixdown;
}
void
InternalAudioPort::set_mixdown_function (void (*func)(const list<InternalPort*>&, AudioBuffer&, nframes_t, nframes_t))
{
_mixdown = func;
}
void
InternalAudioPort::reset ()
{
_buffer.resize (engine->frames_per_cycle());
_buffer.silence (_buffer.size());
}
AudioBuffer&
InternalAudioPort::get_audio_buffer ()
{
if (_connections.empty()) {
return AudioPort::get_audio_buffer();
}
/* XXX what about offset/size being more dynamic ? */
(*_mixdown) (_connections, _buffer, _buffer.size(), 0);
return _buffer;
}

View file

@ -0,0 +1,164 @@
/*
Copyright (C) 2007 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <pbd/error.h>
#include <ardour/internal_port.h>
#include <ardour/audioengine.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace std;
AudioEngine* InternalPort::engine = 0;
void
InternalPort::set_engine (AudioEngine* e)
{
engine = e;
}
InternalPort::InternalPort (const string& str, DataType type, Flags flags)
{
set_name (str);
_type = type;
_flags = flags;
}
InternalPort::~InternalPort ()
{
disconnect ();
}
void
InternalPort::set_latency (nframes_t val)
{
_latency = val;
}
bool
InternalPort::connected_to (const string& portname) const
{
/* caller must hold process lock */
for (list<InternalPort*>::const_iterator p = _connections.begin(); p != _connections.end(); ++p) {
if ((*p)->name() == portname) {
return true;
}
}
return false;
}
const char**
InternalPort::get_connections () const
{
/* caller must hold process lock */
int i;
list<InternalPort*>::const_iterator p;
if (_connections.empty()) {
return 0;
}
char **names = (char**) malloc (sizeof (char*) * ( _connections.size() + 1));
for (i = 0, p = _connections.begin(); p != _connections.end(); ++p, ++i) {
names[i] = (char*) (*p)->name().c_str();
}
names[i] = 0;
return (const char**) names;
}
int
InternalPort::connected() const
{
/* caller must hold process lock */
return !_connections.empty();
}
int
InternalPort::set_name (string str)
{
_name = "internal:";
_name += str;
return 0;
}
string
InternalPort::short_name ()
{
return _name.substr (9);
}
void
InternalPort::connect (InternalPort& src, InternalPort& dst)
{
/* caller must hold process lock */
src._connections.push_back (&dst);
dst._connections.push_back (&src);
}
void
InternalPort::disconnect (InternalPort& a, InternalPort& b)
{
/* caller must hold process lock */
a._connections.remove (&b);
b._connections.remove (&a);
}
int
InternalPort::disconnect ()
{
/* caller must hold process lock */
for (list<InternalPort*>::const_iterator p = _connections.begin(); p != _connections.end(); ) {
list<InternalPort*>::const_iterator tmp;
tmp = p;
++tmp;
disconnect (*this, **p);
p = tmp;
}
_connections.clear ();
return 0;
}
int
InternalPort::reestablish ()
{
return 0;
}
void
InternalPort::recompute_total_latency () const
{
return;
}

View file

@ -602,7 +602,7 @@ IO::add_output_port (string destination, void* src, DataType type)
snprintf (name, sizeof (name), _("%s/out %u"), _name.c_str(), find_output_port_hole());
}
if ((our_port = _session.engine().register_output_port (type, name)) == 0) {
if ((our_port = _session.engine().register_output_port (Jack, type, name)) == 0) {
error << string_compose(_("IO: cannot register output port %1"), name) << endmsg;
return -1;
}
@ -713,7 +713,7 @@ IO::add_input_port (string source, void* src, DataType type)
snprintf (name, sizeof (name), _("%s/in %u"), _name.c_str(), find_input_port_hole());
}
if ((our_port = _session.engine().register_input_port (type, name)) == 0) {
if ((our_port = _session.engine().register_input_port (Jack, type, name)) == 0) {
error << string_compose(_("IO: cannot register input port %1"), name) << endmsg;
return -1;
}
@ -822,7 +822,7 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
try {
if ((input_port = _session.engine().register_input_port (*t, buf)) == 0) {
if ((input_port = _session.engine().register_input_port (Jack, *t, buf)) == 0) {
error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
return -1;
}
@ -938,7 +938,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
}
try {
if ((port = _session.engine().register_input_port (*t, buf)) == 0) {
if ((port = _session.engine().register_input_port (Jack, *t, buf)) == 0) {
error << string_compose(_("IO: cannot register input port %1"), buf) << endmsg;
return -1;
}
@ -970,7 +970,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
}
try {
if ((port = _session.engine().register_output_port (*t, buf)) == 0) {
if ((port = _session.engine().register_output_port (Jack, *t, buf)) == 0) {
error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
return -1;
}
@ -1090,7 +1090,7 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
snprintf (buf, sizeof (buf), _("%s/out %u"), _name.c_str(), find_output_port_hole());
}
if ((output_port = _session.engine().register_output_port (*t, buf)) == 0) {
if ((output_port = _session.engine().register_output_port (Jack, *t, buf)) == 0) {
error << string_compose(_("IO: cannot register output port %1"), buf) << endmsg;
return -1;
}

View file

@ -109,3 +109,4 @@ JackPort::recompute_total_latency () const
#endif
}

View file

@ -38,20 +38,31 @@ MidiBuffer::MidiBuffer(size_t capacity)
, _events(NULL)
, _data(NULL)
{
assert(capacity > 0);
_data = 0;
resize (_capacity);
silence(_capacity);
}
void
MidiBuffer::resize (size_t size)
{
assert(size > 0);
if (_data) {
free (_data);
}
_size = 0;
_capacity = size;
#ifdef NO_POSIX_MEMALIGN
_events = (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
_data = (Byte *) malloc(sizeof(Byte) * capacity * MAX_EVENT_SIZE);
_events = (MidiEvent *) malloc(sizeof(MidiEvent) * _capacity);
_data = (Byte *) malloc(sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
#else
posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * capacity);
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * capacity * MAX_EVENT_SIZE);
posix_memalign((void**)&_events, CPU_CACHE_ALIGN, sizeof(MidiEvent) * _capacity);
posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Byte) * _capacity * MAX_EVENT_SIZE);
#endif
assert(_data);
assert(_events);
silence(_capacity);
}
void