Merge branch 'master' of https://github.com/tildearrow/furnace into command-palette
BIN
demos/genesis/mm5_boss.fur
Normal file
|
@ -33,6 +33,6 @@ Everything from the instrument list applies here also, with one major difference
|
|||
|
||||

|
||||
|
||||
Everything from the wavetables list applies here also, with the addition of two buttons:
|
||||
Everything from the wavetables list applies here also, with the addition of two buttons before the Delete button:
|
||||
- **Preview**: Plays the selected sample at its default note.
|
||||
- **Stop preview**: Stops the sample playback.
|
||||
|
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 44 KiB |
|
@ -4,12 +4,38 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
|
||||
|
||||
|
||||
# General
|
||||
## General
|
||||
|
||||
- **Workspace layout**
|
||||
- **Import**: reads a .ini layout file.
|
||||
- **Export**: writes current layout to a .ini file.
|
||||
- **Reset**: resets layout to default.
|
||||
### Program
|
||||
|
||||
- **Render backend**
|
||||
- changing this may help with performace issues.
|
||||
- **Late render clear**
|
||||
- **Power-saving mode**
|
||||
- saves power by lowering the frame rate to 2fps when idle.
|
||||
- may cause issues under Mesa drivers!
|
||||
- **Disable threaded input (restart after changing!)**
|
||||
- threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.
|
||||
- however, crashes have been reported when threaded input is on. enable this option if that is the case.
|
||||
- **Enable event delay**
|
||||
- may cause issues with high-polling-rate mice when previewing notes.
|
||||
|
||||
### File
|
||||
|
||||
- **Use system file picker**: use native OS file dialog instead of Furnace's.
|
||||
- **Number of recent files**
|
||||
- **Compress when saving**
|
||||
- use zlib to compress saved songs.
|
||||
- **Save unused patterns**
|
||||
- **Use new pattern format when saving**
|
||||
- **Don't apply compatibility flags when loading .dmf**
|
||||
- **Audio export loop/fade out time:**
|
||||
- **Set to these values on start-up:**
|
||||
- **Loops**: number of additional times to play through `0Bxx` song loop.
|
||||
- **Fade out (seconds)**: length of fade out after final loop.
|
||||
- **Remember last values**
|
||||
|
||||
### Chip
|
||||
|
||||
- **Initial system**: the system of chips loaded on starting Furnace.
|
||||
- **Current system**: sets current chips as default.
|
||||
|
@ -18,172 +44,131 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
- **Reset to defaults**: sets default to "Sega Genesis/Mega Drive".
|
||||
- **Name**: name for the default system. may be set to any text.
|
||||
- system configuration: same as in the [chip manager](../8-advanced/chip-manager.md) and [mixer](../8-advanced/mixer.md).
|
||||
- **When creating new song**:
|
||||
- **Display system preset selector**
|
||||
- **Start with initial system**
|
||||
- **Restart song when changing chip properties**
|
||||
|
||||
### Start-up
|
||||
|
||||
- **Play intro on start-up:**
|
||||
- **No**: skips intro entirely.
|
||||
- **Short**: shows silent title screen briefly.
|
||||
- **Full (short when loading song)**: shows animated musical intro unless started with a song (command line, double-clicking a .fur file, etc.)
|
||||
- **Full (always)**: always shows animated musical intro.
|
||||
- **When creating new song**:
|
||||
- **Display system preset selector**
|
||||
- **Start with initial system**
|
||||
- **Disable fade-in during start-up**
|
||||
- **About screen party time**
|
||||
- _warning:_ may cause epileptic seizures.
|
||||
|
||||
### Behavior
|
||||
|
||||
- **Double-click time (seconds)**: maximum time between mouse clicks to recognize them as a double-click.
|
||||
- **Toggle channel solo on:** select which interactions with a channel header will toggle solo for that channel.
|
||||
- **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh.
|
||||
- if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`.
|
||||
- if on: with the cursor on the value `A5` and typing a "B" results in `5B`.
|
||||
- **Move cursor up on backspace-delete**
|
||||
- **Move cursor by edit step on delete**
|
||||
- **Change current instrument when changing instrument column (absorb)**
|
||||
- **Delete effect value when deleting effect**
|
||||
- **Change order when scrolling outside of pattern bounds**:
|
||||
- if off, the pattern edit cursor will stay locked within the current order.
|
||||
- if on, moving the cursor past the edge of the previous or next order will move to that order.
|
||||
- **Move cursor by edit step on insert (push)**
|
||||
- **Move cursor to end of clipboard content when pasting**
|
||||
- **Don't scroll when moving cursor**
|
||||
- **Double click selects entire column**
|
||||
- **Allow docking editors**
|
||||
- **Don't raise pattern editor on click**
|
||||
- **Focus pattern editor when selecting instrument**
|
||||
- **Restart song when changing chip properties**
|
||||
- **Use system file picker**: use native OS file dialog instead of Furnace's.
|
||||
- **Only allow window movement when clicking on title bar**
|
||||
- **Enable event delay**
|
||||
- may cause issues with high-polling-rate mice when previewing notes.
|
||||
- **Power-saving mode**
|
||||
- saves power by lowering the frame rate to 2fps when idle.
|
||||
- may cause issues under Mesa drivers!
|
||||
- **Disable threaded input (restart after changing!)**
|
||||
- threaded input processes key presses for note preview on a separate thread (on supported platforms), which reduces latency.
|
||||
- however, crashes have been reported when threaded input is on. enable this option if that is the case.
|
||||
- **Remember window position**
|
||||
- remembers the window's last position on start-up.
|
||||
- **New instruments are blank**
|
||||
- **Save unused patterns**
|
||||
- **Compress when saving**
|
||||
- use zlib to compress saved songs.
|
||||
- **Cursor follows current order when moving it**
|
||||
- applies when playback is stopped.
|
||||
- **Audio export loop/fade out time:**
|
||||
- **Set to these values on start-up:**
|
||||
- **Loops**: number of additional times to play through `0Bxx` song loop.
|
||||
- **Fade out (seconds)**: length of fade out after final loop.
|
||||
- **Remember last values**
|
||||
- **Note preview behavior:**
|
||||
- **Never**
|
||||
- **When cursor is in Note column**
|
||||
- **When cursor is in Note column or not in edit mode**
|
||||
- **Always**
|
||||
- **Wrap pattern cursor horizontally:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes, and move to next/prev row**
|
||||
- **Wrap pattern cursor vertically:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes, and move to next/prev pattern**
|
||||
- **Cursor movement keys behavior:**
|
||||
- **Move by one**
|
||||
- **Move by Edit Step**
|
||||
- **Effect input cursor behavior:**
|
||||
- **Move down**
|
||||
- **Move to effect value (otherwise move down)**
|
||||
- **Move to effect value/next effect and wrap around**
|
||||
- **Allow dragging selection:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes (while holding Ctrl only)**
|
||||
|
||||
|
||||
|
||||
# Audio/MIDI
|
||||
## Audio
|
||||
|
||||
### Output
|
||||
|
||||
- **Backend**: select SDL or JACK for audio output.
|
||||
- only appears on Linux, or MacOS compiled with JACK support
|
||||
- **Driver**
|
||||
- **Device**: audio device for playback.
|
||||
- **Sample rate**
|
||||
- **Outputs**: select number of audio outputs created, up to 16.
|
||||
- only appears when Backend is JACK.
|
||||
- **Channels**: number of output channels to use.
|
||||
- **Buffer size**: size of buffer in both samples and milliseconds.
|
||||
- **Quality**: selects quality of resampling. low quality reduces CPU load.
|
||||
- **Metronome volume**
|
||||
- **Low-latency mode (experimental!)**: reduces latency by running the engine faster than the tick rate. useful for live playback/jam mode.
|
||||
- _warning:_ experimental! may produce glitches. only enable if your buffer size is small (10ms or less).
|
||||
- **Force mono audio**
|
||||
- **Software clipping**: clips output to nominal range (-1.0 to 1.0) before passing it to the audio device.
|
||||
- this avoids activating Windows' built-in limiter.
|
||||
- **want:** displays requested audio configuration.
|
||||
- **got:** displays actual audio configuration returned by audio backend.
|
||||
|
||||
- **MIDI input**
|
||||
- **MIDI output**
|
||||
- **MIDI input settings**
|
||||
- **Note input**
|
||||
- **Velocity input**
|
||||
- **Map MIDI channels to direct channels**
|
||||
- **Map Yamaha FM voice data to instruments**
|
||||
- **Program change is instrument selection**
|
||||
- **Value input style**:
|
||||
### Mixing
|
||||
|
||||
- **Quality**: selects quality of resampling. low quality reduces CPU load.
|
||||
- **Software clipping**: clips output to nominal range (-1.0 to 1.0) before passing it to the audio device.
|
||||
- this avoids activating Windows' built-in limiter.
|
||||
|
||||
### Metronome
|
||||
|
||||
- **Metronome volume**
|
||||
|
||||
|
||||
|
||||
## MIDI
|
||||
|
||||
### MIDI input
|
||||
|
||||
- **MIDI input**: input device.
|
||||
- **Note input**
|
||||
- **Velocity input**
|
||||
- **Map MIDI channels to direct channels**
|
||||
- **Map Yamaha FM voice data to instruments**
|
||||
- **Program change is instrument selection**
|
||||
- **Value input style**:
|
||||
- **Disabled/custom**
|
||||
- **Two octaves (0 is C-4, F is D#5)**
|
||||
- **Raw (note number is value)**
|
||||
- **Two octaves alternate (lower keys are 0-9, upper keys are A-F)**
|
||||
- **Use dual control change (one for each nibble)**
|
||||
- **CC of upper nibble**
|
||||
- **CC of lower nibble**
|
||||
- **Use 14-bit control change**
|
||||
- **MSB CC**
|
||||
- **LSB CC**
|
||||
- **Use single control change**
|
||||
- **Control**
|
||||
- **Per-column control change**
|
||||
- **Instrument**\
|
||||
**Volume**\
|
||||
**Effect `x` type**\
|
||||
**Effect `x` value**
|
||||
- **Disabled/custom**
|
||||
- **Two octaves (0 is C-4, F is D#5)**
|
||||
- **Raw (note number is value)**
|
||||
- **Two octaves alternate (lower keys are 0-9, upper keys are A-F)**
|
||||
- **Use dual control change (one for each nibble)**
|
||||
- **CC of upper nibble**
|
||||
- **CC of lower nibble**
|
||||
- **Use 14-bit control change**
|
||||
- **MSB CC**
|
||||
- **LSB CC**
|
||||
- **Use single control change**
|
||||
- **Use single control change (imprecise)**
|
||||
- **Control**
|
||||
- **Per-column control change**
|
||||
- **Instrument**\
|
||||
**Volume**\
|
||||
**Effect `x` type**\
|
||||
**Effect `x` value**
|
||||
- **Disabled/custom**
|
||||
- **Use dual control change (one for each nibble)**
|
||||
- **CC of upper nibble**
|
||||
- **CC of lower nibble**
|
||||
- **Use 14-bit control change**
|
||||
- **MSB CC**
|
||||
- **LSB CC**
|
||||
- **Use single control change (imprecise)**
|
||||
- **Control**
|
||||
- **Volume curve**
|
||||
- **Actions:**
|
||||
- **`+`** button: adds a new action.
|
||||
- window-with-arrow button: new action with learning! press a button or move a slider/knob/something on your device.
|
||||
- each action has the following:
|
||||
- **Type**
|
||||
- **Channel**
|
||||
- **Note/Control**
|
||||
- **Velocity/Value**
|
||||
- **Action**
|
||||
- **Learn**
|
||||
- **Remove**
|
||||
- **Volume curve**
|
||||
- **Actions:**
|
||||
- **`+`** button: adds a new action.
|
||||
- window-with-arrow button: new action with learning! press a button or move a slider/knob/something on your device.
|
||||
- each action has the following:
|
||||
- **Type**
|
||||
- **Channel**
|
||||
- **Note/Control**
|
||||
- **Velocity/Value**
|
||||
- **Action**
|
||||
- **Learn**
|
||||
- **Remove**
|
||||
|
||||
- **MIDI output settings**
|
||||
- **Output mode:**
|
||||
- **Off (use for TX81Z)**
|
||||
- **Melodic**
|
||||
- **Send Program Change**
|
||||
- **Send MIDI clock**
|
||||
- **Send MIDI timecode**
|
||||
- **Timecode frame rate:**
|
||||
- **Closest to Tick Rate**
|
||||
- **Film (24fps)**
|
||||
- **PAL (25fps)**
|
||||
- **NTSC drop (29.97fps)**
|
||||
- **NTSC non-drop (30fps)**
|
||||
### MIDI output
|
||||
|
||||
# Emulation
|
||||
- **MIDI output**: output device.
|
||||
- **Output mode:**
|
||||
- **Off (use for TX81Z)**
|
||||
- **Melodic**
|
||||
- **Send Program Change**
|
||||
- **Send MIDI clock**
|
||||
- **Send MIDI timecode**
|
||||
- **Timecode frame rate:**
|
||||
- **Closest to Tick Rate**
|
||||
- **Film (24fps)**
|
||||
- **PAL (25fps)**
|
||||
- **NTSC drop (29.97fps)**
|
||||
- **NTSC non-drop (30fps)**
|
||||
|
||||
|
||||
|
||||
## Emulation
|
||||
|
||||
### Cores
|
||||
|
||||
- **Arcade/YM2151 core**\
|
||||
**Genesis/YM2612 core**\
|
||||
**SN76489 core**\
|
||||
|
@ -202,16 +187,122 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
|
||||
|
||||
|
||||
# Appearance
|
||||
## Keyboard
|
||||
|
||||
### Keyboard
|
||||
|
||||
- **Import**
|
||||
- **Export**
|
||||
- **Reset defaults**
|
||||
- several categories of keybinds...
|
||||
- click on a keybind then enter a key or key combination to change it
|
||||
- right-click to clear the keybind
|
||||
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
### Layout
|
||||
|
||||
- **Workspace layout**
|
||||
- **Import**: reads a .ini layout file.
|
||||
- **Export**: writes current layout to a .ini file.
|
||||
- **Reset**: resets layout to default.
|
||||
- **Allow docking editors**
|
||||
- **Remember window position**
|
||||
- remembers the window's last position on start-up.
|
||||
- **Only allow window movement when clicking on title bar**
|
||||
- **Play/edit controls layout:**
|
||||
- **Classic**
|
||||
- **Compact**
|
||||
- **Compact (vertical)**
|
||||
- **Split**
|
||||
- **Position of buttons in Orders:**
|
||||
- **Top**
|
||||
- **Left**
|
||||
- **Right**
|
||||
|
||||
### Mouse
|
||||
|
||||
- **Double-click time (seconds)**: maximum time between mouse clicks to recognize them as a double-click.
|
||||
- **Don't raise pattern editor on click**
|
||||
- **Focus pattern editor when selecting instrument**
|
||||
- **Note preview behavior:**
|
||||
- **Never**
|
||||
- **When cursor is in Note column**
|
||||
- **When cursor is in Note column or not in edit mode**
|
||||
- **Always**
|
||||
- **Allow dragging selection:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes (while holding Ctrl only)**
|
||||
- **Toggle channel solo on:** select which interactions with a channel header will toggle solo for that channel.
|
||||
- Right-click or double click
|
||||
- Right-click
|
||||
- Double-click
|
||||
- **Double click selects entire column**
|
||||
|
||||
### Cursor behavior
|
||||
|
||||
- **Insert pushes entire channel row**
|
||||
- **Pull delete affects entire channel row**
|
||||
- **Push value when overwriting instead of clearing it**: in the order list and pattern editors, typing into an already-filled value will shift digits instead of starting fresh.
|
||||
- if off: moving the cursor onto the value `A5` and typing a "B" results in `0B`.
|
||||
- if on: with the cursor on the value `A5` and typing a "B" results in `5B`.
|
||||
- **Effect input behavior:**
|
||||
- **Move down**
|
||||
- **Move to effect value (otherwise move down)**
|
||||
- **Move to effect value/next effect and wrap around**
|
||||
- **Delete effect value when deleting effect**
|
||||
- **Change current instrument when changing instrument column (absorb)**
|
||||
|
||||
|
||||
### Cursor movement
|
||||
|
||||
- **Wrap horizontally:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes, and move to next/prev row**
|
||||
- **Wrap vertically:**
|
||||
- **No**
|
||||
- **Yes**
|
||||
- **Yes, and move to next/prev pattern**
|
||||
- **Yes, and move to next/prev pattern (wrap around)**
|
||||
- **Cursor movement keys behavior:**
|
||||
- **Move by one**
|
||||
- **Move by Edit Step**
|
||||
- **Move cursor by edit step on delete**
|
||||
- **Move cursor by edit step on insert (push)**
|
||||
- **Move cursor up on backspace-delete**
|
||||
- **Move cursor to end of clipboard content when pasting**
|
||||
|
||||
### Scrolling
|
||||
|
||||
- **Change order when scrolling outside of pattern bounds**:
|
||||
- **No**: the pattern edit cursor will stay locked within the current order.
|
||||
- **Yes**: moving the cursor past the edge of the previous or next order will move to that order, but not past the start or end of a song.
|
||||
- **Yes, and wrap around song**: as above, but will wrap from song end to start.
|
||||
- **Cursor follows current order when moving it**
|
||||
- applies when playback is stopped.
|
||||
- **Don't scroll when moving cursor**
|
||||
- **Move cursor with scroll wheel**
|
||||
|
||||
|
||||
|
||||
## Appearance
|
||||
|
||||
### Scaling
|
||||
|
||||
- **Render driver**
|
||||
- **Automatic UI scaling factor**: automatically match the OS's UI scaling.
|
||||
- **UI scaling factor**: only if "Automatic UI scaling factor" is off.
|
||||
- **Icon size**
|
||||
|
||||
### Text
|
||||
|
||||
- **Main font**: if "Custom...", a file path selector will appear beneath.
|
||||
- **Size**
|
||||
- **Pattern font**: if "Custom...", a file path selector will appear beneath.
|
||||
- **Size**
|
||||
- **Icon size**
|
||||
- **Display Japanese characters**\
|
||||
**Display Chinese (Simplified) characters**\
|
||||
**Display Chinese (Traditional) characters**\
|
||||
|
@ -219,25 +310,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
- only toggle these options if you have enough graphics memory.
|
||||
- these are a temporary solution until dynamic font atlas is implemented in Dear ImGui.
|
||||
|
||||
- **Number of recent files**
|
||||
|
||||
- **Pattern view labels:**
|
||||
- **Note off (3-char)**: default is `OFF`
|
||||
- **Note release (3-char)**: default is `===`.
|
||||
- **Macro release (3-char)**: default is `REL`.
|
||||
- **Empty field (3-char)**: default is `...`.
|
||||
- **Empty field (2-char)**: default is `..`.
|
||||
|
||||
- **Orders row number format:**
|
||||
- **Decimal**
|
||||
- **Hexadecimal**
|
||||
- **Pattern row number format:**
|
||||
- **Decimal**
|
||||
- **Hexadecimal**
|
||||
- **FM parameter names:**
|
||||
- **Friendly**
|
||||
- **Technical**
|
||||
- **Technical (alternate)**
|
||||
### Program
|
||||
|
||||
- **Title bar:**
|
||||
- **Furnace**
|
||||
|
@ -251,43 +324,40 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
- **File path**
|
||||
- **Cursor details or file path**
|
||||
- **Nothing**
|
||||
- **Play/edit controls layout:**
|
||||
- **Classic**
|
||||
- **Compact**
|
||||
- **Compact (vertical)**
|
||||
- **Split**
|
||||
- **Position of buttons in Orders:**
|
||||
- **Top**
|
||||
- **Left**
|
||||
- **Right**
|
||||
- **FM parameter editor layout:**
|
||||
- **Modern**
|
||||
- **Compact (2x2, classic)**
|
||||
- **Compact (1x4)**
|
||||
- **Compact (4x1)**
|
||||
- **Alternate (2x2)**
|
||||
- **Alternate (1x4)**
|
||||
- **Alternate (4x1)**
|
||||
- **Position of Sustain in FM editor:**
|
||||
- **Between Decay and Sustain Rate**
|
||||
- **After Release Rate**
|
||||
- **Macro editor layout:**
|
||||
- **Unified**
|
||||
- **Mobile**
|
||||
- **Grid**
|
||||
- **Single (with list)**
|
||||
- **Single (combo box)**
|
||||
|
||||
- **Namco 163 chip name**
|
||||
### Orders
|
||||
|
||||
- **Highlight channel at cursor in Orders**
|
||||
- **Orders row number format:**
|
||||
- **Decimal**
|
||||
- **Hexadecimal**
|
||||
|
||||
### Pattern
|
||||
|
||||
- **Center pattern view**: centers pattern horizontally in view.
|
||||
- **Overflow pattern highlights**
|
||||
- **Display previous/next pattern**
|
||||
- **Pattern row number format:**
|
||||
- **Decimal**
|
||||
- **Hexadecimal**
|
||||
- **Pattern view labels:**
|
||||
- **Note off (3-char)**: default is `OFF`
|
||||
- **Note release (3-char)**: default is `===`.
|
||||
- **Macro release (3-char)**: default is `REL`.
|
||||
- **Empty field (3-char)**: default is `...`.
|
||||
- **Empty field (2-char)**: default is `..`.
|
||||
- **Pattern view spacing after:** number of pixels of space between columns.
|
||||
- **Note**
|
||||
- **Instrument**
|
||||
- **Volume**
|
||||
- **Effect**
|
||||
- **Effect value**
|
||||
- **Single-digit effects for 00-0F**
|
||||
- **Use flats instead of sharps**
|
||||
- **Use German notation**: display `B` notes as `H`, and `A#` notes as `B`.
|
||||
|
||||
### Channel
|
||||
|
||||
- **Channel colors:**
|
||||
- **Single**
|
||||
- **Channel type**
|
||||
- **Instrument type**
|
||||
- **Channel name colors:**
|
||||
- **Single**
|
||||
- **Channel type**
|
||||
- **Instrument type**
|
||||
- **Channel style:**
|
||||
- **Classic**
|
||||
- **Line**
|
||||
|
@ -310,60 +380,88 @@ settings are saved when clicking the **OK** button at the bottom of the dialog.
|
|||
- **Regular**
|
||||
- **Monospace**
|
||||
- **Center channel name**
|
||||
- **Channel colors:**
|
||||
- **Single**
|
||||
- **Channel type**
|
||||
- **Instrument type**
|
||||
- **Channel name colors:**
|
||||
- **Single**
|
||||
- **Channel type**
|
||||
- **Instrument type**
|
||||
|
||||
### Assets
|
||||
|
||||
- **Colorize instrument editor using instrument type**
|
||||
- **Use separate colors for carriers/modulators in FM editor**
|
||||
- **Unified instrument/wavetable/sample list**
|
||||
- **Horizontal instrument list**
|
||||
- **Use standard OPL waveform names**
|
||||
- **Overflow pattern highlights**
|
||||
- **Display previous/next pattern**
|
||||
- **Use German notation**: display `B` notes as `H`, and `A#` notes as `B`.
|
||||
- **Single-digit effects for 00-0F**
|
||||
- **Center pattern view**: centers pattern horizontally in view.
|
||||
- **Unsigned FM detune values**
|
||||
- **Highlight channel at cursor in Orders**
|
||||
- **About screen party time**
|
||||
- _warning:_ may cause epileptic seizures.
|
||||
- **Colorize instrument editor using instrument type**
|
||||
|
||||
### Macro Editor
|
||||
|
||||
- **Macro editor layout:**
|
||||
- **Unified**
|
||||
- **Mobile**
|
||||
- **Grid**
|
||||
- **Single (with list)**
|
||||
- **Single (combo box)**
|
||||
- **Use classic macro editor vertical slider**
|
||||
|
||||
### Wave Editor
|
||||
|
||||
- **Use compact wave editor**
|
||||
- **Use classic macro editor vertical slider**
|
||||
|
||||
### FM Editor
|
||||
|
||||
- **FM parameter names:**
|
||||
- **Friendly**
|
||||
- **Technical**
|
||||
- **Technical (alternate)**
|
||||
- **Use standard OPL waveform names**
|
||||
- **FM parameter editor layout:**
|
||||
- **Modern**
|
||||
- **Compact (2x2, classic)**
|
||||
- **Compact (1x4)**
|
||||
- **Compact (4x1)**
|
||||
- **Alternate (2x2)**
|
||||
- **Alternate (1x4)**
|
||||
- **Alternate (4x1)**
|
||||
- **Position of Sustain in FM editor:**
|
||||
- **Between Decay and Sustain Rate**
|
||||
- **After Release Rate**
|
||||
- **Use separate colors for carriers/modulators in FM editor**
|
||||
- **Unsigned FM detune values**
|
||||
|
||||
### Statistics
|
||||
|
||||
- **Chip memory usage unit:**
|
||||
- **Bytes**
|
||||
- **Kilobytes**
|
||||
|
||||
### Oscilloscope
|
||||
|
||||
- **Rounded corners**
|
||||
- **Border**
|
||||
- **Fill entire window**
|
||||
- **Waveform goes out of bounds**
|
||||
|
||||
### Windows
|
||||
|
||||
- **Rounded window corners**
|
||||
- **Rounded buttons**
|
||||
- **Rounded menu corners**
|
||||
- **Borders around widgets**
|
||||
- **Disable fade-in during start-up**
|
||||
|
||||
- **Oscilloscope settings:**
|
||||
- **Rounded corners**
|
||||
- **Fill entire window**
|
||||
- **Waveform goes out of bounds**
|
||||
- **Border**
|
||||
|
||||
- **Pattern view spacing after:**
|
||||
- **Note**
|
||||
- **Instrument**
|
||||
- **Volume**
|
||||
- **Effect**
|
||||
- **Effect value**
|
||||
- **Color scheme**
|
||||
- **Import**
|
||||
- **Export**
|
||||
- **Reset defaults**
|
||||
- **General**
|
||||
- **Color scheme type:**
|
||||
- **Dark**
|
||||
- **Light**
|
||||
- **Frame shading**
|
||||
- several more categories...
|
||||
|
||||
|
||||
|
||||
# Keyboard
|
||||
## Color
|
||||
|
||||
### Color scheme
|
||||
|
||||
- **Import**
|
||||
- **Export**
|
||||
- **Reset defaults**
|
||||
- several categories of keybinds...
|
||||
- click on a keybind then enter a key or key combination to change it
|
||||
- right-click to clear the keybind
|
||||
- **General**
|
||||
- **Color scheme type:**
|
||||
- **Dark**
|
||||
- **Light**
|
||||
- **Frame shading**: applies a gradient effect to buttons and input boxes.
|
||||
- several more categories...
|
||||
|
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 27 KiB |
|
@ -4,41 +4,85 @@ the pattern view allows you to edit the song.
|
|||
|
||||

|
||||
|
||||
a pattern consists of columns ("channels") and rows.
|
||||
a pattern consists of columns ("channels") and numbered rows.
|
||||
each column has several subcolumns in this order:
|
||||
|
||||
1. note
|
||||
2. instrument
|
||||
3. volume
|
||||
4. effect and effect value (several)
|
||||
4. effects, split into effect type and effect value
|
||||
|
||||
all columns are represented in hexadecimal, except for the note column.
|
||||
|
||||
# managing channels
|
||||
row highlights show beats and measures, and are configured in the [the Speed window](../2-interface/song-info.md).
|
||||
|
||||
you may mute channels, toggle solo mode, collapse channels or even hide them.
|
||||
|
||||
clicking on a channel name mutes that channel.
|
||||
|
||||
double-clicking or right-clicking it enables solo mode, in where only that channel will be audible.
|
||||
|
||||
clicking the `++` at the top left corner of the pattern view displays additional buttons for channel configuration:
|
||||
|
||||

|
||||
|
||||
to rename and/or hide channels, see the Channels window (window > channels).
|
||||
|
||||

|
||||
|
||||
# cursor and selection
|
||||
## cursor and selection
|
||||
|
||||
you may change the cursor position by clicking anywhere on the pattern.
|
||||
|
||||
to select, press and hold the left mouse button. then drag the mouse and release the button to finish selection.
|
||||
to select an area, press and hold the left mouse button. then drag the mouse and release the button to finish selection.
|
||||
|
||||
# keyboard layout
|
||||
right-clicking within the pattern view brings up a pop-up menu with everything in the [edit menu](../2-interface/menu-bar.md) that makes sense for entering data or altering a selected area.
|
||||
|
||||
## shortcuts
|
||||
|
||||
|
||||
## channel bar
|
||||
|
||||
using the channel bar, you may adjust several aspects of the channel display.
|
||||
|
||||

|
||||
|
||||
clicking on a channel name mutes that channel.
|
||||
|
||||
double-clicking or right-clicking it enables solo mode, in which only that channel will be audible.
|
||||
|
||||
clicking the `++` at the top left corner of the pattern view cycles through three channel bar view modes:
|
||||
- **Compact**: shows only channel names.
|
||||
- **Expanded**: as shown above. adds buttons:
|
||||
- **-**: collapse visible columns. changes to **+** when columns are hidden; click to expand them.
|
||||
- **<**: disables the last effect column and hides it. effects are not deleted...
|
||||
- **>**: adds an effects column. if one previously existed, its contents will be preserved.
|
||||
- **Pattern names**: adds a text field with which one can name the current pattern. pattern names are also visible when hovering over a pattern in the order list.
|
||||
|
||||
right-clicking the `++` toggles the visualizer, which is active only during playback.
|
||||
|
||||
to rename and/or hide channels, open [the Channels window](../8-advanced/channels.md) via the window menu.
|
||||
|
||||
|
||||
# input
|
||||
|
||||
## note input
|
||||
|
||||

|
||||
|
||||
- pressing any of the respective keys will insert a note at the cursor's location, then advance to the next row (or otherwise according to the Edit Step.)
|
||||
- **note off** turns off the last played note in that channel (key off for FM; note cut otherwise).
|
||||
- **note release** triggers macro release (and in FM channels it also triggers key off).
|
||||
- **macro release** does the same as above, but does not trigger key off in FM channels.
|
||||
- **toggle edit** enables and disables editing. when editing is enabled, the cursor's row will be shaded red.
|
||||
|
||||
## instrument/volume input
|
||||
|
||||
type any hexadecimal number (0-9 and A-F). the cursor will move by the Edit Step when a suitable value is entered.
|
||||
|
||||
## effect input
|
||||
|
||||
works like the instrument/volume input.
|
||||
|
||||
each effect column has two subcolumns: effect and effect value.
|
||||
if the effect value is not present, it is treated as `00`.
|
||||
|
||||
most effects run until canceled using an effect of the same type with effect value `00`, with some exceptions.
|
||||
|
||||
here's [a list of effect types](effects.md).
|
||||
|
||||
|
||||
|
||||
# keyboard shortcuts
|
||||
|
||||
these are the default key functions. all keys are configurable in the Keyboard tab of the Settings window.
|
||||
|
||||
key | action
|
||||
------------|-----------------------------------------------------------------
|
||||
|
@ -68,31 +112,3 @@ Ctrl-F2 | transpose selection (+1 semitone)
|
|||
Ctrl-F3 | transpose selection (-1 octave)
|
||||
Ctrl-F4 | transpose selection (+1 octave)
|
||||
Space | toggle note input (edit)
|
||||
|
||||
## note input
|
||||
|
||||

|
||||
|
||||
- pressing any of the respective keys will insert a note at the cursor's location, and then advance it by the Edit Step.
|
||||
- note off turns off the last played note in that channel (key off for FM; note cut otherwise).
|
||||
- note release triggers macro release (and in FM channels it also triggers key off).
|
||||
- macro release does the same as above, but does not trigger key off in FM channels.
|
||||
|
||||
## instrument/volume input
|
||||
|
||||
type any hexadecimal number (0-9 and A-F). the cursor will move by the Edit Step when a suitable value is entered.
|
||||
|
||||
## effect input
|
||||
|
||||
works like the instrument/volume input.
|
||||
|
||||
each effect column has two subcolumns: effect and effect value.
|
||||
if the effect value is not present, it is treated as `00`.
|
||||
|
||||
most effects run until canceled using an effect of the same type with effect value `00`, with some exceptions.
|
||||
|
||||
here's [a list of effects](effects.md).
|
||||
|
||||
# pop-up menu
|
||||
|
||||
right-clicking within the pattern view brings up a pop-up menu with everything in the [edit menu](../2-interface/menu-bar.md) that makes sense for entering data or altering a selected area.
|
||||
|
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 294 KiB |
|
@ -1,11 +1,3 @@
|
|||
# instrument list
|
||||
|
||||

|
||||
|
||||
click on an instrument to select it.
|
||||
|
||||
double-click to open the instrument editor.
|
||||
|
||||
# instrument editor
|
||||
|
||||
every instrument can be renamed and have its type changed.
|
||||
|
@ -66,14 +58,16 @@ Some macros are "bitmap" style. They represent a number of "bits" that can be to
|
|||
|
||||
The number between the macro type label and the macro type button is the macro length in steps. The `-` and `+` buttons change the length of the macro. Start out by adding at least a few steps.
|
||||
|
||||
The values of the macro can be drawn in the "bar graph box". Just beneath the box is shorter bar graph.
|
||||
- Click to set the start point of a loop; the end point is the last value or release point. Right-click to remove the loop.
|
||||
- Shift-click to set the release point. When played, the macro will hold here until the note is released. Right-click to remove the release point.
|
||||
The values of the macro can be drawn in the "bar graph" box.
|
||||
|
||||
Just beneath the box is a shorter bar that controls looping.
|
||||
- Click to set the start point of a loop; the end point is the last value or release point. It appears as half-height bars. Right-click to remove the loop.
|
||||
- Shift-click to set the release point. When played, the macro will hold here until the note is released. It appears as a full-height bar. Right-click to remove the release point.
|
||||
|
||||
Finally, the sequence of values can be directly edited in the text box at the bottom.
|
||||
- The loop start is entered as a `|`.
|
||||
- The release point is entered as a `/`.
|
||||
- In arpeggio macros, a value starting with a `@` is an absolute note (instead of a relative shift). No matter the note played, `@` values will be played at that exact note. This is especially useful for noise instruments with preset periods.
|
||||
- In arpeggio macros, a value starting with a `@` is an absolute note (instead of a relative shift). No matter the note entered in the pattern, `@` values will be played at that exact note. This is especially useful for noise instruments with preset periods.
|
||||
|
||||
### ADSR
|
||||
|
||||
|
@ -100,15 +94,29 @@ Finally, the sequence of values can be directly edited in the text box at the bo
|
|||
- **Phase** is which part of the waveform the macro will start at, measured in 1/1024 increments.
|
||||
- **Shape** is the waveform used. Triangle is the default, and Saw and Square are exactly as they say.
|
||||
|
||||
# samples
|
||||
|
||||
|
||||
# wavetable
|
||||
|
||||
This tab appears for PC Engine, FDS, Namco WSG, and other wavetable-based instruments.
|
||||
|
||||

|
||||
|
||||
When **Enable synthesizer** is off, the only option is to select a wavetable entry with the text entry box beneath the **Wave 1** preview.
|
||||
|
||||
To use the wavetable synthesizer, refer to the bottom part of [the wavetable documentation](../5-wave/README.md).
|
||||
|
||||
|
||||
# sample
|
||||
|
||||
This tab appears for Generic PCM, SNES, Amiga, and other sample-based instruments.
|
||||
|
||||

|
||||

|
||||
|
||||
- **Initial Sample**: the sample that the instrument will use.
|
||||
- **Use wavetable**: instead of samples, use wavetables. this causes the [Wavetables](../5-wave/README.md) tab to appear next to Sample.
|
||||
- depending on the system and use of the wavetable synthesizer, this may or may not be reproducible on hardware.
|
||||
- **Use sample map**: assigns a sample to each note.
|
||||
- samples will be played at their default pitch.
|
||||
- to set a note's sample, click the list entry in the `#` column then type the number of the sample.
|
||||
- to set a note's sample, click the list entry in the "#" column then type the number of the sample.
|
||||
- to set the pitch at which a sample is played, click the list entry in the "note" column and press the key for the new note.
|
||||
|
||||
|
|
Before Width: | Height: | Size: 128 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 135 KiB |
|
@ -5,11 +5,11 @@ The Namco 163 instrument editor consists of two tabs: "Namco 163" for control of
|
|||
## Namco 163
|
||||
|
||||
- **Load waveform**: if enabled, a waveform will be loaded when this instrument plays.
|
||||
- if it isn't then only the offset/length change.
|
||||
- if it isn't then only the position/length change.
|
||||
- **Waveform**: determines the waveform that will be loaded.
|
||||
- only appears when Load waveform is enabled.
|
||||
- **Per-channel wave offset/length**: when enabled, the offset/length settings are split per channel.
|
||||
- **Offset**: determines the waveform position in RAM.
|
||||
- **Per-channel wave position/length**: when enabled, the position/length settings are split per channel.
|
||||
- **Position**: determines the waveform position in RAM.
|
||||
- **Length**: determines the waveform length in RAM.
|
||||
|
||||
## Macros
|
||||
|
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
BIN
doc/4-instrument/wavetable.png
Normal file
After Width: | Height: | Size: 59 KiB |
|
@ -2,19 +2,19 @@
|
|||
|
||||
Wavetable synthesizers, in context of Furnace, are sound sources that operate on extremely short n-bit PCM streams. By extremely short, no more than 256 bytes. This amount of space is nowhere near enough to store an actual sampled sound, it allows certain amount of freedom to define a waveform shape.
|
||||
|
||||
Each chip has its own maximum size, shown in the following table. If a larger wave is defined for these chips, it will be squashed to fit within the constraints of the chips. Some hardware doesn't work well with the wavetable synthesizer (described below); these systems are marked in the "synth?" column.
|
||||
Each chip has its own maximum size, shown in the following table. If a larger wave is defined for these chips, it will be squashed to fit within the constraints of the chips. Some hardware doesn't work well with the wavetable synthesizer (described below); these systems are marked in the "notes" column.
|
||||
|
||||
system | width | height | synth?
|
||||
system | width | height | notes
|
||||
--------------------|------:|:-------|:------
|
||||
Bubble System | 32 | 16 |
|
||||
Game Boy | 32 | 16 |
|
||||
Game Boy | 32 | 16 | phase reset on waveform change (clicking)
|
||||
SM8521 | 32 | 16 |
|
||||
Namco WSG | 32 | 16 | RAM only
|
||||
WonderSwan | 32 | 16 |
|
||||
Namco 163 | ≤128 | 16 |
|
||||
Namco 163 | ≤240 | 16 | limits differ depending on channel count
|
||||
SNES | ≤256 | 16 |
|
||||
PC Engine | 32 | 32 |
|
||||
Virtual Boy | 32 | 64 | no
|
||||
PC Engine | 32 | 32 | phase reset on waveform change (clicking)
|
||||
Virtual Boy | 32 | 64 | wavesynth unsupported
|
||||
Famicom Disk System | 64 | 64 |
|
||||
Konami SCC | 32 | 256 |
|
||||
Seta X1-010 | 128 | 256 |
|
||||
|
|
|
@ -32,7 +32,6 @@ the following sound chips have sample support:
|
|||
- Ensoniq OTTO/ES5506
|
||||
- Yamaha PCMD8/YMZ280B
|
||||
- MMC5 (last channel only)
|
||||
- SNES/S-DSP
|
||||
|
||||
## compatible sample mode
|
||||
|
||||
|
|
|
@ -25,4 +25,271 @@ Furnace isn't complete without this one...
|
|||
- `C`: low square
|
||||
- `D`: low square
|
||||
- `E`: low pure buzzy
|
||||
- `F`: low reedy
|
||||
- `F`: low reedy
|
||||
|
||||
|
||||
|
||||
# tables
|
||||
|
||||
pitch number can be used for absolute notes in arpeggio macros.
|
||||
|
||||
## shape 1
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 2096.0 | C-7 | +2 | 2080.0 | C-7 | -1
|
||||
| 1 | 1048.0 | C-6 | +2 | 1040.0 | C-6 | -1
|
||||
| 2 | 698.7 | F-5 | 0.0| 693.3 | F-5 | -1
|
||||
| 3 | 524.0 | C-5 | +2 | 520.0 | C-5 | -1
|
||||
| 4 | 419.2 | G#4 | +16 | 416.0 | G#4 | +3
|
||||
| 5 | 349.3 | F-4 | 0.0| 346.7 | F-4 | -13
|
||||
| 6 | 299.4 | D-4 | +33 | 297.1 | D-4 | +20
|
||||
| 7 | 262.0 | C-4 | +3 | 260.0 | C-4 | -11
|
||||
| 8 | 232.9 | A#3 | -2 | 231.1 | A#3 | -15
|
||||
| 9 | 209.6 | G#3 | +15 | 208.0 | G#3 | +2
|
||||
| 10 | 190.5 | F#3 | +50 | 189.1 | F#3 | +37
|
||||
| 11 | 174.7 | F-3 | +1 | 173.3 | F-3 | -13
|
||||
| 12 | 161.2 | E-3 | -39 | 160.0 | D#3 | +48
|
||||
| 13 | 149.7 | D-3 | +33 | 148.6 | D-3 | +20
|
||||
| 14 | 139.7 | C#3 | +13 | 138.7 | C#3 | +1
|
||||
| 15 | 131.0 | C-3 | +3 | 130.0 | C-3 | -11
|
||||
| 16 | 123.3 | B-2 | -3 | 122.4 | B-2 | -16
|
||||
| 17 | 116.4 | A#2 | 0.0| 115.6 | A#2 | -14
|
||||
| 18 | 110.3 | A-2 | +5 | 109.5 | A-2 | -8
|
||||
| 19 | 104.8 | G#2 | +16 | 104.0 | G#2 | +3
|
||||
| 20 | 99.8 | G-2 | +31 | 99.0 | G-2 | +17
|
||||
| 21 | 95.3 | G-2 | -49 | 94.5 | F#2 | +36
|
||||
| 22 | 91.1 | F#2 | -27 | 90.4 | F#2 | -40
|
||||
| 23 | 87.3 | F-2 | 0.0| 86.7 | F-2 | -12
|
||||
| 24 | 83.8 | E-2 | +29 | 83.2 | E-2 | +16
|
||||
| 25 | 80.6 | E-2 | -39 | 80.0 | D#2 | +48
|
||||
| 26 | 77.6 | D#2 | -5 | 77.0 | D#2 | -18
|
||||
| 27 | 74.9 | D-2 | +34 | 74.3 | D-2 | +20
|
||||
| 28 | 72.3 | D-2 | -27 | 71.7 | D-2 | -41
|
||||
| 29 | 69.9 | C#2 | +15 | 69.3 | C#2 | 0
|
||||
| 30 | 67.6 | C#2 | -44 | 67.1 | C-2 | +44
|
||||
| 31 | 65.5 | C-2 | +3 | 65.0 | C-2 | -11
|
||||
|
||||
## shapes 2, 3
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 67.6 | C#2 | -44 | 67.1 | C-2 | +44
|
||||
| 1 | 33.8 | C#1 | -42 | 33.5 | C-1 | +42
|
||||
| 2 | 22.5 | F#0 | -46 | 22.4 | F-0 | +46
|
||||
| 3 | 16.9 | C#0 | -44 | 16.8 | C-0 | +44
|
||||
| 4 | 13.5 | | | 13.4
|
||||
| 5 | 11.3 | | | 11.2
|
||||
| 6 | 9.7 | | | 9.6
|
||||
| 7 | 8.5 | | | 8.4
|
||||
| 8 | 7.5 | | | 7.5
|
||||
| 9 | 6.8 | | | 6.7
|
||||
| 10 | 6.1 | | | 6.1
|
||||
| 11 | 5.6 | | | 5.6
|
||||
| 12 | 5.2 | | | 5.2
|
||||
| 13 | 4.8 | | | 4.8
|
||||
| 14 | 4.5 | | | 4.5
|
||||
| 15 | 4.2 | | | 4.2
|
||||
| 16 | 4.0 | | | 4.0
|
||||
| 17 | 3.8 | | | 3.7
|
||||
| 18 | 3.6 | | | 3.5
|
||||
| 19 | 3.4 | | | 3.4
|
||||
| 20 | 3.2 | | | 3.2
|
||||
| 21 | 3.1 | | | 3.0
|
||||
| 22 | 3.0 | | | 2.9
|
||||
| 23 | 2.8 | | | 2.8
|
||||
| 24 | 2.7 | | | 2.7
|
||||
| 25 | 2.6 | | | 2.6
|
||||
| 26 | 2.5 | | | 2.5
|
||||
| 27 | 2.4 | | | 2.4
|
||||
| 28 | 2.3 | | | 2.3
|
||||
| 29 | 2.3 | | | 2.2
|
||||
| 30 | 2.2 | | | 2.2
|
||||
| 31 | 2.1 | | | 2.1
|
||||
|
||||
## shapes 4, 5
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 15720.0 | B-9 | -9 | 15600.0 | B-9 | -23
|
||||
| 1 | 7860.0 | B-8 | -9 | 7800.0 | B-8 | -23
|
||||
| 2 | 5240.0 | E-8 | -11 | 5200.0 | E-8 | -25
|
||||
| 3 | 3930.0 | B-7 | -10 | 3900.0 | B-7 | -23
|
||||
| 4 | 3144.0 | G-7 | +4 | 3120.0 | G-7 | -9
|
||||
| 5 | 2620.0 | E-7 | -11 | 2600.0 | E-7 | -25
|
||||
| 6 | 2245.7 | C#7 | +21 | 2228.6 | C#7 | +8
|
||||
| 7 | 1965.0 | B-6 | -9 | 1950.0 | B-6 | -23
|
||||
| 8 | 1746.7 | A-6 | -13 | 1733.3 | A-6 | -27
|
||||
| 9 | 1572.0 | G-6 | +4 | 1560.0 | G-6 | -9
|
||||
| 10 | 1429.1 | F-6 | +39 | 1418.2 | F-6 | +25
|
||||
| 11 | 1310.0 | E-6 | -11 | 1300.0 | E-6 | -25
|
||||
| 12 | 1209.2 | D-6 | +49 | 1200.0 | D-6 | +36
|
||||
| 13 | 1122.9 | C#6 | +22 | 1114.3 | C#6 | +8
|
||||
| 14 | 1048.0 | C-6 | +2 | 1040.0 | C-6 | -11
|
||||
| 15 | 982.5 | B-5 | -10 | 975.0 | B-5 | -23
|
||||
| 16 | 924.7 | A#5 | -15 | 917.6 | A#5 | -28
|
||||
| 17 | 873.3 | A-5 | -14 | 866.7 | A-5 | -27
|
||||
| 18 | 827.4 | G#5 | -7 | 821.1 | G#5 | -20
|
||||
| 19 | 786.0 | G-5 | +4 | 780.0 | G-5 | -9
|
||||
| 20 | 748.6 | F#5 | +20 | 742.9 | F#5 | +7
|
||||
| 21 | 714.5 | F-5 | +39 | 709.1 | F-5 | +26
|
||||
| 22 | 683.5 | F-5 | -38 | 678.3 | E-5 | +48
|
||||
| 23 | 655.0 | E-5 | -12 | 650.0 | E-5 | -25
|
||||
| 24 | 628.8 | D#5 | +18 | 624.0 | D#5 | +5
|
||||
| 25 | 604.6 | D-5 | +49 | 600.0 | D-5 | +36
|
||||
| 26 | 582.2 | D-5 | -16 | 577.8 | D-5 | -29
|
||||
| 27 | 561.4 | C#5 | +21 | 557.1 | C#5 | +8
|
||||
| 28 | 542.1 | C#5 | -40 | 537.9 | C-5 | +47
|
||||
| 29 | 524.0 | C-5 | +2 | 520.0 | C-5 | -11
|
||||
| 30 | 507.1 | B-4 | +45 | 503.2 | B-4 | +32
|
||||
| 31 | 491.3 | B-4 | -9 | 487.5 | B-4 | -23
|
||||
|
||||
## shapes 6, 7, 9, 10
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 1014.2 | B-5 | +45 | 1006.5 | B-5 | +32
|
||||
| 1 | 507.1 | B-4 | +45 | 503.2 | B-4 | +32
|
||||
| 2 | 338.1 | E-4 | +43 | 335.5 | E-4 | +30
|
||||
| 3 | 253.5 | B-3 | +45 | 251.6 | B-3 | +32
|
||||
| 4 | 202.8 | G#3 | -42 | 201.3 | G-3 | +45
|
||||
| 5 | 169.0 | E-3 | +43 | 167.7 | E-3 | +30
|
||||
| 6 | 144.9 | D-3 | -23 | 143.8 | D-3 | -37
|
||||
| 7 | 126.8 | B-2 | +42 | 125.8 | B-2 | +32
|
||||
| 8 | 112.7 | A-2 | +42 | 111.8 | A-2 | +28
|
||||
| 9 | 101.4 | G#2 | -41 | 100.6 | G-2 | +45
|
||||
| 10 | 92.2 | F#2 | -6 | 91.5 | F#2 | -19
|
||||
| 11 | 84.5 | E-2 | +43 | 83.9 | E-2 | +31
|
||||
| 12 | 78.0 | D#2 | +4 | 77.4 | D#2 | -9
|
||||
| 13 | 72.4 | D-2 | -24 | 71.9 | D-2 | -37
|
||||
| 14 | 67.6 | C#2 | -44 | 67.1 | C-2 | +44
|
||||
| 15 | 63.4 | B-1 | +46 | 62.9 | B-1 | +32
|
||||
| 16 | 59.7 | A#1 | +41 | 59.2 | A#1 | +26
|
||||
| 17 | 56.3 | A-1 | +39 | 55.9 | A-1 | +27
|
||||
| 18 | 53.4 | G#1 | +48 | 53.0 | G#1 | +35
|
||||
| 19 | 50.7 | G#1 | -41 | 50.3 | G-1 | +45
|
||||
| 20 | 48.3 | G-1 | -25 | 47.9 | G-1 | -39
|
||||
| 21 | 46.1 | F#1 | -4 | 45.7 | F#1 | -20
|
||||
| 22 | 44.1 | F-1 | +16 | 43.8 | F-1 | +4
|
||||
| 23 | 42.3 | E-1 | +44 | 41.9 | E-1 | +28
|
||||
| 24 | 40.6 | E-1 | -26 | 40.3 | E-1 | -39
|
||||
| 25 | 39.0 | D#1 | +4 | 38.7 | D#1 | -9
|
||||
| 26 | 37.6 | D-1 | +41 | 37.3 | D-1 | +27
|
||||
| 27 | 36.2 | D-1 | -24 | 35.9 | D-1 | -38
|
||||
| 28 | 35.0 | C#1 | +19 | 34.7 | C#1 | +5
|
||||
| 29 | 33.8 | C#1 | -42 | 33.5 | C-1 | +42
|
||||
| 30 | 32.7 | C-1 | 0.0 | 32.5 | C-1 | -11
|
||||
| 31 | 31.7 | B-0 | +44 | 31.5 | B-0 | +33
|
||||
|
||||
## shapes 8
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 61.5 | B-1 | -6| 61.1 | B-1 | -18
|
||||
| 1 | 30.8 | B-0 | -6| 30.5 | B-0 | -22
|
||||
| 2 | 20.5 | E-0 | -8| 20.4 | E-0 | -17
|
||||
| 3 | 15.4 | | | 15.3
|
||||
| 4 | 12.3 | | | 12.2
|
||||
| 5 | 10.3 | | | 10.2
|
||||
| 6 | 8.8 | | | 8.7
|
||||
| 7 | 7.7 | | | 7.6
|
||||
| 8 | 6.8 | | | 6.8
|
||||
| 9 | 6.2 | | | 6.1
|
||||
| 10 | 5.6 | | | 5.6
|
||||
| 11 | 5.1 | | | 5.1
|
||||
| 12 | 4.7 | | | 4.7
|
||||
| 13 | 4.4 | | | 4.4
|
||||
| 14 | 4.1 | | | 4.1
|
||||
| 15 | 3.8 | | | 3.8
|
||||
| 16 | 3.6 | | | 3.6
|
||||
| 17 | 3.4 | | | 3.4
|
||||
| 18 | 3.2 | | | 3.2
|
||||
| 19 | 3.1 | | | 3.1
|
||||
| 20 | 2.9 | | | 2.9
|
||||
| 21 | 2.8 | | | 2.8
|
||||
| 22 | 2.7 | | | 2.7
|
||||
| 23 | 2.6 | | | 2.5
|
||||
| 24 | 2.5 | | | 2.4
|
||||
| 25 | 2.4 | | | 2.3
|
||||
| 26 | 2.3 | | | 2.3
|
||||
| 27 | 2.2 | | | 2.2
|
||||
| 28 | 2.1 | | | 2.1
|
||||
| 29 | 2.0 | | | 2.0
|
||||
| 30 | 2.0 | | | 2.0
|
||||
| 31 | 1.9 | | | 1.9
|
||||
|
||||
## shapes 12, 13
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 5240.0 | E-8 | -11 | 5200.0 | E-8 | -25
|
||||
| 1 | 2620.0 | E-7 | -11 | 2600.0 | E-7 | -25
|
||||
| 2 | 1746.6 | A-6 | -14 | 1733.3 | A-6 | -27
|
||||
| 3 | 1310.0 | E-6 | -11 | 1300.0 | E-6 | -25
|
||||
| 4 | 1048.0 | C-6 | +2 | 1040.0 | C-6 | -11
|
||||
| 5 | 873.3 | A-5 | -14 | 866.7 | A-5 | -27
|
||||
| 6 | 748.6 | F#5 | +20 | 742.9 | F#5 | +7
|
||||
| 7 | 655.0 | E-5 | -12 | 650.0 | E-5 | -25
|
||||
| 8 | 582.2 | D-5 | -16 | 577.8 | D-5 | -29
|
||||
| 9 | 524.0 | C-5 | +2 | 520.0 | C-5 | -11
|
||||
| 10 | 476.4 | A#4 | +39 | 472.7 | A#4 | +23
|
||||
| 11 | 436.7 | A-4 | -13 | 433.3 | A-4 | -27
|
||||
| 12 | 403.1 | G-4 | +48 | 400.0 | G-4 | +34
|
||||
| 13 | 374.3 | F#4 | +20 | 371.4 | F#4 | +6
|
||||
| 14 | 349.3 | F-4 | 0.0 | 346.7 | F-4 | -13
|
||||
| 15 | 327.5 | E-4 | -11 | 325.0 | E-4 | -25
|
||||
| 16 | 308.2 | D#4 | -17 | 305.9 | D#4 | -30
|
||||
| 17 | 291.1 | D-4 | -16 | 288.9 | D-4 | -29
|
||||
| 18 | 275.8 | C#4 | -9 | 273.7 | C#4 | -22
|
||||
| 19 | 262.0 | C-4 | +3 | 260.0 | C-4 | -11
|
||||
| 20 | 249.5 | B-3 | +18 | 247.6 | B-3 | +5
|
||||
| 21 | 238.2 | A#3 | +37 | 236.4 | A#3 | +24
|
||||
| 22 | 227.8 | A#3 | -40 | 226.1 | A-3 | +47
|
||||
| 23 | 218.3 | A-3 | -14 | 216.7 | A-3 | -27
|
||||
| 24 | 209.6 | G#3 | +15 | 208.0 | G#3 | +2
|
||||
| 25 | 201.5 | G-3 | +47 | 200.0 | G-3 | +34
|
||||
| 26 | 194.1 | G-3 | -17 | 192.6 | G-3 | -31
|
||||
| 27 | 187.1 | F#3 | +19 | 185.7 | F#3 | +6
|
||||
| 28 | 180.7 | F#3 | -41 | 179.3 | F-3 | +45
|
||||
| 29 | 174.7 | F-3 | +1 | 173.3 | F-3 | -13
|
||||
| 30 | 169.0 | E-3 | +43 | 167.7 | E-3 | +30
|
||||
| 31 | 163.8 | E-3 | -11 | 162.5 | E-3 | -25
|
||||
|
||||
## shapes 14, 15
|
||||
|
||||
| pitch | NTSC | note | cent | PAL | note | cent
|
||||
|------:|--------:|:----:|-----:|--------:|:----:|-----:
|
||||
| 0 | 338.1 | E-4 | +43 | 335.5 | E-4 | +30
|
||||
| 1 | 169.0 | E-3 | +43 | 167.7 | E-3 | +30
|
||||
| 2 | 112.7 | A-2 | +42 | 111.8 | A-2 | +28
|
||||
| 3 | 84.5 | E-2 | +43 | 83.9 | E-2 | +31
|
||||
| 4 | 67.6 | C#2 | -44 | 67.1 | C-2 | +44
|
||||
| 5 | 56.3 | A-1 | +39 | 55.9 | A-1 | +27
|
||||
| 6 | 48.3 | G-1 | -25 | 47.9 | G-1 | -39
|
||||
| 7 | 42.3 | E-1 | +44 | 41.9 | E-1 | +28
|
||||
| 8 | 37.6 | D-1 | +41 | 37.3 | D-1 | +27
|
||||
| 9 | 33.8 | C#1 | -42 | 33.5 | C-1 | +42
|
||||
| 10 | 30.7 | B-0 | -11 | 30.5 | B-0 | -22
|
||||
| 11 | 28.2 | A-0 | +44 | 28.0 | A-0 | +31
|
||||
| 12 | 26.0 | G#0 | 0.0 | 25.8 | G#0 | -13
|
||||
| 13 | 24.1 | G-0 | -29 | 24.0 | G-0 | -36
|
||||
| 14 | 22.5 | F#0 | -46 | 22.4 | F-0 | +46
|
||||
| 15 | 21.1 | E-0 | +42 | 21.0 | E-0 | +33
|
||||
| 16 | 19.9 | D#0 | +42 | 19.7 | D#0 | +25
|
||||
| 17 | 18.8 | D-0 | +40 | 18.6 | D-0 | +20
|
||||
| 18 | 17.8 | C#0 | +45 | 17.7 | C#0 | +36
|
||||
| 19 | 16.9 | C#0 | -44 | 16.8 | C-0 | +44
|
||||
| 20 | 16.1 | C-0 | -30 | 16.0 | C-0 | -40
|
||||
| 21 | 15.4 | | | 15.2
|
||||
| 22 | 14.7 | | | 14.6
|
||||
| 23 | 14.1 | | | 14
|
||||
| 24 | 13.5 | | | 13.4
|
||||
| 25 | 13.0 | | | 12.9
|
||||
| 26 | 12.5 | | | 12.4
|
||||
| 27 | 12.1 | | | 12
|
||||
| 28 | 11.7 | | | 11.6
|
||||
| 29 | 11.3 | | | 11.2
|
||||
| 30 | 10.9 | | | 10.8
|
||||
| 31 | 10.6 | | | 10.5
|
||||
|
||||
reference: [Atari 2600 VCS Sound Frequency and Waveform Guide](http://7800.8bitdev.org/index.php/Atari_2600_VCS_Sound_Frequency_and_Waveform_Guide)
|
|
@ -3,4 +3,5 @@
|
|||
here is a small collection of useful tricks and techniques to really make Furnace sing.
|
||||
|
||||
- [using samples with limited playback rates](limited-samples.md)
|
||||
- [choosing emulation cores](emulation-cores.md)
|
||||
- [choosing emulation cores](emulation-cores.md)
|
||||
- [guide on using OPLL patch macro](opllswitching.md)
|
19
doc/9-guides/opllswitching.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# using OPLL patch macro
|
||||
|
||||
YM2413's biggest flaw (or, rather, cost-saving feature) was that it could use only one user-defined instrument at once. It wasn't monotimbrial; you could use 15 built-in presets and 5 built-in drum tones freely, but for these going off the beaten path, it surely was limiting. However, there is one technique, as amazing as simple: **mid-note preset switching**.
|
||||
|
||||
the idea is to use the first patch to put the envelope in an unintended state for the second patch so that it sounds different, with a higher or lower modulation level. the sustain level defines at which "envelope level" the envelope will switch to the sustain state (or release depending on envelope type). if the first patch is used to put the envelope into sustain at a higher or lower envelope state than intended for the second patch, it'll still be in sustain/release but at a higher or lower level than it should be at that point.
|
||||
|
||||
therefore, much more variety can be forced out, without using custom instruments. As of July 2023, Furnace is the only tool supporting this feature. It is accessed in 'Macros' tab in OPLL instrument editor.
|
||||
|
||||
For example, try putting the first macro value as 14 (acoustic bass preset), followed by 4 (flute preset). This way you will get distortion guitar-like sound this is nothing like other 2413 preset! There are many combination to test out, which is highly recommended (I can only say, 12->1 or 12->4 produces sound similiar to the well-known 4-op FM mallet brass)
|
||||
|
||||
## drums using this technique
|
||||
|
||||
Using OPLL's drum mode, described is systems/opll.md, you gain access to 5 hardcoded drum tones at the expense of 3 melodic FM channels. Patch switching eliminates that, as using it, it's also possible to construct percussive sounds, some even fuller than their drum mode counterparts!
|
||||
In short, noise portion of drums (as in hi-hats), can be created of the very high pitched pseudo-distortion guitar, described as above. For kicks, snares, toms and claps, more effort is needed, however using volume and arpeggio macros will help.
|
||||
|
||||
## examples
|
||||
|
||||
- [Lman-Clubster cover by Mahbod](https://www.youtube.com/watch?v=jfHs7tSyjXI)
|
||||
- [OPLL Nation by Mahbod](https://www.youtube.com/watch?v=ou6pEfxByeE)
|
|
@ -25,8 +25,3 @@ writers:
|
|||
- WindowxDeveloper
|
||||
- polluks
|
||||
- Electric Keet
|
||||
|
||||
other:
|
||||
|
||||
- [3-pattern/keyboard.png](3-pattern/keyboard.png) licensed under CC-BY-SA 3.0.
|
||||
- this is a derivative of [KB United States.svg](https://en.wikipedia.org/wiki/File:KB_United_States.svg) by Denelson83 under the same license.
|
||||
|
|
416
extern/igfd/ImGuiFileDialog.cpp
vendored
|
@ -800,138 +800,138 @@ namespace IGFD
|
|||
|
||||
// will be called internally
|
||||
// will not been exposed to IGFD API
|
||||
bool IGFD::FilterManager::prFillFileStyle(std::shared_ptr<FileInfos> vFileInfos) const
|
||||
bool IGFD::FilterManager::prFillFileStyle(FileInfos& vFileInfos) const
|
||||
{
|
||||
if (vFileInfos.use_count() && !prFilesStyle.empty())
|
||||
if (!prFilesStyle.empty())
|
||||
{
|
||||
for (const auto& _flag : prFilesStyle)
|
||||
{
|
||||
for (const auto& _file : _flag.second)
|
||||
{
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType == 'd')
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos.fileType == 'd')
|
||||
{
|
||||
if (_file.first.empty()) // for all dirs
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
else if (_file.first == vFileInfos->fileNameExt) // for dirs who are equal to style criteria
|
||||
else if (_file.first == vFileInfos.fileNameExt) // for dirs who are equal to style criteria
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType == 'f')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos.fileType == 'f')
|
||||
{
|
||||
if (_file.first.empty()) // for all files
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
else if (_file.first == vFileInfos->fileNameExt) // for files who are equal to style criteria
|
||||
else if (_file.first == vFileInfos.fileNameExt) // for files who are equal to style criteria
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType == 'l')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos.fileType == 'l')
|
||||
{
|
||||
if (_file.first.empty()) // for all links
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
else if (_file.first == vFileInfos->fileNameExt) // for links who are equal to style criteria
|
||||
else if (_file.first == vFileInfos.fileNameExt) // for links who are equal to style criteria
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (_flag.first & IGFD_FileStyleByExtention)
|
||||
{
|
||||
if (_file.first == vFileInfos->fileExt)
|
||||
if (_file.first == vFileInfos.fileExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
|
||||
// can make sense for some dirs like the hidden by ex ".git"
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType == 'd')
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos.fileType == 'd')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileExt)
|
||||
if (_file.first == vFileInfos.fileExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType == 'f')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos.fileType == 'f')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileExt)
|
||||
if (_file.first == vFileInfos.fileExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType == 'l')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos.fileType == 'l')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileExt)
|
||||
if (_file.first == vFileInfos.fileExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_flag.first & IGFD_FileStyleByFullName)
|
||||
{
|
||||
if (_file.first == vFileInfos->fileNameExt)
|
||||
if (_file.first == vFileInfos.fileNameExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType == 'd')
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos.fileType == 'd')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileNameExt)
|
||||
if (_file.first == vFileInfos.fileNameExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType == 'f')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos.fileType == 'f')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileNameExt)
|
||||
if (_file.first == vFileInfos.fileNameExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType == 'l')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos.fileType == 'l')
|
||||
{
|
||||
if (_file.first == vFileInfos->fileNameExt)
|
||||
if (_file.first == vFileInfos.fileNameExt)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_flag.first & IGFD_FileStyleByContainedInFullName)
|
||||
{
|
||||
if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos)
|
||||
if (vFileInfos.fileNameExt.find(_file.first) != std::string::npos)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType == 'd')
|
||||
if (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos.fileType == 'd')
|
||||
{
|
||||
if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos)
|
||||
if (vFileInfos.fileNameExt.find(_file.first) != std::string::npos)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType == 'f')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos.fileType == 'f')
|
||||
{
|
||||
if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos)
|
||||
if (vFileInfos.fileNameExt.find(_file.first) != std::string::npos)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType == 'l')
|
||||
else if (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos.fileType == 'l')
|
||||
{
|
||||
if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos)
|
||||
if (vFileInfos.fileNameExt.find(_file.first) != std::string::npos)
|
||||
{
|
||||
vFileInfos->fileStyle = _file.second;
|
||||
vFileInfos.fileStyle = _file.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vFileInfos->fileStyle.use_count())
|
||||
if (vFileInfos.fileStyle.use_count())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1142,6 +1142,7 @@ namespace IGFD
|
|||
for (int i=1; i<4; i++) {
|
||||
puSortingDirection[i]=false;
|
||||
}
|
||||
invalidFile.isValid=false;
|
||||
}
|
||||
|
||||
void IGFD::FileManager::OpenCurrentPath(const FileDialogInternal& vFileDialogInternal)
|
||||
|
@ -1191,29 +1192,24 @@ namespace IGFD
|
|||
puHeaderFileName = tableHeaderDescendingIcon + puHeaderFileName;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
// this code fail in c:\\Users with the link "All users". got a invalid comparator
|
||||
/*
|
||||
// use code from https://github.com/jackm97/ImGuiFileDialog/commit/bf40515f5a1de3043e60562dc1a494ee7ecd3571
|
||||
// strict ordering for file/directory types beginning in '.'
|
||||
// common on Linux platforms
|
||||
if (a->fileNameExt[0] == '.' && b->fileNameExt[0] != '.')
|
||||
if (a.fileNameExt[0] == '.' && b.fileNameExt[0] != '.')
|
||||
return false;
|
||||
if (a->fileNameExt[0] != '.' && b->fileNameExt[0] == '.')
|
||||
if (a.fileNameExt[0] != '.' && b.fileNameExt[0] == '.')
|
||||
return true;
|
||||
if (a->fileNameExt[0] == '.' && b->fileNameExt[0] == '.')
|
||||
if (a.fileNameExt[0] == '.' && b.fileNameExt[0] == '.')
|
||||
{
|
||||
return (stricmp(a->fileNameExt.c_str(), b->fileNameExt.c_str()) < 0); // sort in insensitive case
|
||||
return (stricmp(a.fileNameExt.c_str(), b.fileNameExt.c_str()) < 0); // sort in insensitive case
|
||||
}
|
||||
*/
|
||||
if (a->fileType != b->fileType) return (a->fileType == 'd'); // directory in first
|
||||
return (stricmp(a->fileNameExt.c_str(), b->fileNameExt.c_str()) < 0); // sort in insensitive case
|
||||
if (a.fileType != b.fileType) return (a.fileType == 'd'); // directory in first
|
||||
return (stricmp(a.fileNameExt.c_str(), b.fileNameExt.c_str()) < 0); // sort in insensitive case
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -1222,28 +1218,23 @@ namespace IGFD
|
|||
puHeaderFileName = tableHeaderAscendingIcon + puHeaderFileName;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
// this code fail in c:\\Users with the link "All users". got a invalid comparator
|
||||
/*
|
||||
// use code from https://github.com/jackm97/ImGuiFileDialog/commit/bf40515f5a1de3043e60562dc1a494ee7ecd3571
|
||||
// strict ordering for file/directory types beginning in '.'
|
||||
// common on Linux platforms
|
||||
if (a->fileNameExt[0] == '.' && b->fileNameExt[0] != '.')
|
||||
if (a.fileNameExt[0] == '.' && b.fileNameExt[0] != '.')
|
||||
return false;
|
||||
if (a->fileNameExt[0] != '.' && b->fileNameExt[0] == '.')
|
||||
if (a.fileNameExt[0] != '.' && b.fileNameExt[0] == '.')
|
||||
return true;
|
||||
if (a->fileNameExt[0] == '.' && b->fileNameExt[0] == '.')
|
||||
if (a.fileNameExt[0] == '.' && b.fileNameExt[0] == '.')
|
||||
{
|
||||
return (stricmp(a->fileNameExt.c_str(), b->fileNameExt.c_str()) > 0); // sort in insensitive case
|
||||
return (stricmp(a.fileNameExt.c_str(), b.fileNameExt.c_str()) > 0); // sort in insensitive case
|
||||
}
|
||||
*/
|
||||
return (stricmp(a->fileNameExt.c_str(), b->fileNameExt.c_str()) > 0); // sort in insensitive case
|
||||
return (stricmp(a.fileNameExt.c_str(), b.fileNameExt.c_str()) > 0); // sort in insensitive case
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1259,13 +1250,10 @@ namespace IGFD
|
|||
puHeaderFileType = tableHeaderDescendingIcon + puHeaderFileType;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType == 'd'); // directory in first
|
||||
return (a->fileExt < b->fileExt); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType == 'd'); // directory in first
|
||||
return (a.fileExt < b.fileExt); // else
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -1274,15 +1262,10 @@ namespace IGFD
|
|||
puHeaderFileType = tableHeaderAscendingIcon + puHeaderFileType;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last
|
||||
return (a->fileExt > b->fileExt); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType != 'd'); // directory in last
|
||||
return (a.fileExt > b.fileExt); // else
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1298,15 +1281,10 @@ namespace IGFD
|
|||
puHeaderFileSize = tableHeaderDescendingIcon + puHeaderFileSize;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType == 'd'); // directory in first
|
||||
return (a->fileSize < b->fileSize); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType == 'd'); // directory in first
|
||||
return (a.fileSize < b.fileSize); // else
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -1315,15 +1293,10 @@ namespace IGFD
|
|||
puHeaderFileSize = tableHeaderAscendingIcon + puHeaderFileSize;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last
|
||||
return (a->fileSize > b->fileSize); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType != 'd'); // directory in last
|
||||
return (a.fileSize > b.fileSize); // else
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1339,15 +1312,10 @@ namespace IGFD
|
|||
puHeaderFileDate = tableHeaderDescendingIcon + puHeaderFileDate;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType == 'd'); // directory in first
|
||||
return (a->fileModifDate < b->fileModifDate); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType == 'd'); // directory in first
|
||||
return (a.fileModifDate < b.fileModifDate); // else
|
||||
});
|
||||
}
|
||||
else
|
||||
|
@ -1356,15 +1324,10 @@ namespace IGFD
|
|||
puHeaderFileDate = tableHeaderAscendingIcon + puHeaderFileDate;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (a==NULL || b==NULL)
|
||||
return false;
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last
|
||||
return (a->fileModifDate > b->fileModifDate); // else
|
||||
if (a.fileType != b.fileType) return (a.fileType != 'd'); // directory in last
|
||||
return (a.fileModifDate > b.fileModifDate); // else
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1384,15 +1347,12 @@ namespace IGFD
|
|||
puHeaderFileThumbnails = tableHeaderDescendingIcon + puHeaderFileThumbnails;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType == 'd'); // directory in first
|
||||
if (a->thumbnailInfo.textureWidth == b->thumbnailInfo.textureWidth)
|
||||
return (a->thumbnailInfo.textureHeight < b->thumbnailInfo.textureHeight);
|
||||
return (a->thumbnailInfo.textureWidth < b->thumbnailInfo.textureWidth);
|
||||
if (a.fileType != b.fileType) return (a.fileType == 'd'); // directory in first
|
||||
if (a.thumbnailInfo.textureWidth == b.thumbnailInfo.textureWidth)
|
||||
return (a.thumbnailInfo.textureHeight < b.thumbnailInfo.textureHeight);
|
||||
return (a.thumbnailInfo.textureWidth < b.thumbnailInfo.textureWidth);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1402,15 +1362,12 @@ namespace IGFD
|
|||
puHeaderFileThumbnails = tableHeaderAscendingIcon + puHeaderFileThumbnails;
|
||||
#endif // USE_CUSTOM_SORTING_ICON
|
||||
std::sort(prFileList.begin(), prFileList.end(),
|
||||
[](const std::shared_ptr<FileInfos>& a, const std::shared_ptr<FileInfos>& b) -> bool
|
||||
[](const FileInfos& a, const FileInfos& b) -> bool
|
||||
{
|
||||
if (!a.use_count() || !b.use_count())
|
||||
return false;
|
||||
|
||||
if (a->fileType != b->fileType) return (a->fileType != 'd'); // directory in last
|
||||
if (a->thumbnailInfo.textureWidth == b->thumbnailInfo.textureWidth)
|
||||
return (a->thumbnailInfo.textureHeight > b->thumbnailInfo.textureHeight);
|
||||
return (a->thumbnailInfo.textureWidth > b->thumbnailInfo.textureWidth);
|
||||
if (a.fileType != b.fileType) return (a.fileType != 'd'); // directory in last
|
||||
if (a.thumbnailInfo.textureWidth == b.thumbnailInfo.textureWidth)
|
||||
return (a.thumbnailInfo.textureHeight > b.thumbnailInfo.textureHeight);
|
||||
return (a.thumbnailInfo.textureWidth > b.thumbnailInfo.textureWidth);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1441,38 +1398,38 @@ namespace IGFD
|
|||
return fileNameExt;
|
||||
}
|
||||
|
||||
void IGFD::FileManager::AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, const char& vFileType, void* ent)
|
||||
void IGFD::FileManager::AddFile(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, char vFileType, void* ent)
|
||||
{
|
||||
auto infos = std::make_shared<FileInfos>();
|
||||
FileInfos infos;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct dirent* dent=(struct dirent*)ent;
|
||||
#endif
|
||||
|
||||
infos->filePath = vPath;
|
||||
infos->fileNameExt = vFileName;
|
||||
infos->fileNameExt_optimized = prOptimizeFilenameForSearchOperations(infos->fileNameExt);
|
||||
infos->fileType = vFileType;
|
||||
infos.filePath = vPath;
|
||||
infos.fileNameExt = vFileName;
|
||||
infos.fileNameExt_optimized = prOptimizeFilenameForSearchOperations(infos.fileNameExt);
|
||||
infos.fileType = vFileType;
|
||||
|
||||
if (infos->fileNameExt.empty() || ((infos->fileNameExt == "." || infos->fileNameExt == "..") && !vFileDialogInternal.puFilterManager.puDLGFilters.empty())) return; // filename empty or filename is the current dir '.' //-V807
|
||||
if (infos->fileNameExt != ".." && (vFileDialogInternal.puDLGflags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos->fileNameExt[0] == '.') // dont show hidden files
|
||||
if (!vFileDialogInternal.puFilterManager.puDLGFilters.empty() || (vFileDialogInternal.puFilterManager.puDLGFilters.empty() && infos->fileNameExt != ".")) // except "." if in directory mode //-V728
|
||||
if (infos.fileNameExt.empty() || ((infos.fileNameExt == "." || infos.fileNameExt == "..") && !vFileDialogInternal.puFilterManager.puDLGFilters.empty())) return; // filename empty or filename is the current dir '.' //-V807
|
||||
if (infos.fileNameExt != ".." && (vFileDialogInternal.puDLGflags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos.fileNameExt[0] == '.') // dont show hidden files
|
||||
if (!vFileDialogInternal.puFilterManager.puDLGFilters.empty() || (vFileDialogInternal.puFilterManager.puDLGFilters.empty() && infos.fileNameExt != ".")) // except "." if in directory mode //-V728
|
||||
return;
|
||||
|
||||
if (infos->fileType == 'f' ||
|
||||
infos->fileType == 'l') // link can have the same extention of a file
|
||||
if (infos.fileType == 'f' ||
|
||||
infos.fileType == 'l') // link can have the same extention of a file
|
||||
{
|
||||
size_t lpt = infos->fileNameExt.find_last_of('.');
|
||||
size_t lpt = infos.fileNameExt.find_last_of('.');
|
||||
if (lpt != std::string::npos)
|
||||
{
|
||||
infos->fileExt = infos->fileNameExt.substr(lpt);
|
||||
infos.fileExt = infos.fileNameExt.substr(lpt);
|
||||
}
|
||||
|
||||
for (char& i: infos->fileExt) {
|
||||
for (char& i: infos.fileExt) {
|
||||
if (i>='A' && i<='Z') i+='a'-'A';
|
||||
}
|
||||
|
||||
if (!vFileDialogInternal.puFilterManager.IsCoveredByFilters(infos->fileExt))
|
||||
if (!vFileDialogInternal.puFilterManager.IsCoveredByFilters(infos.fileExt))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1483,16 +1440,16 @@ namespace IGFD
|
|||
SYSTEMTIME localTime;
|
||||
char timebuf[100];
|
||||
|
||||
infos->fileSize=dent->dwin_size;
|
||||
infos.fileSize=dent->dwin_size;
|
||||
if (FileTimeToSystemTime(&dent->dwin_mtime,&systemTime)==TRUE) {
|
||||
if (SystemTimeToTzSpecificLocalTime(NULL,&systemTime,&localTime)==TRUE) {
|
||||
snprintf(timebuf,99,"%d/%.2d/%.2d %.2d:%.2d",localTime.wYear,localTime.wMonth,localTime.wDay,localTime.wHour,localTime.wMinute);
|
||||
} else {
|
||||
snprintf(timebuf,99,"%d/%.2d/%.2d %.2d:%.2d",systemTime.wYear,systemTime.wMonth,systemTime.wDay,systemTime.wHour,systemTime.wMinute);
|
||||
}
|
||||
infos->fileModifDate=timebuf;
|
||||
infos.fileModifDate=timebuf;
|
||||
} else {
|
||||
infos->fileModifDate="???";
|
||||
infos.fileModifDate="???";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1534,7 +1491,7 @@ namespace IGFD
|
|||
{
|
||||
struct dirent* ent = files[i];
|
||||
std::string where = path + std::string(PATH_SEP_STR) + std::string(ent->d_name);
|
||||
char fileType = 0;
|
||||
char fileType = 'f';
|
||||
#if defined(HAVE_DIRENT_TYPE) || defined(_WIN32)
|
||||
if (ent->d_type != DT_UNKNOWN)
|
||||
{
|
||||
|
@ -1544,7 +1501,7 @@ namespace IGFD
|
|||
fileType = 'f'; break;
|
||||
case DT_DIR:
|
||||
fileType = 'd'; break;
|
||||
case DT_LNK:
|
||||
case DT_LNK: {
|
||||
#ifdef _WIN32
|
||||
fileType = 'f';
|
||||
#else
|
||||
|
@ -1557,7 +1514,8 @@ namespace IGFD
|
|||
}
|
||||
else
|
||||
{
|
||||
fileType = 'l';
|
||||
// why does 'l' make it crash?
|
||||
fileType = 'f';
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1568,6 +1526,9 @@ namespace IGFD
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fileType = 'f'; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif // HAVE_DIRENT_TYPE
|
||||
|
@ -1622,12 +1583,12 @@ namespace IGFD
|
|||
ClearFileLists();
|
||||
for (auto& drive : drives)
|
||||
{
|
||||
auto info = std::make_shared<FileInfos>();
|
||||
info->fileNameExt = drive;
|
||||
info->fileNameExt_optimized = prOptimizeFilenameForSearchOperations(drive);
|
||||
info->fileType = 'd';
|
||||
FileInfos info;
|
||||
info.fileNameExt = drive;
|
||||
info.fileNameExt_optimized = prOptimizeFilenameForSearchOperations(drive);
|
||||
info.fileType = 'd';
|
||||
|
||||
if (!info->fileNameExt.empty())
|
||||
if (!info.fileNameExt.empty())
|
||||
{
|
||||
prFileList.push_back(info);
|
||||
}
|
||||
|
@ -1658,11 +1619,11 @@ namespace IGFD
|
|||
return prFileList.size();
|
||||
}
|
||||
|
||||
std::shared_ptr<FileInfos> IGFD::FileManager::GetFullFileAt(size_t vIdx)
|
||||
const FileInfos& IGFD::FileManager::GetFullFileAt(size_t vIdx)
|
||||
{
|
||||
if (vIdx < prFileList.size())
|
||||
return prFileList[vIdx];
|
||||
return nullptr;
|
||||
return invalidFile;
|
||||
}
|
||||
|
||||
bool IGFD::FileManager::IsFilteredListEmpty()
|
||||
|
@ -1675,11 +1636,11 @@ namespace IGFD
|
|||
return prFilteredFileList.size();
|
||||
}
|
||||
|
||||
std::shared_ptr<FileInfos> IGFD::FileManager::GetFilteredFileAt(size_t vIdx)
|
||||
const FileInfos& IGFD::FileManager::GetFilteredFileAt(size_t vIdx)
|
||||
{
|
||||
if (vIdx < prFilteredFileList.size())
|
||||
return prFilteredFileList[vIdx];
|
||||
return nullptr;
|
||||
return invalidFile;
|
||||
}
|
||||
|
||||
bool IGFD::FileManager::IsFileNameSelected(const std::string& vFileName)
|
||||
|
@ -1706,14 +1667,12 @@ namespace IGFD
|
|||
void IGFD::FileManager::ApplyFilteringOnFileList(const FileDialogInternal& vFileDialogInternal)
|
||||
{
|
||||
prFilteredFileList.clear();
|
||||
for (const auto& file : prFileList)
|
||||
for (const FileInfos& file : prFileList)
|
||||
{
|
||||
if (!file.use_count())
|
||||
continue;
|
||||
bool show = true;
|
||||
if (!file->IsTagFound(vFileDialogInternal.puSearchManager.puSearchTag)) // if search tag
|
||||
if (!file.IsTagFound(vFileDialogInternal.puSearchManager.puSearchTag)) // if search tag
|
||||
show = false;
|
||||
if (puDLGDirectoryMode && file->fileType != 'd') // directory mode
|
||||
if (puDLGDirectoryMode && file.fileType != 'd') // directory mode
|
||||
show = false;
|
||||
if (show)
|
||||
prFilteredFileList.push_back(file);
|
||||
|
@ -1750,13 +1709,10 @@ namespace IGFD
|
|||
return "";
|
||||
}
|
||||
|
||||
void IGFD::FileManager::prCompleteFileInfos(const std::shared_ptr<FileInfos>& vInfos)
|
||||
void IGFD::FileManager::prCompleteFileInfos(FileInfos& vInfos)
|
||||
{
|
||||
if (!vInfos.use_count())
|
||||
return;
|
||||
|
||||
if (vInfos->fileNameExt != "." &&
|
||||
vInfos->fileNameExt != "..")
|
||||
if (vInfos.fileNameExt != "." &&
|
||||
vInfos.fileNameExt != "..")
|
||||
{
|
||||
// _stat struct :
|
||||
//dev_t st_dev; /* ID of device containing file */
|
||||
|
@ -1774,25 +1730,25 @@ namespace IGFD
|
|||
//time_t st_ctime; /* time of last status change - not sure out of ntfs */
|
||||
|
||||
#ifdef _WIN32
|
||||
if (vInfos->fileType != 'd')
|
||||
if (vInfos.fileType != 'd')
|
||||
{
|
||||
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
|
||||
vInfos.formatedFileSize = prFormatFileSize(vInfos.fileSize);
|
||||
}
|
||||
#else
|
||||
std::string fpn;
|
||||
|
||||
if (vInfos->fileType == 'f' || vInfos->fileType == 'l' || vInfos->fileType == 'd') // file
|
||||
fpn = vInfos->filePath + std::string(1u, PATH_SEP) + vInfos->fileNameExt;
|
||||
if (vInfos.fileType == 'f' || vInfos.fileType == 'l' || vInfos.fileType == 'd') // file
|
||||
fpn = vInfos.filePath + std::string(1u, PATH_SEP) + vInfos.fileNameExt;
|
||||
|
||||
struct stat statInfos = {};
|
||||
char timebuf[100];
|
||||
int result = stat(fpn.c_str(), &statInfos);
|
||||
if (result!=-1)
|
||||
{
|
||||
if (vInfos->fileType != 'd')
|
||||
if (vInfos.fileType != 'd')
|
||||
{
|
||||
vInfos->fileSize = (size_t)statInfos.st_size;
|
||||
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
|
||||
vInfos.fileSize = (size_t)statInfos.st_size;
|
||||
vInfos.formatedFileSize = prFormatFileSize(vInfos.fileSize);
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
|
@ -1806,12 +1762,12 @@ namespace IGFD
|
|||
#endif // MSVC
|
||||
if (len)
|
||||
{
|
||||
vInfos->fileModifDate = std::string(timebuf, len);
|
||||
vInfos.fileModifDate = std::string(timebuf, len);
|
||||
}
|
||||
} else {
|
||||
vInfos->fileSize=0;
|
||||
vInfos->formatedFileSize = prFormatFileSize(vInfos->fileSize);
|
||||
vInfos->fileModifDate="???";
|
||||
vInfos.fileSize=0;
|
||||
vInfos.formatedFileSize = prFormatFileSize(vInfos.fileSize);
|
||||
vInfos.fileModifDate="???";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1994,14 +1950,11 @@ namespace IGFD
|
|||
IGFD::Utils::SetBuffer(puFileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFileName);
|
||||
}
|
||||
|
||||
bool IGFD::FileManager::SelectDirectory(const std::shared_ptr<FileInfos>& vInfos)
|
||||
bool IGFD::FileManager::SelectDirectory(const FileInfos& vInfos)
|
||||
{
|
||||
if (!vInfos.use_count())
|
||||
return false;
|
||||
|
||||
bool pathClick = false;
|
||||
|
||||
if (vInfos->fileNameExt == "..")
|
||||
if (vInfos.fileNameExt == "..")
|
||||
{
|
||||
pathClick = SetPathOnParentDirectoryIfAny();
|
||||
}
|
||||
|
@ -2011,23 +1964,23 @@ namespace IGFD
|
|||
|
||||
if (puShowDrives)
|
||||
{
|
||||
newPath = vInfos->fileNameExt + std::string(1u, PATH_SEP);
|
||||
newPath = vInfos.fileNameExt + std::string(1u, PATH_SEP);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (puFsRoot == prCurrentPath)
|
||||
newPath = prCurrentPath + vInfos->fileNameExt;
|
||||
newPath = prCurrentPath + vInfos.fileNameExt;
|
||||
else
|
||||
#endif // __linux__
|
||||
newPath = prCurrentPath + std::string(1u, PATH_SEP) + vInfos->fileNameExt;
|
||||
newPath = prCurrentPath + std::string(1u, PATH_SEP) + vInfos.fileNameExt;
|
||||
}
|
||||
|
||||
if (IGFD::Utils::IsDirectoryExist(newPath))
|
||||
{
|
||||
if (puShowDrives)
|
||||
{
|
||||
prCurrentPath = vInfos->fileNameExt;
|
||||
prCurrentPath = vInfos.fileNameExt;
|
||||
puFsRoot = prCurrentPath;
|
||||
}
|
||||
else
|
||||
|
@ -2041,35 +1994,32 @@ namespace IGFD
|
|||
return pathClick;
|
||||
}
|
||||
|
||||
void IGFD::FileManager::SelectFileName(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr<FileInfos>& vInfos)
|
||||
void IGFD::FileManager::SelectFileName(const FileDialogInternal& vFileDialogInternal, const FileInfos& vInfos)
|
||||
{
|
||||
if (!vInfos.use_count())
|
||||
return;
|
||||
|
||||
if (ImGui::GetIO().KeyCtrl)
|
||||
{
|
||||
if (puDLGcountSelectionMax == 0) // infinite selection
|
||||
{
|
||||
if (prSelectedFileNames.find(vInfos->fileNameExt) == prSelectedFileNames.end()) // not found +> add
|
||||
if (prSelectedFileNames.find(vInfos.fileNameExt) == prSelectedFileNames.end()) // not found +> add
|
||||
{
|
||||
prAddFileNameInSelection(vInfos->fileNameExt, true);
|
||||
prAddFileNameInSelection(vInfos.fileNameExt, true);
|
||||
}
|
||||
else // found +> remove
|
||||
{
|
||||
prRemoveFileNameInSelection(vInfos->fileNameExt);
|
||||
prRemoveFileNameInSelection(vInfos.fileNameExt);
|
||||
}
|
||||
}
|
||||
else // selection limited by size
|
||||
{
|
||||
if (prSelectedFileNames.size() < puDLGcountSelectionMax)
|
||||
{
|
||||
if (prSelectedFileNames.find(vInfos->fileNameExt) == prSelectedFileNames.end()) // not found +> add
|
||||
if (prSelectedFileNames.find(vInfos.fileNameExt) == prSelectedFileNames.end()) // not found +> add
|
||||
{
|
||||
prAddFileNameInSelection(vInfos->fileNameExt, true);
|
||||
prAddFileNameInSelection(vInfos.fileNameExt, true);
|
||||
}
|
||||
else // found +> remove
|
||||
{
|
||||
prRemoveFileNameInSelection(vInfos->fileNameExt);
|
||||
prRemoveFileNameInSelection(vInfos.fileNameExt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2081,18 +2031,15 @@ namespace IGFD
|
|||
prSelectedFileNames.clear();
|
||||
// we will iterate filelist and get the last selection after the start selection
|
||||
bool startMultiSelection = false;
|
||||
std::string fileNameToSelect = vInfos->fileNameExt;
|
||||
std::string fileNameToSelect = vInfos.fileNameExt;
|
||||
std::string savedLastSelectedFileName; // for invert selection mode
|
||||
for (const auto& file : prFileList)
|
||||
for (const FileInfos& file : prFileList)
|
||||
{
|
||||
if (!file.use_count())
|
||||
continue;
|
||||
|
||||
bool canTake = true;
|
||||
if (!file->IsTagFound(vFileDialogInternal.puSearchManager.puSearchTag)) canTake = false;
|
||||
if (!file.IsTagFound(vFileDialogInternal.puSearchManager.puSearchTag)) canTake = false;
|
||||
if (canTake) // if not filtered, we will take files who are filtered by the dialog
|
||||
{
|
||||
if (file->fileNameExt == prLastSelectedFileName)
|
||||
if (file.fileNameExt == prLastSelectedFileName)
|
||||
{
|
||||
startMultiSelection = true;
|
||||
prAddFileNameInSelection(prLastSelectedFileName, false);
|
||||
|
@ -2101,13 +2048,13 @@ namespace IGFD
|
|||
{
|
||||
if (puDLGcountSelectionMax == 0) // infinite selection
|
||||
{
|
||||
prAddFileNameInSelection(file->fileNameExt, false);
|
||||
prAddFileNameInSelection(file.fileNameExt, false);
|
||||
}
|
||||
else // selection limited by size
|
||||
{
|
||||
if (prSelectedFileNames.size() < puDLGcountSelectionMax)
|
||||
{
|
||||
prAddFileNameInSelection(file->fileNameExt, false);
|
||||
prAddFileNameInSelection(file.fileNameExt, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2119,7 +2066,7 @@ namespace IGFD
|
|||
}
|
||||
}
|
||||
|
||||
if (file->fileNameExt == fileNameToSelect)
|
||||
if (file.fileNameExt == fileNameToSelect)
|
||||
{
|
||||
if (!startMultiSelection) // we are before the last Selected FileName, so we must inverse
|
||||
{
|
||||
|
@ -2145,7 +2092,7 @@ namespace IGFD
|
|||
{
|
||||
prSelectedFileNames.clear();
|
||||
IGFD::Utils::ResetBuffer(puFileNameBuffer);
|
||||
prAddFileNameInSelection(vInfos->fileNameExt, true);
|
||||
prAddFileNameInSelection(vInfos.fileNameExt, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3922,11 +3869,8 @@ namespace IGFD
|
|||
}
|
||||
|
||||
// returns 0 if not break loop, 1 if break loop, 2 if exit dialog
|
||||
int IGFD::FileDialog::prSelectableItem(int vidx, std::shared_ptr<FileInfos> vInfos, bool vSelected, const char* vFmt, ...)
|
||||
int IGFD::FileDialog::prSelectableItem(int vidx, const FileInfos& vInfos, bool vSelected, const char* vFmt, ...)
|
||||
{
|
||||
if (!vInfos.use_count())
|
||||
return 0;
|
||||
|
||||
auto& fdi = prFileDialogInternal.puFileManager;
|
||||
|
||||
static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick |
|
||||
|
@ -3957,7 +3901,7 @@ namespace IGFD
|
|||
#endif // USE_EXPLORATION_BY_KEYS
|
||||
if (res)
|
||||
{
|
||||
if (vInfos->fileType == 'd')
|
||||
if (vInfos.fileType == 'd')
|
||||
{
|
||||
bool isSelectingDir=false;
|
||||
// nav system, selectebale cause open directory or select directory
|
||||
|
@ -4012,27 +3956,27 @@ namespace IGFD
|
|||
return 0;
|
||||
}
|
||||
|
||||
void IGFD::FileDialog::prBeginFileColorIconStyle(std::shared_ptr<FileInfos> vFileInfos, bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont)
|
||||
void IGFD::FileDialog::prBeginFileColorIconStyle(const FileInfos& vFileInfos, bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont)
|
||||
{
|
||||
vOutStr.clear();
|
||||
vOutShowColor = false;
|
||||
|
||||
if (vFileInfos->fileStyle.use_count()) //-V807 //-V522
|
||||
if (vFileInfos.fileStyle.use_count()) //-V807 //-V522
|
||||
{
|
||||
vOutShowColor = true;
|
||||
|
||||
*vOutFont = vFileInfos->fileStyle->font;
|
||||
*vOutFont = vFileInfos.fileStyle->font;
|
||||
}
|
||||
|
||||
if (vOutShowColor && !vFileInfos->fileStyle->icon.empty()) vOutStr = vFileInfos->fileStyle->icon;
|
||||
else if (vFileInfos->fileType == 'd') vOutStr = dirEntryString;
|
||||
else if (vFileInfos->fileType == 'l') vOutStr = linkEntryString;
|
||||
else if (vFileInfos->fileType == 'f') vOutStr = fileEntryString;
|
||||
if (vOutShowColor && !vFileInfos.fileStyle->icon.empty()) vOutStr = vFileInfos.fileStyle->icon;
|
||||
else if (vFileInfos.fileType == 'd') vOutStr = dirEntryString;
|
||||
else if (vFileInfos.fileType == 'l') vOutStr = linkEntryString;
|
||||
else if (vFileInfos.fileType == 'f') vOutStr = fileEntryString;
|
||||
|
||||
vOutStr += " " + vFileInfos->fileNameExt;
|
||||
vOutStr += " " + vFileInfos.fileNameExt;
|
||||
|
||||
if (vOutShowColor)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, vFileInfos->fileStyle->color);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, vFileInfos.fileStyle->color);
|
||||
if (*vOutFont)
|
||||
ImGui::PushFont(*vOutFont);
|
||||
}
|
||||
|
@ -4126,13 +4070,13 @@ namespace IGFD
|
|||
{
|
||||
if (i < 0) continue;
|
||||
|
||||
auto infos = fdi.GetFilteredFileAt((size_t)i);
|
||||
if (!infos.use_count())
|
||||
const FileInfos& infos = fdi.GetFilteredFileAt((size_t)i);
|
||||
if (!infos.isValid)
|
||||
continue;
|
||||
|
||||
prBeginFileColorIconStyle(infos, _showColor, _str, &_font);
|
||||
|
||||
bool selected = fdi.IsFileNameSelected(infos->fileNameExt); // found
|
||||
bool selected = fdi.IsFileNameSelected(infos.fileNameExt); // found
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
|
@ -4147,13 +4091,13 @@ namespace IGFD
|
|||
}
|
||||
if (ImGui::TableNextColumn()) // file type
|
||||
{
|
||||
ImGui::Text("%s", infos->fileExt.c_str());
|
||||
ImGui::Text("%s", infos.fileExt.c_str());
|
||||
}
|
||||
if (ImGui::TableNextColumn()) // file size
|
||||
{
|
||||
if (infos->fileType != 'd')
|
||||
if (infos.fileType != 'd')
|
||||
{
|
||||
ImGui::Text("%s ", infos->formatedFileSize.c_str());
|
||||
ImGui::Text("%s ", infos.formatedFileSize.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4162,7 +4106,7 @@ namespace IGFD
|
|||
}
|
||||
if (ImGui::TableNextColumn()) // file date + time
|
||||
{
|
||||
ImGui::Text("%s", infos->fileModifDate.c_str());
|
||||
ImGui::Text("%s", infos.fileModifDate.c_str());
|
||||
}
|
||||
|
||||
prEndFileColorIconStyle(_showColor, _font);
|
||||
|
|
24
extern/igfd/ImGuiFileDialog.h
vendored
|
@ -766,7 +766,7 @@ namespace IGFD
|
|||
void ParseFilters(const char* vFilters); // Parse filter syntax, detect and parse filter collection
|
||||
void SetSelectedFilterWithExt(const std::string& vFilter); // Select filter
|
||||
|
||||
bool prFillFileStyle(std::shared_ptr<FileInfos> vFileInfos) const; // fill with the good style
|
||||
bool prFillFileStyle(FileInfos& vFileInfos) const; // fill with the good style
|
||||
|
||||
void SetFileStyle(
|
||||
const IGFD_FileStyleFlags& vFlags,
|
||||
|
@ -812,6 +812,7 @@ namespace IGFD
|
|||
#ifdef USE_THUMBNAILS
|
||||
IGFD_Thumbnail_Info thumbnailInfo; // structre for the display for image file tetxure
|
||||
#endif // USE_THUMBNAILS
|
||||
bool isValid = true;
|
||||
|
||||
public:
|
||||
bool IsTagFound(const std::string& vTag) const;
|
||||
|
@ -824,6 +825,7 @@ namespace IGFD
|
|||
class FileManager
|
||||
{
|
||||
public: // types
|
||||
FileInfos invalidFile;
|
||||
enum class SortingFieldEnum // sorting for filetering of the file lsit
|
||||
{
|
||||
FIELD_NONE = 0, // no sorting preference, result indetermined haha..
|
||||
|
@ -839,8 +841,8 @@ namespace IGFD
|
|||
private:
|
||||
std::string prCurrentPath; // current path (to be decomposed in prCurrentPathDecomposition
|
||||
std::vector<std::string> prCurrentPathDecomposition; // part words
|
||||
std::vector<std::shared_ptr<FileInfos>> prFileList; // base container
|
||||
std::vector<std::shared_ptr<FileInfos>> prFilteredFileList; // filtered container (search, sorting, etc..)
|
||||
std::vector<FileInfos> prFileList; // base container
|
||||
std::vector<FileInfos> prFilteredFileList; // filtered container (search, sorting, etc..)
|
||||
std::string prLastSelectedFileName; // for shift multi selection
|
||||
std::set<std::string> prSelectedFileNames; // the user selection of FilePathNames
|
||||
bool prCreateDirectoryMode = false; // for create directory widget
|
||||
|
@ -879,11 +881,11 @@ namespace IGFD
|
|||
static std::string prRoundNumber(double vvalue, int n); // custom rounding number
|
||||
static std::string prFormatFileSize(size_t vByteSize); // format file size field
|
||||
static std::string prOptimizeFilenameForSearchOperations(const std::string& vFileNameExt); // turn all text in lower case for search facilitie
|
||||
static void prCompleteFileInfos(const std::shared_ptr<FileInfos>& FileInfos); // set time and date infos of a file (detail view mode)
|
||||
static void prCompleteFileInfos(FileInfos& FileInfos); // set time and date infos of a file (detail view mode)
|
||||
void prRemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name
|
||||
void prAddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name
|
||||
void AddFile(const FileDialogInternal& vFileDialogInternal,
|
||||
const std::string& vPath, const std::string& vFileName, const char& vFileType, void* ent); // add file called by scandir
|
||||
const std::string& vPath, const std::string& vFileName, char vFileType, void* ent); // add file called by scandir
|
||||
|
||||
public:
|
||||
FileManager();
|
||||
|
@ -892,9 +894,9 @@ namespace IGFD
|
|||
bool IsFileListEmpty();
|
||||
bool IsFilteredListEmpty();
|
||||
size_t GetFullFileListSize();
|
||||
std::shared_ptr<FileInfos> GetFullFileAt(size_t vIdx);
|
||||
const FileInfos& GetFullFileAt(size_t vIdx);
|
||||
size_t GetFilteredListSize();
|
||||
std::shared_ptr<FileInfos> GetFilteredFileAt(size_t vIdx);
|
||||
const FileInfos& GetFilteredFileAt(size_t vIdx);
|
||||
bool IsFileNameSelected(const std::string& vFileName);
|
||||
std::string GetBack();
|
||||
void ClearComposer();
|
||||
|
@ -912,9 +914,9 @@ namespace IGFD
|
|||
void SetCurrentPath(const std::string& vCurrentPath); // set the current path
|
||||
static bool IsFileExist(const std::string& vFile);
|
||||
void SetDefaultFileName(const std::string& vFileName);
|
||||
bool SelectDirectory(const std::shared_ptr<FileInfos>& vInfos); // enter directory
|
||||
bool SelectDirectory(const FileInfos& vInfos); // enter directory
|
||||
void SelectFileName(const FileDialogInternal& vFileDialogInternal,
|
||||
const std::shared_ptr<FileInfos>& vInfos); // select filename
|
||||
const FileInfos& vInfos); // select filename
|
||||
|
||||
//depend of dirent.h
|
||||
void SetCurrentDir(const std::string& vPath); // define current directory for scan
|
||||
|
@ -1311,7 +1313,7 @@ namespace IGFD
|
|||
// widgets components
|
||||
virtual void prDrawSidePane(float vHeight); // draw side pane
|
||||
virtual int prSelectableItem(int vidx,
|
||||
std::shared_ptr<FileInfos> vInfos,
|
||||
const FileInfos& vInfos,
|
||||
bool vSelected, const char* vFmt, ...); // draw a custom selectable behavior item
|
||||
virtual bool prDrawFileListView(ImVec2 vSize); // draw file list view (default mode)
|
||||
|
||||
|
@ -1325,7 +1327,7 @@ namespace IGFD
|
|||
// - prDrawThumbnailsListView
|
||||
// - prDrawThumbnailsGridView
|
||||
void prBeginFileColorIconStyle(
|
||||
std::shared_ptr<FileInfos> vFileInfos,
|
||||
const FileInfos& vFileInfos,
|
||||
bool& vOutShowColor,
|
||||
std::string& vOutStr,
|
||||
ImFont** vOutFont); // begin style apply of filter with color an icon if any
|
||||
|
|
|
@ -226,7 +226,7 @@ void k053260_core::voice_t::write(u8 address, u8 data)
|
|||
m_start = (m_start & ~0x00ff00) | (u32(data) << 8);
|
||||
break;
|
||||
case 6: // start address bit 16-20
|
||||
m_start = (m_start & ~0x1f0000) | (u32(bitfield(data, 16, 5)) << 16);
|
||||
m_start = (m_start & ~0x1f0000) | (u32(bitfield(data, 0, 5)) << 16);
|
||||
break;
|
||||
case 7: // volume
|
||||
m_volume = bitfield(data, 0, 7);
|
||||
|
|
98
papers/clipboard-format.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
# clipboard format
|
||||
|
||||
when copying pattern data from Furnace, it's stored in the clipboard as plain text.
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
```
|
||||
|
||||
this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre7 is `162`.
|
||||
|
||||
the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from.
|
||||
- `0`: note.
|
||||
- `1`: instrument.
|
||||
- `2`: volume.
|
||||
- `3`: effect 1 type.
|
||||
- `4`: effect 1 value. effect type is always included in the clip, even if skipped over.
|
||||
- `5`: effect 2 type.
|
||||
- `6`: effect 2 value. effect type is always included in the clip, even if skipped over.
|
||||
- `7`: effect 3 type...
|
||||
- ...and so on.
|
||||
|
||||
examples of the starting column:
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
0
|
||||
D-6007F08080706|...........|
|
||||
...............|...........|
|
||||
...............|A#500..080F|
|
||||
...............|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
1
|
||||
007F08080706|...........|
|
||||
............|...........|
|
||||
............|A#500..080F|
|
||||
............|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
2
|
||||
7F08080706|...........|
|
||||
..........|...........|
|
||||
..........|A#500..080F|
|
||||
..........|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
3
|
||||
08080706|...........|
|
||||
........|...........|
|
||||
........|A#500..080F|
|
||||
........|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
4
|
||||
08080706|...........|
|
||||
........|...........|
|
||||
........|A#500..080F|
|
||||
........|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
5
|
||||
0706|...........|
|
||||
....|...........|
|
||||
....|A#500..080F|
|
||||
....|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
6
|
||||
0706|...........|
|
||||
....|...........|
|
||||
....|A#500..080F|
|
||||
....|...........|
|
||||
```
|
||||
|
||||
```
|
||||
org.tildearrow.furnace - Pattern Data (144)
|
||||
0
|
||||
...........|
|
||||
...........|
|
||||
A#500..080F|
|
||||
...........|
|
||||
```
|
||||
|
||||
each line following the column number is verbatim from the pattern view with channels separated by `|`. each line also ends in `|`.
|
||||
|
||||
notes use the default settings for note display (no German notation), including note off `OFF`, note release `===`, and macro release `REL`.
|
|
@ -927,12 +927,13 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
}
|
||||
|
||||
float* outBuf[2];
|
||||
float* outBuf[DIV_MAX_OUTPUTS];
|
||||
memset(outBuf,0,sizeof(void*)*DIV_MAX_OUTPUTS);
|
||||
outBuf[0]=new float[EXPORT_BUFSIZE];
|
||||
outBuf[1]=new float[EXPORT_BUFSIZE];
|
||||
short* sysBuf[DIV_MAX_CHIPS];
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
sysBuf[i]=new short[EXPORT_BUFSIZE*2];
|
||||
sysBuf[i]=new short[EXPORT_BUFSIZE*disCont[i].dispatch->getOutputCount()];
|
||||
}
|
||||
|
||||
// take control of audio output
|
||||
|
@ -3850,6 +3851,23 @@ void DivEngine::delSample(int index) {
|
|||
song.sampleLen=song.sample.size();
|
||||
removeAsset(song.sampleDir,index);
|
||||
checkAssetDir(song.sampleDir,song.sample.size());
|
||||
|
||||
// compensate
|
||||
for (DivInstrument* i: song.ins) {
|
||||
if (i->amiga.initSample==index) {
|
||||
i->amiga.initSample=-1;
|
||||
} else if (i->amiga.initSample>index) {
|
||||
i->amiga.initSample--;
|
||||
}
|
||||
for (int j=0; j<120; j++) {
|
||||
if (i->amiga.noteMap[j].map==index) {
|
||||
i->amiga.noteMap[j].map=-1;
|
||||
} else if (i->amiga.noteMap[j].map>index) {
|
||||
i->amiga.noteMap[j].map--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderSamples();
|
||||
}
|
||||
saveLock.unlock();
|
||||
|
@ -4041,6 +4059,27 @@ void DivEngine::exchangeIns(int one, int two) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivEngine::exchangeWave(int one, int two) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
void DivEngine::exchangeSample(int one, int two) {
|
||||
for (DivInstrument* i: song.ins) {
|
||||
if (i->amiga.initSample==one) {
|
||||
i->amiga.initSample=two;
|
||||
} else if (i->amiga.initSample==two) {
|
||||
i->amiga.initSample=one;
|
||||
}
|
||||
for (int j=0; j<120; j++) {
|
||||
if (i->amiga.noteMap[j].map==one) {
|
||||
i->amiga.noteMap[j].map=two;
|
||||
} else if (i->amiga.noteMap[j].map==two) {
|
||||
i->amiga.noteMap[j].map=one;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DivEngine::moveInsUp(int which) {
|
||||
if (which<1 || which>=(int)song.ins.size()) return false;
|
||||
BUSY_BEGIN;
|
||||
|
@ -4063,6 +4102,7 @@ bool DivEngine::moveWaveUp(int which) {
|
|||
song.wave[which]=song.wave[which-1];
|
||||
song.wave[which-1]=prev;
|
||||
moveAsset(song.waveDir,which,which-1);
|
||||
exchangeWave(which,which-1);
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
return true;
|
||||
|
@ -4079,6 +4119,7 @@ bool DivEngine::moveSampleUp(int which) {
|
|||
song.sample[which]=song.sample[which-1];
|
||||
song.sample[which-1]=prev;
|
||||
moveAsset(song.sampleDir,which,which-1);
|
||||
exchangeSample(which,which-1);
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
BUSY_END;
|
||||
|
@ -4106,6 +4147,7 @@ bool DivEngine::moveWaveDown(int which) {
|
|||
saveLock.lock();
|
||||
song.wave[which]=song.wave[which+1];
|
||||
song.wave[which+1]=prev;
|
||||
exchangeWave(which,which+1);
|
||||
moveAsset(song.waveDir,which,which+1);
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
|
@ -4122,6 +4164,7 @@ bool DivEngine::moveSampleDown(int which) {
|
|||
saveLock.lock();
|
||||
song.sample[which]=song.sample[which+1];
|
||||
song.sample[which+1]=prev;
|
||||
exchangeSample(which,which+1);
|
||||
moveAsset(song.sampleDir,which,which+1);
|
||||
saveLock.unlock();
|
||||
renderSamples();
|
||||
|
|
|
@ -531,6 +531,9 @@ class DivEngine {
|
|||
void initSongWithDesc(const char* description, bool inBase64=true, bool oldVol=false);
|
||||
|
||||
void exchangeIns(int one, int two);
|
||||
void exchangeWave(int one, int two);
|
||||
void exchangeSample(int one, int two);
|
||||
|
||||
void swapChannels(int src, int dest);
|
||||
void stompChannel(int ch);
|
||||
|
||||
|
|
|
@ -142,76 +142,78 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
}
|
||||
|
||||
// compatibility flags
|
||||
ds.limitSlides=true;
|
||||
ds.linearPitch=1;
|
||||
ds.loopModality=0;
|
||||
ds.properNoiseLayout=false;
|
||||
ds.waveDutyIsVol=false;
|
||||
// TODO: WHAT?! geodude.dmf fails when this is true
|
||||
// but isn't that how Defle behaves???
|
||||
ds.resetMacroOnPorta=false;
|
||||
ds.legacyVolumeSlides=true;
|
||||
ds.compatibleArpeggio=true;
|
||||
ds.noteOffResetsSlides=true;
|
||||
ds.targetResetsSlides=true;
|
||||
ds.arpNonPorta=false;
|
||||
ds.algMacroBehavior=false;
|
||||
ds.brokenShortcutSlides=false;
|
||||
ds.ignoreDuplicateSlides=true;
|
||||
ds.brokenDACMode=true;
|
||||
ds.oneTickCut=false;
|
||||
ds.newInsTriggersInPorta=true;
|
||||
ds.arp0Reset=true;
|
||||
ds.brokenSpeedSel=true;
|
||||
ds.noSlidesOnFirstTick=false;
|
||||
ds.rowResetsArpPos=false;
|
||||
ds.ignoreJumpAtEnd=true;
|
||||
ds.buggyPortaAfterSlide=true;
|
||||
ds.gbInsAffectsEnvelope=true;
|
||||
ds.ignoreDACModeOutsideIntendedChannel=false;
|
||||
ds.e1e2AlsoTakePriority=true;
|
||||
ds.fbPortaPause=true;
|
||||
ds.snDutyReset=true;
|
||||
ds.oldOctaveBoundary=false;
|
||||
ds.noOPN2Vol=true;
|
||||
ds.newVolumeScaling=false;
|
||||
ds.volMacroLinger=false;
|
||||
ds.brokenOutVol=true;
|
||||
ds.brokenOutVol2=true;
|
||||
ds.e1e2StopOnSameNote=true;
|
||||
ds.brokenPortaArp=false;
|
||||
ds.snNoLowPeriods=true;
|
||||
ds.disableSampleMacro=true;
|
||||
ds.delayBehavior=0;
|
||||
ds.jumpTreatment=2;
|
||||
if (!getConfInt("noDMFCompat",0)) {
|
||||
ds.limitSlides=true;
|
||||
ds.linearPitch=1;
|
||||
ds.loopModality=0;
|
||||
ds.properNoiseLayout=false;
|
||||
ds.waveDutyIsVol=false;
|
||||
// TODO: WHAT?! geodude.dmf fails when this is true
|
||||
// but isn't that how Defle behaves???
|
||||
ds.resetMacroOnPorta=false;
|
||||
ds.legacyVolumeSlides=true;
|
||||
ds.compatibleArpeggio=true;
|
||||
ds.noteOffResetsSlides=true;
|
||||
ds.targetResetsSlides=true;
|
||||
ds.arpNonPorta=false;
|
||||
ds.algMacroBehavior=false;
|
||||
ds.brokenShortcutSlides=false;
|
||||
ds.ignoreDuplicateSlides=true;
|
||||
ds.brokenDACMode=true;
|
||||
ds.oneTickCut=false;
|
||||
ds.newInsTriggersInPorta=true;
|
||||
ds.arp0Reset=true;
|
||||
ds.brokenSpeedSel=true;
|
||||
ds.noSlidesOnFirstTick=false;
|
||||
ds.rowResetsArpPos=false;
|
||||
ds.ignoreJumpAtEnd=true;
|
||||
ds.buggyPortaAfterSlide=true;
|
||||
ds.gbInsAffectsEnvelope=true;
|
||||
ds.ignoreDACModeOutsideIntendedChannel=false;
|
||||
ds.e1e2AlsoTakePriority=true;
|
||||
ds.fbPortaPause=true;
|
||||
ds.snDutyReset=true;
|
||||
ds.oldOctaveBoundary=false;
|
||||
ds.noOPN2Vol=true;
|
||||
ds.newVolumeScaling=false;
|
||||
ds.volMacroLinger=false;
|
||||
ds.brokenOutVol=true;
|
||||
ds.brokenOutVol2=true;
|
||||
ds.e1e2StopOnSameNote=true;
|
||||
ds.brokenPortaArp=false;
|
||||
ds.snNoLowPeriods=true;
|
||||
ds.disableSampleMacro=true;
|
||||
ds.delayBehavior=0;
|
||||
ds.jumpTreatment=2;
|
||||
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
ds.waveDutyIsVol=true;
|
||||
ds.legacyVolumeSlides=false;
|
||||
}
|
||||
// 1.1 compat flags
|
||||
if (ds.version>24) {
|
||||
ds.waveDutyIsVol=true;
|
||||
ds.legacyVolumeSlides=false;
|
||||
}
|
||||
|
||||
// Neo Geo detune is caused by Defle running Neo Geo at the wrong clock.
|
||||
/*
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610_FULL || ds.system[0]==DIV_SYSTEM_YM2610_FULL_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610B || ds.system[0]==DIV_SYSTEM_YM2610B_EXT) {
|
||||
ds.tuning=443.23;
|
||||
}
|
||||
*/
|
||||
// Neo Geo detune is caused by Defle running Neo Geo at the wrong clock.
|
||||
/*
|
||||
if (ds.system[0]==DIV_SYSTEM_YM2610 || ds.system[0]==DIV_SYSTEM_YM2610_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610_FULL || ds.system[0]==DIV_SYSTEM_YM2610_FULL_EXT
|
||||
|| ds.system[0]==DIV_SYSTEM_YM2610B || ds.system[0]==DIV_SYSTEM_YM2610B_EXT) {
|
||||
ds.tuning=443.23;
|
||||
}
|
||||
*/
|
||||
|
||||
// Genesis detuned on Defle v10 and earlier
|
||||
/*if (ds.version<19 && ds.system[0]==DIV_SYSTEM_GENESIS) {
|
||||
ds.tuning=443.23;
|
||||
}*/
|
||||
// C64 detuned on Defle v11 and earlier
|
||||
/*if (ds.version<21 && (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580)) {
|
||||
ds.tuning=433.2;
|
||||
}*/
|
||||
// Genesis detuned on Defle v10 and earlier
|
||||
/*if (ds.version<19 && ds.system[0]==DIV_SYSTEM_GENESIS) {
|
||||
ds.tuning=443.23;
|
||||
}*/
|
||||
// C64 detuned on Defle v11 and earlier
|
||||
/*if (ds.version<21 && (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580)) {
|
||||
ds.tuning=433.2;
|
||||
}*/
|
||||
|
||||
// Game Boy arp+soundLen screwery
|
||||
if (ds.system[0]==DIV_SYSTEM_GB) {
|
||||
ds.systemFlags[0].set("enoughAlready",true);
|
||||
// Game Boy arp+soundLen screwery
|
||||
if (ds.system[0]==DIV_SYSTEM_GB) {
|
||||
ds.systemFlags[0].set("enoughAlready",true);
|
||||
}
|
||||
}
|
||||
|
||||
logI("reading module data...");
|
||||
|
@ -869,7 +871,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
|
|||
if (ds.version>0x15) {
|
||||
sample->depth=(DivSampleDepth)reader.readC();
|
||||
if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
logW("%d: sample depth is wrong! (%d)",i,sample->depth);
|
||||
logW("%d: sample depth is wrong! (%d)",i,(int)sample->depth);
|
||||
sample->depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
} else {
|
||||
|
@ -1937,8 +1939,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.system[i]=systemFromFileFur(sysID);
|
||||
logD("- %d: %.2x (%s)",i,sysID,getSystemName(ds.system[i]));
|
||||
if (sysID!=0 && systemToFileFur(ds.system[i])==0) {
|
||||
logE("unrecognized system ID %.2x",ds.system[i]);
|
||||
lastError=fmt::sprintf("unrecognized system ID %.2x!",ds.system[i]);
|
||||
logE("unrecognized system ID %.2x",sysID);
|
||||
lastError=fmt::sprintf("unrecognized system ID %.2x!",sysID);
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -360,26 +360,6 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].pcm.isNoteMap) {
|
||||
// note map macros
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].std.wave.val>=0 && chan[i].std.wave.val<120) {
|
||||
if (chan[i].pcm.next!=chan[i].std.wave.val) {
|
||||
chan[i].pcm.next=chan[i].std.wave.val;
|
||||
chan[i].pcmChanged.index=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!chan[i].pcm.isNoteMap) {
|
||||
if (chan[i].std.wave.had) {
|
||||
if (chan[i].std.wave.val>=0 && chan[i].std.wave.val<parent->song.sampleLen) {
|
||||
if (chan[i].pcm.next!=chan[i].std.wave.val) {
|
||||
chan[i].pcm.next=chan[i].std.wave.val;
|
||||
chan[i].pcmChanged.index=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// update registers
|
||||
if (chan[i].volChanged.changed) {
|
||||
// calculate volume (16 bit)
|
||||
|
@ -432,7 +412,7 @@ void DivPlatformES5506::tick(bool sysTick) {
|
|||
off=(double)center/8363.0;
|
||||
}
|
||||
if (ins->amiga.useNoteMap) {
|
||||
chan[i].pcm.note=next;
|
||||
//chan[i].pcm.note=next;
|
||||
}
|
||||
// get loop mode
|
||||
DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX;
|
||||
|
@ -748,13 +728,13 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
if (((ins->amiga.useNoteMap) && (c.value>=0 && c.value<120)) ||
|
||||
((!ins->amiga.useNoteMap) && (ins->amiga.initSample>=0 && ins->amiga.initSample<parent->song.sampleLen))) {
|
||||
int sample=ins->amiga.getSample(c.value);
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
sampleValid=true;
|
||||
chan[c.chan].volMacroMax=ins->type==DIV_INS_AMIGA?64:0xfff;
|
||||
chan[c.chan].panMacroMax=ins->type==DIV_INS_AMIGA?127:0xfff;
|
||||
chan[c.chan].pcm.note=c.value;
|
||||
chan[c.chan].pcm.next=ins->amiga.useNoteMap?c.value:sample;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].pcm.note=c.value;
|
||||
chan[c.chan].filter=ins->es5506.filter;
|
||||
chan[c.chan].envelope=ins->es5506.envelope;
|
||||
}
|
||||
|
@ -870,20 +850,6 @@ int DivPlatformES5506::dispatch(DivCommand c) {
|
|||
chan[c.chan].pitch=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
// sample commands
|
||||
case DIV_CMD_WAVE:
|
||||
if (!chan[c.chan].useWave) {
|
||||
if (chan[c.chan].active) {
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_ES5506);
|
||||
if (((ins->amiga.useNoteMap) && (c.value>=0 && c.value<120)) ||
|
||||
((!ins->amiga.useNoteMap) && (c.value>=0 && c.value<parent->song.sampleLen))) {
|
||||
chan[c.chan].pcm.next=c.value;
|
||||
chan[c.chan].pcmChanged.index=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reserved for useWave
|
||||
break;
|
||||
// Filter commands
|
||||
case DIV_CMD_ES5506_FILTER_MODE:
|
||||
if (!chan[c.chan].active) {
|
||||
|
@ -1253,6 +1219,7 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, const DivCo
|
|||
dumpWrites=false;
|
||||
skipRegisterWrites=false;
|
||||
volScale=0;
|
||||
curPage=0;
|
||||
|
||||
for (int i=0; i<32; i++) {
|
||||
isMuted[i]=false;
|
||||
|
|
|
@ -109,7 +109,8 @@ class DivPlatformFMBase: public DivDispatch {
|
|||
if (!skipRegisterWrites && !flushFirst) {
|
||||
if (writes.empty()) {
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
} else if (writes.size()>16 || writes.front().addrOrVal) {
|
||||
} else if ((writes.size()>16 && writes.front().addr!=0xf0) || writes.front().addrOrVal) {
|
||||
// $f0 is used by OPN hard reset
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
} else {
|
||||
writes.push_front(QueuedWrite(a,v));
|
||||
|
|
|
@ -255,7 +255,7 @@ void DivPlatformGB::tick(bool sysTick) {
|
|||
chan[i].sweepChanged=true;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_WAIT:
|
||||
chan[i].hwSeqDelay=data+1;
|
||||
chan[i].hwSeqDelay=(data+1)*parent->tickMult;
|
||||
leave=true;
|
||||
break;
|
||||
case DivInstrumentGB::DIV_GB_HWCMD_WAIT_REL:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "genesisext.h"
|
||||
#include "../engine.h"
|
||||
#include "../../ta-log.h"
|
||||
#include <math.h>
|
||||
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
|
@ -476,13 +477,6 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
if (chan[csmChan].active) { // CSM
|
||||
writeMask^=0xf0;
|
||||
}
|
||||
/*printf(
|
||||
"Mask: %c %c %c %c\n",
|
||||
(writeMask&0x10)?'1':'-',
|
||||
(writeMask&0x20)?'2':'-',
|
||||
(writeMask&0x40)?'3':'-',
|
||||
(writeMask&0x80)?'4':'-'
|
||||
);*/
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
|
@ -576,6 +570,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
unsigned char hardResetMask=0;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -603,8 +598,13 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
writeNoteOn=true;
|
||||
if (opChan[i].mask) {
|
||||
writeMask|=1<<(4+i);
|
||||
if (opChan[i].hardReset) {
|
||||
hardResetMask|=1<<(4+i);
|
||||
}
|
||||
}
|
||||
if (!opChan[i].hardReset) {
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,14 +631,9 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
if (chan[csmChan].active) { // CSM
|
||||
writeMask^=0xf0;
|
||||
}
|
||||
/*printf(
|
||||
"Mask: %c %c %c %c\n",
|
||||
(writeMask&0x10)?'1':'-',
|
||||
(writeMask&0x20)?'2':'-',
|
||||
(writeMask&0x40)?'3':'-',
|
||||
(writeMask&0x80)?'4':'-'
|
||||
);*/
|
||||
writeMask^=hardResetMask;
|
||||
immWrite(0x28,writeMask);
|
||||
writeMask^=hardResetMask;
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
|
@ -651,6 +646,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
|
|||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
|
|
|
@ -145,15 +145,15 @@ void DivPlatformK053260::tick(bool sysTick) {
|
|||
off=8363.0/s->centerRate;
|
||||
}
|
||||
}
|
||||
DivSample* s=parent->getSample(chan[i].sample);
|
||||
DivSample* s=parent->getSample(sample);
|
||||
chan[i].freq=0x1000-(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER));
|
||||
if (chan[i].freq>4095) chan[i].freq=4095;
|
||||
if (chan[i].freq<0) chan[i].freq=0;
|
||||
if (chan[i].keyOn) {
|
||||
unsigned int start=0;
|
||||
unsigned int length=0;
|
||||
if (chan[i].sample>=0 && chan[i].sample<parent->song.sampleLen) {
|
||||
start=sampleOffK053260[chan[i].sample];
|
||||
if (sample>=0 && sample<parent->song.sampleLen) {
|
||||
start=sampleOffK053260[sample];
|
||||
length=s->length8;
|
||||
if (chan[i].reverse) {
|
||||
start+=length;
|
||||
|
@ -163,8 +163,7 @@ void DivPlatformK053260::tick(bool sysTick) {
|
|||
if (chan[i].audPos>0) {
|
||||
if (chan[i].reverse) {
|
||||
start=start-MIN(chan[i].audPos,s->length8);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
start=start+MIN(chan[i].audPos,s->length8);
|
||||
}
|
||||
length=MAX(1,length-chan[i].audPos);
|
||||
|
|
|
@ -386,6 +386,9 @@ int DivPlatformMSM6258::init(DivEngine* p, int channels, int sugRate, const DivC
|
|||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
msm=new okim6258_device(4000000);
|
||||
msm->set_start_div(okim6258_device::FOSC_DIV_BY_1024);
|
||||
msm->set_type(okim6258_device::TYPE_4BITS);
|
||||
msm->set_outbits(okim6258_device::OUTPUT_12BITS);
|
||||
msm->device_start();
|
||||
setFlags(flags);
|
||||
reset();
|
||||
|
|
|
@ -47,7 +47,6 @@ class DivPlatformMSM6258: public DivDispatch {
|
|||
};
|
||||
FixedQueue<QueuedWrite,256> writes;
|
||||
okim6258_device* msm;
|
||||
unsigned char lastBusy;
|
||||
|
||||
unsigned char sampleBank, msmPan, msmDivider, rateSel, msmClock, clockSel;
|
||||
signed char msmDividerCount, msmClockCount;
|
||||
|
|
|
@ -571,7 +571,7 @@ void DivPlatformNamcoWSG::setFlags(const DivConfig& flags) {
|
|||
chipClock=3072000;
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock/32;
|
||||
namco->device_clock_changed(rate);
|
||||
namco->device_clock_changed(96000);
|
||||
for (int i=0; i<chans; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
|
|
|
@ -130,9 +130,9 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) {
|
|||
for (size_t i=0; i<len; i++) {
|
||||
doPCM;
|
||||
|
||||
nes1_NP->Tick(1);
|
||||
nes2_NP->TickFrameSequence(1);
|
||||
nes2_NP->Tick(1);
|
||||
nes1_NP->Tick(8);
|
||||
nes2_NP->TickFrameSequence(8);
|
||||
nes2_NP->Tick(8);
|
||||
nes1_NP->Render(out1);
|
||||
nes2_NP->Render(out2);
|
||||
|
||||
|
@ -140,7 +140,7 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) {
|
|||
if (sample>32767) sample=32767;
|
||||
if (sample<-32768) sample=-32768;
|
||||
buf[0][i]=sample;
|
||||
if (++writeOscBuf>=32) {
|
||||
if (++writeOscBuf>=4) {
|
||||
writeOscBuf=0;
|
||||
oscBuf[0]->data[oscBuf[0]->needle++]=nes1_NP->out[0]<<11;
|
||||
oscBuf[1]->data[oscBuf[1]->needle++]=nes1_NP->out[1]<<11;
|
||||
|
@ -749,8 +749,11 @@ void DivPlatformNES::setFlags(const DivConfig& flags) {
|
|||
}
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
rate=chipClock;
|
||||
if (useNP) {
|
||||
rate/=8;
|
||||
}
|
||||
for (int i=0; i<5; i++) {
|
||||
oscBuf[i]->rate=rate/32;
|
||||
oscBuf[i]->rate=rate/(useNP?4:32);
|
||||
}
|
||||
|
||||
dpcmModeDefault=flags.getBool("dpcmMode",true);
|
||||
|
|
|
@ -392,6 +392,15 @@ void DivPlatformOPLL::commitState(int ch, DivInstrument* ins) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformOPLL::switchMode(bool mode) {
|
||||
if (mode==properDrums) return;
|
||||
if (mode) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformOPLL::dispatch(DivCommand c) {
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
|
@ -773,18 +782,10 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
if ((int)properDrums==c.value) break;
|
||||
if (c.value) {
|
||||
properDrums=true;
|
||||
immWrite(0x0e,0x20);
|
||||
drumState=0;
|
||||
} else {
|
||||
properDrums=false;
|
||||
immWrite(0x0e,0x00);
|
||||
drumState=0;
|
||||
}
|
||||
chan[6].freqChanged=true;
|
||||
chan[7].freqChanged=true;
|
||||
chan[8].freqChanged=true;
|
||||
chan[9].freqChanged=true;
|
||||
chan[10].freqChanged=true;
|
||||
switchMode(properDrums);
|
||||
break;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
|
|
|
@ -75,6 +75,7 @@ class DivPlatformOPLL: public DivDispatch {
|
|||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
void commitState(int ch, DivInstrument* ins);
|
||||
void switchMode(bool mode);
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
|
|
@ -283,6 +283,7 @@ void DivPlatformPET::reset() {
|
|||
memset(regPool,0,16);
|
||||
chan[0]=Channel();
|
||||
chan[0].std.setEngine(parent);
|
||||
rWrite(10,chan[0].wave);
|
||||
}
|
||||
|
||||
int DivPlatformPET::getOutputCount() {
|
||||
|
|
|
@ -733,6 +733,7 @@ int DivPlatformSNES::getRegisterPoolSize() {
|
|||
|
||||
void DivPlatformSNES::initEcho() {
|
||||
unsigned char esa=0xf8-(echoDelay<<3);
|
||||
unsigned char control=(noiseFreq&0x1f)|(echoOn?0:0x20);
|
||||
if (echoOn) {
|
||||
rWrite(0x6d,esa);
|
||||
rWrite(0x7d,echoDelay);
|
||||
|
@ -742,13 +743,14 @@ void DivPlatformSNES::initEcho() {
|
|||
for (int i=0; i<8; i++) {
|
||||
rWrite(0x0f+(i<<4),echoFIR[i]);
|
||||
}
|
||||
rWrite(0x6c,control);
|
||||
} else {
|
||||
rWrite(0x6d,0);
|
||||
rWrite(0x7d,0);
|
||||
rWrite(0x2c,0);
|
||||
rWrite(0x3c,0);
|
||||
rWrite(0x6c,control);
|
||||
rWrite(0x7d,0);
|
||||
rWrite(0x6d,0xff);
|
||||
}
|
||||
writeControl=true;
|
||||
}
|
||||
|
||||
void DivPlatformSNES::reset() {
|
||||
|
|
|
@ -626,7 +626,7 @@ void DivPlatformSoundUnit::quit() {
|
|||
delete oscBuf[i];
|
||||
}
|
||||
delete su;
|
||||
delete sampleMem;
|
||||
delete[] sampleMem;
|
||||
}
|
||||
|
||||
DivPlatformSoundUnit::~DivPlatformSoundUnit() {
|
||||
|
|
|
@ -356,12 +356,12 @@ void DivPlatformTIA::poke(std::vector<DivRegWrite>& wlist) {
|
|||
|
||||
void DivPlatformTIA::setFlags(const DivConfig& flags) {
|
||||
if (flags.getInt("clockSel",0)) {
|
||||
rate=COLOR_PAL*4.0/5.0;
|
||||
chipClock=COLOR_PAL*4.0/5.0;
|
||||
} else {
|
||||
rate=COLOR_NTSC;
|
||||
chipClock=COLOR_NTSC;
|
||||
}
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
chipClock=rate;
|
||||
rate=chipClock;
|
||||
mixingType=flags.getInt("mixingType",0)&3;
|
||||
for (int i=0; i<2; i++) {
|
||||
oscBuf[i]->rate=rate/114;
|
||||
|
|
|
@ -355,6 +355,9 @@ int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
opChan[ch].hardReset=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
@ -385,6 +388,9 @@ static int opChanOffsH[4]={
|
|||
};
|
||||
|
||||
void DivPlatformYM2203Ext::tick(bool sysTick) {
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -395,6 +401,12 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
|
|||
writeMask&=~(1<<(4+i));
|
||||
opChan[i].keyOff=false;
|
||||
}
|
||||
if (opChan[i].hardReset && opChan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
if (writeSomething) {
|
||||
immWrite(0x28,writeMask);
|
||||
|
@ -491,6 +503,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
|
|||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
unsigned char hardResetMask=0;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -517,12 +530,36 @@ void DivPlatformYM2203Ext::tick(bool sysTick) {
|
|||
writeNoteOn=true;
|
||||
if (opChan[i].mask) {
|
||||
writeMask|=1<<(4+i);
|
||||
if (opChan[i].hardReset) {
|
||||
hardResetMask|=1<<(4+i);
|
||||
}
|
||||
}
|
||||
if (!opChan[i].hardReset) {
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
if (writeNoteOn) {
|
||||
writeMask^=hardResetMask;
|
||||
immWrite(0x28,writeMask);
|
||||
writeMask^=hardResetMask;
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0xf0,i&0xff);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (opChan[i].keyOn && opChan[i].hardReset) {
|
||||
// restore SL/RR
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -378,6 +378,9 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
opChan[ch].hardReset=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
@ -408,6 +411,9 @@ static int opChanOffsH[4]={
|
|||
};
|
||||
|
||||
void DivPlatformYM2608Ext::tick(bool sysTick) {
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -418,6 +424,12 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
|
|||
writeMask&=~(1<<(4+i));
|
||||
opChan[i].keyOff=false;
|
||||
}
|
||||
if (opChan[i].hardReset && opChan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
if (writeSomething) {
|
||||
immWrite(0x28,writeMask);
|
||||
|
@ -513,6 +525,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
|
|||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
unsigned char hardResetMask=0;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -539,12 +552,36 @@ void DivPlatformYM2608Ext::tick(bool sysTick) {
|
|||
writeNoteOn=true;
|
||||
if (opChan[i].mask) {
|
||||
writeMask|=1<<(4+i);
|
||||
if (opChan[i].hardReset) {
|
||||
hardResetMask|=1<<(4+i);
|
||||
}
|
||||
}
|
||||
if (!opChan[i].hardReset) {
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
if (writeNoteOn) {
|
||||
writeMask^=hardResetMask;
|
||||
immWrite(0x28,writeMask);
|
||||
writeMask^=hardResetMask;
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0xf0,i&0xff);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (opChan[i].keyOn && opChan[i].hardReset) {
|
||||
// restore SL/RR
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -374,6 +374,9 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
opChan[ch].hardReset=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
@ -404,6 +407,9 @@ static int opChanOffsH[4]={
|
|||
};
|
||||
|
||||
void DivPlatformYM2610BExt::tick(bool sysTick) {
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -414,6 +420,12 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
|||
writeMask&=~(1<<(4+i));
|
||||
opChan[i].keyOff=false;
|
||||
}
|
||||
if (opChan[i].hardReset && opChan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
if (writeSomething) {
|
||||
immWrite(0x28,writeMask);
|
||||
|
@ -509,6 +521,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
|||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
unsigned char hardResetMask=0;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -535,12 +548,36 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
|
|||
writeNoteOn=true;
|
||||
if (opChan[i].mask) {
|
||||
writeMask|=1<<(4+i);
|
||||
if (opChan[i].hardReset) {
|
||||
hardResetMask|=1<<(4+i);
|
||||
}
|
||||
}
|
||||
if (!opChan[i].hardReset) {
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
if (writeNoteOn) {
|
||||
writeMask^=hardResetMask;
|
||||
immWrite(0x28,writeMask);
|
||||
writeMask^=hardResetMask;
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0xf0,i&0xff);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (opChan[i].keyOn && opChan[i].hardReset) {
|
||||
// restore SL/RR
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -374,6 +374,9 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
opChan[ch].hardReset=c.value;
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
@ -404,6 +407,9 @@ static int opChanOffsH[4]={
|
|||
};
|
||||
|
||||
void DivPlatformYM2610Ext::tick(bool sysTick) {
|
||||
int hardResetElapsed=0;
|
||||
bool mustHardReset=false;
|
||||
|
||||
if (extMode) {
|
||||
bool writeSomething=false;
|
||||
unsigned char writeMask=2;
|
||||
|
@ -414,6 +420,12 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
|||
writeMask&=~(1<<(4+i));
|
||||
opChan[i].keyOff=false;
|
||||
}
|
||||
if (opChan[i].hardReset && opChan[i].keyOn) {
|
||||
mustHardReset=true;
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,0x0f);
|
||||
hardResetElapsed++;
|
||||
}
|
||||
}
|
||||
if (writeSomething) {
|
||||
immWrite(0x28,writeMask);
|
||||
|
@ -509,6 +521,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
|||
|
||||
bool writeNoteOn=false;
|
||||
unsigned char writeMask=2;
|
||||
unsigned char hardResetMask=0;
|
||||
if (extMode) for (int i=0; i<4; i++) {
|
||||
if (opChan[i].freqChanged) {
|
||||
if (parent->song.linearPitch==2) {
|
||||
|
@ -535,12 +548,36 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
|
|||
writeNoteOn=true;
|
||||
if (opChan[i].mask) {
|
||||
writeMask|=1<<(4+i);
|
||||
if (opChan[i].hardReset) {
|
||||
hardResetMask|=1<<(4+i);
|
||||
}
|
||||
}
|
||||
if (!opChan[i].hardReset) {
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
if (writeNoteOn) {
|
||||
writeMask^=hardResetMask;
|
||||
immWrite(0x28,writeMask);
|
||||
writeMask^=hardResetMask;
|
||||
|
||||
// hard reset handling
|
||||
if (mustHardReset) {
|
||||
for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) {
|
||||
immWrite(0xf0,i&0xff);
|
||||
}
|
||||
for (int i=0; i<4; i++) {
|
||||
if (opChan[i].keyOn && opChan[i].hardReset) {
|
||||
// restore SL/RR
|
||||
unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i];
|
||||
DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i];
|
||||
immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
opChan[i].keyOn=false;
|
||||
}
|
||||
}
|
||||
immWrite(0x28,writeMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) {
|
|||
|
||||
// render data
|
||||
if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
logW("sample depth is wrong! (%d)",depth);
|
||||
logW("sample depth is wrong! (%d)",(int)depth);
|
||||
depth=DIV_SAMPLE_DEPTH_16BIT;
|
||||
}
|
||||
samples=(double)samples/samplePitchesSD[pitch];
|
||||
|
|
|
@ -1542,7 +1542,6 @@ void DivEngine::registerSystems() {
|
|||
);
|
||||
|
||||
EffectHandlerMap es5506PreEffectHandlerMap={
|
||||
{0x10, {DIV_CMD_WAVE, "10xx: Change waveform (00 to FF)",effectVal}},
|
||||
{0x11, {DIV_CMD_ES5506_FILTER_MODE, "11xx: Set filter mode (00 to 03)",effectValAnd<3>}},
|
||||
{0x14, {DIV_CMD_ES5506_FILTER_K1, "14xx: Set filter coefficient K1 low byte (00 to FF)",effectValShift<0>,constVal<0x00ff>}},
|
||||
{0x15, {DIV_CMD_ES5506_FILTER_K1, "15xx: Set filter coefficient K1 high byte (00 to FF)",effectValShift<8>,constVal<0xff00>}},
|
||||
|
|
|
@ -52,7 +52,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
|||
break;
|
||||
default:
|
||||
IGNORED++;
|
||||
logD("Ignoring chip %d systemID %d",i,song.system[i]);
|
||||
logD("Ignoring chip %d systemID %d",i,(int)song.system[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
|||
playSub(false);
|
||||
//size_t tickCount=0;
|
||||
bool done=false;
|
||||
bool loopNow=false;
|
||||
int loopPos=-1;
|
||||
int fracWait=0; // accumulates fractional ticks
|
||||
if (VERA>=0) disCont[VERA].dispatch->toggleRegisterDump(true);
|
||||
|
@ -109,9 +110,17 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) {
|
|||
|
||||
while (!done) {
|
||||
if (loopPos==-1) {
|
||||
if (loopOrder==curOrder && loopRow==curRow && ticks==1 && loop) {
|
||||
loopPos=zsm.getoffset();
|
||||
zsm.setLoopPoint();
|
||||
if (loopOrder==curOrder && loopRow==curRow && loop)
|
||||
loopNow=true;
|
||||
if (loopNow) {
|
||||
// If Virtual Tempo is in use, our exact loop point
|
||||
// might be skipped due to quantization error.
|
||||
// If this happens, the tick immediately following is our loop point.
|
||||
if (ticks==1 || !(loopOrder==curOrder && loopRow==curRow)) {
|
||||
loopPos=zsm.getoffset();
|
||||
zsm.setLoopPoint();
|
||||
loopNow=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextTick() || !playing) {
|
||||
|
|
|
@ -84,7 +84,7 @@ const char* aboutLine[]={
|
|||
"djtuBIG-MaliceX",
|
||||
"dumbut",
|
||||
"Eknous-P",
|
||||
"ElectricKeet",
|
||||
"Electric Keet",
|
||||
"EpicTyphlosion",
|
||||
"FΛDE",
|
||||
"Forte",
|
||||
|
@ -121,6 +121,7 @@ const char* aboutLine[]={
|
|||
"SwapXFO",
|
||||
"TakuikaNinja",
|
||||
"TCORPStudios",
|
||||
"Teuthida",
|
||||
"The Blender Fiddler",
|
||||
"TheDuccinator",
|
||||
"theloredev",
|
||||
|
@ -137,6 +138,7 @@ const char* aboutLine[]={
|
|||
"ZoomTen (Zumi)",
|
||||
"",
|
||||
"-- additional feedback/fixes --",
|
||||
"Electric Keet",
|
||||
"fd",
|
||||
"GENATARi",
|
||||
"host12prog",
|
||||
|
|
|
@ -304,6 +304,7 @@ void FurnaceGUI::drawChanOsc() {
|
|||
"- %C: channel short name\n"
|
||||
"- %d: channel number (starting from 0)\n"
|
||||
"- %D: channel number (starting from 1)\n"
|
||||
"- %n: channel note\n"
|
||||
"- %i: instrument name\n"
|
||||
"- %I: instrument number (decimal)\n"
|
||||
"- %x: instrument number (hex)\n"
|
||||
|
@ -539,6 +540,12 @@ void FurnaceGUI::drawChanOsc() {
|
|||
text+=fmt::sprintf("%.2X",chanState->volume>>8);
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
DivChannelState* chanState=e->getChanState(ch);
|
||||
if (chanState==NULL || !(chanState->keyOn)) break;
|
||||
text+=fmt::sprintf("%s",noteName(short (chanState->note),0));
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
text+='%';
|
||||
break;
|
||||
|
|
|
@ -69,6 +69,7 @@ void FurnaceGUI::drawChannels() {
|
|||
if (dragItem->IsDataType("FUR_CHAN")) {
|
||||
if (chanToMove!=i && chanToMove>=0) {
|
||||
e->swapChannelsP(chanToMove,i);
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
chanToMove=-1;
|
||||
}
|
||||
|
|
|
@ -330,9 +330,6 @@ void FurnaceGUI::insListItem(int i, int dir, int asset) {
|
|||
if (ImGui::MenuItem("save")) {
|
||||
doAction(GUI_ACTION_INS_LIST_SAVE);
|
||||
}
|
||||
if (ImGui::MenuItem("save (legacy .fui)")) {
|
||||
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||
}
|
||||
if (ImGui::MenuItem("save (.dmp)")) {
|
||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||
}
|
||||
|
|
|
@ -648,9 +648,6 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_INS_LIST_SAVE:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE);
|
||||
break;
|
||||
case GUI_ACTION_INS_LIST_SAVE_OLD:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_OLD);
|
||||
break;
|
||||
case GUI_ACTION_INS_LIST_SAVE_DMP:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_DMP);
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "gui.h"
|
||||
#include "guiConst.h"
|
||||
#include <imgui.h>
|
||||
#include "IconsFontAwesome4.h"
|
||||
|
||||
void FurnaceGUI::drawEffectList() {
|
||||
if (nextWindow==GUI_WINDOW_EFFECT_LIST) {
|
||||
|
@ -11,7 +12,28 @@ void FurnaceGUI::drawEffectList() {
|
|||
if (!effectListOpen) return;
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(60.0f*dpiScale,20.0f*dpiScale),ImVec2(canvasW,canvasH));
|
||||
if (ImGui::Begin("Effect List",&effectListOpen,globalWinFlags)) {
|
||||
ImGui::Text("Chip at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse]));
|
||||
float availB=ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing();
|
||||
if (availB>0) {
|
||||
ImGui::PushTextWrapPos(availB);
|
||||
ImGui::TextWrapped("Chip at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse]));
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
ImGui::Button(ICON_FA_BARS "##SortEffects");
|
||||
if (ImGui::BeginPopupContextItem("effectSort",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
for (int i=0; i<9; i++) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColorsSort[i]]);
|
||||
ImGui::Checkbox(fxColorsNames[i],&effectsShow[i]);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (ImGui::Button("All")) memset(effectsShow,1,sizeof(bool)*10);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("None")) memset(effectsShow,0,sizeof(bool)*10);
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("effectList",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
@ -25,11 +47,24 @@ void FurnaceGUI::drawEffectList() {
|
|||
const char* prevName=NULL;
|
||||
for (int i=0; i<256; i++) {
|
||||
const char* name=e->getEffectDesc(i,cursor.xCoarse);
|
||||
bool effectShow = true;
|
||||
if (name==prevName) {
|
||||
continue;
|
||||
}
|
||||
prevName=name;
|
||||
if (name!=NULL) {
|
||||
switch (fxColors[i]) {
|
||||
case GUI_COLOR_PATTERN_EFFECT_MISC: effectShow = effectsShow[8]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_SONG: effectShow = effectsShow[1]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_SPEED: effectShow = effectsShow[3]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_TIME: effectShow = effectsShow[2]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_PITCH: effectShow = effectsShow[0]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_PANNING: effectShow = effectsShow[4]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_VOLUME: effectShow = effectsShow[5]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY: effectShow = effectsShow[6]; break;
|
||||
case GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY: effectShow = effectsShow[7]; break;
|
||||
default: effectShow = true; break;
|
||||
}
|
||||
if (name!=NULL && effectShow) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushFont(patFont);
|
||||
|
|
|
@ -1653,16 +1653,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_INS_SAVE_OLD:
|
||||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
"Save Instrument",
|
||||
{"Furnace instrument", "*.fui"},
|
||||
"Furnace instrument{.fui}",
|
||||
workingDirIns,
|
||||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_INS_SAVE_DMP:
|
||||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
|
@ -4601,7 +4591,6 @@ bool FurnaceGUI::loop() {
|
|||
case GUI_FILE_INS_OPEN:
|
||||
case GUI_FILE_INS_OPEN_REPLACE:
|
||||
case GUI_FILE_INS_SAVE:
|
||||
case GUI_FILE_INS_SAVE_OLD:
|
||||
case GUI_FILE_INS_SAVE_DMP:
|
||||
workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
|
@ -4704,9 +4693,6 @@ bool FurnaceGUI::loop() {
|
|||
if (curFileDialog==GUI_FILE_INS_SAVE) {
|
||||
checkExtension(".fui");
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_INS_SAVE_OLD) {
|
||||
checkExtension(".fui");
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_INS_SAVE_DMP) {
|
||||
checkExtension(".dmp");
|
||||
}
|
||||
|
@ -4800,11 +4786,6 @@ bool FurnaceGUI::loop() {
|
|||
e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song);
|
||||
}
|
||||
break;
|
||||
case GUI_FILE_INS_SAVE_OLD:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
||||
e->song.ins[curIns]->save(copyOfName.c_str(),true);
|
||||
}
|
||||
break;
|
||||
case GUI_FILE_INS_SAVE_DMP:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
||||
if (!e->song.ins[curIns]->saveDMP(copyOfName.c_str())) {
|
||||
|
@ -7317,6 +7298,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
memset(macroRelLabel,0,32);
|
||||
memset(emptyLabel,0,32);
|
||||
memset(emptyLabel2,0,32);
|
||||
//effect sorting
|
||||
memset(effectsShow,1,sizeof(bool)*10);
|
||||
|
||||
strncpy(noteOffLabel,"OFF",32);
|
||||
strncpy(noteRelLabel,"===",32);
|
||||
|
|
|
@ -402,7 +402,6 @@ enum FurnaceGUIFileDialogs {
|
|||
GUI_FILE_INS_OPEN,
|
||||
GUI_FILE_INS_OPEN_REPLACE,
|
||||
GUI_FILE_INS_SAVE,
|
||||
GUI_FILE_INS_SAVE_OLD,
|
||||
GUI_FILE_INS_SAVE_DMP,
|
||||
GUI_FILE_WAVE_OPEN,
|
||||
GUI_FILE_WAVE_OPEN_REPLACE,
|
||||
|
@ -612,7 +611,6 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_INS_LIST_OPEN,
|
||||
GUI_ACTION_INS_LIST_OPEN_REPLACE,
|
||||
GUI_ACTION_INS_LIST_SAVE,
|
||||
GUI_ACTION_INS_LIST_SAVE_OLD,
|
||||
GUI_ACTION_INS_LIST_SAVE_DMP,
|
||||
GUI_ACTION_INS_LIST_MOVE_UP,
|
||||
GUI_ACTION_INS_LIST_MOVE_DOWN,
|
||||
|
@ -1531,6 +1529,7 @@ class FurnaceGUI {
|
|||
int newSongBehavior;
|
||||
int memUsageUnit;
|
||||
int cursorFollowsWheel;
|
||||
int noDMFCompat;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
@ -1685,6 +1684,7 @@ class FurnaceGUI {
|
|||
newSongBehavior(0),
|
||||
memUsageUnit(1),
|
||||
cursorFollowsWheel(0),
|
||||
noDMFCompat(0),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
@ -2038,6 +2038,9 @@ class FurnaceGUI {
|
|||
bool pianoReadonly;
|
||||
int pianoOffset, pianoOffsetEdit;
|
||||
int pianoView, pianoInputPadMode;
|
||||
|
||||
//effect sorting
|
||||
bool effectsShow[10];
|
||||
|
||||
// TX81Z
|
||||
bool hasACED;
|
||||
|
|
|
@ -208,6 +208,32 @@ const char* resampleStrats[]={
|
|||
"best possible"
|
||||
};
|
||||
|
||||
const FurnaceGUIColors fxColorsSort[]={//used for sorting
|
||||
GUI_COLOR_PATTERN_EFFECT_PITCH,
|
||||
GUI_COLOR_PATTERN_EFFECT_SONG,
|
||||
GUI_COLOR_PATTERN_EFFECT_TIME,
|
||||
GUI_COLOR_PATTERN_EFFECT_SPEED,
|
||||
GUI_COLOR_PATTERN_EFFECT_PANNING,
|
||||
GUI_COLOR_PATTERN_EFFECT_VOLUME,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID
|
||||
};
|
||||
|
||||
const char* fxColorsNames[]={
|
||||
"Pitch",
|
||||
"Song",
|
||||
"Time",
|
||||
"Speed",
|
||||
"Panning",
|
||||
"Volume",
|
||||
"System Primary",
|
||||
"System Secondary",
|
||||
"Miscellaneous",
|
||||
"Invalid"
|
||||
};
|
||||
|
||||
const FurnaceGUIColors fxColors[256]={
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC, // 00
|
||||
GUI_COLOR_PATTERN_EFFECT_PITCH, // 01
|
||||
|
@ -646,7 +672,6 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("INS_LIST_OPEN", "Open", 0),
|
||||
D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
||||
D("INS_LIST_SAVE", "Save", 0),
|
||||
D("INS_LIST_SAVE_OLD", "Save (legacy .fui)", 0),
|
||||
D("INS_LIST_SAVE_DMP", "Save (.dmp)", 0),
|
||||
D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
||||
D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
||||
|
|
|
@ -57,4 +57,6 @@ extern const FurnaceGUIActionDef guiActions[];
|
|||
extern const FurnaceGUIColorDef guiColors[];
|
||||
extern const int altValues[24];
|
||||
extern const int vgmVersions[7];
|
||||
extern const FurnaceGUIColors fxColors[256];
|
||||
extern const FurnaceGUIColors fxColors[256];
|
||||
extern const FurnaceGUIColors fxColorsSort[10];
|
||||
extern const char* fxColorsNames[10];
|
|
@ -2288,9 +2288,6 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::SetTooltip("Save");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) {
|
||||
if (ImGui::MenuItem("save in legacy format...")) {
|
||||
doAction(GUI_ACTION_INS_LIST_SAVE_OLD);
|
||||
}
|
||||
if (ImGui::MenuItem("save as .dmp...")) {
|
||||
doAction(GUI_ACTION_INS_LIST_SAVE_DMP);
|
||||
}
|
||||
|
@ -4688,7 +4685,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::Separator();
|
||||
|
||||
P(ImGui::Checkbox("Per-channel wave offset/length",&ins->n163.perChanPos));
|
||||
P(ImGui::Checkbox("Per-channel wave position/length",&ins->n163.perChanPos));
|
||||
|
||||
if (ins->n163.perChanPos) {
|
||||
if (ImGui::BeginTable("N1PerChPos",3)) {
|
||||
|
@ -4700,7 +4697,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Ch");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Offset");
|
||||
ImGui::Text("Position");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Length");
|
||||
|
||||
|
@ -4732,7 +4729,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::EndTable();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::InputInt("Offset##WAVEPOS",&ins->n163.wavePos,1,16)) { PARAMETER
|
||||
if (ImGui::InputInt("Position##WAVEPOS",&ins->n163.wavePos,1,16)) { PARAMETER
|
||||
if (ins->n163.wavePos<0) ins->n163.wavePos=0;
|
||||
if (ins->n163.wavePos>255) ins->n163.wavePos=255;
|
||||
}
|
||||
|
@ -5563,6 +5560,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ins->type==DIV_INS_MSM6295) waveMax=0;
|
||||
if (ins->type==DIV_INS_SEGAPCM) waveMax=0;
|
||||
if (ins->type==DIV_INS_K007232) waveMax=0;
|
||||
if (ins->type==DIV_INS_ES5506) waveMax=0;
|
||||
if (ins->type==DIV_INS_GA20) waveMax=0;
|
||||
if (ins->type==DIV_INS_K053260) waveMax=0;
|
||||
if (ins->type==DIV_INS_POKEMINI) waveMax=0;
|
||||
|
|
|
@ -991,7 +991,7 @@ void FurnaceGUI::initSystemPresets() {
|
|||
}
|
||||
);
|
||||
ENTRY(
|
||||
"PC + AdLib/Sound Blaster (drums mode)", {
|
||||
"PC + Sound Blaster (drums mode)", {
|
||||
CH(DIV_SYSTEM_OPL2_DRUMS, 1.0f, 0, ""),
|
||||
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, ""),
|
||||
CH(DIV_SYSTEM_PCM_DAC, 1.0f, 0,
|
||||
|
|