diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2646eb8d4..b1b68d7cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: pushd ${{ steps.package-identify.outputs.filename }} cp -v ../LICENSE LICENSE.txt - cp -v ../README.md README.txt + cp -v ../res/releaseReadme/unstable-win.txt README.txt cp -vr ../papers ../${binPath}/furnace.exe ./ if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then cp -v ../${binPath}/furnace.pdb ./ @@ -285,7 +285,34 @@ jobs: run: | pushd build cpack - mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} + + mkdir orig + mkdir new + echo "y" | hdiutil attach Furnace-*-Darwin.dmg -readonly -mount required -mountpoint orig + + cp -v -r orig/Furnace.app new/Furnace.app + hdiutil detach orig + + rmdir orig + rm Furnace-*-Darwin.dmg + + if [ -e new/Furnace.app/Contents/Resources/bin/furnace ]; then + rm -v new/Furnace.app/Contents/Resources/bin/furnace + rmdir new/Furnace.app/Contents/Resources/bin + fi + + cp -v ../LICENSE new/LICENSE.txt + cp -v ../res/releaseReadme/stable-mac.txt new/README + cp -v -r ../demos new/demos + cp -v -r ../instruments new/instruments + cp -v -r ../wavetables new/wavetables + cd new + wget https://tildearrow.org/furproto/manual.pdf + cd .. + + hdiutil create -srcfolder new -volname Furnace -format UDZO furnace.dmg + + mv furnace.dmg ../${{ steps.package-identify.outputs.filename }} popd - name: Package [Linux] @@ -317,7 +344,7 @@ jobs: cd .. cp ../../LICENSE . - cp ../../README.md . + cp ../../res/releaseReadme/unstable-other.txt . cp -r ../../papers papers rmdir usr diff --git a/.gitignore b/.gitignore index 1c7ed1ead..e69bf71bb 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,8 @@ src/asm/68k/amigatest/*.bin src/asm/68k/amigatest/player res/binary_to_compressed_c res/binary_to_compressed_c.exe +res/docpdf/manual.html +res/docpdf/manual.pdf +res/docpdf/.venv +res/docpdf/htmldoc/ +res/furnace.appdata.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8aa144dc8..d9da131d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ project(furnace) if (APPLE) enable_language(OBJC) + enable_language(OBJCXX) endif() set(CMAKE_CXX_STANDARD 14) @@ -25,6 +26,15 @@ set(SYSTEM_SDL2_DEFAULT OFF) include(CheckIncludeFile) include(TestBigEndian) +execute_process(COMMAND git status RESULT_VARIABLE DONT_HAVE_GIT WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) +if (NOT DONT_HAVE_GIT) + message(STATUS "Git is available") +else() + message(WARNING "either Git is not available, or this Git repository has not been initialized. +if you have used the \"Source code\" option in the GitHub release page, you are doing it wrong! unless you manually initialize submodules, the build is guaranteed to FAIL spectacularly! +read the \"developer info\" section of README.md for more information.") +endif() + if (ANDROID) set(USE_RTMIDI_DEFAULT OFF) set(WITH_PORTAUDIO_DEFAULT OFF) @@ -211,7 +221,7 @@ endif() if (WITH_PORTAUDIO) if (SYSTEM_PORTAUDIO) find_package(PkgConfig REQUIRED) - pkg_check_modules(PORTAUDIO REQUIRED portaudio) + pkg_check_modules(PORTAUDIO REQUIRED portaudio-2.0) list(APPEND DEPENDENCIES_INCLUDE_DIRS ${PORTAUDIO_INCLUDE_DIRS}) list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${PORTAUDIO_CFLAGS_OTHER}) list(APPEND DEPENDENCIES_LIBRARIES ${PORTAUDIO_LIBRARIES}) @@ -357,14 +367,16 @@ endif() if (WITH_JACK) find_package(PkgConfig REQUIRED) pkg_check_modules(JACK REQUIRED jack) + list(APPEND AUDIO_SOURCES extern/weakjack/weak_libjack.c) list(APPEND AUDIO_SOURCES src/audio/jack.cpp) list(APPEND DEPENDENCIES_INCLUDE_DIRS ${JACK_INCLUDE_DIRS}) list(APPEND DEPENDENCIES_DEFINES HAVE_JACK) - list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${JACK_CFLAGS_OTHER}) - list(APPEND DEPENDENCIES_LIBRARIES ${JACK_LIBRARIES}) - list(APPEND DEPENDENCIES_LIBRARY_DIRS ${JACK_LIBRARY_DIRS}) - list(APPEND DEPENDENCIES_LINK_OPTIONS ${JACK_LDFLAGS_OTHER}) - list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${JACK_LDFLAGS}) + list(APPEND DEPENDENCIES_DEFINES USE_WEAK_JACK) + #list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${JACK_CFLAGS_OTHER}) + #list(APPEND DEPENDENCIES_LIBRARIES ${JACK_LIBRARIES}) + #list(APPEND DEPENDENCIES_LIBRARY_DIRS ${JACK_LIBRARY_DIRS}) + #list(APPEND DEPENDENCIES_LINK_OPTIONS ${JACK_LDFLAGS_OTHER}) + #list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${JACK_LDFLAGS}) message(STATUS "Building with JACK support") else() message(STATUS "Building without JACK support") @@ -437,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 @@ -920,6 +935,15 @@ if (WARNINGS_ARE_ERRORS) ) endif() +if (NOT ANDROID OR TERMUX) + if (NOT WIN32 AND NOT APPLE) + if (NOT DONT_HAVE_GIT) + add_custom_command(OUTPUT furnace.appdata.xml COMMAND res/make-appdata.sh ARGS ${CMAKE_SOURCE_DIR}/res/furnace.appdata.xml.in ${CMAKE_BINARY_DIR}/furnace.appdata.xml DEPENDS res/furnace.appdata.xml.in WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + list(APPEND USED_SOURCES furnace.appdata.xml) + endif() + endif() +endif() + if(ANDROID AND NOT TERMUX) add_library(furnace SHARED ${USED_SOURCES}) elseif(WIN32) @@ -945,12 +969,29 @@ 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 (CMAKE_MAJOR_VERSION GREATER_EQUAL 3 AND CMAKE_MINOR_VERSION GREATER_EQUAL 16) + if (BUILD_GUI) + target_precompile_headers(furnace PUBLIC + $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui.h> + $<$:${CMAKE_CURRENT_SOURCE_DIR}/extern/imgui_patched/imgui_internal.h> + ) + else() + target_precompile_headers(furnace PUBLIC + $<$:${CMAKE_CURRENT_SOURCE_DIR}/src/pch.h> + ) + endif() +endif() + if (NOT ANDROID OR TERMUX) if (NOT WIN32 AND NOT APPLE) include(GNUInstallDirs) install(TARGETS furnace RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES res/furnace.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) - install(FILES res/furnace.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) + if (NOT DONT_HAVE_GIT) + install(FILES ${CMAKE_BINARY_DIR}/furnace.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo) + endif() install(DIRECTORY doc DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(DIRECTORY papers DESTINATION ${CMAKE_INSTALL_DOCDIR}/other) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/furnace) diff --git a/README.md b/README.md index 37549dbda..26ce48094 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ for other operating systems, you may [build the source](#developer-info). - Irem GA20 - Ensoniq ES5506 - Namco C140 + - Namco C219 - wavetable chips: - HuC6280 used in PC Engine - Konami Bubble System WSG @@ -136,7 +137,7 @@ for other operating systems, you may [build the source](#developer-info). some people have provided packages for Unix/Unix-like distributions. here's a list. - **Arch Linux**: [furnace](https://archlinux.org/packages/extra/x86_64/furnace/) is in the official repositories. -- **FreeBSD**: [a package in ports](https://www.freshports.org/audio/furnace/) is available courtesy of ehaupt (warning: 0.5.8!). +- **FreeBSD**: [a package in ports](https://www.freshports.org/audio/furnace/) is available courtesy of ehaupt. - **Nix**: [package](https://search.nixos.org/packages?channel=unstable&show=furnace&from=0&size=50&sort=relevance&type=packages&query=furnace) thanks to OPNA2608. - **openSUSE**: [a package](https://software.opensuse.org/package/furnace) is available, courtesy of fpesari. - **Void Linux**: [furnace](https://github.com/void-linux/void-packages/tree/master/srcpkgs/furnace) is available in the official repository. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index c190afd18..000000000 --- a/TODO.md +++ /dev/null @@ -1,12 +0,0 @@ -# to-do for 0.6pre7 - -- tutorial? -- ease-of-use improvements... ideas: - - preset compat flags - - maybe reduced set of presets for the sake of simplicity - - a more preferable highlight/drag system - - some speed/intuitive workflow improvements that go a long way - - make .pdf manual out of doc/ - - break compatibility if it relieves complexity -- multi-key binds -- bug fixes diff --git a/android/app/build.gradle b/android/app/build.gradle index dcf7fe76e..8939a6d1d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 169 - versionName "0.6pre9" + versionCode 178 + versionName "0.6pre16" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index dd3c7a0bd..5a99f3cb1 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur b/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur new file mode 100644 index 000000000..9319c7b3f Binary files /dev/null and b/demos/arcade/WSG_Loop_Tune_NamcoWSG.fur differ diff --git a/demos/gameboy/On_Hold.fur b/demos/gameboy/On_Hold.fur new file mode 100644 index 000000000..e77c639b6 Binary files /dev/null and b/demos/gameboy/On_Hold.fur differ diff --git a/demos/multichip/PinBot-C30C140.fur b/demos/multichip/PinBot-C30C140.fur new file mode 100644 index 000000000..e20b2b7df Binary files /dev/null and b/demos/multichip/PinBot-C30C140.fur differ diff --git a/demos/nes/Sky Sanctuary Zone.fur b/demos/nes/Sky Sanctuary Zone.fur new file mode 100644 index 000000000..c719ee285 Binary files /dev/null and b/demos/nes/Sky Sanctuary Zone.fur differ diff --git a/demos/x16/Exerion_II_Tune.fur b/demos/x16/Exerion_II_Tune.fur new file mode 100644 index 000000000..eabc1902d Binary files /dev/null and b/demos/x16/Exerion_II_Tune.fur differ diff --git a/doc/1-intro/README.md b/doc/1-intro/README.md index f864f8f9d..cd0376e99 100644 --- a/doc/1-intro/README.md +++ b/doc/1-intro/README.md @@ -12,9 +12,11 @@ Furnace uses hexadecimal (abbreviated as "hex") numbers frequently. see [this gu ## interface -Furnace uses a music tracker interface. think of a table with music notes written on it. then that table scrolls up and plays the notes. even experienced tracker musicians might benefit from a quick review of [tracker concepts and terms](concepts.md) before using Furnace. there's also a [glossary of common terms](glossary.md). +Furnace uses a music tracker interface. think of a table with music notes written on it. then that table scrolls up and plays the notes. +for an introduction to a tracker interface, see [tracker concepts and terms](concepts.md) before using Furnace. +there's also a [glossary of common terms](glossary.md). -due to its nature of being feature-packed, it may be technical and somewhat difficult to get around. therefore we added a basic mode, which hides several advanced features. +due to its nature of being feature-packed, it may be technical and somewhat difficult to get around. therefore we added a [basic mode](../2-interface/basic-mode.md), which hides several advanced features. it also has a flexible windowing system which you may move around and organize. @@ -22,8 +24,6 @@ see [2-interface](../2-interface/README.md) and [3-pattern](../3-pattern/README. once familiar with the tracker, look to [9-guides](../9-guides/README.md) for useful techniques. +## tutorial? - -# links - -[Furnace Tutorials](https://youtube.com/playlist?list=PLCELB6AsTZUnwv0PC5AAGHjvg47F44YQ1): video tutorials created by Spinning Square Waves. \ No newline at end of file +[Furnace Tutorials](https://youtube.com/playlist?list=PLCELB6AsTZUnwv0PC5AAGHjvg47F44YQ1): video tutorials created by Spinning Square Waves. be noted that these may not apply to the current version. diff --git a/doc/1-intro/concepts.md b/doc/1-intro/concepts.md index b91797179..43361d49b 100644 --- a/doc/1-intro/concepts.md +++ b/doc/1-intro/concepts.md @@ -1,36 +1,39 @@ # concepts and terms -- A **module** is a file for a tracker that contains at least one **song**. -- Each Furnace module involves at least one **[chip](../7-systems/README.md)**, an emulation of a specific audio processor. +- a **song** (also called **module**) is a file for a tracker that contains at least one **subsong**. +- each Furnace song involves at least one **chip**, an emulation of a specific audio processor. ## tracking -The **[pattern view](../3-pattern/README.md)** is like a spreadsheet that displays the following: -- Each labeled column represents a **channel** of sound provided by the chips in use. -- Each **note** starts a sound playing. Within a channel, only one note can play at a time. -- Each note is assigned an **[instrument](../4-instrument/README.md)** which describes what it will sound like. -- An **effect** is a command that changes some aspect of playback. It can alter note pitch, volume, timing, and more. -- An instrument **macro** is an automated sequence of effects that applies to every note of that instrument. +the **[pattern view](../3-pattern/README.md)** is similar to spreadsheet that displays the following: +- each labeled column represents a **channel** of sound provided by the chips in use. +- each **note** starts a sound playing. within a channel, only one note can play at a time. +- each note is assigned an **[instrument](../4-instrument/README.md)** which describes what it will sound like. +- an **effect** is a command that changes some aspect of playback. it can alter note pitch, volume, timing, and more. +- an instrument **macro** is an automated sequence of effects that applies to every note of that instrument. +- during playback, the **playhead** moves down, scrolling through the pattern view, triggering the notes that it encounters. ## structure -The **order list** is a smaller spreadsheet showing the overall song structure. -- A song is made up of a list of orders. -- An **order** is a set of numbered patterns used for each channel. -- Each channel has its own unique list of patterns. -- Each **pattern** contains note and effect data for that channel only. -- Patterns may be used multiple times in the order list. Changing a pattern's data in one order will affect the same pattern used in other orders. +the **order list** is a smaller spreadsheet showing the overall song structure. +- a song is made up of a list of orders. +- an **order** is a set of numbered patterns used for each channel. +- each channel has its own unique list of patterns. +- each **pattern** contains note and effect data for that channel only. +- patterns may be used multiple times in the order list. changing a pattern's data in one order will affect the same pattern used in other orders. +- each pattern is made of the same number of rows as seen in the tracker view. +- during playback, the **playhead** moves down as described previously. when it reaches the end of the pattern view, it will go to the next order. +- if the last order is reached and the playhear reaches the end of the pattern view, it will go back to the beginning of the song. ## time -- Each pattern is made of the same number of rows as seen in the tracker view. -- During playback, each **row** lasts a number of ticks determined by its **speed** value. -- A **tick** is the smallest measure of time to which all note, effect, and macro times are quantized. +- during playback, each **row** lasts a number of ticks determined by the song's **speed** value(s). +- a **tick** is the smallest measure of time to which all note, effect, and macro times are quantized. ## sound -Different chips have different capabilities. Even within the same chip, each channel may have its own ways of making sound. -- Some channels use one or more waveform **generators** (sine, square, noise...) to build up a sound. -- Of special note are **[FM (frequency modulation)](../4-instrument/fm.md)** channels, which use a number of generators called **operators** that can interact to make very complex sounds. -- Some channels use **[samples](../6-sample/README.md)** which are recordings of sounds, often with defined loop points to allow a note to sustain. -- Some channels use **[wavetables](../5-wave/README.md)**, which are like very short samples of fixed length that automatically loop. \ No newline at end of file +sound chips have different capabilities. even within the same chip, each channel may have its own ways of making sound. +- some channels use one or more waveform **generators** (sine, square, noise...) to build up a sound. + - of special note are **FM (frequency modulation)** channels, which use a number of generators called **operators** that can interact to make very complex sounds. +- some channels use **[samples](../6-sample/README.md)** which are (usually) recordings of sounds, often with defined loop points to allow a note to sustain. +- some channels use **[wavetables](../5-wave/README.md)**, which are very short samples of fixed length that automatically loop. diff --git a/doc/1-intro/glossary.md b/doc/1-intro/glossary.md index fe8eacf8d..54d9fab1d 100644 --- a/doc/1-intro/glossary.md +++ b/doc/1-intro/glossary.md @@ -4,12 +4,14 @@ **ADPCM**: adaptive differential pulse code modulation. this is a variety of DPCM with a more complex method of storing the amplitude differences. -**ADSR**: attack, decay, sustain, release. these are the four necessary values for a basic volume envelope. +**ADSR**: attack, decay, sustain and release. these are elements that comprise a basic envelope. **algorithm**: the way in which the operators in an FM instrument interact. - when two operators connect to the same point, their sounds are added together. - when two operators are connected left to right, the left is the modulator and the right is the carrier sound that is modified. +**asset**: an instrument, wavetable or sample. + **bitbang**: to achieve PCM sound by sending a rapid stream of volume commands to a non-PCM channel. **BRR**: a lossy sample format used by the SNES. it has a fixed compression ratio; groups of 32 bytes (16 samples) are encoded in 9 bytes each. diff --git a/doc/1-intro/hex.md b/doc/1-intro/hex.md index 16a28bc24..d433a38a8 100644 --- a/doc/1-intro/hex.md +++ b/doc/1-intro/hex.md @@ -41,7 +41,7 @@ hex | decimal 40 | 64 ``` -# hex to decimal +## hex to decimal for example, take hexadecimal number `AA`: @@ -67,7 +67,7 @@ now for hexadecimal number `4C5F`: = 19551 ``` -# decimal to hex +## decimal to hex if it's less than 16, just memorize the table at the top of this document. @@ -96,7 +96,7 @@ now for decimal number `69420`: = 10F2C ``` -# hex-decimal table +## hex to decimal table hex | `0` | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | `9` | `A` | `B` | `C` | `D` | `E` | `F` -----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----:|----: diff --git a/doc/2-interface/README.md b/doc/2-interface/README.md index c4a375322..aa16af8d4 100644 --- a/doc/2-interface/README.md +++ b/doc/2-interface/README.md @@ -8,13 +8,13 @@ the default layout of Furnace is depicted below. ## general info -- [UI components](components.md): recommended reading for all! +- [UI components](components.md): read first! - [global keyboard shortcuts](keyboard.md) - [menu bar](menu-bar.md) ## primary windows -- [order list](order-list.md) +- [orders](order-list.md) - [play/edit controls](play-edit-controls.md) - [instrument/wavetable/sample list](asset-list.md) - [song information](song-info.md) @@ -44,4 +44,4 @@ the default layout of Furnace is depicted below. ## other topics - [basic mode](basic-mode.md) -- [settings](../2-interface/settings.md) +- [settings](settings.md) diff --git a/doc/2-interface/asset-list.md b/doc/2-interface/asset-list.md index b9fa9ce85..cc94312d4 100644 --- a/doc/2-interface/asset-list.md +++ b/doc/2-interface/asset-list.md @@ -1,48 +1,59 @@ -# instrument list +# asset list + +an "asset" refers to an instrument, wavetable or sample. + +## instrument list ![instruments window](instruments.png) -Buttons from left to right: +buttons from left to right: + - **Add**: pops up a menu to select which type of instrument to add. if only one instrument type is available, the menu is skipped. - - If the "Display instrument type menu when adding instrument" setting is disabled, this skips the menu and creates an instrument according to the chip under the cursor. - - Right-clicking always brings up the menu. -- **Duplicate**: Duplicates the currently selected instrument. -- **Open**: Brings up a file dialog to load a file as a new instrument at the end of the list. -- **Save**: Brings up a file dialog to save the currently selected asset. - - Instruments are saved as Furnace instrument (.fui) files. - - Wavetables are saved as Furnace wavetable (.fuw) files. - - Samples are saved as standard wave (.wav) files. - - Right-clicking brings up a menu with the applicable items from this list: + - if the "Display instrument type menu when adding instrument" setting is disabled, this skips the menu and creates an instrument according to the chip under the cursor. + - right-clicking always brings up the menu. +- **Duplicate**: duplicates the currently selected instrument. +- **Open**: brings up a file dialog to load a file as a new instrument at the end of the list. +- **Save**: brings up a file dialog to save the currently selected instrument. + - instruments are saved as Furnace instrument (.fui) files. + - right-clicking brings up a menu with the following options: - **save instrument as .dmp...**: saves the selected instrument in DefleMask format. - - **save wavetable as .dmw...**: saves the selected wavetable in DefleMask format. - - **save raw wavetable...**: saves the selected wavetable as raw data. - - **save raw sample...**: saves the selected sample as raw data. -- **Toggle folders/standard view**: Enables (and disables) folder view, explained below. -- **Move up**: Moves the currently selected instrument up in the list. Pattern data will automatically be adjusted to match. -- **Move down**: Same, but downward. -- **Delete**: Deletes the currently selected instrument. Pattern data will be adjusted to use the next available instrument in the list. +- **Toggle folders/standard view**: enables (and disables) folder view, explained below. +- **Move up**: moves the currently selected instrument up in the list. pattern data will automatically be adjusted to match. +- **Move down**: same, but downward. +- **Delete**: deletes the currently selected instrument. pattern data will be adjusted to use the next available instrument in the list. ## folder view ![instruments window in folder view](instruments-folder.png) -In folder view, the "Move up" and "Move down buttons disappear and a new one appears: -- **New folder**: Creates a new folder. +in folder view, the "Move up" and "Move down buttons disappear and a new one appears: +- **New folder**: creates a new folder. -Instruments may be dragged from folder to folder and even rearranged within folders without changing their associated numbers. +assets may be dragged from folder to folder and even rearranged within folders without changing their associated numbers. -Right-clicking on a folder allows one to rename or delete it. Deleting a folder does not remove the instruments in it. +right-clicking on a folder allows one to rename or delete it. deleting a folder does not remove the instruments in it. -# wavetable list +## wavetable list ![wavetables window](wavetables.png) -Everything from the instrument list applies here also, with one major difference: Moving waves around with the buttons will change their associated numbers in the list but _not_ in pattern or instrument data. Be careful! +everything from the instrument list applies here also, with one major difference: moving waves around with the buttons will change their associated numbers in the list but **not** in pattern or instrument data. be careful! -# sample list +wavetables are saved as Furnace wavetable (.fuw) files. + +- right-clicking the Save button brings up a menu with the following options: + - **save wavetable as .dmw...**: saves the selected wavetable in DefleMask format. + - **save raw wavetable...**: saves the selected wavetable as raw data. + +## sample list ![samples window](samples.png) -Everything from the wavetables list applies here also, with the addition of one button before the Delete button: -- **Preview**: Plays the selected sample at its default note. - - Right-clicking stops the sample playback. +everything from the wavetables list applies here also, with the addition of one button before the Delete button: +- **Preview**: plays the selected sample at its default note. + - right-clicking stops the sample playback. + +samples are saved as standard wave (.wav) files. + +- right-clicking the Save button brings up a menu with the following options: + - **save raw sample...**: saves the selected sample as raw data. diff --git a/doc/2-interface/basic-mode.md b/doc/2-interface/basic-mode.md index c764d9de2..cb69659d3 100644 --- a/doc/2-interface/basic-mode.md +++ b/doc/2-interface/basic-mode.md @@ -3,32 +3,34 @@ Furnace comes with a "basic mode" that can be toggled through the "settings" menu. it disables certain features in Furnace that may look intimidating or confusing for newcomers. if you find that a certain feature of Furnace is missing, see if this setting is enabled or not. among the features that cannot be accessed in this mode are: -* file menu: - * chip manipulation options (add, configure, change, remove chips) -* edit menu: - * paste special… - * operation masking - * input latch - * find and replace -* speed window: - * virtual tempo - * divider - * song length -* song info window: - * manual system naming - * tuning options -* right-clicking on the pattern window: - * gradient/fade… - * scale - * randomize - * invert values - * flip selection - * collapse - * expand -* these windows: - * mixer - * grooves - * channels - * pattern manager - * chip manager - * compatibility flags + +### edit menu +- paste special +- operation masking +- input latch +- find and replace + +### speed window +- virtual tempo +- divider +- song length + +### song info window +- manual system naming +- tuning options + +### pattern right-click menu +- gradient/fade +- scale +- randomize +- invert values +- flip selection +- collapse +- expand + +### other windows +- mixer +- grooves +- channels +- pattern manager +- compatibility flags diff --git a/doc/2-interface/components.md b/doc/2-interface/components.md index 7182138ee..4ed6e6a44 100644 --- a/doc/2-interface/components.md +++ b/doc/2-interface/components.md @@ -60,9 +60,9 @@ the options are: drag your mouse cursor to any of the options to dock the window. -if you drag to the sides (marked with blue text), the window will cover that side of the workspace. +if you drag to the sides, the window will cover that side of the workspace. -if you drag it to a window or empty space (marked with yellow text), five docking positions will appear. +if you drag it to a window or empty space, five docking positions will appear. if you drag the window to the center of another window, it will appear as another tab. diff --git a/doc/2-interface/control-edit.png b/doc/2-interface/control-edit.png index e3e2d177a..f7f3e9384 100644 Binary files a/doc/2-interface/control-edit.png and b/doc/2-interface/control-edit.png differ diff --git a/doc/2-interface/control-metronome.png b/doc/2-interface/control-metronome.png index 51822c0e4..0aa230aa6 100644 Binary files a/doc/2-interface/control-metronome.png and b/doc/2-interface/control-metronome.png differ diff --git a/doc/2-interface/control-play-pattern.png b/doc/2-interface/control-play-pattern.png index a11f0aab2..b9bec627f 100644 Binary files a/doc/2-interface/control-play-pattern.png and b/doc/2-interface/control-play-pattern.png differ diff --git a/doc/2-interface/control-play-repeat.png b/doc/2-interface/control-play-repeat.png index fc2865902..b2ae8dd95 100644 Binary files a/doc/2-interface/control-play-repeat.png and b/doc/2-interface/control-play-repeat.png differ diff --git a/doc/2-interface/control-play.png b/doc/2-interface/control-play.png index c258b5fd8..88c16d2c8 100644 Binary files a/doc/2-interface/control-play.png and b/doc/2-interface/control-play.png differ diff --git a/doc/2-interface/control-repeat.png b/doc/2-interface/control-repeat.png index 2a6a96add..ed925f389 100644 Binary files a/doc/2-interface/control-repeat.png and b/doc/2-interface/control-repeat.png differ diff --git a/doc/2-interface/control-step.png b/doc/2-interface/control-step.png index e2d86be34..2d5a68b97 100644 Binary files a/doc/2-interface/control-step.png and b/doc/2-interface/control-step.png differ diff --git a/doc/2-interface/control-stop.png b/doc/2-interface/control-stop.png index e124c60d2..d6e6f340b 100644 Binary files a/doc/2-interface/control-stop.png and b/doc/2-interface/control-stop.png differ diff --git a/doc/2-interface/controls-classic.png b/doc/2-interface/controls-classic.png index 7ffa10503..d5512c65c 100644 Binary files a/doc/2-interface/controls-classic.png and b/doc/2-interface/controls-classic.png differ diff --git a/doc/2-interface/controls-compact.png b/doc/2-interface/controls-compact.png index 7d9c7cca2..eb4c5d06f 100644 Binary files a/doc/2-interface/controls-compact.png and b/doc/2-interface/controls-compact.png differ diff --git a/doc/2-interface/controls-split.png b/doc/2-interface/controls-split.png index 89ae53c7c..6ba03a5e9 100644 Binary files a/doc/2-interface/controls-split.png and b/doc/2-interface/controls-split.png differ diff --git a/doc/2-interface/controls-vertical.png b/doc/2-interface/controls-vertical.png index 6dfd57706..c648910e0 100644 Binary files a/doc/2-interface/controls-vertical.png and b/doc/2-interface/controls-vertical.png differ diff --git a/doc/2-interface/docking.png b/doc/2-interface/docking.png index ba4d6973f..35b828688 100644 Binary files a/doc/2-interface/docking.png and b/doc/2-interface/docking.png differ diff --git a/doc/2-interface/effect-list-window.md b/doc/2-interface/effect-list-window.md index 28a1c313c..6abadae9d 100644 --- a/doc/2-interface/effect-list-window.md +++ b/doc/2-interface/effect-list-window.md @@ -1,10 +1,10 @@ # effect list window -(for more details about these effects, see [the effects page](../3-pattern/effects.md)) - ![effect list window](effect-list.png) this window provides a list of the effects that are available. +for more details about these effects, see [the effects page](../3-pattern/effects.md). + - **Chip at cursor**: the currently selected chip. the list only shows available effects for this chip. -- menu button: opens a small list of effect categories. toggle each to change whether they're shown in the list. +- menu button: opens a small list of effect categories. toggle each to change whether effects belonging to such categories will be shown in the list. diff --git a/doc/2-interface/instruments.png b/doc/2-interface/instruments.png index 56f994957..750c01594 100644 Binary files a/doc/2-interface/instruments.png and b/doc/2-interface/instruments.png differ diff --git a/doc/2-interface/interface1.png b/doc/2-interface/interface1.png index 33018b0b5..47160cae5 100644 Binary files a/doc/2-interface/interface1.png and b/doc/2-interface/interface1.png differ diff --git a/doc/2-interface/keyboard.md b/doc/2-interface/keyboard.md index 2255670e6..fec4609d7 100644 --- a/doc/2-interface/keyboard.md +++ b/doc/2-interface/keyboard.md @@ -1,10 +1,8 @@ # keyboard -everything on this list can be configured in the "Keyboard" tab of the Settings dialog: -- click on a keybind then enter a key or key combination to change it. -- right-click to clear the keybind. +everything on this list can be configured in the "Keyboard" tab of the Settings dialog. -the keys in the "Global hotkeys" section can be used in any window, though not within text boxes. +the keys in the "Global hotkeys" section can be used in any window, although not when a text field is activated. | action | default keybind | |--------------------------------------------------------|------------------| @@ -242,15 +240,4 @@ the keys in the "Global hotkeys" section can be used in any window, though not w | Zoom out | `Ctrl--` | | Toggle auto-zoom | `Ctrl-0` | | Create instrument from sample | — | -| Set loop to selection | `Ctrl-l` | - -## note input - -the settings for note input keybinds operate differently. each entry in the list of keybinds is made of the following: -- **Key**: key assignment. -- **Type**: type of note input. left-click cycles through "Note", "Note off", "Note release", and "Macro release". - - _note:_ the list is sorted by type. on changing a key's type, it will instantly move to its new sorting position! -- **Value**: number of semitones above C at the current octave. only appears for note type binds. -- **Remove**: removes the keybind from the list. - -below all the binds, select a key from the dropdown list to add it. it will appear at or near the top of the list as a note with value 0. +| Set loop to selection | `Ctrl-L` | diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index 2a6c184a5..bb3a520cb 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -2,9 +2,9 @@ the menu bar allows you to select from five menus: file, edit, settings, window and help. -items in _italics_ don't appear in basic mode and are only available in advanced mode. +items in _italic_ don't appear in basic mode and are only available in advanced mode. -# file +## file - **new...**: creates a new song. - **open...**: opens the file picker, allowing you to select a song to open. @@ -50,9 +50,9 @@ items in _italics_ don't appear in basic mode and are only available in advanced - Linux/other: `~/.config/furnace/backups` - this directory grows in size as you use Furnace. remember to delete old backups periodically to save space. -- **exit**: I think you know what this does. +- **exit**: closes Furnace. -## export audio +### export audio this option allows you to export your song in .wav format. I know I know, no .mp3 or .ogg export yet, but you can use a converter. @@ -70,7 +70,7 @@ and three export choices: - **multiple files (one per channel)**: exports the output of each channel to .wav files. - useful for usage with a channel visualizer such as corrscope. -## export VGM +### export VGM this option allows exporting to a VGM (Video Game Music) file. these can be played back with VGMPlay (for example). @@ -104,7 +104,7 @@ the following settings exist: click on **click to export** to begin exporting. -## export ZSM +### export ZSM ZSM (ZSound Music) is a format designed for the Commander X16 to allow hardware playback. it may contain data for either YM2151 or VERA chips. @@ -120,7 +120,7 @@ the following settings are available: click on **Begin Export** to... you know. -## export command stream +### export command stream this option exports a text or binary file which contains a dump of the internal command stream produced when playing the song. @@ -129,7 +129,7 @@ it's not really useful, unless you're a developer and want to use a command stre - **export (binary)**: exports in Furnace's own command stream format (FCS). see `export-tech.md` in `papers/` for details. - **export (text)**: exports the command stream as a text file. only useful for analysis, really. -# edit +## edit - **...**: does nothing except prevent accidental clicks on later menu items if the menu is too tall to fit on the program window. @@ -189,9 +189,9 @@ it's not really useful, unless you're a developer and want to use a command stre - _**find/replace**:_ shows [the Find/Replace window](../8-advanced/find-replace.md). -- **clear**: allows you to mass-delete things like songs, instruments and the like. +- **clear**: opens a window that allows you to mass-delete things like songs, unused instruments, and the like. -# settings +## settings - **full screen**: expands the Furnace window so it covers your screen. - **lock layout**: prevents you from dragging/resizing docked windows, or docking more. @@ -200,7 +200,7 @@ it's not really useful, unless you're a developer and want to use a command stre - **reset layout**: resets the workspace to its defaults. - **settings...**: shows the Settings window. these are detailed in [settings.md]. -# window +## window all these menu items show or hide their associated windows. @@ -212,23 +212,23 @@ all these menu items show or hide their associated windows. - [samples](../6-sample/README.md) - [orders](order-list.md) - [pattern](../3-pattern/README.md) -- _[mixer](mixer.md)_ -- _[grooves](grooves.md)_ -- _[channels](channels.md)_ -- _[pattern manager](pat-manager.md)_ -- _[chip manager](chip-manager.md)_ -- _[compatibility flags](compat-flags.md)_ -- [song comments](comments.md) +- _[mixer](../8-advanced/mixer.md)_ +- _[grooves](../8-advanced/grooves.md)_ +- _[channels](../8-advanced/channels.md)_ +- _[pattern manager](../8-advanced/pat-manager.md)_ +- _[chip manager](../8-advanced/chip-manager.md)_ +- _[compatibility flags](../8-advanced/compat-flags.md)_ +- [song comments](../8-advanced/comments.md) -- [piano](piano.md) -- [oscilloscope](osc.md) -- [oscilloscopes (per-channel)](chanosc.md) -- [clock](clock.md) -- [register view](regview.md) -- [log viewer](log-viewer.md) -- [stats](stats.md) +- [piano](../8-advanced/piano.md) +- [oscilloscope](../8-advanced/osc.md) +- [oscilloscopes (per-channel)](../8-advanced/chanosc.md) +- [clock](../8-advanced/clock.md) +- [register view](../8-advanced/regview.md) +- [log viewer](../8-advanced/log-viewer.md) +- [stats](../8-advanced/stats.md) -# help +## help - **effect list**: displays the effect list. - **debug menu**: this menu contains various debug utilities. @@ -244,6 +244,6 @@ at the end of the menu bar, more information may be shown: - instrument number and name. - volume in decimal, hex, and percentage. - effect type and description. -- during playback, the current values of the following will be listed:\ - > speed/groove @ tick rate (BPM) | order | row | elapsed time. +- during playback, these values will be displayed: + - `speed/groove @ tick rate (BPM) | order | row | elapsed time` - if any changes or edits have been made but not yet saved, "modified" will appear. diff --git a/doc/2-interface/order-list.md b/doc/2-interface/order-list.md index b838d811b..d118c3fa4 100644 --- a/doc/2-interface/order-list.md +++ b/doc/2-interface/order-list.md @@ -1,21 +1,22 @@ -# order list +# orders -the order list is a playlist for patterns. +this window displays the order list. a spreadsheet that contains the order of patterns that will play, from top to bottom. ![order list](order-list.png) along the top are the available channels. their abbreviations can be set in the [channels window](../8-advanced/channels.md). the highlighted channel follows the channel the pattern view cursor is in. -along the left are the order numbers. these are referenced with the `0Bxx` command. the highlighted row follows the order the pattern view cursor is in. +along the left are the order numbers. the highlighted row follows the order the pattern view cursor is in. each entry in the table is the pattern that will play during that order. these can be changed according to the order edit mode. hovering over a pattern number will pop up a tooltip showing the name of that pattern, if it has one. -The buttons are as follows: -- **Add new order**. -- **Remove order**. -- **Duplicate order**: adds a new order with patterns matching the selected one directly below it. right-click to "deep clone"; this copies all patterns involved to new ones. +the buttons are: +- **Add new order**: adds a new order. +- **Remove order**: removes the currently selected order. +- **Duplicate order**: adds a new order with patterns matching the selected one directly below it. + - right-click to "deep clone"; this copies all patterns involved to new ones. - **Move order up**: swaps the selected order with the one above it. - **Move order down**: swaps the selected order with the one below it. - **Duplicate order at end of song**: same as "Duplicate order" except the new order is added at the bottom of the list. @@ -24,6 +25,6 @@ The buttons are as follows: - **entire row**: all patterns in the order will change. - **Order edit mode**: selects the method of changing orders. - **Click to change**: a click will add one to the pattern number. a right-click will subtract one. - - **Select and type (don't scroll)**: select a pattern and type. + - **Select and type (don't scroll)**: select a pattern number and type. - **Select and type (scroll horizontally)**: as above, but after entering two digits, the cursor moves to the next channel. - **Select and type (scroll vertically)**: as above, but after entering two digits, the cursor moves to the next order. diff --git a/doc/2-interface/play-edit-controls.md b/doc/2-interface/play-edit-controls.md index 038c458eb..d7814ac25 100644 --- a/doc/2-interface/play-edit-controls.md +++ b/doc/2-interface/play-edit-controls.md @@ -1,24 +1,24 @@ # play/edit controls -The "Play/Edit Controls" are used to control playback and change parameters of the pattern view. +the "Play/Edit Controls" are used to control playback and change parameters of the pattern view. -- ![](control-play.png) **Play**: Plays from cursor position. -- ![](control-stop.png) **Stop**: Stops all playback. -- ![](control-play-pattern.png) **Play from the beginning of this pattern**: Plays from the start of current pattern. -- ![](control-play-repeat.png) **Repeat from the beginning of this pattern**: Repeats current pattern from its start. -- ![](control-step.png) **Step one row**: Plays only the row at cursor position and moves down one. -- ![](control-edit.png) **Edit**: Toggles edit mode. If off, nothing can be edited in the pattern window. (Great for playing around on the keyboard!) -- ![](control-metronome.png) **Metronome**: Toggles the metronome, which only sounds during playback. -- ![](control-repeat.png) **Repeat pattern**: Toggles pattern repeat. During playback while this is on, the current pattern will play over and over instead of following the order list. -- **Poly**: Turns on polyphony for previewing notes. Toggles to **Mono** for monophony (one note at a time only). -- **Octave**: Sets current input octave. -- **Step**: Sets edit step. If this is 1, entering a note or effect will move to the next row. If this is a larger number, rows will be skipped. If this is 0, the cursor will stay in place. -- **Follow orders**: If on, the selected order in the orders window will follow the song during playback. -- **Follow pattern**: If on, the cursor will follow playback and the song will scroll by as it plays. +- ![play](control-play.png) **Play**: plays from cursor position. +- ![stop](control-stop.png) **Stop**: stops all playback. +- ![play pattern](control-play-pattern.png) **Play from the beginning of this pattern**: plays from the start of current pattern. +- ![play repeat](control-play-repeat.png) **Repeat from the beginning of this pattern**: repeats current pattern from its start. +- ![step](control-step.png) **Step one row**: plays only the row at cursor position and moves down one. +- ![edit](control-edit.png) **Edit**: toggles edit mode. when turned off, you won't be able to enter notes. +- ![metronome](control-metronome.png) **Metronome**: toggles the metronome, which only works during playback. +- ![repeat](control-repeat.png) **Repeat pattern**: toggles pattern repeat. during playback while this is on, the current pattern will play over and over instead of following the order list. +- **Poly**: turns on polyphony for previewing notes. toggles to **Mono** for monophony (one note at a time only). +- **Octave**: sets current input octave. +- **Step**: sets edit step. if this is 1, entering a note or effect will move to the next row. if this is a larger number, rows will be skipped. if this is 0, the cursor will stay in place. +- **Follow orders**: if on, the selected order in the orders window will follow the song during playback. +- **Follow pattern**: if on, the cursor will follow playback and the song will scroll by as it plays. ## layouts -The layout can be changed in Settings > Appearance to one of these: +the layout can be changed in Settings > Appearance to one of these: ### classic diff --git a/doc/2-interface/samples.png b/doc/2-interface/samples.png index 3c6af8590..f4aa04499 100644 Binary files a/doc/2-interface/samples.png and b/doc/2-interface/samples.png differ diff --git a/doc/2-interface/settings.md b/doc/2-interface/settings.md index 34b5c8fab..c6c08a082 100644 --- a/doc/2-interface/settings.md +++ b/doc/2-interface/settings.md @@ -13,6 +13,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Disable threaded input (restart after changing!)**: processes key presses for note preview on a separate thread (on supported platforms), which reduces latency. - however, crashes have been reported when threaded input is on. enable this option if that is the case. - **Enable event delay**: may cause issues with high-polling-rate mice when previewing notes. +- **Per-channel oscilloscope threads**: runs the per-channel oscilloscope in separate threads for a performance boost when there are lots of channels. ### File @@ -31,8 +32,10 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Loops**: number of additional times to play through `0Bxx` song loop. - **Fade out (seconds)**: length of fade out after final loop. - **Remember last values** +- **Store instrument name in .fui**: when enabled, saving an instrument will store its name. this may increase file size. +- **Load instrument name from .fui**: when enabled, loading an instrument will use the stored name (if present). otherwise, it will use the file name. -### Chip +### New Song - **Initial system**: the system of chips loaded on starting Furnace. - **Current system**: sets current chips as default. @@ -58,9 +61,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Behavior -- **New instruments are blank** - - +- **New instruments are blank**: when enabled, adding FM instruments will make them blank (rather than loading the default one). ## Audio @@ -106,7 +107,11 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Metronome -- **Metronome volume** +- **Volume**: sets volume of metronome. + +### Sample preview + +- **Volume**: sets volume of sample preview. ## MIDI @@ -141,19 +146,6 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Use single control change**: maps one control change event. not useful if you want to input odd numbers. - **Control**: select the CC number that will change the value. - **Per-column control change**: when enabled, you can map several control change events to a channel's columns. - - **Instrument**\ - **Volume**\ - **Effect `x` type**\ - **Effect `x` value** - - **Disabled/custom** - - **Use dual control change (one for each nibble)** - - **CC of upper nibble** - - **CC of lower nibble** - - **Use 14-bit control change** - - **MSB CC** - - **LSB CC** - - **Use single control change (imprecise)** - - **Control** - **Volume curve**: adjust the velocity to volume curve. - **Actions**: this allows you to bind note input and control change events to actions. - **`+`** button: adds a new action. @@ -187,19 +179,12 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Cores -- **Arcade/YM2151 core**\ - **Genesis/YM2612 core**\ - **SN76489 core**\ - **NES core**\ - **FDS core**\ - **SID core**\ - **POKEY core**\ - **OPN/OPNA/OPNB cores**: - - **Playback Core(s)**: core(s) to use for realtime playback. - - **Render Core(s)**: core(s) to use for exporting audio. - - all of these are covered in the [guide to choosing emulation cores](../9-guides/emulation-cores.md). +- **Playback Core(s)**: core(s) to use for playback. +- **Render Core(s)**: core(s) to use when exporting audio. -- **PC Speaker strategy**: this is covered in the [PC speaker system doc](../7-systems/pcspkr.md). +all of these are covered in the [guide to choosing emulation cores](../9-guides/emulation-cores.md). + +- **PC Speaker strategy**: this is covered in the [PC speaker page](../7-systems/pcspkr.md). ## Keyboard @@ -208,11 +193,22 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Import** - **Export** - **Reset defaults** -- [grouped list of keybinds...](keyboard.md) - - click on a keybind then enter a key or key combination to change it - - right-click to clear the keybind +a list of keybinds is displayed. +- click on a keybind. then enter a key or key combination to change it. +- right-click to clear the keybind. +- the full list is in the [keyboard](keyboard.md) page. +#### note input + +the settings for note input keybinds operate differently. each entry in the list of keybinds is made of the following: +- **Key**: key assignment. +- **Type**: type of note input. left-click cycles through "Note", "Note off", "Note release", and "Macro release". + - note: the list is sorted by type. on changing a key's type, it will instantly move to its new sorting position! +- **Value**: number of semitones above C at the current octave. only appears for note type binds. +- **Remove**: removes the keybind from the list. + +below all the binds, select a key from the dropdown list to add it. it will appear at or near the top of the list as a note with value 0. ## Interface @@ -222,7 +218,7 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Import**: reads a .ini layout file. - **Export**: writes current layout to a .ini file. - **Reset**: resets layout to default. -- **Allow docking editors** +- **Allow docking editors**: when enabled, you'll be able to dock instrument/wave/sample editors. - **Remember window position**: remembers the window's last position on start-up. - **Only allow window movement when clicking on title bar** - **Center pop-up windows** @@ -241,56 +237,57 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Double-click time (seconds)**: maximum time between mouse clicks to recognize them as a double-click. - **Don't raise pattern editor on click** - **Focus pattern editor when selecting instrument** -- **Note preview behavior:** - - **Never** - - **When cursor is in Note column** - - **When cursor is in Note column or not in edit mode** - - **Always** +- **Note preview behavior:** allows you to disable note preview when entering notes in the pattern. + - **Never**: don't preview notes at all. + - **When cursor is in Note column**: only when the cursor is in the Note column + - **When cursor is in Note column or not in edit mode**: erm... yeah. + - **Always**: always preview notes. - **Allow dragging selection:** - - **No** - - **Yes** - - **Yes (while holding Ctrl only)** + - **No**: don't allow drag-and-drop. + - **Yes**: allow drag-and-drop. + - **Yes (while holding Ctrl only)**: allow drag-and-drop but only when holding Control (Command on macOS). - **Toggle channel solo on:** selects which interactions with a channel header will toggle solo for that channel. - Right-click or double click - Right-click - Double-click -- **Double click selects entire column** +- **Double click selects entire column**: when enabled, double clicking on a cell of the pattern will select the entire column. ### Cursor behavior -- **Insert pushes entire channel row** -- **Pull delete affects entire channel row** -- **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh. +- **Insert pushes entire channel row**: when enabled, pressing Insert will push the entire channel rather than the column at the cursor position. +- **Pull delete affects entire channel row**: when enabled, pull deleting (Backspace by default) will pull the entire channel rather than the column at the cursor position. +- **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh. for example: - if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`. - if on: moving the cursor onto the value `A5` and typing a "B" results in `5B`. - **Effect input behavior:** - - **Move down** - - **Move to effect value (otherwise move down)** - - **Move to effect value/next effect and wrap around** -- **Delete effect value when deleting effect** -- **Change current instrument when changing instrument column (absorb)** -- **Remove instrument value when inserting note off/release** -- **Remove volume value when inserting note off/release** - + - **Move down**: after entering an effect (or effect value), the cursor moves down. + - **Move to effect value (otherwise move down)**: after entering an effect, the cursor moves to its value. if entering a value, the cursor moves down. + - **Move to effect value/next effect and wrap around**: after entering an effect or effect value, the cursor moves right. if it was on the last column, it jumps back to the first effect. +- **Delete effect value when deleting effect**: if enabled, deleting effect will also delete its value. +- **Change current instrument when changing instrument column (absorb)**: if enabled, typing on the instrument column will also select the instrument you've typed. +- **Remove instrument value when inserting note off/release**: if enabled, inserting a note off or release on a row that has instrument value will remove the instrument value. +- **Remove volume value when inserting note off/release**: same as above, but for volume. ### Cursor movement -- **Wrap horizontally:** - - **No** - - **Yes** - - **Yes, and move to next/prev row** -- **Wrap vertically:** - - **No** - - **Yes** - - **Yes, and move to next/prev pattern** - - **Yes, and move to next/prev pattern (wrap around)** -- **Cursor movement keys behavior:** - - **Move by one** - - **Move by Edit Step** -- **Move cursor by edit step on delete** -- **Move cursor by edit step on insert (push)** -- **Move cursor up on backspace-delete** -- **Move cursor to end of clipboard content when pasting** +- **Wrap horizontally:** selects what to do when the cursor hits horizontal boundaries. + - **No**: don't wrap the cursor. + - **Yes**: wrap the cursor. + - **Yes, and move to next/prev row**: wrap the cursor and move it to the other row. +- **Wrap vertically:** selects what to do when the cursor hits vertical boundaries. + - **No**: don't wrap the cursor. + - **Yes**: wrap the cursor. + - **Yes, and move to next/prev pattern**: wrap the cursor and go to the next/previous order. + - **Yes, and move to next/prev pattern (wrap around)**: same as the previous option, but also wraps around the song. +- **Cursor movement keys behavior:** allows you to select how much will the cursor move by when pressing cursor movement keys. + - **Move by one**: guess. + - **Move by Edit Step**: guess. +- **Move cursor by edit step on delete**: when deleting, moves the cursor by Edit Step. +- **Move cursor by edit step on insert (push)**: when inserting, moves the cursor by Edit Step. +- **Move cursor up on backspace-delete**: when pull deleting (Backspace by default), moves cursor up. +- **Move cursor to end of clipboard content when pasting**: allows you to choose what happens after pasting. + - if on, the cursor will move to the end of the clipboard content. + - if off, the cursor won't move. ### Scrolling @@ -303,8 +300,6 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o - **Don't scroll when moving cursor** - **Move cursor with scroll wheel** - - ## Appearance ### Scaling @@ -315,16 +310,12 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o ### Text -- **Main font**: overall interface font.\ - **Header font**: font for section headers.\ - **Pattern font** font for the pattern view, the order list, and related. +- **Main font**: overall interface font. +- **Header font**: font for section headers. +- **Pattern font** font for the pattern view, the order list, and related. - if "Custom...", a file path selector will appear. - **Size**: font size. -- **Display Japanese characters**\ - **Display Chinese (Simplified) characters**\ - **Display Chinese (Traditional) characters**\ - **Display Korean characters** - - only toggle these options if you have enough graphics memory. +- **Display Japanese characters**, **Display Chinese (Simplified) characters**, **Display Chinese (Traditional) characters** and **Display Korean characters**: only toggle these options if you have enough graphics memory. - these are a temporary solution until dynamic font atlas is implemented in Dear ImGui. ### Program diff --git a/doc/2-interface/song-info.md b/doc/2-interface/song-info.md index 03d698576..1ead4f879 100644 --- a/doc/2-interface/song-info.md +++ b/doc/2-interface/song-info.md @@ -1,51 +1,53 @@ # song info -- **Name**: The track's title. -- **Author**: List of contributors to a song. If the song is a cover of someone else's work, it's customary to list their name first, followed by `[cv. YourName]`. -- **Album**: The associated album name, the name of the game the song is from, or whatever. -- **System**: The game console or computer the track is designed for. This is automatically set when creating a new tune, but in advanced mode, it can be changed to anything one wants. The **Auto** button will provide a guess based on the chips in use. +- **Name**: the track's title. +- **Author**: the author(s) of this track. +- **Album**: the associated album name (or the name of the game the song is from). +- **System**: the game console or computer the track is designed for. this is automatically set when creating a new tune, but in advanced mode, it can be changed to anything one wants. the **Auto** button will provide a guess based on the chips in use. -All of this metadata will be included in a VGM export. This isn't the case for a WAV export, however. +all of this metadata will be included in a VGM export. this isn't the case for an audio export, however. -- _**Tuning (A-4)**:_ Set tuning based on the note A-4, which should be 440 in most cases. Opening an Amiga MOD will set it to 436 for hardware compatibility. Available only in advanced mode. +- _**Tuning (A-4)**_: set tuning based on the note A-4, which should be 440 in most cases. opening an Amiga MOD will set it to 436 for hardware compatibility. available only in advanced mode. -# subsongs +## subsongs -This window allows one to create **subsongs** - multiple individual songs within a single file. Each song has its own order list and patterns, but all songs within a file share the same chips, samples, and so forth. +this window allows one to create **subsongs** - multiple individual songs within a single file. each song has its own order list and patterns, but all songs within a file share the same chips, samples, and so forth. -- The drop-down box selects the current subsong. -- The **`+`** button adds a new subsong. -- The **`−`** button permanently deletes the current subsong (unless it's the only one). -- **Name**: Title of the current subsong. -- The box at the bottom can store any arbitrary text, like a separate "Comments" box for the current subsong. +- the drop-down box selects the current subsong. +- the **`+`** button adds a new subsong. +- the **`−`** button permanently deletes the current subsong (unless it's the only one). +- **Name**: title of the current subsong. +- the box at the bottom can store any arbitrary text, like a separate "Comments" box for the current subsong. -# speed +## speed -There are multiple ways to set the tempo of a song. +there are multiple ways to set the tempo of a song. -Items in _italics_ don't appear in basic mode and are only available in advanced mode. +items in _italic_ don't appear in basic mode and are only available in advanced mode. -**Tick Rate**: The frequency of ticks per second, thus the rate at which notes and effects are processed. -- All values are allowed for all chips, though most chips have hardware limitations that mean they should stay at either 60 (approximately NTSC) or 50 (exactly PAL). -- Clicking the Tick Rate button switches to a more traditional **Base Tempo** BPM setting. +**Tick Rate**: the frequency of ticks per second, thus the rate at which notes and effects are processed. +- all values are allowed for all chips, though most chips have hardware limitations that mean they should stay at either 60 (approximately NTSC) or 50 (exactly PAL). +- clicking the Tick Rate button switches to a more traditional **Base Tempo** BPM setting. -**Speed**: The number of ticks per row. -- Clicking the "Speed" button changes to more complex modes covered in the [grooves] page. +**Speed**: the number of ticks per row. +- clicking the "Speed" button changes to more complex modes covered in the [grooves] page. -_**Virtual Tempo**:_ Simulates any arbitrary tempo without altering the tick rate. It does this by adding or skipping ticks to approximate the tempo. The two numbers represent a ratio applied to the actual tick rate. Example: -- Set tick rate to 150 BPM (60 Hz) and speed to 6. -- Set the first virtual tempo number (numerator) to 200. -- Set the second virtual tempo number (denominator) to 150. -- The track will play at 200 BPM. -- The ratio doesn't have to match BPM numbers. Set the numerator to 4 and the denominator to 5, and the virtual BPM becomes 150 × 4/5 = 120. +_**Virtual Tempo**:_ Simulates any arbitrary tempo without altering the tick rate. it does this by adding or skipping ticks to approximate the tempo. the two numbers represent a ratio applied to the actual tick rate. example: +- set tick rate to 150 BPM (60 Hz) and speed to 6. +- set the first virtual tempo number (numerator) to 200. +- set the second virtual tempo number (denominator) to 150. +- the track will play at 200 BPM. +- the ratio doesn't have to match BPM numbers. set the numerator to 4 and the denominator to 5, and the virtual BPM becomes 150 × 4/5 = 120. +- another way to accomplish this with more control over the results is to use grooves. see the page on [grooves](../8-advanced/grooves.md) for details. -_**Divider**:_ Changes the effective tick rate. A tick rate of 60Hz and a divisor of 6 will result in ticks lasting a tenth of a second each! +_**Divider**:_ Changes the effective tick rate. a tick rate of 60Hz and a divisor of 6 will result in ticks lasting a tenth of a second each! -**Highlight**: Sets the pattern row highlights: -- The first value represents the number of rows per beat. -- The second value represents the number of rows per measure. -- These don't have to line up with the music's actual beats and measures. Set them as preferred for tracking. _Note:_ These values are used for the metronome and calculating BPM. +**Highlight**: sets the pattern row highlights: +- the first value represents the number of rows per beat. +- the second value represents the number of rows per measure. +- these don't have to line up with the music's actual beats and measures. set them as preferred for tracking. + - note: these values are used for the metronome and calculating BPM. -**Pattern Length**: The length of each pattern in rows. This affects all patterns in the song, and every pattern must be the same length. (Individual patterns can be cut short by `0Bxx`, `0Dxx`, and `FFxx` commands.) +**Pattern Length**: the length of each pattern in rows. this affects all patterns in the song, and every pattern must be the same length. (Individual patterns can be cut short by `0Bxx`, `0Dxx`, and `FFxx` commands.) -_**Song Length**:_ How many orders are in the order list. Decreasing it will hide the orders at the bottom. Increasing it will restore those orders; increasing it further will add new orders of all `00` patterns. +_**Song Length**:_ how many orders are in the order list. decreasing it will hide the orders at the bottom. increasing it will restore those orders; increasing it further will add new orders of all `00` patterns. diff --git a/doc/2-interface/wavetables.png b/doc/2-interface/wavetables.png index 3de7413c3..fba696509 100644 Binary files a/doc/2-interface/wavetables.png and b/doc/2-interface/wavetables.png differ diff --git a/doc/2-interface/window.png b/doc/2-interface/window.png index 0bc4e239b..fa46ccc53 100644 Binary files a/doc/2-interface/window.png and b/doc/2-interface/window.png differ diff --git a/doc/3-pattern/README.md b/doc/3-pattern/README.md index d7e1dd7eb..f619ce287 100644 --- a/doc/3-pattern/README.md +++ b/doc/3-pattern/README.md @@ -1,6 +1,6 @@ -# patterns +# pattern -the pattern view allows you to edit the song. +the pattern view allows you to edit the song's patterns. ![pattern view](pattern.png) @@ -24,7 +24,7 @@ you may change the cursor position by clicking anywhere on the pattern. to select an area, press and hold the left mouse button. then drag the mouse and release the button to finish selection. -right-clicking within the pattern view brings up a pop-up menu with everything in the [edit menu](../2-interface/menu-bar.md) that makes sense for entering data or altering a selected area. +right-clicking within the pattern view brings up a pop-up menu with most options from the [edit menu](../2-interface/menu-bar.md). @@ -44,30 +44,30 @@ clicking the `++` at the top left corner of the pattern view cycles through thre - **-**: collapse visible columns. changes to **+** when columns are hidden; click to expand them. - **<**: disables the last effect column and hides it. effects are not deleted... - **>**: adds an effects column. if one previously existed, its contents will be preserved. -- **Pattern names**: adds a text field with which one can name the current pattern. pattern names are also visible when hovering over a pattern in the order list. +- **Pattern names**: displays pattern names (per channel). pattern names are also visible when hovering over a pattern in the order list. right-clicking the `++` toggles the visualizer, which is active only during playback. to rename and/or hide channels, open [the Channels window](../8-advanced/channels.md) via the window menu. -# input +## input -## note input +### note input ![keyboard](keyboard.png) - pressing any of the respective keys will insert a note at the cursor's location, then advance to the next row (or otherwise according to the Edit Step.) -- **note off** turns off the last played note in that channel (key off for FM; note cut otherwise). -- **note release** triggers macro release (and in FM channels it also triggers key off). -- **macro release** does the same as above, but does not trigger key off in FM channels. +- **note off** (`OFF`) turns off the last played note in that channel (key off for FM/hardware envelope; note cut otherwise). +- **note release** (`===`) triggers macro release (and in FM/hardware envelope channels it also triggers key off). +- **macro release** (`REL`) does the same as above, but does not trigger key off in FM/hardware envelope channels. - **toggle edit** enables and disables editing. when editing is enabled, the cursor's row will be shaded red. -## instrument/volume input +### instrument/volume input type any hexadecimal number (0-9 and A-F). the cursor will move by the Edit Step when a suitable value is entered. -## effect input +### effect input works like the instrument/volume input. @@ -80,7 +80,7 @@ here's [a list of effect types](effects.md). -# keyboard shortcuts +## keyboard shortcuts these are the default key functions. all keys are configurable in the Keyboard tab of the Settings window. diff --git a/doc/3-pattern/effects.md b/doc/3-pattern/effects.md index 6a9515d6c..b2622426c 100644 --- a/doc/3-pattern/effects.md +++ b/doc/3-pattern/effects.md @@ -1,14 +1,14 @@ # effect list -most of the effect numbers are from ProTracker / FastTracker 2. +some of the effect numbers are taken from ProTracker / FastTracker 2. however, effects are continuous, which means you only need to type it once and then stop it with an effect value of `00` or no effect value at all. ## volume - `0Axy`: **Volume slide.** - - If `x` is 0 then this slides volume down by `y` each tick. - - If `y` is 0 then this slides volume up by `x` each tick. + - if `x` is 0 then this slides volume down by `y` each tick. + - if `y` is 0 then this slides volume up by `x` each tick. - `FAxy`: **Fast volume slide.** same as `0Axy` above but 4× faster. - `F3xx`: **Fine volume slide up.** same as `0Ax0` but 64× slower. - `F4xx`: **Fine volume slide down.** same as `0A0x` but 64× slower. @@ -16,8 +16,8 @@ however, effects are continuous, which means you only need to type it once and t - `F9xx`: **Single tick volume slide down.** subtracts `x` from volume on first tick only. - --- - `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed. `y` is the depth. - - Tremolo is downward only. - - Maximum tremolo depth is -60 volume steps. + - tremolo is downward only. + - maximum tremolo depth is -60 volume steps. ## pitch @@ -38,11 +38,11 @@ however, effects are continuous, which means you only need to type it once and t - `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values. default is 1. - --- - `04xy`: **Vibrato.** changes pitch to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth. - - Maximum vibrato depth is ±1 semitone. + - maximum vibrato depth is ±1 semitone. - `E3xx`: **Set vibrato direction.** `xx` may be one of the following: - - `00`: Up and down. default. - - `01`: Up only. - - `02`: Down only. + - `00`: up and down. default. + - `01`: up only. + - `02`: down only. - `E4xx`: **Set vibrato range** in 1/16th of a semitone. ## panning @@ -63,7 +63,7 @@ not all chips support these effects. ## time -- `09xx`: **Set speed/groove.** if no grooves are defined, this sets speed. If alternating speeds are active, this sets the first speed. +- `09xx`: **Set speed/groove.** if no grooves are defined, this sets speed. if alternating speeds are active, this sets the first speed. - `0Fxx`: **Set speed 2.** during alternating speeds or a groove, this sets the second speed. - --- - `Cxxx`: **Set tick rate.** changes tick rate to `xxx` Hz (ticks per second). @@ -79,20 +79,21 @@ not all chips support these effects. ## note - `0Cxx`: **Retrigger.** repeats current note every `xx` ticks. - - This effect is not continuous; it must be entered on every row. -- `ECxx`: **Note cut.** ends current note after `xx` ticks. For FM instruments, it's equivalent to a "key off". + - this effect is not continuous; it must be entered on every row. +- `ECxx`: **Note cut.** ends current note after `xx` ticks. for FM instruments, it's equivalent to a "key off". - `EDxx`: **Note delay.** delays note by `x` ticks. ## other - `9xxx`: **Set sample position.** jumps current sample to position `xxx * 0x100`. - - Not all chips support this effect. + - not all chips support this effect. - `EBxx`: **Set LEGACY sample mode bank.** selects sample bank. used only for compatibility. - does not apply on Amiga. - `EExx`: **Send external command.** - this effect is currently incomplete. -- `F5xx`: **Disable macro.**\ - `F6xx`: **Enable macro.** see macro table at the end of this document for possible values. +- `F5xx`: **Disable macro.** +- `F6xx`: **Enable macro.** + - see macro table at the end of this document for possible values. additionally, [each chip has its own effects](../7-systems/README.md). @@ -147,19 +148,53 @@ additionally, [each chip has its own effects](../7-systems/README.md). the interpretation of duty, wave and extra macros depends on chip/instrument type: -ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx | C64 | SAA1099 | X1-010 | Namco 163 | FDS | Sound Unit | ES5506 | MSM6258 | QSound | SNES | MSM5232 | ----|--------|-----------|-----------|-------|------------|------------|----------|------------|----------|------------|------------|-----------|------------|-----------|----------|--------------|-----------|-----------| - D | NoiseF | NoiseFreq | | | NoiseFreq | NoiseFreq | Duty/Int | Duty | | | Wave Pos | | Duty | Filt Mode | FreqDiv | Echo Level | NoiseFreq | GroupCtrl | - W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | Waveform | Waveform | Waveform | Waveform | Waveform | | | | Waveform | | - 1 | | AMD | AMD | | | Duty | | FilterMode | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | EchoFeedback | Special | GroupAtk | - 2 | | PMD | PMD | | Envelope | Envelope | | Resonance | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | Echo Length | Gain | GroupDec | - 3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | | AutoEnvNum | WaveLoad W | | Control | Env Count | | | | Noise | - A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | | AutoEnvDen | WaveLoad P | | | Control | | | | | - B | FB | FB | FB | | | Noise AND | | | | | WaveLoad L | | | | | | | | - C | FMS | FMS | FMS | | | Noise OR | | | | | WaveLoad T | | | | | | | | - D | AMS | AMS | AMS | | | | | | | | | | | | | | | | - 4 | OpMask | OpMask | | | | | | Test/Gate | | | | | PResetTime | EnvRampL | | | | | - 5 | | | AMD2 | | | | | | | | | | | EnvRampR | | | | | - 6 | | | PMD2 | | | | | | | | | | | EnvRampK1 | | | | | - 7 | | | LFO2Speed | | | | | | | | | | | EnvRampK2 | | | | | - 8 | | | LFO2Shape | | | | | | | | | | | Env Mode | | | | | +ex | FM | OPM | OPZ | OPLL | AY-3-8910 | AY8930 | Lynx | C64 | +---|--------|-----------|-----------|-------|------------|------------|----------|------------| + D | NoiseF | NoiseFreq | | | NoiseFreq | NoiseFreq | Duty/Int | Duty | + W | | LFO Shape | LFO Shape | Patch | Waveform | Waveform | | Waveform | + 1 | | AMD | AMD | | | Duty | | FilterMode | + 2 | | PMD | PMD | | Envelope | Envelope | | Resonance | + 3 | LFOSpd | LFO Speed | LFO Speed | | AutoEnvNum | AutoEnvNum | | Special | + A | ALG | ALG | ALG | | AutoEnvDen | AutoEnvDen | | | + B | FB | FB | FB | | | Noise AND | | | + C | FMS | FMS | FMS | | | Noise OR | | | + D | AMS | AMS | AMS | | | | | | + 4 | OpMask | OpMask | | | | | | Test/Gate | + 5 | | | AMD2 | | | | | | + 6 | | | PMD2 | | | | | | + 7 | | | LFO2Speed | | | | | | + 8 | | | LFO2Shape | | | | | | + +ex | SAA1099 | X1-010 | Namco 163 | FDS | Sound Unit | ES5506 | MSM6258 | +---|----------|------------|------------|-----------|------------|-----------|----------| + D | | | Wave Pos | | Duty | Filt Mode | FreqDiv | + W | Waveform | Waveform | Waveform | Waveform | Waveform | | | + 1 | Envelope | EnvMode | WaveLen | Mod Depth | Cutoff | Filter K1 | ClockDiv | + 2 | | Envelope | WaveUpdate | Mod Speed | Resonance | Filter K2 | | + 3 | | AutoEnvNum | WaveLoad W | | Control | Env Count | | + A | | AutoEnvDen | WaveLoad P | | | Control | | + B | | | WaveLoad L | | | | | + C | | | WaveLoad T | | | | | + D | | | | | | | | + 4 | | | | | PResetTime | EnvRampL | | + 5 | | | | | | EnvRampR | | + 6 | | | | | | EnvRampK1 | | + 7 | | | | | | EnvRampK2 | | + 8 | | | | | | Env Mode | | + +ex | QSound | SNES | MSM5232 | +---|--------------|-----------|-----------| + D | Echo Level | NoiseFreq | GroupCtrl | + W | | Waveform | | + 1 | EchoFeedback | Special | GroupAtk | + 2 | Echo Length | Gain | GroupDec | + 3 | | | Noise | + A | | | | + B | | | | + C | | | | + D | | | | + 4 | | | | + 5 | | | | + 6 | | | | + 7 | | | | + 8 | | | | diff --git a/doc/4-instrument/8930.md b/doc/4-instrument/8930.md deleted file mode 100644 index ecb1e8ed8..000000000 --- a/doc/4-instrument/8930.md +++ /dev/null @@ -1,16 +0,0 @@ -# AY8930 instrument editor - -AY8930 instrument editor consists of these macros. - -- **Volume**: volume sequence -- **Arpeggio**: pitch in half-steps -- **Noise Freq**: AY8930 noise generator frequency sequence -- **Waveform**: selector of sound type: pulse wave tone, noise or envelope generator -- **Pitch**: fine pitch -- **Phase Reset**: trigger restart of waveform -- **Duty**: duty cycle of a pulse wave sequence -- **Envelope**: allows shaping an envelope -- **AutoEnv Num**: sets the envelope to the channel's frequency multiplied by numerator -- **AutoEnv Den**: sets the envelope to the channel's frequency divided by denominator -- **Noise AND Mask**: alters the shape/frequency of the noise generator, allowing to produce various interesting sound effects and even PWM phasing -- **Noise OR Mask**: see above diff --git a/doc/4-instrument/README.md b/doc/4-instrument/README.md index d8fa8b2ee..dd24c7260 100644 --- a/doc/4-instrument/README.md +++ b/doc/4-instrument/README.md @@ -12,81 +12,112 @@ the instrument editor always starts with this section: - **Type**: the system for which the instrument is intended. - if changed, all applicable settings and macros will remain as they are. numbers will not be adjusted. -depending on the instrument type, there are many different types of instrument editor: +## instrument types -- [FM synthesis](fm.md) - for use with YM2612, YM2151 and FM block portion of YM2610. -- [PSG](psg.md) - for use with TI SN76489 and derivatives like Sega Master System's PSG. -- [NES](nes.md) - for use with NES. +the following instrument types are available: + +- [SN76489/Sega PSG](psg.md) - for use with TI SN76489 and derivatives like Sega Master System's PSG. +- [FM (OPN)](fm-opn.md) - for use with YM2612, YM2203, YM2608, YM2610 and YM2610B. - [Game Boy](game-boy.md) - for use with Game Boy APU. -- [PC Engine / TurboGrafx-16](pce.md) - for use with PC Engine's wavetable synthesizer. -- [WonderSwan](wonderswan.md) - for use with WonderSwan's wavetable synthesizer. -- [AY8930](8930.md) - for use with Microchip AY8930 E-PSG sound source. -- [Commodore 64](c64.md) - for use with Commodore 64 SID. -- [SAA1099](saa.md) - for use with Philips SAA1099 PSG sound source. +- [C64](c64.md) - for use with Commodore 64 SID. +- [Generic Sample](sample.md) for controlling Amiga and other sample channels/chips like YM2612's Channel 6 PCM mode, NES channel 5, Sega PCM, X1-010 and PC Engine's sample playback mode. +- [PC Engine](pce.md) - for use with PC Engine's wavetable synthesizer. +- [AY-3-8910/SSG](ay8910.md) - for use with AY-3-8910 PSG sound source and SSG portion in YM2610. +- [AY8930](ay8930.md) - for use with Microchip AY8930 E-PSG sound source. - [TIA](tia.md) - for use with Atari 2600 chip. -- [AY-3-8910](ay8910.md) - for use with AY-3-8910 PSG sound source and SSG portion in YM2610. -- [Generic Sample](amiga.md) for controlling Amiga and other sample channels/chips like YM2612's Channel 6 PCM mode, NES channel 5, Sega PCM, X1-010 and PC Engine's sample playback mode. +- [SAA1099](saa.md) - for use with Philips SAA1099 PSG sound source. +- [VIC](vic.md) - for use with VIC-20 sound chip. +- [PET](pet.md) - for use with Commodore PET. +- [VRC6](vrc6.md) - for use with VRC6's PSG sound source. +- [FM (OPLL)](fm-opll.md) - for use with YM2413. +- [FM (OPL)](fm-opll.md) - for use with YM3526 (OPL), YM3812 (OPL2) and YMF262 (OPL3). +- [FDS](fds.md) - for use with Famicom Disk System sound source. +- [Virtual Boy](virtual-boy.md) - for use with Virtual Boy. +- [Namco 163](n163.md) - for use with Namco 163. +- [Konami SCC/Bubble System WSG](scc.md) - for use with Konami SCC and Wavetable portion in Bubble System's sound hardware. +- [FM (OPZ)](fm-opz.md) - for use with YM2414. +- [POKEY](pokey.md) - for use with Atari 8-bit computers and their POKEY sound source. +- [Beeper](beeper.md) - for use with PC Speaker and ZX Spectrum Beeper (SFX-like engine). +- [WonderSwan](wonderswan.md) - for use with WonderSwan's wavetable synthesizer. - [Atari Lynx](lynx.md) - for use with Atari Lynx handheld console. - [VERA](vera.md) - for use with Commander X16 VERA. - [Seta/Allumer X1-010](x1_010.md) - for use with Wavetable portion in Seta/Allumer X1-010. -- [Konami SCC / Bubble System WSG](scc.md) - for use with Konami SCC and Wavetable portion in Bubble System's sound hardware. -- [Namco 163](n163.md) - for use with Namco 163. -- [Konami VRC6](vrc6.md) - for use with VRC6's PSG sound source. -- [SNES](snes.md) - for use with SNES S-APU. -- [Casio PV-1000](pv1000.md) - for use with Casio PV-1000. -- [C140](c140.md) for use with Namco C140. +- [ES5506](es5506.md) - for use with Ensoniq ES5506 sound chip. +- [SNES](snes.md) - for use with SNES. +- [Sound Unit](su.md) - for use with Sound Unit chip. +- [Namco WSG](wsg.md) - for use with Namco WSG wavetable chips, including C15 and C30. +- [FM (OPM)](fm-opm.md) - for use with YM2151. +- [NES](nes.md) - for use with NES. +- [MSM6258](msm6258.md) - for use with MSM6258 sample chip. +- [MSM6295](msm6295.md) - for use with MSM6295 sample chip. +- [ADPCM-A](adpcm-a.md) - for use with ADPCM-A sample chip. +- [ADPCM-B](adpcm-b.md) - for use with ADPCM-B sample chip. +- [SegaPCM](segapcm.md) - for use with SegaPCM sample chip. +- [QSound](qsound.md) - for use with QSound sample chip. +- [YMZ280B](ymz280b.md) - for use with YMZ280B sample chip. +- [RF5C68](rf5c68.md) - for use with RF5C68 sample chip. +- [MSM5232](msm5232.md) - for use with MSM5232 PSG sound source. +- [T6W28](t6w28.md) - for use with Toshiba T6W28 PSG sound source. +- [K007232](k007232.md) - for use with K007232 sample chip. +- [GA20](ga20.md) - for use with GA20 sample chip. +- [Pokémon Mini/QuadTone](pokemini.md) - for use with these systems. +- [SM8521](sm8521.md) - for use with SM8521 chip, used in Tiger Game.com. +- [PV-1000](pv1000.md) - for use with Casio PV-1000. +- [K053260](k053260.md) - for use with K053260 sample chip. +- [TED](ted.md) - for use with Commodore Plus/4 and Commodore 16's TED chip. +- [C140](c140.md) - for use with C140 sample chip. +- [C219](c219.md) - for use with C219 sample chip. +## macros -# macros +macros are incredibly versatile tools for automating instrument parameters. -Macros are incredibly versatile tools for automating instrument parameters. - -After creating an instrument, open the Instrument Editor and select the "Macros" tab. There may be multiple macro tabs to control individual FM operators and such. +after creating an instrument, open the Instrument Editor and select the "Macros" tab. there may be multiple macro tabs to control individual FM operators and such. ![macro view](macroview.png) -The very first numeric entry sets the visible width of the bars in sequence-type macros. The scrollbar affects the view of all macros at once. There's a matching scrollbar at the bottom underneath all the macros. +the very first numeric entry sets the visible width of the bars in sequence-type macros. the scrollbar affects the view of all macros at once. there's a matching scrollbar at the bottom underneath all the macros. -Each macro has two buttons on the left. -- Macro type (explained below). -- Timing editor, which pops up a small dialog: - - Step Length (ticks): Determines how many ticks pass before each change of value. Default is 1. - - Delay: Delays the start of the macro until this many ticks have passed. Default is 0. - - The button is highlighted if either of these is set differently from default. +each macro has two buttons on the left. +- macro type (explained below). +- timing editor, which pops up a small dialog: + - **Step Length (ticks)**: determines how many ticks pass before each change of value. default is 1. + - **Delay**: delays the start of the macro until this many ticks have passed. default is 0. + - the button is highlighted if either of these is set differently from default. ## macro types -Every macro can be defined though one of three methods, selectable with the leftmost button under the macro type label: +every macro can be defined though one of three methods, selectable with the leftmost button under the macro type label: -- ![](macro-button-seq.png) **Sequence:** displayed as a bar graph, this is a sequence of numeric values. -- ![](macro-button-ADSR.png) **ADSR:** this is a traditional ADSR envelope, defined by the rate of increase and decrease of value over time. -- ![](macro-button-LFO.png) **LFO:** the Low Frequency Oscillator generates a repeating wave of values. +- ![sequence](macro-button-seq.png) **Sequence:** displayed as a bar graph, this is a sequence of numeric values. +- ![ADSR](macro-button-ADSR.png) **ADSR:** this is a traditional ADSR envelope, defined by the rate of increase and decrease of value over time. +- ![LFO](macro-button-LFO.png) **LFO:** the Low Frequency Oscillator generates a repeating wave of values. -Some macros are "bitmap" style. They represent a number of "bits" that can be toggled individually, and the values listed represent the sum of which bits are turned on. +some macros are "bitmap" style. they represent a number of "bits" that can be toggled individually, and the values listed represent the sum of which bits are turned on. ### sequence ![sequence macro editor](macro-seq.png) -The number between the macro type label and the macro type button is the macro length in steps. The `-` and `+` buttons change the length of the macro. Start out by adding at least a few steps. +the number between the macro type label and the macro type button is the macro length in steps. the `-` and `+` buttons change the length of the macro. start out by adding at least a few steps. -The values of the macro can be drawn in the "bar graph" box. +the values of the macro can be drawn in the "bar graph" box. -Just beneath the box is a shorter bar that controls looping. -- Click to set the start point of a loop; the end point is the last value or release point. It appears as half-height bars. Right-click to remove the loop. -- Shift-click to set the release point. When played, the macro will hold here until the note is released. It appears as a full-height bar. Right-click to remove the release point. +just beneath the box is a shorter bar that controls looping. +- click to set the start point of a loop; the end point is the last value or release point. it appears as half-height bars. right-click to remove the loop. +- shift-click to set the release point. when played, the macro will hold here until the note is released. it appears as a full-height bar. right-click to remove the release point. -Finally, the sequence of values can be directly edited in the text box at the bottom. -- The loop start is entered as a `|`. -- The release point is entered as a `/`. -- In arpeggio macros, a value starting with a `@` is an absolute note (instead of a relative shift). No matter the note entered in the pattern, `@` values will be played at that exact note. This is especially useful for noise instruments with preset periods. +finally, the sequence of values can be directly edited in the text box at the bottom. +- the loop start is entered as a `|`. +- the release point is entered as a `/`. +- in arpeggio macros, a value starting with a `@` is an absolute note (instead of a relative shift). no matter the note entered in the pattern, `@` values will be played at that exact note. this is especially useful for noise instruments with preset periods. ### ADSR ![ADSR macro editor](macro-ADSR.png) - **Bottom** and **Top** determine the range of outputs generated by the macro. (Bottom can be larger than Top to invert the envelope!) All outputs will be between these two values. -- Attack, Decay, Sustain, SusDecay, and Release accept inputs between 0 to 255. These are scaled to the distance between Bottom and Top. +- attack, Decay, Sustain, SusDecay, and Release accept inputs between 0 to 255. these are scaled to the distance between Bottom and Top. - **Attack** is how much the value moves toward Top with each tick. - **Hold** sets how many ticks to stay at Top before Decay. - **Decay** is how much the value moves to the Sustain level. @@ -104,31 +135,25 @@ Finally, the sequence of values can be directly edited in the text box at the bo - **Bottom** and **Top** determine the range of values generated by the macro. (Bottom can be larger than Top to invert the waveform!) - **Speed** is how quickly the values change - the frequency of the oscillator. - **Phase** is which part of the waveform the macro will start at, measured in 1/1024 increments. -- **Shape** is the waveform used. Triangle is the default, and Saw and Square are exactly as they say. +- **Shape** is the waveform used. triangle is the default, and Saw and Square are exactly as they say. -# wavetable +## wavetable -This tab appears for PC Engine, FDS, Namco WSG, and other wavetable-based instruments. +this tab appears for PC Engine, FDS, Namco WSG, and other wavetable-based instruments. ![wavetable tab](wavetable.png) -When **Enable synthesizer** is off, the wavetable used for the instrument may be selected by creating a Waveform macro with a single value. +when **Enable synthesizer** is off, the wavetable used for the instrument may be selected by creating a Waveform macro with a single value. -To use the wavetable synthesizer, refer to the bottom part of [the wavetable documentation](../5-wave/README.md). +to use the wavetable synthesizer, refer to [the wavetable synthesizer section](wavesynth.md). -# sample +## sample -This tab appears for Generic PCM, SNES, Amiga, and other sample-based instruments. +this tab appears for Generic PCM DAC, Amiga and SNES. ![sample tab](sample-map.png) -- **Initial Sample**: the sample that the instrument will use. -- **Use wavetable**: instead of samples, use wavetables. this causes the [Wavetables](../5-wave/README.md) tab to appear next to Sample. - - depending on the system and use of the wavetable synthesizer, this may or may not be reproducible on hardware. -- **Use sample map**: assigns a sample to each note. - - to set a note's sample, click the list entry in the "#" column then type the number of the sample. - - to set the pitch at which a sample is played, click the list entry in the "note" column and press the key for the new note. - +see the [Generic Sample section](sample.md) for more information. diff --git a/doc/4-instrument/adpcm-a.md b/doc/4-instrument/adpcm-a.md new file mode 100644 index 000000000..55d96f860 --- /dev/null +++ b/doc/4-instrument/adpcm-a.md @@ -0,0 +1,16 @@ +# ADPCM-A instrument editor + +the ADPCM-A instrument editor contains two tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +note that samples on ADPCM-A are tied to one frequency. + +## Macros + +- **Volume**: volume sequence. +- **Global Volume**: sets the global volume of the ADPCM-A part. +- **Panning**: toggle left/right output. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/adpcm-b.md b/doc/4-instrument/adpcm-b.md new file mode 100644 index 000000000..75579e4c9 --- /dev/null +++ b/doc/4-instrument/adpcm-b.md @@ -0,0 +1,15 @@ +# ADPCM-B instrument editor + +the ADPCM-B instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning**: toggle left/right output. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/amiga.md b/doc/4-instrument/amiga.md deleted file mode 100644 index 4799d7cf3..000000000 --- a/doc/4-instrument/amiga.md +++ /dev/null @@ -1,18 +0,0 @@ -# Amiga/PCM sound source instrument editor - -The Generic Sample instrument editor consists of a sample selector and several macros: - -# Sample - -- **Initial sample**: specifies which sample should be assigned to the instrument, or the first one in the sequence -- **Use sample map**: enables mapping different samples to notes. - -# Macros - -- **Volume**: volume sequence. does not apply to some chips. -- **Arpeggio**: pitch sequence. -- **Waveform**: waveform sequence. -- **Panning (left)**: output level for left channel. -- **Panning (right)**: output level for right channel. -- **Pitch**: fine pitch. -- **Phase Reset**: trigger restart of waveform. \ No newline at end of file diff --git a/doc/4-instrument/ay8910.md b/doc/4-instrument/ay8910.md index c4a0a8154..b47e46444 100644 --- a/doc/4-instrument/ay8910.md +++ b/doc/4-instrument/ay8910.md @@ -1,13 +1,30 @@ # AY-3-8910 instrument editor -The AY-3-8910 instrument editor consists of these macros. +the AY-3-8910 instrument editor consists of two tabs. -- **Volume**: volume levels sequence -- **Arpeggio**: pitch sequence -- **Noise Freq**: AY-3-8910 noise generator frequency sequence -- **Waveform**: selector of sound type - square wave tone, noise or envelope generator -- **Pitch**: fine pitch -- **Phase Reset**: trigger restart of waveform -- **Envelope**: allows shaping an envelope -- **AutoEnv Num**: sets the envelope to the channel's frequency multiplied by numerator -- **AutoEnv Den**: sets the envelope to the channel's frequency multiplied by denominator +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +note that using samples on AY is CPU expensive! + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise Freq**: noise generator frequency sequence. + - note: global! +- **Waveform**: selector of sound type - square wave tone, noise and/or envelope generator. + - you may select more than one option. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of **envelope**. +- **Envelope**: configures the hardware envelope. + - **enable**: sets whether envelope is enabled. + - **direction**: flips the envelope's direction. + - **alternate**: when enabled, the envelope will change direction once it hits a boundary. + - **hold**: sets whether the envelope should stop when hitting boundary, or loop. +- **AutoEnv Num**: sets the envelope to the channel's frequency multiplied by numerator. +- **AutoEnv Den**: sets the envelope to the channel's frequency multiplied by denominator. + - these two must be set in order for AutoEnv to work! diff --git a/doc/4-instrument/ay8930.md b/doc/4-instrument/ay8930.md new file mode 100644 index 000000000..7bec40073 --- /dev/null +++ b/doc/4-instrument/ay8930.md @@ -0,0 +1,33 @@ +# AY8930 instrument editor + +the AY8930 instrument editor consists of two tabs. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +note that using samples on AY is CPU expensive! + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise Freq**: noise generator frequency sequence. + - note: global! +- **Waveform**: selector of sound type - square wave tone, noise and/or envelope generator. + - you may select more than one option. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of **envelope**. +- **Duty**: duty cycle sequence. +- **Envelope**: configures the hardware envelope. + - **enable**: sets whether envelope is enabled. + - **direction**: flips the envelope's direction. + - **alternate**: when enabled, the envelope will change direction once it hits a boundary. + - **hold**: sets whether the envelope should stop when hitting boundary, or loop. +- **AutoEnv Num**: sets the envelope to the channel's frequency multiplied by numerator. +- **AutoEnv Den**: sets the envelope to the channel's frequency multiplied by denominator. + - these two must be set in order for AutoEnv to work! +- **Noise AND Mask**: alters the shape/frequency of the noise generator, allowing to produce various interesting sound effects and even PWM phasing. +- **Noise OR Mask**: see above. diff --git a/doc/4-instrument/beeper.md b/doc/4-instrument/beeper.md new file mode 100644 index 000000000..18fca296d --- /dev/null +++ b/doc/4-instrument/beeper.md @@ -0,0 +1,9 @@ +# beeper instrument editor + +used in PC Speaker and ZX Spectrum (SFX-like engine). + +- **Volume**: on-off volume sequence. +- **Arpeggio**: pitch sequence. +- **Pulse Width**: pulse width sequence. + - only on ZX Spectrum. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/c140.md b/doc/4-instrument/c140.md index 50d20d3e9..65331b34f 100644 --- a/doc/4-instrument/c140.md +++ b/doc/4-instrument/c140.md @@ -1,17 +1,16 @@ # Namco C140 instrument editor -the Namco C140 instrument editor consists of a sample selector and several macros: +the Namco C140 instrument editor contains two tabs: Sample and Macros. -# Sample +## Sample -- **Initial sample**: specifies which sample should be assigned to the instrument, or the first one in the sequence. -- **Use sample map**: enables mapping different samples to notes. +for sample settings, see [the Sample instrument editor](sample.md). -# Macros +## Macros - **Volume**: volume sequence. - **Arpeggio**: pitch sequence. - **Panning (left)**: output level for left channel. - **Panning (right)**: output level for right channel. - **Pitch**: fine pitch. -- **Phase Reset**: trigger restart of sample. \ No newline at end of file +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/c219.md b/doc/4-instrument/c219.md new file mode 100644 index 000000000..0b8b3586f --- /dev/null +++ b/doc/4-instrument/c219.md @@ -0,0 +1,20 @@ +# Namco C219 instrument editor + +the Namco C219 instrument editor contains two tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Control**: channel control sequence: + - **surround**: invert the right output for a surround effect. + - **invert**: invert both outputs. when used together with surround, this inverts just the left output. + - **noise**: toggles noise mode. + - setting control bits restart the sample! +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/c64.md b/doc/4-instrument/c64.md index 5dd20408a..bd864b031 100644 --- a/doc/4-instrument/c64.md +++ b/doc/4-instrument/c64.md @@ -1,35 +1,48 @@ # C64 SID instrument editor -The C64 instrument editor consists of two tabs: "C64" to control various parameters of sound channels, and "Macros" containing several macros. +the C64 instrument editor consists of two tabs: "C64" to control various parameters of sound channels, and "Macros" containing several macros. ## C64 -- **Waveform**: allows selecting a waveform. NOTE: more than one waveform can be selected at once, logical AND mix of waves will be produced, with an exception of a noise waveform, it can't be mixed. -- **Attack**: determines the rising time for the sound. The bigger the value, the slower the attack. (0-15 range) -- **Decay**: Determines the diminishing time for the sound. The higher the value, the longer the decay. It's the initial amplitude decay rate. (0-15 range) -- **Sustain**: Sets the volume level at which the sound stops decaying and holds steady. (0-15 range) -- **Release**: Determines the rate at which the sound disappears after KEY-OFF. The higher the value, the longer the release. (0-15 range) -- **Ring Modulation**: enables the ring modulation affecting the instrument. -- **Duty**: specifies the width of a pulse wave. (0-4095 range) -- **Oscillator Sync**: enables the oscillator hard sync. As one oscillator finishes a cycle, it resets the period of another oscillator, forcing the latter to have the same base frequency. This can produce a harmonically rich sound, the timbre of which can be altered by varying the synced oscillator's frequency. -- **Enable filter**: enables analogue filter affecting the instrument +- **Waveform**: allows selecting a waveform. + - more than one waveform can be selected at once. in that case logical AND mix of waves will occur. + - noise is an exception. it cannot be used with any of the other waveforms. +- **Attack**: determines the rising time for the sound. the bigger the value, the slower the attack. (0 to 15). +- **Decay**: determines the diminishing time for the sound. the higher the value, the longer the decay (0 to 15). +- **Sustain**: sets the volume level at which the sound stops decaying and holds steady (0 to 15). +- **Release**: determines the rate at which the sound fades out after note off. the higher the value, the longer the release (0 to 15). + +- **Duty**: specifies the width of a pulse wave (0 to 4095). + +- **Ring Modulation**: when enabled, the channel's output will be multiplied with the previous channel's. +- **Oscillator Sync**: enables oscillator hard sync. as the previous channel's oscillator finishes a cycle, it resets the period of the channel's oscillator, forcing the latter to have the same base frequency. this can produce a harmonically rich sound, the timbre of which can be altered by varying the synchronized oscillator's frequency. + +- **Enable filter**: when enabled, this instrument will go through the filter. - **Initialize filter**: initializes the filter with the specified parameters: -- **Cutoff**: defines the "intensity" of a filter, to put in in layman terms (0-2047 range) -- **Resonance**: defines an additional controlled amplification of that cutoff frequency, creating a secondary peak forms and colors the original pitch. (0-15 range) -- **Filter mode**: determined the filter mode NOTE: SID's filter is multi-mode, you can mix different modes together (like low and high-pass filters at once) CH3-OFF disables the channel 3, for no reason whatsoever lmao -- **Volume Macro is Cutoff Macro**: turns a volume macro in a macros tab into a filter cutoff macro. -- **Absolute Cutoff Macro**: changes the behaviour of a cutoff macro from the old-style, compatible to much more define-able. -- **Absolute Duty Macro**: changes the behaviour of a duty cycle macro from the old-style, compatible to much more definable. -- **Don't test/gate before new note**: Don't reset the envelope to zero when a new note starts. (Read "Test/Gate" below for more info.) + - **Cutoff**: the filter's point in where frequencies are cut off (0 to 2047). + - **Resonance**: amplifies or focuses on the cutoff frequency, creating a secondary peak forms and colors the original pitch (0 to 15). + - **Filter mode**: sets the filter mode. you may pick one or more of the following: + - **low**: a low-pass filter. the lower the cutoff, the darker the sound. + - **high**: a high-pass filter. higher cutoff values result in a less "bassy" sound. + - **band**: a band-pass filter. cutoff determines which part of the sound is heard (from bass to treble). + - **ch3off**: mutes channel 3 when enabled. not sure why is this part of the chip's design, but it is. + +- **Volume Macro is Cutoff Macro**: turns the volume macro in the Macros tab into a filter cutoff macro. + - volume control is global (affects entire chip output), hence the option. +- **Absolute Cutoff Macro**: when enabled, the cutoff macro will go from 0 to 2047, and it will be absolute (in other words, control the cutoff directly rather than being relative). +- **Absolute Duty Macro**: when enabled, the duty macro will go from 0 to 4095. +- **Don't test before new note**: this option disables the one-tick hard reset and test bit before a new note. ## Macros -- **Volume**: volume sequence (WARNING: Volume sequence is global for ALL three channels!!) -- **Arpeggio**: pitch sequence -- **Duty**: pulse duty cycle sequence -- **Waveform**: select the waveform used by instrument -- **Pitch**: fine pitch -- **Filter mode**: select the filter mode/sequence -- **Resonance**: filter resonance sequence -- **Special**: ring and oscillator sync selector -- **Test/Gate**: When on, the TEST bit resets and locks Oscillator 1 at zero until cleared. The GATE bit controls Oscillator 1's envelope: Gate on runs through the envelope's attack, delay, and sustain; Gate off is envelope release. \ No newline at end of file +- **Volume**: volume sequence. + - warning: volume sequence is global! this means it controls the chip's volume and therefore affects all channels. + - this macro becomes **Cutoff** when the **Volume Macro is Cutoff Macro** option is enabled in the C64 tab. +- **Arpeggio**: pitch sequence. +- **Duty**: pulse width sequence. +- **Waveform**: select the waveform used by instrument. +- **Pitch**: fine pitch. +- **Filter mode**: select the filter mode. +- **Resonance**: filter resonance sequence. +- **Special**: ring and oscillator sync selector. +- **Test/Gate**: when on, the test bit is set, which mutes the channel. diff --git a/doc/4-instrument/es5506.md b/doc/4-instrument/es5506.md new file mode 100644 index 000000000..891cf484f --- /dev/null +++ b/doc/4-instrument/es5506.md @@ -0,0 +1,43 @@ +# Ensoniq ES5506 instrument editor + +the ES5506 instrument editor contains three tabs: Sample, ES5506 and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## ES5506 + +ES5506 contains a filter, which is somewhat configurable. +there's also a hardware envelope, but it's probably most useful for smoothing. + +you may use this tab to set up ES5506-specific parameters: + +- **Filter Mode**: sets filter mode. + - **HP/K2, HP/K2**: run high-pass twice using filter K2. + - **HP/K2, LP/K1**: run high-pass using filter K2, and then low-pass using filter K1. + - **LP/K2, LP/K2**: run low-pass twice using filter K2. + - **LP/K2, LP/K1**: run low-pass using filter K2, and then again using filter K1. +- **Filter K1**: set coefficient 1 (K1). effectively controls cutoff. +- **Filter K2**: set coefficient 2 (K2). effectively controls cutoff. +- **Envelope count**: set length of hardware envelope (it's very short even at highest value). +- **Left Volume Ramp**: how much to change left volume on every envelope step. +- **Right Volume Ramp**: how much to change right volume on every envelope step. +- **Filter K1 Ramp**: how much to change filter K1 every envelope step. +- **Filter K2 Ramp**: how much to change filter K2 on every envelope step. +- **K1 Ramp Slowdown**: increases length of K1 ramp. +- **K2 Ramp Slowdown**: increases length of K2 ramp. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Filter Mode**: sets filter mode. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. +- **Filter K1**: K1 sequence. +- **Filter K2**: K2 sequence. +- **Outputs**: ES5506 has 6 stereo output (total 12). select which pair of outputs to use. +- **Control**: reverse/pause sequence. diff --git a/doc/4-instrument/fds.md b/doc/4-instrument/fds.md new file mode 100644 index 000000000..fb72dddc6 --- /dev/null +++ b/doc/4-instrument/fds.md @@ -0,0 +1,29 @@ +# FDS instrument editor + +the FDS instrument editor contains three tabs: FDS, Wavetable and Macros. + +## FDS + +here you can edit FDS-specific settings. + +- **Compatibility mode**: DO NOT ENABLE. this exists for DefleMask compatibility. leave it alone. + +- **Modulation depth**: sets frequency modulation depth. +- **Modulation speed**: sets frequency modulation speed. +- **Modulation table**: this allows you to define a waveform for frequency modulation. + - the range is -4 to 3. + - a value of -4 will reset the modulator. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Waveform**: wavetable sequence. +- **Pitch**: fine pitch. +- **Mod Depth**: modulation depth. +- **Mod Speed**: modulation speed. +- **Mod Position**: sets position of modulator. diff --git a/doc/4-instrument/fm-opl.md b/doc/4-instrument/fm-opl.md new file mode 100644 index 000000000..bfd979651 --- /dev/null +++ b/doc/4-instrument/fm-opl.md @@ -0,0 +1,71 @@ +# OPL FM synthesis instrument editor + +the OPL FM editor is divided into 7 tabs: + +- **FM**: for controlling the basic parameters of FM sound source. +- **Macros (FM)**: for macros controlling algorithm and feedback. +- **Macros (OP1)**: for macros controlling FM parameters of operator 1. +- **Macros (OP2)**: for macros controlling FM parameters of operator 2. +- **Macros (OP3)**: for macros controlling FM parameters of operator 3 (only when 4-op flag is set and only on OPL3!). +- **Macros (OP4)**: for macros controlling FM parameters of operator 4 (only when 4-op flag is set and only on OPL3!). +- **Macros**: for other macros (volume/arp/pitch/pan). + +## FM + +the OPL synthesizers are nominally two-operator (OPL3 supports 4-operator mode on up to six channels), meaning it takes two oscillators to produce a single sound. + +these apply to the instrument as a whole: +- **Algorithm (ALG)**: determines how operators are connected to each other (0-1 range and OPL1 and OPL2; 0-3 range on OPL3 4op mode). + - left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. + - right-click to switch to a preview display of the waveform generated on a new note: + - left-click restarts the preview. + - middle-click pauses and unpauses the preview. + - right-click returns to algorithm view. +- **Feedback (FB)**: determines how many times operator 1 returns its output to itself (0 to 7). + +- **4-op**: enables 4-operator FM instrument editor mode (only on OPL3). +- **Drums**: enables OPL drum mode editor. + +these apply to each operator: +- the crossed-arrows button can be dragged to rearrange operators. +- **Amplitude Modulation (AM)**: makes the operator affected by LFO tremolo. +- **Sustain flag (SUS)**: when enabled, value of Sustain Level is in effect. +- **Attack Rate (AR)**: determines the rising time for the sound. the bigger the value, the faster the attack (0 to 15). +- **Decay Rate (DR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. it's the initial amplitude decay rate (0 to 15). +- **Sustain Level (SL)**: determines the point at which the sound ceases to decay and changes to a sound having a constant level. the sustain level is expressed as a fraction of the maximum level (0 to 15). +- **Release Rate (RR)**: determines the rate at which the sound disappears after note off. the higher the value, the shorter the release (0 to 15). +- **Total Level (TL)**: represents the envelope’s highest amplitude, with 0 being the largest and 63 (decimal) the smallest. a change of one unit is about 0.75 dB. +- **Key Scale Level (KSL)**: also known as "Level Scale". determines the degree to which the amplitude decreases according to the pitch. + +![FM ADSR chart](FM-ADSRchart.png) + +- **Key Scale Rate (KSR)**: also known as "Rate Scale". determines the degree to which the envelope execution speed increases according to the pitch. +- **Frequency Multiplier (MULT)**: sets the coarse pitch offset in relation to the note (0 to 15). 0 is -1 octave, 1 is 0 octaves, 2 is 1 octave, 3 is 1 octave 7 semitones, and so on. + - note that values 11, 13 and 14 behave as 10, 12 and 12 respectively. +- **Waveform Select (WS)**: changes the waveform of the operator (OPL2 and OPL3 only, 0-3 range on OPL2 and 0-7 on OPL3). +- **Vibrato (VIB)**: makes the operator affected by LFO vibrato. + +## macros + +these macros allow you to control several parameters of FM per tick. + +## FM Macros + +all parameters are listed above. + +## OP1-OP4 Macros + +all parameters are listed above. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning**: enables output on left/right/rear channels. OPL3 only. +- **Pitch**: fine pitch. + - **Relative**: when enabled, pitch changes are relative to the current pitch. +- **Phase Reset**: restarts all operators and resets the waveform to its start. + +## OPL (drums) instrument editor + +this is similar to the OPL instrument editor, but sets the parameters of snare, tom, top and hi-hat directly once a drums instrument is activated. diff --git a/doc/4-instrument/fm-opll.md b/doc/4-instrument/fm-opll.md new file mode 100644 index 000000000..87eac0253 --- /dev/null +++ b/doc/4-instrument/fm-opll.md @@ -0,0 +1,74 @@ +# OPLL FM synthesis instrument editor + +the OPLL FM editor is divided into 5 tabs: + +- **FM**: for controlling the basic parameters of FM sound source. +- **Macros (FM)**: for macros controlling algorithm, waveform and feedback. +- **Macros (OP1)**: for macros controlling FM parameters of operator 1. +- **Macros (OP2)**: for macros controlling FM parameters of operator 2. +- **Macros**: for other macros (volume/arp/pitch/patch). + +## FM + +the OPLL synthesizer is two-operator, meaning it takes two oscillators to produce a single sound. +however, unlike the other FM chips, only one custom patch may be set at a time, shared among all 9 channels. + +but don't worry! there also are 15 preset patches that you may select at any time. + +these apply to the instrument as a whole: +- **Feedback (FB)**: determines how many times operator 1 returns its output to itself (0 to 7). +- **Sustain (SUS)**: enables the sustain flag (sets the release rate to 5). +- **DC (half-sine carrier)**: sets the waveform produced by carrier operator to half-sine. +- **DM (half-sine modulator)**: sets the waveform produced by modulator operator to half-sine. +- **preset dropdown**: selects OPLL preset instrument. + - this is the selector for the preset patches I mentioned before. + - once a preset patch is selected, only the volume is configurable. + - only one user-specified patch may be applied at a time! + +if you select the special Drums patch, you may use the instrument in Drums mode of OPLL. an extra setting also appears: +- **Fixed frequency mode**: allows you to set a fixed frequency for the drum channels. + +these apply to each operator: +- the crossed-arrows button can be dragged to rearrange operators. +- **Amplitude Modulation (AM)**: makes the operator affected by LFO tremolo. +- **Envelope generator sustain flag (EGS)**: when enabled, value of Sustain Level is in effect. +- **Attack Rate (AR)**: determines the rising time for the sound. the bigger the value, the faster the attack (0 to 15). +- **Decay Rate (DR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. it's the initial amplitude decay rate (0 to 15). +- **Sustain Level (SL)**: determines the point at which the sound ceases to decay and changes to a sound having a constant level. the sustain level is expressed as a fraction of the maximum level (0 to 15). +- **Release Rate (RR)**: determines the rate at which the sound disappears after note off. the higher the value, the shorter the release (0 to 15). +- **Total Level (TL)**: represents the envelope’s highest amplitude, with 0 being the largest and 63 (decimal) the smallest. a change of one unit is about 0.75 dB. + - in the case of the second operator, it goes from 0 to 15 instead. +- **Key Scale Level (KSL)**: also known as "Level Scale". determines the degree to which the amplitude decreases according to the pitch. + +![FM ADSR chart](FM-ADSRchart.png) + +- **Envelope Scale (KSR)**: also known as "Key Scale". determines the degree to which the envelope execution speed increases according to the pitch. +- **Frequency Multiplier (MULT)**: sets the coarse pitch offset in relation to the note (0 to 15). 0 is -1 octave, 1 is 0 octaves, 2 is 1 octave, 3 is 1 octave 7 semitones, and so on. + - note that values 11, 13 and 14 behave as 10, 12 and 12 respectively. +- **Vibrato (VIB)**: makes the operator affected by LFO vibrato. + +## macros + +these macros allow you to control several parameters of FM per tick. + +## FM Macros + +all parameters are listed above. + +## OP1-OP4 Macros + +all parameters are listed above. + +## Macros + +- **Arpeggio**: pitch change sequence. +- **Patch**: changes the playing preset mid-note. + - through use of this macro, you may unlock different glitched sounds. useful for distortion guitars! +- **Pitch**: fine pitch. + - **Relative**: when enabled, pitch changes are relative to the current pitch. +- **Phase Reset**: restarts all operators and resets the waveform to its start. + + +## links + +[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. this was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fm-opm.md b/doc/4-instrument/fm-opm.md new file mode 100644 index 000000000..a5d12f4df --- /dev/null +++ b/doc/4-instrument/fm-opm.md @@ -0,0 +1,78 @@ +# FM (OPM) instrument editor + +the FM editor is divided into 7 tabs: + +- **FM**: for controlling the basic parameters of FM sound source. +- **Macros (FM)**: for macros controlling algorithm, feedback and LFO. +- **Macros (OP1)**: for macros controlling FM parameters of operator 1. +- **Macros (OP2)**: for macros controlling FM parameters of operator 2. +- **Macros (OP3)**: for macros controlling FM parameters of operator 3. +- **Macros (OP4)**: for macros controlling FM parameters of operator 4. +- **Macros**: for other macros (volume/arp/pitch/noise). + +## FM + +OPM is four-operator, meaning it takes four oscillators to produce a single sound. + +these apply to the instrument as a whole: +- **Feedback (FB)**: determines how many times operator 1 returns its output to itself (0 to 7). +- **Algorithm (ALG)**: determines how operators are connected to each other (0 to 7). + - left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. + - right-click to switch to a preview display of the waveform generated on a new note: + - left-click restarts the preview. + - middle-click pauses and unpauses the preview. + - right-click returns to algorithm view. + +- **LFO > Freq (FMS)**: determines how much will LFO have an effect in frequency (0 to 7). +- **LFO > Amp (AMS)**: determines how much will LFO have an effect in volume (0 to 3). + - only applies to operators which have AM turned on. + +these apply to each operator: +- the crossed-arrows button can be dragged to rearrange operators. +- the **OP1**, **OP2**, **OP3**, and **OP4** buttons enable or disable those operators. +- **Amplitude Modulation (AM)**: makes the operator volume affected by LFO. +- **Attack Rate (AR)**: determines the rising time for the sound. the bigger the value, the faster the attack (0 to 31). +- **Decay Rate (DR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. it's the initial amplitude decay rate (0 to 31). +- **Sustain Level (SL)**: determines the point at which the sound ceases to decay and changes to a sound having a constant level. the sustain level is expressed as a fraction of the maximum level (0 to 15). +- **Decay Rate 2 (D2R) / Sustain Rate (SR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. this is the long "tail" of the sound that continues as long as the key is depressed (0 to 31). +- **Release Rate (RR)**: determines the rate at which the sound disappears after note off. the higher the value, the shorter the release (0 to 15). +- **Total Level (TL)**: represents the envelope’s highest amplitude, with 0 being the largest and 127 (decimal) the smallest. a change of one unit is about 0.75 dB. + +![FM ADSR chart](FM-ADSRchart.png) + +- **Envelope Scale (RS/KS)**: also known as "Key Scale" or "Rate Scale". determines the degree to which the envelope execution speed increases according to the pitch (0 to 3). +- **Frequency Multiplier (MULT)**: sets the coarse pitch offset in relation to the note (0 to 15). 0 is -1 octave, 1 is 0 octaves, 2 is 1 octave, 3 is 1 octave 7 semitones, and so on. +- **Fine Detune (DT)**: shifts the pitch a little (0 to 7). +- **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3). + + +## macros + +these macros allow you to control several parameters of FM per tick. + +## FM Macros + +- **AM Depth**: amplitude modulation depth. +- **PM Depth**: pitch modulation depth. +- **LFO Speed**: LFO frequency. +- **LFO Shape**: LFO shape. choose between saw, square, triangle, and random. +- **OpMask**: toggles each operator. + +## OP1-OP4 Macros + +all parameters are listed above. + +## Macros + +- **Arpeggio**: pitch sequence. +- **Noise Frequency**: specifies the noise frequency. + - this only applies to operator 4 of channel 8! +- **Panning**: toggles output on left and right channels. +- **Pitch**: fine pitch. + - **Relative**: when enabled, pitch changes are relative to the current pitch. +- **Phase Reset**: restarts all operators and resets the waveform to its start. + + +## links + +[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. this was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fm-opn.md b/doc/4-instrument/fm-opn.md new file mode 100644 index 000000000..fd318ee3b --- /dev/null +++ b/doc/4-instrument/fm-opn.md @@ -0,0 +1,75 @@ +# FM (OPN) instrument editor + +the FM editor is divided into 7 tabs: + +- **FM**: for controlling the basic parameters of FM sound source. +- **Macros (FM)**: for macros controlling algorithm, feedback and LFO. +- **Macros (OP1)**: for macros controlling FM parameters of operator 1. +- **Macros (OP2)**: for macros controlling FM parameters of operator 2. +- **Macros (OP3)**: for macros controlling FM parameters of operator 3. +- **Macros (OP4)**: for macros controlling FM parameters of operator 4. +- **Macros**: for other macros (volume/arp/pitch). + +## FM + +OPN is four-operator, meaning it takes four oscillators to produce a single sound. + +these apply to the instrument as a whole: +- **Algorithm (ALG)**: determines how operators are connected to each other (0 to 7). + - left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. + - right-click to switch to a preview display of the waveform generated on a new note: + - left-click restarts the preview. + - middle-click pauses and unpauses the preview. + - right-click returns to algorithm view. +- **Feedback (FB)**: determines how many times operator 1 returns its output to itself (0 to 7). + +- **LFO > Freq (FMS)**: determines how much will LFO have an effect in frequency (0 to 7). +- **LFO > Amp (AMS)**: determines how much will LFO have an effect in volume (0 to 3). + - only applies to operators which have AM turned on. + - does not apply to YM2203. + +these apply to each operator: +- the crossed-arrows button can be dragged to rearrange operators. +- the **OP1**, **OP2**, **OP3**, and **OP4** buttons enable or disable those operators. +- **Amplitude Modulation (AM)**: makes the operator's volume affected by LFO. + - does not apply to YM2203. +- **Attack Rate (AR)**: determines the rising time for the sound. the bigger the value, the faster the attack (0 to 31). +- **Decay Rate (DR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. it's the initial amplitude decay rate (0 to 31). +- **Sustain Level (SL)**: determines the point at which the sound ceases to decay and changes to a sound having a constant level. the sustain level is expressed as a fraction of the maximum level (0 to 15). +- **Decay Rate 2 (D2R) / Sustain Rate (SR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. this is the long "tail" of the sound that continues as long as the key is depressed (0 to 31). +- **Release Rate (RR)**: determines the rate at which the sound disappears after note off. the higher the value, the shorter the release (0 to 15). +- **Total Level (TL)**: represents the envelope’s highest amplitude, with 0 being the largest and 127 (decimal) the smallest. a change of one unit is about 0.75 dB. +- **Hardware Envelope Generator (SSG-EG)**: executes the built-in envelope, inherited from AY-3-8910 PSG. speed of execution is controlled via Decay Rate. + +![FM ADSR chart](FM-ADSRchart.png) + +- **Envelope Scale (RS/KS)**: also known as "Key Scale" or "Rate Scale". determines the degree to which the envelope execution speed increases according to the pitch (0 to 3). +- **Frequency Multiplier (MULT)**: sets the coarse pitch offset in relation to the note (0 to 15). 0 is -1 octave, 1 is 0 octaves, 2 is 1 octave, 3 is 1 octave 7 semitones, and so on. +- **Fine Detune (DT)**: shifts the pitch a little (0 to 7). + + +## macros + +these macros allow you to control several parameters of FM per tick. + +## FM Macros + +- **LFO Speed**: LFO frequency. +- **OpMask**: toggles each operator. + +## OP1-OP4 Macros + +all parameters are listed above. + +## Macros + +- **Arpeggio**: pitch change sequence in semitones. +- **Panning**: toggles output on left and right channels. +- **Pitch**: fine pitch. + - **Relative**: when enabled, pitch changes are relative to the current pitch. +- **Phase Reset**: restarts all operators and resets the waveform to its start. + + +## links + +[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. this was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fm-opz.md b/doc/4-instrument/fm-opz.md new file mode 100644 index 000000000..d6a400e63 --- /dev/null +++ b/doc/4-instrument/fm-opz.md @@ -0,0 +1,102 @@ +# FM (OPZ) instrument editor + +the FM editor is divided into 7 tabs: + +- **FM**: for controlling the basic parameters of FM sound source. +- **Macros (FM)**: for macros controlling algorithm, feedback and LFO +- **Macros (OP1)**: for macros controlling FM parameters of operator 1 +- **Macros (OP2)**: for macros controlling FM parameters of operator 2 +- **Macros (OP3)**: for macros controlling FM parameters of operator 3 +- **Macros (OP4)**: for macros controlling FM parameters of operator 4 +- **Macros**: for other macros (volume/arp/pitch/noise). + +## FM + +OPZ is four-operator, meaning it takes four oscillators to produce a single sound. + +these apply to the instrument as a whole: +- **Algorithm (ALG)**: determines how operators are connected to each other (0 to 7). + - left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. + - right-click to switch to a preview display of the waveform generated on a new note: + - left-click restarts the preview. + - middle-click pauses and unpauses the preview. + - right-click returns to algorithm view. +- **Feedback (FB)**: determines how many times operator 1 returns its output to itself (0 to 7). + +- **LFO > Freq (FMS/PMS)**: determines how much will LFO have an effect in frequency (0 to 7). +- **LFO > Amp (AM)**: determines how much will LFO have an effect in volume (0 to 3). +- **LFO2 > Freq (FMS/PMS2)**: determines how much will the second LFO have an effect in frequency (0 to 7). +- **LFO2 > Amp (AMS2)**: determines how much will the second LFO have an effect in volume (0 to 3). + +- **Request from TX81Z**: if a Yamaha TX81Z is plugged in as MIDI input and output device, this sends a SysEx to the device in order to fetch its current voice. + +these apply to each operator: +- the crossed-arrows button can be dragged to rearrange operators. +- **Amplitude Modulation (AM)**: makes the operator's volume affected by LFO. +- **Attack Rate (AR)**: determines the rising time for the sound. the bigger the value, the faster the attack (0 to 31). +- **Decay Rate (DR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. it's the initial amplitude decay rate (0 to 31). +- **Sustain Level (SL)**: determines the point at which the sound ceases to decay and changes to a sound having a constant level. the sustain level is expressed as a fraction of the maximum level (0 to 15). +- **Decay Rate 2 (D2R) / Sustain Rate (SR)**: determines the diminishing time for the sound. the higher the value, the shorter the decay. this is the long "tail" of the sound that continues as long as the key is depressed (0 to 31). +- **Release Rate (RR)**: determines the rate at which the sound disappears after note off. the higher the value, the shorter the release (0 to 15). +- **Total Level (TL)**: represents the envelope’s highest amplitude, with 0 being the largest and 127 (decimal) the smallest. a change of one unit is about 0.75 dB. + +![FM ADSR chart](FM-ADSRchart.png) + +- **Envelope Scale (RS/KS)**: also known as "Rate Scale" or "Key Scale". determines the degree to which the envelope execution speed increases according to the pitch (0 to 3). +- **Frequency Multiplier (MULT)**: sets the coarse pitch offset in relation to the note (0 to 15). 0 is -1 octave, 1 is 0 octaves, 2 is 1 octave, 3 is 1 octave 7 semitones, and so on. +- **Fine Frequency Multiplier (Fine)**: a fine control for MULT. +- **Envelope Generator Shift (EGS)**: adds a "handicap" to the envelope. in other words, the minimum volume of the operator. + - 0: no change + - 1: -12dB + - 2: -24dB + - 3: -48dB + - 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). +- **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3). + +#### I am familiar with Yamaha TX81Z. where's LS and KVS? + +these are software effects. +- you may use TL effects to simulate LS. +- you may access a KVS-like feature by clicking on the algorithm preview. + +### fixed frequency mode + +each operator has a Fixed Frequency mode. once enabled, the operator runs at the specified frequency regardless of the note. + + +## macros + +these macros allow you to control several parameters of FM per tick. + +## FM Macros + +- **AM Depth**: amplitude modulation depth. +- **PM Depth**: pitch modulation depth. +- **LFO Speed**: LFO frequency. +- **LFO Shape**: LFO shape. choose between saw, square, triangle, and random. +- **AM Depth 2**: amplitude modulation depth (second LFO). +- **PM Depth 2**: pitch modulation depth (second LFO). +- **LFO2 Speed**: LFO 2 frequency. +- **LFO2 Shape**: LFO 2 shape. choose between saw, square, triangle, and random. + +## OP1-OP4 Macros + +most parameters are listed above. + +## Macros + +- **Arpeggio**: pitch change sequence in semitones. +- **Noise Frequency**: specifies the noise frequency. + - this only applies to operator 4 of channel 8! +- **Panning**: toggles output on left and right channels. +- **Pitch**: fine pitch. + - **Relative**: when enabled, pitch changes are relative to the current pitch. +- **Phase Reset**: restarts all operators and resets the waveform to its start. effectively the same as a `0Cxx` retrigger. + + +## links + +[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. this was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fm.md b/doc/4-instrument/fm.md deleted file mode 100644 index 72c0ba781..000000000 --- a/doc/4-instrument/fm.md +++ /dev/null @@ -1,77 +0,0 @@ -# FM synthesis instrument editor - -The FM editor is divided into 7 tabs: - -- **FM**: for controlling the basic parameters of FM sound source. -- **Macros (FM)**: for macros controlling algorithm, feedback and LFO -- **Macros (OP1)**: for macros controlling FM parameters of operator 1 -- **Macros (OP2)**: for macros controlling FM parameters of operator 2 -- **Macros (OP3)**: for macros controlling FM parameters of operator 3 -- **Macros (OP4)**: for macros controlling FM parameters of operator 4 -- **Macros**: for miscellaneous macros controlling volume, arpeggio, and YM2151 noise generator. - -## FM - -The FM synthesizers Furnace supports are four-operator, meaning it takes four oscillators to produce a single sound. - -These apply to the instrument as a whole: -- **Feedback (FB)**: Determines how many times operator 1 returns its output to itself. (0-7 range) -- **Algorithm (AL)**: Determines how operators are connected to each other. (0-7 range) - - Left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. - - Right-click to switch to a preview display of the waveform generated on a new note: - - Left-click restarts the preview. - - Middle-click pauses and unpauses the preview. - - Right-click returns to algorithm view. - -- **LFO Frequency Sensitivity**: Determines the amount of LFO frequency changes. (0-7 range) -- **LFO Amplitude Sensitivity (AM)**: Determines the amount of LFO amplitude changes. (0-3 range) - -These apply to each operator: -- The crossed-arrows button can be dragged to rearrange operators. -- The **OP1**, **OP2**, **OP3**, and **OP4** buttons enable or disable those operators. -- **Amplitude Modulation (AM)**: Makes the operator affected by LFO. -- **Hardware Envelope Generator (SSG-EG)**: Executes the built-in envelope, inherited from AY-3-8910 PSG. Speed of execution is controlled via Decay Rate. YM2610/YM2612 sound source only. -- **Attack Rate (AR)**: determines the rising time for the sound. The bigger the value, the faster the attack. (0-31 range) -- **Decay Rate (DR)**: Determines the diminishing time for the sound. The higher the value, the shorter the decay. It's the initial amplitude decay rate. (0-31 range) -- **Sustain Level (SL)**: Determines the point at which the sound ceases to decay and changes to a sound having a constant level. The sustain level is expressed as a fraction of the maximum level. (0-15 range) -- **Secondary Decay Rate (DR2) / Sustain Rate (SR)**: Determines the diminishing time for the sound. The higher the value, the shorter the decay. This is the long "tail" of the sound that continues as long as the key is depressed. (0-31 range) -- **Release Rate (RR)**: Determines the rate at which the sound disappears after KEY-OFF. The higher the value, the shorter the release. (0-15 range) -- **Total Level (TL)**: Represents the envelope’s highest amplitude, with 0 being the largest and 127 (decimal) the smallest. A change of one unit is about 0.75 dB. - -![FM ADSR chart](FM-ADSRchart.png) - -- **Envelope Scale (KSR)**: Also known as "Key Scale". Determines the degree to which the envelope execution speed increases according to the pitch. (0-3 range) -- **Frequency Multiplier (MULT)**: Determines the operator frequency in relation to the pitch. (0-15 range) -- **Fine Detune (DT)**: Shifts the pitch a little. (0-7 range) -- **Coarse Detune (DT2)**: Shifts the pitch by tens of cents. (0-3 range) YM2151 sound source only. - - -## macros - -Macros define the sequence of values passed to the given parameter. Via macro, along with the previously mentioned parameters, the following can be controlled: - -## FM Macros - -- **AM Depth**: amplitude modulation depth. YM2151 sound source only. -- **PM Depth**: pitch modulation depth. YM2151 sound source only. -- **LFO Speed**: LFO frequency. -- **LFO Shape**: LFO shape. Choose between saw, square, triangle, and random. -- **OpMask**: toggles each operator. - -## OP1-OP4 Macros - -All parameters are listed above. - -## Macros - -- **Arpeggio**: Pitch change sequence in semitones. -- **Noise Frequency**: specifies the noise frequency in noise mode of YM2151's Channel 8 Operator 4 special mode. -- **Panning**: toggles output on left and right channels. -- **Pitch**: fine pitch. - - **Relative**: pitch changes are relative to the current pitch, not the note's base pitch. -- **Phase Reset**: Restarts all operators and resets the waveform to its start. Effectively the same as a `0Cxx` retrigger. - - -# links - -[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. This was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fmopl.md b/doc/4-instrument/fmopl.md deleted file mode 100644 index da03ffc7c..000000000 --- a/doc/4-instrument/fmopl.md +++ /dev/null @@ -1,70 +0,0 @@ -# OPL FM synthesis instrument editor - -The OPL FM editor is divided into 7 tabs: - -- **FM**: for controlling the basic parameters of FM sound source. -- **Macros (FM)**: for macros controlling algorithm and feedback -- **Macros (OP1)**: for macros controlling FM parameters of operator 1 -- **Macros (OP2)**: for macros controlling FM parameters of operator 2 -- **Macros (OP3)**: for macros controlling FM parameters of operator 3 (Warning: only when 4-op flag is set, only on OPL3!) -- **Macros (OP4)**: for macros controlling FM parameters of operator 4 (Warning: only when 4-op flag is set, only on OPL3!) -- **Macros**: for miscellaneous macros controlling volume, arpeggio, and YMF262 panning. - -## FM - -The OPL synthesizers are nominally two-operator (OPL3 supports limited 4-operator mode), meaning it takes two oscillators to produce a single sound. - -These apply to the instrument as a whole: -- **Feedback (FB)**: Determines how many times operator 1 returns its output to itself. (0-7 range) -- **Algorithm (AL)**: Determines how operators are connected to each other. (0-1 range and OPL1 and OPL2, 0-3 range on OPL3 4op mode) - - Left-click pops up a small "operators changes with volume?" dialog where each operator can be toggled to scale with volume level. - - Right-click to switch to a preview display of the waveform generated on a new note: - - Left-click restarts the preview. - - Middle-click pauses and unpauses the preview. - - Right-click returns to algorithm view. - -- **4-op**: Enables 4-operator FM instrument editor mode (ONLY ON OPL3) -- **Drums**: Enables OPL drum mode editor - -These apply to each operator: -- The crossed-arrows button can be dragged to rearrange operators. -- The **OP1**, **OP2**, **OP3**, and **OP4** buttons enable or disable those operators. -- **Amplitude Modulation (AM)**: Makes the operator affected by LFO tremolo. -- **Sustain flag (SUS)**: When enabled, value of Sustain Level is in effect. -- **Attack Rate (AR)**: determines the rising time for the sound. The bigger the value, the faster the attack. (0-15 range) -- **Decay Rate (DR)**: Determines the diminishing time for the sound. The higher the value, the shorter the decay. It's the initial amplitude decay rate. (0-315 range) -- **Sustain Level (SL)**: Determines the point at which the sound ceases to decay and changes to a sound having a constant level. The sustain level is expressed as a fraction of the maximum level. (0-15 range) -- **Release Rate (RR)**: Determines the rate at which the sound disappears after KEY-OFF. The higher the value, the shorter the release. (0-15 range) -- **Total Level (TL)**: Represents the envelope’s highest amplitude, with 0 being the largest and 63 (decimal) the smallest. A change of one unit is about 0.75 dB. - -![FM ADSR chart](FM-ADSRchart.png) - -- **Envelope Scale (KSR)**: Also known as "Key Scale". Determines the degree to which the envelope execution speed increases according to the pitch. -- **Frequency Multiplier (MULT)**: Determines the operator frequency in relation to the pitch. (0-10, 12, 15 range) -- **Waveform select (WS)**: Changes the waveform generated by oscillator (OPL2 and OPL3 only, 0-7 range) -- **Pitch Modulation (VIB)**: Makes the operator affected by LFO vibrato. - -## macros - -Macros define the sequence of values passed to the given parameter. Via macro, along with the previously mentioned parameters, the following can be controlled: - -## FM Macros - -All parameters are listed above. - -## OP1-OP4 Macros - -All parameters are listed above. - -## Macros - -- **Arpeggio**: Pitch change sequence in semitones. -- **Panning**: toggles output on left and right channels. (OPL3 only!) -- **Pitch**: fine pitch. - - **Relative**: pitch changes are relative to the current pitch, not the note's base pitch. -- **Phase Reset**: Restarts all operators and resets the waveform to its start. Effectively the same as a `0Cxx` retrigger. - - -# links - -[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. This was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/fmopll.md b/doc/4-instrument/fmopll.md deleted file mode 100644 index 901ec45a2..000000000 --- a/doc/4-instrument/fmopll.md +++ /dev/null @@ -1,66 +0,0 @@ -# OPLL FM synthesis instrument editor - -The OPLL FM editor is divided into 5 tabs: - -- **FM**: for controlling the basic parameters of FM sound source. -- **Macros (FM)**: for macros controlling algorithm, waveform and feedback -- **Macros (OP1)**: for macros controlling FM parameters of operator 1 -- **Macros (OP2)**: for macros controlling FM parameters of operator 2 -- **Macros**: for miscellaneous macros controlling volume, arpeggio, and preset. - -## FM - -The OPLL synthesizer is two-operator, meaning it takes two oscillators to produce a single sound. - -These apply to the instrument as a whole: -- **Feedback (FB)**: Determines how many times operator 1 returns its output to itself. (0-7 range) -- **Sustain (SUS)**: enables the sustain flag (sets the release rate to 5) -- algorithm: shows the connection of operators (though they are always connected the same way). - - Right-click to switch to a preview display of the waveform generated on a new note: - - Left-click restarts the preview. - - Middle-click pauses and unpauses the preview. - - Right-click returns to algorithm view. -- **DC (half-sine carrier)**: Sets the waveform produced by carrier operator to half-sine -- **DM (half-sine modulator)**: Sets the waveform produced by modulator operator to half-sine -- preset dropdown: selects OPLL preset instrument. - -These apply to each operator: -- The crossed-arrows button can be dragged to rearrange operators. -- **Amplitude Modulation (AM)**: Makes the operator affected by LFO tremolo. -- **Envelope generator sustain flag (EGS)**: When enabled, value of Sustain Level is in effect. -- **Attack Rate (AR)**: determines the rising time for the sound. The bigger the value, the faster the attack. (0-15 range) -- **Decay Rate (DR)**: Determines the diminishing time for the sound. The higher the value, the shorter the decay. It's the initial amplitude decay rate. (0-15 range) -- **Sustain Level (SL)**: Determines the point at which the sound ceases to decay and changes to a sound having a constant level. The sustain level is expressed as a fraction of the maximum level. (0-15 range) -- **Release Rate (RR)**: Determines the rate at which the sound disappears after KEY-OFF. The higher the value, the shorter the release. (0-15 range) -- **Total Level (TL)**: Represents the envelope’s highest amplitude, with 0 being the largest and 63 (decimal) the smallest. A change of one unit is about 0.75 dB. - -![FM ADSR chart](FM-ADSRchart.png) - -- **Envelope Scale (KSR)**: Also known as "Key Scale". Determines the degree to which the envelope execution speed increases according to the pitch. -- **Frequency Multiplier (MULT)**: Determines the operator frequency in relation to the pitch. (0-10, 12, 15 range) -- **Pitch Modulation (VIB)**: Makes the operator affected by LFO vibrato. - -## macros - -Macros define the sequence of values passed to the given parameter. Via macro, along with the previously mentioned parameters, the following can be controlled: - -## FM Macros - -All parameters are listed above. - -## OP1-OP4 Macros - -All parameters are listed above. - -## Macros - -- **Arpeggio**: Pitch change sequence in semitones. -- **Patch**: changes the playing preset mid-note -- **Pitch**: fine pitch. - - **Relative**: pitch changes are relative to the current pitch, not the note's base pitch. -- **Phase Reset**: Restarts all operators and resets the waveform to its start. Effectively the same as a `0Cxx` retrigger. - - -# links - -[FM instrument tutorial](https://www.youtube.com/watch?v=wS8edjurjDw): A great starting point to learn how create and work with FM sounds. This was made for DefleMask, but all the same principles apply. diff --git a/doc/4-instrument/ga20.md b/doc/4-instrument/ga20.md new file mode 100644 index 000000000..4affe54f9 --- /dev/null +++ b/doc/4-instrument/ga20.md @@ -0,0 +1,14 @@ +# Irem GA20 instrument editor + +the GA20 instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/game-boy.md b/doc/4-instrument/game-boy.md index fd982615d..50b30b5b1 100644 --- a/doc/4-instrument/game-boy.md +++ b/doc/4-instrument/game-boy.md @@ -1,25 +1,58 @@ # Game Boy instrument editor -GB instrument editor consists of two tabs: one controlling envelope of sound channels and macro tab containing several macros. +the Game Boy instrument editor consists of three tabs: one controlling envelope of sound channels, another for the wave synth and macro tab containing several macros. ## Game Boy -- **Use software envelope**: switch to volume macro instead of envelope -- **Initialize envelope on every note**: forces a volume reset on each new note -- **Volume**: initial channel volume (range 0-15) -- **Length**: envelope decay/attack duration (range 0-7) -- **Sound Length**: cuts off sound after specified length, overriding the Length value +- **Use software envelope**: switch to volume macro instead of envelope. + - this exploits a bug in the Game Boy sound hardware in order to have software envelopes ("zombie mode"). + - only a couple emulators have accurate reproduction of this bug. +- **Initialize envelope on every note**: forces a volume reset on each new note. +- **Volume**: initial channel volume (0 to 15). +- **Length**: envelope decay/attack duration (0 to 7) +- **Sound Length**: cuts off channel after specified length, overriding the Length value. -- **Up and Down radio buttons**: Up makes the envelope an attack, down makes it decay. _Note:_ For envelope attack to have any effect, start at a lower volume! +- **Direction**: up makes the envelope an attack. down makes it decay. + - note: for attack to have effect, start at a lower volume. -- **Hardware Sequence**: (document this) +- **Hardware Sequence**: this allows you to define a sequence of hardware envelope changes for creating complex envelopes. see the next section for more information. + +### hardware sequence + +Furnace provides a sequencer for the hardware envelope. this way you can define timed envelope changes which may be used for simulating ADSR, adding simple release, and other things. + +the sequence consists of a list of "commands". + +the `+` button adds a new command, which may be one of the following: + +- **Envelope**: sets envelope values and retriggers note. it is highly recommended to have this as the first command. +- **Sweep**: sets sweep parameters. only works on the first channel. +- **Wait**: waits a specific number of ticks. +- **Wait for Release**: waits until the note is released with `===` or `REL`. +- **Loop**: goes to a previous position in the sequence. +- **Loop until Release**: same as Loop, but doesn't have effect after releasing the note. + +each command in the sequence is represented in three columns: + +- **Tick**: the tick this command will execute, followed by position in the sequence. +- **Command**: the command and its parameters. +- **Move/Remove**: allows you to move the command, or remove it. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +notes: +- only for Wave channel. +- on Game Boy, using the wave synth may result in clicking and/or phase resets. by default Furnace attempts to mitigate this problem though, but some clicking may still be audible. ## Macros -- **Volume**: volume sequence. _Note:_ This only appears if "Use software envelope" is checked. -- **Arpeggio**: pitch in half-steps -- **Duty/Noise**: pulse wave duty cycle or noise mode sequence -- **Waveform**: ch3 wavetable sequence -- **Panning**: output for left and right channels -- **Pitch**: fine pitch -- **Phase Reset**: trigger restart of waveform +- **Volume**: volume sequence. + - note: this only appears if "Use software envelope" is checked. +- **Arpeggio**: pitch sequence. +- **Duty/Noise**: pulse wave duty cycle or noise mode sequence. +- **Waveform**: channel 3 wavetable sequence. +- **Panning**: output for left and right channels. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/instrument-editor-top.png b/doc/4-instrument/instrument-editor-top.png index 138a117fe..5aa3f7289 100644 Binary files a/doc/4-instrument/instrument-editor-top.png and b/doc/4-instrument/instrument-editor-top.png differ diff --git a/doc/4-instrument/instrument-wavetable.png b/doc/4-instrument/instrument-wavetable.png new file mode 100644 index 000000000..8be2d9e8a Binary files /dev/null and b/doc/4-instrument/instrument-wavetable.png differ diff --git a/doc/4-instrument/k007232.md b/doc/4-instrument/k007232.md new file mode 100644 index 000000000..a260abeff --- /dev/null +++ b/doc/4-instrument/k007232.md @@ -0,0 +1,16 @@ +# Konami K007232 instrument editor + +the K007232 instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/k053260.md b/doc/4-instrument/k053260.md new file mode 100644 index 000000000..0cfb62084 --- /dev/null +++ b/doc/4-instrument/k053260.md @@ -0,0 +1,15 @@ +# K053260 instrument editor + +the K053260 instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning**: stereo panning sequence. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/lynx.md b/doc/4-instrument/lynx.md index 43dc1734d..e4bb3bc78 100644 --- a/doc/4-instrument/lynx.md +++ b/doc/4-instrument/lynx.md @@ -1,28 +1,38 @@ # Atari Lynx instrument editor -Atari Lynx instrument editor consists of these macros: +Atari Lynx instrument editor consists of two tabs: Sample and Macros. -- **Volume**: volume sequence -- **Arpeggio**: pitch in half-steps -- **Duty/Int**: bit pattern for LFSR taps and integration -- **Panning (left)**: output level for left channel -- **Panning (right)**: output level for right channel -- **Pitch**: fine pitch -- **Phase Reset**: trigger restart of waveform +## Sample -## Audio generation description +for sample settings, see [the Sample instrument editor](sample.md). -Atari Lynx generates sound using a 12-bit linear feedback shift register with configurable tap. Nine separate bits can be enabled to be the source of feedback: 0, 1, 2, 3, 4, 5, 7, 10 and 11. To generate _any_ sound at least one bit _must_ be enabled. +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. -### Square wave +note that using samples on Lynx is CPU expensive! -The LFSR is shifted at the rate define by sound pitch and generates square wave by setting channel output value to +volume or -volume, depending on the bit shifted in. +## Macros -### Triangle wave +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty/Int**: bit pattern for LFSR taps and integration. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform/LFSR reset. -Alternatively when "int" bit is set sound wave is generated by adding or subtracting volume from output effectively producing triangle wave. +## audio generation description -#### How triangle wave works? +Atari Lynx generates sound using a 12-bit linear feedback shift register with configurable tap. nine separate bits can be enabled to be the source of feedback: 0, 1, 2, 3, 4, 5, 7, 10 and 11. to generate _any_ sound at least one bit _must_ be enabled. -Hint: To obtain triangle set bits "int" and "11" in "Duty/Int" sequence and set volume to about 22. -By enabling 11th tap bit the value shifted in is negated after 11 bit is shifted in hence the volume is added for 11 cycles and then subtracted for 11 cycles. +### square wave + +the LFSR is shifted at the rate define by sound pitch and generates square wave by setting channel output value to +volume or -volume, depending on the bit shifted in. + +### triangle wave + +alternatively when "int" bit is set sound wave is generated by adding or subtracting volume from output effectively producing triangle wave. + +#### how triangle wave works? + +hint: to obtain triangle set bits "int" and "11" in "Duty/Int" sequence and set volume to about 22. +by enabling 11th tap bit the value shifted in is negated after 11 bit is shifted in hence the volume is added for 11 cycles and then subtracted for 11 cycles. diff --git a/doc/4-instrument/macro-button-ADSR.png b/doc/4-instrument/macro-button-ADSR.png index 6529a72ca..f76ed6585 100644 Binary files a/doc/4-instrument/macro-button-ADSR.png and b/doc/4-instrument/macro-button-ADSR.png differ diff --git a/doc/4-instrument/macro-button-LFO.png b/doc/4-instrument/macro-button-LFO.png index 8ad9c24b3..93da266cd 100644 Binary files a/doc/4-instrument/macro-button-LFO.png and b/doc/4-instrument/macro-button-LFO.png differ diff --git a/doc/4-instrument/macro-button-seq.png b/doc/4-instrument/macro-button-seq.png index dd316c205..933a5476f 100644 Binary files a/doc/4-instrument/macro-button-seq.png and b/doc/4-instrument/macro-button-seq.png differ diff --git a/doc/4-instrument/msm5232.md b/doc/4-instrument/msm5232.md new file mode 100644 index 000000000..31c10320e --- /dev/null +++ b/doc/4-instrument/msm5232.md @@ -0,0 +1,16 @@ +# MSM5232 instrument editor + +the instrument editor for MSM5232 consists of these macros: + +- **Volume**: volume sequence. + - only has effect when the envelope mode of a group is set to External. +- **Arpeggio**: pitch sequence. +- **Group Ctrl**: group control sequence: + - **sustain**: enable sustain mode. + - **2'**: enable 2' overtone. + - **4'**: enable 4' overtone. + - **8'**: enable 8' overtone. + - **16'**: enable 16' overtone. +- **Group Attack**: set attack rate of group. +- **Group Decay**: set decay rate of group. +- **Noise**: toggle noise mode. diff --git a/doc/4-instrument/msm6258.md b/doc/4-instrument/msm6258.md new file mode 100644 index 000000000..695ad467f --- /dev/null +++ b/doc/4-instrument/msm6258.md @@ -0,0 +1,19 @@ +# MSM6258 instrument editor + +the MSM6258 instrument editor contains two tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +note that samples on MSM6258 are tied to one frequency. + +## Macros + +- **Frequency Divider**: selects the frequency divider for the output. + - `0`: divide by 512. + - `1`: divide by 768. + - `2`: divide by 1024. +- **Panning**: toggle left/right output. +- **Phase Reset**: trigger restart of sample. +- **Clock Divider**: clock divider sequence. when it is 1, the clock is divided by half. diff --git a/doc/4-instrument/msm6295.md b/doc/4-instrument/msm6295.md new file mode 100644 index 000000000..8b01b94dd --- /dev/null +++ b/doc/4-instrument/msm6295.md @@ -0,0 +1,17 @@ +# MSM6295 instrument editor + +the MSM6295 instrument editor contains two tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +note that samples on MSM6295 are tied to one frequency. + +## Macros + +- **Volume**: volume sequence. +- **Frequency Divider**: selects the frequency divider for the output. + - `0`: divide by 132. + - `1`: divide by 165. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/n163.md b/doc/4-instrument/n163.md index b12bfe354..f07de82a1 100644 --- a/doc/4-instrument/n163.md +++ b/doc/4-instrument/n163.md @@ -1,6 +1,6 @@ # Namco 163 instrument editor -The Namco 163 instrument editor consists of two tabs: "Namco 163" for control of various waveform parameters, and "Macro" containing several macros. +the Namco 163 instrument editor consists of three tabs: "Namco 163" for control of various waveform parameters, "Wavetable" for control of the wave synth and "Macro" containing several macros. ## Namco 163 @@ -12,15 +12,20 @@ The Namco 163 instrument editor consists of two tabs: "Namco 163" for control of - **Position**: determines the waveform position in RAM. - **Length**: determines the waveform length in RAM. +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +note that setting the Update Rate to something greater than 1 and playing the instrument in two channels may result in conflicts. + ## Macros -- **Volume**: volume levels sequence -- **Arpeggio**: pitch sequence -- **Wave Pos**: sets waveform seek position in RAM -- **Waveform**: sets waveform source for playback immediately or update later -- **Panning**: output for left and right channels -- **Pitch**: fine pitch -- **Wave Length**: sets waveform length +- **Volume**: volume levels sequence. +- **Arpeggio**: pitch sequence. +- **Wave Pos**: sets waveform seek position in RAM. +- **Waveform**: sets waveform. +- **Pitch**: fine pitch. +- **Wave Length**: sets waveform length. diff --git a/doc/4-instrument/nes.md b/doc/4-instrument/nes.md index d8df859af..53c8560f6 100644 --- a/doc/4-instrument/nes.md +++ b/doc/4-instrument/nes.md @@ -1,18 +1,17 @@ -# Standard instrument editor +# NES instrument editor -The instrument editor for NES consists of these macros: +the instrument editor for NES consists of these macros: -- **Volume**: volume. -- **Arpeggio**: pitch in half-steps. -- **Duty**: duty cycle and noise mode. +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty/Noise**: duty cycle and noise mode. - pulse duty cycles: - `0`: 12.5% - `1`: 25% - `2`: 50% - `3`: 75% - noise modes: - - `0`: long noise. - - `1`: short noise. -- **Panning**: output for left and right channels. + - `0`: long noise + - `1`: short noise - **Pitch**: fine pitch. -- **Phase Reset**: trigger restart of waveform. \ No newline at end of file +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/pce.md b/doc/4-instrument/pce.md index 72c87470b..658988840 100644 --- a/doc/4-instrument/pce.md +++ b/doc/4-instrument/pce.md @@ -1,14 +1,27 @@ # NEC PC Engine instrument editor -The PCE instrument editor consists of these macros: +the PCE instrument editor contains three tabs: Sample, Wavetable and Macros. -- **Volume**: volume sequence -- **Arpeggio**: pitch in half-steps -- **Noise**: enable noise mode (ch5 and ch6 only) -- **Waveform**: wavetable sequence -- **Panning (left)**: output level for left channel -- **Panning (right)**: output level for right channel -- **Pitch**: fine pitch -- **Phase Reset**: trigger restart of waveform +## Sample -It also has wavetable synthesizer support, but unfortunately, it clicks a lot when in use on the HuC6280. +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +note: on PC Engine, using the wave synth may result in clicking and/or phase resets. by default Furnace attempts to mitigate this problem though. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise**: enable noise mode. + - only on channels 5 and 6. +- **Waveform**: wavetable sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/pet.md b/doc/4-instrument/pet.md new file mode 100644 index 000000000..a8ab1e8f3 --- /dev/null +++ b/doc/4-instrument/pet.md @@ -0,0 +1,8 @@ +# Commodore PET instrument editor + +the PET instrument editor consists of these macros: + +- **Volume**: volume sequence (on/off). +- **Arpeggio**: pitch sequence. +- **Waveform**: an 8×1 waveform. +- **Pitch**: fine pitch sequence. diff --git a/doc/4-instrument/pokemini.md b/doc/4-instrument/pokemini.md new file mode 100644 index 000000000..ceec01a1c --- /dev/null +++ b/doc/4-instrument/pokemini.md @@ -0,0 +1,8 @@ +# Pokémon Mini/QuadTone instrument editor + +used in these two chips/systems. these macros are available: + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Pulse Width**: pulse width sequence. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/pokey.md b/doc/4-instrument/pokey.md new file mode 100644 index 000000000..8b3ac7fc4 --- /dev/null +++ b/doc/4-instrument/pokey.md @@ -0,0 +1,25 @@ +# Atari POKEY instrument editor + +the instrument editor for POKEY consists of these macros: + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **AUDCTL**: audio control register sequence: + - **poly9**: reduces size of LFSR. only on noise waveforms! + - **high1**: runs channel 1 at 1.79MHz. + - **high3**: runs channel 3 at 1.79MHz. + - **16-bit 1+2**: enables 16-bit frequency mode by combining channels 1 and 2. + - **16-bit 3+4**: enables 16-bit frequency mode by combining channels 3 and 4. + - **filter 1+3**: applies a high-pass "filter" by combining channels 1 and 3. + - **filter 2+4**: applies a high-pass "filter" by combining channels 2 and 4. + - **15KHz**: runs channels at 15KHz. +- **Waveform**: wave selection sequence: + - 0: harsh noise (poly5+17) + - 1: square buzz (poly5) + - 2: weird noise (poly4+5) + - 3: square buzz (poly5) + - 4: soft noise (poly17) + - 5: square + - 6: bass (poly4) + - 7: buzz (poly4) +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/psg.md b/doc/4-instrument/psg.md index 15bb8ff8b..6b09e534f 100644 --- a/doc/4-instrument/psg.md +++ b/doc/4-instrument/psg.md @@ -1,14 +1,15 @@ # Sega PSG instrument editor -The instrument editor for Sega PSG (SMS, and other TI SN76489 derivatives) consists of these macros: +the instrument editor for Sega PSG (SMS, and other TI SN76489 derivatives) consists of these macros: -- **Volume**: volume. -- **Arpeggio**: pitch in half-steps. +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. - **Duty**: noise mode. - - `0`: short noise, preset frequencies. - - `1`: long noise, preset frequencies. - - `2`: short noise, use channel 3 for frequency. - - `3`: long noise, use channel 3 for frequency. + - `0`: short noise; preset frequencies. + - `1`: long noise; preset frequencies. + - `2`: short noise; use channel 3 for frequency. + - `3`: long noise; use channel 3 for frequency. - **Panning**: output for left and right channels. + - only on Game Gear! - **Pitch**: fine pitch. - **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/pv1000.md b/doc/4-instrument/pv1000.md index 5d6a88534..b3aa474e6 100644 --- a/doc/4-instrument/pv1000.md +++ b/doc/4-instrument/pv1000.md @@ -1,7 +1,7 @@ # PV-1000 instrument editor -The instrument editor for the Casio PV-1000 consists of these macros: +the instrument editor for the Casio PV-1000 consists of these macros: -- **Volume**: volume -- **Arpeggio**: pitch in half-steps -- **Pitch**: fine pitch +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/qsound.md b/doc/4-instrument/qsound.md new file mode 100644 index 000000000..3e2f54ed5 --- /dev/null +++ b/doc/4-instrument/qsound.md @@ -0,0 +1,21 @@ +# Capcom QSound instrument editor + +the QSound instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Echo Level**: echo wet volume sequence. +- **Panning**: stereo panning sequence. +- **Surround**: toggles whether QSound algorithm is enabled. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. +- **Echo Feedback**: echo feedback sequence. + - note: global! +- **Echo Length**: echo length sequence. + - note: global! diff --git a/doc/4-instrument/rf5c68.md b/doc/4-instrument/rf5c68.md new file mode 100644 index 000000000..6df2bac80 --- /dev/null +++ b/doc/4-instrument/rf5c68.md @@ -0,0 +1,16 @@ +# Ricoh RF5C68 instrument editor + +the RF5C68 instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/saa.md b/doc/4-instrument/saa.md index f005261b4..79e2b3a7f 100644 --- a/doc/4-instrument/saa.md +++ b/doc/4-instrument/saa.md @@ -1,20 +1,25 @@ # Philips SAA1099 instrument editor -The SAA1099 instrument editor consists of these macros: +the SAA1099 instrument editor consists of these macros: -- **Volume**: volume sequence -- **Arpeggio**: pitch sequence -- **Duty/Noise**: noise generator frequency -- **Waveform**: selector between tone and noise -- **Panning (left)**: output level for left channel -- **Panning (right)**: output level for right channel -- **Pitch**: fine pitch +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty/Noise**: noise generator frequency. the following values are available: + - `0`: high + - `1`: mid + - `2`: low + - `3`: use frequency of channel 1 or 4 (depending on where the instrument plays). +- **Waveform**: selector between tone and noise. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. - **Envelope**: envelope generator settings: - enable: enables the envelope generator - N/A: has no effect - fixed: toggles whether to use a fixed frequency or lock to the frequency of channel 2 or 5 - resolution: increases the envelope generator pitch resolution - direction: inverts the waveform around Y axis - cut: cuts the waveform (producing saw wave out of tri wave) - loop: toggles wheteher evelope is one-off or constantly looping - mirror: sets whether the right output will mirror the left one + - **enable**: enables the envelope generator. + - **N/A**: has no effect. + - **fixed**: toggles whether to use a fixed, slow frequency or lock to the frequency of channel 2 or 5 (depending on where the instrument plays). + - **resolution**: increases the envelope generator pitch resolution. + - **direction**: inverts the envelope. + - **cut**: cuts the envelope (producing saw wave out of tri wave) + - **loop**: toggles whether envelope is one-shot or constantly looping. + - **mirror**: sets whether the right output will mirror the left one. + - the envelope only has effect in channels 3 and 6. diff --git a/doc/4-instrument/sample-map.png b/doc/4-instrument/sample-map.png index fb1f9b51e..03e12c2cf 100644 Binary files a/doc/4-instrument/sample-map.png and b/doc/4-instrument/sample-map.png differ diff --git a/doc/4-instrument/sample.md b/doc/4-instrument/sample.md new file mode 100644 index 000000000..8c3f7545e --- /dev/null +++ b/doc/4-instrument/sample.md @@ -0,0 +1,38 @@ +# Amiga/PCM sound source instrument editor + +the Generic Sample instrument editor consists of a sample selector and several macros: + +## Sample + +- **Initial sample**: specifies which sample should be assigned to the instrument. +- **Use wavetable**: uses wavetable instead of a sample. + - only available in Amiga and Generic PCM DAC. +- **Use sample map**: enables mapping different samples to notes. see next section for more information. + +### sample map + +the sample map allows you to set a sample for each note. this can be used to create more realistic instruments, split key instruments, drum kits and more. + +after enabling this option, a table appears with the contents of the sample map. +- the first column represents the input note. +- the second column allows you to type in a sample number for each note. + - you may press Delete to clear it. +- the third one is used to set the note at which the specified sample will play. +- the fourth and last column provides a combo box for selecting a sample. + +you may right-click anywhere in the number and note columns for additional options: +- **set entire map to this note**: sets the note number of all notes to the selected cell's. +- **set entire map to this sample**: sets the sample number of all notes to the selected cell's. +- **reset notes**: resets the sample map's notes to defaults (a chromatic scale). +- **clear map samples**: removes all samples from the map. + +## Macros + +- **Volume**: volume sequence. does not apply to some chips. +- **Arpeggio**: pitch sequence. +- **Waveform**: waveform sequence. + - only appears when "Use wavetable" is enabled. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/scc.md b/doc/4-instrument/scc.md index 29139fe7c..ca26f2c69 100644 --- a/doc/4-instrument/scc.md +++ b/doc/4-instrument/scc.md @@ -1,8 +1,16 @@ # Konami SCC/Bubble System WSG instrument editor -The SCC/Bubble System WSG instrument editor consists of these macros: +the SCC/Bubble System WSG instrument editor consists of two tabs. -- **Volume**: volume sequence -- **Arpeggio**: pitch sequence -- **Waveform**: specifies wavetable sequence -- **Pitch**: fine pitch +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +be noted that channel 4 and 5 share the same waveform on SCC (non-plus). careful. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Waveform**: specifies wavetable. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/segapcm.md b/doc/4-instrument/segapcm.md new file mode 100644 index 000000000..e02653138 --- /dev/null +++ b/doc/4-instrument/segapcm.md @@ -0,0 +1,16 @@ +# SegaPCM instrument editor + +the SegaPCM instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/4-instrument/sm8521.md b/doc/4-instrument/sm8521.md new file mode 100644 index 000000000..93f925709 --- /dev/null +++ b/doc/4-instrument/sm8521.md @@ -0,0 +1,14 @@ +# SM8521 instrument editor + +the SM8521 instrument editor contains two tabs: Wavetable and Macros. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Waveform**: wavetable sequence. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/snes.md b/doc/4-instrument/snes.md index ddc7204fe..0df51be56 100644 --- a/doc/4-instrument/snes.md +++ b/doc/4-instrument/snes.md @@ -1,42 +1,51 @@ # SNES instrument editor -these tabs are unique to the editor for SNES instruments. +these four tabs are unique to the editor for SNES instruments. +## Sample +for sample settings, see [the Sample instrument editor](sample.md). -# SNES +## SNES -**Use envelope** enables the ADSR volume envelope. if it's on: +**Use envelope** enables the ADSR volume envelope. if it is on: - **A**: attack rate. - **D**: decay rate. - **S**: sustain level. - **D2**: decay rate during sustain. + - only appears when Sustain/release mode is Effective or Delayed. - **R**: release rate. - **Sustain/release mode**: - **Direct**: note release acts as note cut. - **Effective (linear decrease)**: after release, volume lowers by subtractions of 1/64 steps. - **Effective (exponential decrease)**: after release, volume decays exponentially. see [gain chart](../7-systems/snes.md). - - **Delayed (write R on release)**: after release, waits until A and D have completed before starting exponential decrease. + - **Delayed (write R on release)**: after release, waits until A and D have completed before starting release. if envelope is off: - **Gain Mode**: selects gain mode. - - **Direct**: direct gain from 0 to 127 - - **Decrease (linear)**: linear gain from -0 to -31 - - **Decrease (logarithmic)**: exponential gain from -0 to -31 - - **Increase (linear)**: linear gain from +0 to +31 - - **Increase (bent line)**: exponential gain from +0 to +31 - - _note:_ using decrease modes will not produce any sound unless a Gain macro is set. The first tick must be the initial gain, and the second tick must be the decrease gain value. gain values are as described in the Macros section below. + - **Direct**: direct gain from 0 to 127. + - **Decrease (linear)**: linear gain from -0 to -31. + - **Decrease (logarithmic)**: exponential gain from -0 to -31. + - note: using decrease modes will not produce any sound unless a Gain macro is set. the first tick must be the initial gain, and the second tick must be the decrease gain value. gain values are as described in the Macros section below. + - **Increase (linear)**: linear gain from +0 to +31. + - **Increase (bent line)**: inverse exponential gain from +0 to +31. - **Gain**: value of gain. +## Wavetable +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. -# Macros +only active when Use wavetable is enabled in the Sample tab. -- **Volume**: volume. -- **Arpeggio**: pitch in half-steps. -- **Noise Freq**: preset frequency of noise generator. +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise Freq**: frequency of noise generator. + - note: global! - **Waveform**: waveform. + - only effective when Use wavetable is enabled. - **Panning (left)**: output level of left channel. - **Panning (right)**: output level of right channel. - **Pitch**: fine pitch. @@ -47,8 +56,8 @@ if envelope is off: - echo: enables echo. - noise: enables noise generator. - **Gain**: sets mode and value of gain. - - 0 - 127: direct gain from 0 to 127 - - 128 - 159: linear gain from -0 to -31 - - 160 - 191: exponential gain from -0 to -31 - - 192 - 223: linear gain from +0 to +31 - - 224 - 255: exponential gain from +0 to +31 + - 0 to 127: direct gain from 0 to 127. + - 128 to 159: linear gain from -0 to -31 (decrease linear). + - 160 to 191: exponential gain from -0 to -31 (decrease exponential). + - 192 to 223: linear gain from +0 to +31 (increase linear). + - 224 to 255: exponential gain from +0 to +31 (increase bent line). diff --git a/doc/4-instrument/su.md b/doc/4-instrument/su.md new file mode 100644 index 000000000..b646edc14 --- /dev/null +++ b/doc/4-instrument/su.md @@ -0,0 +1,42 @@ +# tildearrow Sound Unit instrument editor + +this instrument editor has two tabs. + +## Sound Unit + +for sample settings, see [the Sample instrument editor](sample.md). + +the differences are: +- the lack of an "Use wavetable" option +- the presence of a "Use sample" one +- the presence of a "**Switch roles of frequency and phase reset timer**" option. when enabled, this writes frequency to the phase reset timer register rather than the frequency register + - this may be used to create sync-like effects. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty/Noise**: waveform duty cycle sequence. +- **Waveform**: select waveform. + - `0`: pulse wave + - `1`: sawtooth + - `2`: sine wave + - `3`: triangle wave + - `4`: noise + - `5`: periodic noise + - `6`: XOR sine + - `7`: XOR triangle +- **Panning**: stereo panning sequence. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. +- **Cutoff**: set filter cutoff. +- **Resonance**: set filter resonance. + - values that are too high may distort the output! +- **Control**: filter parameter/ring mod sequence. + - **band pass**: a band-pass filter. cutoff determines which part of the sound is heard (from bass to treble). + - **high pass**: a high-pass filter. higher cutoff values result in a less "bassy" sound. + - **low pass**: a low-pass filter. the lower the cutoff, the darker the sound. + - **ring mod**: enable ring modulation with previous channel. + - note: square wave goes from 0 to volume, so in that case it acts more like amplitude modulation. +- **Phase Reset Timer**: sets the phase reset timer. + - if the "Switch roles of frequency and phase reset timer" option in the Sound Unit tab is enabled, this macro controls the frequency register instead. diff --git a/doc/4-instrument/t6w28.md b/doc/4-instrument/t6w28.md new file mode 100644 index 000000000..8343733bd --- /dev/null +++ b/doc/4-instrument/t6w28.md @@ -0,0 +1,13 @@ +# T6W28 instrument editor + +the instrument editor for T6W28 consists of these macros: + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise Type**: noise type sequence: + - `0`: short noise + - `1`: long noise +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/ted.md b/doc/4-instrument/ted.md index 47a5f6d6f..b57ac1038 100644 --- a/doc/4-instrument/ted.md +++ b/doc/4-instrument/ted.md @@ -2,10 +2,12 @@ TED instrument editor consists of these macros: -- **Volume**: volume sequence. **global!** -- **Arpeggio**: pitch sequence -- **Square/Noise**: select whether square, noise or nothing will be output +- **Volume**: volume sequence. + - note: global! affects entire chip. +- **Arpeggio**: pitch sequence. +- **Square/Noise**: select whether square, noise or nothing will be output. - noise only available on channel 2 - if square and noise are enabled, square takes precedence. -- **Pitch**: "fine" pitch -- **Phase Reset**: trigger restart of waveform. **global!** +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. + - note: global! triggers both channels... diff --git a/doc/4-instrument/tia.md b/doc/4-instrument/tia.md index 704d3aa21..a08ec0a3a 100644 --- a/doc/4-instrument/tia.md +++ b/doc/4-instrument/tia.md @@ -1,8 +1,25 @@ # Atari TIA instrument editor -The TIA instrument editor consists of these macros: +the TIA instrument editor consists of these macros: -- **Volume**: volume sequence -- **Arpeggio**: pitch sequencr -- **Waveform**: 1-bit polynomial pattern type sequence -- **Pitch**: "fine" pitch +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. + - note: fixed mode works differently. it sets the frequency directly rather than the note, so it only goes from 0 to 31. +- **Waveform**: selects waveform to be used: + - `0`: nothing + - `1`: buzzy + - `2`: low buzzy + - `3`: flangy + - `4`: square + - `5`: square + - `6`: pure buzzy + - `7`: reedy + - `8`: noise + - `9`: reedy + - `A`: pure buzzy + - `B`: nothing + - `C`: low square + - `D`: low square + - `E`: low pure buzzy + - `F`: low reedy +- **Pitch**: "fine" pitch. fine in quotes as TIA doesn't have true pitch control at all. diff --git a/doc/4-instrument/vera.md b/doc/4-instrument/vera.md index ec76f6598..e5443beef 100644 --- a/doc/4-instrument/vera.md +++ b/doc/4-instrument/vera.md @@ -2,9 +2,9 @@ VERA instrument editor consists of these macros: -- **Volume**: volume sequence -- **Arpeggio**: pitch sequence -- **Duty**: pulse duty cycle sequence -- **Waveform**: select the waveform used by instrument -- **Panning**: output for left and right channels -- **Pitch**: fine pitch +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty**: pulse duty cycle sequence. +- **Waveform**: select the waveform used by instrument. +- **Panning**: toggles left/right output. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/vic.md b/doc/4-instrument/vic.md new file mode 100644 index 000000000..40d31603a --- /dev/null +++ b/doc/4-instrument/vic.md @@ -0,0 +1,10 @@ +# Commodore VIC instrument editor + +the VIC instrument editor consists of these macros: + +- **Volume**: volume sequence. + - note: global! affects entire chip. +- **Arpeggio**: pitch sequence. +- **On/Off**: enable/disable channel output. +- **Waveform**: square wave distortion type sequence. +- **Pitch**: "fine" pitch. diff --git a/doc/4-instrument/virtual-boy.md b/doc/4-instrument/virtual-boy.md new file mode 100644 index 000000000..c36e2a0f6 --- /dev/null +++ b/doc/4-instrument/virtual-boy.md @@ -0,0 +1,23 @@ +# Virtual Boy instrument editor + +the Virtual Boy instrument editor contains three tabs: Virtual Boy, Wavetable and Macros. + +## Virtual Boy + +- **Set modulation table**: when enabled, playing this instrument on channel 5 will write to the modulation table. +- **Modulation table**: this allows you to define a waveform for frequency modulation. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise Length**: sets the noise length. higher values result in shorter noise. +- **Waveform**: wavetable sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/vrc6.md b/doc/4-instrument/vrc6.md index 17588b219..64691282d 100644 --- a/doc/4-instrument/vrc6.md +++ b/doc/4-instrument/vrc6.md @@ -1,16 +1,28 @@ # VRC6 instrument editor -The VRC6 (regular) instrument editor consists of these macros: +the VRC6 (regular) instrument editor consists of two tabs. -- **Volume**: volume sequence -- **Arpeggio**: pitch sequence -- **Duty**: specifies duty cycle for pulse wave channels -- **Pitch**: fine pitch +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +note that using samples on VRC6 is CPU expensive! + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Duty**: specifies duty cycle for pulse wave channels. +- **Pitch**: fine pitch. ## VRC6 (saw) instrument editor -This channel has its own instrument, a (currently, as of 0.6) one-of-a-kind thing in Furnace. +this channel has its own instrument type, a one-of-a-kind thing in Furnace that was decided as a compromise during a debate. -The only differences from this instrument type from compared to the regular instrument are that it: - - has a volume range of 0-63 instead of 0-15. - - has no duty cycle range +the only differences from this instrument type compared to the regular one are: +- the lack of a Sample tab. +- it has a volume range of 0-63 instead of 0-15. +- it lacks a duty cycle macro. + - if you come from FamiTracker, this may seem strange to you, but it isn't. diff --git a/doc/4-instrument/wavesynth.md b/doc/4-instrument/wavesynth.md new file mode 100644 index 000000000..44b2c938a --- /dev/null +++ b/doc/4-instrument/wavesynth.md @@ -0,0 +1,29 @@ +# wavetable synthesizer + +within the "Wavetable" tab of the instrument editor, Furnace allows you to modulate or combine 1 or 2 waves to create unique "animated" sounds. think of it like a VST or a plugin, as it's basically an extension of regular wavetable soundchips that still allow it to run on real hardware. + +this is accomplished by selecting a wave or two, a mode, and adjusting the settings as needed until you come up with a sound that you like, without taking up a load of space. this allows you to create unique sound effects or instruments, that, when used well, almost sound like they're Amiga samples. + +unfortunately, on some chips like the HuC6280, you cannot use the wavetable synth to animate waveforms and have them sound smooth, as the chip resets the channel's phase when a waveform is changed while the channel is playing. on certain frequencies, this can be avoided, but not on most, unfortunately. + +![instrument wavetable tab](instrument-wavetable.png) + +input waveforms should match the size of the wavetable or unexpected results may occur. + +- **Enable synthesizer**: must be on for the rest of this to work. +- synthesizer type: selects the synthesis algorithm. +- waveform displays. +- **Wave 1**: selects input waveform. + - this will turn yellow to indicate that a Waveform macro is set. +- **Wave 2**: selects second input waveform. only appears when a dual-waveform synthesizer is selected. +- **Pause preview**: toggles live waveform preview. +- **Restart preview**: restarts preview from initial state. +- **Copy to new wavetable**: copies the currently displayed output waveform into the wavetable as a new entry. +- (width×height): size of wavetable. +- **Update Rate**: time in ticks between waveform changes. +- **Speed**: rate of change with each update. +- **Amount**: strength of synthesizer function. +- **Power**: only appears when synthesizer type is "Phase Modulation". +- **Global**: + - if disabled, each note resets the synthesizer to the start. + - if enabled, synthesis continues unbroken from note to note. diff --git a/doc/4-instrument/wavetable.png b/doc/4-instrument/wavetable.png index 2b7e4ac5e..64589ae04 100644 Binary files a/doc/4-instrument/wavetable.png and b/doc/4-instrument/wavetable.png differ diff --git a/doc/4-instrument/wonderswan.md b/doc/4-instrument/wonderswan.md index d43e154ec..d6a325d38 100644 --- a/doc/4-instrument/wonderswan.md +++ b/doc/4-instrument/wonderswan.md @@ -1,8 +1,27 @@ # WonderSwan instrument editor -WS instrument editor consists of only four macros, similar to PCE but with different volume and noise range: +the WonderSwan instrument editor contains three tabs: Sample, Wavetable and Macros. -- **Volume**: volume sequence -- **Arpeggio**: pitch sequencr -- **Noise**: noise LFSR tap sequence -- **Waveform**: spicifies wavetables sequence +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +only on channel 2! + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +these are similar to PC Engine, with some differences. + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise**: set noise size. + - only on channel 4. +- **Waveform**: wave sequence. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of waveform. diff --git a/doc/4-instrument/wsg.md b/doc/4-instrument/wsg.md index 14aa36382..5c32f50b2 100644 --- a/doc/4-instrument/wsg.md +++ b/doc/4-instrument/wsg.md @@ -1,11 +1,20 @@ # Namco WSG instrument editor -The Namco WSG/C15/C30 instrument editor consists of these macros: +the Namco WSG/C15/C30 instrument editor consists of two tabs: Wavetable and Macros. -- **Volume**: volume sequence -- **Arpeggio**: pitch sequence -- **Waveform**: specifies wavetable sequence -- **Noise**: specifies noise pitch (WARNING: only on C30!) -- **Panning (left)**: output level of left channel -- **Panning (right)**: output level of right channel -- **Pitch**: fine pitch +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Noise**: specifies noise pitch. + - only applicable for Namco C30, and even so, only on the last 4 channels. +- **Waveform**: specifies wavetable sequence. +- **Panning (left)**: output level of left channel. + - Namco C30 only. +- **Panning (right)**: output level of right channel. + - Namco C30 only. +- **Pitch**: fine pitch. diff --git a/doc/4-instrument/x1_010.md b/doc/4-instrument/x1_010.md index 8be27f057..948a24867 100644 --- a/doc/4-instrument/x1_010.md +++ b/doc/4-instrument/x1_010.md @@ -1,11 +1,30 @@ # X1-010 instrument editor -X1-010 instrument editor consists of these macros. +X1-010 instrument editor contains three tabs: Sample, Wavetable and Macros. -- **Volume**: volume levels sequence -- **Arpeggio**: pitch sequence -- **Waveform**: specifies wavetables sequence -- **Envelope Mode**: allows shaping an envelope -- **Envelope**: specifies envelope shape sequence, it's also wavetable. -- **Auto envelope numerator**: sets the envelope to the channel's frequency multiplied by numerator -- **Auto envelope denominator**: sets the envelope to the channel's frequency divided by denominator +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +the only differences are the lack of an "Use wavetable" option, and the presence of a "Use sample" one. + +there also is a "Sample bank slot" setting, but I think that does nothing for now. + +## Wavetable + +this allows you to enable and configure the Furnace wavetable synthesizer. see [this page](wavesynth.md) for more information. + +## Macros + +- **Volume**: volume levels sequence. +- **Arpeggio**: pitch sequence. +- **Waveform**: waveform selection sequence. +- **Panning (left)**: output level for left channel. +- **Panning (right)**: output level for right channel. +- **Pitch**: fine pitch. +- **Envelope Mode**: sets up envelope. the way it works is kind of complicated and even I don't understand how it works, so it's not documented for now. +- **Envelope**: specifies which wavetable should be used for envelope. +- **AutoEnv Num**: sets the envelope to the channel's frequency multiplied by numerator. +- **AutoEnv Den**: sets the envelope to the channel's frequency divided by denominator. + - the X1-010 hardware envelope is considerably slower than AY's. beware! + - these two must be set in order for AutoEnv to work! diff --git a/doc/4-instrument/ymz280b.md b/doc/4-instrument/ymz280b.md new file mode 100644 index 000000000..3dc935d5e --- /dev/null +++ b/doc/4-instrument/ymz280b.md @@ -0,0 +1,15 @@ +# YMZ280B instrument editor + +the YMZ280B instrument editor contains three tabs: Sample and Macros. + +## Sample + +for sample settings, see [the Sample instrument editor](sample.md). + +## Macros + +- **Volume**: volume sequence. +- **Arpeggio**: pitch sequence. +- **Panning**: stereo panning sequence. +- **Pitch**: fine pitch. +- **Phase Reset**: trigger restart of sample. diff --git a/doc/5-wave/README.md b/doc/5-wave/README.md index 243e92366..fc0957ad5 100644 --- a/doc/5-wave/README.md +++ b/doc/5-wave/README.md @@ -1,27 +1,28 @@ # wavetables -Wavetable synthesizers, in context of Furnace, are sound sources that operate on extremely short n-bit PCM streams. By extremely short, no more than 256 bytes. This amount of space is nowhere near enough to store an actual sampled sound, it allows certain amount of freedom to define a waveform shape. +wavetable chips, in context of Furnace, are sound generators that operate on extremely short, looping sample streams. by extremely short, usually no more than 256 samples. +this amount of space is nowhere near enough to store an actual sampled sound, but it allows certain amount of freedom to define a waveform shape. -Each chip has its own maximum size, shown in the following table. If a larger wave is defined for these chips, it will be squashed to fit within the constraints of the chips. Some hardware doesn't work well with the wavetable synthesizer (described below); these systems are marked in the "notes" column. +each chip has its own maximum size, shown in the following table. if a larger wave is defined for these chips, it will be scaled to fit within the constraints of the chips. some of these don't work well with the wavetable synthesizer (described below); these systems are marked in the "notes" column. -system | width | height | notes ---------------------|------:|:-------|:------ -Bubble System | 32 | 16 | -Game Boy | 32 | 16 | phase reset on waveform change (clicking) -SM8521 | 32 | 16 | -Namco WSG | 32 | 16 | RAM only -WonderSwan | 32 | 16 | -Namco 163 | ≤240 | 16 | limits differ depending on channel count -SNES | ≤256 | 16 | -PC Engine | 32 | 32 | phase reset on waveform change (clicking) -Virtual Boy | 32 | 64 | wavesynth unsupported -Famicom Disk System | 64 | 64 | -Konami SCC | 32 | 256 | -Seta X1-010 | 128 | 256 | -Amiga | ≤256 | 256 | +system | width | height | notes +--------------|------:|:-------|:------ +Bubble System | 32 | 16 | +Game Boy | 32 | 16 | phase reset on waveform change (clicking) +SM8521 | 32 | 16 | +Namco WSG | 32 | 16 | RAM only +WonderSwan | 32 | 16 | +Namco 163 | ≤240 | 16 | limits differ depending on channel count +SNES | ≤256 | 16 | +PC Engine | 32 | 32 | phase reset on waveform change (clicking) +Virtual Boy | 32 | 64 | +FDS | 64 | 64 | +Konami SCC | 32 | 256 | +Seta X1-010 | 128 | 256 | +Amiga | ≤256 | 256 | -# wavetable editor +## wavetable editor ![wavetable editor](wave-editor.png) @@ -35,22 +36,22 @@ controls across the top line: - **Steps**: view waveform as discrete blocks. - **Lines**: view waveform as a continuous line. - **Width**: length of the waveform data. maximum is 256. -- **Height**: depth of the waveform. maximum is 256. -- `<` / `>`: toggle tabs (described below). +- **Height**: height of the waveform. maximum is 256. +- `<` / `>`: show/hide waveform utilities (described below). waveform display: - the waveform is directly editable with the mouse. - hovering will display a tooltip with the waveform position and value. controls across the bottom line: -- **Dec**: view MML stream as decimal. -- **Hex**: view MML stream as hexadecimal. -- `+` / `±`: toggle MML stream as unsigned/signed. also adjusts waveform display. -- MML stream: waveform data as an editable numeric sequence. +- **Dec**: view text input as decimal. +- **Hex**: view text input as hexadecimal. +- `+` / `±`: toggle text input as unsigned/signed. also adjusts waveform display. +- text input: waveform data as an editable numeric sequence. also called "MML stream". -## tabs +## waveform utilities -each tab provides different ways of creating or altering a waveform. +these provide different ways of creating or altering a waveform. ### Shapes @@ -58,9 +59,9 @@ each tab provides different ways of creating or altering a waveform. this creates a waveform by adding together a few predefined basic wave shapes. - shape: select shape from sine, triangle, saw, and square. -- **Duty**: only affects pulse waves, determining their width +- **Duty**: only affects pulse waves, determining their width. - **Exponent**: applies an exponent (power) to the waveform (^2, ^3 and so on). -- **XOR Point**: determines the point where the waveform gets negated. +- **XOR Point**: determines the point where the waveform gets inverted. - **Amplitude/Phase**: add together up to 16 instances of the shape. - **Amplitude**: height of the shape. - **Phase**: position along the shape. for example, 0.250 starts the shape a quarter of the way along. @@ -71,7 +72,7 @@ this creates a waveform by adding together a few predefined basic wave shapes. this creates a waveform using frequency modulation synthesis with up to four operators. -one can set carrier/modulation levels, frequency multipliers, connections between operators and FM waveforms of these operators. +you can set carrier/modulation levels, frequency multipliers, connections between operators and FM waveforms of these operators. ### WaveTools @@ -79,11 +80,11 @@ one can set carrier/modulation levels, frequency multipliers, connections betwee these are useful editing tools to fine-tune the waveform: - **Scale X**: stretches the waveform to a new length. -- interpolation method: filters the waveform when stretching. choose from none, linear, cosine, and cubic interpolation. +- **interpolation method**: filters the waveform when stretching. choose from none, linear, cosine, and cubic interpolation. - **Scale Y**: resizes the waveform to a new height. it will clip at the top and bottom. - **Offset X**: slides the the waveform forward or back. it will wrap around. - **Offset Y**: slides the waveform up or down. it will clip at the top and bottom. -- **Smooth**. smooths waveform. +- **Smooth**. averages values in the waveform. - **Amplify**. changes the volume of the waveform. it will clip at the top and bottom. - **Normalize**: stretches waveform to maximum within the wavetable height. - **Invert**: flips waveform vertically. @@ -92,35 +93,3 @@ these are useful editing tools to fine-tune the waveform: - **Double**: doubles the waveform's frequency by squashing it to half length then repeating it. - **Convert Signed/Unsigned**. worth trying if an imported wave sounds corrupted. - **Randomize**: generate a completely random waveform. - - - -# wavetable synthesizer - -Within the "Wavetable" tab of the instrument editor, Furnace allows you to modulate or combine 1 or 2 waves to create unique "animated" sounds. Think of it like a VST or a plugin, as it's basically an extension of regular wavetable soundchips that still allow it to run on real hardware. - -This is accomplished by selecting a wave or two, a mode, and adjusting the settings as needed until you come up with a sound that you like, without taking up a load of space. This allows you to create unique sound effects or instruments, that, when used well, almost sound like they're Amiga samples. - -Unfortunately, on some chips like the HuC6280, you cannot use the wavetable synth to animate waveforms and have them sound smooth, as the chip resets the channel's phase when a waveform is changed while the channel is playing. On certain frequencies, this can be avoided, but not on most, unfortunately. - -![instrument wavetable tab](instrument-wavetable.png) - -input waveforms should match the size of the wavetable or unexpected results may occur. - -- **Enable synthesizer**: must be on for the rest of this to work. -- synthesizer type: selects the synthesis algorithm. -- waveform displays. -- **Wave 1**: selects input waveform. - - this will turn yellow to indicate that a Waveform macro is set. -- **Wave 2**: selects second input waveform. only appears when a dual-waveform synthesizer is selected. -- **Pause preview**: toggles live waveform preview. -- **Restart preview**: restarts preview from initial state. -- **Copy to new wavetable**: copies the currently displayed output waveform into the wavetable as a new entry. -- (width×height): size of wavetable. -- **Update Rate**: time in ticks between waveform changes. -- **Speed**: rate of change with each update. -- **Amount**: strength of synthesizer function. -- **Power**: only appears when synthesizer type is "Phase Modulation". -- **Global**: - - if disabled, each note resets the synthesizer to the start. - - if enabled, synthesis continues unbroken from note to note. diff --git a/doc/5-wave/instrument-wavetable.png b/doc/5-wave/instrument-wavetable.png deleted file mode 100644 index 4710b6680..000000000 Binary files a/doc/5-wave/instrument-wavetable.png and /dev/null differ diff --git a/doc/5-wave/wave-editor-FM.png b/doc/5-wave/wave-editor-FM.png index 2fd255d31..8461ed718 100644 Binary files a/doc/5-wave/wave-editor-FM.png and b/doc/5-wave/wave-editor-FM.png differ diff --git a/doc/5-wave/wave-editor-shapes.png b/doc/5-wave/wave-editor-shapes.png index 6fbffa028..f0e197fbc 100644 Binary files a/doc/5-wave/wave-editor-shapes.png and b/doc/5-wave/wave-editor-shapes.png differ diff --git a/doc/5-wave/wave-editor-tools.png b/doc/5-wave/wave-editor-tools.png index aea9ab457..e45a4b556 100644 Binary files a/doc/5-wave/wave-editor-tools.png and b/doc/5-wave/wave-editor-tools.png differ diff --git a/doc/5-wave/wave-editor.png b/doc/5-wave/wave-editor.png index 570a915fb..1239c1378 100644 Binary files a/doc/5-wave/wave-editor.png and b/doc/5-wave/wave-editor.png differ diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index ccd663c1f..539dbbf0a 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -1,8 +1,8 @@ # samples -In the context of Furnace, a sound sample (usually just referred to as a sample) is a string of numbers that represent sampled PCM audio. +in the context of Furnace, a sound sample (usually just referred to as a sample) stores a sound. -In Furnace, these samples can be generated by importing a .wav (think of it as an higher quality MP3) file. +in Furnace, these samples can be generated by importing a .wav file. ## supported chips @@ -10,28 +10,34 @@ the following sound chips have sample support: - NES/Ricoh 2A03 (with DPCM support and only on channel 5) - Sega Genesis/YM2612 (channel 6 only) -- PC Engine/TurboGrafx-16/HuC6280 -- Amiga/Paula +- PC Engine/TurboGrafx-16 +- Amiga - SegaPCM -- NEC PC-9801/YM2608 (ADPCM channel only) -- Neo Geo/Neo Geo CD/YM2610 (ADPCM channels only) +- YM2608 (ADPCM channel only) +- YM2610(B) (ADPCM channels only) - Seta/Allumer X1-010 - Atari Lynx -- MSM6258 and MSM6295 -- YMU759/MA-2 (last channel only) +- MSM6258 +- MSM6295 - QSound -- ZX Spectrum 48k (1-bit) +- ZX Spectrum 48K (1-bit overlay) - RF5C68 -- SNES/S-DSP -- WonderSwan (second channel only) -- tildearrow Sound Unit +- SNES +- WonderSwan (channel 2 only) +- Sound Unit - VERA (last channel only) - Y8950 (last channel only) - Konami K007232 +- Konami K053260 - Irem GA20 - Ensoniq OTTO/ES5506 - Yamaha PCMD8/YMZ280B - MMC5 (last channel only) +- VRC6 (software!) +- AY-3-8910 (software!) +- AY8930 (software!) +- Namco C140 +- Namco C219 ## compatible sample mode (LEGACY) @@ -50,20 +56,18 @@ due to limitations in some of those sound chips, some restrictions exist: - NES: if on DPCM mode, only a limited selection of frequencies is available, and loop position isn't supported (only entire sample). - SegaPCM: your sample can't be longer than 65535, and the maximum frequency is 31.25KHz. - QSound: your sample can't be longer than 65535, and the loop length shall not be greater than 32767. -- Neo Geo (ADPCM-A): no looping supported. your samples will play at 18.518KHz. -- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is 55.555KHz. -- YM2608: the maximum frequency is 55.555KHz. +- ADPCM-A: no looping supported. your samples will play at around 18.518KHz. +- ADPCM-B/YM2608: no loop position supported (only entire sample), and the maximum frequency is 55.555KHz. - MSM6258/MSM6295: no arbitrary frequency. - ZX Spectrum Beeper: your sample can't be longer than 2048, and it always plays at ~55KHz. - Seta/Allumer X1-010: frequency resolution is terrible in the lower end. your sample can't be longer than 131072. +- C219: sample lengths and loop will be set to an even number, and your sample can't be longer than 131070. furthermore, many of these chips have a limited amount of sample memory. check memory usage in window > statistics. -# the sample editor +## the sample editor -you can actually tweak your samples in Furnace's sample editor, which can be accessed by clicking on `window` (at the top of the screen) then clicking on `sample editor`. - -the changes you make will be applied as soon as you've committed them to your sample, but they can be undone and redone, just like text. +you can edit your samples in Furnace's sample editor, which can be accessed by clicking on `window` (at the top of the screen) then clicking on `sample editor`, or by double-clicking a sample in the sample list. in there, you can modify certain data pertaining to your sample, such as the: - volume of the sample in percentage, where 100% is the current level of the sample (note that you can distort it if you put it too high) @@ -75,25 +79,31 @@ in there, you can modify certain data pertaining to your sample, such as the: - top-left drop-down box: sample slot. - **Open**: replaces current sample. - - Right-clicking brings up a menu: + - right-clicking brings up a menu: - **import raw...**: brings up a file selector, then presents a dialog to choose the format of the selected file. - **Save**: saves current sample to disk. - - Right-clicking brings up a menu: + - right-clicking brings up a menu: - **save raw...**: brings up a file selector, then saves the sample as raw data. - **Name**: name in sample list. -- button to left of **Info**: collapses and expands the info bar. -- **Type**: sample format. only 8-bit and 16-bit PCM samples are editable. selecting a format converts the sample data. -- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. should not be enabled for BRR-type samples. only appears when applicable. -- **8-bit dither**: applies dithering to samples meant to play back at 8-bit resolution. only appears when applicable. +- button to left of **Info**: collapses and expands the info section. +- **Type**: sample format. + - only 8-bit and 16-bit PCM samples are editable. + - selecting a format converts the sample data. +- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. + - should not be enabled for BRR-type samples. + - only appears when applicable. +- **8-bit dither**: applies dithering to samples meant to play back at 8-bit resolution. + - only appears when applicable. - **Rate**: switches to normal rate values. - **Compat Rate**: switches to DefleMask-compatible rate values for sample mapping. + - **use of this is discouraged!** - **Hz**: base frequency of sample played at `C-4`. - **Note**: note corresponding to Hz. - **Fine**: fine tuning. ranges from -64 to 63, which maps to -1 to almost +1 semitone. - **Loop**: enable or disable sample loop. only on supported chips. -- **Mode**: direction of loop. backward and ping pong loops are only natively available on some chips; on others, loop will be automatically unrolled as needed. +- **Mode**: direction of loop. backward and ping pong loops are only natively available on some chips. - **Start**: start of loop. - **End**: end of loop. @@ -126,7 +136,8 @@ in there, you can modify certain data pertaining to your sample, such as the: - **Trim**: removes all but selection. - **Reverse**: reverses direction of selection. - **Invert**: flips selection "vertically". -- **Signed/unsigned exchange**: reinterprets selection data as being of the opposite sign. if a sample sounds fine elsewhere but is distorted on import, it may have been interpreted as signed when it should be unsigned, or vice versa; this will correct that. +- **Signed/unsigned exchange**: reinterprets selection data as being of the opposite sign. + - if a sample sounds fine elsewhere but is distorted on import, it may have been interpreted as signed when it should be unsigned, or vice versa; this will correct that. - **Apply filter**: filters the selection. pops up a dialog box: - **From**: filter cutoff frequency at start of selection. - **To**: filter cutoff frequency at end of selection. @@ -137,6 +148,6 @@ in there, you can modify certain data pertaining to your sample, such as the: - **High-pass**: amount to attenuate everything below cutoff. - **Preview sample**: plays sample at base frequency. - **Stop sample preview**: stops preview. -- **Create instrument from sample**: creates a new instrument with its initial sample set to the current sample. +- **Create instrument from sample**: creates a new instrument with its sample set to the current sample. - **Zoom**: shows and sets sample view zoom level. - **Zoom mode**: switches between "Auto" (entire sample fits in window) and "100%" (each horizontal pixel represents one sample point). diff --git a/doc/6-sample/sample-editor.png b/doc/6-sample/sample-editor.png index 1086e43d4..155f2ce10 100644 Binary files a/doc/6-sample/sample-editor.png and b/doc/6-sample/sample-editor.png differ diff --git a/doc/7-systems/README.md b/doc/7-systems/README.md index 367ca9d83..a8387d85e 100644 --- a/doc/7-systems/README.md +++ b/doc/7-systems/README.md @@ -1,8 +1,8 @@ # systems -this is a list of some of the systems that Furnace supports, as shown in the new file dialog. each chip links to a page with information and a list of supported effects. +this is a list that contains some of the systems that Furnace supports, as shown in the New File dialog. each chip links to a page with information and a list of supported effects. -some systems have alternate chips, such as the Sega Genesis having a YM2612, a YM3438, or YMF276 depending on the model. this list shows the default configuration. +some systems have alternate chips, such as the Sega Genesis having a YM2612 or YM3438 depending on the model. this list shows the default configuration. - **Sega Genesis**: [YM3438](ym2612.md), [SN76489](sms.md) - **Sega Genesis (with Sega CD)**: [YM3438](ym2612.md), [SN76489](sms.md), [RF5C164](ricoh.md) @@ -31,9 +31,9 @@ some systems have alternate chips, such as the Sega Genesis having a YM2612, a Y - **Amiga**: [Amiga](amiga.md) -- **Arcade (YM2151 and SegaPCM)**: [YM2151](ym2152.md), [SegaPCM](segapcm.md) +- **Arcade (YM2151 and SegaPCM)**: [YM2151](ym2151.md), [SegaPCM](segapcm.md) -- **Capcom CPS-1**: [YM2151](ym2152.md), [MSM6295](msm6295.md) +- **Capcom CPS-1**: [YM2151](ym2151.md), [MSM6295](msm6295.md) - **Capcom CPS-2 (QSound)**: [QSound](qsound.md) - **Neo Geo CD**: [YM2610](ym2610.md) @@ -46,7 +46,7 @@ some systems have alternate chips, such as the Sega Genesis having a YM2612, a Y - **Konami Bubble System**: [AY-3-8910](ay8910.md) × 2, [Konami WSG](bubblesystem.md) -- **Sharp X68000**: [YM2151](ym2152.md), [MSM6258](msm6258.md) +- **Sharp X68000**: [YM2151](ym2151.md), [MSM6258](msm6258.md) - **PC + Sound Blaster Pro**: [YM3812](opl.md) × 2, [DAC](dac.md), [PC Speaker](pcspkr.md) @@ -59,7 +59,7 @@ some systems have alternate chips, such as the Sega Genesis having a YM2612, a Y -# chips +## chips this is the full list of chips that Furnace supports. @@ -111,7 +111,7 @@ this is the full list of chips that Furnace supports. - [VRC7, Y8950, YM3526, YM3812 and YMF262 (OPL)](opl.md) - [YM2413 (OPLL)](opll.md) - [YM2414 (OPZ)](opz.md) -- [YM2151 (OPM)](ym2152.md) +- [YM2151 (OPM)](ym2151.md) - [YM2203 (OPN)](ym2203.md) - [YM2608 (OPNA)](ym2608.md) - [YM2610 (OPNB)](ym2610.md) diff --git a/doc/7-systems/amiga.md b/doc/7-systems/amiga.md index c40d6eed6..af6bfb67f 100644 --- a/doc/7-systems/amiga.md +++ b/doc/7-systems/amiga.md @@ -6,7 +6,7 @@ in this very computer music trackers were born... imported MOD files use this chip, and will set A-4 tuning to 436. -# effects +## effects - `10xx`: **toggle low-pass filter.** `0` turns it off and `1` turns it on. - `11xx`: **toggle amplitude modulation with the next channel.** @@ -16,10 +16,10 @@ imported MOD files use this chip, and will set A-4 tuning to 436. - `13xx`: **change wave.** - only works when "Mode" is set to "Wavetable" in the instrument. -# info +## info -this chip uses the [Generic Sample](../4-instrument/amiga.md) instrument editor. +this chip uses the [Generic Sample](../4-instrument/sample.md) instrument editor. - the maximum rate for sample playback is technically 31469Hz but anything higher than 28867Hz will sound glitchy on hardware. - sample lengths and loop will be set to an even number. -- samples can't be longer than 131070. \ No newline at end of file +- samples can't be longer than 131070. diff --git a/doc/7-systems/ay8910.md b/doc/7-systems/ay8910.md index 8c88d704e..853395496 100644 --- a/doc/7-systems/ay8910.md +++ b/doc/7-systems/ay8910.md @@ -6,9 +6,9 @@ it is a 3-channel square/noise/envelope sound generator. the chip's powerful sou the AY-3-8914 variant was used in Intellivision, which is pretty much an AY with 4 level envelope volume per channel and different register format. -as of Furnace 0.6pre7, AY-3-8910 supports software sample playback, where all 3 channels can play 4-bit PCM samples (at the cost of a very high CPU usage) +Furnace is capable of doing software sample playback on AY-3-8910, where all 3 channels can play 4-bit PCM samples (at the cost of a very high CPU usage). -# effects +## effects - `20xx`: **set channel mode.** - `0`: square @@ -47,10 +47,11 @@ as of Furnace 0.6pre7, AY-3-8910 supports software sample playback, where all 3 - `2Fxx`: **write to I/O port B.** - this changes the port's mode to "write". make sure you have connected something to it. -# info +## what is obelisco -this chip uses the [AY-3-8910](../4-instrument/ay8910.md) instrument editor. +it's a name I use for a spiky waveform that starts low. +its origin is a wavetable that comes in DefleMask that happens to be called Obelisco. ## AY derivative modes @@ -59,3 +60,7 @@ AY-3-810 was an absurdly popular chip that was blessed with many third-party clo - the AY-3-8914 variant was used in Intellivision, which is pretty much an 8910 with 4 level envelope volume per channel and different register format. - Yamaha YM2149 was an AY-3-8910 clone released in 1983. it's almost identical to AY with minor differences being: higher hardware envelope step resolution (16 vs 32), half-clock mode when voltage level is low, much stronger DC offset and cleaner, but softer output. - Sunsoft 5B is YM2149 clone with half-clock mode forced on. + +## info + +this chip uses the [AY-3-8910](../4-instrument/ay8910.md) instrument editor. diff --git a/doc/7-systems/ay8930.md b/doc/7-systems/ay8930.md index 545e8fd0b..c865b7f7a 100644 --- a/doc/7-systems/ay8930.md +++ b/doc/7-systems/ay8930.md @@ -3,13 +3,13 @@ a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator. sadly, this soundchip has only ever observed minimal success, and has remained rather obscure since. -it is best known for being used in the Covox Sound Master, which didn't sell well either. it also observed very minimal success in Merit's CRT-250 machines, but only as a replacement for the AY-3-8910. +it is known for being used in the Covox Sound Master, which didn't sell well either. emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted. -as of Furnace 0.6pre7, AY8930 supports software PCM, where all 3 channels can play 5-bit PCM samples (at the cost of a very high CPU usage) +Furnace is able to do software PCM on AY8930, where all 3 channels can play 5-bit PCM samples (at the cost of a very high CPU usage). -# effects +## effects - `12xx`: **set channel duty cycle.** - `0`: 3.125% @@ -56,6 +56,6 @@ as of Furnace 0.6pre7, AY8930 supports software PCM, where all 3 channels can pl - `y` is the denominator. - if `x` or `y` are 0 this will disable auto-envelope mode. -# info +## info -this chip uses the [AY8930](../4-instrument/8930.md) instrument editor. +this chip uses the [AY8930](../4-instrument/ay8930.md) instrument editor. diff --git a/doc/7-systems/bubblesystem.md b/doc/7-systems/bubblesystem.md index 946fd61d8..5a589407b 100644 --- a/doc/7-systems/bubblesystem.md +++ b/doc/7-systems/bubblesystem.md @@ -8,10 +8,10 @@ another AY-3-8910 IO is used for reading sound hardware status. Furnace emulates this configuration as a "chip" with 32×16 wavetables. -# effects +## effects - `10xx`: **change wave.** -# info +## info -this chip uses the [Konami SCC/ Bubble System WSG](../4-instrument/scc.md) instrument editor. +this chip uses the [Konami SCC/Bubble System WSG](../4-instrument/scc.md) instrument editor. diff --git a/doc/7-systems/c140.md b/doc/7-systems/c140.md index eb39e3461..97509b32f 100644 --- a/doc/7-systems/c140.md +++ b/doc/7-systems/c140.md @@ -1,19 +1,17 @@ # Namco C140 -Namco C140 is a 24-channel custom PCM sound chip manufactured jointly by Fujitsu and Namco. It was first used in Namco Sytem 2 arcade family starting in 1987. +the Namco C140 is a 24-channel custom PCM sound chip manufactured jointly by Fujitsu and Namco. it was first used in Namco System 2 arcade family starting in 1987. -This chip features: +this chip features: - stereo soft panning -- accepts either raw 12-bit PCM or proprietary 8-bit u-law compressed PCM samples +- accepts either raw 12-bit PCM or 8-bit µ-law compressed PCM samples - 21.4 kHz sampling rate -# effects +## effects -- `80xx`: set panning (`00: left, `80`: center, `FF`: right) -- `81xx`: set left channel panning -- `82xx`: set right channel panning +none! -# info +## info this chip uses the [C140](../4-instrument/c140.md) instrument editor. diff --git a/doc/7-systems/c219.md b/doc/7-systems/c219.md new file mode 100644 index 000000000..44d0cafd0 --- /dev/null +++ b/doc/7-systems/c219.md @@ -0,0 +1,19 @@ +# Namco C219 + +Namco C219 is a 16-channel PCM sound chip that's a lot like C140, but has a noise generator, surround effect and a different µ-law curve. + +this chip features: + +- stereo soft panning +- accepts either 8-bit PCM or proprietary 8-bit µ-law compressed PCM samples + +## effects + +- `11xx`: **set noise mode.** +- `12xy`: **set invert mode.** + - if `x` is 1 or higher, surround is enabled. + - if `y` is 1 or higher, invert is enabled. + +## info + +this chip uses the [C219](../4-instrument/c219.md) instrument editor. diff --git a/doc/7-systems/c64.md b/doc/7-systems/c64.md index 04035df58..28a69671b 100644 --- a/doc/7-systems/c64.md +++ b/doc/7-systems/c64.md @@ -6,7 +6,7 @@ very popular in Europe and mostly due to the demoscene, which stretched the mach two versions of aforementioned chip exist - 6581 (original chip) and 8580 (improved version with working waveform mixing and somewhat more consistent filter curves). -# effects +## effects - `10xx`: **change wave.** the following values are accepted: - `00`: nothing @@ -58,6 +58,6 @@ two versions of aforementioned chip exist - 6581 (original chip) and 8580 (impro - `3xxx`: **set duty cycle.** `xxx` range is `000` to `FFF`. - `4xxx`: **set cutoff.** `xxx` range is `000` to `7FF`. -# info +## info this chip uses the [C64](../4-instrument/c64.md) instrument editor. diff --git a/doc/7-systems/dac.md b/doc/7-systems/dac.md index 3c6445db9..7639495ea 100644 --- a/doc/7-systems/dac.md +++ b/doc/7-systems/dac.md @@ -4,10 +4,10 @@ a sample channel, with freely selectable rate, mono/stereo and bit depth setting with it, you can emulate PCM DACs found in Williams arcade boards, Sound Blasters, MSX TurboR, Atari STe, NEC PC-9801-86, among others. -# effects +## effects none yet. -# info +## info -this chip uses the [Generic Sample](../4-instrument/amiga.md) instrument editor. +this chip uses the [Generic Sample](../4-instrument/sample.md) instrument editor. diff --git a/doc/7-systems/es5506.md b/doc/7-systems/es5506.md index e36eff1c5..d6ddb9d79 100644 --- a/doc/7-systems/es5506.md +++ b/doc/7-systems/es5506.md @@ -2,15 +2,15 @@ sample-based synthesis chip used in a bunch of Taito arcade machines and PC sound cards like Soundscape Elite. a variant of it was the heart of the well-known Gravis Ultrasound. -it supports a whopping 32 channels of 16-bit PCM and: +it has a whopping 32 channels of 16-bit PCM and: - real time digital filters -- frequency interpolation +- linear interpolation - loop start and stop positions for each voice (bidirectional and reverse looping) - internal volume multiplication and stereo panning -- hardware support for envelopes +- hardware support for short envelopes -# effects +## effects - `10xx`: **set waveform.** - `11xx`: **set filter mode.** values are `0` through `3`. @@ -37,9 +37,10 @@ it supports a whopping 32 channels of 16-bit PCM and: - `88xx`: **set panning (rear channels).** - `89xx`: **set panning (rear left channel).** - `8Axx`: **set panning (rear right channel).** -- `9xxx`: **set sample offset.** resets sample position to `xxx * 0x100`. +- `9xxx`: **set sample offset.** + - resets sample position to `xxx * 0x100`. - `DFxx`: **set sample playback direction.** -# info +## info this chip uses the [ES5506](../4-instrument/es5506.md) instrument editor. diff --git a/doc/7-systems/fds.md b/doc/7-systems/fds.md index f26ccef9b..6df219cd3 100644 --- a/doc/7-systems/fds.md +++ b/doc/7-systems/fds.md @@ -5,7 +5,7 @@ as it name implies, it allowed people to play games on specialized floppy disks it also offers an additional 6-bit, 64-byte wavetable sound channel with (somewhat limited) FM capabilities, which is what Furnace supports. -# effects +## effects - `10xx`: **change wave.** - `11xx`: **set modulation depth.** @@ -24,8 +24,8 @@ it also offers an additional 6-bit, 64-byte wavetable sound channel with (somewh - 5: -3 - 6: -2 - 7: -1 - - why is this mapping so unnatural? because that's how DefleMask does it (yeah, as you may have guessed this effect is mostly for compatibility reasons)... + - **do not use this effect.** it only exists for compatibility reasons -# info +## info this chip uses the [FDS](../4-instrument/fds.md) instrument editor. diff --git a/doc/7-systems/ga20.md b/doc/7-systems/ga20.md index 875564870..dc2bac6c6 100644 --- a/doc/7-systems/ga20.md +++ b/doc/7-systems/ga20.md @@ -1,8 +1,15 @@ # Irem GA20 -ga20 is a 4 channel PCM sound source used by Irem in their arcades in late 1980s and eraly 1990s, often paired with [Yamaha YM2151](ym2151.md). Soundchip itself is rather unremarkable, having 8-bit volume and pitch control, no stereo panning +it is a 4 channel PCM sound source used by Irem in their arcades in late 1980s and early 1990s, often paired with [Yamaha YM2151](ym2151.md). +the sound chip itself is rather unremarkable, having 8-bit volume and pitch control and no stereo panning... -# effects +## effects none + +let's be honest. Furnace has too many chips and a great portion of them are sample chips that do the same task: playing back samples. + +## info + +this chip uses the [GA20](../4-instrument/ga20.md) instrument type. diff --git a/doc/7-systems/game-boy.md b/doc/7-systems/game-boy.md index b2b624dba..5550e5fba 100644 --- a/doc/7-systems/game-boy.md +++ b/doc/7-systems/game-boy.md @@ -1,10 +1,10 @@ # Game Boy -the Nintendo Game Boy is one of the most successful portable game systems ever made. +the Game Boy is one of the most successful portable game systems ever made. -with stereo sound, two pulse channels, a wave channel and a noise channel, it packed some serious punch. +it has stereo sound, two pulse channels, a wave channel and a noise channel. -# effects +## effects - `10xx`: **change wave.** - `11xx`: **set noise length.** @@ -21,13 +21,12 @@ with stereo sound, two pulse channels, a wave channel and a noise channel, it pa - set to `0` to disable it. - `14xx`: **set sweep direction.** `0` is up and `1` is down. -# info +## info this chip uses the [Game Boy](../4-instrument/game-boy.md) instrument editor. - -# links +## links - [Gameboy sound hardware](https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware) - detailed technical information -- [GameBoy Sound Table](http://www.devrs.com/gb/files/sndtab.html) - note frequency table \ No newline at end of file +- [GameBoy Sound Table](http://www.devrs.com/gb/files/sndtab.html) - note frequency table diff --git a/doc/7-systems/genesis.md b/doc/7-systems/genesis.md index 5215fb101..283fe3ddc 100644 --- a/doc/7-systems/genesis.md +++ b/doc/7-systems/genesis.md @@ -4,7 +4,7 @@ a video game console that showed itself as the first true rival to Nintendo's vi this console is powered by two sound chips: the [Yamaha YM2612](ym2612.md) and [a derivative of the SN76489](sms.md). -# effects +## effects - `10xy`: **set LFO parameters.** - `x` toggles the LFO. @@ -16,7 +16,7 @@ this console is powered by two sound chips: the [Yamaha YM2612](ym2612.md) and [ - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `17xx`: **enable PCM channel.** - this only works on channel 6. - _this effect is here for compatibility reasons!_ it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used). @@ -38,13 +38,13 @@ this console is powered by two sound chips: the [Yamaha YM2612](ym2612.md) and [ -# system modes +## system modes ## extended channel 3 in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. -all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. +all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2-op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. ## CSM diff --git a/doc/7-systems/k007232.md b/doc/7-systems/k007232.md index f7e9d69c1..ca2efdbb2 100644 --- a/doc/7-systems/k007232.md +++ b/doc/7-systems/k007232.md @@ -6,10 +6,12 @@ its sample format is unique; the topmost bit is the end marker, and the low 7 bi it has 7 bit digital output per each channel and no volume register on chip, so it needs external logic to control channel volume. -# effects +## effects -- nothing for now. +nothing. -# info +yeah. + +## info this chip uses the [K007232](../4-instrument/k007232.md) instrument editor. diff --git a/doc/7-systems/k056320.md b/doc/7-systems/k056320.md index ad3fb4a96..5c03c87f0 100644 --- a/doc/7-systems/k056320.md +++ b/doc/7-systems/k056320.md @@ -1,13 +1,13 @@ -# Konami 056320 +# Konami K053260 -the 056320 is a sample-based chip that featured in a number of Konami arcade games, notably _Sunset Riders_ and _Teenage Mutant Ninja Turtles: Turtles in Time_. it has four channels of audio, 12-bit pitch resolution and stereo output, and can access up to 2MB of samples in 8-bit PCM or 4-bit ADPCM formats. +this chip is a sample-based chip that featured in a number of Konami arcade games, notably _Sunset Riders_ and _Teenage Mutant Ninja Turtles: Turtles in Time_. it has four channels of audio, 12-bit pitch resolution and stereo output, and can access up to 2MB of samples in 8-bit PCM or 4-bit ADPCM formats. +## effects +- `DFxx`: **set sample playback direction.** + - `0` is normal. + - `1` is reverse. -# effects +## info -- `DFxx`: Set sample playback direction. `0` is normal; `1` is reverse. - -# info - -this chip uses the [C140](../4-instrument/c140.md) instrument editor. +this chip uses the [K053260](../4-instrument/k053260.md) instrument editor. diff --git a/doc/7-systems/lynx.md b/doc/7-systems/lynx.md index e3bb087db..c6b6e9ed8 100644 --- a/doc/7-systems/lynx.md +++ b/doc/7-systems/lynx.md @@ -1,11 +1,13 @@ # Atari Lynx/MIKEY -the Atari Lynx is a 16 bit handheld console developed by (obviously) Atari Corporation, and initially released in September of 1989, with the worldwide release being in 1990. +the Atari Lynx is a 16 bit handheld console developed by Atari Corporation, and initially released in September of 1989, with the worldwide release being in 1990. -while it was an incredible handheld for the time (and a lot more powerful than a Game Boy), it unfortunately meant nothing in the end due to the Lynx being a market failure, and ending up as one of the things that contributed to the downfall of Atari. +while it was an incredible handheld for the time (and a lot more powerful than Game Boy), it unfortunately meant nothing in the end due to Lynx being a market failure, and ending up as one of the things that contributed to the downfall of Atari. although the Lynx is still getting (rather impressive) homebrew developed for it, that does not mean the Lynx is a popular system at all. +but hey, Furnace supports it, so... + the Atari Lynx has a 6502-based CPU with a sound part (this chip is known as MIKEY). it has the following sound capabilities: - 4 channels of LFSR-based sound, which can be modulated with different frequencies (×0, ×1, ×2, ×3, ×4, ×5, ×7, ×10, and ×11) to create square waves and wavetable-like results. - likewise, when a lot of the modulators are activated, this can provide a "pseudo-white noise"-like effect, which can be useful for drums and sound effects. @@ -13,11 +15,11 @@ the Atari Lynx has a 6502-based CPU with a sound part (this chip is known as MIK - four 8-bit DACs (Digital to Analog Converter), one for each voice. this allows for sample playback (at the cost of CPU time and memory). - a variety of pitches to choose from, and they go from 32Hz to "above the range of human hearing", according to Atari. -# effects +## effects - `3xxx`: **load LFSR.** this is a bitmask with values ranging from `000` to `FFF`. - for it to work, duty macro in instrument editor must be set to some value. without it LFSR will not be fed with any bits. -# info +## info this chip uses the [Atari Lynx](../4-instrument/lynx.md) instrument editor. diff --git a/doc/7-systems/mmc5.md b/doc/7-systems/mmc5.md index 90d8c5696..0b54cc866 100644 --- a/doc/7-systems/mmc5.md +++ b/doc/7-systems/mmc5.md @@ -6,11 +6,11 @@ it has two pulse channels which are very similar to the ones found in the NES, b additionally, it offers an 8-bit DAC which can be used to play samples. only one game is known to use it, though. -# effects +## effects - `12xx`: **set duty cycle or noise mode of channel.** - may be `0` through `3` for the pulse channels. -# info +## info -this chip uses the [NES](../4-instrument/nes.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [NES](../4-instrument/nes.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. diff --git a/doc/7-systems/msm5232.md b/doc/7-systems/msm5232.md index 17ee9ee03..3408e00e9 100644 --- a/doc/7-systems/msm5232.md +++ b/doc/7-systems/msm5232.md @@ -14,7 +14,7 @@ Furnace implements this chip in a way that allows the following features: - global fine tune - global vibrato (some arcade boards played with the clock input to simulate vibrato) -# effects +## effects - `10xy`: **set group control.** - `x` sets sustain mode. @@ -25,6 +25,6 @@ Furnace implements this chip in a way that allows the following features: - `13xx`: **set group decay.** range is `0` to `11`. - only in internal (capacitor-based) envelope mode. -# info +## info this chip uses the [MSM5232](../4-instrument/msm5232.md) instrument editor. diff --git a/doc/7-systems/msm6258.md b/doc/7-systems/msm6258.md index 9cabf1405..9c2d638f0 100644 --- a/doc/7-systems/msm6258.md +++ b/doc/7-systems/msm6258.md @@ -3,14 +3,19 @@ a single-channel ADPCM sound source developed by OKI. it allows max sample rate of 15.6 KHz... with no variable pitch. most prominent use of this chip was Sharp X68000 computer, where it was paired with Yamaha YM2151. Furnace's implementation is MSM6258V, a CPU driven variant that is unlimited by amount of sample data, being able to be fed from the system's RAM. -# effects +## effects -... -# chip config +- `20xx`: **set frequency divider (0 to 2).** + - `0`: /512 + - `1`: /768 + - `2`: /1024 +- `21xx`: **select clock rate.** + - `0`: full + - `1`: half -## chip clock rates +## chip config -MSM6258 is an extremely basic ADPCM sound codec. it has no variable frequency rate; it depends on clock rate of a chip itself. Furnace supports following rates: +MSM6258 is an extremely basic ADPCM sound codec. it has no variable frequency rate; it depends on clock rate of a chip itself. Furnace supports the following rates: | clock rate | sampling rate | |--------------------|---------------| @@ -19,6 +24,6 @@ MSM6258 is an extremely basic ADPCM sound codec. it has no variable frequency ra | 8 MHz | 15625 Hz | | 8.192 MHz | 16000 Hz | -# info +## info -this chip uses the [MSM6258](../4-instrument/msm6258.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [MSM6258](../4-instrument/msm6258.md) instrument editor. diff --git a/doc/7-systems/msm6295.md b/doc/7-systems/msm6295.md index 9906de6b1..3fbcea689 100644 --- a/doc/7-systems/msm6295.md +++ b/doc/7-systems/msm6295.md @@ -1,16 +1,16 @@ # OKI MSM6295 -an upgrade from 6258 - it provides 4 ADPCM channels, at max 32 KHz (still no variable pitch though). between late '80s and late '90s, it was one of the most common, if not _the_ most common soundchip used in arcade machines (Capcom, Toaplan, Kaneko, Atari, Tecmo, the list can go on and on...). Without bankswitching, the chip supports 256kB of sample RAM and can hold up to 127 samples at once. +an upgrade from 6258 - it provides 4 ADPCM channels, at max 32 KHz (still no variable pitch though). between late '80s and late '90s, it was one of the most common, if not _the_ most common soundchip used in arcade machines (Capcom, Toaplan, Kaneko, Atari, Tecmo, the list can go on and on...). without bankswitching, the chip supports 256kB of sample RAM and can hold up to 127 samples at once. -# effects +## effects - `20xx`: **set chip output rate.** - + - `0`: /132 + - `1`: /165 -# info - -this chip uses the [MSM6295](../4-instrument/msm6295.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +## info +this chip uses the [MSM6295](../4-instrument/msm6295.md) instrument editor. ## chip clock rates @@ -36,4 +36,6 @@ like MSM6258, MSM6295 is an extremely basic ADPCM sound codec. it has no variabl ## chip clock divisor -MSM6295 clock rate could be divided by 132 (resulting sample rates above), or by 165. To get a clock rate using divisor of 165, formula is clock rate (in Hz) / 165. Example: 1 MHz MSM6295 in 165 divisor mode results in output rate of 6060 Hz. +MSM6295 clock rate could be divided by 132 (resulting sample rates above), or by 165. +to get a clock rate using divisor of 165, formula is clock rate (in Hz) / 165. +example: 1 MHz MSM6295 in 165 divisor mode results in output rate of 6060 Hz. diff --git a/doc/7-systems/n163.md b/doc/7-systems/n163.md index af1bffbee..a810f8106 100644 --- a/doc/7-systems/n163.md +++ b/doc/7-systems/n163.md @@ -1,4 +1,4 @@ -# Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) +# Namco 163 (also called N163, Namco C163, Namco 106 [sic], Namco 160 or Namco 129) this is one of Namco's NES mappers, with up to 8 wavetable channels. @@ -8,7 +8,7 @@ wavetables are variable in size and may be allocated anywhere in RAM. at least 1 Namco 163 uses time-division multiplexing for its output. this means that only one channel is output per sample (like OPLL and OPN2). therefore, its sound quality gets worse as more channels are activated. -# waveform load position versus waveform position +## waveform load position versus waveform position in Furnace, waveform **load** position/length is different from the waveform position/length. @@ -22,7 +22,7 @@ the waveform pos/len macros only change the pos/len, and not the **load** one. if the waveform changes (e.g. ins change, wave macro or wave synth), or the **load** pos/len changes, the wave is written to memory. -# effects +## effects - `10xx`: **set waveform for playback.** - `11xx`: **set waveform position in RAM for playback.** @@ -39,6 +39,6 @@ if the waveform changes (e.g. ins change, wave macro or wave synth), or the **lo - make sure to use `21xx` first! - `21xx`: **set position for 20xx.** -# info +## info this chip uses the [Namco 163](../4-instrument/n163.md) instrument editor. diff --git a/doc/7-systems/namco.md b/doc/7-systems/namco.md index ffa5817b9..2cfc72b3a 100644 --- a/doc/7-systems/namco.md +++ b/doc/7-systems/namco.md @@ -1,14 +1,14 @@ -# Namco WSG | Namco C15 | Namco C30 +# Namco WSG / Namco C15 / Namco C30 -a family of wavetable synth sound chips used by Namco in their arcade machines (Pacman and later). waveforms are 4-bit, with 32-byte sample length. +a family of wavetable synth sound chips used by Namco in their arcade machines (Pac-Man and later). waveforms are 4-bit, with 32-byte sample length. everything starts with Namco WSG, which is a simple 3-channel wavetable with no extra frills. C15 is a much more advanced sound source with 8 channels, and C30 adds stereo output and noise mode. -# effects +## effects - `10xx`: **change waveform.** - `11xx`: **toggle noise mode.** _warning:_ only on C30. -# info +## info -this chip uses the [Namco WSG](../4-instrument/namco.md) instrument editor. +this chip uses the [Namco WSG](../4-instrument/wsg.md) instrument editor. diff --git a/doc/7-systems/nes.md b/doc/7-systems/nes.md index 28df60676..cfd1823a6 100644 --- a/doc/7-systems/nes.md +++ b/doc/7-systems/nes.md @@ -4,7 +4,7 @@ the console from Nintendo that plays Super Mario Bros. and helped revive the ago also known as Famicom. it is a five-channel sound generator: first two channels play pulse wave with three different duty cycles, third is a fixed-volume triangle channel, fourth is a noise channel (can work in both pseudo-random and periodic modes) and fifth is a (D)PCM sample channel. -# effects +## effects - `11xx`: **write to delta modulation counter.** range is `00` to `7F`. - this may be used to attenuate the triangle and noise channels; at `7F`, they will be at about 57% volume. @@ -31,7 +31,7 @@ also known as Famicom. it is a five-channel sound generator: first two channels - `1`: length counter. volume represents output volume. - `2`: looping envelope. volume represents envelope duration. - `3`: constant volume. default value. volume represents output volume. - - Pulse and noise channels only. + - pulse and noise channels only. - you may need to apply a phase reset (using the macro) to make the envelope effective. - `16xx`: **set length counter.** - see table below for possible values. @@ -57,10 +57,9 @@ also known as Famicom. it is a five-channel sound generator: first two channels - see table below for possible values. -# info - -this chip uses the [NES](../4-instrument/nes.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +## info +this chip uses the [NES](../4-instrument/nes.md) instrument editor. ## short noise frequencies (NTSC) @@ -126,8 +125,6 @@ reference: [NESdev](https://www.nesdev.org/wiki/APU_Length_Counter) ## DPCM frequency table -"value" is for DefleMask compatability. - value | tracker | NTSC freq | NTSC pitch | PAL freq | PAL pitch -----:|:-------:|----------:|:----------:|----------:|:----------: `00` | `C-3` | 4181.7Hz | C-8 - 2¢ | 4177.4Hz | C-8 - 4¢ @@ -147,4 +144,4 @@ value | tracker | NTSC freq | NTSC pitch | PAL freq | PAL pitch `0E` | `G-5` | 24858.0Hz | G-10 - 16¢ | 25191.0Hz | G-10 + 7¢ `0F` | `C-6` | 33143.9Hz | C-11 - 18¢ | 33252.1Hz | C-11 - 12¢ -reference: [NESdev](https://www.nesdev.org/wiki/APU_DMC#Pitch_table) \ No newline at end of file +reference: [NESdev](https://www.nesdev.org/wiki/APU_DMC#Pitch_table) diff --git a/doc/7-systems/opl.md b/doc/7-systems/opl.md index ac82ded0e..2937fa893 100644 --- a/doc/7-systems/opl.md +++ b/doc/7-systems/opl.md @@ -10,11 +10,11 @@ the original OPL (Yamaha YM3526) was present as an expansion for the Commodore 6 its successor, the OPL2 (Yamaha YM3812), added 3 more waveforms and was one of the more popular chips because it was present on the AdLib card for PC. later Creative would borrow the chip to make the Sound Blaster, and totally destroyed AdLib's dominance. -the OPL3 (Yamaha YMF262) added 9 more channels, 4 more waveforms, rudimentary 4-operator mode (pairing up to 12 channels to make up to six 4-operator channels), quadraphonic output (sadly Furnace only supports stereo) and some other things. +the OPL3 (Yamaha YMF262) added 9 more channels, 4 more waveforms, rudimentary 4-operator mode (pairing up to 12 channels to make up to six 4-operator channels), quadraphonic output and some other things. afterwards everyone moved to Windows and software mixed PCM streaming... -# effects +## effects - `10xx`: **set AM depth.** the following values are accepted: - `0`: 1dB (shallow) @@ -27,9 +27,9 @@ afterwards everyone moved to Windows and software mixed PCM streaming... - only in 4-op mode (OPL3). - `15xx`: **set operator 4 level.** - only in 4-op mode (OPL3). -- `16xy`: **sSet multiplier of operator.** +- `16xy`: **set multiplier of operator.** - `x` is the operator (1-4; last 2 operators only in 4-op mode). - - `y` is the multiplier. + - `y` is the new MULT value.. - `17xx`: **set vibrato depth.** - `0`: normal - `1`: double @@ -79,6 +79,6 @@ afterwards everyone moved to Windows and software mixed PCM streaming... - `x` is the operator from 1 to 4; the last 2 operators only work in 4-op mode. a value of `0` means "all operators". - `y` determines whether KSR is on. -# info +## info this chip uses the [FM (OPL)](../4-instrument/fm-opl.md) instrument editor. diff --git a/doc/7-systems/opll.md b/doc/7-systems/opll.md index f32f1eefc..2cf068c13 100644 --- a/doc/7-systems/opll.md +++ b/doc/7-systems/opll.md @@ -1,19 +1,19 @@ # Yamaha YM2413/OPLL -the YM2413, otherwise known as OPLL, is a cost-reduced FM synthesis sound chip, based on the Yamaha YM3812 (OPL2). thought OPL was downgraded enough? :p +the YM2413, otherwise known as OPLL, is a cost-reduced FM synthesis sound chip, based on the Yamaha YM3812 (OPL2). OPLL also spawned a few derivative chips, the best known of these is: - the famous Konami VRC7. used in the Japan-only video game Lagrange Point, it was **another** cost reduction on top of the OPLL! this time just 6 channels... -- Yamaha YM2423, same chip as YM2413, just a different patch set -- Yamaha YMF281, ditto +- Yamaha YM2423, same chip as YM2413, just a different patch set... +- Yamaha YMF281, ditto..... -# technical specifications +## technical specifications the YM2413 is equipped with the following features: - 9 channels of 2 operator FM synthesis - a drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. only pitch might be altered. - - drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mixer twice for 2× volume, like all drum sounds. FM channel 8 splits to Snare, Drum, and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave. + - drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mixer twice for 2× volume, like all drum sounds. FM channel 8 splits to Snare, Drum, and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. channel 9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave. - special synthesis mentioned already is: 5 square waves are gathered from 4×, 64× and 128× the pitch of channel 8 and 16× and 64× the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd. - 1 user-definable patch (this patch can be changed throughout the course of the song) - 15 pre-defined patches which can all be used at the same time @@ -25,14 +25,14 @@ the YM2413 is equipped with the following features: - modulator and carrier key scaling - built-in hardware vibrato support -# effects +## effects - `11xx`: **set feedback of channel.** - `12xx`: **set operator 1 level.** - `13xx`: **set operator 2 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator, either 1 or 2. - - `y` is the multiplier. + - `y` is the new MULT value.. - `18xx`: **toggle drums mode.** - `0` disables it and `1` enables it. - only in drums mode. @@ -64,11 +64,11 @@ the YM2413 is equipped with the following features: - `x` is the operator, either 1 or 2. a value of `0` means "all operators". - `y` determines whether KSR is on. -# info +## info this chip uses the [FM (OPLL)](../4-instrument/fm-opll.md) instrument editor. ## chip options -- **Ignore top/hi-hat frequency changes**: in drums mode, makes the top/hi-hat channels not write frequency since they share it with snare and tom -- **Apply fixed frequency to all drums at once**: sets the frequency of all drums to that of a fixed frequency OPLL drums instrument when one note with it is reached +- **Ignore top/hi-hat frequency changes**: in drums mode, makes the top/hi-hat channels not write frequency since they share it with snare and tom. +- **Apply fixed frequency to all drums at once**: sets the frequency of all drums to that of a fixed frequency OPLL drums instrument when one note with it is reached. diff --git a/doc/7-systems/opz.md b/doc/7-systems/opz.md index c4b0413a9..7dcf58241 100644 --- a/doc/7-systems/opz.md +++ b/doc/7-systems/opz.md @@ -23,7 +23,7 @@ no plans have been made for TX81Z MIDI passthrough, because: - the TX81Z is very slow to process a note on/off or parameter change event. - the TL range has been reduced to 0-99, but the chip goes from 0-127. -# effects +## effects - `10xx`: **set noise frequency of channel 8 operator 4.** `00` disables noise while `01` to `20` enable it. - `11xx`: **set feedback of channel.** @@ -33,7 +33,7 @@ no plans have been made for TX81Z MIDI passthrough, because: - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `17xx`: **set LFO speed.** - `18xx`: **set LFO waveform.** `xx` may be one of the following: - `00`: saw @@ -114,6 +114,6 @@ no plans have been made for TX81Z MIDI passthrough, because: - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** -# info +## info -this chip uses the [FM (OPZ)](../4-instrument/opz.md) instrument editor. +this chip uses the [FM (OPZ)](../4-instrument/fm-opz.md) instrument editor. diff --git a/doc/7-systems/pce.md b/doc/7-systems/pce.md index 308d42e46..ec6633c3e 100644 --- a/doc/7-systems/pce.md +++ b/doc/7-systems/pce.md @@ -1,13 +1,13 @@ # PC Engine/TurboGrafx-16 a console from NEC that, depending on a region: -- attempted to enter the fierce battle between Nintendo and Sega, but because its capabilities are a mix of third and fourth generation, it failed to last long. (US and Europe) -- was Nintendo's most fearsome rival, completely defeating Sega Mega Drive and defending itself against Super Famicom (Japan) +- attempted to enter the fierce battle between Nintendo and Sega, but because its capabilities are a mix of third and fourth generation, it failed to last long (US and Europe), or +- was Nintendo's most fearsome rival, completely defeating Sega Mega Drive and defending itself against Super Famicom (Japan). it has 6 wavetable channels and the last two ones also double as noise channels. furthermore, it has some PCM and LFO! -# effects +## effects - `10xx`: **change wave.** - `11xx`: **toggle noise mode.** only available in the last two channels. @@ -21,6 +21,6 @@ furthermore, it has some PCM and LFO! - `17xx`: **toggle LEGACY sample mode.** - **this effect exists only for compatibility reasons! its use is NOT recommented. use Sample type instruments instead.** -# info +## info -this chip uses the [PC Engine](../4-instrument/pce.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [PC Engine](../4-instrument/pce.md) instrument editor. diff --git a/doc/7-systems/pcspkr.md b/doc/7-systems/pcspkr.md index d84181bfe..23009f915 100644 --- a/doc/7-systems/pcspkr.md +++ b/doc/7-systems/pcspkr.md @@ -1,8 +1,8 @@ # PC Speaker -40 years of one square beep - and still going! Single channel, no volume control... +40 years of one square beep - and still going! single channel, no volume control... -# real output +## real output so far this is the only chip in Furnace which has a real hardware output option. to enable it, select file > configure chip... > PC Speaker > Use system beeper. @@ -26,10 +26,10 @@ you may configure the output method by going in Settings > Emulation > PC Speake real hardware output only works on BIOS/UEFI (non-Mac) x86-based machines! attempting to do this under any other device **will not work**, or may even brick the device (if using `/dev/port` or `outb()`)! oh, and of course you also need the beeper to be present in your machine. some laptops connect the beeper output to the built-in speakers (or the audio output jack), and some other don't do this at all. -# effects +## effects ha! effects... -# info +## info this chip uses the [Beeper](../4-instrument/beeper.md) instrument editor. diff --git a/doc/7-systems/pet.md b/doc/7-systems/pet.md index e99e17925..472bb2ec8 100644 --- a/doc/7-systems/pet.md +++ b/doc/7-systems/pet.md @@ -6,10 +6,11 @@ maybe no better than a computer terminal, but somebody discovered a way to updat some of these didn't even have sound... -# effects +## effects -- `10xx`: **set waveform.** `xx` is a bitmask. +- `10xx`: **set waveform.** + - `xx` is a bitmask. -# info +## info this chip uses the [PET](../4-instrument/pet.md) instrument editor. diff --git a/doc/7-systems/pokemini.md b/doc/7-systems/pokemini.md index 7633f27a2..49e6cfbc3 100644 --- a/doc/7-systems/pokemini.md +++ b/doc/7-systems/pokemini.md @@ -2,10 +2,10 @@ the Pokémon Mini is a ridiculously small handheld system from 2001. its single pulse channel has only three volume steps (full, half, and off)... but variable pulse width. -# effects +## effects none. -# info +## info -this chip uses the [Pokémon Mini/QuadTone](../4-instrument/quadtone.md) instrument editor. +this chip uses the [Pokémon Mini/QuadTone](../4-instrument/pokemini.md) instrument editor. diff --git a/doc/7-systems/pokey.md b/doc/7-systems/pokey.md index 31832e580..eff37cd8c 100644 --- a/doc/7-systems/pokey.md +++ b/doc/7-systems/pokey.md @@ -2,7 +2,7 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400, 800, XL/XE and so on). 4 channels of signature Atari sounds. -# effects +## effects - `10xx`: **set waveform.** - 0: harsh noise (poly5+17) @@ -36,6 +36,6 @@ a sound and input chip developed by Atari for their 8-bit computers (Atari 400, - when enabled, channel 2 modulates channel 1. I don't know how, but it does. - only on ASAP core. -# info +## info this chip uses the [POKEY](../4-instrument/pokey.md) instrument editor. diff --git a/doc/7-systems/pv1000.md b/doc/7-systems/pv1000.md index 97cb617b5..1031af815 100644 --- a/doc/7-systems/pv1000.md +++ b/doc/7-systems/pv1000.md @@ -2,10 +2,12 @@ released only in Japan, this console was pulled after only a few weeks on the market. it has only 3 square waves with 6-bit pitch resolution and no bass. -# effects +## effects -- `10xx`: **set ring modulation.** amplitude modulation by the previous channel's output. `0` turns it off and `1` turns it on. +- `10xx`: **set ring modulation.** + - amplitude modulation by the previous channel's output. + - `0` turns it off and `1` turns it on. -# info +## info this chip uses the [PV-1000](../4-instrument/pv1000.md) instrument editor. diff --git a/doc/7-systems/qsound.md b/doc/7-systems/qsound.md index 6aa57d365..5534f18ae 100644 --- a/doc/7-systems/qsound.md +++ b/doc/7-systems/qsound.md @@ -4,20 +4,21 @@ this chip was used in Capcom's CP System Dash, CP System II and ZN arcade PCBs. it supports 16 PCM channels and uses the patented (now expired) QSound stereo expansion algorithm, as the name implies. -because the chip lacks sample interpolation, it is recommended that you try to play samples at around 24038 Hz to avoid aliasing. this is especially important for e.g. cymbals. +because the chip lacks sample interpolation, it is recommended that you try to play samples at around 24038Hz to avoid aliasing. this is especially important for e.g. cymbals. the QSound chip also has a small echo buffer, somewhat similar to the SNES, although with a very basic (and non-adjustable) filter. it is however possible to adjust the feedback and length of the echo buffer (the initial values can be set in the "configure chip" option in the file menu or the chip manager). -there are also 3 ADPCM channels. ADPCM samples are fixed to 8012 Hz. +there are also 3 ADPCM channels. ADPCM samples are fixed to 8012Hz. -# effects +## effects - `10xx`: **set echo feedback level.** - this effect will apply to all channels. - `11xx`: **set echo level.** -- `12xx`: **toggle QSound algorithm.** on by default. +- `12xx`: **toggle QSound algorithm.** + - on by default. - `3xxx`: **set echo delay buffer length.** -# info +## info -this chip uses the [QSound](../4-instrument/qsound.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [QSound](../4-instrument/qsound.md) instrument editor. diff --git a/doc/7-systems/ricoh.md b/doc/7-systems/ricoh.md index 1c3695cad..6f406ccd8 100644 --- a/doc/7-systems/ricoh.md +++ b/doc/7-systems/ricoh.md @@ -1,11 +1,11 @@ # Ricoh RF5C68 -YM2612's sidekick - poor man's SNES DSP. 8-channel PCM sample-based synthesizer used in Sega CD, Fujitsu FM Towns and some of Sega's arcade machines. supports up to 64KB of external PCM data. +YM2612's sidekick - poor man's SNES DSP. 8-channel PCM sample-based synthesizer used in Sega CD, Fujitsu FM Towns and some of Sega's arcade machines. supports up to 64KB of sample data. -# effects +## effects none so far. -# info +## info -this chip uses the [RF5C68](../4-instrument/ricoh.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [RF5C68](../4-instrument/rf5c68.md) instrument editor. diff --git a/doc/7-systems/saa1099.md b/doc/7-systems/saa1099.md index 8036ec71e..7284b563c 100644 --- a/doc/7-systems/saa1099.md +++ b/doc/7-systems/saa1099.md @@ -4,7 +4,7 @@ this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY- - an instrument with envelope settings is placed on channel 2 or channel 5 - an instrument that is used as an "envelope output" is placed on channel 3 or channel 6 (you may want to disable wave output on the output channel) -# effects +## effects - `10xy`: **set channel mode.** - `x` toggles noise. @@ -28,6 +28,6 @@ this was used by the Game Blaster and SAM Coupé. it's pretty similar to the AY- - bit 0 sets whether the right output will mirror the left one. - this effect affects either the first 3 or last 3 channels, depending on where it is placed. -# info +## info this chip uses the [SAA1099](../4-instrument/saa.md) instrument editor. diff --git a/doc/7-systems/scc.md b/doc/7-systems/scc.md index 8e5b01475..9ad30cf94 100644 --- a/doc/7-systems/scc.md +++ b/doc/7-systems/scc.md @@ -6,10 +6,10 @@ it was used in (of course) several Konami games, which had better audio quality the only problem? the waveform of the fourth channel is shared with the fifth one due to not enough memory in the chip! the SCC+ fixes this issue though (while being compatible with SCC games). -# effects +## effects - `10xx`: **change wave.** -# info +## info this chip uses the [Konami SCC/Bubble System WSG](../4-instrument/scc.md) instrument editor. diff --git a/doc/7-systems/segapcm.md b/doc/7-systems/segapcm.md index 296f2a884..9e8b7783e 100644 --- a/doc/7-systems/segapcm.md +++ b/doc/7-systems/segapcm.md @@ -6,16 +6,16 @@ yep, that's right! 16 channels of PCM! a chip used in the Sega OutRun/X/Y arcade boards. eventually the MultiPCM surpassed it with 28 channels, and later they joined the software mixing gang. -# 5-channel SegaPCM +## 5-channel SegaPCM Furnace also has a five channel version of this chip, but it only exists for DefleMask compatibility reasons (which doesn't expose the other channels for rather arbitrary reasons). -# effects +## effects - `20xx`: **set PCM frequency.** - `xx` is a 256th fraction of 31250Hz. - this effect exists mostly for DefleMask compatibility; it is otherwise recommended to use Sample type instruments. -# info +## info -this chip uses the [SegaPCM](../4-instrument/segapcm.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [SegaPCM](../4-instrument/segapcm.md) instrument editor. diff --git a/doc/7-systems/sm8521.md b/doc/7-systems/sm8521.md index c29ff79ae..2e0e8dc5c 100644 --- a/doc/7-systems/sm8521.md +++ b/doc/7-systems/sm8521.md @@ -2,11 +2,11 @@ the SM8521 is the CPU and sound chip of the Game.com, a handheld console released in 1997 as a competitor to the infamous Nintendo Virtual Boy. -ultimately, most of the games for the Game.com ended up being failures in the eyes of reviewers, thus giving the Game.com a pretty bad reputation. this was one of the reasons that the Game.com only ended up selling at least 300,000 units. for these reasons and more, the Game.com ended up being discontinued in 2000. +sadly, the Game.com ended up being a failure as well, mostly due to poor quality games. the Game.com only lasted 3 years before being discontinued. -however, for its time, it was a pretty competitively priced system. the Gameboy Color was to be released in a year for $79.95, while the Game.com was released for $69.99, and its later model, the Pocket Pro, was released in mid-1999 for $29.99 due to the Game.com's apparent significant decrease in value. +however, for its time, it was a pretty competitively priced system. the Game Boy Color was to be released in a year for $79.95, while the Game.com was released for $69.99; its later model, the Pocket Pro, was released in mid-1999 for $29.99 due to the Game.com's apparent significant decrease in value. -in fact, most games never used the wavetable/noise mode of the chip. sonic Jam, for example, uses a sine wave with a software-controlled volume envelope on the DAC channel (see below for more information on the DAC channel). +in fact, most games never used the wavetable/noise mode of the chip. Sonic Jam, for example, uses a sine wave with a software-controlled volume envelope on the DAC channel (see below for more information on the DAC channel). the sound-related features and quirks of the SM8521 are as follows: - 2 4-bit wavetable channels @@ -15,13 +15,13 @@ the sound-related features and quirks of the SM8521 are as follows: - a low bit-depth output (which means it distorts a lot). - it phase resets when you switch waves - 12-bit pitch with a wide frequency range -- a software-controlled D/A register that (potentially) requires all other registers to be stopped to play. due to this, it is currently not implemented in Furnace as of version 0.6pre4. +- a software-controlled D/A register that (potentially) requires all other registers to be stopped to play. due to this, it is currently not implemented in Furnace. -## effect commands +## effects - `10xx`: **set waveform.** - `xx` is a value between 0 and 255 that sets the waveform of the channel you place it on. -# info +## info this chip uses the [SM8521](../4-instrument/sm8521.md) instrument editor. diff --git a/doc/7-systems/sms.md b/doc/7-systems/sms.md index e4fe22317..576311596 100644 --- a/doc/7-systems/sms.md +++ b/doc/7-systems/sms.md @@ -1,12 +1,26 @@ # TI SN76489 (e.g. Sega Master System) -a relatively simple sound chip made by Texas Instruments. a derivative of it is used in Sega's Master System, the predecessor to Genesis. It has three square wave channels and one noise channel... not really. +a relatively simple sound chip made by Texas Instruments. a derivative of it is used in Sega's Master System, the predecessor to Genesis. it has three square wave channels and one noise channel... not really. -Nominal mode of SN76489 has 3 quare wave channels, with noise channel having only 3 preset frequencies to use (absurdly low, very low, low). To use more pitches, one can enable mode, which "steals" pitch data from square wave channel 3. By doing that, SN76489 becomes effectively a 3 channel sound chip. In addition, periodic noise mode can be enabled, with same caveats. +nominal mode of SN76489 has 3 square wave channels, with noise channel having only 3 preset frequencies to use (absurdly low, very low, low). to use more pitches, one can enable a mode which "steals" the frequency from square wave channel 3. by doing that, SN76489 becomes effectively a 3 channel sound chip. in addition, periodic noise mode can be enabled, with same caveats. -the original iteration of the SN76489 used in the TI-99/4A computer, the SN94624, could only produce tones as low as 100Hz, and was clocked at 447 KHz. all later versions (such as the one in the Master System and Genesis) had a clock divider but ran on a faster clock... except for the SN76494, which can play notes as low as 13.670 Hz (A -1). consequently, its pitch accuracy for higher notes is compromised. +the original iteration of the SN76489 used in the TI-99/4A computer, the SN94624, could only produce tones as low as 100Hz, and was clocked at 447 KHz. all later versions (such as the one in the Master System and Genesis) had a clock divider but ran on a faster clock... except for the SN76494, which can play notes as low as 13670 Hz (A -1). as a result, its pitch accuracy for higher notes is compromised. -# effects +## SN7 versions + +SN7 was extremely popular due to low cost. therefore, it was cloned and copied to no end, often with minor differences between each other. Furnace supports several of these: +- SN94624, can only produce tones as low as 100Hz, and is clocked at 447 KHz. +- SN76494, which can play notes as low as 13.670 Hz (A -1). it has a different noise feedback and invert masks. +- SN76489, identical to SN94624, just without a clock divider. +- SN76489A, identical to 76494, just with a /8 clock divider. +- SN76496, literally identical to former. why is it even here? +- SN76496 with a Atari-like short noise. the chip of many legend and rumours which may be a result of inaccurate emulation. +- Sega Master System VDP version has a different, characteristic noise LFSR. +- Game Gear SN7, identical to the above, but with stereo. +- NCR8496, different noise invert mask. +- PSSJ3, literally identical to the former. it just swaps "high" and "low" signals in the output, which results in no audible difference. + +## effects - `20xy`: **set noise mode.** - `x` controls whether to inherit frequency from channel 3. @@ -17,22 +31,6 @@ the original iteration of the SN76489 used in the TI-99/4A computer, the SN94624 - `1`: noise. -# info +## info this chip uses the [SN76489/Sega PSG](../4-instrument/psg.md) instrument editor. - - -## SN7 versions -SN7 was extremely popular due to low cost. Therefore, it was cloned and copied to no end, often with minor differences between each other. Furnace supports several of these: -- SN94624, can only produce tones as low as 100Hz, and is clocked at 447 KHz. -- SN76494, which can play notes as low as 13.670 Hz (A -1). It has a different noise feedback and invert masks. -- SN76489, identical to SN94624, just without a clock divider -- SN76489A, identical to 76494, just with a /8 clock divider -- SN76496, literally identical to former. Why is it even here? -- SN76496 with a Atari-like short noise. The chip of many legend and rumours, might be a result of inaccurate emulation. -- Sega Master System VDP version has a different, characteristic noise LFSR. -- Game Gear SN7, identical to the above, but with stereo -- NCR8496, different noise invert masks -- PSSJ3, literally identical to the former, it just swaps "high" and "low" signals in the output, which results in no audible difference - -TODO: all these checkboxes diff --git a/doc/7-systems/snes.md b/doc/7-systems/snes.md index 9c57d7526..cf518a0d9 100644 --- a/doc/7-systems/snes.md +++ b/doc/7-systems/snes.md @@ -8,7 +8,7 @@ this whole system itself is pretty much a separate computer that the main CPU ne Furnace communicates with the DSP directly and provides a full 64KB of memory. this memory might be reduced excessively on ROM export to make up for playback engine and pattern data. you can go to window > statistics to see how much memory your samples are using. some notable features of the DSP are: -- pitch modulation, meaning that you can use 2 channels to make a basic FM synth without eating up too much memory. +- pitch modulation. - a built in noise generator, useful for hi-hats, cymbals, rides, effects, among other things. - per-channel echo, which unfortunately eats up a lot of memory but can be used to save channels in songs. - an 8-tap FIR filter for the echo, which is basically a procedural low-pass filter that you can edit however you want. @@ -18,9 +18,9 @@ some notable features of the DSP are: - 7-bit volume per channel. - sample interpolation, which is basically a low-pass filter that gets affected by the pitch of the channel. -Furnace also allows the SNES to use wavetables (and the wavetable synthesizer) in order to create more 'animated' sounds, using less memory than regular samples. this however is not a hardware feature, and might be difficult to implement on real hardware. +Furnace also allows the SNES to use wavetables (and the wavetable synthesizer) in order to create more 'animated' sounds, using less memory than regular samples. -# effects +## effects - `10xx`: **set waveform.** - `11xx`: **toggle noise mode.** @@ -37,37 +37,31 @@ Furnace also allows the SNES to use wavetables (and the wavetable synthesizer) i - `16xx`: **set gain.** `00` to `7F` if direct, `00` to `1F` otherwise. - `18xx`: **enable echo buffer.** - `19xx`: **set echo delay.** range is `0` to `F`. -- `1Axx`: **set left echo channel volume.**\ - `1Bxx`: **set right echo channel volume.**\ - `1Cxx`: **set echo feedback.** +- `1Axx`: **set left echo channel volume.** +- `1Bxx`: **set right echo channel volume.** +- `1Cxx`: **set echo feedback.** - all of these are signed numbers. - `00` to `7F` for 0 to 127. - `80` to `FF` for -128 to -1. - - setting these to -128 is not recommended as it may cause echo output to overflow and therefore click. + - setting these to -128 is not recommended as it may cause echo output to overflow and therefore click. - `1Dxx`: **set noise generator frequency.** range is `00` to `1F`. see noise frequencies chart below. -- `1Exx`: **set left dry / global volume.**\ - `1Fxx`: **set right dry / global volume.** +- `1Exx`: **set left dry / global volume.** +- `1Fxx`: **set right dry / global volume.** - these do not affect echo. -- `20xx`: **set attack.** range is `0` to `F`.\ - `21xx`: **set decay.** range is `0` to `7`.\ - `22xx`: **set sustain.** range is `0` to `7`.\ - `23xx`: **set release.** range is `00` to `1F`. +- `20xx`: **set attack.** range is `0` to `F`. +- `21xx`: **set decay.** range is `0` to `7`. +- `22xx`: **set sustain.** range is `0` to `7`. +- `23xx`: **set release.** range is `00` to `1F`. - these four are only used in ADSR envelope mode. see ADSR chart below. -- `30xx`: **set echo filter coefficient 0.**\ - `31xx`: **set echo filter coefficient 1.**\ - `32xx`: **set echo filter coefficient 2.**\ - `33xx`: **set echo filter coefficient 3.**\ - `34xx`: **set echo filter coefficient 4.**\ - `35xx`: **set echo filter coefficient 5.**\ - `36xx`: **set echo filter coefficient 6.**\ - `37xx`: **set echo filter coefficient 7.** - - all of these are signed numbers. - - `00` to `7F` for 0 to 127. - - `80` to `FF` for -128 to -1. - - _Note:_ Be sure the sum of all coefficients is between -128 and 127. sums outside that may result in overflow and therefore clicking. +- `3xyy`: **set echo filter coefficient.** + - `x` is the coefficient from 0 to 7. + - `yy` is the value (signed number). + - `00` to `7F` for 0 to 127. + - `80` to `FF` for -128 to -1. + - note: be sure the sum of all coefficients is between -128 and 127. sums outside that may result in overflow and therefore clicking. - see [SnesLab](https://sneslab.net/wiki/FIR_Filter) for a full explanation and examples. -# info +## info this chip uses the [SNES](../4-instrument/snes.md) instrument editor. @@ -173,8 +167,6 @@ value | freq. | value | freq. reference: [Super Famicom Development Wiki](https://wiki.superfamicom.org/spc700-reference#dsp-register:-flg-1318) - - -# resources +## resources - [SNES-format BRR samples](https://www.smwcentral.net/?p=stion&s=brrsamples) at SMW Central diff --git a/doc/7-systems/soundunit.md b/doc/7-systems/soundunit.md index 00706c0f1..3bf13a136 100644 --- a/doc/7-systems/soundunit.md +++ b/doc/7-systems/soundunit.md @@ -12,7 +12,7 @@ it has the following capabilities: - volume, frequency and cutoff sweep units (per-channel) - phase reset timer (per-channel) -# effects +## effects - `10xx`: **set waveform.** - `0`: pulse wave @@ -55,6 +55,6 @@ it has the following capabilities: - bit 7: up direction - `4xxx`: **set cutoff.** range is `0` to `FFF`. -# info +## info -this chip uses the [Sound Unit](../4-instrument/soundunit.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [Sound Unit](../4-instrument/su.md) instrument editor. diff --git a/doc/7-systems/t6w28.md b/doc/7-systems/t6w28.md index 26d7d977c..5d6af1871 100644 --- a/doc/7-systems/t6w28.md +++ b/doc/7-systems/t6w28.md @@ -4,12 +4,12 @@ an enhanced SN76489 derivative. same 4 channels, but with stereo (soft panning!) this chip was used in Neo Geo Pocket. -# effects +## effects - `20xx`: **set noise mode.** - `0`: thin pulse. - `1`: noise. -# info +## info this chip uses the [T6W28](../4-instrument/t6w28.md) instrument editor. diff --git a/doc/7-systems/ted.md b/doc/7-systems/ted.md index 4333fcea6..d9cbca996 100644 --- a/doc/7-systems/ted.md +++ b/doc/7-systems/ted.md @@ -5,10 +5,10 @@ also called 7360/8360, TED stands for Text Editing Device. it's both a video and its audio portion is pretty barren - only 2 channels. one can output square wave and other may be either square or noise. pitch range is limited as well, akin to that of SN76489, and volume control is global. -# effects +## effects none so far. -# info +## info this chip uses the [TED](../4-instrument/ted.md) instrument editor. diff --git a/doc/7-systems/tia.md b/doc/7-systems/tia.md index 9e6d9cfa6..6d95c8ae2 100644 --- a/doc/7-systems/tia.md +++ b/doc/7-systems/tia.md @@ -7,7 +7,7 @@ only 2 channels and 31 frequencies?! Furnace isn't complete without this one... -# effects +## effects - `10xx`: **select shape.** - `0`: nothing @@ -29,14 +29,13 @@ Furnace isn't complete without this one... -# info +## info this chip uses the [TIA](../4-instrument/tia.md) instrument editor. +the arp macro's fixed mode operates differently, writing the direct pitch to the chip. here's a list of pitches. -- pitch number can be used for absolute notes in arpeggio macros. - -## shape 1 +### shape 1 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -73,7 +72,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 67.6 | C#2 | -44 | 67.1 | C-2 | +44 | 31 | 65.5 | C-2 | +3 | 65.0 | C-2 | -11 -## shapes 2, 3 +### shapes 2 and 3 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -110,7 +109,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 2.2 | | | 2.2 | 31 | 2.1 | | | 2.1 -## shapes 4, 5 +### shapes 4 and 5 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -147,7 +146,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 507.1 | B-4 | +45 | 503.2 | B-4 | +32 | 31 | 491.3 | B-4 | -9 | 487.5 | B-4 | -23 -## shapes 6, 7, 9, 10 +### shapes 6, 7, 9 and 10 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -184,7 +183,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 32.7 | C-1 | 0.0 | 32.5 | C-1 | -11 | 31 | 31.7 | B-0 | +44 | 31.5 | B-0 | +33 -## shape 8 +### shape 8 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -221,7 +220,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 2.0 | | | 2.0 | 31 | 1.9 | | | 1.9 -## shapes 12, 13 +### shapes 12 and 13 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -258,7 +257,7 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 169.0 | E-3 | +43 | 167.7 | E-3 | +30 | 31 | 163.8 | E-3 | -11 | 162.5 | E-3 | -25 -## shapes 14, 15 +### shapes 14 and 15 | pitch | NTSC | note | cent | PAL | note | cent |------:|--------:|:----:|-----:|--------:|:----:|-----: @@ -295,4 +294,4 @@ this chip uses the [TIA](../4-instrument/tia.md) instrument editor. | 30 | 10.9 | | | 10.8 | 31 | 10.6 | | | 10.5 -reference: [Atari 2600 VCS Sound Frequency and Waveform Guide](http://7800.8bitdev.org/index.php/Atari_2600_VCS_Sound_Frequency_and_Waveform_Guide) \ No newline at end of file +reference: [Atari 2600 VCS Sound Frequency and Waveform Guide](http://7800.8bitdev.org/index.php/Atari_2600_VCS_Sound_Frequency_and_Waveform_Guide) diff --git a/doc/7-systems/vera.md b/doc/7-systems/vera.md index d4189412a..98de3b440 100644 --- a/doc/7-systems/vera.md +++ b/doc/7-systems/vera.md @@ -1,21 +1,22 @@ # VERA -this is a video and sound generator chip used in the Commander X16, a modern 8-bit computer created by The 8-Bit Guy. +this is a video and sound generator chip used in the Commander X16, a modern 8-bit computer created by the 8-Bit Guy. it has 16 channels of pulse/triangle/saw/noise and one stereo PCM channel. currently Furnace does not support the PCM channel's stereo mode, though (except for panning). -# effects +## effects - `20xx`: **set waveform.** - `0`: pulse - `1`: saw - `2`: triangle - `3`: noise -- `22xx`: **set duty cycle.** range is `0` to `3F`. +- `22xx`: **set duty cycle.** + - range is `0` to `3F`. - `EExx`: **ZSM synchronization event.** - - Where `xx` is the event payload. This has no effect in how the music is played in Furnace, but the ZSMKit library for the Commander X16 interprets these events inside ZSM files and optionally triggers a callback routine. This can be used, for instance, to cause game code to respond to beats or at certain points in the music. + - `xx` is the event payload. this has no effect in how the music is played in Furnace, but the ZSMKit library for the Commander X16 interprets these events inside ZSM files and optionally triggers a callback routine. this can be used, for instance, to cause game code to respond to beats or at certain points in the music. -# info +## info -this chip uses the [VERA](../4-instrument/vera.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [VERA](../4-instrument/vera.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. diff --git a/doc/7-systems/vic20.md b/doc/7-systems/vic20.md index 6d5a9bd41..064ce233f 100644 --- a/doc/7-systems/vic20.md +++ b/doc/7-systems/vic20.md @@ -1,6 +1,6 @@ # Commodore VIC-20 -the Commodore VIC-20 was Commodore's major attempt at making a personal home computer, and is the percursor to the Commodore 64. +the Commodore VIC-20 was Commodore's major attempt at making a personal home computer, and is the precursor to the Commodore 64. it was also known as the VC-20 in Germany, and the VIC-1001 in Japan. @@ -17,6 +17,6 @@ these channels are not referred as "square" wave channels since a technique to p - `10xx`: **switch waveform.** range is `00` to `0F`. -# info +## info this chip uses the [VIC](../4-instrument/vic.md) instrument editor. diff --git a/doc/7-systems/virtual-boy.md b/doc/7-systems/virtual-boy.md index 8dc11da98..6aa260188 100644 --- a/doc/7-systems/virtual-boy.md +++ b/doc/7-systems/virtual-boy.md @@ -8,7 +8,7 @@ its sound generation chip is called Virtual Sound Unit (VSU), a wavetable chip t additionally, channel 5 offers a modulation/sweep unit. the former is similar to FDS' but has much reduced speed control. -# effects +## effects - `10xx`: **set waveform.** - `11xx`: **set noise length.** range is `0` to `7`. @@ -42,6 +42,6 @@ additionally, channel 5 offers a modulation/sweep unit. the former is similar to - `xx` points to a wavetable. range is `0` to `FF`. - this is an alternative to setting the modulation wave through the instrument. -# info +## info this chip uses the [Virtual Boy](../4-instrument/virtual-boy.md) instrument editor. diff --git a/doc/7-systems/vrc6.md b/doc/7-systems/vrc6.md index ba6df1d2a..00dcbc7f3 100644 --- a/doc/7-systems/vrc6.md +++ b/doc/7-systems/vrc6.md @@ -10,7 +10,7 @@ for that reason, the sawtooth channel has its own instrument type. setting volum pulse wave duty cycle is 8-level. it can be ignored and it has potential for DAC at this case: volume register in this mode is DAC output and it can be PCM playback through this mode. Furnace supports this routine for PCM playback, but it consumes a lot of CPU time in real hardware (even if conjunction with VRC6's integrated IRQ timer). -# effects +## effects these effects only are effective in the pulse channels. @@ -18,6 +18,6 @@ these effects only are effective in the pulse channels. - `17xx`: **toggle LEGACY sample mode.** - **this effect exists only for compatibility reasons! its use is NOT recommented. use Sample type instruments instead.** -# info +## info -this chip uses the [VRC](../4-instrument/vrc6.md), [VRC (saw)](../4-instrument/vrc6.md), and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [VRC6](../4-instrument/vrc6.md) and [VRC6 (saw)](../4-instrument/vrc6.md) instrument editors. diff --git a/doc/7-systems/wonderswan.md b/doc/7-systems/wonderswan.md index e386461b7..edd189649 100644 --- a/doc/7-systems/wonderswan.md +++ b/doc/7-systems/wonderswan.md @@ -8,18 +8,19 @@ it has 4 wavetable channels. some of them have additional capabilities: - the third one has hardware sweep - the fourth one also does noise -# effects +## effects - `10xx`: **change wave**. - `11xx`: **setup noise mode.** channel 4 only. - 0: disable. - - 1-8: enable and set tap preset. + - 1-8: enable and set length. - `12xx`: **setup sweep period.** channel 3 only. - 0: disable. - 1-32: enable and set period. - `13xx`: **setup sweep amount.** channel 3 only. -- `17xx`: **toggle PCM mode.** channel 2 only. + - `00` to `7F` for 0 to 127. + - `80` to `FF` for -128 to -1. -# info +## info -this chip uses the [WonderSwan](../4-instrument/wonderswan.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [WonderSwan](../4-instrument/wonderswan.md) instrument editor. diff --git a/doc/7-systems/x1-010.md b/doc/7-systems/x1-010.md index e4836cf8f..8ac56a230 100644 --- a/doc/7-systems/x1-010.md +++ b/doc/7-systems/x1-010.md @@ -1,29 +1,19 @@ # Seta/Allumer X1-010 -a sound chip designed by Seta, mainly used in their own arcade hardware from the late 80s to the early 2000s. -it has 2 output channels, but there is no known hardware taking advantage of stereo sound capabilities. -later hardware paired this with external bankswitching logic, but this isn't emulated yet. -Allumer rebadged it for their own arcade hardware. +the X1-010 is a chip used by Seta (and Allumer) in the Seta 1 and 2 arcade boards. -it has 16 channels, which can all be switched between PCM sample or wavetable playback mode. -wavetable playback needs to paired with envelope, similar to AY PSG, but shapes are stored in RAM and as such are user-definable. +it has 16 channels of wavetable sound with some support for 8-bit samples up to 128KB in length. +the sample frequency resolution is pretty bad in the low end though... -in Furnace, this chip can be configured for original arcade mono output or stereo output - it simulates early 'incorrect' emulation on some mono hardware, but it is also based on the assumption that each channel is connected to each output. +even though this chip has stereo output, no board (as far as we know) uses the two outputs that it has... instead, only one output is connected, effectively being used as a mono chip. -# waveform types +the chip also has some (complicated) hardware volume envelope capabilities, with half of its memory being usable for that purpose. the shape of a volume envelope is defined by user-provided 128×16 waveforms. -this chip supports 2 types of waveforms, needs to be paired to external 8 KB RAM to access these features: +the chip can store up to 32 sound waveforms and envelope waveforms at once. -one is a signed 8 bit mono waveform, operated like other wavetable based sound systems. -these are stored at the lower half of RAM at common case. +this chip was the inspiration for Organya/PxTone (the former being used in a well-known game called Cave Story). -the other one ("Envelope") is a 4 bit stereo waveform, multiplied with the above and calculates final output, each nibble is used for each output channel. -these are stored at the upper half of RAM at common case. - -both waveforms are 128 bytes (fixed size), freely allocated at each half of RAM except the channel register area: each half can store total 32/31 waveforms at once. -in Furnace, you can enable the envelope shape split mode. when it is set, its waveform will be split to the left and right halves for each output. each max size is 128 bytes, total 256 bytes. - -# effects +## effects - `10xx`: **change wave.** - `11xx`: **change envelope shape.** also wavetable. @@ -34,8 +24,8 @@ in Furnace, you can enable the envelope shape split mode. when it is set, its wa - range is 1.95KHz to 498KHz if the chip clock is 16MHz. - `22xx`: **set envelope mode.** - bit 0 sets whether envelope will affect this channel. - - bit 1 toggles the envelope one-shot mode. when it is set, channel is halted after envelope cycle is finished. - - bit 2 toggles the envelope shape split mode. when it is set, envelope shape will be split to left half and right half. + - bit 1 sets whether envelope will run once instead of looping. + - bit 2 sets whether split mode is used. I don't know what it does. - bit 3/5 sets whether the right/left shape will mirror the original one. - bit 4/6 sets whether the right/left output will mirror the original one. - `23xx`: **set envelope period.** @@ -47,6 +37,6 @@ in Furnace, you can enable the envelope shape split mode. when it is set, its wa - `y` is the denominator. - if `x` or `y` are 0 this will disable auto-envelope mode. -# info +## info -this chip uses the [X1-010](../4-instrument/x1_010.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [X1-010](../4-instrument/x1_010.md) instrument editor. diff --git a/doc/7-systems/ym2151.md b/doc/7-systems/ym2151.md index 58b4fd1f7..4c6fce90c 100644 --- a/doc/7-systems/ym2151.md +++ b/doc/7-systems/ym2151.md @@ -1,12 +1,12 @@ # Yamaha YM2151 -the sound chip powering several arcade boards, the Sharp X1/X68000 and the Commander X16. eight 4-op FM channels, with overpowered LFO and almost unused noise generator. +the sound chip powering several arcade boards, synthesizers and the Sharp X1/X68000. eight 4-op FM channels, with overpowered LFO and almost unused noise generator. it also was present on several pinball machines and synthesizers of the era, and later surpassed by the YM2414 (OPZ) present in the world-famous TX81Z. -in most arcade boards the chip was used in combination with a PCM chip, like [SegaPCM](segapcm.md) or [OKI's line of ADPCM chips](oki.md). +in most arcade boards the chip was used in combination with a PCM chip, like [SegaPCM](segapcm.md) or [OKI's line of ADPCM chips](msm6295.md). -# effects +## effects - `10xx`: **set noise frequency of channel 8 operator 4.** `00` disables noise while `01` to `20` enables it. - `11xx`: **set feedback of channel.** @@ -16,7 +16,7 @@ in most arcade boards the chip was used in combination with a PCM chip, like [Se - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `17xx`: **set LFO speed.** - `18xx`: **set LFO waveform.** - `00`: saw @@ -69,6 +69,6 @@ in most arcade boards the chip was used in combination with a PCM chip, like [Se - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** -# info +## info this chip uses the [FM (OPM)](../4-instrument/fm-opm.md) instrument editor. diff --git a/doc/7-systems/ym2203.md b/doc/7-systems/ym2203.md index f8fd41fe9..b01d2a054 100644 --- a/doc/7-systems/ym2203.md +++ b/doc/7-systems/ym2203.md @@ -9,7 +9,7 @@ this chip was used in the NEC PC-88/PC-98 series of computers, the Fujitsu FM-7A several variants of this chip were released as well, with more features. -# effects +## effects - `11xx`: **set feedback of channel.** - `12xx`: **set operator 1 level.** @@ -18,7 +18,7 @@ several variants of this chip were released as well, with more features. - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator from 1 to 4. - - `y` is the multiplier. + - `y` is the new MULT value.. - `18xx`: **toggle extended channel 3 mode.** - `0` disables it and `1` enables it. - only in extended channel 3 chip. @@ -100,13 +100,14 @@ several variants of this chip were released as well, with more features. - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** +## extended channel 3 -# info +in ExtCh mode, channel 3 is split into one column for each of its four operators and feedback are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. + +all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. + +## info this chip uses the [FM (OPN)](../4-instrument/fm-opn.md) and [AY-3-8910/SSG](../4-instrument/ay8910.md) instrument editor. -## extended channel 3 -in ExtCh mode, channel 3 is split into one column for each of its four operators and feedback are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. - -all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. diff --git a/doc/7-systems/ym2608.md b/doc/7-systems/ym2608.md index 51ea15d90..27d5f1e06 100644 --- a/doc/7-systems/ym2608.md +++ b/doc/7-systems/ym2608.md @@ -6,7 +6,7 @@ it was one of the available sound chips for the NEC PC-88VA and later models of the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built-in drums have been replaced with 6 sample channels. -# effects +## effects - `10xy`: **set LFO parameters.** - `x` toggles the LFO. @@ -18,7 +18,7 @@ the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built- - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `18xx`: **toggle extended channel 3 mode.** - `0` disables it and `1` enables it. - only in extended channel 3 chip. @@ -100,13 +100,12 @@ the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built- - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** - -# info - -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/amiga.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - ## extended channel 3 + in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. + +## info + +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2610.md b/doc/7-systems/ym2610.md index b56df33d7..29a85675b 100644 --- a/doc/7-systems/ym2610.md +++ b/doc/7-systems/ym2610.md @@ -4,7 +4,7 @@ originally an arcade board, but SNK shortly adapted it to a rather expensive vid its soundchip is a 4-in-1: 4ch 4-op FM, YM2149 (AY-3-8910 clone) and [2 different format ADPCM](https://wiki.neogeodev.org/index.php?title=ADPCM) in a single package! -# effects +## effects - `10xy`: **set LFO parameters.** - `x` toggles the LFO. @@ -16,7 +16,7 @@ its soundchip is a 4-in-1: 4ch 4-op FM, YM2149 (AY-3-8910 clone) and [2 differen - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `18xx`: **toggle extended channel 2 mode.** - 0 disables it and 1 enables it. - only in extended channel 2 chip. @@ -98,12 +98,12 @@ its soundchip is a 4-in-1: 4ch 4-op FM, YM2149 (AY-3-8910 clone) and [2 differen - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** -# info - -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/amiga.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - ## extended channel 2 + in ExtCh mode, channel 2 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. + +## info + +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2610b.md b/doc/7-systems/ym2610b.md index a670cfc2c..5f15fb8e2 100644 --- a/doc/7-systems/ym2610b.md +++ b/doc/7-systems/ym2610b.md @@ -3,7 +3,7 @@ YM2610B is basically YM2610 with 2 extra FM channels used at some 90s Taito arcade hardware. it is backward compatible with the original chip. -# effects +## effects - `10xy`: **set LFO parameters.** - `x` toggles the LFO. @@ -15,7 +15,7 @@ it is backward compatible with the original chip. - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `18xx`: **toggle extended channel 3 mode.** - 0 disables it and 1 enables it. - only in extended channel 3 chip. @@ -97,13 +97,12 @@ it is backward compatible with the original chip. - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** -# info - -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [Generic Sample](../4-instrument/amiga.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md), and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. - - ## extended channel 3 in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. + +## info + +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md), [AY-3-8910/SSG](../4-instrument/ay8910.md), [ADPCM-A](../4-instrument/adpcm-a.md) and [ADPCM-B](../4-instrument/adpcm-b.md) instrument editors. diff --git a/doc/7-systems/ym2612.md b/doc/7-systems/ym2612.md index 7804984eb..dd5ba5502 100644 --- a/doc/7-systems/ym2612.md +++ b/doc/7-systems/ym2612.md @@ -1,9 +1,24 @@ # Yamaha YM2612 one of two chips that powered the Sega Genesis. it is a six-channel, four-operator FM synthesizer. channel #6 can be turned into 8-bit PCM player, that via software mixing, thanks to Z80 sound CPU, can play more than one channel of straight-shot samples at once. -as of Furnace 0.6pre5, Furnace offers DualPCM, a Z80 driver that splits channel 6 into two individual PCM channels with variable pitch. using the console's Z80 processor, these are mixed together in software and streamed to channel 6 in PCM mode with a mix rate of 13750 Hz. VGM export requires the "direct stream mode" option to be enabled, and resulting files will be very large. +Furnace also offers DualPCM, a Z80 driver that splits channel 6 into two individual PCM channels with variable pitch. using the console's Z80 processor, these are mixed together in software and streamed to channel 6 in PCM mode with a mix rate of 13750 Hz. VGM export requires the "direct stream mode" option to be enabled, and resulting files will be very large. -# effects +## extended channel 3 + +in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. + +all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. + +## CSM + +CSM is short for "Composite Sinusoidal Modeling". CSM works by sending key-on and key-off commands to channel 3 at a specific frequency, controlled by the added "CSM Timer" channel. this can be used to create vocal formants (speech synthesis!) or other complex effects. + +CSM is beyond the scope of this documentation. for more information, see this [brief SSG-EG and CSM video tutorial](https://www.youtube.com/watch?v=IKOR0TUlnWU). + +## DualPCM + +thanks to the Z80 sound CPU, DualPCM can play two samples at once! this mode splits channel 6 into two individual PCM channels with variable pitch. these are mixed together in software and streamed to channel 6 with a mix rate of 13750 Hz. VGM export requires the "direct stream mode" option to be enabled, and resulting files will be very large. +## effects - `10xy`: **set LFO parameters.** - `x` toggles the LFO. @@ -15,7 +30,7 @@ as of Furnace 0.6pre5, Furnace offers DualPCM, a Z80 driver that splits channel - `15xx`: **set operator 4 level.** - `16xy`: **set multiplier of operator.** - `x` is the operator (1-4). - - `y` is the multiplier. + - `y` is the new MULT value.. - `17xx`: **toggle LEGACY sample mode.** - this only works on channel 6. - **this effect exists only for compatibility reasons! its use is NOT recommented. use Sample type instruments instead.** @@ -68,23 +83,6 @@ as of Furnace 0.6pre5, Furnace offers DualPCM, a Z80 driver that splits channel - `5Exx`: **set D2R/SR of operator 3.** - `5Fxx`: **set D2R/SR of operator 4.** -# info +## info -this chip uses the [FM (OPN)](../4-instrument/fm-opn.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. - - -## extended channel 3 - -in ExtCh mode, channel 3 is split into one column for each of its four operators. feedback and LFO levels are shared. the frequency of each operator may be controlled independently with notes and effects. this can be used for more polyphony or more complex sounds. - -all four operators are still combined according to the algorithm in use. for example, algorithm 7 acts as four independent sine waves. algorithm 4 acts as two independent 2op sounds. even with algorithm 0, placing a note in any operator triggers that operator alone. - -## CSM - -CSM is short for "Composite Sinusoidal Modeling". CSM works by sending key-on and key-off commands to channel 3 at a specific frequency, controlled by the added "CSM Timer" channel. this can be used to create vocal formants (speech synthesis!) or other complex effects. - -CSM is beyond the scope of this documentation. for more information, see this [brief SSG-EG and CSM video tutorial](https://www.youtube.com/watch?v=IKOR0TUlnWU). - -## DualPCM - -thanks to the Z80 sound CPU, DualPCM can play two samples at once! this mode splits channel 6 into two individual PCM channels with variable pitch. these are mixed together in software and streamed to channel 6 with a mix rate of 13750 Hz. VGM export requires the "direct stream mode" option to be enabled, and resulting files will be very large. +this chip uses the [FM (OPN)](../4-instrument/fm-opn.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. diff --git a/doc/7-systems/ymu759.md b/doc/7-systems/ymu759.md index 956b37aca..268e08021 100644 --- a/doc/7-systems/ymu759.md +++ b/doc/7-systems/ymu759.md @@ -5,9 +5,9 @@ it is also known as MA-2. sadly Yamaha didn't care about these chips too much, and the register specs were completely unavailable, which means the YMU759 is totally unsupported and unemulated besides Yamaha's official emulator for it built into MidRadio. -Furnace 0.6 loads DefleMask modules written for this system; however, it doesn't support any of its effects and is simulated using the OPL core. +Furnace is able to load DefleMask modules written for this system; however, it doesn't support any of its effects and is simulated using the OPL core. -# effects +## effects since this chip is so abandoned, there isn't any support for it. @@ -16,6 +16,6 @@ even DefleMask dropped support for the chip in version 0.11, which just shows ho hey, at least it was the spark that ignited the idea of DefleMask. -# info +## info -this chip uses the [FM (OPL)](../4-instrument/fm-opl.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [FM (OPL)](../4-instrument/fm-opl.md) and [Generic Sample](../4-instrument/sample.md) instrument editors. diff --git a/doc/7-systems/ymz280b.md b/doc/7-systems/ymz280b.md index 982df8d25..6edc34251 100644 --- a/doc/7-systems/ymz280b.md +++ b/doc/7-systems/ymz280b.md @@ -4,10 +4,10 @@ it has 16-level stereo panning, up to 16-bit PCM and up to 16MB of external PCM data. -# effects +## effects none so far. -# info +## info -this chip uses the [YMZ280B](../4-instrument/ymz280b.md) and [Generic Sample](../4-instrument/amiga.md) instrument editors. +this chip uses the [YMZ280B](../4-instrument/ymz280b.md) instrument editor. diff --git a/doc/7-systems/zxbeep.md b/doc/7-systems/zxbeep.md index 183beb4fc..384b6e189 100644 --- a/doc/7-systems/zxbeep.md +++ b/doc/7-systems/zxbeep.md @@ -2,12 +2,12 @@ rather than having a dedicated sound synthesizer, early ZX Spectrum models had one piezo beeper, controlled by Z80 CPU and ULA chip. its capabilities should be on par with an IBM PC speaker... right? -not really - very soon talented programmers found out ways to output much more than one square wave channel. a lot of ZX beeper routines do exist, but as of 0.6 Furnace supports two engines: +not really - very soon talented programmers found out ways to output much more than one square wave channel. a lot of ZX beeper routines do exist, but Furnace only supports two engines: - a Follin/SFX-like engine with 6 channels of narrow pulse wave and click drums. - QuadTone: PWM-driven engine with 4ch of pulse wave with freely variable duty cycles and 1-bit PCM drums. -# effects +## effects - **`12xx`**: set pulse width. - **`17xx`**: trigger overlay drum. @@ -15,6 +15,6 @@ not really - very soon talented programmers found out ways to output much more t - overlay drums are 1-bit and always play at 55930Hz (NTSC) or 55420Hz (PAL). - the maximum length is 2048! -# info +## info -this chip uses the [Beeper](../4-instrument/beeper.md), [Generic Sample](../4-instrument/amiga.md), and [Pokémon Mini/QuadTone](../4-instrument/quadtone.md) instrument editors. +this chip uses the [Beeper](../4-instrument/beeper.md) or [Pokémon Mini/QuadTone](../4-instrument/pokemini.md) instrument editor. diff --git a/doc/8-advanced/channels.md b/doc/8-advanced/channels.md index 7bf4fbf72..a57698559 100644 --- a/doc/8-advanced/channels.md +++ b/doc/8-advanced/channels.md @@ -1,11 +1,12 @@ # channels -The "Channels" dialog allows manipulation of the song's channels. +the "Channels" dialog allows manipulation of the song's channels. ![channels dialog](channels.png) -Each channel has the following options: -- **Visible**: uncheck the box to hide the channel from view. Pattern data will be kept. -- Crossed-arrows button: Click and drag to rearrange pattern data throughout the song. _Note:_ This does _not_ move channels around within a chip! It only affects pattern data. +each channel has the following options: +- **Visible**: uncheck the box to hide the channel from view. pattern data will be kept. +- crossed-arrows button: click and drag to rearrange pattern data throughout the song. + - note: this does _not_ move channels around within a chip! it only affects pattern data. - **Name** is the name displayed at the top of each channel in the tracker view. -- To the right of that is the abbreviation used above each channel in the order view. \ No newline at end of file +- to the right of that is the abbreviation used above each channel in the order view. diff --git a/doc/8-advanced/channels.png b/doc/8-advanced/channels.png index e51815ebd..31afb7c6c 100644 Binary files a/doc/8-advanced/channels.png and b/doc/8-advanced/channels.png differ diff --git a/doc/8-advanced/chanosc-gradient.png b/doc/8-advanced/chanosc-gradient.png index cd255d523..0a413d266 100644 Binary files a/doc/8-advanced/chanosc-gradient.png and b/doc/8-advanced/chanosc-gradient.png differ diff --git a/doc/8-advanced/chanosc.md b/doc/8-advanced/chanosc.md index f58ae2960..b811add81 100644 --- a/doc/8-advanced/chanosc.md +++ b/doc/8-advanced/chanosc.md @@ -35,7 +35,7 @@ right-clicking within the view will change it to the configuration view shown ab - `%V`: volume (percentage) - `%b`: volume (hex) - `%%`: percent sign -- The OK button returns from options view to the oscilloscopes. +- the OK button returns from options view to the oscilloscopes. ## gradient @@ -49,13 +49,13 @@ in this mode, the color selector is replaced by a square field onto which circul - **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the target color. - **Background**: sets background color for entire field. -- **X Axis**: determines what the horizontal maps to, from left to right.\ - **Y Axis**: determines what the vertical maps to, from bottom to top. these can be set to the following: +- **X Axis**: determines what the horizontal maps to, from left to right. +- **Y Axis**: determines what the vertical maps to. from bottom to top. these can be set to the following: - **None (0%)**: stays at the left or bottom. - **None (50%)**: stays at the center. - **None (100%)**: stays at the right or top. - **Frequency**: changes color with note frequency. - **Volume**: changes color with volume. - **Channel**: changes color based on channel number. - - **Brightness**: {{document this}} + - **Brightness**: currently does nothing. - **Note Trigger**: changes color when a new note is played. diff --git a/doc/8-advanced/chanosc.png b/doc/8-advanced/chanosc.png index 2d05dbdf1..8128b1d8e 100644 Binary files a/doc/8-advanced/chanosc.png and b/doc/8-advanced/chanosc.png differ diff --git a/doc/8-advanced/chip-manager-change.png b/doc/8-advanced/chip-manager-change.png index 0def9180b..4e9a29f2c 100644 Binary files a/doc/8-advanced/chip-manager-change.png and b/doc/8-advanced/chip-manager-change.png differ diff --git a/doc/8-advanced/chip-manager-move.png b/doc/8-advanced/chip-manager-move.png index 022eae230..46925f76d 100644 Binary files a/doc/8-advanced/chip-manager-move.png and b/doc/8-advanced/chip-manager-move.png differ diff --git a/doc/8-advanced/chip-manager-remove.png b/doc/8-advanced/chip-manager-remove.png index aea34d9c4..3e80749d4 100644 Binary files a/doc/8-advanced/chip-manager-remove.png and b/doc/8-advanced/chip-manager-remove.png differ diff --git a/doc/8-advanced/chip-manager.md b/doc/8-advanced/chip-manager.md index 722f3a973..d0cb89943 100644 --- a/doc/8-advanced/chip-manager.md +++ b/doc/8-advanced/chip-manager.md @@ -1,15 +1,15 @@ # chip manager -The **chip manager** window does exactly what it says. +the **chip manager** window does exactly what it says. ![chip manager](chip-manager.png) -**Preserve channel order**: Make existing pattern data stay in place even when chips are rearranged. If turned off, pattern data will rearrange to match (the default, and usually the desired behavior). +**Preserve channel order**: make existing pattern data stay in place even when chips are rearranged. if turned off, pattern data will rearrange to match (the default, and usually the desired behavior). -To move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to its left. +to move a chip around, click and drag the ![crossed-arrows](chip-manager-move.png) button to its left. -To replace a chip with a different one, click the ![down-angle](chip-manager-change.png) and select the replacement. +to replace a chip with a different one, click the ![down-angle](chip-manager-change.png) and select the replacement. -To remove a chip entirely, click the ![X](chip-manager-remove.png) button. +to remove a chip entirely, click the ![X](chip-manager-remove.png) button. -Click a chip's name to open its options, where one can set clock rate, chip variant, and other specifics. \ No newline at end of file +click a chip's name to open its options, where one can set clock rate, chip variant, and other specifics. \ No newline at end of file diff --git a/doc/8-advanced/chip-manager.png b/doc/8-advanced/chip-manager.png index 690777795..fbc5045c2 100644 Binary files a/doc/8-advanced/chip-manager.png and b/doc/8-advanced/chip-manager.png differ diff --git a/doc/8-advanced/clock.md b/doc/8-advanced/clock.md index 8c2bcc7cd..e9a512d28 100644 --- a/doc/8-advanced/clock.md +++ b/doc/8-advanced/clock.md @@ -2,7 +2,7 @@ ![clock dialog](clock.png) -The clock shows the current playback position relative to the start of the song: +the clock shows the current playback position relative to the start of the song: - order : row - measure : beat (as defined by row highlight settings) diff --git a/doc/8-advanced/clock.png b/doc/8-advanced/clock.png index 47ca4fd60..20f906e5c 100644 Binary files a/doc/8-advanced/clock.png and b/doc/8-advanced/clock.png differ diff --git a/doc/8-advanced/comments.md b/doc/8-advanced/comments.md index 3fc14d590..ebb05d700 100644 --- a/doc/8-advanced/comments.md +++ b/doc/8-advanced/comments.md @@ -2,7 +2,6 @@ ![comments dialog](comments.png) -Comments, credits, or any arbitrary text may be entered here.\ -It has no effect on the song. +comments, credits, or any arbitrary text may be entered here. it has no effect on the song. -There is no word wrap; long lines must be broken manually with the Enter key. \ No newline at end of file +there is no word wrap; long lines must be broken manually with the Enter key. diff --git a/doc/8-advanced/comments.png b/doc/8-advanced/comments.png index dec7c26a0..e102d7fad 100644 Binary files a/doc/8-advanced/comments.png and b/doc/8-advanced/comments.png differ diff --git a/doc/8-advanced/compat-flags.md b/doc/8-advanced/compat-flags.md index 55319cc16..6e050a410 100644 --- a/doc/8-advanced/compat-flags.md +++ b/doc/8-advanced/compat-flags.md @@ -1,5 +1,5 @@ # compatibility flags -The **Compatibility Flags** window contains several tabs full of settings that change aspects of tracking and playback. A new Furnace file will leave them all at their defaults (off), while opening a DefleMask, Amiga MOD, or earlier Furnace file will automatically set the appropriate options. +the **Compatibility Flags** window contains several tabs full of settings that change aspects of tracking and playback. a new Furnace song will have these disabled, while opening a DefleMask module, .mod, or earlier Furnace file will automatically set the appropriate options. -Hovering over most options will bring up additional info about them. It's not recommended to change any of these without clear reason. _There be dragons here._ +hovering over most options will bring up additional info about them. it is not recommended to change any of these, especially the ones in the DefleMask and Old Furnace sections. diff --git a/doc/8-advanced/find-find.png b/doc/8-advanced/find-find.png index 8f061ebe5..1d5e05ba9 100644 Binary files a/doc/8-advanced/find-find.png and b/doc/8-advanced/find-find.png differ diff --git a/doc/8-advanced/find-replace.md b/doc/8-advanced/find-replace.md index 872abb1c3..613865c3c 100644 --- a/doc/8-advanced/find-replace.md +++ b/doc/8-advanced/find-replace.md @@ -2,59 +2,76 @@ Furnace has a powerful find-and-replace function that can take the repetitive work out of mass editing. -# find +## find ![find dialog](find-find.png) all data that can be found within a pattern can be searched for here. -- a find term contains: - - **Note**: note.\ - **Ins**: instrument.\ - **Volume**: volume.\ - **Effect**: effect type.\ - **Value**: effect value. all of these have the following choices for what data will be found: - - **ignore**: ignore this. - - **equals**: match the given value exactly. - - **not equal**: match everything but the given value. - - **between**: match anything between and including the given values. - - **not between**: match anything outside the given range of values. - - **any**: match all values. - - **none**: match blanks only. - - **-**: remove find term. if only one find term exists, it is cleared. - - **Add effect**: adds another Effect and Value to the term, each set representing additional effects columns. - - **Remove effect**: removes last Effect and Value from the term. -- **+**: adds another find term. -- **Search range**: restricts the find to the whole **Song**, the current **Selection**, or the currently viewed **Pattern**. -- **Confine to channels**: restricts the find to the selected channels and the channels between them. +a query contains: + +- **Note**: note. +- **Ins**: instrument. +- **Volume**: volume. +- **Effect**: effect type. +- **Value**: effect value. + +all of these have the following choices for what data will be found: + +- **ignore**: ignore this. +- **equals**: match the given value exactly. +- **not equal**: match everything but the given value. +- **between**: match anything between and including the given values. +- **not between**: match anything outside the given range of values. +- **any**: match all values. +- **none**: match blanks only. + +the following options also are available: + +- **-**: remove query. if only one query exists, it is cleared. +- **Add effect**: adds another Effect and Value to the query, each set representing additional effects columns. +- **Remove effect**: removes last Effect and Value from the query. +- **+**: adds another query. + +- **Search range**: restricts search range to the whole **Song**, the current **Selection**, or the currently viewed **Pattern**. +- **Confine to channels**: restricts to the selected channels and the channels between them. - **Match effect position**: chooses how the order of effect types and effect values will matter when finding them. - **No**: no attention is paid to what order the effects appear in. - **Lax**: matches effects if they appear in the same order as selected above. - **Strict**: effects may only match in their correponding effects columns. -- **Find**: finds everything that matches the terms and displays it in a list. - - the **order**, **row**, and **channel** columns are as they say. - - the **go** column of buttons will snap the pattern cursor to the location of the find. -# replace +- **Find**: finds everything that matches the query and displays it in a list. + - the **order**, **row**, and **channel** columns are as they say. + - the **go** column of buttons will take you to the location of the result. + +## replace ![replace dialog](find-replace.png) -- the replacement term contains: - - **Note**: note.\ - **Ins**: instrument.\ - **Volume**: volume.\ - **Effect**: effect type.\ - **Value**: effect value. all of these have the following choices for how they alter the found data: - - **set**: changes found data to this value. - - **add**: adds this value to the found data. it may be negative for subtraction. notes are calculated in semitones. - - **add (overflow)**: as "add" above, but values will wrap around; for example, adding 13 to `FF` will result in `0C`. - - **scale**: multiply value to this percentage; for example, scaling `1A` by `150` results in `27`. not available for "note". - - **clear**: erases data. - - **Add effect**: adds another Effect and Value to be replaced according to how they were found. - - **Remove effect**: removes last Effect and Value. +you may select any of these to replace: + +- **Note**: note. +- **Ins**: instrument. +- **Volume**: volume. +- **Effect**: effect type. +- **Value**: effect value. + +all of these have the following choices for how they alter matches: + +- **set**: changes matched data to this value. +- **add**: adds this value to matched data. it may be negative for subtraction. notes are calculated in semitones. +- **add (overflow)**: as "add" above, but values will wrap around; for example, adding 13 to `FF` will result in `0C`. +- **scale**: multiply value to this percentage; for example, scaling `1A` by `150` results in `27`. not available for "note". +- **clear**: erases matched data. + +the following options also are available: + +- **Add effect**: adds another Effect and Value to be replaced according to how they were found. +- **Remove effect**: removes last Effect and Value. - **Effect replace mode**: - **Replace matches only**: replaces only the effect columns that match. - **Replace matches, then free spaces**: replaces matched effects; if there are effect columns without data, those will be filled in with the additional effect replacements. - **Clear effects**: overwrites effect data with replacement effects. - **Insert in free spaces**: replaces nothing; replacement effects are inserted in free effects columns when available. -- **Replace**: finds everything from the "Find" tab and replaces it as directed. + +- **Replace**: performs the query specified in the Find tab and replaces it as directed. diff --git a/doc/8-advanced/find-replace.png b/doc/8-advanced/find-replace.png index 77f46f6ef..a9206beae 100644 Binary files a/doc/8-advanced/find-replace.png and b/doc/8-advanced/find-replace.png differ diff --git a/doc/8-advanced/grooves.md b/doc/8-advanced/grooves.md index d6fea075a..38775c5ab 100644 --- a/doc/8-advanced/grooves.md +++ b/doc/8-advanced/grooves.md @@ -1,23 +1,63 @@ # grooves -Grooves are macros for speed. +grooves are macros for speed. -A **groove** is the equivalent of repeating `0Fxx` commands on each row to get a cycle of speeds. For example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... +a **groove** is the equivalent of repeating `0Fxx` commands on each row to get a cycle of speeds. for example, a groove of "6 4 5 3" makes the first row 6 ticks long, the next row 4 ticks, then 5, 3, 6, 4, 5, 3... ![groove](groove.png) -To set the song's groove: -- Open the "Speed" window. -- Click the "Speed" button so it becomes "Speeds" (effectively a groove of two speeds). -- Click again so it becomes "Groove". -- Enter a sequence of up to 16 speeds. +to set the song's groove: +- open the "Speed" window. +- click the "Speed" button so it becomes "Speeds" (effectively a groove of two speeds). +- click again so it becomes "Groove". +- enter a sequence of up to 16 speeds. ![groove patterns](grooves.png) -The "Grooves" window is for entering preset groove patterns. -- The **`+`** button adds a new groove pattern; click in the pattern to edit it. -- The **`×`** buttons remove them. +the "Grooves" window is for entering preset groove patterns. +- the **`+`** button adds a new groove pattern; click in the pattern to edit it. +- the **`×`** buttons remove them. -A single `09xx` command will switch to the matching numbered groove pattern. +a single `09xx` command will switch to the matching numbered groove pattern. + +## BPM + +this is a non-exhaustive list of grooves and their equivalent BPM. + +note: this table assumes a song's tick rate setting is left at its default value for the chosen engine speed: 60 for NTSC, or 50 for PAL. + +BPM NTSC | BPM PAL | groove | | BPM NTSC | BPM PAL | groove +--------:|--------:|:-----------------------|-|---------:|--------:|:---------------------- + 100.00 | 83.33 | 9 | | 168.75 | 140.63 | 6, 5, 5 + 102.86 | 85.71 | 9, 9, 9, 8 | | 171.43 | 142.86 | 6, 5, 5, 5 + 103.85 | 86.54 | 9, 9, 8 | | 175.61 | 146.34 | 6, 5, 5, 5, 5, 5, 5, 5 + 105.88 | 88.24 | 9, 8 | | 180.00 | 150.00 | 5 + 108.00 | 90.00 | 9, 8, 8 | | 184.62 | 153.85 | 5, 5, 5, 5, 5, 5, 5, 4 + 109.09 | 90.91 | 9, 8, 8, 8 | | 189.47 | 157.89 | 5, 5, 5, 4 + 112.50 | 93.75 | 8 | | 192.86 | 160.71 | 5, 5, 4 + 114.29 | 95.24 | 8, 8, 8, 8, 8, 8, 8, 7 | | 194.59 | 162.16 | 6, 4, 5, 4, 5, 4, 5, 4 + 116.13 | 96.77 | 8, 8, 8, 7 | | 200.00 | 166.67 | 5, 4 + 118.03 | 98.36 | 9, 7, 8, 7, 8, 7, 8, 7 | | 205.71 | 171.43 | 5, 4, 5, 4, 5, 4, 4, 4 + 120.00 | 100.00 | 8, 7 | | 207.69 | 173.08 | 5, 4, 4 + 122.03 | 101.69 | 8, 7, 8, 7, 8, 7, 7, 7 | | 211.76 | 176.47 | 5, 4, 4, 4 + 124.14 | 103.45 | 8, 7, 7, 7 | | 218.18 | 181.82 | 5, 4, 4, 4, 4, 4, 4, 4 + 126.32 | 105.26 | 8, 7, 7, 7, 7, 7, 7, 7 | | 225.00 | 187.50 | 4 + 128.57 | 107.14 | 7 | | 232.26 | 193.55 | 4, 4, 4, 4, 4, 4, 4, 3 + 130.91 | 109.09 | 7, 7, 7, 7, 7, 7, 7, 6 | | 240.00 | 200.00 | 4, 4, 4, 3 + 133.33 | 111.11 | 7, 7, 7, 6 | | 245.45 | 204.55 | 4, 4, 3 + 135.00 | 112.50 | 7, 7, 6 | | 248.28 | 206.90 | 5, 3, 4, 3, 4, 3, 4, 3 + 135.85 | 113.21 | 8, 6, 7, 6, 7, 6, 7, 6 | | 257.14 | 214.29 | 4, 3 + 138.46 | 115.38 | 7, 6 | | 266.67 | 222.22 | 4, 3, 4, 3, 4, 3, 3, 3 + 141.18 | 117.65 | 7, 6, 7, 6, 7, 6, 6, 6 | | 270.00 | 225.00 | 4, 3, 3 + 142.11 | 118.42 | 7, 6, 6 | | 276.92 | 230.77 | 4, 3, 3, 3 + 144.00 | 120.00 | 7, 6, 6, 6 | | 288.00 | 240.00 | 4, 3, 3, 3, 3, 3, 3, 3 + 146.94 | 122.45 | 7, 6, 6, 6, 6, 6, 6, 6 | | 300.00 | 250.00 | 3 + 150.00 | 125.00 | 6 | | 327.27 | 272.73 | 3, 3, 3, 2 + 153.19 | 127.66 | 6, 6, 6, 6, 6, 6, 6, 5 | | 337.50 | 281.25 | 3, 3, 2 + 156.52 | 130.43 | 6, 6, 6, 5 | | 360.00 | 300.00 | 3, 2 + 158.82 | 132.35 | 6, 6, 5 | | 385.71 | 321.43 | 3, 2, 2 + 160.00 | 133.33 | 7, 5, 6, 5, 6, 5, 6, 5 | | 400.00 | 333.33 | 3, 2, 2, 2 + 163.64 | 136.36 | 6, 5 | | 450.00 | 375.00 | 2 + 167.44 | 139.53 | 6, 5, 6, 5, 6, 5, 5, 5 | | 900.00 | 750.00 | 1 diff --git a/doc/8-advanced/grooves.png b/doc/8-advanced/grooves.png index 2130dad39..e38e944f0 100644 Binary files a/doc/8-advanced/grooves.png and b/doc/8-advanced/grooves.png differ diff --git a/doc/8-advanced/log-viewer.md b/doc/8-advanced/log-viewer.md index 4f1e1e4b6..275cc1c92 100644 --- a/doc/8-advanced/log-viewer.md +++ b/doc/8-advanced/log-viewer.md @@ -1,12 +1,12 @@ # log viewer -The log viewer provides a look at Furnace's internal messages. This can be useful for chasing down problems. +the log viewer provides a look at Furnace's internal messages. this can be useful for chasing down problems. ![log viewer dialog](log-viewer.png) -If the **Follow** checkbox is enabled, the log will snap to the bottom and continually scroll to show the newest messages. If disabled, it will stay put on what's currently shown. +if the **Follow** checkbox is enabled, the log will snap to the bottom and continually scroll to show the newest messages. if disabled, it will stay put on what's currently shown. -The **Level** dropdown determines the minimum importance of the messages displayed. +the **Level** dropdown determines the minimum importance of the messages displayed. | level | message shown | |---|---| diff --git a/doc/8-advanced/log-viewer.png b/doc/8-advanced/log-viewer.png index aa0076508..820ea1761 100644 Binary files a/doc/8-advanced/log-viewer.png and b/doc/8-advanced/log-viewer.png differ diff --git a/doc/8-advanced/mixer-mixer.png b/doc/8-advanced/mixer-mixer.png index 249c6fbed..01dfdc5c7 100644 Binary files a/doc/8-advanced/mixer-mixer.png and b/doc/8-advanced/mixer-mixer.png differ diff --git a/doc/8-advanced/mixer-patchbay.png b/doc/8-advanced/mixer-patchbay.png index 52ca7ab3e..ff36d9d07 100644 Binary files a/doc/8-advanced/mixer-patchbay.png and b/doc/8-advanced/mixer-patchbay.png differ diff --git a/doc/8-advanced/mixer.md b/doc/8-advanced/mixer.md index bafa0fe8d..55beca2a1 100644 --- a/doc/8-advanced/mixer.md +++ b/doc/8-advanced/mixer.md @@ -1,6 +1,6 @@ # mixer -The "Mixer" dialog provides options for overall sound mixing. +the "Mixer" dialog provides options for overall sound mixing. ## "Mixer" tab @@ -8,18 +8,18 @@ The "Mixer" dialog provides options for overall sound mixing. "Master Volume" controls the overall mix. -Each chip has several options: -- **Invert**: Flips the output wave. -- **Volume**: Controls the chip's volume relative to other chips. -- **Panning**: Left-right sound control. -- **Front/Rear**: Front-read sound control. Only useful for setups with four or more speakers. +each chip has several options: +- **Invert**: flips the output wave. +- **Volume**: controls the chip's volume relative to other chips. +- **Panning**: left-right sound control. +- **Front/Rear**: front-read sound control. only useful for setups with four or more speakers. ## "Patchbay" tab ![mixer dialog on patchbay tab](mixer-patchbay.png) -- **Automatic patchbay**: Make appropriate connections when adding, removing, or changing chips and chip settings. -- **Display hidden ports**: Shows all available connection ports. The "System" unit actually has 16 ports; 1 maps to the left channel, and 2 maps to the right. +- **Automatic patchbay**: make appropriate connections when adding, removing, or changing chips and chip settings. +- **Display hidden ports**: shows all available connection ports. the "System" unit actually has 16 ports; 1 maps to the left channel, and 2 maps to the right. - **Display internal**: hows two additional units, one for sample previews and one for the metronome sound. -The graph shows each existing unit along with their outputs, inputs, and the "patch cables" connecting them. Connections can be made by dragging between an output and an input. Right-clicking on a unit gives the option to disconnect all patches from that unit. +the graph shows each existing unit along with their outputs, inputs, and the "patch cables" connecting them. connections can be made by dragging between an output and an input. right-clicking on a unit gives the option to disconnect all patches from that unit. diff --git a/doc/8-advanced/osc.md b/doc/8-advanced/osc.md index fe90e3971..db625e71c 100644 --- a/doc/8-advanced/osc.md +++ b/doc/8-advanced/osc.md @@ -1,9 +1,9 @@ # oscilloscope -The Oscilloscope shows the waveform of the mix of all currently playing sounds. +the Oscilloscope shows the waveform of the mix of all currently playing sounds. ![oscilloscope view](osc.png) -Right-clicking on the oscilloscope toggles the adjustment sliders: +right-clicking on the oscilloscope toggles the adjustment sliders: - waveform height zoom - width of viewed audio (window size) in milliseconds. diff --git a/doc/8-advanced/pat-manager.md b/doc/8-advanced/pat-manager.md index ea058e667..79b854a48 100644 --- a/doc/8-advanced/pat-manager.md +++ b/doc/8-advanced/pat-manager.md @@ -1,6 +1,6 @@ # pattern manager -The pattern manager is useful for cleaning up stray patterns and as an overview of pattern usage. +the pattern manager is useful for cleaning up stray patterns and as an overview of pattern usage. ![pattern manager dialog](pattern-manager.png) @@ -8,7 +8,7 @@ The pattern manager is useful for cleaning up stray patterns and as an overview **Re-arrange patterns** renumbers patterns to be in sequence, along with changing all references in the order list to match. -The pattern grid shows each channel and all its patterns. These are color-coded to show how much they're used in the song; these colors can be changed in Settings. +the pattern grid shows each channel and all its patterns. these are color-coded to show how much they're used in the song; these colors can be changed in Settings. | default color | name in Settings | meaning | | --- | --- | --- | @@ -19,4 +19,4 @@ The pattern grid shows each channel and all its patterns. These are color-coded | orange | Really overused | used in half or more orders | | magenta | Combo Breaker | the only used pattern in this channel! | -Right-clicking a pattern will permanently delete it. +right-clicking a pattern will permanently delete it. diff --git a/doc/8-advanced/pattern-manager.png b/doc/8-advanced/pattern-manager.png index b64b9d291..3ac440cb6 100644 Binary files a/doc/8-advanced/pattern-manager.png and b/doc/8-advanced/pattern-manager.png differ diff --git a/doc/8-advanced/piano.md b/doc/8-advanced/piano.md index 4218ef083..302177e0a 100644 --- a/doc/8-advanced/piano.md +++ b/doc/8-advanced/piano.md @@ -1,33 +1,33 @@ # piano / input pad -The piano serves as a non-keyboard interface to input notes. +the piano serves as a non-keyboard interface to input notes. ![piano chart](piano.png) -The buttons at the left do the following: +the buttons at the left do the following: | | | | | :---: | :---: | :---: | | move one octave down | move one octave up | open options | | fewer visible octaves | more visible octaves | swap buttons | -When swapped, the bottons do the following: +when swapped, the buttons do the following: | | | | | :---: | :---: | :---: | | input note off | input note release | open options | | input macro release | delete | swap buttons | -Every C key is labelled with its octave. +every C key is labelled with its octave. -Right-clicking on the piano keys will make the buttons disappear; right-clicking again brings them back. +right-clicking on the piano keys will make the buttons disappear; right-clicking again brings them back. ## options -Key layout: +key layout: - **Automatic** -- **Standard**: Black keys are 2/3 length. -- **Continuous**: Black keys are full length. +- **Standard**: black keys are 2/3 length. +- **Continuous**: black keys are full length. -**Share play/edit offset/range**: If disabled, the piano will keep different octave and range values for playback and non-playback states. -**Read-only (can't input notes): Prevents note entry. \ No newline at end of file +**Share play/edit offset/range**: if disabled, the piano will keep different octave and range values for playback and non-playback states. +**Read-only (can't input notes): prevents note entry. diff --git a/doc/8-advanced/piano.png b/doc/8-advanced/piano.png index ee04dd442..9b2b7b4c3 100644 Binary files a/doc/8-advanced/piano.png and b/doc/8-advanced/piano.png differ diff --git a/doc/8-advanced/register.png b/doc/8-advanced/register.png index 76ec9894f..a456608db 100644 Binary files a/doc/8-advanced/register.png and b/doc/8-advanced/register.png differ diff --git a/doc/8-advanced/regview.md b/doc/8-advanced/regview.md index 57f526fb3..e9d92c972 100644 --- a/doc/8-advanced/regview.md +++ b/doc/8-advanced/regview.md @@ -1,5 +1,5 @@ # register view -During playback, "Register View" shows the hex data involved with each chip's operation. +during playback, "Register View" shows the hex data involved with each chip's operation. ![register view dialog](register.png) diff --git a/doc/8-advanced/stats.md b/doc/8-advanced/stats.md index 9f3c5f490..01bc78775 100644 --- a/doc/8-advanced/stats.md +++ b/doc/8-advanced/stats.md @@ -1,5 +1,5 @@ # statistics -The Statistics dialog shows running stats such as overall audio processing load and per-chip sample memory. +the Statistics dialog shows running stats such as overall audio processing load and per-chip sample memory. ![statistics dialog](stats.png) diff --git a/doc/8-advanced/stats.png b/doc/8-advanced/stats.png index aabafa50e..6e4ec92a0 100644 Binary files a/doc/8-advanced/stats.png and b/doc/8-advanced/stats.png differ diff --git a/doc/9-guides/README.md b/doc/9-guides/README.md index 4efaf6634..66748e615 100644 --- a/doc/9-guides/README.md +++ b/doc/9-guides/README.md @@ -1,12 +1,12 @@ # guides -here is a small collection of useful tricks and techniques to really make Furnace sing. +this is collection of user-contributed Furnace guides which may be useful during composition. - [using samples with limited playback rates](limited-samples.md) - [choosing emulation cores](emulation-cores.md) - [using OPLL patch macro](opllswitching.md) - [using AY/SAA hardware envelope](envelope.md) -# links +## other resources -- [FM Synthesis of Real Instruments](http://www.javelinart.com/FM_Synthesis_of_Real_Instruments.pdf): an in-depth tutorial on creating FM patches from scratch. \ No newline at end of file +- [FM Synthesis of Real Instruments](http://www.javelinart.com/FM_Synthesis_of_Real_Instruments.pdf): an in-depth tutorial on creating FM patches from scratch. diff --git a/doc/README.md b/doc/README.md index 90e6e905b..3e6652c13 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,6 +1,8 @@ # Furnace user manual -this documentation is a work in progress! expect several sections to be incomplete. +this is the manual for Furnace, the chiptune tracker. + +the index follows. 1. [introduction](1-intro/README.md) 2. [interface](2-interface/README.md) @@ -12,16 +14,23 @@ this documentation is a work in progress! expect several sections to be incomple 8. [advanced topics](8-advanced/README.md) 9. [guides](9-guides/README.md) -# attribution +## authors -writers: - -- tildearrow -- freq-mod -- nicco1690 -- DeMOSic - cam900 -- host12prog -- WindowxDeveloper -- polluks +- DeMOSic - Electric Keet +- freq-mod +- host12prog +- nicco1690 +- tildearrow + +## information + +copyright © 2023 tildearrow and other authors. + +this documentation is under the [Creative Commons Attribution 3.0 Unported](https://creativecommons.org/licenses/by/3.0/) license. +you may reproduce, modify and/or distribute this documentation provided this copyright notice (including license and attribution) is present and any necessary disclaimers whether modifications have been made. + +this documentation is provided as-is and without warranty of any kind. + + diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index 82207a587..a7c1c2b89 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -1934,14 +1934,23 @@ namespace IGFD prCurrentPath = vCurrentPath; } - bool IGFD::FileManager::IsFileExist(const std::string& vFile) + bool IGFD::FileManager::IsFileExist(const std::string& vFile, const std::string& vFileExt) { std::ifstream docFile(vFile, std::ios::in); + logV("IGFD: IsFileExist(%s)",vFile); if (docFile.is_open()) { docFile.close(); return true; } + + std::ifstream docFileE(vFile+vFileExt, std::ios::in); + logV("IGFD: IsFileExist(%s)",vFile+vFileExt); + if (docFileE.is_open()) + { + docFileE.close(); + return true; + } return false; } @@ -4564,7 +4573,7 @@ namespace IGFD { if (prFileDialogInternal.puIsOk) // catched only one time { - if (!prFileDialogInternal.puFileManager.IsFileExist(GetFilePathName())) // not existing => quit dialog + if (!prFileDialogInternal.puFileManager.IsFileExist(GetFilePathName(),prFileDialogInternal.puFilterManager.GetSelectedFilter().firstFilter)) // not existing => quit dialog { QuitFrame(); return true; diff --git a/extern/igfd/ImGuiFileDialog.h b/extern/igfd/ImGuiFileDialog.h index cecf885a3..6336c1979 100644 --- a/extern/igfd/ImGuiFileDialog.h +++ b/extern/igfd/ImGuiFileDialog.h @@ -913,7 +913,7 @@ namespace IGFD bool SetPathOnParentDirectoryIfAny(); // compose paht on parent directory std::string GetCurrentPath(); // get the current path void SetCurrentPath(const std::string& vCurrentPath); // set the current path - static bool IsFileExist(const std::string& vFile); + static bool IsFileExist(const std::string& vFile, const std::string& vFileExt); void SetDefaultFileName(const std::string& vFileName); bool SelectDirectory(const FileInfos& vInfos); // enter directory void SelectFileName(const FileDialogInternal& vFileDialogInternal, diff --git a/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index e7966cab4..97a458696 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -2550,6 +2550,8 @@ struct ImGuiListClipper // - It is important that we are keeping those disabled by default so they don't leak in user space. // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) // - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. +#define IMGUI_DEFINE_MATH_OPERATORS + #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index 90e28ec3c..5bd95013b 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -7,6 +7,12 @@ #ifdef __MINGW32__ // Explicitly setting NTDDI version, this is necessary for the MinGW compiler +#ifdef NTDDI_VERSION +#undef NTDDI_VERSION +#endif +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif #define NTDDI_VERSION NTDDI_VISTA #define _WIN32_WINNT _WIN32_WINNT_VISTA #endif diff --git a/extern/weakjack/.gitignore b/extern/weakjack/.gitignore new file mode 100644 index 000000000..1377554eb --- /dev/null +++ b/extern/weakjack/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/extern/weakjack/README.md b/extern/weakjack/README.md new file mode 100644 index 000000000..7b957d0f4 --- /dev/null +++ b/extern/weakjack/README.md @@ -0,0 +1,79 @@ +Weak-JACK +========= + +This small library abstracts the [JACK](http://jackaudio.org) Application Binary Interface. + +Background and Motivation +------------------------- + +The jack shared library needs to be installed system-wide (for all jack applications +to share), it can not be part of an application itself. + +JACK developers take great care to not break binary compatibility of libjack. An +application compiled with one version of jack will work with all future versions +of jack. However, this only works well on GNU/Linux, BSD and to some extend on OSX. + +weak-jack linking is useful (at least) in the following cases: + +* the resulting application should not be directly linked to libjack.[so|dll|dylib] + IOW: the application should start even if libjack is not installed. +* the ABI of libjack is not stable. Note, this is only relevant for the Windows .dll + (e.g. applications compiled and linked with jack-1.9.9 will crash with jack-1.9.10 + on windows. -- MSVC has a workaround: link by function-name, not ordinal, mingw + does not offer this) +* Reference new API functions (e.g. meta-data API or new latency compensation) + in the application, which is not available on older versions of jack. + +Usage +----- + +1. Copy the source files into your application's source (or use a git submodule) +2. replace all `#include` in your sources with `#include "weak-jack.h"` +3. add `weak_libjack.c` to the build-source of your project + (in case your build-system does not detect `#include` dependencies automatically, + also reference the header and .def file). +4. Define `USE_WEAK_JACK` for all platforms where you want to use weak-linking. Usually + `CFLAGS+=-DUSE_WEAK_JACK CXXFLAGS+=-DUSE_WEAK_JACK` +5. Do not link your application to libjack (`-ljack`) when `USE_WEAK_JACK` is defined. + +Note the jack-headers still need to be present when compiling the application. + +The application code itself does not need to be changed. + +The first call to `jack_client_open()` will try to find and load libjack, if it cannot be +found, it will fail (return `NULL` and set `jack_status_t` if provided to `JackFailure`.) + +It is possible to explicitly initialize and query availability of libjack using +`have_libjack();` it returns 0 if libjack is available and can be used. (see the header +file for non-zero error codes). + +Caveats +------- + +If libjack is not available, all `jack_*` API calls are turned into no-operation functions. +This is not a problem in general, as jack-applications will not use any part of the jack API if +jack_client_open fails. The only exception here may be `jack_ringbuffer`. Note that the ringbuffer +implementation is also part of libjack and will not be available. + +The dummy implementation for the ringbuffer API is safe (read, writes are ignored and return failure +or zero-bytes length), but if your application depends on it to work, you're out of luck :) + +The function wrappers in `weak_libjack.def` were collected pragmatically it's quite possible that +some JACK API calls have been missed. If you application fails to link (without -ljack), please report +at https://github.com/x42/weakjack/issues + +License +------- + +GNU General Public License version 2 (or later). + +Alternatives +------------ + +An alternative, more liberally licensed, implementation that abstracts and wraps jack completely +(incl headers) can be found at +https://github.com/falkTX/Carla/tree/master/source/jackbridge (C++ only), +and a jack2 specific version at https://github.com/sletz/jack2/blob/master/common/JackWeakAPI.c + +A variant for python bindings is also provided by falkTX: +https://github.com/falkTX/Cadence/blob/master/src/jacklib.py diff --git a/extern/weakjack/weak_libjack.c b/extern/weakjack/weak_libjack.c new file mode 100644 index 000000000..f1c7d4bae --- /dev/null +++ b/extern/weakjack/weak_libjack.c @@ -0,0 +1,291 @@ +/* runtime/weak dynamic JACK linking + * + * (C) 2014 Robin Gareus + * + * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "weak_libjack.h" + +#define NDEBUG + +#ifndef USE_WEAK_JACK + +int have_libjack (void) { + return 0; +} + +#else + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +static void* lib_open(const char* const so) { +#ifdef _WIN32 + return (void*) LoadLibraryA(so); +#else + return dlopen(so, RTLD_NOW|RTLD_LOCAL); +#endif +} + +static void* lib_symbol(void* const lib, const char* const sym) { +#ifdef _WIN32 + return (void*) GetProcAddress((HMODULE)lib, sym); +#else + return dlsym(lib, sym); +#endif +} + +#if defined _MSC_VER && ! defined __INTEL_COMPILER +typedef void * pvoid_t; +#define MAPSYM(SYM, FAIL) _j._ ## SYM = (func_t)lib_symbol(lib, "jack_" # SYM); \ + if (!_j._ ## SYM) err |= FAIL; +#elif defined NDEBUG +typedef void * __attribute__ ((__may_alias__)) pvoid_t; +#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \ + if (!_j._ ## SYM) err |= FAIL; +#else +typedef void * __attribute__ ((__may_alias__)) pvoid_t; +#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \ + if (!_j._ ## SYM) { \ + if (FAIL) { \ + fprintf(stderr, "*** WEAK-JACK: required symbol 'jack_%s' was not found\n", "" # SYM); \ + } \ + err |= FAIL; \ + } +#endif + +typedef void (* func_t) (void); + +/* function pointers to the real jack API */ +static struct WeakJack { + func_t _client_open; // special case due to varargs + +#define JCFUN(ERR, RTYPE, NAME, RVAL) func_t _ ## NAME ; +#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) func_t _ ## NAME ; +#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) func_t _ ## NAME ; +#define JVFUN(ERR, NAME, DEF, ARGS, CODE) func_t _ ## NAME ; + +#include "weak_libjack.def" + +#undef JCFUN +#undef JPFUN +#undef JXFUN +#undef JVFUN +} _j; + +static int _status = -1; +#if !defined _MSC_VER || defined __INTEL_COMPILER +__attribute__((constructor)) +#endif +static void init_weak_jack(void) +{ + void* lib; + int err = 0; +#ifndef NDEBUG + fprintf(stderr, "*** WEAK-JACK: initializing\n"); +#endif + + memset(&_j, 0, sizeof(_j)); + +#ifdef __APPLE__ + lib = lib_open("libjack.dylib"); + if (!lib) { + lib = lib_open("/usr/local/lib/libjack.dylib"); + } + if (!lib) { + /* New Homebrew location */ + lib = lib_open("/opt/homebrew/lib/libjack.dylib"); + if (lib) { + fprintf(stderr, "*** WEAK-JACK: using Homebrew\n"); + } + } + if (!lib) { + /* MacPorts location */ + lib = lib_open("/opt/local/lib/libjack.dylib"); + if (lib) { + fprintf(stderr, "*** WEAK-JACK: using MacPorts\n"); + } + } + +#elif (defined _WIN32) +# if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__) + lib = lib_open("libjack64.dll"); +# else + lib = lib_open("libjack.dll"); +# endif +#else + lib = lib_open("libjack.so.0"); +#endif + if (!lib) { +#ifndef NDEBUG + fprintf(stderr, "*** WEAK-JACK: libjack was not found\n"); +#endif + _status = -2; + return; + } + + /* found library, now lookup functions */ + MAPSYM(client_open, 2) + +#define JCFUN(ERR, RTYPE, NAME, RVAL) MAPSYM(NAME, ERR) +#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) MAPSYM(NAME, ERR) +#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR) +#define JVFUN(ERR, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR) + +#include "weak_libjack.def" + +#undef JCFUN +#undef JPFUN +#undef JXFUN +#undef JVFUN + + /* if a required symbol is not found, disable JACK completly */ + if (err) { + _j._client_open = NULL; + } + _status = err; +#ifndef NDEBUG + fprintf(stderr, "*** WEAK-JACK: %s. (%d)\n", err ? "jack is not available" : "OK", _status); +#endif +} + +int have_libjack (void) { + if (_status == -1) { + init_weak_jack(); + } + return _status; +} + +/******************************************************************************* + * helper macros + */ + +#if defined(__GNUC__) && (__GNUC__ > 2) && !defined(NDEBUG) +#define likely(expr) (__builtin_expect (!!(expr), 1)) +#else +#define likely(expr) (expr) +#endif + +#ifndef NDEBUG +# define WJACK_WARNING(NAME) \ + fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME); +#else +# define WJACK_WARNING(NAME) ; +#endif + +/****************************************************************************** + * JACK API wrapper functions. + * + * if a function pointer is set in the static struct WeakJack _j, + * the function is called directly. + * Otherwise a dummy NOOP implementation is provided. + * The latter is mainly for compile-time warnings. + * + * If libjack is not found, jack_client_open() will fail. + * In that case the application should not call any other libjack + * functions. Hence a real implementation is not needed. + * (jack ringbuffer may be an exception for some apps) + */ + +/* dedicated support for jack_client_open(,..) variable arg function macro */ +func_t WJACK_get_client_open(void) { + if (_status == -1) { + init_weak_jack(); + } + return _j._client_open; +} + +/* callback to set status */ +jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...) { + WJACK_WARNING(client_open); + if (status) { *status = JackFailure; } + return NULL; +} + +/******************************************************************************* + * Macros to wrap jack API + */ + +/* abstraction for jack_client functions + * rtype jack_function_name (jack_client_t *client) { return rval; } + */ +#define JCFUN(ERR, RTYPE, NAME, RVAL) \ + RTYPE WJACK_ ## NAME (jack_client_t *client) { \ + if likely(_j._ ## NAME) { \ + return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \ + } else { \ + WJACK_WARNING(NAME) \ + return RVAL; \ + } \ + } + +/* abstraction for NOOP functions with return value + * rtype jack_function_name (ARGS) { return rval; } + */ +#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) \ + RTYPE WJACK_ ## NAME DEF { \ + if likely(_j._ ## NAME) { \ + return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + return RVAL; \ + } \ + } + +/* abstraction for functions that need custom code. + * e.g. functions with return-value-pointer args, + * use CODE to initialize value + * + * rtype jack_function_name (ARGS) { CODE } + */ +#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) \ + RTYPE WJACK_ ## NAME DEF { \ + if likely(_j._ ## NAME) { \ + return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + CODE \ + } \ + } + +/* abstraction for void functions with return-value-pointer args + * void jack_function_name (ARGS) { CODE } + */ +#define JVFUN(ERR, NAME, DEF, ARGS, CODE) \ + void WJACK_ ## NAME DEF { \ + if likely(_j._ ## NAME) { \ + ((void (*)DEF) _j._ ## NAME) ARGS; \ + } else { \ + WJACK_WARNING(NAME) \ + CODE \ + } \ + } + +#include "weak_libjack.def" + +#undef JCFUN +#undef JPFUN +#undef JXFUN +#undef JVFUN + +#endif // end USE_WEAK_JACK diff --git a/extern/weakjack/weak_libjack.def b/extern/weakjack/weak_libjack.def new file mode 100644 index 000000000..fda83a4fc --- /dev/null +++ b/extern/weakjack/weak_libjack.def @@ -0,0 +1,179 @@ +/* macro-absraction of the JACK API + * + * see weak_libjack.c for details, in general arguments are: + * + * [required], [return type], [name], [arguments], [code or return value] + * + * This file is included multiple times with different macro definitions + * do not add header guards. + * see https://en.wikibooks.org/wiki/C_Programming/Preprocessor#X-Macros + */ + +#ifdef USE_WEAK_JACK + +/* */ +JCFUN(1, int, client_close, 0) +JCFUN(1, char*, get_client_name, NULL) +JVFUN(0, on_shutdown, (jack_client_t *c, JackShutdownCallback s, void *a), (c,s,a),) +JVFUN(0, on_info_shutdown, (jack_client_t *c, JackInfoShutdownCallback s, void *a), (c,s,a),) + +JPFUN(1, int, set_process_callback, (jack_client_t *c, JackProcessCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_freewheel_callback, (jack_client_t *c, JackFreewheelCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_buffer_size_callback, (jack_client_t *c, JackBufferSizeCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_sample_rate_callback, (jack_client_t *c, JackSampleRateCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_port_registration_callback, (jack_client_t *c, JackPortRegistrationCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_port_connect_callback, (jack_client_t *c, JackPortConnectCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_graph_order_callback, (jack_client_t *c, JackGraphOrderCallback g, void *a), (c,g,a), -1) +JPFUN(1, int, set_xrun_callback, (jack_client_t *c, JackXRunCallback g, void *a), (c,g,a), -1) +JPFUN(1, int, set_latency_callback, (jack_client_t *c, JackLatencyCallback g, void *a), (c,g,a), -1) +JVFUN(1, set_error_function, (void (*f)(const char *)), (f),) +JVFUN(1, set_info_function, (void (*f)(const char *)), (f),) + +JCFUN(1, int, activate, -1) +JCFUN(1, int, deactivate, -1) + +JPFUN(1, int, client_name_size, (), (), 32) + +JCFUN(1, jack_nframes_t, get_sample_rate, 0) +JCFUN(1, jack_nframes_t, get_buffer_size, 0) +JPFUN(1, jack_nframes_t, frames_since_cycle_start, (const jack_client_t *c), (c), 0) +JPFUN(1, jack_nframes_t, frame_time, (const jack_client_t *c), (c), 0) +JPFUN(1, jack_nframes_t, last_frame_time, (const jack_client_t *c), (c), 0) +JPFUN(1, jack_time_t, get_time, (void), (), 0) +JCFUN(1, float, cpu_load, 0) +JCFUN(1, int, is_realtime, 0) + +JPFUN(1, int, set_freewheel, (jack_client_t *c, int o), (c,o), 0) +JPFUN(1, int, set_buffer_size, (jack_client_t *c, jack_nframes_t b), (c,b), 0) + +JCFUN(0, int, recompute_total_latencies, 0) +JPFUN(0, jack_nframes_t, port_get_total_latency, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JVFUN(0, port_get_latency_range, (jack_port_t *p, jack_latency_callback_mode_t m, jack_latency_range_t *r), (p,m,r), if (r) {r->min = r->max = 0;}) +JVFUN(0, port_set_latency_range, (jack_port_t *p, jack_latency_callback_mode_t m, jack_latency_range_t *r), (p,m,r),) + +JPFUN(1, void*, port_get_buffer, (jack_port_t *p, jack_nframes_t n), (p,n), NULL) +JPFUN(1, int, port_request_monitor, (jack_port_t *p, int o), (p,o), 0) +JPFUN(1, int, port_ensure_monitor, (jack_port_t *p, int o), (p,o), 0) +JPFUN(1, int, port_monitoring_input, (jack_port_t *p), (p), 0) + +JPFUN(1, const char*, port_name, (const jack_port_t *p), (p), NULL) +JPFUN(1, const char*, port_short_name, (const jack_port_t *p), (p), NULL) +JPFUN(1, int, port_flags, (const jack_port_t *p), (p), 0) +JPFUN(1, int, port_is_mine, (const jack_client_t *c, const jack_port_t *p), (c,p), 0) +JPFUN(1, int, port_connected, (const jack_port_t *p), (p), 0) +JPFUN(1, const char**, get_ports,(jack_client_t *c, const char *p, const char *t, unsigned long f), (c,p,t,f), NULL) +JPFUN(1, int, port_name_size, (void), (), 0) +JPFUN(1, int, port_type_size, (void), (), 0) +JPFUN(1, size_t, port_type_get_buffer_size, (jack_client_t *c, const char *t), (c,t), 0) +JPFUN(1, jack_port_t*, port_by_name, (jack_client_t *c, const char *n), (c,n), NULL) +JPFUN(1, jack_port_t*, port_by_id, (jack_client_t *c, jack_port_id_t i), (c,i), NULL) +JPFUN(1, jack_port_t*, port_register, (jack_client_t *c, const char *n, const char *t, unsigned long f, unsigned long b), (c,n,t,f,b), NULL) +JPFUN(1, int, port_unregister, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JPFUN(1, const char *, port_type, (const jack_port_t *p), (p), 0) +JPFUN(1, const char **, port_get_connections, (const jack_port_t *p), (p), 0) +JPFUN(1, const char **, port_get_all_connections, (const jack_client_t *c, const jack_port_t *p), (c,p), 0) +JPFUN(1, int, port_set_name, (jack_port_t *p, const char *n), (p,n), -1) +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif +JXFUN(0, int, port_rename, (jack_client_t *c, jack_port_t *p, const char *n), (c,p,n), return jack_port_set_name (p,n);) +#if defined(__clang__) +#pragma clang diagnostic pop +#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif +JPFUN(1, int, port_get_aliases, (const jack_port_t *port, char* const aliases[2]), (port,aliases), 0) +JPFUN(1, int, port_disconnect, (jack_client_t *c, jack_port_t *p), (c,p), 0) +JPFUN(1, int, connect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1) +JPFUN(1, int, disconnect, (jack_client_t *c, const char *s, const char *d), (c,s,d), -1) +JVFUN(0, free, (void *p), (p), free(p);) + +JCFUN(1, jack_nframes_t, cycle_wait, 0) +JVFUN(1, cycle_signal, (jack_client_t *c, int s), (c,s),) +JPFUN(1, int, set_process_thread, (jack_client_t *c, JackThreadCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_thread_init_callback, (jack_client_t *c, JackThreadInitCallback p, void *a), (c,p,a), -1) + +JPFUN(1, int, transport_locate, (jack_client_t *c, jack_nframes_t f), (c,f), 0) +JVFUN(1, transport_start, (jack_client_t *c), (c),) +JVFUN(1, transport_stop, (jack_client_t *c), (c),) +JPFUN(1, jack_nframes_t, get_current_transport_frame, (const jack_client_t *c), (c), 0) +JXFUN(1, jack_transport_state_t, transport_query, (const jack_client_t *c, jack_position_t *p), (c,p), memset(p, 0, sizeof(jack_position_t)); return JackTransportStopped;) +JPFUN(1, int, set_sync_callback, (jack_client_t *c, JackSyncCallback p, void *a), (c,p,a), -1) +JPFUN(1, int, set_timebase_callback, (jack_client_t *c, int l, JackTimebaseCallback p, void *a), (c,l,p,a), -1) +JPFUN(1, int, set_sync_timeout, (jack_client_t *c, jack_time_t t), (c,t), -1) +JCFUN(1, int, release_timebase, 0) + +/* */ +JPFUN(1, uint32_t, midi_get_event_count, (void* p), (p), 0) +JPFUN(1, int, midi_event_get, (jack_midi_event_t *e, void *p, uint32_t i), (e,p,i), -1) +JPFUN(1, int, midi_event_write, (void *b, jack_nframes_t t, const jack_midi_data_t *d, size_t s), (b,t,d,s), -1) +JVFUN(1, midi_clear_buffer, (void *b), (b),) + +/* */ +JPFUN(0, int, set_session_callback, (jack_client_t *c, JackSessionCallback s, void *a), (c,s,a), -1) +JPFUN(0, int, session_reply, (jack_client_t *c, jack_session_event_t *e), (c,e), -1) +JVFUN(0, session_event_free, (jack_session_event_t *e), (e), ) + +/* */ +JPFUN(1, jack_ringbuffer_t *, ringbuffer_create, (size_t s), (s), NULL) +JVFUN(1, ringbuffer_free, (jack_ringbuffer_t *rb), (rb), ) +JVFUN(1, ringbuffer_reset, (jack_ringbuffer_t *rb), (rb), ) +JVFUN(1, ringbuffer_read_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), ) +JVFUN(1, ringbuffer_write_advance, (jack_ringbuffer_t *rb, size_t c), (rb,c), ) +JPFUN(1, size_t, ringbuffer_read_space, (const jack_ringbuffer_t *rb), (rb), 0) +JPFUN(1, size_t, ringbuffer_write_space, (const jack_ringbuffer_t *rb), (rb), 0) +JPFUN(1, size_t, ringbuffer_read, (jack_ringbuffer_t *rb, char *d, size_t c), (rb,d,c), 0) +JPFUN(1, size_t, ringbuffer_write, (jack_ringbuffer_t *rb, const char *s, size_t c), (rb,s,c), 0) +JPFUN(0, int, ringbuffer_mlock, (jack_ringbuffer_t *rb), (rb), 0) +JVFUN(0, ringbuffer_get_read_vector, (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *v), (rb,v), if (v) {v->buf=NULL; v->len=0;} ) +JVFUN(0, ringbuffer_get_write_vector, (const jack_ringbuffer_t *rb, jack_ringbuffer_data_t *v), (rb,v), if (v) {v->buf=NULL; v->len=0;} ) +JPFUN(0, size_t, ringbuffer_peek, (jack_ringbuffer_t *rb, char *d, size_t c), (rb,d,c), 0) + +/* */ +JCFUN(0, int, client_real_time_priority, 0) +JCFUN(0, int, client_max_real_time_priority, 0) +JPFUN(0, int, acquire_real_time_scheduling, (jack_native_thread_t t, int p), (t,p), 0) +JPFUN(0, int, drop_real_time_scheduling, (jack_native_thread_t t), (t), 0) +#if (!defined _WIN32 && (defined _REENTRANT || defined __linux__)) + /* on POSIX systems, call pthread_join() when libjack does not provide jack_client_stop_thread */ +JXFUN(0, int, client_stop_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), if (t) { pthread_join(t, NULL); return 0; } else { return -1;}) +#else +JPFUN(0, int, client_stop_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0) +#endif +JPFUN(0, int, client_kill_thread, (jack_client_t* c, jack_native_thread_t t), (c,t), 0) +#ifndef _WIN32 +JVFUN(0, set_thread_creator, (jack_thread_creator_t c), (c),) +#endif +JPFUN(1, int, client_create_thread, \ + (jack_client_t* c, jack_native_thread_t *t, int p, int r, void *(*f)(void*), void *a), (c,t,p,r,f,a), 0) + +#ifndef NO_JACK_METADATA +/* - TODO*/ + +/* */ +JPFUN(0, char *, get_uuid_for_client_name, (jack_client_t* c, const char* n), (c,n), NULL) +JPFUN(0, char *, get_client_name_by_uuid, (jack_client_t* c, const char* u), (c,u), NULL) +JPFUN(0, jack_uuid_t, port_uuid, (const jack_port_t *p), (p), 0) + +/* */ +JPFUN(0, int, set_property, (jack_client_t* c, jack_uuid_t s, const char* k, const char* v, const char* t), (c,s,k,v,t), -1) +JXFUN(0, int, get_property, (jack_uuid_t s, const char* k, char** v, char** t), (s,k,v,t), if (v) *v=NULL; if (t) *t=NULL; return -1;) +JVFUN(0, free_description, (jack_description_t* d, int f), (d,f),) +JXFUN(0, int, get_properties, (jack_uuid_t s, jack_description_t* d), (s,d), if (d) {d->properties = NULL; d->property_cnt = 0;} return -1;) +JXFUN(0, int, get_all_properties, (jack_description_t** d), (d), if (d) *d=NULL; return -1;) +JPFUN(0, int, remove_property, (jack_client_t* c, jack_uuid_t s, const char* k), (c,s,k), -1) +JPFUN(0, int, remove_properties, (jack_client_t* c, jack_uuid_t s), (c,s), -1) +JPFUN(0, int, remove_all_properties, (jack_client_t* c), (c), -1) +JPFUN(0, int, set_property_change_callback, (jack_client_t *c, JackPropertyChangeCallback s, void *a), (c,s,a), -1) +#endif + +/* */ +JCFUN(1, float, get_max_delayed_usecs, 0.0) +JCFUN(1, float, get_xrun_delayed_usecs, 0.0) +JVFUN(0, reset_max_delayed_usecs, (jack_client_t *c), (c),) + +#endif // end USE_WEAK_JACK diff --git a/extern/weakjack/weak_libjack.h b/extern/weakjack/weak_libjack.h new file mode 100644 index 000000000..e23f92389 --- /dev/null +++ b/extern/weakjack/weak_libjack.h @@ -0,0 +1,230 @@ +/* runtime/weak dynamic JACK linking + * + * (C) 2014 Robin Gareus + * + * The wrapped jack API itself is + * (C) 2001 Paul Davis + * (C) 2004 Jack O'Quin + * + * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef _WEAK_JACK_H +#define _WEAK_JACK_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** check if libjack is available + * + * return 0 if libjack is dynamically linked of was + * successfully dl-opened. Otherwise: + * + * -1: library was not initialized + * -2: libjack was not found + * > 0 bitwise flags: + * 1: a required function was not found in libjack + * 2: jack_client_open was not found in libjack + */ +int have_libjack(void); + +#ifdef __cplusplus +} +#endif + +#ifdef USE_WEAK_JACK + +/* */ +#define jack_client_close WJACK_client_close +#define jack_get_client_name WJACK_get_client_name +#define jack_get_sample_rate WJACK_get_sample_rate +#define jack_get_buffer_size WJACK_get_buffer_size +#define jack_frames_since_cycle_start WJACK_frames_since_cycle_start +#define jack_frame_time WJACK_frame_time +#define jack_last_frame_time WJACK_last_frame_time +#define jack_get_time WJACK_get_time +#define jack_cpu_load WJACK_cpu_load +#define jack_is_realtime WJACK_is_realtime + +#define jack_client_name_size WJACK_client_name_size + +#define jack_set_freewheel WJACK_set_freewheel +#define jack_set_buffer_size WJACK_set_buffer_size + +#define jack_on_shutdown WJACK_on_shutdown +#define jack_on_info_shutdown WJACK_on_info_shutdown +#define jack_set_process_callback WJACK_set_process_callback +#define jack_set_freewheel_callback WJACK_set_freewheel_callback +#define jack_set_buffer_size_callback WJACK_set_buffer_size_callback +#define jack_set_sample_rate_callback WJACK_set_sample_rate_callback +#define jack_set_port_registration_callback WJACK_set_port_registration_callback +#define jack_set_port_connect_callback WJACK_set_port_connect_callback +#define jack_set_graph_order_callback WJACK_set_graph_order_callback +#define jack_set_xrun_callback WJACK_set_xrun_callback +#define jack_set_latency_callback WJACK_set_latency_callback +#define jack_set_error_function WJACK_set_error_function +#define jack_set_info_function WJACK_set_info_function + +#define jack_activate WJACK_activate +#define jack_deactivate WJACK_deactivate + +#define jack_recompute_total_latencies WJACK_recompute_total_latencies +#define jack_port_get_total_latency WJACK_port_get_total_latency +#define jack_port_get_latency_range WJACK_port_get_latency_range +#define jack_port_set_latency_range WJACK_port_set_latency_range +#define jack_port_get_buffer WJACK_port_get_buffer +#define jack_port_request_monitor WJACK_port_request_monitor +#define jack_port_ensure_monitor WJACK_port_ensure_monitor +#define jack_port_monitoring_input WJACK_port_monitoring_input + +#define jack_port_name WJACK_port_name +#define jack_port_short_name WJACK_port_short_name +#define jack_port_flags WJACK_port_flags +#define jack_port_is_mine WJACK_port_is_mine +#define jack_port_connected WJACK_port_connected +#define jack_get_ports WJACK_get_ports +#define jack_port_name_size WJACK_port_name_size +#define jack_port_type_size WJACK_port_type_size +#define jack_port_type_get_buffer_size WJACK_port_type_get_buffer_size +#define jack_port_by_name WJACK_port_by_name +#define jack_port_by_id WJACK_port_by_id +#define jack_port_set_name WJACK_port_set_name +#define jack_port_get_aliases WJACK_port_get_aliases +#define jack_port_rename WJACK_port_rename +#define jack_port_disconnect WJACK_port_disconnect +#define jack_port_register WJACK_port_register +#define jack_port_unregister WJACK_port_unregister +#define jack_port_type WJACK_port_type +#define jack_port_get_connections WJACK_port_get_connections +#define jack_port_get_all_connections WJACK_port_get_all_connections +#define jack_connect WJACK_connect +#define jack_disconnect WJACK_disconnect +#define jack_free WJACK_free + +#define jack_cycle_wait WJACK_cycle_wait +#define jack_cycle_signal WJACK_cycle_signal +#define jack_set_process_thread WJACK_set_process_thread +#define jack_set_thread_init_callback WJACK_set_thread_init_callback + +/* */ +#define jack_get_current_transport_frame WJACK_get_current_transport_frame +#define jack_transport_locate WJACK_transport_locate +#define jack_transport_start WJACK_transport_start +#define jack_transport_stop WJACK_transport_stop +#define jack_transport_query WJACK_transport_query +#define jack_set_sync_callback WJACK_set_sync_callback +#define jack_set_timebase_callback WJACK_set_timebase_callback +#define jack_release_timebase WJACK_release_timebase + +/* */ +#define jack_midi_get_event_count WJACK_midi_get_event_count +#define jack_midi_event_get WJACK_midi_event_get +#define jack_midi_event_write WJACK_midi_event_write +#define jack_midi_clear_buffer WJACK_midi_clear_buffer + +/* */ +#define jack_set_session_callback WJACK_set_session_callback +#define jack_session_reply WJACK_session_reply +#define jack_session_event_free WJACK_session_event_free + +/* */ +#define jack_ringbuffer_create WJACK_ringbuffer_create +#define jack_ringbuffer_free WJACK_ringbuffer_free +#define jack_ringbuffer_reset WJACK_ringbuffer_reset +#define jack_ringbuffer_read_advance WJACK_ringbuffer_read_advance +#define jack_ringbuffer_write_advance WJACK_ringbuffer_write_advance +#define jack_ringbuffer_read_space WJACK_ringbuffer_read_space +#define jack_ringbuffer_write_space WJACK_ringbuffer_write_space +#define jack_ringbuffer_read WJACK_ringbuffer_read +#define jack_ringbuffer_write WJACK_ringbuffer_write +#define jack_ringbuffer_mlock WJACK_ringbuffer_mlock +#define jack_ringbuffer_get_read_vector WJACK_ringbuffer_get_read_vector +#define jack_ringbuffer_get_write_vector WJACK_ringbuffer_get_write_vector +#define jack_ringbuffer_peek WJACK_ringbuffer_peek + +/* */ +#define jack_client_real_time_priority WJACK_client_real_time_priority +#define jack_client_max_real_time_priority WJACK_client_max_real_time_priority +#define jack_acquire_real_time_scheduling WJACK_acquire_real_time_scheduling +#define jack_client_create_thread WJACK_client_create_thread +#define jack_drop_real_time_scheduling WJACK_drop_real_time_scheduling +#define jack_client_stop_thread WJACK_client_stop_thread +#define jack_client_kill_thread WJACK_client_kill_thread +#define jack_set_thread_creator WJACK_set_thread_creator + +#define jack_client_open WJACK_client_client_openXXX + +#ifndef NO_JACK_METADATA +/* */ +#define jack_get_uuid_for_client_name WJACK_get_uuid_for_client_name +#define jack_get_client_name_by_uuid WJACK_get_client_name_by_uuid +#define jack_port_uuid WJACK_port_uuid + +#define jack_set_property WJACK_set_property +#define jack_get_property WJACK_get_property +#define jack_free_description WJACK_free_description +#define jack_get_properties WJACK_get_properties +#define jack_get_all_properties WJACK_get_all_properties +#define jack_remove_property WJACK_remove_property +#define jack_remove_properties WJACK_remove_properties +#define jack_remove_all_properties WJACK_remove_all_properties +#define jack_set_property_change_callback WJACK_set_property_change_callback +#endif + +/* */ +#define jack_get_max_delayed_usecs WJACK_get_max_delayed_usecs +#define jack_get_xrun_delayed_usecs WJACK_get_xrun_delayed_usecs +#define jack_reset_max_delayed_usecs WJACK_reset_max_delayed_usecs + +#endif // end USE_WEAK_JACK + +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_JACK_METADATA +#include +#endif + +#ifdef USE_WEAK_JACK + +#undef jack_client_open + +/* var-args hack */ + +#ifdef __cplusplus +extern "C" { +#endif +void (* WJACK_get_client_open (void)) (void); +jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...); +#ifdef __cplusplus +} +#endif + +#define jack_client_open(...) \ +( \ + (WJACK_get_client_open() != NULL) \ + ? ((jack_client_t* (*)(const char *, jack_options_t, jack_status_t *, ...))(WJACK_get_client_open()))(__VA_ARGS__) \ + : WJACK_no_client_open(__VA_ARGS__) \ +) + +#endif // end USE_WEAK_JACK + +#endif // _WEAK_JACK_H diff --git a/papers/clipboard-format.md b/papers/clipboard-format.md index cb353546c..ec6378837 100644 --- a/papers/clipboard-format.md +++ b/papers/clipboard-format.md @@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te org.tildearrow.furnace - Pattern Data (144) ``` -this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre9 is `169`. +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`. the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from. - `0`: note. diff --git a/papers/format.md b/papers/format.md index 66bec724e..f2281f43d 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,13 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 178: Furnace 0.6pre16 +- 177: Furnace 0.6pre15 +- 175: Furnace 0.6pre14 +- 174: Furnace 0.6pre13 +- 173: Furnace 0.6pre12 +- 172: Furnace 0.6pre11 +- 171: Furnace 0.6pre10 - 169: Furnace 0.6pre9 - 166: Furnace 0.6pre8 - 162: Furnace 0.6pre7 diff --git a/res/Info.plist b/res/Info.plist index a7e16ca73..da4c26491 100644 --- a/res/Info.plist +++ b/res/Info.plist @@ -15,17 +15,17 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 0.6pre9 + 0.6pre16 CFBundleName Furnace CFBundlePackageType APPL CFBundleShortVersionString - 0.6pre9 + 0.6pre16 CFBundleSignature ???? CFBundleVersion - 0.6pre9 + 0.6pre16 NSHumanReadableCopyright NSHighResolutionCapable diff --git a/res/docpdf/COPYING b/res/docpdf/COPYING new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/res/docpdf/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/res/docpdf/README.md b/res/docpdf/README.md new file mode 100644 index 000000000..9ac9c881a --- /dev/null +++ b/res/docpdf/README.md @@ -0,0 +1,3 @@ +# thanks ZoomTen + +for https://github.com/ZoomTen/furnace-paper-to-pdf diff --git a/res/docpdf/fonts/Exo2-Italic[wght].ttf b/res/docpdf/fonts/Exo2-Italic[wght].ttf new file mode 100644 index 000000000..46046ca2e Binary files /dev/null and b/res/docpdf/fonts/Exo2-Italic[wght].ttf differ diff --git a/res/docpdf/fonts/Exo2[wght].ttf b/res/docpdf/fonts/Exo2[wght].ttf new file mode 100644 index 000000000..f6ec22983 Binary files /dev/null and b/res/docpdf/fonts/Exo2[wght].ttf differ diff --git a/res/docpdf/fonts/IBMPlexMono-Regular.ttf b/res/docpdf/fonts/IBMPlexMono-Regular.ttf new file mode 100644 index 000000000..651ae32e9 Binary files /dev/null and b/res/docpdf/fonts/IBMPlexMono-Regular.ttf differ diff --git a/res/docpdf/fonts/OFL_exo2.txt b/res/docpdf/fonts/OFL_exo2.txt new file mode 100644 index 000000000..222fbb540 --- /dev/null +++ b/res/docpdf/fonts/OFL_exo2.txt @@ -0,0 +1,93 @@ +Copyright 2013 The Exo 2 Project Authors (https://github.com/NDISCOVER/Exo-2.0) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/res/docpdf/fonts/OFL_plex.txt b/res/docpdf/fonts/OFL_plex.txt new file mode 100644 index 000000000..c35c4c618 --- /dev/null +++ b/res/docpdf/fonts/OFL_plex.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/res/docpdf/make-doc-html.sh b/res/docpdf/make-doc-html.sh new file mode 100755 index 000000000..3af163f43 --- /dev/null +++ b/res/docpdf/make-doc-html.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +echo "compiling Furnace doc (HTML)..." + +if [ -e htmldoc ]; then + rm -r htmldoc +fi + +if [ ! -e .venv ]; then + python3 -m virtualenv .venv || exit 1 +fi + +source .venv/bin/activate + +if [ ! -e .venv/req_installed ]; then + pip install -r requirements.txt || exit 1 + touch .venv/req_installed +fi + +python3 make_htmldoc.py + +echo "copying assets..." +for i in `find ../../doc -name "*.png"`; do + cp "$i" "htmldoc${i#../../doc}" +done diff --git a/res/docpdf/make-doc-pdf.sh b/res/docpdf/make-doc-pdf.sh new file mode 100755 index 000000000..c5d53ae16 --- /dev/null +++ b/res/docpdf/make-doc-pdf.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +echo "compiling Furnace doc (PDF)..." + +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_paper.py > manual.html + +weasyprint -O all -dv manual.html manual.pdf diff --git a/res/docpdf/make_htmldoc.py b/res/docpdf/make_htmldoc.py new file mode 100644 index 000000000..18be36d73 --- /dev/null +++ b/res/docpdf/make_htmldoc.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +import os +import sys + +import markdown +from mdx_gfm import GithubFlavoredMarkdownExtension + +import re + +import logging +logging.basicConfig(format='%(levelname)s: %(message)s' ,stream=sys.stderr, level=logging.INFO) +LOGGER = logging.getLogger('preprocess') + +hosted = False + +# sort the file order +def sort_func(x): + # place "papers/" at the end (like an appendix) + try: + x.index('%sdoc%s' % (os.path.sep, os.path.sep)) + except ValueError: + return 'z' + + # place readmes at the start of each section + try: + rm = x.index('README.md') + return x[:rm] + '0' + except ValueError: + return x + +# make the links work in-pdf +def fix_links(match): + # images + if os.path.splitext(match.group(2))[-1] == '.png': + return '[%s](%s)' % ( + match.group(1), + match.group(2) + ) + + # preserve external urls + elif match.group(2).startswith('http'): + return match.group(0) + + elif match.group(2).endswith('README.md'): + return '[%s](%s)' % ( + match.group(1), + match.group(2).replace('README.md','index.html') + ) + + # fix paths + return '[%s](%s)' % ( + match.group(1), + match.group(2).replace('.md','.html') + ) + +def fix_headings(match): + return '%s#' % ( + match.group(1) + ) + +if __name__ == "__main__": + # check whether hosted mode is on + if len(sys.argv)>1: + if sys.argv[1]=='hosted': + hosted=True + + #-- first, prepare the file list --# + file_list = [] + for i in os.walk('../../doc'): + base_dir, subfolders, files = i + for file_ in filter(lambda x: x.lower().endswith('.md'), files): + file_list.append(os.path.join(base_dir, file_)) + + #-- then, create the document --# + html = '' + + # perform sort + file_list.sort(key=sort_func) + + first = True + + for my_file in file_list: + with open(my_file, 'r') as md: + LOGGER.info("processing file %s" % my_file) + data = md.read() + + # retrieve path + pagePath = 'htmldoc' + os.path.sep + my_file[10:] + pagePathH = re.sub(r'\.md$','.html',pagePath).replace("README.html","index.html") + docDir = pagePath[:pagePath.rfind(os.path.sep)] + LOGGER.info("path: %s" % pagePathH) + + if not os.path.exists(docDir): + os.makedirs(docDir) + + # retrieve title + pageTitle = data.partition('\n')[0].replace("# ","") + + # perform link fixing + data = re.sub(r'\[(.+?)\]\((.+?)\)', fix_links, data) + data = re.sub(r'^\s*(#+)', fix_headings, data, flags=re.MULTILINE) + + # convert + html = ''' + + + + + + + %s + + + %s + + +''' % ( + pageTitle, + markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()]) + ) + + with open(pagePathH, 'w') as ht: + ht.write(html) diff --git a/res/docpdf/make_paper.py b/res/docpdf/make_paper.py new file mode 100644 index 000000000..c02b1eca7 --- /dev/null +++ b/res/docpdf/make_paper.py @@ -0,0 +1,363 @@ +#!/usr/bin/env python3 + +import os +import sys + +import markdown +from mdx_gfm import GithubFlavoredMarkdownExtension + +import weasyprint +import re + +import logging +logging.basicConfig(format='%(levelname)s: %(message)s' ,stream=sys.stderr, level=logging.INFO) +LOGGER = logging.getLogger('preprocess') + +# 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), + os.path.join(os.path.split(my_file)[0], match.group(2)) + ) + + # urls to other files + BASE_URL = 'https://github.com/tildearrow/furnace/tree/master/' + if match.group(2).startswith(BASE_URL): + file_path = match.group(2).split(BASE_URL)[-1] + if os.path.splitext(file_path)[-1] == '': + file_path += '/README.md' + return '[%s](#%s)' % ( + match.group(1), + file_path.replace('/','__') + ) + + # preserve external urls + elif match.group(2).startswith('http'): + return match.group(0) + + # fix paths + act_path = os.path.split(my_file)[0] + '/' + match.group(2) + act_path = os.path.relpath(os.path.abspath(act_path)) + return '[%s](#%s)' % ( + match.group(1), + act_path.replace(os.path.sep,'__') + ) + +def fix_headings(match): + return '%s#' % ( + match.group(1) + ) + +if __name__ == "__main__": + #-- 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 index --# + index = '

contents

    ' + + #-- then, create the document --# + html = '' + + # perform sort + file_list.sort(key=sort_func) + + first = True + + for my_file in file_list: + pageLink = my_file.replace(os.path.sep, "__") + + if pageLink.endswith("__doc__README.md"): + continue + + with open(my_file, 'r') as md: + LOGGER.info("processing file %s" % my_file) + data = md.read() + + # retrieve title + pageTitle = data.partition('\n')[0].replace("# ","") + + if pageLink.endswith("__README.md"): + if first: + first = False + else: + index += '
' + + index += '
  • %s' % ( pageLink, pageTitle, pageLink ) + if pageLink.endswith("__README.md"): + index += '
      ' + else: + index += '' + + # perform link fixing + data = re.sub(r'\[(.+?)\]\((.+?)\)', fix_links, data) + data = re.sub(r'^\s*(#+)', fix_headings, data, flags=re.MULTILINE) + + # each file is its own section + html +='
      %s
      ' % ( + my_file.replace(os.path.sep, "__"), + markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()]) + ) + + # finish index + index += '
  • ' + + # build html + final_html = (''' + + + + + Furnace Manual + + + +
    +
    +
    +
    + +

    Furnace
    User Manual

    +
    +
    + for version 0.6 +
    +
    +
    +
    +
    +
    +

    authors

    +
      +
    • cam900
    • +
    • DeMOSic
    • +
    • Electric Keet
    • +
    • freq-mod
    • +
    • host12prog
    • +
    • nicco1690
    • +
    • tildearrow
    • +
    +

    special thanks to ZoomTen for providing tools which assisted in the production of this document!

    +

    copyright © 2023 tildearrow and other authors.

    +

    this documentation is under the Creative Commons Attribution 3.0 Unported license.

    +

    you may reproduce, modify and/or distribute this documentation provided this copyright notice (including license and attribution) is present and any necessary disclaimers whether modifications have been made.

    +

    this documentation is provided as-is and without warranty of any kind.

    +

    this manual is written for version 0.6 of Furnace.
    it may not necessarily apply to previous or future versions.

    +
    +
    + %s +
    + %s + + + ''' % ( + index, html + ) + ) + + print(final_html) diff --git a/res/docpdf/requirements.txt b/res/docpdf/requirements.txt new file mode 100644 index 000000000..d06226b3c --- /dev/null +++ b/res/docpdf/requirements.txt @@ -0,0 +1,17 @@ +Brotli==1.0.9 +cffi==1.15.1 +cssselect2==0.7.0 +fonttools==4.39.3 +html5lib==1.1 +Markdown==3.4.3 +Pillow==9.4.0 +mdx-breakless-lists==1.0.1 +py-gfm==2.0.0 +pycparser==2.21 +pydyf==0.5.0 +pyphen==0.14.0 +six==1.16.0 +tinycss2==1.2.1 +weasyprint==58.1 +webencodings==0.5.1 +zopfli==0.2.2 diff --git a/res/furnace.appdata.xml b/res/furnace.appdata.xml.in similarity index 79% rename from res/furnace.appdata.xml rename to res/furnace.appdata.xml.in index 5055d0df9..6103fef1f 100644 --- a/res/furnace.appdata.xml +++ b/res/furnace.appdata.xml.in @@ -4,13 +4,14 @@ Furnace Open-source chiptune tracker + https://github.com/tildearrow/furnace CC0-1.0 GPL-2.0-or-later

    - the biggest chiptune tracker ever made! + Furnace - the biggest chiptune tracker ever made!

    it allows you to create songs using a music tracker interface for several computer/game console/arcade sound chips. @@ -19,7 +20,7 @@ it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability.

    - rationale for intense profanity: the tracker itself is clean, but a few demo songs and instruments contain a small amount of strong language. + rationale for intense profanity: the tracker itself is clean, but a few demo songs and instruments contain a small amount of strong language.

    @@ -34,4 +35,4 @@ https://tildearrow.org/storage/images/furnace.png - + diff --git a/res/make-appdata.sh b/res/make-appdata.sh new file mode 100755 index 000000000..78d1865ee --- /dev/null +++ b/res/make-appdata.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then + echo "usage: $0 input output" + exit 1 +fi + +#echo "generating $2..." + +cat "$1" > "$2" + +echo " " >> "$2" + +for i in `git log --tags='v*' --no-walk --format="%as/%(describe:tags)"`; do + releaseDate=${i%/*} + releaseVer=${i#*/} + releaseVerProper=$releaseVer + case $releaseVer in + *pre*) + releaseType=development + releaseVerProper="${releaseVer%pre*}~pre${releaseVer#*pre}" + ;; + *) releaseType=stable;; + esac + echo " " >> "$2" + echo " https://github.com/tildearrow/furnace/releases/tag/$releaseVer" >> "$2" + echo " " >> "$2" +done + +echo " " >> "$2" + +echo "" >> "$2" + +#echo "done." diff --git a/res/releaseReadme/stable-linux.txt b/res/releaseReadme/stable-linux.txt index 3eb6e77d9..979720a83 100644 --- a/res/releaseReadme/stable-linux.txt +++ b/res/releaseReadme/stable-linux.txt @@ -1,5 +1,35 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. extract this archive, and run `furnace` to get started. + +# help + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/res/releaseReadme/stable-mac.txt b/res/releaseReadme/stable-mac.txt index fb84fb870..d2a50cd89 100644 --- a/res/releaseReadme/stable-mac.txt +++ b/res/releaseReadme/stable-mac.txt @@ -1,8 +1,9 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. + +# help -move Furnace to Applications (or some other place). if you are using a recent version of macOS, you may get an error saying that Furnace is damaged. in that case, open Terminal, and type this: @@ -13,3 +14,32 @@ xattr -d com.apple.quarantine /path/to/Furnace.app (replace `/path/to/Furnace.app` with the path where Furnace.app is located, e.g. `/Applications/Furnace.app`) you may need to reboot after doing this before launching Furnace. + + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/res/releaseReadme/stable-win.txt b/res/releaseReadme/stable-win.txt index 22eed14ca..562037c2c 100644 --- a/res/releaseReadme/stable-win.txt +++ b/res/releaseReadme/stable-win.txt @@ -1,5 +1,35 @@ # Furnace (chiptune tracker) -thank you for downloading Furnace! I hope you enjoy using it. +thank you for acquiring Furnace! I hope you enjoy using it. extract this archive, and run furnace.exe to get started. + +# help + +some technical computing background is recommended for the best experience. +be sure to read the `manual.pdf` file for information on how to use this program. + +if you find issues (e.g. bugs or annoyances), report them. links below. + +# links + +- Furnace on GitHub (project page and issue tracker): https://github.com/tildearrow/furnace + - issues: https://github.com/tildearrow/furnace/issues + - discussion: https://github.com/tildearrow/furnace/discussions +- Furnace on Revolt: https://rvlt.gg/GRPS6tmc +- Furnace on Discord: https://discord.gg/EfrwT2wq7z +- online manual: https://tildearrow.org/furnace/doc/v0.6/ + +# notes + +copyright (C) 2021-2023 tildearrow and contributors. + +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +Furnace is NOT affiliated with Delek or DefleMask in any form, regardless of its ability to load and save the .dmf, .dmp and .dmw file formats. +additionally, Furnace does not intend to replace DefleMask, nor any other program. diff --git a/scripts/release-linux-AppImage.sh b/scripts/release-linux-AppImage.sh index 4cf8a8cd4..c535d2f6e 100755 --- a/scripts/release-linux-AppImage.sh +++ b/scripts/release-linux-AppImage.sh @@ -30,8 +30,8 @@ cp -v ../../../res/logo.png furnace.png || exit 1 ln -s furnace.png .DirIcon || exit 1 cp -v ../../../res/furnace.desktop . || exit 1 #mkdir -p usr/share/metainfo || exit 1 -cp -v ../../../res/furnace.appdata.xml usr/share/metainfo/org.tildearrow.furnace.metainfo.xml || exit 1 -rm usr/share/metainfo/furnace.appdata.xml || exit 1 +#cp -v ../../../res/furnace.appdata.xml usr/share/metainfo/org.tildearrow.furnace.metainfo.xml || exit 1 +#rm usr/share/metainfo/furnace.appdata.xml || exit 1 cp -v ../../../res/AppRun . || exit 1 #cp /usr/lib/libm.so.6 usr/lib/ || exit 1 diff --git a/scripts/release-linux.sh b/scripts/release-linux.sh index 0c744296f..bb6d944f5 100755 --- a/scripts/release-linux.sh +++ b/scripts/release-linux.sh @@ -14,7 +14,8 @@ fi cd linuxbuild -cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-O3" -DCMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wno-unused-parameter -Werror" -DWITH_DEMOS=ON -DWITH_INSTRUMENTS=ON -DWITH_WAVETABLES=ON .. || exit 1 +# -DWITH_PORTAUDIO=OFF: Ubuntu 16.04 doesn't like it +cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-O3" -DCMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wno-unused-parameter -Werror" -DWITH_PORTAUDIO=OFF -DWITH_DEMOS=ON -DWITH_INSTRUMENTS=ON -DWITH_WAVETABLES=ON .. || exit 1 make -j4 || exit 1 cd .. @@ -49,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/furproto/manual.pdf" > manual.pdf rmdir usr || exit 1 strip -s furnace diff --git a/scripts/release-win32.sh b/scripts/release-win32.sh index d189ca6de..58e3fb38f 100755 --- a/scripts/release-win32.sh +++ b/scripts/release-win32.sh @@ -25,13 +25,14 @@ 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 diff --git a/scripts/release-win64.sh b/scripts/release-win64.sh index 9183007b5..482c1698c 100755 --- a/scripts/release-win64.sh +++ b/scripts/release-win64.sh @@ -25,13 +25,14 @@ 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 diff --git a/scripts/release-winxp.sh b/scripts/release-winxp.sh index 9242bfc6c..91b4397cd 100755 --- a/scripts/release-winxp.sh +++ b/scripts/release-winxp.sh @@ -25,13 +25,14 @@ cd release/winxp cp ../../LICENSE LICENSE.txt || exit 1 cp ../../xpbuild/furnace.exe . || exit 1 -cp ../../README.md README.txt || exit 1 +cp ../../res/releaseReadme/stable-win.txt README.txt || exit 1 cp -r ../../papers papers || exit 1 -cp -r ../../doc doc || exit 1 cp -r ../../demos demos || exit 1 cp -r ../../instruments instruments || exit 1 cp -r ../../wavetables wavetables || exit 1 +cp ../../res/docpdf/manual.pdf . || exit 1 + i686-w64-mingw32-strip -s furnace.exe || exit 1 # patch to remove GetTickCount64 diff --git a/src/audio/jack.cpp b/src/audio/jack.cpp index 2ffe19b63..64c106c54 100644 --- a/src/audio/jack.cpp +++ b/src/audio/jack.cpp @@ -198,10 +198,19 @@ String TAAudioJACK::printStatus(jack_status_t status) { bool TAAudioJACK::init(TAAudioDesc& request, TAAudioDesc& response) { if (initialized) return false; - if (jack_client_open==NULL) { + int haveJACK=have_libjack(); + if (haveJACK==-1) { + logE("JACK library not initialized!"); + return false; + } + if (haveJACK==-2) { logE("JACK not installed!"); return false; } + if (haveJACK!=0) { + logE("JACK symbol error!"); + return false; + } desc=request; desc.outFormat=TA_AUDIO_FORMAT_F32; diff --git a/src/audio/jack.h b/src/audio/jack.h index 8018d6c20..41d76824b 100644 --- a/src/audio/jack.h +++ b/src/audio/jack.h @@ -18,8 +18,7 @@ */ #include "taAudio.h" -#include -#include +#include "../../extern/weakjack/weak_libjack.h" class TAAudioJACK: public TAAudio { jack_client_t* ac; diff --git a/src/audio/pa.cpp b/src/audio/pa.cpp index e2bdfdd8d..3ae960860 100644 --- a/src/audio/pa.cpp +++ b/src/audio/pa.cpp @@ -18,7 +18,6 @@ */ #include -#include #include "../ta-log.h" #include "pa.h" #ifdef _WIN32 diff --git a/src/audio/sdlAudio.cpp b/src/audio/sdlAudio.cpp index ddbe85947..e01f073c8 100644 --- a/src/audio/sdlAudio.cpp +++ b/src/audio/sdlAudio.cpp @@ -18,7 +18,6 @@ */ #include -#include #include "../ta-log.h" #include "sdlAudio.h" diff --git a/src/audio/taAudio.h b/src/audio/taAudio.h index 20491dbbe..0b6f530c6 100644 --- a/src/audio/taAudio.h +++ b/src/audio/taAudio.h @@ -21,8 +21,8 @@ #define _TAAUDIO_H #include "../ta-utils.h" #include -#include -#include +#include "../fixedQueue.h" +#include "../pch.h" struct SampleRateChangeEvent { double rate; @@ -124,7 +124,7 @@ struct TAMidiMessage { class TAMidiIn { public: - std::queue queue; + FixedQueue queue; virtual bool gather(); bool next(TAMidiMessage& where); virtual bool isDeviceOpen(); @@ -139,7 +139,7 @@ class TAMidiIn { }; class TAMidiOut { - std::queue queue; + FixedQueue queue; public: virtual bool send(const TAMidiMessage& what); virtual bool isDeviceOpen(); diff --git a/src/baseutils.h b/src/baseutils.h index 0e1b31911..7e3d8e8eb 100644 --- a/src/baseutils.h +++ b/src/baseutils.h @@ -20,7 +20,7 @@ #ifndef _BASEUTILS_H #define _BASEUTILS_H -#include +#include "pch.h" std::string taEncodeBase64(const std::string& data); std::string taDecodeBase64(const char* str); diff --git a/src/engine/config.h b/src/engine/config.h index 12105d696..b9f5e43e1 100644 --- a/src/engine/config.h +++ b/src/engine/config.h @@ -21,8 +21,6 @@ #define _DIVCONFIG_H #include "../ta-utils.h" -#include -#include #include class DivConfig { diff --git a/src/engine/configEngine.cpp b/src/engine/configEngine.cpp index f793d35c2..123a19a81 100644 --- a/src/engine/configEngine.cpp +++ b/src/engine/configEngine.cpp @@ -61,9 +61,11 @@ void DivEngine::initConfDir() { return; } #else - // TODO this should check XDG_CONFIG_HOME first + char* xdgConfigHome=getenv("XDG_CONFIG_HOME"); char* home=getenv("HOME"); - if (home==NULL) { + if (xdgConfigHome) { + configPath=xdgConfigHome; + } else if (home==NULL) { int uid=getuid(); struct passwd* entry=getpwuid(uid); if (entry==NULL) { @@ -79,8 +81,9 @@ void DivEngine::initConfDir() { #ifdef __APPLE__ configPath+="/Library/Application Support"; #else - // FIXME this doesn't honour XDG_CONFIG_HOME *at all* - configPath+="/.config"; + if (xdgConfigHome==NULL) { + configPath+="/.config"; + } #endif // __APPLE__ #endif // __HAIKU__ #ifdef __APPLE__ diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 0ad264e53..ecb2ebc6e 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -22,7 +22,7 @@ #include #include -#include +#include "../pch.h" #include "config.h" #include "chipUtils.h" diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 86eebfa31..4d07acd45 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -396,13 +396,13 @@ int DivEngine::loadSampleROMs() { return error; } -void DivEngine::renderSamplesP() { +void DivEngine::renderSamplesP(int whichSample) { BUSY_BEGIN; - renderSamples(); + renderSamples(whichSample); BUSY_END; } -void DivEngine::renderSamples() { +void DivEngine::renderSamples(int whichSample) { sPreview.sample=-1; sPreview.pos=0; sPreview.dir=false; @@ -418,8 +418,12 @@ void DivEngine::renderSamples() { } // step 1: render samples - for (int i=0; irender(formatMask); + if (whichSample==-1) { + for (int i=0; irender(formatMask); + } + } else if (whichSample>=0 && whichSamplerender(formatMask); } // step 2: render samples to dispatch @@ -879,6 +883,119 @@ void DivEngine::clearSubSongs() { BUSY_END; } +void DivEngine::delUnusedIns() { + BUSY_BEGIN; + saveLock.lock(); + + bool isUsed[256]; + memset(isUsed,0,256*sizeof(bool)); + + // scan + for (int i=0; ipat[i].data[k]==NULL) continue; + for (int l=0; lpatLen; l++) { + if (song.subsong[j]->pat[i].data[k]->data[l][2]>=0 && song.subsong[j]->pat[i].data[k]->data[l][2]<256) { + isUsed[song.subsong[j]->pat[i].data[k]->data[l][2]]=true; + } + } + } + } + } + + // delete + for (int i=0; itype==DIV_INS_PCE && i->amiga.useSample) || + i->type==DIV_INS_MSM6258 || + i->type==DIV_INS_MSM6295 || + i->type==DIV_INS_ADPCMA || + i->type==DIV_INS_ADPCMB || + i->type==DIV_INS_SEGAPCM || + i->type==DIV_INS_QSOUND || + i->type==DIV_INS_YMZ280B || + i->type==DIV_INS_RF5C68 || + i->type==DIV_INS_AMIGA || + i->type==DIV_INS_MULTIPCM || + (i->type==DIV_INS_MIKEY && i->amiga.useSample) || + (i->type==DIV_INS_X1_010 && i->amiga.useSample) || + (i->type==DIV_INS_SWAN && i->amiga.useSample) || + (i->type==DIV_INS_AY && i->amiga.useSample) || + (i->type==DIV_INS_AY8930 && i->amiga.useSample) || + (i->type==DIV_INS_VRC6 && i->amiga.useSample) || + (i->type==DIV_INS_SU && i->amiga.useSample) || + i->type==DIV_INS_SNES || + i->type==DIV_INS_ES5506 || + i->type==DIV_INS_K007232 || + i->type==DIV_INS_GA20 || + i->type==DIV_INS_K053260 || + i->type==DIV_INS_C140 || + i->type==DIV_INS_C219) { + if (i->amiga.initSample>=0 && i->amiga.initSampleamiga.initSample]=true; + } + if (i->amiga.useNoteMap) { + for (int j=0; j<120; j++) { + if (i->amiga.noteMap[j].map>=0 && i->amiga.noteMap[j].mapamiga.noteMap[j].map]=true; + } + } + } + } + } + + // delete + for (int i=0; imidiOut->send(TAMidiMessage(TA_MIDI_MACHINE_PLAY,0,0)); } + bool didItPlay=playing; BUSY_END; + return didItPlay; } -void DivEngine::playToRow(int row) { +bool DivEngine::playToRow(int row) { BUSY_BEGIN_SOFT; sPreview.sample=-1; sPreview.wave=-1; @@ -1685,7 +1804,9 @@ void DivEngine::playToRow(int row) { for (int i=0; i=0 && index<(int)song.ins.size()) { for (int i=0; inotifyInsDeletion(song.ins[index]); @@ -2260,6 +2386,12 @@ void DivEngine::delInstrument(int index) { removeAsset(song.insDir,index); checkAssetDir(song.insDir,song.ins.size()); } +} + +void DivEngine::delInstrument(int index) { + BUSY_BEGIN; + saveLock.lock(); + delInstrumentUnsafe(index); saveLock.unlock(); BUSY_END; } @@ -2440,9 +2572,7 @@ DivWavetable* DivEngine::waveFromFile(const char* path, bool addRaw) { return wave; } -void DivEngine::delWave(int index) { - BUSY_BEGIN; - saveLock.lock(); +void DivEngine::delWaveUnsafe(int index) { if (index>=0 && index<(int)song.wave.size()) { delete song.wave[index]; song.wave.erase(song.wave.begin()+index); @@ -2450,6 +2580,12 @@ void DivEngine::delWave(int index) { removeAsset(song.waveDir,index); checkAssetDir(song.waveDir,song.wave.size()); } +} + +void DivEngine::delWave(int index) { + BUSY_BEGIN; + saveLock.lock(); + delWaveUnsafe(index); saveLock.unlock(); BUSY_END; } @@ -2494,12 +2630,10 @@ int DivEngine::addSamplePtr(DivSample* which) { return sampleCount; } -void DivEngine::delSample(int index) { - BUSY_BEGIN; +void DivEngine::delSampleUnsafe(int index, bool render) { sPreview.sample=-1; sPreview.pos=0; sPreview.dir=false; - saveLock.lock(); if (index>=0 && index<(int)song.sample.size()) { delete song.sample[index]; song.sample.erase(song.sample.begin()+index); @@ -2523,8 +2657,14 @@ void DivEngine::delSample(int index) { } } - renderSamples(); + if (render) renderSamples(); } +} + +void DivEngine::delSample(int index) { + BUSY_BEGIN; + saveLock.lock(); + delSampleUnsafe(index); saveLock.unlock(); BUSY_END; } @@ -3113,6 +3253,10 @@ void DivEngine::setMetronomeVol(float vol) { metroVol=vol; } +void DivEngine::setSamplePreviewVol(float vol) { + previewVol=vol; +} + void DivEngine::setConsoleMode(bool enable) { consoleMode=enable; } @@ -3260,6 +3404,7 @@ void DivEngine::quitDispatch() { playing=false; curSpeed=0; endOfSong=false; + stepPlay=0; ticks=0; tempoAccum=0; curRow=0; @@ -3316,6 +3461,7 @@ bool DivEngine::initAudioBackend() { clampSamples=getConfInt("clampSamples",0); lowLatency=getConfInt("lowLatency",0); metroVol=(float)(getConfInt("metroVol",100))/100.0f; + previewVol=(float)(getConfInt("sampleVol",50))/100.0f; midiOutClock=getConfInt("midiOutClock",0); midiOutTime=getConfInt("midiOutTime",0); midiOutTimeRate=getConfInt("midiOutTimeRate",0); @@ -3323,6 +3469,8 @@ bool DivEngine::initAudioBackend() { midiOutMode=getConfInt("midiOutMode",DIV_MIDI_MODE_NOTE); if (metroVol<0.0f) metroVol=0.0f; if (metroVol>2.0f) metroVol=2.0f; + if (previewVol<0.0f) previewVol=0.0f; + if (previewVol>1.0f) previewVol=1.0f; renderPoolThreads=getConfInt("renderPoolThreads",0); if (lowLatency) logI("using low latency mode."); diff --git a/src/engine/engine.h b/src/engine/engine.h index f94cb3e1f..1fd054635 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -30,14 +30,10 @@ #include "cmdStream.h" #include "../audio/taAudio.h" #include "blip_buf.h" -#include #include #include #include -#include -#include -#include -#include +#include "../fixedQueue.h" class DivWorkPool; @@ -58,8 +54,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "dev170" -#define DIV_ENGINE_VERSION 170 +#define DIV_VERSION "0.6pre16" +#define DIV_ENGINE_VERSION 178 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 @@ -176,14 +172,28 @@ struct DivChannelState { }; struct DivNoteEvent { - int channel, ins, note, volume; - bool on; + signed char channel; + unsigned char ins; + signed char note, volume; + bool on, nop, pad1, pad2; DivNoteEvent(int c, int i, int n, int v, bool o): channel(c), ins(i), note(n), volume(v), - on(o) {} + on(o), + nop(false), + pad1(false), + pad2(false) {} + DivNoteEvent(): + channel(-1), + ins(0), + note(0), + volume(0), + on(false), + nop(true), + pad1(false), + pad2(false) {} }; struct DivDispatchContainer { @@ -428,11 +438,11 @@ class DivEngine { DivAudioExportModes exportMode; double exportFadeOut; DivConfig conf; - std::deque pendingNotes; + FixedQueue pendingNotes; // bitfield unsigned char walked[8192]; bool isMuted[DIV_MAX_CHANS]; - std::mutex isBusy, saveLock; + std::mutex isBusy, saveLock, playPosLock; String configPath; String configFile; String lastError; @@ -490,6 +500,7 @@ class DivEngine { float metroFreq, metroPos; float metroAmp; float metroVol; + float previewVol; size_t totalProcessed; @@ -708,11 +719,11 @@ class DivEngine { // find song loop position void walkSong(int& loopOrder, int& loopRow, int& loopEnd); - // play - void play(); + // play (returns whether successful) + bool play(); - // play to row - void playToRow(int row); + // play to row (returns whether successful) + bool playToRow(int row); // play by one row void stepOne(int row); @@ -729,6 +740,9 @@ class DivEngine { int getSamplePreviewPos(); double getSamplePreviewRate(); + // set sample preview volume (1.0 = 100%) + void setSamplePreviewVol(float vol); + // trigger sample preview void previewSample(int sample, int note=-1, int pStart=-1, int pEnd=-1); void stopSamplePreview(); @@ -830,6 +844,9 @@ class DivEngine { // get current row int getRow(); + // synchronous get order/row + void getPlayPos(int& order, int& row); + // get beat/bar int getElapsedBars(); int getElapsedBeats(); @@ -882,13 +899,14 @@ class DivEngine { // get instrument from file // if the returned vector is empty then there was an error. - std::vector instrumentFromFile(const char* path, bool loadAssets=true); + std::vector instrumentFromFile(const char* path, bool loadAssets=true, bool readInsName=true); // load temporary instrument void loadTempIns(DivInstrument* which); // delete instrument void delInstrument(int index); + void delInstrumentUnsafe(int index); // add wavetable int addWave(); @@ -901,6 +919,7 @@ class DivEngine { // delete wavetable void delWave(int index); + void delWaveUnsafe(int index); // add sample int addSample(); @@ -916,6 +935,7 @@ class DivEngine { // delete sample void delSample(int index); + void delSampleUnsafe(int index, bool render=true); // add order void addOrder(int pos, bool duplicate, bool where); @@ -1064,10 +1084,14 @@ class DivEngine { unsigned int getSampleFormatMask(); // UNSAFE render samples - only execute when locked - void renderSamples(); + void renderSamples(int whichSample=-1); // public render samples - void renderSamplesP(); + // values for whichSample + // -2: don't render anything - just update chip sample memory + // -1: render all samples + // >=0: render specific sample + void renderSamplesP(int whichSample=-1); // public swap channels void swapChannelsP(int src, int dest); @@ -1091,6 +1115,11 @@ class DivEngine { // clear all subsong data void clearSubSongs(); + // optimize assets + void delUnusedIns(); + void delUnusedWaves(); + void delUnusedSamples(); + // change system void changeSystem(int index, DivSystem which, bool preserveOrder=true); @@ -1270,6 +1299,7 @@ class DivEngine { metroPos(0), metroAmp(0.0f), metroVol(1.0f), + previewVol(1.0f), totalProcessed(0), renderPoolThreads(0), renderPool(NULL), diff --git a/src/engine/export.h b/src/engine/export.h index 07354fdb3..3a51ee236 100644 --- a/src/engine/export.h +++ b/src/engine/export.h @@ -22,7 +22,7 @@ #include "song.h" #include -#include +#include "../pch.h" class DivEngine; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 746f59046..6f7065ef4 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1058,6 +1058,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.systemFlags[0].set("keyPriority",false); } + // OPM broken pitch + if (ds.system[0]==DIV_SYSTEM_YM2151) { + ds.systemFlags[0].set("brokenPitch",true); + } + ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); if (active) quitDispatch(); @@ -2792,6 +2797,11 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { pat->data[j][4+(k<<1)]=reader.readS(); pat->data[j][5+(k<<1)]=reader.readS(); } + if (pat->data[j][0]==0 && pat->data[j][1]!=0) { + logD("what? %d:%d:%d note %d octave %d",chan,i,j,pat->data[j][0],pat->data[j][1]); + pat->data[j][0]=12; + pat->data[j][1]--; + } } if (ds.version>=51) { @@ -2971,6 +2981,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // OPM/OPZ slide compat + if (ds.version<176) { + for (int i=0; i& ret, S } } -std::vector DivEngine::instrumentFromFile(const char* path, bool loadAssets) { +std::vector DivEngine::instrumentFromFile(const char* path, bool loadAssets, bool readInsName) { std::vector ret; warnings=""; @@ -1921,12 +1921,17 @@ std::vector DivEngine::instrumentFromFile(const char* path, bool reader.seek(dataPtr,SEEK_SET); } + ins->name=stripPath; + if (ins->readInsData(reader,version,loadAssets?(&song):NULL)!=DIV_DATA_SUCCESS) { lastError="invalid instrument header/data!"; delete ins; delete[] buf; return ret; } else { + if (!readInsName) { + ins->name=stripPath; + } ret.push_back(ins); } } catch (EndOfFileException& e) { diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index ac9441adc..1fb503543 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -274,10 +274,13 @@ DivSample* DivEngine::sampleFromFile(const char* path) { { // There's no documentation on libsndfile detune range, but the code // implies -50..50. Yet when loading a file you can get a >50 value. + // disabled for now + /* if(inst.detune > 50) inst.detune = inst.detune - 100; short pitch = ((0x3c-inst.basenote)*100) + inst.detune; sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); + */ if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) { sample->loop=true; diff --git a/src/engine/filter.cpp b/src/engine/filter.cpp index 5c8ab218e..ee325052b 100644 --- a/src/engine/filter.cpp +++ b/src/engine/filter.cpp @@ -26,6 +26,7 @@ float* DivFilterTables::cubicTable=NULL; float* DivFilterTables::sincTable=NULL; float* DivFilterTables::sincTable8=NULL; float* DivFilterTables::sincIntegralTable=NULL; +float* DivFilterTables::sincIntegralSmallTable=NULL; // portions from Schism Tracker (scripts/lutgen.c) // licensed under same license as this program. @@ -106,3 +107,25 @@ float* DivFilterTables::getSincIntegralTable() { } return sincIntegralTable; } + +float* DivFilterTables::getSincIntegralSmallTable() { + if (sincIntegralSmallTable==NULL) { + logD("initializing small sinc integral table."); + sincIntegralSmallTable=new float[512]; + + sincIntegralSmallTable[0]=-0.5f; + for (int i=1; i<512; i++) { + int mapped=((i&63)<<3)|(i>>6); + int mappedPrev=(((i-1)&63)<<3)|((i-1)>>6); + double x=(double)i*M_PI/64.0; + double sinc=sin(x)/x; + sincIntegralSmallTable[mapped]=sincIntegralSmallTable[mappedPrev]+(sinc/64.0); + } + + for (int i=0; i<512; i++) { + int mapped=((i&63)<<3)|(i>>6); + sincIntegralSmallTable[mapped]*=pow(cos(M_PI*(double)i/1024.0),2.0); + } + } + return sincIntegralSmallTable; +} \ No newline at end of file diff --git a/src/engine/filter.h b/src/engine/filter.h index 1e6597e4f..1406ee145 100644 --- a/src/engine/filter.h +++ b/src/engine/filter.h @@ -23,6 +23,7 @@ class DivFilterTables { static float* sincTable; static float* sincTable8; static float* sincIntegralTable; + static float* sincIntegralSmallTable; /** * get a 1024x4 cubic spline table. @@ -47,4 +48,10 @@ class DivFilterTables { * @return the table. */ static float* getSincIntegralTable(); + + /** + * get a 32x8 one-side sine-windowed sinc integral table. + * @return the table. + */ + static float* getSincIntegralSmallTable(); }; \ No newline at end of file diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 28cb99bca..6b871155c 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -719,7 +719,7 @@ void DivInstrument::writeFeatureX1(SafeWriter* w) { FEATURE_END; } -void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { +void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bool insName) { size_t blockStartSeek=0; size_t blockEndSeek=0; size_t slSeek=0; @@ -1021,7 +1021,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { } // check ins name - if (!name.empty()) { + if (!name.empty() && insName) { featureNA=true; } @@ -3380,7 +3380,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version, DivS return readInsDataOld(reader,version); } -bool DivInstrument::save(const char* path, bool oldFormat, DivSong* song) { +bool DivInstrument::save(const char* path, bool oldFormat, DivSong* song, bool writeInsName) { SafeWriter* w=new SafeWriter(); w->init(); @@ -3397,14 +3397,14 @@ bool DivInstrument::save(const char* path, bool oldFormat, DivSong* song) { // pointer to data w->writeI(32); - // currently reserved (TODO; wavetable and sample here) + // reserved w->writeS(0); w->writeS(0); w->writeI(0); putInsData(w); } else { - putInsData2(w,true,song); + putInsData2(w,true,song,writeInsName); } FILE* outFile=ps_fopen(path,"wb"); diff --git a/src/engine/instrument.h b/src/engine/instrument.h index a019198f0..a804f87f2 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -22,7 +22,7 @@ #include "safeWriter.h" #include "dataErrors.h" #include "../ta-utils.h" -#include +#include "../pch.h" struct DivSong; @@ -720,7 +720,7 @@ struct DivInstrument { * save the instrument to a SafeWriter using new format. * @param w the SafeWriter in question. */ - void putInsData2(SafeWriter* w, bool fui=false, const DivSong* song=NULL); + void putInsData2(SafeWriter* w, bool fui=false, const DivSong* song=NULL, bool insName=true); /** * read instrument data in .fui format. @@ -735,9 +735,10 @@ struct DivInstrument { * @param path file path. * @param oldFormat whether to save in legacy Furnace ins format. * @param song if new format, a DivSong to read wavetables and samples. + * @param writeInsName whether to write the instrument name or not. ignored if old format. * @return whether it was successful. */ - bool save(const char* path, bool oldFormat=false, DivSong* song=NULL); + bool save(const char* path, bool oldFormat=false, DivSong* song=NULL, bool writeInsName=true); /** * save this instrument to a file in .dmp format. diff --git a/src/engine/pattern.h b/src/engine/pattern.h index 257ce7eca..8bb8fa21e 100644 --- a/src/engine/pattern.h +++ b/src/engine/pattern.h @@ -18,7 +18,7 @@ */ #include "safeReader.h" -#include +#include "../pch.h" struct DivPattern { String name; diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 26ad689a1..ab26b5b08 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -197,10 +197,10 @@ void DivPlatformArcade::tick(bool sysTick) { if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { - chan[i].pitch2+=chan[i].std.pitch.val; + chan[i].pitch2+=chan[i].std.pitch.val*(brokenPitch?2:1); CLAMP_VAR(chan[i].pitch2,-32768,32767); } else { - chan[i].pitch2=chan[i].std.pitch.val; + chan[i].pitch2=chan[i].std.pitch.val*(brokenPitch?2:1); } chan[i].freqChanged=true; } @@ -354,18 +354,18 @@ void DivPlatformArcade::tick(bool sysTick) { for (int i=0; i<8; i++) { if (chan[i].freqChanged) { - chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2; + chan[i].freq=chan[i].baseFreq+chan[i].pitch-128+chan[i].pitch2; if (!parent->song.oldArpStrategy) { if (chan[i].fixedArp) { - chan[i].freq=(chan[i].baseNoteOverride<<6)+(chan[i].pitch>>1)-64+chan[i].pitch2; + chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+chan[i].pitch2; } else { - chan[i].freq+=chan[i].arpOff<<6; + chan[i].freq+=chan[i].arpOff<<7; } } if (chan[i].freq<0) chan[i].freq=0; - if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1; - immWrite(i+0x28,hScale(chan[i].freq>>6)); - immWrite(i+0x30,chan[i].freq<<2); + if (chan[i].freq>=(95<<7)) chan[i].freq=(95<<7)-1; + immWrite(i+0x28,hScale(chan[i].freq>>7)); + immWrite(i+0x30,((chan[i].freq<<1)&0xfc)); hardResetElapsed+=2; chan[i].freqChanged=false; } @@ -534,13 +534,13 @@ int DivPlatformArcade::dispatch(DivCommand c) { int newFreq; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { - newFreq=chan[c.chan].baseFreq+c.value; + newFreq=chan[c.chan].baseFreq+c.value*(brokenPitch?2:1); if (newFreq>=destFreq) { newFreq=destFreq; return2=true; } } else { - newFreq=chan[c.chan].baseFreq-c.value; + newFreq=chan[c.chan].baseFreq-c.value*(brokenPitch?2:1); if (newFreq<=destFreq) { newFreq=destFreq; return2=true; @@ -932,7 +932,9 @@ void DivPlatformArcade::setFlags(const DivConfig& flags) { } CHECK_CUSTOM_CLOCK; - baseFreqOff=round(768.0*(log((COLOR_NTSC/(double)chipClock))/log(2.0))); + baseFreqOff=round(1536.0*(log((COLOR_NTSC/(double)chipClock))/log(2.0))); + + brokenPitch=flags.getBool("brokenPitch",false); rate=chipClock/64; for (int i=0; i<8; i++) { diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 2948f3b85..354557fda 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -20,7 +20,7 @@ #ifndef _AY_H #define _AY_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/ay8910.h" class DivPlatformAY8910: public DivDispatch { diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 0ff69ad40..ba2f9abea 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -20,7 +20,7 @@ #ifndef _AY8930_H #define _AY8930_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/ay8910.h" class DivPlatformAY8930: public DivDispatch { diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index ed9426674..30ec91f0d 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_FREQBASE (is219?74448896:12582912) @@ -152,11 +151,18 @@ void DivPlatformC140::tick(bool sysTick) { } if (is219) { if (chan[i].std.duty.had) { - chan[i].noise=chan[i].std.duty.val&1; - chan[i].invert=chan[i].std.duty.val&2; - chan[i].surround=chan[i].std.duty.val&4; - chan[i].freqChanged=true; - chan[i].writeCtrl=true; + unsigned char singleByte=( + (chan[i].noise?1:0)| + (chan[i].invert?2:0)| + (chan[i].surround?4:0) + ); + if (singleByte!=(chan[i].std.duty.val&7)) { + chan[i].noise=chan[i].std.duty.val&1; + chan[i].invert=chan[i].std.duty.val&2; + chan[i].surround=chan[i].std.duty.val&4; + chan[i].freqChanged=true; + chan[i].writeCtrl=true; + } } } if (chan[i].std.pitch.had) { @@ -209,7 +215,7 @@ void DivPlatformC140::tick(bool sysTick) { if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; if (is219) { - ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_C219)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable() || chan[i].noise)?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_C219)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); } else { ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); } @@ -228,11 +234,15 @@ void DivPlatformC140::tick(bool sysTick) { start=sampleOff[chan[i].sample]&0xffff; end=MIN(start+s->length8-1,65535); } + } else if (chan[i].noise && is219) { + bank=groupBank[i>>2]; + start=0; + end=1; } if (chan[i].audPos>0) { start=MIN(start+(MIN(chan[i].audPos,s->length8)>>1),65535); } - if (s->isLoopable()) { + if (chan[i].sample>=0 && chan[i].samplesong.sampleLen && s->isLoopable()) { if (is219) { loop=MIN(start+(s->loopStart>>1),65535); end=MIN(start+(s->loopEnd>>1)-1,65535); @@ -240,6 +250,8 @@ void DivPlatformC140::tick(bool sysTick) { loop=MIN(start+s->loopStart,65535); end=MIN(start+s->loopEnd-1,65535); } + } else if (chan[i].noise && is219) { + loop=0; } rWrite(0x05+(i<<4),0); // force keyoff first if (is219) { diff --git a/src/engine/platform/c140.h b/src/engine/platform/c140.h index fb74151c0..9dea0c0c5 100644 --- a/src/engine/platform/c140.h +++ b/src/engine/platform/c140.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "sound/c140_c219.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" class DivPlatformC140: public DivDispatch { struct Channel: public SharedChannel { diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index def32eaab..38e735d9a 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -21,7 +21,7 @@ #define _C64_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/c64/sid.h" #include "sound/c64_fp/SID.h" #include "sound/c64_d/dsid.h" diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 227917636..b93f0c163 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define PITCH_OFFSET ((double)(16*2048*(chanMax+1))) #define NOTE_ES5506(c,note) (parent->calcBaseFreq(chipClock,chan[c].pcm.freqOffs,note,false)) diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 07bdb2380..6bac20c37 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "../engine.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../macroInt.h" #include "../sample.h" #include "vgsound_emu/src/es550x/es5506.hpp" diff --git a/src/engine/platform/fmshared_OPM.h b/src/engine/platform/fmshared_OPM.h index e922e8abb..2002db333 100644 --- a/src/engine/platform/fmshared_OPM.h +++ b/src/engine/platform/fmshared_OPM.h @@ -22,7 +22,7 @@ #include "fmsharedbase.h" -#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0) +#define NOTE_LINEAR(x) (((x)<<7)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*128.0) class DivPlatformOPM: public DivPlatformFMBase { protected: @@ -42,13 +42,15 @@ class DivPlatformOPM: public DivPlatformFMBase { }; unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2; + bool brokenPitch; DivPlatformOPM(): DivPlatformFMBase(), lfoValue(0), lfoValue2(0), lfoShape(0), - lfoShape2(0) {} + lfoShape2(0), + brokenPitch(false) {} }; #endif diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 9be217b94..e458904eb 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "../instrument.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #define KVS(x,y) ((chan[x].state.op[y].kvs==2 && isOutput[chan[x].state.alg][y]) || chan[x].state.op[y].kvs==1) diff --git a/src/engine/platform/ga20.h b/src/engine/platform/ga20.h index 691b68f0a..3831d32c2 100644 --- a/src/engine/platform/ga20.h +++ b/src/engine/platform/ga20.h @@ -21,7 +21,7 @@ #define _GA20_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../macroInt.h" #include "sound/ga20/iremga20.h" diff --git a/src/engine/platform/gb.h b/src/engine/platform/gb.h index f92a0b895..0e7fb52d3 100644 --- a/src/engine/platform/gb.h +++ b/src/engine/platform/gb.h @@ -23,7 +23,7 @@ #include "../dispatch.h" #include "../waveSynth.h" #include "sound/gb/gb.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" class DivPlatformGB: public DivDispatch { struct Channel: public SharedChannel { diff --git a/src/engine/platform/k007232.h b/src/engine/platform/k007232.h index e3409b31f..5eb379985 100644 --- a/src/engine/platform/k007232.h +++ b/src/engine/platform/k007232.h @@ -21,7 +21,7 @@ #define _K007232_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../macroInt.h" #include "vgsound_emu/src/k007232/k007232.hpp" diff --git a/src/engine/platform/k053260.cpp b/src/engine/platform/k053260.cpp index 3c9d21932..e05b13a70 100644 --- a/src/engine/platform/k053260.cpp +++ b/src/engine/platform/k053260.cpp @@ -314,7 +314,7 @@ int DivPlatformK053260::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val-12):(0))); + chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0))); chan[c.chan].freqChanged=true; chan[c.chan].note=c.value; break; diff --git a/src/engine/platform/msm5232.h b/src/engine/platform/msm5232.h index abdb72f06..efa5c919c 100644 --- a/src/engine/platform/msm5232.h +++ b/src/engine/platform/msm5232.h @@ -21,7 +21,7 @@ #define _MSM5232_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/oki/msm5232.h" class DivPlatformMSM5232: public DivDispatch { diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index cb0ed05ed..c5d5c2c0e 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -30,6 +30,16 @@ const char** DivPlatformMSM6258::getRegisterSheet() { return NULL; } +static const int msmRates[4]={ + 4, 3, 2, 2 +}; + +int DivPlatformMSM6258::calcVGMRate() { + int ret=chipClock/((clockSel+1)*512*msmRates[rateSel&3]); + logD("MSM rate: %d",ret); + return ret; +} + void DivPlatformMSM6258::acquire(short** buf, size_t len) { for (size_t h=0; h=0 && samplesong.sampleLen) { + // turn on rWrite(0,2); + if (dumpWrites) addWrite(0xffff0000,sample); + int newRate=calcVGMRate(); + if (dumpWrites) addWrite(0xffff0001,newRate); } else { sample=-1; } @@ -220,10 +243,12 @@ int DivPlatformMSM6258::dispatch(DivCommand c) { case DIV_CMD_SAMPLE_FREQ: rateSel=c.value&3; rWrite(12,rateSel); + updateSampleFreq=true; break; case DIV_CMD_SAMPLE_MODE: clockSel=c.value&1; rWrite(8,clockSel); + updateSampleFreq=true; break; case DIV_CMD_PANNING: { if (c.value==0 && c.value2==0) { @@ -317,8 +342,10 @@ void DivPlatformMSM6258::reset() { msmPan=3; rateSel=2; clockSel=0; + updateSampleFreq=true; if (dumpWrites) { addWrite(0xffffffff,0); + addWrite(0xffff0001,calcVGMRate()); } for (int i=0; i<1; i++) { chan[i]=DivPlatformMSM6258::Channel(); diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index 21ff2a9f2..2a4c3512b 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -21,7 +21,7 @@ #define _MSM6258_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/oki/okim6258.h" class DivPlatformMSM6258: public DivDispatch { @@ -50,12 +50,15 @@ class DivPlatformMSM6258: public DivDispatch { unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel; signed char msmDividerCount, msmClockCount; + bool updateSampleFreq; short msmOut; int delay, updateOsc, sample, samplePos; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); + + int calcVGMRate(); public: void acquire(short** buf, size_t len); diff --git a/src/engine/platform/msm6295.cpp b/src/engine/platform/msm6295.cpp index 60c8f6a6a..d0c28833a 100644 --- a/src/engine/platform/msm6295.cpp +++ b/src/engine/platform/msm6295.cpp @@ -207,7 +207,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) { chan[c.chan].std.release(); break; case DIV_CMD_VOLUME: { - chan[c.chan].vol=c.value; + chan[c.chan].vol=MIN(8,c.value); if (!chan[c.chan].std.vol.has) { chan[c.chan].outVol=c.value; } diff --git a/src/engine/platform/msm6295.h b/src/engine/platform/msm6295.h index 041d36861..e38a4ec6a 100644 --- a/src/engine/platform/msm6295.h +++ b/src/engine/platform/msm6295.h @@ -21,7 +21,7 @@ #define _MSM6295_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "vgsound_emu/src/msm6295/msm6295.hpp" class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf { diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index c5ec64b7e..e4d5b24d2 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -21,7 +21,7 @@ #define _N163_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" #include "vgsound_emu/src/n163/n163.hpp" diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index 7d6943323..ab4451705 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -21,7 +21,7 @@ #define _NAMCOWSG_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" #include "sound/namco.h" diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 44e9b3b14..5a7580a78 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -722,6 +722,10 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { } } + if (properDrums && ch>melodicChans) { + return; + } + if (isMuted[ch]) { rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1)); if (ops==4) { diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index 2298f6132..bcc147da1 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -21,7 +21,7 @@ #define _OPL_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../../../extern/opl/opl3.h" #include "sound/ymfm/ymfm_adpcm.h" diff --git a/src/engine/platform/opll.h b/src/engine/platform/opll.h index 8bb6baa2c..e8bd627a4 100644 --- a/src/engine/platform/opll.h +++ b/src/engine/platform/opll.h @@ -21,7 +21,7 @@ #define _OPLL_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" extern "C" { #include "../../../extern/Nuked-OPLL/opll.h" diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index f989034af..2436453e4 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -21,7 +21,7 @@ #define _PCE_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" #include "sound/pce_psg.h" diff --git a/src/engine/platform/pcspkr.h b/src/engine/platform/pcspkr.h index d9315b5ec..b1a394444 100644 --- a/src/engine/platform/pcspkr.h +++ b/src/engine/platform/pcspkr.h @@ -21,9 +21,8 @@ #define _PCSPKR_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include -#include #include class DivPlatformPCSpeaker: public DivDispatch { diff --git a/src/engine/platform/pokey.h b/src/engine/platform/pokey.h index 979f60754..7e64c3c78 100644 --- a/src/engine/platform/pokey.h +++ b/src/engine/platform/pokey.h @@ -21,7 +21,7 @@ #define _POKEY_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" extern "C" { #include "sound/pokey/mzpokeysnd.h" diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 5c98990b4..95a455e3f 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_DIVIDER (1248*2) #define QS_NOTE_FREQUENCY(x) parent->calcBaseFreq(440,4096,(x)-3,false) diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 36db57cb7..339799d2e 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -21,7 +21,7 @@ #define _SAA_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../../../extern/SAASound/src/SAASound.h" class DivPlatformSAA1099: public DivDispatch { diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 639d875b4..b03459f5d 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -23,7 +23,7 @@ #include "../dispatch.h" #include "../instrument.h" #include "sound/segapcm.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" class DivPlatformSegaPCM: public DivDispatch { protected: diff --git a/src/engine/platform/sm8521.h b/src/engine/platform/sm8521.h index 02e2f458e..f9faeebda 100644 --- a/src/engine/platform/sm8521.h +++ b/src/engine/platform/sm8521.h @@ -21,7 +21,7 @@ #define _SM8521_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" #include "sound/sm8521.h" diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index d87546b30..5eaf204ba 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -25,7 +25,7 @@ extern "C" { #include "../../../extern/Nuked-PSG/ympsg.h" } -#include "../fixedQueue.h" +#include "../../fixedQueue.h" class DivPlatformSMS: public DivDispatch { struct Channel: public SharedChannel { diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index a799c7a5d..0992a46a7 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -22,7 +22,7 @@ #include "../dispatch.h" #include "../waveSynth.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/snes/SPC_DSP.h" class DivPlatformSNES: public DivDispatch { diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 6d5dd6a0c..859c95518 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -459,7 +459,7 @@ DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) { } unsigned short DivPlatformSoundUnit::getPan(int ch) { - return parent->convertPanLinearToSplit(chan[ch].pan^0x80,8,255); + return parent->convertPanLinearToSplit(chan[ch].pan+127,8,255); } DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) { diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index 99b784df3..4f227e5b5 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -21,7 +21,7 @@ #define _SU_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/su.h" class DivPlatformSoundUnit: public DivDispatch { diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index 1e0fbeef7..5f33e81c0 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -23,7 +23,7 @@ #include "../dispatch.h" #include "../waveSynth.h" #include "sound/swan.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" class DivPlatformSwan: public DivDispatch { struct Channel: public SharedChannel { diff --git a/src/engine/platform/t6w28.h b/src/engine/platform/t6w28.h index 4bb3cda2a..5e69c6268 100644 --- a/src/engine/platform/t6w28.h +++ b/src/engine/platform/t6w28.h @@ -21,7 +21,7 @@ #define _T6W28_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/t6w28/T6W28_Apu.h" class DivPlatformT6W28: public DivDispatch { diff --git a/src/engine/platform/ted.h b/src/engine/platform/ted.h index 58b4d0b7d..a2bd1d636 100644 --- a/src/engine/platform/ted.h +++ b/src/engine/platform/ted.h @@ -21,7 +21,7 @@ #define _TED_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/ted-sound.h" class DivPlatformTED: public DivDispatch { diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index a8f3a2f46..f677429ff 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -147,10 +147,10 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (chan[i].std.pitch.had) { if (chan[i].std.pitch.mode) { - chan[i].pitch2+=chan[i].std.pitch.val; + chan[i].pitch2+=chan[i].std.pitch.val*(brokenPitch?2:1); CLAMP_VAR(chan[i].pitch2,-32768,32767); } else { - chan[i].pitch2=chan[i].std.pitch.val; + chan[i].pitch2=chan[i].std.pitch.val*(brokenPitch?2:1); } chan[i].freqChanged=true; } @@ -337,18 +337,18 @@ void DivPlatformTX81Z::tick(bool sysTick) { for (int i=0; i<8; i++) { if (chan[i].freqChanged) { - chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2; + chan[i].freq=chan[i].baseFreq+chan[i].pitch-128+chan[i].pitch2; if (!parent->song.oldArpStrategy) { if (chan[i].fixedArp) { - chan[i].freq=(chan[i].baseNoteOverride<<6)+(chan[i].pitch>>1)-64+chan[i].pitch2; + chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+chan[i].pitch2; } else { - chan[i].freq+=chan[i].arpOff<<6; + chan[i].freq+=chan[i].arpOff<<7; } } if (chan[i].freq<0) chan[i].freq=0; - if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1; - immWrite(i+0x28,hScale(chan[i].freq>>6)); - immWrite(i+0x30,(chan[i].freq<<2)|(chan[i].chVolL==chan[i].chVolR)); + if (chan[i].freq>=(95<<7)) chan[i].freq=(95<<7)-1; + immWrite(i+0x28,hScale(chan[i].freq>>7)); + immWrite(i+0x30,((chan[i].freq<<1)&0xfc)|(chan[i].chVolL==chan[i].chVolR)); hardResetElapsed+=2; chan[i].freqChanged=false; } @@ -523,13 +523,13 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { int newFreq; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { - newFreq=chan[c.chan].baseFreq+c.value; + newFreq=chan[c.chan].baseFreq+c.value*(brokenPitch?2:1); if (newFreq>=destFreq) { newFreq=destFreq; return2=true; } } else { - newFreq=chan[c.chan].baseFreq-c.value; + newFreq=chan[c.chan].baseFreq-c.value*(brokenPitch?2:1); if (newFreq<=destFreq) { newFreq=destFreq; return2=true; @@ -1043,7 +1043,9 @@ void DivPlatformTX81Z::setFlags(const DivConfig& flags) { } CHECK_CUSTOM_CLOCK; - baseFreqOff=round(768.0*(log((COLOR_NTSC/(double)chipClock))/log(2.0))); + baseFreqOff=round(1536.0*(log((COLOR_NTSC/(double)chipClock))/log(2.0))); + + brokenPitch=flags.getBool("brokenPitch",false); rate=chipClock/64; for (int i=0; i<8; i++) { diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index c14bc0117..93da1cd7a 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -21,7 +21,7 @@ #define _TX81Z_H #include "fmshared_OPM.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "sound/ymfm/ymfm_opz.h" class DivTXInterface: public ymfm::ymfm_interface { diff --git a/src/engine/platform/vb.h b/src/engine/platform/vb.h index 2282f62fe..508e9a049 100644 --- a/src/engine/platform/vb.h +++ b/src/engine/platform/vb.h @@ -21,7 +21,7 @@ #define _PLATFORM_VB_H #include "../dispatch.h" -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../waveSynth.h" #include "sound/vsu.h" diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index df0aa92e5..f20e0d39c 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -20,7 +20,7 @@ #ifndef _VRC6_H #define _VRC6_H -#include "../fixedQueue.h" +#include "../../fixedQueue.h" #include "../dispatch.h" #include "vgsound_emu/src/vrcvi/vrcvi.hpp" diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 53d2cfe06..913f84045 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -231,7 +231,7 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) { buf[0][h]=os; for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } for (int i=3; i<6; i++) { @@ -282,7 +282,8 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) { for (int i=0; i<3; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } for (int i=3; i<6; i++) { diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 743cfab46..9ec5518b0 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -402,7 +402,7 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -471,7 +471,8 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; i<6; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 173d882a6..01d5a3bb6 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -333,7 +333,7 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[bchOffs[i]]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -404,7 +404,8 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) { buf[1][h]=os[1]; for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 4f00a7761..1937abd62 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -401,7 +401,7 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=fm_nuked.ch_out[i]<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm_nuked.ch_out[i]<<1,-32768,32767); } ssge->get_last_out(ssgOut); @@ -471,7 +471,8 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) { for (int i=0; idata[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + int out=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))<<1; + oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(out,-32768,32767); } ssge->get_last_out(ssgOut); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 12f2251da..9a8b45e9d 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -21,7 +21,6 @@ #include "../engine.h" #include "../../ta-log.h" #include -#include #define CHIP_FREQBASE 25165824 diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 6f6414225..affd720e8 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1164,8 +1164,10 @@ void DivEngine::nextRow() { } if (!stepPlay) { + playPosLock.lock(); prevOrder=curOrder; prevRow=curRow; + playPosLock.unlock(); } for (int i=0; i on sequence in %d",pendingNotes[i].channel); - pendingNotes.erase(pendingNotes.begin()+i); + //logV("erasing off -> on sequence in %d",pendingNotes[i].channel); + pendingNotes[i].nop=true; } } } @@ -1355,12 +1357,13 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { while (!pendingNotes.empty()) { DivNoteEvent& note=pendingNotes.front(); - if (note.channel<0 || note.channel>=chans) { + if (note.nop || note.channel<0 || note.channel>=chans) { pendingNotes.pop_front(); continue; } if (note.on) { dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1)); + //dispatchCmd(DivCommand(DIV_CMD_VOLUME,note.channel,(note.volume*(chan[note.channel].volMax>>8))/127)); dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note)); keyHit[note.channel]=true; chan[note.channel].noteOnInhibit=true; @@ -1402,8 +1405,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { endOfSong=false; if (stepPlay==2) { stepPlay=1; + playPosLock.lock(); prevOrder=curOrder; prevRow=curRow; + playPosLock.unlock(); } nextRow(); break; @@ -1847,7 +1852,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } } - logD("%.2x",msg.type); + //logD("%.2x",msg.type); output->midiIn->queue.pop(); } @@ -2118,6 +2123,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi logW("%d: sizepush([](void* d) { DivDispatchContainer* dc=(DivDispatchContainer*)d; dc->fillBuf(dc->runtotal,dc->lastAvail,dc->size-dc->lastAvail); @@ -2201,7 +2207,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else if (srcPortSet==0xffd) { // sample preview for (size_t j=0; j +#include "../fixedQueue.h" enum DivSampleLoopMode: unsigned char { DIV_SAMPLE_LOOP_FORWARD=0, @@ -144,8 +144,8 @@ struct DivSample { unsigned int samples; - std::deque undoHist; - std::deque redoHist; + FixedQueue undoHist; + FixedQueue redoHist; /** * put sample data. diff --git a/src/engine/song.h b/src/engine/song.h index 78c49b4e1..ec316464c 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -20,7 +20,7 @@ #ifndef _SONG_H #define _SONG_H #include -#include +#include "../pch.h" #include "defines.h" #include "../ta-utils.h" diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 52806aa70..17ab8cfc3 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1137,7 +1137,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_PCSPKR]=new DivSysDef( "PC Speaker", NULL, 0x93, 0, 1, false, true, 0, false, 0, - "good luck!", + "good luck! you get one square and no volume control.", {"Square"}, {"SQ"}, {DIV_CH_PULSE}, @@ -1146,7 +1146,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_PONG]=new DivSysDef( "Pong", NULL, 0xfc, 0, 1, false, true, 0, false, 0, - "LOL", + "please don't use this chip. it was added as a joke.", {"Square"}, {"SQ"}, {DIV_CH_PULSE}, @@ -1181,7 +1181,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef( "WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false, 1U<, effectVal}}, - {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direciton is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, + {0x21, {DIV_CMD_SU_SWEEP_ENABLE, "21xx: Toggle volume sweep (bit 0-4: speed; bit 5: direction is up; bit 6: loop; bit 7: alternate)", constVal<1>, effectVal}}, {0x22, {DIV_CMD_SU_SWEEP_ENABLE, "22xx: Toggle cutoff sweep (bit 0-6: speed; bit 7: direction is up)", constVal<2>, effectVal}}, }; const EffectHandler suCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, "4xxx: Set cutoff (0 to FFF)", effectValLong<12>); @@ -1820,7 +1820,7 @@ void DivEngine::registerSystems() { sysDefs[DIV_SYSTEM_GA20]=new DivSysDef( "Irem GA20", NULL, 0xc7, 0, 4, false, true, 0x171, false, 1U<writeC(8); w->writeC(0xff); break; + case DIV_SYSTEM_MSM6258: + w->writeC(0xb8); // stop + w->writeC(baseAddr2|0); + w->writeC(1); + break; case DIV_SYSTEM_MSM6295: w->writeC(0xb8); // disable all channels w->writeC(baseAddr2|0); @@ -1055,6 +1060,12 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write w->writeC(write.addr&0xff); w->writeC(write.val); break; + case DIV_SYSTEM_MSM6258: + w->writeC(0xb7); + w->writeC(baseAddr2|(write.addr&0x7f)); + w->writeC(write.val); + logV("MSM write to %.2x %.2x",write.addr,write.val); + break; case DIV_SYSTEM_MSM6295: w->writeC(0xb8); w->writeC(baseAddr2|(write.addr&0x7f)); @@ -1238,6 +1249,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p bool writeDACSamples=false; bool writeNESSamples=false; bool writePCESamples=false; + bool writeVOXSamples=false; DivDispatch* writeADPCM_OPNA[2]={NULL,NULL}; DivDispatch* writeADPCM_OPNB[2]={NULL,NULL}; DivDispatch* writeADPCM_Y8950[2]={NULL,NULL}; @@ -1746,6 +1758,21 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p writeRF5C68[0]=disCont[i].dispatch; } break; + case DIV_SYSTEM_MSM6258: + if (!hasOKIM6258) { + hasOKIM6258=disCont[i].dispatch->chipClock; + CHIP_VOL(23,0.65); + willExport[i]=true; + writeVOXSamples=true; + } else if (!(hasOKIM6258&0x40000000)) { + isSecond[i]=true; + CHIP_VOL_SECOND(23,0.65); + willExport[i]=true; + writeVOXSamples=true; + hasOKIM6258|=0x40000000; + howManyChips++; + } + break; case DIV_SYSTEM_MSM6295: if (!hasOKIM6295) { hasOKIM6295=disCont[i].dispatch->chipClock; @@ -1927,7 +1954,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p w->writeI(hasMultiPCM); w->writeI(hasuPD7759); w->writeI(hasOKIM6258); - w->writeC(0); // flags + w->writeC(hasOKIM6258?10:0); // flags w->writeC(0); // K flags w->writeC(c140Type); // C140 chip type w->writeC(0); // reserved @@ -2066,6 +2093,18 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p } } + if (writeVOXSamples && !directStream) for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(4); + w->writeI(sample->lengthVOX); + for (unsigned int j=0; jlengthVOX; j++) { + unsigned char actualData=(sample->dataVOX[j]>>4)|(sample->dataVOX[j]<<4); + w->writeC(actualData); + } + } + for (int i=0; i<2; i++) { // SegaPCM if (writeSegaPCM[i]!=NULL && writeSegaPCM[i]->getSampleMemUsage(0)>0) { @@ -2344,6 +2383,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p w->writeI(24000); // default streamID++; break; + case DIV_SYSTEM_MSM6258: + w->writeC(0x90); + w->writeC(streamID); + w->writeC(isSecond[i]?0x97:0x17); + w->writeC(0); // port + w->writeC(1); // data input + + w->writeC(0x91); + w->writeC(streamID); + w->writeC(4); + w->writeC(1); + w->writeC(0); + streamID++; + break; default: break; } diff --git a/src/engine/workPool.h b/src/engine/workPool.h index 9c41e1ccf..ec12843aa 100644 --- a/src/engine/workPool.h +++ b/src/engine/workPool.h @@ -21,12 +21,11 @@ #define _WORKPOOL_H #include -#include #include #include #include -#include "fixedQueue.h" +#include "../fixedQueue.h" class DivWorkPool; diff --git a/src/engine/fixedQueue.h b/src/fixedQueue.h similarity index 80% rename from src/engine/fixedQueue.h rename to src/fixedQueue.h index ad43f160d..9866fe732 100644 --- a/src/engine/fixedQueue.h +++ b/src/fixedQueue.h @@ -21,17 +21,20 @@ #define _FIXED_QUEUE_H #include -#include "../ta-log.h" +#include "ta-log.h" template struct FixedQueue { size_t readPos, writePos; T data[items]; + T& operator[](size_t pos); T& front(); T& back(); bool pop(); bool push(const T& item); + bool erase(size_t pos); + bool pop_front(); bool pop_back(); bool push_front(const T& item); @@ -44,6 +47,13 @@ template struct FixedQueue { writePos(0) {} }; +template T& FixedQueue::operator[](size_t pos) { + if (pos>=size()) { + logW("accessing invalid position. bug!"); + } + return data[(readPos+pos)%items]; +} + template T& FixedQueue::front() { return data[readPos]; } @@ -53,6 +63,36 @@ template T& FixedQueue::back() { return data[writePos-1]; } +template bool FixedQueue::erase(size_t pos) { + size_t curSize=size(); + if (pos>=curSize) { + logW("accessing invalid position. bug!"); + return false; + } + if (pos==0) { + return pop_front(); + } + if (pos==curSize-1) { + return pop_back(); + } + + for (size_t i=pos+1, p=(readPos+pos)%items, p1=(readPos+pos+1)%items; i=items) p-=items; + if (p1>=items) p1-=items; + data[p]=data[p1]; + p++; + p1++; + } + + if (writePos>0) { + writePos--; + } else { + writePos=items-1; + } + + return true; +} + template bool FixedQueue::pop() { if (readPos==writePos) return false; if (++readPos>=items) readPos=0; diff --git a/src/gui/about.cpp b/src/gui/about.cpp index cdb2fbc23..6b13b66ce 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -30,6 +30,9 @@ 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 --", @@ -163,6 +166,7 @@ const char* aboutLine[]={ "Portable File Dialogs by Sam Hocevar", "Native File Dialog by Frogtoss Games", "PortAudio", + "Weak-JACK by x42", "RtMidi by Gary P. Scavone", "FFTW by Matteo Frigo and Steven G. Johnson", "backward-cpp by Google", diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 04908702e..abdf708b0 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -96,16 +96,16 @@ void FurnaceGUI::calcChanOsc() { // 30ms should be enough int displaySize=(float)(buf->rate)*0.03f; if (e->isRunning()) { - float minLevel=1.0f; - float maxLevel=-1.0f; + short minLevel=32767; + short maxLevel=-32768; unsigned short needlePos=buf->needle; needlePos-=displaySize; for (unsigned short i=0; i<512; i++) { - float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/32768.0f; + short y=buf->data[(unsigned short)(needlePos+(i*displaySize/512))]; if (minLevel>y) minLevel=y; if (maxLevel1.0f) estimate=1.0f; chanOscVol[i]=MAX(chanOscVol[i]*0.87f,estimate); } @@ -357,7 +357,7 @@ void FurnaceGUI::drawChanOsc() { } else { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f)); float availY=ImGui::GetContentRegionAvail().y; - if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) { + if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders|ImGuiTableFlags_NoClip)) { std::vector oscBufs; std::vector oscFFTs; std::vector oscChans; diff --git a/src/gui/clock.cpp b/src/gui/clock.cpp index 5db890558..a44ae13d5 100644 --- a/src/gui/clock.cpp +++ b/src/gui/clock.cpp @@ -29,13 +29,13 @@ void FurnaceGUI::drawClock() { } if (!clockOpen) return; if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) { - int row=e->getRow(); + int row=oldRow; int elapsedBars=e->getElapsedBars(); int elapsedBeats=e->getElapsedBeats(); bool playing=e->isPlaying(); if (clockShowRow) { ImGui::PushFont(bigFont); - ImGui::Text("%.3d:%.3d",e->getOrder(),row); + ImGui::Text("%.3d:%.3d",playOrder,row); ImGui::PopFont(); } if (clockShowBeat) { diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index ab9d341e9..8925b69fe 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -172,12 +172,14 @@ void FurnaceGUI::waveListItem(int i, float* wavePreview, int dir, int asset) { wavePreview[i]=wave->data[i]; } if (wave->len>0) wavePreview[wave->len]=wave->data[wave->len-1]; - ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0,0.5f)); - if (ImGui::Selectable(fmt::sprintf(" %d##_WAVE%d\n",i,i).c_str(),curWave==i,0,ImVec2(0,23*dpiScale))) { // i didnt think that the 0 would work, but it does + ImVec2 curPos=ImGui::GetCursorPos(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign,ImVec2(0,0.5f)); + if (ImGui::Selectable(fmt::sprintf(" %d##_WAVE%d\n",i,i).c_str(),curWave==i,0,ImVec2(0,ImGui::GetFrameHeight()))) { curWave=i; lastAssetType=1; } ImGui::PopStyleVar(); + curPos.x+=ImGui::CalcTextSize("2222").x; if (wantScrollList && curWave==i) ImGui::SetScrollHereY(); if (ImGui::IsItemHovered()) { if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { @@ -190,7 +192,8 @@ void FurnaceGUI::waveListItem(int i, float* wavePreview, int dir, int asset) { DRAG_TARGET(dir,asset,e->song.waveDir,"FUR_WAVEDIR"); } ImGui::SameLine(); - PlotNoLerp(fmt::sprintf("##_WAVEP%d",i).c_str(),wavePreview,wave->len+1,0,NULL,0,wave->max); + ImGui::SetCursorPos(curPos); + PlotNoLerp(fmt::sprintf("##_WAVEP%d",i).c_str(),wavePreview,wave->len+1,0,NULL,0,wave->max,ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetFrameHeight())); } void FurnaceGUI::sampleListItem(int i, int dir, int asset) { @@ -421,7 +424,7 @@ void FurnaceGUI::drawInsList(bool asChild) { } if (!insListDir) { ImGui::SameLine(); - if (ImGui::ArrowButton("InsUp",ImGuiDir_Up)) { + if (ImGui::Button(ICON_FA_ARROW_UP "##InsUp")) { if (settings.unifiedDataView) { switch (lastAssetType) { case 0: @@ -442,7 +445,7 @@ void FurnaceGUI::drawInsList(bool asChild) { ImGui::SetTooltip("Move up"); } ImGui::SameLine(); - if (ImGui::ArrowButton("InsDown",ImGuiDir_Down)) { + if (ImGui::Button(ICON_FA_ARROW_DOWN "##InsDown")) { if (settings.unifiedDataView) { switch (lastAssetType) { case 0: @@ -726,14 +729,14 @@ void FurnaceGUI::drawWaveList(bool asChild) { } if (!waveListDir) { ImGui::SameLine(); - if (ImGui::ArrowButton("WaveUp",ImGuiDir_Up)) { + if (ImGui::Button(ICON_FA_ARROW_UP "##WaveUp")) { doAction(GUI_ACTION_WAVE_LIST_MOVE_UP); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Move up"); } ImGui::SameLine(); - if (ImGui::ArrowButton("WaveDown",ImGuiDir_Down)) { + if (ImGui::Button(ICON_FA_ARROW_DOWN "##WaveDown")) { doAction(GUI_ACTION_WAVE_LIST_MOVE_DOWN); } if (ImGui::IsItemHovered()) { @@ -868,14 +871,14 @@ void FurnaceGUI::drawSampleList(bool asChild) { } if (!sampleListDir) { ImGui::SameLine(); - if (ImGui::ArrowButton("SampleUp",ImGuiDir_Up)) { + if (ImGui::Button(ICON_FA_ARROW_UP "##SampleUp")) { doAction(GUI_ACTION_SAMPLE_LIST_MOVE_UP); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Move up"); } ImGui::SameLine(); - if (ImGui::ArrowButton("SampleDown",ImGuiDir_Down)) { + if (ImGui::Button(ICON_FA_ARROW_DOWN "##SampleDown")) { doAction(GUI_ACTION_SAMPLE_LIST_MOVE_DOWN); } if (ImGui::IsItemHovered()) { diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 916204030..1efde1e09 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -574,6 +574,16 @@ void FurnaceGUI::drawDebug() { ImGui::PlotLines("##DebugFMPreview",asFloat,FM_PREVIEW_SIZE,0,"Preview",-1.0,1.0,ImVec2(300.0f*dpiScale,150.0f*dpiScale)); ImGui::TreePop(); } + if (ImGui::TreeNode("Recent Files")) { + ImGui::Text("Items: %d - Max: %d",(int)recentFile.size(),settings.maxRecentFile); + ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos); + ImGui::Indent(); + for (size_t i=0; isyncReset(); break; case GUI_ACTION_CLEAR: - showWarning("Are you sure you want to clear... (cannot be undone!)",GUI_WARN_CLEAR); + showWarning("Select an option: (cannot be undone!)",GUI_WARN_CLEAR); break; case GUI_ACTION_WINDOW_EDIT_CONTROLS: @@ -919,7 +919,7 @@ void FurnaceGUI::doAction(int what) { sample->strip(start,end); updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=-1; sampleSelEnd=-1; @@ -965,7 +965,7 @@ void FurnaceGUI::doAction(int what) { memcpy(&(sample->data16[pos]),sampleClipboard,sizeof(short)*sampleClipboardLen); } } - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=pos; sampleSelEnd=pos+sampleClipboardLen; @@ -995,7 +995,7 @@ void FurnaceGUI::doAction(int what) { sample->data16[pos+i]=sampleClipboard[i]; } } - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=pos; sampleSelEnd=pos+sampleClipboardLen; @@ -1032,7 +1032,7 @@ void FurnaceGUI::doAction(int what) { sample->data16[pos+i]=val; } } - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=pos; sampleSelEnd=pos+sampleClipboardLen; @@ -1104,7 +1104,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1135,7 +1135,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1166,7 +1166,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1195,7 +1195,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1211,7 +1211,7 @@ void FurnaceGUI::doAction(int what) { sample->strip(start,end); updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=-1; sampleSelEnd=-1; @@ -1229,7 +1229,7 @@ void FurnaceGUI::doAction(int what) { sample->trim(start,end); updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); sampleSelStart=-1; sampleSelEnd=-1; @@ -1264,7 +1264,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1291,7 +1291,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1316,7 +1316,7 @@ void FurnaceGUI::doAction(int what) { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1441,7 +1441,7 @@ void FurnaceGUI::doAction(int what) { sample->loop=true; updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; break; @@ -1566,8 +1566,6 @@ void FurnaceGUI::doAction(int what) { e->deleteOrder(curOrder); if (curOrder>=e->curSubSong->ordersLen) { curOrder=e->curSubSong->ordersLen-1; - oldOrder=curOrder; - oldOrder1=curOrder; e->setOrder(curOrder); } makeUndo(GUI_UNDO_CHANGE_ORDER); diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 1e55d86e3..aa7e6f5c7 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -1209,8 +1209,6 @@ void FurnaceGUI::doUndo() { if (curOrder>=e->curSubSong->ordersLen) { curOrder=e->curSubSong->ordersLen-1; - oldOrder=curOrder; - oldOrder1=curOrder; e->setOrder(curOrder); } @@ -1287,8 +1285,6 @@ void FurnaceGUI::doRedo() { if (curOrder>=e->curSubSong->ordersLen) { curOrder=e->curSubSong->ordersLen-1; - oldOrder=curOrder; - oldOrder1=curOrder; e->setOrder(curOrder); } diff --git a/src/gui/fileDialog.cpp b/src/gui/fileDialog.cpp index e4dd8d3cd..cd5116414 100644 --- a/src/gui/fileDialog.cpp +++ b/src/gui/fileDialog.cpp @@ -80,6 +80,7 @@ void FurnaceGUIFileDialog::convertFilterList(std::vector& filter) { memset(noSysFilter,0,4096); String result; + char sprintfBuf[4096]; for (size_t i=0; (i+1)& filter) { if (filter[i+1]=="*") { ext=".*"; - } else for (char i: filter[i+1]) { - switch (i) { + } else for (char j: filter[i+1]) { + switch (j) { case '*': break; case ' ': ext+=','; break; default: - ext+=i; + ext+=j; break; } } if (!result.empty()) result+=','; - result+=fmt::sprintf("%s{%s}",label,ext); + // what the heck? fmt::sprintf not working?! + snprintf(sprintfBuf,4095,"%s{%s}",label.c_str(),ext.c_str()); + result+=sprintfBuf; } strncpy(noSysFilter,result.c_str(),4095); diff --git a/src/gui/fileDialog.h b/src/gui/fileDialog.h index 371fa7c21..1a34ca1bc 100644 --- a/src/gui/fileDialog.h +++ b/src/gui/fileDialog.h @@ -1,7 +1,7 @@ #include "../ta-utils.h" #include "imgui.h" #include -#include +#include "../pch.h" #if defined(_WIN64) || defined(__APPLE__) #define USE_NFD diff --git a/src/gui/findReplace.cpp b/src/gui/findReplace.cpp index 40e259eb3..f6bf5eedd 100644 --- a/src/gui/findReplace.cpp +++ b/src/gui/findReplace.cpp @@ -670,31 +670,13 @@ void FurnaceGUI::drawFindReplace() { ImGui::Combo("##ICondition",&i.insMode,queryModes,GUI_QUERY_MAX); ImGui::TableNextColumn(); if (FIRST_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.ins); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.ins==j)) { - i.ins=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##II1",ImGuiDataType_U8,&i.ins,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextColumn(); if (SECOND_VISIBLE(i.insMode)) { - snprintf(tempID,1024,"%.2X",i.insMax); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("II2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.insMax==j)) { - i.insMax=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##II2",ImGuiDataType_U8,&i.insMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextRow(); @@ -706,31 +688,13 @@ void FurnaceGUI::drawFindReplace() { ImGui::Combo("##VCondition",&i.volMode,queryModes,GUI_QUERY_MAX); ImGui::TableNextColumn(); if (FIRST_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.vol); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV1",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.vol==j)) { - i.vol=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##VV1",ImGuiDataType_U8,&i.vol,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } ImGui::TableNextColumn(); if (SECOND_VISIBLE(i.volMode)) { - snprintf(tempID,1024,"%.2X",i.volMax); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("VV2",tempID)) { - for (int j=0; j<256; j++) { - snprintf(tempID,1024,"%.2X",j); - if (ImGui::Selectable(tempID,i.volMax==j)) { - i.volMax=j; - } - } - ImGui::EndCombo(); - } + ImGui::InputScalar("##VV2",ImGuiDataType_U8,&i.volMax,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal); } for (int j=0; jsetOrder(curOrder); if (row>0) { - e->playToRow(row); + if (!e->playToRow(row)) { + showError("the song is over!"); + } } else { - e->play(); + if (!e->play()) { + showError("the song is over!"); + } } curNibble=false; orderNibble=false; @@ -1130,7 +1134,7 @@ void FurnaceGUI::stop() { if (followPattern && wasPlaying) { nextScroll=-1.0f; nextAddScroll=0.0f; - cursor.y=e->getRow(); + cursor.y=oldRow; if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) { selStart=cursor; selEnd=cursor; @@ -1270,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; @@ -2203,7 +2208,7 @@ void FurnaceGUI::pushRecentFile(String path) { if (path.find(backupPath)==0) return; for (int i=0; i<(int)recentFile.size(); i++) { if (recentFile[i]==path) { - recentFile.erase(recentFile.begin()+i); + recentFile.erase(i); i--; } } @@ -3254,7 +3259,7 @@ void FurnaceGUI::pointUp(int x, int y, int button) { if (sampleDragActive) { logD("stopping sample drag"); if (sampleDragMode) { - e->renderSamplesP(); + e->renderSamplesP(curSample); } else { if (sampleSelStart>sampleSelEnd) { sampleSelStart^=sampleSelEnd; @@ -3540,8 +3545,12 @@ bool FurnaceGUI::loop() { break; case SDL_DROPFILE: if (ev.drop.file!=NULL) { + if (introPos<11.0) { + SDL_free(ev.drop.file); + break; + } int sampleCountBefore=e->song.sampleLen; - std::vector instruments=e->instrumentFromFile(ev.drop.file); + std::vector instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames); DivWavetable* droppedWave=NULL; DivSample* droppedSample=NULL; if (!instruments.empty()) { @@ -3918,6 +3927,19 @@ bool FurnaceGUI::loop() { curWindow=GUI_WINDOW_NOTHING; editOptsVisible=false; + 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; + } + if (!mobileUI) { ImGui::BeginMainMenuBar(); if (ImGui::BeginMenu(settings.capitalMenuBar?"File":"file")) { @@ -3944,7 +3966,7 @@ bool FurnaceGUI::loop() { nextFile=item; showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP); } else { - recentFile.erase(recentFile.begin()+i); + recentFile.erase(i); i--; if (load(item)>0) { showError(fmt::sprintf("Error while loading file! (%s)",lastError)); @@ -4191,7 +4213,7 @@ bool FurnaceGUI::loop() { exitDisabledTimer=1; for (int i=0; isong.systemLen; i++) { if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSP%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true,true); + drawSysConf(i,i,e->song.system[i],e->song.systemFlags[i],true,true); ImGui::TreePop(); } } @@ -4322,8 +4344,8 @@ bool FurnaceGUI::loop() { if (ImGui::MenuItem("channels",BIND_FOR(GUI_ACTION_WINDOW_CHANNELS),channelsOpen)) channelsOpen=!channelsOpen; } if (ImGui::MenuItem("pattern manager",BIND_FOR(GUI_ACTION_WINDOW_PAT_MANAGER),patManagerOpen)) patManagerOpen=!patManagerOpen; + if (ImGui::MenuItem("chip manager",BIND_FOR(GUI_ACTION_WINDOW_SYS_MANAGER),sysManagerOpen)) sysManagerOpen=!sysManagerOpen; if (!basicMode) { - if (ImGui::MenuItem("chip manager",BIND_FOR(GUI_ACTION_WINDOW_SYS_MANAGER),sysManagerOpen)) sysManagerOpen=!sysManagerOpen; if (ImGui::MenuItem("compatibility flags",BIND_FOR(GUI_ACTION_WINDOW_COMPAT_FLAGS),compatFlagsOpen)) compatFlagsOpen=!compatFlagsOpen; } if (ImGui::MenuItem("song comments",BIND_FOR(GUI_ACTION_WINDOW_NOTES),notesOpen)) notesOpen=!notesOpen; @@ -4375,15 +4397,15 @@ bool FurnaceGUI::loop() { info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD)); if (settings.orderRowsBase) { - info+=fmt::sprintf("| Order %.2X/%.2X ",e->getOrder(),e->curSubSong->ordersLen-1); + info+=fmt::sprintf("| Order %.2X/%.2X ",playOrder,e->curSubSong->ordersLen-1); } else { - info+=fmt::sprintf("| Order %d/%d ",e->getOrder(),e->curSubSong->ordersLen-1); + info+=fmt::sprintf("| Order %d/%d ",playOrder,e->curSubSong->ordersLen-1); } if (settings.patRowsBase) { - info+=fmt::sprintf("| Row %.2X/%.2X ",e->getRow(),e->curSubSong->patLen); + info+=fmt::sprintf("| Row %.2X/%.2X ",oldRow,e->curSubSong->patLen); } else { - info+=fmt::sprintf("| Row %d/%d ",e->getRow(),e->curSubSong->patLen); + info+=fmt::sprintf("| Row %d/%d ",oldRow,e->curSubSong->patLen); } info+=fmt::sprintf("| %d:%.2d:%.2d.%.2d",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); @@ -4455,10 +4477,6 @@ bool FurnaceGUI::loop() { MEASURE(calcChanOsc,calcChanOsc()); - if (followPattern) { - curOrder=e->getOrder(); - } - if (mobileUI) { globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; //globalWinFlags=ImGuiWindowFlags_NoTitleBar; @@ -4521,6 +4539,8 @@ bool FurnaceGUI::loop() { MEASURE(log,drawLog()); MEASURE(compatFlags,drawCompatFlags()); MEASURE(stats,drawStats()); + MEASURE(readOsc,readOsc()); + MEASURE(osc,drawOsc()); MEASURE(chanOsc,drawChanOsc()); MEASURE(regView,drawRegView()); } else { @@ -4563,9 +4583,7 @@ bool FurnaceGUI::loop() { MEASURE(channels,drawChannels()); } MEASURE(patManager,drawPatManager()); - if (!basicMode) { - MEASURE(sysManager,drawSysManager()); - } + MEASURE(sysManager,drawSysManager()); MEASURE(clock,drawClock()); MEASURE(regView,drawRegView()); MEASURE(log,drawLog()); @@ -4846,7 +4864,7 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_INS_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { - if (e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song)) { + if (e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song,settings.writeInsNames)) { pushRecentSys(copyOfName.c_str()); } } @@ -4882,7 +4900,7 @@ bool FurnaceGUI::loop() { } break; case GUI_FILE_SAMPLE_OPEN: { - String errs="there were some errors while loading wavetables:\n"; + String errs="there were some errors while loading samples:\n"; bool warn=false; for (String i: fileDialog->getFileName()) { DivSample* s=e->sampleFromFile(i.c_str()); @@ -4972,7 +4990,7 @@ bool FurnaceGUI::loop() { String warns="there were some warnings/errors while loading instruments:\n"; int sampleCountBefore=e->song.sampleLen; for (String i: fileDialog->getFileName()) { - std::vector insTemp=e->instrumentFromFile(i.c_str()); + std::vector insTemp=e->instrumentFromFile(i.c_str(),true,settings.readInsNames); if (insTemp.empty()) { warn=true; warns+=fmt::sprintf("> %s: cannot load instrument! (%s)\n",i,e->getLastError()); @@ -5018,7 +5036,7 @@ bool FurnaceGUI::loop() { } case GUI_FILE_INS_OPEN_REPLACE: { int sampleCountBefore=e->song.sampleLen; - std::vector instruments=e->instrumentFromFile(copyOfName.c_str()); + std::vector instruments=e->instrumentFromFile(copyOfName.c_str(),true,settings.readInsNames); if (!instruments.empty()) { if (e->song.sampleLen!=sampleCountBefore) { e->renderSamplesP(); @@ -5521,90 +5539,138 @@ bool FurnaceGUI::loop() { } break; case GUI_WARN_CLEAR: - if (ImGui::Button("All subsongs")) { - stop(); - e->clearSubSongs(); - curOrder=0; - oldOrder=0; - oldOrder1=0; - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Current subsong")) { - stop(); - e->lockEngine([this]() { - e->curSubSong->clearData(); - }); - e->setOrder(0); - curOrder=0; - oldOrder=0; - oldOrder1=0; - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Orders")) { - stop(); - e->lockEngine([this]() { - memset(e->curOrders->ord,0,DIV_MAX_CHANS*DIV_MAX_PATTERNS); - e->curSubSong->ordersLen=1; - }); - e->setOrder(0); - curOrder=0; - oldOrder=0; - oldOrder1=0; - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Pattern")) { - stop(); - e->lockEngine([this]() { - for (int i=0; igetTotalChannelCount(); i++) { - DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],true); - memset(pat->data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short)); - for (int j=0; jdata[j][0]=0; - pat->data[j][1]=0; + if (ImGui::BeginTable("EraseOpt",2,ImGuiTableFlags_BordersInnerV)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::PushFont(headFont); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Erasing"); + ImGui::PopFont(); + + if (ImGui::Button("All subsongs")) { + stop(); + e->clearSubSongs(); + curOrder=0; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Current subsong")) { + stop(); + e->lockEngine([this]() { + e->curSubSong->clearData(); + }); + e->setOrder(0); + curOrder=0; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Orders")) { + stop(); + e->lockEngine([this]() { + memset(e->curOrders->ord,0,DIV_MAX_CHANS*DIV_MAX_PATTERNS); + e->curSubSong->ordersLen=1; + }); + e->setOrder(0); + curOrder=0; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Pattern")) { + stop(); + e->lockEngine([this]() { + for (int i=0; igetTotalChannelCount(); i++) { + DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][curOrder],true); + memset(pat->data,-1,DIV_MAX_ROWS*DIV_MAX_COLS*sizeof(short)); + for (int j=0; jdata[j][0]=0; + pat->data[j][1]=0; + } } - } - }); - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Instruments")) { - stop(); - e->lockEngine([this]() { - e->song.clearInstruments(); - }); - curIns=-1; - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Wavetables")) { - stop(); - e->lockEngine([this]() { - e->song.clearWavetables(); - }); - curWave=0; - MARK_MODIFIED; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Samples")) { - stop(); - e->lockEngine([this]() { - e->song.clearSamples(); - }); - curSample=0; - ImGui::CloseCurrentPopup(); + }); + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Instruments")) { + stop(); + e->lockEngine([this]() { + e->song.clearInstruments(); + }); + curIns=-1; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Wavetables")) { + stop(); + e->lockEngine([this]() { + e->song.clearWavetables(); + }); + curWave=0; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Samples")) { + stop(); + e->lockEngine([this]() { + e->song.clearSamples(); + }); + curSample=0; + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + + ImGui::TableNextColumn(); + ImGui::PushFont(headFont); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Optimization"); + ImGui::PopFont(); + + if (ImGui::Button("De-duplicate patterns")) { + stop(); + e->lockEngine([this]() { + e->curSubSong->optimizePatterns(); + e->curSubSong->rearrangePatterns(); + }); + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + if (ImGui::Button("Remove unused instruments")) { + stop(); + e->delUnusedIns(); + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + /* + if (ImGui::Button("Remove unused wavetables")) { + stop(); + e->delUnusedWaves(); + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + }*/ + if (ImGui::Button("Remove unused samples")) { + stop(); + e->delUnusedSamples(); + MARK_MODIFIED; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndTable(); } - if (ImGui::Button("Wait! What am I doing? Cancel!") || ImGui::IsKeyPressed(ImGuiKey_Escape)) { - ImGui::CloseCurrentPopup(); + if (ImGui::BeginTable("EraseOptFooter",3)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + if (ImGui::Button("Never mind! Cancel") || ImGui::IsKeyPressed(ImGuiKey_Escape)) { + ImGui::CloseCurrentPopup(); + } + ImGui::TableNextColumn(); + ImGui::EndTable(); } break; case GUI_WARN_SUBSONG_DEL: @@ -5613,8 +5679,6 @@ bool FurnaceGUI::loop() { undoHist.clear(); redoHist.clear(); updateScroll(0); - oldOrder=0; - oldOrder1=0; oldRow=0; cursor.xCoarse=0; cursor.xFine=0; @@ -7021,10 +7085,9 @@ FurnaceGUI::FurnaceGUI(): curSample(0), curOctave(3), curOrder(0), + playOrder(0), prevIns(0), oldRow(0), - oldOrder(0), - oldOrder1(0), editStep(1), exportLoops(0), soloChan(-1), @@ -7049,6 +7112,8 @@ FurnaceGUI::FurnaceGUI(): exitDisabledTimer(0), soloTimeout(0.0f), exportFadeOut(5.0), + newSongFirstFrame(false), + oldRowChanged(false), editControlsOpen(true), ordersOpen(true), insListOpen(true), diff --git a/src/gui/gui.h b/src/gui/gui.h index a4bf28caa..0c495a6ee 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -27,14 +27,11 @@ #include "imgui_impl_sdl2.h" #include #include -#include #include -#include #include #include -#include #include -#include +#include "../pch.h" #include "fileDialog.h" @@ -874,6 +871,18 @@ struct UndoStep { std::vector ord; std::vector pat; std::vector other; + + UndoStep(): + type(GUI_UNDO_CHANGE_ORDER), + cursor(), + selStart(), + selEnd(), + order(0), + nibble(false), + oldOrdersLen(0), + newOrdersLen(0), + oldPatLen(0), + newPatLen(0) {} }; // -1 = any @@ -1317,12 +1326,13 @@ class FurnaceGUI { String workingDirVGMExport, workingDirZSMExport, workingDirROMExport, workingDirFont, workingDirColors, workingDirKeybinds; String workingDirLayout, workingDirROM, workingDirTest; String mmlString[32]; - String mmlStringW, mmlStringSNES, grooveString, grooveListString, mmlStringModTable; + String mmlStringW, grooveString, grooveListString, mmlStringModTable; + String mmlStringSNES[DIV_MAX_CHIPS]; String folderString; std::vector sysSearchResults; std::vector newSongSearchResults; - std::deque recentFile; + FixedQueue recentFile; std::vector makeInsTypeList; std::vector availRenderDrivers; std::vector availAudioDrivers; @@ -1390,7 +1400,7 @@ class FurnaceGUI { String backupPath; std::mutex midiLock; - std::queue midiQueue; + FixedQueue midiQueue; MIDIMap midiMap; int learning; @@ -1502,6 +1512,7 @@ class FurnaceGUI { int separateFMColors; int insEditColorize; int metroVol; + int sampleVol; int pushNibble; int scrollChangesOrder; int oplStandardWaveNames; @@ -1578,6 +1589,8 @@ class FurnaceGUI { int chanOscThreads; int renderPoolThreads; int showPool; + int writeInsNames; + int readInsNames; unsigned int maxUndoSteps; String mainFontPath; String headFontPath; @@ -1682,6 +1695,7 @@ class FurnaceGUI { separateFMColors(0), insEditColorize(0), metroVol(100), + sampleVol(50), pushNibble(0), scrollChangesOrder(0), oplStandardWaveNames(0), @@ -1757,6 +1771,8 @@ class FurnaceGUI { chanOscThreads(0), renderPoolThreads(0), showPool(0), + writeInsNames(1), + readInsNames(1), maxUndoSteps(100), mainFontPath(""), headFontPath(""), @@ -1792,7 +1808,7 @@ class FurnaceGUI { DivInstrument* prevInsData; - int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan,orderEditMode, orderCursor; + int curIns, curWave, curSample, curOctave, curOrder, playOrder, prevIns, oldRow, editStep, exportLoops, soloChan,orderEditMode, orderCursor; int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, newSongCategory, latchTarget; int wheelX, wheelY, dragSourceX, dragSourceXFine, dragSourceY, dragDestinationX, dragDestinationXFine, dragDestinationY, oldBeat, oldBar; int curGroove, exitDisabledTimer; @@ -1800,7 +1816,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; @@ -2002,8 +2018,8 @@ class FurnaceGUI { int oldOrdersLen; DivOrders oldOrders; DivPattern* oldPat[DIV_MAX_CHANS]; - std::deque undoHist; - std::deque redoHist; + FixedQueue undoHist; + FixedQueue redoHist; // sample editor specific double sampleZoom; @@ -2176,7 +2192,7 @@ class FurnaceGUI { void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); - bool drawSysConf(int chan, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu=false); + bool drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu=false); void kvsConfig(DivInstrument* ins, bool supportsKVS=true); void drawFMPreview(const ImVec2& size); void renderFMPreview(const DivInstrument* ins, int pos=0); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 00cc903f2..f4542d06d 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2531,10 +2531,12 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Button("Request from TX81Z")) { doAction(GUI_ACTION_TX81Z_REQUEST); } + /* ImGui::SameLine(); if (ImGui::Button("Send to TX81Z")) { showError("Coming soon!"); } + */ break; case DIV_INS_OPL: case DIV_INS_OPL_DRUMS: { @@ -4490,7 +4492,7 @@ void FurnaceGUI::drawInsEdit() { ins->std.dutyMacro.vZoom=-1; PARAMETER; } - P(ImGui::Checkbox("Don't test/gate before new note",&ins->c64.noTest)); + P(ImGui::Checkbox("Don't test before new note",&ins->c64.noTest)); ImGui::EndTabItem(); } if (ins->type==DIV_INS_PCE || @@ -5862,7 +5864,7 @@ void FurnaceGUI::drawInsEdit() { if (volMax>0) { macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME])); } - if (ins->type!=DIV_INS_MSM6258 && ins->type!=DIV_INS_MSM6295) { + if (ins->type!=DIV_INS_MSM6258 && ins->type!=DIV_INS_MSM6295 && ins->type!=DIV_INS_ADPCMA) { macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,0,true,ins->std.arpMacro.val)); } if (dutyMax>0) { @@ -5906,7 +5908,7 @@ void FurnaceGUI::drawInsEdit() { } } } - if (ins->type!=DIV_INS_MSM5232 && ins->type!=DIV_INS_MSM6258 && ins->type!=DIV_INS_MSM6295) { + if (ins->type!=DIV_INS_MSM5232 && ins->type!=DIV_INS_MSM6258 && ins->type!=DIV_INS_MSM6295 && ins->type!=DIV_INS_ADPCMA) { macroList.push_back(FurnaceGUIMacroDesc("Pitch",&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode)); } if (ins->type==DIV_INS_FM || @@ -5943,6 +5945,7 @@ void FurnaceGUI::drawInsEdit() { ins->type==DIV_INS_GA20 || ins->type==DIV_INS_K053260 || ins->type==DIV_INS_C140 || + ins->type==DIV_INS_C219 || ins->type==DIV_INS_TED) { macroList.push_back(FurnaceGUIMacroDesc("Phase Reset",&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true)); } diff --git a/src/gui/orders.cpp b/src/gui/orders.cpp index afd96ea5d..43dba3d79 100644 --- a/src/gui/orders.cpp +++ b/src/gui/orders.cpp @@ -259,18 +259,18 @@ void FurnaceGUI::drawOrders() { } ImGui::PushFont(patFont); bool tooSmall=((displayChans+1)>((ImGui::GetContentRegionAvail().x)/(ImGui::CalcTextSize("AA").x+2.0*ImGui::GetStyle().ItemInnerSpacing.x))); - ImGui::PopFont(); float yHeight=ImGui::GetContentRegionAvail().y; + float lineHeight=(ImGui::GetTextLineHeight()+4*dpiScale); + if (e->isPlaying()) { + if (followOrders) { + float nextOrdScroll=(playOrder+1)*lineHeight-((yHeight-(tooSmall?ImGui::GetStyle().ScrollbarSize:0.0f))/2.0f); + if (nextOrdScroll<0.0f) nextOrdScroll=0.0f; + ImGui::SetNextWindowScroll(ImVec2(-1.0f,nextOrdScroll)); + } + } if (ImGui::BeginTable("OrdersTable",1+displayChans,(tooSmall?ImGuiTableFlags_SizingFixedFit:ImGuiTableFlags_SizingStretchSame)|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY)) { - ImGui::PushFont(patFont); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,prevSpacing); ImGui::TableSetupScrollFreeze(1,1); - float lineHeight=(ImGui::GetTextLineHeight()+4*dpiScale); - if (e->isPlaying()) { - if (followOrders) { - ImGui::SetScrollY((e->getOrder()+1)*lineHeight-((yHeight-(tooSmall?ImGui::GetStyle().ScrollbarSize:0.0f))/2.0f)); - } - } ImGui::TableNextRow(0,lineHeight); ImVec2 ra=ImGui::GetContentRegionAvail(); ImGui::TableNextColumn(); @@ -283,9 +283,9 @@ void FurnaceGUI::drawOrders() { ImGui::PopStyleColor(); for (int i=0; icurSubSong->ordersLen; i++) { ImGui::TableNextRow(0,lineHeight); - if (oldOrder1==i) ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_ORDER_ACTIVE])); + if (playOrder==i && e->isPlaying()) ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_ORDER_ACTIVE])); ImGui::TableNextColumn(); - if ((!followPattern && curOrder==i) || (followPattern && oldOrder1==i)) { + if (curOrder==i) { // draw a border ImDrawList* dl=ImGui::GetWindowDrawList(); ImVec2 rBegin=ImGui::GetCursorScreenPos(); @@ -322,7 +322,7 @@ void FurnaceGUI::drawOrders() { //} ImGui::PushStyleColor(ImGuiCol_Text,(curOrder==i || e->curOrders->ord[j][i]==e->curOrders->ord[j][curOrder])?uiColors[GUI_COLOR_ORDER_SIMILAR]:uiColors[GUI_COLOR_ORDER_INACTIVE]); - if (ImGui::Selectable(selID,settings.ordersCursor?(cursor.xCoarse==j && oldOrder1!=i):false)) { + if (ImGui::Selectable(selID,settings.ordersCursor?(cursor.xCoarse==j && curOrder!=i):false)) { if (curOrder==i) { if (orderEditMode==0) { prepareUndo(GUI_UNDO_CHANGE_ORDER); @@ -394,9 +394,9 @@ void FurnaceGUI::drawOrders() { } } ImGui::PopStyleVar(); - ImGui::PopFont(); ImGui::EndTable(); } + ImGui::PopFont(); if (settings.orderButtonPos==2) { ImGui::TableNextColumn(); @@ -411,6 +411,5 @@ void FurnaceGUI::drawOrders() { } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ORDERS; - oldOrder1=e->getOrder(); ImGui::End(); } diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index fc3b17245..dd40b9da0 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -52,35 +52,44 @@ void FurnaceGUI::readOsc() { for (int ch=0; chgetAudioDescGot().outChans; ch++) { if (oscValues[ch]==NULL) { - oscValues[ch]=new float[1024]; + oscValues[ch]=new float[2048]; } - memset(oscValues[ch],0,1024*sizeof(float)); - float* sincITable=DivFilterTables::getSincIntegralTable(); + memset(oscValues[ch],0,2048*sizeof(float)); + float* sincITable=DivFilterTables::getSincIntegralSmallTable(); float posFrac=0.0; - int posInt=oscReadPos; float factor=(float)oscWidth/(float)winSize; - for (int i=0; ioscBuf[ch][posInt&0x7fff]; posFrac+=1.0; while (posFrac>=1.0) { - unsigned int n=((unsigned int)(posFrac*8192.0))&8191; + unsigned int n=((unsigned int)(posFrac*64.0))&63; posFrac-=factor; posInt++; - float* t1=&sincITable[(8191-n)<<3]; + float* t1=&sincITable[(63-n)<<3]; float* t2=&sincITable[n<<3]; float delta=e->oscBuf[ch][posInt&0x7fff]-e->oscBuf[ch][(posInt-1)&0x7fff]; - for (int j=0; j<8; j++) { - if (i-j>0) { - oscValues[ch][i-j]+=t1[j]*-delta; - } - if (i+j+1DC.CursorPos; @@ -246,61 +255,63 @@ void FurnaceGUI::drawOsc() { dpiScale ); - oscWidth=round(inRect.Max.x-inRect.Min.x); - if (oscWidth<1) oscWidth=1; - if (oscWidth>1024) oscWidth=1024; + oscWidth=round(inRect.Max.x-inRect.Min.x)+24; + if (oscWidth<17) oscWidth=17; + if (oscWidth>2048) oscWidth=2048; ImDrawListFlags prevFlags=dl->Flags; if (!settings.oscAntiAlias) { dl->Flags&=~(ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex); } - if (settings.oscMono) { - for (int i=0; igetAudioDescGot().outChans; j++) { - avg+=oscValues[j][i]; - } - avg/=e->getAudioDescGot().outChans; + if ((oscWidth-24)>0) { + if (settings.oscMono) { + for (int i=0; igetAudioDescGot().outChans; j++) { + avg+=oscValues[j][i+12]; + } + avg/=e->getAudioDescGot().outChans; - float y=avg*oscZoom; - if (!settings.oscEscapesBoundary) { - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - } - waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); - } - - if (settings.oscEscapesBoundary) { - dl->PushClipRectFullScreen(); - dl->AddPolyline(waveform,oscWidth,color,ImDrawFlags_None,dpiScale); - dl->PopClipRect(); - } else { - dl->AddPolyline(waveform,oscWidth,color,ImDrawFlags_None,dpiScale); - } - } else { - for (int ch=0; chgetAudioDescGot().outChans; ch++) { - for (int i=0; i0.5f) y=0.5f; } waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); } - - if (!isClipping) { - color=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_WAVE_CH0+ch]); - } if (settings.oscEscapesBoundary) { dl->PushClipRectFullScreen(); - dl->AddPolyline(waveform,oscWidth,color,ImDrawFlags_None,dpiScale); + dl->AddPolyline(waveform,oscWidth-24,color,ImDrawFlags_None,dpiScale); dl->PopClipRect(); } else { - dl->AddPolyline(waveform,oscWidth,color,ImDrawFlags_None,dpiScale); + dl->AddPolyline(waveform,oscWidth-24,color,ImDrawFlags_None,dpiScale); + } + } else { + for (int ch=0; chgetAudioDescGot().outChans; ch++) { + for (int i=0; i0.5f) y=0.5f; + } + waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); + } + + if (!isClipping) { + color=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_WAVE_CH0+ch]); + } + + if (settings.oscEscapesBoundary) { + dl->PushClipRectFullScreen(); + dl->AddPolyline(waveform,oscWidth-24,color,ImDrawFlags_None,dpiScale); + dl->PopClipRect(); + } else { + dl->AddPolyline(waveform,oscWidth-24,color,ImDrawFlags_None,dpiScale); + } } } } diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index f87b4ae7c..efb949867 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -91,7 +91,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int if (settings.overflowHighlight) { if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) { ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); - } else if (isPlaying && oldRow==i && ord==e->getOrder()) { + } else if (isPlaying && oldRow==i && ord==playOrder) { ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD])); } else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) { ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); @@ -102,7 +102,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int isPushing=true; if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) { ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING])); - } else if (isPlaying && oldRow==i && ord==e->getOrder()) { + } else if (isPlaying && oldRow==i && ord==playOrder) { ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD])); } else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) { ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2])); @@ -377,11 +377,14 @@ void FurnaceGUI::drawPattern() { bool inhibitMenu=false; - if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) { - cursor.y=e->isStepping()?e->getRow():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; @@ -419,8 +422,7 @@ void FurnaceGUI::drawPattern() { } //char id[32]; ImGui::PushFont(patFont); - int ord=oldOrder; - oldOrder=curOrder; + int ord=curOrder; int chans=e->getTotalChannelCount(); int displayChans=0; const DivPattern* patCache[DIV_MAX_CHANS]; @@ -437,23 +439,24 @@ void FurnaceGUI::drawPattern() { ImGui::SetCursorPosX(ImGui::GetCursorPosX()+centerOff); } } + if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) updateScroll(oldRow); + if (--pendingStepUpdate<0) pendingStepUpdate=0; + if (nextScroll>-0.5f) { + ImGui::SetNextWindowScroll(ImVec2(-1.0f,nextScroll)); + nextScroll=-1.0f; + nextAddScroll=0.0f; + } if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea|((settings.cursorFollowsWheel || wheelCalmDown)?ImGuiTableFlags_NoScrollWithMouse:0))) { ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed); char chanID[2048]; float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale); - int curRow=e->getRow(); - if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) updateScroll(curRow); - if (--pendingStepUpdate<0) pendingStepUpdate=0; - if (nextScroll>-0.5f) { - ImGui::SetScrollY(nextScroll); - nextScroll=-1.0f; - nextAddScroll=0.0f; - } + if (nextAddScroll!=0.0f) { ImGui::SetScrollY(ImGui::GetScrollY()+nextAddScroll); nextScroll=-1.0f; nextAddScroll=0.0f; } + ImGui::TableSetupScrollFreeze(1,1); for (int i=0; icurSubSong->chanShow[i]) continue; @@ -937,7 +940,6 @@ void FurnaceGUI::drawPattern() { ImGui::EndDisabled(); ImGui::PopStyleVar(); - oldRow=curRow; if (demandScrollX) { int totalDemand=demandX-ImGui::GetScrollX(); if (totalDemand<80) { diff --git a/src/gui/plot_nolerp.h b/src/gui/plot_nolerp.h index 50334dda6..fbc66c1eb 100644 --- a/src/gui/plot_nolerp.h +++ b/src/gui/plot_nolerp.h @@ -18,7 +18,7 @@ */ #include "imgui.h" -#include +#include "../pch.h" void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f)); diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index d6463564d..b83794638 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1098,7 +1098,7 @@ void FurnaceGUI::initSystemPresets() { ENTRY( "Sharp X68000", { CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2"), - CH(DIV_SYSTEM_MSM6258, 1.0f, 0, "") + CH(DIV_SYSTEM_MSM6258, 1.0f, 0, "clockSel=2") } ); ENTRY( diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 3d17bec78..9e8212216 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -195,6 +195,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Separator(); String warnLoop, warnLoopMode, warnLoopPos; + String warnLoopStart, warnLoopEnd; String warnLength, warnRate; bool isChipVisible[DIV_MAX_CHIPS]; @@ -213,9 +214,21 @@ void FurnaceGUI::drawSampleEdit() { switch (e->song.system[i]) { case DIV_SYSTEM_SNES: if (sample->loop) { - if (sample->loopStart&15 || sample->loopEnd&15) { - SAMPLE_WARN(warnLoopPos,"SNES: loop must be a multiple of 16"); + if (sample->loopStart&15) { + int tryWith=(sample->loopStart+8)&(~15); + if (tryWith>(int)sample->samples) tryWith-=16; + String alignHint=fmt::sprintf("SNES: loop start must be a multiple of 16 (try with %d)",tryWith); + SAMPLE_WARN(warnLoopStart,alignHint); } + if (sample->loopEnd&15) { + int tryWith=(sample->loopEnd+8)&(~15); + if (tryWith>(int)sample->samples) tryWith-=16; + String alignHint=fmt::sprintf("SNES: loop end must be a multiple of 16 (try with %d)",tryWith); + SAMPLE_WARN(warnLoopEnd,alignHint); + } + } + if (sample->samples&15) { + SAMPLE_WARN(warnLength,"SNES: sample length will be padded to multiple of 16"); } if (dispatch!=NULL) { MAX_RATE("SNES",dispatch->chipClock/8.0); @@ -302,8 +315,11 @@ void FurnaceGUI::drawSampleEdit() { break; case DIV_SYSTEM_AMIGA: if (sample->loop) { - if (sample->loopStart&1 || sample->loopEnd&1) { - SAMPLE_WARN(warnLoopPos,"Amiga: loop must be a multiple of 2"); + if (sample->loopStart&1) { + SAMPLE_WARN(warnLoopStart,"Amiga: loop start must be a multiple of 2"); + } + if (sample->loopEnd&1) { + SAMPLE_WARN(warnLoopEnd,"Amiga: loop end must be a multiple of 2"); } } if (sample->samples>131070) { @@ -342,8 +358,11 @@ void FurnaceGUI::drawSampleEdit() { break; case DIV_SYSTEM_C219: if (sample->loop) { - if (sample->loopStart&1 || sample->loopEnd&1) { - SAMPLE_WARN(warnLoopPos,"C219: loop must be a multiple of 2"); + if (sample->loopStart&1) { + SAMPLE_WARN(warnLoopStart,"C219: loop start must be a multiple of 2"); + } + if (sample->loopEnd&1) { + SAMPLE_WARN(warnLoopEnd,"C219: loop end must be a multiple of 2"); } } if (sample->samples>131072) { @@ -353,6 +372,10 @@ void FurnaceGUI::drawSampleEdit() { MAX_RATE("C219",dispatch->rate); } break; + case DIV_SYSTEM_MSM6295: + if (sample->loop) { + SAMPLE_WARN(warnLoop,"MSM6295: samples can't loop"); + } default: break; } @@ -411,7 +434,8 @@ void FurnaceGUI::drawSampleEdit() { ImGui::TableNextColumn(); bool doLoop=(sample->loop); pushWarningColor(!warnLoop.empty()); - if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED + String loopCheckboxName=(doLoop && (sample->loopEnd-sample->loopStart)>0)?fmt::sprintf("Loop (length: %d)##Loop",sample->loopEnd-sample->loopStart):String("Loop"); + if (ImGui::Checkbox(loopCheckboxName.c_str(),&doLoop)) { MARK_MODIFIED if (doLoop) { sample->loop=true; if (sample->loopStart<0) { @@ -428,7 +452,7 @@ void FurnaceGUI::drawSampleEdit() { } updateSampleTex=true; if (e->getSampleFormatMask()&(1U<renderSamplesP(); + e->renderSamplesP(curSample); } } popWarningColor(); @@ -458,7 +482,7 @@ void FurnaceGUI::drawSampleEdit() { sample->prepareUndo(true); e->lockEngine([this,sample,i]() { sample->convert((DivSampleDepth)i); - e->renderSamples(); + e->renderSamples(curSample); }); updateSampleTex=true; MARK_MODIFIED; @@ -479,7 +503,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::Checkbox("BRR emphasis",&be)) { sample->prepareUndo(true); sample->brrEmphasis=be; - e->renderSamplesP(); + e->renderSamplesP(curSample); updateSampleTex=true; MARK_MODIFIED; } @@ -496,7 +520,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::Checkbox("8-bit dither",&di)) { sample->prepareUndo(true); sample->dither=di; - e->renderSamplesP(); + e->renderSamplesP(curSample); updateSampleTex=true; MARK_MODIFIED; } @@ -627,7 +651,7 @@ void FurnaceGUI::drawSampleEdit() { if (ImGui::Selectable(sampleLoopModes[i])) { sample->prepareUndo(true); sample->loopMode=(DivSampleLoopMode)i; - e->renderSamplesP(); + e->renderSamplesP(curSample); updateSampleTex=true; MARK_MODIFIED; } @@ -639,7 +663,7 @@ void FurnaceGUI::drawSampleEdit() { } popWarningColor(); - pushWarningColor(!warnLoopPos.empty()); + pushWarningColor(!warnLoopPos.empty() || !warnLoopStart.empty()); ImGui::AlignTextToFramePadding(); ImGui::Text("Start"); ImGui::SameLine(); @@ -653,19 +677,29 @@ void FurnaceGUI::drawSampleEdit() { } updateSampleTex=true; if (e->getSampleFormatMask()&(1U<renderSamplesP(); + e->renderSamplesP(curSample); } } if (ImGui::IsItemActive()) { keepLoopAlive=true; } - if (ImGui::IsItemHovered() && (!warnLoopPos.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) { - if (sample->depth==DIV_SAMPLE_DEPTH_BRR) { - SAMPLE_WARN(warnLoopPos,"changing the loop in a BRR sample may result in glitches!"); + if (ImGui::IsItemHovered() && (!warnLoopPos.empty() || !warnLoopStart.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) { + if (ImGui::BeginTooltip()) { + if (sample->depth==DIV_SAMPLE_DEPTH_BRR) { + ImGui::Text("changing the loop in a BRR sample may result in glitches!"); + } + if (!warnLoopStart.empty()) { + ImGui::Text("%s",warnLoopStart.c_str()); + } + if (!warnLoopPos.empty()) { + ImGui::Text("%s",warnLoopPos.c_str()); + } + ImGui::EndTooltip(); } - ImGui::SetTooltip("%s",warnLoopPos.c_str()); } + popWarningColor(); + pushWarningColor(!warnLoopPos.empty() || !warnLoopEnd.empty()); ImGui::AlignTextToFramePadding(); ImGui::Text("End"); ImGui::SameLine(); @@ -679,17 +713,25 @@ void FurnaceGUI::drawSampleEdit() { } updateSampleTex=true; if (e->getSampleFormatMask()&(1U<renderSamplesP(); + e->renderSamplesP(curSample); } } if (ImGui::IsItemActive()) { keepLoopAlive=true; } - if (ImGui::IsItemHovered() && (!warnLoopPos.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) { - if (sample->depth==DIV_SAMPLE_DEPTH_BRR) { - SAMPLE_WARN(warnLoopPos,"changing the loop in a BRR sample may result in glitches!"); + if (ImGui::IsItemHovered() && (!warnLoopPos.empty() || !warnLoopEnd.empty() || sample->depth==DIV_SAMPLE_DEPTH_BRR)) { + if (ImGui::BeginTooltip()) { + if (sample->depth==DIV_SAMPLE_DEPTH_BRR) { + ImGui::Text("changing the loop in a BRR sample may result in glitches!"); + } + if (!warnLoopEnd.empty()) { + ImGui::Text("%s",warnLoopEnd.c_str()); + } + if (!warnLoopPos.empty()) { + ImGui::Text("%s",warnLoopPos.c_str()); + } + ImGui::EndTooltip(); } - ImGui::SetTooltip("%s",warnLoopPos.c_str()); } popWarningColor(); ImGui::EndDisabled(); @@ -748,7 +790,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::PushStyleColor(ImGuiCol_CheckMark,baseColor); if (ImGui::Checkbox(id,&sample->renderOn[i][j])) { - e->renderSamplesP(); + e->renderSamplesP(curSample); } ImGui::PopStyleColor(4); @@ -791,12 +833,6 @@ void FurnaceGUI::drawSampleEdit() { ImGui::EndTable(); } - /* - if (ImGui::Button("Apply")) { - e->renderSamplesP(); - } - ImGui::SameLine(); - */ ImGui::Separator(); pushToggleColors(!sampleDragMode); @@ -842,7 +878,7 @@ void FurnaceGUI::drawSampleEdit() { if (!sample->resize(resizeSize)) { showError("couldn't resize! make sure your sample is 8 or 16-bit."); } - e->renderSamples(); + e->renderSamples(curSample); }); updateSampleTex=true; sampleSelStart=-1; @@ -897,7 +933,7 @@ void FurnaceGUI::drawSampleEdit() { if (!sample->resample(targetRate,resampleTarget,resampleStrat)) { showError("couldn't resample! make sure your sample is 8 or 16-bit."); } - e->renderSamples(); + e->renderSamples(curSample); }); updateSampleTex=true; sampleSelStart=-1; @@ -968,7 +1004,7 @@ void FurnaceGUI::drawSampleEdit() { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; ImGui::CloseCurrentPopup(); @@ -1017,7 +1053,7 @@ void FurnaceGUI::drawSampleEdit() { if (!sample->insert(pos,silenceSize)) { showError("couldn't insert! make sure your sample is 8 or 16-bit."); } - e->renderSamples(); + e->renderSamples(curSample); }); updateSampleTex=true; sampleSelStart=pos; @@ -1178,7 +1214,7 @@ void FurnaceGUI::drawSampleEdit() { updateSampleTex=true; - e->renderSamples(); + e->renderSamples(curSample); }); MARK_MODIFIED; ImGui::CloseCurrentPopup(); @@ -1865,7 +1901,7 @@ void FurnaceGUI::doUndoSample() { DivSample* sample=e->song.sample[curSample]; e->lockEngine([this,sample]() { if (sample->undo()==2) { - e->renderSamples(); + e->renderSamples(curSample); updateSampleTex=true; } }); @@ -1877,7 +1913,7 @@ void FurnaceGUI::doRedoSample() { DivSample* sample=e->song.sample[curSample]; e->lockEngine([this,sample]() { if (sample->redo()==2) { - e->renderSamples(); + e->renderSamples(curSample); updateSampleTex=true; } }); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 5d49c021e..51ea3cb01 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -498,8 +498,24 @@ void FurnaceGUI::drawSettings() { } ImGui::Unindent(); - // SUBSECTION CHIP - CONFIG_SUBSECTION("Chip"); + bool writeInsNamesB=settings.writeInsNames; + if (ImGui::Checkbox("Store instrument name in .fui",&writeInsNamesB)) { + settings.writeInsNames=writeInsNamesB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, saving an instrument will store its name.\nthis may increase file size."); + } + + bool readInsNamesB=settings.readInsNames; + if (ImGui::Checkbox("Load instrument name from .fui",&readInsNamesB)) { + settings.readInsNames=readInsNamesB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, loading an instrument will use the stored name (if present).\notherwise, it will use the file name."); + } + + // SUBSECTION NEW SONG + CONFIG_SUBSECTION("New Song"); ImGui::AlignTextToFramePadding(); ImGui::Text("Initial system:"); ImGui::SameLine(); @@ -653,7 +669,7 @@ void FurnaceGUI::drawSettings() { String sysFlagsS=settings.initialSys.getString(fmt::sprintf("flags%d",i),""); DivConfig sysFlags; sysFlags.loadFromBase64(sysFlagsS.c_str()); - if (drawSysConf(-1,sysID,sysFlags,false)) { + if (drawSysConf(-1,i,sysID,sysFlags,false)) { settings.initialSys.set(fmt::sprintf("flags%d",i),sysFlags.toBase64()); } ImGui::TreePop(); @@ -967,7 +983,7 @@ void FurnaceGUI::drawSettings() { // SUBSECTION METRONOME CONFIG_SUBSECTION("Metronome"); ImGui::AlignTextToFramePadding(); - ImGui::Text("Metronome volume"); + ImGui::Text("Volume"); ImGui::SameLine(); if (ImGui::SliderInt("##MetroVol",&settings.metroVol,0,200,"%d%%")) { if (settings.metroVol<0) settings.metroVol=0; @@ -975,6 +991,17 @@ void FurnaceGUI::drawSettings() { e->setMetronomeVol(((float)settings.metroVol)/100.0f); } + // SUBSECTION SAMPLE PREVIEW + CONFIG_SUBSECTION("Sample preview"); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Volume"); + ImGui::SameLine(); + if (ImGui::SliderInt("##SampleVol",&settings.sampleVol,0,100,"%d%%")) { + if (settings.sampleVol<0) settings.sampleVol=0; + if (settings.sampleVol>100) settings.sampleVol=100; + e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f); + } + END_SECTION; } CONFIG_SECTION("MIDI") { @@ -3246,6 +3273,7 @@ void FurnaceGUI::syncSettings() { settings.separateFMColors=e->getConfInt("separateFMColors",0); settings.insEditColorize=e->getConfInt("insEditColorize",0); settings.metroVol=e->getConfInt("metroVol",100); + settings.sampleVol=e->getConfInt("sampleVol",50); settings.pushNibble=e->getConfInt("pushNibble",0); settings.scrollChangesOrder=e->getConfInt("scrollChangesOrder",0); settings.oplStandardWaveNames=e->getConfInt("oplStandardWaveNames",0); @@ -3329,6 +3357,8 @@ void FurnaceGUI::syncSettings() { settings.chanOscThreads=e->getConfInt("chanOscThreads",0); settings.renderPoolThreads=e->getConfInt("renderPoolThreads",0); settings.showPool=e->getConfInt("showPool",0); + settings.writeInsNames=e->getConfInt("writeInsNames",1); + settings.readInsNames=e->getConfInt("readInsNames",1); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.headFontSize,2,96); @@ -3407,6 +3437,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.separateFMColors,0,1); clampSetting(settings.insEditColorize,0,1); clampSetting(settings.metroVol,0,200); + clampSetting(settings.sampleVol,0,100); clampSetting(settings.pushNibble,0,1); clampSetting(settings.scrollChangesOrder,0,2); clampSetting(settings.oplStandardWaveNames,0,1); @@ -3481,6 +3512,8 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.chanOscThreads,0,256); clampSetting(settings.renderPoolThreads,0,DIV_MAX_CHIPS); clampSetting(settings.showPool,0,1); + clampSetting(settings.writeInsNames,0,1); + clampSetting(settings.readInsNames,0,1); if (settings.exportLoops<0.0) settings.exportLoops=0.0; if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0; @@ -3535,6 +3568,7 @@ void FurnaceGUI::syncSettings() { e->setMidiDirect(midiMap.directChannel); e->setMetronomeVol(((float)settings.metroVol)/100.0f); + e->setSamplePreviewVol(((float)settings.sampleVol)/100.0f); } void FurnaceGUI::commitSettings() { @@ -3656,6 +3690,7 @@ void FurnaceGUI::commitSettings() { e->setConf("separateFMColors",settings.separateFMColors); e->setConf("insEditColorize",settings.insEditColorize); e->setConf("metroVol",settings.metroVol); + e->setConf("sampleVol",settings.sampleVol); e->setConf("pushNibble",settings.pushNibble); e->setConf("scrollChangesOrder",settings.scrollChangesOrder); e->setConf("oplStandardWaveNames",settings.oplStandardWaveNames); @@ -3740,6 +3775,8 @@ void FurnaceGUI::commitSettings() { e->setConf("chanOscThreads",settings.chanOscThreads); e->setConf("renderPoolThreads",settings.renderPoolThreads); e->setConf("showPool",settings.showPool); + e->setConf("writeInsNames",settings.writeInsNames); + e->setConf("readInsNames",settings.readInsNames); // colors for (int i=0; igetCurrentSubSong())) { e->changeSongP(i); updateScroll(0); - oldOrder=0; - oldOrder1=0; oldRow=0; cursor.xCoarse=0; cursor.xFine=0; @@ -76,8 +74,6 @@ void FurnaceGUI::drawSubSongs(bool asChild) { } else { e->changeSongP(e->song.subsong.size()-1); updateScroll(0); - oldOrder=0; - oldOrder1=0; oldRow=0; cursor.xCoarse=0; cursor.xFine=0; @@ -98,8 +94,6 @@ void FurnaceGUI::drawSubSongs(bool asChild) { } else { e->changeSongP(e->song.subsong.size()-1); updateScroll(0); - oldOrder=0; - oldOrder1=0; oldRow=0; cursor.xCoarse=0; cursor.xFine=0; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 87d94ec08..6dd42bea7 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -22,7 +22,7 @@ #include "misc/cpp/imgui_stdlib.h" #include -bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu) { +bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu) { bool altered=false; bool restart=modifyOnChange; bool supportsCustomRate=true; @@ -461,6 +461,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } case DIV_SYSTEM_YM2151: { int clockSel=flags.getInt("clockSel",0); + bool brokenPitch=flags.getBool("brokenPitch",false); ImGui::Indent(); if (ImGui::RadioButton("NTSC/X16 (3.58MHz)",clockSel==0)) { @@ -477,9 +478,34 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } ImGui::Unindent(); + if (ImGui::Checkbox("Broken pitch macro/slides (compatibility)",&brokenPitch)) { + altered=true; + } + if (altered) { e->lockSave([&]() { flags.set("clockSel",clockSel); + flags.set("brokenPitch",brokenPitch); + }); + } + break; + } + case DIV_SYSTEM_OPZ: { + bool clockSel=flags.getInt("clockSel",0); + bool brokenPitch=flags.getBool("brokenPitch",false); + + if (ImGui::Checkbox("Pseudo-PAL",&clockSel)) { + altered=true; + } + + if (ImGui::Checkbox("Broken pitch macro/slides (compatibility)",&brokenPitch)) { + altered=true; + } + + if (altered) { + e->lockSave([&]() { + flags.set("clockSel",(int)clockSel); + flags.set("brokenPitch",brokenPitch); }); } break; @@ -1338,6 +1364,64 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo altered=true; } ImGui::Unindent(); + + int chipClock=flags.getInt("customClock",0); + if (!chipClock) { + switch (clockSel) { + case 0: + chipClock=4000000; + break; + case 1: + chipClock=4096000; + break; + case 2: + chipClock=8000000; + break; + case 3: + chipClock=8192000; + break; + } + } + + ImGui::Text("Sample rate table:"); + if (ImGui::BeginTable("6258Rate",3)) { + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("divider \\ clock"); + ImGui::TableNextColumn(); + ImGui::Text("full"); + ImGui::TableNextColumn(); + ImGui::Text("half"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/512"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/512); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1024); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/768"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/768); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1536); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(ImGuiCol_TableHeaderBg)); + ImGui::Text("/1024"); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/1024); + ImGui::TableNextColumn(); + ImGui::Text("%dHz",chipClock/2048); + + ImGui::EndTable(); + } if (altered) { e->lockSave([&]() { @@ -1756,11 +1840,11 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); // wavetable text input size found here - if (ImGui::InputText("##MMLWave",&mmlStringSNES)) { + if (ImGui::InputText("##MMLWave",&mmlStringSNES[sysPos])) { int actualData[256]; int discardIt=0; memset(actualData,0,256*sizeof(int)); - decodeMMLStrW(mmlStringSNES,actualData,discardIt,snesFilterHex?0:-128,snesFilterHex?255:127,snesFilterHex); + decodeMMLStrW(mmlStringSNES[sysPos],actualData,discardIt,snesFilterHex?0:-128,snesFilterHex?255:127,snesFilterHex); if (snesFilterHex) { for (int i=0; i<8; i++) { if (actualData[i]>=128) actualData[i]-=256; @@ -1778,7 +1862,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo actualData[i]=echoFilter[i]; } } - encodeMMLStr(mmlStringSNES,actualData,8,-1,-1,snesFilterHex); + encodeMMLStr(mmlStringSNES[sysPos],actualData,8,-1,-1,snesFilterHex); } int filterSum=( diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index ad71e0e86..80f9c001a 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -79,7 +79,7 @@ void FurnaceGUI::drawSysManager() { } ImGui::TableNextColumn(); if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSM%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true); + drawSysConf(i,i,e->song.system[i],e->song.systemFlags[i],true); ImGui::TreePop(); } ImGui::TableNextColumn(); diff --git a/src/main.cpp b/src/main.cpp index 6cc6b803d..7c7c0dd51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include "pch.h" #ifdef HAVE_SDL2 #include "SDL_events.h" #endif @@ -167,6 +167,7 @@ TAParamResult pVersion(String) { printf("- SDL2 by Sam Lantinga (zlib license)\n"); printf("- zlib by Jean-loup Gailly and Mark Adler (zlib license)\n"); printf("- PortAudio (PortAudio license)\n"); + printf("- Weak-JACK by x42 (GPLv2)\n"); printf("- RtMidi by Gary P. Scavone (RtMidi license)\n"); printf("- backward-cpp by Google (MIT)\n"); printf("- Dear ImGui by Omar Cornut (MIT)\n"); diff --git a/src/pch.cpp b/src/pch.cpp new file mode 100644 index 000000000..b1cd9d3f5 --- /dev/null +++ b/src/pch.cpp @@ -0,0 +1,20 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "pch.h" \ No newline at end of file diff --git a/src/pch.h b/src/pch.h new file mode 100644 index 000000000..7821ee302 --- /dev/null +++ b/src/pch.h @@ -0,0 +1,30 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef FUR_PCH_H +#define FUR_PCH_H + +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include + +#endif diff --git a/src/ta-log.h b/src/ta-log.h index d36f5da7d..de93e24a7 100644 --- a/src/ta-log.h +++ b/src/ta-log.h @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include "pch.h" #define LOGLEVEL_ERROR 0 #define LOGLEVEL_WARN 1 diff --git a/src/ta-utils.h b/src/ta-utils.h index 0b81cc853..6b3c201f5 100644 --- a/src/ta-utils.h +++ b/src/ta-utils.h @@ -21,7 +21,7 @@ #define _TA_UTILS_H #include #include -#include +#include "pch.h" #ifdef _MSC_VER #include