From b4d97006a52c0dc099e73b426a71d8fc87309747 Mon Sep 17 00:00:00 2001 From: Gauthier Segay Date: Tue, 10 May 2022 17:19:49 +0200 Subject: [PATCH] initialize data structures for pitchbend and CC support in MidiDrop, nothing is handled in the UI yet, but it parses the MidiTrackEvent objects. --- .../Midi/Commands/AddNote.cpp | 2 +- .../Midi/Commands/AddNote.hpp | 4 +- .../score-plugin-midi/Midi/MidiDrop.cpp | 16 ++-- .../score-plugin-midi/Midi/MidiDrop.hpp | 92 ++++++++++++++++++- .../score-plugin-midi/Midi/MidiPresenter.cpp | 7 +- 5 files changed, 107 insertions(+), 14 deletions(-) diff --git a/src/plugins/score-plugin-midi/Midi/Commands/AddNote.cpp b/src/plugins/score-plugin-midi/Midi/Commands/AddNote.cpp index dcd594892b..8da7b56ad1 100644 --- a/src/plugins/score-plugin-midi/Midi/Commands/AddNote.cpp +++ b/src/plugins/score-plugin-midi/Midi/Commands/AddNote.cpp @@ -69,7 +69,7 @@ void AddNotes::deserializeImpl(DataStreamOutput& s) ReplaceNotes::ReplaceNotes( const ProcessModel& model, - const std::vector& n, + const MidiTrackNotes& n, int min, int max, TimeVal d) diff --git a/src/plugins/score-plugin-midi/Midi/Commands/AddNote.hpp b/src/plugins/score-plugin-midi/Midi/Commands/AddNote.hpp index 75fc3419ed..5f418ef3dc 100644 --- a/src/plugins/score-plugin-midi/Midi/Commands/AddNote.hpp +++ b/src/plugins/score-plugin-midi/Midi/Commands/AddNote.hpp @@ -1,6 +1,8 @@ #pragma once + #include #include +#include "Midi/MidiDrop.hpp" #include #include @@ -52,7 +54,7 @@ class SCORE_PLUGIN_MIDI_EXPORT ReplaceNotes final : public score::Command public: ReplaceNotes( const ProcessModel& model, - const std::vector& note, + const MidiTrackNotes& note, int min, int max, TimeVal dur); diff --git a/src/plugins/score-plugin-midi/Midi/MidiDrop.cpp b/src/plugins/score-plugin-midi/Midi/MidiDrop.cpp index b320873f3b..339f7c434b 100644 --- a/src/plugins/score-plugin-midi/Midi/MidiDrop.cpp +++ b/src/plugins/score-plugin-midi/Midi/MidiDrop.cpp @@ -65,11 +65,8 @@ void DropHandler::dropData( const double ratio = song_t / actualDuration.msec(); if (ratio != 1.) { - for (auto& note : track.notes) - { - note.setStart(ratio * note.start()); - note.setDuration(ratio * note.duration()); - } + track.trackEvents.apply_scale_ratio(ratio); + track.notes.apply_scale_ratio(ratio); } disp.submit(new Midi::ReplaceNotes{ midi, track.notes, track.min, track.max, actualDuration}); @@ -389,6 +386,13 @@ void parseEvent(const libremidi::track_event& ev, MidiTrack& nv, midi_note_map& nv.notes.push_back(note); } notes.erase(ev.m.bytes[1]); + + break; + } + case libremidi::message_type::CONTROL_CHANGE: + { + const auto& cc = ControllerData::make_cc(ev.m.get_channel() - 1, ev.m.bytes[1], ev.m.bytes[2]); + nv.trackEvents.push_back(delta, tick, total, cc); break; } default: @@ -487,7 +491,7 @@ MidiTrack::parse(const QByteArray& dat, const score::DocumentContext& ctx) tick += ev.tick; parseEvent(ev, nv, notes, delta, tick, total); } - if (nv.notes.size() > 0) + if (nv.notes.size() > 0 || nv.trackEvents.size() > 0) m.tracks.push_back(std::move(nv)); } break; diff --git a/src/plugins/score-plugin-midi/Midi/MidiDrop.hpp b/src/plugins/score-plugin-midi/Midi/MidiDrop.hpp index e3b37dc095..cec9c1473e 100644 --- a/src/plugins/score-plugin-midi/Midi/MidiDrop.hpp +++ b/src/plugins/score-plugin-midi/Midi/MidiDrop.hpp @@ -18,11 +18,101 @@ class DropHandler final : public Process::ProcessDropHandler const score::DocumentContext& ctx) const noexcept override; }; +struct PitchbendData{ + int16_t bend; +}; +struct ControllerData { + midi_size_t channel; + midi_size_t number; + midi_size_t value; + static ControllerData make_cc(const midi_size_t channel, const midi_size_t controller, const midi_size_t value) + { + SCORE_ASSERT(channel >= 0 && channel < 16); + return ControllerData{channel, controller, value}; + } +}; + +struct NoteOnData { + midi_size_t channel; + midi_size_t note; + midi_size_t velocity; +}; +struct NoteOffData { + midi_size_t channel; + midi_size_t note; + midi_size_t velocity; +}; +struct MidiTrackEvent { + static MidiTrackEvent make_note_off(const double start, const midi_size_t ch, const midi_size_t n, const midi_size_t v){ + return MidiTrackEvent{m_start: start, m_message: Midi::NoteOffData{channel: ch, note: n, velocity: v}}; + } + static MidiTrackEvent make_note_on(const double start, const midi_size_t ch, const midi_size_t n, const midi_size_t v){ + return MidiTrackEvent{m_start: start, m_message: Midi::NoteOnData{channel: ch, note: n, velocity: v}}; + } + double m_start{}; + + void setStart(const double start){ m_start = start; } + const double start(){return m_start; } + std::variant m_message; +}; + +struct MidiTrackEvents { + void push_back(double delta, int tick, double total, Midi::ControllerData c){ + const double start = delta * (tick / total); + trackEvents.push_back(MidiTrackEvent{m_start:start, m_message: c}); + } + + void push_back(double delta, int tick, double total, Midi::NoteOnData n){ + const double start = delta * (tick / total); + trackEvents.push_back(MidiTrackEvent{m_start:start, m_message: n}); + } + + void push_back(double delta, int tick, double total, Midi::NoteOffData n){ + const double start = delta * (tick / total); + trackEvents.push_back(MidiTrackEvent{m_start:start, m_message: n}); + } + + void apply_scale_ratio(const double ratio){ + for (auto& event : trackEvents) + { + event.setStart(ratio * event.start()); + } + } + auto size() const { return trackEvents.size(); } + std::vector trackEvents; +}; + +struct MidiTrackNotes { + std::vector notes; + void push_back(Midi::NoteData note){ + notes.push_back(note); + } + + auto begin() { return notes.begin(); } + auto end() { return notes.end(); } + auto cbegin() const { return notes.begin(); } + auto cend() const { return notes.end(); } + auto begin() const { return notes.begin(); } + auto end() const { return notes.end(); } + + auto size() const { return notes.size(); } + auto empty() const { return notes.empty(); } + void apply_scale_ratio(const double ratio){ + for (auto& note : notes) + { + note.setStart(ratio * note.start()); + note.setDuration(ratio * note.duration()); + } + } +}; + + struct MidiTrack { QString name; - std::vector notes; + MidiTrackNotes notes; + MidiTrackEvents trackEvents; int min{127}, max{0}; struct MidiSong diff --git a/src/plugins/score-plugin-midi/Midi/MidiPresenter.cpp b/src/plugins/score-plugin-midi/Midi/MidiPresenter.cpp index 9a91133710..baeea1bc1d 100644 --- a/src/plugins/score-plugin-midi/Midi/MidiPresenter.cpp +++ b/src/plugins/score-plugin-midi/Midi/MidiPresenter.cpp @@ -372,11 +372,8 @@ void Presenter::on_drop(const QPointF& pos, const QMimeData& md) // Scale notes so that the durations are relative to the ratio of the song // duration & constraint duration const double ratio = song.durationInMs / model().duration().msec(); - for (auto& note : track.notes) - { - note.setStart(ratio * note.start()); - note.setDuration(ratio * note.duration()); - } + track.notes.apply_scale_ratio(ratio); + track.trackEvents.apply_scale_ratio(ratio); disp.submit( model(), track.notes, track.min, track.max, model().duration()); }