GUI: try using FFTW for per-chan osc wave center

not reliable yet
This commit is contained in:
tildearrow 2022-05-31 03:24:29 -05:00
parent c306b33603
commit 54e93db207
3504 changed files with 492683 additions and 21 deletions

View file

@ -18,9 +18,12 @@
*/
#include "gui.h"
#include "../ta-log.h"
#include "imgui.h"
#include "imgui_internal.h"
#define FURNACE_FFT_SIZE 8192
void FurnaceGUI::drawChanOsc() {
if (nextWindow==GUI_WINDOW_CHAN_OSC) {
chanOscOpen=true;
@ -61,6 +64,7 @@ void FurnaceGUI::drawChanOsc() {
float availY=ImGui::GetContentRegionAvail().y;
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) {
std::vector<DivDispatchOscBuffer*> oscBufs;
std::vector<ChanOscStatus*> oscFFTs;
std::vector<int> oscChans;
int chans=e->getTotalChannelCount();
ImDrawList* dl=ImGui::GetWindowDrawList();
@ -74,6 +78,7 @@ void FurnaceGUI::drawChanOsc() {
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
if (buf!=NULL) {
oscBufs.push_back(buf);
oscFFTs.push_back(&chanOscChan[i]);
oscChans.push_back(i);
}
}
@ -84,6 +89,7 @@ void FurnaceGUI::drawChanOsc() {
ImGui::TableNextColumn();
DivDispatchOscBuffer* buf=oscBufs[i];
ChanOscStatus* fft=oscFFTs[i];
int ch=oscChans[i];
if (buf==NULL) {
ImGui::Text("Error!");
@ -91,6 +97,14 @@ void FurnaceGUI::drawChanOsc() {
ImVec2 size=ImGui::GetContentRegionAvail();
size.y=availY/rows;
// check FFT status existence
if (fft->plan==NULL) {
logD("creating FFT plan for channel %d",ch);
fft->inBuf=(double*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(double));
fft->outBuf=(fftw_complex*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(fftw_complex));
fft->plan=fftw_plan_dft_r2c_1d(FURNACE_FFT_SIZE,fft->inBuf,fft->outBuf,FFTW_ESTIMATE);
}
int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f);
ImVec2 minArea=window->DC.CursorPos;
@ -114,30 +128,61 @@ void FurnaceGUI::drawChanOsc() {
} else {
unsigned short needlePos=buf->needle;
if (chanOscWaveCorr) {
float cutoff=0.01f;
double fftDataRate=(FURNACE_FFT_SIZE*80.0)/((double)buf->rate);
while (buf->readNeedle!=needlePos) {
//float old=chanOscLP1[ch];
chanOscLP0[ch]+=cutoff*((float)buf->data[buf->readNeedle]-chanOscLP0[ch]);
chanOscLP1[ch]+=cutoff*(chanOscLP0[ch]-chanOscLP1[ch]);
if (chanOscLP1[ch]>=20) {
lastCorrPos[ch]=buf->readNeedle;
fft->inBufPosFrac+=fftDataRate;
while (fft->inBufPosFrac>=1.0) {
fft->inBuf[fft->inBufPos]=(double)buf->data[buf->readNeedle]/32768.0;
if (++fft->inBufPos>=FURNACE_FFT_SIZE) {
fftw_execute(fft->plan);
fft->inBufPos=0;
fft->needle=buf->readNeedle;
}
fft->inBufPosFrac-=1.0;
}
buf->readNeedle++;
}
needlePos=lastCorrPos[ch];
/*
for (unsigned short i=0; i<displaySize; i++) {
short old=buf->data[needlePos--];
if (buf->data[needlePos]>old) break;
}*/
}
needlePos-=displaySize;
for (unsigned short i=0; i<512; i++) {
float x=(float)i/512.0f;
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
if (y<-0.5f) y=-0.5f;
if (y>0.5f) y=0.5f;
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y));
// find origin frequency
int point=1;
double candAmp=0.0;
for (unsigned short i=1; i<512; i++) {
fftw_complex& f=fft->outBuf[i];
// AMPLITUDE
double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/(double)i;
if (amp>candAmp) {
point=i;
candAmp=amp;
}
}
// PHASE
fftw_complex& candPoint=fft->outBuf[point];
double phase=((double)buf->rate/80.0)*(atan2(candPoint[1],candPoint[0])/(M_PI*4));
//printf("%d cphase: %f\n",ch,phase*((double)buf->rate/80.0));
String cPhase=fmt::sprintf("%d cphase: %f\n",ch,phase);
dl->AddText(inRect.Min,0xffffffff,cPhase.c_str());
needlePos=fft->needle;
needlePos-=phase;
needlePos-=displaySize;
for (unsigned short i=0; i<512; i++) {
float x=(float)i/512.0f;
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
if (y<-0.5f) y=-0.5f;
if (y>0.5f) y=0.5f;
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y));
}
} else {
needlePos-=displaySize;
for (unsigned short i=0; i<512; i++) {
float x=(float)i/512.0f;
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
if (y<-0.5f) y=-0.5f;
if (y>0.5f) y=0.5f;
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y));
}
}
}
dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale);