diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2646eb8d4..01817d11b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: pushd ${{ steps.package-identify.outputs.filename }} cp -v ../LICENSE LICENSE.txt - cp -v ../README.md README.txt + cp -v ../res/releaseReadme/unstable-win.txt README.txt cp -vr ../papers ../${binPath}/furnace.exe ./ if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then cp -v ../${binPath}/furnace.pdb ./ @@ -285,7 +285,34 @@ jobs: run: | pushd build cpack - mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} + + mkdir orig + mkdir new + echo "y" | hdiutil attach Furnace-*-Darwin.dmg -readonly -mount required -mountpoint orig + + cp -v -r orig/Furnace.app new/Furnace.app + hdiutil detach orig + + rmdir orig + rm Furnace-*-Darwin.dmg + + if [ -e new/Furnace.app/Contents/Resources/bin/furnace ]; then + rm -v new/Furnace.app/Contents/Resources/bin/furnace + rmdir new/Furnace.app/Contents/Resources/bin + fi + + cp -v ../LICENSE new/LICENSE.txt + cp -v ../res/releaseReadme/stable-mac.txt new/README + cp -v -r ../demos new/demos + cp -v -r ../instruments new/instruments + cp -v -r ../wavetables new/wavetables + cd new + wget https://tildearrow.org/furnace/doc/latest/manual.pdf + cd .. + + hdiutil create -srcfolder new -volname Furnace -format UDZO furnace.dmg + + mv furnace.dmg ../${{ steps.package-identify.outputs.filename }} popd - name: Package [Linux] @@ -317,7 +344,7 @@ jobs: cd .. cp ../../LICENSE . - cp ../../README.md . + cp ../../res/releaseReadme/unstable-other.txt . cp -r ../../papers papers rmdir usr diff --git a/.gitignore b/.gitignore index 6bd68968c..09314bb24 100644 --- a/.gitignore +++ b/.gitignore @@ -27,9 +27,11 @@ 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 res/docpdf/manual.pdf res/docpdf/.venv +res/docpdf/htmldoc/ res/furnace.appdata.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e0e76f9e..6fd435f28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ project(furnace) if (APPLE) enable_language(OBJC) + enable_language(OBJCXX) endif() set(CMAKE_CXX_STANDARD 14) @@ -448,6 +449,9 @@ extern/Nuked-PSG/ympsg.c extern/opm/opm.c extern/Nuked-OPLL/opll.c extern/opl/opl3.c + +src/pch.cpp + src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/ay8910.cpp src/engine/platform/sound/saa1099.cpp @@ -965,6 +969,21 @@ if (PKG_CONFIG_FOUND AND (SYSTEM_FMT OR SYSTEM_LIBSNDFILE OR SYSTEM_ZLIB OR SYST endif() endif() +# why 3.16..... why not 3.0? +if (NOT "${CMAKE_VERSION}" VERSION_LESS "3.16") + if (BUILD_GUI) + target_precompile_headers(furnace PUBLIC + $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui.h> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui_internal.h> + ) + else() + target_precompile_headers(furnace PUBLIC + $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h> + ) + endif() +endif() + if (NOT ANDROID OR TERMUX) if (NOT WIN32 AND NOT APPLE) include(GNUInstallDirs) 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/nes/Sky Sanctuary Zone.fur b/demos/nes/Sky Sanctuary Zone.fur new file mode 100644 index 000000000..c719ee285 Binary files /dev/null and b/demos/nes/Sky Sanctuary Zone.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/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index e7966cab4..97a458696 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -2550,6 +2550,8 @@ struct ImGuiListClipper // - It is important that we are keeping those disabled by default so they don't leak in user space. // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) // - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. +#define IMGUI_DEFINE_MATH_OPERATORS + #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index 90e28ec3c..5bd95013b 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -7,6 +7,12 @@ #ifdef __MINGW32__ // Explicitly setting NTDDI version, this is necessary for the MinGW compiler +#ifdef NTDDI_VERSION +#undef NTDDI_VERSION +#endif +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif #define NTDDI_VERSION NTDDI_VISTA #define _WIN32_WINNT _WIN32_WINNT_VISTA #endif 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-doc-html.sh b/res/docpdf/make-doc-html.sh new file mode 100755 index 000000000..3af163f43 --- /dev/null +++ b/res/docpdf/make-doc-html.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +echo "compiling Furnace doc (HTML)..." + +if [ -e htmldoc ]; then + rm -r htmldoc +fi + +if [ ! -e .venv ]; then + python3 -m virtualenv .venv || exit 1 +fi + +source .venv/bin/activate + +if [ ! -e .venv/req_installed ]; then + pip install -r requirements.txt || exit 1 + touch .venv/req_installed +fi + +python3 make_htmldoc.py + +echo "copying assets..." +for i in `find ../../doc -name "*.png"`; do + cp "$i" "htmldoc${i#../../doc}" +done diff --git a/res/docpdf/make-doc-pdf.sh b/res/docpdf/make-doc-pdf.sh index 91d018d45..c5d53ae16 100755 --- a/res/docpdf/make-doc-pdf.sh +++ b/res/docpdf/make-doc-pdf.sh @@ -1,6 +1,6 @@ #!/bin/bash -echo "compiling Furnace doc..." +echo "compiling Furnace doc (PDF)..." if [ ! -e .venv ]; then python3 -m virtualenv .venv || exit 1 diff --git a/res/docpdf/make_htmldoc.py b/res/docpdf/make_htmldoc.py new file mode 100644 index 000000000..18be36d73 --- /dev/null +++ b/res/docpdf/make_htmldoc.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +import os +import sys + +import markdown +from mdx_gfm import GithubFlavoredMarkdownExtension + +import re + +import logging +logging.basicConfig(format='%(levelname)s: %(message)s' ,stream=sys.stderr, level=logging.INFO) +LOGGER = logging.getLogger('preprocess') + +hosted = False + +# sort the file order +def sort_func(x): + # place "papers/" at the end (like an appendix) + try: + x.index('%sdoc%s' % (os.path.sep, os.path.sep)) + except ValueError: + return 'z' + + # place readmes at the start of each section + try: + rm = x.index('README.md') + return x[:rm] + '0' + except ValueError: + return x + +# make the links work in-pdf +def fix_links(match): + # images + if os.path.splitext(match.group(2))[-1] == '.png': + return '[%s](%s)' % ( + match.group(1), + match.group(2) + ) + + # preserve external urls + elif match.group(2).startswith('http'): + return match.group(0) + + elif match.group(2).endswith('README.md'): + return '[%s](%s)' % ( + match.group(1), + match.group(2).replace('README.md','index.html') + ) + + # fix paths + return '[%s](%s)' % ( + match.group(1), + match.group(2).replace('.md','.html') + ) + +def fix_headings(match): + return '%s#' % ( + match.group(1) + ) + +if __name__ == "__main__": + # check whether hosted mode is on + if len(sys.argv)>1: + if sys.argv[1]=='hosted': + hosted=True + + #-- first, prepare the file list --# + file_list = [] + for i in os.walk('../../doc'): + base_dir, subfolders, files = i + for file_ in filter(lambda x: x.lower().endswith('.md'), files): + file_list.append(os.path.join(base_dir, file_)) + + #-- then, create the document --# + html = '' + + # perform sort + file_list.sort(key=sort_func) + + first = True + + for my_file in file_list: + with open(my_file, 'r') as md: + LOGGER.info("processing file %s" % my_file) + data = md.read() + + # retrieve path + pagePath = 'htmldoc' + os.path.sep + my_file[10:] + pagePathH = re.sub(r'\.md$','.html',pagePath).replace("README.html","index.html") + docDir = pagePath[:pagePath.rfind(os.path.sep)] + LOGGER.info("path: %s" % pagePathH) + + if not os.path.exists(docDir): + os.makedirs(docDir) + + # retrieve title + pageTitle = data.partition('\n')[0].replace("# ","") + + # perform link fixing + data = re.sub(r'\[(.+?)\]\((.+?)\)', fix_links, data) + data = re.sub(r'^\s*(#+)', fix_headings, data, flags=re.MULTILINE) + + # convert + html = ''' + + + + + + + %s + + + %s + + +''' % ( + pageTitle, + markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()]) + ) + + with open(pagePathH, 'w') as ht: + ht.write(html) 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

    +
  • brickblock369
  • cam900
  • DeMOSic
  • Electric Keet
  • freq-mod
  • host12prog
  • +
  • Lunathir
  • nicco1690
  • tildearrow
diff --git a/res/releaseReadme/stable-linux.txt b/res/releaseReadme/stable-linux.txt index 3eb6e77d9..979720a83 100644 --- a/res/releaseReadme/stable-linux.txt +++ b/res/releaseReadme/stable-linux.txt @@ -1,5 +1,35 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. extract this archive, and run `furnace` to get started. + +# help + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/res/releaseReadme/stable-mac.txt b/res/releaseReadme/stable-mac.txt index fb84fb870..d2a50cd89 100644 --- a/res/releaseReadme/stable-mac.txt +++ b/res/releaseReadme/stable-mac.txt @@ -1,8 +1,9 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. + +# help -move Furnace to Applications (or some other place). if you are using a recent version of macOS, you may get an error saying that Furnace is damaged. in that case, open Terminal, and type this: @@ -13,3 +14,32 @@ xattr -d com.apple.quarantine /path/to/Furnace.app (replace `/path/to/Furnace.app` with the path where Furnace.app is located, e.g. `/Applications/Furnace.app`) you may need to reboot after doing this before launching Furnace. + + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/res/releaseReadme/stable-win.txt b/res/releaseReadme/stable-win.txt index 22eed14ca..562037c2c 100644 --- a/res/releaseReadme/stable-win.txt +++ b/res/releaseReadme/stable-win.txt @@ -1,5 +1,35 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. extract this archive, and run furnace.exe to get started. + +# help + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/scripts/release-linux.sh b/scripts/release-linux.sh index 563e08127..08c7f73cc 100755 --- a/scripts/release-linux.sh +++ b/scripts/release-linux.sh @@ -50,9 +50,9 @@ rmdir share || exit 1 cd .. cp ../../../LICENSE . || exit 1 -cp ../../../README.md . || exit 1 +cp ../../../res/releaseReadme/stable-linux.txt README.md || exit 1 cp -r ../../../papers papers || exit 1 -cp -r ../../../doc doc || exit 1 +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 d189ca6de..604e17251 100755 --- a/scripts/release-win32.sh +++ b/scripts/release-win32.sh @@ -25,16 +25,17 @@ cd release/win32 cp ../../LICENSE LICENSE.txt || exit 1 cp ../../win32build/furnace.exe . || exit 1 -cp ../../README.md README.txt || exit 1 +cp ../../res/releaseReadme/stable-win.txt README.txt || exit 1 cp -r ../../papers papers || exit 1 -cp -r ../../doc doc || exit 1 cp -r ../../demos demos || exit 1 cp -r ../../instruments instruments || exit 1 cp -r ../../wavetables wavetables || exit 1 +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 9183007b5..edd4007fc 100755 --- a/scripts/release-win64.sh +++ b/scripts/release-win64.sh @@ -25,16 +25,17 @@ cd release/windows cp ../../LICENSE LICENSE.txt || exit 1 cp ../../winbuild/furnace.exe . || exit 1 -cp ../../README.md README.txt || exit 1 +cp ../../res/releaseReadme/stable-win.txt README.txt || exit 1 cp -r ../../papers papers || exit 1 -cp -r ../../doc doc || exit 1 cp -r ../../demos demos || exit 1 cp -r ../../instruments instruments || exit 1 cp -r ../../wavetables wavetables || exit 1 +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 9242bfc6c..71ff675ea 100755 --- a/scripts/release-winxp.sh +++ b/scripts/release-winxp.sh @@ -25,13 +25,14 @@ cd release/winxp cp ../../LICENSE LICENSE.txt || exit 1 cp ../../xpbuild/furnace.exe . || exit 1 -cp ../../README.md README.txt || exit 1 +cp ../../res/releaseReadme/stable-win.txt README.txt || exit 1 cp -r ../../papers papers || exit 1 -cp -r ../../doc doc || exit 1 cp -r ../../demos demos || exit 1 cp -r ../../instruments instruments || exit 1 cp -r ../../wavetables wavetables || exit 1 +cp ../../res/docpdf/manual.pdf . || exit 1 + i686-w64-mingw32-strip -s furnace.exe || exit 1 # patch to remove GetTickCount64 @@ -39,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/audio/pa.cpp b/src/audio/pa.cpp index e2bdfdd8d..3ae960860 100644 --- a/src/audio/pa.cpp +++ b/src/audio/pa.cpp @@ -18,7 +18,6 @@ */ #include -#include #include "../ta-log.h" #include "pa.h" #ifdef _WIN32 diff --git a/src/audio/sdlAudio.cpp b/src/audio/sdlAudio.cpp index ddbe85947..e01f073c8 100644 --- a/src/audio/sdlAudio.cpp +++ b/src/audio/sdlAudio.cpp @@ -18,7 +18,6 @@ */ #include -#include #include "../ta-log.h" #include "sdlAudio.h" diff --git a/src/audio/taAudio.h b/src/audio/taAudio.h index 12de61e95..0b6f530c6 100644 --- a/src/audio/taAudio.h +++ b/src/audio/taAudio.h @@ -22,7 +22,7 @@ #include "../ta-utils.h" #include #include "../fixedQueue.h" -#include +#include "../pch.h" struct SampleRateChangeEvent { double rate; diff --git a/src/baseutils.h b/src/baseutils.h index 0e1b31911..7e3d8e8eb 100644 --- a/src/baseutils.h +++ b/src/baseutils.h @@ -20,7 +20,7 @@ #ifndef _BASEUTILS_H #define _BASEUTILS_H -#include +#include "pch.h" std::string taEncodeBase64(const std::string& data); std::string taDecodeBase64(const char* str); diff --git a/src/engine/config.h b/src/engine/config.h index 12105d696..b9f5e43e1 100644 --- a/src/engine/config.h +++ b/src/engine/config.h @@ -21,8 +21,6 @@ #define _DIVCONFIG_H #include "../ta-utils.h" -#include -#include #include class DivConfig { diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 0ad264e53..ecb2ebc6e 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -22,7 +22,7 @@ #include #include -#include +#include "../pch.h" #include "config.h" #include "chipUtils.h" diff --git a/src/engine/engine.h b/src/engine/engine.h index 46b96ac57..734d10daf 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -30,13 +30,9 @@ #include "cmdStream.h" #include "../audio/taAudio.h" #include "blip_buf.h" -#include #include #include #include -#include -#include -#include #include "../fixedQueue.h" class DivWorkPool; @@ -56,10 +52,10 @@ class DivWorkPool; #define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; -#define DIV_UNSTABLE +//#define DIV_UNSTABLE -#define DIV_VERSION "0.6pre16" -#define DIV_ENGINE_VERSION 178 +#define DIV_VERSION "0.6" +#define DIV_ENGINE_VERSION 181 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/export.h b/src/engine/export.h index 07354fdb3..3a51ee236 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -22,7 +22,7 @@ #include "song.h" #include -#include +#include "../pch.h" class DivEngine; 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/instrument.h b/src/engine/instrument.h index 20172b7b8..a804f87f2 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -22,7 +22,7 @@ #include "safeWriter.h" #include "dataErrors.h" #include "../ta-utils.h" -#include +#include "../pch.h" struct DivSong; diff --git a/src/engine/pattern.h b/src/engine/pattern.h index 257ce7eca..8bb8fa21e 100644 --- a/src/engine/pattern.h +++ b/src/engine/pattern.h @@ -18,7 +18,7 @@ */ #include "safeReader.h" -#include +#include "../pch.h" struct DivPattern { String name; diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index 1e77ad35a..9e144c663 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_FREQBASE (is219?74448896:12582912) @@ -246,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; @@ -576,7 +575,7 @@ void DivPlatformC140::renderSamples(int sysID) { } if (is219) { // C219 (8-bit) - unsigned int length=s->length8; + unsigned int length=s->length8+4; // fit sample size to single bank size if (length>131072) { length=131072; @@ -595,27 +594,39 @@ void DivPlatformC140::renderSamples(int sysID) { logW("out of C219 memory for sample %d!",i); } if (s->depth==DIV_SAMPLE_DEPTH_C219) { + unsigned char next=0; + unsigned int sPos=0; for (unsigned int i=0; i=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; @@ -642,7 +653,20 @@ void DivPlatformC140::renderSamples(int sysID) { sampleMem[1+i+memPos]=c140Mu; } } else { - memcpy(sampleMem+memPos,s->data16,length); + short next=0; + unsigned int sPos=0; + for (unsigned int i=0; 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/es5506.cpp b/src/engine/platform/es5506.cpp index 227917636..b93f0c163 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define PITCH_OFFSET ((double)(16*2048*(chanMax+1))) #define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) 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/msm6295.cpp b/src/engine/platform/msm6295.cpp index 3d823d16f..6fba09fd1 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -185,7 +185,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { chan[c.chan].std.release(); break; case DIV_CMD_VOLUME: { - chan[c.chan].vol=c.value; + chan[c.chan].vol=MIN(8,c.value); if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } 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/pcspkr.h b/src/engine/platform/pcspkr.h index b2a88b903..b1a394444 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -23,7 +23,6 @@ #include "../dispatch.h" #include "../../fixedQueue.h" #include -#include #include class DivPlatformPCSpeaker: public DivDispatch { diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 5c98990b4..95a455e3f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_DIVIDER (1248*2) #define QS_NOTE_FREQUENCY(x) parent->calcBaseFreq(440,4096,(x)-3,false) 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/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 53d2cfe06..913f84045 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -231,7 +231,7 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { buf[0][h]=os; for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } for (int i=3; i<6; i++) { @@ -282,7 +282,8 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) { for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } for (int i=3; i<6; i++) { diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 743cfab46..9ec5518b0 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -402,7 +402,7 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -471,7 +471,8 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 173d882a6..01d5a3bb6 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -333,7 +333,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[bchOffs[i]]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -404,7 +404,8 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 4f00a7761..1937abd62 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -401,7 +401,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -471,7 +471,8 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 12f2251da..9a8b45e9d 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_FREQBASE 25165824 diff --git a/src/engine/song.h b/src/engine/song.h index ae144d714..291acd211 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -20,7 +20,7 @@ #ifndef _SONG_H #define _SONG_H #include -#include +#include "../pch.h" #include "defines.h" #include "../ta-utils.h" diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index a5c1d40eb..6b1365e4d 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1181,7 +1181,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef( "WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false, 1U<, effectVal}}, - {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, + {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direction is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, {0x22, {DIV_CMD_SU_SWEEP_ENABLE, "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)", constVal<2>, effectVal}}, }; const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>); @@ -1708,6 +1708,10 @@ void DivEngine::registerSystems() { EffectHandlerMap namcoEffectHandlerMap={ {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, + }; + + EffectHandlerMap namcoC30EffectHandlerMap={ + {0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, {0x11, {DIV_CMD_STD_NOISE_MODE, "11xx: Toggle noise mode"}}, }; @@ -1741,7 +1745,7 @@ void DivEngine::registerSystems() { {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO, DIV_INS_NAMCO}, {}, - namcoEffectHandlerMap + namcoC30EffectHandlerMap ); sysDefs[DIV_SYSTEM_MSM5232]=new DivSysDef( 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 -#include #include #include #include diff --git a/src/fixedQueue.h b/src/fixedQueue.h index 9866fe732..4e3379622 100644 --- a/src/fixedQueue.h +++ b/src/fixedQueue.h @@ -101,11 +101,11 @@ template 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/chanOsc.cpp b/src/gui/chanOsc.cpp index 41ed6ca9e..abdf708b0 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -357,7 +357,7 @@ void FurnaceGUI::drawChanOsc() { } else { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); float availY=ImGui::GetContentRegionAvail().y; - if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) { + if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders|ImGuiTableFlags_NoClip)) { std::vector oscBufs; std::vector oscFFTs; std::vector oscChans; 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/fileDialog.h b/src/gui/fileDialog.h index 371fa7c21..1a34ca1bc 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -1,7 +1,7 @@ #include "../ta-utils.h" #include "imgui.h" #include -#include +#include "../pch.h" #if defined(_WIN64) || defined(__APPLE__) #define USE_NFD diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 40e259eb3..f6bf5eedd 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -670,31 +670,13 @@ void FurnaceGUI::drawFindReplace() { ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); ImGui::TableNextColumn(); if (FIRST_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.ins); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.ins==j)) { - i.ins=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##II1",ImGuiDataType_U8,&i.ins,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextColumn(); if (SECOND_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.insMax); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.insMax==j)) { - i.insMax=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##II2",ImGuiDataType_U8,&i.insMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextRow(); @@ -706,31 +688,13 @@ void FurnaceGUI::drawFindReplace() { ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); ImGui::TableNextColumn(); if (FIRST_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.vol); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.vol==j)) { - i.vol=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##VV1",ImGuiDataType_U8,&i.vol,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextColumn(); if (SECOND_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.volMax); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.volMax==j)) { - i.volMax=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##VV2",ImGuiDataType_U8,&i.volMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } for (int j=0; jgetMaxVolumeChan(cursor.xCoarse)<16) { curNibble=false; + if (pat->data[cursor.y][target]>e->getMaxVolumeChan(cursor.xCoarse)) pat->data[cursor.y][target]=e->getMaxVolumeChan(cursor.xCoarse); editAdvance(); } else { curNibble=!curNibble; @@ -3544,6 +3545,10 @@ bool FurnaceGUI::loop() { break; case SDL_DROPFILE: if (ev.drop.file!=NULL) { + if (introPos<11.0) { + SDL_free(ev.drop.file); + break; + } int sampleCountBefore=e->song.sampleLen; std::vector instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames); DivWavetable* droppedWave=NULL; @@ -3579,6 +3584,9 @@ bool FurnaceGUI::loop() { SDL_free(ev.drop.file); } break; + case SDL_USEREVENT: + // used for MIDI wake up + break; case SDL_QUIT: if (modified) { showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT); @@ -3642,6 +3650,7 @@ bool FurnaceGUI::loop() { while (true) { midiLock.lock(); + midiWakeUp=true; if (midiQueue.empty()) { midiLock.unlock(); break; @@ -3925,11 +3934,13 @@ bool FurnaceGUI::loop() { int nextPlayOrder=0; int nextOldRow=0; e->getPlayPos(nextPlayOrder,nextOldRow); + oldRowChanged=false; playOrder=nextPlayOrder; if (followPattern) { curOrder=playOrder; } if (e->isPlaying()) { + if (oldRow!=nextOldRow) oldRowChanged=true; oldRow=nextOldRow; } @@ -4535,6 +4546,7 @@ bool FurnaceGUI::loop() { MEASURE(readOsc,readOsc()); MEASURE(osc,drawOsc()); MEASURE(chanOsc,drawChanOsc()); + MEASURE(grooves,drawGrooves()); MEASURE(regView,drawRegView()); } else { globalWinFlags=0; @@ -5863,8 +5875,6 @@ bool FurnaceGUI::loop() { if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) { pendingRawSampleChannels=1; - } - if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) { pendingRawSampleBigEndian=false; } @@ -5891,6 +5901,10 @@ bool FurnaceGUI::loop() { ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles); } + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_8BIT) { + ImGui::Checkbox("Swap words",&pendingRawSampleBigEndian); + } + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) { ImGui::Text("Encoding:"); ImGui::Indent(); @@ -6722,11 +6736,20 @@ bool FurnaceGUI::init() { firstFrame=true; - // TODO: MIDI mapping time! + userEvents=SDL_RegisterEvents(1); + e->setMidiCallback([this](const TAMidiMessage& msg) -> int { if (introPos<11.0) return -2; midiLock.lock(); midiQueue.push(msg); + if (userEvents!=0xffffffff && midiWakeUp) { + midiWakeUp=false; + userEvent.user.type=userEvents; + userEvent.user.code=0; + userEvent.user.data1=NULL; + userEvent.user.data2=NULL; + SDL_PushEvent(&userEvent); + } midiLock.unlock(); e->setMidiBaseChan(cursor.xCoarse); if (msg.type==TA_MIDI_SYSEX) return -2; @@ -7006,6 +7029,7 @@ FurnaceGUI::FurnaceGUI(): displayEditString(false), mobileEdit(false), killGraphics(false), + midiWakeUp(true), audioEngineChanged(false), settingsChanged(false), debugFFT(false), @@ -7019,6 +7043,8 @@ FurnaceGUI::FurnaceGUI(): mobileEditPage(0), wheelCalmDown(0), shallDetectScale(0), + cpuCores(0), + userEvents(0xffffffff), mobileMenuPos(0.0f), autoButtonSize(0.0f), mobileEditAnim(0.0f), @@ -7105,6 +7131,8 @@ FurnaceGUI::FurnaceGUI(): exitDisabledTimer(0), soloTimeout(0.0f), exportFadeOut(5.0), + newSongFirstFrame(false), + oldRowChanged(false), editControlsOpen(true), ordersOpen(true), insListOpen(true), diff --git a/src/gui/gui.h b/src/gui/gui.h index c760354b8..f0e2e7555 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -28,12 +28,10 @@ #include #include #include -#include #include #include -#include #include -#include +#include "../pch.h" #include "fileDialog.h" @@ -1347,6 +1345,7 @@ class FurnaceGUI { bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString; bool mobileEdit; bool killGraphics; + bool midiWakeUp; bool audioEngineChanged, settingsChanged, debugFFT; bool willExport[DIV_MAX_CHIPS]; int vgmExportVersion; @@ -1360,6 +1359,7 @@ class FurnaceGUI { int wheelCalmDown; int shallDetectScale; int cpuCores; + unsigned int userEvents; float mobileMenuPos, autoButtonSize, mobileEditAnim; ImVec2 mobileEditButtonPos, mobileEditButtonSize; const int* curSysSection; @@ -1373,6 +1373,7 @@ class FurnaceGUI { void* fmPreviewOPZ; void* fmPreviewOPZInterface; String* editString; + SDL_Event userEvent; String pendingRawSample; int pendingRawSampleDepth, pendingRawSampleChannels; @@ -1818,7 +1819,7 @@ class FurnaceGUI { double exportFadeOut; - bool newSongFirstFrame; + bool newSongFirstFrame, oldRowChanged; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; 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/pattern.cpp b/src/gui/pattern.cpp index b85b802c1..efb949867 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -377,11 +377,14 @@ void FurnaceGUI::drawPattern() { bool inhibitMenu=false; - if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) { - cursor.y=oldRow; - if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { - selStart=cursor; - selEnd=cursor; + if (e->isPlaying() && followPattern) { + if (oldRowChanged || !e->isStepping()) { + if (e->isStepping()) pendingStepUpdate=1; + cursor.y=oldRow; + if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { + selStart=cursor; + selEnd=cursor; + } } } demandX=0; diff --git a/src/gui/plot_nolerp.h b/src/gui/plot_nolerp.h index 50334dda6..fbc66c1eb 100644 --- a/src/gui/plot_nolerp.h +++ b/src/gui/plot_nolerp.h @@ -18,7 +18,7 @@ */ #include "imgui.h" -#include +#include "../pch.h" void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); 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)" ); diff --git a/src/main.cpp b/src/main.cpp index 87b36f668..7c7c0dd51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include "pch.h" #ifdef HAVE_SDL2 #include "SDL_events.h" #endif diff --git a/src/pch.cpp b/src/pch.cpp new file mode 100644 index 000000000..b1cd9d3f5 --- /dev/null +++ b/src/pch.cpp @@ -0,0 +1,20 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pch.h" \ No newline at end of file diff --git a/src/pch.h b/src/pch.h new file mode 100644 index 000000000..7821ee302 --- /dev/null +++ b/src/pch.h @@ -0,0 +1,30 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FUR_PCH_H +#define FUR_PCH_H + +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include + +#endif diff --git a/src/ta-log.h b/src/ta-log.h index d36f5da7d..de93e24a7 100644 --- a/src/ta-log.h +++ b/src/ta-log.h @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include "pch.h" #define LOGLEVEL_ERROR 0 #define LOGLEVEL_WARN 1 diff --git a/src/ta-utils.h b/src/ta-utils.h index 0b81cc853..6b3c201f5 100644 --- a/src/ta-utils.h +++ b/src/ta-utils.h @@ -21,7 +21,7 @@ #define _TA_UTILS_H #include #include -#include +#include "pch.h" #ifdef _MSC_VER #include