From 41ae38dea50566b54aa117fec1bc4fc173d29924 Mon Sep 17 00:00:00 2001
From: Florian Jung <flo@windfisch.org>
Date: Sun, 10 Apr 2011 15:29:12 +0000
Subject: clefs and time signatures with more than one digit were done
 correctly

---
 muse2/muse/midiedit/scoreedit.cpp | 243 +++++++++++++++++++++-----------------
 muse2/muse/midiedit/scoreedit.h   |  12 +-
 2 files changed, 143 insertions(+), 112 deletions(-)

(limited to 'muse2')

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);
-- 
cgit v1.2.3