1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-12-11 07:06:33 +01:00
Files
audacity/lib-src/sbsms/src/track.cpp

311 lines
6.3 KiB
C++

#include "track.h"
#include <math.h>
#include "utils.h"
#include "real.h"
#include "sbsms.h"
#include "sms.h"
#include <vector>
using namespace std;
namespace _sbsms_ {
#define SBSMS_TRACK_BLOCK 2048
TrackAllocator :: TrackAllocator(bool bManageIndex)
{
this-> bManageIndex = bManageIndex;
}
TrackAllocator :: TrackAllocator(bool bManageIndex, unsigned short maxtrackindex)
{
this-> bManageIndex = bManageIndex;
gTrack.resize(maxtrackindex);
init();
}
TrackAllocator :: ~TrackAllocator()
{
}
void TrackAllocator :: init()
{
for(unsigned short k=0;k<gTrack.size();k++)
gTrack[k] = NULL;
while(!gTrackIndex.empty())
gTrackIndex.pop();
#ifdef MULTITHREADED
pthread_mutex_init(&taMutex,NULL);
#endif
}
track *TrackAllocator :: getTrack(unsigned short index)
{
return gTrack[index];
}
int TrackAllocator :: size()
{
return gTrack.size();
}
track *TrackAllocator :: create(track *precursor, sms *owner, int res, unsigned short index)
{
track *t = new track(precursor,owner,res);
t->index = index;
gTrack[index] = t;
return t;
}
track *TrackAllocator :: create(track *precursor, sms *owner, int res)
{
#ifdef MULTITHREADED
pthread_mutex_lock(&taMutex);
#endif
if(gTrackIndex.empty()) {
unsigned short n = gTrack.size();
gTrack.resize(n+SBSMS_TRACK_BLOCK);
for(int k=n+SBSMS_TRACK_BLOCK-1;k>=n;k--) {
gTrackIndex.push(k);
gTrack[k] = NULL;
}
}
unsigned short index = gTrackIndex.top();
gTrackIndex.pop();
#ifdef MULTITHREADED
pthread_mutex_unlock(&taMutex);
#endif
return create(precursor, owner, res, index);
}
void TrackAllocator :: destroy(track *t)
{
#ifdef MULTITHREADED
pthread_mutex_lock(&taMutex);
#endif
gTrack[t->index] = NULL;
if(bManageIndex)
gTrackIndex.push(t->index);
delete t;
#ifdef MULTITHREADED
pthread_mutex_unlock(&taMutex);
#endif
}
track :: track(track *precursor, sms *owner, int res)
{
this->owner = owner;
this->res = res;
this->descendant = NULL;
this->precursor = precursor;
this->end = LONG_MAX;
this->rise = 0.3f;
this->fall = 0.5f;
tailEnd = 0;
tailStart = 0;
m_p = 0.0;
currtime = 0;
}
void track :: endTrack(bool bTail)
{
end = back()->time;
if(bTail) {
this->fall = min(1.5f,.25f + back()->y / point[point.size()-2]->y);
tailEnd = 1;
end++;
trackpoint *f = new trackpoint(back());
f->time = back()->time + 1;
point.push_back(f);
}
}
void track :: synth(SampleBuf *out,
long writePos,
int c,
long synthtime,
int steps,
real fScale0,
real fScale1,
real mScale) {
if(point.size()==0) return;
long k = synthtime - start;
if(k>=(long)point.size()-1) return;
currtime = synthtime;
if(k<0) return;
int k1 = k + 1;
tpoint *tp0 = point[k];
tpoint *tp1 = point[k1];
real w0 = tp0->f;
real w1 = tp1->f;
real ph0 = tp0->ph;
real ph1 = tp1->ph;
real h = tp0->h;
real dp = ph1 - ph0;
if(dp>PI) dp-=TWOPI;
else if(dp<-PI) dp+=TWOPI;
real dp0 = 0.5f*h*(w0 + w1);
real dw = canon(dp - dp0)/h;
if(k==0) {
if(precursor) {
m_p = precursor->m_pDescendant;
} else {
dw = 0;
}
}
real dt = (real)steps;
w0 = (w0+dw);
w1 = (w1+dw);
w0 = w0*fScale0;
w1 = w1*fScale1;
dp = dt*0.5f*(w0 + w1);
real b = (w1 - w0)/(2.0f*dt);
bool bEnd = (k1==(long)point.size()-1);
bool bStart = (k==0);
if(bStart && tailStart) {
if(w0 < PI && w0 > -PI) {
real ph = m_p;
int rise = round2int(this->rise * (real)steps);
real dm = mScale*tp1->y/(real)rise;
real m = mScale*tp1->y - dm;
for(int i=steps-1;i>=steps-rise+1;i--) {
ph -= w0;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
out->buf[writePos+i][c] += m * COS(ph);
m -= dm;
}
}
} else if(bEnd && tailEnd) {
if(w0 < PI && w0 > -PI) {
real ph = m_p;
int fall = round2int(this->fall * (real)steps);
real dm = mScale*tp0->y/(real)fall;
real m = mScale*tp0->y;
for(int i=0;i<fall;i++) {
out->buf[writePos+i][c] += m * COS(ph);
ph += w0;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
m -= dm;
}
}
} else {
real m = mScale*tp0->y;
real dm = mScale*(tp1->y0 - tp0->y)/dt;
real ph = m_p;
real b2tt1 = b;
real b2 = 2.0f*b;
real dph;
audio *o = &(out->buf[writePos]);
for(int i=0;i<steps;i++) {
dph = w0 + b2tt1;
if(dph < PI && dph > -PI) (*o)[c] += m * COS(ph);
ph += dph;
if(ph<-PI) ph += TWOPI;
else if(ph>PI) ph -= TWOPI;
b2tt1 += b2;
m += dm;
o++;
}
}
if(bEnd) {
if(descendant && descendant->back()->M < tp0->M) {
m_pDescendant = canon(m_p + dp/dt*(real)(descendant->owner->samplePos - owner->samplePos));
}
} else if(bStart && tailStart) {
} else {
m_p = canon(m_p + dp);
if(descendant && descendant->back()->M > tp0->M && (k1+res==(long)point.size()-1)) {
m_pDescendant = canon(m_p + dp/dt*(real)(descendant->owner->samplePos - (owner->samplePos+steps)));
}
}
}
bool track :: isEnded()
{
return (end!=LONG_MAX);
}
void track :: push_back_tpoint(tpoint *p)
{
point.push_back(p);
}
void track :: push_back(trackpoint *p)
{
point.push_back(p);
p->owner = this;
}
void track :: startTrack(trackpoint *p, bool bTail)
{
push_back(p);
start = p->time;
m_pDescendant = p->ph;
if(bTail) {
tailStart = 1;
start--;
trackpoint *s = new trackpoint(p);
s->time = p->time - 1;
point.insert(point.begin(),s);
m_p = p->ph;
}
currtime = p->time-1;
}
trackpoint *track :: back()
{
return (trackpoint*)point.back();
}
trackpoint *track :: getTrackPoint(long time)
{
long k = time-start;
if(k<0 || k >= (long)point.size())
return NULL;
else
return (trackpoint*)point[k];
}
bool track :: isStart(long synthtime)
{
return (synthtime == start);
}
bool track :: isEnd(long synthtime)
{
return (synthtime == end);
}
bool track :: isDone()
{
return (currtime-start+1 >= (long)point.size()-1);
}
long track :: size()
{
return 1+end-start-tailEnd-tailStart;
}
track :: ~track() {
if(precursor) precursor->descendant = NULL;
if(descendant) descendant->precursor = NULL;
for(vector<tpoint*>::iterator i = point.begin();
i != point.end();
i++) {
delete (*i);
}
}
}