1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-01 08:28:11 +00:00

LibDSP: Introduce the Keyboard

This is a class for handling user MIDI input, which is combined by the
Track with roll note data if applicable.
This commit is contained in:
kleines Filmröllchen 2022-05-13 10:13:14 +02:00 committed by Linus Groh
parent a54b681149
commit 37b340a698
4 changed files with 128 additions and 0 deletions

View file

@ -3,6 +3,7 @@ set(SOURCES
Track.cpp
Effects.cpp
Synthesizers.cpp
Keyboard.cpp
)
serenity_lib(LibDSP dsp)

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021-2022, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Keyboard.h"
#include "Music.h"
#include <AK/Error.h>
#include <AK/NumericLimits.h>
namespace LibDSP {
void Keyboard::set_keyboard_note(u8 pitch, Keyboard::Switch note_switch)
{
VERIFY(pitch < note_frequencies.size());
if (note_switch == Switch::Off) {
m_pressed_notes.remove(pitch);
return;
}
auto fake_note = RollNote {
.on_sample = m_transport->time(),
.off_sample = NumericLimits<u32>::max(),
.pitch = pitch,
.velocity = NumericLimits<i8>::max(),
};
m_pressed_notes.set(pitch, fake_note);
}
void Keyboard::set_keyboard_note_in_active_octave(i8 octave_offset, Switch note_switch)
{
u8 real_note = octave_offset + (m_virtual_keyboard_octave - 1) * notes_per_octave;
set_keyboard_note(real_note, note_switch);
}
void Keyboard::change_virtual_keyboard_octave(Direction direction)
{
if (direction == Direction::Up) {
if (m_virtual_keyboard_octave < octave_max)
++m_virtual_keyboard_octave;
} else {
if (m_virtual_keyboard_octave > octave_min)
--m_virtual_keyboard_octave;
}
}
ErrorOr<void> Keyboard::set_virtual_keyboard_octave(u8 octave)
{
if (octave <= octave_max && octave >= octave_min) {
m_virtual_keyboard_octave = octave;
return {};
}
return Error::from_string_literal("Octave out of range");
}
bool Keyboard::is_pressed(u8 pitch) const
{
return m_pressed_notes.get(pitch).has_value() && m_pressed_notes.get(pitch)->is_playing(m_transport->time());
}
bool Keyboard::is_pressed_in_active_octave(i8 octave_offset) const
{
return is_pressed(octave_offset + virtual_keyboard_octave_base());
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2021-2022, kleines Filmröllchen <filmroellchen@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <LibDSP/Music.h>
#include <LibDSP/Transport.h>
namespace LibDSP {
class Keyboard : public RefCounted<Keyboard> {
public:
enum class Direction : bool {
Down,
Up,
};
enum class Switch : bool {
Off,
On,
};
Keyboard(NonnullRefPtr<Transport> transport)
: m_transport(move(transport))
{
}
u8 virtual_keyboard_octave() const { return m_virtual_keyboard_octave; }
u8 virtual_keyboard_octave_base() const { return (m_virtual_keyboard_octave - octave_min) * 12; }
// Automatically clips the octave between the minimum and maximum.
void change_virtual_keyboard_octave(Direction);
// Errors out if the set octave is out of range.
ErrorOr<void> set_virtual_keyboard_octave(u8 octave);
void set_keyboard_note(u8 pitch, Switch note_switch);
void set_keyboard_note_in_active_octave(i8 octave_offset, Switch note_switch);
RollNotes const& notes() const { return m_pressed_notes; }
Optional<RollNote> note_at(u8 pitch) const { return m_pressed_notes.get(pitch); }
bool is_pressed(u8 pitch) const;
bool is_pressed_in_active_octave(i8 octave_offset) const;
private:
u8 m_virtual_keyboard_octave { 4 };
RollNotes m_pressed_notes;
NonnullRefPtr<Transport> m_transport;
static constexpr int const octave_min = 1;
static constexpr int const octave_max = 7;
};
}

View file

@ -196,6 +196,7 @@ constexpr Array<double, 84> note_frequencies = {
3951.0664100489994,
};
constexpr size_t const notes_per_octave = 12;
constexpr double const middle_c = note_frequencies[36];
}