xtc/examples/quality_preview.c

70 lines
3.5 KiB
C

/* Generate matched raw/smoothed previews for human listening; never plays audio.
* Usage: quality-preview /absolute/path/prefix (writes prefix-{raw,smooth}.wav). */
#include "xtc/xtc_audio.h"
#include "xtc/xtc_midi.h"
#include "xtc/xtc_dsp.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static xtc_result preview(const char *prefix, int smooth)
{
xtc_project *project = NULL;
xtc_midi_plan *midi = NULL;
xtc_recorder *recorder = NULL;
xtc_gain_ramp ramp;
uint64_t track, clip, note, position;
char path[1024];
xtc_result result;
int n = snprintf(path, sizeof(path), "%s-%s.wav", prefix, smooth ? "smooth" : "raw");
if (n < 0 || (size_t)n >= sizeof(path)) return XTC_ERR_CAPACITY;
result = xtc_project_create(&project);
if (result == XTC_OK) result = xtc_project_add_track(project, "Listening phrase", &track);
if (result == XTC_OK) result = xtc_project_add_midi_clip(project, track, 0, 7680, &clip);
if (result == XTC_OK) result = xtc_project_add_note(project, clip, 0, 480, 60, 100, 0, &note);
if (result == XTC_OK) result = xtc_project_add_note(project, clip, 720, 480, 64, 100, 0, &note);
if (result == XTC_OK) result = xtc_project_add_note(project, clip, 1440, 1440, 67, 100, 0, &note);
if (result == XTC_OK) result = xtc_midi_plan_create(project, 48000, &midi);
if (result == XTC_OK) result = xtc_midi_plan_set_fade_frames(midi, smooth ? 240U : 0U);
if (result == XTC_OK) result = xtc_recorder_create_replace(path, 48000, 256, 1, &recorder);
(void)xtc_gain_ramp_reset(&ramp, smooth ? 0 : 1);
(void)xtc_gain_ramp_target(&ramp, 1, smooth ? 240U : 0U);
for (position = 0; result == XTC_OK && position < 192000; position += 256) {
float samples[256];
size_t i;
result = xtc_midi_plan_render(midi, position, NULL, 0, samples, 256);
if (result != XTC_OK) break;
for (i = 0; i < 256; ++i) {
uint64_t sample = position + i;
/* Deliberately abrupt constant clips with 5 ms fades in the smooth
* version, followed by a tone stopped mid-period at three seconds. */
if (sample >= 96000 && sample < 108000) {
uint64_t age = sample - 96000, tail = 107999 - sample;
uint64_t distance = age < tail ? age : tail;
float envelope = smooth && distance < 240 ? (float)distance / 240.0f : 1;
samples[i] += 0.2f * envelope;
}
if (sample >= 120000 && sample < 144000)
samples[i] += 0.2f * (float)sin(6.283185307179586 * 443.0 * (double)(sample - 120000) / 48000.0);
if (sample == 143760)
(void)xtc_gain_ramp_target(&ramp, 0, smooth ? 240U : 0U);
(void)xtc_gain_ramp_process(&ramp, samples + i, NULL, 1);
}
xtc_recorder_push(recorder, samples, 256);
result = xtc_recorder_drain(recorder);
}
if (result == XTC_OK) result = xtc_recorder_finish(recorder);
xtc_recorder_destroy(recorder); xtc_midi_plan_destroy(midi); xtc_project_destroy(project);
if (result == XTC_OK) printf("Wrote %s\n", path);
return result;
}
int main(int argc, char **argv)
{
xtc_result result;
if (argc != 2) { fprintf(stderr, "Usage: %s OUTPUT_PREFIX\n", argv[0]); return EXIT_FAILURE; }
result = preview(argv[1], 0);
if (result == XTC_OK) result = preview(argv[1], 1);
if (result != XTC_OK) { fprintf(stderr, "%s\n", xtc_result_string(result)); return EXIT_FAILURE; }
return EXIT_SUCCESS;
}