#include "mix_internal.h" #include #include 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)); }