1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

AudioProcessor: Allow querying of the host timestamp in processBlock

This commit is contained in:
reuk 2022-03-16 15:01:44 +00:00
parent 5d096b46d7
commit cfa289d943
No known key found for this signature in database
GPG key ID: 9ADCD339CFC98A11
31 changed files with 496 additions and 185 deletions

View file

@ -69,9 +69,14 @@ public:
CallbackHandler (AudioDeviceManager& adm) noexcept : owner (adm) {}
private:
void audioDeviceIOCallback (const float** ins, int numIns, float** outs, int numOuts, int numSamples) override
void audioDeviceIOCallbackWithContext (const float** ins,
int numIns,
float** outs,
int numOuts,
int numSamples,
const AudioIODeviceCallbackContext& context) override
{
owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples);
owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples, context);
}
void audioDeviceAboutToStart (AudioIODevice* device) override
@ -900,7 +905,8 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples)
int numSamples,
const AudioIODeviceCallbackContext& context)
{
const ScopedLock sl (audioCallbackLock);
@ -912,15 +918,23 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true);
callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples);
callbacks.getUnchecked(0)->audioDeviceIOCallbackWithContext (inputChannelData,
numInputChannels,
outputChannelData,
numOutputChannels,
numSamples,
context);
auto** tempChans = tempBuffer.getArrayOfWritePointers();
for (int i = callbacks.size(); --i > 0;)
{
callbacks.getUnchecked(i)->audioDeviceIOCallback (inputChannelData, numInputChannels,
tempChans, numOutputChannels, numSamples);
callbacks.getUnchecked(i)->audioDeviceIOCallbackWithContext (inputChannelData,
numInputChannels,
tempChans,
numOutputChannels,
numSamples,
context);
for (int chan = 0; chan < numOutputChannels; ++chan)
{

View file

@ -526,8 +526,12 @@ private:
class CallbackHandler;
std::unique_ptr<CallbackHandler> callbackHandler;
void audioDeviceIOCallbackInt (const float** inputChannelData, int totalNumInputChannels,
float** outputChannelData, int totalNumOutputChannels, int numSamples);
void audioDeviceIOCallbackInt (const float** inputChannelData,
int totalNumInputChannels,
float** outputChannelData,
int totalNumOutputChannels,
int numSamples,
const AudioIODeviceCallbackContext& context);
void audioDeviceAboutToStartInt (AudioIODevice*);
void audioDeviceStoppedInt();
void audioDeviceErrorInt (const String&);

View file

@ -25,6 +25,14 @@ namespace juce
class AudioIODevice;
/** Additional information that may be passed to the AudioIODeviceCallback. */
struct AudioIODeviceCallbackContext
{
/** If the host provides this information, this field will be set to point to
an integer holding the current value; otherwise, this will be nullptr.
*/
const uint64_t* hostTimeNs = nullptr;
};
//==============================================================================
/**
@ -87,7 +95,26 @@ public:
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples) = 0;
int numSamples)
{
ignoreUnused (inputChannelData, numInputChannels, outputChannelData, numOutputChannels, numSamples);
}
/** The same as audioDeviceIOCallback(), but with an additional context argument.
The default implementation of this function will call audioDeviceIOCallback(),
but you can override this function if you need to make use of the context information.
*/
virtual void audioDeviceIOCallbackWithContext (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples,
const AudioIODeviceCallbackContext& context)
{
audioDeviceIOCallback (inputChannelData, numInputChannels, outputChannelData, numOutputChannels, numSamples);
ignoreUnused (context);
}
/** Called to indicate that the device is about to start calling back.

View file

@ -357,9 +357,11 @@ public:
if (callback != nullptr)
{
callback->audioDeviceIOCallback (inputChannelBuffer.getArrayOfReadPointers(), numClientInputChannels,
outputChannelBuffer.getArrayOfWritePointers(), numClientOutputChannels,
actualBufferSize);
callback->audioDeviceIOCallbackWithContext (inputChannelBuffer.getArrayOfReadPointers(),
numClientInputChannels,
outputChannelBuffer.getArrayOfWritePointers(),
numClientOutputChannels,
actualBufferSize, {});
}
else
{

View file

@ -428,8 +428,12 @@ private:
{
if (auto* cb = callback.exchange (nullptr))
{
cb->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numFrames);
cb->audioDeviceIOCallbackWithContext (inputChannelData,
numInputChannels,
outputChannelData,
numOutputChannels,
numFrames,
{});
callback.set (cb);
}
else

View file

@ -605,7 +605,7 @@ public:
{
if (auto* cb = callback.exchange (nullptr))
{
cb->audioDeviceIOCallback (inputChannelData, inputChannels, outputChannelData, outputChannels, bufferSize);
cb->audioDeviceIOCallbackWithContext (inputChannelData, inputChannels, outputChannelData, outputChannels, bufferSize, {});
callback.set (cb);
}
else

View file

@ -20,6 +20,8 @@
==============================================================================
*/
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
namespace juce
{
@ -900,9 +902,14 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead,
zeromem (inputData[c], channelDataSize);
}
callback->audioDeviceIOCallback ((const float**) inputData, channelData.inputs ->numActiveChannels,
outputData, channelData.outputs->numActiveChannels,
(int) numFrames);
const auto nanos = time != nullptr ? timeConversions.hostTimeToNanos (time->mHostTime) : 0;
callback->audioDeviceIOCallbackWithContext ((const float**) inputData,
channelData.inputs ->numActiveChannels,
outputData,
channelData.outputs->numActiveChannels,
(int) numFrames,
{ (time != nullptr && (time->mFlags & kAudioTimeStampHostTimeValid) != 0) ? &nanos : nullptr });
for (int c = 0; c < channelData.outputs->numActiveChannels; ++c)
{
@ -1329,6 +1336,8 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead,
AudioBuffer<float> audioData { 0, 0 };
};
CoreAudioTimeConversions timeConversions;
IOChannelData channelData;
BigInteger requestedInputChannels, requestedOutputChannels;

View file

@ -711,11 +711,12 @@ public:
if (callback != nullptr)
{
callback->audioDeviceIOCallback (inputChannelDataForCallback.getRawDataPointer(),
inputChannelDataForCallback.size(),
outputChannelDataForCallback.getRawDataPointer(),
outputChannelDataForCallback.size(),
bufferSize);
callback->audioDeviceIOCallbackWithContext (inputChannelDataForCallback.getRawDataPointer(),
inputChannelDataForCallback.size(),
outputChannelDataForCallback.getRawDataPointer(),
outputChannelDataForCallback.size(),
bufferSize,
{});
}
else
{

View file

@ -433,9 +433,12 @@ private:
channelOutBuffer[ch] = &context.analogOut[(Frames) (ch - analogChannelStart) * context.audioFrames];
}
callback->audioDeviceIOCallback (channelInBuffer.getData(), actualNumberOfInputs,
channelOutBuffer.getData(), actualNumberOfOutputs,
(int) context.audioFrames);
callback->audioDeviceIOCallbackWithContext (channelInBuffer.getData(),
actualNumberOfInputs,
channelOutBuffer.getData(),
actualNumberOfOutputs,
(int) context.audioFrames,
{});
}
}

View file

@ -462,8 +462,12 @@ private:
if (callback != nullptr)
{
if ((numActiveInChans + numActiveOutChans) > 0)
callback->audioDeviceIOCallback (const_cast<const float**> (inChans.getData()), numActiveInChans,
outChans, numActiveOutChans, numSamples);
callback->audioDeviceIOCallbackWithContext (const_cast<const float**> (inChans.getData()),
numActiveInChans,
outChans,
numActiveOutChans,
numSamples,
{});
}
else
{

View file

@ -20,6 +20,8 @@
==============================================================================
*/
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
namespace juce
{
@ -746,7 +748,8 @@ public:
double getSampleRate() const { return sampleRate; }
int getBufferSize() const { return bufferSize; }
void audioCallback (const AudioBufferList* inInputData,
void audioCallback (const AudioTimeStamp* timeStamp,
const AudioBufferList* inInputData,
AudioBufferList* outOutputData)
{
const ScopedLock sl (callbackLock);
@ -778,11 +781,14 @@ public:
}
}
callback->audioDeviceIOCallback (const_cast<const float**> (tempInputBuffers.get()),
numInputChans,
tempOutputBuffers,
numOutputChans,
bufferSize);
const auto nanos = timeStamp != nullptr ? timeConversions.hostTimeToNanos (timeStamp->mHostTime) : 0;
callback->audioDeviceIOCallbackWithContext (const_cast<const float**> (tempInputBuffers.get()),
numInputChans,
tempOutputBuffers,
numOutputChans,
bufferSize,
{ timeStamp != nullptr ? &nanos : nullptr });
for (int i = numOutputChans; --i >= 0;)
{
@ -838,6 +844,7 @@ public:
AudioDeviceIOProcID audioProcID = {};
private:
CoreAudioTimeConversions timeConversions;
AudioIODeviceCallback* callback = nullptr;
CriticalSection callbackLock;
AudioDeviceID deviceID;
@ -876,14 +883,14 @@ private:
}
static OSStatus audioIOProc (AudioDeviceID /*inDevice*/,
const AudioTimeStamp* /*inNow*/,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* /*inInputTime*/,
AudioBufferList* outOutputData,
const AudioTimeStamp* /*inOutputTime*/,
void* device)
{
static_cast<CoreAudioInternal*> (device)->audioCallback (inInputData, outOutputData);
static_cast<CoreAudioInternal*> (device)->audioCallback (inNow, inInputData, outOutputData);
return noErr;
}
@ -1624,8 +1631,12 @@ private:
const ScopedLock sl (callbackLock);
if (callback != nullptr)
callback->audioDeviceIOCallback ((const float**) inputChans.getRawDataPointer(), numInputChans,
outputChans.getRawDataPointer(), numOutputChans, numSamples);
callback->audioDeviceIOCallbackWithContext ((const float**) inputChans.getRawDataPointer(),
numInputChans,
outputChans.getRawDataPointer(),
numOutputChans,
numSamples,
{}); // Can't predict when the next output callback will happen
else
didCallback = false;
}
@ -1920,9 +1931,12 @@ private:
outputFifo.finishedWrite (size1 + size2);
}
void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels,
float** outputChannelData, int numOutputChannels,
int numSamples) override
void audioDeviceIOCallbackWithContext (const float** inputChannelData,
int numInputChannels,
float** outputChannelData,
int numOutputChannels,
int numSamples,
const AudioIODeviceCallbackContext&) override
{
if (numInputChannels > 0)
{

View file

@ -1326,8 +1326,12 @@ private:
inputFormat[i].convertToFloat (infos[i].buffers[bufferIndex], inBuffers[i], samps);
}
currentCallback->audioDeviceIOCallback (const_cast<const float**> (inBuffers.getData()), numActiveInputChans,
outBuffers, numActiveOutputChans, samps);
currentCallback->audioDeviceIOCallbackWithContext (const_cast<const float**> (inBuffers.getData()),
numActiveInputChans,
outBuffers,
numActiveOutputChans,
samps,
{});
for (int i = 0; i < numActiveOutputChans; ++i)
{

View file

@ -1016,9 +1016,12 @@ public:
if (isStarted)
{
callback->audioDeviceIOCallback (inputBuffers.getArrayOfReadPointers(), inputBuffers.getNumChannels(),
outputBuffers.getArrayOfWritePointers(), outputBuffers.getNumChannels(),
bufferSizeSamples);
callback->audioDeviceIOCallbackWithContext (inputBuffers.getArrayOfReadPointers(),
inputBuffers.getNumChannels(),
outputBuffers.getArrayOfWritePointers(),
outputBuffers.getNumChannels(),
bufferSizeSamples,
{});
}
else
{

View file

@ -1515,8 +1515,12 @@ public:
const ScopedTryLock sl (startStopLock);
if (sl.isLocked() && isStarted)
callback->audioDeviceIOCallback (const_cast<const float**> (inputBuffers), numInputBuffers,
outputBuffers, numOutputBuffers, bufferSize);
callback->audioDeviceIOCallbackWithContext (const_cast<const float**> (inputBuffers),
numInputBuffers,
outputBuffers,
numOutputBuffers,
bufferSize,
{});
else
outs.clear();
}