mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-19 14:17:41 +02:00
Improved Note Track vertical ruler zooming...
... Make consistent zoom in and out limits for mouse picks and for scrollwheel Make scrollwheel do in or out by a constant multiplier, analogously with wave track The Note track remembers a continuously varying key height, but rounds it off whenever it draws
This commit is contained in:
parent
c476110589
commit
207db5e547
@ -122,7 +122,7 @@ NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager)
|
||||
mVelocity = 0;
|
||||
#endif
|
||||
mBottomNote = 24;
|
||||
mPitchHeight = 5;
|
||||
mPitchHeight = 5.0f;
|
||||
|
||||
mVisibleChannels = ALL_CHANNELS;
|
||||
}
|
||||
@ -184,7 +184,7 @@ Track::Holder NoteTrack::Duplicate() const
|
||||
}
|
||||
// copy some other fields here
|
||||
duplicate->SetBottomNote(mBottomNote);
|
||||
duplicate->SetPitchHeight(mPitchHeight);
|
||||
duplicate->mPitchHeight = mPitchHeight;
|
||||
duplicate->mVisibleChannels = mVisibleChannels;
|
||||
duplicate->SetOffset(GetOffset());
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
@ -912,6 +912,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const
|
||||
xmlFile.EndTag(wxT("notetrack"));
|
||||
}
|
||||
|
||||
#if 0
|
||||
void NoteTrack::StartVScroll()
|
||||
{
|
||||
mStartBottomNote = mBottomNote;
|
||||
@ -923,17 +924,17 @@ void NoteTrack::VScroll(int start, int end)
|
||||
int delta = ((end - start) + ph / 2) / ph;
|
||||
SetBottomNote(mStartBottomNote + delta);
|
||||
}
|
||||
#endif
|
||||
|
||||
void NoteTrack::Zoom(const wxRect &rect, int y, int amount, bool center)
|
||||
void NoteTrack::Zoom(const wxRect &rect, int y, float multiplier, bool center)
|
||||
{
|
||||
// Construct track rectangle to map pitch to screen coordinates
|
||||
// Only y and height are needed:
|
||||
wxRect trackRect(0, rect.GetY(), 1, rect.GetHeight());
|
||||
PrepareIPitchToY(trackRect);
|
||||
int clickedPitch = YToIPitch(y);
|
||||
// zoom out by changing the pitch height -- a small integer
|
||||
mPitchHeight += amount;
|
||||
if (mPitchHeight <= 0) mPitchHeight = 1;
|
||||
// zoom by changing the pitch height
|
||||
SetPitchHeight(rect.height, mPitchHeight * multiplier);
|
||||
PrepareIPitchToY(trackRect); // update because mPitchHeight changed
|
||||
if (center) {
|
||||
int newCenterPitch = YToIPitch(rect.GetY() + rect.GetHeight() / 2);
|
||||
@ -960,13 +961,8 @@ void NoteTrack::ZoomTo(const wxRect &rect, int start, int end)
|
||||
Zoom(rect, start, 1, true);
|
||||
return;
|
||||
}
|
||||
int trialPitchHeight = trackRect.height / (topPitch - botPitch);
|
||||
if (trialPitchHeight > 25) { // keep mPitchHeight in bounds [1...25]
|
||||
trialPitchHeight = 25;
|
||||
} else if (trialPitchHeight == 0) {
|
||||
trialPitchHeight = 1;
|
||||
}
|
||||
Zoom(rect, (start + end) / 2, trialPitchHeight - mPitchHeight, true);
|
||||
auto trialPitchHeight = (float)trackRect.height / (topPitch - botPitch);
|
||||
Zoom(rect, (start + end) / 2, trialPitchHeight / mPitchHeight, true);
|
||||
}
|
||||
|
||||
int NoteTrack::YToIPitch(int y)
|
||||
@ -976,7 +972,9 @@ int NoteTrack::YToIPitch(int y)
|
||||
y -= octave * GetOctaveHeight();
|
||||
// result is approximate because C and G are one pixel taller than
|
||||
// mPitchHeight.
|
||||
return (y / mPitchHeight) + octave * 12;
|
||||
return (y / GetPitchHeight()) + octave * 12;
|
||||
}
|
||||
|
||||
const float NoteTrack::ZoomStep = powf( 2.0f, 0.25f );
|
||||
|
||||
#endif // USE_MIDI
|
||||
|
@ -122,27 +122,38 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
( QuantizedTimeAndBeat t0, QuantizedTimeAndBeat t1, double newDur );
|
||||
|
||||
int GetBottomNote() const { return mBottomNote; }
|
||||
int GetPitchHeight() const { return mPitchHeight; }
|
||||
void SetPitchHeight(int h) { mPitchHeight = h; }
|
||||
/// Zooms out by one unit
|
||||
void ZoomOut(const wxRect &rect, int y) { Zoom(rect, y, -1, true); }
|
||||
/// Zooms in by one unit
|
||||
void ZoomIn(const wxRect &rect, int y) { Zoom(rect, y, 1, true); }
|
||||
int GetPitchHeight() const { return std::max(1, (int)mPitchHeight); }
|
||||
void SetPitchHeight(int rectHeight, float h)
|
||||
{
|
||||
// Impose certain zoom limits
|
||||
auto octavePadding = 2 * 10; // 10 octaves times 2 single-pixel seperations per pixel
|
||||
auto availableHeight = rectHeight - octavePadding;
|
||||
auto numNotes = 128.f;
|
||||
auto minSpacePerNote =
|
||||
std::max((float)MinPitchHeight, availableHeight / numNotes);
|
||||
mPitchHeight =
|
||||
std::max(minSpacePerNote,
|
||||
std::min((float)MaxPitchHeight, h));
|
||||
}
|
||||
/// 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 contant factor (subject to zoom limits)
|
||||
void ZoomIn(const wxRect &rect, int y) { Zoom(rect, y, ZoomStep, true); }
|
||||
/// Zoom the note track around y.
|
||||
/// Positive amounts zoom in; negative amounts zoom out.
|
||||
/// If center is true, the result will be centered at y.
|
||||
void Zoom(const wxRect &rect, int y, int amount, bool center);
|
||||
void Zoom(const wxRect &rect, int y, float multiplier, bool center);
|
||||
void ZoomTo(const wxRect &rect, int start, int end);
|
||||
int GetNoteMargin(int height) const
|
||||
{ return std::min(height / 4, (mPitchHeight + 1) / 2); }
|
||||
int GetOctaveHeight() const { return mPitchHeight * 12 + 2; }
|
||||
{ return std::min(height / 4, (GetPitchHeight() + 1) / 2); }
|
||||
int GetOctaveHeight() const { return GetPitchHeight() * 12 + 2; }
|
||||
// call this once before a series of calls to IPitchToY(). It
|
||||
// sets mBottom to offset of octave 0 so that mBottomNote
|
||||
// is located at r.y + r.height - (GetNoteMargin() + 1 + mPitchHeight)
|
||||
// is located at r.y + r.height - (GetNoteMargin() + 1 + GetPitchHeight())
|
||||
void PrepareIPitchToY(const wxRect &r) const {
|
||||
mBottom = r.y + r.height - GetNoteMargin(r.height) - 1 - mPitchHeight +
|
||||
(mBottomNote / 12) * GetOctaveHeight() +
|
||||
GetNotePos(mBottomNote % 12);
|
||||
mBottom =
|
||||
r.y + r.height - GetNoteMargin(r.height) - 1 - GetPitchHeight() +
|
||||
(mBottomNote / 12) * GetOctaveHeight() +
|
||||
GetNotePos(mBottomNote % 12);
|
||||
}
|
||||
// IPitchToY returns Y coordinate of top of pitch p
|
||||
int IPitchToY(int p) const {
|
||||
@ -151,7 +162,7 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
// 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) + mPitchHeight + 1;
|
||||
return IPitchToY(oct * 12) + GetPitchHeight() + 1;
|
||||
}
|
||||
// Y coordinate for given floating point pitch (rounded to int)
|
||||
int PitchToY(double p) const {
|
||||
@ -162,7 +173,8 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
// 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 + mPitchHeight * (p + 1) + (p > 4); }
|
||||
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
|
||||
@ -178,6 +190,8 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
|
||||
mBottomNote = note;
|
||||
}
|
||||
|
||||
#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.
|
||||
@ -186,6 +200,7 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
// 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;
|
||||
@ -238,7 +253,14 @@ class AUDACITY_DLL_API NoteTrack final
|
||||
mutable int mBottom;
|
||||
int mBottomNote;
|
||||
int mStartBottomNote;
|
||||
int mPitchHeight;
|
||||
|
||||
// Remember continuous variation for zooming,
|
||||
// but it is rounded off whenever drawing:
|
||||
float mPitchHeight;
|
||||
|
||||
enum { MinPitchHeight = 1, MaxPitchHeight = 25 };
|
||||
static const float ZoomStep;
|
||||
|
||||
int mVisibleChannels; // bit set of visible channels
|
||||
|
||||
std::weak_ptr<StretchHandle> mStretchHandle;
|
||||
|
@ -66,7 +66,10 @@ unsigned NoteTrackVRulerControls::HandleWheelRotation
|
||||
|
||||
const auto nt = static_cast<NoteTrack*>(pTrack.get());
|
||||
if (event.CmdDown() && !event.ShiftDown()) {
|
||||
nt->Zoom(evt.rect, evt.event.m_y, (int) (steps), false);
|
||||
if (steps > 0)
|
||||
nt->ZoomIn(evt.rect, evt.event.m_y);
|
||||
else
|
||||
nt->ZoomOut(evt.rect, evt.event.m_y);
|
||||
} else if (!event.CmdDown() && event.ShiftDown()) {
|
||||
// Scroll some fixed number of notes, independent of zoom level or track height:
|
||||
static const int movement = 6; // 6 semitones is half an octave
|
||||
|
@ -132,11 +132,7 @@ UIHandle::Result NoteTrackVZoomHandle::Release
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out completely
|
||||
pTrack->SetBottomNote(0);
|
||||
auto octavePadding = 2 * 10; // 10 octaves times 2 single-pixel seperations per pixel
|
||||
auto availableHeight = evt.rect.height - octavePadding;
|
||||
auto numNotes = 128;
|
||||
auto spacePerNote = availableHeight / numNotes;
|
||||
pTrack->SetPitchHeight(std::max(spacePerNote, 1));
|
||||
pTrack->SetPitchHeight(evt.rect.height, 1);
|
||||
} else {
|
||||
// Zoom out
|
||||
pTrack->ZoomOut(evt.rect, mZoomEnd);
|
||||
|
Loading…
x
Reference in New Issue
Block a user