OSSIA
Open Scenario System for Interactive Application
dummy_protocol.hpp
1 #pragma once
2 #include <ossia/audio/audio_engine.hpp>
3 #include <ossia/detail/thread.hpp>
4 
5 #include <thread>
6 
7 namespace ossia
8 {
9 class dummy_engine final : public audio_engine
10 {
11  int effective_sample_rate{}, effective_buffer_size{};
12  std::atomic_bool m_active;
13 
14 public:
15  dummy_engine(int rate, int bs)
16  {
17  effective_sample_rate = rate;
18  effective_buffer_size = bs;
19  effective_inputs = 0;
20  effective_outputs = 0;
21 
22  setup_thread();
23  }
24 
25  bool running() const override { return m_active; }
26 
27  void setup_thread()
28  {
29  m_active = true;
30 
31  int us_per_buffer
32  = 1e6 * double(effective_buffer_size) / double(effective_sample_rate);
33 
34  m_runThread = std::thread{[this, us_per_buffer] {
35  ossia::set_thread_name("ossia audio 0");
36  ossia::set_thread_pinned(thread_type::Audio, 0);
37 
38  using clk = std::chrono::high_resolution_clock;
39 
40  clk::time_point start = clk::now();
41  auto orig_start = start;
42  auto end = start;
43  uint64_t iter_total = 0;
44  int64_t ns_total = 0;
45  int64_t ns_delta = 0;
46  while(m_active)
47  {
48  iter_total++;
49  // TODO condition variables for the sleeping instead
50  // linux :
51  // https://stackoverflow.com/questions/24051863/how-to-implement-highly-accurate-timers-in-linux-userspace
52  // win : https://stackoverflow.com/a/13413019/1495627
53  // mac : https://stackoverflow.com/a/52905687/1495627
54  // other: naive way
55  // auto time_to_sleep = std::chrono::microseconds(us_per_buffer);
56  // auto actual_next = start + time_to_sleep;
57  auto now = start;
58  auto elapsed = (now - orig_start);
59  auto expected_next_elapsed = clk::duration(iter_total * us_per_buffer);
60  // auto delta = expected_next_elapsed - elapsed;
61  double delta_p = (expected_next_elapsed.count() - elapsed.count() / 1000.);
62  if(delta_p > 0)
63  {
64  std::this_thread::sleep_for(std::chrono::microseconds((int)delta_p));
65  }
66  end = clk::now();
67  tick_start();
68  if(stop_processing)
69  {
70  start = clk::now();
71  tick_clear();
72  continue;
73  }
74 
75  auto ns
76  = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
77  ns += ns_delta;
78  ns_total += ns;
79 
80  ns_delta = std::chrono::duration_cast<std::chrono::nanoseconds>(end - orig_start)
81  .count()
82  - ns_total;
83 
84  int samples = std::ceil(double(effective_sample_rate) * ns / 1e9);
85  samples = std::min(samples, effective_buffer_size);
86  if(samples < 0)
87  samples = 0;
88 
89  ossia::audio_tick_state ts{nullptr, nullptr, 0,
90  0, (uint64_t)samples, ns_total / 1e9};
91  audio_tick(ts);
92 
93  start = clk::now();
94  tick_end();
95  }
96  }};
97  }
98 
99  ~dummy_engine() override
100  {
101  m_active = false;
102  if(m_runThread.joinable())
103  m_runThread.join();
104  }
105 
106 private:
107  std::thread m_runThread;
108 };
109 }
Definition: git_info.h:7
constexpr OSSIA_INLINE auto min(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
min function tailored for values
Definition: math.hpp:125