Ardour  9.0-pre0-582-g084a23a80d
midi_model.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2016 David Robillard <d@drobilla.net>
3  * Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
4  * Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2015 AndrĂ© Nusser <andre.nusser@googlemail.com>
7  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #pragma once
25 
26 #include <deque>
27 #include <map>
28 #include <queue>
29 #include <utility>
30 
31 #include <glibmm/threads.h>
32 
33 #include "pbd/command.h"
34 
36 #include "ardour/automation_list.h"
38 #include "ardour/source.h"
39 #include "ardour/types.h"
40 #include "ardour/types.h"
41 #include "ardour/variant.h"
42 
43 #include "evoral/Note.h"
44 #include "evoral/Sequence.h"
45 
46 namespace PBD {
47  class HistoryOwner;
48 }
49 
50 namespace ARDOUR {
51 
52 class MidiSource;
53 class MidiStateTracker;
54 
62 class LIBARDOUR_API MidiModel : public AutomatableSequence<Temporal::Beats> {
63 public:
65 
67  MidiModel (MidiModel const & other, MidiSource&);
68 
70  public:
71 
72  DiffCommand (std::shared_ptr<MidiModel> m, const std::string& name);
73 
74  const std::string& name () const { return _name; }
75 
76  virtual void operator() () = 0;
77  virtual void undo () = 0;
78 
79  virtual int set_state (const XMLNode&, int version) = 0;
80  virtual XMLNode & get_state () const = 0;
81 
82  std::shared_ptr<MidiModel> model() const { return _model; }
83 
84  protected:
85  std::shared_ptr<MidiModel> _model;
86  const std::string _name;
87 
88  };
89 
91  public:
92 
93  NoteDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
94  NoteDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
95 
96  enum Property {
101  Channel
102  };
103 
104  void operator() ();
105  void undo ();
106 
107  int set_state (const XMLNode&, int version);
108  XMLNode & get_state () const;
109 
110  void add (const NotePtr note);
111  void remove (const NotePtr note);
112  void side_effect_remove (const NotePtr note);
113 
114  void change (const NotePtr note, Property prop, uint8_t new_value) {
115  change(note, prop, Variant(new_value));
116  }
117 
118  void change (const NotePtr note, Property prop, TimeType new_time) {
119  change(note, prop, Variant(new_time));
120  }
121 
122  void change (const NotePtr note, Property prop, const Variant& new_value);
123 
124  bool adds_or_removes() const {
125  return !_added_notes.empty() || !_removed_notes.empty();
126  }
127 
128  NoteDiffCommand& operator+= (const NoteDiffCommand& other);
129 
130  static Variant get_value (const NotePtr note, Property prop);
131 
133 
134  struct NoteChange {
137  uint32_t note_id;
140  };
141 
142  typedef std::list<NoteChange> ChangeList;
143  typedef std::list< std::shared_ptr< Evoral::Note<TimeType> > > NoteList;
144 
145  const ChangeList& changes() const { return _changes; }
146  const NoteList& added_notes() const { return _added_notes; }
147  const NoteList& removed_notes() const { return _removed_notes; }
148 
149  private:
153 
154  std::set<NotePtr> side_effect_removals;
155 
158 
159  XMLNode &marshal_note(const NotePtr note) const;
161  };
162 
163  /* Currently this class only supports changes of sys-ex time, but could be expanded */
165  public:
166  SysExDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
167  SysExDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
168 
169  enum Property {
171  };
172 
173  int set_state (const XMLNode&, int version);
174  XMLNode & get_state () const;
175 
177  void operator() ();
178  void undo ();
179 
180  void change (std::shared_ptr<Evoral::Event<TimeType> >, TimeType);
181 
182  private:
183  struct Change {
184  Change () : sysex_id (0) {}
185  std::shared_ptr<Evoral::Event<TimeType> > sysex;
186  gint sysex_id;
190  };
191 
192  typedef std::list<Change> ChangeList;
194 
195  std::list<SysExPtr> _removed;
196 
197  XMLNode & marshal_change (const Change &) const;
199  };
200 
202  public:
203  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const std::string &);
204  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const XMLNode &);
205 
206  int set_state (const XMLNode &, int version);
207  XMLNode & get_state () const;
208 
209  void operator() ();
210  void undo ();
211 
218 
219  enum Property {
223  Bank
224  };
225 
226  private:
227  struct Change {
230  gint patch_id;
232  union {
233  uint8_t old_channel;
234  int old_bank;
235  uint8_t old_program;
236  };
238  union {
239  uint8_t new_channel;
240  uint8_t new_program;
241  int new_bank;
242  };
243 
244  Change() : patch_id (-1) {}
245  };
246 
247  typedef std::list<Change> ChangeList;
249 
250  std::list<PatchChangePtr> _added;
251  std::list<PatchChangePtr> _removed;
252 
253  XMLNode & marshal_change (const Change &) const;
255 
258  };
259 
260  void create_mapping_stash (Temporal::Beats const & offset);
262 
269  MidiModel::NoteDiffCommand* new_note_diff_command (const std::string& name = "midi edit");
271  MidiModel::SysExDiffCommand* new_sysex_diff_command (const std::string& name = "midi edit");
272 
275 
283 
284  void apply_diff_command_as_commit (PBD::HistoryOwner* history, PBD::Command* cmd) { if (history) { apply_diff_command_as_commit (*history, cmd); } }
285 
292 
298 
299  bool sync_to_source (const Source::WriterLock& source_lock);
300 
301  bool write_to(std::shared_ptr<MidiSource> source,
302  const Source::WriterLock& source_lock);
303 
304  bool write_section_to(std::shared_ptr<MidiSource> source,
305  const Source::WriterLock& source_lock,
308  bool offset_events = false);
309 
310  // MidiModel doesn't use the normal AutomationList serialisation code
311  // since controller data is stored in the .mid
312  XMLNode& get_state() const;
313  int set_state(const XMLNode&) { return 0; }
314 
317 
318  std::shared_ptr<Evoral::Note<TimeType> > find_note (NotePtr);
320  std::shared_ptr<Evoral::Note<TimeType> > find_note (Evoral::event_id_t);
321  std::shared_ptr<Evoral::Event<TimeType> > find_sysex (Evoral::event_id_t);
322 
325 
326  std::shared_ptr<Evoral::Control> control_factory(const Evoral::Parameter& id);
327 
329  void transpose (NoteDiffCommand *, const NotePtr, int);
330 
331  void track_state (timepos_t const & when, MidiStateTracker&) const;
333 
334  protected:
335  int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
336 
337  protected:
338  friend class NoteDiffCommand;
339  friend class SysExDiffCommand;
341 
342  MidiSource& midi_source() const { return _midi_source; }
343 
344  private:
346  WriteLockImpl(Source::WriterLock* slock, Glib::Threads::RWLock& s, Glib::Threads::Mutex& c)
348  , source_lock (slock)
349  {}
351  delete source_lock;
352  }
354  };
355 
356 public:
358 
359 private:
360  friend class DeltaCommand;
361 
366 
368 
370 
373 
374  typedef std::map<void*,superclock_t> TempoMappingStash;
376 
377 };
378 
379 } /* namespace ARDOUR */
380 
381 
DiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
std::shared_ptr< MidiModel > _model
Definition: midi_model.h:85
const std::string _name
Definition: midi_model.h:86
std::shared_ptr< MidiModel > model() const
Definition: midi_model.h:82
const std::string & name() const
Definition: midi_model.h:74
virtual XMLNode & get_state() const =0
virtual int set_state(const XMLNode &, int version)=0
std::list< std::shared_ptr< Evoral::Note< TimeType > > > NoteList
Definition: midi_model.h:143
static Variant get_value(const NotePtr note, Property prop)
void side_effect_remove(const NotePtr note)
XMLNode & marshal_note(const NotePtr note) const
XMLNode & marshal_change(const NoteChange &) const
void add(const NotePtr note)
int set_state(const XMLNode &, int version)
void change(const NotePtr note, Property prop, const Variant &new_value)
NoteDiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.h:93
void remove(const NotePtr note)
const NoteList & removed_notes() const
Definition: midi_model.h:147
std::list< NoteChange > ChangeList
Definition: midi_model.h:142
NoteChange unmarshal_change(XMLNode *xml_note)
NoteDiffCommand(std::shared_ptr< MidiModel > m, const XMLNode &node)
const ChangeList & changes() const
Definition: midi_model.h:145
std::set< NotePtr > side_effect_removals
Definition: midi_model.h:154
NotePtr unmarshal_note(XMLNode *xml_note)
void change(const NotePtr note, Property prop, TimeType new_time)
Definition: midi_model.h:118
void change(const NotePtr note, Property prop, uint8_t new_value)
Definition: midi_model.h:114
const NoteList & added_notes() const
Definition: midi_model.h:146
static Variant::Type value_type(Property prop)
PatchChangeDiffCommand(std::shared_ptr< MidiModel >, const std::string &)
int set_state(const XMLNode &, int version)
std::list< PatchChangePtr > _removed
Definition: midi_model.h:251
std::list< PatchChangePtr > _added
Definition: midi_model.h:250
void change_channel(PatchChangePtr, uint8_t)
void change_bank(PatchChangePtr, int)
void change_program(PatchChangePtr, uint8_t)
void change_time(PatchChangePtr, TimeType)
XMLNode & marshal_patch_change(constPatchChangePtr) const
XMLNode & marshal_change(const Change &) const
PatchChangePtr unmarshal_patch_change(XMLNode *)
PatchChangeDiffCommand(std::shared_ptr< MidiModel >, const XMLNode &)
std::list< Change > ChangeList
Definition: midi_model.h:192
int set_state(const XMLNode &, int version)
std::list< SysExPtr > _removed
Definition: midi_model.h:195
SysExDiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.h:166
void change(std::shared_ptr< Evoral::Event< TimeType > >, TimeType)
XMLNode & marshal_change(const Change &) const
SysExDiffCommand(std::shared_ptr< MidiModel > m, const XMLNode &node)
void source_interpolation_changed(Evoral::Parameter const &, AutomationList::InterpolationStyle)
InsertMergePolicy insert_merge_policy() const
std::map< void *, superclock_t > TempoMappingStash
Definition: midi_model.h:374
bool write_section_to(std::shared_ptr< MidiSource > source, const Source::WriterLock &source_lock, Temporal::Beats begin=Temporal::Beats(), Temporal::Beats end=std::numeric_limits< Temporal::Beats >::max(), bool offset_events=false)
TempoMappingStash tempo_mapping_stash
Definition: midi_model.h:375
PBD::ScopedConnectionList _midi_source_connections
Definition: midi_model.h:369
std::shared_ptr< Evoral::Control > control_factory(const Evoral::Parameter &id)
void rebuild_from_mapping_stash(Temporal::Beats const &offset)
MidiSource & midi_source() const
Definition: midi_model.h:342
MidiModel::PatchChangeDiffCommand * new_patch_change_diff_command(const std::string &name="midi edit")
void source_automation_state_changed(Evoral::Parameter const &, AutoState)
void control_list_marked_dirty()
void apply_diff_command_only(PBD::Command *cmd)
void set_insert_merge_policy(InsertMergePolicy)
PBD::Signal< void(Temporal::timecnt_t)> ContentsShifted
Definition: midi_model.h:316
void apply_diff_command_as_commit(PBD::HistoryOwner &, PBD::Command *cmd)
int resolve_overlaps_unlocked(const NotePtr, void *arg=0)
MidiModel(MidiModel const &other, MidiSource &)
int set_state(const XMLNode &)
Definition: midi_model.h:313
void create_mapping_stash(Temporal::Beats const &offset)
InsertMergePolicy _insert_merge_policy
Definition: midi_model.h:372
WriteLock edit_lock()
Temporal::Beats TimeType
Definition: midi_model.h:64
PatchChangePtr find_patch_change(Evoral::event_id_t)
bool write_to(std::shared_ptr< MidiSource > source, const Source::WriterLock &source_lock)
PBD::Signal< void()> ContentsChanged
Definition: midi_model.h:315
MidiModel::NoteDiffCommand * new_note_diff_command(const std::string &name="midi edit")
void control_list_interpolation_changed(Evoral::Parameter const &, AutomationList::InterpolationStyle)
std::shared_ptr< Evoral::Event< TimeType > > find_sysex(Evoral::event_id_t)
void insert_silence_at_start(TimeType)
void automation_list_automation_state_changed(Evoral::Parameter const &, AutoState)
void apply_diff_command_as_subcommand(PBD::HistoryOwner &, PBD::Command *cmd)
MidiModel::SysExDiffCommand * new_sysex_diff_command(const std::string &name="midi edit")
void track_state(timepos_t const &when, MidiStateTracker &) const
void render(const ReadLock &lock, Evoral::EventSink< Temporal::Beats > &dst)
MidiModel(MidiSource &)
bool sync_to_source(const Source::WriterLock &source_lock)
std::shared_ptr< Evoral::Note< TimeType > > find_note(NotePtr)
MidiSource & _midi_source
Definition: midi_model.h:371
std::shared_ptr< Evoral::Note< TimeType > > find_note(Evoral::event_id_t)
void apply_diff_command_as_commit(PBD::HistoryOwner *history, PBD::Command *cmd)
Definition: midi_model.h:284
void transpose(NoteDiffCommand *, const NotePtr, int)
XMLNode & get_state() const
Glib::Threads::RWLock::WriterLock WriterLock
std::shared_ptr< PatchChange< Temporal::Beats > > PatchChangePtr
Definition: Sequence.h:205
std::shared_ptr< const PatchChange< Temporal::Beats > > constPatchChangePtr
Definition: Sequence.h:206
std::shared_ptr< Glib::Threads::RWLock::ReaderLock > ReadLock
Definition: Sequence.h:94
std::shared_ptr< Event< Temporal::Beats > > SysExPtr
Definition: Sequence.h:192
std::shared_ptr< Evoral::Note< Temporal::Beats > > NotePtr
Definition: Sequence.h:89
std::shared_ptr< WriteLockImpl > WriteLock
Definition: Sequence.h:95
Definition: xml++.h:114
GtkImageIconNameData name
Definition: gtkimage.h:6
#define LIBARDOUR_API
int32_t event_id_t
Definition: axis_view.h:42
SysExDiffCommand::Property property
Definition: midi_model.h:187
std::shared_ptr< Evoral::Event< TimeType > > sysex
Definition: midi_model.h:185
WriteLockImpl(Source::WriterLock *slock, Glib::Threads::RWLock &s, Glib::Threads::Mutex &c)
Definition: midi_model.h:346
Source::WriterLock * source_lock
Definition: midi_model.h:353
static Temporal::Beats max()
Definition: beats.h:300