mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Highlight chords (badly), nonblocking sound
This commit is contained in:
parent
50da584417
commit
cbc2b31da8
BIN
English.lproj/VLDocument.nib/keyedobjects.nib
generated
BIN
English.lproj/VLDocument.nib/keyedobjects.nib
generated
Binary file not shown.
|
@ -16,6 +16,9 @@
|
|||
- (NSString *) stringValue;
|
||||
- (void) setStringValue:(NSString*)val;
|
||||
- (BOOL) validValue:(NSString*)val;
|
||||
- (void) moveToNext;
|
||||
- (void) moveToPrev;
|
||||
- (void) highlightCursor;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void) moveToNext
|
||||
{
|
||||
}
|
||||
|
||||
- (void) moveToPrev
|
||||
{
|
||||
}
|
||||
|
||||
- (void) highlightCursor
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation VLDocument
|
||||
|
|
|
@ -40,8 +40,14 @@ enum VLRegion {
|
|||
kRegionLyrics
|
||||
};
|
||||
|
||||
enum VLRecalc {
|
||||
kNoRecalc,
|
||||
kRecalc,
|
||||
kFirstRecalc
|
||||
};
|
||||
|
||||
@interface VLSheetView : NSView {
|
||||
BOOL fNeedsRecalc;
|
||||
VLRecalc fNeedsRecalc;
|
||||
BOOL fIsRest;
|
||||
float fClefKeyW;
|
||||
float fMeasureW;
|
||||
|
@ -58,7 +64,6 @@ enum VLRegion {
|
|||
VLFract fCursorAt;
|
||||
int fCursorPitch;
|
||||
|
||||
BOOL fShowFieldEditor;
|
||||
IBOutlet id fFieldEditor;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,15 +79,19 @@ static float sFlatPos[] = {
|
|||
[sMusic[i] setSize:sz];
|
||||
}
|
||||
}
|
||||
fNeedsRecalc = YES;
|
||||
fNeedsRecalc = kFirstRecalc;
|
||||
fIsRest = NO;
|
||||
fShowFieldEditor = NO;
|
||||
fDisplayScale = 1.0f;
|
||||
fCursorPitch = VLNote::kNoPitch;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (VLDocument *) document
|
||||
{
|
||||
return [[[self window] windowController] document];
|
||||
|
@ -167,7 +171,6 @@ static float sFlatPos[] = {
|
|||
- (void) recalculateDimensions
|
||||
{
|
||||
NSScrollView * scroll = [self enclosingScrollView];
|
||||
fNeedsRecalc = NO;
|
||||
|
||||
NSSize sz = [scroll contentSize];
|
||||
sz.width /= fDisplayScale;
|
||||
|
@ -202,6 +205,16 @@ static float sFlatPos[] = {
|
|||
[self setFrameSize:frameSz];
|
||||
[self setBoundsSize:sz];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
if (fNeedsRecalc == kFirstRecalc) {
|
||||
NSView *dv = [scroll documentView];
|
||||
NSView *cv = [scroll contentView];
|
||||
|
||||
[dv scrollPoint:
|
||||
NSMakePoint(0.0, NSMaxY([dv frame])-NSHeight([cv bounds]))];
|
||||
}
|
||||
|
||||
fNeedsRecalc = kNoRecalc;
|
||||
}
|
||||
|
||||
- (void)drawGridForSystem:(int)system
|
||||
|
@ -318,14 +331,15 @@ static float sFlatPos[] = {
|
|||
[self drawNotesForSystem:system];
|
||||
[self drawChordsForSystem:system];
|
||||
}
|
||||
VLEditable * editable = [[self document] valueForKey: @"editTarget"];
|
||||
[editable highlightCursor];
|
||||
}
|
||||
|
||||
- (IBAction) setKey:(id)sender
|
||||
{
|
||||
int key = [[sender selectedItem] tag];
|
||||
[[self document] setKey: key transpose: YES];
|
||||
fNeedsRecalc = YES;
|
||||
[self setNeedsDisplay: YES];
|
||||
fNeedsRecalc = kRecalc;
|
||||
}
|
||||
|
||||
- (IBAction) setTime:(id)sender
|
||||
|
@ -333,7 +347,7 @@ static float sFlatPos[] = {
|
|||
int time = [[sender selectedItem] tag];
|
||||
|
||||
[[self document] setTimeNum: time >> 8 denom: time & 0xFF];
|
||||
fNeedsRecalc = YES;
|
||||
fNeedsRecalc = kRecalc;
|
||||
[self setNeedsDisplay: YES];
|
||||
}
|
||||
|
||||
|
@ -342,15 +356,13 @@ static float sFlatPos[] = {
|
|||
int div = [[sender selectedItem] tag];
|
||||
|
||||
[[self document] setDivisions: div];
|
||||
fNeedsRecalc = YES;
|
||||
fNeedsRecalc = kRecalc;
|
||||
[self setNeedsDisplay: YES];
|
||||
}
|
||||
|
||||
- (IBAction)hideFieldEditor:(id)sender
|
||||
{
|
||||
[fFieldEditor setAction:nil];
|
||||
[self setValue: [NSNumber numberWithBool:NO]
|
||||
forKey: @"fShowFieldEditor"];
|
||||
}
|
||||
|
||||
const float kSemiFloor = -2.5f*kLineH;
|
||||
|
@ -480,4 +492,26 @@ static int sSemiToPitch[] = {
|
|||
return [editable validValue:[fFieldEditor stringValue]];
|
||||
}
|
||||
|
||||
- (void)controlTextDidEndEditing:(NSNotification *)note
|
||||
{
|
||||
VLEditable * editable = [[self document] valueForKey: @"editTarget"];
|
||||
switch ([[[note userInfo] objectForKey:@"NSTextMovement"] intValue]) {
|
||||
case NSTabTextMovement:
|
||||
[editable moveToNext];
|
||||
break;
|
||||
case NSBacktabTextMovement:
|
||||
[editable moveToPrev];
|
||||
break;
|
||||
default:
|
||||
[editable autorelease];
|
||||
editable = nil;
|
||||
}
|
||||
[[self document] setValue:editable forKey: @"editTarget"];
|
||||
if (editable)
|
||||
[fFieldEditor selectText:self];
|
||||
[[self window] performSelectorOnMainThread:@selector(makeFirstResponder:)
|
||||
withObject:(editable ? fFieldEditor : self)
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -6,10 +6,34 @@
|
|||
// Copyright 2006 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "VLDocument.h"
|
||||
|
||||
|
||||
@interface VLChordEditable : VLEditable {
|
||||
VLSheetView * fView;
|
||||
VLSong * fSong;
|
||||
int fMeasure;
|
||||
VLFract fAt;
|
||||
}
|
||||
|
||||
- (VLChordEditable *)initWithView:(VLSheetView *)view
|
||||
song:(VLSong *)song
|
||||
measure:(int)measure
|
||||
at:(VLFract)at;
|
||||
- (NSString *) stringValue;
|
||||
- (void) setStringValue:(NSString*)val;
|
||||
- (BOOL) validValue:(NSString*)val;
|
||||
- (void) moveToNext;
|
||||
- (void) moveToPrev;
|
||||
- (void) highlightCursor;
|
||||
|
||||
@end
|
||||
|
||||
@interface VLSheetView (Chords)
|
||||
|
||||
- (void) editChord;
|
||||
- (void) drawChordsForSystem:(int)system;
|
||||
- (void) highlightChordInMeasure:(int)measure at:(VLFraction)at;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -12,12 +12,11 @@
|
|||
|
||||
#import "VLModel.h"
|
||||
#import "VLSoundOut.h"
|
||||
#import "VLDocument.h"
|
||||
|
||||
std::string NormalizeName(NSString* rawName)
|
||||
{
|
||||
std::string chordName =
|
||||
(const char *)[[rawName lowercaseString] UTF8String];
|
||||
rawName ? (const char *)[[rawName lowercaseString] UTF8String] : "";
|
||||
//
|
||||
// Normalize # and b
|
||||
//
|
||||
|
@ -65,26 +64,9 @@ std::string NormalizeName(NSString* rawName)
|
|||
|
||||
@end
|
||||
|
||||
@interface VLChordEditable : VLEditable {
|
||||
NSView * fView;
|
||||
VLSong * fSong;
|
||||
int fMeasure;
|
||||
VLFract fAt;
|
||||
}
|
||||
|
||||
- (VLChordEditable *)initWithView:(NSView *)view
|
||||
song:(VLSong *)song
|
||||
measure:(int)measure
|
||||
at:(VLFract)at;
|
||||
- (NSString *) stringValue;
|
||||
- (void) setStringValue:(NSString*)val;
|
||||
- (BOOL) validValue:(NSString*)val;
|
||||
|
||||
@end
|
||||
|
||||
@implementation VLChordEditable
|
||||
|
||||
- (VLChordEditable *)initWithView:(NSView *)view
|
||||
- (VLChordEditable *)initWithView:(VLSheetView *)view
|
||||
song:(VLSong *)song
|
||||
measure:(int)measure
|
||||
at:(VLFract)at;
|
||||
|
@ -95,6 +77,8 @@ std::string NormalizeName(NSString* rawName)
|
|||
fMeasure= measure;
|
||||
fAt = at;
|
||||
|
||||
[fView setNeedsDisplay: YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -151,6 +135,33 @@ std::string NormalizeName(NSString* rawName)
|
|||
return chord.fPitch != VLNote::kNoPitch;
|
||||
}
|
||||
|
||||
- (void) moveToNext
|
||||
{
|
||||
const VLProperties & prop = fSong->fProperties.front();
|
||||
|
||||
fAt = fAt+VLFraction(1,4);
|
||||
if (fAt >= prop.fTime) {
|
||||
fAt = VLFraction(0,4);
|
||||
fMeasure = (fMeasure+1) % fSong->CountMeasures();
|
||||
}
|
||||
}
|
||||
|
||||
- (void) moveToPrev
|
||||
{
|
||||
if (fAt < VLFraction(1,4)) {
|
||||
const VLProperties & prop = fSong->fProperties.front();
|
||||
fAt = prop.fTime - VLFraction(1,4);
|
||||
fMeasure =
|
||||
(fMeasure+fSong->CountMeasures()-1) % fSong->CountMeasures();
|
||||
} else
|
||||
fAt = fAt-VLFraction(1,4);
|
||||
}
|
||||
|
||||
- (void) highlightCursor
|
||||
{
|
||||
[fView highlightChordInMeasure:fMeasure at:fAt];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation VLSheetView (Chords)
|
||||
|
@ -236,7 +247,17 @@ std::string NormalizeName(NSString* rawName)
|
|||
measure:fCursorMeasure
|
||||
at:fCursorAt];
|
||||
[doc setValue:e forKey:@"editTarget"];
|
||||
[self setValue:[NSNumber numberWithBool:YES] forKey:@"fShowFieldEditor"];
|
||||
[fFieldEditor selectText:self];
|
||||
}
|
||||
|
||||
- (void) highlightChordInMeasure:(int)measure at:(VLFraction)at
|
||||
{
|
||||
const float kSystemY = [self systemY:measure / fMeasPerSystem];
|
||||
NSRect r =
|
||||
NSMakeRect([self noteXInMeasure:measure at:at],
|
||||
kSystemY+kChordY, 3.0f*kNoteW, 20.0f);
|
||||
[[NSColor colorWithCalibratedWhite:0.8f alpha:1.0f] setFill];
|
||||
NSRectFillUsingOperation(r, NSCompositePlusDarker);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -42,18 +42,66 @@ private:
|
|||
void Run();
|
||||
void Stop();
|
||||
void Play(const int8_t * note, size_t numNotes = 1);
|
||||
protected:
|
||||
friend class VLAUSoundEvent;
|
||||
|
||||
void Play(const int8_t * note, size_t numNotes,
|
||||
UInt32 msg, UInt32 velocity);
|
||||
};
|
||||
|
||||
VLSoundEvent::~VLSoundEvent()
|
||||
{
|
||||
}
|
||||
|
||||
class VLAUSoundEvent : public VLSoundEvent {
|
||||
public:
|
||||
VLAUSoundEvent(VLAUSoundOut * soundOut,
|
||||
const int8_t * note, size_t numNotes,
|
||||
UInt32 msg, UInt32 velocity)
|
||||
: fSoundOut(soundOut), fNotes(note, note+numNotes),
|
||||
fMsg(msg), fVelocity(velocity)
|
||||
{}
|
||||
|
||||
virtual void Perform();
|
||||
private:
|
||||
VLAUSoundOut * fSoundOut;
|
||||
std::vector<int8_t> fNotes;
|
||||
UInt32 fMsg;
|
||||
UInt32 fVelocity;
|
||||
};
|
||||
|
||||
void VLAUSoundEvent::Perform()
|
||||
{
|
||||
fSoundOut->Play(&fNotes[0], fNotes.size(), fMsg, fVelocity);
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
void VLSoundScheduler::Schedule(VLSoundEvent * what, float when)
|
||||
{
|
||||
usleep((int)(1000000.0f*when));
|
||||
what->Perform();
|
||||
}
|
||||
|
||||
static std::auto_ptr<VLSoundOut> sSoundOut;
|
||||
static std::auto_ptr<VLSoundScheduler> sSoundScheduler;
|
||||
|
||||
VLSoundOut * VLSoundOut::Instance()
|
||||
{
|
||||
if (!sSoundOut.get())
|
||||
if (!sSoundOut.get()) {
|
||||
sSoundOut.reset(new VLAUSoundOut);
|
||||
if (!sSoundScheduler.get())
|
||||
sSoundScheduler.reset(new VLSoundScheduler);
|
||||
}
|
||||
|
||||
return sSoundOut.get();
|
||||
}
|
||||
|
||||
void VLSoundOut::SetScheduler(VLSoundScheduler * scheduler)
|
||||
{
|
||||
sSoundScheduler.reset(scheduler);
|
||||
}
|
||||
|
||||
VLSoundOut::~VLSoundOut()
|
||||
{
|
||||
}
|
||||
|
@ -149,11 +197,14 @@ void VLAUSoundOut::Play(const int8_t * note, size_t numNotes)
|
|||
const UInt32 kNoteOff = kMidiMessage_NoteOff << 4 | kMidiChannelInUse;
|
||||
const UInt32 kNoteVelocity= 127;
|
||||
|
||||
for (size_t i = 0; i<numNotes; ++i)
|
||||
MusicDeviceMIDIEvent(fSynth, kNoteOn, note[i], kNoteVelocity, 0);
|
||||
|
||||
usleep (500 * 1000);
|
||||
|
||||
for (size_t i = 0; i<numNotes; ++i)
|
||||
MusicDeviceMIDIEvent(fSynth, kNoteOff, note[i], kNoteVelocity, 0);
|
||||
Play(note, numNotes, kNoteOn, kNoteVelocity);
|
||||
sSoundScheduler.get()->Schedule(
|
||||
new VLAUSoundEvent(this, note, numNotes, kNoteOff, kNoteVelocity), 0.5f);
|
||||
}
|
||||
|
||||
void VLAUSoundOut::Play(const int8_t * note, size_t numNotes,
|
||||
UInt32 msg, UInt32 velocity)
|
||||
{
|
||||
for (size_t i = 0; i<numNotes; ++i)
|
||||
MusicDeviceMIDIEvent(fSynth, msg, note[i], velocity, 0);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,26 @@
|
|||
|
||||
#include "VLModel.h"
|
||||
|
||||
class VLSoundEvent {
|
||||
protected:
|
||||
VLSoundEvent() {}
|
||||
public:
|
||||
virtual ~VLSoundEvent();
|
||||
|
||||
virtual void Perform() {}
|
||||
};
|
||||
|
||||
class VLSoundScheduler {
|
||||
public:
|
||||
virtual void Schedule(VLSoundEvent * what, float when);
|
||||
|
||||
virtual ~VLSoundScheduler() {}
|
||||
};
|
||||
|
||||
class VLSoundOut {
|
||||
public:
|
||||
static VLSoundOut * Instance();
|
||||
static void SetScheduler(VLSoundScheduler * scheduler);
|
||||
|
||||
virtual void PlayNote(const VLNote & note) = 0;
|
||||
virtual void PlayChord(const VLChord & chord) = 0;
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "VLSoundSched.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
[VLSoundSched setup];
|
||||
return NSApplicationMain(argc, (const char **) argv);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -31,6 +31,7 @@
|
|||
95B3E1A70960E58B000E9C0D /* Music in Resources */ = {isa = PBXBuildFile; fileRef = 95B3E1980960E58B000E9C0D /* Music */; };
|
||||
95B66658096BCA1F00FE18C9 /* VLSheetViewNotes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95B66657096BCA1F00FE18C9 /* VLSheetViewNotes.mm */; };
|
||||
95BDA15909540BF1009F9D65 /* VLSheetView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95BDA15809540BF1009F9D65 /* VLSheetView.mm */; };
|
||||
95D44D1F0AD8BFEF00384FE5 /* VLSoundSched.mm in Sources */ = {isa = PBXBuildFile; fileRef = 95D44D1E0AD8BFEF00384FE5 /* VLSoundSched.mm */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -68,6 +69,8 @@
|
|||
95B66657096BCA1F00FE18C9 /* VLSheetViewNotes.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLSheetViewNotes.mm; path = Sources/VLSheetViewNotes.mm; sourceTree = "<group>"; };
|
||||
95BDA15709540BF1009F9D65 /* VLSheetView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLSheetView.h; path = Sources/VLSheetView.h; sourceTree = "<group>"; };
|
||||
95BDA15809540BF1009F9D65 /* VLSheetView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLSheetView.mm; path = Sources/VLSheetView.mm; sourceTree = "<group>"; };
|
||||
95D44D1D0AD8BFEF00384FE5 /* VLSoundSched.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLSoundSched.h; path = Sources/VLSoundSched.h; sourceTree = "<group>"; };
|
||||
95D44D1E0AD8BFEF00384FE5 /* VLSoundSched.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VLSoundSched.mm; path = Sources/VLSoundSched.mm; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -167,6 +170,8 @@
|
|||
952DCD77096BBB11001C2316 /* VLSheetViewChords.mm */,
|
||||
95B66656096BCA1F00FE18C9 /* VLSheetViewNotes.h */,
|
||||
95B66657096BCA1F00FE18C9 /* VLSheetViewNotes.mm */,
|
||||
95D44D1D0AD8BFEF00384FE5 /* VLSoundSched.h */,
|
||||
95D44D1E0AD8BFEF00384FE5 /* VLSoundSched.mm */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
|
@ -329,6 +334,7 @@
|
|||
952CBB9D095FD1CA00434E43 /* VLSoundOut.cpp in Sources */,
|
||||
952DCD78096BBB11001C2316 /* VLSheetViewChords.mm in Sources */,
|
||||
95B66658096BCA1F00FE18C9 /* VLSheetViewNotes.mm in Sources */,
|
||||
95D44D1F0AD8BFEF00384FE5 /* VLSoundSched.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -447,7 +453,7 @@
|
|||
GCC_PREFIX_HEADER = Sources/Vocalese_Prefix.pch;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INFOPLIST_FILE = Resources/Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Applications";
|
||||
PREBINDING = NO;
|
||||
PRODUCT_NAME = Vocalese;
|
||||
|
|
Loading…
Reference in New Issue
Block a user