Ardour  9.2-79-gba93f2fe52
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 "pbd/command.h"
32 #include "pbd/mutex.h"
33 
35 #include "ardour/automation_list.h"
37 #include "ardour/source.h"
38 #include "ardour/types.h"
39 #include "ardour/types.h"
40 #include "ardour/variant.h"
41 
42 #include "evoral/Note.h"
43 #include "evoral/Sequence.h"
44 
45 namespace PBD {
46  class HistoryOwner;
47 }
48 
49 namespace ARDOUR {
50 
51 class MidiSource;
52 class MidiStateTracker;
53 
61 class LIBARDOUR_API MidiModel : public AutomatableSequence<Temporal::Beats> {
62 public:
64 
66  MidiModel (MidiModel const & other, MidiSource&);
67 
69  public:
70 
71  DiffCommand (std::shared_ptr<MidiModel> m, const std::string& name);
72 
73  const std::string& name () const { return _name; }
74 
75  virtual void operator() () = 0;
76  virtual void undo () = 0;
77 
78  virtual int set_state (const XMLNode&, int version) = 0;
79  virtual XMLNode & get_state () const = 0;
80 
81  std::shared_ptr<MidiModel> model() const { return _model; }
82 
83  protected:
84  std::shared_ptr<MidiModel> _model;
85  const std::string _name;
86 
87  };
88 
90  public:
91  ShiftCommand (std::shared_ptr<MidiModel> m, std::string const & name, TimeType distance);
92  ShiftCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
93 
94  void operator() ();
95  void undo ();
96 
97  int set_state (const XMLNode&, int version);
98  XMLNode & get_state () const;
99 
100  private:
102  };
103 
105  public:
106 
107  NoteDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
108  NoteDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
109 
110  enum Property {
115  Channel
116  };
117 
118  void operator() ();
119  void undo ();
120 
121  int set_state (const XMLNode&, int version);
122  XMLNode & get_state () const;
123 
124  void add (const NotePtr note);
125  void remove (const NotePtr note);
126  void side_effect_remove (const NotePtr note);
127 
128  void change (const NotePtr note, Property prop, uint8_t new_value) {
129  change(note, prop, Variant(new_value));
130  }
131 
132  void change (const NotePtr note, Property prop, TimeType new_time) {
133  change(note, prop, Variant(new_time));
134  }
135 
136  void change (const NotePtr note, Property prop, const Variant& new_value);
137 
138  bool adds_or_removes() const {
139  return !_added_notes.empty() || !_removed_notes.empty();
140  }
141 
142  NoteDiffCommand& operator+= (const NoteDiffCommand& other);
143 
144  static Variant get_value (const NotePtr note, Property prop);
145 
147 
148  struct NoteChange {
151  uint32_t note_id;
154  };
155 
156  typedef std::list<NoteChange> ChangeList;
157  typedef std::list< std::shared_ptr< Evoral::Note<TimeType> > > NoteList;
158 
159  const ChangeList& changes() const { return _changes; }
160  const NoteList& added_notes() const { return _added_notes; }
161  const NoteList& removed_notes() const { return _removed_notes; }
162 
163  private:
167 
168  std::set<NotePtr> side_effect_removals;
169 
172 
173  XMLNode &marshal_note(const NotePtr note) const;
175  };
176 
177  /* Currently this class only supports changes of sys-ex time, but could be expanded */
179  public:
180  SysExDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
181  SysExDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
182 
183  enum Property {
185  };
186 
187  int set_state (const XMLNode&, int version);
188  XMLNode & get_state () const;
189 
191  void operator() ();
192  void undo ();
193 
194  void change (std::shared_ptr<Evoral::Event<TimeType> >, TimeType);
195 
196  private:
197  struct Change {
198  Change () : sysex_id (0) {}
199  std::shared_ptr<Evoral::Event<TimeType> > sysex;
200  gint sysex_id;
204  };
205 
206  typedef std::list<Change> ChangeList;
208 
209  std::list<SysExPtr> _removed;
210 
211  XMLNode & marshal_change (const Change &) const;
213  };
214 
216  public:
217  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const std::string &);
218  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const XMLNode &);
219 
220  int set_state (const XMLNode &, int version);
221  XMLNode & get_state () const;
222 
223  void operator() ();
224  void undo ();
225 
232 
233  enum Property {
237  Bank
238  };
239 
240  private:
241  struct Change {
244  gint patch_id;
246  union {
247  uint8_t old_channel;
248  int old_bank;
249  uint8_t old_program;
250  };
252  union {
253  uint8_t new_channel;
254  uint8_t new_program;
255  int new_bank;
256  };
257 
258  Change() : patch_id (-1) {}
259  };
260 
261  typedef std::list<Change> ChangeList;
263 
264  std::list<PatchChangePtr> _added;
265  std::list<PatchChangePtr> _removed;
266 
267  XMLNode & marshal_change (const Change &) const;
269 
272  };
273 
274  void create_mapping_stash (Temporal::Beats const & offset);
276 
283  MidiModel::NoteDiffCommand* new_note_diff_command (const std::string& name = "midi edit");
285  MidiModel::SysExDiffCommand* new_sysex_diff_command (const std::string& name = "midi edit");
286 
289 
297 
298  void apply_diff_command_as_commit (PBD::HistoryOwner* history, PBD::Command* cmd) { if (history) { apply_diff_command_as_commit (*history, cmd); } }
299 
306 
312 
313  bool sync_to_source (const Source::WriterLock& source_lock);
314 
315  bool write_to(std::shared_ptr<MidiSource> source,
316  const Source::WriterLock& source_lock);
317 
318  bool write_section_to(std::shared_ptr<MidiSource> source,
319  const Source::WriterLock& source_lock,
322  bool offset_events = false);
323 
324  // MidiModel doesn't use the normal AutomationList serialisation code
325  // since controller data is stored in the .mid
326  XMLNode& get_state() const;
327  int set_state(const XMLNode&) { return 0; }
328 
331 
332  std::shared_ptr<Evoral::Note<TimeType> > find_note (NotePtr);
334  std::shared_ptr<Evoral::Note<TimeType> > find_note (Evoral::event_id_t);
335  std::shared_ptr<Evoral::Event<TimeType> > find_sysex (Evoral::event_id_t);
336 
339 
340  std::shared_ptr<Evoral::Control> control_factory(const Evoral::Parameter& id);
341 
343  void transpose (NoteDiffCommand *, const NotePtr, int);
344 
345  void track_state (timepos_t const & when, MidiStateTracker&) const;
347 
348  protected:
349  int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
350 
351  protected:
352  friend class NoteDiffCommand;
353  friend class SysExDiffCommand;
355 
356  MidiSource& midi_source() const { return _midi_source; }
357 
358  private:
362  , source_lock (slock)
363  {}
365  delete source_lock;
366  }
368  };
369 
370 public:
372 
373 private:
374  friend class DeltaCommand;
375 
380 
382 
384 
387 
388  typedef std::map<void*,superclock_t> TempoMappingStash;
390 
391 };
392 
393 } /* namespace ARDOUR */
394 
395 
DiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
std::shared_ptr< MidiModel > _model
Definition: midi_model.h:84
const std::string _name
Definition: midi_model.h:85
std::shared_ptr< MidiModel > model() const
Definition: midi_model.h:81
const std::string & name() const
Definition: midi_model.h:73
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:157
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:107
void remove(const NotePtr note)
const NoteList & removed_notes() const
Definition: midi_model.h:161
std::list< NoteChange > ChangeList
Definition: midi_model.h:156
NoteChange unmarshal_change(XMLNode *xml_note)
NoteDiffCommand(std::shared_ptr< MidiModel > m, const XMLNode &node)
const ChangeList & changes() const
Definition: midi_model.h:159
std::set< NotePtr > side_effect_removals
Definition: midi_model.h:168
NotePtr unmarshal_note(XMLNode *xml_note)
void change(const NotePtr note, Property prop, TimeType new_time)
Definition: midi_model.h:132
void change(const NotePtr note, Property prop, uint8_t new_value)
Definition: midi_model.h:128
const NoteList & added_notes() const
Definition: midi_model.h:160
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:265
std::list< PatchChangePtr > _added
Definition: midi_model.h:264
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 &)
int set_state(const XMLNode &, int version)
ShiftCommand(std::shared_ptr< MidiModel > m, std::string const &name, TimeType distance)
ShiftCommand(std::shared_ptr< MidiModel > m, const XMLNode &node)
std::list< Change > ChangeList
Definition: midi_model.h:206
int set_state(const XMLNode &, int version)
std::list< SysExPtr > _removed
Definition: midi_model.h:209
SysExDiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.h:180
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:388
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:389
PBD::ScopedConnectionList _midi_source_connections
Definition: midi_model.h:383
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:356
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:330
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:327
void create_mapping_stash(Temporal::Beats const &offset)
InsertMergePolicy _insert_merge_policy
Definition: midi_model.h:386
WriteLock edit_lock()
Temporal::Beats TimeType
Definition: midi_model.h:63
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:329
void insert_silence_at_start(TimeType, PBD::HistoryOwner &)
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 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:385
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:298
void transpose(NoteDiffCommand *, const NotePtr, int)
XMLNode & get_state() const
std::shared_ptr< PBD::RWLock::ReaderLock > ReadLock
Definition: Sequence.h:95
std::shared_ptr< PatchChange< Temporal::Beats > > PatchChangePtr
Definition: Sequence.h:206
std::shared_ptr< const PatchChange< Temporal::Beats > > constPatchChangePtr
Definition: Sequence.h:207
std::shared_ptr< Event< Temporal::Beats > > SysExPtr
Definition: Sequence.h:193
std::shared_ptr< Evoral::Note< Temporal::Beats > > NotePtr
Definition: Sequence.h:90
std::shared_ptr< WriteLockImpl > WriteLock
Definition: Sequence.h:96
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:201
std::shared_ptr< Evoral::Event< TimeType > > sysex
Definition: midi_model.h:199
WriteLockImpl(Source::WriterLock *slock, PBD::RWLock &s, PBD::Mutex &c)
Definition: midi_model.h:360
Source::WriterLock * source_lock
Definition: midi_model.h:367
static Temporal::Beats max()
Definition: beats.h:300