Skip to content

Commit

Permalink
feat(midi): Recognize system messages in Log Node
Browse files Browse the repository at this point in the history
  • Loading branch information
mfep committed Jun 14, 2024
1 parent 87f1be1 commit e0e1dc5
Show file tree
Hide file tree
Showing 3 changed files with 503 additions and 27 deletions.
115 changes: 94 additions & 21 deletions src/LogNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ void mc::LogNode::render_internal()
ImGui::TextUnformatted("MIDI in");
ImNodes::EndInputAttribute();

bool clear = false;
if (ImGui::Button("Clear"))
{
clear = true;
}
ImGui::SameLine();
int new_buffer_size = static_cast<int>(m_max_buffer_size);
ImGui::SetNextItemWidth(100.0F * m_scale_provider->get_scale_value());
if (ImGui::InputInt("Buffer Size", &new_buffer_size))
Expand All @@ -57,6 +63,10 @@ void mc::LogNode::render_internal()
}

std::unique_lock lock(m_buffer_mutex);
if (clear)
{
m_message_buffer.clear();
}
while (!m_message_buffer.empty() && m_message_buffer.size() > m_max_buffer_size)
{
m_message_buffer.pop_back();
Expand Down Expand Up @@ -130,6 +140,29 @@ void mc::LogNode::message_received(std::span<const unsigned char> message_bytes)

m_input_indicator.trigger();
midi::MessageView message(message_bytes);
midi::tag_overloads message_visitor{
[](midi::ChannelMessageViewTag, auto channel_message) -> BufferElement {
return parse_channel_message(channel_message);
},
[](midi::SystemMessageViewTag, auto system_message) -> BufferElement {
return parse_system_message(system_message);
},
[]<class Tag>(
Tag, auto) -> std::enable_if_t<!std::is_base_of_v<midi::ChannelMessageViewTag, Tag> &&
!std::is_base_of_v<midi::SystemMessageViewTag, Tag>,
BufferElement> {
return BufferElement{"Unknown"s};
}};
const BufferElement new_element = std::visit(message_visitor, message.parse());

std::lock_guard guard(m_buffer_mutex);
m_message_buffer.push_front(std::move(new_element));
}

mc::LogNode::BufferElement mc::LogNode::parse_channel_message(
midi::ChannelMessageView<false> message_view)
{
using namespace std::string_literals;
midi::tag_overloads message_visitor{
[](midi::NoteOnMessageViewTag, auto note_on) -> BufferElement {
return BufferElement{"Note On"s,
Expand All @@ -150,35 +183,33 @@ void mc::LogNode::message_received(std::span<const unsigned char> message_bytes)
fmt::format("Pressure: {}", poly_key_pressure.get_pressure())};
},
[](midi::AllSoundOffMessageViewTag, auto all_sound_off) -> BufferElement {
return BufferElement{"All Sound Off"s, all_sound_off.get_channel_human(), ""s, ""s};
return BufferElement{"All Sound Off"s, all_sound_off.get_channel_human()};
},
[](midi::ResetAllControllersMessageViewTag, auto reset_all_controllers) -> BufferElement {
return BufferElement{
"Reset All Controllers"s, reset_all_controllers.get_channel_human(), ""s, ""s};
return BufferElement{"Reset All Controllers"s,
reset_all_controllers.get_channel_human()};
},
[](midi::LocalControlMessageViewTag, auto local_control) -> BufferElement {
return BufferElement{"Local Control"s,
local_control.get_channel_human(),
local_control.get_value() ? "On"s : "Off"s,
""s};
local_control.get_value() ? "On"s : "Off"s};
},
[](midi::AllNotesOffMessageViewTag, auto all_notes_off) -> BufferElement {
return BufferElement{"All Notes Off"s, all_notes_off.get_channel_human(), ""s, ""s};
return BufferElement{"All Notes Off"s, all_notes_off.get_channel_human()};
},
[](midi::OmniModeOffMessageViewTag, auto omni_off) -> BufferElement {
return BufferElement{"Omni Mode Off"s, omni_off.get_channel_human(), ""s, ""s};
return BufferElement{"Omni Mode Off"s, omni_off.get_channel_human()};
},
[](midi::OmniModeOnMessageViewTag, auto omni_on) -> BufferElement {
return BufferElement{"Omni Mode On"s, omni_on.get_channel_human(), ""s, ""s};
return BufferElement{"Omni Mode On"s, omni_on.get_channel_human()};
},
[](midi::MonoModeOnMessageViewTag, auto mono_mode) -> BufferElement {
return BufferElement{"Mono Mode On"s,
mono_mode.get_channel_human(),
fmt::format("Channels: {}", mono_mode.get_num_channels()),
""s};
fmt::format("Channels: {}", mono_mode.get_num_channels())};
},
[](midi::PolyModeOnMessageViewTag, auto poly_mode) -> BufferElement {
return BufferElement{"Poly Mode On"s, poly_mode.get_channel_human(), ""s, ""s};
return BufferElement{"Poly Mode On"s, poly_mode.get_channel_human()};
},
[](midi::ControlChangeMessageViewTag, auto control_change) -> BufferElement {
return BufferElement{"Control Change"s,
Expand All @@ -191,26 +222,68 @@ void mc::LogNode::message_received(std::span<const unsigned char> message_bytes)
[](midi::ProgramChangeMessageViewTag, auto program_change) -> BufferElement {
return BufferElement{"Program Change"s,
program_change.get_channel_human(),
fmt::format("Program: {}", program_change.get_program_number()),
""s};
fmt::format("Program: {}", program_change.get_program_number())};
},
[](midi::ChannelPressureMessageViewTag, auto channel_pressure) -> BufferElement {
return BufferElement{"Channel Aftertouch"s,
channel_pressure.get_channel_human(),
fmt::format("Pressure: {}", channel_pressure.get_pressure()),
""s};
fmt::format("Pressure: {}", channel_pressure.get_pressure())};
},
[](midi::PitchBendMessageViewTag, auto pitch_bend) -> BufferElement {
return BufferElement{"Pitch bend"s,
pitch_bend.get_channel_human(),
fmt::format("Value: {}", pitch_bend.get_value_human()),
""s};
fmt::format("Value: {}", pitch_bend.get_value_human())};
},
[](auto, auto) -> BufferElement {
return BufferElement{"Unknown"s, std::nullopt, ""s, ""s};
return BufferElement{"Unknown channel message"s};
}};
const BufferElement new_element = std::visit(message_visitor, message.parse());
return std::visit(message_visitor, message_view.parse());
}

std::lock_guard guard(m_buffer_mutex);
m_message_buffer.push_front(std::move(new_element));
mc::LogNode::BufferElement mc::LogNode::parse_system_message(
midi::SystemMessageView<false> message_view)
{
using namespace std::string_literals;
midi::tag_overloads message_visitor{
[](midi::SystemExclusiveMessageViewTag, auto system_exclusive) -> BufferElement {
return BufferElement{"System Exclusive"s,
fmt::format("ID: {}", system_exclusive.get_manufacturer_id()),
fmt::format("{} bytes", system_exclusive.get_length())};
},
[](midi::TimeCodeQuarterFrameMessageViewTag, auto timecode_quarter) -> BufferElement {
return BufferElement{"Timecode Quarter Frame"s,
fmt::format("Type: {}", timecode_quarter.get_type()),
fmt::format("Values: {}", timecode_quarter.get_values())};
},
[](midi::SongPositionPointerMessageViewTag, auto song_position) -> BufferElement {
return BufferElement{"Song Position"s, std::to_string(song_position.get_position())};
},
[](midi::SongSelectMessageViewTag, auto song_select) -> BufferElement {
return BufferElement{"Song Select"s, std::to_string(song_select.get_song())};
},
[](midi::TuneRequestMessageViewTag, auto) -> BufferElement {
return BufferElement{"Tune Request"s};
},
[](midi::TimingClockMessageViewTag, auto) -> BufferElement {
return BufferElement{"Timing Clock"s};
},
[](midi::StartSequenceMessageViewTag, auto) -> BufferElement {
return BufferElement{"Start Sequence"s};
},
[](midi::ContinueSequenceMessageViewTag, auto) -> BufferElement {
return BufferElement{"Continue Sequence"s};
},
[](midi::StopSequenceMessageViewTag, auto) -> BufferElement {
return BufferElement{"Stop Sequence"s};
},
[](midi::ActiveSensingMessageViewTag, auto) -> BufferElement {
return BufferElement{"Active Sensing"s};
},
[](midi::ResetMessageViewTag, auto) -> BufferElement {
return BufferElement{"Reset everything"s};
},
[](auto, auto) -> BufferElement {
return BufferElement{"Unknown system message"s};
}};
return std::visit(message_visitor, message_view.parse());
}
24 changes: 20 additions & 4 deletions src/LogNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

namespace mc
{
namespace midi
{
template <bool>
class ChannelMessageView;
template <bool>
class SystemMessageView;
} // namespace midi

class LogNode final : public Node, private midi::GraphObserver
{
Expand Down Expand Up @@ -43,23 +50,32 @@ class LogNode final : public Node, private midi::GraphObserver

struct BufferElement
{
BufferElement(std::string&& name,
std::optional<int>&& channel,
std::string&& data_0,
std::string&& data_1)
explicit BufferElement(std::string&& name,
std::optional<int>&& channel = {},
std::string&& data_0 = {},
std::string&& data_1 = {})
: m_arrived(std::chrono::system_clock::now()), m_name(std::move(name)),
m_channel(std::move(channel)), m_data_0(std::move(data_0)),
m_data_1(std::move(data_1))
{
}

BufferElement(std::string&& name, std::string&& data_0, std::string&& data_1 = {})
: m_arrived(std::chrono::system_clock::now()), m_name(std::move(name)),
m_data_0(std::move(data_0)), m_data_1(std::move(data_1))
{
}

std::chrono::time_point<std::chrono::system_clock> m_arrived;
std::string m_name;
std::optional<int> m_channel;
std::string m_data_0;
std::string m_data_1;
};

static BufferElement parse_channel_message(midi::ChannelMessageView<false> message_view);
static BufferElement parse_system_message(midi::SystemMessageView<false> message_view);

std::mutex m_buffer_mutex;
std::deque<BufferElement> m_message_buffer;
LogMidiNode m_log_midi_node;
Expand Down
Loading

0 comments on commit e0e1dc5

Please sign in to comment.