Merge branch 'tildearrow:master' into master

This commit is contained in:
DevEd 2023-10-02 01:07:35 -04:00 committed by GitHub
commit ac85732ef2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 602 additions and 211 deletions

View file

@ -18,7 +18,6 @@
*/
#include <string.h>
#include <vector>
#include "../ta-log.h"
#include "pa.h"
#ifdef _WIN32

View file

@ -18,7 +18,6 @@
*/
#include <string.h>
#include <vector>
#include "../ta-log.h"
#include "sdlAudio.h"

View file

@ -22,7 +22,7 @@
#include "../ta-utils.h"
#include <memory>
#include "../fixedQueue.h"
#include <vector>
#include "../pch.h"
struct SampleRateChangeEvent {
double rate;

View file

@ -20,7 +20,7 @@
#ifndef _BASEUTILS_H
#define _BASEUTILS_H
#include <string>
#include "pch.h"
std::string taEncodeBase64(const std::string& data);
std::string taDecodeBase64(const char* str);

View file

@ -21,8 +21,6 @@
#define _DIVCONFIG_H
#include "../ta-utils.h"
#include <map>
#include <vector>
#include <initializer_list>
class DivConfig {

View file

@ -22,7 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "../pch.h"
#include "config.h"
#include "chipUtils.h"

View file

@ -30,13 +30,9 @@
#include "cmdStream.h"
#include "../audio/taAudio.h"
#include "blip_buf.h"
#include <atomic>
#include <functional>
#include <initializer_list>
#include <thread>
#include <mutex>
#include <map>
#include <unordered_map>
#include "../fixedQueue.h"
class DivWorkPool;
@ -56,10 +52,10 @@ class DivWorkPool;
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
#define DIV_UNSTABLE
//#define DIV_UNSTABLE
#define DIV_VERSION "0.6pre16"
#define DIV_ENGINE_VERSION 178
#define DIV_VERSION "0.6"
#define DIV_ENGINE_VERSION 181
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02

View file

@ -22,7 +22,7 @@
#include "song.h"
#include <initializer_list>
#include <vector>
#include "../pch.h"
class DivEngine;

View file

@ -464,6 +464,13 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth,
accum/=channels;
sample->data8[i]=accum;
}
if (bigEndian) {
for (unsigned int i=0; (i+1)<samples; i+=2) {
sample->data8[i]^=sample->data8[i^1];
sample->data8[i^1]^=sample->data8[i];
sample->data8[i]^=sample->data8[i^1];
}
}
} else {
memcpy(sample->getCurBuf(),buf,len);
}

View file

@ -22,7 +22,7 @@
#include "safeWriter.h"
#include "dataErrors.h"
#include "../ta-utils.h"
#include <vector>
#include "../pch.h"
struct DivSong;

View file

@ -18,7 +18,7 @@
*/
#include "safeReader.h"
#include <vector>
#include "../pch.h"
struct DivPattern {
String name;

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define CHIP_FREQBASE (is219?74448896:12582912)
@ -246,10 +245,10 @@ void DivPlatformC140::tick(bool sysTick) {
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen && s->isLoopable()) {
if (is219) {
loop=MIN(start+(s->loopStart>>1),65535);
end=MIN(start+(s->loopEnd>>1)-1,65535);
end=MIN(start+(s->loopEnd>>1),65535);
} else {
loop=MIN(start+s->loopStart,65535);
end=MIN(start+s->loopEnd-1,65535);
loop=MIN(start+s->loopStart+1,65535);
end=MIN(start+s->loopEnd+1,65535);
}
} else if (chan[i].noise && is219) {
loop=0;
@ -576,7 +575,7 @@ void DivPlatformC140::renderSamples(int sysID) {
}
if (is219) { // C219 (8-bit)
unsigned int length=s->length8;
unsigned int length=s->length8+4;
// fit sample size to single bank size
if (length>131072) {
length=131072;
@ -595,27 +594,39 @@ void DivPlatformC140::renderSamples(int sysID) {
logW("out of C219 memory for sample %d!",i);
}
if (s->depth==DIV_SAMPLE_DEPTH_C219) {
unsigned char next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i++) {
if (i>=s->lengthC219) {
sampleMem[(memPos+i)^1]=0;
} else {
sampleMem[(memPos+i)^1]=s->dataC219[i];
if (sPos<s->lengthC219) {
next=s->dataC219[sPos++];
if (s->isLoopable()) {
if ((int)sPos>=s->loopEnd) {
sPos=s->loopStart;
}
}
}
sampleMem[(memPos+i)^1]=next;
}
} else {
signed char next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i++) {
if (i>=s->length8) {
sampleMem[(memPos+i)^1]=0;
} else {
sampleMem[(memPos+i)^1]=s->data8[i];
if (sPos<s->length8) {
next=s->data8[sPos++];
if (s->isLoopable()) {
if ((int)sPos>=s->loopEnd) {
sPos=s->loopStart;
}
}
}
sampleMem[(memPos+i)^1]=next;
}
}
sampleOff[i]=memPos>>1;
sampleLoaded[i]=true;
memPos+=length;
} else { // C140 (16-bit)
unsigned int length=s->length16;
unsigned int length=s->length16+4;
// fit sample size to single bank size
if (length>(131072)) {
length=131072;
@ -642,7 +653,20 @@ void DivPlatformC140::renderSamples(int sysID) {
sampleMem[1+i+memPos]=c140Mu;
}
} else {
memcpy(sampleMem+memPos,s->data16,length);
short next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i+=2) {
if (sPos<s->samples) {
next=s->data16[sPos++];
if (s->isLoopable()) {
if ((int)sPos>=s->loopEnd) {
sPos=s->loopStart;
}
}
}
sampleMem[memPos+i]=((unsigned short)next);
sampleMem[memPos+i+1]=((unsigned short)next)>>8;
}
}
sampleOff[i]=memPos>>1;
sampleLoaded[i]=true;

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define PITCH_OFFSET ((double)(16*2048*(chanMax+1)))
#define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))

View file

@ -431,7 +431,7 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) {
}
unsigned short DivPlatformK007232::getPan(int ch) {
return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4);
return stereo?(((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4)):0;
}
DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) {

View file

@ -185,7 +185,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
chan[c.chan].std.release();
break;
case DIV_CMD_VOLUME: {
chan[c.chan].vol=c.value;
chan[c.chan].vol=MIN(8,c.value);
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}

View file

@ -201,7 +201,7 @@ void DivPlatformNamcoWSG::tick(bool sysTick) {
if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
}
if (chan[i].std.duty.had && i>=4) {
if (chan[i].std.duty.had) {
chan[i].noise=chan[i].std.duty.val;
chan[i].freqChanged=true;
}
@ -418,6 +418,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
}
case DIV_CMD_STD_NOISE_MODE:
chan[c.chan].noise=c.value;
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);

View file

@ -23,7 +23,6 @@
#include "../dispatch.h"
#include "../../fixedQueue.h"
#include <thread>
#include <mutex>
#include <condition_variable>
class DivPlatformPCSpeaker: public DivDispatch {

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define CHIP_DIVIDER (1248*2)
#define QS_NOTE_FREQUENCY(x) parent->calcBaseFreq(440,4096,(x)-3,false)

View file

@ -104,7 +104,7 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle
if (!voice->muted)
{
// fetch 12 bit sample
signed short s1 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | voice->addr] & ~0xf;
signed short s1 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | (voice->addr & 0xffff)] & ~0xf;
signed short s2 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | ((voice->addr + 1) & 0xffff)] & ~0xf;
if (voice->compressed)
{
@ -171,7 +171,7 @@ void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle
else
{
// fetch 8 bit sample
signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | (voice->addr^1)];
signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | ((voice->addr^1) & 0x1ffff)];
signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | (((voice->addr + 1) & 0x1ffff)^1)];
if (voice->compressed)
{

View file

@ -231,7 +231,7 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
buf[0][h]=os;
for (int i=0; i<3; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767);
}
for (int i=3; i<6; i++) {
@ -282,7 +282,8 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
for (int i=0; i<3; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767);
}
for (int i=3; i<6; i++) {

View file

@ -402,7 +402,7 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767);
}
ssge->get_last_out(ssgOut);
@ -471,7 +471,8 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) {
buf[1][h]=os[1];
for (int i=0; i<6; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767);
}
ssge->get_last_out(ssgOut);

View file

@ -333,7 +333,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[bchOffs[i]]<<1,-32768,32767);
}
ssge->get_last_out(ssgOut);
@ -404,7 +404,8 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
buf[1][h]=os[1];
for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767);
}
ssge->get_last_out(ssgOut);

View file

@ -401,7 +401,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767);
}
ssge->get_last_out(ssgOut);
@ -471,7 +471,8 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1;
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767);
}
ssge->get_last_out(ssgOut);

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define CHIP_FREQBASE 25165824

View file

@ -20,7 +20,7 @@
#ifndef _SONG_H
#define _SONG_H
#include <stdio.h>
#include <vector>
#include "../pch.h"
#include "defines.h"
#include "../ta-utils.h"

View file

@ -1181,7 +1181,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef(
"WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false, 1U<<DIV_SAMPLE_DEPTH_8BIT,
"developed by the makers of the Game Boy and the Virtual Boy...",
{"Wave", "Wave/PCM", "Wave", "Wave/Noise"},
{"Wave", "Wave/PCM", "Wave/Sweep", "Wave/Noise"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE},
{DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN},
@ -1649,7 +1649,7 @@ void DivEngine::registerSystems() {
{0x1e, {DIV_CMD_SU_SYNC_PERIOD_LOW, "1Exx: Set phase reset period low byte"}},
{0x1f, {DIV_CMD_SU_SYNC_PERIOD_HIGH, "1Fxx: Set phase reset period high byte"}},
{0x20, {DIV_CMD_SU_SWEEP_ENABLE, "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)", constVal<0>, effectVal}},
{0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}},
{0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direction is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}},
{0x22, {DIV_CMD_SU_SWEEP_ENABLE, "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)", constVal<2>, effectVal}},
};
const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>);
@ -1708,6 +1708,10 @@ void DivEngine::registerSystems() {
EffectHandlerMap namcoEffectHandlerMap={
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}},
};
EffectHandlerMap namcoC30EffectHandlerMap={
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}},
{0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}},
};
@ -1741,7 +1745,7 @@ void DivEngine::registerSystems() {
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
{DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO},
{},
namcoEffectHandlerMap
namcoC30EffectHandlerMap
);
sysDefs[DIV_SYSTEM_MSM5232]=new DivSysDef(

View file

@ -1747,13 +1747,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (!hasRFC1) {
hasRFC1=disCont[i].dispatch->chipClock;
isSecond[i]=true;
CHIP_VOL(16,1.6);
CHIP_VOL(16,0.8);
willExport[i]=true;
writeRF5C68[1]=disCont[i].dispatch;
}
} else if (!hasRFC) {
hasRFC=disCont[i].dispatch->chipClock;
CHIP_VOL(5,1.6);
CHIP_VOL(5,1.1);
willExport[i]=true;
writeRF5C68[0]=disCont[i].dispatch;
}
@ -2418,8 +2418,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
}
while (!done) {
if (loopPos==-1) {
if (loopOrder==curOrder && loopRow==curRow && ticks==1) {
writeLoop=true;
if (loopOrder==curOrder && loopRow==curRow) {
if ((ticks-((tempoAccum+curSubSong->virtualTempoN)/curSubSong->virtualTempoD))<=0) {
writeLoop=true;
}
}
}
songTick++;

View file

@ -106,7 +106,6 @@ void DivEngine::runExportThread() {
if (sfWrap.doClose()!=0) {
logE("could not close audio file!");
}
exporting=false;
if (initAudioBackend()) {
for (int i=0; i<song.systemLen; i++) {
@ -118,6 +117,7 @@ void DivEngine::runExportThread() {
}
}
logI("done!");
exporting=false;
break;
}
case DIV_EXPORT_MODE_MANY_SYS: {
@ -217,7 +217,6 @@ void DivEngine::runExportThread() {
logE("could not close audio file!");
}
}
exporting=false;
if (initAudioBackend()) {
for (int i=0; i<song.systemLen; i++) {
@ -229,6 +228,7 @@ void DivEngine::runExportThread() {
}
}
logI("done!");
exporting=false;
break;
}
case DIV_EXPORT_MODE_MANY_CHAN: {
@ -336,7 +336,6 @@ void DivEngine::runExportThread() {
if (stopExport) break;
}
exporting=false;
delete[] outBuf[0];
delete[] outBuf[1];
@ -359,6 +358,7 @@ void DivEngine::runExportThread() {
}
}
logI("done!");
exporting=false;
break;
}
}

View file

@ -21,7 +21,6 @@
#define _WORKPOOL_H
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>
#include <future>

View file

@ -101,11 +101,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop() {
template <typename T, size_t items> bool FixedQueue<T,items>::push(const T& item) {
if (writePos==(readPos-1)) {
logW("queue overflow!");
//logW("queue overflow!");
return false;
}
if (writePos==items-1 && readPos==0) {
logW("queue overflow!");
//logW("queue overflow!");
return false;
}
data[writePos]=item;
@ -121,11 +121,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop_front() {
template <typename T, size_t items> bool FixedQueue<T,items>::push_back(const T& item) {
if (writePos==(readPos-1)) {
logW("queue overflow!");
//logW("queue overflow!");
return false;
}
if (writePos==items-1 && readPos==0) {
logW("queue overflow!");
//logW("queue overflow!");
return false;
}
data[writePos]=item;
@ -145,11 +145,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop_back() {
template <typename T, size_t items> bool FixedQueue<T,items>::push_front(const T& item) {
if (readPos==(writePos+1)) {
logW("stack overflow!");
//logW("stack overflow!");
return false;
}
if (readPos==0 && writePos==items-1) {
logW("stack overflow!");
//logW("stack overflow!");
return false;
}
if (readPos>0) {

View file

@ -30,9 +30,6 @@ const char* aboutLine[]={
"the biggest multi-system chiptune tracker!",
"featuring DefleMask song compatibility.",
"",
"this is a version released during The Freeze.",
"please report any issues you find!",
"",
"> CREDITS <",
"",
"-- program --",
@ -57,20 +54,21 @@ const char* aboutLine[]={
"Raijin",
"",
"-- documentation --",
"tildearrow",
"freq-mod",
"nicco1690",
"DeMOSic",
"brickblock369",
"cam900",
"host12prog",
"WindowxDeveloper",
"polluks",
"DeMOSic",
"Electric Keet",
"freq-mod",
"host12prog",
"Lunathir",
"nicco1690",
"tildearrow",
"",
"-- demo songs --",
"0x5066",
"Abstract 64",
"ActualNK358",
"airconmanws",
"akumanatt",
"AmigaX",
"AURORA*FIELDS",
@ -123,10 +121,12 @@ const char* aboutLine[]={
"psxdominator",
"Raijin",
"railzen7",
"RevvoBolt",
"SnugglyBun",
"SuperJet Spade",
"SwapXFO",
"TakuikaNinja",
"tapekeep",
"TCORPStudios",
"Teuthida",
"ThaCuber",

View file

@ -357,7 +357,7 @@ void FurnaceGUI::drawChanOsc() {
} else {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f));
float availY=ImGui::GetContentRegionAvail().y;
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) {
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders|ImGuiTableFlags_NoClip)) {
std::vector<DivDispatchOscBuffer*> oscBufs;
std::vector<ChanOscStatus*> oscFFTs;
std::vector<int> oscChans;

View file

@ -584,6 +584,10 @@ void FurnaceGUI::drawMobileControls() {
if (ImGui::Button("Stats")) {
statsOpen=!statsOpen;
}
ImGui::SameLine();
if (ImGui::Button("Grooves")) {
groovesOpen=!groovesOpen;
}
if (ImGui::Button("Compat Flags")) {
compatFlagsOpen=!compatFlagsOpen;
}

View file

@ -1,7 +1,7 @@
#include "../ta-utils.h"
#include "imgui.h"
#include <functional>
#include <vector>
#include "../pch.h"
#if defined(_WIN64) || defined(__APPLE__)
#define USE_NFD

View file

@ -670,31 +670,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.insMode)) {
snprintf(tempID,1024,"%.2X",i.ins);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("II1",tempID)) {
for (int j=0; j<256; j++) {
snprintf(tempID,1024,"%.2X",j);
if (ImGui::Selectable(tempID,i.ins==j)) {
i.ins=j;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##II1",ImGuiDataType_U8,&i.ins,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.insMode)) {
snprintf(tempID,1024,"%.2X",i.insMax);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("II2",tempID)) {
for (int j=0; j<256; j++) {
snprintf(tempID,1024,"%.2X",j);
if (ImGui::Selectable(tempID,i.insMax==j)) {
i.insMax=j;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##II2",ImGuiDataType_U8,&i.insMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextRow();
@ -706,31 +688,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.volMode)) {
snprintf(tempID,1024,"%.2X",i.vol);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("VV1",tempID)) {
for (int j=0; j<256; j++) {
snprintf(tempID,1024,"%.2X",j);
if (ImGui::Selectable(tempID,i.vol==j)) {
i.vol=j;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##VV1",ImGuiDataType_U8,&i.vol,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.volMode)) {
snprintf(tempID,1024,"%.2X",i.volMax);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("VV2",tempID)) {
for (int j=0; j<256; j++) {
snprintf(tempID,1024,"%.2X",j);
if (ImGui::Selectable(tempID,i.volMax==j)) {
i.volMax=j;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##VV2",ImGuiDataType_U8,&i.volMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
for (int j=0; j<i.effectCount; j++) {
@ -744,31 +708,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effect[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE1",tempID)) {
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effect[j]==k)) {
i.effect[j]=k;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##EE1",ImGuiDataType_U8,&i.effect[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE2",tempID)) {
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectMax[j]==k)) {
i.effectMax[j]=k;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##EE2",ImGuiDataType_U8,&i.effectMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextRow();
@ -780,31 +726,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectVal[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV1",tempID)) {
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectVal[j]==k)) {
i.effectVal[j]=k;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##EV1",ImGuiDataType_U8,&i.effectVal[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectValMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV2",tempID)) {
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectValMax[j]==k)) {
i.effectValMax[j]=k;
}
}
ImGui::EndCombo();
}
ImGui::InputScalar("##EV2",ImGuiDataType_U8,&i.effectValMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::PopID();

View file

@ -1274,6 +1274,7 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
} else {
if (e->getMaxVolumeChan(cursor.xCoarse)<16) {
curNibble=false;
if (pat->data[cursor.y][target]>e->getMaxVolumeChan(cursor.xCoarse)) pat->data[cursor.y][target]=e->getMaxVolumeChan(cursor.xCoarse);
editAdvance();
} else {
curNibble=!curNibble;
@ -3544,6 +3545,10 @@ bool FurnaceGUI::loop() {
break;
case SDL_DROPFILE:
if (ev.drop.file!=NULL) {
if (introPos<11.0) {
SDL_free(ev.drop.file);
break;
}
int sampleCountBefore=e->song.sampleLen;
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames);
DivWavetable* droppedWave=NULL;
@ -3579,6 +3584,9 @@ bool FurnaceGUI::loop() {
SDL_free(ev.drop.file);
}
break;
case SDL_USEREVENT:
// used for MIDI wake up
break;
case SDL_QUIT:
if (modified) {
showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT);
@ -3642,6 +3650,7 @@ bool FurnaceGUI::loop() {
while (true) {
midiLock.lock();
midiWakeUp=true;
if (midiQueue.empty()) {
midiLock.unlock();
break;
@ -3925,11 +3934,13 @@ bool FurnaceGUI::loop() {
int nextPlayOrder=0;
int nextOldRow=0;
e->getPlayPos(nextPlayOrder,nextOldRow);
oldRowChanged=false;
playOrder=nextPlayOrder;
if (followPattern) {
curOrder=playOrder;
}
if (e->isPlaying()) {
if (oldRow!=nextOldRow) oldRowChanged=true;
oldRow=nextOldRow;
}
@ -4535,6 +4546,7 @@ bool FurnaceGUI::loop() {
MEASURE(readOsc,readOsc());
MEASURE(osc,drawOsc());
MEASURE(chanOsc,drawChanOsc());
MEASURE(grooves,drawGrooves());
MEASURE(regView,drawRegView());
} else {
globalWinFlags=0;
@ -5863,8 +5875,6 @@ bool FurnaceGUI::loop() {
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
pendingRawSampleChannels=1;
}
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
pendingRawSampleBigEndian=false;
}
@ -5891,6 +5901,10 @@ bool FurnaceGUI::loop() {
ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles);
}
if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_8BIT) {
ImGui::Checkbox("Swap words",&pendingRawSampleBigEndian);
}
if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) {
ImGui::Text("Encoding:");
ImGui::Indent();
@ -6722,11 +6736,20 @@ bool FurnaceGUI::init() {
firstFrame=true;
// TODO: MIDI mapping time!
userEvents=SDL_RegisterEvents(1);
e->setMidiCallback([this](const TAMidiMessage& msg) -> int {
if (introPos<11.0) return -2;
midiLock.lock();
midiQueue.push(msg);
if (userEvents!=0xffffffff && midiWakeUp) {
midiWakeUp=false;
userEvent.user.type=userEvents;
userEvent.user.code=0;
userEvent.user.data1=NULL;
userEvent.user.data2=NULL;
SDL_PushEvent(&userEvent);
}
midiLock.unlock();
e->setMidiBaseChan(cursor.xCoarse);
if (msg.type==TA_MIDI_SYSEX) return -2;
@ -7006,6 +7029,7 @@ FurnaceGUI::FurnaceGUI():
displayEditString(false),
mobileEdit(false),
killGraphics(false),
midiWakeUp(true),
audioEngineChanged(false),
settingsChanged(false),
debugFFT(false),
@ -7019,6 +7043,8 @@ FurnaceGUI::FurnaceGUI():
mobileEditPage(0),
wheelCalmDown(0),
shallDetectScale(0),
cpuCores(0),
userEvents(0xffffffff),
mobileMenuPos(0.0f),
autoButtonSize(0.0f),
mobileEditAnim(0.0f),
@ -7105,6 +7131,8 @@ FurnaceGUI::FurnaceGUI():
exitDisabledTimer(0),
soloTimeout(0.0f),
exportFadeOut(5.0),
newSongFirstFrame(false),
oldRowChanged(false),
editControlsOpen(true),
ordersOpen(true),
insListOpen(true),

View file

@ -28,12 +28,10 @@
#include <SDL.h>
#include <fftw3.h>
#include <initializer_list>
#include <map>
#include <future>
#include <memory>
#include <mutex>
#include <tuple>
#include <vector>
#include "../pch.h"
#include "fileDialog.h"
@ -1347,6 +1345,7 @@ class FurnaceGUI {
bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString;
bool mobileEdit;
bool killGraphics;
bool midiWakeUp;
bool audioEngineChanged, settingsChanged, debugFFT;
bool willExport[DIV_MAX_CHIPS];
int vgmExportVersion;
@ -1360,6 +1359,7 @@ class FurnaceGUI {
int wheelCalmDown;
int shallDetectScale;
int cpuCores;
unsigned int userEvents;
float mobileMenuPos, autoButtonSize, mobileEditAnim;
ImVec2 mobileEditButtonPos, mobileEditButtonSize;
const int* curSysSection;
@ -1373,6 +1373,7 @@ class FurnaceGUI {
void* fmPreviewOPZ;
void* fmPreviewOPZInterface;
String* editString;
SDL_Event userEvent;
String pendingRawSample;
int pendingRawSampleDepth, pendingRawSampleChannels;
@ -1818,7 +1819,7 @@ class FurnaceGUI {
double exportFadeOut;
bool newSongFirstFrame;
bool newSongFirstFrame, oldRowChanged;
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;

View file

@ -120,8 +120,8 @@ const int vgmVersions[7]={
// name, icon, letter icon
const char* insTypes[DIV_INS_MAX+1][3]={
{"SN76489/Sega PSG",ICON_FA_AREA_CHART,ICON_FUR_INS_STD},
{"FM (OPN)",ICON_FA_BAR_CHART,ICON_FUR_INS_FM},
{"SN76489/Sega PSG",ICON_FA_BAR_CHART,ICON_FUR_INS_STD},
{"FM (OPN)",ICON_FA_AREA_CHART,ICON_FUR_INS_FM},
{"Game Boy",ICON_FA_GAMEPAD,ICON_FUR_INS_GB},
{"C64",ICON_FA_KEYBOARD_O,ICON_FUR_INS_C64},
{"Generic Sample",ICON_FA_VOLUME_UP,ICON_FUR_INS_AMIGA},

View file

@ -377,11 +377,14 @@ void FurnaceGUI::drawPattern() {
bool inhibitMenu=false;
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) {
cursor.y=oldRow;
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
selStart=cursor;
selEnd=cursor;
if (e->isPlaying() && followPattern) {
if (oldRowChanged || !e->isStepping()) {
if (e->isStepping()) pendingStepUpdate=1;
cursor.y=oldRow;
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
selStart=cursor;
selEnd=cursor;
}
}
}
demandX=0;

View file

@ -18,7 +18,7 @@
*/
#include "imgui.h"
#include <string>
#include "../pch.h"
void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f));

View file

@ -3093,6 +3093,7 @@ void FurnaceGUI::drawSettings() {
// "42 63" - enables all instrument types
// "4-bit FDS" - enables partial pitch linearity option
// "Power of the Chip" - enables options for multi-threaded audio
// "btcdbcb" - use modern UI padding
// "????" - enables stuff
CONFIG_SECTION("Cheat Codes") {
// SUBSECTION ENTER CODE:
@ -3131,6 +3132,14 @@ void FurnaceGUI::drawSettings() {
mmlString[30]="unlocked audio multi-threading options!";
settings.showPool=1;
}
if (checker==0x94222d83 && checker1==0x6600) {
mmlString[30]="enabled \"comfortable\" mode";
ImGuiStyle& sty=ImGui::GetStyle();
sty.FramePadding=ImVec2(20.0f*dpiScale,20.0f*dpiScale);
sty.ItemSpacing=ImVec2(10.0f*dpiScale,10.0f*dpiScale);
sty.ItemInnerSpacing=ImVec2(10.0f*dpiScale,10.0f*dpiScale);
settingsOpen=false;
}
mmlString[31]="";
}

View file

@ -273,7 +273,7 @@ void FurnaceGUI::drawTutorial() {
ImGui::TextWrapped(
"if you need help, you may:\n"
"- read the (incomplete) manual: https://github.com/tildearrow/furnace/blob/master/doc/README.md\n"
"- read the manual (a file called manual.pdf)\n"
"- ask for help in Discussions (https://github.com/tildearrow/furnace/discussions), the Furnace Discord (https://discord.gg/EfrwT2wq7z) or Furnace in Revolt (https://rvlt.gg/GRPS6tmc)"
);

View file

@ -19,7 +19,7 @@
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "pch.h"
#ifdef HAVE_SDL2
#include "SDL_events.h"
#endif

20
src/pch.cpp Normal file
View file

@ -0,0 +1,20 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2023 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "pch.h"

30
src/pch.h Normal file
View file

@ -0,0 +1,30 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2023 tildearrow and contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef FUR_PCH_H
#define FUR_PCH_H
#define _USE_MATH_DEFINES
#include <string>
#include <vector>
#include <mutex>
#include <map>
#include <unordered_map>
#endif

View file

@ -23,8 +23,8 @@
#include <stdarg.h>
#include <time.h>
#include <atomic>
#include <string>
#include <fmt/printf.h>
#include "pch.h"
#define LOGLEVEL_ERROR 0
#define LOGLEVEL_WARN 1

View file

@ -21,7 +21,7 @@
#define _TA_UTILS_H
#include <stdio.h>
#include <string.h>
#include <string>
#include "pch.h"
#ifdef _MSC_VER
#include <BaseTsd.h>