audioIODeviceCallback vs ProcessBlock vs process(): Why?


#1

Can we get a little explanation as to why the JUCE folks chose what they chose for these very important methods?

virtual void AudioDeviceManager::audioDeviceIOCallback (const float **inputChannelData, 
                                    int numInputChannels, 
                                    float **outputChannelData, 
                                    int numOutputChannels, 
                                    int numSamples)=0
virtual void AudioProcessor::processBlock( AudioBuffer<float>& buffer,
                                           MidiBuffer& midiMessages)	
static void AudioBlock::process (const AudioBlock< SampleType > &inBlock, 
                                 AudioBlock< SampleType > &outBlock, 
                                 const FunctionType &function)
template<typename SampleType >
template<typename ProcessContext >
void FIR::Filter< SampleType >::process	(	const ProcessContext & 	context	)	
void AudioSource::getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill)

seems like every class has their own name and signature for processing a block of audio samples… Why not be consistent and provide the same name and method signature since they’re all doing the same thing: processing a block of audio samples


#2

I would guess : legacy reasons.

By the way, AudioSource also has :

void getNextAudioBlock(const AudioSourceChannelInfo & bufferToFill)

:wink:


#3

lol original post updated!


#4

Well said. Consider that JUCE is, what, 15 years old now?

Thing is, each of those signatures make sense when you understand the surrounding context and related back-end aspects. More importantly, even if the signatures could be unified, changing those really deep APIs in one foul swoop would be a massive headache - not only would be it be huge pain in the ass for Roli to get right, the users are going to have to fix any products of theirs based on the library.

Roli provides insights on some of the differences in a couple posts:


#5

way back when, I’m sure JUCE was first designed to be a cross-platform wrapper for methods like this:

typedef OSStatus (*AudioDeviceIOProc)(AudioObjectID inDevice, 
const AudioTimeStamp *inNow, 
const AudioBufferList *inInputData, 
const AudioTimeStamp *inInputTime, 
AudioBufferList *outOutputData, 
const AudioTimeStamp *inOutputTime, 
void *inClientData);

taken from: https://developer.apple.com/documentation/coreaudio/audiodeviceioproc?language=objc

and whatever the PC version of that is. maybe this thing, but who knows:

 HRESULT IAudioRenderClient::GetBuffer(
  [in]  UINT32 NumFramesRequested,
  [out] BYTE   **ppData
);
taken from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd368243(v=vs.85).aspx

it’s pretty easy to see how AudioDeviceIOCallback was created. and for AudioUnits, I dug this snippet up from the Learning Core Audio book, chapter 7:

typedef OSStatus (*AURenderCallback) (
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData
);

This was back in the days of XCode4, so I have no idea what version of OS X was being used at the time of that book’s publication, but it was definitely a while ago. Probably OS X 10.6 or 10.5. Either way, we can kind of get a vibe for where
AudioBuffer (Type *const *dataToReferTo, int numChannelsToUse, int numSamples)
came from. i’m sure there’s a VST SDK equivalent too, but that VST SDK Documentation isn’t browsable online (annoying).

My main reason for asking was that it would make plugin and audio app development that much easier and more accessible if a consistent interface were used, regardless of the legacy code that might get broken. Every time apple or microsoft release a new OS, old code gets broken and 3rd party devs have to release updates to their products for compatibility. Why should Juce be any different?


#6

Newsflash:

(Version 3, but anyway…)

EDIT: Maybe I spoke too soon… all folders seem to be submodules outside the repository… :frowning:


#7

I was just investigating that the other day - pretty cool!

What’s the issue with this exactly? You can add this repo as a submodule in your project, and recursively update with one git command…


#8

Ah, thanks for making me look again…
Yes, pretty cool, after calling

git submodule update --init *

So just for browsing online it is lacking some direct links to the submodules:


#9

No problem! FYI, you can only init once - for every other time you want to update your submodules to your repository’s latest, you’ll need to do:

git submodule update --recursive

#10

…or you can issue always the same command which will always do the right thing:

git submodule update --init --recursive