From fe55af3f7c413f62d27657dad399181fa14e977a Mon Sep 17 00:00:00 2001 From: Matthias Neeracher Date: Sat, 14 Oct 2006 10:10:19 +0000 Subject: [PATCH] Implemen loading, update management --- English.lproj/VLDocument.nib/classes.nib | 2 +- English.lproj/VLDocument.nib/info.nib | 2 +- English.lproj/VLDocument.nib/keyedobjects.nib | Bin 14713 -> 14718 bytes Resources/Info.plist | 4 +- Sources/VLDocument.mm | 35 ++---- Sources/VLSheetViewChords.mm | 1 + Sources/VLSheetViewNotes.mm | 1 + Sources/VLXMLDocument.mm | 109 +++++++++++++++++- 8 files changed, 125 insertions(+), 29 deletions(-) diff --git a/English.lproj/VLDocument.nib/classes.nib b/English.lproj/VLDocument.nib/classes.nib index ea32267..28b8ef2 100644 --- a/English.lproj/VLDocument.nib/classes.nib +++ b/English.lproj/VLDocument.nib/classes.nib @@ -1,8 +1,8 @@ { IBClasses = ( {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, - {CLASS = MyDocument; LANGUAGE = ObjC; SUPERCLASS = NSDocument; }, {CLASS = VLDocument; LANGUAGE = ObjC; SUPERCLASS = NSDocument; }, + {CLASS = VLEditable; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = {hideFieldEditor = id; setDivisions = id; setKey = id; setTime = id; }; CLASS = VLSheetView; diff --git a/English.lproj/VLDocument.nib/info.nib b/English.lproj/VLDocument.nib/info.nib index 470d47e..fa0cb16 100644 --- a/English.lproj/VLDocument.nib/info.nib +++ b/English.lproj/VLDocument.nib/info.nib @@ -11,6 +11,6 @@ 5 IBSystem Version - 9A274 + 9A283 diff --git a/English.lproj/VLDocument.nib/keyedobjects.nib b/English.lproj/VLDocument.nib/keyedobjects.nib index 61dcccba9ae9fa488850ba74b3425d6bc282dc47..4191aa7bb3fbf335a83da21dfd2b0c743a053913 100644 GIT binary patch delta 5065 zcmZuz33wCL_Mb`aOp-|^b0?X}KG`Noo0-eLS13?u*~?l=*_Re%DO+2hY?&#t2m*zG ziYv%N>>ornd2ALCmA`_5Ae*Sj1Jvh&Y>J@3o220P^n1DA&D?wL$vx-%&hO00-Kh_z zRy*|d$p+ip5AXy5C}0Lo-~w*o0U<02L=XdU&`6Us22DT+v;yt5bq?sDt-FAH&=d3n zgTW|J3`)RgFb0eTNpDc9o%F^klC?Tlw(cw9 zN8%^q8u2r6owz~VByJJ6iC>6ci95t^#9iVZ@jLMcai4fVJR~s^Cv~Kr1SCO{qyhVg zG$ws|UqpXEw}y0*F49eUNH2Db^pOJTCj(@V43S|nN@kMsj(++TI9{Fn23!#@D_50k z%5CMI@`s8WRNSQEW)-JZoKbPRit{S&+wmjO-5b^4*SEml0GRSGrA8T}TpCbTQr>TD zX-U>etO?c>=mA&{Kypqf+A6KN5t!1NymF;b)9hAKnRO1MumWHKG_Yd*u|mKAhQ4#)p)8EKa5X(2TL z4V9GD8_IPpu%DHi8b_iX>#Q~dEmGE+E4R|t{&xtiwTs$dHJ~kMm%iwZ@~bjO`9=9H zSt>TDUw2V1=#;uBPq~}E=(7|SDHPIR)qoypu;wVgCqEK>LLbmqxv0T>U&TpH6BK~{ zpb!iIMc8&QD5;Osj}a=aHz^NJYS(08Ibf(V>K|Yj7!F2&k;+3A$5b3wab2<~k`sJV z#X%hw<3Pb{pa5%8x0?V;*Mm|pF}W|&j7_w`*-idzSd&Kp}Yp*XjAZ26?AXaAP?RN5D7m@UyP zE=?h(;x-j$70oV8ZjAP9vpOBUw≱A^xWzktmHFM*fqe(q9nr?Owg9V+flHi^m3 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 BzhM9X delta 5058 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 Yo`PrLuSn|8V7UFn+uVNM`G!~j4UhG{r2qf` diff --git a/Resources/Info.plist b/Resources/Info.plist index a8198fc..2f134c1 100644 --- a/Resources/Info.plist +++ b/Resources/Info.plist @@ -12,7 +12,7 @@ vlsong CFBundleTypeIconFile - + vlsong.icns CFBundleTypeName Song CFBundleTypeOSTypes @@ -32,7 +32,7 @@ CFBundleExecutable Vocalese CFBundleIconFile - + vocalese CFBundleIdentifier com.aereperennius.Vocalese CFBundleInfoDictionaryVersion diff --git a/Sources/VLDocument.mm b/Sources/VLDocument.mm index 88746a8..79c6723 100644 --- a/Sources/VLDocument.mm +++ b/Sources/VLDocument.mm @@ -76,8 +76,13 @@ { VLProperties & prop = song->fProperties.front(); + if (transpose) + song->Transpose((7*((key>>8)-prop.fKey) % 12)); + prop.fKey = key >> 8; prop.fMode= key & 0xFF; + + [self updateChangeCount:NSChangeDone]; } - (NSNumber *) songTime @@ -92,6 +97,8 @@ VLProperties & prop = song->fProperties.front(); prop.fTime = VLFraction(num, denom); + + [self updateChangeCount:NSChangeDone]; } - (NSNumber *) songDivisions @@ -106,37 +113,19 @@ VLProperties & prop = song->fProperties.front(); prop.fDivisions = divisions; + + [self updateChangeCount:NSChangeDone]; } - (NSString *)windowNibName { - // Override returning the nib file name of the document - // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead. return @"VLDocument"; } -- (void)windowControllerDidLoadNib:(NSWindowController *) aController +- (void)windowControllerDidLoadNib:(NSWindowController *) controller { - [super windowControllerDidLoadNib:aController]; - // Add any code here that needs to be executed once the windowController has loaded the document's window. -} - -- (NSData *)dataRepresentationOfType:(NSString *)aType -{ - // Insert code here to write your document from the given data. You can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead. - - // For applications targeted for Tiger or later systems, you should use the new Tiger API -dataOfType:error:. In this case you can also choose to override -writeToURL:ofType:error:, -fileWrapperOfType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead. - - return nil; -} - -- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType -{ - // Insert code here to read your document from the given data. You can also choose to override -loadFileWrapperRepresentation:ofType: or -readFromFile:ofType: instead. - - // For applications targeted for Tiger or later systems, you should use the new Tiger API readFromData:ofType:error:. In this case you can also choose to override -readFromURL:ofType:error: or -readFromFileWrapper:ofType:error: instead. - - return YES; + [super windowControllerDidLoadNib:controller]; + [controller setShouldCloseDocument:YES]; } @end diff --git a/Sources/VLSheetViewChords.mm b/Sources/VLSheetViewChords.mm index a97226e..f316463 100644 --- a/Sources/VLSheetViewChords.mm +++ b/Sources/VLSheetViewChords.mm @@ -119,6 +119,7 @@ std::string NormalizeName(NSString* rawName) fSong->AddChord(chord, fMeasure, fAt); [fView setNeedsDisplay:YES]; } + [[fView document] updateChangeCount:NSChangeDone]; } - (BOOL) validValue:(NSString *)val diff --git a/Sources/VLSheetViewNotes.mm b/Sources/VLSheetViewNotes.mm index 107dc77..2b72703 100644 --- a/Sources/VLSheetViewNotes.mm +++ b/Sources/VLSheetViewNotes.mm @@ -23,6 +23,7 @@ [self song]->AddNote(newNote, fCursorMeasure, fCursorAt); [self setNeedsDisplay:YES]; + [[self document] updateChangeCount:NSChangeDone]; VLSoundOut::Instance()->PlayNote(newNote); diff --git a/Sources/VLXMLDocument.mm b/Sources/VLXMLDocument.mm index 5d8eef5..12b4d25 100644 --- a/Sources/VLXMLDocument.mm +++ b/Sources/VLXMLDocument.mm @@ -20,7 +20,8 @@ - (id) nodeForXPath:(NSString *)path error:(NSError **)outError { - return [[self nodesForXPath:path error:outError] objectAtIndex:0]; + NSArray * nodes = [self nodesForXPath:path error:outError]; + return [nodes count] ? [nodes objectAtIndex:0] : nil; } - (NSString *)stringForXPath:(NSString *)path error:(NSError **)outError @@ -259,6 +260,105 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB "; return YES; } +int8_t sStepToPitch[] = { + 9, 11, 0, 2, 4, 5, 7 +}; + +- (VLNote) readNote:(NSXMLElement*)note withUnit:(VLFraction)unit +{ + NSError * outError; + VLNote n; + + n.fTied = 0; + + if ([[note elementsForName:@"rest"] count]) { + n.fPitch = VLNote::kNoPitch; + } else { + n.fPitch = ([note intForXPath:@"./pitch/octave" error:&outError]+1)*12; + n.fPitch += + sStepToPitch[[[note stringForXPath:@"./pitch/step" error:&outError] + characterAtIndex:0] - 'A']; + if (NSXMLElement * alter = [note nodeForXPath:@"./pitch/alter" error:&outError]) + n.fPitch += [[alter stringValue] intValue]; + } + n.fDuration = VLFraction([note intForXPath:@"./duration" error:&outError])*unit; + + return n; +} + +- (void) readMelody:(NSArray *)measures error:(NSError **)outError +{ + NSEnumerator * e = [measures objectEnumerator]; + + for (NSXMLElement * measure; measure = [e nextObject]; ) { + VLProperties & prop = song->fProperties.front(); + VLFraction unit(1, 4*prop.fDivisions); + VLFraction at(0); + int m = [[[measure attributeForName:@"number"] + stringValue] intValue]-1; + + if (m >= song->CountMeasures()) + song->fMeasures.resize(m); + + NSEnumerator * n = [[measure elementsForName:@"note"] objectEnumerator]; + + for (NSXMLElement * note; note = [n nextObject]; ) { + VLNote n = [self readNote:note withUnit:unit]; + if (n.fPitch != VLNote::kNoPitch) + song->AddNote(n, m, at); + at += n.fDuration; + } + } +} + +- (void) readChords:(NSArray *)measures error:(NSError **)outError +{ + NSEnumerator * e = [measures objectEnumerator]; + + for (NSXMLElement * measure; measure = [e nextObject]; ) { + VLProperties & prop = song->fProperties.front(); + VLFraction unit(1, 4*prop.fDivisions); + VLFraction at(0); + VLFraction dur(0); + int m = [[[measure attributeForName:@"number"] + stringValue] intValue]-1; + VLChord chord; + + chord.fSteps = 0; + if (m >= song->CountMeasures()) + song->fMeasures.resize(m); + + NSEnumerator * n = [[measure elementsForName:@"note"] objectEnumerator]; + + for (NSXMLElement * note; note = [n nextObject]; ) { + VLNote n = [self readNote:note withUnit:unit]; + if (![[note elementsForName:@"chord"] count]) { + // + // Start of new chord + // + if (chord.fSteps) + song->AddChord(chord, m, at); + at += dur; + chord.fPitch = n.fPitch; + chord.fRootPitch= VLNote::kNoPitch; + chord.fDuration = n.fDuration; + chord.fSteps = n.fPitch == VLNote::kNoPitch ? 0 : VLChord::kmUnison; + dur = n.fDuration; + if (n.fPitch < VLNote::kMiddleC) { + chord.fPitch = VLNote::kNoPitch; + chord.fRootPitch= n.fPitch; + } + } else if (chord.fPitch == VLNote::kNoPitch) { + chord.fPitch = n.fPitch; + } else { + chord.fSteps |= 1 << (n.fPitch-chord.fPitch); + } + } + if (chord.fSteps) + song->AddChord(chord, m, at); + } +} + - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError { NSXMLDocument * doc = [[NSXMLDocument alloc] initWithData:data @@ -280,7 +380,12 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB "; error:outError] ) return NO; - + + [self readMelody:[melody nodesForXPath:@"./measure" error:outError] + error:outError]; + [self readChords:[chords nodesForXPath:@"./measure" error:outError] + error:outError]; + return YES; }