Highlight chords (badly), nonblocking sound

This commit is contained in:
Matthias Neeracher 2006-10-08 05:56:25 +00:00
parent 50da584417
commit cbc2b31da8
13 changed files with 989 additions and 1298 deletions

Binary file not shown.

View File

@ -16,6 +16,9 @@
- (NSString *) stringValue;
- (void) setStringValue:(NSString*)val;
- (BOOL) validValue:(NSString*)val;
- (void) moveToNext;
- (void) moveToPrev;
- (void) highlightCursor;
@end

View File

@ -24,6 +24,18 @@
return YES;
}
- (void) moveToNext
{
}
- (void) moveToPrev
{
}
- (void) highlightCursor
{
}
@end
@implementation VLDocument

View File

@ -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;
}

View File

@ -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
@ -317,15 +330,16 @@ static float sFlatPos[] = {
[self drawGridForSystem:system];
[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

View File

@ -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

View File

@ -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

View File

@ -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);
};
static std::auto_ptr<VLSoundOut> sSoundOut;
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);
}

View File

@ -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;

View File

@ -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

View File

@ -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;