Browse Source

AudioProcessor: Allow querying of the host timestamp in processBlock

pull/22/head
reuk 3 years ago
parent
commit
cfa289d943
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
31 changed files with 496 additions and 185 deletions
  1. +2
    -0
      modules/juce_audio_basics/juce_audio_basics.cpp
  2. +1
    -1
      modules/juce_audio_basics/juce_audio_basics.h
  3. +80
    -0
      modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h
  4. +21
    -7
      modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  5. +6
    -2
      modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  6. +28
    -1
      modules/juce_audio_devices/audio_io/juce_AudioIODevice.h
  7. +5
    -3
      modules/juce_audio_devices/native/juce_android_Audio.cpp
  8. +6
    -2
      modules/juce_audio_devices/native/juce_android_Oboe.cpp
  9. +1
    -1
      modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  10. +12
    -3
      modules/juce_audio_devices/native/juce_ios_Audio.cpp
  11. +6
    -5
      modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  12. +6
    -3
      modules/juce_audio_devices/native/juce_linux_Bela.cpp
  13. +6
    -2
      modules/juce_audio_devices/native/juce_linux_JackAudio.cpp
  14. +27
    -13
      modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp
  15. +6
    -2
      modules/juce_audio_devices/native/juce_win32_ASIO.cpp
  16. +6
    -3
      modules/juce_audio_devices/native/juce_win32_DirectSound.cpp
  17. +6
    -2
      modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
  18. +18
    -0
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  19. +19
    -0
      modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
  20. +24
    -17
      modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
  21. +36
    -7
      modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  22. +14
    -0
      modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  23. +26
    -51
      modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  24. +15
    -28
      modules/juce_audio_processors/format_types/juce_VST3Common.h
  25. +12
    -2
      modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  26. +22
    -19
      modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  27. +1
    -0
      modules/juce_audio_processors/juce_audio_processors.cpp
  28. +48
    -0
      modules/juce_audio_processors/processors/juce_AudioProcessor.h
  29. +19
    -5
      modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
  30. +16
    -5
      modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp
  31. +1
    -1
      modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h

+ 2
- 0
modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -31,6 +31,8 @@
#include "juce_audio_basics.h"
#include <juce_core/containers/juce_Optional.h>
#if JUCE_MINGW && ! defined (alloca)
#define alloca __builtin_alloca
#endif


+ 1
- 1
modules/juce_audio_basics/juce_audio_basics.h View File

@@ -120,4 +120,4 @@
#include "sources/juce_ReverbAudioSource.h"
#include "sources/juce_ToneGeneratorAudioSource.h"
#include "synthesisers/juce_Synthesiser.h"
#include "audio_play_head/juce_AudioPlayHead.h"
#include "audio_play_head/juce_AudioPlayHead.h"

+ 80
- 0
modules/juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h View File

@@ -0,0 +1,80 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
// This file will be included directly by macOS/iOS-specific .cpps
#pragma once
#if ! DOXYGEN
#include <mach/mach_time.h>
namespace juce
{
struct CoreAudioTimeConversions
{
public:
CoreAudioTimeConversions()
{
mach_timebase_info_data_t info{};
mach_timebase_info (&info);
numerator = info.numer;
denominator = info.denom;
}
uint64_t hostTimeToNanos (uint64_t hostTime) const
{
return multiplyByRatio (hostTime, numerator, denominator);
}
uint64_t nanosToHostTime (uint64_t nanos) const
{
return multiplyByRatio (nanos, denominator, numerator);
}
private:
// Adapted from CAHostTimeBase.h in the Core Audio Utility Classes
static uint64_t multiplyByRatio (uint64_t toMultiply, uint64_t numerator, uint64_t denominator)
{
#if defined (__SIZEOF_INT128__)
unsigned __int128
#else
long double
#endif
result = toMultiply;
if (numerator != denominator)
{
result *= numerator;
result /= denominator;
}
return (uint64_t) result;
}
uint64_t numerator = 0, denominator = 0;
};
} // namespace juce
#endif

+ 21
- 7
modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp 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)
{


+ 6
- 2
modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h 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&);


+ 28
- 1
modules/juce_audio_devices/audio_io/juce_AudioIODevice.h 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.


+ 5
- 3
modules/juce_audio_devices/native/juce_android_Audio.cpp 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
{


+ 6
- 2
modules/juce_audio_devices/native/juce_android_Oboe.cpp 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


+ 1
- 1
modules/juce_audio_devices/native/juce_android_OpenSL.cpp 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


+ 12
- 3
modules/juce_audio_devices/native/juce_ios_Audio.cpp 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;


+ 6
- 5
modules/juce_audio_devices/native/juce_linux_ALSA.cpp 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
{


+ 6
- 3
modules/juce_audio_devices/native/juce_linux_Bela.cpp 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,
{});
}
}


+ 6
- 2
modules/juce_audio_devices/native/juce_linux_JackAudio.cpp 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
{


+ 27
- 13
modules/juce_audio_devices/native/juce_mac_CoreAudio.cpp 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)
{


+ 6
- 2
modules/juce_audio_devices/native/juce_win32_ASIO.cpp 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)
{


+ 6
- 3
modules/juce_audio_devices/native/juce_win32_DirectSound.cpp 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
{


+ 6
- 2
modules/juce_audio_devices/native/juce_win32_WASAPI.cpp 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();
}


+ 18
- 0
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -77,6 +77,7 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#include "../utility/juce_CarbonVisibility.h"
#include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
#include <juce_audio_processors/format_types/juce_AU_Shared.h>
@@ -1287,6 +1288,22 @@ public:
{
lastTimeStamp = inTimeStamp;
jassert (! juceFilter->getHostTimeNs());
if ((inTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0)
{
const auto timestamp = timeConversions.hostTimeToNanos (inTimeStamp.mHostTime);
juceFilter->setHostTimeNanos (&timestamp);
}
struct AtEndOfScope
{
~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
AudioProcessor& proc;
};
const AtEndOfScope scope { *juceFilter };
// prepare buffers
{
pullInputAudio (ioActionFlags, inTimeStamp, nFrames);
@@ -1816,6 +1833,7 @@ private:
// According to the docs, this is the maximum size of a MIDIPacketList.
static constexpr UInt32 packetListBytes = 65536;
CoreAudioTimeConversions timeConversions;
AudioUnitEvent auEvent;
mutable Array<AUPreset> presetsArray;
CriticalSection incomingMidiLock;


+ 19
- 0
modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm View File

@@ -51,6 +51,7 @@
#include <juce_graphics/native/juce_mac_CoreGraphicsHelpers.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
#include <juce_audio_processors/format_types/juce_AU_Shared.h>
@@ -1521,6 +1522,23 @@ private:
const auto numProcessorBusesOut = AudioUnitHelpers::getBusCount (processor, false);
if (timestamp != nullptr)
{
if ((timestamp->mFlags & kAudioTimeStampHostTimeValid) != 0)
{
const auto convertedTime = timeConversions.hostTimeToNanos (timestamp->mHostTime);
getAudioProcessor().setHostTimeNanos (&convertedTime);
}
}
struct AtEndOfScope
{
~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
AudioProcessor& proc;
};
const AtEndOfScope scope { getAudioProcessor() };
if (lastTimeStamp.mSampleTime != timestamp->mSampleTime)
{
// process params and incoming midi (only once for a given timestamp)
@@ -1764,6 +1782,7 @@ private:
int totalInChannels, totalOutChannels;
CoreAudioTimeConversions timeConversions;
std::unique_ptr<AUAudioUnitBusArray, NSObjectDeleter> inputBusses, outputBusses;
ObjCBlock<AUImplementorValueObserver> paramObserver;


+ 24
- 17
modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h View File

@@ -441,11 +441,12 @@ private:
inner.audioDeviceAboutToStart (device);
}
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& context) override
{
jassertquiet ((int) storedInputChannels.size() == numInputChannels);
jassertquiet ((int) storedOutputChannels.size() == numOutputChannels);
@@ -459,11 +460,12 @@ private:
initChannelPointers (inputChannelData, storedInputChannels, position);
initChannelPointers (outputChannelData, storedOutputChannels, position);
inner.audioDeviceIOCallback (storedInputChannels.data(),
(int) storedInputChannels.size(),
storedOutputChannels.data(),
(int) storedOutputChannels.size(),
blockLength);
inner.audioDeviceIOCallbackWithContext (storedInputChannels.data(),
(int) storedInputChannels.size(),
storedOutputChannels.data(),
(int) storedOutputChannels.size(),
blockLength,
context);
position += blockLength;
}
@@ -591,11 +593,12 @@ private:
};
//==============================================================================
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& context) override
{
if (muteInput)
{
@@ -603,8 +606,12 @@ private:
inputChannelData = emptyBuffer.getArrayOfReadPointers();
}
player.audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples);
player.audioDeviceIOCallbackWithContext (inputChannelData,
numInputChannels,
outputChannelData,
numOutputChannels,
numSamples,
context);
}
void audioDeviceAboutToStart (AudioIODevice* device) override


+ 36
- 7
modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp View File

@@ -18,6 +18,7 @@
#include <juce_core/system/juce_CompilerWarnings.h>
#include <juce_core/system/juce_TargetPlatform.h>
#include <juce_core/containers/juce_Optional.h>
#include "../utility/juce_CheckSettingMacros.h"
#if JucePlugin_Build_VST
@@ -354,7 +355,7 @@ public:
jassert (isProcessing);
// (tragically, some hosts actually need this, although it's stupid to have
// to do it here..)
// to do it here.)
if (! isProcessing)
resume();
@@ -389,6 +390,16 @@ public:
}
else
{
updateCallbackContextInfo();
struct AtEndOfScope
{
~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
AudioProcessor& proc;
};
const AtEndOfScope scope { *processor };
int i;
for (i = 0; i < numOut; ++i)
{
@@ -589,25 +600,28 @@ public:
}
}
//==============================================================================
bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) override
void updateCallbackContextInfo()
{
const Vst2::VstTimeInfo* ti = nullptr;
if (hostCallback != nullptr)
{
int32 flags = Vst2::kVstPpqPosValid | Vst2::kVstTempoValid
| Vst2::kVstBarsValid | Vst2::kVstCyclePosValid
| Vst2::kVstTimeSigValid | Vst2::kVstSmpteValid
| Vst2::kVstClockValid;
| Vst2::kVstBarsValid | Vst2::kVstCyclePosValid
| Vst2::kVstTimeSigValid | Vst2::kVstSmpteValid
| Vst2::kVstClockValid | Vst2::kVstNanosValid;
auto result = hostCallback (&vstEffect, Vst2::audioMasterGetTime, 0, flags, nullptr, 0);
ti = reinterpret_cast<Vst2::VstTimeInfo*> (result);
}
if (ti == nullptr || ti->sampleRate <= 0)
return false;
{
currentPosition.reset();
return;
}
auto& info = currentPosition.emplace();
info.bpm = (ti->flags & Vst2::kVstTempoValid) != 0 ? ti->tempo : 0.0;
if ((ti->flags & Vst2::kVstTimeSigValid) != 0)
@@ -675,6 +689,20 @@ public:
info.ppqLoopEnd = 0;
}
if ((ti->flags & Vst2::kVstNanosValid) != 0)
{
const auto nanos = (uint64_t) ti->nanoSeconds;
processor->setHostTimeNanos (&nanos);
}
}
//==============================================================================
bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) override
{
if (! currentPosition.hasValue())
return false;
info = *currentPosition;
return true;
}
@@ -2068,6 +2096,7 @@ private:
Vst2::ERect editorRect;
MidiBuffer midiEvents;
VSTMidiEventList outgoingEvents;
Optional<CurrentPositionInfo> currentPosition;
LegacyAudioParametersWrapper juceParameters;


+ 14
- 0
modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -3170,6 +3170,12 @@ public:
{
processContext = *data.processContext;
if ((processContext.state & Vst::ProcessContext::kSystemTimeValid) != 0)
{
const auto timestamp = (uint64_t) processContext.systemTime;
getPluginInstance().setHostTimeNanos (&timestamp);
}
if (juceVST3EditController != nullptr)
juceVST3EditController->vst3IsPlaying = (processContext.state & Vst::ProcessContext::kPlaying) != 0;
}
@@ -3181,6 +3187,14 @@ public:
juceVST3EditController->vst3IsPlaying = false;
}
struct AtEndOfScope
{
~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
AudioProcessor& proc;
};
const AtEndOfScope scope { getPluginInstance() };
midiBuffer.clear();
if (data.inputParameterChanges != nullptr)


+ 26
- 51
modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -34,6 +34,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
#include <CoreAudioKit/AUViewController.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
#include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h>
#include <juce_audio_basics/midi/juce_MidiDataConcatenator.h>
#include "juce_AU_Shared.h"
@@ -332,39 +333,25 @@ namespace AudioUnitFormatHelpers
#endif
template <typename Value>
struct BasicOptional
{
BasicOptional() = default;
explicit constexpr BasicOptional (Value&& v) : value (std::move (v)), isValid (true) {}
explicit constexpr BasicOptional (const Value& v) : value (v), isValid (true) {}
explicit constexpr operator bool() const noexcept { return isValid; }
Value value;
bool isValid { false };
};
template <typename Value>
static BasicOptional<Value> tryGetProperty (AudioUnit inUnit,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement)
static Optional<Value> tryGetProperty (AudioUnit inUnit,
AudioUnitPropertyID inID,
AudioUnitScope inScope,
AudioUnitElement inElement)
{
Value data;
auto size = (UInt32) sizeof (Value);
if (AudioUnitGetProperty (inUnit, inID, inScope, inElement, &data, &size) == noErr)
return BasicOptional<Value> (data);
return data;
return BasicOptional<Value>();
return {};
}
static UInt32 getElementCount (AudioUnit comp, AudioUnitScope scope) noexcept
{
const auto count = tryGetProperty<UInt32> (comp, kAudioUnitProperty_ElementCount, scope, 0);
jassert (count.isValid);
return count.value;
jassert (count);
return *count;
}
/* The plugin may expect its channels in a particular order, reported to the host
@@ -390,8 +377,8 @@ namespace AudioUnitFormatHelpers
if (const auto layout = tryGetProperty<AudioChannelLayout> (comp, kAudioUnitProperty_AudioChannelLayout, scope, busIndex))
{
const auto juceChannelOrder = CoreAudioLayouts::fromCoreAudio (layout.value);
const auto auChannelOrder = CoreAudioLayouts::getCoreAudioLayoutChannels (layout.value);
const auto juceChannelOrder = CoreAudioLayouts::fromCoreAudio (*layout);
const auto auChannelOrder = CoreAudioLayouts::getCoreAudioLayoutChannels (*layout);
for (auto juceChannelIndex = 0; juceChannelIndex < juceChannelOrder.size(); ++juceChannelIndex)
busMap.push_back ((size_t) auChannelOrder.indexOf (juceChannelOrder.getTypeOfChannel (juceChannelIndex)));
@@ -1090,7 +1077,7 @@ public:
zerostruct (timeStamp);
timeStamp.mSampleTime = 0;
timeStamp.mHostTime = GetCurrentHostTime (0, newSampleRate, isAUv3);
timeStamp.mHostTime = mach_absolute_time();
timeStamp.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid;
wasPlaying = false;
@@ -1148,6 +1135,17 @@ public:
void processAudio (AudioBuffer<float>& buffer, MidiBuffer& midiMessages, bool processBlockBypassedCalled)
{
if (const auto* hostTimeNs = getHostTimeNs())
{
timeStamp.mHostTime = *hostTimeNs;
timeStamp.mFlags |= kAudioTimeStampHostTimeValid;
}
else
{
timeStamp.mHostTime = 0;
timeStamp.mFlags &= ~kAudioTimeStampHostTimeValid;
}
// If these are hit, we might allocate in the process block!
jassert (buffer.getNumChannels() <= preparedChannels);
jassert (buffer.getNumSamples() <= preparedSamples);
@@ -1156,7 +1154,7 @@ public:
// to the following bus.
inputBuffer.makeCopyOf (buffer, true);
auto numSamples = buffer.getNumSamples();
const auto numSamples = buffer.getNumSamples();
if (auSupportsBypass)
{
@@ -1170,8 +1168,6 @@ public:
if (prepared)
{
timeStamp.mHostTime = GetCurrentHostTime (numSamples, getSampleRate(), isAUv3);
const auto numOutputBuses = getBusCount (false);
for (int i = 0; i < numOutputBuses; ++i)
@@ -1615,6 +1611,8 @@ private:
friend class AudioUnitPluginWindowCocoa;
friend class AudioUnitPluginFormat;
CoreAudioTimeConversions timeConversions;
AudioComponentDescription componentDesc;
AudioComponent auComponent;
String pluginName, manufacturer, version;
@@ -2164,29 +2162,6 @@ private:
}
//==============================================================================
static UInt64 GetCurrentHostTime (int numSamples, double sampleRate, bool isAUv3) noexcept
{
#if ! JUCE_IOS
if (! isAUv3)
return AudioGetCurrentHostTime();
#else
ignoreUnused (isAUv3);
#endif
UInt64 currentTime = mach_absolute_time();
static mach_timebase_info_data_t sTimebaseInfo = { 0, 0 };
if (sTimebaseInfo.denom == 0)
mach_timebase_info (&sTimebaseInfo);
auto bufferNanos = static_cast<double> (numSamples) * 1.0e9 / sampleRate;
auto bufferTicks = static_cast<UInt64> (std::ceil (bufferNanos * (static_cast<double> (sTimebaseInfo.denom)
/ static_cast<double> (sTimebaseInfo.numer))));
currentTime += bufferTicks;
return currentTime;
}
bool isBusCountWritable (bool isInput) const noexcept
{
UInt32 countSize;


+ 15
- 28
modules/juce_audio_processors/format_types/juce_VST3Common.h View File

@@ -20,6 +20,8 @@
#ifndef DOXYGEN
#include <juce_core/containers/juce_Optional.h>
namespace juce
{
@@ -1033,10 +1035,8 @@ public:
if (eventList.getEvent (i, e) != Steinberg::kResultOk)
continue;
const auto message = toMidiMessage (e);
if (message.isValid)
result.addEvent (message.item, e.sampleOffset);
if (const auto message = toMidiMessage (e))
result.addEvent (*message, e.sampleOffset);
}
}
@@ -1109,15 +1109,12 @@ private:
}
}
auto maybeEvent = createVstEvent (msg, metadata.data, kind);
if (! maybeEvent.isValid)
continue;
auto& e = maybeEvent.item;
e.busIndex = 0;
e.sampleOffset = metadata.samplePosition;
result.addEvent (e);
if (auto maybeEvent = createVstEvent (msg, metadata.data, kind))
{
maybeEvent->busIndex = 0;
maybeEvent->sampleOffset = metadata.samplePosition;
result.addEvent (*maybeEvent);
}
}
}
@@ -1234,19 +1231,9 @@ private:
msg.getQuarterFrameValue());
}
template <typename Item>
struct BasicOptional final
{
BasicOptional() noexcept = default;
BasicOptional (const Item& i) noexcept : item { i }, isValid { true } {}
Item item;
bool isValid{};
};
static BasicOptional<Steinberg::Vst::Event> createVstEvent (const MidiMessage& msg,
const uint8* midiEventData,
EventConversionKind kind) noexcept
static Optional<Steinberg::Vst::Event> createVstEvent (const MidiMessage& msg,
const uint8* midiEventData,
EventConversionKind kind) noexcept
{
if (msg.isNoteOn())
return createNoteOnEvent (msg);
@@ -1290,7 +1277,7 @@ private:
return {};
}
static BasicOptional<MidiMessage> toMidiMessage (const Steinberg::Vst::LegacyMIDICCOutEvent& e)
static Optional<MidiMessage> toMidiMessage (const Steinberg::Vst::LegacyMIDICCOutEvent& e)
{
if (e.controlNumber <= 127)
return MidiMessage::controllerEvent (createSafeChannel (int16 (e.channel)),
@@ -1327,7 +1314,7 @@ private:
}
}
static BasicOptional<MidiMessage> toMidiMessage (const Steinberg::Vst::Event& e)
static Optional<MidiMessage> toMidiMessage (const Steinberg::Vst::Event& e)
{
switch (e.type)
{


+ 12
- 2
modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -240,7 +240,10 @@ static void setStateForAllBusesOfType (Vst::IComponent* component,
}
//==============================================================================
static void toProcessContext (Vst::ProcessContext& context, AudioPlayHead* playHead, double sampleRate)
static void toProcessContext (Vst::ProcessContext& context,
AudioPlayHead* playHead,
double sampleRate,
const uint64_t* hostTimeNs)
{
jassert (sampleRate > 0.0); //Must always be valid, as stated by the VST3 SDK
@@ -295,6 +298,13 @@ static void toProcessContext (Vst::ProcessContext& context, AudioPlayHead* playH
if (context.timeSigNumerator > 0 && context.timeSigDenominator > 0)
context.state |= ProcessContext::kTimeSigValid;
if (hostTimeNs != nullptr)
{
context.systemTime = (int64_t) *hostTimeNs;
jassert (context.systemTime >= 0);
context.state |= ProcessContext::kSystemTimeValid;
}
}
//==============================================================================
@@ -3345,7 +3355,7 @@ private:
void updateTimingInformation (Vst::ProcessData& destination, double processSampleRate)
{
toProcessContext (timingInfo, getPlayHead(), processSampleRate);
toProcessContext (timingInfo, getPlayHead(), processSampleRate, getHostTimeNs());
destination.processContext = &timingInfo;
}


+ 22
- 19
modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp View File

@@ -2367,7 +2367,6 @@ private:
if (currentPlayHead->getCurrentPosition (position))
{
vstHostTime.samplePos = (double) position.timeInSamples;
vstHostTime.tempo = position.bpm;
vstHostTime.timeSigNumerator = position.timeSigNumerator;
@@ -2375,9 +2374,19 @@ private:
vstHostTime.ppqPos = position.ppqPosition;
vstHostTime.barStartPos = position.ppqPositionOfLastBarStart;
vstHostTime.flags |= Vst2::kVstTempoValid
| Vst2::kVstTimeSigValid
| Vst2::kVstPpqPosValid
| Vst2::kVstBarsValid;
| Vst2::kVstTimeSigValid
| Vst2::kVstPpqPosValid
| Vst2::kVstBarsValid;
if (const auto* hostTimeNs = getHostTimeNs())
{
vstHostTime.nanoSeconds = (double) *hostTimeNs;
vstHostTime.flags |= Vst2::kVstNanosValid;
}
else
{
vstHostTime.flags &= ~Vst2::kVstNanosValid;
}
int32 newTransportFlags = 0;
if (position.isPlaying) newTransportFlags |= Vst2::kVstTransportPlaying;
@@ -2389,28 +2398,22 @@ private:
else
vstHostTime.flags &= ~Vst2::kVstTransportChanged;
struct OptionalFrameRate
{
bool valid;
Vst2::VstInt32 rate;
};
const auto optionalFrameRate = [&fr = position.frameRate]() -> OptionalFrameRate
const auto optionalFrameRate = [&fr = position.frameRate]() -> Optional<Vst2::VstInt32>
{
switch (fr.getBaseRate())
{
case 24: return { true, fr.isPullDown() ? Vst2::kVstSmpte239fps : Vst2::kVstSmpte24fps };
case 25: return { true, fr.isPullDown() ? Vst2::kVstSmpte249fps : Vst2::kVstSmpte25fps };
case 30: return { true, fr.isPullDown() ? (fr.isDrop() ? Vst2::kVstSmpte2997dfps : Vst2::kVstSmpte2997fps)
: (fr.isDrop() ? Vst2::kVstSmpte30dfps : Vst2::kVstSmpte30fps) };
case 60: return { true, fr.isPullDown() ? Vst2::kVstSmpte599fps : Vst2::kVstSmpte60fps };
case 24: return fr.isPullDown() ? Vst2::kVstSmpte239fps : Vst2::kVstSmpte24fps;
case 25: return fr.isPullDown() ? Vst2::kVstSmpte249fps : Vst2::kVstSmpte25fps;
case 30: return fr.isPullDown() ? (fr.isDrop() ? Vst2::kVstSmpte2997dfps : Vst2::kVstSmpte2997fps)
: (fr.isDrop() ? Vst2::kVstSmpte30dfps : Vst2::kVstSmpte30fps);
case 60: return fr.isPullDown() ? Vst2::kVstSmpte599fps : Vst2::kVstSmpte60fps;
}
return { false, Vst2::VstSmpteFrameRate{} };
return {};
}();
vstHostTime.flags |= optionalFrameRate.valid ? Vst2::kVstSmpteValid : 0;
vstHostTime.smpteFrameRate = optionalFrameRate.rate;
vstHostTime.flags |= optionalFrameRate ? Vst2::kVstSmpteValid : 0;
vstHostTime.smpteFrameRate = optionalFrameRate.orFallback (Vst2::VstSmpteFrameRate{});
vstHostTime.smpteOffset = (int32) (position.timeInSeconds * 80.0 * position.frameRate.getEffectiveRate() + 0.5);
if (position.isLooping)


+ 1
- 0
modules/juce_audio_processors/juce_audio_processors.cpp View File

@@ -33,6 +33,7 @@
#include "juce_audio_processors.h"
#include <juce_gui_extra/juce_gui_extra.h>
#include <juce_core/containers/juce_Optional.h>
//==============================================================================
#if JUCE_MAC


+ 48
- 0
modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -1125,6 +1125,51 @@ public:
*/
virtual void setPlayHead (AudioPlayHead* newPlayHead);
//==============================================================================
/** Hosts may call this function to supply the system time corresponding to the
current audio buffer.
If you want to set a valid time, pass a pointer to a uint64_t holding the current time. The
value will be copied into the AudioProcessor instance without any allocation/deallocation.
If you want to clear any stored host time, pass nullptr.
Calls to this function must be synchronised (i.e. not simultaneous) with the audio callback.
@code
const auto currentHostTime = computeHostTimeNanos();
processor.setHostTimeNanos (&currentHostTime); // Set a valid host time
// ...call processBlock etc.
processor.setHostTimeNanos (nullptr); // Clear host time
@endcode
*/
void setHostTimeNanos (const uint64_t* hostTimeIn)
{
hasHostTime = hostTimeIn != nullptr;
hostTime = hasHostTime ? *hostTimeIn : 0;
}
/** The plugin may call this function inside the processBlock function (and only there!)
to find the timestamp associated with the current audio block.
If a timestamp is available, this will return a pointer to that timestamp. You should
immediately copy the pointed-to value and use that in any following code. Do *not* free
any pointer returned by this function.
If no timestamp is provided, this will return nullptr.
@code
void processBlock (AudioBuffer<float>&, MidiBuffer&) override
{
if (auto* timestamp = getHostTimeNs())
{
// Use *timestamp here to compensate for callback jitter etc.
}
}
@endcode
*/
const uint64_t* getHostTimeNs() const { return hasHostTime ? &hostTime : nullptr; }
//==============================================================================
/** This is called by the processor to specify its details before being played. Use this
version of the function if you are not interested in any sidechain and/or aux buses
@@ -1473,6 +1518,9 @@ private:
AudioProcessorParameterGroup parameterTree;
Array<AudioProcessorParameter*> flatParameterList;
uint64_t hostTime = 0;
bool hasHostTime = false;
AudioProcessorParameter* getParamChecked (int) const;
#if JUCE_DEBUG


+ 19
- 5
modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp View File

@@ -37,10 +37,11 @@ struct GraphRenderSequence
FloatType** audioBuffers;
MidiBuffer* midiBuffers;
AudioPlayHead* audioPlayHead;
Optional<uint64_t> hostTimeNs;
int numSamples;
};
void perform (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages, AudioPlayHead* audioPlayHead)
void perform (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages, AudioPlayHead* audioPlayHead, Optional<uint64_t> hostTimeNs)
{
auto numSamples = buffer.getNumSamples();
auto maxSamples = renderingBuffer.getNumSamples();
@@ -57,7 +58,9 @@ struct GraphRenderSequence
midiChunk.clear();
midiChunk.addEvents (midiMessages, chunkStartSample, chunkSize, -chunkStartSample);
perform (audioChunk, midiChunk, audioPlayHead);
// Splitting up the buffer like this will cause the play head and host time to be
// invalid for all but the first chunk...
perform (audioChunk, midiChunk, audioPlayHead, hostTimeNs);
chunkStartSample += maxSamples;
}
@@ -72,7 +75,7 @@ struct GraphRenderSequence
currentMidiOutputBuffer.clear();
{
const Context context { renderingBuffer.getArrayOfWritePointers(), midiBuffers.begin(), audioPlayHead, numSamples };
const Context context { renderingBuffer.getArrayOfWritePointers(), midiBuffers.begin(), audioPlayHead, hostTimeNs, numSamples };
for (auto* op : renderOps)
op->perform (context);
@@ -257,6 +260,7 @@ private:
void perform (const Context& c) override
{
processor.setPlayHead (c.audioPlayHead);
processor.setHostTimeNanos (c.hostTimeNs.hasValue() ? &(*c.hostTimeNs) : nullptr);
for (int i = 0; i < totalChans; ++i)
audioChannels[i] = c.audioBuffers[audioChannelsToUse.getUnchecked (i)];
@@ -278,6 +282,8 @@ private:
buffer.clear();
else
callProcess (buffer, c.midiBuffers[midiBufferToUse]);
processor.setHostTimeNanos (nullptr);
}
void callProcess (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
@@ -1389,6 +1395,14 @@ static void processBlockForBuffer (AudioBuffer<FloatType>& buffer, MidiBuffer& m
std::unique_ptr<SequenceType>& renderSequence,
std::atomic<bool>& isPrepared)
{
const auto getHostTime = [&]() -> Optional<uint64_t>
{
if (auto* nanos = graph.getHostTimeNs())
return *nanos;
return nullopt;
};
if (graph.isNonRealtime())
{
while (! isPrepared)
@@ -1397,7 +1411,7 @@ static void processBlockForBuffer (AudioBuffer<FloatType>& buffer, MidiBuffer& m
const ScopedLock sl (graph.getCallbackLock());
if (renderSequence != nullptr)
renderSequence->perform (buffer, midiMessages, graph.getPlayHead());
renderSequence->perform (buffer, midiMessages, graph.getPlayHead(), getHostTime());
}
else
{
@@ -1406,7 +1420,7 @@ static void processBlockForBuffer (AudioBuffer<FloatType>& buffer, MidiBuffer& m
if (isPrepared)
{
if (renderSequence != nullptr)
renderSequence->perform (buffer, midiMessages, graph.getPlayHead());
renderSequence->perform (buffer, midiMessages, graph.getPlayHead(), getHostTime());
}
else
{


+ 16
- 5
modules/juce_audio_utils/players/juce_AudioProcessorPlayer.cpp View File

@@ -226,11 +226,12 @@ void AudioProcessorPlayer::setMidiOutput (MidiOutput* midiOutputToUse)
}
//==============================================================================
void AudioProcessorPlayer::audioDeviceIOCallback (const float** const inputChannelData,
const int numInputChannels,
float** const outputChannelData,
const int numOutputChannels,
const int numSamples)
void AudioProcessorPlayer::audioDeviceIOCallbackWithContext (const float** const inputChannelData,
const int numInputChannels,
float** const outputChannelData,
const int numOutputChannels,
const int numSamples,
const AudioIODeviceCallbackContext& context)
{
const ScopedLock sl (lock);
@@ -259,6 +260,16 @@ void AudioProcessorPlayer::audioDeviceIOCallback (const float** const inputChann
const ScopedLock sl2 (processor->getCallbackLock());
processor->setHostTimeNanos (context.hostTimeNs);
struct AtEndOfScope
{
~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
AudioProcessor& proc;
};
const AtEndOfScope scope { *processor };
if (! processor->isSuspended())
{
if (processor->isUsingDoublePrecision())


+ 1
- 1
modules/juce_audio_utils/players/juce_AudioProcessorPlayer.h View File

@@ -85,7 +85,7 @@ public:
//==============================================================================
/** @internal */
void audioDeviceIOCallback (const float**, int, float**, int, int) override;
void audioDeviceIOCallbackWithContext (const float**, int, float**, int, int, const AudioIODeviceCallbackContext&) override;
/** @internal */
void audioDeviceAboutToStart (AudioIODevice*) override;
/** @internal */


Loading…
Cancel
Save