2016-05-25 02:00:22 +00:00
|
|
|
#import <AppKit/AppKit.h>
|
|
|
|
#import <AudioUnit/AudioUnit.h>
|
|
|
|
#import <CoreAudioKit/AUViewController.h>
|
|
|
|
#import "AudioUnitViewController.hpp"
|
2016-06-04 22:38:55 +00:00
|
|
|
#import "AmuseContainingApp.hpp"
|
2016-06-04 02:34:35 +00:00
|
|
|
#include <amuse/amuse.hpp>
|
2016-06-03 02:53:52 +00:00
|
|
|
|
|
|
|
@class DataOutlineController;
|
|
|
|
@class SamplesTableController;
|
|
|
|
@class SFXTableController;
|
2016-05-25 02:00:22 +00:00
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
/* Blocks mousedown events (so button may be used as a visual element only) */
|
2016-06-05 03:11:24 +00:00
|
|
|
@interface InactiveButton : NSButton {}
|
|
|
|
@end
|
|
|
|
@implementation InactiveButton
|
|
|
|
- (void)mouseDown:(NSEvent *)theEvent {}
|
|
|
|
@end
|
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
/* Restricts mousedown to checkbox */
|
|
|
|
@interface RestrictedCheckButton : NSButtonCell {}
|
|
|
|
@end
|
|
|
|
@implementation RestrictedCheckButton
|
|
|
|
- (NSCellHitResult)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView
|
|
|
|
{
|
|
|
|
NSRect restrictFrame = cellFrame;
|
|
|
|
restrictFrame.size.width = 22;
|
|
|
|
if (NSPointInRect([controlView convertPoint:[event locationInWindow] fromView:nil], restrictFrame))
|
|
|
|
return NSCellHitTrackableArea;
|
|
|
|
return NSCellHitNone;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2016-06-04 22:38:55 +00:00
|
|
|
@implementation DataOutlineView
|
2016-06-05 03:11:24 +00:00
|
|
|
- (id)initWithCoder:(NSCoder *)coder
|
2016-06-03 02:53:52 +00:00
|
|
|
{
|
2016-06-05 03:11:24 +00:00
|
|
|
self = [super initWithCoder:coder];
|
|
|
|
[self registerForDraggedTypes:@[NSURLPboardType]];
|
2016-06-04 22:38:55 +00:00
|
|
|
return self;
|
|
|
|
}
|
2016-06-05 03:11:24 +00:00
|
|
|
- (id)initWithFrame:(NSRect)frameRect
|
2016-06-04 22:38:55 +00:00
|
|
|
{
|
2016-06-05 03:11:24 +00:00
|
|
|
self = [super initWithFrame:frameRect];
|
|
|
|
[self registerForDraggedTypes:@[NSURLPboardType]];
|
|
|
|
return self;
|
2016-06-03 02:53:52 +00:00
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2016-05-27 00:56:18 +00:00
|
|
|
@interface MainTabView : NSTabView
|
|
|
|
{}
|
|
|
|
- (IBAction)selectDataTab:(id)sender;
|
|
|
|
- (IBAction)selectSFXTab:(id)sender;
|
|
|
|
- (IBAction)selectSamplesTab:(id)sender;
|
|
|
|
- (IBAction)selectCreditsTab:(id)sender;
|
2016-05-26 01:28:50 +00:00
|
|
|
@end
|
2016-05-25 02:00:22 +00:00
|
|
|
|
2016-05-27 00:56:18 +00:00
|
|
|
@implementation MainTabView
|
|
|
|
- (IBAction)selectDataTab:(id)sender
|
2016-05-26 01:28:50 +00:00
|
|
|
{
|
2016-05-27 00:56:18 +00:00
|
|
|
[self selectTabViewItemAtIndex:0];
|
2016-05-26 01:28:50 +00:00
|
|
|
}
|
2016-05-27 00:56:18 +00:00
|
|
|
- (IBAction)selectSFXTab:(id)sender
|
|
|
|
{
|
|
|
|
[self selectTabViewItemAtIndex:1];
|
2016-05-25 02:00:22 +00:00
|
|
|
}
|
2016-05-27 00:56:18 +00:00
|
|
|
- (IBAction)selectSamplesTab:(id)sender
|
|
|
|
{
|
|
|
|
[self selectTabViewItemAtIndex:2];
|
2016-05-26 01:28:50 +00:00
|
|
|
}
|
2016-05-27 00:56:18 +00:00
|
|
|
- (IBAction)selectCreditsTab:(id)sender
|
2016-05-26 01:28:50 +00:00
|
|
|
{
|
2016-05-27 00:56:18 +00:00
|
|
|
[self selectTabViewItemAtIndex:3];
|
2016-05-25 02:00:22 +00:00
|
|
|
}
|
2016-05-27 00:56:18 +00:00
|
|
|
@end
|
2016-05-25 02:00:22 +00:00
|
|
|
|
2016-06-03 02:53:52 +00:00
|
|
|
|
|
|
|
@implementation SamplesTableController
|
|
|
|
|
|
|
|
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
|
|
|
|
{
|
2016-06-05 22:37:49 +00:00
|
|
|
return presenter->m_sampleTableData.size();
|
2016-06-03 02:53:52 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
2016-06-03 02:53:52 +00:00
|
|
|
{
|
2016-06-05 22:37:49 +00:00
|
|
|
if (presenter->m_sampleTableData.size() <= row)
|
|
|
|
return nil;
|
|
|
|
NSTableCellView* view = [tableView makeViewWithIdentifier:@"SampleIDColumn" owner:self];
|
|
|
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
|
|
|
if ([tableColumn.identifier isEqualToString:@"SampleIDColumn"])
|
|
|
|
view.textField.attributedStringValue = sampToken->m_name;
|
|
|
|
else if ([tableColumn.identifier isEqualToString:@"SampleDetailsColumn"])
|
|
|
|
view.textField.stringValue = @"";
|
|
|
|
else
|
|
|
|
view.textField.attributedStringValue = sampToken->m_name;
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row
|
|
|
|
{
|
|
|
|
if (presenter->m_sampleTableData.size() <= row)
|
|
|
|
return NO;
|
|
|
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
|
|
|
if (!sampToken->m_sample)
|
|
|
|
return YES;
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
|
|
|
|
{
|
|
|
|
if (presenter->m_sampleTableData.size() <= row)
|
|
|
|
return NO;
|
|
|
|
AudioGroupSampleToken* sampToken = presenter->m_sampleTableData[row];
|
|
|
|
if (!sampToken->m_sample)
|
|
|
|
return NO;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
presenter = present;
|
|
|
|
return self;
|
2016-06-03 02:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation SFXTableController
|
|
|
|
|
|
|
|
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
|
2016-05-27 00:56:18 +00:00
|
|
|
{
|
2016-06-05 22:37:49 +00:00
|
|
|
return presenter->m_sfxTableData.size();
|
2016-05-27 00:56:18 +00:00
|
|
|
}
|
2016-06-03 02:53:52 +00:00
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
2016-06-03 02:53:52 +00:00
|
|
|
{
|
2016-06-05 22:37:49 +00:00
|
|
|
if (presenter->m_sfxTableData.size() <= row)
|
|
|
|
return nil;
|
|
|
|
NSTableCellView* view = [tableView makeViewWithIdentifier:@"SFXIDColumn" owner:self];
|
|
|
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
|
|
|
if ([tableColumn.identifier isEqualToString:@"SFXIDColumn"])
|
|
|
|
view.textField.attributedStringValue = sfxToken->m_name;
|
|
|
|
else if ([tableColumn.identifier isEqualToString:@"SFXDetailsColumn"])
|
|
|
|
view.textField.stringValue = @"";
|
|
|
|
else
|
|
|
|
view.textField.attributedStringValue = sfxToken->m_name;
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row
|
|
|
|
{
|
|
|
|
if (presenter->m_sfxTableData.size() <= row)
|
|
|
|
return NO;
|
|
|
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
|
|
|
if (!sfxToken->m_sfx)
|
|
|
|
return YES;
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
|
|
|
|
{
|
|
|
|
if (presenter->m_sfxTableData.size() <= row)
|
|
|
|
return NO;
|
|
|
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
|
|
|
if (!sfxToken->m_sfx)
|
|
|
|
return NO;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)tableViewSelectionDidChange:(NSNotification *)notification
|
|
|
|
{
|
|
|
|
NSTableView* table = notification.object;
|
|
|
|
NSInteger row = table.selectedRow;
|
|
|
|
if (presenter->m_sfxTableData.size() <= row)
|
|
|
|
return;
|
|
|
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
2016-06-07 03:42:51 +00:00
|
|
|
AppDelegate* delegate = (AppDelegate*)NSApp.delegate;
|
2016-06-05 22:37:49 +00:00
|
|
|
[delegate startSFX:sfxToken->m_loadId];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
presenter = present;
|
|
|
|
return self;
|
2016-06-03 02:53:52 +00:00
|
|
|
}
|
|
|
|
|
2016-05-25 02:00:22 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation AppDelegate
|
|
|
|
|
2016-06-05 03:11:24 +00:00
|
|
|
- (void)applicationWillFinishLaunching:(NSNotification*)notification
|
2016-05-26 01:28:50 +00:00
|
|
|
{
|
2016-06-05 22:37:49 +00:00
|
|
|
booEngine = boo::NewAudioVoiceEngine();
|
|
|
|
amuseAllocator.emplace(*booEngine);
|
|
|
|
amuseEngine.emplace(*amuseAllocator);
|
|
|
|
|
2016-05-27 00:56:18 +00:00
|
|
|
[mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"];
|
2016-06-03 02:53:52 +00:00
|
|
|
|
2016-06-07 03:42:51 +00:00
|
|
|
groupFilePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
|
2016-06-03 02:53:52 +00:00
|
|
|
|
2016-06-04 02:34:35 +00:00
|
|
|
dataOutline.dataSource = groupFilePresenter;
|
|
|
|
dataOutline.delegate = groupFilePresenter;
|
2016-06-03 02:53:52 +00:00
|
|
|
[dataOutline reloadItem:nil reloadChildren:YES];
|
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
samplesController = [[SamplesTableController alloc] initWithAudioGroupPresenter:groupFilePresenter];
|
2016-06-03 02:53:52 +00:00
|
|
|
samplesTable.dataSource = samplesController;
|
|
|
|
samplesTable.delegate = samplesController;
|
|
|
|
[samplesTable reloadData];
|
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
sfxController = [[SFXTableController alloc] initWithAudioGroupPresenter:groupFilePresenter];
|
2016-06-03 02:53:52 +00:00
|
|
|
sfxTable.dataSource = sfxController;
|
|
|
|
sfxTable.delegate = sfxController;
|
|
|
|
[sfxTable reloadData];
|
2016-06-05 22:37:49 +00:00
|
|
|
|
|
|
|
[NSTimer scheduledTimerWithTimeInterval:1.0 / 60.0 target:self selector:@selector(pumpTimer:) userInfo:nil repeats:YES];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)pumpTimer:(NSTimer*)timer
|
|
|
|
{
|
2017-12-16 00:18:57 +00:00
|
|
|
booEngine->pumpAndMixVoices();
|
2016-05-26 01:28:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2016-06-04 02:34:35 +00:00
|
|
|
- (BOOL)importURL:(NSURL*)url
|
|
|
|
{
|
|
|
|
amuse::ContainerRegistry::Type containerType;
|
|
|
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>> data =
|
|
|
|
amuse::ContainerRegistry::LoadContainer(url.path.UTF8String, containerType);
|
|
|
|
if (data.empty())
|
|
|
|
{
|
|
|
|
NSString* err = [NSString stringWithFormat:@"Unable to load Audio Groups from %s", url.path.UTF8String];
|
|
|
|
NSAlert* alert = [[NSAlert alloc] init];
|
|
|
|
alert.informativeText = err;
|
|
|
|
alert.messageText = @"Invalid Data File";
|
|
|
|
[alert runModal];
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string name(amuse::ContainerRegistry::TypeToName(containerType));
|
2016-06-05 03:11:24 +00:00
|
|
|
if (containerType == amuse::ContainerRegistry::Type::Raw4)
|
|
|
|
name = url.URLByDeletingPathExtension.lastPathComponent.UTF8String;
|
2016-06-04 02:34:35 +00:00
|
|
|
return [groupFilePresenter addCollectionName:std::move(name) items:std::move(data)];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)importFile:(id)sender
|
2016-05-26 01:28:50 +00:00
|
|
|
{
|
2016-06-04 02:34:35 +00:00
|
|
|
__block NSOpenPanel* panel = [NSOpenPanel openPanel];
|
|
|
|
[panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
|
2017-12-16 00:18:57 +00:00
|
|
|
if (result == NSModalResponseOK)
|
2016-06-04 02:34:35 +00:00
|
|
|
{
|
|
|
|
[self importURL:panel.URL];
|
|
|
|
}
|
|
|
|
}];
|
2016-05-26 01:28:50 +00:00
|
|
|
}
|
2016-05-25 02:00:22 +00:00
|
|
|
|
2016-06-05 22:37:49 +00:00
|
|
|
- (void)startSFX:(int)sfxId
|
|
|
|
{
|
|
|
|
if (activeSFXVox)
|
|
|
|
activeSFXVox->keyOff();
|
|
|
|
activeSFXVox = amuseEngine->fxStart(sfxId, 1.f, 0.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)startSample:(int)sampleId
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)reloadTables
|
|
|
|
{
|
|
|
|
[sfxTable reloadData];
|
|
|
|
[samplesTable reloadData];
|
|
|
|
}
|
|
|
|
|
2016-06-04 22:38:55 +00:00
|
|
|
- (IBAction)filterDataOutline:(id)sender
|
|
|
|
{
|
|
|
|
[groupFilePresenter setSearchFilter:[sender stringValue]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)removeDataItem:(id)sender
|
|
|
|
{
|
|
|
|
[groupFilePresenter removeSelectedItem];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)outlineView:(DataOutlineView *)ov selectionChanged:(id)item
|
|
|
|
{
|
|
|
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
|
|
|
{
|
|
|
|
removeDataButton.enabled = TRUE;
|
|
|
|
removeDataMenu.enabled = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
removeDataButton.enabled = FALSE;
|
|
|
|
removeDataMenu.enabled = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-05 03:11:24 +00:00
|
|
|
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename
|
|
|
|
{
|
|
|
|
NSURL* url = [NSURL fileURLWithPath:filename isDirectory:NO];
|
|
|
|
return [self importURL:url];
|
|
|
|
}
|
|
|
|
|
2016-06-07 03:42:51 +00:00
|
|
|
- (amuse::Engine&)getAmuseEngine
|
|
|
|
{
|
|
|
|
return *amuseEngine;
|
|
|
|
}
|
|
|
|
|
2016-05-26 01:28:50 +00:00
|
|
|
@end
|
2016-05-25 02:00:22 +00:00
|
|
|
|
2016-05-26 01:28:50 +00:00
|
|
|
int main(int argc, const char * argv[])
|
|
|
|
{
|
2016-05-27 00:56:18 +00:00
|
|
|
return NSApplicationMain(argc, argv);
|
2016-05-25 02:00:22 +00:00
|
|
|
}
|