3 <alsa/asoundlib.h>) && __has_include(<zita-alsa-pcmi-ardour.h>) && !defined(__EMSCRIPTEN__)
5#include <ossia/audio/audio_engine.hpp>
6#include <ossia/dataflow/float_to_sample.hpp>
7#include <ossia/dataflow/sample_to_float.hpp>
9#include <ossia/detail/pod_vector.hpp>
10#include <ossia/detail/thread.hpp>
12#include <alsa/asoundlib.h>
13#include <kfr/base/conversion.hpp>
22#include <zita-alsa-pcmi-ardour.h>
24#define OSSIA_AUDIO_ALSA 1
28class alsa_engine final :
public audio_engine
32 std::string card_in, std::string card_out,
int inputs,
int outputs,
int rate,
35 m_client = std::make_unique<Alsa_pcmi>(
36 card_in.c_str(), card_out.c_str(),
nullptr, rate, bs, 2, 2,
37 Alsa_pcmi::DEBUG_ALL);
39 if(m_client->state() != 0)
41 throw std::runtime_error(
"Could not open ALSA");
44 effective_sample_rate = rate;
45 effective_buffer_size = bs;
46 effective_inputs = std::min(inputs, (
int)m_client->ncapt());
47 effective_outputs = std::min(outputs, (
int)m_client->nplay());
48 m_thread = std::thread{[
this] {
52 set_thread_realtime(m_thread);
63 m_stop_token.store(
false, std::memory_order_relaxed);
64 assert(m_thread.joinable());
73 ~alsa_engine()
override { stop(); }
75 bool running()
const override
84 auto& client = *this->m_client.get();
86 std::vector<float> buf_capture;
87 buf_capture.resize(effective_buffer_size * effective_inputs);
88 std::vector<float> buf_capture_deint;
89 buf_capture_deint.resize(effective_buffer_size * effective_inputs);
90 std::vector<float*> ptrs_capture;
91 for(
int i = 0; i < effective_inputs; i++)
92 ptrs_capture.push_back(buf_capture_deint.data() + i * effective_buffer_size);
94 std::vector<float> buf_playback;
95 buf_playback.resize(effective_buffer_size * effective_outputs);
96 std::vector<float> buf_playback_deint;
97 buf_playback_deint.resize(effective_buffer_size * effective_outputs);
98 std::vector<float*> ptrs_playback;
99 for(
int i = 0; i < effective_outputs; i++)
100 ptrs_playback.push_back(buf_playback_deint.data() + i * effective_buffer_size);
105 while(m_stop_token.load(std::memory_order_relaxed))
107 k = client.pcm_wait();
109 while(k >= effective_buffer_size)
111 client.capt_init(effective_buffer_size);
112 for(
int c = 0; c < effective_inputs; c++)
114 c, buf_capture.data() + c, effective_buffer_size, effective_inputs);
115 client.capt_done(effective_buffer_size);
118 ptrs_capture.data(), buf_capture.data(), effective_inputs,
119 effective_buffer_size);
122 buf_playback_deint.data(), effective_buffer_size * effective_outputs, 0);
124 process(ptrs_capture.data(), ptrs_playback.data(), effective_buffer_size);
127 buf_playback.data(), (
const float**)ptrs_playback.data(), effective_outputs,
128 effective_buffer_size);
130 client.play_init(effective_buffer_size);
131 for(
int c = 0; c < effective_outputs; c++)
133 c, buf_playback.data() + c, effective_buffer_size, effective_outputs);
135 for(std::size_t i = effective_outputs; i < client.nplay(); i++)
136 client.clear_chan(i, effective_buffer_size);
138 client.play_done(effective_buffer_size);
140 k -= effective_buffer_size;
150 ossia::set_thread_name(
"ossia audio 0");
151 ossia::set_thread_pinned(thread_type::Audio, 0);
154 void process(
float** float_input,
float** float_output, uint64_t nframes)
156 auto& self = *
static_cast<alsa_engine*
>(
this);
159 const auto inputs = this->effective_inputs;
160 const auto outputs = this->effective_outputs;
161 if(self.stop_processing)
167 using namespace std::chrono;
168 ossia::audio_tick_state ts{
174 duration_cast<nanoseconds>(m_last_time - m_start_time).count() / 1e9};
178 m_last_time = clk::now();
181 std::unique_ptr<Alsa_pcmi> m_client;
182 std::thread m_thread;
183 using clk = std::chrono::steady_clock;
184 clk::time_point m_start_time{};
185 clk::time_point m_last_time{};
186 std::atomic_bool m_stop_token{
true};
187 std::atomic_bool m_activated{};