MuseScore/libmscore/drumset.cpp

278 lines
13 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2007-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "drumset.h"
#include "xml.h"
#include "note.h"
#include "articulation.h"
namespace Ms {
Drumset* smDrumset; // standard midi drumset
Drumset* gpDrumset; // guitar pro drumset
//---------------------------------------------------------
// save
//---------------------------------------------------------
void Drumset::save(XmlWriter& xml) const
{
for (int i = 0; i < 128; ++i) {
if (!isValid(i))
continue;
xml.stag(QString("Drum pitch=\"%1\"").arg(i));
const NoteHead::Group nh = noteHead(i);
//write custom as Normal notehead group + noteheads tag to keep compatibility with 2.X versions
const NoteHead::Group saveNHValue = (nh == NoteHead::Group::HEAD_CUSTOM) ? NoteHead::Group::HEAD_NORMAL : nh;
xml.tag("head", NoteHead::group2name(saveNHValue));
if (nh == NoteHead::Group::HEAD_CUSTOM) {
xml.stag("noteheads");
for (int j = 0; j < int(NoteHead::Type::HEAD_TYPES); j++) {
xml.tag(NoteHead::type2name(NoteHead::Type(j)), Sym::id2name(noteHeads(i, NoteHead::Type(j))));
}
xml.etag();
}
xml.tag("line", line(i));
xml.tag("voice", voice(i));
xml.tag("name", name(i));
xml.tag("stem", int(stemDirection(i)));
if (shortcut(i)) {
switch (shortcut(i)) {
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'A':
case 'B':
{
char a[2];
a[0] = shortcut(i);
a[1] = 0;
xml.tag("shortcut", a);
}
break;
default:
qDebug("illegal drum shortcut");
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();
}
}
bool Drumset::readProperties(XmlReader& e, int pitch)
{
if (pitch < 0 || pitch > DRUM_INSTRUMENTS - 1)
return false;
const QStringRef& tag(e.name());
if (tag == "head")
_drum[pitch].notehead = NoteHead::name2group(e.readElementText());
else if (tag == "noteheads") {
_drum[pitch].notehead = NoteHead::Group::HEAD_CUSTOM;
while (e.readNextStartElement()) {
const QStringRef& nhTag(e.name());
int noteType = int(NoteHead::name2type(nhTag.toString()));
if (noteType > int(NoteHead::Type::HEAD_TYPES) - 1 || noteType < 0)
return false;
_drum[pitch].noteheads[noteType] = Sym::name2id(e.readElementText());
}
}
else if (tag == "line")
_drum[pitch].line = e.readInt();
else if (tag == "voice")
_drum[pitch].voice = e.readInt();
else if (tag == "name")
_drum[pitch].name = e.readElementText();
else if (tag == "stem")
_drum[pitch].stemDirection = Direction(e.readInt());
else if (tag == "shortcut") {
bool isNum;
QString val(e.readElementText());
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
return false;
return true;
}
//---------------------------------------------------------
// load
//---------------------------------------------------------
void Drumset::load(XmlReader& e)
{
int pitch = e.intAttribute("pitch", -1);
if (pitch < 0 || pitch > 127) {
qDebug("load drumset: invalid pitch %d", pitch);
return;
}
while (e.readNextStartElement()) {
if (readProperties(e, pitch))
;
else
e.unknown();
}
}
//---------------------------------------------------------
// clear
//---------------------------------------------------------
void Drumset::clear()
{
for (int i = 0; i < 128; ++i) {
_drum[i].name = "";
_drum[i].notehead = NoteHead::Group::HEAD_INVALID;
_drum[i].shortcut = 0;
_drum[i].variants.clear();
}
}
//---------------------------------------------------------
// nextPitch
//---------------------------------------------------------
int Drumset::nextPitch(int ii) const
{
for (int i = ii + 1; i < 127; ++i) {
if (isValid(i))
return i;
}
for (int i = 0; i <= ii; ++i) {
if (isValid(i))
return i;
}
return 0;
}
//---------------------------------------------------------
// prevPitch
//---------------------------------------------------------
int Drumset::prevPitch(int ii) const
{
for (int i = ii - 1; i >= 0; --i) {
if (isValid(i))
return i;
}
for (int i = 127; i >= ii; --i) {
if (isValid(i))
return i;
}
return 0;
}
//---------------------------------------------------------
// findVariant
/// find a variant for the given pitch with matching chord articulation and tremolo
//---------------------------------------------------------
DrumInstrumentVariant Drumset::findVariant(int p, const QVector<Articulation*> articulations, Tremolo* tremolo) const
{
DrumInstrumentVariant div;
auto vs = variants(p);
for (auto v : vs) {
bool matchTremolo = (!tremolo && v.tremolo == TremoloType::INVALID_TREMOLO) || (tremolo && v.tremolo == tremolo->tremoloType());
bool matchArticulation = v.articulationName.isEmpty() && articulations.isEmpty();
for (auto a : articulations) {
matchArticulation = a->articulationName() == v.articulationName;
if (!matchArticulation)
break;
}
if (matchArticulation && matchTremolo) {
div = v;
break;
}
}
return div;
}
//---------------------------------------------------------
// initDrumset
// initialize standard midi drumset
//---------------------------------------------------------
void initDrumset()
{
smDrumset = new Drumset;
for (int i = 0; i < 128; ++i) {
smDrumset->drum(i).notehead = NoteHead::Group::HEAD_INVALID;
smDrumset->drum(i).line = 0;
smDrumset->drum(i).shortcut = 0;
smDrumset->drum(i).voice = 0;
smDrumset->drum(i).stemDirection = Direction::UP;
}
smDrumset->drum(35) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Acoustic Bass Drum"), NoteHead::Group::HEAD_NORMAL, 7, Direction::DOWN, 1);
smDrumset->drum(36) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Bass Drum 1"), NoteHead::Group::HEAD_NORMAL, 7, Direction::DOWN, 1, Qt::Key_B);
smDrumset->drum(37) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Side Stick"), NoteHead::Group::HEAD_CROSS, 3, Direction::UP);
smDrumset->drum(38) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Acoustic Snare"), NoteHead::Group::HEAD_NORMAL, 3, Direction::UP, 0, Qt::Key_A);
smDrumset->drum(40) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Electric Snare"), NoteHead::Group::HEAD_NORMAL, 3, Direction::UP);
smDrumset->drum(41) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Low Floor Tom"), NoteHead::Group::HEAD_NORMAL, 5, Direction::UP);
smDrumset->drum(42) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Closed Hi-Hat"), NoteHead::Group::HEAD_CROSS, -1, Direction::UP, 0, Qt::Key_G);
smDrumset->drum(43) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "High Floor Tom"), NoteHead::Group::HEAD_NORMAL, 5, Direction::DOWN, 1);
smDrumset->drum(44) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Pedal Hi-Hat"), NoteHead::Group::HEAD_CROSS, 9, Direction::DOWN, 1, Qt::Key_F);
smDrumset->drum(45) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Low Tom"), NoteHead::Group::HEAD_NORMAL, 2, Direction::UP);
smDrumset->drum(46) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Open Hi-Hat"), NoteHead::Group::HEAD_CROSS, 1, Direction::UP);
smDrumset->drum(47) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Low-Mid Tom"), NoteHead::Group::HEAD_NORMAL, 1, Direction::UP);
smDrumset->drum(48) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Hi-Mid Tom"), NoteHead::Group::HEAD_NORMAL, 0, Direction::UP);
smDrumset->drum(49) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Crash Cymbal 1"), NoteHead::Group::HEAD_CROSS, -2, Direction::UP, 0, Qt::Key_C);
smDrumset->drum(50) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "High Tom"), NoteHead::Group::HEAD_NORMAL, 0, Direction::UP, 0, Qt::Key_E);
smDrumset->drum(51) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Ride Cymbal 1"), NoteHead::Group::HEAD_CROSS, 0, Direction::UP, 0, Qt::Key_D);
smDrumset->drum(52) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Chinese Cymbal"), NoteHead::Group::HEAD_CROSS, -3, Direction::UP);
smDrumset->drum(53) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Ride Bell"), NoteHead::Group::HEAD_DIAMOND, 0, Direction::UP);
smDrumset->drum(54) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Tambourine"), NoteHead::Group::HEAD_DIAMOND, 2, Direction::UP);
smDrumset->drum(55) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Splash Cymbal"), NoteHead::Group::HEAD_CROSS, -3, Direction::UP);
smDrumset->drum(56) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Cowbell"), NoteHead::Group::HEAD_TRIANGLE_DOWN, 1, Direction::UP);
smDrumset->drum(57) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Crash Cymbal 2"), NoteHead::Group::HEAD_CROSS, -3, Direction::UP);
smDrumset->drum(59) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Ride Cymbal 2"), NoteHead::Group::HEAD_CROSS, 2, Direction::UP);
smDrumset->drum(63) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Open Hi Conga"), NoteHead::Group::HEAD_CROSS, 4, Direction::UP);
smDrumset->drum(64) = DrumInstrument(QT_TRANSLATE_NOOP("drumset", "Low Conga"), NoteHead::Group::HEAD_CROSS, 6, Direction::UP);
}
}