mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 13:05:11 +00:00
Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: (53 commits) prepare for better backward writing VGM export: fix oops GUI: drag-and-drop ins/wave/sample loading GUI: add "set loop" to sample editor MSM6295: VGM export! oops MSM6295: add rate select effect (20xx) update meteor shower MSVC is better than GCC right? update to-do list door into summer GUI: implement input for touch events GUI: update SDL hints fix Termux build add another demo song add demos/ecolove.fur update to-do list update demos/README.md add new demo songs dev99 - major Fractal system change ... # Conflicts: # src/engine/dispatch.h # src/engine/platform/genesis.cpp # src/engine/playback.cpp # src/engine/song.h # src/engine/vgmOps.cpp
This commit is contained in:
commit
32152fd89b
72 changed files with 967 additions and 304 deletions
|
@ -25,6 +25,10 @@ set(SYSTEM_SDL2_DEFAULT OFF)
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
set(USE_RTMIDI_DEFAULT OFF)
|
set(USE_RTMIDI_DEFAULT OFF)
|
||||||
set(USE_BACKWARD_DEFAULT OFF)
|
set(USE_BACKWARD_DEFAULT OFF)
|
||||||
|
find_library(TERMUX rt)
|
||||||
|
if (TERMUX)
|
||||||
|
message(STATUS "Termux detected")
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
set(USE_RTMIDI_DEFAULT ON)
|
set(USE_RTMIDI_DEFAULT ON)
|
||||||
set(USE_BACKWARD_DEFAULT ON)
|
set(USE_BACKWARD_DEFAULT ON)
|
||||||
|
@ -53,7 +57,7 @@ option(WARNINGS_ARE_ERRORS "Whether warnings in furnace's C++ code should be tre
|
||||||
|
|
||||||
set(DEPENDENCIES_INCLUDE_DIRS "")
|
set(DEPENDENCIES_INCLUDE_DIRS "")
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID AND NOT TERMUX)
|
||||||
set(DEPENDENCIES_DEFINES "IS_MOBILE")
|
set(DEPENDENCIES_DEFINES "IS_MOBILE")
|
||||||
else()
|
else()
|
||||||
set(DEPENDENCIES_DEFINES "")
|
set(DEPENDENCIES_DEFINES "")
|
||||||
|
@ -188,7 +192,7 @@ if (USE_SDL2)
|
||||||
endif()
|
endif()
|
||||||
message(STATUS "Using system-installed SDL2")
|
message(STATUS "Using system-installed SDL2")
|
||||||
else()
|
else()
|
||||||
if (ANDROID)
|
if (ANDROID AND NOT TERMUX)
|
||||||
set(SDL_SHARED ON CACHE BOOL "Force no dynamically-linked SDL" FORCE)
|
set(SDL_SHARED ON CACHE BOOL "Force no dynamically-linked SDL" FORCE)
|
||||||
set(SDL_STATIC OFF CACHE BOOL "Force statically-linked SDL" FORCE)
|
set(SDL_STATIC OFF CACHE BOOL "Force statically-linked SDL" FORCE)
|
||||||
else()
|
else()
|
||||||
|
@ -203,7 +207,7 @@ if (USE_SDL2)
|
||||||
add_subdirectory(extern/SDL EXCLUDE_FROM_ALL)
|
add_subdirectory(extern/SDL EXCLUDE_FROM_ALL)
|
||||||
list(APPEND DEPENDENCIES_DEFINES HAVE_SDL2)
|
list(APPEND DEPENDENCIES_DEFINES HAVE_SDL2)
|
||||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include)
|
list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include)
|
||||||
if (ANDROID)
|
if (ANDROID AND NOT TERMUX)
|
||||||
list(APPEND DEPENDENCIES_LIBRARIES SDL2)
|
list(APPEND DEPENDENCIES_LIBRARIES SDL2)
|
||||||
else()
|
else()
|
||||||
list(APPEND DEPENDENCIES_LIBRARIES SDL2-static)
|
list(APPEND DEPENDENCIES_LIBRARIES SDL2-static)
|
||||||
|
@ -579,7 +583,7 @@ endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_executable(furnace WIN32 ${USED_SOURCES})
|
add_executable(furnace WIN32 ${USED_SOURCES})
|
||||||
elseif(ANDROID)
|
elseif(ANDROID AND NOT TERMUX)
|
||||||
add_library(furnace SHARED ${USED_SOURCES})
|
add_library(furnace SHARED ${USED_SOURCES})
|
||||||
else()
|
else()
|
||||||
add_executable(furnace ${USED_SOURCES})
|
add_executable(furnace ${USED_SOURCES})
|
||||||
|
@ -602,7 +606,7 @@ if (PKG_CONFIG_FOUND AND (SYSTEM_FMT OR SYSTEM_LIBSNDFILE OR SYSTEM_ZLIB OR SYST
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT ANDROID)
|
if (NOT ANDROID OR TERMUX)
|
||||||
install(TARGETS furnace RUNTIME DESTINATION bin)
|
install(TARGETS furnace RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
if (NOT WIN32 AND NOT APPLE)
|
if (NOT WIN32 AND NOT APPLE)
|
||||||
|
|
8
TODO.md
8
TODO.md
|
@ -8,12 +8,10 @@
|
||||||
|
|
||||||
- additional YM2612 features
|
- additional YM2612 features
|
||||||
- CSM
|
- CSM
|
||||||
- DualPCM
|
- MSM6258 pitch and clock select
|
||||||
- reverse sample playback
|
- the last three compat flags
|
||||||
- ADPCM chips
|
- add OPL drum instrument type
|
||||||
- Game Boy envelope macro/sequence
|
- Game Boy envelope macro/sequence
|
||||||
- drag-and-drop ins/wave/sample loading
|
|
||||||
- "set loop" in right click menu of sample editor
|
|
||||||
- sample editor preview in selection
|
- sample editor preview in selection
|
||||||
- rewrite the system name detection function anyway
|
- rewrite the system name detection function anyway
|
||||||
- unified data view
|
- unified data view
|
||||||
|
|
BIN
demos/AY-3-8910_Jam.fur
Normal file
BIN
demos/AY-3-8910_Jam.fur
Normal file
Binary file not shown.
BIN
demos/AgentX.fur
Normal file
BIN
demos/AgentX.fur
Normal file
Binary file not shown.
BIN
demos/C64 junk.fur
Normal file
BIN
demos/C64 junk.fur
Normal file
Binary file not shown.
BIN
demos/Eternal_Forest_Taito_Arcade.fur
Normal file
BIN
demos/Eternal_Forest_Taito_Arcade.fur
Normal file
Binary file not shown.
BIN
demos/HoldOn.fur
Normal file
BIN
demos/HoldOn.fur
Normal file
Binary file not shown.
BIN
demos/Lagrange_Point.fur
Normal file
BIN
demos/Lagrange_Point.fur
Normal file
Binary file not shown.
BIN
demos/LedStorm.fur
Normal file
BIN
demos/LedStorm.fur
Normal file
Binary file not shown.
BIN
demos/Neo_Seaside_Volley_Court.fur
Normal file
BIN
demos/Neo_Seaside_Volley_Court.fur
Normal file
Binary file not shown.
BIN
demos/OPL3_SegaPCM_Xeno_Crisis_-_Facility_Area_2.fur
Normal file
BIN
demos/OPL3_SegaPCM_Xeno_Crisis_-_Facility_Area_2.fur
Normal file
Binary file not shown.
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
demo songs for Furnace.
|
demo songs for Furnace.
|
||||||
|
|
||||||
these demo songs are not under the GPL. in the case of covers, all rights are reserved to the original author.
|
these demo songs are not under the GPL. all rights are reserved to the original author(s).
|
||||||
|
|
||||||
# submit demo songs!
|
# submit demo songs!
|
||||||
|
|
||||||
just send a pull request if you want your song to be added to this collection. thank you!
|
contact me or send a pull request if you want your song to be added to this collection. be noted we have two rules:
|
||||||
|
|
||||||
|
- Nintendo covers are frowned upon
|
||||||
|
- big label music covers also are discouraged
|
||||||
|
|
||||||
|
thank you for contributing!
|
||||||
|
|
BIN
demos/Red_Planet.fur
Normal file
BIN
demos/Red_Planet.fur
Normal file
Binary file not shown.
BIN
demos/Road_Rash_Grass_Valley_Lynx_01d.fur
Normal file
BIN
demos/Road_Rash_Grass_Valley_Lynx_01d.fur
Normal file
Binary file not shown.
BIN
demos/Rusty_-_Queen_in_the_Dark_Night.fur
Normal file
BIN
demos/Rusty_-_Queen_in_the_Dark_Night.fur
Normal file
Binary file not shown.
BIN
demos/Samsung SGH-x830 - Ringtone 8.fur
Normal file
BIN
demos/Samsung SGH-x830 - Ringtone 8.fur
Normal file
Binary file not shown.
BIN
demos/Stereotactics_Rewritten.fur
Normal file
BIN
demos/Stereotactics_Rewritten.fur
Normal file
Binary file not shown.
BIN
demos/Tyrian-Camanis.fur
Normal file
BIN
demos/Tyrian-Camanis.fur
Normal file
Binary file not shown.
BIN
demos/UNATCOPCM.fur
Normal file
BIN
demos/UNATCOPCM.fur
Normal file
Binary file not shown.
BIN
demos/UT99_Run_Taito_Arcade.fur
Normal file
BIN
demos/UT99_Run_Taito_Arcade.fur
Normal file
Binary file not shown.
BIN
demos/carve_your_own_path.fur
Normal file
BIN
demos/carve_your_own_path.fur
Normal file
Binary file not shown.
BIN
demos/chippylotus.fur
Normal file
BIN
demos/chippylotus.fur
Normal file
Binary file not shown.
BIN
demos/doorintosummer.fur
Normal file
BIN
demos/doorintosummer.fur
Normal file
Binary file not shown.
BIN
demos/ecolove.fur
Normal file
BIN
demos/ecolove.fur
Normal file
Binary file not shown.
BIN
demos/fight and flight.fur
Normal file
BIN
demos/fight and flight.fur
Normal file
Binary file not shown.
BIN
demos/green_biker_dude_opl.fur
Normal file
BIN
demos/green_biker_dude_opl.fur
Normal file
Binary file not shown.
BIN
demos/insert_title_lynx.fur
Normal file
BIN
demos/insert_title_lynx.fur
Normal file
Binary file not shown.
BIN
demos/meteor_shower.fur
Normal file
BIN
demos/meteor_shower.fur
Normal file
Binary file not shown.
BIN
demos/oby1_ingame.fur
Normal file
BIN
demos/oby1_ingame.fur
Normal file
Binary file not shown.
BIN
demos/opll-fashioned_drums.fur
Normal file
BIN
demos/opll-fashioned_drums.fur
Normal file
Binary file not shown.
BIN
demos/puggs_in_space.fur
Normal file
BIN
demos/puggs_in_space.fur
Normal file
Binary file not shown.
BIN
demos/sijofsjfsoeife.fur
Normal file
BIN
demos/sijofsjfsoeife.fur
Normal file
Binary file not shown.
BIN
demos/skate_or_die.fur
Normal file
BIN
demos/skate_or_die.fur
Normal file
Binary file not shown.
BIN
demos/su_memory.fur
Normal file
BIN
demos/su_memory.fur
Normal file
Binary file not shown.
BIN
demos/yky.fur
BIN
demos/yky.fur
Binary file not shown.
26
extern/Nuked-PSG/ympsg.c
vendored
26
extern/Nuked-PSG/ympsg.c
vendored
|
@ -8,6 +8,10 @@ const float ympsg_vol[17] = {
|
||||||
1.0, 0.772, 0.622, 0.485, 0.382, 0.29, 0.229, 0.174, 0.132, 0.096, 0.072, 0.051, 0.034, 0.019, 0.009, 0.0, -1.059
|
1.0, 0.772, 0.622, 0.485, 0.382, 0.29, 0.229, 0.174, 0.132, 0.096, 0.072, 0.051, 0.034, 0.019, 0.009, 0.0, -1.059
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const float tipsg_vol[17] = {
|
||||||
|
1.0, 0.794, 0.631, 0.501, 0.398, 0.316, 0.251, 0.2, 0.158, 0.126, 0.1, 0.079, 0.063, 0.05, 0.04, 0.0, -1.059
|
||||||
|
};
|
||||||
|
|
||||||
static void YMPSG_WriteLatch(ympsg_t *chip)
|
static void YMPSG_WriteLatch(ympsg_t *chip)
|
||||||
{
|
{
|
||||||
uint8_t data = chip->data;
|
uint8_t data = chip->data;
|
||||||
|
@ -260,6 +264,10 @@ void YMPSG_Init(ympsg_t *chip, uint8_t real_sn)
|
||||||
YMPSG_SetIC(chip, 1);
|
YMPSG_SetIC(chip, 1);
|
||||||
chip->noise_tap2 = real_sn ? 13 : 15;
|
chip->noise_tap2 = real_sn ? 13 : 15;
|
||||||
chip->noise_size = real_sn ? 16383 : 32767;
|
chip->noise_size = real_sn ? 16383 : 32767;
|
||||||
|
for (i = 0; i < 17; i++)
|
||||||
|
{
|
||||||
|
chip->vol_table[i]=(real_sn?tipsg_vol[i]:ympsg_vol[i]) * 8192.0f;
|
||||||
|
}
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
YMPSG_Clock(chip);
|
YMPSG_Clock(chip);
|
||||||
|
@ -307,29 +315,29 @@ void YMPSG_Clock(ympsg_t *chip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float YMPSG_GetOutput(ympsg_t *chip)
|
int YMPSG_GetOutput(ympsg_t *chip)
|
||||||
{
|
{
|
||||||
float sample = 0.f;
|
int sample = 0;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
YMPSG_UpdateSample(chip);
|
YMPSG_UpdateSample(chip);
|
||||||
if (chip->test & 1)
|
if (chip->test & 1)
|
||||||
{
|
{
|
||||||
sample += ympsg_vol[chip->volume_out[chip->test >> 1]];
|
sample += chip->vol_table[chip->volume_out[chip->test >> 1]];
|
||||||
sample += ympsg_vol[16] * 3.f;
|
sample += chip->vol_table[16] * 3;
|
||||||
}
|
}
|
||||||
else if (!chip->mute)
|
else if (!chip->mute)
|
||||||
{
|
{
|
||||||
sample += ympsg_vol[chip->volume_out[0]];
|
sample += chip->vol_table[chip->volume_out[0]];
|
||||||
sample += ympsg_vol[chip->volume_out[1]];
|
sample += chip->vol_table[chip->volume_out[1]];
|
||||||
sample += ympsg_vol[chip->volume_out[2]];
|
sample += chip->vol_table[chip->volume_out[2]];
|
||||||
sample += ympsg_vol[chip->volume_out[3]];
|
sample += chip->vol_table[chip->volume_out[3]];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
if (!((chip->mute>>i) & 1))
|
if (!((chip->mute>>i) & 1))
|
||||||
sample += ympsg_vol[chip->volume_out[i]];
|
sample += chip->vol_table[chip->volume_out[i]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sample;
|
return sample;
|
||||||
|
|
6
extern/Nuked-PSG/ympsg.h
vendored
6
extern/Nuked-PSG/ympsg.h
vendored
|
@ -58,6 +58,10 @@ typedef struct {
|
||||||
uint64_t writebuf_lasttime;
|
uint64_t writebuf_lasttime;
|
||||||
ympsg_writebuf writebuf[YMPSG_WRITEBUF_SIZE];
|
ympsg_writebuf writebuf[YMPSG_WRITEBUF_SIZE];
|
||||||
|
|
||||||
|
//
|
||||||
|
short vol_table[17];
|
||||||
|
|
||||||
|
|
||||||
uint8_t mute;
|
uint8_t mute;
|
||||||
} ympsg_t;
|
} ympsg_t;
|
||||||
|
|
||||||
|
@ -67,7 +71,7 @@ uint16_t YMPSG_Read(ympsg_t *chip);
|
||||||
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn);
|
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn);
|
||||||
void YMPSG_SetIC(ympsg_t *chip, uint32_t ic);
|
void YMPSG_SetIC(ympsg_t *chip, uint32_t ic);
|
||||||
void YMPSG_Clock(ympsg_t *chip);
|
void YMPSG_Clock(ympsg_t *chip);
|
||||||
float YMPSG_GetOutput(ympsg_t *chip);
|
int YMPSG_GetOutput(ympsg_t *chip);
|
||||||
void YMPSG_Test(ympsg_t *chip, uint16_t test);
|
void YMPSG_Test(ympsg_t *chip, uint16_t test);
|
||||||
|
|
||||||
|
|
||||||
|
|
25
extern/backward/backward.hpp
vendored
25
extern/backward/backward.hpp
vendored
|
@ -4252,7 +4252,20 @@ public:
|
||||||
st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr);
|
st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* crashDump=fopen("furnace_crash.txt","w");
|
#ifdef _WIN32
|
||||||
|
MessageBox(NULL,"Error","Furnace has crashed! please report this to the issue tracker immediately:\r\nhttps://github.com/tildearrow/furnace/issues/new\r\n\r\na file called furnace_crash.txt will be created in your user directory.\r\nthis will be important for locating the origin of the crash.",MB_OK|MB_ICONERROR);
|
||||||
|
std::string crashLocation;
|
||||||
|
char* userProfile=getenv("USERPROFILE");
|
||||||
|
if (userProfile==NULL) {
|
||||||
|
crashLocation="C:\\furnace_crash.txt";
|
||||||
|
} else {
|
||||||
|
crashLocation=userProfile;
|
||||||
|
crashLocation+="\\furnace_crash.txt";
|
||||||
|
}
|
||||||
|
FILE* crashDump=fopen(crashLocation.c_str(),"w");
|
||||||
|
#else
|
||||||
|
FILE* crashDump=fopen("/tmp/furnace_crash.txt","w");
|
||||||
|
#endif
|
||||||
|
|
||||||
Printer printer;
|
Printer printer;
|
||||||
printer.address = true;
|
printer.address = true;
|
||||||
|
@ -4263,6 +4276,16 @@ public:
|
||||||
printer.address = true;
|
printer.address = true;
|
||||||
printer.print(st, crashDump);
|
printer.print(st, crashDump);
|
||||||
fclose(crashDump);
|
fclose(crashDump);
|
||||||
|
} else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::string str;
|
||||||
|
Printer failedPrinter;
|
||||||
|
failedPrinter.address = true;
|
||||||
|
failedPrinter.print(st, str);
|
||||||
|
str+="\r\ncould not open furnace_crash.txt!\r\nplease take a screenshot of this error message box!";
|
||||||
|
fprintf(stderr,"NOTICE: could not open furnace_crash.txt!\n");
|
||||||
|
MessageBox(NULL,"Error",str.c_str(),MB_OK|MB_ICONERROR);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || \
|
#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700) || \
|
||||||
|
|
77
extern/imgui_patched/imgui_internal.h
vendored
77
extern/imgui_patched/imgui_internal.h
vendored
|
@ -567,6 +567,36 @@ struct ImBitArray
|
||||||
void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); }
|
void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); }
|
||||||
void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2)
|
void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2)
|
||||||
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||||
|
ImBitArray& operator|=(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); return *this; }
|
||||||
|
bool operator&(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||||
|
bool operator==(ImBitArray const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ((BITCOUNT + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] != a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool operator!=(ImBitArray const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ((BITCOUNT + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] == a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template<int DSTBITCOUNT> bool operator==(ImBitArray<DSTBITCOUNT> const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ImMin((DSTBITCOUNT + 31) >> 5, (BITCOUNT + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] != a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template<int DSTBITCOUNT> bool operator!=(ImBitArray<DSTBITCOUNT> const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ImMin((DSTBITCOUNT + 31) >> 5, (BITCOUNT + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] == a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper: ImBitVector
|
// Helper: ImBitVector
|
||||||
|
@ -574,11 +604,33 @@ struct ImBitArray
|
||||||
struct IMGUI_API ImBitVector
|
struct IMGUI_API ImBitVector
|
||||||
{
|
{
|
||||||
ImVector<ImU32> Storage;
|
ImVector<ImU32> Storage;
|
||||||
void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
int BitCount = 0;
|
||||||
|
ImBitVector(int sz = 0) { if (sz > 0) { Create(sz); } }
|
||||||
|
void Create(int sz) { BitCount = sz; Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||||
void Clear() { Storage.clear(); }
|
void Clear() { Storage.clear(); }
|
||||||
bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); }
|
void ClearAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||||
void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }
|
void SetAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 255, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||||
void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }
|
bool TestBit(int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); }
|
||||||
|
void SetBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); }
|
||||||
|
void SetBitRange(int n, int n2) { IM_ASSERT(n >= 0 && n < BitCount && n2 > n && n2 <= BitCount); ImBitArraySetBitRange(Storage.Data, n, n2); } // Works on range [n..n2)
|
||||||
|
void ClearBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArrayClearBit(Storage.Data, n); }
|
||||||
|
bool operator[](int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); }
|
||||||
|
ImBitVector& operator|=(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); return *this; }
|
||||||
|
bool operator&(int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); }
|
||||||
|
bool operator==(ImBitVector const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] != a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool operator!=(ImBitVector const &a) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i)
|
||||||
|
if (Storage[i] == a.Storage[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper: ImSpan<>
|
// Helper: ImSpan<>
|
||||||
|
@ -2448,12 +2500,11 @@ struct IMGUI_API ImGuiTabBar
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
|
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
|
||||||
#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64.
|
#define IMGUI_TABLE_DRAW_CHANNELS(c) (4 + (c) * 2) // See TableSetupDrawChannels()
|
||||||
#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels()
|
|
||||||
|
|
||||||
// Our current column maximum is 64 but we may raise that in the future.
|
// Our current column maximum is IMGUI_TABLE_MAX_COLUMNS but we may raise that in the future.
|
||||||
typedef ImS8 ImGuiTableColumnIdx;
|
typedef ImS32 ImGuiTableColumnIdx;
|
||||||
typedef ImU8 ImGuiTableDrawChannelIdx;
|
typedef ImU32 ImGuiTableDrawChannelIdx;
|
||||||
|
|
||||||
// [Internal] sizeof() ~ 104
|
// [Internal] sizeof() ~ 104
|
||||||
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
|
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
|
||||||
|
@ -2543,10 +2594,10 @@ struct IMGUI_API ImGuiTable
|
||||||
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
||||||
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
||||||
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
|
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
|
||||||
ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
|
ImBitVector EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
|
||||||
ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
|
ImBitVector EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
|
||||||
ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
|
ImBitVector VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
|
||||||
ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items)
|
ImBitVector RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items)
|
||||||
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
|
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
|
||||||
int SettingsOffset; // Offset in g.SettingsTables
|
int SettingsOffset; // Offset in g.SettingsTables
|
||||||
int LastFrameActive;
|
int LastFrameActive;
|
||||||
|
|
72
extern/imgui_patched/imgui_tables.cpp
vendored
72
extern/imgui_patched/imgui_tables.cpp
vendored
|
@ -315,7 +315,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!");
|
IM_ASSERT(columns_count > 0 && "Only 1..64 columns allowed!");
|
||||||
if (flags & ImGuiTableFlags_ScrollX)
|
if (flags & ImGuiTableFlags_ScrollX)
|
||||||
IM_ASSERT(inner_width >= 0.0f);
|
IM_ASSERT(inner_width >= 0.0f);
|
||||||
|
|
||||||
|
@ -358,6 +358,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
|
||||||
table->LastFrameActive = g.FrameCount;
|
table->LastFrameActive = g.FrameCount;
|
||||||
table->OuterWindow = table->InnerWindow = outer_window;
|
table->OuterWindow = table->InnerWindow = outer_window;
|
||||||
table->ColumnsCount = columns_count;
|
table->ColumnsCount = columns_count;
|
||||||
|
if (table->EnabledMaskByDisplayOrder.BitCount < columns_count ||
|
||||||
|
table->EnabledMaskByIndex.BitCount < columns_count ||
|
||||||
|
table->VisibleMaskByIndex.BitCount < columns_count ||
|
||||||
|
table->RequestOutputMaskByIndex.BitCount < columns_count)
|
||||||
|
{
|
||||||
|
table->EnabledMaskByDisplayOrder.Create(columns_count);
|
||||||
|
table->EnabledMaskByIndex.Create(columns_count);
|
||||||
|
table->VisibleMaskByIndex.Create(columns_count);
|
||||||
|
table->RequestOutputMaskByIndex.Create(columns_count);
|
||||||
|
}
|
||||||
table->IsLayoutLocked = false;
|
table->IsLayoutLocked = false;
|
||||||
table->InnerWidth = inner_width;
|
table->InnerWidth = inner_width;
|
||||||
temp_data->UserOuterSize = outer_size;
|
temp_data->UserOuterSize = outer_size;
|
||||||
|
@ -721,8 +731,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
|
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
|
||||||
table->IsDefaultDisplayOrder = true;
|
table->IsDefaultDisplayOrder = true;
|
||||||
table->ColumnsEnabledCount = 0;
|
table->ColumnsEnabledCount = 0;
|
||||||
table->EnabledMaskByIndex = 0x00;
|
table->EnabledMaskByIndex.ClearAllBits();
|
||||||
table->EnabledMaskByDisplayOrder = 0x00;
|
table->EnabledMaskByDisplayOrder.ClearAllBits();
|
||||||
table->LeftMostEnabledColumn = -1;
|
table->LeftMostEnabledColumn = -1;
|
||||||
table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
|
table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
|
||||||
|
|
||||||
|
@ -787,8 +797,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
else
|
else
|
||||||
table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;
|
table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;
|
||||||
column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
|
column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
|
||||||
table->EnabledMaskByIndex |= (ImU64)1 << column_n;
|
table->EnabledMaskByIndex |= column_n;
|
||||||
table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder;
|
table->EnabledMaskByDisplayOrder |= column->DisplayOrder;
|
||||||
prev_visible_column_idx = column_n;
|
prev_visible_column_idx = column_n;
|
||||||
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
|
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
|
||||||
|
|
||||||
|
@ -836,7 +846,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
|
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
if (!(table->EnabledMaskByIndex & column_n))
|
||||||
continue;
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
|
|
||||||
|
@ -852,7 +862,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
|
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
|
||||||
if (column->AutoFitQueue != 0x00)
|
if (column->AutoFitQueue != 0x00)
|
||||||
column->WidthRequest = width_auto;
|
column->WidthRequest = width_auto;
|
||||||
else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)))
|
else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & column_n))
|
||||||
column->WidthRequest = width_auto;
|
column->WidthRequest = width_auto;
|
||||||
|
|
||||||
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
|
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
|
||||||
|
@ -899,7 +909,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
|
table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
if (!(table->EnabledMaskByIndex & column_n))
|
||||||
continue;
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
|
|
||||||
|
@ -926,7 +936,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
|
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
|
||||||
for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
|
for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
if (!(table->EnabledMaskByDisplayOrder & order_n))
|
||||||
continue;
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
|
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
|
||||||
if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))
|
if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))
|
||||||
|
@ -949,8 +959,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
|
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
|
||||||
ImRect host_clip_rect = table->InnerClipRect;
|
ImRect host_clip_rect = table->InnerClipRect;
|
||||||
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
|
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
|
||||||
table->VisibleMaskByIndex = 0x00;
|
table->VisibleMaskByIndex.ClearAllBits();
|
||||||
table->RequestOutputMaskByIndex = 0x00;
|
table->RequestOutputMaskByIndex.ClearAllBits();
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
{
|
{
|
||||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||||
|
@ -967,7 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
// Clear status flags
|
// Clear status flags
|
||||||
column->Flags &= ~ImGuiTableColumnFlags_StatusMask_;
|
column->Flags &= ~ImGuiTableColumnFlags_StatusMask_;
|
||||||
|
|
||||||
if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0)
|
if ((table->EnabledMaskByDisplayOrder & order_n) == 0)
|
||||||
{
|
{
|
||||||
// Hidden column: clear a few fields and we are done with it for the remainder of the function.
|
// Hidden column: clear a few fields and we are done with it for the remainder of the function.
|
||||||
// We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper.
|
// We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper.
|
||||||
|
@ -1020,12 +1030,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
||||||
column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y);
|
column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y);
|
||||||
const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;
|
const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;
|
||||||
if (is_visible)
|
if (is_visible)
|
||||||
table->VisibleMaskByIndex |= ((ImU64)1 << column_n);
|
table->VisibleMaskByIndex |= column_n;
|
||||||
|
|
||||||
// Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output.
|
// Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output.
|
||||||
column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;
|
column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;
|
||||||
if (column->IsRequestOutput)
|
if (column->IsRequestOutput)
|
||||||
table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n);
|
table->RequestOutputMaskByIndex |= column_n;
|
||||||
|
|
||||||
// Mark column as SkipItems (ignoring all items/layout)
|
// Mark column as SkipItems (ignoring all items/layout)
|
||||||
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
|
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
|
||||||
|
@ -1153,7 +1163,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
||||||
|
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
if (!(table->EnabledMaskByDisplayOrder & order_n))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||||
|
@ -1289,7 +1299,7 @@ void ImGui::EndTable()
|
||||||
float auto_fit_width_for_stretched = 0.0f;
|
float auto_fit_width_for_stretched = 0.0f;
|
||||||
float auto_fit_width_for_stretched_min = 0.0f;
|
float auto_fit_width_for_stretched_min = 0.0f;
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
|
if (table->EnabledMaskByIndex & column_n)
|
||||||
{
|
{
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);
|
float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);
|
||||||
|
@ -1480,7 +1490,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
|
||||||
ImGuiTable* table = g.CurrentTable;
|
ImGuiTable* table = g.CurrentTable;
|
||||||
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
|
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
|
||||||
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
|
IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
|
||||||
IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
|
IM_ASSERT(columns >= 0);
|
||||||
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
|
||||||
|
|
||||||
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0;
|
table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0;
|
||||||
|
@ -1635,7 +1645,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n
|
||||||
return;
|
return;
|
||||||
if (column_n == -1)
|
if (column_n == -1)
|
||||||
column_n = table->CurrentColumn;
|
column_n = table->CurrentColumn;
|
||||||
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
|
if ((table->VisibleMaskByIndex & column_n) == 0)
|
||||||
return;
|
return;
|
||||||
if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
|
if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
|
||||||
table->RowCellDataCurrent++;
|
table->RowCellDataCurrent++;
|
||||||
|
@ -1910,7 +1920,7 @@ bool ImGui::TableSetColumnIndex(int column_n)
|
||||||
|
|
||||||
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
|
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
|
||||||
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
|
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
|
||||||
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
|
return (table->RequestOutputMaskByIndex & column_n) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [Public] Append into the next column, wrap and create a new row when already on last column
|
// [Public] Append into the next column, wrap and create a new row when already on last column
|
||||||
|
@ -1936,7 +1946,7 @@ bool ImGui::TableNextColumn()
|
||||||
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
|
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
|
||||||
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
|
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
|
||||||
int column_n = table->CurrentColumn;
|
int column_n = table->CurrentColumn;
|
||||||
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
|
return (table->RequestOutputMaskByIndex & column_n) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2349,17 +2359,23 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||||
{
|
{
|
||||||
ImRect ClipRect;
|
ImRect ClipRect;
|
||||||
int ChannelsCount;
|
int ChannelsCount;
|
||||||
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> ChannelsMask;
|
ImBitVector ChannelsMask;
|
||||||
|
|
||||||
MergeGroup() { ChannelsCount = 0; }
|
MergeGroup(int sz) : ChannelsMask(sz) { ChannelsCount = 0; }
|
||||||
};
|
};
|
||||||
int merge_group_mask = 0x00;
|
int merge_group_mask = 0x00;
|
||||||
MergeGroup merge_groups[4];
|
int merge_group_bitlen = IMGUI_TABLE_DRAW_CHANNELS(table->ColumnsCount);
|
||||||
|
MergeGroup merge_groups[4]{
|
||||||
|
merge_group_bitlen,
|
||||||
|
merge_group_bitlen,
|
||||||
|
merge_group_bitlen,
|
||||||
|
merge_group_bitlen
|
||||||
|
};
|
||||||
|
|
||||||
// 1. Scan channels and take note of those which can be merged
|
// 1. Scan channels and take note of those which can be merged
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
|
if ((table->VisibleMaskByIndex & column_n) == 0)
|
||||||
continue;
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
|
|
||||||
|
@ -2391,7 +2407,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||||
}
|
}
|
||||||
|
|
||||||
const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2);
|
const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2);
|
||||||
IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS);
|
IM_ASSERT(channel_no < merge_group_bitlen);
|
||||||
MergeGroup* merge_group = &merge_groups[merge_group_n];
|
MergeGroup* merge_group = &merge_groups[merge_group_n];
|
||||||
if (merge_group->ChannelsCount == 0)
|
if (merge_group->ChannelsCount == 0)
|
||||||
merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
|
merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||||
|
@ -2431,7 +2447,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||||
const int LEADING_DRAW_CHANNELS = 2;
|
const int LEADING_DRAW_CHANNELS = 2;
|
||||||
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
|
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
|
||||||
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
|
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
|
||||||
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask; // We need 132-bit of storage
|
ImBitVector remaining_mask(merge_group_bitlen); // We need 132-bit of storage
|
||||||
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count);
|
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count);
|
||||||
remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
|
remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
|
||||||
IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
|
IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
|
||||||
|
@ -2466,7 +2482,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
|
||||||
GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200));
|
GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200));
|
||||||
#endif
|
#endif
|
||||||
remaining_count -= merge_group->ChannelsCount;
|
remaining_count -= merge_group->ChannelsCount;
|
||||||
for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++)
|
for (int n = 0; n < remaining_mask.Storage.size(); n++)
|
||||||
remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n];
|
remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n];
|
||||||
for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)
|
for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)
|
||||||
{
|
{
|
||||||
|
@ -2523,7 +2539,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
||||||
{
|
{
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
if (!(table->EnabledMaskByDisplayOrder & order_n))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||||
|
|
|
@ -29,6 +29,8 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 99: Furnace dev99
|
||||||
|
- 98: Furnace dev98
|
||||||
- 97: Furnace dev97
|
- 97: Furnace dev97
|
||||||
- 96: Furnace dev96
|
- 96: Furnace dev96
|
||||||
- 95: Furnace dev95
|
- 95: Furnace dev95
|
||||||
|
@ -226,6 +228,9 @@ size | description
|
||||||
| - 0xb9: Namco WSG - 3 channels
|
| - 0xb9: Namco WSG - 3 channels
|
||||||
| - 0xba: Namco 15xx - 8 channels
|
| - 0xba: Namco 15xx - 8 channels
|
||||||
| - 0xbb: Namco CUS30 - 8 channels
|
| - 0xbb: Namco CUS30 - 8 channels
|
||||||
|
| - 0xbc: reserved - 8 channels
|
||||||
|
| - 0xbd: YM2612 extra features extended - 11 channels
|
||||||
|
| - 0xbe: YM2612 extra features - 7 channels
|
||||||
| - 0xde: YM2610B extended - 19 channels
|
| - 0xde: YM2610B extended - 19 channels
|
||||||
| - 0xe0: QSound - 19 channels
|
| - 0xe0: QSound - 19 channels
|
||||||
| - 0xfd: Dummy System - 8 channels
|
| - 0xfd: Dummy System - 8 channels
|
||||||
|
@ -302,7 +307,11 @@ size | description
|
||||||
1 | pitch macro is linear (>=90) or reserved
|
1 | pitch macro is linear (>=90) or reserved
|
||||||
1 | pitch slide speed in full linear pitch mode (>=94) or reserved
|
1 | pitch slide speed in full linear pitch mode (>=94) or reserved
|
||||||
1 | old octave boundary behavior (>=97) or reserved
|
1 | old octave boundary behavior (>=97) or reserved
|
||||||
13 | reserved
|
1 | disable OPN2 DAC volume control (>=98) or reserved
|
||||||
|
1 | new volume scaling strategy (>=99) or reserved
|
||||||
|
1 | volume macro still applies after end (>=99) or reserved
|
||||||
|
1 | broken outVol (>=99) or reserved
|
||||||
|
9 | reserved
|
||||||
--- | **virtual tempo data**
|
--- | **virtual tempo data**
|
||||||
2 | virtual tempo numerator of first song (>=96) or reserved
|
2 | virtual tempo numerator of first song (>=96) or reserved
|
||||||
2 | virtual tempo denominator of first song (>=96) or reserved
|
2 | virtual tempo denominator of first song (>=96) or reserved
|
||||||
|
|
|
@ -59,6 +59,7 @@ enum DivDispatchCmds {
|
||||||
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
DIV_CMD_SAMPLE_FREQ, // (frequency)
|
||||||
DIV_CMD_SAMPLE_BANK, // (bank)
|
DIV_CMD_SAMPLE_BANK, // (bank)
|
||||||
DIV_CMD_SAMPLE_POS, // (pos)
|
DIV_CMD_SAMPLE_POS, // (pos)
|
||||||
|
DIV_CMD_SAMPLE_DIR, // (direction)
|
||||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, // (enabled)
|
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, // (enabled)
|
||||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, // (slice)
|
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, // (slice)
|
||||||
|
|
||||||
|
@ -236,6 +237,8 @@ struct DivRegWrite {
|
||||||
* - data is the sample rate
|
* - data is the sample rate
|
||||||
* - 0xffffxx02: stop sample playback
|
* - 0xffffxx02: stop sample playback
|
||||||
* - xx is the instance ID
|
* - xx is the instance ID
|
||||||
|
* - 0xffffxx03: set sample playback direction
|
||||||
|
* - x is the instance ID
|
||||||
* - 0xffffffff: reset
|
* - 0xffffffff: reset
|
||||||
*/
|
*/
|
||||||
unsigned int addr;
|
unsigned int addr;
|
||||||
|
|
|
@ -185,10 +185,22 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
||||||
case DIV_SYSTEM_YM2612:
|
case DIV_SYSTEM_YM2612:
|
||||||
dispatch=new DivPlatformGenesis;
|
dispatch=new DivPlatformGenesis;
|
||||||
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||||
|
((DivPlatformGenesis*)dispatch)->setSoftPCM(false);
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_YM2612_EXT:
|
case DIV_SYSTEM_YM2612_EXT:
|
||||||
dispatch=new DivPlatformGenesisExt;
|
dispatch=new DivPlatformGenesisExt;
|
||||||
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||||
|
((DivPlatformGenesisExt*)dispatch)->setSoftPCM(false);
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC:
|
||||||
|
dispatch=new DivPlatformGenesis;
|
||||||
|
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||||
|
((DivPlatformGenesis*)dispatch)->setSoftPCM(true);
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_YM2612_FRAC_EXT:
|
||||||
|
dispatch=new DivPlatformGenesisExt;
|
||||||
|
((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||||
|
((DivPlatformGenesisExt*)dispatch)->setSoftPCM(true);
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_SMS:
|
case DIV_SYSTEM_SMS:
|
||||||
dispatch=new DivPlatformSMS;
|
dispatch=new DivPlatformSMS;
|
||||||
|
|
|
@ -697,7 +697,7 @@ void DivEngine::initSongWithDesc(const int* description) {
|
||||||
song.systemFlags[index]=description[i+3];
|
song.systemFlags[index]=description[i+3];
|
||||||
index++;
|
index++;
|
||||||
chanCount+=getChannelCount(song.system[index]);
|
chanCount+=getChannelCount(song.system[index]);
|
||||||
if (chanCount>=63) break;
|
if (chanCount>=DIV_MAX_CHANS) break;
|
||||||
if (index>=32) break;
|
if (index>=32) break;
|
||||||
}
|
}
|
||||||
song.systemLen=index;
|
song.systemLen=index;
|
||||||
|
@ -887,9 +887,8 @@ bool DivEngine::addSystem(DivSystem which) {
|
||||||
lastError="max number of systems is 32";
|
lastError="max number of systems is 32";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// this was DIV_MAX_CHANS but I am setting it to 63 for now due to an ImGui limitation
|
if (chans+getChannelCount(which)>DIV_MAX_CHANS) {
|
||||||
if (chans+getChannelCount(which)>63) {
|
lastError=fmt::sprintf("max number of total channels is %d",DIV_MAX_CHANS);
|
||||||
lastError="max number of total channels is 63";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
quitDispatch();
|
quitDispatch();
|
||||||
|
@ -1773,7 +1772,7 @@ int DivEngine::addWave() {
|
||||||
return waveCount;
|
return waveCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivEngine::addWaveFromFile(const char* path) {
|
bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
||||||
if (song.wave.size()>=256) {
|
if (song.wave.size()>=256) {
|
||||||
lastError="too many wavetables!";
|
lastError="too many wavetables!";
|
||||||
return false;
|
return false;
|
||||||
|
@ -1869,6 +1868,7 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// read as binary
|
// read as binary
|
||||||
|
if (addRaw) {
|
||||||
logI("reading binary...");
|
logI("reading binary...");
|
||||||
len=reader.size();
|
len=reader.size();
|
||||||
if (len>256) len=256;
|
if (len>256) len=256;
|
||||||
|
@ -1878,9 +1878,15 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
||||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||||
}
|
}
|
||||||
wave->len=len;
|
wave->len=len;
|
||||||
|
} else {
|
||||||
|
delete wave;
|
||||||
|
delete[] buf;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (EndOfFileException& e) {
|
} catch (EndOfFileException& e) {
|
||||||
// read as binary
|
// read as binary
|
||||||
|
if (addRaw) {
|
||||||
len=reader.size();
|
len=reader.size();
|
||||||
logI("reading binary for being too small...");
|
logI("reading binary for being too small...");
|
||||||
if (len>256) len=256;
|
if (len>256) len=256;
|
||||||
|
@ -1890,6 +1896,11 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
||||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||||
}
|
}
|
||||||
wave->len=len;
|
wave->len=len;
|
||||||
|
} else {
|
||||||
|
delete wave;
|
||||||
|
delete[] buf;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (EndOfFileException& e) {
|
} catch (EndOfFileException& e) {
|
||||||
|
|
|
@ -45,8 +45,8 @@
|
||||||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||||
|
|
||||||
#define DIV_VERSION "dev97"
|
#define DIV_VERSION "dev99"
|
||||||
#define DIV_ENGINE_VERSION 97
|
#define DIV_ENGINE_VERSION 99
|
||||||
|
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
|
@ -377,7 +377,7 @@ class DivEngine {
|
||||||
void processRow(int i, bool afterDelay);
|
void processRow(int i, bool afterDelay);
|
||||||
void nextOrder();
|
void nextOrder();
|
||||||
void nextRow();
|
void nextRow();
|
||||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond);
|
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond);
|
||||||
// returns true if end of song.
|
// returns true if end of song.
|
||||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
|
@ -676,7 +676,7 @@ class DivEngine {
|
||||||
int addWave();
|
int addWave();
|
||||||
|
|
||||||
// add wavetable from file
|
// add wavetable from file
|
||||||
bool addWaveFromFile(const char* path);
|
bool addWaveFromFile(const char* path, bool loadRaw=true);
|
||||||
|
|
||||||
// delete wavetable
|
// delete wavetable
|
||||||
void delWave(int index);
|
void delWave(int index);
|
||||||
|
|
|
@ -167,6 +167,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
||||||
ds.fbPortaPause=true;
|
ds.fbPortaPause=true;
|
||||||
ds.snDutyReset=true;
|
ds.snDutyReset=true;
|
||||||
ds.oldOctaveBoundary=false;
|
ds.oldOctaveBoundary=false;
|
||||||
|
ds.noOPN2Vol=true;
|
||||||
|
ds.newVolumeScaling=false;
|
||||||
|
ds.volMacroLinger=false;
|
||||||
|
ds.brokenOutVol=true; // ???
|
||||||
|
|
||||||
// 1.1 compat flags
|
// 1.1 compat flags
|
||||||
if (ds.version>24) {
|
if (ds.version>24) {
|
||||||
|
@ -1031,6 +1035,14 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
if (ds.version<97) {
|
if (ds.version<97) {
|
||||||
ds.oldOctaveBoundary=true;
|
ds.oldOctaveBoundary=true;
|
||||||
}
|
}
|
||||||
|
if (ds.version<97) { // actually should be 98 but yky uses this feature ahead of time
|
||||||
|
ds.noOPN2Vol=true;
|
||||||
|
}
|
||||||
|
if (ds.version<99) {
|
||||||
|
ds.newVolumeScaling=false;
|
||||||
|
ds.volMacroLinger=false;
|
||||||
|
ds.brokenOutVol=true;
|
||||||
|
}
|
||||||
ds.isDMF=false;
|
ds.isDMF=false;
|
||||||
|
|
||||||
reader.readS(); // reserved
|
reader.readS(); // reserved
|
||||||
|
@ -1413,7 +1425,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
for (int i=0; i<13; i++) {
|
if (ds.version>=98) {
|
||||||
|
ds.noOPN2Vol=reader.readC();
|
||||||
|
} else {
|
||||||
|
reader.readC();
|
||||||
|
}
|
||||||
|
if (ds.version>=99) {
|
||||||
|
ds.newVolumeScaling=reader.readC();
|
||||||
|
ds.volMacroLinger=reader.readC();
|
||||||
|
ds.brokenOutVol=reader.readC();
|
||||||
|
} else {
|
||||||
|
reader.readC();
|
||||||
|
reader.readC();
|
||||||
|
reader.readC();
|
||||||
|
}
|
||||||
|
for (int i=0; i<9; i++) {
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2894,7 +2920,11 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
||||||
w->writeC(song.pitchMacroIsLinear);
|
w->writeC(song.pitchMacroIsLinear);
|
||||||
w->writeC(song.pitchSlideSpeed);
|
w->writeC(song.pitchSlideSpeed);
|
||||||
w->writeC(song.oldOctaveBoundary);
|
w->writeC(song.oldOctaveBoundary);
|
||||||
for (int i=0; i<13; i++) {
|
w->writeC(song.noOPN2Vol);
|
||||||
|
w->writeC(song.newVolumeScaling);
|
||||||
|
w->writeC(song.volMacroLinger);
|
||||||
|
w->writeC(song.brokenOutVol);
|
||||||
|
for (int i=0; i<9; i++) {
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,50 +125,108 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
||||||
case 0x5f:
|
case 0x5f:
|
||||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||||
break;
|
break;
|
||||||
|
case 0xdf:
|
||||||
|
return "DFxx: Set sample playback direction (0: normal; 1: reverse)";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformGenesis::processDAC() {
|
||||||
|
if (softPCM) {
|
||||||
|
softPCMTimer+=chipClock/576;
|
||||||
|
if (softPCMTimer>rate) {
|
||||||
|
softPCMTimer-=rate;
|
||||||
|
|
||||||
|
int sample=0;
|
||||||
|
for (int i=5; i<7; i++) {
|
||||||
|
if (chan[i].dacSample!=-1) {
|
||||||
|
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||||
|
if (!isMuted[i] && s->samples>0) {
|
||||||
|
if (parent->song.noOPN2Vol) {
|
||||||
|
sample+=s->data8[chan[i].getDacDirection()?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
|
||||||
|
} else {
|
||||||
|
sample+=(s->data8[chan[i].getDacDirection()?(s->samples-chan[i].dacPos-1):chan[i].dacPos]*dacVolTable[chan[i].outVol])>>7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan[i].dacPeriod+=chan[i].dacRate;
|
||||||
|
if (chan[i].dacPeriod>=(chipClock/576)) {
|
||||||
|
if (s->samples>0) {
|
||||||
|
while (chan[i].dacPeriod>=(chipClock/576)) {
|
||||||
|
chan[i].dacPos++;
|
||||||
|
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[i].dacPos>=s->loopEnd) || (chan[i].dacPos>=s->samples)) {
|
||||||
|
if (s->isLoopable() && !chan[i].getDacDirection()) {
|
||||||
|
chan[i].dacPos=s->loopStart;
|
||||||
|
} else {
|
||||||
|
chan[i].dacSample=-1;
|
||||||
|
chan[i].dacPeriod=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan[i].dacPeriod-=(chipClock/576);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chan[i].dacSample=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//sample>>=1;
|
||||||
|
if (sample<-128) sample=-128;
|
||||||
|
if (sample>127) sample=127;
|
||||||
|
urgentWrite(0x2a,(unsigned char)sample+0x80);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!chan[5].dacReady) {
|
||||||
|
chan[5].dacDelay+=32000;
|
||||||
|
if (chan[5].dacDelay>=rate) {
|
||||||
|
chan[5].dacDelay-=rate;
|
||||||
|
chan[5].dacReady=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[5].dacMode && chan[5].dacSample!=-1) {
|
||||||
|
chan[5].dacPeriod+=chan[5].dacRate;
|
||||||
|
if (chan[5].dacPeriod>=rate) {
|
||||||
|
DivSample* s=parent->getSample(chan[5].dacSample);
|
||||||
|
if (s->samples>0) {
|
||||||
|
if (!isMuted[5]) {
|
||||||
|
if (chan[5].dacReady && writes.size()<16) {
|
||||||
|
int sample;
|
||||||
|
if (parent->song.noOPN2Vol) {
|
||||||
|
sample=s->data8[chan[5].getDacDirection()?(s->samples-chan[5].dacPos-1):chan[5].dacPos];
|
||||||
|
} else {
|
||||||
|
sample=(s->data8[chan[5].getDacDirection()?(s->samples-chan[5].dacPos-1):chan[5].dacPos]*dacVolTable[chan[5].outVol])>>7;
|
||||||
|
}
|
||||||
|
urgentWrite(0x2a,(unsigned char)sample+0x80);
|
||||||
|
chan[5].dacReady=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chan[5].dacPos++;
|
||||||
|
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && chan[5].dacPos>=s->loopEnd) || (chan[5].dacPos>=s->samples)) {
|
||||||
|
if (s->isLoopable() && !chan[5].getDacDirection()) {
|
||||||
|
chan[5].dacPos=s->loopStart;
|
||||||
|
} else {
|
||||||
|
chan[5].dacSample=-1;
|
||||||
|
if (parent->song.brokenDACMode) {
|
||||||
|
rWrite(0x2b,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (chan[5].dacPeriod>=rate) chan[5].dacPeriod-=rate;
|
||||||
|
} else {
|
||||||
|
chan[5].dacSample=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
static short o[2];
|
static short o[2];
|
||||||
static int os[2];
|
static int os[2];
|
||||||
|
|
||||||
for (size_t h=start; h<start+len; h++) {
|
for (size_t h=start; h<start+len; h++) {
|
||||||
if (!dacReady) {
|
processDAC();
|
||||||
dacDelay+=32000;
|
|
||||||
if (dacDelay>=rate) {
|
|
||||||
dacDelay-=rate;
|
|
||||||
dacReady=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dacMode && dacSample!=-1) {
|
|
||||||
dacPeriod+=dacRate;
|
|
||||||
if (dacPeriod>=rate) {
|
|
||||||
DivSample* s=parent->getSample(dacSample);
|
|
||||||
if (s->samples>0) {
|
|
||||||
if (!isMuted[5]) {
|
|
||||||
if (dacReady && writes.size()<16) {
|
|
||||||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
|
||||||
dacReady=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dacPos++;
|
|
||||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) {
|
|
||||||
if (s->isLoopable()) {
|
|
||||||
dacPos=s->loopStart;
|
|
||||||
} else {
|
|
||||||
dacSample=-1;
|
|
||||||
if (parent->song.brokenDACMode) {
|
|
||||||
rWrite(0x2b,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (dacPeriod>=rate) dacPeriod-=rate;
|
|
||||||
} else {
|
|
||||||
dacSample=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os[0]=0; os[1]=0;
|
os[0]=0; os[1]=0;
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
|
@ -215,41 +273,7 @@ void DivPlatformGenesis::acquire_ymfm(short* bufL, short* bufR, size_t start, si
|
||||||
ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine();
|
ymfm::ym2612::fm_engine* fme=fm_ymfm->debug_engine();
|
||||||
|
|
||||||
for (size_t h=start; h<start+len; h++) {
|
for (size_t h=start; h<start+len; h++) {
|
||||||
if (!dacReady) {
|
processDAC();
|
||||||
dacDelay+=32000;
|
|
||||||
if (dacDelay>=rate) {
|
|
||||||
dacDelay-=rate;
|
|
||||||
dacReady=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dacMode && dacSample!=-1) {
|
|
||||||
dacPeriod+=dacRate;
|
|
||||||
if (dacPeriod>=rate) {
|
|
||||||
DivSample* s=parent->getSample(dacSample);
|
|
||||||
if (s->samples>0) {
|
|
||||||
if (!isMuted[5]) {
|
|
||||||
if (dacReady && writes.size()<16) {
|
|
||||||
urgentWrite(0x2a,(unsigned char)s->data8[dacPos]+0x80);
|
|
||||||
dacReady=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dacPos++;
|
|
||||||
if (((s->loopMode!=DIV_SAMPLE_LOOPMODE_ONESHOT) && dacPos>=s->loopEnd) || (dacPos>=s->samples)) {
|
|
||||||
if (s->isLoopable()) {
|
|
||||||
dacPos=s->loopStart;
|
|
||||||
} else {
|
|
||||||
dacSample=-1;
|
|
||||||
if (parent->song.brokenDACMode) {
|
|
||||||
rWrite(0x2b,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (dacPeriod>=rate) dacPeriod-=rate;
|
|
||||||
} else {
|
|
||||||
dacSample=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os[0]=0; os[1]=0;
|
os[0]=0; os[1]=0;
|
||||||
if (!writes.empty()) {
|
if (!writes.empty()) {
|
||||||
|
@ -474,7 +498,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<8; i++) {
|
||||||
if (i==2 && extMode) continue;
|
if (i==2 && extMode) continue;
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
if (parent->song.linearPitch==2) {
|
if (parent->song.linearPitch==2) {
|
||||||
|
@ -493,12 +517,14 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
||||||
chan[i].freq=(block<<11)|fNum;
|
chan[i].freq=(block<<11)|fNum;
|
||||||
}
|
}
|
||||||
if (chan[i].freq>0x3fff) chan[i].freq=0x3fff;
|
if (chan[i].freq>0x3fff) chan[i].freq=0x3fff;
|
||||||
|
if (i<6) {
|
||||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||||
if (chan[i].furnaceDac && dacMode) {
|
}
|
||||||
|
if (chan[i].furnaceDac && chan[i].dacMode) {
|
||||||
double off=1.0;
|
double off=1.0;
|
||||||
if (dacSample>=0 && dacSample<parent->song.sampleLen) {
|
if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
|
||||||
DivSample* s=parent->getSample(dacSample);
|
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||||
if (s->centerRate<1) {
|
if (s->centerRate<1) {
|
||||||
off=1.0;
|
off=1.0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -506,14 +532,14 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
||||||
dacRate=chan[i].freq*off;
|
chan[i].dacRate=chan[i].freq*off;
|
||||||
if (dacRate<1) dacRate=1;
|
if (chan[i].dacRate<1) chan[i].dacRate=1;
|
||||||
if (dumpWrites) addWrite(0xffff0001,dacRate);
|
if (dumpWrites) addWrite(0xffff0001,chan[i].dacRate);
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
if (chan[i].keyOn) {
|
if (chan[i].keyOn) {
|
||||||
immWrite(0x28,0xf0|konOffs[i]);
|
if (i<6) immWrite(0x28,0xf0|konOffs[i]);
|
||||||
chan[i].keyOn=false;
|
chan[i].keyOn=false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,6 +547,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
||||||
|
|
||||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||||
isMuted[ch]=mute;
|
isMuted[ch]=mute;
|
||||||
|
if (ch>5) return;
|
||||||
for (int j=0; j<4; j++) {
|
for (int j=0; j<4; j++) {
|
||||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||||
|
@ -541,29 +568,33 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
if (c.chan==5) {
|
if (c.chan>=5) {
|
||||||
if (ins->type==DIV_INS_AMIGA) {
|
if (ins->type==DIV_INS_AMIGA) {
|
||||||
dacMode=1;
|
chan[c.chan].dacMode=1;
|
||||||
rWrite(0x2b,1<<7);
|
rWrite(0x2b,1<<7);
|
||||||
} else if (chan[c.chan].furnaceDac) {
|
} else if (chan[c.chan].furnaceDac) {
|
||||||
dacMode=0;
|
chan[c.chan].dacMode=0;
|
||||||
rWrite(0x2b,0<<7);
|
rWrite(0x2b,0<<7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c.chan==5 && dacMode) {
|
if (c.chan>=5 && chan[c.chan].dacMode) {
|
||||||
if (skipRegisterWrites) break;
|
if (skipRegisterWrites) break;
|
||||||
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
||||||
dacSample=ins->amiga.getSample(c.value);
|
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||||
dacSample=-1;
|
chan[c.chan].dacSample=-1;
|
||||||
if (dumpWrites) addWrite(0xffff0002,0);
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
chan[c.chan].dacReversed=ins->amiga.getReversed(c.value);
|
||||||
rWrite(0x2b,1<<7);
|
rWrite(0x2b,1<<7);
|
||||||
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
if (dumpWrites) {
|
||||||
|
addWrite(0xffff0000,chan[c.chan].dacSample);
|
||||||
|
addWrite(0xffff0003,chan[c.chan].getDacDirection());
|
||||||
}
|
}
|
||||||
dacPos=0;
|
}
|
||||||
dacPeriod=0;
|
chan[c.chan].dacPos=0;
|
||||||
|
chan[c.chan].dacPeriod=0;
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
|
@ -573,23 +604,25 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
}
|
}
|
||||||
dacSample=12*sampleBank+chan[c.chan].note%12;
|
chan[c.chan].dacSample=12*chan[c.chan].sampleBank+chan[c.chan].note%12;
|
||||||
if (dacSample>=parent->song.sampleLen) {
|
if (chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||||
dacSample=-1;
|
chan[c.chan].dacSample=-1;
|
||||||
if (dumpWrites) addWrite(0xffff0002,0);
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
rWrite(0x2b,1<<7);
|
rWrite(0x2b,1<<7);
|
||||||
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
if (dumpWrites) addWrite(0xffff0000,chan[c.chan].dacSample);
|
||||||
}
|
}
|
||||||
dacPos=0;
|
chan[c.chan].dacPos=0;
|
||||||
dacPeriod=0;
|
chan[c.chan].dacPeriod=0;
|
||||||
dacRate=MAX(1,parent->getSample(dacSample)->rate);
|
chan[c.chan].dacRate=MAX(1,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||||
if (dumpWrites) addWrite(0xffff0001,parent->getSample(dacSample)->rate);
|
if (dumpWrites) addWrite(0xffff0001,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||||
chan[c.chan].furnaceDac=false;
|
chan[c.chan].furnaceDac=false;
|
||||||
|
chan[c.chan].dacReversed=false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (c.chan>=6) break;
|
||||||
|
|
||||||
if (chan[c.chan].insChanged) {
|
if (chan[c.chan].insChanged) {
|
||||||
chan[c.chan].state=ins->fm;
|
chan[c.chan].state=ins->fm;
|
||||||
|
@ -642,12 +675,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_NOTE_OFF:
|
case DIV_CMD_NOTE_OFF:
|
||||||
if (c.chan==5) {
|
if (c.chan>=5) {
|
||||||
dacSample=-1;
|
chan[c.chan].dacSample=-1;
|
||||||
if (dumpWrites) addWrite(0xffff0002,0);
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
if (parent->song.brokenDACMode) {
|
if (parent->song.brokenDACMode) {
|
||||||
rWrite(0x2b,0);
|
rWrite(0x2b,0);
|
||||||
if (dacMode) break;
|
if (chan[c.chan].dacMode) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
|
@ -655,8 +688,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
if (c.chan==5) {
|
if (c.chan>=5) {
|
||||||
dacSample=-1;
|
chan[c.chan].dacSample=-1;
|
||||||
if (dumpWrites) addWrite(0xffff0002,0);
|
if (dumpWrites) addWrite(0xffff0002,0);
|
||||||
}
|
}
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
|
@ -672,6 +705,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].std.vol.has) {
|
if (!chan[c.chan].std.vol.has) {
|
||||||
chan[c.chan].outVol=c.value;
|
chan[c.chan].outVol=c.value;
|
||||||
}
|
}
|
||||||
|
if (c.chan>=6) break;
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -698,6 +732,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
chan[c.chan].ins=c.value;
|
chan[c.chan].ins=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_PANNING: {
|
case DIV_CMD_PANNING: {
|
||||||
|
if (c.chan>5) c.chan=5;
|
||||||
if (c.value==0 && c.value2==0) {
|
if (c.value==0 && c.value2==0) {
|
||||||
chan[c.chan].pan=3;
|
chan[c.chan].pan=3;
|
||||||
} else {
|
} else {
|
||||||
|
@ -735,7 +770,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||||
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
|
int destFreq=parent->calcBaseFreq(1,1,c.value2,false);
|
||||||
bool return2=false;
|
bool return2=false;
|
||||||
if (destFreq>chan[c.chan].baseFreq) {
|
if (destFreq>chan[c.chan].baseFreq) {
|
||||||
|
@ -762,18 +797,26 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_SAMPLE_MODE: {
|
case DIV_CMD_SAMPLE_MODE: {
|
||||||
dacMode=c.value;
|
if (c.chan<5) c.chan=5;
|
||||||
|
chan[c.chan].dacMode=c.value;
|
||||||
rWrite(0x2b,c.value<<7);
|
rWrite(0x2b,c.value<<7);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_SAMPLE_BANK:
|
case DIV_CMD_SAMPLE_BANK:
|
||||||
sampleBank=c.value;
|
if (c.chan<5) c.chan=5;
|
||||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
chan[c.chan].sampleBank=c.value;
|
||||||
sampleBank=parent->song.sample.size()/12;
|
if (chan[c.chan].sampleBank>(parent->song.sample.size()/12)) {
|
||||||
|
chan[c.chan].sampleBank=parent->song.sample.size()/12;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_SAMPLE_DIR: {
|
||||||
|
if (c.chan<5) c.chan=5;
|
||||||
|
chan[c.chan].dacDirection=c.value;
|
||||||
|
if (dumpWrites) addWrite(0xffff0003,chan[c.chan].dacDirection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_CMD_LEGATO: {
|
case DIV_CMD_LEGATO: {
|
||||||
if (c.chan==5 && chan[c.chan].furnaceDac && dacMode) {
|
if (c.chan>=5 && chan[c.chan].furnaceDac && chan[c.chan].dacMode) {
|
||||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||||
|
@ -783,16 +826,19 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_LFO: {
|
case DIV_CMD_FM_LFO: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
lfoValue=(c.value&7)|((c.value>>4)<<3);
|
lfoValue=(c.value&7)|((c.value>>4)<<3);
|
||||||
rWrite(0x22,lfoValue);
|
rWrite(0x22,lfoValue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
chan[c.chan].state.fb=c.value&7;
|
chan[c.chan].state.fb=c.value&7;
|
||||||
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: {
|
case DIV_CMD_FM_MULT: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.mult=c.value2&15;
|
op.mult=c.value2&15;
|
||||||
|
@ -800,6 +846,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: {
|
case DIV_CMD_FM_TL: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||||
op.tl=c.value2;
|
op.tl=c.value2;
|
||||||
|
@ -815,6 +862,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -831,6 +879,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RS: {
|
case DIV_CMD_FM_RS: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -847,6 +896,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AM: {
|
case DIV_CMD_FM_AM: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -863,6 +913,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_DR: {
|
case DIV_CMD_FM_DR: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -879,6 +930,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SL: {
|
case DIV_CMD_FM_SL: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -895,6 +947,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RR: {
|
case DIV_CMD_FM_RR: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -911,6 +964,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_D2R: {
|
case DIV_CMD_FM_D2R: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -927,6 +981,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_DT: {
|
case DIV_CMD_FM_DT: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -943,6 +998,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SSG: {
|
case DIV_CMD_FM_SSG: {
|
||||||
|
if (c.chan>=6) break;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||||
|
@ -959,6 +1015,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_HARD_RESET:
|
case DIV_CMD_FM_HARD_RESET:
|
||||||
|
if (c.chan>=6) break;
|
||||||
chan[c.chan].hardReset=c.value;
|
chan[c.chan].hardReset=c.value;
|
||||||
break;
|
break;
|
||||||
case DIV_ALWAYS_SET_VOLUME:
|
case DIV_ALWAYS_SET_VOLUME:
|
||||||
|
@ -1007,7 +1064,7 @@ void DivPlatformGenesis::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dacMode) {
|
if (chan[5].dacMode) {
|
||||||
rWrite(0x2b,0x80);
|
rWrite(0x2b,0x80);
|
||||||
}
|
}
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
|
@ -1057,18 +1114,18 @@ void DivPlatformGenesis::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
lastBusy=60;
|
lastBusy=60;
|
||||||
dacMode=0;
|
|
||||||
dacPeriod=0;
|
|
||||||
dacPos=0;
|
|
||||||
dacRate=0;
|
|
||||||
dacDelay=0;
|
|
||||||
dacReady=true;
|
|
||||||
dacSample=-1;
|
|
||||||
sampleBank=0;
|
|
||||||
lfoValue=8;
|
lfoValue=8;
|
||||||
|
softPCMTimer=0;
|
||||||
extMode=false;
|
extMode=false;
|
||||||
|
|
||||||
|
if (softPCM) {
|
||||||
|
chan[5].dacMode=true;
|
||||||
|
chan[6].dacMode=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal sample direction
|
||||||
|
if (dumpWrites) addWrite(0xffff0003,0);
|
||||||
|
|
||||||
// LFO
|
// LFO
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
|
|
||||||
|
@ -1088,7 +1145,7 @@ bool DivPlatformGenesis::keyOffAffectsPorta(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::notifyInsChange(int ins) {
|
void DivPlatformGenesis::notifyInsChange(int ins) {
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<10; i++) {
|
||||||
if (chan[i].ins==ins) {
|
if (chan[i].ins==ins) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
@ -1114,6 +1171,10 @@ void DivPlatformGenesis::setYMFM(bool use) {
|
||||||
useYMFM=use;
|
useYMFM=use;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformGenesis::setSoftPCM(bool value) {
|
||||||
|
softPCM=value;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::setFlags(unsigned int flags) {
|
void DivPlatformGenesis::setFlags(unsigned int flags) {
|
||||||
switch (flags) {
|
switch (flags) {
|
||||||
case 1: chipClock=COLOR_PAL*12.0/7.0; break;
|
case 1: chipClock=COLOR_PAL*12.0/7.0; break;
|
||||||
|
@ -1152,6 +1213,11 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i
|
||||||
fm_ymfm=NULL;
|
fm_ymfm=NULL;
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
|
|
||||||
|
for (int i=0; i<128; i++) {
|
||||||
|
dacVolTable[127-i]=128*pow(10.0f,(float)(-i)*0.75f/20.0f);
|
||||||
|
}
|
||||||
|
dacVolTable[0]=0;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,24 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
|
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
|
||||||
int vol, outVol;
|
int vol, outVol;
|
||||||
unsigned char pan;
|
unsigned char pan;
|
||||||
|
|
||||||
|
bool dacMode;
|
||||||
|
int dacPeriod;
|
||||||
|
int dacRate;
|
||||||
|
unsigned int dacPos;
|
||||||
|
int dacSample;
|
||||||
|
int dacDelay;
|
||||||
|
bool dacReady;
|
||||||
|
bool dacDirection;
|
||||||
|
bool dacReversed;
|
||||||
|
unsigned char sampleBank;
|
||||||
void macroInit(DivInstrument* which) {
|
void macroInit(DivInstrument* which) {
|
||||||
std.init(which);
|
std.init(which);
|
||||||
pitch2=0;
|
pitch2=0;
|
||||||
}
|
}
|
||||||
|
bool getDacDirection() {
|
||||||
|
return dacReversed^dacDirection;
|
||||||
|
}
|
||||||
Channel():
|
Channel():
|
||||||
freqH(0),
|
freqH(0),
|
||||||
freqL(0),
|
freqL(0),
|
||||||
|
@ -65,7 +79,18 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
hardReset(false),
|
hardReset(false),
|
||||||
vol(0),
|
vol(0),
|
||||||
pan(3) {}
|
outVol(0),
|
||||||
|
pan(3),
|
||||||
|
dacMode(false),
|
||||||
|
dacPeriod(0),
|
||||||
|
dacRate(0),
|
||||||
|
dacPos(0),
|
||||||
|
dacSample(-1),
|
||||||
|
dacDelay(0),
|
||||||
|
dacReady(true),
|
||||||
|
dacDirection(false),
|
||||||
|
dacReversed(false),
|
||||||
|
sampleBank(0) {}
|
||||||
};
|
};
|
||||||
Channel chan[10];
|
Channel chan[10];
|
||||||
DivDispatchOscBuffer* oscBuf[10];
|
DivDispatchOscBuffer* oscBuf[10];
|
||||||
|
@ -86,24 +111,21 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
DivYM2612Interface iface;
|
DivYM2612Interface iface;
|
||||||
unsigned char regPool[512];
|
unsigned char regPool[512];
|
||||||
|
|
||||||
bool dacMode;
|
|
||||||
int dacPeriod;
|
|
||||||
int dacRate;
|
|
||||||
unsigned int dacPos;
|
|
||||||
int dacSample;
|
|
||||||
int dacDelay;
|
|
||||||
bool dacReady;
|
|
||||||
unsigned char sampleBank;
|
|
||||||
unsigned char lfoValue;
|
unsigned char lfoValue;
|
||||||
|
|
||||||
bool extMode, useYMFM;
|
int softPCMTimer;
|
||||||
|
|
||||||
|
bool extMode, softPCM, useYMFM;
|
||||||
bool ladder;
|
bool ladder;
|
||||||
|
|
||||||
short oldWrites[512];
|
short oldWrites[512];
|
||||||
short pendingWrites[512];
|
short pendingWrites[512];
|
||||||
|
|
||||||
|
unsigned char dacVolTable[128];
|
||||||
|
|
||||||
friend void putDispatchChan(void*,int,int);
|
friend void putDispatchChan(void*,int,int);
|
||||||
|
|
||||||
|
inline void processDAC();
|
||||||
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
|
void acquire_ymfm(short* bufL, short* bufR, size_t start, size_t len);
|
||||||
|
|
||||||
|
@ -126,6 +148,7 @@ class DivPlatformGenesis: public DivDispatch {
|
||||||
void setFlags(unsigned int flags);
|
void setFlags(unsigned int flags);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
|
void setSoftPCM(bool value);
|
||||||
int getPortaFloor(int ch);
|
int getPortaFloor(int ch);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
|
|
|
@ -156,16 +156,16 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_SAMPLE_MODE: {
|
case DIV_CMD_SAMPLE_MODE: {
|
||||||
// not ignored actually!
|
// not ignored actually!
|
||||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||||
dacMode=c.value;
|
chan[5].dacMode=c.value;
|
||||||
rWrite(0x2b,c.value<<7);
|
rWrite(0x2b,c.value<<7);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_SAMPLE_BANK:
|
case DIV_CMD_SAMPLE_BANK:
|
||||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||||
sampleBank=c.value;
|
chan[5].sampleBank=c.value;
|
||||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
if (chan[5].sampleBank>(parent->song.sample.size()/12)) {
|
||||||
sampleBank=parent->song.sample.size()/12;
|
chan[5].sampleBank=parent->song.sample.size()/12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -484,7 +484,7 @@ void DivPlatformGenesisExt::forceIns() {
|
||||||
chan[i].freqChanged=true;
|
chan[i].freqChanged=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dacMode) {
|
if (chan[5].dacMode) {
|
||||||
rWrite(0x2b,0x80);
|
rWrite(0x2b,0x80);
|
||||||
}
|
}
|
||||||
immWrite(0x22,lfoValue);
|
immWrite(0x22,lfoValue);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#define WRITE_VOLUME(ch,v) rWrite(0x20+(ch<<3),(v))
|
#define WRITE_VOLUME(ch,v) rWrite(0x20+(ch<<3),(v))
|
||||||
#define WRITE_FEEDBACK(ch,v) rWrite(0x21+(ch<<3),(v))
|
#define WRITE_FEEDBACK(ch,v) rWrite(0x21+(ch<<3),(v))
|
||||||
|
#define WRITE_OUTPUT(ch,v) rWrite(0x22+(ch<<3),(v))
|
||||||
#define WRITE_LFSR(ch,v) rWrite(0x23+(ch<<3),(v))
|
#define WRITE_LFSR(ch,v) rWrite(0x23+(ch<<3),(v))
|
||||||
#define WRITE_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
#define WRITE_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
||||||
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
||||||
|
@ -151,18 +152,23 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
||||||
DivSample* s=parent->getSample(chan[i].sample);
|
DivSample* s=parent->getSample(chan[i].sample);
|
||||||
if (s!=NULL) {
|
if (s!=NULL) {
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
WRITE_VOLUME(i,0);
|
WRITE_OUTPUT(i,0);
|
||||||
chan[i].samplePos++;
|
chan[i].samplePos++;
|
||||||
} else {
|
} else {
|
||||||
WRITE_VOLUME(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
WRITE_OUTPUT(i,(s->data8[chan[i].samplePos++]*chan[i].outVol)>>7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[i].samplePos>=(int)s->samples) {
|
if (chan[i].samplePos>=(int)s->samples) {
|
||||||
|
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||||
|
chan[i].samplePos=s->loopStart;
|
||||||
|
} else {
|
||||||
chan[i].sample=-1;
|
chan[i].sample=-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mikey->sampleAudio( bufL + h, bufR + h, 1, oscBuf );
|
mikey->sampleAudio( bufL + h, bufR + h, 1, oscBuf );
|
||||||
}
|
}
|
||||||
|
@ -176,8 +182,8 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6;
|
chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6;
|
||||||
} else {
|
} else {
|
||||||
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
chan[i].outVol=((chan[i].vol&127)*MIN(127,chan[i].std.vol.val))>>7;
|
||||||
WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127)));
|
|
||||||
}
|
}
|
||||||
|
WRITE_VOLUME(i,(isMuted[i]?0:(chan[i].outVol&127)));
|
||||||
}
|
}
|
||||||
if (chan[i].std.arp.had) {
|
if (chan[i].std.arp.had) {
|
||||||
if (!chan[i].inPorta) {
|
if (!chan[i].inPorta) {
|
||||||
|
@ -244,11 +250,6 @@ void DivPlatformLynx::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
chan[i].sampleFreq=off*parent->calcFreq(chan[i].sampleBaseFreq,chan[i].pitch,false,2,chan[i].pitch2,1,1);
|
||||||
WRITE_FEEDBACK(i,0);
|
|
||||||
WRITE_LFSR(i,0);
|
|
||||||
WRITE_OTHER(i,0);
|
|
||||||
WRITE_CONTROL(i,0x18);
|
|
||||||
WRITE_BACKUP(i,2);
|
|
||||||
} else {
|
} else {
|
||||||
if (chan[i].lfsr >= 0) {
|
if (chan[i].lfsr >= 0) {
|
||||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||||
|
@ -301,6 +302,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_OFF:
|
case DIV_CMD_NOTE_OFF:
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
WRITE_VOLUME(c.chan,0);
|
WRITE_VOLUME(c.chan,0);
|
||||||
|
WRITE_CONTROL(c.chan,0);
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
if (chan[c.chan].pcm) {
|
if (chan[c.chan].pcm) {
|
||||||
chan[c.chan].pcm=false;
|
chan[c.chan].pcm=false;
|
||||||
|
|
|
@ -23,13 +23,18 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define rWrite(v) if (!skipRegisterWrites) {writes.emplace(0,v); if (dumpWrites) {addWrite(0,v);} }
|
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
|
||||||
|
|
||||||
const char** DivPlatformMSM6295::getRegisterSheet() {
|
const char** DivPlatformMSM6295::getRegisterSheet() {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
|
const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
|
||||||
|
switch (effect) {
|
||||||
|
case 0x20:
|
||||||
|
return "20xx: Set chip output rate (0: clock/132; 1: clock/165)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +47,28 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
||||||
if (delay<=0) {
|
if (delay<=0) {
|
||||||
if (!writes.empty()) {
|
if (!writes.empty()) {
|
||||||
QueuedWrite& w=writes.front();
|
QueuedWrite& w=writes.front();
|
||||||
|
switch (w.addr) {
|
||||||
|
case 0: // command
|
||||||
msm->command_w(w.val);
|
msm->command_w(w.val);
|
||||||
|
break;
|
||||||
|
case 8: // chip clock select (VGM)
|
||||||
|
case 9:
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
break;
|
||||||
|
case 12: // rate select
|
||||||
|
msm->ss_w(!w.val);
|
||||||
|
break;
|
||||||
|
case 14: // enable bankswitch
|
||||||
|
break;
|
||||||
|
case 15: // set bank base
|
||||||
|
break;
|
||||||
|
case 16: // switch bank
|
||||||
|
case 17:
|
||||||
|
case 18:
|
||||||
|
case 19:
|
||||||
|
break;
|
||||||
|
}
|
||||||
writes.pop();
|
writes.pop();
|
||||||
delay=32;
|
delay=32;
|
||||||
}
|
}
|
||||||
|
@ -92,9 +118,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
chan[c.chan].keyOn=true;
|
chan[c.chan].keyOn=true;
|
||||||
rWrite((8<<c.chan)); // turn off
|
rWrite(0,(8<<c.chan)); // turn off
|
||||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -107,9 +133,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||||
rWrite((8<<c.chan)); // turn off
|
rWrite(0,(8<<c.chan)); // turn off
|
||||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -117,14 +143,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
rWrite((8<<c.chan)); // turn off
|
rWrite(0,(8<<c.chan)); // turn off
|
||||||
chan[c.chan].macroInit(NULL);
|
chan[c.chan].macroInit(NULL);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
chan[c.chan].keyOff=true;
|
chan[c.chan].keyOff=true;
|
||||||
chan[c.chan].keyOn=false;
|
chan[c.chan].keyOn=false;
|
||||||
chan[c.chan].active=false;
|
chan[c.chan].active=false;
|
||||||
rWrite((8<<c.chan)); // turn off
|
rWrite(0,(8<<c.chan)); // turn off
|
||||||
chan[c.chan].std.release();
|
chan[c.chan].std.release();
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_ENV_RELEASE:
|
case DIV_CMD_ENV_RELEASE:
|
||||||
|
@ -153,6 +179,10 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
||||||
case DIV_CMD_NOTE_PORTA: {
|
case DIV_CMD_NOTE_PORTA: {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
case DIV_CMD_SAMPLE_FREQ:
|
||||||
|
rateSel=c.value;
|
||||||
|
rWrite(12,!rateSel);
|
||||||
|
break;
|
||||||
case DIV_CMD_SAMPLE_BANK:
|
case DIV_CMD_SAMPLE_BANK:
|
||||||
sampleBank=c.value;
|
sampleBank=c.value;
|
||||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||||
|
@ -190,6 +220,7 @@ void DivPlatformMSM6295::forceIns() {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
chan[i].insChanged=true;
|
chan[i].insChanged=true;
|
||||||
}
|
}
|
||||||
|
rWrite(12,!rateSel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DivPlatformMSM6295::getChanState(int ch) {
|
void* DivPlatformMSM6295::getChanState(int ch) {
|
||||||
|
@ -219,6 +250,7 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
|
||||||
void DivPlatformMSM6295::reset() {
|
void DivPlatformMSM6295::reset() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
msm->reset();
|
msm->reset();
|
||||||
|
msm->ss_w(false);
|
||||||
if (dumpWrites) {
|
if (dumpWrites) {
|
||||||
addWrite(0xffffffff,0);
|
addWrite(0xffffffff,0);
|
||||||
}
|
}
|
||||||
|
@ -232,6 +264,7 @@ void DivPlatformMSM6295::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleBank=0;
|
sampleBank=0;
|
||||||
|
rateSel=false;
|
||||||
|
|
||||||
delay=0;
|
delay=0;
|
||||||
}
|
}
|
||||||
|
@ -240,6 +273,10 @@ bool DivPlatformMSM6295::keyOffAffectsArp(int ch) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float DivPlatformMSM6295::getPostAmp() {
|
||||||
|
return 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6295::notifyInsChange(int ins) {
|
void DivPlatformMSM6295::notifyInsChange(int ins) {
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
if (chan[i].ins==ins) {
|
if (chan[i].ins==ins) {
|
||||||
|
@ -302,12 +339,21 @@ void DivPlatformMSM6295::renderSamples() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformMSM6295::setFlags(unsigned int flags) {
|
void DivPlatformMSM6295::setFlags(unsigned int flags) {
|
||||||
if (flags&1) {
|
switch (flags) {
|
||||||
chipClock=8448000;
|
case 0:
|
||||||
} else {
|
chipClock=4000000/4;
|
||||||
chipClock=8000000;
|
break;
|
||||||
|
case 1:
|
||||||
|
chipClock=4224000/4;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
chipClock=4000000;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
chipClock=4224000;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
rate=chipClock/((flags&2)?6:24);
|
rate=chipClock/3;
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
isMuted[i]=false;
|
isMuted[i]=false;
|
||||||
oscBuf[i]->rate=rate/22;
|
oscBuf[i]->rate=rate/22;
|
||||||
|
|
|
@ -101,6 +101,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
||||||
int delay, updateOsc;
|
int delay, updateOsc;
|
||||||
|
|
||||||
bool extMode;
|
bool extMode;
|
||||||
|
bool rateSel;
|
||||||
|
|
||||||
short oldWrites[512];
|
short oldWrites[512];
|
||||||
short pendingWrites[512];
|
short pendingWrites[512];
|
||||||
|
@ -119,6 +120,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
||||||
void tick(bool sysTick=true);
|
void tick(bool sysTick=true);
|
||||||
void muteChannel(int ch, bool mute);
|
void muteChannel(int ch, bool mute);
|
||||||
bool keyOffAffectsArp(int ch);
|
bool keyOffAffectsArp(int ch);
|
||||||
|
float getPostAmp();
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
|
|
|
@ -735,6 +735,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
|
||||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||||
immWrite(8,0);
|
immWrite(8,0);
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
immWrite(9,(s->offB>>2)&0xff);
|
immWrite(9,(s->offB>>2)&0xff);
|
||||||
immWrite(10,(s->offB>>10)&0xff);
|
immWrite(10,(s->offB>>10)&0xff);
|
||||||
int end=s->offB+s->lengthB-1;
|
int end=s->offB+s->lengthB-1;
|
||||||
|
@ -770,6 +771,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||||
immWrite(8,0);
|
immWrite(8,0);
|
||||||
|
immWrite(7,0x01); // reset
|
||||||
immWrite(9,(s->offB>>2)&0xff);
|
immWrite(9,(s->offB>>2)&0xff);
|
||||||
immWrite(10,(s->offB>>10)&0xff);
|
immWrite(10,(s->offB>>10)&0xff);
|
||||||
int end=s->offB+s->lengthB-1;
|
int end=s->offB+s->lengthB-1;
|
||||||
|
|
|
@ -42,6 +42,7 @@ const char* DivPlatformSMS::getEffectName(unsigned char effect) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
|
int o=0;
|
||||||
for (size_t h=start; h<start+len; h++) {
|
for (size_t h=start; h<start+len; h++) {
|
||||||
if (!writes.empty()) {
|
if (!writes.empty()) {
|
||||||
unsigned char w=writes.front();
|
unsigned char w=writes.front();
|
||||||
|
@ -64,7 +65,10 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
||||||
YMPSG_Clock(&sn_nuked);
|
YMPSG_Clock(&sn_nuked);
|
||||||
YMPSG_Clock(&sn_nuked);
|
YMPSG_Clock(&sn_nuked);
|
||||||
YMPSG_Clock(&sn_nuked);
|
YMPSG_Clock(&sn_nuked);
|
||||||
bufL[h]=YMPSG_GetOutput(&sn_nuked)*8192.0;
|
o=YMPSG_GetOutput(&sn_nuked);
|
||||||
|
if (o<-32768) o=-32768;
|
||||||
|
if (o>32767) o=32767;
|
||||||
|
bufL[h]=o;
|
||||||
/*
|
/*
|
||||||
for (int i=0; i<4; i++) {
|
for (int i=0; i<4; i++) {
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
|
|
|
@ -63,6 +63,7 @@ const char* cmdName[]={
|
||||||
"SAMPLE_FREQ",
|
"SAMPLE_FREQ",
|
||||||
"SAMPLE_BANK",
|
"SAMPLE_BANK",
|
||||||
"SAMPLE_POS",
|
"SAMPLE_POS",
|
||||||
|
"SAMPLE_DIR",
|
||||||
"SAMPLE_TRANSWAVE_SLICE_MODE", // (enabled)
|
"SAMPLE_TRANSWAVE_SLICE_MODE", // (enabled)
|
||||||
"SAMPLE_TRANSWAVE_SLICE_POS", // (slice)
|
"SAMPLE_TRANSWAVE_SLICE_POS", // (slice)
|
||||||
|
|
||||||
|
@ -570,6 +571,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
||||||
clockDrift=0;
|
clockDrift=0;
|
||||||
subticks=0;
|
subticks=0;
|
||||||
break;
|
break;
|
||||||
|
case 0xdf: // set sample direction
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal));
|
||||||
|
break;
|
||||||
case 0xe0: // arp speed
|
case 0xe0: // arp speed
|
||||||
if (effectVal>0) {
|
if (effectVal>0) {
|
||||||
curSubSong->arpLen=effectVal;
|
curSubSong->arpLen=effectVal;
|
||||||
|
|
|
@ -111,6 +111,9 @@ enum DivSystem {
|
||||||
DIV_SYSTEM_NAMCO,
|
DIV_SYSTEM_NAMCO,
|
||||||
DIV_SYSTEM_NAMCO_15XX,
|
DIV_SYSTEM_NAMCO_15XX,
|
||||||
DIV_SYSTEM_NAMCO_CUS30,
|
DIV_SYSTEM_NAMCO_CUS30,
|
||||||
|
DIV_SYSTEM_YM2612_FRAC,
|
||||||
|
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||||
|
DIV_SYSTEM_RESERVED_8,
|
||||||
DIV_SYSTEM_DUMMY,
|
DIV_SYSTEM_DUMMY,
|
||||||
DIV_SYSTEM_MAX // boundary for max system number
|
DIV_SYSTEM_MAX // boundary for max system number
|
||||||
};
|
};
|
||||||
|
@ -395,6 +398,10 @@ struct DivSong {
|
||||||
bool snDutyReset;
|
bool snDutyReset;
|
||||||
bool pitchMacroIsLinear;
|
bool pitchMacroIsLinear;
|
||||||
bool oldOctaveBoundary;
|
bool oldOctaveBoundary;
|
||||||
|
bool noOPN2Vol;
|
||||||
|
bool newVolumeScaling;
|
||||||
|
bool volMacroLinger;
|
||||||
|
bool brokenOutVol;
|
||||||
|
|
||||||
std::vector<DivInstrument*> ins;
|
std::vector<DivInstrument*> ins;
|
||||||
std::vector<DivWavetable*> wave;
|
std::vector<DivWavetable*> wave;
|
||||||
|
@ -488,7 +495,11 @@ struct DivSong {
|
||||||
fbPortaPause(false),
|
fbPortaPause(false),
|
||||||
snDutyReset(false),
|
snDutyReset(false),
|
||||||
pitchMacroIsLinear(true),
|
pitchMacroIsLinear(true),
|
||||||
oldOctaveBoundary(false) {
|
oldOctaveBoundary(false),
|
||||||
|
noOPN2Vol(false),
|
||||||
|
newVolumeScaling(true),
|
||||||
|
volMacroLinger(true),
|
||||||
|
brokenOutVol(false) {
|
||||||
for (int i=0; i<32; i++) {
|
for (int i=0; i<32; i++) {
|
||||||
system[i]=DIV_SYSTEM_NULL;
|
system[i]=DIV_SYSTEM_NULL;
|
||||||
systemVol[i]=64;
|
systemVol[i]=64;
|
||||||
|
|
|
@ -2027,12 +2027,23 @@ void DivEngine::registerSystems() {
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef(
|
||||||
"OKI MSM6295", NULL, 0xaa, 0, 4, false, true, 0, false,
|
"OKI MSM6295", NULL, 0xaa, 0, 4, false, true, 0x161, false,
|
||||||
"an ADPCM sound chip manufactured by OKI and used in many arcade boards.",
|
"an ADPCM sound chip manufactured by OKI and used in many arcade boards.",
|
||||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||||
{"CH1", "CH2", "CH3", "CH4"},
|
{"CH1", "CH2", "CH3", "CH4"},
|
||||||
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||||
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}
|
{DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||||
|
{},
|
||||||
|
[this](int ch, unsigned char effect, unsigned char effectVal) -> bool {
|
||||||
|
switch (effect) {
|
||||||
|
case 0x20: // select rate
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_MSM6258]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_MSM6258]=new DivSysDef(
|
||||||
|
@ -2100,6 +2111,40 @@ void DivEngine::registerSystems() {
|
||||||
namcoEffectHandler
|
namcoEffectHandler
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// replace with an 8-channel chip in a future
|
||||||
|
sysDefs[DIV_SYSTEM_RESERVED_8]=new DivSysDef(
|
||||||
|
"Reserved", NULL, 0xbc, 0, 8, false, true, 0, false,
|
||||||
|
"this was YM2612_FRAC, but due to changes this ID is reserved.",
|
||||||
|
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
|
||||||
|
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
|
||||||
|
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
|
||||||
|
{DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}
|
||||||
|
);
|
||||||
|
|
||||||
|
sysDefs[DIV_SYSTEM_YM2612_FRAC]=new DivSysDef(
|
||||||
|
"Yamaha YM2612 (OPN2) with DualPCM", NULL, 0xbe, 0, 7, true, false, 0, false,
|
||||||
|
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.",
|
||||||
|
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6/PCM 1", "PCM 2"},
|
||||||
|
{"F1", "F2", "F3", "F4", "F5", "P1", "P2"},
|
||||||
|
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM},
|
||||||
|
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AMIGA},
|
||||||
|
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL},
|
||||||
|
opn2EffectHandler,
|
||||||
|
fmPostEffectHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
sysDefs[DIV_SYSTEM_YM2612_FRAC_EXT]=new DivSysDef(
|
||||||
|
"Yamaha YM2612 (OPN2) Extended Channel 3 with DualPCM and CSM", NULL, 0xbd, 0, 11, true, false, 0, false,
|
||||||
|
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis system uses software mixing to provide two sample channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
|
||||||
|
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6/PCM 1", "PCM 2", "CSM Timer"},
|
||||||
|
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "P1", "P2", "CSM"},
|
||||||
|
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE},
|
||||||
|
{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_AMIGA, DIV_INS_FM},
|
||||||
|
{DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL},
|
||||||
|
opn2EffectHandler,
|
||||||
|
fmPostEffectHandler
|
||||||
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
|
||||||
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
|
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
|
||||||
"this is a system designed for testing purposes.",
|
"this is a system designed for testing purposes.",
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||||
|
|
||||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond) {
|
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond) {
|
||||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||||
unsigned char baseAddr2=isSecond?0x80:0;
|
unsigned char baseAddr2=isSecond?0x80:0;
|
||||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||||
|
@ -420,22 +420,22 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
case DIV_SYSTEM_Y8950_DRUMS:
|
case DIV_SYSTEM_Y8950_DRUMS:
|
||||||
// disable envelope
|
// disable envelope
|
||||||
for (int i=0; i<6; i++) {
|
for (int i=0; i<6; i++) {
|
||||||
w->writeC(0x0b|baseAddr1);
|
w->writeC(0x0c|baseAddr1);
|
||||||
w->writeC(0x80+i);
|
w->writeC(0x80+i);
|
||||||
w->writeC(0x0f);
|
w->writeC(0x0f);
|
||||||
w->writeC(0x0b|baseAddr1);
|
w->writeC(0x0c|baseAddr1);
|
||||||
w->writeC(0x88+i);
|
w->writeC(0x88+i);
|
||||||
w->writeC(0x0f);
|
w->writeC(0x0f);
|
||||||
w->writeC(0x0b|baseAddr1);
|
w->writeC(0x0c|baseAddr1);
|
||||||
w->writeC(0x90+i);
|
w->writeC(0x90+i);
|
||||||
w->writeC(0x0f);
|
w->writeC(0x0f);
|
||||||
}
|
}
|
||||||
// key off + freq reset
|
// key off + freq reset
|
||||||
for (int i=0; i<9; i++) {
|
for (int i=0; i<9; i++) {
|
||||||
w->writeC(0x0b|baseAddr1);
|
w->writeC(0x0c|baseAddr1);
|
||||||
w->writeC(0xa0+i);
|
w->writeC(0xa0+i);
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
w->writeC(0x0b|baseAddr1);
|
w->writeC(0x0c|baseAddr1);
|
||||||
w->writeC(0xb0+i);
|
w->writeC(0xb0+i);
|
||||||
w->writeC(0);
|
w->writeC(0);
|
||||||
}
|
}
|
||||||
|
@ -522,6 +522,15 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(rf5c68Addr);
|
w->writeC(rf5c68Addr);
|
||||||
w->writeC(8);
|
w->writeC(8);
|
||||||
w->writeC(0xff);
|
w->writeC(0xff);
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_MSM6295:
|
||||||
|
w->writeC(0xb8); // disable all channels
|
||||||
|
w->writeC(baseAddr2|0);
|
||||||
|
w->writeC(0x78);
|
||||||
|
w->writeC(0xb8); // select rate
|
||||||
|
w->writeC(baseAddr2|12);
|
||||||
|
w->writeC(1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -536,8 +545,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(0x95);
|
w->writeC(0x95);
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
w->writeS(write.val); // sample number
|
w->writeS(write.val); // sample number
|
||||||
w->writeC((sample->loopStart==0)); // flags
|
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||||
if (sample->loopStart>0) {
|
if (sample->loopStart>0 && !sampleDir[streamID]) {
|
||||||
loopTimer[streamID]=(double)sample->loopEnd;
|
loopTimer[streamID]=(double)sample->loopEnd;
|
||||||
loopSample[streamID]=write.val;
|
loopSample[streamID]=write.val;
|
||||||
}
|
}
|
||||||
|
@ -554,6 +563,9 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
loopSample[streamID]=-1;
|
loopSample[streamID]=-1;
|
||||||
break;
|
break;
|
||||||
|
case 3: // set sample direction
|
||||||
|
sampleDir[streamID]=write.val;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -818,6 +830,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
w->writeC(write.addr&0xff);
|
w->writeC(write.addr&0xff);
|
||||||
w->writeC(write.val);
|
w->writeC(write.val);
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_MSM6295:
|
||||||
|
w->writeC(0xb8);
|
||||||
|
w->writeC(baseAddr2|(write.addr&0x7f));
|
||||||
|
w->writeC(write.val);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
logW("write not handled!");
|
logW("write not handled!");
|
||||||
break;
|
break;
|
||||||
|
@ -923,11 +940,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
double loopTimer[DIV_MAX_CHANS];
|
double loopTimer[DIV_MAX_CHANS];
|
||||||
double loopFreq[DIV_MAX_CHANS];
|
double loopFreq[DIV_MAX_CHANS];
|
||||||
int loopSample[DIV_MAX_CHANS];
|
int loopSample[DIV_MAX_CHANS];
|
||||||
|
bool sampleDir[DIV_MAX_CHANS];
|
||||||
|
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
loopTimer[i]=0;
|
loopTimer[i]=0;
|
||||||
loopFreq[i]=0;
|
loopFreq[i]=0;
|
||||||
loopSample[i]=-1;
|
loopSample[i]=-1;
|
||||||
|
sampleDir[i]=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeDACSamples=false;
|
bool writeDACSamples=false;
|
||||||
|
@ -942,6 +961,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
DivDispatch* writeES5506[2]={NULL,NULL};
|
DivDispatch* writeES5506[2]={NULL,NULL};
|
||||||
DivDispatch* writeZ280[2]={NULL,NULL};
|
DivDispatch* writeZ280[2]={NULL,NULL};
|
||||||
DivDispatch* writeRF5C68[2]={NULL,NULL};
|
DivDispatch* writeRF5C68[2]={NULL,NULL};
|
||||||
|
DivDispatch* writeMSM6295[2]={NULL,NULL};
|
||||||
|
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
willExport[i]=false;
|
willExport[i]=false;
|
||||||
|
@ -1348,6 +1368,19 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
writeRF5C68[0]=disCont[i].dispatch;
|
writeRF5C68[0]=disCont[i].dispatch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_MSM6295:
|
||||||
|
if (!hasOKIM6295) {
|
||||||
|
hasOKIM6295=disCont[i].dispatch->chipClock;
|
||||||
|
willExport[i]=true;
|
||||||
|
writeMSM6295[0]=disCont[i].dispatch;
|
||||||
|
} else if (!(hasOKIM6295&0x40000000)) {
|
||||||
|
isSecond[i]=true;
|
||||||
|
willExport[i]=true;
|
||||||
|
writeMSM6295[1]=disCont[i].dispatch;
|
||||||
|
hasOKIM6295|=0x40000000;
|
||||||
|
howManyChips++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1694,6 +1727,15 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
w->writeI(0);
|
w->writeI(0);
|
||||||
w->write(writeRF5C68[i]->getSampleMem(),writeRF5C68[i]->getSampleMemUsage());
|
w->write(writeRF5C68[i]->getSampleMem(),writeRF5C68[i]->getSampleMemUsage());
|
||||||
}
|
}
|
||||||
|
if (writeMSM6295[i]!=NULL && writeMSM6295[i]->getSampleMemUsage()>0) {
|
||||||
|
w->writeC(0x67);
|
||||||
|
w->writeC(0x66);
|
||||||
|
w->writeC(0x8b);
|
||||||
|
w->writeI((writeMSM6295[i]->getSampleMemUsage()+8)|(i*0x80000000));
|
||||||
|
w->writeI(writeMSM6295[i]->getSampleMemCapacity());
|
||||||
|
w->writeI(0);
|
||||||
|
w->write(writeMSM6295[i]->getSampleMem(),writeMSM6295[i]->getSampleMemUsage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -1829,7 +1871,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||||
for (DivRegWrite& j: writes) {
|
for (DivRegWrite& j: writes) {
|
||||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,isSecond[i]);
|
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i]);
|
||||||
writeCount++;
|
writeCount++;
|
||||||
}
|
}
|
||||||
writes.clear();
|
writes.clear();
|
||||||
|
|
|
@ -186,7 +186,7 @@ bool DivWaveSynth::tick(bool skipSubDiv) {
|
||||||
break;
|
break;
|
||||||
case DIV_WS_PHASE_MOD:
|
case DIV_WS_PHASE_MOD:
|
||||||
for (int i=0; i<=state.speed; i++) {
|
for (int i=0; i<=state.speed; i++) {
|
||||||
int mod=(wave2[pos]*(state.param2-stage)*width)/512;
|
int mod=(wave2[pos]*(state.param2-stage)*width)/(64*(height+1));
|
||||||
output[pos]=wave1[(pos+mod)%width];
|
output[pos]=wave1[(pos+mod)%width];
|
||||||
if (++pos>=width) {
|
if (++pos>=width) {
|
||||||
pos=0;
|
pos=0;
|
||||||
|
|
|
@ -31,26 +31,42 @@ void FurnaceGUI::drawChannels() {
|
||||||
if (!channelsOpen) return;
|
if (!channelsOpen) return;
|
||||||
if (ImGui::Begin("Channels",&channelsOpen,globalWinFlags)) {
|
if (ImGui::Begin("Channels",&channelsOpen,globalWinFlags)) {
|
||||||
if (ImGui::BeginTable("ChannelList",3)) {
|
if (ImGui::BeginTable("ChannelList",3)) {
|
||||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale);
|
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale);
|
||||||
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Visible");
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("Name");
|
||||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(i);
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]);
|
ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::BeginDisabled(i==0);
|
if (ImGui::Button(ICON_FA_ARROWS)) {
|
||||||
if (ImGui::Button(ICON_FA_CHEVRON_UP)) {
|
|
||||||
e->swapChannelsP(i,i-1);
|
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
if (ImGui::BeginDragDropSource()) {
|
||||||
ImGui::SameLine();
|
chanToMove=i;
|
||||||
ImGui::BeginDisabled(i==(e->getTotalChannelCount()-1));
|
ImGui::SetDragDropPayload("FUR_CHAN",NULL,0,ImGuiCond_Once);
|
||||||
if (ImGui::Button(ICON_FA_CHEVRON_DOWN)) {
|
ImGui::Button(ICON_FA_ARROWS "##ChanDrag");
|
||||||
e->swapChannelsP(i,i+1);
|
ImGui::EndDragDropSource();
|
||||||
|
} else if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("%s #%d\n(drag to swap channels)",e->getSystemName(e->sysOfChan[i]),e->dispatchChanOfChan[i]);
|
||||||
|
}
|
||||||
|
if (ImGui::BeginDragDropTarget()) {
|
||||||
|
const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN");
|
||||||
|
if (dragItem!=NULL) {
|
||||||
|
if (dragItem->IsDataType("FUR_CHAN")) {
|
||||||
|
if (chanToMove!=i && chanToMove>=0) {
|
||||||
|
e->swapChannelsP(chanToMove,i);
|
||||||
|
}
|
||||||
|
chanToMove=-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndDragDropTarget();
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]);
|
ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]);
|
||||||
|
|
|
@ -213,6 +213,10 @@ void FurnaceGUI::drawCompatFlags() {
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("behavior changed in 0.6");
|
ImGui::SetTooltip("behavior changed in 0.6");
|
||||||
}
|
}
|
||||||
|
ImGui::Checkbox("No OPN2 DAC volume control",&e->song.noOPN2Vol);
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip("behavior changed in 0.6");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
|
@ -394,7 +394,7 @@ void FurnaceGUI::drawSampleList() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FurnaceGUI::actualWaveList() {
|
void FurnaceGUI::actualWaveList() {
|
||||||
float wavePreview[256];
|
float wavePreview[257];
|
||||||
for (int i=0; i<(int)e->song.wave.size(); i++) {
|
for (int i=0; i<(int)e->song.wave.size(); i++) {
|
||||||
DivWavetable* wave=e->song.wave[i];
|
DivWavetable* wave=e->song.wave[i];
|
||||||
for (int i=0; i<wave->len; i++) {
|
for (int i=0; i<wave->len; i++) {
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "IconsFontAwesome4.h"
|
#include "IconsFontAwesome4.h"
|
||||||
|
#include <SDL_timer.h>
|
||||||
#include <fmt/printf.h>
|
#include <fmt/printf.h>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
@ -373,6 +374,13 @@ void FurnaceGUI::drawDebug() {
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
if (ImGui::TreeNode("Performance")) {
|
||||||
|
double perfFreq=SDL_GetPerformanceFrequency()/1000000.0;
|
||||||
|
ImGui::Text("render: %.0fµs",(double)renderTimeDelta/perfFreq);
|
||||||
|
ImGui::Text("layout: %.0fµs",(double)layoutTimeDelta/perfFreq);
|
||||||
|
ImGui::Text("event: %.0fµs",(double)eventTimeDelta/perfFreq);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
if (ImGui::TreeNode("Settings")) {
|
if (ImGui::TreeNode("Settings")) {
|
||||||
if (ImGui::Button("Sync")) syncSettings();
|
if (ImGui::Button("Sync")) syncSettings();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
|
@ -1233,6 +1233,22 @@ void FurnaceGUI::doAction(int what) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GUI_ACTION_SAMPLE_SET_LOOP: {
|
||||||
|
if (curSample<0 || curSample>=(int)e->song.sample.size()) break;
|
||||||
|
DivSample* sample=e->song.sample[curSample];
|
||||||
|
sample->prepareUndo(true);
|
||||||
|
e->lockEngine([this,sample]() {
|
||||||
|
SAMPLE_OP_BEGIN;
|
||||||
|
|
||||||
|
sample->trim(0,end);
|
||||||
|
sample->loopStart=start;
|
||||||
|
updateSampleTex=true;
|
||||||
|
|
||||||
|
e->renderSamples();
|
||||||
|
});
|
||||||
|
MARK_MODIFIED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GUI_ACTION_ORDERS_UP:
|
case GUI_ACTION_ORDERS_UP:
|
||||||
if (curOrder>0) {
|
if (curOrder>0) {
|
||||||
|
|
|
@ -2368,6 +2368,10 @@ void FurnaceGUI::processPoint(SDL_Event& ev) {
|
||||||
point->x=ev.tfinger.x*scrW*dpiScale;
|
point->x=ev.tfinger.x*scrW*dpiScale;
|
||||||
point->y=ev.tfinger.y*scrH*dpiScale;
|
point->y=ev.tfinger.y*scrH*dpiScale;
|
||||||
point->z=ev.tfinger.pressure;
|
point->z=ev.tfinger.pressure;
|
||||||
|
|
||||||
|
if (point->id==0) {
|
||||||
|
ImGui::GetIO().AddMousePosEvent(point->x,point->y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2383,6 +2387,11 @@ void FurnaceGUI::processPoint(SDL_Event& ev) {
|
||||||
TouchPoint newPoint(ev.tfinger.fingerId,ev.tfinger.x*scrW*dpiScale,ev.tfinger.y*scrH*dpiScale,ev.tfinger.pressure);
|
TouchPoint newPoint(ev.tfinger.fingerId,ev.tfinger.x*scrW*dpiScale,ev.tfinger.y*scrH*dpiScale,ev.tfinger.pressure);
|
||||||
activePoints.push_back(newPoint);
|
activePoints.push_back(newPoint);
|
||||||
pressedPoints.push_back(newPoint);
|
pressedPoints.push_back(newPoint);
|
||||||
|
|
||||||
|
if (newPoint.id==0) {
|
||||||
|
ImGui::GetIO().AddMousePosEvent(newPoint.x,newPoint.y);
|
||||||
|
ImGui::GetIO().AddMouseButtonEvent(ImGuiMouseButton_Left,true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_FINGERUP: {
|
case SDL_FINGERUP: {
|
||||||
|
@ -2391,6 +2400,11 @@ void FurnaceGUI::processPoint(SDL_Event& ev) {
|
||||||
if (point.id==ev.tfinger.fingerId) {
|
if (point.id==ev.tfinger.fingerId) {
|
||||||
releasedPoints.push_back(point);
|
releasedPoints.push_back(point);
|
||||||
activePoints.erase(activePoints.begin()+i);
|
activePoints.erase(activePoints.begin()+i);
|
||||||
|
|
||||||
|
if (point.id==0) {
|
||||||
|
ImGui::GetIO().AddMouseButtonEvent(ImGuiMouseButton_Left,false);
|
||||||
|
ImGui::GetIO().AddMousePosEvent(-FLT_MAX,-FLT_MAX);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2411,6 +2425,7 @@ bool FurnaceGUI::loop() {
|
||||||
drawHalt=0;
|
drawHalt=0;
|
||||||
if (settings.powerSave) SDL_WaitEventTimeout(NULL,500);
|
if (settings.powerSave) SDL_WaitEventTimeout(NULL,500);
|
||||||
}
|
}
|
||||||
|
eventTimeBegin=SDL_GetPerformanceCounter();
|
||||||
while (SDL_PollEvent(&ev)) {
|
while (SDL_PollEvent(&ev)) {
|
||||||
WAKE_UP;
|
WAKE_UP;
|
||||||
ImGui_ImplSDL2_ProcessEvent(&ev);
|
ImGui_ImplSDL2_ProcessEvent(&ev);
|
||||||
|
@ -2529,7 +2544,23 @@ bool FurnaceGUI::loop() {
|
||||||
break;
|
break;
|
||||||
case SDL_DROPFILE:
|
case SDL_DROPFILE:
|
||||||
if (ev.drop.file!=NULL) {
|
if (ev.drop.file!=NULL) {
|
||||||
if (modified) {
|
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file);
|
||||||
|
if (!instruments.empty()) {
|
||||||
|
if (!e->getWarnings().empty()) {
|
||||||
|
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||||
|
}
|
||||||
|
for (DivInstrument* i: instruments) {
|
||||||
|
e->addInstrumentPtr(i);
|
||||||
|
}
|
||||||
|
nextWindow=GUI_WINDOW_INS_LIST;
|
||||||
|
MARK_MODIFIED;
|
||||||
|
} else if (e->addWaveFromFile(ev.drop.file,false)) {
|
||||||
|
nextWindow=GUI_WINDOW_WAVE_LIST;
|
||||||
|
MARK_MODIFIED;
|
||||||
|
} else if (e->addSampleFromFile(ev.drop.file)!=-1) {
|
||||||
|
nextWindow=GUI_WINDOW_SAMPLE_LIST;
|
||||||
|
MARK_MODIFIED;
|
||||||
|
} else if (modified) {
|
||||||
nextFile=ev.drop.file;
|
nextFile=ev.drop.file;
|
||||||
showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP);
|
showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2721,6 +2752,10 @@ bool FurnaceGUI::loop() {
|
||||||
midiLock.unlock();
|
midiLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eventTimeEnd=SDL_GetPerformanceCounter();
|
||||||
|
|
||||||
|
layoutTimeBegin=SDL_GetPerformanceCounter();
|
||||||
|
|
||||||
ImGui_ImplSDLRenderer_NewFrame();
|
ImGui_ImplSDLRenderer_NewFrame();
|
||||||
ImGui_ImplSDL2_NewFrame(sdlWin);
|
ImGui_ImplSDL2_NewFrame(sdlWin);
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
@ -3740,6 +3775,8 @@ bool FurnaceGUI::loop() {
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layoutTimeEnd=SDL_GetPerformanceCounter();
|
||||||
|
|
||||||
// backup trigger
|
// backup trigger
|
||||||
if (modified) {
|
if (modified) {
|
||||||
if (backupTimer>0) {
|
if (backupTimer>0) {
|
||||||
|
@ -3778,10 +3815,16 @@ bool FurnaceGUI::loop() {
|
||||||
uiColors[GUI_COLOR_BACKGROUND].z*255,
|
uiColors[GUI_COLOR_BACKGROUND].z*255,
|
||||||
uiColors[GUI_COLOR_BACKGROUND].w*255);
|
uiColors[GUI_COLOR_BACKGROUND].w*255);
|
||||||
SDL_RenderClear(sdlRend);
|
SDL_RenderClear(sdlRend);
|
||||||
|
renderTimeBegin=SDL_GetPerformanceCounter();
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
renderTimeEnd=SDL_GetPerformanceCounter();
|
||||||
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
||||||
SDL_RenderPresent(sdlRend);
|
SDL_RenderPresent(sdlRend);
|
||||||
|
|
||||||
|
layoutTimeDelta=layoutTimeEnd-layoutTimeBegin;
|
||||||
|
renderTimeDelta=renderTimeEnd-renderTimeBegin;
|
||||||
|
eventTimeDelta=eventTimeEnd-eventTimeBegin;
|
||||||
|
|
||||||
if (--soloTimeout<0) soloTimeout=0;
|
if (--soloTimeout<0) soloTimeout=0;
|
||||||
|
|
||||||
wheelX=0;
|
wheelX=0;
|
||||||
|
@ -3867,6 +3910,16 @@ bool FurnaceGUI::init() {
|
||||||
if (orderEditMode<0) orderEditMode=0;
|
if (orderEditMode<0) orderEditMode=0;
|
||||||
if (orderEditMode>3) orderEditMode=3;
|
if (orderEditMode>3) orderEditMode=3;
|
||||||
|
|
||||||
|
pianoOctaves=e->getConfInt("pianoOctaves",pianoOctaves);
|
||||||
|
pianoOctavesEdit=e->getConfInt("pianoOctavesEdit",pianoOctavesEdit);
|
||||||
|
pianoOptions=e->getConfBool("pianoOptions",pianoOptions);
|
||||||
|
pianoSharePosition=e->getConfBool("pianoSharePosition",pianoSharePosition);
|
||||||
|
pianoOptionsSet=e->getConfBool("pianoOptionsSet",pianoOptionsSet);
|
||||||
|
pianoOffset=e->getConfInt("pianoOffset",pianoOffset);
|
||||||
|
pianoOffsetEdit=e->getConfInt("pianoOffsetEdit",pianoOffsetEdit);
|
||||||
|
pianoView=e->getConfInt("pianoView",pianoView);
|
||||||
|
pianoInputPadMode=e->getConfInt("pianoInputPadMode",pianoInputPadMode);
|
||||||
|
|
||||||
syncSettings();
|
syncSettings();
|
||||||
|
|
||||||
if (settings.dpiScale>=0.5f) {
|
if (settings.dpiScale>=0.5f) {
|
||||||
|
@ -3887,8 +3940,11 @@ bool FurnaceGUI::init() {
|
||||||
SDL_Rect displaySize;
|
SDL_Rect displaySize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SDL_SetHint("SDL_HINT_VIDEO_ALLOW_SCREENSAVER","1");
|
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER,"1");
|
||||||
SDL_SetHint("SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH","1");
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS,"0");
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS,"0");
|
||||||
|
// don't disable compositing on KWin
|
||||||
|
SDL_SetHint(SDL_HINT_X11_WINDOW_TYPE,"_NET_WM_WINDOW_TYPE_NORMAL");
|
||||||
|
|
||||||
SDL_Init(SDL_INIT_VIDEO);
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
@ -4064,6 +4120,17 @@ bool FurnaceGUI::finish() {
|
||||||
e->setConf("followPattern",followPattern);
|
e->setConf("followPattern",followPattern);
|
||||||
e->setConf("orderEditMode",orderEditMode);
|
e->setConf("orderEditMode",orderEditMode);
|
||||||
|
|
||||||
|
// commit piano state
|
||||||
|
e->setConf("pianoOctaves",pianoOctaves);
|
||||||
|
e->setConf("pianoOctavesEdit",pianoOctavesEdit);
|
||||||
|
e->setConf("pianoOptions",pianoOptions);
|
||||||
|
e->setConf("pianoSharePosition",pianoSharePosition);
|
||||||
|
e->setConf("pianoOptionsSet",pianoOptionsSet);
|
||||||
|
e->setConf("pianoOffset",pianoOffset);
|
||||||
|
e->setConf("pianoOffsetEdit",pianoOffsetEdit);
|
||||||
|
e->setConf("pianoView",pianoView);
|
||||||
|
e->setConf("pianoInputPadMode",pianoInputPadMode);
|
||||||
|
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
delete oldPat[i];
|
delete oldPat[i];
|
||||||
}
|
}
|
||||||
|
@ -4283,6 +4350,16 @@ FurnaceGUI::FurnaceGUI():
|
||||||
bindSetPending(false),
|
bindSetPending(false),
|
||||||
nextScroll(-1.0f),
|
nextScroll(-1.0f),
|
||||||
nextAddScroll(0.0f),
|
nextAddScroll(0.0f),
|
||||||
|
layoutTimeBegin(0),
|
||||||
|
layoutTimeEnd(0),
|
||||||
|
layoutTimeDelta(0),
|
||||||
|
renderTimeBegin(0),
|
||||||
|
renderTimeEnd(0),
|
||||||
|
renderTimeDelta(0),
|
||||||
|
eventTimeBegin(0),
|
||||||
|
eventTimeEnd(0),
|
||||||
|
eventTimeDelta(0),
|
||||||
|
chanToMove(-1),
|
||||||
transposeAmount(0),
|
transposeAmount(0),
|
||||||
randomizeMin(0),
|
randomizeMin(0),
|
||||||
randomizeMax(255),
|
randomizeMax(255),
|
||||||
|
|
|
@ -491,6 +491,7 @@ enum FurnaceGUIActions {
|
||||||
GUI_ACTION_SAMPLE_ZOOM_OUT,
|
GUI_ACTION_SAMPLE_ZOOM_OUT,
|
||||||
GUI_ACTION_SAMPLE_ZOOM_AUTO,
|
GUI_ACTION_SAMPLE_ZOOM_AUTO,
|
||||||
GUI_ACTION_SAMPLE_MAKE_INS,
|
GUI_ACTION_SAMPLE_MAKE_INS,
|
||||||
|
GUI_ACTION_SAMPLE_SET_LOOP,
|
||||||
GUI_ACTION_SAMPLE_MAX,
|
GUI_ACTION_SAMPLE_MAX,
|
||||||
|
|
||||||
GUI_ACTION_ORDERS_MIN,
|
GUI_ACTION_ORDERS_MIN,
|
||||||
|
@ -944,6 +945,11 @@ class FurnaceGUI {
|
||||||
int noMultiSystem;
|
int noMultiSystem;
|
||||||
int oldMacroVSlider;
|
int oldMacroVSlider;
|
||||||
int displayAllInsTypes;
|
int displayAllInsTypes;
|
||||||
|
int noteCellSpacing;
|
||||||
|
int insCellSpacing;
|
||||||
|
int volCellSpacing;
|
||||||
|
int effectCellSpacing;
|
||||||
|
int effectValCellSpacing;
|
||||||
unsigned int maxUndoSteps;
|
unsigned int maxUndoSteps;
|
||||||
String mainFontPath;
|
String mainFontPath;
|
||||||
String patFontPath;
|
String patFontPath;
|
||||||
|
@ -1037,6 +1043,11 @@ class FurnaceGUI {
|
||||||
noMultiSystem(0),
|
noMultiSystem(0),
|
||||||
oldMacroVSlider(0),
|
oldMacroVSlider(0),
|
||||||
displayAllInsTypes(0),
|
displayAllInsTypes(0),
|
||||||
|
noteCellSpacing(0),
|
||||||
|
insCellSpacing(0),
|
||||||
|
volCellSpacing(0),
|
||||||
|
effectCellSpacing(0),
|
||||||
|
effectValCellSpacing(0),
|
||||||
maxUndoSteps(100),
|
maxUndoSteps(100),
|
||||||
mainFontPath(""),
|
mainFontPath(""),
|
||||||
patFontPath(""),
|
patFontPath(""),
|
||||||
|
@ -1180,10 +1191,17 @@ class FurnaceGUI {
|
||||||
|
|
||||||
float nextScroll, nextAddScroll;
|
float nextScroll, nextAddScroll;
|
||||||
|
|
||||||
|
int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta;
|
||||||
|
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||||
|
int eventTimeBegin, eventTimeEnd, eventTimeDelta;
|
||||||
|
|
||||||
|
int chanToMove;
|
||||||
|
|
||||||
ImVec2 patWindowPos, patWindowSize;
|
ImVec2 patWindowPos, patWindowSize;
|
||||||
|
|
||||||
// pattern view specific
|
// pattern view specific
|
||||||
ImVec2 fourChars, threeChars, twoChars;
|
ImVec2 fourChars, threeChars, twoChars;
|
||||||
|
ImVec2 noteCellSize, insCellSize, volCellSize, effectCellSize, effectValCellSize;
|
||||||
SelectionPoint sel1, sel2;
|
SelectionPoint sel1, sel2;
|
||||||
int dummyRows, demandX;
|
int dummyRows, demandX;
|
||||||
int transposeAmount, randomizeMin, randomizeMax, fadeMin, fadeMax;
|
int transposeAmount, randomizeMin, randomizeMax, fadeMin, fadeMax;
|
||||||
|
|
|
@ -401,7 +401,7 @@ const FurnaceGUIColors fxColors[256]={
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
GUI_COLOR_PATTERN_EFFECT_MISC, // DF
|
||||||
|
|
||||||
// E0-FF extended effects
|
// E0-FF extended effects
|
||||||
GUI_COLOR_PATTERN_EFFECT_MISC, // E0
|
GUI_COLOR_PATTERN_EFFECT_MISC, // E0
|
||||||
|
@ -638,6 +638,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
||||||
D("SAMPLE_ZOOM_OUT", "Zoom out", FURKMOD_CMD|SDLK_MINUS),
|
D("SAMPLE_ZOOM_OUT", "Zoom out", FURKMOD_CMD|SDLK_MINUS),
|
||||||
D("SAMPLE_ZOOM_AUTO", "Toggle auto-zoom", FURKMOD_CMD|SDLK_0),
|
D("SAMPLE_ZOOM_AUTO", "Toggle auto-zoom", FURKMOD_CMD|SDLK_0),
|
||||||
D("SAMPLE_MAKE_INS", "Create instrument from sample", 0),
|
D("SAMPLE_MAKE_INS", "Create instrument from sample", 0),
|
||||||
|
D("SAMPLE_SET_LOOP", "Set loop to selection", FURKMOD_CMD|SDLK_l),
|
||||||
D("SAMPLE_MAX", "", NOT_AN_ACTION),
|
D("SAMPLE_MAX", "", NOT_AN_ACTION),
|
||||||
|
|
||||||
D("ORDERS_MIN", "---Orders", NOT_AN_ACTION),
|
D("ORDERS_MIN", "---Orders", NOT_AN_ACTION),
|
||||||
|
@ -832,6 +833,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
||||||
const int availableSystems[]={
|
const int availableSystems[]={
|
||||||
DIV_SYSTEM_YM2612,
|
DIV_SYSTEM_YM2612,
|
||||||
DIV_SYSTEM_YM2612_EXT,
|
DIV_SYSTEM_YM2612_EXT,
|
||||||
|
DIV_SYSTEM_YM2612_FRAC,
|
||||||
|
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||||
DIV_SYSTEM_SMS,
|
DIV_SYSTEM_SMS,
|
||||||
DIV_SYSTEM_GB,
|
DIV_SYSTEM_GB,
|
||||||
DIV_SYSTEM_PCE,
|
DIV_SYSTEM_PCE,
|
||||||
|
|
|
@ -1868,12 +1868,12 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
op.ar&=maxArDr;
|
op.ar&=maxArDr;
|
||||||
CENTER_VSLIDER;
|
CENTER_VSLIDER;
|
||||||
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&_ZERO,&maxArDr));
|
P(CWVSliderScalar("##AR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
op.dr&=maxArDr;
|
op.dr&=maxArDr;
|
||||||
CENTER_VSLIDER;
|
CENTER_VSLIDER;
|
||||||
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&_ZERO,&maxArDr));
|
P(CWVSliderScalar("##DR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
|
||||||
|
|
||||||
if (settings.susPosition==0) {
|
if (settings.susPosition==0) {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
@ -1886,13 +1886,13 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
op.d2r&=31;
|
op.d2r&=31;
|
||||||
CENTER_VSLIDER;
|
CENTER_VSLIDER;
|
||||||
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_ZERO,&_THIRTY_ONE));
|
P(CWVSliderScalar("##D2R",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
op.rr&=15;
|
op.rr&=15;
|
||||||
CENTER_VSLIDER;
|
CENTER_VSLIDER;
|
||||||
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_ZERO,&_FIFTEEN));
|
P(CWVSliderScalar("##RR",ImVec2(20.0f*dpiScale,sliderHeight),ImGuiDataType_U8,&op.rr,&_FIFTEEN,&_ZERO));
|
||||||
|
|
||||||
if (settings.susPosition==1) {
|
if (settings.susPosition==1) {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
|
@ -138,12 +138,12 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
||||||
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,threeChars);
|
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,noteCellSize);
|
||||||
demandX=ImGui::GetCursorPosX();
|
demandX=ImGui::GetCursorPosX();
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
} else {
|
} else {
|
||||||
if (selectedNote) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
if (selectedNote) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
||||||
ImGui::Selectable(id,isPushing || selectedNote,ImGuiSelectableFlags_NoPadWithHalfSpacing,threeChars);
|
ImGui::Selectable(id,isPushing || selectedNote,ImGuiSelectableFlags_NoPadWithHalfSpacing,noteCellSize);
|
||||||
if (selectedNote) ImGui::PopStyleColor();
|
if (selectedNote) ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
|
@ -178,12 +178,12 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
||||||
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,insCellSize);
|
||||||
demandX=ImGui::GetCursorPosX();
|
demandX=ImGui::GetCursorPosX();
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
} else {
|
} else {
|
||||||
if (selectedIns) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
if (selectedIns) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
||||||
ImGui::Selectable(id,isPushing || selectedIns,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,isPushing || selectedIns,ImGuiSelectableFlags_NoPadWithHalfSpacing,insCellSize);
|
||||||
if (selectedIns) ImGui::PopStyleColor();
|
if (selectedIns) ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
|
@ -212,12 +212,12 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
||||||
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,volCellSize);
|
||||||
demandX=ImGui::GetCursorPosX();
|
demandX=ImGui::GetCursorPosX();
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
} else {
|
} else {
|
||||||
if (selectedVol) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
if (selectedVol) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
||||||
ImGui::Selectable(id,isPushing || selectedVol,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,isPushing || selectedVol,ImGuiSelectableFlags_NoPadWithHalfSpacing,volCellSize);
|
||||||
if (selectedVol) ImGui::PopStyleColor();
|
if (selectedVol) ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
|
@ -257,12 +257,12 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
||||||
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,effectCellSize);
|
||||||
demandX=ImGui::GetCursorPosX();
|
demandX=ImGui::GetCursorPosX();
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
} else {
|
} else {
|
||||||
if (selectedEffect) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
if (selectedEffect) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
||||||
ImGui::Selectable(id,isPushing || selectedEffect,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,isPushing || selectedEffect,ImGuiSelectableFlags_NoPadWithHalfSpacing,effectCellSize);
|
||||||
if (selectedEffect) ImGui::PopStyleColor();
|
if (selectedEffect) ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
|
@ -283,12 +283,12 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_CURSOR]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_CURSOR_HOVER]);
|
||||||
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,effectValCellSize);
|
||||||
demandX=ImGui::GetCursorPosX();
|
demandX=ImGui::GetCursorPosX();
|
||||||
ImGui::PopStyleColor(3);
|
ImGui::PopStyleColor(3);
|
||||||
} else {
|
} else {
|
||||||
if (selectedEffectVal) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
if (selectedEffectVal) ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]);
|
||||||
ImGui::Selectable(id,isPushing || selectedEffectVal,ImGuiSelectableFlags_NoPadWithHalfSpacing,twoChars);
|
ImGui::Selectable(id,isPushing || selectedEffectVal,ImGuiSelectableFlags_NoPadWithHalfSpacing,effectValCellSize);
|
||||||
if (selectedEffectVal) ImGui::PopStyleColor();
|
if (selectedEffectVal) ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked()) {
|
if (ImGui::IsItemClicked()) {
|
||||||
|
@ -549,7 +549,20 @@ void FurnaceGUI::drawPattern() {
|
||||||
threeChars=ImVec2(oneCharSize*3.0f,lineHeight);
|
threeChars=ImVec2(oneCharSize*3.0f,lineHeight);
|
||||||
twoChars=ImVec2(oneCharSize*2.0f,lineHeight);
|
twoChars=ImVec2(oneCharSize*2.0f,lineHeight);
|
||||||
//ImVec2 oneChar=ImVec2(oneCharSize,lineHeight);
|
//ImVec2 oneChar=ImVec2(oneCharSize,lineHeight);
|
||||||
|
|
||||||
|
noteCellSize=threeChars;
|
||||||
|
noteCellSize.x+=(float)settings.noteCellSpacing*dpiScale;
|
||||||
|
insCellSize=twoChars;
|
||||||
|
insCellSize.x+=(float)settings.insCellSpacing*dpiScale;
|
||||||
|
volCellSize=twoChars;
|
||||||
|
volCellSize.x+=(float)settings.volCellSpacing*dpiScale;
|
||||||
|
effectCellSize=twoChars;
|
||||||
|
effectCellSize.x+=(float)settings.effectCellSpacing*dpiScale;
|
||||||
|
effectValCellSize=twoChars;
|
||||||
|
effectValCellSize.x+=(float)settings.effectValCellSpacing*dpiScale;
|
||||||
|
|
||||||
dummyRows=(ImGui::GetWindowSize().y/lineHeight)/2;
|
dummyRows=(ImGui::GetWindowSize().y/lineHeight)/2;
|
||||||
|
|
||||||
// オップナー2608 i owe you one more for this horrible code
|
// オップナー2608 i owe you one more for this horrible code
|
||||||
// previous pattern
|
// previous pattern
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
|
|
|
@ -102,6 +102,18 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha YM2612 (OPN2) with DualPCM", {
|
||||||
|
DIV_SYSTEM_YM2612, 64, 0, (int)0x80000000,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha YM2612 (extended channel 3) with DualPCM", {
|
||||||
|
DIV_SYSTEM_YM2612_EXT, 64, 0, (int)0x80000000,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
cat.systems.push_back(FurnaceGUISysDef(
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
"Yamaha YM2413 (OPLL)", {
|
"Yamaha YM2413 (OPLL)", {
|
||||||
DIV_SYSTEM_OPLL, 64, 0, 0,
|
DIV_SYSTEM_OPLL, 64, 0, 0,
|
||||||
|
@ -132,6 +144,18 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha YM3438 (OPN2C) with DualPCM", {
|
||||||
|
DIV_SYSTEM_YM2612_FRAC, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Yamaha YM3438 (extended channel 3) with DualPCM", {
|
||||||
|
DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
cat.systems.push_back(FurnaceGUISysDef(
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
"Yamaha YM3526 (OPL)", {
|
"Yamaha YM3526 (OPL)", {
|
||||||
DIV_SYSTEM_OPL, 64, 0, 0,
|
DIV_SYSTEM_OPL, 64, 0, 0,
|
||||||
|
@ -435,6 +459,20 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Sega Genesis (Fractal Sound template)", {
|
||||||
|
DIV_SYSTEM_YM2612_FRAC, 64, 0, 0,
|
||||||
|
DIV_SYSTEM_SMS, 24, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
|
"Sega Genesis (Fractal Sound template, extended channel 3)", {
|
||||||
|
DIV_SYSTEM_YM2612_FRAC_EXT, 64, 0, 0,
|
||||||
|
DIV_SYSTEM_SMS, 24, 0, 0,
|
||||||
|
0
|
||||||
|
}
|
||||||
|
));
|
||||||
cat.systems.push_back(FurnaceGUISysDef(
|
cat.systems.push_back(FurnaceGUISysDef(
|
||||||
"Sega Genesis (with Sega CD)", {
|
"Sega Genesis (with Sega CD)", {
|
||||||
DIV_SYSTEM_YM2612, 64, 0, 0,
|
DIV_SYSTEM_YM2612, 64, 0, 0,
|
||||||
|
|
|
@ -1312,6 +1312,10 @@ void FurnaceGUI::drawSampleEdit() {
|
||||||
if (ImGui::MenuItem("select all",BIND_FOR(GUI_ACTION_SAMPLE_SELECT_ALL))) {
|
if (ImGui::MenuItem("select all",BIND_FOR(GUI_ACTION_SAMPLE_SELECT_ALL))) {
|
||||||
doAction(GUI_ACTION_SAMPLE_SELECT_ALL);
|
doAction(GUI_ACTION_SAMPLE_SELECT_ALL);
|
||||||
}
|
}
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::MenuItem("set loop to selection",BIND_FOR(GUI_ACTION_SAMPLE_SET_LOOP))) {
|
||||||
|
doAction(GUI_ACTION_SAMPLE_SET_LOOP);
|
||||||
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1240,6 +1240,35 @@ void FurnaceGUI::drawSettings() {
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::Text("Pattern view spacing after:");
|
||||||
|
|
||||||
|
if (CWSliderInt("Note",&settings.noteCellSpacing,0,32)) {
|
||||||
|
if (settings.noteCellSpacing<0) settings.noteCellSpacing=0;
|
||||||
|
if (settings.noteCellSpacing>32) settings.noteCellSpacing=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CWSliderInt("Instrument",&settings.insCellSpacing,0,32)) {
|
||||||
|
if (settings.insCellSpacing<0) settings.insCellSpacing=0;
|
||||||
|
if (settings.insCellSpacing>32) settings.insCellSpacing=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CWSliderInt("Volume",&settings.volCellSpacing,0,32)) {
|
||||||
|
if (settings.volCellSpacing<0) settings.volCellSpacing=0;
|
||||||
|
if (settings.volCellSpacing>32) settings.volCellSpacing=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CWSliderInt("Effect",&settings.effectCellSpacing,0,32)) {
|
||||||
|
if (settings.effectCellSpacing<0) settings.effectCellSpacing=0;
|
||||||
|
if (settings.effectCellSpacing>32) settings.effectCellSpacing=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CWSliderInt("Effect value",&settings.effectValCellSpacing,0,32)) {
|
||||||
|
if (settings.effectValCellSpacing<0) settings.effectValCellSpacing=0;
|
||||||
|
if (settings.effectValCellSpacing>32) settings.effectValCellSpacing=32;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::TreeNode("Color scheme")) {
|
if (ImGui::TreeNode("Color scheme")) {
|
||||||
if (ImGui::Button("Import")) {
|
if (ImGui::Button("Import")) {
|
||||||
openFileDialog(GUI_FILE_IMPORT_COLORS);
|
openFileDialog(GUI_FILE_IMPORT_COLORS);
|
||||||
|
@ -1806,6 +1835,7 @@ void FurnaceGUI::drawSettings() {
|
||||||
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_ZOOM_OUT);
|
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_ZOOM_OUT);
|
||||||
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_ZOOM_AUTO);
|
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_ZOOM_AUTO);
|
||||||
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_MAKE_INS);
|
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_MAKE_INS);
|
||||||
|
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_SET_LOOP);
|
||||||
|
|
||||||
KEYBIND_CONFIG_END;
|
KEYBIND_CONFIG_END;
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
@ -1975,6 +2005,11 @@ void FurnaceGUI::syncSettings() {
|
||||||
settings.noMultiSystem=e->getConfInt("noMultiSystem",0);
|
settings.noMultiSystem=e->getConfInt("noMultiSystem",0);
|
||||||
settings.oldMacroVSlider=e->getConfInt("oldMacroVSlider",0);
|
settings.oldMacroVSlider=e->getConfInt("oldMacroVSlider",0);
|
||||||
settings.displayAllInsTypes=e->getConfInt("displayAllInsTypes",0);
|
settings.displayAllInsTypes=e->getConfInt("displayAllInsTypes",0);
|
||||||
|
settings.noteCellSpacing=e->getConfInt("noteCellSpacing",0);
|
||||||
|
settings.insCellSpacing=e->getConfInt("insCellSpacing",0);
|
||||||
|
settings.volCellSpacing=e->getConfInt("volCellSpacing",0);
|
||||||
|
settings.effectCellSpacing=e->getConfInt("effectCellSpacing",0);
|
||||||
|
settings.effectValCellSpacing=e->getConfInt("effectValCellSpacing",0);
|
||||||
|
|
||||||
clampSetting(settings.mainFontSize,2,96);
|
clampSetting(settings.mainFontSize,2,96);
|
||||||
clampSetting(settings.patFontSize,2,96);
|
clampSetting(settings.patFontSize,2,96);
|
||||||
|
@ -2052,6 +2087,11 @@ void FurnaceGUI::syncSettings() {
|
||||||
clampSetting(settings.noMultiSystem,0,1);
|
clampSetting(settings.noMultiSystem,0,1);
|
||||||
clampSetting(settings.oldMacroVSlider,0,1);
|
clampSetting(settings.oldMacroVSlider,0,1);
|
||||||
clampSetting(settings.displayAllInsTypes,0,1);
|
clampSetting(settings.displayAllInsTypes,0,1);
|
||||||
|
clampSetting(settings.noteCellSpacing,0,32);
|
||||||
|
clampSetting(settings.insCellSpacing,0,32);
|
||||||
|
clampSetting(settings.volCellSpacing,0,32);
|
||||||
|
clampSetting(settings.effectCellSpacing,0,32);
|
||||||
|
clampSetting(settings.effectValCellSpacing,0,32);
|
||||||
|
|
||||||
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
|
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
|
||||||
if (settings.initialSys.size()<4) {
|
if (settings.initialSys.size()<4) {
|
||||||
|
@ -2178,6 +2218,11 @@ void FurnaceGUI::commitSettings() {
|
||||||
e->setConf("noMultiSystem",settings.noMultiSystem);
|
e->setConf("noMultiSystem",settings.noMultiSystem);
|
||||||
e->setConf("oldMacroVSlider",settings.oldMacroVSlider);
|
e->setConf("oldMacroVSlider",settings.oldMacroVSlider);
|
||||||
e->setConf("displayAllInsTypes",settings.displayAllInsTypes);
|
e->setConf("displayAllInsTypes",settings.displayAllInsTypes);
|
||||||
|
e->setConf("noteCellSpacing",settings.noteCellSpacing);
|
||||||
|
e->setConf("insCellSpacing",settings.insCellSpacing);
|
||||||
|
e->setConf("volCellSpacing",settings.volCellSpacing);
|
||||||
|
e->setConf("effectCellSpacing",settings.effectCellSpacing);
|
||||||
|
e->setConf("effectValCellSpacing",settings.effectValCellSpacing);
|
||||||
|
|
||||||
// colors
|
// colors
|
||||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||||
|
|
Loading…
Reference in a new issue