diff options
-rw-r--r-- | Applications/Piano/AudioEngine.cpp | 38 | ||||
-rw-r--r-- | Applications/Piano/AudioEngine.h | 9 | ||||
-rw-r--r-- | Applications/Piano/KnobsWidget.cpp | 13 | ||||
-rw-r--r-- | Applications/Piano/KnobsWidget.h | 3 | ||||
-rw-r--r-- | Applications/Piano/MainWidget.cpp | 2 | ||||
-rw-r--r-- | Applications/Piano/Music.h | 7 |
6 files changed, 62 insertions, 10 deletions
diff --git a/Applications/Piano/AudioEngine.cpp b/Applications/Piano/AudioEngine.cpp index e853bdf05a..2af2fb30bd 100644 --- a/Applications/Piano/AudioEngine.cpp +++ b/Applications/Piano/AudioEngine.cpp @@ -32,6 +32,7 @@ AudioEngine::AudioEngine() { set_sustain_impl(0); + set_attack(0); set_decay(0); } @@ -45,12 +46,26 @@ void AudioEngine::fill_buffer(FixedArray<Sample>& buffer) for (size_t i = 0; i < buffer.size(); ++i) { for (size_t note = 0; note < note_count; ++note) { - if (!m_note_on[note]) + switch (m_envelope[note]) { + case Done: continue; - - m_power[note] -= m_decay_step; - if (m_power[note] < m_sustain_level) - m_power[note] = m_sustain_level; + case Attack: + m_power[note] += m_attack_step; + if (m_power[note] >= 1) { + m_power[note] = 1; + m_envelope[note] = Decay; + } + break; + case Decay: + m_power[note] -= m_decay_step; + if (m_power[note] < m_sustain_level) + m_power[note] = m_sustain_level; + break; + case Release: + break; + default: + ASSERT_NOT_REACHED(); + } double val = 0; switch (m_wave) { @@ -150,13 +165,15 @@ void AudioEngine::set_note(int note, Switch switch_note) if (switch_note == On) { if (m_note_on[note] == 0) { m_pos[note] = 0; - m_power[note] = 1; + m_envelope[note] = Attack; } ++m_note_on[note]; } else { if (m_note_on[note] >= 1) { - if (m_note_on[note] == 1) + if (m_note_on[note] == 1) { m_power[note] = 0; + m_envelope[note] = Done; + } --m_note_on[note]; } } @@ -209,6 +226,13 @@ static inline double calculate_step(double distance, int milliseconds) return step; } +void AudioEngine::set_attack(int attack) +{ + ASSERT(attack >= 0); + m_attack = attack; + m_attack_step = calculate_step(1, m_attack); +} + void AudioEngine::set_decay(int decay) { ASSERT(decay >= 0); diff --git a/Applications/Piano/AudioEngine.h b/Applications/Piano/AudioEngine.h index 33ef6af27a..430745f007 100644 --- a/Applications/Piano/AudioEngine.h +++ b/Applications/Piano/AudioEngine.h @@ -43,6 +43,7 @@ public: int octave() const { return m_octave; } int octave_base() const { return (m_octave - octave_min) * 12; } int wave() const { return m_wave; } + int attack() const { return m_attack; } int decay() const { return m_decay; } int sustain() const { return m_sustain; } int delay() const { return m_delay; } @@ -55,6 +56,7 @@ public: void set_octave(Direction); void set_wave(int wave); void set_wave(Direction); + void set_attack(int attack); void set_decay(int decay); void set_sustain(int sustain); void set_delay(int delay); @@ -76,11 +78,14 @@ private: Queue<NonnullOwnPtr<FixedArray<Sample>>> m_delay_buffers; u8 m_note_on[note_count] { 0 }; - double m_power[note_count]; // Initialized lazily. - double m_pos[note_count]; // Initialized lazily. + double m_power[note_count] { 0 }; + double m_pos[note_count]; // Initialized lazily. + Envelope m_envelope[note_count] { Done }; int m_octave { 4 }; int m_wave { first_wave }; + int m_attack; + double m_attack_step; int m_decay; double m_decay_step; int m_sustain; diff --git a/Applications/Piano/KnobsWidget.cpp b/Applications/Piano/KnobsWidget.cpp index 0ea9432dee..d2d9324bfb 100644 --- a/Applications/Piano/KnobsWidget.cpp +++ b/Applications/Piano/KnobsWidget.cpp @@ -50,6 +50,7 @@ KnobsWidget::KnobsWidget(GUI::Widget* parent, AudioEngine& audio_engine, MainWid m_octave_label = GUI::Label::construct("Octave", m_labels_container); m_wave_label = GUI::Label::construct("Wave", m_labels_container); + m_attack_label = GUI::Label::construct("Attack", m_labels_container); m_decay_label = GUI::Label::construct("Decay", m_labels_container); m_sustain_label = GUI::Label::construct("Sustain", m_labels_container); m_delay_label = GUI::Label::construct("Delay", m_labels_container); @@ -61,6 +62,7 @@ KnobsWidget::KnobsWidget(GUI::Widget* parent, AudioEngine& audio_engine, MainWid m_octave_value = GUI::Label::construct(String::number(m_audio_engine.octave()), m_values_container); m_wave_value = GUI::Label::construct(wave_strings[m_audio_engine.wave()], m_values_container); + m_attack_value = GUI::Label::construct(String::number(m_audio_engine.attack()), m_values_container); m_decay_value = GUI::Label::construct(String::number(m_audio_engine.decay()), m_values_container); m_sustain_value = GUI::Label::construct(String::number(m_audio_engine.sustain()), m_values_container); m_delay_value = GUI::Label::construct(String::number(m_audio_engine.delay() / m_audio_engine.tick()), m_values_container); @@ -93,6 +95,17 @@ KnobsWidget::KnobsWidget(GUI::Widget* parent, AudioEngine& audio_engine, MainWid m_wave_value->set_text(wave_strings[new_wave]); }; + constexpr int max_attack = 1000; + m_attack_knob = GUI::Slider::construct(Orientation::Vertical, m_knobs_container); + m_attack_knob->set_range(0, max_attack); + m_attack_knob->set_value(max_attack - m_audio_engine.attack()); + m_attack_knob->on_value_changed = [this](int value) { + int new_attack = max_attack - value; + m_audio_engine.set_attack(new_attack); + ASSERT(new_attack == m_audio_engine.attack()); + m_attack_value->set_text(String::number(new_attack)); + }; + constexpr int max_decay = 1000; m_decay_knob = GUI::Slider::construct(Orientation::Vertical, m_knobs_container); m_decay_knob->set_range(0, max_decay); diff --git a/Applications/Piano/KnobsWidget.h b/Applications/Piano/KnobsWidget.h index 3e39694b80..2eca83982f 100644 --- a/Applications/Piano/KnobsWidget.h +++ b/Applications/Piano/KnobsWidget.h @@ -53,6 +53,7 @@ private: RefPtr<GUI::Widget> m_labels_container; RefPtr<GUI::Label> m_octave_label; RefPtr<GUI::Label> m_wave_label; + RefPtr<GUI::Label> m_attack_label; RefPtr<GUI::Label> m_decay_label; RefPtr<GUI::Label> m_sustain_label; RefPtr<GUI::Label> m_delay_label; @@ -60,6 +61,7 @@ private: RefPtr<GUI::Widget> m_values_container; RefPtr<GUI::Label> m_octave_value; RefPtr<GUI::Label> m_wave_value; + RefPtr<GUI::Label> m_attack_value; RefPtr<GUI::Label> m_decay_value; RefPtr<GUI::Label> m_sustain_value; RefPtr<GUI::Label> m_delay_value; @@ -67,6 +69,7 @@ private: RefPtr<GUI::Widget> m_knobs_container; RefPtr<GUI::Slider> m_octave_knob; RefPtr<GUI::Slider> m_wave_knob; + RefPtr<GUI::Slider> m_attack_knob; RefPtr<GUI::Slider> m_decay_knob; RefPtr<GUI::Slider> m_sustain_knob; RefPtr<GUI::Slider> m_delay_knob; diff --git a/Applications/Piano/MainWidget.cpp b/Applications/Piano/MainWidget.cpp index 09d3881100..9d2003763d 100644 --- a/Applications/Piano/MainWidget.cpp +++ b/Applications/Piano/MainWidget.cpp @@ -60,7 +60,7 @@ MainWidget::MainWidget(AudioEngine& audio_engine) m_knobs_widget = KnobsWidget::construct(m_keys_and_knobs_container, audio_engine, *this); m_knobs_widget->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); - m_knobs_widget->set_preferred_size(250, 0); + m_knobs_widget->set_preferred_size(300, 0); } MainWidget::~MainWidget() diff --git a/Applications/Piano/Music.h b/Applications/Piano/Music.h index 716a17ddfc..858edd45d2 100644 --- a/Applications/Piano/Music.h +++ b/Applications/Piano/Music.h @@ -80,6 +80,13 @@ constexpr const char* wave_strings[] = { constexpr int first_wave = Sine; constexpr int last_wave = Noise; +enum Envelope { + Done, + Attack, + Decay, + Release, +}; + enum KeyColor { White, Black, |