92 lines
3 KiB
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));
|
|
}
|