66 props.hasAudio =
false;
67 props.hasMidi =
false;
68 props.numberOfChannels = 0;
70 for (
auto& node : inputs)
72 auto nodeProps = node->getNodeProperties();
73 props.hasAudio = props.hasAudio || nodeProps.hasAudio;
74 props.hasMidi = props.hasMidi || nodeProps.hasMidi;
75 props.numberOfChannels =
std::max (props.numberOfChannels, nodeProps.numberOfChannels);
76 props.latencyNumSamples =
std::max (props.latencyNumSamples, nodeProps.latencyNumSamples);
77 hash_combine (props.nodeID, nodeProps.nodeID);
83 const auto hashSalt = 8507534508343435306;
84 hash_combine (props.nodeID, hashSalt);
85 hash_combine (props.nodeID, containerClipID.getRawID());
127 const auto dynamicOffset = *dynamicOffsetBeats;
128 const auto sectionEditBeatRange = getEditBeatRange();
129 const auto sectionEditSampleRange = getTimelineSampleRange();
131 if (sectionEditBeatRange.getEnd() <= (clipPosition.getStart() + dynamicOffset)
132 || sectionEditBeatRange.getStart() >= (clipPosition.getEnd() + dynamicOffset))
135 const auto editStartBeatOfLocalTimeline = clipPosition.getStart() + dynamicOffset - getOffset();
137 auto section1 = sectionEditBeatRange;
140 if (! loopRange.isEmpty())
142 const auto playbackStartBeatRelativeToClip = sectionEditBeatRange.getStart() - editStartBeatOfLocalTimeline;
143 const auto loopIteration = loopRange.isEmpty() ? 0
144 :
static_cast<int> (playbackStartBeatRelativeToClip.inBeats() / loopRange.getLength().inBeats());
145 const auto loopEndBeat = editStartBeatOfLocalTimeline + (loopRange.getLength() * (loopIteration + 1));
147 if (loopEndBeat > sectionEditBeatRange.getStart()
148 && loopEndBeat < sectionEditBeatRange.getEnd())
150 section1 = sectionEditBeatRange.withEnd (loopEndBeat);
151 section2 = sectionEditBeatRange.withStart (section1.getEnd());
154 sectionEditBeatRange.getLength().inBeats()));
172 processSection (pc, section1);
176 assert (section2->getLength() > 0_bd);
178 sectionEditBeatRange.getEnd().inBeats());
180 auto processSubSection = [
this, &pc, &blockRangeBeats] (
auto section)
184 const auto startFrame = (choc::buffer::FrameCount)
std::llround (proportion.getStart() * pc.numSamples);
185 const auto endFrame = (choc::buffer::FrameCount)
std::llround (proportion.getEnd() * pc.numSamples);
187 const auto sectionNumFrames = endFrame - startFrame;
189 if (sectionNumFrames == 0)
192 const auto numRefSamples = pc.referenceSampleRange.
getLength();
196 const juce::Range subSectionReferenceSampleRange (startRefSample, endRefSample);
198 for (
auto& node : orderedNodes)
199 node->prepareForNextBlock (subSectionReferenceSampleRange);
201 auto sectionBufferView = pc.buffers.audio.getFrameRange ({ startFrame, endFrame });
203 sectionNumFrames, subSectionReferenceSampleRange,
204 { sectionBufferView, pc.buffers.midi }
206 processSection (subSection, section);
209 processSubSection (section1);
210 processSubSection (*section2);
215 const TimeRange clipTimeRange (tempoPosition.set (clipPosition.getStart() + dynamicOffset),
216 tempoPosition.set (clipPosition.getEnd() + dynamicOffset));
217 const auto editPositionInSamples = toSamples ({ clipTimeRange.getStart(), clipTimeRange.getEnd() }, getSampleRate());
219 const auto destBuffer = pc.buffers.audio;
220 auto numSamplesToClearAtStart =
std::min (editPositionInSamples.getStart() - sectionEditSampleRange.getStart(), (SampleCount) destBuffer.getNumFrames());
221 auto numSamplesToClearAtEnd =
std::min (sectionEditSampleRange.getEnd() - editPositionInSamples.getEnd(), (SampleCount) destBuffer.getNumFrames());
223 if (numSamplesToClearAtStart > 0)
224 destBuffer.getStart ((choc::buffer::FrameCount) numSamplesToClearAtStart).clear();
226 if (numSamplesToClearAtEnd > 0)
227 destBuffer.getEnd ((choc::buffer::FrameCount) numSamplesToClearAtEnd).clear();
Struct to describe a single iteration of a process call.