I’ve generated c++ for the following rather artificial example:
namespace Events
{
struct Input
{
float f1;
float f2;
}
struct Output
{
float sum;
float product;
}
}
processor SumProduct [[ main ]]
{
input stream float audioIn;
output stream float audioOut;
input event Events::Input eventIn;
output event Events::Output eventOut;
event eventIn (Events::Input i)
{
sum = i.f1 + i.f2;
product = i.f1 * i.f2;
}
float sum;
float product;
void run()
{
loop
{
eventOut << Events::Output (sum, product);
loop (10)
{
audioOut << audioIn * product;
advance();
}
}
}
}
And for my test, i’m calling it like this:
TEST (CppGenerator, SumProduct)
{
uint32_t sampleRate = 44100;
uint32_t blockSize = 100;
auto inputChannels = soul::AllocatedChannelSet<soul::DiscreteChannelSet<float>> (1, blockSize);
auto outputChannels = soul::AllocatedChannelSet<soul::DiscreteChannelSet<float>> (1, blockSize);
for (uint32_t i = 0; i < blockSize; i++)
inputChannels.channelSet.getSample (0, i) = float (i);
SumProduct sumProduct;
sumProduct.init (sampleRate);
// Submit an event
sumProduct._external_event_eventIn (sumProduct.state, { 0.1f, 0.2f } );
// Render 100 samples
auto rc = SumProduct::RenderContext { inputChannels.channelSet.channels, outputChannels.channelSet.channels, nullptr, blockSize, 1, 1, 0 };
sumProduct.render (rc);
// Check output data
for (uint32_t i = 0; i < blockSize; i++)
EXPECT_NEAR (outputChannels.channelSet.getSample (0, i), 0.02f * float(i), 0.0001f);
// Retrieve output events
SumProduct::FixedSizeArray<SumProduct::Events__Output, 1024> events;
SumProduct::FixedSizeArray<int32_t, 1024> eventTimes;
auto eventCount = sumProduct._getEventsFromOutput_eventOut(sumProduct.state, events, eventTimes);
EXPECT_EQ (10, eventCount);
for (int i = 0; i < eventCount; i++)
{
EXPECT_NEAR (0.3f, events[i].m_sum, 0.0001f);
EXPECT_NEAR (0.02f, events[i].m_product, 0.0001f);
EXPECT_EQ (i * 10, eventTimes[i]);
}
}
As I said, it’s not pretty, but you should be able to understand what we’re up to. Events in are processed immediately, so if you want to put an event in half way through a block, it’s your problem to split the block into pieces and call the eventIn handler at the appropriate sample number.
For output events, you retrieve them to a FixedSizedArray, and the return tells you how many were generated during that block. Now this can overflow the buffer, so if > 1024 were generated in the block, we’d only get the first 1024, but the return code would indicate the number that were generated (so we can tell event overflow). This test code doesn’t deal with that situation.
Hopefully this is clear. Sorry the interface is a bit crappy, but this is as I said an area we’re working to improve.