mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-24 14:20:19 +01:00
746 lines
21 KiB
C++
746 lines
21 KiB
C++
#include "sbsms.h"
|
|
#include "real.h"
|
|
#include "subband.h"
|
|
#include "track.h"
|
|
#include "utils.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "config.h"
|
|
#ifdef MULTITHREADED
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
using namespace _sbsms_;
|
|
|
|
real SBSMS_P1 = 2.0f;
|
|
real SBSMS_Q1 = (4.0f/3.0f);
|
|
int SBSMS_FRAME_SIZE[SBSMS_QUALITIES] = {512,512,512};
|
|
int SBSMS_BANDS[SBSMS_QUALITIES] = {7,7,7};
|
|
int SBSMS_MAX_FRAME_SIZE[SBSMS_QUALITIES] = {SBSMS_MAX_STRETCH*512,SBSMS_MAX_STRETCH*512,SBSMS_MAX_STRETCH*512};
|
|
int SBSMS_H[SBSMS_QUALITIES][5] = {{8,12,16,24,32},{6,8,8,8,12},{4,6,8,12,16}};
|
|
int SBSMS_M_MAX[SBSMS_QUALITIES] = {64,64,64};
|
|
int SBSMS_RES[SBSMS_QUALITIES][SBSMS_MAX_BANDS] = {{1,1,1,2,2,1,1}, {1,1,2,2,1,2,1}, {1,1,2,2,2,2,1}};
|
|
real SBSMS_PAD[SBSMS_QUALITIES][SBSMS_MAX_BANDS] = {{2,2,4,4,4,4,4},{2,2,4,4,4,4,6},{4,4,4,4,4,6}};
|
|
int SBSMS_N[SBSMS_QUALITIES][SBSMS_MAX_BANDS] = {{384,384,576,480,384,288,252},{384,384,576,480,384,288,336},{768,768,576,480,384,288,288}};
|
|
|
|
|
|
#ifdef MULTITHREADED
|
|
|
|
struct assign_data {
|
|
sbsms *sbsmser;
|
|
int c;
|
|
bool bFirst;
|
|
bool bLast;
|
|
};
|
|
|
|
struct thread_data {
|
|
pthread_mutex_t writeMutex;
|
|
pthread_cond_t writeCond;
|
|
|
|
pthread_t addThread;
|
|
pthread_mutex_t addMutex;
|
|
pthread_cond_t addCond;
|
|
bool bAddThread;
|
|
|
|
pthread_t assignThread[2];
|
|
pthread_mutex_t assignMutex;
|
|
pthread_cond_t assignCond;
|
|
bool bAssignThread;
|
|
assign_data assignData[2];
|
|
|
|
pthread_t synthThread;
|
|
pthread_mutex_t synthMutex;
|
|
pthread_cond_t synthCond;
|
|
bool bSynthThread;
|
|
|
|
// hack to break out of possible (but very rare) deadlocks caused by checking
|
|
// condition predicates after broadcasting conditions
|
|
pthread_t pollThread;
|
|
|
|
bool bActive;
|
|
};
|
|
|
|
void *pollThreadCB(void *data) {
|
|
sbsms *sbsmser = (sbsms*)data;
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
subband *top = sbsmser->top;
|
|
|
|
while(threadData->bActive) {
|
|
if(top->isWriteReady()) {
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_broadcast(&threadData->writeCond);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
if(top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
if(top->isMarkReady()) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_broadcast(&threadData->assignCond);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
if(top->isSynthReady()) {
|
|
if(threadData->bSynthThread) {
|
|
pthread_mutex_lock(&threadData->synthMutex);
|
|
pthread_cond_broadcast(&threadData->synthCond);
|
|
pthread_mutex_unlock(&threadData->synthMutex);
|
|
}
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_broadcast(&threadData->writeCond);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
#ifdef _WIN32
|
|
Sleep(100);
|
|
#else
|
|
usleep(100000);
|
|
#endif
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
void *addThreadCB(void *data) {
|
|
sbsms *sbsmser = (sbsms*)data;
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
subband *top = sbsmser->top;
|
|
|
|
while(threadData->bActive) {
|
|
if(!top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_wait(&threadData->addCond,&threadData->addMutex);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
while(top->addInit(true)) {
|
|
top->addTrackPoints();
|
|
top->stepAddFrame();
|
|
if(top->isMarkReady()) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_broadcast(&threadData->assignCond);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
if(top->isWriteReady()) {
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_broadcast(&threadData->writeCond);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
}
|
|
}
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
void *assignThreadCB(void *data) {
|
|
assign_data *assignData = (assign_data*)data;
|
|
sbsms *sbsmser = assignData->sbsmser;
|
|
int c = assignData->c;
|
|
bool bFirst = assignData->bFirst;
|
|
bool bLast = assignData->bLast;
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
subband *top = sbsmser->top;
|
|
|
|
while(threadData->bActive) {
|
|
if(!top->markInit(false,c)) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_wait(&threadData->assignCond,&threadData->assignMutex);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
while(top->markInit(true,c)) {
|
|
top->markDuplicates(c);
|
|
top->stepMarkFrame(c);
|
|
if(top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
}
|
|
while(top->assignInit(true,c)) {
|
|
top->assignTrackPoints(c);
|
|
top->advanceTrackPoints(c);
|
|
top->stepAssignFrame(c);
|
|
if(top->isSynthReady()) {
|
|
if(threadData->bSynthThread) {
|
|
pthread_mutex_lock(&threadData->synthMutex);
|
|
pthread_cond_broadcast(&threadData->synthCond);
|
|
pthread_mutex_unlock(&threadData->synthMutex);
|
|
}
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_broadcast(&threadData->writeCond);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
}
|
|
}
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
void *synthThreadCB(void *data) {
|
|
sbsms *sbsmser = (sbsms*)data;
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
subband *top = sbsmser->top;
|
|
|
|
while(threadData->bActive) {
|
|
if(!top->isSynthReady()) {
|
|
pthread_mutex_lock(&threadData->synthMutex);
|
|
pthread_cond_wait(&threadData->synthCond,&threadData->synthMutex);
|
|
pthread_mutex_unlock(&threadData->synthMutex);
|
|
}
|
|
while(top->synthInit(true)) {
|
|
top->synthTracks();
|
|
top->stepSynthFrame();
|
|
if(top->isAssignReady()) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_wait(&threadData->assignCond,&threadData->assignMutex);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
}
|
|
}
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
void sbsms_init_threads(sbsms *sbsmser, bool bAnalyze, bool bSynthesize)
|
|
{
|
|
thread_data *threadData = (thread_data*)calloc(1,sizeof(thread_data));
|
|
sbsmser->threadData = threadData;
|
|
threadData->bActive = true;
|
|
|
|
pthread_cond_init(&threadData->writeCond, NULL);
|
|
pthread_mutex_init(&threadData->writeMutex, NULL);
|
|
|
|
if(bAnalyze) {
|
|
pthread_cond_init(&threadData->addCond, NULL);
|
|
pthread_mutex_init(&threadData->addMutex, NULL);
|
|
threadData->bAddThread = true;
|
|
|
|
pthread_cond_init(&threadData->assignCond, NULL);
|
|
pthread_mutex_init(&threadData->assignMutex, NULL);
|
|
threadData->bAssignThread = true;
|
|
|
|
for(int c=0;c<sbsmser->channels;c++) {
|
|
threadData->assignData[c].sbsmser = sbsmser;
|
|
threadData->assignData[c].c = c;
|
|
threadData->assignData[c].bFirst = (c==0);
|
|
threadData->assignData[c].bLast = (c==sbsmser->channels-1);
|
|
}
|
|
} else {
|
|
threadData->bAddThread = false;
|
|
threadData->bAssignThread = false;
|
|
}
|
|
|
|
if(!bAnalyze) bSynthesize = false;
|
|
|
|
if(bSynthesize) {
|
|
pthread_cond_init(&threadData->synthCond, NULL);
|
|
pthread_mutex_init(&threadData->synthMutex, NULL);
|
|
threadData->bSynthThread = true;
|
|
} else {
|
|
threadData->bSynthThread = false;
|
|
}
|
|
|
|
if(bAnalyze) {
|
|
pthread_create(&threadData->addThread, NULL, addThreadCB, (void*)sbsmser);
|
|
for(int c=0;c<sbsmser->channels;c++) {
|
|
pthread_create(&threadData->assignThread[c], NULL, assignThreadCB, (void*)(&threadData->assignData[c]));
|
|
}
|
|
}
|
|
if(bSynthesize) {
|
|
pthread_create(&threadData->synthThread, NULL, synthThreadCB, (void*)sbsmser);
|
|
}
|
|
|
|
pthread_create(&threadData->pollThread, NULL, pollThreadCB, (void*)sbsmser);
|
|
}
|
|
|
|
void sbsms_destroy_threads(sbsms *sbsmser)
|
|
{
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
threadData->bActive = false;
|
|
if(threadData->bAddThread) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
pthread_join(threadData->addThread,NULL);
|
|
}
|
|
if(threadData->bAssignThread) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_broadcast(&threadData->assignCond);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
for(int c=0;c<sbsmser->channels;c++) {
|
|
pthread_join(threadData->assignThread[c],NULL);
|
|
}
|
|
}
|
|
if(threadData->bSynthThread) {
|
|
pthread_mutex_lock(&threadData->synthMutex);
|
|
pthread_cond_broadcast(&threadData->synthCond);
|
|
pthread_mutex_unlock(&threadData->synthMutex);
|
|
pthread_join(threadData->synthThread,NULL);
|
|
}
|
|
pthread_join(threadData->pollThread,NULL);
|
|
}
|
|
#else
|
|
void sbsms_init_threads(sbsms *sbsmser, bool bAnalyze, bool bSynthesize)
|
|
{
|
|
sbsmser->threadData = NULL;
|
|
}
|
|
void sbsms_destroy_threads(sbsms *sbsmser)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void sbsms_init(int n) {
|
|
cosinit(n);
|
|
}
|
|
|
|
void sbsms_private_init(sbsms *sbsmser, bool bAnalyze, bool bSynthesize)
|
|
{
|
|
sbsmser->bufsize = SBSMS_MAX_FRAME_SIZE[sbsmser->quality];
|
|
sbsmser->chunksize = SBSMS_FRAME_SIZE[sbsmser->quality];
|
|
sbsmser->n_postpad = LONG_MAX;
|
|
sbsmser->ina = make_audio_buf(sbsmser->bufsize);
|
|
sbsms_init_threads(sbsmser,bAnalyze,bSynthesize);
|
|
}
|
|
|
|
void sbsms_reset(sbsms *sbsmser)
|
|
{
|
|
sbsmser->ta->init();
|
|
sbsmser->n_processed = 0;
|
|
sbsmser->bWritingComplete = false;
|
|
if(sbsmser->getSamplesCB) {
|
|
sbsmser->n_prepad = SBSMS_N[sbsmser->quality][SBSMS_BANDS[sbsmser->quality]-1]*SBSMS_M_MAX[sbsmser->quality];
|
|
sbsmser->n_prespent = SBSMS_N[sbsmser->quality][SBSMS_BANDS[sbsmser->quality]-1]/SBSMS_H[sbsmser->quality][2]/2;
|
|
} else {
|
|
sbsmser->n_prepad = SBSMS_N[sbsmser->quality][SBSMS_BANDS[sbsmser->quality]-1]/SBSMS_H[sbsmser->quality][2]/2;
|
|
sbsmser->n_prespent = SBSMS_N[sbsmser->quality][SBSMS_BANDS[sbsmser->quality]-1]/SBSMS_H[sbsmser->quality][2]/2;
|
|
}
|
|
sbsmser->top->reset();
|
|
}
|
|
|
|
void sbsms_seek(sbsms *sbsmser, long framePos, long samplePos)
|
|
{
|
|
sbsmser->n_processed = samplePos;
|
|
sbsmser->top->seek(framePos);
|
|
}
|
|
|
|
sbsms* sbsms_create(FILE *fp, sbsms_stretch_cb getStretchCB, sbsms_ratio_cb getRatioCB)
|
|
{
|
|
sbsms *sbsmser = (sbsms*) calloc(1,sizeof(sbsms));
|
|
// samples, frames
|
|
fseek(fp,0,SEEK_SET);
|
|
long samples, frames;
|
|
fread(&samples,sizeof(long),1,fp);
|
|
fread(&frames,sizeof(long),1,fp);
|
|
fread(&(sbsmser->channels),sizeof(int),1,fp);
|
|
fread(&(sbsmser->quality),sizeof(int),1,fp);
|
|
unsigned short maxtrackindex;
|
|
fread(&maxtrackindex,sizeof(unsigned short),1,fp);
|
|
sbsmser->fp = fp;
|
|
sbsmser->getSamplesCB = NULL;
|
|
sbsmser->getStretchCB = getStretchCB;
|
|
sbsmser->getRatioCB = getRatioCB;
|
|
sbsmser->ta = new TrackAllocator(false,maxtrackindex);
|
|
sbsmser->pa = new PeakAllocator();
|
|
sbsmser->top = new subband(NULL,1,sbsmser->channels,sbsmser->quality,2,false,sbsmser->ta,sbsmser->pa);
|
|
sbsmser->top->setFramesInFile(frames);
|
|
sbsms_private_init(sbsmser,false,false);
|
|
sbsms_reset(sbsmser);
|
|
return sbsmser;
|
|
}
|
|
|
|
sbsms* sbsms_create(sbsms_cb getSamplesCB, sbsms_stretch_cb getStretchCB, sbsms_ratio_cb getRatioCB, int channels, int quality, bool bPreAnalyze, bool bSynthesize)
|
|
{
|
|
sbsms *sbsmser = (sbsms*) calloc(1,sizeof(sbsms));
|
|
sbsmser->channels = channels;
|
|
sbsmser->quality = quality;
|
|
sbsmser->getSamplesCB = getSamplesCB;
|
|
sbsmser->getStretchCB = getStretchCB;
|
|
sbsmser->getRatioCB = getRatioCB;
|
|
sbsmser->ta = new TrackAllocator(true);
|
|
sbsmser->pa = new PeakAllocator();
|
|
sbsmser->top = new subband(NULL,1,sbsmser->channels,sbsmser->quality,6,bPreAnalyze,sbsmser->ta,sbsmser->pa);
|
|
sbsms_private_init(sbsmser,true,bSynthesize);
|
|
sbsms_reset(sbsmser);
|
|
return sbsmser;
|
|
}
|
|
|
|
void sbsms_destroy(sbsms* sbsmser)
|
|
{
|
|
free_audio_buf((audio*)sbsmser->ina);
|
|
sbsms_destroy_threads(sbsmser);
|
|
if(sbsmser->threadData)
|
|
free(sbsmser->threadData);
|
|
delete sbsmser->top;
|
|
delete sbsmser->ta;
|
|
delete sbsmser->pa;
|
|
free(sbsmser);
|
|
}
|
|
|
|
void sbsms_pre_analyze_complete(sbsms *sbsmser)
|
|
{
|
|
sbsmser->top->preAnalyzeComplete();
|
|
}
|
|
|
|
long sbsms_pre_analyze(sbsms_cb getSamplesCB, void *data, sbsms *sbsmser)
|
|
{
|
|
long n_towrite = 0;
|
|
real stretch = (sbsmser->getStretchCB)(sbsmser->n_processed,data);
|
|
real ratio = (sbsmser->getRatioCB)(sbsmser->n_processed,data);
|
|
real a = 1.0/(ratio*stretch);
|
|
|
|
if(sbsmser->n_prepad) {
|
|
a = 1.0;
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = getSamplesCB(sbsmser->ina,sbsmser->chunksize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
if(sbsmser->n_postpad) {
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_postpad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_postpad -= n_towrite;
|
|
}
|
|
}
|
|
if(n_towrite==0) {
|
|
sbsmser->bWritingComplete = true;
|
|
sbsmser->top->writingComplete();
|
|
}
|
|
}
|
|
return sbsmser->top->preAnalyze(sbsmser->ina, n_towrite, a, ratio);
|
|
}
|
|
|
|
long sbsms_read_frame(audio *buf, void *data, sbsms *sbsmser, real *ratio0, real *ratio1)
|
|
{
|
|
long n_read = 0;
|
|
long n_write = 0;
|
|
#ifdef MULTITHREADED
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
#endif
|
|
|
|
do {
|
|
real stretch = (sbsmser->getStretchCB)(sbsmser->n_processed,data);
|
|
real ratio = (sbsmser->getRatioCB)(sbsmser->n_processed,data);
|
|
real a = 1.0/(ratio*stretch);
|
|
|
|
if(sbsmser->n_prespent) {
|
|
n_read = sbsmser->top->read(NULL, ratio0, ratio1);
|
|
if(n_read) sbsmser->n_prespent--;
|
|
n_read = 0;
|
|
} else {
|
|
n_read = sbsmser->top->read(buf, ratio0, ratio1);
|
|
}
|
|
|
|
n_write = 0;
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAddThread && sbsmser->top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
#endif
|
|
if(n_read == 0) {
|
|
#ifdef MULTITHREADED
|
|
if(!sbsmser->top->isWriteReady()) {
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_wait(&threadData->writeCond,&threadData->writeMutex);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
#endif
|
|
long n_towrite = 0;
|
|
if(sbsmser->getSamplesCB) {
|
|
if(sbsmser->n_prepad) {
|
|
a = 1.0;
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = (sbsmser->getSamplesCB)(sbsmser->ina,sbsmser->chunksize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
if(sbsmser->n_postpad) {
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_postpad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_postpad -= n_towrite;
|
|
}
|
|
}
|
|
if(n_towrite==0) {
|
|
sbsmser->bWritingComplete = true;
|
|
sbsmser->top->writingComplete();
|
|
}
|
|
}
|
|
n_write = sbsmser->top->write(sbsmser->ina, n_towrite, a, ratio);
|
|
} else {
|
|
if(sbsmser->n_prepad) {
|
|
n_write = sbsmser->top->zeroPad();
|
|
sbsmser->n_prepad--;
|
|
} else {
|
|
n_write = sbsmser->top->readFromFile(sbsmser->fp, a, ratio);
|
|
sbsmser->n_processed += n_write;
|
|
if(n_write == 0) {
|
|
sbsmser->bWritingComplete = true;
|
|
sbsmser->top->writingComplete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bSynthThread && sbsmser->top->isSynthReady()) {
|
|
pthread_mutex_lock(&threadData->synthMutex);
|
|
pthread_cond_broadcast(&threadData->synthCond);
|
|
pthread_mutex_unlock(&threadData->synthMutex);
|
|
}
|
|
#endif
|
|
bool bProcess = true;
|
|
bool bSynth = true;
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAddThread && threadData->bAssignThread) bProcess = false;
|
|
if(threadData->bSynthThread) bSynth = false;
|
|
#endif
|
|
if(bProcess) sbsmser->top->process();
|
|
if(bSynth) sbsmser->top->synth();
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAssignThread && sbsmser->top->isAssignReady()) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_broadcast(&threadData->assignCond);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
#endif
|
|
if(sbsmser->bWritingComplete &&
|
|
!sbsmser->top->isframe_readable() &&
|
|
sbsmser->top->getFramesAtBack() == 0) {
|
|
n_write = sbsmser->top->zeroPad();
|
|
}
|
|
} while(!n_read);
|
|
return n_read;
|
|
}
|
|
|
|
long sbsms_write_frame(FILE *fp, void *data, sbsms *sbsmser)
|
|
{
|
|
long n_tofile = 0;
|
|
long n_write = 0;
|
|
#ifdef MULTITHREADED
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
#endif
|
|
|
|
do {
|
|
real stretch = (sbsmser->getStretchCB)(sbsmser->n_processed,data);
|
|
real ratio = (sbsmser->getRatioCB)(sbsmser->n_processed,data);
|
|
real a = 1.0/(ratio*stretch);
|
|
|
|
n_tofile = sbsmser->top->getFramesWrittenToFile();
|
|
|
|
n_write = 0;
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAddThread && sbsmser->top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
#endif
|
|
if(n_tofile == 0) {
|
|
#ifdef MULTITHREADED
|
|
if(!sbsmser->top->isWriteReady()) {
|
|
pthread_mutex_lock(&threadData->writeMutex);
|
|
pthread_cond_wait(&threadData->writeCond,&threadData->writeMutex);
|
|
pthread_mutex_unlock(&threadData->writeMutex);
|
|
}
|
|
#endif
|
|
if(sbsmser->top->isWriteReady()) {
|
|
long n_towrite = 0;
|
|
if(sbsmser->n_prepad) {
|
|
a = 1.0;
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = (sbsmser->getSamplesCB)(sbsmser->ina,sbsmser->chunksize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
if(sbsmser->n_postpad) {
|
|
n_towrite = min(sbsmser->chunksize,sbsmser->n_postpad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_postpad -= n_towrite;
|
|
}
|
|
}
|
|
if(!sbsmser->n_postpad)
|
|
sbsmser->top->writingComplete();
|
|
}
|
|
n_write = sbsmser->top->write(sbsmser->ina, n_towrite, a, ratio);
|
|
}
|
|
}
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAddThread && sbsmser->top->isAddReady()) {
|
|
pthread_mutex_lock(&threadData->addMutex);
|
|
pthread_cond_broadcast(&threadData->addCond);
|
|
pthread_mutex_unlock(&threadData->addMutex);
|
|
}
|
|
#endif
|
|
#ifndef MULTITHREADED
|
|
sbsmser->top->process();
|
|
#endif
|
|
long n_written = 0;
|
|
if(sbsmser->n_prespent) {
|
|
n_written = sbsmser->top->writeToFile(NULL);
|
|
if(n_written) sbsmser->n_prespent--;
|
|
n_written = 0;
|
|
} else {
|
|
n_written = sbsmser->top->writeToFile(fp);
|
|
}
|
|
#ifdef MULTITHREADED
|
|
if(threadData->bAssignThread && sbsmser->top->isAssignReady()) {
|
|
pthread_mutex_lock(&threadData->assignMutex);
|
|
pthread_cond_broadcast(&threadData->assignCond);
|
|
pthread_mutex_unlock(&threadData->assignMutex);
|
|
}
|
|
#endif
|
|
} while(!n_tofile);
|
|
return n_tofile;
|
|
}
|
|
|
|
FILE *sbsms_open_read(const char *fileName)
|
|
{
|
|
FILE *fp = fopen(fileName,"rb");
|
|
return fp;
|
|
}
|
|
|
|
void sbsms_close_read(FILE *fp)
|
|
{
|
|
fclose(fp);
|
|
}
|
|
|
|
FILE *sbsms_open_write(const char *fileName, sbsms *sbsmser, long samples_to_process)
|
|
{
|
|
FILE *fp = fopen(fileName,"wb");
|
|
if(!fp)
|
|
return NULL;
|
|
fwrite(&samples_to_process,sizeof(long),1,fp);
|
|
long nframes = 0;
|
|
fwrite(&nframes,sizeof(long),1,fp);
|
|
fwrite(&(sbsmser->channels),sizeof(int),1,fp);
|
|
fwrite(&(sbsmser->quality),sizeof(int),1,fp);
|
|
unsigned short maxtrackindex = 0;
|
|
fwrite(&maxtrackindex,sizeof(unsigned short),1,fp);
|
|
sbsmser->top->fp = fp;
|
|
return fp;
|
|
}
|
|
|
|
void sbsms_close_write(FILE *fp, sbsms *sbsmser)
|
|
{
|
|
sbsmser->top->writeFramePositionsToFile(fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
long sbsms_get_samples_to_process(FILE *fp)
|
|
{
|
|
fseek(fp,0,SEEK_SET);
|
|
long samples;
|
|
fread(&samples,sizeof(long),1,fp);
|
|
return samples;
|
|
}
|
|
|
|
long sbsms_get_frames_to_process(FILE *fp)
|
|
{
|
|
// samples
|
|
long offset = sizeof(long);
|
|
fseek(fp,offset,SEEK_SET);
|
|
long frames;
|
|
fread(&frames,sizeof(long),1,fp);
|
|
return frames;
|
|
}
|
|
|
|
long sbsms_get_channels(FILE *fp)
|
|
{
|
|
//samples, frames
|
|
long offset = 2*sizeof(long);
|
|
fseek(fp,offset,SEEK_SET);
|
|
int channels;
|
|
fread(&channels,sizeof(int),1,fp);
|
|
return channels;
|
|
}
|
|
|
|
long sbsms_get_quality(FILE *fp)
|
|
{
|
|
//samples, frames, channels
|
|
long offset = 2*sizeof(long) + sizeof(int);
|
|
fseek(fp,offset,SEEK_SET);
|
|
int quality;
|
|
fread(&quality,sizeof(int),1,fp);
|
|
return quality;
|
|
}
|
|
|
|
void sbsms_seek_start_data(FILE *fp)
|
|
{
|
|
// samples, frames, channels, quality, maxtrackindex
|
|
long offset = 2*sizeof(long) + 2*sizeof(int) + sizeof(unsigned short);
|
|
fseek(fp,offset,SEEK_SET);
|
|
}
|
|
|
|
long sbsms_samples_processed(sbsms *sbsmser)
|
|
{
|
|
return sbsmser->n_processed;
|
|
}
|
|
|
|
long sbsms_get_samples_queued(sbsms *sbsmser)
|
|
{
|
|
return sbsmser->top->getSamplesQueued();
|
|
}
|
|
|
|
long sbsms_get_frames_queued(sbsms *sbsmser)
|
|
{
|
|
return sbsmser->top->getFramesQueued();
|
|
}
|
|
|
|
long sbsms_get_last_input_frame_size(sbsms *sbsmser)
|
|
{
|
|
return sbsmser->top->getLastInputFrameSize();
|
|
}
|
|
|
|
long sbsms_get_frame_pos(sbsms *sbsmser)
|
|
{
|
|
return sbsmser->top->getFramePos();
|
|
}
|
|
|
|
real stretchCBLinear(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
real t0 = (real)nProcessed/(real)si->samplesToProcess;
|
|
real stretch = si->stretch0 + (si->stretch1-si->stretch0)*t0;
|
|
return stretch;
|
|
}
|
|
|
|
real stretchCBConstant(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
return si->stretch0;
|
|
}
|
|
|
|
real ratioCBLinear(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
real t0 = (real)nProcessed/(real)si->samplesToProcess;
|
|
real stretch = si->stretch0 + (si->stretch1-si->stretch0)*t0;
|
|
real t1;
|
|
if(stretch == si->stretch0)
|
|
t1 = 1.0/stretch;
|
|
else
|
|
t1 = log(stretch/si->stretch0)/(stretch-si->stretch0);
|
|
|
|
real ratio = si->ratio0 + (si->ratio1-si->ratio0)*t1*(real)nProcessed/(real)si->samplesToGenerate;
|
|
|
|
return ratio;
|
|
}
|
|
|
|
real ratioCBConstant(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
return si->ratio0;
|
|
}
|