Merge branch 'tildearrow:master' into master
This commit is contained in:
commit
16aed41e89
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -32,3 +32,4 @@ res/binary_to_compressed_c.exe
|
||||||
res/docpdf/manual.html
|
res/docpdf/manual.html
|
||||||
res/docpdf/manual.pdf
|
res/docpdf/manual.pdf
|
||||||
res/docpdf/.venv
|
res/docpdf/.venv
|
||||||
|
res/furnace.appdata.xml
|
||||||
|
|
|
@ -25,6 +25,15 @@ set(SYSTEM_SDL2_DEFAULT OFF)
|
||||||
include(CheckIncludeFile)
|
include(CheckIncludeFile)
|
||||||
include(TestBigEndian)
|
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)
|
if (ANDROID)
|
||||||
set(USE_RTMIDI_DEFAULT OFF)
|
set(USE_RTMIDI_DEFAULT OFF)
|
||||||
set(WITH_PORTAUDIO_DEFAULT OFF)
|
set(WITH_PORTAUDIO_DEFAULT OFF)
|
||||||
|
@ -357,14 +366,16 @@ endif()
|
||||||
if (WITH_JACK)
|
if (WITH_JACK)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(JACK REQUIRED jack)
|
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 AUDIO_SOURCES src/audio/jack.cpp)
|
||||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${JACK_INCLUDE_DIRS})
|
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${JACK_INCLUDE_DIRS})
|
||||||
list(APPEND DEPENDENCIES_DEFINES HAVE_JACK)
|
list(APPEND DEPENDENCIES_DEFINES HAVE_JACK)
|
||||||
list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${JACK_CFLAGS_OTHER})
|
list(APPEND DEPENDENCIES_DEFINES USE_WEAK_JACK)
|
||||||
list(APPEND DEPENDENCIES_LIBRARIES ${JACK_LIBRARIES})
|
#list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${JACK_CFLAGS_OTHER})
|
||||||
list(APPEND DEPENDENCIES_LIBRARY_DIRS ${JACK_LIBRARY_DIRS})
|
#list(APPEND DEPENDENCIES_LIBRARIES ${JACK_LIBRARIES})
|
||||||
list(APPEND DEPENDENCIES_LINK_OPTIONS ${JACK_LDFLAGS_OTHER})
|
#list(APPEND DEPENDENCIES_LIBRARY_DIRS ${JACK_LIBRARY_DIRS})
|
||||||
list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${JACK_LDFLAGS})
|
#list(APPEND DEPENDENCIES_LINK_OPTIONS ${JACK_LDFLAGS_OTHER})
|
||||||
|
#list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${JACK_LDFLAGS})
|
||||||
message(STATUS "Building with JACK support")
|
message(STATUS "Building with JACK support")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Building without JACK support")
|
message(STATUS "Building without JACK support")
|
||||||
|
@ -920,6 +931,15 @@ if (WARNINGS_ARE_ERRORS)
|
||||||
)
|
)
|
||||||
endif()
|
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)
|
if(ANDROID AND NOT TERMUX)
|
||||||
add_library(furnace SHARED ${USED_SOURCES})
|
add_library(furnace SHARED ${USED_SOURCES})
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
|
@ -950,7 +970,9 @@ if (NOT ANDROID OR TERMUX)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS furnace RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS furnace RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
install(FILES res/furnace.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
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 doc DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||||
install(DIRECTORY papers DESTINATION ${CMAKE_INSTALL_DOCDIR}/other)
|
install(DIRECTORY papers DESTINATION ${CMAKE_INSTALL_DOCDIR}/other)
|
||||||
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/furnace)
|
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/licenses/furnace)
|
||||||
|
|
|
@ -15,8 +15,8 @@ android {
|
||||||
}
|
}
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 26
|
targetSdkVersion 26
|
||||||
versionCode 175
|
versionCode 178
|
||||||
versionName "0.6pre14"
|
versionName "0.6pre16"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"
|
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.tildearrow.furnace"
|
package="org.tildearrow.furnace"
|
||||||
android:versionCode="175"
|
android:versionCode="178"
|
||||||
android:versionName="0.6pre14"
|
android:versionName="0.6pre16"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
<!-- OpenGL ES 2.0 -->
|
<!-- OpenGL ES 2.0 -->
|
||||||
|
|
|
@ -3,29 +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.
|
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:
|
among the features that cannot be accessed in this mode are:
|
||||||
- edit menu:
|
|
||||||
- paste special
|
### edit menu
|
||||||
- operation masking
|
- paste special
|
||||||
- input latch
|
- operation masking
|
||||||
- find and replace
|
- input latch
|
||||||
- speed window:
|
- find and replace
|
||||||
- virtual tempo
|
|
||||||
- divider
|
### speed window
|
||||||
- song length
|
- virtual tempo
|
||||||
- song info window:
|
- divider
|
||||||
- manual system naming
|
- song length
|
||||||
- tuning options
|
|
||||||
- right-clicking on the pattern window:
|
### song info window
|
||||||
- gradient/fade
|
- manual system naming
|
||||||
- scale
|
- tuning options
|
||||||
- randomize
|
|
||||||
- invert values
|
### pattern right-click menu
|
||||||
- flip selection
|
- gradient/fade
|
||||||
- collapse
|
- scale
|
||||||
- expand
|
- randomize
|
||||||
- these windows:
|
- invert values
|
||||||
- mixer
|
- flip selection
|
||||||
- grooves
|
- collapse
|
||||||
- channels
|
- expand
|
||||||
- pattern manager
|
|
||||||
- compatibility flags
|
### other windows
|
||||||
|
- mixer
|
||||||
|
- grooves
|
||||||
|
- channels
|
||||||
|
- pattern manager
|
||||||
|
- compatibility flags
|
||||||
|
|
|
@ -32,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.
|
- **Loops**: number of additional times to play through `0Bxx` song loop.
|
||||||
- **Fade out (seconds)**: length of fade out after final loop.
|
- **Fade out (seconds)**: length of fade out after final loop.
|
||||||
- **Remember last values**
|
- **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.
|
- **Initial system**: the system of chips loaded on starting Furnace.
|
||||||
- **Current system**: sets current chips as default.
|
- **Current system**: sets current chips as default.
|
||||||
|
@ -105,7 +107,11 @@ settings are saved when clicking the **OK** or **Apply** buttons at the bottom o
|
||||||
|
|
||||||
### Metronome
|
### Metronome
|
||||||
|
|
||||||
- **Metronome volume**: sets volume of metronome.
|
- **Volume**: sets volume of metronome.
|
||||||
|
|
||||||
|
### Sample preview
|
||||||
|
|
||||||
|
- **Volume**: sets volume of sample preview.
|
||||||
|
|
||||||
## MIDI
|
## MIDI
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ the OPL FM editor is divided into 7 tabs:
|
||||||
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
- **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 (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 (OP4)**: for macros controlling FM parameters of operator 4 (only when 4-op flag is set and only on OPL3!).
|
||||||
- **Macros**: for miscellaneous macros controlling volume, arpeggio, and OPL3 panning.
|
- **Macros**: for other macros (volume/arp/pitch/pan).
|
||||||
|
|
||||||
## FM
|
## FM
|
||||||
|
|
||||||
|
@ -40,13 +40,14 @@ these apply to each operator:
|
||||||

|

|
||||||
|
|
||||||
- **Key Scale Rate (KSR)**: also known as "Rate Scale". determines the degree to which the envelope execution speed increases according to the pitch.
|
- **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)**: determines the operator frequency in relation to the pitch (0-15 range but be noted that 11, 13 and 14 have no effect!).
|
- **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).
|
- **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.
|
- **Vibrato (VIB)**: makes the operator affected by LFO vibrato.
|
||||||
|
|
||||||
## macros
|
## 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:
|
these macros allow you to control several parameters of FM per tick.
|
||||||
|
|
||||||
## FM Macros
|
## FM Macros
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ the OPLL FM editor is divided into 5 tabs:
|
||||||
- **Macros (FM)**: for macros controlling algorithm, waveform and feedback.
|
- **Macros (FM)**: for macros controlling algorithm, waveform and feedback.
|
||||||
- **Macros (OP1)**: for macros controlling FM parameters of operator 1.
|
- **Macros (OP1)**: for macros controlling FM parameters of operator 1.
|
||||||
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
||||||
- **Macros**: for miscellaneous macros controlling volume, arpeggio, and preset.
|
- **Macros**: for other macros (volume/arp/pitch/patch).
|
||||||
|
|
||||||
## FM
|
## FM
|
||||||
|
|
||||||
|
@ -43,12 +43,13 @@ these apply to each operator:
|
||||||

|

|
||||||
|
|
||||||
- **Envelope Scale (KSR)**: also known as "Key Scale". determines the degree to which the envelope execution speed increases according to the pitch.
|
- **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)
|
- **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.
|
- **Vibrato (VIB)**: makes the operator affected by LFO vibrato.
|
||||||
|
|
||||||
## macros
|
## 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:
|
these macros allow you to control several parameters of FM per tick.
|
||||||
|
|
||||||
## FM Macros
|
## FM Macros
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ the FM editor is divided into 7 tabs:
|
||||||
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
||||||
- **Macros (OP3)**: for macros controlling FM parameters of operator 3.
|
- **Macros (OP3)**: for macros controlling FM parameters of operator 3.
|
||||||
- **Macros (OP4)**: for macros controlling FM parameters of operator 4.
|
- **Macros (OP4)**: for macros controlling FM parameters of operator 4.
|
||||||
- **Macros**: for miscellaneous macros controlling volume, arpeggio, and noise generator.
|
- **Macros**: for other macros (volume/arp/pitch/noise).
|
||||||
|
|
||||||
## FM
|
## FM
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ these apply to each operator:
|
||||||

|

|
||||||
|
|
||||||
- **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).
|
- **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)**: determines the operator frequency in relation to the pitch (0 to 15).
|
- **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).
|
- **Fine Detune (DT)**: shifts the pitch a little (0 to 7).
|
||||||
- **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3).
|
- **Coarse Detune (DT2)**: shifts the pitch by tens of cents (0 to 3).
|
||||||
|
|
||||||
|
|
||||||
## macros
|
## 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:
|
these macros allow you to control several parameters of FM per tick.
|
||||||
|
|
||||||
## FM Macros
|
## FM Macros
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ the FM editor is divided into 7 tabs:
|
||||||
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
- **Macros (OP2)**: for macros controlling FM parameters of operator 2.
|
||||||
- **Macros (OP3)**: for macros controlling FM parameters of operator 3.
|
- **Macros (OP3)**: for macros controlling FM parameters of operator 3.
|
||||||
- **Macros (OP4)**: for macros controlling FM parameters of operator 4.
|
- **Macros (OP4)**: for macros controlling FM parameters of operator 4.
|
||||||
- **Macros**: for miscellaneous macros controlling volume, arpeggio, and pitch.
|
- **Macros**: for other macros (volume/arp/pitch).
|
||||||
|
|
||||||
## FM
|
## FM
|
||||||
|
|
||||||
|
@ -44,13 +44,13 @@ these apply to each operator:
|
||||||

|

|
||||||
|
|
||||||
- **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).
|
- **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)**: determines the operator frequency in relation to the pitch (0 to 15).
|
- **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).
|
- **Fine Detune (DT)**: shifts the pitch a little (0 to 7).
|
||||||
|
|
||||||
|
|
||||||
## macros
|
## 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:
|
these macros allow you to control several parameters of FM per tick.
|
||||||
|
|
||||||
## FM Macros
|
## FM Macros
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# FM (OPM) instrument editor
|
# FM (OPZ) instrument editor
|
||||||
|
|
||||||
the FM editor is divided into 7 tabs:
|
the FM editor is divided into 7 tabs:
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ the FM editor is divided into 7 tabs:
|
||||||
- **Macros (OP2)**: for macros controlling FM parameters of operator 2
|
- **Macros (OP2)**: for macros controlling FM parameters of operator 2
|
||||||
- **Macros (OP3)**: for macros controlling FM parameters of operator 3
|
- **Macros (OP3)**: for macros controlling FM parameters of operator 3
|
||||||
- **Macros (OP4)**: for macros controlling FM parameters of operator 4
|
- **Macros (OP4)**: for macros controlling FM parameters of operator 4
|
||||||
- **Macros**: for miscellaneous macros controlling volume, arpeggio, and YM2151 noise generator.
|
- **Macros**: for other macros (volume/arp/pitch/noise).
|
||||||
|
|
||||||
## FM
|
## FM
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ these apply to each operator:
|
||||||

|

|
||||||
|
|
||||||
- **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).
|
- **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)**: determines the operator frequency in relation to the pitch (0 to 15).
|
- **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.
|
- **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.
|
- **Envelope Generator Shift (EGS)**: adds a "handicap" to the envelope. in other words, the minimum volume of the operator.
|
||||||
- 0: no change
|
- 0: no change
|
||||||
|
@ -69,7 +69,7 @@ each operator has a Fixed Frequency mode. once enabled, the operator runs at the
|
||||||
|
|
||||||
## macros
|
## 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:
|
these macros allow you to control several parameters of FM per tick.
|
||||||
|
|
||||||
## FM Macros
|
## FM Macros
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,6 @@ furthermore, many of these chips have a limited amount of sample memory. check m
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
in there, you can modify certain data pertaining to your sample, such as the:
|
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)
|
- 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)
|
||||||
- the sample rate.
|
- the sample rate.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
a backwards-compatible successor to the AY-3-8910, with increased volume resolution, duty cycle control, three envelopes and highly configurable noise generator.
|
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.
|
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.
|
emulation of this chip in Furnace is now complete thanks to community efforts and hardware testing, which an MSX board called Darky has permitted.
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ this console is powered by two sound chips: the [Yamaha YM2612](ym2612.md) and [
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `17xx`: **enable PCM channel.**
|
- `17xx`: **enable PCM channel.**
|
||||||
- this only works on channel 6.
|
- 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).
|
- _this effect is here for compatibility reasons!_ it is otherwise recommended to use Sample type instruments (which automatically enable PCM mode when used).
|
||||||
|
|
|
@ -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.
|
this is one of Namco's NES mappers, with up to 8 wavetable channels.
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ afterwards everyone moved to Windows and software mixed PCM streaming...
|
||||||
- only in 4-op mode (OPL3).
|
- only in 4-op mode (OPL3).
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4; last 2 operators only in 4-op mode).
|
- `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.**
|
- `17xx`: **set vibrato depth.**
|
||||||
- `0`: normal
|
- `0`: normal
|
||||||
- `1`: double
|
- `1`: double
|
||||||
|
|
|
@ -32,7 +32,7 @@ the YM2413 is equipped with the following features:
|
||||||
- `13xx`: **set operator 2 level.**
|
- `13xx`: **set operator 2 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator, either 1 or 2.
|
- `x` is the operator, either 1 or 2.
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `18xx`: **toggle drums mode.**
|
- `18xx`: **toggle drums mode.**
|
||||||
- `0` disables it and `1` enables it.
|
- `0` disables it and `1` enables it.
|
||||||
- only in drums mode.
|
- only in drums mode.
|
||||||
|
|
|
@ -33,7 +33,7 @@ no plans have been made for TX81Z MIDI passthrough, because:
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `17xx`: **set LFO speed.**
|
- `17xx`: **set LFO speed.**
|
||||||
- `18xx`: **set LFO waveform.** `xx` may be one of the following:
|
- `18xx`: **set LFO waveform.** `xx` may be one of the following:
|
||||||
- `00`: saw
|
- `00`: saw
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
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.
|
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 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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ a relatively simple sound chip made by Texas Instruments. a derivative of it is
|
||||||
|
|
||||||
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.
|
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 13670 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.
|
||||||
|
|
||||||
## SN7 versions
|
## SN7 versions
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,17 @@
|
||||||
# Seta/Allumer X1-010
|
# 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.
|
the X1-010 is a chip used by Seta (and Allumer) in the Seta 1 and 2 arcade boards.
|
||||||
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.
|
|
||||||
|
|
||||||
it has 16 channels, which can all be switched between PCM sample or wavetable playback mode.
|
it has 16 channels of wavetable sound with some support for 8-bit samples up to 128KB in length.
|
||||||
wavetable playback needs to paired with envelope, similar to AY PSG, but shapes are stored in RAM and as such are user-definable.
|
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.
|
this chip was the inspiration for Organya/PxTone (the former being used in a well-known game called Cave Story).
|
||||||
these are stored at the lower half of RAM at common case.
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -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.
|
- range is 1.95KHz to 498KHz if the chip clock is 16MHz.
|
||||||
- `22xx`: **set envelope mode.**
|
- `22xx`: **set envelope mode.**
|
||||||
- bit 0 sets whether envelope will affect this channel.
|
- 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 1 sets whether envelope will run once instead of looping.
|
||||||
- bit 2 toggles the envelope shape split mode. when it is set, envelope shape will be split to left half and right half.
|
- 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 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.
|
- bit 4/6 sets whether the right/left output will mirror the original one.
|
||||||
- `23xx`: **set envelope period.**
|
- `23xx`: **set envelope period.**
|
||||||
|
|
|
@ -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.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `17xx`: **set LFO speed.**
|
- `17xx`: **set LFO speed.**
|
||||||
- `18xx`: **set LFO waveform.**
|
- `18xx`: **set LFO waveform.**
|
||||||
- `00`: saw
|
- `00`: saw
|
||||||
|
|
|
@ -18,7 +18,7 @@ several variants of this chip were released as well, with more features.
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator from 1 to 4.
|
- `x` is the operator from 1 to 4.
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `18xx`: **toggle extended channel 3 mode.**
|
- `18xx`: **toggle extended channel 3 mode.**
|
||||||
- `0` disables it and `1` enables it.
|
- `0` disables it and `1` enables it.
|
||||||
- only in extended channel 3 chip.
|
- only in extended channel 3 chip.
|
||||||
|
|
|
@ -18,7 +18,7 @@ the YM2610 (OPNB) and YM2610B chips are very similar to this one, but the built-
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `18xx`: **toggle extended channel 3 mode.**
|
- `18xx`: **toggle extended channel 3 mode.**
|
||||||
- `0` disables it and `1` enables it.
|
- `0` disables it and `1` enables it.
|
||||||
- only in extended channel 3 chip.
|
- only in extended channel 3 chip.
|
||||||
|
|
|
@ -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.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `18xx`: **toggle extended channel 2 mode.**
|
- `18xx`: **toggle extended channel 2 mode.**
|
||||||
- 0 disables it and 1 enables it.
|
- 0 disables it and 1 enables it.
|
||||||
- only in extended channel 2 chip.
|
- only in extended channel 2 chip.
|
||||||
|
|
|
@ -15,7 +15,7 @@ it is backward compatible with the original chip.
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `18xx`: **toggle extended channel 3 mode.**
|
- `18xx`: **toggle extended channel 3 mode.**
|
||||||
- 0 disables it and 1 enables it.
|
- 0 disables it and 1 enables it.
|
||||||
- only in extended channel 3 chip.
|
- only in extended channel 3 chip.
|
||||||
|
|
|
@ -30,7 +30,7 @@ thanks to the Z80 sound CPU, DualPCM can play two samples at once! this mode spl
|
||||||
- `15xx`: **set operator 4 level.**
|
- `15xx`: **set operator 4 level.**
|
||||||
- `16xy`: **set multiplier of operator.**
|
- `16xy`: **set multiplier of operator.**
|
||||||
- `x` is the operator (1-4).
|
- `x` is the operator (1-4).
|
||||||
- `y` is the multiplier.
|
- `y` is the new MULT value..
|
||||||
- `17xx`: **toggle LEGACY sample mode.**
|
- `17xx`: **toggle LEGACY sample mode.**
|
||||||
- this only works on channel 6.
|
- this only works on channel 6.
|
||||||
- **this effect exists only for compatibility reasons! its use is NOT recommented. use Sample type instruments instead.**
|
- **this effect exists only for compatibility reasons! its use is NOT recommented. use Sample type instruments instead.**
|
||||||
|
|
|
@ -22,6 +22,15 @@ the index follows.
|
||||||
- freq-mod
|
- freq-mod
|
||||||
- host12prog
|
- host12prog
|
||||||
- nicco1690
|
- nicco1690
|
||||||
- polluks
|
|
||||||
- tildearrow
|
- tildearrow
|
||||||
- WindowxDeveloper
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
|
||||||
|
|
1
extern/weakjack/.gitignore
vendored
Normal file
1
extern/weakjack/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.swp
|
79
extern/weakjack/README.md
vendored
Normal file
79
extern/weakjack/README.md
vendored
Normal file
|
@ -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<jack/*>` 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
|
291
extern/weakjack/weak_libjack.c
vendored
Normal file
291
extern/weakjack/weak_libjack.c
vendored
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
/* runtime/weak dynamic JACK linking
|
||||||
|
*
|
||||||
|
* (C) 2014 Robin Gareus <robin@gareus.org>
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#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
|
179
extern/weakjack/weak_libjack.def
vendored
Normal file
179
extern/weakjack/weak_libjack.def
vendored
Normal file
|
@ -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
|
||||||
|
|
||||||
|
/* <jack/jack.h> */
|
||||||
|
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)
|
||||||
|
|
||||||
|
/* <jack/midiport.h> */
|
||||||
|
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),)
|
||||||
|
|
||||||
|
/* <jack/session.h> */
|
||||||
|
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), )
|
||||||
|
|
||||||
|
/* <jack/ringbuffer.h> */
|
||||||
|
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)
|
||||||
|
|
||||||
|
/* <jack/thread.h> */
|
||||||
|
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
|
||||||
|
/* <jack/uuid.h> - TODO*/
|
||||||
|
|
||||||
|
/* <jack/jack.h> */
|
||||||
|
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)
|
||||||
|
|
||||||
|
/* <jack/metadata.h> */
|
||||||
|
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
|
||||||
|
|
||||||
|
/* <jack/statistics.h> */
|
||||||
|
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
|
230
extern/weakjack/weak_libjack.h
vendored
Normal file
230
extern/weakjack/weak_libjack.h
vendored
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
/* runtime/weak dynamic JACK linking
|
||||||
|
*
|
||||||
|
* (C) 2014 Robin Gareus <robin@gareus.org>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/* <jack/jack.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/transport.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/midiport.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/session.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/ringbuffer.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/thread.h> */
|
||||||
|
#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
|
||||||
|
/* <jack/metadata.h> */
|
||||||
|
#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
|
||||||
|
|
||||||
|
/* <jack/statistics.h> */
|
||||||
|
#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 <jack/jack.h>
|
||||||
|
#include <jack/transport.h>
|
||||||
|
#include <jack/ringbuffer.h>
|
||||||
|
#include <jack/midiport.h>
|
||||||
|
#include <jack/session.h>
|
||||||
|
#include <jack/thread.h>
|
||||||
|
#include <jack/statistics.h>
|
||||||
|
|
||||||
|
#ifndef NO_JACK_METADATA
|
||||||
|
#include <jack/metadata.h>
|
||||||
|
#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
|
|
@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te
|
||||||
org.tildearrow.furnace - Pattern Data (144)
|
org.tildearrow.furnace - Pattern Data (144)
|
||||||
```
|
```
|
||||||
|
|
||||||
this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre14 is `175`.
|
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.
|
the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from.
|
||||||
- `0`: note.
|
- `0`: note.
|
||||||
|
|
|
@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 178: Furnace 0.6pre16
|
||||||
|
- 177: Furnace 0.6pre15
|
||||||
- 175: Furnace 0.6pre14
|
- 175: Furnace 0.6pre14
|
||||||
- 174: Furnace 0.6pre13
|
- 174: Furnace 0.6pre13
|
||||||
- 173: Furnace 0.6pre12
|
- 173: Furnace 0.6pre12
|
||||||
|
|
|
@ -15,17 +15,17 @@
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleLongVersionString</key>
|
<key>CFBundleLongVersionString</key>
|
||||||
<string>0.6pre14</string>
|
<string>0.6pre16</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>Furnace</string>
|
<string>Furnace</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.6pre14</string>
|
<string>0.6pre16</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>0.6pre14</string>
|
<string>0.6pre16</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
|
|
|
@ -73,17 +73,42 @@ if __name__ == "__main__":
|
||||||
for file_ in filter(lambda x: x.lower().endswith('.md'), files):
|
for file_ in filter(lambda x: x.lower().endswith('.md'), files):
|
||||||
file_list.append(os.path.join(base_dir, file_))
|
file_list.append(os.path.join(base_dir, file_))
|
||||||
|
|
||||||
|
#-- then, create the index --#
|
||||||
|
index = '<h2>contents</h2><ol>'
|
||||||
|
|
||||||
#-- then, create the document --#
|
#-- then, create the document --#
|
||||||
html = ''
|
html = ''
|
||||||
|
|
||||||
# perform sort
|
# perform sort
|
||||||
file_list.sort(key=sort_func)
|
file_list.sort(key=sort_func)
|
||||||
|
|
||||||
|
first = True
|
||||||
|
|
||||||
for my_file in file_list:
|
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:
|
with open(my_file, 'r') as md:
|
||||||
LOGGER.info("processing file %s" % my_file)
|
LOGGER.info("processing file %s" % my_file)
|
||||||
data = md.read()
|
data = md.read()
|
||||||
|
|
||||||
|
# retrieve title
|
||||||
|
pageTitle = data.partition('\n')[0].replace("# ","")
|
||||||
|
|
||||||
|
if pageLink.endswith("__README.md"):
|
||||||
|
if first:
|
||||||
|
first = False
|
||||||
|
else:
|
||||||
|
index += '</li></ol>'
|
||||||
|
|
||||||
|
index += '<li><a href="#%s" class="indexItemPre">%s</a><a href="#%s" class="indexItem"></a>' % ( pageLink, pageTitle, pageLink )
|
||||||
|
if pageLink.endswith("__README.md"):
|
||||||
|
index += '<ol>'
|
||||||
|
else:
|
||||||
|
index += '</li>'
|
||||||
|
|
||||||
# perform link fixing
|
# perform link fixing
|
||||||
data = re.sub(r'\[(.+?)\]\((.+?)\)', fix_links, data)
|
data = re.sub(r'\[(.+?)\]\((.+?)\)', fix_links, data)
|
||||||
data = re.sub(r'^\s*(#+)', fix_headings, data, flags=re.MULTILINE)
|
data = re.sub(r'^\s*(#+)', fix_headings, data, flags=re.MULTILINE)
|
||||||
|
@ -94,6 +119,9 @@ if __name__ == "__main__":
|
||||||
markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()])
|
markdown.markdown(data, extensions=['nl2br', 'mdx_breakless_lists', GithubFlavoredMarkdownExtension()])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# finish index
|
||||||
|
index += '</ol></li></ol>'
|
||||||
|
|
||||||
# build html
|
# build html
|
||||||
final_html = ('''
|
final_html = ('''
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -136,7 +164,7 @@ if __name__ == "__main__":
|
||||||
margin-right: 4pt;
|
margin-right: 4pt;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
li:before {
|
ul > li:before {
|
||||||
content: '-';
|
content: '-';
|
||||||
padding-right: 3pt;
|
padding-right: 3pt;
|
||||||
}
|
}
|
||||||
|
@ -193,6 +221,24 @@ if __name__ == "__main__":
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #555;
|
color: #555;
|
||||||
}
|
}
|
||||||
|
a.indexItemPre {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: .01em;
|
||||||
|
}
|
||||||
|
a.indexItemPre[href^='#']:after {
|
||||||
|
content: ' ' leader('.') ' ';
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
a.indexItem {
|
||||||
|
float: right;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
a.indexItem[href^='#']:after {
|
||||||
|
content: target-counter(attr(href),page);
|
||||||
|
color: #000;
|
||||||
|
font-size: 11pt;
|
||||||
|
}
|
||||||
#cover {
|
#cover {
|
||||||
height: 100%%;
|
height: 100%%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -282,11 +328,35 @@ if __name__ == "__main__":
|
||||||
<i>for version 0.6</i>
|
<i>for version 0.6</i>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="authors">
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>authors</h3>
|
||||||
|
<ul>
|
||||||
|
<li>cam900</li>
|
||||||
|
<li>DeMOSic</li>
|
||||||
|
<li>Electric Keet</li>
|
||||||
|
<li>freq-mod</li>
|
||||||
|
<li>host12prog</li>
|
||||||
|
<li>nicco1690</li>
|
||||||
|
<li>tildearrow</li>
|
||||||
|
</ul>
|
||||||
|
<p>special thanks to ZoomTen for providing tools which assisted in the production of this document!</p>
|
||||||
|
<p>copyright © 2023 tildearrow and other authors.</p>
|
||||||
|
<p>this documentation is under the <a href="https://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported</a> license.</p>
|
||||||
|
<p>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.</p>
|
||||||
|
<p>this documentation is provided as-is and without warranty of any kind.</p>
|
||||||
|
<p>this manual is written for version 0.6 of Furnace.<br/>it may not necessarily apply to previous or future versions.</p>
|
||||||
|
</section>
|
||||||
|
<section id="index">
|
||||||
|
%s
|
||||||
|
</section>
|
||||||
%s
|
%s
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
''' % (
|
''' % (
|
||||||
html
|
index, html
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
|
|
||||||
<name>Furnace</name>
|
<name>Furnace</name>
|
||||||
<summary>Open-source chiptune tracker</summary>
|
<summary>Open-source chiptune tracker</summary>
|
||||||
|
<url type="homepage">https://github.com/tildearrow/furnace</url>
|
||||||
|
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-2.0-or-later</project_license>
|
<project_license>GPL-2.0-or-later</project_license>
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
the biggest chiptune tracker ever made!
|
Furnace - the biggest chiptune tracker ever made!
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
it allows you to create songs using a music tracker interface for several computer/game console/arcade sound chips.
|
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.
|
it also offers DefleMask compatibility, allowing you to import your songs and even export them back for interoperability.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>rationale for intense profanity:</b> 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.
|
||||||
</p>
|
</p>
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
|
@ -34,4 +35,4 @@
|
||||||
<image>https://tildearrow.org/storage/images/furnace.png</image>
|
<image>https://tildearrow.org/storage/images/furnace.png</image>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
</component>
|
|
34
res/make-appdata.sh
Executable file
34
res/make-appdata.sh
Executable file
|
@ -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 " <releases>" >> "$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 " <release version=\"${releaseVerProper}\" date=\"$releaseDate\" type=\"$releaseType\">" >> "$2"
|
||||||
|
echo " <url>https://github.com/tildearrow/furnace/releases/tag/$releaseVer</url>" >> "$2"
|
||||||
|
echo " </release>" >> "$2"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo " </releases>" >> "$2"
|
||||||
|
|
||||||
|
echo "</component>" >> "$2"
|
||||||
|
|
||||||
|
#echo "done."
|
|
@ -30,8 +30,8 @@ cp -v ../../../res/logo.png furnace.png || exit 1
|
||||||
ln -s furnace.png .DirIcon || exit 1
|
ln -s furnace.png .DirIcon || exit 1
|
||||||
cp -v ../../../res/furnace.desktop . || exit 1
|
cp -v ../../../res/furnace.desktop . || exit 1
|
||||||
#mkdir -p usr/share/metainfo || 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
|
#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
|
#rm usr/share/metainfo/furnace.appdata.xml || exit 1
|
||||||
cp -v ../../../res/AppRun . || exit 1
|
cp -v ../../../res/AppRun . || exit 1
|
||||||
|
|
||||||
#cp /usr/lib/libm.so.6 usr/lib/ || exit 1
|
#cp /usr/lib/libm.so.6 usr/lib/ || exit 1
|
||||||
|
|
|
@ -198,10 +198,19 @@ String TAAudioJACK::printStatus(jack_status_t status) {
|
||||||
|
|
||||||
bool TAAudioJACK::init(TAAudioDesc& request, TAAudioDesc& response) {
|
bool TAAudioJACK::init(TAAudioDesc& request, TAAudioDesc& response) {
|
||||||
if (initialized) return false;
|
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!");
|
logE("JACK not installed!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (haveJACK!=0) {
|
||||||
|
logE("JACK symbol error!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
desc=request;
|
desc=request;
|
||||||
desc.outFormat=TA_AUDIO_FORMAT_F32;
|
desc.outFormat=TA_AUDIO_FORMAT_F32;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "taAudio.h"
|
#include "taAudio.h"
|
||||||
#include <jack/weakjack.h>
|
#include "../../extern/weakjack/weak_libjack.h"
|
||||||
#include <jack/jack.h>
|
|
||||||
|
|
||||||
class TAAudioJACK: public TAAudio {
|
class TAAudioJACK: public TAAudio {
|
||||||
jack_client_t* ac;
|
jack_client_t* ac;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _TAAUDIO_H
|
#define _TAAUDIO_H
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <queue>
|
#include "../fixedQueue.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct SampleRateChangeEvent {
|
struct SampleRateChangeEvent {
|
||||||
|
@ -124,7 +124,7 @@ struct TAMidiMessage {
|
||||||
|
|
||||||
class TAMidiIn {
|
class TAMidiIn {
|
||||||
public:
|
public:
|
||||||
std::queue<TAMidiMessage> queue;
|
FixedQueue<TAMidiMessage,8192> queue;
|
||||||
virtual bool gather();
|
virtual bool gather();
|
||||||
bool next(TAMidiMessage& where);
|
bool next(TAMidiMessage& where);
|
||||||
virtual bool isDeviceOpen();
|
virtual bool isDeviceOpen();
|
||||||
|
@ -139,7 +139,7 @@ class TAMidiIn {
|
||||||
};
|
};
|
||||||
|
|
||||||
class TAMidiOut {
|
class TAMidiOut {
|
||||||
std::queue<TAMidiMessage> queue;
|
FixedQueue<TAMidiMessage,8192> queue;
|
||||||
public:
|
public:
|
||||||
virtual bool send(const TAMidiMessage& what);
|
virtual bool send(const TAMidiMessage& what);
|
||||||
virtual bool isDeviceOpen();
|
virtual bool isDeviceOpen();
|
||||||
|
|
|
@ -61,9 +61,11 @@ void DivEngine::initConfDir() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// TODO this should check XDG_CONFIG_HOME first
|
char* xdgConfigHome=getenv("XDG_CONFIG_HOME");
|
||||||
char* home=getenv("HOME");
|
char* home=getenv("HOME");
|
||||||
if (home==NULL) {
|
if (xdgConfigHome) {
|
||||||
|
configPath=xdgConfigHome;
|
||||||
|
} else if (home==NULL) {
|
||||||
int uid=getuid();
|
int uid=getuid();
|
||||||
struct passwd* entry=getpwuid(uid);
|
struct passwd* entry=getpwuid(uid);
|
||||||
if (entry==NULL) {
|
if (entry==NULL) {
|
||||||
|
@ -79,8 +81,9 @@ void DivEngine::initConfDir() {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
configPath+="/Library/Application Support";
|
configPath+="/Library/Application Support";
|
||||||
#else
|
#else
|
||||||
// FIXME this doesn't honour XDG_CONFIG_HOME *at all*
|
if (xdgConfigHome==NULL) {
|
||||||
configPath+="/.config";
|
configPath+="/.config";
|
||||||
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
#endif // __HAIKU__
|
#endif // __HAIKU__
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
|
@ -2166,6 +2166,13 @@ int DivEngine::getRow() {
|
||||||
return prevRow;
|
return prevRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivEngine::getPlayPos(int& order, int& row) {
|
||||||
|
playPosLock.lock();
|
||||||
|
order=prevOrder;
|
||||||
|
row=prevRow;
|
||||||
|
playPosLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
int DivEngine::getElapsedBars() {
|
int DivEngine::getElapsedBars() {
|
||||||
return elapsedBars;
|
return elapsedBars;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <deque>
|
#include "../fixedQueue.h"
|
||||||
|
|
||||||
class DivWorkPool;
|
class DivWorkPool;
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ class DivWorkPool;
|
||||||
|
|
||||||
#define DIV_UNSTABLE
|
#define DIV_UNSTABLE
|
||||||
|
|
||||||
#define DIV_VERSION "0.6pre14"
|
#define DIV_VERSION "0.6pre16"
|
||||||
#define DIV_ENGINE_VERSION 175
|
#define DIV_ENGINE_VERSION 178
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
#define DIV_VERSION_FC 0xff02
|
#define DIV_VERSION_FC 0xff02
|
||||||
|
@ -176,14 +176,28 @@ struct DivChannelState {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DivNoteEvent {
|
struct DivNoteEvent {
|
||||||
int channel, ins, note, volume;
|
signed char channel;
|
||||||
bool on;
|
unsigned char ins;
|
||||||
|
signed char note, volume;
|
||||||
|
bool on, nop, pad1, pad2;
|
||||||
DivNoteEvent(int c, int i, int n, int v, bool o):
|
DivNoteEvent(int c, int i, int n, int v, bool o):
|
||||||
channel(c),
|
channel(c),
|
||||||
ins(i),
|
ins(i),
|
||||||
note(n),
|
note(n),
|
||||||
volume(v),
|
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 {
|
struct DivDispatchContainer {
|
||||||
|
@ -428,11 +442,11 @@ class DivEngine {
|
||||||
DivAudioExportModes exportMode;
|
DivAudioExportModes exportMode;
|
||||||
double exportFadeOut;
|
double exportFadeOut;
|
||||||
DivConfig conf;
|
DivConfig conf;
|
||||||
std::deque<DivNoteEvent> pendingNotes;
|
FixedQueue<DivNoteEvent,8192> pendingNotes;
|
||||||
// bitfield
|
// bitfield
|
||||||
unsigned char walked[8192];
|
unsigned char walked[8192];
|
||||||
bool isMuted[DIV_MAX_CHANS];
|
bool isMuted[DIV_MAX_CHANS];
|
||||||
std::mutex isBusy, saveLock;
|
std::mutex isBusy, saveLock, playPosLock;
|
||||||
String configPath;
|
String configPath;
|
||||||
String configFile;
|
String configFile;
|
||||||
String lastError;
|
String lastError;
|
||||||
|
@ -834,6 +848,9 @@ class DivEngine {
|
||||||
// get current row
|
// get current row
|
||||||
int getRow();
|
int getRow();
|
||||||
|
|
||||||
|
// synchronous get order/row
|
||||||
|
void getPlayPos(int& order, int& row);
|
||||||
|
|
||||||
// get beat/bar
|
// get beat/bar
|
||||||
int getElapsedBars();
|
int getElapsedBars();
|
||||||
int getElapsedBeats();
|
int getElapsedBeats();
|
||||||
|
@ -886,7 +903,7 @@ class DivEngine {
|
||||||
|
|
||||||
// get instrument from file
|
// get instrument from file
|
||||||
// if the returned vector is empty then there was an error.
|
// if the returned vector is empty then there was an error.
|
||||||
std::vector<DivInstrument*> instrumentFromFile(const char* path, bool loadAssets=true);
|
std::vector<DivInstrument*> instrumentFromFile(const char* path, bool loadAssets=true, bool readInsName=true);
|
||||||
|
|
||||||
// load temporary instrument
|
// load temporary instrument
|
||||||
void loadTempIns(DivInstrument* which);
|
void loadTempIns(DivInstrument* which);
|
||||||
|
|
|
@ -1058,6 +1058,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.systemFlags[0].set("keyPriority",false);
|
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));
|
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
|
@ -2976,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<ds.systemLen; i++) {
|
||||||
|
if (ds.system[i]==DIV_SYSTEM_YM2151 ||
|
||||||
|
ds.system[i]==DIV_SYSTEM_OPZ) {
|
||||||
|
ds.systemFlags[i].set("brokenPitch",true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
|
|
|
@ -1816,7 +1816,7 @@ void DivEngine::loadWOPN(SafeReader& reader, std::vector<DivInstrument*>& ret, S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path, bool loadAssets) {
|
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path, bool loadAssets, bool readInsName) {
|
||||||
std::vector<DivInstrument*> ret;
|
std::vector<DivInstrument*> ret;
|
||||||
warnings="";
|
warnings="";
|
||||||
|
|
||||||
|
@ -1921,12 +1921,17 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path, bool
|
||||||
reader.seek(dataPtr,SEEK_SET);
|
reader.seek(dataPtr,SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ins->name=stripPath;
|
||||||
|
|
||||||
if (ins->readInsData(reader,version,loadAssets?(&song):NULL)!=DIV_DATA_SUCCESS) {
|
if (ins->readInsData(reader,version,loadAssets?(&song):NULL)!=DIV_DATA_SUCCESS) {
|
||||||
lastError="invalid instrument header/data!";
|
lastError="invalid instrument header/data!";
|
||||||
delete ins;
|
delete ins;
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
if (!readInsName) {
|
||||||
|
ins->name=stripPath;
|
||||||
|
}
|
||||||
ret.push_back(ins);
|
ret.push_back(ins);
|
||||||
}
|
}
|
||||||
} catch (EndOfFileException& e) {
|
} catch (EndOfFileException& e) {
|
||||||
|
|
|
@ -719,7 +719,7 @@ void DivInstrument::writeFeatureX1(SafeWriter* w) {
|
||||||
FEATURE_END;
|
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 blockStartSeek=0;
|
||||||
size_t blockEndSeek=0;
|
size_t blockEndSeek=0;
|
||||||
size_t slSeek=0;
|
size_t slSeek=0;
|
||||||
|
@ -1021,7 +1021,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check ins name
|
// check ins name
|
||||||
if (!name.empty()) {
|
if (!name.empty() && insName) {
|
||||||
featureNA=true;
|
featureNA=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3380,7 +3380,7 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version, DivS
|
||||||
return readInsDataOld(reader,version);
|
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();
|
SafeWriter* w=new SafeWriter();
|
||||||
w->init();
|
w->init();
|
||||||
|
|
||||||
|
@ -3397,14 +3397,14 @@ bool DivInstrument::save(const char* path, bool oldFormat, DivSong* song) {
|
||||||
// pointer to data
|
// pointer to data
|
||||||
w->writeI(32);
|
w->writeI(32);
|
||||||
|
|
||||||
// currently reserved (TODO; wavetable and sample here)
|
// reserved
|
||||||
w->writeS(0);
|
w->writeS(0);
|
||||||
w->writeS(0);
|
w->writeS(0);
|
||||||
w->writeI(0);
|
w->writeI(0);
|
||||||
|
|
||||||
putInsData(w);
|
putInsData(w);
|
||||||
} else {
|
} else {
|
||||||
putInsData2(w,true,song);
|
putInsData2(w,true,song,writeInsName);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* outFile=ps_fopen(path,"wb");
|
FILE* outFile=ps_fopen(path,"wb");
|
||||||
|
|
|
@ -720,7 +720,7 @@ struct DivInstrument {
|
||||||
* save the instrument to a SafeWriter using new format.
|
* save the instrument to a SafeWriter using new format.
|
||||||
* @param w the SafeWriter in question.
|
* @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.
|
* read instrument data in .fui format.
|
||||||
|
@ -735,9 +735,10 @@ struct DivInstrument {
|
||||||
* @param path file path.
|
* @param path file path.
|
||||||
* @param oldFormat whether to save in legacy Furnace ins format.
|
* @param oldFormat whether to save in legacy Furnace ins format.
|
||||||
* @param song if new format, a DivSong to read wavetables and samples.
|
* @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.
|
* @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.
|
* save this instrument to a file in .dmp format.
|
||||||
|
|
|
@ -197,10 +197,10 @@ void DivPlatformArcade::tick(bool sysTick) {
|
||||||
|
|
||||||
if (chan[i].std.pitch.had) {
|
if (chan[i].std.pitch.had) {
|
||||||
if (chan[i].std.pitch.mode) {
|
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);
|
CLAMP_VAR(chan[i].pitch2,-32768,32767);
|
||||||
} else {
|
} else {
|
||||||
chan[i].pitch2=chan[i].std.pitch.val;
|
chan[i].pitch2=chan[i].std.pitch.val*(brokenPitch?2:1);
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -354,18 +354,18 @@ void DivPlatformArcade::tick(bool sysTick) {
|
||||||
|
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
if (chan[i].freqChanged) {
|
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 (!parent->song.oldArpStrategy) {
|
||||||
if (chan[i].fixedArp) {
|
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 {
|
} 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<0) chan[i].freq=0;
|
||||||
if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
|
if (chan[i].freq>=(95<<7)) chan[i].freq=(95<<7)-1;
|
||||||
immWrite(i+0x28,hScale(chan[i].freq>>6));
|
immWrite(i+0x28,hScale(chan[i].freq>>7));
|
||||||
immWrite(i+0x30,chan[i].freq<<2);
|
immWrite(i+0x30,((chan[i].freq<<1)&0xfc));
|
||||||
hardResetElapsed+=2;
|
hardResetElapsed+=2;
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
|
@ -534,13 +534,13 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
||||||
int newFreq;
|
int newFreq;
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
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) {
|
if (newFreq>=destFreq) {
|
||||||
newFreq=destFreq;
|
newFreq=destFreq;
|
||||||
return2=true;
|
return2=true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newFreq=chan[c.chan].baseFreq-c.value;
|
newFreq=chan[c.chan].baseFreq-c.value*(brokenPitch?2:1);
|
||||||
if (newFreq<=destFreq) {
|
if (newFreq<=destFreq) {
|
||||||
newFreq=destFreq;
|
newFreq=destFreq;
|
||||||
return2=true;
|
return2=true;
|
||||||
|
@ -932,7 +932,9 @@ void DivPlatformArcade::setFlags(const DivConfig& flags) {
|
||||||
}
|
}
|
||||||
CHECK_CUSTOM_CLOCK;
|
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;
|
rate=chipClock/64;
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef _AY_H
|
#ifndef _AY_H
|
||||||
#define _AY_H
|
#define _AY_H
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/ay8910.h"
|
#include "sound/ay8910.h"
|
||||||
|
|
||||||
class DivPlatformAY8910: public DivDispatch {
|
class DivPlatformAY8910: public DivDispatch {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef _AY8930_H
|
#ifndef _AY8930_H
|
||||||
#define _AY8930_H
|
#define _AY8930_H
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/ay8910.h"
|
#include "sound/ay8910.h"
|
||||||
|
|
||||||
class DivPlatformAY8930: public DivDispatch {
|
class DivPlatformAY8930: public DivDispatch {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "sound/c140_c219.h"
|
#include "sound/c140_c219.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
class DivPlatformC140: public DivDispatch {
|
class DivPlatformC140: public DivDispatch {
|
||||||
struct Channel: public SharedChannel<int> {
|
struct Channel: public SharedChannel<int> {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _C64_H
|
#define _C64_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/c64/sid.h"
|
#include "sound/c64/sid.h"
|
||||||
#include "sound/c64_fp/SID.h"
|
#include "sound/c64_fp/SID.h"
|
||||||
#include "sound/c64_d/dsid.h"
|
#include "sound/c64_d/dsid.h"
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../macroInt.h"
|
#include "../macroInt.h"
|
||||||
#include "../sample.h"
|
#include "../sample.h"
|
||||||
#include "vgsound_emu/src/es550x/es5506.hpp"
|
#include "vgsound_emu/src/es550x/es5506.hpp"
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "fmsharedbase.h"
|
#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 {
|
class DivPlatformOPM: public DivPlatformFMBase {
|
||||||
protected:
|
protected:
|
||||||
|
@ -42,13 +42,15 @@ class DivPlatformOPM: public DivPlatformFMBase {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2;
|
unsigned char lfoValue, lfoValue2, lfoShape, lfoShape2;
|
||||||
|
bool brokenPitch;
|
||||||
|
|
||||||
DivPlatformOPM():
|
DivPlatformOPM():
|
||||||
DivPlatformFMBase(),
|
DivPlatformFMBase(),
|
||||||
lfoValue(0),
|
lfoValue(0),
|
||||||
lfoValue2(0),
|
lfoValue2(0),
|
||||||
lfoShape(0),
|
lfoShape(0),
|
||||||
lfoShape2(0) {}
|
lfoShape2(0),
|
||||||
|
brokenPitch(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../instrument.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)
|
#define KVS(x,y) ((chan[x].state.op[y].kvs==2 && isOutput[chan[x].state.alg][y]) || chan[x].state.op[y].kvs==1)
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _GA20_H
|
#define _GA20_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../macroInt.h"
|
#include "../macroInt.h"
|
||||||
#include "sound/ga20/iremga20.h"
|
#include "sound/ga20/iremga20.h"
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/gb/gb.h"
|
#include "sound/gb/gb.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
class DivPlatformGB: public DivDispatch {
|
class DivPlatformGB: public DivDispatch {
|
||||||
struct Channel: public SharedChannel<signed char> {
|
struct Channel: public SharedChannel<signed char> {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _K007232_H
|
#define _K007232_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../macroInt.h"
|
#include "../macroInt.h"
|
||||||
#include "vgsound_emu/src/k007232/k007232.hpp"
|
#include "vgsound_emu/src/k007232/k007232.hpp"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _MSM5232_H
|
#define _MSM5232_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/oki/msm5232.h"
|
#include "sound/oki/msm5232.h"
|
||||||
|
|
||||||
class DivPlatformMSM5232: public DivDispatch {
|
class DivPlatformMSM5232: public DivDispatch {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _MSM6258_H
|
#define _MSM6258_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/oki/okim6258.h"
|
#include "sound/oki/okim6258.h"
|
||||||
|
|
||||||
class DivPlatformMSM6258: public DivDispatch {
|
class DivPlatformMSM6258: public DivDispatch {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _MSM6295_H
|
#define _MSM6295_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "vgsound_emu/src/msm6295/msm6295.hpp"
|
#include "vgsound_emu/src/msm6295/msm6295.hpp"
|
||||||
|
|
||||||
class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _N163_H
|
#define _N163_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "vgsound_emu/src/n163/n163.hpp"
|
#include "vgsound_emu/src/n163/n163.hpp"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _NAMCOWSG_H
|
#define _NAMCOWSG_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/namco.h"
|
#include "sound/namco.h"
|
||||||
|
|
||||||
|
|
|
@ -722,6 +722,10 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properDrums && ch>melodicChans) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isMuted[ch]) {
|
if (isMuted[ch]) {
|
||||||
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
rWrite(chanMap[ch]+ADDR_LR_FB_ALG,(chan[ch].state.alg&1)|(chan[ch].state.fb<<1));
|
||||||
if (ops==4) {
|
if (ops==4) {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _OPL_H
|
#define _OPL_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../../../extern/opl/opl3.h"
|
#include "../../../extern/opl/opl3.h"
|
||||||
#include "sound/ymfm/ymfm_adpcm.h"
|
#include "sound/ymfm/ymfm_adpcm.h"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _OPLL_H
|
#define _OPLL_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "../../../extern/Nuked-OPLL/opll.h"
|
#include "../../../extern/Nuked-OPLL/opll.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _PCE_H
|
#define _PCE_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/pce_psg.h"
|
#include "sound/pce_psg.h"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _PCSPKR_H
|
#define _PCSPKR_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _POKEY_H
|
#define _POKEY_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "sound/pokey/mzpokeysnd.h"
|
#include "sound/pokey/mzpokeysnd.h"
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _SAA_H
|
#define _SAA_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../../../extern/SAASound/src/SAASound.h"
|
#include "../../../extern/SAASound/src/SAASound.h"
|
||||||
|
|
||||||
class DivPlatformSAA1099: public DivDispatch {
|
class DivPlatformSAA1099: public DivDispatch {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../instrument.h"
|
#include "../instrument.h"
|
||||||
#include "sound/segapcm.h"
|
#include "sound/segapcm.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
class DivPlatformSegaPCM: public DivDispatch {
|
class DivPlatformSegaPCM: public DivDispatch {
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _SM8521_H
|
#define _SM8521_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/sm8521.h"
|
#include "sound/sm8521.h"
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "../../../extern/Nuked-PSG/ympsg.h"
|
#include "../../../extern/Nuked-PSG/ympsg.h"
|
||||||
}
|
}
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
class DivPlatformSMS: public DivDispatch {
|
class DivPlatformSMS: public DivDispatch {
|
||||||
struct Channel: public SharedChannel<signed char> {
|
struct Channel: public SharedChannel<signed char> {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/snes/SPC_DSP.h"
|
#include "sound/snes/SPC_DSP.h"
|
||||||
|
|
||||||
class DivPlatformSNES: public DivDispatch {
|
class DivPlatformSNES: public DivDispatch {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _SU_H
|
#define _SU_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/su.h"
|
#include "sound/su.h"
|
||||||
|
|
||||||
class DivPlatformSoundUnit: public DivDispatch {
|
class DivPlatformSoundUnit: public DivDispatch {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/swan.h"
|
#include "sound/swan.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
|
|
||||||
class DivPlatformSwan: public DivDispatch {
|
class DivPlatformSwan: public DivDispatch {
|
||||||
struct Channel: public SharedChannel<int> {
|
struct Channel: public SharedChannel<int> {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _T6W28_H
|
#define _T6W28_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/t6w28/T6W28_Apu.h"
|
#include "sound/t6w28/T6W28_Apu.h"
|
||||||
|
|
||||||
class DivPlatformT6W28: public DivDispatch {
|
class DivPlatformT6W28: public DivDispatch {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _TED_H
|
#define _TED_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/ted-sound.h"
|
#include "sound/ted-sound.h"
|
||||||
|
|
||||||
class DivPlatformTED: public DivDispatch {
|
class DivPlatformTED: public DivDispatch {
|
||||||
|
|
|
@ -147,10 +147,10 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
||||||
|
|
||||||
if (chan[i].std.pitch.had) {
|
if (chan[i].std.pitch.had) {
|
||||||
if (chan[i].std.pitch.mode) {
|
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);
|
CLAMP_VAR(chan[i].pitch2,-32768,32767);
|
||||||
} else {
|
} else {
|
||||||
chan[i].pitch2=chan[i].std.pitch.val;
|
chan[i].pitch2=chan[i].std.pitch.val*(brokenPitch?2:1);
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -337,18 +337,18 @@ void DivPlatformTX81Z::tick(bool sysTick) {
|
||||||
|
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
if (chan[i].freqChanged) {
|
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 (!parent->song.oldArpStrategy) {
|
||||||
if (chan[i].fixedArp) {
|
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 {
|
} 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<0) chan[i].freq=0;
|
||||||
if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
|
if (chan[i].freq>=(95<<7)) chan[i].freq=(95<<7)-1;
|
||||||
immWrite(i+0x28,hScale(chan[i].freq>>6));
|
immWrite(i+0x28,hScale(chan[i].freq>>7));
|
||||||
immWrite(i+0x30,(chan[i].freq<<2)|(chan[i].chVolL==chan[i].chVolR));
|
immWrite(i+0x30,((chan[i].freq<<1)&0xfc)|(chan[i].chVolL==chan[i].chVolR));
|
||||||
hardResetElapsed+=2;
|
hardResetElapsed+=2;
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
|
@ -523,13 +523,13 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
||||||
int newFreq;
|
int newFreq;
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
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) {
|
if (newFreq>=destFreq) {
|
||||||
newFreq=destFreq;
|
newFreq=destFreq;
|
||||||
return2=true;
|
return2=true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newFreq=chan[c.chan].baseFreq-c.value;
|
newFreq=chan[c.chan].baseFreq-c.value*(brokenPitch?2:1);
|
||||||
if (newFreq<=destFreq) {
|
if (newFreq<=destFreq) {
|
||||||
newFreq=destFreq;
|
newFreq=destFreq;
|
||||||
return2=true;
|
return2=true;
|
||||||
|
@ -1043,7 +1043,9 @@ void DivPlatformTX81Z::setFlags(const DivConfig& flags) {
|
||||||
}
|
}
|
||||||
CHECK_CUSTOM_CLOCK;
|
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;
|
rate=chipClock/64;
|
||||||
for (int i=0; i<8; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _TX81Z_H
|
#define _TX81Z_H
|
||||||
|
|
||||||
#include "fmshared_OPM.h"
|
#include "fmshared_OPM.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "sound/ymfm/ymfm_opz.h"
|
#include "sound/ymfm/ymfm_opz.h"
|
||||||
|
|
||||||
class DivTXInterface: public ymfm::ymfm_interface {
|
class DivTXInterface: public ymfm::ymfm_interface {
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define _PLATFORM_VB_H
|
#define _PLATFORM_VB_H
|
||||||
|
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../waveSynth.h"
|
#include "../waveSynth.h"
|
||||||
#include "sound/vsu.h"
|
#include "sound/vsu.h"
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef _VRC6_H
|
#ifndef _VRC6_H
|
||||||
#define _VRC6_H
|
#define _VRC6_H
|
||||||
|
|
||||||
#include "../fixedQueue.h"
|
#include "../../fixedQueue.h"
|
||||||
#include "../dispatch.h"
|
#include "../dispatch.h"
|
||||||
#include "vgsound_emu/src/vrcvi/vrcvi.hpp"
|
#include "vgsound_emu/src/vrcvi/vrcvi.hpp"
|
||||||
|
|
||||||
|
|
|
@ -1167,8 +1167,10 @@ void DivEngine::nextRow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stepPlay) {
|
if (!stepPlay) {
|
||||||
|
playPosLock.lock();
|
||||||
prevOrder=curOrder;
|
prevOrder=curOrder;
|
||||||
prevRow=curRow;
|
prevRow=curRow;
|
||||||
|
playPosLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
|
@ -1349,8 +1351,8 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
isOn[pendingNotes[i].channel]=true;
|
isOn[pendingNotes[i].channel]=true;
|
||||||
} else {
|
} else {
|
||||||
if (isOn[pendingNotes[i].channel]) {
|
if (isOn[pendingNotes[i].channel]) {
|
||||||
logV("erasing off -> on sequence in %d",pendingNotes[i].channel);
|
//logV("erasing off -> on sequence in %d",pendingNotes[i].channel);
|
||||||
pendingNotes.erase(pendingNotes.begin()+i);
|
pendingNotes[i].nop=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1358,12 +1360,13 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
|
|
||||||
while (!pendingNotes.empty()) {
|
while (!pendingNotes.empty()) {
|
||||||
DivNoteEvent& note=pendingNotes.front();
|
DivNoteEvent& note=pendingNotes.front();
|
||||||
if (note.channel<0 || note.channel>=chans) {
|
if (note.nop || note.channel<0 || note.channel>=chans) {
|
||||||
pendingNotes.pop_front();
|
pendingNotes.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (note.on) {
|
if (note.on) {
|
||||||
dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,note.channel,note.ins,1));
|
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));
|
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,note.channel,note.note));
|
||||||
keyHit[note.channel]=true;
|
keyHit[note.channel]=true;
|
||||||
chan[note.channel].noteOnInhibit=true;
|
chan[note.channel].noteOnInhibit=true;
|
||||||
|
@ -1405,8 +1408,10 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) {
|
||||||
endOfSong=false;
|
endOfSong=false;
|
||||||
if (stepPlay==2) {
|
if (stepPlay==2) {
|
||||||
stepPlay=1;
|
stepPlay=1;
|
||||||
|
playPosLock.lock();
|
||||||
prevOrder=curOrder;
|
prevOrder=curOrder;
|
||||||
prevRow=curRow;
|
prevRow=curRow;
|
||||||
|
playPosLock.unlock();
|
||||||
}
|
}
|
||||||
nextRow();
|
nextRow();
|
||||||
break;
|
break;
|
||||||
|
@ -1850,7 +1855,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();
|
output->midiIn->queue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "safeWriter.h"
|
#include "safeWriter.h"
|
||||||
#include "dataErrors.h"
|
#include "dataErrors.h"
|
||||||
#include <deque>
|
#include "../fixedQueue.h"
|
||||||
|
|
||||||
enum DivSampleLoopMode: unsigned char {
|
enum DivSampleLoopMode: unsigned char {
|
||||||
DIV_SAMPLE_LOOP_FORWARD=0,
|
DIV_SAMPLE_LOOP_FORWARD=0,
|
||||||
|
@ -144,8 +144,8 @@ struct DivSample {
|
||||||
|
|
||||||
unsigned int samples;
|
unsigned int samples;
|
||||||
|
|
||||||
std::deque<DivSampleHistory*> undoHist;
|
FixedQueue<DivSampleHistory*,128> undoHist;
|
||||||
std::deque<DivSampleHistory*> redoHist;
|
FixedQueue<DivSampleHistory*,128> redoHist;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* put sample data.
|
* put sample data.
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
|
||||||
#include "fixedQueue.h"
|
#include "../fixedQueue.h"
|
||||||
|
|
||||||
class DivWorkPool;
|
class DivWorkPool;
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,20 @@
|
||||||
#define _FIXED_QUEUE_H
|
#define _FIXED_QUEUE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../ta-log.h"
|
#include "ta-log.h"
|
||||||
|
|
||||||
template<typename T, size_t items> struct FixedQueue {
|
template<typename T, size_t items> struct FixedQueue {
|
||||||
size_t readPos, writePos;
|
size_t readPos, writePos;
|
||||||
T data[items];
|
T data[items];
|
||||||
|
|
||||||
|
T& operator[](size_t pos);
|
||||||
T& front();
|
T& front();
|
||||||
T& back();
|
T& back();
|
||||||
bool pop();
|
bool pop();
|
||||||
bool push(const T& item);
|
bool push(const T& item);
|
||||||
|
|
||||||
|
bool erase(size_t pos);
|
||||||
|
|
||||||
bool pop_front();
|
bool pop_front();
|
||||||
bool pop_back();
|
bool pop_back();
|
||||||
bool push_front(const T& item);
|
bool push_front(const T& item);
|
||||||
|
@ -44,6 +47,13 @@ template<typename T, size_t items> struct FixedQueue {
|
||||||
writePos(0) {}
|
writePos(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t items> T& FixedQueue<T,items>::operator[](size_t pos) {
|
||||||
|
if (pos>=size()) {
|
||||||
|
logW("accessing invalid position. bug!");
|
||||||
|
}
|
||||||
|
return data[(readPos+pos)%items];
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, size_t items> T& FixedQueue<T,items>::front() {
|
template <typename T, size_t items> T& FixedQueue<T,items>::front() {
|
||||||
return data[readPos];
|
return data[readPos];
|
||||||
}
|
}
|
||||||
|
@ -53,6 +63,36 @@ template <typename T, size_t items> T& FixedQueue<T,items>::back() {
|
||||||
return data[writePos-1];
|
return data[writePos-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t items> bool FixedQueue<T,items>::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<curSize; i++) {
|
||||||
|
if (p>=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 <typename T, size_t items> bool FixedQueue<T,items>::pop() {
|
template <typename T, size_t items> bool FixedQueue<T,items>::pop() {
|
||||||
if (readPos==writePos) return false;
|
if (readPos==writePos) return false;
|
||||||
if (++readPos>=items) readPos=0;
|
if (++readPos>=items) readPos=0;
|
|
@ -166,6 +166,7 @@ const char* aboutLine[]={
|
||||||
"Portable File Dialogs by Sam Hocevar",
|
"Portable File Dialogs by Sam Hocevar",
|
||||||
"Native File Dialog by Frogtoss Games",
|
"Native File Dialog by Frogtoss Games",
|
||||||
"PortAudio",
|
"PortAudio",
|
||||||
|
"Weak-JACK by x42",
|
||||||
"RtMidi by Gary P. Scavone",
|
"RtMidi by Gary P. Scavone",
|
||||||
"FFTW by Matteo Frigo and Steven G. Johnson",
|
"FFTW by Matteo Frigo and Steven G. Johnson",
|
||||||
"backward-cpp by Google",
|
"backward-cpp by Google",
|
||||||
|
|
|
@ -29,13 +29,13 @@ void FurnaceGUI::drawClock() {
|
||||||
}
|
}
|
||||||
if (!clockOpen) return;
|
if (!clockOpen) return;
|
||||||
if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) {
|
if (ImGui::Begin("Clock",&clockOpen,globalWinFlags)) {
|
||||||
int row=e->getRow();
|
int row=oldRow;
|
||||||
int elapsedBars=e->getElapsedBars();
|
int elapsedBars=e->getElapsedBars();
|
||||||
int elapsedBeats=e->getElapsedBeats();
|
int elapsedBeats=e->getElapsedBeats();
|
||||||
bool playing=e->isPlaying();
|
bool playing=e->isPlaying();
|
||||||
if (clockShowRow) {
|
if (clockShowRow) {
|
||||||
ImGui::PushFont(bigFont);
|
ImGui::PushFont(bigFont);
|
||||||
ImGui::Text("%.3d:%.3d",e->getOrder(),row);
|
ImGui::Text("%.3d:%.3d",playOrder,row);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
if (clockShowBeat) {
|
if (clockShowBeat) {
|
||||||
|
|
|
@ -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::PlotLines("##DebugFMPreview",asFloat,FM_PREVIEW_SIZE,0,"Preview",-1.0,1.0,ImVec2(300.0f*dpiScale,150.0f*dpiScale));
|
||||||
ImGui::TreePop();
|
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; i<recentFile.size(); i++) {
|
||||||
|
ImGui::Text("%d: %s",(int)i,recentFile[i].c_str());
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
if (ImGui::TreeNode("User Interface")) {
|
if (ImGui::TreeNode("User Interface")) {
|
||||||
if (ImGui::Button("Inspect")) {
|
if (ImGui::Button("Inspect")) {
|
||||||
inspectorOpen=!inspectorOpen;
|
inspectorOpen=!inspectorOpen;
|
||||||
|
|
|
@ -1566,8 +1566,6 @@ void FurnaceGUI::doAction(int what) {
|
||||||
e->deleteOrder(curOrder);
|
e->deleteOrder(curOrder);
|
||||||
if (curOrder>=e->curSubSong->ordersLen) {
|
if (curOrder>=e->curSubSong->ordersLen) {
|
||||||
curOrder=e->curSubSong->ordersLen-1;
|
curOrder=e->curSubSong->ordersLen-1;
|
||||||
oldOrder=curOrder;
|
|
||||||
oldOrder1=curOrder;
|
|
||||||
e->setOrder(curOrder);
|
e->setOrder(curOrder);
|
||||||
}
|
}
|
||||||
makeUndo(GUI_UNDO_CHANGE_ORDER);
|
makeUndo(GUI_UNDO_CHANGE_ORDER);
|
||||||
|
|
|
@ -1209,8 +1209,6 @@ void FurnaceGUI::doUndo() {
|
||||||
|
|
||||||
if (curOrder>=e->curSubSong->ordersLen) {
|
if (curOrder>=e->curSubSong->ordersLen) {
|
||||||
curOrder=e->curSubSong->ordersLen-1;
|
curOrder=e->curSubSong->ordersLen-1;
|
||||||
oldOrder=curOrder;
|
|
||||||
oldOrder1=curOrder;
|
|
||||||
e->setOrder(curOrder);
|
e->setOrder(curOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1287,8 +1285,6 @@ void FurnaceGUI::doRedo() {
|
||||||
|
|
||||||
if (curOrder>=e->curSubSong->ordersLen) {
|
if (curOrder>=e->curSubSong->ordersLen) {
|
||||||
curOrder=e->curSubSong->ordersLen-1;
|
curOrder=e->curSubSong->ordersLen-1;
|
||||||
oldOrder=curOrder;
|
|
||||||
oldOrder1=curOrder;
|
|
||||||
e->setOrder(curOrder);
|
e->setOrder(curOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1134,7 +1134,7 @@ void FurnaceGUI::stop() {
|
||||||
if (followPattern && wasPlaying) {
|
if (followPattern && wasPlaying) {
|
||||||
nextScroll=-1.0f;
|
nextScroll=-1.0f;
|
||||||
nextAddScroll=0.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) {
|
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
|
||||||
selStart=cursor;
|
selStart=cursor;
|
||||||
selEnd=cursor;
|
selEnd=cursor;
|
||||||
|
@ -2207,7 +2207,7 @@ void FurnaceGUI::pushRecentFile(String path) {
|
||||||
if (path.find(backupPath)==0) return;
|
if (path.find(backupPath)==0) return;
|
||||||
for (int i=0; i<(int)recentFile.size(); i++) {
|
for (int i=0; i<(int)recentFile.size(); i++) {
|
||||||
if (recentFile[i]==path) {
|
if (recentFile[i]==path) {
|
||||||
recentFile.erase(recentFile.begin()+i);
|
recentFile.erase(i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3545,7 +3545,7 @@ bool FurnaceGUI::loop() {
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
if (ev.drop.file!=NULL) {
|
if (ev.drop.file!=NULL) {
|
||||||
int sampleCountBefore=e->song.sampleLen;
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file);
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file,true,settings.readInsNames);
|
||||||
DivWavetable* droppedWave=NULL;
|
DivWavetable* droppedWave=NULL;
|
||||||
DivSample* droppedSample=NULL;
|
DivSample* droppedSample=NULL;
|
||||||
if (!instruments.empty()) {
|
if (!instruments.empty()) {
|
||||||
|
@ -3922,6 +3922,17 @@ bool FurnaceGUI::loop() {
|
||||||
curWindow=GUI_WINDOW_NOTHING;
|
curWindow=GUI_WINDOW_NOTHING;
|
||||||
editOptsVisible=false;
|
editOptsVisible=false;
|
||||||
|
|
||||||
|
int nextPlayOrder=0;
|
||||||
|
int nextOldRow=0;
|
||||||
|
e->getPlayPos(nextPlayOrder,nextOldRow);
|
||||||
|
playOrder=nextPlayOrder;
|
||||||
|
if (followPattern) {
|
||||||
|
curOrder=playOrder;
|
||||||
|
}
|
||||||
|
if (e->isPlaying()) {
|
||||||
|
oldRow=nextOldRow;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mobileUI) {
|
if (!mobileUI) {
|
||||||
ImGui::BeginMainMenuBar();
|
ImGui::BeginMainMenuBar();
|
||||||
if (ImGui::BeginMenu(settings.capitalMenuBar?"File":"file")) {
|
if (ImGui::BeginMenu(settings.capitalMenuBar?"File":"file")) {
|
||||||
|
@ -3948,7 +3959,7 @@ bool FurnaceGUI::loop() {
|
||||||
nextFile=item;
|
nextFile=item;
|
||||||
showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP);
|
showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP);
|
||||||
} else {
|
} else {
|
||||||
recentFile.erase(recentFile.begin()+i);
|
recentFile.erase(i);
|
||||||
i--;
|
i--;
|
||||||
if (load(item)>0) {
|
if (load(item)>0) {
|
||||||
showError(fmt::sprintf("Error while loading file! (%s)",lastError));
|
showError(fmt::sprintf("Error while loading file! (%s)",lastError));
|
||||||
|
@ -4379,15 +4390,15 @@ bool FurnaceGUI::loop() {
|
||||||
info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD));
|
info+=fmt::sprintf(" @ %gHz (%g BPM) ",e->getCurHz(),calcBPM(e->getSpeeds(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD));
|
||||||
|
|
||||||
if (settings.orderRowsBase) {
|
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 {
|
} 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) {
|
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 {
|
} 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);
|
info+=fmt::sprintf("| %d:%.2d:%.2d.%.2d",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000);
|
||||||
|
@ -4459,10 +4470,6 @@ bool FurnaceGUI::loop() {
|
||||||
|
|
||||||
MEASURE(calcChanOsc,calcChanOsc());
|
MEASURE(calcChanOsc,calcChanOsc());
|
||||||
|
|
||||||
if (followPattern) {
|
|
||||||
curOrder=e->getOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mobileUI) {
|
if (mobileUI) {
|
||||||
globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus;
|
globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||||
//globalWinFlags=ImGuiWindowFlags_NoTitleBar;
|
//globalWinFlags=ImGuiWindowFlags_NoTitleBar;
|
||||||
|
@ -4850,7 +4857,7 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_INS_SAVE:
|
case GUI_FILE_INS_SAVE:
|
||||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
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());
|
pushRecentSys(copyOfName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4976,7 +4983,7 @@ bool FurnaceGUI::loop() {
|
||||||
String warns="there were some warnings/errors while loading instruments:\n";
|
String warns="there were some warnings/errors while loading instruments:\n";
|
||||||
int sampleCountBefore=e->song.sampleLen;
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
for (String i: fileDialog->getFileName()) {
|
for (String i: fileDialog->getFileName()) {
|
||||||
std::vector<DivInstrument*> insTemp=e->instrumentFromFile(i.c_str());
|
std::vector<DivInstrument*> insTemp=e->instrumentFromFile(i.c_str(),true,settings.readInsNames);
|
||||||
if (insTemp.empty()) {
|
if (insTemp.empty()) {
|
||||||
warn=true;
|
warn=true;
|
||||||
warns+=fmt::sprintf("> %s: cannot load instrument! (%s)\n",i,e->getLastError());
|
warns+=fmt::sprintf("> %s: cannot load instrument! (%s)\n",i,e->getLastError());
|
||||||
|
@ -5022,7 +5029,7 @@ bool FurnaceGUI::loop() {
|
||||||
}
|
}
|
||||||
case GUI_FILE_INS_OPEN_REPLACE: {
|
case GUI_FILE_INS_OPEN_REPLACE: {
|
||||||
int sampleCountBefore=e->song.sampleLen;
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(copyOfName.c_str());
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(copyOfName.c_str(),true,settings.readInsNames);
|
||||||
if (!instruments.empty()) {
|
if (!instruments.empty()) {
|
||||||
if (e->song.sampleLen!=sampleCountBefore) {
|
if (e->song.sampleLen!=sampleCountBefore) {
|
||||||
e->renderSamplesP();
|
e->renderSamplesP();
|
||||||
|
@ -5540,8 +5547,6 @@ bool FurnaceGUI::loop() {
|
||||||
stop();
|
stop();
|
||||||
e->clearSubSongs();
|
e->clearSubSongs();
|
||||||
curOrder=0;
|
curOrder=0;
|
||||||
oldOrder=0;
|
|
||||||
oldOrder1=0;
|
|
||||||
MARK_MODIFIED;
|
MARK_MODIFIED;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
@ -5552,8 +5557,6 @@ bool FurnaceGUI::loop() {
|
||||||
});
|
});
|
||||||
e->setOrder(0);
|
e->setOrder(0);
|
||||||
curOrder=0;
|
curOrder=0;
|
||||||
oldOrder=0;
|
|
||||||
oldOrder1=0;
|
|
||||||
MARK_MODIFIED;
|
MARK_MODIFIED;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
@ -5565,8 +5568,6 @@ bool FurnaceGUI::loop() {
|
||||||
});
|
});
|
||||||
e->setOrder(0);
|
e->setOrder(0);
|
||||||
curOrder=0;
|
curOrder=0;
|
||||||
oldOrder=0;
|
|
||||||
oldOrder1=0;
|
|
||||||
MARK_MODIFIED;
|
MARK_MODIFIED;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
@ -5671,8 +5672,6 @@ bool FurnaceGUI::loop() {
|
||||||
undoHist.clear();
|
undoHist.clear();
|
||||||
redoHist.clear();
|
redoHist.clear();
|
||||||
updateScroll(0);
|
updateScroll(0);
|
||||||
oldOrder=0;
|
|
||||||
oldOrder1=0;
|
|
||||||
oldRow=0;
|
oldRow=0;
|
||||||
cursor.xCoarse=0;
|
cursor.xCoarse=0;
|
||||||
cursor.xFine=0;
|
cursor.xFine=0;
|
||||||
|
@ -7079,10 +7078,9 @@ FurnaceGUI::FurnaceGUI():
|
||||||
curSample(0),
|
curSample(0),
|
||||||
curOctave(3),
|
curOctave(3),
|
||||||
curOrder(0),
|
curOrder(0),
|
||||||
|
playOrder(0),
|
||||||
prevIns(0),
|
prevIns(0),
|
||||||
oldRow(0),
|
oldRow(0),
|
||||||
oldOrder(0),
|
|
||||||
oldOrder1(0),
|
|
||||||
editStep(1),
|
editStep(1),
|
||||||
exportLoops(0),
|
exportLoops(0),
|
||||||
soloChan(-1),
|
soloChan(-1),
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "imgui_impl_sdl2.h"
|
#include "imgui_impl_sdl2.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
#include <deque>
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
@ -874,6 +873,18 @@ struct UndoStep {
|
||||||
std::vector<UndoOrderData> ord;
|
std::vector<UndoOrderData> ord;
|
||||||
std::vector<UndoPatternData> pat;
|
std::vector<UndoPatternData> pat;
|
||||||
std::vector<UndoOtherData> other;
|
std::vector<UndoOtherData> other;
|
||||||
|
|
||||||
|
UndoStep():
|
||||||
|
type(GUI_UNDO_CHANGE_ORDER),
|
||||||
|
cursor(),
|
||||||
|
selStart(),
|
||||||
|
selEnd(),
|
||||||
|
order(0),
|
||||||
|
nibble(false),
|
||||||
|
oldOrdersLen(0),
|
||||||
|
newOrdersLen(0),
|
||||||
|
oldPatLen(0),
|
||||||
|
newPatLen(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// -1 = any
|
// -1 = any
|
||||||
|
@ -1323,7 +1334,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
std::vector<DivSystem> sysSearchResults;
|
std::vector<DivSystem> sysSearchResults;
|
||||||
std::vector<FurnaceGUISysDef> newSongSearchResults;
|
std::vector<FurnaceGUISysDef> newSongSearchResults;
|
||||||
std::deque<String> recentFile;
|
FixedQueue<String,32> recentFile;
|
||||||
std::vector<DivInstrumentType> makeInsTypeList;
|
std::vector<DivInstrumentType> makeInsTypeList;
|
||||||
std::vector<String> availRenderDrivers;
|
std::vector<String> availRenderDrivers;
|
||||||
std::vector<String> availAudioDrivers;
|
std::vector<String> availAudioDrivers;
|
||||||
|
@ -1391,7 +1402,7 @@ class FurnaceGUI {
|
||||||
String backupPath;
|
String backupPath;
|
||||||
|
|
||||||
std::mutex midiLock;
|
std::mutex midiLock;
|
||||||
std::queue<TAMidiMessage> midiQueue;
|
FixedQueue<TAMidiMessage,4096> midiQueue;
|
||||||
MIDIMap midiMap;
|
MIDIMap midiMap;
|
||||||
int learning;
|
int learning;
|
||||||
|
|
||||||
|
@ -1580,6 +1591,8 @@ class FurnaceGUI {
|
||||||
int chanOscThreads;
|
int chanOscThreads;
|
||||||
int renderPoolThreads;
|
int renderPoolThreads;
|
||||||
int showPool;
|
int showPool;
|
||||||
|
int writeInsNames;
|
||||||
|
int readInsNames;
|
||||||
unsigned int maxUndoSteps;
|
unsigned int maxUndoSteps;
|
||||||
String mainFontPath;
|
String mainFontPath;
|
||||||
String headFontPath;
|
String headFontPath;
|
||||||
|
@ -1760,6 +1773,8 @@ class FurnaceGUI {
|
||||||
chanOscThreads(0),
|
chanOscThreads(0),
|
||||||
renderPoolThreads(0),
|
renderPoolThreads(0),
|
||||||
showPool(0),
|
showPool(0),
|
||||||
|
writeInsNames(1),
|
||||||
|
readInsNames(1),
|
||||||
maxUndoSteps(100),
|
maxUndoSteps(100),
|
||||||
mainFontPath(""),
|
mainFontPath(""),
|
||||||
headFontPath(""),
|
headFontPath(""),
|
||||||
|
@ -1795,7 +1810,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
DivInstrument* prevInsData;
|
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 loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, newSongCategory, latchTarget;
|
||||||
int wheelX, wheelY, dragSourceX, dragSourceXFine, dragSourceY, dragDestinationX, dragDestinationXFine, dragDestinationY, oldBeat, oldBar;
|
int wheelX, wheelY, dragSourceX, dragSourceXFine, dragSourceY, dragDestinationX, dragDestinationXFine, dragDestinationY, oldBeat, oldBar;
|
||||||
int curGroove, exitDisabledTimer;
|
int curGroove, exitDisabledTimer;
|
||||||
|
@ -2005,8 +2020,8 @@ class FurnaceGUI {
|
||||||
int oldOrdersLen;
|
int oldOrdersLen;
|
||||||
DivOrders oldOrders;
|
DivOrders oldOrders;
|
||||||
DivPattern* oldPat[DIV_MAX_CHANS];
|
DivPattern* oldPat[DIV_MAX_CHANS];
|
||||||
std::deque<UndoStep> undoHist;
|
FixedQueue<UndoStep,256> undoHist;
|
||||||
std::deque<UndoStep> redoHist;
|
FixedQueue<UndoStep,256> redoHist;
|
||||||
|
|
||||||
// sample editor specific
|
// sample editor specific
|
||||||
double sampleZoom;
|
double sampleZoom;
|
||||||
|
|
|
@ -259,18 +259,18 @@ void FurnaceGUI::drawOrders() {
|
||||||
}
|
}
|
||||||
ImGui::PushFont(patFont);
|
ImGui::PushFont(patFont);
|
||||||
bool tooSmall=((displayChans+1)>((ImGui::GetContentRegionAvail().x)/(ImGui::CalcTextSize("AA").x+2.0*ImGui::GetStyle().ItemInnerSpacing.x)));
|
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 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)) {
|
if (ImGui::BeginTable("OrdersTable",1+displayChans,(tooSmall?ImGuiTableFlags_SizingFixedFit:ImGuiTableFlags_SizingStretchSame)|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY)) {
|
||||||
ImGui::PushFont(patFont);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,prevSpacing);
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,prevSpacing);
|
||||||
ImGui::TableSetupScrollFreeze(1,1);
|
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);
|
ImGui::TableNextRow(0,lineHeight);
|
||||||
ImVec2 ra=ImGui::GetContentRegionAvail();
|
ImVec2 ra=ImGui::GetContentRegionAvail();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
@ -283,9 +283,9 @@ void FurnaceGUI::drawOrders() {
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
for (int i=0; i<e->curSubSong->ordersLen; i++) {
|
for (int i=0; i<e->curSubSong->ordersLen; i++) {
|
||||||
ImGui::TableNextRow(0,lineHeight);
|
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();
|
ImGui::TableNextColumn();
|
||||||
if ((!followPattern && curOrder==i) || (followPattern && oldOrder1==i)) {
|
if (curOrder==i) {
|
||||||
// draw a border
|
// draw a border
|
||||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||||
ImVec2 rBegin=ImGui::GetCursorScreenPos();
|
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]);
|
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 (curOrder==i) {
|
||||||
if (orderEditMode==0) {
|
if (orderEditMode==0) {
|
||||||
prepareUndo(GUI_UNDO_CHANGE_ORDER);
|
prepareUndo(GUI_UNDO_CHANGE_ORDER);
|
||||||
|
@ -394,9 +394,9 @@ void FurnaceGUI::drawOrders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
ImGui::PopFont();
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
if (settings.orderButtonPos==2) {
|
if (settings.orderButtonPos==2) {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
@ -411,6 +411,5 @@ void FurnaceGUI::drawOrders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ORDERS;
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ORDERS;
|
||||||
oldOrder1=e->getOrder();
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
if (settings.overflowHighlight) {
|
if (settings.overflowHighlight) {
|
||||||
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
||||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
|
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]));
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
|
||||||
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
|
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
|
||||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2]));
|
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;
|
isPushing=true;
|
||||||
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
|
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]));
|
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
|
||||||
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
|
} else if (e->curSubSong->hilightB>0 && !(i%e->curSubSong->hilightB)) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2]));
|
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_HI_2]));
|
||||||
|
@ -378,7 +378,7 @@ void FurnaceGUI::drawPattern() {
|
||||||
bool inhibitMenu=false;
|
bool inhibitMenu=false;
|
||||||
|
|
||||||
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) {
|
if (e->isPlaying() && followPattern && (!e->isStepping() || pendingStepUpdate)) {
|
||||||
cursor.y=e->isStepping()?e->getRow():oldRow;
|
cursor.y=oldRow;
|
||||||
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
|
if (selStart.xCoarse==selEnd.xCoarse && selStart.xFine==selEnd.xFine && selStart.y==selEnd.y && !selecting) {
|
||||||
selStart=cursor;
|
selStart=cursor;
|
||||||
selEnd=cursor;
|
selEnd=cursor;
|
||||||
|
@ -419,8 +419,7 @@ void FurnaceGUI::drawPattern() {
|
||||||
}
|
}
|
||||||
//char id[32];
|
//char id[32];
|
||||||
ImGui::PushFont(patFont);
|
ImGui::PushFont(patFont);
|
||||||
int ord=oldOrder;
|
int ord=curOrder;
|
||||||
oldOrder=curOrder;
|
|
||||||
int chans=e->getTotalChannelCount();
|
int chans=e->getTotalChannelCount();
|
||||||
int displayChans=0;
|
int displayChans=0;
|
||||||
const DivPattern* patCache[DIV_MAX_CHANS];
|
const DivPattern* patCache[DIV_MAX_CHANS];
|
||||||
|
@ -437,23 +436,24 @@ void FurnaceGUI::drawPattern() {
|
||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+centerOff);
|
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))) {
|
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);
|
ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed);
|
||||||
char chanID[2048];
|
char chanID[2048];
|
||||||
float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale);
|
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) {
|
if (nextAddScroll!=0.0f) {
|
||||||
ImGui::SetScrollY(ImGui::GetScrollY()+nextAddScroll);
|
ImGui::SetScrollY(ImGui::GetScrollY()+nextAddScroll);
|
||||||
nextScroll=-1.0f;
|
nextScroll=-1.0f;
|
||||||
nextAddScroll=0.0f;
|
nextAddScroll=0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableSetupScrollFreeze(1,1);
|
ImGui::TableSetupScrollFreeze(1,1);
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
if (!e->curSubSong->chanShow[i]) continue;
|
if (!e->curSubSong->chanShow[i]) continue;
|
||||||
|
@ -937,7 +937,6 @@ void FurnaceGUI::drawPattern() {
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
oldRow=curRow;
|
|
||||||
if (demandScrollX) {
|
if (demandScrollX) {
|
||||||
int totalDemand=demandX-ImGui::GetScrollX();
|
int totalDemand=demandX-ImGui::GetScrollX();
|
||||||
if (totalDemand<80) {
|
if (totalDemand<80) {
|
||||||
|
|
|
@ -1098,7 +1098,7 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
ENTRY(
|
ENTRY(
|
||||||
"Sharp X68000", {
|
"Sharp X68000", {
|
||||||
CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2"),
|
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(
|
ENTRY(
|
||||||
|
|
|
@ -498,8 +498,24 @@ void FurnaceGUI::drawSettings() {
|
||||||
}
|
}
|
||||||
ImGui::Unindent();
|
ImGui::Unindent();
|
||||||
|
|
||||||
// SUBSECTION CHIP
|
bool writeInsNamesB=settings.writeInsNames;
|
||||||
CONFIG_SUBSECTION("Chip");
|
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::AlignTextToFramePadding();
|
||||||
ImGui::Text("Initial system:");
|
ImGui::Text("Initial system:");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -3341,6 +3357,8 @@ void FurnaceGUI::syncSettings() {
|
||||||
settings.chanOscThreads=e->getConfInt("chanOscThreads",0);
|
settings.chanOscThreads=e->getConfInt("chanOscThreads",0);
|
||||||
settings.renderPoolThreads=e->getConfInt("renderPoolThreads",0);
|
settings.renderPoolThreads=e->getConfInt("renderPoolThreads",0);
|
||||||
settings.showPool=e->getConfInt("showPool",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.mainFontSize,2,96);
|
||||||
clampSetting(settings.headFontSize,2,96);
|
clampSetting(settings.headFontSize,2,96);
|
||||||
|
@ -3494,6 +3512,8 @@ void FurnaceGUI::syncSettings() {
|
||||||
clampSetting(settings.chanOscThreads,0,256);
|
clampSetting(settings.chanOscThreads,0,256);
|
||||||
clampSetting(settings.renderPoolThreads,0,DIV_MAX_CHIPS);
|
clampSetting(settings.renderPoolThreads,0,DIV_MAX_CHIPS);
|
||||||
clampSetting(settings.showPool,0,1);
|
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.exportLoops<0.0) settings.exportLoops=0.0;
|
||||||
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
||||||
|
@ -3755,6 +3775,8 @@ void FurnaceGUI::commitSettings() {
|
||||||
e->setConf("chanOscThreads",settings.chanOscThreads);
|
e->setConf("chanOscThreads",settings.chanOscThreads);
|
||||||
e->setConf("renderPoolThreads",settings.renderPoolThreads);
|
e->setConf("renderPoolThreads",settings.renderPoolThreads);
|
||||||
e->setConf("showPool",settings.showPool);
|
e->setConf("showPool",settings.showPool);
|
||||||
|
e->setConf("writeInsNames",settings.writeInsNames);
|
||||||
|
e->setConf("readInsNames",settings.readInsNames);
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue