mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 04:55:13 +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)
|
||||
set(USE_RTMIDI_DEFAULT OFF)
|
||||
set(USE_BACKWARD_DEFAULT OFF)
|
||||
find_library(TERMUX rt)
|
||||
if (TERMUX)
|
||||
message(STATUS "Termux detected")
|
||||
endif()
|
||||
else()
|
||||
set(USE_RTMIDI_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 "")
|
||||
|
||||
if (ANDROID)
|
||||
if (ANDROID AND NOT TERMUX)
|
||||
set(DEPENDENCIES_DEFINES "IS_MOBILE")
|
||||
else()
|
||||
set(DEPENDENCIES_DEFINES "")
|
||||
|
@ -188,7 +192,7 @@ if (USE_SDL2)
|
|||
endif()
|
||||
message(STATUS "Using system-installed SDL2")
|
||||
else()
|
||||
if (ANDROID)
|
||||
if (ANDROID AND NOT TERMUX)
|
||||
set(SDL_SHARED ON CACHE BOOL "Force no dynamically-linked SDL" FORCE)
|
||||
set(SDL_STATIC OFF CACHE BOOL "Force statically-linked SDL" FORCE)
|
||||
else()
|
||||
|
@ -203,7 +207,7 @@ if (USE_SDL2)
|
|||
add_subdirectory(extern/SDL EXCLUDE_FROM_ALL)
|
||||
list(APPEND DEPENDENCIES_DEFINES HAVE_SDL2)
|
||||
list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include)
|
||||
if (ANDROID)
|
||||
if (ANDROID AND NOT TERMUX)
|
||||
list(APPEND DEPENDENCIES_LIBRARIES SDL2)
|
||||
else()
|
||||
list(APPEND DEPENDENCIES_LIBRARIES SDL2-static)
|
||||
|
@ -579,7 +583,7 @@ endif()
|
|||
|
||||
if (MSVC)
|
||||
add_executable(furnace WIN32 ${USED_SOURCES})
|
||||
elseif(ANDROID)
|
||||
elseif(ANDROID AND NOT TERMUX)
|
||||
add_library(furnace SHARED ${USED_SOURCES})
|
||||
else()
|
||||
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()
|
||||
|
||||
if (NOT ANDROID)
|
||||
if (NOT ANDROID OR TERMUX)
|
||||
install(TARGETS furnace RUNTIME DESTINATION bin)
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
|
|
8
TODO.md
8
TODO.md
|
@ -8,12 +8,10 @@
|
|||
|
||||
- additional YM2612 features
|
||||
- CSM
|
||||
- DualPCM
|
||||
- reverse sample playback
|
||||
- ADPCM chips
|
||||
- MSM6258 pitch and clock select
|
||||
- the last three compat flags
|
||||
- add OPL drum instrument type
|
||||
- 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
|
||||
- rewrite the system name detection function anyway
|
||||
- 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.
|
||||
|
||||
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!
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t data = chip->data;
|
||||
|
@ -260,6 +264,10 @@ void YMPSG_Init(ympsg_t *chip, uint8_t real_sn)
|
|||
YMPSG_SetIC(chip, 1);
|
||||
chip->noise_tap2 = real_sn ? 13 : 15;
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
YMPSG_UpdateSample(chip);
|
||||
if (chip->test & 1)
|
||||
{
|
||||
sample += ympsg_vol[chip->volume_out[chip->test >> 1]];
|
||||
sample += ympsg_vol[16] * 3.f;
|
||||
sample += chip->vol_table[chip->volume_out[chip->test >> 1]];
|
||||
sample += chip->vol_table[16] * 3;
|
||||
}
|
||||
else if (!chip->mute)
|
||||
{
|
||||
sample += ympsg_vol[chip->volume_out[0]];
|
||||
sample += ympsg_vol[chip->volume_out[1]];
|
||||
sample += ympsg_vol[chip->volume_out[2]];
|
||||
sample += ympsg_vol[chip->volume_out[3]];
|
||||
sample += chip->vol_table[chip->volume_out[0]];
|
||||
sample += chip->vol_table[chip->volume_out[1]];
|
||||
sample += chip->vol_table[chip->volume_out[2]];
|
||||
sample += chip->vol_table[chip->volume_out[3]];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (!((chip->mute>>i) & 1))
|
||||
sample += ympsg_vol[chip->volume_out[i]];
|
||||
sample += chip->vol_table[chip->volume_out[i]];
|
||||
}
|
||||
}
|
||||
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;
|
||||
ympsg_writebuf writebuf[YMPSG_WRITEBUF_SIZE];
|
||||
|
||||
//
|
||||
short vol_table[17];
|
||||
|
||||
|
||||
uint8_t mute;
|
||||
} 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_SetIC(ympsg_t *chip, uint32_t ic);
|
||||
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);
|
||||
|
||||
|
||||
|
|
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);
|
||||
}
|
||||
|
||||
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.address = true;
|
||||
|
@ -4263,6 +4276,16 @@ public:
|
|||
printer.address = true;
|
||||
printer.print(st, 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) || \
|
||||
|
|
97
extern/imgui_patched/imgui_internal.h
vendored
97
extern/imgui_patched/imgui_internal.h
vendored
|
@ -559,14 +559,44 @@ template<int BITCOUNT, int OFFSET = 0>
|
|||
struct ImBitArray
|
||||
{
|
||||
ImU32 Storage[(BITCOUNT + 31) >> 5];
|
||||
ImBitArray() { ClearAllBits(); }
|
||||
void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }
|
||||
void SetAllBits() { memset(Storage, 255, sizeof(Storage)); }
|
||||
bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||
void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(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)
|
||||
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||
ImBitArray() { ClearAllBits(); }
|
||||
void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }
|
||||
void SetAllBits() { memset(Storage, 255, sizeof(Storage)); }
|
||||
bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
|
||||
void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(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)
|
||||
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
|
||||
|
@ -574,11 +604,33 @@ struct ImBitArray
|
|||
struct IMGUI_API ImBitVector
|
||||
{
|
||||
ImVector<ImU32> Storage;
|
||||
void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||
void Clear() { Storage.clear(); }
|
||||
bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); }
|
||||
void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }
|
||||
void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }
|
||||
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 ClearAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||
void SetAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 255, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
|
||||
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<>
|
||||
|
@ -2447,13 +2499,12 @@ struct IMGUI_API ImGuiTabBar
|
|||
// [SECTION] Table support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#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_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels()
|
||||
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
|
||||
#define IMGUI_TABLE_DRAW_CHANNELS(c) (4 + (c) * 2) // See TableSetupDrawChannels()
|
||||
|
||||
// Our current column maximum is 64 but we may raise that in the future.
|
||||
typedef ImS8 ImGuiTableColumnIdx;
|
||||
typedef ImU8 ImGuiTableDrawChannelIdx;
|
||||
// Our current column maximum is IMGUI_TABLE_MAX_COLUMNS but we may raise that in the future.
|
||||
typedef ImS32 ImGuiTableColumnIdx;
|
||||
typedef ImU32 ImGuiTableDrawChannelIdx;
|
||||
|
||||
// [Internal] sizeof() ~ 104
|
||||
// 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<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.
|
||||
ImU64 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
|
||||
ImU64 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 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
|
||||
ImBitVector EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
|
||||
ImBitVector VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
|
||||
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)
|
||||
int SettingsOffset; // Offset in g.SettingsTables
|
||||
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;
|
||||
|
||||
// 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)
|
||||
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->OuterWindow = table->InnerWindow = outer_window;
|
||||
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->InnerWidth = inner_width;
|
||||
temp_data->UserOuterSize = outer_size;
|
||||
|
@ -721,8 +731,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
|
||||
table->IsDefaultDisplayOrder = true;
|
||||
table->ColumnsEnabledCount = 0;
|
||||
table->EnabledMaskByIndex = 0x00;
|
||||
table->EnabledMaskByDisplayOrder = 0x00;
|
||||
table->EnabledMaskByIndex.ClearAllBits();
|
||||
table->EnabledMaskByDisplayOrder.ClearAllBits();
|
||||
table->LeftMostEnabledColumn = -1;
|
||||
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
|
||||
table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;
|
||||
column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
|
||||
table->EnabledMaskByIndex |= (ImU64)1 << column_n;
|
||||
table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder;
|
||||
table->EnabledMaskByIndex |= column_n;
|
||||
table->EnabledMaskByDisplayOrder |= column->DisplayOrder;
|
||||
prev_visible_column_idx = column_n;
|
||||
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
|
||||
|
||||
|
@ -836,7 +846,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
||||
if (!(table->EnabledMaskByIndex & column_n))
|
||||
continue;
|
||||
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!)
|
||||
if (column->AutoFitQueue != 0x00)
|
||||
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;
|
||||
|
||||
// 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;
|
||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||
{
|
||||
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
||||
if (!(table->EnabledMaskByIndex & column_n))
|
||||
continue;
|
||||
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))
|
||||
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;
|
||||
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
|
||||
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;
|
||||
ImRect host_clip_rect = table->InnerClipRect;
|
||||
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
|
||||
table->VisibleMaskByIndex = 0x00;
|
||||
table->RequestOutputMaskByIndex = 0x00;
|
||||
table->VisibleMaskByIndex.ClearAllBits();
|
||||
table->RequestOutputMaskByIndex.ClearAllBits();
|
||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||
{
|
||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||
|
@ -967,7 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||
// Clear status flags
|
||||
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.
|
||||
// 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);
|
||||
const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;
|
||||
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.
|
||||
column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;
|
||||
if (column->IsRequestOutput)
|
||||
table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n);
|
||||
table->RequestOutputMaskByIndex |= column_n;
|
||||
|
||||
// Mark column as SkipItems (ignoring all items/layout)
|
||||
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++)
|
||||
{
|
||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
||||
if (!(table->EnabledMaskByDisplayOrder & order_n))
|
||||
continue;
|
||||
|
||||
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_min = 0.0f;
|
||||
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];
|
||||
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;
|
||||
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
|
||||
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
|
||||
|
||||
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;
|
||||
if (column_n == -1)
|
||||
column_n = table->CurrentColumn;
|
||||
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
|
||||
if ((table->VisibleMaskByIndex & column_n) == 0)
|
||||
return;
|
||||
if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
|
||||
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,
|
||||
// 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
|
||||
|
@ -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,
|
||||
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
|
||||
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;
|
||||
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;
|
||||
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
|
||||
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;
|
||||
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);
|
||||
IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS);
|
||||
IM_ASSERT(channel_no < merge_group_bitlen);
|
||||
MergeGroup* merge_group = &merge_groups[merge_group_n];
|
||||
if (merge_group->ChannelsCount == 0)
|
||||
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;
|
||||
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
|
||||
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.ClearBit(table->Bg2DrawChannelUnfrozen);
|
||||
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));
|
||||
#endif
|
||||
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];
|
||||
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++)
|
||||
{
|
||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
||||
if (!(table->EnabledMaskByDisplayOrder & order_n))
|
||||
continue;
|
||||
|
||||
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:
|
||||
|
||||
- 99: Furnace dev99
|
||||
- 98: Furnace dev98
|
||||
- 97: Furnace dev97
|
||||
- 96: Furnace dev96
|
||||
- 95: Furnace dev95
|
||||
|
@ -226,6 +228,9 @@ size | description
|
|||
| - 0xb9: Namco WSG - 3 channels
|
||||
| - 0xba: Namco 15xx - 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
|
||||
| - 0xe0: QSound - 19 channels
|
||||
| - 0xfd: Dummy System - 8 channels
|
||||
|
@ -302,7 +307,11 @@ size | description
|
|||
1 | pitch macro is linear (>=90) or reserved
|
||||
1 | pitch slide speed in full linear pitch mode (>=94) 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**
|
||||
2 | virtual tempo numerator 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_BANK, // (bank)
|
||||
DIV_CMD_SAMPLE_POS, // (pos)
|
||||
DIV_CMD_SAMPLE_DIR, // (direction)
|
||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_MODE, // (enabled)
|
||||
DIV_CMD_SAMPLE_TRANSWAVE_SLICE_POS, // (slice)
|
||||
|
||||
|
@ -236,6 +237,8 @@ struct DivRegWrite {
|
|||
* - data is the sample rate
|
||||
* - 0xffffxx02: stop sample playback
|
||||
* - xx is the instance ID
|
||||
* - 0xffffxx03: set sample playback direction
|
||||
* - x is the instance ID
|
||||
* - 0xffffffff: reset
|
||||
*/
|
||||
unsigned int addr;
|
||||
|
|
|
@ -185,10 +185,22 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_YM2612:
|
||||
dispatch=new DivPlatformGenesis;
|
||||
((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0));
|
||||
((DivPlatformGenesis*)dispatch)->setSoftPCM(false);
|
||||
break;
|
||||
case DIV_SYSTEM_YM2612_EXT:
|
||||
dispatch=new DivPlatformGenesisExt;
|
||||
((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;
|
||||
case DIV_SYSTEM_SMS:
|
||||
dispatch=new DivPlatformSMS;
|
||||
|
|
|
@ -697,7 +697,7 @@ void DivEngine::initSongWithDesc(const int* description) {
|
|||
song.systemFlags[index]=description[i+3];
|
||||
index++;
|
||||
chanCount+=getChannelCount(song.system[index]);
|
||||
if (chanCount>=63) break;
|
||||
if (chanCount>=DIV_MAX_CHANS) break;
|
||||
if (index>=32) break;
|
||||
}
|
||||
song.systemLen=index;
|
||||
|
@ -887,9 +887,8 @@ bool DivEngine::addSystem(DivSystem which) {
|
|||
lastError="max number of systems is 32";
|
||||
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)>63) {
|
||||
lastError="max number of total channels is 63";
|
||||
if (chans+getChannelCount(which)>DIV_MAX_CHANS) {
|
||||
lastError=fmt::sprintf("max number of total channels is %d",DIV_MAX_CHANS);
|
||||
return false;
|
||||
}
|
||||
quitDispatch();
|
||||
|
@ -1773,7 +1772,7 @@ int DivEngine::addWave() {
|
|||
return waveCount;
|
||||
}
|
||||
|
||||
bool DivEngine::addWaveFromFile(const char* path) {
|
||||
bool DivEngine::addWaveFromFile(const char* path, bool addRaw) {
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return false;
|
||||
|
@ -1869,8 +1868,27 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
}
|
||||
} else {
|
||||
// read as binary
|
||||
logI("reading binary...");
|
||||
if (addRaw) {
|
||||
logI("reading binary...");
|
||||
len=reader.size();
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
if (addRaw) {
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
|
@ -1878,18 +1896,11 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
} else {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
// read as binary
|
||||
len=reader.size();
|
||||
logI("reading binary for being too small...");
|
||||
if (len>256) len=256;
|
||||
reader.seek(0,SEEK_SET);
|
||||
for (int i=0; i<len; i++) {
|
||||
wave->data[i]=(unsigned char)reader.readC();
|
||||
if (wave->max<wave->data[i]) wave->max=wave->data[i];
|
||||
}
|
||||
wave->len=len;
|
||||
}
|
||||
}
|
||||
} catch (EndOfFileException& e) {
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "dev97"
|
||||
#define DIV_ENGINE_VERSION 97
|
||||
#define DIV_VERSION "dev99"
|
||||
#define DIV_ENGINE_VERSION 99
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
@ -377,7 +377,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
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.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
@ -676,7 +676,7 @@ class DivEngine {
|
|||
int addWave();
|
||||
|
||||
// add wavetable from file
|
||||
bool addWaveFromFile(const char* path);
|
||||
bool addWaveFromFile(const char* path, bool loadRaw=true);
|
||||
|
||||
// delete wavetable
|
||||
void delWave(int index);
|
||||
|
|
|
@ -167,6 +167,10 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.fbPortaPause=true;
|
||||
ds.snDutyReset=true;
|
||||
ds.oldOctaveBoundary=false;
|
||||
ds.noOPN2Vol=true;
|
||||
ds.newVolumeScaling=false;
|
||||
ds.volMacroLinger=false;
|
||||
ds.brokenOutVol=true; // ???
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
|
@ -1031,6 +1035,14 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
if (ds.version<97) {
|
||||
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;
|
||||
|
||||
reader.readS(); // reserved
|
||||
|
@ -1413,7 +1425,21 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -2894,7 +2920,11 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) {
|
|||
w->writeC(song.pitchMacroIsLinear);
|
||||
w->writeC(song.pitchSlideSpeed);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,51 +125,109 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
|||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0xdf:
|
||||
return "DFxx: Set sample playback direction (0: normal; 1: reverse)";
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
static short o[2];
|
||||
static int os[2];
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!dacReady) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processDAC();
|
||||
|
||||
os[0]=0; os[1]=0;
|
||||
for (int i=0; i<6; i++) {
|
||||
if (!writes.empty() && --delay<0) {
|
||||
|
@ -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();
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!dacReady) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
processDAC();
|
||||
|
||||
os[0]=0; os[1]=0;
|
||||
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 (chan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -493,12 +517,14 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
chan[i].freq=(block<<11)|fNum;
|
||||
}
|
||||
if (chan[i].freq>0x3fff) chan[i].freq=0x3fff;
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||
if (chan[i].furnaceDac && dacMode) {
|
||||
if (i<6) {
|
||||
immWrite(chanOffs[i]+ADDR_FREQH,chan[i].freq>>8);
|
||||
immWrite(chanOffs[i]+ADDR_FREQ,chan[i].freq&0xff);
|
||||
}
|
||||
if (chan[i].furnaceDac && chan[i].dacMode) {
|
||||
double off=1.0;
|
||||
if (dacSample>=0 && dacSample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(dacSample);
|
||||
if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} 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);
|
||||
dacRate=chan[i].freq*off;
|
||||
if (dacRate<1) dacRate=1;
|
||||
if (dumpWrites) addWrite(0xffff0001,dacRate);
|
||||
chan[i].dacRate=chan[i].freq*off;
|
||||
if (chan[i].dacRate<1) chan[i].dacRate=1;
|
||||
if (dumpWrites) addWrite(0xffff0001,chan[i].dacRate);
|
||||
}
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
immWrite(0x28,0xf0|konOffs[i]);
|
||||
if (i<6) immWrite(0x28,0xf0|konOffs[i]);
|
||||
chan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
@ -521,6 +547,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
|
|||
|
||||
void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>5) return;
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
|
@ -541,29 +568,33 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
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) {
|
||||
dacMode=1;
|
||||
chan[c.chan].dacMode=1;
|
||||
rWrite(0x2b,1<<7);
|
||||
} else if (chan[c.chan].furnaceDac) {
|
||||
dacMode=0;
|
||||
chan[c.chan].dacMode=0;
|
||||
rWrite(0x2b,0<<7);
|
||||
}
|
||||
}
|
||||
if (c.chan==5 && dacMode) {
|
||||
if (c.chan>=5 && chan[c.chan].dacMode) {
|
||||
if (skipRegisterWrites) break;
|
||||
if (ins->type==DIV_INS_AMIGA) { // Furnace mode
|
||||
dacSample=ins->amiga.getSample(c.value);
|
||||
if (dacSample<0 || dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
break;
|
||||
} else {
|
||||
chan[c.chan].dacReversed=ins->amiga.getReversed(c.value);
|
||||
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) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
chan[c.chan].freqChanged=true;
|
||||
|
@ -573,23 +604,25 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
dacSample=12*sampleBank+chan[c.chan].note%12;
|
||||
if (dacSample>=parent->song.sampleLen) {
|
||||
dacSample=-1;
|
||||
chan[c.chan].dacSample=12*chan[c.chan].sampleBank+chan[c.chan].note%12;
|
||||
if (chan[c.chan].dacSample>=parent->song.sampleLen) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
break;
|
||||
} else {
|
||||
rWrite(0x2b,1<<7);
|
||||
if (dumpWrites) addWrite(0xffff0000,dacSample);
|
||||
if (dumpWrites) addWrite(0xffff0000,chan[c.chan].dacSample);
|
||||
}
|
||||
dacPos=0;
|
||||
dacPeriod=0;
|
||||
dacRate=MAX(1,parent->getSample(dacSample)->rate);
|
||||
if (dumpWrites) addWrite(0xffff0001,parent->getSample(dacSample)->rate);
|
||||
chan[c.chan].dacPos=0;
|
||||
chan[c.chan].dacPeriod=0;
|
||||
chan[c.chan].dacRate=MAX(1,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||
if (dumpWrites) addWrite(0xffff0001,parent->getSample(chan[c.chan].dacSample)->rate);
|
||||
chan[c.chan].furnaceDac=false;
|
||||
chan[c.chan].dacReversed=false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c.chan>=6) break;
|
||||
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].state=ins->fm;
|
||||
|
@ -642,12 +675,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
if (c.chan==5) {
|
||||
dacSample=-1;
|
||||
if (c.chan>=5) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
if (parent->song.brokenDACMode) {
|
||||
rWrite(0x2b,0);
|
||||
if (dacMode) break;
|
||||
if (chan[c.chan].dacMode) break;
|
||||
}
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
|
@ -655,8 +688,8 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=false;
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
if (c.chan==5) {
|
||||
dacSample=-1;
|
||||
if (c.chan>=5) {
|
||||
chan[c.chan].dacSample=-1;
|
||||
if (dumpWrites) addWrite(0xffff0002,0);
|
||||
}
|
||||
chan[c.chan].keyOff=true;
|
||||
|
@ -672,6 +705,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>=6) break;
|
||||
for (int i=0; i<4; i++) {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[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;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.chan>5) c.chan=5;
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
|
@ -735,7 +770,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
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);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
|
@ -762,18 +797,26 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
if (c.chan<5) c.chan=5;
|
||||
chan[c.chan].sampleBank=c.value;
|
||||
if (chan[c.chan].sampleBank>(parent->song.sample.size()/12)) {
|
||||
chan[c.chan].sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
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: {
|
||||
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);
|
||||
} else {
|
||||
chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11);
|
||||
|
@ -783,16 +826,19 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_LFO: {
|
||||
if (c.chan>=6) break;
|
||||
lfoValue=(c.value&7)|((c.value>>4)<<3);
|
||||
rWrite(0x22,lfoValue);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>=6) break;
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>=6) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.mult=c.value2&15;
|
||||
|
@ -800,6 +846,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>=6) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.tl=c.value2;
|
||||
|
@ -815,6 +862,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -831,6 +879,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -847,6 +896,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -863,6 +913,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -879,6 +930,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -895,6 +947,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -911,6 +964,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -927,6 +981,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -943,6 +998,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.chan>=6) break;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
|
@ -959,6 +1015,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
if (c.chan>=6) break;
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
case DIV_ALWAYS_SET_VOLUME:
|
||||
|
@ -1007,7 +1064,7 @@ void DivPlatformGenesis::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (dacMode) {
|
||||
if (chan[5].dacMode) {
|
||||
rWrite(0x2b,0x80);
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
|
@ -1057,18 +1114,18 @@ void DivPlatformGenesis::reset() {
|
|||
}
|
||||
|
||||
lastBusy=60;
|
||||
dacMode=0;
|
||||
dacPeriod=0;
|
||||
dacPos=0;
|
||||
dacRate=0;
|
||||
dacDelay=0;
|
||||
dacReady=true;
|
||||
dacSample=-1;
|
||||
sampleBank=0;
|
||||
lfoValue=8;
|
||||
|
||||
softPCMTimer=0;
|
||||
extMode=false;
|
||||
|
||||
if (softPCM) {
|
||||
chan[5].dacMode=true;
|
||||
chan[6].dacMode=true;
|
||||
}
|
||||
|
||||
// normal sample direction
|
||||
if (dumpWrites) addWrite(0xffff0003,0);
|
||||
|
||||
// LFO
|
||||
immWrite(0x22,lfoValue);
|
||||
|
||||
|
@ -1088,7 +1145,7 @@ bool DivPlatformGenesis::keyOffAffectsPorta(int ch) {
|
|||
}
|
||||
|
||||
void DivPlatformGenesis::notifyInsChange(int ins) {
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i=0; i<10; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
|
@ -1114,6 +1171,10 @@ void DivPlatformGenesis::setYMFM(bool use) {
|
|||
useYMFM=use;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::setSoftPCM(bool value) {
|
||||
softPCM=value;
|
||||
}
|
||||
|
||||
void DivPlatformGenesis::setFlags(unsigned int flags) {
|
||||
switch (flags) {
|
||||
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;
|
||||
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();
|
||||
return 10;
|
||||
}
|
||||
|
|
|
@ -41,10 +41,24 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
|
||||
int vol, outVol;
|
||||
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) {
|
||||
std.init(which);
|
||||
pitch2=0;
|
||||
}
|
||||
bool getDacDirection() {
|
||||
return dacReversed^dacDirection;
|
||||
}
|
||||
Channel():
|
||||
freqH(0),
|
||||
freqL(0),
|
||||
|
@ -65,7 +79,18 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
inPorta(false),
|
||||
hardReset(false),
|
||||
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];
|
||||
DivDispatchOscBuffer* oscBuf[10];
|
||||
|
@ -86,24 +111,21 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
DivYM2612Interface iface;
|
||||
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;
|
||||
|
||||
bool extMode, useYMFM;
|
||||
int softPCMTimer;
|
||||
|
||||
bool extMode, softPCM, useYMFM;
|
||||
bool ladder;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
unsigned char dacVolTable[128];
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
inline void processDAC();
|
||||
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);
|
||||
|
||||
|
@ -126,6 +148,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
void setSoftPCM(bool value);
|
||||
int getPortaFloor(int ch);
|
||||
void poke(unsigned int addr, unsigned short val);
|
||||
void poke(std::vector<DivRegWrite>& wlist);
|
||||
|
|
|
@ -156,16 +156,16 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
case DIV_CMD_SAMPLE_MODE: {
|
||||
// not ignored actually!
|
||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||
dacMode=c.value;
|
||||
chan[5].dacMode=c.value;
|
||||
rWrite(0x2b,c.value<<7);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
if (!parent->song.ignoreDACModeOutsideIntendedChannel) {
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
sampleBank=parent->song.sample.size()/12;
|
||||
chan[5].sampleBank=c.value;
|
||||
if (chan[5].sampleBank>(parent->song.sample.size()/12)) {
|
||||
chan[5].sampleBank=parent->song.sample.size()/12;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -484,7 +484,7 @@ void DivPlatformGenesisExt::forceIns() {
|
|||
chan[i].freqChanged=true;
|
||||
}
|
||||
}
|
||||
if (dacMode) {
|
||||
if (chan[5].dacMode) {
|
||||
rWrite(0x2b,0x80);
|
||||
}
|
||||
immWrite(0x22,lfoValue);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#define WRITE_VOLUME(ch,v) rWrite(0x20+(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_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
||||
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
||||
|
@ -151,13 +152,18 @@ void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len
|
|||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
if (s!=NULL) {
|
||||
if (isMuted[i]) {
|
||||
WRITE_VOLUME(i,0);
|
||||
WRITE_OUTPUT(i,0);
|
||||
chan[i].samplePos++;
|
||||
} 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) {
|
||||
chan[i].sample=-1;
|
||||
if (s->loopStart>=0 && s->loopStart<(int)s->samples) {
|
||||
chan[i].samplePos=s->loopStart;
|
||||
} else {
|
||||
chan[i].sample=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,8 +182,8 @@ void DivPlatformLynx::tick(bool sysTick) {
|
|||
chan[i].outVol=((chan[i].vol&127)*MIN(64,chan[i].std.vol.val))>>6;
|
||||
} else {
|
||||
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].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);
|
||||
WRITE_FEEDBACK(i,0);
|
||||
WRITE_LFSR(i,0);
|
||||
WRITE_OTHER(i,0);
|
||||
WRITE_CONTROL(i,0x18);
|
||||
WRITE_BACKUP(i,2);
|
||||
} else {
|
||||
if (chan[i].lfsr >= 0) {
|
||||
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||
|
@ -300,7 +301,8 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_NOTE_OFF:
|
||||
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);
|
||||
if (chan[c.chan].pcm) {
|
||||
chan[c.chan].pcm=false;
|
||||
|
|
|
@ -23,13 +23,18 @@
|
|||
#include <string.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() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -42,7 +47,28 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
|
|||
if (delay<=0) {
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite& w=writes.front();
|
||||
msm->command_w(w.val);
|
||||
switch (w.addr) {
|
||||
case 0: // command
|
||||
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();
|
||||
delay=32;
|
||||
}
|
||||
|
@ -92,9 +118,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -107,9 +133,9 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
}
|
||||
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
|
||||
chan[c.chan].sample=12*sampleBank+c.value%12;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite((16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
rWrite(0,0x80|chan[c.chan].sample); // set phrase
|
||||
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -117,14 +143,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].macroInit(NULL);
|
||||
break;
|
||||
case DIV_CMD_NOTE_OFF_ENV:
|
||||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
rWrite((8<<c.chan)); // turn off
|
||||
rWrite(0,(8<<c.chan)); // turn off
|
||||
chan[c.chan].std.release();
|
||||
break;
|
||||
case DIV_CMD_ENV_RELEASE:
|
||||
|
@ -153,6 +179,10 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
|
|||
case DIV_CMD_NOTE_PORTA: {
|
||||
return 2;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_FREQ:
|
||||
rateSel=c.value;
|
||||
rWrite(12,!rateSel);
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
if (sampleBank>(parent->song.sample.size()/12)) {
|
||||
|
@ -190,6 +220,7 @@ void DivPlatformMSM6295::forceIns() {
|
|||
for (int i=0; i<4; i++) {
|
||||
chan[i].insChanged=true;
|
||||
}
|
||||
rWrite(12,!rateSel);
|
||||
}
|
||||
|
||||
void* DivPlatformMSM6295::getChanState(int ch) {
|
||||
|
@ -219,6 +250,7 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
|
|||
void DivPlatformMSM6295::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
msm->reset();
|
||||
msm->ss_w(false);
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
}
|
||||
|
@ -232,6 +264,7 @@ void DivPlatformMSM6295::reset() {
|
|||
}
|
||||
|
||||
sampleBank=0;
|
||||
rateSel=false;
|
||||
|
||||
delay=0;
|
||||
}
|
||||
|
@ -240,6 +273,10 @@ bool DivPlatformMSM6295::keyOffAffectsArp(int ch) {
|
|||
return false;
|
||||
}
|
||||
|
||||
float DivPlatformMSM6295::getPostAmp() {
|
||||
return 3.0f;
|
||||
}
|
||||
|
||||
void DivPlatformMSM6295::notifyInsChange(int ins) {
|
||||
for (int i=0; i<4; i++) {
|
||||
if (chan[i].ins==ins) {
|
||||
|
@ -302,12 +339,21 @@ void DivPlatformMSM6295::renderSamples() {
|
|||
}
|
||||
|
||||
void DivPlatformMSM6295::setFlags(unsigned int flags) {
|
||||
if (flags&1) {
|
||||
chipClock=8448000;
|
||||
} else {
|
||||
chipClock=8000000;
|
||||
switch (flags) {
|
||||
case 0:
|
||||
chipClock=4000000/4;
|
||||
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++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]->rate=rate/22;
|
||||
|
|
|
@ -101,6 +101,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
int delay, updateOsc;
|
||||
|
||||
bool extMode;
|
||||
bool rateSel;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
@ -119,6 +120,7 @@ class DivPlatformMSM6295: public DivDispatch {
|
|||
void tick(bool sysTick=true);
|
||||
void muteChannel(int ch, bool mute);
|
||||
bool keyOffAffectsArp(int ch);
|
||||
float getPostAmp();
|
||||
void notifyInsChange(int ins);
|
||||
void notifyInsDeletion(void* ins);
|
||||
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) {
|
||||
DivSample* s=parent->getSample(chan[c.chan].sample);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
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);
|
||||
immWrite(8,0);
|
||||
immWrite(7,0x01); // reset
|
||||
immWrite(9,(s->offB>>2)&0xff);
|
||||
immWrite(10,(s->offB>>10)&0xff);
|
||||
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) {
|
||||
int o=0;
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!writes.empty()) {
|
||||
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);
|
||||
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++) {
|
||||
if (isMuted[i]) {
|
||||
|
|
|
@ -63,6 +63,7 @@ const char* cmdName[]={
|
|||
"SAMPLE_FREQ",
|
||||
"SAMPLE_BANK",
|
||||
"SAMPLE_POS",
|
||||
"SAMPLE_DIR",
|
||||
"SAMPLE_TRANSWAVE_SLICE_MODE", // (enabled)
|
||||
"SAMPLE_TRANSWAVE_SLICE_POS", // (slice)
|
||||
|
||||
|
@ -570,6 +571,9 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
clockDrift=0;
|
||||
subticks=0;
|
||||
break;
|
||||
case 0xdf: // set sample direction
|
||||
dispatchCmd(DivCommand(DIV_CMD_SAMPLE_DIR,i,effectVal));
|
||||
break;
|
||||
case 0xe0: // arp speed
|
||||
if (effectVal>0) {
|
||||
curSubSong->arpLen=effectVal;
|
||||
|
|
|
@ -111,6 +111,9 @@ enum DivSystem {
|
|||
DIV_SYSTEM_NAMCO,
|
||||
DIV_SYSTEM_NAMCO_15XX,
|
||||
DIV_SYSTEM_NAMCO_CUS30,
|
||||
DIV_SYSTEM_YM2612_FRAC,
|
||||
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||
DIV_SYSTEM_RESERVED_8,
|
||||
DIV_SYSTEM_DUMMY,
|
||||
DIV_SYSTEM_MAX // boundary for max system number
|
||||
};
|
||||
|
@ -395,6 +398,10 @@ struct DivSong {
|
|||
bool snDutyReset;
|
||||
bool pitchMacroIsLinear;
|
||||
bool oldOctaveBoundary;
|
||||
bool noOPN2Vol;
|
||||
bool newVolumeScaling;
|
||||
bool volMacroLinger;
|
||||
bool brokenOutVol;
|
||||
|
||||
std::vector<DivInstrument*> ins;
|
||||
std::vector<DivWavetable*> wave;
|
||||
|
@ -488,7 +495,11 @@ struct DivSong {
|
|||
fbPortaPause(false),
|
||||
snDutyReset(false),
|
||||
pitchMacroIsLinear(true),
|
||||
oldOctaveBoundary(false) {
|
||||
oldOctaveBoundary(false),
|
||||
noOPN2Vol(false),
|
||||
newVolumeScaling(true),
|
||||
volMacroLinger(true),
|
||||
brokenOutVol(false) {
|
||||
for (int i=0; i<32; i++) {
|
||||
system[i]=DIV_SYSTEM_NULL;
|
||||
systemVol[i]=64;
|
||||
|
|
|
@ -2027,12 +2027,23 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
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.",
|
||||
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
|
||||
{"CH1", "CH2", "CH3", "CH4"},
|
||||
{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(
|
||||
|
@ -2100,6 +2111,40 @@ void DivEngine::registerSystems() {
|
|||
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(
|
||||
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
|
||||
"this is a system designed for testing purposes.",
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
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 baseAddr2=isSecond?0x80: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:
|
||||
// disable envelope
|
||||
for (int i=0; i<6; i++) {
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x80+i);
|
||||
w->writeC(0x0f);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x88+i);
|
||||
w->writeC(0x0f);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0x90+i);
|
||||
w->writeC(0x0f);
|
||||
}
|
||||
// key off + freq reset
|
||||
for (int i=0; i<9; i++) {
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0xa0+i);
|
||||
w->writeC(0);
|
||||
w->writeC(0x0b|baseAddr1);
|
||||
w->writeC(0x0c|baseAddr1);
|
||||
w->writeC(0xb0+i);
|
||||
w->writeC(0);
|
||||
}
|
||||
|
@ -522,6 +522,15 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(rf5c68Addr);
|
||||
w->writeC(8);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -536,8 +545,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
w->writeC((sample->loopStart==0)); // flags
|
||||
if (sample->loopStart>0) {
|
||||
w->writeC((sample->loopStart==0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
if (sample->loopStart>0 && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=(double)sample->loopEnd;
|
||||
loopSample[streamID]=write.val;
|
||||
}
|
||||
|
@ -554,6 +563,9 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(streamID);
|
||||
loopSample[streamID]=-1;
|
||||
break;
|
||||
case 3: // set sample direction
|
||||
sampleDir[streamID]=write.val;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -818,6 +830,11 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
w->writeC(write.addr&0xff);
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
case DIV_SYSTEM_MSM6295:
|
||||
w->writeC(0xb8);
|
||||
w->writeC(baseAddr2|(write.addr&0x7f));
|
||||
w->writeC(write.val);
|
||||
break;
|
||||
default:
|
||||
logW("write not handled!");
|
||||
break;
|
||||
|
@ -923,11 +940,13 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
double loopTimer[DIV_MAX_CHANS];
|
||||
double loopFreq[DIV_MAX_CHANS];
|
||||
int loopSample[DIV_MAX_CHANS];
|
||||
bool sampleDir[DIV_MAX_CHANS];
|
||||
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
loopTimer[i]=0;
|
||||
loopFreq[i]=0;
|
||||
loopSample[i]=-1;
|
||||
sampleDir[i]=false;
|
||||
}
|
||||
|
||||
bool writeDACSamples=false;
|
||||
|
@ -942,6 +961,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
DivDispatch* writeES5506[2]={NULL,NULL};
|
||||
DivDispatch* writeZ280[2]={NULL,NULL};
|
||||
DivDispatch* writeRF5C68[2]={NULL,NULL};
|
||||
DivDispatch* writeMSM6295[2]={NULL,NULL};
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
willExport[i]=false;
|
||||
|
@ -1348,6 +1368,19 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
writeRF5C68[0]=disCont[i].dispatch;
|
||||
}
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -1694,6 +1727,15 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
w->writeI(0);
|
||||
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
|
||||
|
@ -1829,7 +1871,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
|
|||
for (int i=0; i<song.systemLen; i++) {
|
||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||
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++;
|
||||
}
|
||||
writes.clear();
|
||||
|
|
|
@ -186,7 +186,7 @@ bool DivWaveSynth::tick(bool skipSubDiv) {
|
|||
break;
|
||||
case DIV_WS_PHASE_MOD:
|
||||
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];
|
||||
if (++pos>=width) {
|
||||
pos=0;
|
||||
|
|
|
@ -31,26 +31,42 @@ void FurnaceGUI::drawChannels() {
|
|||
if (!channelsOpen) return;
|
||||
if (ImGui::Begin("Channels",&channelsOpen,globalWinFlags)) {
|
||||
if (ImGui::BeginTable("ChannelList",3)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
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++) {
|
||||
ImGui::PushID(i);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]);
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(i==0);
|
||||
if (ImGui::Button(ICON_FA_CHEVRON_UP)) {
|
||||
e->swapChannelsP(i,i-1);
|
||||
if (ImGui::Button(ICON_FA_ARROWS)) {
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(i==(e->getTotalChannelCount()-1));
|
||||
if (ImGui::Button(ICON_FA_CHEVRON_DOWN)) {
|
||||
e->swapChannelsP(i,i+1);
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
chanToMove=i;
|
||||
ImGui::SetDragDropPayload("FUR_CHAN",NULL,0,ImGuiCond_Once);
|
||||
ImGui::Button(ICON_FA_ARROWS "##ChanDrag");
|
||||
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::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]);
|
||||
|
|
|
@ -213,6 +213,10 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
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;
|
||||
ImGui::End();
|
||||
|
|
|
@ -394,7 +394,7 @@ void FurnaceGUI::drawSampleList() {
|
|||
}
|
||||
|
||||
void FurnaceGUI::actualWaveList() {
|
||||
float wavePreview[256];
|
||||
float wavePreview[257];
|
||||
for (int i=0; i<(int)e->song.wave.size(); i++) {
|
||||
DivWavetable* wave=e->song.wave[i];
|
||||
for (int i=0; i<wave->len; i++) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "gui.h"
|
||||
#include "debug.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include <SDL_timer.h>
|
||||
#include <fmt/printf.h>
|
||||
#include <imgui.h>
|
||||
|
||||
|
@ -373,6 +374,13 @@ void FurnaceGUI::drawDebug() {
|
|||
}
|
||||
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::Button("Sync")) syncSettings();
|
||||
ImGui::SameLine();
|
||||
|
|
|
@ -1233,6 +1233,22 @@ void FurnaceGUI::doAction(int what) {
|
|||
}
|
||||
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:
|
||||
if (curOrder>0) {
|
||||
|
|
|
@ -2368,6 +2368,10 @@ void FurnaceGUI::processPoint(SDL_Event& ev) {
|
|||
point->x=ev.tfinger.x*scrW*dpiScale;
|
||||
point->y=ev.tfinger.y*scrH*dpiScale;
|
||||
point->z=ev.tfinger.pressure;
|
||||
|
||||
if (point->id==0) {
|
||||
ImGui::GetIO().AddMousePosEvent(point->x,point->y);
|
||||
}
|
||||
}
|
||||
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);
|
||||
activePoints.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;
|
||||
}
|
||||
case SDL_FINGERUP: {
|
||||
|
@ -2391,6 +2400,11 @@ void FurnaceGUI::processPoint(SDL_Event& ev) {
|
|||
if (point.id==ev.tfinger.fingerId) {
|
||||
releasedPoints.push_back(point);
|
||||
activePoints.erase(activePoints.begin()+i);
|
||||
|
||||
if (point.id==0) {
|
||||
ImGui::GetIO().AddMouseButtonEvent(ImGuiMouseButton_Left,false);
|
||||
ImGui::GetIO().AddMousePosEvent(-FLT_MAX,-FLT_MAX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2411,6 +2425,7 @@ bool FurnaceGUI::loop() {
|
|||
drawHalt=0;
|
||||
if (settings.powerSave) SDL_WaitEventTimeout(NULL,500);
|
||||
}
|
||||
eventTimeBegin=SDL_GetPerformanceCounter();
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
WAKE_UP;
|
||||
ImGui_ImplSDL2_ProcessEvent(&ev);
|
||||
|
@ -2529,7 +2544,23 @@ bool FurnaceGUI::loop() {
|
|||
break;
|
||||
case SDL_DROPFILE:
|
||||
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;
|
||||
showWarning("Unsaved changes! Save changes before opening file?",GUI_WARN_OPEN_DROP);
|
||||
} else {
|
||||
|
@ -2720,6 +2751,10 @@ bool FurnaceGUI::loop() {
|
|||
midiQueue.pop();
|
||||
midiLock.unlock();
|
||||
}
|
||||
|
||||
eventTimeEnd=SDL_GetPerformanceCounter();
|
||||
|
||||
layoutTimeBegin=SDL_GetPerformanceCounter();
|
||||
|
||||
ImGui_ImplSDLRenderer_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(sdlWin);
|
||||
|
@ -3740,6 +3775,8 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
layoutTimeEnd=SDL_GetPerformanceCounter();
|
||||
|
||||
// backup trigger
|
||||
if (modified) {
|
||||
if (backupTimer>0) {
|
||||
|
@ -3778,10 +3815,16 @@ bool FurnaceGUI::loop() {
|
|||
uiColors[GUI_COLOR_BACKGROUND].z*255,
|
||||
uiColors[GUI_COLOR_BACKGROUND].w*255);
|
||||
SDL_RenderClear(sdlRend);
|
||||
renderTimeBegin=SDL_GetPerformanceCounter();
|
||||
ImGui::Render();
|
||||
renderTimeEnd=SDL_GetPerformanceCounter();
|
||||
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
|
||||
SDL_RenderPresent(sdlRend);
|
||||
|
||||
layoutTimeDelta=layoutTimeEnd-layoutTimeBegin;
|
||||
renderTimeDelta=renderTimeEnd-renderTimeBegin;
|
||||
eventTimeDelta=eventTimeEnd-eventTimeBegin;
|
||||
|
||||
if (--soloTimeout<0) soloTimeout=0;
|
||||
|
||||
wheelX=0;
|
||||
|
@ -3867,6 +3910,16 @@ bool FurnaceGUI::init() {
|
|||
if (orderEditMode<0) orderEditMode=0;
|
||||
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();
|
||||
|
||||
if (settings.dpiScale>=0.5f) {
|
||||
|
@ -3887,8 +3940,11 @@ bool FurnaceGUI::init() {
|
|||
SDL_Rect displaySize;
|
||||
#endif
|
||||
|
||||
SDL_SetHint("SDL_HINT_VIDEO_ALLOW_SCREENSAVER","1");
|
||||
SDL_SetHint("SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH","1");
|
||||
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER,"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);
|
||||
|
||||
|
@ -4064,6 +4120,17 @@ bool FurnaceGUI::finish() {
|
|||
e->setConf("followPattern",followPattern);
|
||||
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++) {
|
||||
delete oldPat[i];
|
||||
}
|
||||
|
@ -4283,6 +4350,16 @@ FurnaceGUI::FurnaceGUI():
|
|||
bindSetPending(false),
|
||||
nextScroll(-1.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),
|
||||
randomizeMin(0),
|
||||
randomizeMax(255),
|
||||
|
|
|
@ -491,6 +491,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_SAMPLE_ZOOM_OUT,
|
||||
GUI_ACTION_SAMPLE_ZOOM_AUTO,
|
||||
GUI_ACTION_SAMPLE_MAKE_INS,
|
||||
GUI_ACTION_SAMPLE_SET_LOOP,
|
||||
GUI_ACTION_SAMPLE_MAX,
|
||||
|
||||
GUI_ACTION_ORDERS_MIN,
|
||||
|
@ -944,6 +945,11 @@ class FurnaceGUI {
|
|||
int noMultiSystem;
|
||||
int oldMacroVSlider;
|
||||
int displayAllInsTypes;
|
||||
int noteCellSpacing;
|
||||
int insCellSpacing;
|
||||
int volCellSpacing;
|
||||
int effectCellSpacing;
|
||||
int effectValCellSpacing;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
@ -1037,6 +1043,11 @@ class FurnaceGUI {
|
|||
noMultiSystem(0),
|
||||
oldMacroVSlider(0),
|
||||
displayAllInsTypes(0),
|
||||
noteCellSpacing(0),
|
||||
insCellSpacing(0),
|
||||
volCellSpacing(0),
|
||||
effectCellSpacing(0),
|
||||
effectValCellSpacing(0),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
@ -1180,10 +1191,17 @@ class FurnaceGUI {
|
|||
|
||||
float nextScroll, nextAddScroll;
|
||||
|
||||
int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta;
|
||||
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||
int eventTimeBegin, eventTimeEnd, eventTimeDelta;
|
||||
|
||||
int chanToMove;
|
||||
|
||||
ImVec2 patWindowPos, patWindowSize;
|
||||
|
||||
// pattern view specific
|
||||
ImVec2 fourChars, threeChars, twoChars;
|
||||
ImVec2 noteCellSize, insCellSize, volCellSize, effectCellSize, effectValCellSize;
|
||||
SelectionPoint sel1, sel2;
|
||||
int dummyRows, demandX;
|
||||
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_MISC, // DF
|
||||
|
||||
// E0-FF extended effects
|
||||
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_AUTO", "Toggle auto-zoom", FURKMOD_CMD|SDLK_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("ORDERS_MIN", "---Orders", NOT_AN_ACTION),
|
||||
|
@ -832,6 +833,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
const int availableSystems[]={
|
||||
DIV_SYSTEM_YM2612,
|
||||
DIV_SYSTEM_YM2612_EXT,
|
||||
DIV_SYSTEM_YM2612_FRAC,
|
||||
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||
DIV_SYSTEM_SMS,
|
||||
DIV_SYSTEM_GB,
|
||||
DIV_SYSTEM_PCE,
|
||||
|
|
|
@ -1868,12 +1868,12 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
op.ar&=maxArDr;
|
||||
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();
|
||||
op.dr&=maxArDr;
|
||||
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) {
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -1886,13 +1886,13 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
op.d2r&=31;
|
||||
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();
|
||||
op.rr&=15;
|
||||
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) {
|
||||
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_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||
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();
|
||||
ImGui::PopStyleColor(3);
|
||||
} else {
|
||||
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 (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_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||
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();
|
||||
ImGui::PopStyleColor(3);
|
||||
} else {
|
||||
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 (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_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||
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();
|
||||
ImGui::PopStyleColor(3);
|
||||
} else {
|
||||
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 (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_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||
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();
|
||||
ImGui::PopStyleColor(3);
|
||||
} else {
|
||||
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 (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_HeaderActive,uiColors[GUI_COLOR_PATTERN_CURSOR_ACTIVE]);
|
||||
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();
|
||||
ImGui::PopStyleColor(3);
|
||||
} else {
|
||||
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 (ImGui::IsItemClicked()) {
|
||||
|
@ -549,7 +549,20 @@ void FurnaceGUI::drawPattern() {
|
|||
threeChars=ImVec2(oneCharSize*3.0f,lineHeight);
|
||||
twoChars=ImVec2(oneCharSize*2.0f,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;
|
||||
|
||||
// オップナー2608 i owe you one more for this horrible code
|
||||
// previous pattern
|
||||
ImGui::BeginDisabled();
|
||||
|
|
|
@ -102,6 +102,18 @@ void FurnaceGUI::initSystemPresets() {
|
|||
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(
|
||||
"Yamaha YM2413 (OPLL)", {
|
||||
DIV_SYSTEM_OPLL, 64, 0, 0,
|
||||
|
@ -132,6 +144,18 @@ void FurnaceGUI::initSystemPresets() {
|
|||
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(
|
||||
"Yamaha YM3526 (OPL)", {
|
||||
DIV_SYSTEM_OPL, 64, 0, 0,
|
||||
|
@ -435,6 +459,20 @@ void FurnaceGUI::initSystemPresets() {
|
|||
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(
|
||||
"Sega Genesis (with Sega CD)", {
|
||||
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))) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1240,6 +1240,35 @@ void FurnaceGUI::drawSettings() {
|
|||
|
||||
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::Button("Import")) {
|
||||
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_AUTO);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_MAKE_INS);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_SAMPLE_SET_LOOP);
|
||||
|
||||
KEYBIND_CONFIG_END;
|
||||
ImGui::TreePop();
|
||||
|
@ -1975,6 +2005,11 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.noMultiSystem=e->getConfInt("noMultiSystem",0);
|
||||
settings.oldMacroVSlider=e->getConfInt("oldMacroVSlider",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.patFontSize,2,96);
|
||||
|
@ -2052,6 +2087,11 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.noMultiSystem,0,1);
|
||||
clampSetting(settings.oldMacroVSlider,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",""));
|
||||
if (settings.initialSys.size()<4) {
|
||||
|
@ -2178,6 +2218,11 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("noMultiSystem",settings.noMultiSystem);
|
||||
e->setConf("oldMacroVSlider",settings.oldMacroVSlider);
|
||||
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
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
|
|
Loading…
Reference in a new issue