6#include "dsp/graph_node.h"
7#include "dsp/itransport.h"
8#include "dsp/midi_event_buffer.h"
9#include "dsp/timeline_data_cache.h"
10#include "structure/arrangement/region_renderer.h"
11#include "utils/expandable_tick_range.h"
14#include <farbot/RealtimeObject.hpp>
16namespace zrythm::structure::arrangement
26class TimelineDataProvider :
public QObject
31 using IntervalType = std::pair<units::sample_t, units::sample_t>;
33 explicit TimelineDataProvider (QObject * parent =
nullptr) : QObject (parent)
37 ~TimelineDataProvider ()
override;
51 template <RegionObject RegionType>
54 const dsp::TempoMap &tempo_map,
59 const auto sample_interval = [&affected_range, &tempo_map] ()
60 -> std::pair<units::sample_t, units::sample_t> {
63 const auto tick_range = affected_range.
range ().value ();
64 return std::make_pair (
65 tempo_map.tick_to_samples_rounded (units::ticks (tick_range.first)),
66 tempo_map.tick_to_samples_rounded (units::ticks (tick_range.second)));
68 return std::make_pair (
69 units::samples (
static_cast<int64_t
> (0)),
70 units::samples (std::numeric_limits<int64_t>::max ()));
78 self.get_base_cache ()->clear ();
82 self.get_base_cache ()->remove_sequences_matching_interval (
86 const auto regions_inside_interval_filter_func =
87 [&affected_range, sample_interval] (
const auto ®ion) {
91 return region->bounds ()->is_hit_by_range (sample_interval);
94 const auto cache_region = [&] (
const auto * r) {
96 if (r->mute ()->muted ())
100 std::is_same_v<RegionType, arrangement::MidiRegion>
101 || std::is_same_v<RegionType, arrangement::ChordRegion>)
103 self.cache_midi_region (*r, tempo_map);
105 else if constexpr (std::is_same_v<RegionType, arrangement::AudioRegion>)
107 self.cache_audio_region (*r);
110 std::is_same_v<RegionType, arrangement::AutomationRegion>)
112 self.cache_automation_region (*r, tempo_map);
117 std::ranges::for_each (
118 std::views::filter (regions, regions_inside_interval_filter_func),
122 self.get_base_cache ()->finalize_changes ();
125 virtual void clear_all_caches () = 0;
127 remove_sequences_matching_interval_from_all_caches (IntervalType interval) = 0;
135 dsp::ITransport::PlayState::Paused
148class MidiTimelineDataProvider :
public TimelineDataProvider
150 friend class TimelineDataProvider;
153 explicit MidiTimelineDataProvider (QObject * parent =
nullptr);
157 return midi_cache_.get ();
165 dsp::ITransport::PlayState transport_state,
168 void clear_all_caches ()
override;
169 void remove_sequences_matching_interval_from_all_caches (
170 IntervalType interval)
override;
172 std::span<const dsp::SampleBasedMidiEvent> midi_events ()
const;
185 const dsp::TempoMap &tempo_map,
190 tempo_map, midi_regions, affected_range);
191 set_midi_events (midi_cache_->midi_events ());
205 const dsp::TempoMap &tempo_map,
210 tempo_map, chord_regions, affected_range);
211 set_midi_events (midi_cache_->midi_events ());
217 return midi_cache_.get ();
224 template <
typename M
idiRegionType>
226 cache_midi_region (
const MidiRegionType ®ion,
const dsp::TempoMap &tempo_map)
229 juce::MidiMessageSequence region_seq;
233 region_seq.addTimeToMessages (region.position ()->ticks ());
236 std::vector<dsp::SampleBasedMidiEvent> native_events;
237 native_events.reserve (region_seq.getNumEvents ());
238 for (
const auto &event : region_seq)
240 const auto sample_time = tempo_map.tick_to_samples_rounded (
241 units::ticks (event->message.getTimeStamp ()));
242 const auto * raw =
event->message.getRawData ();
243 const auto raw_size =
244 static_cast<size_t> (
event->message.getRawDataSize ());
245 native_events.push_back (
247 std::span<const midi_byte_t>{ raw, raw_size }, sample_time));
251 midi_cache_->add_midi_sequence (
253 units::samples (region.position ()->samples ()),
254 region.bounds ()->get_end_position_samples (
true)),
263 void set_midi_events (std::span<const dsp::SampleBasedMidiEvent> events);
265 utils::QObjectUniquePtr<dsp::MidiTimelineDataCache> midi_cache_;
267 farbot::RealtimeObject<
268 std::vector<dsp::SampleBasedMidiEvent>,
269 farbot::RealtimeObjectOptions::nonRealtimeMutatable>
270 active_midi_playback_sequence_;
279class AudioTimelineDataProvider :
public TimelineDataProvider
281 friend class TimelineDataProvider;
284 explicit AudioTimelineDataProvider (QObject * parent =
nullptr);
288 return audio_cache_.get ();
296 dsp::ITransport::PlayState transport_state,
297 std::span<float> output_left,
298 std::span<float> output_right)
noexcept [[clang::nonblocking]];
300 void clear_all_caches ()
override;
301 void remove_sequences_matching_interval_from_all_caches (
302 IntervalType interval)
override;
304 std::span<const dsp::AudioTimelineDataCache::AudioRegionEntry>
305 audio_regions ()
const;
318 const dsp::TempoMap &tempo_map,
323 tempo_map, audio_regions, affected_range);
324 set_audio_regions (audio_cache_->audio_regions ());
330 return audio_cache_.get ();
344 void set_audio_regions (
345 std::span<const dsp::AudioTimelineDataCache::AudioRegionEntry> regions);
349 farbot::RealtimeObject<
350 std::vector<dsp::AudioTimelineDataCache::AudioRegionEntry>,
351 farbot::RealtimeObjectOptions::nonRealtimeMutatable>
352 active_audio_regions_;
361class AutomationTimelineDataProvider :
public TimelineDataProvider
363 friend class TimelineDataProvider;
366 explicit AutomationTimelineDataProvider (QObject * parent =
nullptr);
370 return automation_cache_.get ();
378 dsp::ITransport::PlayState transport_state,
379 std::span<float> output_values)
noexcept [[clang::nonblocking]];
389 [[clang::nonblocking]];
391 void clear_all_caches ()
override;
392 void remove_sequences_matching_interval_from_all_caches (
393 IntervalType interval)
override;
395 std::span<const dsp::AutomationTimelineDataCache::AutomationCacheEntry>
396 automation_sequences ()
const;
409 const dsp::TempoMap &tempo_map,
414 tempo_map, automation_regions, affected_range);
415 set_automation_sequences (automation_cache_->automation_sequences ());
421 return automation_cache_.get ();
428 void cache_automation_region (
430 const dsp::TempoMap &tempo_map);
437 void set_automation_sequences (
438 std::span<const dsp::AutomationTimelineDataCache::AutomationCacheEntry>
443 farbot::RealtimeObject<
444 std::vector<dsp::AutomationTimelineDataCache::AutomationCacheEntry>,
445 farbot::RealtimeObjectOptions::nonRealtimeMutatable>
446 active_automation_sequences_;
Packed contiguous buffer for RT MIDI events.
Base class for timeline data caches.
A region for playing back audio samples.
void process_audio_events(const dsp::graph::ProcessBlockInfo &time_nfo, dsp::ITransport::PlayState transport_state, std::span< float > output_left, std::span< float > output_right) noexcept
Process audio events for the given time range.
void generate_audio_events(const dsp::TempoMap &tempo_map, utils::RangeOf< const arrangement::AudioRegion * > auto audio_regions, utils::ExpandableTickRange affected_range)
Generate the audio event sequence to be used during realtime processing.
Represents an automation region, which contains a collection of automation points.
std::optional< float > get_automation_value_rt(units::sample_t sample_position) noexcept
Get the automation value for a specific sample position.
void process_automation_events(const dsp::graph::ProcessBlockInfo &time_nfo, dsp::ITransport::PlayState transport_state, std::span< float > output_values) noexcept
Process automation events for the given time range.
void generate_automation_events(const dsp::TempoMap &tempo_map, utils::RangeOf< const arrangement::AutomationRegion * > auto automation_regions, utils::ExpandableTickRange affected_range)
Generate the automation event sequence to be used during realtime processing.
void process_midi_events(const dsp::graph::ProcessBlockInfo &time_nfo, dsp::ITransport::PlayState transport_state, dsp::MidiEventBuffer &output_buffer) noexcept
Process MIDI events for the given time range.
void generate_midi_events(const dsp::TempoMap &tempo_map, utils::RangeOf< const arrangement::ChordRegion * > auto chord_regions, utils::ExpandableTickRange affected_range)
Generate the MIDI event sequence to be used during realtime processing.
void generate_midi_events(const dsp::TempoMap &tempo_map, utils::RangeOf< const arrangement::MidiRegion * > auto midi_regions, utils::ExpandableTickRange affected_range)
Generate the MIDI event sequence to be used during realtime processing.
static void serialize_to_sequence(const MidiRegion ®ion, juce::MidiMessageSequence &events, std::optional< std::pair< double, double > > timeline_range_ticks=std::nullopt)
Serializes a MIDI region to a MIDI message sequence.
dsp::ITransport::PlayState last_seen_transport_state_
Last transport state we've seen.
void generate_events(this auto &self, const dsp::TempoMap &tempo_map, utils::RangeOf< const RegionType * > auto regions, utils::ExpandableTickRange affected_range)
Generate the event sequence to be used during realtime processing.
units::sample_t next_expected_transport_position_
Next expected transport position (for detecting jumps).
bool is_full_content() const
Returns whether the range is the full content (ie, there is no range).
auto range() const -> std::optional< std::pair< double, double > >
Returns the range, or nullopt if the full content is covered.
A unique pointer for QObject objects that also works with QObject-based ownership.
MidiEvent< TimeType > make_raw(std::span< const midi_byte_t > raw, TimeType time)
Creates a raw MIDI event from the given bytes.
Common struct to pass around during processing to avoid repeating the data in function arguments.