OSSIA
Open Scenario System for Interactive Application
sine.hpp
1 #pragma once
2 #include <ossia/dataflow/graph_node.hpp>
3 #include <ossia/dataflow/port.hpp>
4 #include <ossia/detail/math.hpp>
5 
6 #include <boost/predef.h>
7 
8 namespace ossia::nodes
9 {
10 struct sine final : public ossia::nonowning_graph_node
11 {
12  ossia::value_inlet freq_in;
13  ossia::audio_outlet audio_out;
14 
15  double m_cos = 1.;
16  double m_sin = 0.;
17 
18 public:
19  double freq = 440.;
20  double amplitude = 0.8;
21  sine()
22  {
23  m_inlets.push_back(&freq_in);
24  m_outlets.push_back(&audio_out);
25  }
26  void run(const ossia::token_request& t, ossia::exec_state_facade st) noexcept override
27  {
28  auto& vals = freq_in.target<ossia::value_port>()->get_data();
29  if(!vals.empty())
30  {
31  freq = ossia::clamp(ossia::convert<float>(vals.back().value), 0.f, 20000.f);
32  }
33 
34  ossia::audio_port& audio = *audio_out;
35  const auto [tick_start, N] = st.timings(t);
36 
37  if(N > 0)
38  {
39  audio.set_channels(1);
40  auto& c = audio.channel(0);
41  c.resize(tick_start + N);
42 
43  // Uses the method in
44  // https://github.com/mbrucher/AudioTK/blob/master/ATK/Tools/SinusGeneratorFilter.cpp
45  const auto fs = st.sampleRate();
46  auto frequ_cos = std::cos(ossia::two_pi * freq / fs);
47  auto frequ_sin = std::sin(ossia::two_pi * freq / fs);
48  for(int64_t i = tick_start; i < tick_start + N; i++)
49  {
50  auto new_cos = m_cos * frequ_cos - m_sin * frequ_sin;
51  auto new_sin = m_cos * frequ_sin + m_sin * frequ_cos;
52  auto norm = (new_cos * new_cos + new_sin * new_sin);
53 
54  m_cos = new_cos / norm;
55  m_sin = new_sin / norm;
56 
57  c[i] = amplitude * m_sin;
58  }
59  }
60  }
61 };
62 }
constexpr OSSIA_INLINE T clamp(T d, const T min, const T max) noexcept
clamp Returns the value bounded by a min and a max
Definition: math.hpp:154