268 lines
12 KiB
C
268 lines
12 KiB
C
#ifndef XTC_BACKEND_H
|
|
#define XTC_BACKEND_H
|
|
|
|
#include "xtc_engine.h"
|
|
#include "xtc_audio.h"
|
|
#include "xtc_midi.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Control-consumed interval maxima; quantized to 1e-6 linear, capped at 1000.
|
|
* Track tap is post-track controls/solo, pre-bus; bus tap is post-bus controls,
|
|
* both before the modular graph. Master is post-graph and transport envelope.
|
|
* Readers consume maxima, so use one control-thread reader at UI refresh rate. */
|
|
typedef struct { uint64_t id; float left, right; } xtc_track_peak;
|
|
typedef struct {
|
|
size_t count;
|
|
xtc_track_peak tracks[XTC_PROJECT_MAX_TRACKS];
|
|
float master_left, master_right;
|
|
} xtc_meter_snapshot;
|
|
|
|
typedef struct xtc_backend xtc_backend;
|
|
typedef int (*xtc_backend_port_visitor)(const char *name, void *context);
|
|
|
|
typedef enum {
|
|
XTC_BACKEND_JACK = 1
|
|
} xtc_backend_kind;
|
|
|
|
typedef struct {
|
|
xtc_backend_kind kind;
|
|
const char *client_name; /* Borrowed for open only; nonempty. */
|
|
size_t max_frames; /* 1..65536, at least the server's current block. */
|
|
size_t channel_count; /* 1 mono or 2 stereo output; input/recording remain mono. */
|
|
} xtc_backend_config;
|
|
|
|
typedef struct {
|
|
float peak_left, peak_right; /* Last-block output peaks, zero while stopped. */
|
|
unsigned int sample_rate;
|
|
unsigned int buffer_frames;
|
|
unsigned int xruns; /* Wraps modulo UINT_MAX + 1. */
|
|
unsigned int processed_blocks;
|
|
unsigned int midi_dropped; /* Malformed/overflowed input; unsigned wrap. */
|
|
unsigned int asset_issues; /* Unique missing/unreadable/unsupported assets. */
|
|
uint64_t sample_position; /* Successful callback frames; retained across stop/submit. */
|
|
unsigned int submitted_revision, active_revision;
|
|
int running;
|
|
int stopping; /* Graceful stop requested; collect completes deactivation. */
|
|
int server_lost;
|
|
int sample_rate_changed; /* Sticky: close/reopen and resubmit to recover. */
|
|
xtc_result process_result;
|
|
} xtc_backend_status;
|
|
|
|
/* All operations are serialized on one control thread. Public API contains
|
|
* no JACK types. JACK is optional at build time (otherwise UNSUPPORTED).
|
|
* Opens without starting a server, changing devices, or connecting ports.
|
|
* Returns IO if server/client setup fails. On failure *out_backend is NULL,
|
|
* except if cleanup itself fails: a non-NULL handle must be closed/retried;
|
|
* only close is permitted on that partially initialized handle. */
|
|
/**
|
|
* @brief Opens a JACK client and registers its ports without starting the server or connecting routes.
|
|
*
|
|
* @param config Backend kind, client name, block capacity, and output channel configuration.
|
|
* @param out_backend Receives the newly allocated backend; caller owns it on success.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_open(const xtc_backend_config *config, xtc_backend **out_backend);
|
|
/* Stop/close establish callback quiescence before state can be destroyed.
|
|
* On failure the handle remains owned by caller; retry close. NULL close OK. */
|
|
/**
|
|
* @brief Quiesces callbacks and releases the backend; failed cleanup leaves the handle owned by the caller.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_close(xtc_backend *backend);
|
|
/**
|
|
* @brief Activates the backend and enables audio processing.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_start(xtc_backend *backend);
|
|
/* Activate with transport held until chosen MIDI routes are established.
|
|
* NULL/empty routes mean none. Control-thread only; failed routes stop playback.
|
|
* Avoids losing notes at position zero while JACK publishes/connects ports. */
|
|
xtc_result xtc_backend_start_routed(xtc_backend *,const char *input_source,const char *output_destination);
|
|
/**
|
|
* @brief Deactivates the backend and establishes callback quiescence.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_stop(xtc_backend *backend);
|
|
/* Configure while stopped, before preparing a project. Default zero preserves
|
|
* raw rendering/immediate stop. GUI uses 5 ms (rate/200). Frames <=65536.
|
|
* Applies source-boundary fades and a master start/stop gain ramp. */
|
|
xtc_result xtc_backend_set_transition_frames(xtc_backend *backend, size_t frames);
|
|
/* Non-blocking graceful stop request; not callback quiescence. Repeated calls
|
|
* are idempotent. Process finishes the ramp, then emits silence/holds position.
|
|
* Poll/collect on the control thread to deactivate. Recorder must be detached.
|
|
* Immediate stop/close remain the escape path if callbacks cease or errors occur. */
|
|
xtc_result xtc_backend_request_stop(xtc_backend *backend);
|
|
|
|
/* Stopped only; changes transport clock, not oscillator phase. */
|
|
/**
|
|
* @brief Changes the stopped backend's sample position and resets MIDI voices.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param sample Absolute sample position.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_seek(xtc_backend *backend, uint64_t sample);
|
|
/* Stopped-only loop [start,end) in samples. Enabled loops require >=64 samples
|
|
* and cannot be combined with recording. Callback splits at exact boundaries;
|
|
* live MIDI offsets remain relative to the JACK block. */
|
|
xtc_result xtc_backend_set_loop(xtc_backend *backend, uint64_t start, uint64_t end, int enabled);
|
|
/* Copies graph. While running, capacity means pending slot busy.
|
|
* While stopped, transactionally replaces all retained plans (counters/revisions
|
|
* restart); failed compilation leaves the previous engine intact. */
|
|
/**
|
|
* @brief Compiles and submits a graph while preserving the previous engine on failure.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param graph Graph model; borrowed for this call.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_submit(xtc_backend *backend, const xtc_graph *graph);
|
|
/* Stopped only. Preloads immutable audio and submits graph before committing.
|
|
* Asset issues are silent and reported in status/asset_issue. Other failures
|
|
* retain the previous plans. Arrangement edits are adopted on the next prepare. */
|
|
/**
|
|
* @brief Preloads project audio and MIDI and submits its graph while stopped.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param project Project model; borrowed for this call.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_prepare_project(xtc_backend *backend, const xtc_project *project);
|
|
/**
|
|
* @brief Returns the first asset issue path, or an empty string when none is available.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @return Borrowed path string, or an empty string if no issue is available.
|
|
*/
|
|
const char *xtc_backend_asset_issue(const xtc_backend *backend);
|
|
/* Borrowed recorder, set/detach only while stopped. Stop before finish/destroy. */
|
|
/* Control-thread panic is delivered at a block boundary via lock-free counter.
|
|
* Stops, seeks, xruns and event overflow also clear instrument voices. */
|
|
/**
|
|
* @brief Requests an instrument panic at the next audio block boundary.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_panic(xtc_backend *backend);
|
|
/**
|
|
* @brief Returns the borrowed name of the backend's MIDI input port.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param out_name Receives the name.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_midi_port_name(const xtc_backend *backend, const char **out_name);
|
|
/* MIDI counterparts. direction is local for naming/routing, remote for visiting.
|
|
* Routing requires an active backend. No server starts or implicit device routes.
|
|
* Port names are JACK/PipeWire names; physical ALSA devices need host exposure. */
|
|
xtc_result xtc_backend_midi_name(const xtc_backend *,xtc_port_direction,const char **);
|
|
xtc_result xtc_backend_visit_midi_ports(xtc_backend *,xtc_port_direction,xtc_backend_port_visitor,void *);
|
|
xtc_result xtc_backend_route_midi(xtc_backend *,xtc_port_direction,const char *,int disconnect);
|
|
/* Stopped only. Input channel/output channel -1 preserves all/original channels,
|
|
* otherwise 0..15. thru=1 forwards supported live messages to MIDI output. */
|
|
xtc_result xtc_backend_set_midi_options(xtc_backend *,int input_channel,int output_channel,int thru);
|
|
|
|
/**
|
|
* @brief Attaches or detaches a borrowed recorder while the backend is stopped.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param recorder Recorder handle.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_set_recorder(xtc_backend *backend, xtc_recorder *recorder);
|
|
/**
|
|
* @brief Completes acknowledged fades and reclaims retired plans on the control thread.
|
|
*
|
|
* @param backend Backend handle.
|
|
*/
|
|
void xtc_backend_collect(xtc_backend *backend);
|
|
/* Snapshot fields are individually coherent, not a transactional snapshot. */
|
|
/**
|
|
* @brief Copies individually coherent backend counters and transport state.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param out_status Receives the status.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_get_status(const xtc_backend *backend, xtc_backend_status *out_status);
|
|
/* Borrowed names valid until close. Direction is the client's own port. */
|
|
/* Output channel 0 is legacy output, channel 1 is output_right in stereo. */
|
|
/**
|
|
* @brief Returns the borrowed name of an output channel port.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param channel Output channel index: 0 for primary, 1 for stereo right.
|
|
* @param out_name Receives the name.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_output_name(const xtc_backend * backend, size_t channel, const char **out_name);
|
|
/**
|
|
* @brief Returns the borrowed name of the mono input or primary output port.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param direction Local port direction.
|
|
* @param out_name Receives the name.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_port_name(const xtc_backend *backend, xtc_port_direction direction, const char **out_name);
|
|
/* Enumerates available mono audio ports (devices and software routes). Visitor
|
|
* receives a borrowed name valid only during call; return nonzero to stop.
|
|
* Control-thread only. JACK NULL list means no matching ports. */
|
|
/**
|
|
* @brief Inspects one available audio port during control-thread enumeration.
|
|
*
|
|
* @param name Borrowed port name, valid only during this callback.
|
|
* @param context Opaque pointer supplied to xtc_backend_visit_ports().
|
|
* @return Nonzero to stop enumeration, zero to continue.
|
|
*/
|
|
|
|
/**
|
|
* @brief Visits available audio ports matching the requested direction until the visitor stops.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param direction Local port direction.
|
|
* @param visitor Visitor called with each borrowed port name.
|
|
* @param context Opaque callback context.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_visit_ports(xtc_backend *backend, xtc_port_direction direction, xtc_backend_port_visitor visitor,
|
|
void *context);
|
|
/* Connect/disconnect this client's port with a remote opposite-direction port.
|
|
* own_direction INPUT receives remote output; OUTPUT sends to remote input.
|
|
* Explicit user choice only; no automatic physical routing. */
|
|
/**
|
|
* @brief Connects this client's port to a remote port with the opposite direction.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param own_direction Local port direction.
|
|
* @param remote_name Borrowed remote port name.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_connect(xtc_backend *backend, xtc_port_direction own_direction, const char *remote_name);
|
|
/**
|
|
* @brief Disconnects this client's port from a remote port.
|
|
*
|
|
* @param backend Backend handle.
|
|
* @param own_direction Local port direction.
|
|
* @param remote_name Borrowed remote port name.
|
|
* @return XTC_OK on success, or an error code describing the failure.
|
|
*/
|
|
xtc_result xtc_backend_disconnect(xtc_backend *backend, xtc_port_direction own_direction, const char *remote_name);
|
|
|
|
xtc_result xtc_backend_read_meters(xtc_backend *backend, xtc_meter_snapshot *out);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|