ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

commit 8eb89a1cfaf049ba6d97626ae4e749fb1c328770
parent 506d1b78eb878807fbc889cad6c14de881d7f063
Author: Olav Sørensen <olav.sorensen@live.no>
Date:   Wed, 15 Jan 2020 13:37:58 +0100

Pushed v1.06 code

- Bugfix: Scopes were not doing backwards sampling correctly on pingpong loops.
  This would also affect the sample playback line in Smp. Ed. It was especially
  noticable on very low sampling rates (note).
- For devs: Added HAS_MIDI compiler pre-processor flag. If not defined, MIDI
  will not be used in the clone. Handy for situations where rtmidi and/or
  libstdc++ can't be used/compiled.

Diffstat:
Amake-linux-nomidi.sh | 14++++++++++++++
Mmake-linux.sh | 2+-
Mmake-macos.sh | 2+-
Msrc/ft2_audio.c | 36+++++++++++++++++-------------------
Msrc/ft2_config.c | 29++++++++++++++++++++++++++---
Msrc/ft2_config.h | 2++
Msrc/ft2_edit.c | 12++++++++++++
Msrc/ft2_events.c | 13+++++++++----
Msrc/ft2_header.h | 2+-
Msrc/ft2_keyboard.c | 2++
Msrc/ft2_main.c | 22++++++++++++++++------
Msrc/ft2_midi.c | 8+++++++-
Msrc/ft2_midi.h | 4++++
Msrc/ft2_module_loader.c | 3+++
Msrc/ft2_mouse.c | 21+++++++++++++--------
Msrc/ft2_palette.c | 2+-
Msrc/ft2_pushbuttons.c | 2++
Msrc/ft2_pushbuttons.h | 2++
Msrc/ft2_radiobuttons.c | 3+++
Msrc/ft2_radiobuttons.h | 3+++
Msrc/ft2_replayer.c | 12+++++++++++-
Msrc/ft2_sample_ed_features.c | 9+++++----
Asrc/ft2_scopedraw.c | 364+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ft2_scopedraw.h | 8++++++++
Msrc/ft2_scopes.c | 225++++++-------------------------------------------------------------------------
Msrc/ft2_scopes.h | 13+++++++++++++
Msrc/ft2_scrollbars.c | 5+++++
Msrc/ft2_scrollbars.h | 2++
Msrc/ft2_video.c | 16+++++++---------
Mvs2019_project/ft2-clone/ft2-clone.vcxproj | 10++++++----
Mvs2019_project/ft2-clone/ft2-clone.vcxproj.filters | 4++++
31 files changed, 580 insertions(+), 272 deletions(-)

diff --git a/make-linux-nomidi.sh b/make-linux-nomidi.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +rm release/other/ft2-clone &> /dev/null +echo Compiling \(with no MIDI functionality\), please wait patiently... + +# If you're compiling for *SLOW* devices, try adding -DLERPMIX right after gcc +# This will activate 2-tap linear interpolation mixing (blurrier sound) instead +# of 3-tap quadratic interpolation mixing (sharper sound) + +gcc -DNDEBUG src/gfxdata/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone + +rm src/gfxdata/*.o src/*.o &> /dev/null + +echo Done! The executable is in the folder named \'release/other\'. diff --git a/make-linux.sh b/make-linux.sh @@ -7,7 +7,7 @@ echo Compiling, please wait patiently... # This will activate 2-tap linear interpolation mixing (blurrier sound) instead # of 3-tap quadratic interpolation mixing (sharper sound) -gcc -DNDEBUG -D__LINUX_ALSA__ src/rtmidi/*.cpp src/gfxdata/*.c src/*.c -lSDL2 -lpthread -lasound -lstdc++ -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone +gcc -DNDEBUG -DHAS_MIDI -D__LINUX_ALSA__ src/rtmidi/*.cpp src/gfxdata/*.c src/*.c -lSDL2 -lpthread -lasound -lstdc++ -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -march=native -mtune=native -O3 -o release/other/ft2-clone rm src/rtmidi/*.o src/gfxdata/*.o src/*.o &> /dev/null diff --git a/make-macos.sh b/make-macos.sh @@ -8,7 +8,7 @@ else rm release/macos/ft2-clone-macos.app/Contents/MacOS/ft2-clone-macos &> /dev/null - clang -mmacosx-version-min=10.7 -arch x86_64 -mmmx -mfpmath=sse -msse2 -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -g0 -DNDEBUG -D__MACOSX_CORE__ -stdlib=libc++ src/rtmidi/*.cpp src/gfxdata/*.c src/*.c -O3 /usr/lib/libiconv.dylib -lm -Winit-self -Wno-deprecated -Wextra -Wunused -mno-ms-bitfields -Wno-missing-field-initializers -Wswitch-default -framework SDL2 -framework CoreMidi -framework CoreAudio -framework Cocoa -lpthread -lm -lstdc++ -o release/macos/ft2-clone-macos.app/Contents/MacOS/ft2-clone-macos + clang -mmacosx-version-min=10.7 -arch x86_64 -mmmx -mfpmath=sse -msse2 -I/Library/Frameworks/SDL2.framework/Headers -F/Library/Frameworks -g0 -DNDEBUG -DHAS_MIDI -D__MACOSX_CORE__ -stdlib=libc++ src/rtmidi/*.cpp src/gfxdata/*.c src/*.c -O3 /usr/lib/libiconv.dylib -lm -Winit-self -Wno-deprecated -Wextra -Wunused -mno-ms-bitfields -Wno-missing-field-initializers -Wswitch-default -framework SDL2 -framework CoreMidi -framework CoreAudio -framework Cocoa -lpthread -lm -lstdc++ -o release/macos/ft2-clone-macos.app/Contents/MacOS/ft2-clone-macos strip release/macos/ft2-clone-macos.app/Contents/MacOS/ft2-clone-macos install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/../Frameworks/SDL2.framework/Versions/A/SDL2 release/macos/ft2-clone-macos.app/Contents/MacOS/ft2-clone-macos diff --git a/src/ft2_audio.c b/src/ft2_audio.c @@ -168,10 +168,8 @@ void setSpeed(uint16_t bpm) tickTimeLen = (uint32_t)dInt; // fractional part (scaled to 0..2^32-1) - dFrac *= UINT32_MAX + 1.0; - if (dFrac > (double)UINT32_MAX) - dFrac = (double)UINT32_MAX; - tickTimeLenFrac = (uint32_t)dFrac; + dFrac *= UINT32_MAX; + tickTimeLenFrac = (uint32_t)(dFrac + 0.5); } } @@ -1038,9 +1036,8 @@ static void SDLCALL mixCallback(void *userdata, Uint8 *stream, int len) chQueuePush(chSyncData); audio.tickTime64 += tickTimeLen; - audio.tickTime64Frac += tickTimeLenFrac; - if (audio.tickTime64Frac >= (1ULL << 32)) + if (audio.tickTime64Frac > 0xFFFFFFFF) { audio.tickTime64Frac &= 0xFFFFFFFF; audio.tickTime64++; @@ -1055,7 +1052,7 @@ static void SDLCALL mixCallback(void *userdata, Uint8 *stream, int len) b = pmpLeft; mixAudio(stream, b, pmpChannels); - stream += (b * pmpCountDiv); + stream += b * pmpCountDiv; a -= b; pmpLeft -= b; @@ -1133,24 +1130,23 @@ void updateSendAudSamplesRoutine(bool lockMixer) static void calcAudioLatencyVars(uint16_t haveSamples, int32_t haveFreq) { - double dAudioLatencySecs, dInt, dFrac; + double dHaveFreq, dAudioLatencySecs, dInt, dFrac; - if (haveFreq == 0) + dHaveFreq = haveFreq; + if (dHaveFreq == 0.0) return; // panic! - dAudioLatencySecs = haveSamples / (double)haveFreq; + dAudioLatencySecs = haveSamples / dHaveFreq; - // dear SDL2, haveSamples and haveFreq better not be bogus values... + // XXX: haveSamples and haveFreq better not be bogus values... dFrac = modf(dAudioLatencySecs * editor.dPerfFreq, &dInt); // integer part audio.audLatencyPerfValInt = (uint32_t)dInt; // fractional part (scaled to 0..2^32-1) - dFrac *= UINT32_MAX + 1.0; - if (dFrac > (double)UINT32_MAX) - dFrac = (double)UINT32_MAX; - audio.audLatencyPerfValFrac = (uint32_t)round(dFrac); + dFrac *= UINT32_MAX; + audio.audLatencyPerfValFrac = (uint32_t)(dFrac + 0.5); audio.dAudioLatencyMs = dAudioLatencySecs * 1000.0; } @@ -1200,8 +1196,10 @@ bool setupAudio(bool showErrorMsg) // get audio buffer size from config special flags configAudioBufSize = 1024; - if (config.specialFlags & BUFFSIZE_512) configAudioBufSize = 512; - else if (config.specialFlags & BUFFSIZE_2048) configAudioBufSize = 2048; + if (config.specialFlags & BUFFSIZE_512) + configAudioBufSize = 512; + else if (config.specialFlags & BUFFSIZE_2048) + configAudioBufSize = 2048; audio.wantFreq = config.audioFreq; audio.wantSamples = configAudioBufSize; @@ -1211,8 +1209,8 @@ bool setupAudio(bool showErrorMsg) memset(&want, 0, sizeof (want)); // these three may change after opening a device, but our mixer is dealing with it - want.freq = config.audioFreq; - want.format = (config.specialFlags & BITDEPTH_24) ? AUDIO_F32 : AUDIO_S16; + want.freq = config.audioFreq; + want.format = (config.specialFlags & BITDEPTH_24) ? AUDIO_F32 : AUDIO_S16; want.channels = 2; // ------------------------------------------------------------------------------- want.callback = mixCallback; diff --git a/src/ft2_config.c b/src/ft2_config.c @@ -269,12 +269,14 @@ bool loadConfig(bool showErrorFlag) audio.currOutputDevice = getAudioOutputDeviceFromConfig(); audio.currInputDevice = getAudioInputDeviceFromConfig(); +#ifdef HAS_MIDI if (midi.initThreadDone) { setMidiInputDeviceFromConfig(); if (editor.ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT) drawMidiInputList(); } +#endif if (editor.configFileLocation == NULL) { @@ -388,7 +390,10 @@ bool saveConfig(bool showErrorFlag) } saveAudioDevicesToConfig(audio.currOutputDevice, audio.currInputDevice); + +#ifdef HAS_MIDI saveMidiInputDeviceToConfig(); +#endif out = UNICHAR_FOPEN(editor.configFileLocation, "wb"); if (out == NULL) @@ -791,7 +796,9 @@ static void setConfigRadioButtonStates(void) case CONFIG_SCREEN_IO_DEVICES: tmpID = RB_CONFIG_IO_DEVICES; break; case CONFIG_SCREEN_LAYOUT: tmpID = RB_CONFIG_LAYOUT; break; case CONFIG_SCREEN_MISCELLANEOUS: tmpID = RB_CONFIG_MISCELLANEOUS; break; +#ifdef HAS_MIDI case CONFIG_SCREEN_MIDI_INPUT: tmpID = RB_CONFIG_MIDI_INPUT; break; +#endif } radioButtons[tmpID].state = RADIOBUTTON_CHECKED; @@ -1012,7 +1019,11 @@ static void setConfigMiscCheckButtonStates(void) checkBoxes[CB_CONF_QUANTIZATION].checked = config.recQuant; checkBoxes[CB_CONF_CHANGE_PATTLEN_INS_DEL].checked = config.recTrueInsert; checkBoxes[CB_CONF_MIDI_ALLOW_PC].checked = config.recMIDIAllowPC; +#ifdef HAS_MIDI checkBoxes[CB_CONF_MIDI_ENABLE].checked = midi.enable; +#else + checkBoxes[CB_CONF_MIDI_ENABLE].checked = false; +#endif checkBoxes[CB_CONF_MIDI_REC_ALL].checked = config.recMIDIAllChn; checkBoxes[CB_CONF_MIDI_REC_TRANS].checked = config.recMIDITransp; checkBoxes[CB_CONF_MIDI_REC_VELOC].checked = config.recMIDIVelocity; @@ -1097,8 +1108,9 @@ void showConfigScreen(void) textOutShadow(22, 20, PAL_FORGRND, PAL_DSKTOP2, "I/O devices"); textOutShadow(22, 36, PAL_FORGRND, PAL_DSKTOP2, "Layout"); textOutShadow(22, 52, PAL_FORGRND, PAL_DSKTOP2, "Miscellaneous"); +#ifdef HAS_MIDI textOutShadow(22, 68, PAL_FORGRND, PAL_DSKTOP2, "MIDI input"); - +#endif textOutShadow(19, 92, PAL_FORGRND, PAL_DSKTOP2, "Auto save"); switch (editor.currConfigScreen) @@ -1377,13 +1389,13 @@ void showConfigScreen(void) blitFast(517, 51, midiLogo, 103, 55); +#ifdef HAS_MIDI showPushButton(PB_CONFIG_MIDI_INPUT_DOWN); showPushButton(PB_CONFIG_MIDI_INPUT_UP); - rescanMidiInputDevices(); drawMidiInputList(); - showScrollBar(SB_MIDI_INPUT_SCROLL); +#endif } break; } @@ -1490,10 +1502,12 @@ void hideConfigScreen(void) hideTextBox(TB_CONF_DEF_TRACKS_DIR); hideScrollBar(SB_MIDI_SENS); +#ifdef HAS_MIDI // CONFIG MIDI hidePushButton(PB_CONFIG_MIDI_INPUT_DOWN); hidePushButton(PB_CONFIG_MIDI_INPUT_UP); hideScrollBar(SB_MIDI_INPUT_SCROLL); +#endif editor.ui.configScreenShown = false; } @@ -1543,6 +1557,7 @@ void rbConfigMiscellaneous(void) showConfigScreen(); } +#ifdef HAS_MIDI void rbConfigMidiInput(void) { checkRadioButton(RB_CONFIG_MIDI_INPUT); @@ -1551,6 +1566,7 @@ void rbConfigMidiInput(void) hideConfigScreen(); showConfigScreen(); } +#endif void rbConfigSbs512(void) { @@ -2022,7 +2038,14 @@ void cbMIDIAllowPC(void) void cbMIDIEnable(void) { +#ifdef HAS_MIDI midi.enable ^= 1; +#else + checkBoxes[CB_CONF_MIDI_ENABLE].checked = false; + drawCheckBox(CB_CONF_MIDI_ENABLE); + + okBox(0, "System message", "This program was not compiled with MIDI functionality!"); +#endif } void cbMIDIRecTransp(void) diff --git a/src/ft2_config.h b/src/ft2_config.h @@ -197,7 +197,9 @@ void configMIDISensUp(void); void rbConfigIODevices(void); void rbConfigLayout(void); void rbConfigMiscellaneous(void); +#ifdef HAS_MIDI void rbConfigMidiInput(void); +#endif void rbConfigSbs512(void); void rbConfigSbs1024(void); void rbConfigSbs2048(void); diff --git a/src/ft2_edit.c b/src/ft2_edit.c @@ -438,7 +438,13 @@ void recordNote(uint8_t note, int8_t vol) editor.keyOnTab[c] = note; if (pattpos >= oldpattpos) // non-FT2 fix: only do this if we didn't quantize to next row + { +#ifdef HAS_MIDI playTone(c, editor.curInstr, note, vol, midi.currMIDIVibDepth, midi.currMIDIPitch); +#else + playTone(c, editor.curInstr, note, vol, 0, 0); +#endif + } if (editmode || recmode) { @@ -490,7 +496,13 @@ void recordNote(uint8_t note, int8_t vol) editor.keyOffTime[c] = ++editor.keyOffNr; if (pattpos >= oldpattpos) // non-FT2 fix: only do this if we didn't quantize to next row + { +#ifdef HAS_MIDI playTone(c, editor.curInstr, 97, vol, midi.currMIDIVibDepth, midi.currMIDIPitch); +#else + playTone(c, editor.curInstr, 97, vol, 0, 0); +#endif + } if (config.recRelease && recmode) { diff --git a/src/ft2_events.c b/src/ft2_events.c @@ -105,6 +105,7 @@ void handleThreadEvents(void) void handleEvents(void) { +#ifdef HAS_MIDI // called after MIDI has been initialized if (midi.rescanDevicesFlag) { @@ -114,6 +115,7 @@ void handleEvents(void) if (editor.ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT) drawMidiInputList(); } +#endif if (editor.trimThreadWasDone) { @@ -396,7 +398,6 @@ void setupCrashHandler(void) static void handleInput(void) { char *inputText; - uint8_t vibDepth; uint32_t eventType; SDL_Event event; SDL_Keycode key; @@ -472,8 +473,10 @@ static void handleInput(void) } else if (event.type == SDL_MOUSEWHEEL) { - if (event.wheel.y > 0) mouseWheelHandler(MOUSE_WHEEL_UP); - else if (event.wheel.y < 0) mouseWheelHandler(MOUSE_WHEEL_DOWN); + if (event.wheel.y > 0) + mouseWheelHandler(MOUSE_WHEEL_UP); + else if (event.wheel.y < 0) + mouseWheelHandler(MOUSE_WHEEL_DOWN); } else if (event.type == SDL_DROPFILE) { @@ -527,8 +530,10 @@ static void handleInput(void) editor.programRunning = false; } +#ifdef HAS_MIDI // MIDI vibrato - vibDepth = (midi.currMIDIVibDepth >> 9) & 0x0F; + uint8_t vibDepth = (midi.currMIDIVibDepth >> 9) & 0x0F; if (vibDepth > 0) recordMIDIEffect(0x04, 0xA0 | vibDepth); +#endif } diff --git a/src/ft2_header.h b/src/ft2_header.h @@ -12,7 +12,7 @@ #endif #include "ft2_replayer.h" -#define PROG_VER_STR "1.05" +#define PROG_VER_STR "1.06" // do NOT change these! It will only mess things up... diff --git a/src/ft2_keyboard.c b/src/ft2_keyboard.c @@ -1186,6 +1186,7 @@ static bool checkModifiedKeys(SDL_Keycode keycode) return true; } +#ifdef HAS_MIDI else if (keyb.leftCtrlPressed) { editor.currConfigScreen = 3; @@ -1194,6 +1195,7 @@ static bool checkModifiedKeys(SDL_Keycode keycode) return true; } +#endif break; case SDLK_5: diff --git a/src/ft2_main.c b/src/ft2_main.c @@ -32,7 +32,9 @@ #include "ft2_midi.h" #include "ft2_events.h" +#ifdef HAS_MIDI static SDL_Thread *initMidiThread; +#endif static void setupPerfFreq(void); static void initializeVars(void); @@ -196,6 +198,7 @@ int main(int argc, char *argv[]) enterFullscreen(); } +#ifdef HAS_MIDI // set up MIDI input (in a thread because it can take quite a while on f.ex. macOS) initMidiThread = SDL_CreateThread(initMidiFunc, NULL, NULL); if (initMidiThread == NULL) @@ -205,6 +208,7 @@ int main(int argc, char *argv[]) return 1; } SDL_DetachThread(initMidiThread); // don't wait for this thread, let it clean up when done +#endif setupWaitVBL(); handleModuleLoadFromArg(argc, argv); @@ -278,22 +282,26 @@ static void initializeVars(void) editor.ptnJumpPos[3] = 0x30; editor.copyMaskEnable = true; - memset(editor.copyMask, 1, sizeof (editor.copyMask)); + memset(editor.copyMask, 1, sizeof (editor.copyMask)); memset(editor.pasteMask, 1, sizeof (editor.pasteMask)); +#ifdef HAS_MIDI midi.enable = true; +#endif editor.diskOpReadOnOpen = true; - editor.programRunning = true; + editor.programRunning = true; } static void cleanUpAndExit(void) // never call this inside the main loop! { +#ifdef HAS_MIDI if (midi.closeMidiOnExit) { closeMidiInDevice(); freeMidiIn(); } +#endif closeAudio(); closeReplayer(); @@ -302,16 +310,20 @@ static void cleanUpAndExit(void) // never call this inside the main loop! freeDiskOp(); clearCopyBuffer(); freeAudioDeviceSelectorBuffers(); +#ifdef HAS_MIDI freeMidiInputDeviceList(); +#endif windUpFTHelp(); freeTextBoxes(); freeMouseCursors(); +#ifdef HAS_MIDI if (midi.inputDeviceName != NULL) { free(midi.inputDeviceName); midi.inputDeviceName = NULL; } +#endif if (editor.audioDevConfigFileLocation != NULL) { @@ -392,10 +404,8 @@ static void setupPerfFreq(void) video.vblankTimeLen = (uint32_t)dInt; // fractional part scaled to 0..2^32-1 - dFrac *= UINT32_MAX + 1.0; - if (dFrac > (double)UINT32_MAX) - dFrac = (double)UINT32_MAX; - video.vblankTimeLenFrac = (uint32_t)round(dFrac); + dFrac *= UINT32_MAX; + video.vblankTimeLenFrac = (uint32_t)(dFrac + 0.5); } #ifdef _WIN32 diff --git a/src/ft2_midi.c b/src/ft2_midi.c @@ -1,3 +1,5 @@ +#ifdef HAS_MIDI + // for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER #include <crtdbg.h> @@ -28,7 +30,7 @@ static RtMidiPtr midiDev; static inline void midiInSetChannel(uint8_t status) { - recMIDIValidChn = (config.recMIDIAllChn || (status & 0x0F) == config.recMIDIChn -1); + recMIDIValidChn = (config.recMIDIAllChn || (status & 0xF) == config.recMIDIChn-1); } static inline void midiInKeyAction(int8_t m, uint8_t mv) @@ -518,3 +520,7 @@ int32_t SDLCALL initMidiFunc(void *ptr) return true; } + +#else +typedef int make_iso_compilers_happy; // kludge: prevent warning about empty .c file if HAS_MIDI is not defined +#endif diff --git a/src/ft2_midi.h b/src/ft2_midi.h @@ -1,5 +1,7 @@ #pragma once +#ifdef HAS_MIDI + #include <stdint.h> #include <stdbool.h> #include <SDL2/SDL.h> @@ -32,3 +34,5 @@ void scrollMidiInputDevListDown(void); void sbMidiInputSetPos(uint32_t pos); bool testMidiInputDeviceListMouseDown(void); int32_t SDLCALL initMidiFunc(void *ptr); + +#endif diff --git a/src/ft2_module_loader.c b/src/ft2_module_loader.c @@ -2278,8 +2278,11 @@ static void setupLoadedModule(void) editor.currVolEnvPoint = 0; editor.currPanEnvPoint = 0; + +#ifdef HAS_MIDI midi.currMIDIVibDepth = 0; midi.currMIDIPitch = 0; +#endif memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab)); diff --git a/src/ft2_mouse.c b/src/ft2_mouse.c @@ -477,12 +477,14 @@ void mouseWheelHandler(bool directionUp) directionUp ? scrollAudInputDevListUp() : scrollAudInputDevListDown(); } } +#ifdef HAS_MIDI else if (editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT) { // midi input device selector if (mouse.x >= 110 && mouse.x <= 503 && mouse.y <= 173) directionUp ? scrollMidiInputDevListUp() : scrollMidiInputDevListDown(); } +#endif } if (!editor.ui.aboutScreenShown && !editor.ui.helpScreenShown && @@ -707,15 +709,18 @@ void mouseButtonDownHandler(uint8_t mouseButton) if (editor.ui.sysReqShown) return; - if (testInstrVolEnvMouseDown(false)) return; - if (testInstrPanEnvMouseDown(false)) return; - if (testDiskOpMouseDown(false)) return; - if (testPianoKeysMouseDown(false)) return; - if (testSamplerDataMouseDown()) return; - if (testPatternDataMouseDown()) return; - if (testScopesMouseDown()) return; - if (testAudioDeviceListsMouseDown()) return; + if (testInstrVolEnvMouseDown(false)) return; + if (testInstrPanEnvMouseDown(false)) return; + if (testDiskOpMouseDown(false)) return; + if (testPianoKeysMouseDown(false)) return; + if (testSamplerDataMouseDown()) return; + if (testPatternDataMouseDown()) return; + if (testScopesMouseDown()) return; + if (testAudioDeviceListsMouseDown()) return; + +#ifdef HAS_MIDI if (testMidiInputDeviceListMouseDown()) return; +#endif } void handleLastGUIObjectDown(void) diff --git a/src/ft2_palette.c b/src/ft2_palette.c @@ -20,7 +20,7 @@ static uint8_t palContrast[12][2] = // palette desktop/button contrasts void setPal16(pal16 *p, bool redrawScreen) { -#define LOOP_PIN_COL_SUB 106 +#define LOOP_PIN_COL_SUB 118 #define TEXT_MARK_COLOR 0x0078D7 #define BOX_SELECT_COLOR 0x7F7F7F diff --git a/src/ft2_pushbuttons.c b/src/ft2_pushbuttons.c @@ -345,10 +345,12 @@ pushButton_t pushButtons[NUM_PUSHBUTTONS] = { 556, 158, 22, 13, 1, 4, ARROW_LEFT_STRING, NULL, configMIDISensDown, NULL }, { 607, 158, 22, 13, 1, 4, ARROW_RIGHT_STRING, NULL, configMIDISensUp, NULL }, +#ifdef HAS_MIDI // ------ CONFIG MIDI PUSHBUTTONS ------ //x, y, w, h, p, d, text #1, text #2, funcOnDown, funcOnUp { 483, 2, 18, 13, 1, 4, ARROW_UP_STRING, NULL, scrollMidiInputDevListUp, NULL }, { 483, 158, 18, 13, 1, 4, ARROW_DOWN_STRING, NULL, scrollMidiInputDevListDown, NULL }, +#endif // ------ DISK OP. PUSHBUTTONS ------ //x, y, w, h, p, d, text #1, text #2, funcOnDown, funcOnUp diff --git a/src/ft2_pushbuttons.h b/src/ft2_pushbuttons.h @@ -290,9 +290,11 @@ enum // PUSHBUTTONS PB_CONFIG_MIDISENS_DOWN, PB_CONFIG_MIDISENS_UP, +#ifdef HAS_MIDI // CONFIG MIDI PB_CONFIG_MIDI_INPUT_DOWN, PB_CONFIG_MIDI_INPUT_UP, +#endif // DISK OP. PB_DISKOP_SAVE, diff --git a/src/ft2_radiobuttons.c b/src/ft2_radiobuttons.c @@ -65,7 +65,10 @@ radioButton_t radioButtons[NUM_RADIOBUTTONS] = { 4, 19, 87, RB_GROUP_CONFIG_SELECT, rbConfigIODevices }, { 4, 35, 59, RB_GROUP_CONFIG_SELECT, rbConfigLayout }, { 4, 51, 99, RB_GROUP_CONFIG_SELECT, rbConfigMiscellaneous }, + +#ifdef HAS_MIDI { 4, 67, 74, RB_GROUP_CONFIG_SELECT, rbConfigMidiInput }, +#endif // ------ CONFIG AUDIO ------ diff --git a/src/ft2_radiobuttons.h b/src/ft2_radiobuttons.h @@ -38,7 +38,10 @@ enum // RADIOBUTTONS RB_CONFIG_IO_DEVICES, RB_CONFIG_LAYOUT, RB_CONFIG_MISCELLANEOUS, + +#ifdef HAS_MIDI RB_CONFIG_MIDI_INPUT, +#endif // CONFIG AUDIO diff --git a/src/ft2_replayer.c b/src/ft2_replayer.c @@ -1452,7 +1452,11 @@ static void fixaEnvelopeVibrato(stmTyp *ch) } // *** AUTO VIBRATO *** +#ifdef HAS_MIDI if (ch->midiVibDepth > 0 || ins->vibDepth > 0) +#else + if (ins->vibDepth > 0) +#endif { if (ch->eVibSweep > 0) { @@ -1474,12 +1478,13 @@ static void fixaEnvelopeVibrato(stmTyp *ch) autoVibAmp = ch->eVibAmp; } +#ifdef HAS_MIDI // non-FT2 hack to make modulation wheel work when auto vibrato rate is zero if (ch->midiVibDepth > 0 && ins->vibRate == 0) ins->vibRate = 0x20; autoVibAmp += ch->midiVibDepth; - +#endif ch->eVibPos += ins->vibRate; if (ins->vibTyp == 1) autoVibVal = (ch->eVibPos > 127) ? 64 : -64; // square @@ -1500,11 +1505,14 @@ static void fixaEnvelopeVibrato(stmTyp *ch) else { ch->finalPeriod = ch->outPeriod; + +#ifdef HAS_MIDI if (midi.enable) { ch->finalPeriod -= ch->midiPitch; ch->status |= IS_Period; } +#endif } } @@ -2879,8 +2887,10 @@ void stopPlaying(void) if (songWasPlaying) editor.pattPos = song.pattPos; +#ifdef HAS_MIDI midi.currMIDIVibDepth = 0; midi.currMIDIPitch = 0; +#endif memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab)); diff --git a/src/ft2_sample_ed_features.c b/src/ft2_sample_ed_features.c @@ -1,8 +1,9 @@ /* This file contains the routines for the following sample editor functions: -** - Resampler -** - Echo -** - Mix -** - Volume */ + * - Resampler + * - Echo + * - Mix + * - Volume + */ // for finding memory leaks in debug mode with Visual Studio #if defined _DEBUG && defined _MSC_VER diff --git a/src/ft2_scopedraw.c b/src/ft2_scopedraw.c @@ -0,0 +1,364 @@ +#include "ft2_scopes.h" +#include "ft2_scopedraw.h" +#include "ft2_video.h" + +/* ----------------------------------------------------------------------- */ +/* SCOPE DRAWING MACROS */ +/* ----------------------------------------------------------------------- */ + +#define SCOPE_REGS \ + int32_t sample; \ + int32_t scopeDrawPos = s->SPos; \ + int32_t scopeDrawFrac = 0; \ + uint32_t scopePixelColor = video.palette[PAL_PATTEXT]; \ + uint32_t len = x + w; \ + +#define SCOPE_REGS_PINGPONG \ + int32_t sample; \ + int32_t scopeDrawPos = s->SPos; \ + int32_t scopeDrawFrac = 0; \ + int32_t drawPosDir = s->SPosDir; \ + uint32_t scopePixelColor = video.palette[PAL_PATTEXT]; \ + uint32_t len = x + w; \ + +#define LINED_SCOPE_REGS \ + int32_t sample; \ + int32_t y1, y2; \ + int32_t scopeDrawPos = s->SPos; \ + int32_t scopeDrawFrac = 0; \ + uint32_t len = (x + w) - 1; \ + +#define LINED_SCOPE_REGS_PINGPONG \ + int32_t sample; \ + int32_t y1, y2; \ + int32_t scopeDrawPos = s->SPos; \ + int32_t scopeDrawFrac = 0; \ + int32_t drawPosDir = s->SPosDir; \ + uint32_t len = (x + w) - 1; \ + +#define SCOPE_GET_SMP8 \ + if (!s->active) \ + { \ + sample = 0; \ + } \ + else \ + { \ + assert(scopeDrawPos >= 0 && scopeDrawPos < s->SLen); \ + sample = (s->sampleData8[scopeDrawPos] * s->SVol) >> 8; \ + } \ + +#define SCOPE_GET_SMP16 \ + if (!s->active) \ + { \ + sample = 0; \ + } \ + else \ + { \ + assert(scopeDrawPos >= 0 && scopeDrawPos < s->SLen); \ + sample = (int8_t)((s->sampleData16[scopeDrawPos] * s->SVol) >> 16); \ + } \ + +#define SCOPE_UPDATE_DRAWPOS \ + scopeDrawFrac += s->SFrq >> 6; \ + scopeDrawPos += scopeDrawFrac >> 16; \ + scopeDrawFrac &= 0xFFFF; \ + +#define SCOPE_UPDATE_DRAWPOS_PINGPONG \ + scopeDrawFrac += s->SFrq >> 6; \ + scopeDrawPos += (scopeDrawFrac >> 16) * drawPosDir; \ + scopeDrawFrac &= 0xFFFF; \ + +#define SCOPE_DRAW_SMP \ + video.frameBuffer[((lineY - sample) * SCREEN_W) + x] = scopePixelColor; + +#define LINED_SCOPE_PREPARE_SMP8 \ + SCOPE_GET_SMP8 \ + y1 = lineY - sample; \ + SCOPE_UPDATE_DRAWPOS + +#define LINED_SCOPE_PREPARE_SMP16 \ + SCOPE_GET_SMP16 \ + y1 = lineY - sample; \ + SCOPE_UPDATE_DRAWPOS + +#define LINED_SCOPE_DRAW_SMP \ + y2 = lineY - sample; \ + scopeLine(x, y1, y2); \ + y1 = y2; \ + +#define SCOPE_HANDLE_POS_NO_LOOP \ + if (scopeDrawPos >= s->SLen) \ + s->active = false; \ + +#define SCOPE_HANDLE_POS_LOOP \ + if (scopeDrawPos >= s->SLen) \ + { \ + if (s->SRepL < 2) \ + scopeDrawPos = s->SRepS; \ + else \ + scopeDrawPos = s->SRepS + ((scopeDrawPos - s->SLen) % s->SRepL); \ + \ + assert(scopeDrawPos >= s->SRepS && scopeDrawPos < s->SLen); \ + } \ + +#define SCOPE_HANDLE_POS_PINGPONG \ + if (drawPosDir == -1 && scopeDrawPos < s->SRepS) \ + { \ + drawPosDir = 1; /* change direction to forwards */ \ + \ + if (s->SRepL < 2) \ + scopeDrawPos = s->SRepS; \ + else \ + scopeDrawPos = s->SRepS + ((s->SRepS - scopeDrawPos - 1) % s->SRepL); \ + \ + assert(scopeDrawPos >= s->SRepS && scopeDrawPos < s->SLen); \ + } \ + else if (scopeDrawPos >= s->SLen) \ + { \ + drawPosDir = -1; /* change direction to backwards */ \ + \ + if (s->SRepL < 2) \ + scopeDrawPos = s->SLen - 1; \ + else \ + scopeDrawPos = (s->SLen - 1) - ((scopeDrawPos - s->SLen) % s->SRepL); \ + \ + assert(scopeDrawPos >= s->SRepS && scopeDrawPos < s->SLen); \ + } \ + assert(scopeDrawPos >= 0); \ + +static void scopeLine(int32_t x1, int32_t y1, int32_t y2) +{ + int32_t pitch, d, sy, dy; + uint32_t ay, pixVal, *dst32; + + dy = y2 - y1; + ay = ABS(dy); + sy = SGN(dy); + + pixVal = video.palette[PAL_PATTEXT]; + pitch = sy * SCREEN_W; + + dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1]; + *dst32 = pixVal; + + if (ay <= 1) + { + if (ay != 0) + dst32 += pitch; + + *++dst32 = pixVal; + return; + } + + d = 2 - ay; + + ay *= 2; + while (y1 != y2) + { + if (d >= 0) + { + d -= ay; + dst32++; + } + + y1 += sy; + d += 2; + + dst32 += pitch; + *dst32 = pixVal; + } +} + +/* ----------------------------------------------------------------------- */ +/* SCOPE DRAWING ROUTINES */ +/* ----------------------------------------------------------------------- */ + +static void scopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_NO_LOOP + } +} + +static void scopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_LOOP + } +} + +static void scopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS_PINGPONG + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS_PINGPONG + SCOPE_HANDLE_POS_PINGPONG + } +} + +static void scopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_NO_LOOP + } +} + +static void scopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_LOOP + } +} + +static void scopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + SCOPE_REGS_PINGPONG + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS_PINGPONG + SCOPE_HANDLE_POS_PINGPONG + } +} + +/* ----------------------------------------------------------------------- */ +/* LINED SCOPE DRAWING ROUTINES */ +/* ----------------------------------------------------------------------- */ + +static void linedScopeDrawNoLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS + LINED_SCOPE_PREPARE_SMP8 + SCOPE_HANDLE_POS_NO_LOOP + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_NO_LOOP + } +} + +static void linedScopeDrawLoop_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS + LINED_SCOPE_PREPARE_SMP8 + SCOPE_HANDLE_POS_LOOP + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_LOOP + } +} + +static void linedScopeDrawPingPong_8bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS_PINGPONG + LINED_SCOPE_PREPARE_SMP8 + SCOPE_HANDLE_POS_PINGPONG + + for (; x < len; x++) + { + SCOPE_GET_SMP8 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS_PINGPONG + SCOPE_HANDLE_POS_PINGPONG + } +} + +static void linedScopeDrawNoLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS + LINED_SCOPE_PREPARE_SMP16 + SCOPE_HANDLE_POS_NO_LOOP + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_NO_LOOP + } +} + +static void linedScopeDrawLoop_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS + LINED_SCOPE_PREPARE_SMP16 + SCOPE_HANDLE_POS_LOOP + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS + SCOPE_HANDLE_POS_LOOP + } +} + +static void linedScopeDrawPingPong_16bit(scope_t *s, uint32_t x, uint32_t lineY, uint32_t w) +{ + LINED_SCOPE_REGS_PINGPONG + LINED_SCOPE_PREPARE_SMP16 + SCOPE_HANDLE_POS_PINGPONG + + for (; x < len; x++) + { + SCOPE_GET_SMP16 + LINED_SCOPE_DRAW_SMP + SCOPE_UPDATE_DRAWPOS_PINGPONG + SCOPE_HANDLE_POS_PINGPONG + } +} + +// ----------------------------------------------------------------------- + +const scopeDrawRoutine scopeDrawRoutineTable[12] = +{ + (scopeDrawRoutine)scopeDrawNoLoop_8bit, + (scopeDrawRoutine)scopeDrawLoop_8bit, + (scopeDrawRoutine)scopeDrawPingPong_8bit, + (scopeDrawRoutine)scopeDrawNoLoop_16bit, + (scopeDrawRoutine)scopeDrawLoop_16bit, + (scopeDrawRoutine)scopeDrawPingPong_16bit, + (scopeDrawRoutine)linedScopeDrawNoLoop_8bit, + (scopeDrawRoutine)linedScopeDrawLoop_8bit, + (scopeDrawRoutine)linedScopeDrawPingPong_8bit, + (scopeDrawRoutine)linedScopeDrawNoLoop_16bit, + (scopeDrawRoutine)linedScopeDrawLoop_16bit, + (scopeDrawRoutine)linedScopeDrawPingPong_16bit +}; diff --git a/src/ft2_scopedraw.h b/src/ft2_scopedraw.h @@ -0,0 +1,8 @@ +#pragma once + +#include <stdint.h> +#include "ft2_scopes.h" + +typedef void (*scopeDrawRoutine)(scope_t *, uint32_t, uint32_t, uint32_t); + +extern const scopeDrawRoutine scopeDrawRoutineTable[12]; // ft2_scopedraw.c diff --git a/src/ft2_scopes.c b/src/ft2_scopes.c @@ -19,6 +19,7 @@ #include "ft2_scopes.h" #include "ft2_mouse.h" #include "ft2_video.h" +#include "ft2_scopedraw.h" enum { @@ -37,19 +38,6 @@ typedef struct scopeState_t int32_t len, repS, repL, playOffset; } scopeState_t; -// actual scope data -typedef struct scope_t -{ - volatile bool active; - const int8_t *sampleData8; - const int16_t *sampleData16; - int8_t SVol; - bool wasCleared, sample16Bit; - uint8_t loopType; - int32_t SRepS, SRepL, SLen, SPos; - uint32_t SFrq, SPosDec, posXOR; -} scope_t; - static volatile bool scopesUpdatingFlag, scopesDisplayingFlag; static uint32_t oldVoiceDelta, oldSFrq, scopeTimeLen, scopeTimeLenFrac; static uint64_t timeNext64, timeNext64Frac; @@ -408,7 +396,7 @@ static void scopeTrigger(uint8_t ch, sampleTyp *s, int32_t playOffset) tempState.sample16Bit = sampleIs16Bit; tempState.loopType = loopType; - tempState.posXOR = 0; // forwards + tempState.SPosDir = 1; // forwards tempState.SLen = (loopType > 0) ? (loopBegin + loopLength) : length; tempState.SRepS = loopBegin; tempState.SRepL = loopLength; @@ -454,14 +442,14 @@ static void updateScopes(void) // scope position update tempState.SPosDec += tempState.SFrq; - tempState.SPos += ((tempState.SPosDec >> 16) ^ tempState.posXOR); + tempState.SPos += ((tempState.SPosDec >> 16) * tempState.SPosDir); tempState.SPosDec &= 0xFFFF; // handle loop wrapping or sample end - if (tempState.posXOR == 0xFFFFFFFF && tempState.SPos < tempState.SRepS) // sampling backwards (definitely pingpong loop) + if (tempState.SPosDir == -1 && tempState.SPos < tempState.SRepS) // sampling backwards (definitely pingpong loop) { - tempState.posXOR = 0; // change direction to forwards + tempState.SPosDir = 1; // change direction to forwards if (tempState.SRepL < 2) tempState.SPos = tempState.SRepS; @@ -488,7 +476,7 @@ static void updateScopes(void) } else // pingpong loop { - tempState.posXOR = 0xFFFFFFFF; // change direction to backwards + tempState.SPosDir = -1; // change direction to backwards tempState.SPos = (tempState.SLen - 1) - loopOverflowVal; assert(tempState.SPos >= tempState.SRepS && tempState.SPos < tempState.SLen); } @@ -500,118 +488,11 @@ static void updateScopes(void) scopesUpdatingFlag = false; } -static void scopeLine(int16_t x1, int16_t y1, int16_t y2) -{ - int16_t d, sy, dy; - uint16_t ay; - int32_t pitch; - uint32_t pixVal, *dst32; - - dy = y2 - y1; - ay = ABS(dy); - sy = SGN(dy); - - pixVal = video.palette[PAL_PATTEXT]; - pitch = sy * SCREEN_W; - - dst32 = &video.frameBuffer[(y1 * SCREEN_W) + x1]; - *dst32 = pixVal; - - if (ay <= 1) - { - if (ay != 0) - dst32 += pitch; - - *++dst32 = pixVal; - return; - } - - d = 2 - ay; - - ay *= 2; - while (y1 != y2) - { - if (d >= 0) - { - d -= ay; - dst32++; - } - - y1 += sy; - d += 2; - - dst32 += pitch; - *dst32 = pixVal; - } -} - -static inline int8_t getScaledScopeSample8(scope_t *sc, int32_t drawPos) -{ - if (!sc->active) - return 0; - - assert(drawPos >= 0 && drawPos < sc->SLen); - return (sc->sampleData8[drawPos] * sc->SVol) >> 8; -} - -static inline int8_t getScaledScopeSample16(scope_t *sc, int32_t drawPos) -{ - if (!sc->active) - return 0; - - assert(drawPos >= 0 && drawPos < sc->SLen); - return (int8_t)((sc->sampleData16[drawPos] * sc->SVol) >> 16); -} - -#define SCOPE_UPDATE_DRAWPOS \ - scopeDrawFrac += s.SFrq >> 6; \ - scopeDrawPos += ((scopeDrawFrac >> 16) ^ drawPosXOR); \ - scopeDrawFrac &= 0xFFFF; \ - \ - if (drawPosXOR == 0xFFFFFFFF && scopeDrawPos < s.SRepS) /* sampling backwards (definitely pingpong loop) */ \ - { \ - drawPosXOR = 0; /* change direction to forwards */ \ - \ - if (s.SRepL < 2) \ - scopeDrawPos = s.SRepS; \ - else \ - scopeDrawPos = s.SRepS + ((s.SRepS - scopeDrawPos - 1) % s.SRepL); \ - \ - assert(scopeDrawPos >= s.SRepS && scopeDrawPos < s.SLen); \ - } \ - else if (scopeDrawPos >= s.SLen) \ - { \ - if (s.SRepL < 2) \ - loopOverflowVal = 0; \ - else \ - loopOverflowVal = (scopeDrawPos - s.SLen) % s.SRepL; \ - \ - if (s.loopType == LOOP_NONE) \ - { \ - s.active = false; \ - } \ - else if (s.loopType == LOOP_FORWARD) \ - { \ - scopeDrawPos = s.SRepS + loopOverflowVal; \ - assert(scopeDrawPos >= s.SRepS && scopeDrawPos < s.SLen); \ - } \ - else /* pingpong loop */ \ - { \ - drawPosXOR = 0xFFFFFFFF; /* change direction to backwards */ \ - scopeDrawPos = (s.SLen - 1) - loopOverflowVal; \ - assert(scopeDrawPos >= s.SRepS && scopeDrawPos < s.SLen); \ - } \ - \ - } \ - assert(scopeDrawPos >= 0); \ - void drawScopes(void) { - int16_t y1, y2, sample, scopeLineY; + int16_t scopeLineY; const uint16_t *scopeLens; - uint16_t chansPerRow, x16, scopeXOffs, scopeYOffs, scopeDrawLen; - int32_t scopeDrawPos, loopOverflowVal; - uint32_t x, len, drawPosXOR, scopeDrawFrac, scopePixelColor; + uint16_t chansPerRow, scopeXOffs, scopeYOffs, scopeDrawLen; volatile scope_t *sc; scope_t s; @@ -651,80 +532,9 @@ void drawScopes(void) // clear scope background clearRect(scopeXOffs, scopeYOffs, scopeDrawLen, SCOPE_HEIGHT); - scopeDrawPos = s.SPos; - scopeDrawFrac = 0; - drawPosXOR = s.posXOR; - - // draw current scope - if (config.specialFlags & LINED_SCOPES) - { - // LINE SCOPE - - if (s.sample16Bit) - { - y1 = scopeLineY - getScaledScopeSample16(&s, scopeDrawPos); - SCOPE_UPDATE_DRAWPOS - - x16 = scopeXOffs; - len = scopeXOffs + (scopeDrawLen - 1); - - for (; x16 < len; x16++) - { - y2 = scopeLineY - getScaledScopeSample16(&s, scopeDrawPos); - scopeLine(x16, y1, y2); - y1 = y2; - - SCOPE_UPDATE_DRAWPOS - } - } - else - { - y1 = scopeLineY - getScaledScopeSample8(&s, scopeDrawPos); - SCOPE_UPDATE_DRAWPOS - - x16 = scopeXOffs; - len = scopeXOffs + (scopeDrawLen - 1); - - for (; x16 < len; x16++) - { - y2 = scopeLineY - getScaledScopeSample8(&s, scopeDrawPos); - scopeLine(x16, y1, y2); - y1 = y2; - - SCOPE_UPDATE_DRAWPOS - } - } - } - else - { - // PIXEL SCOPE - - scopePixelColor = video.palette[PAL_PATTEXT]; - - x = scopeXOffs; - len = scopeXOffs + scopeDrawLen; - - if (s.sample16Bit) - { - for (; x < len; x++) - { - sample = getScaledScopeSample16(&s, scopeDrawPos); - video.frameBuffer[((scopeLineY - sample) * SCREEN_W) + x] = scopePixelColor; - - SCOPE_UPDATE_DRAWPOS - } - } - else - { - for (; x < len; x++) - { - sample = getScaledScopeSample8(&s, scopeDrawPos); - video.frameBuffer[((scopeLineY - sample) * SCREEN_W) + x] = scopePixelColor; - - SCOPE_UPDATE_DRAWPOS - } - } - } + // draw scope + bool linedScopes = !!(config.specialFlags & LINED_SCOPES); + scopeDrawRoutineTable[(linedScopes * 6) + (s.sample16Bit * 3) + s.loopType](&s, scopeXOffs, scopeLineY, scopeDrawLen); } else { @@ -850,12 +660,11 @@ static int32_t SDLCALL scopeThreadFunc(void *ptr) // update next tick time timeNext64 += scopeTimeLen; - timeNext64Frac += scopeTimeLenFrac; - if (timeNext64Frac >= (1ULL << 32)) + if (timeNext64Frac > 0xFFFFFFFF) { - timeNext64++; timeNext64Frac &= 0xFFFFFFFF; + timeNext64++; } } @@ -872,11 +681,9 @@ bool initScopes(void) // integer part scopeTimeLen = (uint32_t)dInt; - // fractional part scaled to 0..2^32-1 - dFrac *= UINT32_MAX + 1.0; - if (dFrac > (double)UINT32_MAX) - dFrac = (double)UINT32_MAX; - scopeTimeLenFrac = (uint32_t)round(dFrac); + // fractional part (scaled to 0..2^32-1) + dFrac *= UINT32_MAX; + scopeTimeLenFrac = (uint32_t)(dFrac + 0.5); scopeThread = SDL_CreateThread(scopeThreadFunc, NULL, NULL); if (scopeThread == NULL) diff --git a/src/ft2_scopes.h b/src/ft2_scopes.h @@ -13,6 +13,19 @@ void drawScopes(void); void drawScopeFramework(void); bool initScopes(void); +// actual scope data +typedef struct scope_t +{ + volatile bool active; + const int8_t *sampleData8; + const int16_t *sampleData16; + int8_t SVol; + bool wasCleared, sample16Bit; + uint8_t loopType; + int32_t SPosDir, SRepS, SRepL, SLen, SPos; + uint32_t SFrq, SPosDec; +} scope_t; + typedef struct lastChInstr_t { uint8_t sampleNr, instrNr; diff --git a/src/ft2_scrollbars.c b/src/ft2_scrollbars.c @@ -90,9 +90,11 @@ scrollBar_t scrollBars[NUM_SCROLLBARS] = //x, y, w, h, type, style funcOnDown { 578, 158, 29, 13, SCROLLBAR_HORIZONTAL, SCROLLBAR_THUMB_NOFLAT, sbMIDISens }, +#ifdef HAS_MIDI // ------ CONFIG MIDI SCROLLBARS ------ //x, y, w, h, type, style funcOnDown { 483, 15, 18, 143, SCROLLBAR_VERTICAL, SCROLLBAR_THUMB_FLAT, sbMidiInputSetPos }, +#endif // ------ DISK OP. SCROLLBARS ------ //x, y, w, h, type, style funcOnDown @@ -651,8 +653,11 @@ void initializeScrollBars(void) setScrollBarEnd(SB_AUDIO_OUTPUT_SCROLL, 1); setScrollBarPageLength(SB_AUDIO_INPUT_SCROLL, 4); setScrollBarEnd(SB_AUDIO_INPUT_SCROLL, 1); + +#ifdef HAS_MIDI setScrollBarPageLength(SB_MIDI_INPUT_SCROLL, 15); setScrollBarEnd(SB_MIDI_INPUT_SCROLL, 1); +#endif // disk op. setScrollBarPageLength(SB_DISKOP_LIST, DISKOP_ENTRY_NUM); diff --git a/src/ft2_scrollbars.h b/src/ft2_scrollbars.h @@ -45,8 +45,10 @@ enum // SCROLLBARS // Config Miscellaneous SB_MIDI_SENS, +#ifdef HAS_MIDI // Config Midi SB_MIDI_INPUT_SCROLL, +#endif // Disk Op. SB_DISKOP_LIST, diff --git a/src/ft2_video.c b/src/ft2_video.c @@ -76,9 +76,6 @@ static void drawFPSCounter(void) uint16_t xPos, yPos; double dRefreshRate, dAudLatency; - if (!video.showFPSCounter) - return; - if (editor.framesPassed >= FPS_SCAN_FRAMES && (editor.framesPassed % FPS_SCAN_FRAMES) == 0) { dAvgFPS = dRunningFPS * (1.0 / FPS_SCAN_FRAMES); @@ -163,7 +160,10 @@ void flipFrame(void) uint32_t windowFlags = SDL_GetWindowFlags(video.window); renderSprites(); - drawFPSCounter(); + + if (video.showFPSCounter) + drawFPSCounter(); + SDL_UpdateTexture(video.texture, NULL, video.frameBuffer, SCREEN_W * sizeof (int32_t)); SDL_RenderClear(video.renderer); SDL_RenderCopy(video.renderer, video.texture, NULL, NULL); @@ -363,7 +363,7 @@ bool setupSprites(void) // setup refresh buffer (used to clear sprites after each frame) for (uint32_t i = 0; i < SPRITE_NUM; i++) { - sprites[i].refreshBuffer = (uint32_t *)malloc((sprites[i].w * sprites[i].h) * sizeof (int32_t)); + sprites[i].refreshBuffer = (uint32_t *)malloc(sprites[i].w * sprites[i].h * sizeof (int32_t)); if (sprites[i].refreshBuffer == NULL) return false; } @@ -423,7 +423,7 @@ void eraseSprites(void) uint32_t *dst32; sprite_t *s; - for (i = (SPRITE_NUM - 1); i >= 0; i--) // erasing must be done in reverse order + for (i = SPRITE_NUM-1; i >= 0; i--) // erasing must be done in reverse order { s = &sprites[i]; if (s->x >= SCREEN_W) // sprite is hidden, don't erase @@ -725,11 +725,9 @@ void waitVBL(void) } // update next frame time - timeNext64 += video.vblankTimeLen; - timeNext64Frac += video.vblankTimeLenFrac; - if (timeNext64Frac >= (1ULL << 32)) + if (timeNext64Frac > 0xFFFFFFFF) { timeNext64Frac &= 0xFFFFFFFF; timeNext64++; diff --git a/vs2019_project/ft2-clone/ft2-clone.vcxproj b/vs2019_project/ft2-clone/ft2-clone.vcxproj @@ -94,7 +94,7 @@ <Optimization>MaxSpeed</Optimization> <AdditionalIncludeDirectories> </AdditionalIncludeDirectories> - <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI</PreprocessorDefinitions> + <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI;HAS_MIDI</PreprocessorDefinitions> <MultiProcessorCompilation>true</MultiProcessorCompilation> <CompileAsManaged>false</CompileAsManaged> <IntrinsicFunctions>true</IntrinsicFunctions> @@ -151,7 +151,7 @@ <Optimization>MaxSpeed</Optimization> <AdditionalIncludeDirectories> </AdditionalIncludeDirectories> - <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI</PreprocessorDefinitions> + <PreprocessorDefinitions>__WINDOWS_MM__;NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI;HAS_MIDI</PreprocessorDefinitions> <MultiProcessorCompilation>true</MultiProcessorCompilation> <CompileAsManaged>false</CompileAsManaged> <IntrinsicFunctions>true</IntrinsicFunctions> @@ -220,7 +220,7 @@ <WarningLevel>Level4</WarningLevel> <AdditionalIncludeDirectories> </AdditionalIncludeDirectories> - <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI</PreprocessorDefinitions> + <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI;HAS_MIDI</PreprocessorDefinitions> <ExceptionHandling>false</ExceptionHandling> <FloatingPointModel>Fast</FloatingPointModel> <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet> @@ -265,7 +265,7 @@ <WarningLevel>Level4</WarningLevel> <AdditionalIncludeDirectories> </AdditionalIncludeDirectories> - <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI</PreprocessorDefinitions> + <PreprocessorDefinitions>__WINDOWS_MM__;_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;HAVE_M_PI;HAS_MIDI</PreprocessorDefinitions> <ExceptionHandling>false</ExceptionHandling> <FloatingPointModel>Fast</FloatingPointModel> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> @@ -351,6 +351,7 @@ <ClCompile Include="..\..\src\ft2_sample_ed.c" /> <ClCompile Include="..\..\src\ft2_sample_loader.c" /> <ClCompile Include="..\..\src\ft2_sample_saver.c" /> + <ClCompile Include="..\..\src\ft2_scopedraw.c" /> <ClCompile Include="..\..\src\ft2_scopes.c" /> <ClCompile Include="..\..\src\ft2_scrollbars.c" /> <ClCompile Include="..\..\src\ft2_sysreqs.c" /> @@ -417,6 +418,7 @@ <ClInclude Include="..\..\src\ft2_sample_ed.h" /> <ClInclude Include="..\..\src\ft2_sample_loader.h" /> <ClInclude Include="..\..\src\ft2_sample_saver.h" /> + <ClInclude Include="..\..\src\ft2_scopedraw.h" /> <ClInclude Include="..\..\src\ft2_scopes.h" /> <ClInclude Include="..\..\src\ft2_scrollbars.h" /> <ClInclude Include="..\..\src\ft2_sysreqs.h" /> diff --git a/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters b/vs2019_project/ft2-clone/ft2-clone.vcxproj.filters @@ -69,6 +69,7 @@ <Filter>rtmidi</Filter> </ClCompile> <ClCompile Include="..\..\src\ft2_palette.c" /> + <ClCompile Include="..\..\src\ft2_scopedraw.c" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\src\ft2_audio.h"> @@ -197,6 +198,9 @@ <ClInclude Include="..\..\src\rtmidi\rtmidi_c.h"> <Filter>rtmidi</Filter> </ClInclude> + <ClInclude Include="..\..\src\ft2_scopedraw.h"> + <Filter>headers</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Filter Include="headers">