Play selection / cursor

This commit is contained in:
Matthias Neeracher 2011-09-11 23:27:53 +02:00
parent 72c4ac4d2b
commit 19c8663dcd
11 changed files with 151 additions and 47 deletions

View File

@ -11,6 +11,7 @@
#import "VLModel.h" #import "VLModel.h"
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "VLKeyValueUndo.h" #import "VLKeyValueUndo.h"
#import <AudioToolbox/AudioToolbox.h>
@class VLSheetWindow; @class VLSheetWindow;
@ -56,7 +57,7 @@ enum {
NSMutableDictionary*validTmpFiles; NSMutableDictionary*validTmpFiles;
int repeatVolta; int repeatVolta;
bool brandNew; bool brandNew;
bool hasMusicSequence; MusicSequence musicSequence;
VLSheetWindow * sheetWin; VLSheetWindow * sheetWin;
VLKeyValueUndo* undo; VLKeyValueUndo* undo;
VLKeyValueUndo* staffMetrics; VLKeyValueUndo* staffMetrics;

View File

@ -102,7 +102,7 @@
vcsWrapper = nil; vcsWrapper = nil;
repeatVolta = 2; repeatVolta = 2;
brandNew = true; brandNew = true;
hasMusicSequence = false; musicSequence = nil;
playRate = 1.0; playRate = 1.0;
validTmpFiles = [[NSMutableDictionary alloc] initWithCapacity:10]; validTmpFiles = [[NSMutableDictionary alloc] initWithCapacity:10];
[self setHasUndoManager:YES]; [self setHasUndoManager:YES];
@ -138,7 +138,7 @@
- (void)updateChangeCount:(NSDocumentChangeType)changeType - (void)updateChangeCount:(NSDocumentChangeType)changeType
{ {
hasMusicSequence = false; musicSequence = nil;
[validTmpFiles removeAllObjects]; [validTmpFiles removeAllObjects];
[super updateChangeCount:changeType]; [super updateChangeCount:changeType];
} }
@ -458,15 +458,16 @@
- (void) playSong - (void) playSong
{ {
if (hasMusicSequence) { if (musicSequence) {
void (^finalizer)() = [sheetWin willPlaySequence:musicSequence];
VLSoundOut::Instance()->PlaySequence(NULL); VLSoundOut::Instance()->PlaySequence(NULL);
finalizer();
} else { } else {
[self createTmpFileWithExtension:@"mid" ofType:VLMIDIType]; [self createTmpFileWithExtension:@"mid" ofType:VLMIDIType];
MusicSequence music; NewMusicSequence(&musicSequence);
NewMusicSequence(&music);
MusicSequenceFileLoad(music, (CFURLRef)[self fileURLWithExtension:@"mid"], MusicSequenceFileLoad(musicSequence, (CFURLRef)[self fileURLWithExtension:@"mid"],
0, 0); 0, 0);
size_t countIn = 0; size_t countIn = 0;
@ -477,14 +478,14 @@
case 0x608: case 0x608:
countIn = 2; countIn = 2;
} }
VLMIDIWriter annotate(music, countIn); VLMIDIWriter annotate(musicSequence, countIn);
annotate.Visit(*song); annotate.Visit(*song);
hasMusicSequence = true;
[sheetWin willPlaySequence:music];
baseTempo = songTempo; baseTempo = songTempo;
VLSoundOut::Instance()->SetPlayRate(playRate); void (^finalizer)() = [sheetWin willPlaySequence:musicSequence];
VLSoundOut::Instance()->PlaySequence(music); VLSoundOut::Instance()->SetPlayRate(playRate);
VLSoundOut::Instance()->PlaySequence(musicSequence);
finalizer();
} }
[self setPlayElements:[self playElements]]; [self setPlayElements:[self playElements]];
} }
@ -494,7 +495,7 @@
NSString * savedGroove = songGroove; NSString * savedGroove = songGroove;
[validTmpFiles removeObjectForKey:@"mma"]; [validTmpFiles removeObjectForKey:@"mma"];
[validTmpFiles removeObjectForKey:@"mid"]; [validTmpFiles removeObjectForKey:@"mid"];
hasMusicSequence = false; musicSequence = nil;
songGroove = groove; songGroove = groove;
previewRange = sections; previewRange = sections;
playElements |= kVLPlayGroovePreview; playElements |= kVLPlayGroovePreview;
@ -503,7 +504,7 @@
songGroove = savedGroove; songGroove = savedGroove;
[validTmpFiles removeObjectForKey:@"mma"]; [validTmpFiles removeObjectForKey:@"mma"];
[validTmpFiles removeObjectForKey:@"mid"]; [validTmpFiles removeObjectForKey:@"mid"];
hasMusicSequence = false; musicSequence = nil;
} }
- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings - (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings

View File

@ -11,6 +11,50 @@
#include "VLMIDIWriter.h" #include "VLMIDIWriter.h"
#include <AudioToolbox/AudioToolbox.h> #include <AudioToolbox/AudioToolbox.h>
VLMIDIUtilities::VLMIDIUtilities(MusicSequence music)
: fMusic(music)
{
}
MusicTimeStamp VLMIDIUtilities::Length()
{
UInt32 ntracks;
MusicSequenceGetTrackCount(fMusic, &ntracks);
MusicTimeStamp sequenceLength = 0;
for (UInt32 i = 0; i < ntracks; ++i) {
MusicTrack track;
MusicTimeStamp trackLength;
UInt32 propsize = sizeof(MusicTimeStamp);
MusicSequenceGetIndTrack(fMusic, i, &track);
MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
&trackLength, &propsize);
sequenceLength = std::max(sequenceLength, trackLength);
}
return sequenceLength;
}
MusicTimeStamp VLMIDIUtilities::Find(VLLocation at)
{
UInt32 ntracks;
MusicSequenceGetTrackCount(fMusic, &ntracks);
MusicTrack track;
MusicSequenceGetIndTrack(fMusic, ntracks-1, &track);
MusicEventIterator iter;
NewMusicEventIterator(track, &iter);
Boolean hasEvent;
while (!MusicEventIteratorHasCurrentEvent(iter, &hasEvent) && hasEvent) {
MusicTimeStamp ts;
MusicEventType ty;
const VLMIDIUserEvent * data;
UInt32 sz;
MusicEventIteratorGetEventInfo(iter, &ts, &ty, (const void **)&data, &sz);
if (ty == kMusicEventType_User && data->fAt >= at)
return ts;
MusicEventIteratorNextEvent(iter);
}
return Length();
}
struct VLMetaEvent : MIDIMetaEvent { struct VLMetaEvent : MIDIMetaEvent {
char fPadding[32]; char fPadding[32];

View File

@ -20,6 +20,16 @@ struct VLMIDIUserEvent {
VLLocation fAt; VLLocation fAt;
}; };
class VLMIDIUtilities {
public:
VLMIDIUtilities(MusicSequence music);
MusicTimeStamp Length();
MusicTimeStamp Find(VLLocation at);
public:
MusicSequence fMusic;
};
class VLMIDIWriter: public VLSongVisitor { class VLMIDIWriter: public VLSongVisitor {
public: public:
VLMIDIWriter(MusicSequence music, size_t countIn) VLMIDIWriter(MusicSequence music, size_t countIn)

View File

@ -13,6 +13,9 @@
#include <string> #include <string>
#include <inttypes.h> #include <inttypes.h>
#ifndef __VLMODEL__
#define __VLMODEL__
#pragma mark - #pragma mark -
#pragma mark class VLFraction #pragma mark class VLFraction
@ -497,6 +500,8 @@ protected:
void VisitChords(VLMeasure & measure); void VisitChords(VLMeasure & measure);
}; };
#endif
// Local Variables: // Local Variables:
// mode:C++ // mode:C++
// End: // End:

View File

@ -36,7 +36,8 @@
- (void)updateMenus; - (void)updateMenus;
- (void) willPlaySequence:(MusicSequence)music; - (void (^)()) willPlaySequence:(MusicSequence)music;
- (void) playWasPaused;
@end @end

View File

@ -17,6 +17,8 @@
#import "VLSheetWindow.h" #import "VLSheetWindow.h"
#import "VLDocument.h" #import "VLDocument.h"
#import "VLPitchGrid.h" #import "VLPitchGrid.h"
#import "VLSoundOut.h"
#import "VLMIDIWriter.h"
#pragma mark VLMeasureEditable #pragma mark VLMeasureEditable
@ -126,6 +128,11 @@
return self; return self;
} }
- (void)dealloc
{
[fView setNeedsDisplay:YES];
}
- (void) userEvent:(const VLMIDIUserEvent *) event - (void) userEvent:(const VLMIDIUserEvent *) event
{ {
if (event->fPitch) { if (event->fPitch) {
@ -583,12 +590,28 @@ inline int TimeTag(const VLProperties & prop)
[self updateGrooveMenu]; [self updateGrooveMenu];
} }
- (void) willPlaySequence:(MusicSequence)music - (void (^)()) willPlaySequence:(MusicSequence)music
{ {
uint32_t selStart = fSelStart;
uint32_t selEnd = fSelEnd;
VLEditable * e = VLEditable * e =
[[VLPlaybackEditable alloc] initWithView:self]; [[VLPlaybackEditable alloc] initWithView:self];
[self setEditTarget:e]; [self setEditTarget:e];
MusicSequenceSetUserCallback(music, VLSequenceCallback, e); MusicSequenceSetUserCallback(music, VLSequenceCallback, e);
return [Block_copy(^{
if (selEnd != kNoMeasure) {
VLMIDIUtilities locator(music);
VLLocation start = {selStart, VLFraction(0)};
VLLocation end = {selEnd, VLFraction(0)};
VLSoundOut::Instance()->SetStart(locator.Find(start));
if (selEnd > selStart) {
VLSoundOut::Instance()->SetEnd(locator.Find(end));
[self selectMeasure:selStart to:selEnd];
}
}
}) autorelease];
} }
@end @end

View File

@ -64,7 +64,7 @@
- (void) setEditTarget:(VLEditable *)editable; - (void) setEditTarget:(VLEditable *)editable;
- (void) startAnimation; - (void) startAnimation;
- (void) stopAnimation; - (void) stopAnimation;
- (void) willPlaySequence:(MusicSequence)music; - (void (^)()) willPlaySequence:(MusicSequence)music;
- (void) showLogAndBeep; - (void) showLogAndBeep;
@end @end

View File

@ -77,6 +77,8 @@
soundStopObserver = [nc addObserverForName:(NSString*)kVLSoundStoppedNotification soundStopObserver = [nc addObserverForName:(NSString*)kVLSoundStoppedNotification
object:nil queue:oq usingBlock:^(NSNotification *note) { object:nil queue:oq usingBlock:^(NSNotification *note) {
[[[self window] toolbar] validateVisibleItems]; [[[self window] toolbar] validateVisibleItems];
if (VLSoundOut::Instance()->AtBeginning())
[self setEditTarget:nil]; // Kill note cursor if we ran to end
}]; }];
} }
return self; return self;
@ -96,8 +98,10 @@
- (void)setEditTarget:(VLEditable *)editable - (void)setEditTarget:(VLEditable *)editable
{ {
[editTarget autorelease]; if (editTarget != editable) {
editTarget = editable; [editTarget release];
editTarget = editable;
}
} }
- (void) startAnimation - (void) startAnimation
@ -125,9 +129,9 @@
[sheetView mouseMoved:event]; [sheetView mouseMoved:event];
} }
- (void) willPlaySequence:(MusicSequence)music - (void (^)()) willPlaySequence:(MusicSequence)music
{ {
[sheetView willPlaySequence:music]; return [sheetView willPlaySequence:music];
} }
- (IBAction) togglePlayElements:(id)sender - (IBAction) togglePlayElements:(id)sender
@ -183,7 +187,7 @@
- (IBAction) playStop:(id)sender - (IBAction) playStop:(id)sender
{ {
if (VLSoundOut::Instance()->Playing()) if (VLSoundOut::Instance()->Playing())
[self stop:sender]; [self stop:sender];
else else
[[self document] playSong]; [[self document] playSong];

View File

@ -9,6 +9,7 @@
// //
#include "VLSoundOut.h" #include "VLSoundOut.h"
#include "VLMIDIWriter.h"
#include <AudioUnit/AudioUnit.h> #include <AudioUnit/AudioUnit.h>
@ -31,9 +32,12 @@ public:
virtual void PlayNote(const VLNote & note); virtual void PlayNote(const VLNote & note);
virtual void PlayChord(const VLChord & chord); virtual void PlayChord(const VLChord & chord);
virtual void PlaySequence(MusicSequence music); virtual void PlaySequence(MusicSequence music);
virtual void SetStart(MusicTimeStamp start);
virtual void SetEnd(MusicTimeStamp end);
virtual void Stop(bool pause); virtual void Stop(bool pause);
virtual bool Playing(); virtual bool Playing();
virtual bool AtEnd(); virtual bool AtEnd();
virtual bool AtBeginning();
virtual void SetPlayRate(float rate); virtual void SetPlayRate(float rate);
virtual void Fwd(); virtual void Fwd();
virtual void Bck(); virtual void Bck();
@ -47,16 +51,16 @@ protected:
void InitSoundOutput(bool fileOutput); void InitSoundOutput(bool fileOutput);
virtual void SetupOutput(AUNode outputNode); virtual void SetupOutput(AUNode outputNode);
MusicTimeStamp SequenceLength(MusicSequence music);
void SkipTimeInterval(); void SkipTimeInterval();
AUGraph fGraph; AUGraph fGraph;
MusicPlayer fPlayer; MusicPlayer fPlayer;
private: private:
MusicSequence fMusic; MusicSequence fMusic;
MusicTimeStamp fMusicLength; MusicTimeStamp fMusicEnd;
bool fRunning; bool fRunning;
bool fForward; bool fForward;
bool fWasAtEnd;
float fPlayRate; float fPlayRate;
dispatch_source_t fMusicPoll; dispatch_source_t fMusicPoll;
@ -157,7 +161,7 @@ VLSoundOut::~VLSoundOut()
} }
VLAUSoundOut::VLAUSoundOut() VLAUSoundOut::VLAUSoundOut()
: fMusic(0), fRunning(false), fForward(true) : fMusic(0), fRunning(false), fForward(true), fWasAtEnd(true)
{ {
InitSoundOutput(false); InitSoundOutput(false);
fMusicPoll = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); fMusicPoll = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
@ -245,8 +249,9 @@ void VLAUSoundOut::PlaySequence(MusicSequence music)
Stop(false); Stop(false);
fMusic = music; fMusic = music;
fMusicLength = SequenceLength(music); fMusicEnd = VLMIDIUtilities(music).Length();
fPlayRate = 1.0; fPlayRate = 1.0;
fWasAtEnd = true;
R(MusicSequenceSetAUGraph(fMusic, fGraph)); R(MusicSequenceSetAUGraph(fMusic, fGraph));
R(MusicPlayerSetSequence(fPlayer, fMusic)); R(MusicPlayerSetSequence(fPlayer, fMusic));
@ -256,7 +261,19 @@ void VLAUSoundOut::PlaySequence(MusicSequence music)
fRunning = true; fRunning = true;
CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), kVLSoundStartedNotification, CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), kVLSoundStartedNotification,
NULL, NULL, false); NULL, NULL, false);
dispatch_source_set_timer(fMusicPoll, DISPATCH_TIME_NOW, 500*NSEC_PER_MSEC, 200*NSEC_PER_MSEC); dispatch_source_set_timer(fMusicPoll, DISPATCH_TIME_NOW, 10*NSEC_PER_MSEC, 200*NSEC_PER_MSEC);
}
void VLAUSoundOut::SetStart(MusicTimeStamp start)
{
if (fWasAtEnd)
MusicPlayerSetTime(fPlayer, start);
}
void VLAUSoundOut::SetEnd(MusicTimeStamp end)
{
if (fWasAtEnd)
fMusicEnd = end;
} }
void VLAUSoundOut::SetMelodyState(VLSoundOut::MelodyState state) void VLAUSoundOut::SetMelodyState(VLSoundOut::MelodyState state)
@ -282,7 +299,7 @@ void VLAUSoundOut::SetPlayRate(float rate)
MusicTimeStamp rightNow; MusicTimeStamp rightNow;
MusicPlayerGetTime(fPlayer, &rightNow); MusicPlayerGetTime(fPlayer, &rightNow);
MusicSequenceReverse(fMusic); MusicSequenceReverse(fMusic);
MusicPlayerSetTime(fPlayer, fMusicLength - rightNow); MusicPlayerSetTime(fPlayer, fMusicEnd - rightNow);
} }
fPlayRate = fabsf(rate); fPlayRate = fabsf(rate);
MusicPlayerSetPlayRateScalar(fPlayer, fPlayRate); MusicPlayerSetPlayRateScalar(fPlayer, fPlayRate);
@ -343,8 +360,12 @@ void VLAUSoundOut::Slow(float rate)
void VLAUSoundOut::Stop(bool pause) void VLAUSoundOut::Stop(bool pause)
{ {
if (!fRunning)
return;
MusicPlayerStop(fPlayer); MusicPlayerStop(fPlayer);
fRunning = false; fRunning = false;
fWasAtEnd = false;
if (!pause && fMusic) { if (!pause && fMusic) {
MusicPlayerSetSequence(fPlayer, NULL); MusicPlayerSetSequence(fPlayer, NULL);
DisposeMusicSequence(fMusic); DisposeMusicSequence(fMusic);
@ -364,7 +385,14 @@ bool VLAUSoundOut::AtEnd()
{ {
MusicTimeStamp time; MusicTimeStamp time;
return !MusicPlayerGetTime(fPlayer, &time) && time >= fMusicLength; return !MusicPlayerGetTime(fPlayer, &time) && time >= fMusicEnd;
}
bool VLAUSoundOut::AtBeginning()
{
MusicTimeStamp time;
return MusicPlayerGetTime(fPlayer, &time) || !time;
} }
void VLAUSoundOut::PollMusic() void VLAUSoundOut::PollMusic()
@ -372,6 +400,7 @@ void VLAUSoundOut::PollMusic()
if (fRunning && AtEnd()) { if (fRunning && AtEnd()) {
MusicPlayerSetTime(fPlayer, 0); MusicPlayerSetTime(fPlayer, 0);
Stop(true); Stop(true);
fWasAtEnd = true;
} }
} }
@ -412,23 +441,6 @@ void VLAUSoundOut::Play(const int8_t * note, size_t numNotes)
PlaySequence(music); PlaySequence(music);
} }
MusicTimeStamp VLAUSoundOut::SequenceLength(MusicSequence music)
{
UInt32 ntracks;
MusicSequenceGetTrackCount(music, &ntracks);
MusicTimeStamp sequenceLength = 0;
for (UInt32 i = 0; i < ntracks; ++i) {
MusicTrack track;
MusicTimeStamp trackLength;
UInt32 propsize = sizeof(MusicTimeStamp);
MusicSequenceGetIndTrack(music, i, &track);
MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength,
&trackLength, &propsize);
sequenceLength = std::max(sequenceLength, trackLength);
}
return sequenceLength;
}
VLAUFileSoundOut::VLAUFileSoundOut(CFURLRef file, OSType dataFormat) VLAUFileSoundOut::VLAUFileSoundOut(CFURLRef file, OSType dataFormat)
: VLAUSoundOut(true), fFile(file), fDataFormat(dataFormat) : VLAUSoundOut(true), fFile(file), fDataFormat(dataFormat)
{ {
@ -459,7 +471,7 @@ void VLAUFileSoundOut::PlaySequence(MusicSequence music)
UInt32 size; UInt32 size;
UInt32 numFrames = 512; UInt32 numFrames = 512;
MusicTimeStamp musicLen = SequenceLength(music)+8; MusicTimeStamp musicLen = VLMIDIUtilities(music).Length()+8;
CFStringRef name = CFStringRef name =
CFURLCopyLastPathComponent(fFile); CFURLCopyLastPathComponent(fFile);
CAAudioFileFormats * formats = CAAudioFileFormats::Instance(); CAAudioFileFormats * formats = CAAudioFileFormats::Instance();

View File

@ -42,9 +42,12 @@ public:
virtual void PlayChord(const VLChord & chord) = 0; virtual void PlayChord(const VLChord & chord) = 0;
void PlayFile(CFDataRef file); void PlayFile(CFDataRef file);
virtual void PlaySequence(MusicSequence music) = 0; virtual void PlaySequence(MusicSequence music) = 0;
virtual void SetStart(MusicTimeStamp start) = 0;
virtual void SetEnd(MusicTimeStamp end) = 0;
virtual void Stop(bool pause=true) = 0; virtual void Stop(bool pause=true) = 0;
virtual bool Playing() = 0; virtual bool Playing() = 0;
virtual bool AtEnd() = 0; virtual bool AtEnd() = 0;
virtual bool AtBeginning() = 0;
virtual void SetPlayRate(float rate) = 0; virtual void SetPlayRate(float rate) = 0;
virtual void Fwd() = 0; virtual void Fwd() = 0;
virtual void Bck() = 0; virtual void Bck() = 0;