diff options
author | Hans Baier <hansfbaier@googlemail.com> | 2008-08-04 22:37:24 +0000 |
---|---|---|
committer | Hans Baier <hansfbaier@googlemail.com> | 2008-08-04 22:37:24 +0000 |
commit | ed990de6040215412baf8f448b1876d78bd9cc19 (patch) | |
tree | 196c6552040b0ad1c9c402cba2b4543ae39536ef /libs | |
parent | 44fd104ada0fbd8b76d34150e941d85d6de6f81b (diff) |
* first implementation of MIDI Clock Slave support
git-svn-id: svn://localhost/ardour2/branches/3.0@3652 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/SConscript | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/ardour.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/configuration_vars.h | 6 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 188 | ||||
-rw-r--r-- | libs/ardour/ardour/slave.h | 92 | ||||
-rw-r--r-- | libs/ardour/ardour/types.h | 45 | ||||
-rw-r--r-- | libs/ardour/enums.cc | 35 | ||||
-rw-r--r-- | libs/ardour/globals.cc | 75 | ||||
-rw-r--r-- | libs/ardour/session.cc | 664 | ||||
-rw-r--r-- | libs/ardour/session_midi.cc | 221 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 210 | ||||
-rw-r--r-- | libs/ardour/utils.cc | 65 | ||||
-rw-r--r-- | libs/midi++2/midi++/midnam_patch.h | 50 | ||||
-rw-r--r-- | libs/midi++2/midnam_patch.cc | 53 |
14 files changed, 957 insertions, 755 deletions
diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index b50aecbcb3..44f4718384 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -92,6 +92,7 @@ midi_stretch.cc midi_track.cc mix.cc mtc_slave.cc +midi_clock_slave.cc named_selection.cc note.cc panner.cc diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h index 6f653f10bf..fecd0fcf4e 100644 --- a/libs/ardour/ardour/ardour.h +++ b/libs/ardour/ardour/ardour.h @@ -1,5 +1,5 @@ /* - Copyright (C) 1999 Paul Davis + Copyright (C) 1999 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 @@ -51,9 +51,9 @@ namespace ARDOUR { int cleanup (); std::string get_ardour_revision (); - + void find_bindings_files (std::map<std::string,std::string>&); - + const layer_t max_layer = UCHAR_MAX; microseconds_t get_microseconds (); @@ -82,6 +82,7 @@ namespace ARDOUR { extern MIDI::Port* default_mmc_port; extern MIDI::Port* default_mtc_port; extern MIDI::Port* default_midi_port; +extern MIDI::Port *default_midi_clock_port; #endif /* __ardour_ardour_h__ */ diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h index 4e2a14c07b..7a7a2ce419 100644 --- a/libs/ardour/ardour/configuration_vars.h +++ b/libs/ardour/ardour/configuration_vars.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2007 Paul Davis + Copyright (C) 2000-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,11 +30,13 @@ CONFIG_VARIABLE (std::string, auditioner_output_right, "auditioner-output-right" CONFIG_VARIABLE (std::string, mtc_port_name, "mtc-port-name", "default") CONFIG_VARIABLE (std::string, mmc_port_name, "mmc-port-name", "default") CONFIG_VARIABLE (std::string, midi_port_name, "midi-port-name", "default") +CONFIG_VARIABLE (std::string, midi_clock_port_name, "midi-clock-port-name", "default") CONFIG_VARIABLE (bool, trace_midi_input, "trace-midi-input", false) CONFIG_VARIABLE (bool, trace_midi_output, "trace-midi-output", false) CONFIG_VARIABLE (bool, send_mtc, "send-mtc", false) CONFIG_VARIABLE (bool, send_mmc, "send-mmc", true) CONFIG_VARIABLE (bool, mmc_control, "mmc-control", true) +CONFIG_VARIABLE (bool, midi_clock_control, "midi-clock-control", false) CONFIG_VARIABLE (bool, midi_feedback, "midi-feedback", false) CONFIG_VARIABLE (uint8_t, mmc_receive_device_id, "mmc-receive-device-id", 0) CONFIG_VARIABLE (uint8_t, mmc_send_device_id, "mmc-send-device-id", 0) @@ -139,7 +141,7 @@ CONFIG_VARIABLE (nframes_t, over_length_short, "over-length-short", 2) CONFIG_VARIABLE (nframes_t, over_length_long, "over-length-long", 10) /* miscellany */ - + CONFIG_VARIABLE (bool, hiding_groups_deactivates_groups, "hiding-groups-deactivates-groups", true) CONFIG_VARIABLE (bool, verify_remove_last_capture, "verify-remove-last-capture", true) CONFIG_VARIABLE (bool, no_new_session_dialog, "no-new-session-dialog", false) diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index b718d751b4..00cbc9922e 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000 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 @@ -46,8 +46,8 @@ #include <midi++/types.h> #include <midi++/mmc.h> -#include <pbd/stateful.h> -#include <pbd/destructible.h> +#include <pbd/stateful.h> +#include <pbd/destructible.h> #include <ardour/ardour.h> #include <ardour/configuration.h> @@ -150,7 +150,7 @@ class Session : public PBD::StatefulDestructible InputConfigurationChange, SetAudioRange, SetPlayRange, - + /* only one of each of these events can be queued at any one time */ @@ -165,7 +165,7 @@ class Session : public PBD::StatefulDestructible Replace, Clear }; - + Type type; Action action; nframes_t action_frame; @@ -186,14 +186,14 @@ class Session : public PBD::StatefulDestructible list<MusicRange> music_range; Event(Type t, Action a, nframes_t when, nframes_t where, float spd, bool yn = false) - : type (t), + : type (t), action (a), action_frame (when), target_frame (where), speed (spd), yes_or_no (yn) {} - void set_ptr (void* p) { + void set_ptr (void* p) { ptr = p; } @@ -242,7 +242,7 @@ class Session : public PBD::StatefulDestructible uint32_t n_physical_in, uint32_t n_physical_out, nframes_t initial_length); - + virtual ~Session (); string path() const { return _path; } @@ -265,20 +265,20 @@ class Session : public PBD::StatefulDestructible static sigc::signal<void> AutoBindingOff; static sigc::signal<void,std::string> Dialog; - + std::string sound_dir (bool with_path = true) const; std::string peak_dir () const; std::string dead_sound_dir () const; std::string automation_dir () const; std::string analysis_dir() const; - + int ensure_subdirs (); Glib::ustring peak_path (Glib::ustring) const; static string change_audio_path_by_name (string oldpath, string oldname, string newname, bool destructive); static string change_midi_path_by_name (string oldpath, string oldname, string newname, bool destructive); - + string peak_path_from_audio_path (string) const; string audio_path_from_name (string, uint32_t nchans, uint32_t chan, bool destructive); string midi_path_from_name (string); @@ -288,7 +288,7 @@ class Session : public PBD::StatefulDestructible BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO); BufferSet& get_scratch_buffers (ChanCount count = ChanCount::ZERO); BufferSet& get_mix_buffers (ChanCount count = ChanCount::ZERO); - + void add_diskstream (boost::shared_ptr<Diskstream>); boost::shared_ptr<Diskstream> diskstream_by_id (const PBD::ID& id); boost::shared_ptr<Diskstream> diskstream_by_name (string name); @@ -298,17 +298,17 @@ class Session : public PBD::StatefulDestructible void refill_all_diskstream_buffers (); uint32_t audio_diskstream_buffer_size() const { return audio_dstream_buffer_size; } uint32_t midi_diskstream_buffer_size() const { return midi_dstream_buffer_size; } - + uint32_t get_next_diskstream_id() const { return n_diskstreams(); } uint32_t n_diskstreams() const; - + typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList; - typedef std::list<boost::shared_ptr<Route> > RouteList; - + typedef std::list<boost::shared_ptr<Route> > RouteList; + boost::shared_ptr<RouteList> get_routes() const { return routes.reader (); } - + uint32_t nroutes() const { return routes.reader()->size(); } uint32_t ntracks () const; uint32_t nbusses () const; @@ -316,7 +316,7 @@ class Session : public PBD::StatefulDestructible struct RoutePublicOrderSorter { bool operator() (boost::shared_ptr<Route>, boost::shared_ptr<Route> b); }; - + template<class T> void foreach_route (T *obj, void (T::*func)(Route&)); template<class T> void foreach_route (T *obj, void (T::*func)(boost::shared_ptr<Route>)); template<class T, class A> void foreach_route (T *obj, void (T::*func)(Route&, A), A arg); @@ -327,7 +327,7 @@ class Session : public PBD::StatefulDestructible bool route_name_unique (string) const; - bool get_record_enabled() const { + bool get_record_enabled() const { return (record_status () >= Enabled); } @@ -343,7 +343,7 @@ class Session : public PBD::StatefulDestructible void maybe_enable_record (); void disable_record (bool rt_context, bool force = false); void step_back_from_record (); - + void maybe_write_autosave (); /* Proxy signal for region hidden changes */ @@ -351,9 +351,9 @@ class Session : public PBD::StatefulDestructible sigc::signal<void,boost::shared_ptr<Region> > RegionHiddenChange; /* Emitted when all i/o connections are complete */ - + sigc::signal<void> IOConnectionsComplete; - + /* Record status signals */ sigc::signal<void> RecordStateChanged; @@ -442,10 +442,10 @@ class Session : public PBD::StatefulDestructible void remove_state (string snapshot_name); void rename_state (string old_name, string new_name); void remove_pending_capture_state (); - + sigc::signal<void,string> StateSaved; sigc::signal<void> StateReady; - + vector<string*>* possible_states() const; static vector<string*>* possible_states(string path); @@ -499,14 +499,14 @@ class Session : public PBD::StatefulDestructible std::list<boost::shared_ptr<AudioTrack> > new_audio_track (int input_channels, int output_channels, TrackMode mode = Normal, uint32_t how_many = 1); RouteList new_audio_route (int input_channels, int output_channels, uint32_t how_many); - + std::list<boost::shared_ptr<MidiTrack> > new_midi_track (TrackMode mode = Normal, uint32_t how_many = 1); //boost::shared_ptr<Route> new_midi_route (uint32_t how_many = 1); void remove_route (boost::shared_ptr<Route>); void resort_routes (); void resort_routes_using (boost::shared_ptr<RouteList>); - + void set_remote_control_ids(); AudioEngine & engine() { return _engine; } @@ -563,18 +563,18 @@ class Session : public PBD::StatefulDestructible float transport_speed() const { return _transport_speed; } bool transport_stopped() const { return _transport_speed == 0.0f; } bool transport_rolling() const { return _transport_speed != 0.0f; } - + void set_silent (bool yn); bool silent () { return _silent; } int jack_slave_sync (nframes_t); TempoMap& tempo_map() { return *_tempo_map; } - + /* region info */ void add_regions (std::vector<boost::shared_ptr<Region> >&); - + sigc::signal<void,boost::weak_ptr<Region> > RegionAdded; sigc::signal<void,std::vector<boost::weak_ptr<Region> >& > RegionsAdded; sigc::signal<void,boost::weak_ptr<Region> > RegionRemoved; @@ -584,7 +584,7 @@ class Session : public PBD::StatefulDestructible string path_from_region_name (DataType type, string name, string identifier); boost::shared_ptr<Region> find_whole_file_parent (boost::shared_ptr<Region const>); - + void find_equivalent_playlist_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >& result); boost::shared_ptr<Region> XMLRegionFactory (const XMLNode&, bool full); @@ -597,16 +597,16 @@ class Session : public PBD::StatefulDestructible struct import_status : public InterThreadInfo { string doing_what; - + /* control info */ SrcQuality quality; volatile bool freeze; std::vector<Glib::ustring> paths; bool replace_existing_source; - + /* result */ SourceList sources; - + }; void import_audiofiles (import_status&); @@ -640,7 +640,7 @@ class Session : public PBD::StatefulDestructible "yes, delete this playlist" and 1 for "no, don't delete this playlist. */ - + sigc::signal<int,boost::shared_ptr<ARDOUR::Playlist> > AskAboutPlaylistDeletion; /* handlers should return 0 for "ignore the rate mismatch" @@ -654,7 +654,7 @@ class Session : public PBD::StatefulDestructible */ static sigc::signal<int> AskAboutPendingState; - + boost::shared_ptr<AudioFileSource> create_audio_source_for_session (ARDOUR::AudioDiskstream&, uint32_t which_channel, bool destructive); boost::shared_ptr<MidiSource> create_midi_source_for_session (ARDOUR::MidiDiskstream&); @@ -687,7 +687,7 @@ class Session : public PBD::StatefulDestructible /* Curves and AutomationLists (TODO when they go away) */ void add_curve(Curve*); void add_automation_list(AutomationList*); - + /* fade curves */ float get_default_fade_length () const { return default_fade_msecs; } @@ -701,7 +701,7 @@ class Session : public PBD::StatefulDestructible void audition_region (boost::shared_ptr<Region>); void cancel_audition (); bool is_auditioning () const; - + sigc::signal<void,bool> AuditionActive; /* flattening stuff */ @@ -712,7 +712,7 @@ class Session : public PBD::StatefulDestructible int freeze (InterThreadInfo&); /* session-wide solo/mute/rec-enable */ - + bool soloing() const { return currently_soloing; } void set_all_solo (bool); @@ -720,7 +720,7 @@ class Session : public PBD::StatefulDestructible sigc::signal<void,bool> SoloActive; sigc::signal<void> SoloChanged; - + void record_disenable_all (); void record_enable_all (); @@ -730,15 +730,15 @@ class Session : public PBD::StatefulDestructible boost::shared_ptr<IO> master_out() const { return _master_out; } /* insert/send management */ - + uint32_t n_port_inserts() const { return _port_inserts.size(); } uint32_t n_plugin_inserts() const { return _plugin_inserts.size(); } uint32_t n_sends() const { return _sends.size(); } - - static void set_disable_all_loaded_plugins (bool yn) { + + static void set_disable_all_loaded_plugins (bool yn) { _disable_all_loaded_plugins = yn; } - static bool get_disable_all_loaded_plugins() { + static bool get_disable_all_loaded_plugins() { return _disable_all_loaded_plugins; } @@ -748,7 +748,7 @@ class Session : public PBD::StatefulDestructible void mark_insert_id (uint32_t); /* s/w "RAID" management */ - + nframes_t available_capture_duration(); /* I/O bundles */ @@ -767,23 +767,26 @@ class Session : public PBD::StatefulDestructible int set_mtc_port (string port_tag); int set_mmc_port (string port_tag); int set_midi_port (string port_tag); + int set_midi_clock_port (string port_tag); MIDI::Port *mtc_port() const { return _mtc_port; } MIDI::Port *mmc_port() const { return _mmc_port; } MIDI::Port *midi_port() const { return _midi_port; } + MIDI::Port *midi_clock_port() const { return _midi_clock_port; } sigc::signal<void> MTC_PortChanged; sigc::signal<void> MMC_PortChanged; sigc::signal<void> MIDI_PortChanged; + sigc::signal<void> MIDIClock_PortChanged; void set_trace_midi_input (bool, MIDI::Port* port = 0); void set_trace_midi_output (bool, MIDI::Port* port = 0); bool get_trace_midi_input(MIDI::Port *port = 0); bool get_trace_midi_output(MIDI::Port *port = 0); - + void set_mmc_receive_device_id (uint32_t id); void set_mmc_send_device_id (uint32_t id); - + /* Scrubbing */ void start_scrub (nframes_t where); @@ -806,7 +809,7 @@ class Session : public PBD::StatefulDestructible } UndoHistory& history() { return _history; } - + uint32_t undo_depth() const { return _history.undo_depth(); } uint32_t redo_depth() const { return _history.redo_depth(); } string next_undo() const { return _history.next_undo(); } @@ -839,7 +842,7 @@ class Session : public PBD::StatefulDestructible GlobalRouteBooleanState before, after; Session& sess; void* src; - + }; class GlobalSoloStateCommand : public GlobalRouteStateCommand @@ -896,7 +899,7 @@ class Session : public PBD::StatefulDestructible /* clicking */ boost::shared_ptr<IO> click_io() { return _click_io; } - + /* disk, buffer loads */ uint32_t playback_load (); @@ -906,7 +909,7 @@ class Session : public PBD::StatefulDestructible void reset_playback_load_min (); void reset_capture_load_min (); - + float read_data_rate () const; float write_data_rate () const; @@ -929,7 +932,7 @@ class Session : public PBD::StatefulDestructible TransportContext, ExportContext }; - + /* VST support */ static long vst_callback (AEffect* effect, @@ -938,7 +941,7 @@ class Session : public PBD::StatefulDestructible long value, void* ptr, float opt); - + typedef float (*compute_peak_t) (Sample *, nframes_t, float); typedef void (*find_peaks_t) (Sample *, nframes_t, float *, float*); typedef void (*apply_gain_to_buffer_t) (Sample *, nframes_t, float); @@ -974,11 +977,11 @@ class Session : public PBD::StatefulDestructible friend class Route; void schedule_curve_reallocation (); void update_latency_compensation (bool, bool); - + private: int create (bool& new_session, const string& mix_template, nframes_t initial_length); void destroy (); - + nframes_t compute_initial_length (); enum SubState { @@ -995,7 +998,7 @@ class Session : public PBD::StatefulDestructible */ typedef void (Session::*process_function_type)(nframes_t); - + AudioEngine& _engine; mutable gint processing_prohibited; process_function_type process_function; @@ -1039,13 +1042,13 @@ class Session : public PBD::StatefulDestructible void update_latency_compensation_proxy (void* ignored); void ensure_buffers (ChanCount howmany); - + void process_scrub (nframes_t); void process_without_events (nframes_t); void process_with_events (nframes_t); void process_audition (nframes_t); int process_export (nframes_t, ARDOUR::ExportSpecification*); - + /* slave tracking */ static const int delta_accumulator_size = 25; @@ -1054,13 +1057,13 @@ class Session : public PBD::StatefulDestructible long average_slave_delta; int average_dir; bool have_first_delta_accumulator; - + enum SlaveState { Stopped, Waiting, Running }; - + SlaveState slave_state; nframes_t slave_wait_end; @@ -1116,6 +1119,7 @@ class Session : public PBD::StatefulDestructible MIDI::Port* _mmc_port; MIDI::Port* _mtc_port; MIDI::Port* _midi_port; + MIDI::Port* _midi_clock_port; string _path; string _name; bool session_send_mmc; @@ -1153,7 +1157,7 @@ class Session : public PBD::StatefulDestructible bool pending_locate_flush; bool pending_abort; bool pending_auto_loop; - + Sample* butler_mixdown_buffer; float* butler_gain_buffer; pthread_t butler_thread; @@ -1164,7 +1168,7 @@ class Session : public PBD::StatefulDestructible 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 { Wake, @@ -1191,8 +1195,8 @@ class Session : public PBD::StatefulDestructible PostTransportInputChange = 0x20000, PostTransportCurveRealloc = 0x40000 }; - - static const PostTransportWork ProcessCannotProceedMask = + + static const PostTransportWork ProcessCannotProceedMask = PostTransportWork (PostTransportInputChange| PostTransportSpeed| PostTransportReverse| @@ -1201,7 +1205,7 @@ class Session : public PBD::StatefulDestructible PostTransportAudition| PostTransportLocate| PostTransportStop); - + PostTransportWork post_transport_work; void summon_butler (); @@ -1264,7 +1268,7 @@ class Session : public PBD::StatefulDestructible int midi_read (MIDI::Port *); void enable_record (); - + void increment_transport_position (uint32_t val) { if (max_frames - val < _transport_frame) { _transport_frame = max_frames; @@ -1297,6 +1301,10 @@ class Session : public PBD::StatefulDestructible void spp_continue (MIDI::Parser&); void spp_stop (MIDI::Parser&); + void midi_clock_start (MIDI::Parser&); + void midi_clock_continue (MIDI::Parser&); + void midi_clock_stop (MIDI::Parser&); + void mmc_deferred_play (MIDI::MachineControl &); void mmc_stop (MIDI::MachineControl &); void mmc_step (MIDI::MachineControl &, int); @@ -1327,7 +1335,7 @@ class Session : public PBD::StatefulDestructible nframes_t outbound_mtc_smpte_frame; SMPTE::Time transmitting_smpte_time; int next_quarter_frame_to_send; - + double _frames_per_smpte_frame; /* has to be floating point because of drop frame */ nframes_t _frames_per_hour; nframes_t _smpte_frames_per_hour; @@ -1339,28 +1347,28 @@ class Session : public PBD::StatefulDestructible bool last_smpte_valid; nframes_t last_smpte_when; SMPTE::Time last_smpte; - + bool _send_smpte_update; ///< Flag to send a full frame (SMPTE) MTC message this cycle int send_full_time_code(nframes_t nframes); int send_midi_time_code_for_cycle(nframes_t nframes); nframes_t adjust_apparent_position (nframes_t frames); - + void reset_record_status (); - + int no_roll (nframes_t nframes, nframes_t offset); - + bool non_realtime_work_pending() const { return static_cast<bool>(post_transport_work); } bool process_can_proceed() const { return !(post_transport_work & ProcessCannotProceedMask); } struct MIDIRequest { - + enum Type { PortChange, Quit }; - + Type type; MIDIRequest () {} @@ -1419,7 +1427,7 @@ class Session : public PBD::StatefulDestructible /* disk-streams */ - SerializedRCUManager<DiskstreamList> diskstreams; + SerializedRCUManager<DiskstreamList> diskstreams; uint32_t audio_dstream_buffer_size; uint32_t midi_dstream_buffer_size; @@ -1439,7 +1447,7 @@ class Session : public PBD::StatefulDestructible bool solo_update_disabled; bool currently_soloing; - + void route_mute_changed (void *src); void route_solo_changed (void *src, boost::weak_ptr<Route>); void catch_up_on_solo (); @@ -1452,7 +1460,7 @@ class Session : public PBD::StatefulDestructible mutable Glib::Mutex region_lock; typedef map<PBD::ID,boost::shared_ptr<Region> > RegionList; RegionList regions; - + void add_region (boost::shared_ptr<Region>); void region_changed (Change, boost::weak_ptr<Region>); void remove_region (boost::weak_ptr<Region>); @@ -1460,7 +1468,7 @@ class Session : public PBD::StatefulDestructible int load_regions (const XMLNode& node); /* SOURCES */ - + mutable Glib::Mutex source_lock; typedef std::map<PBD::ID,boost::shared_ptr<Source> > SourceMap; @@ -1468,7 +1476,7 @@ class Session : public PBD::StatefulDestructible public: SourceMap get_sources() { return sources; } - + private: @@ -1478,7 +1486,7 @@ class Session : public PBD::StatefulDestructible boost::shared_ptr<Source> XMLSourceFactory (const XMLNode&); /* PLAYLISTS */ - + mutable Glib::Mutex playlist_lock; typedef set<boost::shared_ptr<Playlist> > PlaylistList; PlaylistList playlists; @@ -1529,7 +1537,7 @@ class Session : public PBD::StatefulDestructible int flatten_one_track (AudioTrack&, nframes_t start, nframes_t cnt); /* INSERT AND SEND MANAGEMENT */ - + list<PortInsert *> _port_inserts; list<PluginInsert *> _plugin_inserts; list<Send *> _sends; @@ -1547,8 +1555,8 @@ class Session : public PBD::StatefulDestructible struct space_and_path { uint32_t blocks; /* 4kB blocks */ string path; - - space_and_path() { + + space_and_path() { blocks = 0; } }; @@ -1558,14 +1566,14 @@ class Session : public PBD::StatefulDestructible return a.blocks > b.blocks; } }; - + void setup_raid_path (string path); vector<space_and_path> session_dirs; vector<space_and_path>::iterator last_rr_session_dir; uint32_t _total_free_4k_blocks; Glib::Mutex space_lock; - + string get_best_session_directory_for_new_source (); void refresh_disk_space (); @@ -1612,9 +1620,9 @@ class Session : public PBD::StatefulDestructible nframes_t offset; const Sample *data; - Click (nframes_t s, nframes_t d, const Sample *b) + Click (nframes_t s, nframes_t d, const Sample *b) : start (s), duration (d), data (b) { offset = 0; } - + void *operator new(size_t ignored) { return pool.alloc (); }; @@ -1626,7 +1634,7 @@ class Session : public PBD::StatefulDestructible private: static Pool pool; }; - + typedef list<Click*> Clicks; Clicks clicks; @@ -1649,7 +1657,7 @@ class Session : public PBD::StatefulDestructible void click (nframes_t start, nframes_t nframes, nframes_t offset); vector<Route*> master_outs; - + /* range playback */ list<AudioRange> current_audio_range; @@ -1659,7 +1667,7 @@ class Session : public PBD::StatefulDestructible /* main outs */ uint32_t main_outs; - + boost::shared_ptr<IO> _master_out; boost::shared_ptr<IO> _control_out; @@ -1702,10 +1710,10 @@ class Session : public PBD::StatefulDestructible void config_changed (const char*); XMLNode& get_control_protocol_state (); - + void set_history_depth (uint32_t depth); void sync_order_keys (); - + static bool _disable_all_loaded_plugins; }; diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 509f8fa9d2..9df8574430 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002 Paul Davis + Copyright (C) 2002 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 @@ -50,6 +50,18 @@ class Slave { virtual bool is_always_synced() const { return false; } }; +struct SafeTime { + int guard1; + nframes_t position; + nframes_t timestamp; + int guard2; + + SafeTime() { + guard1 = 0; + guard2 = 0; + timestamp = 0; + } +}; class MTC_Slave : public Slave, public sigc::trackable { public: @@ -59,9 +71,9 @@ class MTC_Slave : public Slave, public sigc::trackable { void rebind (MIDI::Port&); bool speed_and_position (float&, nframes_t&); - bool locked() const; - bool ok() const; - void handle_locate (const MIDI::byte*); + bool locked() const; + bool ok() const; + void handle_locate (const MIDI::byte*); nframes_t resolution() const; bool requires_seekahead () const { return true; } @@ -72,27 +84,11 @@ class MTC_Slave : public Slave, public sigc::trackable { std::vector<sigc::connection> connections; bool can_notify_on_unknown_rate; - struct SafeTime { - - - int guard1; - //SMPTE_Time mtc; - nframes_t position; - nframes_t timestamp; - int guard2; - - SafeTime() { - guard1 = 0; - guard2 = 0; - timestamp = 0; - } - }; - - SafeTime current; + SafeTime current; nframes_t mtc_frame; /* current time */ nframes_t last_inbound_frame; /* when we got it; audio clocked */ - float mtc_speed; + float mtc_speed; nframes_t first_mtc_frame; nframes_t first_mtc_time; @@ -108,12 +104,56 @@ class MTC_Slave : public Slave, public sigc::trackable { void read_current (SafeTime *) const; }; -class ADAT_Slave : public Slave +class MIDIClock_Slave : public Slave, public sigc::trackable { + public: + MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24); + ~MIDIClock_Slave (); + + void rebind (MIDI::Port&); + bool speed_and_position (float&, nframes_t&); + + bool locked() const; + bool ok() const; + bool starting() const { return _starting; } + + nframes_t resolution() const; + bool requires_seekahead () const { return true; } + + private: + Session& session; + MIDI::Port* port; + std::vector<sigc::connection> connections; + + int ppqn; + double one_ppqn_in_frames; + + SafeTime current; + nframes_t midi_clock_frame; /* current time */ + nframes_t last_inbound_frame; /* when we got it; audio clocked */ + + float midi_clock_speed; + nframes_t first_midi_clock_frame; + nframes_t first_midi_clock_time; + + static const int32_t accumulator_size = 128; + float accumulator[accumulator_size]; + int32_t accumulator_index; + bool have_first_accumulated_speed; + + void reset (); + void start (MIDI::Parser& parser); + void stop (MIDI::Parser& parser); + void update_midi_clock (MIDI::Parser& parser); + void read_current (SafeTime *) const; + bool _starting; +}; + +class ADAT_Slave : public Slave { public: ADAT_Slave () {} ~ADAT_Slave () {} - + bool speed_and_position (float& speed, nframes_t& pos) { speed = 0; pos = 0; @@ -126,12 +166,12 @@ class ADAT_Slave : public Slave bool requires_seekahead () const { return true; } }; -class JACK_Slave : public Slave +class JACK_Slave : public Slave { public: JACK_Slave (jack_client_t*); ~JACK_Slave (); - + bool speed_and_position (float& speed, nframes_t& pos); bool starting() const { return _starting; } diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 9bfd93cdbf..d94683f427 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002 Paul Davis + Copyright (C) 2002 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 @@ -41,7 +41,7 @@ typedef int intptr_t; #endif -/* eventually, we'd like everything (including JACK) to +/* eventually, we'd like everything (including JACK) to move to this. for now, its a dedicated type. */ @@ -69,7 +69,7 @@ namespace ARDOUR { OverlapNone, // no overlap OverlapInternal, // the overlap is 100% with the object OverlapStart, // overlap covers start, but ends within - OverlapEnd, // overlap begins within and covers end + OverlapEnd, // overlap begins within and covers end OverlapExternal // overlap extends to (at least) begin+end }; @@ -128,12 +128,12 @@ namespace ARDOUR { Normal, Destructive }; - + enum NoteMode { Sustained, Percussive }; - + enum ChannelMode { AllChannels = 0, ///< Pass through all channel information unmodified FilterChannels, ///< Ignore events on certain channels @@ -144,7 +144,7 @@ namespace ARDOUR { Frames, Beats }; - + struct BBT_Time { uint32_t bars; uint32_t beats; @@ -157,12 +157,12 @@ namespace ARDOUR { } /* we can't define arithmetic operators for BBT_Time, because - the results depend on a TempoMap, but we can define + the results depend on a TempoMap, but we can define a useful check on the less-than condition. */ bool operator< (const BBT_Time& other) const { - return bars < other.bars || + return bars < other.bars || (bars == other.bars && beats < other.beats) || (bars == other.bars && beats == other.beats && ticks < other.ticks); } @@ -170,7 +170,7 @@ namespace ARDOUR { bool operator== (const BBT_Time& other) const { return bars == other.bars && beats == other.beats && ticks == other.ticks; } - + }; enum SmpteFormat { smpte_23976, @@ -198,7 +198,7 @@ namespace ARDOUR { SMPTE::Time smpte; BBT_Time bbt; - union { + union { nframes_t frames; double seconds; }; @@ -210,10 +210,10 @@ namespace ARDOUR { nframes_t start; nframes_t end; uint32_t id; - + AudioRange (nframes_t s, nframes_t e, uint32_t i) : start (s), end (e) , id (i) {} - - nframes_t length() { return end - start + 1; } + + nframes_t length() { return end - start + 1; } bool operator== (const AudioRange& other) const { return start == other.start && end == other.end && id == other.id; @@ -227,12 +227,12 @@ namespace ARDOUR { return ARDOUR::coverage (start, end, s, e); } }; - + struct MusicRange { BBT_Time start; BBT_Time end; uint32_t id; - + MusicRange (BBT_Time& s, BBT_Time& e, uint32_t i) : start (s), end (e), id (i) {} @@ -273,7 +273,7 @@ namespace ARDOUR { Lock }; - enum RegionPoint { + enum RegionPoint { Start, End, SyncPoint @@ -312,7 +312,7 @@ namespace ARDOUR { FullCrossfade, ShortCrossfade }; - + enum LayerModel { LaterHigher, MoveAddHigher, @@ -355,11 +355,11 @@ namespace ARDOUR { struct PeakData { typedef Sample PeakDatum; - + PeakDatum min; PeakDatum max; }; - + enum PluginType { AudioUnit, LADSPA, @@ -370,7 +370,8 @@ namespace ARDOUR { enum SlaveSource { None = 0, MTC, - JACK + JACK, + MIDIClock }; enum ShuttleBehaviour { @@ -399,8 +400,8 @@ namespace ARDOUR { float time_fraction; float pitch_fraction; /* SoundTouch */ - bool quick_seek; - bool antialias; + bool quick_seek; + bool antialias; /* RubberBand */ int opts; // really RubberBandStretcher::Options }; diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 71b699396b..0781f8c8e1 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2007 Paul Davis + Copyright (C) 2000-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -103,7 +103,7 @@ setup_enum_writer () REGISTER_ENUM (OverlapEnd); REGISTER_ENUM (OverlapExternal); REGISTER (_OverlapType); - + REGISTER_ENUM (GainAutomation); REGISTER_ENUM (PanAutomation); REGISTER_ENUM (PluginAutomation); @@ -126,22 +126,22 @@ setup_enum_writer () REGISTER_BITS (_AutoStyle); REGISTER_ENUM (CaptureTime); - REGISTER_ENUM (ExistingMaterial); + REGISTER_ENUM (ExistingMaterial); REGISTER (_AlignStyle); REGISTER_ENUM (MeterInput); REGISTER_ENUM (MeterPreFader); - REGISTER_ENUM (MeterPostFader); + REGISTER_ENUM (MeterPostFader); REGISTER (_MeterPoint); REGISTER_ENUM (Normal); REGISTER_ENUM (Destructive); REGISTER (_TrackMode); - + REGISTER_ENUM (Sustained); REGISTER_ENUM (Percussive); REGISTER (_NoteMode); - + REGISTER_ENUM (AllChannels); REGISTER_ENUM (FilterChannels); REGISTER_ENUM (ForceChannel); @@ -155,7 +155,7 @@ setup_enum_writer () REGISTER_ENUM (MeterFalloffFaster); REGISTER_ENUM (MeterFalloffFastest); REGISTER (_MeterFalloff); - + REGISTER_ENUM (MeterHoldOff); REGISTER_ENUM (MeterHoldShort); REGISTER_ENUM (MeterHoldMedium); @@ -163,12 +163,12 @@ setup_enum_writer () REGISTER (_MeterHold); REGISTER_ENUM (Slide); - REGISTER_ENUM (Splice); + REGISTER_ENUM (Splice); REGISTER (_EditMode); REGISTER_ENUM (Start); REGISTER_ENUM (End); - REGISTER_ENUM (SyncPoint); + REGISTER_ENUM (SyncPoint); REGISTER (_RegionPoint); REGISTER_ENUM (PreFader); @@ -197,11 +197,11 @@ setup_enum_writer () REGISTER_ENUM (LaterHigher); REGISTER_ENUM (MoveAddHigher); - REGISTER_ENUM (AddHigher); + REGISTER_ENUM (AddHigher); REGISTER (_LayerModel); REGISTER_ENUM (InverseMute); - REGISTER_ENUM (SoloBus); + REGISTER_ENUM (SoloBus); REGISTER (_SoloModel); REGISTER_ENUM (AutoConnectPhysical); @@ -219,7 +219,7 @@ setup_enum_writer () REGISTER_ENUM (CAF); REGISTER_ENUM (AIFF); REGISTER_ENUM (iXML); - REGISTER_ENUM (RF64); + REGISTER_ENUM (RF64); REGISTER (_HeaderFormat); REGISTER_ENUM (AudioUnit); @@ -229,15 +229,16 @@ setup_enum_writer () REGISTER_ENUM (None); REGISTER_ENUM (MTC); - REGISTER_ENUM (JACK); + REGISTER_ENUM (JACK); + REGISTER_ENUM (MIDIClock); REGISTER (_SlaveSource); REGISTER_ENUM (Sprung); - REGISTER_ENUM (Wheel); + REGISTER_ENUM (Wheel); REGISTER (_ShuttleBehaviour); REGISTER_ENUM (Percentage); - REGISTER_ENUM (Semitones); + REGISTER_ENUM (Semitones); REGISTER (_ShuttleUnits); REGISTER_CLASS_ENUM (Session, Disabled); @@ -379,10 +380,10 @@ setup_enum_writer () REGISTER_CLASS_ENUM (Track, Frozen); REGISTER_CLASS_ENUM (Track, UnFrozen); REGISTER (_Track_FreezeState); - + REGISTER_CLASS_ENUM (AutomationList, Discrete); REGISTER_CLASS_ENUM (AutomationList, Linear); REGISTER_CLASS_ENUM (AutomationList, Curved); REGISTER (_AutomationList_InterpolationStyle); - + } diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 02c4a5ced6..1397a7d959 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 Paul Davis + Copyright (C) 2000 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 @@ -73,7 +73,7 @@ #if defined (__APPLE__) #include <Carbon/Carbon.h> // For Gestalt #endif - + #include "i18n.h" ARDOUR::Configuration* ARDOUR::Config = 0; @@ -91,6 +91,7 @@ using namespace PBD; MIDI::Port *default_mmc_port = 0; MIDI::Port *default_mtc_port = 0; MIDI::Port *default_midi_port = 0; +MIDI::Port *default_midi_clock_port = 0; Change ARDOUR::StartChanged = ARDOUR::new_change (); Change ARDOUR::LengthChanged = ARDOUR::new_change (); @@ -111,11 +112,11 @@ static int setup_osc () { /* no real cost to creating this object, and it avoids - conditionals anywhere that uses it + conditionals anywhere that uses it */ - + osc = new OSC (Config->get_osc_port()); - + if (Config->get_use_osc ()) { BootMessage (_("Starting OSC")); return osc->start (); @@ -125,7 +126,7 @@ setup_osc () } #endif -int +int setup_midi () { if (Config->midi_ports.size() == 0) { @@ -150,16 +151,20 @@ setup_midi () if (Config->get_mmc_port_name() != N_("default")) { default_mmc_port = MIDI::Manager::instance()->port (Config->get_mmc_port_name()); - } + } if (Config->get_mtc_port_name() != N_("default")) { default_mtc_port = MIDI::Manager::instance()->port (Config->get_mtc_port_name()); - } + } if (Config->get_midi_port_name() != N_("default")) { default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_port_name()); - } - + } + + if (Config->get_midi_clock_port_name() != N_("default")) { + default_midi_port = MIDI::Manager::instance()->port (Config->get_midi_clock_port_name()); + } + /* If that didn't work, just use the first listed port */ if (default_mmc_port == 0) { @@ -173,7 +178,11 @@ setup_midi () if (default_midi_port == 0) { default_midi_port = first; } - + + if (default_midi_clock_port == 0) { + default_midi_clock_port = first; + } + } else if (ports.size() == 1) { first = ports.begin()->second; @@ -183,21 +192,27 @@ setup_midi () default_mmc_port = first; default_mtc_port = default_mmc_port; default_midi_port = default_mmc_port; + default_midi_clock_port = default_mmc_port; } if (default_mmc_port == 0) { - warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name()) + warning << string_compose (_("No MMC control (MIDI port \"%1\" not available)"), Config->get_mmc_port_name()) << endmsg; return 0; - } + } if (default_mtc_port == 0) { - warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name()) + warning << string_compose (_("No MTC support (MIDI port \"%1\" not available)"), Config->get_mtc_port_name()) << endmsg; } if (default_midi_port == 0) { - warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name()) + warning << string_compose (_("No MIDI parameter support (MIDI port \"%1\" not available)"), Config->get_midi_port_name()) + << endmsg; + } + + if (default_midi_clock_port == 0) { + warning << string_compose (_("No MIDI Clock support (MIDI port \"%1\" not available)"), Config->get_midi_clock_port_name()) << endmsg; } @@ -331,7 +346,7 @@ ARDOUR::init (bool use_vst, bool try_optimization) return -1; } #endif - + /* Make VAMP look in our library ahead of anything else */ char *p = getenv ("VAMP_PATH"); @@ -339,7 +354,7 @@ ARDOUR::init (bool use_vst, bool try_optimization) if (p) { vamppath += ':'; vamppath += p; - } + } setenv ("VAMP_PATH", vamppath.c_str(), 1); @@ -350,7 +365,7 @@ ARDOUR::init (bool use_vst, bool try_optimization) /* singleton - first object is "it" */ new PluginManager (); - + /* singleton - first object is "it" */ new ControlProtocolManager (); ControlProtocolManager::instance().discover_control_protocols (); @@ -359,7 +374,7 @@ ARDOUR::init (bool use_vst, bool try_optimization) if ((node = Config->control_protocol_state()) != 0) { ControlProtocolManager::instance().set_state (*node); } - + BoundsChanged = Change (StartChanged|PositionChanged|LengthChanged); return 0; @@ -430,7 +445,7 @@ ARDOUR::find_bindings_files (map<string,string>& files) if (found.empty()) { return; } - + for (vector<sys::path>::iterator x = found.begin(); x != found.end(); ++x) { sys::path path = *x; pair<string,string> namepath; @@ -445,7 +460,7 @@ ARDOUR::LocaleGuard::LocaleGuard (const char* str) old = strdup (setlocale (LC_NUMERIC, NULL)); if (strcmp (old, str)) { setlocale (LC_NUMERIC, str); - } + } } ARDOUR::LocaleGuard::~LocaleGuard () @@ -472,7 +487,7 @@ ARDOUR::setup_fpu () /* XXX use real code to determine if the processor supports DenormalsAreZero and FlushToZero */ - + if (!fpu.has_flush_to_zero() && !fpu.has_denormals_are_zero()) { return; } @@ -496,7 +511,7 @@ ARDOUR::setup_fpu () MXCSR |= 0x8000; } break; - + case DenormalFTZDAZ: if (fpu.has_flush_to_zero()) { if (fpu.has_denormals_are_zero()) { @@ -514,7 +529,7 @@ ARDOUR::setup_fpu () } ARDOUR::OverlapType -ARDOUR::coverage (nframes_t sa, nframes_t ea, +ARDOUR::coverage (nframes_t sa, nframes_t ea, nframes_t sb, nframes_t eb) { /* OverlapType returned reflects how the second (B) @@ -539,7 +554,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea, |-----------------| B - "B is internal to A" + "B is internal to A" */ #ifdef OLD_COVERAGE @@ -555,7 +570,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea, ----| B -----------------------| B --| B - + "B overlaps the start of A" */ @@ -563,13 +578,13 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea, if ((eb >= sa) && (eb <= ea)) { return OverlapStart; } - /* + /* |---------------------| A |----------------- B - |----------------------- B + |----------------------- B |- B - "B overlaps the end of A" + "B overlaps the end of A" */ if ((sb > sa) && (sb <= ea)) { @@ -577,7 +592,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea, } /* |--------------------| A - -------------------------- B + -------------------------- B |----------------------- B ----------------------| B |--------------------| B diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index ff269cc931..1124b8960f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2004 Paul Davis + Copyright (C) 1999-2004 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 @@ -131,11 +131,12 @@ Session::Session (AudioEngine &eng, _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _midi_clock_port (default_midi_clock_port), _session_dir (new SessionDirectory(fullpath)), pending_events (2048), post_transport_work((PostTransportWork)0), _send_smpte_update (false), - midi_requests (128), + midi_requests (128), diskstreams (new DiskstreamList), routes (new RouteList), auditioner ((Auditioner*) 0), @@ -148,7 +149,7 @@ Session::Session (AudioEngine &eng, if (!eng.connected()) { throw failed_constructor(); } - + cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl; n_physical_outputs = _engine.n_physical_outputs(); @@ -164,14 +165,14 @@ Session::Session (AudioEngine &eng, throw failed_constructor (); } } - + if (second_stage_init (new_session)) { destroy (); throw failed_constructor (); } - + store_recent_sessions(_name, _path); - + bool was_dirty = dirty(); _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); @@ -201,6 +202,7 @@ Session::Session (AudioEngine &eng, _mmc_port (default_mmc_port), _mtc_port (default_mtc_port), _midi_port (default_midi_port), + _midi_clock_port (default_midi_clock_port), _session_dir ( new SessionDirectory(fullpath)), pending_events (2048), post_transport_work((PostTransportWork)0), @@ -244,31 +246,31 @@ Session::Session (AudioEngine &eng, { /* set up Master Out and Control Out if necessary */ - + RouteList rl; int control_id = 1; - + if (control_out_channels) { shared_ptr<Route> r (new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut)); r->set_remote_control_id (control_id++); - + rl.push_back (r); } - + if (master_out_channels) { shared_ptr<Route> r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut)); r->set_remote_control_id (control_id); - + rl.push_back (r); } else { /* prohibit auto-connect to master, because there isn't one */ output_ac = AutoConnectOption (output_ac & ~AutoConnectMaster); } - + if (!rl.empty()) { add_routes (rl, false); } - + } Config->set_input_auto_connect (input_ac); @@ -278,9 +280,9 @@ Session::Session (AudioEngine &eng, destroy (); throw failed_constructor (); } - + store_recent_sessions (_name, _path); - + _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty); Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed)); @@ -305,7 +307,7 @@ Session::destroy () _engine.remove_session (); GoingAway (); /* EMIT SIGNAL */ - + /* do this */ notify_callbacks (); @@ -315,14 +317,14 @@ Session::destroy () _history.clear (); /* clear state tree so that no references to objects are held any more */ - + if (state_tree) { delete state_tree; } terminate_butler_thread (); //terminate_midi_thread (); - + if (click_data && click_data != default_click) { delete [] click_data; } @@ -338,9 +340,9 @@ Session::destroy () delete _mix_buffers; AudioDiskstream::free_working_buffers(); - + Route::SyncOrderKeys.clear(); - + #undef TRACK_DESTRUCTION #ifdef TRACK_DESTRUCTION cerr << "delete named selections\n"; @@ -365,10 +367,10 @@ Session::destroy () ++tmp; (*i)->drop_references (); - + i = tmp; } - + for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ) { PlaylistList::iterator tmp; @@ -376,17 +378,17 @@ Session::destroy () ++tmp; (*i)->drop_references (); - + i = tmp; } - + playlists.clear (); unused_playlists.clear (); #ifdef TRACK_DESTRUCTION cerr << "delete regions\n"; #endif /* TRACK_DESTRUCTION */ - + for (RegionList::iterator i = regions.begin(); i != regions.end(); ) { RegionList::iterator tmp; @@ -436,13 +438,13 @@ Session::destroy () tmp = i; ++tmp; - + i->second->drop_references (); - + i = tmp; } sources.clear (); - + #ifdef TRACK_DESTRUCTION cerr << "delete mix groups\n"; #endif /* TRACK_DESTRUCTION */ @@ -462,7 +464,7 @@ Session::destroy () #endif /* TRACK_DESTRUCTION */ for (list<RouteGroup *>::iterator i = edit_groups.begin(); i != edit_groups.end(); ) { list<RouteGroup*>::iterator tmp; - + tmp = i; ++tmp; @@ -470,7 +472,7 @@ Session::destroy () i = tmp; } - + if (butler_mixdown_buffer) { delete [] butler_mixdown_buffer; } @@ -497,7 +499,7 @@ Session::set_worst_io_latencies () } boost::shared_ptr<RouteList> r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { _worst_output_latency = max (_worst_output_latency, (*i)->output_latency()); _worst_input_latency = max (_worst_input_latency, (*i)->input_latency()); @@ -536,15 +538,15 @@ Session::when_engine_running () try { XMLNode* child = 0; - + _click_io.reset (new ClickIO (*this, "click", 0, 0, -1, -1)); if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) { /* existing state for Click */ - + if (_click_io->set_state (*child->children().front()) == 0) { - + _clicking = Config->get_clicking (); } else { @@ -554,7 +556,7 @@ Session::when_engine_running () } } else { - + /* default state for Click */ first_physical_output = _engine.get_nth_physical_output (DataType::AUDIO, 0); @@ -642,24 +644,24 @@ Session::when_engine_running () if (_master_out) { /* create master/control ports */ - + if (_master_out) { uint32_t n; /* force the master to ignore any later call to this */ - + if (_master_out->pending_state_node) { _master_out->ports_became_legal(); } /* no panner resets till we are through */ - + _master_out->defer_pan_reset (); - + while (_master_out->n_inputs().n_audio() < _master_out->input_maximum().n_audio()) { if (_master_out->add_input_port ("", this, DataType::AUDIO)) { - error << _("cannot setup master inputs") + error << _("cannot setup master inputs") << endmsg; break; } @@ -676,7 +678,7 @@ Session::when_engine_running () } _master_out->allow_pan_reset (); - + } shared_ptr<AutoBundle> c (new AutoBundle (_("Master Out"), true)); @@ -686,8 +688,8 @@ Session::when_engine_running () c->set_port (n, _master_out->input(n)->name()); } add_bundle (c); - } - + } + BootMessage (_("Setup signal flow and plugins")); hookup_io (); @@ -697,7 +699,7 @@ Session::when_engine_running () BootMessage (_("Catch up with send/insert state")); insert_cnt = 0; - + for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) { uint32_t id; @@ -712,7 +714,7 @@ Session::when_engine_running () for (list<Send*>::iterator i = _sends.begin(); i != _sends.end(); ++i) { uint32_t id; - + if (sscanf ((*i)->name().c_str(), "%*s %u", &id) == 1) { if (id > send_cnt) { send_cnt = id; @@ -720,7 +722,7 @@ Session::when_engine_running () } } - + _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty)); /* hook us up to the engine */ @@ -736,7 +738,7 @@ Session::when_engine_running () osc->set_session (*this); #endif - + } void @@ -750,16 +752,16 @@ Session::hookup_io () 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; } @@ -797,7 +799,7 @@ Session::hookup_io () cports.push_back (_control_out->input(n)->name()); } - boost::shared_ptr<RouteList> r = routes.reader (); + boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator x = r->begin(); x != r->end(); ++x) { (*x)->set_control_outs (cports); @@ -808,7 +810,7 @@ Session::hookup_io () if (_bundle_xml_node) { load_bundles (*_bundle_xml_node); delete _bundle_xml_node; - } + } /* Tell all IO objects to connect themselves together */ @@ -839,10 +841,10 @@ Session::hookup_io () void Session::playlist_length_changed () { - /* we can't just increase end_location->end() if pl->get_maximum_extent() + /* we can't just increase end_location->end() if pl->get_maximum_extent() if larger. if the playlist used to be the longest playlist, and its now shorter, we have to decrease end_location->end(). hence, - we have to iterate over all diskstreams and check the + we have to iterate over all diskstreams and check the playlists currently in use. */ find_current_end (); @@ -856,7 +858,7 @@ Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream) if ((playlist = dstream->playlist()) != 0) { playlist->LengthChanged.connect (mem_fun (this, &Session::playlist_length_changed)); } - + /* see comment in playlist_length_changed () */ find_current_end (); } @@ -909,7 +911,7 @@ Session::auto_punch_start_changed (Location* location) /* capture start has been changed, so save new pending state */ save_state ("", true); } -} +} void Session::auto_punch_end_changed (Location* location) @@ -917,7 +919,7 @@ Session::auto_punch_end_changed (Location* location) nframes_t when_to_stop = location->end(); // when_to_stop += _worst_output_latency + _worst_input_latency; replace_event (Event::PunchOut, when_to_stop); -} +} void Session::auto_punch_changed (Location* location) @@ -927,7 +929,7 @@ Session::auto_punch_changed (Location* location) replace_event (Event::PunchIn, location->start()); //when_to_stop += _worst_output_latency + _worst_input_latency; replace_event (Event::PunchOut, when_to_stop); -} +} void Session::auto_loop_changed (Location* location) @@ -941,12 +943,12 @@ Session::auto_loop_changed (Location* location) if (_transport_frame > location->end()) { // relocate to beginning of loop clear_events (Event::LocateRoll); - + request_locate (location->start(), true); } else if (Config->get_seamless_loop() && !loop_changing) { - + // schedule a locate-roll to refill the diskstreams at the // previous loop end loop_changing = true; @@ -958,7 +960,7 @@ Session::auto_loop_changed (Location* location) } } - } + } last_loopend = location->end(); } @@ -983,7 +985,7 @@ Session::set_auto_punch_location (Location* location) if (location == 0) { return; } - + if (location->end() <= location->start()) { error << _("Session: you can't use that location for auto punch (start <= end)") << endmsg; return; @@ -992,7 +994,7 @@ Session::set_auto_punch_location (Location* location) auto_punch_start_changed_connection.disconnect(); auto_punch_end_changed_connection.disconnect(); auto_punch_changed_connection.disconnect(); - + auto_punch_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_punch_start_changed)); auto_punch_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_punch_end_changed)); auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed)); @@ -1018,7 +1020,7 @@ Session::set_auto_loop_location (Location* location) remove_event (existing->end(), Event::AutoLoop); auto_loop_location_changed (0); } - + set_dirty(); if (location == 0) { @@ -1031,11 +1033,11 @@ Session::set_auto_loop_location (Location* location) } last_loopend = location->end(); - + auto_loop_start_changed_connection.disconnect(); auto_loop_end_changed_connection.disconnect(); auto_loop_changed_connection.disconnect(); - + auto_loop_start_changed_connection = location->start_changed.connect (mem_fun (this, &Session::auto_loop_changed)); auto_loop_end_changed_connection = location->end_changed.connect (mem_fun (this, &Session::auto_loop_changed)); auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed)); @@ -1083,7 +1085,7 @@ Session::handle_locations_changed (Locations::LocationList& locations) set_auto_loop_location (location); set_loop = true; } - + } if (!set_loop) { @@ -1094,7 +1096,7 @@ Session::handle_locations_changed (Locations::LocationList& locations) } set_dirty(); -} +} void Session::enable_record () @@ -1109,7 +1111,7 @@ Session::enable_record () boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { - (*i)->monitor_input (true); + (*i)->monitor_input (true); } } } @@ -1141,14 +1143,14 @@ Session::disable_record (bool rt_context, bool force) if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) { boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } - + RecordStateChanged (); /* emit signal */ if (!rt_context) { @@ -1166,11 +1168,11 @@ Session::step_back_from_record () if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) { boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } @@ -1191,7 +1193,7 @@ Session::maybe_enable_record () if (_transport_speed) { if (!Config->get_punch_in()) { enable_record (); - } + } } else { deliver_mmc (MIDI::MachineControl::cmdRecordPause, _transport_frame); RecordStateChanged (); /* EMIT SIGNAL */ @@ -1208,7 +1210,7 @@ Session::audible_frame () const nframes_t tf; /* the first of these two possible settings for "offset" - mean that the audible frame is stationary until + mean that the audible frame is stationary until audio emerges from the latency compensation "pseudo-pipeline". @@ -1221,7 +1223,7 @@ Session::audible_frame () const if (offset > current_block_size) { offset -= current_block_size; - } else { + } else { /* XXX is this correct? if we have no external physical connections and everything is internal then surely this is zero? still, how @@ -1251,7 +1253,7 @@ Session::audible_frame () const /* MOVING */ /* take latency into account */ - + ret -= offset; } @@ -1262,7 +1264,7 @@ void Session::set_frame_rate (nframes_t frames_per_second) { /** \fn void Session::set_frame_size(nframes_t) - the AudioEngine object that calls this guarantees + the AudioEngine object that calls this guarantees that it will not be called while we are also in ::process(). Its fine to do things that block here. @@ -1275,7 +1277,7 @@ Session::set_frame_rate (nframes_t frames_per_second) Automatable::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval()))); clear_clicks (); - + // XXX we need some equivalent to this, somehow // SndFileSource::setup_standard_crossfades (frames_per_second); @@ -1287,14 +1289,14 @@ Session::set_frame_rate (nframes_t frames_per_second) void Session::set_block_size (nframes_t nframes) { - /* the AudioEngine guarantees + /* the AudioEngine guarantees that it will not be called while we are also in ::process(). It is therefore fine to do things that block here. */ - { - + { + current_block_size = nframes; ensure_buffers(_scratch_buffers->available()); @@ -1311,7 +1313,7 @@ Session::set_block_size (nframes_t nframes) for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_block_size (nframes); } - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->set_block_size (nframes); @@ -1326,18 +1328,18 @@ Session::set_default_fade (float steepness, float fade_msecs) { #if 0 nframes_t fade_frames; - + /* Don't allow fade of less 1 frame */ - + if (fade_msecs < (1000.0 * (1.0/_current_frame_rate))) { fade_msecs = 0; fade_frames = 0; } else { - + fade_frames = (nframes_t) floor (fade_msecs * _current_frame_rate * 0.001); - + } default_fade_msecs = fade_msecs; @@ -1352,7 +1354,7 @@ Session::set_default_fade (float steepness, float fade_msecs) set_dirty(); /* XXX have to do this at some point */ - /* foreach region using default fade, reset, then + /* foreach region using default fade, reset, then refill_all_diskstream_buffers (); */ #endif @@ -1388,7 +1390,7 @@ trace_terminal (shared_ptr<Route> r1, shared_ptr<Route> rbase) if ((r1->fed_by.find (rbase) != r1->fed_by.end()) && (rbase->fed_by.find (r1) != rbase->fed_by.end())) { info << string_compose(_("feedback loop setup between %1 and %2"), r1->name(), rbase->name()) << endmsg; return; - } + } /* make a copy of the existing list of routes that feed r1 */ @@ -1452,45 +1454,45 @@ void Session::resort_routes_using (shared_ptr<RouteList> r) { RouteList::iterator i, j; - + for (i = r->begin(); i != r->end(); ++i) { - + (*i)->fed_by.clear (); - + for (j = r->begin(); j != r->end(); ++j) { - + /* although routes can feed themselves, it will cause an endless recursive descent if we detect it. so don't bother checking for self-feeding. */ - + if (*j == *i) { continue; } - + if ((*j)->feeds (*i)) { (*i)->fed_by.insert (*j); - } + } } } - + for (i = r->begin(); i != r->end(); ++i) { trace_terminal (*i, *i); } - + RouteSorter cmp; r->sort (cmp); - + #if 0 cerr << "finished route resort\n"; - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { cerr << " " << (*i)->name() << " signal order = " << (*i)->order_key ("signal") << endl; } cerr << endl; #endif - + } list<boost::shared_ptr<MidiTrack> > @@ -1505,7 +1507,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) //uint32_t control_id; // FIXME: need physical I/O and autoconnect stuff for MIDI - + /* count existing midi tracks */ { @@ -1539,7 +1541,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) save, close,restart,add new route - first named route is now Audio2) */ - + do { ++track_id; @@ -1549,7 +1551,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) if (route_by_name (track_name) == 0) { break; } - + } while (track_id < (UINT_MAX-1)); /* @@ -1558,7 +1560,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) } else { nphysical_in = 0; } - + if (Config->get_output_auto_connect() & AutoConnectPhysical) { nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size()); } else { @@ -1567,10 +1569,10 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) */ shared_ptr<MidiTrack> track; - + try { track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode))); - + if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) { error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg; goto failed; @@ -1579,23 +1581,23 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) /* if (nphysical_in) { for (uint32_t x = 0; x < track->n_inputs().n_midi() && x < nphysical_in; ++x) { - + port = ""; - + if (Config->get_input_auto_connect() & AutoConnectPhysical) { port = physinputs[(channels_used+x)%nphysical_in]; - } - + } + if (port.length() && track->connect_input (track->input (x), port, this)) { break; } } } - + for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) { - + port = ""; - + if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) { port = physoutputs[(channels_used+x)%nphysical_out]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { @@ -1603,18 +1605,18 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) port = _master_out->input (x%_master_out->n_inputs().n_midi())->name(); } } - + if (port.length() && track->connect_output (track->output (x), port, this)) { break; } } - + channels_used += track->n_inputs ().n_midi(); */ track->midi_diskstream()->non_realtime_input_change(); - + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); //track->set_remote_control_id (control_id); @@ -1629,7 +1631,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) /* we need to get rid of this, since the track failed to be created */ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */ - { + { RCUWriter<DiskstreamList> writer (diskstreams); boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->remove (track->midi_diskstream()); @@ -1647,7 +1649,7 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) /* we need to get rid of this, since the track failed to be created */ /* XXX arguably, MidiTrack::MidiTrack should not do the Session::add_diskstream() */ - { + { RCUWriter<DiskstreamList> writer (diskstreams); boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->remove (track->midi_diskstream()); @@ -1712,7 +1714,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod save, close,restart,add new route - first named route is now Audio2) */ - + do { ++track_id; @@ -1722,7 +1724,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod if (route_by_name (track_name) == 0) { break; } - + } while (track_id < (UINT_MAX-1)); if (Config->get_input_auto_connect() & AutoConnectPhysical) { @@ -1730,7 +1732,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod } else { nphysical_in = 0; } - + if (Config->get_output_auto_connect() & AutoConnectPhysical) { nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size()); } else { @@ -1738,10 +1740,10 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod } shared_ptr<AudioTrack> track; - + try { track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode))); - + if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), input_channels, output_channels) @@ -1751,23 +1753,23 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod if (nphysical_in) { for (uint32_t x = 0; x < track->n_inputs().n_audio() && x < nphysical_in; ++x) { - + port = ""; - + if (Config->get_input_auto_connect() & AutoConnectPhysical) { port = physinputs[(channels_used+x)%nphysical_in]; - } - + } + if (port.length() && track->connect_input (track->input (x), port, this)) { break; } } } - + for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) { - + port = ""; - + if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) { port = physoutputs[(channels_used+x)%nphysical_out]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { @@ -1775,16 +1777,16 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod port = _master_out->input (x%_master_out->n_inputs().n_audio())->name(); } } - + if (port.length() && track->connect_output (track->output (x), port, this)) { break; } } - + channels_used += track->n_inputs ().n_audio(); track->audio_diskstream()->non_realtime_input_change(); - + track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes)); track->set_remote_control_id (control_id); ++control_id; @@ -1800,7 +1802,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod /* we need to get rid of this, since the track failed to be created */ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */ - { + { RCUWriter<DiskstreamList> writer (diskstreams); boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->remove (track->audio_diskstream()); @@ -1818,7 +1820,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod /* we need to get rid of this, since the track failed to be created */ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */ - { + { RCUWriter<DiskstreamList> writer (diskstreams); boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->remove (track->audio_diskstream()); @@ -1847,14 +1849,14 @@ Session::set_remote_control_ids () shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if ( MixerOrdered == m) { + if ( MixerOrdered == m) { long order = (*i)->order_key(N_("signal")); (*i)->set_remote_control_id( order+1 ); } else if ( EditorOrdered == m) { long order = (*i)->order_key(N_("editor")); (*i)->set_remote_control_id( order+1 ); } else if ( UserOrdered == m) { - //do nothing ... only changes to remote id's are initiated by user + //do nothing ... only changes to remote id's are initiated by user } } } @@ -1906,31 +1908,31 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ try { shared_ptr<Route> bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), DataType::AUDIO)); - + if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), input_channels, output_channels) << endmsg; goto failure; } - + for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) { - + port = ""; if (Config->get_input_auto_connect() & AutoConnectPhysical) { port = physinputs[((n+x)%n_physical_inputs)]; - } - + } + if (port.length() && bus->connect_input (bus->input (x), port, this)) { break; } } - + for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().n_audio(); ++x) { - + port = ""; - + if (Config->get_output_auto_connect() & AutoConnectPhysical) { port = physoutputs[((n+x)%n_physical_outputs)]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { @@ -1938,18 +1940,18 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ port = _master_out->input (x%_master_out->n_inputs().n_audio())->name(); } } - + if (port.length() && bus->connect_output (bus->output (x), port, this)) { break; } } - + bus->set_remote_control_id (control_id); ++control_id; ret.push_back (bus); } - + catch (failed_constructor &err) { error << _("Session: could not create new audio route.") << endmsg; @@ -1977,7 +1979,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ void Session::add_routes (RouteList& new_routes, bool save) { - { + { RCUWriter<RouteList> writer (routes); shared_ptr<RouteList> r = writer.get_copy (); r->insert (r->end(), new_routes.begin(), new_routes.end()); @@ -1985,18 +1987,18 @@ Session::add_routes (RouteList& new_routes, bool save) } for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { - + boost::weak_ptr<Route> wpr (*x); (*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr)); (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed)); (*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x)); (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false)); - + if ((*x)->is_master()) { _master_out = (*x); } - + if ((*x)->is_control()) { _control_out = (*x); } @@ -2017,7 +2019,7 @@ Session::add_routes (RouteList& new_routes, bool save) for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { (*x)->set_control_outs (cports); } - } + } set_dirty(); @@ -2033,7 +2035,7 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream) { /* need to do this in case we're rolling at the time, to prevent false underruns */ dstream->do_refill_with_alloc (); - + dstream->set_block_size (current_block_size); { @@ -2041,7 +2043,7 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream) boost::shared_ptr<DiskstreamList> ds = writer.get_copy(); ds->push_back (dstream); /* writer goes out of scope, copies ds back to main */ - } + } dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream)); /* this will connect to future changes, and check the current length */ @@ -2054,10 +2056,10 @@ Session::add_diskstream (boost::shared_ptr<Diskstream> dstream) void Session::remove_route (shared_ptr<Route> route) { - { + { RCUWriter<RouteList> writer (routes); shared_ptr<RouteList> rs = writer.get_copy (); - + rs->remove (route); /* deleting the master out seems like a dumb @@ -2082,17 +2084,17 @@ Session::remove_route (shared_ptr<Route> route) } update_route_solo_state (); - + /* writer goes out of scope, forces route list update */ } Track* t; boost::shared_ptr<Diskstream> ds; - + if ((t = dynamic_cast<Track*>(route.get())) != 0) { ds = t->diskstream(); } - + if (ds) { { @@ -2103,12 +2105,12 @@ Session::remove_route (shared_ptr<Route> route) } find_current_end (); - - // We need to disconnect the routes inputs and outputs + + // We need to disconnect the routes inputs and outputs route->disconnect_inputs (0); route->disconnect_outputs (0); - + update_latency_compensation (false, false); set_dirty(); @@ -2127,7 +2129,7 @@ Session::remove_route (shared_ptr<Route> route) if (save_state (_current_snapshot_name)) { save_history (_current_snapshot_name); } -} +} void Session::route_mute_changed (void* src) @@ -2137,12 +2139,12 @@ Session::route_mute_changed (void* src) void Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr) -{ +{ if (solo_update_disabled) { // We know already return; } - + bool is_track; boost::shared_ptr<Route> route = wpr.lock (); @@ -2153,46 +2155,46 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr) } is_track = (boost::dynamic_pointer_cast<AudioTrack>(route) != 0); - + shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + /* soloing a track mutes all other tracks, soloing a bus mutes all other busses */ - + if (is_track) { - + /* don't mess with busses */ - + if (dynamic_cast<Track*>((*i).get()) == 0) { continue; } - + } else { - + /* don't mess with tracks */ - + if (dynamic_cast<Track*>((*i).get()) != 0) { continue; } } - + if ((*i) != route && ((*i)->mix_group () == 0 || (*i)->mix_group () != route->mix_group () || !route->mix_group ()->is_active())) { - + if ((*i)->soloed()) { - + /* if its already soloed, and solo latching is enabled, then leave it as it is. */ - + if (Config->get_solo_latched()) { continue; - } + } } - + /* do it */ solo_update_disabled = true; @@ -2200,7 +2202,7 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr) solo_update_disabled = false; } } - + bool something_soloed = false; bool same_thing_soloed = false; bool signal = false; @@ -2222,12 +2224,12 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr) break; } } - + if (something_soloed != currently_soloing) { signal = true; currently_soloing = something_soloed; } - + modify_solo_mute (is_track, same_thing_soloed); if (signal) { @@ -2251,7 +2253,7 @@ Session::update_route_solo_state () /* this is where we actually implement solo by changing the solo mute setting of each track. */ - + shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -2276,7 +2278,7 @@ Session::update_route_solo_state () for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { (*i)->set_solo_mute (false); } - + if (signal) { SoloActive (false); } @@ -2297,11 +2299,11 @@ Session::modify_solo_mute (bool is_track, bool mute) shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + if (is_track) { - + /* only alter track solo mute */ - + if (dynamic_cast<Track*>((*i).get())) { if ((*i)->soloed()) { (*i)->set_solo_mute (!mute); @@ -2325,7 +2327,7 @@ Session::modify_solo_mute (bool is_track, bool mute) /* don't mute master or control outs in response to another bus solo */ - + if ((*i) != _master_out && (*i) != _control_out) { (*i)->set_solo_mute (mute); @@ -2335,7 +2337,7 @@ Session::modify_solo_mute (bool is_track, bool mute) } } -} +} void @@ -2347,8 +2349,8 @@ Session::catch_up_on_solo () has. */ update_route_solo_state(); -} - +} + shared_ptr<Route> Session::route_by_name (string name) { @@ -2411,7 +2413,7 @@ nframes_t Session::get_maximum_extent () const { nframes_t max = 0; - nframes_t me; + nframes_t me; boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); @@ -2464,7 +2466,7 @@ Session::new_region_name (string old) char buf[len]; if ((last_period = old.find_last_of ('.')) == string::npos) { - + /* no period present - add one explicitly */ old += '.'; @@ -2492,7 +2494,7 @@ Session::new_region_name (string old) break; } } - + if (i == regions.end()) { break; } @@ -2500,7 +2502,7 @@ Session::new_region_name (string old) if (number != (UINT_MAX-1)) { return buf; - } + } error << string_compose (_("cannot create new name for region \"%1\""), old) << endmsg; return old; @@ -2515,19 +2517,19 @@ Session::region_name (string& result, string base, bool newlevel) const assert(base.find("/") == string::npos); if (base == "") { - + Glib::Mutex::Lock lm (region_lock); snprintf (buf, sizeof (buf), "%d", (int)regions.size() + 1); - + result = "region."; result += buf; } else { /* XXX this is going to be slow. optimize me later */ - + if (newlevel) { subbase = base; } else { @@ -2542,38 +2544,38 @@ Session::region_name (string& result, string base, bool newlevel) const } bool name_taken = true; - + { Glib::Mutex::Lock lm (region_lock); - + for (int n = 1; n < 5000; ++n) { - + result = subbase; snprintf (buf, sizeof (buf), ".%d", n); result += buf; - + name_taken = false; - + for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { if (i->second->name() == result) { name_taken = true; break; } } - + if (!name_taken) { break; } } } - + if (name_taken) { fatal << string_compose(_("too many regions with names like %1"), base) << endmsg; /*NOTREACHED*/ } } return 0; -} +} void Session::add_region (boost::shared_ptr<Region> region) @@ -2582,49 +2584,49 @@ Session::add_region (boost::shared_ptr<Region> region) v.push_back (region); add_regions (v); } - + void Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions) { bool added = false; - { + { Glib::Mutex::Lock lm (region_lock); for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) { - + boost::shared_ptr<Region> region = *ii; - + if (region == 0) { error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg; } else { - + RegionList::iterator x; - + for (x = regions.begin(); x != regions.end(); ++x) { - + if (region->region_list_equivalent (x->second)) { break; } } - + if (x == regions.end()) { - + pair<RegionList::key_type,RegionList::mapped_type> entry; - + entry.first = region->id(); entry.second = region; - + pair<RegionList::iterator,bool> x = regions.insert (entry); - + if (!x.second) { return; } - + added = true; - } + } } } } @@ -2632,9 +2634,9 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions) /* mark dirty because something has changed even if we didn't add the region to the region list. */ - + set_dirty(); - + if (added) { vector<boost::weak_ptr<Region> > v; @@ -2659,7 +2661,7 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions) region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region))); region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region))); } - + if (!v.empty()) { RegionsAdded (v); /* EMIT SIGNAL */ } @@ -2693,7 +2695,7 @@ Session::remove_region (boost::weak_ptr<Region> weak_region) bool removed = false; - { + { Glib::Mutex::Lock lm (region_lock); if ((i = regions.find (region->id())) != regions.end()) { @@ -2718,7 +2720,7 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) { RegionList::iterator i; boost::shared_ptr<Region> region; - + Glib::Mutex::Lock lm (region_lock); for (i = regions.begin(); i != regions.end(); ++i) { @@ -2731,10 +2733,10 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) return region; } } - } + } return boost::shared_ptr<Region> (); -} +} void Session::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vector<boost::shared_ptr<Region> >& result) @@ -2747,12 +2749,12 @@ int Session::destroy_region (boost::shared_ptr<Region> region) { vector<boost::shared_ptr<Source> > srcs; - + { if (region->playlist()) { region->playlist()->destroy_region (region); } - + for (uint32_t n = 0; n < region->n_channels(); ++n) { srcs.push_back (region->source (n)); } @@ -2764,7 +2766,7 @@ Session::destroy_region (boost::shared_ptr<Region> region) (*i)->mark_for_remove (); (*i)->drop_references (); - + cerr << "source was not used by any playlist\n"; } @@ -2784,12 +2786,12 @@ int Session::remove_last_capture () { list<boost::shared_ptr<Region> > r; - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { list<boost::shared_ptr<Region> >& l = (*i)->last_capture_regions(); - + if (!l.empty()) { r.insert (r.end(), l.begin(), l.end()); l.clear (); @@ -2819,7 +2821,7 @@ Session::add_source (boost::shared_ptr<Source> source) entry.first = source->id(); entry.second = source; - + { Glib::Mutex::Lock lm (source_lock); result = sources.insert (entry); @@ -2829,14 +2831,14 @@ Session::add_source (boost::shared_ptr<Source> source) source->GoingAway.connect (sigc::bind (mem_fun (this, &Session::remove_source), boost::weak_ptr<Source> (source))); set_dirty(); } - + boost::shared_ptr<AudioFileSource> afs; if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) { if (Config->get_auto_analyse_audio()) { Analyser::queue_source_for_analysis (source, false); } - } + } } void @@ -2847,22 +2849,22 @@ Session::remove_source (boost::weak_ptr<Source> src) if (!source) { return; - } + } - { + { Glib::Mutex::Lock lm (source_lock); if ((i = sources.find (source->id())) != sources.end()) { sources.erase (i); - } + } } - + if (!_state_of_the_state & InCleanup) { - + /* save state so we don't end up with a session file referring to non-existent sources. */ - + save_state (_current_snapshot_name); } } @@ -2893,8 +2895,8 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn) if (afs && afs->path() == path && chn == afs->channel()) { return afs; - } - + } + } return boost::shared_ptr<Source>(); } @@ -2917,14 +2919,14 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, /* note: we know (or assume) the old path is already valid */ if (destructive) { - + /* destructive file sources have a name of the form: /path/to/Tnnnn-NAME(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + /* find last slash */ string dir; @@ -2951,16 +2953,16 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, path += '-'; path += new_legalized; path += ".wav"; /* XXX gag me with a spoon */ - + } else { - + /* non-destructive file sources have a name of the form: /path/to/NAME-nnnnn(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + string dir; string suffix; string::size_type slash; @@ -2982,7 +2984,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname, } suffix = path.substr (dash+1); - + // Suffix is now everything after the dash. Now we need to eliminate // the nnnnn part, which is done by either finding a '%' or a '.' @@ -3085,7 +3087,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool if (sys::exists(buf)) { existing++; - } + } } @@ -3112,7 +3114,7 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool spath += '/'; string::size_type pos = foo.find_last_of ('/'); - + if (pos == string::npos) { spath += foo; } else { @@ -3141,14 +3143,14 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, /* note: we know (or assume) the old path is already valid */ if (destructive) { - + /* destructive file sources have a name of the form: /path/to/Tnnnn-NAME(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + /* find last slash */ string dir; @@ -3175,16 +3177,16 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, path += '-'; path += new_legalized; path += ".mid"; /* XXX gag me with a spoon */ - + } else { - + /* non-destructive file sources have a name of the form: /path/to/NAME-nnnnn(%[LR])?.wav - + the task here is to replace NAME with the new name. */ - + string dir; string suffix; string::size_type slash; @@ -3206,7 +3208,7 @@ Session::change_midi_path_by_name (string path, string oldname, string newname, } suffix = path.substr (dash+1); - + // Suffix is now everything after the dash. Now we need to eliminate // the nnnnn part, which is done by either finding a '%' or a '.' @@ -3269,7 +3271,7 @@ Session::midi_path_from_name (string name) for (i = session_dirs.begin(); i != session_dirs.end(); ++i) { SessionDirectory sdir((*i).path); - + sys::path p = sdir.midi_path(); p /= legalized; @@ -3280,7 +3282,7 @@ Session::midi_path_from_name (string name) if (sys::exists (buf)) { existing++; - } + } } if (existing == 0) { @@ -3305,7 +3307,7 @@ Session::midi_path_from_name (string name) spath += '/'; string::size_type pos = foo.find_last_of ('/'); - + if (pos == string::npos) { spath += foo; } else { @@ -3314,12 +3316,12 @@ Session::midi_path_from_name (string name) return spath; } - + boost::shared_ptr<MidiSource> Session::create_midi_source_for_session (MidiDiskstream& ds) { string mpath = midi_path_from_name (ds.name()); - + return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate())); } @@ -3351,7 +3353,7 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist) return; } - { + { Glib::Mutex::Lock lm (playlist_lock); if (find (playlists.begin(), playlists.end(), playlist) == playlists.end()) { playlists.insert (playlists.begin(), playlist); @@ -3368,7 +3370,7 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist) void Session::get_playlists (vector<boost::shared_ptr<Playlist> >& s) { - { + { Glib::Mutex::Lock lm (playlist_lock); for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { s.push_back (*i); @@ -3395,22 +3397,22 @@ Session::track_playlist (bool inuse, boost::weak_ptr<Playlist> wpl) return; } - { + { Glib::Mutex::Lock lm (playlist_lock); if (!inuse) { unused_playlists.insert (pl); - + if ((x = playlists.find (pl)) != playlists.end()) { playlists.erase (x); } - + } else { playlists.insert (pl); - + if ((x = unused_playlists.find (pl)) != unused_playlists.end()) { unused_playlists.erase (x); } @@ -3431,7 +3433,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist) return; } - { + { Glib::Mutex::Lock lm (playlist_lock); PlaylistList::iterator i; @@ -3445,7 +3447,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist) if (i != unused_playlists.end()) { unused_playlists.erase (i); } - + } set_dirty(); @@ -3453,7 +3455,7 @@ Session::remove_playlist (boost::weak_ptr<Playlist> weak_playlist) PlaylistRemoved (playlist); /* EMIT SIGNAL */ } -void +void Session::set_audition (boost::shared_ptr<Region> r) { pending_audition_region = r; @@ -3510,7 +3512,7 @@ Session::remove_empty_sounds () vector<string> audio_filenames; get_files_in_directory (_session_dir->sound_path(), audio_filenames); - + Glib::Mutex::Lock lm (source_lock); TapeFileMatcher tape_file_matcher; @@ -3523,7 +3525,7 @@ Session::remove_empty_sounds () sys::path audio_file_path (_session_dir->sound_path()); audio_file_path /= *i; - + if (AudioFileSource::is_empty (*this, audio_file_path.to_string())) { try @@ -3534,7 +3536,7 @@ Session::remove_empty_sounds () } catch (const sys::filesystem_error& err) { - error << err.what() << endmsg; + error << err.what() << endmsg; } } } @@ -3555,7 +3557,7 @@ void Session::set_all_solo (bool yn) { shared_ptr<RouteList> r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->is_hidden()) { (*i)->set_solo (yn, this); @@ -3564,12 +3566,12 @@ Session::set_all_solo (bool yn) set_dirty(); } - + void Session::set_all_mute (bool yn) { shared_ptr<RouteList> r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if (!(*i)->is_hidden()) { (*i)->set_mute (yn, this); @@ -3578,7 +3580,7 @@ Session::set_all_mute (bool yn) set_dirty(); } - + uint32_t Session::n_diskstreams () const { @@ -3604,7 +3606,7 @@ Session::graph_reordered () if (_state_of_the_state & InitialConnecting) { return; } - + /* every track/bus asked for this to be handled but it was deferred because we were connecting. do it now. */ @@ -3613,10 +3615,10 @@ Session::graph_reordered () resort_routes (); - /* force all diskstreams to update their capture offset values to + /* force all diskstreams to update their capture offset values to reflect any changes in latencies within the graph. */ - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { @@ -3640,7 +3642,7 @@ void Session::record_enable_change_all (bool yn) { shared_ptr<RouteList> r = routes.reader (); - + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { Track* at; @@ -3648,7 +3650,7 @@ Session::record_enable_change_all (bool yn) at->set_record_enable (yn, this); } } - + /* since we don't keep rec-enable state, don't mark session dirty */ } @@ -3681,7 +3683,7 @@ Session::remove_processor (Processor* processor) Send* send; PortInsert* port_insert; PluginInsert* plugin_insert; - + if ((port_insert = dynamic_cast<PortInsert *> (processor)) != 0) { list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert); if (x != _port_inserts.end()) { @@ -3722,7 +3724,7 @@ Session::available_capture_duration () sample_bytes_on_disk = 2.0; break; - default: + default: /* impossible, but keep some gcc versions happy */ fatal << string_compose (_("programming error: %1"), X_("illegal native file data format")) @@ -3735,7 +3737,7 @@ Session::available_capture_duration () if (_total_free_4k_blocks * scale > (double) max_frames) { return max_frames; } - + return (nframes_t) floor (_total_free_4k_blocks * scale); } @@ -3746,7 +3748,7 @@ Session::add_bundle (shared_ptr<Bundle> bundle) Glib::Mutex::Lock guard (bundle_lock); _bundles.push_back (bundle); } - + BundleAdded (bundle); /* EMIT SIGNAL */ set_dirty(); @@ -3760,7 +3762,7 @@ Session::remove_bundle (shared_ptr<Bundle> bundle) { Glib::Mutex::Lock guard (bundle_lock); BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle); - + if (i != _bundles.end()) { _bundles.erase (i); removed = true; @@ -3792,7 +3794,7 @@ void Session::tempo_map_changed (Change ignored) { clear_clicks (); - + for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) { (*i)->update_after_tempo_map_change (); } @@ -3812,7 +3814,7 @@ Session::ensure_buffers (ChanCount howmany) { if (current_block_size == 0) return; // too early? (is this ok?) - + // We need at least 2 MIDI scratch buffers to mix/merge if (howmany.n_midi() < 2) howmany.set_midi(2); @@ -3822,7 +3824,7 @@ Session::ensure_buffers (ChanCount howmany) _scratch_buffers->ensure_buffers(howmany, current_block_size); _mix_buffers->ensure_buffers(howmany, current_block_size); _silent_buffers->ensure_buffers(howmany, current_block_size); - + allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false); } @@ -3836,10 +3838,10 @@ Session::next_insert_id () if (!insert_bitset[n]) { insert_bitset[n] = true; return n; - + } } - + /* none available, so resize and try again */ insert_bitset.resize (insert_bitset.size() + 16, false); @@ -3856,10 +3858,10 @@ Session::next_send_id () if (!send_bitset[n]) { send_bitset[n] = true; return n; - + } } - + /* none available, so resize and try again */ send_bitset.resize (send_bitset.size() + 16, false); @@ -3907,7 +3909,7 @@ Session::named_selection_by_name (string name) void Session::add_named_selection (NamedSelection* named_selection) { - { + { Glib::Mutex::Lock lm (named_selection_lock); named_selections.insert (named_selections.begin(), named_selection); } @@ -3926,7 +3928,7 @@ Session::remove_named_selection (NamedSelection* named_selection) { bool removed = false; - { + { Glib::Mutex::Lock lm (named_selection_lock); NamedSelectionList::iterator i = find (named_selections.begin(), named_selections.end(), named_selection); @@ -3958,13 +3960,13 @@ bool Session::route_name_unique (string n) const { shared_ptr<RouteList> r = routes.reader (); - + for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->name() == n) { return false; } } - + return true; } @@ -3992,7 +3994,7 @@ Session::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, b } _pan_automation_buffer = new pan_t*[howmany]; - + for (uint32_t i = 0; i < howmany; ++i) { _pan_automation_buffer[i] = new pan_t[nframes]; } @@ -4021,7 +4023,7 @@ Session::freeze (InterThreadInfo& itt) } int -Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len, +Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len, bool overwrite, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt) { int ret = -1; @@ -4041,9 +4043,9 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le const nframes_t chunk_size = (128 * 1024)/4; g_atomic_int_set (&processing_prohibited, 1); - + /* call tree *MUST* hold route_lock */ - + if ((playlist = track.diskstream()->playlist()) == 0) { goto out; } @@ -4062,17 +4064,17 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le break; } } - + if (x == 99999) { error << string_compose (_("too many bounced versions of playlist \"%1\""), playlist->name()) << endmsg; goto out; } - + try { fsource = boost::dynamic_pointer_cast<AudioFileSource> ( SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate())); } - + catch (failed_constructor& err) { error << string_compose (_("cannot create new audio file \"%1\" for %2"), buf, track.name()) << endmsg; goto out; @@ -4082,7 +4084,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le } /* XXX need to flush all redirects */ - + position = start; to_do = len; @@ -4095,11 +4097,11 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le if (afs) afs->prepare_for_peakfile_writes (); } - + while (to_do && !itt.cancel) { - + this_chunk = min (to_do, chunk_size); - + if (track.export_stuff (buffers, start, this_chunk)) { goto out; } @@ -4107,45 +4109,45 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le uint32_t n = 0; for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src, ++n) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src); - + if (afs) { if (afs->write (buffers.get_audio(n).data(), this_chunk) != this_chunk) { goto out; } } } - + start += this_chunk; to_do -= this_chunk; - + itt.progress = (float) (1.0 - ((double) to_do / len)); } if (!itt.cancel) { - + time_t now; struct tm* xnow; time (&now); xnow = localtime (&now); - + for (vector<boost::shared_ptr<Source> >::iterator src=srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src); - + if (afs) { afs->update_header (position, *xnow, now); afs->flush_header (); } } - + /* construct a region to represent the bounced material */ - boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(), + boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(), region_name_from_path (srcs.front()->name(), true)); ret = 0; } - + out: if (ret) { for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) { @@ -4161,7 +4163,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le } else { for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) { boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src); - + if (afs) afs->done_with_peakfile_writes (); } @@ -4183,7 +4185,7 @@ Session::get_silent_buffers (ChanCount count) _silent_buffers->get(*t, i).clear(); } } - + return *_silent_buffers; } @@ -4203,7 +4205,7 @@ Session::get_mix_buffers (ChanCount count) return *_mix_buffers; } -uint32_t +uint32_t Session::ntracks () const { uint32_t n = 0; @@ -4218,7 +4220,7 @@ Session::ntracks () const return n; } -uint32_t +uint32_t Session::nbusses () const { uint32_t n = 0; diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index b4938636a2..a807c5e98b 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -1,6 +1,6 @@ /* - Copyright (C) 1999-2002 Paul Davis + Copyright (C) 1999-2002 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 @@ -94,8 +94,14 @@ Session::use_config_midi_ports () set_midi_port (""); } + if (default_midi_clock_port) { + set_midi_clock_port (default_midi_clock_port->name()); + } else { + set_midi_clock_port (""); + } + return 0; -} +} /*********************************************************************** @@ -190,7 +196,7 @@ Session::set_mmc_port (string port_tag) delete mmc; } - mmc = new MIDI::MachineControl (*_mmc_port, 1.0, + mmc = new MIDI::MachineControl (*_mmc_port, 1.0, MMC_CommandSignature, MMC_ResponseSignature); @@ -199,29 +205,29 @@ Session::set_mmc_port (string port_tag) mmc->set_send_device_id (old_send_device_id); } - mmc->Play.connect + mmc->Play.connect (mem_fun (*this, &Session::mmc_deferred_play)); - mmc->DeferredPlay.connect + mmc->DeferredPlay.connect (mem_fun (*this, &Session::mmc_deferred_play)); - mmc->Stop.connect + mmc->Stop.connect (mem_fun (*this, &Session::mmc_stop)); - mmc->FastForward.connect + mmc->FastForward.connect (mem_fun (*this, &Session::mmc_fast_forward)); - mmc->Rewind.connect + mmc->Rewind.connect (mem_fun (*this, &Session::mmc_rewind)); - mmc->Pause.connect + mmc->Pause.connect (mem_fun (*this, &Session::mmc_pause)); - mmc->RecordPause.connect + mmc->RecordPause.connect (mem_fun (*this, &Session::mmc_record_pause)); - mmc->RecordStrobe.connect + mmc->RecordStrobe.connect (mem_fun (*this, &Session::mmc_record_strobe)); - mmc->RecordExit.connect + mmc->RecordExit.connect (mem_fun (*this, &Session::mmc_record_exit)); - mmc->Locate.connect + mmc->Locate.connect (mem_fun (*this, &Session::mmc_locate)); - mmc->Step.connect + mmc->Step.connect (mem_fun (*this, &Session::mmc_step)); - mmc->Shuttle.connect + mmc->Shuttle.connect (mem_fun (*this, &Session::mmc_shuttle)); mmc->TrackRecordStatusChange.connect (mem_fun (*this, &Session::mmc_record_enable)); @@ -232,7 +238,7 @@ Session::set_mmc_port (string port_tag) _mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start)); _mmc_port->input()->contineu.connect (mem_fun (*this, &Session::spp_continue)); _mmc_port->input()->stop.connect (mem_fun (*this, &Session::spp_stop)); - + Config->set_mmc_port_name (port_tag); out: @@ -261,9 +267,9 @@ Session::set_midi_port (string port_tag) } _midi_port = port; - + /* XXX need something to forward this to control protocols ? or just - use the signal below + use the signal below */ Config->set_midi_port_name (port_tag); @@ -276,6 +282,52 @@ Session::set_midi_port (string port_tag) return 0; } +int +Session::set_midi_clock_port (string port_tag) +{ + MIDIClock_Slave *ms; + + if (port_tag.length() == 0) { + + if (_slave && ((ms = dynamic_cast<MIDIClock_Slave*> (_slave)) != 0)) { + error << _("Ardour is slaved to MIDI Clock - port cannot be reset") << endmsg; + return -1; + } + + if (_midi_clock_port == 0) { + return 0; + } + + _midi_clock_port = 0; + goto out; + } + + MIDI::Port* port; + + if ((port = MIDI::Manager::instance()->port (port_tag)) == 0) { + error << string_compose (_("unknown port %1 requested for MIDI Clock"), port_tag) << endl; + return -1; + } + + _midi_clock_port = port; + + if (_slave && ((ms = dynamic_cast<MIDIClock_Slave*> (_slave)) != 0)) { + ms->rebind (*port); + } + + Config->set_midi_clock_port_name (port_tag); + + _midi_clock_port->input()->start.connect (mem_fun (*this, &Session::midi_clock_start)); + _midi_clock_port->input()->contineu.connect (mem_fun (*this, &Session::midi_clock_continue)); + _midi_clock_port->input()->stop.connect (mem_fun (*this, &Session::midi_clock_stop)); + + out: + MIDIClock_PortChanged(); /* EMIT SIGNAL */ + change_midi_ports (); + set_dirty(); + return 0; +} + void Session::set_trace_midi_input (bool yn, MIDI::Port* port) { @@ -292,7 +344,7 @@ Session::set_trace_midi_input (bool yn, MIDI::Port* port) input_parser->trace (yn, &cout, "input: "); } } - + if (_mtc_port && _mtc_port != _mmc_port) { if ((input_parser = _mtc_port->input()) != 0) { input_parser->trace (yn, &cout, "input: "); @@ -324,7 +376,7 @@ Session::set_trace_midi_output (bool yn, MIDI::Port* port) output_parser->trace (yn, &cout, "output: "); } } - + if (_mtc_port && _mtc_port != _mmc_port) { if ((output_parser = _mtc_port->output()) != 0) { output_parser->trace (yn, &cout, "output: "); @@ -357,7 +409,7 @@ Session::get_trace_midi_input(MIDI::Port *port) return input_parser->tracing(); } } - + if (_mtc_port) { if ((input_parser = _mtc_port->input()) != 0) { return input_parser->tracing(); @@ -389,7 +441,7 @@ Session::get_trace_midi_output(MIDI::Port *port) return output_parser->tracing(); } } - + if (_mtc_port) { if ((output_parser = _mtc_port->output()) != 0) { return output_parser->tracing(); @@ -414,14 +466,14 @@ Session::setup_midi_control () next_quarter_frame_to_send = 0; /* setup the MMC buffer */ - + mmc_buffer[0] = 0xf0; // SysEx mmc_buffer[1] = 0x7f; // Real Time SysEx ID for MMC mmc_buffer[2] = (mmc ? mmc->send_device_id() : 0x7f); mmc_buffer[3] = 0x6; // MCC /* Set up the qtr frame message */ - + mtc_msg[0] = 0xf1; mtc_msg[2] = 0xf1; mtc_msg[4] = 0xf1; @@ -455,6 +507,28 @@ Session::spp_stop (Parser& ignored) } void +Session::midi_clock_start (Parser& ignored) +{ + if (Config->get_midi_clock_control() && (Config->get_slave_source() == MIDIClock)) { + request_transport_speed (1.0); + } +} + +void +Session::midi_clock_continue (Parser& ignored) +{ + midi_clock_start (ignored); +} + +void +Session::midi_clock_stop (Parser& ignored) +{ + if (Config->get_midi_clock_control()) { + request_stop (); + } +} + +void Session::mmc_deferred_play (MIDI::MachineControl &mmc) { if (Config->get_mmc_control() && (Config->get_slave_source() != MTC)) { @@ -473,7 +547,7 @@ Session::mmc_record_pause (MIDI::MachineControl &mmc) void Session::mmc_record_strobe (MIDI::MachineControl &mmc) { - if (!Config->get_mmc_control()) + if (!Config->get_mmc_control()) return; /* record strobe does an implicit "Play" command */ @@ -485,11 +559,11 @@ Session::mmc_record_strobe (MIDI::MachineControl &mmc) its not the same as maybe_enable_record() though, because that *can* switch to Recording, which we do not want. */ - + save_state ("", true); g_atomic_int_set (&_record_status, Enabled); RecordStateChanged (); /* EMIT SIGNAL */ - + request_transport_speed (1.0); } else { @@ -545,7 +619,7 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps) struct timeval diff = { 0, 0 }; gettimeofday (&now, 0); - + timersub (&now, &last_mmc_step, &diff); gettimeofday (&now, 0); @@ -554,10 +628,10 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps) if (last_mmc_step.tv_sec != 0 && (diff.tv_usec + (diff.tv_sec * 1000000)) < _engine.usecs_per_cycle()) { return; } - + double diff_secs = diff.tv_sec + (diff.tv_usec / 1000000.0); 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 */ step_speed = cur_speed; @@ -568,13 +642,13 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps) step_speed *= 0.25; #if 0 - cerr << "delta = " << diff_secs + cerr << "delta = " << diff_secs << " ct = " << _transport_speed << " steps = " << steps - << " new speed = " << cur_speed + << " new speed = " << cur_speed << " speed = " << step_speed << endl; -#endif +#endif request_transport_speed (step_speed); last_mmc_step = now; @@ -617,10 +691,10 @@ Session::mmc_locate (MIDI::MachineControl &mmc, const MIDI::byte* mmc_tc) 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 */ ); - + if (target_frame > max_frames) { target_frame = max_frames; } @@ -667,7 +741,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) RouteList::iterator i; boost::shared_ptr<RouteList> r = routes.reader(); - + for (i = r->begin(); i != r->end(); ++i) { AudioTrack *at; @@ -710,7 +784,7 @@ Session::send_full_time_code(nframes_t nframes) if (_mtc_port == 0 || !session_send_mtc) { return 0; } - + // Get smpte time for this transport frame sample_to_smpte(_transport_frame, smpte, true /* use_offset */, false /* no subframes */); @@ -763,31 +837,31 @@ Session::send_full_time_code(nframes_t nframes) */ int Session::send_midi_time_code_for_cycle(nframes_t nframes) -{ +{ assert (next_quarter_frame_to_send >= 0); assert (next_quarter_frame_to_send <= 7); - + if (_mtc_port == 0 || !session_send_mtc || transmitting_smpte_time.negative /*|| (next_quarter_frame_to_send < 0)*/ ) { // cerr << "(MTC) Not sending MTC\n"; return 0; } - + /* Duration of one quarter frame */ nframes_t quarter_frame_duration = ((long) _frames_per_smpte_frame) >> 2; - + // cerr << "(MTC) TR: " << _transport_frame << " - SF: " << outbound_mtc_smpte_frame // << " - NQ: " << next_quarter_frame_to_send << " - FD" << quarter_frame_duration << endl; - + // FIXME: this should always be true //assert((outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration)) // > _transport_frame); - + // Send quarter frames for this cycle while (_transport_frame + nframes > (outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration))) { - + // cerr << "(MTC) Next frame to send: " << next_quarter_frame_to_send << endl; switch (next_quarter_frame_to_send) { @@ -815,11 +889,11 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes) case 7: mtc_msg[1] = 0x70 | (((mtc_smpte_bits|transmitting_smpte_time.hours) & 0xf0) >> 4); break; - } - + } + const nframes_t msg_time = (outbound_mtc_smpte_frame + (quarter_frame_duration * next_quarter_frame_to_send)); - + // This message must fall within this block or something is broken assert(msg_time >= _transport_frame); assert(msg_time < _transport_frame + nframes); @@ -828,7 +902,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes) assert(out_stamp < nframes); if (_mtc_port->midimsg (mtc_msg, 2, out_stamp)) { - error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) + error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) << endmsg; return -1; } @@ -840,7 +914,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes) << ", qfm = " << next_quarter_frame_to_send << ", stamp = " << out_stamp << ", delta = " << _transport_frame + out_stamp - last_time << endl;*/ - + // Increment quarter frame counter next_quarter_frame_to_send++; @@ -849,7 +923,7 @@ Session::send_midi_time_code_for_cycle(nframes_t nframes) next_quarter_frame_to_send = 0; // Increment smpte time twice SMPTE::increment( transmitting_smpte_time ); - SMPTE::increment( transmitting_smpte_time ); + SMPTE::increment( transmitting_smpte_time ); // Re-calculate timing of first quarter frame //smpte_to_sample( transmitting_smpte_time, outbound_mtc_smpte_frame, true /* use_offset */, false ); outbound_mtc_smpte_frame += 8 * quarter_frame_duration; @@ -880,7 +954,7 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, nframes_t where) mmc_buffer[nbytes++] = cmd; // cerr << "delivering MMC, cmd = " << hex << (int) cmd << dec << endl; - + switch (cmd) { case MachineControl::cmdLocate: smpte_time_subframes (where, smpte); @@ -925,7 +999,7 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, nframes_t where) if (_mmc_port->midimsg (mmc_buffer, nbytes, 0)) { error << string_compose(_("MMC: cannot send command %1%2%3"), &hex, cmd, &dec) << endmsg; - } + } } } @@ -959,7 +1033,7 @@ Session::mmc_step_timeout () } /*--------------------------------------------------------------------------- - MIDI THREAD + MIDI THREAD ---------------------------------------------------------------------------*/ int @@ -995,9 +1069,9 @@ Session::terminate_midi_thread () MIDIRequest* request = new MIDIRequest; void* status; - + request->type = MIDIRequest::Quit; - + midi_requests.write (&request, 1); poke_midi_thread (); @@ -1042,14 +1116,14 @@ Session::midi_thread_work () memset (&rtparam, 0, sizeof (rtparam)); rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */ - + if ((x = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) { // do we care? not particularly. - } + } - /* set up the port vector; 4 is the largest possible size for now */ + /* set up the port vector; 5 is the largest possible size for now */ - ports.assign (4, (MIDI::Port*) 0); + ports.assign (5, (MIDI::Port*) 0); while (1) { @@ -1078,6 +1152,15 @@ Session::midi_thread_work () nfds++; } + cerr << "before handling midi clock port" << endl; + if (_midi_clock_port && (_midi_clock_port != _mmc_port || !Config->get_mmc_control()) && _midi_clock_port->selectable() >= 0) { + cerr << "inside handling midi clock port" << endl; + pfd[nfds].fd = _midi_clock_port->selectable(); + pfd[nfds].events = POLLIN|POLLHUP|POLLERR; + ports[nfds] = _midi_clock_port; + nfds++; + } + /* if we are using MMC control, we obviously have to listen the relevant port. */ @@ -1088,7 +1171,7 @@ Session::midi_thread_work () ports[nfds] = _midi_port; nfds++; } - + if (!midi_timeouts.empty()) { timeout = 100; /* 10msecs */ } else { @@ -1121,7 +1204,7 @@ Session::midi_thread_work () if (pfd[0].revents & POLLIN) { char foo[16]; - + // cerr << "MIDI request FIFO ready\n"; fds_ready++; @@ -1154,13 +1237,13 @@ Session::midi_thread_work () // cerr << "rebind\n"; restart = true; break; - + case MIDIRequest::Quit: delete request; pthread_exit_pbd (0); /*NOTREACHED*/ break; - + default: break; } @@ -1169,7 +1252,7 @@ Session::midi_thread_work () delete request; } - } + } if (restart) { continue; @@ -1182,7 +1265,7 @@ Session::midi_thread_work () // error << string_compose(_("Transport: error polling MIDI port %1 (revents =%2%3%4"), p, &hex, pfd[p].revents, &dec) << endmsg; break; } - + if (pfd[p].revents & POLLIN) { fds_ready++; ports[p]->parse (); @@ -1190,19 +1273,19 @@ Session::midi_thread_work () } /* timeout driven */ - + if (fds_ready < 2 && timeout != -1) { for (MidiTimeoutList::iterator i = midi_timeouts.begin(); i != midi_timeouts.end(); ) { - + MidiTimeoutList::iterator tmp; tmp = i; ++tmp; - + if (!(*i)()) { midi_timeouts.erase (i); } - + i = tmp; } } diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index c86a868e56..61a741d0fb 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2003 Paul Davis + Copyright (C) 1999-2003 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 @@ -55,7 +55,7 @@ Session::request_input_change_handling () if (!(_state_of_the_state & (InitialConnecting|Deletion))) { Event* ev = new Event (Event::InputConfigurationChange, Event::Add, Event::Immediate, 0, 0.0); queue_event (ev); - } + } } void @@ -112,7 +112,7 @@ Session::force_locate (nframes_t target_frame, bool with_roll) void Session::request_play_loop (bool yn) { - Event* ev; + Event* ev; Location *location = _locations.auto_loop_location(); if (location == 0 && yn) { @@ -135,7 +135,7 @@ void Session::realtime_stop (bool abort) { /* assume that when we start, we'll be moving forwards */ - + // FIXME: where should this really be? [DR] //send_full_time_code(); deliver_mmc (MIDI::MachineControl::cmdStop, _transport_frame); @@ -174,7 +174,7 @@ Session::realtime_stop (bool abort) disable_record (true); reset_slave_state (); - + _transport_speed = 0; if (Config->get_use_video_sync()) { @@ -221,7 +221,7 @@ Session::butler_transport_work () /* 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) { @@ -239,7 +239,7 @@ Session::butler_transport_work () } } } - + if (post_transport_work & PostTransportLocate) { non_realtime_locate (); } @@ -263,7 +263,7 @@ Session::butler_transport_work () if (post_transport_work & PostTransportAudition) { non_realtime_set_audition (); } - + g_atomic_int_dec_and_test (&butler_should_do_transport_work); } @@ -293,7 +293,7 @@ Session::non_realtime_overwrite (int on_entry, bool& finished) } } - + void Session::non_realtime_locate () { @@ -317,7 +317,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) saved = false; boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->get_captured_frames () != 0) { did_record = true; @@ -326,7 +326,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) } /* stop and locate are merged here because they share a lot of common stuff */ - + time (&xnow); now = localtime (&xnow); @@ -340,10 +340,10 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (did_record) { begin_reversible_command ("capture"); - + Location* loc = _locations.end_location(); bool change_end = false; - + if (_transport_frame < loc->end()) { /* stopped recording before current end */ @@ -353,15 +353,15 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* first capture for this session, move end back to where we are */ change_end = true; - } + } } else if (_transport_frame > loc->end()) { - + /* stopped recording after the current end, extend it */ change_end = true; } - + if (change_end) { XMLNode &before = loc->get_state(); loc->set_end(_transport_frame); @@ -376,7 +376,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->transport_stopped (*now, xnow, abort); } - + boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { @@ -384,25 +384,25 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) (*i)->set_pending_declick (0); } } - + if (did_record) { commit_reversible_command (); - } - + } + if (_engine.running()) { update_latency_compensation (true, abort); } - if ((Config->get_slave_source() == None && Config->get_auto_return()) || - (post_transport_work & PostTransportLocate) || + if ((Config->get_slave_source() == None && Config->get_auto_return()) || + (post_transport_work & PostTransportLocate) || (_requested_return_frame >= 0) || synced_to_jack()) { - + if (pending_locate_flush) { flush_all_inserts (); } - - if (((Config->get_slave_source() == None && Config->get_auto_return()) || + + if (((Config->get_slave_source() == None && Config->get_auto_return()) || synced_to_jack() || _requested_return_frame >= 0) && !(post_transport_work & PostTransportLocate)) { @@ -421,12 +421,12 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) if (synced_to_jack() && !play_loop) { do_locate = true; } - + if (do_locate) { // cerr << "non-realtimestop: transport locate to " << _transport_frame << endl; _engine.transport_locate (_transport_frame); } - } + } #ifndef LEAVE_TRANSPORT_UNADJUSTED } @@ -475,7 +475,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) RecordStateChanged (); /* emit signal */ #endif } - + if ((post_transport_work & PostTransportLocate) && get_record_enabled()) { /* capture start has been changed, so save pending state */ save_state ("", true); @@ -485,7 +485,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) /* always try to get rid of this */ remove_pending_capture_state (); - + /* save the current state of things if appropriate */ if (did_record && !saved) { @@ -496,11 +496,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) DurationChanged (); /* EMIT SIGNAL */ } - if (post_transport_work & PostTransportStop) { + if (post_transport_work & PostTransportStop) { _play_range = false; /* do not turn off autoloop on stop */ - + } nframes_t tf = _transport_frame; @@ -524,7 +524,7 @@ Session::check_declick_out () /* this is called after a process() iteration. if PendingDeclickOut was set, it means that we were waiting to declick the output (which has just been done) before doing something else. this is where we do that "something else". - + note: called from the audio thread. */ @@ -544,11 +544,11 @@ void Session::set_play_loop (bool yn) { /* Called from event-handling context */ - + if ((actively_recording() && yn) || _locations.auto_loop_location() == 0) { return; } - + set_dirty(); if (yn && Config->get_seamless_loop() && synced_to_jack()) { @@ -558,12 +558,12 @@ Session::set_play_loop (bool yn) return; } - + if ((play_loop = yn)) { Location *loc; - + if ((loc = _locations.auto_loop_location()) != 0) { if (Config->get_seamless_loop()) { @@ -584,9 +584,9 @@ Session::set_play_loop (bool yn) } } } - + /* stick in the loop event */ - + Event* event = new Event (Event::AutoLoop, Event::Replace, loc->end(), loc->start(), 0.0f); merge_event (event); @@ -614,7 +614,7 @@ Session::set_play_loop (bool yn) (*i)->set_loop (0); } } - + } } @@ -689,17 +689,17 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w pending_locate_roll = with_roll; pending_locate_flush = with_flush; return; - } + } } if (transport_rolling() && (!auto_play_legal || !Config->get_auto_play()) && !with_roll && !(synced_to_jack() && play_loop)) { realtime_stop (false); - } + } if ( !with_loop || loop_changing) { post_transport_work = PostTransportWork (post_transport_work | PostTransportLocate); - + if (with_roll) { post_transport_work = PostTransportWork (post_transport_work | PostTransportRoll); } @@ -711,13 +711,13 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w /* this is functionally what clear_clicks() does but with a tentative lock */ Glib::RWLock::WriterLock clickm (click_lock, Glib::TRY_LOCK); - + if (clickm.locked()) { - + for (Clicks::iterator i = clicks.begin(); i != clicks.end(); ++i) { delete *i; } - + clicks.clear (); } } @@ -752,7 +752,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w /* cancel looped playback if transport pos outside of loop range */ if (play_loop) { Location* al = _locations.auto_loop_location(); - + if (al && (_transport_frame < al->start() || _transport_frame > al->end())) { // cancel looping directly, this is called from event handling context set_play_loop (false); @@ -762,7 +762,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w // this is only necessary for seamless looping boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); - + for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { // tell it we've looped, so it can deal with the record state @@ -774,7 +774,7 @@ Session::locate (nframes_t target_frame, bool with_roll, bool with_flush, bool w TransportLooped(); // EMIT SIGNAL } } - + loop_changing = false; _send_smpte_update = true; @@ -808,7 +808,7 @@ Session::set_transport_speed (float speed, bool abort) for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->record_enabled ()) { //cerr << "switching to input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (true); + (*i)->monitor_input (true); } } } @@ -818,7 +818,7 @@ Session::set_transport_speed (float speed, bool abort) } else { stop_transport (abort); } - + } else if (transport_stopped() && speed == 1.0) { /* we are stopped and we want to start rolling at speed 1 */ @@ -834,7 +834,7 @@ Session::set_transport_speed (float speed, bool abort) for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (Config->get_auto_input() && (*i)->record_enabled ()) { //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl; - (*i)->monitor_input (false); + (*i)->monitor_input (false); } } } @@ -868,7 +868,7 @@ Session::set_transport_speed (float speed, bool abort) if (speed < 0.0f && _transport_frame == 0) { return; } - + clear_clicks (); /* if we are reversing relative to the current speed, or relative to the speed @@ -878,17 +878,17 @@ Session::set_transport_speed (float speed, bool abort) if ((_transport_speed && speed * _transport_speed < 0.0f) || (_last_transport_speed * speed < 0.0f) || (_last_transport_speed == 0.0f && speed < 0.0f)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportReverse); } - + _last_transport_speed = _transport_speed; _transport_speed = speed; - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if ((*i)->realtime_set_speed ((*i)->speed(), true)) { post_transport_work = PostTransportWork (post_transport_work | PostTransportSpeed); } } - + if (post_transport_work & (PostTransportSpeed|PostTransportReverse)) { schedule_butler_transport_work (); } @@ -903,11 +903,11 @@ Session::stop_transport (bool abort) if (_transport_speed == 0.0f) { return; } - - if (actively_recording() && !(transport_sub_state & StopPendingCapture) && - _worst_output_latency > current_block_size) + + if (actively_recording() && !(transport_sub_state & StopPendingCapture) && + _worst_output_latency > current_block_size) { - + /* we need to capture the audio that has still not yet been received by the system at the time the stop is requested, so we have to roll past that time. @@ -915,16 +915,16 @@ Session::stop_transport (bool abort) block before the actual end. we'll declick in the subsequent block, and then we'll really be stopped. */ - - Event *ev = new Event (Event::StopOnce, Event::Replace, + + Event *ev = new Event (Event::StopOnce, Event::Replace, _transport_frame + _worst_output_latency - current_block_size, 0, 0, abort); - + merge_event (ev); transport_sub_state |= StopPendingCapture; pending_abort = abort; return; - } + } if ((transport_sub_state & PendingDeclickOut) == 0) { @@ -944,7 +944,7 @@ Session::start_transport () _last_roll_location = _transport_frame; /* if record status is Enabled, move it to Recording. if its - already Recording, move it to Disabled. + already Recording, move it to Disabled. */ switch (record_status()) { @@ -978,7 +978,7 @@ Session::actually_start_transport () transport_sub_state |= PendingDeclickIn; _transport_speed = 1.0; - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { (*i)->realtime_set_speed ((*i)->speed(), true); @@ -1012,7 +1012,7 @@ Session::post_transport () if (((Config->get_slave_source() == None && (auto_play_legal && Config->get_auto_play())) && !_exporting) || (post_transport_work & PostTransportRoll)) { start_transport (); - + } else { transport_sub_state = 0; } @@ -1057,7 +1057,7 @@ Session::set_slave_source (SlaveSource src) // if (src == JACK && Config->get_jack_time_master()) { // return; // } - + if (_slave) { delete _slave; _slave = 0; @@ -1071,7 +1071,7 @@ Session::set_slave_source (SlaveSource src) case None: stop_transport (); break; - + case MTC: if (_mtc_port) { try { @@ -1088,15 +1088,33 @@ Session::set_slave_source (SlaveSource src) } _desired_transport_speed = _transport_speed; break; - + + case MIDIClock: + if (_midi_clock_port) { + try { + _slave = new MIDIClock_Slave (*this, *_midi_clock_port, 24); + } + + catch (failed_constructor& err) { + return; + } + + } else { + error << _("No MIDI Clock port defined: MIDI Clock slaving is impossible.") << endmsg; + return; + } + _desired_transport_speed = _transport_speed; + break; + case JACK: _slave = new JACK_Slave (_engine.jack()); _desired_transport_speed = _transport_speed; break; + }; Config->set_slave_source (src); - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { if (!(*i)->hidden()) { @@ -1174,7 +1192,7 @@ Session::setup_auto_play () /* Called from event-processing context */ Event* ev; - + _clear_event_type (Event::RangeStop); _clear_event_type (Event::RangeLocate); @@ -1183,48 +1201,48 @@ Session::setup_auto_play () } list<AudioRange>::size_type sz = current_audio_range.size(); - + if (sz > 1) { - - list<AudioRange>::iterator i = current_audio_range.begin(); + + list<AudioRange>::iterator i = current_audio_range.begin(); list<AudioRange>::iterator next; - + while (i != current_audio_range.end()) { - + next = i; ++next; - + /* locating/stopping is subject to delays for declicking. */ - + nframes_t requested_frame = (*i).end; - + if (requested_frame > current_block_size) { requested_frame -= current_block_size; } else { requested_frame = 0; } - + if (next == current_audio_range.end()) { ev = new Event (Event::RangeStop, Event::Add, requested_frame, 0, 0.0f); } else { ev = new Event (Event::RangeLocate, Event::Add, requested_frame, (*next).start, 0.0f); } - + merge_event (ev); - + i = next; } - + } else if (sz == 1) { - + ev = new Event (Event::RangeStop, Event::Add, current_audio_range.front().end, 0, 0.0f); merge_event (ev); - - } + + } /* now start rolling at the right place */ - + ev = new Event (Event::LocateRoll, Event::Add, Event::Immediate, current_audio_range.front().start, 0.0f, false); merge_event (ev); } @@ -1254,14 +1272,14 @@ Session::engine_halted () /* there will be no more calls to process(), so we'd better clean up for ourselves, right now. - but first, make sure the butler is out of + but first, make sure the butler is out of the picture. */ g_atomic_int_set (&butler_should_do_transport_work, 0); post_transport_work = PostTransportWork (0); stop_butler (); - + realtime_stop (false); non_realtime_stop (false, 0, ignored); transport_sub_state = 0; @@ -1282,7 +1300,7 @@ Session::xrun_recovery () */ engine_halted(); - } + } } void @@ -1299,15 +1317,15 @@ Session::update_latency_compensation (bool with_stop, bool abort) boost::shared_ptr<RouteList> r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - + if (with_stop) { - (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), + (*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate), (!(post_transport_work & PostTransportLocate) || pending_locate_flush)); } - + nframes_t old_latency = (*i)->signal_latency (); nframes_t track_latency = (*i)->update_total_latency (); - + if (old_latency != track_latency) { (*i)->update_port_total_latencies (); update_jack = true; @@ -1316,7 +1334,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) if (!(*i)->is_hidden() && ((*i)->active())) { _worst_track_latency = max (_worst_track_latency, track_latency); } - } + } if (update_jack) { _engine.update_total_latencies (); @@ -1330,7 +1348,7 @@ Session::update_latency_compensation (bool with_stop, bool abort) /* reflect any changes in latencies into capture offsets */ - + boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader(); for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) { diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index f30f568f9d..58443bd005 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2003 Paul Davis + Copyright (C) 2000-2003 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 @@ -50,7 +50,7 @@ using namespace std; using namespace PBD; using Glib::ustring; -ustring +ustring legalize_for_path (ustring str) { ustring::size_type pos; @@ -97,7 +97,7 @@ string bump_name_once(std::string name) char buf[32]; snprintf (buf, sizeof(buf), "%ld", version+1); - + newname = name.substr (0, period+1); newname += buf; } @@ -140,7 +140,7 @@ cmp_nocase (const string& s, const string& s2) { string::const_iterator p = s.begin(); string::const_iterator p2 = s2.begin(); - + while (p != s.end() && p2 != s2.end()) { if (toupper(*p) != toupper(*p2)) { return (toupper(*p) < toupper(*p2)) ? -1 : 1; @@ -148,7 +148,7 @@ cmp_nocase (const string& s, const string& s2) ++p; ++p2; } - + return (s2.size() == s.size()) ? 0 : (s.size() < s2.size()) ? -1 : 1; } @@ -171,12 +171,12 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi 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] == '.') && + + 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); } } @@ -184,7 +184,7 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi if (add_channel_suffix) { path += '%'; - + if (total > 2) { path += (char) ('a' + this_one); } else { @@ -193,7 +193,7 @@ region_name_from_path (ustring path, bool strip_channels, bool add_channel_suffi } return path; -} +} bool path_is_paired (ustring path, ustring& pair_base) @@ -207,7 +207,7 @@ path_is_paired (ustring path, ustring& pair_base) } /* remove filename suffixes etc. */ - + if ((pos = path.find_last_of ('.')) != string::npos) { path = path.substr (0, pos); } @@ -216,13 +216,13 @@ path_is_paired (ustring path, ustring& pair_base) /* look for possible channel identifier: "?R", "%R", ".L" etc. */ - if (len > 3 && (path[len-2] == '%' || 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])))) { - + pair_base = path.substr (0, len-2); return true; - } + } return false; } @@ -253,20 +253,20 @@ path_expand (ustring path) wordfree (&expansion); return ret; -#else +#else return path; #endif } #if defined(HAVE_COREAUDIO) || defined(HAVE_AUDIOUNITS) -string +string CFStringRefToStdString(CFStringRef stringRef) { - CFIndex size = - CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , + CFIndex size = + CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , kCFStringEncodingUTF8); char *buf = new char[size]; - + std::string result; if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) { @@ -285,11 +285,11 @@ compute_equal_power_fades (nframes_t nframes, float* in, float* out) step = 1.0/nframes; in[0] = 0.0f; - + for (nframes_t i = 1; i < nframes - 1; ++i) { in[i] = in[i-1] + step; } - + in[nframes-1] = 1.0; const float pan_law_attenuation = -3.0f; @@ -340,11 +340,15 @@ string_to_slave_source (string str) if (str == _("Internal")) { return None; } - + if (str == _("MTC")) { return MTC; } + if (str == _("MIDI Clock")) { + return MIDIClock; + } + if (str == _("JACK")) { return JACK; } @@ -363,11 +367,14 @@ slave_source_to_string (SlaveSource src) case MTC: return _("MTC"); - + + case MIDIClock: + return _("MIDI Clock"); + default: case None: return _("Internal"); - + } } @@ -449,7 +456,7 @@ meter_hold_to_float (MeterHold hold) } } -AutoState +AutoState ARDOUR::string_to_auto_state (std::string str) { if (str == X_("Off")) { @@ -467,7 +474,7 @@ ARDOUR::string_to_auto_state (std::string str) return Touch; } -string +string ARDOUR::auto_state_to_string (AutoState as) { /* to be used only for XML serialization, no i18n done */ @@ -491,7 +498,7 @@ ARDOUR::auto_state_to_string (AutoState as) return ""; } -AutoStyle +AutoStyle ARDOUR::string_to_auto_style (std::string str) { if (str == X_("Absolute")) { @@ -505,7 +512,7 @@ ARDOUR::string_to_auto_style (std::string str) return Trim; } -string +string ARDOUR::auto_style_to_string (AutoStyle as) { /* to be used only for XML serialization, no i18n done */ diff --git a/libs/midi++2/midi++/midnam_patch.h b/libs/midi++2/midi++/midnam_patch.h index 492eacd897..50c51b317f 100644 --- a/libs/midi++2/midi++/midnam_patch.h +++ b/libs/midi++2/midi++/midnam_patch.h @@ -19,22 +19,22 @@ class Patch : public PBD::Stateful { public: typedef std::list<MIDI::Event> PatchMidiCommands; - + Patch() {}; Patch(string a_number, string a_name) : _number(a_number), _name(a_name) {}; ~Patch() {}; - + const string& name() const { return _name; } void set_name(const string a_name) { _name = a_name; } - + const string& number() const { return _number; } void set_number(const string a_number) { _number = a_number; } - + const PatchMidiCommands& patch_midi_commands() const { return _patch_midi_commands; } - + XMLNode& get_state (void); int set_state (const XMLNode& a_node); - + private: string _number; string _name; @@ -45,19 +45,19 @@ class PatchBank : public PBD::Stateful { public: typedef std::list<Patch> PatchNameList; - + PatchBank() {}; virtual ~PatchBank() {}; PatchBank(string a_name) : _name(a_name) {}; - + const string& name() const { return _name; } - void set_name(const string a_name) { _name = a_name; } - + void set_name(const string a_name) { _name = a_name; } + const PatchNameList& patch_name_list() const { return _patch_name_list; } - + XMLNode& get_state (void); int set_state (const XMLNode& a_node); - + private: string _name; PatchNameList _patch_name_list; @@ -68,29 +68,41 @@ class ChannelNameSet : public PBD::Stateful public: typedef std::set<uint8_t> AvailableForChannels; typedef std::list<PatchBank> PatchBanks; - + ChannelNameSet() {}; virtual ~ChannelNameSet() {}; ChannelNameSet(string a_name) : _name(a_name) {}; - + const string& name() const { return _name; } - void set_name(const string a_name) { _name = a_name; } - + void set_name(const string a_name) { _name = a_name; } + const AvailableForChannels& available_for_channels() const { return _available_for_channels; } const PatchBanks& patch_banks() const { return _patch_banks; } - + XMLNode& get_state (void); int set_state (const XMLNode& a_node); - + private: string _name; AvailableForChannels _available_for_channels; PatchBanks _patch_banks; }; +class MIDINameDocument : public PBD::Stateful +{ +public: + MIDINameDocument() {}; + virtual ~MIDINameDocument() {}; -} + XMLNode& get_state (void); + int set_state (const XMLNode& a_node); + +private: + string _author; + +}; } +} #endif /*MIDNAM_PATCH_H_*/ diff --git a/libs/midi++2/midnam_patch.cc b/libs/midi++2/midnam_patch.cc index c103237d99..f149f2884b 100644 --- a/libs/midi++2/midnam_patch.cc +++ b/libs/midi++2/midnam_patch.cc @@ -7,19 +7,19 @@ namespace MIDI namespace Name { -XMLNode& +XMLNode& Patch::get_state (void) { XMLNode* node = new XMLNode("Patch"); node->add_property("Number", _number); node->add_property("Name", _name); XMLNode* commands = node->add_child("PatchMIDICommands"); - for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin(); + for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin(); event != _patch_midi_commands.end(); ++event) { commands->add_child_copy(*(event->to_xml())); } - + return *node; } @@ -35,22 +35,22 @@ Patch::set_state (const XMLNode& node) for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) { _patch_midi_commands.push_back(*(new Event(*(*i)))); } - + return 0; } -XMLNode& +XMLNode& PatchBank::get_state (void) { XMLNode* node = new XMLNode("PatchBank"); node->add_property("Name", _name); XMLNode* patch_name_list = node->add_child("PatchNameList"); - for (PatchNameList::iterator patch = _patch_name_list.begin(); + for (PatchNameList::iterator patch = _patch_name_list.begin(); patch != _patch_name_list.end(); ++patch) { patch_name_list->add_child_nocopy(patch->get_state()); } - + return *node; } @@ -67,38 +67,38 @@ PatchBank::set_state (const XMLNode& node) patch.set_state(*(*i)); _patch_name_list.push_back(patch); } - + return 0; } -XMLNode& +XMLNode& ChannelNameSet::get_state (void) { XMLNode* node = new XMLNode("ChannelNameSet"); node->add_property("Name", _name); - + XMLNode* available_for_channels = node->add_child("AvailableForChannels"); assert(available_for_channels); - + for (uint8_t channel = 0; channel < 16; ++channel) { XMLNode* available_channel = available_for_channels->add_child("AvailableChannel"); assert(available_channel); - + available_channel->add_property("Channel", (long) channel); - + if (_available_for_channels.find(channel) != _available_for_channels.end()) { - available_channel->add_property("Available", "true"); + available_channel->add_property("Available", "true"); } else { - available_channel->add_property("Available", "false"); + available_channel->add_property("Available", "false"); } } - - for (PatchBanks::iterator patch_bank = _patch_banks.begin(); + + for (PatchBanks::iterator patch_bank = _patch_banks.begin(); patch_bank != _patch_banks.end(); ++patch_bank) { node->add_child_nocopy(patch_bank->get_state()); } - + return *node; } @@ -120,17 +120,28 @@ ChannelNameSet::set_state (const XMLNode& node) _available_for_channels.insert(atoi((*i)->attribute_value().c_str())); } } - + if (node->name() == "PatchBank") { PatchBank bank; bank.set_state(*node); _patch_banks.push_back(bank); - } + } } - + return 0; } +int +MIDINameDocument::set_state(const XMLNode & a_node) +{ +} + +XMLNode& +MIDINameDocument::get_state(void) +{ +} + + } //namespace Name } //namespace MIDI |