162 lines
7.2 KiB
C
162 lines
7.2 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include "xtc/xtc.h"
|
|
#include "xtc/xtc_version.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "xtc/xtc_project.h"
|
|
#include "xtc/xtc_audio.h"
|
|
#include "xtc/xtc_midi.h"
|
|
#include <limits.h>
|
|
#include <inttypes.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include "xtc/xtc_plugin.h"
|
|
|
|
/* Dependency inspection checks readable regular files, never plugin code or
|
|
* audio contents. Escape untrusted path/label bytes in terminal output. */
|
|
static void quoted(const char *text)
|
|
{
|
|
const unsigned char *p = (const unsigned char *)text;
|
|
putchar('"');
|
|
for (; *p; ++p) {
|
|
if (*p == '"' || *p == '\\') printf("\\%c",*p);
|
|
else if (*p < 32 || *p == 127) printf("\\x%02x",(unsigned int)*p);
|
|
else putchar(*p);
|
|
}
|
|
putchar('"');
|
|
}
|
|
static int readable_file(const char *path)
|
|
{
|
|
struct stat info;
|
|
return stat(path,&info) == 0 && S_ISREG(info.st_mode) && access(path,R_OK) == 0;
|
|
}
|
|
static int inspect(const xtc_project *project, uint64_t version)
|
|
{
|
|
size_t tracks = 0, clips = 0, nodes = 0, edges = 0, i, missing = 0;
|
|
const xtc_graph *graph = xtc_project_graph(project);
|
|
xtc_project_get_counts(project,&tracks,&clips);
|
|
xtc_graph_get_counts(graph,&nodes,&edges);
|
|
printf("Project format %" PRIu64 " (writer %u): %zu tracks/buses, %zu clips, %zu graph nodes, %zu edges.\n",
|
|
version,XTC_PROJECT_FORMAT_VERSION,tracks,clips,nodes,edges);
|
|
for (i = 0; i < clips; ++i) {
|
|
xtc_clip_info clip;
|
|
xtc_project_get_clip(project,i,&clip);
|
|
if (clip.asset_path[0]) {
|
|
int available = readable_file(clip.asset_path);
|
|
printf("Media clip %" PRIu64 ": %s ",clip.id,available ? "available" : "missing/unreadable");
|
|
quoted(clip.asset_path); putchar('\n');
|
|
if (!available) ++missing;
|
|
}
|
|
}
|
|
for (i = 0; i < nodes; ++i) {
|
|
xtc_node_info node; xtc_plugin_spec spec;
|
|
xtc_graph_get_node(graph,i,&node);
|
|
if (xtc_graph_get_plugin(graph,node.id,&spec) == XTC_OK) {
|
|
int available = readable_file(spec.path);
|
|
printf("%s node %zu ID %u descriptor %u ",xtc_plugin_format_name(spec.format),node.id,spec.unique_id,spec.index);
|
|
if (spec.identifier[0]) { quoted(spec.identifier); putchar(' '); }
|
|
quoted(spec.label); printf(": %s ",available ? "available" : "missing/unreadable");
|
|
quoted(spec.path); putchar('\n');
|
|
if (!available) ++missing;
|
|
}
|
|
}
|
|
for (i = 0; i < tracks; ++i) {
|
|
xtc_track_info track; xtc_plugin_spec spec;
|
|
xtc_project_get_track(project,i,&track);
|
|
if (xtc_project_get_instrument(project,track.id,&spec) == XTC_OK) {
|
|
int available = readable_file(spec.path);
|
|
printf("%s instrument track %" PRIu64 " descriptor %u ",xtc_plugin_format_name(spec.format),track.id,spec.index);
|
|
quoted(spec.identifier); putchar(' '); quoted(spec.label);
|
|
printf(": %s ",available ? "available" : "missing/unreadable"); quoted(spec.path); putchar('\n');
|
|
if (!available) ++missing;
|
|
}
|
|
}
|
|
printf("Dependency references missing/unreadable: %zu.\n",missing);
|
|
puts("File availability only: WAV contents, plugin identity/initialization, JACK and hardware not checked; no plugin code executed.");
|
|
return missing ? 2 : EXIT_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Runs the xtc-check command-line entry point.
|
|
*
|
|
* Supports version/help, metadata validation and dependency inspection. With no arguments it
|
|
* creates and destroys the application shell to check core startup/shutdown.
|
|
* Any other argument count prints usage to stderr.
|
|
*
|
|
* @param argc Number of command-line arguments, including the program name.
|
|
* @param argv Command-line argument vector; argv[0] is the program name.
|
|
* @return EXIT_SUCCESS on success, or EXIT_FAILURE for invalid usage,
|
|
* validation failure, or core initialization failure.
|
|
*/
|
|
int main(int argc, char **argv)
|
|
{
|
|
if (argc == 2 && !strcmp(argv[1], "--version")) {
|
|
printf("%s %s\n", XTC_PROJECT_NAME, XTC_VERSION_STRING);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc == 2 && !strcmp(argv[1], "--diagnose")) {
|
|
unsigned int features = xtc_build_features();
|
|
printf("xtc %s; %zu-bit process\nProject formats: 1..%u\nJACK compiled: %s\nLADSPA compiled: %s\nCLAP/VST2/VST3: compiled (mono effects/instruments, default configuration)\n"
|
|
"Limits: 256 graph nodes (64/project), %u tracks, %u clips, %u notes, 65536 frames/block\n"
|
|
"No server, device or plugin probed. Runtime errors appear in GUI status/stderr.\n",
|
|
XTC_VERSION_STRING,sizeof(void *)*CHAR_BIT,XTC_PROJECT_FORMAT_VERSION,
|
|
features & XTC_FEATURE_JACK ? "yes" : "no",features & XTC_FEATURE_LADSPA ? "yes" : "no",
|
|
XTC_PROJECT_MAX_TRACKS,XTC_PROJECT_MAX_CLIPS,XTC_PROJECT_MAX_NOTES);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc == 2 && !strcmp(argv[1], "--help")) {
|
|
puts("Usage: xtc-check [--version | --help | --diagnose | --validate PROJECT | --inspect PROJECT | --recover-recording TEMP NEW.wav]\nNo arguments checks core startup/shutdown. "
|
|
"Validation checks metadata only.");
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc == 4 && !strcmp(argv[1], "--recover-recording")) {
|
|
xtc_result result = xtc_recorder_recover(argv[2], argv[3]);
|
|
if (result != XTC_OK) {
|
|
fprintf(stderr, "Recording recovery failed: %s. Source retained; choose a new writable destination.\n",
|
|
xtc_result_string(result));
|
|
return EXIT_FAILURE;
|
|
}
|
|
puts("Complete recorded frames recovered; source retained.");
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc == 3 && (!strcmp(argv[1], "--validate") || !strcmp(argv[1], "--inspect"))) {
|
|
xtc_project *project = NULL;
|
|
xtc_project_diagnostic diagnostic = {0};
|
|
xtc_result result = xtc_project_create(&project);
|
|
if (result == XTC_OK) result = xtc_project_load_diagnostic(project,argv[2],&diagnostic);
|
|
if (result != XTC_OK) {
|
|
fprintf(stderr,"Project validation failed: %s; line %zu, %s: %s\n",xtc_result_string(result),
|
|
diagnostic.line,diagnostic.record,diagnostic.message);
|
|
xtc_project_destroy(project);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (!strcmp(argv[1],"--inspect")) {
|
|
int code = inspect(project,diagnostic.format_version);
|
|
xtc_project_destroy(project);
|
|
return code;
|
|
}
|
|
xtc_project_destroy(project);
|
|
puts("Project metadata valid (external assets not loaded).");
|
|
return EXIT_SUCCESS;
|
|
}
|
|
if (argc != 1) {
|
|
fputs("Usage: xtc-check [--version | --help | --diagnose | --validate PROJECT | --inspect PROJECT | --recover-recording TEMP NEW.wav]\n", stderr);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
xtc_app *app = NULL;
|
|
xtc_result result = xtc_app_create(&app);
|
|
|
|
if (result != XTC_OK) {
|
|
(void)fprintf(stderr, "Application initialization failed: %s\n", xtc_result_string(result));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
xtc_app_destroy(app);
|
|
if (printf("%s %s: core startup/shutdown OK\n", XTC_PROJECT_NAME, XTC_VERSION_STRING) < 0) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|