From 532f6aad4ac79ca15d69deccd18fca90e444c437 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 9 Jan 2007 23:24:54 +0000 Subject: 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 --- libs/ardour/SConscript | 51 +++- libs/ardour/ardour/audio_diskstream.h | 58 ++-- libs/ardour/ardour/audio_library.h | 50 +--- libs/ardour/ardour/audioengine.h | 5 +- libs/ardour/ardour/audiofilesource.h | 2 + libs/ardour/ardour/audioplaylist.h | 9 +- libs/ardour/ardour/audiosource.h | 5 +- libs/ardour/ardour/automation_event.h | 6 +- libs/ardour/ardour/configuration_vars.h | 18 +- libs/ardour/ardour/crossfade.h | 5 +- libs/ardour/ardour/cycles.h | 2 +- libs/ardour/ardour/diskstream.h | 16 +- libs/ardour/ardour/insert.h | 11 +- libs/ardour/ardour/io.h | 6 +- libs/ardour/ardour/location.h | 5 +- libs/ardour/ardour/meter.h | 10 + libs/ardour/ardour/midi_diskstream.h | 4 +- libs/ardour/ardour/midi_playlist.h | 9 +- libs/ardour/ardour/named_selection.h | 5 +- libs/ardour/ardour/playlist.h | 54 ++-- libs/ardour/ardour/playlist_factory.h | 25 ++ libs/ardour/ardour/redirect.h | 2 - libs/ardour/ardour/region.h | 7 +- libs/ardour/ardour/route.h | 2 +- libs/ardour/ardour/route_group.h | 2 +- libs/ardour/ardour/send.h | 8 +- libs/ardour/ardour/session.h | 181 +++++++------ libs/ardour/ardour/session_playlist.h | 2 +- libs/ardour/ardour/source.h | 6 +- libs/ardour/ardour/track.h | 5 +- libs/ardour/ardour/types.h | 15 +- libs/ardour/ardour/utils.h | 12 +- libs/ardour/audio_diskstream.cc | 215 ++++++++------- libs/ardour/audio_library.cc | 459 +++++--------------------------- libs/ardour/audio_playlist.cc | 39 ++- libs/ardour/audio_track.cc | 77 +++--- libs/ardour/audioengine.cc | 91 +++++-- libs/ardour/audiofilesource.cc | 43 ++- libs/ardour/audioregion.cc | 147 +++++----- libs/ardour/audiosource.cc | 116 ++++++-- libs/ardour/auditioner.cc | 32 ++- libs/ardour/automation_event.cc | 93 ++++++- libs/ardour/configuration.cc | 4 - libs/ardour/control_protocol_manager.cc | 6 +- libs/ardour/crossfade.cc | 2 +- libs/ardour/diskstream.cc | 39 +-- libs/ardour/enums.cc | 327 +++++++++++++++++++++++ libs/ardour/globals.cc | 102 ++++--- libs/ardour/import.cc | 32 ++- libs/ardour/insert.cc | 120 +++++---- libs/ardour/io.cc | 43 +-- libs/ardour/location.cc | 48 +++- libs/ardour/meter.cc | 16 +- libs/ardour/midi_diskstream.cc | 46 ++-- libs/ardour/midi_playlist.cc | 15 +- libs/ardour/midi_port.cc | 2 +- libs/ardour/midi_track.cc | 6 +- libs/ardour/named_selection.cc | 18 +- libs/ardour/panner.cc | 8 +- libs/ardour/playlist.cc | 180 ++++++------- libs/ardour/playlist_factory.cc | 91 ++++++- libs/ardour/plugin_manager.cc | 3 +- libs/ardour/redirect.cc | 31 ++- libs/ardour/region.cc | 88 +++--- libs/ardour/route.cc | 14 +- libs/ardour/route_group.cc | 23 +- libs/ardour/send.cc | 15 +- libs/ardour/session.cc | 258 ++++++++++++------ libs/ardour/session_butler.cc | 2 - libs/ardour/session_command.cc | 424 +++++++++++++++++++++++++---- libs/ardour/session_events.cc | 11 +- libs/ardour/session_midi.cc | 4 +- libs/ardour/session_process.cc | 2 +- libs/ardour/session_state.cc | 302 ++++++++++++--------- libs/ardour/session_time.cc | 168 ++++++++++-- libs/ardour/session_transport.cc | 69 +++-- libs/ardour/smf_source.cc | 2 +- libs/ardour/sndfilesource.cc | 29 +- libs/ardour/source.cc | 13 +- libs/ardour/source_factory.cc | 161 +++++------ libs/ardour/tempo.cc | 8 +- libs/ardour/utils.cc | 132 ++++++--- 82 files changed, 2990 insertions(+), 1784 deletions(-) create mode 100644 libs/ardour/ardour/playlist_factory.h create mode 100644 libs/ardour/enums.cc (limited to 'libs/ardour') 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 +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(_playlist); } + boost::shared_ptr audio_playlist () { return boost::dynamic_pointer_cast(_playlist); } - int use_playlist (Playlist *); + int use_playlist (boost::shared_ptr); 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 fades_source; - boost::shared_ptr write_source; - - Port *source; - Sample *current_capture_buffer; - Sample *current_playback_buffer; + ChannelInfo (); + ~ChannelInfo (); - RingBufferNPT *playback_buf; - RingBufferNPT *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::rw_vector playback_vector; - RingBufferNPT::rw_vector capture_vector; - - RingBufferNPT * 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 fades_source; + boost::shared_ptr write_source; + + Port *source; + Sample *current_capture_buffer; + Sample *current_playback_buffer; + + RingBufferNPT *playback_buf; + RingBufferNPT *capture_buf; + + Sample* scrub_buffer; + Sample* scrub_forward_buffer; + Sample* scrub_reverse_buffer; + + RingBufferNPT::rw_vector playback_vector; + RingBufferNPT::rw_vector capture_vector; + + RingBufferNPT * 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 #include -#include - -#include - 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 paths); - vector get_paths (); - void scan_paths (); - - void add_member (string member); - void remove_member (string uri); + void set_tags (string member, vector tags); + vector get_tags (string member); - void search_members_and (vector& results, - const map& fields); - void search_members_or (vector& results, - const map& fields); - - void add_field (string field); - void get_fields (vector& 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& results, const vector tags); void save_changes(); - - sigc::signal fields_changed; private: - vector 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& 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, string name, bool hidden = false); + AudioPlaylist (boost::shared_ptr, 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, bool norefresh); void remove_dependents (boost::shared_ptr 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 > pending_peak_sources; static Glib::Mutex* pending_peak_sources_lock; - static void queue_for_peaks (boost::shared_ptr); + static void queue_for_peaks (boost::shared_ptr, 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, boost::shared_ptr); /* 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 #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 () { return _playlist; } - virtual int use_playlist (Playlist *); + virtual int use_playlist (boost::shared_ptr); 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); 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; 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 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 _peak_power; std::vector _visible_peak_power; + std::vector _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(_playlist); } + boost::shared_ptr midi_playlist () { return boost::dynamic_pointer_cast(_playlist); } - int use_playlist (Playlist *); + int use_playlist (boost::shared_ptr); 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 other, string name, bool hidden = false); + MidiPlaylist (boost::shared_ptr 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); void remove_dependents (boost::shared_ptr 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 #include +#include #include @@ -35,12 +36,12 @@ class Playlist; struct NamedSelection : public Stateful { - NamedSelection (std::string, std::list&); + NamedSelection (std::string, std::list >&); NamedSelection (Session&, const XMLNode&); virtual ~NamedSelection (); std::string name; - std::list playlists; + std::list > 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 #include #include +#include #include @@ -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 { public: typedef list > 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, string name, bool hidden = false); + Playlist (boost::shared_ptr, 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, nframes_t position, float times); void nudge_after (nframes_t start, nframes_t distance, bool forwards); - Playlist* cut (list&, bool result_is_hidden = true); - Playlist* copy (list&, bool result_is_hidden = true); - int paste (Playlist&, nframes_t position, float times); + boost::shared_ptr cut (list&, bool result_is_hidden = true); + boost::shared_ptr copy (list&, bool result_is_hidden = true); + int paste (boost::shared_ptr, 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 InUse; - sigc::signal Modified; - sigc::signal NameChanged; - sigc::signal LengthChanged; - sigc::signal LayeringChanged; - sigc::signal StatePushed; - - static sigc::signal PlaylistCreated; + sigc::signal InUse; + sigc::signal Modified; + sigc::signal NameChanged; + sigc::signal LengthChanged; + sigc::signal 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_by_id (PBD::ID); - void add_region_internal (boost::shared_ptr, nframes_t position, bool delay_sort = false); - - int remove_region_internal (boost::shared_ptr, bool delay_sort = false); + void add_region_internal (boost::shared_ptr, nframes_t position); + + int remove_region_internal (boost::shared_ptr); 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& 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 cut_copy (boost::shared_ptr (Playlist::*pmf)(nframes_t, nframes_t, bool), + list& ranges, bool result_is_hidden); + boost::shared_ptr cut (nframes_t start, nframes_t cnt, bool result_is_hidden); + boost::shared_ptr copy (nframes_t start, nframes_t cnt, bool result_is_hidden); int move_region_to_layer (layer_t, boost::shared_ptr 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 + +class XMLNode; + +namespace ARDOUR { + +class Session; + +class PlaylistFactory { + + public: + static sigc::signal > PlaylistCreated; + + static boost::shared_ptr create (Session&, const XMLNode&, bool hidden = false); + static boost::shared_ptr create (DataType type, Session&, string name, bool hidden = false); + static boost::shared_ptr create (boost::shared_ptr, string name, bool hidden = false); + static boost::shared_ptr create (boost::shared_ptr, 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 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 playlist() const { return _playlist.lock(); } + virtual void set_playlist (boost::weak_ptr); void source_deleted (boost::shared_ptr); @@ -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 _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 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 #include +#include #include @@ -117,9 +118,9 @@ using std::set; class Session : public PBD::StatefulDestructible { private: - typedef std::pair,bool> RouteBooleanState; + typedef std::pair,bool> RouteBooleanState; typedef vector GlobalRouteBooleanState; - typedef std::pair,MeterPoint> RouteMeterState; + typedef std::pair,MeterPoint> RouteMeterState; typedef vector 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 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 paths; /* result */ std::vector > new_regions; @@ -602,7 +594,6 @@ class Session : public PBD::StatefulDestructible void add_source (boost::shared_ptr); void remove_source (boost::weak_ptr); - int cleanup_audio_file_source (boost::shared_ptr); struct cleanup_report { vector paths; @@ -622,8 +613,7 @@ class Session : public PBD::StatefulDestructible this playlist. */ - sigc::signal AskAboutPlaylistDeletion; - + sigc::signal > 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 AskAboutPendingState; - sigc::signal > SourceAdded; - sigc::signal > SourceRemoved; - boost::shared_ptr create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); boost::shared_ptr 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 PlaylistAdded; - sigc::signal PlaylistRemoved; + boost::shared_ptr playlist_by_name (string name); + void add_playlist (boost::shared_ptr); + sigc::signal > PlaylistAdded; + sigc::signal > PlaylistRemoved; uint32_t n_playlists() const; - template void foreach_playlist (T *obj, void (T::*func)(Playlist *)); - void get_playlists (std::vector&); + template void foreach_playlist (T *obj, void (T::*func)(boost::shared_ptr)); + void get_playlists (std::vector >&); /* 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 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 PlaylistList; + typedef set > 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); + void track_playlist (bool, boost::weak_ptr); - Playlist *playlist_factory (string name); - Playlist *XMLPlaylistFactory (const XMLNode&); + boost::shared_ptr playlist_factory (string name); + boost::shared_ptr XMLPlaylistFactory (const XMLNode&); - void playlist_length_changed (Playlist *); + void playlist_length_changed (); void diskstream_playlist_changed (boost::shared_ptr); /* NAMED SELECTIONS */ @@ -1522,9 +1528,12 @@ class Session : public PBD::StatefulDestructible list _port_inserts; list _plugin_inserts; list _sends; + boost::dynamic_bitset send_bitset; + boost::dynamic_bitset 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 void -Session::foreach_playlist (T *obj, void (T::*func)(Playlist *)) +Session::foreach_playlist (T *obj, void (T::*func)(boost::shared_ptr)) { 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); + void remove_playlist (boost::weak_ptr); uint32_t used() const; @@ -83,7 +83,7 @@ class Source : public PBD::StatefulDestructible time_t _timestamp; jack_nframes_t _length; - std::set _playlists; + std::set > _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; vector 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 #include #include +#include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -95,34 +97,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 (_session.diskstream_buffer_size()); - chan.capture_buf = new RingBufferNPT (_session.diskstream_buffer_size()); - chan.capture_transition_buf = new RingBufferNPT (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) { @@ -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 playlist; - if ((pl = _session.playlist_by_name (name)) == 0) { - playlist = new AudioPlaylist(_session, name); - pl = playlist; + if ((playlist = boost::dynamic_pointer_cast (_session.playlist_by_name (name))) == 0) { + playlist = boost::dynamic_pointer_cast (PlaylistFactory::create (_session, name)); } - if ((playlist = dynamic_cast (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) { - assert(dynamic_cast(playlist)); + assert(boost::dynamic_pointer_cast(playlist)); Diskstream::use_playlist(playlist); @@ -318,7 +271,7 @@ int AudioDiskstream::use_new_playlist () { string newname; - AudioPlaylist* playlist; + boost::shared_ptr 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 (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 playlist; newname = Playlist::bump_name (_playlist->name(), _session); - if ((playlist = new AudioPlaylist (*audio_playlist(), newname)) != 0) { + if ((playlist = boost::dynamic_pointer_cast(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 (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 (RegionFactory::create (pending_sources, 0, first_fs->length(), region_name_from_path (first_fs->name()))); + region = boost::dynamic_pointer_cast (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 (bufsize); + capture_buf = new RingBufferNPT (bufsize); + capture_transition_buf = new RingBufferNPT (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 // Needed so that libraptor (included in lrdf) won't complain -#include -#include #include -#include -#include -#include -#include +#include #include #include -#include -#include #include #include @@ -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,80 +44,103 @@ 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 () { } -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 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::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 +AudioLibrary::get_tags (string member) { - lrdf_remove_uri_matches (uri.c_str()); + vector 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& members, - const map& fields) +AudioLibrary::search_members_and (vector& members, const vector tags) { lrdf_statement **head; lrdf_statement* pattern = 0; lrdf_statement* old = 0; head = &pattern; - map::const_iterator i; - for (i = fields.begin(); i != fields.end(); ++i){ + vector::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& 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& members, - const map& fields) -{ - map::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& 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& vec) -{ - sort(vec.begin(), vec.end()); - unique(vec.begin(), vec.end()); -} - -void -AudioLibrary::set_paths (vector paths) -{ - sfdb_paths = paths; - - scan_paths (); -} - -vector -AudioLibrary::get_paths () -{ - return sfdb_paths; -} - -void -AudioLibrary::scan_paths () -{ - if (sfdb_paths.size() < 1) { - return; - } - - vector 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::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 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 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 ar = boost::dynamic_pointer_cast(*in_o); // We look only for crossfades which begin with the current region, so we don't get doubles - for (list::const_iterator xfades = other._crossfades.begin(); xfades != other._crossfades.end(); ++xfades) { + for (list::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_ptrar2 = boost::dynamic_pointer_cast(*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 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 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) x = xtmp; } - region->set_playlist (0); + region->set_playlist (boost::shared_ptr()); } 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 + #include #include #include +#include +#include + #include #include #include @@ -32,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -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::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 pl = _session.playlist_by_name (prop->value()); if (pl) { - _freeze_record.playlist = dynamic_cast (pl); + _freeze_record.playlist = boost::dynamic_pointer_cast (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(diskstream->playlist()); + boost::shared_ptr apl = boost::dynamic_pointer_cast(diskstream->playlist()); assert(apl); if (apl->read (buffers.get_audio(nframes).data(nframes), @@ -777,12 +768,12 @@ AudioTrack::freeze (InterThreadInfo& itt) { vector > srcs; string new_playlist_name; - Playlist* new_playlist; + boost::shared_ptr new_playlist; string dir; string region_name; boost::shared_ptr diskstream = audio_diskstream(); - if ((_freeze_record.playlist = dynamic_cast(diskstream->playlist())) == 0) { + if ((_freeze_record.playlist = boost::dynamic_pointer_cast(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(new_playlist)); + diskstream->use_playlist (boost::dynamic_pointer_cast(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(arg)->Xrun (); /* EMIT SIGNAL */ + AudioEngine* ae = static_cast (arg); + if (ae->jack()) { + ae->Xrun (); /* EMIT SIGNAL */ + } return 0; } int AudioEngine::_graph_order_callback (void *arg) { - static_cast(arg)->GraphReordered (); /* EMIT SIGNAL */ + AudioEngine* ae = static_cast (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 (arg); + AudioEngine* ae = static_cast (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 #include #include +#include #include #include #include #include #include +#include #include @@ -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 #include #include +#include #include #include @@ -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 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 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 #include +#include #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 source) +AudioSource::queue_for_peaks (boost::shared_ptr 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 #include +#include #include #include #include @@ -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(_diskstream->playlist()); + boost::shared_ptr apl = boost::dynamic_pointer_cast(_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 #include #include -#include +#include #include "i18n.h" @@ -37,6 +37,11 @@ using namespace PBD; sigc::signal 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,15 +521,43 @@ 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 (); } maybe_signal_changed (); } +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) { @@ -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 #include -#include #include #include #include @@ -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 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) { { 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))); } - 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 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 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace PBD; +using namespace ARDOUR; + +void +setup_enum_writer () +{ + EnumWriter* enum_writer = new EnumWriter(); + vector i; + vector 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 (o, var); } std::istream& operator>>(std::istream& o, ShuttleBehaviour& var) { return int_to_type (o, var); } std::istream& operator>>(std::istream& o, ShuttleUnits& var) { return int_to_type (o, var); } +std::istream& operator>>(std::istream& o, SmpteFormat& var) { return int_to_type (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 r (boost::dynamic_pointer_cast (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 r (boost::dynamic_pointer_cast + (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 (RegionFactory::create (boost::static_pointer_cast (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 #include +#include #include #include @@ -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) { @@ -403,6 +403,40 @@ Locations::set_current (Location *loc, bool want_lock) return ret; } +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; kname(); + 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) { 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 @@ -56,6 +56,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) { @@ -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 @@ -36,6 +34,7 @@ #include #include #include +#include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -220,16 +220,14 @@ MidiDiskstream::get_input_sources () int MidiDiskstream::find_and_use_playlist (const string& name) { - Playlist* pl; - MidiPlaylist* playlist; + boost::shared_ptr playlist; - if ((pl = _session.playlist_by_name (name)) == 0) { - playlist = new MidiPlaylist(_session, name); - pl = playlist; + if ((playlist = boost::dynamic_pointer_cast (_session.playlist_by_name (name))) == 0) { + playlist = boost::dynamic_pointer_cast (PlaylistFactory::create (_session, name)); } - if ((playlist = dynamic_cast (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(playlist)); +MidiDiskstream::use_playlist (boost::shared_ptr playlist) +{ + assert(boost::dynamic_pointer_cast(playlist)); - return Diskstream::use_playlist(playlist); + Diskstream::use_playlist(playlist); + + return 0; } int MidiDiskstream::use_new_playlist () -{ +{ string newname; - MidiPlaylist* playlist; + boost::shared_ptr 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 (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 playlist; newname = Playlist::bump_name (_playlist->name(), _session); - if ((playlist = new MidiPlaylist (*midi_playlist(), newname)) != 0) { + if ((playlist = boost::dynamic_pointer_cast(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 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 (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 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 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 pl = _session.playlist_by_name (prop->value()); if (pl) { - _freeze_record.playlist = dynamic_cast (pl); + _freeze_record.playlist = boost::dynamic_pointer_cast (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 NamedSelection::NamedSelectionCreated; -NamedSelection::NamedSelection (string n, list& l) +typedef std::list > PlaylistList; + +NamedSelection::NamedSelection (string n, PlaylistList& l) : name (n) { playlists = l; - for (list::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; 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::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::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 #include #include +#include #include #include @@ -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 #include #include +#include #include "i18n.h" @@ -43,14 +44,12 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -sigc::signal Playlist::PlaylistCreated; - struct ShowMeTheList { - ShowMeTheList (Playlist *pl, const string& n) : playlist (pl), name (n) {} + ShowMeTheList (boost::shared_ptr pl, const string& n) : playlist (pl), name (n) {} ~ShowMeTheList () { cerr << ">>>>" << name << endl; playlist->dump(); cerr << "<<<<" << name << endl << endl; }; - Playlist *playlist; + boost::shared_ptr 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 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 >::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 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 (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; boost::shared_ptr 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 >::iterator i = all_regions.begin(); i != all_regions.end(); ++i) { - (*i)->set_playlist (0); + (*i)->set_playlist (boost::shared_ptr()); } } @@ -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, 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, nframes_t position, floa for (int i = 0; i < itimes; ++i) { boost::shared_ptr 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, nframes_t position, floa string name; _session.region_name (name, region->name(), false); boost::shared_ptr 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 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, nframes_t position, bool delay_sort) +Playlist::add_region_internal (boost::shared_ptr region, nframes_t position) { RegionSortByPosition cmp; nframes_t old_length = 0; @@ -511,7 +517,11 @@ Playlist::add_region_internal (boost::shared_ptr region, nframes_t posit old_length = _get_maximum_extent(); } - region->set_playlist (this); + if (!in_set_state) { + boost::shared_ptr foo (shared_from_this()); + region->set_playlist (boost::weak_ptr(foo)); + } + region->set_position (position, this); timestamp_layer_op (region); @@ -564,7 +574,7 @@ Playlist::remove_region (boost::shared_ptr region) } int -Playlist::remove_region_internal (boost::shared_ptrregion, bool delay_sort) +Playlist::remove_region_internal (boost::shared_ptrregion) { 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& ranges, bool result_is_hidden) +boost::shared_ptr +Playlist::cut_copy (boost::shared_ptr (Playlist::*pmf)(nframes_t, nframes_t,bool), list& ranges, bool result_is_hidden) { - Playlist* ret; - Playlist* pl; + boost::shared_ptr ret; + boost::shared_ptr pl; nframes_t start; if (ranges.empty()) { - return 0; + return boost::shared_ptr(); } start = ranges.front().start; - for (list::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::cut (list& ranges, bool result_is_hidden) { - Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut; + boost::shared_ptr (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::cut; return cut_copy (pmf, ranges, result_is_hidden); } -Playlist* +boost::shared_ptr Playlist::copy (list& ranges, bool result_is_hidden) { - Playlist* (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy; + boost::shared_ptr (Playlist::*pmf)(nframes_t,nframes_t,bool) = &Playlist::copy; return cut_copy (pmf, ranges, result_is_hidden); } -Playlist * +boost::shared_ptr Playlist::cut (nframes_t start, nframes_t cnt, bool result_is_hidden) { - Playlist *the_copy; + boost::shared_ptr 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(); } 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::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 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 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, nframes_t position, float while (itimes--) { boost::shared_ptr 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, nframes_t position, float string name; _session.region_name (name, region->name(), false); boost::shared_ptr 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, 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, 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 } 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 } 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 #include +#include +#include #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 > PlaylistFactory::PlaylistCreated; + +boost::shared_ptr +PlaylistFactory::create (Session& s, const XMLNode& node, bool hidden) +{ + const XMLProperty* type = node.property("type"); + + boost::shared_ptr pl; + + if ( !type || type->value() == "audio" ) + pl = boost::shared_ptr (new AudioPlaylist (s, node, hidden)); + else if ( type->value() == "midi" ) + pl = boost::shared_ptr (new MidiPlaylist (s, node, hidden)); + + pl->set_region_ownership (); + + if (pl && !hidden) { + PlaylistCreated (pl); + } + return pl; +} + +boost::shared_ptr +PlaylistFactory::create (DataType type, Session& s, string name, bool hidden) +{ + boost::shared_ptr pl; + + if (type == DataType::AUDIO) + pl = boost::shared_ptr (new AudioPlaylist (s, name, hidden)); + else if (type == DataType::MIDI) + pl = boost::shared_ptr (new MidiPlaylist (s, name, hidden)); + + if (pl && !hidden) { + PlaylistCreated (pl); + } + + return pl; +} + +boost::shared_ptr +PlaylistFactory::create (boost::shared_ptr old, string name, bool hidden) { - const AudioPlaylist* apl; - - if ((apl = dynamic_cast (&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 pl; + boost::shared_ptr apl; + boost::shared_ptr mpl; + + if ((apl = boost::dynamic_pointer_cast (old)) != 0) { + pl = boost::shared_ptr (new AudioPlaylist (apl, name, hidden)); + pl->set_region_ownership (); + } else if ((mpl = boost::dynamic_pointer_cast (old)) != 0) { + pl = boost::shared_ptr (new MidiPlaylist (mpl, name, hidden)); + pl->set_region_ownership (); } + + if (pl && !hidden) { + PlaylistCreated (pl); + } + + return pl; +} + +boost::shared_ptr +PlaylistFactory::create (boost::shared_ptr old, nframes_t start, nframes_t cnt, string name, bool hidden) +{ + boost::shared_ptr pl; + boost::shared_ptr apl; + boost::shared_ptr mpl; + + if ((apl = boost::dynamic_pointer_cast (old)) != 0) { + pl = boost::shared_ptr (new AudioPlaylist (apl, start, cnt, name, hidden)); + pl->set_region_ownership (); + } else if ((mpl = boost::dynamic_pointer_cast (old)) != 0) { + pl = boost::shared_ptr (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 (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 #include +#include #include #include @@ -58,6 +59,7 @@ Redirect::Redirect (Session& s, const string& name, Placement p, Redirect::~Redirect () { + notify_callbacks (); } boost::shared_ptr @@ -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 @@ -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 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 > unique_srcs; @@ -125,7 +123,6 @@ Region::Region (boost::shared_ptr 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 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 > unique_srcs; for (SourceList::iterator i=srcs.begin(); i != srcs.end(); ++i) { @@ -250,7 +243,6 @@ Region::Region (boost::shared_ptr 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 src, const XMLNode& node) Region::~Region () { - if (_playlist) { + boost::shared_ptr 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 wpl) { - if (pl == _playlist) { + boost::shared_ptr old_playlist = (_playlist.lock()); + boost::shared_ptr 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 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 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 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 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 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 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 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 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::get_parent() const { - if (_playlist) { + boost::shared_ptr pl (playlist()); + + if (pl) { boost::shared_ptr r; boost::shared_ptr grrr2 = boost::dynamic_pointer_cast (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 (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 #include +#include #include #include @@ -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, 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 #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -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 (); } @@ -401,6 +405,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 dstream) { - Playlist *playlist; + boost::shared_ptr 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 dsl = diskstreams.reader(); for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) { - Playlist* pl = (*i)->playlist(); + boost::shared_ptr pl = (*i)->playlist(); if ((me = pl->get_maximum_extent()) > max) { max = me; } @@ -2697,14 +2719,10 @@ Session::add_source (boost::shared_ptr 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))); + set_dirty(); } - - source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr (source))); - set_dirty(); - - SourceAdded (source); /* EMIT SIGNAL */ } void @@ -2737,8 +2755,6 @@ Session::remove_source (boost::weak_ptr src) save_state (_current_snapshot_name); } - - SourceRemoved(source); /* EMIT SIGNAL */ } boost::shared_ptr @@ -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 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(); } void -Session::add_playlist (Playlist* playlist) +Session::add_playlist (boost::shared_ptr 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->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_playlist), boost::weak_ptr(playlist))); } } @@ -3216,7 +3235,7 @@ Session::add_playlist (Playlist* playlist) } void -Session::get_playlists (vector& s) +Session::get_playlists (vector >& s) { { Glib::Mutex::Lock lm (playlist_lock); @@ -3230,15 +3249,25 @@ Session::get_playlists (vector& s) } void -Session::track_playlist (Playlist* pl, bool inuse) +Session::track_playlist (bool inuse, boost::weak_ptr wpl) { + boost::shared_ptr 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 weak_playlist) { if (_state_of_the_state & Deletion) { return; } + boost::shared_ptr 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 (redirect)) != 0) { if ((port_insert = dynamic_cast (insert)) != 0) { - _port_inserts.remove (port_insert); + list::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 (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 (redirect)) != 0) { - _sends.remove (send); + list::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::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::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 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 >& srcs, InterThreadInfo& itt) { + int ret = -1; + boost::shared_ptr playlist; boost::shared_ptr 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 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 #include #include -using namespace PBD; -#include "i18n.h" +#include +#include +#include +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(*_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(*pl, before, after); + if (boost::shared_ptr pl = playlist_by_name(child->property("name")->value())) { + return new MementoCommand(*(pl.get()), before, after); + } } else if (obj_T == typeid (Route).name() || obj_T == typeid (AudioTrack).name()) { return new MementoCommand(*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; + 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); + + 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 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 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 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 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; + 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); + + 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 #else -#include #include +#include #endif #include @@ -57,6 +57,8 @@ #include #include #include +#include +#include #include #include @@ -93,6 +95,7 @@ #include #include #include +#include #include @@ -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; nlist = node.children(); @@ -1812,7 +1863,7 @@ Session::load_unused_playlists (const XMLNode& node) { XMLNodeList nlist; XMLNodeConstIterator niter; - Playlist *playlist; + boost::shared_ptr 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)); } return 0; } -Playlist * +boost::shared_ptr 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(); + } } 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 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 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& result, bool exclude_th return 0; } +struct RegionCounter { + typedef std::map > AudioSourceList; + AudioSourceList::iterator iter; + boost::shared_ptr region; + uint32_t count; + + RegionCounter() : count (0) {} +}; + int Session::cleanup_sources (Session::cleanup_report& rep) { vector > dead_sources; - vector playlists_tbd; + vector > playlists_tbd; PathScanner scanner; string sound_path; vector::iterator i; @@ -2549,73 +2605,36 @@ Session::cleanup_sources (Session::cleanup_report& rep) /* now delete any that were marked for deletion */ - for (vector::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 >::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 >::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 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; @@ -2865,6 +2901,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) { @@ -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 - + // 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 r = routes.reader (); boost::shared_ptr 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 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 pl) { _playlists.insert (pl); + pl->GoingAway.connect (bind (mem_fun (*this, &Source::remove_playlist), boost::weak_ptr (pl))); } void -Source::remove_playlist (Playlist* pl) +Source::remove_playlist (boost::weak_ptr wpl) { - std::set::iterator x; + boost::shared_ptr pl (wpl.lock()); + + if (!pl) { + return; + } + + std::set >::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 ret (new DestructiveFileSource (s, node)); + try { + boost::shared_ptr ret (new CoreAudioSource (s, node)); if (setup_peakfile (ret)) { return boost::shared_ptr(); } SourceCreated (ret); return ret; + } - } else { - - try { - boost::shared_ptr ret (new CoreAudioSource (s, node)); + catch (failed_constructor& err) { + boost::shared_ptr ret (new SndFileSource (s, node)); if (setup_peakfile (ret)) { return boost::shared_ptr(); } SourceCreated (ret); return ret; - - } catch (failed_constructor& err) { - - try { - boost::shared_ptr ret (new CoreAudioSource (node)); - SourceCreated (ret); - return ret; - } - - - catch (failed_constructor& err) { - - boost::shared_ptr ret (new SndFileSource (s, node)); - if (setup_peakfile (ret)) { - return boost::shared_ptr(); - } - SourceCreated (ret); - return ret; - } } } else if (type == DataType::MIDI) { - + boost::shared_ptr 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 ret (new DestructiveFileSource (s, node)); - if (setup_peakfile (ret)) { - return boost::shared_ptr(); - } - SourceCreated (ret); - return ret; + boost::shared_ptr ret (new SndFileSource (s, node)); - } else { - - boost::shared_ptr ret (new SndFileSource (s, node)); - if (setup_peakfile (ret)) { - return boost::shared_ptr(); - } - SourceCreated (ret); - return ret; + if (setup_peakfile (ret)) { + return boost::shared_ptr(); } + + SourceCreated (ret); + return ret; } else if (type == DataType::MIDI) { boost::shared_ptr ret (new SMFSource (s, node)); + SourceCreated (ret); return ret; } - + return boost::shared_ptr (); } @@ -164,39 +134,53 @@ boost::shared_ptr SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce) { if (type == DataType::AUDIO) { - if (flags & Destructive) { - boost::shared_ptr ret (new DestructiveFileSource (s, idstr, flags)); - if (setup_peakfile (ret)) { - return boost::shared_ptr(); - } - if (announce) { - SourceCreated (ret); - } - return ret; - + + if (!(flags & Destructive)) { + try { boost::shared_ptr ret (new CoreAudioSource (s, idstr, flags)); + if (setup_peakfile (ret)) { + return boost::shared_ptr(); + } if (announce) { SourceCreated (ret); } return ret; - - } catch (failed_constructor& err) { + } + + catch (failed_constructor& err) { boost::shared_ptr ret (new SndFileSource (s, idstr, flags)); + if (setup_peakfile (ret)) { + return boost::shared_ptr(); + } if (announce) { SourceCreated (ret); } return ret; } + } else { + + boost::shared_ptr ret (new SndFileSource (s, idstr, flags)); + if (setup_peakfile (ret)) { + return boost::shared_ptr(); + } + if (announce) { + SourceCreated (ret); + } + return ret; + } + } else if (type == DataType::MIDI) { boost::shared_ptr ret (new SMFSource (s, node)); - SourceCreated (ret); + if (announce) { + SourceCreated (ret); + } return ret; } - + return boost::shared_ptr(); } @@ -206,27 +190,32 @@ boost::shared_ptr SourceFactory::createReadable (DataType type, Session& s, string idstr, AudioFileSource::Flag flags, bool announce) { if (type == DataType::AUDIO) { - + boost::shared_ptr ret (new SndFileSource (s, idstr, flags)); + if (setup_peakfile (ret)) { return boost::shared_ptr(); } + if (announce) { SourceCreated (ret); } + return ret; } else if (type == DataType::MIDI) { - boost::shared_ptr ret (new SMFSource (s, idstr, SMFSource::Flag(0))); // FIXME: flags? + // FIXME: flags? + boost::shared_ptr ret (new SMFSource (s, idstr, SMFSource::Flag(0))); + if (announce) { SourceCreated (ret); } - return ret; + return ret; } - - return boost::shared_ptr (); + + return boost::shared_ptr(); } #endif // HAVE_COREAUDIO @@ -235,39 +224,33 @@ boost::shared_ptr 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 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(); - } - if (announce) { - SourceCreated (ret); - } - } else { - boost::shared_ptr 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(); - } - if (announce) { - SourceCreated (ret); - } - return ret; + boost::shared_ptr 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(); + } + if (announce) { + SourceCreated (ret); } + return ret; } else if (type == DataType::MIDI) { boost::shared_ptr ret (new SMFSource (s, path)); - SourceCreated (ret); + + if (announce) { + SourceCreated (ret); + } return ret; - + } return boost::shared_ptr (); 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 #include #include +#include #include #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; } } -- cgit v1.2.3