xtc/src/gui/mixer_widget.hpp

199 lines
6.8 KiB
C++
Raw Normal View History

#ifndef XTC_MIXER_WIDGET_HPP
#define XTC_MIXER_WIDGET_HPP
#include "xtc/xtc_mixer.h"
#include <FL/Fl_Group.H>
#include <chrono>
#include <vector>
2026-10-27 01:37:21 +01:00
class Fl_Choice;
class Fl_Value_Slider;
class Fl_Check_Button;
class Fl_Progress;
class Fl_Value_Input;
class AutomationLane;
2026-10-27 01:37:21 +01:00
class MixerWidget : public Fl_Group {
public:
/**
* @brief Prepares a model edit using the widget's opaque callback context.
*
* @return XTC_OK to allow the edit, or an error to cancel it.
*/
using BeforeEdit = xtc_result (*)(void *);
/**
* @brief Creates the mixer panel and its child controls.
*
* Builds the track chooser, gain/pan sliders, mute/solo buttons, output
* meters, automation controls, and lane, then displays the given project.
*
* @param x Left edge in parent coordinates.
* @param y Top edge in parent coordinates.
* @param w Widget width in pixels.
* @param h Widget height in pixels.
* @param p Project to display; borrowed and must outlive its use.
* @param before Callback invoked before each edit; may be nullptr.
* @param context Opaque pointer forwarded to before.
*/
MixerWidget(int x, int y, int w, int h, xtc_project * p, BeforeEdit before, void * context);
/**
* @brief Displays a different project and refreshes the controls.
*
* The current track selection is preserved only when the same project
* pointer is passed again. The project is borrowed and must outlive use.
*
* @param p Project to display; must remain valid while shown.
*/
void set_project(xtc_project * p);
/**
* @brief Updates the left and right output meters.
*
* Meter values are clamped to 1.0, while the over-range color is chosen
* from the unclamped level.
*
* @param left Left-channel peak level.
* @param right Right-channel peak level.
*/
void peaks(float left, float right);
/**
* @brief Returns the ID of the track selected in the track chooser.
*
* @return Selected track ID, or UINT64_MAX when the chooser selection does
* not resolve to a project track.
*/
uint64_t selected_track() const;
2026-10-27 01:37:21 +01:00
/**
* @brief Returns the project currently displayed by the widget.
*
* @return Borrowed project pointer, possibly nullptr; the widget does not
* own it.
*/
xtc_project *project() const
{
return project_;
}
2026-10-27 01:37:21 +01:00
/**
* @brief Returns the automation parameter selected in the chooser.
*
* @return XTC_AUTOMATION_PAN when the chooser selects "Pan", otherwise
* XTC_AUTOMATION_GAIN.
*/
xtc_automation_parameter parameter() const;
/**
* @brief Returns the first tick shown by the automation lane.
*
* @return Clamped first tick in project ticks, or 0 when the input value is
* not finite.
*/
uint64_t lane_start() const;
/**
* @brief Adds, replaces, or removes an automation point.
*
* The constructor's before-edit callback runs first; the edit is skipped
* if it returns an error. On success the widget callback is invoked and
* the controls are refreshed.
*
* @param tick Automation tick to modify; must be within the project range.
* @param value New value; ignored when remove is true.
* @param remove When true, removes the point instead of setting it.
* @return XTC_OK on success, or the before-edit or project mutation error.
*/
xtc_result point(uint64_t tick, float value, bool remove = false);
/**
* @brief Applies gain, pan, mute, and solo to the selected track.
*
* The constructor's before-edit callback runs first; the edit is skipped
* if it returns an error. On success the widget callback is invoked and
* the controls are refreshed.
*
* @param gain Linear gain in the range 0..4.
* @param pan Pan position in the range -1 (left)..1 (right).
* @param mute Mute state: 0 or 1.
* @param solo Solo state: 0 or 1.
* @return XTC_OK on success, or the before-edit or project mutation error.
*/
xtc_result add_bus();
xtc_result route(uint64_t bus);
bool select_track(uint64_t id);
void track_peaks(float left, float right);
void reset_meters();
bool master_clipped() const { return master_[0].clipped || master_[1].clipped; }
xtc_result mix(float gain, float pan, int mute, int solo);
/**
* @brief Handles keyboard shortcuts and forwards other events.
*
* M and S toggle mute and solo, Left/Right adjust gain (Shift adjusts pan),
* and Up/Down change the selected track. Modified key presses fall through.
*
* @param event FLTK event code.
* @return 1 when the event was consumed, otherwise the Fl_Group result.
*/
int handle(int event) override;
private:
xtc_project *project_;
BeforeEdit before_;
void *context_;
Fl_Choice *tracks_, *parameter_, *routes_;
std::vector<uint64_t> route_ids_;
Fl_Value_Slider *gain_, *pan_;
Fl_Check_Button *mute_, *solo_;
Fl_Progress *left_, *right_, *track_left_, *track_right_;
xtc_peak_meter master_[2]{}, track_meter_[2]{};
uint64_t meter_track_ = UINT64_MAX;
std::chrono::steady_clock::time_point peak_time_ = std::chrono::steady_clock::now();
double meter_elapsed_ = 0.1;
void display_peaks(Fl_Progress *left, Fl_Progress *right, xtc_peak_meter *meters, const char *prefix);
Fl_Value_Input *start_;
AutomationLane *lane_;
/**
* @brief Reports an edit result and refreshes the controls.
*
* A successful result invokes the widget callback so the owner can mark
* the project dirty; a failure shows a modal alert. The controls are
* resynchronized in both cases.
*
* @param r Result of the attempted edit.
* @return The same result passed in.
*/
xtc_result changed(xtc_result r);
/**
* @brief Synchronizes the child controls with the selected track.
*
* Controls are deactivated when no valid track is selected. Gain falls
* back to 1, and the remaining values come from the track info or zero when
* unresolved.
*/
void selection();
/**
* @brief FLTK callback for the gain, pan, mute, and solo controls.
*
* Reads all four controls and applies them together to the selected track
* through mix().
*
* @param widget Widget that triggered the callback; unused.
* @param c Opaque MixerWidget pointer supplied as callback context.
*/
static void control(Fl_Widget * widget, void * c);
/**
* @brief FLTK callback for the track, parameter, and first-tick controls.
*
* @param widget Widget that triggered the callback; unused.
* @param c Opaque MixerWidget pointer supplied as callback context.
*/
static void select(Fl_Widget * widget, void * c);
};
#endif