Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
60 changes: 38 additions & 22 deletions libmscore/rendermidi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,13 @@ void Score::updateChannel()
//---------------------------------------------------------

static void playNote(EventMap* events, const Note* note, int channel, int pitch,
int velo, int onTime, int offTime)
int velo, int onTime, int offTime, int staffIdx)
{
if (!note->play())
return;
velo = note->customizeVelocity(velo);
NPlayEvent ev(ME_NOTEON, channel, pitch, velo);
ev.setOriginatingStaff(staffIdx);
ev.setTuning(note->tuning());
ev.setNote(note);
events->insert(std::pair<int, NPlayEvent>(onTime, ev));
Expand All @@ -175,7 +176,7 @@ static void playNote(EventMap* events, const Note* note, int channel, int pitch,
// collectNote
//---------------------------------------------------------

static void collectNote(EventMap* events, int channel, const Note* note, int velo, int tickOffset)
static void collectNote(EventMap* events, int channel, const Note* note, int velo, int tickOffset, int staffIdx)
{
if (!note->play() || note->hidden()) // do not play overlapping notes
return;
Expand Down Expand Up @@ -208,7 +209,7 @@ static void collectNote(EventMap* events, int channel, const Note* note, int vel
}
else {
// recurse
collectNote(events, channel, n, velo, tickOffset);
collectNote(events, channel, n, velo, tickOffset, staffIdx);
break;
}
if (n->tieFor() && n != n->tieFor()->endNote())
Expand Down Expand Up @@ -243,7 +244,7 @@ static void collectNote(EventMap* events, int channel, const Note* note, int vel
int off = on + (ticks * e.len())/1000 - 1;
if (tieFor && i == nels - 1)
off += tieLen;
playNote(events, note, channel, p, velo, on, off);
playNote(events, note, channel, p, velo, on, off, staffIdx);
}

// Bends
Expand All @@ -269,6 +270,7 @@ static void collectNote(EventMap* events, int channel, const Note* note, int vel
int msb = midiPitch / 128;
int lsb = midiPitch % 128;
NPlayEvent ev(ME_PITCHBEND, channel, lsb, msb);
ev.setOriginatingStaff(staffIdx);
events->insert(std::pair<int, NPlayEvent>(lastPointTick, ev));
lastPointTick = nextPointTick;
continue;
Expand Down Expand Up @@ -296,11 +298,13 @@ static void collectNote(EventMap* events, int channel, const Note* note, int vel
int msb = midiPitch / 128;
int lsb = midiPitch % 128;
NPlayEvent ev(ME_PITCHBEND, channel, lsb, msb);
ev.setOriginatingStaff(staffIdx);
events->insert(std::pair<int, NPlayEvent>(i, ev));
}
lastPointTick = nextPointTick;
}
NPlayEvent ev(ME_PITCHBEND, channel, 0, 64); // 0:64 is 8192 - no pitch bend
ev.setOriginatingStaff(staffIdx);
events->insert(std::pair<int, NPlayEvent>(tick1+noteLen, ev));
}
}
Expand Down Expand Up @@ -355,29 +359,31 @@ static void collectMeasureEvents(EventMap* events, Measure* m, Staff* staff, int

Chord* chord = static_cast<Chord*>(cr);
Staff* staff = chord->staff();
int staffIdx = staff->idx();
int velocity = staff->velocities().velo(seg->tick());
Instrument* instr = chord->part()->instrument(tick);
int channel = instr->channel(chord->upNote()->subchannel())->channel;
events->registerChannel(channel);

foreach (Articulation* a, chord->articulations()) {
instr->updateVelocity(&velocity,channel, a->subtypeName());
}

for (Chord* c : chord->graceNotesBefore()) {
for (const Note* note : c->notes())
collectNote(events, channel, note, velocity, tickOffset);
collectNote(events, channel, note, velocity, tickOffset, staffIdx);
}

foreach (const Note* note, chord->notes())
collectNote(events, channel, note, velocity, tickOffset);
collectNote(events, channel, note, velocity, tickOffset, staffIdx);

#if 0
// TODO: add support for grace notes after - see createPlayEvents()
QList<Chord*> gna;
chord->getGraceNotesAfter(&gna);
for (Chord* c : gna) {
for (const Note* note : c->notes())
collectNote(events, channel, note, velocity, tickOffset);
collectNote(events, channel, note, velocity, tickOffset, staffIdx);
}
#endif

Expand Down Expand Up @@ -407,6 +413,7 @@ static void collectMeasureEvents(EventMap* events, Measure* m, Staff* staff, int
for (MidiCoreEvent event : nel->events) {
event.setChannel(channel);
NPlayEvent e(event);
e.setOriginatingStaff(firstStaffIdx);
if (e.dataA() == CTRL_PROGRAM)
events->insert(std::pair<int, NPlayEvent>(tick-1, e));
else
Expand Down Expand Up @@ -643,54 +650,56 @@ void Score::renderStaff(EventMap* events, Staff* staff)
// renderSpanners
//---------------------------------------------------------

void Score::renderSpanners(EventMap* events, int staffIdx)
void Score::renderSpanners(EventMap* events)
{
foreach (const RepeatSegment* rs, *repeatList()) {
int tickOffset = rs->utick - rs->tick;
int utick1 = rs->utick;
int tick1 = repeatList()->utick2tick(utick1);
int tick2 = tick1 + rs->len();
std::map<int, std::vector<std::pair<int, bool>>> channelPedalEvents = std::map<int, std::vector<std::pair<int, bool>>>();
std::map<int, std::vector<std::pair<int, std::pair<bool, int>>>> channelPedalEvents;
for (const auto& sp : _spanner.map()) {
Spanner* s = sp.second;
if (s->type() != Element::Type::PEDAL || (staffIdx != -1 && s->staffIdx() != staffIdx))
if (s->type() != Element::Type::PEDAL)
continue;

int staff = s->staffIdx();
int idx = s->staff()->channel(s->tick(), 0);
int channel = s->part()->instrument(s->tick())->channel(idx)->channel;
channelPedalEvents.insert({channel, std::vector<std::pair<int, bool>>()});
std::vector<std::pair<int, bool>> pedalEventList = channelPedalEvents.at(channel);
std::pair<int, bool> lastEvent;
channelPedalEvents.insert({channel, std::vector<std::pair<int, std::pair<bool, int>>>()});
std::vector<std::pair<int, std::pair<bool, int>>> pedalEventList = channelPedalEvents.at(channel);
std::pair<int, std::pair<bool, int>> lastEvent;

if (!pedalEventList.empty())
lastEvent = pedalEventList.back();
else
lastEvent = std::pair<int, bool>(0, true);
lastEvent = std::pair<int, std::pair<bool, int>>(0, std::pair<bool, int>(true, staff));

if (s->tick() >= tick1 && s->tick() < tick2) {
// Handle "overlapping" pedal segments (usual case for connected pedal line)
if (lastEvent.second == false && lastEvent.first >= (s->tick() + tickOffset + 2)) {
if (lastEvent.second.first == false && lastEvent.first >= (s->tick() + tickOffset + 2)) {
channelPedalEvents.at(channel).pop_back();
channelPedalEvents.at(channel).push_back(std::pair<int, bool>(s->tick() + tickOffset + 1, false));
channelPedalEvents.at(channel).push_back(std::pair<int, std::pair<bool, int>>(s->tick() + tickOffset + 1, std::pair<bool, int>(false, staff)));
}
channelPedalEvents.at(channel).push_back(std::pair<int, bool>(s->tick() + tickOffset + 2, true));
channelPedalEvents.at(channel).push_back(std::pair<int, std::pair<bool, int>>(s->tick() + tickOffset + 2, std::pair<bool, int>(true, staff)));
}
if (s->tick2() >= tick1 && s->tick2() <= tick2) {
int t = s->tick2() + tickOffset + 1;
if (t > repeatList()->last()->utick + repeatList()->last()->len())
t = repeatList()->last()->utick + repeatList()->last()->len();
channelPedalEvents.at(channel).push_back(std::pair<int, bool>(t, false));
channelPedalEvents.at(channel).push_back(std::pair<int, std::pair<bool, int>>(t, std::pair<bool, int>(false, staff)));
}
}

for (const auto& pedalEvents : channelPedalEvents) {
int channel = pedalEvents.first;
for (const auto& pe : pedalEvents.second) {
NPlayEvent event;
if (pe.second == true)
if (pe.second.first == true)
event = NPlayEvent(ME_CONTROLLER, channel, CTRL_SUSTAIN, 127);
else
event = NPlayEvent(ME_CONTROLLER, channel, CTRL_SUSTAIN, 0);
event.setOriginatingStaff(pe.second.second);
events->insert(std::pair<int,NPlayEvent>(pe.first, event));
}
}
Expand Down Expand Up @@ -1562,22 +1571,29 @@ void Score::renderMetronome(EventMap* events, Measure* m, int tickOffset)
//---------------------------------------------------------

void Score::renderMidi(EventMap* events)
{
renderMidi(events, true, MScore::playRepeats);
}

void Score::renderMidi(EventMap* events, bool metronome, bool expandRepeats)
{
updateSwing();
createPlayEvents();

updateRepeatList(MScore::playRepeats);
_foundPlayPosAfterRepeats = false;
updateRepeatList(expandRepeats);
updateChannel();
updateVelo();

// create note & other events
foreach (Staff* part, _staves)
renderStaff(events, part);
events->fixupMIDI();

// create sustain pedal events
renderSpanners(events, -1);
renderSpanners(events);

if (!metronome)
return;
// add metronome ticks
foreach (const RepeatSegment* rs, *repeatList()) {
int startTick = rs->tick;
Expand Down
12 changes: 5 additions & 7 deletions libmscore/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,10 +398,6 @@ class Score : public QObject, public ScoreElement {

int _pos[3]; ///< 0 - current, 1 - left loop, 2 - right loop

bool _foundPlayPosAfterRepeats; ///< Temporary used during playback rendering
///< indicating if playPos after expanded repeats
///< has been calculated.

int _fileDivision; ///< division of current loading *.mscx file
int _mscVersion; ///< version of .mscx file during file read, then changed to MSCVERSION for drag and drop
int _mscRealVersion; ///< keep the actual and initial version of current loaded *.mscx file
Expand Down Expand Up @@ -494,6 +490,10 @@ class Score : public QObject, public ScoreElement {
FileError read114(XmlReader&);
FileError read1(XmlReader&, bool ignoreVersionError);

void renderStaff(EventMap* events, Staff*);
void renderSpanners(EventMap* events);
void renderMetronome(EventMap* events, Measure* m, int tickOffset);

protected:
void createPlayEvents(Chord*);
void createGraceNotesPlayEvents(QList<Chord*> gnb, int tick, Chord* chord, int& ontime);
Expand Down Expand Up @@ -807,9 +807,7 @@ class Score : public QObject, public ScoreElement {
PasteStatus pasteStaff(XmlReader&, Segment* dst, int staffIdx);
void pasteSymbols(XmlReader& e, ChordRest* dst);
void renderMidi(EventMap* events);
void renderStaff(EventMap* events, Staff*);
void renderSpanners(EventMap* events, int staffIdx);
void renderMetronome(EventMap* events, Measure* m, int tickOffset);
void renderMidi(EventMap* events, bool metronome, bool expandRepeats);

BeatType tick2beatType(int tick);

Expand Down
16 changes: 7 additions & 9 deletions mscore/exportmidi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@ bool ExportMidi::write(const QString& name, bool midiExpandRepeats)
for (int i = 0; i < cs->nstaves(); ++i)
tracks.append(MidiTrack());

cs->updateSwing();
cs->createPlayEvents();
cs->updateRepeatList(midiExpandRepeats);
EventMap events;
cs->renderMidi(&events, false, midiExpandRepeats);

pauseMap.calculate(cs);
writeHeader();

Expand All @@ -235,11 +235,6 @@ bool ExportMidi::write(const QString& name, bool midiExpandRepeats)
track.setOutPort(part->midiPort());
track.setOutChannel(part->midiChannel());

// Render each staff only once
EventMap events;
cs->renderStaff(&events, staff);
cs->renderSpanners(&events, staffIdx);

// Pass throught the all instruments in the part
const InstrumentList* il = part->instruments();
for(auto j = il->begin(); j!= il->end(); j++) {
Expand Down Expand Up @@ -292,7 +287,10 @@ bool ExportMidi::write(const QString& name, bool midiExpandRepeats)
}

for (auto i = events.begin(); i != events.end(); ++i) {
NPlayEvent event(i->second);
const NPlayEvent& event = i->second;
if (event.getOriginatingStaff() != staffIdx)
continue;

char eventPort = cs->midiPort(event.channel());
char eventChannel = cs->midiChannel(event.channel());
if (port != eventPort || channel != eventChannel)
Expand Down
Loading