| 297 | } |
| 298 | |
| 299 | bool SampledAudioNode::renderSample(ContextRenderLock& r, Scheduled& schedule, size_t destinationSampleOffset, size_t frameSize) |
| 300 | { |
| 301 | std::shared_ptr<AudioBus> srcBus = m_sourceBus->valueBus(); |
| 302 | AudioBus* dstBus = output(0)->bus(r); |
| 303 | size_t dstChannelCount = dstBus->numberOfChannels(); |
| 304 | size_t srcChannelCount = srcBus->numberOfChannels(); |
| 305 | ASSERT(dstChannelCount == srcChannelCount); |
| 306 | |
| 307 | float* buffer = dstBus->channel(0)->mutableData(); |
| 308 | float rate = totalPitchRate(r); |
| 309 | if (fabsf(rate - 1.f) < 1e-3f) |
| 310 | { |
| 311 | // no pitch modification |
| 312 | int write_index = (int) destinationSampleOffset; |
| 313 | while (write_index < AudioNode::ProcessingSizeInFrames) |
| 314 | { |
| 315 | int count = AudioNode::ProcessingSizeInFrames - write_index; |
| 316 | int remainder = schedule.grain_end - schedule.cursor; |
| 317 | bool ending = remainder < count; |
| 318 | count = std::min(count, remainder); |
| 319 | |
| 320 | for (int i = 0; i < srcChannelCount; ++i) |
| 321 | { |
| 322 | float* buffer = dstBus->channel(i)->mutableData(); |
| 323 | VectorMath::vadd(srcBus->channel(i)->data() + schedule.cursor, 1, |
| 324 | buffer + write_index, 1, buffer + write_index, 1, count); |
| 325 | } |
| 326 | |
| 327 | schedule.cursor += count; |
| 328 | write_index += count; |
| 329 | |
| 330 | if (ending) |
| 331 | { |
| 332 | schedule.cursor = schedule.grain_start; // reset to start |
| 333 | |
| 334 | if (schedule.loopCount > 0) |
| 335 | schedule.loopCount--; |
| 336 | else if (schedule.loopCount < 0) |
| 337 | { |
| 338 | // infinite looping |
| 339 | } |
| 340 | else |
| 341 | { |
| 342 | schedule.loopCount = -3; // signal retirement of the schedule |
| 343 | break; // and stop the write loop |
| 344 | } |
| 345 | } |
| 346 | } |
| 347 | } |
| 348 | else |
| 349 | { |
| 350 | while (schedule.resampler.size() < srcBus->numberOfChannels()) |
| 351 | { |
| 352 | // samplers are expensive to allocate, so if there's one to recycle, use it |
| 353 | if (_resamplers.size()) |
| 354 | { |
| 355 | auto resampler = _resamplers.back(); |
| 356 | schedule.resampler.push_back(resampler); |
nothing calls this directly
no test coverage detected