commit 007b8a42742ad0f220568db820b8d91a3c9ce2ec
parent ba70ad4ef096963531b39cfbf682d03a3e001358
Author: Olav Sørensen <olav.sorensen@live.no>
Date: Wed, 18 Mar 2020 11:34:32 +0100
Pushed v1.13 code
- Fixed crash when loading some very specific S3M modules
- Linux: Fixed CMakeLists.txt to work on Arch Linux
- Some other small miscellaneous fixes not worth of a mention
Diffstat:
12 files changed, 83 insertions(+), 113 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -5,23 +5,25 @@ project(ft2-clone)
find_package(SDL2 REQUIRED)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${ft2-clone_SOURCE_DIR}/release/other/")
-
file(GLOB ft2-clone_SRC
"${ft2-clone_SOURCE_DIR}/src/rtmidi/*.cpp"
"${ft2-clone_SOURCE_DIR}/src/*.c"
- "${ft2-clone_SOURCE_DIR}/src/gfxdata/*.c"
+ "${ft2-clone_SOURCE_DIR}/src/gfxdata/*.c"
)
-
add_executable(ft2-clone ${ft2-clone_SRC})
target_include_directories(ft2-clone SYSTEM
PRIVATE ${SDL2_INCLUDE_DIRS})
-target_link_libraries(ft2-clone
+if("${SDL2_LIBRARIES}" STREQUAL "")
+ message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
+ set(SDL2_LIBRARIES "SDL2::SDL2")
+endif()
+
+target_link_libraries(ft2-clone
PRIVATE m asound pthread ${SDL2_LIBRARIES})
target_compile_definitions(ft2-clone PRIVATE __LINUX_ALSA__)
-
install(TARGETS ft2-clone
- RUNTIME DESTINATION bin )
-\ No newline at end of file
+ RUNTIME DESTINATION bin )
diff --git a/LICENSE b/LICENSE
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2019-2020, Olav Sørensen
+Copyright (c) 2016-2020, Olav Sørensen
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/release/LICENSES.txt b/release/LICENSES.txt
@@ -2,7 +2,7 @@
---------------------- Source code (BSD 3-clause license) ----------------------
--------------------------------------------------------------------------------
-Copyright (c) 2016-2020, Olav Srensen
+Copyright (c) 2016-2020, Olav Sørensen
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -19,7 +19,7 @@ modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL OLAV SRENSEN BE LIABLE FOR ANY
+DISCLAIMED. IN NO EVENT SHALL OLAV SØRENSEN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -85,7 +85,7 @@ freely, subject to the following restrictions:
--------------------------------------------------------------------------------
-- Graphics, except program icon, MIDI logo and new FT2 logo: by Magnus Hgdahl -
+- Graphics, except program icon, MIDI logo and new FT2 logo: by Magnus Högdahl -
--------------------------------------------------------------------------------
Attribution-NonCommercial-ShareAlike 4.0 International
@@ -510,7 +510,7 @@ Section 8 -- Interpretation.
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
-will be considered the Licensor. The text of the Creative Commons
+will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
diff --git a/src/ft2_audio.h b/src/ft2_audio.h
@@ -33,7 +33,7 @@ struct audio_t
uint32_t freq;
uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
uint64_t tickTime64, tickTime64Frac;
- double dAudioLatencyMs, dSpeedValMul, dScopeFreqMul;
+ double dAudioLatencyMs, dSpeedValMul, dScopeFreqMul, dPianoDeltaMul;
SDL_AudioDeviceID dev;
uint32_t wantFreq, haveFreq, wantSamples, haveSamples, wantChannels, haveChannels;
} audio;
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.12"
+#define PROG_VER_STR "1.13"
// do NOT change these! It will only mess things up...
diff --git a/src/ft2_inst_ed.c b/src/ft2_inst_ed.c
@@ -1701,108 +1701,74 @@ bool testPianoKeysMouseDown(bool mouseButtonDown)
/* 8bitbubsy: This is my new version of FT2's buggy getNote().
** It's used to convert a channel's period into a piano key number.
+** Or in this case, a voice's frequency into a piano key number.
**
-** It's probably slower in "Amiga frequencies" mode, but at least it doesn't
-** have weird overflow/underflow patterns.
+** It's probably slower than the original version, but this one is
+** 100% accurate in all (quirky) situations.
**
** Warning: This function intentionally doesn't clamp the output value!
*/
-static int32_t getPianoKey(int32_t period, int32_t finetune, int32_t relativeTone, bool linearFrequencies)
+static int32_t getPianoKey(int32_t voiceDelta, int32_t finetune, int32_t relativeNote)
{
- int32_t note;
+ finetune >>= 3; // FT2 does this in the replayer internally (-128..127 -> -16..15)
- finetune >>= 3; // FT2 does this in the replayer internally
+ double dTmp = voiceDelta * audio.dPianoDeltaMul;
+ dTmp = (log2(dTmp) * 12.0) - (finetune * (1.0 / 16.0));
+ int32_t note = (int32_t)(dTmp + 0.5); // rounded
- if (linearFrequencies)
- {
- period = ((10 * 12 * 16 * 4) - period) - (finetune << 2);
- note = (period + (1 << 5)) >> 6; // rounded
- }
- else
- {
- double dNote = (log2(period * (1.0 / (1712.0 * 16.0))) * -12.0) - (finetune * (1.0 / 16.0));
- note = (int32_t)(dNote + 0.5); // rounded
- }
+ note -= relativeNote;
+ // "note" is now the raw piano key number, unaffected by finetune/relativeNote
- note -= relativeTone;
return note;
}
-void drawPiano(void) // draw piano in idle mode (jamming keys)
+void drawPiano(chSyncData_t *chSyncData)
{
- bool keyDown, newStatus[96];
- uint8_t key, octave;
+ bool newStatus[96];
int32_t note;
- stmTyp *ch;
memset(newStatus, 0, sizeof (newStatus));
// find active notes
if (editor.curInstr > 0)
{
- for (uint8_t i = 0; i < song.antChn; i++)
+ if (chSyncData != NULL) // song is playing, use replayer channel state
{
- ch = &stm[i];
- if (ch->instrNr == editor.curInstr && ch->envSustainActive)
+ syncedChannel_t *c = chSyncData->channels;
+ for (int32_t i = 0; i < song.antChn; i++, c++)
{
- note = getPianoKey(ch->finalPeriod, ch->fineTune, ch->relTonNr, linearFrqTab);
- if (note >= 0 && note <= 95)
- newStatus[note] = true;
+ if (c->instrNr == editor.curInstr && c->envSustainActive)
+ {
+ note = getPianoKey(c->voiceDelta, c->fineTune, c->relTonNr);
+ if (note >= 0 && note <= 95)
+ newStatus[note] = true;
+ }
}
}
- }
-
- // draw keys
- for (uint8_t i = 0; i < 96; i++)
- {
- keyDown = newStatus[i];
- if (pianoKeyStatus[i] ^ keyDown)
+ else // song is not playing (jamming from keyboard/MIDI)
{
- key = noteTab1[i];
- octave = noteTab2[i];
-
- if (keyIsBlackTab[key])
- drawBlackPianoKey(key, octave, keyDown);
- else
- drawWhitePianoKey(key, octave, keyDown);
-
- pianoKeyStatus[i] = keyDown;
- }
- }
-}
-
-void drawPianoReplayer(chSyncData_t *chSyncData) // draw piano with synced replayer state (song playing)
-{
- bool keyDown, newStatus[96];
- uint8_t key, octave;
- int32_t note;
- syncedChannel_t *ch;
-
- memset(newStatus, 0, sizeof (newStatus));
-
- // find active notes
- if (editor.curInstr > 0)
- {
- for (uint8_t i = 0; i < song.antChn; i++)
- {
- ch = &chSyncData->channels[i];
- if (ch->instrNr == editor.curInstr && ch->envSustainActive)
+ stmTyp *c = stm;
+ for (int32_t i = 0; i < song.antChn; i++, c++)
{
- note = getPianoKey(ch->finalPeriod, ch->fineTune, ch->relTonNr, linearFrqTab);
- if (note >= 0 && note <= 95)
- newStatus[note] = true;
+ if (c->instrNr == editor.curInstr && c->envSustainActive)
+ {
+ int32_t voiceDelta = getFrequenceValue(c->finalPeriod);
+ note = getPianoKey(voiceDelta, c->fineTune, c->relTonNr);
+ if (note >= 0 && note <= 95)
+ newStatus[note] = true;
+ }
}
}
}
// draw keys
- for (uint8_t i = 0; i < 96; i++)
+ for (int32_t i = 0; i < 96; i++)
{
- keyDown = newStatus[i];
+ bool keyDown = newStatus[i];
if (pianoKeyStatus[i] ^ keyDown)
{
- key = noteTab1[i];
- octave = noteTab2[i];
+ uint8_t key = noteTab1[i];
+ uint8_t octave = noteTab2[i];
if (keyIsBlackTab[key])
drawBlackPianoKey(key, octave, keyDown);
@@ -1839,10 +1805,10 @@ static void envelopeLine(int32_t nr, int16_t x1, int16_t y1, int16_t x2, int16_t
// get coefficients
dx = x2 - x1;
- ax = ABS(dx) * 2;
+ ax = ABS(dx) << 1;
sx = SGN(dx);
dy = y2 - y1;
- ay = ABS(dy) * 2;
+ ay = ABS(dy) << 1;
sy = SGN(dy);
x = x1;
y = y1;
@@ -1857,7 +1823,7 @@ static void envelopeLine(int32_t nr, int16_t x1, int16_t y1, int16_t x2, int16_t
// draw line
if (ax > ay)
{
- d = ay - (ax / 2);
+ d = ay - (ax >> 1);
while (true)
{
@@ -1886,7 +1852,7 @@ static void envelopeLine(int32_t nr, int16_t x1, int16_t y1, int16_t x2, int16_t
}
else
{
- d = ax - (ay / 2);
+ d = ax - (ay >> 1);
while (true)
{
diff --git a/src/ft2_inst_ed.h b/src/ft2_inst_ed.h
@@ -90,8 +90,7 @@ void cbVEnvLoop(void);
void cbPEnv(void);
void cbPEnvSus(void);
void cbPEnvLoop(void);
-void drawPiano(void);
-void drawPianoReplayer(chSyncData_t *chSyncData);
+void drawPiano(chSyncData_t *chSyncData);
bool testInstrVolEnvMouseDown(bool mouseButtonDown);
bool testInstrPanEnvMouseDown(bool mouseButtonDown);
bool testPianoKeysMouseDown(bool mouseButtonDown);
diff --git a/src/ft2_module_loader.c b/src/ft2_module_loader.c
@@ -2616,7 +2616,7 @@ static void setupLoadedModule(void)
showBottomScreen(); // redraw bottom screen (also redraws pattern editor)
if (editor.ui.instEditorShown)
- drawPiano(); // redraw piano now (since if playing = wait for next tick update)
+ drawPiano(NULL); // redraw piano now (since if playing = wait for next tick update)
removeSongModifiedFlag();
diff --git a/src/ft2_replayer.c b/src/ft2_replayer.c
@@ -26,7 +26,7 @@
*/
static bool bxxOverflow;
-static int32_t oldPeriod;
+static uint16_t oldPeriod;
static uint32_t oldRate, frequenceDivFactor, frequenceMulFactor;
static tonTyp nilPatternLine;
@@ -342,13 +342,17 @@ void calcReplayRate(int32_t rate) // 100% FT2-accurate routine, do not touch!
// for audio/video sync
audio.dSpeedValMul = (1.0 / rate) * editor.dPerfFreq;
+
+ uint32_t deltaBase = frequenceDivFactor / (1712 * 16); // exact 16.16 delta base for this audio rate
+ audio.dPianoDeltaMul = 1.0 / deltaBase; // for piano in Instr. Ed.
}
// 100% FT2-accurate routine, do not touch!
-uint32_t getFrequenceValue(int32_t period)
+uint32_t getFrequenceValue(uint16_t period)
{
uint8_t shift;
- int32_t index, indexQuotient, indexRemainder;
+ uint16_t index;
+ int32_t indexQuotient, indexRemainder;
uint32_t rate;
if (period == 0)
@@ -439,21 +443,17 @@ static void startTone(uint8_t ton, uint8_t effTyp, uint8_t eff, stmTyp *ch)
ch->oldPan = s->pan;
if (effTyp == 0x0E && (eff & 0xF0) == 0x50)
- ch->fineTune = ((eff & 0x0F) * 16) - 128; // result is now -128 .. 127
+ ch->fineTune = ((eff & 0x0F) << 4) - 128; // result is now -128..127
else
ch->fineTune = s->fine;
- if (ton > 0)
+ if (ton != 0)
{
- tmpTon = ((ton - 1) * 16) + (((ch->fineTune >> 3) + 16) & 0xFF);
- if (tmpTon < MAX_NOTES) // should always happen, but FT2 does this check
+ tmpTon = ((ton - 1) << 4) + (((ch->fineTune >> 3) + 16) & 0xFF);
+ if (tmpTon < MAX_NOTES)
{
assert(note2Period != NULL);
- ch->realPeriod = note2Period[tmpTon];
-
- ch->outPeriod = ch->realPeriod;
- ch->midiCurPeriod = ch->realPeriod;
- ch->midiPortaPeriod = ch->realPeriod;
+ ch->outPeriod = ch->realPeriod = note2Period[tmpTon];
}
}
@@ -2837,15 +2837,19 @@ void playTone(uint8_t stmm, uint8_t inst, uint8_t ton, int8_t vol, uint16_t midi
assert(stmm < MAX_VOICES && inst < MAX_INST && ton <= 97);
ch = &stm[stmm];
+ // FT2 bugfix: Don't play tone if certain requirements are not met
if (ton != 97)
{
- if (ton < 1 || ton > 96)
+ if (ton == 0 || ton > 96)
return;
- s = &ins->samp[ins->ta[ton-1] & 0x0F];
- if (s->pek == NULL || s->len == 0 || ton+s->relTon <= 0 || ton+s->relTon >= 12*10)
+ s = &ins->samp[ins->ta[ton-1] & 0xF];
+
+ int16_t newTon = (int16_t)ton + s->relTon;
+ if (s->pek == NULL || s->len == 0 || newTon <= 0 || newTon >= 12*10)
return;
}
+ // -------------------
lockAudio();
diff --git a/src/ft2_replayer.h b/src/ft2_replayer.h
@@ -201,8 +201,7 @@ typedef struct stmTyp_t
uint8_t portaUpSpeed, portaDownSpeed, retrigSpeed, retrigCnt, retrigVol;
uint8_t volKolVol, tonNr, envPPos, eVibPos, envVPos, realVol, oldVol, outVol;
uint8_t oldPan, outPan, finalPan;
- int16_t midiCurChannel, midiCurTone, midiCurVibDepth, midiCurPeriod, midiCurPitch;
- int16_t midiBend, midiPortaPeriod, midiPitch, realPeriod, envVIPValue, envPIPValue;
+ int16_t midiPitch, realPeriod, envVIPValue, envPIPValue;
uint16_t finalVol, outPeriod, finalPeriod, tonTyp, wantPeriod, portaSpeed;
uint16_t envVCnt, envVAmp, envPCnt, envPAmp, eVibAmp, eVibSweep;
uint16_t fadeOutAmp, fadeOutSpeed, midiVibDepth;
@@ -244,7 +243,7 @@ void fixSampleName(int16_t nr); // removes spaces from right side of ins/smp nam
void calcReplayRate(int32_t rate);
void resetOldRates(void);
void tuneSample(sampleTyp *s, int32_t midCFreq);
-uint32_t getFrequenceValue(int32_t period);
+uint32_t getFrequenceValue(uint16_t period);
bool allocateInstr(int16_t nr);
void freeInstr(int32_t nr);
diff --git a/src/ft2_scopes.c b/src/ft2_scopes.c
@@ -378,9 +378,10 @@ static void scopeTrigger(uint8_t ch, sampleTyp *s, int32_t playOffset)
/* Update live scope now.
** In theory it -can- be written to in the middle of a cached read,
- ** then the read thread writes its own non-updated cached copy back and
+ ** then the read thread writes its own non-updated cached copy back and
** the trigger never happens. So far I have never seen it happen,
- ** so it's probably very rare. Yes, this is not good coding... */
+ ** so it's probably very rare. Yes, this is not good coding...
+ */
*sc = tempState;
}
@@ -558,7 +559,7 @@ void handleScopesFromChQueue(chSyncData_t *chSyncData, uint8_t *scopeUpdateStatu
if (ch->voiceDelta != oldVoiceDelta)
{
oldVoiceDelta = ch->voiceDelta;
- oldSFrq = (int32_t)((oldVoiceDelta * audio.dScopeFreqMul) + 0.5); // rounded
+ oldSFrq = (int32_t)(((int32_t)oldVoiceDelta * audio.dScopeFreqMul) + 0.5); // rounded
}
sc->SFrq = oldSFrq;
diff --git a/src/ft2_video.c b/src/ft2_video.c
@@ -1108,7 +1108,7 @@ static void drawReplayerData(void)
if (editor.ui.instEditorShown)
{
if (chSyncEntry != NULL)
- drawPianoReplayer(chSyncEntry);
+ drawPiano(chSyncEntry);
}
}
@@ -1157,7 +1157,7 @@ static void drawReplayerData(void)
}
else if (editor.ui.instEditorShown)
{
- drawPiano();
+ drawPiano(NULL);
}
// handle pattern data updates