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

2
.gitignore vendored
View file

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

View file

@ -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
$<$<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 WIN32 AND NOT APPLE)
include(GNUInstallDirs)

View file

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

View file

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

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.tildearrow.furnace"
android:versionCode="178"
android:versionName="0.6pre16"
android:versionCode="181"
android:versionName="0.6"
android:installLocation="auto">
<!-- 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.
- **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?

View file

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

View file

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

View file

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

View file

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

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.
// - 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

View file

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

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)
```
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.

View file

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

View file

@ -15,17 +15,17 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>0.6pre16</string>
<string>0.6</string>
<key>CFBundleName</key>
<string>Furnace</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.6pre16</string>
<string>0.6</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>0.6pre16</string>
<string>0.6</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<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
echo "compiling Furnace doc..."
echo "compiling Furnace doc (PDF)..."
if [ ! -e .venv ]; then
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>
<h3>authors</h3>
<ul>
<li>brickblock369</li>
<li>cam900</li>
<li>DeMOSic</li>
<li>Electric Keet</li>
<li>freq-mod</li>
<li>host12prog</li>
<li>Lunathir</li>
<li>nicco1690</li>
<li>tildearrow</li>
</ul>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,13 +30,9 @@
#include "cmdStream.h"
#include "../audio/taAudio.h"
#include "blip_buf.h"
#include <atomic>
#include <functional>
#include <initializer_list>
#include <thread>
#include <mutex>
#include <map>
#include <unordered_map>
#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

View file

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

View file

@ -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)<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 {
memcpy(sample->getCurBuf(),buf,len);
}

View file

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

View file

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

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#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 (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<length; i++) {
if (i>=s->lengthC219) {
sampleMem[(memPos+i)^1]=0;
} else {
sampleMem[(memPos+i)^1]=s->dataC219[i];
if (sPos<s->lengthC219) {
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<length; i++) {
if (i>=s->length8) {
sampleMem[(memPos+i)^1]=0;
} else {
sampleMem[(memPos+i)^1]=s->data8[i];
if (sPos<s->length8) {
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; 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;
sampleLoaded[i]=true;

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define PITCH_OFFSET ((double)(16*2048*(chanMax+1)))
#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) {
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) {

View file

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

View file

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

View file

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

View file

@ -21,7 +21,6 @@
#include "../engine.h"
#include "../../ta-log.h"
#include <math.h>
#include <map>
#define CHIP_DIVIDER (1248*2)
#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)
{
// 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)
{

View file

@ -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++) {

View file

@ -402,7 +402,7 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) {
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);
@ -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);

View file

@ -333,7 +333,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) {
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);
@ -404,7 +404,8 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
buf[1][h]=os[1];
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);

View file

@ -401,7 +401,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) {
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);
@ -471,7 +471,8 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) {
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);

View file

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

View file

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

View file

@ -1181,7 +1181,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef(
"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...",
{"Wave", "Wave/PCM", "Wave", "Wave/Noise"},
{"Wave", "Wave/PCM", "Wave/Sweep", "Wave/Noise"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE},
{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"}},
{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}},
{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(

View file

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

View file

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

View file

@ -21,7 +21,6 @@
#define _WORKPOOL_H
#include <thread>
#include <mutex>
#include <atomic>
#include <functional>
#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) {
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 <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) {
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 <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) {
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) {

View file

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

View file

@ -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<DivDispatchOscBuffer*> oscBufs;
std::vector<ChanOscStatus*> oscFFTs;
std::vector<int> oscChans;

View file

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

View file

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

View file

@ -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; j<i.effectCount; j++) {
@ -744,31 +708,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##ECondition",&i.effectMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effect[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE1",tempID)) {
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::InputScalar("##EE1",ImGuiDataType_U8,&i.effect[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EE2",tempID)) {
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::InputScalar("##EE2",ImGuiDataType_U8,&i.effectMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextRow();
@ -780,31 +726,13 @@ void FurnaceGUI::drawFindReplace() {
ImGui::Combo("##EVCondition",&i.effectValMode[j],queryModes,GUI_QUERY_MAX);
ImGui::TableNextColumn();
if (FIRST_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectVal[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV1",tempID)) {
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::InputScalar("##EV1",ImGuiDataType_U8,&i.effectVal[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::TableNextColumn();
if (SECOND_VISIBLE(i.effectValMode[j])) {
snprintf(tempID,1024,"%.2X",i.effectValMax[j]);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("EV2",tempID)) {
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::InputScalar("##EV2",ImGuiDataType_U8,&i.effectValMax[j],NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
}
ImGui::PopID();

View file

@ -1274,6 +1274,7 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) {
} else {
if (e->getMaxVolumeChan(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<DivInstrument*> 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),

View file

@ -28,12 +28,10 @@
#include <SDL.h>
#include <fftw3.h>
#include <initializer_list>
#include <map>
#include <future>
#include <memory>
#include <mutex>
#include <tuple>
#include <vector>
#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;

View file

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

View file

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

View file

@ -18,7 +18,7 @@
*/
#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 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
// "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]="";
}

View file

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

View file

@ -19,7 +19,7 @@
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "pch.h"
#ifdef HAVE_SDL2
#include "SDL_events.h"
#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 <time.h>
#include <atomic>
#include <string>
#include <fmt/printf.h>
#include "pch.h"
#define LOGLEVEL_ERROR 0
#define LOGLEVEL_WARN 1

View file

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