#if SC_AUDIO_API == SC_AUDIO_API_EXTERNAL
# include "SC_CoreAudio.h"
# include "SC_HiddenWorld.h"
# include "SC_Prototypes.h"
# include "SC_Time.hpp"
# include "SC_World.h"
extern "C" int32 server_timeseed() { return timeSeed(); }
extern "C" int64 oscTimeNow() { return OSCTime(getTime()); }
void initializeScheduler() {}
class SC_ExternalDriver : public SC_AudioDriver {
public:
SC_ExternalDriver(World* inWorld): SC_AudioDriver(inWorld) { mOSCbuftime = 0; }
~SC_ExternalDriver() override = default;
void processBlock(const float* input, int numInputChannels, float* output, int numOutputChannels,
int numFrames);
protected:
bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate) override {
*outSampleRate =
mPreferredSampleRate != 0 ? (double)mPreferredSampleRate : (double)mWorld->mBufLength * 1.0;
if (mPreferredSampleRate == 0)
*outSampleRate = 44100.0;
*outNumSamplesPerCallback =
mPreferredHardwareBufferFrameSize != 0 ? (int)mPreferredHardwareBufferFrameSize : (int)mWorld->mBufLength;
return true;
}
bool DriverStart() override { return true; }
bool DriverStop() override { return true; }
};
SC_AudioDriver* SC_NewAudioDriver(World* inWorld) { return new SC_ExternalDriver(inWorld); }
void SC_ExternalDriver::processBlock(const float* input, int numInputChannels, float* output, int numOutputChannels,
int numFrames) {
World* world = mWorld;
mFromEngine.Free();
mToEngine.Perform();
mOscPacketsToEngine.Perform();
const int bufFrames = (int)world->mBufLength;
const int numBufs = numFrames / bufFrames;
float* inBuses = world->mAudioBus + world->mNumOutputs * bufFrames;
const float* outBuses = world->mAudioBus;
int32* inTouched = world->mAudioBusTouched + world->mNumOutputs;
const int32* outTouched = world->mAudioBusTouched;
int64 oscTime = mOSCbuftime;
const int64 oscInc = mOSCincrement;
int frameOffset = 0;
for (int i = 0; i < numBufs; ++i, world->mBufCounter++, frameOffset += bufFrames) {
const int32 bufCounter = world->mBufCounter;
for (int ch = 0; input && ch < (int)world->mNumInputs && ch < numInputChannels; ++ch) {
float* dst = inBuses + ch * bufFrames;
const float* src = input + frameOffset * numInputChannels + ch;
for (int k = 0; k < bufFrames; ++k)
dst[k] = src[k * numInputChannels];
inTouched[ch] = bufCounter;
}
const int64 nextTime = oscTime + oscInc;
while (mScheduler.NextTime() <= nextTime) {
SC_ScheduledEvent event = mScheduler.Remove();
event.Perform();
}
world->mSampleOffset = 0;
world->mSubsampleOffset = 0.f;
World_Run(world);
for (int ch = 0; ch < (int)world->mNumOutputs && ch < numOutputChannels; ++ch) {
float* dst = output + frameOffset * numOutputChannels + ch;
if (outTouched[ch] == bufCounter) {
const float* srcBus = outBuses + ch * bufFrames;
for (int k = 0; k < bufFrames; ++k)
dst[k * numOutputChannels] = srcBus[k];
} else {
for (int k = 0; k < bufFrames; ++k)
dst[k * numOutputChannels] = 0.f;
}
}
oscTime = mOSCbuftime = nextTime;
}
for (int f = numBufs * bufFrames; f < numFrames; ++f)
for (int ch = 0; ch < numOutputChannels; ++ch)
output[f * numOutputChannels + ch] = 0.f;
mAudioSync.Signal();
}
extern "C" void scsynth_pump(World* world, const float* input, int numInputChannels, float* output,
int numOutputChannels, int numFrames) {
if (!world || !world->hw || !world->hw->mAudioDriver)
return;
auto* driver = static_cast<SC_ExternalDriver*>(world->hw->mAudioDriver);
driver->processBlock(input, numInputChannels, output, numOutputChannels, numFrames);
}
#endif