VocalEasel/Sources/VLLilypondDocument.mm

211 lines
6.7 KiB
Plaintext
Raw Permalink Normal View History

2006-10-22 07:16:29 +00:00
//
2007-04-27 06:41:34 +00:00
// File: VLLilypondDocument.mm - Export document in LilyPond format
2006-10-22 07:16:29 +00:00
//
2007-04-27 06:41:34 +00:00
// Author(s):
//
// (MN) Matthias Neeracher
//
// Copyright © 2006-2017 Matthias Neeracher
2006-10-22 07:16:29 +00:00
//
#import "VLLilypondDocument.h"
#import "VLLilypondWriter.h"
2006-10-22 07:16:29 +00:00
2008-01-26 20:56:36 +00:00
#import <algorithm>
2006-10-22 07:16:29 +00:00
@interface NSMutableString (VLLilypond)
- (void) substituteMacro:(NSString *)macro withValue:(NSString *)value;
- (void) purgeMacros;
@end
@implementation NSMutableString (VLLilypond)
2006-11-27 07:07:45 +00:00
- (void) substituteMacro:(NSString *)m withValue:(NSString *)value repeat:(BOOL)repeat
2006-10-22 07:16:29 +00:00
{
2006-10-23 07:42:53 +00:00
if ([value isEqual:@""])
return;
2006-10-22 07:16:29 +00:00
NSString * macro = [NSString stringWithFormat:@"<{%@}>", m];
NSRange range =
[value rangeOfCharacterFromSet:
[NSCharacterSet characterSetWithCharactersInString:@"\n"]];
BOOL hasEOL= range.location != NSNotFound;
2006-11-27 07:07:45 +00:00
unsigned from = 0;
2006-10-22 07:16:29 +00:00
for (range = [self rangeOfString:macro];
range.location != NSNotFound;
2006-11-27 07:07:45 +00:00
range = [self rangeOfString:macro options:0
range:NSMakeRange(from, [self length]-from)]
2006-10-22 07:16:29 +00:00
) {
if (hasEOL) {
//
// Multi line substitution, figure out a prefix
//
NSRange prefix, suffix;
NSRange line = [self lineRangeForRange:range];
suffix.location = range.location+range.length;
suffix.length = line.location+line.length-suffix.location;
prefix.location = line.location;
prefix.length = range.location-prefix.location;
NSString * pfxStr = [self substringWithRange:prefix];
NSString * nonBlank =
[pfxStr stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]];
NSString * sfxStr =
[[self substringWithRange:suffix]
stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceCharacterSet]];
2006-11-27 07:07:45 +00:00
NSString * nl;
2006-10-22 07:16:29 +00:00
if ([nonBlank length]) {
NSRange nb = [pfxStr rangeOfString:nonBlank];
2006-11-27 07:07:45 +00:00
prefix.length = nb.location;
2006-10-22 07:16:29 +00:00
pfxStr =
[[self substringWithRange:prefix]
stringByAppendingString:@" "];
sfxStr = [NSString stringWithFormat:@"\n%@", pfxStr];
2006-11-27 07:07:45 +00:00
nl = @"\n";
2006-10-22 07:16:29 +00:00
} else {
range = line;
2006-11-27 07:07:45 +00:00
nl = @"";
2006-10-22 07:16:29 +00:00
}
NSArray * lines = [value componentsSeparatedByString:@"\n"];
value =
2006-11-27 07:07:45 +00:00
[NSString stringWithFormat:@"%@%@%@%@", nl, pfxStr,
2006-10-22 07:16:29 +00:00
[lines componentsJoinedByString:
[@"\n" stringByAppendingString:pfxStr]],
sfxStr];
}
2006-11-27 07:07:45 +00:00
from = range.location + [value length];
if (repeat) {
NSRange line = [self lineRangeForRange:range];
[self insertString:[self substringWithRange:line]
atIndex:line.location+line.length];
from = line.location+2*line.length+[value length]-range.length;
}
2006-10-22 07:16:29 +00:00
[self replaceCharactersInRange:range withString:value];
}
}
2006-11-27 07:07:45 +00:00
- (void)substituteMacro:(NSString*)macro withValue:(NSString*)value
{
[self substituteMacro:macro withValue:value repeat:NO];
}
2011-08-26 18:17:32 +00:00
- (void)substituteMacro:(NSString*)macro withValue:(NSString*)value escapingQuotes:(BOOL)escape
{
if (escape)
value = [value stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
[self substituteMacro:macro withValue:value repeat:NO];
}
2006-10-22 07:16:29 +00:00
- (void) purgeMacros
{
for (NSRange range = [self rangeOfString:@"<{"];
range.location != NSNotFound;
range = [self rangeOfString:@"<{"]
)
[self replaceCharactersInRange:[self lineRangeForRange:range]
withString: @""];
}
@end
2008-01-26 20:56:36 +00:00
static NSSize sPaperSizes[] = {
{842.0f, 1191.0f}, {595.0f, 842.0f}, {421.0f, 595.0f}, {298.0f, 421.0f},
{612.0f, 1008.0f}, {612.0f, 792.0f}, {792.0f, 1224.0f}
};
static const char * sPaperNames[] = {
"a3", "a4", "a5", "a6", "legal", "letter", "11x17", 0
2008-01-26 20:56:36 +00:00
};
2006-10-22 07:16:29 +00:00
@implementation VLDocument (Lilypond)
- (NSData *)lilypondDataWithError:(NSError **)outError
{
VLLilypondWriter writer;
writer.Visit(*song);
2006-10-23 07:42:53 +00:00
NSBundle * bndl = [NSBundle mainBundle];
NSString * tmpl =
2006-10-22 07:16:29 +00:00
[bndl pathForResource:lilypondTemplate
ofType:@"lyt" inDirectory:@"Templates"];
2006-10-23 07:42:53 +00:00
NSStringEncoding enc = NSUTF8StringEncoding;
NSMutableString * ly =
[NSMutableString stringWithContentsOfFile:tmpl encoding:enc error:outError];
2008-01-26 20:56:36 +00:00
NSPrintInfo * pi = [self printInfo];
NSSize sz = [pi paperSize];
int bestPaper = -1;
float bestDist = 1e10f;
if ([pi orientation] == NSLandscapeOrientation)
std::swap(sz.width, sz.height);
for (int paper = 0; sPaperNames[paper]; ++paper) {
float dist = hypotf(sz.width - sPaperSizes[paper].width,
sz.height- sPaperSizes[paper].height);
if (dist < bestDist) {
bestPaper = paper;
bestDist = dist;
}
}
NSString * paper = [NSString stringWithFormat:
[pi orientation] == NSLandscapeOrientation ? @"\"%s\" 'landscape" : @"\"%s\"",
sPaperNames[bestPaper]];
float scaling= [[[pi dictionary] objectForKey:NSPrintScalingFactor]
floatValue];
2011-08-26 18:17:32 +00:00
[ly substituteMacro:@"TITLE" withValue:songTitle escapingQuotes:YES];
[ly substituteMacro:@"POET" withValue:songLyricist escapingQuotes:YES];
[ly substituteMacro:@"COMPOSER" withValue:songComposer escapingQuotes:YES];
[ly substituteMacro:@"ARRANGER" withValue:songArranger escapingQuotes:YES];
2006-10-23 07:42:53 +00:00
[ly substituteMacro:@"VLVERSION" withValue:
2011-07-24 03:32:43 +00:00
[bndl objectForInfoDictionaryKey:@"CFBundleVersion"]];
2008-01-26 20:56:36 +00:00
[ly substituteMacro:@"PAPERSIZE" withValue:paper];
2008-01-27 10:43:16 +00:00
// [ly substituteMacro:@"FORMATTING" withValue:@"ragged-last-bottom = ##f"];
2006-10-22 07:16:29 +00:00
[ly substituteMacro:@"VLVERSION" withValue:
2011-07-24 03:32:43 +00:00
[bndl objectForInfoDictionaryKey:@"CFBundleVersion"]];
2008-01-26 16:38:30 +00:00
[ly substituteMacro:@"CHORDSIZE" withValue:
2011-07-24 03:32:43 +00:00
[NSString stringWithFormat:@"%f", chordSize]];
2008-01-26 16:38:30 +00:00
[ly substituteMacro:@"LYRICSIZE" withValue:
2011-07-24 03:32:43 +00:00
[NSString stringWithFormat:@"%f", lyricSize]];
2008-01-26 16:38:30 +00:00
[ly substituteMacro:@"STAFFSIZE" withValue:
2011-07-24 03:32:43 +00:00
[NSString stringWithFormat:@"%f", staffSize*scaling]];
[ly substituteMacro:@"TOPPADDING" withValue:
[NSString stringWithFormat:@"%f", topPadding]];
[ly substituteMacro:@"TITLEPADDING" withValue:
[NSString stringWithFormat:@"%f", titlePadding]];
[ly substituteMacro:@"STAFFPADDING" withValue:
[NSString stringWithFormat:@"%f", staffPadding]];
[ly substituteMacro:@"CHORDPADDING" withValue:
[NSString stringWithFormat:@"%f", chordPadding]];
[ly substituteMacro:@"LYRICPADDING" withValue:
[NSString stringWithFormat:@"%f", lyricPadding]];
2006-10-23 07:42:53 +00:00
[ly substituteMacro:@"CHORDS" withValue:
[NSString stringWithUTF8String:writer.Chords().c_str()]];
2006-10-23 07:42:53 +00:00
[ly substituteMacro:@"NOTES" withValue:
[NSString stringWithUTF8String:writer.Melody().c_str()]];
2006-11-27 07:07:45 +00:00
if (size_t stanzas = song->CountStanzas())
for (size_t s=0; s<stanzas; ++s) {
2006-11-27 07:07:45 +00:00
[ly substituteMacro:@"LYRICS" withValue:
[NSString stringWithUTF8String:writer.Lyrics(s).c_str()]
2006-11-27 07:07:45 +00:00
repeat: s<stanzas];
}
2006-10-22 07:16:29 +00:00
[ly purgeMacros];
return [ly dataUsingEncoding:enc];
}
- (NSFileWrapper *)lilypondFileWrapperWithError:(NSError **)outError
{
NSData * data = [self lilypondDataWithError:outError];
if (!data)
return nil;
else
return [[[NSFileWrapper alloc]
initRegularFileWithContents:data]
autorelease];
}
2006-10-22 07:16:29 +00:00
@end