mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 07:39:42 +02:00
1834 lines
48 KiB
C++
1834 lines
48 KiB
C++
#include "sms.h"
|
|
#include "real.h"
|
|
#include "utils.h"
|
|
#include "dBTable.h"
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <set>
|
|
using namespace std;
|
|
|
|
namespace _sbsms_ {
|
|
|
|
SMS :: SMS(SMS *lo, int N, int band, int bandMax, int h, int res, int N0, int N1, int N2, int channels, audio *peak2)
|
|
{
|
|
this->lo = lo;
|
|
if(lo) lo->hi = this;
|
|
hi = NULL;
|
|
this->band = band;
|
|
this->h = h;
|
|
this->h1 = (double)(h<<band);
|
|
this->res = res;
|
|
this->resMask = res - 1;
|
|
this->channels = channels;
|
|
this->N = N;
|
|
this->Nover2 = N/2;
|
|
float pad2 = (float)N/(float)N2;
|
|
float pad1 = (float)N/(float)N1;
|
|
float pad0 = (float)N/(float)N0;
|
|
M = (float)(1<<band);
|
|
peakThresh = 1e-8f;
|
|
|
|
float maxDF2 = square(0.005f * (float)h) / M;
|
|
maxDF = sqrt(maxDF2);
|
|
maxCost2 = 0.5f * maxDF2;
|
|
dMCoeff2 = 0.002f * maxDF2;
|
|
|
|
float maxDF2SplitMerge = square(0.001f * (float)h) / M;
|
|
maxDFSplitMerge = sqrt(maxDF2SplitMerge);
|
|
maxCost2SplitMerge = 1.0f * maxDF2SplitMerge;
|
|
dMCoeff2SplitMerge = 0.006f * maxDF2SplitMerge;
|
|
|
|
maxDFMatch = .06f / M;
|
|
float maxDF2Match = square(maxDFMatch);
|
|
dMCoeff2Match = 0.0075f * maxDF2Match;
|
|
maxCost2Match = 0.8f * maxDF2Match;
|
|
|
|
maxDFStereo = .04f / (float)M;
|
|
float maxDF2Stereo = square(maxDFStereo);
|
|
dMCoeff2Stereo = 0.005f * maxDF2Stereo;
|
|
maxCost2Stereo = 1.0f*maxDF2Stereo;
|
|
|
|
peakWidth0 = lrintf(pad0*(float)N*0.0055f) + 1;
|
|
peakWidth1 = lrintf(pad1*(float)N*0.0055f) + 1;
|
|
peakWidth2 = lrintf(pad2*(float)N*0.0055f) + 1;
|
|
minTrackSize = max(384/(h<<band),N2/h/2);
|
|
minCutSep2 = max((int)lrintf(0.008f * (float)N),peakWidth1);
|
|
minCutSep1 = max((int)lrintf(0.011f * (float)N),peakWidth0);
|
|
if(band==bandMax) kLo = 1;
|
|
else kLo = max(1L,lrintf(floor(0.5f*(float)N/(float)lo->N*(float)lo->kHi-maxDFMatch*M/TWOPI*(float)N)));
|
|
if(band==0) kHi = Nover2;
|
|
else kHi = max(1L,lrintf(0.4785f * N)-peakWidth0*2);
|
|
kStart = max(1,kLo-peakWidth0);
|
|
kEnd = min(Nover2-1,kHi+peakWidth0*2);
|
|
float kNorm = TWOPI / (float)(M * N);
|
|
maxFHi = (float)kHi * kNorm + maxDF;
|
|
minFLo = (float)kLo * kNorm - maxDF;
|
|
if(lo) maxFMatchM = (float)lo->kHi * TWOPI / (float)(lo->N * M * 2) + maxDFMatch;
|
|
else maxFMatchM = 0.0f;
|
|
minFMatchL = (float)kLo * kNorm - maxDFMatch;
|
|
if(lo) maxFMid = (float)lo->kHi * TWOPI / (float)(lo->N * M * 2) + maxDF;
|
|
else maxFMid = 0.0f;
|
|
if(lo) lo->minFMid = (float)kLo * kNorm - lo->maxDF;
|
|
if(lo && lo->lo) {
|
|
minK = max(1L,(lrintf(0.25f * (float)N / (float)lo->lo->N * (float)lo->lo->kHi + peakWidth0)));
|
|
} else {
|
|
minK = 1;
|
|
}
|
|
maxK = min(kEnd,kHi + peakWidth0);
|
|
localFavorRatio = 1.1f;
|
|
mNorm = MScale * MScale * 16.061113032124002f * pad2 / square((float)N);
|
|
for(int c=0; c<channels; c++) {
|
|
bAssignDone[c] = false;
|
|
addtime[c] = 0;
|
|
assigntime[c] = 0;
|
|
trial2time[c] = 0;
|
|
trial1time[c] = 0;
|
|
synthtime[c] = 0;
|
|
for(int k=1; k<256; k++) {
|
|
trackIndex[c].push(k);
|
|
}
|
|
trial2Buf[c] = (float*)malloc(h*res*sizeof(float));
|
|
trial2RingBuf[c] = new ArrayRingBuffer<float>(0);
|
|
dmag1[c] = (float*)malloc(N*sizeof(float));
|
|
mag11[c] = (float*)malloc((Nover2+1)*sizeof(float));
|
|
x10[c] = (audio*)malloc(N*sizeof(audio));
|
|
x11[c] = (audio*)malloc(N*sizeof(audio));
|
|
trial1Buf[c] = (float*)malloc(h*res*sizeof(float));
|
|
trial1RingBuf[c] = new ArrayRingBuffer<float>(0);
|
|
dmag0[c] = (float*)malloc(N*sizeof(float));
|
|
mag01[c] = (float*)malloc((Nover2+1)*sizeof(float));
|
|
x00[c] = (audio*)malloc(N*sizeof(audio));
|
|
x01[c] = (audio*)malloc(N*sizeof(audio));
|
|
mag2[c] = (float*)malloc((Nover2+1)*sizeof(float));
|
|
dec2[c] = (float*)malloc(N*sizeof(float));
|
|
x2[c] = (audio*)malloc(N*sizeof(audio));
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_init(&renderMutex[c],NULL);
|
|
pthread_mutex_init(&trackMutex[c],NULL);
|
|
pthread_mutex_init(&sliceMutex[c],NULL);
|
|
pthread_mutex_init(&trial2Mutex[c],NULL);
|
|
pthread_mutex_init(&trial1Mutex[c],NULL);
|
|
pthread_mutex_init(&magMutex[c],NULL);
|
|
#endif
|
|
}
|
|
h2cum = 0.0;
|
|
adjust2time = 0;
|
|
adjust1time = 0;
|
|
trial2GrainBuf = new GrainBuf(N,h,N1,hannpoisson);
|
|
trial1GrainBuf = new GrainBuf(N,h,N0,hannpoisson);
|
|
peak20 = (float*)calloc(2*N,sizeof(float));
|
|
peak2N = peak20 + N;
|
|
for(int k=-Nover2;k<=Nover2;k++) {
|
|
peak2N[k] = norm2(peak2[(k+N)%N]);
|
|
}
|
|
}
|
|
|
|
SMS :: ~SMS()
|
|
{
|
|
for(int c=0;c<channels;c++) {
|
|
while(!mag1Queue[c].empty()) {
|
|
delete mag1Queue[c].front();
|
|
mag1Queue[c].pop();
|
|
}
|
|
while(!mag0Queue[c].empty()) {
|
|
delete mag0Queue[c].front();
|
|
mag0Queue[c].pop();
|
|
}
|
|
set<Track*> tracks;
|
|
for(list<Track*>::iterator i=assignTracks[c].begin();
|
|
i != assignTracks[c].end();
|
|
++i ) {
|
|
tracks.insert(*i);
|
|
}
|
|
for(list<Track*>::iterator i=renderTracks[c].begin();
|
|
i != renderTracks[c].end();
|
|
++i ) {
|
|
tracks.insert(*i);
|
|
}
|
|
for(set<Track*>::iterator i=tracks.begin();
|
|
i != tracks.end();
|
|
++i ) {
|
|
delete *i;
|
|
}
|
|
set<Slice*> slices;
|
|
while(!adjust2SliceQueue[c].empty()) {
|
|
slices.insert(adjust2SliceQueue[c].front());
|
|
adjust2SliceQueue[c].pop();
|
|
}
|
|
while(!adjust1SliceQueue[c].empty()) {
|
|
slices.insert(adjust1SliceQueue[c].front());
|
|
adjust1SliceQueue[c].pop();
|
|
}
|
|
for(long k=sliceBuffer[c].readPos; k<sliceBuffer[c].writePos; k++) {
|
|
slices.insert(sliceBuffer[c].read(k));
|
|
}
|
|
for(set<Slice*>::iterator i = slices.begin();
|
|
i != slices.end();
|
|
++i) {
|
|
Slice *s = *i;
|
|
TrackPoint *tp = s->bottom;
|
|
delete s;
|
|
while(tp) {
|
|
TrackPoint *tpn = tp->pn;
|
|
if(!tp->owner) tp->destroy();
|
|
tp = tpn;
|
|
}
|
|
}
|
|
free(trial2Buf[c]);
|
|
delete trial2RingBuf[c];
|
|
free(trial1Buf[c]);
|
|
delete trial1RingBuf[c];
|
|
free(dmag1[c]);
|
|
free(mag11[c]);
|
|
free(x10[c]);
|
|
free(x11[c]);
|
|
free(dmag0[c]);
|
|
free(mag01[c]);
|
|
free(x00[c]);
|
|
free(x01[c]);
|
|
free(mag2[c]);
|
|
free(x2[c]);
|
|
free(dec2[c]);
|
|
}
|
|
free(peak20);
|
|
delete trial2GrainBuf;
|
|
delete trial1GrainBuf;
|
|
}
|
|
|
|
void SMS :: trial2Start(int c)
|
|
{
|
|
if(band >= minTrial2Band) {
|
|
memset(trial2Buf[c],0,h*res*sizeof(float));
|
|
}
|
|
}
|
|
|
|
void SMS :: trial2End(int c)
|
|
{
|
|
if(band < minTrial2Band) return;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trial2Mutex[c]);
|
|
#endif
|
|
trial2RingBuf[c]->write(trial2Buf[c],h*res);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trial2Mutex[c]);
|
|
#endif
|
|
}
|
|
|
|
void SMS :: trial2(int c)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
for(list<Track*>::iterator tt = renderTracks[c].begin();
|
|
tt != renderTracks[c].end();
|
|
++tt) {
|
|
Track *t = (*tt);
|
|
if(trial2time[c] >= t->start) {
|
|
if(trial2time[c] > t->last) continue;
|
|
t->updateM(trial2time[c],synthModeTrial2);
|
|
if(hi && hi->band >= minTrial2Band) {
|
|
float f = 0.5f*M;
|
|
t->updateFPH(trial2time[c],synthModeTrial2,h<<1,f,f);
|
|
t->synth(hi->trial2Buf[c],trial2time[c],h<<1,synthModeTrial2,c);
|
|
}
|
|
if(lo && lo->band >= minTrial2Band) {
|
|
float f = 2.0f*M;
|
|
t->updateFPH(trial2time[c],synthModeTrial2,h>>1,f,f);
|
|
t->synth(lo->trial2Buf[c]+(trial2time[c]&(res*lo->res-1))*(h>>1),trial2time[c],h>>1,synthModeTrial2,c);
|
|
}
|
|
if(band >= minTrial2Band) {
|
|
float f = M;
|
|
t->updateFPH(trial2time[c],synthModeTrial2,h,f,f);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
trial2time[c]++;
|
|
}
|
|
|
|
void SMS :: trial1Start(int c)
|
|
{
|
|
if(band >= minTrial1Band) {
|
|
memset(trial1Buf[c],0,h*res*sizeof(float));
|
|
}
|
|
}
|
|
|
|
void SMS :: trial1End(int c)
|
|
{
|
|
if(band < minTrial1Band) return;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trial1Mutex[c]);
|
|
#endif
|
|
trial1RingBuf[c]->write(trial1Buf[c],h*res);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trial1Mutex[c]);
|
|
#endif
|
|
}
|
|
|
|
void SMS :: trial1(int c)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
for(list<Track*>::iterator tt = renderTracks[c].begin();
|
|
tt != renderTracks[c].end();
|
|
++tt) {
|
|
Track *t = (*tt);
|
|
if(trial1time[c] >= t->start) {
|
|
if(trial1time[c] > t->last) continue;
|
|
t->updateM(trial1time[c],synthModeTrial1);
|
|
if(hi && hi->band >= minTrial1Band) {
|
|
float f = 0.5f*M;
|
|
t->updateFPH(trial1time[c],synthModeTrial1,h<<1,f,f);
|
|
t->synth(hi->trial1Buf[c],trial1time[c],h<<1,synthModeTrial1,c);
|
|
}
|
|
if(lo && lo->band >= minTrial1Band) {
|
|
float f = 2.0f*M;
|
|
t->updateFPH(trial1time[c],synthModeTrial1,h>>1,f,f);
|
|
t->synth(lo->trial1Buf[c]+(trial1time[c]&(res*lo->res-1))*(h>>1),trial1time[c],h>>1,synthModeTrial1,c);
|
|
}
|
|
if(band >= minTrial1Band) {
|
|
float f = M;
|
|
t->updateFPH(trial1time[c],synthModeTrial1,h,f,f);
|
|
t->synth(trial1Buf[c]+(trial1time[c]&resMask)*h,trial1time[c],h,synthModeTrial1,c);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
trial1time[c]++;
|
|
}
|
|
|
|
void SMS :: adjust2()
|
|
{
|
|
Slice* slice[2];
|
|
for(int c=0; c<channels; c++) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
slice[c] = adjust2SliceQueue[c].front(); adjust2SliceQueue[c].pop();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
}
|
|
if(band >= minTrial2Band) {
|
|
#ifdef MULTITHREADED
|
|
for(int c=0; c<channels; c++) {
|
|
pthread_mutex_lock(&trial2Mutex[c]);
|
|
}
|
|
#endif
|
|
adjustInit(trial2RingBuf,trial2GrainBuf);
|
|
#ifdef MULTITHREADED
|
|
for(int c=channels-1; c>=0; c--) {
|
|
pthread_mutex_unlock(&trial2Mutex[c]);
|
|
}
|
|
#endif
|
|
adjust(trial2GrainBuf,mag1Queue,minCutSep1,mag11,dmag1,x11,adjust2time,slice);
|
|
}
|
|
if(channels == 2) {
|
|
for(int c=0; c<2; c++) {
|
|
for(TrackPoint *pc = slice[c]->bottom;
|
|
pc;
|
|
pc = pc->pn) {
|
|
pc->bOwned = false;
|
|
pc->cont = NULL;
|
|
}
|
|
}
|
|
for(int c=0; c<2; c++) {
|
|
int c2 = (c==0?1:0);
|
|
TrackPoint *begin = slice[c2]->bottom;
|
|
for(TrackPoint *pc = slice[c]->bottom;
|
|
pc;
|
|
pc = pc->pn) {
|
|
float F;
|
|
pc->cont = nearestForward(&begin,pc,&F,maxCost2Stereo,maxDFStereo,dMCoeff2Stereo);
|
|
}
|
|
}
|
|
for(TrackPoint *p0 = slice[0]->bottom;
|
|
p0;
|
|
p0 = p0->pn) {
|
|
TrackPoint *p1 = p0->cont;
|
|
if(p1 && p1->cont == p0) {
|
|
p0->dupStereo = p1;
|
|
p1->dupStereo = p0;
|
|
}
|
|
}
|
|
}
|
|
adjust2time++;
|
|
}
|
|
|
|
void SMS :: adjust1(float stretch, float pitch0, float pitch1)
|
|
{
|
|
Slice* slice[2];
|
|
for(int c=0; c<channels; c++) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
slice[c] = adjust1SliceQueue[c].front(); adjust1SliceQueue[c].pop();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
}
|
|
if(band >= minTrial1Band) {
|
|
#ifdef MULTITHREADED
|
|
for(int c=0; c<channels; c++) {
|
|
pthread_mutex_lock(&trial1Mutex[c]);
|
|
}
|
|
#endif
|
|
adjustInit(trial1RingBuf,trial1GrainBuf);
|
|
#ifdef MULTITHREADED
|
|
for(int c=channels-1; c>=0; c--) {
|
|
pthread_mutex_unlock(&trial1Mutex[c]);
|
|
}
|
|
#endif
|
|
adjust(trial1GrainBuf,mag0Queue,minCutSep1,mag01,dmag0,x01,adjust1time,slice);
|
|
}
|
|
for(int c=0; c<channels; c++) {
|
|
delete slice[c];
|
|
}
|
|
double h2 = stretch * h1;
|
|
h2cum += h2;
|
|
int h2i = lrint(h2cum);
|
|
h2cum -= h2i;
|
|
for(int c=0; c<channels; c++) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&renderMutex[c]);
|
|
#endif
|
|
nRender[c].push(h2i);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&renderMutex[c]);
|
|
#endif
|
|
}
|
|
list<TrackPoint*> dupStereoPostponed;
|
|
for(int c=0; c<channels; c++) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
for(list<Track*>::iterator tt = renderTracks[c].begin();
|
|
tt != renderTracks[c].end();
|
|
++tt) {
|
|
Track *t = (*tt);
|
|
if(adjust1time >= t->start) {
|
|
if(adjust1time <= t->last) {
|
|
TrackPoint *tp = t->updateFPH(adjust1time,synthModeOutput,h2i,pitch0,pitch1);
|
|
if(tp) dupStereoPostponed.push_back(tp);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
}
|
|
for(list<TrackPoint*>::iterator tpi = dupStereoPostponed.begin();
|
|
tpi != dupStereoPostponed.end();
|
|
tpi++) {
|
|
TrackPoint *tp = (*tpi);
|
|
tp->phSynth = canon2PI(tp->dupStereo->phSynth + tp->ph - tp->dupStereo->ph);
|
|
}
|
|
adjust1time++;
|
|
}
|
|
|
|
int SMS :: findCut(float *dmag, int k0, int maxK)
|
|
{
|
|
int k;
|
|
for(k = max(1,k0); k <= maxK; k++) {
|
|
float dd0 = dmag[k+1] - dmag[k];
|
|
if(dd0 > 0.0f) {
|
|
float d02 = square(dmag[k+1] + dmag[k]);
|
|
if(dd0 * square(dmag[k] + dmag[k-1]) > (dmag[k] - dmag[k-1]) * d02
|
|
&&
|
|
dd0 * square(dmag[k+2] + dmag[k+1]) > (dmag[k+2] - dmag[k+1]) * d02) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return k;
|
|
}
|
|
|
|
void SMS :: adjustInit(ArrayRingBuffer<float> **trialRingBuf,
|
|
GrainBuf *trialGrainBuf)
|
|
{
|
|
long n = trialRingBuf[0]->nReadable();
|
|
for(int c=1; c<channels; c++) {
|
|
n = min(n,trialRingBuf[c]->nReadable());
|
|
}
|
|
long ndone = 0;
|
|
while(n) {
|
|
audio abuf[512];
|
|
long ntodo = min(512L,n);
|
|
for(int c=0; c<channels; c++) {
|
|
float *fbuf = trialRingBuf[c]->getReadBuf();
|
|
for(int k=0; k<ntodo; k++) {
|
|
abuf[k][c] = fbuf[ndone+k];
|
|
}
|
|
}
|
|
for(int c=channels; c<2; c++) {
|
|
for(int k=0; k<ntodo; k++) {
|
|
abuf[k][c] = 0.0f;
|
|
}
|
|
}
|
|
trialGrainBuf->write(abuf,ntodo);
|
|
ndone += ntodo;
|
|
n -= ntodo;
|
|
}
|
|
for(int c=0; c<channels; c++) {
|
|
trialRingBuf[c]->advance(ndone);
|
|
}
|
|
}
|
|
|
|
void SMS :: adjust(GrainBuf *trialGrainBuf,
|
|
queue<float*> *magQueue,
|
|
int minCutSep,
|
|
float **_mag1,
|
|
float **_dmag1,
|
|
audio **x1,
|
|
const TimeType &time,
|
|
Slice **slices)
|
|
{
|
|
grain *g = trialGrainBuf->read(trialGrainBuf->readPos);
|
|
g->analyze();
|
|
for(int c=0; c<channels; c++) {
|
|
Slice *slice = slices[c];
|
|
TrackPoint *p = slice->bottom;
|
|
if(c == 0) {
|
|
c2even(g->x, x1[0], N);
|
|
} else {
|
|
c2odd(g->x, x1[1], N);
|
|
}
|
|
float *mag1 = _mag1[c];
|
|
calcmags(mag1, x1[c]);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&magMutex[c]);
|
|
#endif
|
|
float *mag0 = magQueue[c].front(); magQueue[c].pop();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&magMutex[c]);
|
|
#endif
|
|
if(p) {
|
|
float *dmag = _dmag1[c];
|
|
list<int> cuts;
|
|
int k3 = min(Nover2,maxK+2);
|
|
dmag[0] = mag1[0];
|
|
for(int k=max(1,minK-2); k<k3; k++) {
|
|
dmag[k] = mag1[k] - mag1[k-1];
|
|
}
|
|
int k = minK;
|
|
while(true) {
|
|
k = findCut(dmag,k+1,maxK);
|
|
if(k >= maxK) {
|
|
break;
|
|
} else {
|
|
cuts.push_back(k);
|
|
}
|
|
}
|
|
bool bDone = false;
|
|
while(!bDone) {
|
|
bDone = true;
|
|
for(list<int>::iterator i = cuts.begin();
|
|
i != cuts.end();
|
|
++i) {
|
|
int k0 = *i;
|
|
list<int>::iterator ibad = cuts.end();
|
|
list<int>::iterator i2 = i;
|
|
++i2;
|
|
float maxY = 0.0f;
|
|
for(;
|
|
i2 != cuts.end();
|
|
++i2) {
|
|
int k2 = *i2;
|
|
if(k2 - k0 >= minCutSep) break;
|
|
float y = mag0[k2] * mag1[k2];
|
|
if(y >= maxY) {
|
|
maxY = y;
|
|
ibad = i2;
|
|
}
|
|
k0 = k2;
|
|
}
|
|
if(ibad != cuts.end()) {
|
|
if(mag0[*i] * mag1[*i] > maxY) {
|
|
ibad = i;
|
|
}
|
|
cuts.erase(ibad);
|
|
bDone = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
cuts.push_front(minK);
|
|
cuts.push_back(maxK);
|
|
list<int>::iterator i = cuts.begin();
|
|
while(p) {
|
|
int k0 = *i;
|
|
++i;
|
|
if(i == cuts.end()) break;
|
|
int k2 = *i;
|
|
if(p->x > k2) continue;
|
|
float m0 = 0.0f;
|
|
float m1 = 0.0f;
|
|
for(int k=k0;k<=k2;k++) {
|
|
m0 += mag0[k];
|
|
m1 += mag1[k];
|
|
}
|
|
float s = (m1>m0?sqrt(m0/m1):1.0f);
|
|
while(p && p->x <= k2) {
|
|
p->m *= s;
|
|
p = p->pn;
|
|
}
|
|
}
|
|
}
|
|
free(mag0);
|
|
}
|
|
trialGrainBuf->advance(1);
|
|
}
|
|
|
|
void SMS :: render(int c, list<SBSMSRenderer*> &renderers)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&renderMutex[c]);
|
|
#endif
|
|
int n = nRender[c].front(); nRender[c].pop();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&renderMutex[c]);
|
|
#endif
|
|
TimeType time = synthtime[c];
|
|
for(list<SBSMSRenderer*>::iterator i = renderers.begin(); i != renderers.end(); ++i) {
|
|
SBSMSRenderer *renderer = *i;
|
|
renderer->startTime(c,time,n);
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
for(list<Track*>::iterator tt = renderTracks[c].begin();
|
|
tt != renderTracks[c].end();) {
|
|
Track *t = (*tt);
|
|
if(t->bEnded && time > t->last) {
|
|
list<Track*>::iterator eraseMe = tt;
|
|
++tt;
|
|
renderTracks[c].erase(eraseMe);
|
|
delete t;
|
|
} else if(time >= t->start) {
|
|
if(time <= t->last) {
|
|
t->updateM(time,synthModeOutput);
|
|
for(list<SBSMSRenderer*>::iterator i = renderers.begin(); i != renderers.end(); ++i) {
|
|
SBSMSRenderer *renderer = *i;
|
|
renderer->render(c,t);
|
|
}
|
|
t->step(time);
|
|
}
|
|
++tt;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
for(list<SBSMSRenderer*>::iterator i = renderers.begin(); i != renderers.end(); ++i) {
|
|
SBSMSRenderer *renderer = *i;
|
|
renderer->endTime(c);
|
|
}
|
|
synthtime[c]++;
|
|
}
|
|
|
|
TrackPoint *SMS :: nearestForward(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF, float dMCoeff2, float dNCoeff2)
|
|
{
|
|
*minCost2 = TrackPointNoCont;
|
|
float minF = tp0->f - maxDF;
|
|
float maxF = tp0->f + maxDF;
|
|
float maxDF2 = square(maxDF);
|
|
while((*begin) && (*begin)->f < minF) {
|
|
(*begin) = (*begin)->pn;
|
|
}
|
|
TrackPoint *mintp1 = NULL;
|
|
for(TrackPoint *tp1 = (*begin);
|
|
tp1;
|
|
tp1 = tp1->pn) {
|
|
if(tp1->bOwned) continue;
|
|
float df2 = square(tp1->f - tp0->f);
|
|
if(df2 > maxDF2) break;
|
|
float dM2 = dBApprox(tp1->m2,tp0->m2);
|
|
float cost2 = (df2+dMCoeff2*dM2);
|
|
if(cost2 > maxCost2) continue;
|
|
if(cost2 < (*minCost2)) {
|
|
(*minCost2) = cost2;
|
|
mintp1 = tp1;
|
|
}
|
|
}
|
|
return mintp1;
|
|
}
|
|
|
|
TrackPoint *SMS :: nearestReverse(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF, float dMCoeff2, float dNCoeff2)
|
|
{
|
|
*minCost2 = TrackPointNoCont;
|
|
float minF = tp0->f - maxDF;
|
|
float maxF = tp0->f + maxDF;
|
|
float maxDF2 = square(maxDF);
|
|
while((*begin) && (*begin)->f > maxF) {
|
|
(*begin) = (*begin)->pp;
|
|
}
|
|
TrackPoint *mintp1 = NULL;
|
|
for(TrackPoint *tp1 = (*begin);
|
|
tp1;
|
|
tp1 = tp1->pp) {
|
|
if(tp1->bOwned) continue;
|
|
float df2 = square(tp1->f - tp0->f);
|
|
if(df2 > maxDF2) break;
|
|
float dM2 = dBApprox(tp1->m2,tp0->m2);
|
|
float cost2 = (df2+dMCoeff2*dM2);
|
|
if(cost2 > maxCost2) continue;
|
|
if(cost2 < (*minCost2)) {
|
|
(*minCost2) = cost2;
|
|
mintp1 = tp1;
|
|
}
|
|
}
|
|
return mintp1;
|
|
}
|
|
|
|
TrackPoint *SMS :: nearestForward2(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF, float dMCoeff2, float dNCoeff2)
|
|
{
|
|
*minCost2 = TrackPointNoCont;
|
|
float minF = tp0->f - maxDF;
|
|
float maxF = tp0->f + maxDF;
|
|
float maxDF2 = square(maxDF);
|
|
while((*begin) && (*begin)->f < minF) {
|
|
(*begin) = (*begin)->pn;
|
|
}
|
|
TrackPoint *mintp1 = NULL;
|
|
for(TrackPoint *tp1 = (*begin);
|
|
tp1;
|
|
tp1 = tp1->pn) {
|
|
if(!tp1->owner) continue;
|
|
float df2 = square(tp1->f - tp0->f);
|
|
if(df2 > maxDF2) break;
|
|
float dM2 = dBApprox(0.25f*tp1->m2,tp0->m2);
|
|
float cost2 = (df2+dMCoeff2*dM2);
|
|
if(cost2 > maxCost2) continue;
|
|
if(cost2 < (*minCost2)) {
|
|
(*minCost2) = cost2;
|
|
mintp1 = tp1;
|
|
}
|
|
}
|
|
return mintp1;
|
|
}
|
|
|
|
TrackPoint *SMS :: nearestReverse2(TrackPoint **begin, TrackPoint *tp0, float *minCost2, float maxCost2, float maxDF, float dMCoeff2, float dNCoeff2)
|
|
{
|
|
*minCost2 = TrackPointNoCont;
|
|
float minF = tp0->f - maxDF;
|
|
float maxF = tp0->f + maxDF;
|
|
float maxDF2 = square(maxDF);
|
|
while((*begin) && (*begin)->f > maxF) {
|
|
(*begin) = (*begin)->pp;
|
|
}
|
|
TrackPoint *mintp1 = NULL;
|
|
for(TrackPoint *tp1 = (*begin);
|
|
tp1;
|
|
tp1 = tp1->pp) {
|
|
if(!tp1->owner) continue;
|
|
float df2 = square(tp1->f - tp0->f);
|
|
if(df2 > maxDF2) break;
|
|
float dM2 = dBApprox(tp1->m2,tp0->m2);
|
|
float cost2 = (df2+dMCoeff2*dM2);
|
|
if(cost2 > maxCost2) continue;
|
|
if(cost2 < (*minCost2)) {
|
|
(*minCost2) = cost2;
|
|
mintp1 = tp1;
|
|
}
|
|
}
|
|
return mintp1;
|
|
}
|
|
|
|
void SMS :: connect(TrackPoint *tp0, TrackPoint *tp1, int ilo, int c)
|
|
{
|
|
TimeType time = assigntime[c];
|
|
if(tp0->slice->band == tp1->slice->band) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
tp0->owner->push_back(tp1);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
} else if(tp0->slice->band < tp1->slice->band) {
|
|
Track *precursor = tp0->owner;
|
|
if(ilo == 1) {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
precursor->push_back(tp1);
|
|
precursor->endTrack(true);
|
|
TimeType time = precursor->end/res;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&lo->trackMutex[c]);
|
|
#endif
|
|
lo->createTrack(c,tp1,time,true);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&lo->trackMutex[c]);
|
|
#endif
|
|
} else {
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
TimeType time = precursor->end/res;
|
|
precursor->endTrack(true);
|
|
TrackPoint *last = precursor->back();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&lo->trackMutex[c]);
|
|
#endif
|
|
Track *t = lo->createTrack(c,last,time,true);
|
|
t->push_back(tp1);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&lo->trackMutex[c]);
|
|
#endif
|
|
last->owner = precursor;
|
|
}
|
|
} else {
|
|
Track *precursor = tp0->owner;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
precursor->push_back(tp1);
|
|
precursor->endTrack(true);
|
|
TimeType time = precursor->end*hi->res;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&hi->trackMutex[c]);
|
|
#endif
|
|
hi->createTrack(c,tp1,time,true);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&hi->trackMutex[c]);
|
|
#endif
|
|
}
|
|
tp0->bConnected = true;
|
|
tp1->bConnected = true;
|
|
tp0->bOwned = true;
|
|
tp1->bOwned = true;
|
|
if(tp0->dupcont) {
|
|
TrackPoint *dup = tp0->dupcont;
|
|
if(!dup->owner) {
|
|
dup->bOwned = true;
|
|
dup->bDelete = true;
|
|
}
|
|
}
|
|
TrackPoint *dup2 = tp0->dup[2];
|
|
if(dup2 && dup2 != tp1 && !dup2->owner) {
|
|
dup2->bOwned = true;
|
|
dup2->bDelete = true;
|
|
}
|
|
for(int d=0;d<3;d++) {
|
|
TrackPoint *dup = tp1->dup[d];
|
|
if(dup && !dup->owner && (d<2 || dup->slice->band < tp1->slice->band)) {
|
|
dup->bOwned = true;
|
|
dup->bDelete = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SMS :: mark(long offset, int c)
|
|
{
|
|
mark(offset,0,c);
|
|
if(offset&resMask) {
|
|
mark(offset,1,c);
|
|
}
|
|
}
|
|
|
|
void SMS :: mark(long offset, long offsetlo, int c)
|
|
{
|
|
if(!lo) return;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&lo->sliceMutex[c]);
|
|
#endif
|
|
Slice *sliceL1 = lo->sliceBuffer[c].read(lo->sliceBuffer[c].readPos+offset/res+offsetlo);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&lo->sliceMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
Slice *sliceM1 = sliceBuffer[c].read(sliceBuffer[c].readPos+offset);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
bool b0 = !(offset&resMask);
|
|
bool bDone = false;
|
|
bool bLastDitch = false;
|
|
while(!bDone) {
|
|
int nToCont = 0;
|
|
int nCont = 0;
|
|
TrackPoint *rbegin = NULL;
|
|
TrackPoint *begin = sliceL1->bottom;
|
|
for(TrackPoint *tp = sliceM1->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bMarked) continue;
|
|
if(tp->f > maxFMatchM) {
|
|
break;
|
|
} else {
|
|
rbegin = tp;
|
|
}
|
|
float F;
|
|
tp->cont = nearestForward(&begin,tp,&F,maxCost2Match,maxDFMatch,dMCoeff2Match);
|
|
if(tp->cont) nToCont++;
|
|
}
|
|
if(sliceL1) {
|
|
for(TrackPoint *tp = sliceL1->top;
|
|
tp;
|
|
tp = tp->pp) {
|
|
if(tp->f < minFLo) break;
|
|
float F;
|
|
tp->cont = nearestReverse(&rbegin,tp,&F,maxCost2Match,maxDFMatch,dMCoeff2Match);
|
|
}
|
|
}
|
|
for(TrackPoint *tp0 = sliceM1->bottom;
|
|
tp0;
|
|
tp0 = tp0->pn) {
|
|
if(tp0->bMarked) continue;
|
|
if(tp0->f > maxFMatchM) {
|
|
break;
|
|
}
|
|
TrackPoint *tp1 = tp0->cont;
|
|
if(tp1) {
|
|
if(bLastDitch || tp1->cont == tp0) {
|
|
nCont++;
|
|
bool bAlreadyMarked = false;
|
|
if(b0) {
|
|
if(tp1->dup[1] || tp0->dup[1]) {
|
|
bAlreadyMarked = true;
|
|
}
|
|
} else {
|
|
if(tp1->dup[2-2*offsetlo] || tp0->dup[2*offsetlo]) {
|
|
bAlreadyMarked = true;
|
|
}
|
|
}
|
|
if(!bAlreadyMarked) {
|
|
if(b0) {
|
|
tp1->dup[1] = tp0;
|
|
tp0->dup[1] = tp1;
|
|
} else {
|
|
tp1->dup[2-2*offsetlo] = tp0;
|
|
tp0->dup[2*offsetlo] = tp1;
|
|
}
|
|
}
|
|
tp0->bMarked = true;
|
|
}
|
|
}
|
|
}
|
|
bDone = (nToCont == nCont);
|
|
bLastDitch = (!bDone && nCont==0);
|
|
}
|
|
}
|
|
|
|
void SMS :: assignStart(long offset, int c)
|
|
{
|
|
bAssignDone[c] = false;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
sliceM0[c] = sliceBuffer[c].read(sliceBuffer[c].readPos+offset);
|
|
sliceM1[c] = sliceBuffer[c].read(sliceBuffer[c].readPos+offset+1);
|
|
if(res == 2) {
|
|
sliceM2[c] = sliceBuffer[c].read(sliceBuffer[c].readPos+offset+2);
|
|
} else {
|
|
sliceM2[c] = NULL;
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
for(TrackPoint *tp = sliceM0[c]->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(!tp->owner->bEnded) {
|
|
tp->owner->bEnd = true;
|
|
tp->bConnected = false;
|
|
tp->bOwned = false;
|
|
} else {
|
|
tp->bConnected = true;
|
|
tp->bOwned = true;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
if(hi) pthread_mutex_lock(&hi->sliceMutex[c]);
|
|
#endif
|
|
sliceH0[c] = hi?hi->sliceBuffer[c].read(hi->sliceBuffer[c].readPos+(offset+1)*hi->res):NULL;
|
|
sliceH0[c] = NULL;
|
|
sliceH1[c] = hi?hi->sliceBuffer[c].read(hi->sliceBuffer[c].readPos+(offset+1)*hi->res):NULL;
|
|
#ifdef MULTITHREADED
|
|
if(hi) pthread_mutex_unlock(&hi->sliceMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
if(lo) pthread_mutex_lock(&lo->sliceMutex[c]);
|
|
#endif
|
|
sliceL0[c] = lo?lo->sliceBuffer[c].read(lo->sliceBuffer[c].readPos+offset/res+1):NULL;
|
|
sliceL0[c] = NULL;
|
|
sliceL1[c] = lo?lo->sliceBuffer[c].read(lo->sliceBuffer[c].readPos+offset/res+1):NULL;
|
|
#ifdef MULTITHREADED
|
|
if(lo) pthread_mutex_unlock(&lo->sliceMutex[c]);
|
|
#endif
|
|
}
|
|
|
|
void SMS :: assignInit(long offset, int c)
|
|
{
|
|
for(TrackPoint *tp = sliceM1[c]->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
tp->cont = NULL;
|
|
tp->contF = TrackPointNoCont;
|
|
}
|
|
if(sliceM2[c]) {
|
|
for(TrackPoint *tp = sliceM2[c]->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
tp->cont = NULL;
|
|
tp->contF = TrackPointNoCont;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SMS :: assignFind(long offset, int c)
|
|
{
|
|
if(bAssignDone[c]) return;
|
|
Slice *sliceM0 = this->sliceM0[c];
|
|
Slice *sliceM1 = this->sliceM1[c];
|
|
Slice *sliceM2 = this->sliceM2[c];
|
|
Slice *sliceL1 = this->sliceL1[c];
|
|
Slice *sliceH1 = this->sliceH1[c];
|
|
TrackPoint *begin;
|
|
begin = sliceM0->bottom;
|
|
for(TrackPoint *tp = sliceM1->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bOwned) continue;
|
|
float F;
|
|
tp->bConnect = false;
|
|
TrackPoint *minM = nearestForward(&begin,tp,&F,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
if(minM && F < tp->contF) {
|
|
tp->cont = minM;
|
|
tp->contF = F;
|
|
}
|
|
}
|
|
if(sliceL1) {
|
|
TrackPoint *rbegin = sliceM0->top;
|
|
for(TrackPoint *tp = sliceL1->top;
|
|
tp;
|
|
tp = tp->pp) {
|
|
if(tp->bOwned) continue;
|
|
if(tp->f < minFLo) break;
|
|
float F;
|
|
TrackPoint *minL = nearestReverse(&rbegin,tp,&F,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
if(minL) {
|
|
F *= localFavorRatio;
|
|
if(F < tp->contF) {
|
|
tp->cont = minL;
|
|
tp->contF = F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
begin = sliceM0->bottom;
|
|
if(sliceH1) {
|
|
for(TrackPoint *tp = sliceH1->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bOwned) continue;
|
|
if(tp->f > maxFHi) break;
|
|
float F;
|
|
TrackPoint *minH = nearestForward(&begin,tp,&F,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
if(minH) {
|
|
F *= localFavorRatio;
|
|
if(F < tp->contF) {
|
|
tp->cont = minH;
|
|
tp->contF = F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(sliceM2 && !(offset&resMask)) {
|
|
begin = sliceM1->bottom;
|
|
for(TrackPoint *tp = sliceM2->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bOwned) continue;
|
|
float F;
|
|
tp->bConnect = false;
|
|
TrackPoint *minM = nearestForward(&begin,tp,&F,maxCost2,maxDF,dMCoeff2);
|
|
if(minM) {
|
|
tp->cont = minM;
|
|
tp->contF = F;
|
|
}
|
|
}
|
|
if(sliceL1) {
|
|
for(TrackPoint *tp = sliceM2->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bOwned) continue;
|
|
if(tp->f > maxFMid) break;
|
|
float F;
|
|
TrackPoint *rbegin = sliceL1->top;
|
|
TrackPoint *minL = nearestReverse(&rbegin,tp,&F,maxCost2,maxDF,dMCoeff2);
|
|
if(minL) {
|
|
F *= localFavorRatio;
|
|
if(F < tp->contF) {
|
|
tp->cont = minL;
|
|
tp->contF = F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SMS :: assignConnect(long offset, int c, bool bLastDitch)
|
|
{
|
|
if(bAssignDone[c]) return false;
|
|
Slice *sliceM0 = this->sliceM0[c];
|
|
Slice *sliceM1 = this->sliceM1[c];
|
|
Slice *sliceL1 = this->sliceL1[c];
|
|
Slice *sliceH1 = this->sliceH1[c];
|
|
int nToCont = 0;
|
|
int nCont = 0;
|
|
bool b0 = !(offset&resMask);
|
|
int ilo;
|
|
if(res == 2 && b0) {
|
|
ilo = 0;
|
|
} else {
|
|
ilo = 1;
|
|
}
|
|
TrackPoint *beginM1 = sliceM1->bottom;
|
|
TrackPoint *beginH1;
|
|
if(sliceH1) beginH1 = sliceH1->bottom;
|
|
for(TrackPoint *tp = sliceM0->bottom;
|
|
tp;
|
|
tp = tp->pn) {
|
|
if(tp->bOwned) continue;
|
|
float FM1 = TrackPointNoCont;
|
|
float FL1 = TrackPointNoCont;
|
|
float FH1 = TrackPointNoCont;
|
|
TrackPoint *minM1 = nearestForward(&beginM1,tp,&FM1,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
TrackPoint *minL1 = NULL;
|
|
if(sliceL1 && tp->f < maxFMid) {
|
|
TrackPoint *rbeginL1 = sliceL1->top;
|
|
minL1 = nearestReverse(&rbeginL1,tp,&FL1,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
FL1 *= localFavorRatio;
|
|
}
|
|
TrackPoint *minH1 = NULL;
|
|
if(sliceH1 && tp->f > minFMid) {
|
|
minH1 = nearestForward(&beginH1,tp,&FH1,maxCost2,maxDF,dMCoeff2,dNCoeff2);
|
|
FH1 *= localFavorRatio;
|
|
}
|
|
if(minM1 &&
|
|
((FM1<=FH1 && FM1<=FL1)
|
|
||(minL1 && FL1<=FH1 && FL1<=FM1 && minL1->dup[ilo] == minM1)
|
|
||(minH1 && FH1<=FL1 && FH1<=FM1 && minH1->dup[1] == minM1))) {
|
|
if(ilo == 1 && minL1 && minL1->dup[1] == minM1) {
|
|
tp->dupcont = minL1;
|
|
} else if(minH1 && minH1->dup[1] == minM1) {
|
|
tp->dupcont = minH1;
|
|
} else {
|
|
tp->dupcont = NULL;
|
|
}
|
|
tp->contF = FM1;
|
|
tp->cont = minM1;
|
|
nToCont++;
|
|
} else if(minL1 && FL1<=FM1 && FL1<=FH1) {
|
|
if(minM1 && minL1->dup[ilo] == minM1) {
|
|
tp->dupcont = minM1;
|
|
} else {
|
|
tp->dupcont = NULL;
|
|
}
|
|
tp->contF = FL1;
|
|
tp->cont = minL1;
|
|
nToCont++;
|
|
} else if(minH1 && FH1<=FM1 && FH1<=FL1) {
|
|
if(minM1 && minH1->dup[1] == minM1) {
|
|
tp->dupcont = minM1;
|
|
} else {
|
|
tp->dupcont = NULL;
|
|
}
|
|
tp->contF = FH1;
|
|
tp->cont = minH1;
|
|
nToCont++;
|
|
} else {
|
|
tp->cont = NULL;
|
|
}
|
|
}
|
|
for(TrackPoint *tp0 = sliceM0->bottom;
|
|
tp0;
|
|
tp0 = tp0->pn) {
|
|
if(tp0->bOwned) continue;
|
|
tp0->bConnect = false;
|
|
TrackPoint *tp1 = tp0->cont;
|
|
TimeType time = assigntime[c];
|
|
if(tp1 && !tp1->bOwned &&
|
|
(bLastDitch ||
|
|
(tp1->cont == tp0) ||
|
|
((tp1->cont && tp0->contF <= tp1->cont->contF) &&
|
|
((tp1->cont->dup[0] == tp0) ||
|
|
(tp1->cont->dup[1] == tp0))))) {
|
|
tp1->cont = tp0;
|
|
tp0->bConnect = true;
|
|
tp1->bConnect = true;
|
|
}
|
|
}
|
|
for(TrackPoint *tp0 = sliceM0->bottom;
|
|
tp0;
|
|
tp0 = tp0->pn) {
|
|
if(tp0->bOwned) continue;
|
|
TrackPoint *tp1 = tp0->cont;
|
|
if(tp0->bConnect && tp1 && !tp1->bOwned && tp1->bConnect && tp1->cont == tp0) {
|
|
TrackPoint *dupcont = tp0->dupcont;
|
|
if(dupcont && dupcont->bConnect) {
|
|
if(!tp1->bConnected && !dupcont->bConnected) {
|
|
if(!tp0->bConnected && (dupcont->cont == NULL || tp0->contF <= dupcont->cont->contF)) {
|
|
nCont++;
|
|
connect(tp0,tp1,ilo,c);
|
|
tp0->owner->bEnd = false;
|
|
dupcont->bConnect = false;
|
|
} else if(dupcont->cont && !dupcont->cont->bConnected) {
|
|
nCont++;
|
|
connect(dupcont->cont,dupcont,ilo,c);
|
|
dupcont->cont->owner->bEnd = false;
|
|
tp1->bConnect = false;
|
|
}
|
|
}
|
|
} else if(!tp0->bConnected && !tp1->bConnected) {
|
|
nCont++;
|
|
connect(tp0,tp1,ilo,c);
|
|
tp0->owner->bEnd = false;
|
|
}
|
|
}
|
|
}
|
|
bAssignDone[c] = (nToCont == nCont || bLastDitch);
|
|
return !(bAssignDone[c] || nCont == 0);
|
|
}
|
|
|
|
void SMS :: start(long offset, int c)
|
|
{
|
|
started[c].clear();
|
|
ended[c].clear();
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
for(list<Track*>::iterator tt = assignTracks[c].begin();
|
|
tt != assignTracks[c].end(); ) {
|
|
Track *t = (*tt);
|
|
bool bKeep;
|
|
if(t->bEnded) {
|
|
bKeep = ((!t->bRender) && (t->bStitch || t->size() >= minTrackSize));
|
|
if(assigntime[c] > t->last) {
|
|
returnTrackIndex(c,t);
|
|
list<Track*>::iterator eraseMe = tt;
|
|
++tt;
|
|
assignTracks[c].erase(eraseMe);
|
|
} else {
|
|
++tt;
|
|
}
|
|
} else if(t->bEnd) {
|
|
bKeep = (t->bStitch || t->size() >= minTrackSize);
|
|
if(bKeep) {
|
|
bKeep = !t->bRender;
|
|
t->endTrack(false);
|
|
ended[c].push_back(t->back());
|
|
++tt;
|
|
} else {
|
|
list<Track*>::iterator eraseMe = tt;
|
|
++tt;
|
|
assignTracks[c].erase(eraseMe);
|
|
returnTrackIndex(c,t);
|
|
t->absorb();
|
|
delete t;
|
|
continue;
|
|
}
|
|
} else {
|
|
bKeep = ((!t->bRender) && (t->bStitch || t->size() >= minTrackSize));
|
|
++tt;
|
|
}
|
|
if(bKeep) {
|
|
list<Track*>::reverse_iterator tt0 = renderTracks[c].rbegin();
|
|
while(tt0 != renderTracks[c].rend()) {
|
|
Track *t0 = *tt0;
|
|
if(t->start >= t0->start) {
|
|
break;
|
|
}
|
|
tt0++;
|
|
}
|
|
renderTracks[c].insert(tt0.base(),t);
|
|
t->bRender = true;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
Slice *sliceM0 = sliceBuffer[c].read(sliceBuffer[c].readPos+offset);
|
|
adjust2SliceQueue[c].push(sliceM0);
|
|
adjust1SliceQueue[c].push(sliceM0);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
for(TrackPoint *tp = sliceM0->bottom;
|
|
tp;) {
|
|
TrackPoint *tpn = tp->pn;
|
|
if(tp->bOwned) {
|
|
if(tp->bDelete) {
|
|
tp->destroy();
|
|
}
|
|
} else {
|
|
Track *t = createTrack(c,tp,assigntime[c],false);
|
|
started[c].push_back(tp);
|
|
for(int d=0;d<2;d++) {
|
|
TrackPoint *dup = tp->dup[d];
|
|
if(dup && !dup->owner) {
|
|
dup->destroy();
|
|
}
|
|
}
|
|
}
|
|
tp = tpn;
|
|
}
|
|
assigntime[c]++;
|
|
}
|
|
|
|
void SMS :: splitMerge(int c)
|
|
{
|
|
TimeType time = assigntime[c] - 1;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&trackMutex[c]);
|
|
#endif
|
|
Slice *sliceM0 = this->sliceM0[c];
|
|
Slice *sliceL0 = this->sliceL0[c];
|
|
Slice *sliceH0 = this->sliceH0[c];
|
|
Slice *sliceM1 = this->sliceM1[c];
|
|
Slice *sliceL1 = this->sliceL1[c];
|
|
Slice *sliceH1 = this->sliceH1[c];
|
|
TrackPoint *rbeginL0 = sliceL0?sliceL0->top:NULL;
|
|
TrackPoint *beginM0 = sliceM0->bottom;
|
|
TrackPoint *beginH0 = sliceH0?sliceH0->bottom:NULL;
|
|
for(list<TrackPoint*>::iterator i = started[c].begin();
|
|
i != started[c].end();
|
|
++i) {
|
|
TrackPoint *tp = *i;
|
|
float F, FL, FH;
|
|
tp->cont = nearestForward2(&beginM0,tp,&F,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
TrackPoint *minL = nearestReverse2(&rbeginL0,tp,&FL,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
if(minL) {
|
|
FL *= localFavorRatio;
|
|
if(FL < F) {
|
|
tp->cont = minL;
|
|
F = FL;
|
|
}
|
|
}
|
|
TrackPoint *minH = nearestForward2(&beginH0,tp,&FH,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
if(minH) {
|
|
FH *= localFavorRatio;
|
|
if(FH < F) {
|
|
tp->cont = minH;
|
|
}
|
|
}
|
|
if(tp->cont) {
|
|
tp->owner->point.insert(tp->owner->point.begin(),tp->cont);
|
|
tp->owner->first--;
|
|
tp->owner->bStitch = true;
|
|
tp->bSplit = true;
|
|
tp->cont->bSplit = true;
|
|
tp->owner->bSplit = true;
|
|
tp->cont->refCount++;
|
|
tp->cont->owner->bStitch = true;
|
|
}
|
|
}
|
|
|
|
TrackPoint *rbeginL1 = sliceL1?sliceL1->top:NULL;
|
|
TrackPoint *beginM1 = sliceM1->bottom;
|
|
TrackPoint *beginH1 = sliceH1?sliceH1->bottom:NULL;
|
|
for(list<TrackPoint*>::iterator i = ended[c].begin();
|
|
i != ended[c].end();
|
|
++i) {
|
|
TrackPoint *tp = *i;
|
|
float F, FL, FH;
|
|
tp->cont = nearestForward2(&beginM1,tp,&F,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
TrackPoint *minL = nearestReverse2(&rbeginL1,tp,&FL,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
if(minL) {
|
|
FL *= localFavorRatio;
|
|
if(FL < F) {
|
|
tp->cont = minL;
|
|
F = FL;
|
|
}
|
|
}
|
|
TrackPoint *minH = nearestForward2(&beginH1,tp,&FH,maxCost2SplitMerge,maxDFSplitMerge,dMCoeff2SplitMerge);
|
|
if(minH) {
|
|
FH *= localFavorRatio;
|
|
if(FH < F) {
|
|
tp->cont = minH;
|
|
}
|
|
}
|
|
if(tp->cont) {
|
|
tp->owner->point.insert(tp->owner->point.end(),tp->cont);
|
|
tp->owner->last++;
|
|
tp->owner->bStitch = true;
|
|
tp->bMerge = true;
|
|
tp->cont->bMerge = true;
|
|
tp->owner->bMerge = true;
|
|
tp->cont->refCount++;
|
|
tp->cont->owner->bStitch = true;
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&trackMutex[c]);
|
|
#endif
|
|
}
|
|
|
|
void SMS :: advance(int c)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
sliceBuffer[c].advance(1);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
}
|
|
|
|
void SMS :: add(grain *g0, grain *g1, grain *g2, int c)
|
|
{
|
|
if(c == 0) {
|
|
if(band >= minTrial1Band) {
|
|
c2even(g0->x, x00[0], N);
|
|
}
|
|
if(band >= minTrial2Band) {
|
|
c2even(g1->x, x10[0], N);
|
|
}
|
|
c2even(g2->x, x2[0], N);
|
|
} else {
|
|
if(band >= minTrial1Band) {
|
|
c2odd(g0->x, x00[1], N);
|
|
}
|
|
if(band >= minTrial2Band) {
|
|
c2odd(g1->x, x10[1], N);
|
|
}
|
|
c2odd(g2->x, x2[1], N);
|
|
}
|
|
|
|
float *mag0;
|
|
if(band >= minTrial1Band) {
|
|
mag0 = (float*)malloc((Nover2+1)*sizeof(float));
|
|
calcmags(mag0, x00[c]);
|
|
}
|
|
float *mag1;
|
|
if(band >= minTrial2Band) {
|
|
mag1 = (float*)malloc((Nover2+1)*sizeof(float));
|
|
calcmags(mag1, x10[c]);
|
|
}
|
|
float mag2sum[1024];
|
|
memset(mag2sum,0,1024*sizeof(float));
|
|
|
|
float *mag2 = this->mag2[c];
|
|
calcmags(mag2sum, g2->x);
|
|
calcmags(mag2sum, x2[c]);
|
|
calcmags(mag2, x2[c]);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&magMutex[c]);
|
|
#endif
|
|
if(band >= minTrial1Band) mag0Queue[c].push(mag0);
|
|
if(band >= minTrial2Band) mag1Queue[c].push(mag1);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&magMutex[c]);
|
|
#endif
|
|
float magmax = mag2[0];
|
|
for(int k=1;k<=kEnd;k++) {
|
|
if(magmax < mag2[k]) magmax = mag2[k];
|
|
}
|
|
float peakmin = magmax * peakThresh;
|
|
|
|
float xt2 = 1.0f;
|
|
bool bTroughN1 = false;
|
|
bool bTroughN2 = false;
|
|
float x0 = 1.0f;
|
|
float y0 = mag2[1];
|
|
float x1 = 0.0f;
|
|
float y1 = 0.0f;
|
|
bool bX0 = !lo;
|
|
bool bX1 = false;
|
|
TrackPoint *prev = NULL;
|
|
|
|
Slice *slice = new Slice(band,addtime[c]);
|
|
|
|
for(int k=1; k<=kEnd; k++) {
|
|
if(mag2[k] > peakmin && mag2[k] > mag2[k-1] && mag2[k] >= mag2[k+1]) {
|
|
if(k < kLo) {
|
|
x0 = findExtremum(mag2,mag2,k,&y0);
|
|
bX0 = true;
|
|
} else if(k > kHi) {
|
|
if(!bX1) {
|
|
x1 = findExtremum(mag2,mag2,k,&y1);
|
|
if(prev) {
|
|
prev->x01 = x1;
|
|
prev->y01 = y1;
|
|
}
|
|
bX1 = true;
|
|
}
|
|
} else {
|
|
TrackPoint *p = new TrackPoint(slice,peak2N,x2[c],mag2,mag2,k,N,band);
|
|
|
|
if(prev) {
|
|
prev->pn = p;
|
|
p->pp = prev;
|
|
} else {
|
|
slice->bottom = p;
|
|
}
|
|
slice->top = p;
|
|
prev = p;
|
|
p->xtn2 = (float)maxK;
|
|
bTroughN1 = true;
|
|
bTroughN2 = true;
|
|
p->xtp2 = xt2;
|
|
p->x01 = x0;
|
|
p->y01 = y0;
|
|
}
|
|
} else if(mag2[k] <= mag2[k-1] && mag2[k] <= mag2[k+1]) {
|
|
xt2 = findExtremum(mag2,mag2,k,NULL);
|
|
xt2 = max(1.0f,xt2);
|
|
xt2 = min((float)kEnd,xt2);
|
|
if(bTroughN2) {
|
|
prev->xtn2 = xt2;
|
|
bTroughN2 = false;
|
|
}
|
|
}
|
|
}
|
|
if(bTroughN2) {
|
|
prev->xtn2 = (float)kEnd;
|
|
}
|
|
if(!bX1 && !hi) {
|
|
x1 = (float)kEnd;
|
|
y1 = mag2[kEnd];
|
|
bX1 = true;
|
|
}
|
|
float *dec2 = this->dec2[c];
|
|
memset(dec2,0,(Nover2+1)*sizeof(float));
|
|
if(bX0 && prev) {
|
|
int k1 = lrintf(x0);
|
|
int ko1 = k1 > x0 ? -1 : 1;
|
|
float kf1 = k1 > x0 ? k1 - x0 : x0 - k1;
|
|
int k3 = min(kEnd,k1+peakWidth2);
|
|
for(int k=lrintf(slice->bottom->xtp2);k<=k3;k++) {
|
|
float m = interp2(k-k1,ko1,kf1);
|
|
dec2[k] += m * y0;
|
|
}
|
|
}
|
|
if(bX1 && prev) {
|
|
int k1 = lrintf(x1);
|
|
int ko1 = k1 > x1 ? -1 : 1;
|
|
float kf1 = k1 > x1 ? k1 - x1 : x1 - k1;
|
|
int k3 = lrintf(slice->top->xtn2);
|
|
for(int k=max(0,k1-peakWidth2);k<=k3;k++) {
|
|
float m = interp2(k-k1,ko1,kf1);
|
|
dec2[k] += m * y1;
|
|
}
|
|
}
|
|
for(TrackPoint *p = slice->bottom;
|
|
p;
|
|
p = p->pn) {
|
|
int k1 = lrintf(p->x);
|
|
int ko1 = k1 > p->x ? -1 : 1;
|
|
float kf1 = k1 > p->x ? k1 - p->x : p->x - k1;
|
|
int k0 = lrintf(p->xtp2);
|
|
float kf0 = (k0 > p->xtp2 ? k0 - p->xtp2 : p->xtp2 - k0);
|
|
int k2 = lrintf(p->xtn2);
|
|
float kf2 = (k2 > p->xtn2 ? k2 - p->xtn2 : p->xtn2 - k2);
|
|
float m2 = 0.0f;
|
|
if(k0 < p->xtp2) {
|
|
m2 += (mag2[k0] + mag2[k0+1]) * 0.5f * (1.0f - kf0) + 0.5f * mag2[k0+1];
|
|
int i = k0 - k1;
|
|
float m = interp2(i,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k0]) * 0.5f * (1.0f + kf0);
|
|
m2 += m;
|
|
dec2[k0] += m;
|
|
m = interp2(i+1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k0+1]) * 0.5f * kf0;
|
|
m2 += m;
|
|
dec2[k0+1] += m;
|
|
m = interp2(i-1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k0-1]);
|
|
m2 += m;
|
|
dec2[k0-1] += m;
|
|
} else {
|
|
m2 += (mag2[k0] + mag2[k0-1]) * 0.5f * kf0 + 0.5f * mag2[k0] + mag2[k0+1];
|
|
int i = k0 - k1;
|
|
float m = interp2(i,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k0]) * 0.5f * (1.0f - kf0);
|
|
m2 += m;
|
|
dec2[k0] += m;
|
|
m = interp2(i-1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k0-1]) * 0.5f * (2.0f - kf0);
|
|
m2 += m;
|
|
dec2[k0-1] += m;
|
|
}
|
|
if(k2 < p->xtn2) {
|
|
m2 += mag2[k2-1] + 0.5f * mag2[k2] + 0.5f * kf2 * (mag2[k2] + mag2[k2+1]);
|
|
int i = k2 - k1;
|
|
float m = interp2(i,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k2]) * 0.5f * (1.0f - kf2);
|
|
m2 += m;
|
|
dec2[k2] += m;
|
|
m = interp2(i+1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k2+1]) * 0.5f * (2.0f - kf2);
|
|
m2 += m;
|
|
dec2[k2+1] += m;
|
|
} else {
|
|
m2 += (mag2[k2-1] + mag2[k2]) * (1.0f - kf2) * 0.5f + 0.5f * mag2[k2-1];
|
|
int i = k2 - k1;
|
|
float m = interp2(i,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k2]) * 0.5f * (1.0f + kf2);
|
|
m2 += m;
|
|
dec2[k2] += m;
|
|
m = interp2(i-1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k2-1]) * 0.5f * kf2;
|
|
m2 += m;
|
|
dec2[k2-1] += m;
|
|
m = interp2(i+1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k2+1]);
|
|
m2 += m;
|
|
dec2[k2+1] += m;
|
|
}
|
|
for(int k=k0+2;k<k2-1;k++) {
|
|
m2 += mag2[k];
|
|
}
|
|
if(k0 + 1 == k2 - 1) {
|
|
m2 -= mag2[k0+1];
|
|
}
|
|
for(int k=max(0,k1-peakWidth2);k<k0-1;k++) {
|
|
float m = interp2(k-k1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k]);
|
|
m2 += m;
|
|
dec2[k] += m;
|
|
}
|
|
int k3 = min(kEnd,k1+peakWidth2);
|
|
for(int k=k2+2;k<=k3;k++) {
|
|
float m = interp2(k-k1,ko1,kf1) * p->y;
|
|
m = min(m,mag2[k]);
|
|
m2 += m;
|
|
dec2[k] += m;
|
|
}
|
|
p->m2 = m2;
|
|
}
|
|
float m2max = 0.0f;
|
|
for(TrackPoint *p = slice->bottom;
|
|
p;
|
|
p = p->pn) {
|
|
int k1 = lrintf(p->x);
|
|
int ko1 = k1 > p->x ? -1 : 1;
|
|
float kf1 = k1 > p->x ? k1 - p->x : p->x - k1;
|
|
int k0 = lrintf(p->xtp2);
|
|
float kf0 = (k0 > p->xtp2 ? k0 - p->xtp2 : p->xtp2 - k0);
|
|
int k2 = lrintf(p->xtn2);
|
|
float kf2 = (k2 > p->xtn2 ? k2 - p->xtn2 : p->xtn2 - k2);
|
|
float mdec = 0.0f;
|
|
if(k0 < p->xtp2) {
|
|
mdec += (dec2[k0] + dec2[k0+1]) * 0.5f * (1.0f - kf0) + 0.5f * dec2[k0+1];
|
|
} else {
|
|
mdec += (dec2[k0] + dec2[k0-1]) * 0.5f * kf0 + 0.5f * dec2[k0] + dec2[k0+1];
|
|
}
|
|
if(k2 < p->xtn2) {
|
|
mdec += dec2[k2-1] + 0.5f * dec2[k2] + 0.5f * kf2 * (dec2[k2] + dec2[k2+1]);
|
|
} else {
|
|
mdec += (dec2[k2-1] + dec2[k2]) * (1.0f - kf2) * 0.5f + 0.5f * dec2[k2-1];
|
|
}
|
|
for(int k=k0+2;k<k2-1;k++) {
|
|
mdec += dec2[k];
|
|
}
|
|
if(k0 + 1 == k2 - 1) {
|
|
mdec -= dec2[k0+1];
|
|
}
|
|
|
|
p->m2 -= mdec;
|
|
p->m2 *= mNorm;
|
|
if(p->m2 > m2max) {
|
|
m2max = p->m2;
|
|
}
|
|
}
|
|
float m2min = m2max * peakThresh;
|
|
for(TrackPoint *p = slice->bottom;
|
|
p; ) {
|
|
TrackPoint *pn = p->pn;
|
|
if(p->m2 < m2min) {
|
|
if(p->m2 < 0) { p->m2 = 0; }
|
|
p->absorb();
|
|
delete p;
|
|
}
|
|
p = pn;
|
|
}
|
|
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&sliceMutex[c]);
|
|
#endif
|
|
sliceBuffer[c].write(slice);
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&sliceMutex[c]);
|
|
#endif
|
|
addtime[c]++;
|
|
}
|
|
|
|
void SMS :: prepad1(audio *buf, long n)
|
|
{
|
|
if(band >= minTrial2Band) {
|
|
trial2GrainBuf->write(buf,n);
|
|
}
|
|
}
|
|
|
|
void SMS :: prepad0(audio *buf, long n)
|
|
{
|
|
if(band >= minTrial1Band) {
|
|
trial1GrainBuf->write(buf,n);
|
|
}
|
|
}
|
|
|
|
int SMS :: getTrial2Latency()
|
|
{
|
|
return minTrackSize;
|
|
}
|
|
|
|
Track *SMS :: createTrack(int c, TrackPoint *tp, const TimeType &time, bool bStitch)
|
|
{
|
|
TrackIndexType index;
|
|
if(trackIndex[c].empty()) {
|
|
index = trackIndexNone;
|
|
} else {
|
|
index = trackIndex[c].front();
|
|
trackIndex[c].pop();
|
|
}
|
|
Track *t = new Track(h1,index,tp,time,bStitch);
|
|
assignTracks[c].push_back(t);
|
|
return t;
|
|
}
|
|
|
|
void SMS :: returnTrackIndex(int c, Track *t)
|
|
{
|
|
if(t->index != trackIndexNone) {
|
|
trackIndex[c].push(t->index);
|
|
t->index = trackIndexNone;
|
|
}
|
|
}
|
|
|
|
float SMS :: interp2(int k, int ko, float kf) {
|
|
return (1.0f-kf)*peak2N[k] + kf*peak2N[k+ko];
|
|
}
|
|
|
|
float SMS :: findExtremum(float *mag, float *mag2, int k, float *y)
|
|
{
|
|
float y0 = mag[k-1];
|
|
float y1 = mag[k];
|
|
float y2 = mag[k+1];
|
|
float d = (y0 + y2 - y1 - y1);
|
|
float x = (d==0.0f?k:k + 0.5f * (y0 - y2) / d);
|
|
if(y) {
|
|
int ki = lrintf(x);
|
|
float kf = ki<x?x-ki:ki-x;
|
|
int ki1 = ki<k?ki+1:ki-1;
|
|
*y = ((1.0f-kf)*mag2[ki] + kf*mag2[ki1]);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
void SMS :: calcmags(float *mag, audio *x) {
|
|
for(int k=0;k<=Nover2;k++) {
|
|
mag[k] = norm2(x[k]);
|
|
}
|
|
}
|
|
|
|
SynthRenderer :: SynthRenderer(int channels, int h)
|
|
{
|
|
this->channels = channels;
|
|
for(int c=0; c<channels; c++) {
|
|
sines[c] = new ArrayRingBuffer<float>(0);
|
|
synthBufLength[c] = h << 4;
|
|
synthBuf[c] = (float*)malloc(synthBufLength[c]*sizeof(float));
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_init(&bufferMutex,NULL);
|
|
#endif
|
|
}
|
|
|
|
SynthRenderer :: ~SynthRenderer()
|
|
{
|
|
for(int c=0; c<channels; c++) {
|
|
delete sines[c];
|
|
free(synthBuf[c]);
|
|
}
|
|
}
|
|
|
|
void SynthRenderer :: startTime(int c, const TimeType &time, int n)
|
|
{
|
|
if(n > synthBufLength[c]) {
|
|
free(synthBuf[c]);
|
|
synthBufLength[c] = n << 1;
|
|
synthBuf[c] = (float*)malloc(synthBufLength[c]*sizeof(float));
|
|
}
|
|
this->n[c] = n;
|
|
this->time[c] = time;
|
|
memset(synthBuf[c],0,n*sizeof(float));
|
|
}
|
|
|
|
void SynthRenderer :: render(int c, SBSMSTrack *t)
|
|
{
|
|
((Track*)t)->synth(synthBuf[c],time[c],n[c],synthModeOutput,c);
|
|
}
|
|
|
|
void SynthRenderer :: endTime(int c)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&bufferMutex);
|
|
#endif
|
|
int n = this->n[c];
|
|
sines[c]->grow(n);
|
|
long j = sines[c]->writePos;
|
|
float *dest = sines[c]->buf;
|
|
float *src = synthBuf[c];
|
|
for(int k=0; k<n; k++) {
|
|
dest[j++] += src[k];
|
|
}
|
|
sines[c]->writePos += n;
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&bufferMutex);
|
|
#endif
|
|
}
|
|
|
|
long SynthRenderer :: read(audio *out, long n)
|
|
{
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_lock(&bufferMutex);
|
|
#endif
|
|
n = min(n,sines[0]->nReadable());
|
|
for(int c=1; c<channels; c++) {
|
|
n = min(n,sines[c]->nReadable());
|
|
}
|
|
for(int c=0; c<channels; c++) {
|
|
float *buf = sines[c]->getReadBuf();
|
|
for(int k=0; k<n; k++) {
|
|
out[k][c] = buf[k];
|
|
}
|
|
sines[c]->advance(n);
|
|
}
|
|
#ifdef MULTITHREADED
|
|
pthread_mutex_unlock(&bufferMutex);
|
|
#endif
|
|
return n;
|
|
}
|
|
|
|
}
|