Skip to content

Commit

Permalink
note input: first impl. of note insert
Browse files Browse the repository at this point in the history
  • Loading branch information
wschweer committed Aug 3, 2016
1 parent 1d3f978 commit aed09cc
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 83 deletions.
2 changes: 2 additions & 0 deletions libmscore/chordrest.h
Expand Up @@ -178,6 +178,8 @@ class ChordRest : public DurationElement {
virtual Shape shape() const override;
virtual void layoutStem1() {};
virtual void computeUp() { _up = true; };

bool isFullMeasureRest() const { return _durationType == TDuration::DurationType::V_MEASURE; }
};


Expand Down
37 changes: 26 additions & 11 deletions libmscore/cmd.cpp
Expand Up @@ -668,9 +668,10 @@ Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet
if (seg->tick() < nextTick)
continue;
Segment* seg1 = seg->next(Segment::Type::ChordRest);
int tick2 = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
int tick2 = seg1 ? seg1->tick() : seg->measure()->tick() + seg->measure()->ticks();
printf("====ticks %d\n", tick2 - seg->tick());
segment = seg;
Fraction td(Fraction::fromTicks(tick2 - seg->tick()));
segment = seg;
if (td > sd)
td = sd;
akkumulated += td;
Expand All @@ -680,6 +681,16 @@ Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet
nextTick = tick2;
continue;
}
if (seg->tick() > nextTick) {
// there was a gap
Fraction td(Fraction::fromTicks(seg->tick() - nextTick));
if (td > sd)
td = sd;
akkumulated += td;
sd -= td;
if (sd.isZero())
return akkumulated;
}
//
// limit to tuplet level
//
Expand All @@ -699,7 +710,7 @@ Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet
Fraction td(cr->duration());

// remove tremolo between 2 notes, if present
if (cr->type() == Element::Type::CHORD) {
if (cr->isChord()) {
Chord* c = toChord(cr);
if (c->tremolo()) {
Tremolo* tremolo = c->tremolo();
Expand Down Expand Up @@ -753,7 +764,6 @@ Fraction Score::makeGap(Segment* segment, int track, const Fraction& _sd, Tuplet

if ((tuplet == 0) && (((measure->tick() - tick) % dList[0].ticks()) == 0)) {
foreach(TDuration d, dList) {
qDebug("reinstate at %d, %d", tick, d.ticks());
if (ltuplet) {
// take care not to recreate tuplet we just deleted
Rest* r = setRest(tick, track, d.fraction(), false, 0, false);
Expand Down Expand Up @@ -977,13 +987,17 @@ QList<Fraction> Score::splitGapToMeasureBoundaries(ChordRest* cr, Fraction gap)

void Score::changeCRlen(ChordRest* cr, const TDuration& d)
{
Fraction srcF(cr->duration());
Fraction dstF;
if (d.type() == TDuration::DurationType::V_MEASURE)
dstF = cr->measure()->stretchedLen(cr->staff());
else
dstF = d.fraction();
changeCRlen(cr, dstF);
}

void Score::changeCRlen(ChordRest* cr, const Fraction& dstF)
{
Fraction srcF(cr->duration());
if (srcF == dstF)
return;

Expand All @@ -998,7 +1012,7 @@ void Score::changeCRlen(ChordRest* cr, const TDuration& d)
// make shorter and fill with rest
//
deselectAll();
if (cr->type() == Element::Type::CHORD) {
if (cr->isChord()) {
//
// remove ties and tremolo between 2 notes
//
Expand Down Expand Up @@ -1041,7 +1055,7 @@ void Score::changeCRlen(ChordRest* cr, const TDuration& d)
f -= f2;
makeGap(cr1->segment(), cr1->track(), f2, tuplet, first);

if (cr->type() == Element::Type::REST) {
if (cr->isRest()) {
Fraction timeStretch = cr1->staff()->timeStretch(cr1->tick());
Rest* r = toRest(cr);
if (first) {
Expand All @@ -1055,7 +1069,7 @@ void Score::changeCRlen(ChordRest* cr, const TDuration& d)
}
}
else {
r = setRest(tick, track, f2 * timeStretch, (d.dots() > 0), tuplet);
r = setRest(tick, track, f2 * timeStretch, false, tuplet);
}
if (first) {
select(r, SelectType::SINGLE, 0);
Expand All @@ -1065,10 +1079,11 @@ void Score::changeCRlen(ChordRest* cr, const TDuration& d)
}
else {
std::vector<TDuration> dList = toDurationList(f2, true);
Measure* measure = tick2measure(tick);
int etick = measure->tick();
Measure* measure = tick2measure(tick);
int etick = measure->tick();

if (((tick - etick) % dList[0].ticks()) == 0) {
foreach(TDuration du, dList) {
for (TDuration du : dList) {
bool genTie;
Chord* cc;
if (oc) {
Expand Down
134 changes: 81 additions & 53 deletions libmscore/edit.cpp
Expand Up @@ -1323,59 +1323,6 @@ void Score::putNote(const Position& p, bool replace, bool insert)
_is.moveToNextInputPos();
}

//---------------------------------------------------------
// putNoteInsert
//---------------------------------------------------------

void Score::putNoteInsert(const Position& pos)
{
// insert
// TODO:
// - check voices
// - split chord/rest

Element* el = selection().element();
if (!el)
return;
if (!(el->isNote() || el->isRest()))
return;
ChordRest* cr = el->isNote() ? toChordRest(toNote(el)->chord()) : toChordRest(el);
TDuration duration = cr->actualDurationType();
Fraction fraction = cr->duration();
int len = fraction.ticks();
Segment* seg = pos.segment;
int tick = seg->tick();
Measure* m = seg->measure();

for (int track = 0; track < _staves.size() * VOICES; ++track) {
Element* e = seg->element(track);
if (e && e->isChordRest()) {
ChordRest* cr = toChordRest(e);
if (cr->tuplet() && cr->tuplet()->elements().front() != cr) {
qDebug("cannot insert in tuplet");
return;
}
}
}

undoInsertTime(tick, len);
undo(new InsertTime(this, tick, len));
for (Segment* s = pos.segment; s; s = s-> next())
s->undoChangeProperty(P_ID::TICK, s->rtick() + len);
undo(new ChangeMeasureLen(m, m->len() + fraction));

Segment* s = m->undoGetSegment(Segment::Type::ChordRest, tick);
Position p(pos);
p.segment = s;

for (int si = 0; si < _staves.size(); ++si) {
if (si == p.staffIdx)
putNote(p, true, false);
else
addRest(s, si * VOICES, duration, nullptr);
}
}

//---------------------------------------------------------
// repitchNote
//---------------------------------------------------------
Expand Down Expand Up @@ -3164,4 +3111,85 @@ void Score::checkSpanner(int startTick, int endTick)
}
}

//---------------------------------------------------------
// putNoteInsert
//---------------------------------------------------------

void Score::putNoteInsert(const Position& pos)
{
// insert
// TODO:
// - check voices
// - split chord/rest

Element* el = selection().element();
if (!el)
return;
if (!(el->isNote() || el->isRest()))
return;
TDuration duration = _is.duration();
Fraction fraction = duration.fraction();
int len = fraction.ticks();
Segment* seg = pos.segment;
int tick = seg->tick();
Measure* m = seg->measure();

for (int track = 0; track < _staves.size() * VOICES; ++track) {
Element* e = seg->element(track);
if (e && e->isChordRest()) {
ChordRest* cr = toChordRest(e);
if (cr->tuplet() && cr->tuplet()->elements().front() != cr) {
qDebug("cannot insert in tuplet");
return;
}
}
}

undoInsertTime(tick, len);
undo(new InsertTime(this, tick, len));
for (Segment* s = pos.segment; s; s = s-> next())
s->undoChangeProperty(P_ID::TICK, s->rtick() + len);
undo(new ChangeMeasureLen(m, m->len() + fraction));

Segment* s = m->undoGetSegment(Segment::Type::ChordRest, tick);
Position p(pos);
p.segment = s;

int trackI = p.staffIdx * VOICES + _is.voice();
for (int track = 0; track < _staves.size() * VOICES; ++track) {
if (track == trackI)
putNote(p, true, false);
else {
Segment* fs = m->first(Segment::Type::ChordRest);
if (fs->tick() == tick && m->hasVoice(track)) {
setRest(fs->tick(), track, fraction, false, nullptr, false);
continue;
}
Segment* seg1 = 0;
for (Segment* s = fs; s; s = s->next(Segment::Type::ChordRest)) {
if (s->element(track)) {
ChordRest* cr = toChordRest(s->element(track));
if (s->tick() > tick)
break;
if (s->tick() + cr->duration().ticks() < tick)
continue;
seg1 = s;
break;
}
}
if (seg1) {
ChordRest* cr = toChordRest(seg1->element(track));
if (seg1->tick() + cr->duration().ticks() == tick) {
addRest(s, track, duration, nullptr);
}
else if (cr->isFullMeasureRest()) {
// do nothing
}
else
changeCRlen(cr, fraction + cr->duration());
}
}
}
}

}
1 change: 0 additions & 1 deletion libmscore/rest.h
Expand Up @@ -84,7 +84,6 @@ class Rest : public ChordRest {
static int getDotline(TDuration::DurationType durationType);
SymId sym() const { return _sym; }
int computeLineOffset();
bool isFullMeasureRest() const { return durationType() == TDuration::DurationType::V_MEASURE; }
bool accent();
void setAccent(bool flag);

Expand Down
8 changes: 3 additions & 5 deletions libmscore/score.cpp
Expand Up @@ -2554,12 +2554,10 @@ void Score::padToggle(Pad n)

//do not allow to add a dot on a full measure rest
Element* e = selection().element();
if (e && e->type() == Element::Type::REST) {
if (e && e->isRest()) {
Rest* r = toRest(e);
TDuration d = r->durationType();
if (d.type() == TDuration::DurationType::V_MEASURE) {
if (r->isFullMeasureRest())
_is.setDots(0);
}
}

// on measure rest, select the first actual rest
Expand All @@ -2573,7 +2571,7 @@ void Score::padToggle(Pad n)
if (!cr)
return;

if (cr->isChord() && (toChord(cr)->noteType() != NoteType::NORMAL)) {
if (cr->isChord() && (toChord(cr)->isGrace())) {
//
// handle appoggiatura and acciaccatura
//
Expand Down
1 change: 1 addition & 0 deletions libmscore/score.h
Expand Up @@ -616,6 +616,7 @@ class Score : public QObject, public ScoreElement {

Segment* setNoteRest(Segment*, int track, NoteVal nval, Fraction, Direction stemDirection = Direction::AUTO);
void changeCRlen(ChordRest* cr, const TDuration&);
void changeCRlen(ChordRest* cr, const Fraction&);

Fraction makeGap(Segment*, int track, const Fraction&, Tuplet*, bool keepChord = false);
bool makeGap1(int baseTick, int staffIdx, Fraction len, int voiceOffset[VOICES]);
Expand Down
19 changes: 9 additions & 10 deletions mscore/musescore.cpp
Expand Up @@ -464,6 +464,7 @@ void MuseScore::populateNoteInputMenu()
entryTools->addSeparator();
else {
QAction* a = getAction(s);
QWidget* w;
if (strcmp(s, "note-input") == 0) {
//-----------------------------------------------------------------
// Note Entry Modes menu
Expand All @@ -477,16 +478,13 @@ void MuseScore::populateNoteInputMenu()
noteEntryMethods->addAction(getAction("note-input-realtime-auto"));
noteEntryMethods->addAction(getAction("note-input-realtime-manual"));

ToolButtonMenu* noteInputModes = new ToolButtonMenu(tr("Note Entry Methods"),
ToolButtonMenu::TYPES::ICON_CHANGED,
getAction("note-input"),
noteEntryMethods,
this);

entryTools->addWidget(noteInputModes);
w = new ToolButtonMenu(tr("Note Entry Methods"),
ToolButtonMenu::TYPES::ICON_CHANGED,
getAction("note-input"),
noteEntryMethods,
this);
}
else if (strncmp(s, "voice-", 6) == 0) {
// QButton* tb = new QToolButton(this);
AccessibleToolButton* tb = new AccessibleToolButton(this, a);
tb->setFocusPolicy(Qt::ClickFocus);
tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
Expand All @@ -498,10 +496,11 @@ void MuseScore::populateNoteInputMenu()
tb->setPalette(p);
a->setCheckable(true);
// tb->setDefaultAction(a);
entryTools->addWidget(tb);
w = tb;
}
else
entryTools->addWidget(new AccessibleToolButton(entryTools, a));
w = new AccessibleToolButton(entryTools, a);
entryTools->addWidget(w);
}
}
}
Expand Down
24 changes: 21 additions & 3 deletions mscore3.txt
Expand Up @@ -49,6 +49,25 @@
- remove pre 2.0 compatibility


====================================================================
New Features
====================================================================

Timewise insert/delete notes/rests
-----------------------------------

- Ctrl+Shift+[cdefg]
Insert note with current duration.
This increases the duration of the actual measure independent of the
current time signature making it an irregular measure.

- Ctrl + left mouse button in note entry mode
Inserts note/rest with current duration

- Ctrl+Del
Removes the selected Chord/Rest decreasing the duration of the measure.


====================================================================
Programming Style Changes in MuseScore 3
====================================================================
Expand Down Expand Up @@ -87,7 +106,7 @@

Caution when replacing Qt container with stl container as the semantic
may be different. Especially in a "for (xxx : yyy)" loop the Qt container
is copied (copy on write) and the stl container not. That meauns that you can modify a
is copied (copy on write) and the stl container not. That means that you can modify a
Qt container (inserting/deleting elements) in this for loop. This will usually not
work for a stl container.

Expand Down Expand Up @@ -168,6 +187,5 @@

* tablature not tested, has likely regressions
* some scripting interface functions are commented out
* horizontal layout mode not working
* disabled relayout for beamed notes
* horizontal layout mode not working right

0 comments on commit aed09cc

Please sign in to comment.