mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-01 08:29:27 +02:00
747 lines
21 KiB
C++
747 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
|
|
|
|
namespace _sbsms_ {
|
|
|
|
const sbsms_quality sbsms_quality_standard = {
|
|
512,6400,0.08f,12.5f,7,64,
|
|
{6,8,8,8,12},
|
|
{384,384,576,480,384,288,336,NULL},
|
|
{4,4,4,4,4,4,4,NULL},
|
|
{1,1,2,2,1,2,1,NULL},
|
|
{2.00f,2.00f,4.00f,4.00f,4.00f,4.00f,6.00f,NULL},
|
|
{2.00f,2.00f,2.00f,2.00f,2.00f,2.00f,2.00f,NULL},
|
|
{0.75f,0.75f,0.75f,0.75f,0.75f,0.75f,0.75f,NULL}
|
|
};
|
|
|
|
const sbsms_quality sbsms_quality_fast = {
|
|
512,6400,0.08f,12.5f,7,64,
|
|
{6,8,8,8,12},
|
|
{192,192,288,240,192,144,168,NULL},
|
|
{4,4,4,4,4,4,4,NULL},
|
|
{1,1,2,2,1,2,1,NULL},
|
|
{2.00f,2.00f,2.00f,2.00f,2.00f,2.00f,3.00f,NULL},
|
|
{2.00f,2.00f,2.00f,2.00f,2.00f,2.00f,2.00f,NULL},
|
|
{0.50f,0.50f,0.75f,0.75f,0.75f,0.75f,0.75f,NULL}
|
|
};
|
|
|
|
#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->ina = make_audio_buf(sbsmser->quality.maxoutframesize);
|
|
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 = sbsmser->quality.N[sbsmser->quality.bands-1] * sbsmser->quality.M_MAX;
|
|
sbsmser->n_prespent = sbsmser->quality.N[sbsmser->quality.bands-1] / sbsmser->quality.H[2] / 2;
|
|
} else {
|
|
sbsmser->n_prepad = 0;
|
|
sbsmser->n_prespent = 0;
|
|
}
|
|
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_rate_cb getRateCB, sbsms_pitch_cb getPitchCB)
|
|
{
|
|
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(sbsms_quality),1,fp);
|
|
unsigned short maxtrackindex;
|
|
fread(&maxtrackindex,sizeof(unsigned short),1,fp);
|
|
sbsmser->fp = fp;
|
|
sbsmser->getSamplesCB = NULL;
|
|
sbsmser->getRateCB = getRateCB;
|
|
sbsmser->getPitchCB = getPitchCB;
|
|
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_rate_cb getRateCB, sbsms_pitch_cb getPitchCB, int channels, sbsms_quality *quality, bool bPreAnalyze, bool bSynthesize)
|
|
{
|
|
sbsms *sbsmser = (sbsms*) calloc(1,sizeof(sbsms));
|
|
sbsmser->channels = channels;
|
|
sbsmser->quality = *quality;
|
|
sbsmser->getSamplesCB = getSamplesCB;
|
|
sbsmser->getRateCB = getRateCB;
|
|
sbsmser->getPitchCB = getPitchCB;
|
|
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 rate = (sbsmser->getRateCB)(sbsmser->n_processed,data);
|
|
real pitch = (sbsmser->getPitchCB)(sbsmser->n_processed,data);
|
|
real a = 1.0f/rate;
|
|
|
|
if(sbsmser->n_prepad) {
|
|
a = 1.0;
|
|
n_towrite = min(sbsmser->quality.inframesize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = getSamplesCB(sbsmser->ina,sbsmser->quality.inframesize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
n_towrite = sbsmser->quality.inframesize;
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
}
|
|
}
|
|
return sbsmser->top->preAnalyze(sbsmser->ina, n_towrite, a, pitch);
|
|
}
|
|
|
|
long sbsms_read_frame(audio *buf, void *data, sbsms *sbsmser, real *pitch0, real *pitch1)
|
|
{
|
|
long n_read = 0;
|
|
long n_write = 0;
|
|
#ifdef MULTITHREADED
|
|
thread_data *threadData = (thread_data*)sbsmser->threadData;
|
|
#endif
|
|
|
|
do {
|
|
real rate = (sbsmser->getRateCB)(sbsmser->n_processed,data);
|
|
real pitch = (sbsmser->getPitchCB)(sbsmser->n_processed,data);
|
|
real a = 1.0f/rate;
|
|
|
|
if(sbsmser->n_prespent) {
|
|
n_read = sbsmser->top->read(NULL, pitch0, pitch1);
|
|
if(n_read) sbsmser->n_prespent--;
|
|
n_read = 0;
|
|
} else {
|
|
n_read = sbsmser->top->read(buf, pitch0, pitch1);
|
|
}
|
|
|
|
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->quality.inframesize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = (sbsmser->getSamplesCB)(sbsmser->ina,sbsmser->quality.inframesize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
n_towrite = sbsmser->quality.inframesize;
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
}
|
|
}
|
|
n_write = sbsmser->top->write(sbsmser->ina, n_towrite, a, pitch);
|
|
} else {
|
|
n_write = sbsmser->top->readFromFile(sbsmser->fp, a, pitch);
|
|
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 rate = (sbsmser->getRateCB)(sbsmser->n_processed,data);
|
|
real pitch = (sbsmser->getPitchCB)(sbsmser->n_processed,data);
|
|
real a = 1.0f/rate;
|
|
|
|
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->quality.inframesize,sbsmser->n_prepad);
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
sbsmser->n_prepad -= n_towrite;
|
|
} else {
|
|
n_towrite = (sbsmser->getSamplesCB)(sbsmser->ina,sbsmser->quality.inframesize,data);
|
|
sbsmser->n_processed += n_towrite;
|
|
if(n_towrite == 0) {
|
|
n_towrite = sbsmser->quality.inframesize;
|
|
memset(sbsmser->ina,0,n_towrite*sizeof(audio));
|
|
}
|
|
}
|
|
n_write = sbsmser->top->write(sbsmser->ina, n_towrite, a, pitch);
|
|
}
|
|
}
|
|
#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(sbsms_quality),1,fp);
|
|
unsigned short maxtrackindex = 0;
|
|
fwrite(&maxtrackindex,sizeof(unsigned short),1,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;
|
|
}
|
|
|
|
|
|
void sbsms_get_quality(FILE *fp, sbsms_quality *quality)
|
|
{
|
|
//samples, frames, channels
|
|
long offset = 2*sizeof(long) + sizeof(int);
|
|
fseek(fp,offset,SEEK_SET);
|
|
fread(quality,sizeof(sbsms_quality),1,fp);
|
|
}
|
|
|
|
void sbsms_seek_start_data(FILE *fp)
|
|
{
|
|
// samples, frames, channels, quality, maxtrackindex
|
|
long offset = 2*sizeof(long) + sizeof(int) + sizeof(sbsms_quality) + 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 rateCBLinear(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
real t0 = (real)nProcessed/(real)si->samplesToProcess;
|
|
if(t0 > 1.0) t0 = 1.0;
|
|
real rate = si->rate0 + (si->rate1-si->rate0)*t0;
|
|
return rate;
|
|
}
|
|
|
|
real rateCBConstant(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
return si->rate0;
|
|
}
|
|
|
|
long getLinearOutputSamples(sbsmsInfo *si)
|
|
{
|
|
real s;
|
|
if(si->rate0 == si->rate1) {
|
|
s = 1.0f / si->rate0;
|
|
} else {
|
|
s = log(si->rate1/si->rate0)/(si->rate1-si->rate0);
|
|
}
|
|
return (long) (s * si->samplesToProcess);
|
|
}
|
|
|
|
real pitchCBLinear(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
|
|
real t0 = (real)nProcessed/(real)si->samplesToProcess;
|
|
if(t0 > 1.0f) t0 = 1.0f;
|
|
|
|
real rate = si->rate0 + (si->rate1-si->rate0)*t0;
|
|
real stretch;
|
|
if(rate == si->rate0)
|
|
stretch = 1.0f/rate;
|
|
else
|
|
stretch = log(rate/si->rate0)/(rate-si->rate0);
|
|
real t1 = stretch * (real)nProcessed/(real)si->samplesToGenerate;
|
|
if(t1 > 1.0f) t1 = 1.0f;
|
|
|
|
real pitch = si->pitch0 + (si->pitch1-si->pitch0)*t1;
|
|
return pitch;
|
|
}
|
|
|
|
real pitchCBConstant(long nProcessed, void *userData)
|
|
{
|
|
sbsmsInfo *si = (sbsmsInfo*) userData;
|
|
return si->pitch0;
|
|
}
|
|
|
|
}
|