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

Let Ring playback #25864

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void SpannersMetaParser::doParse(const EngravingItem* item, const RenderingConte
break;
}
case ElementType::LET_RING:
type = mpe::ArticulationType::LaissezVibrer;
type = mpe::ArticulationType::LetRing;
break;
case ElementType::PALM_MUTE: {
type = mpe::ArticulationType::PalmMute;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,13 @@ void FluidSequencer::updatePlaybackEvents(EventSequenceMap& destination, const m

destination[timestampTo].emplace(std::move(noteOff));

appendControlSwitch(destination, noteEvent, PEDAL_CC_SUPPORTED_TYPES, midi::SUSTAIN_PEDAL_CONTROLLER);
appendPitchBend(destination, noteEvent, BEND_SUPPORTED_TYPES, channelIdx);
for (const auto& pair : noteEvent.expressionCtx().articulations) {
if (muse::contains(PEDAL_CC_SUPPORTED_TYPES, pair.first)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies if it's a silly question, but is it possible for this conditional to execute more than once throughout the loop? If so, is it OK to call appendControlSwitch more than once for a given noteEvent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be ok to call appendControlSwitch more than once. In practice, that won't happen simply because we only use it for the pedal right now (and each noteEvent will have only 1 pedal articulation)

appendControlSwitch(destination, noteEvent, pair.second.meta, midi::SUSTAIN_PEDAL_CONTROLLER);
} else if (muse::contains(BEND_SUPPORTED_TYPES, pair.first))
appendPitchBend(destination, noteEvent, pair.second.meta, channelIdx);
}
}
}
}
}
Expand All @@ -150,24 +155,8 @@ void FluidSequencer::updateDynamicEvents(EventSequenceMap& destination, const mp
}

void FluidSequencer::appendControlSwitch(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent,
const mpe::ArticulationTypeSet& appliableTypes, const int midiControlIdx)
const mpe::ArticulationMeta& artMeta, const int midiControlIdx)
{
mpe::ArticulationType currentType = mpe::ArticulationType::Undefined;

for (const mpe::ArticulationType type : appliableTypes) {
if (noteEvent.expressionCtx().articulations.contains(type)) {
currentType = type;
break;
}
}

if (currentType == mpe::ArticulationType::Undefined) {
return;
}

const ArticulationAppliedData& articulationData = noteEvent.expressionCtx().articulations.at(currentType);
const ArticulationMeta& articulationMeta = articulationData.meta;

midi::Event start(Event::Opcode::ControlChange, Event::MessageType::ChannelVoice10);
start.setIndex(midiControlIdx);
start.setData(127);
Expand All @@ -178,34 +167,18 @@ void FluidSequencer::appendControlSwitch(EventSequenceMap& destination, const mp
end.setIndex(midiControlIdx);
end.setData(0);

destination[articulationMeta.timestamp + articulationMeta.overallDuration].emplace(std::move(end));
destination[artMeta.timestamp + artMeta.overallDuration].emplace(std::move(end));
}

void FluidSequencer::appendPitchBend(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent,
const mpe::ArticulationTypeSet& appliableTypes, const channel_t channelIdx)
const mpe::ArticulationMeta& artMeta, const channel_t channelIdx)
{
if (noteEvent.pitchCtx().pitchCurve.empty()) {
return;
}

timestamp_t pitchBendTimestampFrom = 0;
duration_t pitchBendDuration = 0;

for (const auto& art : noteEvent.expressionCtx().articulations) {
if (muse::contains(appliableTypes, art.first)) {
const ArticulationMeta& articulationMeta = art.second.meta;
pitchBendTimestampFrom = articulationMeta.timestamp;
pitchBendDuration = articulationMeta.overallDuration;
break;
}
}

if (pitchBendDuration == 0) {
return;
}

const timestamp_t noteTimestampTo = noteEvent.arrangementCtx().actualTimestamp + noteEvent.arrangementCtx().actualDuration;
const timestamp_t pitchBendTimestampTo = std::min(pitchBendTimestampFrom + pitchBendDuration, noteTimestampTo);
const timestamp_t pitchBendTimestampTo = std::min(artMeta.timestamp + artMeta.overallDuration, noteTimestampTo);

midi::Event event(Event::Opcode::PitchBend, Event::MessageType::ChannelVoice10);
event.setChannel(channelIdx);
Expand All @@ -224,8 +197,8 @@ void FluidSequencer::appendPitchBend(EventSequenceMap& destination, const mpe::N
int currBendValue = pitchBendLevel(currIt->second);
int nextBendValue = pitchBendLevel(nextIt->second);

timestamp_t currTime = pitchBendTimestampFrom + pitchBendDuration * percentageToFactor(currIt->first);
timestamp_t nextTime = pitchBendTimestampFrom + pitchBendDuration * percentageToFactor(nextIt->first);
timestamp_t currTime = artMeta.timestamp + artMeta.overallDuration * percentageToFactor(currIt->first);
timestamp_t nextTime = artMeta.timestamp + artMeta.overallDuration * percentageToFactor(nextIt->first);

Interpolation::Point p0 = makePoint(currTime, currBendValue);
Interpolation::Point p1 = makePoint(nextTime, currBendValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ class FluidSequencer : public AbstractEventSequencer<midi::Event>
void updatePlaybackEvents(EventSequenceMap& destination, const mpe::PlaybackEventsMap& changes);
void updateDynamicEvents(EventSequenceMap& destination, const mpe::DynamicLevelLayers& changes);

void appendControlSwitch(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent, const mpe::ArticulationTypeSet& appliableTypes,
void appendControlSwitch(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent, const mpe::ArticulationMeta& artMeta,
const int midiControlIdx);

void appendPitchBend(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent, const mpe::ArticulationTypeSet& appliableTypes,
void appendPitchBend(EventSequenceMap& destination, const mpe::NoteEvent& noteEvent, const mpe::ArticulationMeta& artMeta,
const midi::channel_t channelIdx);

midi::channel_t channel(const mpe::NoteEvent& noteEvent) const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ inline const ArticulationMapping& articulationSounds(const mpe::PlaybackSetupDat
}

static const mpe::ArticulationTypeSet PEDAL_CC_SUPPORTED_TYPES = {
mpe::ArticulationType::Pedal
mpe::ArticulationType::Pedal, mpe::ArticulationType::LetRing,
};

static const mpe::ArticulationTypeSet BEND_SUPPORTED_TYPES = {
Expand Down
1 change: 1 addition & 0 deletions src/framework/mpe/internal/articulationstringutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static const std::unordered_map<ArticulationType, QString> ARTICULATION_TYPE_NAM
{ ArticulationType::Accent, "Accent" },
{ ArticulationType::SoftAccent, "SoftAccent" },
{ ArticulationType::LaissezVibrer, "LaissezVibrer" },
{ ArticulationType::LetRing, "LetRing" },
{ ArticulationType::Subito, "Subito" },
{ ArticulationType::FadeIn, "FadeIn" },
{ ArticulationType::FadeOut, "FadeOut" },
Expand Down
1 change: 1 addition & 0 deletions src/framework/mpe/mpetypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ enum class ArticulationType {
SoftAccent,

LaissezVibrer,
LetRing,

Subito,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,111 @@
}
}
],
"LetRing": [
{
"arrangementPattern": {
"durationFactor": 9900,
"timestampOffset": 0
},
"expressionPattern": {
"dynamicOffsets": [
{
"offsetPosition": 0,
"offsetValue": 0
},
{
"offsetPosition": 1000,
"offsetValue": 1500
},
{
"offsetPosition": 2000,
"offsetValue": 2500
},
{
"offsetPosition": 3000,
"offsetValue": 3500
},
{
"offsetPosition": 4000,
"offsetValue": 4500
},
{
"offsetPosition": 5000,
"offsetValue": 5000
},
{
"offsetPosition": 6000,
"offsetValue": 4500
},
{
"offsetPosition": 7000,
"offsetValue": 3500
},
{
"offsetPosition": 8000,
"offsetValue": 2500
},
{
"offsetPosition": 9000,
"offsetValue": 1500
},
{
"offsetPosition": 10000,
"offsetValue": 0
}
]
},
"patternPosition": 0,
"pitchPattern": {
"pitchOffsets": [
{
"offsetPosition": 0,
"offsetValue": 0
},
{
"offsetPosition": 1000,
"offsetValue": 0
},
{
"offsetPosition": 2000,
"offsetValue": 0
},
{
"offsetPosition": 3000,
"offsetValue": 0
},
{
"offsetPosition": 4000,
"offsetValue": 0
},
{
"offsetPosition": 5000,
"offsetValue": 0
},
{
"offsetPosition": 6000,
"offsetValue": 0
},
{
"offsetPosition": 7000,
"offsetValue": 0
},
{
"offsetPosition": 8000,
"offsetValue": 0
},
{
"offsetPosition": 9000,
"offsetValue": 0
},
{
"offsetPosition": 10000,
"offsetValue": 0
}
]
}
}
],
"PostAppoggiatura": [
{
"arrangementPattern": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5836,6 +5836,111 @@
}
}
],
"LetRing": [
{
"arrangementPattern": {
"durationFactor": 9900,
"timestampOffset": 0
},
"expressionPattern": {
"dynamicOffsets": [
{
"offsetPosition": 0,
"offsetValue": 0
},
{
"offsetPosition": 1000,
"offsetValue": 1500
},
{
"offsetPosition": 2000,
"offsetValue": 2500
},
{
"offsetPosition": 3000,
"offsetValue": 3500
},
{
"offsetPosition": 4000,
"offsetValue": 4500
},
{
"offsetPosition": 5000,
"offsetValue": 5000
},
{
"offsetPosition": 6000,
"offsetValue": 4500
},
{
"offsetPosition": 7000,
"offsetValue": 3500
},
{
"offsetPosition": 8000,
"offsetValue": 2500
},
{
"offsetPosition": 9000,
"offsetValue": 1500
},
{
"offsetPosition": 10000,
"offsetValue": 0
}
]
},
"patternPosition": 0,
"pitchPattern": {
"pitchOffsets": [
{
"offsetPosition": 0,
"offsetValue": 0
},
{
"offsetPosition": 1000,
"offsetValue": 0
},
{
"offsetPosition": 2000,
"offsetValue": 0
},
{
"offsetPosition": 3000,
"offsetValue": 0
},
{
"offsetPosition": 4000,
"offsetValue": 0
},
{
"offsetPosition": 5000,
"offsetValue": 0
},
{
"offsetPosition": 6000,
"offsetValue": 0
},
{
"offsetPosition": 7000,
"offsetValue": 0
},
{
"offsetPosition": 8000,
"offsetValue": 0
},
{
"offsetPosition": 9000,
"offsetValue": 0
},
{
"offsetPosition": 10000,
"offsetValue": 0
}
]
}
}
],
"Legato": [
{
"arrangementPattern": {
Expand Down
Loading