forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNoteTrack.h
295 lines (236 loc) · 9.47 KB
/
NoteTrack.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/**********************************************************************
Sneedacity: A Digital Audio Editor
NoteTrack.h
Dominic Mazzoni
**********************************************************************/
#ifndef __SNEEDACITY_NOTETRACK__
#define __SNEEDACITY_NOTETRACK__
#include <utility>
#include "Track.h"
#if defined(USE_MIDI)
// define this switch to play MIDI during redisplay to sonify run times
// Note that if SONIFY is defined, the default MIDI device will be opened
// and may block normal MIDI playback.
//#define SONIFY 1
#ifdef SONIFY
#define SONFNS(name) \
void Begin ## name(); \
void End ## name();
SONFNS(NoteBackground)
SONFNS(NoteForeground)
SONFNS(Measures)
SONFNS(Serialize)
SONFNS(Unserialize)
SONFNS(ModifyState)
SONFNS(AutoSave)
#undef SONFNS
#endif
class wxDC;
class wxRect;
class Alg_seq; // from "allegro.h"
using NoteTrackBase =
#ifdef EXPERIMENTAL_MIDI_OUT
PlayableTrack
#else
AudioTrack
#endif
;
using QuantizedTimeAndBeat = std::pair< double, double >;
class StretchHandle;
class TimeWarper;
class SNEEDACITY_DLL_API NoteTrack final
: public NoteTrackBase
{
public:
NoteTrack();
virtual ~NoteTrack();
using Holder = std::shared_ptr<NoteTrack>;
private:
Track::Holder Clone() const override;
public:
double GetOffset() const override;
double GetStartTime() const override;
double GetEndTime() const override;
Alg_seq &GetSeq() const;
void WarpAndTransposeNotes(double t0, double t1,
const TimeWarper &warper, double semitones);
static void DrawLabelControls
( const NoteTrack *pTrack, wxDC & dc, const wxRect &rect,
int highlightedChannel = -1 );
int FindChannel(const wxRect &rect, int mx, int my);
bool LabelClick(const wxRect &rect, int x, int y, bool right);
void SetSequence(std::unique_ptr<Alg_seq> &&seq);
void PrintSequence();
Alg_seq *MakeExportableSeq(std::unique_ptr<Alg_seq> &cleanup) const;
bool ExportMIDI(const wxString &f) const;
bool ExportAllegro(const wxString &f) const;
// High-level editing
Track::Holder Cut (double t0, double t1) override;
Track::Holder Copy (double t0, double t1, bool forClipboard = true) const override;
bool Trim (double t0, double t1) /* not override */;
void Clear(double t0, double t1) override;
void Paste(double t, const Track *src) override;
void Silence(double t0, double t1) override;
void InsertSilence(double t, double len) override;
bool Shift(double t) /* not override */;
#ifdef EXPERIMENTAL_MIDI_OUT
float GetVelocity() const { return mVelocity; }
void SetVelocity(float velocity);
#endif
QuantizedTimeAndBeat NearestBeatTime( double time ) const;
bool StretchRegion
( QuantizedTimeAndBeat t0, QuantizedTimeAndBeat t1, double newDur );
/// Gets the current bottom note (a pitch)
int GetBottomNote() const { return mBottomNote; }
/// Gets the current top note (a pitch)
int GetTopNote() const { return mTopNote; }
/// Sets the bottom note (a pitch), making sure that it is never greater than the top note.
void SetBottomNote(int note);
/// Sets the top note (a pitch), making sure that it is never less than the bottom note.
void SetTopNote(int note);
/// Sets the top and bottom note (both pitches) automatically, swapping them if needed.
void SetNoteRange(int note1, int note2);
/// Zooms so that all notes are visible
void ZoomAllNotes();
/// Zooms so that the entire track is visible
void ZoomMaxExtent() { SetNoteRange(MinPitch, MaxPitch); }
/// Shifts all notes vertically by the given pitch
void ShiftNoteRange(int offset);
/// Zooms out a constant factor (subject to zoom limits)
void ZoomOut(const wxRect &rect, int y) { Zoom(rect, y, 1.0f / ZoomStep, true); }
/// Zooms in a constant factor (subject to zoom limits)
void ZoomIn(const wxRect &rect, int y) { Zoom(rect, y, ZoomStep, true); }
/// Zoom the note track around y.
/// If center is true, the result will be centered at y.
void Zoom(const wxRect &rect, int y, float multiplier, bool center);
void ZoomTo(const wxRect &rect, int start, int end);
#if 0
// Vertical scrolling is performed by dragging the keyboard at
// left of track. Protocol is call StartVScroll, then update by
// calling VScroll with original and final mouse position.
// These functions are not used -- instead, zooming/dragging works like
// audio track zooming/dragging. The vertical scrolling is nice however,
// so I left these functions here for possible use in the future.
void StartVScroll();
void VScroll(int start, int end);
#endif
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override;
XMLTagHandler *HandleXMLChild(const wxChar *tag) override;
void WriteXML(XMLWriter &xmlFile) const override;
// channels are numbered as integers 0-15, visible channels
// (mVisibleChannels) is a bit set. Channels are displayed as
// integers 1-16.
// Allegro's data structure does not restrict channels to 16.
// Since there is not way to select more than 16 channels,
// map all channel numbers mod 16. This will have no effect
// on MIDI files, but it will allow users to at least select
// all channels on non-MIDI event sequence data.
#define NUM_CHANNELS 16
// Bitmask with all NUM_CHANNELS bits set
#define ALL_CHANNELS (1 << NUM_CHANNELS) - 1
#define CHANNEL_BIT(c) (1 << (c % NUM_CHANNELS))
bool IsVisibleChan(int c) const {
return (mVisibleChannels & CHANNEL_BIT(c)) != 0;
}
void SetVisibleChan(int c) { mVisibleChannels |= CHANNEL_BIT(c); }
void ClearVisibleChan(int c) { mVisibleChannels &= ~CHANNEL_BIT(c); }
void ToggleVisibleChan(int c) { mVisibleChannels ^= CHANNEL_BIT(c); }
// Solos the given channel. If it's the only channel visible, all channels
// are enabled; otherwise, it is set to the only visible channel.
void SoloVisibleChan(int c) {
if (mVisibleChannels == CHANNEL_BIT(c))
mVisibleChannels = ALL_CHANNELS;
else
mVisibleChannels = CHANNEL_BIT(c);
}
Track::Holder PasteInto( SneedacityProject & ) const override;
ConstIntervals GetIntervals() const override;
Intervals GetIntervals() override;
private:
TrackKind GetKind() const override { return TrackKind::Note; }
void AddToDuration( double delta );
// These are mutable to allow NoteTrack to switch details of representation
// in logically const methods
// At most one of the two pointers is not null at any time.
// Both are null in a newly constructed NoteTrack.
mutable std::unique_ptr<Alg_seq> mSeq;
mutable std::unique_ptr<char[]> mSerializationBuffer;
mutable long mSerializationLength;
#ifdef EXPERIMENTAL_MIDI_OUT
float mVelocity; // velocity offset
#endif
int mBottomNote, mTopNote;
#if 0
// Also unused from vertical scrolling
int mStartBottomNote;
#endif
// Remember continuous variation for zooming,
// but it is rounded off whenever drawing:
float mPitchHeight;
enum { MinPitch = 0, MaxPitch = 127 };
static const float ZoomStep;
int mVisibleChannels; // bit set of visible channels
std::weak_ptr<StretchHandle> mStretchHandle;
};
/// Data used to display a note track
class NoteTrackDisplayData {
private:
float mPitchHeight;
// mBottom is the Y offset of pitch 0 (normally off screen)
// Used so that mBottomNote is located at
// mY + mHeight - (GetNoteMargin() + 1 + GetPitchHeight())
int mBottom;
int mMargin;
enum { MinPitchHeight = 1, MaxPitchHeight = 25 };
public:
NoteTrackDisplayData(const NoteTrack* track, const wxRect &r);
int GetPitchHeight(int factor) const
{ return std::max(1, (int)(factor * mPitchHeight)); }
int GetNoteMargin() const { return mMargin; };
int GetOctaveHeight() const { return GetPitchHeight(12) + 2; }
// IPitchToY returns Y coordinate of top of pitch p
int IPitchToY(int p) const;
// compute the window coordinate of the bottom of an octave: This is
// the bottom of the line separating B and C.
int GetOctaveBottom(int oct) const {
return IPitchToY(oct * 12) + GetPitchHeight(1) + 1;
}
// Y coordinate for given floating point pitch (rounded to int)
int PitchToY(double p) const {
return IPitchToY((int) (p + 0.5));
}
// Integer pitch corresponding to a Y coordinate
int YToIPitch(int y) const;
// map pitch class number (0-11) to pixel offset from bottom of octave
// (the bottom of the black line between B and C) to the top of the
// note. Note extra pixel separates B(11)/C(0) and E(4)/F(5).
int GetNotePos(int p) const
{ return 1 + GetPitchHeight(p + 1) + (p > 4); }
// get pixel offset to top of ith black key note
int GetBlackPos(int i) const { return GetNotePos(i * 2 + 1 + (i > 1)); }
// GetWhitePos tells where to draw lines between keys as an offset from
// GetOctaveBottom. GetWhitePos(0) returns 1, which matches the location
// of the line separating B and C
int GetWhitePos(int i) const { return 1 + (i * GetOctaveHeight()) / 7; }
};
#endif // USE_MIDI
#ifndef SONIFY
// no-ops:
#define SonifyBeginSonification()
#define SonifyEndSonification()
#define SonifyBeginNoteBackground()
#define SonifyEndNoteBackground()
#define SonifyBeginNoteForeground()
#define SonifyEndNoteForeground()
#define SonifyBeginMeasures()
#define SonifyEndMeasures()
#define SonifyBeginSerialize()
#define SonifyEndSerialize()
#define SonifyBeginUnserialize()
#define SonifyEndUnserialize()
#define SonifyBeginAutoSave()
#define SonifyEndAutoSave()
#define SonifyBeginModifyState()
#define SonifyEndModifyState()
#endif
#endif