Skip to content

Commit

Permalink
Merge pull request #6085 from dmitrio95/plugin-api-rests-tuplets
Browse files Browse the repository at this point in the history
Plugin API: add support for tuplets, add Cursor.addRest()
  • Loading branch information
anatoly-os committed Jun 2, 2020
2 parents dfca3a8 + e7d7c7e commit a4f47db
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 23 deletions.
6 changes: 0 additions & 6 deletions libmscore/duration.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,6 @@ class DurationElement : public Element {
Fraction _duration;
Tuplet* _tuplet;

// #ifdef SCRIPT_INTERFACE
// void setDurationW(FractionWrapper* f) { _duration = f->fraction(); }
// FractionWrapper* durationW() const { return new FractionWrapper(_duration); }
// FractionWrapper* globalDurW() const { return new FractionWrapper(globalDuration()); }
// #endif

public:
DurationElement(Score* = 0, ElementFlags = ElementFlag::MOVABLE | ElementFlag::ON_STAFF);
DurationElement(const DurationElement& e);
Expand Down
28 changes: 20 additions & 8 deletions libmscore/edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2848,19 +2848,31 @@ void Score::cmdEnterRest(const TDuration& d)
return;
}
startCmd();
expandVoice();
if (_is.cr() == 0) {
enterRest(d);
endCmd();
}

//---------------------------------------------------------
// enterRest
//---------------------------------------------------------

void Score::enterRest(const TDuration& d, InputState* externalInputState)
{
InputState& is = externalInputState ? (*externalInputState) : _is;

expandVoice(is.segment(), is.track());

if (!is.cr()) {
qDebug("cannot enter rest here");
return;
}

int track = _is.track();
const int track = is.track();
NoteVal nval;
setNoteRest(_is.segment(), track, nval, d.fraction(), Direction::AUTO);
_is.moveToNextInputPos();
if (!noteEntryMode() || usingNoteEntryMethod(NoteEntryMethod::STEPTIME))
_is.setRest(false); // continue with normal note entry
endCmd();
setNoteRest(is.segment(), track, nval, d.fraction(), Direction::AUTO, /* forceAccidental */ false, /* rhythmic */ false, externalInputState);
is.moveToNextInputPos();
if (!is.noteEntryMode() || is.usingNoteEntryMethod(NoteEntryMethod::STEPTIME))
is.setRest(false); // continue with normal note entry
}

//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions libmscore/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,7 @@ class Score : public QObject, public ScoreElement {
Element* selectMove(const QString& cmd);
Element* move(const QString& cmd);
void cmdEnterRest(const TDuration& d);
void enterRest(const TDuration& d, InputState* externalInputState = nullptr);
void cmdAddInterval(int, const std::vector<Note*>&);
void cmdCreateTuplet(ChordRest*, Tuplet*);
void removeAudio();
Expand Down
107 changes: 107 additions & 0 deletions mscore/plugin/api/cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "libmscore/system.h"
#include "libmscore/segment.h"
#include "libmscore/timesig.h"
#include "libmscore/tuplet.h"

namespace Ms {
namespace PluginAPI {
Expand Down Expand Up @@ -388,6 +389,112 @@ void Cursor::addNote(int pitch, bool addToChord)
_score->addPitch(nval, addToChord, is.get());
}

//---------------------------------------------------------
// addRest
/// \brief Adds a rest to the current cursor position.
/// \details The duration of the added rest equals to
/// what has been set by the previous setDuration() call.
/// \since MuseScore 3.5
//---------------------------------------------------------

void Cursor::addRest()
{
if (!segment()) {
qWarning("Cursor::addRest: cursor location is undefined, use rewind() to define its location");
return;
}
if (!inputState().duration().isValid())
setDuration(1, 4);
_score->enterRest(inputState().duration(), is.get());
}

//---------------------------------------------------------
// addTuplet
/// \brief Adds a tuplet to the current cursor position.
/// \details This function provides a possibility to setup
/// the tuplet's ratio to any value (similarly to
/// Add > Tuplets > Other... dialog in MuseScore).
///
/// Examples of most typical usage:
/// \code
/// // add a triplet of three eighth notes
/// cursor.addTuplet(fraction(3, 2), fraction(1, 4));
///
/// // add a quintuplet in place of the current chord/rest
/// var cr = cursor.element;
/// if (cr)
/// cursor.addTuplet(fraction(5, 4), cr.duration);
/// \endcode
///
/// \param ratio tuplet ratio. Numerator represents
/// actual number of notes in this tuplet, denominator is
/// a number of "normal" notes which correspond to the
/// same total duration. For example, a triplet has a
/// ratio of 3/2 as it has 3 notes fitting to the
/// duration which would normally be occupied by 2 notes
/// of the same nominal length.
/// \param duration total duration of the tuplet. To
/// create a tuplet with duration matching to duration of
/// existing chord or rest, use its
/// \ref DurationElement.duration "duration" value as
/// a parameter.
/// \since MuseScore 3.5
/// \see \ref DurationElement.tuplet
//---------------------------------------------------------

void Cursor::addTuplet(FractionWrapper* ratio, FractionWrapper* duration)
{
if (!segment()) {
qWarning("Cursor::addTuplet: cursor location is undefined, use rewind() to define its location");
return;
}

const Ms::Fraction fRatio = ratio->fraction();
const Ms::Fraction fDuration = duration->fraction();

if (!fRatio.isValid() || fRatio.isZero() || fRatio.negative()
|| !fDuration.isValid() || fDuration.isZero() || fDuration.negative()) {
qWarning("Cursor::addTuplet: invalid parameter values: %s, %s", qPrintable(fRatio.toString()), qPrintable(fDuration.toString()));
return;
}

Ms::Measure* tupletMeasure = segment()->measure();
const Ms::Fraction tupletTick = segment()->tick();

if (tupletTick + fDuration > tupletMeasure->endTick()) {
qWarning(
"Cursor::addTuplet: cannot add cross-measure tuplet (measure %d, rel.tick %s, duration %s)",
tupletMeasure->no() + 1, qPrintable(segment()->rtick().toString()), qPrintable(fDuration.toString()));
return;
}

const Ms::Fraction baseLen = fDuration * Fraction(1, fRatio.denominator());
if (!TDuration::isValid(baseLen)) {
qWarning("Cursor::addTuplet: cannot create tuplet for ratio %s and duration %s", qPrintable(fRatio.toString()), qPrintable(fDuration.toString()));
return;
}

_score->expandVoice(inputState().segment(), inputState().track());
Ms::ChordRest* cr = inputState().cr();
if (!cr) // shouldn't happen?
return;

_score->changeCRlen(cr, fDuration);

Ms::Tuplet* tuplet = new Ms::Tuplet(_score);
tuplet->setParent(tupletMeasure);
tuplet->setTrack(track());
tuplet->setTick(tupletTick);
tuplet->setRatio(fRatio);
tuplet->setTicks(fDuration);
tuplet->setBaseLen(baseLen);

_score->cmdCreateTuplet(cr, tuplet);

inputState().setSegment(tupletMeasure->tick2segment(tupletTick));
inputState().setDuration(baseLen);
}

//---------------------------------------------------------
// setDuration
/// Set duration of the notes added by the cursor.
Expand Down
4 changes: 4 additions & 0 deletions mscore/plugin/api/cursor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef __CURSOR_H__
#define __CURSOR_H__

#include "fraction.h"

namespace Ms {

class Element;
Expand Down Expand Up @@ -182,6 +184,8 @@ class Cursor : public QObject {
Q_INVOKABLE void add(Ms::PluginAPI::Element*);

Q_INVOKABLE void addNote(int pitch, bool addToChord = false);
Q_INVOKABLE void addRest();
Q_INVOKABLE void addTuplet(Ms::PluginAPI::FractionWrapper* ratio, Ms::PluginAPI::FractionWrapper* duration);

//@ set duration
//@ z: numerator
Expand Down
32 changes: 32 additions & 0 deletions mscore/plugin/api/elements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//=============================================================================

#include "elements.h"
#include "fraction.h"
#include "libmscore/property.h"
#include "libmscore/undo.h"

Expand Down Expand Up @@ -166,6 +167,33 @@ void Note::remove(Ms::PluginAPI::Element* wrapped)
qDebug("Note::remove() not impl. %s", s->name());
}

//---------------------------------------------------------
// DurationElement::globalDuration
//---------------------------------------------------------

FractionWrapper* DurationElement::globalDuration() const
{
return wrap(durationElement()->globalTicks());
}

//---------------------------------------------------------
// DurationElement::actualDuration
//---------------------------------------------------------

FractionWrapper* DurationElement::actualDuration() const
{
return wrap(durationElement()->actualTicks());
}

//---------------------------------------------------------
// DurationElement::parentTuplet
//---------------------------------------------------------

Tuplet* DurationElement::parentTuplet()
{
return wrap<Tuplet>(durationElement()->tuplet());
}

//---------------------------------------------------------
// Chord::setPlayEventType
//---------------------------------------------------------
Expand Down Expand Up @@ -264,13 +292,17 @@ Element* wrap(Ms::Element* e, Ownership own)
return wrap<Note>(toNote(e), own);
case ElementType::CHORD:
return wrap<Chord>(toChord(e), own);
case ElementType::TUPLET:
return wrap<Tuplet>(toTuplet(e), own);
case ElementType::SEGMENT:
return wrap<Segment>(toSegment(e), own);
case ElementType::MEASURE:
return wrap<Measure>(toMeasure(e), own);
case ElementType::PAGE:
return wrap<Page>(toPage(e), own);
default:
if (e->isDurationElement())
return wrap<DurationElement>(toDurationElement(e), own);
break;
}
return wrap<Element>(e, own);
Expand Down
Loading

0 comments on commit a4f47db

Please sign in to comment.