Audacity  2.2.0
NoteTrack.h
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  NoteTrack.h
6 
7  Dominic Mazzoni
8 
9 **********************************************************************/
10 
11 #ifndef __AUDACITY_NOTETRACK__
12 #define __AUDACITY_NOTETRACK__
13 
14 #include <utility>
15 #include <wx/string.h>
16 #include "Audacity.h"
17 #include "Experimental.h"
18 #include "Track.h"
19 #include "effects/TimeWarper.h"
20 
21 #if defined(USE_MIDI)
22 
23 #include "allegro.h"
24 
25 // define this switch to play MIDI during redisplay to sonify run times
26 // Note that if SONIFY is defined, the default MIDI device will be opened
27 // and may block normal MIDI playback.
28 //#define SONIFY 1
29 
30 #ifdef SONIFY
31 
32 #define SONFNS(name) \
33  void Begin ## name(); \
34  void End ## name();
35 
36 SONFNS(NoteBackground)
37 SONFNS(NoteForeground)
38 SONFNS(Measures)
39 SONFNS(Serialize)
40 SONFNS(Unserialize)
41 SONFNS(ModifyState)
42 SONFNS(AutoSave)
43 
44 #undef SONFNS
45 
46 #endif
47 
48 class wxDC;
49 class wxRect;
50 
51 class DirManager;
52 class Alg_seq; // from "allegro.h"
53 
54 using NoteTrackBase =
55 #ifdef EXPERIMENTAL_MIDI_OUT
57 #else
59 #endif
60  ;
61 
62 using QuantizedTimeAndBeat = std::pair< double, double >;
63 
64 class StretchHandle;
65 
66 class AUDACITY_DLL_API NoteTrack final
67  : public NoteTrackBase
68 {
69  public:
70  NoteTrack(const std::shared_ptr<DirManager> &projDirManager);
71  virtual ~NoteTrack();
72 
73  std::vector<UIHandlePtr> DetailedHitTest
74  (const TrackPanelMouseState &state,
75  const AudacityProject *pProject, int currentTool, bool bMultiTool)
76  override;
77 
78  using Holder = std::unique_ptr<NoteTrack>;
79  Track::Holder Duplicate() const override;
80 
81  int GetKind() const override { return Note; }
82 
83  double GetOffset() const override;
84  double GetStartTime() const override;
85  double GetEndTime() const override;
86 
87  void SetHeight(int h) override;
88 
89  Alg_seq &GetSeq() const;
90 
91  void WarpAndTransposeNotes(double t0, double t1,
92  const TimeWarper &warper, double semitones);
93 
94  static void DrawLabelControls
95  ( const NoteTrack *pTrack, wxDC & dc, const wxRect &rect,
96  int highlightedChannel = -1 );
97  int FindChannel(const wxRect &rect, int mx, int my);
98  bool LabelClick(const wxRect &rect, int x, int y, bool right);
99 
100  void SetSequence(std::unique_ptr<Alg_seq> &&seq);
101  void PrintSequence();
102 
103  Alg_seq *MakeExportableSeq(std::unique_ptr<Alg_seq> &cleanup) const;
104  bool ExportMIDI(const wxString &f) const;
105  bool ExportAllegro(const wxString &f) const;
106 
107  // High-level editing
108  Track::Holder Cut (double t0, double t1) override;
109  Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override;
110  bool Trim (double t0, double t1) /* not override */;
111  void Clear(double t0, double t1) override;
112  void Paste(double t, const Track *src) override;
113  void Silence(double t0, double t1) override;
114  void InsertSilence(double t, double len) override;
115  bool Shift(double t) /* not override */;
116 
117 #ifdef EXPERIMENTAL_MIDI_OUT
118  float GetVelocity() const { return mVelocity; }
119  void SetVelocity(float velocity) { mVelocity = velocity; }
120 #endif
121 
122  QuantizedTimeAndBeat NearestBeatTime( double time ) const;
123  bool StretchRegion
124  ( QuantizedTimeAndBeat t0, QuantizedTimeAndBeat t1, double newDur );
125 
126  int GetBottomNote() const { return mBottomNote; }
127  int GetPitchHeight(int factor) const
128  { return std::max(1, (int)(factor * mPitchHeight)); }
129  void SetPitchHeight(int rectHeight, float h)
130  {
131  // Impose certain zoom limits
132  auto octavePadding = 2 * 10; // 10 octaves times 2 single-pixel seperations per pixel
133  auto availableHeight = rectHeight - octavePadding;
134  auto numNotes = 128.f;
135  auto minSpacePerNote =
136  std::max((float)MinPitchHeight, availableHeight / numNotes);
137  mPitchHeight =
138  std::max(minSpacePerNote,
139  std::min((float)MaxPitchHeight, h));
140  }
142  void ZoomOut(const wxRect &rect, int y) { Zoom(rect, y, 1.0f / ZoomStep, true); }
144  void ZoomIn(const wxRect &rect, int y) { Zoom(rect, y, ZoomStep, true); }
147  void Zoom(const wxRect &rect, int y, float multiplier, bool center);
148  void ZoomTo(const wxRect &rect, int start, int end);
149  int GetNoteMargin(int height) const
150  { return std::min(height / 4, (GetPitchHeight(1) + 1) / 2); }
151  int GetOctaveHeight() const { return GetPitchHeight(12) + 2; }
152  // call this once before a series of calls to IPitchToY(). It
153  // sets mBottom to offset of octave 0 so that mBottomNote
154  // is located at r.y + r.height - (GetNoteMargin() + 1 + GetPitchHeight())
155  void PrepareIPitchToY(const wxRect &r) const {
156  mBottom =
157  r.y + r.height - GetNoteMargin(r.height) - 1 - GetPitchHeight(1) +
158  (mBottomNote / 12) * GetOctaveHeight() +
159  GetNotePos(mBottomNote % 12);
160  }
161  // IPitchToY returns Y coordinate of top of pitch p
162  int IPitchToY(int p) const {
163  return mBottom - (p / 12) * GetOctaveHeight() - GetNotePos(p % 12);
164  }
165  // compute the window coordinate of the bottom of an octave: This is
166  // the bottom of the line separating B and C.
167  int GetOctaveBottom(int oct) const {
168  return IPitchToY(oct * 12) + GetPitchHeight(1) + 1;
169  }
170  // Y coordinate for given floating point pitch (rounded to int)
171  int PitchToY(double p) const {
172  return IPitchToY((int) (p + 0.5));
173  }
174  // Integer pitch corresponding to a Y coordinate
175  int YToIPitch(int y);
176  // map pitch class number (0-11) to pixel offset from bottom of octave
177  // (the bottom of the black line between B and C) to the top of the
178  // note. Note extra pixel separates B(11)/C(0) and E(4)/F(5).
179  int GetNotePos(int p) const
180  { return 1 + GetPitchHeight(p + 1) + (p > 4); }
181  // get pixel offset to top of ith black key note
182  int GetBlackPos(int i) const { return GetNotePos(i * 2 + 1 + (i > 1)); }
183  // GetWhitePos tells where to draw lines between keys as an offset from
184  // GetOctaveBottom. GetWhitePos(0) returns 1, which matches the location
185  // of the line separating B and C
186  int GetWhitePos(int i) const { return 1 + (i * GetOctaveHeight()) / 7; }
187  void SetBottomNote(int note)
188  {
189  if (note < 0)
190  note = 0;
191  else if (note > 96)
192  note = 96;
193 
194  mBottomNote = note;
195  }
196 
197 #if 0
198  // Vertical scrolling is performed by dragging the keyboard at
199  // left of track. Protocol is call StartVScroll, then update by
200  // calling VScroll with original and final mouse position.
201  // These functions are not used -- instead, zooming/dragging works like
202  // audio track zooming/dragging. The vertical scrolling is nice however,
203  // so I left these functions here for possible use in the future.
204  void StartVScroll();
205  void VScroll(int start, int end);
206 #endif
207 
208  bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
209  XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
210  void WriteXML(XMLWriter &xmlFile) const override;
211 
212  // channels are numbered as integers 0-15, visible channels
213  // (mVisibleChannels) is a bit set. Channels are displayed as
214  // integers 1-16.
215 
216  // Allegro's data structure does not restrict channels to 16.
217  // Since there is not way to select more than 16 channels,
218  // map all channel numbers mod 16. This will have no effect
219  // on MIDI files, but it will allow users to at least select
220  // all channels on non-MIDI event sequence data.
221 #define NUM_CHANNELS 16
222  // Bitmask with all NUM_CHANNELS bits set
223 #define ALL_CHANNELS (1 << NUM_CHANNELS) - 1
224 #define CHANNEL_BIT(c) (1 << (c % NUM_CHANNELS))
225  bool IsVisibleChan(int c) const {
226  return (mVisibleChannels & CHANNEL_BIT(c)) != 0;
227  }
228  void SetVisibleChan(int c) { mVisibleChannels |= CHANNEL_BIT(c); }
229  void ClearVisibleChan(int c) { mVisibleChannels &= ~CHANNEL_BIT(c); }
230  void ToggleVisibleChan(int c) { mVisibleChannels ^= CHANNEL_BIT(c); }
231  // Solos the given channel. If it's the only channel visible, all channels
232  // are enabled; otherwise, it is set to the only visible channel.
233  void SoloVisibleChan(int c) {
234  if (mVisibleChannels == CHANNEL_BIT(c))
235  mVisibleChannels = ALL_CHANNELS;
236  else
237  mVisibleChannels = CHANNEL_BIT(c);
238  }
239 
240  private:
241  void AddToDuration( double delta );
242 
243  // These are mutable to allow NoteTrack to switch details of representation
244  // in logically const methods
245  // At most one of the two pointers is not null at any time.
246  // Both are null in a newly constructed NoteTrack.
247  mutable std::unique_ptr<Alg_seq> mSeq;
248  mutable std::unique_ptr<char[]> mSerializationBuffer;
249  mutable long mSerializationLength;
250 
251 #ifdef EXPERIMENTAL_MIDI_OUT
252  float mVelocity; // velocity offset
253 #endif
254 
255  // mBottom is the Y offset of pitch 0 (normally off screen)
256  mutable int mBottom;
257  int mBottomNote;
258  int mStartBottomNote;
259 
260  // Remember continuous variation for zooming,
261  // but it is rounded off whenever drawing:
262  float mPitchHeight;
263 
264  enum { MinPitchHeight = 1, MaxPitchHeight = 25 };
265  static const float ZoomStep;
266 
267  int mVisibleChannels; // bit set of visible channels
268 
269  std::weak_ptr<StretchHandle> mStretchHandle;
270 
271 protected:
272  std::shared_ptr<TrackControls> GetControls() override;
273  std::shared_ptr<TrackVRulerControls> GetVRulerControls() override;
274 };
275 
276 #endif // USE_MIDI
277 
278 #ifndef SONIFY
279 // no-ops:
280 #define SonifyBeginSonification()
281 #define SonifyEndSonification()
282 #define SonifyBeginNoteBackground()
283 #define SonifyEndNoteBackground()
284 #define SonifyBeginNoteForeground()
285 #define SonifyEndNoteForeground()
286 #define SonifyBeginMeasures()
287 #define SonifyEndMeasures()
288 #define SonifyBeginSerialize()
289 #define SonifyEndSerialize()
290 #define SonifyBeginUnserialize()
291 #define SonifyEndUnserialize()
292 #define SonifyBeginAutoSave()
293 #define SonifyEndAutoSave()
294 #define SonifyBeginModifyState()
295 #define SonifyEndModifyState()
296 #endif
297 
298 
299 #endif
Creates and manages BlockFile objects.
Definition: DirManager.h:52
Definition: TrackPanelMouseEvent.h:23
Contains declarations for TimeWarper, IdentityTimeWarper, ShiftTimeWarper, LinearTimeWarper, LinearInputRateSlideTimeWarper, LinearOutputRateSlideTimeWarper, LinearInputInverseRateTimeWarper, GeometricInputRateTimeWarper, GeometricOutputRateTimeWarper classes.
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:161
Definition: Track.h:336
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:85
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:69
int min(int a, int b)
Definition: CompareAudioCommand.cpp:80
Definition: Track.h:351
Definition: StretchHandle.h:24
Transforms one point in time to another point. For example, a time stretching effect might use one to...
Definition: TimeWarper.h:61
std::unique_ptr< Track > Holder
Definition: Track.h:245
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:22
static const char * ZoomOut[]
Definition: FreqWindow.cpp:136
static const char * ZoomIn[]
Definition: FreqWindow.cpp:110
A Track that is used for Midi notes. (Somewhat old code).