Merge branch 'master' of https://github.com/tildearrow/furnace into k053260
This commit is contained in:
commit
7aaa52297e
|
@ -15,8 +15,8 @@ android {
|
|||
}
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 26
|
||||
versionCode 161
|
||||
versionName "0.6pre6"
|
||||
versionCode 162
|
||||
versionName "0.6pre7"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.tildearrow.furnace"
|
||||
android:versionCode="161"
|
||||
android:versionName="0.6pre6"
|
||||
android:versionCode="162"
|
||||
android:versionName="0.6pre7"
|
||||
android:installLocation="auto">
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -8,6 +8,7 @@ the menu bar allows you to select five menus: file, edit, settings, window and h
|
|||
- **open...**: opens the file picker, allowing you to select a song to open.
|
||||
- **open recent**: contains a list of the songs you've opened before.
|
||||
- **clear history**: this option erases the file history.
|
||||
|
||||
- **save**: saves the current song.
|
||||
- opens the file picker if this is a new song, or a backup.
|
||||
- **save as...**: opens the file picker, allowing you to save the song under a different name.
|
||||
|
@ -29,12 +30,14 @@ the menu bar allows you to select five menus: file, edit, settings, window and h
|
|||
- Arcade (YM2151 + SegaPCM 5-channel compatibility)
|
||||
- Neo Geo CD (DefleMask 1.0+)
|
||||
- only use this option if you really need it. there are features which DefleMask does not support, like some effects and FM macros, so these will be lost.
|
||||
|
||||
- **export audio...**: export your song to a .wav file. see next section for more details.
|
||||
- **export VGM...**: export your song to a .vgm file. see next section for more details.
|
||||
- **export ZSM...**: export your song to a .zsm file. see next section for more details.
|
||||
- only available when there's a YM2151 and/or VERA.
|
||||
- **export command stream...**: export song data to a command stream file. see next section for more details.
|
||||
- this option is for developers.
|
||||
|
||||
- **add chip...**: add a chip to the current song.
|
||||
- **configure chip...**: set a chip's parameters.
|
||||
- for a list of parameters, see [7-systems](../7-systems/README.md).
|
||||
|
@ -42,6 +45,7 @@ the menu bar allows you to select five menus: file, edit, settings, window and h
|
|||
- **Preserve channel positions**: enable this option to make sure Furnace does not auto-arrange/delete channels to compensate for differing channel counts. this can be useful for doing ports, e.g. from Genesis to PC-98.
|
||||
- **remove chip...**: remove a chip.
|
||||
- **Preserve channel positions**: same thing as above.
|
||||
|
||||
- **restore backup**: restore a previously saved backup.
|
||||
- Furnace keeps up to 5 backups of a song.
|
||||
- the backup directory is located in:
|
||||
|
@ -49,6 +53,7 @@ the menu bar allows you to select five menus: file, edit, settings, window and h
|
|||
- macOS: `~/Library/Application Support/Furnace/backups`
|
||||
- Linux/other: `~/.config/furnace/backups`
|
||||
- this directory grows in size as you use Furnace. remember to delete old backups periodically to save space.
|
||||
|
||||
- **exit**: I think you know what this does.
|
||||
|
||||
## export audio
|
||||
|
@ -131,6 +136,7 @@ it's not really useful, unless you're a developer and want to use a command stre
|
|||
|
||||
- **undo**: reverts the last action.
|
||||
- **redo**: repeats what you undid previously.
|
||||
|
||||
- **cut**: moves the current selection in the pattern view to clipboard.
|
||||
- **copy**: copies the current selection in the pattern view to clipboard.
|
||||
- **paste**: inserts the clipboard's contents in the cursor position.
|
||||
|
@ -147,11 +153,16 @@ it's not really useful, unless you're a developer and want to use a command stre
|
|||
- if the selection is tall, it will select the entire column.
|
||||
- if a column is already selected, it will select the entire channel.
|
||||
- if a channel is already selected, it will select the entire pattern.
|
||||
|
||||
- **operation mask**: this is an advanced feature. see [this page](../3-pattern/opmask.md) for more information.
|
||||
- **input latch**: this is an advanced feature. see [this page](../3-pattern/inputlatch.md) for more information.
|
||||
|
||||
- **note/octave up/down**: transposes notes in the current selection.
|
||||
|
||||
- **values up/down**: changes values in the current selection by ±1 or ±16.
|
||||
|
||||
- **transpose**: transpose notes or change values by a specific amount.
|
||||
|
||||
- **interpolate**: fills in gaps in the selection by interpolation between values.
|
||||
- **change instrument**: changes the instrument number in a selection.
|
||||
- **gradient/fade**: replace the selection with a "gradient" that goes from the beginning of the selection to the end.
|
||||
|
@ -163,17 +174,22 @@ it's not really useful, unless you're a developer and want to use a command stre
|
|||
- **randomize**: replaces the selection with random values.
|
||||
- does not affect the note column.
|
||||
- **invert values**: `00` becomes `FF`, `01` becomes `FE`, `02` becomes `FD` and so on.
|
||||
|
||||
- **flip selection**: flips the selection so it is backwards.
|
||||
- **collapse/expand amount**: allows you to specify how much to collapse/expand in the next options.
|
||||
- **collapse**: shrinks the selected contents.
|
||||
- **expand**: expands the selected contents.
|
||||
|
||||
- **collapse pattern**: same as collapse, but affects the entire pattern.
|
||||
- **expand pattern**: same as expand, but affects the entire pattern.
|
||||
|
||||
- **collapse song**: same as collapse, but affects the entire song.
|
||||
- it also changes speeds and pattern length to compensate.
|
||||
- **expand song**: same as expand, but affects the entire song.
|
||||
- it also changes speeds and pattern length to compensate.
|
||||
|
||||
- **find/replace**: opens the Find/Replace window. see [this page](../3-pattern/find-replace.md) for more information.
|
||||
|
||||
- **clear**: allows you to mass-delete things like songs, instruments and the like.
|
||||
|
||||
# settings
|
||||
|
@ -202,9 +218,11 @@ it's not really useful, unless you're a developer and want to use a command stre
|
|||
- **chip manager**: shows/hides the Chip Manager window.
|
||||
- **compatibility flags**: shows/hides the Compatibility Flags window.
|
||||
- **song comments**: shows/hides the Song Comments window.
|
||||
- **instrument editor**: shows/hides the Instrument Editor.
|
||||
|
||||
- **instrument editor**: shows/hides the Instrument Editor
|
||||
- **wavetable editor**: shows/hides the Wavetable Editor.
|
||||
- **sample editor**: shows/hides the Sample Editor.
|
||||
|
||||
- **play/edit controls**: shows/hides the Play/Edit Controls.
|
||||
- **piano/input pad**: shows/hides the Piano/Input Pad window.
|
||||
- **oscilloscope (master)**: shows/hides the oscilloscope.
|
||||
|
|
|
@ -7,17 +7,15 @@ however, effects are continuous, which means you only need to type it once and t
|
|||
## volume
|
||||
|
||||
- `0Axy`: **Volume slide.**
|
||||
- If `x` is 0 then this is a slide down.
|
||||
- If `y` is 0 then this is a slide up.
|
||||
- `F8xx`: **Single tick volume slide up.**
|
||||
- `F9xx`: **Single tick volume slide down.**
|
||||
- `F3xx`: **Fine volume slide up.** 64× slower than `0Axy`.
|
||||
- `F4xx`: **Fine volume slide down.** 64× slower than `0Axy`.
|
||||
- `FAxy`: **Fast volume slide.** 4× faster than `0Axy`.
|
||||
- If `x` is 0 then this is a slide down.
|
||||
- If `y` is 0 then this is a slide up.
|
||||
- If `x` is 0 then this slides volume down by `y` each tick.
|
||||
- If `y` is 0 then this slides volume up by `x` each tick.
|
||||
- `FAxy`: **Fast volume slide.** same as `0Axy` above but 4× faster.
|
||||
- `F3xx`: **Fine volume slide up.** same as `0Ax0` but 64× slower.
|
||||
- `F4xx`: **Fine volume slide down.** same as `0A0x` but 64× slower.
|
||||
- `F8xx`: **Single tick volume slide up.** adds `x` to volume on first tick only.
|
||||
- `F9xx`: **Single tick volume slide down.** subtracts `x` from volume on first tick only.
|
||||
|
||||
- `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth.
|
||||
- `07xy`: **Tremolo.** changes volume to be "wavy" with a sine LFO. `x` is the speed. `y` is the depth.
|
||||
- Tremolo is downward only.
|
||||
- Maximum tremolo depth is -60 volume steps.
|
||||
|
||||
|
@ -29,21 +27,22 @@ however, effects are continuous, which means you only need to type it once and t
|
|||
- `F1xx`: **Single tick pitch slide up.**
|
||||
- `F2xx`: **Single tick pitch slide down.**
|
||||
|
||||
- `03xx`: **Portamento.** slides the current note's pitch to the specified note.
|
||||
- `03xx`: **Portamento.** slides the current note's pitch to the specified note. `x` is the slide speed.
|
||||
- A note _must_ be present for this effect to work.
|
||||
- `E1xy`: **Note slide up.** `x` is the speed, while `y` is how many semitones to slide up.
|
||||
- `E2xy`: **Note slide down.** `x` is the speed, while `y` is how many semitones to slide down.
|
||||
|
||||
- `EAxx`: **Toggle legato.** while on, notes instantly change the pitch of the currrently playing sound instead of starting it over.
|
||||
- `00xy`: **Arpeggio.** after using this effect the channel will rapidly switch between semitone values of `note`, `note + x` and `note + y`.
|
||||
- `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values.
|
||||
- `E0xx`: **Set arpeggio speed.** this sets the number of ticks between arpeggio values. default is 1.
|
||||
|
||||
- `04xy`: **Vibrato.** changes pitch to be "wavy" with a sine LFO. `x` is the speed, while `y` is the depth.
|
||||
- Maximum vibrato depth is ±1 semitone.
|
||||
- `E3xx`: **Set vibrato direction.** `xx` may be one of the following:
|
||||
- `00`: Up and down.
|
||||
- `00`: Up and down. default.
|
||||
- `01`: Up only.
|
||||
- `02`: Down only.
|
||||
- `E4xx`: **Set vibrato range** in 1/16th of a semitone.
|
||||
- `E4xx`: **Set vibrato range** in 1/16th of a semitone.
|
||||
|
||||
## panning
|
||||
|
||||
|
@ -51,15 +50,15 @@ not all chips support these effects.
|
|||
|
||||
- `08xy`: **Set panning.** changes stereo volumes independently. `x` is the left channel and `y` is the right one.
|
||||
- `88xy`: **Set rear panning.** changes rear channel volumes independently. `x` is the rear left channel and `y` is the rear right one.
|
||||
- `81xx`: **Set volume of left channel** (from `00` to `FF`).
|
||||
- `82xx`: **Set volume of right channel** (from `00` to `FF`).
|
||||
- `89xx`: **Set volume of rear left channel** (from `00` to `FF`).
|
||||
- `8Axx`: **Set volume of rear right channel** (from `00` to `FF`).
|
||||
|
||||
- `80xx`: **Set panning (linear).** this effect behaves more like other trackers:
|
||||
- `00` is left.
|
||||
- `80` is center.
|
||||
- `FF` is right.
|
||||
- `81xx`: **Set volume of left channel** (from `00` to `FF`).
|
||||
- `82xx`: **Set volume of right channel** (from `00` to `FF`).
|
||||
- `89xx`: **Set volume of rear left channel** (from `00` to `FF`).
|
||||
- `8Axx`: **Set volume of rear right channel** (from `00` to `FF`).
|
||||
|
||||
## time
|
||||
|
||||
|
@ -67,12 +66,14 @@ not all chips support these effects.
|
|||
- `0Fxx`: **Set speed 2.** during alternating speeds or a groove, this sets the second speed.
|
||||
|
||||
- `Cxxx`: **Set tick rate.** changes tick rate to `xxx` Hz (ticks per second).
|
||||
- `xxx` may be from `000` to `3ff`.
|
||||
- `F0xx`: **Set BPM.** changes tick rate according to beats per minute.
|
||||
- `xxx` may be from `000` to `3FF`.
|
||||
- `F0xx`: **Set BPM.** changes tick rate according to beats per minute. range is `01` to `FF`.
|
||||
|
||||
- `0Bxx`: **Jump to order.** this can be used to loop a song.
|
||||
- `0Dxx`: **Jump to next pattern.** this can be used to shorten the current order.
|
||||
- `FFxx`: **Stop song.** stops playback and ends the song.
|
||||
- `0Bxx`: **Jump to order.** `x` is the order to play after the current row.
|
||||
- this marks the end of a loop with order `x` as the loop start.
|
||||
- `0Dxx`: **Jump to next pattern.** skips the current row and remainder of current order.
|
||||
- this can be used to shorten the current order.
|
||||
- `FFxx`: **Stop song.** stops playback and ends the song. `x` is ignored.
|
||||
|
||||
## note
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ this is a list of sound chips that Furnace supports, including effects.
|
|||
- [PC Engine/TurboGrafx-16](pce.md)
|
||||
- [PC Speaker](pcspkr.md)
|
||||
- [Philips SAA1099](saa1099.md)
|
||||
- [Pokémon mini](pokemini.md)
|
||||
- [Capcom QSound](qsound.md)
|
||||
- [Ricoh RF5C68](ricoh.md)
|
||||
- [SegaPCM](segapcm.md)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
the Nintendo Game Boy is one of the most successful portable game systems ever made.
|
||||
|
||||
with stereo sound, two pulse channels, a wave channel and a noise one it packed some serious punch.
|
||||
with stereo sound, two pulse channels, a wave channel and a noise channel, it packed some serious punch.
|
||||
|
||||
# effects
|
||||
|
||||
|
@ -20,3 +20,9 @@ with stereo sound, two pulse channels, a wave channel and a noise one it packed
|
|||
- `y` is the shift.
|
||||
- set to `0` to disable it.
|
||||
- `14xx`: **set sweep direction.** `0` is up and `1` is down.
|
||||
|
||||
# links
|
||||
|
||||
- [Gameboy sound hardware](https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware) - detailed technical information
|
||||
|
||||
- [GameBoy Sound Table](http://www.devrs.com/gb/files/sndtab.html) - note frequency table
|
|
@ -0,0 +1,7 @@
|
|||
# Pokémon Mini
|
||||
|
||||
the Pokémon Mini is a ridiculously small handheld system from 2001. its single pulse channel has only three volume steps (full, half, and off)... but variable pulse width.
|
||||
|
||||
# effects
|
||||
|
||||
none.
|
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
|
@ -1,16 +1,53 @@
|
|||
# oscilloscope (per channel)
|
||||
|
||||
The "Oscilloscope (per channel)" dialog shows an individual oscilloscope for each channel during playback.
|
||||
the "Oscilloscope (per channel)" dialog shows an individual oscilloscope for each channel during playback.
|
||||
|
||||
![oscilloscope per-channel configuration view](chanosc.png)
|
||||
|
||||
Right-clicking within the view will change it to the configuration view shown above:
|
||||
- **Columns**: Sets the number of columns the view will be split into.
|
||||
- **Size (ms)**: Sets what length of audio is visible in each oscilloscope.
|
||||
- **Center waveform**: Does its best to latch to the channel's note frequency and centers the display.
|
||||
- **Gradient**: (document this)
|
||||
- The color selector sets the waveform color. Right-clicking on it pops up an option dialog:
|
||||
- Select between the square selector and the color wheel selector.
|
||||
- **Alpha bar**: Adds a transparency selector.
|
||||
- The boxes below that are for selecting colors numerically by red-green-blue-alpha, hue-saturation-value-alpha, and HTML-style RGBA in hex.
|
||||
- The OK button returns from options view to regular.
|
||||
right-clicking within the view will change it to the configuration view shown above:
|
||||
- **Columns**: arranges oscilloscopes into this many columns.
|
||||
- **Size (ms)**: sets what length of audio is visible in each oscilloscope.
|
||||
- **Center waveform**: does its best to latch the waveform to the channel's note frequency and centers the display.
|
||||
- **Gradient**: see below.
|
||||
- the color selector sets the waveform color. right-clicking on it pops up an option dialog:
|
||||
- select between the square selector and the color wheel selector.
|
||||
- **Alpha bar**: adds a transparency selector.
|
||||
- the boxes below that are for selecting colors numerically by red-green-blue-alpha, hue-saturation-value-alpha, and HTML-style RGBA in hex.
|
||||
- **Text format**: this string determins what text is shown in the top-left of each oscilloscope. it can be any text, and the following shortcodes will be replaced with information about the channel:
|
||||
- `%c`: channel name
|
||||
- `%C`: channel short name
|
||||
- `%d`: channel number (starting from 0)
|
||||
- `%D`: channel number (starting from 1)
|
||||
- `%i`: instrument name
|
||||
- `%I`: instrument number (decimal)
|
||||
- `%x`: instrument number (hex)
|
||||
- `%s`: chip name
|
||||
- `%S`: chip ID
|
||||
- `%v`: volume (decimal)
|
||||
- `%V`: volume (percentage)
|
||||
- `%b`: volume (hex)
|
||||
- `%%`: percent sign
|
||||
- The OK button returns from options view to the oscilloscopes.
|
||||
|
||||
## gradient
|
||||
|
||||
![oscilloscope per-channel gradient configuration view](chanosc-gradient.png)
|
||||
|
||||
in this mode, the color selector is replaced by a square field onto which circular "stops" can be placed. each stop adds a soft circle of color. the resulting image is used to look up the oscilloscope color as determined by each axis.
|
||||
|
||||
- right-click to place a stop.
|
||||
- left-click on a stop to change its color. the color selector is the same as above, with two additions:
|
||||
- **Distance**: the size of the circle.
|
||||
- **Spread**: the size of the solid center of the circle. increasing it fills more of the circle with the target color.
|
||||
|
||||
- **Background**: sets background color for entire field.
|
||||
- **X Axis**: determines what the horizontal maps to, from left to right.\
|
||||
**Y Axis**: determines what the vertical maps to, from bottom to top. these can be set to the following:
|
||||
- **None (0%)**: stays at the left or bottom.
|
||||
- **None (50%)**: stays at the center.
|
||||
- **None (100%)**: stays at the right or top.
|
||||
- **Frequency**: changes color with note frequency.
|
||||
- **Volume**: changes color with volume.
|
||||
- **Channel**: changes color based on channel number.
|
||||
- **Brightness**: {{document this}}
|
||||
- **Note Trigger**: changes color when a new note is played.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 113 KiB |
|
@ -339,17 +339,22 @@ static void ImGui_ImplDX11_CreateFontsTexture()
|
|||
subResource.SysMemPitch = desc.Width * 4;
|
||||
subResource.SysMemSlicePitch = 0;
|
||||
bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
|
||||
IM_ASSERT(pTexture != nullptr);
|
||||
|
||||
// Create texture view
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||
pTexture->Release();
|
||||
if (pTexture != nullptr) {
|
||||
// Create texture view
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||
ZeroMemory(&srvDesc, sizeof(srvDesc));
|
||||
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = desc.MipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView);
|
||||
pTexture->Release();
|
||||
} else {
|
||||
bd->pFontTextureView=NULL;
|
||||
bd->pFontSampler=NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Store our identifier
|
||||
|
@ -609,13 +614,15 @@ void ImGui_ImplDX11_Shutdown()
|
|||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplDX11_NewFrame()
|
||||
bool ImGui_ImplDX11_NewFrame()
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX11_Init()?");
|
||||
|
||||
if (!bd->pFontSampler)
|
||||
ImGui_ImplDX11_CreateDeviceObjects();
|
||||
|
||||
return bd->pFontSampler!=NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -19,7 +19,7 @@ struct ID3D11DeviceContext;
|
|||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX11_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing Dear ImGui state.
|
||||
|
|
|
@ -208,6 +208,8 @@
|
|||
#define GL_CALL(_CALL) _CALL // Call without error check
|
||||
#endif
|
||||
|
||||
#define GL_CALL_FALSE(_CALL) _CALL; { GLenum gl_err = glGetError(); if (gl_err != 0) return false; }
|
||||
|
||||
// OpenGL Data
|
||||
struct ImGui_ImplOpenGL3_Data
|
||||
{
|
||||
|
@ -389,13 +391,14 @@ void ImGui_ImplOpenGL3_Shutdown()
|
|||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
bool ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?");
|
||||
|
||||
if (!bd->ShaderHandle)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
return ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
|
||||
|
@ -674,14 +677,14 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
|||
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||
GLint last_texture;
|
||||
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
|
||||
GL_CALL(glGenTextures(1, &bd->FontTexture));
|
||||
GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
GL_CALL_FALSE(glGenTextures(1, &bd->FontTexture));
|
||||
GL_CALL_FALSE(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
|
||||
GL_CALL_FALSE(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
GL_CALL_FALSE(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
|
||||
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
GL_CALL_FALSE(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
|
||||
#endif
|
||||
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
GL_CALL_FALSE(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
||||
|
@ -918,7 +921,9 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
|||
glGenBuffers(1, &bd->VboHandle);
|
||||
glGenBuffers(1, &bd->ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
bool whatReturn=true;
|
||||
|
||||
if (!ImGui_ImplOpenGL3_CreateFontsTexture()) whatReturn=false;
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
@ -927,7 +932,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
|||
glBindVertexArray(last_vertex_array);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return whatReturn;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// Backend API
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// (Optional) Called by Init/NewFrame/Shutdown
|
||||
|
|
|
@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1).
|
|||
|
||||
the format versions are:
|
||||
|
||||
- 162: Furnace 0.6pre7
|
||||
- 161: Furnace 0.6pre6
|
||||
- 160: Furnace dev160
|
||||
- 159: Furnace dev159
|
||||
|
@ -309,6 +310,7 @@ size | description
|
|||
| - 0xc9: M114S - 16 channels
|
||||
| - 0xca: ZX Spectrum (beeper, QuadTone engine) - 5 channels
|
||||
| - 0xcb: Casio PV-1000 - 3 channels
|
||||
| - 0xcc: K053260 - 4 channels
|
||||
| - 0xde: YM2610B extended - 19 channels
|
||||
| - 0xe0: QSound - 19 channels
|
||||
| - 0xfc: Pong - 1 channel
|
||||
|
|
|
@ -0,0 +1,404 @@
|
|||
# multiplayer protocol
|
||||
|
||||
this is a concept! it has not been implemented yet!
|
||||
|
||||
the Furnace protocol is described here.
|
||||
|
||||
# information
|
||||
|
||||
all numbers are little-endian.
|
||||
|
||||
the following fields may be found in "size":
|
||||
- `f` indicates a floating point number.
|
||||
- `STR` is a UTF-8 zero-terminated string.
|
||||
- `CFG` is the same as STR, but contains a config.
|
||||
- `???` is an array of variable size.
|
||||
- `S??` is an array of `STR`s.
|
||||
- `1??` is an array of bytes.
|
||||
- `2??` is an array of shorts.
|
||||
- `4??` is an array of ints.
|
||||
|
||||
two player IDs are reserved:
|
||||
- 0: system
|
||||
- 1: host (console)
|
||||
|
||||
two usernames are reserved:
|
||||
- SYSTEM
|
||||
- HOST
|
||||
|
||||
some characters are not allowed in usernames: 0x00-0x1f, `@`, 0x7f-0x9f, 0xd800-0xdfff, 0xfeff, 0xfffe and 0xffff.
|
||||
|
||||
# header
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
3 | "fur" header
|
||||
1 | packet type
|
||||
4 | sequence number
|
||||
```
|
||||
the sequence number always starts at 0.
|
||||
|
||||
# client to server packets (init)
|
||||
|
||||
## 0x00: keep-alive
|
||||
|
||||
this packet keeps a connection alive.
|
||||
the server shall respond with a packet of type 0x00 (keep-alive).
|
||||
if the client does not receive any packets during 30 seconds, it will disconnect from the server.
|
||||
likewise, if the server does not receive any packets during 30 seconds, it will disconnect the client.
|
||||
|
||||
## 0x01: start connection
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | reason
|
||||
| - 0: information
|
||||
| - 1: join
|
||||
3 | padding
|
||||
4 | client version
|
||||
STR | host name (may be blank)
|
||||
```
|
||||
after sending, you will receive a packet of type 0x01 (information), 0x02 (disconnect) or 0x03 (authenticate).
|
||||
|
||||
## 0x02: disconnect
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
STR | reason
|
||||
```
|
||||
## 0x03: auth response
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | type
|
||||
| - 0: open
|
||||
| - 1: password
|
||||
| - 2: token
|
||||
--- | **open response**
|
||||
STR | username
|
||||
--- | **password response**
|
||||
1 | password type
|
||||
| - 0: plain text
|
||||
| - 1: SHA-512
|
||||
STR | account name
|
||||
??? | password
|
||||
--- | **token response**
|
||||
STR | token
|
||||
```
|
||||
# server to client packets (init)
|
||||
|
||||
## 0x00: keep-alive
|
||||
|
||||
this packet keeps a connection alive. it is a response to a client's keep-alive packet.
|
||||
|
||||
## 0x01: information
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | server version
|
||||
2 | online players
|
||||
| - if it is 65535, this information is concealed.
|
||||
2 | maximum players
|
||||
| - 0 means unlimited.
|
||||
STR | server version (string)
|
||||
STR | server name
|
||||
STR | server description
|
||||
STR | project name
|
||||
```
|
||||
the client may send a 0x00 (keep-alive) packet after receiving this one within 5 seconds.
|
||||
connection is then closed.
|
||||
|
||||
## 0x02: disconnect
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
STR | reason
|
||||
```
|
||||
after being sent, the connection is closed.
|
||||
|
||||
## 0x03: authenticate
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | authentication type
|
||||
| - 0: open
|
||||
| - 1: password
|
||||
| - 2: token
|
||||
```
|
||||
## 0x04: authentication success
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | player ID
|
||||
STR | username
|
||||
CFG | properties
|
||||
```
|
||||
# client to server packets (session)
|
||||
|
||||
## 0x10: request project
|
||||
|
||||
the client may only send this once every minute.
|
||||
|
||||
## 0x11: participate
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | status
|
||||
| - 0: spectate
|
||||
| - 1: join
|
||||
```
|
||||
## 0x12: send chat message
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
STR | message
|
||||
```
|
||||
## 0x13: send command
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
STR | command
|
||||
2 | number of arguments
|
||||
S?? | arguments
|
||||
```
|
||||
## 0x14: get player list
|
||||
|
||||
no other information required.
|
||||
|
||||
## 0x15: project submission request
|
||||
|
||||
no other information required
|
||||
|
||||
## 0x16: project submission information
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | project size
|
||||
32 | SHA-256 sum of project
|
||||
STR | project name
|
||||
```
|
||||
this is followed by several 0x17 (project data) packets representing a Furnace song. see [format.md](format.md) for more information.
|
||||
|
||||
## 0x17: project submission data
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | offset
|
||||
4 | length
|
||||
??? | data...
|
||||
```
|
||||
the client will send a packet with project size as offset and 0 as length to indicate end of data.
|
||||
the server subsequently loads the project.
|
||||
|
||||
# server to client packets (session)
|
||||
|
||||
## 0x10: project information
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | project size
|
||||
32 | SHA-256 sum of project
|
||||
STR | project name
|
||||
```
|
||||
this is followed by several 0x13 (project data) packets representing a Furnace song. see [format.md](format.md) for more information.
|
||||
|
||||
## 0x11: project data
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | offset
|
||||
4 | length
|
||||
??? | data...
|
||||
```
|
||||
the server will send a packet with project size as offset and 0 as length to indicate end of data.
|
||||
the client subsequently loads the project.
|
||||
|
||||
## 0x12: participate status
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | status
|
||||
| - 0: denied
|
||||
| - 1: allowed
|
||||
|
||||
## 0x13: message
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | player ID
|
||||
8 | time (seconds)
|
||||
4 | time (nanoseconds)
|
||||
4 | message ID
|
||||
1 | type
|
||||
| - 0: chat, public
|
||||
| - 1: chat, private
|
||||
| - 2: notification, info
|
||||
| - 3: notification, warning
|
||||
| - 4: notification, urgent
|
||||
STR | message
|
||||
```
|
||||
## 0x14: system message
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
STR | message
|
||||
```
|
||||
## 0x15: chat message edited
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | message ID
|
||||
STR | message
|
||||
| - an empty message means deleted.
|
||||
```
|
||||
## 0x16: player list
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
2 | number of players
|
||||
--- | **player entry** (×players)
|
||||
4 | ID
|
||||
2 | latency (ms)
|
||||
1 | participating?
|
||||
| - 0: no
|
||||
| - 1: yes
|
||||
1 | status
|
||||
| - 0: normal
|
||||
| - 1: away
|
||||
| - 2: busy
|
||||
STR | name
|
||||
STR | IP address
|
||||
| - if empty, then server is not disclosing IP addresses.
|
||||
```
|
||||
this is sent after receiving 0x14 (get player list).
|
||||
|
||||
## 0x17: project submission request status
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | status
|
||||
| - 0: denied
|
||||
| - 1: allowed
|
||||
```
|
||||
this is sent after a project submission request is accepted.
|
||||
if the status is 1, the client shall submit a project.
|
||||
|
||||
## 0x18: project submission complete
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | status
|
||||
| - 0: error
|
||||
| - 1: success
|
||||
STR | additional information
|
||||
```
|
||||
## 0x19: player joined
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | ID
|
||||
STR | name
|
||||
```
|
||||
## 0x1a: player left
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | ID
|
||||
```
|
||||
# client to server packets (project)
|
||||
|
||||
## 0x20: request orders
|
||||
|
||||
## 0x21: request instrument
|
||||
|
||||
## 0x22: request wavetable
|
||||
|
||||
## 0x23: request sample
|
||||
|
||||
## 0x24: request patterns
|
||||
|
||||
## 0x25: request sub-song
|
||||
|
||||
## 0x26: request song info
|
||||
|
||||
## 0x27: request asset list
|
||||
|
||||
## 0x28: request patchbay
|
||||
|
||||
## 0x29: request grooves
|
||||
|
||||
## 0x30: alter orders
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
4 | transaction ID
|
||||
```
|
||||
## 0x31: alter instrument
|
||||
|
||||
## 0x32: alter wavetable
|
||||
|
||||
## 0x33: alter sample
|
||||
|
||||
## 0x34: alter pattern
|
||||
|
||||
## 0x35: alter sub-song
|
||||
|
||||
## 0x36: alter song info
|
||||
|
||||
## 0x37: alter asset list
|
||||
|
||||
## 0x38: alter patchbay
|
||||
|
||||
## 0x39: alter grooves
|
||||
|
||||
## 0x3a: alter chips
|
||||
|
||||
## 0x3b: alter chip settings
|
||||
|
||||
# server to client packets (project)
|
||||
|
||||
## 0x20: orders
|
||||
|
||||
## 0x21: instrument
|
||||
|
||||
## 0x22: wavetable
|
||||
|
||||
## 0x23: sample
|
||||
|
||||
## 0x24: pattern
|
||||
|
||||
## 0x25: sub-song
|
||||
|
||||
## 0x26: song info
|
||||
|
||||
## 0x27: asset list
|
||||
|
||||
## 0x28: patchbay
|
||||
|
||||
## 0x29: grooves
|
||||
|
||||
## 0x30: transaction response
|
||||
```
|
||||
size | description
|
||||
-----|------------------------------------
|
||||
1 | status
|
||||
| - 0: error
|
||||
| - 1: success
|
||||
| - 2: success but request again
|
||||
STR | additional information
|
||||
```
|
||||
# client to server packets (interact)
|
||||
|
||||
## 0x40: engine command
|
||||
|
||||
## 0x41: playback
|
||||
|
||||
# server to client packets (interact)
|
||||
|
||||
## 0x40: engine command
|
||||
|
||||
## 0x41: playback
|
||||
|
||||
# client to server packets (extension)
|
||||
|
||||
# server to client packets (extension)
|
|
@ -15,17 +15,17 @@
|
|||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>0.6pre6</string>
|
||||
<string>0.6pre7</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Furnace</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.6pre6</string>
|
||||
<string>0.6pre7</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0.6pre6</string>
|
||||
<string>0.6pre7</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
|
|
|
@ -288,6 +288,9 @@ struct DivRegWrite {
|
|||
* - x is the instance ID
|
||||
* - 0xffffxx04: switch sample bank
|
||||
* - for use in VGM export
|
||||
* - 0xffffxx05: set sample position
|
||||
* - xx is the instance ID
|
||||
* - data is the sample position
|
||||
* - 0xffffffff: reset
|
||||
*/
|
||||
unsigned int addr;
|
||||
|
|
|
@ -54,8 +54,10 @@
|
|||
#define EXTERN_BUSY_BEGIN_SOFT e->softLocked=true; e->isBusy.lock();
|
||||
#define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false;
|
||||
|
||||
#define DIV_VERSION "0.6pre6"
|
||||
#define DIV_ENGINE_VERSION 161
|
||||
#define DIV_UNSTABLE
|
||||
|
||||
#define DIV_VERSION "dev163"
|
||||
#define DIV_ENGINE_VERSION 163
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
#define DIV_VERSION_FC 0xff02
|
||||
|
@ -489,7 +491,7 @@ class DivEngine {
|
|||
void processRow(int i, bool afterDelay);
|
||||
void nextOrder();
|
||||
void nextRow();
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream);
|
||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream);
|
||||
// returns true if end of song.
|
||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||
|
|
|
@ -63,7 +63,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
|
|||
for (int i=5; i<7; i++) {
|
||||
if (chan[i].dacSample!=-1) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (!isMuted[i] && s->samples>0) {
|
||||
if (!isMuted[i] && s->samples>0 && chan[i].dacPos<s->samples) {
|
||||
if (parent->song.noOPN2Vol) {
|
||||
chan[i].dacOutput=s->data8[chan[i].dacDirection?(s->samples-chan[i].dacPos-1):chan[i].dacPos];
|
||||
} else {
|
||||
|
@ -110,7 +110,7 @@ void DivPlatformGenesis::processDAC(int iRate) {
|
|||
chan[5].dacPeriod+=chan[5].dacRate;
|
||||
if (chan[5].dacPeriod>=iRate) {
|
||||
DivSample* s=parent->getSample(chan[5].dacSample);
|
||||
if (s->samples>0) {
|
||||
if (s->samples>0 && chan[5].dacPos<s->samples) {
|
||||
if (!isMuted[5]) {
|
||||
if (chan[5].dacReady && writes.size()<16) {
|
||||
int sample;
|
||||
|
@ -122,10 +122,6 @@ void DivPlatformGenesis::processDAC(int iRate) {
|
|||
urgentWrite(0x2a,(unsigned char)sample+0x80);
|
||||
chan[5].dacReady=false;
|
||||
}
|
||||
} else {
|
||||
if (chan[5].dacReady && writes.size()<16) {
|
||||
urgentWrite(0x2a,0x80);
|
||||
}
|
||||
}
|
||||
chan[5].dacPos++;
|
||||
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {
|
||||
|
@ -597,6 +593,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) {
|
|||
isMuted[ch]=mute;
|
||||
if (ch>6) return;
|
||||
if (ch<6) {
|
||||
if (ch==5) immWrite(0x2a,0x80);
|
||||
for (int j=0; j<4; j++) {
|
||||
unsigned short baseAddr=chanOffs[ch]|opOffs[j];
|
||||
DivInstrumentFM::Operator& op=chan[ch].state.op[j];
|
||||
|
@ -704,7 +701,11 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
addWrite(0xffff0003,chan[c.chan].dacDirection);
|
||||
}
|
||||
}
|
||||
chan[c.chan].dacPos=0;
|
||||
if (chan[c.chan].setPos) {
|
||||
chan[c.chan].setPos=false;
|
||||
} else {
|
||||
chan[c.chan].dacPos=0;
|
||||
}
|
||||
chan[c.chan].dacPeriod=0;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
|
||||
|
@ -927,6 +928,12 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
if (dumpWrites) addWrite(0xffff0003,chan[c.chan].dacDirection);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_SAMPLE_POS:
|
||||
if (c.chan<5) c.chan=5;
|
||||
chan[c.chan].dacPos=c.value;
|
||||
chan[c.chan].setPos=true;
|
||||
if (dumpWrites) addWrite(0xffff0005,chan[c.chan].dacPos);
|
||||
break;
|
||||
case DIV_CMD_LEGATO: {
|
||||
if (c.chan==csmChan) {
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
|
|
|
@ -57,6 +57,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
int dacDelay;
|
||||
bool dacReady;
|
||||
bool dacDirection;
|
||||
bool setPos;
|
||||
unsigned char sampleBank;
|
||||
signed char dacOutput;
|
||||
Channel():
|
||||
|
@ -70,6 +71,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
|||
dacDelay(0),
|
||||
dacReady(true),
|
||||
dacDirection(false),
|
||||
setPos(false),
|
||||
sampleBank(0),
|
||||
dacOutput(0) {}
|
||||
};
|
||||
|
|
|
@ -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]<<1;
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=MAX(d65010g031.out[i]<<2,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,6 +141,7 @@ template<bool IsOpnA>
|
|||
bool opn_registers_base<IsOpnA>::write(uint16_t index, uint8_t data, uint32_t &channel, uint32_t &opmask)
|
||||
{
|
||||
assert(index < REGISTERS);
|
||||
if (index >= REGISTERS) return false;
|
||||
|
||||
// writes in the 0xa0-af/0x1a0-af region are handled as latched pairs
|
||||
// borrow unused registers 0xb8-bf/0x1b8-bf as temporary holding locations
|
||||
|
|
|
@ -236,9 +236,12 @@ void DivPlatformVERA::tick(bool sysTick) {
|
|||
if (s->samples>0) {
|
||||
if (s->isLoopable()) {
|
||||
// Inform the export process of the loop point for this sample
|
||||
addWrite(67,s->loopStart&0xff);
|
||||
addWrite(67,(s->loopStart>>8)&0xff);
|
||||
addWrite(67,(s->loopStart>>16)&0xff);
|
||||
int tmp_ls=(s->loopStart<<1); // for stereo
|
||||
if (chan[16].pcm.depth16)
|
||||
tmp_ls<<=1; // for 16 bit
|
||||
addWrite(67,tmp_ls&0xff);
|
||||
addWrite(67,(tmp_ls>>8)&0xff);
|
||||
addWrite(67,(tmp_ls>>16)&0xff);
|
||||
}
|
||||
while (true) {
|
||||
short tmp_l=0;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream) {
|
||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream) {
|
||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||
unsigned char baseAddr2=isSecond?0x80:0;
|
||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||
|
@ -620,15 +620,35 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
pendingFreq[streamID]=write.val;
|
||||
} else {
|
||||
DivSample* sample=song.sample[write.val];
|
||||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
|
||||
int pos=sampleOff8[write.val&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[write.val&0xff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
if (setPos[streamID]!=0) {
|
||||
if (len<=0) {
|
||||
w->writeC(0x94);
|
||||
w->writeC(streamID);
|
||||
} else {
|
||||
w->writeC(0x93);
|
||||
w->writeC(streamID);
|
||||
w->writeI(pos);
|
||||
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
w->writeI(len);
|
||||
}
|
||||
} else {
|
||||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(write.val); // sample number
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
|
||||
}
|
||||
|
||||
if (sample->isLoopable() && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=sample->length8;
|
||||
loopTimer[streamID]=len;
|
||||
loopSample[streamID]=write.val;
|
||||
}
|
||||
playingSample[streamID]=write.val;
|
||||
setPos[streamID]=0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -642,16 +662,36 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
loopFreq[streamID]=realFreq;
|
||||
if (pendingFreq[streamID]!=-1) {
|
||||
DivSample* sample=song.sample[pendingFreq[streamID]];
|
||||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(pendingFreq[streamID]); // sample number
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
|
||||
int pos=sampleOff8[pendingFreq[streamID]&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[pendingFreq[streamID]&0xff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
if (setPos[streamID]!=0) {
|
||||
if (len<=0) {
|
||||
w->writeC(0x94);
|
||||
w->writeC(streamID);
|
||||
} else {
|
||||
w->writeC(0x93);
|
||||
w->writeC(streamID);
|
||||
w->writeI(pos);
|
||||
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
w->writeI(len);
|
||||
}
|
||||
} else {
|
||||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(pendingFreq[streamID]); // sample number
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
|
||||
}
|
||||
|
||||
if (sample->isLoopable() && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=sample->length8;
|
||||
loopTimer[streamID]=len;
|
||||
loopSample[streamID]=pendingFreq[streamID];
|
||||
}
|
||||
playingSample[streamID]=pendingFreq[streamID];
|
||||
pendingFreq[streamID]=-1;
|
||||
setPos[streamID]=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -665,6 +705,41 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
|||
case 3: // set sample direction
|
||||
sampleDir[streamID]=write.val;
|
||||
break;
|
||||
case 5: // set sample pos
|
||||
setPos[streamID]=write.val;
|
||||
|
||||
if (playingSample[streamID]!=-1 && pendingFreq[streamID]==-1) {
|
||||
// play the sample again
|
||||
DivSample* sample=song.sample[playingSample[streamID]];
|
||||
int pos=sampleOff8[playingSample[streamID]&0xff]+setPos[streamID];
|
||||
int len=(int)sampleLen8[playingSample[streamID]&0xff]-setPos[streamID];
|
||||
|
||||
if (len<0) len=0;
|
||||
|
||||
if (setPos[streamID]!=0) {
|
||||
if (len<=0) {
|
||||
w->writeC(0x94);
|
||||
w->writeC(streamID);
|
||||
} else {
|
||||
w->writeC(0x93);
|
||||
w->writeC(streamID);
|
||||
w->writeI(pos);
|
||||
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
|
||||
w->writeI(len);
|
||||
}
|
||||
} else {
|
||||
w->writeC(0x95);
|
||||
w->writeC(streamID);
|
||||
w->writeS(playingSample[streamID]); // sample number
|
||||
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
|
||||
}
|
||||
|
||||
if (sample->isLoopable() && !sampleDir[streamID]) {
|
||||
loopTimer[streamID]=len;
|
||||
loopSample[streamID]=playingSample[streamID];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1082,6 +1157,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
int songTick=0;
|
||||
|
||||
unsigned int sampleOff8[256];
|
||||
unsigned int sampleLen8[256];
|
||||
unsigned int sampleOffSegaPCM[256];
|
||||
|
||||
SafeWriter* w=new SafeWriter;
|
||||
|
@ -1102,6 +1178,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
bool sampleDir[DIV_MAX_CHANS];
|
||||
int pendingFreq[DIV_MAX_CHANS];
|
||||
int playingSample[DIV_MAX_CHANS];
|
||||
int setPos[DIV_MAX_CHANS];
|
||||
std::vector<unsigned int> chipVol;
|
||||
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
|
||||
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
|
||||
|
@ -1121,6 +1198,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
loopSample[i]=-1;
|
||||
pendingFreq[i]=-1;
|
||||
playingSample[i]=-1;
|
||||
setPos[i]=0;
|
||||
sampleDir[i]=false;
|
||||
}
|
||||
|
||||
|
@ -1379,7 +1457,6 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
willExport[i]=true;
|
||||
CHIP_VOL(6,1.0);
|
||||
CHIP_VOL(0x86,1.7);
|
||||
writeDACSamples=true;
|
||||
} else if (!(hasOPN&0x40000000)) {
|
||||
isSecond[i]=true;
|
||||
willExport[i]=true;
|
||||
|
@ -1873,6 +1950,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
|
||||
// initialize sample offsets
|
||||
memset(sampleOff8,0,256*sizeof(unsigned int));
|
||||
memset(sampleLen8,0,256*sizeof(unsigned int));
|
||||
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
|
||||
|
||||
// write samples
|
||||
|
@ -1881,6 +1959,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
DivSample* sample=song.sample[i];
|
||||
logI("setting seek to %d",sampleSeek);
|
||||
sampleOff8[i]=sampleSeek;
|
||||
sampleLen8[i]=sample->length8;
|
||||
sampleSeek+=sample->length8;
|
||||
}
|
||||
|
||||
|
@ -2016,9 +2095,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
w->writeC(0x67);
|
||||
w->writeC(0x66);
|
||||
w->writeC(0xc0+i);
|
||||
w->writeI(writeRF5C68[i]->getSampleMemUsage()+8);
|
||||
w->writeI(writeRF5C68[i]->getSampleMemCapacity());
|
||||
w->writeI(0);
|
||||
w->writeI(writeRF5C68[i]->getSampleMemUsage()+2);
|
||||
w->writeS(0);
|
||||
w->write(writeRF5C68[i]->getSampleMem(),writeRF5C68[i]->getSampleMemUsage());
|
||||
}
|
||||
if (writeMSM6295[i]!=NULL && writeMSM6295[i]->getSampleMemUsage()>0) {
|
||||
|
@ -2281,7 +2359,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
for (int i=0; i<song.systemLen; i++) {
|
||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||
for (DivRegWrite& j: writes) {
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,bankOffset[i],directStream);
|
||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i],directStream);
|
||||
writeCount++;
|
||||
}
|
||||
writes.clear();
|
||||
|
@ -2321,7 +2399,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
|||
lastOne=i.second.time;
|
||||
}
|
||||
// write write
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,bankOffset[i.first],directStream);
|
||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream);
|
||||
// handle global Furnace commands
|
||||
|
||||
writeCount++;
|
||||
|
|
|
@ -318,6 +318,7 @@ void DivZSM::flushWrites() {
|
|||
}
|
||||
pcmCache.resize(pcmCache.size()>>1);
|
||||
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
|
||||
pcmLoopPointCache>>=1; // halve the loop point
|
||||
}
|
||||
}
|
||||
} else { // 8-bit
|
||||
|
@ -334,6 +335,7 @@ void DivZSM::flushWrites() {
|
|||
}
|
||||
pcmCache.resize(pcmCache.size()>>1);
|
||||
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
|
||||
pcmLoopPointCache>>=1; // halve the loop point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,9 +367,9 @@ void DivZSM::flushWrites() {
|
|||
inst.loopPoint=pcmLoopPointCache;
|
||||
inst.isLooped=pcmIsLooped;
|
||||
pcmInsts.push_back(inst);
|
||||
pcmIsLooped=false;
|
||||
pcmLoopPointCache=0;
|
||||
}
|
||||
pcmIsLooped=false;
|
||||
pcmLoopPointCache=0;
|
||||
}
|
||||
if (extCmd0Len>63) { // this would be bad, but will almost certainly never happen
|
||||
logE("ZSM: extCmd 0 exceeded maximum length of 63: %d",extCmd0Len);
|
||||
|
|
|
@ -149,6 +149,14 @@ void FurnaceGUI::drawChanOsc() {
|
|||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::Text("Amplitude");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (CWSliderFloat("##COSAmp",&chanOscAmplify,0.0f,2.0f)) {
|
||||
if (chanOscAmplify<0.0f) chanOscAmplify=0.0f;
|
||||
if (chanOscAmplify>2.0f) chanOscAmplify=2.0f;
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Gradient",&chanOscUseGrad);
|
||||
|
||||
if (chanOscUseGrad) {
|
||||
|
|
|
@ -5759,6 +5759,17 @@ bool FurnaceGUI::loop() {
|
|||
introPos=12.0;
|
||||
}
|
||||
|
||||
#ifdef DIV_UNSTABLE
|
||||
{
|
||||
ImDrawList* dl=ImGui::GetForegroundDrawList();
|
||||
ImVec2 markPos=ImVec2(canvasW-ImGui::CalcTextSize(DIV_VERSION).x-6.0*dpiScale,4.0*dpiScale);
|
||||
ImVec4 markColor=uiColors[GUI_COLOR_TEXT];
|
||||
markColor.w=0.67f;
|
||||
|
||||
dl->AddText(markPos,ImGui::ColorConvertFloat4ToU32(markColor),DIV_VERSION);
|
||||
}
|
||||
#endif
|
||||
|
||||
layoutTimeEnd=SDL_GetPerformanceCounter();
|
||||
|
||||
// backup trigger
|
||||
|
@ -6265,14 +6276,14 @@ bool FurnaceGUI::init() {
|
|||
settings.renderBackend="SDL";
|
||||
e->setConf("renderBackend","SDL");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
lastError=fmt::sprintf("could not init renderer!\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()) {
|
||||
settings.renderDriver="";
|
||||
e->setConf("renderDriver","");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render driver has been set to a safe value. please restart Furnace.");
|
||||
lastError+=fmt::sprintf("\r\nthe render driver has been set to a safe value. please restart Furnace.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -6362,16 +6373,16 @@ bool FurnaceGUI::init() {
|
|||
if (!rend->init(sdlWin)) {
|
||||
if (settings.renderBackend!="SDL") {
|
||||
settings.renderBackend="SDL";
|
||||
e->setConf("renderBackend","");
|
||||
e->setConf("renderBackend","SDL");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render backend has been set to a safe value. please restart Furnace.");
|
||||
lastError=fmt::sprintf("could not init renderer!\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()) {
|
||||
settings.renderDriver="";
|
||||
e->setConf("renderDriver","");
|
||||
e->saveConf();
|
||||
lastError=fmt::sprintf("\r\nthe render driver has been set to a safe value. please restart Furnace.");
|
||||
lastError+=fmt::sprintf("\r\nthe render driver has been set to a safe value. please restart Furnace.");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -6666,6 +6677,10 @@ bool FurnaceGUI::finish() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void FurnaceGUI::requestQuit() {
|
||||
quit=true;
|
||||
}
|
||||
|
||||
FurnaceGUI::FurnaceGUI():
|
||||
e(NULL),
|
||||
renderBackend(GUI_BACKEND_SDL),
|
||||
|
|
|
@ -2307,6 +2307,7 @@ class FurnaceGUI {
|
|||
bool loop();
|
||||
bool finish();
|
||||
bool init();
|
||||
void requestQuit();
|
||||
FurnaceGUI();
|
||||
};
|
||||
|
||||
|
|
|
@ -2378,10 +2378,37 @@ void FurnaceGUI::drawInsEdit() {
|
|||
bool opsAreMutable=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPM);
|
||||
|
||||
if (ImGui::BeginTabItem("FM")) {
|
||||
DivInstrumentFM& fmOrigin=(ins->type==DIV_INS_OPLL && ins->fm.opllPreset>0 && ins->fm.opllPreset<16)?opllPreview:ins->fm;
|
||||
|
||||
bool isPresent[4];
|
||||
int isPresentCount=0;
|
||||
memset(isPresent,0,4*sizeof(bool));
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (e->song.system[i]==DIV_SYSTEM_VRC7) {
|
||||
isPresent[3]=true;
|
||||
} else if (e->song.system[i]==DIV_SYSTEM_OPLL || e->song.system[i]==DIV_SYSTEM_OPLL_DRUMS) {
|
||||
isPresent[(e->song.systemFlags[i].getInt("patchSet",0))&3]=true;
|
||||
}
|
||||
}
|
||||
if (!isPresent[0] && !isPresent[1] && !isPresent[2] && !isPresent[3]) {
|
||||
isPresent[0]=true;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isPresent[i]) isPresentCount++;
|
||||
}
|
||||
int presentWhich=0;
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isPresent[i]) {
|
||||
presentWhich=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("fmDetails",3,ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
|
||||
ImGui::TableNextRow();
|
||||
switch (ins->type) {
|
||||
case DIV_INS_FM:
|
||||
|
@ -2453,14 +2480,14 @@ void FurnaceGUI::drawInsEdit() {
|
|||
break;
|
||||
}
|
||||
case DIV_INS_OPLL: {
|
||||
bool dc=ins->fm.fms;
|
||||
bool dm=ins->fm.ams;
|
||||
bool dc=fmOrigin.fms;
|
||||
bool dm=fmOrigin.ams;
|
||||
bool sus=ins->fm.alg;
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::BeginDisabled(ins->fm.opllPreset!=0);
|
||||
P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(CWSliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&fmOrigin.fb,&_ZERO,&_SEVEN)); rightClickable
|
||||
if (ImGui::Checkbox(FM_NAME(FM_DC),&dc)) { PARAMETER
|
||||
ins->fm.fms=dc;
|
||||
fmOrigin.fms=dc;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -2469,7 +2496,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
ImGui::BeginDisabled(ins->fm.opllPreset!=0);
|
||||
if (ImGui::Checkbox(FM_NAME(FM_DM),&dm)) { PARAMETER
|
||||
ins->fm.ams=dm;
|
||||
fmOrigin.ams=dm;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -2477,30 +2504,6 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
|
||||
bool isPresent[4];
|
||||
int isPresentCount=0;
|
||||
memset(isPresent,0,4*sizeof(bool));
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (e->song.system[i]==DIV_SYSTEM_VRC7) {
|
||||
isPresent[3]=true;
|
||||
} else if (e->song.system[i]==DIV_SYSTEM_OPLL || e->song.system[i]==DIV_SYSTEM_OPLL_DRUMS) {
|
||||
isPresent[(e->song.systemFlags[i].getInt("patchSet",0))&3]=true;
|
||||
}
|
||||
}
|
||||
if (!isPresent[0] && !isPresent[1] && !isPresent[2] && !isPresent[3]) {
|
||||
isPresent[0]=true;
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isPresent[i]) isPresentCount++;
|
||||
}
|
||||
int presentWhich=0;
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isPresent[i]) {
|
||||
presentWhich=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("##LLPreset",opllInsNames[presentWhich][ins->fm.opllPreset])) {
|
||||
if (isPresentCount>1) {
|
||||
if (ImGui::BeginTable("LLPresetList",isPresentCount)) {
|
||||
|
@ -2578,11 +2581,26 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
// update OPLL preset preview
|
||||
if (ins->fm.opllPreset>0 && ins->fm.opllPreset<16) {
|
||||
const opll_patch_t* patchROM=OPLL_GetPatchROM(opll_type_ym2413);
|
||||
const opll_patch_t* patchROM=NULL;
|
||||
|
||||
switch (presentWhich) {
|
||||
case 1:
|
||||
patchROM=OPLL_GetPatchROM(opll_type_ymf281);
|
||||
break;
|
||||
case 2:
|
||||
patchROM=OPLL_GetPatchROM(opll_type_ym2423);
|
||||
break;
|
||||
case 3:
|
||||
patchROM=OPLL_GetPatchROM(opll_type_ds1001);
|
||||
break;
|
||||
default:
|
||||
patchROM=OPLL_GetPatchROM(opll_type_ym2413);
|
||||
break;
|
||||
}
|
||||
|
||||
const opll_patch_t* patch=&patchROM[ins->fm.opllPreset-1];
|
||||
|
||||
opllPreview.alg=0;
|
||||
opllPreview.alg=ins->fm.alg;
|
||||
opllPreview.fb=patch->fb;
|
||||
opllPreview.fms=patch->dm;
|
||||
opllPreview.ams=patch->dc;
|
||||
|
@ -2604,8 +2622,6 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
}
|
||||
|
||||
DivInstrumentFM& fmOrigin=(ins->type==DIV_INS_OPLL && ins->fm.opllPreset>0 && ins->fm.opllPreset<16)?opllPreview:ins->fm;
|
||||
|
||||
ImGui::BeginDisabled(!willDisplayOps);
|
||||
if (settings.fmLayout==0) {
|
||||
int numCols=15;
|
||||
|
|
|
@ -290,8 +290,7 @@ void FurnaceGUIRenderDX11::clear(ImVec4 color) {
|
|||
}
|
||||
|
||||
bool FurnaceGUIRenderDX11::newFrame() {
|
||||
ImGui_ImplDX11_NewFrame();
|
||||
return true;
|
||||
return ImGui_ImplDX11_NewFrame();
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderDX11::createFontsTexture() {
|
||||
|
|
|
@ -233,8 +233,7 @@ void FurnaceGUIRenderGL::clear(ImVec4 color) {
|
|||
}
|
||||
|
||||
bool FurnaceGUIRenderGL::newFrame() {
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
return true;
|
||||
return ImGui_ImplOpenGL3_NewFrame();
|
||||
}
|
||||
|
||||
void FurnaceGUIRenderGL::createFontsTexture() {
|
||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -36,7 +36,10 @@
|
|||
|
||||
typedef HRESULT (WINAPI *SPDA)(PROCESS_DPI_AWARENESS);
|
||||
#else
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct sigaction termsa;
|
||||
#endif
|
||||
|
||||
#include "cli/cli.h"
|
||||
|
@ -356,6 +359,14 @@ void reportError(String what) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifdef HAVE_GUI
|
||||
static void handleTermGUI(int) {
|
||||
g.requestQuit();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO: CoInitializeEx on Windows?
|
||||
// TODO: add crash log
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -646,6 +657,13 @@ int main(int argc, char** argv) {
|
|||
g.setFileName(fileName);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
sigemptyset(&termsa.sa_mask);
|
||||
termsa.sa_flags=0;
|
||||
termsa.sa_handler=handleTermGUI;
|
||||
sigaction(SIGTERM,&termsa,NULL);
|
||||
#endif
|
||||
|
||||
g.loop();
|
||||
logI("closing GUI.");
|
||||
g.finish();
|
||||
|
|
Loading…
Reference in New Issue