2424#ifdef MP_UNITS_IMPORT_STD
2525import std;
2626#else
27+ #include < cassert>
2728#include < iostream>
2829#endif
2930#ifdef MP_UNITS_MODULES
@@ -41,6 +42,7 @@ import mp_units;
4142namespace {
4243using namespace mp_units ;
4344
45+ // ! A DSP generator class that generates sample values for a sine wave oscillator.
4446class sine_wave_osc {
4547public:
4648 sine_wave_osc (const audio::musical_context& context, QuantityOf<isq::frequency> auto freq) :
@@ -65,13 +67,21 @@ class sine_wave_osc {
6567 std::cout << MP_UNITS_STD_FMT::format (" Setting period to {} (i.e. frequency to {})\n " , period, m_frequency);
6668 }
6769
70+ void set_period (QuantityOf<audio::beat_count> auto period)
71+ {
72+ std::cout << MP_UNITS_STD_FMT::format (" Setting period to {} -- " , period);
73+ set_period (period / m_context.tempo );
74+ }
75+
6876 quantity<audio::sample_value, float > operator ()()
6977 {
7078 auto out = angular::sin (m_phase.quantity_from_zero ());
7179 m_phase += m_step;
7280 return out;
7381 }
7482
83+ void reset () { m_phase = phase_t {0 .f * angular::radian}; }
84+
7585private:
7686 using phase_t = quantity_point<angular::radian, mp_units::default_point_origin(angular::radian), float >;
7787
@@ -90,11 +100,50 @@ int main()
90100
91101 const auto context = audio::get_musical_context ();
92102
93-
103+ // Sine oscillators are sometimes used as a "low-frequency oscillator"
104+ // (LFO) that runs at a frequency below the range of human hearing and
105+ // is used a source of modulation for other paramters in an audio
106+ // algorithm.
94107 auto sin_gen = sine_wave_osc{context, 1 * Hz};
95108
96- // TODO set_frequency and set_period calls for demonstrating use of different units
109+ // Depending on the use-case sometimes an LFO will be set with a frequency in Hz
110+ sin_gen.set_frequency (13 * Hz);
111+
112+ // for some use-cases it is more convient for a user to set the period
113+ sin_gen.set_period (42 * s);
114+
115+ // and in some other use-cases setting the period in musical note duration is more intuitive
116+ sin_gen.set_period (1 * audio::half_note);
117+
118+ // Our oscillator can be used to generate sample values for a buffer
119+ // of audio samples. In this example we will create a buffer with
120+ // duration equal to 2 measures of 4/4 music (i.e. 2 whole notes at
121+ // the current tempo):
122+ const auto beats = 2 * audio::whole_note;
123+ const auto buffer_duration = beats / context.tempo ;
124+ const auto buffer_size = (buffer_duration * context.sample_rate ).in (audio::sample);
125+
126+ std::cout << MP_UNITS_STD_FMT::format (" \n Creating buffer with size:\n\t {}\n\t {}\n\t {}\n\n " , beats, buffer_duration,
127+ buffer_size);
128+
129+ using buffer_t = std::vector<quantity<audio::sample_value, float >>;
130+
131+ auto buffer_1 = buffer_t (std::size_t (buffer_size.numerical_value_in (audio::sample)));
132+
133+ std::cout << MP_UNITS_STD_FMT::format (" Filling buffer with values from LFO @ {}" , sin_gen.get_frequency ());
134+ std::generate (begin (buffer_1), end (buffer_1), sin_gen);
135+
136+ assert (buffer_1.size () > 0u );
137+ std::cout << MP_UNITS_STD_FMT::format (" \n LFO Values:\n [{}" , buffer_1[0u ]);
138+ for (std::size_t i = 1u ; i < buffer_1.size (); ++i) {
139+ std::cout << MP_UNITS_STD_FMT::format (" , {}" , buffer_1[i]);
140+ }
141+ std::cout << " ]\n\n " ;
97142
143+ // generated values should be the same after resetting oscillator
144+ sin_gen.reset ();
145+ auto buffer_2 = buffer_t (buffer_1.size ());
146+ std::generate (begin (buffer_2), end (buffer_2), sin_gen);
98147
99- // auto buffer = std::vector<quantity<audio::sample_value, float>>(2 * audio::whole_note)
148+ return buffer_1 == buffer_2;
100149}
0 commit comments