Piano-roll: scale & arpeggio combobox + micro refactoring of ChordCreator::Chord

Signed-off-by: Tobias Doerffel <tobias.doerffel@gmail.com>
This commit is contained in:
NoiseByNorthwest
2012-02-01 15:09:49 +01:00
committed by Tobias Doerffel
parent 1a09828ad4
commit a6ae31a08e
6 changed files with 421 additions and 176 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

View File

@@ -36,12 +36,17 @@ class InstrumentTrack;
class notePlayHandle;
const int MAX_CHORD_POLYPHONY = 10;
class ChordCreator : public Model, public JournallingObject
{
Q_OBJECT
public:
static const int MAX_CHORD_POLYPHONY = 10;
private:
typedef Sint8 ChordSemiTones [MAX_CHORD_POLYPHONY];
public:
ChordCreator( Model * _parent );
virtual ~ChordCreator();
@@ -58,22 +63,84 @@ public:
}
static struct Chord
struct Chord
{
const QString name;
Sint8 interval[MAX_CHORD_POLYPHONY];
} s_chordTable[];
private:
QString m_name;
ChordSemiTones m_semiTones;
int m_size;
public:
Chord() : m_size( 0 ) {}
static inline int getChordSize( Chord & _c )
{
int idx = 0;
while( _c.interval[idx] != -1 )
Chord( const char * n, const ChordSemiTones & semi_tones );
int size() const
{
++idx;
return m_size;
}
return idx;
}
bool isScale() const
{
return size() > 6;
}
bool isEmpty() const
{
return size() == 0;
}
bool hasSemiTone( Sint8 semi_tone ) const;
Sint8 last() const
{
return m_semiTones[size() - 1];
}
const QString & getName() const
{
return m_name;
}
Sint8 operator [] ( int n ) const
{
return m_semiTones[n];
}
};
struct ChordTable : public QVector<Chord>
{
private:
ChordTable();
struct Init
{
const char * m_name;
ChordSemiTones m_semiTones;
};
static Init s_initTable[];
public:
static const ChordTable & getInstance()
{
static ChordTable inst;
return inst;
}
const Chord & getByName( const QString & name, bool is_scale = false ) const;
const Chord & getScaleByName( const QString & name ) const
{
return getByName( name, true );
}
const Chord & getChordByName( const QString & name ) const
{
return getByName( name, false );
}
};
private:

View File

@@ -139,9 +139,16 @@ protected slots:
void zoomingChanged();
void quantizeChanged();
void updateSemiToneMarkerMenu();
void changeNoteEditMode( int i );
void markTone( int i );
void markSemiTone( int i );
signals:
void semiToneMarkerMenuScaleSetEnabled(bool);
void semiToneMarkerMenuChordSetEnabled(bool);
private:
@@ -171,12 +178,12 @@ private:
NoteEditCount // make sure this one is always last
};
enum toneMarkerAction
enum semiToneMarkerAction
{
tmmeUnmarkAll,
tmmeMarkCurrent,
tmmeMarkMinorScale,
tmmeMarkMajorScale,
stmaUnmarkAll,
stmaMarkCurrentSemiTone,
stmaMarkCurrentScale,
stmaMarkCurrentChord,
};
enum pianoRollKeyTypes
@@ -189,8 +196,8 @@ private:
QVector<QString> m_nemStr; // gui names of each edit mode
QMenu * m_noteEditMenu; // when you right click below the key area
QList<int> m_markedTones;
QMenu * m_toneMarkerMenu; // when you right click on the key area
QList<int> m_markedSemiTones;
QMenu * m_semiToneMarkerMenu; // when you right click on the key area
pianoRoll();
pianoRoll( const pianoRoll & );
@@ -251,10 +258,14 @@ private:
comboBox * m_zoomingComboBox;
comboBox * m_quantizeComboBox;
comboBox * m_noteLenComboBox;
comboBox * m_scaleComboBox;
comboBox * m_chordComboBox;
ComboBoxModel m_zoomingModel;
ComboBoxModel m_quantizeModel;
ComboBoxModel m_noteLenModel;
ComboBoxModel m_scaleModel;
ComboBoxModel m_chordModel;

View File

@@ -33,118 +33,177 @@
ChordCreator::Chord ChordCreator::s_chordTable[] =
ChordCreator::ChordTable::Init ChordCreator::ChordTable::s_initTable[] =
{
{ ChordCreator::tr( "octave" ), { 0, -1 } },
{ ChordCreator::tr( "Major" ), { 0, 4, 7, -1 } },
{ ChordCreator::tr( "Majb5" ), { 0, 4, 6, -1 } },
{ ChordCreator::tr( "minor" ), { 0, 3, 7, -1 } },
{ ChordCreator::tr( "minb5" ), { 0, 3, 6, -1 } },
{ ChordCreator::tr( "sus2" ), { 0, 2, 7, -1 } },
{ ChordCreator::tr( "sus4" ), { 0, 5, 7, -1 } },
{ ChordCreator::tr( "aug" ), { 0, 4, 8, -1 } },
{ ChordCreator::tr( "augsus4" ), { 0, 5, 8, -1 } },
{ ChordCreator::tr( "tri" ), { 0, 3, 6, 9, -1 } },
{ "octave", { 0, -1 } },
{ "Major" , { 0, 4, 7, -1 } },
{ "Majb5" , { 0, 4, 6, -1 } },
{ "minor" , { 0, 3, 7, -1 } },
{ "minb5" , { 0, 3, 6, -1 } },
{ "sus2" , { 0, 2, 7, -1 } },
{ "sus4" , { 0, 5, 7, -1 } },
{ "aug" , { 0, 4, 8, -1 } },
{ "augsus4" , { 0, 5, 8, -1 } },
{ "tri" , { 0, 3, 6, 9, -1 } },
{ ChordCreator::tr( "6" ), { 0, 4, 7, 9, -1 } },
{ ChordCreator::tr( "6sus4" ), { 0, 5, 7, 9, -1 } },
{ ChordCreator::tr( "6add9" ), { 0, 4, 7, 12, -1 } },
{ ChordCreator::tr( "m6" ), { 0, 3, 7, 9, -1 } },
{ ChordCreator::tr( "m6add9" ), { 0, 3, 7, 9, 14, -1 } },
{ "6" , { 0, 4, 7, 9, -1 } },
{ "6sus4" , { 0, 5, 7, 9, -1 } },
{ "6add9" , { 0, 4, 7, 12, -1 } },
{ "m6" , { 0, 3, 7, 9, -1 } },
{ "m6add9" , { 0, 3, 7, 9, 14, -1 } },
{ ChordCreator::tr( "7" ), { 0, 4, 7, 10, -1 } },
{ ChordCreator::tr( "7sus4" ), { 0, 5, 7, 10, -1 } },
{ ChordCreator::tr( "7#5" ), { 0, 4, 8, 10, -1 } },
{ ChordCreator::tr( "7b5" ), { 0, 4, 6, 10, -1 } },
{ ChordCreator::tr( "7#9" ), { 0, 4, 7, 10, 13, 18, -1 } },
{ ChordCreator::tr( "7b9" ), { 0, 4, 7, 10, 13, 16, -1 } },
{ ChordCreator::tr( "7#5#9" ), { 0, 4, 8, 12, 14, 19, -1 } },
{ ChordCreator::tr( "7#5b9" ), { 0, 4, 8, 12, 14, 17, -1 } },
{ ChordCreator::tr( "7b5b9" ), { 0, 4, 6, 10, 12, 15, -1 } },
{ ChordCreator::tr( "7add11" ), { 0, 4, 7, 10, 17, -1 } },
{ ChordCreator::tr( "7add13" ), { 0, 4, 7, 10, 21, -1 } },
{ ChordCreator::tr( "7#11" ), { 0, 4, 7, 10, 18, -1 } },
{ ChordCreator::tr( "Maj7" ), { 0, 4, 7, 11, -1 } },
{ ChordCreator::tr( "Maj7b5" ), { 0, 4, 6, 11, -1 } },
{ ChordCreator::tr( "Maj7#5" ), { 0, 4, 8, 11, -1 } },
{ ChordCreator::tr( "Maj7#11" ), { 0, 4, 7, 11, 18, -1 } },
{ ChordCreator::tr( "Maj7add13" ), { 0, 4, 7, 11, 21, -1 } },
{ ChordCreator::tr( "m7" ), { 0, 3, 7, 10, -1 } },
{ ChordCreator::tr( "m7b5" ), { 0, 3, 6, 10, -1 } },
{ ChordCreator::tr( "m7b9" ), { 0, 3, 7, 10, 13, -1 } },
{ ChordCreator::tr( "m7add11" ), { 0, 3, 7, 10, 17, -1 } },
{ ChordCreator::tr( "m7add13" ), { 0, 3, 7, 10, 21, -1 } },
{ ChordCreator::tr( "m-Maj7" ), { 0, 3, 7, 11, -1 } },
{ ChordCreator::tr( "m-Maj7add11" ), { 0, 3, 7, 11, 17, -1 } },
{ ChordCreator::tr( "m-Maj7add13" ), { 0, 3, 7, 11, 21, -1 } },
{ "7" , { 0, 4, 7, 10, -1 } },
{ "7sus4" , { 0, 5, 7, 10, -1 } },
{ "7#5" , { 0, 4, 8, 10, -1 } },
{ "7b5" , { 0, 4, 6, 10, -1 } },
{ "7#9" , { 0, 4, 7, 10, 13, 18, -1 } },
{ "7b9" , { 0, 4, 7, 10, 13, 16, -1 } },
{ "7#5#9" , { 0, 4, 8, 12, 14, 19, -1 } },
{ "7#5b9" , { 0, 4, 8, 12, 14, 17, -1 } },
{ "7b5b9" , { 0, 4, 6, 10, 12, 15, -1 } },
{ "7add11" , { 0, 4, 7, 10, 17, -1 } },
{ "7add13" , { 0, 4, 7, 10, 21, -1 } },
{ "7#11" , { 0, 4, 7, 10, 18, -1 } },
{ "Maj7" , { 0, 4, 7, 11, -1 } },
{ "Maj7b5" , { 0, 4, 6, 11, -1 } },
{ "Maj7#5" , { 0, 4, 8, 11, -1 } },
{ "Maj7#11" , { 0, 4, 7, 11, 18, -1 } },
{ "Maj7add13" , { 0, 4, 7, 11, 21, -1 } },
{ "m7" , { 0, 3, 7, 10, -1 } },
{ "m7b5" , { 0, 3, 6, 10, -1 } },
{ "m7b9" , { 0, 3, 7, 10, 13, -1 } },
{ "m7add11" , { 0, 3, 7, 10, 17, -1 } },
{ "m7add13" , { 0, 3, 7, 10, 21, -1 } },
{ "m-Maj7" , { 0, 3, 7, 11, -1 } },
{ "m-Maj7add11" , { 0, 3, 7, 11, 17, -1 } },
{ "m-Maj7add13" , { 0, 3, 7, 11, 21, -1 } },
{ ChordCreator::tr( "9" ), { 0, 4, 7, 10, 14, -1 } },
{ ChordCreator::tr( "9sus4" ), { 0, 5, 7, 10, 14, -1 } },
{ ChordCreator::tr( "add9" ), { 0, 4, 7, 14, -1 } },
{ ChordCreator::tr( "9#5" ), { 0, 4, 8, 10, 14, -1 } },
{ ChordCreator::tr( "9b5" ), { 0, 4, 6, 10, 14, -1 } },
{ ChordCreator::tr( "9#11" ), { 0, 4, 7, 10, 14, 18, -1 } },
{ ChordCreator::tr( "9b13" ), { 0, 4, 7, 10, 14, 20, -1 } },
{ ChordCreator::tr( "Maj9" ), { 0, 4, 7, 11, 14, -1 } },
{ ChordCreator::tr( "Maj9sus4" ), { 0, 5, 7, 11, 15, -1 } },
{ ChordCreator::tr( "Maj9#5" ), { 0, 4, 8, 11, 14, -1 } },
{ ChordCreator::tr( "Maj9#11" ), { 0, 4, 7, 11, 14, 18, -1 } },
{ ChordCreator::tr( "m9" ), { 0, 3, 7, 10, 14, -1 } },
{ ChordCreator::tr( "madd9" ), { 0, 3, 7, 14, -1 } },
{ ChordCreator::tr( "m9b5" ), { 0, 3, 6, 10, 14, -1 } },
{ ChordCreator::tr( "m9-Maj7" ), { 0, 3, 7, 11, 14, -1 } },
{ "9" , { 0, 4, 7, 10, 14, -1 } },
{ "9sus4" , { 0, 5, 7, 10, 14, -1 } },
{ "add9" , { 0, 4, 7, 14, -1 } },
{ "9#5" , { 0, 4, 8, 10, 14, -1 } },
{ "9b5" , { 0, 4, 6, 10, 14, -1 } },
{ "9#11" , { 0, 4, 7, 10, 14, 18, -1 } },
{ "9b13" , { 0, 4, 7, 10, 14, 20, -1 } },
{ "Maj9" , { 0, 4, 7, 11, 14, -1 } },
{ "Maj9sus4" , { 0, 5, 7, 11, 15, -1 } },
{ "Maj9#5" , { 0, 4, 8, 11, 14, -1 } },
{ "Maj9#11" , { 0, 4, 7, 11, 14, 18, -1 } },
{ "m9" , { 0, 3, 7, 10, 14, -1 } },
{ "madd9" , { 0, 3, 7, 14, -1 } },
{ "m9b5" , { 0, 3, 6, 10, 14, -1 } },
{ "m9-Maj7" , { 0, 3, 7, 11, 14, -1 } },
{ ChordCreator::tr( "11" ), { 0, 4, 7, 10, 14, 17, -1 } },
{ ChordCreator::tr( "11b9" ), { 0, 4, 7, 10, 13, 17, -1 } },
{ ChordCreator::tr( "Maj11" ), { 0, 4, 7, 11, 14, 17, -1 } },
{ ChordCreator::tr( "m11" ), { 0, 3, 7, 10, 14, 17, -1 } },
{ ChordCreator::tr( "m-Maj11" ), { 0, 3, 7, 11, 14, 17, -1 } },
{ "11" , { 0, 4, 7, 10, 14, 17, -1 } },
{ "11b9" , { 0, 4, 7, 10, 13, 17, -1 } },
{ "Maj11" , { 0, 4, 7, 11, 14, 17, -1 } },
{ "m11" , { 0, 3, 7, 10, 14, 17, -1 } },
{ "m-Maj11" , { 0, 3, 7, 11, 14, 17, -1 } },
{ ChordCreator::tr( "13" ), { 0, 4, 7, 10, 14, 21, -1 } },
{ ChordCreator::tr( "13#9" ), { 0, 4, 7, 10, 15, 21, -1 } },
{ ChordCreator::tr( "13b9" ), { 0, 4, 7, 10, 13, 21, -1 } },
{ ChordCreator::tr( "13b5b9" ), { 0, 4, 6, 10, 13, 21, -1 } },
{ ChordCreator::tr( "Maj13" ), { 0, 4, 7, 11, 14, 21, -1 } },
{ ChordCreator::tr( "m13" ), { 0, 3, 7, 10, 14, 21, -1 } },
{ ChordCreator::tr( "m-Maj13" ), { 0, 3, 7, 11, 14, 21, -1 } },
{ ChordCreator::tr( "Major" ), { 0, 2, 4, 5, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Harmonic minor" ), { 0, 2, 3, 5, 7, 8, 11, -1 } },
{ ChordCreator::tr( "Melodic minor" ), { 0, 2, 3, 5, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Whole tone" ), { 0, 2, 4, 6, 8, 10, -1 } },
{ ChordCreator::tr( "Diminished" ), { 0, 2, 3, 5, 6, 8, 9, 11, -1 } },
{ ChordCreator::tr( "Major pentatonic" ), { 0, 2, 4, 7, 10, -1 } },
{ ChordCreator::tr( "Minor pentatonic" ), { 0, 3, 5, 7, 10, -1 } },
{ ChordCreator::tr( "Jap in sen" ), { 0, 1, 5, 7, 10, -1 } },
{ ChordCreator::tr( "Major bebop" ), { 0, 2, 4, 5, 7, 8, 9, 11, -1 } },
{ ChordCreator::tr( "Dominant bebop" ), { 0, 2, 4, 5, 7, 9, 10, 11, -1 } },
{ ChordCreator::tr( "Blues" ), { 0, 3, 5, 6, 7, 10, -1 } },
{ ChordCreator::tr( "Arabic" ), { 0, 1, 4, 5, 7, 8, 11, -1 } },
{ ChordCreator::tr( "Enigmatic" ), { 0, 1, 4, 6, 8, 10, 11, -1 } },
{ ChordCreator::tr( "Neopolitan" ), { 0, 1, 3, 5, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Neopolitan minor" ), { 0, 1, 3, 5, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Hungarian minor" ), { 0, 2, 3, 6, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Dorian" ), { 0, 2, 3, 5, 7, 9, 10, -1 } },
{ ChordCreator::tr( "Phrygolydian" ), { 0, 1, 3, 5, 7, 8, 10, -1 } },
{ ChordCreator::tr( "Lydian" ), { 0, 2, 4, 6, 7, 9, 11, -1 } },
{ ChordCreator::tr( "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, -1 } },
{ ChordCreator::tr( "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, -1 } },
{ ChordCreator::tr( "Locrian" ), { 0, 1, 3, 5, 6, 8, 10, -1 } },
{ "", { -1, -1 } }
{ "13" , { 0, 4, 7, 10, 14, 21, -1 } },
{ "13#9" , { 0, 4, 7, 10, 15, 21, -1 } },
{ "13b9" , { 0, 4, 7, 10, 13, 21, -1 } },
{ "13b5b9" , { 0, 4, 6, 10, 13, 21, -1 } },
{ "Maj13" , { 0, 4, 7, 11, 14, 21, -1 } },
{ "m13" , { 0, 3, 7, 10, 14, 21, -1 } },
{ "m-Maj13" , { 0, 3, 7, 11, 14, 21, -1 } },
{ "Major" , { 0, 2, 4, 5, 7, 9, 11, -1 } },
{ "Harmonic minor" , { 0, 2, 3, 5, 7, 8, 11, -1 } },
{ "Melodic minor" , { 0, 2, 3, 5, 7, 9, 11, -1 } },
{ "Whole tone" , { 0, 2, 4, 6, 8, 10, -1 } },
{ "Diminished" , { 0, 2, 3, 5, 6, 8, 9, 11, -1 } },
{ "Major pentatonic" , { 0, 2, 4, 7, 10, -1 } },
{ "Minor pentatonic" , { 0, 3, 5, 7, 10, -1 } },
{ "Jap in sen" , { 0, 1, 5, 7, 10, -1 } },
{ "Major bebop" , { 0, 2, 4, 5, 7, 8, 9, 11, -1 } },
{ "Dominant bebop" , { 0, 2, 4, 5, 7, 9, 10, 11, -1 } },
{ "Blues" , { 0, 3, 5, 6, 7, 10, -1 } },
{ "Arabic" , { 0, 1, 4, 5, 7, 8, 11, -1 } },
{ "Enigmatic" , { 0, 1, 4, 6, 8, 10, 11, -1 } },
{ "Neopolitan" , { 0, 1, 3, 5, 7, 9, 11, -1 } },
{ "Neopolitan minor" , { 0, 1, 3, 5, 7, 8, 11, -1 } },
{ "Hungarian minor" , { 0, 2, 3, 6, 7, 8, 11, -1 } },
{ "Dorian" , { 0, 2, 3, 5, 7, 9, 10, -1 } },
{ "Phrygolydian" , { 0, 1, 3, 5, 7, 8, 10, -1 } },
{ "Lydian" , { 0, 2, 4, 6, 7, 9, 11, -1 } },
{ "Mixolydian" , { 0, 2, 4, 5, 7, 9, 10, -1 } },
{ "Aeolian" , { 0, 2, 3, 5, 7, 8, 10, -1 } },
{ "Locrian" , { 0, 1, 3, 5, 6, 8, 10, -1 } },
} ;
ChordCreator::Chord::Chord( const char * n, const ChordSemiTones & semi_tones ) :
m_name( tr( n ) )
{
for( m_size = 0; m_size < MAX_CHORD_POLYPHONY; m_size++ )
{
if( semi_tones[m_size] == -1 )
{
break;
}
m_semiTones[m_size] = semi_tones[m_size];
}
}
bool ChordCreator::Chord::hasSemiTone( Sint8 semi_tone ) const
{
for( int i = 0; i < size(); ++i )
{
if( semi_tone == m_semiTones[i] )
return true;
}
return false;
}
ChordCreator::ChordTable::ChordTable() :
QVector<Chord>()
{
for( int i = 0;
i < static_cast<int>( sizeof s_initTable / sizeof *s_initTable );
i++ )
{
push_back( Chord( s_initTable[i].m_name, s_initTable[i].m_semiTones ) );
}
}
const ChordCreator::Chord & ChordCreator::ChordTable::getByName( const QString & name, bool is_scale ) const
{
for( int i = 0; i < size(); i++ )
{
if( at( i ).getName() == name && is_scale == at( i ).isScale() )
return at( i );
}
static Chord empty;
return empty;
}
ChordCreator::ChordCreator( Model * _parent ) :
Model( _parent, tr( "Chords" ) ),
m_chordsEnabledModel( false, this ),
m_chordsModel( this, tr( "Chord type" ) ),
m_chordRangeModel( 1.0f, 1.0f, 9.0f, 1.0f, this, tr( "Chord range" ) )
{
for( int i = 0; s_chordTable[i].interval[0] != -1; ++i )
const ChordTable & chord_table = ChordTable::getInstance();
for( int i = 0; i < chord_table.size(); ++i )
{
m_chordsModel.addItem( tr( s_chordTable[i].name.toUtf8().
m_chordsModel.addItem( tr( chord_table[i].getName().toUtf8().
constData() ) );
}
}
@@ -162,6 +221,7 @@ ChordCreator::~ChordCreator()
void ChordCreator::processNote( notePlayHandle * _n )
{
const int base_note_key = _n->key();
const ChordTable & chord_table = ChordTable::getInstance();
// we add chord-subnotes to note if either note is a base-note and
// arpeggio is not used or note is part of an arpeggio
// at the same time we only add sub-notes if nothing of the note was
@@ -186,13 +246,13 @@ void ChordCreator::processNote( notePlayHandle * _n )
// create it in the following loop, then we loop until
// there's a -1 in the interval-array
for( int i = ( octave_cnt == 0 ) ? 1 : 0;
s_chordTable[selected_chord].interval[i] != -1;
i < chord_table[selected_chord].size();
++i )
{
// add interval to sub-note-key
const int sub_note_key = sub_note_key_base +
(int) s_chordTable[
selected_chord].interval[i];
(int) chord_table[
selected_chord][i];
// maybe we're out of range -> let's get outta
// here!
if( sub_note_key > NumKeys )
@@ -255,11 +315,11 @@ Arpeggiator::Arpeggiator( Model * _parent ) :
m_arpDirectionModel( this, tr( "Arpeggio direction" ) ),
m_arpModeModel( this, tr( "Arpeggio mode" ) )
{
for( int i = 0; ChordCreator::s_chordTable[i].interval[0] != -1; ++i )
const ChordCreator::ChordTable & chord_table = ChordCreator::ChordTable::getInstance();
for( int i = 0; i < chord_table[i].size(); ++i )
{
m_arpModel.addItem( ChordCreator::tr(
ChordCreator::s_chordTable[i].
name.toUtf8().constData() ) );
chord_table[i].getName().toUtf8().constData() ) );
}
m_arpDirectionModel.addItem( tr( "Up" ), new PixmapLoader( "arp_up" ) );
@@ -314,8 +374,8 @@ void Arpeggiator::processNote( notePlayHandle * _n )
}
}
const int cur_chord_size = ChordCreator::getChordSize(
ChordCreator::s_chordTable[selected_arp] );
const ChordCreator::ChordTable & chord_table = ChordCreator::ChordTable::getInstance();
const int cur_chord_size = chord_table[selected_arp].size();
const int range = (int)( cur_chord_size * m_arpRangeModel.value() );
const int total_range = range * cnphv.size();
@@ -401,8 +461,7 @@ void Arpeggiator::processNote( notePlayHandle * _n )
const int sub_note_key = base_note_key + (cur_arp_idx /
cur_chord_size ) *
KeysPerOctave +
ChordCreator::s_chordTable[selected_arp].
interval[cur_arp_idx % cur_chord_size];
chord_table[selected_arp][cur_arp_idx % cur_chord_size];
// range-checking
if( sub_note_key >= NumKeys ||

View File

@@ -138,7 +138,7 @@ const int DEFAULT_PR_PPT = KEY_LINE_HEIGHT * DefaultStepsPerTact;
pianoRoll::pianoRoll() :
m_nemStr( QVector<QString>() ),
m_noteEditMenu( NULL ),
m_toneMarkerMenu( NULL ),
m_semiToneMarkerMenu( NULL ),
m_zoomingModel(),
m_quantizeModel(),
m_noteLenModel(),
@@ -187,30 +187,34 @@ pianoRoll::pianoRoll() :
this, SLOT(changeNoteEditMode(int)) );
signalMapper = new QSignalMapper( this );
m_toneMarkerMenu = new QMenu( this );
m_semiToneMarkerMenu = new QMenu( this );
QAction * act = new QAction( tr("Mark/unmark current tone"), this );
QAction * act = new QAction( tr("Mark/unmark current semitone"), this );
connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
signalMapper->setMapping( act, static_cast<int>( tmmeMarkCurrent ) );
m_toneMarkerMenu->addAction( act );
signalMapper->setMapping( act, static_cast<int>( stmaMarkCurrentSemiTone ) );
m_semiToneMarkerMenu->addAction( act );
act = new QAction( tr("Mark minor scale"), this );
act = new QAction( tr("Mark current scale"), this );
act->setEnabled( false );
connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
signalMapper->setMapping( act, static_cast<int>( tmmeMarkMinorScale ) );
m_toneMarkerMenu->addAction( act );
connect( this, SIGNAL(semiToneMarkerMenuScaleSetEnabled(bool)), act, SLOT(setEnabled(bool)) );
signalMapper->setMapping( act, static_cast<int>( stmaMarkCurrentScale ) );
m_semiToneMarkerMenu->addAction( act );
act = new QAction( tr("Mark major scale"), this );
act = new QAction( tr("Mark current chord"), this );
act->setEnabled( false );
connect( act, SIGNAL(triggered()), signalMapper, SLOT(map()) );
signalMapper->setMapping( act, static_cast<int>( tmmeMarkMajorScale ) );
m_toneMarkerMenu->addAction( act );
connect( this, SIGNAL(semiToneMarkerMenuChordSetEnabled(bool)), act, SLOT(setEnabled(bool)) );
signalMapper->setMapping( act, static_cast<int>( stmaMarkCurrentChord ) );
m_semiToneMarkerMenu->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 );
signalMapper->setMapping( act, static_cast<int>( stmaUnmarkAll ) );
m_semiToneMarkerMenu->addAction( act );
connect( signalMapper, SIGNAL(mapped(int)),
this, SLOT(markTone(int)) );
this, SLOT(markSemiTone(int)) );
// init pixmaps
if( s_whiteKeySmallPm == NULL )
@@ -498,6 +502,52 @@ pianoRoll::pianoRoll() :
this, SLOT( quantizeChanged() ) );
const ChordCreator::ChordTable & chord_table = ChordCreator::ChordTable::getInstance();
// setup scale-stuff
QLabel * scale_lbl = new QLabel( m_toolBar );
scale_lbl->setPixmap( embed::getIconPixmap( "scale" ) );
m_scaleModel.addItem( tr("No scale") );
for( int i = 0; i < chord_table.size(); ++i )
{
if( chord_table[i].isScale() )
{
m_scaleModel.addItem( chord_table[i].getName() );
}
}
m_scaleModel.setValue( 0 );
m_scaleComboBox = new comboBox( m_toolBar );
m_scaleComboBox->setModel( &m_scaleModel );
m_scaleComboBox->setFixedSize( 105, 22 );
// change can update m_semiToneMarkerMenu
connect( &m_scaleModel, SIGNAL( dataChanged() ),
this, SLOT( updateSemiToneMarkerMenu() ) );
// setup chord-stuff
QLabel * chord_lbl = new QLabel( m_toolBar );
chord_lbl->setPixmap( embed::getIconPixmap( "chord" ) );
m_chordModel.addItem( tr("No chord") );
for( int i = 0; i < chord_table.size(); ++i )
{
if( ! chord_table[i].isScale() )
{
m_chordModel.addItem( chord_table[i].getName() );
}
}
m_chordModel.setValue( 0 );
m_chordComboBox = new comboBox( m_toolBar );
m_chordComboBox->setModel( &m_chordModel );
m_chordComboBox->setFixedSize( 105, 22 );
// change can update m_semiToneMarkerMenu
connect( &m_chordModel, SIGNAL( dataChanged() ),
this, SLOT( updateSemiToneMarkerMenu() ) );
tb_layout->addSpacing( 5 );
tb_layout->addWidget( m_playButton );
tb_layout->addWidget( m_recordButton );
@@ -526,6 +576,14 @@ pianoRoll::pianoRoll() :
tb_layout->addWidget( note_len_lbl );
tb_layout->addSpacing( 4 );
tb_layout->addWidget( m_noteLenComboBox );
tb_layout->addSpacing( 10 );
tb_layout->addWidget( scale_lbl );
tb_layout->addSpacing( 4 );
tb_layout->addWidget( m_scaleComboBox );
tb_layout->addSpacing( 10 );
tb_layout->addWidget( chord_lbl );
tb_layout->addSpacing( 4 );
tb_layout->addWidget( m_chordComboBox );
tb_layout->addStretch();
// setup our actual window
@@ -564,60 +622,69 @@ void pianoRoll::changeNoteEditMode( int i )
}
void pianoRoll::markTone( int i )
void pianoRoll::markSemiTone( int i )
{
static const int major_scale[KeysPerOctave] = {
1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1
};
const int key = getKey( mapFromGlobal( m_semiToneMarkerMenu->pos() ).y() );
const ChordCreator::Chord * chord = 0;
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 ) )
switch( static_cast<semiToneMarkerAction>( i ) )
{
case tmmeUnmarkAll:
m_markedTones.clear();
case stmaUnmarkAll:
m_markedSemiTones.clear();
break;
case tmmeMarkCurrent:
case stmaMarkCurrentSemiTone:
{
QList<int>::iterator i = qFind( m_markedTones.begin(), m_markedTones.end(), key );
if( i != m_markedTones.end() )
QList<int>::iterator i = qFind( m_markedSemiTones.begin(), m_markedSemiTones.end(), key );
if( i != m_markedSemiTones.end() )
{
m_markedTones.erase( i );
m_markedSemiTones.erase( i );
}
else
{
m_markedTones.push_back( key );
m_markedSemiTones.push_back( key );
}
break;
}
case tmmeMarkMinorScale:
scale = minor_scale;
case tmmeMarkMajorScale:
if( ! scale )
case stmaMarkCurrentScale:
chord = & ChordCreator::ChordTable::getInstance()
.getScaleByName( m_scaleModel.currentText() );
case stmaMarkCurrentChord:
{
if( ! chord )
{
scale = major_scale;
chord = & ChordCreator::ChordTable::getInstance()
.getChordByName( m_chordModel.currentText() );
}
for( int i = 0; i <= NumKeys; i++ )
if( chord->isEmpty() )
{
if( scale[std::abs( key - i ) % KeysPerOctave] )
break;
}
else if( chord->isScale() )
{
m_markedSemiTones.clear();
}
const int first = chord->isScale() ? 0 : key;
const int last = chord->isScale() ? NumKeys : key + chord->last();
const int cap = chord->isScale() ? KeysPerOctave : chord->last();
for( int i = first; i <= last; i++ )
{
if( chord->hasSemiTone( std::abs( key - i ) % cap ) )
{
m_markedTones.push_back( i );
m_markedSemiTones.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() );
qSort( m_markedSemiTones.begin(), m_markedSemiTones.end(), qGreater<int>() );
QList<int>::iterator new_end = std::unique( m_markedSemiTones.begin(), m_markedSemiTones.end() );
m_markedSemiTones.erase( new_end, m_markedSemiTones.end() );
}
@@ -1453,11 +1520,15 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
else if( _me->button() == Qt::LeftButton &&
m_editMode == ModeDraw )
{
// whether this action creates new note(s) or not
bool is_new_note = false;
note * created_new_note = NULL;
// did it reach end of vector because
// there's no note??
if( it == notes.begin()-1 )
{
is_new_note = true;
m_pattern->setType( pattern::MelodyPattern );
// then set new note
@@ -1470,13 +1541,35 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
// because live notes should still be quantized at the half.
midiTime note_pos( pos_ticks - ( quantization() / 2 ) );
midiTime note_len( newNoteLen() );
note new_note( note_len, note_pos, key_num );
new_note.setSelected( true );
new_note.setPanning( m_lastNotePanning );
new_note.setVolume( m_lastNoteVolume );
created_new_note = m_pattern->addNote( new_note );
const ChordCreator::Chord & chord = ChordCreator::ChordTable::getInstance()
.getChordByName( m_chordModel.currentText() );
if( ! chord.isEmpty() )
{
// if a chord is selected, create following notes in chord
// or arpeggio mode
const bool arpeggio = _me->modifiers() & Qt::ShiftModifier;
for( int i = 1; i < chord.size(); i++ )
{
if( arpeggio )
{
note_pos += note_len;
}
note new_note( note_len, note_pos, key_num + chord[i] );
new_note.setSelected( true );
new_note.setPanning( m_lastNotePanning );
new_note.setVolume( m_lastNoteVolume );
m_pattern->addNote( new_note );
}
}
// reset it so that it can be used for
// ops (move, resize) after this
// code-block
@@ -1579,7 +1672,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
// if they're holding shift, copy all selected notes
if( //*it != created_new_note &&
_me->modifiers() & Qt::ShiftModifier )
! is_new_note && _me->modifiers() & Qt::ShiftModifier )
{
// vector to hold new notes until we're through the loop
QVector<note> newNotes;
@@ -1662,7 +1755,7 @@ void pianoRoll::mousePressEvent( QMouseEvent * _me )
if( _me->buttons() == Qt::RightButton )
{
// right click, tone marker contextual menu
m_toneMarkerMenu->popup( mapToGlobal( QPoint( _me->x(), _me->y() ) ) );
m_semiToneMarkerMenu->popup( mapToGlobal( QPoint( _me->x(), _me->y() ) ) );
}
else
{
@@ -2703,9 +2796,9 @@ void pianoRoll::paintEvent( QPaintEvent * _pe )
}
// display note marks
for( int i = 0; i < m_markedTones.size(); i++ )
for( int i = 0; i < m_markedSemiTones.size(); i++ )
{
const int key_num = m_markedTones.at( i );
const int key_num = m_markedSemiTones.at( i );
const int y = keyAreaBottom() + 5
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
@@ -3673,6 +3766,21 @@ int pianoRoll::quantization() const
void pianoRoll::updateSemiToneMarkerMenu()
{
const ChordCreator::Chord & scale = ChordCreator::ChordTable::getInstance()
.getScaleByName( m_scaleModel.currentText() );
const ChordCreator::Chord & chord = ChordCreator::ChordTable::getInstance()
.getChordByName( m_chordModel.currentText() );
emit semiToneMarkerMenuScaleSetEnabled( ! scale.isEmpty() );
emit semiToneMarkerMenuChordSetEnabled( ! chord.isEmpty() );
}
midiTime pianoRoll::newNoteLen() const
{
if( m_noteLenModel.value() == 0 )