Piano: Add triangle wave and noise

The squad is complete :^)

You can find the equation for the triangle wave here:
https://en.wikipedia.org/wiki/Triangle_wave
We're using this one:
|x mod 4 - 2| - 1
Modifications have been made to correct the frequency and phase:
|(4x + 1) mod 4 - 2| - 1

The white noise is generated by calling rand() and dividing it by
RAND_MAX to get a value from 0 to 1. Then it's adjusted to fit between
-1 and 1.
This commit is contained in:
William McPherson 2019-12-13 19:19:57 +11:00 committed by Andreas Kling
parent 091c783626
commit 69d05fbf44
Notes: sideshowbarker 2024-07-19 10:52:27 +09:00
3 changed files with 38 additions and 1 deletions

View file

@ -9,7 +9,7 @@ struct Sample {
i16 right;
};
enum WaveType { Sine, Saw, Square, InvalidWave };
enum WaveType { Sine, Saw, Square, Triangle, Noise, InvalidWave };
enum PianoKey {
K_None,

View file

@ -32,6 +32,10 @@ void PianoWidget::paint_event(GPaintEvent& event)
wave_color = Color(240, 100, 128);
else if (m_wave_type == WaveType::Square)
wave_color = Color(128, 160, 255);
else if (m_wave_type == WaveType::Triangle)
wave_color = Color(35, 171, 35);
else if (m_wave_type == WaveType::Noise)
wave_color = Color(197, 214, 225);
int prev_x = 0;
int prev_y = m_height / 2;
@ -70,6 +74,10 @@ void PianoWidget::fill_audio_buffer(uint8_t* stream, int len)
val = ((volume * m_power[n]) * w_saw(n));
else if (m_wave_type == WaveType::Square)
val = ((volume * m_power[n]) * w_square(n));
else if (m_wave_type == WaveType::Triangle)
val = ((volume * m_power[n]) * w_triangle(n));
else if (m_wave_type == WaveType::Noise)
val = ((volume * m_power[n]) * w_noise());
if (sst[i].left == 0)
sst[i].left = val;
else
@ -147,6 +155,20 @@ double PianoWidget::w_square(size_t n)
return w;
}
double PianoWidget::w_triangle(size_t n)
{
double triangle_step = note_frequency[n] / 44100.0;
double t = m_triangle_pos[n];
double w = fabs(fmod((4 * t) + 1, 4) - 2) - 1;
m_triangle_pos[n] += triangle_step;
return w;
}
double PianoWidget::w_noise()
{
return (((double)rand() / RAND_MAX) * 2.0) - 1.0;
}
int PianoWidget::octave_base() const
{
return (m_octave - m_octave_min) * 12;
@ -393,6 +415,14 @@ void PianoWidget::render_knobs(GPainter& painter)
r = 128;
g = 160;
b = 255;
} else if (m_wave_type == WaveType::Triangle) {
r = 35;
g = 171;
b = 35;
} else if (m_wave_type == WaveType::Noise) {
r = 197;
g = 214;
b = 225;
}
Rect wave_knob_rect(m_width - knob_width - 16 - knob_width - 16, m_height - 30, knob_width, 16);
const char* wave_name = "";
@ -402,6 +432,10 @@ void PianoWidget::render_knobs(GPainter& painter)
wave_name = "C: Sawtooth";
else if (m_wave_type == WaveType::Square)
wave_name = "C: Square ";
else if (m_wave_type == WaveType::Triangle)
wave_name = "C: Triangle";
else if (m_wave_type == WaveType::Noise)
wave_name = "C: Noise ";
painter.draw_rect(wave_knob_rect, Color(r, g, b));
painter.draw_text(wave_knob_rect, wave_name, TextAlignment::Center, Color(r, g, b));
}

View file

@ -25,6 +25,8 @@ private:
double w_sine(size_t);
double w_saw(size_t);
double w_square(size_t);
double w_triangle(size_t);
double w_noise();
Rect define_piano_key_rect(int index, PianoKey) const;
PianoKey find_key_for_relative_position(int x, int y) const;
@ -49,6 +51,7 @@ private:
double m_sin_pos[note_count];
double m_square_pos[note_count];
double m_saw_pos[note_count];
double m_triangle_pos[note_count];
int m_octave_min { 1 };
int m_octave_max { 6 };