@@ -697,7 +697,6 @@ void LfpDisplayCanvas::loadCustomParametersFromXml (XmlElement* xml)
697697 // LOGD(" Resized in ", MS_FROM_START, " milliseconds");
698698}
699699
700- static int frameCounter = 0 ;
701700
702701LfpDisplaySplitter::LfpDisplaySplitter (LfpDisplayNode* node,
703702 LfpDisplayCanvas* canvas_,
@@ -869,6 +868,9 @@ void LfpDisplaySplitter::beginAnimation()
869868void LfpDisplaySplitter::endAnimation ()
870869{
871870 stopTimer ();
871+
872+ if (viewerProcessing != nullptr )
873+ viewerProcessing->reset ();
872874}
873875
874876void LfpDisplaySplitter::timerCallback ()
@@ -1116,7 +1118,6 @@ void LfpDisplaySplitter::refreshScreenBuffer()
11161118 screenBufferMin->setSize (nChans, screenBufferWidth);
11171119 screenBufferMean->setSize (nChans, screenBufferWidth);
11181120 screenBufferMax->setSize (nChans, screenBufferWidth);
1119- frameCounter = 0 ;
11201121 }
11211122
11221123 // std::cout << "Display " << splitID << " setting screen buffer width to " << screenBufferWidth << std::endl;
@@ -1194,14 +1195,7 @@ void LfpDisplaySplitter::updateScreenBuffer()
11941195{
11951196 if (isVisible () && displayBuffer != nullptr && ! isUpdating)
11961197 {
1197- // Performance timing (log every 100 frames when filtering is active)
1198- const int64 startTime = Time::getHighResolutionTicks ();
1199- int64 preprocessTime = 0 ;
1200-
1201- // Preprocess new samples through filter/CAR if active
1202- const int64 preprocessStart = Time::getHighResolutionTicks ();
12031198 preprocessNewSamples ();
1204- preprocessTime = Time::getHighResolutionTicks () - preprocessStart;
12051199
12061200 // Determine whether to read from the processed shadow buffer or the raw display buffer
12071201 const bool useProcessedBuffer = viewerProcessing != nullptr
@@ -1638,26 +1632,6 @@ void LfpDisplaySplitter::updateScreenBuffer()
16381632 }
16391633 }
16401634
1641- // // Performance logging (every 100 frames when processing is active)
1642- // if (++frameCounter >= 100)
1643- // {
1644- // frameCounter = 0;
1645- // const int64 totalTime = Time::getHighResolutionTicks() - startTime;
1646- // const double preprocessMs = Time::highResolutionTicksToSeconds (preprocessTime) * 1000.0;
1647- // const double totalMs = Time::highResolutionTicksToSeconds (totalTime) * 1000.0;
1648- // const double renderMs = totalMs - preprocessMs;
1649-
1650- // std::cout << "[LFP Performance] Split " << splitID
1651- // << ": Total=" << String (totalMs, 2) << "ms"
1652- // << " | Preprocess=" << String (preprocessMs, 2) << "ms ("
1653- // << String (preprocessMs / totalMs * 100.0, 1) << "%)"
1654- // << " | Render=" << String (renderMs, 2) << "ms ("
1655- // << String (renderMs / totalMs * 100.0, 1) << "%)"
1656- // << " | Channels=" << nChans
1657- // << " | HP=" << (viewerProcessing->isHighPassEnabled() ? "ON" : "OFF")
1658- // << " | CAR=" << (viewerProcessing->isCAREnabled() ? "ON" : "OFF")
1659- // << std::endl;
1660- // }
16611635 }
16621636}
16631637
@@ -1702,58 +1676,38 @@ void LfpDisplaySplitter::preprocessNewSamples()
17021676 if (newSamples > displayBufferSize)
17031677 newSamples = displayBufferSize;
17041678
1705- // Resize temp buffer if needed (reuses memory between calls)
1706- if (tempProcessingBuffer.getNumChannels () != nChans
1707- || tempProcessingBuffer.getNumSamples () < newSamples)
1708- {
1709- tempProcessingBuffer.setSize (nChans, newSamples, false , false , true );
1710- }
1679+ // Copy new samples directly into processedDisplayBuffer,
1680+ // then filter/CAR in-place on contiguous chunk views (avoids temp copy-back).
1681+ const int firstChunk = jmin (newSamples, displayBufferSize - oldIdx);
1682+ const int secondChunk = newSamples - firstChunk;
17111683
1712- // Copy new samples from circular displayBuffer into the contiguous temp buffer
1713- for (int ch = 0 ; ch < nChans; ch++)
1684+ auto copyAndProcessChunk = [&] (int chunkStart, int chunkSize)
17141685 {
1715- const float * src = displayBuffer-> getReadPointer (ch);
1716- float * dst = tempProcessingBuffer. getWritePointer (ch) ;
1686+ if (chunkSize <= 0 )
1687+ return ;
17171688
1718- int srcStart = oldIdx;
1719- int firstChunk = jmin (newSamples, displayBufferSize - srcStart);
1720-
1721- std::memcpy (dst, src + srcStart, firstChunk * sizeof (float ));
1722-
1723- if (firstChunk < newSamples)
1689+ for (int ch = 0 ; ch < nChans; ch++)
17241690 {
1725- std::memcpy (dst + firstChunk, src, (newSamples - firstChunk) * sizeof (float ));
1691+ const float * src = displayBuffer->getReadPointer (ch);
1692+ float * dst = processedDisplayBuffer->getWritePointer (ch);
1693+ std::memcpy (dst + chunkStart, src + chunkStart, chunkSize * sizeof (float ));
17261694 }
1727- }
1728-
1729- // Apply high-pass filter (per channel, in-place on temp buffer)
1730- if (viewerProcessing->isHighPassEnabled ())
1731- {
1732- viewerProcessing->applyHighPass (tempProcessingBuffer, newSamples, nChans);
1733- }
17341695
1735- // Apply CAR (across channels, in-place on temp buffer)
1736- if (viewerProcessing->isCAREnabled ())
1737- {
1738- viewerProcessing->applyCAR (tempProcessingBuffer, newSamples, nChans);
1739- }
1696+ HeapBlock<float *> channelPtrs (nChans);
1697+ for (int ch = 0 ; ch < nChans; ch++)
1698+ channelPtrs[ch] = processedDisplayBuffer->getWritePointer (ch, chunkStart);
17401699
1741- // Write processed data back to the shadow circular buffer
1742- for (int ch = 0 ; ch < nChans; ch++)
1743- {
1744- const float * src = tempProcessingBuffer.getReadPointer (ch);
1745- float * dst = processedDisplayBuffer->getWritePointer (ch);
1700+ AudioBuffer<float > processingView (channelPtrs.getData (), nChans, chunkSize);
17461701
1747- int dstStart = oldIdx;
1748- int firstChunk = jmin (newSamples, displayBufferSize - dstStart );
1702+ if (viewerProcessing-> isHighPassEnabled ())
1703+ viewerProcessing-> applyHighPass (processingView, chunkSize, nChans );
17491704
1750- std::memcpy (dst + dstStart, src, firstChunk * sizeof (float ));
1705+ if (viewerProcessing->isCAREnabled ())
1706+ viewerProcessing->applyCAR (processingView, chunkSize, nChans);
1707+ };
17511708
1752- if (firstChunk < newSamples)
1753- {
1754- std::memcpy (dst, src + firstChunk, (newSamples - firstChunk) * sizeof (float ));
1755- }
1756- }
1709+ copyAndProcessChunk (oldIdx, firstChunk);
1710+ copyAndProcessChunk (0 , secondChunk);
17571711
17581712 // Copy event channel directly (no processing applied)
17591713 {
@@ -1998,7 +1952,6 @@ void LfpDisplaySplitter::visibleAreaChanged()
19981952
19991953void LfpDisplaySplitter::refresh ()
20001954{
2001- const int64 startTime = Time::getHighResolutionTicks ();
20021955 updateScreenBuffer ();
20031956
20041957 if (shouldRebuildChannelList)
@@ -2010,15 +1963,6 @@ void LfpDisplaySplitter::refresh()
20101963 {
20111964 lfpDisplay->refresh (); // redraws only the new part of the screen buffer, unless fullredraw is set to true
20121965 }
2013-
2014- if (frameCounter++ >= 100 )
2015- {
2016- frameCounter = 0 ;
2017- const int64 totalTime = Time::getHighResolutionTicks () - startTime;
2018- const double totalMs = Time::highResolutionTicksToSeconds (totalTime) * 1000.0 ;
2019-
2020- std::cout << " LFP Display Split " << splitID << " refresh time: " << String (totalMs, 2 ) << " ms" << std::endl;
2021- }
20221966}
20231967
20241968void LfpDisplaySplitter::comboBoxChanged (juce::ComboBox* comboBox)
0 commit comments