1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-03 17:39:25 +02:00

359 lines
8.4 KiB
C++

#include "track.h"
#include "real.h"
#include "dBTable.h"
#include "synthTable.h"
#include "utils.h"
#include <algorithm>
using namespace std;
namespace _sbsms_ {
Track :: Track(float h, TrackIndexType index, TrackPoint *p, const TimeType &time, bool bStitch)
{
this->h = h;
jumpThresh = 1.0e-5f * h;
this->index = index;
bEnd = false;
bEnded = false;
bRender = false;
bSplit = false;
bMerge = false;
first = time;
start = time;
if(bStitch) {
this->bStitch = true;
} else {
this->bStitch = false;
if(start > 0) {
start--;
}
}
point.push_back(p);
p->owner = this;
p->refCount++;
end = time;
last = time;
}
Track :: ~Track() {
for(vector<TrackPoint*>::iterator i = point.begin();
i != point.end();
++i) {
TrackPoint *tp = (*i);
if(tp) {
tp->destroy();
}
}
}
TrackIndexType Track :: getIndex()
{
return index;
}
bool Track :: isFirst(const TimeType &time)
{
return (time == first);
}
bool Track :: isLast(const TimeType &time)
{
return (time == last);
}
TimeType Track :: size()
{
return point.size();
}
TrackPoint *Track :: back()
{
return point.back();
}
TrackPoint *Track :: getTrackPoint(const TimeType &time)
{
return point[time - first];
}
SBSMSTrackPoint *Track :: getSBSMSTrackPoint(const TimeType &time)
{
return getTrackPoint(time);
}
bool Track :: jump(TrackPoint *tp0, TrackPoint *tp1)
{
if(tp1->m > tp0->m) {
float cost = 1.0e-4f * dBApprox(tp0->m,tp1->m);
return (cost > jumpThresh);
} else {
return false;
}
}
TrackPoint *Track :: updateFPH(const TimeType &time, int mode, int n, float f0, float f1)
{
if(time == start && time < first) {
TrackPoint *tp1 = getTrackPoint(time+1);
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * tp1->f));
tp1->fSynth0 = tp1->fSynth1;
tp1->phSynth = tp1->ph;
if(mode == synthModeOutput && tp1->dupStereo) {
return tp1;
}
} else if(time == last) {
if(last < end) {
TrackPoint *tp0 = getTrackPoint(time);
tp0->fSynth0 = tp0->fSynth1;
}
} else {
TrackPoint *tp0 = getTrackPoint(time);
TrackPoint *tp1 = getTrackPoint(time+1);
if(mode == synthModeOutput) {
if(tp0->dupStereo && tp1->dupStereo && tp0->dupStereo->owner == tp1->dupStereo->owner) {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
float dpStereo = tp1->dupStereo->ph - tp0->dupStereo->ph;
float dp0Stereo = 0.5f*h*(tp0->dupStereo->f + tp1->dupStereo->f);
float dwStereo = canonPI(dpStereo - dp0Stereo)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
dwStereo = 0;
} else if(dwStereo > .0013f * (tp0->dupStereo->f + tp1->dupStereo->f)) {
dwStereo = 0;
}
float w0 = 0.5f * (tp0->f + tp0->dupStereo->f + dw + dwStereo);
float w1 = 0.5f * (tp1->f + tp1->dupStereo->f + dw + dwStereo);
float dwSynth = 0.5f * canonPI(dp - dpStereo) / n;
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (w0 + dwSynth)));
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (w1 + dwSynth)));
}
} else {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
}
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (tp0->f + dw)));
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (tp1->f + dw)));
}
}
if(!(tp0->bSplit || tp0->bMerge || tp1->bSplit || tp1->bMerge) && jump(tp0,tp1)) {
tp1->bJump = true;
if(tp0->dupStereo && tp1->dupStereo) {
if(tp0->dupStereo->owner == tp1->dupStereo->owner) {
tp1->bSyncStereo = !jump(tp0->dupStereo,tp1->dupStereo);
}
}
}
if(!tp0->bSplit) {
if(tp0->bJump) {
if(tp0->bSyncStereo) {
tp0->phSynth = canon2PI(tp0->dupStereo->phSynth + tp0->ph - tp0->dupStereo->ph);
} else {
tp0->phSynth = tp0->ph;
}
}
}
if(!(bMerge && time + 1 == last)) {
float dw = (tp1->fSynth1 - tp0->fSynth0) / n;
float w = tp0->fSynth0 + 0.5f * dw;
float iw = lrintf(w * WScale) / WScale;
float idw = lrintf(dw * WScale) / WScale;
tp1->phSynth = canon2PI(tp0->phSynth + n * iw + ((n * (n - 1)) >> 1) * idw);
}
} else {
float dp = tp1->ph - tp0->ph;
float dp0 = 0.5f*h*(tp0->f + tp1->f);
float dw = canonPI(dp - dp0)/h;
if(dw > .0013f * (tp0->f + tp1->f)) {
dw = 0;
}
if(!(bSplit && time == first)) {
tp0->fSynth0 = max(0.0f,min(6.0f,f0 * (tp0->f + dw)));
tp0->phSynth = tp0->ph;
}
if(!(bMerge && time + 1 == last)) {
tp1->fSynth1 = max(0.0f,min(6.0f,f1 * (tp1->f + dw)));
tp1->phSynth = tp1->ph;
}
}
}
return NULL;
}
void Track :: updateM(const TimeType &time, int mode)
{
if(mode == synthModeTrial2) {
if(time == first && time == start) {
TrackPoint *tp0 = getTrackPoint(time);
tp0->m = (tp0->m2>0.0f?sqrt(tp0->m2):0.0f);
}
if(time < last) {
TrackPoint *tp1 = getTrackPoint(time+1);
tp1->m = (tp1->m2>0.0f?sqrt(tp1->m2):0.0f);
}
}
}
void Track :: step(const TimeType &time)
{
if(time > first && time < last) {
TrackPoint *tp = point[time-first];
tp->destroy();
point[time-first] = NULL;
}
}
void Track :: push_back(TrackPoint *p)
{
point.push_back(p);
p->owner = this;
p->refCount++;
last++;
end++;
}
void Track :: endTrack(bool bStitch)
{
if(bStitch) {
this->bStitch = true;
} else {
end++;
}
bEnded = true;
}
void Track :: synth(float *out,
const TimeType &time,
int n,
int mode,
int c)
{
float m0, m1;
float w0, w1;
// unused float dw;
float ph0, ph1;
bool bTailStart;
bool bTailEnd;
if(time >= end) return;
if(time < last) {
TrackPoint *tp1 = getTrackPoint(time+1);
w1 = tp1->fSynth1;
m1 = tp1->m;
ph1 = tp1->phSynth;
if(bMerge && time + 1 == last) {
m1 = 0.0f;
}
bTailStart = tp1->bJump;
bTailEnd = tp1->bJump;
} else {
bTailStart = false;
bTailEnd = (last != end);
}
if(time >= first) {
TrackPoint *tp0 = getTrackPoint(time);
w0 = tp0->fSynth0;
m0 = tp0->m;
ph0 = tp0->phSynth;
if(bSplit && time == first) {
m0 = 0.0f;
}
} else {
bTailStart = true;
}
if(bTailEnd) {
int fall = min(n,w0==0.0f?384:min(384,(int)lrintf(PI * 4.0f / w0)));
float dm = m0 / (float)fall;
float w = w0;
float *out2 = out;
float *end = out + fall;
long iph = lrintf(ph0 * WScale);
if(iph>=W2PI) iph -= W2PI;
long iw = lrintf(w * WScale);
while(out2 != end) {
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out2 += m0 * (float)(synthTable1[i] + f * synthTable2[i]);
}
out2++;
m0 -= dm;
iph += iw;
iph &= W2PIMask;
}
}
if(bTailStart) {
int rise = min(n,w1==0.0f?384:min(384,(int)lrintf(PI * 3.0f / w1)));
float dm = m1 / (float)rise;
float w = w1;
out += n;
float *end = out-rise;
long iph = lrintf(ph1 * WScale);
iph &= W2PIMask;
long iw = lrintf(w * WScale);
while(out != end) {
out--;
m1 -= dm;
iph -= iw;
if(iph<0) iph += W2PI;
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out += m1 * (float)(synthTable1[i] + f * synthTable2[i]);
}
}
}
if(!(bTailStart || bTailEnd)) {
float dw = (w1 - w0) / n;
float w = w0 + 0.5f * dw;
float dm = (m1 - m0) / n;
long iph = lrintf(ph0 * WScale);
if(iph>=W2PI) iph -= W2PI;
long iw = lrintf(w * WScale);
long idw = lrintf(dw * WScale);
float *end = out + n;
while(out != end) {
if(iw < WPI) {
long f = (iph>>PhShift)&Ph1;
long i = iph>>WShift;
*out += m0 * (float)(synthTable1[i] + f * synthTable2[i]);
}
iph += iw;
iw += idw;
iph &= W2PIMask;
m0 += dm;
out++;
}
}
}
void Track :: absorb()
{
for(vector<TrackPoint*>::iterator i = point.begin();
i != point.end();
++i) {
TrackPoint *tp = (*i);
tp->absorb();
}
}
}