12namespace tracktion {
inline namespace engine
27 auto ratio = r->sampleRate / targetSampleRate;
28 auto targetLength = (
int) (r->lengthInSamples / ratio);
36 resamplerSource.setResamplingRatio (ratio);
37 resamplerSource.prepareToPlay (targetLength, targetSampleRate);
43 resamplerSource.getNextAudioBlock (info);
52 file.loadFileAsData (mb);
54 return loadWavDataIntoMemory (mb.
getData(), mb.
getSize(), targetSampleRate);
61 : edit (e), midi (isMidi)
68 if (sampleRate != newSampleRate)
70 sampleRate = newSampleRate;
77 bigClickMidiNote = Click::getMidiClickNote (edit.
engine,
true);
78 littleClickMidiNote = Click::getMidiClickNote (edit.
engine,
false);
86 if (file.existsAsFile())
87 bigClick = loadWavDataIntoMemory (file, sampleRate);
90 bigClick = loadWavDataIntoMemory (TracktionBinaryData::bigclick_wav, TracktionBinaryData::bigclick_wavSize, sampleRate);
97 if (file.existsAsFile())
98 littleClick = loadWavDataIntoMemory (file, sampleRate);
101 littleClick = loadWavDataIntoMemory (TracktionBinaryData::littleclick_wav, TracktionBinaryData::littleclick_wavSize, sampleRate);
105 tempoPosition.
set (startTime);
113 bool isFirstBeatOfBar =
false;
119 int beat =
static_cast<int> (
std::floor (beats));
120 const auto beatTime = sequence.toTime (BeatPosition::fromBeats (beat));
123 return { beatTime, isFirstBeatOfBar };
131 if (isMutedAtTime (editTime.getEnd()))
136 tempoPosition.
set (editTime.getStart());
137 auto beatInfo = getBeatInfo (sequence, tempoPosition);
141 if (bufferForMidiMessages ==
nullptr)
145 auto t = beatInfo.time;
147 while (t < editTime.getEnd())
149 auto note = (emphasis && beatInfo.isFirstBeatOfBar) ? bigClickMidiNote
150 : littleClickMidiNote;
152 if (t >= editTime.getStart())
154 (t - editTime.getStart()).inSeconds(),
155 MidiMessageArray::notMPE);
157 tempoPosition.
add (1_bd);
158 beatInfo = getBeatInfo (sequence, tempoPosition);
164 if (destBuffer ==
nullptr)
169 auto num =
std::min (samplesRemaining(),
int (destBuffer->getNumFrames()));
170 auto dstView = destBuffer->getFrameRange ({ 0, (choc::buffer::FrameCount) num });
175 auto t = beatInfo.time;
177 while (t < editTime.getEnd())
179 auto b = (emphasis && beatInfo.isFirstBeatOfBar) ? &bigClick : &littleClick;
181 if (b->getNumSamples() > 0 && t >= editTime.getStart() && ! isMutedAtTime (t))
183 const auto clickStartTime = t - editTime.getStart();
184 const auto clickStartOffset =
static_cast<int> (toSamples (clickStartTime, sampleRate));
189 auto num =
std::min (samplesRemaining(),
int (destBuffer->getNumFrames()) -
int (clickStartOffset));
190 auto dstView = destBuffer->getFrameRange ({ choc::buffer::FrameCount (clickStartOffset), choc::buffer::FrameCount (clickStartOffset + num) });
195 tempoPosition.
add (1_bd);
196 beatInfo = getBeatInfo (sequence, tempoPosition);
202bool ClickGenerator::isMutedAtTime (
TimePosition time)
const
207 if (! range.isEmpty() && time < range.getStart())
214 return ! range.contains (time);
216 return ! clickEnabled;
219bool ClickGenerator::isPlaying()
221 return currentSample !=
nullptr && samplePos >= 0;
230int ClickGenerator::samplesRemaining()
235void ClickGenerator::render (choc::buffer::ChannelArrayView<float>& view)
237 auto todo = view.getNumFrames();
240 copyRemappingChannels (view,
toBufferView (*currentSample).getFrameRange ({ choc::buffer::FrameCount (samplePos), choc::buffer::FrameCount (samplePos) + todo }));
241 applyGain (view, gain);
243 samplePos +=
static_cast<int> (todo);
248void ClickGenerator::reset()
250 currentSample =
nullptr;
257 : edit (e), playHead (playHeadToUse),
258 clickGenerator (edit, isMidi),
259 numChannels (numAudioChannels), generateMidi (isMidi)
271 props.hasAudio = ! generateMidi;
272 props.hasMidi = generateMidi;
273 props.numberOfChannels = numChannels;
281 sampleRate = info.sampleRate;
283 TimePosition::fromSamples (playHead.
getPosition(), sampleRate));
293 SCOPED_REALTIME_CHECK
299 const auto editTime = tracktion::timeRangeFromSamples (splitTimelinePosition.timelineRange1, sampleRate);
300 clickGenerator.
processBlock (&pc.buffers.audio, &pc.buffers.midi, editTime);
307 int getMidiClickNote (
Engine& e,
bool big)
314 n = storage.getProperty (SettingID::clickTrackMidiNoteBig, 37);
316 if (n < 0 || n > 127)
321 n = storage.
getProperty (SettingID::clickTrackMidiNoteLittle, 76);
323 if (n < 0 || n > 127)
332 return e.getPropertyStorage().getProperty (big ? SettingID::clickTrackSampleBig
336 void setMidiClickNote (
Engine& e,
bool big,
int noteNum)
338 auto& storage = e.getPropertyStorage();
341 storage.setProperty (SettingID::clickTrackMidiNoteBig,
juce::String (noteNum));
343 storage.setProperty (SettingID::clickTrackMidiNoteLittle,
juce::String (noteNum));
350 auto& storage = e.getPropertyStorage();
353 storage.setProperty (SettingID::clickTrackSampleBig, filename);
355 storage.setProperty (SettingID::clickTrackSampleSmall, filename);
int getNumSamples() const noexcept
Type get() const noexcept
void * getData() noexcept
size_t getSize() const noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
var getProperty(const Identifier &propertyName, const var &defaultReturnValue) const
void processBlock(choc::buffer::ChannelArrayView< float > *, MidiMessageArray *, TimeRange)
Adds clicks to a block of audio and MIDI for a given time range.
void prepareToPlay(double sampleRate, TimePosition startTime)
Prepares a ClickGenerator to be played.
ClickGenerator(Edit &, bool isMidi)
Creates a click generator for an Edit.
std::vector< Node * > getDirectInputNodes() override
Should return all the inputs directly feeding in to this node.
tracktion::graph::NodeProperties getNodeProperties() override
Should return the properties of the node.
bool isReadyToProcess() override
Should return true when this node is ready to be processed.
void process(ProcessContext &) override
Called when the node is to be processed.
void prepareToPlay(const tracktion::graph::PlaybackInitialisationInfo &) override
Called once before playback begins for each node.
The Tracktion Edit class!
TimeRange getClickTrackRange() const noexcept
Returns the range the click track will be audible within.
float getClickTrackVolume() const noexcept
Returns the click track volume.
TransportControl & getTransport() const noexcept
Returns the TransportControl which is used to stop/stop/position playback and recording.
juce::CachedValue< bool > clickTrackRecordingOnly
Whether the click track should be audible only when recording.
juce::CachedValue< bool > clickTrackEmphasiseBars
Whether the click track should emphasise bars.
juce::CachedValue< bool > clickTrackEnabled
Whether the click track is enabled.
ProjectItemID getProjectItemID() const noexcept
Returns the ProjectItemID of the Edit.
Engine & engine
A reference to the Engine.
The Engine is the central class for all tracktion sessions.
PropertyStorage & getPropertyStorage() const
Returns the PropertyStorage user settings customisable XML file.
int64_t getRawID() const noexcept
Returns a combined ID as an integer, useful for creating hashes.
EditPlaybackContext * getCurrentPlaybackContext() const
Returns the active EditPlaybackContext if this Edit is attached to the DeviceManager for playback.
bool isRecording() const
Returns true if recording is in progress.
static std::vector< std::unique_ptr< ScopedContextAllocator > > restartAllTransports(Engine &, bool clearDevices)
Restarts all TransportControl[s] in the Edit.
Struct to describe a single iteration of a process call.
Converts a monotonically increasing reference range in to a timeline range.
int64_t getPosition() const
Returns the current timeline position.
bool isUserDragging() const
Returns true if the user is dragging.
bool isPlaying() const noexcept
Returns true is the play head is currently playing.
choc::buffer::BufferView< SampleType, choc::buffer::SeparateChannelLayout > toBufferView(juce::AudioBuffer< SampleType > &buffer)
Converts a juce::AudioBuffer<SampleType> to a choc::buffer::BufferView.
SettingID
A list of settings the engine will get and set.
SplitTimelineRange referenceSampleRangeToSplitTimelineRange(const PlayHead &playHead, juce::Range< int64_t > referenceSampleRange)
Converts a reference sample range to a TimelinePositionWindow which could have two time ranges if the...
AudioBuffer< float > * buffer
constexpr double inBeats() const
Returns the position as a number of beats.
Represents a position in real-life time.
int getWholeBeats() const
Returns the number of whole beats.
A Sequence::Position is an iterator through a Sequence.
TimePosition add(TimeDuration)
Increments the position by a time duration.
BeatPosition getBeats() const
Returns the current beats of the Position.
void set(TimePosition)
Sets the Position to a new time.
BarsAndBeats getBarsBeats() const
Returns the current bars and beats of the Position.
Holds some really basic properties of a node.
Passed into Nodes when they are being initialised, to give them useful contextual information that th...