mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-06 11:09:05 +03:00
Piano: Add attack
This commit is contained in:
parent
5990b3b2e6
commit
ab9475a3f3
Notes:
sideshowbarker
2024-07-19 09:39:37 +09:00
Author: https://github.com/willmcpherson2 Commit: https://github.com/SerenityOS/serenity/commit/ab9475a3f31 Pull-request: https://github.com/SerenityOS/serenity/pull/1178
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user