Skip to content

Commit

Permalink
Merge pull request #3674 from lasconic/drumset-variants-2.3
Browse files Browse the repository at this point in the history
fix #272276: Add ability to have a different MIDI pitch for drum inst…
  • Loading branch information
lasconic committed May 16, 2018
2 parents e4d5396 + 53ce87f commit 368ee48
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 7 deletions.
57 changes: 57 additions & 0 deletions libmscore/drumset.cpp
Expand Up @@ -65,6 +65,19 @@ void Drumset::save(Xml& xml) const
break;
}
}
auto vs = variants(i);
if (!vs.isEmpty()) {
xml.stag("variants");
for (auto v : vs) {
xml.stag(QString("variant pitch=\"%1\"").arg(v.pitch));
if (!v.articulationName.isEmpty())
xml.tag("articulation", v.articulationName);
if (v.tremolo != TremoloType::INVALID_TREMOLO)
xml.tag("tremolo", Tremolo::type2name(v.tremolo));
xml.etag();
}
xml.etag();
}
xml.etag();
}
}
Expand Down Expand Up @@ -110,6 +123,25 @@ void Drumset::load(XmlReader& e)
int i = val.toInt(&isNum);
_drum[pitch].shortcut = isNum ? i : toupper(val[0].toLatin1());
}
else if (tag == "variants") {
while(e.readNextStartElement()) {
const QStringRef& tagv(e.name());
if (tagv == "variant") {
DrumInstrumentVariant div;
div.pitch = e.attribute("pitch").toInt();
while (e.readNextStartElement()) {
const QStringRef& taga(e.name());
if (taga == "articulation") {
div.articulationName = e.readElementText();
}
else if (taga == "tremolo") {
div.tremolo = Tremolo::name2Type(e.readElementText());
}
}
_drum[pitch].addVariant(div);
}
}
}
else
e.unknown();
}
Expand Down Expand Up @@ -162,6 +194,31 @@ int Drumset::prevPitch(int ii) const
return 0;
}

//---------------------------------------------------------
// findVariant
/// find a variant for the given pitch with matching chord articulation and tremolo
//---------------------------------------------------------

DrumInstrumentVariant Drumset::findVariant(int p, const QList<Articulation*> articulations, Tremolo* tremolo)
{
DrumInstrumentVariant div;
auto vs = variants(p);
for (auto v : vs) {
bool matchTremolo = (!tremolo && v.tremolo == TremoloType::INVALID_TREMOLO) || v.tremolo == tremolo->tremoloType();
bool matchArticulation = v.articulationName.isEmpty() && articulations.isEmpty();
for (auto a : articulations) {
matchArticulation = a->subtypeName() == v.articulationName;
if (!matchArticulation)
break;
}
if (matchArticulation && matchTremolo) {
div = v;
break;
}
}
return div;
}

//---------------------------------------------------------
// initDrumset
// initialize standard midi drumset
Expand Down
16 changes: 16 additions & 0 deletions libmscore/drumset.h
Expand Up @@ -14,13 +14,25 @@
#define __DRUMSET_H__

#include "mscore.h"
#include "tremolo.h"
#include "note.h"
#include "articulation.h"
#include "sym.h"

namespace Ms {

class Xml;

struct DrumInstrumentVariant {
int pitch;
QString articulationName;
TremoloType tremolo;
DrumInstrumentVariant() {
pitch = INVALID_PITCH;
tremolo = TremoloType::INVALID_TREMOLO;
}
};

//---------------------------------------------------------
// DrumInstrument
//---------------------------------------------------------
Expand All @@ -36,11 +48,13 @@ struct DrumInstrument {
MScore::Direction stemDirection;
int voice;
char shortcut; ///< accelerator key (CDEFGAB)
QList<DrumInstrumentVariant> variants;

DrumInstrument() {}
DrumInstrument(const char* s, NoteHead::Group nh, int l, MScore::Direction d,
int v = 0, char sc = 0)
: name(s), notehead(nh), line(l), stemDirection(d), voice(v), shortcut(sc) {}
void addVariant(DrumInstrumentVariant v) { variants.append(v); }
};

static const int DRUM_INSTRUMENTS = 128;
Expand All @@ -64,6 +78,7 @@ class Drumset {
MScore::Direction stemDirection(int pitch) const { return _drum[pitch].stemDirection; }
const QString& name(int pitch) const { return _drum[pitch].name; }
int shortcut(int pitch) const { return _drum[pitch].shortcut; }
QList<DrumInstrumentVariant> variants(int pitch) const { return _drum[pitch].variants; }

void save(Xml&) const;
void load(XmlReader&);
Expand All @@ -72,6 +87,7 @@ class Drumset {
int prevPitch(int) const;
DrumInstrument& drum(int i) { return _drum[i]; }
const DrumInstrument& drum(int i) const { return _drum[i]; }
DrumInstrumentVariant findVariant(int pitch, const QList<Articulation*> articulations, Tremolo* tremolo);
};

extern Drumset* smDrumset;
Expand Down
14 changes: 12 additions & 2 deletions libmscore/note.cpp
Expand Up @@ -818,7 +818,7 @@ void Note::draw(QPainter* painter) const
// by coloring the notehead
//
if (chord() && chord()->segment() && staff() && !selected()
&& !score()->printing() && MScore::warnPitchRange) {
&& !score()->printing() && MScore::warnPitchRange && !staff()->isDrumStaff()) {
const Instrument* in = part()->instrument(chord()->tick());
int i = ppitch();
if (i < in->minPitchP() || i > in->maxPitchP())
Expand Down Expand Up @@ -2181,7 +2181,17 @@ void Note::setHeadGroup(NoteHead::Group val)

int Note::ppitch() const
{
return _pitch + staff()->pitchOffset(chord()->segment()->tick());
Chord* ch = chord();
// if staff is drum
// match tremolo and articulation between variants and chord
if (play() && ch && ch->staff() && ch->staff()->isDrumStaff()) {
Drumset* ds = ch->staff()->part()->instrument(ch->tick())->drumset();
DrumInstrumentVariant div = ds->findVariant(_pitch, ch->articulations(), ch->tremolo());
if (div.pitch != INVALID_PITCH)
return div.pitch;
}
return _pitch + staff()->pitchOffset(ch->segment()->tick());

}

//---------------------------------------------------------
Expand Down
13 changes: 12 additions & 1 deletion libmscore/rendermidi.cpp
Expand Up @@ -765,11 +765,22 @@ bool Score::isSubdivided(ChordRest* chord, int swingUnit)
// renderTremolo
//---------------------------------------------------------

void renderTremolo(Chord *chord, QList<NoteEventList> & ell)
void renderTremolo(Chord* chord, QList<NoteEventList>& ell)
{
Segment* seg = chord->segment();
Tremolo* tremolo = chord->tremolo();
int notes = chord->notes().size();

// check if tremolo was rendered before for drum staff
if (chord->staff() && chord->staff()->isDrumStaff()) {
Drumset* ds = chord->staff()->part()->instrument(chord->tick())->drumset();
for (Note* n : chord->notes()) {
DrumInstrumentVariant div = ds->findVariant(n->pitch(), chord->articulations(), chord->tremolo());
if (div.pitch !=INVALID_PITCH && div.tremolo == tremolo->tremoloType())
return; // already rendered
}
}

//int n = 1 << tremolo->lines();
//int l = 1000 / n;
if (chord->tremoloChordType() == TremoloChordType::TremoloFirstNote) {
Expand Down
26 changes: 22 additions & 4 deletions libmscore/tremolo.cpp
Expand Up @@ -377,7 +377,25 @@ void Tremolo::read(XmlReader& e)

QString Tremolo::tremoloTypeName() const
{
switch(tremoloType()) {
return type2name(tremoloType());
}

//---------------------------------------------------------
// setTremoloType
//---------------------------------------------------------

void Tremolo::setTremoloType(const QString& s)
{
setTremoloType(name2Type(s));
}

//---------------------------------------------------------
// type2Name
//---------------------------------------------------------

QString Tremolo::type2name(TremoloType t)
{
switch(t) {
case TremoloType::R8: return QString("r8");
case TremoloType::R16: return QString("r16");
case TremoloType::R32: return QString("r32");
Expand All @@ -393,10 +411,10 @@ QString Tremolo::tremoloTypeName() const
}

//---------------------------------------------------------
// setTremoloType
// nameToType
//---------------------------------------------------------

void Tremolo::setTremoloType(const QString& s)
TremoloType Tremolo::name2Type(const QString& s)
{
TremoloType t;
if (s == "r8")
Expand All @@ -417,7 +435,7 @@ void Tremolo::setTremoloType(const QString& s)
t = TremoloType::C64;
else
t = TremoloType(s.toInt()); // for compatibility with old tremolo type
setTremoloType(t);
return t;
}

//---------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions libmscore/tremolo.h
Expand Up @@ -23,6 +23,7 @@ class Chord;

// Tremolo subtypes:
enum class TremoloType : char {
INVALID_TREMOLO = -1,
OLD_R8 = 0,
OLD_R16,
OLD_R32,
Expand Down Expand Up @@ -62,6 +63,8 @@ class Tremolo : public Element {

void setTremoloType(TremoloType t);
TremoloType tremoloType() const { return _tremoloType; }
static TremoloType name2Type(const QString& s);
static QString type2name(TremoloType t);

virtual qreal mag() const;
virtual void draw(QPainter*) const;
Expand Down

0 comments on commit 368ee48

Please sign in to comment.