~s-cecilio/lenmus/v5.1.x

« back to all changes in this revision

Viewing changes to src/auxmusic/lenmus_composer.cpp

  • Committer: cecilios
  • Date: 2012-09-07 17:42:21 UTC
  • Revision ID: svn-v4:2587a929-2f0e-0410-ae78-fe6f687d5efe:branches/TRY-5.0:721
initial commit with all changes for 5.1. See changelog

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
#include <algorithm>
43
43
//#include <vector>
44
44
 
 
45
#define TRACE_COMPOSER  0
 
46
#define TRACE_PITCH     0
45
47
 
46
48
 
47
49
namespace lenmus
136
138
    //        Instead of generating beats, let's organize the main loop around generating
137
139
    //        measures.
138
140
    //        Lets use patterns that contains musical phrases instead of full measures.
139
 
    //        Patterns will contain, when necessary, baline alignment information.
 
141
    //        Patterns will contain, when necessary, barline alignment information.
140
142
    //        Before adding a pattern to the current measure, lets align the pattern by
141
143
    //        inserting rests, if required.
142
144
    //
165
167
    //    Rationale:
166
168
    //        Algorithm 2 generates scores with mis-aligments and irregular measures.
167
169
    //        The problem is due to lack of information about alignment. So in this
168
 
    //        improved algorith we will also use patterns containing musical phrases
 
170
    //        improved algorithm I will also use patterns containing musical phrases
169
171
    //        instead of full measures.
170
172
    //        These patterns will be called 'fragments'. Fragments are divided into
171
173
    //        'segments' (a segment is a group of elements - notes and rests - that must
174
176
    //
175
177
    //        The algorithm is essentialy the same, but the method to add beats is
176
178
    //        improved by taking into account alignment and duration information. Also
177
 
    //        we must take into account that a segment may contain more than a beat.
 
179
    //        it is necessary to take into account that a segment may contain one or
 
180
    //        more beats (not necessarily full beats).
178
181
    //
179
182
    //        Another improvement is generating the final measure not by using fragments
180
 
    //        but by generation a note lasting one ore more beats. And its pitch is the root
181
 
    //        pitch of the used key signature.
 
183
    //        but by generation a note lasting one ore more beats. And its pitch is
 
184
    //        the root pitch of the used key signature.
182
185
    //
183
186
    //        Notes.
184
 
    //        - It is assumed that all beats are equal. Therefore, current algorith
185
 
    //            works only for regular time signature rhythms. It will
186
 
    //            not work, for example, with 7/8.
 
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.
187
190
    //
188
191
    //
189
192
    //
209
212
    //Save parameters
210
213
    m_pConstrains = pConstrains;
211
214
 
212
 
    //Generate a random key, time signature and clef satisfying the constraints
 
215
    //Generate a random key, time signature and clef satisfying the constrains
213
216
    m_nClef = RandomGenerator::generate_clef(m_pConstrains->GetClefConstrains());
214
217
    m_nKey = RandomGenerator::generate_key(m_pConstrains->GetKeyConstrains());
215
218
    m_nTimeSign = RandomGenerator::GenerateTimeSign(m_pConstrains->GetTimeSignConstrains());
 
219
    bool fCompound = get_num_ref_notes_per_pulse_for(m_nTimeSign) != 1;
216
220
 
217
221
    // prepare and initialize the score
218
222
    ImoScore* pScore = static_cast<ImoScore*>(ImFactory::inject(k_imo_score, pDoc));
236
240
    pScore->close();
237
241
    return pScore;
238
242
#else
239
 
    int beats = get_beats_for(m_nTimeSign);
240
 
    int type = get_beat_type_for(m_nTimeSign);
 
243
    int beats = get_top_number_for(m_nTimeSign);
 
244
    int type = get_bottom_number_for(m_nTimeSign);
241
245
    pInstr->add_time_signature(beats, type);
242
246
#endif
243
247
 
250
254
    int nMeasuresToGenerate = NUM_MEASURES - 1;
251
255
    int nNumMeasures = 0;
252
256
    float rMeasureDuration = get_measure_duration_for(m_nTimeSign);       //tm
253
 
    float rBeatDuration = get_beat_duration_for(m_nTimeSign);             //tb
 
257
    float rBeatDuration = get_ref_note_duration_for(m_nTimeSign);             //tb
254
258
    float rTimeRemaining;           //tr
255
259
    float rSegmentDuration;         //ts
256
260
    float rConsumedBeatTime;        //tcb
258
262
 
259
263
 
260
264
    // Loop to generate the required measures
261
 
    string sMeasure;                //source code of current measure
 
265
    wxString sMeasure;                //source code of current measure
262
266
    bool fFits;                     //current segment fits in current measure
263
267
    float rOccupiedDuration;        //consumed time in current measure (tc)
264
268
    bool fMeasure = false;          //there is a measure started
268
272
    if (m_pConstrains->SelectFragments(m_nTimeSign) == 0)
269
273
    {
270
274
        //TODO: error logging. Suppress message
271
 
        wxMessageBox(_("[Composer::GenerateScore] No usable fragments!"));
 
275
        wxLogMessage(_T("[Composer::GenerateScore] No usable fragments!"));
272
276
        return pScore;
273
277
    }
274
278
 
280
284
    int nSegmentLoopCounter = 0;
281
285
    while (nNumMeasures < nMeasuresToGenerate)
282
286
    {
283
 
        //If no measure is opened start a LENMUS_NEW measure
 
287
        //If no measure is opened start a new measure
284
288
        if (!fMeasure)
285
289
        {
286
 
            sMeasure = "";
 
290
            sMeasure = _T("");
287
291
            rOccupiedDuration = 0.0;
288
292
            fMeasure = true;
289
293
        }
290
294
 
291
 
        //If there are no more segments in current fragment, choose a LENMUS_NEW fragment
 
295
        //If there are no more segments in current fragment, choose a new fragment
292
296
        if (!pSegment)
293
297
        {
294
 
            //Randomly choose a LENMUS_NEW fragment satisfying the constraints
 
298
            //Randomly choose a new fragment satisfying the constraints
295
299
            pConstrains->ChooseRandomFragment();
296
300
            pSegment = pConstrains->GetNextSegment();
297
301
            wxASSERT(pSegment);     //there must exits a fragment satisfying
316
320
            fFits = (!is_lower_time(rTimeRemaining, rSegmentDuration)
317
321
                     && !is_greater_time(rConsumedBeatTime, rSegmentAlignBeatTime));
318
322
 
319
 
            ////TODO 5.0
320
 
            //g_pLogger->LogTrace(_T("Composer"), _T("[GenerateScore] sMeasure=%s, pSegment=%s, tr=%.2f, ts=%.2f, tcb=%.2f, tab=%.2f, tc=%.2f, tb=%.2f, fits=%s"),
321
 
            //        sMeasure.c_str(),
322
 
            //        (pSegment->GetSource()).c_str(), rTimeRemaining, rSegmentDuration,
323
 
            //        rConsumedBeatTime, rSegmentAlignBeatTime,
324
 
            //        rOccupiedDuration, rBeatDuration,
325
 
            //        (fFits ? _T("yes") : _T("no")) );
 
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"),
 
325
                    sMeasure.c_str(),
 
326
                    (pSegment->GetSource()).c_str(), rTimeRemaining, rSegmentDuration,
 
327
                    rConsumedBeatTime, rSegmentAlignBeatTime,
 
328
                    rOccupiedDuration, rBeatDuration,
 
329
                    (fFits ? _T("yes") : _T("no")) );
 
330
            #endif
326
331
 
327
332
            //if segment fits add it to current measure
328
333
            if (fFits)
332
337
                if (is_greater_time(rNoteTime, 0.0f))
333
338
                {
334
339
                    if (rConsumedBeatTime > 0.0f)
335
 
                        sMeasure += CreateNote((int)rNoteTime);
 
340
                        sMeasure += CreateNote((int)rNoteTime, fCompound, false /*not final note*/);
336
341
                    else
337
 
                        sMeasure += CreateRest((int)rNoteTime);
 
342
                        sMeasure += CreateRest((int)rNoteTime, fCompound, false /*not final rest*/);
338
343
                }
339
344
 
340
345
                //add segment
341
 
                sMeasure += to_std_string( pSegment->GetSource() );
 
346
                sMeasure += pSegment->GetSource();
 
347
                #if (TRACE_COMPOSER == 1)
 
348
                wxLogMessage(_T("[Composer::GenerateScore] Adding segment. Measure = '%s')"),
 
349
                             sMeasure.c_str());
 
350
                #endif
342
351
 
343
352
                //update tr
344
353
                rOccupiedDuration += rSegmentDuration + rNoteTime;
350
359
            else
351
360
            {
352
361
                //does not fit.
 
362
                #if (TRACE_COMPOSER == 1)
 
363
                wxLogMessage(_T("[Composer::GenerateScore] Segment does not fit. Ignored"));
 
364
                #endif
353
365
                if (nSegmentLoopCounter++ > 100)
354
366
                {
355
367
                    //let's assume that no segment fits. Fill the measure with a note
356
 
                    sMeasure += CreateNote((int)rTimeRemaining);
 
368
                    sMeasure += CreateNote((int)rTimeRemaining, fCompound, false /*not final note*/);
357
369
                    rOccupiedDuration += rTimeRemaining;
358
370
                    nSegmentLoopCounter = 0;
359
371
                }
371
383
 
372
384
            // close current measure
373
385
            fMeasure = false;   // no measure opened
374
 
            sMeasure += "(barline simple)";
 
386
            sMeasure += _T("(barline simple)");
375
387
 
376
388
            // increment measures counter
377
389
            nNumMeasures++;
378
390
 
379
391
            // Instantiate the notes by assigning note pitches and add
380
392
            // the measure to the score
381
 
            ////TODO 5.0
382
 
            //g_pLogger->LogTrace(_T("Composer"),
383
 
            //        _T("[GenerateScore] Adding measure = '%s')"), sMeasure.c_str());
384
 
            pInstr->add_staff_objects(sMeasure);
 
393
            #if (TRACE_COMPOSER == 1)
 
394
            wxLogMessage(_T("[Composer::GenerateScore] Adding measure = '%s')"),
 
395
                         sMeasure.c_str());
 
396
            #endif
 
397
            pInstr->add_staff_objects( to_std_string(sMeasure) );
385
398
        }
386
399
 
387
400
    }
409
422
        ++it;
410
423
    }
411
424
 
412
 
    //    ////TODO 5.0
413
 
//    //g_pLogger->LogTrace(_T("Composer"),
414
 
//    //        _T("[GenerateScore] fOnlyQuarterNotes=%s)"),
415
 
//    //        (fOnlyQuarterNotes ? _T("True") : _T("False")) );
 
425
    #if (TRACE_COMPOSER == 1)
 
426
    wxLogMessage(_T("[Composer::GenerateScore] fOnlyQuarterNotes=%s)"),
 
427
            (fOnlyQuarterNotes ? _T("True") : _T("False")) );
 
428
    #endif
416
429
 
417
430
    // add a final measure with a root pitch note lasting, at least, one beat
418
431
    sMeasure = CreateLastMeasure(++nNumMeasures, m_nTimeSign, fOnlyQuarterNotes);
419
 
    pInstr->add_staff_objects(sMeasure);
 
432
    pInstr->add_staff_objects( to_std_string(sMeasure) );
420
433
 
421
434
    pScore->close();
422
435
 
423
 
    ////TODO 5.0
424
 
    //g_pLogger->LogTrace(_T("Composer"),
425
 
    //        _T("[GenerateScore] Adding final measure = '%s')"), sMeasure.c_str());
 
436
    #if (TRACE_COMPOSER == 1)
 
437
    wxLogMessage(_T("[Composer::GenerateScore] Adding final measure = '%s')"), sMeasure.c_str());
 
438
    #endif
426
439
 
427
440
 
428
441
     //Score is built but pitches are not yet defined.
433
446
#if 0   //useful to generate only the rhymth line, to write documenation
434
447
    InstantiateWithNote(pScore, FPitch("b3") );
435
448
#else
436
 
    InstantiateNotes(pScore, m_nKey);
 
449
    InstantiateNotes(pScore, m_nKey, nNumMeasures);
437
450
#endif
438
451
 
439
452
    // done
453
466
}
454
467
 
455
468
//---------------------------------------------------------------------------------------
456
 
string Composer::CreateNoteRest(int nNoteRestDuration, bool fNote)
 
469
wxString Composer::CreateNoteRest(int nNoteRestDuration, bool fNote, bool fCompound,
 
470
                                  bool fFinal)
457
471
{
458
472
    //Returns a string with one or more LDP elements containing notes o rests up to a total
459
473
    //duration nNoteDuration. They will be notes if fNote==true; otherwise they will be rests.
460
474
    //For example, for nNoteDuration=64 it will return "(n * n)"
461
475
 
462
 
    string sElement = "";
 
476
    wxString sElement = _T("");
463
477
    int nDuration;
464
478
    int nTimeNeeded = nNoteRestDuration;
465
479
 
466
 
    while (nTimeNeeded > 0)
467
 
    {
468
 
        sElement += (fNote ? "(n * " : "(r " );
469
 
        if (nTimeNeeded >= k_duration_whole_dotted)
470
 
        {
471
 
            sElement += "w.)";
472
 
            nDuration = k_duration_whole_dotted;
473
 
        }
474
 
        else if (nTimeNeeded >= k_duration_whole)
475
 
        {
476
 
            sElement += "w)";
477
 
            nDuration = k_duration_whole;
478
 
        }
479
 
        else if (nTimeNeeded >= k_duration_half_dotted)
480
 
        {
481
 
            sElement += "h.)";
482
 
            nDuration = k_duration_half_dotted;
483
 
        }
484
 
        else if (nTimeNeeded >= k_duration_half) 
485
 
        {
486
 
            sElement += "h)";
487
 
            nDuration = k_duration_half;
488
 
        }
489
 
        else if (nTimeNeeded >= k_duration_quarter_dotted) 
490
 
        {
491
 
            sElement += "q.)";
492
 
            nDuration = k_duration_quarter_dotted;
493
 
        }
494
 
        else if (nTimeNeeded >= k_duration_quarter) 
495
 
        {
496
 
            sElement += "q)";
497
 
            nDuration = k_duration_quarter;
498
 
        }
499
 
        else if (nTimeNeeded >= k_duration_eighth_dotted) 
500
 
        {
501
 
            sElement += "e.)";
502
 
            nDuration = k_duration_eighth_dotted;
503
 
        }
504
 
        else if (nTimeNeeded >= k_duration_eighth) 
505
 
        {
506
 
            sElement += "e)";
507
 
            nDuration = k_duration_eighth;
508
 
        }
509
 
        else if (nTimeNeeded >= k_duration_16th_dotted) 
510
 
        {
511
 
            sElement += "s.)";
512
 
            nDuration = k_duration_16th_dotted;
513
 
        }
514
 
        else if (nTimeNeeded >= k_duration_16th) 
515
 
        {
516
 
            sElement += "s)";
517
 
            nDuration = k_duration_16th;
518
 
        }
519
 
        else if (nTimeNeeded >= k_duration_32th_dotted) 
520
 
        {
521
 
            sElement += "t.)";
522
 
            nDuration = k_duration_32th_dotted;
523
 
        }
524
 
        else if (nTimeNeeded >= k_duration_32th) 
525
 
        {
526
 
            sElement += "t)";
527
 
            nDuration = k_duration_32th;
528
 
        }
529
 
        else if (nTimeNeeded >= k_duration_64th_dotted) 
530
 
        {
531
 
            sElement += "i.)";
532
 
            nDuration = k_duration_64th_dotted;
533
 
        }
534
 
        else if (nTimeNeeded >= k_duration_64th) 
535
 
        {
536
 
            sElement += "i)";
537
 
            nDuration = k_duration_64th;
538
 
        }
539
 
        else if (nTimeNeeded >= k_duration_128th_dotted)
540
 
        {
541
 
            sElement += "o.)";
542
 
            nDuration = k_duration_128th_dotted;
543
 
        }
544
 
        else if (nTimeNeeded >= k_duration_128th) 
545
 
        {
546
 
            sElement += "o)";
547
 
            nDuration = k_duration_128th;
548
 
        }
549
 
        else 
550
 
        {
551
 
            sElement += "f)";
552
 
            nDuration = k_duration_256th;
553
 
        }
554
 
 
555
 
        nTimeNeeded -= nDuration;
556
 
    }
557
 
 
558
 
    ////TODO 5.0
559
 
    //g_pLogger->LogTrace(_T("Composer"), _T("[CreateNoteRest] Needed duration= %d, added=%s"),
560
 
    //    nNoteRestDuration, sElement.c_str());
 
480
    if (fCompound && fFinal)
 
481
    {
 
482
        while (nTimeNeeded > 0)
 
483
        {
 
484
            sElement += (fNote ? _T("(n * ") : _T("(r ") );
 
485
            if (nTimeNeeded >= k_duration_whole_dotted)
 
486
            {
 
487
                sElement += _T("w.)");
 
488
                nDuration = k_duration_whole_dotted;
 
489
            }
 
490
            else if (nTimeNeeded >= k_duration_half_dotted)
 
491
            {
 
492
                sElement += _T("h.)");
 
493
                nDuration = k_duration_half_dotted;
 
494
            }
 
495
            else if (nTimeNeeded >= k_duration_quarter_dotted)
 
496
            {
 
497
                sElement += _T("q.)");
 
498
                nDuration = k_duration_quarter_dotted;
 
499
            }
 
500
            else if (nTimeNeeded >= k_duration_eighth_dotted)
 
501
            {
 
502
                sElement += _T("e.)");
 
503
                nDuration = k_duration_eighth_dotted;
 
504
            }
 
505
            else if (nTimeNeeded >= k_duration_16th_dotted)
 
506
            {
 
507
                sElement += _T("s.)");
 
508
                nDuration = k_duration_16th_dotted;
 
509
            }
 
510
            else if (nTimeNeeded >= k_duration_32th_dotted)
 
511
            {
 
512
                sElement += _T("t.)");
 
513
                nDuration = k_duration_32th_dotted;
 
514
            }
 
515
            else if (nTimeNeeded >= k_duration_64th_dotted)
 
516
            {
 
517
                sElement += _T("i.)");
 
518
                nDuration = k_duration_64th_dotted;
 
519
            }
 
520
            else if (nTimeNeeded >= k_duration_128th_dotted)
 
521
            {
 
522
                sElement += _T("o.)");
 
523
                nDuration = k_duration_128th_dotted;
 
524
            }
 
525
            else
 
526
            {
 
527
                sElement += _T("f)");
 
528
                nDuration = k_duration_256th;
 
529
            }
 
530
 
 
531
            nTimeNeeded -= nDuration;
 
532
        }
 
533
    }
 
534
    else
 
535
    {
 
536
        while (nTimeNeeded > 0)
 
537
        {
 
538
            sElement += (fNote ? _T("(n * ") : _T("(r ") );
 
539
            if (nTimeNeeded >= k_duration_whole_dotted)
 
540
            {
 
541
                sElement += _T("w.)");
 
542
                nDuration = k_duration_whole_dotted;
 
543
            }
 
544
            else if (nTimeNeeded >= k_duration_whole)
 
545
            {
 
546
                sElement += _T("w)");
 
547
                nDuration = k_duration_whole;
 
548
            }
 
549
            else if (nTimeNeeded >= k_duration_half_dotted)
 
550
            {
 
551
                sElement += _T("h.)");
 
552
                nDuration = k_duration_half_dotted;
 
553
            }
 
554
            else if (nTimeNeeded >= k_duration_half)
 
555
            {
 
556
                sElement += _T("h)");
 
557
                nDuration = k_duration_half;
 
558
            }
 
559
            else if (nTimeNeeded >= k_duration_quarter_dotted)
 
560
            {
 
561
                sElement += _T("q.)");
 
562
                nDuration = k_duration_quarter_dotted;
 
563
            }
 
564
            else if (nTimeNeeded >= k_duration_quarter)
 
565
            {
 
566
                sElement += _T("q)");
 
567
                nDuration = k_duration_quarter;
 
568
            }
 
569
            else if (nTimeNeeded >= k_duration_eighth_dotted)
 
570
            {
 
571
                sElement += _T("e.)");
 
572
                nDuration = k_duration_eighth_dotted;
 
573
            }
 
574
            else if (nTimeNeeded >= k_duration_eighth)
 
575
            {
 
576
                sElement += _T("e)");
 
577
                nDuration = k_duration_eighth;
 
578
            }
 
579
            else if (nTimeNeeded >= k_duration_16th_dotted)
 
580
            {
 
581
                sElement += _T("s.)");
 
582
                nDuration = k_duration_16th_dotted;
 
583
            }
 
584
            else if (nTimeNeeded >= k_duration_16th)
 
585
            {
 
586
                sElement += _T("s)");
 
587
                nDuration = k_duration_16th;
 
588
            }
 
589
            else if (nTimeNeeded >= k_duration_32th_dotted)
 
590
            {
 
591
                sElement += _T("t.)");
 
592
                nDuration = k_duration_32th_dotted;
 
593
            }
 
594
            else if (nTimeNeeded >= k_duration_32th)
 
595
            {
 
596
                sElement += _T("t)");
 
597
                nDuration = k_duration_32th;
 
598
            }
 
599
            else if (nTimeNeeded >= k_duration_64th_dotted)
 
600
            {
 
601
                sElement += _T("i.)");
 
602
                nDuration = k_duration_64th_dotted;
 
603
            }
 
604
            else if (nTimeNeeded >= k_duration_64th)
 
605
            {
 
606
                sElement += _T("i)");
 
607
                nDuration = k_duration_64th;
 
608
            }
 
609
            else if (nTimeNeeded >= k_duration_128th_dotted)
 
610
            {
 
611
                sElement += _T("o.)");
 
612
                nDuration = k_duration_128th_dotted;
 
613
            }
 
614
            else if (nTimeNeeded >= k_duration_128th)
 
615
            {
 
616
                sElement += _T("o)");
 
617
                nDuration = k_duration_128th;
 
618
            }
 
619
            else
 
620
            {
 
621
                sElement += _T("f)");
 
622
                nDuration = k_duration_256th;
 
623
            }
 
624
 
 
625
            nTimeNeeded -= nDuration;
 
626
        }
 
627
    }
 
628
 
 
629
    #if (TRACE_COMPOSER == 1)
 
630
    wxLogMessage(_T("[Composer::CreateNoteRest] Needed duration= %d, added=%s"),
 
631
        nNoteRestDuration, sElement.c_str());
 
632
    #endif
561
633
 
562
634
    return sElement;
563
635
}
564
636
 
565
637
//---------------------------------------------------------------------------------------
566
 
string Composer::CreateLastMeasure(int nNumMeasure, ETimeSignature nTimeSign,
567
 
                                   bool fOnlyQuarterNotes)
 
638
wxString Composer::CreateLastMeasure(int nNumMeasure, ETimeSignature nTimeSign,
 
639
                                     bool fOnlyQuarterNotes)
568
640
{
569
641
    // Returns a final meaure. This final measure has only a note, long enough, and
570
642
    // a final bar
571
643
 
572
 
    string sMeasure = "";
 
644
    wxString sMeasure = _T("");
573
645
    float rMeasureDuration = get_measure_duration_for(nTimeSign);
574
 
    float rBeatDuration = get_beat_duration_for(nTimeSign);
575
 
    float rNoteDuration = rBeatDuration;
576
 
    if (!fOnlyQuarterNotes && rMeasureDuration / rBeatDuration >= 2.0)
 
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)
577
651
    {
578
652
        //flip coin to randomly add a one-beat note or a two-beats note
579
653
        if (RandomGenerator::flip_coin())
580
 
            rNoteDuration += rBeatDuration;
 
654
            rNoteDuration += rPulseDuration;
581
655
    }
582
656
 
583
 
    sMeasure += CreateNote((int)rNoteDuration);
 
657
    sMeasure += CreateNote((int)rNoteDuration, fCompound, true /*final note*/);
584
658
    rNoteDuration = rMeasureDuration - rNoteDuration;
585
 
    if (rNoteDuration > 0.0f) 
586
 
        sMeasure += CreateRest((int)rNoteDuration);
 
659
    if (rNoteDuration > 0.0f)
 
660
        sMeasure += CreateRest((int)rNoteDuration, fCompound, true /*final rest*/);
587
661
 
588
 
    sMeasure += "(barline end)";
 
662
    sMeasure += _T("(barline end)");
589
663
    return sMeasure;
590
664
}
591
665
 
593
667
// Methods to deal with tonality
594
668
//---------------------------------------------------------------------------------------
595
669
 
596
 
bool Composer::InstantiateNotes(ImoScore* pScore, EKeySignature nKey)
 
670
bool Composer::InstantiateNotes(ImoScore* pScore, EKeySignature nKey, int nNumMeasures)
597
671
{
598
672
    // Returns true if error
599
673
 
600
674
    // Choose a chord progression, based on key signature: nChords[]
601
 
    int nNumMeasures = 8;       //TODO 5.0   pScore->GetNumMeasures();
602
675
    std::vector<long> nChords(nNumMeasures);
603
676
    GetRandomHarmony(nNumMeasures, nChords);
604
677
 
612
685
    // So first we have to compute the number of on-chord notes. The following code is a
613
686
    // loop to count on-chord notes in first staff of first instrument
614
687
    // and to locate last note. This is necessary to assign it the root pitch (later)
615
 
    ImoNote* pLastNote = NULL;
 
688
//    ImoNote* pLastNote = NULL;
616
689
    int nNumPoints = 0;
617
690
    ImoTimeSignature* pTS = NULL;
618
691
    StaffObjsCursor cursor(pScore);
621
694
        ImoStaffObj* pSO = cursor.get_staffobj();
622
695
        if (pSO->is_note())
623
696
        {
624
 
            ImoNote* pNote = static_cast<ImoNote*>(pSO);
 
697
//            ImoNote* pNote = static_cast<ImoNote*>(pSO);
625
698
            int pos = k_off_beat;
626
699
            if (pTS)
627
700
                pos = get_beat_position(cursor.time(), pTS);
629
702
            if(pos != k_off_beat)
630
703
                nNumPoints++;   // on beat note
631
704
 
632
 
            pLastNote = pNote;
 
705
//            pLastNote = pNote;
633
706
        }
634
707
        else if (pSO->is_time_signature())
635
708
        {
660
733
    int iC = 0;                                         //index to current chord (ic)
661
734
    DiatonicPitch dnMinPitch = m_fpMinPitch.to_diatonic_pitch();
662
735
    DiatonicPitch dnMaxPitch = m_fpMaxPitch.to_diatonic_pitch();
663
 
    ////TODO 5.0
664
 
    //g_pLogger->LogTrace(_T("Composer::InstantiateNotes"), _T("min pitch %d (%s), max pitch %d (%s)"),
665
 
    //    dnMinPitch, DiatonicPitch_ToLDPName(dnMinPitch).c_str(),
666
 
    //    dnMaxPitch, DiatonicPitch_ToLDPName(dnMaxPitch).c_str() );
 
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() );
 
740
    #endif
667
741
    std::vector<FPitch> aOnChordPitch;
668
742
    aOnChordPitch.reserve((int(dnMaxPitch) - int(dnMinPitch))/2);    // Reserve space. Upper limit estimation
669
743
    FPitch nRootNote = GenerateInChordList(nKey, nChords[iC], aOnChordPitch);
698
772
                {
699
773
                    // on beat note. Pitch must be on chord.
700
774
                    // Assign a pitch from nChords[iC].
701
 
                    ////TODO 5.0
702
 
                    //for(int k=0; k < (int)aOnChordPitch.size(); k++)
703
 
                    //    g_pLogger->LogTrace(_T("Composer::InstantiateNotes"), _T("OnChord %d = %s"), k, aOnChordPitch[k].LDPName().c_str() );
 
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() );
 
778
    #endif
704
779
                    fpNew = NearestNoteOnChord(aContour[iPt++], pNotePrev, pNoteCur,
705
780
                                                    aOnChordPitch);
706
 
                    ////TODO 5.0
707
 
                    //for(int k=0; k < (int)aOnChordPitch.size(); k++)
708
 
                    //    g_pLogger->LogTrace(_T("Composer::InstantiateNotes"), _T("OnChord %d = %s"), k, aOnChordPitch[k].LDPName().c_str() );
709
 
                    //wxString sNoteName = fpNew.LDPName();
710
 
                    //g_pLogger->LogTrace(_T("Composer::InstantiateNotes"), _T("on-chord note %d. Assigned pitch = %d (%s), chord=%d"),
711
 
                    //    iPt, fpNew.to_diatonic_pitch(), sNoteName.c_str(),
712
 
                    //    nChords[iC] & lmGRADE_MASK);
 
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);
 
788
    #endif
713
789
 
714
790
                    set_pitch(pNoteCur, fpNew);
715
791
 
753
829
        cursor2.move_next();
754
830
    }
755
831
 
756
 
    ////TODO 5.0
757
 
    //g_pLogger->LogTrace(_T("Composer::InstantiateNotes"), sDbg);
 
832
    #if (TRACE_PITCH == 1)
 
833
    wxLogMessage(_T("[Composer::InstantiateNotes] %s"), sDbg.c_str());
 
834
    #endif
758
835
 
759
836
    return false;       // no error
760
837
}
771
848
        {
772
849
            FPitch fp = RandomPitch();
773
850
            ImoNote* pNote = static_cast<ImoNote*>(pImo);
774
 
            //TODO 5.0 propagate to tied notes
775
 
            //set_pitch(pNote, fpNew, lmCHANGE_TIED);
776
851
            set_pitch(pNote, fp);
777
852
        }
778
853
        ++it;
850
925
    notes[1] = FPitch( scale[iF+2] );
851
926
    notes[2] = FPitch( scale[iF+4] );
852
927
 
853
 
    ////TODO 5.0
854
 
    //g_pLogger->LogTrace(_T("Composer::FunctionToChordNotes"), _T("Function %d, Key=%d, note0 %d (%s), note1 %d (%s), note2 %d (%s)."),
855
 
    //    iF, nKey,
856
 
    //    notes[0].to_diatonic_pitch(), notes[0].LDPName().c_str(),
857
 
    //    notes[1].to_diatonic_pitch(), notes[1].LDPName().c_str(),
858
 
    //    notes[2].to_diatonic_pitch(), notes[2].LDPName().c_str() );
 
928
//    #if (TRACE_COMPOSER == 1)
 
929
//    wxLogMessage(_T("[Composer::FunctionToChordNotes] Function %d, Key=%d, note0 %d (%s), note1 %d (%s), note2 %d (%s)."),
 
930
//        iF, nKey,
 
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() );
 
934
//    #endif
859
935
}
860
936
 
861
937
//---------------------------------------------------------------------------------------
862
938
FPitch Composer::MoveByStep(bool fUpStep, FPitch nPitch, FPitch scale[7])
863
939
{
864
 
    // Generates a LENMUS_NEW note by moving up/down one step in the scale
865
 
    // The LENMUS_NEW pitch must be on the key signature natural scale
 
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
866
942
 
867
943
    // extract pitch components
868
944
    int nStep = nPitch.step();
895
971
//---------------------------------------------------------------------------------------
896
972
FPitch Composer::MoveByChromaticStep(bool fUpStep, FPitch pitch)
897
973
{
898
 
    // Generates a LENMUS_NEW note by moving up/down one chromatic step in the scale
 
974
    // Generates a new note by moving up/down one chromatic step in the scale
899
975
 
900
976
    // extract pitch accidentals
901
977
    int acc = pitch.accidentals();
940
1016
    // extract valid steps, to simplify
941
1017
    //TODO: review logic. Value NO_DPITCH is never returned.
942
1018
    int nValidStep[4];
943
 
    for (int i=0; i < 4; i++) 
 
1019
    for (int i=0; i < 4; i++)
944
1020
    {
945
1021
        if (notes[i].to_diatonic_pitch() == NO_DPITCH)
946
1022
            nValidStep[i] = -1;        //you can assign any non valid value for a step
990
1066
    DiatonicPitch dnMinPitch = m_fpMinPitch.to_diatonic_pitch();
991
1067
    DiatonicPitch dnMaxPitch = m_fpMaxPitch.to_diatonic_pitch();
992
1068
    int nAmplitude = int(dnMaxPitch) - int(dnMinPitch) + 1;
993
 
    ////TODO 5.0
994
 
    //g_pLogger->LogTrace(_T("Composer::GenerateContour"), _T("minPitch %d  (%s), max pitch %d (%s), amplitude %d"),
995
 
    //    dnMinPitch, DiatonicPitch_ToLDPName(dnMinPitch).c_str(),
996
 
    //    dnMaxPitch, DiatonicPitch_ToLDPName(dnMaxPitch).c_str(),
997
 
    //    nAmplitude );
 
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(),
 
1073
//        nAmplitude );
 
1074
//    #endif
998
1075
 
999
1076
 
1000
1077
        // determine minimum root pitch
1018
1095
    }
1019
1096
 
1020
1097
 
1021
 
    ////TODO 5.0
1022
 
    //g_pLogger->LogTrace(_T("Composer::GenerateContour"), _T("min root %d  (%s), max root %d (%s)"),
1023
 
    //    dnMinRoot, DiatonicPitch_ToLDPName(dnMinRoot).c_str(),
1024
 
    //    dnMaxRoot, DiatonicPitch_ToLDPName(dnMaxRoot).c_str() );
 
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() );
 
1102
//    #endif
1025
1103
 
1026
1104
 
1027
1105
 
1028
1106
    // Choose a contour curve
1029
 
    enum 
 
1107
    enum
1030
1108
    {
1031
1109
        lmCONTOUR_TRIANGLE = 0,
1032
1110
        lmCONTOUR_TRIANGLE_RAMP,
1078
1156
        fUp = RandomGenerator::flip_coin();
1079
1157
    }
1080
1158
 
1081
 
    ////TODO 5.0
1082
 
    //g_pLogger->LogTrace(_T("Composer::GenerateContour"), _T("type=%d, nNumPoints=%d, up=%s"),
1083
 
    //    nCurve, nNumPoints, (fUp ? _T("Yes") : _T("No")) );
 
1159
    #if (TRACE_PITCH == 1)
 
1160
    wxLogMessage(_T("[Composer::GenerateContour] type=%d, nNumPoints=%d, up=%s"),
 
1161
        nCurve, nNumPoints, (fUp ? _T("Yes") : _T("No")) );
 
1162
    #endif
1084
1163
 
1085
1164
    // prepare curve parameters and compute the curve points
1086
1165
    DiatonicPitch dnLowPitch, dnHighPitch, dnStartRamp, dnEndRamp;
1159
1238
                dnStartRamp = dnHighPitch;
1160
1239
                dnEndRamp = dnLowPitch;
1161
1240
            }
1162
 
            else 
 
1241
            else
1163
1242
            {
1164
1243
                dnHighPitch = dnMaxRoot;
1165
1244
                nAmplitude = dnHighPitch - dnMinPitch;
1191
1270
                dnStartRamp = dnLowPitch;
1192
1271
                dnEndRamp = dnMaxRoot;
1193
1272
            }
1194
 
            else 
 
1273
            else
1195
1274
            {
1196
1275
                dnHighPitch = dnMaxRoot;
1197
1276
                nAmplitude = dnHighPitch - dnMinPitch;
1224
1303
                dnStartRamp = dnLowPitch;
1225
1304
                dnEndRamp = dnMaxRoot;
1226
1305
            }
1227
 
            else 
 
1306
            else
1228
1307
            {
1229
1308
                dnHighPitch = dnMaxRoot;
1230
1309
                nAmplitude = dnHighPitch - dnMinPitch;
1241
1320
        }
1242
1321
    }
1243
1322
 
1244
 
    ////TODO 5.0
1245
 
    //for (int i=0; i < nNumPoints; i++)
1246
 
    //    g_pLogger->LogTrace(_T("Composer::GenerateContour"), _T("point[%d] = %d"), i, aContour[i]);
 
1323
//    #if (TRACE_COMPOSER == 1)
 
1324
//    for (int i=0; i < nNumPoints; i++)
 
1325
//        wxLogMessage(_T("[Composer::GenerateContour] point[%d] = %d"), i, aContour[i]);
 
1326
//    #endif
1247
1327
}
1248
1328
 
1249
1329
//---------------------------------------------------------------------------------------
1258
1338
    float rStep = (float)(dnHighPitch - dnLowPitch) / rNumPoints;
1259
1339
    if (!fUp) rStep = -rStep;
1260
1340
    float yValue = (float)(fUp ? dnLowPitch : dnHighPitch);
1261
 
    ////TODO 5.0
1262
 
    //g_pLogger->LogTrace(_T("Composer"), _T("[ComputeTriangle] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d, rStep=%.5f"),
1263
 
    //    (fUp ? _T("Yes") : _T("No")), iStart, nPoints, dnLowPitch, dnHighPitch, rStep);
 
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);
 
1344
//    #endif
1264
1345
    int i = iStart;
1265
1346
    int nCenter = (nPoints+iStart)/2;
1266
1347
    for (; i < nCenter; i++)
1272
1353
 
1273
1354
    // second ramp
1274
1355
    rStep = (float)(dnHighPitch - dnLowPitch) / ((float)(nPoints-iStart) - rNumPoints);
1275
 
    if (fUp) 
 
1356
    if (fUp)
1276
1357
        rStep = -rStep;
1277
 
    ////TODO 5.0
1278
 
    //g_pLogger->LogTrace(_T("Composer"), _T("[ComputeTriangle] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d, rStep=%.5f"),
1279
 
    //    (fUp ? _T("Yes") : _T("No")), i, nPoints, dnLowPitch, dnHighPitch, rStep);
 
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);
 
1361
//    #endif
1280
1362
    for (; i < nPoints; i++)
1281
1363
    {
1282
1364
        aPoints[i] = (int)floor(yValue+0.5);
1296
1378
    float rNumPoints = (float)(nPoints-iStart);
1297
1379
    float rStep = (float)(dnEndPitch - dnStartPitch) / rNumPoints;
1298
1380
    float yValue = (float)dnStartPitch;
1299
 
    ////TODO 5.0
1300
 
    //g_pLogger->LogTrace(_T("Composer"), _T("[ComputeRamp] iStart=%d, nPoints=%d, dnStartPitch=%d, dnEndPitch=%d, rStep=%.5f"),
1301
 
    //    iStart, nPoints, dnStartPitch, dnEndPitch, rStep);
 
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);
 
1384
//    #endif
1302
1385
    for (int i=iStart; i < nPoints; i++)
1303
1386
    {
1304
1387
        aPoints[i] = (int)floor(yValue+0.5);
1324
1407
    //      a3 = RootPitch
1325
1408
    //      a4 = numPoints
1326
1409
 
1327
 
    ////TODO 5.0
1328
 
    //g_pLogger->LogTrace(_T("Composer"), _T("[ComputeArch] fUp=%s, iStart=%d, nPoints=%d, dnLowPitch=%d, dnHighPitch=%d"),
1329
 
    //    (fUp ? _T("Yes") : _T("No")), iStart, nPoints, dnLowPitch, dnHighPitch);
 
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);
 
1413
//    #endif
1330
1414
    float a1 = 4.0 * (float)(dnHighPitch-dnLowPitch);
1331
1415
    float a2 = (float)(nPoints * nPoints);
1332
1416
    float a3 = (float)dnLowPitch;
1333
1417
    float a4 = (float)nPoints;
1334
1418
    float x = 0.0;
1335
 
    for (int i=iStart; i < iStart+nPoints; i++, x+=1.0) 
 
1419
    for (int i=iStart; i < iStart+nPoints; i++, x+=1.0)
1336
1420
    {
1337
1421
        float y = a3 + ((a1 * x * (a4 - x)) / a2);
1338
1422
        aPoints[i] = (int)floor(y + 0.5);
1347
1431
                                    ImoNote* pNoteCur,
1348
1432
                                    std::vector<FPitch>& aOnChordPitch)
1349
1433
{
1350
 
    ////TODO 5.0
1351
 
    //g_pLogger->LogTrace(_T("Composer::NearestNoteOnChord"), _T("nPoint=%d"), nPoint );
1352
 
 
 
1434
//    #if (TRACE_COMPOSER == 1)
 
1435
//    wxLogMessage(_T("[Composer::NearestNoteOnChord] nPoint=%d"), nPoint );
 
1436
//    #endif
 
1437
//
1353
1438
    // if note is tied to previous one, return previous note pitch
1354
1439
    if (pNotePrev && pNotePrev->is_tied_next() && pNotePrev->is_pitch_defined())
1355
1440
    {
1356
 
        ////TODO 5.0
1357
 
        //g_pLogger->LogTrace(_T("Composer::NearestNoteOnChord"), _T("Previous note = %s"), (pNotePrev->get_fpitch()).LDPName().c_str());
 
1441
//    #if (TRACE_COMPOSER == 1)
 
1442
//        wxLogMessage(_T("[Composer::NearestNoteOnChord] Previous note = %s"), (pNotePrev->get_fpitch()).to_abs_ldp_name().c_str());
 
1443
//    #endif
1358
1444
        return pNotePrev->get_fpitch();
1359
1445
    }
1360
1446
 
1402
1488
        {
1403
1489
            // It is a note. Instantiate it
1404
1490
            ImoNote* pNote = static_cast<ImoNote*>(pImo);
1405
 
            //TODO 5.0 propagate pitch change to tied notes
1406
1491
            set_pitch(pNote, fp);
1407
 
            //pNote->ChangePitch(fp, lmCHANGE_TIED);
1408
1492
        }
1409
1493
        ++it;
1410
1494
    }
1421
1505
 
1422
1506
 
1423
1507
    //case: no non-chord notes. Nothing to do
1424
 
    if (nNumNotes == 0) 
 
1508
    if (nNumNotes == 0)
1425
1509
    {
1426
 
        ////TODO 5.0
1427
 
        //g_pLogger->LogTrace(_T("Composer::AssignNonChordNotes"), _T("[AssignNonChordNotes] No non-chord notes. Nothing to do."));
 
1510
//    #if (TRACE_PITCH == 1)
 
1511
//        wxLogMessage(_T("[Composer::AssignNonChordNotes] No non-chord notes. Nothing to do."));
 
1512
//    #endif
1428
1513
        return;
1429
1514
    }
1430
1515
 
1431
1516
    //case: anacruxis measure
1432
1517
    if (!pOnChord1)
1433
1518
    {
1434
 
        ////TODO 5.0
1435
 
        //g_pLogger->LogTrace(_T("Composer::AssignNonChordNotes"), _T("[AssignNonChordNotes] Anacruxis measure"));
1436
 
        
 
1519
//    #if (TRACE_PITCH == 1)
 
1520
//        wxLogMessage(_T("[Composer::AssignNonChordNotes] Anacruxis measure"));
 
1521
//    #endif
 
1522
 
1437
1523
        //we are going to assing an ascending sequence, by step, to finish in the root
1438
1524
        //note (the first on chord note)
1439
1525
        if (nNumNotes == 1)
1440
1526
        {
1441
1527
            //assign root pitch
1442
 
            //TODO 5.0 propagate to tied notes
1443
1528
            set_pitch(pNonChord[0], pOnChord2->get_fpitch());
1444
 
            //pNonChord[0]->ChangePitch(pOnChord2->get_fpitch(), lmCHANGE_TIED);
1445
1529
        }
1446
1530
        else
1447
1531
        {
1452
1536
                if (!pNonChord[i]->is_pitch_defined())
1453
1537
                {
1454
1538
                    nPitch = MoveByStep(k_down, nPitch, scale);
1455
 
                    //TODO 5.0 propagate to tied notes
1456
1539
                    set_pitch(pNonChord[i], nPitch);
1457
 
                    //pNonChord[i]->ChangePitch(nPitch, lmCHANGE_TIED);
1458
1540
                }
1459
1541
            }
1460
1542
        }
1576
1658
    FPitch ap = pOnChord1->get_fpitch();
1577
1659
    //wxASSERT(ap.to_diatonic_pitch() != lmNO_NOTE);
1578
1660
    FPitch nFirstPitch = MoveByStep(fUpStep, ap, scale);
1579
 
    //TODO 5.0 propagate to tied notes
1580
1661
    set_pitch(pNonChord[0], nFirstPitch);
1581
 
    //pNonChord[0]->ChangePitch(nFirstPitch, lmCHANGE_TIED);
1582
1662
    if (nNumNotes == 1) return;
1583
 
    //TODO 5.0 propagate to tied notes
1584
1663
    set_pitch(pNonChord[1], MoveByStep(!fUpStep, ap, scale));
1585
 
    //pNonChord[1]->ChangePitch(MoveByStep(!fUpStep, ap, scale), lmCHANGE_TIED);
1586
1664
    if (nNumNotes == 2) return;
1587
 
    //TODO 5.0 propagate to tied notes
1588
1665
    set_pitch(pNonChord[2], nFirstPitch);
1589
 
    //pNonChord[2]->ChangePitch(nFirstPitch, lmCHANGE_TIED);
1590
1666
}
1591
1667
 
1592
1668
//---------------------------------------------------------------------------------------
1600
1676
 
1601
1677
    // passing note
1602
1678
    FPitch apNewPitch = pOnChord1->get_fpitch();
1603
 
    //TODO 5.0 propagate to tied notes
1604
1679
    set_pitch(pNonChord[0], MoveByStep(fUp, apNewPitch, scale));
1605
 
    //pNonChord[0]->ChangePitch(MoveByStep(fUp, apNewPitch, scale), lmCHANGE_TIED);
1606
1680
 
1607
1681
    // two passing notes
1608
1682
    for (int i=1; i < nNumNotes; i++)
1609
1683
    {
1610
1684
        apNewPitch = MoveByStep(fUp, apNewPitch, scale);
1611
 
        //TODO 5.0 propagate to tied notes
1612
1685
        set_pitch(pNonChord[i], apNewPitch);
1613
 
    //    pNonChord[1]->ChangePitch(apNewPitch, lmCHANGE_TIED);
1614
1686
    }
1615
1687
}
1616
1688
 
1627
1699
    // third
1628
1700
    FPitch pitch = MoveByStep(fUp, pOnChord1->get_fpitch(), scale);  //second
1629
1701
    pitch = MoveByStep(fUp, pitch, scale);     //third
1630
 
    //TODO 5.0 propagate to tied notes
1631
1702
    set_pitch(pNonChord[0], pitch);
1632
 
    //pNonChord[0]->ChangePitch(pitch, lmCHANGE_TIED);
1633
1703
    if (nNumNotes == 1) return;
1634
1704
    // fifth
1635
1705
    pitch = MoveByStep(fUp, pitch, scale);     //fourth
1636
1706
    pitch = MoveByStep(fUp, pitch, scale);     //fifth
1637
 
    //TODO 5.0 propagate to tied notes
1638
1707
    set_pitch(pNonChord[1], pitch);
1639
 
    //pNonChord[1]->ChangePitch(pitch, lmCHANGE_TIED);
1640
1708
}
1641
1709
 
1642
1710
//---------------------------------------------------------------------------------------
1673
1741
}
1674
1742
 
1675
1743
//---------------------------------------------------------------------------------------
1676
 
int Composer::get_beats_for(ETimeSignature nTimeSign)
 
1744
int Composer::get_top_number_for(ETimeSignature nTimeSign)
1677
1745
{
1678
1746
    //returns the numerator of time signature fraction
1679
1747
 
1705
1773
}
1706
1774
 
1707
1775
//---------------------------------------------------------------------------------------
1708
 
int Composer::get_beat_type_for(ETimeSignature nTimeSign)
 
1776
int Composer::get_bottom_number_for(ETimeSignature nTimeSign)
1709
1777
{
1710
1778
    switch (nTimeSign) {
1711
1779
        case k_time_2_4:
1731
1799
}
1732
1800
 
1733
1801
//---------------------------------------------------------------------------------------
1734
 
float Composer::get_beat_duration_for(ETimeSignature nTimeSign)
 
1802
int Composer::get_num_ref_notes_per_pulse_for(ETimeSignature nTimeSign)
 
1803
{
 
1804
    switch (nTimeSign) {
 
1805
        case k_time_2_4:
 
1806
        case k_time_3_4:
 
1807
        case k_time_4_4:
 
1808
            return 1;
 
1809
 
 
1810
        case k_time_2_8:
 
1811
        case k_time_3_8:
 
1812
        case k_time_6_8:
 
1813
        case k_time_9_8:
 
1814
        case k_time_12_8:
 
1815
            return 3;
 
1816
 
 
1817
        case k_time_2_2:
 
1818
        case k_time_3_2:
 
1819
            return 1;
 
1820
 
 
1821
        default:
 
1822
            wxASSERT(false);
 
1823
            return 1;
 
1824
    }
 
1825
}
 
1826
 
 
1827
//---------------------------------------------------------------------------------------
 
1828
float Composer::get_ref_note_duration_for(ETimeSignature nTimeSign)
1735
1829
{
1736
1830
    // returns beat duration (in LDP notes duration units)
1737
1831
 
1738
 
    int nBeatType = get_beat_type_for(nTimeSign);
1739
 
    return lomse::get_beat_duration_for(nBeatType);
 
1832
    int nBeatType = get_bottom_number_for(nTimeSign);
 
1833
    return lomse::get_duration_for_ref_note(nBeatType);
1740
1834
}
1741
1835
 
1742
1836
//---------------------------------------------------------------------------------------
1744
1838
{
1745
1839
    // Returns the required duration for a measure in the received time signature
1746
1840
 
1747
 
    float rNumBeats = (float)get_beats_for(nTimeSign);
1748
 
    return rNumBeats * get_beat_duration_for(nTimeSign);
 
1841
    float rNumBeats = (float)get_top_number_for(nTimeSign);
 
1842
    return rNumBeats * get_ref_note_duration_for(nTimeSign);
1749
1843
}
1750
1844
 
1751
1845
//---------------------------------------------------------------------------------------
1752
1846
void Composer::set_pitch(ImoNote* pNote, FPitch fp)
1753
1847
{
1754
 
    EAccidentals acc = fp.notated_accidentals_for(m_nKey);
1755
 
    pNote->set_notated_pitch(fp.step(), fp.octave(), acc);
1756
 
    pNote->set_actual_accidentals(fp.num_accidentals());
 
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())
 
1852
    {
 
1853
        pNote->set_notated_pitch(fp.step(), fp.octave(), k_no_accidentals);
 
1854
        pNote->set_actual_accidentals(acc);
 
1855
    }
1757
1856
 
1758
1857
    if (pNote->is_tied_next())
1759
1858
    {
1760
1859
        ImoTie* pTie = pNote->get_tie_next();
1761
1860
        pNote = pTie->get_end_note();
1762
 
        pNote->set_notated_pitch(fp.step(), fp.octave(), acc);
1763
 
        pNote->set_actual_accidentals(fp.num_accidentals());
 
1861
        pNote->set_notated_pitch(fp.step(), fp.octave(), k_no_accidentals);
 
1862
        pNote->set_actual_accidentals(acc);
1764
1863
    }
1765
1864
}
1766
1865