@@ -344,12 +344,12 @@ static bool shouldProceedBend(const Note* note)
344
344
return baseNote->lastTiedNote (false ) == note;
345
345
}
346
346
347
- static BendPlaybackInfo getBendPlaybackInfo (const GuitarBend* bend, int bendStart, int bendDuration)
347
+ static BendPlaybackInfo getBendPlaybackInfo (const GuitarBend* bend, int bendStart, int bendDuration, bool graceBeforeBend )
348
348
{
349
349
BendPlaybackInfo bendInfo;
350
350
351
- // currently ignoring diagram for grace bends
352
- if (bend-> type () != GuitarBendType::GRACE_NOTE_BEND ) {
351
+ // currently ignoring diagram for " grace before" bends
352
+ if (!graceBeforeBend ) {
353
353
bendInfo.startTimeFactor = bend->startTimeFactor ();
354
354
bendInfo.endTimeFactor = bend->endTimeFactor ();
355
355
}
@@ -360,6 +360,71 @@ static BendPlaybackInfo getBendPlaybackInfo(const GuitarBend* bend, int bendStar
360
360
return bendInfo;
361
361
}
362
362
363
+ static void fillBendDurations (const Note* bendStartNote, const std::unordered_set<const Note*>& currentNotes,
364
+ std::unordered_map<const Note*, size_t >& durations, bool tiedToNext)
365
+ {
366
+ if (!bendStartNote || currentNotes.empty ()) {
367
+ return ;
368
+ }
369
+
370
+ size_t bendsAmount = tiedToNext ? currentNotes.size () + 1 : currentNotes.size ();
371
+ size_t eachBendDuration = bendStartNote->chord ()->actualTicks ().ticks () / bendsAmount;
372
+
373
+ for (const Note* note : currentNotes) {
374
+ durations.insert ({ note, eachBendDuration });
375
+ }
376
+ }
377
+
378
+ static std::unordered_map<const Note*, size_t > getGraceNoteBendDurations (const Note* note)
379
+ {
380
+ std::unordered_map<const Note*, size_t > durations;
381
+ const Note* bendStartNote = nullptr ;
382
+ std::unordered_set<const Note*> currentNotes;
383
+
384
+ while (note->tieFor ()) {
385
+ const Tie* tieFor = note->tieFor ();
386
+ IF_ASSERT_FAILED (tieFor->endNote ()) {
387
+ LOGE () << " cannot find tied note for note on track " << note->track () << " , tick " << note->tick ().ticks ();
388
+ return {};
389
+ }
390
+ note = tieFor->endNote ();
391
+ }
392
+
393
+ while (note->bendFor ()) {
394
+ const GuitarBend* bendFor = note->bendFor ();
395
+ const Note* endNote = bendFor->endNote ();
396
+ if (!endNote || note == endNote) {
397
+ LOGE () << " cannot find end bend note for note on track " << note->track () << " , tick " << note->tick ().ticks ();
398
+ return {};
399
+ }
400
+
401
+ if (endNote->chord ()->isGraceAfter ()) {
402
+ if (currentNotes.empty ()) {
403
+ IF_ASSERT_FAILED (note->chord () == endNote->chord ()->explicitParent ()) {
404
+ LOGE () << " error in filling bends midi data for note on track " << note->track () << " , tick " << note->tick ().ticks ();
405
+ return {};
406
+ }
407
+ bendStartNote = note;
408
+ currentNotes.insert (bendStartNote);
409
+ }
410
+
411
+ if (endNote->bendFor ()) {
412
+ currentNotes.insert (endNote);
413
+ }
414
+ } else {
415
+ fillBendDurations (bendStartNote, currentNotes, durations, true );
416
+ bendStartNote = nullptr ;
417
+ currentNotes.clear ();
418
+ }
419
+
420
+ note = bendFor->endNote ();
421
+ }
422
+
423
+ fillBendDurations (bendStartNote, currentNotes, durations, false );
424
+
425
+ return durations;
426
+ }
427
+
363
428
/*
364
429
* All consecutive tie and bend combinations are processed in a single pass, adding pitch bends where needed to ensure continuity between notes.
365
430
*
@@ -378,8 +443,9 @@ static void collectGuitarBend(const Note* note,
378
443
return ;
379
444
}
380
445
446
+ const auto & graceNoteBendDurations = getGraceNoteBendDurations (note);
447
+
381
448
int curPitchBendSegmentStart = onTime;
382
- int curPitchBendSegmentEnd = 0 ;
383
449
384
450
int quarterOffsetFromStartNote = 0 ;
385
451
int currentQuarterTones = 0 ;
@@ -392,22 +458,26 @@ static void collectGuitarBend(const Note* note,
392
458
393
459
while (note->bendFor () || note->tieFor ()) {
394
460
const GuitarBend* bendFor = note->bendFor ();
395
- int duration = 0 ;
396
- if (bendFor && bendFor->type () == GuitarBendType::GRACE_NOTE_BEND) {
397
- duration = (previousChordTicks == -1 ) ? GRACE_BEND_DURATION : std::min (previousChordTicks / 2 , GRACE_BEND_DURATION);
398
- } else {
399
- duration = note->chord ()->actualTicks ().ticks ();
400
- }
401
- curPitchBendSegmentEnd = curPitchBendSegmentStart + duration;
402
-
461
+ int duration = note->chord ()->actualTicks ().ticks ();
403
462
if (bendFor) {
404
463
const Note* endNote = bendFor->endNote ();
405
464
406
465
if (!endNote) {
407
466
return ;
408
467
}
409
468
410
- BendPlaybackInfo bendPlaybackInfo = getBendPlaybackInfo (bendFor, curPitchBendSegmentStart, duration);
469
+ bool graceBeforeBend = false ;
470
+ if (note->chord ()->isGraceBefore () && bendFor) {
471
+ Note* endNote = bendFor->endNote ();
472
+ if (endNote && endNote->noteType () == NoteType::NORMAL) {
473
+ duration = (previousChordTicks == -1 ) ? GRACE_BEND_DURATION : std::min (previousChordTicks / 2 , GRACE_BEND_DURATION);
474
+ graceBeforeBend = true ;
475
+ }
476
+ } else if (muse::contains (graceNoteBendDurations, note)) {
477
+ duration = graceNoteBendDurations.at (note);
478
+ }
479
+
480
+ BendPlaybackInfo bendPlaybackInfo = getBendPlaybackInfo (bendFor, curPitchBendSegmentStart, duration, graceBeforeBend);
411
481
double initialPitchBendValue = quarterOffsetFromStartNote / 2.0 ;
412
482
413
483
if (bendPlaybackInfo.startTick > curPitchBendSegmentStart) {
@@ -435,7 +505,7 @@ static void collectGuitarBend(const Note* note,
435
505
pitchWheelRenderer.addPitchWheelFunction (pitchWheelSquareFunc, channel, note->staffIdx (), effect);
436
506
quarterOffsetFromStartNote += currentQuarterTones;
437
507
438
- if (bendPlaybackInfo.endTick < curPitchBendSegmentEnd ) {
508
+ if (bendPlaybackInfo.endTick < curPitchBendSegmentStart + duration ) {
439
509
addConstPitchWheel (bendPlaybackInfo.endTick , quarterOffsetFromStartNote / 2.0 , pitchWheelRenderer, channel,
440
510
note->staffIdx (),
441
511
effect);
@@ -447,7 +517,7 @@ static void collectGuitarBend(const Note* note,
447
517
448
518
note = endNote;
449
519
} else {
450
- if (note->bendBack ()) {
520
+ if (!note-> isGrace () && note->bendBack ()) {
451
521
addConstPitchWheel (note->tick ().ticks (), quarterOffsetFromStartNote / 2.0 , pitchWheelRenderer, channel,
452
522
note->staffIdx (), effect);
453
523
}
@@ -459,10 +529,10 @@ static void collectGuitarBend(const Note* note,
459
529
}
460
530
}
461
531
462
- curPitchBendSegmentStart = curPitchBendSegmentEnd ;
532
+ curPitchBendSegmentStart += duration ;
463
533
}
464
534
465
- if (note->bendBack ()) {
535
+ if (!note-> isGrace () && note->bendBack ()) {
466
536
addConstPitchWheel (note->tick ().ticks (), quarterOffsetFromStartNote / 2.0 , pitchWheelRenderer, channel, note->staffIdx (), effect);
467
537
}
468
538
}
0 commit comments