mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Added MMA export
This commit is contained in:
parent
71a993f9c6
commit
9c2dcd582e
Binary file not shown.
|
@ -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>
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
NSString * songLyricist;
|
||||
NSString * songComposer;
|
||||
NSString * songArranger;
|
||||
NSString * songGroove;
|
||||
NSNumber * songTempo;
|
||||
|
||||
VLSheetWindow * sheetWin;
|
||||
VLLogWindow * logWin;
|
||||
|
|
|
@ -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
16
Sources/VLMMADocument.h
Normal 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
66
Sources/VLMMADocument.mm
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user