Merge pull request #20015 from alexpavlov96/XTC-289_hairpins_midi_fix

upgraded midi rendering of hairpins and dynamics
This commit is contained in:
Alexander Pavlov 2023-11-22 21:31:41 +09:00 committed by GitHub
commit ff97e3fc69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1229 additions and 43 deletions

View file

@ -197,11 +197,11 @@ void ChangeMap::addRamp(Fraction stick, Fraction etick, int change, ChangeMethod
}
//---------------------------------------------------------
// cleanupStage0
// sortRamps
/// put the ramps in size order if they start at the same point
//---------------------------------------------------------
void ChangeMap::cleanupStage0()
void ChangeMap::sortRamps()
{
for (auto& tick : mu::uniqueKeys(*this)) {
// rampEvents will contain all the ramps at this tick
@ -228,15 +228,13 @@ void ChangeMap::cleanupStage0()
}
//---------------------------------------------------------
// cleanupStage1
/// remove any ramps or fixes that are completely enclosed within other ramps
// resolveRampsCollisions
/// remove any ramps that are completely enclosed within other ramps
//---------------------------------------------------------
void ChangeMap::cleanupStage1()
void ChangeMap::resolveRampsCollisions()
{
Fraction currentRampStart = Fraction(-1, 1); // start point of ramp we're in
Fraction currentRampEnd = Fraction(-1, 1); // end point of ramp we're in
Fraction lastFix = Fraction(-1, 1); // the position of the last fix event
bool inRamp = false; // whether we're in a ramp or not
// Keep a record of the endpoints
@ -262,42 +260,30 @@ void ChangeMap::cleanupStage1()
// don't add to the end points
continue;
} else {
currentRampStart = tick;
currentRampEnd = etick;
startsInRamp.push_back(true);
}
} else {
currentRampStart = tick;
currentRampEnd = etick;
inRamp = true;
startsInRamp.push_back(false);
}
endPoints.push_back(std::make_pair(tick, etick));
} else if (event.m_type == ChangeEventType::FIX) {
if (inRamp) {
if (tick != currentRampStart && tick != currentRampEnd && lastFix != tick) {
// delete, this event is enveloped or at the same point as another fix
i = erase(i);
continue;
}
}
lastFix = tick;
}
i++;
}
cleanupStage2(startsInRamp, endPoints);
adjustCollidingRampsLength(startsInRamp, endPoints);
}
//---------------------------------------------------------
// cleanupStage2
// adjustCollidingRampsLength
/// readjust lengths of any colliding ramps
//---------------------------------------------------------
void ChangeMap::cleanupStage2(std::vector<bool>& startsInRamp, EndPointsVector& endPoints)
void ChangeMap::adjustCollidingRampsLength(std::vector<bool>& startsInRamp, EndPointsVector& endPoints)
{
// moveTo stores the events that need to be moved to a Fraction position
std::map<Fraction, ChangeEvent> moveTo;
@ -331,11 +317,111 @@ void ChangeMap::cleanupStage2(std::vector<bool>& startsInRamp, EndPointsVector&
}
//---------------------------------------------------------
// cleanupStage3
// resolveFixInsideRampCollisions
/// if fix is inside the ramp, shorten ramp length up to this fix
//---------------------------------------------------------
void ChangeMap::resolveFixInsideRampCollisions()
{
auto lastEventIt = end();
auto i = begin();
while (i != end()) {
ChangeEvent& event = i->second;
if (event.m_type == ChangeEventType::FIX && lastEventIt != end() && lastEventIt->second.m_type == ChangeEventType::RAMP) {
Fraction fixTick = i->first;
Fraction lastRampStart = lastEventIt->first;
Fraction lastRampEnd = lastRampStart + lastEventIt->second.m_length;
if (lastRampEnd > fixTick) {
lastEventIt->second.m_length = fixTick - lastRampStart;
}
}
lastEventIt = i;
i++;
}
}
bool ChangeMap::fixExistsOnTick(Fraction tick) const
{
auto values = equal_range(tick);
for (auto it = values.first; it != values.second; ++it) {
auto& event = it->second;
if (event.m_type == ChangeEventType::FIX) {
return true;
}
}
return false;
}
ChangeEvent ChangeMap::fixEventForTick(Fraction tick) const
{
auto equalValues = equal_range(tick);
for (auto it = equalValues.first; it != equalValues.second; ++it) {
auto& event = it->second;
if (event.m_type == ChangeEventType::FIX) {
return event;
}
}
if (equalValues.first == begin()) {
return ChangeEvent();
}
auto previousIt = std::prev(equalValues.first);
auto smallerValues = equal_range(previousIt->first);
for (auto it = smallerValues.first; it != smallerValues.second; ++it) {
auto& event = it->second;
if (event.m_type == ChangeEventType::FIX) {
return event;
}
}
return ChangeEvent();
}
void ChangeMap::addMissingFixesAfterRamps()
{
auto nextDynamicVal = [](int previousFixValue, ChangeDirection rampDirection) {
int newVal
= (rampDirection
== ChangeDirection::INCREASING ? previousFixValue + ChangeMap::STEP : previousFixValue - ChangeMap::STEP);
return std::clamp(newVal, ChangeMap::MIN_VALUE, ChangeMap::MAX_VALUE);
};
for (auto it = begin(); it != end(); it++) {
auto& event = it->second;
if (event.m_type == ChangeEventType::RAMP && event.m_value == 0) {
Fraction startRampTick = it->first;
Fraction endRampTick = it->first + it->second.m_length;
ChangeEvent fixOnCurrentTick = fixEventForTick(startRampTick);
if (!fixExistsOnTick(endRampTick)) {
if (fixOnCurrentTick.m_type != ChangeEventType::INVALID) {
int newVal = nextDynamicVal(fixOnCurrentTick.m_value, event.m_direction);
insert({ endRampTick, ChangeEvent(newVal) });
}
} else {
ChangeEvent fixOnEndTick = fixEventForTick(endRampTick);
int velocityJump = fixOnEndTick.m_value - fixOnCurrentTick.m_value;
if ((event.m_direction
== ChangeDirection::INCREASING && velocityJump < 0)
|| (event.m_direction == ChangeDirection::DECREASING && velocityJump > 0)) {
int newVal = nextDynamicVal(fixOnCurrentTick.m_value, event.m_direction);
event.m_value = newVal - fixOnCurrentTick.m_value;
}
}
}
}
}
//---------------------------------------------------------
// fillRampsCache
/// cache start and end values for each ramp
//---------------------------------------------------------
void ChangeMap::cleanupStage3()
void ChangeMap::fillRampsCache()
{
for (auto i = begin(); i != end(); i++) {
Fraction tick = i->first;
@ -444,16 +530,12 @@ void ChangeMap::cleanup()
return;
}
// LOGD() << "Before cleanup:";
// dump();
cleanupStage0();
cleanupStage1();
cleanupStage3();
sortRamps();
resolveRampsCollisions();
resolveFixInsideRampCollisions();
addMissingFixesAfterRamps();
fillRampsCache();
m_cleanedUp = true;
// LOGD() << "After cleanup:";
// dump();
}
//---------------------------------------------------------

View file

@ -47,8 +47,8 @@ class ChangeEvent
{
public:
ChangeEvent() {}
ChangeEvent(int vel)
: m_value(vel), m_type(ChangeEventType::FIX) {}
ChangeEvent(int val)
: m_value(val), m_type(ChangeEventType::FIX) {}
ChangeEvent(Fraction s, Fraction e, int diff, ChangeMethod m, ChangeDirection d)
: m_value(diff), m_type(ChangeEventType::RAMP), m_length(e - s), m_method(m), m_direction(d) {}
@ -77,7 +77,6 @@ typedef std::vector<std::pair<Fraction, Fraction> > EndPointsVector;
class ChangeMap : public std::multimap<Fraction, ChangeEvent>
{
OBJECT_ALLOCATOR(engraving, ChangeMap)
public:
ChangeMap() {}
int val(Fraction tick);
@ -92,19 +91,26 @@ public:
private:
struct ChangeMethodItem {
ChangeMethod method = ChangeMethod::NORMAL;
const char* name = nullptr;
ChangeMethod method;
const char* name;
};
static bool compareRampEvents(ChangeEvent& a, ChangeEvent& b) { return a.m_length > b.m_length; }
void cleanupStage0();
void cleanupStage1();
void cleanupStage2(std::vector<bool>& startsInRamp, EndPointsVector& endPoints);
void cleanupStage3();
void sortRamps();
void resolveRampsCollisions();
void resolveFixInsideRampCollisions();
void adjustCollidingRampsLength(std::vector<bool>& startsInRamp, EndPointsVector& endPoints);
bool fixExistsOnTick(Fraction tick) const;
ChangeEvent fixEventForTick(Fraction tick) const;
void addMissingFixesAfterRamps();
void fillRampsCache();
bool m_cleanedUp = false;
static const int DEFAULT_VALUE = 80;
static constexpr int DEFAULT_VALUE = 80;
static constexpr int MIN_VALUE = 1;
static constexpr int MAX_VALUE = 127;
static constexpr int STEP = 16;
};
} // namespace mu::engraving
#endif

View file

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.10">
<programVersion>4.1.1</programVersion>
<programRevision>e4d1ddf</programRevision>
<Score>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-11-22</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">gp</metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Steel Guitar</trackName>
<Instrument id="cavaquinho">
<longName>Steel Guitar</longName>
<shortName>s.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="25"/>
<controller ctrl="7" value="101"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>mf</subtype>
<velocity>80</velocity>
</Dynamic>
<Tempo>
<tempo>2</tempo>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Spanner type="HairPin">
<HairPin>
<subtype>0</subtype>
</HairPin>
<next>
<location>
<measures>1</measures>
<fractions>3/4</fractions>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>62</pitch>
<tpc>16</tpc>
<fret>3</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>64</pitch>
<tpc>18</tpc>
<fret>0</fret>
<string>0</string>
</Note>
</Chord>
<Dynamic>
<subtype>p</subtype>
<velocity>49</velocity>
</Dynamic>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>65</pitch>
<tpc>13</tpc>
<fret>1</fret>
<string>0</string>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>67</pitch>
<tpc>15</tpc>
<fret>3</fret>
<string>0</string>
</Note>
</Chord>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>69</pitch>
<tpc>17</tpc>
<fret>5</fret>
<string>0</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>71</pitch>
<tpc>19</tpc>
<fret>7</fret>
<string>0</string>
</Note>
</Chord>
<Spanner type="HairPin">
<prev>
<location>
<measures>-1</measures>
<fractions>-3/4</fractions>
</location>
</prev>
</Spanner>
<Rest>
<durationType>quarter</durationType>
</Rest>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,261 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.10">
<programVersion>4.1.1</programVersion>
<programRevision>e4d1ddf</programRevision>
<Score>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-11-22</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">gp</metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Clean Guitar</trackName>
<Instrument id="electric-guitar">
<longName>Clean Guitar</longName>
<shortName>el.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar.electric</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="27"/>
<controller ctrl="7" value="101"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<Tempo>
<tempo>2</tempo>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Spanner type="HairPin">
<HairPin>
<subtype>0</subtype>
</HairPin>
<next>
<location>
<measures>1</measures>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>55</pitch>
<tpc>15</tpc>
<fret>0</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>57</pitch>
<tpc>17</tpc>
<fret>2</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>62</pitch>
<tpc>16</tpc>
<fret>3</fret>
<string>1</string>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Dynamic>
<subtype>mf</subtype>
<velocity>80</velocity>
</Dynamic>
<Spanner type="HairPin">
<prev>
<location>
<measures>-1</measures>
</location>
</prev>
</Spanner>
<Chord>
<durationType>whole</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<BarLine>
<subtype>double</subtype>
</BarLine>
</voice>
</Measure>
<Measure>
<voice>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<Spanner type="HairPin">
<HairPin>
<subtype>1</subtype>
</HairPin>
<next>
<location>
<measures>1</measures>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>55</pitch>
<tpc>15</tpc>
<fret>0</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>57</pitch>
<tpc>17</tpc>
<fret>2</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>62</pitch>
<tpc>16</tpc>
<fret>3</fret>
<string>1</string>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Dynamic>
<subtype>ff</subtype>
<velocity>112</velocity>
</Dynamic>
<Spanner type="HairPin">
<prev>
<location>
<measures>-1</measures>
</location>
</prev>
</Spanner>
<Chord>
<durationType>whole</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.10">
<programVersion>4.1.1</programVersion>
<programRevision>e4d1ddf</programRevision>
<Score>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-11-21</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">gp</metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Clean Guitar</trackName>
<Instrument id="electric-guitar">
<longName>Clean Guitar</longName>
<shortName>el.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar.electric</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="27"/>
<controller ctrl="7" value="101"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>ff</subtype>
<velocity>112</velocity>
</Dynamic>
<Tempo>
<tempo>2</tempo>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Spanner type="HairPin">
<HairPin>
<subtype>1</subtype>
</HairPin>
<next>
<location>
<fractions>1/2</fractions>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
<fret>0</fret>
<string>1</string>
</Note>
</Chord>
<Spanner type="HairPin">
<prev>
<location>
<fractions>-1/2</fractions>
</location>
</prev>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>55</pitch>
<tpc>15</tpc>
<fret>0</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>52</pitch>
<tpc>18</tpc>
<fret>2</fret>
<string>3</string>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Dynamic>
<subtype>p</subtype>
<velocity>49</velocity>
</Dynamic>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>48</pitch>
<tpc>14</tpc>
<fret>3</fret>
<string>4</string>
</Note>
</Chord>
<Rest>
<durationType>quarter</durationType>
</Rest>
<Rest>
<durationType>half</durationType>
</Rest>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.10">
<programVersion>4.1.1</programVersion>
<programRevision>e4d1ddf</programRevision>
<Score>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-11-21</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">gp</metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Steel Guitar</trackName>
<Instrument id="cavaquinho">
<longName>Steel Guitar</longName>
<shortName>s.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="25"/>
<controller ctrl="7" value="101"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>p</subtype>
<velocity>49</velocity>
</Dynamic>
<Tempo>
<tempo>2</tempo>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Spanner type="HairPin">
<HairPin>
<subtype>0</subtype>
</HairPin>
<next>
<location>
<fractions>3/4</fractions>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
<fret>4</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>5</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>62</pitch>
<tpc>16</tpc>
<fret>7</fret>
<string>2</string>
</Note>
</Chord>
<Dynamic>
<subtype>f</subtype>
<velocity>96</velocity>
</Dynamic>
<Spanner type="HairPin">
<prev>
<location>
<fractions>-3/4</fractions>
</location>
</prev>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>64</pitch>
<tpc>18</tpc>
<fret>9</fret>
<string>2</string>
</Note>
</Chord>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="4.10">
<programVersion>4.1.1</programVersion>
<programRevision>e4d1ddf</programRevision>
<Score>
<Division>480</Division>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<open>1</open>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="creationDate">2023-11-21</metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="originalFormat">gp</metaTag>
<metaTag name="platform">Apple Macintosh</metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle"></metaTag>
<Part id="1">
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
</Staff>
<trackName>Clean Guitar</trackName>
<Instrument id="electric-guitar">
<longName>Clean Guitar</longName>
<shortName>el.guit.</shortName>
<trackName></trackName>
<transposeDiatonic>-7</transposeDiatonic>
<transposeChromatic>-12</transposeChromatic>
<instrumentId>pluck.guitar.electric</instrumentId>
<singleNoteDynamics>0</singleNoteDynamics>
<StringData>
<frets>24</frets>
<string>52</string>
<string>57</string>
<string>62</string>
<string>67</string>
<string>71</string>
<string>76</string>
</StringData>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>30</gateTime>
</Articulation>
<Articulation name="staccato">
<velocity>100</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="portato">
<velocity>100</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="tenuto">
<velocity>100</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="accent">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="marcato">
<velocity>144</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>169</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<program value="27"/>
<controller ctrl="7" value="101"/>
<synti>Fluid</synti>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<KeySig>
<concertKey>0</concertKey>
</KeySig>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Dynamic>
<subtype>ff</subtype>
<velocity>112</velocity>
</Dynamic>
<Tempo>
<tempo>2</tempo>
<text><sym>metNoteQuarterUp</sym> = 120</text>
</Tempo>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>60</pitch>
<tpc>14</tpc>
<fret>1</fret>
<string>1</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>59</pitch>
<tpc>19</tpc>
<fret>0</fret>
<string>1</string>
</Note>
</Chord>
<Spanner type="HairPin">
<HairPin>
<subtype>1</subtype>
</HairPin>
<next>
<location>
<measures>1</measures>
<fractions>-1/4</fractions>
</location>
</next>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>55</pitch>
<tpc>15</tpc>
<fret>0</fret>
<string>2</string>
</Note>
</Chord>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>52</pitch>
<tpc>18</tpc>
<fret>2</fret>
<string>3</string>
</Note>
</Chord>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>50</pitch>
<tpc>16</tpc>
<fret>0</fret>
<string>3</string>
</Note>
</Chord>
<Dynamic>
<subtype>p</subtype>
<velocity>49</velocity>
</Dynamic>
<Spanner type="HairPin">
<prev>
<location>
<measures>-1</measures>
<fractions>1/4</fractions>
</location>
</prev>
</Spanner>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>48</pitch>
<tpc>14</tpc>
<fret>3</fret>
<string>4</string>
</Note>
</Chord>
<Rest>
<durationType>half</durationType>
</Rest>
<BarLine>
<subtype>end</subtype>
</BarLine>
</voice>
</Measure>
</Staff>
</Score>
</museScore>

View file

@ -832,6 +832,89 @@ TEST_F(MidiRenderer_Tests, breathController)
}
}
/*****************************************************************************
Hairpin + dynamic tests
*****************************************************************************/
TEST_F(MidiRenderer_Tests, hairpinSimple)
{
EventsHolder events = getNoteOnEvents(renderMidiEvents(u"hairpin_simple.mscx"));
EXPECT_EQ(events.size(), 1);
EXPECT_EQ(events[DEFAULT_CHANNEL].size(), 8);
checkEventInterval(events, 0, 479, 59, 49);
checkEventInterval(events, 480, 959, 60, 64);
checkEventInterval(events, 960, 1439, 62, 80);
checkEventInterval(events, 1440, 1919, 64, 96);
}
TEST_F(MidiRenderer_Tests, hairpinStartDynamicAway)
{
EventsHolder events = getNoteOnEvents(renderMidiEvents(u"hairpin_start_dynamic_away.mscx"));
EXPECT_EQ(events.size(), 1);
EXPECT_EQ(events[DEFAULT_CHANNEL].size(), 12);
checkEventInterval(events, 0, 479, 60, 112);
checkEventInterval(events, 480, 959, 59, 112);
checkEventInterval(events, 960, 1439, 55, 112);
checkEventInterval(events, 1440, 1919, 52, 91);
checkEventInterval(events, 1920, 2399, 50, 70);
checkEventInterval(events, 2400, 2879, 48, 49);
}
TEST_F(MidiRenderer_Tests, hairpinEndDynamicAway)
{
EventsHolder events = getNoteOnEvents(renderMidiEvents(u"hairpin_end_dynamic_away.mscx"));
EXPECT_EQ(events.size(), 1);
EXPECT_EQ(events[DEFAULT_CHANNEL].size(), 10);
checkEventInterval(events, 0, 479, 60, 112);
checkEventInterval(events, 480, 959, 59, 104);
checkEventInterval(events, 960, 1439, 55, 96);
checkEventInterval(events, 1440, 1919, 52, 96);
checkEventInterval(events, 1920, 2399, 48, 49);
}
TEST_F(MidiRenderer_Tests, hairpinDynamicJump)
{
EventsHolder events = getNoteOnEvents(renderMidiEvents(u"hairpin_dynamic_jump.mscx"));
EXPECT_EQ(events.size(), 1);
EXPECT_EQ(events[DEFAULT_CHANNEL].size(), 20);
checkEventInterval(events, 0, 479, 55, 96);
checkEventInterval(events, 480, 959, 57, 100);
checkEventInterval(events, 960, 1439, 60, 104);
checkEventInterval(events, 1440, 1919, 62, 108);
checkEventInterval(events, 1920, 3839, 60, 80);
checkEventInterval(events, 3840, 4319, 55, 96);
checkEventInterval(events, 4320, 4799, 57, 92);
checkEventInterval(events, 4800, 5279, 60, 88);
checkEventInterval(events, 5280, 5759, 62, 84);
checkEventInterval(events, 5760, 7679, 60, 112);
}
TEST_F(MidiRenderer_Tests, hairpinDynamicInside)
{
EventsHolder events = getNoteOnEvents(renderMidiEvents(u"hairpin_dynamic_inside.mscx"));
EXPECT_EQ(events.size(), 1);
EXPECT_EQ(events[DEFAULT_CHANNEL].size(), 14);
checkEventInterval(events, 0, 479, 60, 80);
checkEventInterval(events, 480, 959, 62, 85);
checkEventInterval(events, 960, 1439, 64, 90);
checkEventInterval(events, 1440, 1919, 65, 49);
checkEventInterval(events, 1920, 2399, 67, 49);
checkEventInterval(events, 2400, 2879, 69, 96);
checkEventInterval(events, 2880, 3359, 71, 96);
}
/*****************************************************************************
DISABLED TESTS BELOW