diff options
author | William McPherson <willmcpherson2@gmail.com> | 2020-06-15 15:33:53 +1000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-18 16:42:37 +0200 |
commit | ee52572ca1bc382e6ccaf8e59e02db2b15157ac8 (patch) | |
tree | 4b106893b9343cba066a076c9a943cc2a714e410 /Applications | |
parent | db5b28b78ef64ab28eee7bc3f237241223e31f20 (diff) | |
download | serenity-ee52572ca1bc382e6ccaf8e59e02db2b15157ac8.zip |
Piano: Allow multiple tracks internally
This commit adds multi-track functionality without exposing it to the
user.
All I really did was rename AudioEngine to Track and allow more than one
Track in TrackManager. A lot of the changes are just changing widgets to
take a TrackManager and use current_track().
The TrackManager creates Tracks and gives them a read-only reference to
the global time value. When the TrackManager wants to fill a sample in
the buffer (in fill_buffer()), it calls fill_sample() on each Track.
The delay code is slightly different - a Track will fill its
m_delay_buffer with the sample it just created rather than the most
recent sample in the buffer (which used to be the same thing).
TrackManager manages the current octave.
Other than those few things, this is a pretty basic separation of
concerns.
Diffstat (limited to 'Applications')
-rw-r--r-- | Applications/Piano/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Applications/Piano/KeysWidget.cpp | 16 | ||||
-rw-r--r-- | Applications/Piano/KeysWidget.h | 6 | ||||
-rw-r--r-- | Applications/Piano/KnobsWidget.cpp | 66 | ||||
-rw-r--r-- | Applications/Piano/KnobsWidget.h | 6 | ||||
-rw-r--r-- | Applications/Piano/MainWidget.cpp | 20 | ||||
-rw-r--r-- | Applications/Piano/MainWidget.h | 6 | ||||
-rw-r--r-- | Applications/Piano/RollWidget.cpp | 12 | ||||
-rw-r--r-- | Applications/Piano/RollWidget.h | 6 | ||||
-rw-r--r-- | Applications/Piano/SamplerWidget.cpp | 16 | ||||
-rw-r--r-- | Applications/Piano/SamplerWidget.h | 10 | ||||
-rw-r--r-- | Applications/Piano/Track.cpp (renamed from Applications/Piano/AudioEngine.cpp) | 216 | ||||
-rw-r--r-- | Applications/Piano/Track.h (renamed from Applications/Piano/AudioEngine.h) | 29 | ||||
-rw-r--r-- | Applications/Piano/TrackManager.cpp | 97 | ||||
-rw-r--r-- | Applications/Piano/TrackManager.h | 71 | ||||
-rw-r--r-- | Applications/Piano/WaveWidget.cpp | 12 | ||||
-rw-r--r-- | Applications/Piano/WaveWidget.h | 6 | ||||
-rw-r--r-- | Applications/Piano/main.cpp | 20 |
18 files changed, 371 insertions, 247 deletions
diff --git a/Applications/Piano/CMakeLists.txt b/Applications/Piano/CMakeLists.txt index 0ba5a8ce91..6756afb18c 100644 --- a/Applications/Piano/CMakeLists.txt +++ b/Applications/Piano/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES - AudioEngine.cpp + Track.cpp + TrackManager.cpp KeysWidget.cpp KnobsWidget.cpp main.cpp diff --git a/Applications/Piano/KeysWidget.cpp b/Applications/Piano/KeysWidget.cpp index c3428120d6..3645c973ab 100644 --- a/Applications/Piano/KeysWidget.cpp +++ b/Applications/Piano/KeysWidget.cpp @@ -26,11 +26,11 @@ */ #include "KeysWidget.h" -#include "AudioEngine.h" +#include "TrackManager.h" #include <LibGUI/Painter.h> -KeysWidget::KeysWidget(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +KeysWidget::KeysWidget(TrackManager& track_manager) + : m_track_manager(track_manager) { set_fill_with_background_color(true); } @@ -41,7 +41,7 @@ KeysWidget::~KeysWidget() int KeysWidget::mouse_note() const { - if (m_mouse_down && m_mouse_note + m_audio_engine.octave_base() < note_count) + if (m_mouse_down && m_mouse_note + m_track_manager.octave_base() < note_count) return m_mouse_note; // Can be -1. else return -1; @@ -49,7 +49,7 @@ int KeysWidget::mouse_note() const void KeysWidget::set_key(int key, Switch switch_key) { - if (key == -1 || key + m_audio_engine.octave_base() >= note_count) + if (key == -1 || key + m_track_manager.octave_base() >= note_count) return; if (switch_key == On) { @@ -60,7 +60,7 @@ void KeysWidget::set_key(int key, Switch switch_key) } ASSERT(m_key_on[key] <= 2); - m_audio_engine.set_note_current_octave(key, switch_key); + m_track_manager.set_note_current_octave(key, switch_key); } int KeysWidget::key_code_to_key(int key_code) const @@ -191,7 +191,7 @@ void KeysWidget::paint_event(GUI::PaintEvent& event) x += white_key_width; ++i; - if (note + m_audio_engine.octave_base() >= note_count) + if (note + m_track_manager.octave_base() >= note_count) break; if (x >= frame_inner_rect().width()) break; @@ -213,7 +213,7 @@ void KeysWidget::paint_event(GUI::PaintEvent& event) x += black_key_offsets[i % black_keys_per_octave]; ++i; - if (note + m_audio_engine.octave_base() >= note_count) + if (note + m_track_manager.octave_base() >= note_count) break; if (x >= frame_inner_rect().width()) break; diff --git a/Applications/Piano/KeysWidget.h b/Applications/Piano/KeysWidget.h index 59bb6e5a4a..b5e4a066d4 100644 --- a/Applications/Piano/KeysWidget.h +++ b/Applications/Piano/KeysWidget.h @@ -30,7 +30,7 @@ #include "Music.h" #include <LibGUI/Frame.h> -class AudioEngine; +class TrackManager; class KeysWidget final : public GUI::Frame { C_OBJECT(KeysWidget) @@ -43,7 +43,7 @@ public: void set_key(int key, Switch); private: - explicit KeysWidget(AudioEngine&); + explicit KeysWidget(TrackManager&); virtual void paint_event(GUI::PaintEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; @@ -52,7 +52,7 @@ private: int note_for_event_position(const Gfx::IntPoint&) const; - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; u8 m_key_on[note_count] { 0 }; diff --git a/Applications/Piano/KnobsWidget.cpp b/Applications/Piano/KnobsWidget.cpp index 7e68687cff..0296124bf1 100644 --- a/Applications/Piano/KnobsWidget.cpp +++ b/Applications/Piano/KnobsWidget.cpp @@ -26,14 +26,14 @@ */ #include "KnobsWidget.h" -#include "AudioEngine.h" #include "MainWidget.h" +#include "TrackManager.h" #include <LibGUI/BoxLayout.h> #include <LibGUI/Label.h> #include <LibGUI/Slider.h> -KnobsWidget::KnobsWidget(AudioEngine& audio_engine, MainWidget& main_widget) - : m_audio_engine(audio_engine) +KnobsWidget::KnobsWidget(TrackManager& track_manager, MainWidget& main_widget) + : m_track_manager(track_manager) , m_main_widget(main_widget) { set_layout<GUI::VerticalBoxLayout>(); @@ -57,13 +57,13 @@ KnobsWidget::KnobsWidget(AudioEngine& audio_engine, MainWidget& main_widget) m_values_container->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); m_values_container->set_preferred_size(0, 10); - m_octave_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.octave())); - m_wave_value = m_values_container->add<GUI::Label>(wave_strings[m_audio_engine.wave()]); - m_attack_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.attack())); - m_decay_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.decay())); - m_sustain_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.sustain())); - m_release_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.release())); - m_delay_value = m_values_container->add<GUI::Label>(String::number(m_audio_engine.delay())); + m_octave_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.octave())); + m_wave_value = m_values_container->add<GUI::Label>(wave_strings[m_track_manager.current_track().wave()]); + m_attack_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().attack())); + m_decay_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().decay())); + m_sustain_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().sustain())); + m_release_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().release())); + m_delay_value = m_values_container->add<GUI::Label>(String::number(m_track_manager.current_track().delay())); m_knobs_container = add<GUI::Widget>(); m_knobs_container->set_layout<GUI::HorizontalBoxLayout>(); @@ -73,82 +73,82 @@ KnobsWidget::KnobsWidget(AudioEngine& audio_engine, MainWidget& main_widget) m_octave_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_octave_knob->set_tooltip("Z: octave down, X: octave up"); m_octave_knob->set_range(octave_min - 1, octave_max - 1); - m_octave_knob->set_value((octave_max - 1) - (m_audio_engine.octave() - 1)); + m_octave_knob->set_value((octave_max - 1) - (m_track_manager.octave() - 1)); m_octave_knob->on_value_changed = [this](int value) { int new_octave = octave_max - value; if (m_change_octave) - m_main_widget.set_octave_and_ensure_note_change(new_octave == m_audio_engine.octave() + 1 ? Up : Down); - ASSERT(new_octave == m_audio_engine.octave()); + m_main_widget.set_octave_and_ensure_note_change(new_octave == m_track_manager.octave() + 1 ? Up : Down); + ASSERT(new_octave == m_track_manager.octave()); m_octave_value->set_text(String::number(new_octave)); }; m_wave_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_wave_knob->set_tooltip("C: cycle through waveforms"); m_wave_knob->set_range(0, last_wave); - m_wave_knob->set_value(last_wave - m_audio_engine.wave()); + m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave()); m_wave_knob->on_value_changed = [this](int value) { int new_wave = last_wave - value; - m_audio_engine.set_wave(new_wave); - ASSERT(new_wave == m_audio_engine.wave()); + m_track_manager.current_track().set_wave(new_wave); + ASSERT(new_wave == m_track_manager.current_track().wave()); m_wave_value->set_text(wave_strings[new_wave]); }; constexpr int max_attack = 1000; m_attack_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_attack_knob->set_range(0, max_attack); - m_attack_knob->set_value(max_attack - m_audio_engine.attack()); + m_attack_knob->set_value(max_attack - m_track_manager.current_track().attack()); m_attack_knob->set_step(100); 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_track_manager.current_track().set_attack(new_attack); + ASSERT(new_attack == m_track_manager.current_track().attack()); m_attack_value->set_text(String::number(new_attack)); }; constexpr int max_decay = 1000; m_decay_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_decay_knob->set_range(0, max_decay); - m_decay_knob->set_value(max_decay - m_audio_engine.decay()); + m_decay_knob->set_value(max_decay - m_track_manager.current_track().decay()); m_decay_knob->set_step(100); m_decay_knob->on_value_changed = [this](int value) { int new_decay = max_decay - value; - m_audio_engine.set_decay(new_decay); - ASSERT(new_decay == m_audio_engine.decay()); + m_track_manager.current_track().set_decay(new_decay); + ASSERT(new_decay == m_track_manager.current_track().decay()); m_decay_value->set_text(String::number(new_decay)); }; constexpr int max_sustain = 1000; m_sustain_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_sustain_knob->set_range(0, max_sustain); - m_sustain_knob->set_value(max_sustain - m_audio_engine.sustain()); + m_sustain_knob->set_value(max_sustain - m_track_manager.current_track().sustain()); m_sustain_knob->set_step(100); m_sustain_knob->on_value_changed = [this](int value) { int new_sustain = max_sustain - value; - m_audio_engine.set_sustain(new_sustain); - ASSERT(new_sustain == m_audio_engine.sustain()); + m_track_manager.current_track().set_sustain(new_sustain); + ASSERT(new_sustain == m_track_manager.current_track().sustain()); m_sustain_value->set_text(String::number(new_sustain)); }; constexpr int max_release = 1000; m_release_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_release_knob->set_range(0, max_release); - m_release_knob->set_value(max_release - m_audio_engine.release()); + m_release_knob->set_value(max_release - m_track_manager.current_track().release()); m_release_knob->set_step(100); m_release_knob->on_value_changed = [this](int value) { int new_release = max_release - value; - m_audio_engine.set_release(new_release); - ASSERT(new_release == m_audio_engine.release()); + m_track_manager.current_track().set_release(new_release); + ASSERT(new_release == m_track_manager.current_track().release()); m_release_value->set_text(String::number(new_release)); }; constexpr int max_delay = 8; m_delay_knob = m_knobs_container->add<GUI::VerticalSlider>(); m_delay_knob->set_range(0, max_delay); - m_delay_knob->set_value(max_delay - m_audio_engine.delay()); + m_delay_knob->set_value(max_delay - m_track_manager.current_track().delay()); m_delay_knob->on_value_changed = [this](int value) { int new_delay = max_delay - value; - m_audio_engine.set_delay(new_delay); - ASSERT(new_delay == m_audio_engine.delay()); + m_track_manager.current_track().set_delay(new_delay); + ASSERT(new_delay == m_track_manager.current_track().delay()); m_delay_value->set_text(String::number(new_delay)); }; } @@ -159,12 +159,12 @@ KnobsWidget::~KnobsWidget() void KnobsWidget::update_knobs() { - m_wave_knob->set_value(last_wave - m_audio_engine.wave()); + m_wave_knob->set_value(last_wave - m_track_manager.current_track().wave()); // FIXME: This is needed because when the slider is changed directly, it // needs to change the octave, but if the octave was changed elsewhere, we // need to change the slider without changing the octave. m_change_octave = false; - m_octave_knob->set_value(octave_max - m_audio_engine.octave()); + m_octave_knob->set_value(octave_max - m_track_manager.octave()); m_change_octave = true; } diff --git a/Applications/Piano/KnobsWidget.h b/Applications/Piano/KnobsWidget.h index 315141144e..f7623df3dc 100644 --- a/Applications/Piano/KnobsWidget.h +++ b/Applications/Piano/KnobsWidget.h @@ -29,7 +29,7 @@ #include <LibGUI/Frame.h> -class AudioEngine; +class TrackManager; class MainWidget; class KnobsWidget final : public GUI::Frame { @@ -40,9 +40,9 @@ public: void update_knobs(); private: - KnobsWidget(AudioEngine&, MainWidget&); + KnobsWidget(TrackManager&, MainWidget&); - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; MainWidget& m_main_widget; RefPtr<GUI::Widget> m_labels_container; diff --git a/Applications/Piano/MainWidget.cpp b/Applications/Piano/MainWidget.cpp index ccfdb35e33..207954738c 100644 --- a/Applications/Piano/MainWidget.cpp +++ b/Applications/Piano/MainWidget.cpp @@ -26,34 +26,34 @@ */ #include "MainWidget.h" -#include "AudioEngine.h" #include "KeysWidget.h" #include "KnobsWidget.h" #include "RollWidget.h" #include "SamplerWidget.h" +#include "TrackManager.h" #include "WaveWidget.h" #include <LibGUI/BoxLayout.h> #include <LibGUI/TabWidget.h> -MainWidget::MainWidget(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +MainWidget::MainWidget(TrackManager& track_manager) + : m_track_manager(track_manager) { set_layout<GUI::VerticalBoxLayout>(); layout()->set_spacing(2); layout()->set_margins({ 2, 2, 2, 2 }); set_fill_with_background_color(true); - m_wave_widget = add<WaveWidget>(audio_engine); + m_wave_widget = add<WaveWidget>(track_manager); m_wave_widget->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); m_wave_widget->set_preferred_size(0, 100); m_tab_widget = add<GUI::TabWidget>(); - m_roll_widget = m_tab_widget->add_tab<RollWidget>("Piano Roll", audio_engine); + m_roll_widget = m_tab_widget->add_tab<RollWidget>("Piano Roll", track_manager); m_roll_widget->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fill); m_roll_widget->set_preferred_size(0, 300); - m_tab_widget->add_tab<SamplerWidget>("Sampler", audio_engine); + m_tab_widget->add_tab<SamplerWidget>("Sampler", track_manager); m_keys_and_knobs_container = add<GUI::Widget>(); m_keys_and_knobs_container->set_layout<GUI::HorizontalBoxLayout>(); @@ -62,9 +62,9 @@ MainWidget::MainWidget(AudioEngine& audio_engine) m_keys_and_knobs_container->set_preferred_size(0, 100); m_keys_and_knobs_container->set_fill_with_background_color(true); - m_keys_widget = m_keys_and_knobs_container->add<KeysWidget>(audio_engine); + m_keys_widget = m_keys_and_knobs_container->add<KeysWidget>(track_manager); - m_knobs_widget = m_keys_and_knobs_container->add<KnobsWidget>(audio_engine, *this); + m_knobs_widget = m_keys_and_knobs_container->add<KnobsWidget>(track_manager, *this); m_knobs_widget->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fill); m_knobs_widget->set_preferred_size(350, 0); } @@ -119,7 +119,7 @@ void MainWidget::special_key_action(int key_code) set_octave_and_ensure_note_change(Up); break; case Key_C: - m_audio_engine.set_wave(Up); + m_track_manager.current_track().set_wave(Up); m_knobs_widget->update_knobs(); break; } @@ -133,7 +133,7 @@ void MainWidget::set_octave_and_ensure_note_change(Direction direction) note_key_action(i, Off); } - m_audio_engine.set_octave(direction); + m_track_manager.set_octave(direction); m_keys_widget->set_key(m_keys_widget->mouse_note(), On); for (int i = 0; i < key_code_count; ++i) { diff --git a/Applications/Piano/MainWidget.h b/Applications/Piano/MainWidget.h index 6d1e80c4c1..6a2a543675 100644 --- a/Applications/Piano/MainWidget.h +++ b/Applications/Piano/MainWidget.h @@ -30,7 +30,7 @@ #include "Music.h" #include <LibGUI/Widget.h> -class AudioEngine; +class TrackManager; class WaveWidget; class RollWidget; class SamplerWidget; @@ -45,7 +45,7 @@ public: void set_octave_and_ensure_note_change(Direction); private: - explicit MainWidget(AudioEngine&); + explicit MainWidget(TrackManager&); virtual void keydown_event(GUI::KeyEvent&) override; virtual void keyup_event(GUI::KeyEvent&) override; @@ -54,7 +54,7 @@ private: void note_key_action(int key_code, Switch); void special_key_action(int key_code); - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; RefPtr<WaveWidget> m_wave_widget; RefPtr<RollWidget> m_roll_widget; diff --git a/Applications/Piano/RollWidget.cpp b/Applications/Piano/RollWidget.cpp index d9968225d9..738bef8f9e 100644 --- a/Applications/Piano/RollWidget.cpp +++ b/Applications/Piano/RollWidget.cpp @@ -26,7 +26,7 @@ */ #include "RollWidget.h" -#include "AudioEngine.h" +#include "TrackManager.h" #include <LibGUI/Painter.h> #include <LibGUI/ScrollBar.h> #include <math.h> @@ -37,8 +37,8 @@ constexpr int roll_height = note_count * note_height; constexpr int horizontal_scroll_sensitivity = 20; constexpr int max_zoom = 1 << 8; -RollWidget::RollWidget(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +RollWidget::RollWidget(TrackManager& track_manager) + : m_track_manager(track_manager) { set_should_hide_unnecessary_scrollbars(true); set_content_size({ 0, roll_height }); @@ -117,7 +117,7 @@ void RollWidget::paint_event(GUI::PaintEvent& event) painter.translate(horizontal_note_offset_remainder, note_offset_remainder); for (int note = note_count - (note_offset + notes_to_paint); note <= (note_count - 1) - note_offset; ++note) { - for (auto roll_note : m_audio_engine.roll_notes(note)) { + for (auto roll_note : m_track_manager.current_track().roll_notes(note)) { int x = m_roll_width * (static_cast<double>(roll_note.on_sample) / roll_length); int width = m_roll_width * (static_cast<double>(roll_note.length()) / roll_length); if (x + width < x_offset || x > x_offset + widget_inner_rect().width()) @@ -134,7 +134,7 @@ void RollWidget::paint_event(GUI::PaintEvent& event) } } - int x = m_roll_width * (static_cast<double>(m_audio_engine.time()) / roll_length); + int x = m_roll_width * (static_cast<double>(m_track_manager.time()) / roll_length); if (x > x_offset && x <= x_offset + widget_inner_rect().width()) painter.draw_line({ x, 0 }, { x, roll_height }, Gfx::Color::Black); @@ -164,7 +164,7 @@ void RollWidget::mousedown_event(GUI::MouseEvent& event) int note = (note_count - 1) - y; u32 on_sample = roll_length * (static_cast<double>(x) / m_num_notes); u32 off_sample = (roll_length * (static_cast<double>(x + 1) / m_num_notes)) - 1; - m_audio_engine.set_roll_note(note, on_sample, off_sample); + m_track_manager.current_track().set_roll_note(note, on_sample, off_sample); update(); } diff --git a/Applications/Piano/RollWidget.h b/Applications/Piano/RollWidget.h index 235d424412..4311038218 100644 --- a/Applications/Piano/RollWidget.h +++ b/Applications/Piano/RollWidget.h @@ -30,7 +30,7 @@ #include "Music.h" #include <LibGUI/ScrollableWidget.h> -class AudioEngine; +class TrackManager; class RollWidget final : public GUI::ScrollableWidget { C_OBJECT(RollWidget) @@ -38,13 +38,13 @@ public: virtual ~RollWidget() override; private: - explicit RollWidget(AudioEngine&); + explicit RollWidget(TrackManager&); virtual void paint_event(GUI::PaintEvent&) override; virtual void mousedown_event(GUI::MouseEvent& event) override; virtual void mousewheel_event(GUI::MouseEvent&) override; - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; int m_roll_width; int m_num_notes; diff --git a/Applications/Piano/SamplerWidget.cpp b/Applications/Piano/SamplerWidget.cpp index f3f116ebe4..e08026453e 100644 --- a/Applications/Piano/SamplerWidget.cpp +++ b/Applications/Piano/SamplerWidget.cpp @@ -25,7 +25,7 @@ */ #include "SamplerWidget.h" -#include "AudioEngine.h" +#include "TrackManager.h" #include <LibGUI/BoxLayout.h> #include <LibGUI/Button.h> #include <LibGUI/FilePicker.h> @@ -33,8 +33,8 @@ #include <LibGUI/MessageBox.h> #include <LibGUI/Painter.h> -WaveEditor::WaveEditor(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +WaveEditor::WaveEditor(TrackManager& track_manager) + : m_track_manager(track_manager) { } @@ -56,7 +56,7 @@ void WaveEditor::paint_event(GUI::PaintEvent& event) GUI::Painter painter(*this); painter.fill_rect(frame_inner_rect(), Color::Black); - auto recorded_sample = m_audio_engine.recorded_sample(); + auto recorded_sample = m_track_manager.current_track().recorded_sample(); if (recorded_sample.is_empty()) return; @@ -88,8 +88,8 @@ void WaveEditor::paint_event(GUI::PaintEvent& event) } } -SamplerWidget::SamplerWidget(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +SamplerWidget::SamplerWidget(TrackManager& track_manager) + : m_track_manager(track_manager) { set_layout<GUI::VerticalBoxLayout>(); layout()->set_margins({ 10, 10, 10, 10 }); @@ -111,7 +111,7 @@ SamplerWidget::SamplerWidget(AudioEngine& audio_engine) Optional<String> open_path = GUI::FilePicker::get_open_filepath(); if (!open_path.has_value()) return; - String error_string = m_audio_engine.set_recorded_sample(open_path.value()); + String error_string = m_track_manager.current_track().set_recorded_sample(open_path.value()); if (!error_string.is_empty()) { GUI::MessageBox::show(String::format("Failed to load WAV file: %s", error_string.characters()), "Error", GUI::MessageBox::Type::Error); return; @@ -123,7 +123,7 @@ SamplerWidget::SamplerWidget(AudioEngine& audio_engine) m_recorded_sample_name = m_open_button_and_recorded_sample_name_container->add<GUI::Label>("No sample loaded"); m_recorded_sample_name->set_text_alignment(Gfx::TextAlignment::CenterLeft); - m_wave_editor = add<WaveEditor>(m_audio_engine); + m_wave_editor = add<WaveEditor>(m_track_manager); m_wave_editor->set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); m_wave_editor->set_preferred_size(0, 100); } diff --git a/Applications/Piano/SamplerWidget.h b/Applications/Piano/SamplerWidget.h index 11c4ec90db..9091e5fef9 100644 --- a/Applications/Piano/SamplerWidget.h +++ b/Applications/Piano/SamplerWidget.h @@ -28,7 +28,7 @@ #include <LibGUI/Frame.h> -class AudioEngine; +class TrackManager; class WaveEditor final : public GUI::Frame { C_OBJECT(WaveEditor) @@ -36,13 +36,13 @@ public: virtual ~WaveEditor() override; private: - explicit WaveEditor(AudioEngine&); + explicit WaveEditor(TrackManager&); virtual void paint_event(GUI::PaintEvent&) override; int sample_to_y(double percentage) const; - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; }; class SamplerWidget final : public GUI::Frame { @@ -51,9 +51,9 @@ public: virtual ~SamplerWidget() override; private: - explicit SamplerWidget(AudioEngine&); + explicit SamplerWidget(TrackManager&); - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; RefPtr<GUI::Widget> m_open_button_and_recorded_sample_name_container; RefPtr<GUI::Button> m_open_button; diff --git a/Applications/Piano/AudioEngine.cpp b/Applications/Piano/Track.cpp index f4f6bb9560..22cbbe03f8 100644 --- a/Applications/Piano/AudioEngine.cpp +++ b/Applications/Piano/Track.cpp @@ -25,12 +25,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "AudioEngine.h" +#include "Track.h" #include <AK/NumericLimits.h> #include <LibAudio/WavLoader.h> #include <math.h> -AudioEngine::AudioEngine() +Track::Track(const u32& time) + : m_time(time) { set_sustain_impl(1000); set_attack(5); @@ -38,119 +39,104 @@ AudioEngine::AudioEngine() set_release(5); } -AudioEngine::~AudioEngine() +Track::~Track() { } -void AudioEngine::fill_buffer(FixedArray<Sample>& buffer) +void Track::fill_sample(Sample& sample) { - memset(buffer.data(), 0, buffer_size); - - for (size_t i = 0; i < buffer.size(); ++i) { - for (size_t note = 0; note < note_count; ++note) { - if (!m_roll_iters[note].is_end()) { - if (m_roll_iters[note]->on_sample == m_time) { - set_note(note, On); - } else if (m_roll_iters[note]->off_sample == m_time) { - set_note(note, Off); - ++m_roll_iters[note]; - if (m_roll_iters[note].is_end()) - m_roll_iters[note] = m_roll_notes[note].begin(); - } - } + Audio::Sample new_sample; - switch (m_envelope[note]) { - case Done: - continue; - 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: - m_power[note] -= m_release_step[note]; - if (m_power[note] <= 0) { - m_power[note] = 0; - m_envelope[note] = Done; - continue; - } - break; - default: - ASSERT_NOT_REACHED(); + for (size_t note = 0; note < note_count; ++note) { + if (!m_roll_iters[note].is_end()) { + if (m_roll_iters[note]->on_sample == m_time) { + set_note(note, On); + } else if (m_roll_iters[note]->off_sample == m_time) { + set_note(note, Off); + ++m_roll_iters[note]; + if (m_roll_iters[note].is_end()) + m_roll_iters[note] = m_roll_notes[note].begin(); } + } - Audio::Sample sample; - switch (m_wave) { - case Wave::Sine: - sample = sine(note); - break; - case Wave::Saw: - sample = saw(note); - break; - case Wave::Square: - sample = square(note); - break; - case Wave::Triangle: - sample = triangle(note); - break; - case Wave::Noise: - sample = noise(); - break; - case Wave::RecordedSample: - sample = recorded_sample(note); - break; - default: - ASSERT_NOT_REACHED(); + switch (m_envelope[note]) { + case Done: + continue; + case Attack: + m_power[note] += m_attack_step; + if (m_power[note] >= 1) { + m_power[note] = 1; + m_envelope[note] = Decay; } - buffer[i].left += sample.left * m_power[note] * volume; - buffer[i].right += sample.right * m_power[note] * volume; + 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: + m_power[note] -= m_release_step[note]; + if (m_power[note] <= 0) { + m_power[note] = 0; + m_envelope[note] = Done; + continue; + } + break; + default: + ASSERT_NOT_REACHED(); } - if (m_delay) { - buffer[i].left += m_delay_buffer[m_delay_index].left * 0.333333; - buffer[i].right += m_delay_buffer[m_delay_index].right * 0.333333; - m_delay_buffer[m_delay_index].left = buffer[i].left; - m_delay_buffer[m_delay_index].right = buffer[i].right; - if (++m_delay_index >= m_delay_samples) - m_delay_index = 0; + Audio::Sample note_sample; + switch (m_wave) { + case Wave::Sine: + note_sample = sine(note); + break; + case Wave::Saw: + note_sample = saw(note); + break; + case Wave::Square: + note_sample = square(note); + break; + case Wave::Triangle: + note_sample = triangle(note); + break; + case Wave::Noise: + note_sample = noise(); + break; + case Wave::RecordedSample: + note_sample = recorded_sample(note); + break; + default: + ASSERT_NOT_REACHED(); } + new_sample.left += note_sample.left * m_power[note] * volume; + new_sample.right += note_sample.right * m_power[note] * volume; + } - if (++m_time >= roll_length) { - m_time = 0; - if (!m_should_loop) - break; - } + if (m_delay) { + new_sample.left += m_delay_buffer[m_delay_index].left * 0.333333; + new_sample.right += m_delay_buffer[m_delay_index].right * 0.333333; + m_delay_buffer[m_delay_index].left = new_sample.left; + m_delay_buffer[m_delay_index].right = new_sample.right; + if (++m_delay_index >= m_delay_samples) + m_delay_index = 0; } - memcpy(m_back_buffer_ptr->data(), buffer.data(), buffer_size); - swap(m_front_buffer_ptr, m_back_buffer_ptr); + sample.left += new_sample.left; + sample.right += new_sample.right; } -void AudioEngine::reset() +void Track::reset() { - memset(m_front_buffer.data(), 0, buffer_size); - memset(m_back_buffer.data(), 0, buffer_size); - m_front_buffer_ptr = &m_front_buffer; - m_back_buffer_ptr = &m_back_buffer; - memset(m_delay_buffer.data(), 0, m_delay_buffer.size() * sizeof(Sample)); m_delay_index = 0; memset(m_note_on, 0, sizeof(m_note_on)); memset(m_power, 0, sizeof(m_power)); memset(m_envelope, 0, sizeof(m_envelope)); - - m_time = 0; } -String AudioEngine::set_recorded_sample(const StringView& path) +String Track::set_recorded_sample(const StringView& path) { Audio::WavLoader wav_loader(path); if (wav_loader.has_error()) @@ -183,7 +169,7 @@ String AudioEngine::set_recorded_sample(const StringView& path) // All of the information for these waves is on Wikipedia. -Audio::Sample AudioEngine::sine(size_t note) +Audio::Sample Track::sine(size_t note) { double pos = note_frequencies[note] / sample_rate; double sin_step = pos * 2 * M_PI; @@ -192,7 +178,7 @@ Audio::Sample AudioEngine::sine(size_t note) return w; } -Audio::Sample AudioEngine::saw(size_t note) +Audio::Sample Track::saw(size_t note) { double saw_step = note_frequencies[note] / sample_rate; double t = m_pos[note]; @@ -201,7 +187,7 @@ Audio::Sample AudioEngine::saw(size_t note) return w; } -Audio::Sample AudioEngine::square(size_t note) +Audio::Sample Track::square(size_t note) { double pos = note_frequencies[note] / sample_rate; double square_step = pos * 2 * M_PI; @@ -210,7 +196,7 @@ Audio::Sample AudioEngine::square(size_t note) return w; } -Audio::Sample AudioEngine::triangle(size_t note) +Audio::Sample Track::triangle(size_t note) { double triangle_step = note_frequencies[note] / sample_rate; double t = m_pos[note]; @@ -219,14 +205,14 @@ Audio::Sample AudioEngine::triangle(size_t note) return w; } -Audio::Sample AudioEngine::noise() const +Audio::Sample Track::noise() const { double random_percentage = static_cast<double>(rand()) / RAND_MAX; double w = (random_percentage * 2) - 1; return w; } -Audio::Sample AudioEngine::recorded_sample(size_t note) +Audio::Sample Track::recorded_sample(size_t note) { int t = m_pos[note]; if (t >= static_cast<int>(m_recorded_sample.size())) @@ -254,7 +240,7 @@ static inline double calculate_step(double distance, int milliseconds) return step; } -void AudioEngine::set_note(int note, Switch switch_note) +void Track::set_note(int note, Switch switch_note) { ASSERT(note >= 0 && note < note_count); @@ -278,12 +264,7 @@ void AudioEngine::set_note(int note, Switch switch_note) ASSERT(m_power[note] >= 0); } -void AudioEngine::set_note_current_octave(int note, Switch switch_note) -{ - set_note(note + octave_base(), switch_note); -} - -void AudioEngine::sync_roll(int note) +void Track::sync_roll(int note) { auto it = m_roll_notes[note].find([&](auto& roll_note) { return roll_note.off_sample > m_time; }); if (it.is_end()) @@ -292,7 +273,7 @@ void AudioEngine::sync_roll(int note) m_roll_iters[note] = it; } -void AudioEngine::set_roll_note(int note, u32 on_sample, u32 off_sample) +void Track::set_roll_note(int note, u32 on_sample, u32 off_sample) { RollNote new_roll_note = { on_sample, off_sample }; @@ -333,24 +314,13 @@ void AudioEngine::set_roll_note(int note, u32 on_sample, u32 off_sample) sync_roll(note); } -void AudioEngine::set_octave(Direction direction) -{ - if (direction == Up) { - if (m_octave < octave_max) - ++m_octave; - } else { - if (m_octave > octave_min) - --m_octave; - } -} - -void AudioEngine::set_wave(int wave) +void Track::set_wave(int wave) { ASSERT(wave >= first_wave && wave <= last_wave); m_wave = wave; } -void AudioEngine::set_wave(Direction direction) +void Track::set_wave(Direction direction) { if (direction == Up) { if (++m_wave > last_wave) @@ -361,40 +331,40 @@ void AudioEngine::set_wave(Direction direction) } } -void AudioEngine::set_attack(int attack) +void Track::set_attack(int attack) { ASSERT(attack >= 0); m_attack = attack; m_attack_step = calculate_step(1, m_attack); } -void AudioEngine::set_decay(int decay) +void Track::set_decay(int decay) { ASSERT(decay >= 0); m_decay = decay; m_decay_step = calculate_step(1 - m_sustain_level, m_decay); } -void AudioEngine::set_sustain_impl(int sustain) +void Track::set_sustain_impl(int sustain) { ASSERT(sustain >= 0); m_sustain = sustain; m_sustain_level = sustain / 1000.0; } -void AudioEngine::set_sustain(int sustain) +void Track::set_sustain(int sustain) { set_sustain_impl(sustain); set_decay(m_decay); } -void AudioEngine::set_release(int release) +void Track::set_release(int release) { ASSERT(release >= 0); m_release = release; } -void AudioEngine::set_delay(int delay) +void Track::set_delay(int delay) { ASSERT(delay >= 0); m_delay = delay; diff --git a/Applications/Piano/AudioEngine.h b/Applications/Piano/Track.h index aae9554520..99f3e1f3ab 100644 --- a/Applications/Piano/AudioEngine.h +++ b/Applications/Piano/Track.h @@ -35,34 +35,27 @@ typedef AK::SinglyLinkedListIterator<SinglyLinkedList<RollNote>, RollNote> RollIter; -class AudioEngine { - AK_MAKE_NONCOPYABLE(AudioEngine) - AK_MAKE_NONMOVABLE(AudioEngine) +class Track { + AK_MAKE_NONCOPYABLE(Track) + AK_MAKE_NONMOVABLE(Track) public: - AudioEngine(); - ~AudioEngine(); + explicit Track(const u32& time); + ~Track(); - const FixedArray<Sample>& buffer() const { return *m_front_buffer_ptr; } const Vector<Audio::Sample>& recorded_sample() const { return m_recorded_sample; } const SinglyLinkedList<RollNote>& roll_notes(int note) const { return m_roll_notes[note]; } - 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 release() const { return m_release; } int delay() const { return m_delay; } - int time() const { return m_time; } - void fill_buffer(FixedArray<Sample>& buffer); + void fill_sample(Sample& sample); void reset(); - void set_should_loop(bool b) { m_should_loop = b; } String set_recorded_sample(const StringView& path); void set_note(int note, Switch); - void set_note_current_octave(int note, Switch); void set_roll_note(int note, u32 on_sample, u32 off_sample); - void set_octave(Direction); void set_wave(int wave); void set_wave(Direction); void set_attack(int attack); @@ -82,11 +75,6 @@ private: void sync_roll(int note); void set_sustain_impl(int sustain); - FixedArray<Sample> m_front_buffer { sample_count }; - FixedArray<Sample> m_back_buffer { sample_count }; - FixedArray<Sample>* m_front_buffer_ptr { &m_front_buffer }; - FixedArray<Sample>* m_back_buffer_ptr { &m_back_buffer }; - Vector<Sample> m_delay_buffer; Vector<Audio::Sample> m_recorded_sample; @@ -96,7 +84,6 @@ private: 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; @@ -110,9 +97,7 @@ private: size_t m_delay_samples { 0 }; size_t m_delay_index { 0 }; - u32 m_time { 0 }; - - bool m_should_loop { true }; + const u32& m_time; SinglyLinkedList<RollNote> m_roll_notes[note_count]; RollIter m_roll_iters[note_count]; diff --git a/Applications/Piano/TrackManager.cpp b/Applications/Piano/TrackManager.cpp new file mode 100644 index 0000000000..2a9419e3be --- /dev/null +++ b/Applications/Piano/TrackManager.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "TrackManager.h" + +TrackManager::TrackManager() +{ + add_track(); +} + +TrackManager::~TrackManager() +{ +} + +void TrackManager::fill_buffer(FixedArray<Sample>& buffer) +{ + memset(buffer.data(), 0, buffer_size); + + for (size_t i = 0; i < buffer.size(); ++i) { + for (auto& track : m_tracks) + track->fill_sample(buffer[i]); + + if (++m_time >= roll_length) { + m_time = 0; + if (!m_should_loop) + break; + } + } + + memcpy(m_back_buffer_ptr->data(), buffer.data(), buffer_size); + swap(m_front_buffer_ptr, m_back_buffer_ptr); +} + +void TrackManager::reset() +{ + memset(m_front_buffer.data(), 0, buffer_size); + memset(m_back_buffer.data(), 0, buffer_size); + + m_front_buffer_ptr = &m_front_buffer; + m_back_buffer_ptr = &m_back_buffer; + + m_time = 0; + + for (auto& track : m_tracks) + track->reset(); +} + +void TrackManager::set_note_current_octave(int note, Switch switch_note) +{ + current_track().set_note(note + octave_base(), switch_note); +} + +void TrackManager::set_octave(Direction direction) +{ + if (direction == Up) { + if (m_octave < octave_max) + ++m_octave; + } else { + if (m_octave > octave_min) + --m_octave; + } +} + +void TrackManager::add_track() +{ + m_tracks.append(make<Track>(m_time)); +} + +void TrackManager::next_track() +{ + if (++m_current_track >= m_tracks.size()) + m_current_track = 0; +} diff --git a/Applications/Piano/TrackManager.h b/Applications/Piano/TrackManager.h new file mode 100644 index 0000000000..2443adc343 --- /dev/null +++ b/Applications/Piano/TrackManager.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "Music.h" +#include "Track.h" +#include <AK/Noncopyable.h> +#include <AK/NonnullOwnPtr.h> +#include <AK/Vector.h> + +class TrackManager { + AK_MAKE_NONCOPYABLE(TrackManager) + AK_MAKE_NONMOVABLE(TrackManager) +public: + TrackManager(); + ~TrackManager(); + + Track& current_track() { return *m_tracks[m_current_track]; } + const FixedArray<Sample>& buffer() const { return *m_front_buffer_ptr; } + int octave() const { return m_octave; } + int octave_base() const { return (m_octave - octave_min) * 12; } + int time() const { return m_time; } + + void fill_buffer(FixedArray<Sample>& buffer); + void reset(); + void set_should_loop(bool b) { m_should_loop = b; } + void set_note_current_octave(int note, Switch); + void set_octave(Direction); + void add_track(); + void next_track(); + +private: + Vector<NonnullOwnPtr<Track>> m_tracks; + size_t m_current_track { 0 }; + + FixedArray<Sample> m_front_buffer { sample_count }; + FixedArray<Sample> m_back_buffer { sample_count }; + FixedArray<Sample>* m_front_buffer_ptr { &m_front_buffer }; + FixedArray<Sample>* m_back_buffer_ptr { &m_back_buffer }; + + int m_octave { 4 }; + + u32 m_time { 0 }; + + bool m_should_loop { true }; +}; diff --git a/Applications/Piano/WaveWidget.cpp b/Applications/Piano/WaveWidget.cpp index 9a8cdebc94..9c40b46bde 100644 --- a/Applications/Piano/WaveWidget.cpp +++ b/Applications/Piano/WaveWidget.cpp @@ -26,12 +26,12 @@ */ #include "WaveWidget.h" -#include "AudioEngine.h" +#include "TrackManager.h" #include <AK/NumericLimits.h> #include <LibGUI/Painter.h> -WaveWidget::WaveWidget(AudioEngine& audio_engine) - : m_audio_engine(audio_engine) +WaveWidget::WaveWidget(TrackManager& track_manager) + : m_track_manager(track_manager) { } @@ -56,9 +56,9 @@ void WaveWidget::paint_event(GUI::PaintEvent& event) painter.fill_rect(frame_inner_rect(), Color::Black); painter.translate(frame_thickness(), frame_thickness()); - Color left_wave_color = left_wave_colors[m_audio_engine.wave()]; - Color right_wave_color = right_wave_colors[m_audio_engine.wave()]; - auto buffer = m_audio_engine.buffer(); + Color left_wave_color = left_wave_colors[m_track_manager.current_track().wave()]; + Color right_wave_color = right_wave_colors[m_track_manager.current_track().wave()]; + auto buffer = m_track_manager.buffer(); double width_scale = static_cast<double>(frame_inner_rect().width()) / buffer.size(); int prev_x = 0; diff --git a/Applications/Piano/WaveWidget.h b/Applications/Piano/WaveWidget.h index 41475eaa11..e8b9cd4d5f 100644 --- a/Applications/Piano/WaveWidget.h +++ b/Applications/Piano/WaveWidget.h @@ -29,7 +29,7 @@ #include <LibGUI/Frame.h> -class AudioEngine; +class TrackManager; class WaveWidget final : public GUI::Frame { C_OBJECT(WaveWidget) @@ -37,11 +37,11 @@ public: virtual ~WaveWidget() override; private: - explicit WaveWidget(AudioEngine&); + explicit WaveWidget(TrackManager&); virtual void paint_event(GUI::PaintEvent&) override; int sample_to_y(int sample) const; - AudioEngine& m_audio_engine; + TrackManager& m_track_manager; }; diff --git a/Applications/Piano/main.cpp b/Applications/Piano/main.cpp index 3fef83134a..0310a29de3 100644 --- a/Applications/Piano/main.cpp +++ b/Applications/Piano/main.cpp @@ -25,8 +25,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "AudioEngine.h" #include "MainWidget.h" +#include "TrackManager.h" #include <LibAudio/ClientConnection.h> #include <LibAudio/WavWriter.h> #include <LibCore/EventLoop.h> @@ -49,10 +49,10 @@ int main(int argc, char** argv) auto audio_client = Audio::ClientConnection::construct(); audio_client->handshake(); - AudioEngine audio_engine; + TrackManager track_manager; auto window = GUI::Window::construct(); - auto& main_widget = window->set_main_widget<MainWidget>(audio_engine); + auto& main_widget = window->set_main_widget<MainWidget>(track_manager); window->set_title("Piano"); window->set_rect(90, 90, 840, 600); window->set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/app-piano.png")); @@ -71,21 +71,21 @@ int main(int argc, char** argv) FixedArray<Sample> buffer(sample_count); for (;;) { - audio_engine.fill_buffer(buffer); + track_manager.fill_buffer(buffer); audio->write(reinterpret_cast<u8*>(buffer.data()), buffer_size); Core::EventLoop::current().post_event(main_widget, make<Core::CustomEvent>(0)); Core::EventLoop::wake(); if (need_to_write_wav) { need_to_write_wav = false; - audio_engine.reset(); - audio_engine.set_should_loop(false); + track_manager.reset(); + track_manager.set_should_loop(false); do { - audio_engine.fill_buffer(buffer); + track_manager.fill_buffer(buffer); wav_writer.write_samples(reinterpret_cast<u8*>(buffer.data()), buffer_size); - } while (audio_engine.time()); - audio_engine.reset(); - audio_engine.set_should_loop(true); + } while (track_manager.time()); + track_manager.reset(); + track_manager.set_should_loop(true); wav_writer.finalize(); } } |