Zrythm v2.0.0-DEV
a highly automated and intuitive digital audio workstation
Loading...
Searching...
No Matches
graph_scheduler.h
1// SPDX-FileCopyrightText: © 2019-2021, 2024 Alexandros Theodotou <alex@zrythm.org>
2// SPDX-License-Identifier: LicenseRef-ZrythmLicense
3/*
4 * This file incorporates work covered by the following copyright and
5 * permission notice:
6 *
7 * ---
8 *
9 * Copyright (C) 2017, 2019 Robin Gareus <robin@gareus.org>
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 *
24 * ---
25 */
26
27#pragma once
28
29#include "dsp/graph_node.h"
30#include "utils/mpmc_queue.h"
31#include "utils/rt_thread_id.h"
32
33#include <juce_audio_basics/juce_audio_basics.h>
34#include <juce_core/juce_core.h>
35#include <moodycamel/lightweightsemaphore.h>
36
37namespace zrythm::dsp::graph
38{
39
40class GraphThread;
41
59{
60 friend class GraphThread;
61 static constexpr int MAX_GRAPH_THREADS = 128;
62
63public:
67 using RunOnMainThreadFunc = std::function<void (std::function<void ()>)>;
68
79 RunOnMainThreadFunc run_on_main_thread_func,
80 units::sample_rate_t sample_rate,
81 units::sample_u32_t max_block_length,
82 bool realtime_threads = true,
83 std::optional<juce::AudioWorkgroup> thread_workgroup = std::nullopt);
84 // copy/move don't make sense here
85 GraphScheduler (const GraphScheduler &) = delete;
86 GraphScheduler &operator= (const GraphScheduler &) = delete;
87 GraphScheduler (GraphScheduler &&) = delete;
88 GraphScheduler &operator= (GraphScheduler &&) = delete;
90
107 GraphNodeCollection &&nodes,
108 units::sample_rate_t sample_rate,
109 units::sample_u32_t max_block_length);
110
119 void start_threads (std::optional<int> num_threads = std::nullopt);
120
125
126 auto &get_nodes () { return graph_nodes_; }
127
138 units::sample_u64_t remaining_preroll_frames,
139 const dsp::ITransport &transport,
140 const dsp::TempoMap &tempo_map);
141
145 bool contains_thread (RTThreadId::IdType thread_id);
146
147 auto get_time_nfo () const { return time_nfo_; }
148 auto get_remaining_preroll_frames () const
149 {
150 return remaining_preroll_frames_;
151 }
152
160 {
161 assert (current_transport_.has_value ());
162 return current_transport_->get ();
163 }
164
172 {
173 assert (current_tempo_map_.has_value ());
174 return current_tempo_map_->get ();
175 }
176
177private:
181 [[gnu::hot]] void trigger_node (GraphNode &node);
182
187 void prepare_nodes_for_processing ();
188
193 void release_node_resources ();
194
195private:
196 struct ThreadSet;
197 std::unique_ptr<ThreadSet> thread_set_;
198 [[nodiscard]] size_t num_threads () const noexcept [[clang::nonblocking]];
199
203 dsp::graph::EngineProcessTimeInfo time_nfo_;
204
208 std::optional<std::reference_wrapper<const dsp::ITransport>> current_transport_;
209
213 std::optional<std::reference_wrapper<const dsp::TempoMap>> current_tempo_map_;
214
218 units::sample_u64_t remaining_preroll_frames_;
219
221 moodycamel::LightweightSemaphore callback_start_sem_{ 0 };
222 moodycamel::LightweightSemaphore callback_done_sem_{ 0 };
223
225 std::atomic<int> idle_thread_cnt_ = 0;
226
228 // This is not a std::counting_semaphore due to issues on MSVC/Windows.
229 moodycamel::LightweightSemaphore trigger_sem_{ 0 };
230
232 MPMCQueue<GraphNode *> trigger_queue_;
233
237 GraphNodeCollection graph_nodes_;
238
240 std::atomic<int> terminal_refcnt_ = 0;
241
246 std::optional<juce::Thread::RealtimeOptions> realtime_thread_options_;
247
249 std::optional<juce::AudioWorkgroup> thread_workgroup_;
250
251 units::sample_rate_t sample_rate_;
252 units::sample_u32_t max_block_length_;
253
254 RunOnMainThreadFunc run_on_main_thread_func_;
255};
256
257} // namespace zrythm::dsp::graph
Multiple Producer Multiple Consumer lock-free queue.
Definition mpmc_queue.h:65
Interface for transport.
Definition itransport.h:16
Manages the collection of graph nodes.
Definition graph_node.h:333
Represents a node in a DSP graph.
Definition graph_node.h:160
void rechain_from_node_collection(GraphNodeCollection &&nodes, units::sample_rate_t sample_rate, units::sample_u32_t max_block_length)
Steals the nodes from the given collection and prepares for processing.
bool contains_thread(RTThreadId::IdType thread_id)
Returns whether the given thread is one of the graph threads.
GraphScheduler(RunOnMainThreadFunc run_on_main_thread_func, units::sample_rate_t sample_rate, units::sample_u32_t max_block_length, bool realtime_threads=true, std::optional< juce::AudioWorkgroup > thread_workgroup=std::nullopt)
Construct a new Graph Scheduler.
auto & get_transport_for_this_cycle() const
Returns the ITransport instance to be used in this cycle.
void run_cycle(dsp::graph::EngineProcessTimeInfo time_nfo, units::sample_u64_t remaining_preroll_frames, const dsp::ITransport &transport, const dsp::TempoMap &tempo_map)
To be called repeatedly by a system audio callback thread.
void terminate_threads()
Tell all threads to terminate.
void start_threads(std::optional< int > num_threads=std::nullopt)
Starts the threads that will be processing the graph.
auto & get_tempo_map_for_this_cycle() const
Returns the TempoMap instance to be used in this cycle.
std::function< void(std::function< void()>)> RunOnMainThreadFunc
Request for a function to run on the main thread (blocking).
Processing graph thread.
Common struct to pass around during processing to avoid repeating the data in function arguments.
Definition graph_node.h:51