mirror of
https://github.com/AxioDL/amuse.git
synced 2025-08-09 13:39:09 +00:00
More UI bindings, metadata management
This commit is contained in:
parent
9ae92313e3
commit
62ece61cb2
@ -19,6 +19,8 @@
|
|||||||
<outlet property="dataOutline" destination="Vlv-Jw-A4U" id="Ggn-DC-cUY"/>
|
<outlet property="dataOutline" destination="Vlv-Jw-A4U" id="Ggn-DC-cUY"/>
|
||||||
<outlet property="dataSearchField" destination="Huk-pR-ayq" id="MbL-0b-KGw"/>
|
<outlet property="dataSearchField" destination="Huk-pR-ayq" id="MbL-0b-KGw"/>
|
||||||
<outlet property="mainWindow" destination="FDh-Mc-OFY" id="CQQ-Dm-Kv3"/>
|
<outlet property="mainWindow" destination="FDh-Mc-OFY" id="CQQ-Dm-Kv3"/>
|
||||||
|
<outlet property="removeDataButton" destination="eh8-gl-WoS" id="U9P-dt-tN5"/>
|
||||||
|
<outlet property="removeDataMenu" destination="pa3-QI-u2k" id="xnq-of-WvG"/>
|
||||||
<outlet property="samplesTable" destination="Frt-wZ-1ZI" id="riC-O4-JXo"/>
|
<outlet property="samplesTable" destination="Frt-wZ-1ZI" id="riC-O4-JXo"/>
|
||||||
<outlet property="sfxTable" destination="4nw-rf-Dh4" id="ebY-ro-tqk"/>
|
<outlet property="sfxTable" destination="4nw-rf-Dh4" id="ebY-ro-tqk"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -78,12 +80,15 @@
|
|||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
|
<menu key="submenu" title="Edit" autoenablesItems="NO" id="W48-6f-4Dl">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="Delete" id="pa3-QI-u2k">
|
<menuItem title="Delete" enabled="NO" id="pa3-QI-u2k">
|
||||||
|
<string key="keyEquivalent" base64-UTF8="YES">
|
||||||
|
CA
|
||||||
|
</string>
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
|
<action selector="removeDataItem:" target="Y3H-Qy-a7C" id="aAl-Ko-LrT"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
|
||||||
@ -182,10 +187,13 @@
|
|||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="31" id="HLy-Rb-n4I"/>
|
<constraint firstAttribute="width" constant="31" id="HLy-Rb-n4I"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="edx-l4-aHD">
|
<buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" enabled="NO" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="edx-l4-aHD">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="removeDataItem:" target="Y3H-Qy-a7C" id="hau-zt-Ozz"/>
|
||||||
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mpK-AK-Otf">
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mpK-AK-Otf">
|
||||||
<rect key="frame" x="58" y="-1" width="486" height="32"/>
|
<rect key="frame" x="58" y="-1" width="486" height="32"/>
|
||||||
@ -213,7 +221,7 @@
|
|||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
</tableHeaderCell>
|
</tableHeaderCell>
|
||||||
<buttonCell key="dataCell" type="check" title="CollectionTitle" bezelStyle="regularSquare" imagePosition="left" alignment="left" lineBreakMode="truncatingTail" inset="2" id="Lpp-wh-qX7">
|
<buttonCell key="dataCell" type="check" title="CollectionTitle" bezelStyle="regularSquare" imagePosition="left" alignment="left" lineBreakMode="truncatingTail" allowsMixedState="YES" inset="2" id="Lpp-wh-qX7">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
@ -255,11 +263,14 @@
|
|||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="22" id="uJy-eO-Y8o"/>
|
<constraint firstAttribute="height" constant="22" id="uJy-eO-Y8o"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="u9E-Ld-d6I">
|
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" sendsSearchStringImmediately="YES" id="u9E-Ld-d6I">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</searchFieldCell>
|
</searchFieldCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="filterDataOutline:" target="Y3H-Qy-a7C" id="D8g-Qv-0QG"/>
|
||||||
|
</connections>
|
||||||
</searchField>
|
</searchField>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
48
AudioUnit/AmuseContainingApp.hpp
Normal file
48
AudioUnit/AmuseContainingApp.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
||||||
|
#define __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
|
||||||
|
@interface DataOutlineView : NSOutlineView
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
IBOutlet NSButton* removeDataButton;
|
||||||
|
IBOutlet NSMenuItem* deleteMenuItem;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SamplesTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface SFXTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||||
|
{
|
||||||
|
IBOutlet NSWindow* mainWindow;
|
||||||
|
IBOutlet NSOutlineView* dataOutline;
|
||||||
|
IBOutlet NSSearchField* dataSearchField;
|
||||||
|
IBOutlet NSTableView* sfxTable;
|
||||||
|
IBOutlet NSTableView* samplesTable;
|
||||||
|
IBOutlet NSTextView* creditsView;
|
||||||
|
|
||||||
|
IBOutlet NSButton* removeDataButton;
|
||||||
|
IBOutlet NSMenuItem* removeDataMenu;
|
||||||
|
|
||||||
|
AudioGroupFilePresenter* groupFilePresenter;
|
||||||
|
|
||||||
|
SamplesTableController* samplesController;
|
||||||
|
SFXTableController* sfxController;
|
||||||
|
}
|
||||||
|
- (BOOL)importURL:(NSURL*)url;
|
||||||
|
- (void)outlineView:(DataOutlineView*)ov selectionChanged:(id)item;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // __AMUSE_AUDIOUNIT_CONTAININGAPP_HPP__
|
@ -2,7 +2,7 @@
|
|||||||
#import <AudioUnit/AudioUnit.h>
|
#import <AudioUnit/AudioUnit.h>
|
||||||
#import <CoreAudioKit/AUViewController.h>
|
#import <CoreAudioKit/AUViewController.h>
|
||||||
#import "AudioUnitViewController.hpp"
|
#import "AudioUnitViewController.hpp"
|
||||||
#import "AudioGroupFilePresenter.hpp"
|
#import "AmuseContainingApp.hpp"
|
||||||
#include <amuse/amuse.hpp>
|
#include <amuse/amuse.hpp>
|
||||||
|
|
||||||
@class DataOutlineController;
|
@class DataOutlineController;
|
||||||
@ -34,21 +34,19 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
|
||||||
|
@implementation DataOutlineView
|
||||||
|
- (id)initWithFrame:(NSRect)frameRect
|
||||||
{
|
{
|
||||||
IBOutlet NSWindow* mainWindow;
|
self = [super initWithFrame:frameRect];
|
||||||
IBOutlet NSOutlineView* dataOutline;
|
[self registerForDraggedTypes:@[(__bridge NSString*)kUTTypeData]];
|
||||||
IBOutlet NSSearchField* dataSearchField;
|
return self;
|
||||||
IBOutlet NSTableView* sfxTable;
|
}
|
||||||
IBOutlet NSTableView* samplesTable;
|
|
||||||
IBOutlet NSTextView* creditsView;
|
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||||
|
{
|
||||||
AudioGroupFilePresenter* groupFilePresenter;
|
return NO;
|
||||||
|
|
||||||
SamplesTableController* samplesController;
|
|
||||||
SFXTableController* sfxController;
|
|
||||||
}
|
}
|
||||||
- (BOOL)importURL:(NSURL*)url;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MainTabView : NSTabView
|
@interface MainTabView : NSTabView
|
||||||
@ -78,34 +76,6 @@
|
|||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface DataOutlineView : NSOutlineView
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation DataOutlineView
|
|
||||||
|
|
||||||
- (id)initWithFrame:(NSRect)frameRect
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:frameRect];
|
|
||||||
[self registerForDraggedTypes:@[(__bridge NSString*)kUTTypeData]];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@interface SamplesTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation SamplesTableController
|
@implementation SamplesTableController
|
||||||
|
|
||||||
@ -121,11 +91,6 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface SFXTableController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation SFXTableController
|
@implementation SFXTableController
|
||||||
|
|
||||||
@ -199,6 +164,30 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int main(int argc, const char * argv[])
|
||||||
|
@ -55,6 +55,9 @@ struct AudioGroupDataCollection
|
|||||||
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta);
|
||||||
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
|
bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;}
|
||||||
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
bool _attemptLoad(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
|
void enable(AudioGroupFilePresenter* presenter);
|
||||||
|
void disable(AudioGroupFilePresenter* presenter);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -90,12 +93,14 @@ struct AudioGroupCollection
|
|||||||
NSURL* m_url;
|
NSURL* m_url;
|
||||||
|
|
||||||
AudioGroupCollectionToken* m_token;
|
AudioGroupCollectionToken* m_token;
|
||||||
std::map<std::string, AudioGroupDataCollection> m_groups;
|
std::map<std::string, std::unique_ptr<AudioGroupDataCollection>> m_groups;
|
||||||
std::experimental::optional<IteratorTracker<AudioGroupDataCollection>> m_iteratorTracker;
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups;
|
||||||
|
//std::experimental::optional<IteratorTracker<std::unique_ptr<AudioGroupDataCollection>>> m_iteratorTracker;
|
||||||
|
|
||||||
AudioGroupCollection(NSURL* url);
|
AudioGroupCollection(NSURL* url);
|
||||||
void addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
void addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void update(AudioGroupFilePresenter* presenter);
|
void update(AudioGroupFilePresenter* presenter);
|
||||||
|
bool doSearch(const std::string& str);
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface AudioGroupDataToken : NSObject
|
@interface AudioGroupDataToken : NSObject
|
||||||
@ -118,14 +123,18 @@ struct AudioGroupCollection
|
|||||||
{
|
{
|
||||||
NSURL* m_groupURL;
|
NSURL* m_groupURL;
|
||||||
NSOperationQueue* m_dataQueue;
|
NSOperationQueue* m_dataQueue;
|
||||||
std::map<std::string, AudioGroupCollection> m_audioGroupCollections;
|
std::map<std::string, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
|
||||||
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections;
|
||||||
NSOutlineView* lastOutlineView;
|
NSOutlineView* lastOutlineView;
|
||||||
|
NSString* searchStr;
|
||||||
|
|
||||||
std::experimental::optional<IteratorTracker<AudioGroupCollection>> m_iteratorTracker;
|
//std::experimental::optional<IteratorTracker<std::unique_ptr<AudioGroupCollection>>> m_iteratorTracker;
|
||||||
}
|
}
|
||||||
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection;
|
||||||
- (void)update;
|
- (void)update;
|
||||||
- (void)resetIterators;
|
- (void)resetIterators;
|
||||||
|
- (void)setSearchFilter:(NSString*)str;
|
||||||
|
- (void)removeSelectedItem;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
#endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
#include "AudioGroupFilePresenter.hpp"
|
#include "AudioGroupFilePresenter.hpp"
|
||||||
#include <athena/FileReader.hpp>
|
#include <athena/FileReader.hpp>
|
||||||
#include <amuse/AudioGroupProject.hpp>
|
#include <amuse/AudioGroupProject.hpp>
|
||||||
#import <AppKit/AppKit.h>
|
#import "AmuseContainingApp.hpp"
|
||||||
|
|
||||||
|
static std::string StrToLower(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string ret = str;
|
||||||
|
std::transform(ret.begin(), ret.end(), ret.begin(), tolower);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@implementation AudioGroupDataToken
|
@implementation AudioGroupDataToken
|
||||||
|
|
||||||
- (id)initWithDataCollection:(AudioGroupDataCollection *)collection
|
- (id)initWithDataCollection:(AudioGroupDataCollection *)collection
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
m_collection = collection;
|
m_collection = collection;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AudioGroupCollectionToken
|
@implementation AudioGroupCollectionToken
|
||||||
|
|
||||||
- (id)initWithCollection:(AudioGroupCollection *)collection
|
- (id)initWithCollection:(AudioGroupCollection *)collection
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
m_collection = collection;
|
m_collection = collection;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation AudioGroupFilePresenter
|
@implementation AudioGroupFilePresenter
|
||||||
@ -51,15 +54,15 @@ void AudioGroupCollection::addCollection(std::vector<std::pair<std::string, amus
|
|||||||
if (search == m_groups.end())
|
if (search == m_groups.end())
|
||||||
{
|
{
|
||||||
search = m_groups.emplace(pair.first,
|
search = m_groups.emplace(pair.first,
|
||||||
AudioGroupDataCollection{pair.first,
|
std::make_unique<AudioGroupDataCollection>(pair.first,
|
||||||
[collectionUrl URLByAppendingPathComponent:@"proj"],
|
[collectionUrl URLByAppendingPathComponent:@"proj"],
|
||||||
[collectionUrl URLByAppendingPathComponent:@"pool"],
|
[collectionUrl URLByAppendingPathComponent:@"pool"],
|
||||||
[collectionUrl URLByAppendingPathComponent:@"sdir"],
|
[collectionUrl URLByAppendingPathComponent:@"sdir"],
|
||||||
[collectionUrl URLByAppendingPathComponent:@"samp"],
|
[collectionUrl URLByAppendingPathComponent:@"samp"],
|
||||||
[collectionUrl URLByAppendingPathComponent:@"meta"]}).first;
|
[collectionUrl URLByAppendingPathComponent:@"meta"])).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupDataCollection& dataCollection = search->second;
|
AudioGroupDataCollection& dataCollection = *search->second;
|
||||||
dataCollection.m_projData.resize(dataIn.getProjSize());
|
dataCollection.m_projData.resize(dataIn.getProjSize());
|
||||||
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
|
memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize());
|
||||||
|
|
||||||
@ -101,18 +104,32 @@ void AudioGroupCollection::update(AudioGroupFilePresenter* presenter)
|
|||||||
std::string nameStr = path.lastPathComponent.UTF8String;
|
std::string nameStr = path.lastPathComponent.UTF8String;
|
||||||
search =
|
search =
|
||||||
m_groups.emplace(nameStr,
|
m_groups.emplace(nameStr,
|
||||||
AudioGroupDataCollection{nameStr,
|
std::make_unique<AudioGroupDataCollection>(nameStr,
|
||||||
[path URLByAppendingPathComponent:@"proj"],
|
[path URLByAppendingPathComponent:@"proj"],
|
||||||
[path URLByAppendingPathComponent:@"pool"],
|
[path URLByAppendingPathComponent:@"pool"],
|
||||||
[path URLByAppendingPathComponent:@"sdir"],
|
[path URLByAppendingPathComponent:@"sdir"],
|
||||||
[path URLByAppendingPathComponent:@"samp"],
|
[path URLByAppendingPathComponent:@"samp"],
|
||||||
[path URLByAppendingPathComponent:@"meta"]}).first;
|
[path URLByAppendingPathComponent:@"meta"])).first;
|
||||||
search->second._attemptLoad(presenter);
|
search->second->_attemptLoad(presenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioGroupCollection::doSearch(const std::string& str)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
m_filterGroups.clear();
|
||||||
|
m_filterGroups.reserve(m_groups.size());
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
if (str.empty() || StrToLower(it->first).find(str) != std::string::npos)
|
||||||
|
{
|
||||||
|
m_filterGroups.push_back(it);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool,
|
AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool,
|
||||||
NSURL* sdir, NSURL* samp, NSURL* meta)
|
NSURL* sdir, NSURL* samp, NSURL* meta)
|
||||||
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta),
|
||||||
@ -120,8 +137,6 @@ AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSUR
|
|||||||
|
|
||||||
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
if (!isDataComplete())
|
|
||||||
return false;
|
|
||||||
if (m_metaData && m_loadedProj)
|
if (m_metaData && m_loadedProj)
|
||||||
return true;
|
return true;
|
||||||
if (!loadProj(presenter))
|
if (!loadProj(presenter))
|
||||||
@ -169,6 +184,40 @@ bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioGroupDataCollection::enable(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
m_metaData->active = true;
|
||||||
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
|
||||||
|
[coord coordinateWritingItemAtURL:m_meta options:0 error:nil
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(newUrl.path.UTF8String, "wb");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fwrite(&*m_metaData, 1, sizeof(*m_metaData), fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioGroupDataCollection::disable(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
m_metaData->active = false;
|
||||||
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter];
|
||||||
|
|
||||||
|
[coord coordinateWritingItemAtURL:m_meta options:0 error:nil
|
||||||
|
byAccessor:^(NSURL* newUrl)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(newUrl.path.UTF8String, "wb");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
fwrite(&*m_metaData, 1, sizeof(*m_metaData), fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl)
|
||||||
{
|
{
|
||||||
if (m_proj)
|
if (m_proj)
|
||||||
@ -319,9 +368,9 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
{
|
{
|
||||||
for (auto& pair : m_audioGroupCollections)
|
for (auto& pair : m_audioGroupCollections)
|
||||||
{
|
{
|
||||||
for (auto& pair2 : pair.second.m_groups)
|
for (auto& pair2 : pair.second->m_groups)
|
||||||
{
|
{
|
||||||
pair2.second.moveURL(oldUrl, newUrl);
|
pair2.second->moveURL(oldUrl, newUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,27 +379,25 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
{
|
{
|
||||||
lastOutlineView = outlineView;
|
lastOutlineView = outlineView;
|
||||||
if (!item)
|
if (!item)
|
||||||
return m_audioGroupCollections.size();
|
return m_filterAudioGroupCollections.size();
|
||||||
|
|
||||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
return collection.m_groups.size();
|
return collection.m_filterGroups.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item
|
- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item
|
||||||
{
|
{
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
auto search = m_iteratorTracker->seekToIndex(index);
|
if (index >= m_filterAudioGroupCollections.size())
|
||||||
if (search == m_audioGroupCollections.end())
|
|
||||||
return nil;
|
return nil;
|
||||||
return search->second.m_token;
|
return m_filterAudioGroupCollections[index]->second->m_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
auto search = collection.m_iteratorTracker->seekToIndex(index);
|
if (index >= collection.m_filterGroups.size())
|
||||||
if (search == collection.m_groups.end())
|
|
||||||
return nil;
|
return nil;
|
||||||
return search->second.m_token;
|
return collection.m_filterGroups[index]->second->m_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
|
- (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
|
||||||
@ -366,7 +413,18 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
{
|
{
|
||||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
return [NSNumber numberWithBool:true];
|
{
|
||||||
|
size_t totalOn = 0;
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
if (pair.second->m_metaData->active)
|
||||||
|
++totalOn;
|
||||||
|
if (totalOn == 0)
|
||||||
|
return [NSNumber numberWithInt:NSOffState];
|
||||||
|
else if (totalOn == collection.m_groups.size())
|
||||||
|
return [NSNumber numberWithInt:NSOnState];
|
||||||
|
else
|
||||||
|
return [NSNumber numberWithInt:NSMixedState];
|
||||||
|
}
|
||||||
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||||
return [NSString stringWithFormat:@"%" PRISize " groups", collection.m_groups.size()];
|
return [NSString stringWithFormat:@"%" PRISize " groups", collection.m_groups.size()];
|
||||||
}
|
}
|
||||||
@ -374,7 +432,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
{
|
{
|
||||||
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||||
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
return [NSNumber numberWithBool:data.m_metaData->active];
|
return [NSNumber numberWithInt:data.m_metaData->active ? NSOnState : NSOffState];
|
||||||
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||||
{
|
{
|
||||||
if (!data.m_loadedProj)
|
if (!data.m_loadedProj)
|
||||||
@ -387,6 +445,43 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable id)item
|
||||||
|
{
|
||||||
|
bool dirty = false;
|
||||||
|
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
|
{
|
||||||
|
NSInteger active = [object integerValue];
|
||||||
|
if (active)
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
pair.second->enable(self);
|
||||||
|
else
|
||||||
|
for (auto& pair : collection.m_groups)
|
||||||
|
pair.second->disable(self);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection;
|
||||||
|
if ([tableColumn.identifier isEqualToString:@"CollectionColumn"])
|
||||||
|
{
|
||||||
|
NSInteger active = [object integerValue];
|
||||||
|
if (active)
|
||||||
|
data.enable(self);
|
||||||
|
else
|
||||||
|
data.disable(self);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirty)
|
||||||
|
[outlineView reloadItem:nil reloadChildren:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(nonnull id)cell forTableColumn:(nullable NSTableColumn *)tableColumn item:(nonnull id)item
|
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(nonnull id)cell forTableColumn:(nullable NSTableColumn *)tableColumn item:(nonnull id)item
|
||||||
{
|
{
|
||||||
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
@ -403,6 +498,13 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
DataOutlineView* ov = notification.object;
|
||||||
|
id item = [ov itemAtRow:ov.selectedRow];
|
||||||
|
[(AppDelegate*)NSApp.delegate outlineView:ov selectionChanged:item];
|
||||||
|
}
|
||||||
|
|
||||||
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection
|
- (BOOL)addCollectionName:(std::string&&)name items:(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&&)collection
|
||||||
{
|
{
|
||||||
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
|
NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self];
|
||||||
@ -410,49 +512,49 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())];
|
NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())];
|
||||||
__block AudioGroupCollection& insert = m_audioGroupCollections.emplace(name, dir).first->second;
|
__block AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(dir)).first->second;
|
||||||
insert.addCollection(std::move(collection));
|
insert.addCollection(std::move(collection));
|
||||||
|
|
||||||
[coord coordinateWritingItemAtURL:m_groupURL options:0 error:nil
|
[coord coordinateWritingItemAtURL:m_groupURL options:0 error:nil
|
||||||
byAccessor:^(NSURL* newUrl)
|
byAccessor:^(NSURL* newUrl)
|
||||||
{
|
{
|
||||||
for (std::pair<const std::string, AudioGroupDataCollection>& pair : insert.m_groups)
|
for (std::pair<const std::string, std::unique_ptr<AudioGroupDataCollection>>& pair : insert.m_groups)
|
||||||
{
|
{
|
||||||
NSURL* collectionUrl = [insert.m_url URLByAppendingPathComponent:@(pair.first.c_str())];
|
NSURL* collectionUrl = [insert.m_url URLByAppendingPathComponent:@(pair.first.c_str())];
|
||||||
[[NSFileManager defaultManager] createDirectoryAtURL:collectionUrl withIntermediateDirectories:YES attributes:nil error:nil];
|
[[NSFileManager defaultManager] createDirectoryAtURL:collectionUrl withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
|
|
||||||
FILE* fp = fopen(pair.second.m_proj.path.UTF8String, "wb");
|
FILE* fp = fopen(pair.second->m_proj.path.UTF8String, "wb");
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite(pair.second.m_projData.data(), 1, pair.second.m_projData.size(), fp);
|
fwrite(pair.second->m_projData.data(), 1, pair.second->m_projData.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(pair.second.m_pool.path.UTF8String, "wb");
|
fp = fopen(pair.second->m_pool.path.UTF8String, "wb");
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite(pair.second.m_poolData.data(), 1, pair.second.m_poolData.size(), fp);
|
fwrite(pair.second->m_poolData.data(), 1, pair.second->m_poolData.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(pair.second.m_sdir.path.UTF8String, "wb");
|
fp = fopen(pair.second->m_sdir.path.UTF8String, "wb");
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite(pair.second.m_sdirData.data(), 1, pair.second.m_sdirData.size(), fp);
|
fwrite(pair.second->m_sdirData.data(), 1, pair.second->m_sdirData.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(pair.second.m_samp.path.UTF8String, "wb");
|
fp = fopen(pair.second->m_samp.path.UTF8String, "wb");
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite(pair.second.m_sampData.data(), 1, pair.second.m_sampData.size(), fp);
|
fwrite(pair.second->m_sampData.data(), 1, pair.second->m_sampData.size(), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(pair.second.m_meta.path.UTF8String, "wb");
|
fp = fopen(pair.second->m_meta.path.UTF8String, "wb");
|
||||||
if (fp)
|
if (fp)
|
||||||
{
|
{
|
||||||
fwrite(&*pair.second.m_metaData, 1, sizeof(*pair.second.m_metaData), fp);
|
fwrite(&*pair.second->m_metaData, 1, sizeof(*pair.second->m_metaData), fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,7 +570,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
return;
|
return;
|
||||||
NSError* coordErr;
|
NSError* coordErr;
|
||||||
__block NSError* managerErr;
|
__block NSError* managerErr;
|
||||||
__block std::map<std::string, AudioGroupCollection>& theMap = m_audioGroupCollections;
|
__block std::map<std::string, std::unique_ptr<AudioGroupCollection>>& theMap = m_audioGroupCollections;
|
||||||
__block AudioGroupFilePresenter* presenter = self;
|
__block AudioGroupFilePresenter* presenter = self;
|
||||||
[coord coordinateReadingItemAtURL:m_groupURL options:NSFileCoordinatorReadingResolvesSymbolicLink error:&coordErr
|
[coord coordinateReadingItemAtURL:m_groupURL options:NSFileCoordinatorReadingResolvesSymbolicLink error:&coordErr
|
||||||
byAccessor:^(NSURL* newUrl)
|
byAccessor:^(NSURL* newUrl)
|
||||||
@ -493,8 +595,8 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
auto search = theMap.find(path.lastPathComponent.UTF8String);
|
auto search = theMap.find(path.lastPathComponent.UTF8String);
|
||||||
if (search == theMap.end())
|
if (search == theMap.end())
|
||||||
{
|
{
|
||||||
search = theMap.emplace(path.lastPathComponent.UTF8String, path).first;
|
search = theMap.emplace(path.lastPathComponent.UTF8String, std::make_unique<AudioGroupCollection>(path)).first;
|
||||||
search->second.update(presenter);
|
search->second->update(presenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -505,12 +607,29 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
|||||||
|
|
||||||
- (void)resetIterators
|
- (void)resetIterators
|
||||||
{
|
{
|
||||||
m_iteratorTracker.emplace(m_audioGroupCollections.begin(), m_audioGroupCollections.end());
|
std::string search;
|
||||||
for (auto& pair : m_audioGroupCollections)
|
if (searchStr)
|
||||||
pair.second.m_iteratorTracker.emplace(pair.second.m_groups.begin(), pair.second.m_groups.end());
|
search = searchStr.UTF8String;
|
||||||
|
|
||||||
|
m_filterAudioGroupCollections.clear();
|
||||||
|
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
||||||
|
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||||
|
if (it->second->doSearch(search) || !searchStr || StrToLower(it->first).find(search) != std::string::npos)
|
||||||
|
m_filterAudioGroupCollections.push_back(it);
|
||||||
[lastOutlineView reloadItem:nil reloadChildren:YES];
|
[lastOutlineView reloadItem:nil reloadChildren:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setSearchFilter:(NSString*)str
|
||||||
|
{
|
||||||
|
searchStr = [str lowercaseString];
|
||||||
|
[self resetIterators];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeSelectedItem
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)init
|
||||||
{
|
{
|
||||||
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
||||||
|
@ -48,7 +48,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainerMainMenu.xib
|
||||||
)
|
)
|
||||||
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.mm
|
add_executable(amuse-au-container MACOSX_BUNDLE AmuseContainingApp.hpp AmuseContainingApp.mm
|
||||||
AudioUnitBackend.hpp AudioUnitBackend.mm
|
AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
Loading…
x
Reference in New Issue
Block a user