Ardour  9.0-pre0-1159-gcb8dd39f31
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  ShiftCommand (std::shared_ptr<MidiModel> m, std::string const & name, TimeType distance);
93  ShiftCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
94 
95  void operator() ();
96  void undo ();
97 
98  int set_state (const XMLNode&, int version);
99  XMLNode & get_state () const;
100 
101  private:
103  };
104 
106  public:
107 
108  NoteDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
109  NoteDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
110 
111  enum Property {
116  Channel
117  };
118 
119  void operator() ();
120  void undo ();
121 
122  int set_state (const XMLNode&, int version);
123  XMLNode & get_state () const;
124 
125  void add (const NotePtr note);
126  void remove (const NotePtr note);
127  void side_effect_remove (const NotePtr note);
128 
129  void change (const NotePtr note, Property prop, uint8_t new_value) {
130  change(note, prop, Variant(new_value));
131  }
132 
133  void change (const NotePtr note, Property prop, TimeType new_time) {
134  change(note, prop, Variant(new_time));
135  }
136 
137  void change (const NotePtr note, Property prop, const Variant& new_value);
138 
139  bool adds_or_removes() const {
140  return !_added_notes.empty() || !_removed_notes.empty();
141  }
142 
143  NoteDiffCommand& operator+= (const NoteDiffCommand& other);
144 
145  static Variant get_value (const NotePtr note, Property prop);
146 
148 
149  struct NoteChange {
152  uint32_t note_id;
155  };
156 
157  typedef std::list<NoteChange> ChangeList;
158  typedef std::list< std::shared_ptr< Evoral::Note<TimeType> > > NoteList;
159 
160  const ChangeList& changes() const { return _changes; }
161  const NoteList& added_notes() const { return _added_notes; }
162  const NoteList& removed_notes() const { return _removed_notes; }
163 
164  private:
168 
169  std::set<NotePtr> side_effect_removals;
170 
173 
174  XMLNode &marshal_note(const NotePtr note) const;
176  };
177 
178  /* Currently this class only supports changes of sys-ex time, but could be expanded */
180  public:
181  SysExDiffCommand (std::shared_ptr<MidiModel> m, const std::string& name) : DiffCommand (m, name) {}
182  SysExDiffCommand (std::shared_ptr<MidiModel> m, const XMLNode& node);
183 
184  enum Property {
186  };
187 
188  int set_state (const XMLNode&, int version);
189  XMLNode & get_state () const;
190 
192  void operator() ();
193  void undo ();
194 
195  void change (std::shared_ptr<Evoral::Event<TimeType> >, TimeType);
196 
197  private:
198  struct Change {
199  Change () : sysex_id (0) {}
200  std::shared_ptr<Evoral::Event<TimeType> > sysex;
201  gint sysex_id;
205  };
206 
207  typedef std::list<Change> ChangeList;
209 
210  std::list<SysExPtr> _removed;
211 
212  XMLNode & marshal_change (const Change &) const;
214  };
215 
217  public:
218  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const std::string &);
219  PatchChangeDiffCommand (std::shared_ptr<MidiModel>, const XMLNode &);
220 
221  int set_state (const XMLNode &, int version);
222  XMLNode & get_state () const;
223 
224  void operator() ();
225  void undo ();
226 
233 
234  enum Property {
238  Bank
239  };
240 
241  private:
242  struct Change {
245  gint patch_id;
247  union {
248  uint8_t old_channel;
249  int old_bank;
250  uint8_t old_program;
251  };
253  union {
254  uint8_t new_channel;
255  uint8_t new_program;
256  int new_bank;
257  };
258 
259  Change() : patch_id (-1) {}
260  };
261 
262  typedef std::list<Change> ChangeList;
264 
265  std::list<PatchChangePtr> _added;
266  std::list<PatchChangePtr> _removed;
267 
268  XMLNode & marshal_change (const Change &) const;
270 
273  };
274 
275  void create_mapping_stash (Temporal::Beats const & offset);
277 
284  MidiModel::NoteDiffCommand* new_note_diff_command (const std::string& name = "midi edit");
286  MidiModel::SysExDiffCommand* new_sysex_diff_command (const std::string& name = "midi edit");
287 
290 
298 
299  void apply_diff_command_as_commit (PBD::HistoryOwner* history, PBD::Command* cmd) { if (history) { apply_diff_command_as_commit (*history, cmd); } }
300 
307 
313 
314  bool sync_to_source (const Source::WriterLock& source_lock);
315 
316  bool write_to(std::shared_ptr<MidiSource> source,
317  const Source::WriterLock& source_lock);
318 
319  bool write_section_to(std::shared_ptr<MidiSource> source,
320  const Source::WriterLock& source_lock,
323  bool offset_events = false);
324 
325  // MidiModel doesn't use the normal AutomationList serialisation code
326  // since controller data is stored in the .mid
327  XMLNode& get_state() const;
328  int set_state(const XMLNode&) { return 0; }
329 
332 
333  std::shared_ptr<Evoral::Note<TimeType> > find_note (NotePtr);
335  std::shared_ptr<Evoral::Note<TimeType> > find_note (Evoral::event_id_t);
336  std::shared_ptr<Evoral::Event<TimeType> > find_sysex (Evoral::event_id_t);
337 
340 
341  std::shared_ptr<Evoral::Control> control_factory(const Evoral::Parameter& id);
342 
344  void transpose (NoteDiffCommand *, const NotePtr, int);
345 
346  void track_state (timepos_t const & when, MidiStateTracker&) const;
348 
349  protected:
350  int resolve_overlaps_unlocked (const NotePtr, void* arg = 0);
351 
352  protected:
353  friend class NoteDiffCommand;
354  friend class SysExDiffCommand;
356 
357  MidiSource& midi_source() const { return _midi_source; }
358 
359  private:
361  WriteLockImpl(Source::WriterLock* slock, Glib::Threads::RWLock& s, Glib::Threads::Mutex& c)
363  , source_lock (slock)
364  {}
366  delete source_lock;
367  }
369  };
370 
371 public:
373 
374 private:
375  friend class DeltaCommand;
376 
381 
383 
385 
388 
389  typedef std::map<void*,superclock_t> TempoMappingStash;
391 
392 };
393 
394 } /* namespace ARDOUR */
395 
396 
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:158
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:108
void remove(const NotePtr note)
const NoteList & removed_notes() const
Definition: midi_model.h:162
std::list< NoteChange > ChangeList
Definition: midi_model.h:157
NoteChange unmarshal_change(XMLNode *xml_note)
NoteDiffCommand(std::shared_ptr< MidiModel > m, const XMLNode &node)
const ChangeList & changes() const
Definition: midi_model.h:160
std::set< NotePtr > side_effect_removals
Definition: midi_model.h:169
NotePtr unmarshal_note(XMLNode *xml_note)
void change(const NotePtr note, Property prop, TimeType new_time)
Definition: midi_model.h:133
void change(const NotePtr note, Property prop, uint8_t new_value)
Definition: midi_model.h:129
const NoteList & added_notes() const
Definition: midi_model.h:161
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:266
std::list< PatchChangePtr > _added
Definition: midi_model.h:265
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:207
int set_state(const XMLNode &, int version)
std::list< SysExPtr > _removed
Definition: midi_model.h:210
SysExDiffCommand(std::shared_ptr< MidiModel > m, const std::string &name)
Definition: midi_model.h:181
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:389
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:390
PBD::ScopedConnectionList _midi_source_connections
Definition: midi_model.h:384
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:357
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:331
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:328
void create_mapping_stash(Temporal::Beats const &offset)
InsertMergePolicy _insert_merge_policy
Definition: midi_model.h:387
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:330
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:386
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:299
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:202
std::shared_ptr< Evoral::Event< TimeType > > sysex
Definition: midi_model.h:200
WriteLockImpl(Source::WriterLock *slock, Glib::Threads::RWLock &s, Glib::Threads::Mutex &c)
Definition: midi_model.h:361
Source::WriterLock * source_lock
Definition: midi_model.h:368
static Temporal::Beats max()
Definition: beats.h:300