@@ -158,16 +158,22 @@ float DataQueue::writeSynchronizedTimestamps (double start, double step, int des
158158 LOGE (__FUNCTION__, " Recording Data Queue Overflow: sz1: " , size1, " sz2: " , size2, " nSamples: " , nSamples);
159159 }
160160
161+ // Get direct pointer access for faster writes
162+ double * writePtr = m_FTSBuffer.getWritePointer (destChannel);
163+
164+ // Fill first segment
161165 for (int i = 0 ; i < size1; i++)
162166 {
163- m_FTSBuffer. setSample (destChannel, index1 + i, start + (double ) i * step) ;
167+ writePtr[ index1 + i] = start + (double ) i * step;
164168 }
165169
170+ // Fill second segment (wrap-around) if present
166171 if (size2 > 0 )
167172 {
173+ double offset = start + (double ) size1 * step;
168174 for (int i = 0 ; i < size2; i++)
169175 {
170- m_FTSBuffer. setSample (destChannel, index2 + i, start + (double ) (size1 * step) + double ( i * step)) ;
176+ writePtr[ index2 + i] = offset + (double ) i * step;
171177 }
172178 }
173179
@@ -214,8 +220,69 @@ float DataQueue::writeChannel (const AudioBuffer<float>& buffer,
214220 return 1 .0f - (float ) m_fifos[destChannel]->getFreeSpace () / (float ) m_fifos[destChannel]->getTotalSize ();
215221}
216222
223+ float DataQueue::writeAllChannels (const AudioBuffer<float >& buffer,
224+ const Array<int >& srcChannels,
225+ int nSamples,
226+ int64 sampleNumber)
227+ {
228+ if (m_numChans == 0 || nSamples == 0 )
229+ return 0 .0f ;
230+
231+ // Get FIFO indices from first channel - all channels should be in sync
232+ int index1, size1, index2, size2;
233+ m_fifos[0 ]->prepareToWrite (nSamples, index1, size1, index2, size2);
234+
235+ if ((size1 + size2) < nSamples)
236+ {
237+ LOGE (__FUNCTION__, " Recording Data Queue Overflow: sz1: " , size1, " sz2: " , size2, " nSamples: " , nSamples);
238+ }
239+
240+ float maxUsage = 0 .0f ;
241+
242+ // Fill sample numbers once for channel 0
243+ fillSampleNumbers (0 , index1, size1, sampleNumber);
244+ if (size2 > 0 )
245+ {
246+ fillSampleNumbers (0 , index2, size2, sampleNumber + size1);
247+ }
248+
249+ // Batch copy and update all channels
250+ for (int destChannel = 0 ; destChannel < m_numChans; ++destChannel)
251+ {
252+ int srcChannel = srcChannels[destChannel];
253+
254+ // Copy first segment
255+ m_buffer.copyFrom (destChannel, index1, buffer, srcChannel, 0 , size1);
256+
257+ // Copy second segment (wrap-around) if present
258+ if (size2 > 0 )
259+ {
260+ m_buffer.copyFrom (destChannel, index2, buffer, srcChannel, size1, size2);
261+ }
262+
263+ // Copy sample numbers from channel 0 (faster than calling fillSampleNumbers for each)
264+ if (destChannel > 0 )
265+ {
266+ std::memcpy (m_sampleNumbers[destChannel]->data (),
267+ m_sampleNumbers[0 ]->data (),
268+ m_numBlocks * sizeof (int64));
269+ }
270+
271+ // Update FIFO state - need to call prepareToWrite for channels > 0
272+ if (destChannel > 0 )
273+ {
274+ int d1, d2, d3, d4;
275+ m_fifos[destChannel]->prepareToWrite (nSamples, d1, d2, d3, d4);
276+ }
277+ m_fifos[destChannel]->finishedWrite (size1 + size2);
278+ }
279+
280+ // Return usage from last channel (all should be the same)
281+ return 1 .0f - (float ) m_fifos[m_numChans - 1 ]->getFreeSpace () / (float ) m_fifos[m_numChans - 1 ]->getTotalSize ();
282+ }
283+
217284/*
218- We could copy the internal circular buffer to an external one, as DataBuffer does. This class
285+ We could copy the internal circular buffer to an external one, as DataBuffer does.
219286is, however, intended for disk writing, which is one of the most CPU-critical systems. Just
220287allowing the record subsystem to access the internal buffer is way faster, although it has to be
221288done with special care and manually finish the read process.
0 commit comments