ref: 8eb89a1cfaf049ba6d97626ae4e749fb1c328770
parent: 506d1b78eb878807fbc889cad6c14de881d7f063
author: Olav Sørensen <[email protected]>
date: Wed Jan 15 08:38:25 EST 2020
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.
--- /dev/null
+++ b/make-linux-nomidi.sh
@@ -1,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\'.
--- a/make-linux.sh
+++ b/make-linux.sh
@@ -7,7 +7,7 @@
# 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
--- a/make-macos.sh
+++ b/make-macos.sh
@@ -8,7 +8,7 @@
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
--- a/src/ft2_audio.c
+++ b/src/ft2_audio.c
@@ -168,10 +168,8 @@
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 @@
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 @@
b = pmpLeft;
mixAudio(stream, b, pmpChannels);
- stream += (b * pmpCountDiv);
+ stream += b * pmpCountDiv;
a -= b;
pmpLeft -= b;
@@ -1133,14 +1130,15 @@
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
@@ -1147,10 +1145,8 @@
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 @@
// 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 @@
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;
--- a/src/ft2_config.c
+++ b/src/ft2_config.c
@@ -269,6 +269,7 @@
audio.currOutputDevice = getAudioOutputDeviceFromConfig();
audio.currInputDevice = getAudioInputDeviceFromConfig();
+#ifdef HAS_MIDI
if (midi.initThreadDone)
{
setMidiInputDeviceFromConfig();
@@ -275,6 +276,7 @@
if (editor.ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT)
drawMidiInputList();
}
+#endif
if (editor.configFileLocation == NULL)
{
@@ -388,7 +390,10 @@
}
saveAudioDevicesToConfig(audio.currOutputDevice, audio.currInputDevice);
+
+#ifdef HAS_MIDI
saveMidiInputDeviceToConfig();
+#endif
out = UNICHAR_FOPEN(editor.configFileLocation, "wb");
if (out == NULL)
@@ -791,7 +796,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
showConfigScreen();
}
+#ifdef HAS_MIDI
void rbConfigMidiInput(void)
{
checkRadioButton(RB_CONFIG_MIDI_INPUT);
@@ -1551,6 +1566,7 @@
hideConfigScreen();
showConfigScreen();
}
+#endif
void rbConfigSbs512(void)
{
@@ -2022,7 +2038,14 @@
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)
--- a/src/ft2_config.h
+++ b/src/ft2_config.h
@@ -197,7 +197,9 @@
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);
--- a/src/ft2_edit.c
+++ b/src/ft2_edit.c
@@ -438,7 +438,13 @@
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 @@
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)
{
--- a/src/ft2_events.c
+++ b/src/ft2_events.c
@@ -105,6 +105,7 @@
void handleEvents(void)
{
+#ifdef HAS_MIDI
// called after MIDI has been initialized
if (midi.rescanDevicesFlag)
{
@@ -114,6 +115,7 @@
if (editor.ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT)
drawMidiInputList();
}
+#endif
if (editor.trimThreadWasDone)
{
@@ -396,7 +398,6 @@
static void handleInput(void)
{
char *inputText;
- uint8_t vibDepth;
uint32_t eventType;
SDL_Event event;
SDL_Keycode key;
@@ -472,8 +473,10 @@
}
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 @@
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
}
--- 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...
--- a/src/ft2_keyboard.c
+++ b/src/ft2_keyboard.c
@@ -1186,6 +1186,7 @@
return true;
}
+#ifdef HAS_MIDI
else if (keyb.leftCtrlPressed)
{
editor.currConfigScreen = 3;
@@ -1194,6 +1195,7 @@
return true;
}
+#endif
break;
case SDLK_5:
--- 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 @@
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 @@
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 @@
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 @@
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 @@
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
--- 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 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 @@
return true;
}
+
+#else
+typedef int make_iso_compilers_happy; // kludge: prevent warning about empty .c file if HAS_MIDI is not defined
+#endif
--- 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 sbMidiInputSetPos(uint32_t pos);
bool testMidiInputDeviceListMouseDown(void);
int32_t SDLCALL initMidiFunc(void *ptr);
+
+#endif
--- a/src/ft2_module_loader.c
+++ b/src/ft2_module_loader.c
@@ -2278,8 +2278,11 @@
editor.currVolEnvPoint = 0;
editor.currPanEnvPoint = 0;
+
+#ifdef HAS_MIDI
midi.currMIDIVibDepth = 0;
midi.currMIDIPitch = 0;
+#endif
memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab));
--- a/src/ft2_mouse.c
+++ b/src/ft2_mouse.c
@@ -477,6 +477,7 @@
directionUp ? scrollAudInputDevListUp() : scrollAudInputDevListDown();
}
}
+#ifdef HAS_MIDI
else if (editor.currConfigScreen == CONFIG_SCREEN_MIDI_INPUT)
{
// midi input device selector
@@ -483,6 +484,7 @@
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 @@
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)
--- a/src/ft2_palette.c
+++ b/src/ft2_palette.c
@@ -20,7 +20,7 @@
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
--- a/src/ft2_pushbuttons.c
+++ b/src/ft2_pushbuttons.c
@@ -345,10 +345,12 @@
{ 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
--- a/src/ft2_pushbuttons.h
+++ b/src/ft2_pushbuttons.h
@@ -290,9 +290,11 @@
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,
--- a/src/ft2_radiobuttons.c
+++ b/src/ft2_radiobuttons.c
@@ -65,7 +65,10 @@
{ 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 ------
--- a/src/ft2_radiobuttons.h
+++ b/src/ft2_radiobuttons.h
@@ -38,7 +38,10 @@
RB_CONFIG_IO_DEVICES,
RB_CONFIG_LAYOUT,
RB_CONFIG_MISCELLANEOUS,
+
+#ifdef HAS_MIDI
RB_CONFIG_MIDI_INPUT,
+#endif
// CONFIG AUDIO
--- a/src/ft2_replayer.c
+++ b/src/ft2_replayer.c
@@ -1452,7 +1452,11 @@
}
// *** 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 @@
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 @@
else
{
ch->finalPeriod = ch->outPeriod;
+
+#ifdef HAS_MIDI
if (midi.enable)
{
ch->finalPeriod -= ch->midiPitch;
ch->status |= IS_Period;
}
+#endif
}
}
@@ -2879,8 +2887,10 @@
if (songWasPlaying)
editor.pattPos = song.pattPos;
+#ifdef HAS_MIDI
midi.currMIDIVibDepth = 0;
midi.currMIDIPitch = 0;
+#endif
memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab));
--- 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
--- /dev/null
+++ b/src/ft2_scopedraw.c
@@ -1,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
+};
--- /dev/null
+++ b/src/ft2_scopedraw.h
@@ -1,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
--- 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 @@
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 @@
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 @@
// 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 @@
}
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 @@
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 @@
// 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 @@
// update next tick time
timeNext64 += scopeTimeLen;
-
timeNext64Frac += scopeTimeLenFrac;
- if (timeNext64Frac >= (1ULL << 32))
+ if (timeNext64Frac > 0xFFFFFFFF)
{
- timeNext64++;
timeNext64Frac &= 0xFFFFFFFF;
+ timeNext64++;
}
}
@@ -872,11 +681,9 @@
// 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)
--- a/src/ft2_scopes.h
+++ b/src/ft2_scopes.h
@@ -13,6 +13,19 @@
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;
--- a/src/ft2_scrollbars.c
+++ b/src/ft2_scrollbars.c
@@ -90,9 +90,11 @@
//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 @@
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);
--- a/src/ft2_scrollbars.h
+++ b/src/ft2_scrollbars.h
@@ -45,8 +45,10 @@
// Config Miscellaneous
SB_MIDI_SENS,
+#ifdef HAS_MIDI
// Config Midi
SB_MIDI_INPUT_SCROLL,
+#endif
// Disk Op.
SB_DISKOP_LIST,
--- a/src/ft2_video.c
+++ b/src/ft2_video.c
@@ -76,9 +76,6 @@
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 @@
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 @@
// 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 @@
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 @@
}
// update next frame time
-
timeNext64 += video.vblankTimeLen;
-
timeNext64Frac += video.vblankTimeLenFrac;
- if (timeNext64Frac >= (1ULL << 32))
+ if (timeNext64Frac > 0xFFFFFFFF)
{
timeNext64Frac &= 0xFFFFFFFF;
timeNext64++;
--- 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" />
--- 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">
@@ -196,6 +197,9 @@
</ClInclude>
<ClInclude Include="..\..\src\rtmidi\rtmidi_c.h">
<Filter>rtmidi</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\src\ft2_scopedraw.h">
+ <Filter>headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>