diff --git a/Resources/Music/extendcursor.eps b/Resources/Music/extendcursor.eps new file mode 100644 index 0000000..09f8755 --- /dev/null +++ b/Resources/Music/extendcursor.eps @@ -0,0 +1,97 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: -1 -215.5 566.742 180 +%%Pages: 0 +%%Title: noteheads.s0triangle from feta26 +%%Creator: FontForge +%%Author: Matthias Neeracher +%%CreationDate: 19:50 21-4-2007 +%%EndComments +%%BeginPreview: 73 51 4 51 +%0027ADC6000000000000000000000000000000000000000000000000000000000000000000 +%07FFFFFFD50000000000000000000000000000000000000000000000000000000000000000 +%1FFFFFFFFFC500000000000000000000000000000000000000000000000000000000000000 +%1FFFFFFFFFFFD6000000000000000000000000000000000000000000000000000000000000 +%06FFFFFFFFFFFFE81000000000000000000000000000000000000000000000000000000000 +%007FFFFFFFFFFFFFFA40000000000000000000000000000000000000000000000000000000 +%0009FFFFFFFFFFFFFFFD710000000000000000000000000000000000000000000000000000 +%0000CFFFFFFFFFFFFFFFFFA500000000000000000000000000000000000000000000000000 +%00002EFFFFFFFFFFFFFFFFFFE9400000000000000000000000000000000000000000000000 +%000006FFFFFFFFFFFFFFFFFFFFFEA510000000000000000000000000000000000000000000 +%000000BFFFFFFFFFFFFFFFFFFFFFFFFB730000000000000000000000000000000000000000 +%0000002FFFFFFFFFFFFFFFFFFFFFFFFFFFEA62000000000000000000000000000000000000 +%00000008FFFFFFFFF9DFFFFFFFFFFFFFFFFFFFEB7410000000000000000000000000000000 +%00000001EFFFFFFFF7038DFFFFFFFFFFFFFFFFFFFFFDA85310000000000000000000000000 +%000000007FFFFFFFFD000038DFFFFFFFFFFFFFFFFFFFFFFFFDB97542000000000000000000 +%000000001EFFFFFFFF600000027BFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA998877653000 +%0000000008FFFFFFFFD000000000149CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC20 +%0000000001FFFFFFFFF4000000000000159CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +%0000000000AFFFFFFFFA0000000000000000148BEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +%00000000005FFFFFFFFF100000000000000000000257ADFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +%00000000000EFFFFFFFF600000000000000000000000000257DFFFFFFFFFFFFFFFFFFFF910 +%000000000009FFFFFFFFB0000000000000000000000000028DFFFFFFFFFFFFFFFFFFB61000 +%000000000005FFFFFFFFF1000000000000000000000003AFFFFFFFFFFFFFFFFFC840000000 +%000000000001FFFFFFFFF40000000000000000000005CFFFFFFFFFFFFFFFFB620000000000 +%000000000000BFFFFFFFF800000000000000000005CFFFFFFFFFFFFFFFB610000000000000 +%0000000000007FFFFFFFFB000000000000000005CFFFFFFFFFFFFFFD720000000000000000 +%0000000000004FFFFFFFFE0000000000000003CFFFFFFFFFFFFFFA40000000000000000000 +%0000000000001FFFFFFFFF10000000000002AFFFFFFFFFFFFFE81000000000000000000000 +%0000000000000DFFFFFFFF3000000000007EFFFFFFFFFFFFD6100000000000000000000000 +%0000000000000BFFFFFFFF50000000003DFFFFFFFFFFFFD600000000000000000000000000 +%00000000000009FFFFFFFF7000000019FFFFFFFFFFFFE60000000000000000000000000000 +%00000000000007FFFFFFFF80000003DFFFFFFFFFFFE7100000000000000000000000000000 +%00000000000006FFFFFFFF8000008FFFFFFFFFFFFA20000000000000000000000000000000 +%00000000000005FFFFFFFF90001BFFFFFFFFFFFC3000000000000000000000000000000000 +%00000000000004FFFFFFFF9003DFFFFFFFFFFF700000000000000000000000000000000000 +%00000000000003FFFFFFFF906FFFFFFFFFFFC2000000000000000000000000000000000000 +%00000000000003FFFFFFFFA9FFFFFFFFFFF700000000000000000000000000000000000000 +%00000000000003FFFFFFFFFFFFFFFFFFFD3000000000000000000000000000000000000000 +%00000000000004FFFFFFFFFFFFFFFFFF910000000000000000000000000000000000000000 +%00000000000004FFFFFFFFFFFFFFFFE6000000000000000000000000000000000000000000 +%00000000000005FFFFFFFFFFFFFFFD30000000000000000000000000000000000000000000 +%00000000000007FFFFFFFFFFFFFFB100000000000000000000000000000000000000000000 +%00000000000008FFFFFFFFFFFFF90000000000000000000000000000000000000000000000 +%0000000000000AFFFFFFFFFFFF700000000000000000000000000000000000000000000000 +%0000000000000DFFFFFFFFFFF5000000000000000000000000000000000000000000000000 +%0000000000001FFFFFFFFFFE40000000000000000000000000000000000000000000000000 +%0000000000003FFFFFFFFFE300000000000000000000000000000000000000000000000000 +%0000000000005FFFFFFFFE3000000000000000000000000000000000000000000000000000 +%0000000000002EFFFFFFD20000000000000000000000000000000000000000000000000000 +%00000000000003CFFFFC200000000000000000000000000000000000000000000000000000 +%00000000000000014551000000000000000000000000000000000000000000000000000000 +%%EndPreview +%%EndProlog +%%Page "noteheads.s0triangle" 1 +gsave newpath + 25 178 moveto + 28 179 34 180 38 180 curveto + 43 180 45 180 59 172 curveto + 164 118 279 83 396 68 curveto + 434 63 466 60 512 59 curveto + 542 58 545 58 550 56 curveto + 564 51 570 39 565 28 curveto + 561 20 553 16 524 8 curveto + 386 -27 266 -95 164 -195 curveto + 153 -205 144 -214 142 -214 curveto + 137 -216 131 -216 119 -214 curveto + 108 -213 99 -208 95 -203 curveto + 91 -198 91 -193 94 -178 curveto + 103 -136 103 -82 94 -35 curveto + 87 1 74 39 58 70 curveto + 43 98 23 127 8 142 curveto + 1 149 -1 153 -1 158 curveto + -1 162 1 167 4 170 curveto + 8 173 17 177 25 178 curveto + closepath + 155 74 moveto + 140 79 128 83 127 84 curveto + 126 84 127 80 132 69 curveto + 158 19 170 -33 170 -88 curveto + 170 -108 171 -111 172 -110 curveto + 179 -104 197 -90 208 -81 curveto + 259 -43 317 -11 377 13 curveto + 385 16 391 19 391 19 curveto + 389 19 354 24 344 26 curveto + 280 37 218 53 155 74 curveto + closepath +1 0 0 setrgbcolor fill grestore +%%EOF diff --git a/Sources/VLModel.cpp b/Sources/VLModel.cpp index 1ae520f..941318f 100644 --- a/Sources/VLModel.cpp +++ b/Sources/VLModel.cpp @@ -999,6 +999,67 @@ void VLSong::DelNote(size_t measure, VLFraction at) } } +void VLSong::ExtendNote(size_t measure, VLFraction at) +{ + VLNoteList::iterator i = fMeasures[measure].fMelody.begin(); + VLFraction t(0); + + for (;;) { + if (t == at) { + if (i->fPitch == VLNote::kNoPitch) + return; // Don't extend rests + do { + VLNoteList::iterator j=i; + ++j; + if (j != fMeasures[measure].fMelody.end()) { + // + // Extend across next note/rest + // + i->fDuration += j->fDuration; + fMeasures[measure].fMelody.erase(j); + } else if (++measure < fMeasures.size()) { + // + // Extend into next measure + // + VLNoteList::iterator k = fMeasures[measure].fMelody.begin(); + if (k->fTied & VLNote::kTiedWithPrev) { + // + // Already extended, extend further + // + i = k; + continue; // Go for another spin + } else { + bool wasTied = k->fTied & VLNote::kTiedWithNext; + // + // Extend previous note + // + k->fPitch = i->fPitch; + k->fTied = VLNote::kTiedWithPrev; + i->fTied != VLNote::kTiedWithNext; + k->fLyrics.clear(); + if (wasTied) { + // + // Extend further + // + i = k; + continue; + } + } + } + } while (0); + // + // Finished extending + // + return; + } + VLFraction tEnd = t+i->fDuration; + if (tEnd > at) + break; // Past the point, quit + t = tEnd; + ++i; + } +} + static void TransposePinned(int8_t & pitch, int semi) { if (pitch == VLNote::kNoPitch) diff --git a/Sources/VLModel.h b/Sources/VLModel.h index cc2b18a..5f3155e 100644 --- a/Sources/VLModel.h +++ b/Sources/VLModel.h @@ -315,6 +315,7 @@ struct VLSong { void AddNote(VLLyricsNote note, size_t measure, VLFraction at); void DelChord(size_t measure, VLFraction at); void DelNote(size_t measure, VLFraction at); + void ExtendNote(size_t measure, VLFraction at); void AddRepeat(size_t beginMeasure, size_t endMeasure, int times); void DelRepeat(size_t beginMeasure, size_t endMeasure); void AddEnding(size_t beginMeasure, size_t endMeasure, size_t volta); diff --git a/Sources/VLSheetView.h b/Sources/VLSheetView.h index 878f131..49037ca 100644 --- a/Sources/VLSheetView.h +++ b/Sources/VLSheetView.h @@ -36,6 +36,7 @@ enum VLMusicElement { kMusicNaturalCursor, kMusicRestCursor, kMusicKillCursor, + kMusicExtendCursor, kMusicCoda, kMusicElements }; diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index 521a4db..4b0e3f3 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -44,6 +44,7 @@ static NSString * sElementNames[kMusicElements] = { @"naturalcursor", @"restcursor", @"killcursor", + @"extendcursor", @"coda" }; @@ -654,9 +655,17 @@ static int8_t sSharpAcc[] = { - (void) accidentalFromEvent:(NSEvent *)event { + fCursorAccidental = (VLMusicElement)0; + + // + // Extension + // + if ([event modifierFlags] & NSShiftKeyMask) { + fCursorAccidental = kMusicExtendCursor; + return; + } const VLProperties & prop = [self song]->fProperties.front(); - fCursorAccidental = (VLMusicElement)0; if (prop.fKey >= 0) { if (prop.fKey >= sSharpAcc[fCursorPitch % 12]) { // Sharp in Key switch ([event modifierFlags] & (NSAlternateKeyMask|NSCommandKeyMask)) { diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index 04baab3..591dce5 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -22,7 +22,9 @@ VLNote newNote(1, fClickMode==' ' ? fCursorActualPitch : VLNote::kNoPitch); [[self document] willChangeSong]; - if (fClickMode == 'k') + if (fCursorAccidental == kMusicExtendCursor) + [self song]->ExtendNote(fCursorMeasure, fCursorAt); + else if (fClickMode == 'k') [self song]->DelNote(fCursorMeasure, fCursorAt); else [self song]->AddNote(VLLyricsNote(newNote), fCursorMeasure, fCursorAt); @@ -75,37 +77,40 @@ VLMusicElement cursorElt; cursorX = [self noteXInMeasure:fCursorMeasure at:fCursorAt]; - switch (fClickMode) { - default: + if (fCursorAccidental == kMusicExtendCursor) { cursorY = [self noteYInMeasure:fCursorMeasure withPitch:fCursorPitch - accidental:&accidental] - -kNoteY; - [self drawLedgerLinesWithPitch:fCursorPitch - at:NSMakePoint(cursorX, - [self systemY:fCursorMeasure/fMeasPerSystem])]; - cursorElt = kMusicNoteCursor; - break; - case 'r': - cursorY = [self noteYInMeasure:fCursorMeasure - withPitch:65 - accidental:&accidental]; - cursorElt = kMusicRestCursor; - break; - case 'k': - cursorY = [self noteYInMeasure:fCursorMeasure - withPitch:fCursorPitch - accidental:&accidental]; - cursorElt = kMusicKillCursor; - break; - } + accidental:&accidental]; + cursorElt = fCursorAccidental; + } else + switch (fClickMode) { + default: + cursorY = + [self noteYInMeasure:fCursorMeasure + withPitch:fCursorPitch accidental:&accidental] - kNoteY; + [self drawLedgerLinesWithPitch:fCursorPitch + at:NSMakePoint(cursorX, + [self systemY:fCursorMeasure/fMeasPerSystem])]; + cursorElt = kMusicNoteCursor; + break; + case 'r': + cursorY = [self noteYInMeasure:fCursorMeasure + withPitch:65 accidental:&accidental]; + cursorElt = kMusicRestCursor; + break; + case 'k': + cursorY = [self noteYInMeasure:fCursorMeasure + withPitch:fCursorPitch accidental:&accidental]; + cursorElt = kMusicKillCursor; + break; + } NSPoint at = NSMakePoint(cursorX-kNoteX, cursorY); [[self musicElement:cursorElt] compositeToPoint:at operation: NSCompositeSourceOver]; - if (fCursorAccidental) { + if (fCursorAccidental && fCursorAccidental != kMusicExtendCursor) { at.y += kNoteY; switch (cursorElt= fCursorAccidental) { case kMusicFlatCursor: