6#include "zrythm-config.h"
8#include "dsp/midi_event.h"
9#include "dsp/port_identifier.h"
10#include "utils/concurrency.h"
12#include "utils/jack.h"
13#include "utils/monotonic_time_provider.h"
16# include "weakjack/weak_libjack.h"
75 PortDesignationProvider designation_provider) = 0;
82 virtual void clear_backend_buffer (dsp::PortType type,
nframes_t nframes) = 0;
84 virtual bool is_exposed ()
const = 0;
91 JackPortBackend (jack_client_t &client) : client_ (client) { }
92 ~JackPortBackend ()
override
104 const auto * in =
reinterpret_cast<const float *
> (
105 jack_port_get_buffer (port_, range.start_frame + range.nframes));
107 utils::float_ranges::add2 (
108 &buf[range.start_frame], &in[range.start_frame], range.nframes);
114 void copy_midi_event_vector_to_jack (
115 const dsp::MidiEventVector &src,
122 src.foreach_event ([&] (
const auto &ev) {
124 ev.time_ < local_start_frames
125 || ev.time_ >= local_start_frames + nframes)
130 std::array<jack_midi_data_t, 3> midi_data{};
132 midi_data.data (), ev.raw_buffer_sz_, (jack_midi_data_t *) buff);
133 jack_midi_event_write (
134 buff, ev.time_, midi_data.data (), ev.raw_buffer_sz_);
137 "wrote MIDI event to JACK MIDI out at %d", ev.time);
143 dsp::MidiEvents &midi_events,
145 MidiEventFilter filter_func)
override
147 const auto start_frame = range.start_frame;
148 const auto nframes = range.nframes;
149 void * port_buf = jack_port_get_buffer (port_, nframes);
150 uint32_t num_events = jack_midi_get_event_count (port_buf);
152 jack_midi_event_t jack_ev;
153 for (
unsigned i = 0; i < num_events; i++)
155 jack_midi_event_get (&jack_ev, port_buf, i);
157 if (jack_ev.time >= start_frame && jack_ev.time < start_frame + nframes)
161 && filter_func (dsp::MidiEvent{
162 jack_ev.buffer[0], jack_ev.buffer[1], jack_ev.buffer[2],
167 jack_ev.time, jack_ev.buffer, (
int) jack_ev.size);
178 void send_data (
const float * buf, FrameRange range)
override
180 if (jack_port_connected (port_) <= 0)
185 auto * out =
reinterpret_cast<float *
> (
186 jack_port_get_buffer (port_, range.start_frame + range.nframes));
188 utils::float_ranges::copy (
189 &out[range.start_frame], &buf[range.start_frame], range.nframes);
191 void send_data (
const dsp::MidiEvents &midi_events, FrameRange range)
override
193 if (jack_port_connected (port_) <= 0)
198 void * buf = jack_port_get_buffer (port_, range.start_frame + range.nframes);
199 copy_midi_event_vector_to_jack (
200 midi_events.
active_events_, range.start_frame, range.nframes, buf);
204 const dsp::PortIdentifier &
id,
205 PortDesignationProvider designation_provider)
override
207 enum JackPortFlags flags
212 flags = JackPortIsOutput;
213 else if (
id.is_output ())
214 flags = JackPortIsInput;
217 z_return_if_reached ();
220 const char * type = get_jack_type (
id.type_);
222 z_return_if_reached ();
224 auto label = designation_provider ();
225 z_info (
"exposing port {} to JACK", label);
226 if (port_ ==
nullptr)
228 port_ = jack_port_register (&client_, label.c_str (), type, flags, 0);
229 z_return_if_fail (port_);
233 jack_port_rename (&client_, port_, label.c_str ());
242 int ret = jack_port_unregister (&client_, port_);
246 auto jack_error = utils::jack::get_error_message ((jack_status_t) ret);
247 z_warning (
"JACK port unregister error: {}", jack_error);
251 bool is_exposed ()
const override {
return port_ !=
nullptr; }
253 void clear_backend_buffer (dsp::PortType type,
nframes_t nframes)
override
255 z_return_if_fail (port_ !=
nullptr);
256 void * buf = jack_port_get_buffer (port_, nframes);
257 z_return_if_fail (buf);
258 if (type == dsp::PortType::Audio)
260 auto * fbuf =
static_cast<float *
> (buf);
261 utils::float_ranges::fill (
264 else if (type == dsp::PortType::Event)
266 jack_midi_clear_buffer (buf);
270 jack_port_t * get_jack_port ()
const {
return port_; }
275 static const char * get_jack_type (dsp::PortType type)
279 case dsp::PortType::Audio:
280 return JACK_DEFAULT_AUDIO_TYPE;
282 case dsp::PortType::Event:
283 return JACK_DEFAULT_MIDI_TYPE;
291 jack_port_t * port_{
nullptr };
292 jack_client_t &client_;
virtual void send_data(const float *buf, FrameRange range)
Sends the port data to the backend, after the port is processed.
virtual void unexpose()=0
Unexposes the port from the backend (if exposed).
virtual void sum_audio_data(float *buf, FrameRange range)
Sums the inputs coming in from the backend, before the port is processed.
virtual void sum_midi_data(dsp::MidiEvents &midi_events, FrameRange range, MidiEventFilter filter_func=[](const auto &) { return true;})
virtual void expose(const dsp::PortIdentifier &id, PortDesignationProvider designation_provider)=0
Exposes the port to the backend, if not already exposed.
std::function< bool(const dsp::MidiEvent &)> MidiEventFilter
Function used to filter MIDI events.
void add_event_from_buf(midi_time_t time, midi_byte_t *buf, int buf_size)
Parses a MidiEvent from a raw MIDI buffer.
Container for passing midi events through ports.
MidiEventVector active_events_
Events to use in this cycle.
Struct used to identify Ports in the project.
Lightweight UTF-8 string wrapper with safe conversions.
uint32_t nframes_t
Frame count.
constexpr float ALMOST_SILENCE
Tiny number to be used for denormaml prevention (-140dB).
Frame range to operate on (on both the port's buffers and the backend's buffers).