Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
This commit is contained in:
commit
7867b59580
|
@ -25,7 +25,7 @@ jobs:
|
||||||
- { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
|
- { name: 'macOS x86_64', os: macos-latest, arch: x86_64 }
|
||||||
- { name: 'macOS ARM', os: macos-latest, arch: arm64 }
|
- { name: 'macOS ARM', os: macos-latest, arch: arm64 }
|
||||||
- { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 }
|
- { name: 'Linux x86_64', os: ubuntu-18.04, arch: x86_64 }
|
||||||
- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf }
|
#- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf }
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|
||||||
name: ${{ matrix.config.name }}
|
name: ${{ matrix.config.name }}
|
||||||
|
|
|
@ -700,11 +700,11 @@ if (WIN32)
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
list(APPEND DEPENDENCIES_LIBRARIES -static)
|
list(APPEND DEPENDENCIES_LIBRARIES -static)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
elseif (APPLE)
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
find_library(COCOA Cocoa REQUIRED)
|
find_library(COCOA Cocoa REQUIRED)
|
||||||
list(APPEND DEPENDENCIES_LIBRARIES ${COCOA})
|
list(APPEND DEPENDENCIES_LIBRARIES ${COCOA})
|
||||||
|
else()
|
||||||
|
list(APPEND DEPENDENCIES_LIBRARIES dl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
|
|
|
@ -76,6 +76,7 @@ additional guidelines:
|
||||||
- I will run a test suite to make sure this is the case.
|
- I will run a test suite to make sure this is the case.
|
||||||
- if something breaks, you might want to add a compatibility flag (this requires changing the format though).
|
- if something breaks, you might want to add a compatibility flag (this requires changing the format though).
|
||||||
- do not use `#pragma once`.
|
- do not use `#pragma once`.
|
||||||
|
- do not memcmp() structs.
|
||||||
- on a switch block, **always** put `default` last and not in any other position.
|
- on a switch block, **always** put `default` last and not in any other position.
|
||||||
- I have fear of some C/C++ compilers ignoring the rest of cases upon hitting default.
|
- I have fear of some C/C++ compilers ignoring the rest of cases upon hitting default.
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ just put your demo song in `demos/`! be noted there are some guidelines:
|
||||||
|
|
||||||
- avoid Nintendo song covers.
|
- avoid Nintendo song covers.
|
||||||
- avoid big label song covers.
|
- avoid big label song covers.
|
||||||
- avoid poor quality songs.
|
- low effort compositions/covers may not be accepted at all.
|
||||||
|
|
||||||
# Finishing
|
# Finishing
|
||||||
|
|
||||||
|
|
1
TODO.md
1
TODO.md
|
@ -5,5 +5,4 @@
|
||||||
- (maybe) YM2612 CSM (no DualPCM)
|
- (maybe) YM2612 CSM (no DualPCM)
|
||||||
- port presets to new format
|
- port presets to new format
|
||||||
- bug fixes
|
- bug fixes
|
||||||
- (maybe) ExtCh FM macros?
|
|
||||||
- (maybe) advanced linear arpeggio? (run arp+slide simultaneously)
|
- (maybe) advanced linear arpeggio? (run arp+slide simultaneously)
|
||||||
|
|
Binary file not shown.
|
@ -6,10 +6,11 @@ these demo songs are not under the GPL. all rights are reserved to the original
|
||||||
|
|
||||||
# submit demo songs!
|
# submit demo songs!
|
||||||
|
|
||||||
contact me or send a pull request if you want your song to be added to this collection. be noted we have two rules:
|
contact me or send a pull request if you want your song to be added to this collection. be noted we have three rules:
|
||||||
|
|
||||||
- Nintendo covers are frowned upon
|
- Nintendo covers are frowned upon
|
||||||
- big label music covers also are discouraged
|
- big label music covers also are discouraged
|
||||||
|
- low effort compositions/covers may not be accepted at all.
|
||||||
|
|
||||||
tildearrow also accepts demo songs in the .dmf format as well as the .fur format.
|
tildearrow also accepts demo songs in the .dmf format as well as the .fur format.
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -12,18 +12,6 @@
|
||||||
#include "SAAFreq.h"
|
#include "SAAFreq.h"
|
||||||
#include "defns.h"
|
#include "defns.h"
|
||||||
|
|
||||||
#ifdef SAAFREQ_FIXED_CLOCKRATE
|
|
||||||
// 'load in' the data for the static frequency lookup table
|
|
||||||
// precomputed for a fixed clockrate
|
|
||||||
// See: tools/freqdat.py
|
|
||||||
const unsigned long CSAAFreq::m_FreqTable[2048] = {
|
|
||||||
#include "SAAFreq.dat"
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
unsigned long CSAAFreq::m_FreqTable[2048];
|
|
||||||
unsigned long CSAAFreq::m_nClockRate = 0;
|
|
||||||
#endif // SAAFREQ_FIXED_CLOCKRATE
|
|
||||||
|
|
||||||
const int INITIAL_LEVEL = 1;
|
const int INITIAL_LEVEL = 1;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -20,8 +20,8 @@ private:
|
||||||
const static unsigned long m_FreqTable[2048];
|
const static unsigned long m_FreqTable[2048];
|
||||||
#else
|
#else
|
||||||
// we'll calculate the frequency lookup table at runtime.
|
// we'll calculate the frequency lookup table at runtime.
|
||||||
static unsigned long m_FreqTable[2048];
|
unsigned long m_FreqTable[2048];
|
||||||
static unsigned long m_nClockRate;
|
unsigned long m_nClockRate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned long m_nCounter;
|
unsigned long m_nCounter;
|
||||||
|
|
|
@ -26,7 +26,9 @@ m_uParamRate(0),
|
||||||
m_nClockRate(EXTERNAL_CLK_HZ),
|
m_nClockRate(EXTERNAL_CLK_HZ),
|
||||||
m_nSampleRate(SAMPLE_RATE_HZ),
|
m_nSampleRate(SAMPLE_RATE_HZ),
|
||||||
m_nOversample(DEFAULT_OVERSAMPLE),
|
m_nOversample(DEFAULT_OVERSAMPLE),
|
||||||
m_bHighpass(false)
|
m_bHighpass(false),
|
||||||
|
filterout_z1_left_mixed(0),
|
||||||
|
filterout_z1_right_mixed(0)
|
||||||
{
|
{
|
||||||
#ifdef USE_CONFIG_FILE
|
#ifdef USE_CONFIG_FILE
|
||||||
m_Config.ReadConfig();
|
m_Config.ReadConfig();
|
||||||
|
@ -301,7 +303,6 @@ void scale_for_output(unsigned int left_input, unsigned int right_input,
|
||||||
void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples, DivDispatchOscBuffer** oscBuf)
|
void CSAASoundInternal::GenerateMany(BYTE* pBuffer, unsigned long nSamples, DivDispatchOscBuffer** oscBuf)
|
||||||
{
|
{
|
||||||
unsigned int left_mixed, right_mixed;
|
unsigned int left_mixed, right_mixed;
|
||||||
static double filterout_z1_left_mixed = 0, filterout_z1_right_mixed = 0;
|
|
||||||
|
|
||||||
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
#if defined(DEBUGSAA) || defined(USE_CONFIG_FILE)
|
||||||
BYTE* pBufferStart = pBuffer;
|
BYTE* pBufferStart = pBuffer;
|
||||||
|
|
|
@ -36,6 +36,7 @@ private:
|
||||||
unsigned int m_nSampleRate;
|
unsigned int m_nSampleRate;
|
||||||
unsigned int m_nOversample;
|
unsigned int m_nOversample;
|
||||||
bool m_bHighpass;
|
bool m_bHighpass;
|
||||||
|
double filterout_z1_left_mixed, filterout_z1_right_mixed;
|
||||||
#ifdef USE_CONFIG_FILE
|
#ifdef USE_CONFIG_FILE
|
||||||
SAAConfig m_Config;
|
SAAConfig m_Config;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,10 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 127: Furnace dev127
|
||||||
|
- 126: Furnace dev126
|
||||||
|
- 125: Furnace dev125
|
||||||
|
- 124: Furnace dev124
|
||||||
- 123: Furnace dev123
|
- 123: Furnace dev123
|
||||||
- 122: Furnace dev122
|
- 122: Furnace dev122
|
||||||
- 121: Furnace dev121
|
- 121: Furnace dev121
|
||||||
|
@ -437,7 +441,23 @@ clock=4000000
|
||||||
stereo=true
|
stereo=true
|
||||||
```
|
```
|
||||||
|
|
||||||
# instrument
|
# instrument (>=127)
|
||||||
|
|
||||||
|
Furnace dev127 and higher use the new instrument format.
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | "INS2" block ID
|
||||||
|
4 | size of this block
|
||||||
|
2 | format version
|
||||||
|
2 | instrument type
|
||||||
|
??? | features...
|
||||||
|
```
|
||||||
|
|
||||||
|
see [newIns.md](newIns.md) for more information.
|
||||||
|
|
||||||
|
# old instrument (<127)
|
||||||
|
|
||||||
notes:
|
notes:
|
||||||
|
|
||||||
|
|
539
papers/newIns.md
539
papers/newIns.md
|
@ -1,49 +1,516 @@
|
||||||
# possible new Furnace instrument format
|
# new Furnace instrument format
|
||||||
|
|
||||||
the main issue with Furnace instrument files is that they are too big, even if the instrument is nothing more than the FM setup...
|
the main issue with Furnace instrument files is that they are too big, even if the instrument is nothing more than the FM setup...
|
||||||
|
|
||||||
the aim of this new format is to greatly reduce the size of a resulting instrument.
|
the aim of this new format is to greatly reduce the size of a resulting instrument.
|
||||||
|
|
||||||
|
# information
|
||||||
|
|
||||||
|
this format is "featural", meaning that only used parameters are stored (depending on instrument types).
|
||||||
|
this is the biggest improvement over the previous format, which stored everything including unused parameters.
|
||||||
|
|
||||||
|
features which are not recognized by Furnace will be ignored.
|
||||||
|
|
||||||
|
instruments are not compressed using zlib, unlike Furnace songs.
|
||||||
|
|
||||||
|
all numbers are little-endian.
|
||||||
|
|
||||||
|
the following fields may be found in "size":
|
||||||
|
- `f` indicates a floating point number.
|
||||||
|
- `STR` is a UTF-8 zero-terminated string.
|
||||||
|
- `???` is an array of variable size.
|
||||||
|
- `S??` is an array of `STR`s.
|
||||||
|
- `1??` is an array of bytes.
|
||||||
|
- `2??` is an array of shorts.
|
||||||
|
- `4??` is an array of ints.
|
||||||
|
|
||||||
|
the format may change across versions. a `(>=VER)` indicates this field is only present starting from format version `VER`, and `(<VER)` indicates this field is present only before version `VER`.
|
||||||
|
|
||||||
|
furthermore, an `or reserved` indicates this field is always present, but is reserved when the version condition is not met.
|
||||||
|
|
||||||
|
the `size of this block` fields represent the size of a block excluding the ID and the aforementioned field.
|
||||||
|
|
||||||
|
# header
|
||||||
|
|
||||||
|
.fui files use the following header:
|
||||||
|
|
||||||
```
|
```
|
||||||
size | description
|
size | description
|
||||||
-----|------------------------------------
|
-----|------------------------------------
|
||||||
6 | "FURINS" format magic
|
4 | "FINS" format magic
|
||||||
2 | format version
|
2 | format version
|
||||||
1 | instrument type
|
2 | instrument type
|
||||||
??? | feature bits
|
??? | features...
|
||||||
4 | instrument length (if wave/sample bits are on)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
the "feature bits" field is a variable length bitfield. bit 7 in a byte indicates "read one more byte".
|
instruments in a .fur file use the following header instead:
|
||||||
|
|
||||||
the feature bits are:
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | "INS2" block ID
|
||||||
|
4 | size of this block
|
||||||
|
2 | format version
|
||||||
|
2 | instrument type
|
||||||
|
??? | features...
|
||||||
|
```
|
||||||
|
|
||||||
- 0: has wavetables
|
a feature uses the following format:
|
||||||
- 1: has samples
|
|
||||||
- 2: has name
|
```
|
||||||
- 3: FM data
|
size | description
|
||||||
- 4: FM data size (1: 2-op, 0: 4-op)
|
-----|------------------------------------
|
||||||
- 5: FM data includes OPL/OPZ data
|
2 | feature code
|
||||||
- if off, only read an op until ssgEnv.
|
2 | length of block
|
||||||
- if on, read everything else.
|
??? | data...
|
||||||
- 6: Game Boy data
|
```
|
||||||
- 7: (continue in next byte)
|
|
||||||
- 8: C64 data
|
the following feature codes are recognized:
|
||||||
- 9: Amiga data
|
|
||||||
- 10: standard data (macros)
|
- `NA`: instrument name
|
||||||
- 11: operator macros
|
- `FM`: FM ins data
|
||||||
- 12: release points
|
- `MA`: macro data
|
||||||
- 13: op release points
|
- `64`: C64 ins data
|
||||||
- 14: extended op macros
|
- `GB`: Game Boy ins data
|
||||||
- 15: (continue in next byte)
|
- `SM`: sample ins data
|
||||||
- 16: OPL drums mode data
|
- `O1`: operator 1 macros
|
||||||
- 17: Amiga sample map data
|
- `O2`: operator 2 macros
|
||||||
- 18: Namco 163 data
|
- `O3`: operator 3 macros
|
||||||
- 19: extra macros
|
- `O4`: operator 4 macros
|
||||||
- 20: FDS data
|
- `LD`: OPL drums mode data
|
||||||
- 21: OPZ data
|
- `SN`: SNES ins data
|
||||||
- 22: wavetable synth data
|
- `N1`: Namco 163 ins data
|
||||||
- 23: (continue in next byte)
|
- `FD`: FDS/Virtual Boy ins data
|
||||||
- 24: additional macro modes
|
- `WS`: wavetable synth data
|
||||||
- 25: extra C64 data
|
- `SL`: list of samples
|
||||||
- 26: MultiPCM data
|
- `WL`: list of wavetables
|
||||||
|
- `MP`: MultiPCM ins data
|
||||||
|
- `SU`: Sound Unit ins data
|
||||||
|
- `ES`: ES5506 ins data
|
||||||
|
- `X1`: X1-010 ins data
|
||||||
|
- `EN`: end of features
|
||||||
|
- if you find this feature code, stop reading the instrument.
|
||||||
|
- it will usually appear only when there sample/wave lists.
|
||||||
|
- instruments in a .fur shall end with this feature code.
|
||||||
|
|
||||||
|
# instrument name (NA)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
STR | instrument name
|
||||||
|
```
|
||||||
|
|
||||||
|
# FM data (FM)
|
||||||
|
|
||||||
|
- FM operator order is:
|
||||||
|
- 1/3/2/4 (internal order) for OPN, OPM, OPZ and OPL 4-op
|
||||||
|
- 1/2/?/? (? = unused) for OPL 2-op and OPLL
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | flags
|
||||||
|
| - bit 4-7: op enabled
|
||||||
|
| - op order from 4 to 7: 0, 2, 1, 3
|
||||||
|
| - 2-op instruments: 0, 1, x, x
|
||||||
|
| - bit 0-3: op count
|
||||||
|
-----|------------------------------------
|
||||||
|
| **base data**
|
||||||
|
| /7 6 5 4 3 2 1 0|
|
||||||
|
1 | |x| ALG |x| FB |
|
||||||
|
1 | |FMS2 |AMS| FMS |
|
||||||
|
1 | |AM2|4| LLPatch |
|
||||||
|
-----|------------------------------------
|
||||||
|
| **operator data × opCount**
|
||||||
|
| /7 6 5 4 3 2 1 0|
|
||||||
|
1 | |r| D T | MULT |
|
||||||
|
| \- KSR
|
||||||
|
1 | |s| T L |
|
||||||
|
| \- SUS
|
||||||
|
1 | |R S|v| A R |
|
||||||
|
| \- VIB
|
||||||
|
1 | |A|KSL| D R |
|
||||||
|
| \- AM
|
||||||
|
1 | |e|KVS| D2R |
|
||||||
|
| \- EGT
|
||||||
|
1 | | S L | R R |
|
||||||
|
1 | | DVB | SSG |
|
||||||
|
1 | | DAM |DT2| W S |
|
||||||
|
```
|
||||||
|
|
||||||
|
# macro data (MA)
|
||||||
|
|
||||||
|
notes:
|
||||||
|
|
||||||
|
- the macro range varies depending on the instrument type.
|
||||||
|
- "macro open" indicates whether the macro is collapsed or not in the instrument editor.
|
||||||
|
- meaning of extended macros varies depending on instrument type.
|
||||||
|
- meaning of panning macros varies depending on instrument type:
|
||||||
|
- for hard-panned chips (e.g. FM and Game Boy): left panning is 2-bit panning macro (left/right)
|
||||||
|
- otherwise both left and right panning macros are used
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
2 | length of macro header
|
||||||
|
??? | data...
|
||||||
|
```
|
||||||
|
|
||||||
|
each macro is represented like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | macro code
|
||||||
|
| - 0: vol
|
||||||
|
| - 1: arp
|
||||||
|
| - 2: duty
|
||||||
|
| - 3: wave
|
||||||
|
| - 4: pitch
|
||||||
|
| - 5: ex1
|
||||||
|
| - 6: ex2
|
||||||
|
| - 7: ex3
|
||||||
|
| - 8: alg
|
||||||
|
| - 9: fb
|
||||||
|
| - 10: fms
|
||||||
|
| - 11: ams
|
||||||
|
| - 12: panL
|
||||||
|
| - 13: panR
|
||||||
|
| - 14: phaseReset
|
||||||
|
| - 15: ex4
|
||||||
|
| - 16: ex5
|
||||||
|
| - 17: ex6
|
||||||
|
| - 18: ex7
|
||||||
|
| - 19: ex8
|
||||||
|
| - 255: stop reading and move on
|
||||||
|
1 | macro length
|
||||||
|
1 | macro loop
|
||||||
|
1 | macro release
|
||||||
|
1 | macro mode
|
||||||
|
1 | macro open/type/word size
|
||||||
|
| - bit 6-7: word size
|
||||||
|
| - 0: 8-bit unsigned
|
||||||
|
| - 1: 8-bit signed
|
||||||
|
| - 2: 16-bit signed
|
||||||
|
| - 3: 32-bit signed
|
||||||
|
| - bit 1-2: type
|
||||||
|
| - 0: normal
|
||||||
|
| - 1: ADSR
|
||||||
|
| - 2: LFO
|
||||||
|
| - bit 0: open
|
||||||
|
1 | macro delay
|
||||||
|
1 | macro speed
|
||||||
|
??? | macro data
|
||||||
|
| - length: macro length × word sizs
|
||||||
|
```
|
||||||
|
|
||||||
|
## interpreting macro mode values
|
||||||
|
|
||||||
|
- sequence (normal): I think this is obvious...
|
||||||
|
- ADSR:
|
||||||
|
- `val[0]`: bottom
|
||||||
|
- `val[1]`: top
|
||||||
|
- `val[2]`: attack
|
||||||
|
- `val[3]`: hold time
|
||||||
|
- `val[4]`: decay
|
||||||
|
- `val[5]`: sustain level
|
||||||
|
- `val[6]`: sustain hold time
|
||||||
|
- `val[7]`: decay 2
|
||||||
|
- `val[8]`: release
|
||||||
|
- LFO:
|
||||||
|
- `val[11]`: speed
|
||||||
|
- `val[12]`: waveform
|
||||||
|
- 0: triangle
|
||||||
|
- 1: saw
|
||||||
|
- 2: pulse
|
||||||
|
- `val[13]`: phase
|
||||||
|
- `val[14]`: loop
|
||||||
|
- `val[15]`: global (not sure how will I implement this)
|
||||||
|
|
||||||
|
# C64 data (64)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | flags 1
|
||||||
|
| - bit 7: dutyIsAbs
|
||||||
|
| - bit 6: initFilter
|
||||||
|
| - bit 5: volIsCutoff
|
||||||
|
| - bit 4: toFilter
|
||||||
|
| - bit 3: noise on
|
||||||
|
| - bit 2: pulse on
|
||||||
|
| - bit 1: saw on
|
||||||
|
| - bit 0: triangle on
|
||||||
|
1 | flags 2
|
||||||
|
| - bit 7: oscSync
|
||||||
|
| - bit 6: ringMod
|
||||||
|
| - bit 5: noTest
|
||||||
|
| - bit 4: filterIsAbs
|
||||||
|
| - bit 3: ch3off
|
||||||
|
| - bit 2: band pass
|
||||||
|
| - bit 1: high pass
|
||||||
|
| - bit 0: low pass
|
||||||
|
1 | attack/decay
|
||||||
|
| - bit 4-7: attack
|
||||||
|
| - bit 0-3: decay
|
||||||
|
1 | sustain release
|
||||||
|
| - bit 4-7: sustain
|
||||||
|
| - bit 0-3: release
|
||||||
|
2 | duty
|
||||||
|
2 | cutoff/resonance
|
||||||
|
| - bit 12-15: resonance
|
||||||
|
| - bit 0-10: cutoff
|
||||||
|
```
|
||||||
|
|
||||||
|
# Game Boy data (GB)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | envelope params
|
||||||
|
| - bit 5-7: length
|
||||||
|
| - bit 4: direction
|
||||||
|
| - bit 0-3: volume
|
||||||
|
1 | sound length
|
||||||
|
| - 64 is infinity
|
||||||
|
1 | flags
|
||||||
|
| - bit 1: always init envelope
|
||||||
|
| - bit 0: software envelope (zombie mode)
|
||||||
|
1 | hardware sequence length
|
||||||
|
??? | hardware sequence...
|
||||||
|
| - length: 3*hwSeqLen
|
||||||
|
```
|
||||||
|
|
||||||
|
a value in the hardware sequence has the following format:
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | command
|
||||||
|
| - 0: set envelope
|
||||||
|
| - 1: set sweep
|
||||||
|
| - 2: wait
|
||||||
|
| - 3: wait for release
|
||||||
|
| - 4: loop
|
||||||
|
| - 5: loop until release
|
||||||
|
2 | data
|
||||||
|
| - for set envelope:
|
||||||
|
| - 1 byte: parameter
|
||||||
|
| - bit 4-7: volume
|
||||||
|
| - bit 3: direction
|
||||||
|
| - bit 0-2: length
|
||||||
|
| - 1 byte: sound length
|
||||||
|
| - for set sweep:
|
||||||
|
| - 1 byte: parameter
|
||||||
|
| - bit 4-6: length
|
||||||
|
| - bit 3: direction
|
||||||
|
| - bit 0-2: shift
|
||||||
|
| - 1 byte: nothing
|
||||||
|
| - for wait:
|
||||||
|
| - 1 byte: length (in ticks)
|
||||||
|
| - 1 byte: nothing
|
||||||
|
| - for wait for release:
|
||||||
|
| - 2 bytes: nothing
|
||||||
|
| - for loop/loop until release:
|
||||||
|
| - 2 bytes: position
|
||||||
|
```
|
||||||
|
|
||||||
|
# sample ins data (SM)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
2 | initial sample
|
||||||
|
1 | flags
|
||||||
|
| - bit 2: use wave
|
||||||
|
| - bit 1: use sample
|
||||||
|
| - bit 0: use sample map
|
||||||
|
1 | waveform length
|
||||||
|
4?? | sample map... (120 entries)
|
||||||
|
| - only read if sample map is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
the sample map format:
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
2 | note to play
|
||||||
|
2 | sample to play
|
||||||
|
```
|
||||||
|
|
||||||
|
# operator macro data (O1, O2, O3 and O4)
|
||||||
|
|
||||||
|
similar to macro data, but using these macro codes:
|
||||||
|
|
||||||
|
- 0: AM
|
||||||
|
- 1: AR
|
||||||
|
- 2: DR
|
||||||
|
- 3: MULT
|
||||||
|
- 4: RR
|
||||||
|
- 5: SL
|
||||||
|
- 6: TL
|
||||||
|
- 7: DT2
|
||||||
|
- 8: RS
|
||||||
|
- 9: DT
|
||||||
|
- 10: D2R
|
||||||
|
- 11: SSG-EG
|
||||||
|
- 12: DAM
|
||||||
|
- 13: DVB
|
||||||
|
- 14: EGT
|
||||||
|
- 15: KSL
|
||||||
|
- 16: SUS
|
||||||
|
- 17: VIB
|
||||||
|
- 18: WS
|
||||||
|
- 19: KSR
|
||||||
|
|
||||||
|
# OPL drums mode data (LD)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | fixed frequency mode
|
||||||
|
2 | kick freq
|
||||||
|
2 | snare/hat freq
|
||||||
|
2 | tom/top freq
|
||||||
|
```
|
||||||
|
|
||||||
|
# SNES data (SN)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | attack/decay
|
||||||
|
| - bit 4-6: decay
|
||||||
|
| - bit 0-3: attack
|
||||||
|
1 | sustain/release
|
||||||
|
| - bit 5-7: sustain
|
||||||
|
| - bit 0-4: release
|
||||||
|
1 | flags
|
||||||
|
| - bit 4: envelope on
|
||||||
|
| - bit 3: make sustain effective
|
||||||
|
| - bit 0-2: gain mode
|
||||||
|
| - 0: direct
|
||||||
|
| - 4: dec
|
||||||
|
| - 5: exp
|
||||||
|
| - 6: inc
|
||||||
|
| - 7: bent
|
||||||
|
1 | gain
|
||||||
|
```
|
||||||
|
|
||||||
|
# Namco 163 data (N1)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | waveform
|
||||||
|
1 | wave pos
|
||||||
|
1 | wave len
|
||||||
|
1 | wave mode
|
||||||
|
```
|
||||||
|
|
||||||
|
# FDS/Virtual Boy data (FD)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | mod speed
|
||||||
|
4 | mod depth
|
||||||
|
1 | init mod table with first wave
|
||||||
|
1?? | modulation table (32 entries)
|
||||||
|
```
|
||||||
|
|
||||||
|
# wavetable synth data (WS)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | first wave
|
||||||
|
4 | second wave
|
||||||
|
1 | rate divider
|
||||||
|
1 | effect
|
||||||
|
| - bit 7: single or dual effect
|
||||||
|
1 | enabled
|
||||||
|
1 | global
|
||||||
|
1 | speed (+1)
|
||||||
|
1 | parameter 1
|
||||||
|
1 | parameter 2
|
||||||
|
1 | parameter 3
|
||||||
|
1 | parameter 4
|
||||||
|
```
|
||||||
|
|
||||||
|
# list of samples (SL)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | number of samples
|
||||||
|
1?? | sample indexes...
|
||||||
|
4?? | pointers to samples...
|
||||||
|
| - these use the Furnace sample format.
|
||||||
|
```
|
||||||
|
|
||||||
|
# list of wavetables (WL)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | number of wavetables
|
||||||
|
1?? | wavetable indexes...
|
||||||
|
4?? | pointers to wavetables...
|
||||||
|
| - these use the Furnace wavetable format.
|
||||||
|
```
|
||||||
|
|
||||||
|
# MultiPCM data (MP)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | attack rate
|
||||||
|
1 | decay 1 rate
|
||||||
|
1 | decay level
|
||||||
|
1 | decay 2 rate
|
||||||
|
1 | release rate
|
||||||
|
1 | rate correction
|
||||||
|
1 | LFO rate
|
||||||
|
1 | vibrato depth
|
||||||
|
1 | AM depth
|
||||||
|
```
|
||||||
|
|
||||||
|
# Sound Unit data (SU)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | switch roles of phase reset timer and frequency
|
||||||
|
```
|
||||||
|
|
||||||
|
# ES5506 data (ES)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
1 | filter mode
|
||||||
|
| - 0: HPK2_HPK2
|
||||||
|
| - 1: HPK2_LPK1
|
||||||
|
| - 2: LPK2_LPK2
|
||||||
|
| - 3: LPK2_LPK1
|
||||||
|
2 | K1
|
||||||
|
2 | K2
|
||||||
|
2 | envelope count
|
||||||
|
1 | left volume ramp
|
||||||
|
1 | right volume ramp
|
||||||
|
1 | K1 ramp
|
||||||
|
1 | K2 ramp
|
||||||
|
1 | K1 slow
|
||||||
|
1 | K2 slow
|
||||||
|
```
|
||||||
|
|
||||||
|
# X1-010 data (X1)
|
||||||
|
|
||||||
|
```
|
||||||
|
size | description
|
||||||
|
-----|------------------------------------
|
||||||
|
4 | bank slot
|
||||||
|
```
|
||||||
|
|
|
@ -532,23 +532,46 @@ class DivDispatch {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get sample memory buffer.
|
* Get sample memory buffer.
|
||||||
|
* @param index the memory index.
|
||||||
|
* @return a pointer to sample memory, or NULL.
|
||||||
*/
|
*/
|
||||||
virtual const void* getSampleMem(int index = 0);
|
virtual const void* getSampleMem(int index = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get sample memory capacity.
|
* Get sample memory capacity.
|
||||||
|
* @param index the memory index.
|
||||||
|
* @return memory capacity in bytes, or 0 if memory doesn't exist.
|
||||||
*/
|
*/
|
||||||
virtual size_t getSampleMemCapacity(int index = 0);
|
virtual size_t getSampleMemCapacity(int index = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get sample memory name.
|
||||||
|
* @param index the memory index.
|
||||||
|
* @return a name, or NULL if it doesn't have any name in particular.
|
||||||
|
*/
|
||||||
|
virtual const char* getSampleMemName(int index=0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get sample memory usage.
|
* Get sample memory usage.
|
||||||
|
* @param index the memory index.
|
||||||
|
* @return memory usage in bytes.
|
||||||
*/
|
*/
|
||||||
virtual size_t getSampleMemUsage(int index = 0);
|
virtual size_t getSampleMemUsage(int index = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render samples into sample memory.
|
* check whether sample has been loaded in memory.
|
||||||
|
* @param memory index.
|
||||||
|
* @param sample the sample in question.
|
||||||
|
* @return whether it did.
|
||||||
*/
|
*/
|
||||||
virtual void renderSamples();
|
virtual bool isSampleLoaded(int index, int sample);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render samples into sample memory.
|
||||||
|
* @param sysID the chip's index in the chip list.
|
||||||
|
*/
|
||||||
|
virtual void renderSamples(int sysID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* initialize this DivDispatch.
|
* initialize this DivDispatch.
|
||||||
|
|
|
@ -1315,7 +1315,7 @@ void DivEngine::renderSamples() {
|
||||||
// step 2: render samples to dispatch
|
// step 2: render samples to dispatch
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
if (disCont[i].dispatch!=NULL) {
|
if (disCont[i].dispatch!=NULL) {
|
||||||
disCont[i].dispatch->renderSamples();
|
disCont[i].dispatch->renderSamples(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2478,10 +2478,10 @@ void DivEngine::previewSampleNoLock(int sample, int note, int pStart, int pEnd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
blip_clear(samp_bb);
|
blip_clear(samp_bb);
|
||||||
double rate=song.sample[sample]->rate;
|
double rate=song.sample[sample]->centerRate;
|
||||||
if (note>=0) {
|
if (note>=0) {
|
||||||
rate=(pow(2.0,(double)(note)/12.0)*((double)song.sample[sample]->centerRate)*0.0625);
|
rate=(pow(2.0,(double)(note)/12.0)*((double)song.sample[sample]->centerRate)*0.0625);
|
||||||
if (rate<=0) rate=song.sample[sample]->rate;
|
if (rate<=0) rate=song.sample[sample]->centerRate;
|
||||||
}
|
}
|
||||||
if (rate<100) rate=100;
|
if (rate<100) rate=100;
|
||||||
blip_set_rates(samp_bb,rate,got.rate);
|
blip_set_rates(samp_bb,rate,got.rate);
|
||||||
|
|
|
@ -47,8 +47,8 @@
|
||||||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||||
|
|
||||||
#define DIV_VERSION "dev125"
|
#define DIV_VERSION "dev128"
|
||||||
#define DIV_ENGINE_VERSION 125
|
#define DIV_ENGINE_VERSION 128
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
#define DIV_VERSION_FC 0xff02
|
#define DIV_VERSION_FC 0xff02
|
||||||
|
@ -766,7 +766,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);
|
std::vector<DivInstrument*> instrumentFromFile(const char* path, bool loadAssets=true);
|
||||||
|
|
||||||
// load temporary instrument
|
// load temporary instrument
|
||||||
void loadTempIns(DivInstrument* which);
|
void loadTempIns(DivInstrument* which);
|
||||||
|
|
|
@ -208,7 +208,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Game Boy arp+soundLen screwery
|
// Game Boy arp+soundLen screwery
|
||||||
|
if (ds.system[0]==DIV_SYSTEM_GB) {
|
||||||
ds.systemFlags[0].set("enoughAlready",true);
|
ds.systemFlags[0].set("enoughAlready",true);
|
||||||
|
}
|
||||||
|
|
||||||
logI("reading module data...");
|
logI("reading module data...");
|
||||||
if (ds.version>0x0c) {
|
if (ds.version>0x0c) {
|
||||||
|
@ -966,6 +968,11 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.system[1]=DIV_SYSTEM_FDS;
|
ds.system[1]=DIV_SYSTEM_FDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SMS noise freq
|
||||||
|
if (ds.system[0]==DIV_SYSTEM_SMS) {
|
||||||
|
ds.systemFlags[0].set("noEasyNoise",true);
|
||||||
|
}
|
||||||
|
|
||||||
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
|
ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0));
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
|
@ -2348,142 +2355,24 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
|
|
||||||
// read samples
|
// read samples
|
||||||
for (int i=0; i<ds.sampleLen; i++) {
|
for (int i=0; i<ds.sampleLen; i++) {
|
||||||
int vol=0;
|
DivSample* sample=new DivSample;
|
||||||
int pitch=0;
|
|
||||||
|
|
||||||
if (!reader.seek(samplePtr[i],SEEK_SET)) {
|
if (!reader.seek(samplePtr[i],SEEK_SET)) {
|
||||||
logE("couldn't seek to sample %d!",i);
|
logE("couldn't seek to sample %d!",i);
|
||||||
lastError=fmt::sprintf("couldn't seek to sample %d!",i);
|
lastError=fmt::sprintf("couldn't seek to sample %d!",i);
|
||||||
ds.unload();
|
ds.unload();
|
||||||
|
delete sample;
|
||||||
delete[] file;
|
delete[] file;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.read(magic,4);
|
if (sample->readSampleData(reader,ds.version)!=DIV_DATA_SUCCESS) {
|
||||||
if (strcmp(magic,"SMPL")!=0 && strcmp(magic,"SMP2")!=0) {
|
lastError="invalid sample header/data!";
|
||||||
logE("%d: invalid sample header!",i);
|
|
||||||
lastError="invalid sample header!";
|
|
||||||
ds.unload();
|
ds.unload();
|
||||||
|
delete sample;
|
||||||
delete[] file;
|
delete[] file;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool isNewSample=(strcmp(magic,"SMP2")==0);
|
|
||||||
reader.readI();
|
|
||||||
DivSample* sample=new DivSample;
|
|
||||||
logD("reading sample %d at %x...",i,samplePtr[i]);
|
|
||||||
if (!isNewSample) logV("(old sample)");
|
|
||||||
|
|
||||||
sample->name=reader.readString();
|
|
||||||
sample->samples=reader.readI();
|
|
||||||
if (!isNewSample) {
|
|
||||||
sample->loopEnd=sample->samples;
|
|
||||||
}
|
|
||||||
sample->rate=reader.readI();
|
|
||||||
|
|
||||||
if (isNewSample) {
|
|
||||||
sample->centerRate=reader.readI();
|
|
||||||
sample->depth=(DivSampleDepth)reader.readC();
|
|
||||||
if (ds.version>=123) {
|
|
||||||
sample->loopMode=(DivSampleLoopMode)reader.readC();
|
|
||||||
} else {
|
|
||||||
sample->loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
|
||||||
reader.readC();
|
|
||||||
}
|
|
||||||
|
|
||||||
// reserved
|
|
||||||
reader.readC();
|
|
||||||
reader.readC();
|
|
||||||
|
|
||||||
sample->loopStart=reader.readI();
|
|
||||||
sample->loopEnd=reader.readI();
|
|
||||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
reader.readI();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ds.version<58) {
|
|
||||||
vol=reader.readS();
|
|
||||||
pitch=reader.readS();
|
|
||||||
} else {
|
|
||||||
reader.readI();
|
|
||||||
}
|
|
||||||
sample->depth=(DivSampleDepth)reader.readC();
|
|
||||||
|
|
||||||
// reserved
|
|
||||||
reader.readC();
|
|
||||||
|
|
||||||
// while version 32 stored this value, it was unused.
|
|
||||||
if (ds.version>=38) {
|
|
||||||
sample->centerRate=(unsigned short)reader.readS();
|
|
||||||
} else {
|
|
||||||
reader.readS();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds.version>=19) {
|
|
||||||
sample->loopStart=reader.readI();
|
|
||||||
sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0);
|
|
||||||
} else {
|
|
||||||
reader.readI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ds.version>=58) { // modern sample
|
|
||||||
sample->init(sample->samples);
|
|
||||||
reader.read(sample->getCurBuf(),sample->getCurBufLen());
|
|
||||||
#ifdef TA_BIG_ENDIAN
|
|
||||||
// convert 16-bit samples to big-endian
|
|
||||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
|
||||||
unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf();
|
|
||||||
size_t sampleBufLen=sample->getCurBufLen();
|
|
||||||
for (size_t pos=0; pos<sampleBufLen; pos+=2) {
|
|
||||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
|
||||||
sampleBuf[pos+1]^=sampleBuf[pos];
|
|
||||||
sampleBuf[pos]^=sampleBuf[pos+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else { // legacy sample
|
|
||||||
int length=sample->samples;
|
|
||||||
short* data=new short[length];
|
|
||||||
reader.read(data,2*length);
|
|
||||||
|
|
||||||
#ifdef TA_BIG_ENDIAN
|
|
||||||
// convert 16-bit samples to big-endian
|
|
||||||
for (int pos=0; pos<length; pos++) {
|
|
||||||
data[pos]=((unsigned short)data[pos]>>8)|((unsigned short)data[pos]<<8);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pitch!=5) {
|
|
||||||
logD("%d: scaling from %d...",i,pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render data
|
|
||||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
|
||||||
logW("%d: sample depth is wrong! (%d)",i,sample->depth);
|
|
||||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
|
||||||
}
|
|
||||||
sample->samples=(double)sample->samples/samplePitches[pitch];
|
|
||||||
sample->init(sample->samples);
|
|
||||||
|
|
||||||
unsigned int k=0;
|
|
||||||
float mult=(float)(vol)/50.0f;
|
|
||||||
for (double j=0; j<length; j+=samplePitches[pitch]) {
|
|
||||||
if (k>=sample->samples) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) {
|
|
||||||
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
|
||||||
sample->data8[k++]=fmin(fmax(next,-128),127);
|
|
||||||
} else {
|
|
||||||
float next=(float)data[(unsigned int)j]*mult;
|
|
||||||
sample->data16[k++]=fmin(fmax(next,-32768),32767);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ds.sample.push_back(sample);
|
ds.sample.push_back(sample);
|
||||||
}
|
}
|
||||||
|
@ -2631,6 +2520,16 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SN noise compat
|
||||||
|
if (ds.version<128) {
|
||||||
|
for (int i=0; i<ds.systemLen; i++) {
|
||||||
|
if (ds.system[i]==DIV_SYSTEM_SMS ||
|
||||||
|
ds.system[i]==DIV_SYSTEM_T6W28) {
|
||||||
|
ds.systemFlags[i].set("noEasyNoise",true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (active) quitDispatch();
|
if (active) quitDispatch();
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
|
@ -4621,7 +4520,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
for (int i=0; i<song.insLen; i++) {
|
for (int i=0; i<song.insLen; i++) {
|
||||||
DivInstrument* ins=song.ins[i];
|
DivInstrument* ins=song.ins[i];
|
||||||
insPtr.push_back(w->tell());
|
insPtr.push_back(w->tell());
|
||||||
ins->putInsData(w);
|
logV("writing instrument %d...",i);
|
||||||
|
ins->putInsData2(w,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WAVETABLE
|
/// WAVETABLE
|
||||||
|
@ -4635,45 +4535,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
for (int i=0; i<song.sampleLen; i++) {
|
||||||
DivSample* sample=song.sample[i];
|
DivSample* sample=song.sample[i];
|
||||||
samplePtr.push_back(w->tell());
|
samplePtr.push_back(w->tell());
|
||||||
w->write("SMP2",4);
|
sample->putSampleData(w);
|
||||||
blockStartSeek=w->tell();
|
|
||||||
w->writeI(0);
|
|
||||||
|
|
||||||
w->writeString(sample->name,false);
|
|
||||||
w->writeI(sample->samples);
|
|
||||||
w->writeI(sample->rate);
|
|
||||||
w->writeI(sample->centerRate);
|
|
||||||
w->writeC(sample->depth);
|
|
||||||
w->writeC(sample->loopMode);
|
|
||||||
w->writeC(0); // reserved
|
|
||||||
w->writeC(0);
|
|
||||||
w->writeI(sample->loop?sample->loopStart:-1);
|
|
||||||
w->writeI(sample->loop?sample->loopEnd:-1);
|
|
||||||
|
|
||||||
for (int i=0; i<4; i++) {
|
|
||||||
w->writeI(0xffffffff);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TA_BIG_ENDIAN
|
|
||||||
// store 16-bit samples as little-endian
|
|
||||||
if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
|
||||||
unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf();
|
|
||||||
size_t bufLen=sample->getCurBufLen();
|
|
||||||
for (size_t i=0; i<bufLen; i+=2) {
|
|
||||||
w->writeC(sampleBuf[i+1]);
|
|
||||||
w->writeC(sampleBuf[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
w->write(sample->getCurBuf(),sample->getCurBufLen());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
w->write(sample->getCurBuf(),sample->getCurBufLen());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
blockEndSeek=w->tell();
|
|
||||||
w->seek(blockStartSeek,SEEK_SET);
|
|
||||||
w->writeI(blockEndSeek-blockStartSeek-4);
|
|
||||||
w->seek(0,SEEK_END);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// PATTERN
|
/// PATTERN
|
||||||
|
|
|
@ -147,7 +147,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
logD("instrument type is C64");
|
logD("instrument type is C64");
|
||||||
break;
|
break;
|
||||||
case 8: // Arcade
|
case 8: // Arcade
|
||||||
ins->type=DIV_INS_FM;
|
ins->type=DIV_INS_OPM;
|
||||||
logD("instrument type is Arcade");
|
logD("instrument type is Arcade");
|
||||||
break;
|
break;
|
||||||
case 9: // Neo Geo
|
case 9: // Neo Geo
|
||||||
|
@ -187,6 +187,8 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
ins->type=DIV_INS_OPLL;
|
ins->type=DIV_INS_OPLL;
|
||||||
} else if (sys==1) {
|
} else if (sys==1) {
|
||||||
ins->type=DIV_INS_OPL;
|
ins->type=DIV_INS_OPL;
|
||||||
|
} else if (sys==8) {
|
||||||
|
ins->type=DIV_INS_OPM;
|
||||||
} else {
|
} else {
|
||||||
ins->type=DIV_INS_FM;
|
ins->type=DIV_INS_FM;
|
||||||
}
|
}
|
||||||
|
@ -1341,7 +1343,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
// At this point we know any other line would be associated with patch params
|
// At this point we know any other line would be associated with patch params
|
||||||
if (newPatch == NULL) {
|
if (newPatch == NULL) {
|
||||||
newPatch = new DivInstrument;
|
newPatch = new DivInstrument;
|
||||||
newPatch->type = DIV_INS_FM;
|
newPatch->type = DIV_INS_OPM;
|
||||||
newPatch->fm.ops = 4;
|
newPatch->fm.ops = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1814,7 +1816,7 @@ void DivEngine::loadWOPN(SafeReader& reader, std::vector<DivInstrument*>& ret, S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path, bool loadAssets) {
|
||||||
std::vector<DivInstrument*> ret;
|
std::vector<DivInstrument*> ret;
|
||||||
warnings="";
|
warnings="";
|
||||||
|
|
||||||
|
@ -1880,10 +1882,19 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
||||||
|
|
||||||
unsigned char magic[16];
|
unsigned char magic[16];
|
||||||
bool isFurnaceInstr=false;
|
bool isFurnaceInstr=false;
|
||||||
|
bool isOldFurnaceIns=false;
|
||||||
try {
|
try {
|
||||||
reader.read(magic,16);
|
reader.read(magic,4);
|
||||||
if (memcmp("-Furnace instr.-",magic,16)==0) {
|
if (memcmp("FINS",magic,4)==0) {
|
||||||
isFurnaceInstr=true;
|
isFurnaceInstr=true;
|
||||||
|
logV("found a new Furnace ins");
|
||||||
|
} else {
|
||||||
|
reader.read(&magic[4],12);
|
||||||
|
if (memcmp("-Furnace instr.-",magic,16)==0) {
|
||||||
|
logV("found an old Furnace ins");
|
||||||
|
isFurnaceInstr=true;
|
||||||
|
isOldFurnaceIns=true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (EndOfFileException& e) {
|
} catch (EndOfFileException& e) {
|
||||||
reader.seek(0,SEEK_SET);
|
reader.seek(0,SEEK_SET);
|
||||||
|
@ -1892,17 +1903,25 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
||||||
if (isFurnaceInstr) {
|
if (isFurnaceInstr) {
|
||||||
DivInstrument* ins=new DivInstrument;
|
DivInstrument* ins=new DivInstrument;
|
||||||
try {
|
try {
|
||||||
short version=reader.readS();
|
short version=0;
|
||||||
|
if (isOldFurnaceIns) {
|
||||||
|
version=reader.readS();
|
||||||
reader.readS(); // reserved
|
reader.readS(); // reserved
|
||||||
|
} else {
|
||||||
|
version=reader.readS();
|
||||||
|
reader.seek(0,SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
if (version>DIV_ENGINE_VERSION) {
|
if (version>DIV_ENGINE_VERSION) {
|
||||||
warnings="this instrument is made with a more recent version of Furnace!";
|
warnings="this instrument is made with a more recent version of Furnace!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isOldFurnaceIns) {
|
||||||
unsigned int dataPtr=reader.readI();
|
unsigned int dataPtr=reader.readI();
|
||||||
reader.seek(dataPtr,SEEK_SET);
|
reader.seek(dataPtr,SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
if (ins->readInsData(reader,version)!=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;
|
||||||
|
@ -1961,6 +1980,11 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
|
||||||
format=DIV_INSFORMAT_WOPL;
|
format=DIV_INSFORMAT_WOPL;
|
||||||
} else if (extS==".wopn") {
|
} else if (extS==".wopn") {
|
||||||
format=DIV_INSFORMAT_WOPN;
|
format=DIV_INSFORMAT_WOPN;
|
||||||
|
} else {
|
||||||
|
// unknown format
|
||||||
|
lastError="unknown instrument format";
|
||||||
|
delete[] buf;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,9 @@
|
||||||
#include "safeWriter.h"
|
#include "safeWriter.h"
|
||||||
#include "dataErrors.h"
|
#include "dataErrors.h"
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct DivSong;
|
||||||
|
|
||||||
// NOTICE!
|
// NOTICE!
|
||||||
// before adding new instrument types to this struct, please ask me first.
|
// before adding new instrument types to this struct, please ask me first.
|
||||||
|
@ -97,11 +100,21 @@ struct DivInstrumentFM {
|
||||||
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset;
|
unsigned char alg, fb, fms, ams, fms2, ams2, ops, opllPreset;
|
||||||
bool fixedDrums;
|
bool fixedDrums;
|
||||||
unsigned short kickFreq, snareHatFreq, tomTopFreq;
|
unsigned short kickFreq, snareHatFreq, tomTopFreq;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentFM& other);
|
||||||
|
bool operator!=(const DivInstrumentFM& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
struct Operator {
|
struct Operator {
|
||||||
bool enable;
|
bool enable;
|
||||||
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
|
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
|
||||||
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
|
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
|
||||||
unsigned char kvs;
|
unsigned char kvs;
|
||||||
|
|
||||||
|
bool operator==(const Operator& other);
|
||||||
|
bool operator!=(const Operator& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
Operator():
|
Operator():
|
||||||
enable(true),
|
enable(true),
|
||||||
am(0),
|
am(0),
|
||||||
|
@ -296,6 +309,12 @@ struct DivInstrumentGB {
|
||||||
unsigned char cmd;
|
unsigned char cmd;
|
||||||
unsigned short data;
|
unsigned short data;
|
||||||
} hwSeq[256];
|
} hwSeq[256];
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentGB& other);
|
||||||
|
bool operator!=(const DivInstrumentGB& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentGB():
|
DivInstrumentGB():
|
||||||
envVol(15),
|
envVol(15),
|
||||||
envDir(0),
|
envDir(0),
|
||||||
|
@ -318,6 +337,11 @@ struct DivInstrumentC64 {
|
||||||
unsigned short cut;
|
unsigned short cut;
|
||||||
bool hp, lp, bp, ch3off;
|
bool hp, lp, bp, ch3off;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentC64& other);
|
||||||
|
bool operator!=(const DivInstrumentC64& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentC64():
|
DivInstrumentC64():
|
||||||
triOn(false),
|
triOn(false),
|
||||||
sawOn(true),
|
sawOn(true),
|
||||||
|
@ -369,6 +393,11 @@ struct DivInstrumentAmiga {
|
||||||
unsigned char waveLen;
|
unsigned char waveLen;
|
||||||
SampleMap noteMap[120];
|
SampleMap noteMap[120];
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentAmiga& other);
|
||||||
|
bool operator!=(const DivInstrumentAmiga& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the sample at specified note.
|
* get the sample at specified note.
|
||||||
* @return the sample.
|
* @return the sample.
|
||||||
|
@ -424,6 +453,11 @@ struct DivInstrumentAmiga {
|
||||||
struct DivInstrumentX1_010 {
|
struct DivInstrumentX1_010 {
|
||||||
int bankSlot;
|
int bankSlot;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentX1_010& other);
|
||||||
|
bool operator!=(const DivInstrumentX1_010& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentX1_010():
|
DivInstrumentX1_010():
|
||||||
bankSlot(0) {}
|
bankSlot(0) {}
|
||||||
};
|
};
|
||||||
|
@ -432,6 +466,11 @@ struct DivInstrumentN163 {
|
||||||
int wave, wavePos, waveLen;
|
int wave, wavePos, waveLen;
|
||||||
unsigned char waveMode;
|
unsigned char waveMode;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentN163& other);
|
||||||
|
bool operator!=(const DivInstrumentN163& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentN163():
|
DivInstrumentN163():
|
||||||
wave(-1),
|
wave(-1),
|
||||||
wavePos(0),
|
wavePos(0),
|
||||||
|
@ -444,6 +483,12 @@ struct DivInstrumentFDS {
|
||||||
int modSpeed, modDepth;
|
int modSpeed, modDepth;
|
||||||
// this is here for compatibility.
|
// this is here for compatibility.
|
||||||
bool initModTableWithFirstWave;
|
bool initModTableWithFirstWave;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentFDS& other);
|
||||||
|
bool operator!=(const DivInstrumentFDS& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentFDS():
|
DivInstrumentFDS():
|
||||||
modSpeed(0),
|
modSpeed(0),
|
||||||
modDepth(0),
|
modDepth(0),
|
||||||
|
@ -456,6 +501,11 @@ struct DivInstrumentMultiPCM {
|
||||||
unsigned char ar, d1r, dl, d2r, rr, rc;
|
unsigned char ar, d1r, dl, d2r, rr, rc;
|
||||||
unsigned char lfo, vib, am;
|
unsigned char lfo, vib, am;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentMultiPCM& other);
|
||||||
|
bool operator!=(const DivInstrumentMultiPCM& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentMultiPCM():
|
DivInstrumentMultiPCM():
|
||||||
ar(15), d1r(15), dl(0), d2r(0), rr(15), rc(15),
|
ar(15), d1r(15), dl(0), d2r(0), rr(15), rc(15),
|
||||||
lfo(0), vib(0), am(0) {
|
lfo(0), vib(0), am(0) {
|
||||||
|
@ -494,6 +544,12 @@ struct DivInstrumentWaveSynth {
|
||||||
unsigned char effect;
|
unsigned char effect;
|
||||||
bool oneShot, enabled, global;
|
bool oneShot, enabled, global;
|
||||||
unsigned char speed, param1, param2, param3, param4;
|
unsigned char speed, param1, param2, param3, param4;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentWaveSynth& other);
|
||||||
|
bool operator!=(const DivInstrumentWaveSynth& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentWaveSynth():
|
DivInstrumentWaveSynth():
|
||||||
wave1(0),
|
wave1(0),
|
||||||
wave2(0),
|
wave2(0),
|
||||||
|
@ -511,6 +567,12 @@ struct DivInstrumentWaveSynth {
|
||||||
|
|
||||||
struct DivInstrumentSoundUnit {
|
struct DivInstrumentSoundUnit {
|
||||||
bool switchRoles;
|
bool switchRoles;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentSoundUnit& other);
|
||||||
|
bool operator!=(const DivInstrumentSoundUnit& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentSoundUnit():
|
DivInstrumentSoundUnit():
|
||||||
switchRoles(false) {}
|
switchRoles(false) {}
|
||||||
};
|
};
|
||||||
|
@ -546,6 +608,12 @@ struct DivInstrumentES5506 {
|
||||||
};
|
};
|
||||||
Filter filter;
|
Filter filter;
|
||||||
Envelope envelope;
|
Envelope envelope;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentES5506& other);
|
||||||
|
bool operator!=(const DivInstrumentES5506& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentES5506():
|
DivInstrumentES5506():
|
||||||
filter(Filter()),
|
filter(Filter()),
|
||||||
envelope(Envelope()) {}
|
envelope(Envelope()) {}
|
||||||
|
@ -563,6 +631,12 @@ struct DivInstrumentSNES {
|
||||||
GainMode gainMode;
|
GainMode gainMode;
|
||||||
unsigned char gain;
|
unsigned char gain;
|
||||||
unsigned char a, d, s, r;
|
unsigned char a, d, s, r;
|
||||||
|
|
||||||
|
bool operator==(const DivInstrumentSNES& other);
|
||||||
|
bool operator!=(const DivInstrumentSNES& other) {
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
|
|
||||||
DivInstrumentSNES():
|
DivInstrumentSNES():
|
||||||
useEnv(true),
|
useEnv(true),
|
||||||
sus(false),
|
sus(false),
|
||||||
|
@ -576,7 +650,6 @@ struct DivInstrumentSNES {
|
||||||
|
|
||||||
struct DivInstrument {
|
struct DivInstrument {
|
||||||
String name;
|
String name;
|
||||||
bool mode;
|
|
||||||
DivInstrumentType type;
|
DivInstrumentType type;
|
||||||
DivInstrumentFM fm;
|
DivInstrumentFM fm;
|
||||||
DivInstrumentSTD std;
|
DivInstrumentSTD std;
|
||||||
|
@ -592,26 +665,79 @@ struct DivInstrument {
|
||||||
DivInstrumentES5506 es5506;
|
DivInstrumentES5506 es5506;
|
||||||
DivInstrumentSNES snes;
|
DivInstrumentSNES snes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* these are internal functions.
|
||||||
|
*/
|
||||||
|
void writeMacro(SafeWriter* w, const DivInstrumentMacro& m, unsigned char macroCode);
|
||||||
|
void writeFeatureNA(SafeWriter* w);
|
||||||
|
void writeFeatureFM(SafeWriter* w, bool fui);
|
||||||
|
void writeFeatureMA(SafeWriter* w);
|
||||||
|
void writeFeature64(SafeWriter* w);
|
||||||
|
void writeFeatureGB(SafeWriter* w);
|
||||||
|
void writeFeatureSM(SafeWriter* w);
|
||||||
|
void writeFeatureOx(SafeWriter* w, int op);
|
||||||
|
void writeFeatureLD(SafeWriter* w);
|
||||||
|
void writeFeatureSN(SafeWriter* w);
|
||||||
|
void writeFeatureN1(SafeWriter* w);
|
||||||
|
void writeFeatureFD(SafeWriter* w);
|
||||||
|
void writeFeatureWS(SafeWriter* w);
|
||||||
|
size_t writeFeatureSL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||||
|
size_t writeFeatureWL(SafeWriter* w, std::vector<int>& list, const DivSong* song);
|
||||||
|
void writeFeatureMP(SafeWriter* w);
|
||||||
|
void writeFeatureSU(SafeWriter* w);
|
||||||
|
void writeFeatureES(SafeWriter* w);
|
||||||
|
void writeFeatureX1(SafeWriter* w);
|
||||||
|
|
||||||
|
void readFeatureNA(SafeReader& reader);
|
||||||
|
void readFeatureFM(SafeReader& reader);
|
||||||
|
void readFeatureMA(SafeReader& reader);
|
||||||
|
void readFeature64(SafeReader& reader);
|
||||||
|
void readFeatureGB(SafeReader& reader);
|
||||||
|
void readFeatureSM(SafeReader& reader);
|
||||||
|
void readFeatureOx(SafeReader& reader, int op);
|
||||||
|
void readFeatureLD(SafeReader& reader);
|
||||||
|
void readFeatureSN(SafeReader& reader);
|
||||||
|
void readFeatureN1(SafeReader& reader);
|
||||||
|
void readFeatureFD(SafeReader& reader);
|
||||||
|
void readFeatureWS(SafeReader& reader);
|
||||||
|
void readFeatureSL(SafeReader& reader, DivSong* song, short version);
|
||||||
|
void readFeatureWL(SafeReader& reader, DivSong* song, short version);
|
||||||
|
void readFeatureMP(SafeReader& reader);
|
||||||
|
void readFeatureSU(SafeReader& reader);
|
||||||
|
void readFeatureES(SafeReader& reader);
|
||||||
|
void readFeatureX1(SafeReader& reader);
|
||||||
|
|
||||||
|
DivDataErrors readInsDataOld(SafeReader& reader, short version);
|
||||||
|
DivDataErrors readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save the instrument to a SafeWriter.
|
* save the instrument to a SafeWriter.
|
||||||
* @param w the SafeWriter in question.
|
* @param w the SafeWriter in question.
|
||||||
*/
|
*/
|
||||||
void putInsData(SafeWriter* w);
|
void putInsData(SafeWriter* w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* save the instrument to a SafeWriter using new format.
|
||||||
|
* @param w the SafeWriter in question.
|
||||||
|
*/
|
||||||
|
void putInsData2(SafeWriter* w, bool fui=false, const DivSong* song=NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* read instrument data in .fui format.
|
* read instrument data in .fui format.
|
||||||
* @param reader the reader.
|
* @param reader the reader.
|
||||||
* @param version the format version.
|
* @param version the format version.
|
||||||
* @return a DivDataErrors.
|
* @return a DivDataErrors.
|
||||||
*/
|
*/
|
||||||
DivDataErrors readInsData(SafeReader& reader, short version);
|
DivDataErrors readInsData(SafeReader& reader, short version, DivSong* song=NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save this instrument to a file.
|
* save this instrument to a file.
|
||||||
* @param path file path.
|
* @param path file path.
|
||||||
|
* @param oldFormat whether to save in legacy Furnace ins format.
|
||||||
|
* @param song if new format, a DivSong to read wavetables and samples.
|
||||||
* @return whether it was successful.
|
* @return whether it was successful.
|
||||||
*/
|
*/
|
||||||
bool save(const char* path);
|
bool save(const char* path, bool oldFormat=false, DivSong* song=NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* save this instrument to a file in .dmp format.
|
* save this instrument to a file in .dmp format.
|
||||||
|
|
|
@ -152,11 +152,20 @@ size_t DivDispatch::getSampleMemCapacity(int index) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* DivDispatch::getSampleMemName(int index) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
size_t DivDispatch::getSampleMemUsage(int index) {
|
size_t DivDispatch::getSampleMemUsage(int index) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivDispatch::renderSamples() {
|
bool DivDispatch::isSampleLoaded(int index, int sample) {
|
||||||
|
printf("you are calling.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivDispatch::renderSamples(int sysID) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1191,13 +1191,25 @@ size_t DivPlatformES5506::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index == 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformES5506::renderSamples() {
|
bool DivPlatformES5506::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformES5506::renderSamples(int sysID) {
|
||||||
memset(sampleMem,0,getSampleMemCapacity());
|
memset(sampleMem,0,getSampleMemCapacity());
|
||||||
memset(sampleOffES5506,0,256*sizeof(unsigned int));
|
memset(sampleOffES5506,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=128; // add silent at begin and end of each bank for reverse playback
|
size_t memPos=128; // add silent at begin and end of each bank for reverse playback
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffES5506[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int length=s->length16;
|
unsigned int length=s->length16;
|
||||||
// fit sample size to single bank size
|
// fit sample size to single bank size
|
||||||
if (length>(4194304-128)) {
|
if (length>(4194304-128)) {
|
||||||
|
@ -1217,6 +1229,7 @@ void DivPlatformES5506::renderSamples() {
|
||||||
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length);
|
memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length);
|
||||||
}
|
}
|
||||||
sampleOffES5506[i]=memPos;
|
sampleOffES5506[i]=memPos;
|
||||||
|
sampleLoaded[i]=true;
|
||||||
memPos+=length;
|
memPos+=length;
|
||||||
}
|
}
|
||||||
sampleMemLen=memPos+256;
|
sampleMemLen=memPos+256;
|
||||||
|
|
|
@ -249,6 +249,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
||||||
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
|
signed short* sampleMem; // ES5506 uses 16 bit data bus for samples
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
unsigned int sampleOffES5506[256];
|
unsigned int sampleOffES5506[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
struct QueuedHostIntf {
|
struct QueuedHostIntf {
|
||||||
unsigned char state;
|
unsigned char state;
|
||||||
unsigned char step;
|
unsigned char step;
|
||||||
|
@ -335,7 +336,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
|
||||||
virtual const void* getSampleMem(int index = 0) override;
|
virtual const void* getSampleMem(int index = 0) override;
|
||||||
virtual size_t getSampleMemCapacity(int index = 0) override;
|
virtual size_t getSampleMemCapacity(int index = 0) override;
|
||||||
virtual size_t getSampleMemUsage(int index = 0) override;
|
virtual size_t getSampleMemUsage(int index = 0) override;
|
||||||
virtual void renderSamples() override;
|
virtual bool isSampleLoaded(int index, int sample) override;
|
||||||
|
virtual void renderSamples(int sysID) override;
|
||||||
virtual const char** getRegisterSheet() override;
|
virtual const char** getRegisterSheet() override;
|
||||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||||
virtual void quit() override;
|
virtual void quit() override;
|
||||||
|
|
|
@ -362,8 +362,15 @@ size_t DivPlatformMSM6258::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? adpcmMemLen : 0;
|
return index == 0 ? adpcmMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6258::renderSamples() {
|
bool DivPlatformMSM6258::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformMSM6258::renderSamples(int sysID) {
|
||||||
memset(adpcmMem,0,getSampleMemCapacity(0));
|
memset(adpcmMem,0,getSampleMemCapacity(0));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
// sample data
|
// sample data
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
|
@ -371,6 +378,8 @@ void DivPlatformMSM6258::renderSamples() {
|
||||||
if (sampleCount>128) sampleCount=128;
|
if (sampleCount>128) sampleCount=128;
|
||||||
for (int i=0; i<sampleCount; i++) {
|
for (int i=0; i<sampleCount; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) continue;
|
||||||
|
|
||||||
int paddedLen=s->lengthVOX;
|
int paddedLen=s->lengthVOX;
|
||||||
if (memPos>=getSampleMemCapacity(0)) {
|
if (memPos>=getSampleMemCapacity(0)) {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
|
@ -381,6 +390,7 @@ void DivPlatformMSM6258::renderSamples() {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ class DivPlatformMSM6258: public DivDispatch {
|
||||||
|
|
||||||
unsigned char* adpcmMem;
|
unsigned char* adpcmMem;
|
||||||
size_t adpcmMemLen;
|
size_t adpcmMemLen;
|
||||||
|
bool sampleLoaded[256];
|
||||||
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
|
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
|
||||||
signed char msmDividerCount, msmClockCount;
|
signed char msmDividerCount, msmClockCount;
|
||||||
short msmOut;
|
short msmOut;
|
||||||
|
@ -113,7 +114,8 @@ class DivPlatformMSM6258: public DivDispatch {
|
||||||
const void* getSampleMem(int index);
|
const void* getSampleMem(int index);
|
||||||
size_t getSampleMemCapacity(int index);
|
size_t getSampleMemCapacity(int index);
|
||||||
size_t getSampleMemUsage(int index);
|
size_t getSampleMemUsage(int index);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
|
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
|
|
|
@ -335,11 +335,18 @@ size_t DivPlatformMSM6295::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? adpcmMemLen : 0;
|
return index == 0 ? adpcmMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6295::renderSamples() {
|
bool DivPlatformMSM6295::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformMSM6295::renderSamples(int sysID) {
|
||||||
unsigned int sampleOffVOX[256];
|
unsigned int sampleOffVOX[256];
|
||||||
|
|
||||||
memset(adpcmMem,0,getSampleMemCapacity(0));
|
memset(adpcmMem,0,getSampleMemCapacity(0));
|
||||||
memset(sampleOffVOX,0,256*sizeof(unsigned int));
|
memset(sampleOffVOX,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
// sample data
|
// sample data
|
||||||
size_t memPos=128*8;
|
size_t memPos=128*8;
|
||||||
|
@ -347,6 +354,11 @@ void DivPlatformMSM6295::renderSamples() {
|
||||||
if (sampleCount>128) sampleCount=128;
|
if (sampleCount>128) sampleCount=128;
|
||||||
for (int i=0; i<sampleCount; i++) {
|
for (int i=0; i<sampleCount; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffVOX[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=s->lengthVOX;
|
int paddedLen=s->lengthVOX;
|
||||||
if (memPos>=getSampleMemCapacity(0)) {
|
if (memPos>=getSampleMemCapacity(0)) {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
|
@ -357,6 +369,7 @@ void DivPlatformMSM6295::renderSamples() {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
memcpy(adpcmMem+memPos,s->dataVOX,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffVOX[i]=memPos;
|
sampleOffVOX[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -68,6 +68,7 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
|
|
||||||
unsigned char* adpcmMem;
|
unsigned char* adpcmMem;
|
||||||
size_t adpcmMemLen;
|
size_t adpcmMemLen;
|
||||||
|
bool sampleLoaded[256];
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
|
||||||
int delay, updateOsc;
|
int delay, updateOsc;
|
||||||
|
@ -101,7 +102,8 @@ class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
virtual const void* getSampleMem(int index) override;
|
virtual const void* getSampleMem(int index) override;
|
||||||
virtual size_t getSampleMemCapacity(int index) override;
|
virtual size_t getSampleMemCapacity(int index) override;
|
||||||
virtual size_t getSampleMemUsage(int index) override;
|
virtual size_t getSampleMemUsage(int index) override;
|
||||||
virtual void renderSamples() override;
|
virtual bool isSampleLoaded(int index, int sample) override;
|
||||||
|
virtual void renderSamples(int chipID) override;
|
||||||
|
|
||||||
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
virtual int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) override;
|
||||||
virtual void quit() override;
|
virtual void quit() override;
|
||||||
|
|
|
@ -721,12 +721,24 @@ size_t DivPlatformNES::getSampleMemUsage(int index) {
|
||||||
return index==0?dpcmMemLen:0;
|
return index==0?dpcmMemLen:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformNES::renderSamples() {
|
bool DivPlatformNES::isSampleLoaded(int index, int sample) {
|
||||||
memset(dpcmMem,0,getSampleMemCapacity(0));
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformNES::renderSamples(int sysID) {
|
||||||
|
memset(dpcmMem,0,getSampleMemCapacity(0));\
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffDPCM[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int paddedLen=(s->lengthDPCM+63)&(~0x3f);
|
unsigned int paddedLen=(s->lengthDPCM+63)&(~0x3f);
|
||||||
logV("%d padded length: %d",i,paddedLen);
|
logV("%d padded length: %d",i,paddedLen);
|
||||||
if ((memPos&(~0x3fff))!=((memPos+paddedLen)&(~0x3fff))) {
|
if ((memPos&(~0x3fff))!=((memPos+paddedLen)&(~0x3fff))) {
|
||||||
|
@ -744,6 +756,7 @@ void DivPlatformNES::renderSamples() {
|
||||||
logW("out of DPCM memory for sample %d!",i);
|
logW("out of DPCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(dpcmMem+memPos,s->dataDPCM,MIN(s->lengthDPCM,paddedLen));
|
memcpy(dpcmMem+memPos,s->dataDPCM,MIN(s->lengthDPCM,paddedLen));
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffDPCM[i]=memPos;
|
sampleOffDPCM[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -68,6 +68,7 @@ class DivPlatformNES: public DivDispatch {
|
||||||
int dacSample;
|
int dacSample;
|
||||||
unsigned char* dpcmMem;
|
unsigned char* dpcmMem;
|
||||||
size_t dpcmMemLen;
|
size_t dpcmMemLen;
|
||||||
|
bool sampleLoaded[256];
|
||||||
unsigned char dpcmBank;
|
unsigned char dpcmBank;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
unsigned char writeOscBuf;
|
unsigned char writeOscBuf;
|
||||||
|
@ -115,7 +116,8 @@ class DivPlatformNES: public DivDispatch {
|
||||||
const void* getSampleMem(int index);
|
const void* getSampleMem(int index);
|
||||||
size_t getSampleMemCapacity(int index);
|
size_t getSampleMemCapacity(int index);
|
||||||
size_t getSampleMemUsage(int index);
|
size_t getSampleMemUsage(int index);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformNES();
|
~DivPlatformNES();
|
||||||
|
|
|
@ -1757,14 +1757,26 @@ size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
||||||
return (index==0 && adpcmChan>=0) ? adpcmBMemLen : 0;
|
return (index==0 && adpcmChan>=0) ? adpcmBMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::renderSamples() {
|
bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformOPL::renderSamples(int sysID) {
|
||||||
if (adpcmChan<0) return;
|
if (adpcmChan<0) return;
|
||||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffB[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
memPos=(memPos+0xfffff)&0xf00000;
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
|
@ -1778,6 +1790,7 @@ void DivPlatformOPL::renderSamples() {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffB[i]=memPos;
|
sampleOffB[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -91,6 +91,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
size_t adpcmBMemLen;
|
size_t adpcmBMemLen;
|
||||||
DivOPLAInterface iface;
|
DivOPLAInterface iface;
|
||||||
unsigned int sampleOffB[256];
|
unsigned int sampleOffB[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
ymfm::adpcm_b_engine* adpcmB;
|
ymfm::adpcm_b_engine* adpcmB;
|
||||||
const unsigned char** slotsNonDrums;
|
const unsigned char** slotsNonDrums;
|
||||||
|
@ -152,7 +153,8 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
const void* getSampleMem(int index);
|
const void* getSampleMem(int index);
|
||||||
size_t getSampleMemCapacity(int index);
|
size_t getSampleMemCapacity(int index);
|
||||||
size_t getSampleMemUsage(int index);
|
size_t getSampleMemUsage(int index);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformOPL();
|
~DivPlatformOPL();
|
||||||
|
|
|
@ -247,7 +247,7 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
||||||
if (chan[i].freq>65535) chan[i].freq=65535;
|
if (chan[i].freq>65535) chan[i].freq=65535;
|
||||||
int freqt=toFreq(chan[i].freq);
|
int freqt=toFreq(chan[i].freq);
|
||||||
chan[i].freqL=freqt&0xff;
|
chan[i].freqL=freqt&0xff;
|
||||||
if (i>=6 && properDrums) {
|
if (i>=6 && properDrums && (i<9 || !noTopHatFreq)) {
|
||||||
immWrite(0x10+drumSlot[i],freqt&0xff);
|
immWrite(0x10+drumSlot[i],freqt&0xff);
|
||||||
immWrite(0x20+drumSlot[i],freqt>>8);
|
immWrite(0x20+drumSlot[i],freqt>>8);
|
||||||
} else if (i<6 || !drums) {
|
} else if (i<6 || !drums) {
|
||||||
|
@ -963,6 +963,7 @@ void DivPlatformOPLL::setFlags(const DivConfig& flags) {
|
||||||
for (int i=0; i<11; i++) {
|
for (int i=0; i<11; i++) {
|
||||||
oscBuf[i]->rate=rate/2;
|
oscBuf[i]->rate=rate/2;
|
||||||
}
|
}
|
||||||
|
noTopHatFreq=flags.getBool("noTopHatFreq",false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ class DivPlatformOPLL: public DivDispatch {
|
||||||
|
|
||||||
bool useYMFM;
|
bool useYMFM;
|
||||||
bool drums;
|
bool drums;
|
||||||
bool properDrums, properDrumsSys;
|
bool properDrums, properDrumsSys, noTopHatFreq;
|
||||||
bool vrc7;
|
bool vrc7;
|
||||||
|
|
||||||
unsigned char patchSet;
|
unsigned char patchSet;
|
||||||
|
|
|
@ -252,6 +252,11 @@ void DivPlatformPCE::tick(bool sysTick) {
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (updateLFO) {
|
||||||
|
rWrite(0x08,lfoSpeed);
|
||||||
|
rWrite(0x09,lfoMode);
|
||||||
|
updateLFO=false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformPCE::dispatch(DivCommand c) {
|
int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
|
@ -389,13 +394,11 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
||||||
} else {
|
} else {
|
||||||
lfoMode=c.value;
|
lfoMode=c.value;
|
||||||
}
|
}
|
||||||
rWrite(0x08,lfoSpeed);
|
updateLFO=true;
|
||||||
rWrite(0x09,lfoMode);
|
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PCE_LFO_SPEED:
|
case DIV_CMD_PCE_LFO_SPEED:
|
||||||
lfoSpeed=255-c.value;
|
lfoSpeed=255-c.value;
|
||||||
rWrite(0x08,lfoSpeed);
|
updateLFO=true;
|
||||||
rWrite(0x09,lfoMode);
|
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
int destFreq=NOTE_PERIODIC(c.value2);
|
int destFreq=NOTE_PERIODIC(c.value2);
|
||||||
|
@ -525,8 +528,7 @@ void DivPlatformPCE::reset() {
|
||||||
rWrite(0,0);
|
rWrite(0,0);
|
||||||
rWrite(0x01,0xff);
|
rWrite(0x01,0xff);
|
||||||
// set LFO
|
// set LFO
|
||||||
rWrite(0x08,lfoSpeed);
|
updateLFO=true;
|
||||||
rWrite(0x09,lfoMode);
|
|
||||||
// set per-channel initial panning
|
// set per-channel initial panning
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
|
chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
|
||||||
|
@ -588,6 +590,7 @@ int DivPlatformPCE::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
||||||
parent=p;
|
parent=p;
|
||||||
dumpWrites=false;
|
dumpWrites=false;
|
||||||
skipRegisterWrites=false;
|
skipRegisterWrites=false;
|
||||||
|
updateLFO=false;
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
isMuted[i]=false;
|
isMuted[i]=false;
|
||||||
oscBuf[i]=new DivDispatchOscBuffer;
|
oscBuf[i]=new DivDispatchOscBuffer;
|
||||||
|
|
|
@ -76,6 +76,7 @@ class DivPlatformPCE: public DivDispatch {
|
||||||
DivDispatchOscBuffer* oscBuf[6];
|
DivDispatchOscBuffer* oscBuf[6];
|
||||||
bool isMuted[6];
|
bool isMuted[6];
|
||||||
bool antiClickEnabled;
|
bool antiClickEnabled;
|
||||||
|
bool updateLFO;
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned char addr;
|
unsigned char addr;
|
||||||
unsigned char val;
|
unsigned char val;
|
||||||
|
|
|
@ -644,13 +644,25 @@ size_t DivPlatformQSound::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index == 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DivPlatformQSound::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: ADPCM... come on...
|
// TODO: ADPCM... come on...
|
||||||
void DivPlatformQSound::renderSamples() {
|
void DivPlatformQSound::renderSamples(int sysID) {
|
||||||
memset(sampleMem,0,getSampleMemCapacity());
|
memset(sampleMem,0,getSampleMemCapacity());
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
offPCM[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int length=s->length8;
|
int length=s->length8;
|
||||||
if (length>65536-16) {
|
if (length>65536-16) {
|
||||||
length=65536-16;
|
length=65536-16;
|
||||||
|
@ -671,6 +683,7 @@ void DivPlatformQSound::renderSamples() {
|
||||||
for (int i=0; i<length; i++) {
|
for (int i=0; i<length; i++) {
|
||||||
sampleMem[(memPos+i)^0x8000]=s->data8[i];
|
sampleMem[(memPos+i)^0x8000]=s->data8[i];
|
||||||
}
|
}
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
offPCM[i]=memPos^0x8000;
|
offPCM[i]=memPos^0x8000;
|
||||||
memPos+=length+16;
|
memPos+=length+16;
|
||||||
|
|
|
@ -69,6 +69,7 @@ class DivPlatformQSound: public DivDispatch {
|
||||||
|
|
||||||
unsigned char* sampleMem;
|
unsigned char* sampleMem;
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
|
bool sampleLoaded[256];
|
||||||
struct qsound_chip chip;
|
struct qsound_chip chip;
|
||||||
unsigned short regPool[512];
|
unsigned short regPool[512];
|
||||||
|
|
||||||
|
@ -103,7 +104,8 @@ class DivPlatformQSound: public DivDispatch {
|
||||||
const void* getSampleMem(int index = 0);
|
const void* getSampleMem(int index = 0);
|
||||||
size_t getSampleMemCapacity(int index = 0);
|
size_t getSampleMemCapacity(int index = 0);
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
};
|
};
|
||||||
|
|
|
@ -385,13 +385,25 @@ size_t DivPlatformRF5C68::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index == 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformRF5C68::renderSamples() {
|
bool DivPlatformRF5C68::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformRF5C68::renderSamples(int sysID) {
|
||||||
memset(sampleMem,0,getSampleMemCapacity());
|
memset(sampleMem,0,getSampleMemCapacity());
|
||||||
memset(sampleOffRFC,0,256*sizeof(unsigned int));
|
memset(sampleOffRFC,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffRFC[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
int length=s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT);
|
||||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)-31,length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
|
@ -412,6 +424,7 @@ void DivPlatformRF5C68::renderSamples() {
|
||||||
}
|
}
|
||||||
// align memPos to 256-byte boundary
|
// align memPos to 256-byte boundary
|
||||||
memPos=(memPos+0xff)&~0xff;
|
memPos=(memPos+0xff)&~0xff;
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleMemLen=memPos;
|
sampleMemLen=memPos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ class DivPlatformRF5C68: public DivDispatch {
|
||||||
int chipType;
|
int chipType;
|
||||||
unsigned char curChan;
|
unsigned char curChan;
|
||||||
unsigned int sampleOffRFC[256];
|
unsigned int sampleOffRFC[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
unsigned char* sampleMem;
|
unsigned char* sampleMem;
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
|
@ -99,7 +100,8 @@ class DivPlatformRF5C68: public DivDispatch {
|
||||||
const void* getSampleMem(int index = 0);
|
const void* getSampleMem(int index = 0);
|
||||||
size_t getSampleMemCapacity(int index = 0);
|
size_t getSampleMemCapacity(int index = 0);
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -71,10 +71,17 @@ void DivPlatformSAA1099::acquire_saaSound(short* bufL, short* bufR, size_t start
|
||||||
writes.pop();
|
writes.pop();
|
||||||
}
|
}
|
||||||
saa_saaSound->GenerateMany((unsigned char*)saaBuf[0],len,oscBuf);
|
saa_saaSound->GenerateMany((unsigned char*)saaBuf[0],len,oscBuf);
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
for (size_t i=0; i<len; i++) {
|
||||||
|
bufL[i+start]=(short)((((unsigned short)saaBuf[0][1+(i<<1)])<<8)|(((unsigned short)saaBuf[0][1+(i<<1)])>>8));
|
||||||
|
bufR[i+start]=(short)((((unsigned short)saaBuf[0][i<<1])<<8)|(((unsigned short)saaBuf[0][i<<1])>>8));
|
||||||
|
}
|
||||||
|
#else
|
||||||
for (size_t i=0; i<len; i++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
bufL[i+start]=saaBuf[0][i<<1];
|
bufL[i+start]=saaBuf[0][i<<1];
|
||||||
bufR[i+start]=saaBuf[0][1+(i<<1)];
|
bufR[i+start]=saaBuf[0][1+(i<<1)];
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSAA1099::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformSAA1099::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
|
|
|
@ -451,7 +451,7 @@ void DivPlatformSegaPCM::reset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSegaPCM::renderSamples() {
|
void DivPlatformSegaPCM::renderSamples(int sysID) {
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
|
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
|
|
|
@ -110,7 +110,7 @@ class DivPlatformSegaPCM: public DivDispatch {
|
||||||
void tick(bool sysTick=true);
|
void tick(bool sysTick=true);
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void renderSamples();
|
void renderSamples(int chipID);
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
bool isStereo();
|
bool isStereo();
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
|
|
|
@ -119,10 +119,29 @@ void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DivPlatformSMS::NOTE_SN(int ch, int note) {
|
||||||
|
double CHIP_DIVIDER=toneDivider;
|
||||||
|
if (ch==3) CHIP_DIVIDER=noiseDivider;
|
||||||
|
if (parent->song.linearPitch==2 || !easyNoise) {
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
if (note>easyThreshold) {
|
||||||
|
return MAX(0,easyStartingPeriod-(note-easyThreshold));
|
||||||
|
}
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DivPlatformSMS::snCalcFreq(int ch) {
|
||||||
|
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(easyThreshold<<7)) {
|
||||||
|
int ret=(((easyStartingPeriod<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(easyThreshold<<7)))>>7;
|
||||||
|
if (ret<0) ret=0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return parent->calcFreq(chan[ch].baseFreq,chan[ch].pitch,true,0,chan[ch].pitch2,chipClock,ch==3?noiseDivider:toneDivider);
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformSMS::tick(bool sysTick) {
|
void DivPlatformSMS::tick(bool sysTick) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
double CHIP_DIVIDER=toneDivider;
|
|
||||||
if (i==3) CHIP_DIVIDER=noiseDivider;
|
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].std.vol.val,chan[i].vol,15);
|
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].std.vol.val,chan[i].vol,15);
|
||||||
|
@ -137,7 +156,7 @@ void DivPlatformSMS::tick(bool sysTick) {
|
||||||
// TODO: add compatibility flag. this is horrible.
|
// TODO: add compatibility flag. this is horrible.
|
||||||
int areYouSerious=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
int areYouSerious=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||||
while (areYouSerious>0x60) areYouSerious-=12;
|
while (areYouSerious>0x60) areYouSerious-=12;
|
||||||
chan[i].baseFreq=NOTE_PERIODIC(areYouSerious);
|
chan[i].baseFreq=NOTE_SN(i,areYouSerious);
|
||||||
chan[i].actualNote=areYouSerious;
|
chan[i].actualNote=areYouSerious;
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +196,7 @@ void DivPlatformSMS::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider);
|
chan[i].freq=snCalcFreq(i);
|
||||||
if (chan[i].freq>1023) chan[i].freq=1023;
|
if (chan[i].freq>1023) chan[i].freq=1023;
|
||||||
if (parent->song.snNoLowPeriods) {
|
if (parent->song.snNoLowPeriods) {
|
||||||
if (chan[i].freq<8) chan[i].freq=1;
|
if (chan[i].freq<8) chan[i].freq=1;
|
||||||
|
@ -196,7 +215,8 @@ void DivPlatformSMS::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (chan[3].freqChanged || updateSNMode) {
|
if (chan[3].freqChanged || updateSNMode) {
|
||||||
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider);
|
chan[3].freq=snCalcFreq(3);
|
||||||
|
//parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider);
|
||||||
if (chan[3].freq>1023) chan[3].freq=1023;
|
if (chan[3].freq>1023) chan[3].freq=1023;
|
||||||
if (parent->song.snNoLowPeriods) {
|
if (parent->song.snNoLowPeriods) {
|
||||||
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
|
||||||
|
@ -244,12 +264,10 @@ void DivPlatformSMS::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformSMS::dispatch(DivCommand c) {
|
int DivPlatformSMS::dispatch(DivCommand c) {
|
||||||
double CHIP_DIVIDER=toneDivider;
|
|
||||||
if (c.chan==3) CHIP_DIVIDER=noiseDivider;
|
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON:
|
case DIV_CMD_NOTE_ON:
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].actualNote=c.value;
|
chan[c.chan].actualNote=c.value;
|
||||||
|
@ -300,7 +318,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
int destFreq=NOTE_PERIODIC(c.value2);
|
int destFreq=NOTE_SN(c.chan,c.value2);
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
chan[c.chan].baseFreq+=c.value;
|
chan[c.chan].baseFreq+=c.value;
|
||||||
|
@ -340,7 +358,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_LEGATO:
|
case DIV_CMD_LEGATO:
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].actualNote=c.value;
|
chan[c.chan].actualNote=c.value;
|
||||||
|
@ -349,7 +367,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].active && c.value2) {
|
if (chan[c.chan].active && c.value2) {
|
||||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
|
||||||
}
|
}
|
||||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
|
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
|
||||||
chan[c.chan].inPorta=c.value;
|
chan[c.chan].inPorta=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
|
@ -446,27 +464,42 @@ void DivPlatformSMS::setFlags(const DivConfig& flags) {
|
||||||
switch (flags.getInt("clockSel",0)) {
|
switch (flags.getInt("clockSel",0)) {
|
||||||
case 1:
|
case 1:
|
||||||
chipClock=COLOR_PAL*4.0/5.0;
|
chipClock=COLOR_PAL*4.0/5.0;
|
||||||
|
easyThreshold=84;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
chipClock=4000000;
|
chipClock=4000000;
|
||||||
|
easyThreshold=86;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
chipClock=COLOR_NTSC/2.0;
|
chipClock=COLOR_NTSC/2.0;
|
||||||
|
easyThreshold=72;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
chipClock=3000000;
|
chipClock=3000000;
|
||||||
|
easyThreshold=81;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
chipClock=2000000;
|
chipClock=2000000;
|
||||||
|
easyThreshold=74;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
chipClock=COLOR_NTSC/8.0;
|
chipClock=COLOR_NTSC/8.0;
|
||||||
|
easyThreshold=48;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
chipClock=COLOR_NTSC;
|
chipClock=COLOR_NTSC;
|
||||||
|
easyThreshold=84;
|
||||||
|
easyStartingPeriod=13;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resetPhase=!flags.getBool("noPhaseReset",false);
|
resetPhase=!flags.getBool("noPhaseReset",false);
|
||||||
|
easyNoise=!flags.getBool("noEasyNoise",false);
|
||||||
divider=16;
|
divider=16;
|
||||||
toneDivider=64.0;
|
toneDivider=64.0;
|
||||||
noiseDivider=64.0;
|
noiseDivider=64.0;
|
||||||
|
|
|
@ -65,11 +65,14 @@ class DivPlatformSMS: public DivDispatch {
|
||||||
int divider=16;
|
int divider=16;
|
||||||
double toneDivider=64.0;
|
double toneDivider=64.0;
|
||||||
double noiseDivider=64.0;
|
double noiseDivider=64.0;
|
||||||
|
int easyThreshold;
|
||||||
|
int easyStartingPeriod;
|
||||||
bool updateSNMode;
|
bool updateSNMode;
|
||||||
bool resetPhase;
|
bool resetPhase;
|
||||||
bool isRealSN;
|
bool isRealSN;
|
||||||
bool stereo;
|
bool stereo;
|
||||||
bool nuked;
|
bool nuked;
|
||||||
|
bool easyNoise;
|
||||||
sn76496_base_device* sn;
|
sn76496_base_device* sn;
|
||||||
ympsg_t sn_nuked;
|
ympsg_t sn_nuked;
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
|
@ -82,6 +85,9 @@ class DivPlatformSMS: public DivDispatch {
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
double NOTE_SN(int ch, int note);
|
||||||
|
int snCalcFreq(int ch);
|
||||||
|
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
void acquire_mame(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_mame(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -797,14 +797,26 @@ size_t DivPlatformSNES::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index == 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSNES::renderSamples() {
|
bool DivPlatformSNES::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformSNES::renderSamples(int sysID) {
|
||||||
memset(copyOfSampleMem,0,getSampleMemCapacity());
|
memset(copyOfSampleMem,0,getSampleMemCapacity());
|
||||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
// skip past sample table and wavetable buffer
|
// skip past sample table and wavetable buffer
|
||||||
size_t memPos=sampleTableBase+8*4+8*9*16;
|
size_t memPos=sampleTableBase+8*4+8*9*16;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOff[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int length=s->lengthBRR;
|
int length=s->lengthBRR;
|
||||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos)/9*9,length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
|
@ -822,6 +834,7 @@ void DivPlatformSNES::renderSamples() {
|
||||||
logW("out of BRR memory for sample %d!",i);
|
logW("out of BRR memory for sample %d!",i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleMemLen=memPos;
|
sampleMemLen=memPos;
|
||||||
memcpy(sampleMem,copyOfSampleMem,65536);
|
memcpy(sampleMem,copyOfSampleMem,65536);
|
||||||
|
|
|
@ -109,6 +109,7 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
signed char copyOfSampleMem[65536];
|
signed char copyOfSampleMem[65536];
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
unsigned int sampleOff[256];
|
unsigned int sampleOff[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
unsigned char regPool[0x80];
|
unsigned char regPool[0x80];
|
||||||
SPC_DSP dsp;
|
SPC_DSP dsp;
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
@ -136,7 +137,8 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
const void* getSampleMem(int index = 0);
|
const void* getSampleMem(int index = 0);
|
||||||
size_t getSampleMemCapacity(int index = 0);
|
size_t getSampleMemCapacity(int index = 0);
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -391,7 +391,18 @@ void SoundUnit::Reset() {
|
||||||
memset(chan,0,sizeof(SUChannel)*8);
|
memset(chan,0,sizeof(SUChannel)*8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
const unsigned char suBERemap[32]={
|
||||||
|
0x01, 0x00, 0x02, 0x03, 0x05, 0x04, 0x07, 0x06, 0x08, 0x09, 0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e,
|
||||||
|
0x11, 0x10, 0x12, 0x13, 0x15, 0x14, 0x16, 0x17, 0x19, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f, 0x1e
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
void SoundUnit::Write(unsigned char addr, unsigned char data) {
|
void SoundUnit::Write(unsigned char addr, unsigned char data) {
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
// remap
|
||||||
|
addr=(addr&0xe0)|(suBERemap[addr&0x1f]);
|
||||||
|
#endif
|
||||||
((unsigned char*)chan)[addr]=data;
|
((unsigned char*)chan)[addr]=data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,6 +286,8 @@ int ymz280b_device::generate_pcm8(struct YMZ280BVoice *voice, s16 *buffer, int s
|
||||||
|
|
||||||
***********************************************************************************************/
|
***********************************************************************************************/
|
||||||
|
|
||||||
|
// according to this core, it should be little-endian.
|
||||||
|
// but it's big-endian in VGMPlay...
|
||||||
int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int samples)
|
int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int samples)
|
||||||
{
|
{
|
||||||
u32 position = voice->position;
|
u32 position = voice->position;
|
||||||
|
@ -298,7 +300,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int
|
||||||
while (samples)
|
while (samples)
|
||||||
{
|
{
|
||||||
/* fetch the current value */
|
/* fetch the current value */
|
||||||
val = (s16)((m_ext_mem[position / 2 + 1] << 8) + m_ext_mem[position / 2 + 0]);
|
val = (s16)((m_ext_mem[position / 2 + 0] << 8) + m_ext_mem[position / 2 + 1]);
|
||||||
|
|
||||||
/* output to the buffer, scaling by the volume */
|
/* output to the buffer, scaling by the volume */
|
||||||
*buffer++ = val;
|
*buffer++ = val;
|
||||||
|
@ -321,7 +323,7 @@ int ymz280b_device::generate_pcm16(struct YMZ280BVoice *voice, s16 *buffer, int
|
||||||
while (samples)
|
while (samples)
|
||||||
{
|
{
|
||||||
/* fetch the current value */
|
/* fetch the current value */
|
||||||
val = (s16)((m_ext_mem[position / 2 + 1] << 8) + m_ext_mem[position / 2 + 0]);
|
val = (s16)((m_ext_mem[position / 2 + 0] << 8) + m_ext_mem[position / 2 + 1]);
|
||||||
|
|
||||||
/* output to the buffer, scaling by the volume */
|
/* output to the buffer, scaling by the volume */
|
||||||
*buffer++ = val;
|
*buffer++ = val;
|
||||||
|
|
|
@ -524,7 +524,7 @@ void DivPlatformSoundUnit::setFlags(const DivConfig& flags) {
|
||||||
sampleMemSize=flags.getInt("sampleMemSize",0);
|
sampleMemSize=flags.getInt("sampleMemSize",0);
|
||||||
|
|
||||||
su->Init(sampleMemSize?65536:8192,flags.getBool("pdm",false));
|
su->Init(sampleMemSize?65536:8192,flags.getBool("pdm",false));
|
||||||
renderSamples();
|
renderSamples(sysIDCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) {
|
void DivPlatformSoundUnit::poke(unsigned int addr, unsigned short val) {
|
||||||
|
@ -547,14 +547,26 @@ size_t DivPlatformSoundUnit::getSampleMemUsage(int index) {
|
||||||
return (index==0)?sampleMemLen:0;
|
return (index==0)?sampleMemLen:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSoundUnit::renderSamples() {
|
bool DivPlatformSoundUnit::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformSoundUnit::renderSamples(int sysID) {
|
||||||
memset(su->pcm,0,getSampleMemCapacity(0));
|
memset(su->pcm,0,getSampleMemCapacity(0));
|
||||||
memset(sampleOffSU,0,256*sizeof(unsigned int));
|
memset(sampleOffSU,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
if (s->data8==NULL) continue;
|
if (s->data8==NULL) continue;
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffSU[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=s->length8;
|
int paddedLen=s->length8;
|
||||||
if (memPos>=getSampleMemCapacity(0)) {
|
if (memPos>=getSampleMemCapacity(0)) {
|
||||||
logW("out of PCM memory for sample %d!",i);
|
logW("out of PCM memory for sample %d!",i);
|
||||||
|
@ -565,12 +577,13 @@ void DivPlatformSoundUnit::renderSamples() {
|
||||||
logW("out of PCM memory for sample %d!",i);
|
logW("out of PCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(su->pcm+memPos,s->data8,paddedLen);
|
memcpy(su->pcm+memPos,s->data8,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffSU[i]=memPos;
|
sampleOffSU[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
}
|
}
|
||||||
sampleMemLen=memPos;
|
sampleMemLen=memPos;
|
||||||
|
sysIDCache=sysID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||||
|
@ -582,6 +595,7 @@ int DivPlatformSoundUnit::init(DivEngine* p, int channels, int sugRate, const Di
|
||||||
oscBuf[i]=new DivDispatchOscBuffer;
|
oscBuf[i]=new DivDispatchOscBuffer;
|
||||||
}
|
}
|
||||||
su=new SoundUnit();
|
su=new SoundUnit();
|
||||||
|
sysIDCache=0;
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
reset();
|
reset();
|
||||||
return 8;
|
return 8;
|
||||||
|
|
|
@ -102,8 +102,9 @@ class DivPlatformSoundUnit: public DivDispatch {
|
||||||
unsigned char initIlCtrl, initIlSize, initFil1;
|
unsigned char initIlCtrl, initIlSize, initFil1;
|
||||||
signed char echoVol, initEchoVol;
|
signed char echoVol, initEchoVol;
|
||||||
unsigned int sampleOffSU[256];
|
unsigned int sampleOffSU[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
int cycles, curChan, delay;
|
int cycles, curChan, delay, sysIDCache;
|
||||||
short tempL;
|
short tempL;
|
||||||
short tempR;
|
short tempR;
|
||||||
unsigned char sampleBank, lfoMode, lfoSpeed;
|
unsigned char sampleBank, lfoMode, lfoSpeed;
|
||||||
|
@ -138,7 +139,8 @@ class DivPlatformSoundUnit: public DivDispatch {
|
||||||
const void* getSampleMem(int index);
|
const void* getSampleMem(int index);
|
||||||
size_t getSampleMemCapacity(int index);
|
size_t getSampleMemCapacity(int index);
|
||||||
size_t getSampleMemUsage(int index);
|
size_t getSampleMemUsage(int index);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformSoundUnit();
|
~DivPlatformSoundUnit();
|
||||||
|
|
|
@ -81,10 +81,29 @@ void DivPlatformT6W28::writeOutVol(int ch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double DivPlatformT6W28::NOTE_SN(int ch, int note) {
|
||||||
|
double CHIP_DIVIDER=16;
|
||||||
|
if (ch==3) CHIP_DIVIDER=15;
|
||||||
|
if (parent->song.linearPitch==2 || !easyNoise) {
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
if (note>107) {
|
||||||
|
return MAX(0,13-(note-107));
|
||||||
|
}
|
||||||
|
return NOTE_PERIODIC(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DivPlatformT6W28::snCalcFreq(int ch) {
|
||||||
|
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(107<<7)) {
|
||||||
|
int ret=(((13<<7)+0x40)-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(107<<7)))>>7;
|
||||||
|
if (ret<0) ret=0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return parent->calcFreq(chan[ch].baseFreq,chan[ch].pitch,true,0,chan[ch].pitch2,chipClock,ch==3?15:16);
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformT6W28::tick(bool sysTick) {
|
void DivPlatformT6W28::tick(bool sysTick) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
double CHIP_DIVIDER=16;
|
|
||||||
if (i==3) CHIP_DIVIDER=15;
|
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol&15,MIN(15,chan[i].std.vol.val),15);
|
||||||
|
@ -92,7 +111,7 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
if (!chan[i].inPorta) {
|
if (!chan[i].inPorta) {
|
||||||
int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
int noiseSeek=parent->calcArp(chan[i].note,chan[i].std.arp.val);
|
||||||
chan[i].baseFreq=NOTE_PERIODIC(noiseSeek);
|
chan[i].baseFreq=NOTE_SN(i,noiseSeek);
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -124,7 +143,7 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
||||||
rWrite(1,0xe0+chan[i].duty);
|
rWrite(1,0xe0+chan[i].duty);
|
||||||
}
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
chan[i].freq=snCalcFreq(i);
|
||||||
if (chan[i].freq>1023) chan[i].freq=1023;
|
if (chan[i].freq>1023) chan[i].freq=1023;
|
||||||
if (i==3) {
|
if (i==3) {
|
||||||
rWrite(1,0x80|(2<<5)|(chan[3].freq&15));
|
rWrite(1,0x80|(2<<5)|(chan[3].freq&15));
|
||||||
|
@ -141,13 +160,11 @@ void DivPlatformT6W28::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformT6W28::dispatch(DivCommand c) {
|
int DivPlatformT6W28::dispatch(DivCommand c) {
|
||||||
double CHIP_DIVIDER=16;
|
|
||||||
if (c.chan==3) CHIP_DIVIDER=15;
|
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE);
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
}
|
}
|
||||||
|
@ -197,7 +214,7 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
int destFreq=NOTE_PERIODIC(c.value2);
|
int destFreq=NOTE_SN(c.chan,c.value2);
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
chan[c.chan].baseFreq+=c.value;
|
chan[c.chan].baseFreq+=c.value;
|
||||||
|
@ -231,15 +248,15 @@ int DivPlatformT6W28::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_LEGATO:
|
case DIV_CMD_LEGATO:
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
chan[c.chan].baseFreq=NOTE_SN(c.chan,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PRE_PORTA:
|
case DIV_CMD_PRE_PORTA:
|
||||||
if (chan[c.chan].active && c.value2) {
|
if (chan[c.chan].active && c.value2) {
|
||||||
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
|
if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_T6W28));
|
||||||
}
|
}
|
||||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note);
|
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_SN(c.chan,chan[c.chan].note);
|
||||||
chan[c.chan].inPorta=c.value;
|
chan[c.chan].inPorta=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
|
@ -330,6 +347,7 @@ void DivPlatformT6W28::setFlags(const DivConfig& flags) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
oscBuf[i]->rate=rate;
|
oscBuf[i]->rate=rate;
|
||||||
}
|
}
|
||||||
|
easyNoise=!flags.getBool("noEasyNoise",false);
|
||||||
|
|
||||||
if (t6w!=NULL) {
|
if (t6w!=NULL) {
|
||||||
delete t6w;
|
delete t6w;
|
||||||
|
|
|
@ -60,6 +60,7 @@ class DivPlatformT6W28: public DivDispatch {
|
||||||
DivDispatchOscBuffer* oscBuf[4];
|
DivDispatchOscBuffer* oscBuf[4];
|
||||||
bool isMuted[4];
|
bool isMuted[4];
|
||||||
bool antiClickEnabled;
|
bool antiClickEnabled;
|
||||||
|
bool easyNoise;
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned char addr;
|
unsigned char addr;
|
||||||
unsigned char val;
|
unsigned char val;
|
||||||
|
@ -75,6 +76,10 @@ class DivPlatformT6W28: public DivDispatch {
|
||||||
unsigned char regPool[128];
|
unsigned char regPool[128];
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
double NOTE_SN(int ch, int note);
|
||||||
|
int snCalcFreq(int ch);
|
||||||
|
|
||||||
void writeOutVol(int ch);
|
void writeOutVol(int ch);
|
||||||
public:
|
public:
|
||||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
|
@ -949,13 +949,25 @@ size_t DivPlatformX1_010::getSampleMemUsage(int index) {
|
||||||
return index >= 0 ? sampleMemLen : 0;
|
return index >= 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformX1_010::renderSamples() {
|
bool DivPlatformX1_010::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformX1_010::renderSamples(int sysID) {
|
||||||
memset(sampleMem,0,getSampleMemCapacity());
|
memset(sampleMem,0,getSampleMemCapacity());
|
||||||
memset(sampleOffX1,0,256*sizeof(unsigned int));
|
memset(sampleOffX1,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffX1[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=(s->length8+4095)&(~0xfff);
|
int paddedLen=(s->length8+4095)&(~0xfff);
|
||||||
if (isBanked) {
|
if (isBanked) {
|
||||||
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
// fit sample bank size to 128KB for Seta 2 external bankswitching logic (not emulated yet!)
|
||||||
|
@ -975,6 +987,7 @@ void DivPlatformX1_010::renderSamples() {
|
||||||
logW("out of X1-010 memory for sample %d!",i);
|
logW("out of X1-010 memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(sampleMem+memPos,s->data8,paddedLen);
|
memcpy(sampleMem+memPos,s->data8,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffX1[i]=memPos;
|
sampleOffX1[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -116,6 +116,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
bool isBanked=false;
|
bool isBanked=false;
|
||||||
unsigned int bankSlot[8];
|
unsigned int bankSlot[8];
|
||||||
unsigned int sampleOffX1[256];
|
unsigned int sampleOffX1[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
unsigned char regPool[0x2000];
|
unsigned char regPool[0x2000];
|
||||||
double NoteX1_010(int ch, int note);
|
double NoteX1_010(int ch, int note);
|
||||||
|
@ -146,7 +147,8 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
|
||||||
const void* getSampleMem(int index = 0);
|
const void* getSampleMem(int index = 0);
|
||||||
size_t getSampleMemCapacity(int index = 0);
|
size_t getSampleMemCapacity(int index = 0);
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
void setBanked(bool banked);
|
void setBanked(bool banked);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
|
|
|
@ -1336,13 +1336,25 @@ size_t DivPlatformYM2608::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? adpcmBMemLen : 0;
|
return index == 0 ? adpcmBMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYM2608::renderSamples() {
|
bool DivPlatformYM2608::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformYM2608::renderSamples(int sysID) {
|
||||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
||||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffB[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
memPos=(memPos+0xfffff)&0xf00000;
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
|
@ -1356,6 +1368,7 @@ void DivPlatformYM2608::renderSamples() {
|
||||||
logW("out of ADPCM memory for sample %d!",i);
|
logW("out of ADPCM memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleOffB[i]=memPos;
|
sampleOffB[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -100,6 +100,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
size_t adpcmBMemLen;
|
size_t adpcmBMemLen;
|
||||||
DivYM2608Interface iface;
|
DivYM2608Interface iface;
|
||||||
unsigned int sampleOffB[256];
|
unsigned int sampleOffB[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
DivPlatformAY8910* ay;
|
DivPlatformAY8910* ay;
|
||||||
unsigned char sampleBank;
|
unsigned char sampleBank;
|
||||||
|
@ -137,7 +138,8 @@ class DivPlatformYM2608: public DivPlatformOPN {
|
||||||
const void* getSampleMem(int index);
|
const void* getSampleMem(int index);
|
||||||
size_t getSampleMemCapacity(int index);
|
size_t getSampleMemCapacity(int index);
|
||||||
size_t getSampleMemUsage(int index);
|
size_t getSampleMemUsage(int index);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
|
|
|
@ -143,6 +143,8 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||||
|
|
||||||
bool extMode, noExtMacros;
|
bool extMode, noExtMacros;
|
||||||
|
|
||||||
|
bool sampleLoaded[2][256];
|
||||||
|
|
||||||
unsigned char writeADPCMAOff, writeADPCMAOn;
|
unsigned char writeADPCMAOff, writeADPCMAOn;
|
||||||
int globalADPCMAVolume;
|
int globalADPCMAVolume;
|
||||||
|
|
||||||
|
@ -204,18 +206,34 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||||
return index == 0 ? 16777216 : index == 1 ? 16777216 : 0;
|
return index == 0 ? 16777216 : index == 1 ? 16777216 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* getSampleMemName(int index=0) {
|
||||||
|
return index == 0 ? "ADPCM-A" : index == 1 ? "ADPCM-B" : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
size_t getSampleMemUsage(int index) {
|
size_t getSampleMemUsage(int index) {
|
||||||
return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0;
|
return index == 0 ? adpcmAMemLen : index == 1 ? adpcmBMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSamples() {
|
bool isSampleLoaded(int index, int sample) {
|
||||||
|
if (index<0 || index>1) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[index][sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderSamples(int sysID) {
|
||||||
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
memset(adpcmAMem,0,getSampleMemCapacity(0));
|
||||||
memset(sampleOffA,0,256*sizeof(unsigned int));
|
memset(sampleOffA,0,256*sizeof(unsigned int));
|
||||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*2*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffA[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=(s->lengthA+255)&(~0xff);
|
int paddedLen=(s->lengthA+255)&(~0xff);
|
||||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
memPos=(memPos+0xfffff)&0xf00000;
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
|
@ -229,6 +247,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||||
logW("out of ADPCM-A memory for sample %d!",i);
|
logW("out of ADPCM-A memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
memcpy(adpcmAMem+memPos,s->dataA,paddedLen);
|
||||||
|
sampleLoaded[0][i]=true;
|
||||||
}
|
}
|
||||||
sampleOffA[i]=memPos;
|
sampleOffA[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
@ -240,6 +259,11 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||||
memPos=0;
|
memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[1][sysID]) {
|
||||||
|
sampleOffB[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int paddedLen=(s->lengthB+255)&(~0xff);
|
int paddedLen=(s->lengthB+255)&(~0xff);
|
||||||
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
if ((memPos&0xf00000)!=((memPos+paddedLen)&0xf00000)) {
|
||||||
memPos=(memPos+0xfffff)&0xf00000;
|
memPos=(memPos+0xfffff)&0xf00000;
|
||||||
|
@ -253,6 +277,7 @@ template<int ChanNum> class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||||
logW("out of ADPCM-B memory for sample %d!",i);
|
logW("out of ADPCM-B memory for sample %d!",i);
|
||||||
} else {
|
} else {
|
||||||
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
memcpy(adpcmBMem+memPos,s->dataB,paddedLen);
|
||||||
|
sampleLoaded[1][i]=true;
|
||||||
}
|
}
|
||||||
sampleOffB[i]=memPos;
|
sampleOffB[i]=memPos;
|
||||||
memPos+=paddedLen;
|
memPos+=paddedLen;
|
||||||
|
|
|
@ -420,18 +420,40 @@ size_t DivPlatformYMZ280B::getSampleMemUsage(int index) {
|
||||||
return index == 0 ? sampleMemLen : 0;
|
return index == 0 ? sampleMemLen : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformYMZ280B::renderSamples() {
|
bool DivPlatformYMZ280B::isSampleLoaded(int index, int sample) {
|
||||||
|
if (index!=0) return false;
|
||||||
|
if (sample<0 || sample>255) return false;
|
||||||
|
return sampleLoaded[sample];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivPlatformYMZ280B::renderSamples(int sysID) {
|
||||||
memset(sampleMem,0,getSampleMemCapacity());
|
memset(sampleMem,0,getSampleMemCapacity());
|
||||||
memset(sampleOff,0,256*sizeof(unsigned int));
|
memset(sampleOff,0,256*sizeof(unsigned int));
|
||||||
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOff[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int length=s->getCurBufLen();
|
int length=s->getCurBufLen();
|
||||||
unsigned char* src=(unsigned char*)s->getCurBuf();
|
unsigned char* src=(unsigned char*)s->getCurBuf();
|
||||||
int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length);
|
int actualLength=MIN((int)(getSampleMemCapacity()-memPos),length);
|
||||||
if (actualLength>0) {
|
if (actualLength>0) {
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
memcpy(&sampleMem[memPos],src,actualLength);
|
memcpy(&sampleMem[memPos],src,actualLength);
|
||||||
|
#else
|
||||||
|
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
for (int i=0; i<actualLength; i++) {
|
||||||
|
sampleMem[memPos+i]=src[i^1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&sampleMem[memPos],src,actualLength);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
sampleOff[i]=memPos;
|
sampleOff[i]=memPos;
|
||||||
memPos+=length;
|
memPos+=length;
|
||||||
}
|
}
|
||||||
|
@ -439,6 +461,7 @@ void DivPlatformYMZ280B::renderSamples() {
|
||||||
logW("out of YMZ280B PCM memory for sample %d!",i);
|
logW("out of YMZ280B PCM memory for sample %d!",i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
sampleLoaded[i]=true;
|
||||||
}
|
}
|
||||||
sampleMemLen=memPos;
|
sampleMemLen=memPos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ class DivPlatformYMZ280B: public DivDispatch {
|
||||||
bool isMuted[8];
|
bool isMuted[8];
|
||||||
int chipType;
|
int chipType;
|
||||||
unsigned int sampleOff[256];
|
unsigned int sampleOff[256];
|
||||||
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
unsigned char* sampleMem;
|
unsigned char* sampleMem;
|
||||||
size_t sampleMemLen;
|
size_t sampleMemLen;
|
||||||
|
@ -99,7 +100,8 @@ class DivPlatformYMZ280B: public DivDispatch {
|
||||||
const void* getSampleMem(int index = 0);
|
const void* getSampleMem(int index = 0);
|
||||||
size_t getSampleMemCapacity(int index = 0);
|
size_t getSampleMemCapacity(int index = 0);
|
||||||
size_t getSampleMemUsage(int index = 0);
|
size_t getSampleMemUsage(int index = 0);
|
||||||
void renderSamples();
|
bool isSampleLoaded(int index, int sample);
|
||||||
|
void renderSamples(int chipID);
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||||
void quit();
|
void quit();
|
||||||
|
|
|
@ -39,6 +39,186 @@ DivSampleHistory::~DivSampleHistory() {
|
||||||
if (data!=NULL) delete[] data;
|
if (data!=NULL) delete[] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivSample::putSampleData(SafeWriter* w) {
|
||||||
|
size_t blockStartSeek, blockEndSeek;
|
||||||
|
|
||||||
|
w->write("SMP2",4);
|
||||||
|
blockStartSeek=w->tell();
|
||||||
|
w->writeI(0);
|
||||||
|
|
||||||
|
w->writeString(name,false);
|
||||||
|
w->writeI(samples);
|
||||||
|
w->writeI(rate);
|
||||||
|
w->writeI(centerRate);
|
||||||
|
w->writeC(depth);
|
||||||
|
w->writeC(loopMode);
|
||||||
|
w->writeC(0); // reserved
|
||||||
|
w->writeC(0);
|
||||||
|
w->writeI(loop?loopStart:-1);
|
||||||
|
w->writeI(loop?loopEnd:-1);
|
||||||
|
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
w->writeI(0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
// store 16-bit samples as little-endian
|
||||||
|
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
unsigned char* sampleBuf=(unsigned char*)getCurBuf();
|
||||||
|
size_t bufLen=getCurBufLen();
|
||||||
|
for (size_t i=0; i<bufLen; i+=2) {
|
||||||
|
w->writeC(sampleBuf[i+1]);
|
||||||
|
w->writeC(sampleBuf[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w->write(getCurBuf(),getCurBufLen());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
w->write(getCurBuf(),getCurBufLen());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
blockEndSeek=w->tell();
|
||||||
|
w->seek(blockStartSeek,SEEK_SET);
|
||||||
|
w->writeI(blockEndSeek-blockStartSeek-4);
|
||||||
|
w->seek(0,SEEK_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delek why
|
||||||
|
static double samplePitchesSD[11]={
|
||||||
|
0.1666666666, 0.2, 0.25, 0.333333333, 0.5,
|
||||||
|
1,
|
||||||
|
2, 3, 4, 5, 6
|
||||||
|
};
|
||||||
|
|
||||||
|
DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
|
||||||
|
int vol=0;
|
||||||
|
int pitch=0;
|
||||||
|
char magic[4];
|
||||||
|
|
||||||
|
reader.read(magic,4);
|
||||||
|
if (memcmp(magic,"SMPL",4)!=0 && memcmp(magic,"SMP2",4)!=0) {
|
||||||
|
logV("header is invalid: %c%c%c%c",magic[0],magic[1],magic[2],magic[3]);
|
||||||
|
return DIV_DATA_INVALID_HEADER;
|
||||||
|
}
|
||||||
|
bool isNewSample=(memcmp(magic,"SMP2",4)==0);
|
||||||
|
reader.readI();
|
||||||
|
if (!isNewSample) logV("(old sample)");
|
||||||
|
|
||||||
|
name=reader.readString();
|
||||||
|
samples=reader.readI();
|
||||||
|
if (!isNewSample) {
|
||||||
|
loopEnd=samples;
|
||||||
|
}
|
||||||
|
rate=reader.readI();
|
||||||
|
|
||||||
|
if (isNewSample) {
|
||||||
|
centerRate=reader.readI();
|
||||||
|
depth=(DivSampleDepth)reader.readC();
|
||||||
|
if (version>=123) {
|
||||||
|
loopMode=(DivSampleLoopMode)reader.readC();
|
||||||
|
} else {
|
||||||
|
loopMode=DIV_SAMPLE_LOOP_FORWARD;
|
||||||
|
reader.readC();
|
||||||
|
}
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
reader.readC();
|
||||||
|
reader.readC();
|
||||||
|
|
||||||
|
loopStart=reader.readI();
|
||||||
|
loopEnd=reader.readI();
|
||||||
|
loop=(loopStart>=0)&&(loopEnd>=0);
|
||||||
|
|
||||||
|
for (int i=0; i<4; i++) {
|
||||||
|
reader.readI();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (version<58) {
|
||||||
|
vol=reader.readS();
|
||||||
|
pitch=reader.readS();
|
||||||
|
} else {
|
||||||
|
reader.readI();
|
||||||
|
}
|
||||||
|
depth=(DivSampleDepth)reader.readC();
|
||||||
|
|
||||||
|
// reserved
|
||||||
|
reader.readC();
|
||||||
|
|
||||||
|
// while version 32 stored this value, it was unused.
|
||||||
|
if (version>=38) {
|
||||||
|
centerRate=(unsigned short)reader.readS();
|
||||||
|
} else {
|
||||||
|
reader.readS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version>=19) {
|
||||||
|
loopStart=reader.readI();
|
||||||
|
loop=(loopStart>=0)&&(loopEnd>=0);
|
||||||
|
} else {
|
||||||
|
reader.readI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version>=58) { // modern sample
|
||||||
|
init(samples);
|
||||||
|
reader.read(getCurBuf(),getCurBufLen());
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
// convert 16-bit samples to big-endian
|
||||||
|
if (depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
unsigned char* sampleBuf=(unsigned char*)getCurBuf();
|
||||||
|
size_t sampleBufLen=getCurBufLen();
|
||||||
|
for (size_t pos=0; pos<sampleBufLen; pos+=2) {
|
||||||
|
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||||
|
sampleBuf[pos+1]^=sampleBuf[pos];
|
||||||
|
sampleBuf[pos]^=sampleBuf[pos+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else { // legacy sample
|
||||||
|
int length=samples;
|
||||||
|
short* data=new short[length];
|
||||||
|
reader.read(data,2*length);
|
||||||
|
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
// convert 16-bit samples to big-endian
|
||||||
|
for (int pos=0; pos<length; pos++) {
|
||||||
|
data[pos]=((unsigned short)data[pos]>>8)|((unsigned short)data[pos]<<8);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pitch!=5) {
|
||||||
|
logD("scaling from %d...",pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render data
|
||||||
|
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
logW("sample depth is wrong! (%d)",depth);
|
||||||
|
depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||||
|
}
|
||||||
|
samples=(double)samples/samplePitchesSD[pitch];
|
||||||
|
init(samples);
|
||||||
|
|
||||||
|
unsigned int k=0;
|
||||||
|
float mult=(float)(vol)/50.0f;
|
||||||
|
for (double j=0; j<length; j+=samplePitchesSD[pitch]) {
|
||||||
|
if (k>=samples) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (depth==DIV_SAMPLE_DEPTH_8BIT) {
|
||||||
|
float next=(float)(data[(unsigned int)j]-0x80)*mult;
|
||||||
|
data8[k++]=fmin(fmax(next,-128),127);
|
||||||
|
} else {
|
||||||
|
float next=(float)data[(unsigned int)j]*mult;
|
||||||
|
data16[k++]=fmin(fmax(next,-32768),32767);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DIV_DATA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
bool DivSample::isLoopable() {
|
bool DivSample::isLoopable() {
|
||||||
return loop && ((loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples));
|
return loop && ((loopStart>=0 && loopStart<loopEnd) && (loopEnd>loopStart && loopEnd<=(int)samples));
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#define _SAMPLE_H
|
#define _SAMPLE_H
|
||||||
|
|
||||||
#include "../ta-utils.h"
|
#include "../ta-utils.h"
|
||||||
|
#include "safeWriter.h"
|
||||||
|
#include "dataErrors.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
enum DivSampleLoopMode: unsigned char {
|
enum DivSampleLoopMode: unsigned char {
|
||||||
|
@ -112,6 +114,8 @@ struct DivSample {
|
||||||
// - 2: Pingpong loop
|
// - 2: Pingpong loop
|
||||||
DivSampleLoopMode loopMode;
|
DivSampleLoopMode loopMode;
|
||||||
|
|
||||||
|
bool renderOn[4][32];
|
||||||
|
|
||||||
// these are the new data structures.
|
// these are the new data structures.
|
||||||
signed char* data8; // 8
|
signed char* data8; // 8
|
||||||
short* data16; // 16
|
short* data16; // 16
|
||||||
|
@ -131,6 +135,20 @@ struct DivSample {
|
||||||
std::deque<DivSampleHistory*> undoHist;
|
std::deque<DivSampleHistory*> undoHist;
|
||||||
std::deque<DivSampleHistory*> redoHist;
|
std::deque<DivSampleHistory*> redoHist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* put sample data.
|
||||||
|
* @param w a SafeWriter.
|
||||||
|
*/
|
||||||
|
void putSampleData(SafeWriter* w);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read sample data.
|
||||||
|
* @param reader the reader.
|
||||||
|
* @param version the format version.
|
||||||
|
* @return a DivDataErrors.
|
||||||
|
*/
|
||||||
|
DivDataErrors readSampleData(SafeReader& reader, short version);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if sample is loopable.
|
* check if sample is loopable.
|
||||||
* @return whether it is loopable.
|
* @return whether it is loopable.
|
||||||
|
@ -310,7 +328,14 @@ struct DivSample {
|
||||||
lengthB(0),
|
lengthB(0),
|
||||||
lengthBRR(0),
|
lengthBRR(0),
|
||||||
lengthVOX(0),
|
lengthVOX(0),
|
||||||
samples(0) {}
|
samples(0) {
|
||||||
|
for (int i=0; i<32; i++) {
|
||||||
|
renderOn[0][i]=true;
|
||||||
|
renderOn[1][i]=true;
|
||||||
|
renderOn[2][i]=true;
|
||||||
|
renderOn[3][i]=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
~DivSample();
|
~DivSample();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1711,8 +1711,7 @@ void DivEngine::registerSystems() {
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_T6W28]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_T6W28]=new DivSysDef(
|
||||||
// 0x0a = wild guess. it may as well be 0x83
|
"T6W28", NULL, 0xbf, 0, 4, false, true, 0x160, false, 0,
|
||||||
"T6W28", NULL, 0xbf, 0x0a, 4, false, true, 0x160, false, 0,
|
|
||||||
"an SN76489 derivative used in Neo Geo Pocket, has independent stereo volume and noise channel frequency.",
|
"an SN76489 derivative used in Neo Geo Pocket, has independent stereo volume and noise channel frequency.",
|
||||||
{"Square 1", "Square 2", "Square 3", "Noise"},
|
{"Square 1", "Square 2", "Square 3", "Noise"},
|
||||||
{"S1", "S2", "S3", "NO"},
|
{"S1", "S2", "S3", "NO"},
|
||||||
|
|
|
@ -1800,21 +1800,6 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
size_t sampleMemLen=writeZ280[i]->getSampleMemUsage();
|
size_t sampleMemLen=writeZ280[i]->getSampleMemUsage();
|
||||||
unsigned char* sampleMem=new unsigned char[sampleMemLen];
|
unsigned char* sampleMem=new unsigned char[sampleMemLen];
|
||||||
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
|
memcpy(sampleMem,writeZ280[i]->getSampleMem(),sampleMemLen);
|
||||||
// TODO: please fix this later
|
|
||||||
/*
|
|
||||||
for (int i=0; i<song.sampleLen; i++) {
|
|
||||||
DivSample* s=song.sample[i];
|
|
||||||
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
|
||||||
unsigned int pos=s->offYMZ280B;
|
|
||||||
for (unsigned int j=0; j<s->samples; j++) {
|
|
||||||
unsigned char lo=sampleMem[pos+j*2];
|
|
||||||
unsigned char hi=sampleMem[pos+j*2+1];
|
|
||||||
sampleMem[pos+j*2]=hi;
|
|
||||||
sampleMem[pos+j*2+1]=lo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
w->writeC(0x67);
|
w->writeC(0x67);
|
||||||
w->writeC(0x66);
|
w->writeC(0x66);
|
||||||
w->writeC(0x86);
|
w->writeC(0x86);
|
||||||
|
|
|
@ -48,6 +48,7 @@ DivDataErrors DivWavetable::readWaveData(SafeReader& reader, short version) {
|
||||||
char magic[4];
|
char magic[4];
|
||||||
reader.read(magic,4);
|
reader.read(magic,4);
|
||||||
if (memcmp(magic,"WAVE",4)!=0) {
|
if (memcmp(magic,"WAVE",4)!=0) {
|
||||||
|
logV("header is invalid: %c%c%c%c",magic[0],magic[1],magic[2],magic[3]);
|
||||||
return DIV_DATA_INVALID_HEADER;
|
return DIV_DATA_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
reader.readI(); // reserved
|
reader.readI(); // reserved
|
||||||
|
@ -57,7 +58,10 @@ DivDataErrors DivWavetable::readWaveData(SafeReader& reader, short version) {
|
||||||
min=reader.readI();
|
min=reader.readI();
|
||||||
max=reader.readI();
|
max=reader.readI();
|
||||||
|
|
||||||
if (len>256 || min!=0 || max>255) return DIV_DATA_INVALID_DATA;
|
if (len>256 || min!=0 || max>255) {
|
||||||
|
logV("invalid len/min/max: %d %d %d",len,min,max);
|
||||||
|
return DIV_DATA_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i=0; i<len; i++) {
|
for (int i=0; i<len; i++) {
|
||||||
data[i]=reader.readI();
|
data[i]=reader.readI();
|
||||||
|
|
|
@ -76,6 +76,7 @@ const char* aboutLine[]={
|
||||||
"Fragmare",
|
"Fragmare",
|
||||||
"freq-mod",
|
"freq-mod",
|
||||||
"iyatemu",
|
"iyatemu",
|
||||||
|
"JayBOB18",
|
||||||
"kleeder",
|
"kleeder",
|
||||||
"jaezu",
|
"jaezu",
|
||||||
"Laggy",
|
"Laggy",
|
||||||
|
@ -93,6 +94,7 @@ const char* aboutLine[]={
|
||||||
"SnugglyBun",
|
"SnugglyBun",
|
||||||
"SuperJet Spade",
|
"SuperJet Spade",
|
||||||
"TakuikaNinja",
|
"TakuikaNinja",
|
||||||
|
"The Blender Fiddler",
|
||||||
"TheDuccinator",
|
"TheDuccinator",
|
||||||
"theloredev",
|
"theloredev",
|
||||||
"TheRealHedgehogSonic",
|
"TheRealHedgehogSonic",
|
||||||
|
|
|
@ -77,7 +77,12 @@ void FurnaceGUI::calcChanOsc() {
|
||||||
int chans=e->getTotalChannelCount();
|
int chans=e->getTotalChannelCount();
|
||||||
|
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
|
int tryAgain=i;
|
||||||
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
||||||
|
while (buf==NULL) {
|
||||||
|
if (--tryAgain<0) break;
|
||||||
|
buf=e->getOscBuffer(tryAgain);
|
||||||
|
}
|
||||||
if (buf!=NULL && e->curSubSong->chanShow[i]) {
|
if (buf!=NULL && e->curSubSong->chanShow[i]) {
|
||||||
// 30ms should be enough
|
// 30ms should be enough
|
||||||
int displaySize=(float)(buf->rate)*0.03f;
|
int displaySize=(float)(buf->rate)*0.03f;
|
||||||
|
|
|
@ -132,6 +132,9 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
||||||
if (ImGui::MenuItem("instrument")) {
|
if (ImGui::MenuItem("instrument")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE);
|
doAction(GUI_ACTION_INS_LIST_SAVE);
|
||||||
}
|
}
|
||||||
|
if (ImGui::MenuItem("instrument (legacy .fui)")) {
|
||||||
|
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||||
|
}
|
||||||
if (ImGui::MenuItem("instrument (.dmp)")) {
|
if (ImGui::MenuItem("instrument (.dmp)")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +154,9 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) {
|
if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) {
|
||||||
|
if (ImGui::MenuItem("save in legacy format...")) {
|
||||||
|
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||||
|
}
|
||||||
if (ImGui::MenuItem("save as .dmp...")) {
|
if (ImGui::MenuItem("save as .dmp...")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||||
}
|
}
|
||||||
|
@ -434,6 +440,9 @@ void FurnaceGUI::drawInsList(bool asChild) {
|
||||||
if (ImGui::MenuItem("save")) {
|
if (ImGui::MenuItem("save")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE);
|
doAction(GUI_ACTION_INS_LIST_SAVE);
|
||||||
}
|
}
|
||||||
|
if (ImGui::MenuItem("save (legacy .fui)")) {
|
||||||
|
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||||
|
}
|
||||||
if (ImGui::MenuItem("save (.dmp)")) {
|
if (ImGui::MenuItem("save (.dmp)")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,6 +387,33 @@ void FurnaceGUI::drawDebug() {
|
||||||
ImGui::Text("System Managed Scale: %d",sysManagedScale);
|
ImGui::Text("System Managed Scale: %d",sysManagedScale);
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
if (ImGui::TreeNode("Visualizer Debug")) {
|
||||||
|
if (ImGui::BeginTable("visX",3,ImGuiTableFlags_Borders)) {
|
||||||
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("channel");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("patChanX");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("patChanSlideY");
|
||||||
|
|
||||||
|
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%d",i);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%f",patChanX[i]);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%f",patChanSlideY[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Text("particle count: %d",(int)particles.size());
|
||||||
|
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
if (ImGui::TreeNode("Playground")) {
|
if (ImGui::TreeNode("Playground")) {
|
||||||
if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0;
|
if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0;
|
||||||
if (ImGui::BeginCombo("Chip",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) {
|
if (ImGui::BeginCombo("Chip",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) {
|
||||||
|
|
|
@ -599,6 +599,9 @@ void FurnaceGUI::doAction(int what) {
|
||||||
case GUI_ACTION_INS_LIST_SAVE:
|
case GUI_ACTION_INS_LIST_SAVE:
|
||||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE);
|
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE);
|
||||||
break;
|
break;
|
||||||
|
case GUI_ACTION_INS_LIST_SAVE_OLD:
|
||||||
|
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_OLD);
|
||||||
|
break;
|
||||||
case GUI_ACTION_INS_LIST_SAVE_DMP:
|
case GUI_ACTION_INS_LIST_SAVE_DMP:
|
||||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_DMP);
|
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_DMP);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -204,13 +204,15 @@ void FurnaceGUI::drawMobileControls() {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Button("Export Audio");
|
ImGui::Button("Export Audio");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Button("Export VGM");
|
if (ImGui::Button("Export VGM")) {
|
||||||
|
openFileDialog(GUI_FILE_EXPORT_VGM);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Button("CmdStream");
|
ImGui::Button("CmdStream");
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::Text("Song info here...");
|
drawSongInfo(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GUI_SCENE_CHANNELS:
|
case GUI_SCENE_CHANNELS:
|
||||||
|
|
|
@ -80,6 +80,14 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, c
|
||||||
if (opened) return false;
|
if (opened) return false;
|
||||||
saving=false;
|
saving=false;
|
||||||
curPath=path;
|
curPath=path;
|
||||||
|
|
||||||
|
// strip excess directory separators
|
||||||
|
while (!curPath.empty()) {
|
||||||
|
if (curPath[curPath.size()-1]!=DIR_SEPARATOR) break;
|
||||||
|
curPath.erase(curPath.size()-1);
|
||||||
|
}
|
||||||
|
curPath+=DIR_SEPARATOR;
|
||||||
|
|
||||||
logD("opening load file dialog with curPath %s",curPath.c_str());
|
logD("opening load file dialog with curPath %s",curPath.c_str());
|
||||||
if (sysDialog) {
|
if (sysDialog) {
|
||||||
#ifdef USE_NFD
|
#ifdef USE_NFD
|
||||||
|
@ -145,6 +153,14 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, c
|
||||||
if (opened) return false;
|
if (opened) return false;
|
||||||
saving=true;
|
saving=true;
|
||||||
curPath=path;
|
curPath=path;
|
||||||
|
|
||||||
|
// strip excess directory separators
|
||||||
|
while (!curPath.empty()) {
|
||||||
|
if (curPath[curPath.size()-1]!=DIR_SEPARATOR) break;
|
||||||
|
curPath.erase(curPath.size()-1);
|
||||||
|
}
|
||||||
|
curPath+=DIR_SEPARATOR;
|
||||||
|
|
||||||
logD("opening save file dialog with curPath %s",curPath.c_str());
|
logD("opening save file dialog with curPath %s",curPath.c_str());
|
||||||
if (sysDialog) {
|
if (sysDialog) {
|
||||||
#ifdef USE_NFD
|
#ifdef USE_NFD
|
||||||
|
|
|
@ -1474,8 +1474,12 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
workingDirIns,
|
workingDirIns,
|
||||||
dpiScale,
|
dpiScale,
|
||||||
[this](const char* path) {
|
[this](const char* path) {
|
||||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(path);
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(path,false);
|
||||||
if (!instruments.empty()) {
|
if (!instruments.empty()) {
|
||||||
|
if (e->song.sampleLen!=sampleCountBefore) {
|
||||||
|
e->renderSamplesP();
|
||||||
|
}
|
||||||
if (curFileDialog==GUI_FILE_INS_OPEN_REPLACE) {
|
if (curFileDialog==GUI_FILE_INS_OPEN_REPLACE) {
|
||||||
if (prevIns==-3) {
|
if (prevIns==-3) {
|
||||||
prevIns=curIns;
|
prevIns=curIns;
|
||||||
|
@ -1506,6 +1510,16 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
||||||
dpiScale
|
dpiScale
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case GUI_FILE_INS_SAVE_OLD:
|
||||||
|
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||||
|
hasOpened=fileDialog->openSave(
|
||||||
|
"Save Instrument",
|
||||||
|
{"Furnace instrument", "*.fui"},
|
||||||
|
"Furnace instrument{.fui}",
|
||||||
|
workingDirIns,
|
||||||
|
dpiScale
|
||||||
|
);
|
||||||
|
break;
|
||||||
case GUI_FILE_INS_SAVE_DMP:
|
case GUI_FILE_INS_SAVE_DMP:
|
||||||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||||
hasOpened=fileDialog->openSave(
|
hasOpened=fileDialog->openSave(
|
||||||
|
@ -3059,10 +3073,14 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
if (ev.drop.file!=NULL) {
|
if (ev.drop.file!=NULL) {
|
||||||
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file);
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file);
|
||||||
DivWavetable* droppedWave=NULL;
|
DivWavetable* droppedWave=NULL;
|
||||||
DivSample* droppedSample=NULL;;
|
DivSample* droppedSample=NULL;;
|
||||||
if (!instruments.empty()) {
|
if (!instruments.empty()) {
|
||||||
|
if (e->song.sampleLen!=sampleCountBefore) {
|
||||||
|
e->renderSamplesP();
|
||||||
|
}
|
||||||
if (!e->getWarnings().empty()) {
|
if (!e->getWarnings().empty()) {
|
||||||
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||||
}
|
}
|
||||||
|
@ -3746,11 +3764,17 @@ bool FurnaceGUI::loop() {
|
||||||
drawSampleEdit();
|
drawSampleEdit();
|
||||||
drawPiano();
|
drawPiano();
|
||||||
break;
|
break;
|
||||||
|
case GUI_SCENE_CHIPS:
|
||||||
|
sysManagerOpen=true;
|
||||||
|
curWindow=GUI_WINDOW_SYS_MANAGER;
|
||||||
|
drawSysManager();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
patternOpen=true;
|
patternOpen=true;
|
||||||
curWindow=GUI_WINDOW_PATTERN;
|
curWindow=GUI_WINDOW_PATTERN;
|
||||||
drawPattern();
|
drawPattern();
|
||||||
drawPiano();
|
drawPiano();
|
||||||
|
drawMobileOrderSel();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3855,6 +3879,7 @@ bool FurnaceGUI::loop() {
|
||||||
case GUI_FILE_INS_OPEN:
|
case GUI_FILE_INS_OPEN:
|
||||||
case GUI_FILE_INS_OPEN_REPLACE:
|
case GUI_FILE_INS_OPEN_REPLACE:
|
||||||
case GUI_FILE_INS_SAVE:
|
case GUI_FILE_INS_SAVE:
|
||||||
|
case GUI_FILE_INS_SAVE_OLD:
|
||||||
case GUI_FILE_INS_SAVE_DMP:
|
case GUI_FILE_INS_SAVE_DMP:
|
||||||
workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||||
break;
|
break;
|
||||||
|
@ -3950,6 +3975,9 @@ bool FurnaceGUI::loop() {
|
||||||
if (curFileDialog==GUI_FILE_INS_SAVE) {
|
if (curFileDialog==GUI_FILE_INS_SAVE) {
|
||||||
checkExtension(".fui");
|
checkExtension(".fui");
|
||||||
}
|
}
|
||||||
|
if (curFileDialog==GUI_FILE_INS_SAVE_OLD) {
|
||||||
|
checkExtension(".fui");
|
||||||
|
}
|
||||||
if (curFileDialog==GUI_FILE_INS_SAVE_DMP) {
|
if (curFileDialog==GUI_FILE_INS_SAVE_DMP) {
|
||||||
checkExtension(".dmp");
|
checkExtension(".dmp");
|
||||||
}
|
}
|
||||||
|
@ -4041,7 +4069,12 @@ 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()) {
|
||||||
e->song.ins[curIns]->save(copyOfName.c_str());
|
e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GUI_FILE_INS_SAVE_OLD:
|
||||||
|
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
||||||
|
e->song.ins[curIns]->save(copyOfName.c_str(),true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GUI_FILE_INS_SAVE_DMP:
|
case GUI_FILE_INS_SAVE_DMP:
|
||||||
|
@ -4141,6 +4174,7 @@ bool FurnaceGUI::loop() {
|
||||||
bool ask=false;
|
bool ask=false;
|
||||||
bool warn=false;
|
bool warn=false;
|
||||||
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;
|
||||||
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());
|
||||||
if (insTemp.empty()) {
|
if (insTemp.empty()) {
|
||||||
|
@ -4155,6 +4189,9 @@ bool FurnaceGUI::loop() {
|
||||||
instruments.push_back(j);
|
instruments.push_back(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (e->song.sampleLen!=sampleCountBefore) {
|
||||||
|
e->renderSamplesP();
|
||||||
|
}
|
||||||
if (warn) {
|
if (warn) {
|
||||||
if (instruments.empty()) {
|
if (instruments.empty()) {
|
||||||
if (fileDialog->getFileName().size()>1) {
|
if (fileDialog->getFileName().size()>1) {
|
||||||
|
@ -4184,8 +4221,12 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GUI_FILE_INS_OPEN_REPLACE: {
|
case GUI_FILE_INS_OPEN_REPLACE: {
|
||||||
|
int sampleCountBefore=e->song.sampleLen;
|
||||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(copyOfName.c_str());
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(copyOfName.c_str());
|
||||||
if (!instruments.empty()) {
|
if (!instruments.empty()) {
|
||||||
|
if (e->song.sampleLen!=sampleCountBefore) {
|
||||||
|
e->renderSamplesP();
|
||||||
|
}
|
||||||
if (!e->getWarnings().empty()) {
|
if (!e->getWarnings().empty()) {
|
||||||
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||||
}
|
}
|
||||||
|
@ -5801,6 +5842,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
oldOrdersLen(0),
|
oldOrdersLen(0),
|
||||||
sampleZoom(1.0),
|
sampleZoom(1.0),
|
||||||
prevSampleZoom(1.0),
|
prevSampleZoom(1.0),
|
||||||
|
minSampleZoom(1.0),
|
||||||
samplePos(0),
|
samplePos(0),
|
||||||
resizeSize(1024),
|
resizeSize(1024),
|
||||||
silenceSize(1024),
|
silenceSize(1024),
|
||||||
|
@ -5809,6 +5851,7 @@ FurnaceGUI::FurnaceGUI():
|
||||||
amplifyVol(100.0),
|
amplifyVol(100.0),
|
||||||
sampleSelStart(-1),
|
sampleSelStart(-1),
|
||||||
sampleSelEnd(-1),
|
sampleSelEnd(-1),
|
||||||
|
sampleInfo(true),
|
||||||
sampleDragActive(false),
|
sampleDragActive(false),
|
||||||
sampleDragMode(false),
|
sampleDragMode(false),
|
||||||
sampleDrag16(false),
|
sampleDrag16(false),
|
||||||
|
|
|
@ -227,6 +227,13 @@ enum FurnaceGUIColors {
|
||||||
GUI_COLOR_SAMPLE_SEL,
|
GUI_COLOR_SAMPLE_SEL,
|
||||||
GUI_COLOR_SAMPLE_SEL_POINT,
|
GUI_COLOR_SAMPLE_SEL_POINT,
|
||||||
GUI_COLOR_SAMPLE_NEEDLE,
|
GUI_COLOR_SAMPLE_NEEDLE,
|
||||||
|
GUI_COLOR_SAMPLE_NEEDLE_PLAYING,
|
||||||
|
GUI_COLOR_SAMPLE_LOOP_POINT,
|
||||||
|
GUI_COLOR_SAMPLE_TIME_BG,
|
||||||
|
GUI_COLOR_SAMPLE_TIME_FG,
|
||||||
|
GUI_COLOR_SAMPLE_CHIP_DISABLED,
|
||||||
|
GUI_COLOR_SAMPLE_CHIP_ENABLED,
|
||||||
|
GUI_COLOR_SAMPLE_CHIP_WARNING,
|
||||||
|
|
||||||
GUI_COLOR_PAT_MANAGER_NULL,
|
GUI_COLOR_PAT_MANAGER_NULL,
|
||||||
GUI_COLOR_PAT_MANAGER_USED,
|
GUI_COLOR_PAT_MANAGER_USED,
|
||||||
|
@ -313,6 +320,7 @@ enum FurnaceGUIFileDialogs {
|
||||||
GUI_FILE_INS_OPEN,
|
GUI_FILE_INS_OPEN,
|
||||||
GUI_FILE_INS_OPEN_REPLACE,
|
GUI_FILE_INS_OPEN_REPLACE,
|
||||||
GUI_FILE_INS_SAVE,
|
GUI_FILE_INS_SAVE,
|
||||||
|
GUI_FILE_INS_SAVE_OLD,
|
||||||
GUI_FILE_INS_SAVE_DMP,
|
GUI_FILE_INS_SAVE_DMP,
|
||||||
GUI_FILE_WAVE_OPEN,
|
GUI_FILE_WAVE_OPEN,
|
||||||
GUI_FILE_WAVE_OPEN_REPLACE,
|
GUI_FILE_WAVE_OPEN_REPLACE,
|
||||||
|
@ -507,6 +515,7 @@ enum FurnaceGUIActions {
|
||||||
GUI_ACTION_INS_LIST_OPEN,
|
GUI_ACTION_INS_LIST_OPEN,
|
||||||
GUI_ACTION_INS_LIST_OPEN_REPLACE,
|
GUI_ACTION_INS_LIST_OPEN_REPLACE,
|
||||||
GUI_ACTION_INS_LIST_SAVE,
|
GUI_ACTION_INS_LIST_SAVE,
|
||||||
|
GUI_ACTION_INS_LIST_SAVE_OLD,
|
||||||
GUI_ACTION_INS_LIST_SAVE_DMP,
|
GUI_ACTION_INS_LIST_SAVE_DMP,
|
||||||
GUI_ACTION_INS_LIST_MOVE_UP,
|
GUI_ACTION_INS_LIST_MOVE_UP,
|
||||||
GUI_ACTION_INS_LIST_MOVE_DOWN,
|
GUI_ACTION_INS_LIST_MOVE_DOWN,
|
||||||
|
@ -913,7 +922,6 @@ struct FurnaceGUISysDefChip {
|
||||||
struct FurnaceGUISysDef {
|
struct FurnaceGUISysDef {
|
||||||
const char* name;
|
const char* name;
|
||||||
String definition;
|
String definition;
|
||||||
FurnaceGUISysDef(const char* n, std::initializer_list<int> def);
|
|
||||||
FurnaceGUISysDef(const char* n, std::initializer_list<FurnaceGUISysDefChip> def);
|
FurnaceGUISysDef(const char* n, std::initializer_list<FurnaceGUISysDefChip> def);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1073,6 +1081,7 @@ class FurnaceGUI {
|
||||||
int displayInsTypeListMakeInsSample;
|
int displayInsTypeListMakeInsSample;
|
||||||
float mobileMenuPos, autoButtonSize;
|
float mobileMenuPos, autoButtonSize;
|
||||||
const int* curSysSection;
|
const int* curSysSection;
|
||||||
|
DivInstrumentFM opllPreview;
|
||||||
|
|
||||||
String pendingRawSample;
|
String pendingRawSample;
|
||||||
int pendingRawSampleDepth, pendingRawSampleChannels;
|
int pendingRawSampleDepth, pendingRawSampleChannels;
|
||||||
|
@ -1581,12 +1590,14 @@ class FurnaceGUI {
|
||||||
// sample editor specific
|
// sample editor specific
|
||||||
double sampleZoom;
|
double sampleZoom;
|
||||||
double prevSampleZoom;
|
double prevSampleZoom;
|
||||||
|
double minSampleZoom;
|
||||||
int samplePos;
|
int samplePos;
|
||||||
int resizeSize, silenceSize;
|
int resizeSize, silenceSize;
|
||||||
double resampleTarget;
|
double resampleTarget;
|
||||||
int resampleStrat;
|
int resampleStrat;
|
||||||
float amplifyVol;
|
float amplifyVol;
|
||||||
int sampleSelStart, sampleSelEnd;
|
int sampleSelStart, sampleSelEnd;
|
||||||
|
bool sampleInfo;
|
||||||
bool sampleDragActive, sampleDragMode, sampleDrag16, sampleZoomAuto;
|
bool sampleDragActive, sampleDragMode, sampleDrag16, sampleZoomAuto;
|
||||||
void* sampleDragTarget;
|
void* sampleDragTarget;
|
||||||
ImVec2 sampleDragStart;
|
ImVec2 sampleDragStart;
|
||||||
|
@ -1719,8 +1730,9 @@ class FurnaceGUI {
|
||||||
void popToggleColors();
|
void popToggleColors();
|
||||||
|
|
||||||
void drawMobileControls();
|
void drawMobileControls();
|
||||||
|
void drawMobileOrderSel();
|
||||||
void drawEditControls();
|
void drawEditControls();
|
||||||
void drawSongInfo();
|
void drawSongInfo(bool asChild=false);
|
||||||
void drawOrders();
|
void drawOrders();
|
||||||
void drawPattern();
|
void drawPattern();
|
||||||
void drawInsList(bool asChild=false);
|
void drawInsList(bool asChild=false);
|
||||||
|
|
|
@ -590,6 +590,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
||||||
D("INS_LIST_OPEN", "Open", 0),
|
D("INS_LIST_OPEN", "Open", 0),
|
||||||
D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
||||||
D("INS_LIST_SAVE", "Save", 0),
|
D("INS_LIST_SAVE", "Save", 0),
|
||||||
|
D("INS_LIST_SAVE_OLD", "Save (legacy .fui)", 0),
|
||||||
D("INS_LIST_SAVE_DMP", "Save (.dmp)", 0),
|
D("INS_LIST_SAVE_DMP", "Save (.dmp)", 0),
|
||||||
D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
||||||
D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
||||||
|
@ -859,6 +860,13 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
||||||
D(GUI_COLOR_SAMPLE_SEL,"",ImVec4(0.26f,0.59f,0.98f,0.25f)),
|
D(GUI_COLOR_SAMPLE_SEL,"",ImVec4(0.26f,0.59f,0.98f,0.25f)),
|
||||||
D(GUI_COLOR_SAMPLE_SEL_POINT,"",ImVec4(0.06f,0.53f,0.98f,0.5f)),
|
D(GUI_COLOR_SAMPLE_SEL_POINT,"",ImVec4(0.06f,0.53f,0.98f,0.5f)),
|
||||||
D(GUI_COLOR_SAMPLE_NEEDLE,"",ImVec4(1.0f,0.8f,0.0f,1.0f)),
|
D(GUI_COLOR_SAMPLE_NEEDLE,"",ImVec4(1.0f,0.8f,0.0f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_NEEDLE_PLAYING,"",ImVec4(0.2f,1.0f,0.0f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_LOOP_POINT,"",ImVec4(1.0f,0.0f,0.0f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_TIME_BG,"",ImVec4(0.1f,0.11f,0.12f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_TIME_FG,"",ImVec4(0.4f,0.4f,0.4f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_CHIP_DISABLED,"",ImVec4(0.6f,0.6f,0.6f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_CHIP_ENABLED,"",ImVec4(0.3f,1.0f,0.3f,1.0f)),
|
||||||
|
D(GUI_COLOR_SAMPLE_CHIP_WARNING,"",ImVec4(1.0f,0.75f,0.3f,1.0f)),
|
||||||
|
|
||||||
D(GUI_COLOR_PAT_MANAGER_NULL,"",ImVec4(0.15f,0.15f,0.15f,1.0f)),
|
D(GUI_COLOR_PAT_MANAGER_NULL,"",ImVec4(0.15f,0.15f,0.15f,1.0f)),
|
||||||
D(GUI_COLOR_PAT_MANAGER_USED,"",ImVec4(0.15f,1.0f,0.15f,1.0f)),
|
D(GUI_COLOR_PAT_MANAGER_USED,"",ImVec4(0.15f,1.0f,0.15f,1.0f)),
|
||||||
|
|
|
@ -28,12 +28,16 @@
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include "plot_nolerp.h"
|
#include "plot_nolerp.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../../extern/Nuked-OPLL/opll.h"
|
||||||
|
}
|
||||||
|
|
||||||
const char* ssgEnvTypes[8]={
|
const char* ssgEnvTypes[8]={
|
||||||
"Down Down Down", "Down.", "Down Up Down Up", "Down UP", "Up Up Up", "Up.", "Up Down Up Down", "Up DOWN"
|
"Down Down Down", "Down.", "Down Up Down Up", "Down UP", "Up Up Up", "Up.", "Up Down Up Down", "Up DOWN"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* fmParamNames[3][32]={
|
const char* fmParamNames[3][32]={
|
||||||
{"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Key Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO2 > Freq", "LFO2 > Amp"},
|
{"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "Sustained", "Sustained", "Level Scaling", "Sustain", "Vibrato", "Waveform", "Scale Rate", "OP2 Half Sine", "OP1 Half Sine", "EnvShift", "Reverb", "Fine", "LFO2 > Freq", "LFO2 > Amp"},
|
||||||
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"},
|
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"},
|
||||||
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}
|
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}
|
||||||
};
|
};
|
||||||
|
@ -333,6 +337,16 @@ const char* snesGainModes[5]={
|
||||||
"Increase (bent line)"
|
"Increase (bent line)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int detuneMap[2][8]={
|
||||||
|
{-3, -2, -1, 0, 1, 2, 3, 4},
|
||||||
|
{ 7, 6, 5, 0, 1, 2, 3, 4}
|
||||||
|
};
|
||||||
|
|
||||||
|
const int detuneUnmap[2][11]={
|
||||||
|
{0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0},
|
||||||
|
{0, 0, 0, 3, 4, 5, 6, 7, 2, 1, 0}
|
||||||
|
};
|
||||||
|
|
||||||
// do not change these!
|
// do not change these!
|
||||||
// anything other than a checkbox will look ugly!
|
// anything other than a checkbox will look ugly!
|
||||||
//
|
//
|
||||||
|
@ -2153,6 +2167,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE);
|
doAction(GUI_ACTION_INS_LIST_SAVE);
|
||||||
}
|
}
|
||||||
if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) {
|
if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) {
|
||||||
|
if (ImGui::MenuItem("save in legacy format...")) {
|
||||||
|
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||||
|
}
|
||||||
if (ImGui::MenuItem("save as .dmp...")) {
|
if (ImGui::MenuItem("save as .dmp...")) {
|
||||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||||
}
|
}
|
||||||
|
@ -2433,8 +2450,38 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
if (ins->fm.opllPreset==16) {
|
if (ins->fm.opllPreset==16) {
|
||||||
ImGui::Text("this volume slider only works in compatibility (non-drums) system.");
|
ImGui::Text("this volume slider only works in compatibility (non-drums) system.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update OPLL preset preview
|
||||||
|
if (ins->fm.opllPreset>0 && ins->fm.opllPreset<16) {
|
||||||
|
const opll_patch_t* patchROM=OPLL_GetPatchROM(opll_type_ym2413);
|
||||||
|
|
||||||
|
const opll_patch_t* patch=&patchROM[ins->fm.opllPreset-1];
|
||||||
|
|
||||||
|
opllPreview.alg=0;
|
||||||
|
opllPreview.fb=patch->fb;
|
||||||
|
opllPreview.fms=patch->dm;
|
||||||
|
opllPreview.ams=patch->dc;
|
||||||
|
|
||||||
|
opllPreview.op[0].tl=patch->tl;
|
||||||
|
opllPreview.op[1].tl=ins->fm.op[1].tl;
|
||||||
|
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
|
opllPreview.op[i].am=patch->am[i];
|
||||||
|
opllPreview.op[i].vib=patch->vib[i];
|
||||||
|
opllPreview.op[i].ssgEnv=patch->et[i]?8:0;
|
||||||
|
opllPreview.op[i].ksr=patch->ksr[i];
|
||||||
|
opllPreview.op[i].mult=patch->multi[i];
|
||||||
|
opllPreview.op[i].ar=patch->ar[i];
|
||||||
|
opllPreview.op[i].dr=patch->dr[i];
|
||||||
|
opllPreview.op[i].sl=patch->sl[i];
|
||||||
|
opllPreview.op[i].rr=patch->rr[i];
|
||||||
}
|
}
|
||||||
if (willDisplayOps) {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DivInstrumentFM& fmOrigin=(ins->type==DIV_INS_OPLL && ins->fm.opllPreset>0 && ins->fm.opllPreset<16)?opllPreview:ins->fm;
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(!willDisplayOps);
|
||||||
if (settings.fmLayout==0) {
|
if (settings.fmLayout==0) {
|
||||||
int numCols=15;
|
int numCols=15;
|
||||||
if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13;
|
if (ins->type==DIV_INS_OPL ||ins->type==DIV_INS_OPL_DRUMS) numCols=13;
|
||||||
|
@ -2584,7 +2631,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
float sliderHeight=32.0f*dpiScale;
|
float sliderHeight=32.0f*dpiScale;
|
||||||
|
|
||||||
for (int i=0; i<opCount; i++) {
|
for (int i=0; i<opCount; i++) {
|
||||||
DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
DivInstrumentFM::Operator& op=fmOrigin.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
@ -2595,12 +2642,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
mod=false;
|
mod=false;
|
||||||
} else if (opCount==4) {
|
} else if (opCount==4) {
|
||||||
if (ins->type==DIV_INS_OPL) {
|
if (ins->type==DIV_INS_OPL) {
|
||||||
if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false;
|
if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false;
|
||||||
} else {
|
} else {
|
||||||
if (opIsOutput[ins->fm.alg&7][i]) mod=false;
|
if (opIsOutput[fmOrigin.alg&7][i]) mod=false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false;
|
if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false;
|
||||||
}
|
}
|
||||||
if (mod) {
|
if (mod) {
|
||||||
pushAccentColors(
|
pushAccentColors(
|
||||||
|
@ -2625,7 +2672,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
String opNameLabel;
|
String opNameLabel;
|
||||||
if (ins->type==DIV_INS_OPL_DRUMS) {
|
if (ins->type==DIV_INS_OPL_DRUMS) {
|
||||||
opNameLabel=fmt::sprintf("%s",oplDrumNames[i]);
|
opNameLabel=fmt::sprintf("%s",oplDrumNames[i]);
|
||||||
} else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) {
|
} else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) {
|
||||||
if (i==1) {
|
if (i==1) {
|
||||||
opNameLabel="Kick";
|
opNameLabel="Kick";
|
||||||
} else {
|
} else {
|
||||||
|
@ -2739,11 +2786,13 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||||
int detune=(op.dt&7)-(settings.unsignedDetune?0:3);
|
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
CENTER_VSLIDER;
|
CENTER_VSLIDER;
|
||||||
if (CWVSliderInt("##DT",ImVec2(20.0f*dpiScale,sliderHeight),&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER
|
if (CWVSliderInt("##DT",ImVec2(20.0f*dpiScale,sliderHeight),&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER
|
||||||
op.dt=detune+(settings.unsignedDetune?0:3);
|
if (detune<-3) detune=-3;
|
||||||
|
if (detune>7) detune=7;
|
||||||
|
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ins->type!=DIV_INS_FM) {
|
if (ins->type!=DIV_INS_FM) {
|
||||||
|
@ -2847,7 +2896,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type);
|
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,sliderHeight),ins->type);
|
||||||
|
|
||||||
if (settings.separateFMColors) {
|
if (settings.separateFMColors) {
|
||||||
popAccentColors();
|
popAccentColors();
|
||||||
|
@ -2876,7 +2925,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale));
|
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(8.0f*dpiScale,4.0f*dpiScale));
|
||||||
if (ImGui::BeginTable("AltFMOperators",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) {
|
if (ImGui::BeginTable("AltFMOperators",columns,ImGuiTableFlags_SizingStretchSame|ImGuiTableFlags_BordersInner)) {
|
||||||
for (int i=0; i<opCount; i++) {
|
for (int i=0; i<opCount; i++) {
|
||||||
DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
DivInstrumentFM::Operator& op=fmOrigin.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
||||||
if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow();
|
if ((settings.fmLayout!=6 && ((i+1)&1)) || i==0 || settings.fmLayout==5) ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::PushID(fmt::sprintf("op%d",i).c_str());
|
ImGui::PushID(fmt::sprintf("op%d",i).c_str());
|
||||||
|
@ -2888,12 +2937,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
mod=false;
|
mod=false;
|
||||||
} else if (opCount==4) {
|
} else if (opCount==4) {
|
||||||
if (ins->type==DIV_INS_OPL) {
|
if (ins->type==DIV_INS_OPL) {
|
||||||
if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false;
|
if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false;
|
||||||
} else {
|
} else {
|
||||||
if (opIsOutput[ins->fm.alg&7][i]) mod=false;
|
if (opIsOutput[fmOrigin.alg&7][i]) mod=false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false;
|
if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false;
|
||||||
}
|
}
|
||||||
if (mod) {
|
if (mod) {
|
||||||
pushAccentColors(
|
pushAccentColors(
|
||||||
|
@ -2915,7 +2964,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::Dummy(ImVec2(dpiScale,dpiScale));
|
ImGui::Dummy(ImVec2(dpiScale,dpiScale));
|
||||||
if (ins->type==DIV_INS_OPL_DRUMS) {
|
if (ins->type==DIV_INS_OPL_DRUMS) {
|
||||||
snprintf(tempID,1024,"%s",oplDrumNames[i]);
|
snprintf(tempID,1024,"%s",oplDrumNames[i]);
|
||||||
} else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) {
|
} else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) {
|
||||||
if (i==1) {
|
if (i==1) {
|
||||||
snprintf(tempID,1024,"Envelope 2 (kick only)");
|
snprintf(tempID,1024,"Envelope 2 (kick only)");
|
||||||
} else {
|
} else {
|
||||||
|
@ -3078,11 +3127,13 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
||||||
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||||
|
|
||||||
int detune=(op.dt&7)-(settings.unsignedDetune?0:3);
|
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
||||||
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
||||||
op.dt=detune+(settings.unsignedDetune?0:3);
|
if (detune<-3) detune=-3;
|
||||||
|
if (detune>7) detune=7;
|
||||||
|
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||||
} rightClickable
|
} rightClickable
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
@ -3100,11 +3151,13 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
||||||
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||||
|
|
||||||
int detune=(op.dt&7)-(settings.unsignedDetune?0:3);
|
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
||||||
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
||||||
op.dt=detune+(settings.unsignedDetune?0:3);
|
if (detune<-3) detune=-3;
|
||||||
|
if (detune>7) detune=7;
|
||||||
|
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||||
} rightClickable
|
} rightClickable
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
@ -3118,7 +3171,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
case DIV_INS_OPLL:
|
case DIV_INS_OPLL:
|
||||||
// waveform
|
// waveform
|
||||||
drawWaveform(i==0?(ins->fm.ams&1):(ins->fm.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
|
drawWaveform(i==0?(fmOrigin.ams&1):(fmOrigin.fms&1),ins->type==DIV_INS_OPZ,ImVec2(waveWidth,waveHeight));
|
||||||
|
|
||||||
// params
|
// params
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
@ -3241,11 +3294,13 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
||||||
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||||
|
|
||||||
int detune=(op.dt&7)-(settings.unsignedDetune?0:3);
|
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_DT));
|
||||||
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4,tempID)) { PARAMETER
|
||||||
op.dt=detune+(settings.unsignedDetune?0:3);
|
if (detune<-3) detune=-3;
|
||||||
|
if (detune>7) detune=7;
|
||||||
|
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||||
} rightClickable
|
} rightClickable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3270,7 +3325,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
if (ins->type==DIV_INS_OPZ) {
|
if (ins->type==DIV_INS_OPZ) {
|
||||||
envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f;
|
envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f;
|
||||||
}
|
}
|
||||||
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type);
|
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type);
|
||||||
|
|
||||||
if (ins->type==DIV_INS_OPZ) {
|
if (ins->type==DIV_INS_OPZ) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
@ -3353,7 +3408,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
if (ImGui::BeginTable("FMOperators",columns,ImGuiTableFlags_SizingStretchSame)) {
|
if (ImGui::BeginTable("FMOperators",columns,ImGuiTableFlags_SizingStretchSame)) {
|
||||||
for (int i=0; i<opCount; i++) {
|
for (int i=0; i<opCount; i++) {
|
||||||
DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
DivInstrumentFM::Operator& op=fmOrigin.op[(opCount==4 && ins->type!=DIV_INS_OPL_DRUMS)?opOrder[i]:i];
|
||||||
if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow();
|
if ((settings.fmLayout!=3 && ((i+1)&1)) || i==0 || settings.fmLayout==2) ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
@ -3366,12 +3421,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
mod=false;
|
mod=false;
|
||||||
} else if (opCount==4) {
|
} else if (opCount==4) {
|
||||||
if (ins->type==DIV_INS_OPL) {
|
if (ins->type==DIV_INS_OPL) {
|
||||||
if (opIsOutputOPL[ins->fm.alg&3][i]) mod=false;
|
if (opIsOutputOPL[fmOrigin.alg&3][i]) mod=false;
|
||||||
} else {
|
} else {
|
||||||
if (opIsOutput[ins->fm.alg&7][i]) mod=false;
|
if (opIsOutput[fmOrigin.alg&7][i]) mod=false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (i==1 || (ins->type==DIV_INS_OPL && (ins->fm.alg&1))) mod=false;
|
if (i==1 || (ins->type==DIV_INS_OPL && (fmOrigin.alg&1))) mod=false;
|
||||||
}
|
}
|
||||||
if (mod) {
|
if (mod) {
|
||||||
pushAccentColors(
|
pushAccentColors(
|
||||||
|
@ -3396,7 +3451,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ins->type==DIV_INS_OPL_DRUMS) {
|
if (ins->type==DIV_INS_OPL_DRUMS) {
|
||||||
opNameLabel=fmt::sprintf("%s",oplDrumNames[i]);
|
opNameLabel=fmt::sprintf("%s",oplDrumNames[i]);
|
||||||
} else if (ins->type==DIV_INS_OPL && ins->fm.opllPreset==16) {
|
} else if (ins->type==DIV_INS_OPL && fmOrigin.opllPreset==16) {
|
||||||
if (i==1) {
|
if (i==1) {
|
||||||
opNameLabel="Envelope 2 (kick only)";
|
opNameLabel="Envelope 2 (kick only)";
|
||||||
} else {
|
} else {
|
||||||
|
@ -3464,7 +3519,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//52.0 controls vert scaling; default 96
|
//52.0 controls vert scaling; default 96
|
||||||
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type);
|
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type);
|
||||||
//P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable
|
//P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable
|
||||||
if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) {
|
if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) {
|
||||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \
|
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \
|
||||||
|
@ -3616,12 +3671,14 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
|
|
||||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPM) {
|
||||||
if (!(ins->type==DIV_INS_OPZ && op.egt)) {
|
if (!(ins->type==DIV_INS_OPZ && op.egt)) {
|
||||||
int detune=(op.dt&7)-(settings.unsignedDetune?0:3);
|
int detune=detuneMap[settings.unsignedDetune?1:0][op.dt&7];
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER
|
if (CWSliderInt("##DT",&detune,settings.unsignedDetune?0:-3,settings.unsignedDetune?7:4)) { PARAMETER
|
||||||
op.dt=detune+(settings.unsignedDetune?0:3);
|
if (detune<-3) detune=-3;
|
||||||
|
if (detune>7) detune=7;
|
||||||
|
op.dt=detuneUnmap[settings.unsignedDetune?1:0][detune+3];
|
||||||
} rightClickable
|
} rightClickable
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%s",FM_NAME(FM_DT));
|
ImGui::Text("%s",FM_NAME(FM_DT));
|
||||||
|
@ -3682,7 +3739,7 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ImGui::EndDisabled();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginTabItem("FM Macros")) {
|
if (ImGui::BeginTabItem("FM Macros")) {
|
||||||
|
|
|
@ -18,8 +18,45 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include <fmt/printf.h>
|
||||||
#include "IconsFontAwesome4.h"
|
#include "IconsFontAwesome4.h"
|
||||||
#include <imgui.h>
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
|
void FurnaceGUI::drawMobileOrderSel() {
|
||||||
|
if (!portrait) return;
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(0.0f,mobileMenuPos*-0.65*canvasH));
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(canvasW,0.12*canvasW));
|
||||||
|
if (ImGui::Begin("OrderSel",NULL,globalWinFlags)) {
|
||||||
|
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||||
|
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||||
|
ImGuiStyle& style=ImGui::GetStyle();
|
||||||
|
|
||||||
|
ImVec2 size=ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
ImVec2 minArea=window->DC.CursorPos;
|
||||||
|
ImVec2 maxArea=ImVec2(
|
||||||
|
minArea.x+size.x,
|
||||||
|
minArea.y+size.y
|
||||||
|
);
|
||||||
|
ImRect rect=ImRect(minArea,maxArea);
|
||||||
|
ImGui::ItemSize(size,style.FramePadding.y);
|
||||||
|
ImU32 col=ImGui::GetColorU32(ImGuiCol_Text);
|
||||||
|
if (ImGui::ItemAdd(rect,ImGui::GetID("OrderSelW"))) {
|
||||||
|
String text=fmt::sprintf("%.2X",curOrder);
|
||||||
|
|
||||||
|
ImVec2 pos=ImLerp(minArea,maxArea,ImVec2(0.5,0.0));
|
||||||
|
ImGui::PushFont(bigFont);
|
||||||
|
ImVec2 textSize=ImGui::CalcTextSize(text.c_str());
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
pos.x-=textSize.x*0.5*(size.y/textSize.y);
|
||||||
|
|
||||||
|
dl->AddText(bigFont,size.y,pos,col,text.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
void FurnaceGUI::drawOrders() {
|
void FurnaceGUI::drawOrders() {
|
||||||
static char selID[4096];
|
static char selID[4096];
|
||||||
|
|
|
@ -133,14 +133,14 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
for (int j=0; j<chans; j++) {
|
for (int j=0; j<chans; j++) {
|
||||||
// check if channel is not hidden
|
// check if channel is not hidden
|
||||||
if (!e->curSubSong->chanShow[j]) {
|
if (!e->curSubSong->chanShow[j]) {
|
||||||
patChanX[j]=ImGui::GetCursorPosX();
|
patChanX[j]=ImGui::GetCursorScreenPos().x;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int chanVolMax=e->getMaxVolumeChan(j);
|
int chanVolMax=e->getMaxVolumeChan(j);
|
||||||
if (chanVolMax<1) chanVolMax=1;
|
if (chanVolMax<1) chanVolMax=1;
|
||||||
const DivPattern* pat=patCache[j];
|
const DivPattern* pat=patCache[j];
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
patChanX[j]=ImGui::GetCursorPosX();
|
patChanX[j]=ImGui::GetCursorScreenPos().x;
|
||||||
|
|
||||||
// selection highlight flags
|
// selection highlight flags
|
||||||
int sel1XSum=sel1.xCoarse*32+sel1.xFine;
|
int sel1XSum=sel1.xCoarse*32+sel1.xFine;
|
||||||
|
@ -331,7 +331,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
patChanX[chans]=ImGui::GetCursorPosX();
|
patChanX[chans]=ImGui::GetCursorScreenPos().x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::drawPattern() {
|
void FurnaceGUI::drawPattern() {
|
||||||
|
@ -376,8 +376,8 @@ void FurnaceGUI::drawPattern() {
|
||||||
}
|
}
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0.0f,0.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0.0f,0.0f));
|
||||||
if (mobileUI) {
|
if (mobileUI) {
|
||||||
patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*canvasH)):ImVec2((0.16*canvasH)+0.5*canvasW*mobileMenuPos,0.0f));
|
patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*canvasH)+(0.12*canvasW)):ImVec2((0.16*canvasH)+0.5*canvasW*mobileMenuPos,0.0f));
|
||||||
patWindowSize=(portrait?ImVec2(canvasW,canvasH-(0.16*canvasW)-(pianoOpen?(0.4*canvasW):0.0f)):ImVec2(canvasW-(0.16*canvasH),canvasH-(pianoOpen?(0.3*canvasH):0.0f)));
|
patWindowSize=(portrait?ImVec2(canvasW,canvasH-(0.16*canvasW)-(0.12*canvasW)-(pianoOpen?(0.4*canvasW):0.0f)):ImVec2(canvasW-(0.16*canvasH),canvasH-(pianoOpen?(0.3*canvasH):0.0f)));
|
||||||
ImGui::SetNextWindowPos(patWindowPos);
|
ImGui::SetNextWindowPos(patWindowPos);
|
||||||
ImGui::SetNextWindowSize(patWindowSize);
|
ImGui::SetNextWindowSize(patWindowSize);
|
||||||
}
|
}
|
||||||
|
@ -652,7 +652,7 @@ void FurnaceGUI::drawPattern() {
|
||||||
}
|
}
|
||||||
case 3: // split button
|
case 3: // split button
|
||||||
ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale));
|
ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale));
|
||||||
ImGui::SetCursorPosX(minLabelArea.x);
|
//ImGui::SetCursorPosX(minLabelArea.x);
|
||||||
ImGui::TextUnformatted(chanID);
|
ImGui::TextUnformatted(chanID);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::PushFont(mainFont);
|
ImGui::PushFont(mainFont);
|
||||||
|
@ -966,7 +966,7 @@ void FurnaceGUI::drawPattern() {
|
||||||
if (fancyPattern) { // visualizer
|
if (fancyPattern) { // visualizer
|
||||||
e->getCommandStream(cmdStream);
|
e->getCommandStream(cmdStream);
|
||||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||||
ImVec2 off=ImGui::GetWindowPos();
|
ImVec2 off=ImVec2(0.0f,ImGui::GetWindowPos().y);
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
for (DivCommand& i: cmdStream) {
|
for (DivCommand& i: cmdStream) {
|
||||||
|
|
|
@ -158,7 +158,7 @@ void FurnaceGUI::drawPiano() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
if (pianoInputPadMode==1 && cursor.xFine>0) {
|
if (pianoInputPadMode==1 && cursor.xFine>0 && curWindow==GUI_WINDOW_PATTERN) {
|
||||||
ImVec2 buttonSize=ImGui::GetContentRegionAvail();
|
ImVec2 buttonSize=ImGui::GetContentRegionAvail();
|
||||||
if (ImGui::BeginTable("InputPadP",8,ImGuiTableFlags_SizingFixedSame)) {
|
if (ImGui::BeginTable("InputPadP",8,ImGuiTableFlags_SizingFixedSame)) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
@ -266,7 +266,7 @@ void FurnaceGUI::drawPiano() {
|
||||||
} else {
|
} else {
|
||||||
int bottomNotes=7*oct;
|
int bottomNotes=7*oct;
|
||||||
// evaluate input
|
// evaluate input
|
||||||
for (TouchPoint& i: activePoints) {
|
if (canInput) for (TouchPoint& i: activePoints) {
|
||||||
if (rect.Contains(ImVec2(i.x,i.y))) {
|
if (rect.Contains(ImVec2(i.x,i.y))) {
|
||||||
// top
|
// top
|
||||||
int o=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*oct;
|
int o=((i.x-rect.Min.x)/(rect.Max.x-rect.Min.x))*oct;
|
||||||
|
@ -430,7 +430,7 @@ void FurnaceGUI::drawPiano() {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// draw input pad if necessary
|
// draw input pad if necessary
|
||||||
if ((pianoInputPadMode==2 && cursor.xFine>0) || pianoInputPadMode==3) {
|
if (curWindow==GUI_WINDOW_PATTERN && ((pianoInputPadMode==2 && cursor.xFine>0) || pianoInputPadMode==3)) {
|
||||||
if (ImGui::Begin("Input Pad",NULL,ImGuiWindowFlags_NoTitleBar)) {
|
if (ImGui::Begin("Input Pad",NULL,ImGuiWindowFlags_NoTitleBar)) {
|
||||||
ImGui::BeginDisabled(cursor.xFine==0);
|
ImGui::BeginDisabled(cursor.xFine==0);
|
||||||
if (ImGui::BeginTable("InputPad",3,ImGuiTableFlags_Borders)) {
|
if (ImGui::BeginTable("InputPad",3,ImGuiTableFlags_Borders)) {
|
||||||
|
|
1125
src/gui/presets.cpp
1125
src/gui/presets.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1540,11 +1540,6 @@ void FurnaceGUI::drawSettings() {
|
||||||
settings.waveLayout=waveLayoutB;
|
settings.waveLayout=waveLayoutB;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sampleLayoutB=settings.sampleLayout;
|
|
||||||
if (ImGui::Checkbox("Use compact sample editor",&sampleLayoutB)) {
|
|
||||||
settings.sampleLayout=sampleLayoutB;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool oldMacroVSliderB=settings.oldMacroVSlider;
|
bool oldMacroVSliderB=settings.oldMacroVSlider;
|
||||||
if (ImGui::Checkbox("Use classic macro editor vertical slider",&oldMacroVSliderB)) {
|
if (ImGui::Checkbox("Use classic macro editor vertical slider",&oldMacroVSliderB)) {
|
||||||
settings.oldMacroVSlider=oldMacroVSliderB;
|
settings.oldMacroVSlider=oldMacroVSliderB;
|
||||||
|
@ -1848,12 +1843,19 @@ void FurnaceGUI::drawSettings() {
|
||||||
if (ImGui::TreeNode("Sample Editor")) {
|
if (ImGui::TreeNode("Sample Editor")) {
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_BG,"Background");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_BG,"Background");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_FG,"Waveform");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_FG,"Waveform");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_TIME_BG,"Time background");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_TIME_FG,"Time text");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_LOOP,"Loop region");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_LOOP,"Loop region");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CENTER,"Center guide");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CENTER,"Center guide");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_GRID,"Grid");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_GRID,"Grid");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL,"Selection");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL,"Selection");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL_POINT,"Selection points");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_SEL_POINT,"Selection points");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_NEEDLE,"Preview needle");
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_NEEDLE,"Preview needle");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_NEEDLE_PLAYING,"Playing needles");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_LOOP_POINT,"Loop markers");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CHIP_DISABLED,"Chip select: disabled");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CHIP_ENABLED,"Chip select: enabled");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_SAMPLE_CHIP_WARNING,"Chip select: enabled (failure)");
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
if (ImGui::TreeNode("Pattern Manager")) {
|
if (ImGui::TreeNode("Pattern Manager")) {
|
||||||
|
|
|
@ -22,14 +22,15 @@
|
||||||
#include "misc/cpp/imgui_stdlib.h"
|
#include "misc/cpp/imgui_stdlib.h"
|
||||||
#include "intConst.h"
|
#include "intConst.h"
|
||||||
|
|
||||||
void FurnaceGUI::drawSongInfo() {
|
void FurnaceGUI::drawSongInfo(bool asChild) {
|
||||||
if (nextWindow==GUI_WINDOW_SONG_INFO) {
|
if (nextWindow==GUI_WINDOW_SONG_INFO) {
|
||||||
songInfoOpen=true;
|
songInfoOpen=true;
|
||||||
ImGui::SetNextWindowFocus();
|
ImGui::SetNextWindowFocus();
|
||||||
nextWindow=GUI_WINDOW_NOTHING;
|
nextWindow=GUI_WINDOW_NOTHING;
|
||||||
}
|
}
|
||||||
if (!songInfoOpen) return;
|
if (!songInfoOpen && !asChild) return;
|
||||||
if (ImGui::Begin("Song Information",&songInfoOpen,globalWinFlags)) {
|
bool began=asChild?ImGui::BeginChild("Song Information"):ImGui::Begin("Song Information",&songInfoOpen,globalWinFlags);
|
||||||
|
if (began) {
|
||||||
if (ImGui::BeginTable("NameAuthor",2,ImGuiTableFlags_SizingStretchProp)) {
|
if (ImGui::BeginTable("NameAuthor",2,ImGuiTableFlags_SizingStretchProp)) {
|
||||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||||
|
@ -240,6 +241,10 @@ void FurnaceGUI::drawSongInfo() {
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO;
|
if (!asChild && ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO;
|
||||||
|
if (asChild) {
|
||||||
|
ImGui::EndChild();
|
||||||
|
} else {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
||||||
int clockSel=flags.getInt("clockSel",0);
|
int clockSel=flags.getInt("clockSel",0);
|
||||||
int chipType=flags.getInt("chipType",0);
|
int chipType=flags.getInt("chipType",0);
|
||||||
bool noPhaseReset=flags.getBool("noPhaseReset",false);
|
bool noPhaseReset=flags.getBool("noPhaseReset",false);
|
||||||
|
bool noEasyNoise=flags.getBool("noEasyNoise",false);
|
||||||
|
|
||||||
ImGui::Text("Clock rate:");
|
ImGui::Text("Clock rate:");
|
||||||
if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) {
|
if (ImGui::RadioButton("3.58MHz (NTSC)",clockSel==0)) {
|
||||||
|
@ -152,11 +153,16 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
||||||
altered=true;
|
altered=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::Checkbox("Disable easy period to note mapping on upper octaves",&noEasyNoise)) {
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (altered) {
|
if (altered) {
|
||||||
e->lockSave([&]() {
|
e->lockSave([&]() {
|
||||||
flags.set("clockSel",clockSel);
|
flags.set("clockSel",clockSel);
|
||||||
flags.set("chipType",chipType);
|
flags.set("chipType",chipType);
|
||||||
flags.set("noPhaseReset",noPhaseReset);
|
flags.set("noPhaseReset",noPhaseReset);
|
||||||
|
flags.set("noEasyNoise",noEasyNoise);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -318,6 +324,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
||||||
case DIV_SYSTEM_VRC7: {
|
case DIV_SYSTEM_VRC7: {
|
||||||
int clockSel=flags.getInt("clockSel",0);
|
int clockSel=flags.getInt("clockSel",0);
|
||||||
int patchSet=flags.getInt("patchSet",0);
|
int patchSet=flags.getInt("patchSet",0);
|
||||||
|
bool noTopHatFreq=flags.getBool("noTopHatFreq",false);
|
||||||
|
|
||||||
ImGui::Text("Clock rate:");
|
ImGui::Text("Clock rate:");
|
||||||
if (ImGui::RadioButton("NTSC (3.58MHz)",clockSel==0)) {
|
if (ImGui::RadioButton("NTSC (3.58MHz)",clockSel==0)) {
|
||||||
|
@ -356,12 +363,19 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type==DIV_SYSTEM_OPLL_DRUMS) {
|
||||||
|
if (ImGui::Checkbox("Ignore top/hi-hat frequency changes",&noTopHatFreq)) {
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (altered) {
|
if (altered) {
|
||||||
e->lockSave([&]() {
|
e->lockSave([&]() {
|
||||||
flags.set("clockSel",clockSel);
|
flags.set("clockSel",clockSel);
|
||||||
if (type!=DIV_SYSTEM_VRC7) {
|
if (type!=DIV_SYSTEM_VRC7) {
|
||||||
flags.set("patchSet",patchSet);
|
flags.set("patchSet",patchSet);
|
||||||
}
|
}
|
||||||
|
flags.set("noTopHatFreq",noTopHatFreq);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1529,12 +1543,25 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DIV_SYSTEM_T6W28: {
|
||||||
|
bool noEasyNoise=flags.getBool("noEasyNoise",false);
|
||||||
|
|
||||||
|
if (ImGui::Checkbox("Disable easy period to note mapping on upper octaves",&noEasyNoise)) {
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (altered) {
|
||||||
|
e->lockSave([&]() {
|
||||||
|
flags.set("noEasyNoise",noEasyNoise);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_SYSTEM_SWAN:
|
case DIV_SYSTEM_SWAN:
|
||||||
case DIV_SYSTEM_VERA:
|
case DIV_SYSTEM_VERA:
|
||||||
case DIV_SYSTEM_BUBSYS_WSG:
|
case DIV_SYSTEM_BUBSYS_WSG:
|
||||||
case DIV_SYSTEM_YMU759:
|
case DIV_SYSTEM_YMU759:
|
||||||
case DIV_SYSTEM_PET:
|
case DIV_SYSTEM_PET:
|
||||||
case DIV_SYSTEM_T6W28:
|
|
||||||
case DIV_SYSTEM_VBOY:
|
case DIV_SYSTEM_VBOY:
|
||||||
ImGui::Text("nothing to configure");
|
ImGui::Text("nothing to configure");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -30,6 +30,14 @@ void FurnaceGUI::drawSysManager() {
|
||||||
nextWindow=GUI_WINDOW_NOTHING;
|
nextWindow=GUI_WINDOW_NOTHING;
|
||||||
}
|
}
|
||||||
if (!sysManagerOpen) return;
|
if (!sysManagerOpen) return;
|
||||||
|
if (mobileUI) {
|
||||||
|
patWindowPos=(portrait?ImVec2(0.0f,(mobileMenuPos*-0.65*canvasH)):ImVec2((0.16*canvasH)+0.5*canvasW*mobileMenuPos,0.0f));
|
||||||
|
patWindowSize=(portrait?ImVec2(canvasW,canvasH-(0.16*canvasW)):ImVec2(canvasW-(0.16*canvasH),canvasH));
|
||||||
|
ImGui::SetNextWindowPos(patWindowPos);
|
||||||
|
ImGui::SetNextWindowSize(patWindowSize);
|
||||||
|
} else {
|
||||||
|
//ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH));
|
||||||
|
}
|
||||||
if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) {
|
if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) {
|
||||||
ImGui::Checkbox("Preserve channel order",&preserveChanPos);
|
ImGui::Checkbox("Preserve channel order",&preserveChanPos);
|
||||||
if (ImGui::BeginTable("SystemList",3)) {
|
if (ImGui::BeginTable("SystemList",3)) {
|
||||||
|
|
Loading…
Reference in New Issue