Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add grace and arpeggios notes to the timemap #3956

Merged
merged 13 commits into from
Feb 18, 2025
101 changes: 77 additions & 24 deletions include/vrv/midifunctor.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,83 @@ class InitTimemapTiesFunctor : public Functor {
private:
//
};
//----------------------------------------------------------------------------
// InitTimemapAdjustNotesFunctor
//----------------------------------------------------------------------------

/**
* This class adjusts note duration for grace notes and arpeggios.
*/
class InitTimemapAdjustNotesFunctor : public Functor {
public:
/**
* @name Constructors, destructors
*/
///@{
InitTimemapAdjustNotesFunctor();
virtual ~InitTimemapAdjustNotesFunctor() = default;
///@}

/*
* Abstract base implementation
*/
bool ImplementsEndInterface() const override { return true; }

/*
* Setter for various properties
*/
///@{
void SetNoCue(bool noCue) { m_noCue = noCue; }
///@}

/*
* Functor interface
*/
///@{
FunctorCode VisitArpeg(Arpeg *arpeg) override;
FunctorCode VisitChord(Chord *chord) override;
FunctorCode VisitGraceGrpEnd(GraceGrp *graceGrp) override;
FunctorCode VisitMeasure(Measure *measure) override;
FunctorCode VisitNote(Note *note) override;
///@}

protected:
//
private:
/**
* Helper struct to store grace note/chord sequences
*/
struct Grace {
std::list<Note *> notes;
data_DURATION duration;
data_PERCENT time;
};

/**
* Set the grace note onset and offset times for the reference note
*/
void SetGraceNotesFor(Note *refNote);

/**
* Set the start (and stop) time for a note (score and real times)
*/
void SetNoteStartStop(Note *note, const Fraction &startTime, const Fraction &stopTime);
void SetNoteStart(Note *note, const Fraction &startTime);

public:
//
private:
// Indicates whether cue notes should be included
bool m_noCue;
// Grace note/chord sequence
std::list<Grace> m_graces;
// Indicates whether the last grace note/chord was accented
bool m_accentedGraceNote;
// The current tempo
double m_currentTempo;
// The last (non grace) note
Note *m_lastNote;
};

//----------------------------------------------------------------------------
// InitMIDIFunctor
Expand Down Expand Up @@ -217,15 +294,13 @@ class InitMIDIFunctor : public ConstFunctor {
*/
///@{
void SetCurrentTempo(double tempo) { m_currentTempo = tempo; }
const std::map<const Note *, double> &GetDeferredNotes() const { return m_deferredNotes; }
const std::list<OctaveInfo> &GetOctaves() const { return m_octaves; }
///@}

/*
* Functor interface
*/
///@{
FunctorCode VisitArpeg(const Arpeg *arpeg) override;
FunctorCode VisitMeasure(const Measure *measure) override;
FunctorCode VisitOctave(const Octave *octave) override;
///@}
Expand All @@ -239,8 +314,6 @@ class InitMIDIFunctor : public ConstFunctor {
private:
// The current tempo
double m_currentTempo;
// Deferred notes which start slightly later
std::map<const Note *, double> m_deferredNotes;
// Octave info which is collected
std::list<OctaveInfo> m_octaves;
};
Expand All @@ -267,16 +340,6 @@ struct MIDIHeldNote {
double m_stopTime = 0;
};

/**
* Helper struct to store chord sequences in MIDI output due to grace notes
*/
struct MIDIChord {
std::set<int> pitches;
double duration;
};

using MIDIChordSequence = std::list<MIDIChord>;

/**
* This class performs the export to a MidiFile.
*/
Expand Down Expand Up @@ -327,7 +390,6 @@ class GenerateMIDIFunctor : public ConstFunctor {
FunctorCode VisitBTrem(const BTrem *bTrem) override;
FunctorCode VisitChord(const Chord *chord) override;
FunctorCode VisitFTrem(const FTrem *fTrem) override;
FunctorCode VisitGraceGrpEnd(const GraceGrp *graceGrp) override;
FunctorCode VisitHalfmRpt(const HalfmRpt *halfmRpt) override;
FunctorCode VisitLayer(const Layer *layer) override;
FunctorCode VisitLayerEnd(const Layer *layer) override;
Expand All @@ -351,11 +413,6 @@ class GenerateMIDIFunctor : public ConstFunctor {
*/
void DeferMIDINote(const Note *refNote, double shift, bool includeChordSiblings);

/**
* Creates the MIDI output of the grace note sequence
*/
void GenerateGraceNoteMIDI(const Note *refNote, double startTime, int tpq, int channel, int velocity);

/**
* Change the octave shift at the begin/end of octaves
*/
Expand Down Expand Up @@ -398,10 +455,6 @@ class GenerateMIDIFunctor : public ConstFunctor {
std::map<const Note *, double> m_deferredNotes;
// Octave info which is used to determine the octave shift
std::list<OctaveInfo> m_octaves;
// Grace note sequence
MIDIChordSequence m_graceNotes;
// Indicates whether the last grace note/chord was accented
bool m_accentedGraceNote;
// Indicates whether cue notes should be included
bool m_noCue;
// Tablature held notes indexed by (course - 1)
Expand Down
1 change: 1 addition & 0 deletions include/vrv/vrvdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace vrv {
#define MIDI_TEMPO 120

#define UNACC_GRACENOTE_DUR 27 // in milliseconds
#define UNACC_GRACENOTE_FRACTION Fraction(1, 2048)

//----------------------------------------------------------------------------
// Object defines
Expand Down
6 changes: 5 additions & 1 deletion src/doc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ void Doc::CalculateTimemap()
initTimemapTies.SetDirection(BACKWARD);
this->Process(initTimemapTies);

// Adjust the duration of notes (grace notes and arpeggios)
InitTimemapAdjustNotesFunctor initTimemapAdjustNotes;
initTimemapAdjustNotes.SetNoCue(this->GetOptions()->m_midiNoCue.GetValue());
this->Process(initTimemapAdjustNotes);

m_timemapTempo = m_options->m_midiTempoAdjustment.GetValue();
}

Expand Down Expand Up @@ -546,7 +551,6 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile)
generateMIDI.SetTempoEventTicks(tempoEventTicks);
generateMIDI.SetTransSemi(transSemi);
generateMIDI.SetCurrentTempo(tempo);
generateMIDI.SetDeferredNotes(initMIDI.GetDeferredNotes());
generateMIDI.SetOctaves(initMIDI.GetOctaves());
generateMIDI.SetNoCue(this->GetOptions()->m_midiNoCue.GetValue());
generateMIDI.SetControlEvents(controlEvents);
Expand Down
Loading
Loading