diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b1b68d7cd..01817d11b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -307,7 +307,7 @@ jobs: cp -v -r ../instruments new/instruments cp -v -r ../wavetables new/wavetables cd new - wget https://tildearrow.org/furproto/manual.pdf + wget https://tildearrow.org/furnace/doc/latest/manual.pdf cd .. hdiutil create -srcfolder new -volname Furnace -format UDZO furnace.dmg diff --git a/.gitignore b/.gitignore index e69bf71bb..09314bb24 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ CMakePresets.json extern/imgui_patched/examples/ src/asm/68k/amigatest/*.bin src/asm/68k/amigatest/player +src/check/calc_checksum res/binary_to_compressed_c res/binary_to_compressed_c.exe res/docpdf/manual.html diff --git a/README.md b/README.md index 26ce48094..de00c5ffe 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ for other operating systems, you may [build the source](#developer-info). ## features -- over 50 sound chips - and counting: +- a large selection of sound chips: - Yamaha FM chips: - YM2151 (OPM) - YM2203 (OPN) @@ -103,7 +103,7 @@ for other operating systems, you may [build the source](#developer-info). - quality emulation cores (Nuked, MAME, SameBoy, Mednafen PCE, NSFplay, puNES, reSID, Stella, SAASound, vgsound_emu and ymfm) - wavetable synthesizer - available on wavetable chips - - create complex sounds with ease - provide up to two wavetables, select and effect and let go! + - create complex sounds with ease - provide up to two wavetables, select an effect and let go! - MIDI input support - additional features: - FM macros! @@ -327,7 +327,7 @@ it is in [doc/](doc/README.md). > is there a tutorial? -sadly, the in-program tutorial isn't ready yet. however, [a video tutorial is available on YouTube](https://youtube.com/playlist?list=PLCELB6AsTZUnwv0PC5AAGHjvg47F44YQ1), made by Spinning Square Waves. +[a video tutorial (of a previous version) is available on YouTube](https://youtube.com/playlist?list=PLCELB6AsTZUnwv0PC5AAGHjvg47F44YQ1), made by Spinning Square Waves. > I've lost my song! diff --git a/android/app/build.gradle b/android/app/build.gradle index 8939a6d1d..1b09780c5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 178 - versionName "0.6pre16" + versionCode 181 + versionName "0.6" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5a99f3cb1..a8b2007b1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/demos/arcade/Hexionology.fur b/demos/arcade/Hexionology.fur new file mode 100644 index 000000000..2de916de8 Binary files /dev/null and b/demos/arcade/Hexionology.fur differ diff --git a/demos/ay8910/Drifting in Colour.fur b/demos/ay8910/Drifting in Colour.fur new file mode 100644 index 000000000..5392419c2 Binary files /dev/null and b/demos/ay8910/Drifting in Colour.fur differ diff --git a/demos/ay8910/cardboardmywater.fur b/demos/ay8910/cardboardmywater.fur new file mode 100644 index 000000000..9f67d1ca6 Binary files /dev/null and b/demos/ay8910/cardboardmywater.fur differ diff --git a/demos/genesis/All Good Times.fur b/demos/genesis/All Good Times.fur new file mode 100644 index 000000000..e5ab47351 Binary files /dev/null and b/demos/genesis/All Good Times.fur differ diff --git a/demos/msx/attack_the_barbarian.fur b/demos/msx/attack_the_barbarian.fur new file mode 100644 index 000000000..b5d77ad29 Binary files /dev/null and b/demos/msx/attack_the_barbarian.fur differ diff --git a/demos/opl/attack_the_barbarian_opl.fur b/demos/opl/attack_the_barbarian_opl.fur deleted file mode 100644 index f0df49f0e..000000000 Binary files a/demos/opl/attack_the_barbarian_opl.fur and /dev/null differ diff --git a/demos/snes/IMU Café.fur b/demos/snes/IMU Café.fur new file mode 100644 index 000000000..4017e472f Binary files /dev/null and b/demos/snes/IMU Café.fur differ diff --git a/demos/snes/Sadness.fur b/demos/snes/Sadness.fur new file mode 100644 index 000000000..bae0cb6ce Binary files /dev/null and b/demos/snes/Sadness.fur differ diff --git a/doc/4-instrument/fm-opz.md b/doc/4-instrument/fm-opz.md index d6a400e63..26ee11946 100644 --- a/doc/4-instrument/fm-opz.md +++ b/doc/4-instrument/fm-opz.md @@ -53,7 +53,7 @@ these apply to each operator: - does not apply for OP4. - **Reverb (REV)**: not a true reverb. extends release time, giving a slight reverb-like effect to the operator. - **Fine Detune (DT)**: shifts the pitch a little (0 to 7). -- **Waveform Select (WS)**: changes the waveform of the operator (OPL2 and OPL3 only, 0-3 range on OPL2 and 0-7 on OPL3). +- **Waveform Select (WS)**: changes the waveform of the operator. - **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3). #### I am familiar with Yamaha TX81Z. where's LS and KVS? diff --git a/doc/4-instrument/wsg.md b/doc/4-instrument/wsg.md index 5c32f50b2..eb379ff04 100644 --- a/doc/4-instrument/wsg.md +++ b/doc/4-instrument/wsg.md @@ -11,7 +11,7 @@ this allows you to enable and configure the Furnace wavetable synthesizer. see [ - **Volume**: volume sequence. - **Arpeggio**: pitch sequence. - **Noise**: specifies noise pitch. - - only applicable for Namco C30, and even so, only on the last 4 channels. + - only applicable for Namco C30. - **Waveform**: specifies wavetable sequence. - **Panning (left)**: output level of left channel. - Namco C30 only. diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 539dbbf0a..a7d9382fd 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -39,6 +39,14 @@ the following sound chips have sample support: - Namco C140 - Namco C219 +## using samples + +the simplest path to using a sample is: +- in the sample list, use the "Open" button (folder icon) to load the sample. +- double-click the sample in the list to open it in the sample editor. +- click the "Create instrument from sample" button (upload icon, to the left of "Zoom"). +- use the created instrument in the track. + ## compatible sample mode (LEGACY) **use of this mode is discouraged in favor of Sample type instruments.** diff --git a/doc/README.md b/doc/README.md index 3e6652c13..4241b92c4 100644 --- a/doc/README.md +++ b/doc/README.md @@ -16,11 +16,13 @@ the index follows. ## authors +- brickblock369 - cam900 - DeMOSic - Electric Keet - freq-mod - host12prog +- Lunathir - nicco1690 - tildearrow diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index a7c1c2b89..b53cdf7d6 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -3859,7 +3859,7 @@ namespace IGFD } } #endif - for (const char* i=n; *i; i++) { + for (const unsigned char* i=(const unsigned char*)n; *i; i++) { #ifdef _WIN32 if (*i<32) { return 3; diff --git a/papers/clipboard-format.md b/papers/clipboard-format.md index ec6378837..06d1c4f4a 100644 --- a/papers/clipboard-format.md +++ b/papers/clipboard-format.md @@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te org.tildearrow.furnace - Pattern Data (144) ``` -this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre16 is `178`. +this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6 is `181`. the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from. - `0`: note. diff --git a/papers/format.md b/papers/format.md index f2281f43d..175183ee4 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,9 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 181: Furnace 0.6 +- 180: Furnace 0.6pre18 +- 179: Furnace 0.6pre17 - 178: Furnace 0.6pre16 - 177: Furnace 0.6pre15 - 175: Furnace 0.6pre14 diff --git a/res/Info.plist b/res/Info.plist index da4c26491..3eeb8ae02 100644 --- a/res/Info.plist +++ b/res/Info.plist @@ -15,17 +15,17 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 0.6pre16 + 0.6 CFBundleName Furnace CFBundlePackageType APPL CFBundleShortVersionString - 0.6pre16 + 0.6 CFBundleSignature ???? CFBundleVersion - 0.6pre16 + 0.6 NSHumanReadableCopyright NSHighResolutionCapable diff --git a/res/docpdf/make_paper.py b/res/docpdf/make_paper.py index c02b1eca7..10de2e1f5 100644 --- a/res/docpdf/make_paper.py +++ b/res/docpdf/make_paper.py @@ -334,11 +334,13 @@ if __name__ == "__main__":

authors

diff --git a/scripts/release-linux.sh b/scripts/release-linux.sh index a87602536..08c7f73cc 100755 --- a/scripts/release-linux.sh +++ b/scripts/release-linux.sh @@ -52,7 +52,7 @@ cd .. cp ../../../LICENSE . || exit 1 cp ../../../res/releaseReadme/stable-linux.txt README.md || exit 1 cp -r ../../../papers papers || exit 1 -curl "https://tildearrow.org/furproto/manual.pdf" > manual.pdf +curl "https://tildearrow.org/furnace/doc/latest/manual.pdf" > manual.pdf rmdir usr || exit 1 strip -s furnace diff --git a/scripts/release-win32.sh b/scripts/release-win32.sh index 58e3fb38f..604e17251 100755 --- a/scripts/release-win32.sh +++ b/scripts/release-win32.sh @@ -35,7 +35,7 @@ cp ../../res/docpdf/manual.pdf . || exit 1 i686-w64-mingw32-strip -s furnace.exe || exit 1 -zip -r furnace.zip LICENSE.txt furnace.exe README.txt papers doc demos instruments wavetables +zip -r furnace.zip LICENSE.txt furnace.exe README.txt manual.pdf papers demos instruments wavetables furName=$(git describe --tags | sed "s/v0/0/") diff --git a/scripts/release-win64.sh b/scripts/release-win64.sh index 482c1698c..edd4007fc 100755 --- a/scripts/release-win64.sh +++ b/scripts/release-win64.sh @@ -35,7 +35,7 @@ cp ../../res/docpdf/manual.pdf . || exit 1 x86_64-w64-mingw32-strip -s furnace.exe || exit 1 -zip -r furnace.zip LICENSE.txt furnace.exe README.txt papers doc demos instruments wavetables +zip -r furnace.zip LICENSE.txt furnace.exe README.txt manual.pdf papers demos instruments wavetables furName=$(git describe --tags | sed "s/v0/0/") diff --git a/scripts/release-winxp.sh b/scripts/release-winxp.sh index 91b4397cd..71ff675ea 100755 --- a/scripts/release-winxp.sh +++ b/scripts/release-winxp.sh @@ -40,7 +40,7 @@ xxd -c 256 -ps furnace.exe | sed "s/4765745469636b436f756e743634/4765745469636b4 rm furnace.exe mv furnace-patched.exe furnace.exe -zip -r furnace.zip LICENSE.txt furnace.exe README.txt papers doc demos instruments wavetables +zip -r furnace.zip LICENSE.txt furnace.exe README.txt manual.pdf papers demos instruments wavetables furName=$(git describe --tags | sed "s/v0/0/") diff --git a/src/engine/engine.h b/src/engine/engine.h index 1fd054635..734d10daf 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -52,10 +52,10 @@ class DivWorkPool; #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; -#define DIV_UNSTABLE +//#define DIV_UNSTABLE -#define DIV_VERSION "0.6pre16" -#define DIV_ENGINE_VERSION 178 +#define DIV_VERSION "0.6" +#define DIV_ENGINE_VERSION 181 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index 1fb503543..4a44d0192 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -464,6 +464,13 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, accum/=channels; sample->data8[i]=accum; } + if (bigEndian) { + for (unsigned int i=0; (i+1)data8[i]^=sample->data8[i^1]; + sample->data8[i^1]^=sample->data8[i]; + sample->data8[i]^=sample->data8[i^1]; + } + } } else { memcpy(sample->getCurBuf(),buf,len); } diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index 30ec91f0d..9e144c663 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -245,10 +245,10 @@ void DivPlatformC140::tick(bool sysTick) { if (chan[i].sample>=0 && chan[i].samplesong.sampleLen && s->isLoopable()) { if (is219) { loop=MIN(start+(s->loopStart>>1),65535); - end=MIN(start+(s->loopEnd>>1)-1,65535); + end=MIN(start+(s->loopEnd>>1),65535); } else { - loop=MIN(start+s->loopStart,65535); - end=MIN(start+s->loopEnd-1,65535); + loop=MIN(start+s->loopStart+1,65535); + end=MIN(start+s->loopEnd+1,65535); } } else if (chan[i].noise && is219) { loop=0; @@ -575,7 +575,7 @@ void DivPlatformC140::renderSamples(int sysID) { } if (is219) { // C219 (8-bit) - unsigned int length=s->length8; + unsigned int length=s->length8+4; // fit sample size to single bank size if (length>131072) { length=131072; @@ -594,27 +594,39 @@ void DivPlatformC140::renderSamples(int sysID) { logW("out of C219 memory for sample %d!",i); } if (s->depth==DIV_SAMPLE_DEPTH_C219) { + unsigned char next=0; + unsigned int sPos=0; for (unsigned int i=0; i=s->lengthC219) { - sampleMem[(memPos+i)^1]=0; - } else { - sampleMem[(memPos+i)^1]=s->dataC219[i]; + if (sPoslengthC219) { + next=s->dataC219[sPos++]; + if (s->isLoopable()) { + if ((int)sPos>=s->loopEnd) { + sPos=s->loopStart; + } + } } + sampleMem[(memPos+i)^1]=next; } } else { + signed char next=0; + unsigned int sPos=0; for (unsigned int i=0; i=s->length8) { - sampleMem[(memPos+i)^1]=0; - } else { - sampleMem[(memPos+i)^1]=s->data8[i]; + if (sPoslength8) { + next=s->data8[sPos++]; + if (s->isLoopable()) { + if ((int)sPos>=s->loopEnd) { + sPos=s->loopStart; + } + } } + sampleMem[(memPos+i)^1]=next; } } sampleOff[i]=memPos>>1; sampleLoaded[i]=true; memPos+=length; } else { // C140 (16-bit) - unsigned int length=s->length16; + unsigned int length=s->length16+4; // fit sample size to single bank size if (length>(131072)) { length=131072; @@ -641,7 +653,20 @@ void DivPlatformC140::renderSamples(int sysID) { sampleMem[1+i+memPos]=c140Mu; } } else { - memcpy(sampleMem+memPos,s->data16,length); + short next=0; + unsigned int sPos=0; + for (unsigned int i=0; isamples) { + next=s->data16[sPos++]; + if (s->isLoopable()) { + if ((int)sPos>=s->loopEnd) { + sPos=s->loopStart; + } + } + } + sampleMem[memPos+i]=((unsigned short)next); + sampleMem[memPos+i+1]=((unsigned short)next)>>8; + } } sampleOff[i]=memPos>>1; sampleLoaded[i]=true; diff --git a/src/engine/platform/k007232.cpp b/src/engine/platform/k007232.cpp index b2a09057a..b2d92e2fc 100644 --- a/src/engine/platform/k007232.cpp +++ b/src/engine/platform/k007232.cpp @@ -431,7 +431,7 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) { } unsigned short DivPlatformK007232::getPan(int ch) { - return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4); + return stereo?(((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4)):0; } DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) { diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index f6b6d062a..0aa4bbd94 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -201,7 +201,7 @@ void DivPlatformNamcoWSG::tick(bool sysTick) { if (chan[i].std.vol.had) { chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; } - if (chan[i].std.duty.had && i>=4) { + if (chan[i].std.duty.had) { chan[i].noise=chan[i].std.duty.val; chan[i].freqChanged=true; } @@ -418,6 +418,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) { } case DIV_CMD_STD_NOISE_MODE: chan[c.chan].noise=c.value; + chan[c.chan].freqChanged=true; break; case DIV_CMD_PANNING: { chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4); diff --git a/src/engine/platform/sound/c140_c219.c b/src/engine/platform/sound/c140_c219.c index 56d96ca19..84e590f14 100644 --- a/src/engine/platform/sound/c140_c219.c +++ b/src/engine/platform/sound/c140_c219.c @@ -104,7 +104,7 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle if (!voice->muted) { // fetch 12 bit sample - signed short s1 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | voice->addr] & ~0xf; + signed short s1 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | (voice->addr & 0xffff)] & ~0xf; signed short s2 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | ((voice->addr + 1) & 0xffff)] & ~0xf; if (voice->compressed) { @@ -171,7 +171,7 @@ void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle else { // fetch 8 bit sample - signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | (voice->addr^1)]; + signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | ((voice->addr^1) & 0x1ffff)]; signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | (((voice->addr + 1) & 0x1ffff)^1)]; if (voice->compressed) { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 17ab8cfc3..6b1365e4d 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1708,6 +1708,10 @@ void DivEngine::registerSystems() { EffectHandlerMap namcoEffectHandlerMap={ {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + }; + + EffectHandlerMap namcoC30EffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, }; @@ -1741,7 +1745,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, {}, - namcoEffectHandlerMap + namcoC30EffectHandlerMap ); sysDefs[DIV_SYSTEM_MSM5232]=new DivSysDef( diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 01dd2cb7c..599f56876 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1747,13 +1747,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p if (!hasRFC1) { hasRFC1=disCont[i].dispatch->chipClock; isSecond[i]=true; - CHIP_VOL(16,1.6); + CHIP_VOL(16,0.8); willExport[i]=true; writeRF5C68[1]=disCont[i].dispatch; } } else if (!hasRFC) { hasRFC=disCont[i].dispatch->chipClock; - CHIP_VOL(5,1.6); + CHIP_VOL(5,1.1); willExport[i]=true; writeRF5C68[0]=disCont[i].dispatch; } @@ -2418,8 +2418,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p } while (!done) { if (loopPos==-1) { - if (loopOrder==curOrder && loopRow==curRow && ticks==1) { - writeLoop=true; + if (loopOrder==curOrder && loopRow==curRow) { + if ((ticks-((tempoAccum+curSubSong->virtualTempoN)/curSubSong->virtualTempoD))<=0) { + writeLoop=true; + } } } songTick++; diff --git a/src/engine/wavOps.cpp b/src/engine/wavOps.cpp index 489426d9d..b3cd8ec80 100644 --- a/src/engine/wavOps.cpp +++ b/src/engine/wavOps.cpp @@ -106,7 +106,6 @@ void DivEngine::runExportThread() { if (sfWrap.doClose()!=0) { logE("could not close audio file!"); } - exporting=false; if (initAudioBackend()) { for (int i=0; i bool FixedQueue::pop() { template bool FixedQueue::push(const T& item) { if (writePos==(readPos-1)) { - logW("queue overflow!"); + //logW("queue overflow!"); return false; } if (writePos==items-1 && readPos==0) { - logW("queue overflow!"); + //logW("queue overflow!"); return false; } data[writePos]=item; @@ -121,11 +121,11 @@ template bool FixedQueue::pop_front() { template bool FixedQueue::push_back(const T& item) { if (writePos==(readPos-1)) { - logW("queue overflow!"); + //logW("queue overflow!"); return false; } if (writePos==items-1 && readPos==0) { - logW("queue overflow!"); + //logW("queue overflow!"); return false; } data[writePos]=item; @@ -145,11 +145,11 @@ template bool FixedQueue::pop_back() { template bool FixedQueue::push_front(const T& item) { if (readPos==(writePos+1)) { - logW("stack overflow!"); + //logW("stack overflow!"); return false; } if (readPos==0 && writePos==items-1) { - logW("stack overflow!"); + //logW("stack overflow!"); return false; } if (readPos>0) { diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 6b13b66ce..e3a699ba1 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -30,9 +30,6 @@ const char* aboutLine[]={ "the biggest multi-system chiptune tracker!", "featuring DefleMask song compatibility.", "", - "this is a version released during The Freeze.", - "please report any issues you find!", - "", "> CREDITS <", "", "-- program --", @@ -57,20 +54,21 @@ const char* aboutLine[]={ "Raijin", "", "-- documentation --", - "tildearrow", - "freq-mod", - "nicco1690", - "DeMOSic", + "brickblock369", "cam900", - "host12prog", - "WindowxDeveloper", - "polluks", + "DeMOSic", "Electric Keet", + "freq-mod", + "host12prog", + "Lunathir", + "nicco1690", + "tildearrow", "", "-- demo songs --", "0x5066", "Abstract 64", "ActualNK358", + "airconmanws", "akumanatt", "AmigaX", "AURORA*FIELDS", @@ -123,10 +121,12 @@ const char* aboutLine[]={ "psxdominator", "Raijin", "railzen7", + "RevvoBolt", "SnugglyBun", "SuperJet Spade", "SwapXFO", "TakuikaNinja", + "tapekeep", "TCORPStudios", "Teuthida", "ThaCuber", diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 2786e536e..b26e773f0 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -584,6 +584,10 @@ void FurnaceGUI::drawMobileControls() { if (ImGui::Button("Stats")) { statsOpen=!statsOpen; } + ImGui::SameLine(); + if (ImGui::Button("Grooves")) { + groovesOpen=!groovesOpen; + } if (ImGui::Button("Compat Flags")) { compatFlagsOpen=!compatFlagsOpen; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c81e552c1..08f5ca9f0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3584,6 +3584,9 @@ bool FurnaceGUI::loop() { SDL_free(ev.drop.file); } break; + case SDL_USEREVENT: + // used for MIDI wake up + break; case SDL_QUIT: if (modified) { showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT); @@ -3647,6 +3650,7 @@ bool FurnaceGUI::loop() { while (true) { midiLock.lock(); + midiWakeUp=true; if (midiQueue.empty()) { midiLock.unlock(); break; @@ -4542,6 +4546,7 @@ bool FurnaceGUI::loop() { MEASURE(readOsc,readOsc()); MEASURE(osc,drawOsc()); MEASURE(chanOsc,drawChanOsc()); + MEASURE(grooves,drawGrooves()); MEASURE(regView,drawRegView()); } else { globalWinFlags=0; @@ -5870,8 +5875,6 @@ bool FurnaceGUI::loop() { if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) { pendingRawSampleChannels=1; - } - if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) { pendingRawSampleBigEndian=false; } @@ -5898,6 +5901,10 @@ bool FurnaceGUI::loop() { ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles); } + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_8BIT) { + ImGui::Checkbox("Swap words",&pendingRawSampleBigEndian); + } + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) { ImGui::Text("Encoding:"); ImGui::Indent(); @@ -6729,11 +6736,20 @@ bool FurnaceGUI::init() { firstFrame=true; - // TODO: MIDI mapping time! + userEvents=SDL_RegisterEvents(1); + e->setMidiCallback([this](const TAMidiMessage& msg) -> int { if (introPos<11.0) return -2; midiLock.lock(); midiQueue.push(msg); + if (userEvents!=0xffffffff && midiWakeUp) { + midiWakeUp=false; + userEvent.user.type=userEvents; + userEvent.user.code=0; + userEvent.user.data1=NULL; + userEvent.user.data2=NULL; + SDL_PushEvent(&userEvent); + } midiLock.unlock(); e->setMidiBaseChan(cursor.xCoarse); if (msg.type==TA_MIDI_SYSEX) return -2; @@ -7013,6 +7029,7 @@ FurnaceGUI::FurnaceGUI(): displayEditString(false), mobileEdit(false), killGraphics(false), + midiWakeUp(true), audioEngineChanged(false), settingsChanged(false), debugFFT(false), @@ -7026,6 +7043,8 @@ FurnaceGUI::FurnaceGUI(): mobileEditPage(0), wheelCalmDown(0), shallDetectScale(0), + cpuCores(0), + userEvents(0xffffffff), mobileMenuPos(0.0f), autoButtonSize(0.0f), mobileEditAnim(0.0f), diff --git a/src/gui/gui.h b/src/gui/gui.h index 0c495a6ee..f0e2e7555 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1345,6 +1345,7 @@ class FurnaceGUI { bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString; bool mobileEdit; bool killGraphics; + bool midiWakeUp; bool audioEngineChanged, settingsChanged, debugFFT; bool willExport[DIV_MAX_CHIPS]; int vgmExportVersion; @@ -1358,6 +1359,7 @@ class FurnaceGUI { int wheelCalmDown; int shallDetectScale; int cpuCores; + unsigned int userEvents; float mobileMenuPos, autoButtonSize, mobileEditAnim; ImVec2 mobileEditButtonPos, mobileEditButtonSize; const int* curSysSection; @@ -1371,6 +1373,7 @@ class FurnaceGUI { void* fmPreviewOPZ; void* fmPreviewOPZInterface; String* editString; + SDL_Event userEvent; String pendingRawSample; int pendingRawSampleDepth, pendingRawSampleChannels; diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index c6069477a..954c29496 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -120,8 +120,8 @@ const int vgmVersions[7]={ // name, icon, letter icon const char* insTypes[DIV_INS_MAX+1][3]={ - {"SN76489/Sega PSG",ICON_FA_AREA_CHART,ICON_FUR_INS_STD}, - {"FM (OPN)",ICON_FA_BAR_CHART,ICON_FUR_INS_FM}, + {"SN76489/Sega PSG",ICON_FA_BAR_CHART,ICON_FUR_INS_STD}, + {"FM (OPN)",ICON_FA_AREA_CHART,ICON_FUR_INS_FM}, {"Game Boy",ICON_FA_GAMEPAD,ICON_FUR_INS_GB}, {"C64",ICON_FA_KEYBOARD_O,ICON_FUR_INS_C64}, {"Generic Sample",ICON_FA_VOLUME_UP,ICON_FUR_INS_AMIGA}, diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 51ea3cb01..086793ae0 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -3093,6 +3093,7 @@ void FurnaceGUI::drawSettings() { // "42 63" - enables all instrument types // "4-bit FDS" - enables partial pitch linearity option // "Power of the Chip" - enables options for multi-threaded audio + // "btcdbcb" - use modern UI padding // "????" - enables stuff CONFIG_SECTION("Cheat Codes") { // SUBSECTION ENTER CODE: @@ -3131,6 +3132,14 @@ void FurnaceGUI::drawSettings() { mmlString[30]="unlocked audio multi-threading options!"; settings.showPool=1; } + if (checker==0x94222d83 && checker1==0x6600) { + mmlString[30]="enabled \"comfortable\" mode"; + ImGuiStyle& sty=ImGui::GetStyle(); + sty.FramePadding=ImVec2(20.0f*dpiScale,20.0f*dpiScale); + sty.ItemSpacing=ImVec2(10.0f*dpiScale,10.0f*dpiScale); + sty.ItemInnerSpacing=ImVec2(10.0f*dpiScale,10.0f*dpiScale); + settingsOpen=false; + } mmlString[31]=""; } diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index ea753205a..ef98a9533 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -273,7 +273,7 @@ void FurnaceGUI::drawTutorial() { ImGui::TextWrapped( "if you need help, you may:\n" - "- read the (incomplete) manual: https://github.com/tildearrow/furnace/blob/master/doc/README.md\n" + "- read the manual (a file called manual.pdf)\n" "- ask for help in Discussions (https://github.com/tildearrow/furnace/discussions), the Furnace Discord (https://discord.gg/EfrwT2wq7z) or Furnace in Revolt (https://rvlt.gg/GRPS6tmc)" );