X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fardour%2Fmidi_model.h;h=dc1c7af0e9796daf97c14a29e06f567543bbbea7;hb=c96ec968c7bb4b1d7c358f522a49b0685c022920;hp=f879c201eecd6743a61d65fe636c6d0e61d3e04c;hpb=ecb0cd5d119d28092a8f48e4521ac5eba197bb54;p=ardour.git diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index f879c201ee..dc1c7af0e9 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -1,6 +1,6 @@ /* Copyright (C) 2007 Paul Davis - Author: Dave Robillard + Author: David Robillard 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 @@ -25,12 +25,14 @@ #include #include #include -#include +#include #include "pbd/command.h" +#include "ardour/libardour_visibility.h" #include "ardour/types.h" #include "ardour/midi_buffer.h" #include "ardour/midi_ring_buffer.h" #include "ardour/automatable_sequence.h" +#include "ardour/libardour_visibility.h" #include "ardour/types.h" #include "evoral/Note.hpp" #include "evoral/Sequence.hpp" @@ -47,17 +49,42 @@ class MidiSource; * Because of this MIDI controllers and automatable controllers/widgets/etc * are easily interchangeable. */ -class MidiModel : public AutomatableSequence { +class LIBARDOUR_API MidiModel : public AutomatableSequence { public: typedef Evoral::MusicalTime TimeType; - MidiModel(MidiSource* s); + MidiModel (boost::shared_ptr); NoteMode note_mode() const { return (percussive() ? Percussive : Sustained); } void set_note_mode(NoteMode mode) { set_percussive(mode == Percussive); }; - class DiffCommand : public Command { + class LIBARDOUR_API DiffCommand : public Command { public: + + DiffCommand (boost::shared_ptr m, const std::string& name); + + const std::string& name () const { return _name; } + + virtual void operator() () = 0; + virtual void undo () = 0; + + virtual int set_state (const XMLNode&, int version) = 0; + virtual XMLNode & get_state () = 0; + + boost::shared_ptr model() const { return _model; } + + protected: + boost::shared_ptr _model; + const std::string _name; + + }; + + class LIBARDOUR_API NoteDiffCommand : public DiffCommand { + public: + + NoteDiffCommand (boost::shared_ptr m, const std::string& name) : DiffCommand (m, name) {} + NoteDiffCommand (boost::shared_ptr m, const XMLNode& node); + enum Property { NoteNumber, Velocity, @@ -66,38 +93,31 @@ public: Channel }; - DiffCommand (boost::shared_ptr m, const std::string& name); - DiffCommand (boost::shared_ptr m, const XMLNode& node); - - const std::string& name() const { return _name; } - - void operator()(); - void undo(); + void operator() (); + void undo (); int set_state (const XMLNode&, int version); - XMLNode& get_state (); + XMLNode & get_state (); void add (const NotePtr note); void remove (const NotePtr note); - void side_effect_remove (const NotePtr note); + void side_effect_remove (const NotePtr note); void change (const NotePtr note, Property prop, uint8_t new_value); void change (const NotePtr note, Property prop, TimeType new_time); - bool adds_or_removes() const { - return !_added_notes.empty() || !_removed_notes.empty(); - } - - DiffCommand& operator+= (const DiffCommand& other); - boost::shared_ptr model() const { return _model; } + bool adds_or_removes() const { + return !_added_notes.empty() || !_removed_notes.empty(); + } - private: - boost::shared_ptr _model; - const std::string _name; + NoteDiffCommand& operator+= (const NoteDiffCommand& other); + private: struct NoteChange { - DiffCommand::Property property; + NoteDiffCommand::Property property; NotePtr note; + uint32_t note_id; + union { uint8_t old_value; TimeType old_time; @@ -115,7 +135,7 @@ public: NoteList _added_notes; NoteList _removed_notes; - std::set side_effect_removals; + std::set side_effect_removals; XMLNode &marshal_change(const NoteChange&); NoteChange unmarshal_change(XMLNode *xml_note); @@ -124,13 +144,111 @@ public: NotePtr unmarshal_note(XMLNode *xml_note); }; - MidiModel::DiffCommand* new_diff_command(const std::string name="midi edit"); - void apply_command(Session& session, Command* cmd); - void apply_command_as_subcommand(Session& session, Command* cmd); + /* Currently this class only supports changes of sys-ex time, but could be expanded */ + class LIBARDOUR_API SysExDiffCommand : public DiffCommand { + public: + SysExDiffCommand (boost::shared_ptr m, const XMLNode& node); + + enum Property { + Time, + }; + + int set_state (const XMLNode&, int version); + XMLNode & get_state (); + + void remove (SysExPtr sysex); + void operator() (); + void undo (); + void change (boost::shared_ptr >, TimeType); + + private: + struct Change { + boost::shared_ptr > sysex; + gint sysex_id; + SysExDiffCommand::Property property; + TimeType old_time; + TimeType new_time; + }; + + typedef std::list ChangeList; + ChangeList _changes; + + std::list _removed; + + XMLNode & marshal_change (const Change &); + Change unmarshal_change (XMLNode *); + }; + + class LIBARDOUR_API PatchChangeDiffCommand : public DiffCommand { + public: + PatchChangeDiffCommand (boost::shared_ptr, const std::string &); + PatchChangeDiffCommand (boost::shared_ptr, const XMLNode &); + + int set_state (const XMLNode &, int version); + XMLNode & get_state (); + + void operator() (); + void undo (); + + void add (PatchChangePtr); + void remove (PatchChangePtr); + void change_time (PatchChangePtr, TimeType); + void change_channel (PatchChangePtr, uint8_t); + void change_program (PatchChangePtr, uint8_t); + void change_bank (PatchChangePtr, int); + + enum Property { + Time, + Channel, + Program, + Bank + }; + + private: + struct Change { + PatchChangePtr patch; + Property property; + gint patch_id; + union { + TimeType old_time; + uint8_t old_channel; + int old_bank; + uint8_t old_program; + }; + union { + uint8_t new_channel; + TimeType new_time; + uint8_t new_program; + int new_bank; + }; + + Change() : patch_id (-1) {} + }; + + typedef std::list ChangeList; + ChangeList _changes; + + std::list _added; + std::list _removed; + + XMLNode & marshal_change (const Change &); + Change unmarshal_change (XMLNode *); + + XMLNode & marshal_patch_change (constPatchChangePtr); + PatchChangePtr unmarshal_patch_change (XMLNode *); + }; + + MidiModel::NoteDiffCommand* new_note_diff_command (const std::string name = "midi edit"); + MidiModel::SysExDiffCommand* new_sysex_diff_command (const std::string name = "midi edit"); + MidiModel::PatchChangeDiffCommand* new_patch_change_diff_command (const std::string name = "midi edit"); + void apply_command (Session& session, Command* cmd); + void apply_command_as_subcommand (Session& session, Command* cmd); + + bool sync_to_source (); bool write_to(boost::shared_ptr source); - bool write_section_to(boost::shared_ptr source, Evoral::MusicalTime begin = Evoral::MinMusicalTime, - Evoral::MusicalTime end = Evoral::MaxMusicalTime); + bool write_section_to (boost::shared_ptr source, Evoral::MusicalTime begin = Evoral::MinMusicalTime, + Evoral::MusicalTime end = Evoral::MaxMusicalTime); // MidiModel doesn't use the normal AutomationList serialisation code // since controller data is stored in the .mid @@ -139,42 +257,61 @@ public: PBD::Signal0 ContentsChanged; - const MidiSource* midi_source() const { return _midi_source; } - void set_midi_source (MidiSource *); + boost::shared_ptr midi_source (); + void set_midi_source (boost::shared_ptr); boost::shared_ptr > find_note (NotePtr); + PatchChangePtr find_patch_change (Evoral::event_id_t); + boost::shared_ptr > find_note (gint note_id); + boost::shared_ptr > find_sysex (gint); + + InsertMergePolicy insert_merge_policy () const; + void set_insert_merge_policy (InsertMergePolicy); + + boost::shared_ptr control_factory(const Evoral::Parameter& id); - InsertMergePolicy insert_merge_policy () const; - void set_insert_merge_policy (InsertMergePolicy); + void insert_silence_at_start (TimeType); + void transpose (TimeType, TimeType, int); protected: - int resolve_overlaps_unlocked (const NotePtr, void* arg = 0); + int resolve_overlaps_unlocked (const NotePtr, void* arg = 0); private: struct WriteLockImpl : public AutomatableSequence::WriteLockImpl { - WriteLockImpl(Glib::Mutex::Lock* source_lock, Glib::RWLock& s, Glib::Mutex& c) + WriteLockImpl(Glib::Threads::Mutex::Lock* slock, Glib::Threads::RWLock& s, Glib::Threads::Mutex& c) : AutomatableSequence::WriteLockImpl(s, c) - , source_lock(source_lock) + , source_lock (slock) {} ~WriteLockImpl() { delete source_lock; } - Glib::Mutex::Lock* source_lock; + Glib::Threads::Mutex::Lock* source_lock; }; public: - virtual WriteLock edit_lock(); - virtual WriteLock write_lock(); + WriteLock edit_lock(); + WriteLock write_lock(); private: friend class DeltaCommand; + void source_interpolation_changed (Evoral::Parameter, Evoral::ControlList::InterpolationStyle); + void source_automation_state_changed (Evoral::Parameter, AutoState); + void control_list_interpolation_changed (Evoral::Parameter, Evoral::ControlList::InterpolationStyle); + void automation_list_automation_state_changed (Evoral::Parameter, AutoState); + + void control_list_marked_dirty (); + + PBD::ScopedConnectionList _midi_source_connections; + // We cannot use a boost::shared_ptr here to avoid a retain cycle - MidiSource* _midi_source; - InsertMergePolicy _insert_merge_policy; + boost::weak_ptr _midi_source; + InsertMergePolicy _insert_merge_policy; }; } /* namespace ARDOUR */ +/* This is a very long comment and stuff oh my god it's so long what are we going to do oh no oh no*/ + #endif /* __ardour_midi_model_h__ */