5fd5946ff6
C++ backend (fully implemented): - MidiMapper: CC processing, mapping table, JSON persistence, learn mode - MidiLearnMode: 3-step learn workflow state machine - MixerEngine::processMidiEvent() wired into AudioHost MIDI pipeline - MixerApi + PiPedalSocket: all WS handlers (getMidiMappings, setMidiLearnMode, setMidiLearnTarget, commitMidiLearn, etc.) React frontend (new): - MidiMappingPanel: dialog with learn mode toggle, CC capture polling, commit workflow, current mappings list with delete, manual add - MixerPage: MIDI button in toolbar, learn mode state management - ChannelStrip + MasterBus: learn mode callbacks on fader/mute/solo touch
67 lines
2.1 KiB
C++
67 lines
2.1 KiB
C++
// Copyright (c) 2026 Ourpad Network
|
|
// See LICENSE file in the project root for full license text.
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <mutex>
|
|
#include "MidiMapper.hpp"
|
|
|
|
namespace pipedal {
|
|
|
|
/// MIDI Learn mode state machine.
|
|
///
|
|
/// Tracks the three-step learn workflow:
|
|
/// 1. User enables learn mode and touches a UI control (setPendingTarget)
|
|
/// 2. User moves a hardware fader — the CC event is captured (captureEvent)
|
|
/// 3. User confirms — a new MidiMappingEntry is created (commitMapping)
|
|
///
|
|
class MidiLearnMode {
|
|
public:
|
|
MidiLearnMode();
|
|
~MidiLearnMode();
|
|
|
|
/// Enable or disable learn mode.
|
|
void setEnabled(bool enabled);
|
|
bool isEnabled() const { return enabled_; }
|
|
|
|
/// Set the mixer parameter that should receive the next learned mapping.
|
|
/// Call this when the user touches a UI control while in learn mode.
|
|
void setPendingTarget(MidiTargetType type, int64_t id);
|
|
|
|
/// Get the current pending target.
|
|
bool getPendingTarget(MidiTargetType& outType, int64_t& outId) const;
|
|
|
|
/// Capture a MIDI CC event while in learn mode.
|
|
/// Call this from the RT audio thread when processEvent sees a CC.
|
|
void captureEvent(int midiChannel, int ccNumber);
|
|
|
|
/// Check if a CC event has been captured since learn mode was entered
|
|
/// or since the last clear().
|
|
bool hasCapturedEvent() const;
|
|
|
|
/// Get the last captured CC event info.
|
|
/// Returns true if an event was captured.
|
|
bool getCapturedEvent(int& outMidiChannel, int& outCcNumber) const;
|
|
|
|
/// Build a MidiMappingEntry from pending target + captured event.
|
|
/// Clears the captured event after building (avoids stale recomit).
|
|
MidiMappingEntry buildMapping() const;
|
|
|
|
/// Clear captured event without committing.
|
|
void clearCapturedEvent();
|
|
|
|
/// Reset all learn state.
|
|
void reset();
|
|
|
|
private:
|
|
bool enabled_ = false;
|
|
MidiTargetType pendingTargetType_ = MidiTargetType::ChannelVolume;
|
|
int64_t pendingTargetId_ = 0;
|
|
int capturedMidiChannel_ = -1;
|
|
int capturedCcNumber_ = -1;
|
|
mutable std::mutex mutex_;
|
|
};
|
|
|
|
} // namespace pipedal
|