Hey guys,

Here is a new feature, based on stable-0.4 (e5bc77f). It add, for the piano
roll, the possibility to mark single tone or a specified note based
diatonic scale (major and natural minor).
I think it also respond to this requested feature:
http://sourceforge.net/tracker/?func=detail&aid=3450211&group_id=105168&atid=640437

When are you planning to release the 0.4.13 ?  Because there are huge bugs
on piano roll and b+b editor when changing the time signature, and i may
have fixed them in few days.

regards,
From b118ec3be88bb9d74c2cf78a2de67eee9477efa7 Mon Sep 17 00:00:00 2001
From: NoiseByNorthwest <[email protected]>
Date: Sun, 29 Jan 2012 16:45:02 +0100
Subject: [PATCH] Add tone marking feature

---
 include/piano_roll.h   |   13 ++++-
 src/gui/piano_roll.cpp |  133 +++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 133 insertions(+), 13 deletions(-)

diff --git a/include/piano_roll.h b/include/piano_roll.h
index c00d649..7780875 100644
--- a/include/piano_roll.h
+++ b/include/piano_roll.h
@@ -141,6 +141,7 @@ protected slots:
 	void quantizeChanged();
 		
 	void changeNoteEditMode( int i );
+	void markTone( int i );
 
 
 private:
@@ -170,6 +171,14 @@ private:
 		NoteEditCount // make sure this one is always last
 	};
 
+	enum toneMarkerAction
+	{
+		tmmeUnmarkAll,
+		tmmeMarkCurrent,
+		tmmeMarkMinorScale,
+		tmmeMarkMajorScale,
+	};
+
 	enum pianoRollKeyTypes
 	{
 		PR_WHITE_KEY_SMALL,
@@ -179,7 +188,9 @@ private:
 
 	QVector<QString> m_nemStr; // gui names of each edit mode
 	QMenu * m_noteEditMenu; // when you right click below the key area
-	QSignalMapper * m_signalMapper; // to keep track of edit mode events
+
+	QList<int> m_markedTones;
+	QMenu * m_toneMarkerMenu; // when you right click on the key area
 
 	pianoRoll();
 	pianoRoll( const pianoRoll & );
diff --git a/src/gui/piano_roll.cpp b/src/gui/piano_roll.cpp
index 7bb995f..3ad36cc 100644
--- a/src/gui/piano_roll.cpp
+++ b/src/gui/piano_roll.cpp
@@ -43,6 +43,7 @@
 #endif
 
 #include <math.h>
+#include <algorithm>
 
 #include "piano_roll.h"
 #include "bb_track_container.h"
@@ -137,7 +138,7 @@ const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DefaultStepsPerTact;
 pianoRoll::pianoRoll() :
 	m_nemStr( QVector<QString>() ),
 	m_noteEditMenu( NULL ),
-	m_signalMapper( NULL ),
+	m_toneMarkerMenu( NULL ),
 	m_zoomingModel(),
 	m_quantizeModel(),
 	m_noteLenModel(),
@@ -172,19 +173,45 @@ pianoRoll::pianoRoll() :
 	m_nemStr.push_back( tr( "Note Volume" ) );
 	m_nemStr.push_back( tr( "Note Panning" ) );
 	
-	m_signalMapper = new QSignalMapper( this );
+	QSignalMapper * signalMapper = new QSignalMapper( this );
 	m_noteEditMenu = new QMenu( this );
 	m_noteEditMenu->clear();
 	for( int i=0; i<m_nemStr.size(); ++i )
 	{
 		QAction * act = new QAction( m_nemStr.at(i), this );
-		connect( act, SIGNAL(triggered()), m_signalMapper, SLOT(map()) );
-		m_signalMapper->setMapping( act, i );
+		connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
+		signalMapper->setMapping( act, i );
 		m_noteEditMenu->addAction( act );
 	}
-	connect( m_signalMapper, SIGNAL(mapped(int)), 
+	connect( signalMapper, SIGNAL(mapped(int)),
 			this, SLOT(changeNoteEditMode(int)) );
 	
+	signalMapper = new QSignalMapper( this );
+	m_toneMarkerMenu = new QMenu( this );
+
+	QAction * act = new QAction( tr("Mark/unmark current tone"), this );
+	connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
+	signalMapper->setMapping( act, static_cast<int>( tmmeMarkCurrent ) );
+	m_toneMarkerMenu->addAction( act );
+
+	act = new QAction( tr("Mark minor scale"), this );
+	connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
+	signalMapper->setMapping( act, static_cast<int>( tmmeMarkMinorScale ) );
+	m_toneMarkerMenu->addAction( act );
+
+	act = new QAction( tr("Mark major scale"), this );
+	connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
+	signalMapper->setMapping( act, static_cast<int>( tmmeMarkMajorScale ) );
+	m_toneMarkerMenu->addAction( act );
+
+	act = new QAction( tr("Unmark all"), this );
+	connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
+	signalMapper->setMapping( act, static_cast<int>( tmmeUnmarkAll ) );
+	m_toneMarkerMenu->addAction( act );
+
+	connect( signalMapper, SIGNAL(mapped(int)),
+			this, SLOT(markTone(int)) );
+
 	// init pixmaps
 	if( s_whiteKeySmallPm == NULL )
 	{
@@ -537,6 +564,63 @@ void pianoRoll::changeNoteEditMode( int i )
 }
 
 
+void pianoRoll::markTone( int i )
+{
+	static const int major_scale[KeysPerOctave] = {
+		1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1
+	};
+
+	static const int minor_scale[KeysPerOctave] = {
+		1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0
+	};
+
+	const int * scale = 0;
+	const int key = getKey( mapFromGlobal( m_toneMarkerMenu->pos() ).y() );
+
+	switch( static_cast<toneMarkerAction>( i ) )
+	{
+		case tmmeUnmarkAll:
+			m_markedTones.clear();
+			break;
+		case tmmeMarkCurrent:
+		{
+			QList<int>::iterator i = qFind( m_markedTones.begin(), m_markedTones.end(), key );
+			if( i != m_markedTones.end() )
+			{
+				m_markedTones.erase( i );
+			}
+			else
+			{
+				m_markedTones.push_back( key );
+			}
+			break;
+		}
+		case tmmeMarkMinorScale:
+			scale = minor_scale;
+		case tmmeMarkMajorScale:
+			if( ! scale )
+			{
+				scale = major_scale;
+			}
+
+			for( int i = 0; i <= NumKeys; i++ )
+			{
+				if( scale[std::abs( key - i ) % KeysPerOctave] )
+				{
+					m_markedTones.push_back( i );
+				}
+			}
+			break;
+		default:
+			;
+	}
+
+	qSort( m_markedTones.begin(), m_markedTones.end(), qGreater<int>() );
+	QList<int>::iterator new_end = std::unique( m_markedTones.begin(), m_markedTones.end() );
+	m_markedTones.erase( new_end, m_markedTones.end() );
+}
+
+
 pianoRoll::~pianoRoll()
 {
 }
@@ -1574,14 +1658,23 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
 		}
 		else if( _me->y() < keyAreaBottom() )
 		{
-			// clicked on keyboard on the left - play note
-			m_lastKey = key_num;
-			if( ! m_recording && ! engine::getSong()->isPlaying() )
+			// clicked on keyboard on the left
+			if( _me->buttons() == Qt::RightButton )
 			{
-				int v = ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * 127;
-				m_pattern->instrumentTrack()->processInEvent(
-							midiEvent( MidiNoteOn, 0, key_num, v ),
-							midiTime() );
+				// right click, tone marker contextual menu
+				m_toneMarkerMenu->popup( mapToGlobal( QPoint( _me->x(), _me->y() ) ) );
+			}
+			else
+			{
+				// left click - play the note
+				m_lastKey = key_num;
+				if( ! m_recording && ! engine::getSong()->isPlaying() )
+				{
+					int v = ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * 127;
+					m_pattern->instrumentTrack()->processInEvent(
+								midiEvent( MidiNoteOn, 0, key_num, v ),
+								midiTime() );
+				}
 			}
 		}
 		else
@@ -2609,6 +2702,22 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
 		++key;
 	}
 
+	// display note marks
+	for( int i = 0; i < m_markedTones.size(); i++ )
+	{
+		const int key_num = m_markedTones.at( i );
+		const int y = keyAreaBottom() + 5
+			- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
+
+		if( y > keyAreaBottom() )
+		{
+			break;
+		}
+
+		p.fillRect( WHITE_KEY_WIDTH, y,
+				width() - 10, 1,
+							QColor( 64, 64 + ( key_num % KeysPerOctave ) * 7, 96 + key_num ) );
+	}
 
 	// erase the area below the piano, because there might be keys that 
 	// should be only half-visible
-- 
1.7.5.4

------------------------------------------------------------------------------
Try before you buy = See our experts in action!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-dev2
_______________________________________________
LMMS-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmms-devel

Reply via email to