Merge branch 'tildearrow:master' into master

This commit is contained in:
DevEd 2023-10-02 01:07:35 -04:00 committed by GitHub
commit ac85732ef2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 602 additions and 211 deletions

View file

@ -271,7 +271,7 @@ jobs:
pushd ${{ steps.package-identify.outputs.filename }} pushd ${{ steps.package-identify.outputs.filename }}
cp -v ../LICENSE LICENSE.txt 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 ./ cp -vr ../papers ../${binPath}/furnace.exe ./
if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then
cp -v ../${binPath}/furnace.pdb ./ cp -v ../${binPath}/furnace.pdb ./
@ -285,7 +285,34 @@ jobs:
run: | run: |
pushd build pushd build
cpack 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 popd
- name: Package [Linux] - name: Package [Linux]
@ -317,7 +344,7 @@ jobs:
cd .. cd ..
cp ../../LICENSE . cp ../../LICENSE .
cp ../../README.md . cp ../../res/releaseReadme/unstable-other.txt .
cp -r ../../papers papers cp -r ../../papers papers
rmdir usr rmdir usr

2
.gitignore vendored
View file

@ -27,9 +27,11 @@ CMakePresets.json
extern/imgui_patched/examples/ extern/imgui_patched/examples/
src/asm/68k/amigatest/*.bin src/asm/68k/amigatest/*.bin
src/asm/68k/amigatest/player src/asm/68k/amigatest/player
src/check/calc_checksum
res/binary_to_compressed_c res/binary_to_compressed_c
res/binary_to_compressed_c.exe res/binary_to_compressed_c.exe
res/docpdf/manual.html res/docpdf/manual.html
res/docpdf/manual.pdf res/docpdf/manual.pdf
res/docpdf/.venv res/docpdf/.venv
res/docpdf/htmldoc/
res/furnace.appdata.xml res/furnace.appdata.xml

View file

@ -8,6 +8,7 @@ project(furnace)
if (APPLE) if (APPLE)
enable_language(OBJC) enable_language(OBJC)
enable_language(OBJCXX)
endif() endif()
set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 14)
@ -448,6 +449,9 @@ extern/Nuked-PSG/ympsg.c
extern/opm/opm.c extern/opm/opm.c
extern/Nuked-OPLL/opll.c extern/Nuked-OPLL/opll.c
extern/opl/opl3.c extern/opl/opl3.c
src/pch.cpp
src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/sn76496.cpp
src/engine/platform/sound/ay8910.cpp src/engine/platform/sound/ay8910.cpp
src/engine/platform/sound/saa1099.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()
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
$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h>
$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui.h>
$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui_internal.h>
)
else()
target_precompile_headers(furnace PUBLIC
$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h>
)
endif()
endif()
if (NOT ANDROID OR TERMUX) if (NOT ANDROID OR TERMUX)
if (NOT WIN32 AND NOT APPLE) if (NOT WIN32 AND NOT APPLE)
include(GNUInstallDirs) include(GNUInstallDirs)

View file

@ -17,7 +17,7 @@ for other operating systems, you may [build the source](#developer-info).
## features ## features
- over 50 sound chips - and counting: - a large selection of sound chips:
- Yamaha FM chips: - Yamaha FM chips:
- YM2151 (OPM) - YM2151 (OPM)
- YM2203 (OPN) - 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) - quality emulation cores (Nuked, MAME, SameBoy, Mednafen PCE, NSFplay, puNES, reSID, Stella, SAASound, vgsound_emu and ymfm)
- wavetable synthesizer - wavetable synthesizer
- available on wavetable chips - 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 - MIDI input support
- additional features: - additional features:
- FM macros! - FM macros!
@ -327,7 +327,7 @@ it is in [doc/](doc/README.md).
> is there a tutorial? > 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! > I've lost my song!

View file

@ -15,8 +15,8 @@ android {
} }
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 26 targetSdkVersion 26
versionCode 178 versionCode 181
versionName "0.6pre16" versionName "0.6"
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="178" android:versionCode="181"
android:versionName="0.6pre16" android:versionName="0.6"
android:installLocation="auto"> android:installLocation="auto">
<!-- OpenGL ES 2.0 --> <!-- OpenGL ES 2.0 -->

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
demos/snes/IMU Café.fur Normal file

Binary file not shown.

BIN
demos/snes/Sadness.fur Normal file

Binary file not shown.

View file

@ -53,7 +53,7 @@ these apply to each operator:
- does not apply for OP4. - does not apply for OP4.
- **Reverb (REV)**: not a true reverb. extends release time, giving a slight reverb-like effect to the operator. - **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). - **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). - **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3).
#### I am familiar with Yamaha TX81Z. where's LS and KVS? #### I am familiar with Yamaha TX81Z. where's LS and KVS?

View file

@ -11,7 +11,7 @@ this allows you to enable and configure the Furnace wavetable synthesizer. see [
- **Volume**: volume sequence. - **Volume**: volume sequence.
- **Arpeggio**: pitch sequence. - **Arpeggio**: pitch sequence.
- **Noise**: specifies noise pitch. - **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. - **Waveform**: specifies wavetable sequence.
- **Panning (left)**: output level of left channel. - **Panning (left)**: output level of left channel.
- Namco C30 only. - Namco C30 only.

View file

@ -39,6 +39,14 @@ the following sound chips have sample support:
- Namco C140 - Namco C140
- Namco C219 - 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) ## compatible sample mode (LEGACY)
**use of this mode is discouraged in favor of Sample type instruments.** **use of this mode is discouraged in favor of Sample type instruments.**

View file

@ -16,11 +16,13 @@ the index follows.
## authors ## authors
- brickblock369
- cam900 - cam900
- DeMOSic - DeMOSic
- Electric Keet - Electric Keet
- freq-mod - freq-mod
- host12prog - host12prog
- Lunathir
- nicco1690 - nicco1690
- tildearrow - tildearrow

View file

@ -3859,7 +3859,7 @@ namespace IGFD
} }
} }
#endif #endif
for (const char* i=n; *i; i++) { for (const unsigned char* i=(const unsigned char*)n; *i; i++) {
#ifdef _WIN32 #ifdef _WIN32
if (*i<32) { if (*i<32) {
return 3; return 3;

View file

@ -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. // - 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) // - 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. // - 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 #ifdef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
IM_MSVC_RUNTIME_CHECKS_OFF IM_MSVC_RUNTIME_CHECKS_OFF

View file

@ -7,6 +7,12 @@
#ifdef __MINGW32__ #ifdef __MINGW32__
// Explicitly setting NTDDI version, this is necessary for the MinGW compiler // 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 NTDDI_VERSION NTDDI_VISTA
#define _WIN32_WINNT _WIN32_WINNT_VISTA #define _WIN32_WINNT _WIN32_WINNT_VISTA
#endif #endif

View file

@ -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) 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. the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from.
- `0`: note. - `0`: note.

View file

@ -32,6 +32,9 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
the format versions are: the format versions are:
- 181: Furnace 0.6
- 180: Furnace 0.6pre18
- 179: Furnace 0.6pre17
- 178: Furnace 0.6pre16 - 178: Furnace 0.6pre16
- 177: Furnace 0.6pre15 - 177: Furnace 0.6pre15
- 175: Furnace 0.6pre14 - 175: Furnace 0.6pre14

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.6pre16</string> <string>0.6</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.6pre16</string> <string>0.6</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.6pre16</string> <string>0.6</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string></string> <string></string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>

25
res/docpdf/make-doc-html.sh Executable file
View file

@ -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

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
echo "compiling Furnace doc..." echo "compiling Furnace doc (PDF)..."
if [ ! -e .venv ]; then if [ ! -e .venv ]; then
python3 -m virtualenv .venv || exit 1 python3 -m virtualenv .venv || exit 1

150
res/docpdf/make_htmldoc.py Normal file
View file

@ -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 = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
body {
background-color: #222;
color: #eee;
font-family: sans-serif;
}
a {
color: #3df;
}
a:visited {
color: #fd3;
}
b {
color: #fff;
}
h1 {
text-align: center;
}
img {
max-width: 100%%;
}
</style>
<title>%s</title>
</head>
<body>
%s
</body>
</html>
''' % (
pageTitle,
markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()])
)
with open(pagePathH, 'w') as ht:
ht.write(html)

View file

@ -334,11 +334,13 @@ if __name__ == "__main__":
<div> <div>
<h3>authors</h3> <h3>authors</h3>
<ul> <ul>
<li>brickblock369</li>
<li>cam900</li> <li>cam900</li>
<li>DeMOSic</li> <li>DeMOSic</li>
<li>Electric Keet</li> <li>Electric Keet</li>
<li>freq-mod</li> <li>freq-mod</li>
<li>host12prog</li> <li>host12prog</li>
<li>Lunathir</li>
<li>nicco1690</li> <li>nicco1690</li>
<li>tildearrow</li> <li>tildearrow</li>
</ul> </ul>

View file

@ -1,5 +1,35 @@
# Furnace (chiptune tracker) # 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. 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.

View file

@ -1,8 +1,9 @@
# Furnace (chiptune tracker) # 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. 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: 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`) (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. 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.

View file

@ -1,5 +1,35 @@
# Furnace (chiptune tracker) # 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. 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.

View file

@ -50,9 +50,9 @@ rmdir share || exit 1
cd .. cd ..
cp ../../../LICENSE . || exit 1 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 ../../../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 rmdir usr || exit 1
strip -s furnace strip -s furnace

View file

@ -25,16 +25,17 @@ cd release/win32
cp ../../LICENSE LICENSE.txt || exit 1 cp ../../LICENSE LICENSE.txt || exit 1
cp ../../win32build/furnace.exe . || 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 ../../papers papers || exit 1
cp -r ../../doc doc || exit 1
cp -r ../../demos demos || exit 1 cp -r ../../demos demos || exit 1
cp -r ../../instruments instruments || exit 1 cp -r ../../instruments instruments || exit 1
cp -r ../../wavetables wavetables || exit 1 cp -r ../../wavetables wavetables || exit 1
cp ../../res/docpdf/manual.pdf . || exit 1
i686-w64-mingw32-strip -s furnace.exe || 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/") furName=$(git describe --tags | sed "s/v0/0/")

View file

@ -25,16 +25,17 @@ cd release/windows
cp ../../LICENSE LICENSE.txt || exit 1 cp ../../LICENSE LICENSE.txt || exit 1
cp ../../winbuild/furnace.exe . || 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 ../../papers papers || exit 1
cp -r ../../doc doc || exit 1
cp -r ../../demos demos || exit 1 cp -r ../../demos demos || exit 1
cp -r ../../instruments instruments || exit 1 cp -r ../../instruments instruments || exit 1
cp -r ../../wavetables wavetables || 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 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/") furName=$(git describe --tags | sed "s/v0/0/")

View file

@ -25,13 +25,14 @@ cd release/winxp
cp ../../LICENSE LICENSE.txt || exit 1 cp ../../LICENSE LICENSE.txt || exit 1
cp ../../xpbuild/furnace.exe . || 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 ../../papers papers || exit 1
cp -r ../../doc doc || exit 1
cp -r ../../demos demos || exit 1 cp -r ../../demos demos || exit 1
cp -r ../../instruments instruments || exit 1 cp -r ../../instruments instruments || exit 1
cp -r ../../wavetables wavetables || exit 1 cp -r ../../wavetables wavetables || exit 1
cp ../../res/docpdf/manual.pdf . || exit 1
i686-w64-mingw32-strip -s furnace.exe || exit 1 i686-w64-mingw32-strip -s furnace.exe || exit 1
# patch to remove GetTickCount64 # patch to remove GetTickCount64
@ -39,7 +40,7 @@ xxd -c 256 -ps furnace.exe | sed "s/4765745469636b436f756e743634/4765745469636b4
rm furnace.exe rm furnace.exe
mv furnace-patched.exe 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/") furName=$(git describe --tags | sed "s/v0/0/")

View file

@ -18,7 +18,6 @@
*/ */
#include <string.h> #include <string.h>
#include <vector>
#include "../ta-log.h" #include "../ta-log.h"
#include "pa.h" #include "pa.h"
#ifdef _WIN32 #ifdef _WIN32

View file

@ -18,7 +18,6 @@
*/ */
#include <string.h> #include <string.h>
#include <vector>
#include "../ta-log.h" #include "../ta-log.h"
#include "sdlAudio.h" #include "sdlAudio.h"

View file

@ -22,7 +22,7 @@
#include "../ta-utils.h" #include "../ta-utils.h"
#include <memory> #include <memory>
#include "../fixedQueue.h" #include "../fixedQueue.h"
#include <vector> #include "../pch.h"
struct SampleRateChangeEvent { struct SampleRateChangeEvent {
double rate; double rate;

View file

@ -20,7 +20,7 @@
#ifndef _BASEUTILS_H #ifndef _BASEUTILS_H
#define _BASEUTILS_H #define _BASEUTILS_H
#include <string> #include "pch.h"
std::string taEncodeBase64(const std::string& data); std::string taEncodeBase64(const std::string& data);
std::string taDecodeBase64(const char* str); std::string taDecodeBase64(const char* str);

View file

@ -21,8 +21,6 @@
#define _DIVCONFIG_H #define _DIVCONFIG_H
#include "../ta-utils.h" #include "../ta-utils.h"
#include <map>
#include <vector>
#include <initializer_list> #include <initializer_list>
class DivConfig { class DivConfig {

View file

@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <vector> #include "../pch.h"
#include "config.h" #include "config.h"
#include "chipUtils.h" #include "chipUtils.h"

View file

@ -30,13 +30,9 @@
#include "cmdStream.h" #include "cmdStream.h"
#include "../audio/taAudio.h" #include "../audio/taAudio.h"
#include "blip_buf.h" #include "blip_buf.h"
#include <atomic>
#include <functional> #include <functional>
#include <initializer_list> #include <initializer_list>
#include <thread> #include <thread>
#include <mutex>
#include <map>
#include <unordered_map>
#include "../fixedQueue.h" #include "../fixedQueue.h"
class DivWorkPool; class DivWorkPool;
@ -56,10 +52,10 @@ class DivWorkPool;
#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_UNSTABLE //#define DIV_UNSTABLE
#define DIV_VERSION "0.6pre16" #define DIV_VERSION "0.6"
#define DIV_ENGINE_VERSION 178 #define DIV_ENGINE_VERSION 181
// 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

@ -22,7 +22,7 @@
#include "song.h" #include "song.h"
#include <initializer_list> #include <initializer_list>
#include <vector> #include "../pch.h"
class DivEngine; class DivEngine;

View file

@ -464,6 +464,13 @@ DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth,
accum/=channels; accum/=channels;
sample->data8[i]=accum; sample->data8[i]=accum;
} }
if (bigEndian) {
for (unsigned int i=0; (i+1)<samples; i+=2) {
sample->data8[i]^=sample->data8[i^1];
sample->data8[i^1]^=sample->data8[i];
sample->data8[i]^=sample->data8[i^1];
}
}
} else { } else {
memcpy(sample->getCurBuf(),buf,len); memcpy(sample->getCurBuf(),buf,len);
} }

View file

@ -22,7 +22,7 @@
#include "safeWriter.h" #include "safeWriter.h"
#include "dataErrors.h" #include "dataErrors.h"
#include "../ta-utils.h" #include "../ta-utils.h"
#include <vector> #include "../pch.h"
struct DivSong; struct DivSong;

View file

@ -18,7 +18,7 @@
*/ */
#include "safeReader.h" #include "safeReader.h"
#include <vector> #include "../pch.h"
struct DivPattern { struct DivPattern {
String name; String name;

View file

@ -21,7 +21,6 @@
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h" #include "../../ta-log.h"
#include <math.h> #include <math.h>
#include <map>
#define CHIP_FREQBASE (is219?74448896:12582912) #define CHIP_FREQBASE (is219?74448896:12582912)
@ -246,10 +245,10 @@ void DivPlatformC140::tick(bool sysTick) {
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen && s->isLoopable()) { if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen && s->isLoopable()) {
if (is219) { if (is219) {
loop=MIN(start+(s->loopStart>>1),65535); loop=MIN(start+(s->loopStart>>1),65535);
end=MIN(start+(s->loopEnd>>1)-1,65535); end=MIN(start+(s->loopEnd>>1),65535);
} else { } else {
loop=MIN(start+s->loopStart,65535); loop=MIN(start+s->loopStart+1,65535);
end=MIN(start+s->loopEnd-1,65535); end=MIN(start+s->loopEnd+1,65535);
} }
} else if (chan[i].noise && is219) { } else if (chan[i].noise && is219) {
loop=0; loop=0;
@ -576,7 +575,7 @@ void DivPlatformC140::renderSamples(int sysID) {
} }
if (is219) { // C219 (8-bit) if (is219) { // C219 (8-bit)
unsigned int length=s->length8; unsigned int length=s->length8+4;
// fit sample size to single bank size // fit sample size to single bank size
if (length>131072) { if (length>131072) {
length=131072; length=131072;
@ -595,27 +594,39 @@ void DivPlatformC140::renderSamples(int sysID) {
logW("out of C219 memory for sample %d!",i); logW("out of C219 memory for sample %d!",i);
} }
if (s->depth==DIV_SAMPLE_DEPTH_C219) { if (s->depth==DIV_SAMPLE_DEPTH_C219) {
unsigned char next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i++) { for (unsigned int i=0; i<length; i++) {
if (i>=s->lengthC219) { if (sPos<s->lengthC219) {
sampleMem[(memPos+i)^1]=0; next=s->dataC219[sPos++];
} else { if (s->isLoopable()) {
sampleMem[(memPos+i)^1]=s->dataC219[i]; if ((int)sPos>=s->loopEnd) {
sPos=s->loopStart;
}
}
} }
sampleMem[(memPos+i)^1]=next;
} }
} else { } else {
signed char next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i++) { for (unsigned int i=0; i<length; i++) {
if (i>=s->length8) { if (sPos<s->length8) {
sampleMem[(memPos+i)^1]=0; next=s->data8[sPos++];
} else { if (s->isLoopable()) {
sampleMem[(memPos+i)^1]=s->data8[i]; if ((int)sPos>=s->loopEnd) {
sPos=s->loopStart;
}
}
} }
sampleMem[(memPos+i)^1]=next;
} }
} }
sampleOff[i]=memPos>>1; sampleOff[i]=memPos>>1;
sampleLoaded[i]=true; sampleLoaded[i]=true;
memPos+=length; memPos+=length;
} else { // C140 (16-bit) } else { // C140 (16-bit)
unsigned int length=s->length16; unsigned int length=s->length16+4;
// fit sample size to single bank size // fit sample size to single bank size
if (length>(131072)) { if (length>(131072)) {
length=131072; length=131072;
@ -642,7 +653,20 @@ void DivPlatformC140::renderSamples(int sysID) {
sampleMem[1+i+memPos]=c140Mu; sampleMem[1+i+memPos]=c140Mu;
} }
} else { } else {
memcpy(sampleMem+memPos,s->data16,length); short next=0;
unsigned int sPos=0;
for (unsigned int i=0; i<length; i+=2) {
if (sPos<s->samples) {
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; sampleOff[i]=memPos>>1;
sampleLoaded[i]=true; sampleLoaded[i]=true;

View file

@ -21,7 +21,6 @@
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h" #include "../../ta-log.h"
#include <math.h> #include <math.h>
#include <map>
#define PITCH_OFFSET ((double)(16*2048*(chanMax+1))) #define PITCH_OFFSET ((double)(16*2048*(chanMax+1)))
#define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) #define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false))

View file

@ -431,7 +431,7 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) {
} }
unsigned short DivPlatformK007232::getPan(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) { DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) {

View file

@ -185,7 +185,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
chan[c.chan].std.release(); chan[c.chan].std.release();
break; break;
case DIV_CMD_VOLUME: { 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) { if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value; chan[c.chan].outVol=c.value;
} }

View file

@ -201,7 +201,7 @@ void DivPlatformNamcoWSG::tick(bool sysTick) {
if (chan[i].std.vol.had) { if (chan[i].std.vol.had) {
chan[i].outVol=((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4; 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].noise=chan[i].std.duty.val;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
@ -418,6 +418,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) {
} }
case DIV_CMD_STD_NOISE_MODE: case DIV_CMD_STD_NOISE_MODE:
chan[c.chan].noise=c.value; chan[c.chan].noise=c.value;
chan[c.chan].freqChanged=true;
break; break;
case DIV_CMD_PANNING: { case DIV_CMD_PANNING: {
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4); chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);

View file

@ -23,7 +23,6 @@
#include "../dispatch.h" #include "../dispatch.h"
#include "../../fixedQueue.h" #include "../../fixedQueue.h"
#include <thread> #include <thread>
#include <mutex>
#include <condition_variable> #include <condition_variable>
class DivPlatformPCSpeaker: public DivDispatch { class DivPlatformPCSpeaker: public DivDispatch {

View file

@ -21,7 +21,6 @@
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h" #include "../../ta-log.h"
#include <math.h> #include <math.h>
#include <map>
#define CHIP_DIVIDER (1248*2) #define CHIP_DIVIDER (1248*2)
#define QS_NOTE_FREQUENCY(x) parent->calcBaseFreq(440,4096,(x)-3,false) #define QS_NOTE_FREQUENCY(x) parent->calcBaseFreq(440,4096,(x)-3,false)

View file

@ -104,7 +104,7 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle
if (!voice->muted) if (!voice->muted)
{ {
// fetch 12 bit sample // 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; signed short s2 = c140->sample_mem[((unsigned int)(voice->bank) << 16) | ((voice->addr + 1) & 0xffff)] & ~0xf;
if (voice->compressed) if (voice->compressed)
{ {
@ -171,7 +171,7 @@ void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle
else else
{ {
// fetch 8 bit sample // 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)]; signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | (((voice->addr + 1) & 0x1ffff)^1)];
if (voice->compressed) if (voice->compressed)
{ {

View file

@ -231,7 +231,7 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
buf[0][h]=os; buf[0][h]=os;
for (int i=0; i<3; i++) { 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++) { 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++) { 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++) { for (int i=3; i<6; i++) {

View file

@ -402,7 +402,7 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) { for (int i=0; i<psgChanOffs; 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);
} }
ssge->get_last_out(ssgOut); ssge->get_last_out(ssgOut);
@ -471,7 +471,8 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) {
buf[1][h]=os[1]; buf[1][h]=os[1];
for (int i=0; i<6; i++) { 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); ssge->get_last_out(ssgOut);

View file

@ -333,7 +333,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) { for (int i=0; i<psgChanOffs; i++) {
oscBuf[i]->data[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); ssge->get_last_out(ssgOut);
@ -404,7 +404,8 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
buf[1][h]=os[1]; buf[1][h]=os[1];
for (int i=0; i<psgChanOffs; i++) { for (int i=0; i<psgChanOffs; 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); ssge->get_last_out(ssgOut);

View file

@ -401,7 +401,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) { for (int i=0; i<psgChanOffs; 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);
} }
ssge->get_last_out(ssgOut); ssge->get_last_out(ssgOut);
@ -471,7 +471,8 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) {
for (int i=0; i<psgChanOffs; i++) { for (int i=0; i<psgChanOffs; 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); ssge->get_last_out(ssgOut);

View file

@ -21,7 +21,6 @@
#include "../engine.h" #include "../engine.h"
#include "../../ta-log.h" #include "../../ta-log.h"
#include <math.h> #include <math.h>
#include <map>
#define CHIP_FREQBASE 25165824 #define CHIP_FREQBASE 25165824

View file

@ -20,7 +20,7 @@
#ifndef _SONG_H #ifndef _SONG_H
#define _SONG_H #define _SONG_H
#include <stdio.h> #include <stdio.h>
#include <vector> #include "../pch.h"
#include "defines.h" #include "defines.h"
#include "../ta-utils.h" #include "../ta-utils.h"

View file

@ -1181,7 +1181,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef( sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef(
"WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false, 1U<<DIV_SAMPLE_DEPTH_8BIT, "WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false, 1U<<DIV_SAMPLE_DEPTH_8BIT,
"developed by the makers of the Game Boy and the Virtual Boy...", "developed by the makers of the Game Boy and the Virtual Boy...",
{"Wave", "Wave/PCM", "Wave", "Wave/Noise"}, {"Wave", "Wave/PCM", "Wave/Sweep", "Wave/Noise"},
{"CH1", "CH2", "CH3", "CH4"}, {"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE}, {DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE},
{DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN}, {DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN},
@ -1649,7 +1649,7 @@ void DivEngine::registerSystems() {
{0x1e, {DIV_CMD_SU_SYNC_PERIOD_LOW, "1Exx: Set phase reset period low byte"}}, {0x1e, {DIV_CMD_SU_SYNC_PERIOD_LOW, "1Exx: Set phase reset period low byte"}},
{0x1f, {DIV_CMD_SU_SYNC_PERIOD_HIGH, "1Fxx: Set phase reset period high byte"}}, {0x1f, {DIV_CMD_SU_SYNC_PERIOD_HIGH, "1Fxx: Set phase reset period high byte"}},
{0x20, {DIV_CMD_SU_SWEEP_ENABLE, "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)", constVal<0>, effectVal}}, {0x20, {DIV_CMD_SU_SWEEP_ENABLE, "20xx: Toggle frequency sweep (bit 0-6: speed; bit 7: direction is up)", constVal<0>, 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}}, {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>); 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={ EffectHandlerMap namcoEffectHandlerMap={
{0x10, {DIV_CMD_WAVE, "10xx: Set waveform"}}, {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"}}, {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_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}, {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( sysDefs[DIV_SYSTEM_MSM5232]=new DivSysDef(

View file

@ -1747,13 +1747,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
if (!hasRFC1) { if (!hasRFC1) {
hasRFC1=disCont[i].dispatch->chipClock; hasRFC1=disCont[i].dispatch->chipClock;
isSecond[i]=true; isSecond[i]=true;
CHIP_VOL(16,1.6); CHIP_VOL(16,0.8);
willExport[i]=true; willExport[i]=true;
writeRF5C68[1]=disCont[i].dispatch; writeRF5C68[1]=disCont[i].dispatch;
} }
} else if (!hasRFC) { } else if (!hasRFC) {
hasRFC=disCont[i].dispatch->chipClock; hasRFC=disCont[i].dispatch->chipClock;
CHIP_VOL(5,1.6); CHIP_VOL(5,1.1);
willExport[i]=true; willExport[i]=true;
writeRF5C68[0]=disCont[i].dispatch; writeRF5C68[0]=disCont[i].dispatch;
} }
@ -2418,8 +2418,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
} }
while (!done) { while (!done) {
if (loopPos==-1) { if (loopPos==-1) {
if (loopOrder==curOrder && loopRow==curRow && ticks==1) { if (loopOrder==curOrder && loopRow==curRow) {
writeLoop=true; if ((ticks-((tempoAccum+curSubSong->virtualTempoN)/curSubSong->virtualTempoD))<=0) {
writeLoop=true;
}
} }
} }
songTick++; songTick++;

View file

@ -106,7 +106,6 @@ void DivEngine::runExportThread() {
if (sfWrap.doClose()!=0) { if (sfWrap.doClose()!=0) {
logE("could not close audio file!"); logE("could not close audio file!");
} }
exporting=false;
if (initAudioBackend()) { if (initAudioBackend()) {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
@ -118,6 +117,7 @@ void DivEngine::runExportThread() {
} }
} }
logI("done!"); logI("done!");
exporting=false;
break; break;
} }
case DIV_EXPORT_MODE_MANY_SYS: { case DIV_EXPORT_MODE_MANY_SYS: {
@ -217,7 +217,6 @@ void DivEngine::runExportThread() {
logE("could not close audio file!"); logE("could not close audio file!");
} }
} }
exporting=false;
if (initAudioBackend()) { if (initAudioBackend()) {
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
@ -229,6 +228,7 @@ void DivEngine::runExportThread() {
} }
} }
logI("done!"); logI("done!");
exporting=false;
break; break;
} }
case DIV_EXPORT_MODE_MANY_CHAN: { case DIV_EXPORT_MODE_MANY_CHAN: {
@ -336,7 +336,6 @@ void DivEngine::runExportThread() {
if (stopExport) break; if (stopExport) break;
} }
exporting=false;
delete[] outBuf[0]; delete[] outBuf[0];
delete[] outBuf[1]; delete[] outBuf[1];
@ -359,6 +358,7 @@ void DivEngine::runExportThread() {
} }
} }
logI("done!"); logI("done!");
exporting=false;
break; break;
} }
} }

View file

@ -21,7 +21,6 @@
#define _WORKPOOL_H #define _WORKPOOL_H
#include <thread> #include <thread>
#include <mutex>
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <future> #include <future>

View file

@ -101,11 +101,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop() {
template <typename T, size_t items> bool FixedQueue<T,items>::push(const T& item) { template <typename T, size_t items> bool FixedQueue<T,items>::push(const T& item) {
if (writePos==(readPos-1)) { if (writePos==(readPos-1)) {
logW("queue overflow!"); //logW("queue overflow!");
return false; return false;
} }
if (writePos==items-1 && readPos==0) { if (writePos==items-1 && readPos==0) {
logW("queue overflow!"); //logW("queue overflow!");
return false; return false;
} }
data[writePos]=item; data[writePos]=item;
@ -121,11 +121,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop_front() {
template <typename T, size_t items> bool FixedQueue<T,items>::push_back(const T& item) { template <typename T, size_t items> bool FixedQueue<T,items>::push_back(const T& item) {
if (writePos==(readPos-1)) { if (writePos==(readPos-1)) {
logW("queue overflow!"); //logW("queue overflow!");
return false; return false;
} }
if (writePos==items-1 && readPos==0) { if (writePos==items-1 && readPos==0) {
logW("queue overflow!"); //logW("queue overflow!");
return false; return false;
} }
data[writePos]=item; data[writePos]=item;
@ -145,11 +145,11 @@ template <typename T, size_t items> bool FixedQueue<T,items>::pop_back() {
template <typename T, size_t items> bool FixedQueue<T,items>::push_front(const T& item) { template <typename T, size_t items> bool FixedQueue<T,items>::push_front(const T& item) {
if (readPos==(writePos+1)) { if (readPos==(writePos+1)) {
logW("stack overflow!"); //logW("stack overflow!");
return false; return false;
} }
if (readPos==0 && writePos==items-1) { if (readPos==0 && writePos==items-1) {
logW("stack overflow!"); //logW("stack overflow!");
return false; return false;
} }
if (readPos>0) { if (readPos>0) {

View file

@ -30,9 +30,6 @@ const char* aboutLine[]={
"the biggest multi-system chiptune tracker!", "the biggest multi-system chiptune tracker!",
"featuring DefleMask song compatibility.", "featuring DefleMask song compatibility.",
"", "",
"this is a version released during The Freeze.",
"please report any issues you find!",
"",
"> CREDITS <", "> CREDITS <",
"", "",
"-- program --", "-- program --",
@ -57,20 +54,21 @@ const char* aboutLine[]={
"Raijin", "Raijin",
"", "",
"-- documentation --", "-- documentation --",
"tildearrow", "brickblock369",
"freq-mod",
"nicco1690",
"DeMOSic",
"cam900", "cam900",
"host12prog", "DeMOSic",
"WindowxDeveloper",
"polluks",
"Electric Keet", "Electric Keet",
"freq-mod",
"host12prog",
"Lunathir",
"nicco1690",
"tildearrow",
"", "",
"-- demo songs --", "-- demo songs --",
"0x5066", "0x5066",
"Abstract 64", "Abstract 64",
"ActualNK358", "ActualNK358",
"airconmanws",
"akumanatt", "akumanatt",
"AmigaX", "AmigaX",
"AURORA*FIELDS", "AURORA*FIELDS",
@ -123,10 +121,12 @@ const char* aboutLine[]={
"psxdominator", "psxdominator",
"Raijin", "Raijin",
"railzen7", "railzen7",
"RevvoBolt",
"SnugglyBun", "SnugglyBun",
"SuperJet Spade", "SuperJet Spade",
"SwapXFO", "SwapXFO",
"TakuikaNinja", "TakuikaNinja",
"tapekeep",
"TCORPStudios", "TCORPStudios",
"Teuthida", "Teuthida",
"ThaCuber", "ThaCuber",

View file

@ -357,7 +357,7 @@ void FurnaceGUI::drawChanOsc() {
} else { } else {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f));
float availY=ImGui::GetContentRegionAvail().y; float availY=ImGui::GetContentRegionAvail().y;
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) { if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders|ImGuiTableFlags_NoClip)) {
std::vector<DivDispatchOscBuffer*> oscBufs; std::vector<DivDispatchOscBuffer*> oscBufs;
std::vector<ChanOscStatus*> oscFFTs; std::vector<ChanOscStatus*> oscFFTs;
std::vector<int> oscChans; std::vector<int> oscChans;

View file

@ -584,6 +584,10 @@ void FurnaceGUI::drawMobileControls() {
if (ImGui::Button("Stats")) { if (ImGui::Button("Stats")) {
statsOpen=!statsOpen; statsOpen=!statsOpen;
} }
ImGui::SameLine();
if (ImGui::Button("Grooves")) {
groovesOpen=!groovesOpen;
}
if (ImGui::Button("Compat Flags")) { if (ImGui::Button("Compat Flags")) {
compatFlagsOpen=!compatFlagsOpen; compatFlagsOpen=!compatFlagsOpen;
} }

View file

@ -1,7 +1,7 @@
#include "../ta-utils.h" #include "../ta-utils.h"
#include "imgui.h" #include "imgui.h"
#include <functional> #include <functional>
#include <vector> #include "../pch.h"
#if defined(_WIN64) || defined(__APPLE__) #if defined(_WIN64) || defined(__APPLE__)
#define USE_NFD #define USE_NFD

View file

@ -670,31 +670,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.insMode)) { if (FIRST_VISIBLE(i.insMode)) {
snprintf(tempID,1024,"%.2X",i.ins);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("II1",tempID)) { ImGui::InputScalar("##II1",ImGuiDataType_U8,&i.ins,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
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::TableNextColumn(); ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.insMode)) { if (SECOND_VISIBLE(i.insMode)) {
snprintf(tempID,1024,"%.2X",i.insMax);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("II2",tempID)) { ImGui::InputScalar("##II2",ImGuiDataType_U8,&i.insMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
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::TableNextRow(); ImGui::TableNextRow();
@ -706,31 +688,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.volMode)) { if (FIRST_VISIBLE(i.volMode)) {
snprintf(tempID,1024,"%.2X",i.vol);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("VV1",tempID)) { ImGui::InputScalar("##VV1",ImGuiDataType_U8,&i.vol,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
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::TableNextColumn(); ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.volMode)) { if (SECOND_VISIBLE(i.volMode)) {
snprintf(tempID,1024,"%.2X",i.volMax);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("VV2",tempID)) { ImGui::InputScalar("##VV2",ImGuiDataType_U8,&i.volMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
for (int j=0; j<256; j++) {
snprintf(tempID,1024,"%.2X",j);
if (ImGui::Selectable(tempID,i.volMax==j)) {
i.volMax=j;
}
}
ImGui::EndCombo();
}
} }
for (int j=0; j<i.effectCount; j++) { for (int j=0; j<i.effectCount; j++) {
@ -744,31 +708,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX); ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectMode[j])) { if (FIRST_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effect[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE1",tempID)) { ImGui::InputScalar("##EE1",ImGuiDataType_U8,&i.effect[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effect[j]==k)) {
i.effect[j]=k;
}
}
ImGui::EndCombo();
}
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectMode[j])) { if (SECOND_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE2",tempID)) { ImGui::InputScalar("##EE2",ImGuiDataType_U8,&i.effectMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectMax[j]==k)) {
i.effectMax[j]=k;
}
}
ImGui::EndCombo();
}
} }
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -780,31 +726,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX); ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectValMode[j])) { if (FIRST_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectVal[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV1",tempID)) { ImGui::InputScalar("##EV1",ImGuiDataType_U8,&i.effectVal[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectVal[j]==k)) {
i.effectVal[j]=k;
}
}
ImGui::EndCombo();
}
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectValMode[j])) { if (SECOND_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectValMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV2",tempID)) { ImGui::InputScalar("##EV2",ImGuiDataType_U8,&i.effectValMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
for (int k=0; k<256; k++) {
snprintf(tempID,1024,"%.2X",k);
if (ImGui::Selectable(tempID,i.effectValMax[j]==k)) {
i.effectValMax[j]=k;
}
}
ImGui::EndCombo();
}
} }
ImGui::PopID(); ImGui::PopID();

View file

@ -1274,6 +1274,7 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
} else { } else {
if (e->getMaxVolumeChan(cursor.xCoarse)<16) { if (e->getMaxVolumeChan(cursor.xCoarse)<16) {
curNibble=false; curNibble=false;
if (pat->data[cursor.y][target]>e->getMaxVolumeChan(cursor.xCoarse)) pat->data[cursor.y][target]=e->getMaxVolumeChan(cursor.xCoarse);
editAdvance(); editAdvance();
} else { } else {
curNibble=!curNibble; curNibble=!curNibble;
@ -3544,6 +3545,10 @@ bool FurnaceGUI::loop() {
break; break;
case SDL_DROPFILE: case SDL_DROPFILE:
if (ev.drop.file!=NULL) { if (ev.drop.file!=NULL) {
if (introPos<11.0) {
SDL_free(ev.drop.file);
break;
}
int sampleCountBefore=e->song.sampleLen; int sampleCountBefore=e->song.sampleLen;
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames); std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames);
DivWavetable* droppedWave=NULL; DivWavetable* droppedWave=NULL;
@ -3579,6 +3584,9 @@ bool FurnaceGUI::loop() {
SDL_free(ev.drop.file); SDL_free(ev.drop.file);
} }
break; break;
case SDL_USEREVENT:
// used for MIDI wake up
break;
case SDL_QUIT: case SDL_QUIT:
if (modified) { if (modified) {
showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT); showWarning("Unsaved changes! Save changes before quitting?",GUI_WARN_QUIT);
@ -3642,6 +3650,7 @@ bool FurnaceGUI::loop() {
while (true) { while (true) {
midiLock.lock(); midiLock.lock();
midiWakeUp=true;
if (midiQueue.empty()) { if (midiQueue.empty()) {
midiLock.unlock(); midiLock.unlock();
break; break;
@ -3925,11 +3934,13 @@ bool FurnaceGUI::loop() {
int nextPlayOrder=0; int nextPlayOrder=0;
int nextOldRow=0; int nextOldRow=0;
e->getPlayPos(nextPlayOrder,nextOldRow); e->getPlayPos(nextPlayOrder,nextOldRow);
oldRowChanged=false;
playOrder=nextPlayOrder; playOrder=nextPlayOrder;
if (followPattern) { if (followPattern) {
curOrder=playOrder; curOrder=playOrder;
} }
if (e->isPlaying()) { if (e->isPlaying()) {
if (oldRow!=nextOldRow) oldRowChanged=true;
oldRow=nextOldRow; oldRow=nextOldRow;
} }
@ -4535,6 +4546,7 @@ bool FurnaceGUI::loop() {
MEASURE(readOsc,readOsc()); MEASURE(readOsc,readOsc());
MEASURE(osc,drawOsc()); MEASURE(osc,drawOsc());
MEASURE(chanOsc,drawChanOsc()); MEASURE(chanOsc,drawChanOsc());
MEASURE(grooves,drawGrooves());
MEASURE(regView,drawRegView()); MEASURE(regView,drawRegView());
} else { } else {
globalWinFlags=0; globalWinFlags=0;
@ -5863,8 +5875,6 @@ bool FurnaceGUI::loop() {
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) { if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
pendingRawSampleChannels=1; pendingRawSampleChannels=1;
}
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
pendingRawSampleBigEndian=false; pendingRawSampleBigEndian=false;
} }
@ -5891,6 +5901,10 @@ bool FurnaceGUI::loop() {
ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles); ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles);
} }
if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_8BIT) {
ImGui::Checkbox("Swap words",&pendingRawSampleBigEndian);
}
if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) { if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) {
ImGui::Text("Encoding:"); ImGui::Text("Encoding:");
ImGui::Indent(); ImGui::Indent();
@ -6722,11 +6736,20 @@ bool FurnaceGUI::init() {
firstFrame=true; firstFrame=true;
// TODO: MIDI mapping time! userEvents=SDL_RegisterEvents(1);
e->setMidiCallback([this](const TAMidiMessage& msg) -> int { e->setMidiCallback([this](const TAMidiMessage& msg) -> int {
if (introPos<11.0) return -2; if (introPos<11.0) return -2;
midiLock.lock(); midiLock.lock();
midiQueue.push(msg); 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(); midiLock.unlock();
e->setMidiBaseChan(cursor.xCoarse); e->setMidiBaseChan(cursor.xCoarse);
if (msg.type==TA_MIDI_SYSEX) return -2; if (msg.type==TA_MIDI_SYSEX) return -2;
@ -7006,6 +7029,7 @@ FurnaceGUI::FurnaceGUI():
displayEditString(false), displayEditString(false),
mobileEdit(false), mobileEdit(false),
killGraphics(false), killGraphics(false),
midiWakeUp(true),
audioEngineChanged(false), audioEngineChanged(false),
settingsChanged(false), settingsChanged(false),
debugFFT(false), debugFFT(false),
@ -7019,6 +7043,8 @@ FurnaceGUI::FurnaceGUI():
mobileEditPage(0), mobileEditPage(0),
wheelCalmDown(0), wheelCalmDown(0),
shallDetectScale(0), shallDetectScale(0),
cpuCores(0),
userEvents(0xffffffff),
mobileMenuPos(0.0f), mobileMenuPos(0.0f),
autoButtonSize(0.0f), autoButtonSize(0.0f),
mobileEditAnim(0.0f), mobileEditAnim(0.0f),
@ -7105,6 +7131,8 @@ FurnaceGUI::FurnaceGUI():
exitDisabledTimer(0), exitDisabledTimer(0),
soloTimeout(0.0f), soloTimeout(0.0f),
exportFadeOut(5.0), exportFadeOut(5.0),
newSongFirstFrame(false),
oldRowChanged(false),
editControlsOpen(true), editControlsOpen(true),
ordersOpen(true), ordersOpen(true),
insListOpen(true), insListOpen(true),

View file

@ -28,12 +28,10 @@
#include <SDL.h> #include <SDL.h>
#include <fftw3.h> #include <fftw3.h>
#include <initializer_list> #include <initializer_list>
#include <map>
#include <future> #include <future>
#include <memory> #include <memory>
#include <mutex>
#include <tuple> #include <tuple>
#include <vector> #include "../pch.h"
#include "fileDialog.h" #include "fileDialog.h"
@ -1347,6 +1345,7 @@ class FurnaceGUI {
bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString; bool displayPendingIns, pendingInsSingle, displayPendingRawSample, snesFilterHex, modTableHex, displayEditString;
bool mobileEdit; bool mobileEdit;
bool killGraphics; bool killGraphics;
bool midiWakeUp;
bool audioEngineChanged, settingsChanged, debugFFT; bool audioEngineChanged, settingsChanged, debugFFT;
bool willExport[DIV_MAX_CHIPS]; bool willExport[DIV_MAX_CHIPS];
int vgmExportVersion; int vgmExportVersion;
@ -1360,6 +1359,7 @@ class FurnaceGUI {
int wheelCalmDown; int wheelCalmDown;
int shallDetectScale; int shallDetectScale;
int cpuCores; int cpuCores;
unsigned int userEvents;
float mobileMenuPos, autoButtonSize, mobileEditAnim; float mobileMenuPos, autoButtonSize, mobileEditAnim;
ImVec2 mobileEditButtonPos, mobileEditButtonSize; ImVec2 mobileEditButtonPos, mobileEditButtonSize;
const int* curSysSection; const int* curSysSection;
@ -1373,6 +1373,7 @@ class FurnaceGUI {
void* fmPreviewOPZ; void* fmPreviewOPZ;
void* fmPreviewOPZInterface; void* fmPreviewOPZInterface;
String* editString; String* editString;
SDL_Event userEvent;
String pendingRawSample; String pendingRawSample;
int pendingRawSampleDepth, pendingRawSampleChannels; int pendingRawSampleDepth, pendingRawSampleChannels;
@ -1818,7 +1819,7 @@ class FurnaceGUI {
double exportFadeOut; double exportFadeOut;
bool newSongFirstFrame; bool newSongFirstFrame, oldRowChanged;
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;

View file

@ -120,8 +120,8 @@ const int vgmVersions[7]={
// name, icon, letter icon // name, icon, letter icon
const char* insTypes[DIV_INS_MAX+1][3]={ const char* insTypes[DIV_INS_MAX+1][3]={
{"SN76489/Sega PSG",ICON_FA_AREA_CHART,ICON_FUR_INS_STD}, {"SN76489/Sega PSG",ICON_FA_BAR_CHART,ICON_FUR_INS_STD},
{"FM (OPN)",ICON_FA_BAR_CHART,ICON_FUR_INS_FM}, {"FM (OPN)",ICON_FA_AREA_CHART,ICON_FUR_INS_FM},
{"Game Boy",ICON_FA_GAMEPAD,ICON_FUR_INS_GB}, {"Game Boy",ICON_FA_GAMEPAD,ICON_FUR_INS_GB},
{"C64",ICON_FA_KEYBOARD_O,ICON_FUR_INS_C64}, {"C64",ICON_FA_KEYBOARD_O,ICON_FUR_INS_C64},
{"Generic Sample",ICON_FA_VOLUME_UP,ICON_FUR_INS_AMIGA}, {"Generic Sample",ICON_FA_VOLUME_UP,ICON_FUR_INS_AMIGA},

View file

@ -377,11 +377,14 @@ void FurnaceGUI::drawPattern() {
bool inhibitMenu=false; bool inhibitMenu=false;
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) { if (e->isPlaying() && followPattern) {
cursor.y=oldRow; if (oldRowChanged || !e->isStepping()) {
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { if (e->isStepping()) pendingStepUpdate=1;
selStart=cursor; cursor.y=oldRow;
selEnd=cursor; if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
selStart=cursor;
selEnd=cursor;
}
} }
} }
demandX=0; demandX=0;

View file

@ -18,7 +18,7 @@
*/ */
#include "imgui.h" #include "imgui.h"
#include <string> #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 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)); 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));

View file

@ -3093,6 +3093,7 @@ void FurnaceGUI::drawSettings() {
// "42 63" - enables all instrument types // "42 63" - enables all instrument types
// "4-bit FDS" - enables partial pitch linearity option // "4-bit FDS" - enables partial pitch linearity option
// "Power of the Chip" - enables options for multi-threaded audio // "Power of the Chip" - enables options for multi-threaded audio
// "btcdbcb" - use modern UI padding
// "????" - enables stuff // "????" - enables stuff
CONFIG_SECTION("Cheat Codes") { CONFIG_SECTION("Cheat Codes") {
// SUBSECTION ENTER CODE: // SUBSECTION ENTER CODE:
@ -3131,6 +3132,14 @@ void FurnaceGUI::drawSettings() {
mmlString[30]="unlocked audio multi-threading options!"; mmlString[30]="unlocked audio multi-threading options!";
settings.showPool=1; 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]=""; mmlString[31]="";
} }

View file

@ -273,7 +273,7 @@ void FurnaceGUI::drawTutorial() {
ImGui::TextWrapped( ImGui::TextWrapped(
"if you need help, you may:\n" "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)" "- 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)"
); );

View file

@ -19,7 +19,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string> #include "pch.h"
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
#include "SDL_events.h" #include "SDL_events.h"
#endif #endif

20
src/pch.cpp Normal file
View file

@ -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"

30
src/pch.h Normal file
View file

@ -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 <string>
#include <vector>
#include <mutex>
#include <map>
#include <unordered_map>
#endif

View file

@ -23,8 +23,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <time.h> #include <time.h>
#include <atomic> #include <atomic>
#include <string>
#include <fmt/printf.h> #include <fmt/printf.h>
#include "pch.h"
#define LOGLEVEL_ERROR 0 #define LOGLEVEL_ERROR 0
#define LOGLEVEL_WARN 1 #define LOGLEVEL_WARN 1

View file

@ -21,7 +21,7 @@
#define _TA_UTILS_H #define _TA_UTILS_H
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <string> #include "pch.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include <BaseTsd.h> #include <BaseTsd.h>