diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b48c493b..2fbae0f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,6 +89,19 @@ jobs: echo "::set-output name=id::${package_name}" echo "::set-output name=filename::${package_name}${package_ext}" + - name: Set build cores amount + id: build-cores + run: | + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources + set amount=2 + if [ '${{ runner.os }}' == 'macOS' ]; then + amount=3 + fi + + echo "Amount of cores we can build with: ${amount}" + + echo "::set-output name=amount::${amount}" + - name: Setup Toolchain [Windows MSVC] if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 @@ -125,9 +138,6 @@ jobs: export CMAKE_EXTRA_ARGS=() if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') - - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') else @@ -159,7 +169,7 @@ jobs: cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ - --parallel 2 + --parallel ${{ steps.build-cores.outputs.amount }} - name: Install (System Libraries) if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} @@ -180,9 +190,6 @@ jobs: if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') - # FIXME We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF - # Force static linking # 1. Make MSVC runtime configurable CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') @@ -211,7 +218,7 @@ jobs: cmake \ --build ${PWD}/build \ --config ${{ env.BUILD_TYPE }} \ - --parallel 2 + --parallel ${{ steps.build-cores.outputs.amount }} - name: Package [Windows] if: ${{ runner.os == 'Windows' || matrix.config.compiler == 'mingw' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 769842f3..fef510ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,10 @@ else() add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include) list(APPEND DEPENDENCIES_LIBRARIES SDL2-static) + # Work around add_subdirectory'd SDL not propagating HAVE_LIBC to MSVC furnace build + if (MSVC) + list(APPEND DEPENDENCIES_COMPILE_OPTIONS "/DHAVE_LIBC") + endif() message(STATUS "Using vendored SDL2") endif() @@ -457,9 +461,13 @@ if (NOT MSVC) list(APPEND WARNING_FLAGS -Werror) endif() else() - # /wd4100 == -Wno-unused-parameter - add_compile_options("/source-charset:utf-8") - set(WARNING_FLAGS /W4 /wd4100 /D_CRT_SECURE_NO_WARNINGS) + add_compile_options("/utf-8") + set(WARNING_FLAGS /W2 /D_CRT_SECURE_NO_WARNINGS) + list(APPEND WARNING_FLAGS + /wd4244 # implicit type conversions + /wd4305 # truncations + /wd4309 # truncations of constant values + ) if (WARNINGS_ARE_ERRORS) list(APPEND WARNING_FLAGS /WX) endif() diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 008fe0a9..fc6df0a1 100644 --- a/extern/pfd-fixed/portable-file-dialogs.h +++ b/extern/pfd-fixed/portable-file-dialogs.h @@ -1331,6 +1331,14 @@ inline std::string internal::file_dialog::select_folder_vista(IFileDialog *ifd, // notify implementation +#if _WIN32 +inline BOOL WINAPI icon_enum_callback(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam) +{ + ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); + return false; +}; +#endif + inline notify::notify(std::string const &title, std::string const &message, icon _icon /* = icon::info */) @@ -1383,14 +1391,8 @@ inline notify::notify(std::string const &title, /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; } - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL WINAPI - { - ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); - return false; - }; - nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); - ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR)nid.get()); + ::EnumResourceNames(nullptr, RT_GROUP_ICON, (ENUMRESNAMEPROC)icon_enum_callback, (LONG_PTR)nid.get()); nid->uTimeout = 5000; diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index b4394f60..5a1c2db6 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -319,6 +319,18 @@ class DivDispatch { */ virtual int getPortaFloor(int ch); + /** + * get the required amplification level of this dispatch's output. + * @return the amplification level. + */ + virtual float getPostAmp(); + + /** + * check whether DC offset correction is required. + * @return truth. + */ + virtual bool getDCOffRequired(); + /** * get a description of a dispatch-specific effect. * @param effect the effect. diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index ba72a695..c89a0fa0 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -79,6 +79,11 @@ void DivDispatchContainer::flush(size_t count) { } void DivDispatchContainer::fillBuf(size_t runtotal, size_t offset, size_t size) { + if (dcOffCompensation && runtotal>0) { + dcOffCompensation=false; + prevSample[0]=bbIn[0][0]; + if (dispatch->isStereo()) prevSample[1]=bbIn[1][0]; + } if (lowQuality) { for (size_t i=0; igetDCOffRequired()) { + dcOffCompensation=true; + } // run for one cycle to determine DC offset // TODO: SAA1099 doesn't like that /*dispatch->acquire(bbIn[0],bbIn[1],0,1); diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 78ae1ce4..5288b839 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -17,9 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "dataErrors.h" -#include "song.h" -#include #define _USE_MATH_DEFINES #include "engine.h" #include "instrument.h" @@ -873,6 +870,11 @@ void DivEngine::play() { for (int i=0; imidiOut!=NULL) { + int pos=totalTicksR/6; + output->midiOut->send(TAMidiMessage(TA_MIDI_POSITION,(pos>>7)&0x7f,pos&0x7f)); + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_PLAY,0,0)); + } BUSY_END; } @@ -918,6 +920,14 @@ void DivEngine::stop() { for (int i=0; inotifyPlaybackStop(); } + if (output) if (output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0)); + for (int i=0; i=0) { + output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0)); + } + } + } BUSY_END; } diff --git a/src/engine/engine.h b/src/engine/engine.h index bf9fe07e..dd9bf25c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -86,7 +86,8 @@ struct DivChannelState { bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp; - int midiNote, curMidiNote; + int midiNote, curMidiNote, midiPitch; + bool midiAftertouch; DivChannelState(): note(-1), @@ -130,7 +131,9 @@ struct DivChannelState { noteOnInhibit(false), resetArp(false), midiNote(-1), - curMidiNote(-1) {} + curMidiNote(-1), + midiPitch(-1), + midiAftertouch(false) {} }; struct DivNoteEvent { @@ -151,7 +154,7 @@ struct DivDispatchContainer { int temp[2], prevSample[2]; short* bbIn[2]; short* bbOut[2]; - bool lowQuality; + bool lowQuality, dcOffCompensation; void setRates(double gotRate); void setQuality(bool lowQual); @@ -169,7 +172,8 @@ struct DivDispatchContainer { prevSample{0,0}, bbIn{NULL,NULL}, bbOut{NULL,NULL}, - lowQuality(false) {} + lowQuality(false), + dcOffCompensation(false) {} }; class DivEngine { @@ -295,6 +299,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); @@ -769,6 +774,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/filter.cpp b/src/engine/filter.cpp index 729c8caa..8e0ac02e 100644 --- a/src/engine/filter.cpp +++ b/src/engine/filter.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #define _USE_MATH_DEFINES #include #include "filter.h" @@ -85,4 +84,4 @@ float* DivFilterTables::getSincIntegralTable() { } } return sincIntegralTable; -} \ No newline at end of file +} diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 9369df9d..ce25d87a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -567,12 +567,12 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(ws.param4); } -void readMacroData(DivInstrumentMacro &m, SafeReader& reader, short version) { +DivDataErrors DivInstrument::readMacroData(DivInstrumentMacro& m, SafeReader& reader, short version) { char magic[4]; reader.read(magic,4); if (memcmp(magic,"MACR",4)!=0) { logE("invalid macro header!\n"); - return /*DIV_DATA_INVALID_HEADER*/; + return DIV_DATA_INVALID_HEADER; } reader.readI(); @@ -591,7 +591,7 @@ void readMacroData(DivInstrumentMacro &m, SafeReader& reader, short version) { reader.readI(); // reserved reader.readI(); // reserved } - /*return DIV_DATA_SUCCESS*/; + return DIV_DATA_SUCCESS; } DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { @@ -695,65 +695,173 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int k=0; k<14; k++) reader.readC(); if (istest) { - readMacroData(std.volMacro,reader,version); - readMacroData(std.arpMacro,reader,version); - readMacroData(std.dutyMacro,reader,version); - readMacroData(std.waveMacro,reader,version); - readMacroData(std.pitchMacro,reader,version); - readMacroData(std.ex1Macro,reader,version); - readMacroData(std.ex2Macro,reader,version); - readMacroData(std.ex3Macro,reader,version); - readMacroData(std.algMacro,reader,version); - readMacroData(std.fbMacro,reader,version); - readMacroData(std.fmsMacro,reader,version); - readMacroData(std.fms2Macro,reader,version); - readMacroData(std.amsMacro,reader,version); - readMacroData(std.ams2Macro,reader,version); - readMacroData(std.panLMacro,reader,version); - readMacroData(std.panRMacro,reader,version); - readMacroData(std.phaseResetMacro,reader,version); - readMacroData(std.ex4Macro,reader,version); - readMacroData(std.ex5Macro,reader,version); - readMacroData(std.ex6Macro,reader,version); - readMacroData(std.ex7Macro,reader,version); - readMacroData(std.ex8Macro,reader,version); + if (readMacroData(std.volMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.arpMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.dutyMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.waveMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.pitchMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex1Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex3Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.algMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.fbMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.fmsMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.fms2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.amsMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ams2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.panLMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.panRMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.phaseResetMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex4Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex5Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex6Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex7Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ex8Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } // FM macros for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - readMacroData(op.amMacro,reader,version); - readMacroData(op.arMacro,reader,version); - readMacroData(op.drMacro,reader,version); - readMacroData(op.multMacro,reader,version); - readMacroData(op.rrMacro,reader,version); - readMacroData(op.slMacro,reader,version); - readMacroData(op.tlMacro,reader,version); - readMacroData(op.dt2Macro,reader,version); - readMacroData(op.rsMacro,reader,version); - readMacroData(op.dtMacro,reader,version); - readMacroData(op.d2rMacro,reader,version); - readMacroData(op.ssgMacro,reader,version); - readMacroData(op.damMacro,reader,version); - readMacroData(op.dvbMacro,reader,version); - readMacroData(op.egtMacro,reader,version); - readMacroData(op.kslMacro,reader,version); - readMacroData(op.susMacro,reader,version); - readMacroData(op.vibMacro,reader,version); - readMacroData(op.wsMacro,reader,version); - readMacroData(op.ksrMacro,reader,version); + if (readMacroData(op.amMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.arMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.drMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.multMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.rrMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.slMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.tlMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.dt2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.rsMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.dtMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.d2rMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.ssgMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.damMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.dvbMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.egtMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.kslMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.susMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.vibMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.wsMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(op.ksrMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } } // wavesynth macros - readMacroData(std.ws.wave1Macro,reader,version); - readMacroData(std.ws.wave2Macro,reader,version); - readMacroData(std.ws.rateDividerMacro,reader,version); - readMacroData(std.ws.effectMacro,reader,version); - readMacroData(std.ws.oneShotMacro,reader,version); - readMacroData(std.ws.enabledMacro,reader,version); - readMacroData(std.ws.globalMacro,reader,version); - readMacroData(std.ws.speedMacro,reader,version); - readMacroData(std.ws.param1Macro,reader,version); - readMacroData(std.ws.param2Macro,reader,version); - readMacroData(std.ws.param3Macro,reader,version); - readMacroData(std.ws.param4Macro,reader,version); + if (readMacroData(std.ws.wave1Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.wave2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.rateDividerMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.effectMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.oneShotMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.enabledMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.globalMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.speedMacro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.param1Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.param2Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.param3Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } + if (readMacroData(std.ws.param4Macro,reader,version)!=DIV_DATA_SUCCESS) { + return DIV_DATA_INVALID_HEADER; + } } if (!istest) { // standard @@ -882,18 +990,42 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { for (int i=0; i<4; i++) { DivInstrumentSTD::OpMacro& op=std.opMacros[i]; - reader.readByte(op.amMacro.val,op.amMacro.len,1); - reader.readByte(op.arMacro.val,op.arMacro.len,1); - reader.readByte(op.drMacro.val,op.drMacro.len,1); - reader.readByte(op.multMacro.val,op.multMacro.len,1); - reader.readByte(op.rrMacro.val,op.rrMacro.len,1); - reader.readByte(op.slMacro.val,op.slMacro.len,1); - reader.readByte(op.tlMacro.val,op.tlMacro.len,1); - reader.readByte(op.dt2Macro.val,op.dt2Macro.len,1); - reader.readByte(op.rsMacro.val,op.rsMacro.len,1); - reader.readByte(op.dtMacro.val,op.dtMacro.len,1); - reader.readByte(op.d2rMacro.val,op.d2rMacro.len,1); - reader.readByte(op.ssgMacro.val,op.ssgMacro.len,1); + for (int l=0; lstd.volMacro.len>0) { macroList.push_back(DivMacroExecList(vol,ins->std.volMacro)); - vol.prepare(&ins->std.volMacro); } if (ins->std.arpMacro.len>0) { macroList.push_back(DivMacroExecList(arp,ins->std.arpMacro)); - arp.prepare(&ins->std.arpMacro); } if (ins->std.dutyMacro.len>0) { macroList.push_back(DivMacroExecList(duty,ins->std.dutyMacro)); - duty.prepare(&ins->std.dutyMacro); } if (ins->std.waveMacro.len>0) { macroList.push_back(DivMacroExecList(wave,ins->std.waveMacro)); - wave.prepare(&ins->std.waveMacro); } if (ins->std.pitchMacro.len>0) { macroList.push_back(DivMacroExecList(pitch,ins->std.pitchMacro)); - pitch.prepare(&ins->std.pitchMacro); } if (ins->std.ex1Macro.len>0) { macroList.push_back(DivMacroExecList(ex1,ins->std.ex1Macro)); - ex1.prepare(&ins->std.ex1Macro); } if (ins->std.ex2Macro.len>0) { macroList.push_back(DivMacroExecList(ex2,ins->std.ex2Macro)); - ex2.prepare(&ins->std.ex2Macro); } if (ins->std.ex3Macro.len>0) { macroList.push_back(DivMacroExecList(ex3,ins->std.ex3Macro)); - ex3.prepare(&ins->std.ex3Macro); } if (ins->std.algMacro.len>0) { macroList.push_back(DivMacroExecList(alg,ins->std.algMacro)); - alg.prepare(&ins->std.algMacro); } if (ins->std.fbMacro.len>0) { macroList.push_back(DivMacroExecList(fb,ins->std.fbMacro)); - fb.prepare(&ins->std.fbMacro); } if (ins->std.fmsMacro.len>0) { macroList.push_back(DivMacroExecList(fms,ins->std.fmsMacro)); - fms.prepare(&ins->std.fmsMacro); } if (ins->std.fms2Macro.len>0) { macroList.push_back(DivMacroExecList(fms2,ins->std.fms2Macro)); - fms2.prepare(&ins->std.fms2Macro); } if (ins->std.amsMacro.len>0) { macroList.push_back(DivMacroExecList(ams,ins->std.amsMacro)); - ams.prepare(&ins->std.amsMacro); } if (ins->std.ams2Macro.len>0) { macroList.push_back(DivMacroExecList(ams2,ins->std.ams2Macro)); - ams2.prepare(&ins->std.ams2Macro); } // TODO: other macros if (ins->std.panLMacro.len>0) { macroList.push_back(DivMacroExecList(panL,ins->std.panLMacro)); - panL.prepare(&ins->std.panLMacro); } if (ins->std.panRMacro.len>0) { macroList.push_back(DivMacroExecList(panR,ins->std.panRMacro)); - panR.prepare(&ins->std.panRMacro); } if (ins->std.phaseResetMacro.len>0) { macroList.push_back(DivMacroExecList(phaseReset,ins->std.phaseResetMacro)); - phaseReset.prepare(&ins->std.phaseResetMacro); } if (ins->std.ex4Macro.len>0) { macroList.push_back(DivMacroExecList(ex4,ins->std.ex4Macro)); - ex4.prepare(&ins->std.ex4Macro); } if (ins->std.ex5Macro.len>0) { macroList.push_back(DivMacroExecList(ex5,ins->std.ex5Macro)); - ex5.prepare(&ins->std.ex5Macro); } if (ins->std.ex6Macro.len>0) { macroList.push_back(DivMacroExecList(ex6,ins->std.ex6Macro)); - ex6.prepare(&ins->std.ex6Macro); } if (ins->std.ex7Macro.len>0) { macroList.push_back(DivMacroExecList(ex7,ins->std.ex7Macro)); - ex7.prepare(&ins->std.ex7Macro); } if (ins->std.ex8Macro.len>0) { macroList.push_back(DivMacroExecList(ex8,ins->std.ex8Macro)); - ex8.prepare(&ins->std.ex8Macro); } // prepare FM operator macros @@ -198,135 +148,103 @@ void DivMacroInt::init(DivInstrument* which) { IntOp& o=op[i]; if (m.amMacro.len>0) { macroList.push_back(DivMacroExecList(o.am,m.amMacro)); - o.am.prepare(&m.amMacro); } if (m.arMacro.len>0) { macroList.push_back(DivMacroExecList(o.ar,m.arMacro)); - o.ar.prepare(&m.arMacro); } if (m.drMacro.len>0) { macroList.push_back(DivMacroExecList(o.dr,m.drMacro)); - o.dr.prepare(&m.drMacro); } if (m.multMacro.len>0) { macroList.push_back(DivMacroExecList(o.mult,m.multMacro)); - o.mult.prepare(&m.multMacro); } if (m.rrMacro.len>0) { macroList.push_back(DivMacroExecList(o.rr,m.rrMacro)); - o.rr.prepare(&m.rrMacro); } if (m.slMacro.len>0) { macroList.push_back(DivMacroExecList(o.sl,m.slMacro)); - o.sl.prepare(&m.slMacro); } if (m.tlMacro.len>0) { macroList.push_back(DivMacroExecList(o.tl,m.tlMacro)); - o.tl.prepare(&m.tlMacro); } if (m.dt2Macro.len>0) { macroList.push_back(DivMacroExecList(o.dt2,m.dt2Macro)); - o.dt2.prepare(&m.dt2Macro); } if (m.rsMacro.len>0) { macroList.push_back(DivMacroExecList(o.rs,m.rsMacro)); - o.rs.prepare(&m.rsMacro); } if (m.dtMacro.len>0) { macroList.push_back(DivMacroExecList(o.dt,m.dtMacro)); - o.dt.prepare(&m.dtMacro); } if (m.d2rMacro.len>0) { macroList.push_back(DivMacroExecList(o.d2r,m.d2rMacro)); - o.d2r.prepare(&m.d2rMacro); } if (m.ssgMacro.len>0) { macroList.push_back(DivMacroExecList(o.ssg,m.ssgMacro)); - o.ssg.prepare(&m.ssgMacro); } if (m.damMacro.len>0) { macroList.push_back(DivMacroExecList(o.dam,m.damMacro)); - o.dam.prepare(&m.damMacro); } if (m.dvbMacro.len>0) { macroList.push_back(DivMacroExecList(o.dvb,m.dvbMacro)); - o.dvb.prepare(&m.dvbMacro); } if (m.egtMacro.len>0) { macroList.push_back(DivMacroExecList(o.egt,m.egtMacro)); - o.egt.prepare(&m.egtMacro); } if (m.kslMacro.len>0) { macroList.push_back(DivMacroExecList(o.ksl,m.kslMacro)); - o.ksl.prepare(&m.kslMacro); } if (m.susMacro.len>0) { macroList.push_back(DivMacroExecList(o.sus,m.susMacro)); - o.sus.prepare(&m.susMacro); } if (m.vibMacro.len>0) { macroList.push_back(DivMacroExecList(o.vib,m.vibMacro)); - o.vib.prepare(&m.vibMacro); } if (m.wsMacro.len>0) { macroList.push_back(DivMacroExecList(o.ws,m.wsMacro)); - o.ws.prepare(&m.wsMacro); } if (m.ksrMacro.len>0) { macroList.push_back(DivMacroExecList(o.ksr,m.ksrMacro)); - o.ksr.prepare(&m.ksrMacro); } } // prepare wavesynth macros if (ins->std.ws.wave1Macro.len>0) { macroList.push_back(DivMacroExecList(ws.wave1,ins->std.ws.wave1Macro)); - ws.wave1.prepare(&ins->std.ws.wave1Macro); } if (ins->std.ws.wave2Macro.len>0) { macroList.push_back(DivMacroExecList(ws.wave2,ins->std.ws.wave2Macro)); - ws.wave2.prepare(&ins->std.ws.wave2Macro); } if (ins->std.ws.rateDividerMacro.len>0) { macroList.push_back(DivMacroExecList(ws.rateDivider,ins->std.ws.rateDividerMacro)); - ws.rateDivider.prepare(&ins->std.ws.rateDividerMacro); } if (ins->std.ws.effectMacro.len>0) { macroList.push_back(DivMacroExecList(ws.effect,ins->std.ws.effectMacro)); - ws.effect.prepare(&ins->std.ws.effectMacro); } if (ins->std.ws.oneShotMacro.len>0) { macroList.push_back(DivMacroExecList(ws.oneShot,ins->std.ws.oneShotMacro)); - ws.oneShot.prepare(&ins->std.ws.oneShotMacro); } if (ins->std.ws.enabledMacro.len>0) { macroList.push_back(DivMacroExecList(ws.enabled,ins->std.ws.enabledMacro)); - ws.enabled.prepare(&ins->std.ws.enabledMacro); } if (ins->std.ws.globalMacro.len>0) { macroList.push_back(DivMacroExecList(ws.global,ins->std.ws.globalMacro)); - ws.global.prepare(&ins->std.ws.globalMacro); } if (ins->std.ws.speedMacro.len>0) { macroList.push_back(DivMacroExecList(ws.speed,ins->std.ws.speedMacro)); - ws.speed.prepare(&ins->std.ws.speedMacro); } if (ins->std.ws.param1Macro.len>0) { macroList.push_back(DivMacroExecList(ws.param1,ins->std.ws.param1Macro)); - ws.param1.prepare(&ins->std.ws.param1Macro); } if (ins->std.ws.param2Macro.len>0) { macroList.push_back(DivMacroExecList(ws.param2,ins->std.ws.param2Macro)); - ws.param2.prepare(&ins->std.ws.param2Macro); } if (ins->std.ws.param3Macro.len>0) { macroList.push_back(DivMacroExecList(ws.param3,ins->std.ws.param3Macro)); - ws.param3.prepare(&ins->std.ws.param3Macro); } if (ins->std.ws.param4Macro.len>0) { macroList.push_back(DivMacroExecList(ws.param4,ins->std.ws.param4Macro)); - ws.param4.prepare(&ins->std.ws.param4Macro); } if (!macroList.empty()) { for (std::list::iterator iter = macroList.begin(); iter!= macroList.end(); iter++) { diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index d7236805..1bc93943 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -24,26 +24,20 @@ #include struct DivMacroStruct { - DivInstrumentMacro* source; int pos; int val; bool has, had, finished, will; unsigned int mode; void doMacro(DivInstrumentMacro& source, bool released); void init() { - source=NULL; pos=mode=0; has=had=will=false; } - void prepare(DivInstrumentMacro* s) { - if (s!=NULL) { - source=s; - has=had=will=true; - mode=source->mode; - } + void prepare(DivInstrumentMacro& source) { + has=had=will=true; + mode=source.mode; } DivMacroStruct(): - source(NULL), pos(0), val(0), has(false), @@ -56,8 +50,11 @@ struct DivMacroStruct { struct DivMacroExecList { DivMacroStruct& macro; DivInstrumentMacro& source; + void init() { + macro.init(); + } void prepare() { - macro.prepare(&source); + macro.prepare(source); } void doMacro(bool released) { macro.doMacro(source, released); @@ -155,6 +152,7 @@ class DivMacroInt { DivMacroInt(): ins(NULL), + macroList(), released(false), vol(), arp(), diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 7b6115ae..b860f680 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -74,6 +74,14 @@ int DivDispatch::getPortaFloor(int ch) { return 0x00; } +float DivDispatch::getPostAmp() { + return 1.0f; +} + +bool DivDispatch::getDCOffRequired() { + return false; +} + const char* DivDispatch::getEffectName(unsigned char effect) { return NULL; } diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 6cdd6b03..30a83812 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -497,6 +497,10 @@ void DivPlatformAY8910::flushWrites() { while (!writes.empty()) writes.pop(); } +bool DivPlatformAY8910::getDCOffRequired() { + return true; +} + void DivPlatformAY8910::reset() { while (!writes.empty()) writes.pop(); ay->device_reset(); diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 82b647f2..b1a3ea12 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -95,6 +95,7 @@ class DivPlatformAY8910: public DivDispatch { void setFlags(unsigned int flags); bool isStereo(); bool keyOffAffectsArp(int ch); + bool getDCOffRequired(); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index de17fa67..a470dceb 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -123,7 +123,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } while (!writes.empty()) { QueuedWrite w=writes.front(); - if (bank!=(w.addr>>4)) { + if ((int)bank!=(w.addr>>4)) { bank=w.addr>>4; ay->address_w(0x0d); ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 786da058..736ed437 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -118,7 +118,7 @@ void DivPlatformC64::acquire(short* bufL, short* bufR, size_t start, size_t len) void DivPlatformC64::updateFilter() { rWrite(0x15,filtCut&7); rWrite(0x16,filtCut>>3); - rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(chan[0].filter)); + rWrite(0x17,(filtRes<<4)|(chan[2].filter<<2)|(chan[1].filter<<1)|(int)(chan[0].filter)); rWrite(0x18,(filtControl<<4)|vol); } @@ -177,7 +177,7 @@ void DivPlatformC64::tick() { } if (chan[i].std.wave.had) { chan[i].wave=chan[i].std.wave.val; - rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|chan[i].active); + rWrite(i*7+4,(isMuted[i]?8:(chan[i].wave<<4))|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active)); } if (chan[i].std.ex1.had) { filtControl=chan[i].std.ex1.val&15; @@ -232,7 +232,7 @@ int DivPlatformC64::dispatch(DivCommand c) { rWrite(c.chan*7+3,chan[c.chan].duty>>8); } if (chan[c.chan].insChanged) { - chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(ins->c64.triOn); + chan[c.chan].wave=(ins->c64.noiseOn<<3)|(ins->c64.pulseOn<<2)|(ins->c64.sawOn<<1)|(int)(ins->c64.triOn); chan[c.chan].attack=ins->c64.a; chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d; chan[c.chan].sustain=ins->c64.s; @@ -245,7 +245,7 @@ int DivPlatformC64::dispatch(DivCommand c) { if (ins->c64.initFilter) { filtCut=ins->c64.cut; filtRes=ins->c64.res; - filtControl=ins->c64.lp|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3); + filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2)|(ins->c64.ch3off<<3); } updateFilter(); } @@ -330,7 +330,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_WAVE: chan[c.chan].wave=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case DIV_CMD_LEGATO: chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); @@ -411,11 +411,11 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case 4: chan[c.chan].ring=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case 5: chan[c.chan].sync=c.value; - rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|chan[c.chan].active); + rWrite(c.chan*7+4,(isMuted[c.chan]?8:(chan[c.chan].wave<<4))|(chan[c.chan].ring<<2)|(chan[c.chan].sync<<1)|(int)(chan[c.chan].active)); break; case 6: filtControl&=7; @@ -434,7 +434,7 @@ int DivPlatformC64::dispatch(DivCommand c) { void DivPlatformC64::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|chan[ch].active); + rWrite(ch*7+4,(isMuted[ch]?8:(chan[ch].wave<<4))|(chan[ch].ring<<2)|(chan[ch].sync<<1)|(int)(chan[ch].active)); } void DivPlatformC64::forceIns() { diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 0f803ee2..79d9fc61 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -89,7 +89,6 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len if (!isMuted[2]) { sample+=mmc5->pcm.output*2; } - sample=(sample-128)<<6; if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; @@ -336,6 +335,10 @@ int DivPlatformMMC5::getRegisterPoolSize() { return 32; } +float DivPlatformMMC5::getPostAmp() { + return 64.0f; +} + void DivPlatformMMC5::reset() { for (int i=0; i<3; i++) { chan[i]=DivPlatformMMC5::Channel(); diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index a29ffc7d..6b364d5a 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -74,6 +74,7 @@ class DivPlatformMMC5: public DivDispatch { void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); + float getPostAmp(); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 5380b0b4..9f56e4e5 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -80,7 +80,14 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) DivSample* s=parent->getSample(dacSample); if (s->samples>0) { if (!isMuted[4]) { - rWrite(0x4011,((unsigned char)s->data8[dacPos]+0x80)>>1); + unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; + if (dacAntiClickOn && dacAntiClick=s->samples) { if (s->loopStart>=0 && s->loopStart<(int)s->samples) { @@ -101,7 +108,7 @@ void DivPlatformNES::acquire(short* bufL, short* bufR, size_t start, size_t len) if (nes->apu.clocked) { nes->apu.clocked=false; } - int sample=(pulse_output(nes)+tnd_output(nes)-128)<<7; + int sample=(pulse_output(nes)+tnd_output(nes)); if (sample>32767) sample=32767; if (sample<-32768) sample=-32768; bufL[i]=sample; @@ -454,6 +461,10 @@ int DivPlatformNES::getRegisterPoolSize() { return 32; } +float DivPlatformNES::getPostAmp() { + return 128.0f; +} + void DivPlatformNES::reset() { for (int i=0; i<5; i++) { chan[i]=DivPlatformNES::Channel(); @@ -476,6 +487,9 @@ void DivPlatformNES::reset() { rWrite(0x4015,0x1f); rWrite(0x4001,chan[0].sweep); rWrite(0x4005,chan[1].sweep); + + dacAntiClickOn=true; + dacAntiClick=0; } bool DivPlatformNES::keyOffAffectsArp(int ch) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index c1b699bc..1dbb4411 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -54,10 +54,11 @@ class DivPlatformNES: public DivDispatch { Channel chan[5]; bool isMuted[5]; int dacPeriod, dacRate; - unsigned int dacPos; + unsigned int dacPos, dacAntiClick; int dacSample; unsigned char sampleBank; unsigned char apuType; + bool dacAntiClickOn; struct NESAPU* nes; unsigned char regPool[128]; @@ -74,6 +75,7 @@ class DivPlatformNES: public DivDispatch { void tick(); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); + float getPostAmp(); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); void poke(unsigned int addr, unsigned short val); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 6b4db8c6..040c8035 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -371,7 +371,7 @@ void DivPlatformOPL::tick() { if (update4OpMask) { update4OpMask=false; if (oplType==3) { - unsigned char opMask=chan[0].fourOp|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5); + unsigned char opMask=(int)(chan[0].fourOp)|(chan[2].fourOp<<1)|(chan[4].fourOp<<2)|(chan[6].fourOp<<3)|(chan[8].fourOp<<4)|(chan[10].fourOp<<5); immWrite(0x104,opMask); //printf("updating opMask to %.2x\n",opMask); } diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 2c23639b..ee07463c 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -620,7 +620,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { } case DIV_CMD_FM_EXTCH: if (!properDrumsSys) break; - if (properDrums==c.value) break; + if ((int)properDrums==c.value) break; if (c.value) { properDrums=true; immWrite(0x0e,0x20); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index db614ee7..708fbc7a 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -414,6 +414,16 @@ void DivPlatformSAA1099::reset() { extMode=false; + rWrite(8,255); + rWrite(9,255); + rWrite(10,255); + rWrite(11,255); + rWrite(12,255); + rWrite(13,255); + rWrite(16,0x77); + rWrite(17,0x77); + rWrite(18,0x77); + rWrite(0x1c,2); rWrite(0x1c,1); } diff --git a/src/engine/platform/sound/ay8910.cpp b/src/engine/platform/sound/ay8910.cpp index 2d734f93..8bb38788 100644 --- a/src/engine/platform/sound/ay8910.cpp +++ b/src/engine/platform/sound/ay8910.cpp @@ -1120,7 +1120,7 @@ void ay8910_device::sound_stream_update(short** outputs, int outLen) for (int chan = 0; chan < NUM_CHANNELS; chan++) { tone = &m_tone[chan]; - m_vol_enabled[chan] = (tone->output | tone_enable(chan)) & (noise_output() | noise_enable(chan)); + m_vol_enabled[chan] = (tone->output | (unsigned char)tone_enable(chan)) & (noise_output() | (unsigned char)noise_enable(chan)); } /* update envelope */ diff --git a/src/engine/platform/sound/nes/apu.c b/src/engine/platform/sound/nes/apu.c index 8d53e583..9e177a78 100644 --- a/src/engine/platform/sound/nes/apu.c +++ b/src/engine/platform/sound/nes/apu.c @@ -213,7 +213,8 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) { a->S2.sweep.delay = 1; a->S2.sweep.divider = 1; a->TR.frequency = 1; - a->TR.sequencer = 0; + /* questo era 0 ma produce click nell'audio */ + a->TR.sequencer = 7; a->NS.frequency = 1; a->NS.shift = 1; a->DMC.frequency = 1; diff --git a/src/engine/platform/sound/ymfm/ymfm.h b/src/engine/platform/sound/ymfm/ymfm.h index 906e3211..7b98f849 100644 --- a/src/engine/platform/sound/ymfm/ymfm.h +++ b/src/engine/platform/sound/ymfm/ymfm.h @@ -33,7 +33,7 @@ #pragma once -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8e1f1d66..0118acc4 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -17,9 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "blip_buf.h" -#include "song.h" -#include "wavetable.h" #define _USE_MATH_DEFINES #include "dispatch.h" #include "engine.h" @@ -201,16 +198,24 @@ int DivEngine::dispatchCmd(DivCommand c) { chan[c.chan].curMidiNote=-1; break; case DIV_CMD_INSTRUMENT: - output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0)); + if (chan[c.chan].lastIns!=c.value) { + output->midiOut->send(TAMidiMessage(0xc0|(c.chan&15),c.value,0)); + } break; case DIV_CMD_VOLUME: - //output->midiOut->send(TAMidiMessage(0xb0|(c.chan&15),0x07,scaledVol)); + if (chan[c.chan].curMidiNote>=0 && chan[c.chan].midiAftertouch) { + chan[c.chan].midiAftertouch=false; + output->midiOut->send(TAMidiMessage(0xa0|(c.chan&15),chan[c.chan].curMidiNote,scaledVol)); + } break; case DIV_CMD_PITCH: { int pitchBend=8192+(c.value<<5); if (pitchBend<0) pitchBend=0; if (pitchBend>16383) pitchBend=16383; - output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7)); + if (pitchBend!=chan[c.chan].midiPitch) { + chan[c.chan].midiPitch=pitchBend; + output->midiOut->send(TAMidiMessage(0xe0|(c.chan&15),pitchBend&0x7f,pitchBend>>7)); + } break; } default: @@ -963,6 +968,9 @@ void DivEngine::processRow(int i, bool afterDelay) { // volume if (pat->data[whatRow][3]!=-1) { if (dispatchCmd(DivCommand(DIV_ALWAYS_SET_VOLUME,i)) || (MIN(chan[i].volMax,chan[i].volume)>>8)!=pat->data[whatRow][3]) { + if (pat->data[whatRow][0]==0 && pat->data[whatRow][1]==0) { + chan[i].midiAftertouch=true; + } chan[i].volume=pat->data[whatRow][3]<<8; dispatchCmd(DivCommand(DIV_CMD_VOLUME,i,chan[i].volume>>8)); } @@ -1436,6 +1444,11 @@ bool DivEngine::nextTick(bool noAccum) { cycles++; } + // MIDI clock + if (output) if (!skipping && output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_CLOCK,0,0)); + } + while (!pendingNotes.empty()) { DivNoteEvent& note=pendingNotes.front(); if (note.on) { @@ -1732,8 +1745,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (!playing) { if (out!=NULL) { - 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; } isBusy.unlock(); @@ -1847,6 +1863,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi for (int i=0; igetPostAmp(); + volR*=disCont[i].dispatch->getPostAmp(); if (disCont[i].dispatch->isStereo()) { for (size_t j=0; j=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/engine/safeReader.cpp b/src/engine/safeReader.cpp index f27e9044..9add1b5a 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -66,42 +66,6 @@ int SafeReader::read(void* where, size_t count) { return count; } -template -int SafeReader::readByte(T* where, size_t count, unsigned char byte, Endianness endianness) { - if (byte==sizeof(T)) { - return read(where,count*byte); - } else { -#ifdef READ_DEBUG - logD("SR: reading %d x %d bit words at %x\n",count,byte<<3,curSeek); -#endif - if (count==0) return 0; - if (curSeek+(count*byte)>len) throw EndOfFileException(this,len); - int start,end,inc; - switch (endianness) { - case BigEndian: - start=byte-1; - end=-1; - inc=-1; - break; - case LittleEndian: - default: - start=0; - end=byte; - inc=1; - break; - } - for (int c=0; c int readByte(T* where, size_t count, unsigned char byte=sizeof(T), Endianness endianness=LittleEndian); // these functions may throw EndOfFileException. signed char readC(); diff --git a/src/engine/safeWriter.cpp b/src/engine/safeWriter.cpp index 2e8fb7dd..f29800a4 100644 --- a/src/engine/safeWriter.cpp +++ b/src/engine/safeWriter.cpp @@ -73,39 +73,6 @@ int SafeWriter::write(const void* what, size_t count) { return count; } -template -int SafeWriter::writeByte(T* what, size_t count, unsigned char byte, Endianness endianness) { - if (byte==sizeof(T)) { - return write(what,count*byte); - } else { - if (!operative) return 0; - checkSize(count*byte); - int start,end,inc; - switch (endianness) { - case BigEndian: - start=byte-1; - end=-1; - inc=-1; - break; - case LittleEndian: - default: - start=0; - end=byte; - inc=1; - break; - } - for (int c=0; c>(byte<<3))&0xff; - } - } - count*=byte; - if (curSeek>len) len=curSeek; - } - return count; -} - int SafeWriter::writeC(signed char val) { return write(&val,1); } diff --git a/src/engine/safeWriter.h b/src/engine/safeWriter.h index c4920378..9072c61d 100644 --- a/src/engine/safeWriter.h +++ b/src/engine/safeWriter.h @@ -43,7 +43,6 @@ class SafeWriter { size_t size(); int write(const void* what, size_t count); - template int writeByte(T* what, size_t count, unsigned char byte=sizeof(T), Endianness endianness=LittleEndian); int writeC(signed char val); int writeS(short val); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 755b825a..66930051 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,10 @@ FurnaceGUI::FurnaceGUI(): openSampleResampleOpt(false), openSampleAmplifyOpt(false), openSampleSilenceOpt(false), - openSampleFilterOpt(false) { + openSampleFilterOpt(false), + oscTotal(0), + oscZoom(0.5f), + oscZoomSlider(false) { // value keys valueKeys[SDLK_0]=0; valueKeys[SDLK_1]=1; @@ -3469,4 +3475,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 a797700f..641cf7c0 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -71,6 +71,16 @@ enum FurnaceGUIColors { GUI_COLOR_FILE_FONT, GUI_COLOR_FILE_OTHER, + GUI_COLOR_OSC_BG1, + GUI_COLOR_OSC_BG2, + GUI_COLOR_OSC_BG3, + GUI_COLOR_OSC_BG4, + GUI_COLOR_OSC_BORDER, + GUI_COLOR_OSC_WAVE, + GUI_COLOR_OSC_WAVE_PEAK, + GUI_COLOR_OSC_REF, + GUI_COLOR_OSC_GUIDE, + GUI_COLOR_VOLMETER_LOW, GUI_COLOR_VOLMETER_HIGH, GUI_COLOR_VOLMETER_PEAK, @@ -976,6 +986,12 @@ class FurnaceGUI { size_t sampleClipboardLen; bool openSampleResizeOpt, openSampleResampleOpt, openSampleAmplifyOpt, openSampleSilenceOpt, openSampleFilterOpt; + // oscilloscope + int oscTotal; + float oscValues[512]; + float oscZoom; + bool oscZoomSlider; + // visualizer float keyHit[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; @@ -996,6 +1012,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/guiConst.cpp b/src/gui/guiConst.cpp index 08582933..c3a7c72b 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -377,6 +377,16 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_FILE_FONT,"",ImVec4(0.3f,1.0f,0.6f,1.0f)), D(GUI_COLOR_FILE_OTHER,"",ImVec4(0.7f,0.7f,0.7f,1.0f)), + D(GUI_COLOR_OSC_BG1,"",ImVec4(0.1f,0.18f,0.3f,1.0f)), + D(GUI_COLOR_OSC_BG2,"",ImVec4(0.1f,0.18f,0.3f,1.0f)), + D(GUI_COLOR_OSC_BG3,"",ImVec4(0.05f,0.15f,0.25f,1.0f)), + D(GUI_COLOR_OSC_BG4,"",ImVec4(0.05f,0.15f,0.25f,1.0f)), + D(GUI_COLOR_OSC_BORDER,"",ImVec4(0.4f,0.6f,0.95f,1.0f)), + D(GUI_COLOR_OSC_WAVE,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), + D(GUI_COLOR_OSC_WAVE_PEAK,"",ImVec4(0.95f,0.95f,1.0f,1.0f)), + D(GUI_COLOR_OSC_REF,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), + D(GUI_COLOR_OSC_GUIDE,"",ImVec4(0.3,0.3f,0.3f,1.0f)), + D(GUI_COLOR_VOLMETER_LOW,"",ImVec4(0.2f,0.6f,0.2f,1.0f)), D(GUI_COLOR_VOLMETER_HIGH,"",ImVec4(1.0f,0.9f,0.2f,1.0f)), D(GUI_COLOR_VOLMETER_PEAK,"",ImVec4(1.0f,0.1f,0.1f,1.0f)), diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1f5d9e91..75e0cdd8 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1068,7 +1068,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ ImGui::SetNextItemWidth(availableWidth); \ if (ImGui::InputText("##IMacroMML_" macroName,&mmlStr)) { \ - decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,macroAMin,(bitfield)?((1<127) macro.len=127; \ } \ if (macroMode) { \ @@ -1146,7 +1146,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y); \ } \ if (displayLoop) { \ - PlotCustom("##IOPMacro.loop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll,¯oHoverLoop); \ + PlotCustom("##IOPMacroLoop_" #op macroName,loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),uiColors[GUI_COLOR_MACRO_OTHER],macro.len-macroDragScroll,¯oHoverLoop); \ if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { \ macroLoopDragStart=ImGui::GetItemRectMin(); \ macroLoopDragAreaSize=ImVec2(availableWidth,8.0f*dpiScale); \ @@ -1168,7 +1168,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ ImGui::SetNextItemWidth(availableWidth); \ if (ImGui::InputText("##IOPMacroMML_" macroName,&mmlStr)) { \ - decodeMMLStr(mmlStr,macro.val,macro.len,macro.loop,0,bitfield?((1< +#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) { @@ -27,21 +73,106 @@ void FurnaceGUI::drawOsc() { } if (!oscOpen) return; ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale)); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); + /*ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,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; + if (oscZoomSlider) { + if (ImGui::VSliderFloat("##OscZoom",ImVec2(20.0f*dpiScale,ImGui::GetContentRegionAvail().y),&oscZoom,0.5,2.0)) { + if (oscZoom<0.5) oscZoom=0.5; + if (oscZoom>2.0) oscZoom=2.0; + } + ImGui::SameLine(); + } + + ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + + ImVec2 waveform[512]; + ImVec2 size=ImGui::GetContentRegionAvail(); + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + ImRect inRect=rect; + inRect.Min.x+=dpiScale; + inRect.Min.y+=dpiScale; + inRect.Max.x-=dpiScale; + inRect.Max.y-=dpiScale; + ImGuiStyle& style=ImGui::GetStyle(); + ImU32 color=ImGui::GetColorU32(isClipping?uiColors[GUI_COLOR_OSC_WAVE_PEAK]:uiColors[GUI_COLOR_OSC_WAVE]); + ImU32 borderColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_BORDER]); + ImU32 refColor=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_REF]); + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("wsDisplay"))) { + // https://github.com/ocornut/imgui/issues/3710 + const int v0 = dl->VtxBuffer.Size; + dl->AddRectFilled(inRect.Min,inRect.Max,0xffffffff,8.0f*dpiScale); + const int v1 = dl->VtxBuffer.Size; + + for (int i=v0; iVtxBuffer.Data[i]; + ImVec4 col0=uiColors[GUI_COLOR_OSC_BG1]; + ImVec4 col1=uiColors[GUI_COLOR_OSC_BG3]; + ImVec4 col2=uiColors[GUI_COLOR_OSC_BG2]; + ImVec4 col3=uiColors[GUI_COLOR_OSC_BG4]; + + float shadeX=(v->pos.x-rect.Min.x)/(rect.Max.x-rect.Min.x); + float shadeY=(v->pos.y-rect.Min.y)/(rect.Max.y-rect.Min.y); + if (shadeX<0.0f) shadeX=0.0f; + if (shadeX>1.0f) shadeX=1.0f; + if (shadeY<0.0f) shadeY=0.0f; + if (shadeY>1.0f) shadeY=1.0f; + + col0.x+=(col2.x-col0.x)*shadeX; + col0.y+=(col2.y-col0.y)*shadeX; + col0.z+=(col2.z-col0.z)*shadeX; + col0.w+=(col2.w-col0.w)*shadeX; + + col1.x+=(col3.x-col1.x)*shadeX; + col1.y+=(col3.y-col1.y)*shadeX; + col1.z+=(col3.z-col1.z)*shadeX; + col1.w+=(col3.w-col1.w)*shadeX; + + col0.x+=(col1.x-col0.x)*shadeY; + col0.y+=(col1.y-col0.y)*shadeY; + col0.z+=(col1.z-col0.z)*shadeY; + col0.w+=(col1.w-col0.w)*shadeY; + + ImVec4 conv=ImGui::ColorConvertU32ToFloat4(v->col); + col0.x*=conv.x; + col0.y*=conv.y; + col0.z*=conv.z; + col0.w*=conv.w; + + v->col=ImGui::ColorConvertFloat4ToU32(col0); + } + + dl->AddLine( + ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), + ImLerp(rect.Min,rect.Max,ImVec2(0.0f,0.5f)), + refColor, + dpiScale + ); + + for (size_t i=0; i<512; i++) { + float x=(float)i/512.0f; + float y=oscValues[i]*oscZoom; + if (y<-0.5f) y=-0.5f; + if (y>0.5f) y=0.5f; + waveform[i]=ImLerp(rect.Min,rect.Max,ImVec2(x,0.5f-y)); + } + dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale); + dl->AddRect(rect.Min,rect.Max,borderColor,8.0f*dpiScale,0,2.0f*dpiScale); + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + oscZoomSlider=!oscZoomSlider; } - //ImGui::SetCursorPos(ImVec2(0,0)); - ImGui::BeginDisabled(); - ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail()); - ImGui::EndDisabled(); } - ImGui::PopStyleVar(3); + //ImGui::PopStyleVar(3); if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE; ImGui::End(); -} \ No newline at end of file +} diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index d4bf904b..d56196d6 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,8 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include -#include #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" @@ -284,27 +282,33 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int sprintf(id,"..##PE%d_%d_%d",k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor); } else { - sprintf(id,"%.2X##PE%d_%d_%d",pat->data[i][index],k,i,j); - if (pat->data[i][index]<0x10) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[pat->data[i][index]]]); - } else if (pat->data[i][index]<0x20) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); - } else if (pat->data[i][index]<0x30) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); - } else if (pat->data[i][index]<0x48) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); - } else if (pat->data[i][index]<0x90) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); - } else if (pat->data[i][index]<0xa0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); - } else if (pat->data[i][index]<0xc0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); - } else if (pat->data[i][index]<0xd0) { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); - } else if (pat->data[i][index]<0xe0) { + if (pat->data[i][index]>0xff) { + sprintf(id,"??##PE%d_%d_%d",k,i,j); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); } else { - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[pat->data[i][index]-0xe0]]); + const unsigned char data=pat->data[i][index]; + sprintf(id,"%.2X##PE%d_%d_%d",data,k,i,j); + if (data<0x10) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); + } else if (data<0x20) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x30) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); + } else if (data<0x48) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x90) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xa0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); + } else if (data<0xc0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xd0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); + } else if (data<0xe0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[data-0xe0]]); + } } } ImGui::SameLine(0.0f,0.0f); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1cbd6a06..316e3ef5 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -942,6 +942,18 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); ImGui::TreePop(); } + if (ImGui::TreeNode("Oscilloscope")) { + UI_COLOR_CONFIG(GUI_COLOR_OSC_BORDER,"Border"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG1,"Background (top-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG2,"Background (top-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG3,"Background (bottom-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG4,"Background (bottom-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE,"Waveform"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE_PEAK,"Waveform (clip)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_REF,"Reference"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_GUIDE,"Guide"); + ImGui::TreePop(); + } if (ImGui::TreeNode("Volume Meter")) { UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low"); UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High"); diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 1bc60c7c..8ecf7c07 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -284,7 +284,7 @@ void FurnaceGUI::drawSysConf(int i) { } sysPal=flags&1; if (ImGui::Checkbox("PAL",&sysPal)) { - e->setSysFlags(i,(flags&(~1))|sysPal,restart); + e->setSysFlags(i,(flags&(~1))|(unsigned int)sysPal,restart); updateWindowTitle(); } bool bypassLimits=flags&4; @@ -395,4 +395,4 @@ void FurnaceGUI::drawSysConf(int i) { } break; } -} \ No newline at end of file +} diff --git a/src/gui/volMeter.cpp b/src/gui/volMeter.cpp index 29f62c96..7be3464e 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;