summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-01-09 23:24:54 +0000
committerDavid Robillard <d@drobilla.net>2007-01-09 23:24:54 +0000
commit532f6aad4ac79ca15d69deccd18fca90e444c437 (patch)
tree0d4ca5449af8eb48ad56e163efcab42c4656e8de /libs
parentef6b25432d9c46d71b08c0f7d5f2686df428c4e8 (diff)
Merged with trunk R1283.
NOTE: Compiles, but broken (crash on adding MIDI track). git-svn-id: svn://localhost/ardour2/branches/midi@1292 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/appleutility/SConscript2
-rw-r--r--libs/ardour/SConscript51
-rw-r--r--libs/ardour/ardour/audio_diskstream.h58
-rw-r--r--libs/ardour/ardour/audio_library.h50
-rw-r--r--libs/ardour/ardour/audioengine.h5
-rw-r--r--libs/ardour/ardour/audiofilesource.h2
-rw-r--r--libs/ardour/ardour/audioplaylist.h9
-rw-r--r--libs/ardour/ardour/audiosource.h5
-rw-r--r--libs/ardour/ardour/automation_event.h6
-rw-r--r--libs/ardour/ardour/configuration_vars.h18
-rw-r--r--libs/ardour/ardour/crossfade.h5
-rw-r--r--libs/ardour/ardour/cycles.h2
-rw-r--r--libs/ardour/ardour/diskstream.h16
-rw-r--r--libs/ardour/ardour/insert.h11
-rw-r--r--libs/ardour/ardour/io.h6
-rw-r--r--libs/ardour/ardour/location.h5
-rw-r--r--libs/ardour/ardour/meter.h10
-rw-r--r--libs/ardour/ardour/midi_diskstream.h4
-rw-r--r--libs/ardour/ardour/midi_playlist.h9
-rw-r--r--libs/ardour/ardour/named_selection.h5
-rw-r--r--libs/ardour/ardour/playlist.h54
-rw-r--r--libs/ardour/ardour/playlist_factory.h25
-rw-r--r--libs/ardour/ardour/redirect.h2
-rw-r--r--libs/ardour/ardour/region.h7
-rw-r--r--libs/ardour/ardour/route.h2
-rw-r--r--libs/ardour/ardour/route_group.h2
-rw-r--r--libs/ardour/ardour/send.h8
-rw-r--r--libs/ardour/ardour/session.h181
-rw-r--r--libs/ardour/ardour/session_playlist.h2
-rw-r--r--libs/ardour/ardour/source.h6
-rw-r--r--libs/ardour/ardour/track.h5
-rw-r--r--libs/ardour/ardour/types.h15
-rw-r--r--libs/ardour/ardour/utils.h12
-rw-r--r--libs/ardour/audio_diskstream.cc215
-rw-r--r--libs/ardour/audio_library.cc459
-rw-r--r--libs/ardour/audio_playlist.cc39
-rw-r--r--libs/ardour/audio_track.cc77
-rw-r--r--libs/ardour/audioengine.cc91
-rw-r--r--libs/ardour/audiofilesource.cc43
-rw-r--r--libs/ardour/audioregion.cc147
-rw-r--r--libs/ardour/audiosource.cc116
-rw-r--r--libs/ardour/auditioner.cc32
-rw-r--r--libs/ardour/automation_event.cc93
-rw-r--r--libs/ardour/configuration.cc4
-rw-r--r--libs/ardour/control_protocol_manager.cc6
-rw-r--r--libs/ardour/crossfade.cc2
-rw-r--r--libs/ardour/diskstream.cc39
-rw-r--r--libs/ardour/enums.cc327
-rw-r--r--libs/ardour/globals.cc102
-rw-r--r--libs/ardour/import.cc32
-rw-r--r--libs/ardour/insert.cc120
-rw-r--r--libs/ardour/io.cc43
-rw-r--r--libs/ardour/location.cc48
-rw-r--r--libs/ardour/meter.cc16
-rw-r--r--libs/ardour/midi_diskstream.cc46
-rw-r--r--libs/ardour/midi_playlist.cc15
-rw-r--r--libs/ardour/midi_port.cc2
-rw-r--r--libs/ardour/midi_track.cc6
-rw-r--r--libs/ardour/named_selection.cc18
-rw-r--r--libs/ardour/panner.cc8
-rw-r--r--libs/ardour/playlist.cc180
-rw-r--r--libs/ardour/playlist_factory.cc91
-rw-r--r--libs/ardour/plugin_manager.cc3
-rw-r--r--libs/ardour/redirect.cc31
-rw-r--r--libs/ardour/region.cc88
-rw-r--r--libs/ardour/route.cc14
-rw-r--r--libs/ardour/route_group.cc23
-rw-r--r--libs/ardour/send.cc15
-rw-r--r--libs/ardour/session.cc258
-rw-r--r--libs/ardour/session_butler.cc2
-rw-r--r--libs/ardour/session_command.cc424
-rw-r--r--libs/ardour/session_events.cc11
-rw-r--r--libs/ardour/session_midi.cc4
-rw-r--r--libs/ardour/session_process.cc2
-rw-r--r--libs/ardour/session_state.cc302
-rw-r--r--libs/ardour/session_time.cc168
-rw-r--r--libs/ardour/session_transport.cc69
-rw-r--r--libs/ardour/smf_source.cc2
-rw-r--r--libs/ardour/sndfilesource.cc29
-rw-r--r--libs/ardour/source.cc13
-rw-r--r--libs/ardour/source_factory.cc161
-rw-r--r--libs/ardour/tempo.cc8
-rw-r--r--libs/ardour/utils.cc132
-rw-r--r--libs/clearlooks/SConscript26
-rw-r--r--libs/flowcanvas/SConscript2
-rw-r--r--libs/fst/SConscript50
-rw-r--r--libs/fst/fstinfofile.c4
-rw-r--r--libs/glibmm2/SConscript2
-rw-r--r--libs/gtkmm2/atk/SConscript2
-rw-r--r--libs/gtkmm2/gdk/SConscript2
-rw-r--r--libs/gtkmm2/gtk/SConscript2
-rw-r--r--libs/gtkmm2/pango/SConscript2
-rw-r--r--libs/gtkmm2ext/SConscript4
-rw-r--r--libs/gtkmm2ext/barcontroller.cc74
-rw-r--r--libs/gtkmm2ext/focus_entry.cc31
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/barcontroller.h22
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/focus_entry.h22
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/pixfader.h70
-rw-r--r--libs/gtkmm2ext/gtkmm2ext/slider_controller.h13
-rw-r--r--libs/gtkmm2ext/pixfader.cc249
-rw-r--r--libs/gtkmm2ext/prompter.cc2
-rw-r--r--libs/gtkmm2ext/slider_controller.cc21
-rw-r--r--libs/gtkmm2ext/tearoff.cc8
-rw-r--r--libs/libglademm/SConscript2
-rw-r--r--libs/libgnomecanvasmm/SConscript2
-rw-r--r--libs/libsndfile/SConscript5
-rwxr-xr-xlibs/libsndfile/configure8
-rw-r--r--libs/midi++2/SConscript2
-rw-r--r--libs/midi++2/jack_midiport.cc4
-rw-r--r--libs/pbd/SConscript6
-rw-r--r--libs/pbd/basename.cc19
-rw-r--r--libs/pbd/controllable.cc4
-rw-r--r--libs/pbd/copyfile.cc38
-rw-r--r--libs/pbd/enumwriter.cc273
-rw-r--r--libs/pbd/pbd/basename.h6
-rw-r--r--libs/pbd/pbd/copyfile.h6
-rw-r--r--libs/pbd/pbd/enumwriter.h77
-rw-r--r--libs/pbd/pbd/tokenizer.h30
-rw-r--r--libs/pbd/pbd/undo.h2
-rw-r--r--libs/pbd/pbd/whitespace.h6
-rw-r--r--libs/pbd/undo.cc26
-rw-r--r--libs/pbd/whitespace.cc6
-rw-r--r--libs/sigc++2/SConscript2
-rw-r--r--libs/soundtouch/SConscript2
-rw-r--r--libs/soundtouch/STTypes.h4
-rw-r--r--libs/surfaces/control_protocol/SConscript2
-rw-r--r--libs/surfaces/control_protocol/control_protocol/smpte.h22
-rw-r--r--libs/surfaces/control_protocol/smpte.cc118
-rw-r--r--libs/surfaces/generic_midi/SConscript3
-rw-r--r--libs/surfaces/generic_midi/generic_midi_control_protocol.cc2
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.cc13
-rw-r--r--libs/surfaces/generic_midi/midicontrollable.h2
-rw-r--r--libs/surfaces/tranzport/SConscript11
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.cc1455
-rw-r--r--libs/surfaces/tranzport/tranzport_control_protocol.h138
135 files changed, 5113 insertions, 2567 deletions
diff --git a/libs/appleutility/SConscript b/libs/appleutility/SConscript
index c8bab03a87..68b731c78e 100644
--- a/libs/appleutility/SConscript
+++ b/libs/appleutility/SConscript
@@ -17,6 +17,6 @@ appleutility.Append(LINKFLAGS='-framework CoreServices')
libappleutility = appleutility.SharedLibrary('appleutility', appleutility_files)
if appleutility['COREAUDIO']:
Default(libappleutility)
- env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libappleutility))
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libappleutility))
env.Alias('tarball', env.Distribute (env['DISTTREE'], ['SConscript'] + appleutility_files + glob.glob('*.h') ))
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript
index 98a1b362bb..68d9112caf 100644
--- a/libs/ardour/SConscript
+++ b/libs/ardour/SConscript
@@ -65,6 +65,7 @@ crossfade.cc
curve.cc
cycle_timer.cc
default_click.cc
+enums.cc
gain.cc
gdither.cc
globals.cc
@@ -127,10 +128,10 @@ if ardour['LIBLO']:
extra_sources += osc_files
ardour.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
-ardour.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
-ardour.Append(CXXFLAGS="-DMODULE_DIR=\\\""+final_prefix+"/lib\\\"")
-ardour.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
-ardour.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+ardour.Append(CXXFLAGS="-DDATA_DIR=\\\"" + os.path.join (final_prefix, 'share') + "\\\"")
+ardour.Append(CXXFLAGS="-DMODULE_DIR=\\\"" + os.path.join (final_prefix, env['LIBDIR']) + "\\\"")
+ardour.Append(CXXFLAGS="-DCONFIG_DIR=\\\"" + final_config_prefix + "\\\"")
+ardour.Append(CXXFLAGS="-DLOCALEDIR=\\\"" + os.path.join (final_prefix, 'share', 'locale') + "\\\"")
ardour.Merge ([ libraries['jack'] ])
@@ -180,17 +181,38 @@ int main(int argc, char** argv)
return 0;
}
"""
-
def CheckJackVideoFrameOffset(context):
context.Message('Checking for JackVideoFrameOffset in jack_position_bits_t enum...')
result = context.TryLink(jack_video_frame_offset_test, '.c')
context.Result(result)
return result
+#
+# See if JACK supports jack_port_ensure_monitor_input()
+#
+jack_ensure_monitor_input_test = """
+#include <jack/jack.h>
+int main(int argc, char** argv)
+{
+ jack_port_t **port;
+
+ jack_port_ensure_monitor (*port, 1);
+ return 0;
+
+}
+"""
+
+def CheckJackEnsureMonitorInput(context):
+ context.Message('Checking for jack_port_ensure_monitor_input()...')
+ result = context.TryLink(jack_ensure_monitor_input_test, '.c')
+ context.Result(result)
+ return result
+
conf = Configure(ardour, custom_tests = {
'CheckJackClientOpen' : CheckJackClientOpen,
'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies,
- 'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset
+ 'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset,
+ 'CheckJackEnsureMonitorInput' : CheckJackEnsureMonitorInput
})
if conf.CheckJackClientOpen():
@@ -201,9 +223,9 @@ if conf.CheckJackRecomputeLatencies():
if conf.CheckJackVideoFrameOffset():
ardour.Append(CXXFLAGS="-DHAVE_JACK_VIDEO_SUPPORT")
-
-if conf.CheckFunc('jack_port_ensure_monitor'):
- env.Append(CCFLAGS='-DHAVE_JACK_PORT_ENSURE_MONITOR')
+
+if conf.CheckJackEnsureMonitorInput():
+ ardour.Append(CXXFLAGS='-DHAVE_JACK_PORT_ENSURE_MONITOR')
else:
print '\nWARNING: You need at least svn revision 985 of jack for hardware monitoring to work correctly.\n'
@@ -220,14 +242,19 @@ if conf.CheckCHeader('sys/vfs.h'):
if conf.CheckCHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
ardour.Append(LINKFLAGS="-framework CoreMIDI")
+if conf.CheckCHeader('/System/Library/Frameworks/AudioToolbox.framework/Headers/ExtendedAudioFile.h'):
+ ardour.Append(LINKFLAGS="-framework AudioToolbox")
+
+if conf.CheckCHeader('/System/Library/Frameworks/CoreAudio.framework/Headers/CoreAudio.h'):
+ ardour.Append(CXXFLAGS="-DHAVE_WEAK_COREAUDIO")
+
if conf.CheckCHeader('/System/Library/Frameworks/AudioUnit.framework/Headers/AudioUnit.h') and ardour['AUDIOUNITS']:
ardour.Append(CXXFLAGS="-DHAVE_AUDIOUNITS")
ardour.Append(LINKFLAGS="-framework AudioUnit")
extra_sources += audiounit_files
-if conf.CheckCHeader('/System/Library/Frameworks/AudioToolbox.framework/Headers/ExtendedAudioFile.h') and ardour['COREAUDIO']:
+if ardour['COREAUDIO']:
ardour.Append(CXXFLAGS="-DHAVE_COREAUDIO")
- ardour.Append(LINKFLAGS="-framework AudioToolbox")
extra_sources += coreaudio_files
if env['CONFIG_ARCH'] == 'apple':
@@ -287,7 +314,7 @@ if env['NLS']:
i18n (ardour, ardour_files + vst_files + coreaudio_files + audiounit_files, env)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libardour))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libardour))
env.Alias('version', ardour.VersionBuild(['version.cc', 'ardour/version.h'], []))
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 4a95e094a9..1da8903a41 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -90,9 +90,9 @@ class AudioDiskstream : public Diskstream
}
}
- AudioPlaylist* audio_playlist () { return dynamic_cast<AudioPlaylist*>(_playlist); }
+ boost::shared_ptr<AudioPlaylist> audio_playlist () { return boost::dynamic_pointer_cast<AudioPlaylist>(_playlist); }
- int use_playlist (Playlist *);
+ int use_playlist (boost::shared_ptr<Playlist>);
int use_new_playlist ();
int use_copy_playlist ();
@@ -173,33 +173,39 @@ class AudioDiskstream : public Diskstream
private:
struct ChannelInfo {
-
- Sample *playback_wrap_buffer;
- Sample *capture_wrap_buffer;
- Sample *speed_buffer;
-
- float peak_power;
- boost::shared_ptr<AudioFileSource> fades_source;
- boost::shared_ptr<AudioFileSource> write_source;
-
- Port *source;
- Sample *current_capture_buffer;
- Sample *current_playback_buffer;
+ ChannelInfo ();
+ ~ChannelInfo ();
- RingBufferNPT<Sample> *playback_buf;
- RingBufferNPT<Sample> *capture_buf;
+ void init (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size);
+ void release ();
- Sample* scrub_buffer;
- Sample* scrub_forward_buffer;
- Sample* scrub_reverse_buffer;
-
- RingBufferNPT<Sample>::rw_vector playback_vector;
- RingBufferNPT<Sample>::rw_vector capture_vector;
-
- RingBufferNPT<CaptureTransition> * capture_transition_buf;
- // the following are used in the butler thread only
- nframes_t curr_capture_cnt;
+ Sample *playback_wrap_buffer;
+ Sample *capture_wrap_buffer;
+ Sample *speed_buffer;
+
+ float peak_power;
+
+ boost::shared_ptr<AudioFileSource> fades_source;
+ boost::shared_ptr<AudioFileSource> write_source;
+
+ Port *source;
+ Sample *current_capture_buffer;
+ Sample *current_playback_buffer;
+
+ RingBufferNPT<Sample> *playback_buf;
+ RingBufferNPT<Sample> *capture_buf;
+
+ Sample* scrub_buffer;
+ Sample* scrub_forward_buffer;
+ Sample* scrub_reverse_buffer;
+
+ RingBufferNPT<Sample>::rw_vector playback_vector;
+ RingBufferNPT<Sample>::rw_vector capture_vector;
+
+ RingBufferNPT<CaptureTransition> * capture_transition_buf;
+ // the following are used in the butler thread only
+ nframes_t curr_capture_cnt;
};
/* The two central butler operations */
diff --git a/libs/ardour/ardour/audio_library.h b/libs/ardour/ardour/audio_library.h
index f5ac6da654..8c01f0e3dc 100644
--- a/libs/ardour/ardour/audio_library.h
+++ b/libs/ardour/ardour/audio_library.h
@@ -1,6 +1,5 @@
/*
- Copyright (C) 2003 Paul Davis
- Author: Taybin Rutkin
+ Copyright (C) 2003-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,7 +15,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#ifndef __ardour_audio_library_h__
@@ -26,64 +24,30 @@
#include <map>
#include <vector>
-#include <sigc++/signal.h>
-
-#include <pbd/stateful.h>
-
using std::vector;
using std::string;
using std::map;
namespace ARDOUR {
-class AudioLibrary : public Stateful
+class AudioLibrary
{
public:
AudioLibrary ();
~AudioLibrary ();
- static string state_node_name;
-
- XMLNode& get_state (void);
- int set_state (const XMLNode&);
-
- void set_paths (vector<string> paths);
- vector<string> get_paths ();
- void scan_paths ();
-
- void add_member (string member);
- void remove_member (string uri);
+ void set_tags (string member, vector<string> tags);
+ vector<string> get_tags (string member);
- void search_members_and (vector<string>& results,
- const map<string,string>& fields);
- void search_members_or (vector<string>& results,
- const map<string,string>& fields);
-
- void add_field (string field);
- void get_fields (vector<string>& fields);
- void remove_field (string field);
- string get_field (string uri, string field);
- void set_field (string uri, string field, string literal);
- string get_label (string uri);
- void set_label (string uri, string name);
+ void search_members_and (vector<string>& results, const vector<string> tags);
void save_changes();
-
- sigc::signal<void> fields_changed;
private:
- vector<string> sfdb_paths;
-
- string field_uri (string name);
-
- bool is_rdf_type (string uri, string type);
- void remove_uri (string uri);
-
string src;
- void initialize_db();
- void compact_vector (vector<string>& vec);
- bool safe_file_extension (string);
+ string path2uri (string path);
+ string uri2path (string uri);
};
extern AudioLibrary* Library;
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index 207e3c6428..3dbd30f841 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -61,7 +61,7 @@ class AudioEngine : public sigc::trackable
bool will_reconnect_at_halt ();
void set_reconnect_at_halt (bool);
- int stop ();
+ int stop (bool forever = false);
int start ();
bool running() const { return _running; }
@@ -195,8 +195,7 @@ class AudioEngine : public sigc::trackable
jack_client_t *_jack;
std::string jack_client_name;
Glib::Mutex _process_lock;
- Glib::Mutex session_remove_lock;
- Glib::Cond session_removed;
+ Glib::Cond session_removed;
bool session_remove_pending;
bool _running;
bool _has_run;
diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h
index bd609a7d80..c1dc7d1e93 100644
--- a/libs/ardour/ardour/audiofilesource.h
+++ b/libs/ardour/ardour/audiofilesource.h
@@ -59,6 +59,8 @@ class AudioFileSource : public AudioSource {
static bool get_soundfile_info (string path, SoundFileInfo& _info, string& error);
+ static bool safe_file_extension (string path);
+
void set_allow_remove_if_empty (bool yn);
void mark_for_remove();
diff --git a/libs/ardour/ardour/audioplaylist.h b/libs/ardour/ardour/audioplaylist.h
index 383ec73531..c0d5ed6e75 100644
--- a/libs/ardour/ardour/audioplaylist.h
+++ b/libs/ardour/ardour/audioplaylist.h
@@ -42,8 +42,10 @@ class AudioPlaylist : public ARDOUR::Playlist
public:
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
AudioPlaylist (Session&, string name, bool hidden = false);
- AudioPlaylist (const AudioPlaylist&, string name, bool hidden = false);
- AudioPlaylist (const AudioPlaylist&, nframes_t start, nframes_t cnt, string name, bool hidden = false);
+ AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, string name, bool hidden = false);
+ AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, nframes_t start, nframes_t cnt, string name, bool hidden = false);
+
+ ~AudioPlaylist ();
void clear (bool with_signals=true);
@@ -70,9 +72,6 @@ class AudioPlaylist : public ARDOUR::Playlist
void check_dependents (boost::shared_ptr<Region> region, bool norefresh);
void remove_dependents (boost::shared_ptr<Region> region);
- protected:
- ~AudioPlaylist (); /* public should use unref() */
-
private:
Crossfades _crossfades; /* xfades currently in use */
Crossfades _pending_xfade_adds;
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 2ada255236..0734a66319 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -113,6 +113,9 @@ const nframes_t frames_per_peak = 256;
void build_peaks_from_scratch ();
int do_build_peak (nframes_t, nframes_t);
+ void truncate_peakfile();
+
+ mutable off_t _peak_byte_max; // modified in do_build_peaks()
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;
@@ -135,7 +138,7 @@ const nframes_t frames_per_peak = 256;
static vector<boost::shared_ptr<AudioSource> > pending_peak_sources;
static Glib::Mutex* pending_peak_sources_lock;
- static void queue_for_peaks (boost::shared_ptr<AudioSource>);
+ static void queue_for_peaks (boost::shared_ptr<AudioSource>, bool notify=true);
static void clear_queue_for_peaks ();
struct PeakBuildRecord {
diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h
index e5c194e683..a2cfb23e61 100644
--- a/libs/ardour/ardour/automation_event.h
+++ b/libs/ardour/ardour/automation_event.h
@@ -82,7 +82,8 @@ class AutomationList : public PBD::StatefulDestructible
void clear ();
void x_scale (double factor);
bool extend_to (double);
-
+ void slide (iterator before, double distance);
+
void reposition_for_rt_add (double when);
void rt_add (double when, double value);
void add (double when, double value);
@@ -190,7 +191,7 @@ class AutomationList : public PBD::StatefulDestructible
AutomationEventList events;
mutable Glib::Mutex lock;
- bool _frozen;
+ int8_t _frozen;
bool changed_when_thawed;
bool _dirty;
@@ -209,6 +210,7 @@ class AutomationList : public PBD::StatefulDestructible
double min_yval;
double max_yval;
double default_value;
+ bool sort_pending;
iterator rt_insertion_point;
double rt_pos;
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 8044190066..c520477c55 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -3,13 +3,8 @@
CONFIG_VARIABLE (AutoConnectOption, output_auto_connect, "output-auto-connect", AutoConnectOption (0))
CONFIG_VARIABLE (AutoConnectOption, input_auto_connect, "input-auto-connect", AutoConnectOption (0))
-#ifdef __APPLE__
-CONFIG_VARIABLE (std::string, auditioner_output_left, "auditioner-output-left", "coreaudio:Built-in Audio:in1")
-CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right", "coreaudio:Built-in Audio:in2")
-#else
-CONFIG_VARIABLE (std::string, auditioner_output_left, "auditioner-output-left", "alsa_pcm:playback_1")
-CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right", "alsa_pcm:playback_2")
-#endif
+CONFIG_VARIABLE (std::string, auditioner_output_left, "auditioner-output-left", "default")
+CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right", "default")
/* MIDI and MIDI related */
@@ -100,16 +95,15 @@ CONFIG_VARIABLE (bool, quieten_at_speed, "quieten-at-speed", true)
/* timecode and sync */
CONFIG_VARIABLE (bool, jack_time_master, "jack-time-master", true)
+CONFIG_VARIABLE (SmpteFormat, smpte_format, "smpte-format", smpte_30)
CONFIG_VARIABLE (bool, use_video_sync, "use-video-sync", false)
CONFIG_VARIABLE (bool, timecode_source_is_synced, "timecode-source-is-synced", true)
-CONFIG_VARIABLE (float, smpte_frames_per_second, "smpte-frames-per-second", 30.0f)
CONFIG_VARIABLE (float, video_pullup, "video-pullup", 0.0f)
-CONFIG_VARIABLE (bool, smpte_drop_frames, "smpte-drop-frames", false)
/* metering */
CONFIG_VARIABLE (float, meter_hold, "meter-hold", 100.0f)
-CONFIG_VARIABLE (float, meter_falloff, "meter-falloff", 0.375f)
+CONFIG_VARIABLE (float, meter_falloff, "meter-falloff", 27.0f)
CONFIG_VARIABLE (nframes_t, over_length_short, "over-length-short", 2)
CONFIG_VARIABLE (nframes_t, over_length_long, "over-length-long", 10)
@@ -119,6 +113,8 @@ CONFIG_VARIABLE (bool, hiding_groups_deactivates_groups, "hiding-groups-deactiva
CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture", true)
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)
/* BWAV */
@@ -127,4 +123,4 @@ CONFIG_VARIABLE (string, bwf_organization_code, "bwf-organization-code", "US")
/* these variables have custom set() methods (e.g. path globbing) */
-CONFIG_VARIABLE_SPECIAL(std::string, raid_path, "raid-path", "", path_expand)
+CONFIG_VARIABLE_SPECIAL(Glib::ustring, raid_path, "raid-path", "", path_expand)
diff --git a/libs/ardour/ardour/crossfade.h b/libs/ardour/ardour/crossfade.h
index d29ba47056..0422698c5e 100644
--- a/libs/ardour/ardour/crossfade.h
+++ b/libs/ardour/ardour/crossfade.h
@@ -64,12 +64,13 @@ class Crossfade : public PBD::StatefulDestructible
/* copy constructor to copy a crossfade with new regions. used (for example)
- when a playlist copy is made */
+ when a playlist copy is made
+ */
Crossfade (const Crossfade &, boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>);
/* the usual XML constructor */
- Crossfade (const ARDOUR::Playlist&, XMLNode&);
+ Crossfade (const Playlist&, XMLNode&);
virtual ~Crossfade();
bool operator== (const ARDOUR::Crossfade&);
diff --git a/libs/ardour/ardour/cycles.h b/libs/ardour/ardour/cycles.h
index ad3e512669..a6f34d59be 100644
--- a/libs/ardour/ardour/cycles.h
+++ b/libs/ardour/ardour/cycles.h
@@ -187,7 +187,7 @@ static inline cycles_t get_cycles (void)
/* begin mach */
#elif defined(__APPLE__)
-#ifdef HAVE_COREAUDIO
+#ifdef HAVE_WEAK_COREAUDIO
#include <CoreAudio/HostTime.h>
#else // Due to MacTypes.h and libgnomecanvasmm Rect conflict
typedef unsigned long long UInt64;
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index eb6d936222..a81921b9f1 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -76,8 +76,8 @@ class IO;
virtual float playback_buffer_load() const = 0;
virtual float capture_buffer_load() const = 0;
- void set_flag (Flag f) { _flags |= f; }
- void unset_flag (Flag f) { _flags &= ~f; }
+ void set_flag (Flag f) { _flags = Flag (_flags | f); }
+ void unset_flag (Flag f) { _flags = Flag (_flags & ~f); }
AlignStyle alignment_style() const { return _alignment_style; }
void set_align_style (AlignStyle);
@@ -104,9 +104,9 @@ class IO;
void set_speed (double);
void non_realtime_set_speed ();
- Playlist* playlist () { return _playlist; }
+ boost::shared_ptr<Playlist> playlist () { return _playlist; }
- virtual int use_playlist (Playlist *);
+ virtual int use_playlist (boost::shared_ptr<Playlist>);
virtual int use_new_playlist () = 0;
virtual int use_copy_playlist () = 0;
@@ -205,7 +205,7 @@ class IO;
virtual void playlist_changed (Change);
virtual void playlist_modified ();
- virtual void playlist_deleted (Playlist*);
+ virtual void playlist_deleted (boost::weak_ptr<Playlist>);
virtual void finish_capture (bool rec_monitors_input) = 0;
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
@@ -245,7 +245,8 @@ class IO;
ARDOUR::Session& _session;
ARDOUR::IO* _io;
ChanCount _n_channels;
- Playlist* _playlist;
+
+ boost::shared_ptr<Playlist> _playlist;
mutable gint _record_enabled;
double _visible_speed;
@@ -299,10 +300,9 @@ class IO;
sigc::connection ports_created_c;
sigc::connection plmod_connection;
- sigc::connection plstate_connection;
sigc::connection plgone_connection;
- unsigned char _flags;
+ Flag _flags;
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/insert.h b/libs/ardour/ardour/insert.h
index 217fd89885..31e59e6704 100644
--- a/libs/ardour/ardour/insert.h
+++ b/libs/ardour/ardour/insert.h
@@ -46,10 +46,8 @@ class Plugin;
class Insert : public Redirect
{
public:
- Insert(Session& s, Placement p);
- Insert(Session& s, string name, Placement p);
-
- Insert(Session& s, Placement p, int imin, int imax, int omin, int omax);
+ Insert(Session& s, std::string name, Placement p);
+ Insert(Session& s, std::string name, Placement p, int imin, int imax, int omin, int omax);
virtual ~Insert() { }
@@ -87,6 +85,11 @@ class PortInsert : public Insert
int32_t can_support_input_configuration (int32_t) const;
int32_t configure_io (int32_t magic, int32_t in, int32_t out);
int32_t compute_output_streams (int32_t cnt) const;
+
+ uint32_t bit_slot() const { return bitslot; }
+
+ private:
+ uint32_t bitslot;
};
class PluginInsert : public Insert
diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h
index f7e1993bb2..c4df46415b 100644
--- a/libs/ardour/ardour/io.h
+++ b/libs/ardour/ardour/io.h
@@ -203,16 +203,16 @@ class IO : public PBD::StatefulDestructible
PBD::Controllable& gain_control() {
return _gain_control;
}
-
+
static void update_meters();
-private:
+ private:
static sigc::signal<void> Meter;
static Glib::StaticMutex m_meter_signal_lock;
sigc::connection m_meter_connection;
-public:
+ public:
/* automation */
diff --git a/libs/ardour/ardour/location.h b/libs/ardour/ardour/location.h
index 94f70bb4e8..57e13de5af 100644
--- a/libs/ardour/ardour/location.h
+++ b/libs/ardour/ardour/location.h
@@ -68,7 +68,7 @@ class Location : public PBD::StatefulDestructible
Location () {
_start = 0;
_end = 0;
- _flags = 0;
+ _flags = Flags (0);
}
Location (const Location& other);
@@ -124,7 +124,7 @@ class Location : public PBD::StatefulDestructible
string _name;
nframes_t _start;
nframes_t _end;
- uint32_t _flags;
+ Flags _flags;
void set_mark (bool yn);
bool set_flag_internal (bool yn, Flags flag);
@@ -153,6 +153,7 @@ class Locations : public PBD::StatefulDestructible
Location* end_location() const;
Location* start_location() const;
+ int next_available_name(string& result,string base);
uint32_t num_range_markers() const;
int set_current (Location *, bool want_lock = true);
diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h
index f18a2e6de9..17379c3baa 100644
--- a/libs/ardour/ardour/meter.h
+++ b/libs/ardour/ardour/meter.h
@@ -38,6 +38,7 @@ public:
void setup (const ChanCount& in);
void reset ();
+ void reset_max ();
/** Compute peaks */
void run (BufferSet& bufs, jack_nframes_t nframes, jack_nframes_t offset=0);
@@ -49,6 +50,14 @@ public:
return minus_infinity();
}
}
+
+ float max_peak_power (uint32_t n) {
+ if (n < _max_peak_power.size()) {
+ return _max_peak_power[n];
+ } else {
+ return minus_infinity();
+ }
+ }
private:
@@ -58,6 +67,7 @@ private:
Session& _session;
std::vector<float> _peak_power;
std::vector<float> _visible_peak_power;
+ std::vector<float> _max_peak_power;
};
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 583cc23de5..ee11b5e133 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -72,9 +72,9 @@ class MidiDiskstream : public Diskstream
void set_record_enabled (bool yn);
- MidiPlaylist* midi_playlist () { return dynamic_cast<MidiPlaylist*>(_playlist); }
+ boost::shared_ptr<MidiPlaylist> midi_playlist () { return boost::dynamic_pointer_cast<MidiPlaylist>(_playlist); }
- int use_playlist (Playlist *);
+ int use_playlist (boost::shared_ptr<Playlist>);
int use_new_playlist ();
int use_copy_playlist ();
diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h
index 6f89d23404..492241d6b5 100644
--- a/libs/ardour/ardour/midi_playlist.h
+++ b/libs/ardour/ardour/midi_playlist.h
@@ -40,10 +40,12 @@ class MidiPlaylist : public ARDOUR::Playlist
public:
MidiPlaylist (Session&, const XMLNode&, bool hidden = false);
MidiPlaylist (Session&, string name, bool hidden = false);
- MidiPlaylist (const MidiPlaylist&, string name, bool hidden = false);
- MidiPlaylist (const MidiPlaylist&, jack_nframes_t start, jack_nframes_t cnt,
+ MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, string name, bool hidden = false);
+ MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, jack_nframes_t start, jack_nframes_t cnt,
string name, bool hidden = false);
+ ~MidiPlaylist ();
+
nframes_t read (MidiRingBuffer& buf,
jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
@@ -63,9 +65,6 @@ protected:
void refresh_dependents (boost::shared_ptr<Region> region);
void remove_dependents (boost::shared_ptr<Region> region);
-protected:
- ~MidiPlaylist (); /* public should use unref() */
-
private:
XMLNode& state (bool full_state);
void dump () const;
diff --git a/libs/ardour/ardour/named_selection.h b/libs/ardour/ardour/named_selection.h
index 87b71e73ff..fd5777ccf6 100644
--- a/libs/ardour/ardour/named_selection.h
+++ b/libs/ardour/ardour/named_selection.h
@@ -23,6 +23,7 @@
#include <string>
#include <list>
+#include <boost/shared_ptr.hpp>
#include <pbd/stateful.h>
@@ -35,12 +36,12 @@ class Playlist;
struct NamedSelection : public Stateful
{
- NamedSelection (std::string, std::list<Playlist*>&);
+ NamedSelection (std::string, std::list<boost::shared_ptr<Playlist> >&);
NamedSelection (Session&, const XMLNode&);
virtual ~NamedSelection ();
std::string name;
- std::list<Playlist*> playlists;
+ std::list<boost::shared_ptr<Playlist> > playlists;
XMLNode& get_state (void);
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index 831c9b3905..9893f7391a 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -26,6 +26,7 @@
#include <map>
#include <list>
#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
#include <sys/stat.h>
@@ -47,21 +48,25 @@ namespace ARDOUR {
class Session;
class Region;
-class Playlist : public PBD::StatefulDestructible {
+class Playlist : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Playlist> {
public:
typedef list<boost::shared_ptr<Region> > RegionList;
Playlist (Session&, const XMLNode&, DataType type, bool hidden = false);
Playlist (Session&, string name, DataType type, bool hidden = false);
- Playlist (const Playlist&, string name, bool hidden = false);
- Playlist (const Playlist&, nframes_t start, nframes_t cnt, string name, bool hidden = false);
+ Playlist (boost::shared_ptr<const Playlist>, string name, bool hidden = false);
+ Playlist (boost::shared_ptr<const Playlist>, nframes_t start, nframes_t cnt, string name, bool hidden = false);
+
+ virtual ~Playlist ();
+
+ void set_region_ownership ();
virtual void clear (bool with_signals=true);
virtual void dump () const;
- void ref();
- void unref();
- uint32_t refcnt() const { return _refcnt; }
+ void use();
+ void release();
+ bool used () const { return _refcnt != 0; }
std::string name() const { return _name; }
void set_name (std::string str);
@@ -92,9 +97,9 @@ class Playlist : public PBD::StatefulDestructible {
void duplicate (boost::shared_ptr<Region>, nframes_t position, float times);
void nudge_after (nframes_t start, nframes_t distance, bool forwards);
- Playlist* cut (list<AudioRange>&, bool result_is_hidden = true);
- Playlist* copy (list<AudioRange>&, bool result_is_hidden = true);
- int paste (Playlist&, nframes_t position, float times);
+ boost::shared_ptr<Playlist> cut (list<AudioRange>&, bool result_is_hidden = true);
+ boost::shared_ptr<Playlist> copy (list<AudioRange>&, bool result_is_hidden = true);
+ int paste (boost::shared_ptr<Playlist>, nframes_t position, float times);
RegionList* regions_at (nframes_t frame);
RegionList* regions_touched (nframes_t start, nframes_t end);
@@ -109,14 +114,11 @@ class Playlist : public PBD::StatefulDestructible {
int set_state (const XMLNode&);
XMLNode& get_template ();
- sigc::signal<void,Playlist*,bool> InUse;
- sigc::signal<void> Modified;
- sigc::signal<void> NameChanged;
- sigc::signal<void> LengthChanged;
- sigc::signal<void> LayeringChanged;
- sigc::signal<void> StatePushed;
-
- static sigc::signal<void,Playlist*> PlaylistCreated;
+ sigc::signal<void,bool> InUse;
+ sigc::signal<void> Modified;
+ sigc::signal<void> NameChanged;
+ sigc::signal<void> LengthChanged;
+ sigc::signal<void> LayeringChanged;
static string bump_name (string old_name, Session&);
static string bump_name_once (string old_name);
@@ -142,7 +144,6 @@ class Playlist : public PBD::StatefulDestructible {
protected:
friend class Session;
- virtual ~Playlist (); /* members of the public use unref() */
protected:
struct RegionLock {
@@ -244,26 +245,23 @@ class Playlist : public PBD::StatefulDestructible {
boost::shared_ptr<Region> region_by_id (PBD::ID);
- void add_region_internal (boost::shared_ptr<Region>, nframes_t position, bool delay_sort = false);
-
- int remove_region_internal (boost::shared_ptr<Region>, bool delay_sort = false);
+ void add_region_internal (boost::shared_ptr<Region>, nframes_t position);
+
+ int remove_region_internal (boost::shared_ptr<Region>);
RegionList *find_regions_at (nframes_t frame);
void copy_regions (RegionList&) const;
void partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist);
nframes_t _get_maximum_extent() const;
- Playlist* cut_copy (Playlist* (Playlist::*pmf)(nframes_t, nframes_t, bool),
- list<AudioRange>& ranges, bool result_is_hidden);
- Playlist *cut (nframes_t start, nframes_t cnt, bool result_is_hidden);
- Playlist *copy (nframes_t start, nframes_t cnt, bool result_is_hidden);
+ boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t, bool),
+ list<AudioRange>& ranges, bool result_is_hidden);
+ boost::shared_ptr<Playlist> cut (nframes_t start, nframes_t cnt, bool result_is_hidden);
+ boost::shared_ptr<Playlist> copy (nframes_t start, nframes_t cnt, bool result_is_hidden);
int move_region_to_layer (layer_t, boost::shared_ptr<Region> r, int dir);
void relayer ();
-
- static Playlist* copyPlaylist (const Playlist&, nframes_t start, nframes_t length,
- string name, bool result_is_hidden);
void unset_freeze_parent (Playlist*);
void unset_freeze_child (Playlist*);
diff --git a/libs/ardour/ardour/playlist_factory.h b/libs/ardour/ardour/playlist_factory.h
new file mode 100644
index 0000000000..23aad3cd78
--- /dev/null
+++ b/libs/ardour/ardour/playlist_factory.h
@@ -0,0 +1,25 @@
+#ifndef __ardour_playlist_factory_h__
+#define __ardour_playlist_factory_h__
+
+#include <ardour/playlist.h>
+
+class XMLNode;
+
+namespace ARDOUR {
+
+class Session;
+
+class PlaylistFactory {
+
+ public:
+ static sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistCreated;
+
+ static boost::shared_ptr<Playlist> create (Session&, const XMLNode&, bool hidden = false);
+ static boost::shared_ptr<Playlist> create (DataType type, Session&, string name, bool hidden = false);
+ static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, string name, bool hidden = false);
+ static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, nframes_t start, nframes_t cnt, string name, bool hidden = false);
+};
+
+}
+
+#endif /* __ardour_playlist_factory_h__ */
diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h
index 79ae4516c5..8c3de09c10 100644
--- a/libs/ardour/ardour/redirect.h
+++ b/libs/ardour/ardour/redirect.h
@@ -111,8 +111,6 @@ class Redirect : public IO
virtual void transport_stopped (nframes_t frame) {};
protected:
- void set_placement (const string&, void *src);
-
/* children may use this stuff as they see fit */
map<uint32_t,AutomationList*> parameter_automation;
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 88bb294e5d..46865d8357 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -167,9 +167,8 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
virtual uint32_t read_data_count() const { return _read_data_count; }
- ARDOUR::Playlist* playlist() const { return _playlist; }
-
- void set_playlist (ARDOUR::Playlist*);
+ boost::shared_ptr<ARDOUR::Playlist> playlist() const { return _playlist.lock(); }
+ virtual void set_playlist (boost::weak_ptr<ARDOUR::Playlist>);
void source_deleted (boost::shared_ptr<Source>);
@@ -238,7 +237,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
Change _pending_changed;
uint64_t _last_layer_op; ///< timestamp
Glib::Mutex _lock;
- ARDOUR::Playlist* _playlist;
+ boost::weak_ptr<ARDOUR::Playlist> _playlist;
SourceList _sources;
/** Used when timefx are applied, so we can always use the original source */
SourceList _master_sources;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 6bc37ee51e..2f94e0c80a 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -248,7 +248,7 @@ class Route : public IO
void curve_reallocate ();
protected:
- unsigned char _flags;
+ Flag _flags;
/* tight cache-line access here is more important than sheer speed of
access.
diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h
index e9fad1aa2b..d87d3fa3a4 100644
--- a/libs/ardour/ardour/route_group.h
+++ b/libs/ardour/ardour/route_group.h
@@ -115,7 +115,7 @@ class RouteGroup : public Stateful, public sigc::trackable {
Session& _session;
list<Route *> routes;
string _name;
- uint32_t _flags;
+ Flag _flags;
void remove_when_going_away (Route*);
};
diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h
index 12a0cba3ec..eceb301bf8 100644
--- a/libs/ardour/ardour/send.h
+++ b/libs/ardour/ardour/send.h
@@ -33,12 +33,15 @@
namespace ARDOUR {
-class Send : public Redirect {
+class Send : public Redirect
+{
public:
Send (Session&, Placement);
Send (Session&, const XMLNode&);
Send (const Send&);
~Send ();
+
+ uint32_t bit_slot() const { return bitslot; }
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
@@ -54,9 +57,12 @@ class Send : public Redirect {
uint32_t pans_required() const { return _expected_inputs.get(DataType::AUDIO); }
void expect_inputs (const ChanCount&);
+ static uint32_t how_many_sends();
+
private:
bool _metering;
ChanCount _expected_inputs;
+ uint32_t bitslot;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 039bf92362..1c1ea9e62c 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -29,6 +29,7 @@
#include <stack>
#include <boost/weak_ptr.hpp>
+#include <boost/dynamic_bitset.hpp>
#include <stdint.h>
@@ -117,9 +118,9 @@ using std::set;
class Session : public PBD::StatefulDestructible
{
private:
- typedef std::pair<boost::shared_ptr<Route>,bool> RouteBooleanState;
+ typedef std::pair<boost::weak_ptr<Route>,bool> RouteBooleanState;
typedef vector<RouteBooleanState> GlobalRouteBooleanState;
- typedef std::pair<boost::shared_ptr<Route>,MeterPoint> RouteMeterState;
+ typedef std::pair<boost::weak_ptr<Route>,MeterPoint> RouteMeterState;
typedef vector<RouteMeterState> GlobalRouteMeterState;
public:
@@ -253,6 +254,7 @@ class Session : public PBD::StatefulDestructible
void set_dirty ();
void set_clean ();
bool dirty() const { return _state_of_the_state & Dirty; }
+ void set_deletion_in_progress ();
bool deletion_in_progress() const { return _state_of_the_state & Deletion; }
sigc::signal<void> DirtyChanged;
@@ -391,6 +393,9 @@ class Session : public PBD::StatefulDestructible
double frames_per_smpte_frame() const { return _frames_per_smpte_frame; }
nframes_t smpte_frames_per_hour() const { return _smpte_frames_per_hour; }
+ float smpte_frames_per_second() const;
+ bool smpte_drop_frames() const;
+
/* Locations */
Locations *locations() { return &_locations; }
@@ -401,6 +406,7 @@ class Session : public PBD::StatefulDestructible
void set_auto_punch_location (Location *);
void set_auto_loop_location (Location *);
+ int location_name(string& result, string base = string(""));
void reset_input_monitor_state ();
@@ -495,19 +501,6 @@ class Session : public PBD::StatefulDestructible
nframes_t transport_frame () const {return _transport_frame; }
nframes_t audible_frame () const;
- enum SmpteFormat {
- smpte_23976,
- smpte_24,
- smpte_24976,
- smpte_25,
- smpte_2997,
- smpte_2997drop,
- smpte_30,
- smpte_30drop,
- smpte_5994,
- smpte_60,
- };
-
enum PullupFormat {
pullup_Plus4Plus1,
pullup_Plus4,
@@ -517,11 +510,10 @@ class Session : public PBD::StatefulDestructible
pullup_Minus1,
pullup_Minus4Plus1,
pullup_Minus4,
- pullup_Minus4Minus1,
+ pullup_Minus4Minus1
};
- int set_smpte_type (float fps, bool drop_frames);
-
+ int set_smpte_format (SmpteFormat);
void sync_time_vars();
void bbt_time (nframes_t when, BBT_Time&);
@@ -584,7 +576,7 @@ class Session : public PBD::StatefulDestructible
bool multichan;
bool sample_convert;
volatile bool freeze;
- string pathname;
+ std::vector<Glib::ustring> paths;
/* result */
std::vector<boost::shared_ptr<Region> > new_regions;
@@ -602,7 +594,6 @@ class Session : public PBD::StatefulDestructible
void add_source (boost::shared_ptr<Source>);
void remove_source (boost::weak_ptr<Source>);
- int cleanup_audio_file_source (boost::shared_ptr<AudioFileSource>);
struct cleanup_report {
vector<string> paths;
@@ -622,8 +613,7 @@ class Session : public PBD::StatefulDestructible
this playlist.
*/
- sigc::signal<int,ARDOUR::Playlist*> AskAboutPlaylistDeletion;
-
+ sigc::signal<int,boost::shared_ptr<ARDOUR::Playlist> > AskAboutPlaylistDeletion;
/* handlers should return !0 for use pending state, 0 for
ignore it.
@@ -631,9 +621,6 @@ class Session : public PBD::StatefulDestructible
static sigc::signal<int> AskAboutPendingState;
- sigc::signal<void,boost::shared_ptr<Source> > SourceAdded;
- sigc::signal<void,boost::shared_ptr<Source> > SourceRemoved;
-
boost::shared_ptr<AudioFileSource> create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive);
boost::shared_ptr<MidiSource> create_midi_source_for_session (ARDOUR::MidiDiskstream&);
@@ -642,15 +629,15 @@ class Session : public PBD::StatefulDestructible
/* playlist management */
- Playlist* playlist_by_name (string name);
- void add_playlist (Playlist *);
- sigc::signal<void,Playlist*> PlaylistAdded;
- sigc::signal<void,Playlist*> PlaylistRemoved;
+ boost::shared_ptr<Playlist> playlist_by_name (string name);
+ void add_playlist (boost::shared_ptr<Playlist>);
+ sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistAdded;
+ sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistRemoved;
uint32_t n_playlists() const;
- template<class T> void foreach_playlist (T *obj, void (T::*func)(Playlist *));
- void get_playlists (std::vector<Playlist*>&);
+ template<class T> void foreach_playlist (T *obj, void (T::*func)(boost::shared_ptr<Playlist>));
+ void get_playlists (std::vector<boost::shared_ptr<Playlist> >&);
/* named selections */
@@ -711,9 +698,11 @@ class Session : public PBD::StatefulDestructible
uint32_t n_plugin_inserts() const { return _plugin_inserts.size(); }
uint32_t n_sends() const { return _sends.size(); }
- string next_send_name();
- string next_insert_name();
-
+ uint32_t next_send_id();
+ uint32_t next_insert_id();
+ void mark_send_id (uint32_t);
+ void mark_insert_id (uint32_t);
+
/* s/w "RAID" management */
nframes_t available_capture_duration();
@@ -786,59 +775,75 @@ class Session : public PBD::StatefulDestructible
std::map<PBD::ID, PBD::StatefulThingWithGoingAway*> registry;
// these commands are implemented in libs/ardour/session_command.cc
- Command *memento_command_factory(XMLNode *n);
- void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway *);
+ Command* memento_command_factory(XMLNode* n);
+ void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*);
+
+ Command* global_state_command_factory (const XMLNode& n);
+
+ class GlobalRouteStateCommand : public Command
+ {
+ public:
+ GlobalRouteStateCommand (Session&, void*);
+ GlobalRouteStateCommand (Session&, const XMLNode& node);
+ int set_state (const XMLNode&);
+ XMLNode& get_state ();
+
+ protected:
+ GlobalRouteBooleanState before, after;
+ Session& sess;
+ void* src;
+
+ };
- class GlobalSoloStateCommand : public Command
+ class GlobalSoloStateCommand : public GlobalRouteStateCommand
{
- GlobalRouteBooleanState before, after;
- Session &sess;
- void *src;
- public:
- GlobalSoloStateCommand(Session &, void *src);
- void operator()();
- void undo();
- XMLNode &get_state();
- void mark();
+ public:
+ GlobalSoloStateCommand (Session &, void *src);
+ GlobalSoloStateCommand (Session&, const XMLNode&);
+ void operator()(); //redo
+ void undo();
+ XMLNode &get_state();
+ void mark();
};
- class GlobalMuteStateCommand : public Command
+ class GlobalMuteStateCommand : public GlobalRouteStateCommand
{
- GlobalRouteBooleanState before, after;
- Session &sess;
- void *src;
- public:
- GlobalMuteStateCommand(Session &, void *src);
- void operator()();
- void undo();
- XMLNode &get_state();
- void mark();
+ public:
+ GlobalMuteStateCommand(Session &, void *src);
+ GlobalMuteStateCommand (Session&, const XMLNode&);
+ void operator()(); // redo
+ void undo();
+ XMLNode &get_state();
+ void mark();
};
- class GlobalRecordEnableStateCommand : public Command
+ class GlobalRecordEnableStateCommand : public GlobalRouteStateCommand
{
- GlobalRouteBooleanState before, after;
- Session &sess;
- void *src;
- public:
- GlobalRecordEnableStateCommand(Session &, void *src);
- void operator()();
- void undo();
- XMLNode &get_state();
- void mark();
+ public:
+ GlobalRecordEnableStateCommand(Session &, void *src);
+ GlobalRecordEnableStateCommand (Session&, const XMLNode&);
+ void operator()(); // redo
+ void undo();
+ XMLNode &get_state();
+ void mark();
};
class GlobalMeteringStateCommand : public Command
{
- GlobalRouteMeterState before, after;
- Session &sess;
- void *src;
- public:
- GlobalMeteringStateCommand(Session &, void *src);
- void operator()();
- void undo();
- XMLNode &get_state();
- void mark();
+ public:
+ GlobalMeteringStateCommand(Session &, void *src);
+ GlobalMeteringStateCommand (Session&, const XMLNode&);
+ void operator()();
+ void undo();
+ XMLNode &get_state();
+ int set_state (const XMLNode&);
+ void mark();
+
+ protected:
+ Session& sess;
+ void* src;
+ GlobalRouteMeterState before;
+ GlobalRouteMeterState after;
};
/* clicking */
@@ -951,6 +956,7 @@ class Session : public PBD::StatefulDestructible
private:
int create (bool& new_session, string* mix_template, nframes_t initial_length);
+ void destroy ();
nframes_t compute_initial_length ();
@@ -1102,7 +1108,6 @@ class Session : public PBD::StatefulDestructible
void hookup_io ();
void when_engine_running ();
- sigc::connection first_time_running;
void graph_reordered ();
string _current_snapshot_name;
@@ -1134,6 +1139,8 @@ class Session : public PBD::StatefulDestructible
bool butler_should_run;
mutable gint butler_should_do_transport_work;
int butler_request_pipe[2];
+
+ inline bool transport_work_requested() const { return g_atomic_int_get(&butler_should_do_transport_work); }
struct ButlerRequest {
enum Type {
@@ -1306,7 +1313,7 @@ class Session : public PBD::StatefulDestructible
nframes_t _smpte_frames_per_hour;
nframes_t _smpte_offset;
bool _smpte_offset_negative;
-
+
/* cache the most-recently requested time conversions. This helps when we
* have multiple clocks showing the same time (e.g. the transport frame) */
bool last_smpte_valid;
@@ -1392,9 +1399,8 @@ class Session : public PBD::StatefulDestructible
void realtime_stop (bool abort);
void non_realtime_start_scrub ();
void non_realtime_set_speed ();
- void non_realtime_stop (bool abort);
- void non_realtime_overwrite ();
- void non_realtime_buffer_fill ();
+ void non_realtime_stop (bool abort, int entry_request_count, bool& finished);
+ void non_realtime_overwrite (int entry_request_count, bool& finished);
void butler_transport_work ();
void post_transport ();
void engine_halted ();
@@ -1469,19 +1475,19 @@ class Session : public PBD::StatefulDestructible
/* PLAYLISTS */
mutable Glib::Mutex playlist_lock;
- typedef set<Playlist *> PlaylistList;
+ typedef set<boost::shared_ptr<Playlist> > PlaylistList;
PlaylistList playlists;
PlaylistList unused_playlists;
int load_playlists (const XMLNode&);
int load_unused_playlists (const XMLNode&);
- void remove_playlist (Playlist *);
- void track_playlist (Playlist *, bool);
+ void remove_playlist (boost::weak_ptr<Playlist>);
+ void track_playlist (bool, boost::weak_ptr<Playlist>);
- Playlist *playlist_factory (string name);
- Playlist *XMLPlaylistFactory (const XMLNode&);
+ boost::shared_ptr<Playlist> playlist_factory (string name);
+ boost::shared_ptr<Playlist> XMLPlaylistFactory (const XMLNode&);
- void playlist_length_changed (Playlist *);
+ void playlist_length_changed ();
void diskstream_playlist_changed (boost::shared_ptr<Diskstream>);
/* NAMED SELECTIONS */
@@ -1522,9 +1528,12 @@ class Session : public PBD::StatefulDestructible
list<PortInsert *> _port_inserts;
list<PluginInsert *> _plugin_inserts;
list<Send *> _sends;
+ boost::dynamic_bitset<uint32_t> send_bitset;
+ boost::dynamic_bitset<uint32_t> insert_bitset;
uint32_t send_cnt;
uint32_t insert_cnt;
+
void add_redirect (Redirect *);
void remove_redirect (Redirect *);
diff --git a/libs/ardour/ardour/session_playlist.h b/libs/ardour/ardour/session_playlist.h
index 6f1b8dbd12..20cf4d8f2e 100644
--- a/libs/ardour/ardour/session_playlist.h
+++ b/libs/ardour/ardour/session_playlist.h
@@ -27,7 +27,7 @@
namespace ARDOUR {
template<class T> void
-Session::foreach_playlist (T *obj, void (T::*func)(Playlist *))
+Session::foreach_playlist (T *obj, void (T::*func)(boost::shared_ptr<Playlist>))
{
Glib::Mutex::Lock lm (playlist_lock);
for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); i++) {
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index e94b1af54f..8eaab14ec5 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -66,8 +66,8 @@ class Source : public PBD::StatefulDestructible
void use () { _in_use++; }
void disuse () { if (_in_use) { _in_use--; } }
- void add_playlist (ARDOUR::Playlist*);
- void remove_playlist (ARDOUR::Playlist*);
+ void add_playlist (boost::shared_ptr<ARDOUR::Playlist>);
+ void remove_playlist (boost::weak_ptr<ARDOUR::Playlist>);
uint32_t used() const;
@@ -83,7 +83,7 @@ class Source : public PBD::StatefulDestructible
time_t _timestamp;
jack_nframes_t _length;
- std::set<ARDOUR::Playlist*> _playlists;
+ std::set<boost::shared_ptr<ARDOUR::Playlist> > _playlists;
private:
uint32_t _in_use;
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index d7a2da2f46..eee04d9bfa 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -115,13 +115,12 @@ class Track : public Route
struct FreezeRecord {
FreezeRecord()
- : playlist(0)
- , have_mementos(false)
+ : have_mementos(false)
{}
~FreezeRecord();
- Playlist* playlist;
+ boost::shared_ptr<Playlist> playlist;
vector<FreezeRecordInsertInfo*> insert_info;
bool have_mementos;
FreezeState state;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 1138b5208f..30cdcd8232 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -143,6 +143,18 @@ namespace ARDOUR {
}
};
+ enum SmpteFormat {
+ smpte_23976,
+ smpte_24,
+ smpte_24976,
+ smpte_25,
+ smpte_2997,
+ smpte_2997drop,
+ smpte_30,
+ smpte_30drop,
+ smpte_5994,
+ smpte_60
+ };
struct AnyTime {
enum Type {
@@ -322,7 +334,7 @@ namespace ARDOUR {
};
enum ShuttleUnits {
- Percentage,
+ Percentage,
Semitones
};
@@ -340,6 +352,7 @@ std::istream& operator>>(std::istream& o, ARDOUR::CrossfadeModel& sf);
std::istream& operator>>(std::istream& o, ARDOUR::SlaveSource& sf);
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleBehaviour& sf);
std::istream& operator>>(std::istream& o, ARDOUR::ShuttleUnits& sf);
+std::istream& operator>>(std::istream& o, ARDOUR::SmpteFormat& sf);
using ARDOUR::nframes_t;
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index d926f52f82..de97a5c150 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -34,10 +34,9 @@
class XMLNode;
void elapsed_time_to_str (char *buf, uint32_t seconds);
-std::string legalize_for_path (std::string str);
+Glib::ustring legalize_for_path (Glib::ustring str);
std::ostream& operator<< (std::ostream& o, const ARDOUR::BBT_Time& bbt);
XMLNode* find_named_node (const XMLNode& node, std::string name);
-std::string placement_as_string (ARDOUR::Placement);
static inline float f_max(float x, float a) {
x -= a;
@@ -52,10 +51,11 @@ int cmp_nocase (const std::string& s, const std::string& s2);
int tokenize_fullpath (std::string fullpath, std::string& path, std::string& name);
-int touch_file(std::string path);
+int touch_file(Glib::ustring path);
-std::string region_name_from_path (std::string path);
-std::string path_expand (std::string);
+Glib::ustring path_expand (Glib::ustring);
+Glib::ustring region_name_from_path (Glib::ustring path, bool strip_channels);
+bool path_is_paired (Glib::ustring path, Glib::ustring& pair_base);
void compute_equal_power_fades (nframes_t nframes, float* in, float* out);
@@ -66,6 +66,8 @@ const char* edit_mode_to_string (ARDOUR::EditMode);
ARDOUR::EditMode string_to_edit_mode (std::string);
float meter_falloff_to_float (ARDOUR::MeterFalloff);
+ARDOUR::MeterFalloff meter_falloff_from_float (float);
+float meter_falloff_to_db_per_sec (float);
float meter_hold_to_float (ARDOUR::MeterHold);
#if defined(HAVE_COREAUDIO) || defined(HAVE_AUDIOUNITS)
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 9c5f5233b7..7165a58b27 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -35,6 +35,7 @@
#include <glibmm/thread.h>
#include <pbd/xml++.h>
#include <pbd/memento_command.h>
+#include <pbd/enumwriter.h>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
@@ -46,6 +47,7 @@
#include <ardour/send.h>
#include <ardour/region_factory.h>
#include <ardour/audioplaylist.h>
+#include <ardour/playlist_factory.h>
#include <ardour/cycle_timer.h>
#include <ardour/audioregion.h>
#include <ardour/audio_port.h>
@@ -96,34 +98,6 @@ AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
}
void
-AudioDiskstream::init_channel (ChannelInfo &chan)
-{
- chan.playback_wrap_buffer = 0;
- chan.capture_wrap_buffer = 0;
- chan.speed_buffer = 0;
- chan.peak_power = 0.0f;
- chan.source = 0;
- chan.current_capture_buffer = 0;
- chan.current_playback_buffer = 0;
- chan.curr_capture_cnt = 0;
-
- chan.playback_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size());
- chan.capture_buf = new RingBufferNPT<Sample> (_session.diskstream_buffer_size());
- chan.capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
-
-
- /* touch the ringbuffer buffers, which will cause
- them to be mapped into locked physical RAM if
- we're running with mlockall(). this doesn't do
- much if we're not.
- */
- memset (chan.playback_buf->buffer(), 0, sizeof (Sample) * chan.playback_buf->bufsize());
- memset (chan.capture_buf->buffer(), 0, sizeof (Sample) * chan.capture_buf->bufsize());
- memset (chan.capture_transition_buf->buffer(), 0, sizeof (CaptureTransition) * chan.capture_transition_buf->bufsize());
-}
-
-
-void
AudioDiskstream::init (Diskstream::Flag f)
{
Diskstream::init(f);
@@ -140,40 +114,21 @@ AudioDiskstream::init (Diskstream::Flag f)
assert(_n_channels == ChanCount(DataType::AUDIO, 1));
}
-void
-AudioDiskstream::destroy_channel (ChannelInfo &chan)
-{
- if (chan.write_source) {
- chan.write_source.reset ();
- }
-
- if (chan.speed_buffer) {
- delete [] chan.speed_buffer;
- }
-
- if (chan.playback_wrap_buffer) {
- delete [] chan.playback_wrap_buffer;
- }
- if (chan.capture_wrap_buffer) {
- delete [] chan.capture_wrap_buffer;
- }
-
- delete chan.playback_buf;
- delete chan.capture_buf;
- delete chan.capture_transition_buf;
-
- chan.playback_buf = 0;
- chan.capture_buf = 0;
-}
-
AudioDiskstream::~AudioDiskstream ()
{
- Glib::Mutex::Lock lm (state_lock);
+ notify_callbacks ();
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan)
- destroy_channel((*chan));
-
- channels.clear();
+ {
+ /* don't be holding this lock as we exit the destructor, glib will wince
+ visibly since the mutex gets destroyed before we release it.
+ */
+
+ Glib::Mutex::Lock lm (state_lock);
+ for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ (*chan).release ();
+ }
+ channels.clear();
+ }
}
void
@@ -288,15 +243,13 @@ AudioDiskstream::get_input_sources ()
int
AudioDiskstream::find_and_use_playlist (const string& name)
{
- Playlist* pl;
- AudioPlaylist* playlist;
+ boost::shared_ptr<AudioPlaylist> playlist;
- if ((pl = _session.playlist_by_name (name)) == 0) {
- playlist = new AudioPlaylist(_session, name);
- pl = playlist;
+ if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (_session.playlist_by_name (name))) == 0) {
+ playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (_session, name));
}
- if ((playlist = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
+ if (!playlist) {
error << string_compose(_("AudioDiskstream: Playlist \"%1\" isn't an audio playlist"), name) << endmsg;
return -1;
}
@@ -305,9 +258,9 @@ AudioDiskstream::find_and_use_playlist (const string& name)
}
int
-AudioDiskstream::use_playlist (Playlist* playlist)
+AudioDiskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
{
- assert(dynamic_cast<AudioPlaylist*>(playlist));
+ assert(boost::dynamic_pointer_cast<AudioPlaylist>(playlist));
Diskstream::use_playlist(playlist);
@@ -318,7 +271,7 @@ int
AudioDiskstream::use_new_playlist ()
{
string newname;
- AudioPlaylist* playlist;
+ boost::shared_ptr<AudioPlaylist> playlist;
if (!in_set_state && destructive()) {
return 0;
@@ -330,9 +283,11 @@ AudioDiskstream::use_new_playlist ()
newname = Playlist::bump_name (_name, _session);
}
- if ((playlist = new AudioPlaylist (_session, newname, hidden())) != 0) {
+ if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (_session, newname, hidden()))) != 0) {
+
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
+
} else {
return -1;
}
@@ -353,11 +308,11 @@ AudioDiskstream::use_copy_playlist ()
}
string newname;
- AudioPlaylist* playlist;
+ boost::shared_ptr<AudioPlaylist> playlist;
newname = Playlist::bump_name (_playlist->name(), _session);
- if ((playlist = new AudioPlaylist (*audio_playlist(), newname)) != 0) {
+ if ((playlist = boost::dynamic_pointer_cast<AudioPlaylist>(PlaylistFactory::create (audio_playlist(), newname))) != 0) {
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
} else {
@@ -1553,7 +1508,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
} else {
string whole_file_region_name;
- whole_file_region_name = region_name_from_path (channels[0].write_source->name());
+ whole_file_region_name = region_name_from_path (channels[0].write_source->name(), true);
/* Register a new region with the Session that
describes the entire source. Do this first
@@ -1684,7 +1639,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input)
void
AudioDiskstream::set_record_enabled (bool yn)
{
- if (!recordable() || !_session.record_enabling_legal()) {
+ if (!recordable() || !_session.record_enabling_legal() || _io->n_inputs().get(DataType::AUDIO) == 0) {
return;
}
@@ -1762,8 +1717,7 @@ AudioDiskstream::get_state ()
char buf[64] = "";
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof(buf), "0x%x", _flags);
- node->add_property ("flags", buf);
+ node->add_property ("flags", enum_2_string (_flags));
snprintf (buf, sizeof(buf), "%zd", channels.size());
node->add_property ("channels", buf);
@@ -1850,7 +1804,7 @@ AudioDiskstream::set_state (const XMLNode& node)
}
if ((prop = node.property ("flags")) != 0) {
- _flags = strtol (prop->value().c_str(), 0, 0);
+ _flags = Flag (string_2_enum (prop->value(), _flags));
}
if ((prop = node.property ("channels")) != 0) {
@@ -1982,7 +1936,7 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
}
capturing_sources.clear ();
-
+
for (chan = channels.begin(), n = 0; chan != channels.end(); ++chan, ++n) {
if (!destructive()) {
@@ -2109,15 +2063,19 @@ AudioDiskstream::add_channel ()
{
/* XXX need to take lock??? */
- ChannelInfo chan;
+ /* this copies the ChannelInfo, which currently has no buffers. kind
+ of pointless really, but we want the channels list to contain
+ actual objects, not pointers to objects. mostly for convenience,
+ which isn't much in evidence.
+ */
- init_channel (chan);
+ channels.push_back (ChannelInfo());
- chan.speed_buffer = new Sample[speed_buffer_size];
- chan.playback_wrap_buffer = new Sample[wrap_buffer_size];
- chan.capture_wrap_buffer = new Sample[wrap_buffer_size];
+ /* now allocate the buffers */
- channels.push_back (chan);
+ channels.back().init (_session.diskstream_buffer_size(),
+ speed_buffer_size,
+ wrap_buffer_size);
_n_channels.set(DataType::AUDIO, channels.size());
@@ -2129,10 +2087,8 @@ AudioDiskstream::remove_channel ()
{
if (channels.size() > 1) {
/* XXX need to take lock??? */
- ChannelInfo & chan = channels.back();
- destroy_channel (chan);
+ channels.back().release ();
channels.pop_back();
-
_n_channels.set(DataType::AUDIO, channels.size());
return 0;
}
@@ -2217,7 +2173,7 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
try {
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, 0, first_fs->length(),
- region_name_from_path (first_fs->name()),
+ region_name_from_path (first_fs->name(), true),
0, AudioRegion::Flag (AudioRegion::DefaultFlags|AudioRegion::Automatic|AudioRegion::WholeFile)));
region->special_set_position (0);
}
@@ -2231,7 +2187,7 @@ AudioDiskstream::use_pending_capture_data (XMLNode& node)
}
try {
- region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, 0, first_fs->length(), region_name_from_path (first_fs->name())));
+ region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (pending_sources, 0, first_fs->length(), region_name_from_path (first_fs->name(), true)));
}
catch (failed_constructor& err) {
@@ -2261,10 +2217,10 @@ AudioDiskstream::set_destructive (bool yn)
if (!can_become_destructive (bounce_ignored)) {
return -1;
}
- _flags |= Destructive;
+ _flags = Flag (_flags | Destructive);
use_destructive_playlist ();
} else {
- _flags &= ~Destructive;
+ _flags = Flag (_flags & ~Destructive);
reset_write_sources (true, true);
}
}
@@ -2313,3 +2269,82 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
requires_bounce = false;
return true;
}
+
+AudioDiskstream::ChannelInfo::ChannelInfo ()
+{
+ playback_wrap_buffer = 0;
+ capture_wrap_buffer = 0;
+ speed_buffer = 0;
+ peak_power = 0.0f;
+ source = 0;
+ current_capture_buffer = 0;
+ current_playback_buffer = 0;
+ curr_capture_cnt = 0;
+ playback_buf = 0;
+ capture_buf = 0;
+ capture_transition_buf = 0;
+}
+
+void
+AudioDiskstream::ChannelInfo::init (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size)
+{
+ speed_buffer = new Sample[speed_size];
+ playback_wrap_buffer = new Sample[wrap_size];
+ capture_wrap_buffer = new Sample[wrap_size];
+
+ playback_buf = new RingBufferNPT<Sample> (bufsize);
+ capture_buf = new RingBufferNPT<Sample> (bufsize);
+ capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
+
+ /* touch the ringbuffer buffers, which will cause
+ them to be mapped into locked physical RAM if
+ we're running with mlockall(). this doesn't do
+ much if we're not.
+ */
+
+ memset (playback_buf->buffer(), 0, sizeof (Sample) * playback_buf->bufsize());
+ memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize());
+ memset (capture_transition_buf->buffer(), 0, sizeof (CaptureTransition) * capture_transition_buf->bufsize());
+}
+
+AudioDiskstream::ChannelInfo::~ChannelInfo ()
+{
+}
+
+void
+AudioDiskstream::ChannelInfo::release ()
+{
+ if (write_source) {
+ write_source.reset ();
+ }
+
+ if (speed_buffer) {
+ delete [] speed_buffer;
+ speed_buffer = 0;
+ }
+
+ if (playback_wrap_buffer) {
+ delete [] playback_wrap_buffer;
+ playback_wrap_buffer = 0;
+ }
+
+ if (capture_wrap_buffer) {
+ delete [] capture_wrap_buffer;
+ capture_wrap_buffer = 0;
+ }
+
+ if (playback_buf) {
+ delete playback_buf;
+ playback_buf = 0;
+ }
+
+ if (capture_buf) {
+ delete capture_buf;
+ capture_buf = 0;
+ }
+
+ if (capture_transition_buf) {
+ delete capture_transition_buf;
+ capture_transition_buf = 0;
+ }
+}
diff --git a/libs/ardour/audio_library.cc b/libs/ardour/audio_library.cc
index 3aa6d05be1..2ed4739a96 100644
--- a/libs/ardour/audio_library.cc
+++ b/libs/ardour/audio_library.cc
@@ -1,6 +1,5 @@
/*
- Copyright (C) 2003 Paul Davis
- Author: Taybin Rutkin
+ Copyright (C) 2003-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,25 +15,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
-#include <cstdio> // Needed so that libraptor (included in lrdf) won't complain
-#include <cerrno>
-#include <iostream>
#include <sstream>
-#include <cctype>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fts.h>
+#include <libxml/uri.h>
#include <lrdf.h>
#include <pbd/compose.h>
-#include <ardour/ardour.h>
-#include <ardour/configuration.h>
#include <ardour/audio_library.h>
#include <ardour/utils.h>
@@ -42,16 +32,11 @@
using namespace std;
using namespace ARDOUR;
-using namespace PBD;
-static char* SOUNDFILE = "http://ardour.org/ontology/Soundfile";
-
-string AudioLibrary::state_node_name = "AudioLibrary";
+static char* TAG = "http://ardour.org/ontology/Tag";
AudioLibrary::AudioLibrary ()
{
-// sfdb_paths.push_back("/Users/taybin/sounds");
-
src = "file:" + get_user_ardour_path() + "sfdb";
// workaround for possible bug in raptor that crashes when saving to a
@@ -59,23 +44,6 @@ AudioLibrary::AudioLibrary ()
touch_file(get_user_ardour_path() + "sfdb");
lrdf_read_file(src.c_str());
-
- lrdf_statement pattern;
-
- pattern.subject = SOUNDFILE;
- pattern.predicate = RDF_TYPE;
- pattern.object = RDFS_CLASS;
- pattern.object_type = lrdf_uri;
-
- lrdf_statement* matches = lrdf_matches(&pattern);
-
- // if empty DB, create basic schema
- if (matches == 0) {
- initialize_db ();
- save_changes();
- }
-
- lrdf_free_statements(matches);
}
AudioLibrary::~AudioLibrary ()
@@ -83,56 +51,96 @@ AudioLibrary::~AudioLibrary ()
}
void
-AudioLibrary::initialize_db ()
-{
- // define ardour:Soundfile
- lrdf_add_triple(src.c_str(), SOUNDFILE, RDF_TYPE, RDFS_CLASS, lrdf_uri);
-
- // add intergral fields
- add_field(_("channels"));
- add_field(_("samplerate"));
- add_field(_("resolution"));
- add_field(_("format"));
-}
-
-void
AudioLibrary::save_changes ()
{
if (lrdf_export_by_source(src.c_str(), src.substr(5).c_str())) {
- warning << string_compose(_("Could not open %1. Audio Library not saved"), src) << endmsg;
+ PBD::warning << string_compose(_("Could not open %1. Audio Library not saved"), src) << endmsg;
}
}
-void
-AudioLibrary::add_member (string member)
+string
+AudioLibrary::path2uri (string path)
{
- string file_uri(string_compose("file:%1", member));
+ xmlURI temp;
+ memset(&temp, 0, sizeof(temp));
+
+ xmlChar *cal = xmlCanonicPath((xmlChar*) path.c_str());
+ temp.path = (char *) cal;
+ xmlChar *ret = xmlSaveUri(&temp);
+ xmlFree(cal);
+
+ stringstream uri;
+ uri << "file:" << (const char*) ret;
+
+ xmlFree (ret);
+
+ return uri.str();
+}
- lrdf_add_triple(src.c_str(), file_uri.c_str(), RDF_TYPE,
- SOUNDFILE, lrdf_uri);
+string
+AudioLibrary::uri2path (string uri)
+{
+ string path = xmlURIUnescapeString(uri.c_str(), 0, 0);
+ return path.substr(5);
}
void
-AudioLibrary::remove_member (string uri)
+AudioLibrary::set_tags (string member, vector<string> tags)
+{
+ sort (tags.begin(), tags.end());
+ tags.erase (unique(tags.begin(), tags.end()), tags.end());
+
+ string file_uri(path2uri(member));
+
+ lrdf_remove_uri_matches (file_uri.c_str());
+
+ for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
+ lrdf_add_triple (src.c_str(), file_uri.c_str(), TAG, (*i).c_str(), lrdf_literal);
+ }
+}
+
+vector<string>
+AudioLibrary::get_tags (string member)
{
- lrdf_remove_uri_matches (uri.c_str());
+ vector<string> tags;
+
+ lrdf_statement pattern;
+ pattern.subject = strdup(path2uri(member).c_str());
+ pattern.predicate = TAG;
+ pattern.object = 0;
+ pattern.object_type = lrdf_literal;
+
+ lrdf_statement* matches = lrdf_matches (&pattern);
+ free (pattern.subject);
+
+ lrdf_statement* current = matches;
+ while (current != 0) {
+ tags.push_back (current->object);
+
+ current = current->next;
+ }
+
+ lrdf_free_statements (matches);
+
+ sort (tags.begin(), tags.end());
+
+ return tags;
}
void
-AudioLibrary::search_members_and (vector<string>& members,
- const map<string,string>& fields)
+AudioLibrary::search_members_and (vector<string>& members, const vector<string> tags)
{
lrdf_statement **head;
lrdf_statement* pattern = 0;
lrdf_statement* old = 0;
head = &pattern;
- map<string,string>::const_iterator i;
- for (i = fields.begin(); i != fields.end(); ++i){
+ vector<string>::const_iterator i;
+ for (i = tags.begin(); i != tags.end(); ++i){
pattern = new lrdf_statement;
pattern->subject = "?";
- pattern->predicate = strdup(field_uri(i->first).c_str());
- pattern->object = strdup((i->second).c_str());
+ pattern->predicate = TAG;
+ pattern->object = strdup((*i).c_str());
pattern->next = old;
old = pattern;
@@ -141,340 +149,21 @@ AudioLibrary::search_members_and (vector<string>& members,
if (*head != 0) {
lrdf_uris* ulist = lrdf_match_multi(*head);
for (uint32_t j = 0; ulist && j < ulist->count; ++j) {
-// printf("AND: %s\n", ulist->items[j]);
- members.push_back(ulist->items[j]);
+// cerr << "AND: " << uri2path(ulist->items[j]) << endl;
+ members.push_back(uri2path(ulist->items[j]));
}
lrdf_free_uris(ulist);
- compact_vector(members);
+ sort(members.begin(), members.end());
+ unique(members.begin(), members.end());
}
// memory clean up
pattern = *head;
while(pattern){
- free(pattern->predicate);
free(pattern->object);
old = pattern;
pattern = pattern->next;
delete old;
}
}
-
-void
-AudioLibrary::search_members_or (vector<string>& members,
- const map<string,string>& fields)
-{
- map<string,string>::const_iterator i;
-
- lrdf_statement pattern;
- for (i = fields.begin(); i != fields.end(); ++i) {
- pattern.subject = 0;
- pattern.predicate = strdup(field_uri(i->first).c_str());
- pattern.object = strdup((i->second).c_str());
- pattern.object_type = lrdf_literal;
-
- lrdf_statement* matched = lrdf_matches(&pattern);
-
- lrdf_statement* old = matched;
- while(matched) {
-// printf ("OR: %s\n", matched->subject);
- members.push_back(matched->subject);
- matched = matched->next;
- }
-
- free(pattern.predicate);
- free(pattern.object);
- lrdf_free_statements (old);
- }
-
- compact_vector(members);
-}
-
-void
-AudioLibrary::add_field (string name)
-{
- string local_field = field_uri(name);
- lrdf_statement pattern;
- pattern.subject = strdup(local_field.c_str());
- pattern.predicate = RDF_TYPE;
- pattern.object = RDF_BASE "Property";
- pattern.object_type = lrdf_uri;
-
- if(lrdf_exists_match(&pattern)) {
- return;
- }
-
- // of type rdf:Property
- lrdf_add_triple(src.c_str(), local_field.c_str(), RDF_TYPE,
- RDF_BASE "Property", lrdf_uri);
- // of range ardour:Soundfile
- lrdf_add_triple(src.c_str(), local_field.c_str(), RDFS_BASE "range",
- SOUNDFILE, lrdf_uri);
- // of domain rdf:Literal
- lrdf_add_triple(src.c_str(), local_field.c_str(), RDFS_BASE "domain",
- RDF_BASE "Literal", lrdf_uri);
-
- set_label (local_field, name);
-
- fields_changed(); /* EMIT SIGNAL */
-}
-
-void
-AudioLibrary::get_fields (vector<string>& fields)
-{
- lrdf_statement pattern;
-
- pattern.subject = 0;
- pattern.predicate = RDFS_BASE "range";
- pattern.object = SOUNDFILE;
- pattern.object_type = lrdf_uri;
-
- lrdf_statement* matches = lrdf_matches(&pattern);
-
- lrdf_statement* current = matches;
- while (current != 0) {
- fields.push_back(get_label(current->subject));
-
- current = current->next;
- }
-
- lrdf_free_statements(matches);
-
- compact_vector(fields);
-}
-
-void
-AudioLibrary::remove_field (string name)
-{
- lrdf_remove_uri_matches(field_uri(name).c_str());
- fields_changed (); /* EMIT SIGNAL */
-}
-
-string
-AudioLibrary::get_field (string uri, string field)
-{
- lrdf_statement pattern;
-
- pattern.subject = strdup(uri.c_str());
-
- pattern.predicate = strdup(field_uri(field).c_str());
-
- pattern.object = 0;
- pattern.object_type = lrdf_literal;
-
- lrdf_statement* matches = lrdf_matches(&pattern);
- free(pattern.subject);
- free(pattern.predicate);
-
- stringstream object;
- if (matches != 0){
- object << matches->object;
- }
-
- lrdf_free_statements(matches);
- return object.str();
-}
-
-void
-AudioLibrary::set_field (string uri, string field, string literal)
-{
- lrdf_statement pattern;
-
- pattern.subject = strdup(uri.c_str());
-
- string local_field = field_uri(field);
- pattern.predicate = strdup(local_field.c_str());
-
- pattern.object = 0;
- pattern.object_type = lrdf_literal;
-
- lrdf_remove_matches(&pattern);
- free(pattern.subject);
- free(pattern.predicate);
-
- lrdf_add_triple(src.c_str(), uri.c_str(), local_field.c_str(),
- literal.c_str(), lrdf_literal);
-
- fields_changed(); /* EMIT SIGNAL */
-}
-
-string
-AudioLibrary::field_uri (string name)
-{
- stringstream local_field;
- local_field << "file:sfdb/fields/" << name;
-
- return local_field.str();
-}
-
-string
-AudioLibrary::get_label (string uri)
-{
- lrdf_statement pattern;
- pattern.subject = strdup(uri.c_str());
- pattern.predicate = RDFS_BASE "label";
- pattern.object = 0;
- pattern.object_type = lrdf_literal;
-
- lrdf_statement* matches = lrdf_matches (&pattern);
- free(pattern.subject);
-
- stringstream label;
- if (matches != 0){
- label << matches->object;
- }
-
- lrdf_free_statements(matches);
-
- return label.str();
-}
-
-void
-AudioLibrary::set_label (string uri, string label)
-{
- lrdf_statement pattern;
- pattern.subject = strdup(uri.c_str());
- pattern.predicate = RDFS_BASE "label";
- pattern.object = 0;
- pattern.object_type = lrdf_literal;
-
- lrdf_remove_matches(&pattern);
- free(pattern.subject);
-
- lrdf_add_triple(src.c_str(), uri.c_str(), RDFS_BASE "label",
- label.c_str(), lrdf_literal);
-}
-
-void
-AudioLibrary::compact_vector(vector<string>& vec)
-{
- sort(vec.begin(), vec.end());
- unique(vec.begin(), vec.end());
-}
-
-void
-AudioLibrary::set_paths (vector<string> paths)
-{
- sfdb_paths = paths;
-
- scan_paths ();
-}
-
-vector<string>
-AudioLibrary::get_paths ()
-{
- return sfdb_paths;
-}
-
-void
-AudioLibrary::scan_paths ()
-{
- if (sfdb_paths.size() < 1) {
- return;
- }
-
- vector<char *> pathv(sfdb_paths.size());
- unsigned int i;
- for (i = 0; i < sfdb_paths.size(); ++i) {
- pathv[i] = new char[sfdb_paths[i].length() +1];
- sfdb_paths[i].copy(pathv[i], string::npos);
- pathv[i][sfdb_paths[i].length()] = 0;
- }
- pathv[i] = 0;
-
- FTS* ft = fts_open(&pathv[0], FTS_LOGICAL|FTS_NOSTAT|FTS_PHYSICAL|FTS_XDEV, 0);
- if (errno) {
- error << strerror(errno) << endmsg;
- return;
- }
-
- lrdf_statement s;
- s.predicate = RDF_TYPE;
- s.object = SOUNDFILE;
- s.object_type = lrdf_uri;
- string filename;
- while (FTSENT* file = fts_read(ft)) {
- if ((file->fts_info & FTS_F) && (safe_file_extension(file->fts_name))) {
- filename = "file:";
- filename.append(file->fts_accpath);
- s.subject = strdup(filename.c_str());
- if (lrdf_exists_match(&s)) {
- continue;
- } else {
- add_member(file->fts_accpath);
- cout << file->fts_accpath << endl;
- }
- free(s.subject);
- }
- }
- fts_close(ft);
-
- for (i = 0; i < pathv.size(); ++i) {
- delete[] pathv[i];
- }
-
- save_changes();
-}
-
-bool
-AudioLibrary::safe_file_extension(string file)
-{
- return !(file.rfind(".wav") == string::npos &&
- file.rfind(".aiff")== string::npos &&
- file.rfind(".aif") == string::npos &&
- file.rfind(".snd") == string::npos &&
- file.rfind(".au") == string::npos &&
- file.rfind(".raw") == string::npos &&
- file.rfind(".sf") == string::npos &&
- file.rfind(".cdr") == string::npos &&
- file.rfind(".smp") == string::npos &&
- file.rfind(".maud")== string::npos &&
- file.rfind(".vwe") == string::npos &&
- file.rfind(".paf") == string::npos &&
-#ifdef HAVE_COREAUDIO
- file.rfind(".mp3") == string::npos &&
- file.rfind(".aac") == string::npos &&
- file.rfind(".mp4") == string::npos &&
-#endif // HAVE_COREAUDIO
- file.rfind(".voc") == string::npos);
-}
-
-XMLNode&
-AudioLibrary::get_state ()
-{
- XMLNode* root = new XMLNode(X_("AudioLibrary"));
-
- for (vector<string>::iterator i = sfdb_paths.begin(); i != sfdb_paths.end(); ++i) {
- XMLNode* node = new XMLNode(X_("Path"));
- node->add_property("value", *i);
- root->add_child_nocopy(*node);
- }
-
- return *root;
-}
-
-int
-AudioLibrary::set_state (const XMLNode& node)
-{
- if (node.name() != X_("AudioLibrary")) {
- fatal << "programming error: AudioLibrary: incorrect XML node sent to set_state()" << endmsg;
- return -1;
- }
-
- XMLNodeList nodes = node.children(X_("Path"));
-
- vector<string> paths;
- XMLProperty* prop;
- XMLNode* child;
- for (XMLNodeConstIterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
- child = *iter;
-
- if ((prop = child->property(X_("value"))) != 0) {
- paths.push_back(prop->value());
- }
- }
-
- set_paths (paths);
-
- return 0;
-}
diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc
index 335cb020ae..91bed1a4fa 100644
--- a/libs/ardour/audio_playlist.cc
+++ b/libs/ardour/audio_playlist.cc
@@ -48,39 +48,31 @@ AudioPlaylist::AudioPlaylist (Session& session, const XMLNode& node, bool hidden
in_set_state++;
set_state (node);
in_set_state--;
-
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
}
AudioPlaylist::AudioPlaylist (Session& session, string name, bool hidden)
: Playlist (session, name, DataType::AUDIO, hidden)
{
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
-
}
-AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidden)
+AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, string name, bool hidden)
: Playlist (other, name, hidden)
{
- RegionList::const_iterator in_o = other.regions.begin();
+ RegionList::const_iterator in_o = other->regions.begin();
RegionList::iterator in_n = regions.begin();
- while (in_o != other.regions.end()) {
+ while (in_o != other->regions.end()) {
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(*in_o);
// We look only for crossfades which begin with the current region, so we don't get doubles
- for (list<Crossfade *>::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) {
+ for (list<Crossfade *>::const_iterator xfades = other->_crossfades.begin(); xfades != other->_crossfades.end(); ++xfades) {
if ((*xfades)->in() == ar) {
// We found one! Now copy it!
- RegionList::const_iterator out_o = other.regions.begin();
+ RegionList::const_iterator out_o = other->regions.begin();
RegionList::const_iterator out_n = regions.begin();
- while (out_o != other.regions.end()) {
+ while (out_o != other->regions.end()) {
boost::shared_ptr<AudioRegion>ar2 = boost::dynamic_pointer_cast<AudioRegion>(*out_o);
@@ -102,13 +94,9 @@ AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, string name, bool hidd
in_o++;
in_n++;
}
-
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
}
-AudioPlaylist::AudioPlaylist (const AudioPlaylist& other, nframes_t start, nframes_t cnt, string name, bool hidden)
+AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, nframes_t start, nframes_t cnt, string name, bool hidden)
: Playlist (other, start, cnt, name, hidden)
{
/* this constructor does NOT notify others (session) */
@@ -437,8 +425,15 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
/* in, out */
xfade = new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn);
add_crossfade (*xfade);
- xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
- add_crossfade (*xfade);
+
+ if (top_region_at (top->last_frame() - 1) == top) {
+ /*
+ only add a fade out if there is no region on top of the end of 'top' (which
+ would cover it).
+ */
+ xfade = new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut);
+ add_crossfade (*xfade);
+ }
} else {
@@ -666,7 +661,7 @@ AudioPlaylist::destroy_region (boost::shared_ptr<Region> region)
x = xtmp;
}
- region->set_playlist (0);
+ region->set_playlist (boost::shared_ptr<Playlist>());
}
for (c = _crossfades.begin(); c != _crossfades.end(); ) {
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index f2681aceba..b0ac7a4bd7 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -17,11 +17,14 @@
$Id$
*/
-#include <pbd/error.h>
+
#include <sigc++/retype.h>
#include <sigc++/retype_return.h>
#include <sigc++/bind.h>
+#include <pbd/error.h>
+#include <pbd/enumwriter.h>
+
#include <ardour/audio_track.h>
#include <ardour/audio_diskstream.h>
#include <ardour/session.h>
@@ -32,6 +35,7 @@
#include <ardour/route_group_specialized.h>
#include <ardour/insert.h>
#include <ardour/audioplaylist.h>
+#include <ardour/playlist_factory.h>
#include <ardour/panner.h>
#include <ardour/utils.h>
#include <ardour/buffer_set.h>
@@ -235,14 +239,7 @@ AudioTrack::_set_state (const XMLNode& node, bool call_base)
}
if ((prop = node.property (X_("mode"))) != 0) {
- if (prop->value() == X_("normal")) {
- _mode = Normal;
- } else if (prop->value() == X_("destructive")) {
- _mode = Destructive;
- } else {
- warning << string_compose ("unknown audio track mode \"%1\" seen and ignored", prop->value()) << endmsg;
- _mode = Normal;
- }
+ _mode = TrackMode (string_2_enum (prop->value(), _mode));
} else {
_mode = Normal;
}
@@ -311,8 +308,7 @@ AudioTrack::state(bool full_state)
freeze_node = new XMLNode (X_("freeze-info"));
freeze_node->add_property ("playlist", _freeze_record.playlist->name());
- snprintf (buf, sizeof (buf), "%d", (int) _freeze_record.state);
- freeze_node->add_property ("state", buf);
+ freeze_node->add_property ("state", enum_2_string (_freeze_record.state));
for (vector<FreezeRecordInsertInfo*>::iterator i = _freeze_record.insert_info.begin(); i != _freeze_record.insert_info.end(); ++i) {
inode = new XMLNode (X_("insert"));
@@ -329,15 +325,8 @@ AudioTrack::state(bool full_state)
/* Alignment: act as a proxy for the diskstream */
XMLNode* align_node = new XMLNode (X_("alignment"));
- switch (_diskstream->alignment_style()) {
- case ExistingMaterial:
- snprintf (buf, sizeof (buf), X_("existing"));
- break;
- case CaptureTime:
- snprintf (buf, sizeof (buf), X_("capture"));
- break;
- }
- align_node->add_property (X_("style"), buf);
+ AlignStyle as = _diskstream->alignment_style ();
+ align_node->add_property (X_("style"), enum_2_string (as));
root.add_child_nocopy (*align_node);
XMLNode* remote_control_node = new XMLNode (X_("remote_control"));
@@ -345,14 +334,7 @@ AudioTrack::state(bool full_state)
remote_control_node->add_property (X_("id"), buf);
root.add_child_nocopy (*remote_control_node);
- switch (_mode) {
- case Normal:
- root.add_property (X_("mode"), X_("normal"));
- break;
- case Destructive:
- root.add_property (X_("mode"), X_("destructive"));
- break;
- }
+ root.add_property (X_("mode"), enum_2_string (_mode));
/* we don't return diskstream state because we don't
own the diskstream exclusively. control of the diskstream
@@ -395,18 +377,18 @@ AudioTrack::set_state_part_two ()
_freeze_record.insert_info.clear ();
if ((prop = fnode->property (X_("playlist"))) != 0) {
- Playlist* pl = _session.playlist_by_name (prop->value());
+ boost::shared_ptr<Playlist> pl = _session.playlist_by_name (prop->value());
if (pl) {
- _freeze_record.playlist = dynamic_cast<AudioPlaylist*> (pl);
+ _freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
} else {
- _freeze_record.playlist = 0;
+ _freeze_record.playlist.reset ();
_freeze_record.state = NoFreeze;
return;
}
}
if ((prop = fnode->property (X_("state"))) != 0) {
- _freeze_record.state = (FreezeState) atoi (prop->value().c_str());
+ _freeze_record.state = FreezeState (string_2_enum (prop->value(), _freeze_record.state));
}
XMLNodeConstIterator citer;
@@ -433,11 +415,21 @@ AudioTrack::set_state_part_two ()
if ((fnode = find_named_node (*pending_state, X_("alignment"))) != 0) {
if ((prop = fnode->property (X_("style"))) != 0) {
- if (prop->value() == "existing") {
- _diskstream->set_persistent_align_style (ExistingMaterial);
- } else if (prop->value() == "capture") {
- _diskstream->set_persistent_align_style (CaptureTime);
+
+ /* fix for older sessions from before EnumWriter */
+
+ string pstr;
+
+ if (prop->value() == "capture") {
+ pstr = "CaptureTime";
+ } else if (prop->value() == "existing") {
+ pstr = "ExistingMaterial";
+ } else {
+ pstr = prop->value();
}
+
+ AlignStyle as = AlignStyle (string_2_enum (pstr, as));
+ _diskstream->set_persistent_align_style (as);
}
}
return;
@@ -669,8 +661,7 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
Glib::RWLock::ReaderLock rlock (redirect_lock);
- // FIXME
- AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(diskstream->playlist());
+ boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
assert(apl);
if (apl->read (buffers.get_audio(nframes).data(nframes),
@@ -777,12 +768,12 @@ AudioTrack::freeze (InterThreadInfo& itt)
{
vector<boost::shared_ptr<Source> > srcs;
string new_playlist_name;
- Playlist* new_playlist;
+ boost::shared_ptr<Playlist> new_playlist;
string dir;
string region_name;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
- if ((_freeze_record.playlist = dynamic_cast<AudioPlaylist*>(diskstream->playlist())) == 0) {
+ if ((_freeze_record.playlist = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist())) == 0) {
return;
}
@@ -839,7 +830,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
}
}
- new_playlist = new AudioPlaylist (_session, new_playlist_name, false);
+ new_playlist = PlaylistFactory::create (_session, new_playlist_name, false);
region_name = new_playlist_name;
/* create a new region from all filesources, keep it private */
@@ -854,7 +845,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
new_playlist->set_frozen (true);
region->set_locked (true);
- diskstream->use_playlist (dynamic_cast<AudioPlaylist*>(new_playlist));
+ diskstream->use_playlist (boost::dynamic_pointer_cast<AudioPlaylist>(new_playlist));
diskstream->set_record_enabled (false);
_freeze_record.state = Frozen;
@@ -886,7 +877,7 @@ AudioTrack::unfreeze ()
}
}
- _freeze_record.playlist = 0;
+ _freeze_record.playlist.reset ();
}
_freeze_record.state = UnFrozen;
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index b0cd64c8d1..be070c74e6 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -49,6 +49,12 @@ using namespace PBD;
gint AudioEngine::m_meter_exit;
+static void
+ardour_jack_error (const char* msg)
+{
+ error << "JACK: " << msg << endmsg;
+}
+
AudioEngine::AudioEngine (string client_name)
: ports (new Ports)
{
@@ -80,11 +86,16 @@ AudioEngine::AudioEngine (string client_name)
AudioEngine::~AudioEngine ()
{
- if (_running) {
- jack_client_close (_jack);
+ {
+ Glib::Mutex::Lock tm (_process_lock);
+ session_removed.signal ();
+
+ if (_running) {
+ jack_client_close (_jack);
+ }
+
+ stop_metering_thread ();
}
-
- stop_metering_thread ();
}
void
@@ -152,11 +163,18 @@ AudioEngine::start ()
}
int
-AudioEngine::stop ()
+AudioEngine::stop (bool forever)
{
if (_running) {
_running = false;
- jack_deactivate (_jack);
+ if (forever) {
+ jack_client_t* foo = _jack;
+ _jack = 0;
+ jack_client_close (foo);
+ stop_metering_thread ();
+ } else {
+ jack_deactivate (_jack);
+ }
Stopped(); /* EMIT SIGNAL */
}
@@ -164,7 +182,6 @@ AudioEngine::stop ()
}
-
bool
AudioEngine::get_sync_offset (nframes_t& offset) const
{
@@ -196,7 +213,7 @@ void
AudioEngine::jack_timebase_callback (jack_transport_state_t state, nframes_t nframes,
jack_position_t* pos, int new_position)
{
- if (session && session->synced_to_jack()) {
+ if (_jack && session && session->synced_to_jack()) {
session->jack_timebase_callback (state, nframes, pos, new_position);
}
}
@@ -210,7 +227,7 @@ AudioEngine::_jack_sync_callback (jack_transport_state_t state, jack_position_t*
int
AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos)
{
- if (session) {
+ if (_jack && session) {
return session->jack_sync_callback (state, pos);
} else {
return true;
@@ -220,14 +237,20 @@ AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t*
int
AudioEngine::_xrun_callback (void *arg)
{
- static_cast<AudioEngine *>(arg)->Xrun (); /* EMIT SIGNAL */
+ AudioEngine* ae = static_cast<AudioEngine*> (arg);
+ if (ae->jack()) {
+ ae->Xrun (); /* EMIT SIGNAL */
+ }
return 0;
}
int
AudioEngine::_graph_order_callback (void *arg)
{
- static_cast<AudioEngine *>(arg)->GraphReordered (); /* EMIT SIGNAL */
+ AudioEngine* ae = static_cast<AudioEngine*> (arg);
+ if (ae->jack()) {
+ ae->GraphReordered (); /* EMIT SIGNAL */
+ }
return 0;
}
@@ -381,9 +404,9 @@ AudioEngine::stop_metering_thread ()
{
if (m_meter_thread) {
g_atomic_int_set (&m_meter_exit, 1);
+ m_meter_thread->join ();
+ m_meter_thread = 0;
}
- m_meter_thread->join ();
- m_meter_thread = 0;
}
void
@@ -397,8 +420,11 @@ AudioEngine::start_metering_thread ()
void
AudioEngine::meter_thread ()
{
- while (g_atomic_int_get(&m_meter_exit) != true) {
+ while (true) {
Glib::usleep (10000); /* 1/100th sec interval */
+ if (g_atomic_int_get(&m_meter_exit)) {
+ break;
+ }
IO::update_meters ();
}
}
@@ -406,8 +432,26 @@ AudioEngine::meter_thread ()
void
AudioEngine::set_session (Session *s)
{
+ Glib::Mutex::Lock pl (_process_lock);
+
if (!session) {
+
session = s;
+
+ nframes_t blocksize = jack_get_buffer_size (_jack);
+
+ /* page in as much of the session process code as we
+ can before we really start running.
+ */
+
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
+ session->process (blocksize);
}
}
@@ -421,16 +465,13 @@ AudioEngine::remove_session ()
if (session) {
session_remove_pending = true;
session_removed.wait(_process_lock);
- }
+ }
} else {
-
session = 0;
-
}
remove_all_ports ();
-
}
Port *
@@ -468,8 +509,6 @@ AudioEngine::register_input_port (DataType type, const string& portname)
return newport;
} else {
-
- _process_lock.unlock();
throw PortRegistrationFailure();
}
@@ -512,8 +551,6 @@ AudioEngine::register_output_port (DataType type, const string& portname)
return newport;
} else {
-
- _process_lock.unlock();
throw PortRegistrationFailure ();
}
@@ -719,11 +756,9 @@ AudioEngine::get_ports (const string& port_name_pattern, const string& type_name
void
AudioEngine::halted (void *arg)
{
- AudioEngine *ae = reinterpret_cast<AudioEngine *> (arg);
+ AudioEngine* ae = static_cast<AudioEngine *> (arg);
ae->_running = false;
- ae->_jack = 0;
-
ae->_buffer_size = 0;
ae->_frame_rate = 0;
@@ -1006,6 +1041,8 @@ AudioEngine::connect_to_jack (string client_name)
if (status & JackNameNotUnique) {
jack_client_name = jack_get_client_name (_jack);
}
+
+ jack_set_error_function (ardour_jack_error);
return 0;
}
@@ -1033,9 +1070,7 @@ AudioEngine::disconnect_from_jack ()
return 0;
}
- if (jack_client_close (_jack)) {
- error << _("cannot shutdown connection to JACK") << endmsg;
- }
+ jack_client_close (_jack);
_buffer_size = 0;
_frame_rate = 0;
diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc
index 16cb990ec2..af41094748 100644
--- a/libs/ardour/audiofilesource.cc
+++ b/libs/ardour/audiofilesource.cc
@@ -22,12 +22,14 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
#include <pbd/mountpoint.h>
#include <pbd/pathscanner.h>
#include <pbd/stl_delete.h>
#include <pbd/strsplit.h>
+#include <pbd/enumwriter.h>
#include <sndfile.h>
@@ -193,9 +195,7 @@ XMLNode&
AudioFileSource::get_state ()
{
XMLNode& root (AudioSource::get_state());
- char buf[16];
- snprintf (buf, sizeof (buf), "0x%x", (int)_flags);
- root.add_property ("flags", buf);
+ root.add_property ("flags", enum_2_string (_flags));
return root;
}
@@ -210,9 +210,7 @@ AudioFileSource::set_state (const XMLNode& node)
if ((prop = node.property (X_("flags"))) != 0) {
- int ival;
- sscanf (prop->value().c_str(), "0x%x", &ival);
- _flags = Flag (ival);
+ _flags = Flag (string_2_enum (prop->value(), _flags));
} else {
@@ -257,7 +255,7 @@ AudioFileSource::mark_streaming_write_completed ()
if (_peaks_built || pending_peak_builds.empty()) {
_peaks_built = true;
- PeaksReady (); /* EMIT SIGNAL */
+ PeaksReady (); /* EMIT SIGNAL */
}
}
@@ -287,9 +285,11 @@ AudioFileSource::move_to_trash (const string trash_dir_name)
stick it in the `trash_dir_name' directory
on whichever filesystem it was already on.
*/
-
+
newpath = Glib::path_get_dirname (_path);
- newpath = Glib::path_get_dirname (newpath);
+ newpath = Glib::path_get_dirname (newpath);
+
+ cerr << "from " << _path << " dead dir looks like " << newpath << endl;
newpath += '/';
newpath += trash_dir_name;
@@ -522,7 +522,7 @@ AudioFileSource::set_name (string newname, bool destructive)
}
if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
- error << string_compose (_("cannot rename audio file for %1 to %2"), _name, newpath) << endmsg;
+ error << string_compose (_("cannot rename audio file %1 to %2"), _name, newpath) << endmsg;
return -1;
}
@@ -556,3 +556,26 @@ AudioFileSource::setup_peakfile ()
return 0;
}
}
+
+bool
+AudioFileSource::safe_file_extension(string file)
+{
+ return !(file.rfind(".wav") == string::npos &&
+ file.rfind(".aiff")== string::npos &&
+ file.rfind(".aif") == string::npos &&
+ file.rfind(".snd") == string::npos &&
+ file.rfind(".au") == string::npos &&
+ file.rfind(".raw") == string::npos &&
+ file.rfind(".sf") == string::npos &&
+ file.rfind(".cdr") == string::npos &&
+ file.rfind(".smp") == string::npos &&
+ file.rfind(".maud")== string::npos &&
+ file.rfind(".vwe") == string::npos &&
+ file.rfind(".paf") == string::npos &&
+#ifdef HAVE_COREAUDIO
+ file.rfind(".mp3") == string::npos &&
+ file.rfind(".aac") == string::npos &&
+ file.rfind(".mp4") == string::npos &&
+#endif // HAVE_COREAUDIO
+ file.rfind(".voc") == string::npos);
+}
diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc
index 939f9c02dd..8b533deda3 100644
--- a/libs/ardour/audioregion.cc
+++ b/libs/ardour/audioregion.cc
@@ -32,6 +32,7 @@
#include <pbd/basename.h>
#include <pbd/xml++.h>
#include <pbd/stacktrace.h>
+#include <pbd/enumwriter.h>
#include <ardour/audioregion.h>
#include <ardour/session.h>
@@ -482,8 +483,8 @@ AudioRegion::state (bool full)
char buf2[64];
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof (buf), "0x%x", (int) _flags);
- node.add_property ("flags", buf);
+ node.add_property ("flags", enum_2_string (_flags));
+
snprintf (buf, sizeof(buf), "%.12g", _scale_amplitude);
node.add_property ("scale-gain", buf);
@@ -564,7 +565,9 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen
uint32_t old_flags = _flags;
if ((prop = node.property ("flags")) != 0) {
- _flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
+ _flags = Flag (string_2_enum (prop->value(), _flags));
+
+ //_flags = Flag (strtol (prop->value().c_str(), (char **) 0, 16));
_flags = Flag (_flags & ~Region::LeftOfSplit);
_flags = Flag (_flags & ~Region::RightOfSplit);
@@ -662,49 +665,49 @@ AudioRegion::set_fade_in (FadeShape shape, nframes_t len)
switch (shape) {
case Linear:
- _fade_in.add (0.0, 0.0);
- _fade_in.add (len, 1.0);
+ _fade_in.fast_simple_add (0.0, 0.0);
+ _fade_in.fast_simple_add (len, 1.0);
break;
case Fast:
- _fade_in.add (0, 0);
- _fade_in.add (len * 0.389401, 0.0333333);
- _fade_in.add (len * 0.629032, 0.0861111);
- _fade_in.add (len * 0.829493, 0.233333);
- _fade_in.add (len * 0.9447, 0.483333);
- _fade_in.add (len * 0.976959, 0.697222);
- _fade_in.add (len, 1);
+ _fade_in.fast_simple_add (0, 0);
+ _fade_in.fast_simple_add (len * 0.389401, 0.0333333);
+ _fade_in.fast_simple_add (len * 0.629032, 0.0861111);
+ _fade_in.fast_simple_add (len * 0.829493, 0.233333);
+ _fade_in.fast_simple_add (len * 0.9447, 0.483333);
+ _fade_in.fast_simple_add (len * 0.976959, 0.697222);
+ _fade_in.fast_simple_add (len, 1);
break;
case Slow:
- _fade_in.add (0, 0);
- _fade_in.add (len * 0.0207373, 0.197222);
- _fade_in.add (len * 0.0645161, 0.525);
- _fade_in.add (len * 0.152074, 0.802778);
- _fade_in.add (len * 0.276498, 0.919444);
- _fade_in.add (len * 0.481567, 0.980556);
- _fade_in.add (len * 0.767281, 1);
- _fade_in.add (len, 1);
+ _fade_in.fast_simple_add (0, 0);
+ _fade_in.fast_simple_add (len * 0.0207373, 0.197222);
+ _fade_in.fast_simple_add (len * 0.0645161, 0.525);
+ _fade_in.fast_simple_add (len * 0.152074, 0.802778);
+ _fade_in.fast_simple_add (len * 0.276498, 0.919444);
+ _fade_in.fast_simple_add (len * 0.481567, 0.980556);
+ _fade_in.fast_simple_add (len * 0.767281, 1);
+ _fade_in.fast_simple_add (len, 1);
break;
case LogA:
- _fade_in.add (0, 0);
- _fade_in.add (len * 0.0737327, 0.308333);
- _fade_in.add (len * 0.246544, 0.658333);
- _fade_in.add (len * 0.470046, 0.886111);
- _fade_in.add (len * 0.652074, 0.972222);
- _fade_in.add (len * 0.771889, 0.988889);
- _fade_in.add (len, 1);
+ _fade_in.fast_simple_add (0, 0);
+ _fade_in.fast_simple_add (len * 0.0737327, 0.308333);
+ _fade_in.fast_simple_add (len * 0.246544, 0.658333);
+ _fade_in.fast_simple_add (len * 0.470046, 0.886111);
+ _fade_in.fast_simple_add (len * 0.652074, 0.972222);
+ _fade_in.fast_simple_add (len * 0.771889, 0.988889);
+ _fade_in.fast_simple_add (len, 1);
break;
case LogB:
- _fade_in.add (0, 0);
- _fade_in.add (len * 0.304147, 0.0694444);
- _fade_in.add (len * 0.529954, 0.152778);
- _fade_in.add (len * 0.725806, 0.333333);
- _fade_in.add (len * 0.847926, 0.558333);
- _fade_in.add (len * 0.919355, 0.730556);
- _fade_in.add (len, 1);
+ _fade_in.fast_simple_add (0, 0);
+ _fade_in.fast_simple_add (len * 0.304147, 0.0694444);
+ _fade_in.fast_simple_add (len * 0.529954, 0.152778);
+ _fade_in.fast_simple_add (len * 0.725806, 0.333333);
+ _fade_in.fast_simple_add (len * 0.847926, 0.558333);
+ _fade_in.fast_simple_add (len * 0.919355, 0.730556);
+ _fade_in.fast_simple_add (len, 1);
break;
}
@@ -722,47 +725,47 @@ AudioRegion::set_fade_out (FadeShape shape, nframes_t len)
switch (shape) {
case Fast:
- _fade_out.add (len * 0, 1);
- _fade_out.add (len * 0.023041, 0.697222);
- _fade_out.add (len * 0.0553, 0.483333);
- _fade_out.add (len * 0.170507, 0.233333);
- _fade_out.add (len * 0.370968, 0.0861111);
- _fade_out.add (len * 0.610599, 0.0333333);
- _fade_out.add (len * 1, 0);
+ _fade_out.fast_simple_add (len * 0, 1);
+ _fade_out.fast_simple_add (len * 0.023041, 0.697222);
+ _fade_out.fast_simple_add (len * 0.0553, 0.483333);
+ _fade_out.fast_simple_add (len * 0.170507, 0.233333);
+ _fade_out.fast_simple_add (len * 0.370968, 0.0861111);
+ _fade_out.fast_simple_add (len * 0.610599, 0.0333333);
+ _fade_out.fast_simple_add (len * 1, 0);
break;
case LogA:
- _fade_out.add (len * 0, 1);
- _fade_out.add (len * 0.228111, 0.988889);
- _fade_out.add (len * 0.347926, 0.972222);
- _fade_out.add (len * 0.529954, 0.886111);
- _fade_out.add (len * 0.753456, 0.658333);
- _fade_out.add (len * 0.9262673, 0.308333);
- _fade_out.add (len * 1, 0);
+ _fade_out.fast_simple_add (len * 0, 1);
+ _fade_out.fast_simple_add (len * 0.228111, 0.988889);
+ _fade_out.fast_simple_add (len * 0.347926, 0.972222);
+ _fade_out.fast_simple_add (len * 0.529954, 0.886111);
+ _fade_out.fast_simple_add (len * 0.753456, 0.658333);
+ _fade_out.fast_simple_add (len * 0.9262673, 0.308333);
+ _fade_out.fast_simple_add (len * 1, 0);
break;
case Slow:
- _fade_out.add (len * 0, 1);
- _fade_out.add (len * 0.305556, 1);
- _fade_out.add (len * 0.548611, 0.991736);
- _fade_out.add (len * 0.759259, 0.931129);
- _fade_out.add (len * 0.918981, 0.68595);
- _fade_out.add (len * 0.976852, 0.22865);
- _fade_out.add (len * 1, 0);
+ _fade_out.fast_simple_add (len * 0, 1);
+ _fade_out.fast_simple_add (len * 0.305556, 1);
+ _fade_out.fast_simple_add (len * 0.548611, 0.991736);
+ _fade_out.fast_simple_add (len * 0.759259, 0.931129);
+ _fade_out.fast_simple_add (len * 0.918981, 0.68595);
+ _fade_out.fast_simple_add (len * 0.976852, 0.22865);
+ _fade_out.fast_simple_add (len * 1, 0);
break;
case LogB:
- _fade_out.add (len * 0, 1);
- _fade_out.add (len * 0.080645, 0.730556);
- _fade_out.add (len * 0.277778, 0.289256);
- _fade_out.add (len * 0.470046, 0.152778);
- _fade_out.add (len * 0.695853, 0.0694444);
- _fade_out.add (len * 1, 0);
+ _fade_out.fast_simple_add (len * 0, 1);
+ _fade_out.fast_simple_add (len * 0.080645, 0.730556);
+ _fade_out.fast_simple_add (len * 0.277778, 0.289256);
+ _fade_out.fast_simple_add (len * 0.470046, 0.152778);
+ _fade_out.fast_simple_add (len * 0.695853, 0.0694444);
+ _fade_out.fast_simple_add (len * 1, 0);
break;
case Linear:
- _fade_out.add (len * 0, 1);
- _fade_out.add (len * 1, 0);
+ _fade_out.fast_simple_add (len * 0, 1);
+ _fade_out.fast_simple_add (len * 1, 0);
break;
}
@@ -851,8 +854,8 @@ AudioRegion::set_default_envelope ()
{
_envelope.freeze ();
_envelope.clear ();
- _envelope.add (0, 1.0f);
- _envelope.add (_length, 1.0f);
+ _envelope.fast_simple_add (0, 1.0f);
+ _envelope.fast_simple_add (_length, 1.0f);
_envelope.thaw ();
}
@@ -996,12 +999,14 @@ AudioRegion::exportme (Session& session, AudioExportSpecification& spec)
void
AudioRegion::set_scale_amplitude (gain_t g)
{
+ boost::shared_ptr<Playlist> pl (playlist());
+
_scale_amplitude = g;
/* tell the diskstream we're in */
-
- if (_playlist) {
- _playlist->Modified();
+
+ if (pl) {
+ pl->Modified();
}
/* tell everybody else */
@@ -1068,8 +1073,10 @@ AudioRegion::normalize_to (float target_dB)
/* tell the diskstream we're in */
- if (_playlist) {
- _playlist->Modified();
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (pl) {
+ pl->Modified();
}
/* tell everybody else */
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index 93165b7fe4..203590a4e1 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -35,6 +35,7 @@
#include <pbd/pthread_utils.h>
#include <ardour/audiosource.h>
+#include <ardour/cycle_timer.h>
#include "i18n.h"
@@ -59,6 +60,7 @@ AudioSource::AudioSource (Session& s, string name)
}
_peaks_built = false;
+ _peak_byte_max = 0;
next_peak_clear_should_notify = true;
_read_data_count = 0;
_write_data_count = 0;
@@ -72,6 +74,7 @@ AudioSource::AudioSource (Session& s, const XMLNode& node)
}
_peaks_built = false;
+ _peak_byte_max = 0;
next_peak_clear_should_notify = true;
_read_data_count = 0;
_write_data_count = 0;
@@ -251,13 +254,13 @@ AudioSource::stop_peak_thread ()
}
void
-AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source)
+AudioSource::queue_for_peaks (boost::shared_ptr<AudioSource> source, bool notify)
{
if (have_peak_thread) {
Glib::Mutex::Lock lm (*pending_peak_sources_lock);
- source->next_peak_clear_should_notify = true;
+ source->next_peak_clear_should_notify = notify;
if (find (pending_peak_sources.begin(),
pending_peak_sources.end(),
@@ -384,8 +387,10 @@ AudioSource::initialize_peakfile (bool newfile, string audio_path)
if (!err && stat_file.st_mtime > statbuf.st_mtime){
_peaks_built = false;
+ _peak_byte_max = 0;
} else {
_peaks_built = true;
+ _peak_byte_max = statbuf.st_size;
}
}
}
@@ -431,7 +436,8 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
expected_peaks = (cnt / (double) frames_per_peak);
scale = npeaks/expected_peaks;
-#if 0
+#undef DEBUG_READ_PEAKS
+#ifdef DEBUG_READ_PEAKS
cerr << "======>RP: npeaks = " << npeaks
<< " start = " << start
<< " cnt = " << cnt
@@ -457,8 +463,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
if (npeaks == cnt) {
+#ifdef DEBUG_READ_PEAKS
cerr << "RAW DATA\n";
-
+#endif
/* no scaling at all, just get the sample data and duplicate it for
both max and min peak values.
*/
@@ -485,12 +492,14 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
/* open, read, close */
- if ((peakfile = ::open (peakpath.c_str(), O_RDWR|O_CREAT, 0664)) < 0) {
+ if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return -1;
}
- // cerr << "DIRECT PEAKS\n";
+#ifdef DEBUG_READ_PEAKS
+ cerr << "DIRECT PEAKS\n";
+#endif
nread = ::pread (peakfile, peaks, sizeof (PeakData)* npeaks, first_peak_byte);
close (peakfile);
@@ -523,8 +532,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
if (scale < 1.0) {
- // cerr << "DOWNSAMPLE\n";
-
+#ifdef DEBUG_READ_PEAKS
+ cerr << "DOWNSAMPLE\n";
+#endif
/* the caller wants:
- more frames-per-peak (lower resolution) than the peakfile, or to put it another way,
@@ -535,7 +545,7 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
to avoid confusion, I'll refer to the requested peaks as visual_peaks and the peakfile peaks as stored_peaks
*/
- const uint32_t chunksize = (uint32_t) min (expected_peaks, 4096.0);
+ const uint32_t chunksize = (uint32_t) min (expected_peaks, 65536.0);
staging = new PeakData[chunksize];
@@ -556,7 +566,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_RDWR|O_CREAT, 0664)) < 0) {
+ if ((peakfile = ::open (peakpath.c_str(), O_RDONLY, 0664)) < 0) {
error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
return 0;
}
@@ -569,10 +579,15 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
tnp = min ((_length/frames_per_peak - current_stored_peak), (nframes_t) expected_peaks);
to_read = min (chunksize, tnp);
- off_t fend = lseek (peakfile, 0, SEEK_END);
+#ifdef DEBUG_READ_PEAKS
+ cerr << "read " << sizeof (PeakData) * to_read << " from peakfile @ " << start_byte << endl;
+#endif
if ((nread = ::pread (peakfile, staging, sizeof (PeakData) * to_read, start_byte))
!= sizeof (PeakData) * to_read) {
+
+ off_t fend = lseek (peakfile, 0, SEEK_END);
+
cerr << "AudioSource["
<< _name
<< "]: cannot read peak data from peakfile ("
@@ -589,11 +604,11 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
<< endl;
goto out;
}
-
+
i = 0;
stored_peaks_read = nread / sizeof(PeakData);
}
-
+
xmax = -1.0;
xmin = 1.0;
@@ -624,8 +639,9 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
} else {
- // cerr << "UPSAMPLE\n";
-
+#ifdef DEBUG_READ_PEAKS
+ cerr << "UPSAMPLE\n";
+#endif
/* the caller wants
- less frames-per-peak (more resolution)
@@ -704,6 +720,10 @@ AudioSource::read_peaks (PeakData *peaks, nframes_t npeaks, nframes_t start, nfr
delete [] raw_staging;
}
+#ifdef DEBUG_READ_PEAKS
+ cerr << "RP DONE\n";
+#endif
+
return ret;
}
@@ -757,6 +777,7 @@ AudioSource::build_peaks ()
}
if (pr_signal) {
+ truncate_peakfile();
PeaksReady (); /* EMIT SIGNAL */
}
}
@@ -777,6 +798,8 @@ AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
off_t first_peak_byte;
int peakfile = -1;
int ret = -1;
+ off_t target_length;
+ off_t endpos;
#ifdef DEBUG_PEAK_BUILD
cerr << pthread_self() << ": " << _name << ": building peaks for " << first_frame << " to " << first_frame + cnt - 1 << endl;
@@ -828,11 +851,32 @@ AudioSource::do_build_peak (nframes_t first_frame, nframes_t cnt)
cnt -= frames_read;
}
+#define BLOCKSIZE (128 * 1024)
+
+ /* on some filesystems (ext3, at least) this helps to reduce fragmentation of
+ the peakfiles. its not guaranteed to do so, and even on ext3 (as of december 2006)
+ it does not cause single-extent allocation even for peakfiles of
+ less than BLOCKSIZE bytes. only call ftruncate if we'll make the file larger.
+ */
+ endpos = lseek (peakfile, 0, SEEK_END);
+
+ target_length = BLOCKSIZE * ((first_peak_byte + BLOCKSIZE + 1) / BLOCKSIZE);
+
+ if (endpos < target_length) {
+ // XXX - we really shouldn't be doing this for destructive source peaks
+ ftruncate (peakfile, target_length);
+ //cerr << "do build TRUNC: " << peakpath << " " << target_length << endl;
+
+ /* error doesn't actually matter though, so continue on without testing */
+ }
+
if (::pwrite (peakfile, peakbuf, sizeof (PeakData) * peaki, first_peak_byte) != (ssize_t) (sizeof (PeakData) * peaki)) {
error << string_compose(_("%1: could not write peak file data (%2)"), _name, strerror (errno)) << endmsg;
goto out;
}
+ _peak_byte_max = max(_peak_byte_max, (off_t) (first_peak_byte + sizeof(PeakData)*peaki));
+
ret = 0;
out:
@@ -850,7 +894,28 @@ AudioSource::build_peaks_from_scratch ()
next_peak_clear_should_notify = true;
pending_peak_builds.push_back (new PeakBuildRecord (0, _length));
- queue_for_peaks (shared_from_this());
+ queue_for_peaks (shared_from_this(), true);
+}
+
+void
+AudioSource::truncate_peakfile ()
+{
+ int peakfile = -1;
+
+ /* truncate the peakfile down to its natural length if necessary */
+
+ if ((peakfile = ::open (peakpath.c_str(), O_RDWR)) >= 0) {
+ off_t end = lseek (peakfile, 0, SEEK_END);
+
+ if (end > _peak_byte_max) {
+ ftruncate(peakfile, _peak_byte_max);
+ //cerr << "truncated " << peakpath << " to " << _peak_byte_max << " bytes" << endl;
+ }
+ else {
+ //cerr << "NOT truncated " << peakpath << " to " << _peak_byte_max << " end " << end << endl;
+ }
+ close (peakfile);
+ }
}
bool
@@ -872,26 +937,19 @@ AudioSource::file_changed (string path)
nframes_t
AudioSource::available_peaks (double zoom_factor) const
{
- int peakfile;
off_t end;
if (zoom_factor < frames_per_peak) {
return length(); // peak data will come from the audio file
}
- /* peak data comes from peakfile */
-
- if ((peakfile = ::open (peakpath.c_str(), O_RDONLY)) < 0) {
- error << string_compose(_("AudioSource: cannot open peakpath \"%1\" (%2)"), peakpath, strerror (errno)) << endmsg;
- return 0;
- }
-
- {
- Glib::Mutex::Lock lm (_lock);
- end = lseek (peakfile, 0, SEEK_END);
- }
+ /* peak data comes from peakfile, but the filesize might not represent
+ the valid data due to ftruncate optimizations, so use _peak_byte_max state.
+ XXX - there might be some atomicity issues here, we should probably add a lock,
+ but _peak_byte_max only monotonically increases after initialization.
+ */
- close (peakfile);
+ end = _peak_byte_max;
return (end/sizeof(PeakData)) * frames_per_peak;
}
diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc
index 34cf5637b6..7bbc4cd0ba 100644
--- a/libs/ardour/auditioner.cc
+++ b/libs/ardour/auditioner.cc
@@ -24,6 +24,7 @@
#include <ardour/audio_diskstream.h>
#include <ardour/audioregion.h>
+#include <ardour/audioengine.h>
#include <ardour/route.h>
#include <ardour/session.h>
#include <ardour/auditioner.h>
@@ -43,8 +44,17 @@ Auditioner::Auditioner (Session& s)
{
string left = Config->get_auditioner_output_left();
string right = Config->get_auditioner_output_right();
+
+ if (left == "default") {
+ left = _session.engine().get_nth_physical_output (DataType::AUDIO, 0);
+ }
+
+ if (right == "default") {
+ right = _session.engine().get_nth_physical_output (DataType::AUDIO, 1);
+ }
if ((left.length() == 0) && (right.length() == 0)) {
+ warning << _("no outputs available for auditioner - manual connection required") << endmsg;
return;
}
@@ -77,7 +87,7 @@ AudioPlaylist&
Auditioner::prepare_playlist ()
{
// FIXME auditioner is still audio-only
- AudioPlaylist* const apl = dynamic_cast<AudioPlaylist*>(_diskstream->playlist());
+ boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(_diskstream->playlist());
assert(apl);
apl->clear ();
@@ -184,18 +194,34 @@ Auditioner::play_audition (nframes_t nframes)
void
Auditioner::output_changed (IOChange change, void* src)
{
+ string phys;
+
if (change & ConnectionsChanged) {
const char ** connections;
connections = output (0)->get_connections ();
if (connections) {
- Config->set_auditioner_output_left (connections[0]);
+ phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0);
+ if (phys != connections[0]) {
+ Config->set_auditioner_output_left (connections[0]);
+ } else {
+ Config->set_auditioner_output_left ("default");
+ }
free (connections);
+ } else {
+ Config->set_auditioner_output_left ("");
}
connections = output (1)->get_connections ();
if (connections) {
- Config->set_auditioner_output_right (connections[0]);
+ phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 1);
+ if (phys != connections[0]) {
+ Config->set_auditioner_output_right (connections[0]);
+ } else {
+ Config->set_auditioner_output_right ("default");
+ }
free (connections);
+ } else {
+ Config->set_auditioner_output_right ("");
}
}
}
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc
index 5cc2f50e38..af6fffdeb9 100644
--- a/libs/ardour/automation_event.cc
+++ b/libs/ardour/automation_event.cc
@@ -26,7 +26,7 @@
#include <algorithm>
#include <sigc++/bind.h>
#include <ardour/automation_event.h>
-#include <pbd/convert.h>
+#include <pbd/stacktrace.h>
#include "i18n.h"
@@ -37,6 +37,11 @@ using namespace PBD;
sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
+static bool sort_events_by_time (ControlEvent* a, ControlEvent* b)
+{
+ return a->when < b->when;
+}
+
#if 0
static void dumpit (const AutomationList& al, string prefix = "")
{
@@ -50,7 +55,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
AutomationList::AutomationList (double defval)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_state = Off;
_style = Absolute;
@@ -63,13 +68,14 @@ AutomationList::AutomationList (double defval)
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_style = other._style;
min_yval = other.min_yval;
@@ -82,6 +88,7 @@ AutomationList::AutomationList (const AutomationList& other)
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
/* we have to use other point_factory() because
@@ -96,7 +103,7 @@ AutomationList::AutomationList (const AutomationList& other)
AutomationList::AutomationList (const AutomationList& other, double start, double end)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_style = other._style;
min_yval = other.min_yval;
@@ -109,6 +116,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
/* now grab the relevant points, and shift them back if necessary */
@@ -129,7 +137,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
AutomationList::AutomationList (const XMLNode& node)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_touching = false;
min_yval = FLT_MIN;
@@ -141,6 +149,7 @@ AutomationList::AutomationList (const XMLNode& node)
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
set_state (node);
@@ -402,7 +411,7 @@ AutomationList::add (double when, double value)
}
if (insert) {
-
+
events.insert (insertion_point, point_factory (when, value));
reposition_for_rt_add (0);
@@ -512,9 +521,18 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
while (start != end) {
(*start)->when += xdelta;
(*start)->value += ydelta;
+ if (isnan ((*start)->value)) {
+ abort ();
+ }
++start;
}
+ if (!_frozen) {
+ events.sort (sort_events_by_time);
+ } else {
+ sort_pending = true;
+ }
+
mark_dirty ();
}
@@ -522,6 +540,25 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double
}
void
+AutomationList::slide (iterator before, double distance)
+{
+ {
+ Glib::Mutex::Lock lm (lock);
+
+ if (before == events.end()) {
+ return;
+ }
+
+ while (before != events.end()) {
+ (*before)->when += distance;
+ ++before;
+ }
+ }
+
+ maybe_signal_changed ();
+}
+
+void
AutomationList::modify (iterator iter, double when, double val)
{
/* note: we assume higher level logic is in place to avoid this
@@ -531,11 +568,23 @@ AutomationList::modify (iterator iter, double when, double val)
{
Glib::Mutex::Lock lm (lock);
+
(*iter)->when = when;
(*iter)->value = val;
+
+ if (isnan (val)) {
+ abort ();
+ }
+
+ if (!_frozen) {
+ events.sort (sort_events_by_time);
+ } else {
+ sort_pending = true;
+ }
+
mark_dirty ();
}
-
+
maybe_signal_changed ();
}
@@ -576,13 +625,31 @@ AutomationList::control_points_adjacent (double xval)
void
AutomationList::freeze ()
{
- _frozen = true;
+ _frozen++;
}
void
AutomationList::thaw ()
{
- _frozen = false;
+ if (_frozen == 0) {
+ PBD::stacktrace (cerr);
+ fatal << string_compose (_("programming error: %1"), X_("AutomationList::thaw() called while not frozen")) << endmsg;
+ /*NOTREACHED*/
+ }
+
+ if (--_frozen > 0) {
+ return;
+ }
+
+ {
+ Glib::Mutex::Lock lm (lock);
+
+ if (sort_pending) {
+ events.sort (sort_events_by_time);
+ sort_pending = false;
+ }
+ }
+
if (changed_when_thawed) {
StateChanged(); /* EMIT SIGNAL */
}
@@ -1240,6 +1307,7 @@ AutomationList::deserialize_events (const XMLNode& node)
}
thaw ();
+
return 0;
}
@@ -1271,6 +1339,7 @@ AutomationList::set_state (const XMLNode& node)
jack_nframes_t x;
double y;
+ freeze ();
clear ();
for (i = elist.begin(); i != elist.end(); ++i) {
@@ -1287,9 +1356,11 @@ AutomationList::set_state (const XMLNode& node)
}
y = atof (prop->value().c_str());
- add (x, y);
+ fast_simple_add (x, y);
}
+ thaw ();
+
return 0;
}
@@ -1345,7 +1416,7 @@ AutomationList::set_state (const XMLNode& node)
deserialize_events (*(*niter));
}
}
-
+
return 0;
}
diff --git a/libs/ardour/configuration.cc b/libs/ardour/configuration.cc
index e84e92fa26..eb3d879447 100644
--- a/libs/ardour/configuration.cc
+++ b/libs/ardour/configuration.cc
@@ -25,7 +25,6 @@
#include <pbd/xml++.h>
#include <ardour/ardour.h>
-#include <ardour/audio_library.h>
#include <ardour/configuration.h>
#include <ardour/audio_diskstream.h>
#include <ardour/destructive_filesource.h>
@@ -172,7 +171,6 @@ Configuration::get_state ()
}
root->add_child_nocopy (ControlProtocolManager::instance().get_state());
- root->add_child_nocopy (Library->get_state());
return *root;
}
@@ -235,8 +233,6 @@ Configuration::set_state (const XMLNode& root)
} else if (node->name() == ControlProtocolManager::state_node_name) {
_control_protocol_state = new XMLNode (*node);
- } else if (node->name() == AudioLibrary::state_node_name) {
- Library->set_state (*node);
}
}
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
index a715254747..de177d0e3d 100644
--- a/libs/ardour/control_protocol_manager.cc
+++ b/libs/ardour/control_protocol_manager.cc
@@ -154,9 +154,11 @@ ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
static bool protocol_filter (const string& str, void *arg)
{
- /* Not a dotfile, has a prefix before a period, suffix is "so" */
+ /* Not a dotfile, has a prefix before a period, suffix is "so", or "dylib" */
- return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
+ return str[0] != '.'
+ && ((str.length() > 3 && str.find (".so") == (str.length() - 3))
+ || (str.length() > 6 && str.find (".dylib") == (str.length() - 6)));
}
void
diff --git a/libs/ardour/crossfade.cc b/libs/ardour/crossfade.cc
index 739ea1cc0e..fd2fced83c 100644
--- a/libs/ardour/crossfade.cc
+++ b/libs/ardour/crossfade.cc
@@ -759,7 +759,7 @@ Crossfade::set_state (const XMLNode& node)
/* fade out */
- _fade_in.freeze ();
+ _fade_out.freeze ();
_fade_out.clear ();
children = fo->children();
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index 5f6f3956cf..09c5b75b86 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -71,14 +71,12 @@ sigc::signal<void> Diskstream::DiskUnderrun;
Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
: _name (name)
, _session (sess)
- , _playlist(NULL)
{
init (flag);
}
Diskstream::Diskstream (Session& sess, const XMLNode& node)
: _session (sess)
- , _playlist(NULL)
{
init (Recordable);
}
@@ -131,7 +129,7 @@ Diskstream::~Diskstream ()
//Glib::Mutex::Lock lm (state_lock);
if (_playlist)
- _playlist->unref ();
+ _playlist->release ();
}
void
@@ -305,7 +303,7 @@ Diskstream::set_speed (double sp)
}
int
-Diskstream::use_playlist (Playlist* playlist)
+Diskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
{
{
Glib::Mutex::Lock lm (state_lock);
@@ -314,26 +312,30 @@ Diskstream::use_playlist (Playlist* playlist)
return 0;
}
- plstate_connection.disconnect();
plmod_connection.disconnect ();
plgone_connection.disconnect ();
if (_playlist) {
- _playlist->unref();
+ _playlist->release();
}
_playlist = playlist;
- _playlist->ref();
+ _playlist->use();
if (!in_set_state && recordable()) {
reset_write_sources (false);
}
plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
- plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), _playlist));
+ plgone_connection = _playlist->GoingAway.connect (bind (mem_fun (*this, &Diskstream::playlist_deleted), boost::weak_ptr<Playlist>(_playlist)));
}
- if (!overwrite_queued) {
+ /* don't do this if we've already asked for it *or* if we are setting up
+ the diskstream for the very first time - the input changed handling will
+ take care of the buffer refill.
+ */
+
+ if (!overwrite_queued && !(_session.state_of_the_state() & Session::CannotSave)) {
_session.request_overwrite_buffer (this);
overwrite_queued = true;
}
@@ -360,14 +362,21 @@ Diskstream::playlist_modified ()
}
void
-Diskstream::playlist_deleted (Playlist* pl)
+Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
{
- /* this catches an ordering issue with session destruction. playlists
- are destroyed before diskstreams. we have to invalidate any handles
- we have to the playlist.
- */
+ boost::shared_ptr<Playlist> pl (wpl.lock());
+
+ if (pl == _playlist) {
- _playlist = 0;
+ /* this catches an ordering issue with session destruction. playlists
+ are destroyed before diskstreams. we have to invalidate any handles
+ we have to the playlist.
+ */
+
+ if (_playlist) {
+ _playlist.reset ();
+ }
+ }
}
int
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
new file mode 100644
index 0000000000..0460df43d8
--- /dev/null
+++ b/libs/ardour/enums.cc
@@ -0,0 +1,327 @@
+#include <pbd/enumwriter.h>
+
+#include <ardour/types.h>
+#include <ardour/session.h>
+#include <ardour/location.h>
+#include <ardour/audiofilesource.h>
+#include <ardour/diskstream.h>
+#include <ardour/audioregion.h>
+#include <ardour/route_group.h>
+#include <ardour/panner.h>
+#include <ardour/track.h>
+
+using namespace std;
+using namespace PBD;
+using namespace ARDOUR;
+
+void
+setup_enum_writer ()
+{
+ EnumWriter* enum_writer = new EnumWriter();
+ vector<int> i;
+ vector<string> s;
+
+ OverlapType _OverlapType;
+ AlignStyle _AlignStyle;
+ MeterPoint _MeterPoint;
+ TrackMode _TrackMode;
+ MeterFalloff _MeterFalloff;
+ MeterHold _MeterHold;
+ EditMode _EditMode;
+ RegionPoint _RegionPoint;
+ Placement _Placement;
+ MonitorModel _MonitorModel;
+ CrossfadeModel _CrossfadeModel;
+ LayerModel _LayerModel;
+ SoloModel _SoloModel;
+ SampleFormat _SampleFormat;
+ HeaderFormat _HeaderFormat;
+ PluginType _PluginType;
+ SlaveSource _SlaveSource;
+ ShuttleBehaviour _ShuttleBehaviour;
+ ShuttleUnits _ShuttleUnits;
+ mute_type _mute_type;
+ Session::RecordState _Session_RecordState;
+ Session::Event::Type _Session_Event_Type;
+ SmpteFormat _Session_SmpteFormat;
+ Session::PullupFormat _Session_PullupFormat;
+ AudioRegion::FadeShape _AudioRegion_FadeShape;
+ Panner::LinkDirection _Panner_LinkDirection;
+ IOChange _IOChange;
+ AutomationType _AutomationType;
+ AutoState _AutoState;
+ AutoStyle _AutoStyle;
+ AutoConnectOption _AutoConnectOption;
+ Session::StateOfTheState _Session_StateOfTheState;
+ Route::Flag _Route_Flag;
+ AudioFileSource::Flag _AudioFileSource_Flag;
+ Diskstream::Flag _Diskstream_Flag;
+ Location::Flags _Location_Flags;
+ RouteGroup::Flag _RouteGroup_Flag;
+ Region::Flag _Region_Flag;
+ Track::FreezeState _Track_FreezeState;
+
+#define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
+#define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
+#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
+#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
+
+ REGISTER_ENUM (NoChange);
+ REGISTER_ENUM (ConfigurationChanged);
+ REGISTER_ENUM (ConnectionsChanged);
+ REGISTER_BITS (_IOChange);
+
+ REGISTER_ENUM (OverlapNone);
+ REGISTER_ENUM (OverlapInternal);
+ REGISTER_ENUM (OverlapStart);
+ REGISTER_ENUM (OverlapEnd);
+ REGISTER_ENUM (OverlapExternal);
+ REGISTER (_OverlapType);
+
+ REGISTER_ENUM (GainAutomation);
+ REGISTER_ENUM (PanAutomation);
+ REGISTER_ENUM (PluginAutomation);
+ REGISTER_ENUM (SoloAutomation);
+ REGISTER_ENUM (MuteAutomation);
+ REGISTER_BITS (_AutomationType);
+
+ REGISTER_ENUM (Off);
+ REGISTER_ENUM (Write);
+ REGISTER_ENUM (Touch);
+ REGISTER_ENUM (Play);
+ REGISTER_BITS (_AutoState);
+
+ REGISTER_ENUM (Absolute);
+ REGISTER_ENUM (Trim);
+ REGISTER_BITS (_AutoStyle);
+
+ REGISTER_ENUM (CaptureTime);
+ REGISTER_ENUM (ExistingMaterial);
+ REGISTER (_AlignStyle);
+
+ REGISTER_ENUM (MeterInput);
+ REGISTER_ENUM (MeterPreFader);
+ REGISTER_ENUM (MeterPostFader);
+ REGISTER (_MeterPoint);
+
+ REGISTER_ENUM (Normal);
+ REGISTER_ENUM (Destructive);
+ REGISTER (_TrackMode);
+
+ REGISTER_ENUM (MeterFalloffOff);
+ REGISTER_ENUM (MeterFalloffSlowest);
+ REGISTER_ENUM (MeterFalloffSlow);
+ REGISTER_ENUM (MeterFalloffMedium);
+ REGISTER_ENUM (MeterFalloffFast);
+ REGISTER_ENUM (MeterFalloffFaster);
+ REGISTER_ENUM (MeterFalloffFastest);
+ REGISTER (_MeterFalloff);
+
+ REGISTER_ENUM (MeterHoldOff);
+ REGISTER_ENUM (MeterHoldShort);
+ REGISTER_ENUM (MeterHoldMedium);
+ REGISTER_ENUM (MeterHoldLong);
+ REGISTER (_MeterHold);
+
+ REGISTER_ENUM (Slide);
+ REGISTER_ENUM (Splice);
+ REGISTER (_EditMode);
+
+ REGISTER_ENUM (Start);
+ REGISTER_ENUM (End);
+ REGISTER_ENUM (SyncPoint);
+ REGISTER (_RegionPoint);
+
+
+ REGISTER_ENUM (PreFader);
+ REGISTER_ENUM (PostFader);
+ REGISTER (_Placement);
+
+ REGISTER_ENUM (HardwareMonitoring);
+ REGISTER_ENUM (SoftwareMonitoring);
+ REGISTER_ENUM (ExternalMonitoring);
+ REGISTER (_MonitorModel);
+
+ REGISTER_ENUM (FullCrossfade);
+ REGISTER_ENUM (ShortCrossfade);
+ REGISTER (_CrossfadeModel);
+
+ REGISTER_ENUM (LaterHigher);
+ REGISTER_ENUM (MoveAddHigher);
+ REGISTER_ENUM (AddHigher);
+ REGISTER (_LayerModel);
+
+ REGISTER_ENUM (InverseMute);
+ REGISTER_ENUM (SoloBus);
+ REGISTER (_SoloModel);
+
+ REGISTER_ENUM (AutoConnectPhysical);
+ REGISTER_ENUM (AutoConnectMaster);
+ REGISTER_BITS (_AutoConnectOption);
+
+ REGISTER_ENUM (FormatFloat);
+ REGISTER_ENUM (FormatInt24);
+ REGISTER (_SampleFormat);
+
+ REGISTER_ENUM (BWF);
+ REGISTER_ENUM (WAVE);
+ REGISTER_ENUM (WAVE64);
+ REGISTER_ENUM (CAF);
+ REGISTER_ENUM (AIFF);
+ REGISTER_ENUM (iXML);
+ REGISTER_ENUM (RF64);
+ REGISTER (_HeaderFormat);
+
+ REGISTER_ENUM (AudioUnit);
+ REGISTER_ENUM (LADSPA);
+ REGISTER_ENUM (VST);
+ REGISTER (_PluginType);
+
+ REGISTER_ENUM (None);
+ REGISTER_ENUM (MTC);
+ REGISTER_ENUM (JACK);
+ REGISTER (_SlaveSource);
+
+ REGISTER_ENUM (Sprung);
+ REGISTER_ENUM (Wheel);
+ REGISTER (_ShuttleBehaviour);
+
+ REGISTER_ENUM (Percentage);
+ REGISTER_ENUM (Semitones);
+ REGISTER (_ShuttleUnits);
+
+ REGISTER_CLASS_ENUM (Session, Disabled);
+ REGISTER_CLASS_ENUM (Session, Enabled);
+ REGISTER_CLASS_ENUM (Session, Recording);
+ REGISTER (_Session_RecordState);
+
+ REGISTER_CLASS_ENUM (Session::Event, SetTransportSpeed);
+ REGISTER_CLASS_ENUM (Session::Event, SetDiskstreamSpeed);
+ REGISTER_CLASS_ENUM (Session::Event, Locate);
+ REGISTER_CLASS_ENUM (Session::Event, LocateRoll);
+ REGISTER_CLASS_ENUM (Session::Event, SetLoop);
+ REGISTER_CLASS_ENUM (Session::Event, PunchIn);
+ REGISTER_CLASS_ENUM (Session::Event, PunchOut);
+ REGISTER_CLASS_ENUM (Session::Event, RangeStop);
+ REGISTER_CLASS_ENUM (Session::Event, RangeLocate);
+ REGISTER_CLASS_ENUM (Session::Event, Overwrite);
+ REGISTER_CLASS_ENUM (Session::Event, SetSlaveSource);
+ REGISTER_CLASS_ENUM (Session::Event, Audition);
+ REGISTER_CLASS_ENUM (Session::Event, InputConfigurationChange);
+ REGISTER_CLASS_ENUM (Session::Event, SetAudioRange);
+ REGISTER_CLASS_ENUM (Session::Event, SetPlayRange);
+ REGISTER_CLASS_ENUM (Session::Event, StopOnce);
+ REGISTER_CLASS_ENUM (Session::Event, AutoLoop);
+ REGISTER (_Session_Event_Type);
+
+ REGISTER_CLASS_ENUM (Session, Clean);
+ REGISTER_CLASS_ENUM (Session, Dirty);
+ REGISTER_CLASS_ENUM (Session, CannotSave);
+ REGISTER_CLASS_ENUM (Session, Deletion);
+ REGISTER_CLASS_ENUM (Session, InitialConnecting);
+ REGISTER_CLASS_ENUM (Session, Loading);
+ REGISTER_CLASS_ENUM (Session, InCleanup);
+ REGISTER_BITS (_Session_StateOfTheState);
+
+ REGISTER_ENUM (smpte_23976);
+ REGISTER_ENUM (smpte_24);
+ REGISTER_ENUM (smpte_24976);
+ REGISTER_ENUM (smpte_25);
+ REGISTER_ENUM (smpte_2997);
+ REGISTER_ENUM (smpte_2997drop);
+ REGISTER_ENUM (smpte_30);
+ REGISTER_ENUM (smpte_30drop);
+ REGISTER_ENUM (smpte_5994);
+ REGISTER_ENUM (smpte_60);
+ REGISTER (_Session_SmpteFormat);
+
+ REGISTER_CLASS_ENUM (Session, pullup_Plus4Plus1);
+ REGISTER_CLASS_ENUM (Session, pullup_Plus4);
+ REGISTER_CLASS_ENUM (Session, pullup_Plus4Minus1);
+ REGISTER_CLASS_ENUM (Session, pullup_Plus1);
+ REGISTER_CLASS_ENUM (Session, pullup_None);
+ REGISTER_CLASS_ENUM (Session, pullup_Minus1);
+ REGISTER_CLASS_ENUM (Session, pullup_Minus4Plus1);
+ REGISTER_CLASS_ENUM (Session, pullup_Minus4);
+ REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
+ REGISTER (_Session_PullupFormat);
+
+ REGISTER_ENUM (PRE_FADER);
+ REGISTER_ENUM (POST_FADER);
+ REGISTER_ENUM (CONTROL_OUTS);
+ REGISTER_ENUM (MAIN_OUTS);
+ REGISTER (_mute_type);
+
+ REGISTER_CLASS_ENUM (Route, Hidden);
+ REGISTER_CLASS_ENUM (Route, MasterOut);
+ REGISTER_CLASS_ENUM (Route, ControlOut);
+ REGISTER_BITS (_Route_Flag);
+
+ REGISTER_CLASS_ENUM (AudioFileSource, Writable);
+ REGISTER_CLASS_ENUM (AudioFileSource, CanRename);
+ REGISTER_CLASS_ENUM (AudioFileSource, Broadcast);
+ REGISTER_CLASS_ENUM (AudioFileSource, Removable);
+ REGISTER_CLASS_ENUM (AudioFileSource, RemovableIfEmpty);
+ REGISTER_CLASS_ENUM (AudioFileSource, RemoveAtDestroy);
+ REGISTER_CLASS_ENUM (AudioFileSource, NoPeakFile);
+ REGISTER_CLASS_ENUM (AudioFileSource, Destructive);
+ REGISTER_BITS (_AudioFileSource_Flag);
+
+ REGISTER_CLASS_ENUM (AudioRegion, Linear);
+ REGISTER_CLASS_ENUM (AudioRegion, Fast);
+ REGISTER_CLASS_ENUM (AudioRegion, Slow);
+ REGISTER_CLASS_ENUM (AudioRegion, LogA);
+ REGISTER_CLASS_ENUM (AudioRegion, LogB);
+ REGISTER (_AudioRegion_FadeShape);
+
+ REGISTER_CLASS_ENUM (Diskstream, Recordable);
+ REGISTER_CLASS_ENUM (Diskstream, Hidden);
+ REGISTER_CLASS_ENUM (Diskstream, Destructive);
+ REGISTER_BITS (_Diskstream_Flag);
+
+ REGISTER_CLASS_ENUM (Location, IsMark);
+ REGISTER_CLASS_ENUM (Location, IsAutoPunch);
+ REGISTER_CLASS_ENUM (Location, IsAutoLoop);
+ REGISTER_CLASS_ENUM (Location, IsHidden);
+ REGISTER_CLASS_ENUM (Location, IsCDMarker);
+ REGISTER_CLASS_ENUM (Location, IsEnd);
+ REGISTER_CLASS_ENUM (Location, IsRangeMarker);
+ REGISTER_CLASS_ENUM (Location, IsStart);
+ REGISTER_BITS (_Location_Flags);
+
+
+ REGISTER_CLASS_ENUM (RouteGroup, Relative);
+ REGISTER_CLASS_ENUM (RouteGroup, Active);
+ REGISTER_CLASS_ENUM (RouteGroup, Hidden);
+ REGISTER_BITS (_RouteGroup_Flag);
+
+ REGISTER_CLASS_ENUM (Panner, SameDirection);
+ REGISTER_CLASS_ENUM (Panner, OppositeDirection);
+ REGISTER (_Panner_LinkDirection);
+
+ REGISTER_CLASS_ENUM (Region, Muted);
+ REGISTER_CLASS_ENUM (Region, Opaque);
+ REGISTER_CLASS_ENUM (Region, EnvelopeActive);
+ REGISTER_CLASS_ENUM (Region, DefaultFadeIn);
+ REGISTER_CLASS_ENUM (Region, DefaultFadeOut);
+ REGISTER_CLASS_ENUM (Region, Locked);
+ REGISTER_CLASS_ENUM (Region, Automatic);
+ REGISTER_CLASS_ENUM (Region, WholeFile);
+ REGISTER_CLASS_ENUM (Region, FadeIn);
+ REGISTER_CLASS_ENUM (Region, FadeOut);
+ REGISTER_CLASS_ENUM (Region, Copied);
+ REGISTER_CLASS_ENUM (Region, Import);
+ REGISTER_CLASS_ENUM (Region, External);
+ REGISTER_CLASS_ENUM (Region, SyncMarked);
+ REGISTER_CLASS_ENUM (Region, LeftOfSplit);
+ REGISTER_CLASS_ENUM (Region, RightOfSplit);
+ REGISTER_CLASS_ENUM (Region, Hidden);
+ REGISTER_CLASS_ENUM (Region, DoNotSaveState);
+ REGISTER_BITS (_Region_Flag);
+
+ REGISTER_CLASS_ENUM (Track, NoFreeze);
+ REGISTER_CLASS_ENUM (Track, Frozen);
+ REGISTER_CLASS_ENUM (Track, UnFrozen);
+ REGISTER (_Track_FreezeState);
+
+}
diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc
index f92660470c..515d9e1c2f 100644
--- a/libs/ardour/globals.cc
+++ b/libs/ardour/globals.cc
@@ -191,42 +191,11 @@ setup_midi (AudioEngine& engine )
return 0;
}
-
-int
-ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization)
+
+void
+setup_hardware_optimization (bool try_optimization)
{
- bool generic_mix_functions = true;
-
- (void) bindtextdomain(PACKAGE, LOCALEDIR);
-
- PBD::ID::init ();
-
- lrdf_init();
- Library = new AudioLibrary;
-
- Config = new Configuration;
-
- if (Config->load_state ()) {
- return -1;
- }
-
- Config->set_use_vst (use_vst);
-
- if (setup_midi (engine)) {
- return -1;
- }
-
-#ifdef HAVE_LIBLO
- if (setup_osc ()) {
- return -1;
- }
-#endif
-
-#ifdef VST_SUPPORT
- if (Config->get_use_vst() && fst_init ()) {
- return -1;
- }
-#endif
+ bool generic_mix_functions = true;
if (try_optimization) {
@@ -261,7 +230,7 @@ ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization)
#endif /* USE_X86_64_ASM */
if (use_sse) {
- cerr << "Enabling SSE optimized routines" << endl;
+ info << "Using SSE optimized routines" << endmsg;
// SSE SET
Session::compute_peak = x86_sse_compute_peak;
@@ -301,6 +270,47 @@ ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization)
info << "No H/W specific optimizations in use" << endmsg;
}
+}
+
+int
+ARDOUR::init (ARDOUR::AudioEngine& engine, bool use_vst, bool try_optimization)
+{
+ extern void setup_enum_writer ();
+
+ (void) bindtextdomain(PACKAGE, LOCALEDIR);
+
+ PBD::ID::init ();
+
+ setup_enum_writer ();
+
+ lrdf_init();
+ Library = new AudioLibrary;
+
+ Config = new Configuration;
+
+ if (Config->load_state ()) {
+ return -1;
+ }
+
+ Config->set_use_vst (use_vst);
+
+ if (setup_midi (engine)) {
+ return -1;
+ }
+
+#ifdef HAVE_LIBLO
+ if (setup_osc ()) {
+ return -1;
+ }
+#endif
+
+#ifdef VST_SUPPORT
+ if (Config->get_use_vst() && fst_init ()) {
+ return -1;
+ }
+#endif
+
+ setup_hardware_optimization (try_optimization);
/* singleton - first object is "it" */
new PluginManager ();
@@ -393,8 +403,14 @@ ARDOUR::get_system_data_path ()
{
string path;
- path += DATA_DIR;
- path += "/ardour2/";
+ char *envvar;
+
+ if ((envvar = getenv ("ARDOUR_DATA_PATH")) != 0) {
+ path = envvar;
+ } else {
+ path += DATA_DIR;
+ path += "/ardour2/";
+ }
return path;
}
@@ -403,9 +419,14 @@ string
ARDOUR::get_system_module_path ()
{
string path;
+ char *envvar;
- path += MODULE_DIR;
- path += "/ardour2/";
+ if ((envvar = getenv ("ARDOUR_MODULE_PATH")) != 0) {
+ path = envvar;
+ } else {
+ path += MODULE_DIR;
+ path += "/ardour2/";
+ }
return path;
}
@@ -602,4 +623,5 @@ std::istream& operator>>(std::istream& o, CrossfadeModel& var) { return int_to_t
std::istream& operator>>(std::istream& o, SlaveSource& var) { return int_to_type<SlaveSource> (o, var); }
std::istream& operator>>(std::istream& o, ShuttleBehaviour& var) { return int_to_type<ShuttleBehaviour> (o, var); }
std::istream& operator>>(std::istream& o, ShuttleUnits& var) { return int_to_type<ShuttleUnits> (o, var); }
+std::istream& operator>>(std::istream& o, SmpteFormat& var) { return int_to_type<SmpteFormat> (o, var); }
diff --git a/libs/ardour/import.cc b/libs/ardour/import.cc
index f16a6e7d8c..4466c40a32 100644
--- a/libs/ardour/import.cc
+++ b/libs/ardour/import.cc
@@ -74,22 +74,22 @@ Session::import_audiofile (import_status& status)
status.new_regions.clear ();
- if ((in = sf_open (status.pathname.c_str(), SFM_READ, &info)) == 0) {
- error << string_compose(_("Import: cannot open input sound file \"%1\""), status.pathname) << endmsg;
+ 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;
return -1;
} else {
if ((uint32_t) info.samplerate != frame_rate()) {
sf_close(in);
status.doing_what = _("resampling audio");
// resample to session frame_rate
- if (sample_rate_convert(status, status.pathname, tmp_convert_file)) {
+ if (sample_rate_convert(status, status.paths.front(), tmp_convert_file)) {
if ((in = sf_open (tmp_convert_file.c_str(), SFM_READ, &info)) == 0) {
error << string_compose(_("Import: cannot open converted sound file \"%1\""), tmp_convert_file) << endmsg;
return -1;
}
} else if (!status.cancel){
// error
- error << string_compose(_("Import: error while resampling sound file \"%1\""), status.pathname) << endmsg;
+ error << string_compose(_("Import: error while resampling sound file \"%1\""), status.paths.front()) << endmsg;
return -1;
} else {
// canceled
@@ -103,7 +103,7 @@ Session::import_audiofile (import_status& status)
}
sounds_dir = discover_best_sound_dir ();
- basepath = PBD::basename_nosuffix (status.pathname);
+ basepath = PBD::basename_nosuffix (status.paths.front());
for (n = 0; n < info.channels; ++n) {
@@ -112,14 +112,14 @@ Session::import_audiofile (import_status& status)
do {
if (info.channels == 2) {
if (n == 0) {
- snprintf (buf, sizeof(buf), "%s%s-L.wav", sounds_dir.c_str(), basepath.c_str());
+ 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());
+ 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%lu.wav", sounds_dir.c_str(), basepath.c_str(), n+1);
+ snprintf (buf, sizeof(buf), "%s/%s-c%lu.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());
+ snprintf (buf, sizeof(buf), "%s/%s.wav", sounds_dir.c_str(), basepath.c_str());
}
if (::access (buf, F_OK) == 0) {
@@ -217,8 +217,13 @@ Session::import_audiofile (import_status& status)
sources.push_back(newfiles[n]);
}
- boost::shared_ptr<AudioRegion> r (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, 0, newfiles[0]->length(), region_name_from_path (Glib::path_get_basename (basepath)),
- 0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile))));
+ 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);
@@ -231,11 +236,14 @@ Session::import_audiofile (import_status& status)
/* 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 (Glib::path_get_basename (newfiles[n]->name())),
+ region_name_from_path (newfiles[n]->name(), false),
0, AudioRegion::Flag (AudioRegion::DefaultFlags | AudioRegion::WholeFile | AudioRegion::Import))));
}
}
diff --git a/libs/ardour/insert.cc b/libs/ardour/insert.cc
index 034b043763..d109642fd4 100644
--- a/libs/ardour/insert.cc
+++ b/libs/ardour/insert.cc
@@ -50,21 +50,15 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-/* ********** FIXME: TYPE ************** */
-/* Inserts are still definitely audio only */
-
-Insert::Insert(Session& s, Placement p)
- : Redirect (s, s.next_insert_name(), p)
-{
-}
-
-Insert::Insert(Session& s, Placement p, int imin, int imax, int omin, int omax)
- : Redirect (s, s.next_insert_name(), p, imin, imax, omin, omax)
+/* ********** FIXME: TYPE **************
+ * Inserts are still definitely audio only */
+Insert::Insert(Session& s, string name, Placement p)
+ : Redirect (s, name, p)
{
}
-Insert::Insert(Session& s, string name, Placement p)
- : Redirect (s, name, p)
+Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
+ : Redirect (s, name, p, imin, imax, omin, omax)
{
}
@@ -624,14 +618,8 @@ PluginInsert::state (bool full)
XMLNode* child = new XMLNode("port");
snprintf(buf, sizeof(buf), "%" PRIu32, *x);
child->add_property("number", string(buf));
-
- if (full) {
- snprintf(buf, sizeof(buf), "0x%x", automation_list (*x).automation_state ());
- } else {
- snprintf(buf, sizeof(buf), "0x%x", ARDOUR::Off);
- }
- child->add_property("auto", string(buf));
-
+
+ child->add_child_nocopy (automation_list (*x).state (full));
autonode->add_child_nocopy (*child);
}
@@ -735,43 +723,62 @@ PluginInsert::set_state(const XMLNode& node)
/* look for port automation node */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
- if ((*niter)->name() == port_automation_node_name) {
- XMLNodeList cnodes;
- XMLProperty *cprop;
- XMLNodeConstIterator iter;
- XMLNode *child;
- const char *port;
- uint32_t port_id;
-
- cnodes = (*niter)->children ("port");
-
- for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
-
- child = *iter;
-
- if ((cprop = child->property("number")) != 0) {
- port = cprop->value().c_str();
- } else {
- warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
- continue;
- }
- sscanf (port, "%" PRIu32, &port_id);
+ if ((*niter)->name() != port_automation_node_name) {
+ continue;
+ }
- if (port_id >= _plugins[0]->parameter_count()) {
- warning << _("PluginInsert: Auto: port id out of range") << endmsg;
- continue;
- }
-
+ XMLNodeList cnodes;
+ XMLProperty *cprop;
+ XMLNodeConstIterator iter;
+ XMLNode *child;
+ const char *port;
+ uint32_t port_id;
+
+ cnodes = (*niter)->children ("port");
+
+ for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
+
+ child = *iter;
+
+ if ((cprop = child->property("number")) != 0) {
+ port = cprop->value().c_str();
+ } else {
+ warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
+ continue;
+ }
+
+ sscanf (port, "%" PRIu32, &port_id);
+
+ if (port_id >= _plugins[0]->parameter_count()) {
+ warning << _("PluginInsert: Auto: port id out of range") << endmsg;
+ continue;
+ }
+
+ if (!child->children().empty()) {
+ automation_list (port_id).set_state (*child->children().front());
+ } else {
if ((cprop = child->property("auto")) != 0) {
+
+ /* old school */
+
int x;
sscanf (cprop->value().c_str(), "0x%x", &x);
automation_list (port_id).set_automation_state (AutoState (x));
+
+ } else {
+
+ /* missing */
+
+ automation_list (port_id).set_automation_state (Off);
}
}
-
- break;
+
}
+
+ /* done */
+
+ break;
}
if (niter == nlist.end()) {
@@ -830,14 +837,14 @@ PluginInsert::type ()
***************************************************************/
PortInsert::PortInsert (Session& s, Placement p)
- : Insert (s, p, 1, -1, 1, -1)
+ : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
}
PortInsert::PortInsert (const PortInsert& other)
- : Insert (other._session, other.placement(), 1, -1, 1, -1)
+ : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
@@ -900,9 +907,11 @@ XMLNode&
PortInsert::state (bool full)
{
XMLNode *node = new XMLNode("Insert");
-
+ char buf[32];
node->add_child_nocopy (Redirect::state(full));
- node->add_property("type", "port");
+ node->add_property ("type", "port");
+ snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
+ node->add_property ("bitslot", buf);
return *node;
}
@@ -925,6 +934,13 @@ PortInsert::set_state(const XMLNode& node)
return -1;
}
+ if ((prop = node.property ("bitslot")) == 0) {
+ bitslot = _session.next_insert_id();
+ } else {
+ sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
+ _session.mark_insert_id (bitslot);
+ }
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index 60e7ec3f42..7ed6158b85 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -55,6 +55,7 @@ extern "C" int isnan (double);
extern "C" int isinf (double);
#endif
+#define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (_session.engine().process_lock())
using namespace std;
using namespace ARDOUR;
@@ -339,7 +340,7 @@ IO::disconnect_input (Port* our_port, string other_port, void* src)
}
{
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -375,7 +376,7 @@ IO::connect_input (Port* our_port, string other_port, void* src)
}
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -409,7 +410,7 @@ IO::disconnect_output (Port* our_port, string other_port, void* src)
}
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -444,7 +445,8 @@ IO::connect_output (Port* our_port, string other_port, void* src)
}
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
+
{
Glib::Mutex::Lock lm (io_lock);
@@ -503,7 +505,8 @@ IO::remove_output_port (Port* port, void* src)
IOChange change (NoChange);
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
+
{
Glib::Mutex::Lock lm (io_lock);
@@ -554,7 +557,8 @@ IO::add_output_port (string destination, void* src, DataType type)
type = _default_type;
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
+
{
Glib::Mutex::Lock lm (io_lock);
@@ -605,7 +609,8 @@ IO::remove_input_port (Port* port, void* src)
IOChange change (NoChange);
{
- Glib::Mutex::Lock em(_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
+
{
Glib::Mutex::Lock lm (io_lock);
@@ -657,7 +662,7 @@ IO::add_input_port (string source, void* src, DataType type)
type = _default_type;
{
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -707,7 +712,7 @@ int
IO::disconnect_inputs (void* src)
{
{
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -729,7 +734,7 @@ int
IO::disconnect_outputs (void* src)
{
{
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
@@ -793,7 +798,7 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
setup_peak_meters ();
reset_panner ();
/* pass it on */
- throw err;
+ throw AudioEngine::PortRegistrationFailure();
}
_inputs.add (input_port);
@@ -845,7 +850,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
}
{
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm (io_lock);
Port* port;
@@ -904,12 +909,12 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
return -1;
}
}
-
+
catch (AudioEngine::PortRegistrationFailure& err) {
setup_peak_meters ();
reset_panner ();
/* pass it on */
- throw err;
+ throw AudioEngine::PortRegistrationFailure();
}
_inputs.add (port);
@@ -941,7 +946,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
setup_peak_meters ();
reset_panner ();
/* pass it on */
- throw err;
+ throw AudioEngine::PortRegistrationFailure ();
}
_outputs.add (port);
@@ -998,7 +1003,7 @@ IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
}
if (lockit) {
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock im (io_lock);
changed = ensure_inputs_locked (count, clear, src);
} else {
@@ -1095,7 +1100,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
/* XXX caller should hold io_lock, but generally doesn't */
if (lockit) {
- Glib::Mutex::Lock em (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock im (io_lock);
changed = ensure_outputs_locked (count, clear, src);
} else {
@@ -1906,7 +1911,7 @@ IO::use_input_connection (Connection& c, void* src)
uint32_t limit;
{
- Glib::Mutex::Lock lm (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
limit = c.nports();
@@ -1985,7 +1990,7 @@ IO::use_output_connection (Connection& c, void* src)
uint32_t limit;
{
- Glib::Mutex::Lock lm (_session.engine().process_lock());
+ BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
limit = c.nports();
diff --git a/libs/ardour/location.cc b/libs/ardour/location.cc
index e09a59d42f..bec87e5dd6 100644
--- a/libs/ardour/location.cc
+++ b/libs/ardour/location.cc
@@ -28,6 +28,7 @@
#include <pbd/stl_delete.h>
#include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
#include <ardour/location.h>
#include <ardour/session.h>
@@ -35,6 +36,8 @@
#include "i18n.h"
+#define SUFFIX_MAX 32
+
using namespace std;
using namespace ARDOUR;
using namespace sigc;
@@ -217,12 +220,12 @@ Location::set_flag_internal (bool yn, Flags flag)
{
if (yn) {
if (!(_flags & flag)) {
- _flags |= flag;
+ _flags = Flags (_flags | flag);
return true;
}
} else {
if (_flags & flag) {
- _flags &= ~flag;
+ _flags = Flags (_flags & ~flag);
return true;
}
}
@@ -273,8 +276,7 @@ Location::get_state (void)
node->add_property ("start", buf);
snprintf (buf, sizeof (buf), "%u", end());
node->add_property ("end", buf);
- snprintf (buf, sizeof (buf), "%" PRIu32, (uint32_t) _flags);
- node->add_property ("flags", buf);
+ node->add_property ("flags", enum_2_string (_flags));
return *node;
}
@@ -327,14 +329,12 @@ Location::set_state (const XMLNode& node)
_end = atoi (prop->value().c_str());
- _flags = 0;
-
if ((prop = node.property ("flags")) == 0) {
error << _("XML node for Location has no flags information") << endmsg;
return -1;
}
- _flags = Flags (atoi (prop->value().c_str()));
+ _flags = Flags (string_2_enum (prop->value(), _flags));
for (cd_iter = cd_list.begin(); cd_iter != cd_list.end(); ++cd_iter) {
@@ -404,6 +404,40 @@ Locations::set_current (Location *loc, bool want_lock)
}
int
+Locations::next_available_name(string& result,string base)
+{
+ LocationList::iterator i;
+ Location* location;
+ string temp;
+ string::size_type l;
+ int suffix;
+ char buf[32];
+ bool available[SUFFIX_MAX+1];
+
+ result = base;
+ for (int k=1; k<SUFFIX_MAX; k++) {
+ available[k] = true;
+ }
+ l = base.length();
+ for (i = locations.begin(); i != locations.end(); ++i) {
+ location =* i;
+ temp = location->name();
+ if (l && !temp.find(base,0)) {
+ suffix = atoi(temp.substr(l,3));
+ if (suffix) available[suffix] = false;
+ }
+ }
+ for (int k=1; k<=SUFFIX_MAX; k++) {
+ if (available[k]) {
+ snprintf (buf, 31, "%d", k);
+ result += buf;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
Locations::set_current_unlocked (Location *loc)
{
if (find (locations.begin(), locations.end(), loc) == locations.end()) {
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index 1ce610d13c..66e0a98dd3 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -57,6 +57,14 @@ PeakMeter::reset ()
}
void
+PeakMeter::reset_max ()
+{
+ for (size_t i = 0; i < _max_peak_power.size(); ++i) {
+ _max_peak_power[i] = -INFINITY;
+ }
+}
+
+void
PeakMeter::setup (const ChanCount& in)
{
uint32_t limit = in.get(DataType::AUDIO);
@@ -68,11 +76,13 @@ PeakMeter::setup (const ChanCount& in)
while (_peak_power.size() < limit) {
_peak_power.push_back (0);
- _visible_peak_power.push_back (0);
+ _visible_peak_power.push_back (minus_infinity());
+ _max_peak_power.push_back (minus_infinity());
}
assert(_peak_power.size() == limit);
assert(_visible_peak_power.size() == limit);
+ assert(_max_peak_power.size() == limit);
}
/** To be driven by the Meter signal from IO.
@@ -102,6 +112,10 @@ PeakMeter::meter ()
new_peak = minus_infinity();
}
+ /* update max peak */
+
+ _max_peak_power[n] = std::max (new_peak, _max_peak_power[n]);
+
if (Config->get_meter_falloff() == 0.0f || new_peak > _visible_peak_power[n]) {
_visible_peak_power[n] = new_peak;
} else {
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index b1ec7da965..f3de214791 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -14,8 +14,6 @@
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: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $
*/
#include <fstream>
@@ -36,6 +34,7 @@
#include <glibmm/thread.h>
#include <pbd/xml++.h>
#include <pbd/memento_command.h>
+#include <pbd/enumwriter.h>
#include <ardour/ardour.h>
#include <ardour/audioengine.h>
@@ -47,6 +46,7 @@
#include <ardour/send.h>
#include <ardour/region_factory.h>
#include <ardour/midi_playlist.h>
+#include <ardour/playlist_factory.h>
#include <ardour/cycle_timer.h>
#include <ardour/midi_region.h>
#include <ardour/midi_port.h>
@@ -220,16 +220,14 @@ MidiDiskstream::get_input_sources ()
int
MidiDiskstream::find_and_use_playlist (const string& name)
{
- Playlist* pl;
- MidiPlaylist* playlist;
+ boost::shared_ptr<MidiPlaylist> playlist;
- if ((pl = _session.playlist_by_name (name)) == 0) {
- playlist = new MidiPlaylist(_session, name);
- pl = playlist;
+ if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (_session.playlist_by_name (name))) == 0) {
+ playlist = boost::dynamic_pointer_cast<MidiPlaylist> (PlaylistFactory::create (_session, name));
}
- if ((playlist = dynamic_cast<MidiPlaylist*> (pl)) == 0) {
- error << string_compose(_("MidiDiskstream: Playlist \"%1\" isn't a midi playlist"), name) << endmsg;
+ if (!playlist) {
+ error << string_compose(_("MidiDiskstream: Playlist \"%1\" isn't an midi playlist"), name) << endmsg;
return -1;
}
@@ -237,18 +235,20 @@ MidiDiskstream::find_and_use_playlist (const string& name)
}
int
-MidiDiskstream::use_playlist (Playlist* playlist)
-{
- assert(dynamic_cast<MidiPlaylist*>(playlist));
+MidiDiskstream::use_playlist (boost::shared_ptr<Playlist> playlist)
+{
+ assert(boost::dynamic_pointer_cast<MidiPlaylist>(playlist));
- return Diskstream::use_playlist(playlist);
+ Diskstream::use_playlist(playlist);
+
+ return 0;
}
int
MidiDiskstream::use_new_playlist ()
-{
+{
string newname;
- MidiPlaylist* playlist;
+ boost::shared_ptr<MidiPlaylist> playlist;
if (!in_set_state && destructive()) {
return 0;
@@ -260,9 +260,11 @@ MidiDiskstream::use_new_playlist ()
newname = Playlist::bump_name (_name, _session);
}
- if ((playlist = new MidiPlaylist (_session, newname, hidden())) != 0) {
+ if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist> (PlaylistFactory::create (_session, newname, hidden()))) != 0) {
+
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
+
} else {
return -1;
}
@@ -271,6 +273,8 @@ MidiDiskstream::use_new_playlist ()
int
MidiDiskstream::use_copy_playlist ()
{
+ assert(midi_playlist());
+
if (destructive()) {
return 0;
}
@@ -281,11 +285,11 @@ MidiDiskstream::use_copy_playlist ()
}
string newname;
- MidiPlaylist* playlist;
+ boost::shared_ptr<MidiPlaylist> playlist;
newname = Playlist::bump_name (_playlist->name(), _session);
- if ((playlist = new MidiPlaylist (*midi_playlist(), newname)) != 0) {
+ if ((playlist = boost::dynamic_pointer_cast<MidiPlaylist>(PlaylistFactory::create (midi_playlist(), newname))) != 0) {
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
} else {
@@ -1039,6 +1043,8 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
}
+ string whole_file_region_name;
+ whole_file_region_name = region_name_from_path (_write_source->name(), true);
/* Register a new region with the Session that
describes the entire source. Do this first
so that any sub-regions will obviously be
@@ -1048,7 +1054,7 @@ MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_cap
assert(_write_source);
boost::shared_ptr<Region> rx (RegionFactory::create (srcs, _write_source->last_capture_start_frame(), total_capture,
- region_name_from_path (_write_source->name()),
+ whole_file_region_name,
0, Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile)));
region = boost::dynamic_pointer_cast<MidiRegion> (rx);
@@ -1289,7 +1295,7 @@ MidiDiskstream::set_state (const XMLNode& node)
}
if ((prop = node.property ("flags")) != 0) {
- _flags = strtol (prop->value().c_str(), 0, 0);
+ _flags = Flag (string_2_enum (prop->value(), _flags));
}
if ((prop = node.property ("channels")) != 0) {
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index b2318bbe96..0352e1e910 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -49,22 +49,14 @@ MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
in_set_state = true;
set_state (node);
in_set_state = false;
-
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
}
MidiPlaylist::MidiPlaylist (Session& session, string name, bool hidden)
: Playlist (session, name, DataType::MIDI, hidden)
{
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
-
}
-MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, string name, bool hidden)
+MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, string name, bool hidden)
: Playlist (other, name, hidden)
{
throw; // nope
@@ -106,12 +98,9 @@ MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, string name, bool hidden)
in_n++;
}
*/
- if (!hidden) {
- PlaylistCreated (this); /* EMIT SIGNAL */
- }
}
-MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, jack_nframes_t start, jack_nframes_t dur, string name, bool hidden)
+MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, jack_nframes_t start, jack_nframes_t dur, string name, bool hidden)
: Playlist (other, start, dur, name, hidden)
{
/* this constructor does NOT notify others (session) */
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index f4d1912061..d7ce12d411 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -61,7 +61,7 @@ MidiPort::cycle_start (jack_nframes_t nframes)
void* jack_buffer = jack_port_get_buffer(_port, nframes);
const jack_nframes_t event_count
- = jack_midi_port_get_info(jack_buffer, nframes)->event_count;
+ = jack_midi_get_event_count(jack_buffer, nframes);
assert(event_count < _buffer.capacity());
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index a18d0c20ce..26441203a3 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -303,11 +303,11 @@ MidiTrack::set_state_part_two ()
_freeze_record.insert_info.clear ();
if ((prop = fnode->property (X_("playlist"))) != 0) {
- Playlist* pl = _session.playlist_by_name (prop->value());
+ boost::shared_ptr<Playlist> pl = _session.playlist_by_name (prop->value());
if (pl) {
- _freeze_record.playlist = dynamic_cast<MidiPlaylist*> (pl);
+ _freeze_record.playlist = boost::dynamic_pointer_cast<MidiPlaylist> (pl);
} else {
- _freeze_record.playlist = 0;
+ _freeze_record.playlist.reset();
_freeze_record.state = NoFreeze;
return;
}
diff --git a/libs/ardour/named_selection.cc b/libs/ardour/named_selection.cc
index 605d7cae13..ecce09692f 100644
--- a/libs/ardour/named_selection.cc
+++ b/libs/ardour/named_selection.cc
@@ -33,12 +33,14 @@ using namespace PBD;
sigc::signal<void,NamedSelection*> NamedSelection::NamedSelectionCreated;
-NamedSelection::NamedSelection (string n, list<Playlist*>& l)
+typedef std::list<boost::shared_ptr<Playlist> > PlaylistList;
+
+NamedSelection::NamedSelection (string n, PlaylistList& l)
: name (n)
{
playlists = l;
- for (list<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
- (*i)->ref();
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ (*i)->use();
}
NamedSelectionCreated (this);
}
@@ -65,13 +67,13 @@ NamedSelection::NamedSelection (Session& session, const XMLNode& node)
const XMLNode* plnode;
string playlist_name;
- Playlist* playlist;
+ boost::shared_ptr<Playlist> playlist;
plnode = *niter;
if ((property = plnode->property ("name")) != 0) {
if ((playlist = session.playlist_by_name (property->value())) != 0) {
- playlist->ref();
+ playlist->use();
playlists.push_back (playlist);
} else {
warning << string_compose (_("Chunk %1 uses an unknown playlist \"%2\""), name, property->value()) << endmsg;
@@ -87,8 +89,8 @@ NamedSelection::NamedSelection (Session& session, const XMLNode& node)
NamedSelection::~NamedSelection ()
{
- for (list<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
- (*i)->unref();
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ (*i)->release();
}
}
@@ -107,7 +109,7 @@ NamedSelection::get_state ()
root->add_property ("name", name);
child = root->add_child ("Playlists");
- for (list<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
XMLNode* plnode = new XMLNode ("Playlist");
plnode->add_property ("name", (*i)->name());
diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc
index ee8e100e4a..c69bd84402 100644
--- a/libs/ardour/panner.cc
+++ b/libs/ardour/panner.cc
@@ -36,6 +36,7 @@
#include <pbd/error.h>
#include <pbd/failed_constructor.h>
#include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
#include <ardour/session.h>
#include <ardour/panner.h>
@@ -1068,8 +1069,7 @@ Panner::state (bool full)
char buf[32];
root->add_property (X_("linked"), (_linked ? "yes" : "no"));
- snprintf (buf, sizeof (buf), "%d", _link_direction);
- root->add_property (X_("link_direction"), buf);
+ root->add_property (X_("link_direction"), enum_2_string (_link_direction));
root->add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
/* add each output */
@@ -1113,8 +1113,8 @@ Panner::set_state (const XMLNode& node)
}
if ((prop = node.property (X_("link_direction"))) != 0) {
- sscanf (prop->value().c_str(), "%d", &i);
- set_link_direction ((LinkDirection) (i));
+ LinkDirection ld; /* here to provide type information */
+ set_link_direction (LinkDirection (string_2_enum (prop->value(), ld)));
}
nlist = node.children();
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index d439cf1265..2becdc19b4 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -36,6 +36,7 @@
#include <ardour/session.h>
#include <ardour/region.h>
#include <ardour/region_factory.h>
+#include <ardour/playlist_factory.h>
#include "i18n.h"
@@ -43,14 +44,12 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-sigc::signal<void,Playlist*> Playlist::PlaylistCreated;
-
struct ShowMeTheList {
- ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {}
+ ShowMeTheList (boost::shared_ptr<Playlist> pl, const string& n) : playlist (pl), name (n) {}
~ShowMeTheList () {
cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl;
};
- Playlist *playlist;
+ boost::shared_ptr<Playlist> playlist;
string name;
};
@@ -91,51 +90,52 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
init (hide);
_name = "unnamed"; /* reset by set_state */
- /* derived class calls set_state() */
+ /* set state called by derived class */
}
-Playlist::Playlist (const Playlist& other, string namestr, bool hide)
- : _name (namestr), _session (other._session), _type(other._type), _orig_diskstream_id(other._orig_diskstream_id)
+Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
+ : _name (namestr), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
{
init (hide);
RegionList tmp;
- other.copy_regions (tmp);
+ other->copy_regions (tmp);
in_set_state++;
for (list<boost::shared_ptr<Region> >::iterator x = tmp.begin(); x != tmp.end(); ++x) {
- add_region_internal( (*x), (*x)->position() );
+ add_region_internal( (*x), (*x)->position());
}
in_set_state--;
- _splicing = other._splicing;
- _nudging = other._nudging;
- _edit_mode = other._edit_mode;
+ _splicing = other->_splicing;
+ _nudging = other->_nudging;
+ _edit_mode = other->_edit_mode;
in_set_state = 0;
in_flush = false;
in_partition = false;
subcnt = 0;
_read_data_count = 0;
- _frozen = other._frozen;
-
- layer_op_counter = other.layer_op_counter;
- freeze_length = other.freeze_length;
+ _frozen = other->_frozen;
+ layer_op_counter = other->layer_op_counter;
+ freeze_length = other->freeze_length;
}
-Playlist::Playlist (const Playlist& other, nframes_t start, nframes_t cnt, string str, bool hide)
- : _name (str), _session (other._session), _type(other._type), _orig_diskstream_id(other._orig_diskstream_id)
+Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
+ : _name (str), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
{
- RegionLock rlock2 (&((Playlist&)other));
-
+ RegionLock rlock2 (const_cast<Playlist*> (other.get()));
+
nframes_t end = start + cnt - 1;
init (hide);
- for (RegionList::const_iterator i = other.regions.begin(); i != other.regions.end(); i++) {
+ in_set_state++;
+
+ for (RegionList::const_iterator i = other->regions.begin(); i != other->regions.end(); i++) {
boost::shared_ptr<Region> region;
boost::shared_ptr<Region> new_region;
@@ -182,32 +182,30 @@ Playlist::Playlist (const Playlist& other, nframes_t start, nframes_t cnt, strin
new_region = RegionFactory::RegionFactory::create (region, offset, len, new_name, region->layer(), region->flags());
- add_region_internal (new_region, position, true);
+ add_region_internal (new_region, position);
}
+ in_set_state--;
+
/* this constructor does NOT notify others (session) */
}
void
-Playlist::ref ()
+Playlist::use ()
{
++_refcnt;
- InUse (this, true); /* EMIT SIGNAL */
+ InUse (true); /* EMIT SIGNAL */
}
void
-Playlist::unref ()
+Playlist::release ()
{
if (_refcnt > 0) {
_refcnt--;
}
+
if (_refcnt == 0) {
- InUse (this, false); /* EMIT SIGNAL */
-
- if (_hidden) {
- /* nobody knows we exist */
- delete this;
- }
+ InUse (false); /* EMIT SIGNAL */
}
}
@@ -266,7 +264,7 @@ Playlist::~Playlist ()
RegionLock rl (this);
for (set<boost::shared_ptr<Region> >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) {
- (*i)->set_playlist (0);
+ (*i)->set_playlist (boost::shared_ptr<Playlist>());
}
}
@@ -411,12 +409,8 @@ Playlist::flush_notifications ()
timestamp_layer_op (*r);
}
pending_length = true;
- n++;
- }
-
- for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
dependent_checks_needed.insert (*r);
- /* don't increment n again - its the same list */
+ n++;
}
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
@@ -424,10 +418,6 @@ Playlist::flush_notifications ()
n++;
}
- for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
- check_dependents (*s, false);
- }
-
for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
remove_dependents (*s);
n++;
@@ -448,6 +438,10 @@ Playlist::flush_notifications ()
Modified (); /* EMIT SIGNAL */
}
+ for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
+ check_dependents (*s, false);
+ }
+
pending_adds.clear ();
pending_removes.clear ();
pending_bounds.clear ();
@@ -471,7 +465,7 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
nframes_t pos = position;
if (itimes >= 1) {
- add_region_internal (region, pos, true);
+ add_region_internal (region, pos);
pos += region->length();
--itimes;
}
@@ -488,7 +482,7 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
for (int i = 0; i < itimes; ++i) {
boost::shared_ptr<Region> copy = RegionFactory::create (region);
- add_region_internal (copy, pos, true);
+ add_region_internal (copy, pos);
pos += region->length();
}
@@ -497,12 +491,24 @@ Playlist::add_region (boost::shared_ptr<Region> region, nframes_t position, floa
string name;
_session.region_name (name, region->name(), false);
boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
- add_region_internal (sub, pos, true);
+ add_region_internal (sub, pos);
+ }
+}
+
+void
+Playlist::set_region_ownership ()
+{
+ RegionLock rl (this);
+ RegionList::iterator i;
+ boost::weak_ptr<Playlist> pl (shared_from_this());
+
+ for (i = regions.begin(); i != regions.end(); ++i) {
+ (*i)->set_playlist (pl);
}
}
void
-Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position, bool delay_sort)
+Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t position)
{
RegionSortByPosition cmp;
nframes_t old_length = 0;
@@ -511,7 +517,11 @@ Playlist::add_region_internal (boost::shared_ptr<Region> region, nframes_t posit
old_length = _get_maximum_extent();
}
- region->set_playlist (this);
+ if (!in_set_state) {
+ boost::shared_ptr<Playlist> foo (shared_from_this());
+ region->set_playlist (boost::weak_ptr<Playlist>(foo));
+ }
+
region->set_position (position, this);
timestamp_layer_op (region);
@@ -564,7 +574,7 @@ Playlist::remove_region (boost::shared_ptr<Region> region)
}
int
-Playlist::remove_region_internal (boost::shared_ptr<Region>region, bool delay_sort)
+Playlist::remove_region_internal (boost::shared_ptr<Region>region)
{
RegionList::iterator i;
nframes_t old_length = 0;
@@ -698,7 +708,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
_session.region_name (new_name, current->name(), false);
region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name,
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit));
- add_region_internal (region, start, true);
+ add_region_internal (region, start);
new_regions.push_back (region);
}
@@ -708,7 +718,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name,
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
- add_region_internal (region, end, true);
+ add_region_internal (region, end);
new_regions.push_back (region);
/* "front" ***** */
@@ -737,7 +747,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
_session.region_name (new_name, current->name(), false);
region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(),
Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit));
- add_region_internal (region, start, true);
+ add_region_internal (region, start);
new_regions.push_back (region);
}
@@ -771,7 +781,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
_session.region_name (new_name, current->name(), false);
region = RegionFactory::create (current, 0, pos3 - pos1, new_name,
regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit));
- add_region_internal (region, pos1, true);
+ add_region_internal (region, pos1);
new_regions.push_back (region);
}
@@ -813,20 +823,19 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi
}
}
-Playlist*
-Playlist::cut_copy (Playlist* (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
+boost::shared_ptr<Playlist>
+Playlist::cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t, nframes_t,bool), list<AudioRange>& ranges, bool result_is_hidden)
{
- Playlist* ret;
- Playlist* pl;
+ boost::shared_ptr<Playlist> ret;
+ boost::shared_ptr<Playlist> pl;
nframes_t start;
if (ranges.empty()) {
- return 0;
+ return boost::shared_ptr<Playlist>();
}
start = ranges.front().start;
-
for (list<AudioRange>::iterator i = ranges.begin(); i != ranges.end(); ++i) {
pl = (this->*pmf)((*i).start, (*i).length(), result_is_hidden);
@@ -840,39 +849,31 @@ Playlist::cut_copy (Playlist* (Playlist::*pmf)(nframes_t, nframes_t,bool), list<
chopped.
*/
- ret->paste (*pl, (*i).start - start, 1.0f);
- delete pl;
+ ret->paste (pl, (*i).start - start, 1.0f);
}
}
- if (ret) {
- /* manually notify session of new playlist here
- because the playlists were constructed without notifying
- */
- PlaylistCreated (ret);
- }
-
return ret;
}
-Playlist*
+boost::shared_ptr<Playlist>
Playlist::cut (list<AudioRange>& ranges, bool result_is_hidden)
{
- Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
+ boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut;
return cut_copy (pmf, ranges, result_is_hidden);
}
-Playlist*
+boost::shared_ptr<Playlist>
Playlist::copy (list<AudioRange>& ranges, bool result_is_hidden)
{
- Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
+ boost::shared_ptr<Playlist> (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy;
return cut_copy (pmf, ranges, result_is_hidden);
}
-Playlist *
+boost::shared_ptr<Playlist>
Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
{
- Playlist *the_copy;
+ boost::shared_ptr<Playlist> the_copy;
RegionList thawlist;
char buf[32];
@@ -881,8 +882,8 @@ Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
new_name += '.';
new_name += buf;
- if ((the_copy = copyPlaylist (*this, start, cnt, new_name, result_is_hidden)) == 0) {
- return 0;
+ if ((the_copy = PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden)) == 0) {
+ return boost::shared_ptr<Playlist>();
}
partition_internal (start, start+cnt-1, true, thawlist);
@@ -895,7 +896,7 @@ Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden)
return the_copy;
}
-Playlist *
+boost::shared_ptr<Playlist>
Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
{
char buf[32];
@@ -906,28 +907,28 @@ Playlist::copy (nframes_t start, nframes_t cnt, bool result_is_hidden)
new_name += buf;
cnt = min (_get_maximum_extent() - start, cnt);
- return copyPlaylist (*this, start, cnt, new_name, result_is_hidden);
+ return PlaylistFactory::create (shared_from_this(), start, cnt, new_name, result_is_hidden);
}
int
-Playlist::paste (Playlist& other, nframes_t position, float times)
+Playlist::paste (boost::shared_ptr<Playlist> other, nframes_t position, float times)
{
times = fabs (times);
nframes_t old_length;
{
RegionLock rl1 (this);
- RegionLock rl2 (&other);
+ RegionLock rl2 (other.get());
old_length = _get_maximum_extent();
int itimes = (int) floor (times);
nframes_t pos = position;
- nframes_t shift = other._get_maximum_extent();
+ nframes_t shift = other->_get_maximum_extent();
layer_t top_layer = regions.size();
while (itimes--) {
- for (RegionList::iterator i = other.regions.begin(); i != other.regions.end(); ++i) {
+ for (RegionList::iterator i = other->regions.begin(); i != other->regions.end(); ++i) {
boost::shared_ptr<Region> copy_of_region = RegionFactory::create (*i);
/* put these new regions on top of all existing ones, but preserve
@@ -966,7 +967,7 @@ Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float
while (itimes--) {
boost::shared_ptr<Region> copy = RegionFactory::create (region);
- add_region_internal (copy, pos, true);
+ add_region_internal (copy, pos);
pos += region->length();
}
@@ -975,7 +976,7 @@ Playlist::duplicate (boost::shared_ptr<Region> region, nframes_t position, float
string name;
_session.region_name (name, region->name(), false);
boost::shared_ptr<Region> sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags());
- add_region_internal (sub, pos, true);
+ add_region_internal (sub, pos);
}
}
@@ -1010,7 +1011,7 @@ Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_pos
_session.region_name (after_name, region->name(), false);
right = RegionFactory::create (region, before, after, after_name, region->layer(), Region::Flag (region->flags()|Region::RightOfSplit));
- add_region_internal (left, region->position(), true);
+ add_region_internal (left, region->position());
add_region_internal (right, region->position() + before);
uint64_t orig_layer_op = region->last_layer_op();
@@ -1027,7 +1028,7 @@ Playlist::split_region (boost::shared_ptr<Region> region, nframes_t playlist_pos
finalize_split_region (region, left, right);
- if (remove_region_internal (region, true)) {
+ if (remove_region_internal (region)) {
return;
}
}
@@ -1118,7 +1119,6 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region>
}
if (what_changed & Change (ARDOUR::PositionChanged|ARDOUR::LengthChanged)) {
-
if (holding_state ()) {
pending_bounds.push_back (region);
} else {
@@ -1128,9 +1128,9 @@ Playlist::region_bounds_changed (Change what_changed, boost::shared_ptr<Region>
}
possibly_splice ();
- check_dependents (region, false);
notify_length_changed ();
relayer ();
+ check_dependents (region, false);
}
}
}
@@ -1397,6 +1397,10 @@ Playlist::set_state (const XMLNode& node)
}
}
+ notify_modified ();
+
+ thaw ();
+
/* update dependents, which was not done during add_region_internal
due to in_set_state being true
*/
@@ -1405,10 +1409,6 @@ Playlist::set_state (const XMLNode& node)
check_dependents (*r, false);
}
- notify_modified ();
-
- thaw ();
-
in_set_state--;
return 0;
diff --git a/libs/ardour/playlist_factory.cc b/libs/ardour/playlist_factory.cc
index 4461783874..862f85a402 100644
--- a/libs/ardour/playlist_factory.cc
+++ b/libs/ardour/playlist_factory.cc
@@ -22,24 +22,91 @@
#include <ardour/playlist.h>
#include <ardour/audioplaylist.h>
+#include <ardour/midi_playlist.h>
+#include <ardour/playlist_factory.h>
#include "i18n.h"
using namespace ARDOUR;
using namespace PBD;
-Playlist*
-Playlist::copyPlaylist (const Playlist& playlist, nframes_t start, nframes_t length,
- string name, bool result_is_hidden)
+sigc::signal<void,boost::shared_ptr<Playlist> > PlaylistFactory::PlaylistCreated;
+
+boost::shared_ptr<Playlist>
+PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden)
+{
+ const XMLProperty* type = node.property("type");
+
+ boost::shared_ptr<Playlist> pl;
+
+ if ( !type || type->value() == "audio" )
+ pl = boost::shared_ptr<Playlist> (new AudioPlaylist (s, node, hidden));
+ else if ( type->value() == "midi" )
+ pl = boost::shared_ptr<Playlist> (new MidiPlaylist (s, node, hidden));
+
+ pl->set_region_ownership ();
+
+ if (pl && !hidden) {
+ PlaylistCreated (pl);
+ }
+ return pl;
+}
+
+boost::shared_ptr<Playlist>
+PlaylistFactory::create (DataType type, Session& s, string name, bool hidden)
+{
+ boost::shared_ptr<Playlist> pl;
+
+ if (type == DataType::AUDIO)
+ pl = boost::shared_ptr<Playlist> (new AudioPlaylist (s, name, hidden));
+ else if (type == DataType::MIDI)
+ pl = boost::shared_ptr<Playlist> (new MidiPlaylist (s, name, hidden));
+
+ if (pl && !hidden) {
+ PlaylistCreated (pl);
+ }
+
+ return pl;
+}
+
+boost::shared_ptr<Playlist>
+PlaylistFactory::create (boost::shared_ptr<const Playlist> old, string name, bool hidden)
{
- const AudioPlaylist* apl;
-
- if ((apl = dynamic_cast<const AudioPlaylist*> (&playlist)) != 0) {
- return new AudioPlaylist (*apl, start, length, name, result_is_hidden);
- } else {
- fatal << _("programming error: Playlist::copyPlaylist called with unknown Playlist type")
- << endmsg;
- /*NOTREACHED*/
- return 0;
+ boost::shared_ptr<Playlist> pl;
+ boost::shared_ptr<const AudioPlaylist> apl;
+ boost::shared_ptr<const MidiPlaylist> mpl;
+
+ if ((apl = boost::dynamic_pointer_cast<const AudioPlaylist> (old)) != 0) {
+ pl = boost::shared_ptr<Playlist> (new AudioPlaylist (apl, name, hidden));
+ pl->set_region_ownership ();
+ } else if ((mpl = boost::dynamic_pointer_cast<const MidiPlaylist> (old)) != 0) {
+ pl = boost::shared_ptr<Playlist> (new MidiPlaylist (mpl, name, hidden));
+ pl->set_region_ownership ();
}
+
+ if (pl && !hidden) {
+ PlaylistCreated (pl);
+ }
+
+ return pl;
+}
+
+boost::shared_ptr<Playlist>
+PlaylistFactory::create (boost::shared_ptr<const Playlist> old, nframes_t start, nframes_t cnt, string name, bool hidden)
+{
+ boost::shared_ptr<Playlist> pl;
+ boost::shared_ptr<const AudioPlaylist> apl;
+ boost::shared_ptr<const MidiPlaylist> mpl;
+
+ if ((apl = boost::dynamic_pointer_cast<const AudioPlaylist> (old)) != 0) {
+ pl = boost::shared_ptr<Playlist> (new AudioPlaylist (apl, start, cnt, name, hidden));
+ pl->set_region_ownership ();
+ } else if ((mpl = boost::dynamic_pointer_cast<const MidiPlaylist> (old)) != 0) {
+ pl = boost::shared_ptr<Playlist> (new MidiPlaylist (mpl, start, cnt, name, hidden));
+ pl->set_region_ownership ();
+ }
+
+ /* this factory method does NOT notify others */
+
+ return pl;
}
diff --git a/libs/ardour/plugin_manager.cc b/libs/ardour/plugin_manager.cc
index b24b2619d3..09da4c9ca7 100644
--- a/libs/ardour/plugin_manager.cc
+++ b/libs/ardour/plugin_manager.cc
@@ -343,7 +343,7 @@ PluginManager::add_vst_directory (string path)
static bool vst_filter (const string& str, void *arg)
{
/* Not a dotfile, has a prefix before a period, suffix is "dll" */
-
+
return str[0] != '.' && (str.length() > 4 && str.find (".dll") == (str.length() - 4));
}
@@ -375,6 +375,7 @@ PluginManager::vst_discover (string path)
FSTInfo* finfo;
if ((finfo = fst_get_info (const_cast<char *> (path.c_str()))) == 0) {
+ warning << "Cannot get VST information from " << path << endmsg;
return -1;
}
diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc
index adad79e2a3..dbdd3d1ddd 100644
--- a/libs/ardour/redirect.cc
+++ b/libs/ardour/redirect.cc
@@ -28,6 +28,7 @@
#include <sigc++/bind.h>
#include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
#include <ardour/redirect.h>
#include <ardour/session.h>
@@ -58,6 +59,7 @@ Redirect::Redirect (Session& s, const string& name, Placement p,
Redirect::~Redirect ()
{
+ notify_callbacks ();
}
boost::shared_ptr<Redirect>
@@ -96,18 +98,6 @@ Redirect::set_placement (Placement p, void *src)
}
}
-void
-Redirect::set_placement (const string& str, void *src)
-{
- if (str == _("pre")) {
- set_placement (PreFader, this);
- } else if (str == _("post")) {
- set_placement (PostFader, this);
- } else {
- error << string_compose(_("Redirect: unknown placement string \"%1\" (ignored)"), str) << endmsg;
- }
-}
-
/* NODE STRUCTURE
<Automation [optionally with visible="...." ]>
@@ -194,7 +184,7 @@ Redirect::state (bool full_state)
stringstream sstr;
node->add_property("active", active() ? "yes" : "no");
- node->add_property("placement", placement_as_string (placement()));
+ node->add_property("placement", enum_2_string (_placement));
node->add_child_nocopy (IO::state (full_state));
if (_extra_xml){
@@ -294,7 +284,20 @@ Redirect::set_state (const XMLNode& node)
return -1;
}
- set_placement (prop->value(), this);
+ /* hack to handle older sessions before we only used EnumWriter */
+
+ string pstr;
+
+ if (prop->value() == "pre") {
+ pstr = "PreFader";
+ } else if (prop->value() == "post") {
+ pstr = "PostFader";
+ } else {
+ pstr = prop->value();
+ }
+
+ Placement p = Placement (string_2_enum (pstr, p));
+ set_placement (p, this);
return 0;
}
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 6d8c71b563..973e14fd31 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -65,7 +65,6 @@ Region::Region (boost::shared_ptr<Source> src, jack_nframes_t start, jack_nframe
, _read_data_count(0)
, _pending_changed(Change (0))
, _last_layer_op(0)
- , _playlist(0)
{
_sources.push_back (src);
_master_sources.push_back (src);
@@ -89,7 +88,6 @@ Region::Region (SourceList& srcs, jack_nframes_t start, jack_nframes_t length, c
, _read_data_count(0)
, _pending_changed(Change (0))
, _last_layer_op(0)
- , _playlist(0)
{
set<boost::shared_ptr<Source> > unique_srcs;
@@ -125,7 +123,6 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
, _read_data_count(0)
, _pending_changed(Change (0))
, _last_layer_op(0)
- , _playlist(0)
{
if (other->_sync_position < offset)
_sync_position = other->_sync_position;
@@ -167,7 +164,6 @@ Region::Region (boost::shared_ptr<const Region> other)
, _read_data_count(0)
, _pending_changed(Change(0))
, _last_layer_op(other->_last_layer_op)
- , _playlist(0)
{
other->_first_edit = EditChangesName;
@@ -209,10 +205,7 @@ Region::Region (SourceList& srcs, const XMLNode& node)
, _read_data_count(0)
, _pending_changed(Change(0))
, _last_layer_op(0)
- , _playlist(0)
-
{
-
set<boost::shared_ptr<Source> > unique_srcs;
for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) {
@@ -250,7 +243,6 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
, _read_data_count(0)
, _pending_changed(Change(0))
, _last_layer_op(0)
- , _playlist(0)
{
_sources.push_back (src);
@@ -265,9 +257,11 @@ Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
Region::~Region ()
{
- if (_playlist) {
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (pl) {
for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
- (*i)->remove_playlist (_playlist);
+ (*i)->remove_playlist (pl);
}
}
@@ -276,29 +270,30 @@ Region::~Region ()
}
void
-Region::set_playlist (Playlist* pl)
+Region::set_playlist (boost::weak_ptr<Playlist> wpl)
{
- if (pl == _playlist) {
+ boost::shared_ptr<Playlist> old_playlist = (_playlist.lock());
+ boost::shared_ptr<Playlist> pl (wpl.lock());
+
+ if (old_playlist == pl) {
return;
}
- Playlist* old_playlist = _playlist;
-
if (pl) {
if (old_playlist) {
for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
- (*i)->remove_playlist (old_playlist);
- (*i)->add_playlist (_playlist);
+ (*i)->remove_playlist (_playlist);
+ (*i)->add_playlist (pl);
}
} else {
for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
- (*i)->add_playlist (_playlist);
+ (*i)->add_playlist (pl);
}
}
} else {
if (old_playlist) {
for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
- (*i)->remove_playlist (old_playlist);
+ (*i)->remove_playlist (_playlist);
}
}
}
@@ -357,9 +352,11 @@ Region::maybe_uncopy ()
void
Region::first_edit ()
{
- if (_first_edit != EditChangesNothing && _playlist) {
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (_first_edit != EditChangesNothing && pl) {
- _name = _playlist->session().new_region_name (_name);
+ _name = pl->session().new_region_name (_name);
_first_edit = EditChangesNothing;
send_change (NameChanged);
@@ -370,7 +367,9 @@ Region::first_edit ()
bool
Region::at_natural_position () const
{
- if (!_playlist) {
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (!pl) {
return false;
}
@@ -388,7 +387,9 @@ Region::at_natural_position () const
void
Region::move_to_natural_position (void *src)
{
- if (!_playlist) {
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (!pl) {
return;
}
@@ -448,7 +449,11 @@ Region::set_position_on_top (nframes_t pos, void *src)
_position = pos;
}
- _playlist->raise_region_to_top (shared_from_this ());
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (pl) {
+ pl->raise_region_to_top (shared_from_this ());
+ }
/* do this even if the position is the same. this helps out
a GUI that has moved its representation already.
@@ -835,42 +840,37 @@ Region::sync_position() const
void
Region::raise ()
{
- if (_playlist == 0) {
- return;
+ boost::shared_ptr<Playlist> pl (playlist());
+ if (pl) {
+ pl->raise_region (shared_from_this ());
}
-
- _playlist->raise_region (shared_from_this ());
}
void
Region::lower ()
{
- if (_playlist == 0) {
- return;
+ boost::shared_ptr<Playlist> pl (playlist());
+ if (pl) {
+ pl->lower_region (shared_from_this ());
}
-
- _playlist->lower_region (shared_from_this ());
}
void
Region::raise_to_top ()
{
-
- if (_playlist == 0) {
- return;
+ boost::shared_ptr<Playlist> pl (playlist());
+ if (pl) {
+ pl->raise_region_to_top (shared_from_this());
}
-
- _playlist->raise_region_to_top (shared_from_this());
}
void
Region::lower_to_bottom ()
{
- if (_playlist == 0) {
- return;
+ boost::shared_ptr<Playlist> pl (playlist());
+ if (pl) {
+ pl->lower_region_to_bottom (shared_from_this());
}
-
- _playlist->lower_region_to_bottom (shared_from_this());
}
void
@@ -919,7 +919,7 @@ Region::state (bool full_state)
snprintf (buf, sizeof (buf), "%d", (int) _layer);
node->add_property ("layer", buf);
- snprintf (buf, sizeof (buf), "%u", _sync_position);
+ snprintf (buf, sizeof (buf), "%" PRIu32, _sync_position);
node->add_property ("sync-position", buf);
return *node;
@@ -1230,11 +1230,13 @@ Region::verify_start_mutable (jack_nframes_t& new_start)
boost::shared_ptr<Region>
Region::get_parent() const
{
- if (_playlist) {
+ boost::shared_ptr<Playlist> pl (playlist());
+
+ if (pl) {
boost::shared_ptr<Region> r;
boost::shared_ptr<Region const> grrr2 = boost::dynamic_pointer_cast<Region const> (shared_from_this());
- if (grrr2 && (r = _playlist->session().find_whole_file_parent (grrr2))) {
+ if (grrr2 && (r = pl->session().find_whole_file_parent (grrr2))) {
return boost::static_pointer_cast<Region> (r);
}
}
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 5314c99632..a2bc65407c 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -24,6 +24,7 @@
#include <sigc++/bind.h>
#include <pbd/xml++.h>
+#include <pbd/enumwriter.h>
#include <ardour/timestamps.h>
#include <ardour/audioengine.h>
@@ -889,6 +890,10 @@ Route::clear_redirects (void *src)
{
Glib::RWLock::WriterLock lm (redirect_lock);
+ RedirectList::iterator i;
+ for (i = _redirects.begin(); i != _redirects.end(); ++i) {
+ (*i)->drop_references ();
+ }
_redirects.clear ();
}
@@ -985,6 +990,8 @@ Route::remove_redirect (boost::shared_ptr<Redirect> redirect, void *src, uint32_
reset_panner ();
}
+ redirect->drop_references ();
+
redirects_changed (src); /* EMIT SIGNAL */
return 0;
}
@@ -1317,8 +1324,7 @@ Route::state(bool full_state)
char buf[32];
if (_flags) {
- snprintf (buf, sizeof (buf), "0x%x", _flags);
- node->add_property("flags", buf);
+ node->add_property("flags", enum_2_string (_flags));
}
node->add_property("default-type", _default_type.to_string());
@@ -1478,9 +1484,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
}
if ((prop = node.property (X_("flags"))) != 0) {
- int x;
- sscanf (prop->value().c_str(), "0x%x", &x);
- _flags = Flag (x);
+ _flags = Flag (string_2_enum (prop->value(), _flags));
} else {
_flags = Flag (0);
}
diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc
index 5730623742..c2aa59ed8b 100644
--- a/libs/ardour/route_group.cc
+++ b/libs/ardour/route_group.cc
@@ -26,6 +26,7 @@
#include <sigc++/bind.h>
#include <pbd/error.h>
+#include <pbd/enumwriter.h>
#include <ardour/route_group.h>
#include <ardour/audio_track.h>
@@ -125,11 +126,9 @@ RouteGroup::get_max_factor(gain_t factor)
XMLNode&
RouteGroup::get_state (void)
{
- char buf[32];
XMLNode *node = new XMLNode ("RouteGroup");
node->add_property ("name", _name);
- snprintf (buf, sizeof (buf), "%" PRIu32, (uint32_t) _flags);
- node->add_property ("flags", buf);
+ node->add_property ("flags", enum_2_string (_flags));
return *node;
}
@@ -143,7 +142,7 @@ RouteGroup::set_state (const XMLNode& node)
}
if ((prop = node.property ("flags")) != 0) {
- _flags = atoi (prop->value().c_str());
+ _flags = Flag (string_2_enum (prop->value(), _flags));
}
return 0;
@@ -157,9 +156,9 @@ RouteGroup::set_active (bool yn, void *src)
return;
}
if (yn) {
- _flags |= Active;
+ _flags = Flag (_flags | Active);
} else {
- _flags &= ~Active;
+ _flags = Flag (_flags & ~Active);
}
_session.set_dirty ();
FlagsChanged (src); /* EMIT SIGNAL */
@@ -173,9 +172,9 @@ RouteGroup::set_relative (bool yn, void *src)
return;
}
if (yn) {
- _flags |= Relative;
+ _flags = Flag (_flags | Relative);
} else {
- _flags &= ~Relative;
+ _flags = Flag (_flags & ~Relative);
}
_session.set_dirty ();
FlagsChanged (src); /* EMIT SIGNAL */
@@ -189,14 +188,14 @@ RouteGroup::set_hidden (bool yn, void *src)
return;
}
if (yn) {
- _flags |= Hidden;
+ _flags = Flag (_flags | Hidden);
if (Config->get_hiding_groups_deactivates_groups()) {
- _flags &= ~Active;
+ _flags = Flag (_flags & ~Active);
}
} else {
- _flags &= ~Hidden;
+ _flags = Flag (_flags & ~Hidden);
if (Config->get_hiding_groups_deactivates_groups()) {
- _flags |= Active;
+ _flags = Flag (_flags | Active);
}
}
_session.set_dirty ();
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index 73dbf11ad5..0141007803 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -34,7 +34,7 @@ using namespace ARDOUR;
using namespace PBD;
Send::Send (Session& s, Placement p)
- : Redirect (s, s.next_send_name(), p)
+ : Redirect (s, string_compose (_("send %1"), (bitslot = s.next_send_id()) + 1), p)
{
_metering = false;
RedirectCreated (this); /* EMIT SIGNAL */
@@ -53,7 +53,7 @@ Send::Send (Session& s, const XMLNode& node)
}
Send::Send (const Send& other)
- : Redirect (other._session, other._session.next_send_name(), other.placement())
+ : Redirect (other._session, string_compose (_("send %1"), (bitslot = other._session.next_send_id()) + 1), other.placement())
{
_metering = false;
RedirectCreated (this); /* EMIT SIGNAL */
@@ -74,7 +74,10 @@ XMLNode&
Send::state(bool full)
{
XMLNode *node = new XMLNode("Send");
+ char buf[32];
node->add_child_nocopy (Redirect::state (full));
+ snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
+ node->add_property ("bitslot", buf);
return *node;
}
@@ -83,6 +86,14 @@ Send::set_state(const XMLNode& node)
{
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
+ const XMLProperty* prop;
+
+ if ((prop = node.property ("bitslot")) == 0) {
+ bitslot = _session.next_send_id();
+ } else {
+ sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
+ _session.mark_send_id (bitslot);
+ }
/* Send has regular IO automation (gain, pan) */
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 1b7c3be6dd..6ad8f7dbd2 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -40,6 +40,7 @@
#include <pbd/pathscanner.h>
#include <pbd/stl_delete.h>
#include <pbd/basename.h>
+#include <pbd/stacktrace.h>
#include <ardour/audioengine.h>
#include <ardour/configuration.h>
@@ -290,12 +291,13 @@ Session::Session (AudioEngine &eng,
if (new_session) {
if (create (new_session, mix_template, compute_initial_length())) {
cerr << "create failed\n";
+ destroy ();
throw failed_constructor ();
}
}
if (second_stage_init (new_session)) {
- cerr << "2nd state failed\n";
+ destroy ();
throw failed_constructor ();
}
@@ -359,6 +361,7 @@ Session::Session (AudioEngine &eng,
if (new_session) {
if (create (new_session, 0, initial_length)) {
+ destroy ();
throw failed_constructor ();
}
}
@@ -386,6 +389,7 @@ Session::Session (AudioEngine &eng,
Config->set_output_auto_connect (output_ac);
if (second_stage_init (new_session)) {
+ destroy ();
throw failed_constructor ();
}
@@ -402,6 +406,12 @@ Session::Session (AudioEngine &eng,
Session::~Session ()
{
+ destroy ();
+}
+
+void
+Session::destroy ()
+{
/* if we got to here, leaving pending capture state around
is a mistake.
*/
@@ -469,10 +479,24 @@ Session::~Session ()
tmp = i;
++tmp;
- delete *i;
+ (*i)->drop_references ();
+
+ i = tmp;
+ }
+
+ for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) {
+ PlaylistList::iterator tmp;
+
+ tmp = i;
+ ++tmp;
+
+ (*i)->drop_references ();
i = tmp;
}
+
+ playlists.clear ();
+ unused_playlists.clear ();
#ifdef TRACK_DESTRUCTION
cerr << "delete regions\n";
@@ -619,8 +643,6 @@ Session::when_engine_running ()
/* we don't want to run execute this again */
- first_time_running.disconnect ();
-
set_block_size (_engine.frames_per_cycle());
set_frame_rate (_engine.frame_rate());
@@ -685,23 +707,6 @@ Session::when_engine_running ()
// XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
}
- if (auditioner == 0) {
-
- /* we delay creating the auditioner till now because
- it makes its own connections to ports named
- in the ARDOUR_RC config file. the engine has
- to be running for this to work.
- */
-
- try {
- auditioner.reset (new Auditioner (*this));
- }
-
- catch (failed_constructor& err) {
- warning << _("cannot create Auditioner: no auditioning of regions possible") << endmsg;
- }
- }
-
/* Create a set of Connection objects that map
to the physical outputs currently available
*/
@@ -841,6 +846,7 @@ Session::when_engine_running ()
}
}
+
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
/* hook us up to the engine */
@@ -867,6 +873,22 @@ Session::hookup_io ()
_state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting);
+ if (auditioner == 0) {
+
+ /* we delay creating the auditioner till now because
+ it makes its own connections to ports.
+ the engine has to be running for this to work.
+ */
+
+ try {
+ auditioner.reset (new Auditioner (*this));
+ }
+
+ catch (failed_constructor& err) {
+ warning << _("cannot create Auditioner: no auditioning of regions possible") << endmsg;
+ }
+ }
+
/* Tell all IO objects to create their ports */
IO::enable_ports ();
@@ -918,7 +940,7 @@ Session::hookup_io ()
}
void
-Session::playlist_length_changed (Playlist* pl)
+Session::playlist_length_changed ()
{
/* we can't just increase end_location->end() if pl->get_maximum_extent()
if larger. if the playlist used to be the longest playlist,
@@ -932,10 +954,10 @@ Session::playlist_length_changed (Playlist* pl)
void
Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream)
{
- Playlist *playlist;
+ boost::shared_ptr<Playlist> playlist;
if ((playlist = dstream->playlist()) != 0) {
- playlist->LengthChanged.connect (sigc::bind (mem_fun (this, &Session::playlist_length_changed), playlist));
+ playlist->LengthChanged.connect (mem_fun (this, &Session::playlist_length_changed));
}
/* see comment in playlist_length_changed () */
@@ -2317,7 +2339,7 @@ Session::get_maximum_extent () const
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) {
- Playlist* pl = (*i)->playlist();
+ boost::shared_ptr<Playlist> pl = (*i)->playlist();
if ((me = pl->get_maximum_extent()) > max) {
max = me;
}
@@ -2697,14 +2719,10 @@ Session::add_source (boost::shared_ptr<Source> source)
result = sources.insert (entry);
}
- if (!result.second) {
- cerr << "\tNOT inserted ? " << result.second << endl;
+ if (result.second) {
+ source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source)));
+ set_dirty();
}
-
- source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source)));
- set_dirty();
-
- SourceAdded (source); /* EMIT SIGNAL */
}
void
@@ -2737,8 +2755,6 @@ Session::remove_source (boost::weak_ptr<Source> src)
save_state (_current_snapshot_name);
}
-
- SourceRemoved(source); /* EMIT SIGNAL */
}
boost::shared_ptr<Source>
@@ -2924,6 +2940,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
} else {
snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str());
}
+
} else {
spath += '/';
@@ -2956,6 +2973,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
if (cnt > limit) {
error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg;
+ destroy ();
throw failed_constructor();
}
}
@@ -2967,6 +2985,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
string foo = buf;
spath = discover_best_sound_dir ();
+ spath += '/';
string::size_type pos = foo.find_last_of ('/');
@@ -3176,7 +3195,7 @@ Session::create_midi_source_for_session (MidiDiskstream& ds)
/* Playlist management */
-Playlist *
+boost::shared_ptr<Playlist>
Session::playlist_by_name (string name)
{
Glib::Mutex::Lock lm (playlist_lock);
@@ -3190,11 +3209,12 @@ Session::playlist_by_name (string name)
return* i;
}
}
- return 0;
+
+ return boost::shared_ptr<Playlist>();
}
void
-Session::add_playlist (Playlist* playlist)
+Session::add_playlist (boost::shared_ptr<Playlist> playlist)
{
if (playlist->hidden()) {
return;
@@ -3204,9 +3224,8 @@ Session::add_playlist (Playlist* playlist)
Glib::Mutex::Lock lm (playlist_lock);
if (find (playlists.begin(), playlists.end(), playlist) == playlists.end()) {
playlists.insert (playlists.begin(), playlist);
- // playlist->ref();
- playlist->InUse.connect (mem_fun (*this, &Session::track_playlist));
- playlist->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_playlist), playlist));
+ playlist->InUse.connect (sigc::bind (mem_fun (*this, &Session::track_playlist), boost::weak_ptr<Playlist>(playlist)));
+ playlist->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_playlist), boost::weak_ptr<Playlist>(playlist)));
}
}
@@ -3216,7 +3235,7 @@ Session::add_playlist (Playlist* playlist)
}
void
-Session::get_playlists (vector<Playlist*>& s)
+Session::get_playlists (vector<boost::shared_ptr<Playlist> >& s)
{
{
Glib::Mutex::Lock lm (playlist_lock);
@@ -3230,15 +3249,25 @@ Session::get_playlists (vector<Playlist*>& s)
}
void
-Session::track_playlist (Playlist* pl, bool inuse)
+Session::track_playlist (bool inuse, boost::weak_ptr<Playlist> wpl)
{
+ boost::shared_ptr<Playlist> pl(wpl.lock());
+
+ if (!pl) {
+ return;
+ }
+
PlaylistList::iterator x;
+ if (pl->hidden()) {
+ /* its not supposed to be visible */
+ return;
+ }
+
{
Glib::Mutex::Lock lm (playlist_lock);
if (!inuse) {
- //cerr << "shifting playlist to unused: " << pl->name() << endl;
unused_playlists.insert (pl);
@@ -3248,8 +3277,7 @@ Session::track_playlist (Playlist* pl, bool inuse)
} else {
- //cerr << "shifting playlist to used: " << pl->name() << endl;
-
+
playlists.insert (pl);
if ((x = unused_playlists.find (pl)) != unused_playlists.end()) {
@@ -3260,20 +3288,24 @@ Session::track_playlist (Playlist* pl, bool inuse)
}
void
-Session::remove_playlist (Playlist* playlist)
+Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist)
{
if (_state_of_the_state & Deletion) {
return;
}
+ boost::shared_ptr<Playlist> playlist (weak_playlist.lock());
+
+ if (!playlist) {
+ return;
+ }
+
{
Glib::Mutex::Lock lm (playlist_lock);
- // cerr << "removing playlist: " << playlist->name() << endl;
PlaylistList::iterator i;
i = find (playlists.begin(), playlists.end(), playlist);
-
if (i != playlists.end()) {
playlists.erase (i);
}
@@ -3451,6 +3483,12 @@ Session::graph_reordered ()
return;
}
+ /* every track/bus asked for this to be handled but it was deferred because
+ we were connecting. do it now.
+ */
+
+ request_input_change_handling ();
+
resort_routes ();
/* force all diskstreams to update their capture offset values to
@@ -3528,18 +3566,28 @@ Session::remove_redirect (Redirect* redirect)
Insert* insert;
PortInsert* port_insert;
PluginInsert* plugin_insert;
-
+
if ((insert = dynamic_cast<Insert *> (redirect)) != 0) {
if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
- _port_inserts.remove (port_insert);
+ list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert);
+ if (x != _port_inserts.end()) {
+ insert_bitset[port_insert->bit_slot()] = false;
+ _port_inserts.erase (x);
+ }
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
_plugin_inserts.remove (plugin_insert);
} else {
- fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
+ fatal << string_compose (_("programming error: %1"),
+ X_("unknown type of Insert deleted!"))
+ << endmsg;
/*NOTREACHED*/
}
} else if ((send = dynamic_cast<Send *> (redirect)) != 0) {
- _sends.remove (send);
+ list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
+ if (x != _sends.end()) {
+ send_bitset[send->bit_slot()] = false;
+ _sends.erase (x);
+ }
} else {
fatal << _("programming error: unknown type of Redirect deleted!") << endmsg;
/*NOTREACHED*/
@@ -3561,6 +3609,13 @@ Session::available_capture_duration ()
case FormatInt24:
sample_bytes_on_disk = 3;
break;
+
+ default:
+ /* impossible, but keep some gcc versions happy */
+ fatal << string_compose (_("programming error: %1"),
+ X_("illegal native file data format"))
+ << endmsg;
+ /*NOTREACHED*/
}
double scale = 4096.0 / sample_bytes_on_disk;
@@ -3642,20 +3697,70 @@ Session::ensure_buffers (ChanCount howmany)
allocate_pan_automation_buffers (current_block_size, howmany.get(DataType::AUDIO), false);
}
-string
-Session::next_send_name ()
+uint32_t
+Session::next_insert_id ()
{
- char buf[32];
- snprintf (buf, sizeof (buf), "send %" PRIu32, ++send_cnt);
- return buf;
+ /* this doesn't really loop forever. just think about it */
+
+ while (true) {
+ for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < insert_bitset.size(); ++n) {
+ if (!insert_bitset[n]) {
+ insert_bitset[n] = true;
+ cerr << "Returning " << n << " as insert ID\n";
+ return n;
+
+ }
+ }
+
+ /* none available, so resize and try again */
+
+ insert_bitset.resize (insert_bitset.size() + 16, false);
+ }
}
-string
-Session::next_insert_name ()
+uint32_t
+Session::next_send_id ()
{
- char buf[32];
- snprintf (buf, sizeof (buf), "insert %" PRIu32, ++insert_cnt);
- return buf;
+ /* this doesn't really loop forever. just think about it */
+
+ while (true) {
+ for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < send_bitset.size(); ++n) {
+ if (!send_bitset[n]) {
+ send_bitset[n] = true;
+ cerr << "Returning " << n << " as send ID\n";
+ return n;
+
+ }
+ }
+
+ /* none available, so resize and try again */
+
+ send_bitset.resize (send_bitset.size() + 16, false);
+ }
+}
+
+void
+Session::mark_send_id (uint32_t id)
+{
+ if (id >= send_bitset.size()) {
+ send_bitset.resize (id+16, false);
+ }
+ if (send_bitset[id]) {
+ warning << string_compose (_("send ID %1 appears to be in use already"), id) << endmsg;
+ }
+ send_bitset[id] = true;
+}
+
+void
+Session::mark_insert_id (uint32_t id)
+{
+ if (id >= insert_bitset.size()) {
+ insert_bitset.resize (id+16, false);
+ }
+ if (insert_bitset[id]) {
+ warning << string_compose (_("insert ID %1 appears to be in use already"), id) << endmsg;
+ }
+ insert_bitset[id] = true;
}
/* Named Selection management */
@@ -3732,12 +3837,6 @@ Session::route_name_unique (string n) const
return true;
}
-int
-Session::cleanup_audio_file_source (boost::shared_ptr<AudioFileSource> fs)
-{
- return fs->move_to_trash (dead_sound_dir_name);
-}
-
uint32_t
Session::n_playlists () const
{
@@ -3794,18 +3893,17 @@ int
Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,
bool overwrite, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt)
{
+ int ret = -1;
+ boost::shared_ptr<Playlist> playlist;
boost::shared_ptr<AudioFileSource> fsource;
-
- int ret = -1;
- Playlist* playlist = 0;
- uint32_t x;
- char buf[PATH_MAX+1];
- string dir;
- ChanCount nchans(track.audio_diskstream()->n_channels());
- jack_nframes_t position;
- jack_nframes_t this_chunk;
- jack_nframes_t to_do;
- BufferSet buffers;
+ uint32_t x;
+ char buf[PATH_MAX+1];
+ string dir;
+ ChanCount nchans(track.audio_diskstream()->n_channels());
+ nframes_t position;
+ nframes_t this_chunk;
+ nframes_t to_do;
+ BufferSet buffers;
// any bigger than this seems to cause stack overflows in called functions
const nframes_t chunk_size = (128 * 1024)/4;
@@ -3915,7 +4013,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
/* construct a region to represent the bounced material */
boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
- region_name_from_path (srcs.front()->name()));
+ region_name_from_path (srcs.front()->name(), true));
ret = 0;
}
diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc
index 832284901c..bb02eede91 100644
--- a/libs/ardour/session_butler.cc
+++ b/libs/ardour/session_butler.cc
@@ -157,8 +157,6 @@ Session::_butler_thread_work (void* arg)
return 0;
}
-#define transport_work_requested() g_atomic_int_get(&butler_should_do_transport_work)
-
void *
Session::butler_thread_work ()
{
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index 5816f1c6b7..9d054c22fd 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -11,18 +11,22 @@
#include <ardour/midi_source.h>
#include <ardour/midi_region.h>
#include <pbd/error.h>
-using namespace PBD;
-#include "i18n.h"
+#include <pbd/id.h>
+#include <pbd/statefuldestructible.h>
+#include <pbd/failed_constructor.h>
+using namespace PBD;
+using namespace ARDOUR;
-namespace ARDOUR {
+#include "i18n.h"
void Session::register_with_memento_command_factory(PBD::ID id, PBD::StatefulThingWithGoingAway *ptr)
{
registry[id] = ptr;
}
-Command *Session::memento_command_factory(XMLNode *n)
+Command *
+Session::memento_command_factory(XMLNode *n)
{
PBD::ID id;
XMLNode *before = 0, *after = 0;
@@ -70,8 +74,9 @@ Command *Session::memento_command_factory(XMLNode *n)
} else if (obj_T == typeid (TempoMap).name()) {
return new MementoCommand<TempoMap>(*_tempo_map, before, after);
} else if (obj_T == typeid (Playlist).name() || obj_T == typeid (AudioPlaylist).name()) {
- if (Playlist *pl = playlist_by_name(child->property("name")->value()))
- return new MementoCommand<Playlist>(*pl, before, after);
+ if (boost::shared_ptr<Playlist> pl = playlist_by_name(child->property("name")->value())) {
+ return new MementoCommand<Playlist>(*(pl.get()), before, after);
+ }
} else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) {
return new MementoCommand<Route>(*route_by_id(id), before, after);
} else if (obj_T == typeid (Curve).name() || obj_T == typeid (AutomationList).name()) {
@@ -86,100 +91,425 @@ Command *Session::memento_command_factory(XMLNode *n)
return 0 ;
}
+Command *
+Session::global_state_command_factory (const XMLNode& node)
+{
+ const XMLProperty* prop;
+ Command* command = 0;
+
+ if ((prop = node.property ("type")) == 0) {
+ error << _("GlobalRouteStateCommand has no \"type\" node, ignoring") << endmsg;
+ return 0;
+ }
+
+ try {
+
+ if (prop->value() == "solo") {
+ command = new GlobalSoloStateCommand (*this, node);
+ } else if (prop->value() == "mute") {
+ command = new GlobalMuteStateCommand (*this, node);
+ } else if (prop->value() == "rec-enable") {
+ command = new GlobalRecordEnableStateCommand (*this, node);
+ } else if (prop->value() == "metering") {
+ command = new GlobalMeteringStateCommand (*this, node);
+ } else {
+ error << string_compose (_("unknown type of GlobalRouteStateCommand (%1), ignored"), prop->value()) << endmsg;
+ }
+ }
+
+ catch (failed_constructor& err) {
+ return 0;
+ }
+
+ return command;
+}
+
+Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, void* p)
+ : sess (s), src (p)
+{
+}
+
+Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, const XMLNode& node)
+ : sess (s), src (this)
+{
+ if (set_state (node)) {
+ throw failed_constructor ();
+ }
+}
+
+int
+Session::GlobalRouteStateCommand::set_state (const XMLNode& node)
+{
+ GlobalRouteBooleanState states;
+ XMLNodeList nlist;
+ const XMLProperty* prop;
+ XMLNode* child;
+ XMLNodeConstIterator niter;
+ int loop;
+
+ before.clear ();
+ after.clear ();
+
+ for (loop = 0; loop < 2; ++loop) {
+
+ const char *str;
+
+ if (loop) {
+ str = "after";
+ } else {
+ str = "before";
+ }
+
+ if ((child = node.child (str)) == 0) {
+ warning << string_compose (_("global route state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
+ return -1;
+ }
+
+ nlist = child->children();
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+ RouteBooleanState rbs;
+ boost::shared_ptr<Route> route;
+ ID id;
+
+ prop = (*niter)->property ("id");
+ id = prop->value ();
+
+ if ((route = sess.route_by_id (id)) == 0) {
+ warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
+ continue;
+ }
+
+ rbs.first = boost::weak_ptr<Route> (route);
+
+ prop = (*niter)->property ("yn");
+ rbs.second = (prop->value() == "1");
+
+ if (loop) {
+ after.push_back (rbs);
+ } else {
+ before.push_back (rbs);
+ }
+ }
+ }
+
+ return 0;
+}
+
+XMLNode&
+Session::GlobalRouteStateCommand::get_state ()
+{
+ XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
+ XMLNode* nbefore = new XMLNode (X_("before"));
+ XMLNode* nafter = new XMLNode (X_("after"));
+
+ for (Session::GlobalRouteBooleanState::iterator x = before.begin(); x != before.end(); ++x) {
+ XMLNode* child = new XMLNode ("s");
+ boost::shared_ptr<Route> r = x->first.lock();
+
+ if (r) {
+ child->add_property (X_("id"), r->id().to_s());
+ child->add_property (X_("yn"), (x->second ? "1" : "0"));
+ nbefore->add_child_nocopy (*child);
+ }
+ }
+
+ for (Session::GlobalRouteBooleanState::iterator x = after.begin(); x != after.end(); ++x) {
+ XMLNode* child = new XMLNode ("s");
+ boost::shared_ptr<Route> r = x->first.lock();
+
+ if (r) {
+ child->add_property (X_("id"), r->id().to_s());
+ child->add_property (X_("yn"), (x->second ? "1" : "0"));
+ nafter->add_child_nocopy (*child);
+ }
+ }
+
+ node->add_child_nocopy (*nbefore);
+ node->add_child_nocopy (*nafter);
+
+ return *node;
+}
+
// solo
+
Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src)
- : sess(sess), src(src)
+ : GlobalRouteStateCommand (sess, src)
{
after = before = sess.get_global_route_boolean(&Route::soloed);
}
-void Session::GlobalSoloStateCommand::mark()
+
+Session::GlobalSoloStateCommand::GlobalSoloStateCommand (Session& sess, const XMLNode& node)
+ : Session::GlobalRouteStateCommand (sess, node)
+{
+}
+
+void
+Session::GlobalSoloStateCommand::mark()
{
after = sess.get_global_route_boolean(&Route::soloed);
}
-void Session::GlobalSoloStateCommand::operator()()
+
+void
+Session::GlobalSoloStateCommand::operator()()
{
sess.set_global_solo(after, src);
}
-void Session::GlobalSoloStateCommand::undo()
+
+void
+Session::GlobalSoloStateCommand::undo()
{
sess.set_global_solo(before, src);
}
-XMLNode &Session::GlobalSoloStateCommand::get_state()
+
+XMLNode&
+Session::GlobalSoloStateCommand::get_state()
{
- XMLNode *node = new XMLNode("GlobalSoloStateCommand");
- return *node;
+ XMLNode& node = GlobalRouteStateCommand::get_state();
+ node.add_property ("type", "solo");
+ return node;
}
// mute
Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src)
- : sess(sess), src(src)
+ : GlobalRouteStateCommand (sess, src)
{
after = before = sess.get_global_route_boolean(&Route::muted);
}
-void Session::GlobalMuteStateCommand::mark()
+
+Session::GlobalMuteStateCommand::GlobalMuteStateCommand (Session& sess, const XMLNode& node)
+ : Session::GlobalRouteStateCommand (sess, node)
{
- after = sess.get_global_route_boolean(&Route::muted);
}
-void Session::GlobalMuteStateCommand::operator()()
+
+void
+Session::GlobalMuteStateCommand::mark()
{
- sess.set_global_mute(after, src);
+ after = sess.get_global_route_boolean(&Route::muted);
}
-void Session::GlobalMuteStateCommand::undo()
+
+void
+Session::GlobalMuteStateCommand::operator()()
{
- sess.set_global_mute(before, src);
+ sess.set_global_mute(after, src);
}
-XMLNode &Session::GlobalMuteStateCommand::get_state()
+
+void
+Session::GlobalMuteStateCommand::undo()
{
- XMLNode *node = new XMLNode("GlobalMuteStateCommand");
- return *node;
+ sess.set_global_mute(before, src);
+}
+
+XMLNode&
+Session::GlobalMuteStateCommand::get_state()
+{
+ XMLNode& node = GlobalRouteStateCommand::get_state();
+ node.add_property ("type", "mute");
+ return node;
}
// record enable
Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src)
- : sess(sess), src(src)
+ : GlobalRouteStateCommand (sess, src)
+{
+ after = before = sess.get_global_route_boolean(&Route::record_enabled);
+}
+
+Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand (Session& sess, const XMLNode& node)
+ : Session::GlobalRouteStateCommand (sess, node)
{
- after = before = sess.get_global_route_boolean(&Route::record_enabled);
}
-void Session::GlobalRecordEnableStateCommand::mark()
+
+void
+Session::GlobalRecordEnableStateCommand::mark()
{
- after = sess.get_global_route_boolean(&Route::record_enabled);
+ after = sess.get_global_route_boolean(&Route::record_enabled);
}
-void Session::GlobalRecordEnableStateCommand::operator()()
+
+void
+Session::GlobalRecordEnableStateCommand::operator()()
{
- sess.set_global_record_enable(after, src);
+ sess.set_global_record_enable(after, src);
}
-void Session::GlobalRecordEnableStateCommand::undo()
+
+void
+Session::GlobalRecordEnableStateCommand::undo()
{
- sess.set_global_record_enable(before, src);
+ sess.set_global_record_enable(before, src);
}
-XMLNode &Session::GlobalRecordEnableStateCommand::get_state()
+
+XMLNode&
+Session::GlobalRecordEnableStateCommand::get_state()
{
- XMLNode *node = new XMLNode("GlobalRecordEnableStateCommand");
- return *node;
+ XMLNode& node = GlobalRouteStateCommand::get_state();
+ node.add_property ("type", "rec-enable");
+ return node;
}
// metering
-Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &sess, void *src)
- : sess(sess), src(src)
+Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &s, void *p)
+ : sess (s), src (p)
{
- after = before = sess.get_global_route_metering();
+ after = before = sess.get_global_route_metering();
}
-void Session::GlobalMeteringStateCommand::mark()
+
+Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand (Session& s, const XMLNode& node)
+ : sess (s), src (this)
{
- after = sess.get_global_route_metering();
+ if (set_state (node)) {
+ throw failed_constructor();
+ }
}
-void Session::GlobalMeteringStateCommand::operator()()
+
+void
+Session::GlobalMeteringStateCommand::mark()
{
- sess.set_global_route_metering(after, src);
+ after = sess.get_global_route_metering();
}
-void Session::GlobalMeteringStateCommand::undo()
+
+void
+Session::GlobalMeteringStateCommand::operator()()
{
- sess.set_global_route_metering(before, src);
+ sess.set_global_route_metering(after, src);
}
-XMLNode &Session::GlobalMeteringStateCommand::get_state()
+
+void
+Session::GlobalMeteringStateCommand::undo()
{
- XMLNode *node = new XMLNode("GlobalMeteringStateCommand");
- return *node;
+ sess.set_global_route_metering(before, src);
}
-} // namespace ARDOUR
+XMLNode&
+Session::GlobalMeteringStateCommand::get_state()
+{
+ XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
+ XMLNode* nbefore = new XMLNode (X_("before"));
+ XMLNode* nafter = new XMLNode (X_("after"));
+
+ for (Session::GlobalRouteMeterState::iterator x = before.begin(); x != before.end(); ++x) {
+ XMLNode* child = new XMLNode ("s");
+ boost::shared_ptr<Route> r = x->first.lock();
+
+ if (r) {
+ child->add_property (X_("id"), r->id().to_s());
+
+ const char* meterstr;
+
+ switch (x->second) {
+ case MeterInput:
+ meterstr = X_("input");
+ break;
+ case MeterPreFader:
+ meterstr = X_("pre");
+ break;
+ case MeterPostFader:
+ meterstr = X_("post");
+ break;
+ }
+
+ child->add_property (X_("meter"), meterstr);
+ nbefore->add_child_nocopy (*child);
+ }
+ }
+
+ for (Session::GlobalRouteMeterState::iterator x = after.begin(); x != after.end(); ++x) {
+ XMLNode* child = new XMLNode ("s");
+ boost::shared_ptr<Route> r = x->first.lock();
+
+ if (r) {
+ child->add_property (X_("id"), r->id().to_s());
+
+ const char* meterstr;
+
+ switch (x->second) {
+ case MeterInput:
+ meterstr = X_("input");
+ break;
+ case MeterPreFader:
+ meterstr = X_("pre");
+ break;
+ case MeterPostFader:
+ meterstr = X_("post");
+ break;
+ }
+
+ child->add_property (X_("meter"), meterstr);
+ nafter->add_child_nocopy (*child);
+ }
+ }
+
+ node->add_child_nocopy (*nbefore);
+ node->add_child_nocopy (*nafter);
+
+ node->add_property ("type", "metering");
+
+ return *node;
+}
+
+int
+Session::GlobalMeteringStateCommand::set_state (const XMLNode& node)
+{
+ GlobalRouteBooleanState states;
+ XMLNodeList nlist;
+ const XMLProperty* prop;
+ XMLNode* child;
+ XMLNodeConstIterator niter;
+ int loop;
+
+ before.clear ();
+ after.clear ();
+
+ for (loop = 0; loop < 2; ++loop) {
+
+ const char *str;
+
+ if (loop) {
+ str = "after";
+ } else {
+ str = "before";
+ }
+
+ if ((child = node.child (str)) == 0) {
+ warning << string_compose (_("global route meter state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
+ return -1;
+ }
+
+ nlist = child->children();
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+ RouteMeterState rms;
+ boost::shared_ptr<Route> route;
+ ID id;
+
+ prop = (*niter)->property ("id");
+ id = prop->value ();
+
+ if ((route = sess.route_by_id (id)) == 0) {
+ warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
+ continue;
+ }
+
+ rms.first = boost::weak_ptr<Route> (route);
+
+ prop = (*niter)->property ("meter");
+
+ if (prop->value() == X_("pre")) {
+ rms.second = MeterPreFader;
+ } else if (prop->value() == X_("post")) {
+ rms.second = MeterPostFader;
+ } else {
+ rms.second = MeterInput;
+ }
+
+ if (loop) {
+ after.push_back (rms);
+ } else {
+ before.push_back (rms);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc
index dc7eabf40f..981f9505d9 100644
--- a/libs/ardour/session_events.cc
+++ b/libs/ardour/session_events.cc
@@ -305,9 +305,14 @@ Session::process_event (Event* ev)
*/
if (non_realtime_work_pending()) {
- immediate_events.insert (immediate_events.end(), ev);
- _remove_event (ev);
- return;
+
+ /* except locates, which we have the capability to handle */
+
+ if (ev->type != Event::Locate) {
+ immediate_events.insert (immediate_events.end(), ev);
+ _remove_event (ev);
+ return;
+ }
}
//printf("Processing event: %s\n", event_names[ev->type]);
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index b3a5ec6e01..18bf9b83e1 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -581,7 +581,7 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps)
}
double diff_secs = diff.tv_sec + (diff.tv_usec / 1000000.0);
- double cur_speed = (((steps * 0.5) * Config->get_smpte_frames_per_second()) / diff_secs) / Config->get_smpte_frames_per_second();
+ double cur_speed = (((steps * 0.5) * smpte_frames_per_second()) / diff_secs) / smpte_frames_per_second();
if (_transport_speed == 0 || cur_speed * _transport_speed < 0) {
/* change direction */
@@ -640,6 +640,8 @@ Session::mmc_locate (MIDI::MachineControl &mmc, const MIDI::byte* mmc_tc)
smpte.minutes = mmc_tc[1];
smpte.seconds = mmc_tc[2];
smpte.frames = mmc_tc[3];
+ smpte.rate = smpte_frames_per_second();
+ smpte.drop = smpte_drop_frames();
// Also takes smpte offset into account:
smpte_to_sample( smpte, target_frame, true /* use_offset */, false /* use_subframes */ );
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index c877abdca4..2de3448cd1 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -57,7 +57,7 @@ Session::process (nframes_t nframes)
}
if (non_realtime_work_pending()) {
- if (g_atomic_int_get (&butler_should_do_transport_work) == 0) {
+ if (!transport_work_requested ()) {
post_transport ();
}
}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index bcc9b730ba..097a9e2381 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -43,8 +43,8 @@
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#else
-#include <sys/mount.h>
#include <sys/param.h>
+#include <sys/mount.h>
#endif
#include <glibmm.h>
@@ -57,6 +57,8 @@
#include <pbd/pathscanner.h>
#include <pbd/pthread_utils.h>
#include <pbd/strsplit.h>
+#include <pbd/stacktrace.h>
+#include <pbd/copyfile.h>
#include <ardour/audioengine.h>
#include <ardour/configuration.h>
@@ -93,6 +95,7 @@
#include <ardour/control_protocol_manager.h>
#include <ardour/region_factory.h>
#include <ardour/source_factory.h>
+#include <ardour/playlist_factory.h>
#include <control_protocol/control_protocol.h>
@@ -107,12 +110,14 @@ void
Session::first_stage_init (string fullpath, string snapshot_name)
{
if (fullpath.length() == 0) {
+ destroy ();
throw failed_constructor();
}
char buf[PATH_MAX+1];
if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
+ destroy ();
throw failed_constructor();
}
@@ -133,7 +138,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
g_atomic_int_set (&processing_prohibited, 0);
- send_cnt = 0;
insert_cnt = 0;
_transport_speed = 0;
_last_transport_speed = 0;
@@ -164,7 +168,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_worst_output_latency = 0;
_worst_input_latency = 0;
_worst_track_latency = 0;
- _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
+ _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading|Deletion);
_slave = 0;
butler_mixdown_buffer = 0;
butler_gain_buffer = 0;
@@ -247,7 +251,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
RegionFactory::CheckNewRegion.connect (mem_fun (*this, &Session::add_region));
SourceFactory::SourceCreated.connect (mem_fun (*this, &Session::add_source));
- Playlist::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
+ PlaylistFactory::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
@@ -316,10 +320,20 @@ Session::second_stage_init (bool new_session)
_engine.Halted.connect (mem_fun (*this, &Session::engine_halted));
_engine.Xrun.connect (mem_fun (*this, &Session::xrun_recovery));
- if (_engine.running()) {
+ try {
when_engine_running();
- } else {
- first_time_running = _engine.Running.connect (mem_fun (*this, &Session::when_engine_running));
+ }
+
+ /* handle this one in a different way than all others, so that its clear what happened */
+
+ catch (AudioEngine::PortRegistrationFailure& err) {
+ error << _("Unable to create all required ports")
+ << endmsg;
+ return -1;
+ }
+
+ catch (...) {
+ return -1;
}
//send_full_time_code ();
@@ -391,6 +405,7 @@ Session::setup_raid_path (string path)
if (fspath[fspath.length()-1] != '/') {
fspath += '/';
}
+
fspath += sound_dir (false);
AudioFileSource::set_search_path (fspath);
@@ -604,15 +619,12 @@ Session::save_state (string snapshot_name, bool pending)
xml_path = _path;
xml_path += snapshot_name;
xml_path += _statefile_suffix;
+
bak_path = xml_path;
bak_path += ".bak";
- // Make backup of state file
-
- if ((access (xml_path.c_str(), F_OK) == 0) &&
- (rename(xml_path.c_str(), bak_path.c_str()))) {
- error << _("could not backup old state file, current state not saved.") << endmsg;
- return -1;
+ if (g_file_test (xml_path.c_str(), G_FILE_TEST_EXISTS)) {
+ copy_file (xml_path, bak_path);
}
} else {
@@ -623,30 +635,31 @@ Session::save_state (string snapshot_name, bool pending)
}
+ string tmp_path;
+
+ tmp_path = _path;
+ tmp_path += snapshot_name;
+ tmp_path += ".tmp";
+
cerr << "actually writing state\n";
- if (!tree.write (xml_path)) {
- error << string_compose (_("state could not be saved to %1"), xml_path) << endmsg;
+ if (!tree.write (tmp_path)) {
+ error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
+ unlink (tmp_path.c_str());
+ return -1;
- /* don't leave a corrupt file lying around if it is
- possible to fix.
- */
+ } else {
- if (unlink (xml_path.c_str())) {
- error << string_compose (_("could not remove corrupt state file %1"), xml_path) << endmsg;
- } else {
- if (!pending) {
- if (rename (bak_path.c_str(), xml_path.c_str())) {
- error << string_compose (_("could not restore state file from backup %1"), bak_path) << endmsg;
- }
- }
+ if (rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
+ error << string_compose (_("could not rename temporary session file %1 to %2"), tmp_path, xml_path) << endmsg;
+ unlink (tmp_path.c_str());
+ return -1;
}
-
- return -1;
}
if (!pending) {
- save_history(snapshot_name);
+
+ save_history (snapshot_name);
bool was_dirty = dirty();
@@ -715,15 +728,52 @@ Session::load_state (string snapshot_name)
set_dirty();
- if (state_tree->read (xmlpath)) {
- return 0;
- } else {
+ if (!state_tree->read (xmlpath)) {
error << string_compose(_("Could not understand ardour file %1"), xmlpath) << endmsg;
+ delete state_tree;
+ state_tree = 0;
+ return -1;
}
- delete state_tree;
- state_tree = 0;
- return -1;
+ XMLNode& root (*state_tree->root());
+
+ if (root.name() != X_("Session")) {
+ error << string_compose (_("Session file %1 is not an Ardour session"), xmlpath) << endmsg;
+ delete state_tree;
+ state_tree = 0;
+ return -1;
+ }
+
+ const XMLProperty* prop;
+ bool is_old = false;
+
+ if ((prop = root.property ("version")) == 0) {
+ /* no version implies very old version of Ardour */
+ is_old = true;
+ } else {
+ int major_version;
+ major_version = atoi (prop->value()); // grab just the first number before the period
+ if (major_version < 2) {
+ is_old = true;
+ }
+ }
+
+ if (is_old) {
+ string backup_path;
+
+ backup_path = xmlpath;
+ backup_path += ".1";
+
+ info << string_compose (_("Copying old session file %1 to %2\nUse %2 with Ardour versions before 2.0 from now on"),
+ xmlpath, backup_path)
+ << endmsg;
+
+ copy_file (xmlpath, backup_path);
+
+ /* if it fails, don't worry. right? */
+ }
+
+ return 0;
}
int
@@ -1520,6 +1570,7 @@ Session::load_sources (const XMLNode& node)
if ((source = XMLSourceFactory (**niter)) == 0) {
error << _("Session: cannot create Source from XML description.") << endmsg;
}
+
}
return 0;
@@ -1791,7 +1842,7 @@ Session::load_playlists (const XMLNode& node)
{
XMLNodeList nlist;
XMLNodeConstIterator niter;
- Playlist *playlist;
+ boost::shared_ptr<Playlist> playlist;
nlist = node.children();
@@ -1812,7 +1863,7 @@ Session::load_unused_playlists (const XMLNode& node)
{
XMLNodeList nlist;
XMLNodeConstIterator niter;
- Playlist *playlist;
+ boost::shared_ptr<Playlist> playlist;
nlist = node.children();
@@ -1827,34 +1878,22 @@ Session::load_unused_playlists (const XMLNode& node)
// now manually untrack it
- track_playlist (playlist, false);
+ track_playlist (false, boost::weak_ptr<Playlist> (playlist));
}
return 0;
}
-Playlist *
+boost::shared_ptr<Playlist>
Session::XMLPlaylistFactory (const XMLNode& node)
{
- const XMLProperty* type = node.property("type");
-
try {
-
- if ( !type || type->value() == "audio" ) {
-
- return new AudioPlaylist (*this, node);
-
- } else if (type->value() == "midi") {
-
- return new MidiPlaylist (*this, node);
-
- }
-
- } catch (failed_constructor& err) {
- return 0;
+ return PlaylistFactory::create (*this, node);
}
- return 0;
+ catch (failed_constructor& err) {
+ return boost::shared_ptr<Playlist>();
+ }
}
int
@@ -1913,7 +1952,6 @@ Session::sound_dir (bool with_path) const
old_withpath = _path;
old_withpath += old_sound_dir_name;
- old_withpath += '/';
if (stat (old_withpath.c_str(), &statbuf) == 0) {
if (with_path)
@@ -1933,7 +1971,6 @@ Session::sound_dir (bool with_path) const
res += legalize_for_path (_name);
res += '/';
res += sound_dir_name;
- res += '/';
return res;
}
@@ -2265,7 +2302,12 @@ void
Session::set_global_route_metering (GlobalRouteMeterState s, void* arg)
{
for (GlobalRouteMeterState::iterator i = s.begin(); i != s.end(); ++i) {
- i->first->set_meter_point (i->second, arg);
+
+ boost::shared_ptr<Route> r = (i->first.lock());
+
+ if (r) {
+ r->set_meter_point (i->second, arg);
+ }
}
}
@@ -2273,8 +2315,13 @@ void
Session::set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void* arg)
{
for (GlobalRouteBooleanState::iterator i = s.begin(); i != s.end(); ++i) {
- Route* r = i->first.get();
- (r->*method) (i->second, arg);
+
+ boost::shared_ptr<Route> r = (i->first.lock());
+
+ if (r) {
+ Route* rp = r.get();
+ (rp->*method) (i->second, arg);
+ }
}
}
@@ -2506,11 +2553,20 @@ Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_th
return 0;
}
+struct RegionCounter {
+ typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
+ AudioSourceList::iterator iter;
+ boost::shared_ptr<Region> region;
+ uint32_t count;
+
+ RegionCounter() : count (0) {}
+};
+
int
Session::cleanup_sources (Session::cleanup_report& rep)
{
vector<boost::shared_ptr<Source> > dead_sources;
- vector<Playlist*> playlists_tbd;
+ vector<boost::shared_ptr<Playlist> > playlists_tbd;
PathScanner scanner;
string sound_path;
vector<space_and_path>::iterator i;
@@ -2549,73 +2605,36 @@ Session::cleanup_sources (Session::cleanup_report& rep)
/* now delete any that were marked for deletion */
- for (vector<Playlist*>::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
- PlaylistList::iterator foo;
-
- if ((foo = unused_playlists.find (*x)) != unused_playlists.end()) {
- unused_playlists.erase (foo);
- }
- delete *x;
+ for (vector<boost::shared_ptr<Playlist> >::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
+ (*x)->drop_references ();
}
- /* step 2: find all un-referenced sources */
+ playlists_tbd.clear ();
+
+ /* step 2: find all un-used sources */
rep.paths.clear ();
rep.space = 0;
for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
-
+
SourceMap::iterator tmp;
tmp = i;
++tmp;
- /* only remove files that are not in use and have some size
- to them. otherwise we remove the current "nascent"
+ /* do not bother with files that are zero size, otherwise we remove the current "nascent"
capture files.
*/
- cerr << "checking out source " << i->second->name() << " use_count = " << i->second.use_count() << endl;
-
- if (i->second.use_count() == 1 && i->second->length() > 0) {
+ if (!i->second->used() && i->second->length() > 0) {
dead_sources.push_back (i->second);
-
- /* remove this source from our own list to avoid us
- adding it to the list of all sources below
- */
-
- sources.erase (i);
- }
+ i->second->GoingAway();
+ }
i = tmp;
}
- /* Step 3: get rid of all regions in the region list that use any dead sources
- in case the sources themselves don't go away (they might be referenced in
- other snapshots).
- */
-
- for (vector<boost::shared_ptr<Source> >::iterator i = dead_sources.begin(); i != dead_sources.end();++i) {
-
- for (RegionList::iterator r = regions.begin(); r != regions.end(); ) {
- RegionList::iterator tmp;
-
- tmp = r;
- ++tmp;
-
- boost::shared_ptr<Region> reg = r->second;
-
- for (uint32_t n = 0; n < reg->n_channels(); ++n) {
- if (reg->source (n) == (*i)) {
- /* this region is dead */
- remove_region (reg);
- }
- }
-
- r = tmp;
- }
- }
-
/* build a list of all the possible sound directories for the session */
for (i = session_dirs.begin(); i != session_dirs.end(); ) {
@@ -2624,7 +2643,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
++nexti;
sound_path += (*i).path;
- sound_path += sound_dir_name;
+ sound_path += sound_dir (false);
if (nexti != session_dirs.end()) {
sound_path += ':';
@@ -2632,7 +2651,7 @@ Session::cleanup_sources (Session::cleanup_report& rep)
i = nexti;
}
-
+
/* now do the same thing for the files that ended up in the sounds dir(s)
but are not referenced as sources in any snapshot.
*/
@@ -2672,7 +2691,6 @@ Session::cleanup_sources (Session::cleanup_report& rep)
used = true;
break;
}
-
}
if (!used) {
@@ -2697,11 +2715,31 @@ Session::cleanup_sources (Session::cleanup_report& rep)
on whichever filesystem it was already on.
*/
- newpath = Glib::path_get_dirname (*x);
- newpath = Glib::path_get_dirname (newpath);
+ if (_path.find ("/sounds/")) {
+
+ /* old school, go up 1 level */
+
+ newpath = Glib::path_get_dirname (*x); // "sounds"
+ newpath = Glib::path_get_dirname (newpath); // "session-name"
+
+ } else {
+
+ /* new school, go up 4 levels */
+
+ newpath = Glib::path_get_dirname (*x); // "audiofiles"
+ newpath = Glib::path_get_dirname (newpath); // "session-name"
+ newpath = Glib::path_get_dirname (newpath); // "interchange"
+ newpath = Glib::path_get_dirname (newpath); // "session-dir"
+ }
newpath += '/';
newpath += dead_sound_dir_name;
+
+ if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
+ error << string_compose(_("Session: cannot create session peakfile dir \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
+ return -1;
+ }
+
newpath += '/';
newpath += Glib::path_get_basename ((*x));
@@ -2741,7 +2779,6 @@ Session::cleanup_sources (Session::cleanup_report& rep)
<< endmsg;
goto out;
}
-
/* see if there an easy to find peakfile for this file, and remove it.
*/
@@ -2759,7 +2796,6 @@ Session::cleanup_sources (Session::cleanup_report& rep)
goto out;
}
}
-
}
ret = 0;
@@ -2866,6 +2902,12 @@ Session::set_clean ()
}
void
+Session::set_deletion_in_progress ()
+{
+ _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
+}
+
+void
Session::add_controllable (Controllable* c)
{
Glib::Mutex::Lock lm (controllables_lock);
@@ -2916,8 +2958,8 @@ Session::save_history (string snapshot_name)
XMLTree tree;
string xml_path;
string bak_path;
-
- tree.set_root (&_history.get_state());
+
+ tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
if (snapshot_name.empty()) {
snapshot_name = _current_snapshot_name;
@@ -2934,8 +2976,6 @@ Session::save_history (string snapshot_name)
return -1;
}
- cerr << "actually writing history\n";
-
if (!tree.write (xml_path))
{
error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
@@ -2965,18 +3005,22 @@ Session::restore_history (string snapshot_name)
XMLTree tree;
string xmlpath;
+ if (snapshot_name.empty()) {
+ snapshot_name = _current_snapshot_name;
+ }
+
/* read xml */
xmlpath = _path + snapshot_name + ".history";
cerr << string_compose(_("Loading history from '%1'."), xmlpath) << endmsg;
if (access (xmlpath.c_str(), F_OK)) {
- error << string_compose(_("%1: session history file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
- return 1;
+ info << string_compose (_("%1: no history file \"%2\" for this session."), _name, xmlpath) << endmsg;
+ return 1;
}
if (!tree.read (xmlpath)) {
- error << string_compose(_("Could not understand ardour file %1"), xmlpath) << endmsg;
- return -1;
+ error << string_compose (_("Could not understand session history file \"%1\""), xmlpath) << endmsg;
+ return -1;
}
/* replace history */
@@ -3005,10 +3049,19 @@ Session::restore_history (string snapshot_name)
if (n->name() == "MementoCommand" ||
n->name() == "MementoUndoCommand" ||
n->name() == "MementoRedoCommand") {
+
if ((c = memento_command_factory(n))) {
ut->add_command(c);
}
+
+ } else if (n->name() == X_("GlobalRouteStateCommand")) {
+
+ if ((c = global_state_command_factory (*n))) {
+ ut->add_command (c);
+ }
+
} else {
+
error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
}
}
@@ -3039,7 +3092,6 @@ Session::config_changed (const char* parameter_name)
for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
if ((*i)->record_enabled ()) {
- //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
(*i)->monitor_input (!Config->get_auto_input());
}
}
@@ -3099,7 +3151,7 @@ Session::config_changed (const char* parameter_name)
setup_raid_path (Config->get_raid_path());
- } else if (PARAM_IS ("smpte-frames-per-second") || PARAM_IS ("smpte-drop-frames")) {
+ } else if (PARAM_IS ("smpte-format")) {
sync_time_vars ();
diff --git a/libs/ardour/session_time.cc b/libs/ardour/session_time.cc
index d24bab5ff8..585dad6b1a 100644
--- a/libs/ardour/session_time.cc
+++ b/libs/ardour/session_time.cc
@@ -48,43 +48,141 @@ Session::bbt_time (nframes_t when, BBT_Time& bbt)
}
/* SMPTE TIME */
+float
+Session::smpte_frames_per_second() const
+{
+ switch (Config->get_smpte_format()) {
+ case smpte_23976:
+ return 23.976;
+
+ break;
+ case smpte_24:
+ return 24;
+
+ break;
+ case smpte_24976:
+ return 24.976;
+
+ break;
+ case smpte_25:
+ return 25;
+
+ break;
+ case smpte_2997:
+ return 29.97;
+
+ break;
+ case smpte_2997drop:
+ return 29.97;
+
+ break;
+ case smpte_30:
+ return 30;
+
+ break;
+ case smpte_30drop:
+ return 30;
+
+ break;
+ case smpte_5994:
+ return 59.94;
+
+ break;
+ case smpte_60:
+ return 60;
+
+ break;
+ default:
+ cerr << "Editor received unexpected smpte type" << endl;
+ }
+ return 30.0;
+}
+bool
+Session::smpte_drop_frames() const
+{
+ switch (Config->get_smpte_format()) {
+ case smpte_23976:
+ return false;
+
+ break;
+ case smpte_24:
+ return false;
+
+ break;
+ case smpte_24976:
+ return false;
+
+ break;
+ case smpte_25:
+ return false;
+
+ break;
+ case smpte_2997:
+ return false;
+ break;
+ case smpte_2997drop:
+ return true;
+
+ break;
+ case smpte_30:
+ return false;
+
+ break;
+ case smpte_30drop:
+ return true;
+
+ break;
+ case smpte_5994:
+ return false;
+
+ break;
+ case smpte_60:
+ return false;
+
+ break;
+ default:
+ cerr << "Editor received unexpected smpte type" << endl;
+ }
+ return false;
+}
void
Session::sync_time_vars ()
{
_current_frame_rate = (nframes_t) round (_base_frame_rate * (1.0 + (Config->get_video_pullup()/100.0)));
- _frames_per_hour = _current_frame_rate * 3600;
- _frames_per_smpte_frame = (double) _current_frame_rate / (double) Config->get_smpte_frames_per_second();
- _smpte_frames_per_hour = (unsigned long) (Config->get_smpte_frames_per_second() * 3600.0);
+ _frames_per_smpte_frame = (double) _current_frame_rate / (double) smpte_frames_per_second();
+ if (smpte_drop_frames()) {
+ _frames_per_hour = (long)(107892 * _frames_per_smpte_frame);
+ } else {
+ _frames_per_hour = (long)(3600 * rint(smpte_frames_per_second()) * _frames_per_smpte_frame);
+ }
+ _smpte_frames_per_hour = (nframes_t)rint(smpte_frames_per_second() * 3600.0);
+
}
int
-Session::set_smpte_type (float fps, bool drop_frames)
+Session::set_smpte_format (SmpteFormat format)
{
- Config->set_smpte_frames_per_second (fps);
- Config->set_smpte_drop_frames (drop_frames);
+
+ Config->set_smpte_format (format);
last_smpte_valid = false;
// smpte type bits are the middle two in the upper nibble
- switch ((int) ceil (fps)) {
+ switch ((int) ceil (smpte_frames_per_second())) {
case 24:
mtc_smpte_bits = 0;
- SMPTE::Time::default_rate = SMPTE::MTC_24_FPS;
break;
case 25:
mtc_smpte_bits = 0x20;
- SMPTE::Time::default_rate = SMPTE::MTC_25_FPS;
break;
case 30:
default:
- if (drop_frames) {
+ if (smpte_drop_frames()) {
mtc_smpte_bits = 0x40;
- SMPTE::Time::default_rate = SMPTE::MTC_30_FPS_DROP;
} else {
mtc_smpte_bits = 0x60;
- SMPTE::Time::default_rate = SMPTE::MTC_30_FPS;
}
break;
};
@@ -113,7 +211,8 @@ Session::set_smpte_offset_negative (bool neg)
void
Session::smpte_to_sample( SMPTE::Time& smpte, nframes_t& sample, bool use_offset, bool use_subframes ) const
{
- if (Config->get_smpte_drop_frames()) {
+
+ if (smpte.drop) {
// The drop frame format was created to better approximate the 30000/1001 = 29.97002997002997....
// framerate of NTSC color TV. The used frame rate of drop frame is 29.97, which drifts by about
// 0.108 frame per hour, or about 1.3 frames per 12 hours. This is not perfect, but a lot better
@@ -152,9 +251,10 @@ Session::smpte_to_sample( SMPTE::Time& smpte, nframes_t& sample, bool use_offset
// 0:10:00:00 0.0 0 600.000 26460000 (accurate)
//
// Per Sigmond <per@sigmond.no>
-
+
// Samples inside time dividable by 10 minutes (real time accurate)
- nframes_t base_samples = ((smpte.hours * 60 * 60) + ((smpte.minutes / 10) * 10 * 60)) * frame_rate();
+ nframes_t base_samples = (nframes_t) (((smpte.hours * 107892) + ((smpte.minutes / 10) * 17982)) * _frames_per_smpte_frame);
+
// Samples inside time exceeding the nearest 10 minutes (always offset, see above)
long exceeding_df_minutes = smpte.minutes % 10;
long exceeding_df_seconds = (exceeding_df_minutes * 60) + smpte.seconds;
@@ -162,12 +262,18 @@ Session::smpte_to_sample( SMPTE::Time& smpte, nframes_t& sample, bool use_offset
nframes_t exceeding_samples = (nframes_t) rint(exceeding_df_frames * _frames_per_smpte_frame);
sample = base_samples + exceeding_samples;
} else {
- // Non drop is easy:
- sample = (((smpte.hours * 60 * 60) + (smpte.minutes * 60) + smpte.seconds) * frame_rate()) + (nframes_t)rint(smpte.frames * _frames_per_smpte_frame);
+ /*
+ Non drop is easy.. just note the use of
+ rint(smpte.rate) * _frames_per_smpte_frame
+ (frames per SMPTE second), which is larger than
+ frame_rate() in the non-integer SMPTE rate case.
+ */
+
+ sample = (nframes_t)rint((((smpte.hours * 60 * 60) + (smpte.minutes * 60) + smpte.seconds) * (rint(smpte.rate) * _frames_per_smpte_frame)) + (smpte.frames * _frames_per_smpte_frame));
}
if (use_subframes) {
- sample += (long) (((double)smpte.subframes * _frames_per_smpte_frame) / 80.0);
+ sample += (long) (((double)smpte.subframes * _frames_per_smpte_frame) / Config->get_subframes_per_frame());
}
if (use_offset) {
@@ -190,6 +296,7 @@ Session::smpte_to_sample( SMPTE::Time& smpte, nframes_t& sample, bool use_offset
}
}
}
+
}
@@ -224,14 +331,14 @@ Session::sample_to_smpte( nframes_t sample, SMPTE::Time& smpte, bool use_offset,
// high sample numbers in the calculations that follow.
smpte.hours = offset_sample / _frames_per_hour;
offset_sample = offset_sample % _frames_per_hour;
-
+
// Calculate exact number of (exceeding) smpte frames and fractional frames
smpte_frames_left_exact = (double) offset_sample / _frames_per_smpte_frame;
smpte_frames_fraction = smpte_frames_left_exact - floor( smpte_frames_left_exact );
- smpte.subframes = (long) rint(smpte_frames_fraction * 80.0);
+ smpte.subframes = (long) rint(smpte_frames_fraction * Config->get_subframes_per_frame());
// XXX Not sure if this is necessary anymore...
- if (smpte.subframes == 80) {
+ if (smpte.subframes == Config->get_subframes_per_frame()) {
// This can happen with 24 fps (and 29.97 fps ?)
smpte_frames_left_exact = ceil( smpte_frames_left_exact );
smpte.subframes = 0;
@@ -240,7 +347,7 @@ Session::sample_to_smpte( nframes_t sample, SMPTE::Time& smpte, bool use_offset,
// Extract hour-exceeding frames for minute, second and frame calculations
smpte_frames_left = ((long) floor( smpte_frames_left_exact ));
- if (Config->get_smpte_drop_frames()) {
+ if (smpte_drop_frames()) {
// See long explanation in smpte_to_sample()...
// Number of 10 minute chunks
@@ -276,15 +383,18 @@ Session::sample_to_smpte( nframes_t sample, SMPTE::Time& smpte, bool use_offset,
}
} else {
// Non drop is easy
- smpte.minutes = smpte_frames_left / ((long) Config->get_smpte_frames_per_second () * 60);
- smpte_frames_left = smpte_frames_left % ((long) Config->get_smpte_frames_per_second () * 60);
- smpte.seconds = smpte_frames_left / (long) Config->get_smpte_frames_per_second ();
- smpte.frames = smpte_frames_left % (long) Config->get_smpte_frames_per_second ();
+ smpte.minutes = smpte_frames_left / ((long) rint (smpte_frames_per_second ()) * 60);
+ smpte_frames_left = smpte_frames_left % ((long) rint (smpte_frames_per_second ()) * 60);
+ smpte.seconds = smpte_frames_left / (long) rint(smpte_frames_per_second ());
+ smpte.frames = smpte_frames_left % (long) rint(smpte_frames_per_second ());
}
if (!use_subframes) {
smpte.subframes = 0;
}
+ /* set frame rate and drop frame */
+ smpte.rate = smpte_frames_per_second ();
+ smpte.drop = smpte_drop_frames();
}
void
@@ -415,7 +525,7 @@ Session::jack_timebase_callback (jack_transport_state_t state,
#ifdef HAVE_JACK_VIDEO_SUPPORT
//poke audio video ratio so Ardour can track Video Sync
- pos->audio_frames_per_video_frame = frame_rate() / Config->get_smpte_frames_per_second ();
+ pos->audio_frames_per_video_frame = frame_rate() / smpte_frames_per_second();
pos->valid = jack_position_bits_t (pos->valid | JackAudioVideoRatio);
#endif
@@ -423,7 +533,7 @@ Session::jack_timebase_callback (jack_transport_state_t state,
/* SMPTE info */
t.smpte_offset = _smpte_offset;
- t.smpte_frame_rate = Config->get_smpte_frames_per_second ();
+ t.smpte_frame_rate = smpte_frames_per_second();
if (_transport_speed) {
@@ -474,7 +584,7 @@ Session::convert_to_frames_at (nframes_t position, AnyTime& any)
secs = any.smpte.hours * 60 * 60;
secs += any.smpte.minutes * 60;
secs += any.smpte.seconds;
- secs += any.smpte.frames / Config->get_smpte_frames_per_second ();
+ secs += any.smpte.frames / smpte_frames_per_second();
if (_smpte_offset_negative)
{
return (nframes_t) floor (secs * frame_rate()) - _smpte_offset;
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index e9c4e3785f..ad3573a72e 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -52,8 +52,10 @@ using namespace PBD;
void
Session::request_input_change_handling ()
{
- Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
- queue_event (ev);
+ if (!(_state_of_the_state & (InitialConnecting|Deletion))) {
+ Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0);
+ queue_event (ev);
+ }
}
void
@@ -185,9 +187,14 @@ Session::realtime_stop (bool abort)
void
Session::butler_transport_work ()
{
+ restart:
+ bool finished;
boost::shared_ptr<RouteList> r = routes.reader ();
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+ int on_entry = g_atomic_int_get (&butler_should_do_transport_work);
+ finished = true;
+
if (post_transport_work & PostTransportCurveRealloc) {
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->curve_reallocate();
@@ -211,30 +218,48 @@ Session::butler_transport_work ()
cumulative_rf_motion = 0;
reset_rf_scale (0);
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
- (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed()));
+ /* don't seek if locate will take care of that in non_realtime_stop() */
+
+ if (!(post_transport_work & PostTransportLocate)) {
+
+ for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+ if (!(*i)->hidden()) {
+ if ((*i)->speed() != 1.0f || (*i)->speed() != -1.0f) {
+ (*i)->seek ((nframes_t) (_transport_frame * (double) (*i)->speed()));
+ }
+ else {
+ (*i)->seek (_transport_frame);
+ }
}
- else {
- (*i)->seek (_transport_frame);
+ if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) {
+ /* new request, stop seeking, and start again */
+ g_atomic_int_dec_and_test (&butler_should_do_transport_work);
+ goto restart;
}
}
}
}
if (post_transport_work & (PostTransportStop|PostTransportLocate)) {
- non_realtime_stop (post_transport_work & PostTransportAbort);
+ non_realtime_stop (post_transport_work & PostTransportAbort, on_entry, finished);
+ if (!finished) {
+ g_atomic_int_dec_and_test (&butler_should_do_transport_work);
+ goto restart;
+ }
}
if (post_transport_work & PostTransportOverWrite) {
- non_realtime_overwrite ();
+ non_realtime_overwrite (on_entry, finished);
+ if (!finished) {
+ g_atomic_int_dec_and_test (&butler_should_do_transport_work);
+ goto restart;
+ }
}
if (post_transport_work & PostTransportAudition) {
non_realtime_set_audition ();
}
-
+
g_atomic_int_dec_and_test (&butler_should_do_transport_work);
}
@@ -249,7 +274,7 @@ Session::non_realtime_set_speed ()
}
void
-Session::non_realtime_overwrite ()
+Session::non_realtime_overwrite (int on_entry, bool& finished)
{
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
@@ -257,11 +282,15 @@ Session::non_realtime_overwrite ()
if ((*i)->pending_overwrite) {
(*i)->overwrite_existing_buffers ();
}
+ if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) {
+ finished = false;
+ return;
+ }
}
}
void
-Session::non_realtime_stop (bool abort)
+Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
{
struct tm* now;
time_t xnow;
@@ -376,6 +405,11 @@ Session::non_realtime_stop (bool abort)
(*i)->seek (_transport_frame);
}
}
+ if (on_entry != g_atomic_int_get (&butler_should_do_transport_work)) {
+ finished = false;
+ /* we will be back */
+ return;
+ }
}
#ifdef LEAVE_TRANSPORT_UNADJUSTED
@@ -629,6 +663,8 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w
} else {
+ cerr << "butler not requested\n";
+
/* this is functionally what clear_clicks() does but with a tentative lock */
Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK);
@@ -904,7 +940,6 @@ Session::post_transport ()
if (post_transport_work & PostTransportLocate) {
if ((Config->get_auto_play() && !_exporting) || (post_transport_work & PostTransportRoll)) {
-
start_transport ();
} else {
@@ -1127,7 +1162,7 @@ void
Session::request_bounded_roll (nframes_t start, nframes_t end)
{
request_stop ();
- Event *ev = new Event (Event::StopOnce, Event::Replace, Event::Immediate, end, 0.0);
+ Event *ev = new Event (Event::StopOnce, Event::Replace, end, Event::Immediate, 0.0);
queue_event (ev);
request_locate (start, true);
}
@@ -1135,6 +1170,8 @@ Session::request_bounded_roll (nframes_t start, nframes_t end)
void
Session::engine_halted ()
{
+ bool ignored;
+
/* there will be no more calls to process(), so
we'd better clean up for ourselves, right now.
@@ -1147,7 +1184,7 @@ Session::engine_halted ()
stop_butler ();
realtime_stop (false);
- non_realtime_stop (false);
+ non_realtime_stop (false, 0, ignored);
transport_sub_state = 0;
TransportStateChange (); /* EMIT SIGNAL */
diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc
index 6fb71e9596..aca8cf5a25 100644
--- a/libs/ardour/smf_source.cc
+++ b/libs/ardour/smf_source.cc
@@ -49,7 +49,7 @@ uint64_t SMFSource::header_position_offset;
*/
SMFSource::SMFSource (Session& s, std::string path, Flag flags)
- : MidiSource (s, region_name_from_path(path))
+ : MidiSource (s, region_name_from_path(path, false))
, _channel(0)
, _flags (Flag(flags | Writable)) // FIXME: this needs to be writable for now
, _allow_remove_if_empty(true)
diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc
index a30bfcf49b..8e90eac6ab 100644
--- a/libs/ardour/sndfilesource.cc
+++ b/libs/ardour/sndfilesource.cc
@@ -408,26 +408,25 @@ SndFileSource::nondestructive_write_unlocked (Sample *data, nframes_t cnt)
PeakBuildRecord *pbr = 0;
if (pending_peak_builds.size()) {
- pbr = pending_peak_builds.back();
- }
+ pbr = pending_peak_builds.back();
+ }
- if (pbr && pbr->frame + pbr->cnt == oldlen) {
-
- /* the last PBR extended to the start of the current write,
- so just extend it again.
- */
-
- pbr->cnt += cnt;
- } else {
- pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
- }
+ if (pbr && pbr->frame + pbr->cnt == oldlen) {
- _peaks_built = false;
+ /* the last PBR extended to the start of the current write,
+ so just extend it again.
+ */
+ pbr->cnt += cnt;
+ } else {
+ pending_peak_builds.push_back (new PeakBuildRecord (oldlen, cnt));
+ }
+
+ _peaks_built = false;
}
if (_build_peakfiles) {
- queue_for_peaks (shared_from_this ());
+ queue_for_peaks (shared_from_this (), false);
}
_write_data_count = cnt;
@@ -540,7 +539,7 @@ SndFileSource::destructive_write_unlocked (Sample* data, nframes_t cnt)
}
if (_build_peakfiles) {
- queue_for_peaks (shared_from_this ());
+ queue_for_peaks (shared_from_this (), true);
}
return cnt;
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index 8f0afd3507..db2147493a 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -131,15 +131,22 @@ Source::update_length (jack_nframes_t pos, jack_nframes_t cnt)
}
void
-Source::add_playlist (Playlist* pl)
+Source::add_playlist (boost::shared_ptr<Playlist> pl)
{
_playlists.insert (pl);
+ pl->GoingAway.connect (bind (mem_fun (*this, &Source::remove_playlist), boost::weak_ptr<Playlist> (pl)));
}
void
-Source::remove_playlist (Playlist* pl)
+Source::remove_playlist (boost::weak_ptr<Playlist> wpl)
{
- std::set<Playlist*>::iterator x;
+ boost::shared_ptr<Playlist> pl (wpl.lock());
+
+ if (!pl) {
+ return;
+ }
+
+ std::set<boost::shared_ptr<Playlist> >::iterator x;
if ((x = _playlists.find (pl)) != _playlists.end()) {
_playlists.erase (x);
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 001af609dc..ad01bf6171 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -64,47 +64,26 @@ SourceFactory::create (Session& s, const XMLNode& node)
if (type == DataType::AUDIO) {
- if (node.property (X_("destructive")) != 0) {
-
- boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
+ try {
+ boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
if (setup_peakfile (ret)) {
return boost::shared_ptr<Source>();
}
SourceCreated (ret);
return ret;
+ }
- } else {
-
- try {
- boost::shared_ptr<Source> ret (new CoreAudioSource (s, node));
+ catch (failed_constructor& err) {
+ boost::shared_ptr<Source> ret (new SndFileSource (s, node));
if (setup_peakfile (ret)) {
return boost::shared_ptr<Source>();
}
SourceCreated (ret);
return ret;
-
- } catch (failed_constructor& err) {
-
- try {
- boost::shared_ptr<Source> ret (new CoreAudioSource (node));
- SourceCreated (ret);
- return ret;
- }
-
-
- catch (failed_constructor& err) {
-
- boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- SourceCreated (ret);
- return ret;
- }
}
} else if (type == DataType::MIDI) {
-
+
boost::shared_ptr<Source> ret (new SMFSource (node));
SourceCreated (ret);
return ret;
@@ -127,33 +106,24 @@ SourceFactory::create (Session& s, const XMLNode& node)
if (type == DataType::AUDIO) {
- if (node.property (X_("destructive")) != 0) {
-
- boost::shared_ptr<Source> ret (new DestructiveFileSource (s, node));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- SourceCreated (ret);
- return ret;
+ boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- } else {
-
- boost::shared_ptr<Source> ret (new SndFileSource (s, node));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- SourceCreated (ret);
- return ret;
+ if (setup_peakfile (ret)) {
+ return boost::shared_ptr<Source>();
}
+
+ SourceCreated (ret);
+ return ret;
} else if (type == DataType::MIDI) {
boost::shared_ptr<Source> ret (new SMFSource (s, node));
+
SourceCreated (ret);
return ret;
}
-
+
return boost::shared_ptr<Source> ();
}
@@ -164,39 +134,53 @@ boost::shared_ptr<Source>
SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
{
if (type == DataType::AUDIO) {
- if (flags & Destructive) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (s, idstr, flags));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- if (announce) {
- SourceCreated (ret);
- }
- return ret;
-
+
+ if (!(flags & Destructive)) {
+
try {
boost::shared_ptr<Source> ret (new CoreAudioSource (s, idstr, flags));
+ if (setup_peakfile (ret)) {
+ return boost::shared_ptr<Source>();
+ }
if (announce) {
SourceCreated (ret);
}
return ret;
-
- } catch (failed_constructor& err) {
+ }
+
+ catch (failed_constructor& err) {
boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+ if (setup_peakfile (ret)) {
+ return boost::shared_ptr<Source>();
+ }
if (announce) {
SourceCreated (ret);
}
return ret;
}
+ } else {
+
+ boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+ if (setup_peakfile (ret)) {
+ return boost::shared_ptr<Source>();
+ }
+ if (announce) {
+ SourceCreated (ret);
+ }
+ return ret;
+ }
+
} else if (type == DataType::MIDI) {
boost::shared_ptr<Source> ret (new SMFSource (s, node));
- SourceCreated (ret);
+ if (announce) {
+ SourceCreated (ret);
+ }
return ret;
}
-
+
return boost::shared_ptr<Source>();
}
@@ -206,27 +190,32 @@ boost::shared_ptr<Source>
SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce)
{
if (type == DataType::AUDIO) {
-
+
boost::shared_ptr<Source> ret (new SndFileSource (s, idstr, flags));
+
if (setup_peakfile (ret)) {
return boost::shared_ptr<Source>();
}
+
if (announce) {
SourceCreated (ret);
}
+
return ret;
} else if (type == DataType::MIDI) {
- boost::shared_ptr<Source> ret (new SMFSource (s, idstr, SMFSource::Flag(0))); // FIXME: flags?
+ // FIXME: flags?
+ boost::shared_ptr<Source> ret (new SMFSource (s, idstr, SMFSource::Flag(0)));
+
if (announce) {
SourceCreated (ret);
}
- return ret;
+ return ret;
}
-
- return boost::shared_ptr<Source> ();
+
+ return boost::shared_ptr<Source>();
}
#endif // HAVE_COREAUDIO
@@ -235,39 +224,33 @@ boost::shared_ptr<Source>
SourceFactory::createWritable (DataType type, Session& s, std::string path, bool destructive, nframes_t rate, bool announce)
{
/* this might throw failed_constructor(), which is OK */
+
if (type == DataType::AUDIO) {
-
- if (destructive) {
- boost::shared_ptr<Source> ret (new DestructiveFileSource (s, path,
- Config->get_native_file_data_format(),
- Config->get_native_file_header_format(),
- rate));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- if (announce) {
- SourceCreated (ret);
- }
- } else {
- boost::shared_ptr<Source> ret (new SndFileSource (s, path,
- Config->get_native_file_data_format(),
- Config->get_native_file_header_format(),
- rate));
- if (setup_peakfile (ret)) {
- return boost::shared_ptr<Source>();
- }
- if (announce) {
- SourceCreated (ret);
- }
- return ret;
+ 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>();
+ }
+ if (announce) {
+ SourceCreated (ret);
}
+ return ret;
} else if (type == DataType::MIDI) {
boost::shared_ptr<Source> ret (new SMFSource (s, path));
- SourceCreated (ret);
+
+ if (announce) {
+ SourceCreated (ret);
+ }
return ret;
-
+
}
return boost::shared_ptr<Source> ();
diff --git a/libs/ardour/tempo.cc b/libs/ardour/tempo.cc
index 0ff94324bb..e86c30dd4d 100644
--- a/libs/ardour/tempo.cc
+++ b/libs/ardour/tempo.cc
@@ -924,7 +924,10 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
return frame_time (the_beat);
- /* XXX just keeping this for reference
+
+
+ /*****************************
+ XXX just keeping this for reference
TempoMap::BBTPointList::iterator i;
TempoMap::BBTPointList *more_zoomed_bbt_points;
@@ -978,7 +981,8 @@ TempoMap::round_to_beat_subdivision (nframes_t fr, int sub_num)
delete more_zoomed_bbt_points;
return fr ;
- */
+ ******************************/
+
}
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 9c94d32241..e0ef8fd0b3 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -40,6 +40,7 @@
#include <pbd/error.h>
#include <pbd/stacktrace.h>
#include <pbd/xml++.h>
+#include <pbd/basename.h>
#include <ardour/utils.h>
#include "i18n.h"
@@ -47,6 +48,7 @@
using namespace ARDOUR;
using namespace std;
using namespace PBD;
+using Glib::ustring;
void
elapsed_time_to_str (char *buf, uint32_t seconds)
@@ -90,6 +92,24 @@ elapsed_time_to_str (char *buf, uint32_t seconds)
}
}
+ustring
+legalize_for_path (ustring str)
+{
+ ustring::size_type pos;
+ ustring legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=: ";
+ ustring legal;
+
+ legal = str;
+ pos = 0;
+
+ while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
+ legal.replace (pos, 1, "_");
+ pos += 1;
+ }
+
+ return legal;
+}
+#if 0
string
legalize_for_path (string str)
{
@@ -107,6 +127,7 @@ legalize_for_path (string str)
return legal;
}
+#endif
ostream&
operator<< (ostream& o, const BBT_Time& bbt)
@@ -180,7 +201,7 @@ tokenize_fullpath (string fullpath, string& path, string& name)
}
int
-touch_file (string path)
+touch_file (ustring path)
{
int fd = open (path.c_str(), O_RDWR|O_CREAT, 0660);
if (fd >= 0) {
@@ -190,22 +211,31 @@ touch_file (string path)
return 1;
}
-string
-placement_as_string (Placement p)
+ustring
+region_name_from_path (ustring path, bool strip_channels)
{
- switch (p) {
- case PreFader:
- return _("pre");
- default: /* to get g++ to realize we have all the cases covered */
- case PostFader:
- return _("post");
+ path = PBD::basename_nosuffix (path);
+
+ if (strip_channels) {
+
+ /* remove any "?R", "?L" or "?[a-z]" channel identifier */
+
+ ustring::size_type len = path.length();
+
+ if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
+ (path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
+
+ path = path.substr (0, path.length() - 2);
+ }
}
-}
-string
-region_name_from_path (string path)
+ return path;
+}
+
+bool
+path_is_paired (ustring path, ustring& pair_base)
{
- string::size_type pos;
+ ustring::size_type pos;
/* remove any leading path */
@@ -219,21 +249,23 @@ region_name_from_path (string path)
path = path.substr (0, pos);
}
- /* remove any "?R", "?L" or "?[a-z]" channel identifier */
-
- string::size_type len = path.length();
+ ustring::size_type len = path.length();
+
+ /* look for possible channel identifier: "?R", "%R", ".L" etc. */
- if (len > 3 && (path[len-2] == '%' || path[len-2] == '?') &&
+ if (len > 3 && (path[len-2] == '%' || path[len-2] == '?' || path[len-2] == '.') &&
(path[len-1] == 'R' || path[len-1] == 'L' || (islower (path[len-1])))) {
- path = path.substr (0, path.length() - 2);
- }
+ pair_base = path.substr (0, len-2);
+ return true;
- return path;
-}
+ }
-string
-path_expand (string path)
+ return false;
+}
+
+ustring
+path_expand (ustring path)
{
#ifdef HAVE_WORDEXP
/* Handle tilde and environment variable expansion in session path */
@@ -371,25 +403,65 @@ slave_source_to_string (SlaveSource src)
}
}
+/* I don't really like hard-coding these falloff rates here
+ * Probably should use a map of some kind that could be configured
+ * These rates are db/sec.
+*/
+
+#define METER_FALLOFF_OFF 0.0f
+#define METER_FALLOFF_SLOWEST 6.6f // BBC standard
+#define METER_FALLOFF_SLOW 8.6f // BBC standard
+#define METER_FALLOFF_MEDIUM 20.0f
+#define METER_FALLOFF_FAST 32.0f
+#define METER_FALLOFF_FASTER 46.0f
+#define METER_FALLOFF_FASTEST 70.0f
+
float
meter_falloff_to_float (MeterFalloff falloff)
{
switch (falloff) {
case MeterFalloffOff:
- return 0.0f;
+ return METER_FALLOFF_OFF;
case MeterFalloffSlowest:
- return 1.0f;
+ return METER_FALLOFF_SLOWEST;
case MeterFalloffSlow:
- return 2.0f;
+ return METER_FALLOFF_SLOW;
case MeterFalloffMedium:
- return 3.0f;
+ return METER_FALLOFF_MEDIUM;
case MeterFalloffFast:
- return 4.0f;
+ return METER_FALLOFF_FAST;
case MeterFalloffFaster:
- return 5.0f;
+ return METER_FALLOFF_FASTER;
case MeterFalloffFastest:
+ return METER_FALLOFF_FASTEST;
default:
- return 6.0f;
+ return METER_FALLOFF_FAST;
+ }
+}
+
+MeterFalloff
+meter_falloff_from_float (float val)
+{
+ if (val == METER_FALLOFF_OFF) {
+ return MeterFalloffOff;
+ }
+ else if (val <= METER_FALLOFF_SLOWEST) {
+ return MeterFalloffSlowest;
+ }
+ else if (val <= METER_FALLOFF_SLOW) {
+ return MeterFalloffSlow;
+ }
+ else if (val <= METER_FALLOFF_MEDIUM) {
+ return MeterFalloffMedium;
+ }
+ else if (val <= METER_FALLOFF_FAST) {
+ return MeterFalloffFast;
+ }
+ else if (val <= METER_FALLOFF_FASTER) {
+ return MeterFalloffFaster;
+ }
+ else {
+ return MeterFalloffFastest;
}
}
diff --git a/libs/clearlooks/SConscript b/libs/clearlooks/SConscript
index 0df20efe56..110bfe41be 100644
--- a/libs/clearlooks/SConscript
+++ b/libs/clearlooks/SConscript
@@ -1,4 +1,14 @@
+# -*- python -*-
+
import os.path
+import glob
+
+libclearlooks_files = [
+ 'clearlooks_draw.c',
+ 'clearlooks_rc_style.c',
+ 'clearlooks_style.c',
+ 'clearlooks_theme_main.c',
+ 'support.c' ]
Import ('env install_prefix')
@@ -7,17 +17,17 @@ clearlooks = env.Copy()
clearlooks.Replace(CCFLAGS = ' `pkg-config --cflags gtk+-2.0` ',
LINKFLAGS = ' `pkg-config --libs gtk+-2.0` ')
-libclearlooks = clearlooks.SharedLibrary('clearlooks', [
- 'clearlooks_draw.c',
- 'clearlooks_rc_style.c',
- 'clearlooks_style.c',
- 'clearlooks_theme_main.c',
- 'support.c'
-])
+libclearlooks = clearlooks.SharedLibrary('clearlooks', libclearlooks_files)
usable_libclearlooks = clearlooks.Install ('engines', libclearlooks)
Default (usable_libclearlooks)
env.Alias('install',
- env.Install(os.path.join(install_prefix,'lib/ardour2/engines'),
+ env.Install(os.path.join(install_prefix,env['LIBDIR'], 'ardour2', 'engines'),
libclearlooks))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'bits.c'] +
+ libclearlooks_files +
+ glob.glob('*.h')
+ ))
diff --git a/libs/flowcanvas/SConscript b/libs/flowcanvas/SConscript
index 6394982a20..18b061ef82 100644
--- a/libs/flowcanvas/SConscript
+++ b/libs/flowcanvas/SConscript
@@ -39,7 +39,7 @@ libflowcanvas = flowcanvas.SharedLibrary('flowcanvas', flowcanvas_files)
Default(libflowcanvas)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libflowcanvas))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libflowcanvas))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
['SConscript'] +
diff --git a/libs/fst/SConscript b/libs/fst/SConscript
index 771de86dc8..bdffd959b5 100644
--- a/libs/fst/SConscript
+++ b/libs/fst/SConscript
@@ -11,24 +11,42 @@ Import('env install_prefix')
fst = env.Copy(CC="winegcc")
fst.Append (CPPPATH=".")
-hackSDK = fst.Command('vst/aeffectx.h', 'vstsdk2.3/source/common/aeffectx.h', [
- Delete ('${TARGET.dir}'),
- Copy ('${TARGET.dir}', '${SOURCE.dir}'),
- "sed -i '/struct VstFileType\|struct VstFileSelect/,/};/d' $TARGET"
-])
-
-a = fst.Object ('fst', 'fst.c')
-b = fst.Object ('fstinfofile', 'fstinfofile.c')
-c = fst.Object ('vstwin', 'vstwin.c')
-d = fst.Object ('vsti', 'vsti.c')
-
if fst['VST']:
- if os.access ('vst/aeffectx.h', os.F_OK):
- Default([hackSDK,a,b,c,d])
+ vst_dir = Dir ('libs/vst')
+ vst_sdk_dir = Dir ('vstsdk2.3')
+ #
+ # if it exists, try to use the Steinberg zip package
+ #
+ vst_sdk_zip = File ('vstsdk2.3.zip')
+
+ if os.access (vst_sdk_zip.abspath, os.F_OK):
+ print 'VST package discovered.'
+ elif os.access ('vst_sdk2_3.zip', os.F_OK):
+ #
+ # add a build target that unpacks the zip package the Steinberg "meta" zip package
+ #
+ vst_meta_zip = fst.Command (vst_sdk_zip, 'vst_sdk2_3.zip', "unzip -o -d ${TARGET.dir} $SOURCES vstsdk2.3.zip" )
+ print 'VST meta-package discovered.'
else:
- print 'You have not installed the VST SDK in the correct location.'
- print 'Please see http://ardour.org/building_vst_support for more information'
- sys.exit (1)
+ if os.access ('vstsdk2.3.zip', os.F_OK) != 1:
+ print 'Did not find vst_sdk2_3.zip or vstsdk2.3.zip in libs/fst.'
+ print 'Make sure the correct file is in the correct location and correctly named.'
+ print 'Please see http://ardour.org/building_vst_support for more information.'
+ sys.exit (1)
+
+ vst_headers = fst.Command ([ 'vst/aeffectx.h', 'vst/AEffect.h' ], vst_sdk_zip, [
+ "unzip -qq -d ${SOURCE.dir} -o $SOURCE",
+ Delete ('$TARGET.dir'),
+ Copy ('${TARGET.dir}', 'libs/fst/vstsdk2.3/source/common'),
+ "sed -i '/struct VstFileType\|struct VstFileSelect/,/};/d' $TARGET"
+ ])
+
+ a = fst.Object ('fst', 'fst.c')
+ b = fst.Object ('fstinfofile', 'fstinfofile.c')
+ c = fst.Object ('vstwin', 'vstwin.c')
+ d = fst.Object ('vsti', 'vsti.c')
+
+ Default([vst_headers,a,b,c,d])
env.Alias('tarball', env.Distribute (env['DISTTREE'],
fst_src + ['SConscript',
diff --git a/libs/fst/fstinfofile.c b/libs/fst/fstinfofile.c
index 7cc98d2233..7b0c69d015 100644
--- a/libs/fst/fstinfofile.c
+++ b/libs/fst/fstinfofile.c
@@ -227,7 +227,9 @@ FSTInfo *fst_get_info( char *dllpath ) {
FSTInfo *info;
char *fstpath;
- if( !(h = fst_load( dllpath )) ) return NULL;
+ if( !(h = fst_load( dllpath )) ) {
+ return NULL;
+ }
if( !(fst = fst_instantiate( h, simple_master_callback, NULL )) ) {
fst_unload( h );
fst_error( "instantiate failed\n" );
diff --git a/libs/glibmm2/SConscript b/libs/glibmm2/SConscript
index dbc58e6499..267f846203 100644
--- a/libs/glibmm2/SConscript
+++ b/libs/glibmm2/SConscript
@@ -28,7 +28,7 @@ else :
Default([glibmm2_config_h, libglibmm2])
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libglibmm2))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libglibmm2))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript',
diff --git a/libs/gtkmm2/atk/SConscript b/libs/gtkmm2/atk/SConscript
index 884ac3cbb0..84a5e8251a 100644
--- a/libs/gtkmm2/atk/SConscript
+++ b/libs/gtkmm2/atk/SConscript
@@ -13,7 +13,7 @@ atkmm.Merge([libraries['glibmm2'], libraries['gtk2'], libraries['sigc2'] ])
libatkmm = atkmm.SharedLibrary('atkmm', atkmm_files)
Default(libatkmm)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libatkmm))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libatkmm))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'atkmm.h'] +
diff --git a/libs/gtkmm2/gdk/SConscript b/libs/gtkmm2/gdk/SConscript
index 58f0ebb2e5..6ea5c7cfef 100644
--- a/libs/gtkmm2/gdk/SConscript
+++ b/libs/gtkmm2/gdk/SConscript
@@ -14,7 +14,7 @@ gdkmm2.Append(CXXFLAGS="-Ilibs/gtkmm2/gtk")
libgdkmm2 = gdkmm2.SharedLibrary('gdkmm2', gdkmm2_files)
Default(libgdkmm2)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libgdkmm2))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libgdkmm2))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'gdkmmconfig.h', 'gdkmm.h'] +
diff --git a/libs/gtkmm2/gtk/SConscript b/libs/gtkmm2/gtk/SConscript
index 90e832b010..b4cd99f023 100644
--- a/libs/gtkmm2/gtk/SConscript
+++ b/libs/gtkmm2/gtk/SConscript
@@ -13,7 +13,7 @@ gtkmm2.Merge([libraries['glibmm2'], libraries['gtk2'], libraries['sigc2'], libra
libgtkmm2 = gtkmm2.SharedLibrary('gtkmm2', gtkmm2_files)
Default(libgtkmm2)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libgtkmm2))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libgtkmm2))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'gtkmmconfig.h', 'gtkmm.h'] +
diff --git a/libs/gtkmm2/pango/SConscript b/libs/gtkmm2/pango/SConscript
index 0ec62a0f02..d045cf2043 100644
--- a/libs/gtkmm2/pango/SConscript
+++ b/libs/gtkmm2/pango/SConscript
@@ -13,7 +13,7 @@ pangomm.Merge([libraries['glibmm2'], libraries['pango'], libraries['sigc2']])
libpangomm = pangomm.SharedLibrary('pangomm', pangomm_files)
Default(libpangomm)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libpangomm))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libpangomm))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'pangomm.h'] +
diff --git a/libs/gtkmm2ext/SConscript b/libs/gtkmm2ext/SConscript
index e654b6cb52..9c7511c85d 100644
--- a/libs/gtkmm2ext/SConscript
+++ b/libs/gtkmm2ext/SConscript
@@ -39,10 +39,12 @@ choice.cc
click_box.cc
dndtreeview.cc
fastmeter.cc
+focus_entry.cc
gtk_ui.cc
hexentry.cc
idle_adjustment.cc
pathlist.cc
+pixfader.cc
pixscroller.cc
popup.cc
prompter.cc
@@ -67,7 +69,7 @@ Default(libgtkmm2ext)
if env['NLS']:
i18n (gtkmm2ext, gtkmm2ext_files, env)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libgtkmm2ext))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libgtkmm2ext))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h'] +
diff --git a/libs/gtkmm2ext/barcontroller.cc b/libs/gtkmm2ext/barcontroller.cc
index 734c4b77e2..f59d192ff1 100644
--- a/libs/gtkmm2ext/barcontroller.cc
+++ b/libs/gtkmm2ext/barcontroller.cc
@@ -70,8 +70,8 @@ BarController::BarController (Gtk::Adjustment& adj,
darea.signal_expose_event().connect (mem_fun (*this, &BarController::expose));
darea.signal_motion_notify_event().connect (mem_fun (*this, &BarController::motion));
- darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press));
- darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release));
+ darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press), false);
+ darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release), false);
darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll));
spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated));
@@ -82,9 +82,21 @@ BarController::BarController (Gtk::Adjustment& adj,
show_all ();
}
+void
+BarController::drop_grab ()
+{
+ if (grabbed) {
+ grabbed = false;
+ darea.remove_modal_grab();
+ StopGesture ();
+ }
+}
+
bool
BarController::button_press (GdkEventButton* ev)
{
+ double fract;
+
if (binding_proxy.button_press_handler (ev)) {
return true;
}
@@ -93,8 +105,7 @@ BarController::button_press (GdkEventButton* ev)
case 1:
if (ev->type == GDK_2BUTTON_PRESS) {
switch_on_release = true;
- grabbed = false;
- darea.remove_modal_grab();
+ drop_grab ();
} else {
switch_on_release = false;
darea.add_modal_grab();
@@ -107,6 +118,9 @@ BarController::button_press (GdkEventButton* ev)
break;
case 2:
+ fract = ev->x / (darea.get_width() - 2.0);
+ adjustment.set_value (adjustment.get_lower() + fract * (adjustment.get_upper() - adjustment.get_lower()));
+
case 3:
break;
@@ -121,6 +135,8 @@ BarController::button_press (GdkEventButton* ev)
bool
BarController::button_release (GdkEventButton* ev)
{
+ drop_grab ();
+
switch (ev->button) {
case 1:
if (switch_on_release) {
@@ -143,23 +159,11 @@ BarController::button_release (GdkEventButton* ev)
mouse_control (ev->x, ev->window, scale);
}
- darea.remove_modal_grab();
- grabbed = false;
- StopGesture ();
- grabbed = false;
break;
case 2:
- if (true) { // XXX FIX ME
- /* relax */
- } else {
- double fract;
- fract = ev->x / (darea.get_width() - 2.0);
- adjustment.set_value (adjustment.get_lower() +
- fract * (adjustment.get_upper() - adjustment.get_lower()));
- }
- return true;
-
+ break;
+
case 3:
return false;
@@ -204,7 +208,7 @@ BarController::motion (GdkEventMotion* ev)
double scale;
if (!grabbed) {
- return TRUE;
+ return true;
}
if ((ev->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK)) == GDK_SHIFT_MASK) {
@@ -225,7 +229,7 @@ BarController::motion (GdkEventMotion* ev)
gint
BarController::mouse_control (double x, GdkWindow* window, double scaling)
{
- double fract;
+ double fract = 0.0;
double delta;
if (window != grab_window) {
@@ -259,7 +263,7 @@ BarController::expose (GdkEventExpose* event)
{
Glib::RefPtr<Gdk::Window> win (darea.get_window());
Widget* parent;
- gint x1, x2, y1, y2;
+ gint x1=0, x2=0, y1=0, y2=0;
gint w, h;
double fract;
@@ -271,6 +275,7 @@ BarController::expose (GdkEventExpose* event)
switch (_style) {
case Line:
+ h = darea.get_height();
x1 = (gint) floor (w * fract);
x2 = x1;
y1 = 0;
@@ -281,22 +286,18 @@ BarController::expose (GdkEventExpose* event)
if (parent) {
win->draw_rectangle (parent->get_style()->get_fg_gc (parent->get_state()),
- true,
- 0, 0, darea.get_width(), darea.get_height());
+ true,
+ 0, 0, darea.get_width(), darea.get_height());
}
- } else {
- win->draw_rectangle (get_style()->get_bg_gc (get_state()),
- true,
- 0, 0, darea.get_width(), darea.get_height());
- }
- if (fract == 0.0) {
- win->draw_rectangle (get_style()->get_fg_gc (get_state()),
- true, x1, 1, 2, darea.get_height() - 2);
} else {
- win->draw_rectangle (get_style()->get_fg_gc (get_state()),
- true, x1 - 1, 1, 3, darea.get_height() - 2);
+
+ win->draw_rectangle (get_style()->get_bg_gc (get_state()),
+ true,
+ 0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height());
}
+
+ win->draw_line (get_style()->get_fg_gc (get_state()), x1, 0, x1, h);
break;
case CenterOut:
@@ -456,3 +457,10 @@ BarController::set_use_parent (bool yn)
use_parent = yn;
queue_draw ();
}
+
+void
+BarController::set_sensitive (bool yn)
+{
+ Frame::set_sensitive (yn);
+ darea.set_sensitive (yn);
+}
diff --git a/libs/gtkmm2ext/focus_entry.cc b/libs/gtkmm2ext/focus_entry.cc
new file mode 100644
index 0000000000..dbe833d06b
--- /dev/null
+++ b/libs/gtkmm2ext/focus_entry.cc
@@ -0,0 +1,31 @@
+#include <gtkmm2ext/focus_entry.h>
+
+using namespace Gtkmm2ext;
+
+FocusEntry::FocusEntry ()
+{
+ next_release_selects = false;
+}
+
+bool
+FocusEntry::on_button_press_event (GdkEventButton* ev)
+{
+ if (!has_focus()) {
+ next_release_selects = true;
+ }
+ return Entry::on_button_press_event (ev);
+}
+
+bool
+FocusEntry::on_button_release_event (GdkEventButton* ev)
+{
+ if (next_release_selects) {
+ bool ret = Entry::on_button_release_event (ev);
+ select_region (0, -1);
+ next_release_selects = false;
+ return ret;
+ }
+
+ return Entry::on_button_release_event (ev);
+}
+
diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
index ebce4e2de9..e5b8e31b58 100644
--- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
+++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h
@@ -20,7 +20,8 @@
#ifndef __gtkmm2ext_bar_controller_h__
#define __gtkmm2ext_bar_controller_h__
-#include <gtkmm.h>
+#include <gtkmm/frame.h>
+#include <gtkmm/drawingarea.h>
#include <gtkmm2ext/binding_proxy.h>
namespace ARDOUR {
@@ -35,10 +36,6 @@ class BarController : public Gtk::Frame
BarController (Gtk::Adjustment& adj, PBD::Controllable&, sigc::slot<void,char*,unsigned int>);
virtual ~BarController () {}
- void set_sensitive (bool yn) {
- darea.set_sensitive (yn);
- }
-
enum Style {
LeftToRight,
RightToLeft,
@@ -53,6 +50,8 @@ class BarController : public Gtk::Frame
void set_with_text (bool yn);
void set_use_parent (bool yn);
+ void set_sensitive (bool yn);
+
Gtk::SpinButton& get_spin_button() { return spinner; }
sigc::signal<void> StartGesture;
@@ -79,12 +78,12 @@ class BarController : public Gtk::Frame
Gtk::SpinButton spinner;
bool use_parent;
- bool button_press (GdkEventButton *);
- bool button_release (GdkEventButton *);
- bool motion (GdkEventMotion *);
- bool expose (GdkEventExpose *);
- bool scroll (GdkEventScroll *);
- bool entry_focus_out (GdkEventFocus*);
+ virtual bool button_press (GdkEventButton *);
+ virtual bool button_release (GdkEventButton *);
+ virtual bool motion (GdkEventMotion *);
+ virtual bool expose (GdkEventExpose *);
+ virtual bool scroll (GdkEventScroll *);
+ virtual bool entry_focus_out (GdkEventFocus*);
gint mouse_control (double x, GdkWindow* w, double scaling);
@@ -92,6 +91,7 @@ class BarController : public Gtk::Frame
gint switch_to_spinner ();
void entry_activated ();
+ void drop_grab ();
};
diff --git a/libs/gtkmm2ext/gtkmm2ext/focus_entry.h b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h
new file mode 100644
index 0000000000..5d9d7fdac7
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/focus_entry.h
@@ -0,0 +1,22 @@
+#ifndef __gtkmm2ext_focus_entry_h__
+#define __gtkmm2ext_focus_entry_h__
+
+#include <gtkmm/entry.h>
+
+namespace Gtkmm2ext {
+
+class FocusEntry : public Gtk::Entry
+{
+ public:
+ FocusEntry ();
+
+ protected:
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ private:
+ bool next_release_selects;
+};
+
+}
+
+#endif /* __gtkmm2ext_focus_entry_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/pixfader.h b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
new file mode 100644
index 0000000000..bb4176240a
--- /dev/null
+++ b/libs/gtkmm2ext/gtkmm2ext/pixfader.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: fastmeter.h 570 2006-06-07 21:21:21Z sampo $
+*/
+
+#ifndef __gtkmm2ext_pixfader_h__
+#define __gtkmm2ext_pixfader_h__
+
+#include <cmath>
+
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/adjustment.h>
+#include <gdkmm/pixbuf.h>
+
+namespace Gtkmm2ext {
+
+class PixFader : public Gtk::DrawingArea {
+ public:
+ PixFader (Glib::RefPtr<Gdk::Pixbuf> belt_image, Gtk::Adjustment& adjustment);
+ virtual ~PixFader ();
+
+ protected:
+ Gtk::Adjustment& adjustment;
+
+ void on_size_request (GtkRequisition*);
+
+ bool on_expose_event (GdkEventExpose*);
+ bool on_button_press_event (GdkEventButton*);
+ bool on_button_release_event (GdkEventButton*);
+ bool on_motion_notify_event (GdkEventMotion*);
+ bool on_scroll_event (GdkEventScroll* ev);
+
+ private:
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf;
+ gint pixheight;
+
+ GdkRectangle view;
+
+ GdkWindow* grab_window;
+ double grab_y;
+ double grab_start;
+ int last_drawn;
+ bool dragging;
+ float default_value;
+ int unity_y;
+
+ void adjustment_changed ();
+
+ int display_height ();
+};
+
+
+} /* namespace */
+
+ #endif /* __gtkmm2ext_pixfader_h__ */
diff --git a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
index f0f645eab7..c137dbabf5 100644
--- a/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
+++ b/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
@@ -22,7 +22,7 @@
#include <gtkmm.h>
#include <gtkmm2ext/popup.h>
-#include <gtkmm2ext/pixscroller.h>
+#include <gtkmm2ext/pixfader.h>
#include <gtkmm2ext/binding_proxy.h>
namespace Gtkmm2ext {
@@ -35,11 +35,10 @@ namespace PBD {
namespace Gtkmm2ext {
-class SliderController : public Gtkmm2ext::PixScroller
+class SliderController : public Gtkmm2ext::PixFader
{
public:
- SliderController (Glib::RefPtr<Gdk::Pixbuf> slider,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+ SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment* adj,
PBD::Controllable&,
bool with_numeric = true);
@@ -64,8 +63,7 @@ class SliderController : public Gtkmm2ext::PixScroller
class VSliderController : public SliderController
{
public:
- VSliderController (Glib::RefPtr<Gdk::Pixbuf> slider,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+ VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
PBD::Controllable&,
bool with_numeric = true);
@@ -74,8 +72,7 @@ class VSliderController : public SliderController
class HSliderController : public SliderController
{
public:
- HSliderController (Glib::RefPtr<Gdk::Pixbuf> slider,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+ HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
PBD::Controllable&,
bool with_numeric = true);
diff --git a/libs/gtkmm2ext/pixfader.cc b/libs/gtkmm2ext/pixfader.cc
new file mode 100644
index 0000000000..f3a40ffc69
--- /dev/null
+++ b/libs/gtkmm2ext/pixfader.cc
@@ -0,0 +1,249 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: fastmeter.h 570 2006-06-07 21:21:21Z sampo $
+*/
+
+
+#include <iostream>
+#include <gtkmm2ext/pixfader.h>
+
+using namespace Gtkmm2ext;
+using namespace Gtk;
+using namespace Gdk;
+using namespace std;
+
+PixFader::PixFader (Glib::RefPtr<Pixbuf> belt, Gtk::Adjustment& adj)
+ : adjustment (adj),
+ pixbuf (belt)
+{
+ dragging = false;
+ default_value = adjustment.get_value();
+ last_drawn = -1;
+ pixheight = pixbuf->get_height();
+
+ view.x = 0;
+ view.y = 0;
+ view.width = pixbuf->get_width();
+ view.height = pixheight / 2;
+
+ unity_y = (int) rint (view.height - (default_value * view.height)) - 1;
+
+ add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
+
+ adjustment.signal_value_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
+ adjustment.signal_changed().connect (mem_fun (*this, &PixFader::adjustment_changed));
+}
+
+PixFader::~PixFader ()
+{
+}
+
+bool
+PixFader::on_expose_event (GdkEventExpose* ev)
+{
+ GdkRectangle intersection;
+ int dh = display_height ();
+ int offset_into_pixbuf = (int) floor (view.height / ((float) view.height / dh));
+ Glib::RefPtr<Gdk::GC> fg_gc (get_style()->get_fg_gc(get_state()));
+
+ if (gdk_rectangle_intersect (&view, &ev->area, &intersection)) {
+ get_window()->draw_pixbuf (fg_gc, pixbuf,
+ intersection.x, offset_into_pixbuf + intersection.y,
+ intersection.x, intersection.y,
+ intersection.width, intersection.height,
+ Gdk::RGB_DITHER_NONE, 0, 0);
+
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, view.width - 1, 0); /* top */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_ACTIVE), 0, 0, 0, view.height - 1); /* left */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), view.width - 1, 0, view.width - 1, view.height - 1); /* right */
+ get_window()->draw_line (get_style()->get_bg_gc(STATE_NORMAL), 0, view.height - 1, view.width - 1, view.height - 1); /* bottom */
+ }
+
+ /* always draw the line */
+
+ get_window()->draw_line (fg_gc, 1, unity_y, view.width - 2, unity_y);
+
+ last_drawn = dh;
+ return true;
+}
+
+void
+PixFader::on_size_request (GtkRequisition* req)
+{
+ req->width = view.width;
+ req->height = view.height;
+}
+
+bool
+PixFader::on_button_press_event (GdkEventButton* ev)
+{
+ switch (ev->button) {
+ case 1:
+ case 2:
+ add_modal_grab();
+ grab_y = ev->y;
+ grab_start = ev->y;
+ grab_window = ev->window;
+ dragging = true;
+ break;
+ default:
+ break;
+ }
+
+
+ return false;
+}
+
+bool
+PixFader::on_button_release_event (GdkEventButton* ev)
+{
+ double fract;
+
+ switch (ev->button) {
+ case 1:
+ if (dragging) {
+ remove_modal_grab();
+ dragging = false;
+
+ if (ev->y == grab_start) {
+
+ /* no motion - just a click */
+
+ if (ev->state & Gdk::SHIFT_MASK) {
+ adjustment.set_value (default_value);
+ } else if (ev->state & GDK_CONTROL_MASK) {
+ adjustment.set_value (adjustment.get_lower());
+ } else if (ev->y < view.height - display_height()) {
+ /* above the current display height, remember X Window coords */
+ adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
+ } else {
+ adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment());
+ }
+ }
+
+ }
+ break;
+
+ case 2:
+ if (dragging) {
+ remove_modal_grab();
+ dragging = false;
+
+ fract = 1.0 - (ev->y / view.height); // inverted X Window coordinates, grrr
+
+ fract = min (1.0, fract);
+ fract = max (0.0, fract);
+
+ adjustment.set_value (fract * (adjustment.get_upper() - adjustment.get_lower()));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool
+PixFader::on_scroll_event (GdkEventScroll* ev)
+{
+ double scale;
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 0.5;
+ }
+
+ switch (ev->direction) {
+
+ case GDK_SCROLL_UP:
+ /* wheel up */
+ adjustment.set_value (adjustment.get_value() + (adjustment.get_page_increment() * scale));
+ break;
+ case GDK_SCROLL_DOWN:
+ /* wheel down */
+ adjustment.set_value (adjustment.get_value() - (adjustment.get_page_increment() * scale));
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+PixFader::on_motion_notify_event (GdkEventMotion* ev)
+{
+ if (dragging) {
+ double fract;
+ double delta;
+ double scale;
+
+ if (ev->window != grab_window) {
+ grab_y = ev->y;
+ grab_window = ev->window;
+ return true;
+ }
+
+ if (ev->state & GDK_CONTROL_MASK) {
+ if (ev->state & GDK_MOD1_MASK) {
+ scale = 0.05;
+ } else {
+ scale = 0.1;
+ }
+ } else {
+ scale = 1.0;
+ }
+
+ delta = ev->y - grab_y;
+ grab_y = ev->y;
+
+ fract = (delta / view.height);
+
+ fract = min (1.0, fract);
+ fract = max (-1.0, fract);
+
+ // X Window is top->bottom for 0..Y
+
+ fract = -fract;
+
+ adjustment.set_value (adjustment.get_value() + scale * fract * (adjustment.get_upper() - adjustment.get_lower()));
+ }
+
+ return true;
+}
+
+void
+PixFader::adjustment_changed ()
+{
+ if (display_height() != last_drawn) {
+ queue_draw ();
+ }
+}
+
+int
+PixFader::display_height ()
+{
+ float fract = (adjustment.get_upper() - adjustment.get_value ()) / ((adjustment.get_upper() - adjustment.get_lower()));
+ return (int) floor (view.height * (1.0 - fract));
+}
diff --git a/libs/gtkmm2ext/prompter.cc b/libs/gtkmm2ext/prompter.cc
index c3a04f19a8..d06204d356 100644
--- a/libs/gtkmm2ext/prompter.cc
+++ b/libs/gtkmm2ext/prompter.cc
@@ -86,7 +86,7 @@ Prompter::get_result (string &str, bool strip)
{
str = entry.get_text ();
if (strip) {
- strip_whitespace_edges (str);
+ PBD::strip_whitespace_edges (str);
}
}
diff --git a/libs/gtkmm2ext/slider_controller.cc b/libs/gtkmm2ext/slider_controller.cc
index e524eba1cb..3e2b42f409 100644
--- a/libs/gtkmm2ext/slider_controller.cc
+++ b/libs/gtkmm2ext/slider_controller.cc
@@ -20,7 +20,7 @@
#include <string>
#include <gtkmm2ext/gtk_ui.h>
-#include <gtkmm2ext/pixscroller.h>
+#include <gtkmm2ext/pixfader.h>
#include <gtkmm2ext/slider_controller.h>
#include "i18n.h"
@@ -28,13 +28,12 @@
using namespace Gtkmm2ext;
using namespace PBD;
-SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> slide,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
Controllable& c,
bool with_numeric)
- : PixScroller (*adj, slide, rail),
+ : PixFader (image, *adj),
binding_proxy (c),
spin (*adj, 0, 2)
{
@@ -47,7 +46,7 @@ SliderController::SliderController (Glib::RefPtr<Gdk::Pixbuf> slide,
void
SliderController::set_value (float v)
{
- adj.set_value (v);
+ adjustment.set_value (v);
}
bool
@@ -56,16 +55,15 @@ SliderController::on_button_press_event (GdkEventButton *ev)
if (binding_proxy.button_press_handler (ev)) {
return true;
}
- return PixScroller::on_button_press_event (ev);
+ return PixFader::on_button_press_event (ev);
}
-VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> slide,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
Controllable& control,
bool with_numeric)
- : SliderController (slide, rail, adj, control, with_numeric)
+ : SliderController (image, adj, control, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);
@@ -76,13 +74,12 @@ VSliderController::VSliderController (Glib::RefPtr<Gdk::Pixbuf> slide,
}
}
-HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> slide,
- Glib::RefPtr<Gdk::Pixbuf> rail,
+HSliderController::HSliderController (Glib::RefPtr<Gdk::Pixbuf> image,
Gtk::Adjustment *adj,
Controllable& control,
bool with_numeric)
- : SliderController (slide, rail, adj, control, with_numeric)
+ : SliderController (image, adj, control, with_numeric)
{
if (with_numeric) {
spin_frame.add (spin);
diff --git a/libs/gtkmm2ext/tearoff.cc b/libs/gtkmm2ext/tearoff.cc
index e4a9207195..92bde5541e 100644
--- a/libs/gtkmm2ext/tearoff.cc
+++ b/libs/gtkmm2ext/tearoff.cc
@@ -127,7 +127,7 @@ TearOff::close_click (GdkEventButton* ev)
gint
TearOff::window_button_press (GdkEventButton* ev)
{
- if (dragging) {
+ if (dragging || ev->button != 1) {
dragging = false;
own_window.remove_modal_grab();
return true;
@@ -172,6 +172,12 @@ TearOff::window_motion (GdkEventMotion* ev)
return true;
}
+ if (!(ev->state & GDK_BUTTON1_MASK)) {
+ dragging = false;
+ own_window.remove_modal_grab();
+ return true;
+ }
+
x_delta = ev->x_root - drag_x;
y_delta = ev->y_root - drag_y;
diff --git a/libs/libglademm/SConscript b/libs/libglademm/SConscript
index 1ee6926580..0d22ba243f 100644
--- a/libs/libglademm/SConscript
+++ b/libs/libglademm/SConscript
@@ -15,7 +15,7 @@ libglade = libglademm.SharedLibrary('libglademm', libglademm_files)
Default(libglade)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libglade))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libglade))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'libglademmconfig.h', 'libglademm.h'] +
diff --git a/libs/libgnomecanvasmm/SConscript b/libs/libgnomecanvasmm/SConscript
index d9620dc378..7cab8b707a 100644
--- a/libs/libgnomecanvasmm/SConscript
+++ b/libs/libgnomecanvasmm/SConscript
@@ -20,7 +20,7 @@ gnomecanvasmm.Merge([libraries['glibmm2'],
libgnomecanvasmm = gnomecanvasmm.SharedLibrary('libgnomecanvasmm', gnomecanvasmm_files)
Default(libgnomecanvasmm)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libgnomecanvasmm))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libgnomecanvasmm))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'libgnomecanvasmmconfig.h', 'libgnomecanvasmm.h'] +
diff --git a/libs/libsndfile/SConscript b/libs/libsndfile/SConscript
index f8e9fc5ecb..9e8ccc93f7 100644
--- a/libs/libsndfile/SConscript
+++ b/libs/libsndfile/SConscript
@@ -6,8 +6,9 @@ import glob
sndfile_files = glob.glob('src/*.c') + glob.glob('src/GSM610/*.c') + glob.glob('src/G72x/*.c')
-Import('env install_prefix')
+Import('env install_prefix libraries')
sndfile = env.Copy()
+sndfile.Merge([libraries['flac'] ])
domain = 'libsndfile'
@@ -31,7 +32,7 @@ sndfile_h = sndfile.Command('src/sndfile.h', ['src/sndfile.h.in'], 'cd libs/libs
Default([sndfile_h,libsndfile])
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libsndfile))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libsndfile))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'NEWS', 'README', 'AUTHORS', 'ChangeLog',
diff --git a/libs/libsndfile/configure b/libs/libsndfile/configure
index 8aaca4e783..bfa95c3aac 100755
--- a/libs/libsndfile/configure
+++ b/libs/libsndfile/configure
@@ -12235,9 +12235,17 @@ rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>conftest.er1
ac_status=$?
+
+ cat conftest.$ac_ext > blah1.c
+
+ echo $CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext > blah1
+
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
+
+ cat conftest.err > blah2
+
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
diff --git a/libs/midi++2/SConscript b/libs/midi++2/SConscript
index 477d49c6ca..e9fbc0abf5 100644
--- a/libs/midi++2/SConscript
+++ b/libs/midi++2/SConscript
@@ -57,7 +57,7 @@ libmidi2 = midi2.SharedLibrary('midi++', [ sources, sysdep_src ])
Default(libmidi2)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libmidi2))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libmidi2))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript' ] + sources + sysdep_sources +
diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc
index 4fc24e8711..2aad0e072d 100644
--- a/libs/midi++2/jack_midiport.cc
+++ b/libs/midi++2/jack_midiport.cc
@@ -109,7 +109,7 @@ JACK_MidiPort::create_ports(PortRequest & req)
_jack_output_port = jack_port_register(_jack_client,
string(req.tagname).append("_out").c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
- jack_midi_reset_new_port(
+ jack_midi_clear_buffer(
jack_port_get_buffer(_jack_output_port, nframes), nframes);
ret = ret && (_jack_output_port != NULL);
}
@@ -118,7 +118,7 @@ JACK_MidiPort::create_ports(PortRequest & req)
_jack_input_port = jack_port_register(_jack_client,
string(req.tagname).append("_in").c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
- jack_midi_reset_new_port(
+ jack_midi_clear_buffer(
jack_port_get_buffer(_jack_input_port, nframes), nframes);
ret = ret && (_jack_input_port != NULL);
}
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
index f474834fd8..afb24a4311 100644
--- a/libs/pbd/SConscript
+++ b/libs/pbd/SConscript
@@ -20,9 +20,11 @@ pbd.Append(POTFILE=domain + '.pot')
pbd_files = Split("""
basename.cc
base_ui.cc
-convert.cc
command.cc
+convert.cc
+copyfile.cc
controllable.cc
+enumwriter.cc
dmalloc.cc
error.cc
id.cc
@@ -66,7 +68,7 @@ mount_env.Program('mountpoint', 'mountpoint.cc')
if env['NLS']:
i18n (pbd, pbd_files, env)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libpbd))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libpbd))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h', 'pbd/abstract_ui.cc' ] +
diff --git a/libs/pbd/basename.cc b/libs/pbd/basename.cc
index a51e393b78..9beed93625 100644
--- a/libs/pbd/basename.cc
+++ b/libs/pbd/basename.cc
@@ -1,20 +1,13 @@
-#include <iostream>
-#include <string.h>
#include <pbd/basename.h>
+#include <glibmm/miscutils.h>
+using Glib::ustring;
-// implement this using Glib::path_get_basename
-std::string
-PBD::basename_nosuffix (const std::string& str)
+ustring
+PBD::basename_nosuffix (ustring str)
{
- std::string::size_type slash = str.find_last_of ('/');
- std::string noslash;
+ ustring base = Glib::path_get_basename (str);
- if (slash == std::string::npos) {
- noslash = str;
- } else {
- noslash = str.substr (slash+1);
- }
+ return base.substr (0, base.find_last_of ('.'));
- return noslash.substr (0, noslash.find_last_of ('.'));
}
diff --git a/libs/pbd/controllable.cc b/libs/pbd/controllable.cc
index 2264a955ae..049ad0aa21 100644
--- a/libs/pbd/controllable.cc
+++ b/libs/pbd/controllable.cc
@@ -18,8 +18,10 @@ Controllable::Controllable (std::string name)
XMLNode&
Controllable::get_state ()
{
- XMLNode* node = new XMLNode (_name);
+ XMLNode* node = new XMLNode (X_("controllable"));
char buf[64];
+
+ node->add_property (X_("name"), _name); // not reloaded from XML state, just there to look at
_id.print (buf, sizeof (buf));
node->add_property (X_("id"), buf);
return *node;
diff --git a/libs/pbd/copyfile.cc b/libs/pbd/copyfile.cc
new file mode 100644
index 0000000000..d36ecef58a
--- /dev/null
+++ b/libs/pbd/copyfile.cc
@@ -0,0 +1,38 @@
+#include <fstream>
+#include <unistd.h>
+
+#include <pbd/copyfile.h>
+#include <pbd/error.h>
+#include <pbd/compose.h>
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace std;
+
+int
+PBD::copy_file (Glib::ustring from, Glib::ustring to)
+{
+ ifstream in (from.c_str());
+ ofstream out (to.c_str());
+
+ if (!in) {
+ error << string_compose (_("Could not open %1 for copy"), from) << endmsg;
+ return -1;
+ }
+
+ if (!out) {
+ error << string_compose (_("Could not open %1 as copy"), to) << endmsg;
+ return -1;
+ }
+
+ out << in.rdbuf();
+
+ if (!in || !out) {
+ error << string_compose (_("Could not copy existing file %1 to %2"), from, to) << endmsg;
+ unlink (to.c_str());
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/libs/pbd/enumwriter.cc b/libs/pbd/enumwriter.cc
new file mode 100644
index 0000000000..7674410ec9
--- /dev/null
+++ b/libs/pbd/enumwriter.cc
@@ -0,0 +1,273 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <ctype.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <pbd/enumwriter.h>
+#include <pbd/error.h>
+#include <pbd/compose.h>
+
+using namespace std;
+using namespace PBD;
+
+#include "i18n.h"
+
+EnumWriter* EnumWriter::_instance = 0;
+map<string,string> EnumWriter::hack_table;
+
+static int
+nocase_cmp(const string & s1, const string& s2)
+{
+ string::const_iterator it1 = s1.begin();
+ string::const_iterator it2 = s2.begin();
+
+ while ((it1 != s1.end()) && (it2 != s2.end())) {
+ if(::toupper(*it1) != ::toupper(*it2)) {//letters differ?
+ // return -1 to indicate 'smaller than', 1 otherwise
+ return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
+ }
+
+ ++it1;
+ ++it2;
+ }
+
+ string::size_type size1 = s1.size();
+ string::size_type size2 = s2.size();
+
+ //return -1,0 or 1 according to strings' lengths
+
+ if (size1 == size2) {
+ return 0;
+ }
+
+ return (size1 < size2) ? -1 : 1;
+}
+
+EnumWriter::EnumWriter ()
+{
+ if (_instance == 0) {
+ _instance = this;
+ }
+}
+
+EnumWriter::~EnumWriter ()
+{
+}
+
+void
+EnumWriter::register_distinct (string type, vector<int> v, vector<string> s)
+{
+ pair<string,EnumRegistration> newpair;
+ pair<Registry::iterator,bool> result;
+
+ newpair.first = type;
+ newpair.second = EnumRegistration (v, s, false);
+
+ result = registry.insert (newpair);
+
+ if (!result.second) {
+ warning << string_compose (_("enum type \"%1\" already registered with the enum writer"), type) << endmsg;
+ }
+}
+
+void
+EnumWriter::register_bits (string type, vector<int> v, vector<string> s)
+{
+ pair<string,EnumRegistration> newpair;
+ pair<Registry::iterator,bool> result;
+
+ newpair.first = type;
+ newpair.second = EnumRegistration (v, s, true);
+
+ result = registry.insert (newpair);
+
+ if (!result.second) {
+ warning << _("enum type \"%1\" already registered with the enum writer") << endmsg;
+ }
+}
+
+string
+EnumWriter::write (string type, int value)
+{
+ Registry::iterator x = registry.find (type);
+
+ if (x == registry.end()) {
+ error << string_compose (_("EnumWriter: unknown enumeration type \"%1\""), type) << endmsg;
+ throw unknown_enumeration();
+ }
+
+ if (x->second.bitwise) {
+ return write_bits (x->second, value);
+ } else {
+ return write_distinct (x->second, value);
+ }
+}
+
+int
+EnumWriter::read (string type, string value)
+{
+ Registry::iterator x = registry.find (type);
+
+ if (x == registry.end()) {
+ error << string_compose (_("EnumWriter: unknown enumeration type \"%1\""), type) << endmsg;
+ throw unknown_enumeration();
+ }
+
+ if (x->second.bitwise) {
+ return read_bits (x->second, value);
+ } else {
+ return read_distinct (x->second, value);
+ }
+}
+
+string
+EnumWriter::write_bits (EnumRegistration& er, int value)
+{
+ vector<int>::iterator i;
+ vector<string>::iterator s;
+ string result;
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (value & (*i)) {
+ if (!result.empty()) {
+ result += ',';
+ }
+ result += (*s);
+ }
+ }
+
+ return result;
+}
+
+string
+EnumWriter::write_distinct (EnumRegistration& er, int value)
+{
+ vector<int>::iterator i;
+ vector<string>::iterator s;
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (value == (*i)) {
+ return (*s);
+ }
+ }
+
+ return string();
+}
+
+int
+EnumWriter::read_bits (EnumRegistration& er, string str)
+{
+ vector<int>::iterator i;
+ vector<string>::iterator s;
+ int result = 0;
+ bool found = false;
+ string::size_type comma;
+
+ /* catch old-style hex numerics */
+
+ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+ return strtol (str.c_str(), (char **) 0, 16);
+ }
+
+ /* catch old style dec numerics */
+
+ if (strspn (str.c_str(), "0123456789") == str.length()) {
+ return strtol (str.c_str(), (char **) 0, 10);
+ }
+
+ do {
+
+ comma = str.find_first_of (',');
+ string segment = str.substr (0, comma);
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (segment == *s || nocase_cmp (segment, *s) == 0) {
+ result |= (*i);
+ found = true;
+ }
+ }
+
+ if (comma == string::npos) {
+ break;
+ }
+
+ str = str.substr (comma+1);
+
+ } while (true);
+
+ if (!found) {
+ throw unknown_enumeration();
+ }
+
+ return result;
+}
+
+int
+EnumWriter::read_distinct (EnumRegistration& er, string str)
+{
+ vector<int>::iterator i;
+ vector<string>::iterator s;
+
+ /* catch old-style hex numerics */
+
+ if (str.length() > 2 && str[0] == '0' && str[1] == 'x') {
+ return strtol (str.c_str(), (char **) 0, 16);
+ }
+
+ /* catch old style dec numerics */
+
+ if (strspn (str.c_str(), "0123456789") == str.length()) {
+ return strtol (str.c_str(), (char **) 0, 10);
+ }
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (str == (*s) || nocase_cmp (str, *s) == 0) {
+ return (*i);
+ }
+ }
+
+ /* failed to find it as-is. check to see if there a hack for the name we're looking up */
+
+ map<string,string>::iterator x;
+
+ if ((x = hack_table.find (str)) != hack_table.end()) {
+
+ cerr << "found hack for " << str << " = " << x->second << endl;
+
+ str = x->second;
+
+ for (i = er.values.begin(), s = er.names.begin(); i != er.values.end(); ++i, ++s) {
+ if (str == (*s) || nocase_cmp (str, *s) == 0) {
+ return (*i);
+ }
+ }
+ }
+
+ throw unknown_enumeration();
+}
+
+void
+EnumWriter::add_to_hack_table (string str, string hacked)
+{
+ hack_table[str] = hacked;
+}
diff --git a/libs/pbd/pbd/basename.h b/libs/pbd/pbd/basename.h
index a7e36acff0..a622643541 100644
--- a/libs/pbd/pbd/basename.h
+++ b/libs/pbd/pbd/basename.h
@@ -1,13 +1,13 @@
#ifndef __stupid_basename_h__
#define __stupid_basename_h__
-#include <string>
+#include <glibmm/ustring.h>
namespace PBD
{
-extern std::string basename_nosuffix (const std::string&);
+Glib::ustring basename_nosuffix (Glib::ustring);
-} // namespace PBD
+}
#endif // __stupid_basename_h__
diff --git a/libs/pbd/pbd/copyfile.h b/libs/pbd/pbd/copyfile.h
new file mode 100644
index 0000000000..8a1bf242bb
--- /dev/null
+++ b/libs/pbd/pbd/copyfile.h
@@ -0,0 +1,6 @@
+#include <glibmm/ustring.h>
+
+namespace PBD {
+
+ int copy_file (Glib::ustring from, Glib::ustring to);
+}
diff --git a/libs/pbd/pbd/enumwriter.h b/libs/pbd/pbd/enumwriter.h
new file mode 100644
index 0000000000..f53388f3cc
--- /dev/null
+++ b/libs/pbd/pbd/enumwriter.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <map>
+#include <string>
+#include <vector>
+#include <exception>
+
+
+namespace PBD {
+
+class unknown_enumeration : public std::exception {
+ public:
+ virtual const char *what() const throw() { return "unknown enumerator in PBD::EnumWriter"; }
+};
+
+class EnumWriter {
+ public:
+ EnumWriter ();
+ ~EnumWriter ();
+
+ static EnumWriter& instance() { return *_instance; }
+
+ void register_distinct (std::string type, std::vector<int>, std::vector<std::string>);
+ void register_bits (std::string type, std::vector<int>, std::vector<std::string>);
+
+ std::string write (std::string type, int value);
+ int read (std::string type, std::string value);
+
+ void add_to_hack_table (std::string str, std::string hacked_str);
+
+ private:
+ struct EnumRegistration {
+ std::vector<int> values;
+ std::vector<std::string> names;
+ bool bitwise;
+
+ EnumRegistration() {}
+ EnumRegistration (std::vector<int>& v, std::vector<std::string>& s, bool b)
+ : values (v), names (s), bitwise (b) {}
+ };
+
+ typedef std::map<std::string, EnumRegistration> Registry;
+ Registry registry;
+
+ std::string write_bits (EnumRegistration&, int value);
+ std::string write_distinct (EnumRegistration&, int value);
+
+ int read_bits (EnumRegistration&, std::string value);
+ int read_distinct (EnumRegistration&, std::string value);
+
+ static EnumWriter* _instance;
+ static std::map<std::string,std::string> hack_table;
+};
+
+}
+
+#define enum_2_string(e) (PBD::EnumWriter::instance().write (typeid(e).name(), e))
+#define string_2_enum(str,e) (PBD::EnumWriter::instance().read (typeid(e).name(), (str)))
+
diff --git a/libs/pbd/pbd/tokenizer.h b/libs/pbd/pbd/tokenizer.h
index a976b79341..b80e3eac4a 100644
--- a/libs/pbd/pbd/tokenizer.h
+++ b/libs/pbd/pbd/tokenizer.h
@@ -4,18 +4,24 @@
#include <iterator>
#include <string>
+#include <pbd/whitespace.h>
+
namespace PBD {
/**
Tokenize string, this should work for standard
- strings aswell as Glib::ustring. This is a bit of a hack,
+ strings as well as Glib::ustring. This is a bit of a hack,
there are much better string tokenizing patterns out there.
+ If strip_whitespace is set to true, tokens will be checked to see
+ that they still have a length after stripping. If no length, they
+ are discarded.
*/
template<typename StringType, typename Iter>
unsigned int
tokenize(const StringType& str,
const StringType& delims,
- Iter it)
+ Iter it,
+ bool strip_whitespace=false)
{
typename StringType::size_type start_pos = 0;
typename StringType::size_type end_pos = 0;
@@ -28,14 +34,30 @@ tokenize(const StringType& str,
if (end_pos == str.npos) {
end_pos = str.length();
}
- *it++ = str.substr(start_pos, end_pos - start_pos);
+ if (strip_whitespace) {
+ StringType stripped = str.substr(start_pos, end_pos - start_pos);
+ strip_whitespace_edges (stripped);
+ if (stripped.length()) {
+ *it++ = stripped;
+ }
+ } else {
+ *it++ = str.substr(start_pos, end_pos - start_pos);
+ }
++token_count;
start_pos = str.find_first_not_of(delims, end_pos + 1);
}
} while (start_pos != str.npos);
if (start_pos != str.npos) {
- *it++ = str.substr(start_pos, str.length() - start_pos);
+ if (strip_whitespace) {
+ StringType stripped = str.substr(start_pos, str.length() - start_pos);
+ strip_whitespace_edges (stripped);
+ if (stripped.length()) {
+ *it++ = stripped;
+ }
+ } else {
+ *it++ = str.substr(start_pos, str.length() - start_pos);
+ }
++token_count;
}
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
index eb46750e4f..4dfab5178f 100644
--- a/libs/pbd/pbd/undo.h
+++ b/libs/pbd/pbd/undo.h
@@ -94,7 +94,7 @@ class UndoHistory : public sigc::trackable
void clear_undo ();
void clear_redo ();
- XMLNode &get_state();
+ XMLNode &get_state(uint32_t depth = 0);
void save_state();
sigc::signal<void> Changed;
diff --git a/libs/pbd/pbd/whitespace.h b/libs/pbd/pbd/whitespace.h
index 6620a8fb50..6adb41641c 100644
--- a/libs/pbd/pbd/whitespace.h
+++ b/libs/pbd/pbd/whitespace.h
@@ -3,6 +3,12 @@
#include <string>
+namespace PBD {
+
+// returns the empty string if the entire string is whitespace
+// so check length after calling.
extern void strip_whitespace_edges (std::string& str);
+} // namespace PBD
+
#endif // __pbd_whitespace_h__
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc
index 277b83bfce..4719d0968e 100644
--- a/libs/pbd/undo.cc
+++ b/libs/pbd/undo.cc
@@ -236,13 +236,31 @@ UndoHistory::clear ()
Changed (); /* EMIT SIGNAL */
}
-XMLNode & UndoHistory::get_state()
+XMLNode&
+UndoHistory::get_state (uint32_t depth)
{
XMLNode *node = new XMLNode ("UndoHistory");
- list<UndoTransaction*>::iterator it;
- for (it = UndoList.begin(); it != UndoList.end(); it++) {
- node->add_child_nocopy((*it)->get_state());
+ 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 */
+
+ list<UndoTransaction*> in_order;
+
+ for (list<UndoTransaction*>::reverse_iterator it = UndoList.rbegin(); it != UndoList.rend() && depth; ++it, depth--) {
+ in_order.push_front (*it);
+ }
+
+ for (list<UndoTransaction*>::iterator it = in_order.begin(); it != in_order.end(); it++) {
+ node->add_child_nocopy((*it)->get_state());
+ }
}
return *node;
diff --git a/libs/pbd/whitespace.cc b/libs/pbd/whitespace.cc
index 53616133ad..a719fb169f 100644
--- a/libs/pbd/whitespace.cc
+++ b/libs/pbd/whitespace.cc
@@ -2,6 +2,8 @@
using namespace std;
+namespace PBD {
+
void
strip_whitespace_edges (string& str)
{
@@ -24,7 +26,8 @@ strip_whitespace_edges (string& str)
}
if (i == len) {
- /* its all whitespace, not much we can do */
+ /* it's all whitespace, not much we can do */
+ str = "";
return;
}
@@ -55,3 +58,4 @@ strip_whitespace_edges (string& str)
}
}
+} // namespace PBD
diff --git a/libs/sigc++2/SConscript b/libs/sigc++2/SConscript
index 65833dfb53..b29aefb0cd 100644
--- a/libs/sigc++2/SConscript
+++ b/libs/sigc++2/SConscript
@@ -20,7 +20,7 @@ else :
Default([sigc2_config_h,libsigc2])
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libsigc2))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libsigc2))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'NEWS', 'README', 'AUTHORS', 'ChangeLog',
diff --git a/libs/soundtouch/SConscript b/libs/soundtouch/SConscript
index d37fd1f99b..9ddee87b0c 100644
--- a/libs/soundtouch/SConscript
+++ b/libs/soundtouch/SConscript
@@ -23,7 +23,7 @@ libst = st.SharedLibrary('soundtouch', soundtouch_files)
Default(libst)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libst))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libst))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript'] + soundtouch_files + glob.glob('*.h')))
diff --git a/libs/soundtouch/STTypes.h b/libs/soundtouch/STTypes.h
index c404675ecd..e1ea90d428 100644
--- a/libs/soundtouch/STTypes.h
+++ b/libs/soundtouch/STTypes.h
@@ -47,8 +47,12 @@ typedef unsigned long ulong;
typedef unsigned int BOOL;
+#ifndef FALSE
#define FALSE 0
+#endif
+#ifndef TRUE
#define TRUE 1
+#endif
#endif // _WINDEF_
diff --git a/libs/surfaces/control_protocol/SConscript b/libs/surfaces/control_protocol/SConscript
index 88aeeda376..026698500a 100644
--- a/libs/surfaces/control_protocol/SConscript
+++ b/libs/surfaces/control_protocol/SConscript
@@ -50,7 +50,7 @@ Default(libardour_cp)
if env['NLS']:
i18n (cp, cp_files, env)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libardour_cp))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2'), libardour_cp))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript' ] +
diff --git a/libs/surfaces/control_protocol/control_protocol/smpte.h b/libs/surfaces/control_protocol/control_protocol/smpte.h
index 09c1c9616a..b25a268aac 100644
--- a/libs/surfaces/control_protocol/control_protocol/smpte.h
+++ b/libs/surfaces/control_protocol/control_protocol/smpte.h
@@ -31,28 +31,18 @@ enum Wrap {
HOURS
};
-/** SMPTE frame rate (in frames per second).
- *
- * This should be eliminated in favour of a float to support arbitrary rates.
- */
-enum FPS {
- MTC_24_FPS = 0,
- MTC_25_FPS = 1,
- MTC_30_FPS_DROP = 2,
- MTC_30_FPS = 3
-};
-
struct Time {
bool negative;
uint32_t hours;
uint32_t minutes;
uint32_t seconds;
- uint32_t frames; ///< SMPTE frames (not audio samples)
- uint32_t subframes; ///< Typically unused
- FPS rate; ///< Frame rate of this Time
- static FPS default_rate; ///< Rate to use for default constructor
+ uint32_t frames; ///< SMPTE frames (not audio samples)
+ uint32_t subframes; ///< Typically unused
+ float rate; ///< Frame rate of this Time
+ static float default_rate;///< Rate to use for default constructor
+ bool drop; ///< Whether this Time uses dropframe SMPTE
- Time(FPS a_rate = default_rate) {
+ Time(float a_rate = default_rate) {
negative = false;
hours = 0;
minutes = 0;
diff --git a/libs/surfaces/control_protocol/smpte.cc b/libs/surfaces/control_protocol/smpte.cc
index 55d0660c59..5df159a52b 100644
--- a/libs/surfaces/control_protocol/smpte.cc
+++ b/libs/surfaces/control_protocol/smpte.cc
@@ -20,10 +20,11 @@
#define SMPTE_IS_ZERO( sm ) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours && !(sm.subframes))
#include <control_protocol/smpte.h>
+#include <ardour/configuration.h>
namespace SMPTE {
-FPS Time::default_rate = MTC_30_FPS;
+float Time::default_rate = 30.0;
/** Increment @a smpte by exactly one frame (keep subframes value).
@@ -38,7 +39,7 @@ increment( Time& smpte )
if (smpte.negative) {
if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) {
// We have a zero transition involving only subframes
- smpte.subframes = 80 - smpte.subframes;
+ smpte.subframes = ARDOUR::Config->get_subframes_per_frame() - smpte.subframes;
smpte.negative = false;
return SECONDS;
}
@@ -50,34 +51,42 @@ increment( Time& smpte )
}
return wrap;
}
-
- switch (smpte.rate) {
- case MTC_24_FPS:
+
+ switch ((int)ceil(smpte.rate)) {
+ case 24:
if (smpte.frames == 23) {
smpte.frames = 0;
wrap = SECONDS;
}
break;
- case MTC_25_FPS:
+ case 25:
if (smpte.frames == 24) {
smpte.frames = 0;
wrap = SECONDS;
}
break;
- case MTC_30_FPS_DROP:
- if (smpte.frames == 29) {
- if ( ((smpte.minutes + 1) % 10) && (smpte.seconds == 59) ) {
- smpte.frames = 2;
- }
- else {
- smpte.frames = 0;
- }
- wrap = SECONDS;
+ case 30:
+ if (smpte.drop) {
+ if (smpte.frames == 29) {
+ if ( ((smpte.minutes + 1) % 10) && (smpte.seconds == 59) ) {
+ smpte.frames = 2;
+ }
+ else {
+ smpte.frames = 0;
+ }
+ wrap = SECONDS;
+ }
+ } else {
+
+ if (smpte.frames == 29) {
+ smpte.frames = 0;
+ wrap = SECONDS;
+ }
}
break;
- case MTC_30_FPS:
- if (smpte.frames == 29) {
- smpte.frames = 0;
+ case 60:
+ if (smpte.frames == 59) {
+ smpte.frames = 0;
wrap = SECONDS;
}
break;
@@ -121,38 +130,46 @@ decrement( Time& smpte )
return wrap;
} else if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) {
// We have a zero transition involving only subframes
- smpte.subframes = 80 - smpte.subframes;
+ smpte.subframes = ARDOUR::Config->get_subframes_per_frame() - smpte.subframes;
smpte.negative = true;
return SECONDS;
}
- switch (smpte.rate) {
- case MTC_24_FPS:
+ switch ((int)ceil(smpte.rate)) {
+ case 24:
if (smpte.frames == 0) {
smpte.frames = 23;
wrap = SECONDS;
}
break;
- case MTC_25_FPS:
+ case 25:
if (smpte.frames == 0) {
smpte.frames = 24;
wrap = SECONDS;
}
break;
- case MTC_30_FPS_DROP:
- if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
- if (smpte.frames <= 2) {
- smpte.frames = 29;
+ case 30:
+ if (smpte.drop) {
+ if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
+ if (smpte.frames <= 2) {
+ smpte.frames = 29;
+ wrap = SECONDS;
+ }
+ } else if (smpte.frames == 0) {
+ smpte.frames = 29;
+ wrap = SECONDS;
+ }
+
+ } else {
+ if (smpte.frames == 0) {
+ smpte.frames = 29;
wrap = SECONDS;
}
- } else if (smpte.frames == 0) {
- smpte.frames = 29;
- wrap = SECONDS;
}
break;
- case MTC_30_FPS:
- if (smpte.frames == 0) {
- smpte.frames = 29;
+ case 60:
+ if (smpte.frames == 0) {
+ smpte.frames = 59;
wrap = SECONDS;
}
break;
@@ -212,7 +229,7 @@ increment_subframes( Time& smpte )
}
smpte.subframes++;
- if (smpte.subframes >= 80) {
+ if (smpte.subframes >= ARDOUR::Config->get_subframes_per_frame()) {
smpte.subframes = 0;
increment( smpte );
return FRAMES;
@@ -274,17 +291,19 @@ increment_seconds( Time& smpte )
}
} else {
// Go to highest possible frame in this second
- switch (smpte.rate) {
- case MTC_24_FPS:
+ switch ((int)ceil(smpte.rate)) {
+ case 24:
smpte.frames = 23;
break;
- case MTC_25_FPS:
+ case 25:
smpte.frames = 24;
break;
- case MTC_30_FPS_DROP:
- case MTC_30_FPS:
+ case 30:
smpte.frames = 29;
break;
+ case 60:
+ smpte.frames = 59;
+ break;
}
// Increment by one frame
@@ -304,17 +323,20 @@ seconds_floor( Time& smpte )
frames_floor( smpte );
// Go to lowest possible frame in this second
- switch (smpte.rate) {
- case MTC_24_FPS:
- case MTC_25_FPS:
- case MTC_30_FPS:
- smpte.frames = 0;
- break;
- case MTC_30_FPS_DROP:
- if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
- smpte.frames = 2;
+ switch ((int)ceil(smpte.rate)) {
+ case 24:
+ case 25:
+ case 30:
+ case 60:
+ if (!(smpte.drop)) {
+ smpte.frames = 0;
} else {
- smpte.frames = 0;
+
+ if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
+ smpte.frames = 2;
+ } else {
+ smpte.frames = 0;
+ }
}
break;
}
diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript
index f9c2de08f8..6c76e05464 100644
--- a/libs/surfaces/generic_midi/SConscript
+++ b/libs/surfaces/generic_midi/SConscript
@@ -34,6 +34,7 @@ genericmidi.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
genericmidi.Merge ([
libraries['ardour'],
libraries['ardour_cp'],
+ libraries['sndfile-ardour'],
libraries['midi++2'],
libraries['pbd'],
libraries['sigc2'],
@@ -50,7 +51,7 @@ Default(libardour_genericmidi)
if env['NLS']:
i18n (genericmidi, genericmidi_files, env)
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_genericmidi))
+env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_genericmidi))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript' ] +
diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
index 03dbfb353c..0256d5c359 100644
--- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
+++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc
@@ -234,7 +234,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node)
controllables.clear ();
- nlist = node.children();
+ nlist = node.children(); // "controls"
if (nlist.empty()) {
return 0;
diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc
index 6dc9bde8ad..75b5699f18 100644
--- a/libs/surfaces/generic_midi/midicontrollable.cc
+++ b/libs/surfaces/generic_midi/midicontrollable.cc
@@ -32,8 +32,6 @@ using namespace MIDI;
using namespace PBD;
using namespace ARDOUR;
-bool MIDIControllable::_send_feedback = false;
-
MIDIControllable::MIDIControllable (Port& p, Controllable& c, bool is_bistate)
: controllable (c), _port (p), bistate (is_bistate)
{
@@ -288,7 +286,7 @@ MIDIControllable::send_feedback ()
{
byte msg[3];
- if (setting || !_send_feedback || control_type == none) {
+ if (setting || !feedback || control_type == none) {
return;
}
@@ -302,7 +300,7 @@ MIDIControllable::send_feedback ()
MIDI::byte*
MIDIControllable::write_feedback (MIDI::byte* buf, int32_t& bufsize, bool force)
{
- if (control_type != none &&_send_feedback && bufsize > 2) {
+ if (control_type != none && feedback && bufsize > 2) {
MIDI::byte gm = (MIDI::byte) (controllable.get_value() * 127.0);
@@ -345,6 +343,12 @@ MIDIControllable::set_state (const XMLNode& node)
return -1;
}
+ if ((prop = node.property ("feedback")) != 0) {
+ feedback = (prop->value() == "yes");
+ } else {
+ feedback = true; // default
+ }
+
bind_midi (control_channel, control_type, control_additional);
return 0;
@@ -362,6 +366,7 @@ MIDIControllable::get_state ()
node.add_property ("channel", buf);
snprintf (buf, sizeof(buf), "0x%x", (int) control_additional);
node.add_property ("additional", buf);
+ node.add_property ("feedback", (feedback ? "yes" : "no"));
return node;
}
diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h
index ab15f9f4ab..8b63172916 100644
--- a/libs/surfaces/generic_midi/midicontrollable.h
+++ b/libs/surfaces/generic_midi/midicontrollable.h
@@ -80,8 +80,6 @@ class MIDIControllable : public Stateful
std::string _control_description;
bool feedback;
- static bool _send_feedback;
-
void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);
void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
diff --git a/libs/surfaces/tranzport/SConscript b/libs/surfaces/tranzport/SConscript
index 3f9cc5cc15..5d390f3e2f 100644
--- a/libs/surfaces/tranzport/SConscript
+++ b/libs/surfaces/tranzport/SConscript
@@ -44,12 +44,11 @@ tranzport.Merge ([
libardour_tranzport = tranzport.SharedLibrary('ardour_tranzport', tranzport_files)
-Default(libardour_tranzport)
-
-if env['NLS']:
- i18n (tranzport, tranzport_files, env)
-
-env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_tranzport))
+if tranzport['TRANZPORT']:
+ Default(libardour_tranzport)
+ if env['NLS']:
+ i18n (tranzport, tranzport_files, env)
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_tranzport))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript' ] +
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc
index ea85a32a77..bbb78d31d1 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc
@@ -18,6 +18,31 @@
$Id$
*/
+/* Design notes: The tranzport is a unique device, basically a
+ 20 lcd gui with 22 shift keys and 8 blinking lights.
+
+ As such it has several unique constraints. The device exerts flow control
+ by having a usb write fail. It is pointless to retry madly at that point,
+ the device is busy, and it's not going to become unbusy very quickly.
+
+ So writes need to be either "mandatory" or "unreliable", and therein
+ lies the rub, as the kernel can also drop writes, and missing an
+ interrupt in userspace is also generally bad.
+
+ It will be good one day, to break the gui, keyboard, and blinking light
+ components into separate parts, but for now, this remains monolithic.
+
+ A more complex surface might have hundreds of lights and several displays.
+
+ mike.taht@gmail.com
+ */
+
+#define DEFAULT_USB_TIMEOUT 10
+#define MAX_RETRY 1
+#define MAX_TRANZPORT_INFLIGHT 4
+#define DEBUG_TRANZPORT 0
+#define HAVE_TRANZPORT_KERNEL_DRIVER 0
+
#include <iostream>
#include <algorithm>
#include <cmath>
@@ -33,6 +58,7 @@
#include <ardour/route.h>
#include <ardour/audio_track.h>
#include <ardour/session.h>
+#include <ardour/tempo.h>
#include <ardour/location.h>
#include <ardour/dB.h>
@@ -51,6 +77,12 @@ BaseUI::RequestType LEDChange = BaseUI::new_request_type ();
BaseUI::RequestType Print = BaseUI::new_request_type ();
BaseUI::RequestType SetCurrentTrack = BaseUI::new_request_type ();
+/* Base Tranzport cmd strings */
+
+static const uint8_t cmd_light_on[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
+static const uint8_t cmd_light_off[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
+static const uint8_t cmd_write_screen[] = { 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00 };
+
static inline double
gain_to_slider_position (ARDOUR::gain_t g)
{
@@ -74,8 +106,7 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s)
/* tranzport controls one track at a time */
set_route_table_size (1);
-
- timeout = 60000;
+ timeout = 6000; // what is this for?
buttonmask = 0;
_datawheel = 0;
_device_status = STATUS_OFFLINE;
@@ -84,51 +115,212 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s)
last_where = max_frames;
wheel_mode = WheelTimeline;
wheel_shift_mode = WheelShiftGain;
+ wheel_increment = WheelIncrScreen;
+ bling_mode = BlingOff;
timerclear (&last_wheel_motion);
last_wheel_dir = 1;
last_track_gain = FLT_MAX;
display_mode = DisplayNormal;
gain_fraction = 0.0;
+ invalidate();
+ screen_init();
+ lights_init();
+ print(0,0,"!!Welcome to Ardour!!");
+ print(1,0,"!Peace through Music!");
+}
- memset (current_screen, 0, sizeof (current_screen));
- memset (pending_screen, 0, sizeof (pending_screen));
+void TranzportControlProtocol::light_validate (LightID light)
+{
+ lights_invalid[light] = 0;
+}
+
+void TranzportControlProtocol::light_invalidate (LightID light)
+{
+ lights_invalid[light] = 1;
+}
+
+void TranzportControlProtocol::lights_validate ()
+{
+ memset (lights_invalid, 0, sizeof (lights_invalid));
+}
+
+void TranzportControlProtocol::lights_invalidate ()
+{
+ memset (lights_invalid, 1, sizeof (lights_invalid));
+}
+
+void TranzportControlProtocol::lights_init()
+{
+ for (uint32_t i = 0; i < sizeof(lights_current)/sizeof(lights_current[0]); i++) {
+ lights_invalid[i] = lights_current[i] =
+ lights_pending[i] = lights_flash[i] = false;
+ }
+}
+
+
+
+int
+TranzportControlProtocol::lights_flush ()
+{
+ if ( _device_status == STATUS_OFFLINE) { return (0); }
+
+ // Figure out iterators one day soon
+ // for (LightID i = i.start(), i = i.end(); i++) {
+ // if (lights_pending[i] != lights_current[i] || lights_invalid[i]) {
+ // if (light_set(i, lights_pending[i])) {
+ // return i-1;
+ // }
+ // }
+ //}
+ if ((lights_pending[LightRecord] != lights_current[LightRecord]) || lights_invalid[LightRecord]) {
+ if (light_set(LightRecord,lights_pending[LightRecord])) {
+ return 1;
+ }
+ }
+ if ((lights_pending[LightTrackrec] != lights_current[LightTrackrec]) || lights_invalid[LightTrackrec]) {
+ if (light_set(LightTrackrec,lights_pending[LightTrackrec])) {
+ return 1;
+ }
+ }
+
+ if ((lights_pending[LightTrackmute] != lights_current[LightTrackmute]) || lights_invalid[LightTrackmute]) {
+ if (light_set(LightTrackmute,lights_pending[LightTrackmute])) {
+ return 1;
+ }
+ }
- for (uint32_t i = 0; i < sizeof(lights)/sizeof(lights[0]); ++i) {
- lights[i] = false;
+ if ((lights_pending[LightTracksolo] != lights_current[LightTracksolo]) || lights_invalid[LightTracksolo]) {
+ if (light_set(LightTracksolo,lights_pending[LightTracksolo])) {
+ return 1;
+ }
+ }
+ if ((lights_pending[LightAnysolo] != lights_current[LightAnysolo]) || lights_invalid[LightAnysolo]) {
+ if (light_set(LightAnysolo,lights_pending[LightAnysolo])) {
+ return 1;
+ }
+ }
+ if ((lights_pending[LightLoop] != lights_current[LightLoop]) || lights_invalid[LightLoop]) {
+ if (light_set(LightLoop,lights_pending[LightLoop])) {
+ return 1;
+ }
}
+ if ((lights_pending[LightPunch] != lights_current[LightPunch]) || lights_invalid[LightPunch]) {
+ if (light_set(LightPunch,lights_pending[LightPunch])) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
- for (uint32_t i = 0; i < sizeof(pending_lights)/sizeof(pending_lights[0]); ++i) {
- pending_lights[i] = false;
+// Screen specific commands
+
+void
+TranzportControlProtocol::screen_clear ()
+{
+ const char *blank = " ";
+ print(0,0,blank);
+ print(1,0,blank);
+}
+
+void TranzportControlProtocol::screen_invalidate ()
+{
+ for(int row = 0; row < 2; row++) {
+ for(int col = 0; col < 20; col++) {
+ screen_invalid[row][col] = true;
+ screen_current[row][col] = 0x7f;
+ screen_pending[row][col] = ' ';
+ // screen_flash[row][col] = ' ';
+ }
}
+ // memset (&screen_invalid, 1, sizeof(screen_invalid));
+ // memset (&screen_current, 0x7F, sizeof (screen_current)); // fill cache with a character we otherwise never use
}
-TranzportControlProtocol::~TranzportControlProtocol ()
+void TranzportControlProtocol::screen_validate ()
{
- set_active (false);
}
-bool
-TranzportControlProtocol::probe ()
+void TranzportControlProtocol::screen_init ()
{
- struct usb_bus *bus;
- struct usb_device *dev;
+ screen_invalidate();
+}
- usb_init();
- usb_find_busses();
- usb_find_devices();
+int
+TranzportControlProtocol::screen_flush ()
+{
+ int cell = 0, row, col_base, col, pending = 0;
+ if ( _device_status == STATUS_OFFLINE) { return (-1); }
+
+ for (row = 0; row < 2 && pending == 0; row++) {
+ for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
+ if ((screen_pending[row][col] != screen_current[row][col])
+ || screen_invalid[row][col]) {
+
+ /* something in this cell is different, so dump the cell to the device. */
+
+ uint8_t cmd[8];
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = screen_pending[row][col_base];
+ cmd[4] = screen_pending[row][col_base+1];
+ cmd[5] = screen_pending[row][col_base+2];
+ cmd[6] = screen_pending[row][col_base+3];
+ cmd[7] = 0x00;
- for (bus = usb_busses; bus; bus = bus->next) {
+ if(write(cmd) != 0) {
+ /* try to update this cell on the next go-round */
+#if DEBUG_TRANZPORT > 4
+ printf("usb screen update failed for some reason... why? \ncmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]);
+#endif
+ pending += 1;
+ // Shouldn't need to do this
+ // screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
+ // screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = true;
- for(dev = bus->devices; dev; dev = dev->next) {
- if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
- return true;
+ } else {
+ /* successful write: copy to current cached display */
+ screen_invalid[row][col_base] = screen_invalid[row][col_base+1] =
+ screen_invalid[row][col_base+2] = screen_invalid[row][col_base+3] = false;
+ memcpy (&screen_current[row][col_base], &screen_pending[row][col_base], 4);
+ }
+
+ /* skip the rest of the 4 character cell since we wrote+copied it already */
+
+ col_base += 4;
+ col = col_base;
+ cell++;
+
+ } else {
+
+ col++;
+
+ if (col && col % 4 == 0) {
+ cell++;
+ col_base += 4;
+ }
}
}
}
+ return pending;
+}
- return false;
+
+// Tranzport specific
+
+void TranzportControlProtocol::invalidate()
+{
+ lcd_damage(); lights_invalidate(); screen_invalidate(); // one of these days lcds can be fine but screens not
}
+TranzportControlProtocol::~TranzportControlProtocol ()
+{
+ set_active (false);
+}
+
+
int
TranzportControlProtocol::set_active (bool yn)
{
@@ -139,7 +331,7 @@ TranzportControlProtocol::set_active (bool yn)
if (open ()) {
return -1;
}
-
+
if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
_active = true;
} else {
@@ -148,11 +340,12 @@ TranzportControlProtocol::set_active (bool yn)
} else {
cerr << "Begin tranzport shutdown\n";
+ screen_clear ();
+ lcd_damage();
+ lights_off ();
+ for(int x = 0; x < 10 && flush(); x++) { usleep(1000); }
pthread_cancel_one (thread);
- cerr << "Thread dead\n";
- // lcd_clear ();
- // lights_off ();
- // cerr << "dev reset\n";
+ cerr << "Tranzport Thread dead\n";
close ();
_active = false;
cerr << "End tranzport shutdown\n";
@@ -167,8 +360,8 @@ TranzportControlProtocol::show_track_gain ()
{
if (route_table[0]) {
gain_t g = route_get_gain (0);
- if (g != last_track_gain) {
- char buf[16];
+ if ((g != last_track_gain) || lcd_isdamaged(0,9,8)) {
+ char buf[16];
snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
print (0, 9, buf);
last_track_gain = g;
@@ -191,20 +384,66 @@ void
TranzportControlProtocol::next_display_mode ()
{
switch (display_mode) {
- case DisplayNormal:
- display_mode = DisplayBigMeter;
- break;
- case DisplayBigMeter:
- display_mode = DisplayNormal;
- break;
+ case DisplayNormal:
+ enter_big_meter_mode();
+ break;
+
+ case DisplayBigMeter:
+ enter_normal_display_mode();
+ break;
+
+ case DisplayRecording:
+ enter_normal_display_mode();
+ break;
+
+ case DisplayRecordingMeter:
+ enter_big_meter_mode();
+ break;
+
+ case DisplayConfig:
+ case DisplayBling:
+ case DisplayBlingMeter:
+ enter_normal_display_mode();
+ break;
}
}
+// FIXME, these 3 aren't done yet
+
+void
+TranzportControlProtocol::enter_recording_mode ()
+{
+ lcd_damage(); // excessive
+ screen_clear ();
+ lights_off ();
+ display_mode = DisplayRecording;
+}
+
+void
+TranzportControlProtocol::enter_bling_mode ()
+{
+ lcd_damage();
+ screen_clear ();
+ lights_off ();
+ display_mode = DisplayBling;
+}
+
+void
+TranzportControlProtocol::enter_config_mode ()
+{
+ lcd_damage();
+ screen_clear ();
+ lights_off ();
+ display_mode = DisplayConfig;
+}
+
+
void
TranzportControlProtocol::enter_big_meter_mode ()
{
- lcd_clear ();
+ screen_clear ();
+ lcd_damage();
lights_off ();
last_meter_fill = 0;
display_mode = DisplayBigMeter;
@@ -213,16 +452,11 @@ TranzportControlProtocol::enter_big_meter_mode ()
void
TranzportControlProtocol::enter_normal_display_mode ()
{
- last_where += 1; /* force time redisplay */
- last_track_gain = FLT_MAX; /* force gain redisplay */
-
- lcd_clear ();
+ screen_clear ();
+ lcd_damage();
lights_off ();
- show_current_track ();
- show_wheel_mode ();
- show_wheel_mode ();
- show_transport_time ();
display_mode = DisplayNormal;
+ // normal_update();
}
@@ -230,10 +464,11 @@ float
log_meter (float db)
{
float def = 0.0f; /* Meter deflection %age */
-
- if (db < -70.0f) {
- def = 0.0f;
- } else if (db < -60.0f) {
+
+ if (db < -70.0f) return 0.0f;
+ if (db > 6.0f) return 1.0f;
+
+ if (db < -60.0f) {
def = (db + 70.0f) * 0.25f;
} else if (db < -50.0f) {
def = (db + 60.0f) * 0.5f + 2.5f;
@@ -245,32 +480,36 @@ log_meter (float db)
def = (db + 30.0f) * 2.0f + 30.0f;
} else if (db < 6.0f) {
def = (db + 20.0f) * 2.5f + 50.0f;
- } else {
- def = 115.0f;
}
-
+
/* 115 is the deflection %age that would be
when db=6.0. this is an arbitrary
endpoint for our scaling.
- */
-
+ */
+
return def/115.0f;
}
void
TranzportControlProtocol::show_meter ()
{
+ // you only seem to get a route_table[0] on moving forward - bug elsewhere
if (route_table[0] == 0) {
+ // Principle of least surprise
+ print (0, 0, "No audio to meter!!!");
+ print (1, 0, "Select another track");
return;
}
float level = route_get_peak_input_power (0, 0);
float fraction = log_meter (level);
+ /* Someday add a peak bar*/
+
/* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
the screen is 20 chars wide, so we can display 40 different levels. compute the level,
then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
- */
+ */
uint32_t fill = (uint32_t) floor (fraction * 40);
char buf[21];
@@ -285,7 +524,7 @@ TranzportControlProtocol::show_meter ()
bool add_single_level = (fill % 2 != 0);
fill /= 2;
-
+
if (fraction > 0.98) {
light_on (LightAnysolo);
}
@@ -310,7 +549,7 @@ TranzportControlProtocol::show_meter ()
}
/* print() requires this */
-
+
buf[21] = '\0';
print (0, 0, buf);
@@ -318,17 +557,56 @@ TranzportControlProtocol::show_meter ()
}
void
+TranzportControlProtocol::show_bbt (nframes_t where)
+{
+ if ((where != last_where) || lcd_isdamaged(1,9,8)) {
+ char buf[16];
+ BBT_Time bbt;
+ session->tempo_map().bbt_time (where, bbt);
+ sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+ last_bars = bbt.bars;
+ last_beats = bbt.beats;
+ last_ticks = bbt.ticks;
+ last_where = where;
+
+ if(last_ticks < 1960) { print (1, 9, buf); } // save a write so we can do leds
+
+ // if displaymode is recordmode show beats but not yet
+ lights_pending[LightRecord] = false;
+ lights_pending[LightAnysolo] = false;
+ switch(last_beats) {
+ case 1: if(last_ticks < 500 || last_ticks > 1960) lights_pending[LightRecord] = true; break;
+ default: if(last_ticks < 250) lights_pending[LightAnysolo] = true;
+ }
+
+ // update lights for tempo one day
+ // if (bbt_upper_info_label) {
+ // TempoMap::Metric m (session->tempo_map().metric_at (when));
+ // sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
+ // bbt_lower_info_label->set_text (buf);
+ // sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
+ // bbt_upper_info_label->set_text (buf);
+ }
+ }
+
+
+void
TranzportControlProtocol::show_transport_time ()
{
nframes_t where = session->transport_frame();
-
- if (where != last_where) {
+ show_bbt(where);
+}
+
+void
+TranzportControlProtocol::show_smpte (nframes_t where)
+{
+ if ((where != last_where) || lcd_isdamaged(1,9,10)) {
char buf[5];
SMPTE::Time smpte;
session->smpte_time (where, smpte);
-
+
if (smpte.negative) {
sprintf (buf, "-%02" PRIu32 ":", smpte.hours);
} else {
@@ -343,7 +621,7 @@ TranzportControlProtocol::show_transport_time ()
print (1, 15, buf);
sprintf (buf, "%02" PRIu32, smpte.frames);
- print (1, 18, buf);
+ print_noretry (1, 18, buf);
last_where = where;
}
@@ -355,6 +633,33 @@ TranzportControlProtocol::_monitor_work (void* arg)
return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
}
+// I note that these usb specific open, close, probe, read routines are basically
+// pure boilerplate and could easily be abstracted elsewhere
+
+#if !HAVE_TRANZPORT_KERNEL_DRIVER
+
+bool
+TranzportControlProtocol::probe ()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+
+ for(dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor == VENDORID && dev->descriptor.idProduct == PRODUCTID) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
int
TranzportControlProtocol::open ()
{
@@ -424,393 +729,469 @@ TranzportControlProtocol::close ()
return ret;
}
+
+int TranzportControlProtocol::read(uint8_t *buf, uint32_t timeout_override)
+{
+ int val;
+ // Get smarter about handling usb errors soon. Like disconnect
+ // pthread_testcancel();
+ val = usb_interrupt_read (udev, READ_ENDPOINT, (char *) buf, 8, 10);
+ // pthread_testcancel();
+ return val;
+}
+
int
-TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
+TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
{
int val;
-
+ if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
- if (val < 0)
+ if (val < 0) {
+#if DEBUG_TRANZPORT
+ printf("usb_interrupt_write failed: %d\n", val);
+#endif
return val;
- if (val != 8)
+ }
+
+ if (val != 8) {
+#if DEBUG_TRANZPORT
+ printf("usb_interrupt_write failed: %d\n", val);
+#endif
return -1;
+ }
+ ++inflight;
+
return 0;
}
-void
-TranzportControlProtocol::lcd_clear ()
+int
+TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
{
- /* special case this for speed and atomicity */
-
- uint8_t cmd[8];
+#if MAX_RETRY > 1
+ int val;
+ int retry = 0;
+ if(inflight > MAX_TRANZPORT_INFLIGHT) { return (-1); }
- cmd[0] = 0x00;
- cmd[1] = 0x01;
- cmd[3] = ' ';
- cmd[4] = ' ';
- cmd[5] = ' ';
- cmd[6] = ' ';
- cmd[7] = 0x00;
-
- for (uint8_t i = 0; i < 10; ++i) {
- cmd[2] = i;
- usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, 1000);
+ while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
+ printf("usb_interrupt_write failed, retrying: %d\n", val);
}
-
- memset (current_screen, ' ', sizeof (current_screen));
- memset (pending_screen, ' ', sizeof (pending_screen));
-}
-void
-TranzportControlProtocol::lights_off ()
+ if (retry == MAX_RETRY) {
+ printf("Too many retries on a tranzport write, aborting\n");
+ }
+
+ if (val < 0) {
+ printf("usb_interrupt_write failed: %d\n", val);
+ return val;
+ }
+ if (val != 8) {
+ printf("usb_interrupt_write failed: %d\n", val);
+ return -1;
+ }
+ ++inflight;
+ return 0;
+#else
+ return (write_noretry(cmd,timeout_override));
+#endif
+
+}
+
+#else
+#error Kernel API not defined yet for Tranzport
+// Something like open(/dev/surface/tranzport/event) for reading and raw for writing)
+#endif
+
+// We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
+// We have another state - no_retry. Misleading, as we still retry on the next pass
+// I think it's pointless to keep no_retry and instead we should throttle writes
+// We have an "displayed" screen
+// We always draw into the pending screen, which could be any of several screens
+// We have an active screen
+// Print arg - we have
+// setactive
+// so someday I think we need a screen object.
+
+/*
+screen_flash.clear();
+screen_flash.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
+screen_flash.print(1,0,"Nextup:");
+
+if(flash_messages && lcd.getactive() != screen_flash) lcd.setactive(screen_flash,2000);
+
+screen::setactive(screen_name,duration); // duration in ms
+screen::getactive();
+*/
+
+
+int
+TranzportControlProtocol::flush ()
{
- uint8_t cmd[8];
+ int pending = 0;
+ if(!(pending = lights_flush())) {
+ pending = screen_flush();
+ }
+ return pending;
+}
- cmd[0] = 0x00;
- cmd[1] = 0x00;
- cmd[3] = 0x00;
- cmd[4] = 0x00;
- cmd[5] = 0x00;
- cmd[6] = 0x00;
- cmd[7] = 0x00;
+// doing these functions made me realize that screen_invalid should be lcd_isdamaged FIXME soon
- cmd[2] = LightRecord;
- if (write (cmd, 1000) == 0) {
- lights[LightRecord] = false;
- }
- cmd[2] = LightTrackrec;
- if (write (cmd, 1000) == 0) {
- lights[LightTrackrec] = false;
- }
- cmd[2] = LightTrackmute;
- if (write (cmd, 1000) == 0) {
- lights[LightTrackmute] = false;
- }
- cmd[2] = LightTracksolo;
- if (write (cmd, 1000) == 0) {
- lights[LightTracksolo] = false;
- }
- cmd[2] = LightAnysolo;
- if (write (cmd, 1000) == 0) {
- lights[LightAnysolo] = false;
+bool TranzportControlProtocol::lcd_damage()
+{
+ screen_invalidate();
+ return true;
+}
+
+bool TranzportControlProtocol::lcd_damage (int row, int col, int length)
+{
+ bool result = false;
+ int endcol = col+length-1;
+ if((endcol > 19)) { endcol = 19; }
+ if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
+ for(int c = col; c < endcol; c++) {
+ screen_invalid[row][c] = true;
+ }
+ result = true;
}
- cmd[2] = LightLoop;
- if (write (cmd, 1000) == 0) {
- lights[LightLoop] = false;
+ return result;
+}
+
+// Gotta switch to bitfields, this is collossally dumb
+// Still working on the layering, arguably screen_invalid should be lcd_invalid
+
+bool TranzportControlProtocol::lcd_isdamaged ()
+{
+ for(int r = 0; r < 2; r++) {
+ for(int c = 0; c < 20; c++) {
+ if(screen_invalid[r][c]) {
+#if DEBUG_TRANZPORT > 5
+ printf("row: %d,col: %d is damaged, should redraw it\n", r,c);
+#endif
+ return true;
+ }
+ }
}
- cmd[2] = LightPunch;
- if (write (cmd, 1000) == 0) {
- lights[LightPunch] = false;
+ return false;
+}
+
+bool TranzportControlProtocol::lcd_isdamaged (int row, int col, int length)
+{
+ bool result = 0;
+ int endcol = col+length;
+ if((endcol > 19)) { endcol = 19; }
+ if((row >= 0 && row < 2) && (col >=0 && col < 20)) {
+ for(int c = col; c < endcol; c++) {
+ if(screen_invalid[row][c]) {
+#if DEBUG_TRANZPORT > 5
+ printf("row: %d,col: %d is damaged, should redraw it\n", row,c);
+#endif
+ return true;
+ }
+ }
}
+ return result;
+}
+
+// lcd_clear would be a separate function for a smart display
+// here it does nothing, but for the sake of completeness it should
+// probably write the lcd, and while I'm on the topic it should probably
+// take a row, col, length argument....
+
+void
+TranzportControlProtocol::lcd_clear ()
+{
+
}
+// These lcd commands are not universally used yet and may drop out of the api
+
int
-TranzportControlProtocol::light_on (LightID light)
+TranzportControlProtocol::lcd_flush ()
{
- uint8_t cmd[8];
+ return 0;
+}
- if (!lights[light]) {
+int
+TranzportControlProtocol::lcd_write(uint8_t* cmd, uint32_t timeout_override)
+{
+ return write(cmd,timeout_override);
+}
- cmd[0] = 0x00;
- cmd[1] = 0x00;
- cmd[2] = light;
- cmd[3] = 0x01;
- cmd[4] = 0x00;
- cmd[5] = 0x00;
- cmd[6] = 0x00;
- cmd[7] = 0x00;
+void
+TranzportControlProtocol::lcd_fill (uint8_t fill_char)
+{
+}
- if (write (cmd, 1000) == 0) {
- lights[light] = true;
- return 0;
- } else {
- return -1;
- }
+void
+TranzportControlProtocol::lcd_print (int row, int col, const char* text)
+{
+ print(row,col,text);
+}
- } else {
- return 0;
- }
+void TranzportControlProtocol::lcd_print_noretry (int row, int col, const char* text)
+{
+ print(row,col,text);
}
-int
-TranzportControlProtocol::light_off (LightID light)
+// Lights are buffered
+
+void
+TranzportControlProtocol::lights_on ()
{
- uint8_t cmd[8];
+ lights_pending[LightRecord] = lights_pending[LightTrackrec] =
+ lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
+ lights_pending[LightAnysolo] = lights_pending[LightLoop] =
+ lights_pending[LightPunch] = true;
+}
- if (lights[light]) {
+void
+TranzportControlProtocol::lights_off ()
+{
+ lights_pending[LightRecord] = lights_pending[LightTrackrec] =
+ lights_pending[LightTrackmute] = lights_pending[LightTracksolo] =
+ lights_pending[LightAnysolo] = lights_pending[LightLoop] =
+ lights_pending[LightPunch] = false;
+}
- cmd[0] = 0x00;
- cmd[1] = 0x00;
- cmd[2] = light;
- cmd[3] = 0x00;
- cmd[4] = 0x00;
- cmd[5] = 0x00;
- cmd[6] = 0x00;
- cmd[7] = 0x00;
+int
+TranzportControlProtocol::light_on (LightID light)
+{
+ lights_pending[light] = true;
+ return 0;
+}
- if (write (cmd, 1000) == 0) {
- lights[light] = false;
- return 0;
- } else {
- return -1;
- }
+int
+TranzportControlProtocol::light_off (LightID light)
+{
+ lights_pending[light] = false;
+ return 0;
+}
- } else {
+int
+TranzportControlProtocol::light_set (LightID light, bool offon)
+{
+ uint8_t cmd[8];
+ cmd[0] = 0x00; cmd[1] = 0x00; cmd[2] = light; cmd[3] = offon;
+ cmd[4] = 0x00; cmd[5] = 0x00; cmd[6] = 0x00; cmd[7] = 0x00;
+
+ if (write (cmd) == 0) {
+ lights_current[light] = offon;
+ lights_invalid[light] = false;
return 0;
+ } else {
+ return -1;
}
}
-void*
-TranzportControlProtocol::monitor_work ()
+int TranzportControlProtocol::rtpriority_set(int priority)
{
struct sched_param rtparam;
int err;
- uint8_t buf[8];
- int val;
- bool first_time = true;
+ // preallocate and memlock some stack with memlock?
+ char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
+ // Note - try SCHED_RR with a low limit
+ // - we don't care if we can't write everything this ms
+ // and it will help if we lose the device
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
+ }
+ return 0;
+}
- PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
+// Running with realtime privs is bad when you have problems
+int TranzportControlProtocol::rtpriority_unset(int priority)
+{
+ struct sched_param rtparam;
+ int err;
memset (&rtparam, 0, sizeof (rtparam));
- rtparam.sched_priority = 3; /* XXX should be relative to audio (JACK) thread */
-
+ rtparam.sched_priority = priority;
if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
- // do we care? not particularly.
- PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
}
+ PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
+ return 0;
+}
+
+// Slowly breaking this into where I can make usb processing it's own thread.
+
+void*
+TranzportControlProtocol::monitor_work ()
+{
+ uint8_t buf[8];
+ int val = 0, pending = 0;
+ bool first_time = true;
+ uint8_t offline = 0;
+
+ PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
-
next_track ();
+ rtpriority_set();
+ inflight=0;
+ flush();
while (true) {
/* bInterval for this beastie is 10ms */
- /* anything to read ? */
-
if (_device_status == STATUS_OFFLINE) {
- light_off (LightRecord);
first_time = true;
+ if(offline++ == 1) {
+ cerr << "Transport has gone offline\n";
+ }
+ } else {
+ offline = 0; // hate writing this
}
- pthread_testcancel();
- val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 10);
- pthread_testcancel();
+ val = read(buf);
if (val == 8) {
process (buf);
}
+#if DEBUG_TRANZPORT > 2
+ if(inflight > 1) printf("Inflight: %d\n", inflight);
+#endif
+
+
if (_device_status != STATUS_OFFLINE) {
if (first_time) {
+ invalidate();
lcd_clear ();
lights_off ();
first_time = false;
+ offline = 0;
+ pending = 3; // Give some time for the device to recover
}
/* update whatever needs updating */
update_state ();
- }
- }
-
- return (void*) 0;
-}
-
-int
-TranzportControlProtocol::update_state ()
-{
- int row;
- int col_base;
- int col;
- int cell;
- /* do the text updates */
-
- switch (display_mode) {
- case DisplayBigMeter:
- show_meter ();
- break;
-
- case DisplayNormal:
- normal_update ();
- break;
- }
-
- /* next: flush LCD */
-
- cell = 0;
-
- for (row = 0; row < 2; ++row) {
-
- for (col_base = 0, col = 0; col < 20; ) {
-
- if (pending_screen[row][col] != current_screen[row][col]) {
-
- /* something in this cell is different, so dump the cell
- to the device.
- */
-
- uint8_t cmd[8];
-
- cmd[0] = 0x00;
- cmd[1] = 0x01;
- cmd[2] = cell;
- cmd[3] = pending_screen[row][col_base];
- cmd[4] = pending_screen[row][col_base+1];
- cmd[5] = pending_screen[row][col_base+2];
- cmd[6] = pending_screen[row][col_base+3];
- cmd[7] = 0x00;
-
- if (usb_interrupt_write (udev, WRITE_ENDPOINT, (char *) cmd, 8, 1000) == 8) {
- /* successful write: copy to current */
- memcpy (&current_screen[row][col_base], &pending_screen[row][col_base], 4);
- }
-
- /* skip the rest of the 4 character cell since we wrote+copied it already */
-
- col_base += 4;
- col = col_base;
- cell++;
+ /* still struggling with a good means of exerting flow control */
+ // pending = flush();
+ if(pending == 0) {
+ pending = flush();
} else {
-
- col++;
-
- if (col && col % 4 == 0) {
- cell++;
- col_base += 4;
+ if(inflight > 0) {
+ pending = --inflight; // we just did a whole bunch of writes so wait
+ } else {
+ pending = 0;
}
}
- }
+ // pending = 0;
+ }
}
- /* now update LED's */
+ return (void*) 0;
+}
- /* per track */
+int TranzportControlProtocol::lights_show_recording()
+{
+ // FIXME, flash recording light when recording and transport is moving
+ return lights_show_normal();
+}
- if (route_table[0]) {
- boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
- if (at && at->record_enabled()) {
- pending_lights[LightTrackrec] = true;
- } else {
- pending_lights[LightTrackrec] = false;
- }
- if (route_get_muted (0)) {
- pending_lights[LightTrackmute] = true;
- } else {
- pending_lights[LightTrackmute] = false;
- }
- if (route_get_soloed (0)) {
- pending_lights[LightTracksolo] = true;
- } else {
- pending_lights[LightTracksolo] = false;
- }
+// gotta do bling next!
- } else {
- pending_lights[LightTrackrec] = false;
- pending_lights[LightTracksolo] = false;
- pending_lights[LightTrackmute] = false;
+int TranzportControlProtocol::lights_show_bling()
+{
+ switch (bling_mode) {
+ case BlingOff: break;
+ case BlingKit: break; // rotate rec/mute/solo/any solo back and forth
+ case BlingRotating: break; // switch between lights
+ case BlingPairs: break; // Show pairs of lights
+ case BlingRows: break; // light each row in sequence
+ case BlingFlashAll: break; // Flash everything randomly
}
+ return 0;
+}
- /* global */
+int TranzportControlProtocol::lights_show_normal()
+{
+ /* Track only */
- if (session->get_play_loop()) {
- pending_lights[LightLoop] = true;
+ if (route_table[0]) {
+ boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
+ lights_pending[LightTrackrec] = at && at->record_enabled();
+ lights_pending[LightTrackmute] = route_get_muted(0);
+ lights_pending[LightTracksolo] = route_get_soloed(0);
} else {
- pending_lights[LightLoop] = false;
+ lights_pending[LightTrackrec] = false;
+ lights_pending[LightTracksolo] = false;
+ lights_pending[LightTrackmute] = false;
}
- if (Config->get_punch_in() || Config->get_punch_out()) {
- pending_lights[LightPunch] = true;
- } else {
- pending_lights[LightPunch] = false;
- }
+ /* Global settings */
- if (session->get_record_enabled()) {
- pending_lights[LightRecord] = true;
- } else {
- pending_lights[LightRecord] = false;
- }
+ lights_pending[LightLoop] = session->get_play_loop();
+ lights_pending[LightPunch] = Config->get_punch_in() || Config->get_punch_out();
+ lights_pending[LightRecord] = session->get_record_enabled();
+ lights_pending[LightAnysolo] = session->soloing();
- if (session->soloing ()) {
- pending_lights[LightAnysolo] = true;
- } else {
- pending_lights[LightAnysolo] = false;
- }
+ return 0;
+}
- /* flush changed light change */
+int TranzportControlProtocol::lights_show_tempo()
+{
+ // someday soon fiddle with the lights based on the tempo
+ return lights_show_normal();
+}
- if (pending_lights[LightRecord] != lights[LightRecord]) {
- if (pending_lights[LightRecord]) {
- light_on (LightRecord);
- } else {
- light_off (LightRecord);
- }
- }
+int
+TranzportControlProtocol::update_state ()
+{
+ /* do the text and light updates */
- if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
- if (pending_lights[LightTracksolo]) {
- light_on (LightTracksolo);
- } else {
- light_off (LightTracksolo);
- }
- }
+ switch (display_mode) {
+ case DisplayBigMeter:
+ lights_show_tempo();
+ show_meter ();
+ break;
- if (pending_lights[LightTrackrec] != lights[LightTrackrec]) {
- if (pending_lights[LightTrackrec]) {
- light_on (LightTrackrec);
- } else {
- light_off (LightTrackrec);
- }
- }
+ case DisplayNormal:
+ lights_show_normal();
+ normal_update ();
+ break;
- if (pending_lights[LightTrackmute] != lights[LightTrackmute]) {
- if (pending_lights[LightTrackmute]) {
- light_on (LightTrackmute);
- } else {
- light_off (LightTrackmute);
- }
- }
+ case DisplayConfig:
+ break;
- if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
- if (pending_lights[LightTracksolo]) {
- light_on (LightTracksolo);
- } else {
- light_off (LightTracksolo);
- }
- }
+ case DisplayRecording:
+ lights_show_recording();
+ normal_update();
+ break;
- if (pending_lights[LightAnysolo] != lights[LightAnysolo]) {
- if (pending_lights[LightAnysolo]) {
- light_on (LightAnysolo);
- } else {
- light_off (LightAnysolo);
- }
- }
+ case DisplayRecordingMeter:
+ lights_show_recording();
+ show_meter();
+ break;
- if (pending_lights[LightLoop] != lights[LightLoop]) {
- if (pending_lights[LightLoop]) {
- light_on (LightLoop);
- } else {
- light_off (LightLoop);
- }
- }
+ case DisplayBling:
+ lights_show_bling();
+ normal_update();
+ break;
- if (pending_lights[LightPunch] != lights[LightPunch]) {
- if (pending_lights[LightPunch]) {
- light_on (LightPunch);
- } else {
- light_off (LightPunch);
- }
+ case DisplayBlingMeter:
+ lights_show_bling();
+ show_meter();
+ break;
}
-
return 0;
+
}
+#define TRANZPORT_BUTTON_HANDLER(callback, button_arg) if (button_changes & button_arg) { \
+ if (buttonmask & button_arg) { \
+ callback##_press (buttonmask&ButtonShift); } else { callback##_release (buttonmask&ButtonShift); } }
+
int
TranzportControlProtocol::process (uint8_t* buf)
{
@@ -820,6 +1201,7 @@ TranzportControlProtocol::process (uint8_t* buf)
uint32_t button_changes;
_device_status = buf[1];
+
this_button_mask = 0;
this_button_mask |= buf[2] << 24;
this_button_mask |= buf[3] << 16;
@@ -834,157 +1216,50 @@ TranzportControlProtocol::process (uint8_t* buf)
datawheel ();
}
- if (button_changes & ButtonBattery) {
- if (buttonmask & ButtonBattery) {
- button_event_battery_press (buttonmask&ButtonShift);
- } else {
- button_event_battery_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonBacklight) {
- if (buttonmask & ButtonBacklight) {
- button_event_backlight_press (buttonmask&ButtonShift);
- } else {
- button_event_backlight_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackLeft) {
- if (buttonmask & ButtonTrackLeft) {
- button_event_trackleft_press (buttonmask&ButtonShift);
- } else {
- button_event_trackleft_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackRight) {
- if (buttonmask & ButtonTrackRight) {
- button_event_trackright_press (buttonmask&ButtonShift);
- } else {
- button_event_trackright_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackRec) {
- if (buttonmask & ButtonTrackRec) {
- button_event_trackrec_press (buttonmask&ButtonShift);
- } else {
- button_event_trackrec_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackMute) {
- if (buttonmask & ButtonTrackMute) {
- button_event_trackmute_press (buttonmask&ButtonShift);
- } else {
- button_event_trackmute_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackSolo) {
- if (buttonmask & ButtonTrackSolo) {
- button_event_tracksolo_press (buttonmask&ButtonShift);
- } else {
- button_event_tracksolo_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonUndo) {
- if (buttonmask & ButtonUndo) {
- button_event_undo_press (buttonmask&ButtonShift);
- } else {
- button_event_undo_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonIn) {
- if (buttonmask & ButtonIn) {
- button_event_in_press (buttonmask&ButtonShift);
- } else {
- button_event_in_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonOut) {
- if (buttonmask & ButtonOut) {
- button_event_out_press (buttonmask&ButtonShift);
- } else {
- button_event_out_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPunch) {
- if (buttonmask & ButtonPunch) {
- button_event_punch_press (buttonmask&ButtonShift);
- } else {
- button_event_punch_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonLoop) {
- if (buttonmask & ButtonLoop) {
- button_event_loop_press (buttonmask&ButtonShift);
- } else {
- button_event_loop_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPrev) {
- if (buttonmask & ButtonPrev) {
- button_event_prev_press (buttonmask&ButtonShift);
- } else {
- button_event_prev_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonAdd) {
- if (buttonmask & ButtonAdd) {
- button_event_add_press (buttonmask&ButtonShift);
- } else {
- button_event_add_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonNext) {
- if (buttonmask & ButtonNext) {
- button_event_next_press (buttonmask&ButtonShift);
- } else {
- button_event_next_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonRewind) {
- if (buttonmask & ButtonRewind) {
- button_event_rewind_press (buttonmask&ButtonShift);
- } else {
- button_event_rewind_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonFastForward) {
- if (buttonmask & ButtonFastForward) {
- button_event_fastforward_press (buttonmask&ButtonShift);
- } else {
- button_event_fastforward_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonStop) {
- if (buttonmask & ButtonStop) {
- button_event_stop_press (buttonmask&ButtonShift);
- } else {
- button_event_stop_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPlay) {
- if (buttonmask & ButtonPlay) {
- button_event_play_press (buttonmask&ButtonShift);
- } else {
- button_event_play_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonRecord) {
- if (buttonmask & ButtonRecord) {
- button_event_record_press (buttonmask&ButtonShift);
- } else {
- button_event_record_release (buttonmask&ButtonShift);
- }
- }
-
+ // SHIFT + STOP + PLAY for bling mode?
+ // if (button_changes & ButtonPlay & ButtonStop) {
+ // bling_mode_toggle();
+ // } or something like that
+
+ TRANZPORT_BUTTON_HANDLER(button_event_battery,ButtonBattery);
+ TRANZPORT_BUTTON_HANDLER(button_event_backlight,ButtonBacklight);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackleft,ButtonTrackLeft);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackright,ButtonTrackRight);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackrec,ButtonTrackRec);
+ TRANZPORT_BUTTON_HANDLER(button_event_trackmute,ButtonTrackMute);
+ TRANZPORT_BUTTON_HANDLER(button_event_tracksolo,ButtonTrackSolo);
+ TRANZPORT_BUTTON_HANDLER(button_event_undo,ButtonUndo);
+ TRANZPORT_BUTTON_HANDLER(button_event_in,ButtonIn);
+ TRANZPORT_BUTTON_HANDLER(button_event_out,ButtonOut);
+ TRANZPORT_BUTTON_HANDLER(button_event_punch,ButtonPunch);
+ TRANZPORT_BUTTON_HANDLER(button_event_loop,ButtonLoop);
+ TRANZPORT_BUTTON_HANDLER(button_event_prev,ButtonPrev);
+ TRANZPORT_BUTTON_HANDLER(button_event_add,ButtonAdd);
+ TRANZPORT_BUTTON_HANDLER(button_event_next,ButtonNext);
+ TRANZPORT_BUTTON_HANDLER(button_event_rewind,ButtonRewind);
+ TRANZPORT_BUTTON_HANDLER(button_event_fastforward,ButtonFastForward);
+ TRANZPORT_BUTTON_HANDLER(button_event_stop,ButtonStop);
+ TRANZPORT_BUTTON_HANDLER(button_event_play,ButtonPlay);
+ TRANZPORT_BUTTON_HANDLER(button_event_record,ButtonRecord);
return 0;
}
void
TranzportControlProtocol::show_current_track ()
{
+ char pad[11];
+ char *v;
+ int len;
if (route_table[0] == 0) {
- print (0, 0, "--------");
+ print (0, 0, "----------");
+ last_track_gain = FLT_MAX;
} else {
- print (0, 0, route_get_name (0).substr (0, 8).c_str());
+ strcpy(pad," ");
+ v = (char *)route_get_name (0).substr (0, 10).c_str();
+ if((len = strlen(v)) > 0) {
+ strncpy(pad,(char *)v,len);
+ }
+ print (0, 0, pad);
}
}
@@ -1001,11 +1276,24 @@ TranzportControlProtocol::button_event_battery_release (bool shifted)
void
TranzportControlProtocol::button_event_backlight_press (bool shifted)
{
+#if DEBUG_TRANZPORT
+ printf("backlight pressed\n");
+#endif
}
void
TranzportControlProtocol::button_event_backlight_release (bool shifted)
{
+#if DEBUG_TRANZPORT
+ printf("backlight released\n\n");
+#endif
+ if (shifted) {
+ lcd_damage();
+ lcd_clear();
+ last_where += 1; /* force time redisplay */
+ last_track_gain = FLT_MAX;
+ normal_update(); // redraw_screen();
+ }
}
void
@@ -1048,7 +1336,11 @@ TranzportControlProtocol::button_event_trackrec_release (bool shifted)
void
TranzportControlProtocol::button_event_trackmute_press (bool shifted)
{
- route_set_muted (0, !route_get_muted (0));
+ if (shifted) {
+ // Mute ALL? Something useful when a phone call comes in. Mute master?
+ } else {
+ route_set_muted (0, !route_get_muted (0));
+ }
}
void
@@ -1059,6 +1351,9 @@ TranzportControlProtocol::button_event_trackmute_release (bool shifted)
void
TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
{
+#if DEBUG_TRANZPORT
+ printf("solo pressed\n");
+#endif
if (display_mode == DisplayBigMeter) {
light_off (LightAnysolo);
return;
@@ -1074,15 +1369,18 @@ TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
void
TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
{
+#if DEBUG_TRANZPORT
+ printf("solo released\n");
+#endif
}
void
TranzportControlProtocol::button_event_undo_press (bool shifted)
{
if (shifted) {
- redo ();
+ redo (); // someday flash the screen with what was redone
} else {
- undo ();
+ undo (); // someday flash the screen with what was undone
}
}
@@ -1235,7 +1533,11 @@ TranzportControlProtocol::button_event_stop_release (bool shifted)
void
TranzportControlProtocol::button_event_play_press (bool shifted)
{
- transport_play ();
+ if (shifted) {
+ set_transport_speed (1.0f);
+ } else {
+ transport_play ();
+ }
}
void
@@ -1258,11 +1560,17 @@ TranzportControlProtocol::button_event_record_release (bool shifted)
{
}
+void button_event_mute (bool pressed, bool shifted)
+{
+ //static int was_pressed = 0;
+ // if(pressed) { }
+}
+
void
TranzportControlProtocol::datawheel ()
{
if ((buttonmask & ButtonTrackRight) || (buttonmask & ButtonTrackLeft)) {
-
+
/* track scrolling */
if (_datawheel < WheelDirectionThreshold) {
@@ -1274,7 +1582,7 @@ TranzportControlProtocol::datawheel ()
timerclear (&last_wheel_motion);
} else if ((buttonmask & ButtonPrev) || (buttonmask & ButtonNext)) {
-
+
if (_datawheel < WheelDirectionThreshold) {
next_marker ();
} else {
@@ -1289,23 +1597,27 @@ TranzportControlProtocol::datawheel ()
if (route_table[0]) {
switch (wheel_shift_mode) {
- case WheelShiftGain:
- if (_datawheel < WheelDirectionThreshold) {
- step_gain_up ();
- } else {
- step_gain_down ();
- }
- break;
- case WheelShiftPan:
- if (_datawheel < WheelDirectionThreshold) {
- step_pan_right ();
- } else {
- step_pan_left ();
- }
- break;
+ case WheelShiftGain:
+ if (_datawheel < WheelDirectionThreshold) {
+ step_gain_up ();
+ } else {
+ step_gain_down ();
+ }
+ break;
+ case WheelShiftPan:
+ if (_datawheel < WheelDirectionThreshold) {
+ step_pan_right ();
+ } else {
+ step_pan_left ();
+ }
+ break;
+
+ case WheelShiftMarker:
+ break;
+
+ case WheelShiftMaster:
+ break;
- case WheelShiftMaster:
- break;
}
}
@@ -1314,17 +1626,17 @@ TranzportControlProtocol::datawheel ()
} else {
switch (wheel_mode) {
- case WheelTimeline:
- scroll ();
- break;
-
- case WheelScrub:
- scrub ();
- break;
+ case WheelTimeline:
+ scroll ();
+ break;
- case WheelShuttle:
- shuttle ();
- break;
+ case WheelScrub:
+ scrub ();
+ break;
+
+ case WheelShuttle:
+ shuttle ();
+ break;
}
}
}
@@ -1332,10 +1644,15 @@ TranzportControlProtocol::datawheel ()
void
TranzportControlProtocol::scroll ()
{
+ float m = 1.0;
if (_datawheel < WheelDirectionThreshold) {
- ScrollTimeline (0.2);
+ m = 1.0;
} else {
- ScrollTimeline (-0.2);
+ m = -1.0;
+ }
+ switch(wheel_increment) {
+ case WheelIncrScreen: ScrollTimeline (0.2*m); break;
+ default: break; // other modes unimplemented as yet
}
}
@@ -1346,42 +1663,48 @@ TranzportControlProtocol::scrub ()
struct timeval now;
struct timeval delta;
int dir;
-
+
gettimeofday (&now, 0);
-
+
if (_datawheel < WheelDirectionThreshold) {
dir = 1;
} else {
dir = -1;
}
-
+
if (dir != last_wheel_dir) {
/* changed direction, start over */
speed = 0.1f;
} else {
if (timerisset (&last_wheel_motion)) {
-
+
timersub (&now, &last_wheel_motion, &delta);
-
+
/* 10 clicks per second => speed == 1.0 */
-
+
speed = 100000.0f / (delta.tv_sec * 1000000 + delta.tv_usec);
-
+
} else {
-
+
/* start at half-speed and see where we go from there */
-
+
speed = 0.5f;
}
}
-
+
last_wheel_motion = now;
last_wheel_dir = dir;
-
+
set_transport_speed (speed * dir);
}
void
+TranzportControlProtocol::config ()
+{
+ // FIXME
+}
+
+void
TranzportControlProtocol::shuttle ()
{
if (_datawheel < WheelDirectionThreshold) {
@@ -1453,6 +1776,10 @@ TranzportControlProtocol::next_wheel_shift_mode ()
break;
case WheelShiftMaster:
wheel_shift_mode = WheelShiftGain;
+ break;
+ case WheelShiftMarker: // Not done yet, disabled
+ wheel_shift_mode = WheelShiftGain;
+ break;
}
show_wheel_mode ();
@@ -1495,36 +1822,48 @@ TranzportControlProtocol::show_wheel_mode ()
string text;
switch (wheel_mode) {
- case WheelTimeline:
- text = "Time";
- break;
- case WheelScrub:
- text = "Scrb";
- break;
- case WheelShuttle:
- text = "Shtl";
- break;
+ case WheelTimeline:
+ text = "Time";
+ break;
+ case WheelScrub:
+ text = "Scrb";
+ break;
+ case WheelShuttle:
+ text = "Shtl";
+ break;
}
switch (wheel_shift_mode) {
- case WheelShiftGain:
- text += ":Gain";
- break;
+ case WheelShiftGain:
+ text += ":Gain";
+ break;
- case WheelShiftPan:
- text += ":Pan";
- break;
+ case WheelShiftPan:
+ text += ":Pan ";
+ break;
- case WheelShiftMaster:
- text += ":Mstr";
- break;
+ case WheelShiftMaster:
+ text += ":Mstr";
+ break;
+
+ case WheelShiftMarker:
+ text += ":Mrkr";
+ break;
}
-
+
print (1, 0, text.c_str());
}
+// Was going to keep state around saying to retry or not
+// haven't got to it yet, still not sure it's a good idea
+
void
-TranzportControlProtocol::print (int row, int col, const char *text)
+TranzportControlProtocol::print (int row, int col, const char *text) {
+ print_noretry(row,col,text);
+}
+
+void
+TranzportControlProtocol::print_noretry (int row, int col, const char *text)
{
int cell;
uint32_t left = strlen (text);
@@ -1564,7 +1903,7 @@ TranzportControlProtocol::print (int row, int col, const char *text)
/* copy current cell contents into tmp */
- memcpy (tmp, &pending_screen[row][base_col], 4);
+ memcpy (tmp, &screen_pending[row][base_col], 4);
/* overwrite with new text */
@@ -1574,7 +1913,7 @@ TranzportControlProtocol::print (int row, int col, const char *text)
/* copy it back to pending */
- memcpy (&pending_screen[row][base_col], tmp, 4);
+ memcpy (&screen_pending[row][base_col], tmp, 4);
text += tocopy;
left -= tocopy;
@@ -1595,3 +1934,17 @@ TranzportControlProtocol::set_state (const XMLNode& node)
{
return 0;
}
+
+int
+TranzportControlProtocol::save (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
+
+int
+TranzportControlProtocol::load (char *name)
+{
+ // Presently unimplemented
+ return 0;
+}
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h
index e5193a761c..f13e4a3a44 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.h
+++ b/libs/surfaces/tranzport/tranzport_control_protocol.h
@@ -1,3 +1,4 @@
+
#ifndef ardour_tranzport_control_protocol_h
#define ardour_tranzport_control_protocol_h
@@ -72,7 +73,8 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
enum WheelShiftMode {
WheelShiftGain,
WheelShiftPan,
- WheelShiftMaster
+ WheelShiftMaster,
+ WheelShiftMarker
};
enum WheelMode {
@@ -81,29 +83,68 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
WheelShuttle
};
+ // FIXME - look at gtk2_ardour for snap settings
+
+ enum WheelIncrement {
+ WheelIncrSlave,
+ WheelIncrScreen,
+ WheelIncrSample,
+ WheelIncrBeat,
+ WheelIncrBar,
+ WheelIncrSecond,
+ WheelIncrMinute
+ };
+
enum DisplayMode {
DisplayNormal,
- DisplayBigMeter
+ DisplayRecording,
+ DisplayRecordingMeter,
+ DisplayBigMeter,
+ DisplayConfig,
+ DisplayBling,
+ DisplayBlingMeter
+ };
+
+ enum BlingMode {
+ BlingOff,
+ BlingKit,
+ BlingRotating,
+ BlingPairs,
+ BlingRows,
+ BlingFlashAll
};
pthread_t thread;
uint32_t buttonmask;
uint32_t timeout;
+ uint32_t inflight;
uint8_t _datawheel;
uint8_t _device_status;
- usb_dev_handle* udev;
-
uint32_t current_track_id;
WheelMode wheel_mode;
WheelShiftMode wheel_shift_mode;
DisplayMode display_mode;
+ BlingMode bling_mode;
+ WheelIncrement wheel_increment;
+ usb_dev_handle* udev;
+
ARDOUR::gain_t gain_fraction;
Glib::Mutex update_lock;
- char current_screen[2][20];
- char pending_screen[2][20];
- bool lights[7];
- bool pending_lights[7];
+
+ bool screen_invalid[2][20];
+ char screen_current[2][20];
+ char screen_pending[2][20];
+ char screen_flash[2][20];
+
+ bool lights_invalid[7];
+ bool lights_current[7];
+ bool lights_pending[7];
+ bool lights_flash[7];
+
+ uint32_t last_bars;
+ uint32_t last_beats;
+ uint32_t last_ticks;
bool last_negative;
uint32_t last_hrs;
@@ -119,28 +160,94 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
Glib::Mutex io_lock;
int open ();
- int read (uint32_t timeout_override = 0);
+ int read (uint8_t *buf,uint32_t timeout_override = 0);
int write (uint8_t* cmd, uint32_t timeout_override = 0);
+ int write_noretry (uint8_t* cmd, uint32_t timeout_override = 0);
int close ();
+ int save(char *name = "default");
+ int load(char *name = "default");
+ void print (int row, int col, const char* text);
+ void print_noretry (int row, int col, const char* text);
+
+ int rtpriority_set(int priority = 52);
+ int rtpriority_unset(int priority = 0);
int open_core (struct usb_device*);
+ static void* _monitor_work (void* arg);
+ void* monitor_work ();
+
+ int process (uint8_t *);
+ int update_state();
+ void invalidate();
+ int flush();
+ // bool isuptodate(); // think on this. It seems futile to update more than 30/sec
+
+ // A screen is a cache of what should be on the lcd
+
+ void screen_init();
+ void screen_validate();
+ void screen_invalidate();
+ int screen_flush();
+ void screen_clear();
+ // bool screen_isuptodate(); // think on this -
+
+ // Commands to write to the lcd
+
+ int lcd_init();
+ bool lcd_damage();
+ bool lcd_isdamaged();
+
+ bool lcd_damage(int row, int col = 0, int length = 20);
+ bool lcd_isdamaged(int row, int col = 0, int length = 20);
+
+ int lcd_flush();
+ int lcd_write(uint8_t* cmd, uint32_t timeout_override = 0); // pedantic alias for write
+ void lcd_fill (uint8_t fill_char);
void lcd_clear ();
- void print (int row, int col, const char* text);
+ void lcd_print (int row, int col, const char* text);
+ void lcd_print_noretry (int row, int col, const char* text);
+
+ // Commands to write to the lights
+ // FIXME - on some devices lights can have intensity and colors
+
+ void lights_init();
+ void lights_validate();
+ void lights_invalidate();
+ void light_validate(LightID light);
+ void light_invalidate(LightID light);
+ int lights_flush();
+ int lights_write(uint8_t* cmd,uint32_t timeout_override = 0); // pedantic alias to write
+
+ // a cache of what should be lit
+
+ void lights_off ();
+ void lights_on ();
+ int light_set(LightID, bool offon = true);
int light_on (LightID);
int light_off (LightID);
- void lights_off ();
+
+ // some modes for the lights, should probably be renamed
+
+ int lights_show_normal();
+ int lights_show_recording();
+ int lights_show_tempo();
+ int lights_show_bling();
void enter_big_meter_mode ();
void enter_normal_display_mode ();
+ void enter_config_mode();
+ void enter_recording_mode();
+ void enter_bling_mode();
void next_display_mode ();
-
void normal_update ();
void show_current_track ();
void show_track_gain ();
void show_transport_time ();
+ void show_bbt (nframes_t where);
+ void show_smpte (nframes_t where);
void show_wheel_mode ();
void show_gain ();
void show_pan ();
@@ -150,6 +257,7 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void scrub ();
void scroll ();
void shuttle ();
+ void config ();
void next_wheel_mode ();
void next_wheel_shift_mode ();
@@ -162,8 +270,6 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void step_pan_right ();
void step_pan_left ();
- static void* _monitor_work (void* arg);
- void* monitor_work ();
void button_event_battery_press (bool shifted);
void button_event_battery_release (bool shifted);
@@ -206,8 +312,8 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
void button_event_record_press (bool shifted);
void button_event_record_release (bool shifted);
- int process (uint8_t *);
- int update_state();
+ // new api
+ void button_event_mute (bool pressed, bool shifted);
};