17#include <AudioToolbox/AudioUnitUtilities.h>
27 std::unique_ptr<Message> Clone()
const override;
28 void Assign(
Message &&src)
override;
29 void Merge(
Message &&src)
override;
35AudioUnitMessage::~AudioUnitMessage() =
default;
37auto AudioUnitMessage::Clone() const ->
std::unique_ptr<
Message>
39 return std::make_unique<AudioUnitMessage>(*
this);
42void AudioUnitMessage::Assign(
Message &&src)
47 std::move(srcSettings), dstSettings,
false);
50void AudioUnitMessage::Merge(
Message &&src)
55 std::move(srcSettings), dstSettings,
true);
59 AudioComponent component,
Parameters ¶meters,
60 const wxString &identifier,
61 unsigned audioIns,
unsigned audioOuts,
bool useLatency
64 , mIdentifier{ identifier }
65 , mBlockSize{ InitialBlockSize() }
66 , mUseLatency{ useLatency }
78 kAudioUnitProperty_MaximumFramesPerSlice, blockSize))
111 Float64 latency = 0.0;
122 Float64 tailTime = 0.0;
124 return tailTime * mSampleRate;
140 memset(&
mTimeStamp, 0,
sizeof(AudioTimeStamp));
143 mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
152 if (AudioUnitInitialize(
mUnit.get())) {
153 wxLogError(
"Couldn't initialize audio unit\n");
164 if (
SetProperty(kAudioUnitProperty_SetRenderCallback,
166 kAudioUnitScope_Input)) {
167 wxLogError(
"Setting input render callback failed.\n");
171 if (AudioUnitReset(
mUnit.get(), kAudioUnitScope_Global, 0))
189 const float *
const *inBlock,
float *
const *outBlock,
size_t blockLen)
195 mInputList[i] = { 1,
static_cast<UInt32
>(
sizeof(float) * blockLen),
196 const_cast<float*
>(inBlock[i]) };
201 mOutputList[i] = { 1,
static_cast<UInt32
>(
sizeof(float) * blockLen),
204 AudioUnitRenderActionFlags flags = 0;
207 result = AudioUnitRender(
mUnit.get(),
213 if (result != noErr) {
214 wxLogError(
"Render failed: %d %4.4s\n",
215 static_cast<int>(result),
reinterpret_cast<char *
>(&result));
240 auto uProcessor = std::make_unique<AudioUnitInstance>(effect,
246 mSlaves.push_back(move(uProcessor));
252return GuardedCall<bool>([&]{
253 for (
auto &pSlave : mSlaves)
254 pSlave->ProcessFinalize();
257 return ProcessFinalize();
267 if (!pSlave->BypassEffect(
true))
279 if (!pSlave->BypassEffect(
false))
291 return std::make_unique<AudioUnitMessage>(std::move(
settings));
295MakeMessage(AudioUnitParameterID
id, AudioUnitParameterValue value)
const
296 -> std::unique_ptr<Message>
299 settings.values[
id].emplace(wxString{}, value);
300 return std::make_unique<AudioUnitMessage>(std::move(
settings));
315 for (
auto &[ID, oPair] :
values)
316 if (oPair.has_value()) {
317 auto value = oPair->second;
318 if (AudioUnitSetParameter(
mUnit.get(), ID,
319 kAudioUnitScope_Global, 0, value, 0)) {
326 storeSettings(*
this);
328 storeSettings(*pSlave);
332 for (
auto &[
_, oPair] :
values)
340 const float *
const *inbuf,
float *
const *outbuf,
size_t numSamples)
346 decltype(
this) pSlave{};
349 else if (--group <
mSlaves.size())
352 return pSlave->ProcessBlock(
settings, inbuf, outbuf, numSamples);
363 AudioUnitRenderActionFlags *inActionFlags,
364 const AudioTimeStamp *inTimeStamp,
365 UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
369 for (; i <
size; ++i)
370 ioData->mBuffers[i].mData =
mInputList[i].mData;
373 for (; i < ioData->mNumberBuffers; ++i)
374 ioData->mBuffers[i].mData =
nullptr;
380 AudioUnitRenderActionFlags *inActionFlags,
381 const AudioTimeStamp *inTimeStamp,
382 UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
385 inTimeStamp, inBusNumber, inNumFrames, ioData);
389 AudioUnitParameterValue inParameterValue)
392 if (inEvent->mEventType == kAudioUnitEvent_PropertyChange) {
394 if (inEvent->mArgument.mProperty.mPropertyID ==
395 kAudioUnitProperty_Latency) {
401 if (inEvent->mEventType != kAudioUnitEvent_ParameterValueChange)
405 const auto parameterStorer = [inParameterValue,
406 ID = inEvent->mArgument.mParameter.mParameterID
408 AudioUnitSetParameter(pUnit, ID,
409 kAudioUnitScope_Global, 0, inParameterValue, 0);
419 parameterStorer(worker->GetAudioUnit());
424 UInt32 value = (bypass ? 1 : 0);
425 if (bypass && AudioUnitReset(
mUnit.get(), kAudioUnitScope_Global, 0))
427 return !
SetProperty(kAudioUnitProperty_BypassEffect, value);
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
for(int ii=0, nn=names.size();ii< nn;++ii)
static Settings & settings()
std::vector< std::unique_ptr< AudioUnitInstance > > mSlaves
bool mRecruited
Whether the master instance is now allocated to a group number.
size_t SetBlockSize(size_t maxBlockSize) override
PackedArray::Ptr< AudioBufferList > mInputList
AudioUnitCleanup< AudioUnit, AudioUnitUninitialize > mInitialization
size_t RealtimeProcess(size_t group, EffectSettings &settings, const float *const *inbuf, float *const *outbuf, size_t numSamples) override
bool RealtimeInitialize(EffectSettings &settings, double sampleRate) override
bool RealtimeSuspend() override
bool RealtimeFinalize(EffectSettings &settings) noexcept override
bool RealtimeResume() override
std::unique_ptr< Message > MakeMessage() const override
Called on the main thread, in which the result may be cloned.
bool ProcessInitialize(EffectSettings &settings, double sampleRate, ChannelNames chanMap) override
bool RealtimeProcessEnd(EffectSettings &settings) noexcept override
settings can be updated to let a dialog change appearance at idle
AudioTimeStamp mTimeStamp
bool UsesMessages() const noexcept override
OSStatus Render(AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
const wxString & mIdentifier
void EventListener(const AudioUnitEvent *inEvent, AudioUnitParameterValue inParameterValue)
bool ProcessFinalize() noexcept override
bool BypassEffect(bool bypass)
bool RealtimeAddProcessor(EffectSettings &settings, EffectOutputs *pOutputs, unsigned numChannels, float sampleRate) override
PackedArray::Ptr< AudioBufferList > mOutputList
bool RealtimeProcessStart(MessagePackage &package) override
settings are possibly changed, since last call, by an asynchronous dialog
AudioUnitInstance(const PerTrackEffect &effect, AudioComponent component, Parameters ¶meters, const wxString &identifier, unsigned audioIns, unsigned audioOuts, bool useLatency)
size_t InitialBlockSize() const
SampleCount GetLatency(const EffectSettings &settings, double sampleRate) const override
static OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData)
size_t GetBlockSize() const override
size_t ProcessBlock(EffectSettings &settings, const float *const *inBlock, float *const *outBlock, size_t blockLen) override
Called for destructive effect computation.
unsigned GetAudioOutCount() const override
How many output buffers to allocate at once.
unsigned GetAudioInCount() const override
How many input buffers to allocate at once.
virtual size_t GetTailSize() const
Hold values to send to effect output meters.
Type of messages to send from main thread to processing.
const PerTrackEffect & mProcessor
Base class for many of the effects in Audacity.
OSStatus GetFixedSizeProperty(AudioUnit unit, AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0)
size_t Count(const Ptr< Type, BaseDeleter > &p)
Find out how many elements were allocated with a Ptr.
constexpr auto sampleRate
TranslatableString Message(unsigned trackCount)
Represents a cached copy of the state stored in an AudioUnit, but can outlive the original AudioUnit.
Manages and interacts with an AudioUnit, providing operations on audio effects.
bool StoreSettings(const EffectDefinitionInterface &effect, const AudioUnitEffectSettings &settings) const
OSStatus GetFixedSizeProperty(AudioUnitPropertyID inID, T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
static bool MoveSettingsContents(AudioUnitEffectSettings &&src, AudioUnitEffectSettings &dst, bool merge)
Copy, then clear the optionals in src.
AudioUnit GetAudioUnit() const
bool SetRateAndChannels(double sampleRate, const wxString &identifier)
AudioUnitCleanup< AudioUnit, AudioComponentInstanceDispose > mUnit
OSStatus SetProperty(AudioUnitPropertyID inID, const T &property, AudioUnitScope inScope=kAudioUnitScope_Global, AudioUnitElement inElement=0) const
static AudioUnitEffectSettings & GetSettings(EffectSettings &settings)
const AudioComponent mComponent
bool FetchSettings(AudioUnitEffectSettings &settings, bool fetchValues, bool fetchPreset=false) const
May allocate memory, so should be called only in the main thread.
Externalized state of a plug-in.
AudioUnitEffectSettings settings
~AudioUnitMessage() override
AudioUnitMessage(AudioUnitEffectSettings settings)