Merge branch 'tildearrow:master' into master
This commit is contained in:
commit
2b6c70a4e3
|
@ -60,6 +60,11 @@ if (APPLE)
|
|||
else()
|
||||
set(WITH_RENDER_OPENGL_DEFAULT ON)
|
||||
endif()
|
||||
if (WIN32)
|
||||
set(WITH_RENDER_DX11_DEFAULT ON)
|
||||
else()
|
||||
set(WITH_RENDER_DX11_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
set(USE_GLES_DEFAULT ON)
|
||||
|
@ -75,6 +80,7 @@ option(USE_BACKWARD "Use backward-cpp to print a backtrace on crash/abort." ${US
|
|||
option(WITH_JACK "Whether to build with JACK support. Auto-detects if JACK is available" ${WITH_JACK_DEFAULT})
|
||||
option(WITH_RENDER_SDL "Whether to build with the SDL_Renderer render backend." ${WITH_RENDER_SDL_DEFAULT})
|
||||
option(WITH_RENDER_OPENGL "Whether to build with the OpenGL render backend." ${WITH_RENDER_OPENGL_DEFAULT})
|
||||
option(WITH_RENDER_DX11 "Whether to build with the DirectX 11 render backend." ${WITH_RENDER_DX11_DEFAULT})
|
||||
option(USE_GLES "Use OpenGL ES for the OpenGL render backend." ${USE_GLES_DEFAULT})
|
||||
option(SYSTEM_FFTW "Use a system-installed version of FFTW instead of the vendored one" OFF)
|
||||
option(SYSTEM_FMT "Use a system-installed version of fmt instead of the vendored one" OFF)
|
||||
|
@ -302,7 +308,7 @@ else()
|
|||
endif()
|
||||
|
||||
if (BUILD_GUI)
|
||||
if (NOT WITH_RENDER_SDL AND NOT WITH_RENDER_OPENGL)
|
||||
if (NOT WITH_RENDER_SDL AND NOT WITH_RENDER_OPENGL AND NOT WITH_RENDER_DX11)
|
||||
message(FATAL_ERROR "No render backends selected!")
|
||||
endif()
|
||||
endif()
|
||||
|
@ -731,6 +737,22 @@ if (WITH_RENDER_OPENGL)
|
|||
message(STATUS "UI render backend: OpenGL")
|
||||
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()
|
||||
else()
|
||||
message(FATAL_ERROR "DirectX 11 render backend only for Windows!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
CHECK_INCLUDE_FILE(sys/io.h SYS_IO_FOUND)
|
||||
CHECK_INCLUDE_FILE(linux/input.h LINUX_INPUT_FOUND)
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -6,7 +6,11 @@ Furnace's wavetable editor is rather simple, you can draw the waveform using mou
|
|||
|
||||
Furnace's wavetable editor features multiple ways of creating desired waveform shape:
|
||||
|
||||
- Shape tab allows you to select a few predefined basic shapes and indirectly edit it via "Duty", "Exponent" and "XOR Point" sliders TODO: what the last two are doing? What is amplitude/phase for?)
|
||||
- Shape tab allows you to select a few predefined basic shapes and indirectly edit it via "Duty", "Exponent" and "XOR Point" sliders:
|
||||
- `Duty` slider affects mainly pulse waves, determining its wisth, like on C64/VRC6
|
||||
- `Exponent` powers the waveform in the mathematical sense of the word (^2, ^3 and so on)
|
||||
- `XOR Point` determines the point where the waveform gets negated.
|
||||
- TODO: amplitude/phase part
|
||||
- FM is for creating the waveform with frequency modulation synthesis principles: One can set carrier/modulation levels, frquency multiplier, connection between operators and FM waveforms of these operators.
|
||||
- WaveTools allows user to fine-tune the waveform: scale said waveform in both X and Y axes, smoothen, amplify, normalize, convert to signed/unisgned, invert or even randomize the wavetable.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# samples
|
||||
|
||||
In the context of Furnace, a sound sample (usually just referred to as a sample) is a string of numbers that hold sampled PCM audio.
|
||||
In the context of Furnace, a sound sample (usually just referred to as a sample) is a string of numbers that represent sampled PCM audio.
|
||||
|
||||
In Furnace, these samples can be generated by importing a .wav (think of it as an higher quality MP3) file.
|
||||
|
||||
|
@ -13,6 +13,7 @@ as of Furnace 0.6, the following sound chips have sample support:
|
|||
- PC Engine/TurboGrafx-16/HuC6280
|
||||
- Amiga/Paula
|
||||
- SegaPCM
|
||||
- NEC PC-9801/YM2608 (ADPCM channel only)
|
||||
- Neo Geo/Neo Geo CD/YM2610 (ADPCM channels only)
|
||||
- Seta/Allumer X1-010
|
||||
- Atari Lynx
|
||||
|
@ -21,12 +22,16 @@ as of Furnace 0.6, the following sound chips have sample support:
|
|||
- QSound
|
||||
- ZX Spectrum 48k (1-bit)
|
||||
- RF5C68
|
||||
- WonderSwan
|
||||
- SNES/S-DSP
|
||||
- WonderSwan (second channel only)
|
||||
- tildearrow Sound Unit
|
||||
- VERA (last channel only)
|
||||
- Y8950 (last channel only)
|
||||
- Konami K007232
|
||||
- a few more that I've forgotten to mention
|
||||
- Irem GA20
|
||||
- Ensoniq OTTO/ES5506
|
||||
- Yamaha PCMD8/YMZ280B
|
||||
- MMC5 (last channel only)
|
||||
|
||||
## compatible sample mode
|
||||
|
||||
|
@ -45,9 +50,9 @@ due to limitations in some of those sound chips, some restrictions exist:
|
|||
- NES: if on DPCM mode, only a limited selection of frequencies is available, and loop position isn't supported (only entire sample).
|
||||
- SegaPCM: your sample can't be longer than 65535, and the maximum frequency is 31.25KHz.
|
||||
- QSound: your sample can't be longer than 65535, and the loop length shall not be greater than 32767.
|
||||
- Neo Geo (ADPCM-A): no looping supported. your samples will play at ~18.5KHz.
|
||||
- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is ~55KHz.
|
||||
- YM2608: the maximum frequency is ~55KHz.
|
||||
- Neo Geo (ADPCM-A): no looping supported. your samples will play at 18.518KHz.
|
||||
- Neo Geo (ADPCM-B): no loop position supported (only entire sample), and the maximum frequency is 55.555KHz.
|
||||
- YM2608: the maximum frequency is 55.555KHz.
|
||||
- MSM6258/MSM6295: no arbitrary frequency.
|
||||
- ZX Spectrum Beeper: your sample can't be longer than 2048, and it always plays at ~55KHz.
|
||||
- Seta/Allumer X1-010: frequency resolution is terrible in the lower end. your sample can't be longer than 131072.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
a series of FM sound chips which were very popular in DOS land. it was so popular that even Yamaha made a logo for it!
|
||||
|
||||
essentially a downgraded version of Yamaha's other FM chips, with only 2 operators per channel.
|
||||
however, it also had a drums mode, and later chips in the series added more waveforms (than just the typical sine) and even a 4-operator mode.
|
||||
however, it also had a [drums mode](opll.md), and later chips in the series added more waveforms (than just the typical sine) and even a 4-operator mode.
|
||||
|
||||
the original OPL (Yamaha YM3526) was present as an expansion for the Commodore 64 and MSX computers (erm, a variant of it). it only had 9 two-operator channels and drums mode.
|
||||
|
||||
|
@ -77,4 +77,4 @@ afterwards everyone moved to Windows and software mixed PCM streaming...
|
|||
- only in 4-op mode (OPL3).
|
||||
- `5Bxy`: set KSR of operator.
|
||||
- `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators".
|
||||
- `y` determines whether KSR is on.
|
||||
- `y` determines whether KSR is on.
|
||||
|
|
|
@ -12,7 +12,11 @@ OPLL also spawned a few derivative chips, the best known of these is:
|
|||
the YM2413 is equipped with the following features:
|
||||
|
||||
- 9 channels of 2 operator FM synthesis
|
||||
- A drum/percussion mode, replacing the last 3 voices with 5 rhythm channels
|
||||
- A drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. Only pitch might be altered.
|
||||
|
||||
- Drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mxier twice for 2x volume, like all drum sounds. FM channel 8 splits to Snare Drum and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave.
|
||||
- Special syntheis mentioned already is: 5 square waves are gathered from 4x, 64x and 128x the pitch of channel 8 and 16x and 64x the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd.
|
||||
|
||||
- 1 user-definable patch (this patch can be changed throughout the course of the song)
|
||||
- 15 pre-defined patches which can all be used at the same time
|
||||
- Support for ADSR on both the modulator and the carrier
|
||||
|
@ -60,4 +64,4 @@ the YM2413 is equipped with the following features:
|
|||
- `58xx`: set DR of operator 2.
|
||||
- `5Bxy`: set KSR of operator.
|
||||
- `x` is the operator (1-2). a value of 0 means "all operators".
|
||||
- `y` determines whether KSR is on.
|
||||
- `y` determines whether KSR is on.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Yamaha YM2612
|
||||
|
||||
one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player.
|
||||
one of two chips that powered the Sega Genesis. It is a six-channel, four-operator FM synthesizer. Channel #6 can be turned into 8-bit PCM player, that via software mixing, thanks to Z80 sound CPU, can play more than one channel of straight-shot samples at once. As of Furnace 0.6pre5, Furnace offers DualPCM, which allows 2 channels of software-mixed 8-bit PCM samples at 13750 Hz.
|
||||
|
||||
# effects
|
||||
|
||||
|
|
|
@ -316,27 +316,27 @@ void CSAADevice::_TickAndOutputStereo(unsigned int& left_mixed, unsigned int& ri
|
|||
m_Noise0.Tick();
|
||||
m_Noise1.Tick();
|
||||
m_Amp0.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp1.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp2.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp3.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp4.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
m_Amp5.TickAndOutputStereo(temp_left, temp_right);
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=(temp_left+temp_right)<<4;
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=(temp_left+temp_right)<<3;
|
||||
accum_left += temp_left;
|
||||
accum_right += temp_right;
|
||||
}
|
||||
|
@ -394,4 +394,4 @@ void CSAADevice::_TickAndOutputSeparate(unsigned int& left_mixed, unsigned int&
|
|||
}
|
||||
left_mixed = accum_left;
|
||||
right_mixed = accum_right;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,9 +2,6 @@
|
|||
|
||||
// uncomment and modify defines under for customize ImGuiFileDialog
|
||||
|
||||
//this options need c++17
|
||||
//#define USE_STD_FILESYSTEM
|
||||
|
||||
//#define MAX_FILE_DIALOG_NAME_BUFFER 1024
|
||||
//#define MAX_PATH_BUFFER_SIZE 1024
|
||||
|
||||
|
|
|
@ -32,16 +32,16 @@
|
|||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2016-05-07: DirectX11: Disabling depth-write.
|
||||
|
||||
// DISCLAIMER: modified with d3dcompiler patch (see https://github.com/ocornut/imgui/pull/638).
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
|
||||
// DirectX
|
||||
#include <stdio.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
|
||||
#endif
|
||||
|
||||
typedef HRESULT (__stdcall *D3DCompile_t)(LPCVOID, SIZE_T, LPCSTR, D3D_SHADER_MACRO*, ID3DInclude*, LPCSTR, LPCSTR, UINT, UINT, ID3DBlob**, ID3DBlob*);
|
||||
|
||||
// DirectX11 data
|
||||
struct ImGui_ImplDX11_Data
|
||||
|
@ -380,11 +380,22 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
|
|||
if (bd->pFontSampler)
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
|
||||
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
|
||||
// If you would like to use this DX11 sample code but remove this dependency you can:
|
||||
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
|
||||
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
|
||||
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
|
||||
// Detect which d3dcompiler_XX.dll is present in the system and grab a pointer to D3DCompile.
|
||||
// Without this, you must link d3dcompiler.lib with the project.
|
||||
D3DCompile_t D3DCompile = NULL;
|
||||
{
|
||||
char dllBuffer[20];
|
||||
for (int i = 47; i > 30 && !D3DCompile; i--)
|
||||
{
|
||||
sprintf(dllBuffer, "d3dcompiler_%d.dll", i);
|
||||
HMODULE hDll = LoadLibraryA(dllBuffer);
|
||||
if (hDll)
|
||||
D3DCompile = (D3DCompile_t)GetProcAddress(hDll, "D3DCompile");
|
||||
}
|
||||
if (!D3DCompile)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the vertex shader
|
||||
{
|
||||
|
|
|
@ -1444,9 +1444,6 @@ void DivEngine::initSongWithDesc(const char* description, bool inBase64, bool ol
|
|||
|
||||
// extra attributes
|
||||
song.subsong[0]->hz=c.getDouble("tickRate",60.0);
|
||||
if (song.subsong[0]->hz!=60.0) {
|
||||
song.subsong[0]->customTempo=true;
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::createNew(const char* description, String sysName, bool inBase64) {
|
||||
|
@ -2696,16 +2693,7 @@ void DivEngine::reset() {
|
|||
elapsedBars=0;
|
||||
elapsedBeats=0;
|
||||
nextSpeed=speeds.val[0];
|
||||
divider=60;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
} else {
|
||||
if (curSubSong->pal) {
|
||||
divider=60;
|
||||
} else {
|
||||
divider=50;
|
||||
}
|
||||
}
|
||||
divider=curSubSong->hz;
|
||||
globalPitch=0;
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
disCont[i].dispatch->reset();
|
||||
|
@ -2920,14 +2908,7 @@ const DivGroovePattern& DivEngine::getSpeeds() {
|
|||
}
|
||||
|
||||
float DivEngine::getHz() {
|
||||
if (curSubSong->customTempo) {
|
||||
return curSubSong->hz;
|
||||
} else if (curSubSong->pal) {
|
||||
return 60.0;
|
||||
} else {
|
||||
return 50.0;
|
||||
}
|
||||
return 60.0;
|
||||
return curSubSong->hz;
|
||||
}
|
||||
|
||||
float DivEngine::getCurHz() {
|
||||
|
@ -4354,23 +4335,11 @@ void DivEngine::updateSysFlags(int system, bool restart) {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::setSongRate(float hz, bool pal) {
|
||||
void DivEngine::setSongRate(float hz) {
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
curSubSong->pal=!pal;
|
||||
curSubSong->hz=hz;
|
||||
// what?
|
||||
curSubSong->customTempo=true;
|
||||
divider=60;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
} else {
|
||||
if (curSubSong->pal) {
|
||||
divider=60;
|
||||
} else {
|
||||
divider=50;
|
||||
}
|
||||
}
|
||||
divider=curSubSong->hz;
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
|
|
@ -954,7 +954,7 @@ class DivEngine {
|
|||
void updateSysFlags(int system, bool restart);
|
||||
|
||||
// set Hz
|
||||
void setSongRate(float hz, bool pal);
|
||||
void setSongRate(float hz);
|
||||
|
||||
// set remaining loops. -1 means loop forever.
|
||||
void setLoops(int loops);
|
||||
|
|
|
@ -220,20 +220,22 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->hilightB=reader.readC();
|
||||
}
|
||||
|
||||
bool customTempo=false;
|
||||
|
||||
ds.subsong[0]->timeBase=reader.readC();
|
||||
ds.subsong[0]->speeds.len=2;
|
||||
ds.subsong[0]->speeds.val[0]=reader.readC();
|
||||
if (ds.version>0x07) {
|
||||
ds.subsong[0]->speeds.val[1]=reader.readC();
|
||||
ds.subsong[0]->pal=reader.readC();
|
||||
ds.subsong[0]->hz=(ds.subsong[0]->pal)?60:50;
|
||||
ds.subsong[0]->customTempo=reader.readC();
|
||||
bool pal=reader.readC();
|
||||
ds.subsong[0]->hz=pal?60:50;
|
||||
customTempo=reader.readC();
|
||||
} else {
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
}
|
||||
if (ds.version>0x0a) {
|
||||
String hz=reader.readString(3);
|
||||
if (ds.subsong[0]->customTempo) {
|
||||
if (customTempo) {
|
||||
try {
|
||||
ds.subsong[0]->hz=std::stoi(hz);
|
||||
} catch (std::exception& e) {
|
||||
|
@ -304,7 +306,6 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->hz=248;
|
||||
break;
|
||||
}
|
||||
ds.subsong[0]->customTempo=true;
|
||||
ds.subsong[0]->timeBase=0;
|
||||
addWarning("Yamaha YMU759 emulation is incomplete! please migrate your song to the OPL3 system.");
|
||||
}
|
||||
|
@ -1864,8 +1865,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
subSong->customTempo=true;
|
||||
|
||||
subSong->patLen=reader.readS();
|
||||
subSong->ordersLen=reader.readS();
|
||||
|
@ -2489,8 +2488,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
subSong->speeds.val[1]=reader.readC();
|
||||
subSong->arpLen=reader.readC();
|
||||
subSong->hz=reader.readF();
|
||||
subSong->pal=(subSong->hz>=53);
|
||||
subSong->customTempo=true;
|
||||
|
||||
subSong->patLen=reader.readS();
|
||||
subSong->ordersLen=reader.readS();
|
||||
|
@ -3322,9 +3319,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->pat[ch].effectCols=fxCols;
|
||||
}
|
||||
|
||||
ds.subsong[0]->pal=false;
|
||||
ds.subsong[0]->hz=50;
|
||||
ds.subsong[0]->customTempo=false;
|
||||
ds.systemLen=(chCount+3)/4;
|
||||
for(int i=0; i<ds.systemLen; i++) {
|
||||
ds.system[i]=DIV_SYSTEM_AMIGA;
|
||||
|
@ -3547,7 +3542,6 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) {
|
|||
|
||||
ds.subsong[0]->speeds.val[0]=(unsigned char)reader.readC();
|
||||
ds.subsong[0]->hz=((double)reader.readC())/2.5;
|
||||
ds.subsong[0]->customTempo=true;
|
||||
|
||||
unsigned char masterVol=reader.readC();
|
||||
|
||||
|
@ -3993,8 +3987,6 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) {
|
|||
ds.subsong[0]->ordersLen=seqLen;
|
||||
ds.subsong[0]->patLen=32;
|
||||
ds.subsong[0]->hz=50;
|
||||
ds.subsong[0]->pal=true;
|
||||
ds.subsong[0]->customTempo=true;
|
||||
ds.subsong[0]->pat[3].effectCols=3;
|
||||
ds.subsong[0]->speeds.val[0]=3;
|
||||
ds.subsong[0]->speeds.len=1;
|
||||
|
@ -5819,12 +5811,14 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
|||
w->writeString(song.author,true);
|
||||
w->writeC(curSubSong->hilightA);
|
||||
w->writeC(curSubSong->hilightB);
|
||||
|
||||
int intHz=curSubSong->hz;
|
||||
|
||||
w->writeC(curSubSong->timeBase);
|
||||
w->writeC(curSubSong->speeds.val[0]);
|
||||
w->writeC((curSubSong->speeds.len>=2)?curSubSong->speeds.val[1]:curSubSong->speeds.val[0]);
|
||||
w->writeC(curSubSong->pal);
|
||||
w->writeC(curSubSong->customTempo);
|
||||
w->writeC((intHz<=53)?1:0);
|
||||
w->writeC((intHz!=60 && intHz!=50));
|
||||
char customHz[4];
|
||||
memset(customHz,0,4);
|
||||
snprintf(customHz,4,"%d",(int)curSubSong->hz);
|
||||
|
|
|
@ -168,7 +168,7 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) {
|
|||
outL+=(output*sep2)>>7;
|
||||
outR+=(output*sep1)>>7;
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<2;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]))<<1;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,8 @@ void DivPlatformArcade::acquire_nuked(short** buf, size_t len) {
|
|||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i];
|
||||
int chOut=(int16_t)fm.ch_out[i];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767);
|
||||
}
|
||||
|
||||
if (o[0]<-32768) o[0]=-32768;
|
||||
|
@ -111,7 +112,8 @@ void DivPlatformArcade::acquire_ymfm(short** buf, size_t len) {
|
|||
fm_ymfm->generate(&out_ymfm);
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1));
|
||||
int chOut=fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut,-32768,32767);
|
||||
}
|
||||
|
||||
os[0]=out_ymfm.data[0];
|
||||
|
|
|
@ -187,9 +187,9 @@ void DivPlatformAY8910::acquire(short** buf, size_t len) {
|
|||
buf[0][i]=ayBuf[0][0];
|
||||
buf[1][i]=buf[0][i];
|
||||
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=sunsoftVolTable[31-(ay->lastIndx&31)]<<3;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=CLAMP(sunsoftVolTable[31-(ay->lastIndx&31)]<<3,-32768,32767);
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=CLAMP(sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3,-32768,32767);
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767);
|
||||
}
|
||||
} else {
|
||||
for (size_t i=0; i<len; i++) {
|
||||
|
|
|
@ -32,7 +32,7 @@ void DivPlatformDummy::acquire(short** buf, size_t len) {
|
|||
if (chan[j].active) {
|
||||
if (!isMuted[j]) {
|
||||
chanOut=(((signed short)chan[j].pos)*chan[j].amp*chan[j].vol)>>12;
|
||||
oscBuf[j]->data[oscBuf[j]->needle++]=chanOut;
|
||||
oscBuf[j]->data[oscBuf[j]->needle++]=chanOut<<1;
|
||||
out+=chanOut;
|
||||
} else {
|
||||
oscBuf[j]->data[oscBuf[j]->needle++]=0;
|
||||
|
|
|
@ -168,7 +168,7 @@ void DivPlatformES5506::acquire(short** buf, size_t len) {
|
|||
buf[(o<<1)|1][h]=es5506.rout(o);
|
||||
}
|
||||
for (int i=chanMax; i>=0; i--) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>5;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ void DivPlatformFDS::acquire_puNES(short* buf, size_t len) {
|
|||
buf[i]=sample;
|
||||
if (++writeOscBuf>=32) {
|
||||
writeOscBuf=0;
|
||||
oscBuf->data[oscBuf->needle++]=sample<<1;
|
||||
oscBuf->data[oscBuf->needle++]=sample*3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ void DivPlatformFDS::acquire_NSFPlay(short* buf, size_t len) {
|
|||
buf[i]=sample;
|
||||
if (++writeOscBuf>=32) {
|
||||
writeOscBuf=0;
|
||||
oscBuf->data[oscBuf->needle++]=sample<<1;
|
||||
oscBuf->data[oscBuf->needle++]=sample*3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,11 +71,16 @@ void DivPlatformGA20::acquire(short** buf, size_t len) {
|
|||
delay=w.delay;
|
||||
}
|
||||
}
|
||||
short *buffer[4] = {&ga20Buf[0][h],&ga20Buf[1][h],&ga20Buf[2][h],&ga20Buf[3][h]};
|
||||
ga20.sound_stream_update(buffer, 1);
|
||||
short *buffer[4]={
|
||||
&ga20Buf[0][h],
|
||||
&ga20Buf[1][h],
|
||||
&ga20Buf[2][h],
|
||||
&ga20Buf[3][h]
|
||||
};
|
||||
ga20.sound_stream_update(buffer,1);
|
||||
buf[0][h]=(signed int)(ga20Buf[0][h]+ga20Buf[1][h]+ga20Buf[2][h]+ga20Buf[3][h])>>2;
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ga20Buf[i][h];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ga20Buf[i][h]>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -184,16 +184,18 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
|
|||
if (i==5) {
|
||||
if (fm.dacen) {
|
||||
if (softPCM) {
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.dacdata<<7;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fm.dacdata^0x100)<<6;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=0;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?2:7),-32768,32767);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?1:6),-32768,32767);
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=0;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?2:7),-32768,32767);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fm.ch_out[i]<<(chipType==2?1:6),-32768,32767);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,19 +243,21 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
|||
//OPN2_Write(&fm,0,0);
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<6;
|
||||
int chOut=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1))<<5;
|
||||
if (chOut<-32768) chOut=-32768;
|
||||
if (chOut>32767) chOut=32767;
|
||||
if (i==5) {
|
||||
if (fm_ymfm->debug_dac_enable()) {
|
||||
if (softPCM) {
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<7;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<7;
|
||||
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_ymfm->debug_dac_data()<<7;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fm_ymfm->debug_dac_data()^0x100)<<6;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=0;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
|
||||
oscBuf[6]->data[oscBuf[6]->needle++]=0;
|
||||
}
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=chOut;
|
||||
|
|
|
@ -79,14 +79,14 @@ void DivPlatformK007232::acquire(short** buf, size_t len) {
|
|||
buf[0][h]=(lout[0]+lout[1])<<4;
|
||||
buf[1][h]=(rout[0]+rout[1])<<4;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<4;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<3;
|
||||
}
|
||||
} else {
|
||||
const unsigned char vol=regPool[0xc];
|
||||
const signed int out[2]={(k007232.output(0)*(vol&0xf)),(k007232.output(1)*((vol>>4)&0xf))};
|
||||
buf[0][h]=(out[0]+out[1])<<4;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<5;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,9 +85,9 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
|
|||
|
||||
if (++writeOscBuf>=32) {
|
||||
writeOscBuf=0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:((mmc5->S3.output*10)<<7);
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:((mmc5->S4.output*10)<<7);
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:((mmc5->pcm.output*2)<<6);
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=isMuted[0]?0:((mmc5->S3.output)<<11);
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=isMuted[1]?0:((mmc5->S4.output)<<11);
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=isMuted[2]?0:((mmc5->pcm.output)<<7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ void DivPlatformMSM5232::acquire(short** buf, size_t len) {
|
|||
((regPool[12+(i>>4)]&2)?((msm->vo8[i]*partVolume[2+(i&4)])>>8):0)+
|
||||
((regPool[12+(i>>4)]&4)?((msm->vo4[i]*partVolume[1+(i&4)])>>8):0)+
|
||||
((regPool[12+(i>>4)]&8)?((msm->vo2[i]*partVolume[i&4])>>8):0)
|
||||
)<<3;
|
||||
)<<2;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(o,-32768,32767);
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void DivPlatformMSM6258::acquire(short** buf, size_t len) {
|
|||
} else {
|
||||
buf[0][h]=(msmPan&2)?msmOut:0;
|
||||
buf[1][h]=(msmPan&1)?msmOut:0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?msmOut:0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=msmPan?(msmOut>>1):0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,9 +79,8 @@ void DivPlatformMSM6295::acquire(short** buf, size_t len) {
|
|||
|
||||
if (++updateOsc>=22) {
|
||||
updateOsc=0;
|
||||
// TODO: per-channel osc
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=msm.voice_out(i)<<6;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=msm.voice_out(i)<<5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ void DivPlatformNamcoWSG::acquire(short** buf, size_t len) {
|
|||
};
|
||||
namco->sound_stream_update(bufC,1);
|
||||
for (int i=0; i<chans; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=namco->m_channel_list[i].last_out*chans;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(namco->m_channel_list[i].last_out*chans)>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) {
|
|||
oscBuf[0]->data[oscBuf[0]->needle++]=nes1_NP->out[0]<<11;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=nes1_NP->out[1]<<11;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=nes2_NP->out[0]<<11;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=nes2_NP->out[1]<<11;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=nes2_NP->out[1]<<12;
|
||||
oscBuf[4]->data[oscBuf[4]->needle++]=nes2_NP->out[2]<<8;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
if (!isMuted[adpcmChan]) {
|
||||
os[0]-=aOut.data[0]>>3;
|
||||
os[1]-=aOut.data[0]>>3;
|
||||
oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=aOut.data[0];
|
||||
oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=aOut.data[0]>>1;
|
||||
} else {
|
||||
oscBuf[adpcmChan]->data[oscBuf[adpcmChan]->needle++]=0;
|
||||
}
|
||||
|
@ -220,47 +220,45 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
if (fm.rhy&0x20) {
|
||||
for (int i=0; i<melodicChans+1; i++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
int chOut=0;
|
||||
if (ch==255) continue;
|
||||
oscBuf[i]->data[oscBuf[i]->needle]=0;
|
||||
if (fm.channel[i].out[0]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0];
|
||||
chOut+=*fm.channel[ch].out[0];
|
||||
}
|
||||
if (fm.channel[i].out[1]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1];
|
||||
chOut+=*fm.channel[ch].out[1];
|
||||
}
|
||||
if (fm.channel[i].out[2]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2];
|
||||
chOut+=*fm.channel[ch].out[2];
|
||||
}
|
||||
if (fm.channel[i].out[3]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3];
|
||||
chOut+=*fm.channel[ch].out[3];
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle]<<=1;
|
||||
oscBuf[i]->needle++;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<(i==melodicChans?1:2),-32768,32767);
|
||||
}
|
||||
// special
|
||||
oscBuf[melodicChans+1]->data[oscBuf[melodicChans+1]->needle++]=fm.slot[16].out*6;
|
||||
oscBuf[melodicChans+2]->data[oscBuf[melodicChans+2]->needle++]=fm.slot[14].out*6;
|
||||
oscBuf[melodicChans+3]->data[oscBuf[melodicChans+3]->needle++]=fm.slot[17].out*6;
|
||||
oscBuf[melodicChans+4]->data[oscBuf[melodicChans+4]->needle++]=fm.slot[13].out*6;
|
||||
oscBuf[melodicChans+1]->data[oscBuf[melodicChans+1]->needle++]=fm.slot[16].out*4;
|
||||
oscBuf[melodicChans+2]->data[oscBuf[melodicChans+2]->needle++]=fm.slot[14].out*4;
|
||||
oscBuf[melodicChans+3]->data[oscBuf[melodicChans+3]->needle++]=fm.slot[17].out*4;
|
||||
oscBuf[melodicChans+4]->data[oscBuf[melodicChans+4]->needle++]=fm.slot[13].out*4;
|
||||
} else {
|
||||
for (int i=0; i<chans; i++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
int chOut=0;
|
||||
if (ch==255) continue;
|
||||
oscBuf[i]->data[oscBuf[i]->needle]=0;
|
||||
if (fm.channel[i].out[0]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0];
|
||||
chOut+=*fm.channel[ch].out[0];
|
||||
}
|
||||
if (fm.channel[i].out[1]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1];
|
||||
chOut+=*fm.channel[ch].out[1];
|
||||
}
|
||||
if (fm.channel[i].out[2]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2];
|
||||
chOut+=*fm.channel[ch].out[2];
|
||||
}
|
||||
if (fm.channel[i].out[3]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3];
|
||||
chOut+=*fm.channel[ch].out[3];
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle]<<=1;
|
||||
oscBuf[i]->needle++;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<2,-32768,32767);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,16 @@ void DivPlatformOPLL::tick(bool sysTick) {
|
|||
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LOG_BROKEN(chan[i].vol,MIN(15,chan[i].std.vol.val),15);
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
|
||||
if (i>=6 && properDrums) {
|
||||
drumVol[i-6]=15-chan[i].outVol;
|
||||
rWrite(0x36,drumVol[0]);
|
||||
rWrite(0x37,drumVol[1]|(drumVol[4]<<4));
|
||||
rWrite(0x38,drumVol[3]|(drumVol[2]<<4));
|
||||
} else if (i<6 || !drums) {
|
||||
if (i<9) {
|
||||
rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ void DivPlatformPCE::acquire(short** buf, size_t len) {
|
|||
pce->ResetTS(0);
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP((pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1])<<1,-32768,32767);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1],-32768,32767);
|
||||
}
|
||||
|
||||
tempL[0]=(tempL[0]>>1)+(tempL[0]>>2);
|
||||
|
|
|
@ -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;
|
||||
oscBuf->data[oscBuf->needle++]=output>>1;
|
||||
if (outStereo) {
|
||||
buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<<depthScale;
|
||||
buf[1][h]=((output*chan[0].panR)>>(depthScale+8))<<depthScale;
|
||||
|
|
|
@ -85,10 +85,10 @@ void DivPlatformPOKEY::acquireMZ(short* buf, size_t len) {
|
|||
|
||||
if (++oscBufDelay>=14) {
|
||||
oscBufDelay=0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=pokey.outvol_0<<11;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=pokey.outvol_1<<11;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=pokey.outvol_2<<11;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=pokey.outvol_3<<11;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=pokey.outvol_0<<10;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=pokey.outvol_1<<10;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=pokey.outvol_2<<10;
|
||||
oscBuf[3]->data[oscBuf[3]->needle++]=pokey.outvol_3<<10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ void DivPlatformPV1000::acquire(short** buf, size_t len) {
|
|||
short samp=d65010g031_sound_tick(&d65010g031,1);
|
||||
buf[0][h]=samp;
|
||||
for (int i=0; i<3; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(d65010g031.out[i]);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=d65010g031.out[i]<<1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,7 +272,7 @@ void DivPlatformQSound::acquire(short** buf, size_t len) {
|
|||
buf[1][h]=chip.out[1];
|
||||
|
||||
for (int i=0; i<19; i++) {
|
||||
int data=chip.voice_output[i]<<2;
|
||||
int data=chip.voice_output[i]<<1;
|
||||
if (data<-32768) data=-32768;
|
||||
if (data>32767) data=32767;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=data;
|
||||
|
|
|
@ -74,7 +74,7 @@ void DivPlatformRF5C68::acquire(short** buf, size_t len) {
|
|||
rf5c68.sound_stream_update(bufPtrs,chBufPtrs,blockLen);
|
||||
for (int i=0; i<8; i++) {
|
||||
for (size_t j=0; j<blockLen; j++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=bufC[i*2][j]+bufC[i*2+1][j];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(bufC[i*2][j]+bufC[i*2+1][j])>>1;
|
||||
}
|
||||
}
|
||||
pos+=blockLen;
|
||||
|
|
|
@ -49,7 +49,7 @@ void DivPlatformSegaPCM::acquire(short** buf, size_t len) {
|
|||
buf[1][h]=os[1];
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=pcm.lastOut[i][0]+pcm.lastOut[i][1];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(pcm.lastOut[i][0]+pcm.lastOut[i][1])>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,9 +58,9 @@ void DivPlatformSM8521::acquire(short** buf, size_t len) {
|
|||
sm8521_sound_tick(&sm8521,8);
|
||||
buf[0][h]=sm8521.out<<6;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=sm8521.sg[i].base.out<<6;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=sm8521.sg[i].base.out<<7;
|
||||
}
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=sm8521.noise.base.out<<6;
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=sm8521.noise.base.out<<7;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ void DivPlatformSNES::acquire(short** buf, size_t len) {
|
|||
next=(next*254)/MAX(1,globalVolL+globalVolR);
|
||||
if (next<-32768) next=-32768;
|
||||
if (next>32767) next=32767;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=next;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=next>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ static constexpr int MuteInit = 2;
|
|||
static constexpr int MuteSerialInput = 8;
|
||||
//just some magick value to match the audio level of mzpokeysnd
|
||||
static constexpr int16_t MAGICK_VOLUME_BOOSTER = 160;
|
||||
static constexpr int16_t MAGICK_OSC_VOLUME_BOOSTER = 4;
|
||||
static constexpr int16_t MAGICK_OSC_VOLUME_BOOSTER = 6;
|
||||
|
||||
struct PokeyBase
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ void DivPlatformT6W28::acquire(short** buf, size_t len) {
|
|||
tempL=0;
|
||||
tempR=0;
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(out[i][1].curValue+out[i][2].curValue)<<6;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(out[i][1].curValue+out[i][2].curValue)<<7;
|
||||
tempL+=out[i][1].curValue<<7;
|
||||
tempR+=out[i][2].curValue<<7;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ void DivPlatformTX81Z::acquire(short** buf, size_t len) {
|
|||
fm_ymfm->generate(&out_ymfm);
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1));
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1),-32768,32767);
|
||||
}
|
||||
|
||||
os[0]=out_ymfm.data[0];
|
||||
|
|
|
@ -107,9 +107,9 @@ void DivPlatformVERA::acquire(short** buf, size_t len) {
|
|||
pos++;
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=psg->channels[i].lastOut<<4;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=psg->channels[i].lastOut<<3;
|
||||
}
|
||||
int pcmOut=whyCallItBuf[2][i]+whyCallItBuf[3][i];
|
||||
int pcmOut=(whyCallItBuf[2][i]+whyCallItBuf[3][i])>>1;
|
||||
if (pcmOut<-32768) pcmOut=-32768;
|
||||
if (pcmOut>32767) pcmOut=32767;
|
||||
oscBuf[16]->data[oscBuf[16]->needle++]=pcmOut;
|
||||
|
|
|
@ -87,7 +87,7 @@ void DivPlatformVRC6::acquire(short** buf, size_t len) {
|
|||
if (++writeOscBuf>=32) {
|
||||
writeOscBuf=0;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.pulse_out(i)<<10;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=vrc6.pulse_out(i)<<11;
|
||||
}
|
||||
oscBuf[2]->data[oscBuf[2]->needle++]=vrc6.sawtooth_out()<<10;
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ void DivPlatformX1_010::acquire(short** buf, size_t len) {
|
|||
if (stereo) buf[1][h]=tempR;
|
||||
|
||||
for (int i=0; i<16; i++) {
|
||||
int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<3;
|
||||
int vo=(x1_010.voice_out(i,0)+x1_010.voice_out(i,1))<<2;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(vo,-32768,32767);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,11 +231,11 @@ void DivPlatformYM2203::acquire_combo(short** buf, size_t len) {
|
|||
buf[0][h]=os;
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1;
|
||||
}
|
||||
|
||||
for (int i=3; i<6; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -282,11 +282,11 @@ void DivPlatformYM2203::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1;
|
||||
}
|
||||
|
||||
for (int i=3; i<6; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fmout.data[i-2]>>1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -402,19 +402,19 @@ void DivPlatformYM2608::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1;
|
||||
}
|
||||
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,19 +471,19 @@ void DivPlatformYM2608::acquire_ymfm(short** buf, size_t len) {
|
|||
buf[1][h]=os[1];
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=6; i<9; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-6]>>1;
|
||||
}
|
||||
|
||||
for (int i=9; i<15; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[15]->data[oscBuf[15]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -333,19 +333,19 @@ void DivPlatformYM2610::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[bchOffs[i]]>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1;
|
||||
}
|
||||
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,19 +404,19 @@ void DivPlatformYM2610::acquire_ymfm(short** buf, size_t len) {
|
|||
buf[1][h]=os[1];
|
||||
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1;
|
||||
}
|
||||
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -401,19 +401,19 @@ void DivPlatformYM2610B::acquire_combo(short** buf, size_t len) {
|
|||
|
||||
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm_nuked.ch_out[i]>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1;
|
||||
}
|
||||
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,19 +471,19 @@ void DivPlatformYM2610B::acquire_ymfm(short** buf, size_t len) {
|
|||
|
||||
|
||||
for (int i=0; i<psgChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1));
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1))>>1;
|
||||
}
|
||||
|
||||
ssge->get_last_out(ssgOut);
|
||||
for (int i=psgChanOffs; i<adpcmAChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs];
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=ssgOut.data[i-psgChanOffs]>>1;
|
||||
}
|
||||
|
||||
for (int i=adpcmAChanOffs; i<adpcmBChanOffs; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1);
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=(adpcmAChan[i-adpcmAChanOffs]->get_last_out(0)+adpcmAChan[i-adpcmAChanOffs]->get_last_out(1))>>1;
|
||||
}
|
||||
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=abe->get_last_out(0)+abe->get_last_out(1);
|
||||
oscBuf[adpcmBChanOffs]->data[oscBuf[adpcmBChanOffs]->needle++]=(abe->get_last_out(0)+abe->get_last_out(1))>>1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ void DivPlatformYMZ280B::acquire(short** buf, size_t len) {
|
|||
for (int j=0; j<8; j++) {
|
||||
dataL+=why[j*2][i];
|
||||
dataR+=why[j*2+1][i];
|
||||
oscBuf[j]->data[oscBuf[j]->needle++]=(short)(((int)why[j*2][i]+why[j*2+1][i])/2);
|
||||
oscBuf[j]->data[oscBuf[j]->needle++]=(short)(((int)why[j*2][i]+why[j*2+1][i])/4);
|
||||
}
|
||||
buf[0][pos]=(short)(dataL/8);
|
||||
buf[1][pos]=(short)(dataR/8);
|
||||
|
|
|
@ -153,8 +153,6 @@ struct DivSubSong {
|
|||
unsigned char timeBase, arpLen;
|
||||
DivGroovePattern speeds;
|
||||
short virtualTempoN, virtualTempoD;
|
||||
bool pal;
|
||||
bool customTempo;
|
||||
float hz;
|
||||
int patLen, ordersLen;
|
||||
|
||||
|
@ -177,8 +175,6 @@ struct DivSubSong {
|
|||
arpLen(1),
|
||||
virtualTempoN(150),
|
||||
virtualTempoD(150),
|
||||
pal(true),
|
||||
customTempo(false),
|
||||
hz(60.0),
|
||||
patLen(64),
|
||||
ordersLen(1) {
|
||||
|
|
|
@ -124,6 +124,7 @@ const char* aboutLine[]={
|
|||
"Ultraprogramer",
|
||||
"UserSniper",
|
||||
"Weeppiko",
|
||||
"Xan",
|
||||
"Yuzu4K",
|
||||
"Zaxolotl",
|
||||
"ZoomTen (Zumi)",
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "../ta-log.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
|
||||
#define FURNACE_FFT_SIZE 4096
|
||||
#define FURNACE_FFT_RATE 80.0
|
||||
|
@ -93,7 +94,7 @@ void FurnaceGUI::calcChanOsc() {
|
|||
unsigned short needlePos=buf->needle;
|
||||
needlePos-=displaySize;
|
||||
for (unsigned short i=0; i<512; i++) {
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/32768.0f;
|
||||
if (minLevel>y) minLevel=y;
|
||||
if (maxLevel<y) maxLevel=y;
|
||||
}
|
||||
|
@ -284,152 +285,266 @@ void FurnaceGUI::drawChanOsc() {
|
|||
ImGui::ColorPicker4("Color",(float*)&chanOscColor);
|
||||
}
|
||||
|
||||
ImGui::Text("Text format:");
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##TextFormat",&chanOscTextFormat);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (ImGui::BeginTooltip()) {
|
||||
ImGui::TextUnformatted(
|
||||
"format guide:\n"
|
||||
"- %c: channel name\n"
|
||||
"- %C: channel short name\n"
|
||||
"- %d: channel number (starting from 0)\n"
|
||||
"- %D: channel number (starting from 1)\n"
|
||||
"- %i: instrument name\n"
|
||||
"- %I: instrument number (decimal)\n"
|
||||
"- %x: instrument number (hex)\n"
|
||||
"- %s: chip name\n"
|
||||
"- %S: chip ID\n"
|
||||
"- %v: volume (decimal)\n"
|
||||
"- %V: volume (percentage)\n"
|
||||
"- %b: volume (hex)\n"
|
||||
"- %%: percent sign"
|
||||
);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::ColorEdit4("Text color",(float*)&chanOscTextColor);
|
||||
|
||||
if (ImGui::Button("OK")) {
|
||||
chanOscOptions=false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f));
|
||||
float availY=ImGui::GetContentRegionAvail().y;
|
||||
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) {
|
||||
std::vector<DivDispatchOscBuffer*> oscBufs;
|
||||
std::vector<ChanOscStatus*> oscFFTs;
|
||||
std::vector<int> oscChans;
|
||||
int chans=e->getTotalChannelCount();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
ImVec2 waveform[512];
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f));
|
||||
float availY=ImGui::GetContentRegionAvail().y;
|
||||
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) {
|
||||
std::vector<DivDispatchOscBuffer*> oscBufs;
|
||||
std::vector<ChanOscStatus*> oscFFTs;
|
||||
std::vector<int> oscChans;
|
||||
int chans=e->getTotalChannelCount();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
ImVec2 waveform[512];
|
||||
ImGuiStyle& style=ImGui::GetStyle();
|
||||
|
||||
ImGuiStyle& style=ImGui::GetStyle();
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
||||
if (buf!=NULL && e->curSubSong->chanShow[i]) {
|
||||
oscBufs.push_back(buf);
|
||||
oscFFTs.push_back(&chanOscChan[i]);
|
||||
oscChans.push_back(i);
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
||||
if (buf!=NULL && e->curSubSong->chanShow[i]) {
|
||||
oscBufs.push_back(buf);
|
||||
oscFFTs.push_back(&chanOscChan[i]);
|
||||
oscChans.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols;
|
||||
int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols;
|
||||
|
||||
for (size_t i=0; i<oscBufs.size(); i++) {
|
||||
if (i%chanOscCols==0) ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
for (size_t i=0; i<oscBufs.size(); i++) {
|
||||
if (i%chanOscCols==0) ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
DivDispatchOscBuffer* buf=oscBufs[i];
|
||||
ChanOscStatus* fft=oscFFTs[i];
|
||||
int ch=oscChans[i];
|
||||
if (buf==NULL) {
|
||||
ImGui::Text("Error!");
|
||||
} else {
|
||||
ImVec2 size=ImGui::GetContentRegionAvail();
|
||||
size.y=availY/rows;
|
||||
DivDispatchOscBuffer* buf=oscBufs[i];
|
||||
ChanOscStatus* fft=oscFFTs[i];
|
||||
int ch=oscChans[i];
|
||||
if (buf==NULL) {
|
||||
ImGui::Text("Error!");
|
||||
} else {
|
||||
ImVec2 size=ImGui::GetContentRegionAvail();
|
||||
size.y=availY/rows;
|
||||
|
||||
if (centerSettingReset) {
|
||||
buf->readNeedle=buf->needle;
|
||||
}
|
||||
if (centerSettingReset) {
|
||||
buf->readNeedle=buf->needle;
|
||||
}
|
||||
|
||||
// check FFT status existence
|
||||
if (fft->plan==NULL) {
|
||||
logD("creating FFT plan for channel %d",ch);
|
||||
fft->inBuf=(double*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(double));
|
||||
fft->outBuf=(fftw_complex*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(fftw_complex));
|
||||
fft->plan=fftw_plan_dft_r2c_1d(FURNACE_FFT_SIZE,fft->inBuf,fft->outBuf,FFTW_ESTIMATE);
|
||||
}
|
||||
// check FFT status existence
|
||||
if (fft->plan==NULL) {
|
||||
logD("creating FFT plan for channel %d",ch);
|
||||
fft->inBuf=(double*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(double));
|
||||
fft->outBuf=(fftw_complex*)fftw_malloc(FURNACE_FFT_SIZE*sizeof(fftw_complex));
|
||||
fft->plan=fftw_plan_dft_r2c_1d(FURNACE_FFT_SIZE,fft->inBuf,fft->outBuf,FFTW_ESTIMATE);
|
||||
}
|
||||
|
||||
int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f);
|
||||
int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f);
|
||||
|
||||
ImVec2 minArea=window->DC.CursorPos;
|
||||
ImVec2 maxArea=ImVec2(
|
||||
minArea.x+size.x,
|
||||
minArea.y+size.y
|
||||
);
|
||||
ImRect rect=ImRect(minArea,maxArea);
|
||||
ImRect inRect=rect;
|
||||
inRect.Min.x+=dpiScale;
|
||||
inRect.Min.y+=dpiScale;
|
||||
inRect.Max.x-=dpiScale;
|
||||
inRect.Max.y-=dpiScale;
|
||||
ImGui::ItemSize(size,style.FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("chOscDisplay"))) {
|
||||
if (!e->isRunning()) {
|
||||
for (unsigned short i=0; i<512; i++) {
|
||||
float x=(float)i/512.0f;
|
||||
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f));
|
||||
}
|
||||
} else {
|
||||
float minLevel=1.0f;
|
||||
float maxLevel=-1.0f;
|
||||
float dcOff=0.0f;
|
||||
unsigned short needlePos=buf->needle;
|
||||
for (int i=0; i<FURNACE_FFT_SIZE; i++) {
|
||||
fft->inBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0;
|
||||
}
|
||||
fftw_execute(fft->plan);
|
||||
|
||||
// find origin frequency
|
||||
int point=1;
|
||||
double candAmp=0.0;
|
||||
for (unsigned short i=1; i<512; i++) {
|
||||
fftw_complex& f=fft->outBuf[i];
|
||||
// AMPLITUDE
|
||||
double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8);
|
||||
if (amp>candAmp) {
|
||||
point=i;
|
||||
candAmp=amp;
|
||||
ImVec2 minArea=window->DC.CursorPos;
|
||||
ImVec2 maxArea=ImVec2(
|
||||
minArea.x+size.x,
|
||||
minArea.y+size.y
|
||||
);
|
||||
ImRect rect=ImRect(minArea,maxArea);
|
||||
ImRect inRect=rect;
|
||||
inRect.Min.x+=dpiScale;
|
||||
inRect.Min.y+=2.0*dpiScale;
|
||||
inRect.Max.x-=dpiScale;
|
||||
inRect.Max.y-=2.0*dpiScale;
|
||||
|
||||
int precision=inRect.Max.x-inRect.Min.x;
|
||||
if (precision<1) precision=1;
|
||||
if (precision>512) precision=512;
|
||||
|
||||
ImGui::ItemSize(size,style.FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("chOscDisplay"))) {
|
||||
if (!e->isRunning()) {
|
||||
for (unsigned short i=0; i<precision; i++) {
|
||||
float x=(float)i/(float)precision;
|
||||
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f));
|
||||
}
|
||||
} else {
|
||||
float minLevel=1.0f;
|
||||
float maxLevel=-1.0f;
|
||||
float dcOff=0.0f;
|
||||
unsigned short needlePos=buf->needle;
|
||||
for (int i=0; i<FURNACE_FFT_SIZE; i++) {
|
||||
fft->inBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0;
|
||||
}
|
||||
fftw_execute(fft->plan);
|
||||
|
||||
// find origin frequency
|
||||
int point=1;
|
||||
double candAmp=0.0;
|
||||
for (unsigned short i=1; i<512; i++) {
|
||||
fftw_complex& f=fft->outBuf[i];
|
||||
// AMPLITUDE
|
||||
double amp=sqrt(pow(f[0],2.0)+pow(f[1],2.0))/pow((double)i,0.8);
|
||||
if (amp>candAmp) {
|
||||
point=i;
|
||||
candAmp=amp;
|
||||
}
|
||||
}
|
||||
|
||||
// PHASE
|
||||
fftw_complex& candPoint=fft->outBuf[point];
|
||||
double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2)));
|
||||
|
||||
if (chanOscWaveCorr) {
|
||||
needlePos-=phase;
|
||||
}
|
||||
chanOscPitch[ch]=(float)point/32.0f;
|
||||
|
||||
/*
|
||||
String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]);
|
||||
dl->AddText(inRect.Min,0xffffffff,cPhase.c_str());
|
||||
*/
|
||||
|
||||
needlePos-=displaySize;
|
||||
for (unsigned short i=0; i<precision; i++) {
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/precision))]/32768.0f;
|
||||
if (minLevel>y) minLevel=y;
|
||||
if (maxLevel<y) maxLevel=y;
|
||||
}
|
||||
dcOff=(minLevel+maxLevel)*0.5f;
|
||||
for (unsigned short i=0; i<precision; i++) {
|
||||
float x=(float)i/(float)precision;
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/precision))]/32768.0f;
|
||||
y-=dcOff;
|
||||
if (y<-0.5f) y=-0.5f;
|
||||
if (y>0.5f) y=0.5f;
|
||||
y*=chanOscAmplify;
|
||||
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y));
|
||||
}
|
||||
}
|
||||
ImU32 color=ImGui::GetColorU32(chanOscColor);
|
||||
if (chanOscUseGrad) {
|
||||
float xVal=computeGradPos(chanOscColorX,ch);
|
||||
float yVal=computeGradPos(chanOscColorY,ch);
|
||||
|
||||
// PHASE
|
||||
fftw_complex& candPoint=fft->outBuf[point];
|
||||
double phase=((double)(displaySize*2)/(double)point)*(0.5+(atan2(candPoint[1],candPoint[0])/(M_PI*2)));
|
||||
xVal=CLAMP(xVal,0.0f,1.0f);
|
||||
yVal=CLAMP(yVal,0.0f,1.0f);
|
||||
|
||||
if (chanOscWaveCorr) {
|
||||
needlePos-=phase;
|
||||
color=chanOscGrad.get(xVal,1.0f-yVal);
|
||||
}
|
||||
chanOscPitch[ch]=(float)point/32.0f;
|
||||
|
||||
/*
|
||||
String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]);
|
||||
dl->AddText(inRect.Min,0xffffffff,cPhase.c_str());
|
||||
*/
|
||||
ImGui::PushClipRect(inRect.Min,inRect.Max,false);
|
||||
|
||||
needlePos-=displaySize;
|
||||
for (unsigned short i=0; i<512; i++) {
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
|
||||
if (minLevel>y) minLevel=y;
|
||||
if (maxLevel<y) maxLevel=y;
|
||||
}
|
||||
dcOff=(minLevel+maxLevel)*0.5f;
|
||||
for (unsigned short i=0; i<512; i++) {
|
||||
float x=(float)i/512.0f;
|
||||
float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f;
|
||||
y-=dcOff;
|
||||
if (y<-0.5f) y=-0.5f;
|
||||
if (y>0.5f) y=0.5f;
|
||||
waveform[i]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y));
|
||||
dl->AddPolyline(waveform,precision,color,ImDrawFlags_None,dpiScale);
|
||||
|
||||
if (!chanOscTextFormat.empty()) {
|
||||
String text;
|
||||
bool inFormat=false;
|
||||
|
||||
for (char i: chanOscTextFormat) {
|
||||
if (inFormat) {
|
||||
switch (i) {
|
||||
case 'c':
|
||||
text+=e->getChannelName(ch);
|
||||
break;
|
||||
case 'C':
|
||||
text+=e->getChannelShortName(ch);
|
||||
break;
|
||||
case 'd':
|
||||
text+=fmt::sprintf("%d",ch);
|
||||
break;
|
||||
case 'D':
|
||||
text+=fmt::sprintf("%d",ch+1);
|
||||
break;
|
||||
case 'i': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
DivInstrument* ins=e->getIns(chanState->lastIns);
|
||||
text+=ins->name;
|
||||
break;
|
||||
}
|
||||
case 'I': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
text+=fmt::sprintf("%d",chanState->lastIns);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL) break;
|
||||
if (chanState->lastIns<0) {
|
||||
text+="??";
|
||||
} else {
|
||||
text+=fmt::sprintf("%.2X",chanState->lastIns);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
text+=e->getSystemName(e->sysOfChan[ch]);
|
||||
break;
|
||||
}
|
||||
case 'S': {
|
||||
text+=fmt::sprintf("%d",e->dispatchOfChan[ch]);
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
break;
|
||||
case 'V':
|
||||
break;
|
||||
case 'b':
|
||||
break;
|
||||
case '%':
|
||||
text+='%';
|
||||
break;
|
||||
default:
|
||||
text+='%';
|
||||
text+=i;
|
||||
break;
|
||||
}
|
||||
inFormat=false;
|
||||
} else {
|
||||
if (i=='%') {
|
||||
inFormat=true;
|
||||
} else {
|
||||
text+=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dl->AddText(ImLerp(inRect.Min,inRect.Max,ImVec2(0.0f,0.0f)),ImGui::GetColorU32(chanOscTextColor),text.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
ImU32 color=ImGui::GetColorU32(chanOscColor);
|
||||
if (chanOscUseGrad) {
|
||||
float xVal=computeGradPos(chanOscColorX,ch);
|
||||
float yVal=computeGradPos(chanOscColorY,ch);
|
||||
|
||||
xVal=CLAMP(xVal,0.0f,1.0f);
|
||||
yVal=CLAMP(yVal,0.0f,1.0f);
|
||||
|
||||
color=chanOscGrad.get(xVal,1.0f-yVal);
|
||||
}
|
||||
dl->AddPolyline(waveform,512,color,ImDrawFlags_None,dpiScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
ImGui::EndTable();
|
||||
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
chanOscOptions=!chanOscOptions;
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
chanOscOptions=!chanOscOptions;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_CHAN_OSC;
|
||||
ImGui::End();
|
||||
|
|
|
@ -380,7 +380,7 @@ void FurnaceGUI::drawDebug() {
|
|||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Window Debug")) {
|
||||
if (ImGui::TreeNodeEx("Window Debug",ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
ImGui::Text("Screen: %dx%d+%d+%d",scrW,scrH,scrX,scrY);
|
||||
ImGui::Text("Screen (Conf): %dx%d+%d+%d",scrConfW,scrConfH,scrConfX,scrConfY);
|
||||
ImGui::Text("Canvas: %dx%d",canvasW,canvasH);
|
||||
|
@ -549,6 +549,7 @@ void FurnaceGUI::drawDebug() {
|
|||
|
||||
ImGui::Text("audio: %dµs",lastProcTime);
|
||||
ImGui::Text("render: %.0fµs",(double)renderTimeDelta/perfFreq);
|
||||
ImGui::Text("draw: %.0fµs",(double)drawTimeDelta/perfFreq);
|
||||
ImGui::Text("layout: %.0fµs",(double)layoutTimeDelta/perfFreq);
|
||||
ImGui::Text("event: %.0fµs",(double)eventTimeDelta/perfFreq);
|
||||
ImGui::Separator();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "fileDialog.h"
|
||||
#include "ImGuiFileDialog.h"
|
||||
#include "util.h"
|
||||
#include "../ta-log.h"
|
||||
|
||||
#ifdef USE_NFD
|
||||
|
@ -152,6 +153,7 @@ bool FurnaceGUIFileDialog::openLoad(String header, std::vector<String> filter, c
|
|||
ImGuiFileDialog::Instance()->singleClickSel=mobileUI;
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->mobileMode=mobileUI;
|
||||
ImGuiFileDialog::Instance()->homePath=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,allowMultiple?999:1,nullptr,0,clickCallback);
|
||||
}
|
||||
opened=true;
|
||||
|
@ -235,6 +237,7 @@ bool FurnaceGUIFileDialog::openSave(String header, std::vector<String> filter, c
|
|||
ImGuiFileDialog::Instance()->singleClickSel=false;
|
||||
ImGuiFileDialog::Instance()->DpiScale=dpiScale;
|
||||
ImGuiFileDialog::Instance()->mobileMode=mobileUI;
|
||||
ImGuiFileDialog::Instance()->homePath=getHomeDir();
|
||||
ImGuiFileDialog::Instance()->OpenModal("FileDialog",header,noSysFilter,path,1,nullptr,ImGuiFileDialogFlags_ConfirmOverwrite);
|
||||
}
|
||||
opened=true;
|
||||
|
|
|
@ -3420,6 +3420,7 @@ bool FurnaceGUI::loop() {
|
|||
logV("portrait: %d (%dx%d)",portrait,scrW,scrH);
|
||||
logD("window resized to %dx%d",scrW,scrH);
|
||||
updateWindow=true;
|
||||
rend->resized(ev);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_MOVED:
|
||||
scrX=ev.window.data1;
|
||||
|
@ -3535,7 +3536,8 @@ bool FurnaceGUI::loop() {
|
|||
// update config x/y/w/h values based on scrMax state
|
||||
if (updateWindow) {
|
||||
logV("updateWindow is true");
|
||||
if (!scrMax) {
|
||||
if (!scrMax && !fullScreen) {
|
||||
logV("updating scrConf");
|
||||
scrConfX=scrX;
|
||||
scrConfY=scrY;
|
||||
scrConfW=scrW;
|
||||
|
@ -5809,6 +5811,7 @@ bool FurnaceGUI::loop() {
|
|||
renderTimeBegin=SDL_GetPerformanceCounter();
|
||||
ImGui::Render();
|
||||
renderTimeEnd=SDL_GetPerformanceCounter();
|
||||
drawTimeBegin=SDL_GetPerformanceCounter();
|
||||
rend->renderGUI();
|
||||
if (mustClear) {
|
||||
rend->clear(ImVec4(0,0,0,0));
|
||||
|
@ -5822,6 +5825,7 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
}
|
||||
}
|
||||
drawTimeEnd=SDL_GetPerformanceCounter();
|
||||
rend->present();
|
||||
if (settings.renderClearPos) {
|
||||
rend->clear(uiColors[GUI_COLOR_BACKGROUND]);
|
||||
|
@ -5829,6 +5833,7 @@ bool FurnaceGUI::loop() {
|
|||
|
||||
layoutTimeDelta=layoutTimeEnd-layoutTimeBegin;
|
||||
renderTimeDelta=renderTimeEnd-renderTimeBegin;
|
||||
drawTimeDelta=drawTimeEnd-drawTimeBegin;
|
||||
eventTimeDelta=eventTimeEnd-eventTimeBegin;
|
||||
|
||||
soloTimeout-=ImGui::GetIO().DeltaTime;
|
||||
|
@ -5980,6 +5985,7 @@ bool FurnaceGUI::init() {
|
|||
pianoOptions=e->getConfBool("pianoOptions",pianoOptions);
|
||||
pianoSharePosition=e->getConfBool("pianoSharePosition",pianoSharePosition);
|
||||
pianoOptionsSet=e->getConfBool("pianoOptionsSet",pianoOptionsSet);
|
||||
pianoReadonly=e->getConfBool("pianoReadonly",false);
|
||||
pianoOffset=e->getConfInt("pianoOffset",pianoOffset);
|
||||
pianoOffsetEdit=e->getConfInt("pianoOffsetEdit",pianoOffsetEdit);
|
||||
pianoView=e->getConfInt("pianoView",pianoView);
|
||||
|
@ -5988,13 +5994,22 @@ bool FurnaceGUI::init() {
|
|||
chanOscCols=e->getConfInt("chanOscCols",3);
|
||||
chanOscColorX=e->getConfInt("chanOscColorX",GUI_OSCREF_CENTER);
|
||||
chanOscColorY=e->getConfInt("chanOscColorY",GUI_OSCREF_CENTER);
|
||||
chanOscTextX=e->getConfFloat("chanOscTextX",0.0f);
|
||||
chanOscTextY=e->getConfFloat("chanOscTextY",0.0f);
|
||||
chanOscAmplify=e->getConfFloat("chanOscAmplify",0.95f);
|
||||
chanOscWindowSize=e->getConfFloat("chanOscWindowSize",20.0f);
|
||||
chanOscWaveCorr=e->getConfBool("chanOscWaveCorr",true);
|
||||
chanOscOptions=e->getConfBool("chanOscOptions",false);
|
||||
chanOscNormalize=e->getConfBool("chanOscNormalize",false);
|
||||
chanOscTextFormat=e->getConfString("chanOscTextFormat","%c");
|
||||
chanOscColor.x=e->getConfFloat("chanOscColorR",1.0f);
|
||||
chanOscColor.y=e->getConfFloat("chanOscColorG",1.0f);
|
||||
chanOscColor.z=e->getConfFloat("chanOscColorB",1.0f);
|
||||
chanOscColor.w=e->getConfFloat("chanOscColorA",1.0f);
|
||||
chanOscTextColor.x=e->getConfFloat("chanOscTextColorR",1.0f);
|
||||
chanOscTextColor.y=e->getConfFloat("chanOscTextColorG",1.0f);
|
||||
chanOscTextColor.z=e->getConfFloat("chanOscTextColorB",1.0f);
|
||||
chanOscTextColor.w=e->getConfFloat("chanOscTextColorA",0.75f);
|
||||
chanOscUseGrad=e->getConfBool("chanOscUseGrad",false);
|
||||
chanOscGrad.fromString(e->getConfString("chanOscGrad",""));
|
||||
chanOscGrad.render();
|
||||
|
@ -6144,7 +6159,7 @@ bool FurnaceGUI::init() {
|
|||
logV("window size: %dx%d",scrW,scrH);
|
||||
|
||||
if (!initRender()) {
|
||||
if (settings.renderBackend=="OpenGL") {
|
||||
if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) {
|
||||
settings.renderBackend="";
|
||||
e->setConf("renderBackend","");
|
||||
e->saveConf();
|
||||
|
@ -6230,11 +6245,11 @@ bool FurnaceGUI::init() {
|
|||
|
||||
logD("starting render backend...");
|
||||
if (!rend->init(sdlWin)) {
|
||||
if (settings.renderBackend=="OpenGL") {
|
||||
if (settings.renderBackend!="SDL" && !settings.renderBackend.empty()) {
|
||||
settings.renderBackend="";
|
||||
e->setConf("renderBackend","");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
//e->setConf("renderBackend","");
|
||||
//e->saveConf();
|
||||
//lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
} else {
|
||||
lastError=fmt::sprintf("could not init renderer! %s",SDL_GetError());
|
||||
if (!settings.renderDriver.empty()) {
|
||||
|
@ -6257,11 +6272,17 @@ bool FurnaceGUI::init() {
|
|||
// special consideration for Wayland
|
||||
if (settings.dpiScale<0.5f) {
|
||||
if (strcmp(videoBackend,"wayland")==0) {
|
||||
if (scrW<1) {
|
||||
int realW=scrW;
|
||||
int realH=scrH;
|
||||
|
||||
SDL_GetWindowSize(sdlWin,&realW,&realH);
|
||||
|
||||
if (realW<1) {
|
||||
logW("screen width is zero!\n");
|
||||
dpiScale=1.0;
|
||||
} else {
|
||||
dpiScale=(double)canvasW/(double)scrW;
|
||||
dpiScale=(double)canvasW/(double)realW;
|
||||
logV("we're on Wayland... scaling factor: %f",dpiScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6465,6 +6486,7 @@ void FurnaceGUI::commitState() {
|
|||
e->setConf("pianoOptions",pianoOptions);
|
||||
e->setConf("pianoSharePosition",pianoSharePosition);
|
||||
e->setConf("pianoOptionsSet",pianoOptionsSet);
|
||||
e->setConf("pianoReadonly",pianoReadonly);
|
||||
e->setConf("pianoOffset",pianoOffset);
|
||||
e->setConf("pianoOffsetEdit",pianoOffsetEdit);
|
||||
e->setConf("pianoView",pianoView);
|
||||
|
@ -6474,13 +6496,22 @@ void FurnaceGUI::commitState() {
|
|||
e->setConf("chanOscCols",chanOscCols);
|
||||
e->setConf("chanOscColorX",chanOscColorX);
|
||||
e->setConf("chanOscColorY",chanOscColorY);
|
||||
e->setConf("chanOscTextX",chanOscTextX);
|
||||
e->setConf("chanOscTextY",chanOscTextY);
|
||||
e->setConf("chanOscAmplify",chanOscAmplify);
|
||||
e->setConf("chanOscWindowSize",chanOscWindowSize);
|
||||
e->setConf("chanOscWaveCorr",chanOscWaveCorr);
|
||||
e->setConf("chanOscOptions",chanOscOptions);
|
||||
e->setConf("chanOscNormalize",chanOscNormalize);
|
||||
e->setConf("chanOscTextFormat",chanOscTextFormat);
|
||||
e->setConf("chanOscColorR",chanOscColor.x);
|
||||
e->setConf("chanOscColorG",chanOscColor.y);
|
||||
e->setConf("chanOscColorB",chanOscColor.z);
|
||||
e->setConf("chanOscColorA",chanOscColor.w);
|
||||
e->setConf("chanOscTextColorR",chanOscTextColor.x);
|
||||
e->setConf("chanOscTextColorG",chanOscTextColor.y);
|
||||
e->setConf("chanOscTextColorB",chanOscTextColor.z);
|
||||
e->setConf("chanOscTextColorA",chanOscTextColor.w);
|
||||
e->setConf("chanOscUseGrad",chanOscUseGrad);
|
||||
e->setConf("chanOscGrad",chanOscGrad.toString());
|
||||
|
||||
|
@ -6825,6 +6856,9 @@ FurnaceGUI::FurnaceGUI():
|
|||
renderTimeBegin(0),
|
||||
renderTimeEnd(0),
|
||||
renderTimeDelta(0),
|
||||
drawTimeBegin(0),
|
||||
drawTimeEnd(0),
|
||||
drawTimeDelta(0),
|
||||
eventTimeBegin(0),
|
||||
eventTimeEnd(0),
|
||||
eventTimeDelta(0),
|
||||
|
@ -6899,11 +6933,17 @@ FurnaceGUI::FurnaceGUI():
|
|||
chanOscColorX(GUI_OSCREF_CENTER),
|
||||
chanOscColorY(GUI_OSCREF_CENTER),
|
||||
chanOscWindowSize(20.0f),
|
||||
chanOscTextX(0.0f),
|
||||
chanOscTextY(0.0f),
|
||||
chanOscAmplify(0.95f),
|
||||
chanOscWaveCorr(true),
|
||||
chanOscOptions(false),
|
||||
updateChanOscGradTex(true),
|
||||
chanOscUseGrad(false),
|
||||
chanOscNormalize(false),
|
||||
chanOscTextFormat("%c"),
|
||||
chanOscColor(1.0f,1.0f,1.0f,1.0f),
|
||||
chanOscTextColor(1.0f,1.0f,1.0f,0.75f),
|
||||
chanOscGrad(64,64),
|
||||
chanOscGradTex(NULL),
|
||||
followLog(true),
|
||||
|
@ -6913,6 +6953,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
pianoOptions(true),
|
||||
pianoSharePosition(false),
|
||||
pianoOptionsSet(false),
|
||||
pianoReadonly(false),
|
||||
pianoOffset(6),
|
||||
pianoOffsetEdit(9),
|
||||
pianoView(PIANO_LAYOUT_AUTOMATIC),
|
||||
|
@ -6922,6 +6963,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
pianoOctavesEdit(4),
|
||||
pianoOptions(false),
|
||||
pianoSharePosition(true),
|
||||
pianoReadonly(false),
|
||||
pianoOffset(6),
|
||||
pianoOffsetEdit(6),
|
||||
pianoView(PIANO_LAYOUT_STANDARD),
|
||||
|
@ -6946,6 +6988,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
mustClear(2),
|
||||
initialScreenWipe(1.0f),
|
||||
introSkipDo(false),
|
||||
introStopped(false),
|
||||
curTutorial(-1),
|
||||
curTutorialStep(0) {
|
||||
// value keys
|
||||
|
|
|
@ -71,16 +71,22 @@
|
|||
|
||||
enum FurnaceGUIRenderBackend {
|
||||
GUI_BACKEND_SDL=0,
|
||||
GUI_BACKEND_GL
|
||||
GUI_BACKEND_GL,
|
||||
GUI_BACKEND_DX11
|
||||
};
|
||||
|
||||
#ifdef HAVE_RENDER_SDL
|
||||
#define GUI_BACKEND_DEFAULT GUI_BACKEND_SDL
|
||||
#define GUI_BACKEND_DEFAULT_NAME "SDL"
|
||||
#else
|
||||
#ifdef HAVE_RENDER_DX11
|
||||
#define GUI_BACKEND_DEFAULT GUI_BACKEND_DX11
|
||||
#define GUI_BACKEND_DEFAULT_NAME "DirectX 11"
|
||||
#else
|
||||
#define GUI_BACKEND_DEFAULT GUI_BACKEND_GL
|
||||
#define GUI_BACKEND_DEFAULT_NAME "OpenGL"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO:
|
||||
// - add colors for FM envelope and waveform
|
||||
|
@ -1242,6 +1248,7 @@ class FurnaceGUIRender {
|
|||
virtual bool destroyTexture(void* which);
|
||||
virtual void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode);
|
||||
virtual void setBlendMode(FurnaceGUIBlendMode mode);
|
||||
virtual void resized(const SDL_Event& ev);
|
||||
virtual void clear(ImVec4 color);
|
||||
virtual bool newFrame();
|
||||
virtual void createFontsTexture();
|
||||
|
@ -1864,6 +1871,7 @@ class FurnaceGUI {
|
|||
|
||||
int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta;
|
||||
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||
int drawTimeBegin, drawTimeEnd, drawTimeDelta;
|
||||
int eventTimeBegin, eventTimeEnd, eventTimeDelta;
|
||||
|
||||
FurnaceGUIPerfMetric perfMetrics[64];
|
||||
|
@ -1939,9 +1947,10 @@ class FurnaceGUI {
|
|||
|
||||
// per-channel oscilloscope
|
||||
int chanOscCols, chanOscColorX, chanOscColorY;
|
||||
float chanOscWindowSize;
|
||||
bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex, chanOscUseGrad;
|
||||
ImVec4 chanOscColor;
|
||||
float chanOscWindowSize, chanOscTextX, chanOscTextY, chanOscAmplify;
|
||||
bool chanOscWaveCorr, chanOscOptions, updateChanOscGradTex, chanOscUseGrad, chanOscNormalize;
|
||||
String chanOscTextFormat;
|
||||
ImVec4 chanOscColor, chanOscTextColor;
|
||||
Gradient2D chanOscGrad;
|
||||
void* chanOscGradTex;
|
||||
float chanOscLP0[DIV_MAX_CHANS];
|
||||
|
@ -1995,6 +2004,7 @@ class FurnaceGUI {
|
|||
bool pianoOptions, pianoSharePosition, pianoOptionsSet;
|
||||
float pianoKeyHit[180];
|
||||
bool pianoKeyPressed[180];
|
||||
bool pianoReadonly;
|
||||
int pianoOffset, pianoOffsetEdit;
|
||||
int pianoView, pianoInputPadMode;
|
||||
|
||||
|
@ -2029,7 +2039,7 @@ class FurnaceGUI {
|
|||
double monitorPos;
|
||||
int mustClear;
|
||||
float initialScreenWipe;
|
||||
bool introSkipDo;
|
||||
bool introSkipDo, introStopped;
|
||||
ImVec2 introMin, introMax;
|
||||
|
||||
// tutorial
|
||||
|
|
|
@ -506,7 +506,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("WINDOW_ABOUT", "About", 0),
|
||||
D("WINDOW_SETTINGS", "Settings", 0),
|
||||
D("WINDOW_MIXER", "Mixer", 0),
|
||||
D("WINDOW_DEBUG", "Debug Menu", 0),
|
||||
D("WINDOW_DEBUG", "Debug Menu", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_d),
|
||||
D("WINDOW_OSCILLOSCOPE", "Oscilloscope (master)", 0),
|
||||
D("WINDOW_VOL_METER", "Volume Meter", 0),
|
||||
D("WINDOW_STATS", "Statistics", 0),
|
||||
|
|
|
@ -2262,9 +2262,11 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::PushID(2+curIns);
|
||||
if (ImGui::InputText("##Name",&ins->name)) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include "gui.h"
|
||||
#include "../ta-log.h"
|
||||
#include "imgui_internal.h"
|
||||
#include <fmt/printf.h>
|
||||
|
||||
|
@ -73,6 +74,8 @@ void FurnaceGUI::drawImage(ImDrawList* dl, FurnaceGUIImages image, const ImVec2&
|
|||
}
|
||||
|
||||
void FurnaceGUI::endIntroTune() {
|
||||
if (introStopped) return;
|
||||
logV("ending intro");
|
||||
stop();
|
||||
if (curFileName.empty()) {
|
||||
e->createNewFromDefaults();
|
||||
|
@ -95,6 +98,8 @@ void FurnaceGUI::endIntroTune() {
|
|||
selEnd=SelectionPoint();
|
||||
cursor=SelectionPoint();
|
||||
updateWindowTitle();
|
||||
updateScroll(0);
|
||||
introStopped=true;
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawIntro(double introTime, bool monitor) {
|
||||
|
@ -290,7 +295,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) {
|
|||
if (introSkipDo) {
|
||||
introSkip+=ImGui::GetIO().DeltaTime;
|
||||
if (introSkip>=0.5) {
|
||||
if (e->isPlaying()) endIntroTune();
|
||||
if (!shortIntro) endIntroTune();
|
||||
introPos=0.1;
|
||||
if (introSkip>=0.75) introPos=12.0;
|
||||
}
|
||||
|
@ -317,7 +322,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) {
|
|||
e->setRepeatPattern(false);
|
||||
play();
|
||||
}
|
||||
if (e->isPlaying() && introPos>=10.0 && !shortIntro) endIntroTune();
|
||||
if (introPos>=10.0 && !shortIntro) endIntroTune();
|
||||
introPos+=ImGui::GetIO().DeltaTime;
|
||||
if (introPos>=(shortIntro?1.0:11.0)) {
|
||||
introPos=12.0;
|
||||
|
@ -325,5 +330,7 @@ void FurnaceGUI::drawIntro(double introTime, bool monitor) {
|
|||
commitTutorial();
|
||||
}
|
||||
}
|
||||
} else if (!shortIntro) {
|
||||
endIntroTune();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ void FurnaceGUI::drawPiano() {
|
|||
pianoInputPadMode=PIANO_INPUT_PAD_SPLIT_VISIBLE;
|
||||
}
|
||||
ImGui::Checkbox("Share play/edit offset/range",&pianoSharePosition);
|
||||
ImGui::Checkbox("Read-only (can't input notes)",&pianoReadonly);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
|
@ -223,7 +224,7 @@ void FurnaceGUI::drawPiano() {
|
|||
//ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y);
|
||||
if (ImGui::ItemAdd(rect,ImGui::GetID("pianoDisplay"))) {
|
||||
bool canInput=false;
|
||||
if (ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) {
|
||||
if (!pianoReadonly && ImGui::ItemHoverable(rect,ImGui::GetID("pianoDisplay"))) {
|
||||
canInput=true;
|
||||
ImGui::InhibitInertialScroll();
|
||||
}
|
||||
|
|
|
@ -25,12 +25,17 @@
|
|||
#ifdef HAVE_RENDER_GL
|
||||
#include "render/renderGL.h"
|
||||
#endif
|
||||
#ifdef HAVE_RENDER_DX11
|
||||
#include "render/renderDX11.h"
|
||||
#endif
|
||||
|
||||
bool FurnaceGUI::initRender() {
|
||||
if (rend!=NULL) return false;
|
||||
|
||||
if (settings.renderBackend=="OpenGL") {
|
||||
renderBackend=GUI_BACKEND_GL;
|
||||
} else if (settings.renderBackend=="DirectX 11") {
|
||||
renderBackend=GUI_BACKEND_DX11;
|
||||
} else if (settings.renderBackend=="SDL") {
|
||||
renderBackend=GUI_BACKEND_SDL;
|
||||
} else {
|
||||
|
@ -44,6 +49,12 @@ bool FurnaceGUI::initRender() {
|
|||
rend=new FurnaceGUIRenderGL;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_RENDER_DX11
|
||||
case GUI_BACKEND_DX11:
|
||||
logI("render backend: DirectX 11");
|
||||
rend=new FurnaceGUIRenderDX11;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_RENDER_SDL
|
||||
case GUI_BACKEND_SDL:
|
||||
logI("render backend: SDL_Renderer");
|
||||
|
|
|
@ -49,6 +49,9 @@ void FurnaceGUIRender::setTextureBlendMode(void* which, FurnaceGUIBlendMode mode
|
|||
void FurnaceGUIRender::setBlendMode(FurnaceGUIBlendMode mode) {
|
||||
}
|
||||
|
||||
void FurnaceGUIRender::resized(const SDL_Event& ev) {
|
||||
}
|
||||
|
||||
void FurnaceGUIRender::clear(ImVec4 color) {
|
||||
}
|
||||
|
||||
|
@ -97,4 +100,4 @@ void FurnaceGUIRender::quitGUI() {
|
|||
}
|
||||
|
||||
FurnaceGUIRender::~FurnaceGUIRender() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,571 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define INCLUDE_D3D11
|
||||
#include "renderDX11.h"
|
||||
#include <SDL_syswm.h>
|
||||
#include "backends/imgui_impl_dx11.h"
|
||||
#include "../../ta-log.h"
|
||||
|
||||
typedef HRESULT (__stdcall *D3DCompile_t)(LPCVOID,SIZE_T,LPCSTR,D3D_SHADER_MACRO*,ID3DInclude*,LPCSTR,LPCSTR,UINT,UINT,ID3DBlob**,ID3DBlob*);
|
||||
|
||||
const char* shD3D11_wipe_srcV=
|
||||
"cbuffer WipeUniform: register(b0) {\n"
|
||||
" float alpha;\n"
|
||||
" float padding1;\n"
|
||||
" float padding2;\n"
|
||||
" float padding3;\n"
|
||||
" float4 padding4;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct vsInput {\n"
|
||||
" float4 pos: POSITION;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"struct fsInput {\n"
|
||||
" float4 pos: SV_POSITION;\n"
|
||||
" float4 color: COLOR0;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"fsInput main(vsInput input) {\n"
|
||||
" fsInput output;\n"
|
||||
" output.pos=input.pos;\n"
|
||||
" output.color=float4(0.0f,0.0f,0.0f,alpha);\n"
|
||||
" return output;\n"
|
||||
"}";
|
||||
|
||||
const char* shD3D11_wipe_srcF=
|
||||
"struct fsInput {\n"
|
||||
" float4 pos: SV_POSITION;\n"
|
||||
" float4 color: COLOR0;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"float4 main(fsInput input): SV_Target {\n"
|
||||
" return input.color;\n"
|
||||
"}";
|
||||
|
||||
const D3D11_INPUT_ELEMENT_DESC shD3D11_wipe_inputLayout={
|
||||
"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0
|
||||
};
|
||||
|
||||
const D3D_FEATURE_LEVEL possibleFeatureLevels[2]={
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_0
|
||||
};
|
||||
|
||||
struct FurnaceDXTexture {
|
||||
ID3D11Texture2D* tex;
|
||||
ID3D11ShaderResourceView* view;
|
||||
int width, height;
|
||||
unsigned char* lockedData;
|
||||
bool dynamic;
|
||||
FurnaceDXTexture():
|
||||
tex(NULL),
|
||||
view(NULL),
|
||||
width(0),
|
||||
height(0),
|
||||
lockedData(NULL),
|
||||
dynamic(false) {}
|
||||
};
|
||||
|
||||
bool FurnaceGUIRenderDX11::destroyRenderTarget() {
|
||||
if (renderTarget!=NULL) {
|
||||
renderTarget->Release();
|
||||
renderTarget=NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::createRenderTarget() {
|
||||
ID3D11Texture2D* screen=NULL;
|
||||
HRESULT result;
|
||||
|
||||
destroyRenderTarget();
|
||||
|
||||
if (swapchain==NULL || device==NULL) {
|
||||
logW("createRenderTarget: swapchain or device are NULL!");
|
||||
return false;
|
||||
}
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC chainDesc;
|
||||
memset(&chainDesc,0,sizeof(chainDesc));
|
||||
if (swapchain->GetDesc(&chainDesc)!=S_OK) {
|
||||
logW("createRenderTarget: could not get swapchain desc!");
|
||||
} else {
|
||||
outW=chainDesc.BufferDesc.Width;
|
||||
outH=chainDesc.BufferDesc.Height;
|
||||
logI("DX11: buffer desc sizes: %d, %d",chainDesc.BufferDesc.Width,chainDesc.BufferDesc.Height);
|
||||
}
|
||||
|
||||
result=swapchain->GetBuffer(0,IID_PPV_ARGS(&screen));
|
||||
if (result!=S_OK) {
|
||||
logW("createRenderTarget: could not get buffer! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
if (screen==NULL) {
|
||||
logW("createRenderTarget: screen is null!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result=device->CreateRenderTargetView(screen,NULL,&renderTarget);
|
||||
if (result!=S_OK) {
|
||||
logW("createRenderTarget: could not create render target view! %.8x",result);
|
||||
screen->Release();
|
||||
return false;
|
||||
}
|
||||
if (renderTarget==NULL) {
|
||||
logW("createRenderTarget: what the hell the render target is null?");
|
||||
screen->Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
ImTextureID FurnaceGUIRenderDX11::getTextureID(void* which) {
|
||||
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
|
||||
return (ImTextureID)t->view;
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::lockTexture(void* which, void** data, int* pitch) {
|
||||
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
|
||||
if (t->lockedData!=NULL) return false;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedRes;
|
||||
memset(&mappedRes,0,sizeof(mappedRes));
|
||||
|
||||
HRESULT result=context->Map(t->tex,D3D11CalcSubresource(0,0,1),D3D11_MAP_WRITE_DISCARD,0,&mappedRes);
|
||||
if (result!=S_OK) {
|
||||
logW("could not map texture! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
t->lockedData=(unsigned char*)mappedRes.pData;
|
||||
*data=mappedRes.pData;
|
||||
*pitch=mappedRes.RowPitch;
|
||||
|
||||
logV("texture locked... pitch: %d",mappedRes.RowPitch);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::unlockTexture(void* which) {
|
||||
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
|
||||
if (t->lockedData==NULL) return false;
|
||||
context->Unmap(t->tex,D3D11CalcSubresource(0,0,1));
|
||||
t->lockedData=NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::updateTexture(void* which, void* data, int pitch) {
|
||||
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
|
||||
if (t->dynamic) {
|
||||
unsigned char* d=NULL;
|
||||
int p=0;
|
||||
if (!lockTexture(t,(void**)&d,&p)) return false;
|
||||
if (p==pitch) {
|
||||
memcpy(d,data,p*t->height);
|
||||
} else {
|
||||
unsigned char* ucData=(unsigned char*)data;
|
||||
int srcPos=0;
|
||||
int destPos=0;
|
||||
for (int i=0; i<t->height; i++) {
|
||||
memcpy(&d[destPos],&ucData[srcPos],pitch);
|
||||
srcPos+=pitch;
|
||||
destPos+=p;
|
||||
}
|
||||
}
|
||||
unlockTexture(t);
|
||||
} else {
|
||||
context->UpdateSubresource(t->tex,D3D11CalcSubresource(0,0,1),NULL,data,pitch,pitch*t->height);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* FurnaceGUIRenderDX11::createTexture(bool dynamic, int width, int height) {
|
||||
D3D11_TEXTURE2D_DESC texDesc;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
|
||||
ID3D11Texture2D* tex=NULL;
|
||||
ID3D11ShaderResourceView* view=NULL;
|
||||
HRESULT result;
|
||||
|
||||
memset(&texDesc,0,sizeof(texDesc));
|
||||
memset(&viewDesc,0,sizeof(viewDesc));
|
||||
|
||||
texDesc.Width=width;
|
||||
texDesc.Height=height;
|
||||
texDesc.MipLevels=1;
|
||||
texDesc.ArraySize=1;
|
||||
texDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM; // ???
|
||||
texDesc.SampleDesc.Count=1;
|
||||
texDesc.SampleDesc.Quality=0;
|
||||
texDesc.Usage=dynamic?D3D11_USAGE_DYNAMIC:D3D11_USAGE_DEFAULT;
|
||||
texDesc.BindFlags=D3D11_BIND_SHADER_RESOURCE;
|
||||
texDesc.CPUAccessFlags=dynamic?D3D11_CPU_ACCESS_WRITE:0;
|
||||
texDesc.MiscFlags=0;
|
||||
|
||||
result=device->CreateTexture2D(&texDesc,NULL,&tex);
|
||||
if (result!=S_OK) {
|
||||
logW("could not create texture! %.8x",result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
viewDesc.Format=texDesc.Format=texDesc.Format;
|
||||
viewDesc.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
viewDesc.Texture2D.MostDetailedMip=0;
|
||||
viewDesc.Texture2D.MipLevels=texDesc.MipLevels;
|
||||
|
||||
result=device->CreateShaderResourceView(tex,&viewDesc,&view);
|
||||
if (result!=S_OK) {
|
||||
logW("could not create texture view! %.8x",result);
|
||||
tex->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FurnaceDXTexture* ret=new FurnaceDXTexture;
|
||||
ret->width=width;
|
||||
ret->height=height;
|
||||
ret->tex=tex;
|
||||
ret->view=view;
|
||||
ret->dynamic=dynamic;
|
||||
textures.push_back(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::destroyTexture(void* which) {
|
||||
FurnaceDXTexture* t=(FurnaceDXTexture*)which;
|
||||
t->view->Release();
|
||||
t->tex->Release();
|
||||
delete t;
|
||||
|
||||
for (size_t i=0; i<textures.size(); i++) {
|
||||
if (textures[i]==t) {
|
||||
textures.erase(textures.begin()+i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::setTextureBlendMode(void* which, FurnaceGUIBlendMode mode) {
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::setBlendMode(FurnaceGUIBlendMode mode) {
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::resized(const SDL_Event& ev) {
|
||||
destroyRenderTarget();
|
||||
logI("DX11: resizing buffers");
|
||||
HRESULT result=swapchain->ResizeBuffers(0,(unsigned int)ev.window.data1,(unsigned int)ev.window.data2,DXGI_FORMAT_UNKNOWN,DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
|
||||
if (result!=S_OK) {
|
||||
logW("error while resizing swapchain buffers! %.8x",result);
|
||||
}
|
||||
createRenderTarget();
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::clear(ImVec4 color) {
|
||||
float floatColor[4]={
|
||||
color.x*color.w,
|
||||
color.y*color.w,
|
||||
color.z*color.w,
|
||||
color.w,
|
||||
};
|
||||
|
||||
context->OMSetRenderTargets(1,&renderTarget,NULL);
|
||||
context->ClearRenderTargetView(renderTarget,floatColor);
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::newFrame() {
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::createFontsTexture() {
|
||||
ImGui_ImplDX11_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::destroyFontsTexture() {
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::renderGUI() {
|
||||
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
const float blendFactor[4]={
|
||||
1.0f, 1.0f, 1.0f, 1.0f
|
||||
};
|
||||
|
||||
void FurnaceGUIRenderDX11::wipe(float alpha) {
|
||||
D3D11_VIEWPORT viewPort;
|
||||
unsigned int strides=4*sizeof(float);
|
||||
unsigned int offsets=0;
|
||||
|
||||
memset(&viewPort,0,sizeof(viewPort));
|
||||
viewPort.TopLeftX=0.0f;
|
||||
viewPort.TopLeftY=0.0f;
|
||||
viewPort.Width=outW;
|
||||
viewPort.Height=outH;
|
||||
viewPort.MinDepth=0.0f;
|
||||
viewPort.MaxDepth=1.0f;
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mappedUniform;
|
||||
if (context->Map(sh_wipe_uniform,0,D3D11_MAP_WRITE_DISCARD,0,&mappedUniform)!=S_OK) {
|
||||
logW("could not map constant");
|
||||
}
|
||||
WipeUniform* sh_wipe_uniformState=(WipeUniform*)mappedUniform.pData;
|
||||
sh_wipe_uniformState->alpha=alpha;
|
||||
context->Unmap(sh_wipe_uniform,0);
|
||||
|
||||
context->RSSetViewports(1,&viewPort);
|
||||
context->RSSetState(rsState);
|
||||
|
||||
context->OMSetBlendState(omBlendState,blendFactor,0xffffffff);
|
||||
context->IASetInputLayout(sh_wipe_inputLayout);
|
||||
context->IASetVertexBuffers(0,1,&quadVertex,&strides,&offsets);
|
||||
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
context->VSSetShader(sh_wipe_vertex,NULL,0);
|
||||
context->VSSetConstantBuffers(0,1,&sh_wipe_uniform);
|
||||
context->PSSetShader(sh_wipe_fragment,NULL,0);
|
||||
|
||||
context->Draw(4,0);
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::present() {
|
||||
swapchain->Present(1,0);
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::getOutputSize(int& w, int& h) {
|
||||
w=outW;
|
||||
h=outH;
|
||||
return true;
|
||||
}
|
||||
|
||||
int FurnaceGUIRenderDX11::getWindowFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::preInit() {
|
||||
}
|
||||
|
||||
const float wipeVertices[4][4]={
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
1.0, -1.0, 0.0, 1.0,
|
||||
-1.0, 1.0, 0.0, 1.0,
|
||||
1.0, 1.0, 0.0, 1.0
|
||||
};
|
||||
|
||||
bool FurnaceGUIRenderDX11::init(SDL_Window* win) {
|
||||
SDL_SysWMinfo sysWindow;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
|
||||
SDL_VERSION(&sysWindow.version);
|
||||
if (SDL_GetWindowWMInfo(win,&sysWindow)==SDL_FALSE) {
|
||||
logE("could not get window WM info! %s",SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
HWND window=(HWND)sysWindow.info.win.window;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC chainDesc;
|
||||
memset(&chainDesc,0,sizeof(chainDesc));
|
||||
chainDesc.BufferDesc.Width=0;
|
||||
chainDesc.BufferDesc.Height=0;
|
||||
chainDesc.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
chainDesc.BufferDesc.RefreshRate.Numerator=60;
|
||||
chainDesc.BufferDesc.RefreshRate.Denominator=1;
|
||||
chainDesc.SampleDesc.Count=1;
|
||||
chainDesc.SampleDesc.Quality=0;
|
||||
chainDesc.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
chainDesc.BufferCount=2;
|
||||
chainDesc.OutputWindow=window;
|
||||
chainDesc.Windowed=TRUE; // TODO: what if we're in full screen mode?
|
||||
chainDesc.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
|
||||
chainDesc.Flags=DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
|
||||
HRESULT result=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,possibleFeatureLevels,2,D3D11_SDK_VERSION,&chainDesc,&swapchain,&device,&featureLevel,&context);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create device and/or swap chain! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/ocornut/imgui/pull/638
|
||||
D3DCompile_t D3DCompile=NULL;
|
||||
char dllBuffer[20];
|
||||
for (int i=47; (i>30 && !D3DCompile); i--) {
|
||||
snprintf(dllBuffer,20,"d3dcompiler_%d.dll",i);
|
||||
HMODULE hDll=LoadLibraryA(dllBuffer);
|
||||
if (hDll) {
|
||||
D3DCompile=(D3DCompile_t)GetProcAddress(hDll,"D3DCompile");
|
||||
}
|
||||
}
|
||||
if (!D3DCompile) {
|
||||
logE("could not find D3DCompile!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// create wipe shader
|
||||
ID3DBlob* wipeBlobV=NULL;
|
||||
ID3DBlob* wipeBlobF=NULL;
|
||||
D3D11_BUFFER_DESC wipeConstantDesc;
|
||||
|
||||
result=D3DCompile(shD3D11_wipe_srcV,strlen(shD3D11_wipe_srcV),NULL,NULL,NULL,"main","vs_4_0",0,0,&wipeBlobV,NULL);
|
||||
if (result!=S_OK) {
|
||||
logE("could not compile vertex shader! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
result=D3DCompile(shD3D11_wipe_srcF,strlen(shD3D11_wipe_srcF),NULL,NULL,NULL,"main","ps_4_0",0,0,&wipeBlobF,NULL);
|
||||
if (result!=S_OK) {
|
||||
logE("could not compile pixel shader! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
result=device->CreateVertexShader(wipeBlobV->GetBufferPointer(),wipeBlobV->GetBufferSize(),NULL,&sh_wipe_vertex);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create vertex shader! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
result=device->CreatePixelShader(wipeBlobF->GetBufferPointer(),wipeBlobF->GetBufferSize(),NULL,&sh_wipe_fragment);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create pixel shader! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
result=device->CreateInputLayout(&shD3D11_wipe_inputLayout,1,wipeBlobV->GetBufferPointer(),wipeBlobV->GetBufferSize(),&sh_wipe_inputLayout);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create input layout! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&wipeConstantDesc,0,sizeof(wipeConstantDesc));
|
||||
wipeConstantDesc.ByteWidth=sizeof(WipeUniform);
|
||||
wipeConstantDesc.Usage=D3D11_USAGE_DYNAMIC;
|
||||
wipeConstantDesc.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
|
||||
wipeConstantDesc.CPUAccessFlags=D3D11_CPU_ACCESS_WRITE;
|
||||
wipeConstantDesc.MiscFlags=0;
|
||||
wipeConstantDesc.StructureByteStride=0;
|
||||
|
||||
result=device->CreateBuffer(&wipeConstantDesc,NULL,&sh_wipe_uniform);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create constant buffer! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create wipe vertices
|
||||
D3D11_BUFFER_DESC vertexDesc;
|
||||
D3D11_SUBRESOURCE_DATA vertexRes;
|
||||
|
||||
memset(&vertexDesc,0,sizeof(vertexDesc));
|
||||
memset(&vertexRes,0,sizeof(vertexRes));
|
||||
|
||||
vertexDesc.ByteWidth=4*4*sizeof(float);
|
||||
vertexDesc.Usage=D3D11_USAGE_DEFAULT;
|
||||
vertexDesc.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
vertexDesc.CPUAccessFlags=0;
|
||||
vertexDesc.MiscFlags=0;
|
||||
vertexDesc.StructureByteStride=0;
|
||||
|
||||
vertexRes.pSysMem=wipeVertices;
|
||||
vertexRes.SysMemPitch=0;
|
||||
vertexRes.SysMemSlicePitch=0;
|
||||
|
||||
result=device->CreateBuffer(&vertexDesc,&vertexRes,&quadVertex);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create vertex buffer! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
// initialize the rest
|
||||
D3D11_RASTERIZER_DESC rasterDesc;
|
||||
D3D11_BLEND_DESC blendDesc;
|
||||
|
||||
memset(&rasterDesc,0,sizeof(rasterDesc));
|
||||
memset(&blendDesc,0,sizeof(blendDesc));
|
||||
|
||||
rasterDesc.FillMode=D3D11_FILL_SOLID;
|
||||
rasterDesc.CullMode=D3D11_CULL_NONE;
|
||||
rasterDesc.FrontCounterClockwise=false;
|
||||
rasterDesc.DepthBias=0;
|
||||
rasterDesc.DepthBiasClamp=0.0f;
|
||||
rasterDesc.SlopeScaledDepthBias=0.0f;
|
||||
rasterDesc.DepthClipEnable=false;
|
||||
rasterDesc.ScissorEnable=false;
|
||||
rasterDesc.MultisampleEnable=false;
|
||||
rasterDesc.AntialiasedLineEnable=false;
|
||||
result=device->CreateRasterizerState(&rasterDesc,&rsState);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create rasterizer state! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
blendDesc.AlphaToCoverageEnable=false;
|
||||
blendDesc.IndependentBlendEnable=false;
|
||||
blendDesc.RenderTarget[0].BlendEnable=true;
|
||||
blendDesc.RenderTarget[0].SrcBlend=D3D11_BLEND_SRC_ALPHA;
|
||||
blendDesc.RenderTarget[0].DestBlend=D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blendDesc.RenderTarget[0].BlendOp=D3D11_BLEND_OP_ADD;
|
||||
blendDesc.RenderTarget[0].SrcBlendAlpha=D3D11_BLEND_ONE;
|
||||
blendDesc.RenderTarget[0].DestBlendAlpha=D3D11_BLEND_INV_SRC_ALPHA;
|
||||
blendDesc.RenderTarget[0].BlendOpAlpha=D3D11_BLEND_OP_ADD;
|
||||
blendDesc.RenderTarget[0].RenderTargetWriteMask=D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
result=device->CreateBlendState(&blendDesc,&omBlendState);
|
||||
if (result!=S_OK) {
|
||||
logE("could not create blend state! %.8x",result);
|
||||
return false;
|
||||
}
|
||||
|
||||
createRenderTarget();
|
||||
return true;
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::initGUI(SDL_Window* win) {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGui_ImplSDL2_InitForD3D(win);
|
||||
ImGui_ImplDX11_Init(device,context);
|
||||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::quit() {
|
||||
destroyRenderTarget();
|
||||
|
||||
for (FurnaceDXTexture* i: textures) {
|
||||
i->view->Release();
|
||||
i->tex->Release();
|
||||
delete i;
|
||||
}
|
||||
textures.clear();
|
||||
|
||||
if (swapchain!=NULL) {
|
||||
swapchain->Release();
|
||||
swapchain=NULL;
|
||||
}
|
||||
if (context!=NULL) {
|
||||
context->Release();
|
||||
context=NULL;
|
||||
}
|
||||
if (device!=NULL) {
|
||||
device->Release();
|
||||
device=NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::quitGUI() {
|
||||
ImGui_ImplDX11_Shutdown();
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2023 tildearrow and contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../gui.h"
|
||||
#ifdef INCLUDE_D3D11
|
||||
#include <d3d11.h>
|
||||
#else
|
||||
typedef void ID3D11DeviceContext;
|
||||
typedef void ID3D11RenderTargetView;
|
||||
typedef void ID3D11Buffer;
|
||||
typedef void ID3D11RasterizerState;
|
||||
typedef void ID3D11BlendState;
|
||||
typedef void ID3D11VertexShader;
|
||||
typedef void ID3D11PixelShader;
|
||||
typedef void ID3D11InputLayout;
|
||||
typedef void IDXGISwapChain;
|
||||
#endif
|
||||
|
||||
struct FurnaceDXTexture;
|
||||
|
||||
class FurnaceGUIRenderDX11: public FurnaceGUIRender {
|
||||
ID3D11Device* device;
|
||||
ID3D11DeviceContext* context;
|
||||
ID3D11RenderTargetView* renderTarget;
|
||||
IDXGISwapChain* swapchain;
|
||||
ID3D11RasterizerState* rsState;
|
||||
ID3D11BlendState* omBlendState;
|
||||
|
||||
ID3D11Buffer* quadVertex;
|
||||
int outW, outH;
|
||||
|
||||
// SHADERS //
|
||||
// -> wipe
|
||||
ID3D11VertexShader* sh_wipe_vertex;
|
||||
ID3D11PixelShader* sh_wipe_fragment;
|
||||
ID3D11InputLayout* sh_wipe_inputLayout;
|
||||
ID3D11Buffer* sh_wipe_uniform;
|
||||
struct WipeUniform {
|
||||
float alpha;
|
||||
float padding[7];
|
||||
};
|
||||
|
||||
bool destroyRenderTarget();
|
||||
bool createRenderTarget();
|
||||
|
||||
std::vector<FurnaceDXTexture*> textures;
|
||||
|
||||
public:
|
||||
ImTextureID getTextureID(void* which);
|
||||
bool lockTexture(void* which, void** data, int* pitch);
|
||||
bool unlockTexture(void* which);
|
||||
bool updateTexture(void* which, void* data, int pitch);
|
||||
void* createTexture(bool dynamic, int width, int height);
|
||||
bool destroyTexture(void* which);
|
||||
void setTextureBlendMode(void* which, FurnaceGUIBlendMode mode);
|
||||
void setBlendMode(FurnaceGUIBlendMode mode);
|
||||
void resized(const SDL_Event& ev);
|
||||
void clear(ImVec4 color);
|
||||
bool newFrame();
|
||||
void createFontsTexture();
|
||||
void destroyFontsTexture();
|
||||
void renderGUI();
|
||||
void wipe(float alpha);
|
||||
void present();
|
||||
bool getOutputSize(int& w, int& h);
|
||||
int getWindowFlags();
|
||||
void preInit();
|
||||
bool init(SDL_Window* win);
|
||||
void initGUI(SDL_Window* win);
|
||||
void quitGUI();
|
||||
bool quit();
|
||||
FurnaceGUIRenderDX11():
|
||||
device(NULL),
|
||||
context(NULL),
|
||||
renderTarget(NULL),
|
||||
swapchain(NULL),
|
||||
rsState(NULL),
|
||||
omBlendState(NULL),
|
||||
quadVertex(NULL),
|
||||
outW(0),
|
||||
outH(0),
|
||||
sh_wipe_vertex(NULL),
|
||||
sh_wipe_fragment(NULL),
|
||||
sh_wipe_inputLayout(NULL),
|
||||
sh_wipe_uniform(NULL) {
|
||||
}
|
||||
};
|
|
@ -158,9 +158,11 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
ImGui::Text("Name");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::PushID(2+curSample);
|
||||
if (ImGui::InputText("##SampleName",&sample->name)) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
|
@ -1229,7 +1231,17 @@ void FurnaceGUI::drawSampleEdit() {
|
|||
}
|
||||
}
|
||||
|
||||
memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int));
|
||||
if ((pitch>>2)==sampleTexW) {
|
||||
memcpy(dataT,data,sampleTexW*sampleTexH*sizeof(unsigned int));
|
||||
} else {
|
||||
int srcY=0;
|
||||
int destY=0;
|
||||
for (int i=0; i<sampleTexH; i++) {
|
||||
memcpy(&dataT[destY],&data[srcY],sampleTexW*sizeof(unsigned int));
|
||||
srcY+=sampleTexW;
|
||||
destY+=pitch>>2;
|
||||
}
|
||||
}
|
||||
rend->unlockTexture(sampleTex);
|
||||
delete[] data;
|
||||
}
|
||||
|
|
|
@ -1303,6 +1303,11 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.renderBackend="SDL";
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RENDER_DX11
|
||||
if (ImGui::Selectable("DirectX 11",curRenderBackend=="DirectX 11")) {
|
||||
settings.renderBackend="DirectX 11";
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_RENDER_GL
|
||||
if (ImGui::Selectable("OpenGL",curRenderBackend=="OpenGL")) {
|
||||
settings.renderBackend="OpenGL";
|
||||
|
|
|
@ -56,7 +56,7 @@ void FurnaceGUI::drawSpeed(bool asChild) {
|
|||
if (tempoView) setHz/=2.5;
|
||||
if (setHz<1) setHz=1;
|
||||
if (setHz>999) setHz=999;
|
||||
e->setSongRate(setHz,setHz<52);
|
||||
e->setSongRate(setHz);
|
||||
}
|
||||
if (tempoView) {
|
||||
ImGui::SameLine();
|
||||
|
|
Loading…
Reference in New Issue