202 lines
6.9 KiB
C++
202 lines
6.9 KiB
C++
#ifndef XTC_MIXER_WIDGET_HPP
|
|
#define XTC_MIXER_WIDGET_HPP
|
|
#include "xtc/xtc_mixer.h"
|
|
#include "xtc/xtc_backend.h"
|
|
#include <FL/Fl_Group.H>
|
|
#include <chrono>
|
|
#include <vector>
|
|
|
|
class Fl_Choice;
|
|
class Fl_Button;
|
|
class Fl_Value_Slider;
|
|
class Fl_Check_Button;
|
|
class Fl_Progress;
|
|
class Fl_Value_Input;
|
|
class AutomationLane;
|
|
class MixerStrip;
|
|
class Fl_Scroll;
|
|
class Fl_Box;
|
|
|
|
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, channel strips, pan knobs, 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;
|
|
|
|
/**
|
|
* @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_;
|
|
}
|
|
|
|
/**
|
|
* @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);
|
|
/* One control-thread snapshot updates all strips; missing taps decay to silence. */
|
|
void meters(const xtc_meter_snapshot &snapshot);
|
|
Fl_Group *strip(uint64_t id) const;
|
|
size_t strip_count() const { return strips_.size(); }
|
|
void resize(int x, int y, int w, int h) override;
|
|
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_, *mode_;
|
|
std::vector<uint64_t> route_ids_;
|
|
Fl_Progress *left_, *right_;
|
|
Fl_Scroll *bank_;
|
|
Fl_Group *master_panel_;
|
|
Fl_Button *bus_, *reset_;
|
|
Fl_Box *hint_, *master_readout_;
|
|
std::vector<MixerStrip *> strips_;
|
|
void sync_strips(bool reset = false);
|
|
void layout();
|
|
xtc_peak_meter master_[2]{};
|
|
uint64_t selected_id_ = 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.
|
|
*
|
|
* Reconcile strip controls with stable model IDs and the selected
|
|
* automation target.
|
|
*/
|
|
void selection();
|
|
|
|
/**
|
|
* @brief FLTK callback for the track, parameter, and first-tick controls.
|
|
*
|
|
* @param widget Track chooser or automation control that changed.
|
|
* @param c Opaque MixerWidget pointer supplied as callback context.
|
|
*/
|
|
static void select(Fl_Widget * widget, void * c);
|
|
};
|
|
#endif
|