summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
authorFlorian Jung <flo@windfisch.org>2011-04-11 12:30:11 +0000
committerFlorian Jung <flo@windfisch.org>2011-04-11 12:30:11 +0000
commitbe4e0679ad4a847f7b3f7e9cb85e54be2f32085f (patch)
treeb9f7e2ed090acbea8832fd49ab49cb11f2d9fa90 /muse2
parentd80dde88f453a5a032213aaacb77d6851b127e69 (diff)
implemented highlighting currently played notes
plus bugfix: manipulating non-zero-aligned parts works now correctly plus some cosmetic stuff in the source (ints -> unsigneds)
Diffstat (limited to 'muse2')
-rw-r--r--muse2/muse/midiedit/scoreedit.cpp244
-rw-r--r--muse2/muse/midiedit/scoreedit.h15
2 files changed, 154 insertions, 105 deletions
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp
index 3634f717..62250bea 100644
--- a/muse2/muse/midiedit/scoreedit.cpp
+++ b/muse2/muse/midiedit/scoreedit.cpp
@@ -85,30 +85,6 @@ using namespace std;
ScoreEdit::ScoreEdit(PartList* pl, QWidget* parent, const char* name, unsigned initPos)
: MidiEditor(0, 0, pl, parent, name)
{
-// Splitter* hsplitter;
- QPushButton* ctrl;
-/*
- hsplitter = new Splitter(Qt::Vertical, mainw, "hsplitter");
- hsplitter->setHandleWidth(2);
-
- ctrl = new QPushButton(tr("ctrl"), mainw);
- ctrl->setObjectName("Ctrl");
- ctrl->setFont(config.fonts[3]);
- ctrl->setToolTip(tr("Add Controller View"));
-
- hsplitter->addWidget(ctrl);
-*/
- /*
- QGridLayout* gridS1 = new QGridLayout(mainw);
- gridS1->setContentsMargins(0, 0, 0, 0);
-
- mainGrid->setRowStretch(0, 100);
- mainGrid->setColumnStretch(1, 100);
-
- gridS1->setRowStretch(2, 100);
- gridS1->setColumnStretch(1, 100);
-*/
-
ScoreCanvas* test=new ScoreCanvas(this, mainw, 1, 1);
hscroll = new QScrollBar(Qt::Horizontal, mainw);
@@ -231,32 +207,37 @@ string IntToStr(int i)
return s.str();
}
+void color_image(QImage& img, const QColor& color)
+{
+ uchar* ptr=img.bits();
+ int bytes=img.byteCount();
+ int r,g,b;
+ color.getRgb(&r,&g,&b);
+
+ for (int i=0; i<bytes/4; i++)
+ {
+ QRgb* rgb=((QRgb*)ptr);
+ (*rgb) = qRgba(r,g,b,qAlpha(*rgb));
+
+ ptr+=4;
+ }
+}
+
void load_colored_pixmaps(string file, QPixmap* array)
{
QString fn(file.c_str());
QImage img(fn);
+
+ color_image(img, Qt::black);
+ array[BLACK_PIXMAP]=QPixmap::fromImage(img);
- int bytes=img.byteCount();
- uchar* bits=img.bits();
- uchar* ptr;
+ color_image(img, Qt::red);
+ array[HIGHLIGHTED_PIXMAP]=QPixmap::fromImage(img);
- array[BLACK_PIXMAP]=QPixmap::fromImage(img); //before anything was changed
- //TODO: really color it black, don't rely on the userdata be correct
for (int color_index=0;color_index<NUM_PARTCOLORS; color_index++)
{
- ptr=bits;
- int r,g,b;
- config.partColors[color_index].getRgb(&r,&g,&b);
-
- for (int i=0; i<bytes/4; i++)
- {
- QRgb* rgb=((QRgb*)ptr);
- (*rgb) = qRgba(r,g,b,qAlpha(*rgb));
-
- ptr+=4;
- }
-
+ color_image(img, config.partColors[color_index]);
array[color_index]=QPixmap::fromImage(img);
}
}
@@ -340,7 +321,7 @@ bool operator< (const note_pos_t& a, const note_pos_t& b)
int flo_quantize(int tick)
{
//TODO quantizing must be done with the proper functions!
- return int(rint((float)tick / FLO_QUANT))*FLO_QUANT;
+ return int(nearbyint((float)tick / FLO_QUANT))*FLO_QUANT;
}
int flo_quantize_floor(int tick)
@@ -412,7 +393,7 @@ ScoreEventList ScoreCanvas::createAppropriateEventList(PartList* pl)
for (it=result.begin(); it!=result.end(); it++)
if (it->second.type==FloEvent::NOTE_ON)
{
- int end_tick=it->first + it->second.len;
+ unsigned end_tick=it->first + it->second.len;
//iterate though all (relevant) later note_ons which are
//at the same pitch. if there's a collision, shorten it's len
@@ -1103,7 +1084,7 @@ void ScoreCanvas::process_itemlist(ScoreItemList& itemlist)
else
{
cout << "creating group #"<<n_groups<<endl;
- temp.pos.height=rint((float)height_cumulative/counter);
+ temp.pos.height=nearbyint((float)height_cumulative/counter);
}
// do NOT first insert, then erase, because if temp.height ==
@@ -1592,7 +1573,6 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
curr_key=key_at_tick(from_it->first);
list<int> new_acc_list=calc_accidentials(curr_key, USED_CLEF);
- QPixmap* pix = is_sharp_key(curr_key) ? &pix_sharp[BLACK_PIXMAP] : &pix_b[BLACK_PIXMAP];
vorzeichen_t new_accidential = is_sharp_key(curr_key) ? SHARP : B;
for (int i=0;i<7;i++)
@@ -1675,10 +1655,17 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
for (int i=12; i<=it->pos.height; i+=2)
p.drawLine(it->x-it->pix->width()*AUX_LINE_LEN/2 -x_pos+x_left,YDIST+4*YLEN - (i-2)*YLEN/2,it->x+it->pix->width()*AUX_LINE_LEN/2-x_pos+x_left,YDIST+4*YLEN - (i-2)*YLEN/2);
}
-
- draw_pixmap(p,it->x -x_pos+x_left,it->y,it->pix[it->source_part->colorIndex()]);
- //TODO FINDMICH draw a margin around bright colors
+ it->is_active= ( (song->cpos() >= it->source_event->tick() + it->source_part->tick()) &&
+ (song->cpos() < it->source_event->endTick() + it->source_part->tick()) );
+
+ int color_index=it->source_part->colorIndex();
+
+ if (audio->isPlaying() && it->is_active)
+ color_index=HIGHLIGHTED_PIXMAP;
+
+ draw_pixmap(p,it->x -x_pos+x_left,it->y,it->pix[color_index]);
+ //TODO FINDMICH maybe draw a margin around bright colors?
//maybe draw the default color in black?
//draw dots
@@ -1696,7 +1683,7 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
for (int i=0;i<it->dots;i++)
{
- draw_pixmap(p,it->x+x_dot -x_pos+x_left,it->y+y_dot,pix_dot[it->source_part->colorIndex()]);
+ draw_pixmap(p,it->x+x_dot -x_pos+x_left,it->y+y_dot,pix_dot[color_index]);
x_dot+=DOT_XDIST;
}
@@ -1712,7 +1699,7 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
case SHARP: acc_pix=pix_sharp; break;
case B: acc_pix=pix_b; break;
}
- draw_pixmap(p,it->x-ACCIDENTIAL_DIST -x_pos+x_left,it->y, acc_pix[it->source_part->colorIndex()]);
+ draw_pixmap(p,it->x-ACCIDENTIAL_DIST -x_pos+x_left,it->y, acc_pix[color_index]);
curr_accidential[modulo(it->pos.height,7)]=it->pos.vorzeichen;
}
@@ -1722,7 +1709,7 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
if (it->is_tie_dest)
{
cout << "drawing tie" << endl;
- draw_tie(p,it->tie_from_x-x_pos+x_left,it->x -x_pos+x_left,it->y, (it->len==0) ? true : (it->stem==DOWNWARDS) , config.partColors[it->source_part->colorIndex()]);
+ draw_tie(p,it->tie_from_x-x_pos+x_left,it->x -x_pos+x_left,it->y, (it->len==0) ? true : (it->stem==DOWNWARDS) , config.partColors[color_index]);
// in english: "if it's a whole note, tie is upwards (true). if not, tie is upwards if
// stem is downwards and vice versa"
}
@@ -1818,6 +1805,49 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList
}
}
+bool ScoreCanvas::need_redraw_for_hilighting()
+{
+ return need_redraw_for_hilighting(x_pos,x_pos+width()-x_left);
+}
+
+bool ScoreCanvas::need_redraw_for_hilighting(int x1, int x2)
+{
+ int from_tick, to_tick;
+ ScoreItemList::iterator from_it, to_it;
+
+ from_tick=x_to_tick(x1);
+ from_it=itemlist.lower_bound(from_tick);
+ //from_it now contains the first time which is fully drawn
+ //however, the previous beat could still be relevant, when it's
+ //partly drawn. so we decrement from_it
+ if (from_it!=itemlist.begin()) from_it--;
+
+ to_tick=x_to_tick(x2);
+ to_it=itemlist.upper_bound(to_tick);
+ //to_it now contains the first time which is not drawn at all any more
+
+ return need_redraw_for_hilighting(from_it, to_it);
+}
+
+bool ScoreCanvas::need_redraw_for_hilighting(ScoreItemList::iterator from_it, ScoreItemList::iterator to_it)
+{
+ //if we aren't playing, there will never be a need for redrawing due to highlighting things
+ if (audio->isPlaying()==false)
+ return false;
+
+ for (ScoreItemList::iterator it2=from_it; it2!=to_it; it2++)
+ for (set<FloItem, floComp>::iterator it=it2->second.begin(); it!=it2->second.end();it++)
+ if (it->type==FloItem::NOTE)
+ {
+ bool is_active= ( (song->cpos() >= it->source_event->tick() + it->source_part->tick()) &&
+ (song->cpos() < it->source_event->endTick() + it->source_part->tick()) );
+ if (it->is_active != is_active)
+ return true;
+ }
+
+ return false;
+}
+
int ScoreCanvas::clef_height(clef_t clef)
{
switch (clef) //CLEF_MARKER
@@ -1912,7 +1942,7 @@ void ScoreCanvas::draw_number(QPainter& p, int x, int y, int n)
string str=IntToStr(n);
int curr_x=x+DIGIT_WIDTH/2;
- for (int i=0;i<str.length(); i++)
+ for (size_t i=0;i<str.length(); i++)
{
draw_pixmap(p, curr_x, y, pix_num[str[i]-'0']);
curr_x+=DIGIT_WIDTH;
@@ -2012,9 +2042,11 @@ int ScoreCanvas::x_to_tick(int x)
return t > min_t ? t : min_t;
}
-tonart_t ScoreCanvas::key_at_tick(int t)
+tonart_t ScoreCanvas::key_at_tick(int t_)
{
tonart_t tmp;
+ unsigned int t= (t_>=0) ? t_ : 0;
+
for (ScoreEventList::iterator it=eventlist.begin(); it!=eventlist.end() && it->first<=t; it++)
if (it->second.type==FloEvent::KEY_CHANGE)
tmp=it->second.tonart;
@@ -2022,9 +2054,11 @@ tonart_t ScoreCanvas::key_at_tick(int t)
return tmp;
}
-timesig_t ScoreCanvas::timesig_at_tick(int t)
+timesig_t ScoreCanvas::timesig_at_tick(int t_)
{
timesig_t tmp;
+ unsigned int t= (t_>=0) ? t_ : 0;
+
for (ScoreEventList::iterator it=eventlist.begin(); it!=eventlist.end() && it->first<=t; it++)
if (it->second.type==FloEvent::TIME_SIG)
{
@@ -2070,7 +2104,7 @@ int ScoreCanvas::height_to_pitch(int h, clef_t clef, tonart_t key)
int ScoreCanvas::y_to_height(int y)
{
//Y_MARKER
- return int(rint(float(YDIST+4*YLEN - y)*2/YLEN))+2 ;
+ return int(nearbyint(float(YDIST+4*YLEN - y)*2.0/YLEN))+2 ;
}
int ScoreCanvas::y_to_pitch(int y, int t, clef_t clef)
@@ -2172,33 +2206,37 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event)
{
if ((event->button()==Qt::LeftButton) && (mouse_inserts_notes))
{
- song->startUndo();
- //stopping undo at the end of this function is unneccessary
- //because we'll begin a drag right after it. finishing
- //this drag will stop undo as well (in mouseReleaseEvent)
-
- Event newevent(Note);
- newevent.setPitch(y_to_pitch(y,tick, USED_CLEF));
- newevent.setVelo(64); //TODO
- newevent.setVeloOff(64); //TODO
- newevent.setTick(tick);
- newevent.setLenTick((new_len>0)?new_len:last_len);
-
- audio->msgAddEvent(newevent, curr_part, false, false, false);
-
- dragged_event_part=curr_part;
- dragged_event=newevent;
- dragged_event_original_pitch=newevent.pitch();
+ signed int relative_tick=(signed) tick - curr_part->tick();
+ if (relative_tick>=0) //TODO FINDMICH do that better
+ {
+ song->startUndo();
+ //stopping undo at the end of this function is unneccessary
+ //because we'll begin a drag right after it. finishing
+ //this drag will stop undo as well (in mouseReleaseEvent)
+
+ Event newevent(Note);
+ newevent.setPitch(y_to_pitch(y,tick, USED_CLEF));
+ newevent.setVelo(64); //TODO
+ newevent.setVeloOff(64); //TODO
+ newevent.setTick(relative_tick);
+ newevent.setLenTick((new_len>0)?new_len:last_len);
+
+ audio->msgAddEvent(newevent, curr_part, false, false, false);
+
+ dragged_event_part=curr_part;
+ dragged_event=newevent;
+ dragged_event_original_pitch=newevent.pitch();
- mouse_down_pos=event->pos();
- mouse_operation=NO_OP;
- mouse_x_drag_operation=LENGTH;
+ mouse_down_pos=event->pos();
+ mouse_operation=NO_OP;
+ mouse_x_drag_operation=LENGTH;
- song_changed(0);
+ song_changed(0);
- setMouseTracking(true);
- dragging=true;
- //song->startUndo(); unneccessary because we have started it already above
+ setMouseTracking(true);
+ dragging=true;
+ //song->startUndo(); unneccessary because we have started it already above
+ }
}
}
@@ -2242,7 +2280,6 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
int dx=event->x()-mouse_down_pos.x();
int dy=event->y()-mouse_down_pos.y();
- int y=event->y();
int x=event->x()+x_pos-x_left;
int tick=flo_quantize_floor(x_to_tick(x));
@@ -2286,10 +2323,12 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
break;
case BEGIN:
- if (dragged_event.tick() != tick)
+ if (dragged_event.tick()+dragged_event_part->tick() != tick)
{
Event tmp=dragged_event.clone();
- tmp.setTick(tick);
+
+ if (tick-signed(dragged_event_part->tick()) >= 0) //TODO FINDMICH do that better
+ tmp.setTick(tick-dragged_event_part->tick());
audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
dragged_event=tmp;
@@ -2301,10 +2340,12 @@ void ScoreCanvas::mouseMoveEvent (QMouseEvent* event)
case LENGTH:
tick+=FLO_QUANT;
- if (dragged_event.tick()+dragged_event.lenTick() != tick)
+ if (dragged_event.tick()+dragged_event.lenTick() + dragged_event_part->tick() != tick)
{
Event tmp=dragged_event.clone();
- tmp.setLenTick(tick-dragged_event.tick());
+
+ if (tick-signed(dragged_event.tick() -dragged_event_part->tick()) >= 0) //TODO FINDMICH do that better
+ tmp.setLenTick(tick-dragged_event.tick() -dragged_event_part->tick());
audio->msgChangeEvent(dragged_event, tmp, dragged_event_part, false, false, false);
dragged_event=tmp;
@@ -2415,19 +2456,22 @@ void ScoreCanvas::resizeEvent(QResizeEvent* ev)
void ScoreCanvas::pos_changed(int index, unsigned tick, bool scroll)
{
- if ((index==0) && scroll) //potential need to scroll?
+ if (index==0)
{
- switch (song->follow())
+ if (scroll) //potential need to scroll?
{
- case Song::NO: break;
- case Song::JUMP: goto_tick(tick,false); break;
- case Song::CONTINUOUS: goto_tick(tick,true); break;
+ switch (song->follow())
+ {
+ case Song::NO: break;
+ case Song::JUMP: goto_tick(tick,false); break;
+ case Song::CONTINUOUS: goto_tick(tick,true); break;
+ }
}
+
+ if (need_redraw_for_hilighting())
+ redraw();
}
}
-// TODO: testen: kommen die segfaults von muse oder von mir? [ von mir ]
-// TODO: testen, ob das noten-splitten korrekt arbeitet [ scheint zu klappen ]
-// TODO: testen, ob shift immer korrekt gesetzt wird [ scheint zu klappen ]
//the following assertions are made:
// pix_quarter.width() == pix_half.width()
@@ -2439,16 +2483,6 @@ void ScoreCanvas::pos_changed(int index, unsigned tick, bool scroll)
-// bei änderung
-// takt- oder tonartänderung:
-// alles ab der betreffenden position löschen
-// alles ab dort neu berechnen
-// notenänderung:
-// alle von der note betroffenen takte löschen und neuberechnen
-// aus erstem betroffenen takt müssen tie-infos gesichert werden
-// im takt nach dem letzten betroffenen müssen die tie-infos
-// geupdated werden. ggf. löschen ist unnötig, da ties nur wandern,
-// aber nicht verschwinden oder neu dazukommen werden.
//hint: recalculating event- and itemlists "from zero"
@@ -2477,6 +2511,11 @@ void ScoreCanvas::pos_changed(int index, unsigned tick, bool scroll)
* o check if "moving away" works for whole notes [seems to NOT work properly]
*
* less important stuff
+ * o when moving or resizing a note, so that its end is out-of-part,
+ * there's strange behaviour
+ * o redraw is called too often
+ * for example, when scroll is continuous, and note-hilighting has
+ * changed, redraw() is called twice
* o ties aren't always drawn correctly when the destination note
* is out of view
* o tied notes don't work properly when there's a key-change in
@@ -2497,6 +2536,7 @@ void ScoreCanvas::pos_changed(int index, unsigned tick, bool scroll)
* the change was introduced after 873815e57a5d1edc147710b524936b6f6260f555
* o refuse to resize so that width gets smaller or equal than x_left
* o set distances properly [looks okay, doesn't it?]
+ * o maybe eliminate all the compiler warnings
*
* stuff for the other muse developers
* o check if dragging notes is done correctly
diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h
index 84d61d11..3542a529 100644
--- a/muse2/muse/midiedit/scoreedit.h
+++ b/muse2/muse/midiedit/scoreedit.h
@@ -225,6 +225,8 @@ class FloItem
mutable int stem_x;
mutable QPixmap* pix;
+ mutable bool is_active;
+
QRect bbox() const;
@@ -405,6 +407,8 @@ struct cumulative_t
};
#define BLACK_PIXMAP (NUM_PARTCOLORS)
+#define HIGHLIGHTED_PIXMAP (NUM_PARTCOLORS+1)
+
struct timesig_t
{
int num;
@@ -453,13 +457,18 @@ class ScoreCanvas : public View
int calc_posadd(int t);
+
+ bool need_redraw_for_hilighting(ScoreItemList::iterator from_it, ScoreItemList::iterator to_it);
+ bool need_redraw_for_hilighting(int x1, int x2);
+ bool need_redraw_for_hilighting();
+
int canvas_width();
int viewport_width();
- QPixmap pix_whole[NUM_PARTCOLORS+1], pix_half[NUM_PARTCOLORS+1], pix_quarter[NUM_PARTCOLORS+1];
+ QPixmap pix_whole[NUM_PARTCOLORS+2], pix_half[NUM_PARTCOLORS+2], pix_quarter[NUM_PARTCOLORS+2];
QPixmap pix_r1, pix_r2, pix_r4, pix_r8, pix_r16;
- QPixmap pix_dot[NUM_PARTCOLORS+1], pix_flag_up[4], pix_flag_down[4];
- QPixmap pix_b[NUM_PARTCOLORS+1], pix_sharp[NUM_PARTCOLORS+1], pix_noacc[NUM_PARTCOLORS+1];
+ QPixmap pix_dot[NUM_PARTCOLORS+2], pix_flag_up[4], pix_flag_down[4];
+ QPixmap pix_b[NUM_PARTCOLORS+2], pix_sharp[NUM_PARTCOLORS+2], pix_noacc[NUM_PARTCOLORS+2];
QPixmap pix_num[10];
QPixmap pix_clef_violin, pix_clef_bass;