def build(bld):
presets = bld.path.ant_glob ('*.preset')
formats = bld.path.ant_glob ('*.format')
- bld.install_files (os.path.join(bld.env['DATADIR'], 'ardour3', 'export'),
+ bld.install_files (os.path.join(bld.env['DATADIR'], 'export'),
presets + formats)
def options(opt):
export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
export ARDOUR_MCP_PATH=$TOP/mcp:.
export ARDOUR_EXPORT_FORMATS_PATH=$TOP/export:.
-export ARDOUR_BACKEND_PATH=$libs/backends/jack:$libs/backends/wavesaudio
+export ARDOUR_BACKEND_PATH=$libs/backends/jack:$libs/backends/wavesaudio:$libs/backends/dummy
#
# even though we set the above variables, ardour requires that these
<menuitem action='nudge-backward'/>
<menuitem action='nudge-forward-by-capture-offset'/>
<menuitem action='nudge-backward-by-capture-offset'/>
+ <menuitem action='sequence-regions'/>
</menu>
<menu action='RegionMenuTrim'>
<menuitem action='trim-front'/>
<menuitem action='nudge-backward'/>
<menuitem action='nudge-forward-by-capture-offset'/>
<menuitem action='nudge-backward-by-capture-offset'/>
+ <menuitem action='sequence-regions'/>
</menu>
<menu action='RegionMenuTrim'>
<menuitem action='trim-front'/>
void nudge_forward_capture_offset ();
void nudge_backward_capture_offset ();
+ void sequence_regions ();
+
/* playhead/screen stuff */
void set_stationary_playhead (bool yn);
reg_sens (_region_actions, "nudge-forward", _("Nudge Later"), sigc::bind (sigc::mem_fun (*this, &Editor::nudge_forward), false, false));
reg_sens (_region_actions, "nudge-backward", _("Nudge Earlier"), sigc::bind (sigc::mem_fun (*this, &Editor::nudge_backward), false, false));
+ reg_sens (_region_actions, "sequence-regions", _("Sequence Regions"), sigc::mem_fun (*this, &Editor::sequence_regions));
+
reg_sens (
_region_actions,
"nudge-forward-by-capture-offset",
commit_reversible_command ();
}
+struct RegionSelectionPositionSorter {
+ bool operator() (RegionView* a, RegionView* b) {
+ return a->region()->position() < b->region()->position();
+ }
+};
+
+void
+Editor::sequence_regions ()
+{
+ framepos_t r_end;
+ framepos_t r_end_prev;
+
+ int iCount=0;
+
+ if (!_session) {
+ return;
+ }
+
+ RegionSelection rs = get_regions_from_selection_and_entered ();
+ rs.sort(RegionSelectionPositionSorter());
+
+ if (!rs.empty()) {
+
+ begin_reversible_command (_("sequence regions"));
+ for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
+ boost::shared_ptr<Region> r ((*i)->region());
+
+ r->clear_changes();
+
+ if(r->locked())
+ {
+ continue;
+ }
+ if(r->position_locked())
+ {
+ continue;
+ }
+ if(iCount>0)
+ {
+ r_end_prev=r_end;
+ r->set_position(r_end_prev);
+ }
+
+ _session->add_command (new StatefulDiffCommand (r));
+
+ r_end=r->position() + r->length();
+
+ iCount++;
+ }
+ commit_reversible_command ();
+ }
+}
+
+
/* DISPLAY MOTION */
void
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
]
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.uselib = 'UUID FLAC FONTCONFIG GLIBMM GTHREAD OGG CURL DL'
obj.uselib += ' FFTW3F'
obj.uselib += ' AUDIOUNITS OSX LO '
#include <string>
#include <iostream>
+#include <boost/function.hpp>
+
#include "pbd/xml++.h"
#include "pbd/crossthread.h"
#include "pbd/signals.h"
#endif
}
+ void set_timer (boost::function<framecnt_t (void)>&);
+
static void set_process_thread (pthread_t);
static pthread_t get_process_thread () { return _process_thread; }
static bool is_process_thread();
private:
bool _currently_in_cycle;
MIDI::timestamp_t _last_write_timestamp;
+ bool have_timer;
+ boost::function<framecnt_t (void)> timer;
RingBuffer< Evoral::Event<double> > output_fifo;
Evoral::EventRingBuffer<MIDI::timestamp_t> input_fifo;
Glib::Threads::Mutex output_fifo_lock;
#include "pbd/statefuldestructible.h"
#include "ardour/ardour.h"
+#include "ardour/scene_change.h"
#include "ardour/session_handle.h"
namespace ARDOUR {
+class SceneChange;
+
class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDestructible
{
public:
Flags flags () const { return _flags; }
+ boost::shared_ptr<SceneChange> scene_change() const { return _scene_change; }
+ void set_scene_change (boost::shared_ptr<SceneChange>);
+
PBD::Signal1<void,Location*> name_changed;
PBD::Signal1<void,Location*> end_changed;
PBD::Signal1<void,Location*> start_changed;
void set_position_lock_style (PositionLockStyle ps);
void recompute_frames_from_bbt ();
+ static PBD::Signal0<void> scene_changed;
+
private:
std::string _name;
framepos_t _start;
Flags _flags;
bool _locked;
PositionLockStyle _position_lock_style;
+ boost::shared_ptr<SceneChange> _scene_change;
void set_mark (bool yn);
bool set_flag_internal (bool yn, Flags flag);
int set_current (Location *, bool want_lock = true);
Location *current () const { return current_location; }
+ Location* mark_at (framepos_t, framecnt_t slop = 0) const;
+
framepos_t first_mark_before (framepos_t, bool include_special_ranges = false);
framepos_t first_mark_after (framepos_t, bool include_special_ranges = false);
--- /dev/null
+/*
+ Copyright (C) 2014 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 __libardour_midi_scene_change_h__
+#define __libardour_midi_scene_change_h__
+
+#include "evoral/PatchChange.hpp"
+
+#include "ardour/scene_change.h"
+
+namespace ARDOUR
+{
+
+class MidiPort;
+
+class MIDISceneChange : public SceneChange
+{
+ public:
+ MIDISceneChange (framepos_t time, int channel, int bank = -1, int program = -1);
+ MIDISceneChange (const XMLNode&, int version);
+ ~MIDISceneChange ();
+
+ void set_channel (int channel);
+ void set_program (int program);
+ void set_bank (int bank);
+
+ int channel () const { return _channel; }
+ int program () const { return _program; }
+ int bank () const { return _bank; }
+
+ size_t get_bank_msb_message (uint8_t* buf, size_t size) const;
+ size_t get_bank_lsb_message (uint8_t* buf, size_t size) const;
+ size_t get_program_message (uint8_t* buf, size_t size) const;
+
+ XMLNode& get_state();
+ int set_state (const XMLNode&, int version);
+
+ private:
+ int _bank;
+ int _program;
+ uint8_t _channel;
+};
+
+} /* namespace */
+
+
+#endif /* __libardour_scene_change_h__ */
--- /dev/null
+/*
+ Copyright (C) 2014 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 __libardour_midi_scene_changer_h__
+#define __libardour_midi_scene_changer_h__
+
+#include "ardour/scene_changer.h"
+
+namespace ARDOUR
+{
+
+class MIDISceneChanger : public SceneChanger
+{
+ public:
+ MIDISceneChanger (Session&);
+ ~MIDISceneChanger ();
+
+ void run (framepos_t start, framepos_t end);
+ void set_input_port (MIDI::Port*);
+ void set_output_port (boost::shared_ptr<MidiPort>);
+
+ uint8_t bank_at (framepos_t, uint8_t channel);
+ uint8_t program_at (framepos_t, uint8_t channel);
+
+ void set_recording (bool);
+ void locate (framepos_t);
+
+ private:
+ typedef std::multimap<framepos_t,boost::shared_ptr<MIDISceneChange> > Scenes;
+
+ MIDI::Port* input_port;
+ boost::shared_ptr<MidiPort> output_port;
+ Scenes scenes;
+ bool _recording;
+ framepos_t last_bank_message_time;
+ framepos_t last_program_message_time;
+ unsigned short current_bank;
+ int last_delivered_program;
+ int last_delivered_bank;
+
+ void gather ();
+ bool recording () const;
+ void jump_to (int bank, int program);
+ void deliver (MidiBuffer&, framepos_t, boost::shared_ptr<MIDISceneChange>);
+
+ void bank_change_input (MIDI::Parser&, unsigned short);
+ void program_change_input (MIDI::Parser&, MIDI::byte);
+ void locations_changed (Locations::Change);
+
+ PBD::ScopedConnection incoming_bank_change_connection;
+ PBD::ScopedConnection incoming_program_change_connection;
+};
+
+} // namespace
+
+#endif /* __libardour_midi_scene_changer_h__ */
#include "midi++/port.h"
#include "ardour/libardour_visibility.h"
+#include "ardour/midi_port.h"
#include "ardour/types.h"
namespace ARDOUR {
MIDI::Port* midi_output_port () const { return _midi_output_port; }
MIDI::Port* mmc_input_port () const { return _mmc_input_port; }
MIDI::Port* mmc_output_port () const { return _mmc_output_port; }
+ MIDI::Port* scene_input_port () const { return _scene_input_port; }
+ MIDI::Port* scene_output_port () const { return _scene_output_port; }
+ boost::shared_ptr<MidiPort> scene_in() const { return boost::dynamic_pointer_cast<MidiPort>(_scene_in); }
+ boost::shared_ptr<MidiPort> scene_out() const { return boost::dynamic_pointer_cast<MidiPort>(_scene_out); }
+
/* Ports used for synchronization. These have their I/O handled inside the
* process callback.
*/
MIDI::Port* _midi_output_port;
MIDI::Port* _mmc_input_port;
MIDI::Port* _mmc_output_port;
- /* these point to the same objects as the 4 members above,
+ MIDI::Port* _scene_input_port;
+ MIDI::Port* _scene_output_port;
+ /* these point to the same objects as the members above,
but cast to their ARDOUR::Port base class
*/
boost::shared_ptr<Port> _midi_in;
boost::shared_ptr<Port> _midi_out;
boost::shared_ptr<Port> _mmc_in;
boost::shared_ptr<Port> _mmc_out;
+ boost::shared_ptr<Port> _scene_in;
+ boost::shared_ptr<Port> _scene_out;
/* synchronously handled ports: ARDOUR::MidiPort */
boost::shared_ptr<MidiPort> _mtc_input_port;
CONFIG_VARIABLE (int32_t, mmc_send_device_id, "mmc-send-device-id", 0)
CONFIG_VARIABLE (int32_t, initial_program_change, "initial-program-change", -1)
CONFIG_VARIABLE (bool, first_midi_bank_is_zero, "display-first-midi-bank-as-zero", false)
+CONFIG_VARIABLE (int32_t, inter_scene_gap_msecs, "inter-scene-gap-msecs", 1)
/* Timecode and related */
--- /dev/null
+/*
+ Copyright (C) 2014 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 __libardour_scene_change_h__
+#define __libardour_scene_change_h__
+
+#include "pbd/stateful.h"
+
+#include "ardour/types.h"
+
+namespace ARDOUR
+{
+
+class SceneChange : public PBD::Stateful
+{
+ public:
+ SceneChange (framepos_t t) : _time (t) {};
+ virtual ~SceneChange () {};
+
+ void set_time (framepos_t);
+ framepos_t time() const { return _time; }
+
+ static boost::shared_ptr<SceneChange> factory (const XMLNode&, int version);
+ static std::string xml_node_name;
+
+ private:
+ framepos_t _time;
+};
+
+} /* namespace */
+
+
+#endif /* __libardour_scene_change_h__ */
--- /dev/null
+/*
+ Copyright (C) 2014 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 __libardour_scene_changer_h__
+#define __libardour_scene_changer_h__
+
+#include <map>
+
+#include "pbd/signals.h"
+
+#include "ardour/location.h"
+#include "ardour/midi_scene_change.h"
+#include "ardour/session_handle.h"
+#include "ardour/types.h"
+
+namespace MIDI
+{
+class Parser;
+class Port;
+}
+
+namespace ARDOUR
+{
+
+class Session;
+class AsyncMidiPort;
+
+class SceneChanger : public SessionHandleRef
+{
+ public:
+ SceneChanger (Session& s) : SessionHandleRef (s) {}
+ virtual ~SceneChanger () {};
+
+ virtual void run (framepos_t start, framepos_t end) = 0;
+};
+
+} /* namespace */
+
+
+#endif /* __libardour_scene_change_h__ */
class RouteGroup;
class SMFSource;
class Send;
+class SceneChanger;
class SessionDirectory;
class SessionMetadata;
class SessionPlaylists;
*/
static PBD::Signal2<void,std::string,std::string> VersionMismatch;
+ SceneChanger* scene_changer() const { return _scene_changer; }
+
boost::shared_ptr<Port> ltc_input_port() const;
boost::shared_ptr<Port> ltc_output_port() const;
boost::shared_ptr<IO> ltc_input_io() { return _ltc_input; }
boost::shared_ptr<IO> ltc_output_io() { return _ltc_output; }
- MIDI::Port* midi_input_port () const;
- MIDI::Port* midi_output_port () const;
- MIDI::Port* mmc_output_port () const;
- MIDI::Port* mmc_input_port () const;
+ MIDI::Port* midi_input_port () const;
+ MIDI::Port* midi_output_port () const;
+ MIDI::Port* mmc_output_port () const;
+ MIDI::Port* mmc_input_port () const;
- boost::shared_ptr<MidiPort> midi_clock_output_port () const;
- boost::shared_ptr<MidiPort> midi_clock_input_port () const;
- boost::shared_ptr<MidiPort> mtc_output_port () const;
- boost::shared_ptr<MidiPort> mtc_input_port () const;
+ MIDI::Port* scene_input_port () const;
+ MIDI::Port* scene_output_port () const;
- MIDI::MachineControl& mmc() { return *_mmc; }
+ boost::shared_ptr<MidiPort> scene_in () const;
+ boost::shared_ptr<MidiPort> scene_out () const;
+
+ boost::shared_ptr<MidiPort> midi_clock_output_port () const;
+ boost::shared_ptr<MidiPort> midi_clock_input_port () const;
+ boost::shared_ptr<MidiPort> mtc_output_port () const;
+ boost::shared_ptr<MidiPort> mtc_input_port () const;
+
+ MIDI::MachineControl& mmc() { return *_mmc; }
protected:
friend class AudioEngine;
void reconnect_ltc_input ();
void reconnect_ltc_output ();
- /* persistent, non-track related MIDI ports */
- MidiPortManager* _midi_ports;
- MIDI::MachineControl* _mmc;
-
- void setup_ltc ();
- void setup_click ();
- void setup_click_state (const XMLNode*);
- void setup_bundles ();
-
- static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath);
+ /* Scene Changing */
+ SceneChanger* _scene_changer;
+
+ /* persistent, non-track related MIDI ports */
+ MidiPortManager* _midi_ports;
+ MIDI::MachineControl* _mmc;
+
+ void setup_ltc ();
+ void setup_click ();
+ void setup_click_state (const XMLNode*);
+ void setup_bundles ();
+
+ static int get_session_info_from_path (XMLTree& state_tree, const std::string& xmlpath);
};
} // namespace ARDOUR
, MIDI::Port (name, MIDI::Port::Flags (0))
, _currently_in_cycle (false)
, _last_write_timestamp (0)
+ , have_timer (false)
, output_fifo (512)
, input_fifo (1024)
#ifndef PLATFORM_WINDOWS
{
}
+void
+AsyncMIDIPort::set_timer (boost::function<framecnt_t (void)>& f)
+{
+ timer = f;
+ have_timer = true;
+}
+
void
AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
{
if (ARDOUR::Port::receives_input()) {
MidiBuffer& mb (get_midi_buffer (nframes));
- pframes_t when = AudioEngine::instance()->sample_time_at_cycle_start();
+ framecnt_t when;
+
+ if (have_timer) {
+ when = timer ();
+ } else {
+ when = AudioEngine::instance()->sample_time_at_cycle_start();
+ }
for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) {
+ if (!have_timer) {
+ when += (*b).time();
+ }
input_fifo.write (when, (Evoral::EventType) 0, (*b).size(), (*b).buffer());
}
#include "pbd/enumwriter.h"
#include "ardour/location.h"
+#include "ardour/midi_scene_change.h"
#include "ardour/session.h"
#include "ardour/audiofilesource.h"
#include "ardour/tempo.h"
using namespace ARDOUR;
using namespace PBD;
+PBD::Signal0<void> Location::scene_changed;
+
Location::Location (Session& s)
: SessionHandleRef (s)
, _start (0)
assert (_start >= 0);
assert (_end >= 0);
+
+ /* scene change is NOT COPIED */
}
Location::Location (Session& s, const XMLNode& node)
_bbt_end = other._bbt_end;
_flags = other._flags;
_position_lock_style = other._position_lock_style;
+
+ /* XXX need to copy scene change */
/* copy is not locked even if original was */
node->add_property ("locked", (_locked ? "yes" : "no"));
node->add_property ("position-lock-style", enum_2_string (_position_lock_style));
+ if (_scene_change) {
+ node->add_child_nocopy (_scene_change->get_state());
+ }
+
return *node;
}
int
-Location::set_state (const XMLNode& node, int /*version*/)
+Location::set_state (const XMLNode& node, int version)
{
const XMLProperty *prop;
_position_lock_style = PositionLockStyle (string_2_enum (prop->value(), _position_lock_style));
}
+ XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
+
+ if (scene_child) {
+ _scene_change = SceneChange::factory (*scene_child, version);
+
+ if (_scene_change) {
+ _scene_change->set_time (_start);
+ }
+ }
+
recompute_bbt_from_frames ();
changed (this); /* EMIT SIGNAL */
LockChanged (this);
}
+void
+Location::set_scene_change (boost::shared_ptr<SceneChange> sc)
+{
+ _scene_change = sc;
+
+ scene_changed (); /* EMIT SIGNAL */
+}
+
/*---------------------------------------------------------------------- */
Locations::Locations (Session& s)
++tmp;
if (!(*i)->is_session_range()) {
+ delete *i;
locations.erase (i);
}
++tmp;
if ((*i)->is_mark() && !(*i)->is_session_range()) {
+ delete *i;
locations.erase (i);
}
++tmp;
if (!(*i)->is_mark()) {
+ delete *i;
locations.erase (i);
}
for (i = locations.begin(); i != locations.end(); ++i) {
if ((*i) == loc) {
+ delete *i;
locations.erase (i);
was_removed = true;
if (current_location == loc) {
return -1;
}
+Location*
+Locations::mark_at (framepos_t pos, framecnt_t slop) const
+{
+ Glib::Threads::Mutex::Lock lm (lock);
+ Location* closest = 0;
+ frameoffset_t mindelta = max_framepos;
+ frameoffset_t delta;
+
+ /* locations are not necessarily stored in linear time order so we have
+ * to iterate across all of them to find the one closest to a give point.
+ */
+
+ for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
+
+ if ((*i)->is_mark()) {
+ if (pos > (*i)->start()) {
+ delta = pos - (*i)->start();
+ } else {
+ delta = (*i)->start() - pos;
+ }
+
+ if (slop == 0 && delta == 0) {
+ /* special case: no slop, and direct hit for position */
+ return *i;
+ }
+
+ if (delta <= slop) {
+ if (delta < mindelta) {
+ closest = *i;
+ mindelta = delta;
+ }
+ }
+ }
+ }
+
+ return closest;
+}
+
framepos_t
Locations::first_mark_after (framepos_t frame, bool include_special_ranges)
{
}
}
}
+
--- /dev/null
+/*
+ Copyright (C) 2014 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 "pbd/compose.h"
+
+#include "ardour/midi_port.h"
+#include "ardour/midi_scene_change.h"
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+MIDISceneChange::MIDISceneChange (framepos_t time, int c, int b, int p)
+ : SceneChange (time)
+ , _bank (b)
+ , _program (p)
+ , _channel (c & 0xf)
+{
+ if (_bank > 16384) {
+ _bank = -1;
+ }
+
+ if (_program > 128) {
+ _program = -1;
+ }
+}
+
+MIDISceneChange::MIDISceneChange (const XMLNode& node, int version)
+ : SceneChange (0)
+ , _bank (-1)
+ , _program (-1)
+ , _channel (-1)
+{
+ set_state (node, version);
+}
+
+MIDISceneChange::~MIDISceneChange ()
+{
+}
+
+size_t
+MIDISceneChange::get_bank_msb_message (uint8_t* buf, size_t size) const
+{
+ if (size < 3 || _bank < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xB0 | (_channel & 0xf);
+ buf[1] = 0x0;
+ buf[2] = (_bank & 0xf700) >> 8;
+
+ return 3;
+}
+
+size_t
+MIDISceneChange::get_bank_lsb_message (uint8_t* buf, size_t size) const
+{
+ if (size < 3 || _bank < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xB0 | (_channel & 0xf);
+ buf[1] = 0x20;
+ buf[2] = (_bank & 0xf7);
+
+ return 3;
+}
+
+size_t
+MIDISceneChange::get_program_message (uint8_t* buf, size_t size) const
+{
+ if (size < 2 || _program < 0) {
+ return 0;
+ }
+
+ buf[0] = 0xC0 | (_channel & 0xf);
+ buf[1] = _program & 0xf7;
+
+ return 2;
+}
+
+XMLNode&
+MIDISceneChange::get_state ()
+{
+ char buf[32];
+ XMLNode* node = new XMLNode (SceneChange::xml_node_name);
+
+ node->add_property (X_("type"), X_("MIDI"));
+ snprintf (buf, sizeof (buf), "%d", (int) _program);
+ node->add_property (X_("id"), id().to_s());
+ snprintf (buf, sizeof (buf), "%d", (int) _program);
+ node->add_property (X_("program"), buf);
+ snprintf (buf, sizeof (buf), "%d", (int) _bank);
+ node->add_property (X_("bank"), buf);
+ snprintf (buf, sizeof (buf), "%d", (int) _channel);
+ node->add_property (X_("channel"), buf);
+
+ return *node;
+}
+
+int
+MIDISceneChange::set_state (const XMLNode& node, int /* version-ignored */)
+{
+ if (!set_id (node)) {
+ return -1;
+ }
+
+ const XMLProperty* prop;
+
+ if ((prop = node.property (X_("program"))) == 0) {
+ return -1;
+ }
+ _program = atoi (prop->value());
+
+ if ((prop = node.property (X_("bank"))) == 0) {
+ return -1;
+ }
+ _bank = atoi (prop->value());
+
+ if ((prop = node.property (X_("channel"))) == 0) {
+ return -1;
+ }
+ _channel = atoi (prop->value());
+
+ return 0;
+}
--- /dev/null
+/*
+ Copyright (C) 2014 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 "evoral/MIDIEvent.hpp"
+#include "midi++/parser.h"
+#include "midi++/port.h"
+
+#include "ardour/event_type_map.h"
+#include "ardour/midi_port.h"
+#include "ardour/midi_scene_change.h"
+#include "ardour/midi_scene_changer.h"
+#include "ardour/session.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+
+MIDISceneChanger::MIDISceneChanger (Session& s)
+ : SceneChanger (s)
+ , _recording (true)
+ , last_bank_message_time (-1)
+ , last_program_message_time (-1)
+ , last_delivered_program (-1)
+ , last_delivered_bank (-1)
+
+{
+ _session.locations()->changed.connect_same_thread (*this, boost::bind (&MIDISceneChanger::locations_changed, this, _1));
+ Location::scene_changed.connect_same_thread (*this, boost::bind (&MIDISceneChanger::gather, this));
+}
+
+MIDISceneChanger::~MIDISceneChanger ()
+{
+}
+
+void
+MIDISceneChanger::locations_changed (Locations::Change)
+{
+ gather ();
+}
+
+/** Use the session's list of locations to collect all patch changes.
+ *
+ * This is called whenever the locations change in anyway.
+ */
+void
+MIDISceneChanger::gather ()
+{
+ const Locations::LocationList& locations (_session.locations()->list());
+ boost::shared_ptr<SceneChange> sc;
+
+ scenes.clear ();
+
+ for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) {
+
+ if ((sc = (*l)->scene_change()) != 0) {
+
+ boost::shared_ptr<MIDISceneChange> msc = boost::dynamic_pointer_cast<MIDISceneChange> (sc);
+
+ if (msc) {
+ scenes.insert (std::make_pair (msc->time(), msc));
+ }
+ }
+ }
+}
+
+void
+MIDISceneChanger::deliver (MidiBuffer& mbuf, framepos_t when, boost::shared_ptr<MIDISceneChange> msc)
+{
+ uint8_t buf[4];
+ size_t cnt;
+
+ if ((cnt = msc->get_bank_msb_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+
+ if ((cnt = msc->get_bank_lsb_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+ }
+
+ last_delivered_bank = msc->bank();
+ }
+
+ if ((cnt = msc->get_program_message (buf, sizeof (buf))) > 0) {
+ mbuf.push_back (when, cnt, buf);
+
+ last_delivered_program = msc->program();
+ }
+}
+
+
+void
+MIDISceneChanger::run (framepos_t start, framepos_t end)
+{
+ if (!output_port || recording()) {
+ return;
+ }
+
+ /* get lower bound of events to consider */
+
+ Scenes::const_iterator i = scenes.lower_bound (start);
+ MidiBuffer& mbuf (output_port->get_midi_buffer (end-start));
+
+ while (i != scenes.end()) {
+
+ if (i->first >= end) {
+ break;
+ }
+
+ deliver (mbuf, i->first - start, i->second);
+
+ ++i;
+ }
+}
+
+void
+MIDISceneChanger::locate (framepos_t pos)
+{
+ Scenes::const_iterator i = scenes.upper_bound (pos);
+
+ if (i == scenes.end()) {
+ return;
+ }
+
+ if (i->second->program() != last_delivered_program || i->second->bank() != last_delivered_bank) {
+ // MidiBuffer& mbuf (output_port->get_midi_buffer (end-start));
+ // deliver (mbuf, i->first, i->second);
+ }
+}
+
+void
+MIDISceneChanger::set_input_port (MIDI::Port* mp)
+{
+ input_port = mp;
+
+ incoming_bank_change_connection.disconnect ();
+ incoming_program_change_connection.disconnect ();
+
+ if (input_port) {
+
+ /* midi port is asynchronous. MIDI parsing will be carried out
+ * by the MIDI UI thread which will emit the relevant signals
+ * and thus invoke our callbacks as necessary.
+ */
+
+ input_port->parser()->bank_change.connect_same_thread (incoming_bank_change_connection, boost::bind (&MIDISceneChanger::bank_change_input, this, _1, _2));
+ input_port->parser()->program_change.connect_same_thread (incoming_program_change_connection, boost::bind (&MIDISceneChanger::program_change_input, this, _1, _2));
+ }
+}
+
+void
+MIDISceneChanger::set_output_port (boost::shared_ptr<MidiPort> mp)
+{
+ output_port = mp;
+}
+
+void
+MIDISceneChanger::set_recording (bool yn)
+{
+ _recording = yn;
+}
+
+bool
+MIDISceneChanger::recording() const
+{
+ return _session.transport_rolling() && _session.get_record_enabled();
+}
+
+void
+MIDISceneChanger::bank_change_input (MIDI::Parser& parser, unsigned short bank)
+{
+ if (!recording()) {
+ return;
+ }
+
+ last_bank_message_time = parser.get_timestamp ();
+ current_bank = bank;
+}
+
+void
+MIDISceneChanger::program_change_input (MIDI::Parser& parser, MIDI::byte program)
+{
+ framecnt_t time = parser.get_timestamp ();
+ frameoffset_t delta = time - last_program_message_time;
+
+ last_program_message_time = time;
+
+ if (!recording()) {
+ jump_to (current_bank, program);
+ return;
+ }
+
+ Locations* locations (_session.locations ());
+ Location* loc;
+ bool new_mark = false;
+ framecnt_t slop = (framecnt_t) floor ((Config->get_inter_scene_gap_msecs() / 1000.0) * _session.frame_rate());
+
+ /* check for marker at current location */
+
+ loc = locations->mark_at (time, slop);
+
+ if (!loc) {
+ /* create a new marker at the desired position */
+
+ std::string new_name;
+
+ if (!locations->next_available_name (new_name, _("Scene "))) {
+ std::cerr << "No new marker name available\n";
+ return;
+ }
+
+ loc = new Location (_session, time, time, new_name, Location::IsMark);
+ new_mark = true;
+ }
+
+ uint8_t bank;
+ uint8_t channel = (program & 0xf0) >> 8;
+
+ /* if we received a bank change message within the last 2 msec, use the
+ * current bank value, otherwise lookup the current bank number and use
+ * that.
+ */
+
+ if (time - last_bank_message_time < (2 * _session.frame_rate() / 1000.0)) {
+ bank = current_bank;
+ } else {
+ bank = -1;
+ }
+
+ MIDISceneChange* msc =new MIDISceneChange (loc->start(), channel, bank, program & 0x7f);
+
+ loc->set_scene_change (boost::shared_ptr<MIDISceneChange> (msc));
+
+ /* this will generate a "changed" signal to be emitted by locations,
+ and we will call ::gather() to update our list of MIDI events.
+ */
+
+ if (new_mark) {
+ locations->add (loc);
+ }
+}
+
+void
+MIDISceneChanger::jump_to (int bank, int program)
+{
+ const Locations::LocationList& locations (_session.locations()->list());
+ boost::shared_ptr<SceneChange> sc;
+ framepos_t where = max_framepos;
+
+ for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) {
+
+ if ((sc = (*l)->scene_change()) != 0) {
+
+ boost::shared_ptr<MIDISceneChange> msc = boost::dynamic_pointer_cast<MIDISceneChange> (sc);
+
+ if (msc->bank() == bank && msc->program() == program && (*l)->start() < where) {
+ where = (*l)->start();
+ }
+ }
+ }
+
+ if (where != max_framepos) {
+ _session.request_locate (where);
+ }
+}
if ((p = dynamic_cast<AsyncMIDIPort*> (_session.mmc_input_port()))) {
ports.push_back (p);
}
+
+ if ((p = dynamic_cast<AsyncMIDIPort*> (_session.scene_input_port()))) {
+ ports.push_back (p);
+ }
if (ports.empty()) {
return;
if (_midi_in) {
AudioEngine::instance()->unregister_port (_midi_in);
}
- if (_midi_in) {
- AudioEngine::instance()->unregister_port (_midi_in);
+ if (_midi_out) {
+ AudioEngine::instance()->unregister_port (_midi_out);
+ }
+ if (_scene_in) {
+ AudioEngine::instance()->unregister_port (_scene_in);
+ }
+ if (_scene_out) {
+ AudioEngine::instance()->unregister_port (_scene_out);
}
if (_mtc_input_port) {
AudioEngine::instance()->unregister_port (_mtc_input_port);
_mmc_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("MMC in"), true);
_mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("MMC out"), true);
-
+
+ _scene_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Scene in"), true);
+ _scene_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Scene out"), true);
+
/* XXX nasty type conversion needed because of the mixed inheritance
* required to integrate MIDI::IPMidiPort and ARDOUR::AsyncMIDIPort.
*
_mmc_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_in).get();
_mmc_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_mmc_out).get();
+ _scene_input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_scene_in).get();
+ _scene_output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_scene_out).get();
+
/* Now register ports used for sync (MTC and MIDI Clock)
*/
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
+ ports.insert (make_pair (_scene_output_port->name(), _scene_out));
+ ports.insert (make_pair (_scene_input_port->name(), _scene_in));
for (XMLNodeList::const_iterator n = nodes.begin(); n != nodes.end(); ++n) {
if ((prop = (*n)->property (X_("name"))) == 0) {
ports.insert (make_pair (_midi_output_port->name(), _midi_out));
ports.insert (make_pair (_mmc_input_port->name(), _mmc_in));
ports.insert (make_pair (_mmc_output_port->name(), _mmc_out));
+ ports.insert (make_pair (_scene_output_port->name(), _scene_out));
+ ports.insert (make_pair (_scene_input_port->name(), _scene_in));
for (PortMap::const_iterator p = ports.begin(); p != ports.end(); ++p) {
s.push_back (&p->second->get_state());
--- /dev/null
+/*
+ Copyright (C) 2014 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 "ardour/midi_scene_change.h"
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace ARDOUR;
+
+std::string SceneChange::xml_node_name = X_("SceneChange");
+
+boost::shared_ptr<SceneChange>
+SceneChange::factory (const XMLNode& node, int version)
+{
+ const XMLProperty* prop = node.property (X_("type"));
+
+ if (prop->value() == X_("MIDI")) {
+ return boost::shared_ptr<SceneChange> (new MIDISceneChange (node, version));
+ }
+
+ return boost::shared_ptr<SceneChange>();
+}
+
+void
+SceneChange::set_time (framepos_t t)
+{
+ _time = t;
+}
#include "ardour/filename_extensions.h"
#include "ardour/graph.h"
#include "ardour/midiport_manager.h"
+#include "ardour/scene_changer.h"
#include "ardour/midi_track.h"
#include "ardour/midi_ui.h"
#include "ardour/operations.h"
, _speakers (new Speakers)
, _order_hint (0)
, ignore_route_processor_changes (false)
+ , _scene_changer (0)
, _midi_ports (0)
, _mmc (0)
{
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();
+ delete _scene_changer; _scene_changer = 0;
+
delete _mmc; _mmc = 0;
delete _midi_ports; _midi_ports = 0;
delete _locations; _locations = 0;
{
return _midi_ports->mmc_input_port ();
}
+
+MIDI::Port*
+Session::scene_output_port () const
+{
+ return _midi_ports->scene_output_port ();
+}
+
+MIDI::Port*
+Session::scene_input_port () const
+{
+ return _midi_ports->scene_input_port ();
+}
+
+boost::shared_ptr<MidiPort>
+Session::scene_in () const
+{
+ return _midi_ports->scene_in ();
+}
+
+boost::shared_ptr<MidiPort>
+Session::scene_out () const
+{
+ return _midi_ports->scene_out ();
+}
#include "ardour/graph.h"
#include "ardour/port.h"
#include "ardour/process_thread.h"
+#include "ardour/scene_changer.h"
#include "ardour/session.h"
#include "ardour/slave.h"
#include "ardour/ticker.h"
if (!_silent && !_engine.freewheeling() && Config->get_send_midi_clock() && (transport_speed() == 1.0f || transport_speed() == 0.0f) && midi_clock->has_midi_port()) {
midi_clock->tick (transport_at_start, nframes);
}
+
+ _scene_changer->run (transport_at_start, transport_at_start + nframes);
+
} catch (...) {
/* don't bother with a message */
}
#include "pbd/localtime_r.h"
#include "ardour/amp.h"
+#include "ardour/async_midi_port.h"
#include "ardour/audio_diskstream.h"
#include "ardour/audio_track.h"
#include "ardour/audioengine.h"
#include "ardour/midi_model.h"
#include "ardour/midi_patch_manager.h"
#include "ardour/midi_region.h"
+#include "ardour/midi_scene_changer.h"
#include "ardour/midi_source.h"
#include "ardour/midi_track.h"
#include "ardour/pannable.h"
BootMessage (_("Using configuration"));
_midi_ports = new MidiPortManager;
+
+ MIDISceneChanger* msc;
+
+ _scene_changer = msc = new MIDISceneChanger (*this);
+ msc->set_input_port (scene_input_port());
+ msc->set_output_port (scene_out());
+
+ boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
+ boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
+
setup_midi_machine_control ();
if (_butler->start_thread()) {
'midi_port.cc',
'midi_region.cc',
'midi_ring_buffer.cc',
+ 'midi_scene_change.cc',
+ 'midi_scene_changer.cc',
'midi_source.cc',
'midi_state_tracker.cc',
'midi_stretch.cc',
'route_group.cc',
'route_group_member.cc',
'rb_effect.cc',
+ 'scene_change.cc',
'search_paths.cc',
'send.cc',
'session.cc',
obj.use.extend(['librubberband', 'libltc_includes', 'libltc'])
obj.vnum = LIBARDOUR_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.defines += [
'PACKAGE="' + I18N_PACKAGE + '"',
'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"',
testobj.name = name
testobj.target = target
# not sure about install path
- testobj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ testobj.install_path = bld.env['LIBDIR']
testobj.defines = [
'PACKAGE="libardour3test"',
'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"',
audiographer.uselib = 'GLIB GLIBMM GTHREAD SAMPLERATE SNDFILE'
audiographer.use = 'libpbd'
audiographer.vnum = AUDIOGRAPHER_LIB_VERSION
- audiographer.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ audiographer.install_path = bld.env['LIBDIR']
if bld.env['BUILD_TESTS'] and bld.is_defined('HAVE_CPPUNIT'):
--- /dev/null
+/*
+ * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2013 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 <sys/time.h>
+#include <regex.h>
+
+#include "dummy_audiobackend.h"
+#include "pbd/error.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)
+ , _running (false)
+ , _freewheeling (false)
+ , _samplerate (48000)
+ , _samples_per_period (1024)
+ , _dsp_load (0)
+ , _n_inputs (0)
+ , _n_outputs (0)
+ , _systemic_input_latency (0)
+ , _systemic_output_latency (0)
+ , _processed_samples (0)
+{
+ _instance_name = s_instance_name;
+}
+
+DummyAudioBackend::~DummyAudioBackend ()
+{
+}
+
+/* AUDIOBACKEND API */
+
+std::string
+DummyAudioBackend::name () const
+{
+ return X_("Dummy");
+}
+
+bool
+DummyAudioBackend::is_realtime () const
+{
+ return false;
+}
+
+std::vector<AudioBackend::DeviceStatus>
+DummyAudioBackend::enumerate_devices () const
+{
+ std::vector<AudioBackend::DeviceStatus> s;
+ s.push_back (DeviceStatus (_("Dummy"), true));
+ return s;
+}
+
+std::vector<float>
+DummyAudioBackend::available_sample_rates (const std::string&) const
+{
+ std::vector<float> sr;
+ sr.push_back (8000.0);
+ sr.push_back (22050.0);
+ sr.push_back (24000.0);
+ sr.push_back (44100.0);
+ sr.push_back (48000.0);
+ sr.push_back (88200.0);
+ sr.push_back (96000.0);
+ sr.push_back (176400.0);
+ sr.push_back (192000.0);
+ return sr;
+}
+
+std::vector<uint32_t>
+DummyAudioBackend::available_buffer_sizes (const std::string&) const
+{
+ std::vector<uint32_t> bs;
+ bs.push_back (4);
+ bs.push_back (8);
+ bs.push_back (16);
+ bs.push_back (32);
+ bs.push_back (64);
+ bs.push_back (128);
+ bs.push_back (256);
+ bs.push_back (512);
+ bs.push_back (1024);
+ bs.push_back (2048);
+ bs.push_back (4096);
+ bs.push_back (8192);
+ return bs;
+}
+
+uint32_t
+DummyAudioBackend::available_input_channel_count (const std::string&) const
+{
+ return 128;
+}
+
+uint32_t
+DummyAudioBackend::available_output_channel_count (const std::string&) const
+{
+ return 128;
+}
+
+bool
+DummyAudioBackend::can_change_sample_rate_when_running () const
+{
+ return true;
+}
+
+bool
+DummyAudioBackend::can_change_buffer_size_when_running () const
+{
+ return true;
+}
+
+int
+DummyAudioBackend::set_device_name (const std::string&)
+{
+ return 0;
+}
+
+int
+DummyAudioBackend::set_sample_rate (float sr)
+{
+ if (sr <= 0) { return -1; }
+ _samplerate = sr;
+ engine.sample_rate_change (sr);
+ return 0;
+}
+
+int
+DummyAudioBackend::set_buffer_size (uint32_t bs)
+{
+ if (bs <= 0 || bs >= _max_buffer_size) {
+ return -1;
+ }
+ _samples_per_period = bs;
+ engine.buffer_size_change (bs);
+ return 0;
+}
+
+int
+DummyAudioBackend::set_interleaved (bool yn)
+{
+ if (!yn) { return 0; }
+ return -1;
+}
+
+int
+DummyAudioBackend::set_input_channels (uint32_t cc)
+{
+ _n_inputs = cc;
+ return 0;
+}
+
+int
+DummyAudioBackend::set_output_channels (uint32_t cc)
+{
+ _n_outputs = cc;
+ return 0;
+}
+
+int
+DummyAudioBackend::set_systemic_input_latency (uint32_t sl)
+{
+ _systemic_input_latency = sl;
+ return 0;
+}
+
+int
+DummyAudioBackend::set_systemic_output_latency (uint32_t sl)
+{
+ _systemic_output_latency = sl;
+ return 0;
+}
+
+/* Retrieving parameters */
+std::string
+DummyAudioBackend::device_name () const
+{
+ return _("Dummy Device");
+}
+
+float
+DummyAudioBackend::sample_rate () const
+{
+ return _samplerate;
+}
+
+uint32_t
+DummyAudioBackend::buffer_size () const
+{
+ return _samples_per_period;
+}
+
+bool
+DummyAudioBackend::interleaved () const
+{
+ return false;
+}
+
+uint32_t
+DummyAudioBackend::input_channels () const
+{
+ return _n_inputs;
+}
+
+uint32_t
+DummyAudioBackend::output_channels () const
+{
+ return _n_outputs;
+}
+
+uint32_t
+DummyAudioBackend::systemic_input_latency () const
+{
+ return _systemic_input_latency;
+}
+
+uint32_t
+DummyAudioBackend::systemic_output_latency () const
+{
+ return _systemic_output_latency;
+}
+
+/* MIDI */
+std::vector<std::string>
+DummyAudioBackend::enumerate_midi_options () const
+{
+ std::vector<std::string> m;
+ m.push_back (_("None"));
+ return m;
+}
+
+int
+DummyAudioBackend::set_midi_option (const std::string&)
+{
+ return -1;
+}
+
+std::string
+DummyAudioBackend::midi_option () const
+{
+ return "";
+}
+
+/* State Control */
+
+static void * pthread_process (void *arg)
+{
+ DummyAudioBackend *d = static_cast<DummyAudioBackend *>(arg);
+ d->main_process_thread ();
+ pthread_exit (0);
+ return 0;
+}
+
+int
+DummyAudioBackend::_start (bool /*for_latency_measurement*/)
+{
+ if (_running) {
+ PBD::error << _("DummyAudioBackend: already active.") << endmsg;
+ return -1;
+ }
+
+ if (_ports.size()) {
+ PBD::warning << _("DummyAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
+ _ports.clear();
+ }
+
+ if (register_system_ports()) {
+ PBD::error << _("DummyAudioBackend: failed to register system ports.") << endmsg;
+ return -1;
+ }
+
+ if (engine.reestablish_ports ()) {
+ PBD::error << _("DummyAudioBackend: Could not re-establish ports.") << endmsg;
+ stop ();
+ return -1;
+ }
+
+ engine.reconnect_ports ();
+
+ if (pthread_create (&_main_thread, NULL, pthread_process, this)) {
+ PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
+ }
+
+ int timeout = 5000;
+ while (!_running && --timeout > 0) { usleep (1000); }
+
+ if (timeout == 0 || !_running) {
+ PBD::error << _("DummyAudioBackend: failed to start process thread.") << endmsg;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+DummyAudioBackend::stop ()
+{
+ void *status;
+ if (!_running) {
+ return -1;
+ }
+
+ _running = false;
+ if (pthread_join (_main_thread, &status)) {
+ PBD::error << _("DummyAudioBackend: failed to terminate.") << endmsg;
+ return -1;
+ }
+ unregister_system_ports();
+ return 0;
+}
+
+int
+DummyAudioBackend::freewheel (bool onoff)
+{
+ if (onoff == _freewheeling) {
+ return 0;
+ }
+ _freewheeling = onoff;
+ engine.freewheel_callback (onoff);
+ return 0;
+}
+
+float
+DummyAudioBackend::dsp_load () const
+{
+ return 100.f * _dsp_load;
+}
+
+size_t
+DummyAudioBackend::raw_buffer_size (DataType t)
+{
+ switch (t) {
+ case DataType::AUDIO:
+ return _max_buffer_size * sizeof(Sample);
+ case DataType::MIDI:
+ return _max_buffer_size; // XXX not really limited
+ }
+ return 0;
+}
+
+/* Process time */
+pframes_t
+DummyAudioBackend::sample_time ()
+{
+ return _processed_samples;
+}
+
+pframes_t
+DummyAudioBackend::sample_time_at_cycle_start ()
+{
+ return _processed_samples;
+}
+
+pframes_t
+DummyAudioBackend::samples_since_cycle_start ()
+{
+ return 0;
+}
+
+
+void *
+DummyAudioBackend::dummy_process_thread (void *arg)
+{
+ ThreadData* td = reinterpret_cast<ThreadData*> (arg);
+ boost::function<void ()> f = td->f;
+ delete td;
+ f ();
+ return 0;
+}
+
+int
+DummyAudioBackend::create_process_thread (boost::function<void()> func)
+{
+ pthread_t thread_id;
+ pthread_attr_t attr;
+ size_t stacksize = 100000;
+
+ pthread_attr_init (&attr);
+ pthread_attr_setstacksize (&attr, stacksize);
+ ThreadData* td = new ThreadData (this, func, stacksize);
+
+ if (pthread_create (&thread_id, &attr, dummy_process_thread, td)) {
+ PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
+ return -1;
+ }
+
+ _threads.push_back (thread_id);
+ return 0;
+}
+
+int
+DummyAudioBackend::join_process_threads ()
+{
+ int rv = 0;
+
+ for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
+ {
+ void *status;
+ if (pthread_join (*i, &status)) {
+ PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
+ rv -= 1;
+ }
+ }
+ _threads.clear ();
+ return rv;
+}
+
+bool
+DummyAudioBackend::in_process_thread ()
+{
+ 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;
+}
+
+uint32_t
+DummyAudioBackend::process_thread_count ()
+{
+ return _threads.size ();
+}
+
+void
+DummyAudioBackend::update_latencies ()
+{
+}
+
+/* PORTENGINE API */
+
+void*
+DummyAudioBackend::private_handle () const
+{
+ return NULL;
+}
+
+const std::string&
+DummyAudioBackend::my_name () const
+{
+ return _instance_name;
+}
+
+bool
+DummyAudioBackend::available () const
+{
+ return true;
+}
+
+uint32_t
+DummyAudioBackend::port_name_size () const
+{
+ return 256;
+}
+
+int
+DummyAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::set_port_name: Invalid Port(s)") << endmsg;
+ return -1;
+ }
+ return static_cast<DummyPort*>(port)->set_name (_instance_name + ":" + name);
+}
+
+std::string
+DummyAudioBackend::get_port_name (PortEngine::PortHandle port) const
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::get_port_name: Invalid Port(s)") << endmsg;
+ return std::string ();
+ }
+ return static_cast<DummyPort*>(port)->name ();
+}
+
+PortEngine::PortHandle
+DummyAudioBackend::get_port_by_name (const std::string& name) const
+{
+ PortHandle port = (PortHandle) find_port (name);
+ return port;
+}
+
+int
+DummyAudioBackend::get_ports (
+ const std::string& port_name_pattern,
+ DataType type, PortFlags flags,
+ std::vector<std::string>& port_names) const
+{
+ int rv = 0;
+ regex_t port_regex;
+ bool use_regexp = false;
+ if (port_name_pattern.size () > 0) {
+ if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
+ use_regexp = true;
+ }
+ }
+ for (size_t i = 0; i < _ports.size (); ++i) {
+ DummyPort* port = _ports[i];
+ if ((port->type () == type) && (port->flags () & flags)) {
+ if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
+ port_names.push_back (port->name ());
+ ++rv;
+ }
+ }
+ }
+ if (use_regexp) {
+ regfree (&port_regex);
+ }
+ return rv;
+}
+
+DataType
+DummyAudioBackend::port_data_type (PortEngine::PortHandle port) const
+{
+ if (!valid_port (port)) {
+ return DataType::NIL;
+ }
+ return static_cast<DummyPort*>(port)->type ();
+}
+
+PortEngine::PortHandle
+DummyAudioBackend::register_port (
+ const std::string& name,
+ ARDOUR::DataType type,
+ ARDOUR::PortFlags flags)
+{
+ if (name.size () == 0) { return 0; }
+ if (flags & IsPhysical) { return 0; }
+ return add_port (_instance_name + ":" + name, type, flags);
+}
+
+PortEngine::PortHandle
+DummyAudioBackend::add_port (
+ const std::string& name,
+ ARDOUR::DataType type,
+ ARDOUR::PortFlags flags)
+{
+ assert(name.size ());
+ if (find_port (name)) {
+ PBD::error << _("DummyBackend::register_port: Port already exists:")
+ << " (" << name << ")" << endmsg;
+ return 0;
+ }
+ DummyPort* port = NULL;
+ switch (type) {
+ case DataType::AUDIO:
+ port = new DummyAudioPort (name, flags);
+ break;
+ case DataType::MIDI:
+ port = new DummyMidiPort (name, flags);
+ break;
+ default:
+ PBD::error << _("DummyBackend::register_port: Invalid Data Type.") << endmsg;
+ return 0;
+ }
+
+ _ports.push_back (port);
+
+ return port;
+}
+
+void
+DummyAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
+{
+ if (!valid_port (port_handle)) {
+ PBD::error << _("DummyBackend::unregister_port: Invalid Port.") << endmsg;
+ }
+ DummyPort* port = static_cast<DummyPort*>(port_handle);
+ std::vector<DummyPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<DummyPort*>(port_handle));
+ if (i == _ports.end ()) {
+ PBD::error << _("DummyBackend::unregister_port: Failed to find port") << endmsg;
+ return;
+ }
+ disconnect_all(port_handle);
+ _ports.erase (i);
+ delete port;
+}
+
+int
+DummyAudioBackend::register_system_ports()
+{
+ LatencyRange lr;
+
+ 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;
+
+ /* audio ports */
+ lr.min = lr.max = _samples_per_period + _systemic_input_latency;
+ for (int i = 1; i <= a_ins; ++i) {
+ char tmp[64];
+ snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
+ PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
+ if (!p) return -1;
+ set_latency_range (p, false, lr);
+ }
+
+ lr.min = lr.max = _samples_per_period + _systemic_output_latency;
+ for (int i = 1; i <= a_out; ++i) {
+ char tmp[64];
+ 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);
+ }
+
+ /* midi ports */
+ lr.min = lr.max = _samples_per_period + _systemic_input_latency;
+ for (int i = 1; i <= m_ins; ++i) {
+ char tmp[64];
+ snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
+ PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
+ if (!p) return -1;
+ set_latency_range (p, false, lr);
+ }
+
+ lr.min = lr.max = _samples_per_period + _systemic_output_latency;
+ for (int i = 1; i <= m_out; ++i) {
+ char tmp[64];
+ 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);
+ }
+
+ return 0;
+}
+
+void
+DummyAudioBackend::unregister_system_ports()
+{
+ size_t i = 0;
+ while (i < _ports.size ()) {
+ DummyPort* port = _ports[i];
+ if (port->is_physical () && port->is_terminal ()) {
+ port->disconnect_all ();
+ _ports.erase (_ports.begin() + i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+int
+DummyAudioBackend::connect (const std::string& src, const std::string& dst)
+{
+ DummyPort* src_port = find_port (src);
+ DummyPort* dst_port = find_port (dst);
+
+ if (!src_port) {
+ PBD::error << _("DummyBackend::connect: Invalid Source port:")
+ << " (" << src <<")" << endmsg;
+ return -1;
+ }
+ if (!dst_port) {
+ PBD::error << _("DummyBackend::connect: Invalid Destination port:")
+ << " (" << dst <<")" << endmsg;
+ return -1;
+ }
+ return src_port->connect (dst_port);
+}
+
+int
+DummyAudioBackend::disconnect (const std::string& src, const std::string& dst)
+{
+ DummyPort* src_port = find_port (src);
+ DummyPort* dst_port = find_port (dst);
+
+ if (!src_port || !dst_port) {
+ PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
+ return -1;
+ }
+ return src_port->disconnect (dst_port);
+}
+
+int
+DummyAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
+{
+ DummyPort* dst_port = find_port (dst);
+ if (!valid_port (src)) {
+ PBD::error << _("DummyBackend::connect: Invalid Source Port Handle") << endmsg;
+ return -1;
+ }
+ if (!dst_port) {
+ PBD::error << _("DummyBackend::connect: Invalid Destination Port")
+ << " (" << dst << ")" << endmsg;
+ return -1;
+ }
+ return static_cast<DummyPort*>(src)->connect (dst_port);
+}
+
+int
+DummyAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
+{
+ DummyPort* dst_port = find_port (dst);
+ if (!valid_port (src) || !dst_port) {
+ PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
+ return -1;
+ }
+ return static_cast<DummyPort*>(src)->disconnect (dst_port);
+}
+
+int
+DummyAudioBackend::disconnect_all (PortEngine::PortHandle port)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
+ return -1;
+ }
+ static_cast<DummyPort*>(port)->disconnect_all ();
+ return 0;
+}
+
+bool
+DummyAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
+ return false;
+ }
+ return static_cast<DummyPort*>(port)->is_connected ();
+}
+
+bool
+DummyAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
+{
+ DummyPort* dst_port = find_port (dst);
+ if (!valid_port (src) || !dst_port) {
+ PBD::error << _("DummyBackend::connected_to: Invalid Port") << endmsg;
+ return false;
+ }
+ return static_cast<DummyPort*>(src)->is_connected (dst_port);
+}
+
+bool
+DummyAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::physically_connected: Invalid Port") << endmsg;
+ return false;
+ }
+ return static_cast<DummyPort*>(port)->is_physically_connected ();
+}
+
+int
+DummyAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyBackend::get_connections: Invalid Port") << endmsg;
+ return -1;
+ }
+
+ assert (0 == names.size ());
+
+ const std::vector<DummyPort*>& connected_ports = static_cast<DummyPort*>(port)->get_connections ();
+
+ for (std::vector<DummyPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
+ names.push_back ((*i)->name ());
+ }
+
+ return (int)names.size ();
+}
+
+/* MIDI */
+int
+DummyAudioBackend::midi_event_get (
+ pframes_t& timestamp,
+ size_t& size, uint8_t** buf, void* port_buffer,
+ uint32_t event_index)
+{
+ assert (buf && port_buffer);
+ DummyMidiBuffer& source = * static_cast<DummyMidiBuffer*>(port_buffer);
+ if (event_index >= source.size ()) {
+ return -1;
+ }
+ DummyMidiEvent * const event = source[event_index].get ();
+
+ timestamp = event->timestamp ();
+ size = event->size ();
+ *buf = event->data ();
+ return 0;
+}
+
+int
+DummyAudioBackend::midi_event_put (
+ void* port_buffer,
+ pframes_t timestamp,
+ const uint8_t* buffer, size_t size)
+{
+ assert (buffer && port_buffer);
+ DummyMidiBuffer& dst = * static_cast<DummyMidiBuffer*>(port_buffer);
+ if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
+ fprintf (stderr, "DummyMidiBuffer: it's too late for this event.\n");
+ return -1;
+ }
+ dst.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (timestamp, buffer, size)));
+ return 0;
+}
+
+uint32_t
+DummyAudioBackend::get_midi_event_count (void* port_buffer)
+{
+ assert (port_buffer && _running);
+ return static_cast<DummyMidiBuffer*>(port_buffer)->size ();
+}
+
+void
+DummyAudioBackend::midi_clear (void* port_buffer)
+{
+ assert (port_buffer && _running);
+ DummyMidiBuffer * buf = static_cast<DummyMidiBuffer*>(port_buffer);
+ assert (buf);
+ buf->clear ();
+}
+
+/* Monitoring */
+
+bool
+DummyAudioBackend::can_monitor_input () const
+{
+ return false;
+}
+
+int
+DummyAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
+{
+ return -1;
+}
+
+int
+DummyAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
+{
+ return -1;
+}
+
+bool
+DummyAudioBackend::monitoring_input (PortEngine::PortHandle)
+{
+ return false;
+}
+
+/* Latency management */
+
+void
+DummyAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyPort::set_latency_range (): invalid port.") << endmsg;
+ }
+ static_cast<DummyPort*>(port)->set_latency_range (latency_range, for_playback);
+}
+
+LatencyRange
+DummyAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyPort::get_latency_range (): invalid port.") << endmsg;
+ LatencyRange r;
+ r.min = 0;
+ r.max = 0;
+ return r;
+ }
+ return static_cast<DummyPort*>(port)->latency_range (for_playback);
+}
+
+/* Discovering physical ports */
+
+bool
+DummyAudioBackend::port_is_physical (PortEngine::PortHandle port) const
+{
+ if (!valid_port (port)) {
+ PBD::error << _("DummyPort::port_is_physical (): invalid port.") << endmsg;
+ return false;
+ }
+ return static_cast<DummyPort*>(port)->is_physical ();
+}
+
+void
+DummyAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
+{
+ for (size_t i = 0; i < _ports.size (); ++i) {
+ DummyPort* port = _ports[i];
+ if ((port->type () == type) && port->is_output () && port->is_physical ()) {
+ port_names.push_back (port->name ());
+ }
+ }
+}
+
+void
+DummyAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
+{
+ for (size_t i = 0; i < _ports.size (); ++i) {
+ DummyPort* port = _ports[i];
+ if ((port->type () == type) && port->is_input () && port->is_physical ()) {
+ port_names.push_back (port->name ());
+ }
+ }
+}
+
+ChanCount
+DummyAudioBackend::n_physical_outputs () const
+{
+ int n_midi = 0;
+ int n_audio = 0;
+ for (size_t i = 0; i < _ports.size (); ++i) {
+ DummyPort* port = _ports[i];
+ if (port->is_output () && port->is_physical ()) {
+ switch (port->type ()) {
+ case DataType::AUDIO: ++n_audio; break;
+ case DataType::MIDI: ++n_midi; break;
+ default: break;
+ }
+ }
+ }
+ ChanCount cc;
+ cc.set (DataType::AUDIO, n_audio);
+ cc.set (DataType::MIDI, n_midi);
+ return cc;
+}
+
+ChanCount
+DummyAudioBackend::n_physical_inputs () const
+{
+ int n_midi = 0;
+ int n_audio = 0;
+ for (size_t i = 0; i < _ports.size (); ++i) {
+ DummyPort* port = _ports[i];
+ if (port->is_input () && port->is_physical ()) {
+ switch (port->type ()) {
+ case DataType::AUDIO: ++n_audio; break;
+ case DataType::MIDI: ++n_midi; break;
+ default: break;
+ }
+ }
+ }
+ ChanCount cc;
+ cc.set (DataType::AUDIO, n_audio);
+ cc.set (DataType::MIDI, n_midi);
+ return cc;
+}
+
+/* Getting access to the data buffer for a port */
+
+void*
+DummyAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
+{
+ assert (port && _running);
+ assert (valid_port (port));
+ return static_cast<DummyPort*>(port)->get_buffer (nframes);
+}
+
+/* Engine Process */
+void *
+DummyAudioBackend::main_process_thread ()
+{
+ AudioEngine::thread_init_callback (this);
+ _running = true;
+ _processed_samples = 0;
+
+ struct timeval clock1, clock2;
+ ::gettimeofday (&clock1, NULL);
+ 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;
+ _dsp_load = elapsed_time / (float) nomial_time;
+ if (elapsed_time < nomial_time) {
+ ::usleep (nomial_time - elapsed_time);
+ } else {
+ ::usleep (100); // don't hog cpu
+ }
+ } else {
+ _dsp_load = 1.0;
+ ::usleep (100); // don't hog cpu
+ }
+ ::gettimeofday (&clock1, NULL);
+ }
+ _running = false;
+ return 0;
+}
+
+
+/******************************************************************************/
+
+static boost::shared_ptr<DummyAudioBackend> _instance;
+
+static boost::shared_ptr<AudioBackend>
+backend_factory (AudioEngine& e)
+{
+ if (!_instance) {
+ _instance.reset (new DummyAudioBackend (e));
+ }
+ return _instance;
+}
+
+static int
+instantiate (const std::string& arg1, const std::string& /* arg2 */)
+{
+ s_instance_name = arg1;
+ return 0;
+}
+
+static int
+deinstantiate ()
+{
+ _instance.reset ();
+ return 0;
+}
+
+static bool
+already_configured ()
+{
+ 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)
+ , _flags (flags)
+{
+ _capture_latency_range.min = 0;
+ _capture_latency_range.max = 0;
+ _playback_latency_range.min = 0;
+ _playback_latency_range.max = 0;
+}
+
+DummyPort::~DummyPort () {
+ disconnect_all ();
+}
+
+
+int DummyPort::connect (DummyPort *port)
+{
+ if (!port) {
+ PBD::error << _("DummyPort::connect (): invalid (null) port") << endmsg;
+ return -1;
+ }
+
+ if (type () != port->type ()) {
+ PBD::error << _("DummyPort::connect (): wrong port-type") << endmsg;
+ return -1;
+ }
+
+ if (is_output () && port->is_output ()) {
+ PBD::error << _("DummyPort::connect (): cannot inter-connect output ports.") << endmsg;
+ return -1;
+ }
+
+ if (is_input () && port->is_input ()) {
+ PBD::error << _("DummyPort::connect (): cannot inter-connect input ports.") << endmsg;
+ return -1;
+ }
+
+ if (this == port) {
+ PBD::error << _("DummyPort::connect (): cannot self-connect ports.") << endmsg;
+ return -1;
+ }
+
+ if (is_connected (port)) {
+#if 0 // don't bother to warn about this for now. just ignore it
+ PBD::error << _("DummyPort::connect (): ports are already connected:")
+ << " (" << name () << ") -> (" << port->name () << ")"
+ << endmsg;
+#endif
+ return -1;
+ }
+
+ _connect (port, true);
+ return 0;
+}
+
+
+void DummyPort::_connect (DummyPort *port, bool callback)
+{
+ _connections.push_back (port);
+ if (callback) {
+ port->_connect (this, false);
+ }
+}
+
+int DummyPort::disconnect (DummyPort *port)
+{
+ if (!port) {
+ PBD::error << _("DummyPort::disconnect (): invalid (null) port") << endmsg;
+ return -1;
+ }
+
+ if (!is_connected (port)) {
+ PBD::error << _("DummyPort::disconnect (): ports are not connected:")
+ << " (" << name () << ") -> (" << port->name () << ")"
+ << endmsg;
+ return -1;
+ }
+ _disconnect (port, true);
+ return 0;
+}
+
+void DummyPort::_disconnect (DummyPort *port, bool callback)
+{
+ std::vector<DummyPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
+
+ assert (it != _connections.end ());
+
+ _connections.erase (it);
+
+ if (callback) {
+ port->_disconnect (this, false);
+ }
+}
+
+
+void DummyPort::disconnect_all ()
+{
+ while (!_connections.empty ()) {
+ _connections.back ()->_disconnect (this, false);
+ _connections.pop_back ();
+ }
+}
+
+bool
+DummyPort::is_connected (const DummyPort *port) const
+{
+ return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
+}
+
+bool DummyPort::is_physically_connected () const
+{
+ for (std::vector<DummyPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
+ if ((*it)->is_physical ()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/******************************************************************************/
+
+DummyAudioPort::DummyAudioPort (const std::string& name, PortFlags flags)
+ : DummyPort (name, flags)
+{
+ memset (_buffer, 0, sizeof (_buffer));
+}
+
+DummyAudioPort::~DummyAudioPort () { }
+
+void* DummyAudioPort::get_buffer (pframes_t n_samples)
+{
+ if (is_input ()) {
+ std::vector<DummyPort*>::const_iterator it = get_connections ().begin ();
+ if (it == get_connections ().end ()) {
+ memset (_buffer, 0, n_samples * sizeof (Sample));
+ } else {
+ DummyAudioPort const * source = static_cast<const DummyAudioPort*>(*it);
+ assert (source && source->is_output ());
+ memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
+ while (++it != get_connections ().end ()) {
+ source = static_cast<const DummyAudioPort*>(*it);
+ assert (source && source->is_output ());
+ Sample* dst = buffer ();
+ const Sample* src = source->const_buffer ();
+ for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
+ *dst += *src;
+ }
+ }
+ }
+ } else if (is_output () && is_physical () && is_terminal()) {
+ memset (_buffer, 0, n_samples * sizeof (Sample));
+ }
+ return _buffer;
+}
+
+
+DummyMidiPort::DummyMidiPort (const std::string& name, PortFlags flags)
+ : DummyPort (name, flags)
+{
+ _buffer.clear ();
+}
+
+DummyMidiPort::~DummyMidiPort () { }
+
+void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
+{
+ if (is_input ()) {
+ _buffer.clear ();
+ for (std::vector<DummyPort*>::const_iterator i = get_connections ().begin ();
+ i != get_connections ().end ();
+ ++i) {
+ const DummyMidiBuffer src = static_cast<const DummyMidiPort*>(*i)->const_buffer ();
+ for (DummyMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
+ _buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
+ }
+ }
+ std::sort (_buffer.begin (), _buffer.end ());
+ } else if (is_output () && is_physical () && is_terminal()) {
+ _buffer.clear ();
+ }
+ return &_buffer;
+}
+
+DummyMidiEvent::DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
+ : _size (size)
+ , _timestamp (timestamp)
+ , _data (0)
+{
+ if (size > 0) {
+ _data = (uint8_t*) malloc (size);
+ memcpy (_data, data, size);
+ }
+}
+
+DummyMidiEvent::DummyMidiEvent (const DummyMidiEvent& other)
+ : _size (other.size ())
+ , _timestamp (other.timestamp ())
+ , _data (0)
+{
+ if (other.size () && other.const_data ()) {
+ _data = (uint8_t*) malloc (other.size ());
+ memcpy (_data, other.const_data (), other.size ());
+ }
+};
+
+DummyMidiEvent::~DummyMidiEvent () {
+ free (_data);
+};
--- /dev/null
+/*
+ * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2013 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 __libbackend_dummy_audiobackend_h__
+#define __libbackend_dummy_audiobackend_h__
+
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+#include <stdint.h>
+#include <pthread.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include "ardour/types.h"
+#include "ardour/audio_backend.h"
+
+namespace ARDOUR {
+
+class DummyMidiEvent {
+ public:
+ DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size);
+ DummyMidiEvent (const DummyMidiEvent& other);
+ ~DummyMidiEvent ();
+ size_t size () const { return _size; };
+ pframes_t timestamp () const { return _timestamp; };
+ const unsigned char* const_data () const { return _data; };
+ unsigned char* data () { return _data; };
+ bool operator< (const DummyMidiEvent &other) const { return timestamp () < other.timestamp (); };
+ private:
+ size_t _size;
+ pframes_t _timestamp;
+ uint8_t *_data;
+};
+
+typedef std::vector<boost::shared_ptr<DummyMidiEvent> > DummyMidiBuffer;
+
+class DummyPort {
+ protected:
+ DummyPort (const std::string&, PortFlags);
+ public:
+ virtual ~DummyPort ();
+
+ const std::string& name () const { return _name; }
+ PortFlags flags () const { return _flags; }
+
+ int set_name (const std::string &name) { _name = name; return 0; }
+
+ virtual DataType type () const = 0;
+
+ bool is_input () const { return flags () & IsInput; }
+ bool is_output () const { return flags () & IsOutput; }
+ bool is_physical () const { return flags () & IsPhysical; }
+ bool is_terminal () const { return flags () & IsTerminal; }
+ bool is_connected () const { return _connections.size () != 0; }
+ bool is_connected (const DummyPort *port) const;
+ bool is_physically_connected () const;
+
+ const std::vector<DummyPort *>& get_connections () const { return _connections; }
+
+ int connect (DummyPort *port);
+ int disconnect (DummyPort *port);
+ void disconnect_all ();
+
+ virtual void* get_buffer (pframes_t nframes) = 0;
+
+ const LatencyRange& latency_range (bool for_playback) const
+ {
+ return for_playback ? _playback_latency_range : _capture_latency_range;
+ }
+
+ void set_latency_range (const LatencyRange &latency_range, bool for_playback)
+ {
+ if (for_playback)
+ {
+ _playback_latency_range = latency_range;
+ }
+ else
+ {
+ _capture_latency_range = latency_range;
+ }
+ }
+
+ private:
+ std::string _name;
+ const PortFlags _flags;
+ LatencyRange _capture_latency_range;
+ LatencyRange _playback_latency_range;
+ std::vector<DummyPort*> _connections;
+
+ void _connect (DummyPort* , bool);
+ void _disconnect (DummyPort* , bool);
+
+}; // class DummyPort
+
+class DummyAudioPort : public DummyPort {
+ public:
+ DummyAudioPort (const std::string&, PortFlags);
+ ~DummyAudioPort ();
+
+ DataType type () const { return DataType::AUDIO; };
+
+ Sample* buffer () { return _buffer; }
+ const Sample* const_buffer () const { return _buffer; }
+ void* get_buffer (pframes_t nframes);
+
+ private:
+ Sample _buffer[8192];
+}; // class DummyAudioPort
+
+class DummyMidiPort : public DummyPort {
+ public:
+ DummyMidiPort (const std::string&, PortFlags);
+ ~DummyMidiPort ();
+
+ DataType type () const { return DataType::MIDI; };
+
+ void* get_buffer (pframes_t nframes);
+ const DummyMidiBuffer const_buffer () const { return _buffer; }
+
+ private:
+ DummyMidiBuffer _buffer;
+}; // class DummyMidiPort
+
+class DummyAudioBackend : public AudioBackend {
+ public:
+ DummyAudioBackend (AudioEngine& e);
+ ~DummyAudioBackend ();
+
+ /* AUDIOBACKEND API */
+
+ std::string name () const;
+ bool is_realtime () const;
+
+ std::vector<DeviceStatus> enumerate_devices () const;
+ std::vector<float> available_sample_rates (const std::string& device) const;
+ std::vector<uint32_t> available_buffer_sizes (const std::string& device) const;
+ uint32_t available_input_channel_count (const std::string& device) const;
+ uint32_t available_output_channel_count (const std::string& device) const;
+
+ bool can_change_sample_rate_when_running () const;
+ bool can_change_buffer_size_when_running () const;
+
+ int set_device_name (const std::string&);
+ int set_sample_rate (float);
+ int set_buffer_size (uint32_t);
+ int set_interleaved (bool yn);
+ int set_input_channels (uint32_t);
+ int set_output_channels (uint32_t);
+ int set_systemic_input_latency (uint32_t);
+ int set_systemic_output_latency (uint32_t);
+
+ /* Retrieving parameters */
+ std::string device_name () const;
+ float sample_rate () const;
+ uint32_t buffer_size () const;
+ bool interleaved () const;
+ uint32_t input_channels () const;
+ uint32_t output_channels () const;
+ uint32_t systemic_input_latency () const;
+ uint32_t systemic_output_latency () const;
+
+ /* External control app */
+ std::string control_app_name () const { return std::string (); }
+ void launch_control_app () {}
+
+ /* MIDI */
+ std::vector<std::string> enumerate_midi_options () const;
+ int set_midi_option (const std::string&);
+ std::string midi_option () const;
+
+ /* State Control */
+ protected:
+ int _start (bool for_latency_measurement);
+ public:
+ int stop ();
+ int freewheel (bool);
+ float dsp_load () const;
+ size_t raw_buffer_size (DataType t);
+
+ /* Process time */
+ pframes_t sample_time ();
+ pframes_t sample_time_at_cycle_start ();
+ pframes_t samples_since_cycle_start ();
+
+ int create_process_thread (boost::function<void()> func);
+ int join_process_threads ();
+ bool in_process_thread ();
+ uint32_t process_thread_count ();
+
+ void update_latencies ();
+
+ /* PORTENGINE API */
+
+ void* private_handle () const;
+ const std::string& my_name () const;
+ bool available () const;
+ uint32_t port_name_size () const;
+
+ int set_port_name (PortHandle, const std::string&);
+ std::string get_port_name (PortHandle) const;
+ PortHandle get_port_by_name (const std::string&) const;
+
+ int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&) const;
+
+ DataType port_data_type (PortHandle) const;
+
+ PortHandle register_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
+ void unregister_port (PortHandle);
+
+ int connect (const std::string& src, const std::string& dst);
+ int disconnect (const std::string& src, const std::string& dst);
+ int connect (PortHandle, const std::string&);
+ int disconnect (PortHandle, const std::string&);
+ int disconnect_all (PortHandle);
+
+ bool connected (PortHandle, bool process_callback_safe);
+ bool connected_to (PortHandle, const std::string&, bool process_callback_safe);
+ bool physically_connected (PortHandle, bool process_callback_safe);
+ int get_connections (PortHandle, std::vector<std::string>&, bool process_callback_safe);
+
+ /* MIDI */
+ int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index);
+ int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size);
+ uint32_t get_midi_event_count (void* port_buffer);
+ void midi_clear (void* port_buffer);
+
+ /* Monitoring */
+
+ bool can_monitor_input () const;
+ int request_input_monitoring (PortHandle, bool);
+ int ensure_input_monitoring (PortHandle, bool);
+ bool monitoring_input (PortHandle);
+
+ /* Latency management */
+
+ void set_latency_range (PortHandle, bool for_playback, LatencyRange);
+ LatencyRange get_latency_range (PortHandle, bool for_playback);
+
+ /* Discovering physical ports */
+
+ bool port_is_physical (PortHandle) const;
+ void get_physical_outputs (DataType type, std::vector<std::string>&);
+ void get_physical_inputs (DataType type, std::vector<std::string>&);
+ ChanCount n_physical_outputs () const;
+ ChanCount n_physical_inputs () const;
+
+ /* Getting access to the data buffer for a port */
+
+ void* get_buffer (PortHandle, pframes_t);
+
+ void* main_process_thread ();
+
+ private:
+ std::string _instance_name;
+ bool _running;
+ bool _freewheeling;
+
+ float _samplerate;
+ size_t _samples_per_period;
+ float _dsp_load;
+ static size_t _max_buffer_size;
+
+ uint32_t _n_inputs;
+ uint32_t _n_outputs;
+
+ uint32_t _systemic_input_latency;
+ uint32_t _systemic_output_latency;
+
+ uint64_t _processed_samples;
+
+ pthread_t _main_thread;
+
+ /* process threads */
+ static void* dummy_process_thread (void *);
+ std::vector<pthread_t> _threads;
+
+ struct ThreadData {
+ DummyAudioBackend* engine;
+ boost::function<void ()> f;
+ size_t stacksize;
+
+ ThreadData (DummyAudioBackend* e, boost::function<void ()> fp, size_t stacksz)
+ : engine (e) , f (fp) , stacksize (stacksz) {}
+ };
+
+ /* port engine */
+ PortHandle add_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
+ int register_system_ports ();
+ void unregister_system_ports ();
+
+ std::vector<DummyPort *> _ports;
+
+ bool valid_port (PortHandle port) const {
+ return std::find (_ports.begin (), _ports.end (), (DummyPort*)port) != _ports.end ();
+ }
+ DummyPort * find_port (const std::string& port_name) const {
+ for (std::vector<DummyPort*>::const_iterator it = _ports.begin (); it != _ports.end (); ++it) {
+ if ((*it)->name () == port_name) {
+ return *it;
+ }
+ }
+ return NULL;
+ }
+
+}; // class DummyAudioBackend
+
+} // namespace
+
+#endif /* __libbackend_dummy_audiobackend_h__ */
--- /dev/null
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+import os
+import sys
+import re
+
+# Library version (UNIX style major, minor, micro)
+# major increment <=> incompatible changes
+# minor increment <=> compatible changes (additions)
+# micro increment <=> no interface changes
+DUMMYBACKEND_VERSION = '0.0.1'
+I18N_PACKAGE = 'dummy-backend'
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+ autowaf.set_options(opt)
+
+def configure(conf):
+ autowaf.configure(conf)
+
+def build(bld):
+ obj = bld(features = 'cxx cxxshlib')
+ obj.source = [
+ 'dummy_audiobackend.cc',
+ ]
+ obj.includes = ['.']
+ obj.name = 'dummy_audiobackend'
+ obj.target = 'dummy_audiobackend'
+ obj.use = 'libardour libpbd'
+ obj.vnum = DUMMYBACKEND_VERSION
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends')
+ obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
+ 'ARDOURBACKEND_DLL_EXPORTS'
+ ]
obj.uselib = [ 'JACK' ]
obj.use = 'libardour libpbd'
obj.vnum = JACKBACKEND_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'backends')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends')
obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
'ARDOURBACKEND_DLL_EXPORTS'
]
obj.target = 'waves_audiobackend'
obj.use = [ 'libardour', 'libpbd' ]
obj.vnum = WAVESAUDIOBACKEND_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'backends')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'backends')
obj.defines = ['PACKAGE="' + I18N_PACKAGE + '"',
'__MACOS__',
'ARDOURBACKEND_DLL_EXPORTS'
top = '.'
out = 'build'
-backends = [ 'jack' ]
+backends = [ 'jack', 'dummy' ]
if sys.platform == 'darwin':
backends += ['wavesaudio' ]
obj.name = 'libcanvas'
obj.target = 'canvas'
obj.vnum = CANVAS_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.defines += [ 'PACKAGE="' + I18N_PACKAGE + '"' ]
if bld.env['BUILD_TESTS'] and bld.env['HAVE_CPPUNIT']:
obj.target = 'clearlooks'
obj.uselib = 'GTK'
obj.includes = '.'
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'engines')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'engines')
autowaf.ensure_visible_symbols (obj, True)
if sys.platform == 'darwin':
libsmf.uselib = 'GLIB'
libsmf.cxxflags = [ '-fPIC' ]
libsmf.cflags = [ '-fPIC' ]
- libsmf.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ libsmf.install_path = bld.env['LIBDIR']
lib_source = '''
src/Control.cpp
obj.uselib = 'GLIBMM GTHREAD SMF'
obj.use = 'libsmf libpbd'
obj.vnum = EVORAL_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.defines += [ 'PACKAGE="libevoral"', 'EVORAL_MIDI_XML=1' ]
if bld.env['BUILD_TESTS'] and bld.is_defined('HAVE_CPPUNIT'):
obj.source = 'scanner.wine'
obj.target = 'ardour-vst-scanner'
obj.chmod = Utils.O755
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3/fst')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'fst')
obj.dict = {
'VERSION' : bld.env['VERSION'],
}
'VST_SCANNER_APP',
'PACKAGE="' + I18N_PACKAGE + '"',
]
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3/fst')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'fst')
obj.uselib = 'GTKMM GTK GTKOSX OSX GDK'
obj.use = [ 'libpbd' ]
obj.vnum = GTKMM2EXT_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.defines += [
'PACKAGE="' + I18N_PACKAGE + '"',
'LOCALEDIR="' + os.path.join(
all changes *are* atomic.
*/
- if (tb->controller_number <= 31) { /* unsigned: no test for >= 0 */
+ if (tb->controller_number < 32) { /* unsigned: no test for >= 0 */
/* if this controller is already known to use 14 bits,
then treat this value as the MSB, and combine it
cv = (unsigned short) _controller_val[tb->controller_number];
if (_controller_14bit[tb->controller_number]) {
- cv = ((tb->value << 7) | (cv & 0x7f));
+ cv = ((tb->value & 0x7f) << 7) | (cv & 0x7f);
} else {
cv = tb->value;
}
cv = (cv & 0x3f80) | (tb->value & 0x7f);
}
- _controller_val[tb->controller_number] =
- (controller_value_t) cv;
+ /* update the 14 bit value */
+ _controller_val[cn] = (controller_value_t) cv;
+
+ /* also store the "raw" 7 bit value in the incoming controller
+ value store
+ */
+ _controller_val[tb->controller_number] = (controller_value_t) tb->value;
+
} else {
/* controller can only take 7 bit values */
/* bank numbers are special, in that they have their own signal
*/
- if (tb->controller_number == 0) {
- _bank_number = (unsigned short) _controller_val[0];
+ if (tb->controller_number == 0 || tb->controller_number == 0x20) {
+ _bank_number = _controller_val[0];
_port.parser()->bank_change (*_port.parser(), _bank_number);
_port.parser()->channel_bank_change[_channel_number] (*_port.parser(), _bank_number);
}
-
}
void
Port &midi_port() { return _port; }
byte channel() { return _channel_number; }
byte program() { return _program_number; }
- byte bank() { return _bank_number; }
+ unsigned short bank() { return _bank_number; }
byte pressure () { return _chanpress; }
byte poly_pressure (byte n) { return _polypress[n]; }
/* Current channel values */
byte _channel_number;
- byte _bank_number;
+ unsigned short _bank_number;
byte _program_number;
byte _rpn_msb;
byte _rpn_lsb;
class Parser;
typedef PBD::Signal1<void,Parser&> ZeroByteSignal;
+typedef PBD::Signal2<void,Parser&,unsigned short> BankSignal;
typedef PBD::Signal2<void,Parser&,framecnt_t> TimestampedSignal;
typedef PBD::Signal2<void,Parser&, byte> OneByteSignal;
typedef PBD::Signal2<void,Parser &, EventTwoBytes *> TwoByteSignal;
/* signals that anyone can connect to */
- OneByteSignal bank_change;
+ BankSignal bank_change;
TwoByteSignal note_on;
TwoByteSignal note_off;
TwoByteSignal poly_pressure;
PitchBendSignal pitchbend;
TwoByteSignal controller;
- OneByteSignal channel_bank_change[16];
+ BankSignal channel_bank_change[16];
TwoByteSignal channel_note_on[16];
TwoByteSignal channel_note_off[16];
TwoByteSignal channel_poly_pressure[16];
obj.uselib = 'GLIBMM SIGCPP XML OSX'
obj.use = 'libpbd libevoral libtimecode'
obj.vnum = LIBMIDIPP_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
if bld.env['BUILD_TESTS'] and bld.is_defined('HAVE_CPPUNIT'):
# Unit tests
obj.target = 'pan1in2out'
obj.use = 'libardour libardour_cp libpbd'
obj.vnum = LIBARDOUR_PAN1IN2OUT_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'panners')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'panners')
def shutdown():
autowaf.shutdown()
obj.target = 'pan2in2out'
obj.use = 'libardour libardour_cp libpbd'
obj.vnum = LIBARDOUR_PAN2IN2OUT_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'panners')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'panners')
def shutdown():
autowaf.shutdown()
obj.target = 'panbalance'
obj.use = 'libardour libardour_cp libpbd'
obj.vnum = LIBARDOUR_PAN2IN2OUT_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'panners')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'panners')
def shutdown():
autowaf.shutdown()
obj.target = 'panvbap'
obj.use = 'libardour libardour_cp libpbd'
obj.vnum = LIBARDOUR_PANVBAP_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'panners')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'panners')
def shutdown():
autowaf.shutdown()
obj.source += [ 'cocoa_open_uri.mm' ]
obj.uselib += ' OSX'
obj.vnum = LIBPBD_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
obj.defines += [ 'PACKAGE="' + I18N_PACKAGE + '"',
]
obj.name = 'libqmdsp'
obj.target = 'qmdsp'
obj.vnum = QM_DSP_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
def shutdown():
autowaf.shutdown()
obj.target = 'ardourcp'
obj.use = 'libardour'
obj.vnum = LIBARDOUR_CP_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
def shutdown():
autowaf.shutdown()
obj.target = 'generic_midi'
obj.use = 'libardour libardourcp'
obj.vnum = LIBSURFACES_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.uselib = 'GTKMM GTK GDK'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.vnum = LIBARDOUR_GENERIC_MIDI_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.uselib = 'GTKMM'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.vnum = LIBARDOUR_MCP_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.uselib = ' LO '
obj.use = 'libardour libardour_cp libpbd'
obj.vnum = LIBARDOUR_OSC_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.target = 'ardour_tranzport'
obj.use = 'libardour libardour_cp'
obj.vnum = LIBARDOUR_TRANZPORT_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.uselib = 'GTKMM CWIID'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.vnum = LIBARDOUR_WIIMOTE_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
obj.source += ' Onset.cpp '
obj.uselib += ' AUBIO '
obj.vnum = LIBARDOURVAMPPLUGINS_LIB_VERSION
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'vamp')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'vamp')
def shutdown():
autowaf.shutdown()
obj = bld (features = 'c cprogram')
obj.source = 'exec_wrapper.c'
obj.target = 'ardour-exec-wrapper'
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3/vfork')
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'vfork')
obj.defines = [
'_POSIX_SOURCE',
'_XOPEN_SOURCE=500',
def build(bld):
devinfo = bld.path.ant_glob ('*.device')
profiles = bld.path.ant_glob ('*.profile')
- bld.install_files (os.path.join(bld.env['DATADIR'], 'ardour3', 'mcp'), devinfo)
- bld.install_files (os.path.join(bld.env['DATADIR'], 'ardour3', 'mcp'), profiles)
+ bld.install_files (os.path.join(bld.env['DATADIR'], 'mcp'), devinfo)
+ bld.install_files (os.path.join(bld.env['DATADIR'], 'mcp'), profiles)
def options(opt):
pass
def build(bld):
maps = bld.path.ant_glob ('*.map')
- bld.install_files (os.path.join(bld.env['DATADIR'], 'ardour3', 'midi_maps'),
+ bld.install_files (os.path.join(bld.env['DATADIR'], 'midi_maps'),
maps)
def options(opt):
def build(bld):
patchfiles = bld.path.ant_glob ('*.midnam')
- bld.install_files (os.path.join(bld.env['DATADIR'], 'ardour3', 'patchfiles'), patchfiles)
+ bld.install_files (os.path.join(bld.env['DATADIR'], 'patchfiles'), patchfiles)
def options(opt):
pass
name = 'template',
source = [ t ],
target = [ os.path.join(dir_name, file_name) ],
- install_path = os.path.join(bld.env['DATADIR'], 'ardour3', os.path.join('templates', dir_name)))
+ install_path = os.path.join(bld.env['DATADIR'], os.path.join('templates', dir_name)))
def options(opt):
pass
cp $BUILD_ROOT/libs/panners/*/lib*.so* $Panners
# Backends
-cp $BUILD_ROOT/libs/backends/*/lib*.so* $Backends
+for backend in jack wavesaudio ; do
+ cp $BUILD_ROOT/libs/backends/$backend/lib*.so* $Backends
+done
# VAMP plugins that we use
cp $BUILD_ROOT/libs/vamp-plugins/libardourvampplugins.so* $Libraries
cp $BUILD_ROOT/libs/panners/*/lib*.dylib $Panners
# Backends
-cp $BUILD_ROOT/libs/backends/*/lib*.dylib $Backends
+for backend in jack wavesaudio ; do
+ cp $BUILD_ROOT/libs/backends/$backend/lib*.dylib $Backends
+done
# Export Formats/Presets
for f in $BUILD_ROOT/../export/*.preset $BUILD_ROOT/../export/*.format ; do
obj.source = [ 'main.cpp', 'systemtest.cpp' ]
obj.target = 'sanityCheck'
obj.name = 'sanityCheck'
- obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+ obj.install_path = bld.env['LIBDIR']
bld.env['CONFDIR'] = os.path.join(bld.env['SYSCONFDIR'], lwrcase_dirname)
# data files loaded at run time go here
bld.env['DATADIR'] = os.path.join(bld.env['DATADIR'], lwrcase_dirname)
- # shared objects loaded at runtime go here
+ # shared objects loaded at runtime go here (two aliases)
bld.env['DLLDIR'] = os.path.join(bld.env['LIBDIR'], lwrcase_dirname)
+ bld.env['LIBDIR'] = bld.env['DLLDIR']
autowaf.set_recursive()
for i in children:
bld.recurse(i)
- bld.install_files (os.path.join(bld.env['SYSCONFDIR'], 'ardour3', ), 'ardour_system.rc')
+ bld.install_files (bld.env['SYSCONFDIR'], 'ardour_system.rc')
if bld.env['RUN_TESTS']:
bld.add_post_fun(test)