Skip to content
Permalink
Browse files

fix #282165: Mute voice produces note that doesn't stop when overlap …

…present
  • Loading branch information...
mattmcclinch committed Jul 25, 2019
1 parent b2dffcd commit 711b7ab72caa07318a7b086c4372e5a440ae2020
@@ -293,6 +293,8 @@ bool ExportMidi::write(QIODevice* device, bool midiExpandRepeats, bool exportRPN
for (auto i = events.begin(); i != events.end(); ++i) {
const NPlayEvent& event = i->second;

if (event.isMuted())
continue;
if (event.discard() == staffIdx + 1 && event.velo() > 0)
// turn note off so we can restrike it in another track
track.insert(pauseMap.addPauseTicks(i->first), MidiEvent(ME_NOTEON, channel,
@@ -515,16 +515,7 @@ void Seq::playEvent(const NPlayEvent& event, unsigned framePos)
{
int type = event.type();
if (type == ME_NOTEON) {
bool mute = false;

const Note* note = event.note();
if (note) {
Staff* staff = note->staff();
Instrument* instr = staff->part()->instrument(note->chord()->tick());
const Channel* a = instr->playbackChannel(note->subchannel(), cs);
mute = a->mute() || a->soloMute() || !staff->playbackVoice(note->voice());
}
if (!mute) {
if (!event.isMuted()) {
if (event.discard()) { // ignore noteoff but restrike noteon
if (event.velo() > 0)
putEvent(NPlayEvent(ME_NOTEON, event.channel(), event.pitch(), 0) ,framePos);
Binary file not shown.
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<museScore version="3.01">
<Score>
<LayerTag id="0" tag="default"></LayerTag>
<currentLayer>0</currentLayer>
<Division>480</Division>
<Style>
<pageWidth>8.5</pageWidth>
<pageHeight>11</pageHeight>
<pagePrintableWidth>7.7126</pagePrintableWidth>
<Spatium>1.76389</Spatium>
</Style>
<showInvisible>1</showInvisible>
<showUnprintable>1</showUnprintable>
<showFrames>1</showFrames>
<showMargins>0</showMargins>
<metaTag name="arranger"></metaTag>
<metaTag name="composer"></metaTag>
<metaTag name="copyright"></metaTag>
<metaTag name="lyricist"></metaTag>
<metaTag name="movementNumber"></metaTag>
<metaTag name="movementTitle"></metaTag>
<metaTag name="poet"></metaTag>
<metaTag name="source"></metaTag>
<metaTag name="translator"></metaTag>
<metaTag name="workNumber"></metaTag>
<metaTag name="workTitle">Stuck Note Test</metaTag>
<Part>
<Staff id="1">
<StaffType group="pitched">
<name>stdNormal</name>
</StaffType>
<playbackVoice2>0</playbackVoice2>
</Staff>
<trackName>Piano</trackName>
<Instrument>
<longName>Piano</longName>
<shortName>Pno.</shortName>
<trackName>Piano</trackName>
<minPitchP>21</minPitchP>
<maxPitchP>108</maxPitchP>
<minPitchA>21</minPitchA>
<maxPitchA>108</maxPitchA>
<instrumentId>keyboard.piano</instrumentId>
<Articulation>
<velocity>100</velocity>
<gateTime>95</gateTime>
</Articulation>
<Articulation name="staccatissimo">
<velocity>100</velocity>
<gateTime>33</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="marcato">
<velocity>120</velocity>
<gateTime>67</gateTime>
</Articulation>
<Articulation name="sforzato">
<velocity>150</velocity>
<gateTime>100</gateTime>
</Articulation>
<Articulation name="sforzatoStaccato">
<velocity>150</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoStaccato">
<velocity>120</velocity>
<gateTime>50</gateTime>
</Articulation>
<Articulation name="marcatoTenuto">
<velocity>120</velocity>
<gateTime>100</gateTime>
</Articulation>
<Channel>
<controller ctrl="0" value="0"/>
<controller ctrl="32" value="0"/>
<program value="19"/>
</Channel>
</Instrument>
</Part>
<Staff id="1">
<Measure>
<voice>
<TimeSig>
<sigN>4</sigN>
<sigD>4</sigD>
</TimeSig>
<Rest>
<durationType>quarter</durationType>
</Rest>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>64</pitch>
<tpc>18</tpc>
</Note>
</Chord>
<Rest>
<durationType>quarter</durationType>
</Rest>
<Rest>
<durationType>quarter</durationType>
</Rest>
</voice>
<voice>
<Chord>
<dots>1</dots>
<durationType>half</durationType>
<Note>
<pitch>64</pitch>
<tpc>18</tpc>
</Note>
</Chord>
<Rest>
<durationType>quarter</durationType>
</Rest>
</voice>
</Measure>
<Measure>
<voice>
<Chord>
<durationType>quarter</durationType>
<Note>
<pitch>64</pitch>
<tpc>18</tpc>
</Note>
</Chord>
<Rest>
<durationType>quarter</durationType>
</Rest>
<Rest>
<durationType>half</durationType>
</Rest>
</voice>
</Measure>
</Staff>
</Score>
</museScore>
@@ -60,6 +60,7 @@ class TestMidi : public QObject, public MTest
void midiBendsExport2() { midiExportTestRef("testBends2"); } // Play property test
void midiPortExport() { midiExportTestRef("testMidiPort"); }
void midiArpeggio() { midiExportTestRef("testArpeggio"); }
void midiMutedUnison() { midiExportTestRef("testMutedUnison"); }
void midi184376ExportMidiInitialKeySig()
{
midiExportTestRef("testInitialKeySigThenRepeatToMeas2"); // tick 0 has Bb keysig. Meas 2 has no key sig. Meas 2 repeats back to start of Meas 2. Result should have initial Bb keysig
@@ -14,6 +14,9 @@
#include "libmscore/note.h"
#include "libmscore/sig.h"
#include "event.h"
#include "libmscore/staff.h"
#include "libmscore/instrument.h"
#include "libmscore/part.h"

namespace Ms {

@@ -163,6 +166,23 @@ NPlayEvent::NPlayEvent(BeatType beatType)
}
}

//---------------------------------------------------------
// isMuted
//---------------------------------------------------------

bool NPlayEvent::isMuted() const
{
const Note* n = note();
if (n) {
MasterScore* cs = n->masterScore();
Staff* staff = n->staff();
Instrument* instr = staff->part()->instrument(n->tick());
const Channel* a = instr->playbackChannel(n->subchannel(), cs);
return a->mute() || a->soloMute() || !staff->playbackVoice(n->voice());
}
return false;
}

//---------------------------------------------------------
// dump
//---------------------------------------------------------
@@ -391,25 +411,26 @@ void EventMap::fixupMIDI()

auto it = begin();
while (it != end()) {
NPlayEvent& event = it->second;
/* ME_NOTEOFF is never emitted, no need to check for it */
if (it->second.type() == ME_NOTEON) {
unsigned short np = info[it->second.channel()].nowPlaying[it->second.pitch()];
if (it->second.velo() == 0) {
if (event.type() == ME_NOTEON && !event.isMuted()) {
unsigned short np = info[event.channel()].nowPlaying[event.pitch()];
if (event.velo() == 0) {
/* already off (should not happen) or still playing? */
if (np == 0 || --np > 0)
it->second.setDiscard(1);
event.setDiscard(1);
else {
/* hoist NOTEOFF to same track as NOTEON */
it->second.setOriginatingStaff(info[it->second.channel()].event[it->second.pitch()]->getOriginatingStaff());
event.setOriginatingStaff(info[event.channel()].event[event.pitch()]->getOriginatingStaff());
}
}
else {
if (++np > 1)
/* restrike, possibly on different track */
it->second.setDiscard(info[it->second.channel()].event[it->second.pitch()]->getOriginatingStaff() + 1);
info[it->second.channel()].event[it->second.pitch()] = &(it->second);
event.setDiscard(info[event.channel()].event[event.pitch()]->getOriginatingStaff() + 1);
info[event.channel()].event[event.pitch()] = &event;
}
info[it->second.channel()].nowPlaying[it->second.pitch()] = np;
info[event.channel()].nowPlaying[event.pitch()] = np;
}

++it;
@@ -254,6 +254,7 @@ class NPlayEvent : public PlayEvent {
void setOriginatingStaff(int i) { _origin = i; }
void setDiscard(int d) { _discard = d; }
int discard() const { return _discard; }
bool isMuted() const;
};

//---------------------------------------------------------

0 comments on commit 711b7ab

Please sign in to comment.
You can’t perform that action at this time.