mirror of
https://github.com/microtherion/VocalEasel.git
synced 2024-12-22 11:14:00 +00:00
Refactor music playing code
This commit is contained in:
parent
ab32c3cc12
commit
273ee8ee73
|
@ -41,7 +41,7 @@ enum {
|
|||
NSString * songComposer;
|
||||
NSString * songArranger;
|
||||
NSString * songGroove;
|
||||
NSNumber * songTempo;
|
||||
float songTempo;
|
||||
float chordSize;
|
||||
float lyricSize;
|
||||
float staffSize;
|
||||
|
@ -65,6 +65,7 @@ enum {
|
|||
float baseTempo;
|
||||
}
|
||||
|
||||
@property (nonatomic) float songTempo;
|
||||
@property (nonatomic) int playElements;
|
||||
|
||||
- (VLSong *) song;
|
||||
|
@ -83,12 +84,8 @@ enum {
|
|||
|
||||
- (void) setRepeatVolta:(int)repeatVolta;
|
||||
|
||||
- (IBAction) play:(id)sender;
|
||||
- (IBAction) stop:(id)sender;
|
||||
- (IBAction) playStop:(id)sender;
|
||||
- (IBAction) playMusic:(id)sender;
|
||||
- (IBAction) adjustTempo:(id)sender;
|
||||
|
||||
- (void) playSong;
|
||||
|
||||
- (NSURL *) tmpURL;
|
||||
- (NSURL *) workURL;
|
||||
- (NSString *) baseName;
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
|
||||
@implementation VLDocument
|
||||
|
||||
@synthesize playElements;
|
||||
@synthesize songTempo, playElements;
|
||||
|
||||
+ (BOOL)autosavesInPlace
|
||||
{
|
||||
|
@ -87,7 +87,7 @@
|
|||
songArranger = @"";
|
||||
songGroove = @"Swing";
|
||||
playElements = kVLPlayAccompaniment|kVLPlayMelody|kVLPlayCountIn;
|
||||
songTempo = [[NSNumber alloc] initWithInt:120];
|
||||
songTempo = 120.0f;
|
||||
baseTempo = 120.0f;
|
||||
chordSize = 6.0f;
|
||||
lyricSize = 0.0f;
|
||||
|
@ -142,7 +142,7 @@
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
VLSoundOut::Instance()->Stop();
|
||||
VLSoundOut::Instance()->Stop(false);
|
||||
|
||||
delete song;
|
||||
|
||||
|
@ -237,13 +237,12 @@
|
|||
[self didChangeSong];
|
||||
}
|
||||
|
||||
- (void) setSongTempo:(int)tempo
|
||||
- (void) setSongTempo:(float)tempo
|
||||
{
|
||||
if (tempo == [songTempo intValue])
|
||||
if (tempo == songTempo)
|
||||
return;
|
||||
|
||||
[songTempo autorelease];
|
||||
songTempo = [[NSNumber numberWithInt:tempo] retain];
|
||||
songTempo = tempo;
|
||||
if (VLSoundOut::Instance()->Playing())
|
||||
VLSoundOut::Instance()->SetPlayRate(playRate*tempo/baseTempo);
|
||||
}
|
||||
|
@ -466,7 +465,7 @@
|
|||
return task;
|
||||
}
|
||||
|
||||
- (IBAction) play:(id)sender
|
||||
- (void) playSong
|
||||
{
|
||||
if (hasMusicSequence) {
|
||||
VLSoundOut::Instance()->PlaySequence(NULL);
|
||||
|
@ -492,7 +491,7 @@
|
|||
|
||||
hasMusicSequence = true;
|
||||
[sheetWin willPlaySequence:music];
|
||||
baseTempo = [songTempo floatValue];
|
||||
baseTempo = songTempo;
|
||||
VLSoundOut::Instance()->SetPlayRate(playRate);
|
||||
VLSoundOut::Instance()->PlaySequence(music);
|
||||
}
|
||||
|
@ -507,7 +506,7 @@
|
|||
songGroove = groove;
|
||||
previewRange = sections;
|
||||
playElements |= kVLPlayGroovePreview;
|
||||
[self play:groove];
|
||||
[self playSong];
|
||||
playElements &= ~kVLPlayGroovePreview;
|
||||
songGroove = savedGroove;
|
||||
[validTmpFiles removeObjectForKey:@"mma"];
|
||||
|
@ -515,49 +514,6 @@
|
|||
hasMusicSequence = false;
|
||||
}
|
||||
|
||||
- (IBAction) stop:(id)sender
|
||||
{
|
||||
VLSoundOut::Instance()->Stop();
|
||||
}
|
||||
|
||||
- (IBAction) playStop:(id)sender
|
||||
{
|
||||
if (VLSoundOut::Instance()->Playing()) {
|
||||
[self stop:sender];
|
||||
if ([sender isKindOfClass:[NSMenuItem class]]) {
|
||||
[sender setTitle:@"Play"];
|
||||
} else {
|
||||
[sender setLabel:@"Play"];
|
||||
[sender setImage:[NSImage imageNamed:@"play.icns"]];
|
||||
}
|
||||
} else {
|
||||
[self play:sender];
|
||||
if ([sender isKindOfClass:[NSMenuItem class]]) {
|
||||
[sender setTitle:@"Stop"];
|
||||
} else {
|
||||
[sender setLabel:@"Stop"];
|
||||
[sender setImage:[NSImage imageNamed:@"stop.icns"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) playMusic:(id)sender
|
||||
{
|
||||
switch ([sender tag]) {
|
||||
case 1: // Fwd
|
||||
VLSoundOut::Instance()->Fwd();
|
||||
break;
|
||||
case -1: // Rew
|
||||
VLSoundOut::Instance()->Bck();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) adjustTempo:(id)sender
|
||||
{
|
||||
[self setSongTempo:[songTempo intValue]+[sender tag]];
|
||||
}
|
||||
|
||||
- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings
|
||||
error:(NSError **)outError
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class VLSheetView;
|
||||
@class VLDocument;
|
||||
@class VLSheetWindow;
|
||||
|
||||
@interface VLGrooveController : NSWindowController {
|
||||
NSDictionary * fGrooves;
|
||||
|
@ -24,7 +24,7 @@
|
|||
NSArray * fSubStyleList;
|
||||
NSPredicate * fSubStyleFilter;
|
||||
VLSheetView * fView;
|
||||
VLDocument * fDocument;
|
||||
VLSheetWindow * fSheetWin;
|
||||
}
|
||||
|
||||
- (id) initWithSheetView:(VLSheetView *)view;
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
//
|
||||
// (MN) Matthias Neeracher
|
||||
//
|
||||
// Copyright © 2007 Matthias Neeracher
|
||||
// Copyright © 2007-2011 Matthias Neeracher
|
||||
//
|
||||
|
||||
#import "VLGrooveController.h"
|
||||
#import "VLSheetView.h"
|
||||
#import "VLDocument.h"
|
||||
#import "VLSheetWindow.h"
|
||||
|
||||
@implementation VLGrooveController
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
|||
@"!(SELF matches[c] '.*(Intro|End)\\\\d*$')"]
|
||||
retain];
|
||||
fView = view;
|
||||
fDocument = [view document];
|
||||
fSheetWin = (VLSheetWindow *)[view window];
|
||||
|
||||
[NSApp beginSheet: [self window]
|
||||
modalForWindow: [view window]
|
||||
|
@ -46,7 +46,7 @@
|
|||
if ([sender state])
|
||||
[fView playWithGroove:[[fBrowser selectedCellInColumn:1] stringValue]];
|
||||
else
|
||||
[fDocument stop:sender];
|
||||
[fSheetWin stop:self];
|
||||
}
|
||||
|
||||
- (IBAction)endSheet:(id)sender
|
||||
|
@ -56,7 +56,7 @@
|
|||
|
||||
- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
|
||||
{
|
||||
[fDocument stop:self];
|
||||
[fSheetWin stop:self];
|
||||
if (returnCode == NSAlertFirstButtonReturn)
|
||||
[fView setGroove:[[fBrowser selectedCellInColumn:1] stringValue]];
|
||||
|
||||
|
@ -119,7 +119,7 @@
|
|||
[fSubStyles objectForKey:@".DESC"],
|
||||
[fSubStyles objectForKey:
|
||||
[[fBrowser selectedCellInColumn:1] stringValue]]]];
|
||||
[fDocument stop:self];
|
||||
[fSheetWin stop:self];
|
||||
[self togglePlay:fPlayButton];
|
||||
} else
|
||||
[fDescription setStringValue:[fSubStyles objectForKey:@".DESC"]];
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
+ (const char *)[[bndl objectForInfoDictionaryKey:@"CFBundleVersion"]
|
||||
UTF8String]
|
||||
+ "\n\n";
|
||||
sprintf(buf, "Tempo %d\n", [songTempo intValue]);
|
||||
sprintf(buf, "Tempo %ld\n", lround(songTempo));
|
||||
mmaFile += buf;
|
||||
if (playElements & kVLPlayGroovePreview) {
|
||||
//
|
||||
|
|
|
@ -243,7 +243,7 @@ void VLPlistVisitor::VisitChord(VLChord & c)
|
|||
{
|
||||
NSMutableDictionary * plist =
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
songTitle, @"title", songTempo, @"tempo",
|
||||
songTitle, @"title", [NSNumber numberWithLong:lround(songTempo)], @"tempo",
|
||||
[NSString stringWithUTF8String:song->PrimaryGroove().c_str()], @"groove",
|
||||
songComposer, @"composer", songLyricist, @"lyricist",
|
||||
[NSDate date], @"saved",
|
||||
|
|
|
@ -120,6 +120,7 @@ enum VLCursorVisual {
|
|||
- (IBAction) editDisplayOptions:(id)sender;
|
||||
- (IBAction) transposeOctave:(id)sender;
|
||||
|
||||
|
||||
- (VLDocument *) document;
|
||||
- (VLSong *) song;
|
||||
- (NSImage *) musicElement:(VLMusicElement)elt;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
IBOutlet NSProgressIndicator * progressIndicator;
|
||||
IBOutlet VLLogWindow * logWin;
|
||||
IBOutlet VLPDFWindow * pdfWin;
|
||||
id soundStartObserver;
|
||||
id soundStopObserver;
|
||||
|
||||
|
||||
VLEditable * editTarget;
|
||||
|
@ -46,6 +48,10 @@
|
|||
|
||||
- (IBAction) togglePlayElements:(id)sender;
|
||||
- (IBAction) showOutput:(id)sender;
|
||||
- (IBAction) stop:(id)sender;
|
||||
- (IBAction) playStop:(id)sender;
|
||||
- (IBAction) playMusic:(id)sender;
|
||||
- (IBAction) adjustTempo:(id)sender;
|
||||
|
||||
- (VLEditable *) editTarget;
|
||||
- (void) setEditTarget:(VLEditable *)editable;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#import "VLDocument.h"
|
||||
#import "VLPDFWindow.h"
|
||||
#import "VLLogWindow.h"
|
||||
#import "VLSoundOut.h"
|
||||
|
||||
@implementation VLEditable
|
||||
|
||||
|
@ -51,10 +52,27 @@
|
|||
{
|
||||
if (self = [super initWithWindow:window]) {
|
||||
editTarget = nil;
|
||||
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
|
||||
NSOperationQueue * oq = [NSOperationQueue mainQueue];
|
||||
soundStartObserver = [nc addObserverForName:(NSString*)kVLSoundStartedNotification
|
||||
object:nil queue:oq usingBlock:^(NSNotification *note) {
|
||||
[[[self window] contentView] setNeedsDisplay:YES];
|
||||
}];
|
||||
soundStopObserver = [nc addObserverForName:(NSString*)kVLSoundStoppedNotification
|
||||
object:nil queue:oq usingBlock:^(NSNotification *note) {
|
||||
[[[self window] contentView] setNeedsDisplay:YES];
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:soundStartObserver];
|
||||
[nc removeObserver:soundStopObserver];
|
||||
}
|
||||
|
||||
- (VLEditable *)editTarget
|
||||
{
|
||||
return editTarget;
|
||||
|
@ -100,11 +118,25 @@
|
|||
[[self document] setPlayElements:[[self document] playElements] ^ [sender tag]];
|
||||
}
|
||||
|
||||
- (BOOL) validateMenuItem:(NSMenuItem *)menuItem
|
||||
- (BOOL) validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
|
||||
{
|
||||
if ([menuItem action] == @selector(togglePlayElements:))
|
||||
if (int tag = [menuItem tag])
|
||||
if ([item action] == @selector(togglePlayElements:)) {
|
||||
NSMenuItem * menuItem = (NSMenuItem *)item;
|
||||
if (int tag = [item tag])
|
||||
[menuItem setState:([[self document] playElements] & tag) != 0];
|
||||
} else if ([item action] == @selector(playStop:)) {
|
||||
NSMenuItem * menuItem = [(NSObject *)item isKindOfClass:[NSMenuItem class]] ? (NSMenuItem *)item : nil;
|
||||
NSToolbarItem * toolItem = menuItem ? nil : (NSToolbarItem *)item;
|
||||
if (VLSoundOut::Instance()->Playing()) {
|
||||
[menuItem setTitle:@"Stop"];
|
||||
[toolItem setLabel:@"Stop"];
|
||||
[toolItem setImage:[NSImage imageNamed:@"stop.icns"]];
|
||||
} else {
|
||||
[menuItem setTitle:@"Play"];
|
||||
[toolItem setLabel:@"Play"];
|
||||
[toolItem setImage:[NSImage imageNamed:@"play.icns"]];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
@ -127,4 +159,35 @@
|
|||
[pdfWin reloadPDF];
|
||||
}
|
||||
|
||||
- (IBAction) stop:(id)sender
|
||||
{
|
||||
VLSoundOut::Instance()->Stop();
|
||||
}
|
||||
|
||||
- (IBAction) playStop:(id)sender
|
||||
{
|
||||
if (VLSoundOut::Instance()->Playing())
|
||||
[self stop:sender];
|
||||
else
|
||||
[[self document] playSong];
|
||||
}
|
||||
|
||||
- (IBAction) playMusic:(id)sender
|
||||
{
|
||||
switch ([sender tag]) {
|
||||
case 1: // Fwd
|
||||
VLSoundOut::Instance()->Fwd();
|
||||
break;
|
||||
case -1: // Rew
|
||||
VLSoundOut::Instance()->Bck();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction) adjustTempo:(id)sender
|
||||
{
|
||||
[[self document] setSongTempo:[[self document] songTempo]+[sender tag]];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//
|
||||
// (MN) Matthias Neeracher
|
||||
//
|
||||
// Copyright © 2005-2007 Matthias Neeracher
|
||||
// Copyright © 2005-2011 Matthias Neeracher
|
||||
//
|
||||
|
||||
#include "VLSoundOut.h"
|
||||
|
@ -21,6 +21,9 @@
|
|||
|
||||
#define R(x) if (OSStatus r = (x)) fprintf(stderr, "%s -> %d\n", #x, r);
|
||||
|
||||
CFStringRef kVLSoundStartedNotification = CFSTR("VLSoundStarted");
|
||||
CFStringRef kVLSoundStoppedNotification = CFSTR("VLSoundStopped");
|
||||
|
||||
class VLAUSoundOut : public VLSoundOut {
|
||||
public:
|
||||
VLAUSoundOut();
|
||||
|
@ -36,23 +39,25 @@ public:
|
|||
virtual void Bck();
|
||||
|
||||
virtual ~VLAUSoundOut();
|
||||
void PollMusic();
|
||||
protected:
|
||||
VLAUSoundOut(bool fileOutput);
|
||||
|
||||
void InitSoundOutput(bool fileOutput);
|
||||
virtual void SetupOutput(AUNode outputNode);
|
||||
MusicTimeStamp SequenceLength(MusicSequence music);
|
||||
MusicTimeStamp SequenceLength(MusicSequence music);
|
||||
void SkipTimeInterval();
|
||||
|
||||
AUGraph fGraph;
|
||||
MusicPlayer fPlayer;
|
||||
AUGraph fGraph;
|
||||
MusicPlayer fPlayer;
|
||||
private:
|
||||
MusicSequence fMusic;
|
||||
MusicTimeStamp fMusicLength;
|
||||
bool fRunning;
|
||||
bool fForward;
|
||||
MusicSequence fMusic;
|
||||
MusicTimeStamp fMusicLength;
|
||||
bool fRunning;
|
||||
bool fForward;
|
||||
dispatch_source_t fMusicPoll;
|
||||
|
||||
void Play(const int8_t * note, size_t numNotes = 1);
|
||||
void Play(const int8_t * note, size_t numNotes = 1);
|
||||
};
|
||||
|
||||
class VLAUFileSoundOut : public VLAUSoundOut {
|
||||
|
@ -119,6 +124,12 @@ VLAUSoundOut::VLAUSoundOut()
|
|||
: fMusic(0), fRunning(false), fForward(true)
|
||||
{
|
||||
InitSoundOutput(false);
|
||||
fMusicPoll = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
|
||||
dispatch_source_set_event_handler(fMusicPoll, ^{
|
||||
this->PollMusic();
|
||||
});
|
||||
dispatch_source_set_timer(fMusicPoll, DISPATCH_TIME_FOREVER, INT64_MAX, 1000*NSEC_PER_USEC);
|
||||
dispatch_resume(fMusicPoll);
|
||||
}
|
||||
|
||||
VLAUSoundOut::VLAUSoundOut(bool)
|
||||
|
@ -128,8 +139,9 @@ VLAUSoundOut::VLAUSoundOut(bool)
|
|||
|
||||
VLAUSoundOut::~VLAUSoundOut()
|
||||
{
|
||||
DisposeMusicPlayer(fPlayer);
|
||||
Stop(false);
|
||||
dispatch_release(fMusicPoll);
|
||||
DisposeMusicPlayer(fPlayer);
|
||||
DisposeAUGraph(fGraph);
|
||||
}
|
||||
|
||||
|
@ -205,6 +217,9 @@ void VLAUSoundOut::PlaySequence(MusicSequence music)
|
|||
R(MusicPlayerStart(fPlayer));
|
||||
|
||||
fRunning = true;
|
||||
CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), kVLSoundStartedNotification,
|
||||
NULL, NULL, false);
|
||||
dispatch_source_set_timer(fMusicPoll, DISPATCH_TIME_NOW, 500*NSEC_PER_MSEC, 200*NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
void VLAUSoundOut::SetPlayRate(float rate)
|
||||
|
@ -266,6 +281,9 @@ void VLAUSoundOut::Stop(bool pause)
|
|||
DisposeMusicSequence(fMusic);
|
||||
fMusic = 0;
|
||||
}
|
||||
CFNotificationCenterPostNotification(CFNotificationCenterGetLocalCenter(), kVLSoundStoppedNotification,
|
||||
NULL, NULL, false);
|
||||
dispatch_source_set_timer(fMusicPoll, DISPATCH_TIME_FOREVER, INT64_MAX, 200*NSEC_PER_MSEC);
|
||||
}
|
||||
|
||||
bool VLAUSoundOut::Playing()
|
||||
|
@ -280,6 +298,14 @@ bool VLAUSoundOut::AtEnd()
|
|||
return !MusicPlayerGetTime(fPlayer, &time) && time >= fMusicLength;
|
||||
}
|
||||
|
||||
void VLAUSoundOut::PollMusic()
|
||||
{
|
||||
if (fRunning && AtEnd()) {
|
||||
MusicPlayerSetTime(fPlayer, 0);
|
||||
Stop(true);
|
||||
}
|
||||
}
|
||||
|
||||
void VLAUSoundOut::PlayNote(const VLNote & note)
|
||||
{
|
||||
Play(¬e.fPitch);
|
||||
|
|
|
@ -5,13 +5,16 @@
|
|||
//
|
||||
// (MN) Matthias Neeracher
|
||||
//
|
||||
// Copyright © 2005-2008 Matthias Neeracher
|
||||
// Copyright © 2005-2011 Matthias Neeracher
|
||||
//
|
||||
|
||||
#include "VLModel.h"
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
extern CFStringRef kVLSoundStartedNotification;
|
||||
extern CFStringRef kVLSoundStoppedNotification;
|
||||
|
||||
class VLSoundEvent {
|
||||
protected:
|
||||
VLSoundEvent() {}
|
||||
|
|
Loading…
Reference in New Issue
Block a user