Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
46880634b4
|
|
@ -308,6 +308,7 @@ endif()
|
|||
|
||||
set(ENGINE_SOURCES
|
||||
src/log.cpp
|
||||
src/baseutils.cpp
|
||||
src/fileutils.cpp
|
||||
src/utfutils.cpp
|
||||
|
||||
|
|
@ -572,6 +573,7 @@ src/gui/guiConst.cpp
|
|||
src/gui/about.cpp
|
||||
src/gui/channels.cpp
|
||||
src/gui/chanOsc.cpp
|
||||
src/gui/clock.cpp
|
||||
src/gui/compatFlags.cpp
|
||||
src/gui/cursor.cpp
|
||||
src/gui/dataList.cpp
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Furnace Tracker
|
||||
# Furnace (chiptune tracker)
|
||||
|
||||

|
||||
|
||||
|
|
|
|||
BIN
demos/SeeingRed.fur
Normal file
BIN
demos/SeeingRed.fur
Normal file
Binary file not shown.
Binary file not shown.
BIN
demos/splashingwater.fur
Normal file
BIN
demos/splashingwater.fur
Normal file
Binary file not shown.
BIN
demos/watching_paint_dry.fur
Normal file
BIN
demos/watching_paint_dry.fur
Normal file
Binary file not shown.
BIN
instruments/other/TIA Bass Drum.fui
Normal file
BIN
instruments/other/TIA Bass Drum.fui
Normal file
Binary file not shown.
BIN
instruments/other/TIA Clap.fui
Normal file
BIN
instruments/other/TIA Clap.fui
Normal file
Binary file not shown.
BIN
instruments/other/TIA Hi-Hat Long.fui
Normal file
BIN
instruments/other/TIA Hi-Hat Long.fui
Normal file
Binary file not shown.
BIN
instruments/other/TIA Hi-Hat.fui
Normal file
BIN
instruments/other/TIA Hi-Hat.fui
Normal file
Binary file not shown.
BIN
instruments/other/TIA Snare Drum.fui
Normal file
BIN
instruments/other/TIA Snare Drum.fui
Normal file
Binary file not shown.
|
|
@ -3,7 +3,7 @@
|
|||
a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator.
|
||||
|
||||
sadly, this soundchip has only ever observed minimal success, and has remained rather obscure since.
|
||||
it is known for being used in the Covox Sound Master, which didn't sell well either.
|
||||
it is best known for being used in the Covox Sound Master, which didn't sell well either. It also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910.
|
||||
|
||||
emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player.
|
||||
|
||||
For 0.6pre1, Furnace can now support advanced YM2612 features that [Fractal](https://gitlab.com/Natsumi/Fractal-Sound) sound driver adds: two software-mixed PCM channels (variable pitch, sample offsets, max 13.7 khz rate) and CSM - ch3 special mode feature that can be abused to produce rudimentary speech synthesis.
|
||||
|
||||
# effects
|
||||
|
||||
- `10xy`: set LFO parameters.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 123: Furnace dev123
|
||||
- 122: Furnace dev122
|
||||
- 121: Furnace dev121
|
||||
- 120: Furnace dev120
|
||||
- 119: Furnace dev119
|
||||
|
|
@ -1096,7 +1098,11 @@ size | description
|
|||
| - 9: BRR (SNES)
|
||||
| - 10: VOX
|
||||
| - 16: 16-bit PCM
|
||||
3 | reserved
|
||||
1 | loop direction (>=123) or reserved
|
||||
| - 0: forward
|
||||
| - 0: backward
|
||||
| - 0: ping-pong
|
||||
2 | reserved
|
||||
4 | loop start
|
||||
| - -1 means no loop
|
||||
4 | loop end
|
||||
|
|
|
|||
89
src/baseutils.cpp
Normal file
89
src/baseutils.cpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 "baseutils.h"
|
||||
#include <string.h>
|
||||
|
||||
const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
std::string taEncodeBase64(const std::string& data) {
|
||||
std::string ret;
|
||||
|
||||
ret.reserve((2+data.size()*4)/3);
|
||||
|
||||
unsigned int groupOfThree=0;
|
||||
unsigned char pos=0;
|
||||
for (const char& i: data) {
|
||||
groupOfThree|=((unsigned char)i)<<((2-pos)<<3);
|
||||
if (++pos>=3) {
|
||||
pos=0;
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+=base64Table[(groupOfThree>>6)&63];
|
||||
ret+=base64Table[groupOfThree&63];
|
||||
groupOfThree=0;
|
||||
}
|
||||
}
|
||||
if (pos==2) {
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+=base64Table[(groupOfThree>>6)&63];
|
||||
ret+='=';
|
||||
} else if (pos==1) {
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+="==";
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string taDecodeBase64(const char* buf) {
|
||||
std::string data;
|
||||
|
||||
unsigned int groupOfThree=0;
|
||||
signed char pos=18;
|
||||
for (const char* i=buf; *i; i++) {
|
||||
unsigned char nextVal=0;
|
||||
if ((*i)=='/') {
|
||||
nextVal=63;
|
||||
} else if ((*i)=='+') {
|
||||
nextVal=62;
|
||||
} else if ((*i)>='0' && (*i)<='9') {
|
||||
nextVal=52+((*i)-'0');
|
||||
} else if ((*i)>='a' && (*i)<='z') {
|
||||
nextVal=26+((*i)-'a');
|
||||
} else if ((*i)>='A' && (*i)<='Z') {
|
||||
nextVal=((*i)-'A');
|
||||
} else {
|
||||
nextVal=0;
|
||||
}
|
||||
groupOfThree|=nextVal<<pos;
|
||||
pos-=6;
|
||||
if (pos<0) {
|
||||
pos=18;
|
||||
if ((groupOfThree>>16)&0xff) data+=(groupOfThree>>16)&0xff;
|
||||
if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff;
|
||||
if (groupOfThree&0xff) data+=groupOfThree&0xff;
|
||||
groupOfThree=0;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
28
src/baseutils.h
Normal file
28
src/baseutils.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 _BASEUTILS_H
|
||||
#define _BASEUTILS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string taEncodeBase64(const std::string& data);
|
||||
std::string taDecodeBase64(const char* str);
|
||||
|
||||
#endif
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "../ta-log.h"
|
||||
#include "../baseutils.h"
|
||||
#include "../fileutils.h"
|
||||
#include <fmt/printf.h>
|
||||
|
||||
|
|
@ -48,41 +49,9 @@ String DivConfig::toString() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
const char* base64Table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
String DivConfig::toBase64() {
|
||||
String data=toString();
|
||||
String ret;
|
||||
|
||||
ret.reserve((2+data.size()*4)/3);
|
||||
|
||||
unsigned int groupOfThree=0;
|
||||
unsigned char pos=0;
|
||||
for (char& i: data) {
|
||||
groupOfThree|=((unsigned char)i)<<((2-pos)<<3);
|
||||
if (++pos>=3) {
|
||||
pos=0;
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+=base64Table[(groupOfThree>>6)&63];
|
||||
ret+=base64Table[groupOfThree&63];
|
||||
groupOfThree=0;
|
||||
}
|
||||
}
|
||||
if (pos==2) {
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+=base64Table[(groupOfThree>>6)&63];
|
||||
ret+='=';
|
||||
} else if (pos==1) {
|
||||
ret+=base64Table[(groupOfThree>>18)&63];
|
||||
ret+=base64Table[(groupOfThree>>12)&63];
|
||||
ret+="==";
|
||||
}
|
||||
|
||||
logV("toBase64: %s",ret);
|
||||
|
||||
return ret;
|
||||
return taEncodeBase64(data);
|
||||
}
|
||||
|
||||
void DivConfig::parseLine(const char* line) {
|
||||
|
|
@ -143,38 +112,7 @@ bool DivConfig::loadFromMemory(const char* buf) {
|
|||
}
|
||||
|
||||
bool DivConfig::loadFromBase64(const char* buf) {
|
||||
String data;
|
||||
|
||||
unsigned int groupOfThree=0;
|
||||
signed char pos=18;
|
||||
for (const char* i=buf; *i; i++) {
|
||||
unsigned char nextVal=0;
|
||||
if ((*i)=='/') {
|
||||
nextVal=63;
|
||||
} else if ((*i)=='+') {
|
||||
nextVal=62;
|
||||
} else if ((*i)>='0' && (*i)<='9') {
|
||||
nextVal=52+((*i)-'0');
|
||||
} else if ((*i)>='a' && (*i)<='z') {
|
||||
nextVal=26+((*i)-'a');
|
||||
} else if ((*i)>='A' && (*i)<='Z') {
|
||||
nextVal=((*i)-'A');
|
||||
} else {
|
||||
nextVal=0;
|
||||
}
|
||||
groupOfThree|=nextVal<<pos;
|
||||
pos-=6;
|
||||
if (pos<0) {
|
||||
pos=18;
|
||||
if ((groupOfThree>>16)&0xff) data+=(groupOfThree>>16)&0xff;
|
||||
if ((groupOfThree>>8)&0xff) data+=(groupOfThree>>8)&0xff;
|
||||
if (groupOfThree&0xff) data+=groupOfThree&0xff;
|
||||
groupOfThree=0;
|
||||
}
|
||||
}
|
||||
|
||||
logV("fromBase64: %s",data);
|
||||
|
||||
String data=taDecodeBase64(buf);
|
||||
return loadFromMemory(data.c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1390,10 +1390,14 @@ String DivEngine::decodeSysDesc(String desc) {
|
|||
return newDesc.toBase64();
|
||||
}
|
||||
|
||||
void DivEngine::initSongWithDesc(const char* description) {
|
||||
void DivEngine::initSongWithDesc(const char* description, bool inBase64) {
|
||||
int chanCount=0;
|
||||
DivConfig c;
|
||||
c.loadFromBase64(description);
|
||||
if (inBase64) {
|
||||
c.loadFromBase64(description);
|
||||
} else {
|
||||
c.loadFromMemory(description);
|
||||
}
|
||||
int index=0;
|
||||
for (; index<32; index++) {
|
||||
song.system[index]=systemFromFileFur(c.getInt(fmt::sprintf("id%d",index),0));
|
||||
|
|
@ -1414,7 +1418,7 @@ void DivEngine::initSongWithDesc(const char* description) {
|
|||
song.systemLen=index;
|
||||
}
|
||||
|
||||
void DivEngine::createNew(const char* description, String sysName) {
|
||||
void DivEngine::createNew(const char* description, String sysName, bool inBase64) {
|
||||
quitDispatch();
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
|
|
@ -1422,7 +1426,7 @@ void DivEngine::createNew(const char* description, String sysName) {
|
|||
song=DivSong();
|
||||
changeSong(0);
|
||||
if (description!=NULL) {
|
||||
initSongWithDesc(description);
|
||||
initSongWithDesc(description,inBase64);
|
||||
}
|
||||
if (sysName=="") {
|
||||
song.systemName=getSongSystemLegacyName(song,!getConfInt("noMultiSystem",0));
|
||||
|
|
@ -2358,6 +2362,9 @@ void DivEngine::reset() {
|
|||
firstTick=false;
|
||||
shallStop=false;
|
||||
shallStopSched=false;
|
||||
pendingMetroTick=0;
|
||||
elapsedBars=0;
|
||||
elapsedBeats=0;
|
||||
nextSpeed=speed1;
|
||||
divider=60;
|
||||
if (curSubSong->customTempo) {
|
||||
|
|
@ -2548,6 +2555,14 @@ int DivEngine::getRow() {
|
|||
return prevRow;
|
||||
}
|
||||
|
||||
int DivEngine::getElapsedBars() {
|
||||
return elapsedBars;
|
||||
}
|
||||
|
||||
int DivEngine::getElapsedBeats() {
|
||||
return elapsedBeats;
|
||||
}
|
||||
|
||||
size_t DivEngine::getCurrentSubSong() {
|
||||
return curSubSongIndex;
|
||||
}
|
||||
|
|
@ -2673,12 +2688,17 @@ void DivEngine::unmuteAll() {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
int DivEngine::addInstrument(int refChan) {
|
||||
int DivEngine::addInstrument(int refChan, DivInstrumentType fallbackType) {
|
||||
if (song.ins.size()>=256) return -1;
|
||||
BUSY_BEGIN;
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
int insCount=(int)song.ins.size();
|
||||
DivInstrumentType prefType=getPreferInsType(refChan);
|
||||
DivInstrumentType prefType;
|
||||
if (refChan<0) {
|
||||
prefType=fallbackType;
|
||||
} else {
|
||||
prefType=getPreferInsType(refChan);
|
||||
}
|
||||
switch (prefType) {
|
||||
case DIV_INS_OPLL:
|
||||
*ins=song.nullInsOPLL;
|
||||
|
|
@ -2692,8 +2712,10 @@ int DivEngine::addInstrument(int refChan) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
|
||||
*ins=song.nullInsQSound;
|
||||
if (refChan>=0) {
|
||||
if (sysOfChan[refChan]==DIV_SYSTEM_QSOUND) {
|
||||
*ins=song.nullInsQSound;
|
||||
}
|
||||
}
|
||||
ins->name=fmt::sprintf("Instrument %d",insCount);
|
||||
if (prefType!=DIV_INS_NULL) {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev122"
|
||||
#define DIV_ENGINE_VERSION 122
|
||||
#define DIV_VERSION "dev125"
|
||||
#define DIV_ENGINE_VERSION 125
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
@ -351,14 +351,14 @@ class DivEngine {
|
|||
bool midiOutClock;
|
||||
int midiOutMode;
|
||||
int softLockCount;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats;
|
||||
size_t curSubSongIndex;
|
||||
double divider;
|
||||
int cycles;
|
||||
double clockDrift;
|
||||
int stepPlay;
|
||||
int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, totalCmds, lastCmds, cmdsPerSecond, globalPitch;
|
||||
unsigned char extValue;
|
||||
unsigned char extValue, pendingMetroTick;
|
||||
unsigned char speed1, speed2;
|
||||
short tempoAccum;
|
||||
DivStatusView view;
|
||||
|
|
@ -382,9 +382,9 @@ class DivEngine {
|
|||
std::vector<String> midiOuts;
|
||||
std::vector<DivCommand> cmdStream;
|
||||
std::vector<DivInstrumentType> possibleInsTypes;
|
||||
DivSysDef* sysDefs[256];
|
||||
DivSystem sysFileMapFur[256];
|
||||
DivSystem sysFileMapDMF[256];
|
||||
static DivSysDef* sysDefs[256];
|
||||
static DivSystem sysFileMapFur[256];
|
||||
static DivSystem sysFileMapDMF[256];
|
||||
|
||||
struct SamplePreview {
|
||||
double rate;
|
||||
|
|
@ -440,8 +440,6 @@ class DivEngine {
|
|||
void reset();
|
||||
void playSub(bool preserveDrift, int goalRow=0);
|
||||
|
||||
void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
|
||||
|
||||
bool loadDMF(unsigned char* file, size_t len);
|
||||
bool loadFur(unsigned char* file, size_t len);
|
||||
bool loadMod(unsigned char* file, size_t len);
|
||||
|
|
@ -469,7 +467,7 @@ class DivEngine {
|
|||
bool deinitAudioBackend(bool dueToSwitchMaster=false);
|
||||
|
||||
void registerSystems();
|
||||
void initSongWithDesc(const char* description);
|
||||
void initSongWithDesc(const char* description, bool inBase64=true);
|
||||
|
||||
void exchangeIns(int one, int two);
|
||||
void swapChannels(int src, int dest);
|
||||
|
|
@ -503,7 +501,7 @@ class DivEngine {
|
|||
// parse old system setup description
|
||||
String decodeSysDesc(String desc);
|
||||
// start fresh
|
||||
void createNew(const char* description, String sysName);
|
||||
void createNew(const char* description, String sysName, bool inBase64=true);
|
||||
// load a file.
|
||||
bool load(unsigned char* f, size_t length);
|
||||
// save as .dmf.
|
||||
|
|
@ -532,10 +530,14 @@ class DivEngine {
|
|||
void notifyWaveChange(int wave);
|
||||
|
||||
// get system IDs
|
||||
DivSystem systemFromFileFur(unsigned char val);
|
||||
unsigned char systemToFileFur(DivSystem val);
|
||||
DivSystem systemFromFileDMF(unsigned char val);
|
||||
unsigned char systemToFileDMF(DivSystem val);
|
||||
static DivSystem systemFromFileFur(unsigned char val);
|
||||
static unsigned char systemToFileFur(DivSystem val);
|
||||
static DivSystem systemFromFileDMF(unsigned char val);
|
||||
static unsigned char systemToFileDMF(DivSystem val);
|
||||
|
||||
// convert old flags
|
||||
static void convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivSystem sys);
|
||||
|
||||
|
||||
// benchmark (returns time in seconds)
|
||||
double benchmarkPlayback();
|
||||
|
|
@ -709,6 +711,10 @@ class DivEngine {
|
|||
// get current row
|
||||
int getRow();
|
||||
|
||||
// get beat/bar
|
||||
int getElapsedBars();
|
||||
int getElapsedBeats();
|
||||
|
||||
// get current subsong
|
||||
size_t getCurrentSubSong();
|
||||
|
||||
|
|
@ -753,7 +759,7 @@ class DivEngine {
|
|||
bool isExporting();
|
||||
|
||||
// add instrument
|
||||
int addInstrument(int refChan=0);
|
||||
int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD);
|
||||
|
||||
// add instrument from pointer
|
||||
int addInstrumentPtr(DivInstrument* which);
|
||||
|
|
@ -1058,6 +1064,8 @@ class DivEngine {
|
|||
lastLoopPos(0),
|
||||
exportLoopCount(0),
|
||||
nextSpeed(3),
|
||||
elapsedBars(0),
|
||||
elapsedBeats(0),
|
||||
curSubSongIndex(0),
|
||||
divider(60),
|
||||
cycles(0),
|
||||
|
|
@ -1073,6 +1081,7 @@ class DivEngine {
|
|||
cmdsPerSecond(0),
|
||||
globalPitch(0),
|
||||
extValue(0),
|
||||
pendingMetroTick(0),
|
||||
speed1(3),
|
||||
speed2(3),
|
||||
tempoAccum(0),
|
||||
|
|
|
|||
|
|
@ -2383,11 +2383,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (isNewSample) {
|
||||
sample->centerRate=reader.readI();
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
if (ds.version>=123) {
|
||||
sample->loopMode=(DivSampleLoopMode)reader.readC();
|
||||
} else {
|
||||
sample->loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
||||
reader.readC();
|
||||
}
|
||||
|
||||
// reserved
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
reader.readC();
|
||||
|
||||
sample->loopStart=reader.readI();
|
||||
sample->loopEnd=reader.readI();
|
||||
|
|
@ -2611,6 +2616,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// ExtCh compat flag
|
||||
if (ds.version<125) {
|
||||
for (int i=0; i<ds.systemLen; i++) {
|
||||
if (ds.system[i]==DIV_SYSTEM_YM2612_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_YM2612_FRAC_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_YM2610_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_YM2610_FULL_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_YM2610B_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_OPN_EXT ||
|
||||
ds.system[i]==DIV_SYSTEM_PC98_EXT) {
|
||||
ds.systemFlags[i].set("noExtMacros",true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active) quitDispatch();
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
|
|
@ -2946,7 +2966,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
writeFxCol(fxTyp,fxVal);
|
||||
break;
|
||||
case 12: // set vol
|
||||
data[row][3]=fxVal;
|
||||
data[row][3]=MIN(0x40,fxVal);
|
||||
break;
|
||||
case 13: // break to row (BCD)
|
||||
writeFxCol(fxTyp,((fxVal>>4)*10)+(fxVal&15));
|
||||
|
|
@ -4624,9 +4644,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeI(sample->rate);
|
||||
w->writeI(sample->centerRate);
|
||||
w->writeC(sample->depth);
|
||||
w->writeC(sample->loopMode);
|
||||
w->writeC(0); // reserved
|
||||
w->writeC(0);
|
||||
w->writeC(0);
|
||||
w->writeI(sample->loop?sample->loopStart:-1);
|
||||
w->writeI(sample->loop?sample->loopEnd:-1);
|
||||
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
} else {
|
||||
if (chan[i].std.arp.had) {
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(chan[i].note,chan[i].std.arp.val),11);
|
||||
}
|
||||
|
|
@ -1224,6 +1224,7 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
|
|||
break;
|
||||
}
|
||||
ladder=flags.getBool("ladderEffect",false);
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
OPN2_SetChipType(ladder?ym3438_mode_ym2612:0);
|
||||
if (useYMFM) {
|
||||
if (fm_ymfm!=NULL) delete fm_ymfm;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
|
||||
int softPCMTimer;
|
||||
|
||||
bool extMode, softPCM, useYMFM;
|
||||
bool extMode, softPCM, noExtMacros, useYMFM;
|
||||
bool ladder;
|
||||
|
||||
unsigned char dacVolTable[128];
|
||||
|
|
|
|||
|
|
@ -52,6 +52,15 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
chan[2].state.ams=ins->fm.ams;
|
||||
chan[2].state.op[ordch]=ins->fm.op[ordch];
|
||||
}
|
||||
|
||||
if (noExtMacros) {
|
||||
opChan[ch].macroInit(NULL);
|
||||
} else {
|
||||
opChan[ch].macroInit(ins);
|
||||
}
|
||||
if (!opChan[ch].std.vol.will) {
|
||||
opChan[ch].outVol=opChan[ch].vol;
|
||||
}
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
|
||||
|
|
@ -60,7 +69,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
|
|
@ -81,6 +90,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
if (c.value!=DIV_NOTE_NULL) {
|
||||
opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
opChan[ch].portaPause=false;
|
||||
opChan[ch].note=c.value;
|
||||
opChan[ch].freqChanged=true;
|
||||
}
|
||||
opChan[ch].keyOn=true;
|
||||
|
|
@ -92,14 +102,28 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
opChan[ch].keyOn=false;
|
||||
opChan[ch].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (noExtMacros) break;
|
||||
opChan[ch].keyOff=true;
|
||||
opChan[ch].keyOn=false;
|
||||
opChan[ch].active=false;
|
||||
opChan[ch].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
if (noExtMacros) break;
|
||||
opChan[ch].std.release();
|
||||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
if (!opChan[ch].std.vol.has) {
|
||||
opChan[ch].outVol=c.value;
|
||||
}
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -210,7 +234,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (KVS(2,c.value)) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -393,8 +417,8 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) {
|
|||
rWrite(baseAddr+0x40,127);
|
||||
immWrite(baseAddr+0x40,127);
|
||||
} else if (KVS(2,ordch)) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127));
|
||||
immWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
immWrite(baseAddr+0x40,op.tl);
|
||||
|
|
@ -438,6 +462,91 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
if (extMode && !noExtMacros) for (int i=0; i<4; i++) {
|
||||
opChan[i].std.next();
|
||||
|
||||
if (opChan[i].std.vol.had) {
|
||||
opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
|
||||
if (isOpMuted[i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127));
|
||||
}
|
||||
}
|
||||
|
||||
if (opChan[i].std.arp.had) {
|
||||
if (!opChan[i].inPorta) {
|
||||
opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11);
|
||||
}
|
||||
opChan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (opChan[i].std.pitch.had) {
|
||||
if (opChan[i].std.pitch.mode) {
|
||||
opChan[i].pitch2+=opChan[i].std.pitch.val;
|
||||
CLAMP_VAR(opChan[i].pitch2,-32768,32767);
|
||||
} else {
|
||||
opChan[i].pitch2=opChan[i].std.pitch.val;
|
||||
}
|
||||
opChan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
// param macros
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
|
||||
DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]];
|
||||
if (m.am.had) {
|
||||
op.am=m.am.val;
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
if (m.ar.had) {
|
||||
op.ar=m.ar.val;
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
if (m.dr.had) {
|
||||
op.dr=m.dr.val;
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
if (m.mult.had) {
|
||||
op.mult=m.mult.val;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
if (m.rr.had) {
|
||||
op.rr=m.rr.val;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
if (m.sl.had) {
|
||||
op.sl=m.sl.val;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
if (m.tl.had) {
|
||||
op.tl=127-m.tl.val;
|
||||
if (isOpMuted[i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127));
|
||||
}
|
||||
}
|
||||
if (m.rs.had) {
|
||||
op.rs=m.rs.val;
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
if (m.dt.had) {
|
||||
op.dt=m.dt.val;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
if (m.d2r.had) {
|
||||
op.d2r=m.d2r.val;
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
if (m.ssg.had) {
|
||||
op.ssgEnv=m.ssg.val;
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformGenesis::tick(sysTick);
|
||||
|
||||
bool writeNoteOn=false;
|
||||
|
|
@ -527,7 +636,7 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
if (isOpMuted[j]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (KVS(i,j)) {
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].vol&0x7f,127));
|
||||
rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
|
|
@ -601,7 +710,9 @@ void DivPlatformGenesisExt::reset() {
|
|||
|
||||
for (int i=0; i<4; i++) {
|
||||
opChan[i]=DivPlatformGenesisExt::OpChannel();
|
||||
opChan[i].std.setEngine(parent);
|
||||
opChan[i].vol=127;
|
||||
opChan[i].outVol=127;
|
||||
}
|
||||
|
||||
// channel 3 mode
|
||||
|
|
|
|||
|
|
@ -25,11 +25,15 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
|
||||
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins, note;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, mask;
|
||||
int vol;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
void macroInit(DivInstrument* which) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
OpChannel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
|
|
@ -39,6 +43,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
pitch2(0),
|
||||
portaPauseFreq(0),
|
||||
ins(-1),
|
||||
note(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
|
|
@ -48,6 +53,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
inPorta(false),
|
||||
mask(true),
|
||||
vol(0),
|
||||
outVol(0),
|
||||
pan(3) {}
|
||||
};
|
||||
OpChannel opChan[4];
|
||||
|
|
|
|||
|
|
@ -587,7 +587,17 @@ bool DivPlatformPCSpeaker::keyOffAffectsArp(int ch) {
|
|||
}
|
||||
|
||||
void DivPlatformPCSpeaker::setFlags(const DivConfig& flags) {
|
||||
chipClock=COLOR_NTSC/3.0;
|
||||
switch (flags.getInt("clockSel",0)) {
|
||||
case 1: // PC-98
|
||||
chipClock=38400*52;
|
||||
break;
|
||||
case 2: // PC-98
|
||||
chipClock=38400*64;
|
||||
break;
|
||||
default: // IBM PC
|
||||
chipClock=COLOR_NTSC/3.0;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/PCSPKR_DIVIDER;
|
||||
speakerType=flags.getInt("speakerType",0)&3;
|
||||
oscBuf->rate=rate;
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||
// old formula
|
||||
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
|
||||
rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
|
||||
chan[i].writeVol=true;
|
||||
}
|
||||
if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
|
|
@ -235,6 +235,12 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
chan[3].freqChanged=false;
|
||||
updateSNMode=false;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (chan[i].writeVol) {
|
||||
rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
|
||||
chan[i].writeVol=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSMS::dispatch(DivCommand c) {
|
||||
|
|
@ -249,9 +255,11 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
chan[c.chan].actualNote=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
if (!parent->song.brokenOutVol2) {
|
||||
rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
|
||||
}
|
||||
//if (!parent->song.brokenOutVol2) {
|
||||
chan[c.chan].writeVol=true;
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
//rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
|
||||
//}
|
||||
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
|
|
@ -276,7 +284,9 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].writeVol=true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
|
|
@ -356,7 +366,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
|
||||
void DivPlatformSMS::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (chan[ch].active) rWrite(0,0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15))));
|
||||
if (chan[ch].active) chan[ch].writeVol=true;
|
||||
}
|
||||
|
||||
void DivPlatformSMS::forceIns() {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ extern "C" {
|
|||
class DivPlatformSMS: public DivDispatch {
|
||||
struct Channel {
|
||||
int freq, baseFreq, pitch, pitch2, note, actualNote, ins;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, writeVol;
|
||||
signed char vol, outVol;
|
||||
DivMacroInt std;
|
||||
void macroInit(DivInstrument* which) {
|
||||
|
|
@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch {
|
|||
keyOn(false),
|
||||
keyOff(false),
|
||||
inPorta(false),
|
||||
writeVol(false),
|
||||
vol(15),
|
||||
outVol(15) {}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -952,6 +952,7 @@ void DivPlatformYM2203::setFlags(const DivConfig& flags) {
|
|||
ayDiv=16;
|
||||
break;
|
||||
}
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ class DivPlatformYM2203: public DivPlatformOPN {
|
|||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode;
|
||||
bool extMode, noExtMacros;
|
||||
unsigned char prescale;
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
|
|
|
|||
|
|
@ -1394,6 +1394,7 @@ void DivPlatformYM2608::setFlags(const DivConfig& flags) {
|
|||
ayDiv=32;
|
||||
break;
|
||||
}
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
|||
unsigned char writeRSSOff, writeRSSOn;
|
||||
int globalRSSVolume;
|
||||
|
||||
bool extMode;
|
||||
bool extMode, noExtMacros;
|
||||
unsigned char prescale;
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
|
||||
unsigned char sampleBank;
|
||||
|
||||
bool extMode;
|
||||
bool extMode, noExtMacros;
|
||||
|
||||
unsigned char writeADPCMAOff, writeADPCMAOn;
|
||||
int globalADPCMAVolume;
|
||||
|
|
@ -269,6 +269,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
|||
chipClock=8000000.0;
|
||||
break;
|
||||
}
|
||||
noExtMacros=flags.getBool("noExtMacros",false);
|
||||
rate=chipClock/16;
|
||||
for (int i=0; i<ChanNum; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
|
|
|
|||
|
|
@ -975,6 +975,20 @@ void DivEngine::nextRow() {
|
|||
printf("| %.2x:%s | \x1b[1;33m%3d%s\x1b[m\n",curOrder,pb1,curRow,pb3);
|
||||
}
|
||||
|
||||
if (curSubSong->hilightA>0) {
|
||||
if ((curRow%curSubSong->hilightA)==0) {
|
||||
pendingMetroTick=1;
|
||||
elapsedBeats++;
|
||||
}
|
||||
}
|
||||
if (curSubSong->hilightB>0) {
|
||||
if ((curRow%curSubSong->hilightB)==0) {
|
||||
pendingMetroTick=2;
|
||||
elapsedBars++;
|
||||
elapsedBeats=0;
|
||||
}
|
||||
}
|
||||
|
||||
prevOrder=curOrder;
|
||||
prevRow=curRow;
|
||||
|
||||
|
|
@ -1608,16 +1622,6 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
// 2. check whether we gonna tick
|
||||
if (cycles<=0) {
|
||||
// we have to tick
|
||||
if (!freelance && stepPlay!=-1 && subticks==1) {
|
||||
unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC);
|
||||
if (realPos>=size) realPos=size-1;
|
||||
if (curSubSong->hilightA>0) {
|
||||
if ((curRow%curSubSong->hilightA)==0 && ticks==1) metroTick[realPos]=1;
|
||||
}
|
||||
if (curSubSong->hilightB>0) {
|
||||
if ((curRow%curSubSong->hilightB)==0 && ticks==1) metroTick[realPos]=2;
|
||||
}
|
||||
}
|
||||
if (nextTick()) {
|
||||
lastLoopPos=size-(runLeftG>>MASTER_CLOCK_PREC);
|
||||
logD("last loop pos: %d for a size of %d and runLeftG of %d",lastLoopPos,size,runLeftG);
|
||||
|
|
@ -1634,6 +1638,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi
|
|||
}
|
||||
}
|
||||
}
|
||||
if (pendingMetroTick) {
|
||||
unsigned int realPos=size-(runLeftG>>MASTER_CLOCK_PREC);
|
||||
if (realPos>=size) realPos=size-1;
|
||||
metroTick[realPos]=pendingMetroTick;
|
||||
pendingMetroTick=0;
|
||||
}
|
||||
} else {
|
||||
// 3. tick the clock and fill buffers as needed
|
||||
if (cycles<runLeftG) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@
|
|||
#include "song.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
DivSysDef* DivEngine::sysDefs[256];
|
||||
DivSystem DivEngine::sysFileMapFur[256];
|
||||
DivSystem DivEngine::sysFileMapDMF[256];
|
||||
|
||||
DivSystem DivEngine::systemFromFileFur(unsigned char val) {
|
||||
return sysFileMapFur[val];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,10 +94,12 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
|||
if (VERA >= 0) disCont[VERA].dispatch->toggleRegisterDump(true);
|
||||
if (YM >= 0) {
|
||||
disCont[YM].dispatch->toggleRegisterDump(true);
|
||||
zsm.writeYM(0x18,0); // initialize the LFO freq to 0
|
||||
// note - I think there's a bug where Furnace writes AMD/PMD=max
|
||||
// that shouldn't be there, requiring this initialization that shouldn't
|
||||
// be there for ZSM.
|
||||
// emit LFO initialization commands
|
||||
zsm.writeYM(0x18,0); // freq = 0
|
||||
zsm.writeYM(0x19,0x7F); // AMD = 7F
|
||||
zsm.writeYM(0x19,0xFF); // PMD = 7F
|
||||
// TODO: incorporate the Furnace meta-command for init data and filter
|
||||
// out writes to otherwise-unused channels.
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ const char* aboutLine[]={
|
|||
"BlueElectric05",
|
||||
"breakthetargets",
|
||||
"brickblock369",
|
||||
"Burnt Fishy",
|
||||
"CaptainMalware",
|
||||
"DeMOSic",
|
||||
"DevEd",
|
||||
|
|
@ -91,6 +92,7 @@ const char* aboutLine[]={
|
|||
"Raijin",
|
||||
"SnugglyBun",
|
||||
"SuperJet Spade",
|
||||
"TakuikaNinja",
|
||||
"TheDuccinator",
|
||||
"theloredev",
|
||||
"TheRealHedgehogSonic",
|
||||
|
|
@ -153,7 +155,6 @@ const char* aboutLine[]={
|
|||
"MSM6295 emulator by cam900",
|
||||
"",
|
||||
"greetings to:",
|
||||
"Fractal Sound team",
|
||||
"NEOART Costa Rica",
|
||||
"all members of Deflers of Noice!",
|
||||
"",
|
||||
|
|
|
|||
116
src/gui/clock.cpp
Normal file
116
src/gui/clock.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 "gui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui.h"
|
||||
|
||||
void FurnaceGUI::drawClock() {
|
||||
if (nextWindow==GUI_WINDOW_CLOCK) {
|
||||
clockOpen=true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!clockOpen) return;
|
||||
if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) {
|
||||
int row=e->getRow();
|
||||
int elapsedBars=e->getElapsedBars();
|
||||
int elapsedBeats=e->getElapsedBeats();
|
||||
bool playing=e->isPlaying();
|
||||
if (clockShowRow) {
|
||||
ImGui::PushFont(bigFont);
|
||||
ImGui::Text("%.3d:%.3d",e->getOrder(),row);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
if (clockShowBeat) {
|
||||
ImGui::PushFont(bigFont);
|
||||
ImGui::Text("%.3d:%.1d",elapsedBars,elapsedBeats+1);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
if (clockShowMetro) {
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
ImVec2 size=ImGui::GetContentRegionAvail();
|
||||
size.y=12.0f*dpiScale;
|
||||
|
||||
ImVec2 minArea=window->DC.CursorPos;
|
||||
ImVec2 maxArea=ImVec2(
|
||||
minArea.x+size.x,
|
||||
minArea.y+size.y
|
||||
);
|
||||
ImRect rect=ImRect(minArea,maxArea);
|
||||
/*ImRect inRect=rect;
|
||||
inRect.Min.x+=dpiScale;
|
||||
inRect.Min.y+=dpiScale;
|
||||
inRect.Max.x-=dpiScale;
|
||||
inRect.Max.y-=dpiScale;*/
|
||||
ImGuiStyle& style=ImGui::GetStyle();
|
||||
ImGui::ItemSize(size,style.FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("metroQ"))) {
|
||||
int h1=e->curSubSong->hilightA;
|
||||
int h2=e->curSubSong->hilightB;
|
||||
if (h1>0 && h2>0) {
|
||||
int beats=(h2+(h1-1))/h1;
|
||||
if (beats<0) beats=1;
|
||||
if (beats>16) beats=16;
|
||||
if (playing) {
|
||||
if (elapsedBeats!=oldBeat || elapsedBars!=oldBar) {
|
||||
if (elapsedBeats>15) elapsedBeats=15;
|
||||
clockMetroTick[elapsedBeats]=1.0f;
|
||||
oldBeat=elapsedBeats;
|
||||
oldBar=elapsedBars;
|
||||
}
|
||||
} else {
|
||||
oldBeat=-1;
|
||||
oldBar=-1;
|
||||
}
|
||||
for (int i=0; i<beats; i++) {
|
||||
ImVec2 minB=ImLerp(minArea,maxArea,ImVec2((float)i/(float)beats,0.0f));
|
||||
ImVec2 maxB=ImLerp(minArea,maxArea,ImVec2((float)(i+1)/(float)beats,1.0f));
|
||||
ImVec4 col=ImLerp(uiColors[GUI_COLOR_CLOCK_BEAT_LOW],uiColors[GUI_COLOR_CLOCK_BEAT_HIGH],clockMetroTick[i]);
|
||||
dl->AddQuadFilled(
|
||||
ImLerp(minB,maxB,ImVec2(0.35f,0.0f)),
|
||||
ImLerp(minB,maxB,ImVec2(0.9f,0.0f)),
|
||||
ImLerp(minB,maxB,ImVec2(0.65f,1.0f)),
|
||||
ImLerp(minB,maxB,ImVec2(0.1f,1.0f)),
|
||||
ImGui::GetColorU32(col)
|
||||
);
|
||||
|
||||
if (elapsedBeats==i && playing) {
|
||||
clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f;
|
||||
if (clockMetroTick[i]<0.3f) clockMetroTick[i]=0.3f;
|
||||
} else {
|
||||
clockMetroTick[i]-=0.1f*ImGui::GetIO().DeltaTime*60.0f;
|
||||
if (clockMetroTick[i]<0.0f) clockMetroTick[i]=0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clockShowTime) {
|
||||
int totalTicks=e->getTotalTicks();
|
||||
int totalSeconds=e->getTotalSeconds();
|
||||
ImGui::PushFont(bigFont);
|
||||
ImGui::Text("%.2d:%.2d.%.2d",(totalSeconds/60),totalSeconds%60,totalTicks/10000);
|
||||
ImGui::PopFont();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SPOILER;
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
@ -60,6 +60,11 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
|||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
displayInsTypeList=true;
|
||||
displayInsTypeListMakeInsSample=-1;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FILES_O "##InsClone")) {
|
||||
|
|
|
|||
|
|
@ -1291,14 +1291,54 @@ void FurnaceGUI::doAction(int what) {
|
|||
break;
|
||||
case GUI_ACTION_SAMPLE_MAKE_INS: {
|
||||
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||
// determine instrument type
|
||||
std::vector<DivInstrumentType> tempTypeList=e->getPossibleInsTypes();
|
||||
makeInsTypeList.clear();
|
||||
|
||||
for (DivInstrumentType& i: tempTypeList) {
|
||||
if (i==DIV_INS_PCE ||
|
||||
i==DIV_INS_MSM6258 ||
|
||||
i==DIV_INS_MSM6295 ||
|
||||
i==DIV_INS_ADPCMA ||
|
||||
i==DIV_INS_ADPCMB ||
|
||||
i==DIV_INS_SEGAPCM ||
|
||||
i==DIV_INS_QSOUND ||
|
||||
i==DIV_INS_YMZ280B ||
|
||||
i==DIV_INS_RF5C68 ||
|
||||
i==DIV_INS_MULTIPCM ||
|
||||
i==DIV_INS_MIKEY ||
|
||||
i==DIV_INS_X1_010 ||
|
||||
i==DIV_INS_SWAN ||
|
||||
i==DIV_INS_AY ||
|
||||
i==DIV_INS_AY8930 ||
|
||||
i==DIV_INS_VRC6 ||
|
||||
i==DIV_INS_SU ||
|
||||
i==DIV_INS_SNES ||
|
||||
i==DIV_INS_ES5506) {
|
||||
makeInsTypeList.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (makeInsTypeList.size()>1) {
|
||||
displayInsTypeList=true;
|
||||
displayInsTypeListMakeInsSample=curSample;
|
||||
break;
|
||||
}
|
||||
|
||||
DivInstrumentType insType=DIV_INS_AMIGA;
|
||||
if (!makeInsTypeList.empty()) {
|
||||
insType=makeInsTypeList[0];
|
||||
}
|
||||
|
||||
DivSample* sample=e->song.sample[curSample];
|
||||
curIns=e->addInstrument(cursor.xCoarse);
|
||||
if (curIns==-1) {
|
||||
showError("too many instruments!");
|
||||
} else {
|
||||
e->song.ins[curIns]->type=DIV_INS_AMIGA;
|
||||
e->song.ins[curIns]->type=insType;
|
||||
e->song.ins[curIns]->name=sample->name;
|
||||
e->song.ins[curIns]->amiga.initSample=curSample;
|
||||
if (insType!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true;
|
||||
nextWindow=GUI_WINDOW_INS_EDIT;
|
||||
MARK_MODIFIED;
|
||||
wavePreviewInit=true;
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ void FurnaceGUI::drawMobileControls() {
|
|||
ImGui::SameLine();
|
||||
if (ImGui::Button("Settings")) {
|
||||
mobileMenuOpen=false;
|
||||
settingsOpen=true;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Log")) {
|
||||
|
|
|
|||
|
|
@ -2651,8 +2651,11 @@ int _processEvent(void* instance, SDL_Event* event) {
|
|||
|
||||
int FurnaceGUI::processEvent(SDL_Event* ev) {
|
||||
#ifdef IS_MOBILE
|
||||
if (ev->type==SDL_APP_WILLENTERBACKGROUND) {
|
||||
// TODO: save "last state" and potentially suspend engine
|
||||
if (ev->type==SDL_APP_TERMINATING) {
|
||||
// TODO: save last song state here
|
||||
} else if (ev->type==SDL_APP_WILLENTERBACKGROUND) {
|
||||
commitState();
|
||||
e->saveConf();
|
||||
}
|
||||
#endif
|
||||
if (ev->type==SDL_KEYDOWN) {
|
||||
|
|
@ -2958,7 +2961,11 @@ bool FurnaceGUI::detectOutOfBoundsWindow() {
|
|||
}
|
||||
|
||||
bool FurnaceGUI::loop() {
|
||||
#ifdef IS_MOBILE
|
||||
bool doThreadedInput=true;
|
||||
#else
|
||||
bool doThreadedInput=!settings.noThreadedInput;
|
||||
#endif
|
||||
if (doThreadedInput) {
|
||||
logD("key input: event filter");
|
||||
SDL_SetEventFilter(_processEvent,this);
|
||||
|
|
@ -3620,6 +3627,7 @@ bool FurnaceGUI::loop() {
|
|||
if (ImGui::MenuItem("oscilloscope (master)",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen;
|
||||
if (ImGui::MenuItem("oscilloscope (per-channel)",BIND_FOR(GUI_ACTION_WINDOW_CHAN_OSC),chanOscOpen)) chanOscOpen=!chanOscOpen;
|
||||
if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen;
|
||||
if (ImGui::MenuItem("clock",BIND_FOR(GUI_ACTION_WINDOW_CLOCK),clockOpen)) clockOpen=!clockOpen;
|
||||
if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen;
|
||||
if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen;
|
||||
if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen;
|
||||
|
|
@ -3747,6 +3755,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
|
||||
globalWinFlags=0;
|
||||
drawSettings();
|
||||
drawDebug();
|
||||
drawLog();
|
||||
} else {
|
||||
|
|
@ -3782,6 +3791,7 @@ bool FurnaceGUI::loop() {
|
|||
drawChannels();
|
||||
drawPatManager();
|
||||
drawSysManager();
|
||||
drawClock();
|
||||
drawRegView();
|
||||
drawLog();
|
||||
drawEffectList();
|
||||
|
|
@ -4399,6 +4409,11 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::OpenPopup("Import Raw Sample");
|
||||
}
|
||||
|
||||
if (displayInsTypeList) {
|
||||
displayInsTypeList=false;
|
||||
ImGui::OpenPopup("InsTypeList");
|
||||
}
|
||||
|
||||
if (displayExporting) {
|
||||
displayExporting=false;
|
||||
ImGui::OpenPopup("Rendering...");
|
||||
|
|
@ -4428,9 +4443,14 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(canvasW,canvasH));
|
||||
ImVec2 newSongMinSize=mobileUI?ImVec2(canvasW-(portrait?0:(60.0*dpiScale)),canvasH-60.0*dpiScale):ImVec2(400.0f*dpiScale,200.0f*dpiScale);
|
||||
ImVec2 newSongMaxSize=ImVec2(canvasW-((mobileUI && !portrait)?(60.0*dpiScale):0),canvasH-(mobileUI?(60.0*dpiScale):0));
|
||||
ImGui::SetNextWindowSizeConstraints(newSongMinSize,newSongMaxSize);
|
||||
if (ImGui::BeginPopupModal("New Song",NULL,ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
|
||||
ImGui::SetWindowPos(ImVec2(((canvasW)-ImGui::GetWindowSize().x)*0.5,((canvasH)-ImGui::GetWindowSize().y)*0.5));
|
||||
if (ImGui::GetWindowSize().x<newSongMinSize.x || ImGui::GetWindowSize().y<newSongMinSize.y) {
|
||||
ImGui::SetWindowSize(newSongMinSize,ImGuiCond_Always);
|
||||
}
|
||||
drawNewSong();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
|
@ -4774,6 +4794,31 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("InsTypeList",ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings)) {
|
||||
char temp[1024];
|
||||
for (DivInstrumentType& i: makeInsTypeList) {
|
||||
strncpy(temp,insTypes[i],1023);
|
||||
if (ImGui::MenuItem(temp)) {
|
||||
// create ins
|
||||
curIns=e->addInstrument(-1,i);
|
||||
if (curIns==-1) {
|
||||
showError("too many instruments!");
|
||||
} else {
|
||||
if (displayInsTypeListMakeInsSample>=0 && displayInsTypeListMakeInsSample<(int)e->song.sample.size()) {
|
||||
e->song.ins[curIns]->type=i;
|
||||
e->song.ins[curIns]->name=e->song.sample[displayInsTypeListMakeInsSample]->name;
|
||||
e->song.ins[curIns]->amiga.initSample=displayInsTypeListMakeInsSample;
|
||||
if (i!=DIV_INS_AMIGA) e->song.ins[curIns]->amiga.useSample=true;
|
||||
nextWindow=GUI_WINDOW_INS_EDIT;
|
||||
wavePreviewInit=true;
|
||||
}
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - multiple selection
|
||||
// - replace instrument
|
||||
|
|
@ -5020,6 +5065,7 @@ bool FurnaceGUI::init() {
|
|||
channelsOpen=e->getConfBool("channelsOpen",false);
|
||||
patManagerOpen=e->getConfBool("patManagerOpen",false);
|
||||
sysManagerOpen=e->getConfBool("sysManagerOpen",false);
|
||||
clockOpen=e->getConfBool("clockOpen",false);
|
||||
regViewOpen=e->getConfBool("regViewOpen",false);
|
||||
logOpen=e->getConfBool("logOpen",false);
|
||||
effectListOpen=e->getConfBool("effectListOpen",false);
|
||||
|
|
@ -5333,15 +5379,10 @@ bool FurnaceGUI::init() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FurnaceGUI::finish() {
|
||||
void FurnaceGUI::commitState() {
|
||||
if (!mobileUI) {
|
||||
ImGui::SaveIniSettingsToDisk(finalLayoutPath);
|
||||
}
|
||||
ImGui_ImplSDLRenderer_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
SDL_DestroyRenderer(sdlRend);
|
||||
SDL_DestroyWindow(sdlWin);
|
||||
|
||||
e->setConf("configVersion",(int)DIV_ENGINE_VERSION);
|
||||
|
||||
|
|
@ -5383,6 +5424,7 @@ bool FurnaceGUI::finish() {
|
|||
e->setConf("channelsOpen",channelsOpen);
|
||||
e->setConf("patManagerOpen",patManagerOpen);
|
||||
e->setConf("sysManagerOpen",sysManagerOpen);
|
||||
e->setConf("clockOpen",clockOpen);
|
||||
e->setConf("regViewOpen",regViewOpen);
|
||||
e->setConf("logOpen",logOpen);
|
||||
e->setConf("effectListOpen",effectListOpen);
|
||||
|
|
@ -5454,6 +5496,15 @@ bool FurnaceGUI::finish() {
|
|||
e->setConf(key,recentFile[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FurnaceGUI::finish() {
|
||||
commitState();
|
||||
ImGui_ImplSDLRenderer_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
SDL_DestroyRenderer(sdlRend);
|
||||
SDL_DestroyWindow(sdlWin);
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
delete oldPat[i];
|
||||
|
|
@ -5485,6 +5536,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
zsmExportLoop(true),
|
||||
vgmExportPatternHints(false),
|
||||
vgmExportDirectStream(false),
|
||||
displayInsTypeList(false),
|
||||
portrait(false),
|
||||
injectBackUp(false),
|
||||
mobileMenuOpen(false),
|
||||
|
|
@ -5505,6 +5557,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
zsmExportTickRate(60),
|
||||
macroPointSize(16),
|
||||
waveEditStyle(0),
|
||||
displayInsTypeListMakeInsSample(-1),
|
||||
mobileMenuPos(0.0f),
|
||||
autoButtonSize(0.0f),
|
||||
curSysSection(NULL),
|
||||
|
|
@ -5571,6 +5624,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
dragSourceY(0),
|
||||
dragDestinationX(0),
|
||||
dragDestinationY(0),
|
||||
oldBeat(-1),
|
||||
oldBar(-1),
|
||||
exportFadeOut(5.0),
|
||||
editControlsOpen(true),
|
||||
ordersOpen(true),
|
||||
|
|
@ -5603,6 +5658,12 @@ FurnaceGUI::FurnaceGUI():
|
|||
spoilerOpen(false),
|
||||
patManagerOpen(false),
|
||||
sysManagerOpen(false),
|
||||
clockOpen(false),
|
||||
clockShowReal(true),
|
||||
clockShowRow(true),
|
||||
clockShowBeat(true),
|
||||
clockShowMetro(true),
|
||||
clockShowTime(true),
|
||||
selecting(false),
|
||||
selectingFull(false),
|
||||
dragging(false),
|
||||
|
|
@ -5631,7 +5692,6 @@ FurnaceGUI::FurnaceGUI():
|
|||
curWindowLast(GUI_WINDOW_NOTHING),
|
||||
curWindowThreadSafe(GUI_WINDOW_NOTHING),
|
||||
lastPatternWidth(0.0f),
|
||||
nextDesc(NULL),
|
||||
latchNote(-1),
|
||||
latchIns(-2),
|
||||
latchVol(-1),
|
||||
|
|
|
|||
|
|
@ -243,6 +243,10 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE,
|
||||
GUI_COLOR_PIANO_KEY_TOP_ACTIVE,
|
||||
|
||||
GUI_COLOR_CLOCK_TEXT,
|
||||
GUI_COLOR_CLOCK_BEAT_LOW,
|
||||
GUI_COLOR_CLOCK_BEAT_HIGH,
|
||||
|
||||
GUI_COLOR_LOGLEVEL_ERROR,
|
||||
GUI_COLOR_LOGLEVEL_WARNING,
|
||||
GUI_COLOR_LOGLEVEL_INFO,
|
||||
|
|
@ -285,6 +289,7 @@ enum FurnaceGUIWindows {
|
|||
GUI_WINDOW_CHAN_OSC,
|
||||
GUI_WINDOW_SUBSONGS,
|
||||
GUI_WINDOW_FIND,
|
||||
GUI_WINDOW_CLOCK,
|
||||
GUI_WINDOW_SPOILER
|
||||
};
|
||||
|
||||
|
|
@ -425,6 +430,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_WINDOW_CHAN_OSC,
|
||||
GUI_ACTION_WINDOW_SUBSONGS,
|
||||
GUI_ACTION_WINDOW_FIND,
|
||||
GUI_ACTION_WINDOW_CLOCK,
|
||||
|
||||
GUI_ACTION_COLLAPSE_WINDOW,
|
||||
GUI_ACTION_CLOSE_WINDOW,
|
||||
|
|
@ -893,12 +899,22 @@ struct Gradient2D {
|
|||
}
|
||||
};
|
||||
|
||||
struct FurnaceGUISysDefChip {
|
||||
DivSystem sys;
|
||||
int vol, pan;
|
||||
const char* flags;
|
||||
FurnaceGUISysDefChip(DivSystem s, int v, int p, const char* f):
|
||||
sys(s),
|
||||
vol(v),
|
||||
pan(p),
|
||||
flags(f) {}
|
||||
};
|
||||
|
||||
struct FurnaceGUISysDef {
|
||||
const char* name;
|
||||
std::vector<int> definition;
|
||||
FurnaceGUISysDef(const char* n, std::initializer_list<int> def):
|
||||
name(n), definition(def) {
|
||||
}
|
||||
String definition;
|
||||
FurnaceGUISysDef(const char* n, std::initializer_list<int> def);
|
||||
FurnaceGUISysDef(const char* n, std::initializer_list<FurnaceGUISysDefChip> def);
|
||||
};
|
||||
|
||||
struct FurnaceGUISysCategory {
|
||||
|
|
@ -945,6 +961,12 @@ struct FurnaceGUIMacroDesc {
|
|||
}
|
||||
};
|
||||
|
||||
struct FurnaceGUIMacroEditState {
|
||||
int selectedMacro;
|
||||
FurnaceGUIMacroEditState():
|
||||
selectedMacro(0) {}
|
||||
};
|
||||
|
||||
enum FurnaceGUIFindQueryModes {
|
||||
GUI_QUERY_IGNORE=0,
|
||||
GUI_QUERY_MATCH,
|
||||
|
|
@ -1033,9 +1055,11 @@ class FurnaceGUI {
|
|||
std::vector<DivSystem> sysSearchResults;
|
||||
std::vector<FurnaceGUISysDef> newSongSearchResults;
|
||||
std::deque<String> recentFile;
|
||||
std::vector<DivInstrumentType> makeInsTypeList;
|
||||
|
||||
|
||||
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, vgmExportPatternHints;
|
||||
bool vgmExportDirectStream;
|
||||
bool vgmExportDirectStream, displayInsTypeList;
|
||||
bool portrait, injectBackUp, mobileMenuOpen;
|
||||
bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;
|
||||
bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly;
|
||||
|
|
@ -1046,6 +1070,7 @@ class FurnaceGUI {
|
|||
int zsmExportTickRate;
|
||||
int macroPointSize;
|
||||
int waveEditStyle;
|
||||
int displayInsTypeListMakeInsSample;
|
||||
float mobileMenuPos, autoButtonSize;
|
||||
const int* curSysSection;
|
||||
|
||||
|
|
@ -1216,6 +1241,7 @@ class FurnaceGUI {
|
|||
int persistFadeOut;
|
||||
int exportLoops;
|
||||
double exportFadeOut;
|
||||
int macroLayout;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
|
@ -1346,6 +1372,7 @@ class FurnaceGUI {
|
|||
persistFadeOut(1),
|
||||
exportLoops(0),
|
||||
exportFadeOut(0.0),
|
||||
macroLayout(0),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
|
@ -1367,7 +1394,7 @@ class FurnaceGUI {
|
|||
|
||||
int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor;
|
||||
int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget;
|
||||
int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY;
|
||||
int wheelX, wheelY, dragSourceX, dragSourceY, dragDestinationX, dragDestinationY, oldBeat, oldBar;
|
||||
|
||||
double exportFadeOut;
|
||||
|
||||
|
|
@ -1375,7 +1402,10 @@ class FurnaceGUI {
|
|||
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
|
||||
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
|
||||
bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen;
|
||||
bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen;
|
||||
bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen;
|
||||
|
||||
bool clockShowReal, clockShowRow, clockShowBeat, clockShowMetro, clockShowTime;
|
||||
float clockMetroTick[16];
|
||||
|
||||
SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd;
|
||||
bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI;
|
||||
|
|
@ -1387,7 +1417,7 @@ class FurnaceGUI {
|
|||
float patChanX[DIV_MAX_CHANS+1];
|
||||
float patChanSlideY[DIV_MAX_CHANS+1];
|
||||
float lastPatternWidth;
|
||||
const int* nextDesc;
|
||||
String nextDesc;
|
||||
String nextDescName;
|
||||
|
||||
OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue;
|
||||
|
|
@ -1511,6 +1541,8 @@ class FurnaceGUI {
|
|||
int macroLoopDragLen;
|
||||
bool macroLoopDragActive;
|
||||
|
||||
FurnaceGUIMacroEditState macroEditStateFM, macroEditStateOP[4], macroEditStateMacros;
|
||||
|
||||
ImVec2 waveDragStart;
|
||||
ImVec2 waveDragAreaSize;
|
||||
int* waveDragTarget;
|
||||
|
|
@ -1675,7 +1707,8 @@ class FurnaceGUI {
|
|||
|
||||
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel);
|
||||
|
||||
void drawMacros(std::vector<FurnaceGUIMacroDesc>& macros);
|
||||
void drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index);
|
||||
void drawMacros(std::vector<FurnaceGUIMacroDesc>& macros, FurnaceGUIMacroEditState& state);
|
||||
|
||||
void actualWaveList();
|
||||
void actualSampleList();
|
||||
|
|
@ -1717,6 +1750,7 @@ class FurnaceGUI {
|
|||
void drawSubSongs();
|
||||
void drawFindReplace();
|
||||
void drawSpoiler();
|
||||
void drawClock();
|
||||
|
||||
void parseKeybinds();
|
||||
void promptKey(int which);
|
||||
|
|
@ -1736,6 +1770,7 @@ class FurnaceGUI {
|
|||
|
||||
void syncSettings();
|
||||
void commitSettings();
|
||||
void commitState();
|
||||
void processDrags(int dragX, int dragY);
|
||||
void processPoint(SDL_Event& ev);
|
||||
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("WINDOW_CHAN_OSC", "Oscilloscope (per-channel)", 0),
|
||||
D("WINDOW_SUBSONGS", "Subsongs", 0),
|
||||
D("WINDOW_FIND", "Find/Replace", FURKMOD_CMD|SDLK_f),
|
||||
D("WINDOW_CLOCK", "Clock", 0),
|
||||
|
||||
D("COLLAPSE_WINDOW", "Collapse/expand current window", 0),
|
||||
D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE),
|
||||
|
|
@ -874,6 +875,10 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_PIANO_KEY_BOTTOM_ACTIVE,"",ImVec4(0.5f,0.5f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_PIANO_KEY_TOP_ACTIVE,"",ImVec4(0.4f,0.4f,0.4f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_CLOCK_TEXT,"",ImVec4(1.0f,1.0f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_CLOCK_BEAT_LOW,"",ImVec4(0.1f,0.13f,0.25f,1.0f)),
|
||||
D(GUI_COLOR_CLOCK_BEAT_HIGH,"",ImVec4(0.5f,0.8f,1.0f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_LOGLEVEL_ERROR,"",ImVec4(1.0f,0.2f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_LOGLEVEL_WARNING,"",ImVec4(1.0f,1.0f,0.2f,1.0f)),
|
||||
D(GUI_COLOR_LOGLEVEL_INFO,"",ImVec4(0.4f,1.0f,0.4f,1.0f)),
|
||||
|
|
|
|||
1120
src/gui/insEdit.cpp
1120
src/gui/insEdit.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -107,7 +107,7 @@ void FurnaceGUI::drawNewSong() {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) {
|
||||
nextDesc=i.definition.data();
|
||||
nextDesc=i.definition;
|
||||
nextDescName=i.name;
|
||||
accepted=true;
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ void FurnaceGUI::drawNewSong() {
|
|||
ImGui::CloseCurrentPopup();
|
||||
} else {
|
||||
unsigned int selection=rand()%newSystemCat->systems.size();
|
||||
nextDesc=newSystemCat->systems[selection].definition.data();
|
||||
nextDesc=newSystemCat->systems[selection].definition;
|
||||
nextDescName=newSystemCat->systems[selection].name;
|
||||
accepted=true;
|
||||
}
|
||||
|
|
@ -143,16 +143,7 @@ void FurnaceGUI::drawNewSong() {
|
|||
}
|
||||
|
||||
if (accepted) {
|
||||
// TODO: remove after porting all presets to new format
|
||||
String oldDescFormat;
|
||||
for (const int* i=nextDesc; *i; i+=4) {
|
||||
oldDescFormat+=fmt::sprintf("%d ",e->systemToFileFur((DivSystem)i[0]));
|
||||
oldDescFormat+=fmt::sprintf("%d ",i[1]);
|
||||
oldDescFormat+=fmt::sprintf("%d ",i[2]);
|
||||
oldDescFormat+=fmt::sprintf("%d ",i[3]);
|
||||
}
|
||||
String oldDesc=e->decodeSysDesc(oldDescFormat.c_str());
|
||||
e->createNew(oldDesc.c_str(),nextDescName);
|
||||
e->createNew(nextDesc.c_str(),nextDescName,false);
|
||||
undoHist.clear();
|
||||
redoHist.clear();
|
||||
curFileName="";
|
||||
|
|
|
|||
|
|
@ -219,11 +219,14 @@ void FurnaceGUI::drawPiano() {
|
|||
// render piano
|
||||
//ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) {
|
||||
ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"));
|
||||
bool canInput=false;
|
||||
if (ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) {
|
||||
canInput=true;
|
||||
}
|
||||
if (view) {
|
||||
int notes=oct*12;
|
||||
// evaluate input
|
||||
for (TouchPoint& i: activePoints) {
|
||||
if (canInput) for (TouchPoint& i: activePoints) {
|
||||
if (rect.Contains(ImVec2(i.x,i.y))) {
|
||||
int note=(((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*notes)+12*off;
|
||||
if (note<0) continue;
|
||||
|
|
|
|||
2338
src/gui/presets.cpp
2338
src/gui/presets.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -197,10 +197,12 @@ double getScaleFactor(const char* driverHint) {
|
|||
|
||||
// SDL fallback
|
||||
#ifdef ANDROID
|
||||
float dpiScaleF=192.0f;
|
||||
float dpiScaleF=160.0f;
|
||||
if (SDL_GetDisplayDPI(0,&dpiScaleF,NULL,NULL)==0) {
|
||||
ret=round(dpiScaleF/192.0f);
|
||||
ret=dpiScaleF/160.0f;
|
||||
if (ret<1) ret=1;
|
||||
logI("dpiScaleF: %f",dpiScaleF);
|
||||
logI("ret: %f",ret);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@
|
|||
|
||||
#define DEFAULT_NOTE_KEYS "5:7;6:4;7:3;8:16;10:6;11:8;12:24;13:10;16:11;17:9;18:26;19:28;20:12;21:17;22:1;23:19;24:23;25:5;26:14;27:2;28:21;29:0;30:100;31:13;32:15;34:18;35:20;36:22;38:25;39:27;43:100;46:101;47:29;48:31;53:102;"
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(IS_MOBILE)
|
||||
#define POWER_SAVE_DEFAULT 1
|
||||
#else
|
||||
// currently off on Linux/other due to Mesa catch-up behavior.
|
||||
#define POWER_SAVE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#if defined(__HAIKU__) || defined(IS_MOBILE)
|
||||
// NFD doesn't support Haiku
|
||||
#define SYS_FILE_DIALOG_DEFAULT 0
|
||||
#else
|
||||
|
|
@ -239,6 +239,12 @@ void FurnaceGUI::drawSettings() {
|
|||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!settingsOpen) return;
|
||||
if (mobileUI) {
|
||||
ImVec2 setWindowPos=ImVec2(0,0);
|
||||
ImVec2 setWindowSize=ImVec2(canvasW,canvasH);
|
||||
ImGui::SetNextWindowPos(setWindowPos);
|
||||
ImGui::SetNextWindowSize(setWindowSize);
|
||||
}
|
||||
if (ImGui::Begin("Settings",&settingsOpen,ImGuiWindowFlags_NoDocking|globalWinFlags)) {
|
||||
if (!settingsOpen) {
|
||||
settingsOpen=true;
|
||||
|
|
@ -332,7 +338,7 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.initialSys.set("pan0",0);
|
||||
settings.initialSys.set("flags0","");
|
||||
settings.initialSys.set("id1",e->systemToFileFur(DIV_SYSTEM_SMS));
|
||||
settings.initialSys.set("vol1",64);
|
||||
settings.initialSys.set("vol1",32);
|
||||
settings.initialSys.set("pan1",0);
|
||||
settings.initialSys.set("flags1","");
|
||||
settings.initialSysName="Sega Genesis/Mega Drive";
|
||||
|
|
@ -343,11 +349,15 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::InputText("##InitSysName",&settings.initialSysName);
|
||||
|
||||
int sysCount=0;
|
||||
int doRemove=-1;
|
||||
for (size_t i=0; settings.initialSys.getInt(fmt::sprintf("id%d",i),0); i++) {
|
||||
DivSystem sysID=e->systemFromFileFur(settings.initialSys.getInt(fmt::sprintf("id%d",i),0));
|
||||
signed char sysVol=settings.initialSys.getInt(fmt::sprintf("vol%d",i),0);
|
||||
signed char sysPan=settings.initialSys.getInt(fmt::sprintf("pan%d",i),0);
|
||||
|
||||
sysCount=i+1;
|
||||
|
||||
//bool doRemove=false;
|
||||
bool doInvert=sysVol&128;
|
||||
signed char vol=sysVol&127;
|
||||
|
|
@ -373,7 +383,7 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SameLine();
|
||||
//ImGui::BeginDisabled(settings.initialSys.size()<=4);
|
||||
if (ImGui::Button(ICON_FA_MINUS "##InitSysRemove")) {
|
||||
//doRemove=true;
|
||||
doRemove=i;
|
||||
}
|
||||
//ImGui::EndDisabled();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale));
|
||||
|
|
@ -398,17 +408,31 @@ void FurnaceGUI::drawSettings() {
|
|||
}
|
||||
|
||||
ImGui::PopID();
|
||||
/*if (doRemove && settings.initialSys.size()>=8) {
|
||||
settings.initialSys.erase(settings.initialSys.begin()+i,settings.initialSys.begin()+i+4);
|
||||
i-=4;
|
||||
}*/
|
||||
}
|
||||
|
||||
if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) {
|
||||
/*settings.initialSys.push_back(DIV_SYSTEM_YM2612);
|
||||
settings.initialSys.push_back(64);
|
||||
settings.initialSys.push_back(0);
|
||||
settings.initialSys.push_back(0);*/
|
||||
if (doRemove>=0 && sysCount>1) {
|
||||
for (int i=doRemove; i<sysCount-1; i++) {
|
||||
int sysID=settings.initialSys.getInt(fmt::sprintf("id%d",i+1),0);
|
||||
int sysVol=settings.initialSys.getInt(fmt::sprintf("vol%d",i+1),0);
|
||||
int sysPan=settings.initialSys.getInt(fmt::sprintf("pan%d",i+1),0);
|
||||
String sysFlags=settings.initialSys.getString(fmt::sprintf("flags%d",i+1),"");
|
||||
settings.initialSys.set(fmt::sprintf("id%d",i),sysID);
|
||||
settings.initialSys.set(fmt::sprintf("vol%d",i),sysVol);
|
||||
settings.initialSys.set(fmt::sprintf("pan%d",i),sysPan);
|
||||
settings.initialSys.set(fmt::sprintf("flags%d",i),sysFlags);
|
||||
}
|
||||
|
||||
settings.initialSys.remove(fmt::sprintf("id%d",sysCount-1));
|
||||
settings.initialSys.remove(fmt::sprintf("vol%d",sysCount-1));
|
||||
settings.initialSys.remove(fmt::sprintf("pan%d",sysCount-1));
|
||||
settings.initialSys.remove(fmt::sprintf("flags%d",sysCount-1));
|
||||
}
|
||||
|
||||
if (sysCount<32) if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) {
|
||||
settings.initialSys.set(fmt::sprintf("id%d",sysCount),(int)e->systemToFileFur(DIV_SYSTEM_YM2612));
|
||||
settings.initialSys.set(fmt::sprintf("vol%d",sysCount),64);
|
||||
settings.initialSys.set(fmt::sprintf("pan%d",sysCount),0);
|
||||
settings.initialSys.set(fmt::sprintf("flags%d",sysCount),"");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
|
@ -522,6 +546,7 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!");
|
||||
}
|
||||
|
||||
#ifndef IS_MOBILE
|
||||
bool noThreadedInputB=settings.noThreadedInput;
|
||||
if (ImGui::Checkbox("Disable threaded input (restart after changing!)",&noThreadedInputB)) {
|
||||
settings.noThreadedInput=noThreadedInputB;
|
||||
|
|
@ -537,6 +562,7 @@ void FurnaceGUI::drawSettings() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("remembers the window's last position on startup.");
|
||||
}
|
||||
#endif
|
||||
|
||||
bool blankInsB=settings.blankIns;
|
||||
if (ImGui::Checkbox("New instruments are blank",&blankInsB)) {
|
||||
|
|
@ -1318,6 +1344,23 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.susPosition=1;
|
||||
}
|
||||
|
||||
ImGui::Text("Macro editor layout:");
|
||||
if (ImGui::RadioButton("Unified##mel0",settings.macroLayout==0)) {
|
||||
settings.macroLayout=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Mobile##mel1",settings.macroLayout==1)) {
|
||||
settings.macroLayout=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Grid##mel2",settings.macroLayout==2)) {
|
||||
settings.macroLayout=2;
|
||||
}
|
||||
if (ImGui::RadioButton("Single (with list)##mel3",settings.macroLayout==3)) {
|
||||
settings.macroLayout=3;
|
||||
}
|
||||
if (ImGui::RadioButton("Single (combo box)##mel4",settings.macroLayout==4)) {
|
||||
settings.macroLayout=4;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Namco 163 chip name");
|
||||
|
|
@ -2397,6 +2440,7 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.persistFadeOut=e->getConfInt("persistFadeOut",1);
|
||||
settings.exportLoops=e->getConfInt("exportLoops",0);
|
||||
settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0);
|
||||
settings.macroLayout=e->getConfInt("macroLayout",0);
|
||||
|
||||
clampSetting(settings.mainFontSize,2,96);
|
||||
clampSetting(settings.patFontSize,2,96);
|
||||
|
|
@ -2503,6 +2547,7 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.centerPattern,0,1);
|
||||
clampSetting(settings.ordersCursor,0,1);
|
||||
clampSetting(settings.persistFadeOut,0,1);
|
||||
clampSetting(settings.macroLayout,0,4);
|
||||
|
||||
if (settings.exportLoops<0.0) settings.exportLoops=0.0;
|
||||
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
||||
|
|
@ -2675,6 +2720,7 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("persistFadeOut",settings.persistFadeOut);
|
||||
e->setConf("exportLoops",settings.exportLoops);
|
||||
e->setConf("exportFadeOut",settings.exportFadeOut);
|
||||
e->setConf("macroLayout",settings.macroLayout);
|
||||
|
||||
// colors
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
|
|
@ -3082,6 +3128,14 @@ void FurnaceGUI::popAccentColors() {
|
|||
#define SYSTEM_PAT_FONT_PATH_1 "/System/Library/Fonts/SFNSMono.ttf"
|
||||
#define SYSTEM_PAT_FONT_PATH_2 "/System/Library/Fonts/Courier New.ttf"
|
||||
#define SYSTEM_PAT_FONT_PATH_3 "/System/Library/Fonts/Courier New.ttf"
|
||||
#elif defined(ANDROID)
|
||||
#define SYSTEM_FONT_PATH_1 "/system/fonts/Roboto-Regular.ttf"
|
||||
#define SYSTEM_FONT_PATH_2 "/system/fonts/DroidSans.ttf"
|
||||
#define SYSTEM_FONT_PATH_3 "/system/fonts/DroidSans.ttf"
|
||||
// ???
|
||||
#define SYSTEM_PAT_FONT_PATH_1 "/system/fonts/RobotoMono-Regular.ttf"
|
||||
#define SYSTEM_PAT_FONT_PATH_2 "/system/fonts/DroidSansMono.ttf"
|
||||
#define SYSTEM_PAT_FONT_PATH_3 "/system/fonts/CutiveMono.ttf"
|
||||
#else
|
||||
#define SYSTEM_FONT_PATH_1 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
||||
#define SYSTEM_FONT_PATH_2 "/usr/share/fonts/TTF/DejaVuSans.ttf"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
case DIV_SYSTEM_YM2612_FRAC_EXT: {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
bool ladder=flags.getBool("ladderEffect",0);
|
||||
bool noExtMacros=flags.getBool("noExtMacros",false);
|
||||
|
||||
if (ImGui::RadioButton("NTSC (7.67MHz)",clockSel==0)) {
|
||||
clockSel=0;
|
||||
|
|
@ -56,11 +57,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
if (ImGui::Checkbox("Enable DAC distortion",&ladder)) {
|
||||
altered=true;
|
||||
}
|
||||
if (type==DIV_SYSTEM_YM2612_EXT || type==DIV_SYSTEM_YM2612_FRAC_EXT) {
|
||||
if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) {
|
||||
altered=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
flags.set("ladderEffect",ladder);
|
||||
flags.set("noExtMacros",noExtMacros);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
|
@ -439,6 +446,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610B_EXT: {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
bool noExtMacros=flags.getBool("noExtMacros",false);
|
||||
|
||||
if (ImGui::RadioButton("8MHz (Neo Geo MVS)",clockSel==0)) {
|
||||
clockSel=0;
|
||||
|
|
@ -449,9 +457,16 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
altered=true;
|
||||
}
|
||||
|
||||
if (type==DIV_SYSTEM_YM2610_EXT || type==DIV_SYSTEM_YM2610_FULL_EXT || type==DIV_SYSTEM_YM2610B_EXT) {
|
||||
if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) {
|
||||
altered=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
flags.set("noExtMacros",noExtMacros);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
|
@ -668,8 +683,23 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
break;
|
||||
}
|
||||
case DIV_SYSTEM_PCSPKR: {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
int speakerType=flags.getInt("speakerType",0);
|
||||
|
||||
ImGui::Text("Clock rate:");
|
||||
if (ImGui::RadioButton("1.19MHz (PC)",clockSel==0)) {
|
||||
clockSel=0;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton("1.99MHz (PC-98)",clockSel==1)) {
|
||||
clockSel=1;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton("2.46MHz (PC-98)",clockSel==2)) {
|
||||
clockSel=2;
|
||||
altered=true;
|
||||
}
|
||||
|
||||
ImGui::Text("Speaker type:");
|
||||
if (ImGui::RadioButton("Unfiltered",speakerType==0)) {
|
||||
speakerType=0;
|
||||
|
|
@ -690,6 +720,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
flags.set("speakerType",speakerType);
|
||||
});
|
||||
}
|
||||
|
|
@ -805,6 +836,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
case DIV_SYSTEM_OPN_EXT: {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
int prescale=flags.getInt("prescale",0);
|
||||
bool noExtMacros=flags.getBool("noExtMacros",false);
|
||||
|
||||
ImGui::Text("Clock rate:");
|
||||
if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) {
|
||||
|
|
@ -845,10 +877,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
altered=true;
|
||||
}
|
||||
|
||||
if (type==DIV_SYSTEM_OPN_EXT) {
|
||||
if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) {
|
||||
altered=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
flags.set("prescale",prescale);
|
||||
flags.set("noExtMacros",noExtMacros);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
|
@ -857,6 +896,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
case DIV_SYSTEM_PC98_EXT: {
|
||||
int clockSel=flags.getInt("clockSel",0);
|
||||
int prescale=flags.getInt("prescale",0);
|
||||
bool noExtMacros=flags.getBool("noExtMacros",false);
|
||||
|
||||
ImGui::Text("Clock rate:");
|
||||
if (ImGui::RadioButton("8MHz (Arcade)",clockSel==0)) {
|
||||
|
|
@ -881,10 +921,17 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
|||
altered=true;
|
||||
}
|
||||
|
||||
if (type==DIV_SYSTEM_PC98_EXT) {
|
||||
if (ImGui::Checkbox("Disable ExtCh FM macros (compatibility)",&noExtMacros)) {
|
||||
altered=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (altered) {
|
||||
e->lockSave([&]() {
|
||||
flags.set("clockSel",clockSel);
|
||||
flags.set("prescale",prescale);
|
||||
flags.set("noExtMacros",noExtMacros);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue