Zrythm v2.0.0-alpha.1
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
timeline_data_cache.h
1// SPDX-FileCopyrightText: © 2025 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3
4#pragma once
5
6#include <span>
7
8#include "dsp/curve.h"
9#include "dsp/midi_event.h"
10#include "utils/units.h"
11
12#include <QObject>
13
14#include <juce_audio_basics/juce_audio_basics.h>
15
16namespace zrythm::dsp
17{
18
26class TimelineDataCache : public QObject
27{
28 Q_OBJECT
29
30public:
31 using IntervalType = std::pair<units::sample_t, units::sample_t>;
32
33 explicit TimelineDataCache (QObject * parent = nullptr) : QObject (parent) { }
34
35 ~TimelineDataCache () override;
36
40 void clear ()
41 {
42 clear_impl ();
43 Q_EMIT cachedRangesChanged (compute_cached_sample_ranges ());
44 }
45
58 virtual void remove_sequences_matching_interval (IntervalType interval) = 0;
59
68 {
69 finalize_changes_impl ();
70 Q_EMIT cachedRangesChanged (compute_cached_sample_ranges ());
71 }
72
78 virtual bool has_content () const = 0;
79
87 Q_SIGNAL void cachedRangesChanged (std::vector<IntervalType> ranges) const;
88
89protected:
96 static void validate_interval (IntervalType interval)
97 {
98 if (interval.first >= interval.second)
99 {
100 throw std::invalid_argument (
101 "Interval start must be strictly less than end");
102 }
103 }
104
109 static bool intervals_overlap (IntervalType a, IntervalType b) noexcept
110 {
111 return a.second > b.first && a.first < b.second;
112 }
113
114private:
115 virtual void clear_impl () = 0;
116 virtual void finalize_changes_impl () = 0;
117
121 virtual std::vector<IntervalType> compute_cached_sample_ranges () const = 0;
122};
123
130class MidiTimelineDataCache : public TimelineDataCache
131{
132public:
133 explicit MidiTimelineDataCache (QObject * parent = nullptr)
134 : TimelineDataCache (parent)
135 {
136 }
137
145 IntervalType interval,
146 std::span<const SampleBasedMidiEvent> events);
147
153 std::span<const SampleBasedMidiEvent> midi_events () const
154 {
155 return merged_midi_events_;
156 }
157
158 void remove_sequences_matching_interval (IntervalType interval) override;
159 bool has_content () const override;
160
161private:
162 void clear_impl () override;
163 void finalize_changes_impl () override;
164 std::vector<IntervalType> compute_cached_sample_ranges () const override;
171 std::map<IntervalType, std::vector<SampleBasedMidiEvent>> midi_sequences_;
172
179 std::vector<SampleBasedMidiEvent> merged_midi_events_;
180};
181
188class AudioTimelineDataCache : public TimelineDataCache
189{
190public:
191 explicit AudioTimelineDataCache (QObject * parent = nullptr)
192 : TimelineDataCache (parent)
193 {
194 }
195
204 {
206 juce::AudioSampleBuffer audio_buffer;
207
209 units::sample_t start_sample;
210
212 units::sample_t end_sample;
213 };
214
222 IntervalType interval,
223 const juce::AudioSampleBuffer &audio_buffer);
224
230 std::span<const AudioClipEntry> audio_clips () const { return audio_clips_; }
231
232 void remove_sequences_matching_interval (IntervalType interval) override;
233 bool has_content () const override;
234
235private:
236 void clear_impl () override;
237 void finalize_changes_impl () override;
238 std::vector<IntervalType> compute_cached_sample_ranges () const override;
245 std::vector<AudioClipEntry> audio_clips_;
246};
247
254class AutomationTimelineDataCache : public TimelineDataCache
255{
256public:
257 explicit AutomationTimelineDataCache (QObject * parent = nullptr)
258 : TimelineDataCache (parent)
259 {
260 }
261
270 {
272 units::sample_t start_sample;
273 units::sample_t end_sample;
274
283 float ratio_end;
284
287 float point_b_value;
288
291 float curve_curviness;
292 };
293
302 {
304 std::vector<CachedAutomationSegment> segments;
305
307 units::sample_t start_sample;
308
310 units::sample_t end_sample;
311 };
312
319 void
320 add_automation_sequence (IntervalType interval, AutomationCacheEntry &&entry);
321
327 std::span<const AutomationCacheEntry> automation_sequences () const
328 {
329 return automation_sequences_;
330 }
331
332 void remove_sequences_matching_interval (IntervalType interval) override;
333 bool has_content () const override;
334
335private:
336 void clear_impl () override;
337 void finalize_changes_impl () override;
338 std::vector<IntervalType> compute_cached_sample_ranges () const override;
345 std::vector<AutomationCacheEntry> automation_sequences_;
346};
347
348} // namespace zrythm::dsp
349
350Q_DECLARE_METATYPE (std::vector<zrythm::dsp::TimelineDataCache::IntervalType>)
std::span< const AudioClipEntry > audio_clips() const
Gets the cached audio clips.
void add_audio_clip(IntervalType interval, const juce::AudioSampleBuffer &audio_buffer)
Adds an audio clip for the given interval.
void remove_sequences_matching_interval(IntervalType interval) override
Removes cached data for intervals that truly overlap with the given interval.
bool has_content() const override
Checks if the cache has any content.
void remove_sequences_matching_interval(IntervalType interval) override
Removes cached data for intervals that truly overlap with the given interval.
std::span< const AutomationCacheEntry > automation_sequences() const
Gets the cached automation sequences.
bool has_content() const override
Checks if the cache has any content.
void add_automation_sequence(IntervalType interval, AutomationCacheEntry &&entry)
Adds an automation cache entry for the given interval.
Algorithm
The algorithm to use for curves.
Definition curve.h:33
void add_midi_sequence(IntervalType interval, std::span< const SampleBasedMidiEvent > events)
Adds a MIDI sequence for the given interval.
std::span< const SampleBasedMidiEvent > midi_events() const
Gets the cached MIDI events.
void remove_sequences_matching_interval(IntervalType interval) override
Removes cached data for intervals that truly overlap with the given interval.
bool has_content() const override
Checks if the cache has any content.
void finalize_changes()
Finalizes changes, prepares cached data for access, and emits cachedRangesChanged.
virtual bool has_content() const =0
Checks if the cache has any content.
Q_SIGNAL void cachedRangesChanged(std::vector< IntervalType > ranges) const
Emitted when the cache content changes (after finalize_changes or clear).
static bool intervals_overlap(IntervalType a, IntervalType b) noexcept
Returns true if two intervals truly overlap (adjacent intervals do not count).
virtual void remove_sequences_matching_interval(IntervalType interval)=0
Removes cached data for intervals that truly overlap with the given interval.
void clear()
Clears all cached data and emits cachedRangesChanged.
static void validate_interval(IntervalType interval)
Validates that the given interval has a positive width (start < end).
units::sample_t start_sample
Start position in samples.
units::sample_t end_sample
End position in samples.
juce::AudioSampleBuffer audio_buffer
Copy of the audio sample buffer.
std::vector< CachedAutomationSegment > segments
Sorted constant-tempo segments covering the clip's span.
A constant-tempo sub-segment of an automation curve.
units::sample_t start_sample
Absolute sample positions (for binary search).
dsp::CurveOptions::Algorithm curve_algo
Curve parameters from the automation point that drives this segment.
float ratio_start
Position within the full automation point pair (0 = first point, 1 = second point).
float point_a_value
Values of the two automation points bracketing this segment.