diff options
-rw-r--r-- | muse2/muse/midiedit/scoreedit.cpp | 243 | ||||
-rw-r--r-- | muse2/muse/midiedit/scoreedit.h | 12 |
2 files changed, 143 insertions, 112 deletions
diff --git a/muse2/muse/midiedit/scoreedit.cpp b/muse2/muse/midiedit/scoreedit.cpp index 1a264030..7222d18a 100644 --- a/muse2/muse/midiedit/scoreedit.cpp +++ b/muse2/muse/midiedit/scoreedit.cpp @@ -345,6 +345,8 @@ int n_accidentials(tonart_t t) //note needs to be 0..11 +//always assumes violin clef +//only for internal use note_pos_t ScoreCanvas::note_pos_(int note, tonart_t key) { note_pos_t result; @@ -424,7 +426,7 @@ note_pos_t ScoreCanvas::note_pos (int note, tonart_t key, clef_t clef) note_pos_t pos=note_pos_(note,key); - switch (clef) + switch (clef) //CLEF_MARKER { case VIOLIN: pos.height=pos.height + (octave-4)*7; @@ -611,6 +613,7 @@ list<note_len_t> ScoreCanvas::parse_note_len(int len_ticks, int begin_tick, vect } +#define USED_CLEF BASS #define YLEN 10 #define YDIST (2*YLEN) @@ -727,7 +730,7 @@ ScoreItemList ScoreCanvas::create_itemlist(ScoreEventList& eventlist) actual_tick=it->second.tick; if (actual_tick==-1) actual_tick=t; - note_pos_t notepos=note_pos(pitch,tmp_key,VIOLIN); //TODO einstellmöglichkeiten + note_pos_t notepos=note_pos(pitch,tmp_key,USED_CLEF); //TODO einstellmöglichkeiten printf("FLO: t=%i\ttype=%i\tpitch=%i\tvel=%i\tlen=%i\n",it->first, it->second.type, it->second.pitch, it->second.vel, it->second.len); cout << "\tline="<<notepos.height<<"\tvorzeichen="<<notepos.vorzeichen << endl; @@ -1382,9 +1385,9 @@ void ScoreCanvas::calc_item_pos(ScoreItemList& itemlist) } else if (it->type==FloItem::TIME_SIG) { - pos_add+=TIMESIG_POSADD; - - pos_add_list[it2->first]+=TIMESIG_POSADD; + int add=calc_timesig_width(it->num, it->denom); + pos_add+=add; + pos_add_list[it2->first]+=add; //+= is used instead of =, because a key- and time- //change can occur at the same time. } @@ -1392,39 +1395,11 @@ void ScoreCanvas::calc_item_pos(ScoreItemList& itemlist) { tonart_t new_key=it->tonart; - int aufloes_begin; //einschließlich - int aufloes_end; //ausschließlich! - int neue_vz_end; //ausschließlich! - - neue_vz_end=n_accidentials(new_key); - - int n_acc_drawn=0; - - //both are sharp or b keys? - if (is_sharp_key(curr_key) == is_sharp_key(new_key)) - { - // wenn new weniger vorzeichen hat als curr: - // löse nur diese auf - if (n_accidentials(curr_key)>n_accidentials(new_key)) - { - aufloes_begin=n_accidentials(new_key); - aufloes_end=n_accidentials(curr_key); - } - else - { - aufloes_begin=aufloes_end=0; //löse garnichts auf - } - } - else //different key-families (# and b mixed up) - { - aufloes_begin=0; - aufloes_end=n_accidentials(curr_key); - } - - n_acc_drawn=aufloes_end-aufloes_begin + neue_vz_end; - - pos_add+=n_acc_drawn*KEYCHANGE_ACC_DIST+ KEYCHANGE_ACC_LEFTDIST+ KEYCHANGE_ACC_RIGHTDIST; + list<int> aufloes_list=calc_accidentials(curr_key, USED_CLEF, new_key); + list<int> new_acc_list=calc_accidentials(new_key, USED_CLEF); + int n_acc_drawn=aufloes_list.size() + new_acc_list.size(); + pos_add+=n_acc_drawn*KEYCHANGE_ACC_DIST+ KEYCHANGE_ACC_LEFTDIST+ KEYCHANGE_ACC_RIGHTDIST; pos_add_list[it2->first]+=n_acc_drawn*KEYCHANGE_ACC_DIST+ KEYCHANGE_ACC_LEFTDIST+ KEYCHANGE_ACC_RIGHTDIST; //+= is used instead of =, because a key- and time- //change can occur at the same time. @@ -1640,62 +1615,22 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList cout << "\tTIME SIGNATURE: "<<it->num<<"/"<<it->denom<<endl; int y_coord=YDIST+2*YLEN; - p.drawPixmap(it->x + 5 -x_pos, y_coord, pix_num[it->denom]); - p.drawPixmap(it->x + 5 -x_pos, y_coord-NUMBER_HEIGHT, pix_num[it->num]); + draw_timesig(p, it->x - x_pos, y_coord, it->num, it->denom); } else if (it->type==FloItem::KEY_CHANGE) { tonart_t new_key=it->tonart; cout << "\tKEY CHANGE: from "<<curr_key<<" to "<<new_key<<endl; - - int sharp_pos[]={10,7,11,8,5,9,6}; - int b_pos[]={6,9,5,8,4,7,3}; - - int* aufloes_ptr; - int* neue_vz_ptr; - - aufloes_ptr = is_sharp_key(curr_key) ? sharp_pos : b_pos; - neue_vz_ptr = is_sharp_key(new_key) ? sharp_pos : b_pos; - - int aufloes_begin; //einschließlich - int aufloes_end; //ausschließlich! - int neue_vz_end; //ausschließlich! - - neue_vz_end=n_accidentials(new_key); - + int n_acc_drawn=0; - //both are sharp or b keys? - if (is_sharp_key(curr_key) == is_sharp_key(new_key)) - { - cout << "\tboth are # or b-keys" << endl; - // wenn new weniger vorzeichen hat als curr: - // löse nur diese auf - if (n_accidentials(curr_key)>n_accidentials(new_key)) - { - aufloes_begin=n_accidentials(new_key); - aufloes_end=n_accidentials(curr_key); - cout << "\taufloesen im intervall ["<<aufloes_begin<<";"<<aufloes_end<<"["<<endl; - } - else - { - aufloes_begin=aufloes_end=0; //löse garnichts auf - cout << "\tnichts wird aufgeloest"<<endl; - } - } - else - { - cout << "\tdifferent key-families (# and b mixed up)" << endl; - // löse alle auf - aufloes_begin=0; - aufloes_end=n_accidentials(curr_key); - cout << "\talle werden aufgeloest" << endl; - } + list<int> aufloes_list=calc_accidentials(curr_key, USED_CLEF, new_key); + list<int> new_acc_list=calc_accidentials(new_key, USED_CLEF); - // vorzeichen von [aufloes_begin;aufloes_end[ aus curr_key auflösen - for (int i=aufloes_begin; i<aufloes_end; i++) + // vorzeichen aus curr_key auflösen + for (list<int>::iterator acc_it=aufloes_list.begin(); acc_it!=aufloes_list.end(); acc_it++) { - int y_coord=YDIST+4*YLEN - ( aufloes_ptr[i] -2)*YLEN/2; //Y_MARKER + int y_coord=YDIST+4*YLEN - ( *acc_it -2)*YLEN/2; //Y_MARKER draw_pixmap(p,it->x + n_acc_drawn*KEYCHANGE_ACC_DIST + KEYCHANGE_ACC_LEFTDIST -x_pos,y_coord,pix_noacc); n_acc_drawn++; } @@ -1707,13 +1642,13 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList default_accidential[i]=NONE; // alle vorzeichen aus new_key zeichnen - for (int i=0; i<neue_vz_end; i++) + for (list<int>::iterator acc_it=new_acc_list.begin(); acc_it!=new_acc_list.end(); acc_it++) { - int y_coord=YDIST+4*YLEN - ( neue_vz_ptr[i] -2)*YLEN/2; //Y_MARKER + int y_coord=YDIST+4*YLEN - ( *acc_it -2)*YLEN/2; //Y_MARKER draw_pixmap(p,it->x + n_acc_drawn*KEYCHANGE_ACC_DIST + KEYCHANGE_ACC_LEFTDIST -x_pos,y_coord,*pix); n_acc_drawn++; - default_accidential[neue_vz_ptr[i]%7]=new_accidential; + default_accidential[*acc_it % 7]=new_accidential; } curr_key=new_key; @@ -1742,6 +1677,49 @@ void ScoreCanvas::draw_items(QPainter& p, ScoreItemList& itemlist, ScoreItemList } } +#define TIMESIG_LEFTMARGIN 5 +#define TIMESIG_RIGHTMARGIN 5 +#define DIGIT_YDIST 9 +#define DIGIT_WIDTH 12 + +void ScoreCanvas::draw_timesig(QPainter& p, int x, int y, int num, int denom) +{ + int num_width=calc_number_width(num); + int denom_width=calc_number_width(denom); + int width=((num_width > denom_width) ? num_width : denom_width); + int num_indent=(width-num_width)/2 + TIMESIG_LEFTMARGIN; + int denom_indent=(width-denom_width)/2 + TIMESIG_LEFTMARGIN; + + draw_number(p, x+num_indent, y-DIGIT_YDIST, num); + draw_number(p, x+denom_indent, y+DIGIT_YDIST, denom); +} + +int ScoreCanvas::calc_timesig_width(int num, int denom) +{ + int num_width=calc_number_width(num); + int denom_width=calc_number_width(denom); + int width=((num_width > denom_width) ? num_width : denom_width); + return width+TIMESIG_LEFTMARGIN+TIMESIG_RIGHTMARGIN; +} + +int ScoreCanvas::calc_number_width(int n) +{ + string str=IntToStr(n); + return (str.length()*DIGIT_WIDTH); +} + +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++) + { + draw_pixmap(p, curr_x, y, pix_num[str[i]-'0']); + curr_x+=DIGIT_WIDTH; + } +} + void ScoreCanvas::draw(QPainter& p, const QRect& rect) { @@ -1755,6 +1733,43 @@ void ScoreCanvas::draw(QPainter& p, const QRect& rect) draw_items(p, itemlist); } + +list<int> ScoreCanvas::calc_accidentials(tonart_t key, clef_t clef, tonart_t next_key) +{ + list<int> result; + + int violin_sharp_pos[]={10,7,11,8,5,9,6}; //CLEF_MARKER + int violin_b_pos[]={6,9,5,8,4,7,3}; + int bass_sharp_pos[]={8,5,9,6,3,7,4}; + int bass_b_pos[]={4,7,3,6,2,5,1}; + + int* accidential_pos; + + switch (clef) + { + case VIOLIN: accidential_pos = is_sharp_key(key) ? violin_sharp_pos : violin_b_pos; break; + case BASS: accidential_pos = is_sharp_key(key) ? bass_sharp_pos : bass_b_pos; break; + } + + int begin=0; + + if (is_sharp_key(key)==is_sharp_key(next_key)) //same kind of key (both b or both #)? + begin=n_accidentials(next_key); + else + begin=0; + + + int end=n_accidentials(key); + + for (int i=begin; i<end; i++) + result.push_back(accidential_pos[i]); + + return result; +} + + + + int ScoreCanvas::tick_to_x(int t) { int x=t*PIXELS_PER_WHOLE/TICKS_PER_WHOLE; @@ -1805,32 +1820,36 @@ tonart_t ScoreCanvas::key_at_tick(int t) return tmp; } -int ScoreCanvas::height_to_pitch(int h) +int ScoreCanvas::height_to_pitch(int h, clef_t clef) { int foo[]={0,2,4,5,7,9,11}; - - return foo[modulo(h,7)] + ( (h/7)*12 ) + 60; + + switch(clef) //CLEF_MARKER + { + case VIOLIN: return foo[modulo(h,7)] + ( (h/7)*12 ) + 60; + case BASS: return foo[modulo((h-5),7)] + ( ((h-5)/7)*12 ) + 48; + default: + cout << "WARNING: THIS SHOULD NEVER HAPPEN: unknown clef in height_to_pitch" << endl; + return 60; + } } -int ScoreCanvas::height_to_pitch(int h, tonart_t key) +int ScoreCanvas::height_to_pitch(int h, clef_t clef, tonart_t key) { int add=0; - int sharp_pos[]={10,7,11,8,5,9,6}; //TODO merge with draw function (where drawing accidentials) - int b_pos[]={6,9,5,8,4,7,3}; + list<int> accs=calc_accidentials(key,USED_CLEF); - int* acc_ptr = is_sharp_key(key) ? sharp_pos : b_pos; - - for (int i=0;i<n_accidentials(key);i++) + for (list<int>::iterator it=accs.begin(); it!=accs.end(); it++) { - if (modulo(acc_ptr[i],7) == modulo(h,7)) + if (modulo(*it,7) == modulo(h,7)) { add=is_sharp_key(key) ? 1 : -1; break; } } - return height_to_pitch(h)+add; + return height_to_pitch(h,clef)+add; } int ScoreCanvas::y_to_height(int y) @@ -1839,9 +1858,9 @@ int ScoreCanvas::y_to_height(int y) return int(rint(float(YDIST+4*YLEN - y)*2/YLEN))+2 ; } -int ScoreCanvas::y_to_pitch(int y, int t) +int ScoreCanvas::y_to_pitch(int y, int t, clef_t clef) { - return height_to_pitch(y_to_height(y), key_at_tick(t)); + return height_to_pitch(y_to_height(y), clef, key_at_tick(t)); } @@ -1944,7 +1963,7 @@ void ScoreCanvas::mousePressEvent (QMouseEvent* event) //this drag will stop undo as well (in mouseReleaseEvent) Event newevent(Note); - newevent.setPitch(y_to_pitch(y,tick)); + newevent.setPitch(y_to_pitch(y,tick, USED_CLEF)); newevent.setVelo(64); //TODO newevent.setVeloOff(64); //TODO newevent.setTick(tick); @@ -2119,27 +2138,30 @@ void ScoreCanvas::scroll_event(int x) /* BUGS and potential bugs - * o bass-clef (and all other clefs than the violin-clef) will - * cause strange behaviour, for example when drawing accidentials, - * calling y_to_pitch etc. * o when dividing, use a function which always rounds downwards * operator/ rounds towards zero. (-5)/7=0, but should be -1 * * IMPORTANT TODO * o removing the part the score's working on isn't handled - * + * o handle multiple tracks, with different color (QColor c(config.partColors[part->colorIndex()]);) * o let the user select the currently edited part - * - * o use a function for drawing timesig changes. support two(or more)-digit-numbers - * o create nice functions for drawing keychange-accidentials - * o draw clef, maybe support clef changes. support violin and bass at one time + * o draw clef, maybe support clef changes + * o support violin and bass at one time * o eliminate overlapping notes (e.g. C from 0 with len=10 and C from 5 with len=10) + * o use correct scrolling bounds + * o automatically scroll when playing + * o support selections * * less important stuff + * o create nice functions for drawing keychange-accidentials * o check if "moving away" works for whole notes [seems to NOT work properly] * o use bars instead of flags over groups of 8ths / 16ths etc * o (change ItemList into map< pos_t , mutable_stuff_t >) [no] * o deal with expanding parts or clip (expanding is better) + * o check if making the program clef-aware hasn't broken anything + * e.g. accidentials, creating notes, rendering etc. + * o replace all kinds of "full-measure-rests" with the whole rest + * in the middle of the measure * * stuff for the other muse developers * o check if dragging notes is done correctly @@ -2149,9 +2171,12 @@ void ScoreCanvas::scroll_event(int x) * o process key from muse's event list (has to be implemented first in muse) * o process accurate timesignatures from muse's list (has to be implemented first in muse) * ( (2+2+3)/4 or (3+2+2)/4 instead of 7/4 ) + * o maybe do expanding parts inside the msgChangeEvent or + * msgNewEvent functions (see my e-mail) * * GUI stuff * o offer a button for bool mouse_erases_notes and mouse_inserts_notes * o offer dropdown-boxes for lengths of the inserted note * (select between 16th, 8th, ... whole and "last used length") + * o offer a dropdown-box for the clef to use */ diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h index ab35e5b6..6c2a75ce 100644 --- a/muse2/muse/midiedit/scoreedit.h +++ b/muse2/muse/midiedit/scoreedit.h @@ -416,11 +416,17 @@ class ScoreCanvas : public View void draw_items(QPainter& p, ScoreItemList& itemlist, int x1, int x2); void draw_items(QPainter& p, ScoreItemList& itemlist); void calc_item_pos(ScoreItemList& itemlist); + list<int> calc_accidentials(tonart_t key, clef_t clef, tonart_t next_key=C); - int y_to_pitch(int y, int t); + void draw_timesig(QPainter& p, int x, int y, int num, int denom); + int calc_timesig_width(int num, int denom); + void draw_number(QPainter& p, int x, int y, int n); + int calc_number_width(int n); + + int y_to_pitch(int y, int t, clef_t clef); int y_to_height(int y); - int height_to_pitch(int h, tonart_t key); - int height_to_pitch(int h); + int height_to_pitch(int h, clef_t clef, tonart_t key); + int height_to_pitch(int h, clef_t clef); tonart_t key_at_tick(int t); int tick_to_x(int t); |