Merge branch 'master' of https://github.com/tildearrow/furnace into k053260
This commit is contained in:
commit
2a4e7267aa
26
README.md
26
README.md
|
@ -9,7 +9,9 @@ the biggest multi-system chiptune tracker ever made!
|
|||
---
|
||||
## downloads
|
||||
|
||||
check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage).
|
||||
check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux.
|
||||
|
||||
for other operating systems, you may [build the source](#developer-info).
|
||||
|
||||
[see here](https://nightly.link/tildearrow/furnace/workflows/build/master) for the latest unstable build.
|
||||
|
||||
|
@ -79,6 +81,7 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a
|
|||
- modern/fantasy:
|
||||
- Commander X16 VERA
|
||||
- tildearrow Sound Unit
|
||||
- Generic PCM DAC
|
||||
- mix and match sound chips!
|
||||
- over 200 ready to use presets from computers, game consoles and arcade boards...
|
||||
- ...or create your own - up to 32 of them or a total of 128 channels!
|
||||
|
@ -90,6 +93,7 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a
|
|||
- clean-room design (guesswork and ABX tests only, no decompilation involved)
|
||||
- some bug/quirk implementation for increased playback accuracy through compatibility flags
|
||||
- VGM export
|
||||
- ZSM export for Commander X16
|
||||
- modular layout that you may adapt to your needs
|
||||
- audio file export - entire song, per chip or per channel
|
||||
- quality emulation cores (Nuked, MAME, SameBoy, Mednafen PCE, NSFplay, puNES, reSID, Stella, SAASound, vgsound_emu and ymfm)
|
||||
|
@ -120,11 +124,11 @@ check out the [Releases](https://github.com/tildearrow/furnace/releases) page. a
|
|||
# quick references
|
||||
|
||||
- **discussion**: see the [Discussions](https://github.com/tildearrow/furnace/discussions) section, the [official Revolt](https://rvlt.gg/GRPS6tmc) or the [official Discord server](https://discord.gg/EfrwT2wq7z).
|
||||
- **help**: check out the [documentation](doc/README.md). it's incomplete though.
|
||||
- **help**: check out the [documentation](doc/README.md). it's about 80% complete.
|
||||
|
||||
## packages
|
||||
|
||||
[![Packaging status](https://repology.org/badge/tiny-repos/furnace.svg)](https://repology.org/project/furnace/versions)
|
||||
[![Packaging status](https://repology.org/badge/vertical-allrepos/furnace.svg)](https://repology.org/project/furnace/versions)
|
||||
|
||||
some people have provided packages for Unix/Unix-like distributions. here's a list.
|
||||
|
||||
|
@ -156,6 +160,7 @@ otherwise, you may also need the following:
|
|||
- libx11
|
||||
- libasound
|
||||
- libGL
|
||||
- any other libraries which may be used by SDL
|
||||
|
||||
some Linux distributions (e.g. Ubuntu or openSUSE) will require you to install the `-dev` versions of these.
|
||||
|
||||
|
@ -255,6 +260,17 @@ Available options:
|
|||
| `WITH_INSTRUMENTS` | `ON` | Install demo instruments on `make install` |
|
||||
| `WITH_WAVETABLES` | `ON` | Install wavetables on `make install` |
|
||||
|
||||
## CMake Error
|
||||
|
||||
if it says something about a missing subdirectory in `extern`, then either:
|
||||
|
||||
1. you didn't set up submodules, or
|
||||
2. you downloaded the source as a .zip or .tar.gz. don't do this.
|
||||
|
||||
if 1, you may run `git submodule update --init --recursive`. this will initialize submodules.
|
||||
|
||||
if 2, clone this repo.
|
||||
|
||||
## console usage
|
||||
|
||||
(note: if on Windows, type `furnace.exe` instead, or `Debug\furnace.exe` on MSVC)
|
||||
|
@ -289,7 +305,7 @@ this is due to Apple's application signing policy. a workaround is to right clic
|
|||
> it says "Furnace" is damaged and can't be opened!
|
||||
|
||||
**as of Monterey, this workaround no longer works (especially on ARM).** yeah, Apple has decided to be strict on the matter.
|
||||
if you happen to be on that version, use this workaround instead (on a Terminal):
|
||||
if you happen to be on that version (or later), use this workaround instead (on a Terminal):
|
||||
|
||||
```
|
||||
xattr -d com.apple.quarantine /path/to/Furnace.app
|
||||
|
@ -301,7 +317,7 @@ you may need to log out and/or reboot after doing this.
|
|||
|
||||
> where's the manual?
|
||||
|
||||
see [doc/](doc/README.md). it's kind of incomplete though.
|
||||
it is in [doc/](doc/README.md).
|
||||
|
||||
> is there a tutorial?
|
||||
|
||||
|
|
2
TODO.md
2
TODO.md
|
@ -1,4 +1,4 @@
|
|||
# to-do for 0.6pre6
|
||||
# to-do for 0.6pre7
|
||||
|
||||
- tutorial?
|
||||
- ease-of-use improvements... ideas:
|
||||
|
|
|
@ -15,8 +15,8 @@ android {
|
|||
}
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 26
|
||||
versionCode 158
|
||||
versionName "0.6pre5"
|
||||
versionCode 161
|
||||
versionName "0.6pre6"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.tildearrow.furnace"
|
||||
android:versionCode="158"
|
||||
android:versionName="0.6pre5"
|
||||
android:versionCode="161"
|
||||
android:versionName="0.6pre6"
|
||||
android:installLocation="auto">
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
|
|
|
@ -524,7 +524,15 @@ _wreaddir_r(
|
|||
entry->d_off = 0;
|
||||
entry->d_reclen = sizeof (struct _wdirent);
|
||||
|
||||
#ifdef _WIN64
|
||||
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow;
|
||||
#else
|
||||
if (datap->nFileSizeHigh) {
|
||||
entry->dwin_size = 0xffffffff;
|
||||
} else {
|
||||
entry->dwin_size = datap->nFileSizeLow;
|
||||
}
|
||||
#endif
|
||||
entry->dwin_mtime = datap->ftLastWriteTime;
|
||||
|
||||
/* Set result address */
|
||||
|
@ -817,7 +825,15 @@ readdir_r(
|
|||
entry->d_off = 0;
|
||||
entry->d_reclen = sizeof (struct dirent);
|
||||
|
||||
#ifdef _WIN64
|
||||
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow;
|
||||
#else
|
||||
if (datap->nFileSizeHigh) {
|
||||
entry->dwin_size = 0xffffffff;
|
||||
} else {
|
||||
entry->dwin_size = datap->nFileSizeLow;
|
||||
}
|
||||
#endif
|
||||
entry->dwin_mtime = datap->ftLastWriteTime;
|
||||
|
||||
} else {
|
||||
|
|
|
@ -361,9 +361,9 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
D3D11_SAMPLER_DESC desc;
|
||||
ZeroMemory(&desc, sizeof(desc));
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.MipLODBias = 0.f;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
desc.MinLOD = 0.f;
|
||||
|
|
|
@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 161: Furnace 0.6pre6
|
||||
- 160: Furnace dev160
|
||||
- 159: Furnace dev159
|
||||
- 158: Furnace 0.6pre5
|
||||
- 157: Furnace dev157
|
||||
|
|
|
@ -15,17 +15,17 @@
|
|||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>0.6pre5</string>
|
||||
<string>0.6pre6</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Furnace</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.6pre5</string>
|
||||
<string>0.6pre6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.6pre5</string>
|
||||
<string>0.6pre6</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
<p>
|
||||
it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability.
|
||||
</p>
|
||||
<p>
|
||||
<b>rationale for intense profanity:</b> the tracker itself is clean, but a few demo songs and instruments contain a small amount of strong language.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
<content_rating type="oars-1.0">
|
||||
|
|
|
@ -15,7 +15,7 @@ fi
|
|||
cd win32build
|
||||
|
||||
# TODO: potential Arch-ism?
|
||||
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON .. || exit 1
|
||||
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF .. || exit 1
|
||||
make -j8 || exit 1
|
||||
|
||||
cd ..
|
||||
|
|
|
@ -54,8 +54,8 @@
|
|||
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
|
||||
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev160"
|
||||
#define DIV_ENGINE_VERSION 160
|
||||
#define DIV_VERSION "0.6pre6"
|
||||
#define DIV_ENGINE_VERSION 161
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
|
|
@ -130,14 +130,15 @@ class DivPlatformOPN: public DivPlatformFMBase {
|
|||
unsigned char freqH, freqL;
|
||||
int portaPauseFreq;
|
||||
signed char konCycles;
|
||||
bool mask;
|
||||
bool mask, hardReset;
|
||||
OPNOpChannel():
|
||||
SharedChannel<int>(0),
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
portaPauseFreq(0),
|
||||
konCycles(0),
|
||||
mask(true) {}
|
||||
mask(true),
|
||||
hardReset(false) {}
|
||||
};
|
||||
|
||||
struct OPNOpChannelStereo: public OPNOpChannel {
|
||||
|
|
|
@ -397,6 +397,14 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
chan[c.chan].vol=chan[c.chan].envVol;
|
||||
chan[c.chan].outVol=chan[c.chan].envVol;
|
||||
}
|
||||
} else if (chan[c.chan].softEnv && c.chan!=2) {
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
chan[c.chan].envVol=chan[c.chan].outVol;
|
||||
}
|
||||
chan[c.chan].envLen=0;
|
||||
chan[c.chan].envDir=1;
|
||||
chan[c.chan].soundLen=64;
|
||||
}
|
||||
if (c.chan==2 && chan[c.chan].softEnv) {
|
||||
chan[c.chan].soundLen=64;
|
||||
|
@ -674,8 +682,6 @@ void DivPlatformGB::setFlags(const DivConfig& flags) {
|
|||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/16;
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
@ -686,6 +692,12 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, const DivConfig
|
|||
skipRegisterWrites=false;
|
||||
model=GB_MODEL_DMG_B;
|
||||
gb=new GB_gameboy_t;
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 4;
|
||||
|
|
|
@ -123,7 +123,9 @@ void DivPlatformGenesis::processDAC(int iRate) {
|
|||
chan[5].dacReady=false;
|
||||
}
|
||||
} else {
|
||||
urgentWrite(0x2a,0x80);
|
||||
if (chan[5].dacReady && writes.size()<16) {
|
||||
urgentWrite(0x2a,0x80);
|
||||
}
|
||||
}
|
||||
chan[5].dacPos++;
|
||||
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {
|
||||
|
|
|
@ -396,6 +396,9 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
opChan[ch].hardReset=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
|
|
@ -195,9 +195,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].pcm.sample=-1;
|
||||
rWrite(0x86+(c.chan<<3),3);
|
||||
chan[c.chan].macroInit(NULL);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
@ -207,6 +204,16 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].furnacePCM=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
|
||||
if (parent->song.newSegaPCM) {
|
||||
chan[c.chan].chVolL=(chan[c.chan].outVol*chan[c.chan].chPanL)/127;
|
||||
chan[c.chan].chVolR=(chan[c.chan].outVol*chan[c.chan].chPanR)/127;
|
||||
rWrite(2+(c.chan<<3),chan[c.chan].chVolL);
|
||||
rWrite(3+(c.chan<<3),chan[c.chan].chVolR);
|
||||
}
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
} else {
|
||||
|
|
|
@ -548,19 +548,25 @@ void DivPlatformSwan::poke(std::vector<DivRegWrite>& wlist) {
|
|||
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
void DivPlatformSwan::setFlags(const DivConfig& flags) {
|
||||
chipClock=3072000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/16; // = 192000kHz, should be enough
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
ws=new WSwan();
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 4;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ class DivPlatformSwan: public DivDispatch {
|
|||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyWaveChange(int wave);
|
||||
void notifyInsDeletion(void* ins);
|
||||
int getOutputCount();
|
||||
|
|
|
@ -82,6 +82,7 @@ const char* aboutLine[]={
|
|||
"Dippy",
|
||||
"djtuBIG-MaliceX",
|
||||
"dumbut",
|
||||
"Eknous-P",
|
||||
"ElectricKeet",
|
||||
"EpicTyphlosion",
|
||||
"FΛDE",
|
||||
|
|
|
@ -506,12 +506,26 @@ void FurnaceGUI::drawChanOsc() {
|
|||
text+=fmt::sprintf("%d",e->dispatchOfChan[ch]);
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
case 'v': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
text+=fmt::sprintf("%d",chanState->volume>>8);
|
||||
break;
|
||||
case 'V':
|
||||
}
|
||||
case 'V': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
int volMax=chanState->volMax>>8;
|
||||
if (volMax<1) volMax=1;
|
||||
text+=fmt::sprintf("%d%%",(chanState->volume>>8)/volMax);
|
||||
break;
|
||||
case 'b':
|
||||
}
|
||||
case 'b': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
text+=fmt::sprintf("%.2X",chanState->volume>>8);
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
text+='%';
|
||||
break;
|
||||
|
|
|
@ -6261,9 +6261,9 @@ bool FurnaceGUI::init() {
|
|||
logV("window size: %dx%d",scrW,scrH);
|
||||
|
||||
if (!initRender()) {
|
||||
if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) {
|
||||
settings.renderBackend="";
|
||||
e->setConf("renderBackend","");
|
||||
if (settings.renderBackend!="SDL") {
|
||||
settings.renderBackend="SDL";
|
||||
e->setConf("renderBackend","SDL");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
} else {
|
||||
|
@ -6362,9 +6362,9 @@ bool FurnaceGUI::init() {
|
|||
if (!rend->init(sdlWin)) {
|
||||
if (settings.renderBackend!="SDL") {
|
||||
settings.renderBackend="SDL";
|
||||
//e->setConf("renderBackend","");
|
||||
//e->saveConf();
|
||||
//lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
e->setConf("renderBackend","");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
} else {
|
||||
lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError());
|
||||
if (!settings.renderDriver.empty()) {
|
||||
|
|
Loading…
Reference in New Issue