diff --git a/AudioUnit/AmuseContainerMainMenu.xib b/AudioUnit/AmuseContainerMainMenu.xib index 83ba70a..f04a06a 100644 --- a/AudioUnit/AmuseContainerMainMenu.xib +++ b/AudioUnit/AmuseContainerMainMenu.xib @@ -149,7 +149,7 @@ - + @@ -190,10 +190,10 @@ - + - + @@ -287,7 +287,7 @@ @@ -372,7 +372,7 @@ - + @@ -467,7 +467,7 @@ - - diff --git a/AudioUnit/AmuseContainingApp.mm b/AudioUnit/AmuseContainingApp.mm index 6667e68..446601b 100644 --- a/AudioUnit/AmuseContainingApp.mm +++ b/AudioUnit/AmuseContainingApp.mm @@ -2,6 +2,11 @@ #import #import #import "AudioUnitViewController.hpp" +#import "AudioGroupFilePresenter.hpp" + +@class DataOutlineController; +@class SamplesTableController; +@class SFXTableController; @interface MainView : NSView { @@ -28,6 +33,22 @@ @end +@interface AppDelegate : NSObject +{ + IBOutlet NSWindow* mainWindow; + IBOutlet NSOutlineView* dataOutline; + IBOutlet NSTableView* sfxTable; + IBOutlet NSTableView* samplesTable; + IBOutlet NSTextView* creditsView; + + AudioGroupFilePresenter* groupFilePresenter; + + DataOutlineController* dataController; + SamplesTableController* samplesController; + SFXTableController* sfxController; +} +@end + @interface MainTabView : NSTabView {} - (IBAction)selectDataTab:(id)sender; @@ -55,22 +76,102 @@ } @end -@interface AppDelegate : NSObject +@interface DataOutlineView : NSOutlineView { - IBOutlet NSWindow* mainWindow; - IBOutlet NSOutlineView* dataOutline; - IBOutlet NSTableView* sfxTable; - IBOutlet NSTableView* samplesTable; - IBOutlet NSTextView* creditsView; + } @end +@implementation DataOutlineView + +- (id)initWithFrame:(NSRect)frameRect +{ + self = [super initWithFrame:frameRect]; + [self registerForDraggedTypes:@[(__bridge NSString*)kUTTypeData]]; + return self; +} + +- (BOOL)performDragOperation:(id)sender +{ + +} + +@end + +@interface DataOutlineController : NSObject +{ + +} +@end + +@implementation DataOutlineController + + + +@end + +@interface SamplesTableController : NSObject +{ + +} +@end + +@implementation SamplesTableController + +- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView +{ + +} + +- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn*)tableColumn row:(NSInteger)row +{ + +} + +@end + +@interface SFXTableController : NSObject +{ + +} +@end + +@implementation SFXTableController + +- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView +{ +} + +- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn*)tableColumn row:(NSInteger)row +{ + +} + +@end + @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification*)notification { [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"]; [mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"]; + + groupFilePresenter = [AudioGroupFilePresenter new]; + + dataController = [DataOutlineController new]; + dataOutline.dataSource = dataController; + dataOutline.delegate = dataController; + [dataOutline reloadItem:nil reloadChildren:YES]; + + samplesController = [SamplesTableController new]; + samplesTable.dataSource = samplesController; + samplesTable.delegate = samplesController; + [samplesTable reloadData]; + + sfxController = [SFXTableController new]; + sfxTable.dataSource = sfxController; + sfxTable.delegate = sfxController; + [sfxTable reloadData]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender diff --git a/AudioUnit/AudioGroupFilePresenter.hpp b/AudioUnit/AudioGroupFilePresenter.hpp index ccfabfb..df70dba 100644 --- a/AudioUnit/AudioGroupFilePresenter.hpp +++ b/AudioUnit/AudioGroupFilePresenter.hpp @@ -2,6 +2,7 @@ #define __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__ #import +#import #include #include @@ -9,29 +10,40 @@ struct AudioGroupDataCollection { - NSURL* m_proj = nullptr; /* Only this member set for single-file containers */ - NSURL* m_pool = nullptr; - NSURL* m_sdir = nullptr; - NSURL* m_samp = nullptr; + NSURL* m_proj; + NSURL* m_pool; + NSURL* m_sdir; + NSURL* m_samp; + + std::unique_ptr m_projData; + std::unique_ptr m_poolData; + std::unique_ptr m_sdirData; + std::unique_ptr m_sampData; - bool invalidateURL(NSURL* url); void moveURL(NSURL* oldUrl, NSURL* newUrl); - std::unique_ptr _coordinateRead(AudioGroupFilePresenter* presenter, size_t& szOut, NSURL* url); + bool loadProj(AudioGroupFilePresenter* presenter); + bool loadPool(AudioGroupFilePresenter* presenter); + bool loadSdir(AudioGroupFilePresenter* presenter); + bool loadSamp(AudioGroupFilePresenter* presenter); - std::unique_ptr coordinateProjRead(AudioGroupFilePresenter* presenter, size_t& szOut); - std::unique_ptr coordinatePoolRead(AudioGroupFilePresenter* presenter, size_t& szOut); - std::unique_ptr coordinateSdirRead(AudioGroupFilePresenter* presenter, size_t& szOut); - std::unique_ptr coordinateSampRead(AudioGroupFilePresenter* presenter, size_t& szOut); + AudioGroupDataCollection(NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp) + : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp) {} + bool isDataComplete () const {return m_projData && m_poolData && m_sdirData && m_sampData;} }; -@interface AudioGroupFilePresenter : NSObject +@interface AudioGroupFilePresenter : NSObject { NSURL* m_groupURL; NSOperationQueue* m_dataQueue; std::map m_audioGroupCollections; + + std::map::const_iterator m_audioGroupOutlineIt; + size_t m_audioGroupOutlineIdx; } +- (void)update; + @end #endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__ diff --git a/AudioUnit/AudioGroupFilePresenter.mm b/AudioUnit/AudioGroupFilePresenter.mm index fd0e122..9adba9e 100644 --- a/AudioUnit/AudioGroupFilePresenter.mm +++ b/AudioUnit/AudioGroupFilePresenter.mm @@ -1,5 +1,6 @@ #include "AudioGroupFilePresenter.hpp" #include +#import @implementation AudioGroupFilePresenter @@ -13,36 +14,6 @@ return m_dataQueue; } -bool AudioGroupDataCollection::invalidateURL(NSURL* url) -{ - bool valid = false; - if (m_proj) - { - if ([m_proj isEqual:url]) - m_proj = nullptr; - valid |= m_proj != nullptr; - } - if (m_pool) - { - if ([m_pool isEqual:url]) - m_pool = nullptr; - valid |= m_pool != nullptr; - } - if (m_sdir) - { - if ([m_sdir isEqual:url]) - m_sdir = nullptr; - valid |= m_sdir != nullptr; - } - if (m_samp) - { - if ([m_samp isEqual:url]) - m_samp = nullptr; - valid |= m_samp != nullptr; - } - return valid; -} - void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl) { if (m_proj) @@ -67,100 +38,109 @@ void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl) } } -std::unique_ptr AudioGroupDataCollection::_coordinateRead(AudioGroupFilePresenter* presenter, size_t& szOut, NSURL* url) -{ - NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; - if (!coord) - return {}; - NSError* err; - __block std::unique_ptr ret; - __block size_t retSz = 0; - [coord coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err - byAccessor:^(NSURL* newUrl) - { - athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); - if (r.hasError()) - return; - retSz = r.length(); - ret = r.readUBytes(retSz); - }]; - szOut = retSz; - return std::move(ret); -} - -std::unique_ptr AudioGroupDataCollection::coordinateProjRead(AudioGroupFilePresenter* presenter, size_t& szOut) +bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter) { if (!m_proj) - return {}; - return _coordinateRead(presenter, szOut, m_proj); + return false; + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; + if (!coord) + return false; + NSError* err; + __block std::unique_ptr& ret = m_projData; + [coord coordinateReadingItemAtURL:m_proj + options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err + byAccessor:^(NSURL* newUrl) + { + athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); + if (r.hasError()) + return; + ret = r.readUBytes(r.length()); + }]; + return m_projData.operator bool(); } -std::unique_ptr AudioGroupDataCollection::coordinatePoolRead(AudioGroupFilePresenter* presenter, size_t& szOut) +bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter) { if (!m_pool) - return {}; - return _coordinateRead(presenter, szOut, m_pool); + return false; + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; + if (!coord) + return false; + NSError* err; + __block std::unique_ptr& ret = m_poolData; + [coord coordinateReadingItemAtURL:m_pool + options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err + byAccessor:^(NSURL* newUrl) + { + athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); + if (r.hasError()) + return; + ret = r.readUBytes(r.length()); + }]; + return m_poolData.operator bool(); } -std::unique_ptr AudioGroupDataCollection::coordinateSdirRead(AudioGroupFilePresenter* presenter, size_t& szOut) +bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter) { if (!m_sdir) - return {}; - return _coordinateRead(presenter, szOut, m_sdir); + return false; + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; + if (!coord) + return false; + NSError* err; + __block std::unique_ptr& ret = m_sdirData; + [coord coordinateReadingItemAtURL:m_sdir + options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err + byAccessor:^(NSURL* newUrl) + { + athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); + if (r.hasError()) + return; + ret = r.readUBytes(r.length()); + }]; + return m_sdirData.operator bool(); } -std::unique_ptr AudioGroupDataCollection::coordinateSampRead(AudioGroupFilePresenter* presenter, size_t& szOut) +bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter) { if (!m_samp) - return {}; - return _coordinateRead(presenter, szOut, m_samp); -} - -- (void)accommodatePresentedSubitemDeletionAtURL:(NSURL*)url completionHandler:(void (^)(NSError* errorOrNil))completionHandler -{ - for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ;) - { - std::pair& pair = *it; - if (pair.second.invalidateURL(url)) - { - it = m_audioGroupCollections.erase(it); - continue; - } - ++it; - } - completionHandler(nil); + return false; + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; + if (!coord) + return false; + NSError* err; + __block std::unique_ptr& ret = m_sampData; + [coord coordinateReadingItemAtURL:m_samp + options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err + byAccessor:^(NSURL* newUrl) + { + athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); + if (r.hasError()) + return; + ret = r.readUBytes(r.length()); + }]; + return m_sampData.operator bool(); } - (void)presentedSubitemDidAppearAtURL:(NSURL*)url { - NSString* path = [url path]; - if (!path) - return; + NSURL* dir = nil; + if ([url.lastPathComponent isEqualToString:@"proj"] || + [url.lastPathComponent isEqualToString:@"pool"] || + [url.lastPathComponent isEqualToString:@"sdir"] || + [url.lastPathComponent isEqualToString:@"samp"]) + dir = url.baseURL; - NSString* extension = [url pathExtension]; - NSString* lastComp = [url lastPathComponent]; - lastComp = [lastComp substringToIndex:[lastComp length] - [extension length]]; - AudioGroupDataCollection& collection = m_audioGroupCollections[[lastComp UTF8String]]; - - if ([extension isEqualToString:@"pro"] || [extension isEqualToString:@"proj"]) + auto search = m_audioGroupCollections.find(dir.lastPathComponent.UTF8String); + if (search == m_audioGroupCollections.end()) { - collection.m_proj = url; - } - else if ([extension isEqualToString:@"poo"] || [extension isEqualToString:@"pool"]) - { - collection.m_pool = url; - } - else if ([extension isEqualToString:@"sdi"] || [extension isEqualToString:@"sdir"]) - { - collection.m_sdir = url; - } - else if ([extension isEqualToString:@"sam"] || [extension isEqualToString:@"samp"]) - { - collection.m_samp = url; - } - else - { - collection.m_proj = url; + search = + m_audioGroupCollections.emplace(dir.lastPathComponent.UTF8String, + AudioGroupDataCollection{ + [dir URLByAppendingPathComponent:@"proj"], + [dir URLByAppendingPathComponent:@"pool"], + [dir URLByAppendingPathComponent:@"sdir"], + [dir URLByAppendingPathComponent:@"samp"]}).first; } } @@ -173,6 +153,71 @@ std::unique_ptr AudioGroupDataCollection::coordinateSampRead(AudioGro } } +- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item +{ + if (!item) + return m_audioGroupCollections.size(); + return 0; +} + +- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item +{ + if (!item) + { + + } + return nil; +} + +- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item +{ + return NO; +} + +- (void)update +{ + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self]; + if (!coord) + return; + NSError* coordErr; + __block NSError* managerErr; + __block std::map& theMap = m_audioGroupCollections; + [coord coordinateReadingItemAtURL:m_groupURL options:NSFileCoordinatorReadingResolvesSymbolicLink error:&coordErr + byAccessor:^(NSURL* newUrl) + { + NSFileManager* fman = [NSFileManager defaultManager]; + NSArray* contents = + [fman contentsOfDirectoryAtURL:newUrl + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | + NSDirectoryEnumerationSkipsHiddenFiles + error:&managerErr]; + if (!contents) + return; + + for (NSURL* path in contents) + { + NSNumber* isDir; + [path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil]; + + if (isDir.boolValue) + { + auto search = theMap.find(path.lastPathComponent.UTF8String); + if (search == theMap.end()) + { + search = + theMap.emplace(path.lastPathComponent.UTF8String, + AudioGroupDataCollection{ + [path URLByAppendingPathComponent:@"proj"], + [path URLByAppendingPathComponent:@"pool"], + [path URLByAppendingPathComponent:@"sdir"], + [path URLByAppendingPathComponent:@"samp"]}).first; + } + } + } + }]; +} + - (id)init { m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"]; @@ -180,6 +225,7 @@ std::unique_ptr AudioGroupDataCollection::coordinateSampRead(AudioGro return nil; m_dataQueue = [NSOperationQueue new]; [NSFileCoordinator addFilePresenter:self]; + [self update]; return self; } diff --git a/lib/Sequencer.cpp b/lib/Sequencer.cpp index e39e327..6e508d0 100644 --- a/lib/Sequencer.cpp +++ b/lib/Sequencer.cpp @@ -71,7 +71,7 @@ Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId, m_midiSetup = it->second->data(); m_submix = m_engine.addSubmix(smx); - m_submix->makeReverbHi(0.2f, 1.f, 1.f, 0.5f, 0.f, 0.f); + m_submix->makeReverbHi(0.2f, 0.65f, 1.f, 0.5f, 0.f, 0.f); } Sequencer::ChannelState::~ChannelState()