15#include "../lib-src/header-substitutes/allegro.h"
18#include "../../../../NoteTrack.h"
22#include "../../../../HitTestResult.h"
24#include "../../../../TrackArt.h"
25#include "../../../../TrackArtist.h"
26#include "../../../../TrackPanelDrawingContext.h"
27#include "../../../../TrackPanelMouseEvent.h"
29#include "../../../ui/SelectHandle.h"
50 std::vector<UIHandlePtr> results;
52#ifdef EXPERIMENTAL_MIDI_STRETCHING
54 mStretchHandle, state, pProject, Pointer<NoteTrack>(
this) );
56 results.push_back(result);
66 return std::make_shared<NoteTrackView>( track.SharedPointer() );
73 std::make_shared<NoteTrackVRulerControls>( shared_from_this() );
76#define TIME_TO_X(t) (zoomInfo.TimeToPosition((t), rect.x))
77#define X_TO_TIME(xx) (zoomInfo.PositionToTime((xx), rect.x))
145 Alg_parameters_ptr parameters = note->parameters;
147 if (strcmp(parameters->parm.attr_name(),
"shapea") == 0) {
148 return parameters->parm.a;
150 parameters = parameters->next;
158 Alg_parameters_ptr parameters = note->parameters;
160 if (parameters->parm.attr_name() == attr + 1 &&
161 parameters->parm.attr_type() ==
'r') {
162 return parameters->parm.r;
164 parameters = parameters->next;
172 Alg_parameters_ptr parameters = note->parameters;
174 if (parameters->parm.attr_name() == attr + 1 &&
175 parameters->parm.attr_type() ==
'i') {
176 return parameters->parm.i;
178 parameters = parameters->next;
186 Alg_parameters_ptr parameters = note->parameters;
188 if (parameters->parm.attr_name() == attr + 1 &&
189 parameters->parm.attr_type() ==
'l') {
190 return parameters->parm.l;
192 parameters = parameters->next;
200 Alg_parameters_ptr parameters = note->parameters;
202 if (parameters->parm.attr_name() == attr + 1 &&
203 parameters->parm.attr_type() ==
's') {
204 return parameters->parm.s;
206 parameters = parameters->next;
214 Alg_parameters_ptr parameters = note->parameters;
216 if (parameters->parm.attr_name() == attr + 1 &&
217 parameters->parm.attr_type() ==
'a') {
218 return parameters->parm.s;
220 parameters = parameters->next;
232#define CLIP_MAX 16000
233#define CLIP(xx) { long c = (xx); if (c < -CLIP_MAX) c = -CLIP_MAX; \
234 if (c > CLIP_MAX) c = CLIP_MAX; (xx) = c; }
236#define RED(i) ( unsigned char )( (((i) >> 16) & 0xff) )
237#define GREEN(i) ( unsigned char )( (((i) >> 8) & 0xff) )
238#define BLUE(i) ( unsigned char )( ((i) & 0xff) )
263 const wxRect &rect,
const wxRect &sel,
264 const wxBrush &wb,
const wxPen &wp,
265 const wxBrush &bb,
const wxPen &bp,
268 auto &dc = context.
dc;
270 const auto &zoomInfo = *artist->pZoomInfo;
274#ifndef EXPERIMENTAL_NOTETRACK_OVERLAY
275 dc.DrawRectangle(sel);
279 if (left < sel.x) left = sel.x;
282 if (right > sel.x + sel.width) right = sel.x + sel.width;
285 if (left >= right)
return;
291 int obottom = data.GetOctaveBottom(octave);
294 int eOffset = data.GetPitchHeight(5) + 2;
295 while (obottom > rect.y + data.GetNoteMargin() + 3) {
297 if (obottom < rect.y + rect.height - data.GetNoteMargin()) {
298 dc.SetPen(*wxBLACK_PEN);
300 AColor::Line(dc, left, obottom - 1, right, obottom - 1);
304 if (obottom - eOffset > rect.y && obottom - eOffset < rect.y + rect.height) {
306 right, obottom - eOffset);
312 br.width = right - left;
313 br.height = data.GetPitchHeight(1);
314 for (
int black = 0; black < 5; black++) {
315 br.y = obottom - data.GetBlackPos(black);
316 if (br.y > rect.y && br.y + br.height < rect.y + rect.height) {
317 dc.DrawRectangle(br);
320 obottom = data.GetOctaveBottom(++octave);
324 Alg_seq_ptr seq = &track->
GetSeq();
335 Alg_time_sigs &sigs = seq->time_sig;
337 double next_bar_beat = 0.0;
338 double beats_per_measure = 4.0;
340 if (i < sigs.length() && sigs[i].beat < next_bar_beat + ALG_EPS) {
342 Alg_time_sig &sig = sigs[i++];
343 next_bar_beat = sig.beat;
344 beats_per_measure = (sig.num * 4.0) / sig.den;
347 double t = seq->get_time_map()->beat_to_time(next_bar_beat);
350 if (xx > right)
break;
352 next_bar_beat += beats_per_measure;
368 auto &dc = context.
dc;
370 const auto &selectedRegion = *artist->pSelectedRegion;
371 const auto &zoomInfo = *artist->pZoomInfo;
374 double sel0 = selectedRegion.t0();
375 double sel1 = selectedRegion.t1();
378 const double h1 =
X_TO_TIME(rect.x + rect.width);
380 Alg_seq_ptr seq = &track->
GetSeq();
389 int numPitches = (rect.height) / data.GetPitchHeight(1);
390 if (numPitches < 0) numPitches = 0;
398 wxPen blackStripePen;
400 wxBrush blackStripeBrush;
405 const auto &blankBrush = artist->blankBrush;
406 const auto &blankPen = artist->blankPen;
408 blackStripeBrush, blackStripePen, barLinePen);
410 dc.SetClippingRegion(rect);
417 selBG.height = rect.height;
421 wxPen selectedWhiteKeyPen;
422 selectedWhiteKeyPen.SetColour(165, 165, 190);
423 dc.SetPen(selectedWhiteKeyPen);
425 wxBrush selectedWhiteKeyBrush;
428 wxPen selectedBlackKeyPen;
430 wxBrush selectedBlackKeyBrush;
432 wxPen selectedBarLinePen;
436 selectedWhiteKeyBrush, selectedWhiteKeyPen,
437 selectedBlackKeyBrush, selectedBlackKeyPen,
441 int marg = data.GetNoteMargin();
445 Alg_attribute line = symbol_table.insert_string(
"line");
446 Alg_attribute
rectangle = symbol_table.insert_string(
"rectangle");
447 Alg_attribute
triangle = symbol_table.insert_string(
"triangle");
448 Alg_attribute polygon = symbol_table.insert_string(
"polygon");
449 Alg_attribute oval = symbol_table.insert_string(
"oval");
450 Alg_attribute text = symbol_table.insert_string(
"text");
451 Alg_attribute texts = symbol_table.insert_string(
"texts");
452 Alg_attribute x1r = symbol_table.insert_string(
"x1r");
453 Alg_attribute x2r = symbol_table.insert_string(
"x2r");
454 Alg_attribute y1r = symbol_table.insert_string(
"y1r");
455 Alg_attribute y2r = symbol_table.insert_string(
"y2r");
456 Alg_attribute linecolori = symbol_table.insert_string(
"linecolori");
457 Alg_attribute fillcolori = symbol_table.insert_string(
"fillcolori");
458 Alg_attribute linethicki = symbol_table.insert_string(
"linethicki");
459 Alg_attribute filll = symbol_table.insert_string(
"filll");
460 Alg_attribute fonta = symbol_table.insert_string(
"fonta");
461 Alg_attribute roman = symbol_table.insert_string(
"roman");
462 Alg_attribute swiss = symbol_table.insert_string(
"swiss");
463 Alg_attribute modern = symbol_table.insert_string(
"modern");
464 Alg_attribute weighta = symbol_table.insert_string(
"weighta");
465 Alg_attribute bold = symbol_table.insert_string(
"bold");
466 Alg_attribute sizei = symbol_table.insert_string(
"sizei");
467 Alg_attribute justifys = symbol_table.insert_string(
"justifys");
470 seq->convert_to_seconds();
472 Alg_iterator iterator(seq,
false);
476 while (0 != (evt = iterator.next())) {
477 if (evt->get_type() ==
'n') {
478 Alg_note_ptr note = (Alg_note_ptr) evt;
481 double xx = note->time + track->
GetOffset();
482 double x1 = xx + note->dur;
483 if (xx < h1 && x1 > h) {
484 const char *shape = NULL;
485 if (note->loud > 0.0 || 0 == (shape =
IsShape(note))) {
487 nr.y = data.PitchToY(note->pitch);
488 nr.height = data.GetPitchHeight(1);
493 if (nr.x + nr.width >= rect.x && nr.x < rect.x + rect.width) {
495 nr.width -= (rect.x - nr.x);
498 if (nr.x + nr.width > rect.x + rect.width)
499 nr.width = rect.x + rect.width - nr.x;
501 if (nr.y + nr.height < rect.y + marg + 3) {
505 dc.SetBrush(*wxBLACK_BRUSH);
506 dc.SetPen(*wxBLACK_PEN);
507 dc.DrawRectangle(nr);
508 }
else if (nr.y >= rect.y + rect.height - marg - 1) {
510 nr.y = rect.y + rect.height - marg;
512 dc.SetBrush(*wxBLACK_BRUSH);
513 dc.SetPen(*wxBLACK_PEN);
514 dc.DrawRectangle(nr);
516 if (nr.y + nr.height > rect.y + rect.height - marg)
517 nr.height = rect.y + rect.height - nr.y;
518 if (nr.y < rect.y + marg) {
519 int offset = rect.y + marg - nr.y;
528 dc.DrawRectangle(nr);
529 if (data.GetPitchHeight(1) > 2) {
535 nr.x+nr.width-1, nr.y+nr.height-1);
537 nr.x+nr.width-1, nr.y+nr.height-1);
547 int yy = data.PitchToY(note->pitch);
557 dc.SetPen(wxPen(wxColour(
RED(linecolor),
560 linethick, wxPENSTYLE_SOLID));
567 dc.SetBrush(wxBrush(wxColour(
RED(fillcolor),
570 wxBRUSHSTYLE_SOLID));
571 if (!fillflag) dc.SetBrush(*wxTRANSPARENT_BRUSH);
578 yy = (int)((yy + (y1 - yy) * (h - xx) / (x1 - xx)) + 0.5);
582 y1 = (int)((yy + (y1 - yy) * (h1 - xx) / (x1 - xx)) + 0.5);
588 xx =
X_TO_TIME(rect.x - (linethick + 10));
591 xx =
X_TO_TIME(rect.x + rect.width + linethick + 10);
605 dc.DrawPolygon(3, points);
606 }
else if (shape == polygon) {
620 sprintf(
name,
"x%dr", n);
621 Alg_attribute attr = symbol_table.insert_string(
name);
623 if (xn == -1000000.0)
break;
626 sprintf(
name,
"y%dr", n - 1);
627 attr = symbol_table.insert_string(
name);
629 if (yn == -1000000.0)
break;
630 points[n].y = data.PitchToY(yn);
633 dc.DrawPolygon(n, points);
634 }
else if (shape == oval) {
639 dc.DrawEllipse(ix, yy, ix1, y1 - yy + 1);
640 }
else if (shape == text) {
642 dc.SetTextForeground(wxColour(
RED(linecolor),
646 else dc.SetTextForeground(dc.GetBrush().GetColour());
661 wxfont.SetFamily(font == roman ? wxFONTFAMILY_ROMAN :
662 (font == swiss ? wxFONTFAMILY_SWISS :
663 (font == modern ? wxFONTFAMILY_MODERN : wxFONTFAMILY_DEFAULT)));
664 wxfont.SetStyle(wxFONTSTYLE_NORMAL);
665 wxfont.SetWeight(weight == bold ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL);
666 wxfont.SetPointSize(
size);
671 wxCoord textWidth, textHeight;
672 dc.GetTextExtent(wxString::FromUTF8(s), &textWidth, &textHeight);
674 long voffset = -textHeight;
676 if (strlen(justify) != 2) justify =
"ld";
678 if (justify[0] ==
'c') hoffset = -(textWidth/2);
679 else if (justify[0] ==
'r') hoffset = -textWidth;
681 if (justify[1] ==
't') voffset = 0;
682 else if (justify[1] ==
'c') voffset = -(textHeight/2);
683 else if (justify[1] ==
'b') voffset = -textHeight;
688 dc.SetPen(wxPen(wxColour(
RED(fillcolor),
691 1, wxPENSTYLE_SOLID));
692 dc.DrawRectangle(
TIME_TO_X(xx) + hoffset, yy + voffset,
693 textWidth, textHeight);
704 dc.SetPen(*wxBLACK_PEN);
705 AColor::Line(dc, rect.x, rect.y + marg, rect.x + rect.width, rect.y + marg);
706 AColor::Line(dc, rect.x, rect.y + rect.height - marg - 1,
707 rect.x + rect.width, rect.y + rect.height - marg - 1);
709 if (h == 0.0 && track->
GetOffset() < 0.0) {
721 dc.DestroyClippingRegion();
729 const wxRect &rect,
unsigned iPass )
732 const auto nt = std::static_pointer_cast<const NoteTrack>(
733 FindTrack()->SubstitutePendingChangedTrack());
735#ifdef EXPERIMENTAL_MIDI_OUT
737 const auto hasSolo = artist->hasSolo;
738 muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
741#ifdef EXPERIMENTAL_NOTETRACK_OVERLAY
744 bool selected{
false };
745 if (
auto affordance = std::dynamic_pointer_cast<NoteTrackAffordanceControls>(
GetAffordanceControls()))
747 selected = affordance->IsSelected();
std::shared_ptr< UIHandle > UIHandlePtr
const TranslatableString name
#define SonifyBeginNoteBackground()
#define SonifyEndNoteBackground()
#define SonifyBeginNoteForeground()
#define SonifyEndNoteForeground()
DEFINE_ATTACHED_VIRTUAL_OVERRIDE(DoGetNoteTrackView)
@ Grouped
Can be part of a group.
static wxBrush labelSelectedBrush
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
static void LightMIDIChannel(wxDC *dc, int channel)
static void MIDIChannel(wxDC *dc, int channel)
static wxBrush labelUnselectedBrush
static void DarkMIDIChannel(wxDC *dc, int channel)
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
std::shared_ptr< Track > DoFindTrack() override
std::shared_ptr< Track > FindTrack()
Data used to display a note track.
A Track that is used for Midi notes. (Somewhat old code).
double GetOffset() const override
bool IsVisibleChan(int c) const
std::shared_ptr< CommonTrackCell > mpAffordanceCellControl
std::vector< UIHandlePtr > DetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool) override
std::shared_ptr< CommonTrackCell > GetAffordanceControls() override
NoteTrackView(const NoteTrackView &)=delete
~NoteTrackView() override
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
std::shared_ptr< TrackVRulerControls > DoGetVRulerControls() override
static UIHandlePtr HitTest(std::weak_ptr< StretchHandle > &holder, const TrackPanelMouseState &state, const AudacityProject *pProject, const std::shared_ptr< NoteTrack > &pTrack)
wxColour & Colour(int iIndex)
static TrackArtist * Get(TrackPanelDrawingContext &)
bool GetSelected() const
Selectedness is always the same for all channels of a group.
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
AUDACITY_DLL_API void DrawClipEdges(wxDC &dc, const wxRect &clipRect, bool selected=false)
AUDACITY_DLL_API void DrawBackgroundWithSelection(TrackPanelDrawingContext &context, const wxRect &rect, const Track *track, const wxBrush &selBrush, const wxBrush &unselBrush, bool useSelection=true)
AUDACITY_DLL_API void DrawNegativeOffsetTrackArrows(TrackPanelDrawingContext &context, const wxRect &rect)
bool LookupLogicalAttribute(Alg_note_ptr note, Alg_attribute attr, bool def)
const char * IsShape(Alg_note_ptr note)
const char * LookupStringAttribute(Alg_note_ptr note, Alg_attribute attr, const char *def)
const char * LookupAtomAttribute(Alg_note_ptr note, Alg_attribute attr, char *def)
void DrawNoteTrack(TrackPanelDrawingContext &context, const NoteTrack *track, const wxRect &rect, bool muted, bool selected)
double LookupRealAttribute(Alg_note_ptr note, Alg_attribute attr, double def)
void DrawNoteBackground(TrackPanelDrawingContext &context, const NoteTrack *track, const wxRect &rect, const wxRect &sel, const wxBrush &wb, const wxPen &wp, const wxBrush &bb, const wxPen &bp, const wxPen &mp)
long LookupIntAttribute(Alg_note_ptr note, Alg_attribute attr, long def)
For defining overrides of the method.