diff --git a/Sources/VLModel.cpp b/Sources/VLModel.cpp index d8755a5..3dc3fa6 100644 --- a/Sources/VLModel.cpp +++ b/Sources/VLModel.cpp @@ -541,3 +541,53 @@ void VLSong::DelNote(size_t measure, VLFraction at) } } +static void TransposePinned(int8_t & pitch, int semi) +{ + if (pitch == VLNote::kNoPitch) + return; + + int pitchInOctave = pitch % 12; + int octave = pitch-pitchInOctave; + pitchInOctave += semi; + if (pitchInOctave < 0) + pitch = octave+pitchInOctave+12; + else if (pitchInOctave > 11) + pitch = octave+pitchInOctave-12; + else + pitch = octave+pitchInOctave; +} + +void VLSong::Transpose(int semi) +{ + for (int pass=0; pass<2 && semi;) { + int8_t low = 127; + int8_t high = 0; + for (int measure=0; measurefPitch == VLNote::kNoPitch) + continue; + i->fPitch += semi; + low = std::min(low, i->fPitch); + high = std::max(high, i->fPitch); + } + } + if (low < VLNote::kMiddleC-6 && high < VLNote::kMiddleC+7) + semi += 12; // Transpose an Octave up + else if (low > VLNote::kMiddleC+7 && high > VLNote::kMiddleC+16) + semi -= 12; // Transpose an Octave down + else + break; // Looks like we're done + } + for (int measure=0; measurefPitch, semi); + TransposePinned(i->fRootPitch, semi); + } + } +} diff --git a/Sources/VLModel.h b/Sources/VLModel.h index 9b50e7f..efbe9c0 100644 --- a/Sources/VLModel.h +++ b/Sources/VLModel.h @@ -217,6 +217,7 @@ struct VLSong { void AddNote(VLNote note, size_t measure, VLFraction at); void DelChord(size_t measure, VLFraction at); void DelNote(size_t measure, VLFraction at); + void Transpose(int semitones); size_t CountMeasures() const { return fMeasures.size(); } }; diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index c6cf69e..73ed4d0 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -345,8 +345,24 @@ static float sFlatPos[] = { - (IBAction) setKey:(id)sender { + [[NSAlert alertWithMessageText:@"Transpose Song?" + defaultButton:@"Transpose" + alternateButton:@"Cancel" + otherButton:@"Change Key" + informativeTextWithFormat: + @"Do you want to transpose the song into the new key?"] + beginSheetModalForWindow:[self window] + modalDelegate:self didEndSelector:@selector(setKey:returnCode:contextInfo:) + contextInfo:sender]; +} + +- (void)setKey:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(id)sender +{ + if (returnCode == NSAlertAlternateReturn) + return; + int key = [[sender selectedItem] tag]; - [[self document] setKey: key transpose: YES]; + [[self document] setKey:key transpose:returnCode==NSAlertDefaultReturn]; fNeedsRecalc = kRecalc; [self setNeedsDisplay: YES]; }