Skip to content

Commit

Permalink
Initial working AudioUnit integration
Browse files Browse the repository at this point in the history
  • Loading branch information
jackoalan committed Jun 8, 2016
1 parent f260019 commit 117d704
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 57 deletions.
6 changes: 3 additions & 3 deletions AudioUnit/AudioGroupFilePresenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,19 @@ struct AudioGroupCollection
{
@public
NSString* m_name;
int m_id;
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;
- (id)initWithName:(NSString*)name id:(int)gid songGroup:(const amuse::SongGroupIndex*)group;
- (id)initWithName:(NSString*)name id:(int)gid sfxGroup:(const amuse::SFXGroupIndex*)group;
@end

@interface AudioGroupFilePresenter : NSObject <NSFilePresenter, NSOutlineViewDataSource, NSOutlineViewDelegate>
{
@public
id<AudioGroupClient> m_audioGroupClient;
NSURL* m_groupURL;
NSOperationQueue* m_dataQueue;
std::map<std::string, std::unique_ptr<AudioGroupCollection>> m_audioGroupCollections;
std::vector<std::map<std::string, std::unique_ptr<AudioGroupCollection>>::iterator> m_filterAudioGroupCollections;
NSOutlineView* m_lastOutlineView;
Expand Down
23 changes: 12 additions & 11 deletions AudioUnit/AudioGroupFilePresenter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ - (id)initWithName:(NSAttributedString*)name samp:(const std::pair<amuse::AudioG
@end

@implementation AudioGroupToken
- (id)initWithName:(NSString*)name songGroup:(const amuse::SongGroupIndex*)group
- (id)initWithName:(NSString*)name id:(int)gid songGroup:(const amuse::SongGroupIndex*)group
{
self = [super init];
m_name = name;
m_song = group;
m_id = gid;
return self;
}
- (id)initWithName:(NSString*)name sfxGroup:(const amuse::SFXGroupIndex*)group
- (id)initWithName:(NSString*)name id:(int)gid sfxGroup:(const amuse::SFXGroupIndex*)group
{
self = [super init];
m_name = name;
m_sfx = group;
m_id = gid;
return self;
}
@end
Expand All @@ -78,7 +80,7 @@ - (NSURL*)presentedItemURL

- (NSOperationQueue*)presentedItemOperationQueue
{
return m_dataQueue;
return [NSOperationQueue mainQueue];
}

AudioGroupCollection::AudioGroupCollection(NSURL* url)
Expand Down Expand Up @@ -305,7 +307,8 @@ - (NSOperationQueue*)presentedItemOperationQueue
for (const auto& pair : sortGroups)
{
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name songGroup:pair.second]);
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name id:pair.first
songGroup:pair.second]);
}
}
{
Expand All @@ -316,7 +319,8 @@ - (NSOperationQueue*)presentedItemOperationQueue
for (const auto& pair : sortGroups)
{
NSString* name = [NSString stringWithFormat:@"%d", pair.first];
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name sfxGroup:pair.second]);
m_groupTokens.push_back([[AudioGroupToken alloc] initWithName:name id:pair.first
sfxGroup:pair.second]);
}
}
}
Expand Down Expand Up @@ -495,12 +499,10 @@ - (NSOperationQueue*)presentedItemOperationQueue
return ret.operator bool();
}

- (void)presentedSubitemDidAppearAtURL:(NSURL*)url
- (void)presentedSubitemDidChangeAtURL:(NSURL *)url
{
if ([url.lastPathComponent isEqualToString:@"proj"] ||
[url.lastPathComponent isEqualToString:@"pool"] ||
[url.lastPathComponent isEqualToString:@"sdir"] ||
[url.lastPathComponent isEqualToString:@"samp"])
size_t relComps = url.pathComponents.count - m_groupURL.pathComponents.count;
if (relComps <= 1)
[self update];
}

Expand Down Expand Up @@ -850,7 +852,6 @@ - (id)initWithAudioGroupClient:(id<AudioGroupClient>)client
m_groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.io.github.axiodl.Amuse.AudioGroups"];
if (!m_groupURL)
return nil;
m_dataQueue = [NSOperationQueue new];
[NSFileCoordinator addFilePresenter:self];
[self update];
return self;
Expand Down
1 change: 1 addition & 0 deletions AudioUnit/AudioUnitBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ void RegisterAudioUnit();
- (nullable id)initWithComponentDescription:(AudioComponentDescription)componentDescription
error:(NSError * __nullable * __nonnull)outError
viewController:(AudioUnitViewController* __nonnull)vc;
- (void)requestAudioGroup:(AudioGroupToken*)group;
@end

#endif
Expand Down
36 changes: 31 additions & 5 deletions AudioUnit/AudioUnitBackend.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

struct AudioUnitVoiceEngine : boo::BaseAudioVoiceEngine
{
AudioGroupToken* m_reqGroup = nullptr;
AudioGroupToken* m_curGroup = nullptr;
std::vector<float> m_interleavedBuf;
std::vector<std::unique_ptr<float[]>> m_renderBufs;
size_t m_renderFrames = 0;
Expand Down Expand Up @@ -137,6 +139,8 @@ void pumpAndMixVoices()
}
}
}

double getCurrentSampleRate() const {return m_mixInfo.m_sampleRate;}
};

@implementation AmuseAudioUnit
Expand Down Expand Up @@ -165,7 +169,9 @@ - (id)initWithComponentDescription:(AudioComponentDescription)componentDescripti
//m_outBus.supportedChannelCounts = @[@1,@2];
m_outBus.maximumChannelCount = 2;

m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self busType:AUAudioUnitBusTypeOutput busses:@[m_outBus]];
m_outs = [[AUAudioUnitBusArray alloc] initWithAudioUnit:self
busType:AUAudioUnitBusTypeOutput
busses:@[m_outBus]];

m_booBackend = std::make_unique<AudioUnitVoiceEngine>();
if (!m_booBackend)
Expand All @@ -177,15 +183,21 @@ - (id)initWithComponentDescription:(AudioComponentDescription)componentDescripti

m_voxAlloc.emplace(*m_booBackend);
m_engine.emplace(*m_voxAlloc);
dispatch_sync(dispatch_get_main_queue(), ^
{
dispatch_sync(dispatch_get_main_queue(),
^{
m_filePresenter = [[AudioGroupFilePresenter alloc] initWithAudioGroupClient:self];
});

self.maximumFramesToRender = 512;
return self;
}

- (void)requestAudioGroup:(AudioGroupToken*)group
{
AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
voxEngine.m_reqGroup = group;
}

- (BOOL)allocateRenderResourcesAndReturnError:(NSError **)outError
{
if (![super allocateRenderResourcesAndReturnError:outError])
Expand Down Expand Up @@ -232,11 +244,25 @@ - (AUInternalRenderBlock)internalRenderBlock
{
__block AudioUnitVoiceEngine& voxEngine = static_cast<AudioUnitVoiceEngine&>(*m_booBackend);
__block amuse::Engine& amuseEngine = *m_engine;
__block std::shared_ptr<amuse::Sequencer> curSeq;

return ^AUAudioUnitStatus(AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp,
AUAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList* outputData,
const AURenderEvent* realtimeEventListHead, AURenderPullInputBlock pullInputBlock)
{
/* Handle group load request */
AudioGroupToken* reqGroup = voxEngine.m_reqGroup;
if (voxEngine.m_curGroup != reqGroup)
{
voxEngine.m_curGroup = reqGroup;
if (reqGroup->m_song)
{
if (curSeq)
curSeq->kill();
curSeq = amuseEngine.seqPlay(reqGroup->m_id, -1, nullptr);
}
}

/* Process MIDI events first */
if (voxEngine.m_midiReceiver)
{
Expand All @@ -245,9 +271,9 @@ - (AUInternalRenderBlock)internalRenderBlock
{
if (event->eventType == AURenderEventMIDI)
{
NSLog(@"MIDI %d %d", event->length, event->data[0]);
(*voxEngine.m_midiReceiver)(std::vector<uint8_t>(std::cbegin(event->data),
std::cbegin(event->data) + event->length));
std::cbegin(event->data) + event->length),
event->eventSampleTime / voxEngine.getCurrentSampleRate());
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions AudioUnit/AudioUnitViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ - (id)browser:(NSBrowser *)browser objectValueForItem:(id)item
return nil;
}

- (NSIndexSet *)browser:(NSBrowser *)browser selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes inColumn:(NSInteger)column
{
if (column == 2)
{
AudioGroupToken* token = [browser itemAtRow:proposedSelectionIndexes.firstIndex inColumn:column];
[m_audioUnit requestAudioGroup:token];
}
return proposedSelectionIndexes;
}

- (id)initWithAudioUnit:(AmuseAudioUnit*)au
{
self = [super init];
Expand All @@ -152,6 +162,7 @@ - (AUAudioUnit*)createAudioUnitWithComponentDescription:(AudioComponentDescripti
dispatch_sync(dispatch_get_main_queue(), ^
{
m_groupBrowser.delegate = m_groupBrowserDelegate;
[m_groupBrowser loadColumnZero];
});
return m_audioUnit;
}
Expand Down
5 changes: 2 additions & 3 deletions include/amuse/BooBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "IBackendVoiceAllocator.hpp"
#include <mutex>
#include <list>
#include <chrono>

namespace amuse
{
Expand Down Expand Up @@ -77,9 +76,9 @@ class BooBackendMIDIReader : public IMIDIReader, public boo::IMIDIReader
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<double, std::vector<uint8_t>>> m_queue;
std::mutex m_midiMutex;
void _MIDIReceive(std::vector<uint8_t>&& bytes);
void _MIDIReceive(std::vector<uint8_t>&& bytes, double time);

public:
~BooBackendMIDIReader();
Expand Down
4 changes: 2 additions & 2 deletions lib/AudioGroupSampleDirectory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);

memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();

cur += 28;
Expand All @@ -161,7 +161,7 @@ AudioGroupSampleDirectory::AudioGroupSampleDirectory(const unsigned char* data,
std::pair<Entry, ADPCMParms>& store = m_entries[ent.m_sfxId];
ent.setIntoMusyX2(store.first);

memcpy(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
memmove(&store.second.vadpcm.m_coefs, sampData + ent.m_sampleOff, 256);
store.second.swapBigVADPCM();

cur += 24;
Expand Down
46 changes: 35 additions & 11 deletions lib/BooBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "amuse/Voice.hpp"
#include "amuse/Submix.hpp"
#include "amuse/Engine.hpp"
#include <syslog.h>

namespace amuse
{
Expand Down Expand Up @@ -130,42 +131,46 @@ BooBackendMIDIReader::BooBackendMIDIReader(Engine& engine, const char* name, boo
{
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(dev.first.c_str(),
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
std::placeholders::_1));
std::placeholders::_1, std::placeholders::_2));
if (m_midiIn)
return;
}
m_midiIn = voxAlloc.m_booEngine.newVirtualMIDIIn(std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
std::placeholders::_1));
std::placeholders::_1, std::placeholders::_2));
}
else
m_midiIn = voxAlloc.m_booEngine.newRealMIDIIn(name,
std::bind(&BooBackendMIDIReader::_MIDIReceive, this,
std::placeholders::_1));
std::placeholders::_1, std::placeholders::_2));
}

void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes)
void BooBackendMIDIReader::_MIDIReceive(std::vector<uint8_t>&& bytes, double time)
{
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));
if (m_useLock) lk.lock();
m_queue.emplace_back(time, std::move(bytes));
#if 0
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
syslog(LOG_EMERG, "MIDI receive %f\n", time);
closelog();
#endif
}

void BooBackendMIDIReader::pumpReader(double dt)
{
dt += 0.001; /* Add 1ms to ensure consumer keeps up with producer */

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();
if (m_queue.empty())
return;

/* Determine range of buffer updates within this period */
auto periodEnd = m_queue.cbegin();
std::chrono::steady_clock::time_point startPt = m_queue.front().first;
double startPt = m_queue.front().first;
for (; periodEnd != m_queue.cend() ; ++periodEnd)
{
double delta = std::chrono::duration_cast<std::chrono::microseconds>
(periodEnd->first - startPt).count() / 1000000.0;
double delta = periodEnd->first - startPt;
if (delta > dt)
break;
}
Expand All @@ -176,6 +181,15 @@ void BooBackendMIDIReader::pumpReader(double dt)
/* Dispatch buffers */
for (auto it = m_queue.begin() ; it != periodEnd ;)
{
#if 0
char str[64];
sprintf(str, "MIDI %zu %f ", it->second.size(), it->first);
for (uint8_t byte : it->second)
sprintf(str + strlen(str), "%02X ", byte);
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
syslog(LOG_EMERG, "%s\n", str);
closelog();
#endif
m_decoder.receiveBytes(it->second.cbegin(), it->second.cend());
it = m_queue.erase(it);
}
Expand All @@ -185,12 +199,22 @@ void BooBackendMIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
{
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
seq->keyOff(chan, key, velocity);
#if 0
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
syslog(LOG_EMERG, "NoteOff %d", key);
closelog();
#endif
}

void BooBackendMIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
{
for (std::shared_ptr<Sequencer>& seq : m_engine.getActiveSequencers())
seq->keyOn(chan, key, velocity);
#if 0
openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
syslog(LOG_EMERG, "NoteOn %d", key);
closelog();
#endif
}

void BooBackendMIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/)
Expand Down

0 comments on commit 117d704

Please sign in to comment.