midi-renderer: fix glissando+tremolo rendering
This commit is contained in:
parent
796dc69830
commit
a6ae0ef9f3
2 changed files with 34 additions and 23 deletions
|
@ -432,7 +432,7 @@ const Drumset* getDrumset(const Chord* chord)
|
|||
// renderTremolo
|
||||
//---------------------------------------------------------
|
||||
|
||||
static void renderTremolo(Chord* chord, std::vector<NoteEventList>& ell, double tremoloPartOfChord = 1.0)
|
||||
static void renderTremolo(Chord* chord, std::vector<NoteEventList>& ell, int& ontime, double tremoloPartOfChord = 1.0)
|
||||
{
|
||||
Segment* seg = chord->segment();
|
||||
Tremolo* tremolo = chord->tremolo();
|
||||
|
@ -536,13 +536,19 @@ static void renderTremolo(Chord* chord, std::vector<NoteEventList>& ell, double
|
|||
if (t == 0) { // avoid crash on very short tremolo
|
||||
t = 1;
|
||||
}
|
||||
int n = chord->ticks().ticks() / t * tremoloPartOfChord;
|
||||
int l = 1000 / n * tremoloPartOfChord;
|
||||
|
||||
int tremoloEventsSize = chord->ticks().ticks() / t * tremoloPartOfChord;
|
||||
|
||||
constexpr int fullEventTime = 1000;
|
||||
int tremoloTime = fullEventTime * tremoloPartOfChord;
|
||||
int tremoloEventStep = tremoloTime / tremoloEventsSize;
|
||||
ontime += tremoloTime;
|
||||
|
||||
for (int k = 0; k < notes; ++k) {
|
||||
NoteEventList* events = &(ell)[k];
|
||||
events->clear();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
events->push_back(NoteEvent(0, l * i, l));
|
||||
for (int i = 0; i < tremoloEventsSize; i++) {
|
||||
events->push_back(NoteEvent(0, tremoloEventStep * i, tremoloEventStep));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -630,9 +636,9 @@ static bool renderNoteArticulation(NoteEventList* events, Note* note, bool chrom
|
|||
const std::vector<int>& prefix, const std::vector<int>& body,
|
||||
bool repeatp, bool sustainp, const std::vector<int>& suffix,
|
||||
int fastestFreq = 64, int slowestFreq = 8, // 64 Hz and 8 Hz
|
||||
double graceOnBeatProportion = 0, bool clearPrevEvents = true)
|
||||
double graceOnBeatProportion = 0, bool tremoloBefore = false)
|
||||
{
|
||||
if (clearPrevEvents) {
|
||||
if (!tremoloBefore) {
|
||||
events->clear();
|
||||
}
|
||||
|
||||
|
@ -792,8 +798,10 @@ static bool renderNoteArticulation(NoteEventList* events, Note* note, bool chrom
|
|||
|
||||
// shifting glissando sounds to the second half of glissando duration
|
||||
int totalDuration = millespernote * b;
|
||||
int glissandoDuration = totalDuration * (1 - graceOnBeatProportion) / 2;
|
||||
|
||||
int glissandoDuration = tremoloBefore ? totalDuration / 2 : totalDuration * (1 - graceOnBeatProportion) / 2;
|
||||
easeInOut.timeList(b, glissandoDuration, &onTimes);
|
||||
|
||||
if (!onTimes.empty()) {
|
||||
onTimes[0] += graceOnBeatProportion * totalDuration;
|
||||
}
|
||||
|
@ -974,7 +982,7 @@ static bool renderNoteArticulation(NoteEventList* events, Note* note, bool chrom
|
|||
// renderGlissando
|
||||
//---------------------------------------------------------
|
||||
|
||||
static void renderGlissando(NoteEventList* events, Note* notestart, double graceOnBeatProportion)
|
||||
static void renderGlissando(NoteEventList* events, Note* notestart, double graceOnBeatProportion, bool tremoloBefore = false)
|
||||
{
|
||||
std::vector<int> empty = {};
|
||||
std::vector<int> body;
|
||||
|
@ -983,7 +991,7 @@ static void renderGlissando(NoteEventList* events, Note* notestart, double grace
|
|||
&& toGlissando(spanner)->playGlissando()
|
||||
&& Glissando::pitchSteps(spanner, body)) {
|
||||
renderNoteArticulation(events, notestart, true, Constants::division, empty, body, false, true, empty, 16, 0,
|
||||
graceOnBeatProportion, false);
|
||||
graceOnBeatProportion, tremoloBefore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1039,7 +1047,8 @@ static bool graceNotesMerged(Chord* chord)
|
|||
// renderChordArticulation
|
||||
//---------------------------------------------------------
|
||||
|
||||
static void renderChordArticulation(Chord* chord, std::vector<NoteEventList>& ell, int& gateTime, double graceOnBeatProportion)
|
||||
static void renderChordArticulation(Chord* chord, std::vector<NoteEventList>& ell, int& gateTime, double graceOnBeatProportion,
|
||||
bool tremoloBefore = false)
|
||||
{
|
||||
Segment* seg = chord->segment();
|
||||
Instrument* instr = chord->part()->instrument(seg->tick());
|
||||
|
@ -1051,7 +1060,7 @@ static void renderChordArticulation(Chord* chord, std::vector<NoteEventList>& el
|
|||
Trill* trill;
|
||||
|
||||
if (noteHasGlissando(note)) {
|
||||
renderGlissando(events, note, graceOnBeatProportion);
|
||||
renderGlissando(events, note, graceOnBeatProportion, tremoloBefore);
|
||||
} else if (chord->staff()->isPitchedStaff(chord->tick()) && (trill = findFirstTrill(chord)) != nullptr) {
|
||||
renderNoteArticulation(events, note, false, trill->trillType(), trill->ornamentStyle());
|
||||
} else {
|
||||
|
@ -1180,16 +1189,19 @@ static std::vector<NoteEventList> renderChord(Chord* chord, Chord* prevChord, in
|
|||
return noteHasGlissando(note) || note->slide().is(Note::SlideType::Doit) || note->slide().is(Note::SlideType::Fall);
|
||||
});
|
||||
|
||||
bool tremolo = false;
|
||||
|
||||
if (chord->arpeggio() && chord->arpeggio()->playArpeggio()) {
|
||||
renderArpeggio(chord, ell);
|
||||
arpeggio = true;
|
||||
} else {
|
||||
if (chord->tremolo()) {
|
||||
/// when note has glissando, half of chord is played tremolo, second half - glissando
|
||||
renderTremolo(chord, ell, glissandoExists ? 0.5 : 1);
|
||||
renderTremolo(chord, ell, ontime, glissandoExists ? 0.5 : 1);
|
||||
tremolo = true;
|
||||
}
|
||||
|
||||
renderChordArticulation(chord, ell, gateTime, (double)ontime / 1000);
|
||||
renderChordArticulation(chord, ell, gateTime, (double)ontime / 1000, tremolo);
|
||||
}
|
||||
|
||||
// Check each note and apply gateTime
|
||||
|
|
|
@ -227,21 +227,14 @@ TEST_F(MidiRenderer_Tests, diffStringWithEffects)
|
|||
checkEventInterval(events, 960, 1919, 60, defVol, DEFAULT_CHANNEL + 2);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
DISABLED TESTS BELOW
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/// TODO: enable after fix of rendering tremolo and glissando simultaniously
|
||||
TEST_F(MidiRenderer_Tests, DISABLED_tremoloAndGlissando)
|
||||
TEST_F(MidiRenderer_Tests, tremoloAndGlissando)
|
||||
{
|
||||
constexpr int defVol = 96; // f
|
||||
constexpr int glissVol = defVol * NoteEvent::GLISSANDO_VELOCITY_MULTIPLIER;
|
||||
|
||||
EventMap events = renderMidiEvents(u"tremolo_and_glissando.mscx");
|
||||
|
||||
EXPECT_EQ(events.size(), 8);
|
||||
EXPECT_EQ(events.size(), 14);
|
||||
|
||||
checkEventInterval(events, 0, 239, 59, defVol);
|
||||
checkEventInterval(events, 240, 479, 59, defVol);
|
||||
|
@ -252,6 +245,12 @@ TEST_F(MidiRenderer_Tests, DISABLED_tremoloAndGlissando)
|
|||
checkEventInterval(events, 960, 1439, 55, defVol);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
DISABLED TESTS BELOW
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/// TODO: enable after fixing slides midi rendering
|
||||
TEST_F(MidiRenderer_Tests, DISABLED_slideInFromBelow)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue