Skip to content

Commit 86d41da

Browse files
committed
Optimize spike serialization by reusing a persistent buffer and improving MidiBuffer insertion efficiency
1 parent 23d4bb1 commit 86d41da

1 file changed

Lines changed: 32 additions & 3 deletions

File tree

Source/Processors/GenericProcessor/GenericProcessor.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,11 +1509,40 @@ void GenericProcessor::addSpike (const Spike* spike)
15091509
+ spike->spikeChannel->getTotalEventMetadataSize()
15101510
+ spike->spikeChannel->getNumChannels() * sizeof (float);
15111511

1512-
HeapBlock<char> buffer (size);
1512+
// Reuse a function-local persistent buffer, growing only when needed.
1513+
// This avoids a per-spike HeapBlock allocation.
1514+
// Safe because addSpike is only called from the real-time audio thread.
1515+
static HeapBlock<char> serializeBuffer;
1516+
static size_t serializeBufferSize = 0;
15131517

1514-
spike->serialize (buffer, size);
1518+
if (size > serializeBufferSize)
1519+
{
1520+
serializeBuffer.realloc (size);
1521+
serializeBufferSize = size;
1522+
}
15151523

1516-
m_currentMidiBuffer->addEvent (buffer, int (size), 0);
1524+
spike->serialize (serializeBuffer, size);
1525+
1526+
// Directly append to MidiBuffer's data array, bypassing addEvent()'s
1527+
// internal findEventAfter() which performs an O(n) scan of existing events
1528+
// for each insertion — resulting in O(n²) total cost for n spikes per callback.
1529+
//
1530+
// This is safe because downstream event consumers (processEventBuffer,
1531+
// checkForEvents) dispatch events by their raw serialized type byte,
1532+
// not by the MidiBuffer sample position.
1533+
auto& bufferData = m_currentMidiBuffer->data;
1534+
int offset = bufferData.size();
1535+
int newItemSize = (int) (size + sizeof (int32) + sizeof (uint16));
1536+
bufferData.insertMultiple (offset, 0, newItemSize);
1537+
1538+
uint8* d = bufferData.begin() + offset;
1539+
int32 samplePos = 0;
1540+
memcpy (d, &samplePos, sizeof (int32));
1541+
d += sizeof (int32);
1542+
uint16 dataLen = static_cast<uint16> (size);
1543+
memcpy (d, &dataLen, sizeof (uint16));
1544+
d += sizeof (uint16);
1545+
memcpy (d, static_cast<const char*> (serializeBuffer), size);
15171546
}
15181547

15191548
void GenericProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& eventBuffer)

0 commit comments

Comments
 (0)