Merge branch 'cairocanvas' of git.ardour.org:ardour/ardour into cairocanvas
authorCarl Hetherington <cth@carlh.net>
Tue, 29 Apr 2014 11:42:49 +0000 (12:42 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 29 Apr 2014 11:42:49 +0000 (12:42 +0100)
67 files changed:
export/wscript
gtk2_ardour/ardev_common.sh.in
gtk2_ardour/ardour.menus.in
gtk2_ardour/editor.h
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_ops.cc
headless/wscript
libs/ardour/ardour/async_midi_port.h
libs/ardour/ardour/location.h
libs/ardour/ardour/midi_scene_change.h [new file with mode: 0644]
libs/ardour/ardour/midi_scene_changer.h [new file with mode: 0644]
libs/ardour/ardour/midiport_manager.h
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/ardour/scene_change.h [new file with mode: 0644]
libs/ardour/ardour/scene_changer.h [new file with mode: 0644]
libs/ardour/ardour/session.h
libs/ardour/async_midi_port.cc
libs/ardour/location.cc
libs/ardour/midi_scene_change.cc [new file with mode: 0644]
libs/ardour/midi_scene_changer.cc [new file with mode: 0644]
libs/ardour/midi_ui.cc
libs/ardour/midiport_manager.cc
libs/ardour/scene_change.cc [new file with mode: 0644]
libs/ardour/session.cc
libs/ardour/session_midi.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/wscript
libs/audiographer/wscript
libs/backends/dummy/dummy_audiobackend.cc [new file with mode: 0644]
libs/backends/dummy/dummy_audiobackend.h [new file with mode: 0644]
libs/backends/dummy/wscript [new file with mode: 0644]
libs/backends/jack/wscript
libs/backends/wavesaudio/wscript
libs/backends/wscript
libs/canvas/wscript
libs/clearlooks-newer/wscript
libs/evoral/wscript
libs/fst/wscript
libs/gtkmm2ext/wscript
libs/midi++2/channel.cc
libs/midi++2/midi++/channel.h
libs/midi++2/midi++/parser.h
libs/midi++2/wscript
libs/panners/1in2out/wscript
libs/panners/2in2out/wscript
libs/panners/stereobalance/wscript
libs/panners/vbap/wscript
libs/pbd/wscript
libs/qm-dsp/wscript
libs/surfaces/control_protocol/wscript
libs/surfaces/frontier/wscript
libs/surfaces/generic_midi/wscript
libs/surfaces/mackie/wscript
libs/surfaces/osc/wscript
libs/surfaces/tranzport/wscript
libs/surfaces/wiimote/wscript
libs/vamp-plugins/wscript
libs/vfork/wscript
mcp/wscript
midi_maps/wscript
patchfiles/wscript
templates/wscript
tools/linux_packaging/build
tools/osx_packaging/osx_build
tools/sanity_check/wscript
wscript

index 2dce68a01bdcb197b8cff48e3b760962f488d71a..23a070f61dc47c0b3baddcfcc5d5c95597804f7f 100644 (file)
@@ -11,7 +11,7 @@ def configure(conf):
 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):
index 565ea0b865b636c210741c3fdd3c2c2eba5978db..d65a287701b3c83fa471417a7d253328c07c40cf 100644 (file)
@@ -17,7 +17,7 @@ export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour:
 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 
index 6c5e08c8f8dc02c3dd2e19ae05885bb71285a325..6d08937cf05547e162e8360fd2425ddb9d693012 100644 (file)
         <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'/>
index f3f6bfeee71f82c23f3a4bb9dd79b7e70b33e818..1398936979151d3a31207efad60c46b3e081e805 100644 (file)
@@ -319,6 +319,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void nudge_forward_capture_offset ();
        void nudge_backward_capture_offset ();
 
+       void sequence_regions ();
+
        /* playhead/screen stuff */
 
        void set_stationary_playhead (bool yn);
index 674952781d2d1472758703dd74cc2829852d0b33..48d56193a62226d7df4468ff197f7a95777c5a24 100644 (file)
@@ -1897,6 +1897,8 @@ Editor::register_region_actions ()
        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",
index f7dc46659a11de94952b07b213a81f8af348b71c..08d6297faae3162c388f7a76b9cf411307d224b1 100644 (file)
@@ -512,6 +512,60 @@ Editor::nudge_backward_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
index 5001bea77c5d47594135388e85a09960146ca08f..be80f9c73b7ea80de710dab43c7dea2bd23663ca 100644 (file)
@@ -57,7 +57,7 @@ def build(bld):
         '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 '
index c5babf6135c3bbda22b9310d980bede82a2e3120..26946e30167d9932914547c861d869b27fde2ce1 100644 (file)
@@ -22,6 +22,8 @@
 #include <string>
 #include <iostream>
 
+#include <boost/function.hpp>
+
 #include "pbd/xml++.h"
 #include "pbd/crossthread.h"
 #include "pbd/signals.h"
@@ -64,6 +66,8 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
 #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();
@@ -71,6 +75,8 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
   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;
index b0956eea36d2e32e1c257509c29d13b5cee33c26..6cea208f05014e7af62c40147d758ed7c747aa9a 100644 (file)
 #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:
@@ -93,6 +96,9 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
 
        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;
@@ -116,6 +122,8 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
        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;
@@ -125,6 +133,7 @@ class LIBARDOUR_API Location : public SessionHandleRef, public PBD::StatefulDest
        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);
@@ -161,6 +170,8 @@ class LIBARDOUR_API Locations : public SessionHandleRef, public PBD::StatefulDes
        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);
 
diff --git a/libs/ardour/ardour/midi_scene_change.h b/libs/ardour/ardour/midi_scene_change.h
new file mode 100644 (file)
index 0000000..86793c5
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+    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__ */
diff --git a/libs/ardour/ardour/midi_scene_changer.h b/libs/ardour/ardour/midi_scene_changer.h
new file mode 100644 (file)
index 0000000..2cc0464
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+    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__ */
index b5b46e85101df22d4859ba422632a3f32370dadd..5e87238c22f7021fb519d895660f8d1c0e250282 100644 (file)
@@ -30,6 +30,7 @@
 #include "midi++/port.h"
 
 #include "ardour/libardour_visibility.h"
+#include "ardour/midi_port.h"
 #include "ardour/types.h"
 
 namespace ARDOUR {
@@ -56,7 +57,12 @@ class LIBARDOUR_API MidiPortManager {
     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.
      */
@@ -77,13 +83,17 @@ class LIBARDOUR_API MidiPortManager {
     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;
index d290d8ebc844f541a1208cf6b671eb04842a47b7..4401b1f74ca952f9cdd31fb622fdfe289467c990 100644 (file)
@@ -44,6 +44,7 @@ CONFIG_VARIABLE (int32_t, mmc_receive_device_id, "mmc-receive-device-id", 0x7f)
 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 */
 
diff --git a/libs/ardour/ardour/scene_change.h b/libs/ardour/ardour/scene_change.h
new file mode 100644 (file)
index 0000000..b81766b
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    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__ */
diff --git a/libs/ardour/ardour/scene_changer.h b/libs/ardour/ardour/scene_changer.h
new file mode 100644 (file)
index 0000000..d5ba984
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+    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__ */
index 15af67ada7421e452be4b83f593093428f888f37..40ada138a6dac0f8027d0536da423afbba66110a 100644 (file)
@@ -129,6 +129,7 @@ class Route;
 class RouteGroup;
 class SMFSource;
 class Send;
+class SceneChanger;
 class SessionDirectory;
 class SessionMetadata;
 class SessionPlaylists;
@@ -868,23 +869,31 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
         */
         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;
@@ -1607,16 +1616,19 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
         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
index bd583328c30f1781a768d3268f27c1053bb64265..21b59dec00241bacfaa3a9b11acba2fb19fb932d 100644 (file)
@@ -50,6 +50,7 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags)
        , 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
@@ -62,6 +63,13 @@ AsyncMIDIPort::~AsyncMIDIPort ()
 {
 }
 
+void
+AsyncMIDIPort::set_timer (boost::function<framecnt_t (void)>& f)
+{
+       timer = f;
+       have_timer = true;
+}
+
 void
 AsyncMIDIPort::flush_output_fifo (MIDI::pframes_t nframes)
 {
@@ -113,9 +121,18 @@ AsyncMIDIPort::cycle_start (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());
                }
 
index 2a27fc318a9d986a3afc00fdda2f5082fee1d98d..90265af4e4262410fa4bfd37b09d5b117eee89a7 100644 (file)
@@ -30,6 +30,7 @@
 #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"
@@ -42,6 +43,8 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+PBD::Signal0<void> Location::scene_changed;
+
 Location::Location (Session& s)
        : SessionHandleRef (s)
        , _start (0)
@@ -87,6 +90,8 @@ Location::Location (const Location& other)
 
        assert (_start >= 0);
        assert (_end >= 0);
+
+       /* scene change is NOT COPIED */
 }
 
 Location::Location (Session& s, const XMLNode& node)
@@ -134,6 +139,8 @@ Location::operator= (const Location& other)
        _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 */
 
@@ -431,11 +438,15 @@ Location::get_state ()
        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;
 
@@ -521,6 +532,16 @@ Location::set_state (const XMLNode& node, int /*version*/)
                _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 */
@@ -581,6 +602,14 @@ Location::unlock ()
        LockChanged (this);
 }
 
+void
+Location::set_scene_change (boost::shared_ptr<SceneChange>  sc)
+{
+       _scene_change = sc;
+
+       scene_changed (); /* EMIT SIGNAL */
+}
+
 /*---------------------------------------------------------------------- */
 
 Locations::Locations (Session& s)
@@ -675,6 +704,7 @@ Locations::clear ()
                        ++tmp;
 
                        if (!(*i)->is_session_range()) {
+                               delete *i;
                                locations.erase (i);
                        }
 
@@ -700,6 +730,7 @@ Locations::clear_markers ()
                        ++tmp;
 
                        if ((*i)->is_mark() && !(*i)->is_session_range()) {
+                               delete *i;
                                locations.erase (i);
                        }
 
@@ -723,6 +754,7 @@ Locations::clear_ranges ()
                        ++tmp;
 
                        if (!(*i)->is_mark()) {
+                               delete *i;
                                locations.erase (i);
 
                        }
@@ -779,6 +811,7 @@ Locations::remove (Location *loc)
 
                for (i = locations.begin(); i != locations.end(); ++i) {
                        if ((*i) == loc) {
+                               delete *i;
                                locations.erase (i);
                                was_removed = true;
                                if (current_location == loc) {
@@ -972,6 +1005,44 @@ Locations::first_mark_before (framepos_t frame, bool include_special_ranges)
        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)
 {
@@ -1146,3 +1217,4 @@ Locations::find_all_between (framepos_t start, framepos_t end, LocationList& ll,
                }
        }
 }
+
diff --git a/libs/ardour/midi_scene_change.cc b/libs/ardour/midi_scene_change.cc
new file mode 100644 (file)
index 0000000..81a7491
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+    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;
+}
diff --git a/libs/ardour/midi_scene_changer.cc b/libs/ardour/midi_scene_changer.cc
new file mode 100644 (file)
index 0000000..49e835c
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+    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);
+       }
+}
index 97dfdce6bf0ce1fc18d8f7d0d59a6f3adad8ffd4..e00ec587ec4da2f6180b397ee7c3ecb09ce0b92e 100644 (file)
@@ -122,6 +122,10 @@ MidiControlUI::reset_ports ()
        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;
index 6de043658690187d0af697e02e29c9fdb8f8951b..b1699ca5abc5a548abc6fc2bddf64e0d450af5fe 100644 (file)
@@ -40,8 +40,14 @@ MidiPortManager::~MidiPortManager ()
        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);
@@ -73,7 +79,10 @@ MidiPortManager::create_ports ()
 
        _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.
         *
@@ -88,6 +97,9 @@ MidiPortManager::create_ports ()
        _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)
         */
 
@@ -129,6 +141,8 @@ MidiPortManager::set_midi_port_states (const XMLNodeList&nodes)
        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) {
@@ -159,6 +173,8 @@ MidiPortManager::get_midi_port_states () const
        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());
diff --git a/libs/ardour/scene_change.cc b/libs/ardour/scene_change.cc
new file mode 100644 (file)
index 0000000..dec6a11
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    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;
+}
index 2aef7459615de38000acfcfe8c0090fbcd5e3dc1..05fa883a9d3b02343d8cec6553ad1f1893021e8d 100644 (file)
@@ -68,6 +68,7 @@
 #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"
@@ -260,6 +261,7 @@ Session::Session (AudioEngine &eng,
        ,  _speakers (new Speakers)
        , _order_hint (0)
        , ignore_route_processor_changes (false)
+       , _scene_changer (0)
        , _midi_ports (0)
        , _mmc (0)
 {
@@ -547,6 +549,8 @@ Session::destroy ()
        /* 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;
index ea6dfe81cf17f6bd5f9bb5542103af04f39a90b5..93df1fc9466e16ed98c348c4d5f1da4855fee560 100644 (file)
@@ -644,3 +644,27 @@ Session::mmc_input_port () const
 {
        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 ();
+}
index eb5c0de294f00cfbfe4c81b66949683930a13524..680f2861de2a2bdae8e90515ea89c96ef1fdd0d8 100644 (file)
@@ -35,6 +35,7 @@
 #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"
@@ -86,6 +87,9 @@ Session::process (pframes_t nframes)
                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 */
        }
index 07f10e9bc10236538e2207dd3532d2b9b9c9a3ef..6a06863e9e16b1ca347cd261df2fe3e374d861ff 100644 (file)
@@ -77,6 +77,7 @@
 #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"
@@ -92,6 +93,7 @@
 #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"
@@ -207,6 +209,16 @@ Session::post_engine_init ()
        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()) {
index c12aec4ef83aa959d643c04f8646862717948783..4a500645452f046d68c7855799d602e579539dcc 100644 (file)
@@ -119,6 +119,8 @@ libardour_sources = [
         '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',
@@ -164,6 +166,7 @@ libardour_sources = [
         'route_group.cc',
         'route_group_member.cc',
         'rb_effect.cc',
+        'scene_change.cc',
         'search_paths.cc',
         'send.cc',
         'session.cc',
@@ -352,7 +355,7 @@ def build(bld):
         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']) + '"',
@@ -566,7 +569,7 @@ def create_ardour_test_program(bld, includes, name, target, sources):
     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']) + '"',
index 0e4cd5d7f4f62dfa472611f2dfe5fbe7cba0faab..2fe2739741444d979341fb81fee215727ecd4cf7 100644 (file)
@@ -82,7 +82,7 @@ def build(bld):
     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'):
diff --git a/libs/backends/dummy/dummy_audiobackend.cc b/libs/backends/dummy/dummy_audiobackend.cc
new file mode 100644 (file)
index 0000000..f0eeb8d
--- /dev/null
@@ -0,0 +1,1271 @@
+/*
+ * 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);
+};
diff --git a/libs/backends/dummy/dummy_audiobackend.h b/libs/backends/dummy/dummy_audiobackend.h
new file mode 100644 (file)
index 0000000..18d14cb
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * 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__ */
diff --git a/libs/backends/dummy/wscript b/libs/backends/dummy/wscript
new file mode 100644 (file)
index 0000000..8c8db6a
--- /dev/null
@@ -0,0 +1,37 @@
+#!/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'
+                  ]
index b31d9b5d56452cd3b6f2e26f5df82cdc1fa74208..1f54e7a5e704db701ddebba1913363197ac13f39 100644 (file)
@@ -51,7 +51,7 @@ def build(bld):
         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'
                    ]
index 372470c859300238c3244f8d8214cde0eabe328a..814f16bc44956ab7fd2d422cc75ac1dd63e99651 100644 (file)
@@ -67,7 +67,7 @@ def build(bld):
     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'
index f27071127aa63db783925054f70f5c07d8da5567..36ef5c1ecd9c3d036c6af406f73e17a1ab65562e 100644 (file)
@@ -7,7 +7,7 @@ import sys
 top = '.'
 out = 'build'
 
-backends = [ 'jack' ]
+backends = [ 'jack', 'dummy' ]
 
 if sys.platform == 'darwin':
     backends += ['wavesaudio' ]
index 05add846c3fedfde92a819633453273f7f787f2f..0c5192645c43d3683c213f6521af79c75bf17896 100644 (file)
@@ -85,7 +85,7 @@ def build(bld):
     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']:
index e0e5d5fb8a4f5b24a2e6f3e4dcda225480e6294a..6ef94e3afff6d5e2b2931684d5d21b38fda0b38d 100644 (file)
@@ -35,7 +35,7 @@ def build(bld):
     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':
index 55c03fcdf522d801fd3c293c77b7be4709c063c0..a4aea3a3a269f137dd16c089b25460532eb8497d 100644 (file)
@@ -73,7 +73,7 @@ def build(bld):
     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
@@ -108,7 +108,7 @@ def build(bld):
     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'):
index 809f13840b25438288819c490da61137a873615d..91273f3d793b7e02d8ad8947cde201aaa626f8e4 100644 (file)
@@ -51,7 +51,7 @@ def build(bld):
         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'],
                 }
@@ -83,4 +83,4 @@ def build(bld):
         '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')
index 6d9f1edbe8078ff74275090555c838b62d4ed0fc..c2de82d0c27f3389f60fccb8a1ccac6561dbe9f6 100644 (file)
@@ -101,7 +101,7 @@ def build(bld):
     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(
index ed8f4da5bc2b56c7910fd263f5aa7140a4d306ae..190ea185680fa48555acdbbef5d2f825477d71f1 100644 (file)
@@ -115,7 +115,7 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
           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 
@@ -128,7 +128,7 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
                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;
                }
@@ -160,8 +160,14 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
                        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 */
@@ -173,12 +179,11 @@ Channel::process_controller (Parser & /*parser*/, EventTwoBytes *tb)
        /* 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
index 02c16e67297cf2f2198a3b8fea06121689264379..f3ec434ca5008d0338ca2188619626d3e2921a66 100644 (file)
@@ -42,7 +42,7 @@ class LIBMIDIPP_API Channel : public PBD::ScopedConnectionList {
        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]; }
 
@@ -117,7 +117,7 @@ class LIBMIDIPP_API Channel : public PBD::ScopedConnectionList {
 
        /* Current channel values */
        byte               _channel_number;
-       byte               _bank_number;
+       unsigned short     _bank_number;
        byte               _program_number;
        byte               _rpn_msb;
        byte               _rpn_lsb;
index e4126b210bac34db57ae7ee4b8bdcc897679a2b3..420e7fcb7bb89a71115c8b0d76bf81d4ebb89945 100644 (file)
@@ -34,6 +34,7 @@ class Port;
 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;
@@ -55,7 +56,7 @@ class LIBMIDIPP_API Parser {
 
        /* signals that anyone can connect to */
        
-       OneByteSignal         bank_change;
+       BankSignal            bank_change;
        TwoByteSignal         note_on;
        TwoByteSignal         note_off;
        TwoByteSignal         poly_pressure;
@@ -64,7 +65,7 @@ class LIBMIDIPP_API Parser {
        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];
index 928b381326815b0aef7bd6fe583b81999b8ebbd7..e8bfdab217967e31c6216ca5c528a92f8465aaaa 100644 (file)
@@ -75,7 +75,7 @@ def build(bld):
     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
index de6b21af25cfaf40a830b181f2cc37d97732b967..6b7a04a7d9413bb735efc1abb978ef2c0b667d2e 100644 (file)
@@ -29,7 +29,7 @@ def build(bld):
     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()
index 63f029f28793ddbae80b672c6716eb8f82589cdd..f71f514b730f7bbe6111b124d345a550167d6ef0 100644 (file)
@@ -29,7 +29,7 @@ def build(bld):
     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()
index b66a2ffee60e87faf103df9d8e37b64a51385f34..25ab9e5835f3407bbd8003cda2b7fbb92ad5b71e 100644 (file)
@@ -29,7 +29,7 @@ def build(bld):
     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()
index 8fe9dc8e8aa6f547dfc014ac4cbd39356f3f70a0..c2bb313e27df2072b3dfdc086f3d0d1c028162e9 100644 (file)
@@ -29,7 +29,7 @@ def build(bld):
     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()
index e009cc4ed21df722c4088dfdb47d14b609fdde03..3e7b423fc74133728de701451b0ccf387f92a87c 100644 (file)
@@ -146,7 +146,7 @@ def build(bld):
             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 + '"',
                          ]
 
index 96d0b629dd184fe7bc84d5ae761ef06cb642988b..ef15abffb73805454b9bed95ac12d6b64c8351a7 100644 (file)
@@ -53,7 +53,7 @@ def build(bld):
     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()
index f14cee042f27106156aa873d8e7121a12d7ddd6d..1c4235bd148bc6119ef3fb5ada4770bc3a4d27f4 100644 (file)
@@ -41,7 +41,7 @@ def build(bld):
     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()
index 4fcbe6fde369b49f2bc4f0ae8f3dfd9629739949..614c6f28417b63fba44123ee60e13db6371ea2ff 100644 (file)
@@ -41,7 +41,7 @@ def build(bld):
     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()
index 40cb76c9e44ac319e8fc85ea38e42a80ddcec021..b083423eec4a2079d4bd6b3941a4226577cbadcb 100644 (file)
@@ -38,7 +38,7 @@ def build(bld):
     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()
index c1e63e2894a0615e6cbf9a7105a8ee4e84cb806e..fd3e9552bee7eebe042be4704fa79f95b2fc268a 100644 (file)
@@ -50,7 +50,7 @@ def build(bld):
     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()
index a63b580e12f6b87e9315ccf533d568aed91dad1d..fa4918a8f104caad3a68d736c0b0af406331c510 100644 (file)
@@ -35,7 +35,7 @@ def build(bld):
     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()
index 83c39f1d115375e7925675ed80748de3ea9da9ae..6cbafb5173c4a4fd08646efb7d17abc840814395 100644 (file)
@@ -46,7 +46,7 @@ def build(bld):
     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()
index 8513a5be513305e6f989fa57d94d13b150595d0c..b3ea4404a8f934b539e1c1f850b45abda99daea5 100644 (file)
@@ -33,7 +33,7 @@ def build(bld):
     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()
index 4808d33612d98ec48bf6e0788b41355fe8d5e1fd..06d440fa572892562e07b4ad1d0fe608f0d85bf2 100644 (file)
@@ -55,7 +55,7 @@ def build(bld):
         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()
index 48526d07836cdacba300c36a13f30f6f69a460c3..10f11149d856dacc5c2b1be40d70ddbfa725a1a3 100644 (file)
@@ -21,7 +21,7 @@ def build(bld):
     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',
index b1ff9c156b0135e59886a78fb5f069ff2ed4e86d..e3cc341419146e13daa5bf128bae17e839db7660 100644 (file)
@@ -11,8 +11,8 @@ def configure(conf):
 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
index 727f3b6b298f24221a5a46048abe49cdfee54086..ec2e65316a25c0caaf8cb7e98d6dc1f3df1f16a6 100644 (file)
@@ -10,7 +10,7 @@ def configure(conf):
 
 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):
index 3b852974c3918aa0f3a9e2d297671437a5f6b9b0..ea54532e1326d62c74db9218f04560f0c6026dd2 100644 (file)
@@ -10,7 +10,7 @@ def configure(conf):
 
 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
index 8dff100d1a0998b28ecba28fdc2a69f2dec4a1b1..3ea6c4a1e5c0cbb456f5e7b334446ee98e33578a 100644 (file)
@@ -35,7 +35,7 @@ def build(bld):
                   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
index 95f052537ed480615a7c2c353a788048e1f0eeb9..647fc88f4be96a379ccae21fa285c9c16564ef72 100755 (executable)
@@ -389,7 +389,9 @@ done
 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
index 384eeeac3d3b1d2ee650133823956ce834cd3a9f..31ac58e2a2bb1b44b18206a80d76a4d989ed0c9e 100755 (executable)
@@ -337,7 +337,9 @@ cp $BUILD_ROOT/libs/surfaces/control_protocol/libardourcp*.dylib $Frameworks
 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 
index 6bb2274f3f9707e44371d83453cc423401005415..000753e18bfdac5a32ee16dd39e1e51f291c9e7f 100644 (file)
@@ -20,4 +20,4 @@ def build(bld):
     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']
diff --git a/wscript b/wscript
index 3f0a01dcf570f849202f16d570e567d785f31f23..52d1ec6e28ad31fb9fc657aab65e170ff1e35712 100644 (file)
--- a/wscript
+++ b/wscript
@@ -874,8 +874,9 @@ def build(bld):
     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()
 
@@ -890,7 +891,7 @@ def build(bld):
     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)