70 lines
3.5 KiB
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, ¬e);
|
|
if (result == XTC_OK) result = xtc_project_add_note(project, clip, 720, 480, 64, 100, 0, ¬e);
|
|
if (result == XTC_OK) result = xtc_project_add_note(project, clip, 1440, 1440, 67, 100, 0, ¬e);
|
|
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(path, 48000, 256, &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;
|
|
}
|