More AudioUnit integration

This commit is contained in:
Jack Andersen 2016-06-06 17:42:51 -10:00
parent 85b6f406f1
commit f260019b89
15 changed files with 503 additions and 199 deletions

View File

@ -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"/>

View File

@ -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;

View File

@ -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[])

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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__

View File

@ -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

View File

@ -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>

View File

@ -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>/../.."

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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)