diff --git a/Sources/VLPitchGrid.cpp b/Sources/VLPitchGrid.cpp new file mode 100644 index 0000000..157c2a6 --- /dev/null +++ b/Sources/VLPitchGrid.cpp @@ -0,0 +1,237 @@ +// +// File: VLPitchGrid.h - Translate between (MIDI) pitches and their vertical position +// +// Author(s): +// +// (MN) Matthias Neeracher +// +// Copyright © 2011 Matthias Neeracher +// + +#include "VLPitchGrid.h" +#include "VLModel.h" + +#define P(x) (1< 0 && HasSharp(semi, key)) + visual = 0; + goto computePosition; + } + } + // + // No visuals, or no match + // + visual = 0; + if (IsBasicNote(semi)) { + if (key < 0 ? HasFlat(semi, key) : key > 0 && HasSharp(semi, key)) + visual = VLNote::kWantNatural; + } else if (key < 0) { + semi += 1; + if (!HasFlat(semi, key)) + visual = VLNote::kWantFlat; + } else if (key > 0) { + semi -= 1; + if (!HasSharp(semi, key)) + visual = VLNote::kWantSharp; + } else { + semi += 1; + visual = VLNote::kWantFlat; + } +computePosition: + return SemiToStep(semi)+7*octave; +} + +int8_t VLGridToPitch(int gridPos, uint16_t visual, int key) +{ + int octave = VLNote::kMiddleC; + + while (gridPos > 6) { + octave += 12; + gridPos -= 7; + } + while (gridPos < 0) { + octave -= 12; + gridPos += 7; + } + int semi = StepToSemi(gridPos); + int accidental; + switch (visual) { + case VLNote::kWantFlat: + accidental = -1; + break; + case VLNote::kWant2Flat: + accidental = -2; + break; + case VLNote::kWantSharp: + accidental = 1; + break; + case VLNote::kWant2Sharp: + accidental = 2; + break; + case VLNote::kWantNatural: + accidental = 0; + break; + default: + if (key > 0 && HasSharp(semi, key)) + accidental = 1; + else if (key < 0 && HasFlat(semi, key)) + accidental = -1; + else + accidental = 0; + break; + } + return octave+semi+accidental; +} + +VLVisualFilter::VLVisualFilter(int key) +{ + memset(&fKeyState[0], 0, 7*sizeof(fKeyState[0])); + switch (key) { // Almost every state falls through + case -6: + fKeyState[0] = VLNote::kWantFlat; + case -5: + fKeyState[5] = VLNote::kWantFlat; + case -4: + fKeyState[1] = VLNote::kWantFlat; + case -3: + fKeyState[4] = VLNote::kWantFlat; + case -2: + fKeyState[2] = VLNote::kWantFlat; + case -1: + fKeyState[6] = VLNote::kWantFlat; + case 0: + break; + case 6: + fKeyState[2] = VLNote::kWantSharp; + case 5: + fKeyState[5] = VLNote::kWantSharp; + case 4: + fKeyState[1] = VLNote::kWantSharp; + case 3: + fKeyState[4] = VLNote::kWantSharp; + case 2: + fKeyState[0] = VLNote::kWantSharp; + case 1: + fKeyState[3] = VLNote::kWantSharp; + default: + break; + } + memcpy(fState, fKeyState, 7*sizeof(fKeyState[0])); +} + +uint16_t VLVisualFilter::operator()(int gridPos, uint16_t visual) +{ + gridPos %= 12; + if (!visual) + visual = fKeyState[gridPos]; + if (visual != fState[gridPos]) + if (!fState[gridPos] && visual == VLNote::kWantNatural) { + visual = 0; + } else { + if (!visual) + visual = VLNote::kWantNatural; + fState[gridPos] = visual==VLNote::kWantNatural ? 0 : visual; + } + else + visual = 0; + return visual; +} diff --git a/Sources/VLPitchGrid.h b/Sources/VLPitchGrid.h new file mode 100644 index 0000000..a96d1be --- /dev/null +++ b/Sources/VLPitchGrid.h @@ -0,0 +1,30 @@ +// +// File: VLPitchGrid.h - Translate between (MIDI) pitches and their vertical position +// +// Author(s): +// +// (MN) Matthias Neeracher +// +// Copyright © 2011 Matthias Neeracher +// + +#include + +// +// Grid position is defined from middle C +// +int VLPitchToGrid(int8_t pitch, uint16_t & visual, int key); +int8_t VLGridToPitch(int gridPos, uint16_t visual, int key); + +// +// Avoid repeating accidentals +// +class VLVisualFilter { +public: + VLVisualFilter(int key); + + uint16_t operator()(int gridPos, uint16_t visual); +private: + uint16_t fState[7]; + uint16_t fKeyState[7]; +}; \ No newline at end of file diff --git a/Sources/VLSheetView.h b/Sources/VLSheetView.h index 41d9f40..e204f9f 100644 --- a/Sources/VLSheetView.h +++ b/Sources/VLSheetView.h @@ -5,7 +5,7 @@ // // (MN) Matthias Neeracher // -// Copyright © 2005-2008 Matthias Neeracher +// Copyright © 2005-2011 Matthias Neeracher // #import @@ -115,10 +115,13 @@ enum VLRecalc { - (VLSong *) song; - (NSImage *) musicElement:(VLMusicElement)elt; -- (int) stepInSection:(int)section withPitch:(int)pitch visual:(int)visual; - (float) systemY:(int)system; -- (float) noteYInSection:(int)section withPitch:(int)pitch visual:(int)visual accidental:(VLMusicElement*)accidental; -- (float) noteYInMeasure:(int)measure withPitch:(int)pitch visual:(int)visual accidental:(VLMusicElement*)accidental; +- (int) gridInSection:(int)section withPitch:(int)pitch visual:(uint16_t)visual; +- (float) noteYInSection:(int)section withPitch:(int)pitch visual:(uint16_t *)visual; +- (float) noteYInSection:(int)section withPitch:(int)pitch; +- (VLMusicElement)accidentalForVisual:(uint16_t)visual; +- (float) noteYInMeasure:(int)measure withPitch:(int)pitch visual:(uint16_t *)visual; +- (float) noteYInMeasure:(int)measure withPitch:(int)pitch; - (float) noteXInMeasure:(int)measure at:(VLFraction)at; - (void) scrollMeasureToVisible:(int)measure; diff --git a/Sources/VLSheetView.mm b/Sources/VLSheetView.mm index a3fc30e..53891d5 100644 --- a/Sources/VLSheetView.mm +++ b/Sources/VLSheetView.mm @@ -17,6 +17,8 @@ #import "VLSoundOut.h" #import "VLGrooveController.h" +#import "VLPitchGrid.h" + #import "VLDocument.h" #include @@ -139,85 +141,60 @@ static float sFlatPos[] = { return kSystemBaseline+b.origin.y+b.size.height-(system+1)*kSystemH; } -int8_t sSemi2Pitch[4][12] = {{ - // C Db D Eb E F Gb G Ab A Bb B - 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, -},{ - // C C# D D# E F F# G G# A A# B - 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, -}}; - -#define S kMusicSharp, -#define F kMusicFlat, -#define N kMusicNatural, -#define _ kMusicNothing, - -VLMusicElement sSemi2Accidental[13][12] = { - // C DbD EbE F GbG AbA BbB - {N _ N _ N _ _ N _ N _ N}, // Gb major - 6 flats - {_ _ N _ N _ _ N _ N _ N}, // Db major - 5 flats - {_ _ N _ N _ F _ _ N _ N}, // Ab major - 4 flats - {_ F _ _ N _ F _ _ N _ N}, // Eb major - 3 flats - {_ F _ _ N _ F _ F _ _ N}, // Bb major - 2 flats - {_ F _ F _ _ F _ F _ _ N}, // F major - 1 flat - {_ F _ F _ _ F _ F _ F _}, // C major - // C C#D D#E F F#G G#A A#B - {_ S _ S _ N _ _ S _ S _}, // G major - 1 sharp - {N _ _ S _ N _ _ S _ S _}, // D major - 2 sharps - {N _ _ S _ N _ N _ _ S _}, // A major - 3 sharps - {N _ N _ _ N _ N _ _ S _}, // E major - 4 sharps - {N _ N _ _ N _ N _ N _ _}, // B major - 5 sharps - {N _ N _ N N _ N _ N _ _}, // F# major - 6 sharps -}; - -#undef S -#undef F -#undef N -#undef _ - -- (int) stepInSection:(int)section withPitch:(int)pitch visual:(int)visual +- (int) gridInSection:(int)section withPitch:(int)pitch visual:(uint16_t)visual { - int semi = pitch % 12; - int key = [self song]->fProperties[section].fKey; - bool useSharps = (visual & VLNote::kAccidentalsMask) - ? (visual & VLNote::kWantSharp) : (key > 0); - - return sSemi2Pitch[useSharps][semi]; + int key = [self song]->fProperties[section].fKey; + + return VLPitchToGrid(pitch, visual, key); } -- (float) noteYInSection:(int)section withPitch:(int)pitch - visual:(int)visual accidental:(VLMusicElement*)accidental +- (float) noteYInSection:(int)section withPitch:(int)pitch visual:(uint16_t *)visual { - int semi = pitch % 12; - int octave = (pitch / 12) - 5; - int key = [self song]->fProperties[section].fKey; + int key = [self song]->fProperties[section].fKey; + int grid = VLPitchToGrid(pitch, *visual, key); - switch (*accidental = sSemi2Accidental[key+6][semi]) { - case kMusicSharp: - if (visual & VLNote::kWantFlat) - *accidental = kMusicFlat; - break; - case kMusicFlat: - if (visual & VLNote::kWantSharp) - *accidental = kMusicSharp; - break; - default: - visual = 0; - break; - } - - return (octave*3.5f - + [self stepInSection:section withPitch:pitch visual:visual]*0.5f - - 1.0f - )* kLineH; + return (grid*0.5f - 1.0) * kLineH; } -- (float) noteYInMeasure:(int)measure withPitch:(int)pitch - visual:(int)visual accidental:(VLMusicElement*)accidental +- (float) noteYInSection:(int)section withPitch:(int)pitch +{ + int key = [self song]->fProperties[section].fKey; + uint16_t visual = 0; + int grid = VLPitchToGrid(pitch, visual, key); + + return (grid*0.5f - 1.0) * kLineH; +} + +- (VLMusicElement)accidentalForVisual:(uint16_t)visual +{ + switch (visual & VLNote::kAccidentalsMask) { + case VLNote::kWantSharp: + case VLNote::kWant2Sharp: // TODO + return kMusicSharp; + case VLNote::kWantFlat: + case VLNote::kWant2Flat: // TODO + return kMusicFlat; + case VLNote::kWantNatural: + return kMusicNatural; + default: + return kMusicNothing; + } +} + +- (float) noteYInMeasure:(int)measure withPitch:(int)pitch visual:(uint16_t *)visual { return [self systemY:fLayout->SystemForMeasure(measure)] + [self noteYInSection:[self song]->fMeasures[measure].fPropIdx - withPitch:pitch visual:visual accidental:accidental]; + withPitch:pitch visual:visual]; +} + +- (float) noteYInMeasure:(int)measure withPitch:(int)pitch +{ + uint16_t dummyVis = 0; + + return [self systemY:fLayout->SystemForMeasure(measure)] + + [self noteYInSection:[self song]->fMeasures[measure].fPropIdx + withPitch:pitch visual:&dummyVis]; } - (float) noteXInMeasure:(int)measure at:(VLFraction)at @@ -810,8 +787,10 @@ static int8_t sSharpAcc[] = { fCursorAccidental = kMusicSharpCursor; // G -> G# fCursorActualPitch = fCursorPitch+1; break; + case NSAlternateKeyMask|NSCommandKeyMask: + fCursorAccidental = kMusicNaturalCursor; + // Fall through default: - case NSAlternateKeyMask|NSCommandKeyMask: fCursorActualPitch = fCursorPitch; break; // G -> G } diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index 26eb832..77b65d4 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -13,6 +13,7 @@ #import "VLSheetViewInternal.h" #import "VLDocument.h" #import "VLSoundOut.h" +#import "VLPitchGrid.h" #include @@ -29,6 +30,9 @@ case kMusicSharpCursor: newNote.fVisual |= VLNote::kWantSharp; break; + case kMusicNaturalCursor: + newNote.fVisual |= VLNote::kWantNatural; + break; } [[self document] willChangeSong]; if (fCursorAccidental == kMusicExtendCursor) @@ -56,14 +60,10 @@ } } -- (void) drawLedgerLinesInSection:(int)section withPitch:(int)pitch visual:(int)visual at:(NSPoint)p +- (void) drawLedgerLinesInSection:(int)section withPitch:(int)pitch visual:(uint16_t)visual at:(NSPoint)p { - p.x += kLedgerX; - int octave = (pitch / 12) - 5; - int step = (octave*7 - + [self stepInSection:section withPitch:pitch visual:visual] - - 2 - ) / 2; + p.x += kLedgerX; + int step = ([self gridInSection:section withPitch:pitch visual:visual]-2)/2; for (int i=0; i-- > step; ) { NSPoint p0 = p; @@ -88,17 +88,12 @@ int cursorX; int cursorY; int cursorSect; - int cursorVisual = 0; - VLMusicElement acc; + uint16_t cursorVisual = 0; VLMusicElement cursorElt; cursorX = [self noteXInMeasure:measure at:at]; if (accidental == kMusicExtendCursor) { - cursorY = - [self noteYInMeasure:measure - withPitch:pitch - visual:0 - accidental:&acc]; + cursorY = [self noteYInMeasure:measure withPitch:pitch]; cursorElt = accidental; } else switch (mode) { @@ -110,10 +105,12 @@ case kMusicFlat: cursorVisual = VLNote::kWantFlat; break; + default: + break; } cursorY = [self noteYInMeasure:measure withPitch:pitch - visual:cursorVisual accidental:&acc] - kNoteY; + visual:&cursorVisual] - kNoteY; cursorSect = [self song]->fMeasures[measure].fPropIdx; [self drawLedgerLinesInSection:cursorSect withPitch:pitch visual:cursorVisual at:NSMakePoint(cursorX, @@ -121,14 +118,11 @@ cursorElt = kMusicNoteCursor; break; case 'r': - cursorY = [self noteYInMeasure:measure - withPitch:65 visual:0 accidental:&acc]; + cursorY = [self noteYInMeasure:measure withPitch:65]; cursorElt = kMusicRestCursor; break; case 'k': - cursorY = [self noteYInMeasure:measure - withPitch:pitch visual:0 - accidental:&acc]; + cursorY = [self noteYInMeasure:measure withPitch:pitch]; cursorElt = kMusicKillCursor; break; } @@ -219,6 +213,8 @@ at.x += kNaturalW; at.y += kNaturalY; break; + default: + break; } [[self musicElement:accidental] compositeToPoint:at operation: NSCompositeSourceOver]; @@ -349,8 +345,7 @@ bool hasTriplets = false; for (int m = 0; m= song->CountMeasures()) break; @@ -371,34 +366,21 @@ visual:note->fVisual at:NSMakePoint([self noteXInMeasure:measIdx at:at], kSystemY)]; - VLMusicElement accidental; - pos = NSMakePoint([self noteXInMeasure:measIdx at:at], - kSystemY+[self noteYInSection:measure.fPropIdx - withPitch:pitch - visual:note->fVisual - accidental:&accidental]); - VLMusicElement acc = accidental; - int step= [self stepInSection:measure.fPropIdx - withPitch:pitch - visual:note->fVisual]; - if (acc == accidentals[step]) - acc = kMusicNothing; // Don't repeat accidentals - else if (acc == kMusicNothing) - if (accidentals[step] == kMusicNatural) // Resume signature - acc = kProp.fKey < 0 ? kMusicFlat : kMusicSharp; - else - acc = kMusicNatural; + uint16_t visual = note->fVisual; + pos = + NSMakePoint([self noteXInMeasure:measIdx at:at], + kSystemY+[self noteYInSection:measure.fPropIdx + withPitch:pitch visual:&visual]); + int step = [self gridInSection:measure.fPropIdx + withPitch:pitch visual:note->fVisual]; [self drawNote:note->fVisual & VLNote::kNoteHeadMask at: pos - accidental: acc + accidental:[self accidentalForVisual:filterVisuals(step, visual)] tied:tied]; - accidentals[step] = accidental; } else { VLMusicElement accidental; pos = NSMakePoint([self noteXInMeasure:measIdx at:at], - kSystemY+[self noteYInSection:measure.fPropIdx - withPitch:65 visual:0 - accidental:&accidental]); + kSystemY+[self noteYInSection:measure.fPropIdx withPitch:65]); [self drawRest:note->fVisual & VLNote::kNoteHeadMask at: pos]; } if (note->fVisual & VLNote::kTriplet) { diff --git a/Tests/TVLPitchGrid/TVLPitchGrid-Info.plist b/Tests/TVLPitchGrid/TVLPitchGrid-Info.plist new file mode 100644 index 0000000..0e7509b --- /dev/null +++ b/Tests/TVLPitchGrid/TVLPitchGrid-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.aereperennius.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch b/Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch new file mode 100644 index 0000000..d6be813 --- /dev/null +++ b/Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'TVLPitchGrid' target in the 'TVLPitchGrid' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Tests/TVLPitchGrid/TVLPitchGrid.h b/Tests/TVLPitchGrid/TVLPitchGrid.h new file mode 100644 index 0000000..b14ef55 --- /dev/null +++ b/Tests/TVLPitchGrid/TVLPitchGrid.h @@ -0,0 +1,13 @@ +// +// TVLPitchGrid.h +// TVLPitchGrid +// +// Created by Matthias Neeracher on 8/28/11. +// Copyright 2011 Matthias Neeracher +// + +#import + +@interface TVLPitchGrid : SenTestCase + +@end diff --git a/Tests/TVLPitchGrid/TVLPitchGrid.mm b/Tests/TVLPitchGrid/TVLPitchGrid.mm new file mode 100644 index 0000000..793bf58 --- /dev/null +++ b/Tests/TVLPitchGrid/TVLPitchGrid.mm @@ -0,0 +1,116 @@ +// +// TVLPitchGrid.m +// TVLPitchGrid +// +// Created by Matthias Neeracher on 8/28/11. +// Copyright 2011 Matthias Neeracher +// + +#import "TVLPitchGrid.h" +#import "VLPitchGrid.h" +#import "VLModel.h" + +@implementation TVLPitchGrid + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + [super tearDown]; +} + +#define TestPitchToGrid(grid,visualOut,pitch,visualIn,key) \ + do { uint16_t vis = visualIn; \ + STAssertEquals(grid, VLPitchToGrid(pitch,vis,key),\ + @"VLPitchToGrid(%d,%02x,%d)", pitch, visualIn, key);\ + STAssertEquals((uint16_t)visualOut, vis,\ + @"VLPitchToGrid(%d,%02x,%d) [acc]", pitch, visualIn, key);\ + } while (0) + +- (void)testPitchToGrid +{ + TestPitchToGrid( 0, 0, 60, 0, 0); // Middle C, C Major + TestPitchToGrid( 0, VLNote::kWantNatural, 60, 0, 2); // Middle C, D Major + TestPitchToGrid( 0, 0, 60, 0, -5); // Middle C, Db Major + TestPitchToGrid( 0, VLNote::kWantNatural, 60, 0, -6); // Middle C, Gb Major + TestPitchToGrid( 0, 0, 60, VLNote::kWantNatural, 0); + TestPitchToGrid( -1, VLNote::kWantSharp, 60, VLNote::kWantSharp, 0); + TestPitchToGrid( 0, 0, 60, VLNote::kWantFlat, 0); + TestPitchToGrid( 0, VLNote::kWantNatural, 60, VLNote::kWantFlat, 2); + TestPitchToGrid( -1, VLNote::kWantSharp, 60, VLNote::kWant2Sharp, 0); + TestPitchToGrid( 1, VLNote::kWant2Flat, 60, VLNote::kWant2Flat, 0); + + TestPitchToGrid( 1, VLNote::kWantFlat, 61, 0, 0); // D flat, C Major + TestPitchToGrid( 1, VLNote::kWantFlat, 61, 0, -1); // D flat, F Major + TestPitchToGrid( 1, 0, 61, 0, -4); // D flat, Ab Major + TestPitchToGrid( 0, VLNote::kWantSharp, 61, 0, 1); // D flat, G Major + TestPitchToGrid( 0, 0, 61, 0, 2); // D flat, D Major + TestPitchToGrid( 1, VLNote::kWantFlat, 61, VLNote::kWantNatural, 0); + TestPitchToGrid( 0, VLNote::kWantSharp, 61, VLNote::kWantSharp, 0); + TestPitchToGrid( 0, 0, 61, VLNote::kWantSharp, 2); + TestPitchToGrid( 1, VLNote::kWantFlat, 61, VLNote::kWantFlat, 0); + TestPitchToGrid( 1, 0, 61, VLNote::kWantFlat, -4); + TestPitchToGrid( -1, VLNote::kWant2Sharp, 61, VLNote::kWant2Sharp, 0); + TestPitchToGrid( 1, VLNote::kWantFlat, 61, VLNote::kWant2Flat, 0); + + TestPitchToGrid( 1, 0, 62, 0, 0); // D, C Major + TestPitchToGrid( 1, 0, 62, VLNote::kWantNatural, 0); + TestPitchToGrid( 1, 0, 62, VLNote::kWantSharp, 0); + TestPitchToGrid( 1, 0, 62, VLNote::kWantFlat, 0); + TestPitchToGrid( 0, VLNote::kWant2Sharp, 62, VLNote::kWant2Sharp, 0); + TestPitchToGrid( 2, VLNote::kWant2Flat, 62, VLNote::kWant2Flat, 0); + + TestPitchToGrid( 6, 0, 71, 0, 0); // B, C Major + TestPitchToGrid( 6, 0, 71, VLNote::kWantNatural, 0); + TestPitchToGrid( 6, 0, 71, VLNote::kWantSharp, 0); + TestPitchToGrid( 7, VLNote::kWantFlat, 71, VLNote::kWantFlat, 0); + TestPitchToGrid( 5, VLNote::kWant2Sharp, 71, VLNote::kWant2Sharp, 0); + TestPitchToGrid( 7, VLNote::kWantFlat, 71, VLNote::kWant2Flat, 0); + + TestPitchToGrid( 7, 0, 72, 0, 0); // Octaves + TestPitchToGrid( 14, 0, 84, 0, 0); + TestPitchToGrid( -7, 0, 48, 0, 0); +} + +#define TestGridToPitch(pitch,grid,visualIn,key) \ + do { uint16_t vis = visualIn; \ + STAssertEquals(pitch, (int)VLGridToPitch(grid,vis,key),\ + @"VLGridToPitch(%d,%02x,%d)", grid, visualIn, key);\ + } while (0) + +- (void)testGridToPitch +{ + TestGridToPitch(60, 0, 0, 0); + TestGridToPitch(60, 0, VLNote::kWantNatural, 0); + TestGridToPitch(61, 0, 0, 2); + TestGridToPitch(60, 0, VLNote::kWantNatural, 2); + TestGridToPitch(59, 0, 0, -6); + TestGridToPitch(60, 0, VLNote::kWantNatural, -6); + TestGridToPitch(61, 0, VLNote::kWantSharp, 0); + TestGridToPitch(59, 0, VLNote::kWantFlat, 0); + TestGridToPitch(62, 0, VLNote::kWant2Sharp, 0); + TestGridToPitch(58, 0, VLNote::kWant2Flat, 0); + TestGridToPitch(48, -7, 0, 0); + TestGridToPitch(72, 7, 0, 0); +} + +#define TestVisualFilter(visualOut, grid, visualIn, filter) \ + STAssertEquals((uint16_t)visualOut, filter(grid, visualIn), \ + @"VLVisualFilter(%d,%02x)", grid, visualIn); + +- (void)testVisualFilter +{ + VLVisualFilter filterBbMajor(-2); + + TestVisualFilter(0, 0, 0, filterBbMajor); + TestVisualFilter(VLNote::kWantFlat, 0, VLNote::kWantFlat, filterBbMajor); + TestVisualFilter(VLNote::kWantNatural, 0, 0, filterBbMajor); + TestVisualFilter(VLNote::kWantSharp, 0, VLNote::kWantSharp, filterBbMajor); + TestVisualFilter(0, 2, VLNote::kWantFlat, filterBbMajor); + TestVisualFilter(VLNote::kWantSharp, 2, VLNote::kWantSharp, filterBbMajor); + TestVisualFilter(VLNote::kWantFlat, 2, 0, filterBbMajor); +} +@end diff --git a/Tests/TVLPitchGrid/en.lproj/InfoPlist.strings b/Tests/TVLPitchGrid/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Tests/TVLPitchGrid/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/VocalEasel.xcodeproj/project.pbxproj b/VocalEasel.xcodeproj/project.pbxproj index 64268c2..0faa409 100644 --- a/VocalEasel.xcodeproj/project.pbxproj +++ b/VocalEasel.xcodeproj/project.pbxproj @@ -40,6 +40,13 @@ 9531F3520DE2B4CD004F78C2 /* VLMP3Document.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9531F3500DE2B4CD004F78C2 /* VLMP3Document.mm */; }; 9531F3670DE2B872004F78C2 /* lameWrapper in Copy Tools */ = {isa = PBXBuildFile; fileRef = 9531F3660DE2B872004F78C2 /* lameWrapper */; }; 953722670AE9F0E100B6E483 /* VLLilypondDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 953722660AE9F0E100B6E483 /* VLLilypondDocument.mm */; }; + 953F4B3D1409B01200C627F9 /* VLPitchGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 953F4B3C1409B01200C627F9 /* VLPitchGrid.cpp */; }; + 953F4B441409C42100C627F9 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95CFA8481409291500D0DB0D /* SenTestingKit.framework */; }; + 953F4B451409C42100C627F9 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95AC6FFF14094107007EA050 /* Cocoa.framework */; }; + 953F4B4F1409C42100C627F9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 953F4B4D1409C42100C627F9 /* InfoPlist.strings */; }; + 953F4B511409C42100C627F9 /* TVLPitchGrid.h in Resources */ = {isa = PBXBuildFile; fileRef = 953F4B501409C42100C627F9 /* TVLPitchGrid.h */; }; + 953F4B531409C42100C627F9 /* TVLPitchGrid.mm in Sources */ = {isa = PBXBuildFile; fileRef = 953F4B521409C42100C627F9 /* TVLPitchGrid.mm */; }; + 953F4B591409C54600C627F9 /* VLPitchGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 953F4B3C1409B01200C627F9 /* VLPitchGrid.cpp */; }; 9545C5C30C092F4600251547 /* VLMMAWriter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9545C5C10C092F4600251547 /* VLMMAWriter.cpp */; }; 95498DBD0AE3812F006B5F81 /* VLSoundSched.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95498DBC0AE3812F006B5F81 /* VLSoundSched.mm */; }; 954BBD860AEDDE5300BBFD5F /* VLAppController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 954BBD850AEDDE5300BBFD5F /* VLAppController.mm */; }; @@ -210,6 +217,17 @@ 9531F3660DE2B872004F78C2 /* lameWrapper */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = lameWrapper; path = Tools/lameWrapper; sourceTree = ""; }; 953722650AE9F0E100B6E483 /* VLLilypondDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLLilypondDocument.h; path = Sources/VLLilypondDocument.h; sourceTree = ""; }; 953722660AE9F0E100B6E483 /* VLLilypondDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLLilypondDocument.mm; path = Sources/VLLilypondDocument.mm; sourceTree = ""; }; + 953F4B3A1409AFFA00C627F9 /* VLPitchGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLPitchGrid.h; path = Sources/VLPitchGrid.h; sourceTree = ""; }; + 953F4B3C1409B01200C627F9 /* VLPitchGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VLPitchGrid.cpp; path = Sources/VLPitchGrid.cpp; sourceTree = ""; }; + 953F4B431409C42100C627F9 /* TVLPitchGrid.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TVLPitchGrid.octest; sourceTree = BUILT_PRODUCTS_DIR; }; + 953F4B471409C42100C627F9 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; + 953F4B481409C42100C627F9 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 953F4B491409C42100C627F9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 953F4B4C1409C42100C627F9 /* TVLPitchGrid-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "TVLPitchGrid-Info.plist"; path = "Tests/TVLPitchGrid/TVLPitchGrid-Info.plist"; sourceTree = SOURCE_ROOT; }; + 953F4B4E1409C42100C627F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 953F4B501409C42100C627F9 /* TVLPitchGrid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TVLPitchGrid.h; path = Tests/TVLPitchGrid/TVLPitchGrid.h; sourceTree = SOURCE_ROOT; }; + 953F4B521409C42100C627F9 /* TVLPitchGrid.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = TVLPitchGrid.mm; path = Tests/TVLPitchGrid/TVLPitchGrid.mm; sourceTree = SOURCE_ROOT; }; + 953F4B541409C42100C627F9 /* TVLPitchGrid-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "TVLPitchGrid-Prefix.pch"; path = "Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch"; sourceTree = SOURCE_ROOT; }; 9545C5C10C092F4600251547 /* VLMMAWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = VLMMAWriter.cpp; path = Sources/VLMMAWriter.cpp; sourceTree = ""; }; 9545C5C20C092F4600251547 /* VLMMAWriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLMMAWriter.h; path = Sources/VLMMAWriter.h; sourceTree = ""; }; 95498DBB0AE3812F006B5F81 /* VLSoundSched.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLSoundSched.h; path = Sources/VLSoundSched.h; sourceTree = ""; }; @@ -334,6 +352,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 953F4B3F1409C42100C627F9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 953F4B441409C42100C627F9 /* SenTestingKit.framework in Frameworks */, + 953F4B451409C42100C627F9 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 955E595A0957C0FC0045FDA5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -376,6 +403,7 @@ 959408A0096922CA007CCCF8 /* TVLEdit */, 95E04DA00AEB4837006F30A0 /* TVLLilypond */, 95CFA8471409291500D0DB0D /* TVLPitchNames.octest */, + 953F4B431409C42100C627F9 /* TVLPitchGrid.octest */, ); name = Products; sourceTree = ""; @@ -464,10 +492,41 @@ 95AC700314099C64007EA050 /* AudioUnit.framework */, 95AC700614099CF0007EA050 /* Quartz.framework */, 95CFA8481409291500D0DB0D /* SenTestingKit.framework */, + 953F4B461409C42100C627F9 /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; + 953F4B461409C42100C627F9 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 953F4B471409C42100C627F9 /* AppKit.framework */, + 953F4B481409C42100C627F9 /* CoreData.framework */, + 953F4B491409C42100C627F9 /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 953F4B4A1409C42100C627F9 /* TVLPitchGrid */ = { + isa = PBXGroup; + children = ( + 953F4B501409C42100C627F9 /* TVLPitchGrid.h */, + 953F4B521409C42100C627F9 /* TVLPitchGrid.mm */, + 953F4B4B1409C42100C627F9 /* Supporting Files */, + ); + path = TVLPitchGrid; + sourceTree = ""; + }; + 953F4B4B1409C42100C627F9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 953F4B4C1409C42100C627F9 /* TVLPitchGrid-Info.plist */, + 953F4B4D1409C42100C627F9 /* InfoPlist.strings */, + 953F4B541409C42100C627F9 /* TVLPitchGrid-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; 9546A1090B08B47A0028503B /* CoreAudio SDK Sources */ = { isa = PBXGroup; children = ( @@ -488,6 +547,7 @@ 955E59560957C0C50045FDA5 /* Tests */ = { isa = PBXGroup; children = ( + 953F4B4A1409C42100C627F9 /* TVLPitchGrid */, 95CFA84C1409291500D0DB0D /* TVLPitchNames */, 95E04DA60AEB486E006F30A0 /* TVLLilypond.mm */, 959408AC096922EA007CCCF8 /* TVLEdit.cpp */, @@ -528,6 +588,8 @@ 955E58E4095658AB0045FDA5 /* VLModel.cpp */, 95CFA83914091B9000D0DB0D /* VLPitchName.h */, 95CFA83714091B7800D0DB0D /* VLPitchName.cpp */, + 953F4B3A1409AFFA00C627F9 /* VLPitchGrid.h */, + 953F4B3C1409B01200C627F9 /* VLPitchGrid.cpp */, 959A3A6D0DE8CB5B00EF207B /* VLMIDIWriter.h */, 959A3A6C0DE8CB5B00EF207B /* VLMIDIWriter.cpp */, 9531F34D0DE2B4CD004F78C2 /* VLAIFFDocument.h */, @@ -696,6 +758,24 @@ productReference = 952CBB98095FD19D00434E43 /* TVLSoundOut */; productType = "com.apple.product-type.tool"; }; + 953F4B421409C42100C627F9 /* TVLPitchGrid */ = { + isa = PBXNativeTarget; + buildConfigurationList = 953F4B551409C42100C627F9 /* Build configuration list for PBXNativeTarget "TVLPitchGrid" */; + buildPhases = ( + 953F4B3E1409C42100C627F9 /* Sources */, + 953F4B3F1409C42100C627F9 /* Frameworks */, + 953F4B401409C42100C627F9 /* Resources */, + 953F4B411409C42100C627F9 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TVLPitchGrid; + productName = TVLPitchGrid; + productReference = 953F4B431409C42100C627F9 /* TVLPitchGrid.octest */; + productType = "com.apple.product-type.bundle"; + }; 955E595B0957C0FC0045FDA5 /* TVLChord */ = { isa = PBXNativeTarget; buildConfigurationList = 95D7BF7C0AA699C600D5E02C /* Build configuration list for PBXNativeTarget "TVLChord" */; @@ -791,6 +871,7 @@ 9594089F096922CA007CCCF8 /* TVLEdit */, 95E04D9F0AEB4837006F30A0 /* TVLLilypond */, 95CFA8461409291500D0DB0D /* TVLPitchNames */, + 953F4B421409C42100C627F9 /* TVLPitchGrid */, ); }; /* End PBXProject section */ @@ -832,6 +913,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 953F4B401409C42100C627F9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 953F4B4F1409C42100C627F9 /* InfoPlist.strings in Resources */, + 953F4B511409C42100C627F9 /* TVLPitchGrid.h in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 95CFA8441409291500D0DB0D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -844,6 +934,19 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 953F4B411409C42100C627F9 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; + }; 95C462020B04475300649F92 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -914,6 +1017,7 @@ 9531F3520DE2B4CD004F78C2 /* VLMP3Document.mm in Sources */, 959A3A6E0DE8CB5B00EF207B /* VLMIDIWriter.cpp in Sources */, 95CFA83814091B7800D0DB0D /* VLPitchName.cpp in Sources */, + 953F4B3D1409B01200C627F9 /* VLPitchGrid.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -931,6 +1035,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 953F4B3E1409C42100C627F9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 953F4B531409C42100C627F9 /* TVLPitchGrid.mm in Sources */, + 953F4B591409C54600C627F9 /* VLPitchGrid.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 955E59590957C0FC0045FDA5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1038,6 +1151,15 @@ name = VLPDFWindow.xib; sourceTree = ""; }; + 953F4B4D1409C42100C627F9 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 953F4B4E1409C42100C627F9 /* en */, + ); + name = InfoPlist.strings; + path = Tests/TVLPitchGrid; + sourceTree = SOURCE_ROOT; + }; 95CFA84F1409291500D0DB0D /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( @@ -1050,6 +1172,88 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 953F4B561409C42100C627F9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "Tests/TVLPitchGrid/TVLPitchGrid-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + WRAPPER_EXTENSION = octest; + }; + name = Development; + }; + 953F4B571409C42100C627F9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "Tests/TVLPitchGrid/TVLPitchGrid-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + WRAPPER_EXTENSION = octest; + }; + name = Deployment; + }; + 953F4B581409C42100C627F9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Tests/TVLPitchGrid/TVLPitchGrid-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "Tests/TVLPitchGrid/TVLPitchGrid-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + WRAPPER_EXTENSION = octest; + }; + name = Default; + }; 95CFA8581409291500D0DB0D /* Development */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1473,6 +1677,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 953F4B551409C42100C627F9 /* Build configuration list for PBXNativeTarget "TVLPitchGrid" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 953F4B561409C42100C627F9 /* Development */, + 953F4B571409C42100C627F9 /* Deployment */, + 953F4B581409C42100C627F9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + }; 95CFA8571409291500D0DB0D /* Build configuration list for PBXNativeTarget "TVLPitchNames" */ = { isa = XCConfigurationList; buildConfigurations = (