1
0
Fork 0
forked from hanez/xtc
xtc/src/mixer/render.c

92 lines
3 KiB
C

#include "mix_internal.h"
#include <stdlib.h>
#include <string.h>
size_t xtc_mix_track(const xtc_mix_snapshot *m, uint64_t id)
{
size_t i;
for (i = 0; i < m->count; ++i)
if (m->tracks[i].id == id)
return i;
return SIZE_MAX;
}
static int compare(const void *left, const void *right)
{
const xtc_mix_point *a = left, *b = right;
if (a->track != b->track)
return a->track < b->track ? -1 : 1;
if (a->parameter != b->parameter)
return a->parameter < b->parameter ? -1 : 1;
return a->tick < b->tick ? -1 : a->tick != b->tick;
}
xtc_result xtc_mix_prepare(const xtc_project *p, unsigned int rate, xtc_mix_snapshot *m)
{
size_t i;
xtc_result r;
memset(m, 0, sizeof(*m));
m->count = p->track_count;
memcpy(m->tracks, p->tracks, p->track_count * sizeof(*m->tracks));
for (i = 0; i < m->count; ++i)
if (m->tracks[i].solo)
m->any_solo = 1;
for (i = 0; i < p->automation_count; ++i) {
const xtc_automation_point *a = p->automation + i;
xtc_mix_point *b = m->points + i;
b->track = xtc_mix_track(m, a->track_id);
b->parameter = (unsigned int)a->parameter;
if (b->track == SIZE_MAX || b->parameter > 1)
return XTC_ERR_INVALID_STATE;
b->tick = a->tick;
b->value = a->value;
r = xtc_project_tick_to_sample(p, a->tick, rate, &b->sample);
if (r != XTC_OK)
return r;
}
qsort(m->points, p->automation_count, sizeof(*m->points), compare);
for (i = 0; i < p->automation_count; ++i) {
xtc_mix_point *a = m->points + i;
size_t *n = &m->lengths[a->track][a->parameter];
if (!*n)
m->offsets[a->track][a->parameter] = i;
++*n;
}
return XTC_OK;
}
static float value(const xtc_mix_snapshot *m, size_t track, unsigned int param, uint64_t sample)
{
size_t low = 0, high = m->lengths[track][param], count = high;
const xtc_mix_point *p = m->points + m->offsets[track][param];
if (!count)
return param ? m->tracks[track].pan : m->tracks[track].gain;
while (low < high) {
size_t mid = low + (high - low) / 2;
if (p[mid].sample <= sample)
low = mid + 1;
else
high = mid;
}
if (!low)
return p[0].value;
if (low == count)
return p[count - 1].value;
return (float)(p[low - 1].value + ((double)sample - (double)p[low - 1].sample) /
(double)(p[low].sample - p[low - 1].sample) *
(p[low].value - p[low - 1].value));
}
float xtc_mix_level(const xtc_mix_snapshot *m, size_t track, uint64_t sample, unsigned int side)
{
float gain, pan;
if (track >= m->count)
return 0;
if (m->tracks[track].mute || (m->any_solo && !m->tracks[track].solo))
return 0;
gain = value(m, track, 0, sample);
if (side == 2)
return gain;
pan = value(m, track, 1, sample);
return gain * (side == 0 ? (pan > 0 ? 1 - pan : 1) : (pan < 0 ? 1 + pan : 1));
}