Factor out VLPitchGrid, unit tests and code work

This commit is contained in:
Matthias Neeracher 2011-08-28 04:57:49 +02:00
parent d6ce6acd27
commit 9233e42cfc
11 changed files with 722 additions and 118 deletions

237
Sources/VLPitchGrid.cpp Normal file
View File

@ -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<<x)
static inline bool IsBasicNote(int semi)
{
//
// Bitmap of basic notes, padded left and right by two positions
// B C D E F G A B C
const uint16_t kBasicNotes = P( 1)|P( 2)|P( 4)|P( 6)|P( 7)|P( 9)|P(11)|P(13)|P(14);
return kBasicNotes & (1<<(semi+2));
}
static inline bool HasFlat(int semi, int key)
{
const uint16_t kFMajor = P(1) | P(13); // Bb
const uint16_t kBbMajor = kFMajor | P(6); // Eb
const uint16_t kEbMajor = kBbMajor | P(11); // Ab
const uint16_t kAbMajor = kEbMajor | P(4); // Db
const uint16_t kDbMajor = kAbMajor | P(9); // Gb
const uint16_t kGbMajor = kDbMajor | P(2) | P(14); // Cb
static const uint16_t sFlats[] =
{kFMajor, kBbMajor, kEbMajor, kAbMajor, kDbMajor, kGbMajor};
return sFlats[-1-key] & (1<<(semi+2));
}
static inline bool HasSharp(int semi, int key)
{
const uint16_t kGMajor = P(7); // F#
const uint16_t kDMajor = kGMajor | P(2) | P(14); // C#
const uint16_t kAMajor = kDMajor | P(9); // G#
const uint16_t kEMajor = kAMajor | P(4); // D#
const uint16_t kBMajor = kEMajor | P(11); // A#
const uint16_t kFsMajor = kBMajor | P(6); // E#
static const uint16_t sSharps[] =
{kGMajor, kDMajor, kAMajor, kEMajor, kBMajor, kFsMajor};
return sSharps[key-1] & (1<<(semi+2));
}
static inline int8_t SemiToStep(int semi)
{
static const int8_t sSteps[] =
// Bb B C D E F G A B C
{-1,-1,0,0,1,1,2,3,3,4,4,5,5,6,7,7};
return sSteps[semi+2];
}
static inline int8_t StepToSemi(int step)
{
// C D E F G A B
static const int8_t sSemi[] = {0,2,4,5,7,9,11};
return sSemi[step];
}
int VLPitchToGrid(int8_t pitch, uint16_t & visual, int key)
{
int semi = pitch % 12;
int octave = (pitch/12)-5;
if ((visual &= VLNote::kAccidentalsMask)) {
//
// The user expressed a preference, try to match it
//
switch (visual) {
case VLNote::kWantNatural:
if (!IsBasicNote(semi))
break;
visual = 0; // Don't draw naturals unless needed
goto computePosition;
case VLNote::kWant2Flat:
if (IsBasicNote(semi+2)) {
semi += 2;
goto computePosition;
}
visual = VLNote::kWantFlat;
goto flatIsPossible;
case VLNote::kWantFlat:
if (!IsBasicNote(semi+1))
break;
flatIsPossible:
semi += 1;
if (key < 0 && HasFlat(semi, key))
visual = 0;
goto computePosition;
case VLNote::kWant2Sharp:
if (IsBasicNote(semi-2)) {
semi -= 2;
goto computePosition;
}
visual = VLNote::kWantSharp;
goto sharpIsPossible;
case VLNote::kWantSharp:
if (!IsBasicNote(semi-1))
break;
sharpIsPossible:
semi -= 1;
if (key > 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;
}

30
Sources/VLPitchGrid.h Normal file
View File

@ -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 <inttypes.h>
//
// 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];
};

View File

@ -5,7 +5,7 @@
//
// (MN) Matthias Neeracher
//
// Copyright © 2005-2008 Matthias Neeracher
// Copyright © 2005-2011 Matthias Neeracher
//
#import <Cocoa/Cocoa.h>
@ -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;

View File

@ -17,6 +17,8 @@
#import "VLSoundOut.h"
#import "VLGrooveController.h"
#import "VLPitchGrid.h"
#import "VLDocument.h"
#include <cmath>
@ -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
}

View File

@ -13,6 +13,7 @@
#import "VLSheetViewInternal.h"
#import "VLDocument.h"
#import "VLSoundOut.h"
#import "VLPitchGrid.h"
#include <algorithm>
@ -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<kLayout.NumMeasures(); ++m) {
VLMusicElement accidentals[7];
memset(accidentals, 0, 7*sizeof(VLMusicElement));
VLVisualFilter filterVisuals(kProp.fKey);
int measIdx = m+kFirstMeas;
if (measIdx >= 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) {

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>org.aereperennius.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,7 @@
//
// Prefix header for all source files of the 'TVLPitchGrid' target in the 'TVLPitchGrid' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@ -0,0 +1,13 @@
//
// TVLPitchGrid.h
// TVLPitchGrid
//
// Created by Matthias Neeracher on 8/28/11.
// Copyright 2011 Matthias Neeracher
//
#import <SenTestingKit/SenTestingKit.h>
@interface TVLPitchGrid : SenTestCase
@end

View File

@ -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

View File

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

View File

@ -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 = "<group>"; };
953722650AE9F0E100B6E483 /* VLLilypondDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLLilypondDocument.h; path = Sources/VLLilypondDocument.h; sourceTree = "<group>"; };
953722660AE9F0E100B6E483 /* VLLilypondDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLLilypondDocument.mm; path = Sources/VLLilypondDocument.mm; sourceTree = "<group>"; };
953F4B3A1409AFFA00C627F9 /* VLPitchGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLPitchGrid.h; path = Sources/VLPitchGrid.h; sourceTree = "<group>"; };
953F4B3C1409B01200C627F9 /* VLPitchGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VLPitchGrid.cpp; path = Sources/VLPitchGrid.cpp; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
9545C5C20C092F4600251547 /* VLMMAWriter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLMMAWriter.h; path = Sources/VLMMAWriter.h; sourceTree = "<group>"; };
95498DBB0AE3812F006B5F81 /* VLSoundSched.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLSoundSched.h; path = Sources/VLSoundSched.h; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -464,10 +492,41 @@
95AC700314099C64007EA050 /* AudioUnit.framework */,
95AC700614099CF0007EA050 /* Quartz.framework */,
95CFA8481409291500D0DB0D /* SenTestingKit.framework */,
953F4B461409C42100C627F9 /* Other Frameworks */,
);
name = Frameworks;
sourceTree = "<group>";
};
953F4B461409C42100C627F9 /* Other Frameworks */ = {
isa = PBXGroup;
children = (
953F4B471409C42100C627F9 /* AppKit.framework */,
953F4B481409C42100C627F9 /* CoreData.framework */,
953F4B491409C42100C627F9 /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "<group>";
};
953F4B4A1409C42100C627F9 /* TVLPitchGrid */ = {
isa = PBXGroup;
children = (
953F4B501409C42100C627F9 /* TVLPitchGrid.h */,
953F4B521409C42100C627F9 /* TVLPitchGrid.mm */,
953F4B4B1409C42100C627F9 /* Supporting Files */,
);
path = TVLPitchGrid;
sourceTree = "<group>";
};
953F4B4B1409C42100C627F9 /* Supporting Files */ = {
isa = PBXGroup;
children = (
953F4B4C1409C42100C627F9 /* TVLPitchGrid-Info.plist */,
953F4B4D1409C42100C627F9 /* InfoPlist.strings */,
953F4B541409C42100C627F9 /* TVLPitchGrid-Prefix.pch */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
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 = "<group>";
};
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 = (