1
//---------------------------------------------------------------------------------------
2
// LenMus Phonascus: The teacher of music
3
// Copyright (c) 2002-2012 LenMus project
5
// This program is free software; you can redistribute it and/or modify it under the
6
// terms of the GNU General Public License as published by the Free Software Foundation,
7
// either version 3 of the License, or (at your option) any later version.
9
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
10
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
// You should have received a copy of the GNU General Public License along with this
14
// program. If not, see <http://www.gnu.org/licenses/>.
16
// For any comment, suggestion or feature request, please contact the manager of
17
// the project at cecilios@users.sourceforge.net
19
//---------------------------------------------------------------------------------------
22
#include "lenmus_composer.h"
24
#include "lenmus_generators.h"
25
#include "lenmus_utilities.h"
28
#include <lomse_internal_model.h>
29
#include <lomse_im_note.h>
30
#include <lomse_im_factory.h>
31
#include <lomse_score_utilities.h>
32
#include <lomse_staffobjs_table.h>
33
#include <lomse_staffobjs_cursor.h>
34
#include <lomse_time.h>
35
using namespace lomse;
38
//#include <wx/wxprec.h>
39
//#include <wx/arrstr.h> // to use wxArrayString
45
#define TRACE_COMPOSER 0
52
//---------------------------------------------------------------------------------------
53
enum lmEHarmonicFunction
55
lmTONIC = 0x00000001, // I
56
lmSUPERTONIC = 0x00000002, // ii
57
lmMEDIANT = 0x00000003, // iii
58
lmSUBDOMINANT = 0x00000004, // IV
59
lmDOMINANT = 0x00000005, // V
60
lmSUBMEDIANT = 0x00000006, // vi
61
lmLEADING = 0x00000007, // vii
62
lmSUBTONIC = 0x00000007, // vii
74
lmROOT_POSITION = 0x00000008,
75
lmFIRST_INVERSION = 0x00000010,
76
lmSECOND_INVERSION = 0x00000020,
77
lmTHIRD_INVERSION = 0x00000040,
79
lmSEVENTH_ADDED = 0x00000100,
82
lmGRADE_MASK = 0x00000007, // to extract grade
85
//---------------------------------------------------------------------------------------
86
// table of typical harmonic progressions, to base compositions on them
87
static lmEHarmonicFunction m_aProgression[][8] =
89
{lm_I, lm_V, lm_I, lm_IV, lm_II, lm_III, lm_IV, lm_I },
90
{lm_I, lm_II, lm_V, lm_I, lm_III, lm_IV, lm_V, lm_I },
96
//---------------------------------------------------------------------------------------
101
//---------------------------------------------------------------------------------------
102
Composer::~Composer()
106
//---------------------------------------------------------------------------------------
107
ImoScore* Composer::GenerateScore(ScoreConstrains* pConstrains, Document* pDoc)
109
//Synthesises a score
111
//Algorithm 1 to generate N measures
112
//----------------------------------
114
// 1. Determine how may beats we have to generate:
115
// BeatsToGenerate = Beats_per_measure x N
117
// 2. while (NumBeats < BeatsToGenerate) {
118
// 2.1 Randomly choose a pattern satisfying the constraints (lesson, level, time
120
// 2.2 Instantiate the choosen pattern by assingning note pitches
121
// 2.3 NumBeats = NumBeats + num. beats in choosen pattern
123
// 3. Divide generated beats string into measures (just assign to each measure the
124
// next n beats -- where n=Beats_per_measure -- )
127
// - difficulties for using patterns that are not full measures
128
// - difficulties for aligning patterns to barlines at specific points
129
// - strong limitation: requires patterns divided into beats. It would be
130
// impossible, for example, include a dotted quarter note in a binary
135
//Algorithm 2 to generate N measures
136
//----------------------------------
138
// Instead of generating beats, let's organize the main loop around generating
140
// Lets use patterns that contains musical phrases instead of full measures.
141
// Patterns will contain, when necessary, barline alignment information.
142
// Before adding a pattern to the current measure, lets align the pattern by
143
// inserting rests, if required.
146
// while (NumMeasures < MeasuresToGenerate) {
147
// If (no measure is opened) start a measure
148
// If (no beats in pattern) {
149
// Randomly choose a pattern satisfying the constraints (lesson,
150
// level, time signature, etc.).
151
// Instantiate the choosen pattern by assingning note pitches.
152
// Align pattern to measure by adding any required rest to the measure
154
// While (there are beats in the choosen pattern and measure not full) {
164
//Algorithm 3 to generate N measures (8/Feb/06)
165
//---------------------------------------------
168
// Algorithm 2 generates scores with mis-aligments and irregular measures.
169
// The problem is due to lack of information about alignment. So in this
170
// improved algorithm I will also use patterns containing musical phrases
171
// instead of full measures.
172
// These patterns will be called 'fragments'. Fragments are divided into
173
// 'segments' (a segment is a group of elements - notes and rests - that must
174
// go together and occupies one or more full beats).
175
// Fragments will contain baline alignment information.
177
// The algorithm is essentialy the same, but the method to add beats is
178
// improved by taking into account alignment and duration information. Also
179
// it is necessary to take into account that a segment may contain one or
180
// more beats (not necessarily full beats).
182
// Another improvement is generating the final measure not by using fragments
183
// but by generation a note lasting one ore more beats. And its pitch is
184
// the root pitch of the used key signature.
187
// - It is assumed that all beats are equal. Therefore, current algorithm
188
// works only for regular time signature rhythms. It will
189
// not work, for example, with 7/8.
193
// while (NumMeasures < MeasuresToGenerate - 1 ) {
194
// If (no measure is opened) start a measure
195
// If (no beats in pattern) {
196
// Randomly choose a pattern satisfying the constraints (lesson,
197
// level, time signature, etc.).
198
// Instantiate the choosen pattern by assingning note pitches.
200
// While (there are beats in the choosen pattern and measure not full) {
213
m_pConstrains = pConstrains;
215
//Generate a random key, time signature and clef satisfying the constrains
216
m_nClef = RandomGenerator::generate_clef(m_pConstrains->GetClefConstrains());
217
m_nKey = RandomGenerator::generate_key(m_pConstrains->GetKeyConstrains());
218
m_nTimeSign = RandomGenerator::GenerateTimeSign(m_pConstrains->GetTimeSignConstrains());
219
bool fCompound = get_num_ref_notes_per_pulse_for(m_nTimeSign) != 1;
221
// prepare and initialize the score
222
ImoScore* pScore = static_cast<ImoScore*>(ImFactory::inject(k_imo_score, pDoc));
223
ImoInstrument* pInstr = pScore->add_instrument();
224
// (g_pMidi->DefaultVoiceChannel(), g_pMidi->DefaultVoiceInstr(), _T(""));
225
ImoSystemInfo* pInfo = pScore->get_first_system_info();
226
pInfo->set_top_system_distance( pInstr->tenths_to_logical(30) ); // 3 lines
227
pInstr->add_clef(m_nClef);
228
pInstr->add_key_signature(m_nKey);
230
#if 0 //useful for debugging and to generate scores with a chosen rhythm line to write documentation
231
pInstr->add_time_signature(2, 4);
232
pInstr->add_staff_objects("(r e)(n * e)(n * e g+)(n * e l g-)(barline simple)");
233
pInstr->add_staff_objects("(n * e g+)(n * s)(n * s g-)(n * e g+)(n * e g-)(barline simple)");
234
pInstr->add_staff_objects("(n * q)(r e)(n * e)(barline simple)");
235
pInstr->add_staff_objects("(n * s g+)(n * s)(n * s)(n * s g-)(n * e g+)(n * e l g-)(barline simple)");
236
pInstr->add_staff_objects("(n * e g+)(n * s)(n * s g-)(n * s g+)(n * s)(n * s)(n * s g-)(barline simple)");
237
pInstr->add_staff_objects("(n * s g+)(n * s)(n * s)(n * s g-)(n * e g+)(n * e l g-)(barline simple)");
238
pInstr->add_staff_objects("(n * q)(r e)(n * e)(barline simple)");
239
pInstr->add_staff_objects("(n * b)(barline end)");
243
int beats = get_top_number_for(m_nTimeSign);
244
int type = get_bottom_number_for(m_nTimeSign);
245
pInstr->add_time_signature(beats, type);
249
// Content generation
252
// Determine how may measures we have to generate:
253
#define NUM_MEASURES 8 //num of measures to generate
254
int nMeasuresToGenerate = NUM_MEASURES - 1;
255
int nNumMeasures = 0;
256
float rMeasureDuration = get_measure_duration_for(m_nTimeSign); //tm
257
float rBeatDuration = get_ref_note_duration_for(m_nTimeSign); //tb
258
float rTimeRemaining; //tr
259
float rSegmentDuration; //ts
260
float rConsumedBeatTime; //tcb
261
float rSegmentAlignBeatTime; //tab
264
// Loop to generate the required measures
265
wxString sMeasure; //source code of current measure
266
bool fFits; //current segment fits in current measure
267
float rOccupiedDuration; //consumed time in current measure (tc)
268
bool fMeasure = false; //there is a measure started
269
SegmentEntry* pSegment; //segment to add to measure
271
//select all usable fragments for current time signature
272
if (m_pConstrains->SelectFragments(m_nTimeSign) == 0)
274
//TODO: error logging. Suppress message
275
wxLogMessage(_T("[Composer::GenerateScore] No usable fragments!"));
279
//chose ramdomly a fragment satisfying the constraints, and take the first segment
280
pConstrains->ChooseRandomFragment();
281
pSegment = pConstrains->GetNextSegment();
282
//TODO: what if no fragment satisfies the constraints?
284
int nSegmentLoopCounter = 0;
285
while (nNumMeasures < nMeasuresToGenerate)
287
//If no measure is opened start a new measure
291
rOccupiedDuration = 0.0;
295
//If there are no more segments in current fragment, choose a new fragment
298
//Randomly choose a new fragment satisfying the constraints
299
pConstrains->ChooseRandomFragment();
300
pSegment = pConstrains->GetNextSegment();
301
wxASSERT(pSegment); //there must exits a fragment satisfying
302
//the constraints. Otherwise this would have been
303
//detected before entering the main while loop
306
//While (there are segments in the current fragment and the measure is not full) {
307
while (pSegment && rOccupiedDuration < rMeasureDuration)
309
//check if segment fits in. A segment S will fit in the measure
310
//only when (tr >= ts && tcb <= tab)
312
rTimeRemaining = rMeasureDuration - rOccupiedDuration;
313
rSegmentDuration = pSegment->GetSegmentDuration();
314
rConsumedBeatTime = rOccupiedDuration; //this line and next two ones compute tcb = tc % tb;
315
while (is_greater_time(rConsumedBeatTime, 0.0f))
316
rConsumedBeatTime -= rBeatDuration;
317
if (rConsumedBeatTime < 0.0)
318
rConsumedBeatTime += rBeatDuration;
319
rSegmentAlignBeatTime = pSegment->GetTimeAlignBeat();
320
fFits = (!is_lower_time(rTimeRemaining, rSegmentDuration)
321
&& !is_greater_time(rConsumedBeatTime, rSegmentAlignBeatTime));
323
#if (TRACE_COMPOSER == 1)
324
wxLogMessage(_T("[Composer::GenerateScore] sMeasure=%s, pSegment=%s, tr=%.2f, ts=%.2f, tcb=%.2f, tab=%.2f, tc=%.2f, tb=%.2f, fits=%s"),
326
(pSegment->GetSource()).c_str(), rTimeRemaining, rSegmentDuration,
327
rConsumedBeatTime, rSegmentAlignBeatTime,
328
rOccupiedDuration, rBeatDuration,
329
(fFits ? _T("yes") : _T("no")) );
332
//if segment fits add it to current measure
335
//it fits. Add it to current measure
336
float rNoteTime = rSegmentAlignBeatTime - rConsumedBeatTime;
337
if (is_greater_time(rNoteTime, 0.0f))
339
if (rConsumedBeatTime > 0.0f)
340
sMeasure += CreateNote((int)rNoteTime, fCompound, false /*not final note*/);
342
sMeasure += CreateRest((int)rNoteTime, fCompound, false /*not final rest*/);
346
sMeasure += pSegment->GetSource();
347
#if (TRACE_COMPOSER == 1)
348
wxLogMessage(_T("[Composer::GenerateScore] Adding segment. Measure = '%s')"),
353
rOccupiedDuration += rSegmentDuration + rNoteTime;
356
pSegment = pConstrains->GetNextSegment();
357
nSegmentLoopCounter = 0;
362
#if (TRACE_COMPOSER == 1)
363
wxLogMessage(_T("[Composer::GenerateScore] Segment does not fit. Ignored"));
365
if (nSegmentLoopCounter++ > 100)
367
//let's assume that no segment fits. Fill the measure with a note
368
sMeasure += CreateNote((int)rTimeRemaining, fCompound, false /*not final note*/);
369
rOccupiedDuration += rTimeRemaining;
370
nSegmentLoopCounter = 0;
374
// Ignore segment and take a new one
375
pSegment = pConstrains->GetNextSegment();
380
// if measure is full, close it and increment measures count
381
if (rOccupiedDuration >= rMeasureDuration)
384
// close current measure
385
fMeasure = false; // no measure opened
386
sMeasure += _T("(barline simple)");
388
// increment measures counter
391
// Instantiate the notes by assigning note pitches and add
392
// the measure to the score
393
#if (TRACE_COMPOSER == 1)
394
wxLogMessage(_T("[Composer::GenerateScore] Adding measure = '%s')"),
397
pInstr->add_staff_objects( to_std_string(sMeasure) );
402
pScore->close(); //generate ColStaffObjs, to traverse it in following code lines
404
// In Music Reading, level 1, introduction lessons use only quarter notes. In those
405
// exercises we should not use half notes in the last measure. So lets check if
406
// only quarter notes are used in the composed piece of music.
407
bool fOnlyQuarterNotes = true;
408
ColStaffObjs* pColStaffObjs = pScore->get_staffobjs_table();
409
ColStaffObjs::iterator it = pColStaffObjs->begin();
410
while(it != pColStaffObjs->end())
412
ImoObj* pImo = (*it)->imo_object();
415
//Note fount. Take duration
416
ImoNote* pNote = static_cast<ImoNote*>(pImo);
417
fOnlyQuarterNotes &= is_equal_time(pNote->get_duration(),
418
float(k_duration_quarter) );
419
if (!fOnlyQuarterNotes)
425
#if (TRACE_COMPOSER == 1)
426
wxLogMessage(_T("[Composer::GenerateScore] fOnlyQuarterNotes=%s)"),
427
(fOnlyQuarterNotes ? _T("True") : _T("False")) );
430
// add a final measure with a root pitch note lasting, at least, one beat
431
sMeasure = CreateLastMeasure(++nNumMeasures, m_nTimeSign, fOnlyQuarterNotes);
432
pInstr->add_staff_objects( to_std_string(sMeasure) );
436
#if (TRACE_COMPOSER == 1)
437
wxLogMessage(_T("[Composer::GenerateScore] Adding final measure = '%s')"), sMeasure.c_str());
441
//Score is built but pitches are not yet defined.
442
//Proceed to instatiate pitches according to key signature
444
//pScore->Dump(_T("lemus_score_dump.txt"));
446
#if 0 //useful to generate only the rhymth line, to write documenation
447
InstantiateWithNote(pScore, FPitch("b3") );
449
InstantiateNotes(pScore, m_nKey, nNumMeasures);
453
//pScore->Dump(_T("lemus_score_dump.txt"));
457
//---------------------------------------------------------------------------------------
458
void Composer::GetNotesRange()
460
//get the minimum and maximum notes
461
wxString sMinPitch = (m_pConstrains->GetClefConstrains())->GetLowerPitch(m_nClef);
462
m_fpMinPitch = FPitch( to_std_string(sMinPitch) );
464
wxString sMaxPitch = (m_pConstrains->GetClefConstrains())->GetUpperPitch(m_nClef);
465
m_fpMaxPitch = FPitch( to_std_string(sMaxPitch) );
468
//---------------------------------------------------------------------------------------
469
wxString Composer::CreateNoteRest(int nNoteRestDuration, bool fNote, bool fCompound,
472
//Returns a string with one or more LDP elements containing notes o rests up to a total
473
//duration nNoteDuration. They will be notes if fNote==true; otherwise they will be rests.
474
//For example, for nNoteDuration=64 it will return "(n * n)"
476
wxString sElement = _T("");
478
int nTimeNeeded = nNoteRestDuration;
480
if (fCompound && fFinal)
482
while (nTimeNeeded > 0)
484
sElement += (fNote ? _T("(n * ") : _T("(r ") );
485
if (nTimeNeeded >= k_duration_whole_dotted)
487
sElement += _T("w.)");
488
nDuration = k_duration_whole_dotted;
490
else if (nTimeNeeded >= k_duration_half_dotted)
492
sElement += _T("h.)");
493
nDuration = k_duration_half_dotted;
495
else if (nTimeNeeded >= k_duration_quarter_dotted)
497
sElement += _T("q.)");
498
nDuration = k_duration_quarter_dotted;
500
else if (nTimeNeeded >= k_duration_eighth_dotted)
502
sElement += _T("e.)");
503
nDuration = k_duration_eighth_dotted;
505
else if (nTimeNeeded >= k_duration_16th_dotted)
507
sElement += _T("s.)");
508
nDuration = k_duration_16th_dotted;
510
else if (nTimeNeeded >= k_duration_32th_dotted)
512
sElement += _T("t.)");
513
nDuration = k_duration_32th_dotted;
515
else if (nTimeNeeded >= k_duration_64th_dotted)
517
sElement += _T("i.)");
518
nDuration = k_duration_64th_dotted;
520
else if (nTimeNeeded >= k_duration_128th_dotted)
522
sElement += _T("o.)");
523
nDuration = k_duration_128th_dotted;
527
sElement += _T("f)");
528
nDuration = k_duration_256th;
531
nTimeNeeded -= nDuration;
536
while (nTimeNeeded > 0)
538
sElement += (fNote ? _T("(n * ") : _T("(r ") );
539
if (nTimeNeeded >= k_duration_whole_dotted)
541
sElement += _T("w.)");
542
nDuration = k_duration_whole_dotted;
544
else if (nTimeNeeded >= k_duration_whole)
546
sElement += _T("w)");
547
nDuration = k_duration_whole;
549
else if (nTimeNeeded >= k_duration_half_dotted)
551
sElement += _T("h.)");
552
nDuration = k_duration_half_dotted;
554
else if (nTimeNeeded >= k_duration_half)
556
sElement += _T("h)");
557
nDuration = k_duration_half;
559
else if (nTimeNeeded >= k_duration_quarter_dotted)
561
sElement += _T("q.)");
562
nDuration = k_duration_quarter_dotted;
564
else if (nTimeNeeded >= k_duration_quarter)
566
sElement += _T("q)");
567
nDuration = k_duration_quarter;
569
else if (nTimeNeeded >= k_duration_eighth_dotted)
571
sElement += _T("e.)");
572
nDuration = k_duration_eighth_dotted;
574
else if (nTimeNeeded >= k_duration_eighth)
576
sElement += _T("e)");
577
nDuration = k_duration_eighth;
579
else if (nTimeNeeded >= k_duration_16th_dotted)
581
sElement += _T("s.)");
582
nDuration = k_duration_16th_dotted;
584
else if (nTimeNeeded >= k_duration_16th)
586
sElement += _T("s)");
587
nDuration = k_duration_16th;
589
else if (nTimeNeeded >= k_duration_32th_dotted)
591
sElement += _T("t.)");
592
nDuration = k_duration_32th_dotted;
594
else if (nTimeNeeded >= k_duration_32th)
596
sElement += _T("t)");
597
nDuration = k_duration_32th;
599
else if (nTimeNeeded >= k_duration_64th_dotted)
601
sElement += _T("i.)");
602
nDuration = k_duration_64th_dotted;
604
else if (nTimeNeeded >= k_duration_64th)
606
sElement += _T("i)");
607
nDuration = k_duration_64th;
609
else if (nTimeNeeded >= k_duration_128th_dotted)
611
sElement += _T("o.)");
612
nDuration = k_duration_128th_dotted;
614
else if (nTimeNeeded >= k_duration_128th)
616
sElement += _T("o)");
617
nDuration = k_duration_128th;
621
sElement += _T("f)");
622
nDuration = k_duration_256th;
625
nTimeNeeded -= nDuration;
629
#if (TRACE_COMPOSER == 1)
630
wxLogMessage(_T("[Composer::CreateNoteRest] Needed duration= %d, added=%s"),
631
nNoteRestDuration, sElement.c_str());
637
//---------------------------------------------------------------------------------------
638
wxString Composer::CreateLastMeasure(int nNumMeasure, ETimeSignature nTimeSign,
639
bool fOnlyQuarterNotes)
641
// Returns a final meaure. This final measure has only a note, long enough, and
644
wxString sMeasure = _T("");
645
float rMeasureDuration = get_measure_duration_for(nTimeSign);
646
float rPulseDuration = get_ref_note_duration_for(nTimeSign) *
647
get_num_ref_notes_per_pulse_for(nTimeSign);
648
float rNoteDuration = rPulseDuration;
649
bool fCompound = (get_num_ref_notes_per_pulse_for(nTimeSign) != 1);
650
if (!fOnlyQuarterNotes && rMeasureDuration / rPulseDuration >= 2.0)
652
//flip coin to randomly add a one-beat note or a two-beats note
653
if (RandomGenerator::flip_coin())
654
rNoteDuration += rPulseDuration;
657
sMeasure += CreateNote((int)rNoteDuration, fCompound, true /*final note*/);
658
rNoteDuration = rMeasureDuration - rNoteDuration;
659
if (rNoteDuration > 0.0f)
660
sMeasure += CreateRest((int)rNoteDuration, fCompound, true /*final rest*/);
662
sMeasure += _T("(barline end)");
666
//---------------------------------------------------------------------------------------
667
// Methods to deal with tonality
668
//---------------------------------------------------------------------------------------
670
bool Composer::InstantiateNotes(ImoScore* pScore, EKeySignature nKey, int nNumMeasures)
672
// Returns true if error
674
// Choose a chord progression, based on key signature: nChords[]
675
std::vector<long> nChords(nNumMeasures);
676
GetRandomHarmony(nNumMeasures, nChords);
678
// Lets compute the notes in the natural scale of the key signature to use
679
// This will be used later in various places
680
FPitch scale[7]; // the notes in the scale
681
GenerateScale(nKey, scale);
683
// In a later step we are goin to choose and compute a contour curve.
684
// The contour curve will have as many points as on-chord notes in the music line.
685
// So first we have to compute the number of on-chord notes. The following code is a
686
// loop to count on-chord notes in first staff of first instrument
687
// and to locate last note. This is necessary to assign it the root pitch (later)
688
// ImoNote* pLastNote = NULL;
690
ImoTimeSignature* pTS = NULL;
691
StaffObjsCursor cursor(pScore);
692
while(!cursor.is_end())
694
ImoStaffObj* pSO = cursor.get_staffobj();
697
// ImoNote* pNote = static_cast<ImoNote*>(pSO);
698
int pos = k_off_beat;
700
pos = get_beat_position(cursor.time(), pTS);
702
if(pos != k_off_beat)
703
nNumPoints++; // on beat note
705
// pLastNote = pNote;
707
else if (pSO->is_time_signature())
709
pTS = static_cast<ImoTimeSignature*>( pSO );
716
// If number of points is small (i.e < 8) forget about this. Instatiate notes
717
// with random pitch and finish. This bypasess the only problem found, when a
718
// score has rests in all beat positions (L2_musicReading, Lesson 17, exercise 1)
721
InstantiateNotesRandom(pScore);
722
return false; // no error
726
// Now we are going to choose at random a contour curve and compute its points
727
// The curve will always start and finish in the root note. Its amplitude will
728
// be adjusted to satisfy the constrains (min and max pitch)
729
std::vector<DiatonicPitch> aContour(nNumPoints);
730
GenerateContour(nNumPoints, aContour);
732
// allocate a vector for valid notes in chord (all notes in valid notes range)
733
int iC = 0; //index to current chord (ic)
734
DiatonicPitch dnMinPitch = m_fpMinPitch.to_diatonic_pitch();
735
DiatonicPitch dnMaxPitch = m_fpMaxPitch.to_diatonic_pitch();
736
#if (TRACE_PITCH == 1)
737
wxLogMessage(_T("Composer::InstantiateNotes"), _T("min pitch %d (%s), max pitch %d (%s)"),
738
int(dnMinPitch), dnMinPitch.get_ldp_name().c_str(),
739
int(dnMaxPitch), dnMaxPitch.get_ldp_name().c_str() );
741
std::vector<FPitch> aOnChordPitch;
742
aOnChordPitch.reserve((int(dnMaxPitch) - int(dnMinPitch))/2); // Reserve space. Upper limit estimation
743
FPitch nRootNote = GenerateInChordList(nKey, nChords[iC], aOnChordPitch);
745
// Loop to process notes/rests in first staff of first instrument
746
ImoNote* pOnChord1 = NULL; //Pair of on-chord notes. First one
747
ImoNote* pOnChord2 = NULL; //Pair of on-chord notes. Second one
748
ImoNote* pNonChord[20]; //non-chod notes between the two on-chord notes
749
int nCount = 0; //number of non-chord notes between the two on-chord notes
751
ImoNote* pNotePrev = NULL;
755
wxString sDbg = _T("");
756
StaffObjsCursor cursor2(pScore);
757
while(!cursor2.is_end())
759
ImoStaffObj* pImo = cursor2.get_staffobj();
760
if (pImo->is_note_rest())
762
// 1. It is a note or a rest
765
// It is a note. Get its chord position
766
pNoteCur = static_cast<ImoNote*>(pImo);
767
int pos = k_off_beat;
768
ImoTimeSignature* pTS = cursor2.get_applicable_time_signature();
770
pos = get_beat_position(cursor2.time(), pTS);
771
if (pos != k_off_beat)
773
// on beat note. Pitch must be on chord.
774
// Assign a pitch from nChords[iC].
775
#if (TRACE_PITCH == 1)
776
for(int k=0; k < (int)aOnChordPitch.size(); k++)
777
wxLogMessage(_T("[Composer::InstantiateNotes] OnChord %d = %s"), k, aOnChordPitch[k].to_abs_ldp_name().c_str() );
779
fpNew = NearestNoteOnChord(aContour[iPt++], pNotePrev, pNoteCur,
781
#if (TRACE_PITCH == 1)
782
for(int k=0; k < (int)aOnChordPitch.size(); k++)
783
wxLogMessage(_T("[Composer::InstantiateNotes] OnChord %d = %s"), k, aOnChordPitch[k].to_abs_ldp_name().c_str() );
784
string sNoteName = fpNew.to_abs_ldp_name();
785
wxLogMessage(_T("[Composer::InstantiateNotes] on-chord note %d. Assigned pitch = %d (%s), chord=%d"),
786
iPt, int(fpNew.to_diatonic_pitch()), sNoteName.c_str(),
787
nChords[iC] & lmGRADE_MASK);
790
set_pitch(pNoteCur, fpNew);
792
// assing pitch to non-chord notes between previous on-chord one
797
pOnChord2 = pNoteCur;
798
AssignNonChordNotes(nCount, pOnChord1, pOnChord2,
802
// Prepare data for next pair processing
804
pOnChord1 = pNoteCur;
809
// non-chord note. Save it to be processed later
810
if (pNoteCur->get_fpitch() == k_undefined_fpitch)
812
pNonChord[nCount++] = pNoteCur;
818
pNotePrev = pNoteCur;
822
else if (pImo->is_barline())
824
// End of measure: choose the next chord in progression
826
nRootNote = GenerateInChordList(nKey, nChords[iC % 8], aOnChordPitch);
832
#if (TRACE_PITCH == 1)
833
wxLogMessage(_T("[Composer::InstantiateNotes] %s"), sDbg.c_str());
836
return false; // no error
839
//---------------------------------------------------------------------------------------
840
void Composer::InstantiateNotesRandom(ImoScore* pScore)
842
ColStaffObjs* pColStaffObjs = pScore->get_staffobjs_table();
843
ColStaffObjs::iterator it = pColStaffObjs->begin();
844
while(it != pColStaffObjs->end())
846
ImoObj* pImo = (*it)->imo_object();
849
FPitch fp = RandomPitch();
850
ImoNote* pNote = static_cast<ImoNote*>(pImo);
851
set_pitch(pNote, fp);
857
//---------------------------------------------------------------------------------------
858
FPitch Composer::RandomPitch()
860
int nMinPitch = (int)m_fpMinPitch.to_diatonic_pitch();
861
int nMaxPitch = (int)m_fpMaxPitch.to_diatonic_pitch();
862
static int nLastPitch = 0;
865
nLastPitch = (nMinPitch + nMaxPitch) / 2;
867
int nRange = m_pConstrains->GetMaxInterval();
868
int nLowLimit = wxMax(nLastPitch - nRange, nMinPitch);
869
int nUpperLimit = wxMin(nLastPitch + nRange, nMaxPitch);
871
if (nUpperLimit - nLowLimit < 2)
872
nNewPitch = nLowLimit;
874
nNewPitch = RandomGenerator::random_number(nLowLimit, nUpperLimit);
877
nLastPitch = nNewPitch;
879
DiatonicPitch dp(nNewPitch);
880
return FPitch(dp.step(), dp.octave(), 0);
883
//---------------------------------------------------------------------------------------
884
void Composer::GetRandomHarmony(int nFunctions, std::vector<long>& aFunction)
886
//Fills array 'pFunction' with an ordered set of harmonic functions to
887
//build a melody. i.e.: I,V,I,IV,II,III,IV,I
889
int nNumProgs = sizeof(m_aProgression) / (8 * sizeof(long));
890
int iP = RandomGenerator::random_number(0, nNumProgs-1);
891
for(int i=0; i < 8; i++)
892
aFunction[i] = m_aProgression[iP][i];
895
//---------------------------------------------------------------------------------------
896
void Composer::FunctionToChordNotes(EKeySignature nKey, long nFunction,
899
//Given a key signature and an harmonic function returns the notes to build the
900
//chord (four notes per chord). The first chord note is always in octave 4
902
//C Major, II --> d4, f4, a4
903
//D Major, I --> d4, +f4, a4
905
//generate natural scale for key signature
907
get_accidentals_for_key(nKey, nAcc);
908
int step = get_step_for_root_note(nKey);
910
int octave = k_octave_4;
911
for (int iN=0; iN < 15; iN++)
913
scale[iN] = FPitch(step, octave, nAcc[step]);
923
long iF = (nFunction & lmGRADE_MASK) - 1L;
924
notes[0] = FPitch( scale[iF] );
925
notes[1] = FPitch( scale[iF+2] );
926
notes[2] = FPitch( scale[iF+4] );
928
// #if (TRACE_COMPOSER == 1)
929
// wxLogMessage(_T("[Composer::FunctionToChordNotes] Function %d, Key=%d, note0 %d (%s), note1 %d (%s), note2 %d (%s)."),
931
// notes[0].to_diatonic_pitch(), notes[0].to_abs_ldp_name().c_str(),
932
// notes[1].to_diatonic_pitch(), notes[1].to_abs_ldp_name().c_str(),
933
// notes[2].to_diatonic_pitch(), notes[2].to_abs_ldp_name().c_str() );
937
//---------------------------------------------------------------------------------------
938
FPitch Composer::MoveByStep(bool fUpStep, FPitch nPitch, FPitch scale[7])
940
// Generates a new note by moving up/down one step in the scale
941
// The new pitch must be on the key signature natural scale
943
// extract pitch components
944
int nStep = nPitch.step();
945
int nOctave = nPitch.octave();
947
// find current note in scale
949
for (i=0; i < 7; i++) {
950
if (scale[i].step() == nStep) break;
957
if (nStep == k_step_B) nOctave++;
961
if (--i == -1) i = 6;
962
if (nStep == k_step_C) nOctave--;
965
nStep = scale[i].step();
966
int nAcc = scale[i].accidentals();
967
return FPitch(nStep, nOctave, nAcc);
971
//---------------------------------------------------------------------------------------
972
FPitch Composer::MoveByChromaticStep(bool fUpStep, FPitch pitch)
974
// Generates a new note by moving up/down one chromatic step in the scale
976
// extract pitch accidentals
977
int acc = pitch.accidentals();
984
return FPitch(pitch.step(), pitch.octave(), acc);
987
//---------------------------------------------------------------------------------------
988
void Composer::GenerateScale(EKeySignature nKey, FPitch notes[7])
991
get_accidentals_for_key(nKey, acc);
992
int step = get_step_for_root_note(nKey);
993
for (int i=0; i < 7; ++i)
995
notes[i] = FPitch(step, k_octave_4, acc[step]);
1001
//---------------------------------------------------------------------------------------
1002
FPitch Composer::GenerateInChordList(EKeySignature nKey, long nChord,
1003
std::vector<FPitch>& fpValidPitch)
1005
// Returns the root note in octave 4
1006
// Generates a list with all allowed notes in the chord, satisfying the
1007
// constraints for notes range. For instance:
1008
// D Major chord: d4, +f4, a4
1009
// notes range: a3 to a5
1010
// returns: a3, d4, +f4, a4, d5, +f5, a5
1012
// allocate an array for notes in chord (basic chord, octave 4)
1013
FPitch notes[4]; // notes in current chord
1014
FunctionToChordNotes(nKey, nChord, notes);
1016
// extract valid steps, to simplify
1017
//TODO: review logic. Value NO_DPITCH is never returned.
1019
for (int i=0; i < 4; i++)
1021
if (notes[i].to_diatonic_pitch() == NO_DPITCH)
1022
nValidStep[i] = -1; //you can assign any non valid value for a step
1024
nValidStep[i] = notes[i].step();
1027
// empty valid pitches array
1028
fpValidPitch.clear();
1030
// scan notes range and select those in chord
1031
DiatonicPitch dnMinPitch = m_fpMinPitch.to_diatonic_pitch();
1032
DiatonicPitch dnMaxPitch = m_fpMaxPitch.to_diatonic_pitch();
1033
for (int i=int(dnMinPitch); i <= int(dnMaxPitch); i++)
1035
DiatonicPitch dp(i);
1036
int nStep = dp.step();
1037
for (int j=0; j < 4; j++)
1039
if (nStep == nValidStep[j])
1041
// Note in chord. Add it to the list
1042
FPitch nPitch(nStep, dp.octave(), notes[j].num_accidentals());
1043
fpValidPitch.push_back(nPitch);
1051
//---------------------------------------------------------------------------------------
1052
void Composer::GenerateContour(int nNumPoints, std::vector<DiatonicPitch>& aContour)
1054
// In this method we choose at random a contour curve and compute its points
1055
// The curve will always start and finish in the root note. Its amplitude will
1056
// be adjusted to satisfy the constrains (min and max pitch), and will be
1057
// a value between one and two octaves, depending on the valid notes range and
1058
// the type of contour.
1059
// In case the valid notes range is lower than one octave, arch like curves will
1062
// First, we will determine the root note
1063
int nRootStep = get_step_for_root_note(m_nKey);
1065
// Now lets do some computations to determine a suitable octave
1066
DiatonicPitch dnMinPitch = m_fpMinPitch.to_diatonic_pitch();
1067
DiatonicPitch dnMaxPitch = m_fpMaxPitch.to_diatonic_pitch();
1068
int nAmplitude = int(dnMaxPitch) - int(dnMinPitch) + 1;
1069
// #if (TRACE_COMPOSER == 1)
1070
// wxLogMessage(_T("[Composer::GenerateContour] minPitch %d (%s), max pitch %d (%s), amplitude %d"),
1071
// dnMinPitch, dnMinPitch.get_ldp_name().c_str(),
1072
// dnMaxPitch, dnMaxPitch.get_ldp_name().c_str(),
1077
// determine minimum root pitch
1078
int nOctave = dnMinPitch.octave();
1079
if (dnMinPitch.step() > nRootStep)
1081
DiatonicPitch dnMinRoot(nRootStep, nOctave);
1083
// determine maximum root pitch
1084
DiatonicPitch dnMaxRoot = dnMinRoot;
1085
while (dnMaxRoot+7 <= dnMaxPitch)
1088
// if range greater than two octaves reduce it and reposition
1089
if (int(dnMaxRoot)-int(dnMinRoot) > 14)
1091
int nRange = (int(dnMaxRoot)-int(dnMinRoot)) / 7;
1092
int nShift = RandomGenerator::random_number(0, nRange-2);
1093
dnMinRoot += 7*nShift;
1094
dnMaxRoot = dnMinRoot + 14;
1098
// #if (TRACE_COMPOSER == 1)
1099
// wxLogMessage(_T("[Composer::GenerateContour] min root %d (%s), max root %d (%s)"),
1100
// dnMinRoot, DiatonicPitch_ToLDPName(dnMinRoot).c_str(),
1101
// dnMaxRoot, DiatonicPitch_ToLDPName(dnMaxRoot).c_str() );
1106
// Choose a contour curve
1109
lmCONTOUR_TRIANGLE = 0,
1110
lmCONTOUR_TRIANGLE_RAMP,
1111
lmCONTOUR_RAMP_TRIANGLE,
1112
lmSTART_RESTRICTED_CONTOURS,
1113
lmCONTOUR_ZIG_ZAG = lmSTART_RESTRICTED_CONTOURS,
1116
lmCONTOUR_ARCH, //Bad results. Top is very flat so the sensation of
1117
//raeching a peak is very poor
1122
// Choose a contour curve. If range is not at least an octave, do not allow
1126
if (dnMaxRoot == dnMinRoot)
1128
// Pitch range is not at least an octave. Only some curves allowed.
1129
nCurve = RandomGenerator::random_number(0, lmSTART_RESTRICTED_CONTOURS-1);
1130
// Lets force curve direction to better use the avalable notes range
1131
if (dnMaxPitch < dnMinRoot)
1133
// allowed notes does not include root note. Use all notes range.
1134
// Curve direction doesn't matter
1135
dnMinRoot = dnMinPitch;
1136
dnMaxRoot = dnMaxPitch;
1137
fUp = RandomGenerator::flip_coin();
1139
else if (int(dnMinRoot)-int(dnMinPitch) < int(dnMaxPitch)-int(dnMinRoot))
1141
// Use upper part of range. Curve going up
1143
dnMaxRoot = dnMaxPitch;
1147
// use lower part of range. Curve going down.
1149
dnMinRoot = dnMinPitch;
1154
// range is grater than one octave. Any curve and direction allowed
1155
nCurve = RandomGenerator::random_number(0, lmMAX_CONTOUR-1);
1156
fUp = RandomGenerator::flip_coin();
1159
#if (TRACE_PITCH == 1)
1160
wxLogMessage(_T("[Composer::GenerateContour] type=%d, nNumPoints=%d, up=%s"),
1161
nCurve, nNumPoints, (fUp ? _T("Yes") : _T("No")) );
1164
// prepare curve parameters and compute the curve points
1165
DiatonicPitch dnLowPitch, dnHighPitch, dnStartRamp, dnEndRamp;
1168
case lmCONTOUR_ARCH:
1169
//----------------------------------------------------------------------------
1170
// Arch. An arch will be defined by the amplitude, the center beat, and
1175
dnLowPitch = dnMinRoot;
1176
nAmplitude = dnMaxPitch - dnLowPitch;
1177
if (nAmplitude > 14)
1179
dnHighPitch = dnLowPitch + nAmplitude;
1183
dnHighPitch = dnMaxRoot;
1184
nAmplitude = dnHighPitch - dnMinPitch;
1185
if (nAmplitude > 14)
1187
dnLowPitch = dnHighPitch - nAmplitude;
1189
ComputeArch(fUp, 0, nNumPoints, dnLowPitch, dnHighPitch, aContour);
1192
case lmCONTOUR_TRIANGLE:
1193
//----------------------------------------------------------------------------
1194
// Triangle. Defined the amplitude, the center beat, and the direction
1197
dnLowPitch = dnMinRoot;
1198
nAmplitude = dnMaxPitch - dnLowPitch;
1199
if (nAmplitude > 14)
1201
dnHighPitch = dnLowPitch + nAmplitude;
1205
dnHighPitch = dnMaxRoot;
1206
nAmplitude = dnHighPitch - dnMinPitch;
1207
if (nAmplitude > 14)
1209
dnLowPitch = dnHighPitch - nAmplitude;
1211
ComputeTriangle(fUp, 0, nNumPoints, dnLowPitch, dnHighPitch, aContour);
1214
case lmCONTOUR_RAMP:
1215
//----------------------------------------------------------------------------
1217
// Amplitude will move two octaves from root to root note unless not possible
1219
ComputeRamp(0, nNumPoints, dnMinRoot, dnMaxRoot, aContour);
1221
ComputeRamp(0, nNumPoints, dnMaxRoot, dnMinRoot, aContour);
1224
case lmCONTOUR_TRIANGLE_RAMP:
1225
//----------------------------------------------------------------------------
1227
// Triangle occupies two thirds and ramp one third
1229
// Triangle: set up amplitude and last point
1230
int nPoints = 2* nNumPoints / 3;
1233
dnLowPitch = dnMinRoot;
1234
nAmplitude = dnMaxPitch - dnLowPitch;
1235
if (nAmplitude > 14)
1237
dnHighPitch = dnLowPitch + nAmplitude;
1238
dnStartRamp = dnHighPitch;
1239
dnEndRamp = dnLowPitch;
1243
dnHighPitch = dnMaxRoot;
1244
nAmplitude = dnHighPitch - dnMinPitch;
1245
if (nAmplitude > 14)
1247
dnLowPitch = dnHighPitch - nAmplitude;
1248
dnStartRamp = dnLowPitch;
1249
dnEndRamp = dnHighPitch;
1251
ComputeTriangle(fUp, 0, nPoints, dnLowPitch, dnHighPitch, aContour);
1252
ComputeRamp(nPoints, nNumPoints, dnStartRamp, dnEndRamp, aContour);
1256
case lmCONTOUR_ZIG_ZAG:
1257
//----------------------------------------------------------------------------
1259
// Triangle occupies two thirds and ramp one third
1261
// Triangle: set up amplitude and last point
1262
int nPoints = 2* nNumPoints / 3;
1265
dnLowPitch = dnMinRoot;
1266
nAmplitude = dnMaxPitch - dnLowPitch;
1267
if (nAmplitude > 14)
1269
dnHighPitch = dnLowPitch + nAmplitude;
1270
dnStartRamp = dnLowPitch;
1271
dnEndRamp = dnMaxRoot;
1275
dnHighPitch = dnMaxRoot;
1276
nAmplitude = dnHighPitch - dnMinPitch;
1277
if (nAmplitude > 14)
1279
dnLowPitch = dnHighPitch - nAmplitude;
1280
dnStartRamp = dnHighPitch;
1281
dnEndRamp = dnMinRoot;
1283
ComputeTriangle(fUp, 0, nPoints, dnLowPitch, dnHighPitch, aContour);
1284
ComputeRamp(nPoints, nNumPoints, dnStartRamp, dnEndRamp, aContour);
1288
case lmCONTOUR_RAMP_TRIANGLE:
1289
//----------------------------------------------------------------------------
1293
int nPoints = nNumPoints / 3;
1295
// Triangle: set up amplitude and last point
1298
dnLowPitch = dnMinRoot;
1299
nAmplitude = dnMaxPitch - dnLowPitch;
1300
if (nAmplitude > 14)
1302
dnHighPitch = dnLowPitch + nAmplitude;
1303
dnStartRamp = dnLowPitch;
1304
dnEndRamp = dnMaxRoot;
1308
dnHighPitch = dnMaxRoot;
1309
nAmplitude = dnHighPitch - dnMinPitch;
1310
if (nAmplitude > 14)
1312
dnLowPitch = dnHighPitch - nAmplitude;
1313
dnStartRamp = dnHighPitch;
1314
dnEndRamp = dnMinRoot;
1317
ComputeRamp(0, nPoints, dnStartRamp, dnEndRamp, aContour);
1318
ComputeTriangle(fUp, nPoints, nNumPoints, dnLowPitch, dnHighPitch, aContour);
1323
// #if (TRACE_COMPOSER == 1)
1324
// for (int i=0; i < nNumPoints; i++)
1325
// wxLogMessage(_T("[Composer::GenerateContour] point[%d] = %d"), i, aContour[i]);
1329
//---------------------------------------------------------------------------------------
1330
void Composer::ComputeTriangle(bool fUp, int iStart, int nPoints, DiatonicPitch dnLowPitch,
1331
DiatonicPitch dnHighPitch, std::vector<DiatonicPitch>& aPoints)
1333
// Triangle. Defined the amplitude, the center beat, and the direction
1334
// (up/down). Also by start pitch, top/bottom pitch, and end pitch
1337
float rNumPoints = (float)((nPoints-iStart)/2);
1338
float rStep = (float)(dnHighPitch - dnLowPitch) / rNumPoints;
1339
if (!fUp) rStep = -rStep;
1340
float yValue = (float)(fUp ? dnLowPitch : dnHighPitch);
1341
// #if (TRACE_COMPOSER == 1)
1342
// wxLogMessage(_T("[Composer::ComputeTriangle] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d, rStep=%.5f"),
1343
// (fUp ? _T("Yes") : _T("No")), iStart, nPoints, dnLowPitch, dnHighPitch, rStep);
1346
int nCenter = (nPoints+iStart)/2;
1347
for (; i < nCenter; i++)
1349
aPoints[i] = (int)floor(yValue+0.5);
1355
rStep = (float)(dnHighPitch - dnLowPitch) / ((float)(nPoints-iStart) - rNumPoints);
1358
// #if (TRACE_COMPOSER == 1)
1359
// wxLogMessage(_T("[Composer::ComputeTriangle] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d, rStep=%.5f"),
1360
// (fUp ? _T("Yes") : _T("No")), i, nPoints, dnLowPitch, dnHighPitch, rStep);
1362
for (; i < nPoints; i++)
1364
aPoints[i] = (int)floor(yValue+0.5);
1368
//force last point to be a root note
1369
aPoints[nPoints-1] = (fUp ? dnLowPitch : dnHighPitch);
1373
//---------------------------------------------------------------------------------------
1374
void Composer::ComputeRamp(int iStart, int nPoints, DiatonicPitch dnStartPitch,
1375
DiatonicPitch dnEndPitch, std::vector<DiatonicPitch>& aPoints)
1378
float rNumPoints = (float)(nPoints-iStart);
1379
float rStep = (float)(dnEndPitch - dnStartPitch) / rNumPoints;
1380
float yValue = (float)dnStartPitch;
1381
// #if (TRACE_COMPOSER == 1)
1382
// wxLogMessage(_T("[Composer::ComputeRamp] iStart=%d, nPoints=%d, dnStartPitch=%d, dnEndPitch=%d, rStep=%.5f"),
1383
// iStart, nPoints, dnStartPitch, dnEndPitch, rStep);
1385
for (int i=iStart; i < nPoints; i++)
1387
aPoints[i] = (int)floor(yValue+0.5);
1390
//force last point to be a root note
1391
aPoints[nPoints-1] = dnEndPitch;
1395
//---------------------------------------------------------------------------------------
1396
void Composer::ComputeArch(bool fUp, int iStart, int nPoints, DiatonicPitch dnLowPitch,
1397
DiatonicPitch dnHighPitch, std::vector<DiatonicPitch>& aPoints)
1399
// Arch. An arch will be defined the amplitude, the center beat, and the direction
1400
// (up/down). Also by start pitch, top/bottom pitch, and end pitch
1401
// I will use a second degree polinimio. I approximate it by using the Lagrange method.
1402
// The resulting polinom is
1403
// P(x) = RootPitch + ((4 * maxPitch * x * (numPoints - x))/numPoints**2)
1404
// = a3 + ((a1 * x * (numPoints - x))/ a2)
1405
// a1 = 4 * maxPitch
1406
// a2 = numPoints**2
1410
// #if (TRACE_COMPOSER == 1)
1411
// wxLogMessage(_T("[Composer::ComputeArch] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d"),
1412
// (fUp ? _T("Yes") : _T("No")), iStart, nPoints, dnLowPitch, dnHighPitch);
1414
float a1 = 4.0 * (float)(dnHighPitch-dnLowPitch);
1415
float a2 = (float)(nPoints * nPoints);
1416
float a3 = (float)dnLowPitch;
1417
float a4 = (float)nPoints;
1419
for (int i=iStart; i < iStart+nPoints; i++, x+=1.0)
1421
float y = a3 + ((a1 * x * (a4 - x)) / a2);
1422
aPoints[i] = (int)floor(y + 0.5);
1424
//force last point to be a root note
1425
aPoints[iStart+nPoints-1] = (fUp ? dnLowPitch : dnHighPitch);
1429
//---------------------------------------------------------------------------------------
1430
FPitch Composer::NearestNoteOnChord(DiatonicPitch nPoint, ImoNote* pNotePrev,
1432
std::vector<FPitch>& aOnChordPitch)
1434
// #if (TRACE_COMPOSER == 1)
1435
// wxLogMessage(_T("[Composer::NearestNoteOnChord] nPoint=%d"), nPoint );
1438
// if note is tied to previous one, return previous note pitch
1439
if (pNotePrev && pNotePrev->is_tied_next() && pNotePrev->is_pitch_defined())
1441
// #if (TRACE_COMPOSER == 1)
1442
// wxLogMessage(_T("[Composer::NearestNoteOnChord] Previous note = %s"), (pNotePrev->get_fpitch()).to_abs_ldp_name().c_str());
1444
return pNotePrev->get_fpitch();
1447
for (int i=0; i < (int)aOnChordPitch.size(); i++)
1449
DiatonicPitch dnCur = aOnChordPitch[i].to_diatonic_pitch();
1450
if (nPoint == dnCur)
1451
return aOnChordPitch[i];
1452
else if (nPoint < dnCur)
1454
// The nearest one is this one or the previous one
1455
// If no previous one, return this one
1457
return aOnChordPitch[i];
1458
// there is a 'previous one'. So lets compute differences
1459
DiatonicPitch dnPrev = aOnChordPitch[i-1].to_diatonic_pitch();
1460
if (nPoint - dnPrev < dnCur - nPoint)
1461
return aOnChordPitch[i-1];
1463
return aOnChordPitch[i];
1467
//requested note is out of range. Return maximum allowed one
1468
//return aOnChordPitch[aOnChordPitch.size()-1];
1469
return aOnChordPitch[aOnChordPitch.size()-1];
1471
return FPitch("c4");
1474
//---------------------------------------------------------------------------------------
1475
void Composer::InstantiateWithNote(ImoScore* pScore, FPitch fp)
1477
// This method is used only to generate images for documentation.
1478
// The idea is to instantiate the score with the same pitch for all
1479
// notes, to create scores with the rhymth pattern
1481
// Loop to instantiate notes
1482
ColStaffObjs* pColStaffObjs = pScore->get_staffobjs_table();
1483
ColStaffObjs::iterator it = pColStaffObjs->begin();
1484
while(it != pColStaffObjs->end())
1486
ImoObj* pImo = (*it)->imo_object();
1487
if (pImo->is_note())
1489
// It is a note. Instantiate it
1490
ImoNote* pNote = static_cast<ImoNote*>(pImo);
1491
set_pitch(pNote, fp);
1497
//---------------------------------------------------------------------------------------
1498
void Composer::AssignNonChordNotes(int nNumNotes, ImoNote* pOnChord1, ImoNote* pOnChord2,
1499
ImoNote* pNonChord[], FPitch scale[7])
1501
// Receives the two on-chord notes and the non-chord notes between them, and assign
1502
// the pitch to all notes
1503
// The first on-chord note can be NULL (first anacruxis measure)
1504
// The number of non-chord notes received is in 'nNumNotes'
1507
//case: no non-chord notes. Nothing to do
1510
// #if (TRACE_PITCH == 1)
1511
// wxLogMessage(_T("[Composer::AssignNonChordNotes] No non-chord notes. Nothing to do."));
1516
//case: anacruxis measure
1519
// #if (TRACE_PITCH == 1)
1520
// wxLogMessage(_T("[Composer::AssignNonChordNotes] Anacruxis measure"));
1523
//we are going to assing an ascending sequence, by step, to finish in the root
1524
//note (the first on chord note)
1528
set_pitch(pNonChord[0], pOnChord2->get_fpitch());
1532
// ascending sequence of steps
1533
FPitch nPitch = pOnChord2->get_fpitch();
1534
for(int i=nNumNotes-1; i >= 0; i--)
1536
if (!pNonChord[i]->is_pitch_defined())
1538
nPitch = MoveByStep(k_down, nPitch, scale);
1539
set_pitch(pNonChord[i], nPitch);
1546
// Compute inteval formed by on-chord notes
1547
FPitch ap1 = pOnChord1->get_fpitch();
1548
FPitch ap2 = pOnChord2->get_fpitch();
1549
//FPitch fp1 = FPitch(ap1);
1550
//FPitch fp2 = FPitch(ap2);
1551
int nDIntval = ap2.to_diatonic_pitch() - ap1.to_diatonic_pitch();
1552
//int nFIntval = abs(fp2 - fp1);
1553
int nAbsIntval = abs(nDIntval) + 1;
1555
//Choose non-chord notes type depending on interval formed by on-chord notes
1556
if (nAbsIntval == 1)
1559
//If one or two notes use neighboring notes. If more notes
1560
//choose between neighboring notes or on-chord arpege
1562
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1564
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1568
else if (nAbsIntval == 2)
1571
//If one note there are several possibilities (anticipation / suspension /
1572
//retardation / appogiatura) but I will just use a on-chord tone (a third apart)
1574
ThirdFifthNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1576
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1580
else if (nAbsIntval == 3)
1583
//If one note use a passing note, else we could use two passing notes by
1584
//chromatic step, but chromatic accidentals could not be appropriate for
1585
//lower music reading levels; therefore I will use a neighboring tone
1587
PassingNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1589
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1593
else if (nAbsIntval == 4)
1596
//interval 1: Third / Appoggiatura
1597
//interval 2: Two passing tones (by step) / Appoggiatura
1599
ThirdFifthNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1600
else if (nNumNotes == 1)
1601
PassingNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1603
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1607
else if (nAbsIntval == 5)
1610
//interval 1: Third / Appoggiatura
1611
//interval 2: Third+Fifth / Double appoggiatura
1612
//interval 3: three passing tones (by step)
1614
ThirdFifthNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1615
else if (nNumNotes == 3)
1616
PassingNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1618
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1622
else if (nAbsIntval == 6)
1625
//interval 1: Appoggiatura
1626
//interval 2: Double appoggiatura
1627
//interval 4: four passing tones (by step)
1629
ThirdFifthNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1630
else if (nNumNotes == 4)
1631
PassingNotes((nDIntval > 0), nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1633
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1639
wxLogMessage(_T("[Composer::AssignNonChordNotes] Program error: ")
1640
_T("case not defined: Intval %d, num.notes %d"),
1641
nAbsIntval, nNumNotes );
1642
NeightboringNotes(nNumNotes, pOnChord1, pOnChord2, pNonChord, scale);
1647
//---------------------------------------------------------------------------------------
1648
void Composer::NeightboringNotes(int nNumNotes, ImoNote* pOnChord1, ImoNote* pOnChord2,
1649
ImoNote* pNonChord[], FPitch scale[7])
1651
// Receives the two on-chord notes and the non-chord notes between them, and assign
1652
// the pitch to all notes. The number of non-chord notes received is in 'nNumNotes'
1654
//wxASSERT(nNumNotes > 0 && nNumNotes < 4);
1655
//// 1, 2 or 3 neightboring notes
1657
bool fUpStep = RandomGenerator::flip_coin();
1658
FPitch ap = pOnChord1->get_fpitch();
1659
//wxASSERT(ap.to_diatonic_pitch() != lmNO_NOTE);
1660
FPitch nFirstPitch = MoveByStep(fUpStep, ap, scale);
1661
set_pitch(pNonChord[0], nFirstPitch);
1662
if (nNumNotes == 1) return;
1663
set_pitch(pNonChord[1], MoveByStep(!fUpStep, ap, scale));
1664
if (nNumNotes == 2) return;
1665
set_pitch(pNonChord[2], nFirstPitch);
1668
//---------------------------------------------------------------------------------------
1669
void Composer::PassingNotes(bool fUp, int nNumNotes, ImoNote* pOnChord1, ImoNote* pOnChord2,
1670
ImoNote* pNonChord[], FPitch scale[7])
1672
// Receives the two on-chord notes and the non-chord notes between them, and assign
1673
// the pitch to all notes. The number of non-chord notes received is in 'nNumNotes'
1675
wxASSERT(nNumNotes > 0);
1678
FPitch apNewPitch = pOnChord1->get_fpitch();
1679
set_pitch(pNonChord[0], MoveByStep(fUp, apNewPitch, scale));
1681
// two passing notes
1682
for (int i=1; i < nNumNotes; i++)
1684
apNewPitch = MoveByStep(fUp, apNewPitch, scale);
1685
set_pitch(pNonChord[i], apNewPitch);
1689
//---------------------------------------------------------------------------------------
1690
void Composer::ThirdFifthNotes(bool fUp, int nNumNotes, ImoNote* pOnChord1,
1692
ImoNote* pNonChord[], FPitch scale[7])
1694
// Receives the two on-chord notes and the non-chord notes between them, and assign
1695
// the pitch to all notes. The number of non-chord notes received is in 'nNumNotes'
1697
wxASSERT(nNumNotes == 1 || nNumNotes == 2);
1700
FPitch pitch = MoveByStep(fUp, pOnChord1->get_fpitch(), scale); //second
1701
pitch = MoveByStep(fUp, pitch, scale); //third
1702
set_pitch(pNonChord[0], pitch);
1703
if (nNumNotes == 1) return;
1705
pitch = MoveByStep(fUp, pitch, scale); //fourth
1706
pitch = MoveByStep(fUp, pitch, scale); //fifth
1707
set_pitch(pNonChord[1], pitch);
1710
//---------------------------------------------------------------------------------------
1711
int Composer::get_metronome_pulses_for(ETimeSignature nTimeSign)
1713
//returns the number of pulses (metronome pulses) implied by the received
1716
switch (nTimeSign) {
1743
//---------------------------------------------------------------------------------------
1744
int Composer::get_top_number_for(ETimeSignature nTimeSign)
1746
//returns the numerator of time signature fraction
1748
switch (nTimeSign) {
1775
//---------------------------------------------------------------------------------------
1776
int Composer::get_bottom_number_for(ETimeSignature nTimeSign)
1778
switch (nTimeSign) {
1801
//---------------------------------------------------------------------------------------
1802
int Composer::get_num_ref_notes_per_pulse_for(ETimeSignature nTimeSign)
1804
switch (nTimeSign) {
1827
//---------------------------------------------------------------------------------------
1828
float Composer::get_ref_note_duration_for(ETimeSignature nTimeSign)
1830
// returns beat duration (in LDP notes duration units)
1832
int nBeatType = get_bottom_number_for(nTimeSign);
1833
return lomse::get_duration_for_ref_note(nBeatType);
1836
//---------------------------------------------------------------------------------------
1837
float Composer::get_measure_duration_for(ETimeSignature nTimeSign)
1839
// Returns the required duration for a measure in the received time signature
1841
float rNumBeats = (float)get_top_number_for(nTimeSign);
1842
return rNumBeats * get_ref_note_duration_for(nTimeSign);
1845
//---------------------------------------------------------------------------------------
1846
void Composer::set_pitch(ImoNote* pNote, FPitch fp)
1848
int nAccidentals[7];
1849
lomse::get_accidentals_for_key(m_nKey, nAccidentals);
1850
EAccidentals acc = EAccidentals( nAccidentals[fp.step()] );
1851
if (!pNote->is_pitch_defined())
1853
pNote->set_notated_pitch(fp.step(), fp.octave(), k_no_accidentals);
1854
pNote->set_actual_accidentals(acc);
1857
if (pNote->is_tied_next())
1859
ImoTie* pTie = pNote->get_tie_next();
1860
pNote = pTie->get_end_note();
1861
pNote->set_notated_pitch(fp.step(), fp.octave(), k_no_accidentals);
1862
pNote->set_actual_accidentals(acc);
1868
} //namespace lenmus