MainWidget.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2019-2020, William McPherson <willmcpherson2@gmail.com>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include "MainWidget.h"
  9. #include "KeysWidget.h"
  10. #include "KnobsWidget.h"
  11. #include "PlayerWidget.h"
  12. #include "RollWidget.h"
  13. #include "SamplerWidget.h"
  14. #include "TrackManager.h"
  15. #include "WaveWidget.h"
  16. #include <LibGUI/Action.h>
  17. #include <LibGUI/BoxLayout.h>
  18. #include <LibGUI/Menu.h>
  19. #include <LibGUI/TabWidget.h>
  20. ErrorOr<NonnullRefPtr<MainWidget>> MainWidget::try_create(TrackManager& manager, AudioPlayerLoop& loop)
  21. {
  22. auto widget = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) MainWidget(manager, loop)));
  23. TRY(widget->initialize());
  24. return widget;
  25. }
  26. MainWidget::MainWidget(TrackManager& track_manager, AudioPlayerLoop& loop)
  27. : m_track_manager(track_manager)
  28. , m_audio_loop(loop)
  29. {
  30. }
  31. ErrorOr<void> MainWidget::initialize()
  32. {
  33. TRY(try_set_layout<GUI::VerticalBoxLayout>(2, 2));
  34. set_fill_with_background_color(true);
  35. m_wave_widget = TRY(try_add<WaveWidget>(m_track_manager));
  36. m_wave_widget->set_fixed_height(100);
  37. m_tab_widget = TRY(try_add<GUI::TabWidget>());
  38. m_roll_widget = TRY(m_tab_widget->try_add_tab<RollWidget>("Piano Roll", m_track_manager));
  39. m_roll_widget->set_fixed_height(300);
  40. (void)TRY(m_tab_widget->try_add_tab<SamplerWidget>("Sampler", m_track_manager));
  41. m_player_widget = TRY(try_add<PlayerWidget>(m_track_manager, m_audio_loop));
  42. m_keys_and_knobs_container = TRY(try_add<GUI::Widget>());
  43. TRY(m_keys_and_knobs_container->try_set_layout<GUI::HorizontalBoxLayout>(GUI::Margins {}, 2));
  44. m_keys_and_knobs_container->set_fixed_height(130);
  45. m_keys_and_knobs_container->set_fill_with_background_color(true);
  46. m_keys_widget = TRY(m_keys_and_knobs_container->try_add<KeysWidget>(m_track_manager.keyboard()));
  47. m_knobs_widget = TRY(m_keys_and_knobs_container->try_add<KnobsWidget>(m_track_manager, *this));
  48. m_roll_widget->set_keys_widget(m_keys_widget);
  49. return {};
  50. }
  51. ErrorOr<void> MainWidget::add_track_actions(GUI::Menu& menu)
  52. {
  53. TRY(menu.try_add_action(GUI::Action::create("&Add Track", { Mod_Ctrl, Key_T }, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/plus.png"sv)), [&](auto&) {
  54. m_player_widget->add_track();
  55. })));
  56. TRY(menu.try_add_action(GUI::Action::create("&Next Track", { Mod_Ctrl, Key_N }, TRY(Gfx::Bitmap::load_from_file("/res/icons/16x16/go-last.png"sv)), [&](auto&) {
  57. turn_off_pressed_keys();
  58. m_player_widget->next_track();
  59. turn_on_pressed_keys();
  60. m_knobs_widget->update_knobs();
  61. })));
  62. return {};
  63. }
  64. // FIXME: There are some unnecessary calls to update() throughout this program,
  65. // which are an easy target for optimization.
  66. void MainWidget::custom_event(Core::CustomEvent&)
  67. {
  68. m_wave_widget->update();
  69. m_roll_widget->update();
  70. }
  71. void MainWidget::keydown_event(GUI::KeyEvent& event)
  72. {
  73. if (!event.alt() && !event.ctrl() && !event.shift()) {
  74. // This is to stop held-down keys from creating multiple events.
  75. if (m_keys_pressed[event.key()])
  76. return;
  77. else
  78. m_keys_pressed[event.key()] = true;
  79. bool event_was_accepted = false;
  80. if (note_key_action(event.key(), DSP::Keyboard::Switch::On))
  81. event_was_accepted = true;
  82. if (special_key_action(event.key()))
  83. event_was_accepted = true;
  84. if (!event_was_accepted)
  85. event.ignore();
  86. } else {
  87. event.ignore();
  88. }
  89. m_keys_widget->update();
  90. }
  91. void MainWidget::keyup_event(GUI::KeyEvent& event)
  92. {
  93. m_keys_pressed[event.key()] = false;
  94. note_key_action(event.key(), DSP::Keyboard::Switch::Off);
  95. m_keys_widget->update();
  96. }
  97. bool MainWidget::note_key_action(int key_code, DSP::Keyboard::Switch switch_note)
  98. {
  99. auto key = m_keys_widget->key_code_to_key(key_code);
  100. if (key == -1)
  101. return false;
  102. m_track_manager.keyboard()->set_keyboard_note_in_active_octave(key, switch_note);
  103. return true;
  104. }
  105. bool MainWidget::special_key_action(int key_code)
  106. {
  107. switch (key_code) {
  108. case Key_Z:
  109. set_octave_and_ensure_note_change(DSP::Keyboard::Direction::Down);
  110. return true;
  111. case Key_X:
  112. set_octave_and_ensure_note_change(DSP::Keyboard::Direction::Up);
  113. return true;
  114. case Key_Space:
  115. m_player_widget->toggle_paused();
  116. return true;
  117. }
  118. return false;
  119. }
  120. void MainWidget::turn_off_pressed_keys()
  121. {
  122. if (m_keys_widget->mouse_note() != -1)
  123. m_track_manager.keyboard()->set_keyboard_note_in_active_octave(m_keys_widget->mouse_note(), DSP::Keyboard::Switch::Off);
  124. for (int i = 0; i < key_code_count; ++i) {
  125. if (m_keys_pressed[i])
  126. note_key_action(i, DSP::Keyboard::Switch::Off);
  127. }
  128. }
  129. void MainWidget::turn_on_pressed_keys()
  130. {
  131. if (m_keys_widget->mouse_note() != -1)
  132. m_track_manager.keyboard()->set_keyboard_note_in_active_octave(m_keys_widget->mouse_note(), DSP::Keyboard::Switch::On);
  133. for (int i = 0; i < key_code_count; ++i) {
  134. if (m_keys_pressed[i])
  135. note_key_action(i, DSP::Keyboard::Switch::On);
  136. }
  137. }
  138. void MainWidget::set_octave_and_ensure_note_change(int octave)
  139. {
  140. turn_off_pressed_keys();
  141. MUST(m_track_manager.keyboard()->set_virtual_keyboard_octave(octave));
  142. turn_on_pressed_keys();
  143. m_knobs_widget->update_knobs();
  144. m_keys_widget->update();
  145. }
  146. void MainWidget::set_octave_and_ensure_note_change(DSP::Keyboard::Direction direction)
  147. {
  148. turn_off_pressed_keys();
  149. m_track_manager.keyboard()->change_virtual_keyboard_octave(direction);
  150. turn_on_pressed_keys();
  151. m_knobs_widget->update_knobs();
  152. m_keys_widget->update();
  153. }