mirror of https://github.com/AxioDL/amuse.git
More AudioUnit integration
This commit is contained in:
parent
85b6f406f1
commit
f260019b89
|
@ -297,7 +297,7 @@ CA
|
||||||
<rect key="frame" x="1" y="0.0" width="542" height="366"/>
|
<rect key="frame" x="1" y="0.0" width="542" height="366"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="9pb-bl-sSa" viewBased="YES" id="4nw-rf-Dh4">
|
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="9pb-bl-sSa" viewBased="YES" id="4nw-rf-Dh4">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="542" height="343"/>
|
<rect key="frame" x="0.0" y="0.0" width="542" height="343"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="2"/>
|
||||||
|
@ -418,7 +418,7 @@ CA
|
||||||
<rect key="frame" x="1" y="0.0" width="542" height="365"/>
|
<rect key="frame" x="1" y="0.0" width="542" height="365"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="fQK-tA-ezw" viewBased="YES" id="Frt-wZ-1ZI">
|
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="fQK-tA-ezw" viewBased="YES" id="Frt-wZ-1ZI">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="542" height="342"/>
|
<rect key="frame" x="0.0" y="0.0" width="542" height="342"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="2"/>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present;
|
- (id)initWithAudioGroupPresenter:(AudioGroupFilePresenter*)present;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
@interface AppDelegate : NSObject <NSApplicationDelegate, AudioGroupClient>
|
||||||
{
|
{
|
||||||
IBOutlet NSWindow* mainWindow;
|
IBOutlet NSWindow* mainWindow;
|
||||||
IBOutlet NSOutlineView* dataOutline;
|
IBOutlet NSOutlineView* dataOutline;
|
||||||
|
|
|
@ -30,32 +30,6 @@
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MainView : NSView
|
|
||||||
{
|
|
||||||
AudioUnitViewController* amuseVC;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation MainView
|
|
||||||
|
|
||||||
- (id)initWithFrame:(NSRect)frameRect
|
|
||||||
{
|
|
||||||
self = [super initWithFrame:frameRect];
|
|
||||||
if (!self)
|
|
||||||
return nil;
|
|
||||||
amuseVC = [[AudioUnitViewController alloc] initWithNibName:nil bundle:nil];
|
|
||||||
[self addSubview:amuseVC.view];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)translatesAutoresizingMaskIntoConstraints
|
|
||||||
{
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
|
|
||||||
@implementation DataOutlineView
|
@implementation DataOutlineView
|
||||||
- (id)initWithCoder:(NSCoder *)coder
|
- (id)initWithCoder:(NSCoder *)coder
|
||||||
{
|
{
|
||||||
|
@ -200,7 +174,7 @@
|
||||||
if (presenter->m_sfxTableData.size() <= row)
|
if (presenter->m_sfxTableData.size() <= row)
|
||||||
return;
|
return;
|
||||||
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
AudioGroupSFXToken* sfxToken = presenter->m_sfxTableData[row];
|
||||||
AppDelegate* delegate = NSApp.delegate;
|
AppDelegate* delegate = (AppDelegate*)NSApp.delegate;
|
||||||
[delegate startSFX:sfxToken->m_loadId];
|
[delegate startSFX:sfxToken->m_loadId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +197,7 @@
|
||||||
|
|
||||||
[mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"];
|
[mainWindow.toolbar setSelectedItemIdentifier:@"DataTab"];
|
||||||
|
|
||||||
groupFilePresenter = [AudioGroupFilePresenter new];
|
groupFilePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
|
||||||
|
|
||||||
dataOutline.dataSource = groupFilePresenter;
|
dataOutline.dataSource = groupFilePresenter;
|
||||||
dataOutline.delegate = groupFilePresenter;
|
dataOutline.delegate = groupFilePresenter;
|
||||||
|
@ -331,6 +305,11 @@
|
||||||
return [self importURL:url];
|
return [self importURL:url];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (amuse::Engine&)getAmuseEngine
|
||||||
|
{
|
||||||
|
return *amuseEngine;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int main(int argc, const char * argv[])
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
@class AudioGroupCollectionToken;
|
@class AudioGroupCollectionToken;
|
||||||
@class AudioGroupSFXToken;
|
@class AudioGroupSFXToken;
|
||||||
@class AudioGroupSampleToken;
|
@class AudioGroupSampleToken;
|
||||||
|
@class AudioGroupToken;
|
||||||
|
|
||||||
|
@protocol AudioGroupClient
|
||||||
|
- (amuse::Engine&)getAmuseEngine;
|
||||||
|
@end
|
||||||
|
|
||||||
struct AudioGroupDataCollection
|
struct AudioGroupDataCollection
|
||||||
{
|
{
|
||||||
|
@ -45,6 +50,7 @@ struct AudioGroupDataCollection
|
||||||
|
|
||||||
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
|
std::experimental::optional<amuse::AudioGroupData> m_loadedData;
|
||||||
const amuse::AudioGroup* m_loadedGroup;
|
const amuse::AudioGroup* m_loadedGroup;
|
||||||
|
std::vector<AudioGroupToken*> m_groupTokens;
|
||||||
|
|
||||||
void moveURL(NSURL* oldUrl, NSURL* newUrl);
|
void moveURL(NSURL* oldUrl, NSURL* newUrl);
|
||||||
|
|
||||||
|
@ -57,7 +63,8 @@ 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);
|
||||||
|
bool _indexData(AudioGroupFilePresenter* presenter);
|
||||||
|
|
||||||
void enable(AudioGroupFilePresenter* presenter);
|
void enable(AudioGroupFilePresenter* presenter);
|
||||||
void disable(AudioGroupFilePresenter* presenter);
|
void disable(AudioGroupFilePresenter* presenter);
|
||||||
};
|
};
|
||||||
|
@ -71,9 +78,11 @@ struct AudioGroupCollection
|
||||||
std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups;
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupDataCollection>>::iterator> m_filterGroups;
|
||||||
|
|
||||||
AudioGroupCollection(NSURL* url);
|
AudioGroupCollection(NSURL* url);
|
||||||
void addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
void addCollection(AudioGroupFilePresenter* presenter,
|
||||||
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection);
|
||||||
void update(AudioGroupFilePresenter* presenter);
|
void update(AudioGroupFilePresenter* presenter);
|
||||||
bool doSearch(const std::string& str);
|
bool doSearch(const std::string& str);
|
||||||
|
bool doActiveFilter();
|
||||||
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
void addSFX(std::vector<AudioGroupSFXToken*>& vecOut);
|
||||||
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
void addSamples(std::vector<AudioGroupSampleToken*>& vecOut);
|
||||||
};
|
};
|
||||||
|
@ -114,19 +123,32 @@ struct AudioGroupCollection
|
||||||
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample;
|
amuse::AudioGroupSampleDirectory::ADPCMParms>*)sample;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface AudioGroupToken : NSObject
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
NSString* m_name;
|
||||||
|
const amuse::SongGroupIndex* m_song;
|
||||||
|
const amuse::SFXGroupIndex* m_sfx;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSString*)name songGroup:(const amuse::SongGroupIndex*)group;
|
||||||
|
- (id)initWithName:(NSString*)name sfxGroup:(const amuse::SFXGroupIndex*)group;
|
||||||
|
@end
|
||||||
|
|
||||||
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource, NSOutlineViewDelegate>
|
@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||||
{
|
{
|
||||||
|
@public
|
||||||
|
id<AudioGroupClient> m_audioGroupClient;
|
||||||
NSURL* m_groupURL;
|
NSURL* m_groupURL;
|
||||||
NSOperationQueue* m_dataQueue;
|
NSOperationQueue* m_dataQueue;
|
||||||
std::map<std::string, std::unique_ptr<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;
|
std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections;
|
||||||
NSOutlineView* lastOutlineView;
|
NSOutlineView* m_lastOutlineView;
|
||||||
NSString* searchStr;
|
NSString* m_searchStr;
|
||||||
|
|
||||||
@public
|
|
||||||
std::vector<AudioGroupSFXToken*> m_sfxTableData;
|
std::vector<AudioGroupSFXToken*> m_sfxTableData;
|
||||||
std::vector<AudioGroupSampleToken*> m_sampleTableData;
|
std::vector<AudioGroupSampleToken*> m_sampleTableData;
|
||||||
}
|
}
|
||||||
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client;
|
||||||
- (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;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
#include <athena/FileReader.hpp>
|
#include <athena/FileReader.hpp>
|
||||||
#include <amuse/AudioGroupProject.hpp>
|
#include <amuse/AudioGroupProject.hpp>
|
||||||
#import "AmuseContainingApp.hpp"
|
#import "AmuseContainingApp.hpp"
|
||||||
|
#import "AudioUnitBackend.hpp"
|
||||||
|
#import "AudioUnitViewController.hpp"
|
||||||
|
|
||||||
static std::string StrToLower(const std::string& str)
|
static std::string StrToLower(const std::string& str)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +52,23 @@ static std::string StrToLower(const std::string& str)
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation AudioGroupToken
|
||||||
|
- (id)initWithName:(NSString*)name songGroup:(const amuse::SongGroupIndex*)group
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_song = group;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (id)initWithName:(NSString*)name sfxGroup:(const amuse::SFXGroupIndex*)group
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_name = name;
|
||||||
|
m_sfx = group;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
@implementation AudioGroupFilePresenter
|
@implementation AudioGroupFilePresenter
|
||||||
|
|
||||||
- (NSURL*)presentedItemURL
|
- (NSURL*)presentedItemURL
|
||||||
|
@ -65,7 +84,8 @@ static std::string StrToLower(const std::string& str)
|
||||||
AudioGroupCollection::AudioGroupCollection(NSURL* url)
|
AudioGroupCollection::AudioGroupCollection(NSURL* url)
|
||||||
: m_url(url), m_token([[AudioGroupCollectionToken alloc] initWithCollection:this]) {}
|
: m_url(url), m_token([[AudioGroupCollectionToken alloc] initWithCollection:this]) {}
|
||||||
|
|
||||||
void AudioGroupCollection::addCollection(std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection)
|
void AudioGroupCollection::addCollection(AudioGroupFilePresenter* presenter,
|
||||||
|
std::vector<std::pair<std::string, amuse::IntrusiveAudioGroupData>>&& collection)
|
||||||
{
|
{
|
||||||
for (std::pair<std::string, amuse::IntrusiveAudioGroupData>& pair : collection)
|
for (std::pair<std::string, amuse::IntrusiveAudioGroupData>& pair : collection)
|
||||||
{
|
{
|
||||||
|
@ -98,6 +118,7 @@ void AudioGroupCollection::addCollection(std::vector<std::pair<std::string, amus
|
||||||
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
|
memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize());
|
||||||
|
|
||||||
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
|
dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true);
|
||||||
|
dataCollection._indexData(presenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,6 +173,20 @@ bool AudioGroupCollection::doSearch(const std::string& str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioGroupCollection::doActiveFilter()
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
m_filterGroups.clear();
|
||||||
|
m_filterGroups.reserve(m_groups.size());
|
||||||
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
if (it->second->m_metaData->active)
|
||||||
|
{
|
||||||
|
m_filterGroups.push_back(it);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void AudioGroupCollection::addSFX(std::vector<AudioGroupSFXToken*>& vecOut)
|
void AudioGroupCollection::addSFX(std::vector<AudioGroupSFXToken*>& vecOut)
|
||||||
{
|
{
|
||||||
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
|
@ -209,8 +244,6 @@ AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSUR
|
||||||
|
|
||||||
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
||||||
{
|
{
|
||||||
amuse::Engine& engine = *((AppDelegate*)NSApp.delegate)->amuseEngine;
|
|
||||||
|
|
||||||
if (m_metaData && m_loadedData && m_loadedGroup)
|
if (m_metaData && m_loadedData && m_loadedGroup)
|
||||||
return true;
|
return true;
|
||||||
if (!loadProj(presenter))
|
if (!loadProj(presenter))
|
||||||
|
@ -224,6 +257,13 @@ bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
||||||
if (!loadMeta(presenter))
|
if (!loadMeta(presenter))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return _indexData(presenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioGroupDataCollection::_indexData(AudioGroupFilePresenter* presenter)
|
||||||
|
{
|
||||||
|
amuse::Engine& engine = [presenter->m_audioGroupClient getAmuseEngine];
|
||||||
|
|
||||||
switch (m_metaData->fmt)
|
switch (m_metaData->fmt)
|
||||||
{
|
{
|
||||||
case amuse::DataFormat::GCN:
|
case amuse::DataFormat::GCN:
|
||||||
|
@ -251,6 +291,36 @@ bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
|
m_loadedGroup = engine.addAudioGroup(*m_loadedData);
|
||||||
|
m_groupTokens.clear();
|
||||||
|
if (m_loadedGroup)
|
||||||
|
{
|
||||||
|
m_groupTokens.reserve(m_loadedGroup->getProj().songGroups().size() +
|
||||||
|
m_loadedGroup->getProj().sfxGroups().size());
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto& songGroups = m_loadedGroup->getProj().songGroups();
|
||||||
|
std::map<int, const amuse::SongGroupIndex*> sortGroups;
|
||||||
|
for (const auto& pair : songGroups)
|
||||||
|
sortGroups[pair.first] = &pair.second;
|
||||||
|
for (const auto& pair : sortGroups)
|
||||||
|
{
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
|
||||||
|
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name songGroup:pair.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto& sfxGroups = m_loadedGroup->getProj().sfxGroups();
|
||||||
|
std::map<int, const amuse::SFXGroupIndex*> sortGroups;
|
||||||
|
for (const auto& pair : sfxGroups)
|
||||||
|
sortGroups[pair.first] = &pair.second;
|
||||||
|
for (const auto& pair : sortGroups)
|
||||||
|
{
|
||||||
|
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
|
||||||
|
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name sfxGroup:pair.second]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return m_loadedData && m_loadedGroup;
|
return m_loadedData && m_loadedGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +517,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
|
|
||||||
- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item
|
- (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item
|
||||||
{
|
{
|
||||||
lastOutlineView = outlineView;
|
m_lastOutlineView = outlineView;
|
||||||
if (!item)
|
if (!item)
|
||||||
return m_filterAudioGroupCollections.size();
|
return m_filterAudioGroupCollections.size();
|
||||||
|
|
||||||
|
@ -496,7 +566,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
return [NSNumber numberWithInt:NSMixedState];
|
return [NSNumber numberWithInt:NSMixedState];
|
||||||
}
|
}
|
||||||
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"])
|
||||||
return [NSString stringWithFormat:@"%zu Audio Group%s",
|
return [NSString stringWithFormat:@"%zu Group File%s",
|
||||||
collection.m_groups.size(),
|
collection.m_groups.size(),
|
||||||
collection.m_groups.size() > 1 ? "s" : ""];
|
collection.m_groups.size() > 1 ? "s" : ""];
|
||||||
}
|
}
|
||||||
|
@ -620,7 +690,7 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
|
|
||||||
NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())];
|
NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())];
|
||||||
__block AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(dir)).first->second;
|
__block AudioGroupCollection& insert = *m_audioGroupCollections.emplace(name, std::make_unique<AudioGroupCollection>(dir)).first->second;
|
||||||
insert.addCollection(std::move(collection));
|
insert.addCollection(self, 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)
|
||||||
|
@ -715,34 +785,52 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
|
|
||||||
- (void)resetIterators
|
- (void)resetIterators
|
||||||
{
|
{
|
||||||
std::string search;
|
if ([(NSObject*)m_audioGroupClient isKindOfClass:[AppDelegate class]])
|
||||||
if (searchStr)
|
|
||||||
search = searchStr.UTF8String;
|
|
||||||
|
|
||||||
m_sfxTableData.clear();
|
|
||||||
m_sampleTableData.clear();
|
|
||||||
m_filterAudioGroupCollections.clear();
|
|
||||||
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
|
||||||
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
|
||||||
{
|
{
|
||||||
it->second->addSFX(m_sfxTableData);
|
std::string search;
|
||||||
it->second->addSamples(m_sampleTableData);
|
if (m_searchStr)
|
||||||
if (it->second->doSearch(search) || !searchStr || StrToLower(it->first).find(search) != std::string::npos)
|
search = m_searchStr.UTF8String;
|
||||||
m_filterAudioGroupCollections.push_back(it);
|
|
||||||
|
m_sfxTableData.clear();
|
||||||
|
m_sampleTableData.clear();
|
||||||
|
m_filterAudioGroupCollections.clear();
|
||||||
|
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
||||||
|
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||||
|
{
|
||||||
|
it->second->addSFX(m_sfxTableData);
|
||||||
|
it->second->addSamples(m_sampleTableData);
|
||||||
|
if (it->second->doSearch(search) || !m_searchStr || StrToLower(it->first).find(search) != std::string::npos)
|
||||||
|
m_filterAudioGroupCollections.push_back(it);
|
||||||
|
}
|
||||||
|
[m_lastOutlineView reloadItem:nil reloadChildren:YES];
|
||||||
|
[(AppDelegate*)m_audioGroupClient reloadTables];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_sfxTableData.clear();
|
||||||
|
m_sampleTableData.clear();
|
||||||
|
m_filterAudioGroupCollections.clear();
|
||||||
|
m_filterAudioGroupCollections.reserve(m_audioGroupCollections.size());
|
||||||
|
for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it)
|
||||||
|
{
|
||||||
|
it->second->addSFX(m_sfxTableData);
|
||||||
|
it->second->addSamples(m_sampleTableData);
|
||||||
|
if (it->second->doActiveFilter())
|
||||||
|
m_filterAudioGroupCollections.push_back(it);
|
||||||
|
}
|
||||||
|
[((AmuseAudioUnit*)m_audioGroupClient)->m_viewController->m_groupBrowser loadColumnZero];
|
||||||
}
|
}
|
||||||
[lastOutlineView reloadItem:nil reloadChildren:YES];
|
|
||||||
[(AppDelegate*)NSApp.delegate reloadTables];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSearchFilter:(NSString*)str
|
- (void)setSearchFilter:(NSString*)str
|
||||||
{
|
{
|
||||||
searchStr = [str lowercaseString];
|
m_searchStr = [str lowercaseString];
|
||||||
[self resetIterators];
|
[self resetIterators];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeSelectedItem
|
- (void)removeSelectedItem
|
||||||
{
|
{
|
||||||
id item = [lastOutlineView itemAtRow:lastOutlineView.selectedRow];
|
id item = [m_lastOutlineView itemAtRow:m_lastOutlineView.selectedRow];
|
||||||
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
{
|
{
|
||||||
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection;
|
||||||
|
@ -752,12 +840,13 @@ bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter)
|
||||||
[self resetIterators];
|
[self resetIterators];
|
||||||
[[NSFileManager defaultManager] removeItemAtURL:collectionURL error:nil];
|
[[NSFileManager defaultManager] removeItemAtURL:collectionURL error:nil];
|
||||||
if (m_audioGroupCollections.empty())
|
if (m_audioGroupCollections.empty())
|
||||||
[(AppDelegate*)NSApp.delegate outlineView:(DataOutlineView*)lastOutlineView selectionChanged:nil];
|
[(AppDelegate*)NSApp.delegate outlineView:(DataOutlineView*)m_lastOutlineView selectionChanged:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init
|
- (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
|
||||||
{
|
{
|
||||||
|
m_audioGroupClient = client;
|
||||||
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
|
||||||
if (!m_groupURL)
|
if (!m_groupURL)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
|
@ -16,23 +16,16 @@
|
||||||
#include "amuse/IBackendVoice.hpp"
|
#include "amuse/IBackendVoice.hpp"
|
||||||
#include "amuse/IBackendSubmix.hpp"
|
#include "amuse/IBackendSubmix.hpp"
|
||||||
#include "amuse/IBackendVoiceAllocator.hpp"
|
#include "amuse/IBackendVoiceAllocator.hpp"
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
|
||||||
|
@class AudioUnitViewController;
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
|
||||||
/** Backend MIDI event reader for controlling sequencer with external hardware / software */
|
|
||||||
class AudioUnitBackendMIDIReader : public BooBackendMIDIReader
|
|
||||||
{
|
|
||||||
friend class AudioUnitBackendVoiceAllocator;
|
|
||||||
public:
|
|
||||||
AudioUnitBackendMIDIReader(Engine& engine)
|
|
||||||
: BooBackendMIDIReader(engine, "AudioUnit MIDI") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Backend voice allocator implementation for AudioUnit mixer */
|
/** Backend voice allocator implementation for AudioUnit mixer */
|
||||||
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
class AudioUnitBackendVoiceAllocator : public BooBackendVoiceAllocator
|
||||||
{
|
{
|
||||||
friend class AudioUnitBackendMIDIReader;
|
|
||||||
public:
|
public:
|
||||||
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
AudioUnitBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine)
|
||||||
: BooBackendVoiceAllocator(booEngine) {}
|
: BooBackendVoiceAllocator(booEngine) {}
|
||||||
|
@ -42,13 +35,20 @@ void RegisterAudioUnit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface AmuseAudioUnit : AUAudioUnit
|
@interface AmuseAudioUnit : AUAudioUnit <AudioGroupClient>
|
||||||
{
|
{
|
||||||
|
@public
|
||||||
|
AudioUnitViewController* m_viewController;
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
|
std::unique_ptr<boo::IAudioVoiceEngine> m_booBackend;
|
||||||
std::experimental::optional<amuse::AudioUnitBackendVoiceAllocator> m_voxAlloc;
|
std::experimental::optional<amuse::AudioUnitBackendVoiceAllocator> m_voxAlloc;
|
||||||
std::experimental::optional<amuse::Engine> m_engine;
|
std::experimental::optional<amuse::Engine> m_engine;
|
||||||
|
AudioGroupFilePresenter* m_filePresenter;
|
||||||
|
AUAudioUnitBus* m_outBus;
|
||||||
AUAudioUnitBusArray* m_outs;
|
AUAudioUnitBusArray* m_outs;
|
||||||
}
|
}
|
||||||
|
- (nullable id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
|
error:(NSError * __nullable * __nonnull)outError
|
||||||
|
viewController:(AudioUnitViewController* __nonnull)vc;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,13 +12,15 @@
|
||||||
|
|
||||||
#include "logvisor/logvisor.hpp"
|
#include "logvisor/logvisor.hpp"
|
||||||
#include "audiodev/AudioVoiceEngine.hpp"
|
#include "audiodev/AudioVoiceEngine.hpp"
|
||||||
|
#import "AudioUnitViewController.hpp"
|
||||||
|
|
||||||
static logvisor::Module Log("amuse::AudioUnitBackend");
|
static logvisor::Module Log("amuse::AudioUnitBackend");
|
||||||
|
|
||||||
struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
|
std::vector<float> m_interleavedBuf;
|
||||||
std::vector<std::unique_ptr<float[]>> m_renderBufs;
|
std::vector<std::unique_ptr<float[]>> m_renderBufs;
|
||||||
size_t m_frameBytes;
|
size_t m_renderFrames = 0;
|
||||||
AudioBufferList* m_outputData = nullptr;
|
AudioBufferList* m_outputData = nullptr;
|
||||||
|
|
||||||
boo::AudioChannelSet _getAvailableSet()
|
boo::AudioChannelSet _getAvailableSet()
|
||||||
|
@ -31,12 +33,24 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
boo::ReceiveFunctor m_midiReceiver = nullptr;
|
boo::ReceiveFunctor* m_midiReceiver = nullptr;
|
||||||
|
|
||||||
|
struct MIDIIn : public boo::IMIDIIn
|
||||||
|
{
|
||||||
|
MIDIIn(bool virt, boo::ReceiveFunctor&& receiver)
|
||||||
|
: IMIDIIn(virt, std::move(receiver)) {}
|
||||||
|
|
||||||
|
std::string description() const
|
||||||
|
{
|
||||||
|
return "AudioUnit MIDI";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
std::unique_ptr<boo::IMIDIIn> newVirtualMIDIIn(boo::ReceiveFunctor&& receiver)
|
||||||
{
|
{
|
||||||
m_midiReceiver = std::move(receiver);
|
std::unique_ptr<boo::IMIDIIn> ret = std::make_unique<MIDIIn>(true, std::move(receiver));
|
||||||
return {};
|
m_midiReceiver = &ret->m_receiver;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut()
|
std::unique_ptr<boo::IMIDIOut> newVirtualMIDIOut()
|
||||||
|
@ -63,106 +77,140 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool useMIDILock() const {return false;}
|
||||||
|
|
||||||
AudioUnitVoiceEngine()
|
AudioUnitVoiceEngine()
|
||||||
{
|
{
|
||||||
m_mixInfo.m_channels = _getAvailableSet();
|
m_mixInfo.m_periodFrames = 512;
|
||||||
unsigned chCount = ChannelCount(m_mixInfo.m_channels);
|
|
||||||
|
|
||||||
m_mixInfo.m_sampleRate = 96000.0;
|
m_mixInfo.m_sampleRate = 96000.0;
|
||||||
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
|
m_mixInfo.m_sampleFormat = SOXR_FLOAT32_I;
|
||||||
m_mixInfo.m_bitsPerSample = 32;
|
m_mixInfo.m_bitsPerSample = 32;
|
||||||
m_5msFrames = 96000 * 5 / 1000;
|
_buildAudioRenderClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _buildAudioRenderClient()
|
||||||
|
{
|
||||||
|
m_mixInfo.m_channels = _getAvailableSet();
|
||||||
|
unsigned chCount = ChannelCount(m_mixInfo.m_channels);
|
||||||
|
|
||||||
|
m_5msFrames = m_mixInfo.m_sampleRate * 5 / 1000;
|
||||||
|
|
||||||
boo::ChannelMap& chMapOut = m_mixInfo.m_channelMap;
|
boo::ChannelMap& chMapOut = m_mixInfo.m_channelMap;
|
||||||
chMapOut.m_channelCount = 2;
|
chMapOut.m_channelCount = 2;
|
||||||
chMapOut.m_channels[0] = boo::AudioChannel::FrontLeft;
|
chMapOut.m_channels[0] = boo::AudioChannel::FrontLeft;
|
||||||
chMapOut.m_channels[1] = boo::AudioChannel::FrontRight;
|
chMapOut.m_channels[1] = boo::AudioChannel::FrontRight;
|
||||||
|
|
||||||
while (chMapOut.m_channelCount < chCount)
|
while (chMapOut.m_channelCount < chCount)
|
||||||
chMapOut.m_channels[chMapOut.m_channelCount++] = boo::AudioChannel::Unknown;
|
chMapOut.m_channels[chMapOut.m_channelCount++] = boo::AudioChannel::Unknown;
|
||||||
|
}
|
||||||
m_mixInfo.m_periodFrames = 2400;
|
|
||||||
|
void _rebuildAudioRenderClient(double sampleRate, size_t periodFrames)
|
||||||
m_frameBytes = m_mixInfo.m_periodFrames * m_mixInfo.m_channelMap.m_channelCount * 4;
|
{
|
||||||
|
m_mixInfo.m_periodFrames = periodFrames;
|
||||||
|
m_mixInfo.m_sampleRate = sampleRate;
|
||||||
|
_buildAudioRenderClient();
|
||||||
|
|
||||||
|
for (boo::AudioVoice* vox : m_activeVoices)
|
||||||
|
vox->_resetSampleRate(vox->m_sampleRateIn);
|
||||||
|
for (boo::AudioSubmix* smx : m_activeSubmixes)
|
||||||
|
smx->_resetOutputSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pumpAndMixVoices()
|
void pumpAndMixVoices()
|
||||||
{
|
{
|
||||||
if (m_renderBufs.size() < m_outputData->mNumberBuffers)
|
_pumpAndMixVoices(m_renderFrames, m_interleavedBuf.data());
|
||||||
m_renderBufs.resize(m_outputData->mNumberBuffers);
|
|
||||||
|
|
||||||
for (int i=0 ; i<m_outputData->mNumberBuffers ; ++i)
|
for (size_t i=0 ; i<m_renderBufs.size() ; ++i)
|
||||||
{
|
{
|
||||||
std::unique_ptr<float[]>& buf = m_renderBufs[i];
|
std::unique_ptr<float[]>& buf = m_renderBufs[i];
|
||||||
AudioBuffer& auBuf = m_outputData->mBuffers[i];
|
AudioBuffer& auBuf = m_outputData->mBuffers[i];
|
||||||
if (!auBuf.mData)
|
if (!auBuf.mData)
|
||||||
{
|
{
|
||||||
buf.reset(new float[auBuf.mDataByteSize]);
|
buf.reset(new float[auBuf.mDataByteSize / 4]);
|
||||||
auBuf.mData = buf.get();
|
auBuf.mData = buf.get();
|
||||||
}
|
}
|
||||||
|
for (size_t f=0 ; f<m_renderFrames ; ++f)
|
||||||
_pumpAndMixVoices(auBuf.mDataByteSize / 2 / 4, reinterpret_cast<float*>(auBuf.mData));
|
{
|
||||||
|
float* bufOut = reinterpret_cast<float*>(auBuf.mData);
|
||||||
|
bufOut[f] = m_interleavedBuf[f*2+i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@implementation AmuseAudioUnit
|
@implementation AmuseAudioUnit
|
||||||
|
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
|
error:(NSError * _Nullable *)outError
|
||||||
|
viewController:(AudioUnitViewController*)vc
|
||||||
|
{
|
||||||
|
m_viewController = vc;
|
||||||
|
vc->m_audioUnit = self;
|
||||||
|
self = [super initWithComponentDescription:componentDescription error:outError];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
- (id)initWithComponentDescription:(AudioComponentDescription)componentDescription
|
||||||
options:(AudioComponentInstantiationOptions)options
|
options:(AudioComponentInstantiationOptions)options
|
||||||
error:(NSError * _Nullable *)outError;
|
error:(NSError * _Nullable *)outError
|
||||||
{
|
{
|
||||||
self = [super initWithComponentDescription:componentDescription options:options error:outError];
|
self = [super initWithComponentDescription:componentDescription options:options error:outError];
|
||||||
if (!self)
|
if (!self)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
AUAudioUnitBus* outBus = [[AUAudioUnitBus alloc] initWithFormat:
|
AVAudioFormat* format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:96000.0 channels:2];
|
||||||
[[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
|
m_outBus = [[AUAudioUnitBus alloc] initWithFormat:format error:outError];
|
||||||
sampleRate:96000.0
|
if (!m_outBus)
|
||||||
channels:2
|
|
||||||
interleaved:TRUE]
|
|
||||||
error:outError];
|
|
||||||
if (!outBus)
|
|
||||||
return nil;
|
return nil;
|
||||||
|
//m_outBus.supportedChannelCounts = @[@1,@2];
|
||||||
m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses:@[outBus]];
|
m_outBus.maximumChannelCount = 2;
|
||||||
|
|
||||||
self.maximumFramesToRender = 2400;
|
m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses:@[m_outBus]];
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)allocateRenderResourcesAndReturnError:(NSError * _Nullable *)outError
|
|
||||||
{
|
|
||||||
if (![super allocateRenderResourcesAndReturnError:outError])
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
m_booBackend = std::make_unique<AudioUnitVoiceEngine>();
|
m_booBackend = std::make_unique<AudioUnitVoiceEngine>();
|
||||||
if (!m_booBackend)
|
if (!m_booBackend)
|
||||||
{
|
{
|
||||||
*outError = [NSError errorWithDomain:@"amuse" code:-1
|
*outError = [NSError errorWithDomain:@"amuse" code:-1
|
||||||
userInfo:@{NSLocalizedDescriptionKey:@"Unable to construct boo mixer"}];
|
userInfo:@{NSLocalizedDescriptionKey:@"Unable to construct boo mixer"}];
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_voxAlloc.emplace(*m_booBackend);
|
m_voxAlloc.emplace(*m_booBackend);
|
||||||
m_engine.emplace(*m_voxAlloc);
|
m_engine.emplace(*m_voxAlloc);
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^
|
||||||
|
{
|
||||||
|
m_filePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
|
||||||
|
});
|
||||||
|
|
||||||
|
self.maximumFramesToRender = 512;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError
|
||||||
|
{
|
||||||
|
if (![super allocateRenderResourcesAndReturnError:outError])
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
size_t chanCount = m_outBus.format.channelCount;
|
||||||
|
size_t renderFrames = self.maximumFramesToRender;
|
||||||
|
|
||||||
|
NSLog(@"Alloc Chans: %zu Frames: %zu SampRate: %f", chanCount, renderFrames, m_outBus.format.sampleRate);
|
||||||
|
|
||||||
|
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
|
voxEngine.m_renderFrames = renderFrames;
|
||||||
|
voxEngine.m_interleavedBuf.resize(renderFrames * std::max(2ul, chanCount));
|
||||||
|
voxEngine.m_renderBufs.resize(chanCount);
|
||||||
|
voxEngine._rebuildAudioRenderClient(m_outBus.format.sampleRate, renderFrames);
|
||||||
|
|
||||||
*outError = nil;
|
*outError = nil;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deallocateRenderResources
|
- (void)deallocateRenderResources
|
||||||
{
|
{
|
||||||
m_engine = std::experimental::nullopt;
|
|
||||||
m_voxAlloc = std::experimental::nullopt;
|
|
||||||
m_booBackend.reset();
|
|
||||||
[super deallocateRenderResources];
|
[super deallocateRenderResources];
|
||||||
}
|
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
|
||||||
|
voxEngine.m_renderBufs.clear();
|
||||||
- (BOOL)renderResourcesAllocated
|
|
||||||
{
|
|
||||||
if (m_engine)
|
|
||||||
return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (AUAudioUnitBusArray*)outputBusses
|
- (AUAudioUnitBusArray*)outputBusses
|
||||||
|
@ -197,18 +245,25 @@ struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
|
||||||
{
|
{
|
||||||
if (event->eventType == AURenderEventMIDI)
|
if (event->eventType == AURenderEventMIDI)
|
||||||
{
|
{
|
||||||
voxEngine.m_midiReceiver(std::vector<uint8_t>(std::cbegin(event->data),
|
NSLog(@"MIDI %d %d", event->length, event->data[0]);
|
||||||
std::cbegin(event->data) + event->length));
|
(*voxEngine.m_midiReceiver)(std::vector<uint8_t>(std::cbegin(event->data),
|
||||||
|
std::cbegin(event->data) + event->length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output buffers */
|
/* Output buffers */
|
||||||
|
voxEngine.m_renderFrames = frameCount;
|
||||||
voxEngine.m_outputData = outputData;
|
voxEngine.m_outputData = outputData;
|
||||||
amuseEngine.pumpEngine();
|
amuseEngine.pumpEngine();
|
||||||
return noErr;
|
return noErr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (amuse::Engine&)getAmuseEngine
|
||||||
|
{
|
||||||
|
return *m_engine;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
|
|
|
@ -2,9 +2,24 @@
|
||||||
#define __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
#define __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
||||||
|
|
||||||
#import <CoreAudioKit/CoreAudioKit.h>
|
#import <CoreAudioKit/CoreAudioKit.h>
|
||||||
|
#import "AudioGroupFilePresenter.hpp"
|
||||||
|
|
||||||
|
@class AmuseAudioUnit;
|
||||||
|
|
||||||
|
@interface GroupBrowserDelegate : NSObject <NSBrowserDelegate>
|
||||||
|
{
|
||||||
|
AmuseAudioUnit* m_audioUnit;
|
||||||
|
}
|
||||||
|
- (id)initWithAudioUnit:(AmuseAudioUnit*)au;
|
||||||
|
@end
|
||||||
|
|
||||||
@interface AudioUnitViewController : AUViewController <AUAudioUnitFactory>
|
@interface AudioUnitViewController : AUViewController <AUAudioUnitFactory>
|
||||||
|
{
|
||||||
|
@public
|
||||||
|
AmuseAudioUnit* m_audioUnit;
|
||||||
|
IBOutlet NSBrowser* m_groupBrowser;
|
||||||
|
GroupBrowserDelegate* m_groupBrowserDelegate;
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif // __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
#endif // __AMUSE_AUDIOUNIT_VIEWCONTROLLER_HPP__
|
||||||
|
|
|
@ -5,73 +5,155 @@
|
||||||
#error ARC Required
|
#error ARC Required
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@interface AudioUnitView : NSView
|
@implementation GroupBrowserDelegate
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column
|
||||||
{
|
{
|
||||||
NSButton* m_fileButton;
|
if (column == 0)
|
||||||
|
return YES;
|
||||||
|
else if (column == 1)
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = [sender selectedCellInColumn:0];
|
||||||
|
if (collection)
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
else if (column == 2)
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = [sender selectedCellInColumn:1];
|
||||||
|
if (groupFile)
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
}
|
}
|
||||||
- (void)clickFileButton;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AudioUnitView
|
- (NSInteger)browser:(NSBrowser *)sender numberOfRowsInColumn:(NSInteger)column
|
||||||
|
|
||||||
- (id)init
|
|
||||||
{
|
{
|
||||||
self = [super initWithFrame:NSMakeRect(0, 0, 200, 300)];
|
if (column == 0)
|
||||||
m_fileButton = [[NSButton alloc] initWithFrame:NSMakeRect(100, 100, 30, 10)];
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections.size();
|
||||||
m_fileButton.target = self;
|
else if (column == 1)
|
||||||
m_fileButton.action = @selector(clickFileButton);
|
{
|
||||||
[self addSubview:m_fileButton];
|
AudioGroupCollectionToken* collection = [sender selectedCellInColumn:0];
|
||||||
|
if (!collection)
|
||||||
|
return 0;
|
||||||
|
return collection->m_collection->m_filterGroups.size();
|
||||||
|
}
|
||||||
|
else if (column == 2)
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = [sender selectedCellInColumn:1];
|
||||||
|
if (!groupFile)
|
||||||
|
return 0;
|
||||||
|
const amuse::AudioGroup* audioGroupFile = groupFile->m_collection->m_loadedGroup;
|
||||||
|
return audioGroupFile->getProj().songGroups().size() + audioGroupFile->getProj().sfxGroups().size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections.size();
|
||||||
|
else if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_filterGroups.size();
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
const amuse::AudioGroup* audioGroupFile = groupFile->m_collection->m_loadedGroup;
|
||||||
|
return audioGroupFile->getProj().songGroups().size() + audioGroupFile->getProj().sfxGroups().size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)browser:(NSBrowser *)sender titleOfColumn:(NSInteger)column
|
||||||
|
{
|
||||||
|
if (column == 0)
|
||||||
|
return @"Collection";
|
||||||
|
else if (column == 1)
|
||||||
|
return @"File";
|
||||||
|
else if (column == 2)
|
||||||
|
return @"Group";
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return m_audioUnit->m_filePresenter->m_filterAudioGroupCollections[index]->second->m_token;
|
||||||
|
else if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_filterGroups[index]->second->m_token;
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
return groupFile->m_collection->m_groupTokens[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item
|
||||||
|
{
|
||||||
|
if ([item isKindOfClass:[AudioGroupToken class]])
|
||||||
|
return YES;
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)browser:(NSBrowser *)browser shouldEditItem:(id)item
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)browser:(NSBrowser *)browser objectValueForItem:(id)item
|
||||||
|
{
|
||||||
|
if ([item isKindOfClass:[AudioGroupCollectionToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupCollectionToken* collection = item;
|
||||||
|
return collection->m_collection->m_url.lastPathComponent;
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupDataToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupDataToken* groupFile = item;
|
||||||
|
return @(groupFile->m_collection->m_name.c_str());
|
||||||
|
}
|
||||||
|
else if ([item isKindOfClass:[AudioGroupToken class]])
|
||||||
|
{
|
||||||
|
AudioGroupToken* group = item;
|
||||||
|
return group->m_name;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithAudioUnit:(AmuseAudioUnit*)au
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
m_audioUnit = au;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clickFileButton
|
|
||||||
{
|
|
||||||
NSLog(@"Click");
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface AudioUnitViewController ()
|
@implementation AudioUnitViewController
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation AudioUnitViewController {
|
|
||||||
AUAudioUnit *audioUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) viewDidLoad {
|
- (void) viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
if (!audioUnit) {
|
self.preferredContentSize = NSMakeSize(510, 312);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the parameter tree and add observers for any parameters that the UI needs to keep in sync with the AudioUnit
|
// Get the parameter tree and add observers for any parameters that the UI needs to keep in sync with the AudioUnit
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)loadView
|
|
||||||
{
|
|
||||||
self.view = [AudioUnitView new];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredContentSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredMaximumSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSSize)preferredMinimumSize
|
|
||||||
{
|
|
||||||
return NSMakeSize(200, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (AUAudioUnit*)createAudioUnitWithComponentDescription:(AudioComponentDescription)desc error:(NSError**)error {
|
- (AUAudioUnit*)createAudioUnitWithComponentDescription:(AudioComponentDescription)desc error:(NSError**)error {
|
||||||
audioUnit = [[AmuseAudioUnit alloc] initWithComponentDescription:desc error:error];
|
m_audioUnit = [[AmuseAudioUnit alloc] initWithComponentDescription:desc error:error viewController:self];
|
||||||
return audioUnit;
|
m_groupBrowserDelegate = [[GroupBrowserDelegate alloc] initWithAudioUnit:m_audioUnit];
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^
|
||||||
|
{
|
||||||
|
m_groupBrowser.delegate = m_groupBrowserDelegate;
|
||||||
|
});
|
||||||
|
return m_audioUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10116" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10116"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="AudioUnitViewController">
|
||||||
|
<connections>
|
||||||
|
<outlet property="m_groupBrowser" destination="Pbx-jL-10p" id="BEh-LF-c7K"/>
|
||||||
|
<outlet property="view" destination="Pbx-jL-10p" id="dfL-uY-h99"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<browser verticalHuggingPriority="750" allowsExpansionToolTips="YES" enabled="YES" hasHorizontalScroller="YES" allowsEmptySelection="YES" defaultColumnWidth="100" minColumnWidth="100" maxVisibleColumns="3" titled="YES" separatesColumns="YES" allowsTypeSelect="YES" sendsActionOnArrowKeys="YES" columnResizingType="auto" id="Pbx-jL-10p">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="510" height="312"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<point key="canvasLocation" x="313" y="621"/>
|
||||||
|
</browser>
|
||||||
|
</objects>
|
||||||
|
</document>
|
|
@ -21,9 +21,18 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
if(EXISTS "${PROV_PROFILE}")
|
if(EXISTS "${PROV_PROFILE}")
|
||||||
|
|
||||||
# Extension App
|
# Extension App
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
COMMAND ibtool --errors --warnings --notices --module amuse_au --auto-activate-custom-fonts
|
||||||
|
--target-device mac --minimum-deployment-target 10.11 --output-format human-readable-text --compile
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/AudioUnitViewController.xib
|
||||||
|
)
|
||||||
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
add_executable(amuse-au MACOSX_BUNDLE AudioUnitBackend.hpp AudioUnitBackend.mm
|
||||||
AudioUnitViewController.hpp AudioUnitViewController.mm
|
AudioUnitViewController.hpp AudioUnitViewController.mm
|
||||||
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm)
|
AudioGroupFilePresenter.hpp AudioGroupFilePresenter.mm
|
||||||
|
AudioUnitViewController.nib)
|
||||||
|
|
||||||
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse.AudioUnit")
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseExtension.entitlements.in
|
||||||
|
@ -69,6 +78,9 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${APPLE_DEV_ID}")
|
||||||
|
|
||||||
add_custom_command(TARGET amuse-au POST_BUILD
|
add_custom_command(TARGET amuse-au POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/AudioUnitViewController.nib"
|
||||||
|
"$<TARGET_FILE_DIR:amuse-au>/../Resources/AudioUnitViewController.nib"
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
COMMAND ${CMAKE_COMMAND} -E copy "${PROV_PROFILE}" "$<TARGET_FILE_DIR:amuse-au>/../embedded.provisionprofile"
|
||||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
COMMAND ${CMAKE_COMMAND} -E remove_directory "$<TARGET_FILE_DIR:amuse-au-container>/../PlugIns/amuse-au.appex"
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_FILE_DIR:amuse-au>/../.."
|
||||||
|
|
|
@ -76,13 +76,14 @@ class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader
|
||||||
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
std::unique_ptr<boo::IMIDIIn> m_midiIn;
|
||||||
boo::MIDIDecoder m_decoder;
|
boo::MIDIDecoder m_decoder;
|
||||||
|
|
||||||
|
bool m_useLock;
|
||||||
std::list<std::pair<std::chrono::steady_clock::time_point, std::vector<uint8_t>>> m_queue;
|
std::list<std::pair<std::chrono::steady_clock::time_point, std::vector<uint8_t>>> m_queue;
|
||||||
std::mutex m_midiMutex;
|
std::mutex m_midiMutex;
|
||||||
void _MIDIReceive(std::vector<uint8_t>&& bytes);
|
void _MIDIReceive(std::vector<uint8_t>&& bytes);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~BooBackendMIDIReader();
|
~BooBackendMIDIReader();
|
||||||
BooBackendMIDIReader(Engine& engine, const char* name);
|
BooBackendMIDIReader(Engine& engine, const char* name, bool useLock);
|
||||||
|
|
||||||
std::string description();
|
std::string description();
|
||||||
void pumpReader(double dt);
|
void pumpReader(double dt);
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Sequencer : public Entity
|
||||||
{
|
{
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */
|
const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */
|
||||||
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup */
|
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
||||||
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
|
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
|
||||||
|
|
||||||
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
||||||
|
@ -44,7 +44,7 @@ class Sequencer : public Entity
|
||||||
{
|
{
|
||||||
Sequencer& m_parent;
|
Sequencer& m_parent;
|
||||||
uint8_t m_chanId;
|
uint8_t m_chanId;
|
||||||
const SongGroupIndex::MIDISetup& m_setup;
|
const SongGroupIndex::MIDISetup* m_setup = nullptr; /* Channel defaults to program 0 if null */
|
||||||
const SongGroupIndex::PageEntry* m_page = nullptr;
|
const SongGroupIndex::PageEntry* m_page = nullptr;
|
||||||
~ChannelState();
|
~ChannelState();
|
||||||
ChannelState(Sequencer& parent, uint8_t chanId);
|
ChannelState(Sequencer& parent, uint8_t chanId);
|
||||||
|
@ -79,6 +79,7 @@ class Sequencer : public Entity
|
||||||
|
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
void _destroy();
|
void _destroy();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Sequencer();
|
~Sequencer();
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
|
|
|
@ -119,8 +119,8 @@ std::string BooBackendMIDIReader::description()
|
||||||
|
|
||||||
BooBackendMIDIReader::~BooBackendMIDIReader() {}
|
BooBackendMIDIReader::~BooBackendMIDIReader() {}
|
||||||
|
|
||||||
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name)
|
BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name, bool useLock)
|
||||||
: m_engine(engine), m_decoder(*this)
|
: m_engine(engine), m_decoder(*this), m_useLock(useLock)
|
||||||
{
|
{
|
||||||
BooBackendVoiceAllocator& voxAlloc = static_cast<BooBackendVoiceAllocator&>(engine.getBackend());
|
BooBackendVoiceAllocator& voxAlloc = static_cast<BooBackendVoiceAllocator&>(engine.getBackend());
|
||||||
if (!name)
|
if (!name)
|
||||||
|
@ -145,7 +145,9 @@ BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name)
|
||||||
|
|
||||||
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes)
|
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lk(m_midiMutex);
|
std::unique_lock<std::mutex> lk(m_midiMutex, std::defer_lock_t{});
|
||||||
|
if (m_useLock)
|
||||||
|
lk.lock();
|
||||||
m_queue.emplace_back(std::chrono::steady_clock::now(), std::move(bytes));
|
m_queue.emplace_back(std::chrono::steady_clock::now(), std::move(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +310,7 @@ std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enume
|
||||||
|
|
||||||
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
std::unique_ptr<IMIDIReader> BooBackendVoiceAllocator::allocateMIDIReader(Engine& engine, const char* name)
|
||||||
{
|
{
|
||||||
std::unique_ptr<IMIDIReader> ret = std::make_unique<BooBackendMIDIReader>(engine, name);
|
std::unique_ptr<IMIDIReader> ret = std::make_unique<BooBackendMIDIReader>(engine, name, m_booEngine.useMIDILock());
|
||||||
if (!static_cast<BooBackendMIDIReader&>(*ret).m_midiIn)
|
if (!static_cast<BooBackendMIDIReader&>(*ret).m_midiIn)
|
||||||
return {};
|
return {};
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -79,25 +79,50 @@ Sequencer::ChannelState::~ChannelState()
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
Sequencer::ChannelState::ChannelState(Sequencer& parent, uint8_t chanId)
|
||||||
: m_parent(parent), m_chanId(chanId), m_setup(m_parent.m_midiSetup[chanId])
|
: m_parent(parent), m_chanId(chanId)
|
||||||
{
|
{
|
||||||
if (chanId == 9)
|
if (m_parent.m_midiSetup)
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup.m_drumPages.find(m_setup.programNo);
|
m_setup = &m_parent.m_midiSetup[chanId];
|
||||||
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
|
||||||
m_page = it->second;
|
if (chanId == 9)
|
||||||
|
{
|
||||||
|
auto it = m_parent.m_songGroup.m_drumPages.find(m_setup->programNo);
|
||||||
|
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = m_parent.m_songGroup.m_normPages.find(m_setup->programNo);
|
||||||
|
if (it != m_parent.m_songGroup.m_normPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curVol = m_setup->volume / 127.f;
|
||||||
|
m_curPan = m_setup->panning / 64.f - 1.f;
|
||||||
|
m_ctrlVals[0x5b] = m_setup->reverb;
|
||||||
|
m_ctrlVals[0x5d] = m_setup->chorus;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto it = m_parent.m_songGroup.m_normPages.find(m_setup.programNo);
|
if (chanId == 9)
|
||||||
if (it != m_parent.m_songGroup.m_normPages.cend())
|
{
|
||||||
m_page = it->second;
|
auto it = m_parent.m_songGroup.m_drumPages.find(0);
|
||||||
|
if (it != m_parent.m_songGroup.m_drumPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = m_parent.m_songGroup.m_normPages.find(0);
|
||||||
|
if (it != m_parent.m_songGroup.m_normPages.cend())
|
||||||
|
m_page = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curVol = 1.f;
|
||||||
|
m_curPan = 0.f;
|
||||||
|
m_ctrlVals[0x5b] = 0;
|
||||||
|
m_ctrlVals[0x5d] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_curVol = m_setup.volume / 127.f;
|
|
||||||
m_curPan = m_setup.panning / 64.f - 1.f;
|
|
||||||
m_ctrlVals[0x5b] = m_setup.reverb;
|
|
||||||
m_ctrlVals[0x5d] = m_setup.chorus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequencer::advance(double dt)
|
void Sequencer::advance(double dt)
|
||||||
|
|
Loading…
Reference in New Issue