diff --git a/Sources/VLModel.cpp b/Sources/VLModel.cpp index 1926ed1..415874b 100644 --- a/Sources/VLModel.cpp +++ b/Sources/VLModel.cpp @@ -601,6 +601,88 @@ void VLSong::DelChord(VLLocation at) fMeasures.pop_back(); } +VLLyricsNote VLSong::FindNote(VLLocation at) +{ + VLNoteList::iterator i = fMeasures[at.fMeasure].fMelody.begin(); + VLFraction t(0); + + for (;;) { + VLFraction tEnd = t+i->fDuration; + if (tEnd > at.fAt) + return *i; + t = tEnd; + ++i; + } + return ++at.fMeasure < fMeasures.size() + ? fMeasures[at.fMeasure].fMelody.front() : VLLyricsNote(); +} + +bool VLSong::PrevNote(VLLocation &at) +{ + uint32_t meas = at.fMeasure; + VLFraction where = at.fAt; + for (;;) { + bool found = false; + VLNoteList::iterator i = fMeasures[meas].fMelody.begin(); + VLNoteList::iterator end = fMeasures[meas].fMelody.end(); + VLFraction t(0); + VLFraction prevAt(0); + while (i != end) { + VLFraction tEnd = t+i->fDuration; + if (tEnd > where) + break; + if (i->fPitch != VLNote::kNoPitch && !(i->fTied & VLNote::kTiedWithPrev)) { + prevAt = t; + found = true; + } + t = tEnd; + ++i; + } + if (found) { + at.fMeasure = meas; + at.fAt = prevAt; + + return true; + } + if (!meas--) + break; + where = VLFraction(1000); + } + return false; +} + +bool VLSong::NextNote(VLLocation &at) +{ + uint32_t meas = at.fMeasure; + VLFraction where = at.fAt; + bool first = false; + for (;;) { + VLNoteList::iterator i = fMeasures[meas].fMelody.begin(); + VLNoteList::iterator end = fMeasures[meas].fMelody.end(); + VLFraction t(0); + while (i != end) { + VLFraction tEnd = t+i->fDuration; + if ((t > where || first) && i->fPitch != VLNote::kNoPitch + && !(i->fTied & VLNote::kTiedWithPrev) + ) { + at.fMeasure = meas; + at.fAt = t; + + return true; + } + first = false; + t = tEnd; + ++i; + } + if (++meas < fMeasures.size()) { + where = VLFraction(0); + first = true; + } else + break; + } + return false; +} + static uint8_t & FirstTie(VLMeasure & measure) { VLNoteList::iterator i = measure.fMelody.begin(); diff --git a/Sources/VLModel.h b/Sources/VLModel.h index f12f695..e9cc72c 100644 --- a/Sources/VLModel.h +++ b/Sources/VLModel.h @@ -420,6 +420,9 @@ public: iterator begin() { return iterator(*this, false); } iterator end() { return iterator(*this, true); } + VLLyricsNote FindNote(VLLocation at); + bool PrevNote(VLLocation & at); + bool NextNote(VLLocation & at); void AddChord(VLChord chord, VLLocation at); void AddNote(VLLyricsNote note, VLLocation at); void DelChord(VLLocation at); diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index 102335d..21aad1a 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -896,6 +896,15 @@ const float kSemiFloor = -1.0f*kLineH; fClickMode = 'k'; [self setNeedsDisplay:YES]; break; + case '?': + [self playNoteAtCursor]; + break; + case 0xF702: // Left arrow + [self moveCursorToPrevNote]; + break; + case 0xF703: // Right arrow + [self moveCursorToNextNote]; + break; } } diff --git a/Sources/VLSheetViewNotes.h b/Sources/VLSheetViewNotes.h index 6924c66..7eb881e 100644 --- a/Sources/VLSheetViewNotes.h +++ b/Sources/VLSheetViewNotes.h @@ -15,6 +15,9 @@ - (void) drawNotesForSystem:(int)system; - (void) addNoteAtCursor; - (void) drawNoteCursor:(int)vertPos at:(VLLocation)at visual:(uint16_t)visual; +- (void) playNoteAtCursor; +- (void) moveCursorToNextNote; +- (void) moveCursorToPrevNote; @end diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index ca3e2d5..76522ad 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -43,6 +43,32 @@ } } +- (void) playNoteAtCursor +{ + VLNote note = [self song]->FindNote(fCursorLocation); + if (note.fPitch != VLNote::kNoPitch) { + fCursorRegion = kRegionNote; + int section = [self song]->fMeasures[fCursorLocation.fMeasure].fPropIdx; + fCursorVertPos = [self gridInSection:section withPitch:note.fPitch visual:note.fVisual]; + fCursorVisual = note.fVisual & VLNote::kAccidentalsMask; + [self setNeedsDisplay:YES]; + + VLSoundOut::Instance()->PlayNote(note); + } +} + +- (void) moveCursorToNextNote +{ + if ([self song]->NextNote(fCursorLocation)) + [self playNoteAtCursor]; +} + +- (void) moveCursorToPrevNote +{ + if ([self song]->PrevNote(fCursorLocation)) + [self playNoteAtCursor]; +} + - (void) drawLedgerLines:(int)vertPos at:(NSPoint)p { p.x += kLedgerX;