mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 14:33:01 +00:00
Merge branch 'tildearrow:master' into master
This commit is contained in:
commit
e83e0a2266
42 changed files with 3735 additions and 355 deletions
|
@ -149,23 +149,6 @@ else()
|
|||
endif()
|
||||
|
||||
if (SYSTEM_SDL2)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(SDL sdl>=${SYSTEM_SDL_MIN_VER})
|
||||
if (SDL_FOUND)
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${SDL_INCLUDE_DIRS})
|
||||
list(APPEND DEPENDENCIES_COMPILE_OPTIONS ${SDL_CFLAGS_OTHER})
|
||||
list(APPEND DEPENDENCIES_LIBRARIES ${SDL_LIBRARIES})
|
||||
list(APPEND DEPENDENCIES_LIBRARY_DIRS ${SDL_LIBRARY_DIRS})
|
||||
list(APPEND DEPENDENCIES_LINK_OPTIONS ${SDL_LDFLAGS_OTHER})
|
||||
list(APPEND DEPENDENCIES_LEGACY_LDFLAGS ${SDL_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if (NOT SDL_FOUND)
|
||||
find_package(SDL ${SYSTEM_SDL_MIN_VER})
|
||||
if (SDL_FOUND)
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${SDL_INCLUDE_DIR})
|
||||
list(APPEND DEPENDENCIES_LIBRARIES ${SDL_LIBRARY})
|
||||
else()
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(SDL2 sdl2>=${SYSTEM_SDL_MIN_VER})
|
||||
if (SDL2_FOUND)
|
||||
|
@ -182,8 +165,6 @@ if (SYSTEM_SDL2)
|
|||
list(APPEND DEPENDENCIES_INCLUDE_DIRS ${SDL2_INCLUDE_DIR})
|
||||
list(APPEND DEPENDENCIES_LIBRARIES ${SDL2_LIBRARY})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using system-installed SDL2")
|
||||
else()
|
||||
set(SDL_SHARED OFF)
|
||||
|
@ -313,6 +294,8 @@ src/engine/platform/c64.cpp
|
|||
src/engine/platform/arcade.cpp
|
||||
src/engine/platform/ym2610.cpp
|
||||
src/engine/platform/ym2610ext.cpp
|
||||
src/engine/platform/ym2610b.cpp
|
||||
src/engine/platform/ym2610bext.cpp
|
||||
src/engine/platform/ay.cpp
|
||||
src/engine/platform/ay8930.cpp
|
||||
src/engine/platform/tia.cpp
|
||||
|
|
BIN
demos/Another_winter.fur
Normal file
BIN
demos/Another_winter.fur
Normal file
Binary file not shown.
BIN
demos/yky.fur
Normal file
BIN
demos/yky.fur
Normal file
Binary file not shown.
22
extern/Nuked-OPLL/opll.c
vendored
22
extern/Nuked-OPLL/opll.c
vendored
|
@ -290,6 +290,28 @@ static void OPLL_DoModeWrite(opll_t *chip) {
|
|||
}
|
||||
}
|
||||
|
||||
const opll_patch_t* OPLL_GetPatchROM(uint32_t chip_type) {
|
||||
switch (chip_type) {
|
||||
case opll_type_ds1001:
|
||||
return patch_ds1001;
|
||||
break;
|
||||
case opll_type_ymf281:
|
||||
case opll_type_ymf281b:
|
||||
return patch_ymf281;
|
||||
break;
|
||||
case opll_type_ym2423:
|
||||
return patch_ym2423;
|
||||
break;
|
||||
case opll_type_ym2413:
|
||||
case opll_type_ym2413b:
|
||||
case opll_type_ym2420:
|
||||
default:
|
||||
return patch_ym2413;
|
||||
break;
|
||||
}
|
||||
return patch_ym2413;
|
||||
}
|
||||
|
||||
void OPLL_Reset(opll_t *chip, uint32_t chip_type) {
|
||||
uint32_t i;
|
||||
memset(chip, 0, sizeof(opll_t));
|
||||
|
|
2
extern/Nuked-OPLL/opll.h
vendored
2
extern/Nuked-OPLL/opll.h
vendored
|
@ -193,6 +193,8 @@ typedef struct {
|
|||
|
||||
} opll_t;
|
||||
|
||||
const opll_patch_t* OPLL_GetPatchROM(uint32_t chip_type);
|
||||
|
||||
void OPLL_Reset(opll_t *chip, uint32_t chip_type);
|
||||
void OPLL_Clock(opll_t *chip, int32_t *buffer);
|
||||
void OPLL_Write(opll_t *chip, uint32_t port, uint8_t data);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
#include <SDL_render.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
|
@ -184,6 +185,7 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
|
|||
|
||||
// Bind texture, Draw
|
||||
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
|
||||
SDL_SetTextureScaleMode(tex, SDL_ScaleModeBest); // ???
|
||||
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
|
||||
xy, (int)sizeof(ImDrawVert),
|
||||
color, (int)sizeof(ImDrawVert),
|
||||
|
|
|
@ -80,4 +80,4 @@ TODO: image
|
|||
|
||||
sliders are used for controlling values in a quick manner by being dragged.
|
||||
|
||||
alternatively, Ctrl-clicking a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input fine values.
|
||||
alternatively, right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input fine values.
|
||||
|
|
|
@ -10,6 +10,7 @@ this is a list of systems that Furnace supports, including each system's effects
|
|||
- [Commodore 64](c64.md)
|
||||
- [Arcade (YM2151/PCM)](arcade.md)
|
||||
- [Neo Geo/YM2610](ym2610.md)
|
||||
- [Taito Arcade/YM2610B](ym2610b.md)
|
||||
- [AY-3-8910](ay8910.md)
|
||||
- [Amiga](amiga.md)
|
||||
- [Yamaha YM2612 standalone](ym2612.md)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
originally an arcade board, but SNK shortly adapted it to a rather expensive video game console with the world's biggest cartridges because some people liked the system so much they wanted a home version of it.
|
||||
|
||||
its soundchip is a 3-in-1: FM, YM2149 (AY-3-8910 clone) and ADPCM in a single package!
|
||||
its soundchip is a 3-in-1: FM, YM2149 (AY-3-8910 clone) and 2 different format ADPCM in a single package!
|
||||
|
||||
# effects
|
||||
|
||||
|
|
57
papers/doc/7-systems/ym2610b.md
Normal file
57
papers/doc/7-systems/ym2610b.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Taito Arcade/Yamaha YM2610B
|
||||
|
||||
YM2610B is basically YM2610 with 2 extra FM channels used at some 90s Taito Arcade hardwares, it's backward compatible with non-B chip.
|
||||
|
||||
# effects
|
||||
|
||||
- `10xy`: set LFO parameters.
|
||||
- `x` toggles the LFO.
|
||||
- `y` sets its speed.
|
||||
- `11xx`: set feedback of channel.
|
||||
- `12xx`: set operator 1 level.
|
||||
- `13xx`: set operator 2 level.
|
||||
- `14xx`: set operator 3 level.
|
||||
- `15xx`: set operator 4 level.
|
||||
- `16xy`: set multiplier of operator.
|
||||
- `x` is the operator (1-4).
|
||||
- `y` is the mutliplier.
|
||||
- `18xx`: toggle extended channel 2 mode.
|
||||
- 0 disables it and 1 enables it.
|
||||
- only in extended channel 2 system.
|
||||
- `19xx`: set attack of all operators.
|
||||
- `1Axx`: set attack of operator 1.
|
||||
- `1Bxx`: set attack of operator 2.
|
||||
- `1Cxx`: set attack of operator 3.
|
||||
- `1Dxx`: set attack of operator 4.
|
||||
- `20xx`: set SSG channel mode. `xx` may be one of the following:
|
||||
- `00`: square
|
||||
- `01`: noise
|
||||
- `02`: square and noise
|
||||
- `03`: nothing (apparently)
|
||||
- `04`: envelope and square
|
||||
- `05`: envelope and noise
|
||||
- `06`: envelope and square and noise
|
||||
- `07`: nothing
|
||||
- `21xx`: set noise frequency. `xx` is a value between 00 and 1F.
|
||||
- `22xy`: set envelope mode.
|
||||
- `x` sets the envelope shape, which may be one of the following:
|
||||
- `0: \___` decay
|
||||
- `4: /___` attack once
|
||||
- `8: \\\\` saw
|
||||
- `9: \___` decay
|
||||
- `A: \/\/` inverse obelisco
|
||||
- `B: \¯¯¯` decay once
|
||||
- `C: ////` inverse saw
|
||||
- `D: /¯¯¯` attack
|
||||
- `E: /\/\` obelisco
|
||||
- `F: /___` attack once
|
||||
- if `y` is 1 then the envelope will affect this channel.
|
||||
- `23xx`: set envelope period low byte.
|
||||
- `24xx`: set envelope period high byte.
|
||||
- `25xx`: slide envelope period up.
|
||||
- `26xx`: slide envelope period down.
|
||||
- `29xy`: enable SSG auto-envelope mode.
|
||||
- in this mode the envelope period is set to the channel's notes, multiplied by a fraction.
|
||||
- `x` is the numerator.
|
||||
- `y` is the denominator.
|
||||
- if `x` or `y` are 0 this will disable auto-envelope mode.
|
|
@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 61: Furnace dev61
|
||||
- 60: Furnace dev60
|
||||
- 59: Furnace dev59
|
||||
- 58: Furnace dev58
|
||||
|
@ -167,6 +168,7 @@ size | description
|
|||
| - 0xa6: OPL3 4-op + drums (YMF262) - 14 channels
|
||||
| - 0xa7: OPLL drums (YM2413) - 11 channels
|
||||
| - 0xa8: Atari Lynx - 4 channels
|
||||
| - 0xde: YM2610B extended - 19 channels
|
||||
| - 0xe0: QSound - 19 channels
|
||||
| - (compound!) means that the system is composed of two or more chips,
|
||||
| and has to be flattened.
|
||||
|
@ -174,7 +176,7 @@ size | description
|
|||
| - signed char, 64=1.0, 127=~2.0
|
||||
32 | sound chip panning
|
||||
| - signed char, -128=left, 127=right
|
||||
128 | sound chip parameters (TODO)
|
||||
128 | sound chip parameters
|
||||
STR | song name
|
||||
STR | song author
|
||||
4f | A-4 tuning
|
||||
|
@ -426,6 +428,48 @@ size | description
|
|||
4 | DT macro release
|
||||
4 | D2R macro release
|
||||
4 | SSG-EG macro release
|
||||
--- | **extended op macro headers** × 4 (>=61)
|
||||
4 | DAM macro length
|
||||
4 | DVB macro length
|
||||
4 | EGT macro length
|
||||
4 | KSL macro length
|
||||
4 | SUS macro length
|
||||
4 | VIB macro length
|
||||
4 | WS macro length
|
||||
4 | KSR macro length
|
||||
4 | DAM macro loop
|
||||
4 | DVB macro loop
|
||||
4 | EGT macro loop
|
||||
4 | KSL macro loop
|
||||
4 | SUS macro loop
|
||||
4 | VIB macro loop
|
||||
4 | WS macro loop
|
||||
4 | KSR macro loop
|
||||
4 | DAM macro release
|
||||
4 | DVB macro release
|
||||
4 | EGT macro release
|
||||
4 | KSL macro release
|
||||
4 | SUS macro release
|
||||
4 | VIB macro release
|
||||
4 | WS macro release
|
||||
4 | KSR macro release
|
||||
1 | DAM macro open
|
||||
1 | DVB macro open
|
||||
1 | EGT macro open
|
||||
1 | KSL macro open
|
||||
1 | SUS macro open
|
||||
1 | VIB macro open
|
||||
1 | WS macro open
|
||||
1 | KSR macro open
|
||||
--- | **extended op macros** × 4 (>=61)
|
||||
1?? | DAM macro
|
||||
1?? | DVB macro
|
||||
1?? | EGT macro
|
||||
1?? | KSL macro
|
||||
1?? | SUS macro
|
||||
1?? | VIB macro
|
||||
1?? | WS macro
|
||||
1?? | KSR macro
|
||||
```
|
||||
|
||||
# wavetable
|
||||
|
|
|
@ -128,11 +128,6 @@ class TAMidiOut {
|
|||
bool send(TAMidiMessage& what);
|
||||
};
|
||||
|
||||
class TAMidi {
|
||||
std::vector<TAMidiIn*> in;
|
||||
std::vector<TAMidiOut*> out;
|
||||
};
|
||||
|
||||
class TAAudio {
|
||||
protected:
|
||||
TAAudioDesc desc;
|
||||
|
@ -145,7 +140,8 @@ class TAAudio {
|
|||
void (*sampleRateChanged)(SampleRateChangeEvent);
|
||||
void (*bufferSizeChanged)(BufferSizeChangeEvent);
|
||||
public:
|
||||
TAMidi* midi;
|
||||
std::vector<TAMidiIn*> midiIn;
|
||||
std::vector<TAMidiOut*> midiOut;
|
||||
void setSampleRateChangeCallback(void (*callback)(SampleRateChangeEvent));
|
||||
void setBufferSizeChangeCallback(void (*callback)(BufferSizeChangeEvent));
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "platform/arcade.h"
|
||||
#include "platform/ym2610.h"
|
||||
#include "platform/ym2610ext.h"
|
||||
#include "platform/ym2610b.h"
|
||||
#include "platform/ym2610bext.h"
|
||||
#include "platform/ay.h"
|
||||
#include "platform/ay8930.h"
|
||||
#include "platform/tia.h"
|
||||
|
@ -182,6 +184,12 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
dispatch=new DivPlatformYM2610Ext;
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
dispatch=new DivPlatformYM2610B;
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
dispatch=new DivPlatformYM2610BExt;
|
||||
break;
|
||||
case DIV_SYSTEM_AMIGA:
|
||||
dispatch=new DivPlatformAmiga;
|
||||
break;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "dataErrors.h"
|
||||
#include "song.h"
|
||||
#include <cstddef>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "engine.h"
|
||||
#include "instrument.h"
|
||||
|
@ -501,6 +502,7 @@ void DivEngine::renderSamples() {
|
|||
|
||||
// step 4: allocate qsound pcm samples
|
||||
if (qsoundMem==NULL) qsoundMem=new unsigned char[16777216];
|
||||
memset(qsoundMem,0,16777216);
|
||||
|
||||
memPos=0;
|
||||
for (int i=0; i<song.sampleLen; i++) {
|
||||
|
@ -532,13 +534,25 @@ void DivEngine::renderSamples() {
|
|||
qsoundMemLen=memPos+256;
|
||||
}
|
||||
|
||||
void DivEngine::createNew() {
|
||||
DivSystem sys=song.system[0];
|
||||
void DivEngine::createNew(const int* description) {
|
||||
quitDispatch();
|
||||
isBusy.lock();
|
||||
song.unload();
|
||||
song=DivSong();
|
||||
song.system[0]=sys;
|
||||
if (description!=NULL) {
|
||||
if (description[0]!=0) {
|
||||
int index=0;
|
||||
for (int i=0; description[i]; i+=4) {
|
||||
song.system[index]=(DivSystem)description[i];
|
||||
song.systemVol[index]=description[i+1];
|
||||
song.systemPan[index]=description[i+2];
|
||||
song.systemFlags[index]=description[i+3];
|
||||
index++;
|
||||
if (index>=32) break;
|
||||
}
|
||||
song.systemLen=index;
|
||||
}
|
||||
}
|
||||
recalcChans();
|
||||
renderSamples();
|
||||
isBusy.unlock();
|
||||
|
@ -933,7 +947,9 @@ int DivEngine::getEffectiveSampleRate(int rate) {
|
|||
return 1789773/(1789773/rate);
|
||||
case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return (31250*MIN(255,(rate*255/31250)))/255;
|
||||
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL: case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return (24038*MIN(65535,(rate*4096/24038)))/4096;
|
||||
case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL: case DIV_SYSTEM_YM2610_FULL_EXT: case DIV_SYSTEM_YM2610B: case DIV_SYSTEM_YM2610B_EXT:
|
||||
return 18518;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
warnings+=(String("\n")+x); \
|
||||
}
|
||||
|
||||
#define DIV_VERSION "dev60"
|
||||
#define DIV_ENGINE_VERSION 60
|
||||
#define DIV_VERSION "dev61"
|
||||
#define DIV_ENGINE_VERSION 61
|
||||
|
||||
enum DivStatusView {
|
||||
DIV_STATUS_NOTHING=0,
|
||||
|
@ -262,7 +262,7 @@ class DivEngine {
|
|||
DivWavetable* getWave(int index);
|
||||
DivSample* getSample(int index);
|
||||
// start fresh
|
||||
void createNew();
|
||||
void createNew(const int* description);
|
||||
// load a file.
|
||||
bool load(unsigned char* f, size_t length);
|
||||
// save as .dmf.
|
||||
|
|
|
@ -148,7 +148,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
// Neo Geo detune
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT) {
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610_FULL || ds.system[0]==DIV_SYSTEM_YM2610_FULL_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610B || ds.system[0]==DIV_SYSTEM_YM2610B_EXT) {
|
||||
ds.tuning=443.23;
|
||||
}
|
||||
|
||||
|
@ -256,7 +258,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
if (ds.system[0]==DIV_SYSTEM_C64_8580 || ds.system[0]==DIV_SYSTEM_C64_6581) {
|
||||
ins->type=DIV_INS_C64;
|
||||
}
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT) {
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610_FULL || ds.system[0]==DIV_SYSTEM_YM2610_FULL_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610B || ds.system[0]==DIV_SYSTEM_YM2610B_EXT) {
|
||||
if (!ins->mode) {
|
||||
ins->type=DIV_INS_AY;
|
||||
}
|
||||
|
|
|
@ -302,6 +302,75 @@ void DivInstrument::putInsData(SafeWriter* w) {
|
|||
w->writeI(op.d2rMacroRel);
|
||||
w->writeI(op.ssgMacroRel);
|
||||
}
|
||||
|
||||
// extended op macros
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
|
||||
w->writeI(op.damMacroLen);
|
||||
w->writeI(op.dvbMacroLen);
|
||||
w->writeI(op.egtMacroLen);
|
||||
w->writeI(op.kslMacroLen);
|
||||
w->writeI(op.susMacroLen);
|
||||
w->writeI(op.vibMacroLen);
|
||||
w->writeI(op.wsMacroLen);
|
||||
w->writeI(op.ksrMacroLen);
|
||||
|
||||
w->writeI(op.damMacroLoop);
|
||||
w->writeI(op.dvbMacroLoop);
|
||||
w->writeI(op.egtMacroLoop);
|
||||
w->writeI(op.kslMacroLoop);
|
||||
w->writeI(op.susMacroLoop);
|
||||
w->writeI(op.vibMacroLoop);
|
||||
w->writeI(op.wsMacroLoop);
|
||||
w->writeI(op.ksrMacroLoop);
|
||||
|
||||
w->writeI(op.damMacroRel);
|
||||
w->writeI(op.dvbMacroRel);
|
||||
w->writeI(op.egtMacroRel);
|
||||
w->writeI(op.kslMacroRel);
|
||||
w->writeI(op.susMacroRel);
|
||||
w->writeI(op.vibMacroRel);
|
||||
w->writeI(op.wsMacroRel);
|
||||
w->writeI(op.ksrMacroRel);
|
||||
|
||||
w->writeC(op.damMacroOpen);
|
||||
w->writeC(op.dvbMacroOpen);
|
||||
w->writeC(op.egtMacroOpen);
|
||||
w->writeC(op.kslMacroOpen);
|
||||
w->writeC(op.susMacroOpen);
|
||||
w->writeC(op.vibMacroOpen);
|
||||
w->writeC(op.wsMacroOpen);
|
||||
w->writeC(op.ksrMacroOpen);
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
for (int j=0; j<op.damMacroLen; j++) {
|
||||
w->writeC(op.damMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.dvbMacroLen; j++) {
|
||||
w->writeC(op.dvbMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.egtMacroLen; j++) {
|
||||
w->writeC(op.egtMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.kslMacroLen; j++) {
|
||||
w->writeC(op.kslMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.susMacroLen; j++) {
|
||||
w->writeC(op.susMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.vibMacroLen; j++) {
|
||||
w->writeC(op.vibMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.wsMacroLen; j++) {
|
||||
w->writeC(op.wsMacro[j]);
|
||||
}
|
||||
for (int j=0; j<op.ksrMacroLen; j++) {
|
||||
w->writeC(op.ksrMacro[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
||||
|
@ -570,6 +639,61 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) {
|
|||
}
|
||||
}
|
||||
|
||||
// extended op macros
|
||||
if (version>=61) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
|
||||
op.damMacroLen=reader.readI();
|
||||
op.dvbMacroLen=reader.readI();
|
||||
op.egtMacroLen=reader.readI();
|
||||
op.kslMacroLen=reader.readI();
|
||||
op.susMacroLen=reader.readI();
|
||||
op.vibMacroLen=reader.readI();
|
||||
op.wsMacroLen=reader.readI();
|
||||
op.ksrMacroLen=reader.readI();
|
||||
|
||||
op.damMacroLoop=reader.readI();
|
||||
op.dvbMacroLoop=reader.readI();
|
||||
op.egtMacroLoop=reader.readI();
|
||||
op.kslMacroLoop=reader.readI();
|
||||
op.susMacroLoop=reader.readI();
|
||||
op.vibMacroLoop=reader.readI();
|
||||
op.wsMacroLoop=reader.readI();
|
||||
op.ksrMacroLoop=reader.readI();
|
||||
|
||||
op.damMacroRel=reader.readI();
|
||||
op.dvbMacroRel=reader.readI();
|
||||
op.egtMacroRel=reader.readI();
|
||||
op.kslMacroRel=reader.readI();
|
||||
op.susMacroRel=reader.readI();
|
||||
op.vibMacroRel=reader.readI();
|
||||
op.wsMacroRel=reader.readI();
|
||||
op.ksrMacroRel=reader.readI();
|
||||
|
||||
op.damMacroOpen=reader.readC();
|
||||
op.dvbMacroOpen=reader.readC();
|
||||
op.egtMacroOpen=reader.readC();
|
||||
op.kslMacroOpen=reader.readC();
|
||||
op.susMacroOpen=reader.readC();
|
||||
op.vibMacroOpen=reader.readC();
|
||||
op.wsMacroOpen=reader.readC();
|
||||
op.ksrMacroOpen=reader.readC();
|
||||
}
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentSTD::OpMacro& op=std.opMacros[i];
|
||||
reader.read(op.damMacro,op.damMacroLen);
|
||||
reader.read(op.dvbMacro,op.dvbMacroLen);
|
||||
reader.read(op.egtMacro,op.egtMacroLen);
|
||||
reader.read(op.kslMacro,op.kslMacroLen);
|
||||
reader.read(op.susMacro,op.susMacroLen);
|
||||
reader.read(op.vibMacro,op.vibMacroLen);
|
||||
reader.read(op.wsMacro,op.wsMacroLen);
|
||||
reader.read(op.ksrMacro,op.ksrMacroLen);
|
||||
}
|
||||
}
|
||||
|
||||
return DIV_DATA_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,26 @@ enum DivInstrumentType {
|
|||
DIV_INS_MIKEY=23,
|
||||
};
|
||||
|
||||
// FM operator structure:
|
||||
// - OPN:
|
||||
// - AM, AR, DR, MULT, RR, SL, TL, RS, DT, D2R, SSG-EG
|
||||
// - OPM:
|
||||
// - AM, AR, DR, MULT, RR, SL, TL, DT2, RS, DT, D2R
|
||||
// - OPLL:
|
||||
// - AM, AR, DR, MULT, RR, SL, TL, SSG-EG&8 = EG-S
|
||||
// - KSL, VIB, KSR
|
||||
// - OPL:
|
||||
// - AM, AR, DR, MULT, RR, SL, TL, SSG-EG&8 = EG-S
|
||||
// - KSL, VIB, WS (OPL2/3), KSR
|
||||
// - OPZ: NOT FINAL!
|
||||
// - AM, AR, DR, MULT (CRS), RR, SL, TL, DT2, RS, DT, D2R
|
||||
// - KSL = LS, WS, DVB = MULT (FINE), DAM = REV, EGT = EGShift
|
||||
|
||||
struct DivInstrumentFM {
|
||||
unsigned char alg, fb, fms, ams, ops, opllPreset;
|
||||
struct Operator {
|
||||
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
|
||||
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ
|
||||
Operator():
|
||||
am(0),
|
||||
ar(0),
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
} \
|
||||
}
|
||||
|
||||
// CPU hell
|
||||
void DivMacroInt::next() {
|
||||
if (ins==NULL) return;
|
||||
|
||||
|
@ -79,6 +80,16 @@ void DivMacroInt::next() {
|
|||
doMacro(o.finishedDt,o.hadDt,o.hasDt,o.dt,o.dtPos,m.dtMacro,m.dtMacroLen,m.dtMacroLoop,m.dtMacroRel);
|
||||
doMacro(o.finishedD2r,o.hadD2r,o.hasD2r,o.d2r,o.d2rPos,m.d2rMacro,m.d2rMacroLen,m.d2rMacroLoop,m.d2rMacroRel);
|
||||
doMacro(o.finishedSsg,o.hadSsg,o.hasSsg,o.ssg,o.ssgPos,m.ssgMacro,m.ssgMacroLen,m.ssgMacroLoop,m.ssgMacroRel);
|
||||
|
||||
doMacro(o.finishedDam,o.hadDam,o.hasDam,o.dam,o.damPos,m.damMacro,m.damMacroLen,m.damMacroLoop,m.damMacroRel);
|
||||
doMacro(o.finishedDvb,o.hadDvb,o.hasDvb,o.dvb,o.dvbPos,m.dvbMacro,m.dvbMacroLen,m.dvbMacroLoop,m.dvbMacroRel);
|
||||
doMacro(o.finishedEgt,o.hadEgt,o.hasEgt,o.egt,o.egtPos,m.egtMacro,m.egtMacroLen,m.egtMacroLoop,m.egtMacroRel);
|
||||
doMacro(o.finishedKsl,o.hadKsl,o.hasKsl,o.ksl,o.kslPos,m.kslMacro,m.kslMacroLen,m.kslMacroLoop,m.kslMacroRel);
|
||||
|
||||
doMacro(o.finishedSus,o.hadSus,o.hasSus,o.sus,o.susPos,m.susMacro,m.susMacroLen,m.susMacroLoop,m.susMacroRel);
|
||||
doMacro(o.finishedVib,o.hadVib,o.hasVib,o.vib,o.vibPos,m.vibMacro,m.vibMacroLen,m.vibMacroLoop,m.vibMacroRel);
|
||||
doMacro(o.finishedWs,o.hadWs,o.hasWs,o.ws,o.wsPos,m.wsMacro,m.wsMacroLen,m.wsMacroLoop,m.wsMacroRel);
|
||||
doMacro(o.finishedKsr,o.hadKsr,o.hasKsr,o.ksr,o.ksrPos,m.ksrMacro,m.ksrMacroLen,m.ksrMacroLoop,m.ksrMacroRel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,6 +291,47 @@ void DivMacroInt::init(DivInstrument* which) {
|
|||
o.hasSsg=true;
|
||||
o.willSsg=true;
|
||||
}
|
||||
|
||||
if (m.damMacroLen>0) {
|
||||
o.hadDam=true;
|
||||
o.hasDam=true;
|
||||
o.willDam=true;
|
||||
}
|
||||
if (m.dvbMacroLen>0) {
|
||||
o.hadDvb=true;
|
||||
o.hasDvb=true;
|
||||
o.willDvb=true;
|
||||
}
|
||||
if (m.egtMacroLen>0) {
|
||||
o.hadEgt=true;
|
||||
o.hasEgt=true;
|
||||
o.willEgt=true;
|
||||
}
|
||||
if (m.kslMacroLen>0) {
|
||||
o.hadKsl=true;
|
||||
o.hasKsl=true;
|
||||
o.willKsl=true;
|
||||
}
|
||||
if (m.susMacroLen>0) {
|
||||
o.hadSus=true;
|
||||
o.hasSus=true;
|
||||
o.willSus=true;
|
||||
}
|
||||
if (m.vibMacroLen>0) {
|
||||
o.hadVib=true;
|
||||
o.hasVib=true;
|
||||
o.willVib=true;
|
||||
}
|
||||
if (m.wsMacroLen>0) {
|
||||
o.hadWs=true;
|
||||
o.hasWs=true;
|
||||
o.willWs=true;
|
||||
}
|
||||
if (m.ksrMacroLen>0) {
|
||||
o.hadKsr=true;
|
||||
o.hasKsr=true;
|
||||
o.willKsr=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,26 +42,38 @@ class DivMacroInt {
|
|||
int amPos, arPos, drPos, multPos;
|
||||
int rrPos, slPos, tlPos, dt2Pos;
|
||||
int rsPos, dtPos, d2rPos, ssgPos;
|
||||
int damPos, dvbPos, egtPos, kslPos;
|
||||
int susPos, vibPos, wsPos, ksrPos;
|
||||
|
||||
int am, ar, dr, mult;
|
||||
int rr, sl, tl, dt2;
|
||||
int rs, dt, d2r, ssg;
|
||||
int dam, dvb, egt, ksl;
|
||||
int sus, vib, ws, ksr;
|
||||
|
||||
bool hasAm, hasAr, hasDr, hasMult;
|
||||
bool hasRr, hasSl, hasTl, hasDt2;
|
||||
bool hasRs, hasDt, hasD2r, hasSsg;
|
||||
bool hasDam, hasDvb, hasEgt, hasKsl;
|
||||
bool hasSus, hasVib, hasWs, hasKsr;
|
||||
|
||||
bool hadAm, hadAr, hadDr, hadMult;
|
||||
bool hadRr, hadSl, hadTl, hadDt2;
|
||||
bool hadRs, hadDt, hadD2r, hadSsg;
|
||||
bool hadDam, hadDvb, hadEgt, hadKsl;
|
||||
bool hadSus, hadVib, hadWs, hadKsr;
|
||||
|
||||
bool finishedAm, finishedAr, finishedDr, finishedMult;
|
||||
bool finishedRr, finishedSl, finishedTl, finishedDt2;
|
||||
bool finishedRs, finishedDt, finishedD2r, finishedSsg;
|
||||
bool finishedDam, finishedDvb, finishedEgt, finishedKsl;
|
||||
bool finishedSus, finishedVib, finishedWs, finishedKsr;
|
||||
|
||||
bool willAm, willAr, willDr, willMult;
|
||||
bool willRr, willSl, willTl, willDt2;
|
||||
bool willRs, willDt, willD2r, willSsg;
|
||||
bool willDam, willDvb, willEgt, willKsl;
|
||||
bool willSus, willVib, willWs, willKsr;
|
||||
IntOp():
|
||||
amPos(0),
|
||||
arPos(0),
|
||||
|
@ -75,6 +87,14 @@ class DivMacroInt {
|
|||
dtPos(0),
|
||||
d2rPos(0),
|
||||
ssgPos(0),
|
||||
damPos(0),
|
||||
dvbPos(0),
|
||||
egtPos(0),
|
||||
kslPos(0),
|
||||
susPos(0),
|
||||
vibPos(0),
|
||||
wsPos(0),
|
||||
ksrPos(0),
|
||||
am(0),
|
||||
ar(0),
|
||||
dr(0),
|
||||
|
@ -87,18 +107,34 @@ class DivMacroInt {
|
|||
dt(0),
|
||||
d2r(0),
|
||||
ssg(0),
|
||||
dam(0),
|
||||
dvb(0),
|
||||
egt(0),
|
||||
ksl(0),
|
||||
sus(0),
|
||||
vib(0),
|
||||
ws(0),
|
||||
ksr(0),
|
||||
hasAm(false), hasAr(false), hasDr(false), hasMult(false),
|
||||
hasRr(false), hasSl(false), hasTl(false), hasDt2(false),
|
||||
hasRs(false), hasDt(false), hasD2r(false), hasSsg(false),
|
||||
hasDam(false), hasDvb(false), hasEgt(false), hasKsl(false),
|
||||
hasSus(false), hasVib(false), hasWs(false), hasKsr(false),
|
||||
hadAm(false), hadAr(false), hadDr(false), hadMult(false),
|
||||
hadRr(false), hadSl(false), hadTl(false), hadDt2(false),
|
||||
hadRs(false), hadDt(false), hadD2r(false), hadSsg(false),
|
||||
hadDam(false), hadDvb(false), hadEgt(false), hadKsl(false),
|
||||
hadSus(false), hadVib(false), hadWs(false), hadKsr(false),
|
||||
finishedAm(false), finishedAr(false), finishedDr(false), finishedMult(false),
|
||||
finishedRr(false), finishedSl(false), finishedTl(false), finishedDt2(false),
|
||||
finishedRs(false), finishedDt(false), finishedD2r(false), finishedSsg(false),
|
||||
finishedDam(false), finishedDvb(false), finishedEgt(false), finishedKsl(false),
|
||||
finishedSus(false), finishedVib(false), finishedWs(false), finishedKsr(false),
|
||||
willAm(false), willAr(false), willDr(false), willMult(false),
|
||||
willRr(false), willSl(false), willTl(false), willDt2(false),
|
||||
willRs(false), willDt(false), willD2r(false), willSsg(false) {}
|
||||
willRs(false), willDt(false), willD2r(false), willSsg(false),
|
||||
willDam(false), willDvb(false), willEgt(false), willKsl(false),
|
||||
willSus(false), willVib(false), willWs(false), willKsr(false) {}
|
||||
} op[4];
|
||||
void release();
|
||||
void next();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
|
||||
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
#define CHIP_FREQBASE 295017
|
||||
#define CHIP_FREQBASE 1180068
|
||||
|
||||
const char* DivPlatformOPLL::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
|
@ -76,7 +76,11 @@ const char* DivPlatformOPLL::getEffectName(unsigned char effect) {
|
|||
}
|
||||
|
||||
const unsigned char cycleMapOPLL[18]={
|
||||
1, 2, 0, 1, 2, 3, 4, 5, 3, 4, 5, 6, 7, 8, 6, 7, 8, 0
|
||||
8, 7, 6, 7, 8, 7, 8, 6, 0, 1, 2, 7, 8, 9, 3, 4, 5, 9
|
||||
};
|
||||
|
||||
const unsigned char drumSlot[11]={
|
||||
0, 0, 0, 0, 0, 0, 6, 7, 8, 8, 7
|
||||
};
|
||||
|
||||
void DivPlatformOPLL::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
|
@ -103,9 +107,9 @@ void DivPlatformOPLL::acquire_nuked(short* bufL, short* bufR, size_t start, size
|
|||
}
|
||||
}
|
||||
|
||||
unsigned char nextOut=cycleMapOPLL[(fm.cycles+17)%18];
|
||||
OPLL_Clock(&fm,o);
|
||||
if (!isMuted[nextOut]) {
|
||||
unsigned char nextOut=cycleMapOPLL[fm.cycles];
|
||||
if ((nextOut>=6 && properDrums) || !isMuted[nextOut]) {
|
||||
os+=(o[0]+o[1]);
|
||||
}
|
||||
}
|
||||
|
@ -124,12 +128,12 @@ void DivPlatformOPLL::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
}
|
||||
|
||||
void DivPlatformOPLL::tick() {
|
||||
for (int i=0; i<9; i++) {
|
||||
for (int i=0; i<11; i++) {
|
||||
chan[i].std.next();
|
||||
|
||||
if (chan[i].std.hadVol) {
|
||||
chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol))/127;
|
||||
rWrite(0x30+i,(15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)|(chan[i].state.opllPreset<<4));
|
||||
chan[i].outVol=(chan[i].vol*MIN(15,chan[i].std.vol))/15;
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
|
||||
if (chan[i].std.hadArp) {
|
||||
|
@ -147,80 +151,90 @@ void DivPlatformOPLL::tick() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (chan[i].std.hadAlg) {
|
||||
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
if (chan[i].std.hadAlg) { // SUS
|
||||
chan[i].state.alg=chan[i].std.alg;
|
||||
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
if (chan[i].std.hadFb) {
|
||||
chan[i].state.fb=chan[i].std.fb;
|
||||
rWrite(0x03,(chan[i].state.op[0].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
if (chan[i].std.hadFms) {
|
||||
chan[i].state.fms=chan[i].std.fms;
|
||||
rWrite(0x03,(chan[i].state.op[0].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
if (chan[i].std.hadAms) {
|
||||
chan[i].state.ams=chan[i].std.ams;
|
||||
rWrite(0x03,(chan[i].state.op[0].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
|
||||
for (int j=0; j<2; j++) {
|
||||
unsigned short baseAddr=chanOffs[i]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[i].state.op[j];
|
||||
DivMacroInt::IntOp& m=chan[i].std.op[j];
|
||||
|
||||
if (m.hadAm) {
|
||||
op.am=m.am;
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.hadAr) {
|
||||
op.ar=m.ar;
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(0x04+j,(op.ar<<4)|(op.dr));
|
||||
}
|
||||
if (m.hadDr) {
|
||||
op.dr=m.dr;
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
rWrite(0x04+j,(op.ar<<4)|(op.dr));
|
||||
}
|
||||
if (m.hadMult) {
|
||||
op.mult=m.mult;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.hadRr) {
|
||||
op.rr=m.rr;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(0x06+j,(op.sl<<4)|(op.rr));
|
||||
}
|
||||
if (m.hadSl) {
|
||||
op.sl=m.sl;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(0x06+j,(op.sl<<4)|(op.rr));
|
||||
}
|
||||
if (m.hadTl) {
|
||||
op.tl=127-m.tl;
|
||||
if (isMuted[i]) {
|
||||
rWrite(baseAddr+ADDR_TL,127);
|
||||
op.tl=((j==1)?15:63)-m.tl;
|
||||
if (j==1) {
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
} else {
|
||||
if (isOutput[chan[i].state.alg][j]) {
|
||||
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
|
||||
rWrite(0x02,(chan[i].state.op[1].ksl<<6)|(op.tl&63));
|
||||
}
|
||||
}
|
||||
|
||||
if (m.hadEgt) {
|
||||
op.ssgEnv=(m.egt&1)?8:0;
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.hadKsl) {
|
||||
op.ksl=m.ksl;
|
||||
if (j==1) {
|
||||
rWrite(0x02,(op.ksl<<6)|(chan[i].state.op[0].tl&63));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_TL,op.tl);
|
||||
rWrite(0x03,(chan[i].state.op[0].ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
|
||||
}
|
||||
}
|
||||
if (m.hadKsr) {
|
||||
op.ksr=m.ksr;
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
if (m.hadVib) {
|
||||
op.vib=m.vib;
|
||||
rWrite(0x00+j,(op.am<<7)|(op.vib<<6)|((op.ssgEnv&8)<<2)|(op.ksr<<4)|(op.mult));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m.hadRs) {
|
||||
op.rs=m.rs;
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
if (m.hadDt) {
|
||||
op.dt=m.dt;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
if (m.hadD2r) {
|
||||
op.d2r=m.d2r;
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
if (m.hadSsg) {
|
||||
op.ssgEnv=m.ssg;
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (chan[i].keyOn || chan[i].keyOff) {
|
||||
if (i>=6 && drums) {
|
||||
if (i>=6 && properDrums) {
|
||||
drumState&=~(0x10>>(i-6));
|
||||
immWrite(0x0e,0x20|drumState);
|
||||
} else if (i>=6 && drums) {
|
||||
drumState&=~(0x10>>(chan[i].note%12));
|
||||
immWrite(0x0e,0x20|drumState);
|
||||
} else {
|
||||
|
@ -238,23 +252,32 @@ void DivPlatformOPLL::tick() {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<9; i++) {
|
||||
for (int i=0; i<11; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq));
|
||||
if (chan[i].freq>262143) chan[i].freq=262143;
|
||||
int freqt=toFreq(chan[i].freq);
|
||||
chan[i].freqH=freqt>>8;
|
||||
chan[i].freqL=freqt&0xff;
|
||||
if (i<6 || !drums) {
|
||||
if (i>=6 && properDrums) {
|
||||
immWrite(0x10+drumSlot[i],freqt&0xff);
|
||||
immWrite(0x20+drumSlot[i],freqt>>8);
|
||||
} else if (i<6 || !drums) {
|
||||
immWrite(0x10+i,freqt&0xff);
|
||||
}
|
||||
}
|
||||
if (chan[i].keyOn && i>=6 && drums) {
|
||||
if (chan[i].keyOn && i>=6 && properDrums) {
|
||||
if (!isMuted[i]) {
|
||||
drumState|=(0x10>>(i-6));
|
||||
immWrite(0x0e,0x20|drumState);
|
||||
}
|
||||
chan[i].keyOn=false;
|
||||
} else if (chan[i].keyOn && i>=6 && drums) {
|
||||
//printf("%d\n",chan[i].note%12);
|
||||
drumState|=(0x10>>(chan[i].note%12));
|
||||
immWrite(0x0e,0x20|drumState);
|
||||
chan[i].keyOn=false;
|
||||
} else if (chan[i].keyOn || chan[i].freqChanged) {
|
||||
} else if ((chan[i].keyOn || chan[i].freqChanged) && i<9) {
|
||||
//immWrite(0x28,0xf0|konOffs[i]);
|
||||
immWrite(0x20+i,(chan[i].freqH)|(chan[i].active<<4)|(chan[i].state.alg?0x20:0));
|
||||
chan[i].keyOn=false;
|
||||
|
@ -328,6 +351,7 @@ void DivPlatformOPLL::muteChannel(int ch, bool mute) {
|
|||
int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins);
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
@ -338,6 +362,18 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
|
||||
if (c.chan>=6 && properDrums) { // drums mode
|
||||
chan[c.chan].insChanged=false;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
chan[c.chan].keyOn=true;
|
||||
chan[c.chan].active=true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
// update custom preset
|
||||
if (chan[c.chan].state.opllPreset==0) {
|
||||
|
@ -351,6 +387,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
lastCustomMemory=c.chan;
|
||||
}
|
||||
if (chan[c.chan].state.opllPreset==16) { // compatible drums mode
|
||||
if (c.chan>=6) {
|
||||
|
@ -368,10 +405,12 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
}
|
||||
} else {
|
||||
if (c.chan>=6) {
|
||||
if (drums) {
|
||||
drums=false;
|
||||
immWrite(0x0e,0);
|
||||
}
|
||||
rWrite(0x30+c.chan,(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,26 +449,37 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].vol=c.value;
|
||||
if (!chan[c.chan].std.hasVol) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>=6 && properDrums) {
|
||||
drumVol[c.chan-6]=15-chan[c.chan].outVol;
|
||||
rWrite(0x36,drumVol[0]);
|
||||
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
|
||||
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
|
||||
break;
|
||||
}
|
||||
if (c.chan<6 || !drums) {
|
||||
rWrite(0x30+c.chan,(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)|(chan[c.chan].state.opllPreset<<4));
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -444,11 +494,13 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PITCH: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
|
@ -481,12 +533,14 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
//DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
|
@ -495,6 +549,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
}
|
||||
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
if (c.value==0) {
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
mod.mult=c.value2&15;
|
||||
|
@ -502,11 +557,12 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
} else {
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
car.mult=c.value2&15;
|
||||
rWrite(0x30+c.chan,(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)|(chan[c.chan].state.opllPreset<<4));
|
||||
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
if (c.value==0) {
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
|
@ -515,11 +571,12 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
} else {
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
car.tl=c.value2&15;
|
||||
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
|
||||
rWrite(0x30+c.chan,((15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)&15)|(chan[c.chan].state.opllPreset<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
|
@ -536,6 +593,18 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_EXTCH:
|
||||
if (!properDrumsSys) break;
|
||||
if (properDrums==c.value) break;
|
||||
if (c.value) {
|
||||
properDrums=true;
|
||||
immWrite(0x0e,0x20);
|
||||
} else {
|
||||
properDrums=false;
|
||||
immWrite(0x0e,0x00);
|
||||
drumState=0;
|
||||
}
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
|
@ -543,6 +612,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
return 15;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
chan[c.chan].inPorta=c.value;
|
||||
break;
|
||||
case DIV_CMD_PRE_NOTE:
|
||||
|
@ -557,7 +627,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
void DivPlatformOPLL::forceIns() {
|
||||
for (int i=0; i<9; i++) {
|
||||
// update custom preset
|
||||
if (chan[i].state.opllPreset==0) {
|
||||
if (chan[i].state.opllPreset==0 && i==lastCustomMemory) {
|
||||
DivInstrumentFM::Operator& mod=chan[i].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[i].state.op[1];
|
||||
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
|
||||
|
@ -569,10 +639,13 @@ void DivPlatformOPLL::forceIns() {
|
|||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
}
|
||||
rWrite(0x30+i,(15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)|(chan[i].state.opllPreset<<4));
|
||||
rWrite(0x30+i,((15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)&15)|(chan[i].state.opllPreset<<4));
|
||||
if (!(i>=6 && properDrums)) {
|
||||
if (chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (drums) {
|
||||
|
@ -587,6 +660,7 @@ void DivPlatformOPLL::forceIns() {
|
|||
immWrite(0x18,0xC0);
|
||||
immWrite(0x28,0x01);
|
||||
}
|
||||
drumState=0;
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::toggleRegisterDump(bool enable) {
|
||||
|
@ -599,6 +673,7 @@ void DivPlatformOPLL::setVRC7(bool vrc) {
|
|||
|
||||
void DivPlatformOPLL::setProperDrums(bool pd) {
|
||||
properDrums=pd;
|
||||
properDrumsSys=pd;
|
||||
}
|
||||
|
||||
|
||||
|
@ -621,11 +696,25 @@ void DivPlatformOPLL::reset() {
|
|||
OPLL_Reset(&fm,opll_type_ds1001);
|
||||
} else {
|
||||
OPLL_Reset(&fm,opll_type_ym2413);
|
||||
switch (patchSet) {
|
||||
case 0:
|
||||
fm.patchrom=OPLL_GetPatchROM(opll_type_ym2413);
|
||||
break;
|
||||
case 1:
|
||||
fm.patchrom=OPLL_GetPatchROM(opll_type_ymf281);
|
||||
break;
|
||||
case 2:
|
||||
fm.patchrom=OPLL_GetPatchROM(opll_type_ym2423);
|
||||
break;
|
||||
case 3:
|
||||
fm.patchrom=OPLL_GetPatchROM(opll_type_ds1001);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
for (int i=0; i<9; i++) {
|
||||
for (int i=0; i<11; i++) {
|
||||
chan[i]=DivPlatformOPLL::Channel();
|
||||
chan[i].vol=15;
|
||||
chan[i].outVol=15;
|
||||
|
@ -638,6 +727,7 @@ void DivPlatformOPLL::reset() {
|
|||
|
||||
lastBusy=60;
|
||||
drumState=0;
|
||||
lastCustomMemory=-1;
|
||||
|
||||
drumVol[0]=0;
|
||||
drumVol[1]=0;
|
||||
|
@ -646,6 +736,12 @@ void DivPlatformOPLL::reset() {
|
|||
drumVol[4]=0;
|
||||
|
||||
delay=0;
|
||||
drums=false;
|
||||
properDrums=properDrumsSys;
|
||||
|
||||
if (properDrums) {
|
||||
immWrite(0x0e,0x20);
|
||||
}
|
||||
}
|
||||
|
||||
bool DivPlatformOPLL::keyOffAffectsArp(int ch) {
|
||||
|
@ -657,7 +753,7 @@ bool DivPlatformOPLL::keyOffAffectsPorta(int ch) {
|
|||
}
|
||||
|
||||
void DivPlatformOPLL::notifyInsChange(int ins) {
|
||||
for (int i=0; i<9; i++) {
|
||||
for (int i=0; i<11; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
@ -684,23 +780,25 @@ void DivPlatformOPLL::setYMFM(bool use) {
|
|||
}
|
||||
|
||||
void DivPlatformOPLL::setFlags(unsigned int flags) {
|
||||
if (flags==3) {
|
||||
chipClock=COLOR_NTSC;
|
||||
} else if (flags==2) {
|
||||
chipClock=8000000.0;
|
||||
} else if (flags==1) {
|
||||
chipClock=COLOR_PAL*1.0/5.0;
|
||||
if ((flags&15)==3) {
|
||||
chipClock=COLOR_NTSC/2.0;
|
||||
} else if ((flags&15)==2) {
|
||||
chipClock=4000000.0;
|
||||
} else if ((flags&15)==1) {
|
||||
chipClock=COLOR_PAL*4.0/5.0;
|
||||
} else {
|
||||
chipClock=COLOR_NTSC/4.0;
|
||||
chipClock=COLOR_NTSC;
|
||||
}
|
||||
rate=chipClock/9;
|
||||
rate=chipClock/36;
|
||||
patchSet=flags>>4;
|
||||
}
|
||||
|
||||
int DivPlatformOPLL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
for (int i=0; i<9; i++) {
|
||||
patchSet=0;
|
||||
for (int i=0; i<11; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
setFlags(flags);
|
||||
|
|
|
@ -67,7 +67,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
opll_t fm;
|
||||
int delay;
|
||||
int delay, lastCustomMemory;
|
||||
unsigned char lastBusy;
|
||||
unsigned char drumState;
|
||||
unsigned char drumVol[5];
|
||||
|
@ -76,9 +76,11 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
|
||||
bool useYMFM;
|
||||
bool drums;
|
||||
bool properDrums;
|
||||
bool properDrums, properDrumsSys;
|
||||
bool vrc7;
|
||||
|
||||
unsigned char patchSet;
|
||||
|
||||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
||||
|
|
|
@ -226,4 +226,6 @@ void apu_turn_on(struct NESAPU* a, BYTE apu_type) {
|
|||
a->DMC.length = 1;
|
||||
a->DMC.address_start = 0xC000;
|
||||
a->apu.odd_cycle = 0;
|
||||
// come non viene inizializzato? Vorrei qualche spiegazione...
|
||||
a->r4011.frames = 0;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,218 @@ static unsigned char konOffs[4]={
|
|||
|
||||
#define CHIP_DIVIDER 32
|
||||
|
||||
const char* regCheatSheetYM2610[]={
|
||||
// SSG
|
||||
"SSG_FreqL_A", "000",
|
||||
"SSG_FreqH_A", "001",
|
||||
"SSG_FreqL_B", "002",
|
||||
"SSG_FreqH_B", "003",
|
||||
"SSG_FreqL_C", "004",
|
||||
"SSG_FreqH_C", "005",
|
||||
"SSG_FreqNoise", "006",
|
||||
"SSG_Enable", "007",
|
||||
"SSG_Volume_A", "008",
|
||||
"SSG_Volume_B", "009",
|
||||
"SSG_Volume_C", "00A",
|
||||
"SSG_FreqL_Env", "00B",
|
||||
"SSG_FreqH_Env", "00C",
|
||||
"SSG_Control_Env", "00D",
|
||||
// ADPCM-B
|
||||
"ADPCMB_Control", "010",
|
||||
"ADPCMB_L_R", "011",
|
||||
"ADPCMB_StartL", "012",
|
||||
"ADPCMB_StartH", "013",
|
||||
"ADPCMB_EndL", "014",
|
||||
"ADPCMB_EndH", "015",
|
||||
"ADPCMB_FreqL", "019",
|
||||
"ADPCMB_FreqH", "01A",
|
||||
"ADPCMB_Volume", "01B",
|
||||
"ADPCM_Flag", "01C",
|
||||
// FM (Common)
|
||||
"FM_Test", "021",
|
||||
"FM_LFOFreq", "022",
|
||||
"ClockA1", "024",
|
||||
"ClockA2", "025",
|
||||
"ClockB", "026",
|
||||
"FM_Control", "027",
|
||||
"FM_NoteCtl", "028",
|
||||
// FM (Channel 1-2)
|
||||
"FM1_Op1_DT_MULT", "031",
|
||||
"FM2_Op1_DT_MULT", "032",
|
||||
"FM1_Op2_DT_MULT", "035",
|
||||
"FM2_Op2_DT_MULT", "036",
|
||||
"FM1_Op3_DT_MULT", "039",
|
||||
"FM2_Op3_DT_MULT", "03A",
|
||||
"FM1_Op4_DT_MULT", "03D",
|
||||
"FM2_Op4_DT_MULT", "03E",
|
||||
"FM1_Op1_TL", "041",
|
||||
"FM2_Op1_TL", "042",
|
||||
"FM1_Op2_TL", "045",
|
||||
"FM2_Op2_TL", "046",
|
||||
"FM1_Op3_TL", "049",
|
||||
"FM2_Op3_TL", "04A",
|
||||
"FM1_Op4_TL", "04D",
|
||||
"FM2_Op4_TL", "04E",
|
||||
"FM1_Op1_KS_AR", "051",
|
||||
"FM2_Op1_KS_AR", "052",
|
||||
"FM1_Op2_KS_AR", "055",
|
||||
"FM2_Op2_KS_AR", "056",
|
||||
"FM1_Op3_KS_AR", "059",
|
||||
"FM2_Op3_KS_AR", "05A",
|
||||
"FM1_Op4_KS_AR", "05D",
|
||||
"FM2_Op4_KS_AR", "05E",
|
||||
"FM1_Op1_AM_DR", "061",
|
||||
"FM2_Op1_AM_DR", "062",
|
||||
"FM1_Op2_AM_DR", "065",
|
||||
"FM2_Op2_AM_DR", "066",
|
||||
"FM1_Op3_AM_DR", "069",
|
||||
"FM2_Op3_AM_DR", "06A",
|
||||
"FM1_Op4_AM_DR", "06D",
|
||||
"FM2_Op4_AM_DR", "06E",
|
||||
"FM1_Op1_SR", "071",
|
||||
"FM2_Op1_SR", "072",
|
||||
"FM1_Op2_SR", "075",
|
||||
"FM2_Op2_SR", "076",
|
||||
"FM1_Op3_SR", "079",
|
||||
"FM2_Op3_SR", "07A",
|
||||
"FM1_Op4_SR", "07D",
|
||||
"FM2_Op4_SR", "07E",
|
||||
"FM1_Op1_SL_RR", "081",
|
||||
"FM2_Op1_SL_RR", "082",
|
||||
"FM1_Op2_SL_RR", "085",
|
||||
"FM2_Op2_SL_RR", "086",
|
||||
"FM1_Op3_SL_RR", "089",
|
||||
"FM2_Op3_SL_RR", "08A",
|
||||
"FM1_Op4_SL_RR", "08D",
|
||||
"FM2_Op4_SL_RR", "08E",
|
||||
"FM1_Op1_SSG_EG", "091",
|
||||
"FM2_Op1_SSG_EG", "092",
|
||||
"FM1_Op2_SSG_EG", "095",
|
||||
"FM2_Op2_SSG_EG", "096",
|
||||
"FM1_Op3_SSG_EG", "099",
|
||||
"FM2_Op3_SSG_EG", "09A",
|
||||
"FM1_Op4_SSG_EG", "09D",
|
||||
"FM2_Op4_SSG_EG", "09E",
|
||||
"FM1_FNum1", "0A1",
|
||||
"FM2_(Op1)FNum1", "0A2",
|
||||
"FM1_FNum2", "0A5",
|
||||
"FM2_(Op1)FNum2", "0A6",
|
||||
"FM2_Op2_FNum1", "0A8",
|
||||
"FM2_Op3_FNum1", "0A9",
|
||||
"FM2_Op4_FNum1", "0AA",
|
||||
"FM2_Op2_FNum2", "0AC",
|
||||
"FM2_Op3_FNum2", "0AD",
|
||||
"FM2_Op4_FNum2", "0AE",
|
||||
"FM1_FB_ALG", "0B1",
|
||||
"FM2_FB_ALG", "0B2",
|
||||
"FM1_Pan_LFO", "0B5",
|
||||
"FM2_Pan_LFO", "0B6",
|
||||
// ADPCM-A
|
||||
"ADPCMA_Control", "100",
|
||||
"ADPCMA_MVol", "101",
|
||||
"ADPCMA_Test", "102",
|
||||
"ADPCMA_Ch1_Vol", "108",
|
||||
"ADPCMA_Ch2_Vol", "109",
|
||||
"ADPCMA_Ch3_Vol", "10A",
|
||||
"ADPCMA_Ch4_Vol", "10B",
|
||||
"ADPCMA_Ch5_Vol", "10C",
|
||||
"ADPCMA_Ch6_Vol", "10D",
|
||||
"ADPCMA_Ch1_StL", "110",
|
||||
"ADPCMA_Ch2_StL", "111",
|
||||
"ADPCMA_Ch3_StL", "112",
|
||||
"ADPCMA_Ch4_StL", "113",
|
||||
"ADPCMA_Ch5_StL", "114",
|
||||
"ADPCMA_Ch6_StL", "115",
|
||||
"ADPCMA_Ch1_StH", "118",
|
||||
"ADPCMA_Ch2_StH", "119",
|
||||
"ADPCMA_Ch3_StH", "11A",
|
||||
"ADPCMA_Ch4_StH", "11B",
|
||||
"ADPCMA_Ch5_StH", "11C",
|
||||
"ADPCMA_Ch6_StH", "11D",
|
||||
"ADPCMA_Ch1_EdL", "120",
|
||||
"ADPCMA_Ch2_EdL", "121",
|
||||
"ADPCMA_Ch3_EdL", "122",
|
||||
"ADPCMA_Ch4_EdL", "123",
|
||||
"ADPCMA_Ch5_EdL", "124",
|
||||
"ADPCMA_Ch6_EdL", "125",
|
||||
"ADPCMA_Ch1_EdH", "128",
|
||||
"ADPCMA_Ch2_EdH", "129",
|
||||
"ADPCMA_Ch3_EdH", "12A",
|
||||
"ADPCMA_Ch4_EdH", "12B",
|
||||
"ADPCMA_Ch5_EdH", "12C",
|
||||
"ADPCMA_Ch6_EdH", "12D",
|
||||
// FM (Channel 3-4)
|
||||
"FM3_Op1_DT_MULT", "131",
|
||||
"FM4_Op1_DT_MULT", "132",
|
||||
"FM3_Op2_DT_MULT", "135",
|
||||
"FM4_Op2_DT_MULT", "136",
|
||||
"FM3_Op3_DT_MULT", "139",
|
||||
"FM4_Op3_DT_MULT", "13A",
|
||||
"FM3_Op4_DT_MULT", "13D",
|
||||
"FM4_Op4_DT_MULT", "13E",
|
||||
"FM3_Op1_TL", "141",
|
||||
"FM4_Op1_TL", "142",
|
||||
"FM3_Op2_TL", "145",
|
||||
"FM4_Op2_TL", "146",
|
||||
"FM3_Op3_TL", "149",
|
||||
"FM4_Op3_TL", "14A",
|
||||
"FM3_Op4_TL", "14D",
|
||||
"FM4_Op4_TL", "14E",
|
||||
"FM3_Op1_KS_AR", "151",
|
||||
"FM4_Op1_KS_AR", "152",
|
||||
"FM3_Op2_KS_AR", "155",
|
||||
"FM4_Op2_KS_AR", "156",
|
||||
"FM3_Op3_KS_AR", "159",
|
||||
"FM4_Op3_KS_AR", "15A",
|
||||
"FM3_Op4_KS_AR", "15D",
|
||||
"FM4_Op4_KS_AR", "15E",
|
||||
"FM3_Op1_AM_DR", "161",
|
||||
"FM4_Op1_AM_DR", "162",
|
||||
"FM3_Op2_AM_DR", "165",
|
||||
"FM4_Op2_AM_DR", "166",
|
||||
"FM3_Op3_AM_DR", "169",
|
||||
"FM4_Op3_AM_DR", "16A",
|
||||
"FM3_Op4_AM_DR", "16D",
|
||||
"FM4_Op4_AM_DR", "16E",
|
||||
"FM3_Op1_SR", "171",
|
||||
"FM4_Op1_SR", "172",
|
||||
"FM3_Op2_SR", "175",
|
||||
"FM4_Op2_SR", "176",
|
||||
"FM3_Op3_SR", "179",
|
||||
"FM4_Op3_SR", "17A",
|
||||
"FM3_Op4_SR", "17D",
|
||||
"FM4_Op4_SR", "17E",
|
||||
"FM3_Op1_SL_RR", "181",
|
||||
"FM4_Op1_SL_RR", "182",
|
||||
"FM3_Op2_SL_RR", "185",
|
||||
"FM4_Op2_SL_RR", "186",
|
||||
"FM3_Op3_SL_RR", "189",
|
||||
"FM4_Op3_SL_RR", "18A",
|
||||
"FM3_Op4_SL_RR", "18D",
|
||||
"FM4_Op4_SL_RR", "18E",
|
||||
"FM3_Op1_SSG_EG", "191",
|
||||
"FM4_Op1_SSG_EG", "192",
|
||||
"FM3_Op2_SSG_EG", "195",
|
||||
"FM4_Op2_SSG_EG", "196",
|
||||
"FM3_Op3_SSG_EG", "199",
|
||||
"FM4_Op3_SSG_EG", "19A",
|
||||
"FM3_Op4_SSG_EG", "19D",
|
||||
"FM4_Op4_SSG_EG", "19E",
|
||||
"FM3_FNum1", "1A1",
|
||||
"FM4_FNum1", "1A2",
|
||||
"FM3_FNum2", "1A5",
|
||||
"FM4_FNum2", "1A6",
|
||||
"FM3_FB_ALG", "1B1",
|
||||
"FM4_FB_ALG", "1B2",
|
||||
"FM3_Pan_LFO", "1B5",
|
||||
"FM4_Pan_LFO", "1B6",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char** DivPlatformYM2610::getRegisterSheet() {
|
||||
return regCheatSheetYM2610;
|
||||
}
|
||||
|
||||
const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
|
@ -486,7 +698,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,0x80); // start
|
||||
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].baseFreq=NOTE_ADPCMB(chan[c.chan].note);
|
||||
|
@ -512,7 +724,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
immWrite(0x14,(end>>8)&0xff);
|
||||
immWrite(0x15,end>>16);
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
immWrite(0x10,0x80); // start
|
||||
immWrite(0x10,(s->loopStart>=0)?0x90:0x80); // start/repeat
|
||||
chan[c.chan].baseFreq=(((unsigned int)s->rate)<<16)/(chipClock/144);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ class DivYM2610Interface: public ymfm::ymfm_interface {
|
|||
|
||||
class DivPlatformYM2610: public DivDispatch {
|
||||
protected:
|
||||
const unsigned short chanOffs[4]={
|
||||
0x01, 0x02, 0x101, 0x102
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
|
@ -123,6 +127,7 @@ class DivPlatformYM2610: public DivDispatch {
|
|||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
|
|
1352
src/engine/platform/ym2610b.cpp
Normal file
1352
src/engine/platform/ym2610b.cpp
Normal file
File diff suppressed because it is too large
Load diff
129
src/engine/platform/ym2610b.h
Normal file
129
src/engine/platform/ym2610b.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _YM2610B_H
|
||||
#define _YM2610B_H
|
||||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
#include "ym2610.h"
|
||||
|
||||
class DivPlatformYM2610B: public DivDispatch {
|
||||
protected:
|
||||
const unsigned short chanOffs[6]={
|
||||
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch, note;
|
||||
unsigned char ins, psgMode, autoEnvNum, autoEnvDen;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM;
|
||||
int vol, outVol;
|
||||
unsigned char pan;
|
||||
DivMacroInt std;
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
freq(0),
|
||||
baseFreq(0),
|
||||
pitch(0),
|
||||
note(0),
|
||||
ins(-1),
|
||||
psgMode(1),
|
||||
autoEnvNum(0),
|
||||
autoEnvDen(0),
|
||||
active(false),
|
||||
insChanged(true),
|
||||
freqChanged(false),
|
||||
keyOn(false),
|
||||
keyOff(false),
|
||||
portaPause(false),
|
||||
inPorta(false),
|
||||
furnacePCM(false),
|
||||
vol(0),
|
||||
outVol(15),
|
||||
pan(3) {}
|
||||
};
|
||||
Channel chan[16];
|
||||
bool isMuted[16];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
bool addrOrVal;
|
||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||
};
|
||||
std::queue<QueuedWrite> writes;
|
||||
ymfm::ym2610b* fm;
|
||||
ymfm::ym2610b::output_data fmout;
|
||||
DivYM2610Interface iface;
|
||||
unsigned char regPool[512];
|
||||
unsigned char lastBusy;
|
||||
|
||||
bool dacMode;
|
||||
int dacPeriod;
|
||||
int dacRate;
|
||||
int dacPos;
|
||||
int dacSample;
|
||||
int ayNoiseFreq;
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay;
|
||||
|
||||
bool extMode;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
unsigned char ayEnvMode;
|
||||
unsigned short ayEnvPeriod;
|
||||
short ayEnvSlideLow;
|
||||
short ayEnvSlide;
|
||||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
double NOTE_ADPCMB(int note);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
public:
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool isStereo();
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
const char** getRegisterSheet();
|
||||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformYM2610B();
|
||||
};
|
||||
#endif
|
337
src/engine/platform/ym2610bext.cpp
Normal file
337
src/engine/platform/ym2610bext.cpp
Normal file
|
@ -0,0 +1,337 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "ym2610bext.h"
|
||||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "ym2610shared.h"
|
||||
|
||||
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
return DivPlatformYM2610B::dispatch(c);
|
||||
}
|
||||
if (c.chan>5) {
|
||||
c.chan-=3;
|
||||
return DivPlatformYM2610B::dispatch(c);
|
||||
}
|
||||
int ch=c.chan-2;
|
||||
int ordch=orderedOps[ch];
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
// TODO: how does this work?!
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
}
|
||||
}
|
||||
if (opChan[ch].insChanged) {
|
||||
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
|
||||
rWrite(baseAddr+0x70,op.d2r&31);
|
||||
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
|
||||
rWrite(baseAddr+0x90,op.ssgEnv&15);
|
||||
}
|
||||
if (opChan[ch].insChanged) { // TODO how does this work?
|
||||
rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
|
||||
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
}
|
||||
opChan[ch].insChanged=false;
|
||||
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
opChan[ch].freqChanged=true;
|
||||
}
|
||||
opChan[ch].keyOn=true;
|
||||
opChan[ch].active=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
opChan[ch].keyOff=true;
|
||||
opChan[ch].keyOn=false;
|
||||
opChan[ch].active=false;
|
||||
break;
|
||||
case DIV_CMD_VOLUME: {
|
||||
opChan[ch].vol=c.value;
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLUME: {
|
||||
return opChan[ch].vol;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_INSTRUMENT:
|
||||
if (opChan[ch].ins!=c.value || c.value2==1) {
|
||||
opChan[ch].insChanged=true;
|
||||
}
|
||||
opChan[ch].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
switch (c.value) {
|
||||
case 0x01:
|
||||
opChan[ch].pan=1;
|
||||
break;
|
||||
case 0x10:
|
||||
opChan[ch].pan=2;
|
||||
break;
|
||||
default:
|
||||
opChan[ch].pan=3;
|
||||
break;
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
// TODO: ???
|
||||
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_PITCH: {
|
||||
opChan[ch].pitch=c.value;
|
||||
opChan[ch].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
int destFreq=NOTE_FREQUENCY(c.value2);
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
if (destFreq>opChan[ch].baseFreq) {
|
||||
newFreq=opChan[ch].baseFreq+c.value*octave(opChan[ch].baseFreq);
|
||||
if (newFreq>=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
newFreq=opChan[ch].baseFreq-c.value*octave(opChan[ch].baseFreq);
|
||||
if (newFreq<=destFreq) {
|
||||
newFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
if (!opChan[ch].portaPause) {
|
||||
if (octave(opChan[ch].baseFreq)!=octave(newFreq)) {
|
||||
opChan[ch].portaPause=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
opChan[ch].baseFreq=newFreq;
|
||||
opChan[ch].portaPause=false;
|
||||
opChan[ch].freqChanged=true;
|
||||
if (return2) return 2;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
opChan[ch].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: { // TODO
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
if (isOutput[ins->fm.alg][c.value]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,c.value2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
return 0;
|
||||
break;
|
||||
case DIV_CMD_PRE_PORTA:
|
||||
break;
|
||||
default:
|
||||
//printf("WARNING: unimplemented command %d\n",c.cmd);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opChanOffsL[4]={
|
||||
0xa9, 0xaa, 0xa8, 0xa2
|
||||
};
|
||||
|
||||
static int opChanOffsH[4]={
|
||||
0xad, 0xae, 0xac, 0xa6
|
||||
};
|
||||
|
||||
void DivPlatformYM2610BExt::tick() {
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
for (int i=0; i<4; i++) {
|
||||
writeMask|=opChan[i].active<<(4+i);
|
||||
if (opChan[i].keyOn || opChan[i].keyOff) {
|
||||
writeSomething=true;
|
||||
writeMask&=~(1<<(4+i));
|
||||
opChan[i].keyOff=false;
|
||||
}
|
||||
}
|
||||
if (writeSomething) {
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformYM2610B::tick();
|
||||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch);
|
||||
if (opChan[i].freq>262143) opChan[i].freq=262143;
|
||||
int freqt=toFreq(opChan[i].freq);
|
||||
opChan[i].freqH=freqt>>8;
|
||||
opChan[i].freqL=freqt&0xff;
|
||||
immWrite(opChanOffsH[i],opChan[i].freqH);
|
||||
immWrite(opChanOffsL[i],opChan[i].freqL);
|
||||
opChan[i].freqChanged=false;
|
||||
}
|
||||
writeMask|=opChan[i].active<<(4+i);
|
||||
if (opChan[i].keyOn) {
|
||||
writeNoteOn=true;
|
||||
writeMask|=1<<(4+i);
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
if (writeNoteOn) {
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
|
||||
if (ch<2) {
|
||||
DivPlatformYM2610B::muteChannel(ch,mute);
|
||||
return;
|
||||
}
|
||||
if (ch>5) {
|
||||
DivPlatformYM2610B::muteChannel(ch-3,mute);
|
||||
return;
|
||||
}
|
||||
isOpMuted[ch-2]=mute;
|
||||
|
||||
int ordch=orderedOps[ch-2];
|
||||
DivInstrument* ins=parent->getIns(opChan[ch-2].ins);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
|
||||
DivInstrumentFM::Operator op=ins->fm.op[ordch];
|
||||
if (isOpMuted[ch-2]) {
|
||||
rWrite(baseAddr+0x40,127);
|
||||
} else if (isOutput[ins->fm.alg][ordch]) {
|
||||
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
|
||||
} else {
|
||||
rWrite(baseAddr+0x40,op.tl);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::forceIns() {
|
||||
DivPlatformYM2610B::forceIns();
|
||||
for (int i=0; i<4; i++) {
|
||||
opChan[i].insChanged=true;
|
||||
if (opChan[i].active) {
|
||||
opChan[i].keyOn=true;
|
||||
opChan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void* DivPlatformYM2610BExt::getChanState(int ch) {
|
||||
if (ch>=6) return &chan[ch-3];
|
||||
if (ch>=2) return &opChan[ch-2];
|
||||
return &chan[ch];
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::reset() {
|
||||
DivPlatformYM2610B::reset();
|
||||
|
||||
for (int i=0; i<4; i++) {
|
||||
opChan[i]=DivPlatformYM2610BExt::OpChannel();
|
||||
opChan[i].vol=127;
|
||||
}
|
||||
|
||||
// channel 2 mode
|
||||
immWrite(0x27,0x40);
|
||||
extMode=true;
|
||||
}
|
||||
|
||||
bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) {
|
||||
return (ch>8);
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::notifyInsChange(int ins) {
|
||||
DivPlatformYM2610B::notifyInsChange(ins);
|
||||
for (int i=0; i<4; i++) {
|
||||
if (opChan[i].ins==ins) {
|
||||
opChan[i].insChanged=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformYM2610BExt::init(DivEngine* parent, int channels, int sugRate, unsigned int flags) {
|
||||
DivPlatformYM2610B::init(parent,channels,sugRate,flags);
|
||||
for (int i=0; i<4; i++) {
|
||||
isOpMuted[i]=false;
|
||||
}
|
||||
|
||||
reset();
|
||||
return 19;
|
||||
}
|
||||
|
||||
void DivPlatformYM2610BExt::quit() {
|
||||
DivPlatformYM2610B::quit();
|
||||
}
|
||||
|
||||
DivPlatformYM2610BExt::~DivPlatformYM2610BExt() {
|
||||
}
|
51
src/engine/platform/ym2610bext.h
Normal file
51
src/engine/platform/ym2610bext.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../dispatch.h"
|
||||
|
||||
#include "ym2610b.h"
|
||||
|
||||
class DivPlatformYM2610BExt: public DivPlatformYM2610B {
|
||||
struct OpChannel {
|
||||
DivMacroInt std;
|
||||
unsigned char freqH, freqL;
|
||||
int freq, baseFreq, pitch;
|
||||
unsigned char ins;
|
||||
signed char konCycles;
|
||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
|
||||
int vol;
|
||||
unsigned char pan;
|
||||
OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
|
||||
};
|
||||
OpChannel opChan[4];
|
||||
bool isOpMuted[4];
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
public:
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick();
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
void notifyInsChange(int ins);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
~DivPlatformYM2610BExt();
|
||||
};
|
|
@ -147,10 +147,6 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
if (return2) return 2;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_MODE: {
|
||||
// ignored on extended channel 2 mode.
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_LEGATO: {
|
||||
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
opChan[ch].freqChanged=true;
|
||||
|
|
|
@ -17,9 +17,6 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
static unsigned short chanOffs[4]={
|
||||
0x01, 0x02, 0x101, 0x102
|
||||
};
|
||||
static unsigned short opOffs[4]={
|
||||
0x00, 0x04, 0x08, 0x0c
|
||||
};
|
||||
|
|
|
@ -232,6 +232,15 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
}
|
||||
return false;
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
switch (effect) {
|
||||
case 0x18: // drum mode toggle
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
switch (effect) {
|
||||
case 0x10: // echo feedback
|
||||
|
@ -255,7 +264,7 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
|||
return true;
|
||||
}
|
||||
|
||||
#define IS_YM2610 (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL_EXT)
|
||||
#define IS_YM2610 (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610B || sysOfChan[ch]==DIV_SYSTEM_YM2610B_EXT)
|
||||
|
||||
bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) {
|
||||
switch (sysOfChan[ch]) {
|
||||
|
@ -266,6 +275,8 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
switch (effect) {
|
||||
case 0x10: // LFO or noise mode
|
||||
if (sysOfChan[ch]==DIV_SYSTEM_YM2151) {
|
||||
|
@ -389,8 +400,6 @@ bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char
|
|||
dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15));
|
||||
}
|
||||
break;
|
||||
case 0x18: // drum mode toggle
|
||||
break;
|
||||
case 0x19: // AR global
|
||||
dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31));
|
||||
break;
|
||||
|
|
|
@ -90,6 +90,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_OPLL_DRUMS,
|
||||
DIV_SYSTEM_LYNX,
|
||||
DIV_SYSTEM_QSOUND,
|
||||
DIV_SYSTEM_YM2610B_EXT,
|
||||
DIV_SYSTEM_SEGAPCM_COMPAT
|
||||
};
|
||||
|
||||
|
@ -220,6 +221,18 @@ struct DivSong {
|
|||
// - bit 0-11: echo delay length
|
||||
// - Valid values are 0-2725
|
||||
// - 0 is max length, 2725 is min length
|
||||
// - OPLL:
|
||||
// - bit 0-3: clock rate
|
||||
// - 0: NTSC (3.58MHz)
|
||||
// - 1: PAL (3.55MHz)
|
||||
// - 2: Other (4MHz)
|
||||
// - 3: half NTSC (1.79MHz)
|
||||
// - bit 4-7: patch set
|
||||
// - 0: YM2413
|
||||
// - 1: YMF281
|
||||
// - 2: YM2423
|
||||
// - 3: VRC7
|
||||
// - 4: custom (TODO)
|
||||
unsigned int systemFlags[32];
|
||||
|
||||
// song information
|
||||
|
|
|
@ -135,6 +135,8 @@ DivSystem DivEngine::systemFromFile(unsigned char val) {
|
|||
return DIV_SYSTEM_LYNX;
|
||||
case 0xa9:
|
||||
return DIV_SYSTEM_SEGAPCM_COMPAT;
|
||||
case 0xde:
|
||||
return DIV_SYSTEM_YM2610B_EXT;
|
||||
case 0xe0:
|
||||
return DIV_SYSTEM_QSOUND;
|
||||
}
|
||||
|
@ -256,6 +258,8 @@ unsigned char DivEngine::systemToFile(DivSystem val) {
|
|||
return 0xa8;
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return 0xa9;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return 0xde;
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return 0xe0;
|
||||
|
||||
|
@ -376,6 +380,7 @@ int DivEngine::getChannelCount(DivSystem sys) {
|
|||
return 4;
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return 5;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return 19;
|
||||
}
|
||||
|
@ -458,6 +463,18 @@ const char* DivEngine::getSongSystemName() {
|
|||
return "Sega Genesis Extended Channel 3";
|
||||
}
|
||||
|
||||
if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_SMS) {
|
||||
return "NTSC-J Sega Master System";
|
||||
}
|
||||
if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_SMS) {
|
||||
return "NTSC-J Sega Master System + drums";
|
||||
}
|
||||
if (song.system[0]==DIV_SYSTEM_OPLL && song.system[1]==DIV_SYSTEM_AY8910) {
|
||||
return "MSX-MUSIC";
|
||||
}
|
||||
if (song.system[0]==DIV_SYSTEM_OPLL_DRUMS && song.system[1]==DIV_SYSTEM_AY8910) {
|
||||
return "MSX-MUSIC + drums";
|
||||
}
|
||||
if (song.system[0]==DIV_SYSTEM_C64_6581 && song.system[1]==DIV_SYSTEM_C64_6581) {
|
||||
return "Commodore 64 with dual 6581";
|
||||
}
|
||||
|
@ -629,6 +646,8 @@ const char* DivEngine::getSystemName(DivSystem sys) {
|
|||
return "Atari Lynx";
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return "SegaPCM (compatible 5-channel mode)";
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return "Taito Arcade Extended Channel 3";
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return "Capcom QSound";
|
||||
}
|
||||
|
@ -673,9 +692,9 @@ const char* DivEngine::getSystemChips(DivSystem sys) {
|
|||
case DIV_SYSTEM_AMIGA:
|
||||
return "MOS 8364 Paula";
|
||||
case DIV_SYSTEM_YM2151:
|
||||
return "Yamaha YM2151 standalone";
|
||||
return "Yamaha YM2151";
|
||||
case DIV_SYSTEM_YM2612:
|
||||
return "Yamaha YM2612 standalone";
|
||||
return "Yamaha YM2612";
|
||||
case DIV_SYSTEM_TIA:
|
||||
return "Atari TIA";
|
||||
case DIV_SYSTEM_VIC20:
|
||||
|
@ -752,6 +771,8 @@ const char* DivEngine::getSystemChips(DivSystem sys) {
|
|||
return "Mikey";
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
return "SegaPCM (compatible 5-channel mode)";
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return "Yamaha YM2610B Extended Channel 3";
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
return "Capcom DL-1425";
|
||||
}
|
||||
|
@ -822,6 +843,8 @@ bool DivEngine::isFMSystem(DivSystem sys) {
|
|||
sys==DIV_SYSTEM_YM2610_EXT ||
|
||||
sys==DIV_SYSTEM_YM2610_FULL ||
|
||||
sys==DIV_SYSTEM_YM2610_FULL_EXT ||
|
||||
sys==DIV_SYSTEM_YM2610B ||
|
||||
sys==DIV_SYSTEM_YM2610B_EXT ||
|
||||
sys==DIV_SYSTEM_YMU759 ||
|
||||
sys==DIV_SYSTEM_YM2151 ||
|
||||
sys==DIV_SYSTEM_YM2612);
|
||||
|
@ -834,7 +857,7 @@ bool DivEngine::isSTDSystem(DivSystem sys) {
|
|||
sys!=DIV_SYSTEM_YM2151);
|
||||
}
|
||||
|
||||
const char* chanNames[37][24]={
|
||||
const char* chanNames[38][24]={
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM"}, // YMU759/SegaPCM
|
||||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Noise"}, // Genesis
|
||||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Noise"}, // Genesis (extended channel 3)
|
||||
|
@ -872,9 +895,10 @@ const char* chanNames[37][24]={
|
|||
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6"}, // OPL3 4-op
|
||||
{"FM 1", "FM 2", "FM 3", "4OP 1", "4OP 2", "4OP 3", "4OP 4", "4OP 5", "4OP 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, // OPL3 4-op + drums
|
||||
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"}, // QSound
|
||||
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, // YM2610B (extended channel 3)
|
||||
};
|
||||
|
||||
const char* chanShortNames[37][24]={
|
||||
const char* chanShortNames[38][24]={
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "PCM"}, // YMU759
|
||||
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "NO"}, // Genesis
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "S4"}, // Genesis (extended channel 3)
|
||||
|
@ -912,9 +936,10 @@ const char* chanShortNames[37][24]={
|
|||
{"F1", "F2", "F3", "F4", "F5", "F6", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6"}, // OPL3 4-op
|
||||
{"F1", "F2", "F3", "Q1", "Q2", "Q3", "Q4", "Q5", "Q6", "BD", "SD", "TM", "TP", "HH"}, // OPL3 4-op + drums
|
||||
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"}, // QSound
|
||||
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, // YM2610B (extended channel 3)
|
||||
};
|
||||
|
||||
const int chanTypes[37][24]={
|
||||
const int chanTypes[38][24]={
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}, // YMU759
|
||||
{0, 0, 0, 0, 0, 0, 1, 1, 1, 2}, // Genesis
|
||||
{0, 0, 5, 5, 5, 5, 0, 0, 0, 1, 1, 1, 2}, // Genesis (extended channel 3)
|
||||
|
@ -952,9 +977,10 @@ const int chanTypes[37][24]={
|
|||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // OPL3 4-op
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2}, // OPL3 4-op + drums
|
||||
{3, 3, 3, 3}, //Lynx
|
||||
{0, 0, 5, 5, 5, 5, 0, 0, 0, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4}, // YM2610B (extended channel 3)
|
||||
};
|
||||
|
||||
const DivInstrumentType chanPrefType[43][24]={
|
||||
const DivInstrumentType chanPrefType[44][24]={
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, // YMU759
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, // Genesis
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, // Genesis (extended channel 3)
|
||||
|
@ -998,6 +1024,7 @@ const DivInstrumentType chanPrefType[43][24]={
|
|||
{DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN}, // Swan
|
||||
{DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ}, // Z
|
||||
{DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY}, // Lynx
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, // YM2610B (extended channel 3)
|
||||
};
|
||||
|
||||
const char* DivEngine::getChannelName(int chan) {
|
||||
|
@ -1115,6 +1142,9 @@ const char* DivEngine::getChannelName(int chan) {
|
|||
case DIV_SYSTEM_YM2610B:
|
||||
return chanNames[31][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return chanNames[37][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_OPL_DRUMS:
|
||||
case DIV_SYSTEM_OPL2_DRUMS:
|
||||
|
@ -1251,6 +1281,9 @@ const char* DivEngine::getChannelShortName(int chan) {
|
|||
case DIV_SYSTEM_YM2610B:
|
||||
return chanShortNames[31][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return chanShortNames[37][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_OPL_DRUMS:
|
||||
case DIV_SYSTEM_OPL2_DRUMS:
|
||||
|
@ -1385,6 +1418,9 @@ int DivEngine::getChannelType(int chan) {
|
|||
case DIV_SYSTEM_YM2610B:
|
||||
return chanTypes[31][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return chanTypes[37][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_OPL_DRUMS:
|
||||
case DIV_SYSTEM_OPL2_DRUMS:
|
||||
|
@ -1519,6 +1555,9 @@ DivInstrumentType DivEngine::getPreferInsType(int chan) {
|
|||
case DIV_SYSTEM_YM2610B:
|
||||
return chanPrefType[31][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
return chanPrefType[43][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
return chanPrefType[32][dispatchChanOfChan[chan]];
|
||||
break;
|
||||
|
@ -1564,12 +1603,19 @@ bool DivEngine::isVGMExportable(DivSystem which) {
|
|||
case DIV_SYSTEM_YM2612_EXT:
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
case DIV_SYSTEM_AY8910:
|
||||
case DIV_SYSTEM_AY8930:
|
||||
case DIV_SYSTEM_SAA1099:
|
||||
case DIV_SYSTEM_QSOUND:
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
case DIV_SYSTEM_OPLL:
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_VRC7:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -152,8 +152,10 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_FULL:
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
for (int i=0; i<2; i++) { // set SL and RR to highest
|
||||
w->writeC(isSecond?0xa8:0x58);
|
||||
w->writeC(0x81+i);
|
||||
|
@ -212,6 +214,21 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(0);
|
||||
w->writeC(0xbf);
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL:
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_VRC7:
|
||||
for (int i=0; i<9; i++) {
|
||||
w->writeC(isSecond?0xa1:0x51);
|
||||
w->writeC(0x20+i);
|
||||
w->writeC(0);
|
||||
w->writeC(isSecond?0xa1:0x51);
|
||||
w->writeC(0x30+i);
|
||||
w->writeC(0);
|
||||
w->writeC(isSecond?0xa1:0x51);
|
||||
w->writeC(0x10+i);
|
||||
w->writeC(0);
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_AY8910:
|
||||
w->writeC(0xa0);
|
||||
w->writeC(isSecond?0x87:7);
|
||||
|
@ -376,8 +393,10 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_FULL:
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
switch (write.addr>>8) {
|
||||
case 0: // port 0
|
||||
w->writeC(isSecond?0xa8:0x58);
|
||||
|
@ -391,6 +410,13 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL:
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_VRC7:
|
||||
w->writeC(isSecond?0xa1:0x51);
|
||||
w->writeC(write.addr&0xff);
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_AY8910:
|
||||
case DIV_SYSTEM_AY8930:
|
||||
w->writeC(0xa0);
|
||||
|
@ -611,8 +637,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
|||
break;
|
||||
case DIV_SYSTEM_YM2610:
|
||||
case DIV_SYSTEM_YM2610_FULL:
|
||||
case DIV_SYSTEM_YM2610B:
|
||||
case DIV_SYSTEM_YM2610_EXT:
|
||||
case DIV_SYSTEM_YM2610_FULL_EXT:
|
||||
case DIV_SYSTEM_YM2610B_EXT:
|
||||
if (!hasOPNB) {
|
||||
hasOPNB=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
|
@ -623,6 +651,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
|||
hasOPNB|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
if (((song.system[i]==DIV_SYSTEM_YM2610B) || (song.system[i]==DIV_SYSTEM_YM2610B_EXT)) && (!(hasOPNB&0x80000000))) { // YM2610B flag
|
||||
hasOPNB|=0x80000000;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_AY8910:
|
||||
case DIV_SYSTEM_AY8930:
|
||||
|
@ -673,6 +704,19 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
|||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_OPLL:
|
||||
case DIV_SYSTEM_OPLL_DRUMS:
|
||||
case DIV_SYSTEM_VRC7:
|
||||
if (!hasOPLL) {
|
||||
hasOPLL=disCont[i].dispatch->chipClock;
|
||||
willExport[i]=true;
|
||||
} else if (!(hasOPLL&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
hasOPLL|=0x40000000;
|
||||
howManyChips++;
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_LYNX:
|
||||
if (!hasLynx) {
|
||||
hasLynx=disCont[i].dispatch->chipClock;
|
||||
|
@ -895,6 +939,16 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop) {
|
|||
w->write(adpcmAMem,adpcmAMemLen);
|
||||
}
|
||||
|
||||
if (writeADPCM && adpcmBMemLen>0) {
|
||||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0x83);
|
||||
w->writeI(adpcmBMemLen+8);
|
||||
w->writeI(adpcmBMemLen);
|
||||
w->writeI(0);
|
||||
w->write(adpcmBMem,adpcmBMemLen);
|
||||
}
|
||||
|
||||
if (writeQSound && qsoundMemLen>0) {
|
||||
// always write a whole bank
|
||||
unsigned int blockSize=(qsoundMemLen+0xffff)&(~0xffff);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "../engine/platform/arcade.h"
|
||||
#include "../engine/platform/ym2610.h"
|
||||
#include "../engine/platform/ym2610ext.h"
|
||||
#include "../engine/platform/ym2610b.h"
|
||||
#include "../engine/platform/ym2610bext.h"
|
||||
#include "../engine/platform/ay.h"
|
||||
#include "../engine/platform/ay8930.h"
|
||||
#include "../engine/platform/tia.h"
|
||||
|
|
783
src/gui/gui.cpp
783
src/gui/gui.cpp
File diff suppressed because it is too large
Load diff
|
@ -23,9 +23,12 @@
|
|||
#include "imgui_impl_sdlrenderer.h"
|
||||
#include <SDL.h>
|
||||
#include <deque>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#define rightClickable if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) ImGui::SetKeyboardFocusHere(-1);
|
||||
|
||||
enum FurnaceGUIColors {
|
||||
GUI_COLOR_BACKGROUND=0,
|
||||
GUI_COLOR_FRAME_BACKGROUND,
|
||||
|
@ -155,6 +158,7 @@ enum FurnaceGUIWarnings {
|
|||
GUI_WARN_NEW,
|
||||
GUI_WARN_OPEN,
|
||||
GUI_WARN_OPEN_DROP,
|
||||
GUI_WARN_RESET_LAYOUT,
|
||||
GUI_WARN_GENERIC
|
||||
};
|
||||
|
||||
|
@ -388,7 +392,7 @@ struct Particle {
|
|||
const char* type;
|
||||
ImVec2 pos, speed;
|
||||
float gravity, friction, life, lifeSpeed;
|
||||
bool update();
|
||||
bool update(float frameTime);
|
||||
Particle(ImU32* color, const char* ty, float x, float y, float sX, float sY, float g, float fr, float l, float lS):
|
||||
colors(color),
|
||||
type(ty),
|
||||
|
@ -400,6 +404,23 @@ struct Particle {
|
|||
lifeSpeed(lS) {}
|
||||
};
|
||||
|
||||
struct FurnaceGUISysDef {
|
||||
const char* name;
|
||||
std::vector<int> definition;
|
||||
FurnaceGUISysDef(const char* n, std::initializer_list<int> def):
|
||||
name(n), definition(def) {
|
||||
}
|
||||
};
|
||||
|
||||
struct FurnaceGUISysCategory {
|
||||
const char* name;
|
||||
std::vector<FurnaceGUISysDef> systems;
|
||||
FurnaceGUISysCategory(const char* n):
|
||||
name(n) {}
|
||||
FurnaceGUISysCategory():
|
||||
name(NULL) {}
|
||||
};
|
||||
|
||||
class FurnaceGUI {
|
||||
DivEngine* e;
|
||||
|
||||
|
@ -407,10 +428,12 @@ class FurnaceGUI {
|
|||
SDL_Renderer* sdlRend;
|
||||
|
||||
String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile;
|
||||
String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont;
|
||||
String mmlString[12];
|
||||
String mmlStringW;
|
||||
|
||||
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop;
|
||||
bool displayNew;
|
||||
bool willExport[32];
|
||||
|
||||
FurnaceGUIFileDialogs curFileDialog;
|
||||
|
@ -519,7 +542,7 @@ class FurnaceGUI {
|
|||
char finalLayoutPath[4096];
|
||||
|
||||
int curIns, curWave, curSample, curOctave, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor;
|
||||
int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget;
|
||||
int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory;
|
||||
bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen;
|
||||
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
|
||||
bool mixerOpen, debugOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
|
||||
|
@ -531,6 +554,7 @@ class FurnaceGUI {
|
|||
float peak[2];
|
||||
float patChanX[DIV_MAX_CHANS+1];
|
||||
float patChanSlideY[DIV_MAX_CHANS+1];
|
||||
const int* nextDesc;
|
||||
|
||||
// bit 31: ctrl
|
||||
// bit 30: reserved for SDL scancode mask
|
||||
|
@ -561,6 +585,8 @@ class FurnaceGUI {
|
|||
std::vector<DivCommand> cmdStream;
|
||||
std::vector<Particle> particles;
|
||||
|
||||
std::vector<FurnaceGUISysCategory> sysCategories;
|
||||
|
||||
bool wavePreviewOn;
|
||||
SDL_Scancode wavePreviewKey;
|
||||
int wavePreviewNote;
|
||||
|
@ -626,7 +652,7 @@ class FurnaceGUI {
|
|||
int lastIns[DIV_MAX_CHANS];
|
||||
|
||||
void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size);
|
||||
void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, const ImVec2& size);
|
||||
void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, float maxTl, float maxArDr, const ImVec2& size);
|
||||
|
||||
void updateWindowTitle();
|
||||
void prepareLayout();
|
||||
|
@ -655,6 +681,7 @@ class FurnaceGUI {
|
|||
void drawAbout();
|
||||
void drawSettings();
|
||||
void drawDebug();
|
||||
void drawNewSong();
|
||||
|
||||
void parseKeybinds();
|
||||
void promptKey(int which);
|
||||
|
|
|
@ -148,6 +148,10 @@ const char* mikeyFeedbackBits[11] = {
|
|||
"0", "1", "2", "3", "4", "5", "7", "10", "11", "int", NULL
|
||||
};
|
||||
|
||||
const char* oneBit[2]={
|
||||
"on", NULL
|
||||
};
|
||||
|
||||
const int orderedOps[4]={
|
||||
0, 2, 1, 3
|
||||
};
|
||||
|
@ -183,6 +187,13 @@ String macroLFOWaves(int id, float val) {
|
|||
return "???";
|
||||
}
|
||||
|
||||
void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) {
|
||||
ImVec2 pt[2];
|
||||
pt[0]=p1;
|
||||
pt[1]=p2;
|
||||
dl->AddPolyline(pt,2,color,ImDrawFlags_None,thickness);
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size) {
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
|
@ -199,7 +210,6 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImGui::ItemSize(size,style.FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) {
|
||||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
//ImReallyTiredOfThisGarbage();
|
||||
const float circleRadius=6.0f*dpiScale+1.0f;
|
||||
switch (algType) {
|
||||
case FM_ALGS_4OP:
|
||||
|
@ -211,11 +221,11 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.8,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos3,colorL);
|
||||
addAALine(dl,pos2,pos3,colorL);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos3,pos4,colorL);
|
||||
addAALine(dl,pos3,pos4,colorL);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("1").x*0.5;
|
||||
|
@ -239,11 +249,11 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos3,colorL);
|
||||
addAALine(dl,pos1,pos3,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos3,colorL);
|
||||
addAALine(dl,pos2,pos3,colorL);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos3,pos4,colorL);
|
||||
addAALine(dl,pos3,pos4,colorL);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
|
||||
pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -267,11 +277,11 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos4,colorL);
|
||||
addAALine(dl,pos1,pos4,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos3,colorL);
|
||||
addAALine(dl,pos2,pos3,colorL);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos3,pos4,colorL);
|
||||
addAALine(dl,pos3,pos4,colorL);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -295,11 +305,11 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos4,colorL);
|
||||
addAALine(dl,pos2,pos4,colorL);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos3,pos4,colorL);
|
||||
addAALine(dl,pos3,pos4,colorL);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -324,13 +334,13 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos3,pos4,colorL);
|
||||
addAALine(dl,pos3,pos4,colorL);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos5,colorL);
|
||||
dl->AddLine(pos4,pos5,colorL);
|
||||
addAALine(dl,pos2,pos5,colorL);
|
||||
addAALine(dl,pos4,pos5,colorL);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -354,15 +364,15 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
dl->AddLine(pos1,pos3,colorL);
|
||||
dl->AddLine(pos1,pos4,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos3,colorL);
|
||||
addAALine(dl,pos1,pos4,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos5,colorL);
|
||||
dl->AddLine(pos3,pos5,colorL);
|
||||
dl->AddLine(pos4,pos5,colorL);
|
||||
addAALine(dl,pos2,pos5,colorL);
|
||||
addAALine(dl,pos3,pos5,colorL);
|
||||
addAALine(dl,pos4,pos5,colorL);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -386,13 +396,13 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos5=ImLerp(rect.Min,rect.Max,ImVec2(0.75,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos2,pos5,colorL);
|
||||
dl->AddLine(pos3,pos5,colorL);
|
||||
dl->AddLine(pos4,pos5,colorL);
|
||||
addAALine(dl,pos2,pos5,colorL);
|
||||
addAALine(dl,pos3,pos5,colorL);
|
||||
addAALine(dl,pos4,pos5,colorL);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -419,10 +429,10 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos3,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircleFilled(pos4,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos5,colorL);
|
||||
dl->AddLine(pos2,pos5,colorL);
|
||||
dl->AddLine(pos3,pos5,colorL);
|
||||
dl->AddLine(pos4,pos5,colorL);
|
||||
addAALine(dl,pos1,pos5,colorL);
|
||||
addAALine(dl,pos2,pos5,colorL);
|
||||
addAALine(dl,pos3,pos5,colorL);
|
||||
addAALine(dl,pos4,pos5,colorL);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
pos2.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -447,7 +457,7 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.67,0.5));
|
||||
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
|
||||
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
|
||||
dl->AddLine(pos1,pos2,colorL);
|
||||
addAALine(dl,pos1,pos2,colorL);
|
||||
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
|
||||
|
||||
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
|
||||
|
@ -481,7 +491,7 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, const ImVec2& size) {
|
||||
void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, float maxTl, float maxArDr, const ImVec2& size) {
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
|
||||
|
@ -499,8 +509,8 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
|
|||
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
|
||||
|
||||
//calculate x positions
|
||||
float arPos=float(31-ar)/31.0; //peak of AR, start of DR
|
||||
float drPos=arPos+((sl/15.0)*(float(31-dr)/31.0)); //end of DR, start of D2R
|
||||
float arPos=float(maxArDr-ar)/maxArDr; //peak of AR, start of DR
|
||||
float drPos=arPos+((sl/15.0)*(float(maxArDr-dr)/maxArDr)); //end of DR, start of D2R
|
||||
float d2rPos=drPos+(((15.0-sl)/15.0)*(float(31.0-d2r)/31.0)); //End of D2R
|
||||
float rrPos=(float(15-rr)/15.0); //end of RR
|
||||
|
||||
|
@ -511,43 +521,42 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr,
|
|||
rrPos/=1.0;
|
||||
|
||||
ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,1.0)); //the bottom corner
|
||||
ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(arPos,(tl/127.0))); //peak of AR, start of DR
|
||||
ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(drPos,(float)((tl/127.0)+(sl/15.0)-((tl/127.0)*(sl/15.0))))); //end of DR, start of D2R
|
||||
ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(arPos,(tl/maxTl))); //peak of AR, start of DR
|
||||
ImVec2 pos3=ImLerp(rect.Min,rect.Max,ImVec2(drPos,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //end of DR, start of D2R
|
||||
ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(d2rPos,1.0)); //end of D2R
|
||||
ImVec2 posRStart=ImLerp(rect.Min,rect.Max,ImVec2(0.0,(tl/127.0))); //release start
|
||||
ImVec2 posRStart=ImLerp(rect.Min,rect.Max,ImVec2(0.0,(tl/maxTl))); //release start
|
||||
ImVec2 posREnd=ImLerp(rect.Min,rect.Max,ImVec2(rrPos,1.0));//release end
|
||||
ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/127.0)+(sl/15.0)-((tl/127.0)*(sl/15.0))))); //sustain horizontal line end
|
||||
ImVec2 posSLineHEnd=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //sustain horizontal line end
|
||||
ImVec2 posSLineVEnd=ImLerp(rect.Min,rect.Max,ImVec2(drPos,1.0)); //sustain vertical line end
|
||||
ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/127.0))); //Heght of the peak of AR, forever
|
||||
ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/127.0)+(sl/15.0)-((tl/127.0)*(sl/15.0))))); //Heght of the peak of SR, forever
|
||||
ImVec2 posDecayRate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(tl/maxTl))); //Heght of the peak of AR, forever
|
||||
ImVec2 posDecay2Rate0Pt=ImLerp(rect.Min,rect.Max,ImVec2(1.0,(float)((tl/maxTl)+(sl/15.0)-((tl/maxTl)*(sl/15.0))))); //Heght of the peak of SR, forever
|
||||
|
||||
//dl->Flags=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex;
|
||||
if (ar==0.0) { //if AR = 0, the envelope never starts
|
||||
dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything
|
||||
dl->AddLine(pos1,pos4,color); //draw line on ground
|
||||
}
|
||||
else if (dr==0.0 && sl!=0.0) { //if DR = 0 and SL is not 0, then the envelope stays at max volume forever
|
||||
addAALine(dl,pos1,pos4,color); //draw line on ground
|
||||
} else if (dr==0.0 && sl!=0.0) { //if DR = 0 and SL is not 0, then the envelope stays at max volume forever
|
||||
dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything
|
||||
//dl->AddLine(pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
//dl->AddLine(pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
dl->AddLine(pos1,pos2,color); //A
|
||||
dl->AddLine(pos2,posDecayRate0Pt,color); //Line from A to end of graph
|
||||
}
|
||||
else if(d2r==0.0) { //if D2R = 0, the envelope stays at the sustain level forever
|
||||
//addAALine(dl,pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
//addAALine(dl,pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
addAALine(dl,pos1,pos2,color); //A
|
||||
addAALine(dl,pos2,posDecayRate0Pt,color); //Line from A to end of graph
|
||||
} else if (d2r==0.0) { //if D2R = 0, the envelope stays at the sustain level forever
|
||||
dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything
|
||||
dl->AddLine(pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
dl->AddLine(pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
dl->AddLine(pos1,pos2,color); //A
|
||||
dl->AddLine(pos2,pos3,color); //D
|
||||
dl->AddLine(pos3,posDecay2Rate0Pt,color); //Line from D to end of graph
|
||||
}
|
||||
else { //draw graph normally
|
||||
addAALine(dl,pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
addAALine(dl,pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
addAALine(dl,pos1,pos2,color); //A
|
||||
addAALine(dl,pos2,pos3,color); //D
|
||||
addAALine(dl,pos3,posDecay2Rate0Pt,color); //Line from D to end of graph
|
||||
} else { //draw graph normally
|
||||
dl->AddTriangleFilled(posRStart,posREnd,pos1,colorS); //draw release as shaded triangle behind everything
|
||||
dl->AddLine(pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
dl->AddLine(pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
dl->AddLine(pos1,pos2,color); //A
|
||||
dl->AddLine(pos2,pos3,color); //D
|
||||
dl->AddLine(pos3,pos4,color); //D2
|
||||
addAALine(dl,pos3,posSLineHEnd,colorS); //draw horiz line through sustain level
|
||||
addAALine(dl,pos3,posSLineVEnd,colorS); //draw vert. line through sustain level
|
||||
addAALine(dl,pos1,pos2,color); //A
|
||||
addAALine(dl,pos2,pos3,color); //D
|
||||
addAALine(dl,pos3,pos4,color); //D2
|
||||
}
|
||||
//dl->Flags^=ImDrawListFlags_AntiAliasedLines|ImDrawListFlags_AntiAliasedLinesUseTex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,11 +808,11 @@ void FurnaceGUI::drawInsEdit() {
|
|||
case DIV_INS_FM:
|
||||
case DIV_INS_OPZ:
|
||||
ImGui::TableNextColumn();
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
break;
|
||||
|
@ -814,7 +823,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
bool sus=ins->fm.alg;
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::BeginDisabled(ins->fm.opllPreset!=0);
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable
|
||||
if (ImGui::Checkbox(FM_NAME(FM_DC),&dc)) { PARAMETER
|
||||
ins->fm.fms=dc;
|
||||
}
|
||||
|
@ -854,7 +863,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
bool willDisplayOps=true;
|
||||
if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset!=0) willDisplayOps=false;
|
||||
if (!willDisplayOps && ins->type==DIV_INS_OPLL) {
|
||||
P(ImGui::SliderScalar("Volume##TL",ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO));
|
||||
P(ImGui::SliderScalar("Volume##TL",ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
}
|
||||
if (willDisplayOps) if (ImGui::BeginTable("FMOperators",2,ImGuiTableFlags_SizingStretchSame)) {
|
||||
for (int i=0; i<opCount; i++) {
|
||||
|
@ -899,8 +908,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
|
||||
//52.0 controls vert scaling; default 96
|
||||
drawFMEnv(op.tl,op.ar,op.dr,op.d2r,op.rr,op.sl,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale));
|
||||
//P(ImGui::SliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE));
|
||||
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale));
|
||||
//P(ImGui::SliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable
|
||||
if (ImGui::BeginTable("opParams",2,ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); \
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); \
|
||||
|
@ -908,21 +917,21 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
|
||||
P(ImGui::SliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_AR));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
|
||||
P(ImGui::SliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_DR));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO));
|
||||
P(ImGui::SliderScalar("##SL",ImGuiDataType_U8,&op.sl,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_SL));
|
||||
|
||||
|
@ -930,7 +939,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
|
||||
P(ImGui::SliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_D2R));
|
||||
}
|
||||
|
@ -938,14 +947,14 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
|
||||
P(ImGui::SliderScalar("##RR",ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_RR));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO));
|
||||
P(ImGui::SliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_TL));
|
||||
|
||||
|
@ -959,11 +968,11 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
|
||||
P(ImGui::SliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
|
||||
P(ImGui::SliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_RS));
|
||||
} else {
|
||||
P(ImGui::SliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE));
|
||||
P(ImGui::SliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_KSL));
|
||||
}
|
||||
|
@ -971,7 +980,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_MULT));
|
||||
|
||||
|
@ -982,14 +991,14 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderInt("##DT",&detune,-3,3)) { PARAMETER
|
||||
op.dt=detune+3;
|
||||
}
|
||||
} rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_DT));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(ImGui::SliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE));
|
||||
P(ImGui::SliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); rightClickable
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Only for Arcade system");
|
||||
}
|
||||
|
@ -1001,7 +1010,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::SliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
|
||||
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
|
||||
}
|
||||
} rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",FM_NAME(FM_SSG));
|
||||
}
|
||||
|
@ -1027,15 +1036,24 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
if (ImGui::BeginTabItem("FM Macros")) {
|
||||
MACRO_BEGIN(0);
|
||||
if (ins->type==DIV_INS_OPLL) {
|
||||
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false);
|
||||
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
|
||||
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false);
|
||||
NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacroOpen,true,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false);
|
||||
} else {
|
||||
NORMAL_MACRO(ins->std.algMacro,ins->std.algMacroLen,ins->std.algMacroLoop,ins->std.algMacroRel,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false);
|
||||
NORMAL_MACRO(ins->std.fbMacro,ins->std.fbMacroLen,ins->std.fbMacroLoop,ins->std.fbMacroRel,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
|
||||
NORMAL_MACRO(ins->std.fmsMacro,ins->std.fmsMacroLen,ins->std.fmsMacroLoop,ins->std.fmsMacroRel,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
|
||||
NORMAL_MACRO(ins->std.amsMacro,ins->std.amsMacroLen,ins->std.amsMacroLoop,ins->std.amsMacroRel,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false);
|
||||
}
|
||||
|
||||
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
|
||||
NORMAL_MACRO(ins->std.ex1Macro,ins->std.ex1MacroLen,ins->std.ex1MacroLoop,ins->std.ex1MacroRel,0,127,"ex1","AM Depth",128,ins->std.ex1MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,127,NULL,false);
|
||||
NORMAL_MACRO(ins->std.ex2Macro,ins->std.ex2MacroLen,ins->std.ex2MacroLoop,ins->std.ex2MacroRel,0,127,"ex2","PM Depth",128,ins->std.ex2MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,127,NULL,false);
|
||||
NORMAL_MACRO(ins->std.ex3Macro,ins->std.ex3MacroLen,ins->std.ex3MacroLoop,ins->std.ex3MacroRel,0,255,"ex3","LFO Speed",128,ins->std.ex3MacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
|
||||
NORMAL_MACRO(ins->std.waveMacro,ins->std.waveMacroLen,ins->std.waveMacroLoop,ins->std.waveMacroRel,0,3,"wave","LFO Shape",48,ins->std.waveMacroOpen,false,NULL,false,NULL,0,0,0,NULL,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[7],0,3,¯oLFOWaves,false);
|
||||
}
|
||||
MACRO_END;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
@ -1055,6 +1073,20 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
|
||||
|
||||
if (ins->type==DIV_INS_OPLL) {
|
||||
OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].slMacro,ins->std.opMacros[ordi].slMacroLen,ins->std.opMacros[ordi].slMacroLoop,ins->std.opMacros[ordi].slMacroRel,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacroOpen,false,NULL,mmlString[5]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].rrMacro,ins->std.opMacros[ordi].rrMacroLen,ins->std.opMacros[ordi].rrMacroLoop,ins->std.opMacros[ordi].rrMacroRel,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacroOpen,false,NULL,mmlString[4]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].kslMacro,ins->std.opMacros[ordi].kslMacroLen,ins->std.opMacros[ordi].kslMacroLoop,ins->std.opMacros[ordi].kslMacroRel,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacroOpen,false,NULL,mmlString[6]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].multMacro,ins->std.opMacros[ordi].multMacroLen,ins->std.opMacros[ordi].multMacroLoop,ins->std.opMacros[ordi].multMacroRel,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacroOpen,false,NULL,mmlString[7]);
|
||||
|
||||
OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[8]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].vibMacro,ins->std.opMacros[ordi].vibMacroLen,ins->std.opMacros[ordi].vibMacroLoop,ins->std.opMacros[ordi].vibMacroRel,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacroOpen,true,NULL,mmlString[9]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].ksrMacro,ins->std.opMacros[ordi].ksrMacroLen,ins->std.opMacros[ordi].ksrMacroLoop,ins->std.opMacros[ordi].ksrMacroRel,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacroOpen,true,NULL,mmlString[10]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].egtMacro,ins->std.opMacros[ordi].egtMacroLen,ins->std.opMacros[ordi].egtMacroLoop,ins->std.opMacros[ordi].egtMacroRel,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacroOpen,true,NULL,mmlString[11]);
|
||||
} else {
|
||||
OP_MACRO(ins->std.opMacros[ordi].tlMacro,ins->std.opMacros[ordi].tlMacroLen,ins->std.opMacros[ordi].tlMacroLoop,ins->std.opMacros[ordi].tlMacroRel,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacroOpen,false,NULL,mmlString[0]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].arMacro,ins->std.opMacros[ordi].arMacroLen,ins->std.opMacros[ordi].arMacroLoop,ins->std.opMacros[ordi].arMacroRel,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacroOpen,false,NULL,mmlString[1]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].drMacro,ins->std.opMacros[ordi].drMacroLen,ins->std.opMacros[ordi].drMacroLoop,ins->std.opMacros[ordi].drMacroRel,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacroOpen,false,NULL,mmlString[2]);
|
||||
|
@ -1067,6 +1099,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
OP_MACRO(ins->std.opMacros[ordi].dt2Macro,ins->std.opMacros[ordi].dt2MacroLen,ins->std.opMacros[ordi].dt2MacroLoop,ins->std.opMacros[ordi].dt2MacroRel,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2MacroOpen,false,NULL,mmlString[9]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].amMacro,ins->std.opMacros[ordi].amMacroLen,ins->std.opMacros[ordi].amMacroLoop,ins->std.opMacros[ordi].amMacroRel,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacroOpen,true,NULL,mmlString[10]);
|
||||
OP_MACRO(ins->std.opMacros[ordi].ssgMacro,ins->std.opMacros[ordi].ssgMacroLen,ins->std.opMacros[ordi].ssgMacroLoop,ins->std.opMacros[ordi].ssgMacroRel,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacroOpen,true,ssgEnvBits,mmlString[11]);
|
||||
}
|
||||
MACRO_END;
|
||||
ImGui::PopID();
|
||||
ImGui::EndTabItem();
|
||||
|
@ -1074,9 +1107,9 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
if (ins->type==DIV_INS_GB) if (ImGui::BeginTabItem("Game Boy")) {
|
||||
P(ImGui::SliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN));
|
||||
P(ImGui::SliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d"));
|
||||
P(ImGui::SliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable
|
||||
ImGui::Text("Envelope Direction:");
|
||||
|
||||
bool goesUp=ins->gb.envDir;
|
||||
|
@ -1119,11 +1152,11 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
P(ImGui::SliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE));
|
||||
P(ImGui::SliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable
|
||||
|
||||
bool ringMod=ins->c64.ringMod;
|
||||
if (ImGui::Checkbox("Ring Modulation",&ringMod)) { PARAMETER
|
||||
|
@ -1137,8 +1170,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
P(ImGui::Checkbox("Enable filter",&ins->c64.toFilter));
|
||||
P(ImGui::Checkbox("Initialize filter",&ins->c64.initFilter));
|
||||
|
||||
P(ImGui::SliderScalar("Cutoff",ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN));
|
||||
P(ImGui::SliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN));
|
||||
P(ImGui::SliderScalar("Cutoff",ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN)); rightClickable
|
||||
P(ImGui::SliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
|
||||
ImGui::Text("Filter Mode");
|
||||
ImGui::SameLine();
|
||||
|
|
|
@ -451,7 +451,7 @@ void FurnaceGUI::drawPattern() {
|
|||
chanHead.x*=0.25+keyHit[i]; chanHead.y*=0.25+keyHit[i]; chanHead.z*=0.25+keyHit[i];
|
||||
chanHeadActive.x*=0.8; chanHeadActive.y*=0.8; chanHeadActive.z*=0.8;
|
||||
chanHeadHover.x*=0.4+keyHit[i]; chanHeadHover.y*=0.4+keyHit[i]; chanHeadHover.z*=0.4+keyHit[i];
|
||||
keyHit[i]-=0.02;
|
||||
keyHit[i]-=0.02*60.0*ImGui::GetIO().DeltaTime;
|
||||
if (keyHit[i]<0) keyHit[i]=0;
|
||||
ImGui::PushStyleColor(ImGuiCol_Header,chanHead);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive);
|
||||
|
@ -717,6 +717,8 @@ void FurnaceGUI::drawPattern() {
|
|||
}
|
||||
}
|
||||
|
||||
float frameTime=ImGui::GetIO().DeltaTime*60.0f;
|
||||
|
||||
// note slides
|
||||
ImVec2 arrowPoints[7];
|
||||
if (e->isPlaying()) for (int i=0; i<chans; i++) {
|
||||
|
@ -763,7 +765,7 @@ void FurnaceGUI::drawPattern() {
|
|||
dl->AddPolyline(arrowPoints,7,ImGui::GetColorU32(col),ImDrawFlags_None,5.0f*dpiScale);
|
||||
}
|
||||
}
|
||||
patChanSlideY[i]+=((ch->portaNote<=ch->note)?-8:8)*dpiScale;
|
||||
patChanSlideY[i]+=((ch->portaNote<=ch->note)?-8:8)*dpiScale*frameTime;
|
||||
if (width>0) {
|
||||
if (patChanSlideY[i]<0) {
|
||||
patChanSlideY[i]=-fmod(-patChanSlideY[i],width*0.7);
|
||||
|
@ -778,7 +780,7 @@ void FurnaceGUI::drawPattern() {
|
|||
ImDrawList* fdl=ImGui::GetForegroundDrawList();
|
||||
for (size_t i=0; i<particles.size(); i++) {
|
||||
Particle& part=particles[i];
|
||||
if (part.update()) {
|
||||
if (part.update(frameTime)) {
|
||||
if (part.life>255) part.life=255;
|
||||
fdl->AddText(
|
||||
iconFont,
|
||||
|
|
|
@ -292,7 +292,7 @@ void FurnaceGUI::drawSettings() {
|
|||
if (ImGui::SliderFloat("UI scaling factor",&settings.dpiScale,1.0f,3.0f,"%.2fx")) {
|
||||
if (settings.dpiScale<0.5f) settings.dpiScale=0.5f;
|
||||
if (settings.dpiScale>3.0f) settings.dpiScale=3.0f;
|
||||
}
|
||||
} rightClickable
|
||||
}
|
||||
ImGui::Text("Main font");
|
||||
ImGui::SameLine();
|
||||
|
|
|
@ -30,8 +30,10 @@ typedef SSIZE_T ssize_t;
|
|||
|
||||
#ifdef _WIN32
|
||||
#define DIR_SEPARATOR '\\'
|
||||
#define DIR_SEPARATOR_STR "\\"
|
||||
#else
|
||||
#define DIR_SEPARATOR '/'
|
||||
#define DIR_SEPARATOR_STR "/"
|
||||
#endif
|
||||
|
||||
typedef std::string String;
|
||||
|
|
Loading…
Reference in a new issue