diff --git a/src/engine/engine.h b/src/engine/engine.h index 6741a00e2..68ec0ce5b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -298,6 +298,7 @@ class DivEngine { bool keyHit[DIV_MAX_CHANS]; float* oscBuf[2]; float oscSize; + int oscReadPos, oscWritePos; void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); @@ -772,6 +773,8 @@ class DivEngine { totalProcessed(0), oscBuf{NULL,NULL}, oscSize(1), + oscReadPos(0), + oscWritePos(0), adpcmAMem(NULL), adpcmAMemLen(0), adpcmBMem(NULL), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1776b0460..e6fb4d72c 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1896,8 +1896,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi while (metroPos>=1) metroPos--; } - memcpy(oscBuf[0],out[0],size*sizeof(float)); - memcpy(oscBuf[1],out[1],size*sizeof(float)); + for (unsigned int i=0; i=32768) oscWritePos=0; + } oscSize=size; if (forceMono) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 755b825a4..23110ef87 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2600,6 +2600,9 @@ bool FurnaceGUI::loop() { drawInsList(); drawInsEdit(); drawMixer(); + + readOsc(); + drawOsc(); drawVolMeter(); drawSettings(); @@ -3428,7 +3431,8 @@ FurnaceGUI::FurnaceGUI(): openSampleResampleOpt(false), openSampleAmplifyOpt(false), openSampleSilenceOpt(false), - openSampleFilterOpt(false) { + openSampleFilterOpt(false), + oscTotal(0) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -3469,4 +3473,5 @@ FurnaceGUI::FurnaceGUI(): memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(patChanSlideY,0,sizeof(float)*(DIV_MAX_CHANS+1)); memset(lastIns,-1,sizeof(int)*DIV_MAX_CHANS); + memset(oscValues,0,sizeof(float)*512); } diff --git a/src/gui/gui.h b/src/gui/gui.h index a797700f0..6d8f300bb 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -976,6 +976,10 @@ class FurnaceGUI { size_t sampleClipboardLen; bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt; + // oscilloscope + int oscTotal; + float oscValues[512]; + // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; @@ -996,6 +1000,8 @@ class FurnaceGUI { void updateWindowTitle(); void prepareLayout(); + void readOsc(); + float calcBPM(int s1, int s2, float hz); void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache); diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index 0bdcdf8a0..a4da29c8c 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -18,6 +18,50 @@ */ #include "gui.h" +#include + +void FurnaceGUI::readOsc() { + int writePos=e->oscWritePos; + int readPos=e->oscReadPos; + int avail=0; + int total=0; + if (writePos>=readPos) { + avail=writePos-readPos; + } else { + avail=writePos-readPos+32768; + } + if (oscTotal==0) { + oscTotal=ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate; + } else { + oscTotal=(oscTotal+(int)round(ImGui::GetIO().DeltaTime*e->getAudioDescGot().rate))>>1; + } + int bias=avail-oscTotal-e->getAudioDescGot().bufsize; + if (bias<0) bias=0; + total=oscTotal+(bias>>6); + if (total>avail) total=avail; + //printf("total: %d. avail: %d bias: %d\n",total,avail,bias); + for (int i=0; i<512; i++) { + int pos=(readPos+(i*total/512))&0x7fff; + oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; + } + + float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime; + for (int i=0; i<2; i++) { + peak[i]*=1.0-peakDecay; + if (peak[i]<0.0001) peak[i]=0.0; + float newPeak=peak[i]; + for (int j=0; joscBuf[i][pos])>newPeak) { + newPeak=fabs(e->oscBuf[i][pos]); + } + } + peak[i]+=(newPeak-peak[i])*0.9; + } + + readPos=(readPos+total)&0x7fff; + e->oscReadPos=readPos; +} void FurnaceGUI::drawOsc() { if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) { @@ -31,14 +75,9 @@ void FurnaceGUI::drawOsc() { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0)); if (ImGui::Begin("Oscilloscope",&oscOpen)) { - float values[512]; - for (int i=0; i<512; i++) { - int pos=i*e->oscSize/512; - values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; - } //ImGui::SetCursorPos(ImVec2(0,0)); ImGui::BeginDisabled(); - ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); + ImGui::PlotLines("##SingleOsc",oscValues,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); ImGui::EndDisabled(); } ImGui::PopStyleVar(3); diff --git a/src/gui/volMeter.cpp b/src/gui/volMeter.cpp index 29f62c969..7be3464e9 100644 --- a/src/gui/volMeter.cpp +++ b/src/gui/volMeter.cpp @@ -49,17 +49,9 @@ void FurnaceGUI::drawVolMeter() { ImGuiStyle& style=ImGui::GetStyle(); ImGui::ItemSize(ImVec2(4.0f,4.0f),style.FramePadding.y); ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]); - float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime; if (ImGui::ItemAdd(rect,ImGui::GetID("volMeter"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); for (int i=0; i<2; i++) { - peak[i]*=1.0-peakDecay; - if (peak[i]<0.0001) peak[i]=0.0; - for (int j=0; joscSize; j++) { - if (fabs(e->oscBuf[i][j])>peak[i]) { - peak[i]=fabs(e->oscBuf[i][j]); - } - } float logPeak=(20*log10(peak[i])/36.0); if (logPeak==NAN) logPeak=0.0; if (logPeak<-1.0) logPeak=-1.0;