summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-10-11 22:07:47 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-10-11 22:07:47 +0000
commitf7f9d6fdc40248b190ec9c6e1a886261d55777ae (patch)
tree080723e9dc35a66013b37acbafc67a6afa929302 /libs
parentaa1f736a651376534acaa2268b65d42a3786fff7 (diff)
merge from 2.0-ongoing by hand, minus key binding editor
git-svn-id: svn://localhost/ardour2/trunk@2539 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/SConscript3
-rw-r--r--libs/ardour/ardour/ardour.h2
-rw-r--r--libs/ardour/ardour/audiofilesource.h9
-rw-r--r--libs/ardour/ardour/audiosource.h50
-rw-r--r--libs/ardour/ardour/automatable.h9
-rw-r--r--libs/ardour/ardour/configuration.h12
-rw-r--r--libs/ardour/ardour/configuration_vars.h8
-rw-r--r--libs/ardour/ardour/io.h2
-rw-r--r--libs/ardour/ardour/profile.h8
-rw-r--r--libs/ardour/ardour/resampled_source.h50
-rw-r--r--libs/ardour/ardour/route.h3
-rw-r--r--libs/ardour/ardour/session.h15
-rw-r--r--libs/ardour/ardour/sndfilesource.h4
-rw-r--r--libs/ardour/ardour/source_factory.h17
-rw-r--r--libs/ardour/ardour/types.h9
-rw-r--r--libs/ardour/ardour/utils.h2
-rw-r--r--libs/ardour/audio_playlist.cc4
-rw-r--r--libs/ardour/audioengine.cc4
-rw-r--r--libs/ardour/audiofilesource.cc94
-rw-r--r--libs/ardour/audiosource.cc98
-rw-r--r--libs/ardour/auditioner.cc2
-rw-r--r--libs/ardour/automatable.cc4
-rw-r--r--libs/ardour/configuration.cc70
-rw-r--r--libs/ardour/crossfade.cc14
-rw-r--r--libs/ardour/globals.cc65
-rw-r--r--libs/ardour/import.cc368
-rw-r--r--libs/ardour/io.cc4
-rw-r--r--libs/ardour/playlist.cc4
-rw-r--r--libs/ardour/resampled_source.cc128
-rw-r--r--libs/ardour/route.cc33
-rw-r--r--libs/ardour/session.cc39
-rw-r--r--libs/ardour/session_events.cc2
-rw-r--r--libs/ardour/session_state.cc25
-rw-r--r--libs/ardour/sndfilesource.cc54
-rw-r--r--libs/ardour/source_factory.cc189
-rw-r--r--libs/ardour/utils.cc13
-rw-r--r--libs/clearlooks/SConscript3
-rw-r--r--libs/clearlooks/clearlooks_style.c4
-rw-r--r--libs/gtkmm2/gtk/gtkmm/toolbar.cc2
-rw-r--r--libs/midi++2/SConscript3
-rw-r--r--libs/midi++2/alsa_sequencer_midiport.cc250
-rw-r--r--libs/midi++2/coremidi_midiport.cc38
-rw-r--r--libs/midi++2/fd_midiport.cc24
-rw-r--r--libs/midi++2/fifomidi.cc8
-rw-r--r--libs/midi++2/jack_midiport.cc47
-rw-r--r--libs/midi++2/midi++/alsa_rawmidi.h6
-rw-r--r--libs/midi++2/midi++/alsa_sequencer.h24
-rw-r--r--libs/midi++2/midi++/coremidi_midiport.h65
-rw-r--r--libs/midi++2/midi++/factory.h3
-rw-r--r--libs/midi++2/midi++/fd_midiport.h21
-rw-r--r--libs/midi++2/midi++/fifomidi.h5
-rw-r--r--libs/midi++2/midi++/jack.h7
-rw-r--r--libs/midi++2/midi++/manager.h26
-rw-r--r--libs/midi++2/midi++/nullmidi.h1
-rw-r--r--libs/midi++2/midi++/port.h101
-rw-r--r--libs/midi++2/midi++/port_request.h66
-rw-r--r--libs/midi++2/midifactory.cc26
-rw-r--r--libs/midi++2/midimanager.cc196
-rw-r--r--libs/midi++2/midiport.cc105
-rw-r--r--libs/midi++2/miditrace.cc1
-rw-r--r--libs/midi++2/mmctest.cc1
-rw-r--r--libs/midi++2/port_request.cc83
-rw-r--r--libs/pbd/SConscript1
-rw-r--r--libs/pbd/convert.cc47
-rw-r--r--libs/pbd/file_utils.cc8
-rw-r--r--libs/pbd/misc.c21
-rw-r--r--libs/pbd/pbd/convert.h12
-rw-r--r--libs/pbd/pbd/functor_command.h121
-rw-r--r--libs/pbd/pbd/misc.h15
-rw-r--r--libs/pbd/pbd/undo.h14
-rw-r--r--libs/pbd/undo.cc27
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc1
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc1
-rw-r--r--libs/surfaces/powermate/powermate.cc26
74 files changed, 1792 insertions, 1035 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 3892af6e9b..465138d90d 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -12,7 +12,7 @@ ardour = env.Copy()
# this defines the version number of libardour
#
-domain = 'libardour'
+domain = 'libardour2'
ardour.Append(DOMAIN = domain, MAJOR = 2, MINOR = 0, MICRO = 0)
ardour.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
@@ -101,6 +101,7 @@ recent_sessions.cc
region.cc
region_factory.cc
reverse.cc
+resampled_source.cc
quantize.cc
route.cc
route_group.cc
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index 1b9725a04c..6e7b494441 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -47,8 +47,6 @@ namespace ARDOUR {
int init (bool with_vst, bool try_optimization);
int cleanup ();
- int setup_midi(AudioEngine& engine);
-
std::string get_ardour_revision ();
microseconds_t get_microseconds ();
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index 78d10f9d64..4d80c8ddf5 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -61,7 +61,8 @@ class AudioFileSource : public AudioSource {
Glib::ustring path() const { return _path; }
Glib::ustring peak_path (Glib::ustring audio_path);
- Glib::ustring old_peak_path (Glib::ustring audio_path);
+ Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path,
+ Glib::ustring audio_path);
uint16_t channel() const { return _channel; }
@@ -122,7 +123,7 @@ class AudioFileSource : public AudioSource {
to cause issues.
*/
- virtual void handle_header_position_change ();
+ virtual void handle_header_position_change () {}
protected:
@@ -166,6 +167,10 @@ class AudioFileSource : public AudioSource {
bool find (Glib::ustring& path, bool must_exist, bool& is_new, uint16_t& chan);
bool removable() const;
bool writable() const { return _flags & Writable; }
+
+ private:
+ Glib::ustring old_peak_path (Glib::ustring audio_path);
+ Glib::ustring broken_peak_path (Glib::ustring audio_path);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 812c30e8c2..7b22528bd1 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -40,7 +40,6 @@
using std::list;
using std::vector;
-using Glib::ustring;
namespace ARDOUR {
@@ -49,10 +48,23 @@ const nframes_t frames_per_peak = 256;
class AudioSource : public Source, public boost::enable_shared_from_this<ARDOUR::AudioSource>
{
public:
- AudioSource (Session&, ustring name);
+ AudioSource (Session&, Glib::ustring name);
AudioSource (Session&, const XMLNode&);
virtual ~AudioSource ();
+
+ /* one could argue that this should belong to Source, but other data types
+ generally do not come with a model of "offset along an audio timeline"
+ so its here in AudioSource for now.
+ */
+
+ virtual nframes_t natural_position() const { return 0; }
+ /* returns the number of items in this `audio_source' */
+
+ virtual nframes_t length() const {
+ return _length;
+ }
+
virtual nframes_t available_peaks (double zoom) const;
virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const;
@@ -65,8 +77,8 @@ const nframes_t frames_per_peak = 256;
virtual bool can_truncate_peaks() const { return true; }
- void set_captured_for (ustring str) { _captured_for = str; }
- ustring captured_for() const { return _captured_for; }
+ void set_captured_for (Glib::ustring str) { _captured_for = str; }
+ Glib::ustring captured_for() const { return _captured_for; }
uint32_t read_data_count() const { return _read_data_count; }
uint32_t write_data_count() const { return _write_data_count; }
@@ -81,7 +93,7 @@ const nframes_t frames_per_peak = 256;
XMLNode& get_state ();
int set_state (const XMLNode&);
- int rename_peakfile (ustring newpath);
+ int rename_peakfile (Glib::ustring newpath);
void touch_peakfile ();
static void set_build_missing_peakfiles (bool yn) {
@@ -92,35 +104,43 @@ const nframes_t frames_per_peak = 256;
_build_peakfiles = yn;
}
+ static bool get_build_peakfiles () {
+ return _build_peakfiles;
+ }
+
virtual int setup_peakfile () { return 0; }
int prepare_for_peakfile_writes ();
- void done_with_peakfile_writes ();
+ void done_with_peakfile_writes (bool done = true);
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
- bool _peaks_built;
- mutable Glib::Mutex _lock;
- ustring peakpath;
- ustring _captured_for;
+ bool _peaks_built;
+ mutable Glib::Mutex _lock;
+ mutable Glib::Mutex _peaks_ready_lock;
+ nframes_t _length;
+ Glib::ustring peakpath;
+ Glib::ustring _captured_for;
mutable uint32_t _read_data_count; // modified in read()
mutable uint32_t _write_data_count; // modified in write()
- int initialize_peakfile (bool newfile, ustring path);
+ int initialize_peakfile (bool newfile, Glib::ustring path);
int build_peaks_from_scratch ();
- int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force);
+ int compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready_signal);
void truncate_peakfile();
mutable off_t _peak_byte_max; // modified in compute_and_write_peak()
virtual nframes_t read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const = 0;
virtual nframes_t write_unlocked (Sample *dst, nframes_t cnt) = 0;
- virtual ustring peak_path(ustring audio_path) = 0;
- virtual ustring old_peak_path(ustring audio_path) = 0;
+ virtual Glib::ustring peak_path(Glib::ustring audio_path) = 0;
+ virtual Glib::ustring find_broken_peakfile (Glib::ustring missing_peak_path, Glib::ustring audio_path) = 0;
+ void update_length (nframes_t pos, nframes_t cnt);
+
private:
int peakfile;
nframes_t peak_leftover_cnt;
@@ -128,7 +148,7 @@ const nframes_t frames_per_peak = 256;
Sample* peak_leftovers;
nframes_t peak_leftover_frame;
- bool file_changed (ustring path);
+ bool file_changed (Glib::ustring path);
};
}
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h
index fe47614a1f..f96ecc0bd1 100644
--- a/libs/ardour/ardour/automatable.h
+++ b/libs/ardour/ardour/automatable.h
@@ -83,6 +83,14 @@ public:
Glib::Mutex& automation_lock() const { return _automation_lock; }
+ static void set_automation_interval (jack_nframes_t frames) {
+ _automation_interval = frames;
+ }
+
+ static jack_nframes_t automation_interval() {
+ return _automation_interval;
+ }
+
protected:
void can_automate(Parameter);
@@ -102,6 +110,7 @@ protected:
std::set<Parameter> _can_automate_list;
nframes_t _last_automation_snapshot;
+ static nframes_t _automation_interval;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/configuration.h b/libs/ardour/ardour/configuration.h
index 70b7e166c1..7b890500d8 100644
--- a/libs/ardour/ardour/configuration.h
+++ b/libs/ardour/ardour/configuration.h
@@ -42,17 +42,7 @@ class Configuration : public PBD::Stateful
Configuration();
virtual ~Configuration();
- struct MidiPortDescriptor {
- std::string tag;
- std::string device;
- std::string type;
- std::string mode;
-
- MidiPortDescriptor (const XMLNode&);
- XMLNode& get_state();
- };
-
- std::map<std::string,MidiPortDescriptor *> midi_ports;
+ std::map<std::string,XMLNode> midi_ports;
void map_parameters (sigc::slot<void,const char*> theSlot);
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 4d5579a9a0..b592a9f721 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -138,11 +138,15 @@ CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture",
CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false)
CONFIG_VARIABLE (bool, use_vst, "use-vst", true)
CONFIG_VARIABLE (uint32_t, subframes_per_frame, "subframes-per-frame", 100)
-CONFIG_VARIABLE (uint32_t, saved_history_depth, "save-history-depth", 100)
+CONFIG_VARIABLE (bool, save_history, "save-history", true)
+CONFIG_VARIABLE (int32_t, saved_history_depth, "save-history-depth", 20)
+CONFIG_VARIABLE (int32_t, history_depth, "history-depth", 20)
CONFIG_VARIABLE (bool, use_overlap_equivalency, "use-overlap-equivalency", false)
CONFIG_VARIABLE (bool, periodic_safety_backups, "periodic-safety-backups", true)
CONFIG_VARIABLE (uint32_t, periodic_safety_backup_interval, "periodic-safety-backup-interval", 120)
-CONFIG_VARIABLE (string, possible_audio_file_regexp, "possible-audio-file-regexp", "\\.(wav|aiff|caf|w64|L|R)$")
+CONFIG_VARIABLE (float, automation_interval, "automation-interval", 50)
+CONFIG_VARIABLE (bool, sync_all_route_ordering, "sync-all-route-ordering", true)
+CONFIG_VARIABLE (bool, only_copy_imported_files, "only-copy-imported-files", true)
/* denormal management */
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index 6c040be63e..6e68c01d8c 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -219,7 +219,7 @@ class IO : public Automatable, public Latent
public:
/* automation */
-
+
struct GainControl : public AutomationControl {
GainControl (std::string name, IO& i, boost::shared_ptr<AutomationList> al)
: AutomationControl (i._session, al, name)
diff --git a/libs/ardour/ardour/profile.h b/libs/ardour/ardour/profile.h
index 3347447915..b016063c4d 100644
--- a/libs/ardour/ardour/profile.h
+++ b/libs/ardour/ardour/profile.h
@@ -29,6 +29,8 @@ class RuntimeProfile {
public:
enum Element {
SmallScreen,
+ SAE,
+ SinglePackage,
LastElement
};
@@ -38,6 +40,12 @@ class RuntimeProfile {
void set_small_screen() { bits[SmallScreen] = true; }
bool get_small_screen() const { return bits[SmallScreen]; }
+ void set_sae () { bits[SAE] = true; }
+ bool get_sae () const { return bits[SAE]; }
+
+ void set_single_package () { bits[SinglePackage] = true; }
+ bool get_single_package () const { return bits[SinglePackage]; }
+
private:
boost::dynamic_bitset<uint64_t> bits;
diff --git a/libs/ardour/ardour/resampled_source.h b/libs/ardour/ardour/resampled_source.h
new file mode 100644
index 0000000000..9a88ca9644
--- /dev/null
+++ b/libs/ardour/ardour/resampled_source.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_resampled_source_h__
+#define __ardour_resampled_source_h__
+
+#include <samplerate.h>
+
+#include <ardour/types.h>
+#include <ardour/importable_source.h>
+
+namespace ARDOUR {
+
+class ResampledImportableSource : public ImportableSource
+{
+ public:
+ ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality);
+ ~ResampledImportableSource ();
+
+ nframes_t read (Sample* buffer, nframes_t nframes);
+
+ float ratio() const { return src_data.src_ratio; }
+
+ static const uint32_t blocksize;
+
+ private:
+ float* input;
+ SRC_STATE* src_state;
+ SRC_DATA src_data;
+};
+
+}
+
+#endif /* __ardour_resampled_source_h__ */
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 1fd6eff0f8..fc17af06ee 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -258,6 +258,9 @@ class Route : public IO
uint32_t remote_control_id () const;
sigc::signal<void> RemoteControlIDChanged;
+ void sync_order_keys ();
+ static sigc::signal<void> SyncOrderKeys;
+
protected:
friend class Session;
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 94caf8a242..bbcae6e91d 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -261,6 +261,8 @@ class Session : public PBD::StatefulDestructible
std::string automation_dir () const;
+ Glib::ustring peak_path (Glib::ustring) const;
+
static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive);
static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive);
@@ -422,6 +424,7 @@ class Session : public PBD::StatefulDestructible
int restore_history (string snapshot_name);
void remove_state (string snapshot_name);
void rename_state (string old_name, string new_name);
+ void remove_pending_capture_state ();
sigc::signal<void,string> StateSaved;
sigc::signal<void> StateReady;
@@ -568,13 +571,14 @@ class Session : public PBD::StatefulDestructible
string doing_what;
/* control info */
- bool multichan;
bool sample_convert;
+ SrcQuality quality;
volatile bool freeze;
std::vector<Glib::ustring> paths;
/* result */
- std::vector<boost::shared_ptr<Region> > new_regions;
+ SourceList sources;
+
};
int import_audiofile (import_status&);
@@ -650,8 +654,6 @@ class Session : public PBD::StatefulDestructible
void add_curve(Curve*);
void add_automation_list(AutomationList*);
- nframes_t automation_interval () const { return _automation_interval; }
-
/* fade curves */
float get_default_fade_length () const { return default_fade_msecs; }
@@ -1650,8 +1652,6 @@ class Session : public PBD::StatefulDestructible
void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
uint32_t _npan_buffers;
- nframes_t _automation_interval;
-
/* VST support */
long _vst_callback (VSTPlugin*,
@@ -1668,7 +1668,6 @@ class Session : public PBD::StatefulDestructible
uint32_t n_physical_outputs;
uint32_t n_physical_inputs;
- void remove_pending_capture_state ();
int find_all_sources (std::string path, std::set<std::string>& result);
int find_all_sources_across_snapshots (std::set<std::string>& result, bool exclude_this_snapshot);
@@ -1688,6 +1687,8 @@ class Session : public PBD::StatefulDestructible
XMLNode& get_control_protocol_state ();
+ void set_history_depth (uint32_t depth);
+ void sync_order_keys ();
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h
index 916e9da49e..4fd71a4c96 100644
--- a/libs/ardour/ardour/sndfilesource.h
+++ b/libs/ardour/ardour/sndfilesource.h
@@ -76,9 +76,6 @@ class SndFileSource : public AudioFileSource {
SF_INFO _info;
SF_BROADCAST_INFO *_broadcast_info;
- mutable float *interleave_buf;
- mutable nframes_t interleave_bufsize;
-
void init ();
int open();
void close();
@@ -105,6 +102,7 @@ class SndFileSource : public AudioFileSource {
void handle_header_position_change ();
static int64_t get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& exists);
+ static Sample* get_interleave_buffer (nframes_t size);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index fb591216bf..01f50126a4 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -36,16 +36,23 @@ class Session;
class SourceFactory {
public:
+ static void init ();
+
static sigc::signal<void,boost::shared_ptr<Source> > SourceCreated;
- static boost::shared_ptr<Source> create (Session&, const XMLNode& node);
+ static boost::shared_ptr<Source> create (Session&, const XMLNode& node, bool async = false);
static boost::shared_ptr<Source> createSilent (Session&, const XMLNode& node, nframes_t nframes, float sample_rate);
- static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags, bool announce = true);
- static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate, bool announce = true);
+ static boost::shared_ptr<Source> createReadable (DataType type, Session&, std::string path, int chn, AudioFileSource::Flag flags,
+ bool announce = true, bool async = false);
+ static boost::shared_ptr<Source> createWritable (DataType type, Session&, std::string name, bool destructive, nframes_t rate,
+ bool announce = true, bool async = true);
+
+ static Glib::Cond* PeaksToBuild;
+ static Glib::StaticMutex peak_building_lock;
+ static std::list<boost::weak_ptr<AudioSource> > files_with_peaks;
- private:
- static int setup_peakfile (boost::shared_ptr<Source>);
+ static int setup_peakfile (boost::shared_ptr<Source>, bool async);
};
}
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index e13bd09d83..5b50713313 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -370,6 +370,15 @@ namespace ARDOUR {
};
typedef std::vector<boost::shared_ptr<Source> > SourceList;
+
+ enum SrcQuality {
+ SrcBest,
+ SrcGood,
+ SrcQuick,
+ SrcFast,
+ SrcFastest
+ };
+
} // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index cde17d8b49..e52274eb1f 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -50,7 +50,7 @@ int cmp_nocase (const std::string& s, const std::string& s2);
int touch_file(Glib::ustring path);
Glib::ustring path_expand (Glib::ustring);
-Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels);
+Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels, bool add_channel_suffix = false, uint32_t total = 0, uint32_t this_one = 0);
bool path_is_paired (Glib::ustring path, Glib::ustring& pair_base);
void compute_equal_power_fades (nframes_t nframes, float* in, float* out);
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index d28d88488e..d5c6120946 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -379,7 +379,9 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
bottom = region;
}
-
+ if (!top->opaque()) {
+ continue;
+ }
OverlapType c = top->coverage (bottom->position(), bottom->last_frame());
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index a4ce5f291d..2a4b36f7d8 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -156,7 +156,7 @@ AudioEngine::start ()
_has_run = true;
Running(); /* EMIT SIGNAL */
} else {
- error << _("cannot activate JACK client") << endmsg;
+ // error << _("cannot activate JACK client") << endmsg;
}
}
@@ -1078,7 +1078,7 @@ AudioEngine::connect_to_jack (string client_name)
error << _("Unable to connect to JACK server") << endmsg;
}
- error << string_compose (_("Could not connect to JACK server as \"%1\""), jack_client_name) << endmsg;
+ // error message is not useful here
return -1;
}
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 1044dd10d2..1284dd343b 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -21,10 +21,13 @@
#include <sys/time.h>
#include <sys/stat.h>
+#include <stdio.h> // for rename(), sigh
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <pbd/convert.h>
+#include <pbd/basename.h>
#include <pbd/mountpoint.h>
#include <pbd/stl_delete.h>
#include <pbd/strsplit.h>
@@ -40,6 +43,7 @@
#include <ardour/sndfile_helpers.h>
#include <ardour/sndfilesource.h>
#include <ardour/session.h>
+#include <ardour/session_directory.h>
#include <ardour/source_factory.h>
#include <ardour/filename_extensions.h>
@@ -153,7 +157,60 @@ AudioFileSource::init (ustring pathstr, bool must_exist)
ustring
AudioFileSource::peak_path (ustring audio_path)
{
- return _session.peak_path_from_audio_path (audio_path);
+ ustring base;
+
+ base = PBD::basename_nosuffix (audio_path);
+ base += '%';
+ base += (char) ('A' + _channel);
+
+ return _session.peak_path (base);
+}
+
+ustring
+AudioFileSource::find_broken_peakfile (ustring peak_path, ustring audio_path)
+{
+ ustring str;
+
+ /* check for the broken location in use by 2.0 for several months */
+
+ str = broken_peak_path (audio_path);
+
+ if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+
+ if (is_embedded()) {
+
+ /* it would be nice to rename it but the nature of
+ the bug means that we can't reliably use it.
+ */
+
+ peak_path = str;
+
+ } else {
+ /* all native files are mono, so we can just rename
+ it.
+ */
+ ::rename (str.c_str(), peak_path.c_str());
+ }
+
+ } else {
+ /* Nasty band-aid for older sessions that were created before we
+ used libsndfile for all audio files.
+ */
+
+
+ str = old_peak_path (audio_path);
+ if (Glib::file_test (str, Glib::FILE_TEST_EXISTS)) {
+ peak_path = str;
+ }
+ }
+
+ return peak_path;
+}
+
+ustring
+AudioFileSource::broken_peak_path (ustring audio_path)
+{
+ return _session.peak_path (audio_path);
}
ustring
@@ -171,9 +228,9 @@ AudioFileSource::old_peak_path (ustring audio_path)
char buf[32];
#ifdef __APPLE__
- snprintf (buf, sizeof (buf), "%u-%u-%d", stat_mount.st_ino, stat_file.st_ino, _channel);
+ snprintf (buf, sizeof (buf), "%u-%u-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
#else
- snprintf (buf, sizeof (buf), "%ld-%ld-%d", stat_mount.st_ino, stat_file.st_ino, _channel);
+ snprintf (buf, sizeof (buf), "%ld-%ld-%d.peak", stat_mount.st_ino, stat_file.st_ino, _channel);
#endif
ustring res = peak_dir;
@@ -227,7 +284,7 @@ AudioFileSource::set_state (const XMLNode& node)
}
if ((prop = node.property (X_("channel"))) != 0) {
- _channel = atoi (prop->value().c_str());
+ _channel = atoi (prop->value());
} else {
_channel = 0;
}
@@ -265,6 +322,10 @@ AudioFileSource::mark_streaming_write_completed ()
if (!writable()) {
return;
}
+
+ /* XXX notice that we're readers of _peaks_built
+ but we must hold a solid lock on PeaksReady.
+ */
Glib::Mutex::Lock lm (_lock);
@@ -432,7 +493,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t&
fullpath += shorter;
if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
- chan = atoi (pathstr.substr (pos+1).c_str());
+ chan = atoi (pathstr.substr (pos+1));
pathstr = shorter;
keeppath = fullpath;
++cnt;
@@ -484,7 +545,7 @@ AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t&
ustring shorter = pathstr.substr (0, pos);
if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
- chan = atoi (pathstr.substr (pos+1).c_str());
+ chan = atoi (pathstr.substr (pos+1));
pathstr = shorter;
}
}
@@ -542,15 +603,6 @@ AudioFileSource::set_header_position_offset (nframes_t offset)
HeaderPositionOffsetChanged ();
}
-void
-AudioFileSource::handle_header_position_change ()
-{
- if (writable()) {
- set_header_timeline_position ();
- flush_header ();
- }
-}
-
void
AudioFileSource::set_timeline_position (int64_t pos)
{
@@ -603,15 +655,15 @@ AudioFileSource::set_source_name (ustring newname, bool destructive)
bool
AudioFileSource::is_empty (Session& s, ustring path)
{
- bool ret = false;
+ SoundFileInfo info;
+ string err;
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (DataType::AUDIO, s, path, 0, NoPeakFile, false));
-
- if (afs) {
- ret = (afs->length() == 0);
+ if (!get_soundfile_info (path, info, err)) {
+ /* dangerous: we can't get info, so assume that its not empty */
+ return false;
}
- return ret;
+ return info.length == 0;
}
int
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index d09a9b29cd..a2ce7209f6 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <poll.h>
#include <float.h>
#include <utime.h>
#include <cerrno>
@@ -29,18 +30,21 @@
#include <algorithm>
#include <vector>
+#include <glibmm/fileutils.h>
+
#include <pbd/xml++.h>
#include <pbd/pthread_utils.h>
#include <ardour/audiosource.h>
#include <ardour/cycle_timer.h>
-#include <ardour/runtime_functions.h>
+#include <ardour/session.h>
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
+using Glib::ustring;
bool AudioSource::_build_missing_peakfiles = false;
bool AudioSource::_build_peakfiles = false;
@@ -126,12 +130,12 @@ bool
AudioSource::peaks_ready (sigc::slot<void> the_slot, sigc::connection& conn) const
{
bool ret;
- Glib::Mutex::Lock lm (_lock);
+ Glib::Mutex::Lock lm (_peaks_ready_lock);
/* check to see if the peak data is ready. if not
connect the slot while still holding the lock.
*/
-
+
if (!(ret = _peaks_built)) {
conn = PeaksReady.connect (the_slot);
}
@@ -182,15 +186,10 @@ AudioSource::initialize_peakfile (bool newfile, ustring audio_path)
peakpath = peak_path (audio_path);
- /* Nasty band-aid for older sessions that were created before we
- used libsndfile for all audio files.
- */
+ /* if the peak file should be there, but isn't .... */
- if (!newfile && access (peakpath.c_str(), R_OK) != 0) {
- ustring str = old_peak_path (audio_path);
- if (access (str.c_str(), R_OK) == 0) {
- peakpath = str;
- }
+ if (!newfile && !Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
+ peakpath = find_broken_peakfile (peakpath, audio_path);
}
if (newfile) {
@@ -332,7 +331,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open, read, close */
if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
- error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+ error << string_compose(_("AudioSource: cannot open peakpath (a) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
@@ -406,7 +405,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open ... close during out: handling */
if ((_peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
- error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+ error << string_compose(_("AudioSource: cannot open peakpath (b) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return 0;
}
@@ -581,9 +580,11 @@ AudioSource::build_peaks_from_scratch ()
{
nframes_t current_frame;
nframes_t cnt;
- Sample buf[frames_per_peak];
+ Sample* buf = 0;
nframes_t frames_read;
nframes_t frames_to_read;
+ const nframes_t bufsize = 65536; // 256kB per disk read for mono data is about ideal
+
int ret = -1;
{
@@ -598,39 +599,41 @@ AudioSource::build_peaks_from_scratch ()
current_frame = 0;
cnt = _length;
_peaks_built = false;
+ buf = new Sample[bufsize];
while (cnt) {
- frames_to_read = min (frames_per_peak, cnt);
+ frames_to_read = min (bufsize, cnt);
if ((frames_read = read_unlocked (buf, current_frame, frames_to_read)) != frames_to_read) {
error << string_compose(_("%1: could not write read raw data for peak computation (%2)"), _name, strerror (errno)) << endmsg;
- done_with_peakfile_writes ();
+ done_with_peakfile_writes (false);
goto out;
}
- if (compute_and_write_peaks (buf, current_frame, frames_read, true)) {
+ if (compute_and_write_peaks (buf, current_frame, frames_read, true, false)) {
break;
}
current_frame += frames_read;
cnt -= frames_read;
}
-
+
if (cnt == 0) {
/* success */
truncate_peakfile();
- _peaks_built = true;
}
- done_with_peakfile_writes ();
+ done_with_peakfile_writes ((cnt == 0));
}
-
- /* lock no longer held, safe to signal */
-
- if (_peaks_built) {
- PeaksReady (); /* EMIT SIGNAL */
- ret = 0;
+
+ {
+ Glib::Mutex::Lock lm (_peaks_ready_lock);
+
+ if (_peaks_built) {
+ PeaksReady (); /* EMIT SIGNAL */
+ ret = 0;
+ }
}
out:
@@ -638,6 +641,10 @@ AudioSource::build_peaks_from_scratch ()
unlink (peakpath.c_str());
}
+ if (buf) {
+ delete [] buf;
+ }
+
return ret;
}
@@ -645,17 +652,21 @@ int
AudioSource::prepare_for_peakfile_writes ()
{
if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
- error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
+ error << string_compose(_("AudioSource: cannot open peakpath (c) \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
return 0;
}
void
-AudioSource::done_with_peakfile_writes ()
+AudioSource::done_with_peakfile_writes (bool done)
{
if (peak_leftover_cnt) {
- compute_and_write_peaks (0, 0, 0, true);
+ compute_and_write_peaks (0, 0, 0, true, false);
+ }
+
+ if (done) {
+ _peaks_built = true;
}
if (peakfile >= 0) {
@@ -665,7 +676,7 @@ AudioSource::done_with_peakfile_writes ()
}
int
-AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force)
+AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframes_t cnt, bool force, bool intermediate_peaks_ready)
{
Sample* buf2 = 0;
nframes_t to_do;
@@ -695,7 +706,8 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
x.min = peak_leftovers[0];
x.max = peak_leftovers[0];
- find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
+
+ ARDOUR::find_peaks (peak_leftovers + 1, peak_leftover_cnt - 1, &x.min, &x.max);
off_t byte = (peak_leftover_frame / frames_per_peak) * sizeof (PeakData);
@@ -706,8 +718,13 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
_peak_byte_max = max (_peak_byte_max, (off_t) (byte + sizeof(PeakData)));
- PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
- PeaksReady (); /* EMIT SIGNAL */
+ {
+ Glib::Mutex::Lock lm (_peaks_ready_lock);
+ PeakRangeReady (peak_leftover_frame, peak_leftover_cnt); /* EMIT SIGNAL */
+ if (intermediate_peaks_ready) {
+ PeaksReady (); /* EMIT SIGNAL */
+ }
+ }
/* left overs are done */
@@ -778,7 +795,7 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
peakbuf[peaks_computed].max = buf[0];
peakbuf[peaks_computed].min = buf[0];
- find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
+ ARDOUR::find_peaks (buf+1, this_time-1, &peakbuf[peaks_computed].min, &peakbuf[peaks_computed].max);
peaks_computed++;
buf += this_time;
@@ -814,8 +831,11 @@ AudioSource::compute_and_write_peaks (Sample* buf, nframes_t first_frame, nframe
_peak_byte_max = max (_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaks_computed));
if (frames_done) {
+ Glib::Mutex::Lock lm (_peaks_ready_lock);
PeakRangeReady (first_frame, frames_done); /* EMIT SIGNAL */
- PeaksReady (); /* EMIT SIGNAL */
+ if (intermediate_peaks_ready) {
+ PeaksReady (); /* EMIT SIGNAL */
+ }
}
ret = 0;
@@ -882,3 +902,11 @@ AudioSource::available_peaks (double zoom_factor) const
return (end/sizeof(PeakData)) * frames_per_peak;
}
+void
+AudioSource::update_length (nframes_t pos, nframes_t cnt)
+{
+ if (pos + cnt > _length) {
+ _length = pos+cnt;
+ }
+}
+
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index e344d5f2a6..c509997b2e 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -137,7 +137,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
boost::shared_ptr<AudioRegion> the_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region)));
the_region->set_position (0, this);
- _diskstream->playlist()->clear ();
+ _diskstream->playlist()->drop_regions ();
_diskstream->playlist()->add_region (the_region, 0, 1);
if (_diskstream->n_channels().n_audio() < the_region->n_channels()) {
diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc
index 0609b8d380..45b19d1997 100644
--- a/libs/ardour/automatable.cc
+++ b/libs/ardour/automatable.cc
@@ -34,6 +34,8 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
+nframes_t Automatable::_automation_interval = 0;
+
Automatable::Automatable(Session& _session, const string& name)
: SessionObject(_session, name)
, _last_automation_snapshot(0)
@@ -422,7 +424,7 @@ Automatable::protect_automation ()
void
Automatable::automation_snapshot (nframes_t now)
{
- if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
+ if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
for (Controls::iterator i = _controls.begin(); i != _controls.end(); ++i) {
if (i->second->list()->automation_write()) {
diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc
index 5faab7c0ab..1460491180 100644
--- a/libs/ardour/configuration.cc
+++ b/libs/ardour/configuration.cc
@@ -25,6 +25,9 @@
#include <pbd/filesystem.h>
#include <pbd/file_utils.h>
+#include <midi++/manager.h>
+
+#include <ardour/ardour.h>
#include <ardour/configuration.h>
#include <ardour/audio_diskstream.h>
#include <ardour/control_protocol_manager.h>
@@ -195,9 +198,12 @@ Configuration::get_state ()
LocaleGuard lg (X_("POSIX"));
root = new XMLNode("Ardour");
- typedef map<string, MidiPortDescriptor*>::const_iterator CI;
- for(CI m = midi_ports.begin(); m != midi_ports.end(); ++m){
- root->add_child_nocopy(m->second->get_state());
+
+ MIDI::Manager::PortMap::const_iterator i;
+ const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
+
+ for (i = ports.begin(); i != ports.end(); ++i) {
+ root->add_child_nocopy(i->second->get_state());
}
root->add_child_nocopy (get_variables (sigc::mem_fun (*this, &Configuration::save_config_options_predicate), "Config"));
@@ -250,10 +256,13 @@ Configuration::set_state (const XMLNode& root)
if (node->name() == "MIDI-port") {
try {
- pair<string,MidiPortDescriptor*> newpair;
- newpair.second = new MidiPortDescriptor (*node);
- newpair.first = newpair.second->tag;
- midi_ports.insert (newpair);
+
+ MIDI::Port::Descriptor desc (*node);
+ map<string,XMLNode>::iterator x;
+ if ((x = midi_ports.find (desc.tag)) != midi_ports.end()) {
+ midi_ports.erase (x);
+ }
+ midi_ports.insert (pair<string,XMLNode>(desc.tag,*node));
}
catch (failed_constructor& err) {
@@ -296,53 +305,6 @@ Configuration::set_variables (const XMLNode& node, ConfigVariableBase::Owner own
#undef CONFIG_VARIABLE_SPECIAL
}
-
-Configuration::MidiPortDescriptor::MidiPortDescriptor (const XMLNode& node)
-{
- const XMLProperty *prop;
- bool have_tag = false;
- bool have_device = false;
- bool have_type = false;
- bool have_mode = false;
-
- if ((prop = node.property ("tag")) != 0) {
- tag = prop->value();
- have_tag = true;
- }
-
- if ((prop = node.property ("device")) != 0) {
- device = prop->value();
- have_device = true;
- }
-
- if ((prop = node.property ("type")) != 0) {
- type = prop->value();
- have_type = true;
- }
-
- if ((prop = node.property ("mode")) != 0) {
- mode = prop->value();
- have_mode = true;
- }
-
- if (!have_tag || !have_device || !have_type || !have_mode) {
- throw failed_constructor();
- }
-}
-
-XMLNode&
-Configuration::MidiPortDescriptor::get_state()
-{
- XMLNode* root = new XMLNode("MIDI-port");
-
- root->add_property("tag", tag);
- root->add_property("device", device);
- root->add_property("type", type);
- root->add_property("mode", mode);
-
- return *root;
-}
-
void
Configuration::map_parameters (sigc::slot<void,const char*> theSlot)
{
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 556f11125e..d45d5efa9f 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -294,6 +294,13 @@ Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
offset = start - _position;
+ /* Prevent data from piling up inthe crossfade buffers when reading a transparent region */
+ if (!(_out->opaque())) {
+ memset (crossfade_buffer_out, 0, sizeof (Sample) * to_write);
+ } else if (!(_in->opaque())) {
+ memset (crossfade_buffer_in, 0, sizeof (Sample) * to_write);
+ }
+
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n);
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n);
@@ -358,6 +365,13 @@ Crossfade::refresh ()
return false;
}
+ /* Top layer shouldn't be transparent */
+
+ if (!((layer_relation > 0 ? _in : _out)->opaque())) {
+ Invalidated (shared_from_this());
+ return false;
+ }
+
/* layer ordering cannot change */
int32_t new_layer_relation = (int32_t) (_in->layer() - _out->layer());
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index 52be946f1e..c3eae5ad86 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -39,7 +39,6 @@
#include <pbd/fpu.h>
#include <midi++/port.h>
-#include <midi++/port_request.h>
#include <midi++/manager.h>
#include <midi++/mmc.h>
@@ -51,6 +50,7 @@
#include <ardour/audiosource.h>
#include <ardour/utils.h>
#include <ardour/session.h>
+#include <ardour/source_factory.h>
#include <ardour/control_protocol_manager.h>
#include <ardour/audioengine.h>
@@ -114,47 +114,25 @@ setup_osc ()
#endif
int
-ARDOUR::setup_midi (AudioEngine& engine)
+setup_midi ()
{
- std::map<string,Configuration::MidiPortDescriptor*>::iterator i;
- int nports;
-
- if ((nports = Config->midi_ports.size()) == 0) {
+ if (Config->midi_ports.size() == 0) {
warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg;
return 0;
}
- MIDI::Manager::instance()->set_api_data(engine.jack());
-
- for (i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
- Configuration::MidiPortDescriptor* port_descriptor;
-
- port_descriptor = (*i).second;
-
- MIDI::PortRequest request (port_descriptor->device,
- port_descriptor->tag,
- port_descriptor->mode,
- port_descriptor->type);
-
- if (request.status != MIDI::PortRequest::OK) {
- error << string_compose(_("MIDI port specifications for \"%1\" are not understandable."), port_descriptor->tag) << endmsg;
- continue;
- }
-
- MIDI::Manager::instance()->add_port (request);
-
- nports++;
+ for (std::map<string,XMLNode>::iterator i = Config->midi_ports.begin(); i != Config->midi_ports.end(); ++i) {
+ MIDI::Manager::instance()->add_port (i->second);
}
MIDI::Port* first;
const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
- first = ports.begin()->second;
- if (nports > 1) {
+ if (ports.size() > 1) {
- /* More than one port, so try using specific names for each port */
+ first = ports.begin()->second;
- map<string,Configuration::MidiPortDescriptor *>::iterator i;
+ /* More than one port, so try using specific names for each port */
if (Config->get_mmc_port_name() != N_("default")) {
default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name());
@@ -182,11 +160,13 @@ ARDOUR::setup_midi (AudioEngine& engine)
default_midi_port = first;
}
- } else {
+ } else if (ports.size() == 1) {
+
+ first = ports.begin()->second;
/* Only one port described, so use it for both MTC and MMC */
- default_mmc_port = MIDI::Manager::instance()->port ("");
+ default_mmc_port = first;
default_mtc_port = default_mmc_port;
default_midi_port = default_mmc_port;
}
@@ -209,15 +189,16 @@ ARDOUR::setup_midi (AudioEngine& engine)
return 0;
}
-
+
void
setup_hardware_optimization (bool try_optimization)
{
bool generic_mix_functions = true;
- FPU fpu;
if (try_optimization) {
+ FPU fpu;
+
#if defined (ARCH_X86) && defined (BUILD_SSE_OPTIMIZATIONS)
if (fpu.has_sse()) {
@@ -253,6 +234,10 @@ setup_hardware_optimization (bool try_optimization)
info << "Apple VecLib H/W specific optimizations in use" << endmsg;
}
#endif
+
+ /* consider FPU denormal handling to be "h/w optimization" */
+
+ setup_fpu ();
}
if (generic_mix_functions) {
@@ -265,9 +250,6 @@ setup_hardware_optimization (bool try_optimization)
info << "No H/W specific optimizations in use" << endmsg;
}
-
- setup_fpu ();
-
}
int
@@ -306,6 +288,8 @@ ARDOUR::init (bool use_vst, bool try_optimization)
setup_hardware_optimization (try_optimization);
+ SourceFactory::init ();
+
/* singleton - first object is "it" */
new PluginManager ();
@@ -387,6 +371,13 @@ ARDOUR::LocaleGuard::~LocaleGuard ()
void
ARDOUR::setup_fpu ()
{
+
+ if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
+ // valgrind doesn't understand this assembler stuff
+ // September 10th, 2007
+ return;
+ }
+
#if defined(ARCH_X86) && defined(USE_XMMINTRIN)
int MXCSR;
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index bc16cde156..bd6351cf05 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -32,9 +32,9 @@
#include <glibmm.h>
#include <pbd/basename.h>
+#include <pbd/convert.h>
#include <ardour/ardour.h>
-#include <ardour/types.h>
#include <ardour/session.h>
#include <ardour/session_directory.h>
#include <ardour/audio_diskstream.h>
@@ -43,82 +43,22 @@
#include <ardour/audioregion.h>
#include <ardour/region_factory.h>
#include <ardour/source_factory.h>
-
+#include <ardour/resampled_source.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
-#define BLOCKSIZE 4096U
-
-class ImportableSource {
- public:
- ImportableSource (SNDFILE* sf, SF_INFO* info) : in (sf), sf_info (info) {}
- virtual ~ImportableSource() {}
-
- virtual nframes_t read (Sample* buffer, nframes_t nframes) {
- nframes_t per_channel = nframes / sf_info->channels;
- per_channel = sf_readf_float (in, buffer, per_channel);
- return per_channel * sf_info->channels;
- }
-
- virtual float ratio() const { return 1.0f; }
-
-protected:
- SNDFILE* in;
- SF_INFO* sf_info;
-};
-
-class ResampledImportableSource : public ImportableSource {
- public:
- ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate) : ImportableSource (sf, info) {
- int err;
-
- sf_seek (in, 0, SEEK_SET) ;
-
- /* Initialize the sample rate converter. */
-
- if ((src_state = src_new (SRC_SINC_BEST_QUALITY, sf_info->channels, &err)) == 0) {
- error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
- throw failed_constructor ();
- }
-
- src_data.end_of_input = 0 ; /* Set this later. */
-
- /* Start with zero to force load in while loop. */
-
- src_data.input_frames = 0 ;
- src_data.data_in = input ;
-
- src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
-
- }
-
- ~ResampledImportableSource () {
- src_state = src_delete (src_state) ;
- }
-
- nframes_t read (Sample* buffer, nframes_t nframes);
-
- float ratio() const { return src_data.src_ratio; }
-
- private:
- float input[BLOCKSIZE];
- SRC_STATE* src_state;
- SRC_DATA src_data;
-};
-
int
Session::import_audiofile (import_status& status)
{
SNDFILE *in;
vector<boost::shared_ptr<AudioFileSource> > newfiles;
- SourceList sources;
SF_INFO info;
float *data = 0;
Sample **channel_data = 0;
- long nfiles = 0;
+ int nfiles = 0;
string basepath;
string sounds_dir;
nframes_t so_far;
@@ -127,178 +67,166 @@ Session::import_audiofile (import_status& status)
vector<string> new_paths;
struct tm* now;
ImportableSource* importable = 0;
- const nframes_t nframes = BLOCKSIZE;
-
- status.new_regions.clear ();
-
- if ((in = sf_open (status.paths.front().c_str(), SFM_READ, &info)) == 0) {
- error << string_compose(_("Import: cannot open input sound file \"%1\""), status.paths.front()) << endmsg;
- status.done = 1;
- status.cancel = 1;
- return -1;
- }
-
- if ((nframes_t) info.samplerate != frame_rate()) {
- importable = new ResampledImportableSource (in, &info, frame_rate());
- } else {
- importable = new ImportableSource (in, &info);
- }
-
- for (int n = 0; n < info.channels; ++n) {
- newfiles.push_back (boost::shared_ptr<AudioFileSource>());
- }
+ const nframes_t nframes = ResampledImportableSource::blocksize;
+ uint32_t cnt = 1;
- SessionDirectory sdir(get_best_session_directory_for_new_source ());
- sounds_dir = sdir.sound_path().to_string();
-
- basepath = PBD::basename_nosuffix (status.paths.front());
+ status.sources.clear ();
+
+ for (vector<Glib::ustring>::iterator p = status.paths.begin(); p != status.paths.end(); ++p, ++cnt) {
- for (int n = 0; n < info.channels; ++n) {
+ if ((in = sf_open ((*p).c_str(), SFM_READ, &info)) == 0) {
+ error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
+ status.done = 1;
+ status.cancel = 1;
+ return -1;
+ }
+
+ if ((nframes_t) info.samplerate != frame_rate()) {
+ importable = new ResampledImportableSource (in, &info, frame_rate(), status.quality);
+ } else {
+ importable = new ImportableSource (in, &info);
+ }
+
+ newfiles.clear ();
- bool goodfile = false;
+ for (int n = 0; n < info.channels; ++n) {
+ newfiles.push_back (boost::shared_ptr<AudioFileSource>());
+ }
+
+ SessionDirectory sdir(get_best_session_directory_for_new_source ());
+ sounds_dir = sdir.sound_path().to_string();
- do {
- if (info.channels == 2) {
- if (n == 0) {
- snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+ basepath = PBD::basename_nosuffix ((*p));
+
+ for (int n = 0; n < info.channels; ++n) {
+
+ bool goodfile = false;
+
+ do {
+ if (info.channels == 2) {
+ if (n == 0) {
+ snprintf (buf, sizeof(buf), "%s/%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+ } else {
+ snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+ }
+ } else if (info.channels > 1) {
+ snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
} else {
- snprintf (buf, sizeof(buf), "%s/%s-R.wav", sounds_dir.c_str(), basepath.c_str());
+ snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
}
- } else if (info.channels > 1) {
- snprintf (buf, sizeof(buf), "%s/%s-c%d.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
- } else {
- snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
- }
- if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
+ if (Glib::file_test (buf, Glib::FILE_TEST_EXISTS)) {
- /* if the file already exists, we must come up with
- * a new name for it. for now we just keep appending
- * _ to basepath
- */
+ /* if the file already exists, we must come up with
+ * a new name for it. for now we just keep appending
+ * _ to basepath
+ */
- basepath += "_";
+ basepath += "_";
- } else {
+ } else {
- goodfile = true;
- }
+ goodfile = true;
+ }
- } while ( !goodfile);
+ } while ( !goodfile);
- try {
- newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (
- SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
- }
+ try {
+ newfiles[n] = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
+ }
- catch (failed_constructor& err) {
- error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
- goto out;
- }
+ catch (failed_constructor& err) {
+ error << string_compose(_("Session::import_audiofile: cannot open new file source for channel %1"), n+1) << endmsg;
+ goto out;
+ }
- new_paths.push_back (buf);
- nfiles++;
- }
+ new_paths.push_back (buf);
+ newfiles[n]->prepare_for_peakfile_writes ();
+ nfiles++;
+ }
- data = new float[nframes * info.channels];
- channel_data = new Sample * [ info.channels ];
+ data = new float[nframes * info.channels];
+ channel_data = new Sample * [ info.channels ];
- for (int n = 0; n < info.channels; ++n) {
- channel_data[n] = new Sample[nframes];
- }
+ for (int n = 0; n < info.channels; ++n) {
+ channel_data[n] = new Sample[nframes];
+ }
- so_far = 0;
+ so_far = 0;
- status.doing_what = _("converting audio");
- status.progress = 0.0;
+ if ((nframes_t) info.samplerate != frame_rate()) {
+ status.doing_what = string_compose (_("converting %1\n(resample from %2KHz to %3KHz)\n(%4 of %5)"),
+ basepath,
+ info.samplerate/1000.0f,
+ frame_rate()/1000.0f,
+ cnt, status.paths.size());
+
+ } else {
+ status.doing_what = string_compose (_("converting %1\n(%2 of %3)"),
+ basepath,
+ cnt, status.paths.size());
- while (!status.cancel) {
+ }
+
+ status.progress = 0.0;
+
+ while (!status.cancel) {
- nframes_t nread, nfread;
- long x;
- long chn;
+ nframes_t nread, nfread;
+ long x;
+ long chn;
- if ((nread = importable->read (data, nframes)) == 0) {
- break;
- }
- nfread = nread / info.channels;
+ if ((nread = importable->read (data, nframes)) == 0) {
+ break;
+ }
+ nfread = nread / info.channels;
- /* de-interleave */
+ /* de-interleave */
- for (chn = 0; chn < info.channels; ++chn) {
+ for (chn = 0; chn < info.channels; ++chn) {
- nframes_t n;
- for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
- channel_data[chn][n] = (Sample) data[x];
+ nframes_t n;
+ for (x = chn, n = 0; n < nfread; x += info.channels, ++n) {
+ channel_data[chn][n] = (Sample) data[x];
+ }
}
- }
- /* flush to disk */
+ /* flush to disk */
- for (chn = 0; chn < info.channels; ++chn) {
- newfiles[chn]->write (channel_data[chn], nfread);
- }
+ for (chn = 0; chn < info.channels; ++chn) {
+ newfiles[chn]->write (channel_data[chn], nfread);
+ }
- so_far += nread;
- status.progress = so_far / (importable->ratio () * info.frames * info.channels);
- }
+ so_far += nread;
+ status.progress = so_far / (importable->ratio () * info.frames * info.channels);
+ }
- if (status.cancel) {
- goto out;
- }
+ if (status.cancel) {
+ goto out;
+ }
+
+ for (int n = 0; n < info.channels; ++n) {
+ status.sources.push_back (newfiles[n]);
+ }
- if (status.multichan) {
- status.doing_what = _("building region");
- } else {
- status.doing_what = _("building regions");
+ if (status.cancel) {
+ goto out;
+ }
}
-
+
status.freeze = true;
time_t xnow;
time (&xnow);
now = localtime (&xnow);
- if (status.multichan) {
- /* all sources are used in a single multichannel region */
+ /* flush the final length(s) to the header(s) */
- for (int n = 0; n < nfiles && !status.cancel; ++n) {
- /* flush the final length to the header */
- newfiles[n]->update_header(0, *now, xnow);
- sources.push_back(newfiles[n]);
- }
-
- bool strip_paired_suffixes = (newfiles.size() > 1);
-
- boost::shared_ptr<AudioRegion> r (boost::dynamic_pointer_cast<AudioRegion>
- (RegionFactory::create (sources, 0,
- newfiles[0]->length(),
- region_name_from_path (basepath, strip_paired_suffixes),
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
-
- status.new_regions.push_back (r);
-
- } else {
- for (int n = 0; n < nfiles && !status.cancel; ++n) {
-
- /* flush the final length to the header */
-
- newfiles[n]->update_header(0, *now, xnow);
-
- /* The sources had zero-length when created, which means that the Session
- did not bother to create whole-file AudioRegions for them. Do it now.
-
- Note: leave any trailing paired indicators from the file names as part
- of the region name.
- */
-
- status.new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion>
- (RegionFactory::create (boost::static_pointer_cast<Source> (newfiles[n]), 0, newfiles[n]->length(),
- region_name_from_path (newfiles[n]->name(), false),
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile | AudioRegion::Import))));
- }
+ for (SourceList::iterator x = status.sources.begin(); x != status.sources.end() && !status.cancel; ++x) {
+ boost::dynamic_pointer_cast<AudioFileSource>(*x)->update_header(0, *now, xnow);
+ boost::dynamic_pointer_cast<AudioSource>(*x)->done_with_peakfile_writes ();
}
-
+
/* save state so that we don't lose these new Sources */
if (!status.cancel) {
@@ -321,7 +249,8 @@ Session::import_audiofile (import_status& status)
}
if (status.cancel) {
- status.new_regions.clear ();
+
+ status.sources.clear ();
for (vector<string>::iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
unlink ((*i).c_str());
@@ -337,50 +266,3 @@ Session::import_audiofile (import_status& status)
return ret;
}
-
-nframes_t
-ResampledImportableSource::read (Sample* output, nframes_t nframes)
-{
- int err;
-
- /* If the input buffer is empty, refill it. */
-
- if (src_data.input_frames == 0) {
-
- src_data.input_frames = ImportableSource::read (input, BLOCKSIZE);
-
- /* The last read will not be a full buffer, so set end_of_input. */
-
- if ((nframes_t) src_data.input_frames < BLOCKSIZE) {
- src_data.end_of_input = SF_TRUE ;
- }
-
- src_data.input_frames /= sf_info->channels;
- src_data.data_in = input ;
- }
-
- src_data.data_out = output;
-
- if (!src_data.end_of_input) {
- src_data.output_frames = nframes / sf_info->channels ;
- } else {
- src_data.output_frames = src_data.input_frames;
- }
-
- if ((err = src_process (src_state, &src_data))) {
- error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
- return 0 ;
- }
-
- /* Terminate if at end */
-
- if (src_data.end_of_input && src_data.output_frames_gen == 0) {
- return 0;
- }
-
- src_data.data_in += src_data.input_frames_used * sf_info->channels ;
- src_data.input_frames -= src_data.input_frames_used ;
-
- return src_data.output_frames_gen * sf_info->channels;
-}
-
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index a708821c20..bff8c18bc9 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -1307,7 +1307,7 @@ IO::state (bool full_state)
int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
- snprintf (buf, sizeof(buf)-1, "%zd,%d,%zd,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
+ snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
node->add_property ("iolimits", buf);
@@ -2335,7 +2335,7 @@ IO::automation_snapshot (nframes_t now)
{
Automatable::automation_snapshot (now);
- if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _session.automation_interval()) {
+ if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
_panner->snapshot (now);
}
}
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index 4af7e2b907..09b54000d8 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -1176,8 +1176,8 @@ Playlist::region_changed (Change what_changed, boost::shared_ptr<Region> region)
save = !(_splicing || _nudging);
}
- if ((what_changed & Region::MuteChanged) &&
- !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
+ if ((what_changed & our_interests) &&
+ !(what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged))) {
check_dependents (region, false);
}
diff --git a/libs/ardour/resampled_source.cc b/libs/ardour/resampled_source.cc
new file mode 100644
index 0000000000..38aa3832b9
--- /dev/null
+++ b/libs/ardour/resampled_source.cc
@@ -0,0 +1,128 @@
+/*
+ Copyright (C) 2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <pbd/error.h>
+#include <ardour/resampled_source.h>
+#include <pbd/failed_constructor.h>
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+
+const uint32_t ResampledImportableSource::blocksize = 4096U;
+
+ResampledImportableSource::ResampledImportableSource (SNDFILE* sf, SF_INFO* info, nframes_t rate, SrcQuality srcq)
+ : ImportableSource (sf, info)
+{
+ int err;
+
+ sf_seek (in, 0, SEEK_SET) ;
+
+ /* Initialize the sample rate converter. */
+
+ int src_type;
+
+ switch (srcq) {
+ case SrcBest:
+ src_type = SRC_SINC_BEST_QUALITY;
+ break;
+ case SrcGood:
+ src_type = SRC_SINC_MEDIUM_QUALITY;
+ break;
+ case SrcQuick:
+ src_type = SRC_SINC_FASTEST;
+ break;
+ case SrcFast:
+ src_type = SRC_ZERO_ORDER_HOLD;
+ break;
+ case SrcFastest:
+ src_type = SRC_LINEAR;
+ break;
+ }
+
+ if ((src_state = src_new (src_type, sf_info->channels, &err)) == 0) {
+ error << string_compose(_("Import: src_new() failed : %1"), src_strerror (err)) << endmsg ;
+ throw failed_constructor ();
+ }
+
+ src_data.end_of_input = 0 ; /* Set this later. */
+
+ /* Start with zero to force load in while loop. */
+
+ src_data.input_frames = 0 ;
+ src_data.data_in = input ;
+
+ src_data.src_ratio = ((float) rate) / sf_info->samplerate ;
+
+ input = new float[blocksize];
+}
+
+ResampledImportableSource::~ResampledImportableSource ()
+{
+ src_state = src_delete (src_state) ;
+ delete [] input;
+}
+
+nframes_t
+ResampledImportableSource::read (Sample* output, nframes_t nframes)
+{
+ int err;
+
+ /* If the input buffer is empty, refill it. */
+
+ if (src_data.input_frames == 0) {
+
+ src_data.input_frames = ImportableSource::read (input, blocksize);
+
+ /* The last read will not be a full buffer, so set end_of_input. */
+
+ if ((nframes_t) src_data.input_frames < blocksize) {
+ src_data.end_of_input = SF_TRUE ;
+ }
+
+ src_data.input_frames /= sf_info->channels;
+ src_data.data_in = input ;
+ }
+
+ src_data.data_out = output;
+
+ if (!src_data.end_of_input) {
+ src_data.output_frames = nframes / sf_info->channels ;
+ } else {
+ src_data.output_frames = src_data.input_frames;
+ }
+
+ if ((err = src_process (src_state, &src_data))) {
+ error << string_compose(_("Import: %1"), src_strerror (err)) << endmsg ;
+ return 0 ;
+ }
+
+ /* Terminate if at end */
+
+ if (src_data.end_of_input && src_data.output_frames_gen == 0) {
+ return 0;
+ }
+
+ src_data.data_in += src_data.input_frames_used * sf_info->channels ;
+ src_data.input_frames -= src_data.input_frames_used ;
+
+ return src_data.output_frames_gen * sf_info->channels;
+}
+
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 19095425f2..be7dfb8469 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -53,7 +53,7 @@ using namespace ARDOUR;
using namespace PBD;
uint32_t Route::order_key_cnt = 0;
-
+sigc::signal<void> Route::SyncOrderKeys;
Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
: IO (sess, name, input_min, input_max, output_min, output_max, default_type),
@@ -161,10 +161,35 @@ void
Route::set_order_key (const char* name, long n)
{
order_keys[strdup(name)] = n;
+
+ if (Config->get_sync_all_route_ordering()) {
+ for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
+ x->second = n;
+ }
+ }
+
_session.set_dirty ();
}
void
+Route::sync_order_keys ()
+{
+ uint32_t key;
+
+ if (order_keys.empty()) {
+ return;
+ }
+
+ OrderKeys::iterator x = order_keys.begin();
+ key = x->second;
+ ++x;
+
+ for (; x != order_keys.end(); ++x) {
+ x->second = key;
+ }
+}
+
+void
Route::inc_gain (gain_t fraction, void *src)
{
IO::inc_gain (fraction, src);
@@ -460,13 +485,9 @@ Route::process_output_buffers (BufferSet& bufs,
// OR recording
- // h/w monitoring not in use
-
- (!Config->get_monitoring_model() == HardwareMonitoring &&
-
// AND software monitoring required
- Config->get_monitoring_model() == SoftwareMonitoring)) {
+ Config->get_monitoring_model() == SoftwareMonitoring) {
if (apply_gain_automation) {
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 742b17af2c..e7f2c542e6 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -124,8 +124,7 @@ Session::Session (AudioEngine &eng,
routes (new RouteList),
auditioner ((Auditioner*) 0),
_click_io ((IO*) 0),
- main_outs (0),
- _automation_interval (0)
+ main_outs (0)
{
if (!eng.connected()) {
throw failed_constructor();
@@ -224,8 +223,7 @@ Session::Session (AudioEngine &eng,
_send_smpte_update (false),
diskstreams (new DiskstreamList),
routes (new RouteList),
- main_outs (0),
- _automation_interval (0)
+ main_outs (0)
{
if (!eng.connected()) {
@@ -1257,8 +1255,10 @@ Session::set_frame_rate (nframes_t frames_per_second)
sync_time_vars();
- _automation_interval = ((nframes_t) ceil ((double) frames_per_second * 0.25));
+ Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
+ clear_clicks ();
+
// XXX we need some equivalent to this, somehow
// SndFileSource::setup_standard_crossfades (frames_per_second);
@@ -2755,13 +2755,11 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
return boost::shared_ptr<Source>();
}
-string
-Session::peak_path_from_audio_path (string audio_path) const
+Glib::ustring
+Session::peak_path (Glib::ustring base) const
{
sys::path peakfile_path(_session_dir->peak_path());
-
- peakfile_path /= basename_nosuffix (audio_path) + peakfile_suffix;
-
+ peakfile_path /= basename_nosuffix (base) + peakfile_suffix;
return peakfile_path.to_string();
}
@@ -3387,8 +3385,8 @@ Session::remove_empty_sounds ()
try
{
sys::remove (audio_file_path);
- const string peak_path = peak_path_from_audio_path (audio_file_path.to_string());
- sys::remove (peak_path);
+ const string peakfile = peak_path (audio_file_path.to_string());
+ sys::remove (peakfile);
}
catch (const sys::filesystem_error& err)
{
@@ -4124,6 +4122,23 @@ Session::compute_initial_length ()
}
void
+Session::sync_order_keys ()
+{
+ if (!Config->get_sync_all_route_ordering()) {
+ /* leave order keys as they are */
+ return;
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->sync_order_keys ();
+ }
+
+ Route::SyncOrderKeys (); // EMIT SIGNAL
+}
+
+void
Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
{
Glib::Mutex::Lock lm (bundle_lock);
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index 35c1019c0e..aa5a1b87d4 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -410,6 +410,8 @@ Session::process_event (Event* ev)
case Event::Audition:
set_audition (ev->region);
+ // drop reference to region
+ ev->region.reset ();
break;
case Event::InputConfigurationChange:
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index f2f396cbee..0534da6c89 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -138,10 +138,14 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_name = _current_snapshot_name = snapshot_name;
+ set_history_depth (Config->get_history_depth());
+
_current_frame_rate = _engine.frame_rate ();
_tempo_map = new TempoMap (_current_frame_rate);
_tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
+
+
g_atomic_int_set (&processing_prohibited, 0);
insert_cnt = 0;
_transport_speed = 0;
@@ -501,7 +505,7 @@ void
Session::remove_pending_capture_state ()
{
sys::path pending_state_file_path(_session_dir->root_path());
-
+
pending_state_file_path /= _current_snapshot_name + pending_suffix;
try
@@ -2668,8 +2672,6 @@ Session::save_history (string snapshot_name)
{
XMLTree tree;
- tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
-
if (snapshot_name.empty()) {
snapshot_name = _current_snapshot_name;
}
@@ -2691,6 +2693,13 @@ Session::save_history (string snapshot_name)
}
}
+
+ if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
+ return 0;
+ }
+
+ tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
+
if (!tree.write (xml_path.to_string()))
{
error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
@@ -2977,6 +2986,10 @@ Session::config_changed (const char* parameter_name)
set_remote_control_ids ();
} else if (PARAM_IS ("denormal-model")) {
setup_fpu ();
+ } else if (PARAM_IS ("history-depth")) {
+ set_history_depth (Config->get_history_depth());
+ } else if (PARAM_IS ("sync-all-route-ordering")) {
+ sync_order_keys ();
}
set_dirty ();
@@ -2984,3 +2997,9 @@ Session::config_changed (const char* parameter_name)
#undef PARAM_IS
}
+
+void
+Session::set_history_depth (uint32_t d)
+{
+ _history.set_depth (d);
+}
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index 6977eef6bd..7c4859aa55 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -25,7 +25,7 @@
#include <sys/stat.h>
#include <glibmm/miscutils.h>
-
+#include <glibmm/thread.h>
#include <ardour/sndfilesource.h>
#include <ardour/sndfile_helpers.h>
#include <ardour/utils.h>
@@ -45,6 +45,21 @@ const AudioFileSource::Flag SndFileSource::default_writable_flags = AudioFileSou
AudioFileSource::RemovableIfEmpty|
AudioFileSource::CanRename);
+struct SizedSampleBuffer {
+ nframes_t size;
+ Sample* buf;
+
+ SizedSampleBuffer (nframes_t sz) : size (sz) {
+ buf = new Sample[size];
+ }
+
+ ~SizedSampleBuffer() {
+ delete [] buf;
+ }
+};
+
+Glib::StaticPrivate<SizedSampleBuffer> thread_interleave_buffer = GLIBMM_STATIC_PRIVATE_INIT;
+
SndFileSource::SndFileSource (Session& s, const XMLNode& node)
: AudioFileSource (s, node)
{
@@ -186,8 +201,6 @@ SndFileSource::init ()
// lets try to keep the object initalizations here at the top
xfade_buf = 0;
- interleave_buf = 0;
- interleave_bufsize = 0;
sf = 0;
_broadcast_info = 0;
@@ -272,10 +285,6 @@ SndFileSource::~SndFileSource ()
touch_peakfile ();
}
- if (interleave_buf) {
- delete [] interleave_buf;
- }
-
if (_broadcast_info) {
delete _broadcast_info;
}
@@ -341,14 +350,7 @@ SndFileSource::read_unlocked (Sample *dst, nframes_t start, nframes_t cnt) const
real_cnt = cnt * _info.channels;
- if (interleave_bufsize < real_cnt) {
-
- if (interleave_buf) {
- delete [] interleave_buf;
- }
- interleave_bufsize = real_cnt;
- interleave_buf = new float[interleave_bufsize];
- }
+ Sample* interleave_buf = get_interleave_buffer (real_cnt);
nread = sf_read_float (sf, interleave_buf, real_cnt);
ptr = interleave_buf + _channel;
@@ -401,7 +403,7 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
update_length (oldlen, cnt);
if (_build_peakfiles) {
- compute_and_write_peaks (data, frame_pos, cnt, false);
+ compute_and_write_peaks (data, frame_pos, cnt, false, true);
}
_write_data_count = cnt;
@@ -493,7 +495,7 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
update_length (file_pos, cnt);
if (_build_peakfiles) {
- compute_and_write_peaks (data, file_pos, cnt, false);
+ compute_and_write_peaks (data, file_pos, cnt, false, true);
}
file_pos += cnt;
@@ -904,3 +906,21 @@ SndFileSource::one_of_several_channels () const
{
return _info.channels > 1;
}
+
+Sample*
+SndFileSource::get_interleave_buffer (nframes_t size)
+{
+ SizedSampleBuffer* ssb;
+
+ if ((ssb = thread_interleave_buffer.get()) == 0) {
+ ssb = new SizedSampleBuffer (size);
+ thread_interleave_buffer.set (ssb);
+ }
+
+ if (ssb->size < size) {
+ ssb = new SizedSampleBuffer (size);
+ thread_interleave_buffer.set (ssb);
+ }
+
+ return ssb->buf;
+}
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 148f737551..c6b19c8600 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -19,6 +19,8 @@
*/
#include <pbd/error.h>
+#include <pbd/convert.h>
+#include <pbd/pthread_utils.h>
#include <ardour/source_factory.h>
#include <ardour/sndfilesource.h>
@@ -37,15 +39,69 @@ using namespace std;
using namespace PBD;
sigc::signal<void,boost::shared_ptr<Source> > SourceFactory::SourceCreated;
+Glib::Cond* SourceFactory::PeaksToBuild;
+Glib::StaticMutex SourceFactory::peak_building_lock;
+std::list<boost::weak_ptr<AudioSource> > SourceFactory::files_with_peaks;
+
+static void
+peak_thread_work ()
+{
+ PBD::ThreadCreated (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec));
+
+ while (true) {
+
+ SourceFactory::peak_building_lock.lock ();
+
+ wait:
+ if (SourceFactory::files_with_peaks.empty()) {
+ SourceFactory::PeaksToBuild->wait (SourceFactory::peak_building_lock);
+ }
+
+ if (SourceFactory::files_with_peaks.empty()) {
+ goto wait;
+ }
+
+ boost::shared_ptr<AudioSource> as (SourceFactory::files_with_peaks.front().lock());
+ SourceFactory::files_with_peaks.pop_front ();
+ SourceFactory::peak_building_lock.unlock ();
+
+ if (!as) {
+ continue;
+ }
+
+ as->setup_peakfile ();
+ }
+}
+
+void
+SourceFactory::init ()
+{
+ PeaksToBuild = new Glib::Cond();
+
+ for (int n = 0; n < 2; ++n) {
+ Glib::Thread::create (sigc::ptr_fun (::peak_thread_work), false);
+ }
+}
int
-SourceFactory::setup_peakfile (boost::shared_ptr<Source> s)
+SourceFactory::setup_peakfile (boost::shared_ptr<Source> s, bool async)
{
boost::shared_ptr<AudioSource> as (boost::dynamic_pointer_cast<AudioSource> (s));
+
if (as) {
- if (as->setup_peakfile ()) {
- error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
- return -1;
+
+ if (async) {
+
+ Glib::Mutex::Lock lm (peak_building_lock);
+ files_with_peaks.push_back (boost::weak_ptr<AudioSource> (as));
+ PeaksToBuild->broadcast ();
+
+ } else {
+
+ if (as->setup_peakfile ()) {
+ error << string_compose("SourceFactory: could not set up peakfile for %1", as->name()) << endmsg;
+ return -1;
+ }
}
}
@@ -60,84 +116,85 @@ SourceFactory::createSilent (Session& s, const XMLNode& node, nframes_t nframes,
return ret;
}
+#ifdef USE_COREAUDIO_FOR_FILES
boost::shared_ptr<Source>
-SourceFactory::create (Session& s, const XMLNode& node)
+SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
{
- /* this is allowed to throw */
-
- DataType type = DataType::AUDIO;
- const XMLProperty* prop = node.property("type");
- if (prop) {
- type = DataType(prop->value());
- }
-
- if (type == DataType::AUDIO) {
-
-#ifdef HAVE_COREAUDIO
- try {
- boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
- if (setup_peakfile (ret)) {
+ try {
+ boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
return boost::shared_ptr<Source>();
}
- SourceCreated (ret);
- return ret;
- }
+ }
+ SourceCreated (ret);
+ return ret;
+ }
- catch (failed_constructor& err) {
-
- /* this is allowed to throw */
-
- boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- if (setup_peakfile (ret)) {
+
+ catch (failed_constructor& err) {
+
+ /* this is allowed to throw */
+
+ boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
return boost::shared_ptr<Source>();
}
- SourceCreated (ret);
- return ret;
}
-#else
- boost::shared_ptr<Source> ret (new SndFileSource (s, node));
-
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
-
SourceCreated (ret);
return ret;
-#endif
+ }
- } else if (type == DataType::MIDI) {
+ return boost::shared_ptr<Source>();
+}
- boost::shared_ptr<Source> ret (new SMFSource (s, node));
-
- SourceCreated (ret);
- return ret;
+#else
+
+boost::shared_ptr<Source>
+SourceFactory::create (Session& s, const XMLNode& node, bool defer_peaks)
+{
+ /* this is allowed to throw */
+ boost::shared_ptr<Source> ret (new SndFileSource (s, node));
+
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
+ return boost::shared_ptr<Source>();
+ }
}
- return boost::shared_ptr<Source> ();
+ SourceCreated (ret);
+ return ret;
}
+#endif // USE_COREAUDIO_FOR_FILES
+
boost::shared_ptr<Source>
-SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce)
+SourceFactory::createReadable (DataType type, Session& s, string path, int chn, AudioFileSource::Flag flags, bool announce, bool defer_peaks)
{
if (type == DataType::AUDIO) {
#ifdef HAVE_COREAUDIO
try {
boost::shared_ptr<Source> ret (new CoreAudioSource (s, path, chn, flags));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
+ return boost::shared_ptr<Source>();
+ }
}
if (announce) {
SourceCreated (ret);
}
return ret;
}
-
+
catch (failed_constructor& err) {
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
+ return boost::shared_ptr<Source>();
+ }
}
if (announce) {
SourceCreated (ret);
@@ -147,8 +204,10 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
#else
boost::shared_ptr<Source> ret (new SndFileSource (s, path, chn, flags));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
+ return boost::shared_ptr<Source>();
+ }
}
if (announce) {
@@ -157,7 +216,7 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
return ret;
#endif
-
+
} else if (type == DataType::MIDI) {
// FIXME: flags?
@@ -174,21 +233,23 @@ SourceFactory::createReadable (DataType type, Session& s, string path, int chn,
}
boost::shared_ptr<Source>
-SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce)
+SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce, bool defer_peaks)
{
/* this might throw failed_constructor(), which is OK */
-
+
if (type == DataType::AUDIO) {
boost::shared_ptr<Source> ret (new SndFileSource
- (s, path,
- Config->get_native_file_data_format(),
- Config->get_native_file_header_format(),
- rate,
- (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
- SndFileSource::default_writable_flags)));
-
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
+ (s, path,
+ Config->get_native_file_data_format(),
+ Config->get_native_file_header_format(),
+ rate,
+ (destructive ? AudioFileSource::Flag (SndFileSource::default_writable_flags | AudioFileSource::Destructive) :
+ SndFileSource::default_writable_flags)));
+
+ if (!defer_peaks) {
+ if (setup_peakfile (ret, false)) {
+ return boost::shared_ptr<Source>();
+ }
}
if (announce) {
SourceCreated (ret);
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 01e070e920..cfd38c5099 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -143,7 +143,7 @@ touch_file (ustring path)
}
ustring
-region_name_from_path (ustring path, bool strip_channels)
+region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffix, uint32_t total, uint32_t this_one)
{
path = PBD::basename_nosuffix (path);
@@ -160,6 +160,17 @@ region_name_from_path (ustring path, bool strip_channels)
}
}
+ if (add_channel_suffix) {
+
+ path += '%';
+
+ if (total > 2) {
+ path += (char) ('a' + this_one);
+ } else {
+ path += (char) (this_one == 0 ? 'L' : 'R');
+ }
+ }
+
return path;
}
diff --git a/libs/clearlooks/SConscript b/libs/clearlooks/SConscript
index 110bfe41be..2676f63022 100644
--- a/libs/clearlooks/SConscript
+++ b/libs/clearlooks/SConscript
@@ -17,6 +17,9 @@ clearlooks = env.Copy()
clearlooks.Replace(CCFLAGS = ' `pkg-config --cflags gtk+-2.0` ',
LINKFLAGS = ' `pkg-config --libs gtk+-2.0` ')
+if env['GTKOSX']:
+ clearlooks.Append (CCFLAGS = '-DGTKOSX')
+
libclearlooks = clearlooks.SharedLibrary('clearlooks', libclearlooks_files)
usable_libclearlooks = clearlooks.Install ('engines', libclearlooks)
diff --git a/libs/clearlooks/clearlooks_style.c b/libs/clearlooks/clearlooks_style.c
index 241f14c6e4..074f1604b1 100644
--- a/libs/clearlooks/clearlooks_style.c
+++ b/libs/clearlooks/clearlooks_style.c
@@ -1677,14 +1677,18 @@ draw_option (DRAW_ARGS)
x += (width - RADIO_SIZE)/2;
y += (height - RADIO_SIZE)/2;
+#ifndef GTKOSX
gdk_gc_set_clip_mask (gc, clearlooks_style->radio_pixmap_mask);
gdk_gc_set_clip_origin (gc, x, y);
+#endif
gdk_draw_drawable (window, gc, pixmap, 0, 0, x, y,
RADIO_SIZE, RADIO_SIZE);
+#ifndef GTKOSX
gdk_gc_set_clip_origin (gc, 0, 0);
gdk_gc_set_clip_mask (gc, NULL);
+#endif
if (area)
gdk_gc_set_clip_rectangle (gc, NULL);
diff --git a/libs/gtkmm2/gtk/gtkmm/toolbar.cc b/libs/gtkmm2/gtk/gtkmm/toolbar.cc
index a8d10a7dde..8e51d70501 100644
--- a/libs/gtkmm2/gtk/gtkmm/toolbar.cc
+++ b/libs/gtkmm2/gtk/gtkmm/toolbar.cc
@@ -30,7 +30,7 @@
//but the GtkToolbar compatibility system is particularly unpleasant, so we just removed it in gtkmm 2.4. murrayc.
//In future, this GTK_DISABLE_DEPRECATED might be inappropriate because it might cover extra GTK+ API. Just remove it then.
-#define GTK_DISABLE_DEPRECATED
+// #define GTK_DISABLE_DEPRECATED
#include <glib.h>
#include <gtkmm/button.h>
diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript
index 04b027b6a3..769d888903 100644
--- a/libs/midi++2/SConscript
+++ b/libs/midi++2/SConscript
@@ -7,7 +7,7 @@ import glob
Import('env libraries install_prefix')
midi2 = env.Copy()
-midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glib2'], libraries['pbd'], libraries['jack'] ])
+midi2.Merge([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'], libraries['pbd'], libraries['jack'] ])
domain = 'midipp'
@@ -24,7 +24,6 @@ midiparser.cc
midiport.cc
mmc.cc
mtc.cc
-port_request.cc
version.cc
""")
diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc
index bf891108c6..bae8aff2ab 100644
--- a/libs/midi++2/alsa_sequencer_midiport.cc
+++ b/libs/midi++2/alsa_sequencer_midiport.cc
@@ -23,10 +23,12 @@
#include <pbd/failed_constructor.h>
#include <pbd/error.h>
+#include <pbd/xml++.h>
#include <midi++/types.h>
#include <midi++/alsa_sequencer.h>
-#include <midi++/port_request.h>
+
+#include "i18n.h"
//#define DOTRACE 1
@@ -44,31 +46,31 @@ using namespace PBD;
snd_seq_t* ALSA_SequencerMidiPort::seq = 0;
-ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (PortRequest &req)
- : Port (req)
+ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
+ : Port (node)
, decoder (0)
, encoder (0)
, port_id (-1)
{
TR_FN();
int err;
+ Descriptor desc (node);
- if (!seq && init_client (req.devname) < 0) {
+ if (!seq && init_client (desc.device) < 0) {
_ok = false;
} else {
- if (0 <= (err = CreatePorts (req)) &&
+ if (0 <= (err = create_ports (desc)) &&
0 <= (err = snd_midi_event_new (1024, &decoder)) && // Length taken from ARDOUR::Session::midi_read ()
0 <= (err = snd_midi_event_new (64, &encoder))) { // Length taken from ARDOUR::Session::mmc_buffer
snd_midi_event_init (decoder);
snd_midi_event_init (encoder);
_ok = true;
- req.status = PortRequest::OK;
- } else {
- req.status = PortRequest::Unknown;
- }
+ }
}
+
+ set_state (node);
}
ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
@@ -94,7 +96,8 @@ ALSA_SequencerMidiPort::selectable () const
return -1;
}
-int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp)
+int
+ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)
{
TR_FN ();
int R;
@@ -133,7 +136,8 @@ int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen, timestamp_t timesta
return totwritten;
}
-int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp)
+int
+ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t ignored)
{
TR_FN();
int err;
@@ -158,17 +162,20 @@ int ALSA_SequencerMidiPort::read (byte *buf, size_t max, timestamp_t timestamp)
}
int
-ALSA_SequencerMidiPort::CreatePorts (PortRequest &req)
+ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc)
{
int err;
unsigned int caps = 0;
- if (req.mode == O_WRONLY || req.mode == O_RDWR)
+ if (desc.mode == O_WRONLY || desc.mode == O_RDWR)
caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
- if (req.mode == O_RDONLY || req.mode == O_RDWR)
+ if (desc.mode == O_RDONLY || desc.mode == O_RDWR)
caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
- if (0 <= (err = snd_seq_create_simple_port (seq, req.tagname, caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC))) {
+ if (0 <= (err = snd_seq_create_simple_port (seq, desc.tag.c_str(), caps,
+ (SND_SEQ_PORT_TYPE_MIDI_GENERIC|
+ SND_SEQ_PORT_TYPE_SOFTWARE|
+ SND_SEQ_PORT_TYPE_APPLICATION)))) {
port_id = err;
@@ -203,3 +210,216 @@ ALSA_SequencerMidiPort::init_client (std::string name)
return -1;
}
}
+
+int
+ALSA_SequencerMidiPort::discover (vector<PortSet>& ports)
+{
+ int n = 0;
+
+ snd_seq_client_info_t *client_info;
+ snd_seq_port_info_t *port_info;
+
+ snd_seq_client_info_alloca (&client_info);
+ snd_seq_port_info_alloca (&port_info);
+ snd_seq_client_info_set_client (client_info, -1);
+
+ while (snd_seq_query_next_client(seq, client_info) >= 0) {
+
+ int alsa_client;
+
+ if ((alsa_client = snd_seq_client_info_get_client(client_info)) <= 0) {
+ break;
+ }
+
+ snd_seq_port_info_set_client(port_info, alsa_client);
+ snd_seq_port_info_set_port(port_info, -1);
+
+ char client[256];
+ snprintf (client, sizeof (client), "%d:%s", alsa_client, snd_seq_client_info_get_name(client_info));
+
+ ports.push_back (PortSet (client));
+
+ while (snd_seq_query_next_port(seq, port_info) >= 0) {
+
+#if 0
+ int type = snd_seq_port_info_get_type(pinfo);
+ if (!(type & SND_SEQ_PORT_TYPE_PORT)) {
+ continue;
+ }
+#endif
+
+ unsigned int port_capability = snd_seq_port_info_get_capability(port_info);
+
+ if ((port_capability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) {
+
+ int alsa_port = snd_seq_port_info_get_port(port_info);
+
+ char port[256];
+ snprintf (port, sizeof (port), "%d:%s", alsa_port, snd_seq_port_info_get_name(port_info));
+
+ std::string mode;
+
+ if (port_capability & SND_SEQ_PORT_CAP_READ) {
+ if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
+ mode = "duplex";
+ } else {
+ mode = "output";
+ }
+ } else if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
+ if (port_capability & SND_SEQ_PORT_CAP_READ) {
+ mode = "duplex";
+ } else {
+ mode = "input";
+ }
+ }
+
+ XMLNode node (X_("MIDI-port"));
+ node.add_property ("device", client);
+ node.add_property ("tag", port);
+ node.add_property ("mode", mode);
+ node.add_property ("type", "alsa/sequencer");
+
+ ports.back().ports.push_back (node);
+ ++n;
+ }
+ }
+ }
+
+ return n;
+}
+
+void
+ALSA_SequencerMidiPort::get_connections (vector<SequencerPortAddress>& connections, int dir) const
+{
+ snd_seq_query_subscribe_t *subs;
+ snd_seq_addr_t seq_addr;
+
+ snd_seq_query_subscribe_alloca (&subs);
+
+ // Get port connections...
+
+ if (dir) {
+ snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE);
+ } else {
+ snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_READ);
+ }
+
+ snd_seq_query_subscribe_set_index(subs, 0);
+ seq_addr.client = snd_seq_client_id (seq);
+ seq_addr.port = port_id;
+ snd_seq_query_subscribe_set_root(subs, &seq_addr);
+
+ while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
+
+ seq_addr = *snd_seq_query_subscribe_get_addr (subs);
+
+ connections.push_back (SequencerPortAddress (seq_addr.client,
+ seq_addr.port));
+
+ snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
+ }
+}
+
+XMLNode&
+ALSA_SequencerMidiPort::get_state () const
+{
+ XMLNode& root (Port::get_state ());
+ vector<SequencerPortAddress> connections;
+ XMLNode* sub = 0;
+ char buf[256];
+
+ get_connections (connections, 1);
+
+ if (!connections.empty()) {
+ if (!sub) {
+ sub = new XMLNode (X_("connections"));
+ }
+ for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
+ XMLNode* cnode = new XMLNode (X_("read"));
+ snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
+ cnode->add_property ("dest", buf);
+ sub->add_child_nocopy (*cnode);
+ }
+ }
+
+ connections.clear ();
+ get_connections (connections, 0);
+
+ if (!connections.empty()) {
+ if (!sub) {
+ sub = new XMLNode (X_("connections"));
+ }
+ for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
+ XMLNode* cnode = new XMLNode (X_("write"));
+ snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
+ cnode->add_property ("dest", buf);
+ sub->add_child_nocopy (*cnode);
+ }
+ }
+
+ if (sub) {
+ root.add_child_nocopy (*sub);
+ }
+
+ return root;
+}
+
+void
+ALSA_SequencerMidiPort::set_state (const XMLNode& node)
+{
+ Port::set_state (node);
+
+ XMLNodeList children (node.children());
+ XMLNodeIterator iter;
+
+ for (iter = children.begin(); iter != children.end(); ++iter) {
+
+ if ((*iter)->name() == X_("connections")) {
+
+ XMLNodeList gchildren ((*iter)->children());
+ XMLNodeIterator gciter;
+
+ for (gciter = gchildren.begin(); gciter != gchildren.end(); ++gciter) {
+ XMLProperty* prop;
+
+ if ((prop = (*gciter)->property ("dest")) != 0) {
+ int client;
+ int port;
+
+ if (sscanf (prop->value().c_str(), "%d:%d", &client, &port) == 2) {
+
+ snd_seq_port_subscribe_t *sub;
+ snd_seq_addr_t seq_addr;
+
+ snd_seq_port_subscribe_alloca(&sub);
+
+ if ((*gciter)->name() == X_("write")) {
+
+ seq_addr.client = snd_seq_client_id (seq);
+ seq_addr.port = port_id;
+ snd_seq_port_subscribe_set_sender(sub, &seq_addr);
+
+ seq_addr.client = client;
+ seq_addr.port = port;
+ snd_seq_port_subscribe_set_dest(sub, &seq_addr);
+
+ } else {
+
+ seq_addr.client = snd_seq_client_id (seq);
+ seq_addr.port = port_id;
+ snd_seq_port_subscribe_set_dest(sub, &seq_addr);
+
+ seq_addr.client = client;
+ seq_addr.port = port;
+ snd_seq_port_subscribe_set_sender(sub, &seq_addr);
+ }
+
+ snd_seq_subscribe_port (seq, sub);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+}
diff --git a/libs/midi++2/coremidi_midiport.cc b/libs/midi++2/coremidi_midiport.cc
index 2cd98239ec..14020a6f35 100644
--- a/libs/midi++2/coremidi_midiport.cc
+++ b/libs/midi++2/coremidi_midiport.cc
@@ -23,7 +23,6 @@
#include <midi++/coremidi_midiport.h>
#include <midi++/types.h>
-#include <midi++/port_request.h>
#include <mach/mach_time.h>
#include <pbd/pthread_utils.h>
@@ -36,15 +35,15 @@ MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime()
return mach_absolute_time();
}
-CoreMidi_MidiPort::CoreMidi_MidiPort (PortRequest &req) : Port (req)
+CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node)
{
+ Descriptor desc (node);
+
firstrecv = true;
int err;
- if (0 == (err = Open(req))) {
+ if (0 == (err = Open(desc))) {
_ok = true;
- req.status = PortRequest::OK;
- } else
- req.status = PortRequest::Unknown;
+ }
}
CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();}
@@ -56,10 +55,10 @@ void CoreMidi_MidiPort::Close ()
if (midi_client) MIDIClientDispose(midi_client);
}
-int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp)
+int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)
{
OSStatus err;
- MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
+ MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
MIDIPacket* packet = MIDIPacketListInit(pktlist);
packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg);
@@ -77,21 +76,21 @@ int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t timestamp)
}
}
-int CoreMidi_MidiPort::Open (PortRequest &req)
+int CoreMidi_MidiPort::Open (const Descriptor& desc)
{
OSStatus err;
CFStringRef coutputStr;
string str;
-
- coutputStr = CFStringCreateWithCString(0, req.devname, CFStringGetSystemEncoding());
+
+ coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding());
err = MIDIClientCreate(coutputStr, 0, 0, &midi_client);
CFRelease(coutputStr);
- if (!midi_client) {
+ if (!midi_client) {
//error << "Cannot open CoreMidi client : " << err << endmsg.
- goto error;
- }
+ goto error;
+ }
- str = req.tagname + string("_in");
+ str = desc.tag + string("_in");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination);
CFRelease(coutputStr);
@@ -100,7 +99,7 @@ int CoreMidi_MidiPort::Open (PortRequest &req)
goto error;
}
- str = req.tagname + string("_out");
+ str = desc.tag + string("_out");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDISourceCreate(midi_client, coutputStr, &midi_source);
CFRelease(coutputStr);
@@ -142,3 +141,10 @@ void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon,
}
}
+int
+CoreMidi_MidiPort::discover (vector<PortSet>& ports)
+{
+ /* XXX do dynamic port discovery here */
+
+ return 0;
+}
diff --git a/libs/midi++2/fd_midiport.cc b/libs/midi++2/fd_midiport.cc
index 81d81c8558..17a7eff367 100644
--- a/libs/midi++2/fd_midiport.cc
+++ b/libs/midi++2/fd_midiport.cc
@@ -34,40 +34,38 @@ using namespace PBD;
string *FD_MidiPort::midi_dirpath = 0;
string *FD_MidiPort::midi_filename_pattern = 0;
-FD_MidiPort::FD_MidiPort (PortRequest &req,
+FD_MidiPort::FD_MidiPort (const XMLNode& node,
const string &dirpath,
const string &pattern)
- : Port (req)
+ : Port (node)
{
- open (req);
+ Descriptor desc (node);
+
+ open (desc);
if (_fd < 0) {
switch (errno) {
case EBUSY:
error << "MIDI: port device in use" << endmsg;
- req.status = PortRequest::Busy;
break;
case ENOENT:
error << "MIDI: no such port device" << endmsg;
- req.status = PortRequest::NoSuchFile;
break;
case EACCES:
error << "MIDI: access to port denied" << endmsg;
- req.status = PortRequest::NotAllowed;
break;
default:
- req.status = PortRequest::Unknown;
+ break;
}
} else {
_ok = true;
- req.status = PortRequest::OK;
if (midi_dirpath == 0) {
midi_dirpath = new string (dirpath);
midi_filename_pattern = new string (pattern);
}
- if (req.mode & O_NONBLOCK == 0) {
+ if (desc.mode & O_NONBLOCK == 0) {
/* we unconditionally set O_NONBLOCK during
open, but the request didn't ask for it,
so remove it.
@@ -80,11 +78,11 @@ FD_MidiPort::FD_MidiPort (PortRequest &req,
}
void
-FD_MidiPort::open (PortRequest &req)
+FD_MidiPort::open (const Descriptor& desc)
{
- int mode = req.mode | O_NONBLOCK;
- _fd = ::open (req.devname, mode);
+ int mode = desc.mode | O_NONBLOCK;
+ _fd = ::open (desc.device.c_str(), mode);
}
vector<string *> *
@@ -152,7 +150,7 @@ FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen)
}
int
-FD_MidiPort::read (byte* buf, size_t max, timestamp_t timestamp)
+FD_MidiPort::read (byte* buf, size_t max, timestamp_t ignored)
{
int nread;
diff --git a/libs/midi++2/fifomidi.cc b/libs/midi++2/fifomidi.cc
index 7bb126ddeb..a81520bb95 100644
--- a/libs/midi++2/fifomidi.cc
+++ b/libs/midi++2/fifomidi.cc
@@ -26,19 +26,19 @@
using namespace MIDI;
-FIFO_MidiPort::FIFO_MidiPort (PortRequest &req)
- : FD_MidiPort (req, ".", "midi")
+FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node)
+ : FD_MidiPort (node, ".", "midi")
{
}
void
-FIFO_MidiPort::open (PortRequest &req)
+FIFO_MidiPort::open (const Port::Descriptor& desc)
{
/* This is a placeholder for the fun-and-games I think we will
need to do with FIFO's.
*/
- _fd = ::open (req.devname, req.mode|O_NDELAY);
+ _fd = ::open (desc.device.c_str(), desc.mode|O_NDELAY);
}
diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc
index 4b2808a698..11cd70a051 100644
--- a/libs/midi++2/jack_midiport.cc
+++ b/libs/midi++2/jack_midiport.cc
@@ -23,26 +23,22 @@
#include <midi++/types.h>
#include <midi++/jack.h>
-#include <midi++/port_request.h>
using namespace std;
using namespace MIDI;
-JACK_MidiPort::JACK_MidiPort(PortRequest & req, jack_client_t* jack_client)
- : Port(req)
+JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client)
+ : Port(node)
, _jack_client(jack_client)
, _jack_input_port(NULL)
, _jack_output_port(NULL)
, _last_read_index(0)
{
- int err = create_ports(req);
+ int err = create_ports (node);
if (!err) {
- req.status = PortRequest::OK;
_ok = true;
- } else {
- req.status = PortRequest::Unknown;
- }
+ }
}
JACK_MidiPort::~JACK_MidiPort()
@@ -94,8 +90,10 @@ JACK_MidiPort::read(byte * buf, size_t max, timestamp_t timestamp)
}
int
-JACK_MidiPort::create_ports(PortRequest & req)
+JACK_MidiPort::create_ports(const XMLNode& node)
{
+ Descriptor desc (node);
+
assert(!_jack_input_port);
assert(!_jack_output_port);
@@ -103,24 +101,33 @@ JACK_MidiPort::create_ports(PortRequest & req)
bool ret = true;
- if (req.mode == O_RDWR || req.mode == O_WRONLY) {
+ if (desc.mode == O_RDWR || desc.mode == O_WRONLY) {
_jack_output_port = jack_port_register(_jack_client,
- string(req.tagname).append("_out").c_str(),
- JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
- jack_midi_clear_buffer(
- jack_port_get_buffer(_jack_output_port, nframes));
+ string(desc.tag).append("_out").c_str(),
+ JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
+ jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes));
ret = ret && (_jack_output_port != NULL);
}
-
- if (req.mode == O_RDWR || req.mode == O_RDONLY) {
+
+ if (desc.mode == O_RDWR || desc.mode == O_RDONLY) {
_jack_input_port = jack_port_register(_jack_client,
- string(req.tagname).append("_in").c_str(),
- JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
- jack_midi_clear_buffer(
- jack_port_get_buffer(_jack_input_port, nframes));
+ string(desc.tag).append("_in").c_str(),
+ JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
+ jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes));
ret = ret && (_jack_input_port != NULL);
}
return ret ? 0 : -1;
}
+XMLNode&
+JACK_MidiPort::get_state () const
+{
+ XMLNode& root (Port::get_state ());
+ return root;
+}
+
+void
+JACK_MidiPort::set_state (const XMLNode& node)
+{
+}
diff --git a/libs/midi++2/midi++/alsa_rawmidi.h b/libs/midi++2/midi++/alsa_rawmidi.h
index 54b86edd70..e5abc2832f 100644
--- a/libs/midi++2/midi++/alsa_rawmidi.h
+++ b/libs/midi++2/midi++/alsa_rawmidi.h
@@ -34,8 +34,8 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort
{
public:
- ALSA_RawMidiPort (MIDI::PortRequest &req)
- : FD_MidiPort (req, "/dev/snd", "midi") {}
+ ALSA_RawMidiPort (const XMLNode& node)
+ : FD_MidiPort (node, "/dev/snd", "midi") {}
virtual ~ALSA_RawMidiPort () {}
static std::string typestring;
@@ -46,7 +46,7 @@ class ALSA_RawMidiPort : public MIDI::FD_MidiPort
}
};
-} // namespace MIDI
+}
#endif // __alsa_rawmidi_h__
diff --git a/libs/midi++2/midi++/alsa_sequencer.h b/libs/midi++2/midi++/alsa_sequencer.h
index b54486416a..a95f9c476f 100644
--- a/libs/midi++2/midi++/alsa_sequencer.h
+++ b/libs/midi++2/midi++/alsa_sequencer.h
@@ -30,39 +30,45 @@
namespace MIDI {
-class PortRequest;
-
class ALSA_SequencerMidiPort : public Port
+
{
public:
- ALSA_SequencerMidiPort (PortRequest &req);
+ ALSA_SequencerMidiPort (const XMLNode&);
virtual ~ALSA_SequencerMidiPort ();
/* select(2)/poll(2)-based I/O */
virtual int selectable() const;
-
+
+ static int discover (std::vector<PortSet>&);
static std::string typestring;
- protected:
- std::string get_typestring () const {
- return typestring;
- }
+ XMLNode& get_state() const;
+ void set_state (const XMLNode&);
protected:
/* Direct I/O */
+
int write (byte *msg, size_t msglen, timestamp_t timestamp);
int read (byte *buf, size_t max, timestamp_t timestamp);
+ std::string get_typestring () const {
+ return typestring;
+ }
+
private:
snd_midi_event_t *decoder, *encoder;
int port_id;
snd_seq_event_t SEv;
- int CreatePorts(PortRequest &req);
+ int create_ports (const Port::Descriptor&);
static int init_client (std::string name);
static snd_seq_t* seq;
+
+ typedef std::pair<int,int> SequencerPortAddress;
+ void get_connections (std::vector<SequencerPortAddress>&, int dir) const;
};
}; /* namespace MIDI */
diff --git a/libs/midi++2/midi++/coremidi_midiport.h b/libs/midi++2/midi++/coremidi_midiport.h
index 91eccea4a5..d5d3c23ede 100644
--- a/libs/midi++2/midi++/coremidi_midiport.h
+++ b/libs/midi++2/midi++/coremidi_midiport.h
@@ -22,6 +22,7 @@
#include <list>
#include <string>
+#include <vector>
#include <fcntl.h>
#include <unistd.h>
@@ -32,45 +33,47 @@
namespace MIDI {
-namespace PortRequest;
+ class CoreMidi_MidiPort:public Port {
+ public:
+ CoreMidi_MidiPort(const XMLNode& node);
+ virtual ~ CoreMidi_MidiPort();
-class CoreMidi_MidiPort:public Port
-{
- public:
- CoreMidi_MidiPort(PortRequest & req);
- virtual ~ CoreMidi_MidiPort();
-
- virtual int selectable() const {
- return -1;
- }
- static std::string typestring;
+ virtual int selectable() const {
+ return -1;
+ }
+
+ static int discover (std::vector<PortSet>&);
+ static std::string typestring;
+
+ protected:
+ /* Direct I/O */
+ int write (byte * msg, size_t msglen, timestamp_t timestamp);
- protected:
+ int read (byte * buf, size_t max, timestamp_t timestamp) {
+ return 0;
+ }
+
+ /* CoreMidi callback */
+ static void read_proc(const MIDIPacketList * pktlist,
+ void *refCon, void *connRefCon);
+
std::string get_typestring () const {
return typestring;
}
- protected:
- /* Direct I/O */
- int write (byte *msg, size_t msglen, timestamp_t timestamp);
- int read (byte *buf, size_t max, timestamp_t timestamp);
-
- /* CoreMidi callback */
- static void read_proc(const MIDIPacketList * pktlist,
- void *refCon, void *connRefCon);
-
- private:
- byte midi_buffer[1024];
- MIDIClientRef midi_client;
- MIDIEndpointRef midi_destination;
- MIDIEndpointRef midi_source;
+ private:
+ byte midi_buffer[1024];
+ MIDIClientRef midi_client;
+ MIDIEndpointRef midi_destination;
+ MIDIEndpointRef midi_source;
- int Open(PortRequest & req);
- void Close();
- static MIDITimeStamp MIDIGetCurrentHostTime();
+ int Open(const Port::Descriptor&);
+ void Close();
+ static MIDITimeStamp MIDIGetCurrentHostTime();
- bool firstrecv;
-};
+ bool firstrecv;
+
+ };
} // namespace MIDI
diff --git a/libs/midi++2/midi++/factory.h b/libs/midi++2/midi++/factory.h
index 9954ea72fe..f3402546e9 100644
--- a/libs/midi++2/midi++/factory.h
+++ b/libs/midi++2/midi++/factory.h
@@ -23,13 +23,12 @@
#include <string>
#include <midi++/port.h>
-#include <midi++/port_request.h>
namespace MIDI {
class PortFactory {
public:
- Port *create_port (PortRequest &req, void* data);
+ Port *create_port (const XMLNode&, void* data);
static bool ignore_duplicate_devices (Port::Type);
static int get_known_ports (std::vector<PortSet>&);
diff --git a/libs/midi++2/midi++/fd_midiport.h b/libs/midi++2/midi++/fd_midiport.h
index 34e2e27a1a..ec5a9f8af4 100644
--- a/libs/midi++2/midi++/fd_midiport.h
+++ b/libs/midi++2/midi++/fd_midiport.h
@@ -29,7 +29,6 @@
#include <unistd.h>
#include <midi++/port.h>
-#include <midi++/port_request.h>
namespace MIDI {
@@ -37,7 +36,7 @@ class FD_MidiPort : public Port
{
public:
- FD_MidiPort (PortRequest &req,
+ FD_MidiPort (const XMLNode& node,
const std::string &dirpath,
const std::string &pattern);
@@ -46,23 +45,14 @@ class FD_MidiPort : public Port
}
virtual int selectable() const;
- static std::vector<std::string *> *list_devices ();
-
- static std::string typestring;
- protected:
- std::string get_typestring () const {
- return typestring;
- }
+ static std::vector<std::string *> *list_devices ();
protected:
int _fd;
- virtual void open (PortRequest &req);
+ virtual void open (const Port::Descriptor&);
- /* Direct I/O */
-
- virtual int write (byte *msg, size_t msglen,
- timestamp_t timestamp) {
+ virtual int write (byte *msg, size_t msglen, timestamp_t ignored) {
int nwritten;
if ((_mode & O_ACCMODE) == O_RDONLY) {
@@ -89,8 +79,7 @@ class FD_MidiPort : public Port
return nwritten;
}
- virtual int read (byte *buf, size_t max,
- timestamp_t timestamp);
+ virtual int read (byte *buf, size_t max, timestamp_t ignored);
private:
static std::string *midi_dirpath;
diff --git a/libs/midi++2/midi++/fifomidi.h b/libs/midi++2/midi++/fifomidi.h
index ea644dde06..3439c27dcf 100644
--- a/libs/midi++2/midi++/fifomidi.h
+++ b/libs/midi++2/midi++/fifomidi.h
@@ -25,7 +25,6 @@
#include <unistd.h>
#include <midi++/port.h>
-#include <midi++/port_request.h>
#include <midi++/fd_midiport.h>
namespace MIDI {
@@ -34,7 +33,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
{
public:
- FIFO_MidiPort (PortRequest &req);
+ FIFO_MidiPort (const XMLNode&);
~FIFO_MidiPort () {};
static std::string typestring;
@@ -45,7 +44,7 @@ class FIFO_MidiPort : public MIDI::FD_MidiPort
}
private:
- void open (PortRequest &req);
+ void open (const Port::Descriptor&);
};
} // namespace MIDI
diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h
index 1f25609aac..845dd0c229 100644
--- a/libs/midi++2/midi++/jack.h
+++ b/libs/midi++2/midi++/jack.h
@@ -39,7 +39,7 @@ namespace MIDI
class JACK_MidiPort : public Port
{
public:
- JACK_MidiPort (PortRequest &req, jack_client_t* jack_client);
+ JACK_MidiPort (const XMLNode& node, jack_client_t* jack_client);
virtual ~JACK_MidiPort ();
/* No select(2)/poll(2)-based I/O */
@@ -49,6 +49,9 @@ public:
static std::string typestring;
+ virtual XMLNode& get_state () const;
+ virtual void set_state (const XMLNode&);
+
protected:
std::string get_typestring () const {
return typestring;
@@ -60,7 +63,7 @@ protected:
int read(byte *buf, size_t max, timestamp_t timestamp);
private:
- int create_ports(PortRequest &req);
+ int create_ports(const XMLNode&);
jack_client_t* _jack_client;
jack_port_t* _jack_input_port;
diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h
index eef52abe52..bb3bf9b999 100644
--- a/libs/midi++2/midi++/manager.h
+++ b/libs/midi++2/midi++/manager.h
@@ -21,6 +21,8 @@
#define __midi_manager_h__
#include <map>
+#include <vector>
+
#include <string>
#include <midi++/types.h>
@@ -28,20 +30,18 @@
namespace MIDI {
-/** Creates, stores, and manages system MIDI ports.
- */
class Manager {
public:
~Manager ();
void set_api_data(void* data) { api_data = data; }
-
+
/** Signal the start of an audio cycle.
* This MUST be called before any reading/writing for this cycle.
* Realtime safe.
*/
void cycle_start(nframes_t nframes);
-
+
/** Signal the end of an audio cycle.
* This signifies that the cycle began with @ref cycle_start has ended.
* This MUST be called at the end of each cycle.
@@ -49,13 +49,25 @@ class Manager {
*/
void cycle_end();
- Port *add_port (PortRequest &);
+ Port *add_port (const XMLNode& node);
int remove_port (Port*);
Port *port (std::string name);
size_t nports () { return ports_by_device.size(); }
+ /* defaults for clients who are not picky */
+
+ Port *inputPort;
+ Port *outputPort;
+ channel_t inputChannelNumber;
+ channel_t outputChannelNumber;
+
+ int set_input_port (std::string);
+ int set_output_port (std::string);
+ int set_input_channel (channel_t);
+ int set_output_channel (channel_t);
+
int foreach_port (int (*func)(const Port &, size_t n, void *),
void *arg);
@@ -70,7 +82,7 @@ class Manager {
return theManager;
}
- static int parse_port_request (std::string str, Port::Type type);
+ int get_known_ports (std::vector<PortSet>&);
private:
/* This is a SINGLETON pattern */
@@ -81,7 +93,7 @@ class Manager {
PortMap ports_by_device; /* canonical */
PortMap ports_by_tag; /* may contain duplicate Ports */
- void *api_data;
+ void* api_data;
void close_ports ();
};
diff --git a/libs/midi++2/midi++/nullmidi.h b/libs/midi++2/midi++/nullmidi.h
index 6ed94db71c..8f36e6aed8 100644
--- a/libs/midi++2/midi++/nullmidi.h
+++ b/libs/midi++2/midi++/nullmidi.h
@@ -24,7 +24,6 @@
#include <string>
#include <midi++/port.h>
-#include <midi++/port_request.h>
namespace MIDI {
diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h
index e4338cf952..dcae446c42 100644
--- a/libs/midi++2/midi++/port.h
+++ b/libs/midi++2/midi++/port.h
@@ -20,10 +20,11 @@
#define __libmidi_port_h__
#include <string>
+#include <iostream>
#include <sigc++/sigc++.h>
+#include <pbd/xml++.h>
-#include <pbd/selectable.h>
#include <midi++/types.h>
#include <midi++/parser.h>
@@ -44,64 +45,82 @@ class Port : public sigc::trackable {
FIFO
};
- Port (PortRequest &);
+
+ Port (const XMLNode&);
virtual ~Port ();
+ virtual XMLNode& get_state () const;
+ virtual void set_state (const XMLNode&);
+
// FIXME: make Manager a friend of port so these can be hidden?
-
+
/* Only for use by MidiManager. Don't ever call this. */
virtual void cycle_start(nframes_t nframes);
-
/* Only for use by MidiManager. Don't ever call this. */
virtual void cycle_end();
- /* Direct I/O */
-
- /** Read a message from port.
- * @param buf Raw MIDI message to send
- * @param max Max size to write to @a buf
- * @param timestamp Time stamp in frames of this message (relative to cycle start)
- * @return number of bytes successfully written to \a buf
- */
- virtual int read(byte *buf, size_t max, timestamp_t timestamp) = 0;
-
/** Write a message to port.
* @param msg Raw MIDI message to send
* @param msglen Size of @a msg
* @param timestamp Time stamp in frames of this message (relative to cycle start)
* @return number of bytes successfully written
*/
- virtual int write(byte *msg, size_t msglen, timestamp_t timestamp) = 0;
+ virtual int write (byte *msg, size_t msglen, timestamp_t timestamp) = 0;
+
+ /** Read a message from port.
+ * @param buf Raw MIDI message to send
+ * @param max Max size to write to @a buf
+ * @param timestamp Time stamp in frames of this message (relative to cycle start)
+ * @return number of bytes successfully written to \a buf
+ */
+ virtual int read (byte *buf, size_t max, timestamp_t timestamp) = 0;
/** Write a message to port.
* @return true on success.
* FIXME: describe semantics here
*/
- bool midimsg (byte *msg, size_t len, timestamp_t timestamp) {
+ int midimsg (byte *msg, size_t len, timestamp_t timestamp) {
return !(write (msg, len, timestamp) == (int) len);
- }
+ }
+
+ int three_byte_msg (byte a, byte b, byte c, timestamp_t timestamp) {
+ byte msg[3];
+ msg[0] = a;
+ msg[1] = b;
+ msg[2] = c;
+
+ return !(write (msg, 3, timestamp) == 3);
+ }
+
bool clock (timestamp_t timestamp);
+
+ /* slowdown i/o to a loop of single byte emissions
+ interspersed with a busy loop of 10000 * this value.
+
+ This may be ignored by a particular instance
+ of this virtual class. See FD_MidiPort for an
+ example of where it used.
+ */
- /** Slow down I/O to a loop of single byte emissions
- * interspersed with a busy loop of 10000 * this value.
- *
- * This may be ignored by a particular instance of this virtual
- * class. See FD_MidiPort for an example of where it used. */
void set_slowdown (size_t n) { slowdown = n; }
/* select(2)/poll(2)-based I/O */
/** Get the file descriptor for port.
- * @return File descriptor, or -1 if not selectable. */
+ * @return File descriptor, or -1 if not selectable.
+ */
virtual int selectable() const = 0;
+ static void gtk_read_callback (void *ptr, int fd, int cond);
+ static void write_callback (byte *msg, unsigned int len, void *);
+
Channel *channel (channel_t chn) {
return _channel[chn&0x7F];
}
- Parser *input() { return input_parser; }
- Parser *output() { return output_parser; }
+ Parser *input() { return input_parser; }
+ Parser *output() { return output_parser; }
void iostat (int *written, int *read,
const size_t **in_counts,
@@ -121,14 +140,21 @@ class Port : public sigc::trackable {
}
}
- bool clock ();
-
const char *device () const { return _devname.c_str(); }
- const char *name () const { return _tagname.c_str(); }
- Type type () const { return _type; }
- int mode () const { return _mode; }
- bool ok () const { return _ok; }
- size_t number () const { return _number; }
+ const char *name () const { return _tagname.c_str(); }
+ Type type () const { return _type; }
+ int mode () const { return _mode; }
+ bool ok () const { return _ok; }
+
+ struct Descriptor {
+ std::string tag;
+ std::string device;
+ int mode;
+ Port::Type type;
+
+ Descriptor (const XMLNode&);
+ XMLNode& get_state();
+ };
protected:
bool _ok;
@@ -147,10 +173,21 @@ class Port : public sigc::trackable {
Parser *output_parser;
size_t slowdown;
+ virtual std::string get_typestring () const = 0;
+
private:
static size_t nports;
};
+struct PortSet {
+ PortSet (std::string str) : owner (str) { }
+
+ std::string owner;
+ std::list<XMLNode> ports;
+};
+
+std::ostream & operator << ( std::ostream & os, const Port & port );
+
} // namespace MIDI
#endif // __libmidi_port_h__
diff --git a/libs/midi++2/midi++/port_request.h b/libs/midi++2/midi++/port_request.h
deleted file mode 100644
index dfde87a63c..0000000000
--- a/libs/midi++2/midi++/port_request.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- Copyright (C) 1999 Paul Barton-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 __midi_port_request_h__
-#define __midi_port_request_h__
-
-#include <string>
-
-namespace MIDI {
-
-struct PortRequest {
- enum Status {
- Unknown,
- OK,
- Busy,
- NoSuchFile,
- TypeUnsupported,
- NotAllowed
- };
- const char *devname;
- const char *tagname;
- int mode;
- Port::Type type;
- Status status;
-
- PortRequest () {
- devname = 0;
- tagname = 0;
- mode = 0;
- type = Port::Unknown;
- status = Unknown;
- }
-
- PortRequest (const std::string &xdev,
- const std::string &xtag,
- const std::string &xmode,
- const std::string &xtype);
-};
-
-struct PortSet {
- PortSet (std::string str) : owner (str) { }
-
- std::string owner;
- std::list<PortRequest> ports;
-};
-
-} // namespace MIDI
-
-#endif // __midi_port_request_h__
-
diff --git a/libs/midi++2/midifactory.cc b/libs/midi++2/midifactory.cc
index 9d98d9f6a7..d893cc9f47 100644
--- a/libs/midi++2/midifactory.cc
+++ b/libs/midi++2/midifactory.cc
@@ -24,7 +24,6 @@
#include <midi++/types.h>
#include <midi++/factory.h>
-#include <midi++/nullmidi.h>
#include <midi++/fifomidi.h>
#ifdef WITH_JACK_MIDI
@@ -33,7 +32,6 @@
std::string MIDI::JACK_MidiPort::typestring = "jack";
#endif // WITH_JACK_MIDI
-std::string MIDI::Null_MidiPort::typestring = "null";
std::string MIDI::FIFO_MidiPort::typestring = "fifo";
#ifdef WITH_ALSA
@@ -58,50 +56,44 @@ using namespace PBD;
// FIXME: void* data pointer, filthy
Port *
-PortFactory::create_port (PortRequest &req, void* data)
+PortFactory::create_port (const XMLNode& node, void* data)
{
+ Port::Descriptor desc (node);
Port *port;
- switch (req.type) {
+ switch (desc.type) {
#ifdef WITH_JACK_MIDI
case Port::JACK_Midi:
assert(data != NULL);
- port = new JACK_MidiPort (req, (jack_client_t*)data);
+ port = new JACK_MidiPort (node, (jack_client_t*) data);
break;
#endif // WITH_JACK_MIDI
#ifdef WITH_ALSA
case Port::ALSA_RawMidi:
- port = new ALSA_RawMidiPort (req);
+ port = new ALSA_RawMidiPort (node);
break;
case Port::ALSA_Sequencer:
- port = new ALSA_SequencerMidiPort (req);
+ port = new ALSA_SequencerMidiPort (node);
break;
#endif // WITH_ALSA
#if WITH_COREMIDI
case Port::CoreMidi_MidiPort:
- port = new CoreMidi_MidiPort (req);
+ port = new CoreMidi_MidiPort (node);
break;
#endif // WITH_COREMIDI
- case Port::Null:
- port = new Null_MidiPort (req);
- break;
-
case Port::FIFO:
- port = new FIFO_MidiPort (req);
+ port = new FIFO_MidiPort (node);
break;
default:
- req.status = PortRequest::TypeUnsupported;
return 0;
}
- req.status = PortRequest::OK;
-
return port;
}
@@ -179,8 +171,6 @@ PortFactory::string_to_type (const string& xtype)
} else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) {
return Port::CoreMidi_MidiPort;
#endif
- } else if (strings_equal_ignore_case (xtype, Null_MidiPort::typestring)) {
- return Port::Null;
} else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) {
return Port::FIFO;
#ifdef WITH_JACK_MIDI
diff --git a/libs/midi++2/midimanager.cc b/libs/midi++2/midimanager.cc
index ee73bdad86..8a358c3183 100644
--- a/libs/midi++2/midimanager.cc
+++ b/libs/midi++2/midimanager.cc
@@ -27,21 +27,25 @@
#include <midi++/manager.h>
#include <midi++/factory.h>
#include <midi++/channel.h>
-#include <midi++/port_request.h>
using namespace std;
using namespace MIDI;
using namespace PBD;
+/* XXX check for strdup leaks */
+
Manager *Manager::theManager = 0;
Manager::Manager ()
- : api_data(NULL)
{
+ inputPort = 0;
+ outputPort = 0;
+ inputChannelNumber = 0;
+ outputChannelNumber = 0;
+ api_data = 0;
}
Manager::~Manager ()
-
{
PortMap::iterator i;
@@ -58,27 +62,27 @@ Manager::~Manager ()
}
Port *
-Manager::add_port (PortRequest &req)
-
+Manager::add_port (const XMLNode& node)
{
+ Port::Descriptor desc (node);
PortFactory factory;
Port *port;
PortMap::iterator existing;
pair<string, Port *> newpair;
- if (!PortFactory::ignore_duplicate_devices (req.type)) {
+ if (!PortFactory::ignore_duplicate_devices (desc.type)) {
- if ((existing = ports_by_device.find (req.devname)) != ports_by_device.end()) {
+ if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
port = (*existing).second;
- if (port->mode() == req.mode) {
+ if (port->mode() == desc.mode) {
/* Same mode - reuse the port, and just
create a new tag entry.
*/
- newpair.first = req.tagname;
+ newpair.first = desc.tag;
newpair.second = port;
ports_by_tag.insert (newpair);
@@ -91,10 +95,10 @@ Manager::add_port (PortRequest &req)
operation.
*/
- if ((req.mode == O_RDWR && port->mode() != O_RDWR) ||
- (req.mode != O_RDWR && port->mode() == O_RDWR)) {
+ if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
+ (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
error << "MIDIManager: port tagged \""
- << req.tagname
+ << desc.tag
<< "\" cannot be opened duplex and non-duplex"
<< endmsg;
return 0;
@@ -103,7 +107,8 @@ Manager::add_port (PortRequest &req)
/* modes must be different or complementary */
}
}
- port = factory.create_port (req, api_data);
+
+ port = factory.create_port (node, api_data);
if (port == 0) {
return 0;
@@ -122,6 +127,18 @@ Manager::add_port (PortRequest &req)
newpair.second = port;
ports_by_device.insert (newpair);
+ /* first port added becomes the default input
+ port.
+ */
+
+ if (inputPort == 0) {
+ inputPort = port;
+ }
+
+ if (outputPort == 0) {
+ outputPort = port;
+ }
+
return port;
}
@@ -156,119 +173,88 @@ Manager::remove_port (Port* port)
return 0;
}
-Port *
-Manager::port (string name)
+int
+Manager::set_input_port (string tag)
{
PortMap::iterator res;
+ bool found = false;
for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
- if (name == (*res).first) {
- return (*res).second;
+ if (tag == (*res).first) {
+ found = true;
+ break;
}
}
+
+ if (!found) {
+ return -1;
+ }
+
+ inputPort = (*res).second;
return 0;
}
int
-Manager::foreach_port (int (*func)(const Port &, size_t, void *),
- void *arg)
+Manager::set_output_port (string tag)
{
- PortMap::const_iterator i;
- int retval;
- int n;
-
- for (n = 0, i = ports_by_device.begin();
- i != ports_by_device.end(); i++, n++) {
+ PortMap::iterator res;
+ bool found = false;
- if ((retval = func (*((*i).second), n, arg)) != 0) {
- return retval;
+ for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+ if (tag == (*res).first) {
+ found = true;
+ break;
}
}
-
- return 0;
-}
-
-int
-Manager::parse_port_request (string str, Port::Type type)
-{
- PortRequest *req;
- string::size_type colon;
- string tag;
-
- if (str.length() == 0) {
- error << "MIDI: missing port specification" << endmsg;
+
+ if (!found) {
return -1;
}
- /* Port specifications look like:
+ // XXX send a signal to say we're about to change output ports
- devicename
- devicename:tagname
- devicename:tagname:mode
+ if (outputPort) {
+ for (channel_t chan = 0; chan < 16; chan++) {
+ outputPort->channel (chan)->all_notes_off (0);
+ }
+ }
+ outputPort = (*res).second;
- where
+ // XXX send a signal to say we've changed output ports
- "devicename" is the full path to the requested file
-
- "tagname" (optional) is the name used to refer to the
- port. If not given, g_path_get_basename (devicename)
- will be used.
+ return 0;
+}
- "mode" (optional) is either "r" or "w" or something else.
- if it is "r", the port will be opened
- read-only, if "w", the port will be opened
- write-only. Any other value, or no mode
- specification at all, will cause the port to
- be opened for reading and writing.
- */
-
- req = new PortRequest;
- colon = str.find_first_of (':');
+Port *
+Manager::port (string name)
+{
+ PortMap::iterator res;
- if (colon != string::npos) {
- req->devname = strdup (str.substr (0, colon).c_str());
- } else {
- req->devname = strdup (str.c_str());
+ for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
+ if (name == (*res).first) {
+ return (*res).second;
+ }
}
- if (colon < str.length()) {
-
- tag = str.substr (colon+1);
+ return 0;
+}
- /* see if there is a mode specification in the tag part */
+int
+Manager::foreach_port (int (*func)(const Port &, size_t, void *),
+ void *arg)
+{
+ PortMap::const_iterator i;
+ int retval;
+ int n;
- colon = tag.find_first_of (':');
-
- if (colon != string::npos) {
- string modestr;
-
- req->tagname = strdup (tag.substr (0, colon).c_str());
-
- modestr = tag.substr (colon+1);
- if (modestr == "r") {
- req->mode = O_RDONLY;
- } else if (modestr == "w") {
- req->mode = O_WRONLY;
- } else {
- req->mode = O_RDWR;
- }
+ for (n = 0, i = ports_by_device.begin();
+ i != ports_by_device.end(); i++, n++) {
- } else {
- req->tagname = strdup (tag.c_str());
- req->mode = O_RDWR;
+ if ((retval = func (*((*i).second), n, arg)) != 0) {
+ return retval;
}
-
- } else {
- req->tagname = g_path_get_basename (req->devname);
- req->mode = O_RDWR;
- }
-
- req->type = type;
-
- if (MIDI::Manager::instance()->add_port (*req) == 0) {
- return -1;
}
return 0;
@@ -277,16 +263,22 @@ Manager::parse_port_request (string str, Port::Type type)
void
Manager::cycle_start(nframes_t nframes)
{
- for (PortMap::iterator i = ports_by_device.begin();
- i != ports_by_device.end(); i++)
- (*i).second->cycle_start(nframes);
+ for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+ (*i).second->cycle_start (nframes);
+ }
}
void
Manager::cycle_end()
{
- for (PortMap::iterator i = ports_by_device.begin();
- i != ports_by_device.end(); i++)
- (*i).second->cycle_end();
+ for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
+ (*i).second->cycle_end ();
+ }
}
+
+int
+Manager::get_known_ports (vector<PortSet>& ports)
+{
+ return PortFactory::get_known_ports (ports);
+}
diff --git a/libs/midi++2/midiport.cc b/libs/midi++2/midiport.cc
index 7f31b909d3..2e3d36c19c 100644
--- a/libs/midi++2/midiport.cc
+++ b/libs/midi++2/midiport.cc
@@ -17,24 +17,29 @@
$Id$
*/
-
+#include <iostream>
#include <cstdio>
#include <fcntl.h>
+#include <pbd/xml++.h>
+#include <pbd/failed_constructor.h>
+
#include <midi++/types.h>
#include <midi++/port.h>
#include <midi++/channel.h>
-#include <midi++/port_request.h>
+#include <midi++/factory.h>
-using namespace Select;
using namespace MIDI;
+using namespace std;
size_t Port::nports = 0;
-Port::Port (PortRequest &req)
+Port::Port (const XMLNode& node)
: _currently_in_cycle(false)
, _nframes_this_cycle(0)
{
+ Descriptor desc (node);
+
_ok = false; /* derived class must set to true if constructor
succeeds.
*/
@@ -45,10 +50,9 @@ Port::Port (PortRequest &req)
output_parser = 0;
slowdown = 0;
- _devname = req.devname;
- _tagname = req.tagname;
- _mode = req.mode;
- _number = nports++;
+ _devname = desc.device;
+ _tagname = desc.tag;
+ _mode = desc.mode;
if (_mode == O_RDONLY || _mode == O_RDWR) {
input_parser = new Parser (*this);
@@ -77,7 +81,6 @@ Port::Port (PortRequest &req)
Port::~Port ()
-
{
for (int i = 0; i < 16; i++) {
delete _channel[i];
@@ -113,3 +116,87 @@ Port::cycle_end ()
_nframes_this_cycle = 0;
}
+XMLNode&
+Port::get_state () const
+{
+ XMLNode* node = new XMLNode ("MIDI-port");
+ node->add_property ("tag", _tagname);
+ node->add_property ("device", _devname);
+ node->add_property ("mode", PortFactory::mode_to_string (_mode));
+ node->add_property ("type", get_typestring());
+
+ return *node;
+}
+
+void
+Port::set_state (const XMLNode& node)
+{
+ // relax
+}
+
+void
+Port::gtk_read_callback (void *ptr, int fd, int cond)
+{
+ byte buf[64];
+
+ ((Port *)ptr)->read (buf, sizeof (buf), 0);
+}
+
+void
+Port::write_callback (byte *msg, unsigned int len, void *ptr)
+
+{
+ ((Port *)ptr)->write (msg, len, 0);
+}
+
+std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
+{
+ using namespace std;
+ os << "MIDI::Port { ";
+ os << "device: " << port.device();
+ os << "; ";
+ os << "name: " << port.name();
+ os << "; ";
+ os << "type: " << port.type();
+ os << "; ";
+ os << "mode: " << port.mode();
+ os << "; ";
+ os << "ok: " << port.ok();
+ os << "; ";
+ os << " }";
+ return os;
+}
+
+Port::Descriptor::Descriptor (const XMLNode& node)
+{
+ const XMLProperty *prop;
+ bool have_tag = false;
+ bool have_device = false;
+ bool have_type = false;
+ bool have_mode = false;
+
+ if ((prop = node.property ("tag")) != 0) {
+ tag = prop->value();
+ have_tag = true;
+ }
+
+ if ((prop = node.property ("device")) != 0) {
+ device = prop->value();
+ have_device = true;
+ }
+
+ if ((prop = node.property ("type")) != 0) {
+ type = PortFactory::string_to_type (prop->value());
+ have_type = true;
+ }
+
+ if ((prop = node.property ("mode")) != 0) {
+ mode = PortFactory::string_to_mode (prop->value());
+ have_mode = true;
+ }
+
+ if (!have_tag || !have_device || !have_type || !have_mode) {
+ throw failed_constructor();
+ }
+}
+
diff --git a/libs/midi++2/miditrace.cc b/libs/midi++2/miditrace.cc
index d7c65d9f29..fafe822f82 100644
--- a/libs/midi++2/miditrace.cc
+++ b/libs/midi++2/miditrace.cc
@@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
TextReceiver text_receiver ("mmctest");
#include "midi++/port.h"
-#include "midi++/port_request.h"
#include "midi++/manager.h"
using namespace MIDI;
diff --git a/libs/midi++2/mmctest.cc b/libs/midi++2/mmctest.cc
index 36fbd61124..062f6e8d32 100644
--- a/libs/midi++2/mmctest.cc
+++ b/libs/midi++2/mmctest.cc
@@ -11,7 +11,6 @@ Transmitter fatal (Transmitter::Fatal);
TextReceiver text_receiver ("mmctest");
#include "midi++/port.h"
-#include "midi++/port_request.h"
#include "midi++/manager.h"
#include "midi++/mmc.h"
diff --git a/libs/midi++2/port_request.cc b/libs/midi++2/port_request.cc
deleted file mode 100644
index d209f02574..0000000000
--- a/libs/midi++2/port_request.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- Copyright (C) 2000 Paul Barton-Davis
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- $Id$
-*/
-
-#include <fcntl.h>
-#include <string.h>
-#include <midi++/port.h>
-#include <midi++/port_request.h>
-
-using namespace std;
-using namespace MIDI;
-
-PortRequest::PortRequest (const string &xdev,
- const string &xtag,
- const string &xmode,
- const string &xtype)
-
-{
- status = OK;
-
- devname = strdup (xdev.c_str());
- tagname = strdup (xtag.c_str());
-
- if (xmode == "output" ||
- xmode == "out" ||
- xmode == "OUTPUT" ||
- xmode == "OUT") {
- mode = O_WRONLY;
-
- } else if (xmode == "input" ||
- xmode == "in" ||
- xmode == "INPUT" ||
- xmode == "IN") {
- mode = O_RDONLY;
-
- } else if (xmode == "duplex" ||
- xmode == "DUPLEX" ||
- xmode == "inout" ||
- xmode == "INOUT") {
- mode = O_RDWR;
- } else {
- status = Unknown;
- }
-
- if (xtype == "JACK" ||
- xtype == "jack") {
- type = Port::JACK_Midi;
- } else if (xtype == "ALSA/RAW" ||
- xtype == "alsa/raw") {
- type = Port::ALSA_RawMidi;
- } else if (xtype == "ALSA/SEQUENCER" ||
- xtype == "alsa/sequencer") {
- type = Port::ALSA_Sequencer;
- } else if (xtype == "COREMIDI" ||
- xtype == "coremidi") {
- type = Port::CoreMidi_MidiPort;
- } else if (xtype == "NULL" ||
- xtype == "null") {
- type = Port::Null;
- } else if (xtype == "FIFO" ||
- xtype == "fifo") {
- type = Port::FIFO;
- } else {
- status = Unknown;
- }
-}
-
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index 303ac84552..d513dfc762 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -31,6 +31,7 @@ filesystem_paths.cc
file_utils.cc
fpu.cc
id.cc
+misc.c
mountpoint.cc
pathscanner.cc
pool.cc
diff --git a/libs/pbd/convert.cc b/libs/pbd/convert.cc
index 07fcc09ace..2ce99ba631 100644
--- a/libs/pbd/convert.cc
+++ b/libs/pbd/convert.cc
@@ -30,6 +30,7 @@
using std::string;
using std::vector;
+using Glib::ustring;
namespace PBD {
@@ -194,6 +195,52 @@ url_decode (string& url)
}
}
+void
+url_decode (ustring& url)
+{
+ ustring::iterator last;
+ ustring::iterator next;
+
+ for (ustring::iterator i = url.begin(); i != url.end(); ++i) {
+ if ((*i) == '+') {
+ next = i;
+ ++next;
+ url.replace (i, next, 1, ' ');
+ }
+ }
+
+ if (url.length() <= 3) {
+ return;
+ }
+
+ last = url.end();
+
+ --last; /* points at last char */
+ --last; /* points at last char - 1 */
+
+ for (ustring::iterator i = url.begin(); i != last; ) {
+
+ if (*i == '%') {
+
+ next = i;
+
+ url.erase (i);
+
+ i = next;
+ ++next;
+
+ if (isxdigit (*i) && isxdigit (*next)) {
+ /* replace first digit with char */
+ url.replace (i, next, 1, (gunichar) int_from_hex (*i,*next));
+ ++i; /* points at 2nd of 2 digits */
+ url.erase (i);
+ }
+ } else {
+ ++i;
+ }
+ }
+}
+
#if 0
string
length2string (const int32_t frames, const float sample_rate)
diff --git a/libs/pbd/file_utils.cc b/libs/pbd/file_utils.cc
index efb065fbd4..f8dfe269c5 100644
--- a/libs/pbd/file_utils.cc
+++ b/libs/pbd/file_utils.cc
@@ -102,14 +102,6 @@ find_file_in_search_path(const SearchPath& search_path,
if (tmp.size() == 0)
{
- info << string_compose
- (
- "Found no file named %1 in search path %2",
- filename,
- search_path.to_string ()
- )
- << endmsg;
-
return false;
}
diff --git a/libs/pbd/misc.c b/libs/pbd/misc.c
new file mode 100644
index 0000000000..797be5de45
--- /dev/null
+++ b/libs/pbd/misc.c
@@ -0,0 +1,21 @@
+#include <pbd/misc.h>
+
+#ifdef GTKOSX
+#include <AppKit/AppKit.h>
+#endif
+
+void
+disable_screen_updates ()
+{
+#ifdef GTKOSX
+ NSDisableScreenUpdates ();
+#endif
+}
+
+void
+enable_screen_updates ()
+{
+#ifdef GTKOSX
+ NSEnableScreenUpdates();
+#endif
+}
diff --git a/libs/pbd/pbd/convert.h b/libs/pbd/pbd/convert.h
index 00176659cf..83cd285098 100644
--- a/libs/pbd/pbd/convert.h
+++ b/libs/pbd/pbd/convert.h
@@ -22,6 +22,9 @@
#include <string>
#include <vector>
+#include <sstream>
+#include <iostream>
+#include <glibmm/ustring.h>
namespace PBD {
@@ -30,6 +33,7 @@ std::string short_version (std::string, std::string::size_type target_length);
int atoi (const std::string&);
double atof (const std::string&);
void url_decode (std::string&);
+void url_decode (Glib::ustring&);
// std::string length2string (const int32_t frames, const float sample_rate);
std::string length2string (const int64_t frames, const double sample_rate);
@@ -37,6 +41,14 @@ std::string length2string (const int64_t frames, const double sample_rate);
std::vector<std::string> internationalize (const char *, const char **);
bool strings_equal_ignore_case (const std::string& a, const std::string& b);
+template <class T> std::string
+to_string (T t, std::ios_base & (*f)(std::ios_base&))
+{
+ std::ostringstream oss;
+ oss << f << t;
+ return oss.str();
+}
+
} //namespace PBD
#endif /* __pbd_convert_h__ */
diff --git a/libs/pbd/pbd/functor_command.h b/libs/pbd/pbd/functor_command.h
new file mode 100644
index 0000000000..e335f4418e
--- /dev/null
+++ b/libs/pbd/pbd/functor_command.h
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __lib_pbd_functor_command_h__
+#define __lib_pbd_functor_command_h__
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+
+#include <pbd/xml++.h>
+#include <pbd/shiva.h>
+#include <pbd/command.h>
+#include <pbd/failed_constructor.h>
+
+/** This command class is initialized
+ */
+
+namespace PBD {
+
+template <class obj_type, class arg_type>
+class FunctorCommand : public Command
+{
+ private:
+ typedef void (obj_type::*functor_type)(arg_type);
+ typedef std::map< std::string, functor_type > FunctorMap;
+ typedef typename FunctorMap::iterator FunctorMapIterator;
+
+ public:
+ FunctorCommand(
+ std::string functor,
+ obj_type object,
+ arg_type b,
+ arg_type a
+ ) : functor_name(functor),
+ object(object),
+ before(b),
+ after(a)
+ {
+ method = find_functor(functor);
+
+ /* catch destruction of the object */
+ new PBD::Shiva< obj_type, FunctorCommand<obj_type, arg_type> > (object, *this);
+ }
+
+ ~FunctorCommand() {
+ GoingAway();
+ }
+
+ void operator() () {
+ (object.*method) (after);
+ }
+
+ void undo() {
+ (object.*method) (before);
+ }
+
+ virtual XMLNode &get_state() {
+ std::stringstream ss;
+
+ XMLNode *node = new XMLNode("FunctorCommand");
+ node->add_property("functor", functor_name);
+ ss << before;
+ node->add_property("before", ss.str());
+ ss.clear ();
+ ss << after;
+ node->add_property("after", ss.str());
+
+ return *node;
+ }
+
+ static void register_functor(std::string name, functor_type f) {
+ functor_map[name] = f;
+ }
+
+ private:
+ static functor_type find_functor(std::string name) {
+ FunctorMapIterator iter;
+
+ if((iter = functor_map.find(name)) == functor_map.end()) {
+ throw failed_constructor();
+ }
+
+ return iter->second;
+ }
+
+ protected:
+ std::string functor_name;
+ obj_type &object;
+ arg_type before;
+ arg_type after;
+ functor_type method;
+ static FunctorMap functor_map;
+};
+
+// static initialization of functor_map...
+template <class obj_type, class arg_type>
+typename FunctorCommand<obj_type, arg_type>::FunctorMap
+FunctorCommand<obj_type, arg_type>::functor_map;
+
+};
+
+#endif // __lib_pbd_functor_command_h__
+
diff --git a/libs/pbd/pbd/misc.h b/libs/pbd/pbd/misc.h
new file mode 100644
index 0000000000..306c00683e
--- /dev/null
+++ b/libs/pbd/pbd/misc.h
@@ -0,0 +1,15 @@
+#ifndef __pbd_misc_h__
+#define __pbd_misc_h__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void disable_screen_updates ();
+ void enable_screen_updates ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pbd_misc_h__ */
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
index 5bfccf5a06..8f1716d09f 100644
--- a/libs/pbd/pbd/undo.h
+++ b/libs/pbd/pbd/undo.h
@@ -80,20 +80,24 @@ class UndoHistory : public sigc::trackable
unsigned long undo_depth() const { return UndoList.size(); }
unsigned long redo_depth() const { return RedoList.size(); }
- std::string next_undo() const { return (UndoList.empty() ? std::string("") : UndoList.back()->name()); }
- std::string next_redo() const { return (RedoList.empty() ? std::string("") : RedoList.back()->name()); }
+ std::string next_undo() const { return (UndoList.empty() ? std::string() : UndoList.back()->name()); }
+ std::string next_redo() const { return (RedoList.empty() ? std::string() : RedoList.back()->name()); }
void clear ();
void clear_undo ();
void clear_redo ();
- XMLNode &get_state(uint32_t depth = 0);
- void save_state();
+ XMLNode &get_state(int32_t depth = 0);
+ void save_state();
- sigc::signal<void> Changed;
+ void set_depth (int32_t);
+ int32_t get_depth() const { return _depth; }
+ sigc::signal<void> Changed;
+
private:
bool _clearing;
+ int32_t _depth;
std::list<UndoTransaction*> UndoList;
std::list<UndoTransaction*> RedoList;
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc
index 6db85e6ab3..aeff37cce7 100644
--- a/libs/pbd/undo.cc
+++ b/libs/pbd/undo.cc
@@ -148,12 +148,28 @@ XMLNode &UndoTransaction::get_state()
UndoHistory::UndoHistory ()
{
_clearing = false;
+ _depth = 0;
+}
+
+void
+UndoHistory::set_depth (int32_t d)
+{
+ _depth = d;
+
+ while (_depth > 0 && UndoList.size() > (uint32_t) _depth) {
+ UndoList.pop_front ();
+ }
}
void
UndoHistory::add (UndoTransaction* const ut)
{
ut->GoingAway.connect (bind (mem_fun (*this, &UndoHistory::remove), ut));
+
+ while (_depth > 0 && UndoList.size() > (uint32_t) _depth) {
+ UndoList.pop_front ();
+ }
+
UndoList.push_back (ut);
/* we are now owners of the transaction */
@@ -240,17 +256,22 @@ UndoHistory::clear ()
}
XMLNode&
-UndoHistory::get_state (uint32_t depth)
+UndoHistory::get_state (int32_t depth)
{
XMLNode *node = new XMLNode ("UndoHistory");
if (depth == 0) {
+
+ return (*node);
+
+ } else if (depth < 0) {
+
/* everything */
for (list<UndoTransaction*>::iterator it = UndoList.begin(); it != UndoList.end(); ++it) {
node->add_child_nocopy((*it)->get_state());
}
-
+
} else {
/* just the last "depth" transactions */
@@ -268,3 +289,5 @@ UndoHistory::get_state (uint32_t depth)
return *node;
}
+
+
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 3906b53e36..93cbf088c7 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -27,7 +27,6 @@
#include <midi++/port.h>
#include <midi++/manager.h>
-#include <midi++/port_request.h>
#include <ardour/route.h>
#include <ardour/session.h>
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
index 05681c0c25..fa7134fa95 100644
--- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -9,7 +9,6 @@
#include <midi++/types.h>
#include <midi++/port.h>
#include <midi++/manager.h>
-#include <midi++/port_request.h>
#include "i18n.h"
#include <unistd.h>
diff --git a/libs/surfaces/powermate/powermate.cc b/libs/surfaces/powermate/powermate.cc
index 139313f3f8..8b3051af20 100644
--- a/libs/surfaces/powermate/powermate.cc
+++ b/libs/surfaces/powermate/powermate.cc
@@ -14,12 +14,15 @@
#include <i18n.h>
#include <pbd/xml++.h>
+#include <pbd/error.h>
+#include <glibmm.h>
#include "powermate.h"
using namespace ARDOUR;
using namespace std;
using namespace sigc;
+using namespace PBD;
#define NUM_VALID_PREFIXES 2
@@ -32,17 +35,22 @@ static const char *valid_prefix[NUM_VALID_PREFIXES] = {
int open_powermate(const char *dev, int mode)
{
- int fd = open(dev, mode);
- int i;
- char name[255];
-
- if(fd < 0){
- fprintf(stderr, "Unable to open \"%s\": %s\n", dev, strerror(errno));
- return -1;
- }
+ if (!Glib::file_test (dev, Glib::FILE_TEST_EXISTS)) {
+ return -1;
+ }
+ int fd = open(dev, mode);
+ int i;
+ char name[255];
+
+ if(fd < 0){
+ if (errno != EACCES) {
+ error << string_compose ("Unable to open \"%1\": %2", dev, strerror(errno)) << endmsg;
+ }
+ return -1;
+ }
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){
- fprintf(stderr, "\"%s\": EVIOCGNAME failed: %s\n", dev, strerror(errno));
+ error << string_compose ("\"%1\": EVIOCGNAME failed: %2", dev, strerror(errno)) << endmsg;
close(fd);
return -1;
}