#include "SC_WorldOptions.h"
#include "SC_ReplyImpl.hpp"
#include "SC_SndBuf.h"
#include "SC_Errors.h"
#include "malloc_aligned.hpp"
#include <array>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <mutex>
extern "C" void scsynth_default_world_options(WorldOptions* out) { *out = WorldOptions(); }
extern "C" void* scsynth_reply_context(ReplyAddress* a) { return a ? a->mReplyData : nullptr; }
typedef void (*ScBufferFunc)(void* ctx, const float* data, int num_samples, int num_channels,
int num_frames);
extern "C" int scsynth_copy_buffer(World* world, uint32 index, ScBufferFunc fn, void* ctx) {
SndBuf scratch;
std::memset(&scratch, 0, sizeof(scratch));
int err = World_CopySndBuf(world, index, &scratch, false, nullptr);
if (err == kSCErr_None && fn != nullptr) {
fn(ctx, scratch.data, scratch.samples, scratch.channels, scratch.frames);
}
nova::free_aligned(scratch.data);
return err;
}
typedef void (*ScLogFunc)(void* ctx, const char* text, int len);
namespace {
ScLogFunc g_log_func = nullptr;
void* g_log_ctx = nullptr;
std::mutex g_log_mutex;
int scsynth_log_trampoline(const char* fmt, va_list vargs) {
std::array<char, 4096> buf;
int n = std::vsnprintf(buf.data(), buf.size(), fmt, vargs);
if (n < 0) {
return n;
}
int len = n < static_cast<int>(buf.size()) ? n : static_cast<int>(buf.size()) - 1;
std::lock_guard<std::mutex> lock(g_log_mutex);
if (g_log_func != nullptr) {
g_log_func(g_log_ctx, buf.data(), len);
}
return n;
}
}
extern "C" void scsynth_set_log_func(ScLogFunc fn, void* ctx) {
std::lock_guard<std::mutex> lock(g_log_mutex);
g_log_func = fn;
g_log_ctx = ctx;
SetPrintFunc(fn != nullptr ? scsynth_log_trampoline : nullptr);
}