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:
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">