GUI: sample resampling
This commit is contained in:
parent
90a18611cd
commit
03cb910e93
|
@ -282,6 +282,7 @@ src/engine/config.cpp
|
||||||
src/engine/dispatchContainer.cpp
|
src/engine/dispatchContainer.cpp
|
||||||
src/engine/engine.cpp
|
src/engine/engine.cpp
|
||||||
src/engine/fileOps.cpp
|
src/engine/fileOps.cpp
|
||||||
|
src/engine/filter.cpp
|
||||||
src/engine/instrument.cpp
|
src/engine/instrument.cpp
|
||||||
src/engine/macroInt.cpp
|
src/engine/macroInt.cpp
|
||||||
src/engine/pattern.cpp
|
src/engine/pattern.cpp
|
||||||
|
|
88
src/engine/filter.cpp
Normal file
88
src/engine/filter.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* Furnace Tracker - multi-system chiptune tracker
|
||||||
|
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
#include "filter.h"
|
||||||
|
#include "../ta-log.h"
|
||||||
|
|
||||||
|
float* DivFilterTables::cubicTable=NULL;
|
||||||
|
float* DivFilterTables::sincTable=NULL;
|
||||||
|
float* DivFilterTables::sincIntegralTable=NULL;
|
||||||
|
|
||||||
|
// portions from Schism Tracker (scripts/lutgen.c)
|
||||||
|
// licensed under same license as this program.
|
||||||
|
float* DivFilterTables::getCubicTable() {
|
||||||
|
if (cubicTable==NULL) {
|
||||||
|
logD("initializing cubic spline table.\n");
|
||||||
|
cubicTable=new float[4096];
|
||||||
|
|
||||||
|
for (int i=0; i<1024; i++) {
|
||||||
|
float x=(float)i/1024.0;
|
||||||
|
cubicTable[(i<<2)]=-0.5*pow(x,3)+1.0*pow(x,2)-0.5*x;
|
||||||
|
cubicTable[1+(i<<2)]=1.5*pow(x,3)-2.5*pow(x,2)+1.0;
|
||||||
|
cubicTable[2+(i<<2)]=-1.5*pow(x,3)+2.0*pow(x,2)+0.5*x;
|
||||||
|
cubicTable[3+(i<<2)]=0.5*pow(x,3)-0.5*pow(x,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cubicTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
float* DivFilterTables:: getSincTable() {
|
||||||
|
if (sincTable==NULL) {
|
||||||
|
logD("initializing sinc table.\n");
|
||||||
|
sincTable=new float[65536];
|
||||||
|
|
||||||
|
sincTable[0]=1.0f;
|
||||||
|
for (int i=1; i<65536; i++) {
|
||||||
|
int mapped=((i&8191)<<3)|(i>>13);
|
||||||
|
double x=(double)i*M_PI/8192.0;
|
||||||
|
sincTable[mapped]=sin(x)/x;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<65536; i++) {
|
||||||
|
int mapped=((i&8191)<<3)|(i>>13);
|
||||||
|
sincTable[mapped]*=pow(cos(M_PI*(double)i/131072.0),2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sincTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
float* DivFilterTables::getSincIntegralTable() {
|
||||||
|
if (sincIntegralTable==NULL) {
|
||||||
|
logD("initializing sinc integral table.\n");
|
||||||
|
sincIntegralTable=new float[65536];
|
||||||
|
|
||||||
|
sincIntegralTable[0]=-0.5f;
|
||||||
|
for (int i=1; i<65536; i++) {
|
||||||
|
int mapped=((i&8191)<<3)|(i>>13);
|
||||||
|
int mappedPrev=(((i-1)&8191)<<3)|((i-1)>>13);
|
||||||
|
double x=(double)i*M_PI/8192.0;
|
||||||
|
double sinc=sin(x)/x;
|
||||||
|
sincIntegralTable[mapped]=sincIntegralTable[mappedPrev]+(sinc/8192.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<65536; i++) {
|
||||||
|
int mapped=((i&8191)<<3)|(i>>13);
|
||||||
|
sincIntegralTable[mapped]*=pow(cos(M_PI*(double)i/131072.0),2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sincIntegralTable;
|
||||||
|
}
|
43
src/engine/filter.h
Normal file
43
src/engine/filter.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Furnace Tracker - multi-system chiptune tracker
|
||||||
|
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DivFilterTables {
|
||||||
|
public:
|
||||||
|
static float* cubicTable;
|
||||||
|
static float* sincTable;
|
||||||
|
static float* sincIntegralTable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a 1024x4 cubic spline table.
|
||||||
|
* @return the table.
|
||||||
|
*/
|
||||||
|
static float* getCubicTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a 8192x8 one-side sine-windowed sinc table.
|
||||||
|
* @return the table.
|
||||||
|
*/
|
||||||
|
static float* getSincTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a 8192x8 one-side sine-windowed sinc integral table.
|
||||||
|
* @return the table.
|
||||||
|
*/
|
||||||
|
static float* getSincIntegralTable();
|
||||||
|
};
|
|
@ -19,9 +19,10 @@
|
||||||
|
|
||||||
#include "sample.h"
|
#include "sample.h"
|
||||||
#include "../ta-log.h"
|
#include "../ta-log.h"
|
||||||
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
#include <math.h>
|
#include "filter.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "../../extern/adpcm/bs_codec.h"
|
#include "../../extern/adpcm/bs_codec.h"
|
||||||
|
@ -178,6 +179,348 @@ bool DivSample::resize(unsigned int count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RESAMPLE_BEGIN \
|
||||||
|
if (samples<1) return true; \
|
||||||
|
int finalCount=(double)samples*(r/(double)rate); \
|
||||||
|
signed char* oldData8=data8; \
|
||||||
|
short* oldData16=data16; \
|
||||||
|
if (depth==16) { \
|
||||||
|
if (data16!=NULL) { \
|
||||||
|
data16=NULL; \
|
||||||
|
initInternal(16,finalCount); \
|
||||||
|
} \
|
||||||
|
} else if (depth==8) { \
|
||||||
|
if (data8!=NULL) { \
|
||||||
|
data8=NULL; \
|
||||||
|
initInternal(8,finalCount); \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RESAMPLE_END \
|
||||||
|
samples=finalCount; \
|
||||||
|
if (depth==16) { \
|
||||||
|
delete[] oldData16; \
|
||||||
|
} else if (depth==8) { \
|
||||||
|
delete[] oldData8; \
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resampleNone(double r) {
|
||||||
|
RESAMPLE_BEGIN;
|
||||||
|
|
||||||
|
if (depth==16) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
unsigned int pos=(unsigned int)((double)i*((double)rate/r));
|
||||||
|
if (pos>=samples) {
|
||||||
|
data16[i]=0;
|
||||||
|
} else {
|
||||||
|
data16[i]=oldData16[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (depth==8) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
unsigned int pos=(unsigned int)((double)i*((double)rate/r));
|
||||||
|
if (pos>=samples) {
|
||||||
|
data8[i]=0;
|
||||||
|
} else {
|
||||||
|
data8[i]=oldData8[pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate=r;
|
||||||
|
|
||||||
|
RESAMPLE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resampleLinear(double r) {
|
||||||
|
RESAMPLE_BEGIN;
|
||||||
|
|
||||||
|
double posFrac=0;
|
||||||
|
unsigned int posInt=0;
|
||||||
|
double factor=(double)rate/r;
|
||||||
|
|
||||||
|
if (depth==16) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
short s1=(posInt>=samples)?0:oldData16[posInt];
|
||||||
|
short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1];
|
||||||
|
|
||||||
|
data16[i]=s1+(float)(s2-s1)*posFrac;
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (depth==8) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
short s1=(posInt>=samples)?0:oldData8[posInt];
|
||||||
|
short s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1];
|
||||||
|
|
||||||
|
data8[i]=s1+(float)(s2-s1)*posFrac;
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate=r;
|
||||||
|
|
||||||
|
RESAMPLE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resampleCubic(double r) {
|
||||||
|
RESAMPLE_BEGIN;
|
||||||
|
|
||||||
|
double posFrac=0;
|
||||||
|
unsigned int posInt=0;
|
||||||
|
double factor=(double)rate/r;
|
||||||
|
float* cubicTable=DivFilterTables::getCubicTable();
|
||||||
|
|
||||||
|
if (depth==16) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
|
||||||
|
float* t=&cubicTable[n<<2];
|
||||||
|
float s0=(posInt<1)?0:oldData16[posInt-1];
|
||||||
|
float s1=(posInt>=samples)?0:oldData16[posInt];
|
||||||
|
float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+1];
|
||||||
|
float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData16[loopStart]:0):oldData16[posInt+2];
|
||||||
|
|
||||||
|
float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3];
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
data16[i]=result;
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (depth==8) {
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*1024.0))&1023;
|
||||||
|
float* t=&cubicTable[n<<2];
|
||||||
|
float s0=(posInt<1)?0:oldData8[posInt-1];
|
||||||
|
float s1=(posInt>=samples)?0:oldData8[posInt];
|
||||||
|
float s2=(posInt+1>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+1];
|
||||||
|
float s3=(posInt+2>=samples)?((loopStart>=0 && loopStart<(int)samples)?oldData8[loopStart]:0):oldData8[posInt+2];
|
||||||
|
|
||||||
|
float result=s0*t[0]+s1*t[1]+s2*t[2]+s3*t[3];
|
||||||
|
if (result<-128) result=-128;
|
||||||
|
if (result>127) result=127;
|
||||||
|
data8[i]=result;
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate=r;
|
||||||
|
|
||||||
|
RESAMPLE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resampleBlep(double r) {
|
||||||
|
RESAMPLE_BEGIN;
|
||||||
|
|
||||||
|
double posFrac=0;
|
||||||
|
unsigned int posInt=0;
|
||||||
|
double factor=r/(double)rate;
|
||||||
|
float* sincITable=DivFilterTables::getSincIntegralTable();
|
||||||
|
float s[16];
|
||||||
|
|
||||||
|
memset(s,0,16*sizeof(float));
|
||||||
|
|
||||||
|
if (depth==16) {
|
||||||
|
memset(data16,0,finalCount*sizeof(short));
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
if (posInt<samples) {
|
||||||
|
int result=data16[i]+oldData16[posInt];
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
data16[i]=result;
|
||||||
|
}
|
||||||
|
|
||||||
|
posFrac+=1.0;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||||
|
posFrac-=factor;
|
||||||
|
posInt++;
|
||||||
|
|
||||||
|
float* t1=&sincITable[(8191-n)<<3];
|
||||||
|
float* t2=&sincITable[n<<3];
|
||||||
|
float delta=oldData16[posInt]-oldData16[posInt-1];
|
||||||
|
|
||||||
|
for (int j=0; j<8; j++) {
|
||||||
|
if (i-j>0) {
|
||||||
|
float result=data16[i-j]+t1[j]*-delta;
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
data16[i-j]=result;
|
||||||
|
}
|
||||||
|
if (i+j+1<finalCount) {
|
||||||
|
float result=data16[i+j+1]+t2[j]*delta;
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
data16[i+j+1]=result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (depth==8) {
|
||||||
|
memset(data8,0,finalCount*sizeof(short));
|
||||||
|
for (int i=0; i<finalCount; i++) {
|
||||||
|
if (posInt<samples) {
|
||||||
|
int result=data8[i]+oldData8[posInt];
|
||||||
|
if (result<-128) result=-128;
|
||||||
|
if (result>127) result=127;
|
||||||
|
data8[i]=result;
|
||||||
|
}
|
||||||
|
|
||||||
|
posFrac+=1.0;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||||
|
posFrac-=factor;
|
||||||
|
posInt++;
|
||||||
|
|
||||||
|
float* t1=&sincITable[(8191-n)<<3];
|
||||||
|
float* t2=&sincITable[n<<3];
|
||||||
|
float delta=oldData8[posInt]-oldData8[posInt-1];
|
||||||
|
|
||||||
|
for (int j=0; j<8; j++) {
|
||||||
|
if (i-j>0) {
|
||||||
|
float result=data8[i-j]+t1[j]*-delta;
|
||||||
|
if (result<-128) result=-128;
|
||||||
|
if (result>127) result=127;
|
||||||
|
data8[i-j]=result;
|
||||||
|
}
|
||||||
|
if (i+j+1<finalCount) {
|
||||||
|
float result=data8[i+j+1]+t2[j]*delta;
|
||||||
|
if (result<-128) result=-128;
|
||||||
|
if (result>127) result=127;
|
||||||
|
data8[i+j+1]=result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate=r;
|
||||||
|
|
||||||
|
RESAMPLE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resampleSinc(double r) {
|
||||||
|
RESAMPLE_BEGIN;
|
||||||
|
|
||||||
|
double posFrac=0;
|
||||||
|
unsigned int posInt=0;
|
||||||
|
double factor=(double)rate/r;
|
||||||
|
float* sincTable=DivFilterTables::getSincTable();
|
||||||
|
float s[16];
|
||||||
|
|
||||||
|
memset(s,0,16*sizeof(float));
|
||||||
|
|
||||||
|
if (depth==16) {
|
||||||
|
for (int i=0; i<finalCount+8; i++) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||||
|
float result=0;
|
||||||
|
float* t1=&sincTable[(8191-n)<<3];
|
||||||
|
float* t2=&sincTable[n<<3];
|
||||||
|
for (int j=0; j<8; j++) {
|
||||||
|
result+=s[j]*t2[7-j];
|
||||||
|
result+=s[8+j]*t1[j];
|
||||||
|
}
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
if (i>=8) {
|
||||||
|
data16[i-8]=result;
|
||||||
|
}
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
|
||||||
|
for (int j=0; j<15; j++) s[j]=s[j+1];
|
||||||
|
s[15]=(posInt>=samples)?0:oldData16[posInt];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (depth==8) {
|
||||||
|
for (int i=0; i<finalCount+8; i++) {
|
||||||
|
unsigned int n=((unsigned int)(posFrac*8192.0))&8191;
|
||||||
|
float result=0;
|
||||||
|
float* t1=&sincTable[(8191-n)<<3];
|
||||||
|
float* t2=&sincTable[n<<3];
|
||||||
|
for (int j=0; j<8; j++) {
|
||||||
|
result+=s[j]*t2[7-j];
|
||||||
|
result+=s[8+j]*t1[j];
|
||||||
|
}
|
||||||
|
if (result<-32768) result=-32768;
|
||||||
|
if (result>32767) result=32767;
|
||||||
|
if (i>=8) {
|
||||||
|
data8[i-8]=result;
|
||||||
|
}
|
||||||
|
|
||||||
|
posFrac+=factor;
|
||||||
|
while (posFrac>=1.0) {
|
||||||
|
posFrac-=1.0;
|
||||||
|
posInt++;
|
||||||
|
|
||||||
|
for (int j=0; j<15; j++) s[j]=s[j+1];
|
||||||
|
s[15]=(posInt>=samples)?0:oldData8[posInt];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rate=r;
|
||||||
|
|
||||||
|
RESAMPLE_END;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DivSample::resample(double r, int filter) {
|
||||||
|
if (depth!=8 && depth!=16) return false;
|
||||||
|
switch (filter) {
|
||||||
|
case DIV_RESAMPLE_NONE:
|
||||||
|
return resampleNone(r);
|
||||||
|
break;
|
||||||
|
case DIV_RESAMPLE_LINEAR:
|
||||||
|
return resampleLinear(r);
|
||||||
|
break;
|
||||||
|
case DIV_RESAMPLE_CUBIC:
|
||||||
|
return resampleCubic(r);
|
||||||
|
break;
|
||||||
|
case DIV_RESAMPLE_BLEP:
|
||||||
|
return resampleBlep(r);
|
||||||
|
break;
|
||||||
|
case DIV_RESAMPLE_SINC:
|
||||||
|
return resampleSinc(r);
|
||||||
|
break;
|
||||||
|
case DIV_RESAMPLE_BEST:
|
||||||
|
if (r>rate) {
|
||||||
|
return resampleSinc(r);
|
||||||
|
} else {
|
||||||
|
return resampleBlep(r);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DivSample::render() {
|
void DivSample::render() {
|
||||||
// step 1: convert to 16-bit if needed
|
// step 1: convert to 16-bit if needed
|
||||||
if (depth!=16) {
|
if (depth!=16) {
|
||||||
|
|
|
@ -19,6 +19,15 @@
|
||||||
|
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
|
|
||||||
|
enum DivResampleFilters {
|
||||||
|
DIV_RESAMPLE_NONE=0,
|
||||||
|
DIV_RESAMPLE_LINEAR,
|
||||||
|
DIV_RESAMPLE_CUBIC,
|
||||||
|
DIV_RESAMPLE_BLEP,
|
||||||
|
DIV_RESAMPLE_SINC,
|
||||||
|
DIV_RESAMPLE_BEST
|
||||||
|
};
|
||||||
|
|
||||||
struct DivSample {
|
struct DivSample {
|
||||||
String name;
|
String name;
|
||||||
int rate, centerRate, loopStart, loopOffP;
|
int rate, centerRate, loopStart, loopOffP;
|
||||||
|
@ -53,6 +62,15 @@ struct DivSample {
|
||||||
|
|
||||||
unsigned int samples;
|
unsigned int samples;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @warning DO NOT USE - internal functions
|
||||||
|
*/
|
||||||
|
bool resampleNone(double rate);
|
||||||
|
bool resampleLinear(double rate);
|
||||||
|
bool resampleCubic(double rate);
|
||||||
|
bool resampleBlep(double rate);
|
||||||
|
bool resampleSinc(double rate);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save this sample to a file.
|
* save this sample to a file.
|
||||||
* @param path a path.
|
* @param path a path.
|
||||||
|
@ -84,6 +102,15 @@ struct DivSample {
|
||||||
*/
|
*/
|
||||||
bool resize(unsigned int count);
|
bool resize(unsigned int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change the sample rate.
|
||||||
|
* @warning do not attempt to resample outside of a synchronized block!
|
||||||
|
* @param rate number of samples.
|
||||||
|
* @param filter the interpolation filter.
|
||||||
|
* @return whether it was successful.
|
||||||
|
*/
|
||||||
|
bool resample(double rate, int filter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialize the rest of sample formats for this sample.
|
* initialize the rest of sample formats for this sample.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -159,7 +159,9 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
}
|
}
|
||||||
if (ImGui::Button("Resize")) {
|
if (ImGui::Button("Resize")) {
|
||||||
e->synchronized([this,sample]() {
|
e->synchronized([this,sample]() {
|
||||||
sample->resize(resizeSize);
|
if (!sample->resize(resizeSize)) {
|
||||||
|
showError("couldn't resize! make sure your sample is 8 or 16-bit.");
|
||||||
|
}
|
||||||
e->renderSamples();
|
e->renderSamples();
|
||||||
});
|
});
|
||||||
updateSampleTex=true;
|
updateSampleTex=true;
|
||||||
|
@ -202,7 +204,16 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
if (resampleTarget>96000) resampleTarget=96000;
|
if (resampleTarget>96000) resampleTarget=96000;
|
||||||
}
|
}
|
||||||
ImGui::Combo("Filter",&resampleStrat,resampleStrats,6);
|
ImGui::Combo("Filter",&resampleStrat,resampleStrats,6);
|
||||||
ImGui::Button("Resample");
|
if (ImGui::Button("Resample")) {
|
||||||
|
e->synchronized([this,sample]() {
|
||||||
|
if (!sample->resample(resampleTarget,resampleStrat)) {
|
||||||
|
showError("couldn't resample! make sure your sample is 8 or 16-bit.");
|
||||||
|
}
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
updateSampleTex=true;
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
} else {
|
} else {
|
||||||
resampleTarget=sample->rate;
|
resampleTarget=sample->rate;
|
||||||
|
@ -332,7 +343,7 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
|
|
||||||
ImGui::ImageButton(sampleTex,avail,ImVec2(0,0),ImVec2(1,1),0);
|
ImGui::ImageButton(sampleTex,avail,ImVec2(0,0),ImVec2(1,1),0);
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
printf("drawing\n");
|
logD("drawing\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("A workaround! Pretty cool huh?");
|
ImGui::Text("A workaround! Pretty cool huh?");
|
||||||
|
|
Loading…
Reference in a new issue