Added MMA export

This commit is contained in:
Matthias Neeracher 2006-11-04 08:15:34 +00:00
parent 71a993f9c6
commit 9c2dcd582e
9 changed files with 243 additions and 0 deletions

Binary file not shown.

View File

@ -29,6 +29,7 @@
<array>
<string>VLLilypondType</string>
<string>VLMusicXMLType</string>
<string>VLMMAType</string>
</array>
<key>NSPersistentStoreTypeKey</key>
<string>XML</string>
@ -65,6 +66,20 @@
<key>NSPersistentStoreTypeKey</key>
<string>Binary</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>mma</string>
</array>
<key>CFBundleTypeName</key>
<string>VLMMAType</string>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>Binary</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>VocalEasel</string>

View File

@ -21,6 +21,8 @@
NSString * songLyricist;
NSString * songComposer;
NSString * songArranger;
NSString * songGroove;
NSNumber * songTempo;
VLSheetWindow * sheetWin;
VLLogWindow * logWin;

View File

@ -9,6 +9,7 @@
#import "VLDocument.h"
#import "VLXMLDocument.h"
#import "VLLilypondDocument.h"
#import "VLMMADocument.h"
#import "VLPDFWindow.h"
#import "VLLogWindow.h"
#import "VLSheetWindow.h"
@ -25,6 +26,8 @@
songLyricist = @"";
songComposer = @"";
songArranger = @"";
songGroove = @"Swing";
songTempo = [[NSNumber numberWithInt:120] retain];
sheetWin = nil;
pdfWin = nil;
logWin = nil;
@ -157,6 +160,8 @@
return [self XMLFileWrapperWithError:outError flat:YES];
} else if ([typeName isEqual:@"VLLilypondType"]) {
return [self lilypondFileWrapperWithError:outError];
} else if ([typeName isEqual:@"VLMMAType"]) {
return [self mmaFileWrapperWithError:outError];
} else {
if (outError)
*outError = [NSError errorWithDomain:NSCocoaErrorDomain

16
Sources/VLMMADocument.h Normal file
View File

@ -0,0 +1,16 @@
//
// VLMMADocument.h
// Vocalese
//
// Created by Matthias Neeracher on 10/20/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "VLDocument.h"
@interface VLDocument (MMA)
- (NSFileWrapper *)mmaFileWrapperWithError:(NSError **)outError;
@end

66
Sources/VLMMADocument.mm Normal file
View File

@ -0,0 +1,66 @@
//
// VLLilypondDocument.mm
// Vocalese
//
// Created by Matthias Neeracher on 10/20/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
#import "VLMMADocument.h"
@implementation VLDocument (MMA)
const int kMajorOffset = 6;
const int kMinorOffset = 9;
const char * sKeyNames[] = {
"ges", "des", "as", "es", "bes", "f",
"c", "g", "d", "a", "e", "b", "fis", "cis", "gis"
};
- (NSData *)mmaDataWithError:(NSError **)outError
{
char buf[32];
NSBundle * bndl = [NSBundle mainBundle];
const VLProperties & prop = song->fProperties.front();
std::string mmaFile = std::string("// Generated by VocalEasel ")
+ (const char *)[[bndl objectForInfoDictionaryKey:@"CFBundleVersion"]
UTF8String]
+ "\n\n";
sprintf(buf, "Tempo %d\n", [songTempo intValue]);
mmaFile += buf;
sprintf(buf, "Groove %s\n", [songGroove UTF8String]);
mmaFile += buf;
sprintf(buf, "KeySig %d%c\n", labs(prop.fKey), prop.fKey>=0 ? '#' : '&');
mmaFile += buf;
mmaFile += '\n';
std::string mmas;
for (size_t m=0; m<song->CountMeasures(); ++m) {
sprintf(buf, "%-5d", m+1);
mmaFile += buf;
song->fMeasures[m].MMAChords(mmas);
mmaFile += mmas;
song->fMeasures[m].MMANotes(mmas);
mmaFile += "\t{ " + mmas + " }\n";
}
mmaFile += mmas;
return [[NSString stringWithUTF8String:mmaFile.c_str()]
dataUsingEncoding:NSUTF8StringEncoding];
}
- (NSFileWrapper *)mmaFileWrapperWithError:(NSError **)outError
{
NSData * data = [self mmaDataWithError:outError];
if (!data)
return nil;
else
return [[[NSFileWrapper alloc]
initRegularFileWithContents:data]
autorelease];
}
@end

View File

@ -104,6 +104,27 @@ static std::string LilypondPitchName(int8_t pitch, bool useSharps)
return kScale[pitch+1] + std::string("es");
}
static std::string MMAPitchName(int8_t pitch, bool useSharps)
{
if (pitch == VLNote::kNoPitch)
return "r";
char name[3];
name[2] = 0;
name[1] = 'n';
pitch %= 12;
if (kScale[pitch] != ' ') {
name[0] = kScale[pitch];
} else if (useSharps) {
name[0] = kScale[pitch-1];
name[1] = '#';
} else {
name[0] = kScale[pitch+1];
name[1] = '&';
}
return name;
}
VLNote::VLNote(std::string name)
{
//
@ -175,6 +196,50 @@ void VLNote::LilypondName(std::string & name, VLFraction at, const VLProperties
}
}
static struct {
VLFract fVal;
const char * fName;
} sMMADur [] = {
{{1,1}, "1"},
{{1,2}, "2"},
{{1,3}, "23"},
{{1,4}, "4"},
{{1,6}, "81"},
{{1,8}, "8"},
{{1,12}, "82"},
{{1,16}, "16"},
{{1,24}, "6"},
{{1,32}, "32"},
{{1,64}, "64"},
{{0,0}, 0}
};
void VLNote::MMAName(std::string & name, VLFraction at, const VLProperties & prop) const
{
bool useSharps = prop.fKey >= 0;
name.clear();
for (VLFraction dur = fDuration; dur.fNum; ) {
VLFraction part;
prop.PartialNote(at, dur, &part);
for (int d=0; sMMADur[d].fName; ++d)
if (part == sMMADur[d].fVal) {
if (name.size())
name += '+';
name += sMMADur[d].fName;
}
dur -= part;
at += part;
}
name += MMAPitchName(fPitch, useSharps);
if (fPitch != kNoPitch) {
for (int raise = (fPitch-kMiddleC)/kOctave; raise>0; --raise)
name += '+';
for (int lower = (kMiddleC-fPitch)/kOctave; lower>0; --lower)
name += '-';
}
}
struct VLChordModifier {
const char * fName;
uint32_t fAddSteps;
@ -315,6 +380,7 @@ void VLChord::Name(std::string & base, std::string & ext, std::string & root, bo
if (steps & kmMaj7th) {
ext += "Maj";
steps&= ~kmMaj7th;
steps|= kmMin7th; // Write out the 7 for clarification
}
//
// 6/9
@ -431,12 +497,42 @@ void VLChord::LilypondName(std::string & name, bool useSharps) const
name += "/+" + LilypondPitchName(fRootPitch, useSharps);
}
void VLChord::MMAName(std::string & name, bool useSharps) const
{
VLFraction dur = fDuration;
int quarters = static_cast<int>(dur*4.0f+0.5f);
name = "";
if (!quarters--)
return;
if (fPitch == kNoPitch) {
name = '/';
} else {
std::string base, ext, root;
Name(base, ext, root, useSharps);
name = base+ext;
if (root.size())
name += '/'+root;
std::toupper(base[0]);
size_t mod;
while ((mod = name.find("Maj")) != std::string::npos)
name.erase(mod+1, 2);
while ((mod = name.find(kVLSharpStr, 3)) != std::string::npos)
name.replace(mod, 3, '#', 1);
while ((mod = name.find(kVLFlatStr, 3)) != std::string::npos)
name.replace(mod, 3, '&', 1);
}
while (quarters--)
name += " /";
}
static VLFraction MaxNote(VLFraction d)
{
if (d >= 1)
return 1;
if (d.fNum == 1 && !(d.fDenom & (d.fDenom-1))) // Power of 2
return d;
VLFraction note(1,2);
VLFraction triplet(1,3);
@ -512,6 +608,38 @@ VLMeasure::VLMeasure()
{
}
void VLMeasure::MMANotes(std::string & notes) const
{
VLFraction at(0);
VLNoteList::const_iterator i = fMelody.begin();
VLNoteList::const_iterator e = fMelody.end();
notes.clear();
for (; i!=e; ++i) {
std::string note;
i->MMAName(note, at, *fProperties);
if (notes.size())
notes += ' ';
notes += note;
at += i->fDuration;
}
}
void VLMeasure::MMAChords(std::string & chords) const
{
VLChordList::const_iterator i = fChords.begin();
VLChordList::const_iterator e = fChords.end();
chords.clear();
for (; i!=e; ++i) {
std::string chord;
i->MMAName(chord, fProperties->fKey >= 0);
if (chords.size())
chords += ' ';
chords += chord;
}
}
VLSong::VLSong()
{
const VLFraction fourFour(4,4);

View File

@ -124,6 +124,7 @@ struct VLNote {
void Name(std::string & name, bool useSharps = false) const;
void LilypondName(std::string & name, VLFraction at, const VLProperties & prop) const;
void MMAName(std::string & name, VLFraction at, const VLProperties & prop) const;
};
struct VLRest : VLNote {
@ -185,6 +186,7 @@ struct VLChord : VLNote {
VLChord(std::string name);
void Name(std::string & base, std::string & ext, std::string & root, bool useSharps = false) const;
void LilypondName(std::string & name, bool useSharps = false) const;
void MMAName(std::string & name, bool useSharps) const;
};
struct VLProperties {
@ -219,6 +221,9 @@ struct VLMeasure {
VLSyllList fLyrics;
VLMeasure();
void MMANotes(std::string & notes) const;
void MMAChords(std::string & chords) const;
};
struct VLSong {

View File

@ -49,6 +49,7 @@
95ECE6590AF3324300FE3E98 /* lilyWrapper in Resources */ = {isa = PBXBuildFile; fileRef = 95ECE6580AF3324300FE3E98 /* lilyWrapper */; };
95F5F50F0ADCC433003980B2 /* VLXMLDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95F5F50E0ADCC433003980B2 /* VLXMLDocument.mm */; };
95F5F5340ADCCFBB003980B2 /* DTD in Resources */ = {isa = PBXBuildFile; fileRef = 95F5F51E0ADCCFBB003980B2 /* DTD */; };
95F820AB0AF884A30010963D /* VLMMADocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95F820AA0AF884A30010963D /* VLMMADocument.mm */; };
95FC668F0AF0A08C003D9C11 /* VLLogWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95FC668E0AF0A08C003D9C11 /* VLLogWindow.mm */; };
95FC66960AF0A112003D9C11 /* VLLogWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 95FC66950AF0A112003D9C11 /* VLLogWindow.nib */; };
95FC66A60AF0A24C003D9C11 /* VLPDFWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95FC66A50AF0A24C003D9C11 /* VLPDFWindow.mm */; };
@ -118,6 +119,8 @@
95F5F50D0ADCC433003980B2 /* VLXMLDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLXMLDocument.h; path = Sources/VLXMLDocument.h; sourceTree = "<group>"; };
95F5F50E0ADCC433003980B2 /* VLXMLDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLXMLDocument.mm; path = Sources/VLXMLDocument.mm; sourceTree = "<group>"; };
95F5F51E0ADCCFBB003980B2 /* DTD */ = {isa = PBXFileReference; lastKnownFileType = folder; name = DTD; path = Resources/DTD; sourceTree = "<group>"; };
95F820A90AF884A30010963D /* VLMMADocument.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLMMADocument.h; path = Sources/VLMMADocument.h; sourceTree = "<group>"; };
95F820AA0AF884A30010963D /* VLMMADocument.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = VLMMADocument.mm; path = Sources/VLMMADocument.mm; sourceTree = "<group>"; };
95FC668D0AF0A08C003D9C11 /* VLLogWindow.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = VLLogWindow.h; path = Sources/VLLogWindow.h; sourceTree = "<group>"; };
95FC668E0AF0A08C003D9C11 /* VLLogWindow.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = VLLogWindow.mm; path = Sources/VLLogWindow.mm; sourceTree = "<group>"; };
95FC66950AF0A112003D9C11 /* VLLogWindow.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = VLLogWindow.nib; path = English.lproj/VLLogWindow.nib; sourceTree = "<group>"; };
@ -230,6 +233,8 @@
2A37F4ABFDCFA73011CA2CEA /* Classes */ = {
isa = PBXGroup;
children = (
95F820A90AF884A30010963D /* VLMMADocument.h */,
95F820AA0AF884A30010963D /* VLMMADocument.mm */,
95A1C3840AF2ACE20076597D /* VLSheetWindow.h */,
95A1C3850AF2ACE20076597D /* VLSheetWindow.mm */,
95FC66CC0AF0A591003D9C11 /* VLPDFView.mm */,
@ -478,6 +483,7 @@
95FC66A60AF0A24C003D9C11 /* VLPDFWindow.mm in Sources */,
95FC66CE0AF0A591003D9C11 /* VLPDFView.mm in Sources */,
95A1C3860AF2ACE20076597D /* VLSheetWindow.mm in Sources */,
95F820AB0AF884A30010963D /* VLMMADocument.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};