mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-22 20:45:11 +00:00
Merge branch 'doc-general' of https://github.com/tildearrow/furnace into doc-general
This commit is contained in:
commit
c4f3930e3c
24 changed files with 274 additions and 60 deletions
|
@ -757,15 +757,11 @@ endif()
|
|||
|
||||
if (WITH_RENDER_DX11)
|
||||
if (WIN32)
|
||||
if (SUPPORT_XP)
|
||||
message(FATAL_ERROR "SUPPORT_XP is on. cannot enable DirectX 11 backend.")
|
||||
else()
|
||||
list(APPEND GUI_SOURCES src/gui/render/renderDX11.cpp)
|
||||
list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_dx11.cpp)
|
||||
list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_DX11)
|
||||
list(APPEND DEPENDENCIES_LIBRARIES d3d11)
|
||||
message(STATUS "UI render backend: DirectX 11")
|
||||
endif()
|
||||
list(APPEND GUI_SOURCES src/gui/render/renderDX11.cpp)
|
||||
list(APPEND GUI_SOURCES extern/imgui_patched/backends/imgui_impl_dx11.cpp)
|
||||
list(APPEND DEPENDENCIES_DEFINES HAVE_RENDER_DX11)
|
||||
list(APPEND DEPENDENCIES_LIBRARIES d3d11)
|
||||
message(STATUS "UI render backend: DirectX 11")
|
||||
else()
|
||||
message(FATAL_ERROR "DirectX 11 render backend only for Windows!")
|
||||
endif()
|
||||
|
|
|
@ -48,8 +48,10 @@ for other operating systems, you may [build the source](#developer-info).
|
|||
- Ricoh RF5C68 used in Sega CD and FM Towns
|
||||
- OKI MSM6258 and MSM6295
|
||||
- Konami K007232
|
||||
- Konami K053260
|
||||
- Irem GA20
|
||||
- Ensoniq ES5506
|
||||
- Namco C140
|
||||
- wavetable chips:
|
||||
- HuC6280 used in PC Engine
|
||||
- Konami Bubble System WSG
|
||||
|
@ -73,6 +75,7 @@ for other operating systems, you may [build the source](#developer-info).
|
|||
- QuadTone engine
|
||||
- Pokémon Mini
|
||||
- Commodore PET
|
||||
- TED used in Commodore Plus/4
|
||||
- Casio PV-1000
|
||||
- TIA used in Atari 2600
|
||||
- POKEY used in Atari 8-bit computers
|
||||
|
@ -124,7 +127,7 @@ for other operating systems, you may [build the source](#developer-info).
|
|||
# quick references
|
||||
|
||||
- **discussion**: see the [Discussions](https://github.com/tildearrow/furnace/discussions) section, the [official Revolt](https://rvlt.gg/GRPS6tmc) or the [official Discord server](https://discord.gg/EfrwT2wq7z).
|
||||
- **help**: check out the [documentation](doc/README.md). it's about 80% complete.
|
||||
- **help**: check out the [documentation](doc/README.md). it's about 90% complete.
|
||||
|
||||
## packages
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ here is a small collection of useful tricks and techniques to really make Furnac
|
|||
|
||||
- [using samples with limited playback rates](limited-samples.md)
|
||||
- [choosing emulation cores](emulation-cores.md)
|
||||
- [guide on using OPLL patch macro](opllswitching.md)
|
||||
- [using OPLL patch macro](opllswitching.md)
|
||||
- [using AY/SAA hardware envelope](envelope.md)
|
||||
|
||||
# links
|
||||
|
||||
- [FM Synthesis of Real Instruments](http://www.javelinart.com/FM_Synthesis_of_Real_Instruments.pdf): an in-depth tutorial on creating FM patches from scratch.
|
||||
- [FM Synthesis of Real Instruments](http://www.javelinart.com/FM_Synthesis_of_Real_Instruments.pdf): an in-depth tutorial on creating FM patches from scratch.
|
27
doc/9-guides/envelope.md
Normal file
27
doc/9-guides/envelope.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# AY-3-8910/8930/SAA1099 envelope guide
|
||||
|
||||
AY-3-8910 programmable sound generator, aside of normal 4-bit volume control, has an hardware volume envelope - a feature that allows you for defining shape of volume envelope at arbibrary speed, according to 8 preset envelope shapes. One may think, what is any upside of hardware envelope? Well, it's somewhat independent of tone/noise generators, and it goes so high in frequency, it can be used melodically! This guide explains how to abuse AY/SAA envelope.
|
||||
|
||||
## AY-3-8910/AY8930
|
||||
|
||||
going into instrument editor, first set the waveform macro value to `envelope`. This will disable any output, but don't worry. Then, go to `Envelope` macro and select `enable`. You will hear a very high-pitched squeak. This is because you must set envelope period - the frequency at which hardware envelope runs. You can do it in two ways:
|
||||
- either via 23xx and 24xx effects (envelope coarse and fine period) or...
|
||||
- 29xx auto-envelope period effect and macros
|
||||
|
||||
Auto-envelope works via numerator and denominator. In general, the higher the numerator, the higher the envelope pitch. The higher the denominator, the lower the envelope pitch. Why there are both of these? Because, envelope generator might be used to mask the tone output (i.e. affect the square wave as well). To do it, set the waveform macro values to both square and envelope. Then, the higher the denominator value, then the lower the envelope pitch relative to the square wave output, analogously the numerator. With square + envelope setting, a lot of wild, detuned, synth instruments can do made.
|
||||
|
||||
Back to the hardware envelope itself. Depending of the `Envelope` macro value, different envelope shapes can be obtained. The most basic one, at 8 is a sawtooth wave. The `direction` value will invert the envelope, producing the reverse sawtooth. The `alternate` value produces an interesting pseudo-triangular wave, similiar to halved sine. That one can also be reversed. `Hold` option disables the envelope.
|
||||
|
||||
WARNING: the envelope pitch resolution is fairly low, at high pitched it will be detuned. Hence, it was used mostly for bass.
|
||||
WARNING: there is only one hardware envelope generator. So, you cant use two pitches/two waveforms at once.
|
||||
|
||||
## SAA1099
|
||||
|
||||
SAA envelope works a bit differently, It doesn't have its own pitch, it reles on a channel 2/5 pitch. It also has much more parameters than AY envelope. To use it: go to waveform macro, and set it to 0 (unless you want to have sqaure wave mask). Then, set up an envelope macro: tuen on enabled, loop and, depending on a desired shape, cut and direction. Resolution will give you higher pitch range than on AY.
|
||||
Then lay two notes in pattern editor: the one in channel 2 will control the envelope pitch, the one in channel 3 can be any note you wish, its just to enable the envelope output.
|
||||
|
||||
## examples
|
||||
|
||||
- [Demoscene-type Beat by Duccinator](https://www.youtube.com/watch?v=qcBgmpPrlUA)
|
||||
- [Philips SAA1099 Test by Duccinator](https://www.youtube.com/watch?v=IBh2gr09zjs)
|
||||
- [Touhou Kaikidan: Mystic Square title theme by ZUN](https://www.youtube.com/watch?v=tUKei7Pz0Fw) /rare instance of AY envelope used for drums, it can be used to mask the noise generator output too
|
2
extern/fmt
vendored
2
extern/fmt
vendored
|
@ -1 +1 @@
|
|||
Subproject commit afbcf1e8eafc5d7f27e29c7397f22521eaa33fac
|
||||
Subproject commit e57ca2e3685b160617d3d95fcd9e789c4e06ca88
|
|
@ -15,7 +15,7 @@ fi
|
|||
cd win32build
|
||||
|
||||
# TODO: potential Arch-ism?
|
||||
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF .. || exit 1
|
||||
i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=ON .. || exit 1
|
||||
make -j8 || exit 1
|
||||
|
||||
cd ..
|
||||
|
|
|
@ -822,9 +822,6 @@ void DivEngine::runExportThread() {
|
|||
size_t curFadeOutSample=0;
|
||||
bool isFadingOut=false;
|
||||
|
||||
quitDispatch();
|
||||
initDispatch(true);
|
||||
|
||||
switch (exportMode) {
|
||||
case DIV_EXPORT_MODE_ONE: {
|
||||
SNDFILE* sf;
|
||||
|
@ -1149,8 +1146,6 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
}
|
||||
|
||||
quitDispatch();
|
||||
initDispatch(false);
|
||||
stopExport=false;
|
||||
}
|
||||
#else
|
||||
|
@ -1158,6 +1153,11 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool DivEngine::shallSwitchCores() {
|
||||
// TODO: detect whether we should
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) {
|
||||
#ifndef HAVE_SNDFILE
|
||||
logE("Furnace was not compiled with libsndfile. cannot export!");
|
||||
|
@ -1187,6 +1187,20 @@ bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode,
|
|||
} else {
|
||||
remainingLoops=-1;
|
||||
}
|
||||
|
||||
if (shallSwitchCores()) {
|
||||
bool isMutedBefore[DIV_MAX_CHANS];
|
||||
memcpy(isMutedBefore,isMuted,DIV_MAX_CHANS*sizeof(bool));
|
||||
quitDispatch();
|
||||
initDispatch(true);
|
||||
renderSamplesP();
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (isMutedBefore[i]) {
|
||||
muteChannel(i,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exportLoopCount=loops;
|
||||
exportThread=new std::thread(_runExportThread,this);
|
||||
return true;
|
||||
|
@ -1202,9 +1216,26 @@ void DivEngine::waitAudioFile() {
|
|||
bool DivEngine::haltAudioFile() {
|
||||
stopExport=true;
|
||||
stop();
|
||||
waitAudioFile();
|
||||
finishAudioFile();
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::finishAudioFile() {
|
||||
if (shallSwitchCores()) {
|
||||
bool isMutedBefore[DIV_MAX_CHANS];
|
||||
memcpy(isMutedBefore,isMuted,DIV_MAX_CHANS*sizeof(bool));
|
||||
quitDispatch();
|
||||
initDispatch(false);
|
||||
renderSamplesP();
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (isMutedBefore[i]) {
|
||||
muteChannel(i,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::notifyInsChange(int ins) {
|
||||
BUSY_BEGIN;
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
|
|
|
@ -497,6 +497,7 @@ class DivEngine {
|
|||
void playSub(bool preserveDrift, int goalRow=0);
|
||||
void runMidiClock(int totalCycles=1);
|
||||
void runMidiTime(int totalCycles=1);
|
||||
bool shallSwitchCores();
|
||||
|
||||
void testFunction();
|
||||
|
||||
|
@ -614,6 +615,8 @@ class DivEngine {
|
|||
void waitAudioFile();
|
||||
// stop audio file export
|
||||
bool haltAudioFile();
|
||||
// return back to playback cores if necessary
|
||||
void finishAudioFile();
|
||||
// notify instrument parameter change
|
||||
void notifyInsChange(int ins);
|
||||
// notify wavetable change
|
||||
|
|
|
@ -449,6 +449,7 @@ void DivPlatformC140::renderSamples(int sysID) {
|
|||
if (memPos+length>=(getSampleMemCapacity())) {
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
|
||||
for (unsigned int i=0; i<(getSampleMemCapacity())-memPos; i++) {
|
||||
if (i>=s->lengthMuLaw) break;
|
||||
unsigned char x=s->dataMuLaw[i]^0xff;
|
||||
if (x&0x80) x^=15;
|
||||
unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4);
|
||||
|
@ -461,6 +462,7 @@ void DivPlatformC140::renderSamples(int sysID) {
|
|||
} else {
|
||||
if (s->depth==DIV_SAMPLE_DEPTH_MULAW) {
|
||||
for (unsigned int i=0; i<length; i++) {
|
||||
if (i>=s->lengthMuLaw) break;
|
||||
unsigned char x=s->dataMuLaw[i]^0xff;
|
||||
if (x&0x80) x^=15;
|
||||
unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4);
|
||||
|
|
|
@ -559,6 +559,17 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
rWrite(0x22,lfoValue);
|
||||
}
|
||||
|
||||
if (opChan[i].std.panL.had) {
|
||||
opChan[i].pan=opChan[i].std.panL.val&3;
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int j=0; j<4; j++) {
|
||||
if (i==j) continue;
|
||||
opChan[j].pan=opChan[i].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
// param macros
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]];
|
||||
|
|
|
@ -229,7 +229,7 @@ void DivPlatformPCMDAC::acquire(short** buf, size_t len) {
|
|||
} else {
|
||||
output=output*chan[0].vol*chan[0].envVol/16384;
|
||||
}
|
||||
oscBuf->data[oscBuf->needle++]=output>>1;
|
||||
oscBuf->data[oscBuf->needle++]=((output>>depthScale)<<depthScale)>>1;
|
||||
if (outStereo) {
|
||||
buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<<depthScale;
|
||||
buf[1][h]=((output*chan[0].panR)>>(depthScale+8))<<depthScale;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
MODIFIED Namco C140 sound emulator - MODIFIED VERSION
|
||||
by cam900
|
||||
|
||||
MODIFICATION by tildearrow - adds muting function
|
||||
MODIFICATION by tildearrow - adds muting function and fixes overflow
|
||||
THIS IS NOT THE ORIGINAL VERSION - you can find the original one in
|
||||
commit 72d04777c013988ed8cf6da27c62a9d784a59dff
|
||||
|
||||
|
@ -99,8 +99,8 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle
|
|||
s1 = c140->mulaw[(s1 >> 8) & 0xff];
|
||||
s2 = c140->mulaw[(s2 >> 8) & 0xff];
|
||||
}
|
||||
// interpolate
|
||||
signed int sample = s1 + (((voice->frac) * (s2 - s1)) >> 16);
|
||||
// interpolate (originally was >>16, but I had to reduce it to 15 to prevent overflow)
|
||||
signed int sample = s1 + (((voice->frac >> 1) * (s2 - s1)) >> 15);
|
||||
voice->lout = sample * voice->lvol;
|
||||
voice->rout = sample * voice->rvol;
|
||||
}
|
||||
|
|
|
@ -508,6 +508,17 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
|
|||
rWrite(0x22,lfoValue);
|
||||
}
|
||||
|
||||
if (opChan[i].std.panL.had) {
|
||||
opChan[i].pan=opChan[i].std.panL.val&3;
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int j=0; j<4; j++) {
|
||||
if (i==j) continue;
|
||||
opChan[j].pan=opChan[i].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
|
||||
// param macros
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]];
|
||||
|
|
|
@ -504,6 +504,17 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
|||
rWrite(0x22,lfoValue);
|
||||
}
|
||||
|
||||
if (opChan[i].std.panL.had) {
|
||||
opChan[i].pan=opChan[i].std.panL.val&3;
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int j=0; j<4; j++) {
|
||||
if (i==j) continue;
|
||||
opChan[j].pan=opChan[i].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
// param macros
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]];
|
||||
|
|
|
@ -504,6 +504,17 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
|||
rWrite(0x22,lfoValue);
|
||||
}
|
||||
|
||||
if (opChan[i].std.panL.had) {
|
||||
opChan[i].pan=opChan[i].std.panL.val&3;
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int j=0; j<4; j++) {
|
||||
if (i==j) continue;
|
||||
opChan[j].pan=opChan[i].pan;
|
||||
}
|
||||
}
|
||||
rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
|
||||
}
|
||||
|
||||
// param macros
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]];
|
||||
|
|
|
@ -449,7 +449,12 @@ void DivEngine::registerSystems() {
|
|||
{0x30, {DIV_CMD_FM_HARD_RESET, "30xx: Toggle hard envelope reset on new notes"}},
|
||||
};
|
||||
|
||||
EffectHandlerMap fmOPN2EffectHandlerMap(fmEffectHandlerMap);
|
||||
EffectHandlerMap fmExtChEffectHandlerMap(fmEffectHandlerMap);
|
||||
fmExtChEffectHandlerMap.insert({
|
||||
{0x18, {DIV_CMD_FM_EXTCH, "18xx: Toggle extended channel 3 mode"}},
|
||||
});
|
||||
|
||||
EffectHandlerMap fmOPN2EffectHandlerMap(fmExtChEffectHandlerMap);
|
||||
fmOPN2EffectHandlerMap.insert({
|
||||
{0x17, {DIV_CMD_SAMPLE_MODE, "17xx: Toggle PCM mode (LEGACY)"}},
|
||||
{0xdf, {DIV_CMD_SAMPLE_DIR, "DFxx: Set sample playback direction (0: normal; 1: reverse)"}},
|
||||
|
@ -522,7 +527,6 @@ void DivEngine::registerSystems() {
|
|||
|
||||
fmOPNPostEffectHandlerMap.insert({
|
||||
{0x10, {DIV_CMD_FM_LFO, "10xy: Setup LFO (x: enable; y: speed)"}},
|
||||
{0x18, {DIV_CMD_FM_EXTCH, "18xx: Toggle extended channel 3 mode"}},
|
||||
{0x55, {DIV_CMD_FM_SSG, "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)", effectOpVal<4>, effectValAnd<15>}},
|
||||
});
|
||||
EffectHandlerMap fmOPN2PostEffectHandlerMap(fmOPNPostEffectHandlerMap);
|
||||
|
@ -769,7 +773,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, 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_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA},
|
||||
{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_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1028,7 +1032,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY},
|
||||
{},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1040,7 +1044,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY},
|
||||
{},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1064,7 +1068,7 @@ void DivEngine::registerSystems() {
|
|||
{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_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, 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_NULL, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1076,7 +1080,7 @@ void DivEngine::registerSystems() {
|
|||
{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_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, 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_NULL, DIV_INS_NULL, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1368,7 +1372,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, 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_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1380,7 +1384,7 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, 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_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1457,7 +1461,7 @@ void DivEngine::registerSystems() {
|
|||
{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_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, 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_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
@ -1469,7 +1473,7 @@ void DivEngine::registerSystems() {
|
|||
{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_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, 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_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB},
|
||||
{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_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||
fmEffectHandlerMap,
|
||||
fmExtChEffectHandlerMap,
|
||||
fmOPNAPostEffectHandlerMap
|
||||
);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ void _nfdThread(const NFDState state, std::atomic<bool>* ok, std::vector<String>
|
|||
(*errorOutput)=true;
|
||||
break;
|
||||
default:
|
||||
logE("NFD unknown return code %d!\n",ret);
|
||||
logE("NFD unknown return code %d!\n",(int)ret);
|
||||
break;
|
||||
}
|
||||
(*ok)=true;
|
||||
|
|
|
@ -20,8 +20,12 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include "gui.h"
|
||||
#include "../../extern/opn/ym3438.h"
|
||||
#include "../../extern/opm/opm.h"
|
||||
#include "../../extern/opl/opl3.h"
|
||||
#include "../../extern/Nuked-OPLL/opll.h"
|
||||
#include "../engine/platform/sound/ymfm/ymfm_opz.h"
|
||||
|
||||
#define FM_WRITE(addr,val) \
|
||||
#define OPN_WRITE(addr,val) \
|
||||
OPN2_Write((ym3438_t*)fmPreviewOPN,0,(addr)); \
|
||||
do { \
|
||||
OPN2_Clock((ym3438_t*)fmPreviewOPN,out); \
|
||||
|
@ -35,7 +39,7 @@ const unsigned char dtTableFMP[8]={
|
|||
7,6,5,0,1,2,3,4
|
||||
};
|
||||
|
||||
void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) {
|
||||
void FurnaceGUI::renderFMPreviewOPN(const DivInstrumentFM& params, int pos) {
|
||||
if (fmPreviewOPN==NULL) {
|
||||
fmPreviewOPN=new ym3438_t;
|
||||
}
|
||||
|
@ -57,19 +61,19 @@ void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) {
|
|||
for (int i=0; i<4; i++) {
|
||||
const DivInstrumentFM::Operator& op=params.op[i];
|
||||
unsigned short baseAddr=i*4;
|
||||
FM_WRITE(baseAddr+0x40,op.tl);
|
||||
FM_WRITE(baseAddr+0x30,(op.mult&15)|(dtTableFMP[op.dt&7]<<4));
|
||||
FM_WRITE(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
FM_WRITE(baseAddr+0x60,(op.dr&31)|(op.am<<7));
|
||||
FM_WRITE(baseAddr+0x70,op.d2r&31);
|
||||
FM_WRITE(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
|
||||
FM_WRITE(baseAddr+0x90,op.ssgEnv&15);
|
||||
OPN_WRITE(baseAddr+0x40,op.tl);
|
||||
OPN_WRITE(baseAddr+0x30,(op.mult&15)|(dtTableFMP[op.dt&7]<<4));
|
||||
OPN_WRITE(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
OPN_WRITE(baseAddr+0x60,(op.dr&31)|(op.am<<7));
|
||||
OPN_WRITE(baseAddr+0x70,op.d2r&31);
|
||||
OPN_WRITE(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
|
||||
OPN_WRITE(baseAddr+0x90,op.ssgEnv&15);
|
||||
}
|
||||
FM_WRITE(0xb0,(params.alg&7)|((params.fb&7)<<3));
|
||||
FM_WRITE(0xb4,0xc0|(params.fms&7)|((params.ams&3)<<4));
|
||||
FM_WRITE(0xa4,mult0?0x1c:0x14); // frequency
|
||||
FM_WRITE(0xa0,0);
|
||||
FM_WRITE(0x28,0xf0); // key on
|
||||
OPN_WRITE(0xb0,(params.alg&7)|((params.fb&7)<<3));
|
||||
OPN_WRITE(0xb4,0xc0|(params.fms&7)|((params.ams&3)<<4));
|
||||
OPN_WRITE(0xa4,mult0?0x1c:0x14); // frequency
|
||||
OPN_WRITE(0xa0,0);
|
||||
OPN_WRITE(0x28,0xf0); // key on
|
||||
}
|
||||
|
||||
// render
|
||||
|
@ -84,3 +88,37 @@ void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) {
|
|||
fmPreview[i]=aOut;
|
||||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::renderFMPreviewOPM(const DivInstrumentFM& params, int pos) {
|
||||
}
|
||||
|
||||
void FurnaceGUI::renderFMPreviewOPLL(const DivInstrumentFM& params, int pos) {
|
||||
}
|
||||
|
||||
void FurnaceGUI::renderFMPreviewOPL(const DivInstrumentFM& params, int pos) {
|
||||
}
|
||||
|
||||
void FurnaceGUI::renderFMPreviewOPZ(const DivInstrumentFM& params, int pos) {
|
||||
}
|
||||
|
||||
void FurnaceGUI::renderFMPreview(const DivInstrument* ins, int pos) {
|
||||
switch (ins->type) {
|
||||
case DIV_INS_FM:
|
||||
renderFMPreviewOPN(ins->fm,pos);
|
||||
break;
|
||||
case DIV_INS_OPM:
|
||||
renderFMPreviewOPM(ins->fm,pos);
|
||||
break;
|
||||
case DIV_INS_OPLL:
|
||||
renderFMPreviewOPLL(ins->fm,pos);
|
||||
break;
|
||||
case DIV_INS_OPL:
|
||||
renderFMPreviewOPL(ins->fm,pos);
|
||||
break;
|
||||
case DIV_INS_OPZ:
|
||||
renderFMPreviewOPZ(ins->fm,pos);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5262,6 +5262,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
}
|
||||
if (!e->isExporting()) {
|
||||
e->finishAudioFile();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
|
@ -6872,6 +6873,10 @@ FurnaceGUI::FurnaceGUI():
|
|||
fmPreviewOn(false),
|
||||
fmPreviewPaused(false),
|
||||
fmPreviewOPN(NULL),
|
||||
fmPreviewOPM(NULL),
|
||||
fmPreviewOPL(NULL),
|
||||
fmPreviewOPLL(NULL),
|
||||
fmPreviewOPZ(NULL),
|
||||
editString(NULL),
|
||||
pendingRawSampleDepth(8),
|
||||
pendingRawSampleChannels(1),
|
||||
|
|
|
@ -1349,6 +1349,10 @@ class FurnaceGUI {
|
|||
short fmPreview[FM_PREVIEW_SIZE];
|
||||
bool updateFMPreview, fmPreviewOn, fmPreviewPaused;
|
||||
void* fmPreviewOPN;
|
||||
void* fmPreviewOPM;
|
||||
void* fmPreviewOPL;
|
||||
void* fmPreviewOPLL;
|
||||
void* fmPreviewOPZ;
|
||||
String* editString;
|
||||
|
||||
String pendingRawSample;
|
||||
|
@ -2137,7 +2141,12 @@ class FurnaceGUI {
|
|||
bool drawSysConf(int chan, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu=false);
|
||||
void kvsConfig(DivInstrument* ins);
|
||||
void drawFMPreview(const ImVec2& size);
|
||||
void renderFMPreview(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreview(const DivInstrument* ins, int pos=0);
|
||||
void renderFMPreviewOPN(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreviewOPM(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreviewOPLL(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreviewOPL(const DivInstrumentFM& params, int pos=0);
|
||||
void renderFMPreviewOPZ(const DivInstrumentFM& params, int pos=0);
|
||||
|
||||
// these ones offer ctrl-wheel fine value changes.
|
||||
bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0);
|
||||
|
|
|
@ -1284,7 +1284,7 @@ inline bool enBit30(const int val) {
|
|||
|
||||
|
||||
void FurnaceGUI::kvsConfig(DivInstrument* ins) {
|
||||
if (ins->type==DIV_INS_FM && fmPreviewOn) {
|
||||
if (fmPreviewOn) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("left click to restart\nmiddle click to pause\nright click to see algorithm");
|
||||
}
|
||||
|
@ -1299,10 +1299,10 @@ void FurnaceGUI::kvsConfig(DivInstrument* ins) {
|
|||
ImGui::SetTooltip("left click to configure TL scaling\nright click to see FM preview");
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right) && ins->type==DIV_INS_FM) {
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
fmPreviewOn=!fmPreviewOn;
|
||||
}
|
||||
if (!fmPreviewOn || ins->type!=DIV_INS_FM) {
|
||||
if (!fmPreviewOn) {
|
||||
int opCount=4;
|
||||
if (ins->type==DIV_INS_OPLL) opCount=2;
|
||||
if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2;
|
||||
|
@ -1568,6 +1568,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Bottom");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1590,6 +1591,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Attack");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1609,6 +1611,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Hold");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1628,6 +1631,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Decay");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1650,6 +1654,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Release");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1671,6 +1676,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Bottom");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1693,6 +1699,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Speed");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -1711,6 +1718,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail
|
|||
} rightClickable
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("Shape");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
@ -2281,7 +2289,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
} else {
|
||||
DivInstrument* ins=e->song.ins[curIns];
|
||||
if (updateFMPreview) {
|
||||
renderFMPreview(ins->fm);
|
||||
renderFMPreview(ins);
|
||||
updateFMPreview=false;
|
||||
}
|
||||
if (settings.insEditColorize) {
|
||||
|
@ -2469,10 +2477,10 @@ void FurnaceGUI::drawInsEdit() {
|
|||
P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
if (ins->type==DIV_INS_FM && fmPreviewOn) {
|
||||
if (fmPreviewOn) {
|
||||
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
if (!fmPreviewPaused) {
|
||||
renderFMPreview(ins->fm,1);
|
||||
renderFMPreview(ins,1);
|
||||
WAKE_UP;
|
||||
}
|
||||
} else {
|
||||
|
@ -2490,7 +2498,15 @@ void FurnaceGUI::drawInsEdit() {
|
|||
P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable
|
||||
P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable
|
||||
ImGui::TableNextColumn();
|
||||
drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
if (fmPreviewOn) {
|
||||
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
if (!fmPreviewPaused) {
|
||||
renderFMPreview(ins,1);
|
||||
WAKE_UP;
|
||||
}
|
||||
} else {
|
||||
drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
}
|
||||
kvsConfig(ins);
|
||||
|
||||
if (ImGui::Button("Request from TX81Z")) {
|
||||
|
@ -2524,7 +2540,15 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
if (fmPreviewOn) {
|
||||
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
if (!fmPreviewPaused) {
|
||||
renderFMPreview(ins,1);
|
||||
WAKE_UP;
|
||||
}
|
||||
} else {
|
||||
drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
|
||||
}
|
||||
kvsConfig(ins);
|
||||
break;
|
||||
}
|
||||
|
@ -2549,7 +2573,15 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::TableNextColumn();
|
||||
drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale));
|
||||
if (fmPreviewOn) {
|
||||
drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale));
|
||||
if (!fmPreviewPaused) {
|
||||
renderFMPreview(ins,1);
|
||||
WAKE_UP;
|
||||
}
|
||||
} else {
|
||||
drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale));
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
||||
|
|
|
@ -293,6 +293,9 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
if (sample->samples>131070) {
|
||||
SAMPLE_WARN(warnLength,"Amiga: maximum sample length is 131070");
|
||||
}
|
||||
if (dispatch!=NULL) {
|
||||
MAX_RATE("Amiga",31250.0);
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_SEGAPCM:
|
||||
case DIV_SYSTEM_SEGAPCM_COMPAT:
|
||||
|
|
|
@ -1093,7 +1093,7 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
MARK_MODIFIED;
|
||||
});
|
||||
}
|
||||
if (ImGui::Button("Invert",buttonSize)) {
|
||||
if (ImGui::Button("Invert",buttonSizeHalf)) {
|
||||
e->lockEngine([this,wave]() {
|
||||
for (int i=0; i<wave->len; i++) {
|
||||
wave->data[i]=wave->max-wave->data[i];
|
||||
|
@ -1101,6 +1101,18 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
MARK_MODIFIED;
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Reverse",buttonSizeHalf)) {
|
||||
e->lockEngine([this,wave]() {
|
||||
int origData[256];
|
||||
memcpy(origData,wave->data,wave->len*sizeof(int));
|
||||
|
||||
for (int i=0; i<wave->len; i++) {
|
||||
wave->data[i]=origData[wave->len-1-i];
|
||||
}
|
||||
MARK_MODIFIED;
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::Button("Half",buttonSizeHalf)) {
|
||||
int origData[256];
|
||||
|
|
|
@ -97,7 +97,11 @@ int writeLog(int level, const char* msg, fmt::printf_args args) {
|
|||
time_t thisMakesNoSense=time(NULL);
|
||||
int pos=(logPosition.fetch_add(1))&TA_LOG_MASK;
|
||||
|
||||
#if FMT_VERSION >= 100100
|
||||
logEntries[pos].text.assign(fmt::vsprintf(fmt::basic_string_view<char>(msg),args));
|
||||
#else
|
||||
logEntries[pos].text.assign(fmt::vsprintf(msg,args));
|
||||
#endif
|
||||
// why do I have to pass a pointer
|
||||
// can't I just pass the time_t directly?!
|
||||
#ifdef _WIN32
|
||||
|
|
Loading…
Reference in a new issue