Merge branch 'master' of https://github.com/tildearrow/furnace into k053260

This commit is contained in:
cam900 2023-07-09 13:11:53 +09:00
commit 2a4e7267aa
21 changed files with 126 additions and 42 deletions

View file

@ -9,7 +9,9 @@ the biggest multi-system chiptune tracker ever made!
--- ---
## downloads ## 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. [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: - modern/fantasy:
- Commander X16 VERA - Commander X16 VERA
- tildearrow Sound Unit - tildearrow Sound Unit
- Generic PCM DAC
- mix and match sound chips! - mix and match sound chips!
- over 200 ready to use presets from computers, game consoles and arcade boards... - 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! - ...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) - clean-room design (guesswork and ABX tests only, no decompilation involved)
- some bug/quirk implementation for increased playback accuracy through compatibility flags - some bug/quirk implementation for increased playback accuracy through compatibility flags
- VGM export - VGM export
- ZSM export for Commander X16
- modular layout that you may adapt to your needs - modular layout that you may adapt to your needs
- audio file export - entire song, per chip or per channel - 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) - 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 # 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). - **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 ## 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. 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 - libx11
- libasound - libasound
- libGL - 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. 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_INSTRUMENTS` | `ON` | Install demo instruments on `make install` |
| `WITH_WAVETABLES` | `ON` | Install wavetables 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 ## console usage
(note: if on Windows, type `furnace.exe` instead, or `Debug\furnace.exe` on MSVC) (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! > 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. **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 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? > 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? > is there a tutorial?

View file

@ -1,4 +1,4 @@
# to-do for 0.6pre6 # to-do for 0.6pre7
- tutorial? - tutorial?
- ease-of-use improvements... ideas: - ease-of-use improvements... ideas:

View file

@ -15,8 +15,8 @@ android {
} }
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 26
versionCode 158 versionCode 161
versionName "0.6pre5" versionName "0.6pre6"
externalNativeBuild { externalNativeBuild {
cmake { cmake {
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON" arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.tildearrow.furnace" package="org.tildearrow.furnace"
android:versionCode="158" android:versionCode="161"
android:versionName="0.6pre5" android:versionName="0.6pre6"
android:installLocation="auto"> android:installLocation="auto">
<!-- OpenGL ES 2.0 --> <!-- OpenGL ES 2.0 -->

View file

@ -524,7 +524,15 @@ _wreaddir_r(
entry->d_off = 0; entry->d_off = 0;
entry->d_reclen = sizeof (struct _wdirent); entry->d_reclen = sizeof (struct _wdirent);
#ifdef _WIN64
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow; 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; entry->dwin_mtime = datap->ftLastWriteTime;
/* Set result address */ /* Set result address */
@ -817,7 +825,15 @@ readdir_r(
entry->d_off = 0; entry->d_off = 0;
entry->d_reclen = sizeof (struct dirent); entry->d_reclen = sizeof (struct dirent);
#ifdef _WIN64
entry->dwin_size = ((size_t)datap->nFileSizeHigh<<32) | datap->nFileSizeLow; 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; entry->dwin_mtime = datap->ftLastWriteTime;
} else { } else {

View file

@ -361,9 +361,9 @@ static void ImGui_ImplDX11_CreateFontsTexture()
D3D11_SAMPLER_DESC desc; D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc)); ZeroMemory(&desc, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.MipLODBias = 0.f; desc.MipLODBias = 0.f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f; desc.MinLOD = 0.f;

View file

@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are: the format versions are:
- 161: Furnace 0.6pre6
- 160: Furnace dev160
- 159: Furnace dev159 - 159: Furnace dev159
- 158: Furnace 0.6pre5 - 158: Furnace 0.6pre5
- 157: Furnace dev157 - 157: Furnace dev157

View file

@ -15,17 +15,17 @@
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleLongVersionString</key> <key>CFBundleLongVersionString</key>
<string>0.6pre5</string> <string>0.6pre6</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>Furnace</string> <string>Furnace</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.6pre5</string> <string>0.6pre6</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.6pre5</string> <string>0.6pre6</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string></string> <string></string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>

View file

@ -18,6 +18,9 @@
<p> <p>
it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability. it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability.
</p> </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> </description>
<content_rating type="oars-1.0"> <content_rating type="oars-1.0">

View file

@ -15,7 +15,7 @@ fi
cd win32build cd win32build
# TODO: potential Arch-ism? # 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 make -j8 || exit 1
cd .. cd ..

View file

@ -54,8 +54,8 @@
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
#define DIV_VERSION "dev160" #define DIV_VERSION "0.6pre6"
#define DIV_ENGINE_VERSION 160 #define DIV_ENGINE_VERSION 161
// for imports // for imports
#define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02 #define DIV_VERSION_FC 0xff02

View file

@ -130,14 +130,15 @@ class DivPlatformOPN: public DivPlatformFMBase {
unsigned char freqH, freqL; unsigned char freqH, freqL;
int portaPauseFreq; int portaPauseFreq;
signed char konCycles; signed char konCycles;
bool mask; bool mask, hardReset;
OPNOpChannel(): OPNOpChannel():
SharedChannel<int>(0), SharedChannel<int>(0),
freqH(0), freqH(0),
freqL(0), freqL(0),
portaPauseFreq(0), portaPauseFreq(0),
konCycles(0), konCycles(0),
mask(true) {} mask(true),
hardReset(false) {}
}; };
struct OPNOpChannelStereo: public OPNOpChannel { struct OPNOpChannelStereo: public OPNOpChannel {

View file

@ -397,6 +397,14 @@ int DivPlatformGB::dispatch(DivCommand c) {
chan[c.chan].vol=chan[c.chan].envVol; chan[c.chan].vol=chan[c.chan].envVol;
chan[c.chan].outVol=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) { if (c.chan==2 && chan[c.chan].softEnv) {
chan[c.chan].soundLen=64; chan[c.chan].soundLen=64;
@ -674,8 +682,6 @@ void DivPlatformGB::setFlags(const DivConfig& flags) {
CHECK_CUSTOM_CLOCK; CHECK_CUSTOM_CLOCK;
rate=chipClock/16; rate=chipClock/16;
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
oscBuf[i]->rate=rate; oscBuf[i]->rate=rate;
} }
} }
@ -686,6 +692,12 @@ int DivPlatformGB::init(DivEngine* p, int channels, int sugRate, const DivConfig
skipRegisterWrites=false; skipRegisterWrites=false;
model=GB_MODEL_DMG_B; model=GB_MODEL_DMG_B;
gb=new GB_gameboy_t; gb=new GB_gameboy_t;
for (int i=0; i<4; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
setFlags(flags); setFlags(flags);
reset(); reset();
return 4; return 4;

View file

@ -123,7 +123,9 @@ void DivPlatformGenesis::processDAC(int iRate) {
chan[5].dacReady=false; chan[5].dacReady=false;
} }
} else { } else {
urgentWrite(0x2a,0x80); if (chan[5].dacReady && writes.size()<16) {
urgentWrite(0x2a,0x80);
}
} }
chan[5].dacPos++; chan[5].dacPos++;
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) { if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {

View file

@ -396,6 +396,9 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
} }
break; break;
} }
case DIV_CMD_FM_HARD_RESET:
opChan[ch].hardReset=c.value;
break;
case DIV_CMD_GET_VOLMAX: case DIV_CMD_GET_VOLMAX:
return 127; return 127;
break; break;

View file

@ -195,9 +195,6 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
chan[c.chan].pcm.sample=-1; chan[c.chan].pcm.sample=-1;
rWrite(0x86+(c.chan<<3),3); rWrite(0x86+(c.chan<<3),3);
chan[c.chan].macroInit(NULL); chan[c.chan].macroInit(NULL);
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
}
break; break;
} }
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -207,6 +204,16 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
} }
chan[c.chan].furnacePCM=true; chan[c.chan].furnacePCM=true;
chan[c.chan].macroInit(ins); 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].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
} else { } else {

View file

@ -548,19 +548,25 @@ void DivPlatformSwan::poke(std::vector<DivRegWrite>& wlist) {
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val); for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
} }
int DivPlatformSwan::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { void DivPlatformSwan::setFlags(const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;
chipClock=3072000; chipClock=3072000;
CHECK_CUSTOM_CLOCK; CHECK_CUSTOM_CLOCK;
rate=chipClock/16; // = 192000kHz, should be enough rate=chipClock/16; // = 192000kHz, should be enough
for (int i=0; i<4; i++) { for (int i=0; i<4; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
oscBuf[i]->rate=rate; 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(); ws=new WSwan();
setFlags(flags);
reset(); reset();
return 4; return 4;
} }

View file

@ -68,6 +68,7 @@ class DivPlatformSwan: public DivDispatch {
void forceIns(); void forceIns();
void tick(bool sysTick=true); void tick(bool sysTick=true);
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
void setFlags(const DivConfig& flags);
void notifyWaveChange(int wave); void notifyWaveChange(int wave);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
int getOutputCount(); int getOutputCount();

View file

@ -82,6 +82,7 @@ const char* aboutLine[]={
"Dippy", "Dippy",
"djtuBIG-MaliceX", "djtuBIG-MaliceX",
"dumbut", "dumbut",
"Eknous-P",
"ElectricKeet", "ElectricKeet",
"EpicTyphlosion", "EpicTyphlosion",
"FΛDE", "FΛDE",

View file

@ -506,12 +506,26 @@ void FurnaceGUI::drawChanOsc() {
text+=fmt::sprintf("%d",e->dispatchOfChan[ch]); text+=fmt::sprintf("%d",e->dispatchOfChan[ch]);
break; break;
} }
case 'v': case 'v': {
DivChannelState* chanState=e->getChanState(ch);
if (chanState==NULL) break;
text+=fmt::sprintf("%d",chanState->volume>>8);
break; 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; break;
case 'b': }
case 'b': {
DivChannelState* chanState=e->getChanState(ch);
if (chanState==NULL) break;
text+=fmt::sprintf("%.2X",chanState->volume>>8);
break; break;
}
case '%': case '%':
text+='%'; text+='%';
break; break;

View file

@ -6261,9 +6261,9 @@ bool FurnaceGUI::init() {
logV("window size: %dx%d",scrW,scrH); logV("window size: %dx%d",scrW,scrH);
if (!initRender()) { if (!initRender()) {
if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) { if (settings.renderBackend!="SDL") {
settings.renderBackend=""; settings.renderBackend="SDL";
e->setConf("renderBackend",""); e->setConf("renderBackend","SDL");
e->saveConf(); e->saveConf();
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
} else { } else {
@ -6362,9 +6362,9 @@ bool FurnaceGUI::init() {
if (!rend->init(sdlWin)) { if (!rend->init(sdlWin)) {
if (settings.renderBackend!="SDL") { if (settings.renderBackend!="SDL") {
settings.renderBackend="SDL"; settings.renderBackend="SDL";
//e->setConf("renderBackend",""); e->setConf("renderBackend","");
//e->saveConf(); e->saveConf();
//lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace."); lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
} else { } else {
lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError()); lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError());
if (!settings.renderDriver.empty()) { if (!settings.renderDriver.empty()) {