diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5410ebf0e..919f2fdbb 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2820,9 +2820,32 @@ void DivEngine::previewSample(int sample) { samp_prevSample=0; sPreview.pos=0; sPreview.sample=sample; + sPreview.wave=-1; isBusy.unlock(); } +void DivEngine::previewWave(int wave, int note) { + isBusy.lock(); + if (wave<0 || wave>=(int)song.wave.size()) { + sPreview.wave=-1; + sPreview.pos=0; + isBusy.unlock(); + return; + } + blip_clear(samp_bb); + blip_set_rates(samp_bb,song.wave[wave]->len*(27.5*pow(2.0,(double)(note+3)/12.0)),got.rate); + samp_prevSample=0; + sPreview.pos=0; + sPreview.sample=-1; + sPreview.wave=wave; + isBusy.unlock(); +} + +void DivEngine::stopWavePreview() { + sPreview.wave=-1; + sPreview.pos=0; +} + String DivEngine::getConfigPath() { return configPath; } diff --git a/src/engine/engine.h b/src/engine/engine.h index c6edeb16d..9e1697734 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -157,9 +157,11 @@ class DivEngine { struct SamplePreview { int sample; + int wave; unsigned int pos; SamplePreview(): sample(-1), + wave(-1), pos(0) {} } sPreview; @@ -263,6 +265,10 @@ class DivEngine { // trigger sample preview void previewSample(int sample); + // trigger wave preview + void previewWave(int wave, int note); + void stopWavePreview(); + // get config path String getConfigPath(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 2b26a98fa..90855ef41 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1,4 +1,5 @@ #include "blip_buf.h" +#include "wavetable.h" #define _USE_MATH_DEFINES #include "dispatch.h" #include "engine.h" @@ -938,7 +939,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } isBusy.lock(); - if (out!=NULL && sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) { + if (out!=NULL && ((sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) || (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()))) { unsigned int samp_bbOff=0; unsigned int prevAvail=blip_samples_avail(samp_bb); if (prevAvail>size) prevAvail=size; @@ -946,22 +947,38 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi blip_read_samples(samp_bb,samp_bbOut,prevAvail,0); samp_bbOff=prevAvail; } - - DivSample* s=song.sample[sPreview.sample]; size_t prevtotal=blip_clocks_needed(samp_bb,size-prevAvail); - for (size_t i=0; i=s->rendLength) { - samp_temp=0; - } else { - samp_temp=s->rendData[sPreview.pos++]; - } - if (s->depth==8) samp_temp<<=8; - blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); - samp_prevSample=samp_temp; - } + if (sPreview.sample>=0 && sPreview.sample<(int)song.sample.size()) { + DivSample* s=song.sample[sPreview.sample]; - if (sPreview.pos>=s->rendLength) sPreview.sample=-1; + for (size_t i=0; i=s->rendLength) { + samp_temp=0; + } else { + samp_temp=s->rendData[sPreview.pos++]; + } + if (s->depth==8) samp_temp<<=8; + blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); + samp_prevSample=samp_temp; + } + + if (sPreview.pos>=s->rendLength) sPreview.sample=-1; + } else if (sPreview.wave>=0 && sPreview.wave<(int)song.wave.size()) { + DivWavetable* wave=song.wave[sPreview.wave]; + for (size_t i=0; imax<=0) { + samp_temp=0; + } else { + samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192; + } + if (++sPreview.pos>=(unsigned int)wave->len) { + sPreview.pos=0; + } + blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); + samp_prevSample=samp_temp; + } + } blip_end_frame(samp_bb,prevtotal); blip_read_samples(samp_bb,samp_bbOut+samp_bbOff,size-samp_bbOff,0); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f1aa156c4..66d181364 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1213,6 +1213,7 @@ void FurnaceGUI::drawWaveEdit() { if (wave->len>256) wave->len=256; if (wave->len<1) wave->len=1; e->notifyWaveChange(curWave); + if (wavePreviewOn) e->previewWave(curWave,wavePreviewNote); modified=true; } ImGui::SameLine(); @@ -2907,6 +2908,22 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { } } break; + case GUI_WINDOW_WAVE_LIST: + case GUI_WINDOW_WAVE_EDIT: + if (!ev.key.repeat) { + try { + int key=noteKeys.at(ev.key.keysym.scancode); + int num=12*curOctave+key; + if (key!=100) { + e->previewWave(curWave,num); + wavePreviewOn=true; + wavePreviewKey=ev.key.keysym.scancode; + wavePreviewNote=num; + } + } catch (std::out_of_range& e) { + } + } + break; default: break; } @@ -2919,6 +2936,12 @@ void FurnaceGUI::keyUp(SDL_Event& ev) { e->noteOff(noteOffOnReleaseChan); } } + if (wavePreviewOn) { + if (ev.key.keysym.scancode==wavePreviewKey) { + wavePreviewOn=false; + e->stopWavePreview(); + } + } } bool dirExists(String what) { @@ -3260,6 +3283,12 @@ bool FurnaceGUI::loop() { e->noteOff(noteOffOnReleaseChan); } } + if (wavePreviewOn) { + if (ev.key.keysym.scancode==wavePreviewKey) { + wavePreviewOn=false; + e->stopWavePreview(); + } + } } break; case SDL_QUIT: @@ -3847,6 +3876,9 @@ FurnaceGUI::FurnaceGUI(): noteOffOnRelease(false), noteOffOnReleaseKey((SDL_Scancode)0), noteOffOnReleaseChan(0), + wavePreviewOn(false), + wavePreviewKey((SDL_Scancode)0), + wavePreviewNote(0), arpMacroScroll(0), macroDragStart(0,0), macroDragAreaSize(0,0), diff --git a/src/gui/gui.h b/src/gui/gui.h index c6a3a43bd..c71adf6ec 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -223,6 +223,10 @@ class FurnaceGUI { SDL_Scancode noteOffOnReleaseKey; int noteOffOnReleaseChan; + bool wavePreviewOn; + SDL_Scancode wavePreviewKey; + int wavePreviewNote; + std::map noteKeys; std::map valueKeys;