diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..142ad255a --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sfd text diff --git a/.gitignore b/.gitignore index ab6a95188..1c7ed1ead 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ release/ t/ winbuild/ win32build/ +xpbuild/ macbuild/ linuxbuild/ *.swp @@ -27,3 +28,4 @@ extern/imgui_patched/examples/ src/asm/68k/amigatest/*.bin src/asm/68k/amigatest/player res/binary_to_compressed_c +res/binary_to_compressed_c.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index 85fa2b354..63053c787 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -507,7 +507,7 @@ src/engine/platform/sound/d65modified.c src/engine/platform/sound/ted-sound.c -src/engine/platform/sound/c140.c +src/engine/platform/sound/c140_c219.c src/engine/platform/oplAInterface.cpp src/engine/platform/ym2608Interface.cpp @@ -518,6 +518,7 @@ src/engine/brrUtils.c src/engine/safeReader.cpp src/engine/safeWriter.cpp src/engine/cmdStream.cpp +src/engine/cmdStreamOps.cpp src/engine/config.cpp src/engine/configEngine.cpp src/engine/dispatchContainer.cpp @@ -525,6 +526,7 @@ src/engine/engine.cpp src/engine/export.cpp src/engine/fileOps.cpp src/engine/fileOpsIns.cpp +src/engine/fileOpsSample.cpp src/engine/filter.cpp src/engine/instrument.cpp src/engine/macroInt.cpp @@ -535,6 +537,7 @@ src/engine/song.cpp src/engine/sysDef.cpp src/engine/wavetable.cpp src/engine/waveSynth.cpp +src/engine/wavOps.cpp src/engine/vgmOps.cpp src/engine/zsmOps.cpp src/engine/zsm.cpp diff --git a/README.md b/README.md index f4d4af3c3..08ccfc85c 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,10 @@ for other operating systems, you may [build the source](#developer-info). - Ricoh RF5C68 used in Sega CD and FM Towns - OKI MSM6258 and MSM6295 - Konami K007232 + - Konami K053260 - Irem GA20 - Ensoniq ES5506 + - Namco C140 - wavetable chips: - HuC6280 used in PC Engine - Konami Bubble System WSG @@ -73,6 +75,7 @@ for other operating systems, you may [build the source](#developer-info). - QuadTone engine - Pokémon Mini - Commodore PET + - TED used in Commodore Plus/4 - Casio PV-1000 - TIA used in Atari 2600 - POKEY used in Atari 8-bit computers @@ -124,7 +127,7 @@ for other operating systems, you may [build the source](#developer-info). # quick references - **discussion**: see the [Discussions](https://github.com/tildearrow/furnace/discussions) section, the [official Revolt](https://rvlt.gg/GRPS6tmc) or the [official Discord server](https://discord.gg/EfrwT2wq7z). -- **help**: check out the [documentation](doc/README.md). it's about 80% complete. +- **help**: check out the [documentation](doc/README.md). it's about 90% complete. ## packages diff --git a/android/app/build.gradle b/android/app/build.gradle index e19c78a58..dcf7fe76e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,8 +15,8 @@ android { } minSdkVersion 21 targetSdkVersion 26 - versionCode 162 - versionName "0.6pre7" + versionCode 169 + versionName "0.6pre9" externalNativeBuild { cmake { arguments "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DWARNINGS_ARE_ERRORS=ON" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7f6a769d4..dd3c7a0bd 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ diff --git a/demos/opl/DASH.fur b/demos/opl/DASH.fur new file mode 100644 index 000000000..d8c30bd43 Binary files /dev/null and b/demos/opl/DASH.fur differ diff --git a/demos/pc98/atomic_failure.fur b/demos/pc98/atomic_failure.fur new file mode 100644 index 000000000..61b430537 Binary files /dev/null and b/demos/pc98/atomic_failure.fur differ diff --git a/doc/1-intro/concepts.md b/doc/1-intro/concepts.md index 130e2ae83..b91797179 100644 --- a/doc/1-intro/concepts.md +++ b/doc/1-intro/concepts.md @@ -15,22 +15,22 @@ The **[pattern view](../3-pattern/README.md)** is like a spreadsheet that displa ## structure The **order list** is a smaller spreadsheet showing the overall song structure. -- A song is made up of a list of **orders**. -- An **order** is a set of numbered **patterns** used for each channel. +- A song is made up of a list of orders. +- An **order** is a set of numbered patterns used for each channel. - Each channel has its own unique list of patterns. -- Each pattern contains note and effect data for that channel only. +- Each **pattern** contains note and effect data for that channel only. - Patterns may be used multiple times in the order list. Changing a pattern's data in one order will affect the same pattern used in other orders. ## time -- Each pattern is made of the same number of **rows** as seen in the tracker view. -- During playback, Each row lasts a number of **ticks** determined by its **speed** value. -- A tick is the smallest measure of time to which all note, effect, and macro times are quantized. +- Each pattern is made of the same number of rows as seen in the tracker view. +- During playback, each **row** lasts a number of ticks determined by its **speed** value. +- A **tick** is the smallest measure of time to which all note, effect, and macro times are quantized. ## sound Different chips have different capabilities. Even within the same chip, each channel may have its own ways of making sound. - Some channels use one or more waveform **generators** (sine, square, noise...) to build up a sound. - Of special note are **[FM (frequency modulation)](../4-instrument/fm.md)** channels, which use a number of generators called **operators** that can interact to make very complex sounds. -- Some channels use **[samples](../6-sample/README.md)** - recordings of sounds, often with defined loop points to allow a note to sustain. +- Some channels use **[samples](../6-sample/README.md)** which are recordings of sounds, often with defined loop points to allow a note to sustain. - Some channels use **[wavetables](../5-wave/README.md)**, which are like very short samples of fixed length that automatically loop. \ No newline at end of file diff --git a/doc/2-interface/README.md b/doc/2-interface/README.md index 3d6067aff..c4a375322 100644 --- a/doc/2-interface/README.md +++ b/doc/2-interface/README.md @@ -6,9 +6,14 @@ the default layout of Furnace is depicted below. ![interface](interface1.png) -primary topics: +## general info +- [UI components](components.md): recommended reading for all! +- [global keyboard shortcuts](keyboard.md) - [menu bar](menu-bar.md) + +## primary windows + - [order list](order-list.md) - [play/edit controls](play-edit-controls.md) - [instrument/wavetable/sample list](asset-list.md) @@ -19,7 +24,7 @@ primary topics: - [wavetable editor](../5-wave/README.md) - [sample editor](../6-sample/README.md) -advanced topics: +## advanced topics - [mixer](../8-advanced/mixer.md) - [grooves](../8-advanced/grooves.md) @@ -36,9 +41,7 @@ advanced topics: - [log viewer](../8-advanced/log-viewer.md) - [statistics](../8-advanced/stats.md) -other topics: +## other topics -- [settings](../2-interface/settings.md) -- [UI components](components.md) -- [global keyboard shortcuts](keyboard.md) - [basic mode](basic-mode.md) +- [settings](../2-interface/settings.md) diff --git a/doc/2-interface/asset-add.png b/doc/2-interface/asset-add.png deleted file mode 100644 index f6ef5b73b..000000000 Binary files a/doc/2-interface/asset-add.png and /dev/null differ diff --git a/doc/2-interface/asset-delete.png b/doc/2-interface/asset-delete.png deleted file mode 100644 index d0eb8dd97..000000000 Binary files a/doc/2-interface/asset-delete.png and /dev/null differ diff --git a/doc/2-interface/asset-duplicate.png b/doc/2-interface/asset-duplicate.png deleted file mode 100644 index caa740fb1..000000000 Binary files a/doc/2-interface/asset-duplicate.png and /dev/null differ diff --git a/doc/2-interface/asset-folderview.png b/doc/2-interface/asset-folderview.png deleted file mode 100644 index 8d693e0fe..000000000 Binary files a/doc/2-interface/asset-folderview.png and /dev/null differ diff --git a/doc/2-interface/asset-list.md b/doc/2-interface/asset-list.md index 836d9b694..7c8340f5e 100644 --- a/doc/2-interface/asset-list.md +++ b/doc/2-interface/asset-list.md @@ -3,10 +3,20 @@ ![instruments window](instruments.png) Buttons from left to right: -- **Add**: Creates a new, default instrument. +- **Add**: pops up a menu to select which type of instrument to add. if only one instrument type is available, the menu is skipped. + - If the "Display instrument type menu when adding instrument" setting is disabled, this skips the menu and creates an instrument according to the chip under the cursor. + - Right-clicking always brings up the menu. - **Duplicate**: Duplicates the currently selected instrument. - **Open**: Brings up a file dialog to load a file as a new instrument at the end of the list. -- **Save**: Brings up a file dialog to save the currently selected instrument. +- **Save**: Brings up a file dialog to save the currently selected asset. + - Instruments are saved as Furnace instrument (.fui) files. + - Wavetables are saved as Furnace wavetable (.fuw) files. + - Samples are saved as standard wave (.wav) files. + - Right-clicking brings up a menu with the applicable items from this list: + - **save instrument as .dmp...**: saves the selected instrument in DefleMask format. + - **save wavetable as .dmw...**: saves the selected wavetable in DefleMask format. + - **save raw wavetable...**: saves the selected wavetable as raw data. + - **save raw sample...**: saves the selected sample as raw data. - **Toggle folders/standard view**: Enables (and disables) folder view, explained below. - **Move up**: Moves the currently selected instrument up in the list. Pattern data will automatically be adjusted to match. - **Move down**: Same, but downward. diff --git a/doc/2-interface/asset-move.png b/doc/2-interface/asset-move.png deleted file mode 100644 index fdcbca6a9..000000000 Binary files a/doc/2-interface/asset-move.png and /dev/null differ diff --git a/doc/2-interface/asset-newfolder.png b/doc/2-interface/asset-newfolder.png deleted file mode 100644 index 01540abd9..000000000 Binary files a/doc/2-interface/asset-newfolder.png and /dev/null differ diff --git a/doc/2-interface/asset-open.png b/doc/2-interface/asset-open.png deleted file mode 100644 index eea985143..000000000 Binary files a/doc/2-interface/asset-open.png and /dev/null differ diff --git a/doc/2-interface/asset-preview.png b/doc/2-interface/asset-preview.png deleted file mode 100644 index 8636285c4..000000000 Binary files a/doc/2-interface/asset-preview.png and /dev/null differ diff --git a/doc/2-interface/asset-previewstop.png b/doc/2-interface/asset-previewstop.png deleted file mode 100644 index 02fe6498e..000000000 Binary files a/doc/2-interface/asset-previewstop.png and /dev/null differ diff --git a/doc/2-interface/asset-save.png b/doc/2-interface/asset-save.png deleted file mode 100644 index 19dd03e9a..000000000 Binary files a/doc/2-interface/asset-save.png and /dev/null differ diff --git a/doc/2-interface/components.md b/doc/2-interface/components.md index c2fce9993..7182138ee 100644 --- a/doc/2-interface/components.md +++ b/doc/2-interface/components.md @@ -1,6 +1,35 @@ # UI components -the user interface consists of several components. this paper describes some of them. +the user interface consists of several kinds of components, some of which benefit from explanation. + +## text fields + +text fields are able to hold... text. + +click on a text field to start editing, and click away to stop editing. + +the following keyboard shortcuts work while on a text field: + +- `Ctrl-X`: cut +- `Ctrl-C`: copy +- `Ctrl-V`: paste +- `Ctrl-A`: select all + +(replace Ctrl with Command on macOS) + +## number input fields + +these work similar to text fields, but you may only input numbers. + +they also usually have `+` and `-` buttons which allow you to increase/decrease the amount when clicked (and rapidly do so when click-holding). + +## sliders + +sliders are used for controlling values in a quick manner by being dragged. + +using the scroll wheel while holding Ctrl will change the slider's value by small amounts. + +right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input precise values. ## windows @@ -16,7 +45,7 @@ to resize a window, drag the bottom right corner (marked by a triangular tab) or to collapse a window, click on the triangle in the title bar. clicking again expands it. -to close a window, click on the `X` at the top right corner. +to close a window, click on the `X` at the top right corner, or select it from the "window" menu. ### arrangement and docking @@ -55,30 +84,3 @@ selecting this option will hide the tab bar of that window. to bring it back, click on the top left corner. to undock a window, drag its tab away from where it is docked. then it will be floating again. - -## text fields - -text fields are able to hold... text. - -click on a text field to start editing, and click away to stop editing. - -the following keyboard shortcuts work while on a text field: - -- `Ctrl-X`: cut -- `Ctrl-C`: copy -- `Ctrl-V`: paste -- `Ctrl-A`: select all - -(replace Ctrl with Command on macOS) - -## number input fields - -these work similar to text fields, but you may only input numbers. - -they also usually have two buttons which allow you to increase/decrease the amount when clicked (and rapidly do so when click-holding). - -## sliders - -sliders are used for controlling values in a quick manner by being dragged. - -alternatively, right-clicking or Ctrl-clicking or a slider (Command-click on macOS) will turn it into a number input field for a short period of time, allowing you to input fine values. diff --git a/doc/2-interface/controls-classic.png b/doc/2-interface/controls-classic.png index 37295e0df..7ffa10503 100644 Binary files a/doc/2-interface/controls-classic.png and b/doc/2-interface/controls-classic.png differ diff --git a/doc/2-interface/controls-split.png b/doc/2-interface/controls-split.png index 2b3fab407..89ae53c7c 100644 Binary files a/doc/2-interface/controls-split.png and b/doc/2-interface/controls-split.png differ diff --git a/doc/2-interface/docking.png b/doc/2-interface/docking.png index bc8eb1415..ba4d6973f 100644 Binary files a/doc/2-interface/docking.png and b/doc/2-interface/docking.png differ diff --git a/doc/2-interface/interface1.png b/doc/2-interface/interface1.png index 1c2abf07d..33018b0b5 100644 Binary files a/doc/2-interface/interface1.png and b/doc/2-interface/interface1.png differ diff --git a/doc/2-interface/menu-bar.md b/doc/2-interface/menu-bar.md index 9a5c2d17b..9b4268cf4 100644 --- a/doc/2-interface/menu-bar.md +++ b/doc/2-interface/menu-bar.md @@ -6,10 +6,10 @@ items in _italics_ don't appear in basic mode and are only available in advanced # file -- **new...**: create a new song. +- **new...**: creates a new song. - **open...**: opens the file picker, allowing you to select a song to open. - **open recent**: contains a list of the songs you've opened before. - - **clear history**: this option erases the file history. + - **clear history**: erases the file history. - **save**: saves the current song. - opens the file picker if this is a new song, or a backup. @@ -33,9 +33,9 @@ items in _italics_ don't appear in basic mode and are only available in advanced - Neo Geo CD (DefleMask 1.0+) - only use this option if you really need it. there are features which DefleMask does not support, like some effects and FM macros, so these will be lost. -- **export audio...**: export your song to a .wav file. see next section for more details. -- **export VGM...**: export your song to a .vgm file. see next section for more details. -- **export ZSM...**: export your song to a .zsm file. see next section for more details. +- **export audio...**: opens the file picker, allowing you to export your song to a .wav file. see next section for more details. +- **export VGM...**: opens the file picker, allowing you to export your song to a .vgm file. see next section for more details. +- **export ZSM...**: opens the file picker, allowing you to export your song to a .zsm file. see next section for more details. - only available when there's a YM2151 and/or VERA. - **export command stream...**: export song data to a command stream file. see next section for more details. - this option is for developers. @@ -48,7 +48,7 @@ items in _italics_ don't appear in basic mode and are only available in advanced - _**remove chip...**_: remove a chip. - **Preserve channel positions**: same thing as above. -- **restore backup**: restore a previously saved backup. +- **restore backup**: restores a previously saved backup. - Furnace keeps up to 5 backups of a song. - the backup directory is located in: - Windows: `%USERPROFILE%\AppData\Roaming\furnace\backups` @@ -87,8 +87,8 @@ the following settings exist: - other versions may not support all chips. - use this option if you need to export for a quirky player or parser. - for example, RYMCast is picky with format versions. if you're going to use this player, select 1.60. -- **loop**: writes loop. if disabled, the resulting file won't loop. -- **loop trail**: this option allows you to set how much of the song is written after it loops. +- **loop**: includes loop information. if disabled, the resulting file won't loop. +- **loop trail**: sets how much of the song is written after it loops. - the reason this exists is to work around a VGM format limitation in where post-loop state isn't recorded at all. - this may change the song length as it appears on a player. - **auto-detect**: detect how much to write automatically. @@ -122,6 +122,7 @@ the following settings are available: - I suggest you use the same rate as the song's. - apparently ZSM doesn't support changing the rate mid-song. - **loop**: enables loop. if disabled, the song won't loop. +- **optimize size**: removes unnecessary commands to reduce size. click on **Begin Export** to... you know. @@ -136,6 +137,8 @@ it's not really useful, unless you're a developer and want to use a command stre # edit +- **...**: does nothing except prevent accidental clicks on later menu items if the menu is too tall to fit on the program window. + - **undo**: reverts the last action. - **redo**: repeats what you undid previously. diff --git a/doc/2-interface/settings.md b/doc/2-interface/settings.md index 46226475c..7a5546642 100644 --- a/doc/2-interface/settings.md +++ b/doc/2-interface/settings.md @@ -1,32 +1,31 @@ # settings -settings are saved when clicking the **OK** button at the bottom of the dialog. - - +settings are saved when clicking the **OK** or **Apply** buttons at the bottom of the dialog. ## General ### Program -- **Render backend** - - changing this may help with performace issues. -- **Late render clear** +- **Render backend**: changing this may help with performace issues. +- **Late render clear**: this option is only useful when using old versions of Mesa drivers. it force-waits for VBlank by clearing after present, reducing latency. - **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!)**: 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. +- **Enable event delay**: may cause issues with high-polling-rate mice when previewing notes. ### File - **Use system file picker**: uses native OS file dialog instead of Furnace's. -- **Number of recent files**: number of files to show in the _open recent..._ menu. -- **Compress when saving** - - uses zlib to compress saved songs. -- **Save unused patterns** -- **Use new pattern format when saving** -- **Don't apply compatibility flags when loading .dmf** +- **Number of recent files**: number of files that will be remembered in the _open recent..._ menu. +- **Compress when saving**: uses zlib to compress saved songs. +- **Save unused patterns**: stores unused patterns in a saved song. +- **Use new pattern format when saving**: stores patterns in the new, optimized and smaller format. only disable if you need to work with older versions of Furnace. +- **Don't apply compatibility flags when loading .dmf**: does exactly what the option says. your .dmf songs may not play correctly after enabled. +- **Play after opening song:** + - No + - Only if already playing + - Yes - **Audio export loop/fade out time:** - **Set to these values on start-up:** - **Loops**: number of additional times to play through `0Bxx` song loop. @@ -41,11 +40,10 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - this will not choose a random system at each start. - **Reset to defaults**: sets default to "Sega Genesis/Mega Drive". - **Name**: name for the default system. may be set to any text. - - **Configure:**: same as in the [chip manager](../8-advanced/chip-manager.md) and [mixer](../8-advanced/mixer.md). + - **Configure**: 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 @@ -70,22 +68,24 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **Backend**: selects SDL or JACK for audio output. - only appears on Linux, or MacOS compiled with JACK support -- **Driver** +- **Driver**: select a different SDL audio driver if you're having problems with the default one. - **Device**: audio device for playback. - **Sample rate** - **Outputs**: 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. + - setting this to a low value may cause stuttering/glitches in playback (known as "underruns" or "xruns"). + - setting this to a high value increases latency. - **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** + - only enable if your buffer size is small (10ms or less). +- **Force mono audio**: use if you're unable to hear stereo audio (e.g. single speaker or hearing loss in one ear). - **want:** displays requested audio configuration. - **got:** displays actual audio configuration returned by audio backend. ### Mixing -- **Quality**: selects quality of resampling. low quality reduces CPU load. +- **Quality**: selects quality of resampling. low quality reduces CPU load by a small amount. - **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. @@ -93,32 +93,39 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **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** +- **Note input**: enables note input. disable if you intend to use this device only for binding actions. +- **Velocity input**: enables velocity input when entering notes in the pattern. +- **Map MIDI channels to direct channels**: when enabled, notes from MIDI channels will be mapped to channels rather than the cursor position. +- **Map Yamaha FM voice data to instruments**: when enabled, Furnace will listen for any transmitted Yamaha SysEx patches. + - this option is only useful if you have a Yamaha FM synthesizer (e.g. TX81Z). + - selecting a voice or using the "Voice Transmit?" option will send a patch, and Furnace will create a new instrument with its data. + - this may also be triggered by clicking on "Receive from TX81Z" in the instrument editor (OPZ only). +- **Program change is instrument selection**: changes the current instrument when a program change event is received. +- **Value input style**: changes the way values are entered when the pattern cursor is not in the Note column. the following styles are available: + - **Disabled/custom**: no value input through MIDI. + - **Two octaves (0 is C-4, F is D#5)**: maps keys in two octaves to single nibble input. the layout is: + - ` - octave n -- octave n+1 -` + - ` 1 3 6 8 A D F # # # ` + - `0 2 4 5 7 9 B C E # # # # #` + - **Raw (note number is value)**: the note number becomes the input value. not useful if you want to input anything above 7F. + - **Two octaves alternate (lower keys are 0-9, upper keys are A-F)**: maps keys in two octaves, but with a different layout: + - ` - octave n -- octave n+1 -` + - ` A B C D E F # # # # ` + - `0 1 2 3 4 5 6 7 8 9 # # # #` + - **Use dual control change (one for each nibble)**: maps two control change events to the nibbles of a value. + - **CC of upper nibble**: select the CC number that will change the upper nibble. + - **CC of lower nibble**: select the CC number that will change the lower nibble. + - **Use 14-bit control change**: maps two control change events that together form a single 14-bit CC. some MIDI controllers do these. + - **MSB CC**: select the CC containing the upper portion of the control. + - **LSB CC**: select the CC containing the lower portion of the control. + - **Use single control change**: maps one control change event. not useful if you want to input odd numbers. + - **Control**: select the CC number that will change the value. +- **Per-column control change**: when enabled, you can map several control change events to a channel's columns. - **Instrument**\ **Volume**\ **Effect `x` type**\ @@ -132,36 +139,34 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **LSB CC** - **Use single control change (imprecise)** - **Control** -- **Volume curve** -- **Actions:** +- **Volume curve**: adjust the velocity to volume curve. +- **Actions**: this allows you to bind note input and control change events to 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** + - **Type**: type of event. + - **Channel**: channel of event. + - **Note/Control**: the note/control change number. + - **Velocity/Value**: the velocity or control value + - **Action**: the GUI action to perform. + - **Learn**: after clicking on this button, do something in your MIDI device and Furnace will map that to this action. + - **Remove**: remove this action. ### MIDI output - **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)** - - + - **Off (use for TX81Z)**: don't output anything. use if you plan to use Furnace as sync master, or the "Receive from TX81Z" button in the OPZ instrument editor. + - **Melodic**: output MIDI events. +- **Send Program Change**: output program change events when instrument change commands occur. +- **Send MIDI clock**: output MIDI beat clock. +- **Send MIDI timecode**: output MIDI timecode. + - **Timecode frame rate**: sets the timing standard used for MIDI timecode. + - **Closest to Tick Rate**: automatically sets the rate based on the song's Tick Rate. + - **Film (24fps)**: output at 24 codes per second. + - **PAL (25fps)**: output at 25 codes per second. + - **NTSC drop (29.97fps)**: output at ~29.97 codes per second, skipping frames 0 and 1 of each minute that doesn't divide by 10. + - **NTSC non-drop (30fps)**: output at 30 codes per second. ## Emulation @@ -174,17 +179,13 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. **FDS core**\ **SID core**\ **POKEY core**\ - **OPN/OPNA/OPNB cores**: all of these are covered in the [guide to choosing emulation cores](../9-guides/emulation-cores.md). + **OPN/OPNA/OPNB cores**: + - **Playback Core(s)**: core(s) to use for realtime playback. + - **Render Core(s)**: core(s) to use for exporting audio. + - all of these are covered in the [guide to choosing emulation cores](../9-guides/emulation-cores.md). - **PC Speaker strategy**: this is covered in the [PC speaker system doc](../7-systems/pcspkr.md). -- **Sample ROMs:** - - **OPL4 YRW801 path** - - **MultiPCM TG100 path** - - **MultiPCM MU5 path** - - - ## Keyboard ### Keyboard @@ -209,6 +210,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **Allow docking editors** - **Remember window position**: remembers the window's last position on start-up. - **Only allow window movement when clicking on title bar** +- **Center pop-up windows** - **Play/edit controls layout:** - **Classic** - **Compact** @@ -324,6 +326,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **File path** - **Cursor details or file path** - **Nothing** +- **Capitalize menu bar** ### Orders @@ -396,6 +399,7 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **Horizontal instrument list**: when there are more instruments than there is room to display them... - if on, scroll horizontally through multiple columns. - if off, scroll vertically in one long column. + - only appears if "Unified instrument/wavetable/sample list" is off. - **Instrument list icon style:** - **None** - **Graphical icons** @@ -408,10 +412,8 @@ settings are saved when clicking the **OK** button at the bottom of the dialog. - **Macro editor layout:** - **Unified** - - **Mobile** - **Grid** - **Single (with list)** - - **Single (combo box)** - **Use classic macro editor vertical slider** ### Wave Editor diff --git a/doc/2-interface/window.png b/doc/2-interface/window.png index a812b7a89..0bc4e239b 100644 Binary files a/doc/2-interface/window.png and b/doc/2-interface/window.png differ diff --git a/doc/4-instrument/README.md b/doc/4-instrument/README.md index 497204646..c7fbb67d2 100644 --- a/doc/4-instrument/README.md +++ b/doc/4-instrument/README.md @@ -1,6 +1,16 @@ # instrument editor -every instrument can be renamed and have its type changed. +the instrument editor always starts with this section: + +![top of instrument editor](instrument-editor-top.png) + +- top-left numeric dropdown: instrument selector. +- folder icon: open an instrument file. +- save icon: save current instrument as a file. + - right-clicking gives the option to save a .dmp format DefleMask preset. +- **Name**: instrument name. +- **Type**: the system for which the instrument is intended. + - if changed, all applicable settings and macros will remain as they are. numbers will not be adjusted. depending on the instrument type, there are many different types of instrument editor: diff --git a/doc/4-instrument/instrument-editor-top.png b/doc/4-instrument/instrument-editor-top.png new file mode 100644 index 000000000..138a117fe Binary files /dev/null and b/doc/4-instrument/instrument-editor-top.png differ diff --git a/doc/4-instrument/macro-ADSR.png b/doc/4-instrument/macro-ADSR.png index f38d14329..d01e177ef 100644 Binary files a/doc/4-instrument/macro-ADSR.png and b/doc/4-instrument/macro-ADSR.png differ diff --git a/doc/4-instrument/macro-LFO.png b/doc/4-instrument/macro-LFO.png index 90cb5c088..06904e8b7 100644 Binary files a/doc/4-instrument/macro-LFO.png and b/doc/4-instrument/macro-LFO.png differ diff --git a/doc/4-instrument/wavetable.png b/doc/4-instrument/wavetable.png index 7c862d953..2b7e4ac5e 100644 Binary files a/doc/4-instrument/wavetable.png and b/doc/4-instrument/wavetable.png differ diff --git a/doc/5-wave/README.md b/doc/5-wave/README.md index 7c586ef78..8b0db521a 100644 --- a/doc/5-wave/README.md +++ b/doc/5-wave/README.md @@ -27,8 +27,11 @@ Amiga | ≤256 | 256 | controls across the top line: - waveform number. the `-` and `+` buttons step through the list. -- open. -- save. +- open. opens a file selector to choose the file to open. +- save. opens a file selector to choose the file to save to. + - right-clicking brings up a menu: + - **save as .dmw...**: saves the selected wavetable in DefleMask format. + - **save raw...**: saves the selected wavetable as raw data. - **Steps**: view waveform as discrete blocks. - **Lines**: view waveform as a continuous line. - **Width**: length of the waveform data. maximum is 256. diff --git a/doc/5-wave/instrument-wavetable.png b/doc/5-wave/instrument-wavetable.png index d5a8f112b..4710b6680 100644 Binary files a/doc/5-wave/instrument-wavetable.png and b/doc/5-wave/instrument-wavetable.png differ diff --git a/doc/6-sample/README.md b/doc/6-sample/README.md index 9f5a6cf86..ccd663c1f 100644 --- a/doc/6-sample/README.md +++ b/doc/6-sample/README.md @@ -46,7 +46,7 @@ if you need to use more samples, you may change the sample bank using effect `EB due to limitations in some of those sound chips, some restrictions exist: -- Amiga: maximum frequency is 31,469Hz, but anything over 28,867 will sound glitchy on hardware. sample lengths and loop will be set to an even number, and your sample can't be longer than 131070. +- Amiga: maximum frequency is 31469Hz, but anything over 28867 will sound glitchy on hardware. sample lengths and loop will be set to an even number, and your sample can't be longer than 131070. - NES: if on DPCM mode, only a limited selection of frequencies is available, and loop position isn't supported (only entire sample). - SegaPCM: your sample can't be longer than 65535, and the maximum frequency is 31.25KHz. - QSound: your sample can't be longer than 65535, and the loop length shall not be greater than 32767. @@ -75,11 +75,16 @@ in there, you can modify certain data pertaining to your sample, such as the: - top-left drop-down box: sample slot. - **Open**: replaces current sample. + - Right-clicking brings up a menu: + - **import raw...**: brings up a file selector, then presents a dialog to choose the format of the selected file. - **Save**: saves current sample to disk. + - Right-clicking brings up a menu: + - **save raw...**: brings up a file selector, then saves the sample as raw data. - **Name**: name in sample list. - button to left of **Info**: collapses and expands the info bar. - **Type**: sample format. only 8-bit and 16-bit PCM samples are editable. selecting a format converts the sample data. -- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. should not be enabled for BRR-type samples. +- **BRR emphasis**: boosts higher frequencies to compensate for the SNES low-pass filter. should not be enabled for BRR-type samples. only appears when applicable. +- **8-bit dither**: applies dithering to samples meant to play back at 8-bit resolution. only appears when applicable. - **Rate**: switches to normal rate values. - **Compat Rate**: switches to DefleMask-compatible rate values for sample mapping. diff --git a/doc/7-systems/opll.md b/doc/7-systems/opll.md index 92a81490b..f32f1eefc 100644 --- a/doc/7-systems/opll.md +++ b/doc/7-systems/opll.md @@ -13,10 +13,8 @@ the YM2413 is equipped with the following features: - 9 channels of 2 operator FM synthesis - a drum/percussion mode, replacing the last 3 voices with 5 rhythm channels, with drum mode tones hard-defined in the chip itself, like FM instruments. only pitch might be altered. - - drum mode works like following: FM channel 7 is for Kick Drum, which is a normal FM channel but routed through mixer twice for 2× volume, like all drum sounds. FM channel 8 splits to Snare, Drum, and Hi-Hat. Snare Drum is the carrier and it works with a special 1 bit noise generator combined with a square wave, all possible by overriding phase-generator with some different synthesis method. Hi-Hat is the modulator and it works with the noise generator and also the special synthesis. CH9 splits to Top-Cymbal and Tom-Tom, Top-Cymbal is the carrier and only has the special synthesis, while Tom-Tom is basically a 1op wave. - special synthesis mentioned already is: 5 square waves are gathered from 4×, 64× and 128× the pitch of channel 8 and 16× and 64× the pitch of channel 9 and they go through a process where 2 HH bits OR'd together, then 1 HH and 1 TC bit OR'd, then the two TC bits OR'd together, and those 3 results get XOR'd. - - 1 user-definable patch (this patch can be changed throughout the course of the song) - 15 pre-defined patches which can all be used at the same time - support for ADSR on both the modulator and the carrier @@ -37,7 +35,7 @@ the YM2413 is equipped with the following features: - `y` is the multiplier. - `18xx`: **toggle drums mode.** - `0` disables it and `1` enables it. - - only in drums chip. + - only in drums mode. - `19xx`: **set attack of all operators.** - `1Axx`: **set attack of operator 1.** - `1Bxx`: **set attack of operator 2.** @@ -69,3 +67,8 @@ the YM2413 is equipped with the following features: # info this chip uses the [FM (OPLL)](../4-instrument/fm-opll.md) instrument editor. + +## chip options + +- **Ignore top/hi-hat frequency changes**: in drums mode, makes the top/hi-hat channels not write frequency since they share it with snare and tom +- **Apply fixed frequency to all drums at once**: sets the frequency of all drums to that of a fixed frequency OPLL drums instrument when one note with it is reached diff --git a/doc/7-systems/sms.md b/doc/7-systems/sms.md index 36d13976d..e4fe22317 100644 --- a/doc/7-systems/sms.md +++ b/doc/7-systems/sms.md @@ -1,6 +1,8 @@ # TI SN76489 (e.g. Sega Master System) -a relatively simple sound chip made by Texas Instruments. a derivative of it is used in Sega's Master System, the predecessor to Genesis. +a relatively simple sound chip made by Texas Instruments. a derivative of it is used in Sega's Master System, the predecessor to Genesis. It has three square wave channels and one noise channel... not really. + +Nominal mode of SN76489 has 3 quare wave channels, with noise channel having only 3 preset frequencies to use (absurdly low, very low, low). To use more pitches, one can enable mode, which "steals" pitch data from square wave channel 3. By doing that, SN76489 becomes effectively a 3 channel sound chip. In addition, periodic noise mode can be enabled, with same caveats. the original iteration of the SN76489 used in the TI-99/4A computer, the SN94624, could only produce tones as low as 100Hz, and was clocked at 447 KHz. all later versions (such as the one in the Master System and Genesis) had a clock divider but ran on a faster clock... except for the SN76494, which can play notes as low as 13.670 Hz (A -1). consequently, its pitch accuracy for higher notes is compromised. diff --git a/doc/8-advanced/chanosc-gradient.png b/doc/8-advanced/chanosc-gradient.png index 357bbf764..cd255d523 100644 Binary files a/doc/8-advanced/chanosc-gradient.png and b/doc/8-advanced/chanosc-gradient.png differ diff --git a/doc/8-advanced/chanosc.png b/doc/8-advanced/chanosc.png index 06dce19c1..2d05dbdf1 100644 Binary files a/doc/8-advanced/chanosc.png and b/doc/8-advanced/chanosc.png differ diff --git a/doc/8-advanced/comments.md b/doc/8-advanced/comments.md index b36d65ab8..3fc14d590 100644 --- a/doc/8-advanced/comments.md +++ b/doc/8-advanced/comments.md @@ -2,7 +2,7 @@ ![comments dialog](comments.png) -Comments, credits, or any arbitrary text may be entered here. +Comments, credits, or any arbitrary text may be entered here.\ It has no effect on the song. There is no word wrap; long lines must be broken manually with the Enter key. \ No newline at end of file diff --git a/doc/8-advanced/find-find.png b/doc/8-advanced/find-find.png index 64f5c0ea3..8f061ebe5 100644 Binary files a/doc/8-advanced/find-find.png and b/doc/8-advanced/find-find.png differ diff --git a/doc/8-advanced/groove.png b/doc/8-advanced/groove.png index 09ac81780..75beb3caf 100644 Binary files a/doc/8-advanced/groove.png and b/doc/8-advanced/groove.png differ diff --git a/doc/8-advanced/piano.md b/doc/8-advanced/piano.md index 6217f8473..4218ef083 100644 --- a/doc/8-advanced/piano.md +++ b/doc/8-advanced/piano.md @@ -29,10 +29,5 @@ Key layout: - **Standard**: Black keys are 2/3 length. - **Continuous**: Black keys are full length. -Value input pad: (document this) -- **Disabled** -- **Replace piano** -- **Split (automatic)** -- **Split (always visible)** - -**Share play/edit offset/range**: (document this) +**Share play/edit offset/range**: If disabled, the piano will keep different octave and range values for playback and non-playback states. +**Read-only (can't input notes): Prevents note entry. \ No newline at end of file diff --git a/doc/8-advanced/stats.png b/doc/8-advanced/stats.png index 920654e6e..aabafa50e 100644 Binary files a/doc/8-advanced/stats.png and b/doc/8-advanced/stats.png differ diff --git a/doc/9-guides/README.md b/doc/9-guides/README.md index aa6d5cbf6..4efaf6634 100644 --- a/doc/9-guides/README.md +++ b/doc/9-guides/README.md @@ -4,4 +4,9 @@ here is a small collection of useful tricks and techniques to really make Furnac - [using samples with limited playback rates](limited-samples.md) - [choosing emulation cores](emulation-cores.md) -- [guide on using OPLL patch macro](opllswitching.md) \ No newline at end of file +- [using OPLL patch macro](opllswitching.md) +- [using AY/SAA hardware envelope](envelope.md) + +# links + +- [FM Synthesis of Real Instruments](http://www.javelinart.com/FM_Synthesis_of_Real_Instruments.pdf): an in-depth tutorial on creating FM patches from scratch. \ No newline at end of file diff --git a/doc/9-guides/emulation-cores.md b/doc/9-guides/emulation-cores.md index 340f0838b..323e180c4 100644 --- a/doc/9-guides/emulation-cores.md +++ b/doc/9-guides/emulation-cores.md @@ -1,36 +1,36 @@ # choosing emulation cores -Furnace achieves the authentic sound of videogame hardware by emulating sound chips accurately as possible, using **emulator cores**. in some cases there are multiple cores to choose from, each with different strengths and weaknesses. here are the major differences between them all. +Furnace achieves the authentic sound of videogame hardware by emulating sound chips as accurately as possible, using **emulator cores**. in some cases there are multiple cores to choose from, each with different strengths and weaknesses. here are the major differences between them all. - **Arcade/YM2151 core**: - - **ymfm**: default. much less CPU usage than Nuked-OPM, but less accurate. recommended for users with last-gen or earlier hardware. - - **Nuked-OPM**: much more accurate than ymfm, due to the emulator being based on an image of the die map taken from a real YM2151. very CPU heavy, only recommended for users with recent hardware. + - **ymfm**: default playback core. much less CPU usage than Nuked-OPM, but less accurate. recommended for users with last-gen or earlier hardware. + - **Nuked-OPM**: default render core. much more accurate than ymfm, due to the emulator being based on an image of the die map taken from a real YM2151. very CPU heavy, only recommended for users with recent hardware. - **Genesis/YM2612 core**: - - **Nuked-OPN2**: default. a little lighter on the CPU than Nuked-OPM. + - **Nuked-OPN2**: default core. a little lighter on the CPU than Nuked-OPM. - **ymfm**: same as ymfm above. - **SN76489 core**: - - **MAME**: default. less accurate than Nuked, but with lower CPU usage. comes from the MAME emulator project. + - **MAME**: default core. less accurate than Nuked, but with lower CPU usage. comes from the MAME emulator project. - **Nuked-PSG Mod**: more accurate, but not by that much. this originally started as an emulator for the YM7101 PSG sound generator, but was modified to emulate the SN7 as the MAME core was deemed unsatisfactory by some. - **NES core**: - - **puNES**: default. it comes from a dedicated NES emulator. + - **puNES**: default core. it comes from a dedicated NES emulator. - **NSFplay**: higher CPU usage than puNES. - **FDS core**: - - **puNES**: default. lower CPU usage and far less accurate. - - **NSFplay**: higher CPU usage and much more accurate. + - **puNES**: default playback core. lower CPU usage and far less accurate. + - **NSFplay**: default render core. higher CPU usage and much more accurate. - **SID core**: - - **reSID**: default. a high quality emulation core. somewhat CPU heavy. - - **reSIDfp**: improved version of reSID. the most accurate choice. _extremely_ CPU heavy. + - **reSID**: default playback core. a high quality emulation core. somewhat CPU heavy. + - **reSIDfp**: default render core. improved version of reSID. the most accurate choice. _extremely_ CPU heavy. - **dSID**: a lightweight open-source core used in DefleMask. not so accurate but it's very CPU light. - **POKEY core**: - **Atari800 (mzpokeysnd)**: does not emulate two-tone mode. - - **ASAP (C++ port)**: default. the sound core used in the ASAP player. most accurate option. + - **ASAP (C++ port)**: default core. the sound core used in the ASAP player. most accurate option. - **OPN/OPNA/OPNB cores**: - **ymfm only**: lower CPU usage, less accurate FM. - - **Nuked-OPN2 (FM) + ymfm (SSG/ADPCM)**: default. more accurate FM at the cost of more CPU load. + - **Nuked-OPN2 (FM) + ymfm (SSG/ADPCM)**: default cores. more accurate FM at the cost of more CPU load. diff --git a/doc/9-guides/envelope.md b/doc/9-guides/envelope.md new file mode 100644 index 000000000..42aa3dfa0 --- /dev/null +++ b/doc/9-guides/envelope.md @@ -0,0 +1,34 @@ +# AY-3-8910 / AY8930 / SAA1099 envelope guide + +The AY-3-8910 programmable sound generator, aside from normal 4-bit volume control, has an hardware volume envelope. This feature that allows for defining the shape of the volume envelope at arbitrary speed according to 8 preset envelope shapes. One may think, what is any upside of hardware envelope? Well, it's somewhat independent of tone/noise generators, and since it goes so high in frequency, it can be used melodically! This guide explains how to make best use of the AY/SAA envelope. + +## AY-3-8910 / AY8930 + +In the instrument editor: +- Add a single tick to the "Waveform" macro with only `envelope` turned on. This will disable any output, but don't worry. +- Add a single tick to the "Envelope" macro and select `enable`. + +If you play a note now, you will hear a very high-pitched squeak. This is because you must set envelope period, which is the frequency at which the hardware envelope runs. You can do it in two ways: +- `23xx` and `24xx` effects (envelope coarse and fine period); +- `29xx` auto-envelope period effect and macros. + +Auto-envelope works via numerator and denominator. In general, the higher the numerator, the higher the envelope pitch. The higher the denominator, the lower the envelope pitch. Why are there both of these? Because the envelope generator might be used to mask the tone output (i.e. affect the square wave as well). To do it, set the "Waveform" macro values to both `tone` and `envelope`. The higher the denominator value, then the lower the envelope pitch relative to the square wave output, and similarly with the numerator. With the square-and-envelope setting, a lot of wild, detuned synth instruments can be made. + +Back to the hardware envelope itself. Depending on the "Envelope" macro value, different envelope shapes can be obtained. The most basic one, 8, is a sawtooth wave. The `direction` value will invert the envelope, producing the reverse sawtooth. The `alternate` value produces an interesting pseudo-triangular wave, similiar to halved sine. That one can also be reversed. `Hold` option disables the envelope. + +_Warning:_ The envelope pitch resolution is fairly low; at high pitches it will be detuned. Because of this, it's used mostly for bass. + +_Warning_: There is only one hardware envelope generator. You can't use two pitches or two waveforms at once. + +## SAA1099 + +SAA envelope works a bit differently. It doesn't have its own pitch; instead, it relies on the channel 2/5 pitch. It also has many more parameters than the AY envelope. To use it: +- Go to waveform macro and add a single tick set to 0 (unless you want to have a square wave mask). +- Set up an envelope macro. Turn on `enabled`, `loop`, and depending on the desired shape, `cut` and `direction`. `Resolution` will give you higher pitch range than on the AY. +- Place two notes in the pattern editor. One in channel 2 will control the envelope pitch. The other in channel 3 can be any note you wish; it's just to enable the envelope output. + +## examples + +- [Demoscene-type Beat by Duccinator](https://www.youtube.com/watch?v=qcBgmpPrlUA) +- [Philips SAA1099 Test by Duccinator](https://www.youtube.com/watch?v=IBh2gr09zjs) +- [Touhou Kaikidan: Mystic Square title theme by ZUN](https://www.youtube.com/watch?v=tUKei7Pz0Fw): Rare instance of AY envelope used for drums, it can be used to mask the noise generator output too \ No newline at end of file diff --git a/extern/fmt b/extern/fmt index afbcf1e8e..e57ca2e36 160000 --- a/extern/fmt +++ b/extern/fmt @@ -1 +1 @@ -Subproject commit afbcf1e8eafc5d7f27e29c7397f22521eaa33fac +Subproject commit e57ca2e3685b160617d3d95fcd9e789c4e06ca88 diff --git a/extern/igfd/ImGuiFileDialog.cpp b/extern/igfd/ImGuiFileDialog.cpp index fbdd00f07..b5152d7c6 100644 --- a/extern/igfd/ImGuiFileDialog.cpp +++ b/extern/igfd/ImGuiFileDialog.cpp @@ -3880,6 +3880,7 @@ namespace IGFD float posY = ImGui::GetCursorPos().y; // height of last bar calc + ImGui::AlignTextToFramePadding(); if (!fdFile.puDLGDirectoryMode) ImGui::Text(fileNameString); else // directory chooser @@ -3913,8 +3914,9 @@ namespace IGFD prFileDialogInternal.puIsOk = true; res = true; } + ImGui::EndDisabled(); if (!(prFileDialogInternal.puCanWeContinue && notEmpty && fileValid==0)) { - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { if (!notEmpty) { if (prFileDialogInternal.puDLGflags&ImGuiFileDialogFlags_ConfirmOverwrite) { ImGui::SetTooltip("file name is empty"); @@ -3925,7 +3927,11 @@ namespace IGFD ImGui::SetTooltip("we can't continue - this is most likely a bug!"); } else switch (fileValid) { case 1: +#ifdef _WIN32 ImGui::SetTooltip("invalid characters in file name\nmake sure there aren't any of these:\n < > : \" / \\ | ? *"); +#else + ImGui::SetTooltip("invalid characters in file name\nmake sure there aren't any slashes (/)"); +#endif break; case 2: ImGui::SetTooltip("this file name is reserved by the system"); @@ -3939,7 +3945,6 @@ namespace IGFD } } } - ImGui::EndDisabled(); ImGui::SameLine(); diff --git a/extern/igfd/dirent/dirent.h b/extern/igfd/dirent/dirent.h index 7d5c8abec..dccfe5e8c 100644 --- a/extern/igfd/dirent/dirent.h +++ b/extern/igfd/dirent/dirent.h @@ -1114,11 +1114,20 @@ static int u8to16s(wchar_t* dest, const char* src, size_t limit) { int ch, p; char chs; p=0; - while (src[p]!=0 && ret=0x10000) { + ch-=0x10000; + if (ret+1>=limit-1) break; + dest[ret++]=(unsigned short)(0xd800|((ch>>10)&0x3ff)); + dest[ret++]=(unsigned short)(0xdc00|(ch&0x3ff)); + } else if (ch<0xd800 || ch>0xdfff) { + dest[ret++]=(unsigned short)ch; + } p+=chs; } + dest[ret]=0; return ret; } @@ -1176,19 +1185,34 @@ dirent_mbstowcs_s( static int u16to8s(char* dest, const wchar_t* src, size_t limit) { size_t ret=0; + unsigned int next=0; for (; (*src)!=0; src++) { - if ((*src)<0x80) { - if (ret+1>=limit-1) break; - dest[ret++]=(*src); - } else if ((*src)<0x800) { - if (ret+2>=limit-1) break; - dest[ret++]=(0xc0+(((*src)>>6)&31)); - dest[ret++]=(0x80+((*src)&63)); + if ((*src)>=0xd800 && (*src)<0xdc00) { + next=0x10000+(((*src)&0x3ff)<<10); + continue; + } else if ((*src)>=0xdc00 && (*src)<0xe000) { + next|=(*src)&0x3ff; } else { + next=(*src); + } + if (next<0x80) { + if (ret+1>=limit-1) break; + dest[ret++]=next; + } else if (next<0x800) { + if (ret+2>=limit-1) break; + dest[ret++]=(0xc0+((next>>6)&31)); + dest[ret++]=(0x80+(next&63)); + } else if (next<0x10000) { if (ret+3>=limit-1) break; - dest[ret++]=(0xe0+(((*src)>>12)&15)); - dest[ret++]=(0x80+(((*src)>>6)&63)); - dest[ret++]=(0x80+((*src)&63)); + dest[ret++]=(0xe0+((next>>12)&15)); + dest[ret++]=(0x80+((next>>6)&63)); + dest[ret++]=(0x80+(next&63)); + } else { + if (ret+4>=limit-1) break; + dest[ret++]=(0xf0+((next>>18)&7)); + dest[ret++]=(0x80+((next>>12)&63)); + dest[ret++]=(0x80+((next>>6)&63)); + dest[ret++]=(0x80+(next&63)); } } dest[ret]=0; diff --git a/extern/nfd-modified/src/nfd_win.cpp b/extern/nfd-modified/src/nfd_win.cpp index c60f7a753..90e28ec3c 100644 --- a/extern/nfd-modified/src/nfd_win.cpp +++ b/extern/nfd-modified/src/nfd_win.cpp @@ -61,7 +61,7 @@ class NFDWinEvents: public IFileDialogEvents { return ret; } - IFACEMETHODIMP OnFileOk(IFileDialog*) { return E_NOTIMPL; } + IFACEMETHODIMP OnFileOk(IFileDialog*) { return S_OK; } IFACEMETHODIMP OnFolderChange(IFileDialog*) { return E_NOTIMPL; } IFACEMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return E_NOTIMPL; } IFACEMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) { return E_NOTIMPL; } @@ -677,6 +677,21 @@ nfdresult_t NFD_SaveDialog( const std::vector& filterList, goto end; } + // Set a flag for no history + DWORD dwFlags; + result = fileSaveDialog->GetOptions(&dwFlags); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not get options."); + goto end; + } + result = fileSaveDialog->SetOptions(dwFlags | FOS_DONTADDTORECENT); + if ( !SUCCEEDED(result) ) + { + NFDi_SetError("Could not set options."); + goto end; + } + // Show the dialog. result = fileSaveDialog->Show(NULL); if ( SUCCEEDED(result) ) diff --git a/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp b/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp index 02aa34601..6f9e9b811 100644 --- a/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp +++ b/extern/vgsound_emu-modified/vgsound_emu/src/k007232/k007232.cpp @@ -67,7 +67,7 @@ void k007232_core::voice_t::tick(u8 ne) } } - m_out = s8(m_data) - 0x40; // send to output (ASD/BSD) pin + m_out = s8(m_data&0x7f) - 0x40; // send to output (ASD/BSD) pin } else { diff --git a/papers/clipboard-format.md b/papers/clipboard-format.md index d12af1cc2..cb353546c 100644 --- a/papers/clipboard-format.md +++ b/papers/clipboard-format.md @@ -6,7 +6,7 @@ when copying pattern data from Furnace, it's stored in the clipboard as plain te 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`. +this top line of text is always the same except for the number in parentheses, which is the internal build number. for example, 0.6pre9 is `169`. the second line is a number between 0 and 18 (decimal) which indicates which column the clip starts from. - `0`: note. diff --git a/papers/format.md b/papers/format.md index 4a5e6e900..66bec724e 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,8 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 169: Furnace 0.6pre9 +- 166: Furnace 0.6pre8 - 162: Furnace 0.6pre7 - 161: Furnace 0.6pre6 - 158: Furnace 0.6pre5 @@ -220,7 +222,7 @@ size | description | - 0xcc: K053260 - 4 channels | - 0xcd: TED - 2 channels | - 0xce: Namco C140 - 24 channels - | - 0xcf: Namco C219 - 16 channels (UNAVAILABLE) + | - 0xcf: Namco C219 - 16 channels | - 0xd0: Namco C352 - 32 channels (UNAVAILABLE) | - 0xde: YM2610B extended - 19 channels | - 0xe0: QSound - 19 channels @@ -347,7 +349,8 @@ size | description --- | **a couple more compat flags** (>=138) 1 | broken portamento during legato 1 | broken macro during note off in some FM chips (>=155) - 6 | reserved + 1 | pre note (C64) does not compensate for portamento or legato (>=168) + 5 | reserved --- | **speed pattern of first song** (>=139) 1 | length of speed pattern (fail if this is lower than 0 or higher than 16) 16 | speed pattern (this overrides speed 1 and speed 2 settings) diff --git a/papers/newIns.md b/papers/newIns.md index 4ef3be31d..27a505c13 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -120,6 +120,7 @@ the following instrument types are available: - 50: K053260 - 52: TED - 53: C140 +- 54: C219 the following feature codes are recognized: diff --git a/res/Info.plist b/res/Info.plist index 2bb0c814e..a7e16ca73 100644 --- a/res/Info.plist +++ b/res/Info.plist @@ -15,17 +15,17 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - 0.6pre7 + 0.6pre9 CFBundleName Furnace CFBundlePackageType APPL CFBundleShortVersionString - 0.6pre7 + 0.6pre9 CFBundleSignature ???? CFBundleVersion - 0.6pre7 + 0.6pre9 NSHumanReadableCopyright NSHighResolutionCapable diff --git a/res/icons.sfd b/res/icons.sfd index 310090e28..c1e45f2b0 100644 --- a/res/icons.sfd +++ b/res/icons.sfd @@ -21,7 +21,7 @@ OS2Version: 0 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 0 CreationTime: 1691897631 -ModificationTime: 1693202829 +ModificationTime: 1692347465 PfmFamily: 81 TTFWeight: 400 TTFWidth: 5 @@ -47,13 +47,13 @@ LangName: 1033 Encoding: UnicodeBmp UnicodeInterp: none NameList: AGL For New Fonts -DisplaySize: -48 +DisplaySize: -24 AntiAlias: 1 FitToEm: 0 WinInfo: 57568 16 10 BeginPrivate: 0 EndPrivate -BeginChars: 65536 73 +BeginChars: 65536 72 StartChar: space Encoding: 32 32 0 @@ -71,23 +71,6 @@ HStem: 171.516 95.9375<754.864 980.648 1382.09 1612.77> 449.875 95.0781<141.391 VStem: 32.9531 108.438<183 449.875 544.953 758.078> 401.547 114.297<567.194 735.759> 648.969 107.5<611.387 747.68> 1008.97 107.5<294.565 441.758> 1203.19 116.172<330.958 704.848> 1663.97 95.0781<183 284.797 316.503 446.984> DStem2: 863.031 584.25 844.75 481.594 0.978916 -0.204262<-84.378 149.631> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 95.9375<754.864 980.648 1382.09 1612.77> 449.875 95.0781<141.391 377.778 1516.16 1654.36> 768.625 95.9375<141.391 377.778 780.433 998.844 1381.56 1608.87> -VStem: 32.9531 108.438<183 449.875 544.953 758.078> 401.547 114.297<567.194 735.759> 648.969 107.5<611.387 747.68> 1008.97 107.5<294.565 441.758> 1203.19 116.172<330.958 704.848> 1663.97 95.0781<183 284.797 316.503 446.984> -DStem2: 863.031 584.25 844.75 481.594 0.978916 -0.204262<-84.378 149.631> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 32.953125 183 m 1 @@ -187,23 +170,6 @@ HStem: 171.516 90.2344<203.228 410.876> 453.703 90.2344<815.531 1024.71> 762.844 VStem: 46.8594 109.453<309.775 726.303> 457.719 109.453<309.775 726.303> 713.734 101.797<183 453.703 543.938 762.844> 1043.97 108.516<563.279 743.506> 1273.73 117.109<777.653 853.078> 1273.73 97.9688<183 708.051> 1627.02 118.125<183 258.425> 1647.17 97.9688<328.027 853.078> DStem2: 1590.53 450.812 1376.47 710.031 0.377481 -0.926017<-320.846 135.117> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 90.2344<203.228 410.876> 453.703 90.2344<815.531 1024.71> 762.844 90.2344<194.777 419.326 815.531 1024.71> -VStem: 46.8594 109.453<309.775 726.303> 457.719 109.453<309.775 726.303> 713.734 101.797<183 453.703 543.938 762.844> 1043.97 108.516<563.279 743.506> 1273.73 117.109<777.653 853.078> 1273.73 97.9688<183 708.051> 1627.02 118.125<183 258.425> 1647.17 97.9688<328.027 853.078> -DStem2: 1590.53 450.812 1376.47 710.031 0.377481 -0.926017<-320.846 135.117> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 307.015625 171.515625 m 256xfe @@ -281,22 +247,6 @@ Flags: W HStem: 84.8447 121.191<399.409 663.663> 99.2002 116.406<1138.19 1452.86> 429.181 116.406<556.547 729.398> 470.001 112.793<1138.19 1425.21> 820.392 116.406<1138.19 1425.21> 829.962 121.191<400.057 661.626> VStem: 165.336 145.312<297.614 737.606> 741.312 118.945<99.2002 226.446 277.934 429.181> 1002.64 135.547<215.606 470.001 582.794 820.392> 1453.81 142.773<609.386 793.799> 1483.7 142.969<244.11 441.498> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 84.8447 121.191<399.409 663.663> 99.2002 116.406<1138.19 1452.86> 429.181 116.406<556.547 729.398> 470.001 112.793<1138.19 1425.21> 820.392 116.406<1138.19 1425.21> 829.962 121.191<400.057 661.626> -VStem: 165.336 145.312<297.614 737.606> 741.312 118.945<99.2002 226.446 277.934 429.181> 1002.64 135.547<215.606 470.001 582.794 820.392> 1453.81 142.773<609.386 793.799> 1483.7 142.969<244.11 441.498> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 741.3125 226.446289062 m 1x6380 @@ -381,23 +331,6 @@ HStem: 171.516 96.9531<226.177 441.873 832.752 1027.57> 313.547 85.4688<1326.08 VStem: 53.1094 115.156<330.807 708.111> 694.047 112.344<291.954 486.784> 1054.05 111.406<291.954 486.784> 1544.91 102.734<183 313.547 399.016 754.172> DStem2: 1233.89 406.672 1326.08 399.016 0.512745 0.858541<40.6955 454.37> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 96.9531<226.177 441.873 832.752 1027.57> 313.547 85.4688<1326.08 1544.91 1647.64 1738.89> 519.016 87.3438<857.168 1024.42> 754.172 98.9062<1514.99 1544.91> 767.609 96.9531<226.122 440.941> -VStem: 53.1094 115.156<330.807 708.111> 694.047 112.344<291.954 486.784> 1054.05 111.406<291.954 486.784> 1544.91 102.734<183 313.547 399.016 754.172> -DStem2: 1233.89 406.672 1326.08 399.016 0.512745 0.858541<40.6955 454.37> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 334.359375 171.515625 m 0xef80 @@ -488,20 +421,6 @@ HStem: -247.516 89.2969<837.797 1081.62 1317.8 1604.83> 23.1875 90.2344<277.797 VStem: 95.6875 101.719<1044.03 1191.27> 176 101.797<-247.516 23.1875 113.422 332.328> 420.219 101.719<716.929 880.209> 506.234 108.516<132.763 312.99> 544.906 99.8438<618.5 718.344> 736 101.797<-158.219 422.562> 974.125 102.656<618.5 721.156> 1158.66 97.9688<618.5 1141.9> 1216 101.797<-158.219 49.125 137.406 333.266> 1618.5 97.9688<618.5 1143.75> DStem2: 289.594 1016.94 271.312 920.922 0.978371 -0.206857<-75.1218 135.909> 544.906 618.5 644.75 618.5 0.286825 0.957983<28.6377 221.043 308.22 625.862> 875.219 1288.58 835.844 1098.5 0.288055 -0.957614<72.4214 390.859 477.766 670.167> 1278.66 1288.58 1261.47 1143.66 0.416776 -0.909009<124.572 396.023> 1442.88 921.859 1613.81 1145.53 0.379583 0.925158<0 271.817> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 176 -247.515625 m 1xdc2b20 @@ -622,22 +541,6 @@ Flags: W HStem: 183 96.0156<814.669 1050.52 1429.91 1750.53> 449.875 95.0781<149.906 386.215> 474.875 95.9375<1429.91 1720.84> 757.062 96.0156<149.906 386.215 813.763 1048.56 1429.91 1750.53> VStem: 41.4688 108.438<183 449.875 544.953 758.078> 410.062 114.219<567.194 735.759> 651.625 115.156<330.807 708.111> 1321.47 108.438<279.016 474.875 570.812 757.062> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<814.669 1050.52 1429.91 1750.53> 449.875 95.0781<149.906 386.215> 474.875 95.9375<1429.91 1720.84> 757.062 96.0156<149.906 386.215 813.763 1048.56 1429.91 1750.53> -VStem: 41.4688 108.438<183 449.875 544.953 758.078> 410.062 114.219<567.194 735.759> 651.625 115.156<330.807 708.111> 1321.47 108.438<279.016 474.875 570.812 757.062> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 41.46875 183 m 1xdf @@ -706,23 +609,6 @@ HStem: 325.958 116.406<389.164 636.43> 811.993 124.805<499.082 527.573> VStem: 145.609 137.891<99.2002 237.091> 745.609 141.602<99.2002 240.802> 1220.41 135.547<99.2002 492.633> DStem2: 145.609 99.2002 283.5 99.2002 0.303392 0.952866<41.8349 280.126 400.882 789.887> 601.664 936.798 516.312 811.993 0.306233 -0.951957<92.6712 481.326 602.427 841.437> 1087.21 936.798 932.328 936.798 0.479431 -0.877579<0 425.309> 1294.83 563.556 1355.96 431.622 0.477305 0.878738<0 424.748> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 325.958 116.406<389.164 636.43> 811.993 124.805<499.082 527.573> -VStem: 145.609 137.891<99.2002 237.091> 745.609 141.602<99.2002 240.802> 1220.41 135.547<99.2002 492.633> -DStem2: 145.609 99.2002 283.5 99.2002 0.303392 0.952866<41.8349 280.126 400.882 789.887> 601.664 936.798 516.312 811.993 0.306233 -0.951957<92.6712 481.326 602.427 841.437> 1087.21 936.798 932.328 936.798 0.479431 -0.877579<0 425.309> 1294.83 563.556 1355.96 431.622 0.477305 0.878738<0 424.748> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 745.609375 99.2001953125 m 1 @@ -761,22 +647,6 @@ Flags: W HStem: -253.33 91.1719<486.344 688.342 1095.48 1270.78> 60.5762 92.1094<518.508 677.882> 348.545 91.1719<497.902 685.553 1095.48 1270.78> 612.686 87.3438<530.171 727.317> 870.889 87.3438<1092.63 1259.92> 930.42 83.5156<544.742 712.82> 1218.39 87.3438<537.628 719.903 1093.28 1280.94> VStem: 388.742 113.281<728.719 901.73> 408.898 105.625<1038.68 1193.65> 708.586 114.219<179.923 323.321> 722.023 112.344<-131.94 32.8528> 743.039 105.547<1038.68 1193.65> 755.461 113.281<728.719 901.73> 940.305 115.156<-121.3 307.598 991.115 1184.56> 1310.85 115.156<-122.103 308.491 990.464 1185.29> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 91.1719<486.344 688.342 1095.48 1270.78> 60.5762 92.1094<518.508 677.882> 348.545 91.1719<497.902 685.553 1095.48 1270.78> 612.686 87.3438<530.171 727.317> 870.889 87.3438<1092.63 1259.92> 930.42 83.5156<544.742 712.82> 1218.39 87.3438<537.628 719.903 1093.28 1280.94> -VStem: 388.742 113.281<728.719 901.73> 408.898 105.625<1038.68 1193.65> 708.586 114.219<179.923 323.321> 722.023 112.344<-131.94 32.8528> 743.039 105.547<1038.68 1193.65> 755.461 113.281<728.719 901.73> 940.305 115.156<-121.3 307.598 991.115 1184.56> 1310.85 115.156<-122.103 308.491 990.464 1185.29> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 586.6328125 152.685546875 m 1xf226 @@ -957,23 +827,6 @@ HStem: 183 88.2812<711 802.25 910.688 1002.88> 364.406 93.125<1273.34 1471> 757. VStem: 320.062 108.438<183 757.062> 711 291.875<183 271.281 764.797 853.078> 1078.34 110.469<183 293.469> 1558.34 113.281<183 296.281> DStem2: 1078.34 183 1188.81 183 0.303155 0.952941<33.4892 224.122 320.727 631.883> 1443.19 853.078 1375.06 753.234 0.305997 -0.952033<74.2085 385.084> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 88.2812<711 802.25 910.688 1002.88> 364.406 93.125<1273.34 1471> 757.062 96.0156<120.375 320.062 428.5 628.188 711 802.25 910.688 1002.88 1359.62 1385.56> -VStem: 320.062 108.438<183 757.062> 711 291.875<183 271.281 764.797 853.078> 1078.34 110.469<183 293.469> 1558.34 113.281<183 296.281> -DStem2: 1078.34 183 1188.81 183 0.303155 0.952941<33.4892 224.122 320.727 631.883> 1443.19 853.078 1375.06 753.234 0.305997 -0.952033<74.2085 385.084> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 428.5 757.0625 m 1 @@ -1024,23 +877,6 @@ HStem: 171.516 95.9375<134.083 359.867> 364.406 93.125<745.609 943.344 1385.61 1 VStem: 28.1875 107.5<611.387 747.68> 388.188 107.5<294.565 441.758> 550.688 110.391<183 293.391> 1030.69 113.281<183 296.281> 1190.69 110.391<183 293.391> 1670.69 113.281<183 296.281> DStem2: 242.25 584.25 223.969 481.594 0.978916 -0.204262<-84.378 149.631> 550.688 183 661.078 183 0.322775 0.946476<35.6313 226.241 322.753 322.753> 915.531 853.078 847.328 753.234 0.306115 -0.951995<74.1727 385.072 481.954 673.162> 1190.69 183 1301.08 183 0.322775 0.946476<35.6313 226.241 322.753 322.753> 1555.53 853.078 1487.33 753.234 0.306115 -0.951995<74.1727 385.072 481.954 673.162> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 95.9375<134.083 359.867> 364.406 93.125<745.609 943.344 1385.61 1583.34> 753.234 99.8438<830.443 859.33 1470.44 1499.33> 768.625 95.9375<159.651 378.063> -VStem: 28.1875 107.5<611.387 747.68> 388.188 107.5<294.565 441.758> 550.688 110.391<183 293.391> 1030.69 113.281<183 296.281> 1190.69 110.391<183 293.391> 1670.69 113.281<183 296.281> -DStem2: 242.25 584.25 223.969 481.594 0.978916 -0.204262<-84.378 149.631> 550.688 183 661.078 183 0.322775 0.946476<35.6313 226.241 322.753 322.753> 915.531 853.078 847.328 753.234 0.306115 -0.951995<74.1727 385.072 481.954 673.162> 1190.69 183 1301.08 183 0.322775 0.946476<35.6313 226.241 322.753 322.753> 1555.53 853.078 1487.33 753.234 0.306115 -0.951995<74.1727 385.072 481.954 673.162> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 252.796875 171.515625 m 0xdfc0 @@ -1116,23 +952,6 @@ HStem: 183 88.2812<773.109 864.281 972.797 1064.98 1342.08 1563.11> 764.797 88.2 VStem: 96.625 112.344<740.734 853.078> 555.531 109.453<743.625 853.078> 773.109 291.875<183 271.281 764.797 853.078> 1172.17 115.156<330.807 708.111> DStem2: 208.969 853.078 96.625 853.078 0.311738 -0.950168<0 589.589> 383.656 288.625 442.25 183 0.291293 0.956634<0 590.041> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 88.2812<773.109 864.281 972.797 1064.98 1342.08 1563.11> 764.797 88.2812<773.109 864.281 972.797 1064.98 1342.01 1562.58> -VStem: 96.625 112.344<740.734 853.078> 555.531 109.453<743.625 853.078> 773.109 291.875<183 271.281 764.797 853.078> 1172.17 115.156<330.807 708.111> -DStem2: 208.969 853.078 96.625 853.078 0.311738 -0.950168<0 589.589> 383.656 288.625 442.25 183 0.291293 0.956634<0 590.041> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 316.46875 183 m 1 @@ -1192,22 +1011,6 @@ Flags: W HStem: 183 96.0156<820.297 1141> 449.875 95.0781<180.297 416.684> 474.875 95.9375<820.297 1111.23> 757.062 96.0156<180.297 416.684 820.297 1141 1212.33 1412.02 1520.45 1720.14> VStem: 71.8594 108.438<183 449.875 544.953 758.078> 440.453 114.297<567.194 735.759> 711.859 108.438<279.016 474.875 570.812 757.062> 1412.02 108.438<183 757.062> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<820.297 1141> 449.875 95.0781<180.297 416.684> 474.875 95.9375<820.297 1111.23> 757.062 96.0156<180.297 416.684 820.297 1141 1212.33 1412.02 1520.45 1720.14> -VStem: 71.8594 108.438<183 449.875 544.953 758.078> 440.453 114.297<567.194 735.759> 711.859 108.438<279.016 474.875 570.812 757.062> 1412.02 108.438<183 757.062> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 71.859375 183 m 1xdf @@ -1263,23 +1066,6 @@ HStem: -253.33 85.3906<803.27 978.187> 95.1074 85.4688<828.18 977.718> 612.686 8 VStem: 82.0938 106.562<1187.69 1294.25> 493.891 104.688<1189.56 1294.25> 674.359 107.5<-147.67 75.4575> 700.609 101.797<624.17 897.764 983.232 1204.95> 998.891 107.5<-147.386 74.3151> 1030.84 108.516<1002.5 1185.69> 1233.73 109.453<750.416 1168> DStem2: 188.656 1294.25 82.0938 1294.25 0.271727 -0.962374<0 593.586> 375.844 872.842 402.719 624.17 0.269742 0.962933<-155.735 437.628> 1024.12 905.42 922.406 897.764 0.413517 -0.910496<0 262.054> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 85.3906<803.27 978.187> 95.1074 85.4688<828.18 977.718> 612.686 89.2188<1388.21 1579.14> 624.17 92.1875<328.559 354.926> 897.764 85.4688<802.406 938.743> 1204.95 89.2969<802.406 1011.58 1380.73 1582.23> -VStem: 82.0938 106.562<1187.69 1294.25> 493.891 104.688<1189.56 1294.25> 674.359 107.5<-147.67 75.4575> 700.609 101.797<624.17 897.764 983.232 1204.95> 998.891 107.5<-147.386 74.3151> 1030.84 108.516<1002.5 1185.69> 1233.73 109.453<750.416 1168> -DStem2: 188.656 1294.25 82.0938 1294.25 0.271727 -0.962374<0 593.586> 375.844 872.842 402.719 624.17 0.269742 0.962933<-155.735 437.628> 1024.12 905.42 922.406 897.764 0.413517 -0.910496<0 262.054> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 890.296875 -253.330078125 m 0xcfa8 @@ -1376,22 +1162,6 @@ Flags: W HStem: -247.516 96.0156<568.266 840.922 1048.27 1320.92> 607.016 96.9531<456.756 680.46> 885.375 95.0781<1137.88 1374.26> 1203.11 96.9531<456.756 680.46 1137.88 1374.26> VStem: 279.672 116.172<767.663 1139.42> 459.828 108.438<-151.5 422.562> 741.391 116.172<767.663 1139.42> 939.828 108.438<-151.5 422.562> 1029.44 108.438<618.5 885.375 980.453 1193.58> 1398.03 114.297<1002.69 1171.26> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -247.516 96.0156<568.266 840.922 1048.27 1320.92> 607.016 96.9531<456.756 680.46> 885.375 95.0781<1137.88 1374.26> 1203.11 96.9531<456.756 680.46 1137.88 1374.26> -VStem: 279.672 116.172<767.663 1139.42> 459.828 108.438<-151.5 422.562> 741.391 116.172<767.663 1139.42> 939.828 108.438<-151.5 422.562> 1029.44 108.438<618.5 885.375 980.453 1193.58> 1398.03 114.297<1002.69 1171.26> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 459.828125 -247.515625 m 1xfe40 @@ -1474,22 +1244,6 @@ Flags: W HStem: 183 96.0156<177.043 421.987 1508.81 1781.47> 449.875 95.0781<868.812 1105.12> 758.078 95<177.765 421.265 868.812 1105.12> VStem: 10.5312 116.25<332.163 703.916> 472.25 116.25<332.163 703.916> 760.375 108.438<183 449.875 544.953 758.078> 1128.97 114.219<567.194 735.759> 1400.38 108.438<279.016 853.078> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<177.043 421.987 1508.81 1781.47> 449.875 95.0781<868.812 1105.12> 758.078 95<177.765 421.265 868.812 1105.12> -VStem: 10.5312 116.25<332.163 703.916> 472.25 116.25<332.163 703.916> 760.375 108.438<183 449.875 544.953 758.078> 1128.97 114.219<567.194 735.759> 1400.38 108.438<279.016 853.078> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 299.59375 171.515625 m 256 @@ -1566,23 +1320,6 @@ HStem: 183 96.0156<742.719 983.085 1340.88 1585.94> 474.875 95.9375<182.719 458. VStem: 74.2812 108.438<183 474.875 570.812 757.062> 634.281 108.438<279.016 757.062> 1038.34 116.25<334.419 701.659> 1250.22 107.5<611.387 747.68> 1610.22 107.5<294.565 441.758> DStem2: 1464.28 584.25 1446 481.594 0.978916 -0.204262<-84.3745 149.704> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<742.719 983.085 1340.88 1585.94> 474.875 95.9375<182.719 458.188 1468.24 1586.52> 757.062 96.0156<182.719 492.719 742.719 983.085 1378.58 1614.18> -VStem: 74.2812 108.438<183 474.875 570.812 757.062> 634.281 108.438<279.016 757.062> 1038.34 116.25<334.419 701.659> 1250.22 107.5<611.387 747.68> 1610.22 107.5<294.565 441.758> -DStem2: 1464.28 584.25 1446 481.594 0.978916 -0.204262<-84.3745 149.704> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 74.28125 183 m 1 @@ -1662,23 +1399,6 @@ HStem: 99.2002 116.406<1160.36 1475.04> 470.001 112.793<1160.36 1447.48> 820.392 VStem: 143.168 140.43<796.368 936.798> 716.801 136.816<799.981 936.798> 1024.81 135.547<215.606 470.001 582.794 820.392> 1475.98 142.773<609.386 793.799> 1505.96 142.871<244.11 441.498> DStem2: 283.598 936.798 143.168 936.798 0.311738 -0.950168<0 736.986> 501.957 231.231 575.199 99.2002 0.291293 0.956634<0 737.551> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 99.2002 116.406<1160.36 1475.04> 470.001 112.793<1160.36 1447.48> 820.392 116.406<1160.36 1447.48> -VStem: 143.168 140.43<796.368 936.798> 716.801 136.816<799.981 936.798> 1024.81 135.547<215.606 470.001 582.794 820.392> 1475.98 142.773<609.386 793.799> 1505.96 142.871<244.11 441.498> -DStem2: 283.598 936.798 143.168 936.798 0.311738 -0.950168<0 736.986> 501.957 231.231 575.199 99.2002 0.291293 0.956634<0 737.551> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 417.97265625 99.2001953125 m 1xfc @@ -1741,23 +1461,6 @@ HStem: -247.66 88.2812<529.736 717.81 1048.08 1247.08> 66.2461 92.1094<1077.25 1 VStem: 306.078 103.672<629.84 1142.5> 387.641 112.344<-127.222 67.6086> 722.719 103.672<787.262 1299.92> 747.641 111.406<-127.222 67.6086> 1216.16 106.562<720.074 1221.17> 1267.33 114.219<185.593 328.991> 1280.77 112.344<-126.27 38.5227> DStem2: 645.922 929.371 486.547 1000.39 0.508638 -0.860981<-299.653 157.446> 986.703 1114.61 1052.95 1055.15 0.683543 0.72991<1.41729 229.335> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -247.66 88.2812<529.736 717.81 1048.08 1247.08> 66.2461 92.1094<1077.25 1236.62> 99.8398 87.3438<550.762 718.015> 354.215 91.1719<1056.64 1244.29> 629.84 90.2344<1027.95 1216.16 1322.72 1485.92> 1221.17 78.75<1171.98 1216.16> -VStem: 306.078 103.672<629.84 1142.5> 387.641 112.344<-127.222 67.6086> 722.719 103.672<787.262 1299.92> 747.641 111.406<-127.222 67.6086> 1216.16 106.562<720.074 1221.17> 1267.33 114.219<185.593 328.991> 1280.77 112.344<-126.27 38.5227> -DStem2: 645.922 929.371 486.547 1000.39 0.508638 -0.860981<-299.653 157.446> 986.703 1114.61 1052.95 1055.15 0.683543 0.72991<1.41729 229.335> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 623.8125 -247.66015625 m 0xbd40 @@ -1885,23 +1588,6 @@ HStem: 171.516 96.9531<151.634 379.752 774.678 990.363 1414.68 1630.36> 767.609 VStem: 47.4062 107.5<611.387 747.68> 407.406 107.5<294.565 441.758> 601.625 115.156<330.807 708.111> 1241.62 115.156<330.807 708.111> DStem2: 261.469 584.25 243.188 481.594 0.978916 -0.204262<-84.3815 149.558> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 96.9531<151.634 379.752 774.678 990.363 1414.68 1630.36> 767.609 96.9531<178.808 399.181 774.597 989.432 1414.6 1629.43> -VStem: 47.4062 107.5<611.387 747.68> 407.406 107.5<294.565 441.758> 601.625 115.156<330.807 708.111> 1241.62 115.156<330.807 708.111> -DStem2: 261.469 584.25 243.188 481.594 0.978916 -0.204262<-84.3815 149.558> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 271.9375 171.515625 m 0 @@ -1993,23 +1679,6 @@ HStem: 183 89.2969<228.172 451.245 1380.3 1712.48> 453.703 90.2344<848.188 1057. VStem: 79.5156 109.453<309.775 726.303> 490.375 109.453<309.775 726.303> 746.391 101.797<183 453.703 543.938 762.844> 1076.62 108.516<563.279 743.506> DStem2: 1265.14 274.172 1380.3 272.297 0.548962 0.835847<61.6492 585.764> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 89.2969<228.172 451.245 1380.3 1712.48> 453.703 90.2344<848.188 1057.36> 763.781 89.2969<228.172 451.245 848.188 1057.36 1280.45 1586.7> -VStem: 79.5156 109.453<309.775 726.303> 490.375 109.453<309.775 726.303> 746.391 101.797<183 453.703 543.938 762.844> 1076.62 108.516<563.279 743.506> -DStem2: 1265.14 274.172 1380.3 272.297 0.548962 0.835847<61.6492 585.764> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 339.671875 171.515625 m 256 @@ -2082,23 +1751,6 @@ HStem: -247.516 96.0156<794.758 1115.46> 44.3594 95.9375<794.758 1085.7> 326.547 VStem: 46.3203 108.438<-247.516 4.38833 82.7188 422.562> 307.492 108.438<618.5 885.375 980.453 1193.58> 435.07 126.719<295.844 422.562> 450.461 130.547<-247.516 -116.969> 686.32 108.438<-151.5 44.3594 140.297 326.547 1002.69 1171.26> 917.727 116.172<767.663 1139.42> 1379.45 116.172<767.662 1139.42> 1404.68 108.516<-247.516 79.9207> DStem2: 158.586 82.7188 246.945 65.4531 0.660468 0.750854<0 45.3946 144.153 437.782> 322.805 140.297 246.945 65.4531 0.545149 -0.838339<21.3897 394.71> 1298.12 422.562 1174.29 422.562 0.479608 -0.877483<0 340.284> 1464.21 123.969 1513.2 18.4219 0.477483 0.878641<0 339.836> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -247.516 96.0156<794.758 1115.46> 44.3594 95.9375<794.758 1085.7> 326.547 96.0156<794.758 1115.46> 607.016 96.9531<1094.81 1318.51> 885.375 95.0781<415.93 652.317> 1193.58 95<415.93 652.317 1084.89 1328.46> -VStem: 46.3203 108.438<-247.516 4.38833 82.7188 422.562> 307.492 108.438<618.5 885.375 980.453 1193.58> 435.07 126.719<295.844 422.562> 450.461 130.547<-247.516 -116.969> 686.32 108.438<-151.5 44.3594 140.297 326.547 1002.69 1171.26> 917.727 116.172<767.663 1139.42> 1379.45 116.172<767.662 1139.42> 1404.68 108.516<-247.516 79.9207> -DStem2: 158.586 82.7188 246.945 65.4531 0.660468 0.750854<0 45.3946 144.153 437.782> 322.805 140.297 246.945 65.4531 0.545149 -0.838339<21.3897 394.71> 1298.12 422.562 1174.29 422.562 0.479608 -0.877483<0 340.284> 1464.21 123.969 1513.2 18.4219 0.477483 0.878641<0 339.836> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 246.9453125 65.453125 m 1xff70 @@ -2206,33 +1858,6 @@ Flags: W HStem: 15.5 139.688<684.242 1061.86> 460.461 135.352<684.242 1028.79> 880.93 139.688<684.242 1028.79> VStem: 521.586 162.656<155.188 460.461 595.812 880.93> 1062.99 171.328<627.723 849.019> 1098.97 171.445<189.391 426.257> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1687 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet -0 15.5 m 5 -NamedP: "1-char" - 1792 15.5 l 1029 -0 1020.6171875 m 5 -NamedP: "1-char" - 1792 1020.6171875 l 1029 -EndSplineSet -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 521.5859375 1020.6171875 m 5xf4 @@ -2284,23 +1909,6 @@ HStem: -66.1094 93.125<474.359 672.172> 322.719 99.8438<559.262 588.09> 607.016 VStem: 222.406 107.5<1046.89 1183.18> 279.516 110.312<-247.516 -137.203> 582.406 107.5<730.065 877.258> 746.859 110.391<1178.19 1288.58> 759.516 113.281<-247.516 -134.234> 980.922 103.75<-247.516 265.141> 1397.64 103.594<-90.0938 422.562> 1483.19 106.562<1182.02 1288.58> DStem2: 279.516 -247.516 389.828 -247.516 0.303392 0.952866<33.468 224.101 320.706 631.909> 436.469 1019.75 418.188 917.094 0.978916 -0.204262<-84.378 149.631> 644.359 422.562 576.078 322.719 0.306233 -0.951957<74.137 385.061 481.942 673.15> 857.25 1288.58 746.859 1288.58 0.206752 -0.978393<0 557.355> 975.297 743.266 1027.17 618.5 0.24367 0.969858<0 458.809> 1320.77 52.0156 1161.39 123.031 0.508638 -0.860981<-299.653 157.446> 1229.75 1288.58 1167.33 1168.58 0.238997 -0.97102<101.604 559.948> 1364.12 744.281 1424.59 618.5 0.213693 0.976901<0 557.167> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -66.1094 93.125<474.359 672.172> 322.719 99.8438<559.262 588.09> 607.016 95.9375<328.301 554.086> 618.5 124.766<964.387 984.548 1352.16 1364.12> 1204.12 95.9375<353.87 572.282> -VStem: 222.406 107.5<1046.89 1183.18> 279.516 110.312<-247.516 -137.203> 582.406 107.5<730.065 877.258> 746.859 110.391<1178.19 1288.58> 759.516 113.281<-247.516 -134.234> 980.922 103.75<-247.516 265.141> 1397.64 103.594<-90.0938 422.562> 1483.19 106.562<1182.02 1288.58> -DStem2: 279.516 -247.516 389.828 -247.516 0.303392 0.952866<33.468 224.101 320.706 631.909> 436.469 1019.75 418.188 917.094 0.978916 -0.204262<-84.378 149.631> 644.359 422.562 576.078 322.719 0.306233 -0.951957<74.137 385.061 481.942 673.15> 857.25 1288.58 746.859 1288.58 0.206752 -0.978393<0 557.355> 975.297 743.266 1027.17 618.5 0.24367 0.969858<0 458.809> 1320.77 52.0156 1161.39 123.031 0.508638 -0.860981<-299.653 157.446> 1229.75 1288.58 1167.33 1168.58 0.238997 -0.97102<101.604 559.948> 1364.12 744.281 1424.59 618.5 0.213693 0.976901<0 557.167> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 759.515625 -247.515625 m 1xcb60 @@ -2400,23 +2008,6 @@ HStem: 624.17 96.0156<520.383 793.039> VStem: 280.539 103.75<-241.846 270.811> 411.945 108.438<720.186 1294.25> 697.258 103.594<-84.4238 428.232> 938.195 120<-241.846 -121.846> 945.852 127.656<300.576 428.232> 1050.3 108.516<624.17 951.606> 1383.66 127.656<-241.846 -114.189 300.576 428.232> DStem2: 620.383 57.6855 461.008 128.701 0.508638 -0.860981<-299.653 157.446> 943.742 1294.25 819.914 1294.25 0.479608 -0.877483<0 340.284> 938.195 -241.846 1058.2 -241.846 0.552681 0.833393<66.3217 372.475 510.607 804.036> 1073.51 428.232 945.852 428.232 0.546973 -0.83715<0 292.459 418.391 730.603> 1109.84 995.654 1158.82 890.107 0.477483 0.878641<0 339.836> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 624.17 96.0156<520.383 793.039> -VStem: 280.539 103.75<-241.846 270.811> 411.945 108.438<720.186 1294.25> 697.258 103.594<-84.4238 428.232> 938.195 120<-241.846 -121.846> 945.852 127.656<300.576 428.232> 1050.3 108.516<624.17 951.606> 1383.66 127.656<-241.846 -114.189 300.576 428.232> -DStem2: 620.383 57.6855 461.008 128.701 0.508638 -0.860981<-299.653 157.446> 943.742 1294.25 819.914 1294.25 0.479608 -0.877483<0 340.284> 938.195 -241.846 1058.2 -241.846 0.552681 0.833393<66.3217 372.475 510.607 804.036> 1073.51 428.232 945.852 428.232 0.546973 -0.83715<0 292.459 418.391 730.603> 1109.84 995.654 1158.82 890.107 0.477483 0.878641<0 339.836> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 461.0078125 128.701171875 m 1xf1 @@ -2479,23 +2070,6 @@ HStem: -60.4395 93.125<1083.51 1281.16> 28.8574 91.25<418.508 570.842> 333.232 9 VStem: 310.07 108.438<-241.846 28.8574 120.107 333.232> 334.367 112.344<1181.9 1294.25> 678.664 114.219<142.348 310.913> 793.273 109.375<1184.87 1294.25> 888.508 110.469<-241.846 -131.377> 1039.68 108.438<720.186 916.045 1011.98 1198.23> 1368.51 113.281<-241.846 -128.564> DStem2: 446.711 1294.25 334.367 1294.25 0.289596 -0.957149<0 589.723> 662.258 40.4199 551.945 28.8574 0.456936 -0.8895<0 262.07> 621.398 729.795 679.992 624.17 0.291293 0.956634<0 590.041> 888.508 -241.846 998.977 -241.846 0.303155 0.952941<33.4892 224.122 320.727 631.883> 1253.35 428.232 1185.23 328.389 0.305997 -0.952033<74.2085 385.084> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -60.4395 93.125<1083.51 1281.16> 28.8574 91.25<418.508 570.842> 333.232 95<418.508 654.817 1169.79 1195.72> 624.17 96.0156<609.465 629.562 1148.12 1468.74> 916.045 95.9375<1148.12 1439.05> 1198.23 96.0156<1148.12 1468.74> -VStem: 310.07 108.438<-241.846 28.8574 120.107 333.232> 334.367 112.344<1181.9 1294.25> 678.664 114.219<142.348 310.913> 793.273 109.375<1184.87 1294.25> 888.508 110.469<-241.846 -131.377> 1039.68 108.438<720.186 916.045 1011.98 1198.23> 1368.51 113.281<-241.846 -128.564> -DStem2: 446.711 1294.25 334.367 1294.25 0.289596 -0.957149<0 589.723> 662.258 40.4199 551.945 28.8574 0.456936 -0.8895<0 262.07> 621.398 729.795 679.992 624.17 0.291293 0.956634<0 590.041> 888.508 -241.846 998.977 -241.846 0.303155 0.952941<33.4892 224.122 320.727 631.883> 1253.35 428.232 1185.23 328.389 0.305997 -0.952033<74.2085 385.084> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 418.5078125 -241.845703125 m 1x7e98 @@ -2570,23 +2144,6 @@ HStem: 99.2002 112.793<1049.91 1285.26 1418.46 1622.37> 838.36 98.4375<1239.05 1 VStem: 169.633 150<99.2002 249.2> 179.203 159.57<777.228 936.798> 726.469 159.57<99.2002 258.771 777.228 936.798> 1285.26 133.203<211.993 838.36> DStem2: 169.633 99.2002 319.633 99.2002 0.552681 0.833393<82.9021 411.831 638.258 1005.04> 338.773 936.798 179.203 936.798 0.546973 -0.83715<0 365.574 522.989 913.254> 998.344 705.157 1081.16 630.841 0.683539 0.729914<1.88118 286.669> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 99.2002 112.793<1049.91 1285.26 1418.46 1622.37> 838.36 98.4375<1239.05 1285.26> -VStem: 169.633 150<99.2002 249.2> 179.203 159.57<777.228 936.798> 726.469 159.57<99.2002 258.771 777.228 936.798> 1285.26 133.203<211.993 838.36> -DStem2: 169.633 99.2002 319.633 99.2002 0.552681 0.833393<82.9021 411.831 638.258 1005.04> 338.773 936.798 179.203 936.798 0.546973 -0.83715<0 365.574 522.989 913.254> 998.344 705.157 1081.16 630.841 0.683539 0.729914<1.88118 286.669> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 886.0390625 99.2001953125 m 1xdc @@ -2628,20 +2185,6 @@ HStem: -253.3 85.3906<331.166 506.082> -61.0391 130.176<891.389 1021.56> 95.1377 VStem: 82.0938 106.562<1187.72 1294.28> 202.297 107.5<-147.64 75.4877> 493.891 104.688<1189.59 1294.28> 526.75 107.5<-147.355 74.3454> 700.609 101.797<624.2 897.794 983.263 1204.98> 1030.84 108.516<1002.53 1185.72> 1187.45 101.78<-25.0879 211.535> 1233.73 109.453<750.447 1168.03> DStem2: 188.656 1294.28 82.0938 1294.28 0.271727 -0.962374<0 593.586> 891.389 69.1366 891.389 -61.0391 0.717299 0.696766<0 311.586> 1024.12 905.45 922.406 897.794 0.413517 -0.910496<0 262.054> 1289.23 -25.0879 1187.45 -248.968 0.735691 0.677318<0 314.262> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 3 -WasModified: 0 -WasOrder2: 0 -Layer: 2 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 418.234375 -253.330078125 m 0xe3dc @@ -2747,22 +2290,6 @@ Flags: W HStem: -253.33 96.9531<1073.4 1297.1> 332.217 96.0156<306.547 506.234 614.672 814.359 1062.75 1307.77> 612.686 96.9531<474.093 697.732> 1198.23 96.0156<463.45 708.394 987.25 1186.94 1295.38 1495.06> VStem: 296.938 116.25<773.332 1145.09> 506.234 108.438<-241.846 332.217> 758.656 116.25<773.332 1145.09> 896.312 116.172<-92.6831 279.07> 1186.94 108.438<624.17 1198.23> 1358.03 116.172<-92.6831 279.07> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 96.9531<1073.4 1297.1> 332.217 96.0156<306.547 506.234 614.672 814.359 1062.75 1307.77> 612.686 96.9531<474.093 697.732> 1198.23 96.0156<463.45 708.394 987.25 1186.94 1295.38 1495.06> -VStem: 296.938 116.25<773.332 1145.09> 506.234 108.438<-241.846 332.217> 758.656 116.25<773.332 1145.09> 896.312 116.172<-92.6831 279.07> 1186.94 108.438<624.17 1198.23> 1358.03 116.172<-92.6831 279.07> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 614.671875 332.216796875 m 1 @@ -2866,20 +2393,6 @@ HStem: -259 89.2188<739.069 929.998> 23.1875 90.2344<153.266 362.441> 277.641 14 VStem: 51.4688 101.797<-247.516 23.1875 113.422 332.328> 83.1875 97.9688<618.5 1141.9> 381.703 108.516<132.763 312.99> 543.031 97.9688<618.5 1143.75> 584.594 109.453<-121.269 296.316> 797.406 101.797<736.821 1288.58> 1152.64 101.797<736.821 1288.58> 1171.47 97.9688<-247.516 275.885> 1363.19 101.797<707.797 1288.58> 1631.31 97.9688<-247.516 277.731> DStem2: 203.188 1288.58 185.922 1143.66 0.416929 -0.908939<124.527 395.989> 1291.47 422.562 1274.2 277.641 0.416929 -0.908939<124.527 395.989> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 51.46875 -247.515625 m 1xde93 @@ -3007,23 +2520,6 @@ HStem: -241.846 96.0156<497.016 817.797 1015.27 1260.36> 50.0293 95.9375<497.016 VStem: 353.969 107.5<1052.56 1188.85> 388.578 108.438<-145.83 50.0293 145.967 332.217> 713.969 107.5<735.735 882.928> 924.672 107.5<186.541 322.835> 937.875 103.75<624.17 1136.83> 1284.67 107.5<-130.28 16.9126> 1354.59 103.594<781.592 1294.25> DStem2: 568.031 1025.42 549.75 922.764 0.978916 -0.204262<-84.3815 149.558> 1277.72 923.701 1118.34 994.717 0.508638 -0.860981<-299.653 157.446> 1138.73 159.404 1120.45 56.748 0.978916 -0.204262<-84.3815 149.558> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -241.846 96.0156<497.016 817.797 1015.27 1260.36> 50.0293 95.9375<497.016 787.953 1142.69 1260.82> 332.217 96.0156<497.016 817.797 1052.91 1288.54> 612.686 95.9375<459.826 685.636> 1209.79 95.9375<485.37 703.815> -VStem: 353.969 107.5<1052.56 1188.85> 388.578 108.438<-145.83 50.0293 145.967 332.217> 713.969 107.5<735.735 882.928> 924.672 107.5<186.541 322.835> 937.875 103.75<624.17 1136.83> 1284.67 107.5<-130.28 16.9126> 1354.59 103.594<781.592 1294.25> -DStem2: 568.031 1025.42 549.75 922.764 0.978916 -0.204262<-84.3815 149.558> 1277.72 923.701 1118.34 994.717 0.508638 -0.860981<-299.653 157.446> 1138.73 159.404 1120.45 56.748 0.978916 -0.204262<-84.3815 149.558> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 388.578125 -241.845703125 m 1xfb @@ -3132,23 +2628,6 @@ HStem: 84.8447 119.922<380.027 643.107 1147.14 1395.21> 831.231 119.922<401.199 VStem: 232.816 134.375<638.539 801.481> 682.816 134.375<242.984 418.824> 958.012 133.203<263.461 936.798> 1451.18 133.203<263.461 936.798> DStem2: 500.395 600.763 477.543 472.442 0.978916 -0.204262<-105.472 187.038> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 84.8447 119.922<380.027 643.107 1147.14 1395.21> 831.231 119.922<401.199 656.619> -VStem: 232.816 134.375<638.539 801.481> 682.816 134.375<242.984 418.824> 958.012 133.203<263.461 936.798> 1451.18 133.203<263.461 936.798> -DStem2: 500.395 600.763 477.543 472.442 0.978916 -0.204262<-105.472 187.038> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 513.578125 84.8447265625 m 0 @@ -3215,23 +2694,6 @@ HStem: 171.516 89.2188<906.667 1116.84 1445.69 1645.37> 183 108.516<198.32 221.3 VStem: 0 103.75<749.328 853.078> 321.719 123.75<751.086 853.078> 664.375 99.8438<753.234 853.078> 812.781 101.719<608.533 755.771> 1137.31 101.719<281.429 444.709> 1288.88 109.531<309.707 726.324> 1701.69 90.3125<183 281.906 305.738 449.875> DStem2: 103.75 853.078 0 853.078 0.190374 -0.981712<0 567.853> 216.094 291.516 355.312 595.812 0.136058 0.990701<4.46299 473.288> 530.938 445.109 387.969 750.344 0.136058 -0.990701<-318.35 155.035> 585.625 446.984 617.344 183 0.190374 0.981712<-154.194 413.659> 1006.69 581.438 988.406 485.422 0.978371 -0.206857<-75.1218 135.909> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 89.2188<906.667 1116.84 1445.69 1645.37> 183 108.516<198.32 221.367 546.758 569.805> 449.875 87.3438<1569.19 1693.09> 750.344 102.734<371.133 393.242> 775.344 89.2188<935.851 1133.42 1446.32 1654.53> -VStem: 0 103.75<749.328 853.078> 321.719 123.75<751.086 853.078> 664.375 99.8438<753.234 853.078> 812.781 101.719<608.533 755.771> 1137.31 101.719<281.429 444.709> 1288.88 109.531<309.707 726.324> 1701.69 90.3125<183 281.906 305.738 449.875> -DStem2: 103.75 853.078 0 853.078 0.190374 -0.981712<0 567.853> 216.094 291.516 355.312 595.812 0.136058 0.990701<4.46299 473.288> 530.938 445.109 387.969 750.344 0.136058 -0.990701<-318.35 155.035> 585.625 446.984 617.344 183 0.190374 0.981712<-154.194 413.659> 1006.69 581.438 988.406 485.422 0.978371 -0.206857<-75.1218 135.909> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 142.1875 183 m 1x77f0 @@ -3331,22 +2793,6 @@ Flags: W HStem: -247.516 96.0156<738.656 979.032> 326.547 96.0156<738.656 979.032> 618.5 96.0156<177.043 421.987 1508.81 1781.47> 885.375 95.0781<868.812 1105.12> 1193.58 95<177.765 421.265 868.812 1105.12> VStem: 10.5312 116.25<767.663 1139.42> 472.25 116.25<767.663 1139.42> 630.219 108.438<-151.5 326.547> 760.375 108.438<618.5 885.375 980.453 1193.58> 1034.36 116.172<-96.0967 271.144> 1128.97 114.219<1002.69 1171.26> 1400.38 108.438<714.516 1288.58> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -247.516 96.0156<738.656 979.032> 326.547 96.0156<738.656 979.032> 618.5 96.0156<177.043 421.987 1508.81 1781.47> 885.375 95.0781<868.812 1105.12> 1193.58 95<177.765 421.265 868.812 1105.12> -VStem: 10.5312 116.25<767.663 1139.42> 472.25 116.25<767.663 1139.42> 630.219 108.438<-151.5 326.547> 760.375 108.438<618.5 885.375 980.453 1193.58> 1034.36 116.172<-96.0967 271.144> 1128.97 114.219<1002.69 1171.26> 1400.38 108.438<714.516 1288.58> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 630.21875 422.5625 m 5xffd0 @@ -3444,23 +2890,6 @@ HStem: 171.516 90.2344<160.025 367.673> 453.703 90.2344<772.328 981.503> 708.156 VStem: 3.65625 109.453<309.775 726.303> 414.516 109.453<309.775 726.303> 670.531 101.797<183 453.703 543.938 762.844> 1000.77 108.516<563.279 743.506> 1230.53 97.9688<183 706.401> 1690.38 97.9688<183 708.247> DStem2: 1350.53 853.078 1333.27 708.156 0.416929 -0.908939<124.527 395.989> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 90.2344<160.025 367.673> 453.703 90.2344<772.328 981.503> 708.156 144.922<1321.78 1349.11 1669.28 1697.09> 762.844 90.2344<151.573 376.123 772.328 981.503> -VStem: 3.65625 109.453<309.775 726.303> 414.516 109.453<309.775 726.303> 670.531 101.797<183 453.703 543.938 762.844> 1000.77 108.516<563.279 743.506> 1230.53 97.9688<183 706.401> 1690.38 97.9688<183 708.247> -DStem2: 1350.53 853.078 1333.27 708.156 0.416929 -0.908939<124.527 395.989> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 263.8125 171.515625 m 256xcfc0 @@ -3544,23 +2973,6 @@ HStem: 183 96.0156<862.719 1183.34 1380.88 1625.94> 474.875 95.9375<862.719 1153 VStem: 34.2812 103.594<183 695.656> 450.844 103.75<340.422 853.078> 754.281 108.438<279.016 474.875 570.812 757.062> 1290.22 107.5<611.387 747.68> 1650.22 107.5<294.565 441.758> DStem2: 374.125 482.531 214.75 553.547 0.508638 -0.860981<-299.653 157.446> 1504.28 584.25 1486 481.594 0.978916 -0.204262<-84.3745 149.704> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<862.719 1183.34 1380.88 1625.94> 474.875 95.9375<862.719 1153.66 1508.24 1626.52> 757.062 96.0156<862.719 1183.34 1418.58 1654.18> -VStem: 34.2812 103.594<183 695.656> 450.844 103.75<340.422 853.078> 754.281 108.438<279.016 474.875 570.812 757.062> 1290.22 107.5<611.387 747.68> 1650.22 107.5<294.565 441.758> -DStem2: 374.125 482.531 214.75 553.547 0.508638 -0.860981<-299.653 157.446> 1504.28 584.25 1486 481.594 0.978916 -0.204262<-84.3745 149.704> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 214.75 553.546875 m 1 @@ -3636,23 +3048,6 @@ HStem: -253.33 91.1719<499.414 694.483 1066.72 1266.62> 64.4043 83.5156<1082.67 VStem: 386.196 112.344<733.124 927.954> 727.681 113.281<-128.478 61.427> 746.196 111.406<733.124 927.954> 926.665 113.281<-137.297 35.7148> 946.821 105.625<172.66 327.633> 1280.96 105.547<172.66 327.633 996.52 1182.98> 1293.38 113.281<-137.297 35.7148> DStem2: 401.274 54.7949 491.509 97.0605 0.0726244 0.997359<48.7072 286.444> 956.743 727.842 1073.85 716.357 0.752577 0.658505<80.5713 451.637> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 91.1719<499.414 694.483 1066.72 1266.62> 64.4043 83.5156<1082.67 1250.74> 95.1074 89.2969<533.048 697.686> 334.17 94.0625<506.077 806.353> 352.373 87.3438<1075.55 1257.83> 612.686 88.2812<528.291 716.365> 624.17 92.1875<1073.85 1411.82> 960.186 87.3438<549.317 716.57> 1211.67 94.0625<1075.17 1251.25> -VStem: 386.196 112.344<733.124 927.954> 727.681 113.281<-128.478 61.427> 746.196 111.406<733.124 927.954> 926.665 113.281<-137.297 35.7148> 946.821 105.625<172.66 327.633> 1280.96 105.547<172.66 327.633 996.52 1182.98> 1293.38 113.281<-137.297 35.7148> -DStem2: 401.274 54.7949 491.509 97.0605 0.0726244 0.997359<48.7072 286.444> 956.743 727.842 1073.85 716.357 0.752577 0.658505<80.5713 451.637> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 806.352539062 334.169921875 m 1xb1e0 @@ -3819,23 +3214,6 @@ HStem: -253.33 91.1719<1068.73 1263.8> 4.87305 87.3438<519.871 687.162> 95.1074 VStem: 378.877 111.406<124.448 319.279 735.299 925.949> 737.939 112.344<124.448 319.279 733.124 927.954> 1277.63 115.233<990.463 1182.98> 1297 113.281<-128.478 61.427> DStem2: 957.939 727.842 1075.05 716.357 0.752575 0.658506<80.5711 451.636> 970.596 54.7949 1060.83 97.0605 0.0726286 0.997359<48.7076 286.445> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 91.1719<1068.73 1263.8> 4.87305 87.3438<519.871 687.162> 95.1074 89.2969<1102.37 1267.01> 334.17 94.0625<1075.4 1375.67> 351.436 88.2812<519.85 708.188> 612.686 88.2812<529.488 717.562> 624.17 92.1875<1075.05 1413.02> 960.186 87.3438<550.514 717.767> 1211.67 94.0625<1076.36 1252.45> -VStem: 378.877 111.406<124.448 319.279 735.299 925.949> 737.939 112.344<124.448 319.279 733.124 927.954> 1277.63 115.233<990.463 1182.98> 1297 113.281<-128.478 61.427> -DStem2: 957.939 727.842 1075.05 716.357 0.752575 0.658506<80.5711 451.636> 970.596 54.7949 1060.83 97.0605 0.0726286 0.997359<48.7076 286.445> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 850.283203125 178.623046875 m 0xe9e0 @@ -3991,23 +3369,6 @@ HStem: -62.2031 83.5156<801.078 977.719> 330.375 92.1875<873.463 902.443> 607.01 VStem: 57.0938 101.797<618.5 889.203 979.438 1198.34> 387.328 108.516<998.779 1179.01> 590.219 109.453<744.746 1162.33> 624.438 99.8438<-247.516 -147.672> 1053.58 102.734<-247.516 -144.781> 1177.09 97.9688<618.5 1141.9> 1636.94 97.9688<618.5 1143.75> DStem2: 624.438 -247.516 724.281 -247.516 0.286825 0.957983<28.6377 221.043 308.198 625.84> 954.672 422.562 915.297 232.484 0.276827 -0.96092<73.4064 391.949 478.84 671.271> 1297.09 1288.58 1279.83 1143.66 0.416929 -0.908939<124.527 395.989> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -62.2031 83.5156<801.078 977.719> 330.375 92.1875<873.463 902.443> 607.016 89.2188<744.694 935.623> 889.203 90.2344<158.891 368.066> 1143.66 144.922<1268.34 1295.67 1615.84 1643.66> 1198.34 90.2344<158.891 368.066 736.496 938.717> -VStem: 57.0938 101.797<618.5 889.203 979.438 1198.34> 387.328 108.516<998.779 1179.01> 590.219 109.453<744.746 1162.33> 624.438 99.8438<-247.516 -147.672> 1053.58 102.734<-247.516 -144.781> 1177.09 97.9688<618.5 1141.9> 1636.94 97.9688<618.5 1143.75> -DStem2: 624.438 -247.516 724.281 -247.516 0.286825 0.957983<28.6377 221.043 308.198 625.84> 954.672 422.562 915.297 232.484 0.276827 -0.96092<73.4064 391.949 478.84 671.271> 1297.09 1288.58 1279.83 1143.66 0.416929 -0.908939<124.527 395.989> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 1053.578125 -247.515625 m 1xf378 @@ -4103,23 +3464,6 @@ HStem: -247.516 89.2969<766.078 988.208> 51.0781 87.3438<766.078 968.007> 333.26 VStem: 57.0938 101.797<618.5 889.203 979.438 1198.34> 387.328 108.516<998.779 1179.01> 590.219 109.453<744.746 1162.33> 664.281 101.797<-158.219 51.0781 138.422 333.266> 986.859 107.5<156.718 314.969> 1007.95 108.516<-137.91 30.7696> 1177.09 97.9688<618.5 1141.9> 1636.94 97.9688<618.5 1143.75> DStem2: 1297.09 1288.58 1279.83 1143.66 0.416929 -0.908939<124.527 395.989> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -247.516 89.2969<766.078 988.208> 51.0781 87.3438<766.078 968.007> 333.266 89.2969<766.078 968.007> 607.016 89.2188<744.694 935.623> 889.203 90.2344<158.891 368.066> 1143.66 144.922<1268.34 1295.67 1615.84 1643.66> 1198.34 90.2344<158.891 368.066 736.496 938.717> -VStem: 57.0938 101.797<618.5 889.203 979.438 1198.34> 387.328 108.516<998.779 1179.01> 590.219 109.453<744.746 1162.33> 664.281 101.797<-158.219 51.0781 138.422 333.266> 986.859 107.5<156.718 314.969> 1007.95 108.516<-137.91 30.7696> 1177.09 97.9688<618.5 1141.9> 1636.94 97.9688<618.5 1143.75> -DStem2: 1297.09 1288.58 1279.83 1143.66 0.416929 -0.908939<124.527 395.989> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 664.28125 422.5625 m 1xf9ae @@ -4234,23 +3578,6 @@ HStem: -253.33 96.9531<472.423 704.729> -60.4395 93.125<1098.35 1296.09> 22.1387 VStem: 295.148 116.172<-93.8873 280.002> 405.07 107.5<1052.56 1188.85> 755.93 95.0781<-241.846 -140.049 -108.342 22.1387> 765.07 107.5<735.735 882.928> 903.43 110.391<-241.846 -131.455> 989.055 108.438<720.186 916.045 1011.98 1198.23> 1383.43 113.281<-241.846 -128.564> DStem2: 619.133 1025.42 600.852 922.764 0.978916 -0.204262<-84.378 149.631> 903.43 -241.846 1013.82 -241.846 0.322775 0.946476<35.6313 226.241 322.753 322.753> 1268.27 428.232 1200.07 328.389 0.306115 -0.951995<74.1727 385.072 481.954 673.162> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 96.9531<472.423 704.729> -60.4395 93.125<1098.35 1296.09> 22.1387 93.125<608.117 746.32> 328.389 99.8438<1183.19 1212.07> 342.764 96.9531<472.697 701.413> 612.686 95.9375<510.965 736.75 1097.49 1418.2> 916.045 95.9375<1097.49 1388.43> 1209.79 95.9375<536.534 754.946 1097.49 1418.2> -VStem: 295.148 116.172<-93.8873 280.002> 405.07 107.5<1052.56 1188.85> 755.93 95.0781<-241.846 -140.049 -108.342 22.1387> 765.07 107.5<735.735 882.928> 903.43 110.391<-241.846 -131.455> 989.055 108.438<720.186 916.045 1011.98 1198.23> 1383.43 113.281<-241.846 -128.564> -DStem2: 619.133 1025.42 600.852 922.764 0.978916 -0.204262<-84.378 149.631> 903.43 -241.846 1013.82 -241.846 0.322775 0.946476<35.6313 226.241 322.753 322.753> 1268.27 428.232 1200.07 328.389 0.306115 -0.951995<74.1727 385.072 481.954 673.162> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 755.9296875 -140.048828125 m 1xafa2 @@ -4357,22 +3684,6 @@ Flags: W HStem: -233.641 135.352<983.512 1136.47> 892.414 145.43<754.163 1037.71> VStem: 462.641 174.141<270.312 765.753> 829.672 152.812<-98.1521 8.21826> 1155.22 174.141<268.985 765.753> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -233.641 135.352<983.512 1136.47> 892.414 145.43<754.163 1037.71> -VStem: 462.641 174.141<270.312 765.753> 829.672 152.812<-98.1521 8.21826> 1155.22 174.141<268.985 765.753> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 1136.46875 -233.640625 m 5 @@ -4428,23 +3739,6 @@ HStem: 183 89.2969<1439.98 1772.17> 708.156 144.922<737.328 764.657 1084.83 1112 VStem: 227.25 101.719<183 442.219> 646.078 97.9688<183 706.401> 1105.92 97.9688<183 708.247> DStem2: 134.125 853.078 19.8281 853.078 0.450673 -0.892689<0 330.095> 285.766 553.547 328.969 442.219 0.416605 0.909087<0 329.486> 766.078 853.078 748.812 708.156 0.416929 -0.908939<124.527 395.989> 1324.83 274.172 1439.98 272.297 0.548962 0.835847<61.6492 585.764> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 89.2969<1439.98 1772.17> 708.156 144.922<737.328 764.657 1084.83 1112.64> 763.781 89.2969<1340.14 1646.39> -VStem: 227.25 101.719<183 442.219> 646.078 97.9688<183 706.401> 1105.92 97.9688<183 708.247> -DStem2: 134.125 853.078 19.8281 853.078 0.450673 -0.892689<0 330.095> 285.766 553.547 328.969 442.219 0.416605 0.909087<0 329.486> 766.078 853.078 748.812 708.156 0.416929 -0.908939<124.527 395.989> 1324.83 274.172 1439.98 272.297 0.548962 0.835847<61.6492 585.764> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 227.25 183 m 1xbc @@ -4503,23 +3797,6 @@ HStem: 171.516 91.1719<1374.3 1569.36> 453.703 91.25<184.594 336.939> 474.875 95 VStem: 76.1562 108.438<183 453.703 544.953 758.078> 444.75 114.297<567.194 735.759> 716.156 108.438<183 474.875 570.812 757.062> 1602.56 113.281<296.368 486.273> DStem2: 428.422 465.266 318.031 453.703 0.456936 -0.8895<0 262.07> 1276.16 479.641 1366.39 521.906 0.0726244 0.997359<48.7072 286.444> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 91.1719<1374.3 1569.36> 453.703 91.25<184.594 336.939> 474.875 95.9375<824.594 1100.14> 519.953 89.2969<1407.93 1572.57> 757.062 96.0156<184.594 420.981 824.594 1134.67 1380.69 1681.23> -VStem: 76.1562 108.438<183 453.703 544.953 758.078> 444.75 114.297<567.194 735.759> 716.156 108.438<183 474.875 570.812 757.062> 1602.56 113.281<296.368 486.273> -DStem2: 428.422 465.266 318.031 453.703 0.456936 -0.8895<0 262.07> 1276.16 479.641 1366.39 521.906 0.0726244 0.997359<48.7072 286.444> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 184.59375 183 m 1xcf80 @@ -4603,23 +3880,6 @@ HStem: -253.33 91.1719<492.095 694.045 1082.26 1420.23> 60.5762 92.1094<524.289 VStem: 714.289 114.219<179.923 323.321> 727.727 112.344<-131.94 32.8528> 740.148 113.281<737.538 927.443> 965.227 455<-241.846 -149.658 624.17 716.357> 1284.91 115.156<124.902 316.965 1004.13 1182.98> DStem2: 471.32 795.029 392.57 732.686 0.582707 -0.812682<4.77747 136.754> 413.742 920.811 503.977 963.076 0.0726244 0.997359<48.7072 286.444> 955.461 727.842 1072.57 716.357 0.752577 0.658505<80.5713 451.637> 965.227 -138.174 1082.26 -149.658 0.752577 0.658505<80.5125 451.578> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 91.1719<492.095 694.045 1082.26 1420.23> 60.5762 92.1094<524.289 683.663> 348.545 91.1719<503.64 691.332 1086.66 1259.04> 612.686 91.1719<511.882 706.951 1072.57 1410.54> 961.123 89.2969<545.516 710.154> 1200.19 94.0625<518.545 818.82 1064.99 1253.84> -VStem: 714.289 114.219<179.923 323.321> 727.727 112.344<-131.94 32.8528> 740.148 113.281<737.538 927.443> 965.227 455<-241.846 -149.658 624.17 716.357> 1284.91 115.156<124.902 316.965 1004.13 1182.98> -DStem2: 471.32 795.029 392.57 732.686 0.582707 -0.812682<4.77747 136.754> 413.742 920.811 503.977 963.076 0.0726244 0.997359<48.7072 286.444> 955.461 727.842 1072.57 716.357 0.752577 0.658505<80.5713 451.637> 965.227 -138.174 1082.26 -149.658 0.752577 0.658505<80.5125 451.578> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 592.4140625 152.685546875 m 1xfd @@ -4775,23 +4035,6 @@ HStem: 171.516 85.3906<666.317 841.234> 183 108.516<1191.66 1214.71 1540.1 1563. VStem: 211.938 101.719<183 763.781> 537.406 107.5<277.176 500.303> 861.938 107.5<277.46 499.161> 993.344 103.75<749.328 853.078> 1315.06 123.75<751.086 853.078> 1657.72 99.8438<753.234 853.078> DStem2: 1097.09 853.078 993.344 853.078 0.190374 -0.981712<0 567.853> 1209.44 291.516 1348.66 595.812 0.136058 0.990701<4.46299 473.288> 1524.28 445.109 1381.31 750.344 0.136058 -0.990701<-318.35 155.035> 1578.97 446.984 1610.69 183 0.190374 0.981712<-154.194 413.659> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 85.3906<666.317 841.234> 183 108.516<1191.66 1214.71 1540.1 1563.15> 519.953 85.4688<691.227 840.765> 750.344 102.734<1364.48 1386.59> 763.781 89.2969<34.4375 211.938 313.656 491.312> -VStem: 211.938 101.719<183 763.781> 537.406 107.5<277.176 500.303> 861.938 107.5<277.46 499.161> 993.344 103.75<749.328 853.078> 1315.06 123.75<751.086 853.078> 1657.72 99.8438<753.234 853.078> -DStem2: 1097.09 853.078 993.344 853.078 0.190374 -0.981712<0 567.853> 1209.44 291.516 1348.66 595.812 0.136058 0.990701<4.46299 473.288> 1524.28 445.109 1381.31 750.344 0.136058 -0.990701<-318.35 155.035> 1578.97 446.984 1610.69 183 0.190374 0.981712<-154.194 413.659> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 313.65625 763.78125 m 1x6fe0 @@ -4864,23 +4107,6 @@ HStem: 171.516 92.1094<829.327 1005.2 1389.33 1565.2> 772.453 92.1094<829.327 10 VStem: 71.8594 108.438<183 434.904 513.234 853.078> 460.609 126.719<726.359 853.078> 476 130.547<183 313.547> 674.438 115.156<303.546 732.443> 1044.98 115.156<302.743 733.336> 1234.44 115.156<303.546 732.443> 1604.98 115.156<302.743 733.336> DStem2: 348.344 570.812 272.484 495.969 0.54515 -0.838338<21.3896 394.71> 280.141 635.188 348.344 570.812 0.660468 0.750854<-154.984 -109.59 -12.7165 282.798> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 92.1094<829.327 1005.2 1389.33 1565.2> 772.453 92.1094<829.327 1005.2 1389.33 1565.2> -VStem: 71.8594 108.438<183 434.904 513.234 853.078> 460.609 126.719<726.359 853.078> 476 130.547<183 313.547> 674.438 115.156<303.546 732.443> 1044.98 115.156<302.743 733.336> 1234.44 115.156<303.546 732.443> 1604.98 115.156<302.743 733.336> -DStem2: 348.344 570.812 272.484 495.969 0.54515 -0.838338<21.3896 394.71> 280.141 635.188 348.344 570.812 0.660468 0.750854<-154.984 -109.59 -12.7165 282.798> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 272.484375 495.96875 m 1xef80 @@ -4974,23 +4200,6 @@ HStem: -241.846 92.1875<499.047 837.016 1068.8 1262.38> 345.654 94.0625<500.878 VStem: 295.219 116.172<772.128 1146.02> 701.547 115.312<124.447 316.965> 756 95.0781<624.17 725.967 757.673 888.154> 903.5 110.391<624.17 734.561> 922.797 115.156<-121.3 307.598> 1293.27 115.156<-122.103 308.491> 1383.5 113.281<624.17 737.451> DStem2: 381.859 -138.174 499.047 -149.658 0.752577 0.658505<80.6301 451.695> 903.5 624.17 1013.89 624.17 0.303274 0.952903<33.4786 224.111 320.716 631.896> 1268.34 1294.25 1200.14 1194.4 0.306115 -0.951995<74.1727 385.072> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -241.846 92.1875<499.047 837.016 1068.8 1262.38> 345.654 94.0625<500.878 676.405 1076.04 1254.37> 612.686 96.9531<472.493 704.799> 805.576 93.125<1098.42 1296.16> 888.154 93.125<608.188 746.391> 1194.4 99.8438<1183.26 1212.14> 1208.78 96.9531<472.767 701.484> -VStem: 295.219 116.172<772.128 1146.02> 701.547 115.312<124.447 316.965> 756 95.0781<624.17 725.967 757.673 888.154> 903.5 110.391<624.17 734.561> 922.797 115.156<-121.3 307.598> 1293.27 115.156<-122.103 308.491> 1383.5 113.281<624.17 737.451> -DStem2: 381.859 -138.174 499.047 -149.658 0.752577 0.658505<80.6301 451.695> 903.5 624.17 1013.89 624.17 0.303274 0.952903<33.4786 224.111 320.716 631.896> 1268.34 1294.25 1200.14 1194.4 0.306115 -0.951995<74.1727 385.072> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 837.015625 -241.845703125 m 1xe180 @@ -5113,23 +4322,6 @@ HStem: -407.939 90.2344<638.639 740.609> 332.217 96.0156<457.753 702.84 981.547 VStem: 267.875 108.438<624.17 891.045 986.123 1199.25> 291.391 116.094<-92.8317 279.07> 536.078 101.875<-317.614 -243.747> 636.469 114.219<1008.36 1176.93> 753.109 116.094<-92.8297 279.07> 907.875 103.594<624.17 1136.83> 1181.23 108.438<-241.846 332.217> 1420.53 103.594<624.17 1136.83> DStem2: 1036.47 1294.25 1016.31 1136.83 0.468722 -0.883346<129.61 385.178> 1221.78 953.467 1362.88 1028.31 0.468722 0.883346<0 252.858> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -407.939 90.2344<638.639 740.609> 332.217 96.0156<457.753 702.84 981.547 1181.23 1289.67 1489.36> 891.045 95.0781<376.312 612.622> 1199.25 95<376.312 612.622> -VStem: 267.875 108.438<624.17 891.045 986.123 1199.25> 291.391 116.094<-92.8317 279.07> 536.078 101.875<-317.614 -243.747> 636.469 114.219<1008.36 1176.93> 753.109 116.094<-92.8297 279.07> 907.875 103.594<624.17 1136.83> 1181.23 108.438<-241.846 332.217> 1420.53 103.594<624.17 1136.83> -DStem2: 1036.47 1294.25 1016.31 1136.83 0.468722 -0.883346<129.61 385.178> 1221.78 953.467 1362.88 1028.31 0.468722 0.883346<0 252.858> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 740.609375 -407.939453125 m 1xf6f0 @@ -5231,23 +4423,6 @@ HStem: 84.8447 119.922<305.613 568.692> 831.231 119.922<326.785 582.205> VStem: 158.402 134.375<638.539 801.481> 608.402 134.375<242.984 418.824> 888.383 129.59<99.2002 740.021> 1529.2 129.59<99.2002 740.021> DStem2: 425.98 600.763 403.129 472.442 0.978916 -0.204262<-105.472 187.038> 1049.12 936.798 1023.93 740.021 0.468722 -0.883346<162.013 481.472> 1280.77 510.821 1457.13 604.376 0.468722 0.883346<0 316.072> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 84.8447 119.922<305.613 568.692> 831.231 119.922<326.785 582.205> -VStem: 158.402 134.375<638.539 801.481> 608.402 134.375<242.984 418.824> 888.383 129.59<99.2002 740.021> 1529.2 129.59<99.2002 740.021> -DStem2: 425.98 600.763 403.129 472.442 0.978916 -0.204262<-105.472 187.038> 1049.12 936.798 1023.93 740.021 0.468722 -0.883346<162.013 481.472> 1280.77 510.821 1457.13 604.376 0.468722 0.883346<0 316.072> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 439.1640625 84.8447265625 m 0 @@ -5313,23 +4488,6 @@ HStem: 432.794 118.848<317.094 612.675> 818.048 118.75<317.094 612.675> VStem: 181.547 135.547<99.2002 432.794 551.642 818.048> 642.289 142.969<579.443 790.149> 899.906 140.43<796.368 936.798> 1473.54 136.914<799.884 936.798> DStem2: 1040.34 936.798 899.906 936.798 0.311738 -0.950168<0 737.016> 1258.7 231.231 1331.94 99.2002 0.291293 0.956634<0 737.551> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 432.794 118.848<317.094 612.675> 818.048 118.75<317.094 612.675> -VStem: 181.547 135.547<99.2002 432.794 551.642 818.048> 642.289 142.969<579.443 790.149> 899.906 140.43<796.368 936.798> 1473.54 136.914<799.884 936.798> -DStem2: 1040.34 936.798 899.906 936.798 0.311738 -0.950168<0 737.016> 1258.7 231.231 1331.94 99.2002 0.291293 0.956634<0 737.551> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 181.546875 99.2001953125 m 1 @@ -5374,23 +4532,6 @@ HStem: 171.516 92.1094<833.624 1009.5 1373.31 1569.36> 519.953 89.2969<1407.93 1 VStem: 76.1562 108.438<183 434.904 513.234 853.078> 464.906 126.719<726.359 853.078> 480.297 130.547<183 313.547> 678.734 115.156<303.546 732.443> 1049.28 115.156<302.743 733.336> 1602.56 113.281<296.368 486.273> DStem2: 352.641 570.812 276.781 495.969 0.54515 -0.838338<21.3896 394.71> 284.438 635.188 352.641 570.812 0.660468 0.750854<-154.984 -109.59 -12.7165 282.798> 1276.16 479.641 1366.39 521.906 0.0726244 0.997359<48.7072 286.444> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 92.1094<833.624 1009.5 1373.31 1569.36> 519.953 89.2969<1407.93 1572.57> 759.016 94.0625<1380.96 1681.23> 772.453 92.1094<833.624 1009.5> -VStem: 76.1562 108.438<183 434.904 513.234 853.078> 464.906 126.719<726.359 853.078> 480.297 130.547<183 313.547> 678.734 115.156<303.546 732.443> 1049.28 115.156<302.743 733.336> 1602.56 113.281<296.368 486.273> -DStem2: 352.641 570.812 276.781 495.969 0.54515 -0.838338<21.3896 394.71> 284.438 635.188 352.641 570.812 0.660468 0.750854<-154.984 -109.59 -12.7165 282.798> 1276.16 479.641 1366.39 521.906 0.0726244 0.997359<48.7072 286.444> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 276.78125 495.96875 m 1xebc0 @@ -5488,23 +4629,6 @@ HStem: -253.33 95.9375<473.104 698.889> 25.0293 95.0781<1059.63 1296.02> 343.779 VStem: 367.209 107.5<186.541 322.835 1053.58 1188.28> 727.209 107.5<-130.28 16.9126 735.143 882.928> 921.817 115.157<771.976 1149.28> 951.193 108.438<-241.846 25.0293 120.107 333.232> 1319.79 114.296<142.348 310.913> DStem2: 581.271 159.404 562.99 56.748 0.978916 -0.204262<-84.378 149.631> 581.662 1025.42 563.381 922.764 0.978916 -0.204262<-84.3815 149.558> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 95.9375<473.104 698.889> 25.0293 95.0781<1059.63 1296.02> 343.779 95.9375<498.673 717.085 1059.63 1296.02> 612.686 95.9375<473.457 699.267 1095.64 1308.92> 1209.79 95.9375<499.001 717.446 1095.56 1308.05> -VStem: 367.209 107.5<186.541 322.835 1053.58 1188.28> 727.209 107.5<-130.28 16.9126 735.143 882.928> 921.817 115.157<771.976 1149.28> 951.193 108.438<-241.846 25.0293 120.107 333.232> 1319.79 114.296<142.348 310.913> -DStem2: 581.271 159.404 562.99 56.748 0.978916 -0.204262<-84.378 149.631> 581.662 1025.42 563.381 922.764 0.978916 -0.204262<-84.3815 149.558> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 591.818359375 -253.330078125 m 0xfe40 @@ -5625,22 +4749,6 @@ Flags: W HStem: 183 96.0156<774.047 1094.75 1334.05 1574.42> 474.875 95.9375<774.047 1064.98> 757.062 96.0156<46.0781 245.766 354.203 553.891 774.047 1094.75 1334.05 1574.42> VStem: 245.766 108.438<183 757.062> 665.609 108.438<279.016 474.875 570.812 757.062> 1225.61 108.438<279.016 757.062> 1629.75 116.172<334.419 701.659> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 183 96.0156<774.047 1094.75 1334.05 1574.42> 474.875 95.9375<774.047 1064.98> 757.062 96.0156<46.0781 245.766 354.203 553.891 774.047 1094.75 1334.05 1574.42> -VStem: 245.766 108.438<183 757.062> 665.609 108.438<279.016 474.875 570.812 757.062> 1225.61 108.438<279.016 757.062> 1629.75 116.172<334.419 701.659> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 354.203125 757.0625 m 1 @@ -5698,23 +4806,6 @@ HStem: -253.33 92.1094<1088.19 1264.07> -111.299 85.4688<453.891 672.797 775.453 VStem: 331.156 115.156<771.976 1149.28> 672.797 102.656<-241.846 -111.299 -25.8301 329.326> 933.266 115.156<-121.3 307.598> 1191 106.562<714.404 1215.5> 1303.89 115.156<-122.103 308.491> DStem2: 361.703 -18.1738 453.891 -25.8301 0.512884 0.858458<40.7089 454.423> 961.625 1108.94 1027.88 1049.48 0.683541 0.729912<1.41678 229.335> LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: -253.33 92.1094<1088.19 1264.07> -111.299 85.4688<453.891 672.797 775.453 866.703> 329.326 98.9062<642.87 672.797> 347.607 92.1094<1088.19 1264.07> 624.17 90.2344<498.707 724.268 1002.88 1191 1297.56 1460.84> 1208.78 96.9531<503.376 719.013 1142.05 1191> -VStem: 331.156 115.156<771.976 1149.28> 672.797 102.656<-241.846 -111.299 -25.8301 329.326> 933.266 115.156<-121.3 307.598> 1191 106.562<714.404 1215.5> 1303.89 115.156<-122.103 308.491> -DStem2: 361.703 -18.1738 453.891 -25.8301 0.512884 0.858458<40.7089 454.423> 961.625 1108.94 1027.88 1049.48 0.683541 0.729912<1.41678 229.335> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 672.796875 -241.845703125 m 1xefe0 @@ -5809,37 +4900,14 @@ Encoding: 57584 57584 55 Width: 1792 Flags: HW LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet -0 1497.28125 m 1053 -NamedP: "cap heights and baselines for scaled letter icons" -EndSplineSet -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet --717.389648438 -10.8251953125 m 12 +-717.389648438 -10.8251953125 m 8 NamedP: "baseline 2" - 717.249023438 -10.8251953125 l 1028 --896 0 m 12 + 717.249023438 -10.8251953125 l 1024 +-896 0 m 8 NamedP: "baseline 1" - 896 0 l 1028 + 896 0 l 1024 EndSplineSet Comment: "O" Colour: ff00ff @@ -5853,25 +4921,6 @@ Flags: W HStem: 15.5 139.688<684.242 1061.86> 460.461 135.352<684.242 1028.79> 880.93 139.688<684.242 1028.79> VStem: 521.586 162.656<155.188 460.461 595.812 880.93> 1062.99 171.328<627.723 849.019> 1098.97 171.445<189.391 426.257> LayerCount: 2 -UndoRedoHistory -Layer: 0 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 0 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1687 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Back SplineSet 0 15.5 m 5 @@ -5881,22 +4930,6 @@ NamedP: "1-char" NamedP: "1-char" 1792 1020.6171875 l 1029 EndSplineSet -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 15.5 139.688<684.242 1061.86> 460.461 135.352<684.242 1028.79> 880.93 139.688<684.242 1028.79> -VStem: 521.586 162.656<155.188 460.461 595.812 880.93> 1062.99 171.328<627.723 849.019> 1098.97 171.445<189.391 426.257> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 521.5859375 1020.6171875 m 1xf4 @@ -5948,25 +4981,6 @@ HStem: 325.958 116.406<389.164 636.43> 811.993 124.805<499.082 527.573> VStem: 145.609 137.891<99.2002 237.091> 745.609 141.602<99.2002 240.802> 1220.41 135.547<99.2002 492.633> DStem2: 145.609 99.2002 283.5 99.2002 0.303392 0.952866<41.8349 280.126 400.882 789.887> 601.664 936.798 516.312 811.993 0.306233 -0.951957<92.6712 481.326 602.427 841.437> 1087.21 936.798 932.328 936.798 0.479431 -0.877579<0 425.309> 1294.83 563.556 1355.96 431.622 0.477305 0.878738<0 424.748> LayerCount: 2 -UndoRedoHistory -Layer: 0 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 0 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1687 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Back SplineSet 0 99.2001953125 m 5 @@ -5976,23 +4990,6 @@ NamedP: "2-char" NamedP: "2-char" 1792 936.797851562 l 1029 EndSplineSet -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 325.958 116.406<389.164 636.43> 811.993 124.805<499.082 527.573> -VStem: 145.609 137.891<99.2002 237.091> 745.609 141.602<99.2002 240.802> 1220.41 135.547<99.2002 492.633> -DStem2: 145.609 99.2002 283.5 99.2002 0.303392 0.952866<41.8349 280.126 400.882 789.887> 601.664 936.798 516.312 811.993 0.306233 -0.951957<92.6712 481.326 602.427 841.437> 1087.21 936.798 932.328 936.798 0.479431 -0.877579<0 425.309> 1294.83 563.556 1355.96 431.622 0.477305 0.878738<0 424.748> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 745.609375 99.2001953125 m 1 @@ -6032,25 +5029,6 @@ HStem: 171.516 89.2188<906.667 1116.84 1445.69 1645.37> 183 108.516<198.32 221.3 VStem: 0 103.75<749.328 853.078> 321.719 123.75<751.086 853.078> 664.375 99.8438<753.234 853.078> 812.781 101.719<608.533 755.771> 1137.31 101.719<281.429 444.709> 1288.88 109.531<309.707 726.324> 1701.69 90.3125<183 281.906 305.738 449.875> DStem2: 103.75 853.078 0 853.078 0.190374 -0.981712<0 567.853> 216.094 291.516 355.312 595.812 0.136058 0.990701<4.46299 473.288> 530.938 445.109 387.969 750.344 0.136058 -0.990701<-318.35 155.035> 585.625 446.984 617.344 183 0.190374 0.981712<-154.194 413.659> 1006.69 581.438 988.406 485.422 0.978371 -0.206857<-75.1218 135.909> LayerCount: 2 -UndoRedoHistory -Layer: 0 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 0 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1687 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Back SplineSet 0 183 m 5 @@ -6060,23 +5038,6 @@ NamedP: "3-char" NamedP: "3-char" 1792 853.078125 l 1029 EndSplineSet -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 12 -WasModified: 0 -WasOrder2: 0 -Layer: 0 -HStem: 171.516 89.2188<906.667 1116.84 1445.69 1645.37> 183 108.516<198.32 221.367 546.758 569.805> 449.875 87.3438<1569.19 1693.09> 750.344 102.734<371.133 393.242> 775.344 89.2188<935.851 1133.42 1446.32 1654.53> -VStem: 0 103.75<749.328 853.078> 321.719 123.75<751.086 853.078> 664.375 99.8438<753.234 853.078> 812.781 101.719<608.533 755.771> 1137.31 101.719<281.429 444.709> 1288.88 109.531<309.707 726.324> 1701.69 90.3125<183 281.906 305.738 449.875> -DStem2: 103.75 853.078 0 853.078 0.190374 -0.981712<0 567.853> 216.094 291.516 355.312 595.812 0.136058 0.990701<4.46299 473.288> 530.938 445.109 387.969 750.344 0.136058 -0.990701<-318.35 155.035> 585.625 446.984 617.344 183 0.190374 0.981712<-154.194 413.659> 1006.69 581.438 988.406 485.422 0.978371 -0.206857<-75.1218 135.909> -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 142.1875 183 m 5x77f0 @@ -6176,25 +5137,6 @@ HStem: -253.3 85.3906<331.166 506.082> -61.0391 130.176<891.389 1021.56> 95.1377 VStem: 82.0938 106.562<1187.72 1294.28> 202.297 107.5<-147.64 75.4877> 493.891 104.688<1189.59 1294.28> 526.75 107.5<-147.355 74.3454> 700.609 101.797<624.2 897.794 983.263 1204.98> 1030.84 108.516<1002.53 1185.72> 1187.45 101.78<-25.0879 211.535> 1233.73 109.453<750.447 1168.03> DStem2: 188.656 1294.28 82.0938 1294.28 0.271727 -0.962374<0 593.586> 891.389 69.1366 891.389 -61.0391 0.717299 0.696766<0 311.586> 1024.12 905.45 922.406 897.794 0.413517 -0.910496<0 262.054> 1289.23 -25.0879 1187.45 -248.968 0.735691 0.677318<0 314.262> LayerCount: 2 -UndoRedoHistory -Layer: 0 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 0 -WasOrder2: 0 -Layer: 1 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Back SplineSet 0 1294.24804688 m 5 @@ -6210,119 +5152,6 @@ NamedP: "2-line" NamedP: "2-line" 1792 624.169921875 l 1029 EndSplineSet -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet -418.234375 -251.3046875 m 4xe3dc - 346.59375 -251.3046875 292.6875 -229.2734375 256.515625 -185.1328125 c 4 - 220.34375 -140.9140625 202.296875 -76.6171875 202.296875 7.8359375 c 4 - 202.296875 48.1484375 207.375 88.4609375 217.609375 128.8515625 c 4 - 227.84375 169.1640625 242.609375 207.6796875 261.75 244.4765625 c 4 - 280.96875 281.2734375 303.859375 315.7265625 330.421875 347.6796875 c 4 - 356.984375 379.7109375 386.59375 407.2109375 419.25 430.2578125 c 5 - 465.004882812 430.2578125 510.760742188 430.2578125 556.515625 430.2578125 c 5 - 517.453125 400.1796875 483.859375 371.5078125 455.734375 344.3203125 c 4 - 427.53125 317.1328125 403.703125 290.1015625 384.171875 263.2265625 c 4 - 364.640625 236.3515625 348.859375 208.6953125 336.671875 180.1796875 c 4 - 324.484375 151.6640625 315.1875 120.8046875 308.859375 87.5234375 c 5 - 313 87.5234375 317.140625 87.5234375 321.28125 87.5234375 c 5 - 332.21875 118.2265625 349.484375 141.7421875 373.15625 158.0703125 c 4 - 396.828125 174.3984375 424.953125 182.6015625 457.609375 182.6015625 c 4 - 511.984375 182.6015625 555.03125 164.9453125 586.75 129.7890625 c 4 - 618.390625 94.5546875 634.25 42.7578125 634.25 -25.7578125 c 4 - 634.25 -96.7734375 615.890625 -152.1640625 579.09375 -191.8515625 c 4 - 542.296875 -231.5390625 488.625 -251.3046875 418.234375 -251.3046875 c 4xe3dc -418.234375 -165.9140625 m 260 - 490.578125 -165.9140625 526.75 -126.2265625 526.75 -46.8515625 c 5 - 526.75 -38.544921875 526.75 -30.2373046875 526.75 -21.9296875 c 5 - 526.75 57.4453125 490.578125 97.1328125 418.234375 97.1328125 c 260 - 345.96875 97.1328125 309.796875 57.4453125 309.796875 -21.9296875 c 5 - 309.796875 -30.2373046875 309.796875 -38.544921875 309.796875 -46.8515625 c 5 - 309.796875 -126.2265625 345.96875 -165.9140625 418.234375 -165.9140625 c 260 -278.890625 626.1953125 m 5xc7ec - 213.291992188 849.5546875 147.692382812 1072.9140625 82.09375 1296.2734375 c 5 - 117.614257812 1296.2734375 153.135742188 1296.2734375 188.65625 1296.2734375 c 5 - 228.317382812 1155.8046875 267.979492188 1015.3359375 307.640625 874.8671875 c 5 - 316.9375 822.705078125 326.234375 770.543945312 335.53125 718.3828125 c 5 - 339.671875 718.3828125 343.8125 718.3828125 347.953125 718.3828125 c 5 - 357.25 770.543945312 366.546875 822.705078125 375.84375 874.8671875 c 5 - 415.192382812 1015.3359375 454.541992188 1155.8046875 493.890625 1296.2734375 c 5 - 528.786132812 1296.2734375 563.682617188 1296.2734375 598.578125 1296.2734375 c 5 - 533.291992188 1072.9140625 468.004882812 849.5546875 402.71875 626.1953125 c 5 - 361.442382812 626.1953125 320.166992188 626.1953125 278.890625 626.1953125 c 5xc7ec -802.40625 626.1953125 m 5 - 768.473632812 626.1953125 734.541992188 626.1953125 700.609375 626.1953125 c 5 - 700.609375 849.5546875 700.609375 1072.9140625 700.609375 1296.2734375 c 5 - 788.942382812 1296.2734375 877.276367188 1296.2734375 965.609375 1296.2734375 c 5 - 1023.1875 1296.2734375 1066.546875 1279.1640625 1095.6875 1244.9453125 c 4 - 1124.75 1210.6484375 1139.359375 1161.5859375 1139.359375 1097.5234375 c 4 - 1139.359375 1045.7265625 1129.75 1003.7734375 1110.53125 971.8203125 c 4 - 1091.3125 939.7890625 1062.5625 918.3828125 1024.125 907.4453125 c 5 - 1066.703125 813.6953125 1109.28125 719.9453125 1151.859375 626.1953125 c 5 - 1114.09863281 626.1953125 1076.33886719 626.1953125 1038.578125 626.1953125 c 5 - 999.854492188 717.392578125 961.129882812 808.590820312 922.40625 899.7890625 c 5 - 882.40625 899.7890625 842.40625 899.7890625 802.40625 899.7890625 c 5 - 802.40625 808.590820312 802.40625 717.392578125 802.40625 626.1953125 c 5 -956.9375 985.2578125 m 5 - 981.234375 985.2578125 999.671875 991.5078125 1012.171875 1003.9296875 c 4 - 1024.59375 1016.4296875 1030.84375 1036.7421875 1030.84375 1064.9453125 c 5 - 1030.84375 1085.7265625 1030.84375 1106.5078125 1030.84375 1127.2890625 c 5 - 1030.84375 1155.4921875 1024.59375 1175.8046875 1012.171875 1188.3046875 c 4 - 999.671875 1200.7265625 981.234375 1206.9765625 956.9375 1206.9765625 c 5 - 905.426757812 1206.9765625 853.916992188 1206.9765625 802.40625 1206.9765625 c 5 - 802.40625 1133.0703125 802.40625 1059.1640625 802.40625 985.2578125 c 5 - 853.916992188 985.2578125 905.426757812 985.2578125 956.9375 985.2578125 c 5 -1487.171875 614.7109375 m 4xcbcd - 1448.109375 614.7109375 1413.109375 621.2734375 1382.09375 634.3203125 c 4 - 1351 647.4453125 1324.4375 668.1484375 1302.40625 696.2734375 c 4 - 1280.296875 724.3984375 1263.34375 760.4140625 1251.46875 804.2421875 c 4 - 1239.671875 848.1484375 1233.734375 900.4140625 1233.734375 961.2734375 c 260 - 1233.734375 1022.0546875 1239.671875 1074.3203125 1251.46875 1118.2265625 c 4 - 1263.34375 1162.0546875 1280.296875 1198.0703125 1302.40625 1226.1953125 c 4 - 1324.4375 1254.3203125 1351 1275.0234375 1382.09375 1288.1484375 c 4 - 1413.109375 1301.2734375 1448.109375 1307.7578125 1487.171875 1307.7578125 c 4 - 1544.125 1307.7578125 1589.75 1295.4921875 1623.96875 1270.8046875 c 4 - 1658.1875 1246.1953125 1685.609375 1209.2421875 1706.078125 1159.9453125 c 5 - 1677.27636719 1143.95507812 1648.47363281 1127.96582031 1619.671875 1111.9765625 c 5 - 1608.109375 1149.7109375 1592.015625 1176.8984375 1571.15625 1193.5390625 c 4 - 1550.375 1210.1796875 1522.40625 1218.5390625 1487.171875 1218.5390625 c 4 - 1441.78125 1218.5390625 1406.390625 1202.8359375 1381.078125 1171.5078125 c 4 - 1355.84375 1140.1015625 1343.1875 1096.8984375 1343.1875 1041.8984375 c 5 - 1343.1875 988.122070312 1343.1875 934.345703125 1343.1875 880.5703125 c 5 - 1343.1875 825.5703125 1355.84375 782.3671875 1381.078125 750.9609375 c 4 - 1406.390625 719.6328125 1441.78125 703.9296875 1487.171875 703.9296875 c 4 - 1523.03125 703.9296875 1552.015625 712.9140625 1574.046875 730.8046875 c 4 - 1596.15625 748.7734375 1613.265625 777.5234375 1625.453125 817.2109375 c 5 - 1653.60449219 800.5703125 1681.75488281 783.9296875 1709.90625 767.2890625 c 5 - 1688.8125 718.0703125 1660.609375 680.2578125 1625.453125 654.0078125 c 4 - 1590.21875 627.7578125 1544.125 614.7109375 1487.171875 614.7109375 c 4xcbcd -1289.23339844 437.409179688 m 5 - 1289.23339844 -23.0927734375 l 5 - 1585.29882812 249.481445312 l 5 - 1585.29882812 119.305664062 l 5 - 1187.45410156 -246.97265625 l 5xd3ce - 1187.45410156 213.530273438 l 5 - 891.388671875 -59.0439453125 l 5 - 891.388671875 71.1318359375 l 5 - 1289.23339844 437.409179688 l 5 -EndSplineSet -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory Fore SplineSet 418.234375 -253.330078125 m 0xe3dc @@ -6432,6 +5261,31 @@ SplineSet 1700 607 l 1 92 607 l 25 92 677 l 25 +1309.57341482 1153 m 1 + 1169.86816406 1292.70605469 l 1 + 1212.29394531 1335.13183594 l 1 + 1352 1195.42658518 l 1 + 1352 1393 l 1 + 1412 1393 l 1 + 1412 1195.42658518 l 1 + 1551.70605469 1335.13183594 l 1 + 1594.13183594 1292.70605469 l 1 + 1454.42658518 1153 l 1 + 1652 1153 l 1 + 1652 1093 l 1 + 1454.42658518 1093 l 1 + 1594.13183594 953.293945312 l 1 + 1551.70605469 910.868164062 l 1 + 1412 1050.57341482 l 1 + 1412 853 l 1 + 1352 853 l 1 + 1352 1050.57341482 l 1 + 1212.29394531 910.868164062 l 1 + 1169.86816406 953.293945312 l 1 + 1309.57341482 1093 l 1 + 1112 1093 l 1 + 1112 1153 l 1 + 1309.57341482 1153 l 1 EndSplineSet EndChar @@ -6584,6 +5438,19 @@ Flags: HW LayerCount: 2 Fore SplineSet +1432 1353 m 9 + 1432 1173 l 1 + 1612 1173 l 1 + 1612 1073 l 1 + 1432 1073 l 1 + 1432 893 l 25 + 1332 893 l 25 + 1332 1073 l 1 + 1152 1073 l 1 + 1152 1173 l 1 + 1332 1173 l 1 + 1332 1353 l 17 + 1432 1353 l 9 92 677 m 25 1700 677 l 25 1700 607 l 1 @@ -6599,11 +5466,67 @@ Flags: HW LayerCount: 2 Fore SplineSet -92 677 m 25 - 1700 677 l 25 - 1700 607 l 1 - 92 607 l 25 - 92 677 l 25 +1185.02539062 520 m 1 + 1185.02539062 952 l 1 + 1345.02539062 952 l 1 + 1139.02539062 1242 l 1 + 933.025390625 952 l 1 + 1093.02539062 952 l 1 + 1093.02539062 520 l 1 + 1185.02539062 520 l 1 +1039 578 m 1 + 837.650390625 578 l 1 + 763.55078125 364.203125 l 1 + 712.850585938 426.109375 l 1 + 650.450195312 257.4921875 l 1 + 601.700195312 371.125976562 l 1 + 554.900390625 165.8515625 l 1 + 492.5 393.122070312 l 1 + 434 132.860351562 l 1 + 375.5 217.170898438 l 1 + 320.900390625 77.8740234375 l 1 + 295.55078125 184.1796875 l 1 + 246.80078125 -39.423828125 l 1 + 231.200195312 106.947265625 l 1 + 176.600585938 -193.381835938 l 1 + 121.75 67.0830078125 l 1 + 83 557.821289062 l 1 + 83 695.178710938 l 1 + 121.75 1185.91699219 l 1 + 176.600585938 1446.38183594 l 1 + 231.200195312 1109.14160156 l 1 + 246.80078125 1292.42382812 l 1 + 295.55078125 1068.8203125 l 1 + 320.900390625 1175.12597656 l 1 + 375.5 1035.82910156 l 1 + 434 1120.13964844 l 1 + 492.5 859.877929688 l 1 + 554.900390625 1087.1484375 l 1 + 601.700195312 881.874023438 l 1 + 650.450195312 995.5078125 l 1 + 712.850585938 826.890625 l 1 + 763.55078125 888.796875 l 1 + 837.650390625 675 l 1 + 1039 675 l 1 + 1039 578 l 1 +1537 675 m 1 + 1675.02539062 675 l 9 + 1675.02539062 578 l 17 + 1537 578 l 1 + 1537 675 l 1 +1349 578 m 1 + 1233.99999374 578 l 1 + 1233.99999374 675 l 1 + 1349 675 l 1 + 1349 578 l 1 +1485.02539062 733 m 1 + 1485.02539062 301 l 1 + 1645.02539062 301 l 1 + 1439.02539062 11 l 1 + 1233.02539062 301 l 1 + 1393.02539062 301 l 1 + 1393.02539062 733 l 1 + 1485.02539062 733 l 1 EndSplineSet EndChar @@ -6622,14 +5545,14 @@ SplineSet 972 89 l 1 972 349 l 1 820 349 l 25 -820 953.591796875 m 25 - 820 1213.59179688 l 1 - 620 1213.59179688 l 1 - 896 1503.59179688 l 1 - 1172 1213.59179688 l 1 - 972 1213.59179688 l 1 - 972 953.591796875 l 1 - 820 953.591796875 l 25 +820 953.591796875 m 29 + 820 1213.59179688 l 5 + 620 1213.59179688 l 5 + 896 1503.59179688 l 5 + 1172 1213.59179688 l 5 + 972 1213.59179688 l 5 + 972 953.591796875 l 5 + 820 953.591796875 l 29 1700 642.479492188 m 1 1644 668.879882812 l 1 1530 725.040039062 l 1 @@ -6687,11 +5610,51 @@ Flags: HW LayerCount: 2 Fore SplineSet -92 677 m 25 - 1700 677 l 25 - 1700 607 l 1 - 92 607 l 25 - 92 677 l 25 +365 -62 m 5 + 365 -222 l 5 + 75 -16 l 5 + 365 190 l 5 + 365 30 l 5 + 1427 30 l 5 + 1427 190 l 5 + 1717 -16 l 5 + 1427 -222 l 5 + 1427 -62 l 5 + 365 -62 l 5 +102.450195312 789.541015625 m 5 + 179.950195312 403.98046875 l 5 + 289.650390625 199.33984375 l 5 + 398.849609375 435.30078125 l 5 + 430.049804688 320.30078125 l 5 + 527.549804688 495.98046875 l 5 + 578.25 412.458984375 l 5 + 687.450195312 521.900390625 l 5 + 804.450195312 455.66015625 l 5 + 921.450195312 660.140625 l 5 + 1046.25 481.580078125 l 5 + 1139.84960938 642.859375 l 5 + 1237.34960938 553.580078125 l 5 + 1362.15039062 686.05859375 l 5 + 1463.54980469 637.419921875 l 5 + 1611.75 789.740234375 l 5 + 1684.54980469 844.458984375 l 5 + 1611.75 897.259765625 l 5 + 1463.54980469 1049.58007812 l 5 + 1362.15039062 1000.94140625 l 5 + 1237.34960938 1133.41992188 l 5 + 1139.84960938 1044.140625 l 5 + 1046.25 1205.41992188 l 5 + 921.450195312 1026.859375 l 5 + 804.450195312 1231.33984375 l 5 + 687.450195312 1165.09960938 l 5 + 578.25 1274.54101562 l 5 + 527.549804688 1191.01953125 l 5 + 430.049804688 1366.69921875 l 5 + 398.849609375 1222.69921875 l 5 + 289.650390625 1487.66015625 l 5 + 179.950195312 1283.01953125 l 5 + 102.450195312 897.458984375 l 5 + 102.450195312 789.541015625 l 5 EndSplineSet EndChar @@ -6702,11 +5665,40 @@ Flags: HW LayerCount: 2 Fore SplineSet -92 677 m 25 - 1700 677 l 25 - 1700 607 l 1 - 92 607 l 25 - 92 677 l 25 +1432 1353 m 13 + 1432 1173 l 5 + 1612 1173 l 5 + 1612 1073 l 5 + 1432 1073 l 5 + 1432 893 l 29 + 1332 893 l 29 + 1332 1073 l 5 + 1152 1073 l 5 + 1152 1173 l 5 + 1332 1173 l 5 + 1332 1353 l 21 + 1432 1353 l 13 +1018.75 568.98046875 m 1 + 870.549804688 214.33984375 l 1 + 769.150390625 311.6171875 l 1 + 644.349609375 46.66015625 l 1 + 546.849609375 225.21875 l 1 + 453.25 -97.33984375 l 1 + 328.450195312 259.78125 l 1 + 211.450195312 -149.1796875 l 1 + 94.4501953125 -16.69921875 l 1 + 94.4501953125 1269.69921875 l 1 + 211.450195312 1402.1796875 l 1 + 328.450195312 993.21875 l 1 + 453.25 1350.33984375 l 1 + 546.849609375 1027.78125 l 1 + 644.349609375 1206.33984375 l 1 + 769.150390625 941.3828125 l 1 + 870.549804688 1038.66015625 l 1 + 1018.75 684.01953125 l 9 + 1698 684 l 25 + 1698 568 l 25 + 1018.75 568.98046875 l 1 EndSplineSet EndChar @@ -6717,11 +5709,57 @@ Flags: HW LayerCount: 2 Fore SplineSet -92 677 m 25 - 1700 677 l 25 - 1700 607 l 1 - 92 607 l 25 - 92 677 l 25 +203 1027 m 5 + 635 1027 l 5 + 635 1187 l 5 + 925 981 l 5 + 635 775 l 5 + 635 935 l 5 + 203 935 l 5 + 203 1027 l 5 +118 675 m 29 + 118 578 l 29 + 955.375 578 l 5 + 1029.47460938 364.203125 l 5 + 1080.17480469 426.109375 l 5 + 1142.57519531 257.4921875 l 5 + 1191.32519531 371.125976562 l 5 + 1238.125 165.8515625 l 5 + 1300.52539062 393.122070312 l 5 + 1359.02539062 132.860351562 l 5 + 1417.52539062 217.170898438 l 5 + 1472.125 77.8740234375 l 5 + 1497.47460938 184.1796875 l 5 + 1546.22460938 -39.423828125 l 5 + 1561.82519531 106.947265625 l 5 + 1616.42480469 -193.381835938 l 5 + 1671.27539062 67.0830078125 l 5 + 1710.02539062 557.821289062 l 5 + 1710.02539062 695.178710938 l 5 + 1671.27539062 1185.91699219 l 5 + 1616.42480469 1446.38183594 l 5 + 1561.82519531 1109.14160156 l 5 + 1546.22460938 1292.42382812 l 5 + 1497.47460938 1068.8203125 l 5 + 1472.125 1175.12597656 l 5 + 1417.52539062 1035.82910156 l 5 + 1359.02539062 1120.13964844 l 5 + 1300.52539062 859.877929688 l 5 + 1238.125 1087.1484375 l 5 + 1191.32519531 881.874023438 l 5 + 1142.57519531 995.5078125 l 5 + 1080.17480469 826.890625 l 5 + 1029.47460938 888.796875 l 5 + 955.375 675 l 5 + 118 675 l 29 +805 318 m 5 + 373 318 l 5 + 373 478 l 5 + 83 272 l 5 + 373 66 l 5 + 373 226 l 5 + 805 226 l 5 + 805 318 l 5 EndSplineSet EndChar @@ -6750,19 +5788,19 @@ SplineSet 1312 1160 l 1 1312 1340 l 17 1412 1340 l 9 -480 920 m 9 - 480 740 l 1 - 660 740 l 1 - 660 640 l 1 - 480 640 l 1 - 480 460 l 25 - 380 460 l 25 - 380 640 l 1 - 200 640 l 1 - 200 740 l 1 - 380 740 l 1 - 380 920 l 17 - 480 920 l 9 +480 920 m 13 + 480 740 l 5 + 660 740 l 5 + 660 640 l 5 + 480 640 l 5 + 480 460 l 29 + 380 460 l 29 + 380 640 l 5 + 200 640 l 5 + 200 740 l 5 + 380 740 l 5 + 380 920 l 21 + 480 920 l 13 941 1446 m 25 941 -162 l 25 851 -162 l 1 @@ -6774,7 +5812,7 @@ EndChar StartChar: uniE141 Encoding: 57665 57665 71 Width: 1792 -Flags: HW +Flags: HWO LayerCount: 2 Fore SplineSet @@ -6785,586 +5823,5 @@ SplineSet 92 677 l 25 EndSplineSet EndChar - -StartChar: uniE142 -Encoding: 57666 57666 72 -Width: 1792 -Flags: HW -LayerCount: 2 -UndoRedoHistory -Layer: 1 -Undoes -UndoOperation -Index: 0 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet --6.0488281255 -10.8251953125 m 5 - -6.0488281255 -10.44921875 -6.0488281255 -10.0732421875 -6.0488281255 -9.697265625 c 5 - -5.264648438 -9.697265625 -4.4804687505 -9.697265625 -3.696289063 -9.697265625 c 5 - -3.696289063 -7.609375 -3.696289063 -5.521484375 -3.696289063 -3.43359375 c 5 - -3.7285156255 -3.43359375 -3.760742188 -3.43359375 -3.7929687505 -3.43359375 c 5 - -4.44075520883 -4.12532552083 -5.08854166717 -4.81705729167 -5.7363281255 -5.5087890625 c 5 - -6.01236979217 -5.26106770833 -6.28841145883 -5.01334635417 -6.5644531255 -4.765625 c 5 - -5.852539063 -3.99348958333 -5.1406250005 -3.22135416667 -4.428710938 -2.44921875 c 5 - -3.74055989633 -2.44921875 -3.05240885467 -2.44921875 -2.364257813 -2.44921875 c 5 - -2.364257813 -4.865234375 -2.364257813 -7.28125 -2.364257813 -9.697265625 c 5 - -1.68424479217 -9.697265625 -1.00423177133 -9.697265625 -0.3242187505 -9.697265625 c 5 - -0.3242187505 -10.0732421875 -0.3242187505 -10.44921875 -0.3242187505 -10.8251953125 c 5 - -2.2324218755 -10.8251953125 -4.1406250005 -10.8251953125 -6.0488281255 -10.8251953125 c 5 -6.4238281245 -5.5693359375 m 4 - 6.4238281245 -6.1767578125 6.331054687 -6.7490234375 6.147460937 -7.28515625 c 132 - 5.963867187 -7.8212890625 5.727539062 -8.3134765625 5.4394531245 -8.7607421875 c 132 - 5.151367187 -9.208984375 4.829101562 -9.609375 4.473632812 -9.9609375 c 132 - 4.1171874995 -10.3134765625 3.7675781245 -10.6015625 3.4238281245 -10.8251953125 c 5 - 2.82356770783 -10.8251953125 2.22330729117 -10.8251953125 1.6230468745 -10.8251953125 c 5 - 2.0957031245 -10.4814453125 2.5195312495 -10.1494140625 2.895507812 -9.8291015625 c 132 - 3.2714843745 -9.5087890625 3.5996093745 -9.181640625 3.879882812 -8.8447265625 c 132 - 4.159179687 -8.5087890625 4.393554687 -8.1533203125 4.581054687 -7.77734375 c 132 - 4.7695312495 -7.4013671875 4.915039062 -6.9892578125 5.0195312495 -6.541015625 c 5 - 4.99153645783 -6.533203125 4.96354166617 -6.525390625 4.9355468745 -6.517578125 c 5 - 4.8476562495 -6.685546875 4.745117187 -6.8427734375 4.629882812 -6.9912109375 c 132 - 4.5136718745 -7.1396484375 4.377929687 -7.26953125 4.221679687 -7.380859375 c 132 - 4.065429687 -7.4931640625 3.887695312 -7.5810546875 3.6874999995 -7.6455078125 c 132 - 3.487304687 -7.708984375 3.2558593745 -7.7412109375 2.991210937 -7.7412109375 c 4 - 2.639648437 -7.7412109375 2.313476562 -7.681640625 2.0136718745 -7.5615234375 c 132 - 1.713867187 -7.44140625 1.4531249995 -7.267578125 1.233398437 -7.0390625 c 132 - 1.0136718745 -6.8115234375 0.8417968745 -6.5390625 0.717773437 -6.2236328125 c 132 - 0.5937499995 -5.9072265625 0.5312499995 -5.548828125 0.5312499995 -5.1494140625 c 4 - 0.5312499995 -4.7333984375 0.6015624995 -4.349609375 0.741210937 -3.9970703125 c 132 - 0.881835937 -3.6455078125 1.079101562 -3.3447265625 1.3359374995 -3.09765625 c 132 - 1.5917968745 -2.849609375 1.899414062 -2.6552734375 2.2597656245 -2.515625 c 132 - 2.6191406245 -2.375 3.0234374995 -2.3056640625 3.471679687 -2.3056640625 c 4 - 3.9355468745 -2.3056640625 4.3496093745 -2.380859375 4.713867187 -2.533203125 c 132 - 5.077148437 -2.685546875 5.385742187 -2.9033203125 5.637695312 -3.1875 c 132 - 5.889648437 -3.4716796875 6.0839843745 -3.8134765625 6.219726562 -4.212890625 c 132 - 6.3554687495 -4.61328125 6.4238281245 -5.0654296875 6.4238281245 -5.5693359375 c 4 -3.471679687 -6.6494140625 m 260 - 3.959960937 -6.6494140625 4.3398437495 -6.51953125 4.6113281245 -6.2587890625 c 132 - 4.883789062 -5.9990234375 5.0195312495 -5.6171875 5.0195312495 -5.11328125 c 5 - 5.0195312495 -5.05729166667 5.0195312495 -5.00130208333 5.0195312495 -4.9453125 c 5 - 5.0195312495 -4.44140625 4.883789062 -4.0595703125 4.6113281245 -3.798828125 c 132 - 4.3398437495 -3.5390625 3.959960937 -3.4091796875 3.471679687 -3.4091796875 c 260 - 2.983398437 -3.4091796875 2.6035156245 -3.5390625 2.331054687 -3.798828125 c 132 - 2.059570312 -4.0595703125 1.9238281245 -4.44140625 1.9238281245 -4.9453125 c 5 - 1.9238281245 -5.00130208333 1.9238281245 -5.05729166667 1.9238281245 -5.11328125 c 5 - 1.9238281245 -5.6171875 2.059570312 -5.9990234375 2.331054687 -6.2587890625 c 132 - 2.6035156245 -6.51953125 2.983398437 -6.6494140625 3.471679687 -6.6494140625 c 260 --3.400390625 -0.1435546875 m 4 - -4.49609375 -0.1435546875 -5.3564453125 0.2255859375 -5.98046875 0.9658203125 c 132 - -6.6044921875 1.7060546875 -6.916015625 2.7802734375 -6.916015625 4.1884765625 c 4 - -6.916015625 4.8916015625 -6.8359375 5.51171875 -6.67578125 6.0478515625 c 132 - -6.5166015625 6.583984375 -6.2841796875 7.0361328125 -5.98046875 7.404296875 c 132 - -5.67578125 7.7724609375 -5.306640625 8.0498046875 -4.8701171875 8.23828125 c 132 - -4.4345703125 8.42578125 -3.9443359375 8.51953125 -3.400390625 8.51953125 c 4 - -2.671875 8.51953125 -2.0625 8.3603515625 -1.5703125 8.0400390625 c 132 - -1.078125 7.7197265625 -0.6923828125 7.248046875 -0.412109375 6.6240234375 c 5 - -0.7919921875 6.416015625 -1.171875 6.2080078125 -1.5517578125 6 c 5 - -1.6962890625 6.400390625 -1.91796875 6.7177734375 -2.2177734375 6.9541015625 c 132 - -2.5185546875 7.1904296875 -2.912109375 7.3076171875 -3.400390625 7.3076171875 c 4 - -4.0478515625 7.3076171875 -4.556640625 7.087890625 -4.923828125 6.6484375 c 132 - -5.2919921875 6.2080078125 -5.4765625 5.599609375 -5.4765625 4.82421875 c 5 - -5.4765625 4.40006510417 -5.4765625 3.97591145833 -5.4765625 3.5517578125 c 5 - -5.4765625 2.7763671875 -5.2919921875 2.16796875 -4.923828125 1.7275390625 c 132 - -4.556640625 1.2880859375 -4.0478515625 1.068359375 -3.400390625 1.068359375 c 4 - -2.896484375 1.068359375 -2.486328125 1.1982421875 -2.169921875 1.4580078125 c 132 - -1.8544921875 1.7177734375 -1.6201171875 2.0517578125 -1.4677734375 2.4599609375 c 5 - -1.10384114583 2.23990885417 -0.739908854167 2.01985677083 -0.3759765625 1.7998046875 c 5 - -0.65625 1.1923828125 -1.0478515625 0.7158203125 -1.5517578125 0.3720703125 c 132 - -2.056640625 0.0283203125 -2.671875 -0.1435546875 -3.400390625 -0.1435546875 c 4 -6.916015625 0 m 5 - 5.01985677083 -0 3.12369791667 0 1.2275390625 0 c 5 - 1.2275390625 0.431966145833 1.2275390625 0.863932291667 1.2275390625 1.2958984375 c 5 - 2.11979166667 2.091796875 3.01204427083 2.8876953125 3.904296875 3.68359375 c 5 - 4.328125 4.068359375 4.654296875 4.43359375 4.8818359375 4.7822265625 c 132 - 5.109375 5.1298828125 5.2236328125 5.49609375 5.2236328125 5.8798828125 c 5 - 5.2236328125 5.93196614583 5.2236328125 5.98404947917 5.2236328125 6.0361328125 c 5 - 5.2236328125 6.4443359375 5.1015625 6.763671875 4.857421875 6.99609375 c 132 - 4.6142578125 7.2275390625 4.2841796875 7.34375 3.8681640625 7.34375 c 4 - 3.6357421875 7.34375 3.43359375 7.3095703125 3.26171875 7.2421875 c 132 - 3.08984375 7.173828125 2.939453125 7.080078125 2.8115234375 6.9599609375 c 132 - 2.68359375 6.83984375 2.578125 6.7001953125 2.494140625 6.5400390625 c 132 - 2.41015625 6.3798828125 2.34375 6.2080078125 2.2958984375 6.0244140625 c 5 - 1.89973958333 6.17643229167 1.50358072917 6.32845052083 1.107421875 6.48046875 c 5 - 1.1962890625 6.744140625 1.3154296875 6.998046875 1.4677734375 7.2421875 c 132 - 1.6201171875 7.486328125 1.8115234375 7.7041015625 2.0439453125 7.896484375 c 132 - 2.275390625 8.087890625 2.5498046875 8.240234375 2.8662109375 8.3515625 c 132 - 3.181640625 8.4638671875 3.5517578125 8.51953125 3.9755859375 8.51953125 c 260 - 4.3994140625 8.51953125 4.7802734375 8.4580078125 5.1162109375 8.333984375 c 132 - 5.4521484375 8.2099609375 5.7333984375 8.0380859375 5.9619140625 7.818359375 c 132 - 6.189453125 7.59765625 6.3642578125 7.3359375 6.4833984375 7.0322265625 c 132 - 6.603515625 6.7275390625 6.6640625 6.396484375 6.6640625 6.0361328125 c 4 - 6.6640625 5.7001953125 6.6123046875 5.3876953125 6.5078125 5.099609375 c 132 - 6.404296875 4.8115234375 6.259765625 4.5400390625 6.076171875 4.2841796875 c 132 - 5.8916015625 4.0283203125 5.677734375 3.7841796875 5.43359375 3.5517578125 c 132 - 5.189453125 3.3203125 4.931640625 3.083984375 4.66015625 2.84375 c 5 - 4.00390625 2.27994791667 3.34765625 1.71614583333 2.69140625 1.15234375 c 5 - 4.099609375 1.15234375 5.5078125 1.15234375 6.916015625 1.15234375 c 5 - 6.916015625 0.768229166667 6.916015625 0.384114583333 6.916015625 0 c 5 -EndSplineSet -EndUndoOperation -UndoOperation -Index: 1 -Type: 3 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -EndUndoOperation -UndoOperation -Index: 2 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet --6.0488281255 -10.8251953125 m 1 - -6.0488281255 -10.44921875 -6.0488281255 -10.0732421875 -6.0488281255 -9.697265625 c 1 - -5.264648438 -9.697265625 -4.4804687505 -9.697265625 -3.696289063 -9.697265625 c 1 - -3.696289063 -7.609375 -3.696289063 -5.521484375 -3.696289063 -3.43359375 c 1 - -3.7285156255 -3.43359375 -3.760742188 -3.43359375 -3.7929687505 -3.43359375 c 1 - -4.44075520883 -4.12532552083 -5.08854166717 -4.81705729167 -5.7363281255 -5.5087890625 c 1 - -6.01236979217 -5.26106770833 -6.28841145883 -5.01334635417 -6.5644531255 -4.765625 c 1 - -5.852539063 -3.99348958333 -5.1406250005 -3.22135416667 -4.428710938 -2.44921875 c 1 - -3.74055989633 -2.44921875 -3.05240885467 -2.44921875 -2.364257813 -2.44921875 c 1 - -2.364257813 -4.865234375 -2.364257813 -7.28125 -2.364257813 -9.697265625 c 1 - -1.68424479217 -9.697265625 -1.00423177133 -9.697265625 -0.3242187505 -9.697265625 c 1 - -0.3242187505 -10.0732421875 -0.3242187505 -10.44921875 -0.3242187505 -10.8251953125 c 1 - -2.2324218755 -10.8251953125 -4.1406250005 -10.8251953125 -6.0488281255 -10.8251953125 c 1 -6.4238281245 -5.5693359375 m 0 - 6.4238281245 -6.1767578125 6.331054687 -6.7490234375 6.147460937 -7.28515625 c 128 - 5.963867187 -7.8212890625 5.727539062 -8.3134765625 5.4394531245 -8.7607421875 c 128 - 5.151367187 -9.208984375 4.829101562 -9.609375 4.473632812 -9.9609375 c 128 - 4.1171874995 -10.3134765625 3.7675781245 -10.6015625 3.4238281245 -10.8251953125 c 1 - 2.82356770783 -10.8251953125 2.22330729117 -10.8251953125 1.6230468745 -10.8251953125 c 1 - 2.0957031245 -10.4814453125 2.5195312495 -10.1494140625 2.895507812 -9.8291015625 c 128 - 3.2714843745 -9.5087890625 3.5996093745 -9.181640625 3.879882812 -8.8447265625 c 128 - 4.159179687 -8.5087890625 4.393554687 -8.1533203125 4.581054687 -7.77734375 c 128 - 4.7695312495 -7.4013671875 4.915039062 -6.9892578125 5.0195312495 -6.541015625 c 1 - 4.99153645783 -6.533203125 4.96354166617 -6.525390625 4.9355468745 -6.517578125 c 1 - 4.8476562495 -6.685546875 4.745117187 -6.8427734375 4.629882812 -6.9912109375 c 128 - 4.5136718745 -7.1396484375 4.377929687 -7.26953125 4.221679687 -7.380859375 c 128 - 4.065429687 -7.4931640625 3.887695312 -7.5810546875 3.6874999995 -7.6455078125 c 128 - 3.487304687 -7.708984375 3.2558593745 -7.7412109375 2.991210937 -7.7412109375 c 0 - 2.639648437 -7.7412109375 2.313476562 -7.681640625 2.0136718745 -7.5615234375 c 128 - 1.713867187 -7.44140625 1.4531249995 -7.267578125 1.233398437 -7.0390625 c 128 - 1.0136718745 -6.8115234375 0.8417968745 -6.5390625 0.717773437 -6.2236328125 c 128 - 0.5937499995 -5.9072265625 0.5312499995 -5.548828125 0.5312499995 -5.1494140625 c 0 - 0.5312499995 -4.7333984375 0.6015624995 -4.349609375 0.741210937 -3.9970703125 c 128 - 0.881835937 -3.6455078125 1.079101562 -3.3447265625 1.3359374995 -3.09765625 c 128 - 1.5917968745 -2.849609375 1.899414062 -2.6552734375 2.2597656245 -2.515625 c 128 - 2.6191406245 -2.375 3.0234374995 -2.3056640625 3.471679687 -2.3056640625 c 0 - 3.9355468745 -2.3056640625 4.3496093745 -2.380859375 4.713867187 -2.533203125 c 128 - 5.077148437 -2.685546875 5.385742187 -2.9033203125 5.637695312 -3.1875 c 128 - 5.889648437 -3.4716796875 6.0839843745 -3.8134765625 6.219726562 -4.212890625 c 128 - 6.3554687495 -4.61328125 6.4238281245 -5.0654296875 6.4238281245 -5.5693359375 c 0 -3.471679687 -6.6494140625 m 256 - 3.959960937 -6.6494140625 4.3398437495 -6.51953125 4.6113281245 -6.2587890625 c 128 - 4.883789062 -5.9990234375 5.0195312495 -5.6171875 5.0195312495 -5.11328125 c 1 - 5.0195312495 -5.05729166667 5.0195312495 -5.00130208333 5.0195312495 -4.9453125 c 1 - 5.0195312495 -4.44140625 4.883789062 -4.0595703125 4.6113281245 -3.798828125 c 128 - 4.3398437495 -3.5390625 3.959960937 -3.4091796875 3.471679687 -3.4091796875 c 256 - 2.983398437 -3.4091796875 2.6035156245 -3.5390625 2.331054687 -3.798828125 c 128 - 2.059570312 -4.0595703125 1.9238281245 -4.44140625 1.9238281245 -4.9453125 c 1 - 1.9238281245 -5.00130208333 1.9238281245 -5.05729166667 1.9238281245 -5.11328125 c 1 - 1.9238281245 -5.6171875 2.059570312 -5.9990234375 2.331054687 -6.2587890625 c 128 - 2.6035156245 -6.51953125 2.983398437 -6.6494140625 3.471679687 -6.6494140625 c 256 --3.400390625 -0.1435546875 m 0 - -4.49609375 -0.1435546875 -5.3564453125 0.2255859375 -5.98046875 0.9658203125 c 128 - -6.6044921875 1.7060546875 -6.916015625 2.7802734375 -6.916015625 4.1884765625 c 0 - -6.916015625 4.8916015625 -6.8359375 5.51171875 -6.67578125 6.0478515625 c 128 - -6.5166015625 6.583984375 -6.2841796875 7.0361328125 -5.98046875 7.404296875 c 128 - -5.67578125 7.7724609375 -5.306640625 8.0498046875 -4.8701171875 8.23828125 c 128 - -4.4345703125 8.42578125 -3.9443359375 8.51953125 -3.400390625 8.51953125 c 0 - -2.671875 8.51953125 -2.0625 8.3603515625 -1.5703125 8.0400390625 c 128 - -1.078125 7.7197265625 -0.6923828125 7.248046875 -0.412109375 6.6240234375 c 1 - -0.7919921875 6.416015625 -1.171875 6.2080078125 -1.5517578125 6 c 1 - -1.6962890625 6.400390625 -1.91796875 6.7177734375 -2.2177734375 6.9541015625 c 128 - -2.5185546875 7.1904296875 -2.912109375 7.3076171875 -3.400390625 7.3076171875 c 0 - -4.0478515625 7.3076171875 -4.556640625 7.087890625 -4.923828125 6.6484375 c 128 - -5.2919921875 6.2080078125 -5.4765625 5.599609375 -5.4765625 4.82421875 c 1 - -5.4765625 4.40006510417 -5.4765625 3.97591145833 -5.4765625 3.5517578125 c 1 - -5.4765625 2.7763671875 -5.2919921875 2.16796875 -4.923828125 1.7275390625 c 128 - -4.556640625 1.2880859375 -4.0478515625 1.068359375 -3.400390625 1.068359375 c 0 - -2.896484375 1.068359375 -2.486328125 1.1982421875 -2.169921875 1.4580078125 c 128 - -1.8544921875 1.7177734375 -1.6201171875 2.0517578125 -1.4677734375 2.4599609375 c 1 - -1.10384114583 2.23990885417 -0.739908854167 2.01985677083 -0.3759765625 1.7998046875 c 1 - -0.65625 1.1923828125 -1.0478515625 0.7158203125 -1.5517578125 0.3720703125 c 128 - -2.056640625 0.0283203125 -2.671875 -0.1435546875 -3.400390625 -0.1435546875 c 0 -6.916015625 0 m 1 - 5.01985677083 -0 3.12369791667 0 1.2275390625 0 c 1 - 1.2275390625 0.431966145833 1.2275390625 0.863932291667 1.2275390625 1.2958984375 c 1 - 2.11979166667 2.091796875 3.01204427083 2.8876953125 3.904296875 3.68359375 c 1 - 4.328125 4.068359375 4.654296875 4.43359375 4.8818359375 4.7822265625 c 128 - 5.109375 5.1298828125 5.2236328125 5.49609375 5.2236328125 5.8798828125 c 1 - 5.2236328125 5.93196614583 5.2236328125 5.98404947917 5.2236328125 6.0361328125 c 1 - 5.2236328125 6.4443359375 5.1015625 6.763671875 4.857421875 6.99609375 c 128 - 4.6142578125 7.2275390625 4.2841796875 7.34375 3.8681640625 7.34375 c 0 - 3.6357421875 7.34375 3.43359375 7.3095703125 3.26171875 7.2421875 c 128 - 3.08984375 7.173828125 2.939453125 7.080078125 2.8115234375 6.9599609375 c 128 - 2.68359375 6.83984375 2.578125 6.7001953125 2.494140625 6.5400390625 c 128 - 2.41015625 6.3798828125 2.34375 6.2080078125 2.2958984375 6.0244140625 c 1 - 1.89973958333 6.17643229167 1.50358072917 6.32845052083 1.107421875 6.48046875 c 1 - 1.1962890625 6.744140625 1.3154296875 6.998046875 1.4677734375 7.2421875 c 128 - 1.6201171875 7.486328125 1.8115234375 7.7041015625 2.0439453125 7.896484375 c 128 - 2.275390625 8.087890625 2.5498046875 8.240234375 2.8662109375 8.3515625 c 128 - 3.181640625 8.4638671875 3.5517578125 8.51953125 3.9755859375 8.51953125 c 256 - 4.3994140625 8.51953125 4.7802734375 8.4580078125 5.1162109375 8.333984375 c 128 - 5.4521484375 8.2099609375 5.7333984375 8.0380859375 5.9619140625 7.818359375 c 128 - 6.189453125 7.59765625 6.3642578125 7.3359375 6.4833984375 7.0322265625 c 128 - 6.603515625 6.7275390625 6.6640625 6.396484375 6.6640625 6.0361328125 c 0 - 6.6640625 5.7001953125 6.6123046875 5.3876953125 6.5078125 5.099609375 c 128 - 6.404296875 4.8115234375 6.259765625 4.5400390625 6.076171875 4.2841796875 c 128 - 5.8916015625 4.0283203125 5.677734375 3.7841796875 5.43359375 3.5517578125 c 128 - 5.189453125 3.3203125 4.931640625 3.083984375 4.66015625 2.84375 c 1 - 4.00390625 2.27994791667 3.34765625 1.71614583333 2.69140625 1.15234375 c 1 - 4.099609375 1.15234375 5.5078125 1.15234375 6.916015625 1.15234375 c 1 - 6.916015625 0.768229166667 6.916015625 0.384114583333 6.916015625 0 c 1 --896 0 m 12 -NamedP: "baseline 1" - 896 0 l 1028 -EndSplineSet -EndUndoOperation -UndoOperation -Index: 3 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet --6.0488281255 -10.8251953125 m 1 - -6.0488281255 -10.44921875 -6.0488281255 -10.0732421875 -6.0488281255 -9.697265625 c 1 - -5.264648438 -9.697265625 -4.4804687505 -9.697265625 -3.696289063 -9.697265625 c 1 - -3.696289063 -7.609375 -3.696289063 -5.521484375 -3.696289063 -3.43359375 c 1 - -3.7285156255 -3.43359375 -3.760742188 -3.43359375 -3.7929687505 -3.43359375 c 1 - -4.44075520883 -4.12532552083 -5.08854166717 -4.81705729167 -5.7363281255 -5.5087890625 c 1 - -6.01236979217 -5.26106770833 -6.28841145883 -5.01334635417 -6.5644531255 -4.765625 c 1 - -5.852539063 -3.99348958333 -5.1406250005 -3.22135416667 -4.428710938 -2.44921875 c 1 - -3.74055989633 -2.44921875 -3.05240885467 -2.44921875 -2.364257813 -2.44921875 c 1 - -2.364257813 -4.865234375 -2.364257813 -7.28125 -2.364257813 -9.697265625 c 1 - -1.68424479217 -9.697265625 -1.00423177133 -9.697265625 -0.3242187505 -9.697265625 c 1 - -0.3242187505 -10.0732421875 -0.3242187505 -10.44921875 -0.3242187505 -10.8251953125 c 1 - -2.2324218755 -10.8251953125 -4.1406250005 -10.8251953125 -6.0488281255 -10.8251953125 c 1 -6.4238281245 -5.5693359375 m 0 - 6.4238281245 -6.1767578125 6.331054687 -6.7490234375 6.147460937 -7.28515625 c 128 - 5.963867187 -7.8212890625 5.727539062 -8.3134765625 5.4394531245 -8.7607421875 c 128 - 5.151367187 -9.208984375 4.829101562 -9.609375 4.473632812 -9.9609375 c 128 - 4.1171874995 -10.3134765625 3.7675781245 -10.6015625 3.4238281245 -10.8251953125 c 1 - 2.82356770783 -10.8251953125 2.22330729117 -10.8251953125 1.6230468745 -10.8251953125 c 1 - 2.0957031245 -10.4814453125 2.5195312495 -10.1494140625 2.895507812 -9.8291015625 c 128 - 3.2714843745 -9.5087890625 3.5996093745 -9.181640625 3.879882812 -8.8447265625 c 128 - 4.159179687 -8.5087890625 4.393554687 -8.1533203125 4.581054687 -7.77734375 c 128 - 4.7695312495 -7.4013671875 4.915039062 -6.9892578125 5.0195312495 -6.541015625 c 1 - 4.99153645783 -6.533203125 4.96354166617 -6.525390625 4.9355468745 -6.517578125 c 1 - 4.8476562495 -6.685546875 4.745117187 -6.8427734375 4.629882812 -6.9912109375 c 128 - 4.5136718745 -7.1396484375 4.377929687 -7.26953125 4.221679687 -7.380859375 c 128 - 4.065429687 -7.4931640625 3.887695312 -7.5810546875 3.6874999995 -7.6455078125 c 128 - 3.487304687 -7.708984375 3.2558593745 -7.7412109375 2.991210937 -7.7412109375 c 0 - 2.639648437 -7.7412109375 2.313476562 -7.681640625 2.0136718745 -7.5615234375 c 128 - 1.713867187 -7.44140625 1.4531249995 -7.267578125 1.233398437 -7.0390625 c 128 - 1.0136718745 -6.8115234375 0.8417968745 -6.5390625 0.717773437 -6.2236328125 c 128 - 0.5937499995 -5.9072265625 0.5312499995 -5.548828125 0.5312499995 -5.1494140625 c 0 - 0.5312499995 -4.7333984375 0.6015624995 -4.349609375 0.741210937 -3.9970703125 c 128 - 0.881835937 -3.6455078125 1.079101562 -3.3447265625 1.3359374995 -3.09765625 c 128 - 1.5917968745 -2.849609375 1.899414062 -2.6552734375 2.2597656245 -2.515625 c 128 - 2.6191406245 -2.375 3.0234374995 -2.3056640625 3.471679687 -2.3056640625 c 0 - 3.9355468745 -2.3056640625 4.3496093745 -2.380859375 4.713867187 -2.533203125 c 128 - 5.077148437 -2.685546875 5.385742187 -2.9033203125 5.637695312 -3.1875 c 128 - 5.889648437 -3.4716796875 6.0839843745 -3.8134765625 6.219726562 -4.212890625 c 128 - 6.3554687495 -4.61328125 6.4238281245 -5.0654296875 6.4238281245 -5.5693359375 c 0 -3.471679687 -6.6494140625 m 256 - 3.959960937 -6.6494140625 4.3398437495 -6.51953125 4.6113281245 -6.2587890625 c 128 - 4.883789062 -5.9990234375 5.0195312495 -5.6171875 5.0195312495 -5.11328125 c 1 - 5.0195312495 -5.05729166667 5.0195312495 -5.00130208333 5.0195312495 -4.9453125 c 1 - 5.0195312495 -4.44140625 4.883789062 -4.0595703125 4.6113281245 -3.798828125 c 128 - 4.3398437495 -3.5390625 3.959960937 -3.4091796875 3.471679687 -3.4091796875 c 256 - 2.983398437 -3.4091796875 2.6035156245 -3.5390625 2.331054687 -3.798828125 c 128 - 2.059570312 -4.0595703125 1.9238281245 -4.44140625 1.9238281245 -4.9453125 c 1 - 1.9238281245 -5.00130208333 1.9238281245 -5.05729166667 1.9238281245 -5.11328125 c 1 - 1.9238281245 -5.6171875 2.059570312 -5.9990234375 2.331054687 -6.2587890625 c 128 - 2.6035156245 -6.51953125 2.983398437 -6.6494140625 3.471679687 -6.6494140625 c 256 --3.400390625 -0.1435546875 m 0 - -4.49609375 -0.1435546875 -5.3564453125 0.2255859375 -5.98046875 0.9658203125 c 128 - -6.6044921875 1.7060546875 -6.916015625 2.7802734375 -6.916015625 4.1884765625 c 0 - -6.916015625 4.8916015625 -6.8359375 5.51171875 -6.67578125 6.0478515625 c 128 - -6.5166015625 6.583984375 -6.2841796875 7.0361328125 -5.98046875 7.404296875 c 128 - -5.67578125 7.7724609375 -5.306640625 8.0498046875 -4.8701171875 8.23828125 c 128 - -4.4345703125 8.42578125 -3.9443359375 8.51953125 -3.400390625 8.51953125 c 0 - -2.671875 8.51953125 -2.0625 8.3603515625 -1.5703125 8.0400390625 c 128 - -1.078125 7.7197265625 -0.6923828125 7.248046875 -0.412109375 6.6240234375 c 1 - -0.7919921875 6.416015625 -1.171875 6.2080078125 -1.5517578125 6 c 1 - -1.6962890625 6.400390625 -1.91796875 6.7177734375 -2.2177734375 6.9541015625 c 128 - -2.5185546875 7.1904296875 -2.912109375 7.3076171875 -3.400390625 7.3076171875 c 0 - -4.0478515625 7.3076171875 -4.556640625 7.087890625 -4.923828125 6.6484375 c 128 - -5.2919921875 6.2080078125 -5.4765625 5.599609375 -5.4765625 4.82421875 c 1 - -5.4765625 4.40006510417 -5.4765625 3.97591145833 -5.4765625 3.5517578125 c 1 - -5.4765625 2.7763671875 -5.2919921875 2.16796875 -4.923828125 1.7275390625 c 128 - -4.556640625 1.2880859375 -4.0478515625 1.068359375 -3.400390625 1.068359375 c 0 - -2.896484375 1.068359375 -2.486328125 1.1982421875 -2.169921875 1.4580078125 c 128 - -1.8544921875 1.7177734375 -1.6201171875 2.0517578125 -1.4677734375 2.4599609375 c 1 - -1.10384114583 2.23990885417 -0.739908854167 2.01985677083 -0.3759765625 1.7998046875 c 1 - -0.65625 1.1923828125 -1.0478515625 0.7158203125 -1.5517578125 0.3720703125 c 128 - -2.056640625 0.0283203125 -2.671875 -0.1435546875 -3.400390625 -0.1435546875 c 0 -6.916015625 0 m 1 - 5.01985677083 -0 3.12369791667 0 1.2275390625 0 c 1 - 1.2275390625 0.431966145833 1.2275390625 0.863932291667 1.2275390625 1.2958984375 c 1 - 2.11979166667 2.091796875 3.01204427083 2.8876953125 3.904296875 3.68359375 c 1 - 4.328125 4.068359375 4.654296875 4.43359375 4.8818359375 4.7822265625 c 128 - 5.109375 5.1298828125 5.2236328125 5.49609375 5.2236328125 5.8798828125 c 1 - 5.2236328125 5.93196614583 5.2236328125 5.98404947917 5.2236328125 6.0361328125 c 1 - 5.2236328125 6.4443359375 5.1015625 6.763671875 4.857421875 6.99609375 c 128 - 4.6142578125 7.2275390625 4.2841796875 7.34375 3.8681640625 7.34375 c 0 - 3.6357421875 7.34375 3.43359375 7.3095703125 3.26171875 7.2421875 c 128 - 3.08984375 7.173828125 2.939453125 7.080078125 2.8115234375 6.9599609375 c 128 - 2.68359375 6.83984375 2.578125 6.7001953125 2.494140625 6.5400390625 c 128 - 2.41015625 6.3798828125 2.34375 6.2080078125 2.2958984375 6.0244140625 c 1 - 1.89973958333 6.17643229167 1.50358072917 6.32845052083 1.107421875 6.48046875 c 1 - 1.1962890625 6.744140625 1.3154296875 6.998046875 1.4677734375 7.2421875 c 128 - 1.6201171875 7.486328125 1.8115234375 7.7041015625 2.0439453125 7.896484375 c 128 - 2.275390625 8.087890625 2.5498046875 8.240234375 2.8662109375 8.3515625 c 128 - 3.181640625 8.4638671875 3.5517578125 8.51953125 3.9755859375 8.51953125 c 256 - 4.3994140625 8.51953125 4.7802734375 8.4580078125 5.1162109375 8.333984375 c 128 - 5.4521484375 8.2099609375 5.7333984375 8.0380859375 5.9619140625 7.818359375 c 128 - 6.189453125 7.59765625 6.3642578125 7.3359375 6.4833984375 7.0322265625 c 128 - 6.603515625 6.7275390625 6.6640625 6.396484375 6.6640625 6.0361328125 c 0 - 6.6640625 5.7001953125 6.6123046875 5.3876953125 6.5078125 5.099609375 c 128 - 6.404296875 4.8115234375 6.259765625 4.5400390625 6.076171875 4.2841796875 c 128 - 5.8916015625 4.0283203125 5.677734375 3.7841796875 5.43359375 3.5517578125 c 128 - 5.189453125 3.3203125 4.931640625 3.083984375 4.66015625 2.84375 c 1 - 4.00390625 2.27994791667 3.34765625 1.71614583333 2.69140625 1.15234375 c 1 - 4.099609375 1.15234375 5.5078125 1.15234375 6.916015625 1.15234375 c 1 - 6.916015625 0.768229166667 6.916015625 0.384114583333 6.916015625 0 c 1 --717.389648438 -10.8251953125 m 12 -NamedP: "baseline 2" - 717.249023438 -10.8251953125 l 1028 --896 0 m 8 -NamedP: "baseline 1" - 896 0 l 1024 -EndSplineSet -EndUndoOperation -UndoOperation -Index: 4 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet --3.400390625 -0.1435546875 m 0 - -4.49609375 -0.1435546875 -5.3564453125 0.2255859375 -5.98046875 0.9658203125 c 128 - -6.6044921875 1.7060546875 -6.916015625 2.7802734375 -6.916015625 4.1884765625 c 0 - -6.916015625 4.8916015625 -6.8359375 5.51171875 -6.67578125 6.0478515625 c 128 - -6.5166015625 6.583984375 -6.2841796875 7.0361328125 -5.98046875 7.404296875 c 128 - -5.67578125 7.7724609375 -5.306640625 8.0498046875 -4.8701171875 8.23828125 c 128 - -4.4345703125 8.42578125 -3.9443359375 8.51953125 -3.400390625 8.51953125 c 0 - -2.671875 8.51953125 -2.0625 8.3603515625 -1.5703125 8.0400390625 c 128 - -1.078125 7.7197265625 -0.6923828125 7.248046875 -0.412109375 6.6240234375 c 1 - -0.7919921875 6.416015625 -1.171875 6.2080078125 -1.5517578125 6 c 1 - -1.6962890625 6.400390625 -1.91796875 6.7177734375 -2.2177734375 6.9541015625 c 128 - -2.5185546875 7.1904296875 -2.912109375 7.3076171875 -3.400390625 7.3076171875 c 0 - -4.0478515625 7.3076171875 -4.556640625 7.087890625 -4.923828125 6.6484375 c 128 - -5.2919921875 6.2080078125 -5.4765625 5.599609375 -5.4765625 4.82421875 c 1 - -5.4765625 4.40006510417 -5.4765625 3.97591145833 -5.4765625 3.5517578125 c 1 - -5.4765625 2.7763671875 -5.2919921875 2.16796875 -4.923828125 1.7275390625 c 128 - -4.556640625 1.2880859375 -4.0478515625 1.068359375 -3.400390625 1.068359375 c 0 - -2.896484375 1.068359375 -2.486328125 1.1982421875 -2.169921875 1.4580078125 c 128 - -1.8544921875 1.7177734375 -1.6201171875 2.0517578125 -1.4677734375 2.4599609375 c 1 - -1.10384114583 2.23990885417 -0.739908854167 2.01985677083 -0.3759765625 1.7998046875 c 1 - -0.65625 1.1923828125 -1.0478515625 0.7158203125 -1.5517578125 0.3720703125 c 128 - -2.056640625 0.0283203125 -2.671875 -0.1435546875 -3.400390625 -0.1435546875 c 0 -6.916015625 0 m 1 - 5.01985677083 -0 3.12369791667 0 1.2275390625 0 c 1 - 1.2275390625 0.431966145833 1.2275390625 0.863932291667 1.2275390625 1.2958984375 c 1 - 2.11979166667 2.091796875 3.01204427083 2.8876953125 3.904296875 3.68359375 c 1 - 4.328125 4.068359375 4.654296875 4.43359375 4.8818359375 4.7822265625 c 128 - 5.109375 5.1298828125 5.2236328125 5.49609375 5.2236328125 5.8798828125 c 1 - 5.2236328125 5.93196614583 5.2236328125 5.98404947917 5.2236328125 6.0361328125 c 1 - 5.2236328125 6.4443359375 5.1015625 6.763671875 4.857421875 6.99609375 c 128 - 4.6142578125 7.2275390625 4.2841796875 7.34375 3.8681640625 7.34375 c 0 - 3.6357421875 7.34375 3.43359375 7.3095703125 3.26171875 7.2421875 c 128 - 3.08984375 7.173828125 2.939453125 7.080078125 2.8115234375 6.9599609375 c 128 - 2.68359375 6.83984375 2.578125 6.7001953125 2.494140625 6.5400390625 c 128 - 2.41015625 6.3798828125 2.34375 6.2080078125 2.2958984375 6.0244140625 c 1 - 1.89973958333 6.17643229167 1.50358072917 6.32845052083 1.107421875 6.48046875 c 1 - 1.1962890625 6.744140625 1.3154296875 6.998046875 1.4677734375 7.2421875 c 128 - 1.6201171875 7.486328125 1.8115234375 7.7041015625 2.0439453125 7.896484375 c 128 - 2.275390625 8.087890625 2.5498046875 8.240234375 2.8662109375 8.3515625 c 128 - 3.181640625 8.4638671875 3.5517578125 8.51953125 3.9755859375 8.51953125 c 256 - 4.3994140625 8.51953125 4.7802734375 8.4580078125 5.1162109375 8.333984375 c 128 - 5.4521484375 8.2099609375 5.7333984375 8.0380859375 5.9619140625 7.818359375 c 128 - 6.189453125 7.59765625 6.3642578125 7.3359375 6.4833984375 7.0322265625 c 128 - 6.603515625 6.7275390625 6.6640625 6.396484375 6.6640625 6.0361328125 c 0 - 6.6640625 5.7001953125 6.6123046875 5.3876953125 6.5078125 5.099609375 c 128 - 6.404296875 4.8115234375 6.259765625 4.5400390625 6.076171875 4.2841796875 c 128 - 5.8916015625 4.0283203125 5.677734375 3.7841796875 5.43359375 3.5517578125 c 128 - 5.189453125 3.3203125 4.931640625 3.083984375 4.66015625 2.84375 c 1 - 4.00390625 2.27994791667 3.34765625 1.71614583333 2.69140625 1.15234375 c 1 - 4.099609375 1.15234375 5.5078125 1.15234375 6.916015625 1.15234375 c 1 - 6.916015625 0.768229166667 6.916015625 0.384114583333 6.916015625 0 c 1 --717.389648438 -10.8251953125 m 12 -NamedP: "baseline 2" - 717.249023438 -10.8251953125 l 1028 --896 0 m 8 -NamedP: "baseline 1" - 896 0 l 1024 -EndSplineSet -EndUndoOperation -UndoOperation -Index: 5 -Type: 1 -WasModified: 1 -WasOrder2: 0 -Layer: 2 -Width: 1792 -VWidth: 1792 -LBearingChange: 0 -UnicodeEnc: 0 -InstructionsLength: 0 -SplineSet --717.389648438 -10.8251953125 m 8 -NamedP: "baseline 2" - 717.249023438 -10.8251953125 l 1024 --896 0 m 12 -NamedP: "baseline 1" - 896 0 l 1028 -EndSplineSet -EndUndoOperation -UndoOperation -Index: 6 -Type: 3 -WasModified: 0 -WasOrder2: 0 -Layer: 2 -EndUndoOperation -EndUndoes -Redoes -EndRedoes -EndUndoRedoHistory -Fore -SplineSet -412.09375 -247.515625 m 1 - 412.09375 -217.4375 412.09375 -187.359375 412.09375 -157.28125 c 1 - 474.828125 -157.28125 537.5625 -157.28125 600.296875 -157.28125 c 1 - 600.296875 9.75 600.296875 176.78125 600.296875 343.8125 c 1 - 597.71875 343.8125 595.140625 343.8125 592.5625 343.8125 c 1 - 540.739257812 288.473632812 488.916992188 233.135742188 437.09375 177.796875 c 1 - 415.010742188 197.614257812 392.926757812 217.432617188 370.84375 237.25 c 1 - 427.796875 299.020507812 484.75 360.791992188 541.703125 422.5625 c 1 - 596.754882812 422.5625 651.807617188 422.5625 706.859375 422.5625 c 1 - 706.859375 229.28125 706.859375 36 706.859375 -157.28125 c 1 - 761.260742188 -157.28125 815.661132812 -157.28125 870.0625 -157.28125 c 1 - 870.0625 -187.359375 870.0625 -217.4375 870.0625 -247.515625 c 1 - 717.40625 -247.515625 564.75 -247.515625 412.09375 -247.515625 c 1 -1409.90625 172.953125 m 0 - 1409.90625 124.359375 1402.484375 78.578125 1387.796875 35.6875 c 128 - 1373.109375 -7.203125 1354.203125 -46.578125 1331.15625 -82.359375 c 128 - 1308.109375 -118.21875 1282.328125 -150.25 1253.890625 -178.375 c 128 - 1225.375 -206.578125 1197.40625 -229.625 1169.90625 -247.515625 c 1 - 1121.88574219 -247.515625 1073.86425781 -247.515625 1025.84375 -247.515625 c 1 - 1063.65625 -220.015625 1097.5625 -193.453125 1127.640625 -167.828125 c 128 - 1157.71875 -142.203125 1183.96875 -116.03125 1206.390625 -89.078125 c 128 - 1228.734375 -62.203125 1247.484375 -33.765625 1262.484375 -3.6875 c 128 - 1277.5625 26.390625 1289.203125 59.359375 1297.5625 95.21875 c 1 - 1295.32324219 95.84375 1293.08300781 96.46875 1290.84375 97.09375 c 1 - 1283.8125 83.65625 1275.609375 71.078125 1266.390625 59.203125 c 128 - 1257.09375 47.328125 1246.234375 36.9375 1233.734375 28.03125 c 128 - 1221.234375 19.046875 1207.015625 12.015625 1191 6.859375 c 128 - 1174.984375 1.78125 1156.46875 -0.796875 1135.296875 -0.796875 c 0 - 1107.171875 -0.796875 1081.078125 3.96875 1057.09375 13.578125 c 128 - 1033.109375 23.1875 1012.25 37.09375 994.671875 55.375 c 128 - 977.09375 73.578125 963.34375 95.375 953.421875 120.609375 c 128 - 943.5 145.921875 938.5 174.59375 938.5 206.546875 c 0 - 938.5 239.828125 944.125 270.53125 955.296875 298.734375 c 128 - 966.546875 326.859375 982.328125 350.921875 1002.875 370.6875 c 128 - 1023.34375 390.53125 1047.953125 406.078125 1076.78125 417.25 c 128 - 1105.53125 428.5 1137.875 434.046875 1173.734375 434.046875 c 0 - 1210.84375 434.046875 1243.96875 428.03125 1273.109375 415.84375 c 128 - 1302.171875 403.65625 1326.859375 386.234375 1347.015625 363.5 c 128 - 1367.171875 340.765625 1382.71875 313.421875 1393.578125 281.46875 c 128 - 1404.4375 249.4375 1409.90625 213.265625 1409.90625 172.953125 c 0 -1173.734375 86.546875 m 256 - 1212.796875 86.546875 1243.1875 96.9375 1264.90625 117.796875 c 128 - 1286.703125 138.578125 1297.5625 169.125 1297.5625 209.4375 c 1 - 1297.5625 213.916992188 1297.5625 218.395507812 1297.5625 222.875 c 1 - 1297.5625 263.1875 1286.703125 293.734375 1264.90625 314.59375 c 128 - 1243.1875 335.375 1212.796875 345.765625 1173.734375 345.765625 c 256 - 1134.671875 345.765625 1104.28125 335.375 1082.484375 314.59375 c 128 - 1060.765625 293.734375 1049.90625 263.1875 1049.90625 222.875 c 1 - 1049.90625 218.395507812 1049.90625 213.916992188 1049.90625 209.4375 c 1 - 1049.90625 169.125 1060.765625 138.578125 1082.484375 117.796875 c 128 - 1104.28125 96.9375 1134.671875 86.546875 1173.734375 86.546875 c 256 -623.96875 607.015625 m 0 - 536.3125 607.015625 467.484375 636.546875 417.5625 695.765625 c 128 - 367.640625 754.984375 342.71875 840.921875 342.71875 953.578125 c 0 - 342.71875 1009.828125 349.125 1059.4375 361.9375 1102.328125 c 128 - 374.671875 1145.21875 393.265625 1181.390625 417.5625 1210.84375 c 128 - 441.9375 1240.296875 471.46875 1262.484375 506.390625 1277.5625 c 128 - 541.234375 1292.5625 580.453125 1300.0625 623.96875 1300.0625 c 0 - 682.25 1300.0625 731 1287.328125 770.375 1261.703125 c 128 - 809.75 1236.078125 840.609375 1198.34375 863.03125 1148.421875 c 1 - 832.640625 1131.78125 802.25 1115.140625 771.859375 1098.5 c 1 - 760.296875 1130.53125 742.5625 1155.921875 718.578125 1174.828125 c 128 - 694.515625 1193.734375 663.03125 1203.109375 623.96875 1203.109375 c 0 - 572.171875 1203.109375 531.46875 1185.53125 502.09375 1150.375 c 128 - 472.640625 1115.140625 457.875 1066.46875 457.875 1004.4375 c 1 - 457.875 970.504882812 457.875 936.573242188 457.875 902.640625 c 1 - 457.875 840.609375 472.640625 791.9375 502.09375 756.703125 c 128 - 531.46875 721.546875 572.171875 703.96875 623.96875 703.96875 c 0 - 664.28125 703.96875 697.09375 714.359375 722.40625 735.140625 c 128 - 747.640625 755.921875 766.390625 782.640625 778.578125 815.296875 c 1 - 807.692382812 797.692382812 836.807617188 780.088867188 865.921875 762.484375 c 1 - 843.5 713.890625 812.171875 675.765625 771.859375 648.265625 c 128 - 731.46875 620.765625 682.25 607.015625 623.96875 607.015625 c 0 -1449.28125 618.5 m 1 - 1297.58886719 618.5 1145.89550781 618.5 994.203125 618.5 c 1 - 994.203125 653.057617188 994.203125 687.614257812 994.203125 722.171875 c 1 - 1065.58300781 785.84375 1136.96386719 849.515625 1208.34375 913.1875 c 1 - 1242.25 943.96875 1268.34375 973.1875 1286.546875 1001.078125 c 128 - 1304.75 1028.890625 1313.890625 1058.1875 1313.890625 1088.890625 c 1 - 1313.890625 1093.05761719 1313.890625 1097.22363281 1313.890625 1101.390625 c 1 - 1313.890625 1134.046875 1304.125 1159.59375 1284.59375 1178.1875 c 128 - 1265.140625 1196.703125 1238.734375 1206 1205.453125 1206 c 0 - 1186.859375 1206 1170.6875 1203.265625 1156.9375 1197.875 c 128 - 1143.1875 1192.40625 1131.15625 1184.90625 1120.921875 1175.296875 c 128 - 1110.6875 1165.6875 1102.25 1154.515625 1095.53125 1141.703125 c 128 - 1088.8125 1128.890625 1083.5 1115.140625 1079.671875 1100.453125 c 1 - 1047.97949219 1112.61425781 1016.28613281 1124.77636719 984.59375 1136.9375 c 1 - 991.703125 1158.03125 1001.234375 1178.34375 1013.421875 1197.875 c 128 - 1025.609375 1217.40625 1040.921875 1234.828125 1059.515625 1250.21875 c 128 - 1078.03125 1265.53125 1099.984375 1277.71875 1125.296875 1286.625 c 128 - 1150.53125 1295.609375 1180.140625 1300.0625 1214.046875 1300.0625 c 256 - 1247.953125 1300.0625 1278.421875 1295.140625 1305.296875 1285.21875 c 128 - 1332.171875 1275.296875 1354.671875 1261.546875 1372.953125 1243.96875 c 128 - 1391.15625 1226.3125 1405.140625 1205.375 1414.671875 1181.078125 c 128 - 1424.28125 1156.703125 1429.125 1130.21875 1429.125 1101.390625 c 0 - 1429.125 1074.515625 1424.984375 1049.515625 1416.625 1026.46875 c 128 - 1408.34375 1003.421875 1396.78125 981.703125 1382.09375 961.234375 c 128 - 1367.328125 940.765625 1350.21875 921.234375 1330.6875 902.640625 c 128 - 1311.15625 884.125 1290.53125 865.21875 1268.8125 846 c 1 - 1216.3125 800.895507812 1163.8125 755.791992188 1111.3125 710.6875 c 1 - 1223.96875 710.6875 1336.625 710.6875 1449.28125 710.6875 c 1 - 1449.28125 679.958007812 1449.28125 649.229492188 1449.28125 618.5 c 1 -EndSplineSet -EndChar EndChars EndSplineFont diff --git a/res/icons.ttf b/res/icons.ttf index 2f22c8675..949887040 100644 Binary files a/res/icons.ttf and b/res/icons.ttf differ diff --git a/res/releaseReadme/stable-linux.txt b/res/releaseReadme/stable-linux.txt new file mode 100644 index 000000000..3eb6e77d9 --- /dev/null +++ b/res/releaseReadme/stable-linux.txt @@ -0,0 +1,5 @@ +# Furnace (chiptune tracker) + +thank you for downloading Furnace! I hope you enjoy using it. + +extract this archive, and run `furnace` to get started. diff --git a/res/releaseReadme/stable-mac.txt b/res/releaseReadme/stable-mac.txt new file mode 100644 index 000000000..fb84fb870 --- /dev/null +++ b/res/releaseReadme/stable-mac.txt @@ -0,0 +1,15 @@ +# Furnace (chiptune tracker) + +thank you for downloading Furnace! I hope you enjoy using it. + +move Furnace to Applications (or some other place). +if you are using a recent version of macOS, you may get an error saying that Furnace is damaged. +in that case, open Terminal, and type this: + +``` +xattr -d com.apple.quarantine /path/to/Furnace.app +``` + +(replace `/path/to/Furnace.app` with the path where Furnace.app is located, e.g. `/Applications/Furnace.app`) + +you may need to reboot after doing this before launching Furnace. diff --git a/res/releaseReadme/stable-win.txt b/res/releaseReadme/stable-win.txt new file mode 100644 index 000000000..22eed14ca --- /dev/null +++ b/res/releaseReadme/stable-win.txt @@ -0,0 +1,5 @@ +# Furnace (chiptune tracker) + +thank you for downloading Furnace! I hope you enjoy using it. + +extract this archive, and run furnace.exe to get started. diff --git a/res/releaseReadme/unstable-other.txt b/res/releaseReadme/unstable-other.txt new file mode 100644 index 000000000..2b042a2bc --- /dev/null +++ b/res/releaseReadme/unstable-other.txt @@ -0,0 +1,6 @@ +# unstable build notice + +this is a dev build (also known as "unstable", "artifact" or "nightly"). +it may contain work-in-progress features and/or bug fixes. + +no compatibility is guaranteed between unstable and stable - you have been warned! diff --git a/res/releaseReadme/unstable-win.txt b/res/releaseReadme/unstable-win.txt new file mode 100644 index 000000000..2ca438fbb --- /dev/null +++ b/res/releaseReadme/unstable-win.txt @@ -0,0 +1,11 @@ +# unstable build notice + +this is a dev build (also known as "unstable", "artifact" or "nightly"). +it may contain work-in-progress features and/or bug fixes. + +no compatibility is guaranteed between unstable and stable - you have been warned! + +# the .pdb file + +YOU SHALL COPY THIS FILE ALONGSIDE furnace.exe. it contains debug information which is vital in the moment of a crash. +failure to copy this file will result in useless backtraces (furnace_crash.txt) and therefore hinder me from fixing any crashes. diff --git a/scripts/release-linux.sh b/scripts/release-linux.sh index 030f8259f..0c744296f 100755 --- a/scripts/release-linux.sh +++ b/scripts/release-linux.sh @@ -14,7 +14,7 @@ fi cd linuxbuild -cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-O3" -DCMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wno-unused-parameter -Werror" .. || exit 1 +cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-O3" -DCMAKE_CXX_FLAGS="-O3 -Wall -Wextra -Wno-unused-parameter -Werror" -DWITH_DEMOS=ON -DWITH_INSTRUMENTS=ON -DWITH_WAVETABLES=ON .. || exit 1 make -j4 || exit 1 cd .. diff --git a/scripts/release-win32.sh b/scripts/release-win32.sh index fdd0b4c6f..b0c1c2ff6 100755 --- a/scripts/release-win32.sh +++ b/scripts/release-win32.sh @@ -15,7 +15,7 @@ fi cd win32build # TODO: potential Arch-ism? -i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -Werror" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF .. || exit 1 +i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2 -march=i686" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type -march=i686" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=OFF -DWITH_RENDER_DX11=ON .. || exit 1 make -j8 || exit 1 cd .. diff --git a/scripts/release-winxp.sh b/scripts/release-winxp.sh new file mode 100755 index 000000000..59604ea36 --- /dev/null +++ b/scripts/release-winxp.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# make Windows release +# this script shall be run from Arch Linux with MinGW installed! + +if [ ! -e /tmp/furnace ]; then + ln -s "$PWD" /tmp/furnace || exit 1 +fi + +cd /tmp/furnace + +if [ ! -e xpbuild ]; then + mkdir xpbuild || exit 1 +fi + +cd xpbuild + +# TODO: potential Arch-ism? +i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_FLAGS="-O2" -DCMAKE_CXX_FLAGS="-O2 -Wall -Wextra -Wno-unused-parameter -Wno-cast-function-type" -DBUILD_SHARED_LIBS=OFF -DSUPPORT_XP=ON -DWITH_RENDER_DX11=OFF .. || exit 1 +make -j8 || exit 1 + +cd .. + +mkdir -p release/winxp || exit 1 +cd release/winxp + +cp ../../LICENSE LICENSE.txt || exit 1 +cp ../../xpbuild/furnace.exe . || exit 1 +cp ../../README.md README.txt || exit 1 +cp -r ../../papers papers || exit 1 +cp -r ../../doc doc || exit 1 +cp -r ../../demos demos || exit 1 +cp -r ../../instruments instruments || exit 1 +cp -r ../../wavetables wavetables || exit 1 + +i686-w64-mingw32-strip -s furnace.exe || exit 1 + +# patch to remove GetTickCount64 +xxd -c 256 -ps furnace.exe | sed "s/4765745469636b436f756e743634/4765745469636b436f756e740000/g" | xxd -ps -r > furnace-patched.exe +rm furnace.exe +mv furnace-patched.exe furnace.exe + +zip -r furnace.zip LICENSE.txt furnace.exe README.txt papers doc demos instruments wavetables + +furName=$(git describe --tags | sed "s/v0/0/") + +mv furnace.zip furnace-"$furName"-win32-XP-ONLY.zip diff --git a/src/audio/sdlAudio.cpp b/src/audio/sdlAudio.cpp index 5d07921e9..ddbe85947 100644 --- a/src/audio/sdlAudio.cpp +++ b/src/audio/sdlAudio.cpp @@ -127,6 +127,7 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { ac.callback=taSDLProcess; ac.userdata=this; + logV("opening audio device..."); ai=SDL_OpenAudioDevice(request.deviceName.empty()?NULL:request.deviceName.c_str(),0,&ac,&ar,0); if (ai==0) { logE("could not open audio device: %s",SDL_GetError()); @@ -147,6 +148,8 @@ bool TAAudioSDL::init(TAAudioDesc& request, TAAudioDesc& response) { desc.bufsize=ar.samples; desc.fragments=1; + logV("got info: %d channels, %d bufsize",desc.outChans,desc.bufsize); + if (desc.outChans>0) { outBufs=new float*[desc.outChans]; for (int i=0; i255) { \ + chanStream[x]->writeC(0xfc); \ + chanStream[x]->writeS(tick-lastTick[x]); \ + } else if (tick-lastTick[x]>1) { \ + delayPopularity[tick-lastTick[x]]++; \ + chanStream[x]->writeC(0xfd); \ + chanStream[x]->writeC(tick-lastTick[x]); \ + } else if (tick-lastTick[x]>0) { \ + chanStream[x]->writeC(0xfe); \ + } \ + lastTick[x]=tick; \ + } \ + } else { \ + if (!wroteTickGlobal) { \ + wroteTickGlobal=true; \ + w->writeText(fmt::sprintf(">> TICK %d\n",tick)); \ + } \ + } + +void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { + switch (c.cmd) { + case DIV_CMD_NOTE_ON: + if (c.value==DIV_NOTE_NULL) { + w->writeC(0xb4); + } else { + w->writeC(CLAMP(c.value+60,0,0xb3)); + } + break; + case DIV_CMD_NOTE_OFF: + case DIV_CMD_NOTE_OFF_ENV: + case DIV_CMD_ENV_RELEASE: + case DIV_CMD_INSTRUMENT: + case DIV_CMD_PANNING: + case DIV_CMD_PRE_PORTA: + case DIV_CMD_HINT_VIBRATO: + case DIV_CMD_HINT_VIBRATO_RANGE: + case DIV_CMD_HINT_VIBRATO_SHAPE: + case DIV_CMD_HINT_PITCH: + case DIV_CMD_HINT_ARPEGGIO: + case DIV_CMD_HINT_VOLUME: + case DIV_CMD_HINT_PORTA: + case DIV_CMD_HINT_VOL_SLIDE: + case DIV_CMD_HINT_LEGATO: + w->writeC((unsigned char)c.cmd+0xb4); + break; + default: + w->writeC(0xf0); // unoptimized extended command + w->writeC(c.cmd); + break; + } + switch (c.cmd) { + case DIV_CMD_HINT_LEGATO: + if (c.value==DIV_NOTE_NULL) { + w->writeC(0xff); + } else { + w->writeC(c.value+60); + } + break; + case DIV_CMD_NOTE_ON: + case DIV_CMD_NOTE_OFF: + case DIV_CMD_NOTE_OFF_ENV: + case DIV_CMD_ENV_RELEASE: + break; + case DIV_CMD_INSTRUMENT: + case DIV_CMD_HINT_VIBRATO_RANGE: + case DIV_CMD_HINT_VIBRATO_SHAPE: + case DIV_CMD_HINT_PITCH: + case DIV_CMD_HINT_VOLUME: + w->writeC(c.value); + break; + case DIV_CMD_PANNING: + case DIV_CMD_HINT_VIBRATO: + case DIV_CMD_HINT_ARPEGGIO: + case DIV_CMD_HINT_PORTA: + w->writeC(c.value); + w->writeC(c.value2); + break; + case DIV_CMD_PRE_PORTA: + w->writeC((c.value?0x80:0)|(c.value2?0x40:0)); + break; + case DIV_CMD_HINT_VOL_SLIDE: + w->writeS(c.value); + break; + case DIV_CMD_SAMPLE_MODE: + case DIV_CMD_SAMPLE_FREQ: + case DIV_CMD_SAMPLE_BANK: + case DIV_CMD_SAMPLE_POS: + case DIV_CMD_SAMPLE_DIR: + case DIV_CMD_FM_HARD_RESET: + case DIV_CMD_FM_LFO: + case DIV_CMD_FM_LFO_WAVE: + case DIV_CMD_FM_FB: + case DIV_CMD_FM_EXTCH: + case DIV_CMD_FM_AM_DEPTH: + case DIV_CMD_FM_PM_DEPTH: + case DIV_CMD_STD_NOISE_FREQ: + case DIV_CMD_STD_NOISE_MODE: + case DIV_CMD_WAVE: + case DIV_CMD_GB_SWEEP_TIME: + case DIV_CMD_GB_SWEEP_DIR: + case DIV_CMD_PCE_LFO_MODE: + case DIV_CMD_PCE_LFO_SPEED: + case DIV_CMD_NES_DMC: + case DIV_CMD_C64_CUTOFF: + case DIV_CMD_C64_RESONANCE: + case DIV_CMD_C64_FILTER_MODE: + case DIV_CMD_C64_RESET_TIME: + case DIV_CMD_C64_RESET_MASK: + case DIV_CMD_C64_FILTER_RESET: + case DIV_CMD_C64_DUTY_RESET: + case DIV_CMD_C64_EXTENDED: + case DIV_CMD_AY_ENVELOPE_SET: + case DIV_CMD_AY_ENVELOPE_LOW: + case DIV_CMD_AY_ENVELOPE_HIGH: + case DIV_CMD_AY_ENVELOPE_SLIDE: + case DIV_CMD_AY_NOISE_MASK_AND: + case DIV_CMD_AY_NOISE_MASK_OR: + case DIV_CMD_AY_AUTO_ENVELOPE: + case DIV_CMD_FDS_MOD_DEPTH: + case DIV_CMD_FDS_MOD_HIGH: + case DIV_CMD_FDS_MOD_LOW: + case DIV_CMD_FDS_MOD_POS: + case DIV_CMD_FDS_MOD_WAVE: + case DIV_CMD_SAA_ENVELOPE: + case DIV_CMD_AMIGA_FILTER: + case DIV_CMD_AMIGA_AM: + case DIV_CMD_AMIGA_PM: + case DIV_CMD_MACRO_OFF: + case DIV_CMD_MACRO_ON: + case DIV_CMD_HINT_ARP_TIME: + w->writeC(1); // length + w->writeC(c.value); + break; + case DIV_CMD_FM_TL: + case DIV_CMD_FM_AM: + case DIV_CMD_FM_AR: + case DIV_CMD_FM_DR: + case DIV_CMD_FM_SL: + case DIV_CMD_FM_D2R: + case DIV_CMD_FM_RR: + case DIV_CMD_FM_DT: + case DIV_CMD_FM_DT2: + case DIV_CMD_FM_RS: + case DIV_CMD_FM_KSR: + case DIV_CMD_FM_VIB: + case DIV_CMD_FM_SUS: + case DIV_CMD_FM_WS: + case DIV_CMD_FM_SSG: + case DIV_CMD_FM_REV: + case DIV_CMD_FM_EG_SHIFT: + case DIV_CMD_FM_MULT: + case DIV_CMD_FM_FINE: + case DIV_CMD_AY_IO_WRITE: + case DIV_CMD_AY_AUTO_PWM: + case DIV_CMD_SURROUND_PANNING: + w->writeC(2); // length + w->writeC(c.value); + w->writeC(c.value2); + break; + case DIV_CMD_C64_FINE_DUTY: + case DIV_CMD_C64_FINE_CUTOFF: + case DIV_CMD_LYNX_LFSR_LOAD: + w->writeC(2); // length + w->writeS(c.value); + break; + case DIV_CMD_FM_FIXFREQ: + w->writeC(2); // length + w->writeS((c.value<<12)|(c.value2&0x7ff)); + break; + case DIV_CMD_NES_SWEEP: + w->writeC(1); // length + w->writeC((c.value?8:0)|(c.value2&0x77)); + break; + default: + logW("unimplemented command %s!",cmdName[c.cmd]); + w->writeC(0); // length + break; + } +} + +SafeWriter* DivEngine::saveCommand(bool binary) { + stop(); + repeatPattern=false; + shallStop=false; + setOrder(0); + BUSY_BEGIN_SOFT; + // determine loop point + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + walkSong(loopOrder,loopRow,loopEnd); + logI("loop point: %d %d",loopOrder,loopRow); + + int cmdPopularity[256]; + int delayPopularity[256]; + + int sortedCmdPopularity[16]; + int sortedDelayPopularity[16]; + unsigned char sortedCmd[16]; + unsigned char sortedDelay[16]; + + SafeWriter* chanStream[DIV_MAX_CHANS]; + unsigned int chanStreamOff[DIV_MAX_CHANS]; + bool wroteTick[DIV_MAX_CHANS]; + + memset(cmdPopularity,0,256*sizeof(int)); + memset(delayPopularity,0,256*sizeof(int)); + memset(chanStream,0,DIV_MAX_CHANS*sizeof(void*)); + memset(chanStreamOff,0,DIV_MAX_CHANS*sizeof(unsigned int)); + memset(sortedCmdPopularity,0,16*sizeof(int)); + memset(sortedDelayPopularity,0,16*sizeof(int)); + memset(sortedCmd,0,16); + memset(sortedDelay,0,16); + + SafeWriter* w=new SafeWriter; + w->init(); + + // write header + if (binary) { + w->write("FCS",4); + w->writeI(chans); + // offsets + for (int i=0; iinit(); + w->writeI(0); + } + // preset delays and speed dial + for (int i=0; i<32; i++) { + w->writeC(0); + } + } else { + w->writeText("# Furnace Command Stream\n\n"); + + w->writeText("[Information]\n"); + w->writeText(fmt::sprintf("name: %s\n",song.name)); + w->writeText(fmt::sprintf("author: %s\n",song.author)); + w->writeText(fmt::sprintf("category: %s\n",song.category)); + w->writeText(fmt::sprintf("system: %s\n",song.systemName)); + + w->writeText("\n"); + + w->writeText("[SubSongInformation]\n"); + w->writeText(fmt::sprintf("name: %s\n",curSubSong->name)); + w->writeText(fmt::sprintf("tickRate: %f\n",curSubSong->hz)); + + w->writeText("\n"); + + w->writeText("[SysDefinition]\n"); + // TODO + + w->writeText("\n"); + } + + // play the song ourselves + bool done=false; + playSub(false); + + if (!binary) { + w->writeText("[Stream]\n"); + } + int tick=0; + bool oldCmdStreamEnabled=cmdStreamEnabled; + cmdStreamEnabled=true; + double curDivider=divider; + int lastTick[DIV_MAX_CHANS]; + + memset(lastTick,0,DIV_MAX_CHANS*sizeof(int)); + while (!done) { + if (nextTick(false,true) || !playing) { + done=true; + } + // get command stream + bool wroteTickGlobal=false; + memset(wroteTick,0,DIV_MAX_CHANS*sizeof(bool)); + if (curDivider!=divider) { + curDivider=divider; + WRITE_TICK(0); + if (binary) { + chanStream[0]->writeC(0xfb); + chanStream[0]->writeI((int)(curDivider*65536)); + } else { + w->writeText(fmt::sprintf(">> SET_RATE %f\n",curDivider)); + } + } + for (DivCommand& i: cmdStream) { + switch (i.cmd) { + // strip away hinted/useless commands + case DIV_ALWAYS_SET_VOLUME: + break; + case DIV_CMD_GET_VOLUME: + break; + case DIV_CMD_VOLUME: + break; + case DIV_CMD_NOTE_PORTA: + break; + case DIV_CMD_LEGATO: + break; + case DIV_CMD_PITCH: + break; + case DIV_CMD_PRE_NOTE: + break; + default: + WRITE_TICK(i.chan); + if (binary) { + cmdPopularity[i.cmd]++; + writePackedCommandValues(chanStream[i.chan],i); + } else { + w->writeText(fmt::sprintf(" %d: %s %d %d\n",i.chan,cmdName[i.cmd],i.value,i.value2)); + } + break; + } + } + cmdStream.clear(); + tick++; + } + cmdStreamEnabled=oldCmdStreamEnabled; + + if (binary) { + int sortCand=-1; + int sortPos=0; + while (sortPos<16) { + sortCand=-1; + for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) { + if (cmdPopularity[i]) { + if (sortCand==-1) { + sortCand=i; + } else if (cmdPopularity[sortCand]writeC(0xff); + // optimize stream + SafeWriter* oldStream=chanStream[i]; + SafeReader* reader=oldStream->toReader(); + chanStream[i]=new SafeWriter; + chanStream[i]->init(); + + while (1) { + try { + unsigned char next=reader->readC(); + switch (next) { + case 0xb8: // instrument + case 0xc0: // pre porta + case 0xc3: // vibrato range + case 0xc4: // vibrato shape + case 0xc5: // pitch + case 0xc7: // volume + case 0xca: // legato + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + break; + case 0xbe: // panning + case 0xc2: // vibrato + case 0xc6: // arpeggio + case 0xc8: // vol slide + case 0xc9: // porta + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + break; + case 0xf0: { // full command (pre) + unsigned char cmd=reader->readC(); + bool foundShort=false; + for (int j=0; j<16; j++) { + if (sortedCmd[j]==cmd) { + chanStream[i]->writeC(0xd0+j); + foundShort=true; + break; + } + } + if (!foundShort) { + chanStream[i]->writeC(0xf7); // full command + chanStream[i]->writeC(cmd); + } + + unsigned char cmdLen=reader->readC(); + logD("cmdLen: %d",cmdLen); + for (unsigned char j=0; jreadC(); + chanStream[i]->writeC(next); + } + break; + } + case 0xfb: // tick rate + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + next=reader->readC(); + chanStream[i]->writeC(next); + break; + case 0xfc: { // 16-bit wait + unsigned short delay=reader->readS(); + bool foundShort=false; + for (int j=0; j<16; j++) { + if (sortedDelay[j]==delay) { + chanStream[i]->writeC(0xe0+j); + foundShort=true; + break; + } + } + if (!foundShort) { + chanStream[i]->writeC(next); + chanStream[i]->writeS(delay); + } + break; + } + case 0xfd: { // 8-bit wait + unsigned char delay=reader->readC(); + bool foundShort=false; + for (int j=0; j<16; j++) { + if (sortedDelay[j]==delay) { + chanStream[i]->writeC(0xe0+j); + foundShort=true; + break; + } + } + if (!foundShort) { + chanStream[i]->writeC(next); + chanStream[i]->writeC(delay); + } + break; + } + default: + chanStream[i]->writeC(next); + break; + } + } catch (EndOfFileException& e) { + break; + } + } + + oldStream->finish(); + delete oldStream; + } + + for (int i=0; itell(); + logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size()); + w->write(chanStream[i]->getFinalBuf(),chanStream[i]->size()); + chanStream[i]->finish(); + delete chanStream[i]; + } + + w->seek(8,SEEK_SET); + for (int i=0; iwriteI(chanStreamOff[i]); + } + + logD("delay popularity:"); + for (int i=0; i<16; i++) { + w->writeC(sortedDelay[i]); + if (sortedDelayPopularity[i]) logD("- %d: %d",sortedDelay[i],sortedDelayPopularity[i]); + } + + logD("command popularity:"); + for (int i=0; i<16; i++) { + w->writeC(sortedCmd[i]); + if (sortedCmdPopularity[i]) logD("- %s: %d",cmdName[sortedCmd[i]],sortedCmdPopularity[i]); + } + } else { + if (!playing) { + w->writeText(">> END\n"); + } else { + w->writeText(">> LOOP 0\n"); + } + } + + remainingLoops=-1; + playing=false; + freelance=false; + extValuePresent=false; + BUSY_END; + + return w; +} diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 875ff487d..0ad264e53 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -411,6 +411,13 @@ class DivDispatch { */ virtual DivMacroInt* getChanMacroInt(int chan); + /** + * get the stereo panning of a channel. + * @param chan the channel. + * @return a 16-bit number. left in top 8 bits and right in bottom 8 bits. + */ + virtual unsigned short getPan(int chan); + /** * get currently playing sample (and its position). * @param chan the channel. diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index ac92b23f4..8ff1a33c7 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -219,7 +219,7 @@ void DivDispatchContainer::clear() { } } -void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags) { +void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags, bool isRender) { // quit if we already initialized if (dispatch!=NULL) return; @@ -231,33 +231,57 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_YM2612: dispatch=new DivPlatformGenesis; - ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + if (isRender) { + ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612CoreRender",0)); + } else { + ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + } ((DivPlatformGenesis*)dispatch)->setSoftPCM(false); break; case DIV_SYSTEM_YM2612_EXT: dispatch=new DivPlatformGenesisExt; - ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + if (isRender) { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612CoreRender",0)); + } else { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + } ((DivPlatformGenesisExt*)dispatch)->setSoftPCM(false); break; case DIV_SYSTEM_YM2612_CSM: dispatch=new DivPlatformGenesisExt; - ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + if (isRender) { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612CoreRender",0)); + } else { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + } ((DivPlatformGenesisExt*)dispatch)->setSoftPCM(false); ((DivPlatformGenesisExt*)dispatch)->setCSMChannel(6); break; case DIV_SYSTEM_YM2612_DUALPCM: dispatch=new DivPlatformGenesis; - ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + if (isRender) { + ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612CoreRender",0)); + } else { + ((DivPlatformGenesis*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + } ((DivPlatformGenesis*)dispatch)->setSoftPCM(true); break; case DIV_SYSTEM_YM2612_DUALPCM_EXT: dispatch=new DivPlatformGenesisExt; - ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + if (isRender) { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612CoreRender",0)); + } else { + ((DivPlatformGenesisExt*)dispatch)->setYMFM(eng->getConfInt("ym2612Core",0)); + } ((DivPlatformGenesisExt*)dispatch)->setSoftPCM(true); break; case DIV_SYSTEM_SMS: dispatch=new DivPlatformSMS; - ((DivPlatformSMS*)dispatch)->setNuked(eng->getConfInt("snCore",0)); + if (isRender) { + ((DivPlatformSMS*)dispatch)->setNuked(eng->getConfInt("snCoreRender",0)); + } else { + ((DivPlatformSMS*)dispatch)->setNuked(eng->getConfInt("snCore",0)); + } break; case DIV_SYSTEM_GB: dispatch=new DivPlatformGB; @@ -267,39 +291,71 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_NES: dispatch=new DivPlatformNES; - ((DivPlatformNES*)dispatch)->setNSFPlay(eng->getConfInt("nesCore",0)==1); + if (isRender) { + ((DivPlatformNES*)dispatch)->setNSFPlay(eng->getConfInt("nesCoreRender",0)==1); + } else { + ((DivPlatformNES*)dispatch)->setNSFPlay(eng->getConfInt("nesCore",0)==1); + } break; case DIV_SYSTEM_C64_6581: dispatch=new DivPlatformC64; - ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); + if (isRender) { + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64CoreRender",1)); + } else { + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); + } ((DivPlatformC64*)dispatch)->setChipModel(true); break; case DIV_SYSTEM_C64_8580: dispatch=new DivPlatformC64; - ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); + if (isRender) { + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64CoreRender",1)); + } else { + ((DivPlatformC64*)dispatch)->setCore(eng->getConfInt("c64Core",0)); + } ((DivPlatformC64*)dispatch)->setChipModel(false); break; case DIV_SYSTEM_YM2151: dispatch=new DivPlatformArcade; - ((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0); + if (isRender) { + ((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCoreRender",1)==0); + } else { + ((DivPlatformArcade*)dispatch)->setYMFM(eng->getConfInt("arcadeCore",0)==0); + } break; case DIV_SYSTEM_YM2610: case DIV_SYSTEM_YM2610_FULL: dispatch=new DivPlatformYM2610; - ((DivPlatformYM2610*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2610*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_FULL_EXT: dispatch=new DivPlatformYM2610Ext; - ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2610B: dispatch=new DivPlatformYM2610B; - ((DivPlatformYM2610B*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2610B*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610B*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2610B_EXT: dispatch=new DivPlatformYM2610BExt; - ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2610BExt*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_AMIGA: dispatch=new DivPlatformAmiga; @@ -312,26 +368,46 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_FDS: dispatch=new DivPlatformFDS; - ((DivPlatformFDS*)dispatch)->setNSFPlay(eng->getConfInt("fdsCore",0)==1); + if (isRender) { + ((DivPlatformFDS*)dispatch)->setNSFPlay(eng->getConfInt("fdsCoreRender",1)==1); + } else { + ((DivPlatformFDS*)dispatch)->setNSFPlay(eng->getConfInt("fdsCore",0)==1); + } break; case DIV_SYSTEM_TIA: dispatch=new DivPlatformTIA; break; case DIV_SYSTEM_YM2203: dispatch=new DivPlatformYM2203; - ((DivPlatformYM2203*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2203*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2203*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2203_EXT: dispatch=new DivPlatformYM2203Ext; - ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2203Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2608: dispatch=new DivPlatformYM2608; - ((DivPlatformYM2608*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2608*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2608*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_YM2608_EXT: dispatch=new DivPlatformYM2608Ext; - ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + if (isRender) { + ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnCoreRender",1)==1); + } else { + ((DivPlatformYM2608Ext*)dispatch)->setCombo(eng->getConfInt("opnCore",1)==1); + } break; case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL_DRUMS: @@ -396,7 +472,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_POKEY: dispatch=new DivPlatformPOKEY; - ((DivPlatformPOKEY*)dispatch)->setAltASAP(eng->getConfInt("pokeyCore",1)==1); + if (isRender) { + ((DivPlatformPOKEY*)dispatch)->setAltASAP(eng->getConfInt("pokeyCoreRender",1)==1); + } else { + ((DivPlatformPOKEY*)dispatch)->setAltASAP(eng->getConfInt("pokeyCore",1)==1); + } break; case DIV_SYSTEM_QSOUND: dispatch=new DivPlatformQSound; @@ -507,6 +587,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_C140: dispatch=new DivPlatformC140; + ((DivPlatformC140*)dispatch)->set219(false); + break; + case DIV_SYSTEM_C219: + dispatch=new DivPlatformC140; + ((DivPlatformC140*)dispatch)->set219(true); break; case DIV_SYSTEM_PCM_DAC: dispatch=new DivPlatformPCMDAC; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 477487709..7428de45d 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -17,9 +17,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _USE_MATH_DEFINES #include "dispatch.h" #include "song.h" -#define _USE_MATH_DEFINES #include "engine.h" #include "instrument.h" #include "safeReader.h" @@ -34,9 +34,6 @@ #endif #include #include -#ifdef HAVE_SNDFILE -#include "sfWrapper.h" -#endif #include void process(void* u, float** in, float** out, int inChans, int outChans, unsigned int size) { @@ -289,915 +286,6 @@ double DivEngine::benchmarkSeek() { return tAvg; } -#define WRITE_TICK(x) \ - if (binary) { \ - if (!wroteTick[x]) { \ - wroteTick[x]=true; \ - if (tick-lastTick[x]>255) { \ - chanStream[x]->writeC(0xfc); \ - chanStream[x]->writeS(tick-lastTick[x]); \ - } else if (tick-lastTick[x]>1) { \ - delayPopularity[tick-lastTick[x]]++; \ - chanStream[x]->writeC(0xfd); \ - chanStream[x]->writeC(tick-lastTick[x]); \ - } else if (tick-lastTick[x]>0) { \ - chanStream[x]->writeC(0xfe); \ - } \ - lastTick[x]=tick; \ - } \ - } else { \ - if (!wroteTickGlobal) { \ - wroteTickGlobal=true; \ - w->writeText(fmt::sprintf(">> TICK %d\n",tick)); \ - } \ - } - -void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { - switch (c.cmd) { - case DIV_CMD_NOTE_ON: - if (c.value==DIV_NOTE_NULL) { - w->writeC(0xb4); - } else { - w->writeC(CLAMP(c.value+60,0,0xb3)); - } - break; - case DIV_CMD_NOTE_OFF: - case DIV_CMD_NOTE_OFF_ENV: - case DIV_CMD_ENV_RELEASE: - case DIV_CMD_INSTRUMENT: - case DIV_CMD_PANNING: - case DIV_CMD_PRE_PORTA: - case DIV_CMD_HINT_VIBRATO: - case DIV_CMD_HINT_VIBRATO_RANGE: - case DIV_CMD_HINT_VIBRATO_SHAPE: - case DIV_CMD_HINT_PITCH: - case DIV_CMD_HINT_ARPEGGIO: - case DIV_CMD_HINT_VOLUME: - case DIV_CMD_HINT_PORTA: - case DIV_CMD_HINT_VOL_SLIDE: - case DIV_CMD_HINT_LEGATO: - w->writeC((unsigned char)c.cmd+0xb4); - break; - default: - w->writeC(0xf0); // unoptimized extended command - w->writeC(c.cmd); - break; - } - switch (c.cmd) { - case DIV_CMD_HINT_LEGATO: - if (c.value==DIV_NOTE_NULL) { - w->writeC(0xff); - } else { - w->writeC(c.value+60); - } - break; - case DIV_CMD_NOTE_ON: - case DIV_CMD_NOTE_OFF: - case DIV_CMD_NOTE_OFF_ENV: - case DIV_CMD_ENV_RELEASE: - break; - case DIV_CMD_INSTRUMENT: - case DIV_CMD_HINT_VIBRATO_RANGE: - case DIV_CMD_HINT_VIBRATO_SHAPE: - case DIV_CMD_HINT_PITCH: - case DIV_CMD_HINT_VOLUME: - w->writeC(c.value); - break; - case DIV_CMD_PANNING: - case DIV_CMD_HINT_VIBRATO: - case DIV_CMD_HINT_ARPEGGIO: - case DIV_CMD_HINT_PORTA: - w->writeC(c.value); - w->writeC(c.value2); - break; - case DIV_CMD_PRE_PORTA: - w->writeC((c.value?0x80:0)|(c.value2?0x40:0)); - break; - case DIV_CMD_HINT_VOL_SLIDE: - w->writeS(c.value); - break; - case DIV_CMD_SAMPLE_MODE: - case DIV_CMD_SAMPLE_FREQ: - case DIV_CMD_SAMPLE_BANK: - case DIV_CMD_SAMPLE_POS: - case DIV_CMD_SAMPLE_DIR: - case DIV_CMD_FM_HARD_RESET: - case DIV_CMD_FM_LFO: - case DIV_CMD_FM_LFO_WAVE: - case DIV_CMD_FM_FB: - case DIV_CMD_FM_EXTCH: - case DIV_CMD_FM_AM_DEPTH: - case DIV_CMD_FM_PM_DEPTH: - case DIV_CMD_STD_NOISE_FREQ: - case DIV_CMD_STD_NOISE_MODE: - case DIV_CMD_WAVE: - case DIV_CMD_GB_SWEEP_TIME: - case DIV_CMD_GB_SWEEP_DIR: - case DIV_CMD_PCE_LFO_MODE: - case DIV_CMD_PCE_LFO_SPEED: - case DIV_CMD_NES_DMC: - case DIV_CMD_C64_CUTOFF: - case DIV_CMD_C64_RESONANCE: - case DIV_CMD_C64_FILTER_MODE: - case DIV_CMD_C64_RESET_TIME: - case DIV_CMD_C64_RESET_MASK: - case DIV_CMD_C64_FILTER_RESET: - case DIV_CMD_C64_DUTY_RESET: - case DIV_CMD_C64_EXTENDED: - case DIV_CMD_AY_ENVELOPE_SET: - case DIV_CMD_AY_ENVELOPE_LOW: - case DIV_CMD_AY_ENVELOPE_HIGH: - case DIV_CMD_AY_ENVELOPE_SLIDE: - case DIV_CMD_AY_NOISE_MASK_AND: - case DIV_CMD_AY_NOISE_MASK_OR: - case DIV_CMD_AY_AUTO_ENVELOPE: - case DIV_CMD_FDS_MOD_DEPTH: - case DIV_CMD_FDS_MOD_HIGH: - case DIV_CMD_FDS_MOD_LOW: - case DIV_CMD_FDS_MOD_POS: - case DIV_CMD_FDS_MOD_WAVE: - case DIV_CMD_SAA_ENVELOPE: - case DIV_CMD_AMIGA_FILTER: - case DIV_CMD_AMIGA_AM: - case DIV_CMD_AMIGA_PM: - case DIV_CMD_MACRO_OFF: - case DIV_CMD_MACRO_ON: - case DIV_CMD_HINT_ARP_TIME: - w->writeC(1); // length - w->writeC(c.value); - break; - case DIV_CMD_FM_TL: - case DIV_CMD_FM_AM: - case DIV_CMD_FM_AR: - case DIV_CMD_FM_DR: - case DIV_CMD_FM_SL: - case DIV_CMD_FM_D2R: - case DIV_CMD_FM_RR: - case DIV_CMD_FM_DT: - case DIV_CMD_FM_DT2: - case DIV_CMD_FM_RS: - case DIV_CMD_FM_KSR: - case DIV_CMD_FM_VIB: - case DIV_CMD_FM_SUS: - case DIV_CMD_FM_WS: - case DIV_CMD_FM_SSG: - case DIV_CMD_FM_REV: - case DIV_CMD_FM_EG_SHIFT: - case DIV_CMD_FM_MULT: - case DIV_CMD_FM_FINE: - case DIV_CMD_AY_IO_WRITE: - case DIV_CMD_AY_AUTO_PWM: - case DIV_CMD_SURROUND_PANNING: - w->writeC(2); // length - w->writeC(c.value); - w->writeC(c.value2); - break; - case DIV_CMD_C64_FINE_DUTY: - case DIV_CMD_C64_FINE_CUTOFF: - case DIV_CMD_LYNX_LFSR_LOAD: - w->writeC(2); // length - w->writeS(c.value); - break; - case DIV_CMD_FM_FIXFREQ: - w->writeC(2); // length - w->writeS((c.value<<12)|(c.value2&0x7ff)); - break; - case DIV_CMD_NES_SWEEP: - w->writeC(1); // length - w->writeC((c.value?8:0)|(c.value2&0x77)); - break; - default: - logW("unimplemented command %s!",cmdName[c.cmd]); - w->writeC(0); // length - break; - } -} - -SafeWriter* DivEngine::saveCommand(bool binary) { - stop(); - repeatPattern=false; - shallStop=false; - setOrder(0); - BUSY_BEGIN_SOFT; - // determine loop point - int loopOrder=0; - int loopRow=0; - int loopEnd=0; - walkSong(loopOrder,loopRow,loopEnd); - logI("loop point: %d %d",loopOrder,loopRow); - - int cmdPopularity[256]; - int delayPopularity[256]; - - int sortedCmdPopularity[16]; - int sortedDelayPopularity[16]; - unsigned char sortedCmd[16]; - unsigned char sortedDelay[16]; - - SafeWriter* chanStream[DIV_MAX_CHANS]; - unsigned int chanStreamOff[DIV_MAX_CHANS]; - bool wroteTick[DIV_MAX_CHANS]; - - memset(cmdPopularity,0,256*sizeof(int)); - memset(delayPopularity,0,256*sizeof(int)); - memset(chanStream,0,DIV_MAX_CHANS*sizeof(void*)); - memset(chanStreamOff,0,DIV_MAX_CHANS*sizeof(unsigned int)); - memset(sortedCmdPopularity,0,16*sizeof(int)); - memset(sortedDelayPopularity,0,16*sizeof(int)); - memset(sortedCmd,0,16); - memset(sortedDelay,0,16); - - SafeWriter* w=new SafeWriter; - w->init(); - - // write header - if (binary) { - w->write("FCS",4); - w->writeI(chans); - // offsets - for (int i=0; iinit(); - w->writeI(0); - } - // preset delays and speed dial - for (int i=0; i<32; i++) { - w->writeC(0); - } - } else { - w->writeText("# Furnace Command Stream\n\n"); - - w->writeText("[Information]\n"); - w->writeText(fmt::sprintf("name: %s\n",song.name)); - w->writeText(fmt::sprintf("author: %s\n",song.author)); - w->writeText(fmt::sprintf("category: %s\n",song.category)); - w->writeText(fmt::sprintf("system: %s\n",song.systemName)); - - w->writeText("\n"); - - w->writeText("[SubSongInformation]\n"); - w->writeText(fmt::sprintf("name: %s\n",curSubSong->name)); - w->writeText(fmt::sprintf("tickRate: %f\n",curSubSong->hz)); - - w->writeText("\n"); - - w->writeText("[SysDefinition]\n"); - // TODO - - w->writeText("\n"); - } - - // play the song ourselves - bool done=false; - playSub(false); - - if (!binary) { - w->writeText("[Stream]\n"); - } - int tick=0; - bool oldCmdStreamEnabled=cmdStreamEnabled; - cmdStreamEnabled=true; - double curDivider=divider; - int lastTick[DIV_MAX_CHANS]; - - memset(lastTick,0,DIV_MAX_CHANS*sizeof(int)); - while (!done) { - if (nextTick(false,true) || !playing) { - done=true; - } - // get command stream - bool wroteTickGlobal=false; - memset(wroteTick,0,DIV_MAX_CHANS*sizeof(bool)); - if (curDivider!=divider) { - curDivider=divider; - WRITE_TICK(0); - if (binary) { - chanStream[0]->writeC(0xfb); - chanStream[0]->writeI((int)(curDivider*65536)); - } else { - w->writeText(fmt::sprintf(">> SET_RATE %f\n",curDivider)); - } - } - for (DivCommand& i: cmdStream) { - switch (i.cmd) { - // strip away hinted/useless commands - case DIV_ALWAYS_SET_VOLUME: - break; - case DIV_CMD_GET_VOLUME: - break; - case DIV_CMD_VOLUME: - break; - case DIV_CMD_NOTE_PORTA: - break; - case DIV_CMD_LEGATO: - break; - case DIV_CMD_PITCH: - break; - case DIV_CMD_PRE_NOTE: - break; - default: - WRITE_TICK(i.chan); - if (binary) { - cmdPopularity[i.cmd]++; - writePackedCommandValues(chanStream[i.chan],i); - } else { - w->writeText(fmt::sprintf(" %d: %s %d %d\n",i.chan,cmdName[i.cmd],i.value,i.value2)); - } - break; - } - } - cmdStream.clear(); - tick++; - } - cmdStreamEnabled=oldCmdStreamEnabled; - - if (binary) { - int sortCand=-1; - int sortPos=0; - while (sortPos<16) { - sortCand=-1; - for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) { - if (cmdPopularity[i]) { - if (sortCand==-1) { - sortCand=i; - } else if (cmdPopularity[sortCand]writeC(0xff); - // optimize stream - SafeWriter* oldStream=chanStream[i]; - SafeReader* reader=oldStream->toReader(); - chanStream[i]=new SafeWriter; - chanStream[i]->init(); - - while (1) { - try { - unsigned char next=reader->readC(); - switch (next) { - case 0xb8: // instrument - case 0xc0: // pre porta - case 0xc3: // vibrato range - case 0xc4: // vibrato shape - case 0xc5: // pitch - case 0xc7: // volume - case 0xca: // legato - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xbe: // panning - case 0xc2: // vibrato - case 0xc6: // arpeggio - case 0xc8: // vol slide - case 0xc9: // porta - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xf0: { // full command (pre) - unsigned char cmd=reader->readC(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedCmd[j]==cmd) { - chanStream[i]->writeC(0xd0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(0xf7); // full command - chanStream[i]->writeC(cmd); - } - - unsigned char cmdLen=reader->readC(); - logD("cmdLen: %d",cmdLen); - for (unsigned char j=0; jreadC(); - chanStream[i]->writeC(next); - } - break; - } - case 0xfb: // tick rate - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xfc: { // 16-bit wait - unsigned short delay=reader->readS(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedDelay[j]==delay) { - chanStream[i]->writeC(0xe0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(next); - chanStream[i]->writeS(delay); - } - break; - } - case 0xfd: { // 8-bit wait - unsigned char delay=reader->readC(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedDelay[j]==delay) { - chanStream[i]->writeC(0xe0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(next); - chanStream[i]->writeC(delay); - } - break; - } - default: - chanStream[i]->writeC(next); - break; - } - } catch (EndOfFileException& e) { - break; - } - } - - oldStream->finish(); - delete oldStream; - } - - for (int i=0; itell(); - logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size()); - w->write(chanStream[i]->getFinalBuf(),chanStream[i]->size()); - chanStream[i]->finish(); - delete chanStream[i]; - } - - w->seek(8,SEEK_SET); - for (int i=0; iwriteI(chanStreamOff[i]); - } - - logD("delay popularity:"); - for (int i=0; i<16; i++) { - w->writeC(sortedDelay[i]); - if (sortedDelayPopularity[i]) logD("- %d: %d",sortedDelay[i],sortedDelayPopularity[i]); - } - - logD("command popularity:"); - for (int i=0; i<16; i++) { - w->writeC(sortedCmd[i]); - if (sortedCmdPopularity[i]) logD("- %s: %d",cmdName[sortedCmd[i]],sortedCmdPopularity[i]); - } - } else { - if (!playing) { - w->writeText(">> END\n"); - } else { - w->writeText(">> LOOP 0\n"); - } - } - - remainingLoops=-1; - playing=false; - freelance=false; - extValuePresent=false; - BUSY_END; - - return w; -} - -void _runExportThread(DivEngine* caller) { - caller->runExportThread(); -} - -bool DivEngine::isExporting() { - return exporting; -} - -#ifdef HAVE_SNDFILE -void DivEngine::runExportThread() { - size_t fadeOutSamples=got.rate*exportFadeOut; - size_t curFadeOutSample=0; - bool isFadingOut=false; - switch (exportMode) { - case DIV_EXPORT_MODE_ONE: { - SNDFILE* sf; - SF_INFO si; - SFWrapper sfWrap; - si.samplerate=got.rate; - si.channels=2; - si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; - - sf=sfWrap.doOpen(exportPath.c_str(),SFM_WRITE,&si); - if (sf==NULL) { - logE("could not open file for writing! (%s)",sf_strerror(NULL)); - exporting=false; - return; - } - - float* outBuf[3]; - outBuf[0]=new float[EXPORT_BUFSIZE]; - outBuf[1]=new float[EXPORT_BUFSIZE]; - outBuf[2]=new float[EXPORT_BUFSIZE*2]; - - // take control of audio output - deinitAudioBackend(); - playSub(false); - - logI("rendering to file..."); - - while (playing) { - size_t total=0; - nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); - if (totalProcessed>EXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); - totalProcessed=EXPORT_BUFSIZE; - } - for (int i=0; i<(int)totalProcessed; i++) { - total++; - if (isFadingOut) { - double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); - outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]))*mul; - outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]))*mul; - if (++curFadeOutSample>=fadeOutSamples) { - playing=false; - break; - } - } else { - outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i])); - outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i])); - if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) { - logD("start fading out..."); - isFadingOut=true; - } - } - } - - if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { - logE("error: failed to write entire buffer!"); - break; - } - } - - delete[] outBuf[0]; - delete[] outBuf[1]; - delete[] outBuf[2]; - - if (sfWrap.doClose()!=0) { - logE("could not close audio file!"); - } - exporting=false; - - if (initAudioBackend()) { - for (int i=0; isetRun(true)) { - logE("error while activating audio!"); - } - } - logI("done!"); - break; - } - case DIV_EXPORT_MODE_MANY_SYS: { - SNDFILE* sf[DIV_MAX_CHIPS]; - SF_INFO si[DIV_MAX_CHIPS]; - String fname[DIV_MAX_CHIPS]; - SFWrapper sfWrap[DIV_MAX_CHIPS]; - for (int i=0; igetOutputCount(); - si[i].format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; - } - - for (int i=0; igetOutputCount()]; - } - - // take control of audio output - deinitAudioBackend(); - playSub(false); - - logI("rendering to files..."); - - while (playing) { - size_t total=0; - nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); - if (totalProcessed>EXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); - totalProcessed=EXPORT_BUFSIZE; - } - for (int j=0; j<(int)totalProcessed; j++) { - total++; - if (isFadingOut) { - double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); - for (int i=0; i=fadeOutSamples) { - playing=false; - break; - } - } else { - for (int i=0; i-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { - logD("start fading out..."); - isFadingOut=true; - } - } - } - for (int i=0; isetRun(true)) { - logE("error while activating audio!"); - } - } - logI("done!"); - break; - } - case DIV_EXPORT_MODE_MANY_CHAN: { - // take control of audio output - deinitAudioBackend(); - - float* outBuf[3]; - outBuf[0]=new float[EXPORT_BUFSIZE]; - outBuf[1]=new float[EXPORT_BUFSIZE]; - outBuf[2]=new float[EXPORT_BUFSIZE*2]; - int loopCount=remainingLoops; - - logI("rendering to files..."); - - for (int i=0; imuteChannel(dispatchChanOfChan[j],isMuted[j]); - } - } - - curOrder=0; - prevOrder=0; - curFadeOutSample=0; - lastLoopPos=-1; - totalLoops=0; - isFadingOut=false; - if (exportFadeOut<=0.01) { - remainingLoops=loopCount; - } else { - remainingLoops=-1; - } - playSub(false); - - while (playing) { - size_t total=0; - nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); - if (totalProcessed>EXPORT_BUFSIZE) { - logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); - totalProcessed=EXPORT_BUFSIZE; - } - for (int j=0; j<(int)totalProcessed; j++) { - total++; - if (isFadingOut) { - double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); - outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]))*mul; - outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]))*mul; - if (++curFadeOutSample>=fadeOutSamples) { - playing=false; - break; - } - } else { - outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j])); - outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j])); - if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { - logD("start fading out..."); - isFadingOut=true; - } - } - } - if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { - logE("error: failed to write entire buffer!"); - break; - } - } - - if (sfWrap.doClose()!=0) { - logE("could not close audio file!"); - } - - if (getChannelType(i)==5) { - i++; - while (true) { - if (i>=chans) break; - if (getChannelType(i)!=5) break; - i++; - } - i--; - } - - if (stopExport) break; - } - exporting=false; - - delete[] outBuf[0]; - delete[] outBuf[1]; - delete[] outBuf[2]; - - for (int i=0; imuteChannel(dispatchChanOfChan[i],false); - } - } - - if (initAudioBackend()) { - for (int i=0; isetRun(true)) { - logE("error while activating audio!"); - } - } - logI("done!"); - break; - } - } - stopExport=false; -} -#else -void DivEngine::runExportThread() { -} -#endif - -bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) { -#ifndef HAVE_SNDFILE - logE("Furnace was not compiled with libsndfile. cannot export!"); - return false; -#else - exportPath=path; - exportMode=mode; - exportFadeOut=fadeOutTime; - if (exportMode!=DIV_EXPORT_MODE_ONE) { - // remove extension - String lowerCase=exportPath; - for (char& i: lowerCase) { - if (i>='A' && i<='Z') i+='a'-'A'; - } - size_t extPos=lowerCase.rfind(".wav"); - if (extPos!=String::npos) { - exportPath=exportPath.substr(0,extPos); - } - } - exporting=true; - stopExport=false; - stop(); - repeatPattern=false; - setOrder(0); - if (exportFadeOut<=0.01) { - remainingLoops=loops; - } else { - remainingLoops=-1; - } - exportLoopCount=loops; - exportThread=new std::thread(_runExportThread,this); - return true; -#endif -} - -void DivEngine::waitAudioFile() { - if (exportThread!=NULL) { - exportThread->join(); - } -} - -bool DivEngine::haltAudioFile() { - stopExport=true; - stop(); - return true; -} - void DivEngine::notifyInsChange(int ins) { BUSY_BEGIN; for (int i=0; igetOutputCount(); if (outs>16) outs=16; if (outs<2) { + song.patchbay.reserve(DIV_MAX_OUTPUTS); for (unsigned int j=0; j=chans) return 0; + return disCont[dispatchOfChan[ch]].dispatch->getPan(dispatchChanOfChan[ch]); +} + void* DivEngine::getDispatchChanState(int ch) { if (ch<0 || ch>=chans) return NULL; return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]); @@ -2226,6 +1323,7 @@ void DivEngine::enableCommandStream(bool enable) { void DivEngine::getCommandStream(std::vector& where) { BUSY_BEGIN; where.clear(); + where.reserve(cmdStream.size()); for (DivCommand& i: cmdStream) { where.push_back(i); } @@ -3388,459 +2486,6 @@ int DivEngine::addSamplePtr(DivSample* which) { return sampleCount; } -DivSample* DivEngine::sampleFromFile(const char* path) { - if (song.sample.size()>=256) { - lastError="too many samples!"; - return NULL; - } - BUSY_BEGIN; - warnings=""; - - const char* pathRedux=strrchr(path,DIR_SEPARATOR); - if (pathRedux==NULL) { - pathRedux=path; - } else { - pathRedux++; - } - String stripPath; - const char* pathReduxEnd=strrchr(pathRedux,'.'); - if (pathReduxEnd==NULL) { - stripPath=pathRedux; - } else { - for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) { - stripPath+=*i; - } - } - - const char* ext=strrchr(path,'.'); - if (ext!=NULL) { - String extS; - for (; *ext; ext++) { - char i=*ext; - if (i>='A' && i<='Z') { - i+='a'-'A'; - } - extS+=i; - } - if (extS==".dmc" || extS==".brr") { // read as .dmc or .brr - size_t len=0; - DivSample* sample=new DivSample; - sample->name=stripPath; - - FILE* f=ps_fopen(path,"rb"); - if (f==NULL) { - BUSY_END; - lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - if (fseek(f,0,SEEK_END)<0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - len=ftell(f); - - if (len==0) { - fclose(f); - BUSY_END; - lastError="file is empty!"; - delete sample; - return NULL; - } - - if (len==(SIZE_MAX>>1)) { - fclose(f); - BUSY_END; - lastError="file is invalid!"; - delete sample; - return NULL; - } - - if (fseek(f,0,SEEK_SET)<0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - if (extS==".dmc") { - sample->rate=33144; - sample->centerRate=33144; - sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM; - sample->init(len*8); - } else if (extS==".brr") { - sample->rate=32000; - sample->centerRate=32000; - sample->depth=DIV_SAMPLE_DEPTH_BRR; - sample->init(16*(len/9)); - } else { - fclose(f); - BUSY_END; - lastError="wait... is that right? no I don't think so..."; - delete sample; - return NULL; - } - - unsigned char* dataBuf=sample->dataDPCM; - if (extS==".brr") { - dataBuf=sample->dataBRR; - if ((len%9)==2) { - // read loop position - unsigned short loopPos=0; - logD("BRR file has loop position"); - if (fread(&loopPos,1,2,f)!=2) { - logW("could not read loop position! %s",strerror(errno)); - } else { -#ifdef TA_BIG_ENDIAN - loopPos=(loopPos>>8)|(loopPos<<8); -#endif - sample->loopStart=16*(loopPos/9); - sample->loopEnd=sample->samples; - sample->loop=true; - sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; - } - len-=2; - if (len==0) { - fclose(f); - BUSY_END; - lastError="BRR sample is empty!"; - delete sample; - return NULL; - } - } else if ((len%9)!=0) { - fclose(f); - BUSY_END; - lastError="possibly corrupt BRR sample!"; - delete sample; - return NULL; - } - } - - if (fread(dataBuf,1,len,f)==0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); - delete sample; - return NULL; - } - BUSY_END; - return sample; - } - } - -#ifndef HAVE_SNDFILE - lastError="Furnace was not compiled with libsndfile!"; - return NULL; -#else - SF_INFO si; - SFWrapper sfWrap; - memset(&si,0,sizeof(SF_INFO)); - SNDFILE* f=sfWrap.doOpen(path,SFM_READ,&si); - if (f==NULL) { - BUSY_END; - int err=sf_error(NULL); - if (err==SF_ERR_SYSTEM) { - lastError=fmt::sprintf("could not open file! (%s %s)",sf_error_number(err),strerror(errno)); - } else { - lastError=fmt::sprintf("could not open file! (%s)\nif this is raw sample data, you may import it by right-clicking the Load Sample icon and selecting \"import raw\".",sf_error_number(err)); - } - return NULL; - } - if (si.frames>16777215) { - lastError="this sample is too big! max sample size is 16777215."; - sfWrap.doClose(); - BUSY_END; - return NULL; - } - void* buf=NULL; - sf_count_t sampleLen=sizeof(short); - if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { - logD("sample is 8-bit unsigned"); - buf=new unsigned char[si.channels*si.frames]; - sampleLen=sizeof(unsigned char); - } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { - logD("sample is 32-bit float"); - buf=new float[si.channels*si.frames]; - sampleLen=sizeof(float); - } else { - logD("sample is 16-bit signed"); - buf=new short[si.channels*si.frames]; - sampleLen=sizeof(short); - } - if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8 || (si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { - if (sf_read_raw(f,buf,si.frames*si.channels*sampleLen)!=(si.frames*si.channels*sampleLen)) { - logW("sample read size mismatch!"); - } - } else { - if (sf_read_short(f,(short*)buf,si.frames*si.channels)!=(si.frames*si.channels)) { - logW("sample read size mismatch!"); - } - } - DivSample* sample=new DivSample; - int sampleCount=(int)song.sample.size(); - sample->name=stripPath; - - int index=0; - if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { - sample->depth=DIV_SAMPLE_DEPTH_8BIT; - } else { - sample->depth=DIV_SAMPLE_DEPTH_16BIT; - } - sample->init(si.frames); - if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { - for (int i=0; idata8[index++]=averaged; - } - delete[] (unsigned char*)buf; - } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { - for (int i=0; i32767.0) averaged=32767.0; - sample->data16[index++]=averaged; - } - delete[] (float*)buf; - } else { - for (int i=0; idata16[index++]=averaged; - } - delete[] (short*)buf; - } - - sample->rate=si.samplerate; - if (sample->rate<4000) sample->rate=4000; - if (sample->rate>96000) sample->rate=96000; - sample->centerRate=si.samplerate; - - SF_INSTRUMENT inst; - if (sf_command(f, SFC_GET_INSTRUMENT, &inst, sizeof(inst)) == SF_TRUE) - { - // There's no documentation on libsndfile detune range, but the code - // implies -50..50. Yet when loading a file you can get a >50 value. - if(inst.detune > 50) - inst.detune = inst.detune - 100; - short pitch = ((0x3c-inst.basenote)*100) + inst.detune; - sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); - if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) - { - sample->loop=true; - sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); - sample->loopStart=inst.loops[0].start; - sample->loopEnd=inst.loops[0].end; - if(inst.loops[0].end < (unsigned int)sampleCount) - sampleCount=inst.loops[0].end; - } - else - sample->loop=false; - } - - if (sample->centerRate<4000) sample->centerRate=4000; - if (sample->centerRate>64000) sample->centerRate=64000; - sfWrap.doClose(); - BUSY_END; - return sample; -#endif -} - -DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign, bool swapNibbles) { - if (song.sample.size()>=256) { - lastError="too many samples!"; - return NULL; - } - if (channels<1) { - lastError="invalid channel count"; - return NULL; - } - if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) { - if (channels!=1) { - lastError="channel count has to be 1 for non-8/16-bit format"; - return NULL; - } - } - BUSY_BEGIN; - warnings=""; - - const char* pathRedux=strrchr(path,DIR_SEPARATOR); - if (pathRedux==NULL) { - pathRedux=path; - } else { - pathRedux++; - } - String stripPath; - const char* pathReduxEnd=strrchr(pathRedux,'.'); - if (pathReduxEnd==NULL) { - stripPath=pathRedux; - } else { - for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) { - stripPath+=*i; - } - } - - size_t len=0; - size_t lenDivided=0; - DivSample* sample=new DivSample; - sample->name=stripPath; - - FILE* f=ps_fopen(path,"rb"); - if (f==NULL) { - BUSY_END; - lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - if (fseek(f,0,SEEK_END)<0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - len=ftell(f); - - if (len==0) { - fclose(f); - BUSY_END; - lastError="file is empty!"; - delete sample; - return NULL; - } - - if (len==(SIZE_MAX>>1)) { - fclose(f); - BUSY_END; - lastError="file is invalid!"; - delete sample; - return NULL; - } - - if (fseek(f,0,SEEK_SET)<0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); - delete sample; - return NULL; - } - - lenDivided=len/channels; - - unsigned int samples=lenDivided; - switch (depth) { - case DIV_SAMPLE_DEPTH_1BIT: - case DIV_SAMPLE_DEPTH_1BIT_DPCM: - samples=lenDivided*8; - break; - case DIV_SAMPLE_DEPTH_YMZ_ADPCM: - case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: - case DIV_SAMPLE_DEPTH_ADPCM_A: - case DIV_SAMPLE_DEPTH_ADPCM_B: - case DIV_SAMPLE_DEPTH_VOX: - samples=lenDivided*2; - break; - case DIV_SAMPLE_DEPTH_8BIT: - samples=lenDivided; - break; - case DIV_SAMPLE_DEPTH_BRR: - samples=16*((lenDivided+8)/9); - break; - case DIV_SAMPLE_DEPTH_16BIT: - samples=(lenDivided+1)/2; - break; - default: - break; - } - - if (samples>16777215) { - fclose(f); - BUSY_END; - lastError="this sample is too big! max sample size is 16777215."; - delete sample; - return NULL; - } - - sample->rate=32000; - sample->centerRate=32000; - sample->depth=depth; - sample->init(samples); - - unsigned char* buf=new unsigned char[len]; - if (fread(buf,1,len,f)==0) { - fclose(f); - BUSY_END; - lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); - delete[] buf; - delete sample; - return NULL; - } - - fclose(f); - - // import sample - size_t pos=0; - if (depth==DIV_SAMPLE_DEPTH_16BIT) { - for (unsigned int i=0; i=len) break; - if (bigEndian) { - accum+=(short)(((short)((buf[pos]<<8)|buf[pos+1]))^(unsign?0x8000:0)); - } else { - accum+=(short)(((short)(buf[pos]|(buf[pos+1]<<8)))^(unsign?0x8000:0)); - } - pos+=2; - } - accum/=channels; - sample->data16[i]=accum; - } - } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { - for (unsigned int i=0; i=len) break; - accum+=(signed char)(buf[pos++]^(unsign?0x80:0)); - } - accum/=channels; - sample->data8[i]=accum; - } - } else { - memcpy(sample->getCurBuf(),buf,len); - } - delete[] buf; - - // swap nibbles if needed - if (swapNibbles) { - unsigned char* b=(unsigned char*)sample->getCurBuf(); - for (unsigned int i=0; igetCurBufLen(); i++) { - b[i]=(b[i]<<4)|(b[i]>>4); - } - } - - BUSY_END; - return sample; -} - void DivEngine::delSample(int index) { BUSY_BEGIN; sPreview.sample=-1; @@ -4182,23 +2827,26 @@ void DivEngine::autoPatchbay() { unsigned int outs=disCont[i].dispatch->getOutputCount(); if (outs>16) outs=16; if (outs<2) { + song.patchbay.reserve(DIV_MAX_OUTPUTS); for (unsigned int j=0; jlistAudioDevices(); want.deviceName=getConfString("audioDevice",""); @@ -4703,8 +3355,10 @@ bool DivEngine::initAudioBackend() { if (want.outChans<1) want.outChans=1; if (want.outChans>16) want.outChans=16; + logV("setting callback"); output->setCallback(process,this); + logV("calling init"); if (!output->init(want,got)) { logE("error while initializing audio!"); delete output; @@ -4713,6 +3367,7 @@ bool DivEngine::initAudioBackend() { return false; } + logV("allocating oscBuf..."); for (int i=0; iinitMidi(false)) { midiIns=output->midiIn->listDevices(); midiOuts=output->midiOut->listDevices(); @@ -4751,6 +3407,7 @@ bool DivEngine::initAudioBackend() { } } + logV("initAudioBackend done"); return true; } @@ -4794,6 +3451,13 @@ void DivEngine::preInit() { logI("Furnace version " DIV_VERSION "."); loadConf(); + +#ifdef HAVE_SDL2 + String audioDriver=getConfString("sdlAudioDriver",""); + if (!audioDriver.empty()) { + SDL_SetHint("SDL_HINT_AUDIODRIVER",audioDriver.c_str()); + } +#endif } bool DivEngine::init() { @@ -4831,6 +3495,8 @@ bool DivEngine::init() { haveAudio=true; } + logV("creating blip_buf"); + samp_bb=blip_new(32768); if (samp_bb==NULL) { logE("not enough memory!"); @@ -4844,6 +3510,8 @@ bool DivEngine::init() { metroBuf=new float[8192]; metroBufLen=8192; + + logV("setting blip rate of samp_bb (%f)",got.rate); blip_set_rates(samp_bb,44100,got.rate); diff --git a/src/engine/engine.h b/src/engine/engine.h index effa0273f..8df2652d1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -56,8 +56,8 @@ #define DIV_UNSTABLE -#define DIV_VERSION "dev165" -#define DIV_ENGINE_VERSION 165 +#define DIV_VERSION "dev169" +#define DIV_ENGINE_VERSION 169 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 @@ -201,7 +201,7 @@ struct DivDispatchContainer { void flush(size_t count); void fillBuf(size_t runtotal, size_t offset, size_t size); void clear(); - void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags); + void init(DivSystem sys, DivEngine* eng, int chanCount, double gotRate, const DivConfig& flags, bool isRender=false); void quit(); DivDispatchContainer(): dispatch(NULL), @@ -497,6 +497,7 @@ class DivEngine { void playSub(bool preserveDrift, int goalRow=0); void runMidiClock(int totalCycles=1); void runMidiTime(int totalCycles=1); + bool shallSwitchCores(); void testFunction(); @@ -614,6 +615,8 @@ class DivEngine { void waitAudioFile(); // stop audio file export bool haltAudioFile(); + // return back to playback cores if necessary + void finishAudioFile(); // notify instrument parameter change void notifyInsChange(int ins); // notify wavetable change @@ -973,6 +976,9 @@ class DivEngine { // get macro interpreter DivMacroInt* getMacroInt(int chan); + // get channel panning + unsigned short getChanPan(int chan); + // get sample position DivSamplePos getSamplePos(int chan); @@ -1132,7 +1138,7 @@ class DivEngine { TAAudioDesc& getAudioDescGot(); // init dispatch - void initDispatch(); + void initDispatch(bool isRender=false); // quit dispatch void quitDispatch(); diff --git a/src/engine/export/amigaValidation.cpp b/src/engine/export/amigaValidation.cpp index dc836f33e..56d3814a7 100644 --- a/src/engine/export/amigaValidation.cpp +++ b/src/engine/export/amigaValidation.cpp @@ -266,6 +266,7 @@ std::vector DivExportAmigaValidation::go(DivEngine* e) { } // finish + ret.reserve(5); ret.push_back(DivROMExportOutput("sbook.bin",sbook)); ret.push_back(DivROMExportOutput("wbook.bin",wbook)); ret.push_back(DivROMExportOutput("sample.bin",sample)); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 9cf94547b..746f59046 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -183,6 +183,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.brokenPortaArp=false; ds.snNoLowPeriods=true; ds.disableSampleMacro=true; + ds.preNoteNoEffect=true; ds.delayBehavior=0; ds.jumpTreatment=2; @@ -341,6 +342,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.insLen=16; } logI("reading instruments (%d)...",ds.insLen); + ds.ins.reserve(ds.insLen); for (int i=0; i0x0b) { ds.waveLen=(unsigned char)reader.readC(); logI("reading wavetables (%d)...",ds.waveLen); + ds.wave.reserve(ds.waveLen); for (int i=0; ilen=(unsigned char)reader.readI(); @@ -837,6 +840,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { // it appears this byte stored the YMU759 sample rate ymuSampleRate=reader.readC(); } + ds.sample.reserve(ds.sampleLen); for (int i=0; iordersLen); @@ -2341,6 +2349,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // patchbay unsigned int conns=reader.readI(); + ds.patchbay.reserve(conns); for (unsigned int i=0; i=168) { + ds.preNoteNoEffect=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<5; i++) { reader.readC(); } } @@ -2368,6 +2382,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // grooves unsigned char grooveCount=reader.readC(); + ds.grooves.reserve(grooveCount); for (int i=0; i=95) { + ds.subsong.reserve(numberOfSubSongs); for (int i=0; idepth=DIV_SAMPLE_DEPTH_8BIT; @@ -3364,6 +3384,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { } // instrument creation + ds.ins.reserve(insCount); for(int i=0; itype=DIV_INS_AMIGA; @@ -3642,6 +3663,7 @@ bool DivEngine::loadS3M(unsigned char* file, size_t len) { } // load instruments/samples + ds.ins.reserve(ds.insLen); for (int i=0; idepth=DIV_SAMPLE_DEPTH_8BIT; @@ -3972,6 +3999,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { return false; } logD("reading wavetables..."); + ds.wave.reserve(80); for (int i=0; i<80; i++) { DivWavetable* w=new DivWavetable; w->min=0; @@ -4000,6 +4028,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } else { // generate preset waves + ds.wave.reserve(48); for (int i=0; i<48; i++) { DivWavetable* w=new DivWavetable; generateFCPresetWave(i,w); @@ -4147,6 +4176,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // volume sequence ins->std.volMacro.len=0; + ds.ins.reserve(64 - 5); for (int j=5; j<64; j++) { loopMap[j]=ins->std.volMacro.len; if (m.val[j]==0xe1) { // end @@ -4544,6 +4574,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len) { CHECK_BLOCK_VERSION(4); unsigned char totalSongs=reader.readC(); logV("%d songs:",totalSongs+1); + ds.subsong.reserve(totalSongs); for (int i=0; i<=totalSongs; i++) { String subSongName=reader.readString(); ds.subsong.push_back(new DivSubSong); @@ -5078,12 +5109,14 @@ DivDataErrors DivEngine::readAssetDirData(SafeReader& reader, std::vectorwriteC(song.brokenPortaLegato); - for (int i=0; i<7; i++) { + w->writeC(song.brokenFMOff); + w->writeC(song.preNoteNoEffect); + for (int i=0; i<5; i++) { w->writeC(0); } @@ -5414,6 +5449,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { w->seek(0,SEEK_END); /// SUBSONGS + subSongPtr.reserve(song.subsong.size() - 1); for (subSongIndex=1; subSongIndextell()); @@ -5475,6 +5511,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { } /// CHIP FLAGS + sysFlagsPtr.reserve(song.systemLen); for (int i=0; itell()); @@ -5511,6 +5549,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { } /// WAVETABLE + wavePtr.reserve(song.waveLen); for (int i=0; itell()); @@ -5518,6 +5557,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { } /// SAMPLE + samplePtr.reserve(song.sampleLen); for (int i=0; itell()); @@ -5525,6 +5565,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { } /// PATTERN + patPtr.reserve(patsToWrite.size()); for (PatToWrite& i: patsToWrite) { DivPattern* pat=song.subsong[i.subsong]->pat[i.chan].getPattern(i.pat,false); patPtr.push_back(w->tell()); diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp new file mode 100644 index 000000000..4d4b3a0e8 --- /dev/null +++ b/src/engine/fileOpsSample.cpp @@ -0,0 +1,511 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2023 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "engine.h" +#include "../ta-log.h" +#include "../fileutils.h" +#ifdef HAVE_SNDFILE +#include "sfWrapper.h" +#endif + +DivSample* DivEngine::sampleFromFile(const char* path) { + if (song.sample.size()>=256) { + lastError="too many samples!"; + return NULL; + } + BUSY_BEGIN; + warnings=""; + + const char* pathRedux=strrchr(path,DIR_SEPARATOR); + if (pathRedux==NULL) { + pathRedux=path; + } else { + pathRedux++; + } + String stripPath; + const char* pathReduxEnd=strrchr(pathRedux,'.'); + if (pathReduxEnd==NULL) { + stripPath=pathRedux; + } else { + for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) { + stripPath+=*i; + } + } + + const char* ext=strrchr(path,'.'); + if (ext!=NULL) { + String extS; + for (; *ext; ext++) { + char i=*ext; + if (i>='A' && i<='Z') { + i+='a'-'A'; + } + extS+=i; + } + if (extS==".dmc" || extS==".brr") { // read as .dmc or .brr + size_t len=0; + DivSample* sample=new DivSample; + sample->name=stripPath; + + FILE* f=ps_fopen(path,"rb"); + if (f==NULL) { + BUSY_END; + lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_END)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + len=ftell(f); + + if (len==0) { + fclose(f); + BUSY_END; + lastError="file is empty!"; + delete sample; + return NULL; + } + + if (len==(SIZE_MAX>>1)) { + fclose(f); + BUSY_END; + lastError="file is invalid!"; + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_SET)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + if (extS==".dmc") { + sample->rate=33144; + sample->centerRate=33144; + sample->depth=DIV_SAMPLE_DEPTH_1BIT_DPCM; + sample->init(len*8); + } else if (extS==".brr") { + sample->rate=32000; + sample->centerRate=32000; + sample->depth=DIV_SAMPLE_DEPTH_BRR; + sample->init(16*(len/9)); + } else { + fclose(f); + BUSY_END; + lastError="wait... is that right? no I don't think so..."; + delete sample; + return NULL; + } + + unsigned char* dataBuf=sample->dataDPCM; + if (extS==".brr") { + dataBuf=sample->dataBRR; + if ((len%9)==2) { + // read loop position + unsigned short loopPos=0; + logD("BRR file has loop position"); + if (fread(&loopPos,1,2,f)!=2) { + logW("could not read loop position! %s",strerror(errno)); + } else { +#ifdef TA_BIG_ENDIAN + loopPos=(loopPos>>8)|(loopPos<<8); +#endif + sample->loopStart=16*(loopPos/9); + sample->loopEnd=sample->samples; + sample->loop=true; + sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; + } + len-=2; + if (len==0) { + fclose(f); + BUSY_END; + lastError="BRR sample is empty!"; + delete sample; + return NULL; + } + } else if ((len%9)!=0) { + fclose(f); + BUSY_END; + lastError="possibly corrupt BRR sample!"; + delete sample; + return NULL; + } + } + + if (fread(dataBuf,1,len,f)==0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + BUSY_END; + return sample; + } + } + +#ifndef HAVE_SNDFILE + lastError="Furnace was not compiled with libsndfile!"; + return NULL; +#else + SF_INFO si; + SFWrapper sfWrap; + memset(&si,0,sizeof(SF_INFO)); + SNDFILE* f=sfWrap.doOpen(path,SFM_READ,&si); + if (f==NULL) { + BUSY_END; + int err=sf_error(NULL); + if (err==SF_ERR_SYSTEM) { + lastError=fmt::sprintf("could not open file! (%s %s)",sf_error_number(err),strerror(errno)); + } else { + lastError=fmt::sprintf("could not open file! (%s)\nif this is raw sample data, you may import it by right-clicking the Load Sample icon and selecting \"import raw\".",sf_error_number(err)); + } + return NULL; + } + if (si.frames>16777215) { + lastError="this sample is too big! max sample size is 16777215."; + sfWrap.doClose(); + BUSY_END; + return NULL; + } + void* buf=NULL; + sf_count_t sampleLen=sizeof(short); + if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { + logD("sample is 8-bit unsigned"); + buf=new unsigned char[si.channels*si.frames]; + sampleLen=sizeof(unsigned char); + } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { + logD("sample is 32-bit float"); + buf=new float[si.channels*si.frames]; + sampleLen=sizeof(float); + } else { + logD("sample is 16-bit signed"); + buf=new short[si.channels*si.frames]; + sampleLen=sizeof(short); + } + if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8 || (si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { + if (sf_read_raw(f,buf,si.frames*si.channels*sampleLen)!=(si.frames*si.channels*sampleLen)) { + logW("sample read size mismatch!"); + } + } else { + if (sf_read_short(f,(short*)buf,si.frames*si.channels)!=(si.frames*si.channels)) { + logW("sample read size mismatch!"); + } + } + DivSample* sample=new DivSample; + int sampleCount=(int)song.sample.size(); + sample->name=stripPath; + + int index=0; + if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { + sample->depth=DIV_SAMPLE_DEPTH_8BIT; + } else { + sample->depth=DIV_SAMPLE_DEPTH_16BIT; + } + sample->init(si.frames); + if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_PCM_U8) { + for (int i=0; idata8[index++]=averaged; + } + delete[] (unsigned char*)buf; + } else if ((si.format&SF_FORMAT_SUBMASK)==SF_FORMAT_FLOAT) { + for (int i=0; i32767.0) averaged=32767.0; + sample->data16[index++]=averaged; + } + delete[] (float*)buf; + } else { + for (int i=0; idata16[index++]=averaged; + } + delete[] (short*)buf; + } + + sample->rate=si.samplerate; + if (sample->rate<4000) sample->rate=4000; + if (sample->rate>96000) sample->rate=96000; + sample->centerRate=si.samplerate; + + SF_INSTRUMENT inst; + if (sf_command(f, SFC_GET_INSTRUMENT, &inst, sizeof(inst)) == SF_TRUE) + { + // There's no documentation on libsndfile detune range, but the code + // implies -50..50. Yet when loading a file you can get a >50 value. + if(inst.detune > 50) + inst.detune = inst.detune - 100; + short pitch = ((0x3c-inst.basenote)*100) + inst.detune; + sample->centerRate=si.samplerate*pow(2.0,pitch/(12.0 * 100.0)); + if(inst.loop_count && inst.loops[0].mode >= SF_LOOP_FORWARD) + { + sample->loop=true; + sample->loopMode=(DivSampleLoopMode)(inst.loops[0].mode-SF_LOOP_FORWARD); + sample->loopStart=inst.loops[0].start; + sample->loopEnd=inst.loops[0].end; + if(inst.loops[0].end < (unsigned int)sampleCount) + sampleCount=inst.loops[0].end; + } + else + sample->loop=false; + } + + if (sample->centerRate<4000) sample->centerRate=4000; + if (sample->centerRate>64000) sample->centerRate=64000; + sfWrap.doClose(); + BUSY_END; + return sample; +#endif +} + +DivSample* DivEngine::sampleFromFileRaw(const char* path, DivSampleDepth depth, int channels, bool bigEndian, bool unsign, bool swapNibbles) { + if (song.sample.size()>=256) { + lastError="too many samples!"; + return NULL; + } + if (channels<1) { + channels=1; + } + if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) { + if (channels!=1) { + channels=1; + } + } + BUSY_BEGIN; + warnings=""; + + const char* pathRedux=strrchr(path,DIR_SEPARATOR); + if (pathRedux==NULL) { + pathRedux=path; + } else { + pathRedux++; + } + String stripPath; + const char* pathReduxEnd=strrchr(pathRedux,'.'); + if (pathReduxEnd==NULL) { + stripPath=pathRedux; + } else { + for (const char* i=pathRedux; i!=pathReduxEnd && (*i); i++) { + stripPath+=*i; + } + } + + size_t len=0; + size_t lenDivided=0; + DivSample* sample=new DivSample; + sample->name=stripPath; + + FILE* f=ps_fopen(path,"rb"); + if (f==NULL) { + BUSY_END; + lastError=fmt::sprintf("could not open file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_END)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not get file length! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + len=ftell(f); + + if (len==0) { + fclose(f); + BUSY_END; + lastError="file is empty!"; + delete sample; + return NULL; + } + + if (len==(SIZE_MAX>>1)) { + fclose(f); + BUSY_END; + lastError="file is invalid!"; + delete sample; + return NULL; + } + + if (fseek(f,0,SEEK_SET)<0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not seek to beginning of file! (%s)",strerror(errno)); + delete sample; + return NULL; + } + + lenDivided=len/channels; + + unsigned int samples=lenDivided; + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + samples=lenDivided*8; + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + case DIV_SAMPLE_DEPTH_ADPCM_A: + case DIV_SAMPLE_DEPTH_ADPCM_B: + case DIV_SAMPLE_DEPTH_VOX: + samples=lenDivided*2; + break; + case DIV_SAMPLE_DEPTH_8BIT: + case DIV_SAMPLE_DEPTH_MULAW: + samples=lenDivided; + break; + case DIV_SAMPLE_DEPTH_BRR: + samples=16*((lenDivided+8)/9); + break; + case DIV_SAMPLE_DEPTH_16BIT: + samples=(lenDivided+1)/2; + break; + default: + break; + } + + if (samples>16777215) { + fclose(f); + BUSY_END; + lastError="this sample is too big! max sample size is 16777215."; + delete sample; + return NULL; + } + + sample->rate=32000; + sample->centerRate=32000; + sample->depth=depth; + sample->init(samples); + + unsigned char* buf=new unsigned char[len]; + if (fread(buf,1,len,f)==0) { + fclose(f); + BUSY_END; + lastError=fmt::sprintf("could not read file! (%s)",strerror(errno)); + delete[] buf; + delete sample; + return NULL; + } + + fclose(f); + + // import sample + size_t pos=0; + if (depth==DIV_SAMPLE_DEPTH_16BIT) { + for (unsigned int i=0; i=len) break; + if (bigEndian) { + accum+=(short)(((short)((buf[pos]<<8)|buf[pos+1]))^(unsign?0x8000:0)); + } else { + accum+=(short)(((short)(buf[pos]|(buf[pos+1]<<8)))^(unsign?0x8000:0)); + } + pos+=2; + } + accum/=channels; + sample->data16[i]=accum; + } + } else if (depth==DIV_SAMPLE_DEPTH_8BIT) { + for (unsigned int i=0; i=len) break; + accum+=(signed char)(buf[pos++]^(unsign?0x80:0)); + } + accum/=channels; + sample->data8[i]=accum; + } + } else { + memcpy(sample->getCurBuf(),buf,len); + } + delete[] buf; + + if (swapNibbles) { + unsigned char* b=(unsigned char*)sample->getCurBuf(); + switch (depth) { + case DIV_SAMPLE_DEPTH_1BIT: + case DIV_SAMPLE_DEPTH_1BIT_DPCM: + // reverse bit order + for (unsigned int i=0; igetCurBufLen(); i++) { + b[i]=( + ((b[i]&128)?1:0)| + ((b[i]&64)?2:0)| + ((b[i]&32)?4:0)| + ((b[i]&16)?8:0)| + ((b[i]&8)?16:0)| + ((b[i]&4)?32:0)| + ((b[i]&2)?64:0)| + ((b[i]&1)?128:0) + ); + } + break; + case DIV_SAMPLE_DEPTH_YMZ_ADPCM: + case DIV_SAMPLE_DEPTH_QSOUND_ADPCM: + case DIV_SAMPLE_DEPTH_ADPCM_A: + case DIV_SAMPLE_DEPTH_ADPCM_B: + case DIV_SAMPLE_DEPTH_VOX: + // swap nibbles + for (unsigned int i=0; igetCurBufLen(); i++) { + b[i]=(b[i]<<4)|(b[i]>>4); + } + break; + case DIV_SAMPLE_DEPTH_MULAW: + // Namco to G.711 + // Namco: smmmmxxx + // G.711: sxxxmmmm (^0xff) + for (unsigned int i=0; igetCurBufLen(); i++) { + b[i]=(((b[i]&7)<<4)|(((b[i]>>3)&15)^((b[i]&0x80)?15:0))|(b[i]&0x80))^0xff; + } + break; + default: + break; + } + } + + BUSY_END; + return sample; +} diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 3931a6f50..28cb99bca 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -967,6 +967,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { featureSM=true; featureSL=true; break; + case DIV_INS_C219: + featureSM=true; + featureSL=true; + break; case DIV_INS_MAX: break; @@ -2261,6 +2265,19 @@ void DivInstrument::readFeatureOx(SafeReader& reader, int op, short version) { } break; } + + // <167 TL macro compat + if (macroCode==6 && version<167) { + if (target->open&6) { + for (int j=0; j<2; j++) { + target->val[j]^=0x7f; + } + } else { + for (int j=0; jlen; j++) { + target->val[j]^=0x7f; + } + } + } } READ_FEAT_END; @@ -3319,6 +3336,21 @@ DivDataErrors DivInstrument::readInsDataOld(SafeReader &reader, short version) { } } + // <167 TL macro compat + if (version<167) { + for (int i=0; i<4; i++) { + if (std.opMacros[i].tlMacro.open&6) { + for (int j=0; j<2; j++) { + std.opMacros[i].tlMacro.val[j]^=0x7f; + } + } else { + for (int j=0; j0) { delay--; if (!linger) had=false; @@ -401,15 +402,13 @@ void DivMacroInt::init(DivInstrument* which) { if (macroSource[i]!=NULL) { macroList[i]->prepare(*macroSource[i],e); // check ADSR mode - if ((macroSource[i]->open&6)==4) { - hasRelease=false; - } else if ((macroSource[i]->open&6)==2) { + if ((macroSource[i]->open&6)==2) { + if (macroSource[i]->val[8]>0) { + hasRelease=true; + } + } else if (macroSource[i]->rellen) { hasRelease=true; - } else { - hasRelease=(macroSource[i]->rellen); } - } else { - hasRelease=false; } } } diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 2be22d1f4..a06d9caf0 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -33,6 +33,10 @@ void* DivDispatch::getChanState(int chan) { return NULL; } +unsigned short DivDispatch::getPan(int chan) { + return 0; +} + DivMacroInt* DivDispatch::getChanMacroInt(int chan) { return NULL; } diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 20110b9db..95a3d7750 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -299,7 +299,7 @@ void DivPlatformArcade::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (!op.enable) { rWrite(baseAddr+ADDR_TL,127); } else if (KVS(i,j)) { @@ -857,6 +857,10 @@ DivMacroInt* DivPlatformArcade::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformArcade::getPan(int ch) { + return (chan[ch].chVolL<<8)|(chan[ch].chVolR); +} + DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index b5720f197..39ae3705e 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -75,6 +75,7 @@ class DivPlatformArcade: public DivPlatformOPM { void tick(bool sysTick=true); void muteChannel(int ch, bool mute); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); void notifyInsChange(int ins); void notifyInsDeletion(void* ins); void setFlags(const DivConfig& flags); diff --git a/src/engine/platform/c140.cpp b/src/engine/platform/c140.cpp index e5de79488..ba2b5d33e 100644 --- a/src/engine/platform/c140.cpp +++ b/src/engine/platform/c140.cpp @@ -45,15 +45,63 @@ const char* regCheatSheetC140[]={ NULL }; +const char* regCheatSheetC219[]={ + "CHx_RVol", "00+x*10", + "CHx_LVol", "01+x*10", + "CHx_FreqH", "02+x*10", + "CHx_FreqL", "03+x*10", + "CHx_Ctrl", "05+x*10", + "CHx_StartH", "06+x*10", + "CHx_StartL", "07+x*10", + "CHx_EndH", "08+x*10", + "CHx_EndL", "09+x*10", + "CHx_LoopH", "0A+x*10", + "CHx_LoopL", "0B+x*10", + "BankA", "1F7", + "BankB", "1F1", + "BankC", "1F3", + "BankD", "1F5", + NULL +}; + const char** DivPlatformC140::getRegisterSheet() { - return regCheatSheetC140; + return is219?regCheatSheetC219:regCheatSheetC140; } -void DivPlatformC140::acquire(short** buf, size_t len) { +void DivPlatformC140::acquire_219(short** buf, size_t len) { for (size_t h=0; h>= 10; + c219.rout >>= 10; + + if (c219.lout<-32768) c219.lout=-32768; + if (c219.lout>32767) c219.lout=32767; + + if (c219.rout<-32768) c219.rout=-32768; + if (c219.rout>32767) c219.rout=32767; + + buf[0][h]=c219.lout; + buf[1][h]=c219.rout; + + for (int i=0; idata[oscBuf[i]->needle++]=(c219.voice[i].lout+c219.voice[i].rout)>>10; + } + } +} + +void DivPlatformC140::acquire_140(short** buf, size_t len) { + for (size_t h=0; hdata[oscBuf[i]->needle++]=(c140.voice[i].lout+c140.voice[i].rout)>>10; } } } +void DivPlatformC140::acquire(short** buf, size_t len) { + if (is219) { + acquire_219(buf,len); + } else { + acquire_140(buf,len); + } +} + void DivPlatformC140::tick(bool sysTick) { - for (int i=0; i<24; i++) { + for (int i=0; icalcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE)); if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>65535) chan[i].freq=65535; - ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); + if (is219) { + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?1:0)|(chan[i].invert?0x40:0)|(chan[i].surround?8:0)|(chan[i].noise?4:0); + } else { + ctrl|=(chan[i].active?0x80:0)|((s->isLoopable())?0x10:0)|((s->depth==DIV_SAMPLE_DEPTH_MULAW)?0x08:0); + } if (chan[i].keyOn) { unsigned int bank=0; unsigned int start=0; unsigned int loop=0; unsigned int end=0; if (chan[i].sample>=0 && chan[i].samplesong.sampleLen) { - bank=(sampleOff[chan[i].sample]>>16)&0xff; - start=sampleOff[chan[i].sample]&0xffff; - end=MIN(start+s->length8-1,65535); + if (is219) { + bank=(sampleOff[chan[i].sample]>>16)&3; + start=sampleOff[chan[i].sample]&0xffff; + end=MIN(start+(s->length8>>1)-1,65535); + } else { + bank=(sampleOff[chan[i].sample]>>16)&0xff; + start=sampleOff[chan[i].sample]&0xffff; + end=MIN(start+s->length8-1,65535); + } } if (chan[i].audPos>0) { - start=MIN(start+MIN(chan[i].audPos,s->length8),65535); + start=MIN(start+(MIN(chan[i].audPos,s->length8)>>1),65535); } if (s->isLoopable()) { - loop=MIN(start+s->loopStart,65535); - end=MIN(start+s->loopEnd-1,65535); + if (is219) { + loop=MIN(start+(s->loopStart>>1),65535); + end=MIN(start+(s->loopEnd>>1)-1,65535); + } else { + loop=MIN(start+s->loopStart,65535); + end=MIN(start+s->loopEnd-1,65535); + } } rWrite(0x05+(i<<4),0); // force keyoff first - rWrite(0x04+(i<<4),bank); + if (is219) { + if (groupBank[i>>2]!=bank) { + groupBank[i>>2]=bank; + } + rWrite(0x1f1+(((3+(i>>2))&3)<<1),groupBank[i>>2]); + } else { + rWrite(0x04+(i<<4),bank); + } rWrite(0x06+(i<<4),(start>>8)&0xff); rWrite(0x07+(i<<4),start&0xff); rWrite(0x08+(i<<4),(end>>8)&0xff); @@ -323,11 +401,15 @@ int DivPlatformC140::dispatch(DivCommand c) { void DivPlatformC140::muteChannel(int ch, bool mute) { isMuted[ch]=mute; - c140.voice[ch].muted=mute; + if (is219) { + c219.voice[ch].muted=mute; + } else { + c140.voice[ch].muted=mute; + } } void DivPlatformC140::forceIns() { - for (int i=0; i<24; i++) { + for (int i=0; ilength16; - // fit sample size to single bank size - if (length>(131072)) { - length=131072; - } - if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { - memPos=((memPos+0x1ffff)&0xfe0000); - } - if (memPos>=(getSampleMemCapacity())) { - logW("out of C140 memory for sample %d!",i); - break; - } - // why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours... - if (memPos+length>=(getSampleMemCapacity())) { - if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { - for (unsigned int i=0; i<(getSampleMemCapacity())-memPos; i++) { - unsigned char x=s->dataMuLaw[i]^0xff; - if (x&0x80) x^=15; - unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); - sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8); - } - } else { - memcpy(sampleMem+(memPos/sizeof(short)),s->data16,(getSampleMemCapacity())-memPos); + if (is219) { // C219 (8-bit) + unsigned int length=s->length8; + // fit sample size to single bank size + if (length>131072) { + length=131072; + } + if (length&1) length++; + if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { + memPos=((memPos+0x1ffff)&0xfe0000); + } + if (memPos>=(getSampleMemCapacity())) { + logW("out of C219 memory for sample %d!",i); + break; + } + if (memPos+length>=(getSampleMemCapacity())) { + length=getSampleMemCapacity()-memPos; + logW("out of C219 memory for sample %d!",i); } - logW("out of C140 memory for sample %d!",i); - } else { if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { for (unsigned int i=0; idataMuLaw[i]^0xff; - if (x&0x80) x^=15; - unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); - sampleMem[i+(memPos/sizeof(short))]=((c140Mu)<<8); + if (i>=s->lengthMuLaw) { + sampleMem[i+memPos]=0; + } else { + unsigned char x=s->dataMuLaw[i]^0xff; + sampleMem[i+memPos]=x; + } } } else { - memcpy(sampleMem+(memPos/sizeof(short)),s->data16,length); + for (unsigned int i=0; i=s->length8) { + sampleMem[memPos+i]=0; + } else { + sampleMem[memPos+i]=s->data8[i]; + } + } } + sampleOff[i]=memPos>>1; + sampleLoaded[i]=true; + memPos+=length; + } else { // C140 (16-bit) + unsigned int length=s->length16; + // fit sample size to single bank size + if (length>(131072)) { + length=131072; + } + if ((memPos&0xfe0000)!=((memPos+length)&0xfe0000)) { + memPos=((memPos+0x1ffff)&0xfe0000); + } + if (memPos>=(getSampleMemCapacity())) { + logW("out of C140 memory for sample %d!",i); + break; + } + // why is C140 not G.711-compliant? this weird bit mangling had me puzzled for 3 hours... + if (memPos+length>=(getSampleMemCapacity())) { + length=getSampleMemCapacity()-memPos; + logW("out of C140 memory for sample %d!",i); + } + if (s->depth==DIV_SAMPLE_DEPTH_MULAW) { + for (unsigned int i=0; i>1)>=s->lengthMuLaw) break; + unsigned char x=s->dataMuLaw[i>>1]^0xff; + if (x&0x80) x^=15; + unsigned char c140Mu=(x&0x80)|((x&15)<<3)|((x&0x70)>>4); + sampleMem[i+memPos]=0; + sampleMem[1+i+memPos]=c140Mu; + } + } else { + memcpy(sampleMem+memPos,s->data16,length); + } + sampleOff[i]=memPos>>1; + sampleLoaded[i]=true; + memPos+=length; } - sampleOff[i]=memPos>>1; - sampleLoaded[i]=true; - memPos+=length; } sampleMemLen=memPos+256; } +void DivPlatformC140::set219(bool is_219) { + is219=is_219; + totalChans=is219?16:24; +} + void DivPlatformC140::setFlags(const DivConfig& flags) { chipClock=32000*256; // 8.192MHz and 12.288MHz input, verified from Assault Schematics CHECK_CUSTOM_CLOCK; rate=chipClock/192; - for (int i=0; i<24; i++) { + for (int i=0; irate=rate; } } @@ -491,23 +622,28 @@ int DivPlatformC140::init(DivEngine* p, int channels, int sugRate, const DivConf dumpWrites=false; skipRegisterWrites=false; - for (int i=0; i<24; i++) { + for (int i=0; i>1]; + sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; - c140_init(&c140); - c140.sample_mem=sampleMem; + if (is219) { + c219_init(&c219); + c219.sample_mem=(signed char*)sampleMem; + } else { + c140_init(&c140); + c140.sample_mem=(short*)sampleMem; + } setFlags(flags); reset(); - return 24; + return totalChans; } void DivPlatformC140::quit() { delete[] sampleMem; - for (int i=0; i<24; i++) { + for (int i=0; i { unsigned int audPos; int sample, wave; - bool setPos, volChangedL, volChangedR; + bool setPos, invert, surround, noise, volChangedL, volChangedR; int chPanL, chPanR; int chVolL, chVolR; int macroVolMul; @@ -39,6 +39,9 @@ class DivPlatformC140: public DivDispatch { sample(-1), wave(-1), setPos(false), + invert(false), + surround(false), + noise(false), volChangedL(false), volChangedR(false), chPanL(255), @@ -53,8 +56,11 @@ class DivPlatformC140: public DivDispatch { bool isMuted[24]; unsigned int sampleOff[256]; bool sampleLoaded[256]; + bool is219; + int totalChans; + unsigned char groupBank[4]; - signed short* sampleMem; + unsigned char* sampleMem; size_t sampleMemLen; struct QueuedWrite { unsigned short addr; @@ -65,15 +71,20 @@ class DivPlatformC140: public DivDispatch { }; FixedQueue writes; struct c140_t c140; + struct c219_t c219; unsigned char regPool[512]; friend void putDispatchChip(void*,int); friend void putDispatchChan(void*,int,int); + void acquire_219(short** buf, size_t len); + void acquire_140(short** buf, size_t len); + public: void acquire(short** buf, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); @@ -94,6 +105,7 @@ class DivPlatformC140: public DivDispatch { size_t getSampleMemUsage(int index = 0); bool isSampleLoaded(int index, int sample); void renderSamples(int chipID); + void set219(bool is_219); void setFlags(const DivConfig& flags); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 4f8745bda..d5eb38a0b 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -167,7 +167,7 @@ void DivPlatformES5506::acquire(short** buf, size_t len) { buf[(o<<1)|1][h]=es5506.rout(o); } for (int i=chanMax; i>=0; i--) { - oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>6; + oscBuf[i]->data[oscBuf[i]->needle++]=(es5506.voice_lout(i)+es5506.voice_rout(i))>>5; } } } @@ -1057,6 +1057,10 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformES5506::getPan(int ch) { + return ((chan[ch].lVol>>4)<<8)|(chan[ch].rVol>>4); +} + void DivPlatformES5506::reset() { while (!hostIntf32.empty()) hostIntf32.pop(); while (!hostIntf8.empty()) hostIntf8.pop(); diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index b7658c52f..07bdb2380 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -295,6 +295,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual int dispatch(DivCommand c) override; virtual void* getChanState(int chan) override; virtual DivMacroInt* getChanMacroInt(int ch) override; + virtual unsigned short getPan(int chan) override; virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; virtual unsigned char* getRegisterPool() override; virtual int getRegisterPoolSize() override; diff --git a/src/engine/platform/fmshared_OPN.h b/src/engine/platform/fmshared_OPN.h index 8d3d059c4..32ea4c002 100644 --- a/src/engine/platform/fmshared_OPN.h +++ b/src/engine/platform/fmshared_OPN.h @@ -155,6 +155,7 @@ class DivPlatformOPN: public DivPlatformFMBase { unsigned int ayDiv; unsigned char csmChan; unsigned char lfoValue; + unsigned char lastExtChPan; unsigned short ssgVol; unsigned short fmVol; bool extSys, useCombo, fbAllOps; @@ -175,6 +176,7 @@ class DivPlatformOPN: public DivPlatformFMBase { ayDiv(a), csmChan(cc), lfoValue(0), + lastExtChPan(3), ssgVol(128), fmVol(256), extSys(isExtSys), diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 7e2086db0..741fe2c3c 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -458,7 +458,7 @@ int DivPlatformGB::dispatch(DivCommand c) { } chan[c.chan].envVol=chan[c.chan].outVol; - if (!chan[c.chan].keyOn) chan[c.chan].killIt=true; + if (!chan[c.chan].keyOn && chan[c.chan].active) chan[c.chan].killIt=true; chan[c.chan].freqChanged=true; } break; @@ -578,6 +578,11 @@ DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformGB::getPan(int ch) { + unsigned char p=lastPan&(0x11<5) ch=5; + return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1); +} + DivSamplePos DivPlatformGenesis::getSamplePos(int ch) { if (!chan[5].dacMode) return DivSamplePos(); if (ch<5) return DivSamplePos(); diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index d618c6892..8c9181dc9 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -106,6 +106,7 @@ class DivPlatformGenesis: public DivPlatformOPN { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + virtual unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index d8760be9a..a147545cb 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -159,6 +159,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } } rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); + lastExtChPan=opChan[ch].pan; break; } case DIV_CMD_PITCH: { @@ -443,13 +444,15 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { DivPlatformGenesis::muteChannel(extChanOffs,IS_EXTCH_MUTED); if (extMode) { - int ordch=orderedOps[ch-2]; - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=chan[2].state.op[ordch]; - if (isOpMuted[ch-2] || !op.enable) { - rWrite(baseAddr+0x40,127); - } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); + for (int i=0; i<4; i++) { + int ordch=orderedOps[i]; + unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + DivInstrumentFM::Operator op=chan[2].state.op[ordch]; + if (isOpMuted[i] || !op.enable) { + rWrite(baseAddr+0x40,127); + } else { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } } rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); @@ -557,6 +560,17 @@ void DivPlatformGenesisExt::tick(bool sysTick) { rWrite(0x22,lfoValue); } + if (opChan[i].std.panL.had) { + opChan[i].pan=opChan[i].std.panL.val&3; + if (parent->song.sharedExtStat) { + for (int j=0; j<4; j++) { + if (i==j) continue; + opChan[j].pan=opChan[i].pan; + } + } + rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } + // param macros unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; @@ -586,7 +600,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -743,7 +757,7 @@ void DivPlatformGenesisExt::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==2) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } @@ -770,6 +784,9 @@ void DivPlatformGenesisExt::forceIns() { chan[csmChan].freqChanged=true; chan[csmChan].keyOn=true; } + if (!extMode) { + immWrite(0x27,0x00); + } } void* DivPlatformGenesisExt::getChanState(int ch) { @@ -784,6 +801,19 @@ DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformGenesisExt::getPan(int ch) { + if (ch==csmChan) return 0; + if (ch>=4+extChanOffs) return DivPlatformGenesis::getPan(ch-3); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformGenesis::getPan(extChanOffs); + } + } + return DivPlatformGenesis::getPan(ch); +} + DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; @@ -800,6 +830,8 @@ void DivPlatformGenesisExt::reset() { opChan[i].outVol=127; } + lastExtChPan=3; + // channel 3 mode immWrite(0x27,0x40); extMode=true; diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index c668d5104..63112c069 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -34,6 +34,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/k007232.cpp b/src/engine/platform/k007232.cpp index d1037988a..c1e314f53 100644 --- a/src/engine/platform/k007232.cpp +++ b/src/engine/platform/k007232.cpp @@ -78,15 +78,21 @@ void DivPlatformK007232::acquire(short** buf, size_t len) { const signed int rout[2]={(k007232.output(0)*((vol1>>4)&0xf)),(k007232.output(1)*((vol2>>4)&0xf))}; buf[0][h]=(lout[0]+lout[1])<<4; buf[1][h]=(rout[0]+rout[1])<<4; - for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<3; + if (++oscDivider>=8) { + oscDivider=0; + for (int i=0; i<2; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=(lout[i]+rout[i])<<3; + } } } else { const unsigned char vol=regPool[0xc]; const signed int out[2]={(k007232.output(0)*(vol&0xf)),(k007232.output(1)*((vol>>4)&0xf))}; buf[0][h]=(out[0]+out[1])<<4; - for (int i=0; i<2; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<4; + if (++oscDivider>=8) { + oscDivider=0; + for (int i=0; i<2; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=out[i]<<4; + } } } } @@ -424,6 +430,10 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformK007232::getPan(int ch) { + return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4); +} + DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) { return oscBuf[ch]; } @@ -480,7 +490,7 @@ void DivPlatformK007232::setFlags(const DivConfig& flags) { stereo=flags.getBool("stereo",false); for (int i=0; i<2; i++) { chan[i].volumeChanged=true; - oscBuf[i]->rate=rate; + oscBuf[i]->rate=rate/8; } } @@ -571,6 +581,7 @@ int DivPlatformK007232::init(DivEngine* p, int channels, int sugRate, const DivC } sampleMem=new unsigned char[getSampleMemCapacity()]; sampleMemLen=0; + oscDivider=0; setFlags(flags); reset(); diff --git a/src/engine/platform/k007232.h b/src/engine/platform/k007232.h index b1025f574..e3409b31f 100644 --- a/src/engine/platform/k007232.h +++ b/src/engine/platform/k007232.h @@ -68,7 +68,7 @@ class DivPlatformK007232: public DivDispatch, public k007232_intf { bool sampleLoaded[256]; int delay; - unsigned char lastLoop, lastVolume; + unsigned char lastLoop, lastVolume, oscDivider; bool stereo; unsigned char* sampleMem; @@ -85,6 +85,7 @@ class DivPlatformK007232: public DivDispatch, public k007232_intf { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/k053260.cpp b/src/engine/platform/k053260.cpp index 5791d2426..17ff6db48 100644 --- a/src/engine/platform/k053260.cpp +++ b/src/engine/platform/k053260.cpp @@ -370,6 +370,10 @@ DivMacroInt* DivPlatformK053260::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformK053260::getPan(int ch) { + return parent->convertPanLinearToSplit(chan[ch].panning,8,7); +} + DivDispatchOscBuffer* DivPlatformK053260::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/k053260.h b/src/engine/platform/k053260.h index ce531f3d5..27b2a7910 100644 --- a/src/engine/platform/k053260.h +++ b/src/engine/platform/k053260.h @@ -64,6 +64,7 @@ class DivPlatformK053260: public DivDispatch, public k053260_intf { virtual int dispatch(DivCommand c) override; virtual void* getChanState(int chan) override; virtual DivMacroInt* getChanMacroInt(int ch) override; + virtual unsigned short getPan(int chan) override; virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; virtual unsigned char* getRegisterPool() override; virtual int getRegisterPoolSize() override; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 6e87fea78..c8a34d461 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -238,7 +238,9 @@ void DivPlatformLynx::tick(bool sysTick) { chan[i].fd=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].std.duty.had) { chan[i].duty=chan[i].std.duty.val; - WRITE_FEEDBACK(i, chan[i].duty.feedback); + if (!chan[i].pcm) { + WRITE_FEEDBACK(i, chan[i].duty.feedback); + } } WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); WRITE_BACKUP( i, chan[i].fd.backup ); @@ -257,9 +259,21 @@ void DivPlatformLynx::tick(bool sysTick) { int DivPlatformLynx::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { + bool prevPCM=chan[c.chan].pcm; DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY); chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127; chan[c.chan].pcm=(ins->type==DIV_INS_AMIGA || ins->amiga.useSample); + if (chan[c.chan].pcm!=prevPCM) { + if (chan[c.chan].pcm) { + WRITE_FEEDBACK(c.chan,0); + WRITE_CONTROL(c.chan,0x18); + WRITE_BACKUP(c.chan,0); + } else { + WRITE_FEEDBACK(c.chan,chan[c.chan].duty.feedback); + WRITE_CONTROL(c.chan,(chan[c.chan].fd.clockDivider|0x18|chan[c.chan].duty.int_feedback7)); + WRITE_BACKUP(c.chan,chan[c.chan].fd.backup); + } + } if (c.value!=DIV_NOTE_NULL) { if (chan[c.chan].pcm) { chan[c.chan].sample=ins->amiga.getSample(c.value); @@ -416,6 +430,10 @@ DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformLynx::getPan(int ch) { + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivSamplePos DivPlatformLynx::getSamplePos(int ch) { if (ch>=4) return DivSamplePos(); if (!chan[ch].pcm) return DivSamplePos(); diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index c68106dec..e081f7ff7 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -72,6 +72,7 @@ class DivPlatformLynx: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); diff --git a/src/engine/platform/msm6258.cpp b/src/engine/platform/msm6258.cpp index e5de16456..cb0ed05ed 100644 --- a/src/engine/platform/msm6258.cpp +++ b/src/engine/platform/msm6258.cpp @@ -282,6 +282,10 @@ DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformMSM6258::getPan(int ch) { + return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1); +} + DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/msm6258.h b/src/engine/platform/msm6258.h index 6be120c2b..21ff2a9f2 100644 --- a/src/engine/platform/msm6258.h +++ b/src/engine/platform/msm6258.h @@ -62,6 +62,7 @@ class DivPlatformMSM6258: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index e24459ba9..1d6596f12 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -134,14 +134,16 @@ void DivPlatformN163::updateWave(int ch, int wave, int pos, int len) { len&=0xfc; // 4 nibble boundary if (wave<0) { // load from wave synth - for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area - break; + if (ch>=0) { + for (int i=0; i=((0x78-(chanMax<<3))<<1)) { // avoid conflict with channel register area + break; + } + unsigned char mask=(addr&1)?0xf0:0x0f; + int data=chan[ch].ws.output[i]; + rWriteMask(addr>>1,(addr&1)?(data<<4):(data&0xf),mask); } - unsigned char mask=(addr&1)?0xf0:0x0f; - int data=chan[ch].ws.output[i]; - rWriteMask(addr>>1,(addr&1)?(data<<4):(data&0xf),mask); } } else { // load from custom diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 5ac493f19..f6b6d062a 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -473,6 +473,11 @@ DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformNamcoWSG::getPan(int ch) { + if (devType!=30) return 0; + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/namcowsg.h b/src/engine/platform/namcowsg.h index 6aaef0952..7d6943323 100644 --- a/src/engine/platform/namcowsg.h +++ b/src/engine/platform/namcowsg.h @@ -62,6 +62,7 @@ class DivPlatformNamcoWSG: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 6c3fa416d..c8c5c944c 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -436,7 +436,7 @@ void DivPlatformOPL::tick(bool sysTick) { } if (m.tl.had) { - op.tl=63-m.tl.val; + op.tl=m.tl.val&63; } if (m.ksl.had) { op.ksl=m.ksl.val; @@ -1564,6 +1564,18 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformOPL::getPan(int ch) { + if (totalOutputs<=1) return 0; + /*if (chan[ch&(~1)].fourOp) { + if (ch&1) { + return ((chan[ch-1].pan&2)<<7)|(chan[ch-1].pan&1); + } else { + return ((chan[ch+1].pan&2)<<7)|(chan[ch+1].pan&1); + } + }*/ + return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1); +} + DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { if (oplType==759 || chipType==8950) { if (ch>=totalChans+1) return NULL; diff --git a/src/engine/platform/opl.h b/src/engine/platform/opl.h index a417b5088..2298f6132 100644 --- a/src/engine/platform/opl.h +++ b/src/engine/platform/opl.h @@ -114,6 +114,7 @@ class DivPlatformOPL: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 2d283d9a6..1c7dc72e1 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -195,7 +195,7 @@ void DivPlatformOPLL::tick(bool sysTick) { rWrite(0x06+j,(op.sl<<4)|(op.rr)); } if (m.tl.had) { - op.tl=((j==1)?15:63)-m.tl.val; + op.tl=m.tl.val&((j==1)?15:63); if (j==1) { if (i<9) { rWrite(0x30+i,((15-VOL_SCALE_LOG_BROKEN(chan[i].outVol,15-chan[i].state.op[1].tl,15))&15)|(chan[i].state.opllPreset<<4)); diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index b6f43e2da..2daba109e 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -508,6 +508,10 @@ DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformPCE::getPan(int ch) { + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivSamplePos DivPlatformPCE::getSamplePos(int ch) { if (ch>=6) return DivSamplePos(); if (!chan[ch].pcm) return DivSamplePos(); diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index baca77701..f989034af 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -82,6 +82,7 @@ class DivPlatformPCE: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 3a00e431a..1ddd22dae 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -229,7 +229,7 @@ void DivPlatformPCMDAC::acquire(short** buf, size_t len) { } else { output=output*chan[0].vol*chan[0].envVol/16384; } - oscBuf->data[oscBuf->needle++]=output>>1; + oscBuf->data[oscBuf->needle++]=((output>>depthScale)<>1; if (outStereo) { buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<>(depthScale+8))<=1) return DivSamplePos(); return DivSamplePos( diff --git a/src/engine/platform/pcmdac.h b/src/engine/platform/pcmdac.h index 8ef10149c..17513690a 100644 --- a/src/engine/platform/pcmdac.h +++ b/src/engine/platform/pcmdac.h @@ -78,6 +78,7 @@ class DivPlatformPCMDAC: public DivDispatch { void muteChannel(int ch, bool mute); int getOutputCount(); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); void setFlags(const DivConfig& flags); void notifyInsChange(int ins); diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index d7f908f5b..5c98990b4 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -623,6 +623,10 @@ DivMacroInt* DivPlatformQSound::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformQSound::getPan(int ch) { + return parent->convertPanLinearToSplit(chan[ch].panning,8,32); +} + DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/qsound.h b/src/engine/platform/qsound.h index aff53f679..6daccc120 100644 --- a/src/engine/platform/qsound.h +++ b/src/engine/platform/qsound.h @@ -66,6 +66,7 @@ class DivPlatformQSound: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 84522c74f..9319de5d3 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -322,6 +322,10 @@ DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformRF5C68::getPan(int ch) { + return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4); +} + DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/rf5c68.h b/src/engine/platform/rf5c68.h index 4ba40318c..9c706ccd5 100644 --- a/src/engine/platform/rf5c68.h +++ b/src/engine/platform/rf5c68.h @@ -59,6 +59,7 @@ class DivPlatformRF5C68: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 803a6cad3..b1ba48826 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -365,6 +365,10 @@ DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformSAA1099::getPan(int ch) { + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index ffd79db72..36db57cb7 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -79,6 +79,7 @@ class DivPlatformSAA1099: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index b9af8a912..5e584e016 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -394,6 +394,10 @@ DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformSegaPCM::getPan(int ch) { + return (chan[ch].chPanL<<8)|chan[ch].chPanR; +} + DivSamplePos DivPlatformSegaPCM::getSamplePos(int ch) { if (ch>=16) return DivSamplePos(); if (chan[ch].pcm.sample<0 || chan[ch].pcm.sample>=parent->song.sampleLen) return DivSamplePos(); diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 067054fe1..639d875b4 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -89,6 +89,7 @@ class DivPlatformSegaPCM: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 76aa62fcb..7aa0455ca 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -452,6 +452,12 @@ DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformSMS::getPan(int ch) { + if (!stereo) return 0; + unsigned char p=lastPan&(0x11<=8) return DivSamplePos(); if (!chan[ch].active) return DivSamplePos(); diff --git a/src/engine/platform/snes.h b/src/engine/platform/snes.h index cec51c0c1..a799c7a5d 100644 --- a/src/engine/platform/snes.h +++ b/src/engine/platform/snes.h @@ -100,6 +100,7 @@ class DivPlatformSNES: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivSamplePos getSamplePos(int ch); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); diff --git a/src/engine/platform/sound/c140.c b/src/engine/platform/sound/c140_c219.c similarity index 51% rename from src/engine/platform/sound/c140.c rename to src/engine/platform/sound/c140_c219.c index 3d48c1300..4855bd782 100644 --- a/src/engine/platform/sound/c140.c +++ b/src/engine/platform/sound/c140_c219.c @@ -2,10 +2,10 @@ ============================================================================ -MODIFIED Namco C140 sound emulator - MODIFIED VERSION +MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION by cam900 -MODIFICATION by tildearrow - adds muting function +MODIFICATION by tildearrow - adds muting function and fixes overflow THIS IS NOT THE ORIGINAL VERSION - you can find the original one in commit 72d04777c013988ed8cf6da27c62a9d784a59dff @@ -41,7 +41,7 @@ TODO: */ -#include "c140.h" +#include "c140_c219.h" static int c140_max(int a, int b) { return (a > b) ? a : b; } static int c140_min(int a, int b) { return (a < b) ? a : b; } @@ -61,6 +61,18 @@ void c140_tick(struct c140_t *c140, const int cycle) } } +void c219_tick(struct c219_t *c219, const int cycle) +{ + c219->lout = 0; + c219->rout = 0; + for (int i = 0; i < 16; i++) + { + c219_voice_tick(c219, i, cycle); + c219->lout += c219->voice[i].lout; + c219->rout += c219->voice[i].rout; + } +} + void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle) { struct c140_voice_t *voice = &c140->voice[v]; @@ -99,8 +111,8 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle s1 = c140->mulaw[(s1 >> 8) & 0xff]; s2 = c140->mulaw[(s2 >> 8) & 0xff]; } - // interpolate - signed int sample = s1 + (((voice->frac) * (s2 - s1)) >> 16); + // interpolate (originally was >>16, but I had to reduce it to 15 to prevent overflow) + signed int sample = s1 + (((voice->frac >> 1) * (s2 - s1)) >> 15); voice->lout = sample * voice->lvol; voice->rout = sample * voice->rvol; } @@ -117,6 +129,84 @@ void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle } } +void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle) +{ + struct c140_voice_t *voice = &c219->voice[v]; + if (voice->busy && voice->keyon) + { + for (int c = 0; c < cycle; c++) + { + voice->frac += voice->freq; + if (voice->frac > 0xffff) + { + voice->addr += voice->frac >> 16; + if ((voice->addr >> 1) > voice->end_addr) + { + if (voice->loop) + { + voice->addr = (voice->addr + (voice->loop_addr << 1)) - (voice->end_addr << 1); + } + else + { + voice->keyon = false; + voice->lout = 0; + voice->rout = 0; + return; + } + } + if (voice->noise) + { + c219->lfsr = (c219->lfsr >> 1) ^ ((-(c219->lfsr & 1)) & 0xfff6); + } + voice->frac &= 0xffff; + } + } + if (!voice->muted) + { + signed int sample = 0; + if (voice->noise) + { + sample = (signed int)((signed short)(c219->lfsr)); + } + else + { + // fetch 8 bit sample + signed short s1 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | voice->addr]; + signed short s2 = c219->sample_mem[((unsigned int)(c219->bank[(v >> 2) & 3]) << 17) | ((voice->addr + 1) & 0x1ffff)]; + if (voice->compressed) + { + s1 = c219->mulaw[s1]; + s2 = c219->mulaw[s2]; + } + else + { + s1 = (signed short)((signed char)(s1) << 8); + s2 = (signed short)((signed char)(s2) << 8); + } + if (voice->inv_sign) + { + s1 = -s1; + s2 = -s2; + } + // interpolate (originally was >>16, but I had to reduce it to 15 to prevent overflow) + sample = s1 + (((voice->frac >> 1) * (s2 - s1)) >> 15); + } + voice->lout = (voice->inv_lout ? (-sample) : sample) * voice->lvol; + voice->rout = sample * voice->rvol; + } + else + { + voice->lout = 0; + voice->rout = 0; + } + } + else + { + voice->lout = 0; + voice->rout = 0; + } +} + void c140_keyon(struct c140_voice_t *c140_voice) { c140_voice->busy = true; @@ -125,6 +215,14 @@ void c140_keyon(struct c140_voice_t *c140_voice) c140_voice->addr = c140_voice->start_addr; } +void c219_keyon(struct c140_voice_t *c140_voice) +{ + c140_voice->busy = true; + c140_voice->keyon = true; + c140_voice->frac = 0; + c140_voice->addr = c140_voice->start_addr << 1; +} + void c140_init(struct c140_t *c140) { // u-law table verified from Wii Virtual Console Arcade Starblade @@ -149,6 +247,41 @@ void c140_init(struct c140_t *c140) } } +void c219_init(struct c219_t *c219) +{ + // u-law table verified from Wii Virtual Console Arcade Knuckle Heads + for (int i = 0; i < 128; i++) + { + signed int compressed_sample = 0; + if (i < 16) + { + compressed_sample = 0x20 * i; + } + else if (i < 24) + { + compressed_sample = (0x200 + (0x40 * i)) - 0x400; + } + else if (i < 48) + { + compressed_sample = (0x400 + (0x80 * i)) - 0xc00; + } + else if (i < 100) + { + compressed_sample = (0x1000 + (0x100 * i)) - 0x3000; + } + else + { + compressed_sample = (0x4400 + (0x200 * i)) - 0xc800; + } + c219->mulaw[i] = compressed_sample; + c219->mulaw[i + 128] = (~compressed_sample) & 0xffe0; + } + for (int i = 0; i < 16; i++) + { + c219->voice[i].muted = false; + } +} + void c140_reset(struct c140_t *c140) { for (int i = 0; i < 24; i++) @@ -171,6 +304,35 @@ void c140_reset(struct c140_t *c140) } } +void c219_reset(struct c219_t *c219) +{ + for (int i = 0; i < 16; i++) + { + c219->voice[i].busy = false; + c219->voice[i].keyon = false; + c219->voice[i].freq = 0; + c219->voice[i].start_addr = 0; + c219->voice[i].loop_addr = 0; + c219->voice[i].end_addr = 0; + c219->voice[i].lvol = 0; + c219->voice[i].rvol = 0; + c219->voice[i].noise = false; + c219->voice[i].inv_lout = false; + c219->voice[i].inv_sign = false; + c219->voice[i].compressed = false; + c219->voice[i].loop = false; + c219->voice[i].addr = 0; + c219->voice[i].frac = 0; + c219->voice[i].lout = 0; + c219->voice[i].rout = 0; + } + c219->lfsr = 0x1234; + for (int i = 0; i < 4; i++) + { + c219->bank[i] = 0; + } +} + void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data) { // voice register @@ -203,3 +365,47 @@ void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned c } // Timer } + +void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data) +{ + // voice register + if (addr < 0x180) + { + struct c140_voice_t *voice = &c219->voice[addr >> 4]; + switch (addr & 0xf) + { + case 0x0: voice->rvol = data; break; + case 0x1: voice->lvol = data; break; + case 0x2: voice->freq = (voice->freq & ~0xff00) | (unsigned int)(data << 8); break; + case 0x3: voice->freq = (voice->freq & ~0x00ff) | data; break; + //case 0x4: break; // Unknown + case 0x5: + voice->compressed = c140_bit(data, 0); + voice->noise = c140_bit(data, 2); + voice->inv_lout = c140_bit(data, 3); + voice->loop = c140_bit(data, 4); + voice->inv_sign = c140_bit(data, 6); + if (data & 0x80) + c219_keyon(voice); + else + voice->busy = false; + break; + case 0x6: voice->start_addr = (voice->start_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0x7: voice->start_addr = (voice->start_addr & ~0x00ff) | data; break; + case 0x8: voice->end_addr = (voice->end_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0x9: voice->end_addr = (voice->end_addr & ~0x00ff) | data; break; + case 0xa: voice->loop_addr = (voice->loop_addr & ~0xff00) | (unsigned int)(data << 8); break; + case 0xb: voice->loop_addr = (voice->loop_addr & ~0x00ff) | data; break; + default: break; + } + } + // bank + else if (addr >= 0x1f0) + { + if (addr & 1) + { + const unsigned short bankaddr = (addr >> 1) & 3; + c219->bank[(bankaddr + 1) & 3] = (data & 3); + } + } +} diff --git a/src/engine/platform/sound/c140.h b/src/engine/platform/sound/c140_c219.h similarity index 71% rename from src/engine/platform/sound/c140.h rename to src/engine/platform/sound/c140_c219.h index 21a8b8a47..fb19125a3 100644 --- a/src/engine/platform/sound/c140.h +++ b/src/engine/platform/sound/c140_c219.h @@ -2,7 +2,7 @@ ============================================================================ -MODIFIED Namco C140 sound emulator - MODIFIED VERSION +MODIFIED Namco C140/C219 sound emulator - MODIFIED VERSION by cam900 MODIFICATION by tildearrow - adds muting function @@ -41,8 +41,8 @@ TODO: */ -#ifndef _C140_EMU_H -#define _C140_EMU_H +#ifndef _C140_C219_EMU_H +#define _C140_C219_EMU_H #include @@ -58,13 +58,16 @@ struct c140_voice_t bool keyon; // key on flag unsigned short freq; // sample frequency unsigned char bank; // sample bank - unsigned short start_addr; // sample start address - unsigned short loop_addr; // sample loop address - unsigned short end_addr; // sample end address + unsigned int start_addr; // sample start address + unsigned int loop_addr; // sample loop address + unsigned int end_addr; // sample end address int lvol, rvol; // left/right volume + bool noise; // noise flag + bool inv_lout; // invert left output flag + bool inv_sign; // invert sign bit flag bool compressed; // compressed sample flag bool loop; // loop flag - unsigned short addr; // sample address + unsigned int addr; // sample address int frac; // frequency counter (.16 fixed point) int lout, rout; // left/right output }; @@ -77,20 +80,42 @@ struct c140_t signed short *sample_mem; }; +struct c219_t +{ + struct c140_voice_t voice[16]; + signed int lout, rout; + signed short mulaw[256]; + unsigned short lfsr; + unsigned char bank[4]; + signed char *sample_mem; +}; + void c140_tick(struct c140_t *c140, const int cycle); +void c219_tick(struct c219_t *c219, const int cycle); + void c140_voice_tick(struct c140_t *c140, const unsigned char v, const int cycle); +void c219_voice_tick(struct c219_t *c219, const unsigned char v, const int cycle); + void c140_keyon(struct c140_voice_t *c140_voice); +void c219_keyon(struct c140_voice_t *c140_voice); + void c140_write(struct c140_t *c140, const unsigned short addr, const unsigned char data); +void c219_write(struct c219_t *c219, const unsigned short addr, const unsigned char data); + void c140_init(struct c140_t *c140); +void c219_init(struct c219_t *c219); + void c140_reset(struct c140_t *c140); +void c219_reset(struct c219_t *c219); + #ifdef __cplusplus } // extern "C" #endif -#endif // _C140_EMU_H +#endif // _C140_C219_EMU_H diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index 3c591cdaf..0aae51a8c 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -458,6 +458,10 @@ DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformSoundUnit::getPan(int ch) { + return parent->convertPanLinearToSplit(chan[ch].pan,8,255); +} + DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/su.h b/src/engine/platform/su.h index d83ae4777..99b784df3 100644 --- a/src/engine/platform/su.h +++ b/src/engine/platform/su.h @@ -105,6 +105,7 @@ class DivPlatformSoundUnit: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 04039e6e5..4e5fb4cca 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -476,6 +476,10 @@ DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformSwan::getPan(int ch) { + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index 72ddae394..1e0fbeef7 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -62,6 +62,7 @@ class DivPlatformSwan: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/t6w28.cpp b/src/engine/platform/t6w28.cpp index 90140da99..f2dfe7120 100644 --- a/src/engine/platform/t6w28.cpp +++ b/src/engine/platform/t6w28.cpp @@ -300,6 +300,10 @@ DivMacroInt* DivPlatformT6W28::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformT6W28::getPan(int ch) { + return (chan[ch].panL<<8)|chan[ch].panR; +} + DivDispatchOscBuffer* DivPlatformT6W28::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/t6w28.h b/src/engine/platform/t6w28.h index 33c03a886..4bb3cda2a 100644 --- a/src/engine/platform/t6w28.h +++ b/src/engine/platform/t6w28.h @@ -63,6 +63,7 @@ class DivPlatformT6W28: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 6e70895b2..52f71aedc 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -206,7 +206,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (chan[i].std.alg.had) { chan[i].state.alg=chan[i].std.alg.val; - immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0:0x40)|(chan[i].chVolR<<7)); + immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0x40:0)|(chan[i].chVolR<<7)); if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; @@ -223,7 +223,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { } if (chan[i].std.fb.had) { chan[i].state.fb=chan[i].std.fb.val; - immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0:0x40)|(chan[i].chVolR<<7)); + immWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|(chan[i].active?0x40:0)|(chan[i].chVolR<<7)); } if (chan[i].std.fms.had) { chan[i].state.fms=chan[i].std.fms.val; @@ -262,7 +262,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isMuted[i] || !op.enable) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -965,6 +965,10 @@ DivMacroInt* DivPlatformTX81Z::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformTX81Z::getPan(int ch) { + return (chan[ch].chVolL<<8)|(chan[ch].chVolR); +} + DivDispatchOscBuffer* DivPlatformTX81Z::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index d0bc759c1..c14bc0117 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -65,6 +65,7 @@ class DivPlatformTX81Z: public DivPlatformOPM { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/vb.cpp b/src/engine/platform/vb.cpp index 9edaf2db4..588676aff 100644 --- a/src/engine/platform/vb.cpp +++ b/src/engine/platform/vb.cpp @@ -419,6 +419,10 @@ DivMacroInt* DivPlatformVB::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformVB::getPan(int ch) { + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivDispatchOscBuffer* DivPlatformVB::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/vb.h b/src/engine/platform/vb.h index 2efcdd1b8..2282f62fe 100644 --- a/src/engine/platform/vb.h +++ b/src/engine/platform/vb.h @@ -69,6 +69,7 @@ class DivPlatformVB: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index fa0446ca6..6d97c9c4e 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -444,6 +444,10 @@ DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformVERA::getPan(int ch) { + return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1); +} + DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 227512a73..515e17e56 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -64,6 +64,7 @@ class DivPlatformVERA: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 29601ae92..d1422439e 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -863,6 +863,11 @@ DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformX1_010::getPan(int ch) { + if (!stereo) return 0; + return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15); +} + DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index a3af7b291..cc698b650 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -131,6 +131,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 02e92e191..2e805f3cd 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -402,7 +402,7 @@ void DivPlatformYM2203::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isMuted[i] || !op.enable) { rWrite(baseAddr+ADDR_TL,127); } else { diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index 31294bd4f..349c8a820 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -502,7 +502,7 @@ void DivPlatformYM2203Ext::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -606,13 +606,15 @@ void DivPlatformYM2203Ext::muteChannel(int ch, bool mute) { DivPlatformYM2203::muteChannel(extChanOffs,IS_EXTCH_MUTED); if (extMode) { - int ordch=orderedOps[ch-2]; - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=chan[2].state.op[ordch]; - if (isOpMuted[ch-2] || !op.enable) { - rWrite(baseAddr+0x40,127); - } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); + for (int i=0; i<4; i++) { + int ordch=orderedOps[i]; + unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + DivInstrumentFM::Operator op=chan[2].state.op[ordch]; + if (isOpMuted[i] || !op.enable) { + rWrite(baseAddr+0x40,127); + } else { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } } } } @@ -669,6 +671,9 @@ void DivPlatformYM2203Ext::forceIns() { opChan[i].freqChanged=true; } } + if (!extMode) { + immWrite(0x27,0x00); + } } void* DivPlatformYM2203Ext::getChanState(int ch) { diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 183533f81..93c09fd67 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -606,7 +606,7 @@ void DivPlatformYM2608::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isMuted[i] || !op.enable) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -1461,6 +1461,11 @@ DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYM2608::getPan(int ch) { + if (ch>=psgChanOffs && chsong.sharedExtStat) { + for (int j=0; j<4; j++) { + if (i==j) continue; + opChan[j].pan=opChan[i].pan; + } + } + rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } + // param macros unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; @@ -538,7 +550,7 @@ void DivPlatformYM2608Ext::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -641,13 +653,15 @@ void DivPlatformYM2608Ext::muteChannel(int ch, bool mute) { DivPlatformYM2608::muteChannel(extChanOffs,IS_EXTCH_MUTED); if (extMode) { - int ordch=orderedOps[ch-2]; - unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; - DivInstrumentFM::Operator op=chan[2].state.op[ordch]; - if (isOpMuted[ch-2] || !op.enable) { - rWrite(baseAddr+0x40,127); - } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-2].outVol&0x7f,127)); + for (int i=0; i<4; i++) { + int ordch=orderedOps[i]; + unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; + DivInstrumentFM::Operator op=chan[2].state.op[ordch]; + if (isOpMuted[i] || !op.enable) { + rWrite(baseAddr+0x40,127); + } else { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } } rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); @@ -719,6 +733,9 @@ void DivPlatformYM2608Ext::forceIns() { opChan[i].freqChanged=true; } } + if (!extMode) { + immWrite(0x27,0x00); + } } void* DivPlatformYM2608Ext::getChanState(int ch) { @@ -734,6 +751,18 @@ DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYM2608Ext::getPan(int ch) { + if (ch>=4+extChanOffs) return DivPlatformYM2608::getPan(ch-3); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2608::getPan(extChanOffs); + } + } + return DivPlatformYM2608::getPan(ch); +} + DivDispatchOscBuffer* DivPlatformYM2608Ext::getOscBuffer(int ch) { if (ch>=6) return oscBuf[ch-3]; if (ch<3) return oscBuf[ch]; @@ -750,7 +779,9 @@ void DivPlatformYM2608Ext::reset() { opChan[i].outVol=127; } - // channel 2 mode + lastExtChPan=3; + + // channel 3 mode immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/ym2608ext.h b/src/engine/platform/ym2608ext.h index c9348b48f..0c9c1a418 100644 --- a/src/engine/platform/ym2608ext.h +++ b/src/engine/platform/ym2608ext.h @@ -33,6 +33,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 5a1d80b58..b7dcdb231 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -539,7 +539,7 @@ void DivPlatformYM2610::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isMuted[i] || !op.enable) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -1421,6 +1421,11 @@ DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYM2610::getPan(int ch) { + if (ch>=psgChanOffs && ch=psgChanOffs && chsong.sharedExtStat) { + for (int j=0; j<4; j++) { + if (i==j) continue; + opChan[j].pan=opChan[i].pan; + } + } + rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } + // param macros unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]]; DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]]; @@ -533,7 +545,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -636,13 +648,15 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { DivPlatformYM2610B::muteChannel(extChanOffs,IS_EXTCH_MUTED); if (extMode) { - int ordch=orderedOps[ch-extChanOffs]; - unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; - DivInstrumentFM::Operator op=chan[extChanOffs].state.op[ordch]; - if (isOpMuted[ch-extChanOffs] || !op.enable) { - rWrite(baseAddr+0x40,127); - } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-extChanOffs].outVol&0x7f,127)); + for (int i=0; i<4; i++) { + int ordch=orderedOps[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; + DivInstrumentFM::Operator op=chan[extChanOffs].state.op[ordch]; + if (isOpMuted[i] || !op.enable) { + rWrite(baseAddr+0x40,127); + } else { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } } rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-extChanOffs].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); @@ -682,7 +696,7 @@ void DivPlatformYM2610BExt::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==extChanOffs) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } @@ -709,6 +723,9 @@ void DivPlatformYM2610BExt::forceIns() { opChan[i].freqChanged=true; } } + if (!extMode) { + immWrite(0x27,0x00); + } } void* DivPlatformYM2610BExt::getChanState(int ch) { @@ -724,6 +741,18 @@ DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYM2610BExt::getPan(int ch) { + if (ch>=4+extChanOffs) return DivPlatformYM2610B::getPan(ch-3); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2610B::getPan(extChanOffs); + } + } + return DivPlatformYM2610B::getPan(ch); +} + DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) { if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; if (ch<(extChanOffs+1)) return oscBuf[ch]; @@ -740,7 +769,9 @@ void DivPlatformYM2610BExt::reset() { opChan[i].outVol=127; } - // channel 2 mode + lastExtChPan=3; + + // channel 3 mode immWrite(0x27,0x40); extMode=true; } diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index b14ba99c4..024119cff 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -33,6 +33,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 65124f474..f0ab46990 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -152,6 +152,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { } } rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + lastExtChPan=opChan[ch].pan; break; } case DIV_CMD_PITCH: { @@ -504,6 +505,17 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { rWrite(0x22,lfoValue); } + if (opChan[i].std.panL.had) { + opChan[i].pan=opChan[i].std.panL.val&3; + if (parent->song.sharedExtStat) { + for (int j=0; j<4; j++) { + if (i==j) continue; + opChan[j].pan=opChan[i].pan; + } + } + rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); + } + // param macros unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[orderedOps[i]]; DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[orderedOps[i]]; @@ -533,7 +545,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) { rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); } if (m.tl.had) { - op.tl=127-m.tl.val; + op.tl=m.tl.val; if (isOpMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { @@ -636,13 +648,15 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { DivPlatformYM2610::muteChannel(extChanOffs,IS_EXTCH_MUTED); if (extMode) { - int ordch=orderedOps[ch-extChanOffs]; - unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; - DivInstrumentFM::Operator op=chan[extChanOffs].state.op[ordch]; - if (isOpMuted[ch-extChanOffs] || !op.enable) { - rWrite(baseAddr+0x40,127); - } else { - rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch-extChanOffs].outVol&0x7f,127)); + for (int i=0; i<4; i++) { + int ordch=orderedOps[i]; + unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[ordch]; + DivInstrumentFM::Operator op=chan[extChanOffs].state.op[ordch]; + if (isOpMuted[i] || !op.enable) { + rWrite(baseAddr+0x40,127); + } else { + rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); + } } rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-extChanOffs].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); @@ -682,7 +696,7 @@ void DivPlatformYM2610Ext::forceIns() { } rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); if (i==extChanOffs) { - rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } else { rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); } @@ -709,6 +723,9 @@ void DivPlatformYM2610Ext::forceIns() { opChan[i].freqChanged=true; } } + if (!extMode) { + immWrite(0x27,0x00); + } } void* DivPlatformYM2610Ext::getChanState(int ch) { @@ -724,6 +741,18 @@ DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYM2610Ext::getPan(int ch) { + if (ch>=4+extChanOffs) return DivPlatformYM2610::getPan(ch-3); + if (ch>=extChanOffs) { + if (extMode) { + return ((lastExtChPan&2)<<7)|(lastExtChPan&1); + } else { + return DivPlatformYM2610::getPan(extChanOffs); + } + } + return DivPlatformYM2610::getPan(ch); +} + DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) { if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; if (ch<(extChanOffs+1)) return oscBuf[ch]; @@ -740,6 +769,8 @@ void DivPlatformYM2610Ext::reset() { opChan[i].outVol=127; } + lastExtChPan=3; + // channel 2 mode immWrite(0x27,0x40); extMode=true; diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 2ce887c36..f860a36cd 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -33,6 +33,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); void reset(); void forceIns(); diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 496f35686..12f2251da 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -359,6 +359,10 @@ DivMacroInt* DivPlatformYMZ280B::getChanMacroInt(int ch) { return &chan[ch].std; } +unsigned short DivPlatformYMZ280B::getPan(int ch) { + return parent->convertPanLinearToSplit(chan[ch].panning,8,15); +} + DivDispatchOscBuffer* DivPlatformYMZ280B::getOscBuffer(int ch) { return oscBuf[ch]; } diff --git a/src/engine/platform/ymz280b.h b/src/engine/platform/ymz280b.h index 14a67dc98..913b8ec6e 100644 --- a/src/engine/platform/ymz280b.h +++ b/src/engine/platform/ymz280b.h @@ -59,6 +59,7 @@ class DivPlatformYMZ280B: public DivDispatch { int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); + unsigned short getPan(int chan); DivDispatchOscBuffer* getOscBuffer(int chan); unsigned char* getRegisterPool(); int getRegisterPoolSize(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index f379b7219..7483a972a 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1164,7 +1164,11 @@ void DivEngine::nextRow() { } if (haltOn==DIV_HALT_PATTERN) halted=true; } else if (playing) if (++curRow>=curSubSong->patLen) { - nextOrder(); + if (shallStopSched) { + curRow=curSubSong->patLen-1; + } else { + nextOrder(); + } if (haltOn==DIV_HALT_PATTERN) halted=true; } @@ -1208,8 +1212,26 @@ void DivEngine::nextRow() { if (disCont[dispatchOfChan[i]].dispatch!=NULL) { wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote(); if (wantPreNote) { + bool doPreparePreNote=true; int addition=0; + for (int j=0; jdata[curRow][4+(j<<1)]==0x03) { + doPreparePreNote=false; + break; + } + if (pat->data[curRow][4+(j<<1)]==0x06) { + doPreparePreNote=false; + break; + } + if (pat->data[curRow][4+(j<<1)]==0xea) { + if (pat->data[curRow][5+(j<<1)]>0) { + doPreparePreNote=false; + break; + } + } + } if (pat->data[curRow][4+(j<<1)]==0xed) { if (pat->data[curRow][5+(j<<1)]>0) { addition=pat->data[curRow][5+(j<<1)]&255; @@ -1217,7 +1239,7 @@ void DivEngine::nextRow() { } } } - dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition)); + if (doPreparePreNote) dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition)); } } diff --git a/src/engine/song.h b/src/engine/song.h index 803f87360..78c49b4e1 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -130,7 +130,8 @@ enum DivSystem { DIV_SYSTEM_PV1000, DIV_SYSTEM_K053260, DIV_SYSTEM_TED, - DIV_SYSTEM_C140 + DIV_SYSTEM_C140, + DIV_SYSTEM_C219 }; enum DivEffectType: unsigned short { @@ -375,6 +376,7 @@ struct DivSong { bool patchbayAuto; bool brokenPortaLegato; bool brokenFMOff; + bool preNoteNoEffect; std::vector ins; std::vector wave; @@ -493,7 +495,8 @@ struct DivSong { oldArpStrategy(false), patchbayAuto(true), brokenPortaLegato(false), - brokenFMOff(false) { + brokenFMOff(false), + preNoteNoEffect(false) { for (int i=0; i, effectValAnd<15>}}, }); EffectHandlerMap fmOPN2PostEffectHandlerMap(fmOPNPostEffectHandlerMap); @@ -769,7 +773,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1028,7 +1032,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, {}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNPostEffectHandlerMap ); @@ -1040,7 +1044,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, {}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNPostEffectHandlerMap ); @@ -1064,7 +1068,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1076,7 +1080,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1368,7 +1372,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1380,7 +1384,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1457,7 +1461,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1469,7 +1473,7 @@ void DivEngine::registerSystems() { {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMA, DIV_INS_ADPCMB}, {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, - fmEffectHandlerMap, + fmExtChEffectHandlerMap, fmOPNAPostEffectHandlerMap ); @@ -1883,6 +1887,20 @@ void DivEngine::registerSystems() { {} ); + sysDefs[DIV_SYSTEM_C219]=new DivSysDef( + "Namco C219", NULL, 0xcf, 0, 16, false, true, 0x161, false, (1U<runExportThread(); +} + +bool DivEngine::isExporting() { + return exporting; +} + +#ifdef HAVE_SNDFILE +void DivEngine::runExportThread() { + size_t fadeOutSamples=got.rate*exportFadeOut; + size_t curFadeOutSample=0; + bool isFadingOut=false; + + switch (exportMode) { + case DIV_EXPORT_MODE_ONE: { + SNDFILE* sf; + SF_INFO si; + SFWrapper sfWrap; + si.samplerate=got.rate; + si.channels=2; + si.format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; + + sf=sfWrap.doOpen(exportPath.c_str(),SFM_WRITE,&si); + if (sf==NULL) { + logE("could not open file for writing! (%s)",sf_strerror(NULL)); + exporting=false; + return; + } + + float* outBuf[3]; + outBuf[0]=new float[EXPORT_BUFSIZE]; + outBuf[1]=new float[EXPORT_BUFSIZE]; + outBuf[2]=new float[EXPORT_BUFSIZE*2]; + + // take control of audio output + deinitAudioBackend(); + playSub(false); + + logI("rendering to file..."); + + while (playing) { + size_t total=0; + nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); + if (totalProcessed>EXPORT_BUFSIZE) { + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; + } + for (int i=0; i<(int)totalProcessed; i++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i]))*mul; + outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i]))*mul; + if (++curFadeOutSample>=fadeOutSamples) { + playing=false; + break; + } + } else { + outBuf[2][i<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][i])); + outBuf[2][1+(i<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][i])); + if (lastLoopPos>-1 && i>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; + } + } + } + + if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { + logE("error: failed to write entire buffer!"); + break; + } + } + + delete[] outBuf[0]; + delete[] outBuf[1]; + delete[] outBuf[2]; + + if (sfWrap.doClose()!=0) { + logE("could not close audio file!"); + } + exporting=false; + + if (initAudioBackend()) { + for (int i=0; isetRun(true)) { + logE("error while activating audio!"); + } + } + logI("done!"); + break; + } + case DIV_EXPORT_MODE_MANY_SYS: { + SNDFILE* sf[DIV_MAX_CHIPS]; + SF_INFO si[DIV_MAX_CHIPS]; + String fname[DIV_MAX_CHIPS]; + SFWrapper sfWrap[DIV_MAX_CHIPS]; + for (int i=0; igetOutputCount(); + si[i].format=SF_FORMAT_WAV|SF_FORMAT_PCM_16; + } + + for (int i=0; igetOutputCount()]; + } + + // take control of audio output + deinitAudioBackend(); + playSub(false); + + logI("rendering to files..."); + + while (playing) { + size_t total=0; + nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); + if (totalProcessed>EXPORT_BUFSIZE) { + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; + } + for (int j=0; j<(int)totalProcessed; j++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + for (int i=0; i=fadeOutSamples) { + playing=false; + break; + } + } else { + for (int i=0; i-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; + } + } + } + for (int i=0; isetRun(true)) { + logE("error while activating audio!"); + } + } + logI("done!"); + break; + } + case DIV_EXPORT_MODE_MANY_CHAN: { + // take control of audio output + deinitAudioBackend(); + + float* outBuf[3]; + outBuf[0]=new float[EXPORT_BUFSIZE]; + outBuf[1]=new float[EXPORT_BUFSIZE]; + outBuf[2]=new float[EXPORT_BUFSIZE*2]; + int loopCount=remainingLoops; + + logI("rendering to files..."); + + for (int i=0; imuteChannel(dispatchChanOfChan[j],isMuted[j]); + } + } + + curOrder=0; + prevOrder=0; + curFadeOutSample=0; + lastLoopPos=-1; + totalLoops=0; + isFadingOut=false; + if (exportFadeOut<=0.01) { + remainingLoops=loopCount; + } else { + remainingLoops=-1; + } + playSub(false); + + while (playing) { + size_t total=0; + nextBuf(NULL,outBuf,0,2,EXPORT_BUFSIZE); + if (totalProcessed>EXPORT_BUFSIZE) { + logE("error: total processed is bigger than export bufsize! %d>%d",totalProcessed,EXPORT_BUFSIZE); + totalProcessed=EXPORT_BUFSIZE; + } + for (int j=0; j<(int)totalProcessed; j++) { + total++; + if (isFadingOut) { + double mul=(1.0-((double)curFadeOutSample/(double)fadeOutSamples)); + outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j]))*mul; + outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j]))*mul; + if (++curFadeOutSample>=fadeOutSamples) { + playing=false; + break; + } + } else { + outBuf[2][j<<1]=MAX(-1.0f,MIN(1.0f,outBuf[0][j])); + outBuf[2][1+(j<<1)]=MAX(-1.0f,MIN(1.0f,outBuf[1][j])); + if (lastLoopPos>-1 && j>=lastLoopPos && totalLoops>=exportLoopCount) { + logD("start fading out..."); + isFadingOut=true; + } + } + } + if (sf_writef_float(sf,outBuf[2],total)!=(int)total) { + logE("error: failed to write entire buffer!"); + break; + } + } + + if (sfWrap.doClose()!=0) { + logE("could not close audio file!"); + } + + if (getChannelType(i)==5) { + i++; + while (true) { + if (i>=chans) break; + if (getChannelType(i)!=5) break; + i++; + } + i--; + } + + if (stopExport) break; + } + exporting=false; + + delete[] outBuf[0]; + delete[] outBuf[1]; + delete[] outBuf[2]; + + for (int i=0; imuteChannel(dispatchChanOfChan[i],false); + } + } + + if (initAudioBackend()) { + for (int i=0; isetRun(true)) { + logE("error while activating audio!"); + } + } + logI("done!"); + break; + } + } + + stopExport=false; +} +#else +void DivEngine::runExportThread() { +} +#endif + +bool DivEngine::shallSwitchCores() { + // TODO: detect whether we should + return true; +} + +bool DivEngine::saveAudio(const char* path, int loops, DivAudioExportModes mode, double fadeOutTime) { +#ifndef HAVE_SNDFILE + logE("Furnace was not compiled with libsndfile. cannot export!"); + return false; +#else + exportPath=path; + exportMode=mode; + exportFadeOut=fadeOutTime; + if (exportMode!=DIV_EXPORT_MODE_ONE) { + // remove extension + String lowerCase=exportPath; + for (char& i: lowerCase) { + if (i>='A' && i<='Z') i+='a'-'A'; + } + size_t extPos=lowerCase.rfind(".wav"); + if (extPos!=String::npos) { + exportPath=exportPath.substr(0,extPos); + } + } + exporting=true; + stopExport=false; + stop(); + repeatPattern=false; + setOrder(0); + if (exportFadeOut<=0.01) { + remainingLoops=loops; + } else { + remainingLoops=-1; + } + + if (shallSwitchCores()) { + bool isMutedBefore[DIV_MAX_CHANS]; + memcpy(isMutedBefore,isMuted,DIV_MAX_CHANS*sizeof(bool)); + quitDispatch(); + initDispatch(true); + renderSamplesP(); + for (int i=0; ijoin(); + } +} + +bool DivEngine::haltAudioFile() { + stopExport=true; + stop(); + waitAudioFile(); + finishAudioFile(); + return true; +} + +void DivEngine::finishAudioFile() { + if (shallSwitchCores()) { + bool isMutedBefore[DIV_MAX_CHANS]; + memcpy(isMutedBefore,isMuted,DIV_MAX_CHANS*sizeof(bool)); + quitDispatch(); + initDispatch(false); + renderSamplesP(); + for (int i=0; i256) width=256; } -void DivWaveSynth::changeWave1(int num) { +#define SHALL_UPDATE_OUT (!state.enabled || force || (state.enabled && effectOnlyAltersOutput(state.effect))) + +void DivWaveSynth::changeWave1(int num, bool force) { DivWavetable* w1=e->getWave(num); if (width<1) return; for (int i=0; imax<1 || w1->len<1) { wave1[i]=0; - output[i]=0; + if (SHALL_UPDATE_OUT) output[i]=0; } else { int data=w1->data[i*w1->len/width]*height/w1->max; if (data<0) data=0; if (data>height) data=height; wave1[i]=data; - output[i]=data; + if (SHALL_UPDATE_OUT) output[i]=data; } } first=true; @@ -280,9 +298,9 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) { divCounter=0; subDivCounter=0; - changeWave1(state.wave1); + changeWave1(state.wave1,true); changeWave2(state.wave2); - tick(true); + //tick(true); // ??? first=true; } } diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index 81a3cbe19..21b6055ff 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -55,8 +55,9 @@ class DivWaveSynth { /** * change the first wave. * @param num wavetable number. + * @param force whether to force overwriting the current wave. */ - void changeWave1(int num); + void changeWave1(int num, bool force=false); /** * change the second wave. * @param num wavetable number. diff --git a/src/gui/about.cpp b/src/gui/about.cpp index 87d67f9c8..e1ce1b642 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -136,6 +136,7 @@ const char* aboutLine[]={ "UserSniper", "Weeppiko", "Xan", + "YaIiya", "Yuzu4K", "Zaxolotl", "ZoomTen (Zumi)", @@ -198,10 +199,11 @@ const char* aboutLine[]={ "vgsound_emu (second version, modified version) by cam900", "SM8521 emulator (modified version) by cam900", "D65010G031 emulator (modified version) by cam900", - "Namco C140 (modified version) emulator by cam900", + "Namco C140/C219 emulator (modified version) by cam900", "", "greetings to:", "NEOART Costa Rica", + "Xenium Demoparty", "all members of Deflers of Noice!", "", "copyright © 2021-2023 tildearrow", diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index aa7c91b5b..5ca97f479 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -448,6 +448,7 @@ void FurnaceGUI::drawChanOsc() { float maxLevel=-1.0f; float dcOff=0.0f; unsigned short needlePos=buf->needle; + //unsigned short needlePosOrig=needlePos; for (int i=0; iinBuf[i]=(double)buf->data[(unsigned short)(needlePos-displaySize*2+((i*displaySize*2)/FURNACE_FFT_SIZE))]/32768.0; } @@ -475,10 +476,7 @@ void FurnaceGUI::drawChanOsc() { } chanOscPitch[ch]=(float)point/32.0f; - /* - String cPhase=fmt::sprintf("%d cphase: %f vol: %f",point,phase,chanOscVol[ch]); - dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); - */ + needlePos-=displaySize; for (unsigned short i=0; i=needlePosOrig)?"WARN":"OK"); + //dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); } ImU32 color=ImGui::GetColorU32(chanOscColor); if (chanOscUseGrad) { diff --git a/src/gui/channels.cpp b/src/gui/channels.cpp index dd19d652d..48dad94f5 100644 --- a/src/gui/channels.cpp +++ b/src/gui/channels.cpp @@ -51,7 +51,9 @@ void FurnaceGUI::drawChannels() { ImGui::PushID(i); ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]); + if (ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i])) { + MARK_MODIFIED; + } ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROWS)) { } @@ -78,10 +80,14 @@ void FurnaceGUI::drawChannels() { } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]); + if (ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i])) { + MARK_MODIFIED; + } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputTextWithHint("##ChanShortName",e->getChannelShortName(i),&e->curSubSong->chanShortName[i]); + if (ImGui::InputTextWithHint("##ChanShortName",e->getChannelShortName(i),&e->curSubSong->chanShortName[i])) { + MARK_MODIFIED; + } ImGui::PopID(); } ImGui::EndTable(); diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 55f3cb589..efa88feec 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -184,6 +184,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6pre5"); } + ImGui::Checkbox("Pre-note does not take effects into consideration",&e->song.preNoteNoEffect); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6pre9"); + } ImGui::EndTabItem(); } if (ImGui::BeginTabItem(".mod import")) { @@ -314,7 +318,7 @@ void FurnaceGUI::drawCompatFlags() { } ImGui::Checkbox("Continuous vibrato",&e->song.continuousVibrato); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("when enabled, vibrato will not be reset on a new note."); + ImGui::SetTooltip("when enabled, vibrato phase/position will not be reset on a new note."); } InvCheckbox("Pitch macro is not linear",&e->song.pitchMacroIsLinear); if (ImGui::IsItemHovered()) { diff --git a/src/gui/cursor.cpp b/src/gui/cursor.cpp index 15f9e53ff..da2028454 100644 --- a/src/gui/cursor.cpp +++ b/src/gui/cursor.cpp @@ -374,7 +374,9 @@ void FurnaceGUI::moveCursorNextChannel(bool overflow) { } void FurnaceGUI::moveCursorTop(bool select) { - finishSelection(); + if (!select) { + finishSelection(); + } curNibble=false; if (cursor.y==0) { DETERMINE_FIRST; @@ -384,16 +386,18 @@ void FurnaceGUI::moveCursorTop(bool select) { } else { cursor.y=0; } - selStart=cursor; if (!select) { - selEnd=cursor; + selStart=cursor; } + selEnd=cursor; e->setMidiBaseChan(cursor.xCoarse); updateScroll(cursor.y); } void FurnaceGUI::moveCursorBottom(bool select) { - finishSelection(); + if (!select) { + finishSelection(); + } curNibble=false; if (cursor.y==e->curSubSong->patLen-1) { DETERMINE_LAST; diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index b373f72af..1506c5ff3 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -105,8 +105,10 @@ void FurnaceGUI::insListItem(int i, int dir, int asset) { bool insPressed=ImGui::IsItemActivated(); if (insReleased || (!insListDir && insPressed)) { curIns=i; - wavePreviewInit=true; - updateFMPreview=true; + if (!insReleased || insListDir) { + wavePreviewInit=true; + updateFMPreview=true; + } lastAssetType=0; if (settings.insFocusesPattern && patternOpen) nextWindow=GUI_WINDOW_PATTERN; @@ -892,15 +894,11 @@ void FurnaceGUI::drawSampleList(bool asChild) { doAction(GUI_ACTION_SAMPLE_LIST_PREVIEW); } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Preview"); + ImGui::SetTooltip("Preview (right click to stop)"); } - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_VOLUME_OFF "##StopSampleL")) { + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { doAction(GUI_ACTION_SAMPLE_LIST_STOP_PREVIEW); } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Stop preview"); - } ImGui::SameLine(); pushDestColor(); if (ImGui::Button(ICON_FA_TIMES "##SampleDelete")) { diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 9d59e44d2..b3c07b071 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -308,6 +308,21 @@ void FurnaceGUI::drawDebug() { } ImGui::TreePop(); } + if (ImGui::TreeNode("Do Action")) { + char bindID[1024]; + for (int j=0; j* ok, std::vector (*errorOutput)=true; break; default: - logE("NFD unknown return code %d!\n",ret); + logE("NFD unknown return code %d!\n",(int)ret); break; } (*ok)=true; diff --git a/src/gui/fmPreview.cpp b/src/gui/fmPreview.cpp index eaf449ed9..5586d1c20 100644 --- a/src/gui/fmPreview.cpp +++ b/src/gui/fmPreview.cpp @@ -20,8 +20,14 @@ #define _USE_MATH_DEFINES #include "gui.h" #include "../../extern/opn/ym3438.h" +#include "../../extern/opm/opm.h" +#include "../../extern/opl/opl3.h" +extern "C" { +#include "../../extern/Nuked-OPLL/opll.h" +} +#include "../engine/platform/sound/ymfm/ymfm_opz.h" -#define FM_WRITE(addr,val) \ +#define OPN_WRITE(addr,val) \ OPN2_Write((ym3438_t*)fmPreviewOPN,0,(addr)); \ do { \ OPN2_Clock((ym3438_t*)fmPreviewOPN,out); \ @@ -29,22 +35,23 @@ OPN2_Write((ym3438_t*)fmPreviewOPN,1,(val)); \ do { \ OPN2_Clock((ym3438_t*)fmPreviewOPN,out); \ - } while (((ym3438_t*)fmPreviewOPN)->write_busy); \ + } while (((ym3438_t*)fmPreviewOPN)->write_busy); const unsigned char dtTableFMP[8]={ 7,6,5,0,1,2,3,4 }; -void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) { +void FurnaceGUI::renderFMPreviewOPN(const DivInstrumentFM& params, int pos) { if (fmPreviewOPN==NULL) { fmPreviewOPN=new ym3438_t; + pos=0; } short out[2]; int aOut=0; bool mult0=false; if (pos==0) { - OPN2_Reset((ym3438_t*)fmPreviewOPN); + OPN2_Reset((ym3438_t*)fmPreviewOPN); OPN2_SetChipType((ym3438_t*)fmPreviewOPN,ym3438_mode_opn); // set params @@ -57,19 +64,19 @@ void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) { for (int i=0; i<4; i++) { const DivInstrumentFM::Operator& op=params.op[i]; unsigned short baseAddr=i*4; - FM_WRITE(baseAddr+0x40,op.tl); - FM_WRITE(baseAddr+0x30,(op.mult&15)|(dtTableFMP[op.dt&7]<<4)); - FM_WRITE(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); - FM_WRITE(baseAddr+0x60,(op.dr&31)|(op.am<<7)); - FM_WRITE(baseAddr+0x70,op.d2r&31); - FM_WRITE(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); - FM_WRITE(baseAddr+0x90,op.ssgEnv&15); + OPN_WRITE(baseAddr+0x40,op.tl); + OPN_WRITE(baseAddr+0x30,(op.mult&15)|(dtTableFMP[op.dt&7]<<4)); + OPN_WRITE(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); + OPN_WRITE(baseAddr+0x60,(op.dr&31)|(op.am<<7)); + OPN_WRITE(baseAddr+0x70,op.d2r&31); + OPN_WRITE(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); + OPN_WRITE(baseAddr+0x90,op.ssgEnv&15); } - FM_WRITE(0xb0,(params.alg&7)|((params.fb&7)<<3)); - FM_WRITE(0xb4,0xc0|(params.fms&7)|((params.ams&3)<<4)); - FM_WRITE(0xa4,mult0?0x1c:0x14); // frequency - FM_WRITE(0xa0,0); - FM_WRITE(0x28,0xf0); // key on + OPN_WRITE(0xb0,(params.alg&7)|((params.fb&7)<<3)); + OPN_WRITE(0xb4,0xc0|(params.fms&7)|((params.ams&3)<<4)); + OPN_WRITE(0xa4,mult0?0x1c:0x14); // frequency + OPN_WRITE(0xa0,0); + OPN_WRITE(0x28,0xf0); // key on } // render @@ -84,3 +91,270 @@ void FurnaceGUI::renderFMPreview(const DivInstrumentFM& params, int pos) { fmPreview[i]=aOut; } } + +#define OPM_WRITE(addr,val) \ + OPM_Write((opm_t*)fmPreviewOPM,0,(addr)); \ + do { \ + OPM_Clock((opm_t*)fmPreviewOPM,out,NULL,NULL,NULL); \ + OPM_Clock((opm_t*)fmPreviewOPM,out,NULL,NULL,NULL); \ + } while (((opm_t*)fmPreviewOPM)->write_busy); \ + OPM_Write((opm_t*)fmPreviewOPM,1,(val)); \ + do { \ + OPM_Clock((opm_t*)fmPreviewOPM,out,NULL,NULL,NULL); \ + OPM_Clock((opm_t*)fmPreviewOPM,out,NULL,NULL,NULL); \ + } while (((opm_t*)fmPreviewOPM)->write_busy); + +void FurnaceGUI::renderFMPreviewOPM(const DivInstrumentFM& params, int pos) { + if (fmPreviewOPM==NULL) { + fmPreviewOPM=new opm_t; + pos=0; + } + int out[2]; + int aOut=0; + bool mult0=false; + + if (pos==0) { + OPM_Reset((opm_t*)fmPreviewOPM); + + // set params + for (int i=0; i<4; i++) { + if ((params.op[i].mult&15)==0) { + mult0=true; + break; + } + } + for (int i=0; i<4; i++) { + const DivInstrumentFM::Operator& op=params.op[i]; + unsigned short baseAddr=i*8; + OPM_WRITE(baseAddr+0x40,(op.mult&15)|(dtTableFMP[op.dt&7]<<4)); + OPM_WRITE(baseAddr+0x60,op.tl); + OPM_WRITE(baseAddr+0x80,(op.ar&31)|(op.rs<<6)); + OPM_WRITE(baseAddr+0xa0,(op.dr&31)|(op.am<<7)); + OPM_WRITE(baseAddr+0xc0,(op.d2r&31)|(op.dt2<<6)); + OPM_WRITE(baseAddr+0xe0,(op.rr&15)|(op.sl<<4)); + } + OPM_WRITE(0x20,(params.alg&7)|((params.fb&7)<<3)|0xc0); + OPM_WRITE(0x38,((params.fms&7)<<4)|(params.ams&3)); + OPM_WRITE(0x28,mult0?0x39:0x29); // frequency + OPM_WRITE(0x30,0xe6); + OPM_WRITE(0x08,0x78); // key on + } + + // render + for (int i=0; i32767) aOut=32767; + fmPreview[i]=aOut; + } +} + +#define OPLL_WRITE(addr,val) \ + OPLL_Write((opll_t*)fmPreviewOPLL,0,(addr)); \ + for (int _i=0; _i<3; _i++) { \ + OPLL_Clock((opll_t*)fmPreviewOPLL,out); \ + } \ + OPLL_Write((opll_t*)fmPreviewOPLL,1,(val)); \ + for (int _i=0; _i<21; _i++) { \ + OPLL_Clock((opll_t*)fmPreviewOPLL,out); \ + } + +void FurnaceGUI::renderFMPreviewOPLL(const DivInstrumentFM& params, int pos) { + if (fmPreviewOPLL==NULL) { + fmPreviewOPLL=new opm_t; + pos=0; + } + int out[2]; + int aOut=0; + bool mult0=false; + + if (pos==0) { + OPLL_Reset((opll_t*)fmPreviewOPLL,opll_type_ym2413); + + // set params + const DivInstrumentFM::Operator& mod=params.op[0]; + const DivInstrumentFM::Operator& car=params.op[1]; + if (params.opllPreset==0) { + for (int i=0; i<2; i++) { + if ((params.op[i].mult&15)==0) { + mult0=true; + break; + } + } + OPLL_WRITE(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult)); + OPLL_WRITE(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult)); + OPLL_WRITE(0x02,(mod.ksl<<6)|(mod.tl&63)); + OPLL_WRITE(0x03,(car.ksl<<6)|((params.fms&1)<<4)|((params.ams&1)<<3)|(params.fb&7)); + OPLL_WRITE(0x04,(mod.ar<<4)|(mod.dr)); + OPLL_WRITE(0x05,(car.ar<<4)|(car.dr)); + OPLL_WRITE(0x06,(mod.sl<<4)|(mod.rr)); + OPLL_WRITE(0x07,(car.sl<<4)|(car.rr)); + } + OPLL_WRITE(0x10,0); + OPLL_WRITE(0x30,(params.opllPreset<<4)|(car.tl&15)); + OPLL_WRITE(0x20,(params.alg?0x20:0)|(mult0?0x15:0x13)); + } + + // render + for (int i=0; i32767) aOut=32767; + fmPreview[i]=aOut; + } +} + +#define OPL_WRITE(addr,val) \ + OPL3_WriteReg((opl3_chip*)fmPreviewOPL,(addr),(val)); \ + OPL3_Generate4Ch((opl3_chip*)fmPreviewOPL,out); + +const unsigned char lPreviewSlots[4]={ + 0, 3, 8, 11 +}; + +const unsigned char lOpMap[4]={ + 0, 2, 1, 3 +}; + +void FurnaceGUI::renderFMPreviewOPL(const DivInstrumentFM& params, int pos) { + if (fmPreviewOPL==NULL) { + fmPreviewOPL=new opl3_chip; + pos=0; + } + short out[4]; + bool mult0=false; + + if (pos==0) { + OPL3_Reset((opl3_chip*)fmPreviewOPL,49716); + + // set params + int ops=(params.ops==4)?4:2; + for (int i=0; i>1)&1)|(params.fb<<1)|0x10); + } + OPL_WRITE(0xa0,0); + if (ops==4) { + OPL_WRITE(0xa3,0); + } + OPL_WRITE(0xb0,mult0?0x2a:0x26); + if (ops==4) { + OPL_WRITE(0xb3,mult0?0x2a:0x26); + } + } + + // render + for (int i=0; iwrite(0,(addr)); \ + ((ymfm::ym2414*)fmPreviewOPZ)->write(1,(val)); \ + ((ymfm::ym2414*)fmPreviewOPZ)->generate(&out,1); + +void FurnaceGUI::renderFMPreviewOPZ(const DivInstrumentFM& params, int pos) { + if (fmPreviewOPZ==NULL) { + fmPreviewOPZInterface=new ymfm::ymfm_interface(); + fmPreviewOPZ=new ymfm::ym2414(*(ymfm::ymfm_interface*)fmPreviewOPZInterface); + pos=0; + } + ymfm::ymfm_output<2> out; + int aOut=0; + bool mult0=false; + + if (pos==0) { + ((ymfm::ym2414*)fmPreviewOPZ)->reset(); + + // set params + for (int i=0; i<4; i++) { + if ((params.op[i].mult&15)==0) { + mult0=true; + break; + } + } + for (int i=0; i<4; i++) { + const DivInstrumentFM::Operator& op=params.op[i]; + unsigned short baseAddr=i*8; + OPZ_WRITE(baseAddr+0x40,(op.mult&15)|((op.egt?(op.dt&7):dtTableFMP[op.dt&7])<<4)); + OPZ_WRITE(baseAddr+0x40,(op.dvb&15)|((op.ws&7)<<4)|0x80); + OPZ_WRITE(baseAddr+0x60,op.tl); + OPZ_WRITE(baseAddr+0x80,(op.ar&31)|(op.egt<<5)|(op.rs<<6)); + OPZ_WRITE(baseAddr+0xa0,(op.dr&31)|(op.am<<7)); + OPZ_WRITE(baseAddr+0xc0,(op.d2r&31)|(op.dt2<<6)); + OPZ_WRITE(baseAddr+0xc0,(op.dam&7)|(op.ksl<<6)|0x20); + OPZ_WRITE(baseAddr+0xe0,(op.rr&15)|(op.sl<<4)); + } + OPZ_WRITE(0x38,((params.fms&7)<<4)|(params.ams&3)); + OPZ_WRITE(0x38,((params.fms2&7)<<4)|(params.ams2&3)|0x84); + OPZ_WRITE(0x28,mult0?0x39:0x29); // frequency + OPZ_WRITE(0x30,0xe7); + OPZ_WRITE(0x20,(params.alg&7)|((params.fb&7)<<3)|0x40); // key on + } + + // render + for (int i=0; igenerate(&out,1); + aOut+=out.data[0]; + if (aOut<-32768) aOut=-32768; + if (aOut>32767) aOut=32767; + fmPreview[i]=aOut; + } +} + +void FurnaceGUI::renderFMPreview(const DivInstrument* ins, int pos) { + switch (ins->type) { + case DIV_INS_FM: + renderFMPreviewOPN(ins->fm,pos); + break; + case DIV_INS_OPM: + renderFMPreviewOPM(ins->fm,pos); + break; + case DIV_INS_OPLL: + renderFMPreviewOPLL(ins->fm,pos); + break; + case DIV_INS_OPL: + renderFMPreviewOPL(ins->fm,pos); + break; + case DIV_INS_OPZ: + renderFMPreviewOPZ(ins->fm,pos); + break; + default: + break; + } +} diff --git a/src/gui/font_furicon.cpp b/src/gui/font_furicon.cpp index 2e089477e..e149add9e 100644 --- a/src/gui/font_furicon.cpp +++ b/src/gui/font_furicon.cpp @@ -1,267 +1,268 @@ #include "fonts.h" -// File: 'icons.ttf' (28308 bytes) +// File: 'icons.ttf' (28108 bytes) // Exported using binary_to_compressed_c.cpp -const unsigned int furIcons_compressed_size = 14369; -const unsigned int furIcons_compressed_data[14372/4] = +const unsigned int furIcons_compressed_size = 14633; +const unsigned int furIcons_compressed_data[14636/4] = { - 0x0000bc57, 0x00000000, 0x946e0000, 0x00000400, 0x00010037, 0x000e0000, 0x00030080, 0x54464660, 0xb4e6a14d, 0x6e0000de, 0x28158278, 0x4544471c, - 0x00150046, 0x200f8214, 0x2b0f835c, 0x322f534f, 0x7652fa8c, 0x68010000, 0x562c0f82, 0x70616d63, 0xe8cf92c7, 0x60020000, 0xe22c1382, 0x20747663, - 0x6f043b00, 0x44040000, 0x04261f82, 0x70736167, 0x5982ffff, 0x546e0022, 0x08280f82, 0x66796c67, 0x482c6c0b, 0xe42c1f82, 0x80640000, 0x64616568, - 0xf131af24, 0xec201b82, 0x36210382, 0x23108268, 0x05068209, 0x24204b82, 0x24270f82, 0x78746d68, 0x8213d428, 0xc001214f, 0xa0280f82, 0x61636f6c, - 0x7ab2d9cb, 0x43823f82, 0x6d9a0028, 0x00707861, 0x3b820396, 0x0f830120, 0x616e202c, 0x877b656d, 0x000088bc, 0x43826469, 0x6f70f22c, 0x5ca17473, - 0x0000e2b7, 0xa382586b, 0xeb84fa20, 0x0000012d, 0x7a8b1ec8, 0xf53c0f5f, 0x82070b00, 0x00002556, 0x9ffffde0, 0xe12b0883, 0xfc0dea11, 0x0768fe80, - 0x82e00500, 0x0008220f, 0x83058202, 0x22338202, 0x82ff0006, 0x00072909, 0x000080fc, 0x01000007, 0x028b0c82, 0x11840420, 0xbb034c25, 0x83000800, - 0x00022100, 0x25832383, 0x2e004022, 0x0d820b82, 0x0100072b, 0x00050090, 0x048c0400, 0x201182e6, 0x2b0785fa, 0x59005c03, 0x0000cf01, 0x09050002, - 0x02851582, 0x85100121, 0x29058407, 0x54727546, 0x20004000, 0x838542e1, 0x6a840620, 0x8b840485, 0x26833b20, 0x04820720, 0xfc250383, 0x00090280, - 0x220c8291, 0x82200052, 0x00a52c79, 0x004b0035, 0x01910029, 0x8278006d, 0x0060349b, 0x01520047, 0x000a0017, 0x018f004a, 0x001b0032, 0x822e004f, - 0x01ca2631, 0x00360118, 0x251b82a9, 0x01330028, 0x9182004d, 0x03382382, 0x7c012200, 0x39007a01, 0x27013900, 0x1300ce01, 0x73014c00, 0x47002200, - 0x0b240d82, 0xb5008500, 0x5b260f82, 0x4b012e00, 0x01825c00, 0x2a005b22, 0x0b830784, 0xc8240383, 0x56015c00, 0x03208982, 0x1c200386, 0xdc22b386, - 0x09840300, 0x04001c24, 0x1b82c000, 0x0800082e, 0x00000200, 0xf4e02000, 0xffff42e1, 0xf0260984, 0xffff00e1, 0x0b82e3ff, 0x2b840020, 0x0e000622, - 0x04260b82, 0x06000500, 0x2f820700, 0x9d820920, 0x0c000b24, 0x17820d00, 0x10000f26, 0x12001100, 0x142c9d82, 0x16001500, 0x18001700, 0x1a001900, - 0x1c3adb82, 0x1e001d00, 0x20001f00, 0x22002100, 0x24002300, 0x26002500, 0x28002700, 0xab822900, 0x2c002b3a, 0x2e002d00, 0x30002f00, 0x32003100, - 0x34003300, 0x36003500, 0x38003700, 0x2208f182, 0x003b003a, 0x003d003c, 0x003f003e, 0x00410040, 0x00430042, 0x00450044, 0x00470046, 0x00490048, - 0x824b004a, 0x8506209a, 0x229b829e, 0x82020100, 0x00022105, 0x0121008d, 0x8dec8200, 0xd20d4012, 0x6f043b22, 0x2c21d582, 0x08018500, 0x84003c8e, - 0x6404c600, 0xc4052405, 0x5807d406, 0xce08ea07, 0x76093409, 0xfe0ab00a, 0xee0b880b, 0xe60c2e0c, 0xd80d6a0d, 0xca0e640e, 0x5a10a40f, 0x7e11bc10, - 0x9212c611, 0x8c130c13, 0x9814d813, 0x38164815, 0x80171217, 0xae1b1e1b, 0xc01c341c, 0x081fea1d, 0x8020bc1f, 0x8a213421, 0x8622fc21, 0x2a27c823, - 0xb028ca27, 0xc6295229, 0xbe2a0a2a, 0xf42ba42b, 0x242e162e, 0x6e2e482e, 0xde2fd02f, 0x5430ec2f, 0x70306230, 0xb0307e30, 0x4032be30, 0x21089982, - 0x003b0002, 0x04150200, 0x000300aa, 0xb12e0007, 0x3c2f0001, 0x000407b2, 0x06b132ed, 0xb23cdc05, 0x0a820203, 0x03b10022, 0x05201683, 0xb2271683, - 0xfc010607, 0x8301b23c, 0x11333717, 0x21251121, 0x013b2111, 0x0161feda, 0x049cfe64, 0x3b56fbaa, 0x57833404, 0xff80fc25, 0x828003f5, 0x82012009, - 0x05002e59, 0xfd212521, 0xf99a0533, 0x0b0007b3, 0x0815820b, 0x09020325, 0xf7040f00, 0x1b00fd03, 0x2f002500, 0x30010000, 0x15163221, 0x07010e14, - 0x16150706, 0x1e171617, 0x82141501, 0x010e2f0b, 0x21372123, 0x013d3632, 0x21232634, 0x09853335, 0x012b4d08, 0xbd010a02, 0x311f8e7d, 0x1e1e2020, - 0x1f202525, 0x2214132b, 0xfe385f23, 0x1801a217, 0x3f48483f, 0x3dfce8fe, 0xfc3d4242, 0x778dfd03, 0x0d324f38, 0x0208030c, 0x1c1c0d0d, 0x363c3f58, - 0x2c272735, 0x313e428b, 0x3e88423e, 0x3e3a2e39, 0x30088f83, 0x63009100, 0xa9036f06, 0x17000f00, 0x00002b00, 0x30273025, 0x30073021, 0x37123623, - 0x17121633, 0x06233001, 0x26333007, 0x00113001, 0x30333027, 0x2f038513, 0x11070206, 0x4cea0230, 0x8a49c7fe, 0xab2fbf2f, 0x34080382, 0x3c068dfe, - 0x023cf73d, 0x17f7fe84, 0xcb04cc9b, 0x1dce3794, 0x8ce3e363, 0x8c8c2e02, 0x028cd2fd, 0xb9b9b9c9, 0x4a01f0fd, 0xfe28d401, 0x6175018b, 0xfe329afe, - 0x218282b3, 0x04820300, 0x0007ab3a, 0x58036103, 0xba038c03, 0x26370000, 0x30332702, 0x1d17021d, 0x031d1704, 0x14910290, 0x478211a3, 0x719126f1, - 0x1e268695, 0x3e331701, 0x73413701, 0x220d8606, 0x8937033d, 0x8a042002, 0xa317850b, 0xf1298211, 0xa1719126, 0x06332e86, 0x26230702, 0x012e2702, - 0x010e2327, 0x2d0d8207, 0x27262205, 0x1e37013e, 0x35323301, 0x18832634, 0x26272629, 0x33363435, 0x82171632, 0x012e2b21, 0x15062223, 0x17161714, - 0x0285011e, 0x06141523, 0x223b8225, 0x82272223, 0x26272628, 0x37363734, 0x823c823e, 0x84072021, 0x011d352c, 0x32331614, 0x3d023e37, 0x33352301, - 0x188e2311, 0x0168185e, 0x043400cc, 0x040c040e, 0x390e030e, 0x390f7b0e, 0x030f030e, 0x040e030d, 0x012761cc, 0x19621864, 0x833a0e7a, 0x820c205c, - 0x3c0f3b5c, 0x4bf0020f, 0x2f0b276e, 0x314d1d0c, 0x09342a77, 0x2b5a0a24, 0x4865702a, 0x13822463, 0x401a3c08, 0x16373731, 0x24093116, 0x15443009, - 0x02741316, 0x4f090c43, 0x2b2c3448, 0x12132021, 0x22221212, 0x375a3d5f, 0x11531e38, 0x50483c46, 0x1a1e4850, 0x7c16271a, 0x70b75adf, 0xcd70be01, - 0x4d0010b8, 0x1a2d4701, 0x67191968, 0x10014419, 0xf0fe4444, 0x220a8244, 0x101a6819, 0x47015b01, 0x084d4741, 0x42fe70af, 0x13014570, 0x19671a45, - 0x451a6719, 0x0b45edfe, 0x2a0b3638, 0x6d2c290b, 0x020d2f2c, 0x2c150207, 0x615c512d, 0x290a3431, 0x2d24250b, 0x15162a34, 0x0208020c, 0x17171f0b, - 0x6865293f, 0x133e306e, 0x42292a13, 0x4242b842, 0x27282a2a, 0x31314726, 0xa4525c39, 0x09085c52, 0x3b1e3121, 0x009efe57, 0x52000700, 0xae0602ff, - 0x1a001a05, 0x38002400, 0x53004900, 0x80007800, 0x22050000, 0x37343526, 0x3337023e, 0x07060706, 0x3307010e, 0x3233013e, 0x06141516, 0x013d3227, - 0x1d222334, 0x26031401, 0x16332702, 0x17161712, 0x36373633, 0x272a8212, 0x23210702, 0x17322111, 0x07272783, 0x012e2313, 0x48372327, 0x15270779, - 0x27262201, 0x8234012e, 0x3637222a, 0x21238233, 0x58450617, 0x3698080b, 0x17011e37, 0x1105010e, 0x11011501, 0xa2013501, 0x0f106d6b, 0x8a314f3a, - 0x1e2a2a3b, 0x0c09251d, 0x51314711, 0x6d6a6e5f, 0x211f6c6d, 0x136b2183, 0x0e0e1450, 0x140e0e0c, 0x2169144e, 0x8f012083, 0x56090165, 0x3a392b2c, - 0x56087180, 0x249b7817, 0x9b242626, 0x5d3aad02, 0x23232122, 0x2e2e2221, 0x3333563b, 0x12490d1f, 0x4c44353e, 0x4236444c, 0x0e380f12, 0xe4fe6920, - 0x72fe2801, 0x84fdd8fe, 0x3c3d3c7f, 0x2d22606f, 0x28292829, 0x312f3256, 0x776a676a, 0x77197755, 0x56080282, 0x01701803, 0xfe466fbf, 0x4f4e46e7, - 0x01464e4f, 0xfe6f4619, 0x9e027041, 0x4d603433, 0xe7fe1160, 0x5536c913, 0x2a3e2a26, 0x8efede26, 0x842a2a27, 0x2a2a84b6, 0x25251414, 0x3929074a, - 0xa1525f32, 0x3b365e53, 0x4a092108, 0x34feb24e, 0xfe821001, 0xfecd0192, 0x820082ef, 0x00043f00, 0x06ab0020, 0x006103e0, 0x0015000b, 0x0074004a, - 0x11303700, 0x16322130, 0x012b0614, 0xb7490119, 0x46012008, 0x162205ce, 0x12821617, 0x2806d046, 0x3435012e, 0x3233023e, 0x08d14617, 0x1506072c, - 0x011f1614, 0x1415011e, 0xcd46020e, 0x022e2105, 0x16212485, 0x0cc64617, 0x3e373623, 0x06c84601, 0x0121d108, 0x66665d20, 0x2aadb45d, 0xad292f2e, - 0x7655dd02, 0x0d320c2a, 0x362b2b23, 0x3b2e4141, 0x620a270a, 0x563d2162, 0x37384c36, 0x0d320d28, 0x39384b1a, 0x37342020, 0x205d643c, 0xdd025a3f, - 0x4c5e0a04, 0x294a663c, 0x426c4d2a, 0x59237d5a, 0x503d5113, 0x20506161, 0x16161d1c, 0x5ff38a19, 0x6d9e02b7, 0xf5fe6db9, 0x282b6a01, 0xfd2b292e, - 0x0b343db6, 0x162b0c2f, 0x27313a17, 0x07020c2e, 0x515c1202, 0x1b31482c, 0x0b321a1b, 0x29210b2d, 0x2a2c1817, 0x130c0b29, 0x4d2f505d, 0x31711d37, - 0x82572d40, 0x58815454, 0x3447502e, 0x5d663b2f, 0x09665d6e, 0x2f0f1008, 0xfe5d3420, 0x0005009b, 0x06ab002e, 0x006103d2, 0x001f0012, 0x0134002a, - 0x25000046, 0x28076842, 0x1e32013e, 0x020e1402, 0x05834227, 0x1d06222a, 0x05161401, 0x17322111, 0x2c0f5e41, 0x27012e05, 0x17071d23, 0x1d170f1d, - 0x8502870e, 0x3305820b, 0x11231101, 0x17121633, 0x3317011e, 0x3d27053d, 0x0e3d270f, 0x0b880287, 0x3311042d, 0x02262311, 0x603c3301, 0x82232223, - 0x7a5f3a02, 0x23234460, 0x483c6144, 0x4f904f4f, 0x01df014f, 0x2b2c5609, 0x9aa35657, 0x26008225, 0x0863029a, 0x440c0922, 0x62280732, 0x22852175, - 0x0d082308, 0x76231088, 0x42ac8521, 0x282d074c, 0xb6845428, 0x5a275484, 0x52a2525d, 0x3304845d, 0x339e024f, 0xfe67c134, 0x256901f1, 0x26293d2a, - 0x155315b2, 0xae4d7f44, 0xfe02284d, 0x439e0270, 0x4043f4fe, 0x01268088, 0x4362fd90, 0x5f430c01, 0x00a53a05, 0x035b0654, 0x002f00b8, 0x00540048, - 0x2500005e, 0x010e2330, 0x022e2223, 0x078a4435, 0x20083e43, 0x06e34906, 0x82373621, 0x013d3501, 0x11213523, 0x32210123, 0x06141516, 0x07010e07, - 0x17021e15, 0x07300b82, 0x2123020e, 0x37323337, 0x34013d36, 0x012b2627, 0x080a5d4d, 0x0e04e541, 0x804a6074, 0x3035345c, 0x53434330, 0x122b9c71, - 0x6518124a, 0x7979634d, 0x24242863, 0x10101b1b, 0x772f01ac, 0x72010601, 0x141b7769, 0x1a1a3415, 0x1311353d, 0x4f391011, 0x8768fe2f, 0x821e35e9, - 0x356a0800, 0x3733d2e9, 0xe2d23337, 0x6d38503d, 0xa2686aa2, 0x1c1c3738, 0x2b0b5963, 0x7f493b0b, 0x7f758875, 0x14130b0a, 0x41271e1d, 0x0341fe75, - 0x2f627646, 0x14151542, 0x16010703, 0x3525242f, 0x412d2c32, 0x1c1b7525, 0x1b342933, 0x3033711c, 0x00333027, 0x00050000, 0x06ab0035, 0x006103cb, - 0x0046001f, 0x00600053, 0x25000066, 0x1b442622, 0x37362c13, 0x0617011e, 0x22210607, 0x8227012e, 0x37362321, 0x0646013e, 0x2a148205, 0x17163207, - 0x3233033e, 0x4315021e, 0xa8081058, 0x36352135, 0x11333712, 0x15231533, 0x23113325, 0x4e01010e, 0x49269683, 0x76584169, 0x48115b21, 0x59594d3b, - 0x124c3d4d, 0x210e3a0f, 0xfc013c3d, 0x113c5738, 0x23232c10, 0x39902955, 0x22212d2d, 0x020d1617, 0x1c0b0104, 0x2a203025, 0x211d3548, 0x3b35573e, - 0x42754141, 0xfea10242, 0x2eb52dc9, 0xfe5b5b8e, 0x2307dbbe, 0xa9b1ac8e, 0x2e588154, 0x30324b4d, 0x665d6a39, 0x313f6a5d, 0x49092309, 0x44242929, - 0x493d3030, 0x53363680, 0x2627291c, 0x2d2d2928, 0x15010136, 0x1c0f1b23, 0x332f4d37, 0x58213c53, 0x3d0d3d3e, 0x0804843e, 0x5d834d2f, 0x4a2a014a, - 0x83553afe, 0x3b6301d8, 0x000800ed, 0x0608ff4b, 0x001505b5, 0x0016000c, 0x0028001c, 0x0068005c, 0x009b0072, 0x11301700, 0x12354430, 0x83110121, - 0x113323ec, 0x01871521, 0x4c06a645, 0xb44c2d75, 0x13232406, 0x85031333, 0x010f2a0b, 0x013e2533, 0x010e2337, 0x82028207, 0x27028213, 0x17011e23, - 0x33112311, 0x2005af4c, 0x821e8233, 0x11332902, 0x0901b023, 0x582c2c56, 0x30075644, 0xf466ca01, 0xfe850186, 0xfe0301e1, 0xfa1f01fd, 0x0cdd4be7, - 0x4b092521, 0x0c2207dd, 0xdd4b0c2e, 0x38300811, 0xe1092209, 0x64082309, 0xf1ca81c9, 0x0d030e04, 0x3b040e03, 0x02d002b0, 0x080b0104, 0x5716071f, - 0x15571516, 0x0b081f08, 0x62010501, 0x12481278, 0x09200b82, 0x54080382, 0x77124712, 0x9f02f862, 0x67c23334, 0x6901f1fe, 0x293e2926, 0x02bcfd25, - 0x5abbfd9f, 0xc45a9f02, 0x035acf58, 0x0b353957, 0x2c2a0b2b, 0x0c2f2c6e, 0x14020802, 0x5d512c2d, 0x0a343160, 0x25240a29, 0x162a342d, 0x08020b16, - 0x17200a03, 0x64293f17, 0x7c1f0b69, 0x8202821f, 0x01613340, 0x104111e0, 0xd3114110, 0x144c1390, 0x2d134b13, 0x02822db6, 0x13491322, 0xfe290b82, - 0x279f0263, 0x5816279d, 0x82028216, 0x61fd2c08, 0x04000000, 0xab002900, 0x4703d706, 0x3a220553, 0x53474600, 0x1140471a, 0x14011d26, 0x32331617, - 0x20070443, 0x0adc4125, 0x01292108, 0x66655e20, 0x29adb35d, 0xad292e2e, 0x95840f03, 0x41694926, 0x223b3b57, 0x110f3d0f, 0x2c4e3b48, 0x4e350082, - 0x0e134c3c, 0x3c220f3a, 0x012d013d, 0x01bffeae, 0x01ddfe23, 0x10054741, 0x54a9b134, 0x272d5981, 0x22084b26, 0x35393008, 0x5d665d35, 0xc6423535, - 0x020b2a07, 0x60ba609e, 0x000060c4, 0x825f5103, 0x6d01082e, 0x930502ff, 0x44001a05, 0x6d005500, 0x9e299182, 0xd500ab00, 0x0000e300, 0x05584725, - 0x0622232c, 0x27012e07, 0x013e3736, 0x1b443637, 0x0e072205, 0x098f5202, 0x82070621, 0x22232a01, 0x3727022e, 0x17161716, 0x09d6481e, 0x44013521, - 0x37370664, 0x3233023e, 0x27061016, 0x3d023e32, 0x022e3401, 0x07010e22, 0x4f011d06, 0x258205a1, 0x34350225, 0x48353736, 0x322005f2, 0x634a4282, - 0x1e152405, 0x82141501, 0x0ce1476b, 0xee471320, 0x8325200b, 0x2307211e, 0x02829982, 0x27262223, 0x232d8206, 0x2e272223, 0x37204f82, 0x3320b083, - 0x07204c85, 0x7382c988, 0x02165508, 0x3a3c3e4b, 0x17433031, 0x0f0c300c, 0x21331413, 0x502f2b20, 0x0a0a213a, 0x1d1a2f24, 0x13131a19, 0x1f1f2216, - 0x2f362c2d, 0x0f2a3647, 0x0e0e0c50, 0x1c2e1112, 0x3f45413e, 0x3e980247, 0x0f0e3c5c, 0x5c3c0e0f, 0x76767d3e, 0x1e31237d, 0x311e0e0e, 0x071f3145, - 0xb3080082, 0xfd31100f, 0x3d593bf8, 0x343c4a1f, 0x53371e3e, 0x38292968, 0x343f0f0f, 0x10104a3d, 0x3c3a5a3c, 0x42794242, 0x3b373d42, 0x3a3a6f3b, - 0x16165203, 0x90295645, 0x21225b38, 0x05010d2d, 0x0e0e0a01, 0x2a203026, 0x1d352424, 0x1f1f1110, 0x2b383656, 0x10113c2c, 0x42413bec, 0x41413b3a, - 0x07293599, 0x262c312e, 0x160a2a0a, 0x0a1d1415, 0x412d1709, 0x191a2028, 0x04061928, 0x150d0d06, 0x2c253914, 0x0e191a48, 0x2c21140e, 0x11143e17, - 0x0d0c0c11, 0x3407343a, 0x6afe5c36, 0x4040582f, 0x40415253, 0xfeb72f59, 0x1c5cb6b8, 0x752c4933, 0x1c34482c, 0x2424341c, 0x2e080982, 0x1a1a2325, - 0x1d06031c, 0x432a4734, 0x13071151, 0x40263a4e, 0x0c0d192d, 0x2620202d, 0x07134e3a, 0x2a435111, 0x1d342423, 0x13323857, 0x82373732, 0x01382704, - 0x102e303a, 0x0484302e, 0x491f2a08, 0x556b4041, 0x284e291b, 0x01365a28, 0x12121401, 0x0f0e0f1b, 0x32304c36, 0x1e1d2b2a, 0x44131222, 0x3f933030, - 0x3e3c0e3c, 0x2104823e, 0x0082003f, 0x78000437, 0x8806b700, 0x0f005603, 0x37002700, 0x00004000, 0x30113001, 0x2a038423, 0x30213035, 0x30133015, - 0x8a333035, 0x201b830f, 0x22178233, 0x82273021, 0x0c815427, 0x07010e3c, 0x01012e33, 0x01c86cac, 0x5b5b53fc, 0x5c5c2401, 0xfb3c2b02, 0x99266f3a, - 0x03828826, 0xd7fe4308, 0x10411005, 0x024010c6, 0x02c2fdf5, 0xfd60603e, 0xee0158c2, 0x12fe5858, 0x70b5b558, 0x7070be01, 0x027042fe, 0x31c5313a, - 0x0000c531, 0x00080005, 0x03f806ab, 0x00340061, 0x0046003e, 0x00580050, 0x9f4b3700, 0x23272a32, 0x33132307, 0x01171216, 0x90a18623, 0xfd420811, - 0x0d2a7655, 0x2b230d31, 0x4140372b, 0x280a3a2e, 0x2262620a, 0x4c36563c, 0x0d273838, 0x4b1a0d32, 0x1f203a37, 0x653c3634, 0x5a3e215d, 0xfa3dd002, - 0x89e46e3b, 0xfe269826, 0x401104d7, 0x4010c510, 0x13912803, 0x824bac20, 0xb50b242c, 0x419e02b5, 0xfd210a00, 0x20108ef7, 0x34008200, 0x00600003, - 0x03a006ab, 0x00150061, 0x004b002b, 0x03302500, 0x0eaa4630, 0x07020624, 0xb1413521, 0x48052013, 0x012d1d87, 0x1270db3c, 0x2b0a1247, 0x2b0b040b, - 0x2509820b, 0x2595256d, 0xc7414b01, 0x84012605, 0x4a269683, 0x14614868, 0x9e02b728, 0x2737dd37, 0x0282279b, 0xc3830882, 0x2007d641, 0x1741480b, - 0x042acb82, 0xb7004700, 0x5603b906, 0xcd820b00, 0x29002122, 0x46183f46, 0x01280a1b, 0x23112311, 0x48152135, 0x28074c4d, 0x292e2e29, 0x011402ad, - 0x070246ad, 0x6c7b0125, 0x46fc01c8, 0xc1200f08, 0x2106ea45, 0x79423e02, 0x207f8205, 0x08934f06, 0x27001e34, 0x4e003d00, 0x7e005800, 0x22050000, - 0x34352627, 0x01843637, 0x0e333025, 0x4f060702, 0x17200594, 0x2408954f, 0x14011d22, 0x06944f01, 0x200a1256, 0x2d964f06, 0x4f010e21, 0x033f1297, - 0x37366b7a, 0x1d1d0f10, 0x8a312827, 0x123a553b, 0x110c0a12, 0x30513147, 0x6d6a6e2f, 0x4f09fed9, 0x04260692, 0x050c0513, 0x944f0512, 0x4d142212, - 0x17944f14, 0x0e3a0e22, 0x350e954f, 0x7f4242fd, 0x363d3d3c, 0x232f3038, 0x2b50522d, 0x312f332a, 0x904f3535, 0x691a2213, 0x4f02821a, 0x2e221192, - 0x924f2eb6, 0x20082215, 0x0d934f08, 0x0106003c, 0x0508ff17, 0x001505e9, 0x0017000b, 0x004b002d, 0x005f0055, 0x11300500, 0x03823330, 0x15302122, - 0x0b870784, 0x3305c650, 0x37363435, 0x1632013e, 0x14011e17, 0x010e0706, 0x37363227, 0x3d2b0182, 0x26273401, 0x23012e27, 0x82070622, 0x07bf4601, - 0x4f110521, 0xcc2412d1, 0x6311016c, 0x22080382, 0x6a4210fd, 0x29292626, 0x836a2626, 0x2a26256b, 0x6b25262a, 0x17402641, 0x0c0c0d16, 0x4017160d, - 0x873f2826, 0x013f220b, 0x0c8348f4, 0x9f02f825, 0x8460c1fd, 0x57032b04, 0x822b2c2d, 0x2b825455, 0x09832d2c, 0x0883a920, 0x191b612d, 0x2e252519, - 0x25252e69, 0x8c1b1919, 0x02562f0c, 0x6eb86e9f, 0x6a01f5fe, 0x282e282c, 0xf082002c, 0x000a0036, 0x03f606ab, 0x00120061, 0x003a0030, 0x004a0044, - 0x2e222500, 0x4f064050, 0xe6af0749, 0x1133112f, 0x2c011521, 0x294c6a42, 0x426a4c29, 0x9b078541, 0x665d21e0, 0x08086449, 0x6d130222, 0x2dac1001, - 0x54548257, 0x2d2d5882, 0x82a88258, 0x1b602d57, 0x2425191a, 0x242e6a2e, 0x1b1a1925, 0x55200c8c, 0x280e6d50, 0xfd9e02c1, 0x000060c2, 0x2ccb8204, - 0x03b606ab, 0x00130061, 0x002d0022, 0x06d34366, 0x30153023, 0x26038821, 0x30013011, 0x83173233, 0x070124e8, 0x52012b06, 0x272405ba, 0x11012b26, - 0x51064d58, 0x2724077e, 0x012e2726, 0x35220282, 0x80513734, 0x1506230d, 0x80511714, 0x07240806, 0x010e0706, 0xfea3014a, 0xfe1301ca, 0xedc301ed, - 0x4a343441, 0x344a2929, 0xeded4134, 0x2e2e5c4b, 0xdc02804b, 0x2705de45, 0x372b2a24, 0x17174140, 0x2405df45, 0x563d1111, 0x07e04535, 0x384a2b08, - 0x1a1a3f3a, 0x5d653c36, 0x201f1011, 0x9e02b759, 0xfe60ba60, 0x159e02dc, 0xa87d5415, 0x1515547d, 0x6c5b5e60, 0xfe2f2f5b, 0xd6456b22, 0x1717210a, - 0x21075a51, 0x5b512424, 0x2f290809, 0x15142a2c, 0x5c130c0b, 0x26272f51, 0x001d1c1b, 0x8f000400, 0x71066300, 0x1500a903, 0x39002f00, 0x00004300, - 0x30013025, 0x06ec5033, 0x2806535a, 0x01070206, 0x15163221, 0x0bd44914, 0x2322df84, 0xa2523721, 0x09064f08, 0xfea2012e, 0x59168ded, 0x0b360f16, - 0x0b380f05, 0x89370982, 0x012fb92f, 0x687301c2, 0x34291b77, 0x1f1e1919, 0x10241b1a, 0x4e1d1c11, 0x3c2106f5, 0x07f34e3c, 0x46036334, 0x45ecfe45, - 0x3729c536, 0x014525c8, 0xfd8c4514, 0xe44e8cd2, 0x142a3605, 0x0b010703, 0x4918170b, 0x2d2c3235, 0x75252120, 0x34293337, 0x09e34e37, 0xff320134, - 0x05ce0508, 0x00260014, 0x00780033, 0x009b008a, 0xc44e0500, 0x4a01202e, 0x2e3241d1, 0x11232701, 0x13331123, 0x3317011e, 0x23113311, 0x04823521, - 0x07020e26, 0x37362726, 0x30081082, 0x38700215, 0x10103d57, 0x5523222c, 0x2d39902a, 0x1721222d, 0x05010c17, 0x251c0a01, 0x472b1f31, 0x3d221e35, - 0x423a3557, 0x41417542, 0x3b3f4402, 0x08884a39, 0x4a341321, 0x0b220688, 0x884a230a, 0x233c0807, 0x2c2c1f1f, 0x37472f36, 0x0d4f0f29, 0x12110e0e, - 0x413e1d2d, 0xfd474045, 0x0e3408b2, 0xdb796803, 0x0308340e, 0x43017967, 0x341708bc, 0x4002123e, 0xa3a55655, 0x304425f8, 0x81493c30, 0x080d284f, - 0x1b241447, 0x4d361d0f, 0x3c53332f, 0x3d3e5922, 0x3f3f3c0d, 0x3e3d0d3c, 0x29353d01, 0x2b312e07, 0x0a2a0a26, 0x1e141416, 0x2d170909, 0x1a202840, - 0x0619271a, 0x0e0c0605, 0x25381514, 0x1a1a482c, 0x21150e0e, 0x153f172b, 0x06594a10, 0x36333508, 0x104a035c, 0x00fe1b63, 0x8dfe9e02, 0x0210631b, - 0x5a62fd01, 0x3818f501, 0x3a021343, 0xbcfd5d5c, 0x0003005a, 0x06ab001b, 0x006103e5, 0x005c0039, 0x2500007f, 0x430d4749, 0x26220568, 0x69432627, - 0x0aea5410, 0x07060726, 0x2221010e, 0x23051d47, 0x3233013e, 0x200fd051, 0x055b5636, 0x012722a2, 0x2a775410, 0x490c320d, 0x91430570, 0x31312c06, - 0x573c1111, 0x38374c36, 0x49330c27, 0x23080b73, 0x1f1f1011, 0x8429025a, 0x24131395, 0x57426825, 0x3d0f2276, 0x3a48120f, 0x4e58584e, 0x0f124c3c, - 0x79220f3a, 0x8b491e9e, 0x06b4430b, 0x512e2e23, 0x0bb5432c, 0x2d171723, 0x0611552a, 0x1b26272d, 0xa9b11d1c, 0x2c404154, 0x4e4d2e2c, 0x0051053b, - 0x9a52200a, 0x0000281a, 0x004f0005, 0x55b106ab, 0x0021092b, 0x342b5540, 0x35210122, 0x28080282, 0x02061521, 0x54012107, 0x2222603d, 0x22222323, - 0x44607960, 0x60442424, 0x4e4e483c, 0x014f4f90, 0x570901de, 0x57572c2b, 0x058957a3, 0xfe60032e, 0xfe420141, 0x36a601cd, 0x4c0136d6, 0x082bd954, - 0x5bbcfd2a, 0x5b59ea01, 0x52bafe52, 0x2e000700, 0xd20608ff, 0x1c001505, 0x47003300, 0x5d005300, 0x91007300, 0x06370000, 0x30153007, 0x3205034c, - 0x36333011, 0x30373637, 0x16070633, 0x2e231712, 0x45110101, 0xf1450ae5, 0x2726230c, 0x29493330, 0x82332006, 0x301122cf, 0x187d5701, 0x47012e21, - 0x36082df3, 0x6d1a42f7, 0x1848046d, 0x417f5a5a, 0x16ba32ae, 0x01922783, 0xfead01a5, 0xfe2301c0, 0x014001dd, 0x7c737422, 0x031b6d1b, 0x781b6c1b, - 0xfb2da418, 0x5e20014a, 0x505e6565, 0x1720075d, 0x08291448, 0x1e4b4123, 0xfe9f02d0, 0x6d1e5cac, 0x4bce4d6d, 0x3d21e8fe, 0x02e2fee1, 0x60bb609f, - 0x080160c4, 0xc732cbcc, 0x27028232, 0x4ee2fe29, 0x6203f6fe, 0x210df847, 0x3748b5fd, 0x0000212d, 0x358f8362, 0xffca0005, 0x05360608, 0x000f0015, - 0x00330017, 0x00920066, 0x054e0500, 0x07062a11, 0x05263330, 0x2327012e, 0x05494e30, 0x13303326, 0x3317011e, 0x2106e749, 0x63593023, 0x27262110, - 0x5a0a6259, 0x615905ad, 0x0226230d, 0x42823327, 0x53171621, 0x9c53078e, 0x36372706, 0x02063337, 0x6c822307, 0x2327262f, 0x010e0706, 0x3df80207, - 0x266e3afb, 0x07704e98, 0xc6313034, 0x0e190230, 0x68020834, 0x3408db79, 0x7967030e, 0x7c445bfc, 0x050e4805, 0x1e3a2e35, 0x2262621e, 0x4c36563d, - 0x03273837, 0x384a1a49, 0x4d201f3a, 0x5e0807eb, 0x6a1a9001, 0x2e0d6e1a, 0x03171809, 0x0b0a2408, 0x0e790f36, 0x23090a36, 0x23310309, 0x6e1c6b23, - 0x390d7a1b, 0x02191910, 0x3b101919, 0xb6b6f80d, 0x70bf0170, 0x7041fe70, 0x94943b02, 0x641b3494, 0x02fffd0f, 0x0f8dfe9f, 0x01021b64, 0x570361fd, - 0x2f0c343d, 0x16162b0b, 0x2e27313a, 0x5905060b, 0x1a350694, 0x4102321b, 0x17172822, 0x0a2a2a2c, 0x515c130d, 0x1e364d2f, 0x334b830b, 0x6f2ddb3b, - 0x29981e70, 0x3c3cdc2b, 0x94252bdc, 0xa2a1de25, 0x32235f83, 0x82663fea, 0xea3f3700, 0x01040032, 0x050eff18, 0x000f05e8, 0x003a001b, 0x00570043, - 0x7d412500, 0x3021221a, 0x05fc5423, 0x3e230724, 0x0a823701, 0x27089843, 0x1e07010e, 0x33110101, 0x2007c543, 0x06764111, 0x27823320, 0x0806b543, - 0x320ccd36, 0x7867030c, 0x0c310ddb, 0x03796803, 0x6d1b7f3f, 0x6b1b021b, 0x9124781b, 0x238b2324, 0x19661980, 0x1a671a02, 0x248c2478, 0xd9fb9325, - 0x0111016c, 0x269a2601, 0x08078043, 0x9a277723, 0x5f178127, 0x02fffd18, 0x188efe9e, 0x0002175f, 0xb22d62fd, 0x2db22c2c, 0x3639e539, 0xa72936db, - 0x3e028229, 0x3936da36, 0x022903e6, 0x60c2fd9e, 0x01440801, 0xc732430f, 0x32c73131, 0x43f2fe43, 0x8200f6fe, 0x01062200, 0x20f38236, 0x2ff382ca, - 0x001e0014, 0x0032002a, 0x00520046, 0x23300500, 0x22055744, 0x82061415, 0x5d1720cb, 0x27220f19, 0x30650723, 0x070b5008, 0x4f030221, 0x02220e3f, - 0x704e2103, 0x6da33a0b, 0x685a2101, 0x61184142, 0x5a167918, 0x2aac8516, 0xac292f2e, 0xfa3db603, 0x0a66423b, 0x10401034, 0xfd4010c5, 0x716e6e79, - 0x0b114811, 0x0b040a2b, 0x09820b2c, 0x6f706e24, 0x9c4e6801, 0xf2200809, 0x5d6c9e02, 0x2f145f48, 0xb52d2fbc, 0x292b5b2d, 0xd52b282e, 0xb6b696fe, - 0x6fbf0170, 0x7041fe6f, 0x2506fd50, 0x4f015901, 0x554f4f01, 0xb1fe240b, 0x5402b1fe, 0x003007ae, 0x00a90002, 0x03570663, 0x001d00a9, 0x25000033, - 0x2005d341, 0x058d5106, 0x210eb641, 0x0d500516, 0x08194905, 0x33304008, 0x03301530, 0x9027a076, 0x64640413, 0x35c21896, 0xa017bc33, 0x02207f20, - 0x96208120, 0x8a33be17, 0x0aeb2d01, 0x164f411c, 0x41955003, 0x4163ccce, 0xa7a720ed, 0x53330127, 0x2426014f, 0x8234d034, 0xfe243402, 0xd7d74fdb, - 0x1e720271, 0x02175446, 0xfd47a148, 0x1000712b, 0x8101e71e, 0x28010634, 0xd80502ff, 0x0f001a05, 0x43002500, 0x74005600, 0xd3537c00, 0x335b4f11, - 0xa14e0120, 0x07a6512b, 0x6d670228, 0x01fb01c7, 0x704f4173, 0x6b822107, 0x2205824f, 0x4f27416b, 0x27250979, 0x16164027, 0x2c00820d, 0xfd401616, - 0x4c6b41d0, 0x6b4c2929, 0x21078741, 0x1c874126, 0x28264134, 0x0c17163f, 0x170c0d0d, 0xed023f16, 0xfc01c86c, 0xcf514c01, 0xb7fd3605, 0x822c2b2d, - 0x2c815554, 0x2c2d2d2c, 0x82a9812c, 0x612d2b2c, 0x06c04e1a, 0x4e242521, 0x242105c0, 0x06cd4e25, 0x01031a24, 0x2e83572d, 0x2d2d5823, 0x202c8258, - 0x4f2b8a57, 0xf94e09c2, 0x011a2205, 0x083352e8, 0x33000736, 0xc206fdfe, 0x0c000905, 0x3c001600, 0x86006100, 0xa2009c00, 0x6119b95a, 0xf4510f8b, - 0x5a012014, 0x0b210683, 0x1a7f5a01, 0x112c24a5, 0x36321614, 0x11331135, 0x020e0714, 0x2005934d, 0x063e5b11, 0x57090124, 0x284a2b2c, 0xad022a08, - 0x21215e3a, 0x21212323, 0x05b2612f, 0x390c1d52, 0x200e390e, 0x01c30269, 0x080b0105, 0x8282081f, 0x0b081f07, 0x62010401, 0x8b5a1378, 0x20072905, - 0x12471208, 0xc0fb6277, 0x0c202282, 0x82261d82, 0x081e0882, 0x2283020c, 0x12491222, 0x08253382, 0x12072008, 0x33228248, 0x8e386401, 0x0c0c6538, - 0x577f5835, 0x020c0c36, 0xf8f46636, 0x080fc15a, 0x2b27b120, 0x83b6842a, 0x14132b2a, 0x084a2525, 0x32390820, 0x53a1535e, 0x093c365e, 0x4f4a0821, - 0x925aa801, 0xf0fe2305, 0x905a1001, 0xff042117, 0x320823a1, 0x4efe9f02, 0x514d4d51, 0x5efeb201, 0x41323244, 0x32411f1f, 0xa2014432, 0x9f0261fd, - 0x005abbfd, 0x01040000, 0x0502ff4d, 0x001a05b3, 0x00510017, 0x529d008b, 0xbb50059f, 0x09d54a09, 0x4d14aa50, 0xfe482341, 0x297a4d0e, 0xf14e0120, - 0x85012110, 0x38095a46, 0x76544b01, 0x0c320c2a, 0x362c2a24, 0x17174240, 0x0a280a3b, 0x10313161, 0x06d94811, 0x0c330c23, 0x0653621a, 0x5d653b29, - 0x1f201010, 0x848bfd5a, 0x230d2332, 0x32862b2b, 0x620a272e, 0x11113131, 0x4c36563c, 0x0d283738, 0x3c213289, 0x2b328264, 0x015b1f1f, 0x0d310ce2, - 0xdb796802, 0x03230682, 0x46f27967, 0x0b320692, 0x2e0c343d, 0x16162b0c, 0x18273139, 0x07020b17, 0x5e4d1202, 0x2822250d, 0x2b2c1717, 0x210b5e4d, - 0x33b16203, 0x487e0121, 0x002f0f3c, 0x00020000, 0x065400cf, 0x00b80331, 0x4e4a0034, 0x262010d9, 0x5c05666a, 0x5e4a0880, 0x07405209, 0x01020e22, - 0x080d3543, 0x022e2787, 0x02021135, 0x0f34946a, 0x352d0f3f, 0x52504436, 0x2525493a, 0x2a3d3d7b, 0x5e446b4c, 0x5b314646, 0x465d2104, 0x21282847, - 0x7e4b4420, 0x704e2974, 0xc552f901, 0x11108551, 0x3bae764b, 0x55214b3b, 0x3a0f404d, 0x1b1c360f, 0x3a313d48, 0x1706070e, 0x3865393a, 0x21213e59, - 0x03513e21, 0x1c1d322a, 0x1a1a3438, 0x7318100d, 0x44613a65, 0xfd540325, 0x6c6c6bfc, 0xfe04026b, 0x44435c11, 0x16152b57, 0x015c8658, 0x10db82ef, - 0x3d07732d, 0x08ff0a39, 0x1505f606, 0x18000e00, 0x49002b00, 0x5d005300, 0x00006300, 0x5c333001, 0x2b200950, 0x23067e5a, 0x11012b26, 0x5c2ce24c, - 0x113a146b, 0x15211133, 0x41ed7602, 0x29252568, 0x68252529, 0x4beded41, 0x804b5c5c, 0x985b49fe, 0xa7013c3a, 0x7e2a292b, 0x292a7ea7, 0x5b5f602b, - 0xfe5f5b6b, 0x2df70221, 0x54558257, 0x822d5782, 0x82a92007, 0x1b612906, 0x24251919, 0x242f692f, 0x8807bf4c, 0x0e825c0c, 0x02c0fd2e, 0x61c2fd9f, - 0x03000500, 0xfd06ab00, 0x200aa756, 0x34a75659, 0xbd4c0520, 0x56082024, 0xae6b11c0, 0x56a4200d, 0x962006c0, 0x2105744c, 0x744c8307, 0x67612007, - 0xd4560f00, 0x13a73a2b, 0x4b13134c, 0x01effe12, 0x124a1211, 0xfe134a13, 0x279e0263, 0x5916279c, 0x82028216, 0x62fd2208, 0x31008200, 0x00220003, - 0x03de06ab, 0x001b0061, 0x006c0033, 0x41531300, 0x15e7561c, 0x2114114c, 0x5259012e, 0x0fbc5c10, 0x4d53d720, 0x0cdb2805, 0x68030c32, 0x56400179, - 0x4c200abc, 0x212fb85c, 0x214b2a02, 0x0218240a, 0x4b62fd01, 0x0f6e09a1, 0x27b55c08, 0x00002508, 0xff7c0107, 0x05840502, 0x0037001a, 0x0068005b, - 0x009c0075, 0x00d500a9, 0x21300100, 0x3307010e, 0x023e3736, 0x2e078866, 0x23060701, 0x012e2722, 0x37272627, 0x821e1716, 0x05157917, 0x07062222, - 0x3e231482, 0x66213701, 0xbf663a5e, 0x0d246b07, 0x33011e22, 0x2117246b, 0x71823521, 0x24052960, 0x0e222326, 0x82838302, 0x3202233c, 0x01821716, - 0x8206c979, 0x213708c2, 0xd7fe2603, 0x06020c03, 0x200d0d0b, 0x4b2b1c2b, 0x10101f36, 0x392c2d3d, 0x3423232d, 0x4f101314, 0x230d0e0c, 0x413b1c2b, - 0x342b3b41, 0x0f3c0f12, 0x01041104, 0x6669017c, 0x3b37245d, 0x3717fe3b, 0x11103c58, 0x5523232c, 0x2e389029, 0x1622212d, 0x6b010c17, 0x1e21097d, - 0x067d6b22, 0x41415908, 0x39fe5003, 0x33248f23, 0x323a1b1b, 0x141f291c, 0x103f1006, 0x3812120b, 0x1b50664c, 0x190f0e1c, 0x201e1d2d, 0x011a691a, - 0x274e0152, 0x1014289e, 0x1c0c1710, 0x32314e36, 0x113d2a2a, 0x210a0a10, 0x3e181516, 0x19111014, 0x0b3a410d, 0x1421413a, 0x3e020902, 0x57fd3ef9, - 0x21374e66, 0xe66bd101, 0x27262d0b, 0x2d2e2828, 0x14010135, 0x1d101b23, 0x0812e66b, 0x7f20683f, 0x2a2a2e20, 0x38310c2e, 0x16271c11, 0x20061906, - 0x1b2e1d1d, 0x241b1a1e, 0x45282b25, 0x1c1c1c3e, 0x00175a17, 0x01060000, 0x0502ff7a, 0x001a0586, 0x00360028, 0x0092006c, 0x00ca009f, 0x0c406800, - 0x22263f68, 0x42062125, 0x3e241883, 0x031e3701, 0x6906345f, 0x13220738, 0xa75e2521, 0x196b6d14, 0x36352122, 0x42068861, 0x52201e45, 0x35054568, - 0x22225a39, 0x04030d2c, 0x260e0e0a, 0x242b1f30, 0x111e3424, 0x44681e11, 0x3d450805, 0x3bec1010, 0x3a3b4141, 0x34034242, 0x0c05d6fe, 0x0c0d0b07, - 0x2b1d2a21, 0x101f364a, 0x2c2d3e0f, 0x23222d39, 0x10141335, 0x0d0d340e, 0x1c2b221b, 0x3c40403c, 0x0e12342b, 0x12070f3c, 0x10fd7c01, 0x103c5838, - 0x2c238211, 0x38902955, 0x22212e2d, 0x030c1716, 0x07c76d03, 0x2205cd5e, 0x42754141, 0x6b250549, 0x1c1b336b, 0x0548423b, 0x42400f21, 0x1c2e0748, - 0x190f0e1b, 0x201d1e2c, 0x011a691b, 0x3068b352, 0x49f2222d, 0x147542a4, 0x0a2a0a24, 0x76422114, 0x0174230b, 0x3b42b901, 0x605f212d, 0x38243a42, - 0x39000600, 0xc70608ff, 0x0f001505, 0x28001c00, 0x57003200, 0x00007a00, 0x07d15805, 0x30133034, 0x17121633, 0x30272603, 0x30070623, 0x2e333007, - 0x536e0101, 0x0f995315, 0x53132575, 0x16251473, 0x17011e17, 0x05884433, 0x0423113c, 0x06240a1e, 0x0a2406e2, 0x2182c964, 0x0af12187, 0x0a0b0c0b, - 0x290bb13c, 0x306e9bfc, 0x0230080d, 0x215d3bad, 0x21242421, 0x3b2e2f21, 0x1f343355, 0x3f114a0d, 0x4c4c4434, 0x12433544, 0x1f0e380e, 0x01c4026a, - 0x090c0105, 0x82820421, 0x0c092203, 0x623e0c82, 0x09373678, 0x18080521, 0x15520517, 0x23f86277, 0x7f18187f, 0x709f0223, 0x017041fe, 0x008231e0, - 0x8c24d324, 0x4e53a501, 0x2907211d, 0x3f124d53, 0xfe095216, 0x081001f0, 0x4b141651, 0x0263fe12, 0x1975769f, 0x42420e5d, 0xfd2fb10b, 0x07000061, - 0x2c086741, 0x00200016, 0x0035002a, 0x0064003f, 0x08077f87, 0x15070623, 0x061c6c32, 0xa5710e20, 0x3d362305, 0xa3713401, 0x7301200c, 0x785613ff, - 0x1e9b7605, 0x08227541, 0x01980222, 0x37504e10, 0x18171d34, 0x16090a22, 0xfe223928, 0x25a766d5, 0xa7252626, 0x25252197, 0x3bfd9721, 0x3f507d41, - 0x5459a701, 0x0c054841, 0x1c280b0b, 0x472b211c, 0x275a1c33, 0x272c2c2b, 0x2b282457, 0x1d012329, 0x34518541, 0x01050000, 0x0502ff27, 0x001a05d9, - 0x0034002a, 0x0071003c, 0x7314827d, 0x3e240959, 0x16323302, 0x6a197176, 0x7b5410e7, 0x085e650e, 0x5d0d5d65, 0x0c5b0d7c, 0xf402210a, 0x261f8676, - 0xfb3c7302, 0x6be56f3a, 0x402607ed, 0x4010c611, 0xea76b6fd, 0x135d6b12, 0x215e6426, 0x2e015a3f, 0x2009d354, 0x0796768c, 0x762d5921, 0x652e0896, - 0x10100808, 0x5d341f2f, 0xb6b69bfe, 0x345b9e02, 0x544e200b, 0x2f220a51, 0xf376020b, 0x0982540e, 0x2f515c25, 0x6f1d374d, 0x003d09fd, 0xce010200, - 0x320516ff, 0x21000e04, 0x00003b00, 0x22233005, 0x30352627, 0x27012e35, 0x42088226, 0x322f05b0, 0x1e171617, 0x02141501, 0x27331507, 0x74013e32, - 0x2e220598, 0x436f2302, 0x1e280808, 0x8e700402, 0x55272855, 0x1b2f2f88, 0x39383e19, 0x50c45050, 0x3e383950, 0xf09aa0bb, 0x1244603a, 0x44121313, - 0x5f3b3a60, 0x5f310985, 0x492b2cea, 0x414d0b4c, 0x735c5b41, 0x4142c27f, 0x34008222, 0x7fc24241, 0x1cfcfee1, 0x4c28f267, 0x9e453737, 0x4c373745, - 0x290a8a28, 0x13000300, 0xed06b700, 0x07825603, 0x51003d22, 0x20056167, 0x0f5f6103, 0x2206944b, 0x58033003, 0x30230753, 0x6c113023, 0x11230f2b, - 0x82213023, 0x30352201, 0x08058401, 0x15302123, 0x21070206, 0x72cfe330, 0x0d175d17, 0x70175b17, 0x03228a22, 0x01050109, 0x081e080c, 0x1f088282, - 0x05974407, 0x12491236, 0x08082007, 0x12081f08, 0x62771248, 0x41fe9a02, 0xcefe4101, 0x32067662, 0x010301b7, 0x31c8329b, 0x4432c831, 0xfe45eefe, - 0x4b9d01fd, 0x7d622187, 0x00002809, 0x004c0004, 0x82b406ab, 0x001426e3, 0x0028001e, 0x5de5835f, 0xa6421ddb, 0x01112107, 0x2032994a, 0x06e45db9, - 0x5d601921, 0x2e2408e4, 0x1302ac2a, 0x27075668, 0xd7fe5803, 0x07030c03, 0x2123244a, 0x244a0e13, 0x5db72006, 0x28270eec, 0xd52b292e, 0x680296fe, - 0x402a065a, 0x14279e28, 0x0c171010, 0xc549351d, 0x1011210f, 0x200ec549, 0x30008200, 0xff730104, 0x058d0502, 0x004c001a, 0x00b4007d, 0x171772e0, - 0xe24a1720, 0x06072106, 0x15220184, 0xf24a011e, 0x220d8405, 0x57222306, 0x27210511, 0x72178237, 0x324b0c22, 0x2627210a, 0x4b06596b, 0x01230636, - 0x86323637, 0x23548555, 0x2107010e, 0x20336841, 0x49648a01, 0x02211d51, 0x11926750, 0x28286208, 0x11101d1d, 0x12120a0a, 0x1d1a1718, 0x0b131333, - 0x2011110b, 0x362c2c1f, 0x1b24232f, 0x0f15141c, 0x111c0d4f, 0x3d1d2d12, 0x47404542, 0x39fe8003, 0x33238f24, 0x1e1d1b1c, 0x0f2a1b32, 0x050a0b0f, - 0x0b0f4010, 0x26371311, 0x1b516626, 0x190e0e1c, 0x1e1d1616, 0x1b691a20, 0xa7fd5201, 0x0b03d6fe, 0x08934903, 0x0f1e3735, 0x2d2c3e10, 0x23222d39, - 0x0f141434, 0x0e0d0d4e, 0x491b2c22, 0x0f210692, 0x05074c3b, 0xfe500224, 0xb34b2438, 0x1e2a2107, 0x2008b34b, 0x205e854b, 0x08b34b18, 0x08103572, - 0x170b0c27, 0x291f2116, 0x14191a20, 0x060d0c14, 0x151a0604, 0x251c1d14, 0x1a24242c, 0x0a0e0e19, 0x1511110a, 0x143e1716, 0x093d7222, 0x614b7520, - 0x1c1c2609, 0x140e0e11, 0x07644b13, 0x4b0e0d21, 0x29230565, 0x4b1f1f44, 0x05210566, 0x2b224c46, 0xbb4b6220, 0x4f042028, 0x56280627, 0x2e000f00, - 0x8f033700, 0x6f135b5e, 0x0526243f, 0x33270226, 0x4618011d, 0x45182235, 0x38c9158a, 0x26a65fa6, 0x194a4618, 0x46181520, 0x0122153d, 0x45183d37, - 0x14941477, 0x11b34518, 0x38a61191, 0x5fcc26a6, 0x18333521, 0x28103f46, 0xb2663a01, 0x0601c901, 0x05f6706b, 0x70272821, 0x012312f6, 0x185f18eb, - 0x2d4f0346, 0x040e0301, 0x040e040c, 0x7c0e380e, 0x0782390e, 0x52044618, 0x19640128, 0x0f7a1862, 0x6b820f39, 0x0e040b3a, 0x0f3d0f03, 0xbbfdfc02, - 0x59594502, 0x4242b0fd, 0x3c3d3c7f, 0x302f3837, 0x21077a71, 0x7a713430, 0x104a200a, 0x5503da45, 0x0000002f, 0x00470005, 0x03b906ab, 0x001e0061, - 0x280b822f, 0x00700058, 0x010e0100, 0x0ad76c07, 0x2005c67a, 0x6c148233, 0x3e7b06d9, 0xa4052024, 0x10013925, 0x6c103d0f, 0x4010046c, 0x1e791e10, - 0x289f287e, 0x832bad2b, 0x63028822, 0x2718d27a, 0x0f070606, 0x52023110, 0x2208209e, 0x4612f001, 0x9e02cf12, 0x5115acfe, 0x24912514, 0x412fbc2f, - 0x3441fefe, 0x2ef0fed1, 0x53404059, 0x7a414052, 0x1b350679, 0x762b4934, 0x1b34482c, 0x2424341b, 0x252b762c, 0x1b1a1b23, 0x2224a35c, 0x4e060000, - 0x2f3a0893, 0x63004200, 0x98008d00, 0x0000a000, 0x30213005, 0x36373035, 0x30353637, 0xdb493435, 0x37362a0a, 0x1e32013e, 0x15161701, 0x05814a14, - 0x010e0725, 0x56052107, 0x3521052a, 0x211d8234, 0x937c3637, 0x4d3d8306, 0x26210555, 0x20018227, 0x752f8522, 0x162305dd, 0x18011617, 0x4e085142, - 0x122022f7, 0x240cf279, 0x39fe4503, 0x091153d6, 0x2c055a55, 0x664c1c1c, 0x0f0e3750, 0x17160c0d, 0x0613531d, 0x3f490126, 0x0e3c2e2e, 0x23080082, - 0x3f2e2e3c, 0x7c76767c, 0x10181922, 0x0606070f, 0x18100f07, 0x19184519, 0x0706100f, 0x0f100607, 0x89fe1819, 0x26200e4f, 0x3afb3d74, 0x4f72726e, - 0xf22c0c0f, 0x2a2ebf68, 0x310c2f29, 0x261d1138, 0x2a06c349, 0x1e1b1717, 0x2b252435, 0x49222328, 0x672207c3, 0x2e7c1817, 0x18173307, 0xb6b8feb7, - 0x1a0e0e5c, 0x2d24231a, 0x24242c75, 0xa1821a1a, 0x1b1a0e29, 0x752c2423, 0x8323242d, 0x7703210e, 0x231f2d4f, 0x4f014f01, 0x080a2f4f, 0x00000020, - 0xfe0b0106, 0x05f50568, 0x001f000f, 0x00410039, 0x0055004b, 0x0100006f, 0x26222330, 0xfd4e013d, 0x4e062014, 0xf6671afd, 0x77012007, 0x05201287, - 0x0d654118, 0x23112e08, 0x33133311, 0x11333736, 0x5fe50223, 0x5b383539, 0x1211201f, 0x3625262a, 0x35368235, 0x7c292626, 0x27a1676b, 0x0c0d2d40, - 0x402d0d0c, 0x2d098227, 0x0c0d0d0c, 0xed02402d, 0xfb01c76d, 0xff793bfb, 0x15042b0c, 0x09230905, 0x18186219, 0x08821962, 0x80670539, 0x595a06b4, - 0x68fe677b, 0x0732313a, 0x3d2b2b34, 0x81554c3e, 0x82172b2c, 0x2c2b3d00, 0xad965581, 0x1aa24513, 0x2d252533, 0x24252e6a, 0x331b1b33, 0x6a2e2524, - 0x3325252d, 0x2108ec67, 0xe2762401, 0x2e292d09, 0x123e2b28, 0xb32c1249, 0x2cb32d2d, 0xfd390882, 0xfe9e02ff, 0xfdaaabab, 0x00000062, 0x00850002, - 0x037b0654, 0x003400b8, 0x357f644d, 0x08131a41, 0x1133133d, 0x69b70123, 0x3e103594, 0x35362c10, 0x39515144, 0x7a252649, 0x4c2a3e3d, 0x465f436c, - 0x035b3145, 0x48465d21, 0x21202728, 0x757e4a44, 0x03714e29, 0x2c0b06fa, 0x2381130b, 0x82138124, 0x82062708, 0xe007e1a1, 0x8c64829a, 0x8f022a2d, - 0x22175a17, 0xec4040ec, 0x38088222, 0x46037ffd, 0xaa0156fe, 0x0000bafc, 0x00b50003, 0x034b0663, 0x000b00a9, 0x19ad7b15, 0x76010921, 0xb63c11d5, - 0x7f746801, 0xd8e1747f, 0x34393934, 0xfe5a03d8, 0x58178ced, 0x0f370a17, 0x0a380f05, 0x88340982, 0x632eba2e, 0xe6894603, 0x01b2fe89, 0x3a3236c5, - 0x31fd3632, 0x2205a176, 0x7637c825, 0x00200aa1, 0x1b500082, 0x45612007, 0x7e2006bf, 0x4e46bd45, 0x210834ce, 0x0f3d1015, 0x10036d6d, 0x781f1040, - 0xa0287f1e, 0x2bac2b27, 0x02872283, 0x3b5c3f63, 0x0f0e0e0f, 0x43445c3b, 0x1f312805, 0x311f0d0d, 0x441f3145, 0x3122053b, 0x50501a03, 0x3edf4532, - 0x50ef0121, 0x053a2c71, 0x02ff5b01, 0x1a05a505, 0x3e003400, 0x81004800, 0x0000a200, 0x27262205, 0x9f793736, 0x103f5407, 0x2e070225, 0x54222301, - 0x4b180f3f, 0x45891465, 0x76290169, 0xb1570d59, 0x17162a0e, 0x5002010e, 0x252a7655, 0x14c77f26, 0x1e1a0b23, 0x0dc87f09, 0x442d0121, 0xb3350545, - 0x2e2e2aac, 0x2cfeac2a, 0x262b7654, 0x2b2a2425, 0x18424037, 0x11406916, 0x69190d21, 0x74760e40, 0x25210805, 0x58416924, 0x2e2d2275, 0x4e3b4811, - 0x3d4e5858, 0x4d0a134b, 0x3dfd7922, 0x2b232334, 0x31391616, 0x0e8c5427, 0x1b160a23, 0x128d5408, 0x07bf4b18, 0x282e2925, 0x8918012b, 0x2650693d, - 0xa9b12a08, 0x2d404055, 0x4b4d2d2c, 0x39301919, 0x5d665d6a, 0x06313e69, 0x0052492f, 0x00040000, 0x06b7002e, 0x005603d2, 0x0027000f, 0xe7411836, - 0x15d55e15, 0x2d611320, 0x6c622518, 0x70fc01c8, 0x2b09ad55, 0x6940ed83, 0x28282525, 0x40692525, 0x2005f660, 0xe8411881, 0x70022009, 0x022705bb, - 0x2a2a2a9e, 0x827da87d, 0x5e602705, 0x5e5b6c5b, 0x9e8222fe, 0x0106002d, 0x0502ff4b, 0x001a05b5, 0x821e0015, 0x004930ab, 0x00d8016e, 0x35300500, - 0x35302130, 0x74371236, 0x152e053d, 0x15302330, 0x33302530, 0x23301130, 0x145e010e, 0x183e2007, 0x2008d344, 0x073d4801, 0x22012e23, 0x07197e06, - 0x01021e24, 0x006a2622, 0x06816d08, 0x1d060722, 0x0e814618, 0x1133352b, 0x15010f23, 0x0f150e0f, 0x8205840d, 0x270b9108, 0x27012e05, 0x0b3f3537, - 0x0a200284, 0x0b880584, 0x17930620, 0x1133073c, 0xa1021533, 0xb52dc9fe, 0x5c5c8e2d, 0x07dbbffe, 0xaf028e23, 0x0e3c5c3e, 0x44181d0f, 0x072009bd, - 0x0f260082, 0x3145310f, 0x09820f10, 0x311f0739, 0x9683eefd, 0x41684927, 0x213b3b58, 0x11103c0f, 0x2c4d3b48, 0x182c2d2d, 0x220ad849, 0x1808bc2f, - 0xeb2e3b4c, 0x2c0b222e, 0x206ed20b, 0x2453d202, 0xa3a60101, 0xa54a18f2, 0xe2fe290e, 0x4140582f, 0x58835152, 0x07aa4518, 0x2c25243b, 0x24252b75, - 0x1c1c1a1a, 0x25241a1a, 0x252c752b, 0x031c3324, 0x55a9b106, 0x61481880, 0x3e342c0f, 0x09230931, 0x0b292949, 0xd4f5015a, 0x2254d0b1, 0xd00a280a, - 0x41508953, 0x5f8655b6, 0x5abcfd23, 0x38008200, 0x025c0001, 0x02a4065f, 0x000300a5, 0x15211300, 0x48065c21, 0xa502b8f9, 0x271b8546, 0xa40625ff, - 0x1400d605, 0x3c081b82, 0x3e012c32, 0x34113505, 0x022c032e, 0x019d5c23, 0xf6050134, 0x5b7fadc7, 0xaa6f3c2e, 0xfef8fecc, 0xada9fee5, 0x5633a502, - 0x7a837e72, 0xf90e4766, 0x7d5b154f, 0x68869190, 0x0001003e, 0x2447895b, 0x012c2201, 0x2047832e, 0x2747823e, 0x9da40633, 0xfbfeccfe, 0x01254889, - 0x011b0108, 0x82489657, 0x00053293, 0x0638ff2a, 0x009405d6, 0x00400004, 0x014b0044, 0x2b9b8208, 0x21072130, 0x030e2204, 0x07040e07, 0x2e06ab57, - 0x33363435, 0x041e1732, 0x37033e32, 0x8337043e, 0x1716240c, 0x83141516, 0x032e221e, 0x33e98203, 0x05231501, 0x25352325, 0x33023e34, 0x36171632, + 0x0000bc57, 0x00000000, 0xcc6d0000, 0x00000400, 0x00010037, 0x000e0000, 0x00030080, 0x54464660, 0x4458a24d, 0x6d000089, 0x281582b0, 0x4544471c, + 0x00150046, 0x200f8214, 0x2b0f8394, 0x322f534f, 0x7552fa8c, 0x68010000, 0x562c0f82, 0x70616d63, 0x8dc99dcd, 0x60020000, 0xe02c1382, 0x20747663, + 0x6f043b00, 0x40040000, 0x04261f82, 0x70736167, 0x5982ffff, 0x8c6d0022, 0x08280f82, 0x66796c67, 0x3fd5de2d, 0xdc2c1f82, 0xd8630000, 0x64616568, + 0xad24a224, 0xec201b82, 0x36210382, 0x23108268, 0x05068209, 0x24204b82, 0x24280f82, 0x78746d68, 0x1c12b128, 0xc0200f82, 0x9e280f82, 0x61636f6c, + 0x50b6999c, 0x44203f82, 0x98270f82, 0x7078616d, 0x82039500, 0x4801213b, 0x202c0f82, 0x656d616e, 0x1fd1e37f, 0xb4680000, 0xe62c3382, 0x74736f70, + 0x39fe916a, 0x9c6a0000, 0xf020a382, 0x012deb84, 0xff390000, 0x0f5f2c8b, 0x0b00f53c, 0x25368207, 0xfde00000, 0x08839fff, 0xdc04e12b, 0xfe80fcc9, + 0x05000768, 0x220f82e0, 0x82020008, 0x82028305, 0x00062233, 0x290982ff, 0x80fc0007, 0x00070000, 0x0c820100, 0x0420028b, 0x4b251184, 0x0800bb03, + 0x21008300, 0x23830002, 0x40222583, 0x0b822e00, 0x072b0d82, 0x00900100, 0x04000005, 0x82e6048c, 0x85fa2011, 0x5c032b07, 0xcf015900, 0x00020000, + 0x15820905, 0x01210285, 0x84078510, 0x75462905, 0x40005472, 0x41e12000, 0x06208385, 0x04856a84, 0x3b208b84, 0x07202683, 0x03830482, 0x0280fc25, + 0x82910009, 0x0052220c, 0x2c798220, 0x003500a5, 0x0029004b, 0x006d0191, 0x349b8278, 0x00470060, 0x00170152, 0x004a000a, 0x0032018f, 0x004f001b, + 0x2631822e, 0x011801ca, 0x82a90036, 0x0028251b, 0x004d0133, 0x23829182, 0x22000338, 0x7a017c01, 0x39003900, 0xce012701, 0x4c001300, 0x22007301, + 0x0d824700, 0x85000b24, 0x0f82b500, 0x2e005b26, 0x5c004b01, 0x2a200184, 0x53200582, 0x4b260382, 0x53005e00, 0x0982c800, 0x00218882, 0x83048203, + 0x861c2003, 0x00da22b3, 0x24098403, 0x0004001c, 0x2e1b82be, 0x00080008, 0x00000002, 0xe1f4e020, 0x84ffff41, 0xe1f02609, 0xffffff00, 0x200b82e3, + 0x222b8400, 0x820e0006, 0x0004260b, 0x00060005, 0x202f8207, 0x249d8209, 0x000c000b, 0x2617820d, 0x0010000f, 0x82120011, 0x00142c9d, 0x00160015, + 0x00180017, 0x821a0019, 0x1c3808db, 0x1e001d00, 0x20001f00, 0x22002100, 0x24002300, 0x26002500, 0x28002700, 0x2a002900, 0x2c002b00, 0x2e002d00, + 0x30002f00, 0x32003100, 0x34003300, 0x36003500, 0x38003700, 0x2008f182, 0x003b003a, 0x003d003c, 0x003f003e, 0x00410040, 0x00430042, 0x00450044, + 0x00470046, 0x00490048, 0x2098824a, 0x829c8506, 0x01002299, 0x21058202, 0x008d0002, 0x84000121, 0x40148dfc, 0x3b22ce0d, 0xd1826f04, 0x85002c21, + 0x3caf0801, 0xc6008400, 0x24056404, 0xd406c405, 0xea075807, 0x3409ce08, 0xb00a7609, 0x880bfe0a, 0x2e0cee0b, 0x6a0de60c, 0x640ed80d, 0xa40fca0e, + 0xbc105a10, 0xc6117e11, 0x0c139212, 0xd8138c13, 0x48159814, 0x12173816, 0x1e1b8017, 0x341cae1b, 0xea1dc01c, 0xbc1f081f, 0x34218020, 0xfc218a21, + 0xc8238622, 0xca272a27, 0x5229b028, 0x0a2ac629, 0xa42bbe2a, 0x162ef42b, 0x682e442e, 0xf02f8e2e, 0x6a300c30, 0x1e31d230, 0xac315631, 0xec31de31, + 0x3b000200, 0x15020000, 0x0300aa04, 0x2e000700, 0x2f0001b1, 0x0407b23c, 0xb132ed00, 0x3cdc0506, 0x820203b2, 0xb100220a, 0x20168303, 0x27168305, + 0x010607b2, 0x01b23cfc, 0x33371783, 0x25112111, 0x3b211121, 0x61feda01, 0x9cfe6401, 0x56fbaa04, 0x8234043b, 0xfc0226ed, 0x03f5ff80, 0x20098280, + 0x2e598201, 0x25210500, 0x0533fd21, 0x07b3f99a, 0x820b0b00, 0x03250815, 0x0f000902, 0xfd03f704, 0x25001b00, 0x00002f00, 0x32213001, 0x0e141516, + 0x07060701, 0x16171615, 0x15011e17, 0x2f0b8214, 0x2123010e, 0x36322137, 0x2634013d, 0x33352123, 0x4d080985, 0x0a02012b, 0x8e7dbd01, 0x2020311f, + 0x25251e1e, 0x132b1f20, 0x5f232214, 0xa217fe38, 0x483f1801, 0xe8fe3f48, 0x42423dfc, 0xfd03fc3d, 0x4f38778d, 0x030c0d32, 0x0d0d0208, 0x3f581c1c, + 0x2735363c, 0x428b2c27, 0x423e313e, 0x2e393e88, 0x8f833e3a, 0x91003008, 0x6f066300, 0x0f00a903, 0x2b001700, 0x30250000, 0x30213027, 0x36233007, + 0x16333712, 0x30011712, 0x30070623, 0x30012633, 0x30270011, 0x85133033, 0x02062f03, 0x02301107, 0xc7fe4cea, 0xbf2f8a49, 0x0382ab2f, 0x8dfe3408, + 0xf73d3c06, 0xfe84023c, 0xcc9b17f7, 0x3794cb04, 0xe3631dce, 0x2e028ce3, 0xd2fd8c8c, 0xb9c9028c, 0xf0fdb9b9, 0xd4014a01, 0x018bfe28, 0x9afe6175, + 0x82b3fe32, 0x03002182, 0xab3a0482, 0x61030007, 0x8c035803, 0x0000ba03, 0x27022637, 0x021d3033, 0x17041d17, 0x0290031d, 0x11a31491, 0x26f14782, + 0x86957191, 0x17011e26, 0x37013e33, 0x86067341, 0x033d220d, 0x20028937, 0x850b8a04, 0x8211a317, 0x9126f129, 0x2e86a171, 0x07020633, 0x27022623, + 0x2327012e, 0x8207010e, 0x22052d0d, 0x013e2726, 0x33011e37, 0x26343532, 0x26291883, 0x34352627, 0x16323336, 0x2b218217, 0x2223012e, 0x17141506, + 0x011e1716, 0x15230285, 0x82250614, 0x2223223b, 0x26288227, 0x37342627, 0x823e3736, 0x2021823c, 0x352c8407, 0x1614011d, 0x3e373233, 0x23013d02, + 0x23113335, 0x185e188e, 0x00cc0168, 0x040e0434, 0x030e040c, 0x7b0e390e, 0x030e390f, 0x030d030f, 0x61cc040e, 0x18640127, 0x0e7a1962, 0x205c833a, + 0x3b5c820c, 0x020f3c0f, 0x276e4bf0, 0x1d0c2f0b, 0x2a77314d, 0x0a240934, 0x702a2b5a, 0x24634865, 0x3c081382, 0x3731401a, 0x31161637, 0x30092409, + 0x13161544, 0x0c430274, 0x34484f09, 0x20212b2c, 0x12121213, 0x3d5f2222, 0x1e38375a, 0x3c461153, 0x48505048, 0x271a1a1e, 0x5adf7c16, 0xbe0170b7, + 0x10b8cd70, 0x47014d00, 0x19681a2d, 0x44196719, 0x44441001, 0x8244f0fe, 0x6819220a, 0x5b01101a, 0x47414701, 0x70af084d, 0x457042fe, 0x1a451301, + 0x67191967, 0xedfe451a, 0x36380b45, 0x290b2a0b, 0x2f2c6d2c, 0x0207020d, 0x512d2c15, 0x3431615c, 0x250b290a, 0x2a342d24, 0x020c1516, 0x1f0b0208, + 0x293f1717, 0x306e6865, 0x2a13133e, 0xb8424229, 0x2a2a4242, 0x47262728, 0x5c393131, 0x5c52a452, 0x31210908, 0xfe573b1e, 0x0700009e, 0x02ff5200, + 0x1a05ae06, 0x24001a00, 0x49003800, 0x78005300, 0x00008000, 0x35262205, 0x023e3734, 0x07063337, 0x010e0706, 0x013e3307, 0x15163233, 0x32270614, + 0x2334013d, 0x14011d22, 0x27022603, 0x17121633, 0x36331716, 0x82123637, 0x0702272a, 0x21112321, 0x27831732, 0x23130727, 0x2327012e, 0x07794837, + 0x22011527, 0x012e2726, 0x222a8234, 0x82333637, 0x06172123, 0x080b5845, 0x1e373698, 0x010e1701, 0x15011105, 0x35011101, 0x6d6ba201, 0x4f3a0f10, + 0x2a3b8a31, 0x251d1e2a, 0x47110c09, 0x6e5f5131, 0x6c6d6d6a, 0x2183211f, 0x1450136b, 0x0e0c0e0e, 0x144e140e, 0x20832169, 0x01658f01, 0x2b2c5609, + 0x71803a39, 0x78175608, 0x2626249b, 0xad029b24, 0x21225d3a, 0x22212323, 0x563b2e2e, 0x0d1f3333, 0x353e1249, 0x444c4c44, 0x0f124236, 0x69200e38, + 0x2801e4fe, 0xd8fe72fe, 0x3c7f84fd, 0x606f3c3d, 0x28292d22, 0x32562829, 0x676a312f, 0x7755776a, 0x02827719, 0x18035608, 0x6fbf0170, 0x46e7fe46, + 0x4e4f4f4e, 0x46190146, 0x7041fe6f, 0x34339e02, 0x11604d60, 0xc913e7fe, 0x2a265536, 0xde262a3e, 0x2a278efe, 0x84b6842a, 0x14142a2a, 0x074a2525, + 0x5f323929, 0x5e53a152, 0x21083b36, 0xb24e4a09, 0x100134fe, 0x0192fe82, 0x82effecd, 0x3f008200, 0x00200004, 0x03e006ab, 0x000b0061, 0x004a0015, + 0x37000074, 0x21301130, 0x06141632, 0x0119012b, 0x2008b749, 0x05ce4601, 0x16171622, 0xd0461282, 0x012e2806, 0x023e3435, 0x46173233, 0x072c08d1, + 0x16141506, 0x011e011f, 0x020e1415, 0x2105cd46, 0x2485022e, 0x46171621, 0x36230cc6, 0x46013e37, 0xd10806c8, 0x5d200121, 0xb45d6666, 0x2f2e2aad, + 0xdd02ad29, 0x0c2a7655, 0x2b230d32, 0x4141362b, 0x270a3b2e, 0x2162620a, 0x4c36563d, 0x0d283738, 0x4b1a0d32, 0x20203938, 0x643c3734, 0x5a3f205d, + 0x0a04dd02, 0x663c4c5e, 0x4d2a294a, 0x7d5a426c, 0x51135923, 0x6161503d, 0x1d1c2050, 0x8a191616, 0x02b75ff3, 0x6db96d9e, 0x6a01f5fe, 0x292e282b, + 0x3db6fd2b, 0x0c2f0b34, 0x3a17162b, 0x0c2e2731, 0x12020702, 0x482c515c, 0x1a1b1b31, 0x0b2d0b32, 0x18172921, 0x0b292a2c, 0x505d130c, 0x1d374d2f, + 0x2d403171, 0x54548257, 0x502e5881, 0x3b2f3447, 0x5d6e5d66, 0x10080966, 0x34202f0f, 0x009bfe5d, 0x002e0005, 0x03d206ab, 0x00120061, 0x002a001f, + 0x00460134, 0x68422500, 0x013e2807, 0x14021e32, 0x4227020e, 0x222a0583, 0x14011d06, 0x21110516, 0x5e411732, 0x2e052c0f, 0x1d232701, 0x0f1d1707, + 0x870e1d17, 0x820b8502, 0x11013305, 0x16331123, 0x011e1712, 0x053d3317, 0x270f3d27, 0x02870e3d, 0x042d0b88, 0x23113311, 0x33010226, 0x2223603c, + 0x3a028223, 0x44607a5f, 0x61442323, 0x4f4f483c, 0x014f4f90, 0x560901df, 0x56572b2c, 0x82259aa3, 0x029a2600, 0x09220863, 0x0732440c, 0x21756228, + 0x23082285, 0x10880d08, 0x85217623, 0x074c42ac, 0x5428282d, 0x5484b684, 0x525d5a27, 0x845d52a2, 0x024f3304, 0xc134339e, 0x01f1fe67, 0x3d2a2569, + 0x15b22629, 0x7f441553, 0x284dae4d, 0x0270fe02, 0xf4fe439e, 0x80884043, 0xfd900126, 0x0c014362, 0x3a055f43, 0x065400a5, 0x00b8035b, 0x0048002f, + 0x005e0054, 0x23302500, 0x2223010e, 0x4435022e, 0x3e43078a, 0x49062008, 0x362106e3, 0x35018237, 0x3523013d, 0x01231121, 0x15163221, 0x0e070614, + 0x1e150701, 0x0b821702, 0x020e0730, 0x33372123, 0x3d363732, 0x26273401, 0x5d4d012b, 0xe541080a, 0x60740e04, 0x345c804a, 0x43303035, 0x9c715343, + 0x124a122b, 0x634d6518, 0x28637979, 0x1b1b2424, 0x01ac1010, 0x0601772f, 0x77697201, 0x3415141b, 0x353d1a1a, 0x10111311, 0xfe2f4f39, 0x35e98768, + 0x0800821e, 0xd2e9356a, 0x33373733, 0x503de2d2, 0x6aa26d38, 0x3738a268, 0x59631c1c, 0x3b0b2b0b, 0x88757f49, 0x0b0a7f75, 0x1e1d1413, 0xfe754127, + 0x76460341, 0x15422f62, 0x07031415, 0x242f1601, 0x2c323525, 0x7525412d, 0x29331c1b, 0x711c1b34, 0x30273033, 0x00000033, 0x00350005, 0x03cb06ab, + 0x001f0061, 0x00530046, 0x00660060, 0x26222500, 0x2c131b44, 0x011e3736, 0x06070617, 0x012e2221, 0x23218227, 0x013e3736, 0x82050646, 0x32072a14, + 0x033e1716, 0x021e3233, 0x10584315, 0x2135a808, 0x37123635, 0x15331133, 0x33251523, 0x010e2311, 0x96834e01, 0x41694926, 0x5b217658, 0x4d3b4811, + 0x3d4d5959, 0x3a0f124c, 0x3c3d210e, 0x5738fc01, 0x2c10113c, 0x29552323, 0x2d2d3990, 0x16172221, 0x0104020d, 0x30251c0b, 0x35482a20, 0x573e211d, + 0x41413b35, 0x02424275, 0x2dc9fea1, 0x5b8e2eb5, 0xdbbefe5b, 0xac8e2307, 0x8154a9b1, 0x4b4d2e58, 0x6a393032, 0x6a5d665d, 0x2309313f, 0x29294909, + 0x30304424, 0x3680493d, 0x291c5336, 0x29282627, 0x01362d2d, 0x1b231501, 0x4d371c0f, 0x3c53332f, 0x3d3e5821, 0x843e3d0d, 0x4d2f0804, 0x014a5d83, + 0x3afe4a2a, 0x01d88355, 0x00ed3b63, 0xff4b0008, 0x05b50608, 0x000c0015, 0x001c0016, 0x005c0028, 0x00720068, 0x1700009b, 0x44301130, 0x01211235, + 0x23ec8311, 0x15211133, 0xa6450187, 0x2d754c06, 0x2406b44c, 0x13331323, 0x2a0b8503, 0x2533010f, 0x2337013e, 0x8207010e, 0x82138202, 0x1e232702, + 0x23111701, 0xaf4c3311, 0x82332005, 0x2902821e, 0xb0231133, 0x2c560901, 0x5644582c, 0xca013007, 0x0186f466, 0x01e1fe85, 0x01fdfe03, 0x4be7fa1f, + 0x25210cdd, 0x07dd4b09, 0x0c2e0c22, 0x0811dd4b, 0x22093830, 0x2309e109, 0x81c96408, 0x0e04f1ca, 0x0e030d03, 0x02b03b04, 0x010402d0, 0x071f080b, + 0x15165716, 0x1f081557, 0x05010b08, 0x12786201, 0x0b821248, 0x03820920, 0x47125408, 0xf8627712, 0x33349f02, 0xf1fe67c2, 0x29266901, 0xfd25293e, + 0xfd9f02bc, 0x9f025abb, 0xcf58c45a, 0x3957035a, 0x0b2b0b35, 0x2c6e2c2a, 0x08020c2f, 0x2c2d1402, 0x31605d51, 0x0a290a34, 0x342d2524, 0x0b16162a, + 0x0a030802, 0x3f171720, 0x0b696429, 0x821f7c1f, 0x33408202, 0x11e00161, 0x41101041, 0x1390d311, 0x4b13144c, 0x2db62d13, 0x13220282, 0x0b821349, + 0x0263fe29, 0x279d279f, 0x82165816, 0x2c088202, 0x000061fd, 0x29000400, 0xd706ab00, 0x05534703, 0x46003a22, 0x471a5347, 0x1d261140, 0x16171401, + 0x04433233, 0x41252007, 0x21080adc, 0x5e200129, 0xb35d6665, 0x2e2e29ad, 0x0f03ad29, 0x49269584, 0x3b574169, 0x3d0f223b, 0x3b48110f, 0x00822c4e, + 0x4c3c4e35, 0x0f3a0e13, 0x013d3c22, 0xfeae012d, 0xfe2301bf, 0x474101dd, 0xb1341005, 0x598154a9, 0x4b26272d, 0x30082208, 0x5d353539, 0x35355d66, + 0x2a07c642, 0x609e020b, 0x60c460ba, 0x51030000, 0x082e825f, 0x02ff6d01, 0x1a059305, 0x55004400, 0x91826d00, 0xab009e29, 0xe300d500, 0x47250000, + 0x232c0558, 0x2e070622, 0x37362701, 0x3637013e, 0x22051b44, 0x52020e07, 0x0621098f, 0x2a018207, 0x022e2223, 0x17163727, 0x481e1716, 0x352109d6, + 0x06644401, 0x023e3737, 0x10163233, 0x3e322706, 0x34013d02, 0x0e22022e, 0x1d060701, 0x05a14f01, 0x02252582, 0x37363435, 0x05f24835, 0x42823220, + 0x2405634a, 0x15011e15, 0x476b8214, 0x13200ce1, 0x200bee47, 0x211e8325, 0x99822307, 0x22230282, 0x82062726, 0x2223232d, 0x4f822e27, 0xb0833720, + 0x4c853320, 0xc9880720, 0x55087382, 0x3e4b0216, 0x30313a3c, 0x300c1743, 0x14130f0c, 0x2b202133, 0x213a502f, 0x2f240a0a, 0x1a191d1a, 0x22161313, + 0x2c2d1f1f, 0x36472f36, 0x0c500f2a, 0x11120e0e, 0x413e1c2e, 0x02473f45, 0x3c5c3e98, 0x0e0f0f0e, 0x7d3e5c3c, 0x237d7676, 0x0e0e1e31, 0x3145311e, + 0x0082071f, 0x100fb308, 0x3bf8fd31, 0x4a1f3d59, 0x1e3e343c, 0x29685337, 0x0f0f3829, 0x4a3d343f, 0x5a3c1010, 0x42423c3a, 0x3d424279, 0x6f3b3b37, + 0x52033a3a, 0x56451616, 0x5b389029, 0x0d2d2122, 0x0a010501, 0x30260e0e, 0x24242a20, 0x11101d35, 0x36561f1f, 0x3c2c2b38, 0x3bec1011, 0x3b3a4241, + 0x35994141, 0x312e0729, 0x2a0a262c, 0x1415160a, 0x17090a1d, 0x2028412d, 0x1928191a, 0x0d060406, 0x3914150d, 0x1a482c25, 0x140e0e19, 0x3e172c21, + 0x0c111114, 0x343a0d0c, 0x5c363407, 0x582f6afe, 0x52534040, 0x2f594041, 0xb6b8feb7, 0x49331c5c, 0x482c752c, 0x341c1c34, 0x09822424, 0x23252e08, + 0x031c1a1a, 0x47341d06, 0x1151432a, 0x3a4e1307, 0x192d4026, 0x202d0c0d, 0x4e3a2620, 0x51110713, 0x24232a43, 0x38571d34, 0x37321332, 0x27048237, + 0x303a0138, 0x302e102e, 0x2a080484, 0x4041491f, 0x291b556b, 0x5a28284e, 0x14010136, 0x0f1b1212, 0x4c360f0e, 0x2b2a3230, 0x12221e1d, 0x30304413, + 0x0e3c3f93, 0x823e3e3c, 0x003f2104, 0x04370082, 0xb7007800, 0x56038806, 0x27000f00, 0x40003700, 0x30010000, 0x84233011, 0x30352a03, 0x30153021, + 0x30353013, 0x830f8a33, 0x8233201b, 0x30212217, 0x54278227, 0x0e3c0c81, 0x2e330701, 0x6cac0101, 0x53fc01c8, 0x24015b5b, 0x2b025c5c, 0x6f3afb3c, + 0x88269926, 0x43080382, 0x1005d7fe, 0x10c61041, 0xfdf50240, 0x603e02c2, 0x58c2fd60, 0x5858ee01, 0xb55812fe, 0xbe0170b5, 0x42fe7070, 0x313a0270, + 0xc53131c5, 0x00050000, 0x06ab0008, 0x006103f8, 0x003e0034, 0x00500046, 0x37000058, 0x2a329f4b, 0x23072327, 0x12163313, 0x86230117, 0x081190a1, + 0x7655fd42, 0x0d310d2a, 0x372b2b23, 0x3a2e4140, 0x620a280a, 0x563c2262, 0x38384c36, 0x0d320d27, 0x3a374b1a, 0x36341f20, 0x215d653c, 0xd0025a3e, + 0x6e3bfa3d, 0x982689e4, 0x04d7fe26, 0xc5104011, 0x28034010, 0xac201391, 0x242c824b, 0x02b5b50b, 0x0a00419e, 0x8ef7fd21, 0x82002010, 0x00033400, + 0x06ab0060, 0x006103a0, 0x002b0015, 0x2500004b, 0x46300330, 0x06240eaa, 0x35210702, 0x2013b141, 0x1d874805, 0xdb3c012d, 0x12471270, 0x040b2b0a, + 0x820b2b0b, 0x256d2509, 0x4b012595, 0x2605c741, 0x96838401, 0x48684a26, 0xb7281461, 0xdd379e02, 0x279b2737, 0x08820282, 0xd641c383, 0x480b2007, + 0xcb821741, 0x4700042a, 0xb906b700, 0x0b005603, 0x2122cd82, 0x3f462900, 0x0a1b4618, 0x23110128, 0x21352311, 0x4c4d4815, 0x2e292807, 0x02ad292e, + 0x46ad0114, 0x01250702, 0x01c86c7b, 0x0f0846fc, 0xea45c120, 0x3e022106, 0x82057942, 0x4f06207f, 0x1e340893, 0x3d002700, 0x58004e00, 0x00007e00, + 0x26272205, 0x36373435, 0x30250184, 0x07020e33, 0x05944f06, 0x954f1720, 0x1d222408, 0x4f011401, 0x12560694, 0x4f06200a, 0x0e212d96, 0x12974f01, + 0x6b7a033f, 0x0f103736, 0x28271d1d, 0x553b8a31, 0x0a12123a, 0x3147110c, 0x6e2f3051, 0xfed96d6a, 0x06924f09, 0x05130426, 0x0512050c, 0x2212944f, + 0x4f144d14, 0x0e221794, 0x954f0e3a, 0x42fd350e, 0x3d3c7f42, 0x3038363d, 0x522d232f, 0x332a2b50, 0x3535312f, 0x2213904f, 0x821a691a, 0x11924f02, + 0x2eb62e22, 0x2215924f, 0x4f082008, 0x003c0d93, 0xff170106, 0x05e90508, 0x000b0015, 0x002d0017, 0x0055004b, 0x0500005f, 0x33301130, 0x21220382, + 0x07841530, 0xc6500b87, 0x34353305, 0x013e3736, 0x1e171632, 0x07061401, 0x3227010e, 0x01823736, 0x34013d2b, 0x2e272627, 0x06222301, 0x46018207, + 0x052107bf, 0x12d14f11, 0x016ccc24, 0x03826311, 0x10fd2208, 0x26266a42, 0x26262929, 0x256b836a, 0x262a2a26, 0x26416b25, 0x0d161740, 0x160d0c0c, + 0x28264017, 0x220b873f, 0x48f4013f, 0xf8250c83, 0xc1fd9f02, 0x2b048460, 0x2c2d5703, 0x5455822b, 0x2d2c2b82, 0xa9200983, 0x612d0883, 0x2519191b, + 0x2e692e25, 0x19192525, 0x2f0c8c1b, 0x6e9f0256, 0xf5fe6eb8, 0x282c6a01, 0x002c282e, 0x0036f082, 0x06ab000a, 0x006103f6, 0x00300012, 0x0044003a, + 0x2500004a, 0x40502e22, 0x07494f06, 0x112fe6af, 0x15211133, 0x6a422c01, 0x4c29294c, 0x8541426a, 0x21e09b07, 0x6449665d, 0x02220808, 0x10016d13, + 0x82572dac, 0x58825454, 0x82582d2d, 0x2d5782a8, 0x191a1b60, 0x6a2e2425, 0x1925242e, 0x0c8c1b1a, 0x6d505520, 0x02c1280e, 0x60c2fd9e, 0x82040000, + 0x06ab2ccb, 0x006103b6, 0x00220013, 0x4366002d, 0x302306d3, 0x88213015, 0x30112603, 0x32333001, 0x24e88317, 0x2b060701, 0x05ba5201, 0x2b262724, + 0x4d581101, 0x077e5106, 0x27262724, 0x0282012e, 0x37343522, 0x230d8051, 0x17141506, 0x08068051, 0x07060724, 0x014a010e, 0x01cafea3, 0x01edfe13, + 0x3441edc3, 0x29294a34, 0x4134344a, 0x5c4beded, 0x804b2e2e, 0xde45dc02, 0x2a242705, 0x4140372b, 0xdf451717, 0x11112405, 0x4535563d, 0x2b0807e0, + 0x3f3a384a, 0x3c361a1a, 0x10115d65, 0xb759201f, 0xba609e02, 0x02dcfe60, 0x5415159e, 0x547da87d, 0x5e601515, 0x2f5b6c5b, 0x6b22fe2f, 0x210ad645, + 0x5a511717, 0x24242107, 0x08095b51, 0x2a2c2f29, 0x0c0b1514, 0x2f515c13, 0x1c1b2627, 0x0400001d, 0x63008f00, 0xa9037106, 0x2f001500, 0x43003900, + 0x30250000, 0x50333001, 0x535a06ec, 0x02062806, 0x32210107, 0x49141516, 0xdf840bd4, 0x37212322, 0x4f08a252, 0x012e0906, 0x8dedfea2, 0x0f165916, + 0x0f050b36, 0x09820b38, 0xb92f8937, 0x01c2012f, 0x1b776873, 0x19193429, 0x1b1a1f1e, 0x1c111024, 0x06f54e1d, 0x4e3c3c21, 0x633407f3, 0xfe454603, + 0xc53645ec, 0x25c83729, 0x45140145, 0x8cd2fd8c, 0x3605e44e, 0x0703142a, 0x170b0b01, 0x32354918, 0x21202d2c, 0x33377525, 0x4e373429, 0x013409e3, + 0x0508ff32, 0x001405ce, 0x00330026, 0x008a0078, 0x0500009b, 0x202ec44e, 0x41d14a01, 0x27012e32, 0x11231123, 0x011e1333, 0x33113317, 0x35212311, + 0x0e260482, 0x27260702, 0x10823736, 0x02153008, 0x3d573870, 0x222c1010, 0x902a5523, 0x222d2d39, 0x0c171721, 0x0a010501, 0x1f31251c, 0x1e35472b, + 0x35573d22, 0x7542423a, 0x44024141, 0x4a393b3f, 0x13210888, 0x06884a34, 0x230a0b22, 0x0807884a, 0x1f1f233c, 0x2f362c2c, 0x0f293747, 0x0e0e0d4f, + 0x1d2d1211, 0x4045413e, 0x08b2fd47, 0x68030e34, 0x340edb79, 0x79670308, 0x08bc4301, 0x123e3417, 0x56554002, 0x25f8a3a5, 0x3c303044, 0x284f8149, + 0x1447080d, 0x1d0f1b24, 0x332f4d36, 0x59223c53, 0x3c0d3d3e, 0x0d3c3f3f, 0x3d013e3d, 0x2e072935, 0x0a262b31, 0x14160a2a, 0x09091e14, 0x28402d17, + 0x271a1a20, 0x06050619, 0x15140e0c, 0x482c2538, 0x0e0e1a1a, 0x172b2115, 0x4a10153f, 0x35080659, 0x035c3633, 0x1b63104a, 0x9e0200fe, 0x631b8dfe, + 0xfd010210, 0xf5015a62, 0x13433818, 0x5d5c3a02, 0x005abcfd, 0x001b0003, 0x03e506ab, 0x00390061, 0x007f005c, 0x47492500, 0x0568430d, 0x26272622, + 0x54106943, 0x07260aea, 0x010e0706, 0x1d472221, 0x013e2305, 0xd0513233, 0x5636200f, 0x22a2055b, 0x54100127, 0x320d2a77, 0x0570490c, 0x2c069143, + 0x11113131, 0x4c36573c, 0x0c273837, 0x0b734933, 0x10112308, 0x025a1f1f, 0x13958429, 0x68252413, 0x22765742, 0x120f3d0f, 0x584e3a48, 0x4c3c4e58, + 0x0f3a0f12, 0x1e9e7922, 0x430b8b49, 0x2e2306b4, 0x432c512e, 0x17230bb5, 0x552a2d17, 0x272d0611, 0x1d1c1b26, 0x4154a9b1, 0x2e2c2c40, 0x053b4e4d, + 0x200a0051, 0x281a9a52, 0x00050000, 0x06ab004f, 0x092b55b1, 0x55400021, 0x0122342b, 0x02823521, 0x15212808, 0x21070206, 0x603d5401, 0x23232222, + 0x79602222, 0x24244460, 0x483c6044, 0x4f904e4e, 0x01de014f, 0x2c2b5709, 0x57a35757, 0x032e0589, 0x0141fe60, 0x01cdfe42, 0x36d636a6, 0xd9544c01, + 0xfd2a082b, 0xea015bbc, 0xfe525b59, 0x070052ba, 0x08ff2e00, 0x1505d206, 0x33001c00, 0x53004700, 0x73005d00, 0x00009100, 0x30070637, 0x034c3015, + 0x30113205, 0x36373633, 0x06333037, 0x17121607, 0x01012e23, 0x0ae54511, 0x230cf145, 0x33302726, 0x20062949, 0x22cf8233, 0x57013011, 0x2e21187d, + 0x2df34701, 0x42f73608, 0x046d6d1a, 0x5a5a1848, 0x32ae417f, 0x278316ba, 0x01a50192, 0x01c0fead, 0x01ddfe23, 0x74220140, 0x6d1b7c73, 0x6c1b031b, + 0xa418781b, 0x014afb2d, 0x65655e20, 0x075d505e, 0x14481720, 0x41230829, 0x02d01e4b, 0x5cacfe9f, 0x4d6d6d1e, 0xe8fe4bce, 0xfee13d21, 0x609f02e2, + 0x60c460bb, 0xcbcc0801, 0x8232c732, 0xfe292702, 0xf6fe4ee2, 0xf8476203, 0xb5fd210d, 0x212d3748, 0x83620000, 0x0005358f, 0x0608ffca, 0x00150536, + 0x0017000f, 0x00660033, 0x05000092, 0x2a11054e, 0x33300706, 0x012e0526, 0x4e302327, 0x33260549, 0x011e1330, 0xe7493317, 0x30232106, 0x21106359, + 0x62592726, 0x05ad5a0a, 0x230d6159, 0x33270226, 0x16214282, 0x078e5317, 0x27069c53, 0x33373637, 0x23070206, 0x262f6c82, 0x07062327, 0x0207010e, + 0x3afb3df8, 0x4e98266e, 0x30340770, 0x0230c631, 0x08340e19, 0xdb796802, 0x030e3408, 0x5bfc7967, 0x48057c44, 0x2e35050e, 0x621e1e3a, 0x563d2262, + 0x38374c36, 0x1a490327, 0x1f3a384a, 0x07eb4d20, 0x90015e08, 0x6e1a6a1a, 0x18092e0d, 0x24080317, 0x0f360b0a, 0x0a360e79, 0x03092309, 0x6b232331, + 0x7a1b6e1c, 0x1910390d, 0x19190219, 0xf80d3b10, 0x0170b6b6, 0xfe7070bf, 0x3b027041, 0x34949494, 0xfd0f641b, 0xfe9f02ff, 0x1b640f8d, 0x61fd0102, + 0x343d5703, 0x2b0b2f0c, 0x313a1616, 0x060b2e27, 0x06945905, 0x321b1a35, 0x28224102, 0x2a2c1717, 0x130d0a2a, 0x4d2f515c, 0x830b1e36, 0xdb3b334b, + 0x1e706f2d, 0xdc2b2998, 0x2bdc3c3c, 0xde259425, 0x5f83a2a1, 0x3fea3223, 0x37008266, 0x0032ea3f, 0xff180104, 0x05e8050e, 0x001b000f, 0x0043003a, + 0x25000057, 0x221a7d41, 0x54233021, 0x072405fc, 0x37013e23, 0x98430a82, 0x010e2708, 0x01011e07, 0xc5433311, 0x41112007, 0x33200676, 0xb5432782, + 0xcd360806, 0x030c320c, 0x0ddb7867, 0x68030c31, 0x7f3f0379, 0x021b6d1b, 0x781b6b1b, 0x23249124, 0x1980238b, 0x1a021966, 0x24781a67, 0x9325248c, + 0x016cd9fb, 0x26010111, 0x8043269a, 0x77230807, 0x81279a27, 0xfd185f17, 0xfe9e02ff, 0x175f188e, 0x62fd0002, 0x2c2cb22d, 0xe5392db2, 0x36db3639, + 0x8229a729, 0xda363e02, 0x03e63936, 0xfd9e0229, 0x080160c2, 0x430f0144, 0x3131c732, 0xfe4332c7, 0xf6fe43f2, 0x22008200, 0x82360106, 0x82ca20f3, + 0x00142ff3, 0x002a001e, 0x00460032, 0x05000052, 0x57442330, 0x14152205, 0x20cb8206, 0x0f195d17, 0x07232722, 0x50083065, 0x0221070b, 0x0e3f4f03, + 0x21030222, 0x3a0b704e, 0x21016da3, 0x4142685a, 0x79186118, 0x85165a16, 0x2f2e2aac, 0xb603ac29, 0x423bfa3d, 0x10340a66, 0x10c51040, 0x6e79fd40, + 0x4811716e, 0x0a2b0b11, 0x0b2c0b04, 0x6e240982, 0x68016f70, 0x08099c4e, 0x9e02f220, 0x5f485d6c, 0x2fbc2f14, 0x5b2db52d, 0x282e292b, 0x96fed52b, + 0x0170b6b6, 0xfe6f6fbf, 0xfd507041, 0x59012506, 0x4f014f01, 0x240b554f, 0xb1feb1fe, 0x07ae5402, 0x00020030, 0x066300a9, 0x00a90357, 0x0033001d, + 0xd3412500, 0x51062005, 0xb641058d, 0x0516210e, 0x49050d50, 0x40080819, 0x15303330, 0xa0760330, 0x04139027, 0x18966464, 0xbc3335c2, 0x7f20a017, + 0x81200220, 0xbe179620, 0x2d018a33, 0x411c0aeb, 0x5003164f, 0xccce4195, 0x20ed4163, 0x0127a7a7, 0x014f5333, 0xd0342426, 0x34028234, 0x4fdbfe24, + 0x0271d7d7, 0x54461e72, 0xa1480217, 0x712bfd47, 0xe71e1000, 0x06348101, 0x02ff2801, 0x1a05d805, 0x25000f00, 0x56004300, 0x7c007400, 0x4f11d353, + 0x0120335b, 0x512ba14e, 0x022807a6, 0x01c76d67, 0x417301fb, 0x2107704f, 0x824f6b82, 0x416b2205, 0x09794f27, 0x40272725, 0x820d1616, 0x16162c00, + 0x41d0fd40, 0x29294c6b, 0x87416b4c, 0x41262107, 0x41341c87, 0x163f2826, 0x0d0d0c17, 0x3f16170c, 0xc86ced02, 0x4c01fc01, 0x3605cf51, 0x2b2db7fd, + 0x5554822c, 0x2d2c2c81, 0x812c2c2d, 0x2b2c82a9, 0x4e1a612d, 0x252106c0, 0x05c04e24, 0x4e252421, 0x1a2406cd, 0x572d0103, 0x58232e83, 0x82582d2d, + 0x8a57202c, 0x09c24f2b, 0x2205f94e, 0x52e8011a, 0x07360833, 0xfdfe3300, 0x0905c206, 0x16000c00, 0x61003c00, 0x9c008600, 0xb95aa200, 0x0f8b6119, + 0x2014f451, 0x06835a01, 0x5a010b21, 0x24a51a7f, 0x1614112c, 0x11353632, 0x07141133, 0x934d020e, 0x5b112005, 0x0124063e, 0x2b2c5709, 0x2a08284a, + 0x5e3aad02, 0x23232121, 0x612f2121, 0x1d5205b2, 0x390e390c, 0x0269200e, 0x010501c3, 0x081f080b, 0x1f078282, 0x04010b08, 0x13786201, 0x29058b5a, + 0x12082007, 0x62771247, 0x2282c0fb, 0x1d820c20, 0x08828226, 0x020c081e, 0x12222283, 0x33821249, 0x20080825, 0x82481207, 0x64013322, 0x65388e38, + 0x58350c0c, 0x0c36577f, 0x6636020c, 0xc15af8f4, 0xb120080f, 0x842a2b27, 0x2b2a83b6, 0x25251413, 0x0820084a, 0x535e3239, 0x365e53a1, 0x0821093c, + 0xa8014f4a, 0x2305925a, 0x1001f0fe, 0x2117905a, 0x23a1ff04, 0x9f023208, 0x4d514efe, 0xb201514d, 0x32445efe, 0x1f1f4132, 0x44323241, 0x61fda201, + 0xbbfd9f02, 0x0000005a, 0xff4d0104, 0x05b30502, 0x0017001a, 0x008b0051, 0x059f529d, 0x4a09bb50, 0xaa5009d5, 0x23414d14, 0x4d0efe48, 0x0120297a, + 0x2110f14e, 0x5a468501, 0x4b013809, 0x0c2a7654, 0x2a240c32, 0x4240362c, 0x0a3b1717, 0x31610a28, 0x48111031, 0x0c2306d9, 0x621a0c33, 0x3b290653, + 0x10105d65, 0xfd5a1f20, 0x2332848b, 0x2b2b230d, 0x272e3286, 0x3131620a, 0x563c1111, 0x37384c36, 0x32890d28, 0x82643c21, 0x1f1f2b32, 0x0ce2015b, + 0x68020d31, 0x0682db79, 0x79670323, 0x069246f2, 0x343d0b32, 0x2b0c2e0c, 0x31391616, 0x0b171827, 0x12020702, 0x250d5e4d, 0x17172822, 0x5e4d2b2c, + 0x6203210b, 0x012133b1, 0x0f3c487e, 0x0000002f, 0x00cf0002, 0x03310654, 0x003400b8, 0x10d94e4a, 0x666a2620, 0x08805c05, 0x52095e4a, 0x0e220740, + 0x35430102, 0x2787080d, 0x1135022e, 0x946a0202, 0x0f3f0f34, 0x4436352d, 0x493a5250, 0x3d7b2525, 0x6b4c2a3d, 0x46465e44, 0x21045b31, 0x2847465d, + 0x44202128, 0x29747e4b, 0xf901704e, 0x8551c552, 0x764b1110, 0x4b3b3bae, 0x404d5521, 0x360f3a0f, 0x3d481b1c, 0x070e3a31, 0x393a1706, 0x3e593865, + 0x3e212121, 0x322a0351, 0x34381c1d, 0x100d1a1a, 0x3a657318, 0x03254461, 0x6bfcfd54, 0x026b6c6c, 0x5c11fe04, 0x2b574443, 0x86581615, 0x82ef015c, + 0x732d10db, 0x0a393d07, 0xf60608ff, 0x0e001505, 0x2b001800, 0x53004900, 0x63005d00, 0x30010000, 0x09505c33, 0x7e5a2b20, 0x2b262306, 0xe24c1101, + 0x146b5c2c, 0x1133113a, 0x76021521, 0x256841ed, 0x25292925, 0xed416825, 0x5c5c4bed, 0x49fe804b, 0x3c3a985b, 0x292ba701, 0x7ea77e2a, 0x602b292a, + 0x5b6b5b5f, 0x0221fe5f, 0x82572df7, 0x57825455, 0x2007822d, 0x290682a9, 0x19191b61, 0x692f2425, 0xbf4c242f, 0x5c0c8807, 0xfd2e0e82, 0xfd9f02c0, + 0x050061c2, 0xab000300, 0xa756fd06, 0x5659200a, 0x052034a7, 0x2024bd4c, 0x11c05608, 0x200dae6b, 0x06c056a4, 0x744c9620, 0x83072105, 0x2007744c, + 0x0f006761, 0x3a2bd456, 0x134c13a7, 0xfe124b13, 0x121101ef, 0x4a13124a, 0x0263fe13, 0x279c279e, 0x82165916, 0x22088202, 0x820062fd, 0x00033100, + 0x06ab0022, 0x006103de, 0x0033001b, 0x1300006c, 0x561c4153, 0x114c15e7, 0x012e2114, 0x5c105259, 0xd7200fbc, 0x28054d53, 0x0c320cdb, 0x01796803, + 0x0abc5640, 0xb85c4c20, 0x2a02212f, 0x240a214b, 0xfd010218, 0x09a14b62, 0x5c080f6e, 0x250827b5, 0x01070000, 0x0502ff7c, 0x001a0584, 0x005b0037, + 0x00750068, 0x00a9009c, 0x010000d5, 0x010e2130, 0x37363307, 0x8866023e, 0x07012e07, 0x27222306, 0x2627012e, 0x17163727, 0x7917821e, 0x22220515, + 0x14820706, 0x37013e23, 0x3a5e6621, 0x6b07bf66, 0x1e220d24, 0x246b3301, 0x35212117, 0x29607182, 0x23262405, 0x83020e22, 0x233c8283, 0x17163202, + 0xc9790182, 0x08c28206, 0x26032137, 0x0c03d7fe, 0x0d0b0602, 0x1c2b200d, 0x1f364b2b, 0x2d3d1010, 0x232d392c, 0x13143423, 0x0e0c4f10, 0x1c2b230d, + 0x3b41413b, 0x0f12342b, 0x11040f3c, 0x017c0104, 0x245d6669, 0xfe3b3b37, 0x3c583717, 0x232c1110, 0x90295523, 0x212d2e38, 0x0c171622, 0x097d6b01, + 0x6b221e21, 0x5908067d, 0x50034141, 0x8f2339fe, 0x1b1b3324, 0x291c323a, 0x1006141f, 0x120b103f, 0x664c3812, 0x0e1c1b50, 0x1d2d190f, 0x691a201e, + 0x0152011a, 0x289e274e, 0x17101014, 0x4e361c0c, 0x2a2a3231, 0x0a10113d, 0x1516210a, 0x10143e18, 0x410d1911, 0x413a0b3a, 0x09021421, 0x3ef93e02, + 0x4e6657fd, 0xd1012137, 0x2d0be66b, 0x28282726, 0x01352d2e, 0x1b231401, 0xe66b1d10, 0x683f0812, 0x2e207f20, 0x0c2e2a2a, 0x1c113831, 0x19061627, + 0x1d1d2006, 0x1a1e1b2e, 0x2b25241b, 0x1c3e4528, 0x5a171c1c, 0x00000017, 0xff7a0106, 0x05860502, 0x0028001a, 0x006c0036, 0x009f0092, 0x680000ca, + 0x3f680c40, 0x21252226, 0x18834206, 0x37013e24, 0x345f031e, 0x07386906, 0x25211322, 0x6d14a75e, 0x2122196b, 0x88613635, 0x1e454206, 0x45685220, + 0x5a393505, 0x0d2c2222, 0x0e0a0403, 0x1f30260e, 0x3424242b, 0x1e11111e, 0x08054468, 0x10103d45, 0x41413bec, 0x42423a3b, 0xd6fe3403, 0x0b070c05, + 0x2a210c0d, 0x364a2b1d, 0x3e0f101f, 0x2d392c2d, 0x13352322, 0x340e1014, 0x221b0d0d, 0x403c1c2b, 0x342b3c40, 0x0f3c0e12, 0x7c011207, 0x583810fd, + 0x8211103c, 0x29552c23, 0x2e2d3890, 0x17162221, 0x6d03030c, 0xcd5e07c7, 0x41412205, 0x05494275, 0x336b6b25, 0x423b1c1b, 0x0f210548, 0x07484240, + 0x0e1b1c2e, 0x1e2c190f, 0x691b201d, 0xb352011a, 0x222d3068, 0x42a449f2, 0x0a241475, 0x21140a2a, 0x230b7642, 0xb9010174, 0x212d3b42, 0x3a42605f, + 0x06003824, 0x08ff3900, 0x1505c706, 0x1c000f00, 0x32002800, 0x7a005700, 0x58050000, 0x303407d1, 0x16333013, 0x26031712, 0x06233027, 0x30073007, + 0x01012e33, 0x5315536e, 0x25750f99, 0x14735313, 0x1e171625, 0x44331701, 0x113c0588, 0x0a1e0423, 0x06e20624, 0xc9640a24, 0x21872182, 0x0c0b0af1, + 0xb13c0a0b, 0x9bfc290b, 0x080d306e, 0x3bad0230, 0x2421215d, 0x2f212124, 0x33553b2e, 0x4a0d1f34, 0x44343f11, 0x35444c4c, 0x380e1243, 0x026a1f0e, + 0x010501c4, 0x0421090c, 0x22038282, 0x0c820c09, 0x3678623e, 0x05210937, 0x05171808, 0x62771552, 0x187f23f8, 0x02237f18, 0x41fe709f, 0x31e00170, + 0xd3240082, 0xa5018c24, 0x211d4e53, 0x4d532907, 0x52163f12, 0x01f0fe09, 0x16510810, 0xfe124b14, 0x769f0263, 0x0e5d1975, 0xb10b4242, 0x0061fd2f, + 0x67410700, 0x00162c08, 0x002a0020, 0x003f0035, 0x7f870064, 0x06230807, 0x6c321507, 0x0e20061c, 0x2305a571, 0x34013d36, 0x200ca371, 0x13ff7301, + 0x76057856, 0x75411e9b, 0x02220822, 0x4e100198, 0x1d343750, 0x0a221817, 0x39281609, 0x66d5fe22, 0x262625a7, 0x2197a725, 0x97212525, 0x7d413bfd, + 0xa7013f50, 0x48415459, 0x0b0b0c05, 0x211c1c28, 0x1c33472b, 0x2c2b275a, 0x2457272c, 0x23292b28, 0x85411d01, 0x00003451, 0xff270105, 0x05d90502, + 0x002a001a, 0x003c0034, 0x827d0071, 0x09597314, 0x33023e24, 0x71761632, 0x10e76a19, 0x650e7b54, 0x5d65085e, 0x0d7c5d0d, 0x210a0c5b, 0x8676f402, + 0x7302261f, 0x6f3afb3c, 0x07ed6be5, 0xc6114026, 0xb6fd4010, 0x6b12ea76, 0x6426135d, 0x5a3f215e, 0xd3542e01, 0x768c2009, 0x59210796, 0x0896762d, + 0x0808652e, 0x1f2f1010, 0x9bfe5d34, 0x9e02b6b6, 0x200b345b, 0x0a51544e, 0x020b2f22, 0x540ef376, 0x5c250982, 0x374d2f51, 0x09fd6f1d, 0x0200003d, + 0x16ffce01, 0x0e043205, 0x3b002100, 0x30050000, 0x26272223, 0x2e353035, 0x82262701, 0x05b04208, 0x1617322f, 0x15011e17, 0x15070214, 0x3e322733, + 0x05987401, 0x23022e22, 0x0808436f, 0x04021e28, 0x28558e70, 0x2f885527, 0x3e191b2f, 0x50503938, 0x395050c4, 0xa0bb3e38, 0x603af09a, 0x13131244, + 0x3a604412, 0x09855f3b, 0x2cea5f31, 0x0b4c492b, 0x5b41414d, 0xc27f735c, 0x82224142, 0x42413400, 0xfee17fc2, 0xf2671cfc, 0x37374c28, 0x37459e45, + 0x8a284c37, 0x0300290a, 0xb7001300, 0x5603ed06, 0x3d220782, 0x61675100, 0x61032005, 0x944b0f5f, 0x30032206, 0x07535803, 0x30233023, 0x0f2b6c11, + 0x30231123, 0x22018221, 0x84013035, 0x21230805, 0x02061530, 0xe3302107, 0x5d1772cf, 0x5b170d17, 0x8a227017, 0x01090322, 0x080c0105, 0x8282081e, + 0x44071f08, 0x12360597, 0x20071249, 0x1f080808, 0x12481208, 0x9a026277, 0x410141fe, 0x7662cefe, 0x01b73206, 0x329b0103, 0xc83131c8, 0xeefe4432, + 0x01fdfe45, 0x21874b9d, 0x28097d62, 0x00040000, 0x06ab004c, 0x26e382b4, 0x001e0014, 0x835f0028, 0x1ddb5de5, 0x2107a642, 0x994a0111, 0x5db92032, + 0x192106e4, 0x08e45d60, 0xac2a2e24, 0x56681302, 0x58032707, 0x0c03d7fe, 0x244a0703, 0x0e132123, 0x2006244a, 0x0eec5db7, 0x292e2827, 0x96fed52b, + 0x065a6802, 0x9e28402a, 0x10101427, 0x351d0c17, 0x210fc549, 0xc5491011, 0x8200200e, 0x01043000, 0x0502ff73, 0x001a058d, 0x007d004c, 0x72e000b4, + 0x17201717, 0x2106e24a, 0x01840607, 0x011e1522, 0x8405f24a, 0x2306220d, 0x05115722, 0x82372721, 0x0c227217, 0x210a324b, 0x596b2627, 0x06364b06, + 0x36370123, 0x85558632, 0x010e2354, 0x68412107, 0x8a012033, 0x1d514964, 0x67500221, 0x62081192, 0x1d1d2828, 0x0a0a1110, 0x17181212, 0x13331d1a, + 0x110b0b13, 0x2c1f2011, 0x232f362c, 0x141c1b24, 0x0d4f0f15, 0x2d12111c, 0x45423d1d, 0x80034740, 0x8f2439fe, 0x1b1c3323, 0x1b321e1d, 0x0b0f0f2a, + 0x4010050a, 0x13110b0f, 0x66262637, 0x0e1c1b51, 0x1616190e, 0x1a201e1d, 0x52011b69, 0xd6fea7fd, 0x49030b03, 0x37350893, 0x3e100f1e, 0x2d392d2c, + 0x14342322, 0x0d4e0f14, 0x2c220e0d, 0x0692491b, 0x4c3b0f21, 0x02240507, 0x2438fe50, 0x2107b34b, 0xb34b1e2a, 0x854b2008, 0x4b18205e, 0x357208b3, + 0x0c270810, 0x2116170b, 0x1a20291f, 0x0c141419, 0x0604060d, 0x1d14151a, 0x242c251c, 0x0e191a24, 0x110a0a0e, 0x17161511, 0x7222143e, 0x7520093d, + 0x2609614b, 0x0e111c1c, 0x4b13140e, 0x0d210764, 0x05654b0e, 0x1f442923, 0x05664b1f, 0x4c460521, 0x62202b22, 0x2028bb4b, 0x06274f04, 0x0f005628, + 0x37002e00, 0x5b5e8f03, 0x243f6f13, 0x02260526, 0x011d3327, 0x22354618, 0x158a4518, 0x5fa638c9, 0x461826a6, 0x1520194a, 0x153d4618, 0x3d370122, + 0x14774518, 0x45181494, 0x119111b3, 0x26a638a6, 0x35215fcc, 0x3f461833, 0x3a012810, 0xc901b266, 0x706b0601, 0x282105f6, 0x12f67027, 0x18eb0123, + 0x0346185f, 0x03012d4f, 0x040c040e, 0x380e040e, 0x390e7c0e, 0x46180782, 0x01285204, 0x18621964, 0x0f390f7a, 0x0b3a6b82, 0x0f030e04, 0xfc020f3d, + 0x4502bbfd, 0xb0fd5959, 0x3c7f4242, 0x38373c3d, 0x7a71302f, 0x34302107, 0x200a7a71, 0xda45104a, 0x002f5503, 0x00050000, 0x06ab0047, 0x006103b9, + 0x822f001e, 0x0058280b, 0x01000070, 0x6c07010e, 0xc67a0ad7, 0x82332005, 0x06d96c14, 0x20243e7b, 0x3925a405, 0x3d0f1001, 0x046c6c10, 0x1e104010, + 0x287e1e79, 0xad2b289f, 0x8822832b, 0xd27a6302, 0x06062718, 0x31100f07, 0x209e5202, 0xf0012208, 0xcf124612, 0xacfe9e02, 0x25145115, 0xbc2f2491, + 0xfefe412f, 0xfed13441, 0x40592ef0, 0x40525340, 0x06797a41, 0x49341b35, 0x482c762b, 0x341b1b34, 0x762c2424, 0x1b23252b, 0xa35c1b1a, 0x00002224, + 0x08934e06, 0x42002f3a, 0x8d006300, 0xa0009800, 0x30050000, 0x30353021, 0x36373637, 0x34353035, 0x2a0adb49, 0x013e3736, 0x17011e32, 0x4a141516, + 0x07250581, 0x2107010e, 0x052a5605, 0x82343521, 0x3637211d, 0x8306937c, 0x05554d3d, 0x82272621, 0x85222001, 0x05dd752f, 0x16171623, 0x51421801, + 0x22f74e08, 0xf2791220, 0x4503240c, 0x53d639fe, 0x5a550911, 0x1c1c2c05, 0x3750664c, 0x0c0d0f0e, 0x531d1716, 0x01260613, 0x2e2e3f49, 0x00820e3c, + 0x2e3c2308, 0x767c3f2e, 0x19227c76, 0x070f1018, 0x0f070606, 0x45191810, 0x100f1918, 0x06070706, 0x18190f10, 0x0e4f89fe, 0x3d742620, 0x726e3afb, + 0x0c0f4f72, 0xbf68f22c, 0x2f292a2e, 0x1138310c, 0xc349261d, 0x17172a06, 0x24351e1b, 0x23282b25, 0x07c34922, 0x18176722, 0x33072e7c, 0xfeb71817, + 0x0e5cb6b8, 0x231a1a0e, 0x2c752d24, 0x1a1a2424, 0x0e29a182, 0x24231b1a, 0x242d752c, 0x210e8323, 0x2d4f7703, 0x4f01231f, 0x2f4f4f01, 0x0020080a, + 0x01060000, 0x0568fe0b, 0x000f05f5, 0x0039001f, 0x004b0041, 0x006f0055, 0x23300100, 0x013d2622, 0x2014fd4e, 0x1afd4e06, 0x2007f667, 0x12877701, + 0x41180520, 0x2e080d65, 0x33112311, 0x37363313, 0x02231133, 0x35395fe5, 0x201f5b38, 0x262a1211, 0x82353625, 0x26263536, 0x676b7c29, 0x2d4027a1, + 0x0d0c0c0d, 0x8227402d, 0x0d0c2d09, 0x402d0c0d, 0xc76ded02, 0x3bfbfb01, 0x2b0cff79, 0x09051504, 0x62190923, 0x19621818, 0x05390882, 0x06b48067, + 0x677b595a, 0x313a68fe, 0x2b340732, 0x4c3e3d2b, 0x2b2c8155, 0x3d008217, 0x55812c2b, 0x4513ad96, 0x25331aa2, 0x2e6a2d25, 0x1b332425, 0x2524331b, + 0x252d6a2e, 0xec673325, 0x24012108, 0x2d09e276, 0x2b282e29, 0x1249123e, 0x2d2db32c, 0x08822cb3, 0x02fffd39, 0xababfe9e, 0x0062fdaa, 0x00020000, + 0x06540085, 0x00b8037b, 0x644d0034, 0x1a41357f, 0x133d0813, 0x01231133, 0x359469b7, 0x2c103e10, 0x51443536, 0x26493951, 0x3e3d7a25, 0x436c4c2a, + 0x3145465f, 0x5d21035b, 0x27284846, 0x4a442120, 0x4e29757e, 0x06fa0371, 0x130b2c0b, 0x81242381, 0x27088213, 0xe1a18206, 0x829ae007, 0x2a2d8c64, + 0x5a178f02, 0x40ec2217, 0x8222ec40, 0x7ffd3808, 0x56fe4603, 0xbafcaa01, 0x00030000, 0x066300b5, 0x00a9034b, 0x7b15000b, 0x092119ad, 0x11d57601, + 0x6801b63c, 0x747f7f74, 0x3934d8e1, 0x03d83439, 0x8cedfe5a, 0x0a175817, 0x0f050f37, 0x09820a38, 0xba2e8834, 0x4603632e, 0xfe89e689, 0x36c501b2, + 0x36323a32, 0xa17631fd, 0xc8252205, 0x0aa17637, 0x00820020, 0x20071b50, 0x06bf4561, 0xbd457e20, 0x34ce4e46, 0x10152108, 0x6d6d0f3d, 0x10401003, + 0x7f1e781f, 0x2b27a028, 0x22832bac, 0x3f630287, 0x0e0f3b5c, 0x5c3b0f0e, 0x28054344, 0x0d0d1f31, 0x3145311f, 0x053b441f, 0x1a033122, 0x45325050, + 0x01213edf, 0x2c7150ef, 0x5b01053a, 0xa50502ff, 0x34001a05, 0x48003e00, 0xa2008100, 0x22050000, 0x37362726, 0x54079f79, 0x0225103f, 0x23012e07, + 0x0f3f5422, 0x14654b18, 0x01694589, 0x0d597629, 0x2a0eb157, 0x010e1716, 0x76555002, 0x7f26252a, 0x0b2314c7, 0x7f091e1a, 0x01210dc8, 0x0545442d, + 0x2aacb335, 0xac2a2e2e, 0x76542cfe, 0x2425262b, 0x40372b2a, 0x69161842, 0x0d211140, 0x0e406919, 0x08057476, 0x69242521, 0x22755841, 0x48112e2d, + 0x58584e3b, 0x134b3d4e, 0x79224d0a, 0x23343dfd, 0x16162b23, 0x54273139, 0x0a230e8c, 0x54081b16, 0x4b18128d, 0x292507bf, 0x012b282e, 0x693d8918, + 0x2a082650, 0x4055a9b1, 0x2d2c2d40, 0x19194b4d, 0x5d6a3930, 0x3e695d66, 0x492f0631, 0x00000052, 0x002e0004, 0x03d206b7, 0x000f0056, 0x18360027, + 0x5e15e741, 0x132015d5, 0x25182d61, 0x01c86c62, 0xad5570fc, 0xed832b09, 0x25256940, 0x25252828, 0xf6604069, 0x18812005, 0x2009e841, 0x05bb7002, + 0x2a9e0227, 0xa87d2a2a, 0x2705827d, 0x6c5b5e60, 0x22fe5e5b, 0x002d9e82, 0xff4b0106, 0x05b50502, 0x0015001a, 0x30ab821e, 0x016e0049, 0x050000d8, + 0x21303530, 0x12363530, 0x053d7437, 0x2330152e, 0x25301530, 0x11303330, 0x010e2330, 0x2007145e, 0xd344183e, 0x48012008, 0x2e23073d, 0x7e062201, + 0x1e240719, 0x26220102, 0x6d08006a, 0x07220681, 0x46181d06, 0x352b0e81, 0x0f231133, 0x0e0f1501, 0x840d0f15, 0x91088205, 0x2e05270b, 0x35372701, + 0x02840b3f, 0x05840a20, 0x06200b88, 0x073c1793, 0x15331133, 0xc9fea102, 0x8e2db52d, 0xbffe5c5c, 0x8e2307db, 0x5c3eaf02, 0x1d0f0e3c, 0x09bd4418, + 0x00820720, 0x310f0f26, 0x0f103145, 0x07390982, 0xeefd311f, 0x49279683, 0x3b584168, 0x3c0f213b, 0x3b481110, 0x2d2d2c4d, 0xd849182c, 0xbc2f220a, + 0x3b4c1808, 0x222eeb2e, 0xd20b2c0b, 0xd202206e, 0x01012453, 0x18f2a3a6, 0x290ea54a, 0x582fe2fe, 0x51524140, 0x45185883, 0x243b07aa, 0x2b752c25, + 0x1a1a2425, 0x1a1a1c1c, 0x752b2524, 0x3324252c, 0xb106031c, 0x188055a9, 0x2c0f6148, 0x09313e34, 0x29490923, 0x015a0b29, 0xd0b1d4f5, 0x280a2254, + 0x8953d00a, 0x55b64150, 0xfd235f86, 0x82005abc, 0x02350800, 0x5f025c00, 0x7105a406, 0x1b000300, 0x21130000, 0x27012115, 0x33351737, 0x07173715, + 0x17231533, 0x23152707, 0x37270735, 0x065c3523, 0x04b8f948, 0x8c2a8cc2, 0x2103823c, 0x0887c6c6, 0x46a50224, 0x118c2202, 0x00261a84, 0x5c000100, + 0x5b8225ff, 0x1400d622, 0x38085982, 0x3e012c32, 0x34113505, 0x022c032e, 0x019d5c23, 0xf6050134, 0x5b7fadc7, 0xaa6f3c2e, 0xfef8fecc, 0xada9fee5, + 0x5633a502, 0x7a837e72, 0xf90e4766, 0x7d5b154f, 0x68869190, 0x24478d3e, 0x012c2201, 0x2047832e, 0x2747823e, 0x9da40633, 0xfbfeccfe, 0x01254889, + 0x011b0108, 0x82489657, 0x000532ef, 0x0638ff2a, 0x009405d6, 0x00400004, 0x014b0044, 0x2b9b8208, 0x21072130, 0x030e2204, 0x07040e07, 0x2e06eb57, + 0x33363435, 0x041e1732, 0x37033e32, 0x8337043e, 0x1716240c, 0x83141516, 0x032e391e, 0x21152103, 0x05231501, 0x25352325, 0x33023e34, 0x36171632, 0x17031e32, 0x14212682, 0x21058306, 0x05833236, 0x013e1725, 0x82033e37, 0x84362047, 0x22288340, 0x8631011e, 0x2317840c, 0x021e3233, 0x5b852983, 0x85141521, 0x27262961, 0x3435012e, 0x27022e35, 0x0e2e6e83, 0x27222301, 0x0607010e, 0x07062722, 0x0c86030e, 0x02200683, 0xb0840e82, 0x03862683, 0x82022e21, 0x273b08ba, 0x35010e34, 0x2627010e, 0x16172627, 0x06273435, 0x36373437, 0x5c262223, 0xfe46e401, 0x54e00462, 0x2f4f5061, 0x3c15070f, @@ -273,36 +274,40 @@ const unsigned int furIcons_compressed_data[14372/4] = 0x016e5801, 0xf0f0fa25, 0x1d0da0fa, 0x1b151a29, 0x1d110e07, 0x26170e11, 0x0c020b3a, 0x0505070d, 0x0b091037, 0x08040910, 0x040d670c, 0x3b1f2741, 0x0e186037, 0x121d1107, 0x15092617, 0x5201100f, 0x04380443, 0x34010512, 0x10171108, 0x0b122d0c, 0x3e080403, 0x2f070b42, 0x0b24111d, 0x14111045, 0x1d0f331c, 0x0a5d090e, 0x18180c4d, 0x022d410c, 0x17211617, 0x0c110508, 0x2226141b, 0x19220e05, 0x02071703, 0x02030c0c, 0x04110205, 0x04020202, - 0x24038201, 0x171a0702, 0x1e734300, 0x38188f43, 0xff5c0003, 0x05a40637, 0x000600e0, 0x003b000d, 0x23110100, 0x11230109, 0x24068503, 0x07012f01, - 0x20018927, 0x2b0f840f, 0x021f020f, 0x013f1737, 0x1737011f, 0x0328018a, 0x1401c834, 0x98c81401, 0x023d0685, 0x4e7238d8, 0x60484b60, 0x27545a5a, - 0x4554184b, 0x364b394b, 0x2539155a, 0x5a153925, 0x3f0c8236, 0x4b185445, 0x5a5a5427, 0x604b4860, 0x5d01724e, 0xdefefcfe, 0x04012201, 0x04015d02, - 0xdefe2201, 0x2e080f82, 0x04381bc8, 0x59512d42, 0x2a372166, 0x70844858, 0x3b4b645a, 0x6c438f52, 0x528f4a65, 0x5a644b3b, 0x58488470, 0x6621372a, - 0x422d5159, 0x44003804, 0x0741217b, 0x1b3f4118, 0x00042308, 0x065effc8, 0x00a60538, 0x000f0003, 0x001f001b, 0x21352500, 0x33150315, 0x23152315, - 0x33352335, 0x0b8b0135, 0x1123112e, 0xcc016c04, 0x64b4b4b4, 0xc0fcb4b4, 0x02270684, 0x64a05a31, 0x839c0464, 0xb4642312, 0x07855cfe, 0xf90e0225, - 0x9f4806b8, 0x010531b7, 0x0508ff56, 0x001505aa, 0x00de00b4, 0x010c01ec, 0x0524ea82, 0x23113335, 0x49091f49, 0x2b490b28, 0x67082008, 0x332a05ee, - 0x01153311, 0x020e0714, 0x4e532307, 0x012e2305, 0x0e820623, 0x20154e18, 0x6008ad49, 0x36280dd9, 0x17011e37, 0x25060706, 0x2328425c, 0x07bc9c01, - 0xc05ad446, 0x2c0b295a, 0x1d721c0b, 0x1c02a3a5, 0x35053c66, 0x22215b38, 0x04020d2d, 0x0e0f0a01, 0x2a203025, 0x1e352424, 0x4e181111, 0x3a320a82, - 0x3b3a4242, 0x15fe4141, 0x49269584, 0x76574169, 0x734c5b22, 0x0d511806, 0xe2022108, 0x3607f45c, 0x2a1b323b, 0x1005151e, 0x120a0f40, 0x664c3713, - 0x0f1b1c50, 0x5c2c190e, 0xf82107ef, 0xa89a485b, 0x0a273308, 0xfd1f7c1f, 0xa5015bbc, 0x6b414049, 0x4d2a1b55, 0x36592928, 0x12140101, 0x0f101a12, - 0x304c370e, 0x1e2a2b31, 0x1312211e, 0x92303044, 0x3c0e3c3e, 0x04823f3f, 0x08023e32, 0x8154a9b2, 0x4b4d2d58, 0x6a393032, 0x6a5d655d, 0x30089749, - 0x207f2068, 0x2e2a292f, 0x1038310c, 0x0716271d, 0x0ead6818, 0x1c1d1b2d, 0x00165a17, 0x000e0000, 0x820100ae, 0x20028507, 0x240b8602, 0x000d0001, - 0x240b861f, 0x00070002, 0x240b863d, 0x00290003, 0x200b8699, 0x20238204, 0x240b86df, 0x010f0005, 0x2a0b860d, 0x010c0006, 0x00030037, 0x85090401, - 0x220b8654, 0x821a0001, 0x20178509, 0x20778202, 0x2417862d, 0x00520003, 0x200b8645, 0x20238204, 0x240b86c3, 0x001e0005, 0x240b86ed, 0x01180006, - 0x304d831d, 0x00750046, 0x006e0072, 0x00630061, 0x00200065, 0x20078249, 0x2e0f826f, 0x46000073, 0x616e7275, 0x49206563, 0x826e6f63, 0x8252200e, - 0x8267201f, 0x826c202d, 0x0072282b, 0x67655200, 0x82616c75, 0x00452208, 0x2219826c, 0x82740063, 0x82692047, 0x0020223d, 0x200f824b, 0x220f8265, - 0x823a0020, 0x85619951, 0x0032241f, 0x842d0038, 0x00323803, 0x00320030, 0x45000033, 0x7463656c, 0x20636972, 0x7465654b, 0x8c203a20, 0x270f8289, - 0x382d3832, 0x3230322d, 0x5d992a82, 0x5620bf8f, 0x72269582, 0x69007300, 0xdf826f00, 0x6b822020, 0x31003024, 0x07842e00, 0x00003030, 0x73726556, - 0x206e6f69, 0x2e313030, 0x10823030, 0x1741598d, 0x06164111, 0x02000023, 0x20008b00, 0x840c8b01, 0x824c200b, 0x019c0805, 0x03000200, 0x03010201, - 0x05010401, 0x07010601, 0x09010801, 0x0b010a01, 0x0d010c01, 0x0f010e01, 0x11011001, 0x13011201, 0x15011401, 0x17011601, 0x19011801, 0x1b011a01, - 0x1d011c01, 0x1f011e01, 0x21012001, 0x23012201, 0x25012401, 0x27012601, 0x29012801, 0x2b012a01, 0x2d012c01, 0x2f012e01, 0x31013001, 0x33013201, - 0x35013401, 0x37013601, 0x39013801, 0x3b013a01, 0x3d013c01, 0x3f013e01, 0x41014001, 0x43014201, 0x45014401, 0x47014601, 0x49014801, 0x696e7507, - 0x30463045, 0x31200786, 0x32200786, 0x33200786, 0x34200786, 0x31210784, 0x21278530, 0x27853031, 0x85303121, 0x30312127, 0x31212785, 0x20278730, - 0x202f8635, 0x20078636, 0x20078637, 0x20078638, 0x20078639, 0x20078641, 0x20078642, 0x20078643, 0x20078644, 0x20078645, 0x21078546, 0x07863031, - 0x07863120, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, 0x31207f86, - 0x31207f86, 0x31207f86, 0x32217f86, 0x21778530, 0x07863132, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, - 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x32207f86, 0x33217f86, 0x21778530, 0x07863133, 0x33207f86, 0x33207f86, 0x33207f86, - 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x33207f86, 0x34217f86, 0x21778530, - 0x07863134, 0x83003221, 0xff012300, 0xe54400ff, 0x00002607, 0x0014000c, 0x24168204, 0x00000002, 0x85038601, 0xdf002409, 0x8231cbd6, 0xe0002c11, - 0x009ffffd, 0xe1000000, 0x050dea11, 0x401501fa, 0x00000011, + 0x24038201, 0x171a0702, 0x07b34300, 0x00492508, 0x000f000b, 0x33150100, 0x23152315, 0x33352335, 0x15210135, 0xb4980521, 0xb4b464b4, 0x480628fb, + 0x4905b8f9, 0x64380b83, 0x465cfdb4, 0x53000500, 0x8c063eff, 0x0600a705, 0x2c002800, 0x37003000, 0x11293d82, 0x33010b33, 0x07232711, 0x20018327, + 0x26058403, 0x1b35020b, 0x82173702, 0x84132001, 0x33172905, 0x2b153321, 0x37333502, 0x2e082d85, 0xcea0a104, 0xc936a0ce, 0x303f334a, 0x3a3a3f2f, + 0x10311937, 0x27273736, 0x31103637, 0x3a3a3719, 0x3f302f3f, 0x01c94a33, 0xbc8a8af2, 0x83887373, 0x0247082c, 0x01b00108, 0xfedefe22, 0x3ed63a50, + 0xe3cd72a9, 0x8b54fcfe, 0xfe92df6a, 0x010401d4, 0xeb0189eb, 0xaffe0401, 0x8b6adfb7, 0xe3fcfe54, 0x3ea972cd, 0x3a6161d6, 0xdefe50fe, 0xb0012201, + 0x00030000, 0x0637ff5c, 0x82e005a4, 0x000d22bb, 0x26b7833b, 0x23010923, 0x84110311, 0x2f012206, 0x85bf8501, 0x840f2005, 0x020f220f, 0x23c4821f, + 0x011f013f, 0x0586c485, 0xc8340328, 0x14011401, 0x068598c8, 0x38d8023d, 0x4b604e72, 0x5a5a6048, 0x184b2754, 0x394b4554, 0x155a364b, 0x39252539, + 0x82365a15, 0x5445310c, 0x54274b18, 0x48605a5a, 0x724e604b, 0xfcfe5d01, 0x04229484, 0xb9825d02, 0x3008d183, 0x1bc8fefc, 0x2d420438, 0x21665951, + 0x48582a37, 0x645a7084, 0x8f523b4b, 0x4a656c43, 0x4b3b528f, 0x84705a64, 0x372a5848, 0x51596621, 0x3804422d, 0x3b008200, 0xff4b0002, 0x05b50622, + 0x000900d0, 0x0500002a, 0x15012d15, 0x010d3521, 0x17130135, 0x3f20ad8b, 0x0324d98d, 0x6d010307, 0x04227e83, 0x7a820126, 0xd3fa2608, 0x1f6d6e4e, + 0x756d3262, 0x615e7d75, 0x4994667d, 0x7d669449, 0x757d5e61, 0x62326d75, 0x4e6e6d1f, 0xcecea03e, 0x080383a0, 0xfe540333, 0x73eccd7e, 0x426e54b0, + 0x59a1b2cc, 0x36993184, 0x84319935, 0xccb2a159, 0xb0546e42, 0xcd090190, 0x00007efe, 0xff5e0002, 0x05a2066a, 0x000b007b, 0x0e5b421f, 0x03270330, + 0x27020b27, 0x021b3711, 0x13371337, 0x69421521, 0xc7fe2106, 0x86877487, 0x42a70221, 0xfc330777, 0x629dfef0, 0xfeb2f7fe, 0xfe6501be, 0x07058467, + 0x8267fe84, 0xb2be2f09, 0xfe62f7fe, 0x0300749d, 0x3eff5300, 0x9342af06, 0x002f2c06, 0x35211300, 0x2135010d, 0x41211503, 0x80420507, 0x021b2205, + 0x42798235, 0x072109a0, 0x20268503, 0x075442cb, 0x45035522, 0x21068c42, 0x8c42363b, 0x3b36210b, 0x20068c42, 0x074b4296, 0xa0030428, 0xfea0cece, + 0x864261fc, 0x9bfe2126, 0x00202f83, 0x04280082, 0x5effc800, 0xa6053806, 0x0f2bb582, 0x1f001b00, 0x35250000, 0x43031521, 0x0b8b0b7f, 0x1123112e, + 0xcc016c04, 0x64b4b4b4, 0xc0fcb4b4, 0x02270684, 0x64a05a31, 0x439c0464, 0xfe210595, 0x2507855c, 0xb8f90e02, 0x62824806, 0x47010021, 0x0221058f, + 0x2c6382a5, 0x15211300, 0x48065c21, 0xa502b8f9, 0x231c8346, 0xae000e00, 0x0a842182, 0x02200482, 0x01220b86, 0x8b820d00, 0x11820120, 0x02000026, + 0x3d000700, 0x03241786, 0x91002500, 0x04200b86, 0xd3202382, 0x05240b86, 0x01010f00, 0x06240b86, 0x2b010c00, 0x01226b82, 0x3f840904, 0x0b860020, + 0x1a000122, 0x03210982, 0x20178300, 0x20778202, 0x2417862d, 0x004a0003, 0x200b8645, 0x20238204, 0x240b86b7, 0x001e0005, 0x240b86e1, 0x01180006, + 0x304d8311, 0x00750046, 0x006e0072, 0x00630061, 0x00200065, 0x20078249, 0x2e0f826f, 0x46000073, 0x616e7275, 0x49206563, 0x826e6f63, 0x8252200e, + 0x8267201f, 0x826c202d, 0x0072282b, 0x67655200, 0x82616c75, 0x00462108, 0x74212f83, 0x22078300, 0x84670072, 0x823a2045, 0x21599949, 0x1f830020, + 0x38003124, 0x03842d00, 0x30003226, 0x33003200, 0x6f2a7182, 0x6f46746e, 0x20656772, 0x7d8c203a, 0x31270f82, 0x2d382d38, 0x83323032, 0x20b3a826, + 0x248d8256, 0x00730072, 0x20a38469, 0x24678220, 0x00310030, 0x3007842e, 0x56000030, 0x69737265, 0x30206e6f, 0x302e3130, 0x8d108230, 0x110b41b3, + 0x23060a41, 0x00020000, 0x0120008b, 0x0b840c8b, 0x05824b20, 0x00019a08, 0x01030002, 0x01030102, 0x01050104, 0x01070106, 0x01090108, 0x010b010a, + 0x010d010c, 0x010f010e, 0x01110110, 0x01130112, 0x01150114, 0x01170116, 0x01190118, 0x011b011a, 0x011d011c, 0x011f011e, 0x01210120, 0x01230122, + 0x01250124, 0x01270126, 0x01290128, 0x012b012a, 0x012d012c, 0x012f012e, 0x01310130, 0x01330132, 0x01350134, 0x01370136, 0x01390138, 0x013b013a, + 0x013d013c, 0x013f013e, 0x01410140, 0x01430142, 0x01450144, 0x01470146, 0x6e750748, 0x46304569, 0x20078630, 0x20078631, 0x20078632, 0x20078633, + 0x21078434, 0x27853031, 0x85303121, 0x30312127, 0x31212785, 0x21278530, 0x27873031, 0x2f863520, 0x07863620, 0x07863720, 0x07863820, 0x07863920, + 0x07864120, 0x07864220, 0x07864320, 0x07864420, 0x07864520, 0x07854620, 0x86303121, 0x86312007, 0x207f8607, 0x207f8631, 0x207f8631, 0x207f8631, + 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x207f8631, 0x217f8631, 0x77853032, 0x86313221, + 0x207f8607, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, 0x207f8632, + 0x207f8632, 0x217f8632, 0x77853033, 0x86313321, 0x207f8607, 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, + 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, 0x207f8633, 0x217f8633, 0x77853034, 0x00313428, 0xff010000, 0xcd4400ff, 0x00002607, 0x0014000c, + 0x24158204, 0x00000002, 0x85038601, 0xe0002409, 0x82206855, 0xe0002c11, 0x009ffffd, 0xe1000000, 0x05c9dc04, 0xc4a023fa, 0x00000091, }; diff --git a/src/gui/furIcons.h b/src/gui/furIcons.h index ea4477f7a..ad16aba69 100644 --- a/src/gui/furIcons.h +++ b/src/gui/furIcons.h @@ -1,7 +1,7 @@ // not auto-generated. update every time you change icons.ttf! #define ICON_MIN_FUR 0xe0f0 -#define ICON_MAX_FUR 0xe141 +#define ICON_MAX_FUR 0xe142 // test #define ICON_FUR_TEST0 u8"\ue0f0" @@ -65,6 +65,7 @@ #define ICON_FUR_INS_SCSP u8"\ue133" #define ICON_FUR_INS_TED u8"\ue134" #define ICON_FUR_INS_C140 u8"\ue135" +#define ICON_FUR_INS_C219 u8"\ue142" // sample editor #define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136" @@ -78,4 +79,4 @@ #define ICON_FUR_SAMPLE_RESIZE u8"\ue13e" #define ICON_FUR_SAMPLE_REVERSE u8"\ue13f" #define ICON_FUR_SAMPLE_SIGN u8"\ue140" -#define ICON_FUR_SAMPLE_TRIM u8"\ue141" \ No newline at end of file +#define ICON_FUR_SAMPLE_TRIM u8"\ue141" diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 3369381de..1053f202a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2115,6 +2115,7 @@ int FurnaceGUI::save(String path, int dmfVersion) { showWarning(e->getWarnings(),GUI_WARN_GENERIC); } pushRecentFile(path); + pushRecentSys(path.c_str()); logD("save complete."); return 0; } @@ -2222,6 +2223,13 @@ void FurnaceGUI::pushRecentFile(String path) { } } +void FurnaceGUI::pushRecentSys(const char* path) { +#ifdef _WIN32 + WString widePath=utf8To16(path); + SHAddToRecentDocs(SHARD_PATHW,widePath.c_str()); +#endif +} + void FurnaceGUI::delFirstBackup(String name) { std::vector listOfFiles; #ifdef _WIN32 @@ -3512,10 +3520,12 @@ bool FurnaceGUI::loop() { case SDL_DISPLAYEVENT_CONNECTED: logD("display %d connected!",ev.display.display); updateWindow=true; + shallDetectScale=16; break; case SDL_DISPLAYEVENT_DISCONNECTED: logD("display %d disconnected!",ev.display.display); updateWindow=true; + shallDetectScale=16; break; case SDL_DISPLAYEVENT_ORIENTATION: logD("display oriented to %d",ev.display.data1); @@ -4819,29 +4829,39 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_INS_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { - e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song); + if (e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song)) { + pushRecentSys(copyOfName.c_str()); + } } 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())) { showError("error while saving instrument! make sure your instrument is compatible."); + } else { + pushRecentSys(copyOfName.c_str()); } } break; case GUI_FILE_WAVE_SAVE: if (curWave>=0 && curWave<(int)e->song.wave.size()) { - e->song.wave[curWave]->save(copyOfName.c_str()); + if (e->song.wave[curWave]->save(copyOfName.c_str())) { + pushRecentSys(copyOfName.c_str()); + } } break; case GUI_FILE_WAVE_SAVE_DMW: if (curWave>=0 && curWave<(int)e->song.wave.size()) { - e->song.wave[curWave]->saveDMW(copyOfName.c_str()); + if (e->song.wave[curWave]->saveDMW(copyOfName.c_str())) { + pushRecentSys(copyOfName.c_str()); + } } break; case GUI_FILE_WAVE_SAVE_RAW: if (curWave>=0 && curWave<(int)e->song.wave.size()) { - e->song.wave[curWave]->saveRaw(copyOfName.c_str()); + if (e->song.wave[curWave]->saveRaw(copyOfName.c_str())) { + pushRecentSys(copyOfName.c_str()); + } } break; case GUI_FILE_SAMPLE_OPEN: { @@ -4905,6 +4925,8 @@ bool FurnaceGUI::loop() { if (curSample>=0 && curSample<(int)e->song.sample.size()) { if (!e->song.sample[curSample]->save(copyOfName.c_str())) { showError("could not save sample! open Log Viewer for more information."); + } else { + pushRecentSys(copyOfName.c_str()); } } break; @@ -4912,6 +4934,8 @@ bool FurnaceGUI::loop() { if (curSample>=0 && curSample<(int)e->song.sample.size()) { if (!e->song.sample[curSample]->saveRaw(copyOfName.c_str())) { showError("could not save sample! open Log Viewer for more information."); + } else { + pushRecentSys(copyOfName.c_str()); } } break; @@ -5061,6 +5085,7 @@ bool FurnaceGUI::loop() { if (f!=NULL) { fwrite(w->getFinalBuf(),1,w->size(),f); fclose(f); + pushRecentSys(copyOfName.c_str()); } else { showError("could not open file!"); } @@ -5081,6 +5106,7 @@ bool FurnaceGUI::loop() { if (f!=NULL) { fwrite(w->getFinalBuf(),1,w->size(),f); fclose(f); + pushRecentSys(copyOfName.c_str()); } else { showError("could not open file!"); } @@ -5107,6 +5133,7 @@ bool FurnaceGUI::loop() { if (f!=NULL) { fwrite(w->getFinalBuf(),1,w->size(),f); fclose(f); + pushRecentSys(copyOfName.c_str()); } else { showError("could not open file!"); } @@ -5262,6 +5289,7 @@ bool FurnaceGUI::loop() { } } if (!e->isExporting()) { + e->finishAudioFile(); ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -5766,23 +5794,45 @@ bool FurnaceGUI::loop() { pendingRawSampleBigEndian=false; } - ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Channels"); - ImGui::SameLine(); - if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) { + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_8BIT || pendingRawSampleDepth==DIV_SAMPLE_DEPTH_16BIT) { + ImGui::AlignTextToFramePadding(); + ImGui::Text("Channels"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); + if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) { + } + ImGui::Text("(will be mixed down to mono)"); + ImGui::Checkbox("Unsigned",&pendingRawSampleUnsigned); } - ImGui::Text("(will be mixed down to mono)"); - ImGui::Checkbox("Unsigned",&pendingRawSampleUnsigned); - ImGui::EndDisabled(); - ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT); - ImGui::Checkbox("Big endian",&pendingRawSampleBigEndian); - ImGui::EndDisabled(); + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_16BIT) { + ImGui::Checkbox("Big endian",&pendingRawSampleBigEndian); + } - ImGui::BeginDisabled(pendingRawSampleDepth==DIV_SAMPLE_DEPTH_16BIT); - ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles); - ImGui::EndDisabled(); + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_YMZ_ADPCM || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_QSOUND_ADPCM || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_ADPCM_A || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_ADPCM_B || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_VOX) { + ImGui::Checkbox("Swap nibbles",&pendingRawSampleSwapNibbles); + } + + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_MULAW) { + ImGui::Text("Encoding:"); + ImGui::Indent(); + if (ImGui::RadioButton("G.711",pendingRawSampleSwapNibbles==0)) { + pendingRawSampleSwapNibbles=0; + } + if (ImGui::RadioButton("Namco",pendingRawSampleSwapNibbles==1)) { + pendingRawSampleSwapNibbles=1; + } + ImGui::Unindent(); + } + + if (pendingRawSampleDepth==DIV_SAMPLE_DEPTH_1BIT || + pendingRawSampleDepth==DIV_SAMPLE_DEPTH_1BIT_DPCM) { + ImGui::Checkbox("Reverse bit order",&pendingRawSampleSwapNibbles); + } if (ImGui::Button("OK")) { DivSample* s=e->sampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian,pendingRawSampleUnsigned,pendingRawSampleSwapNibbles); @@ -6067,6 +6117,14 @@ bool FurnaceGUI::loop() { willCommit=false; } + if (shallDetectScale) { + if (--shallDetectScale<1) { + if (settings.dpiScale<0.5f) { + applyUISettings(); + } + } + } + if (fontsFailed) { showError("it appears I couldn't load these fonts. any setting you can check?"); logE("couldn't load fonts"); @@ -6840,6 +6898,8 @@ FurnaceGUI::FurnaceGUI(): waveEditStyle(0), displayInsTypeListMakeInsSample(-1), mobileEditPage(0), + wheelCalmDown(0), + shallDetectScale(0), mobileMenuPos(0.0f), autoButtonSize(0.0f), mobileEditAnim(0.0f), @@ -6850,6 +6910,11 @@ FurnaceGUI::FurnaceGUI(): fmPreviewOn(false), fmPreviewPaused(false), fmPreviewOPN(NULL), + fmPreviewOPM(NULL), + fmPreviewOPL(NULL), + fmPreviewOPLL(NULL), + fmPreviewOPZ(NULL), + fmPreviewOPZInterface(NULL), editString(NULL), pendingRawSampleDepth(8), pendingRawSampleChannels(1), diff --git a/src/gui/gui.h b/src/gui/gui.h index c722bf14f..6b22a2d96 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -259,6 +259,7 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_SCSP, GUI_COLOR_INSTR_TED, GUI_COLOR_INSTR_C140, + GUI_COLOR_INSTR_C219, GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_CHANNEL_BG, @@ -1342,6 +1343,8 @@ class FurnaceGUI { int waveEditStyle; int displayInsTypeListMakeInsSample; int mobileEditPage; + int wheelCalmDown; + int shallDetectScale; float mobileMenuPos, autoButtonSize, mobileEditAnim; ImVec2 mobileEditButtonPos, mobileEditButtonSize; const int* curSysSection; @@ -1349,6 +1352,11 @@ class FurnaceGUI { short fmPreview[FM_PREVIEW_SIZE]; bool updateFMPreview, fmPreviewOn, fmPreviewPaused; void* fmPreviewOPN; + void* fmPreviewOPM; + void* fmPreviewOPL; + void* fmPreviewOPLL; + void* fmPreviewOPZ; + void* fmPreviewOPZInterface; String* editString; String pendingRawSample; @@ -1419,6 +1427,14 @@ class FurnaceGUI { int c64Core; int pokeyCore; int opnCore; + int arcadeCoreRender; + int ym2612CoreRender; + int snCoreRender; + int nesCoreRender; + int fdsCoreRender; + int c64CoreRender; + int pokeyCoreRender; + int opnCoreRender; int pcSpeakerOutMethod; String yrw801Path; String tg100Path; @@ -1587,6 +1603,14 @@ class FurnaceGUI { c64Core(0), pokeyCore(1), opnCore(1), + arcadeCoreRender(1), + ym2612CoreRender(0), + snCoreRender(0), + nesCoreRender(0), + fdsCoreRender(1), + c64CoreRender(1), + pokeyCoreRender(1), + opnCoreRender(1), pcSpeakerOutMethod(0), yrw801Path(""), tg100Path(""), @@ -2119,9 +2143,14 @@ class FurnaceGUI { void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, float maxRr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); bool drawSysConf(int chan, DivSystem type, DivConfig& flags, bool modifyOnChange, bool fromMenu=false); - void kvsConfig(DivInstrument* ins); + void kvsConfig(DivInstrument* ins, bool supportsKVS=true); void drawFMPreview(const ImVec2& size); - void renderFMPreview(const DivInstrumentFM& params, int pos=0); + void renderFMPreview(const DivInstrument* ins, int pos=0); + void renderFMPreviewOPN(const DivInstrumentFM& params, int pos=0); + void renderFMPreviewOPM(const DivInstrumentFM& params, int pos=0); + void renderFMPreviewOPLL(const DivInstrumentFM& params, int pos=0); + void renderFMPreviewOPL(const DivInstrumentFM& params, int pos=0); + void renderFMPreviewOPZ(const DivInstrumentFM& params, int pos=0); // these ones offer ctrl-wheel fine value changes. bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0); @@ -2315,6 +2344,7 @@ class FurnaceGUI { int load(String path); int loadStream(String path); void pushRecentFile(String path); + void pushRecentSys(const char* path); void exportAudio(String path, DivAudioExportModes mode); void delFirstBackup(String name); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index bc9f5ff77..4b863d33c 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -174,6 +174,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={ {"SCSP",ICON_FA_QUESTION,ICON_FUR_INS_SCSP}, {"TED",ICON_FA_BAR_CHART,ICON_FUR_INS_TED}, {"C140",ICON_FA_VOLUME_UP,ICON_FUR_INS_C140}, + {"C219",ICON_FA_VOLUME_UP,ICON_FUR_INS_C219}, {NULL,ICON_FA_QUESTION,ICON_FA_QUESTION} }; @@ -939,6 +940,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_SCSP,"",ImVec4(0.5f,0.5f,0.5f,1.0f)), D(GUI_COLOR_INSTR_TED,"",ImVec4(0.7f,0.6f,1.0f,1.0f)), D(GUI_COLOR_INSTR_C140,"",ImVec4(1.0f,1.0f,0.0f,1.0f)), + D(GUI_COLOR_INSTR_C219,"",ImVec4(1.0f,0.8f,0.0f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), @@ -1125,6 +1127,7 @@ const int availableSystems[]={ DIV_SYSTEM_K053260, DIV_SYSTEM_TED, DIV_SYSTEM_C140, + DIV_SYSTEM_C219, DIV_SYSTEM_PCM_DAC, DIV_SYSTEM_PONG, 0 // don't remove this last one! @@ -1236,6 +1239,7 @@ const int chipsSample[]={ DIV_SYSTEM_ES5506, DIV_SYSTEM_K053260, DIV_SYSTEM_C140, + DIV_SYSTEM_C219, 0 // don't remove this last one! }; @@ -1263,4 +1267,4 @@ const char* chipCategoryNames[]={ const char* insIcons[]={ ICON_FA_AREA_CHART, -}; \ No newline at end of file +}; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index e6056d036..98d02e3a2 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -19,6 +19,7 @@ #define _USE_MATH_DEFINES #include "gui.h" +#include "../ta-log.h" #include "imgui_internal.h" #include "../engine/macroInt.h" #include "IconsFontAwesome4.h" @@ -1283,8 +1284,8 @@ inline bool enBit30(const int val) { } -void FurnaceGUI::kvsConfig(DivInstrument* ins) { - if (ins->type==DIV_INS_FM && fmPreviewOn) { +void FurnaceGUI::kvsConfig(DivInstrument* ins, bool supportsKVS) { + if (fmPreviewOn) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("left click to restart\nmiddle click to pause\nright click to see algorithm"); } @@ -1294,15 +1295,23 @@ void FurnaceGUI::kvsConfig(DivInstrument* ins) { if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { fmPreviewPaused=!fmPreviewPaused; } - } else { + } else if (supportsKVS) { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("left click to configure TL scaling\nright click to see FM preview"); } + } else { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("right click to see FM preview"); + } } - if (ImGui::IsItemClicked(ImGuiMouseButton_Right) && ins->type==DIV_INS_FM) { + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { fmPreviewOn=!fmPreviewOn; } - if (!fmPreviewOn || ins->type!=DIV_INS_FM) { + if (ImGui::IsItemHovered() && CHECK_LONG_HOLD) { + NOTIFY_LONG_HOLD; + fmPreviewOn=!fmPreviewOn; + } + if (!fmPreviewOn && supportsKVS) { int opCount=4; if (ins->type==DIV_INS_OPLL) opCount=2; if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; @@ -1568,6 +1577,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Bottom"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1590,6 +1600,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Attack"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1609,6 +1620,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Hold"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1628,6 +1640,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Decay"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1650,6 +1663,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextColumn(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Release"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1671,6 +1685,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Bottom"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1693,6 +1708,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Speed"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1711,6 +1727,7 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail } rightClickable ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); ImGui::Text("Shape"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -1750,8 +1767,12 @@ void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float avail \ /* if ADSR/LFO, populate min/max */ \ if (i.macro->open&6) { \ - i.macro->val[0]=i.min; \ - i.macro->val[1]=i.max; \ + if (i.macro->val[0]==0 && i.macro->val[1]==0) { \ + i.macro->val[0]=i.min; \ + i.macro->val[1]=i.max; \ + } \ + i.macro->val[0]=CLAMP(i.macro->val[0],i.min,i.max); \ + i.macro->val[1]=CLAMP(i.macro->val[1],i.min,i.max); \ } \ } \ PARAMETER; \ @@ -2281,7 +2302,7 @@ void FurnaceGUI::drawInsEdit() { } else { DivInstrument* ins=e->song.ins[curIns]; if (updateFMPreview) { - renderFMPreview(ins->fm); + renderFMPreview(ins); updateFMPreview=false; } if (settings.insEditColorize) { @@ -2469,10 +2490,10 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); - if (ins->type==DIV_INS_FM && fmPreviewOn) { + if (fmPreviewOn) { drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); if (!fmPreviewPaused) { - renderFMPreview(ins->fm,1); + renderFMPreview(ins,1); WAKE_UP; } } else { @@ -2490,7 +2511,15 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); - drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + if (fmPreviewOn) { + drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + if (!fmPreviewPaused) { + renderFMPreview(ins,1); + WAKE_UP; + } + } else { + drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + } kvsConfig(ins); if (ImGui::Button("Request from TX81Z")) { @@ -2524,7 +2553,15 @@ void FurnaceGUI::drawInsEdit() { } } ImGui::TableNextColumn(); - drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + if (fmPreviewOn) { + drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + if (!fmPreviewPaused) { + renderFMPreview(ins,1); + WAKE_UP; + } + } else { + drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + } kvsConfig(ins); break; } @@ -2549,7 +2586,16 @@ void FurnaceGUI::drawInsEdit() { } ImGui::EndDisabled(); ImGui::TableNextColumn(); - drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + if (fmPreviewOn) { + drawFMPreview(ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + if (!fmPreviewPaused) { + renderFMPreview(ins,1); + WAKE_UP; + } + } else { + drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + } + kvsConfig(ins,false); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -5120,10 +5166,9 @@ void FurnaceGUI::drawInsEdit() { ins->snes.sus=3; } } else { - if (ImGui::BeginTable("SNESGainParams",3,ImGuiTableFlags_NoHostExtendX)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + if (ImGui::BeginTable("SNESGainParams",2,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -5132,9 +5177,6 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextColumn(); CENTER_TEXT("Gain"); ImGui::TextUnformatted("Gain"); - ImGui::TableNextColumn(); - CENTER_TEXT("Envelope"); - ImGui::TextUnformatted("Envelope"); ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -5164,11 +5206,11 @@ void FurnaceGUI::drawInsEdit() { if (ins->snes.gain>gainMax) ins->snes.gain=gainMax; P(CWVSliderScalar("##Gain",sliderSize,ImGuiDataType_U8,&ins->snes.gain,&_ZERO,&gainMax)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("Envelope goes here..."); - ImGui::EndTable(); } + if (ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LINEAR || ins->snes.gainMode==DivInstrumentSNES::GAIN_MODE_DEC_LOG) { + ImGui::TextWrapped("using decrease modes will not produce any sound at all, unless you know what you are doing.\nit is recommended to use the Gain macro for decrease instead."); + } } ImGui::EndTabItem(); } @@ -5233,180 +5275,205 @@ void FurnaceGUI::drawInsEdit() { if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) { wavePreviewInit=true; } - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ins->ws.effect&0x80) { - if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) { - ins->ws.effect=0; + if (ins->ws.enabled) { + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ins->ws.effect&0x80) { + if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) { + ins->ws.effect=0; + wavePreviewInit=true; + } + } else { + if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) { + ins->ws.effect=0; + wavePreviewInit=true; + } + } + if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) { + ImGui::Text("Single-waveform"); + ImGui::Indent(); + for (int i=0; iws.effect=i; + wavePreviewInit=true; + } + } + ImGui::Unindent(); + ImGui::Text("Dual-waveform"); + ImGui::Indent(); + for (int i=129; iws.effect=i; + wavePreviewInit=true; + } + } + ImGui::Unindent(); + ImGui::EndCombo(); + } + const bool isSingleWaveFX=(ins->ws.effect>=128); + if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) { + DivWavetable* wave1=e->getWave(ins->ws.wave1); + DivWavetable* wave2=e->getWave(ins->ws.wave2); + if (wavePreviewInit) { + wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true); + wavePreviewInit=false; + } + float wavePreview1[257]; + float wavePreview2[257]; + float wavePreview3[257]; + for (int i=0; ilen; i++) { + if (wave1->data[i]>wave1->max) { + wavePreview1[i]=wave1->max; + } else { + wavePreview1[i]=wave1->data[i]; + } + } + if (wave1->len>0) { + wavePreview1[wave1->len]=wave1->data[wave1->len-1]; + } + for (int i=0; ilen; i++) { + if (wave2->data[i]>wave2->max) { + wavePreview2[i]=wave2->max; + } else { + wavePreview2[i]=wave2->data[i]; + } + } + if (wave2->len>0) { + wavePreview2[wave2->len]=wave2->data[wave2->len-1]; + } + if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) { + wavePreview.tick(true); + WAKE_UP; + } + for (int i=0; i0) { + wavePreview3[wavePreviewLen]=wavePreview3[wavePreviewLen-1]; + } + + float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale; + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize); + PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1); + if (isSingleWaveFX) { + ImGui::TableNextColumn(); + ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize); + PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2); + } + ImGui::TableNextColumn(); + ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize); + PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen+1,0,"Result",0,wavePreviewHeight,size3); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ins->std.waveMacro.len>0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Wave 1 " ICON_FA_EXCLAMATION_TRIANGLE); + ImGui::PopStyleColor(); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("waveform macro is controlling wave 1!\nthis value will be ineffective."); + } + } else { + ImGui::AlignTextToFramePadding(); + ImGui::Text("Wave 1"); + } + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) { + if (ins->ws.wave1<0) ins->ws.wave1=0; + if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1; + wavePreviewInit=true; + } + if (ins->std.waveMacro.len>0) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("waveform macro is controlling wave 1!\nthis value will be ineffective."); + } + } + if (isSingleWaveFX) { + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Wave 2"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) { + if (ins->ws.wave2<0) ins->ws.wave2=0; + if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1; + wavePreviewInit=true; + } + } + ImGui::TableNextColumn(); + if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) { + wavePreviewPaused=!wavePreviewPaused; + } + if (ImGui::IsItemHovered()) { + if (wavePreviewPaused) { + ImGui::SetTooltip("Resume preview"); + } else { + ImGui::SetTooltip("Pause preview"); + } + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) { + wavePreviewInit=true; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Restart preview"); + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) { + curWave=e->addWave(); + if (curWave==-1) { + showError("too many wavetables!"); + } else { + wantScrollList=true; + MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; + nextWindow=GUI_WINDOW_WAVE_EDIT; + + DivWavetable* copyWave=e->song.wave[curWave]; + copyWave->len=wavePreviewLen; + copyWave->max=wavePreviewHeight; + memcpy(copyWave->data,wavePreview.output,256*sizeof(int)); + } + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Copy to new wavetable"); + } + ImGui::SameLine(); + ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1); + ImGui::EndTable(); + } + + if (ImGui::InputScalar("Update Rate",ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_SEVEN)) { + wavePreviewInit=true; + } + int speed=ins->ws.speed+1; + if (ImGui::InputInt("Speed",&speed,1,16)) { + if (speed<1) speed=1; + if (speed>256) speed=256; + ins->ws.speed=speed-1; + wavePreviewInit=true; + } + + if (ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN)) { + wavePreviewInit=true; + } + + if (ins->ws.effect==DIV_WS_PHASE_MOD) { + if (ImGui::InputScalar("Power",ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_SEVEN)) { + wavePreviewInit=true; + } + } + + if (ImGui::Checkbox("Global",&ins->ws.global)) { wavePreviewInit=true; } } else { - if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) { - ins->ws.effect=0; - wavePreviewInit=true; - } - } - if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) { - ImGui::Text("Single-waveform"); - ImGui::Indent(); - for (int i=0; iws.effect=i; - wavePreviewInit=true; - } - } - ImGui::Unindent(); - ImGui::Text("Dual-waveform"); - ImGui::Indent(); - for (int i=129; iws.effect=i; - wavePreviewInit=true; - } - } - ImGui::Unindent(); - ImGui::EndCombo(); - } - const bool isSingleWaveFX=(ins->ws.effect>=128); - if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) { - DivWavetable* wave1=e->getWave(ins->ws.wave1); - DivWavetable* wave2=e->getWave(ins->ws.wave2); - if (wavePreviewInit) { - wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true); - wavePreviewInit=false; - } - float wavePreview1[256]; - float wavePreview2[256]; - float wavePreview3[256]; - for (int i=0; ilen; i++) { - if (wave1->data[i]>wave1->max) { - wavePreview1[i]=wave1->max; - } else { - wavePreview1[i]=wave1->data[i]; - } - } - for (int i=0; ilen; i++) { - if (wave2->data[i]>wave2->max) { - wavePreview2[i]=wave2->max; - } else { - wavePreview2[i]=wave2->data[i]; - } - } - if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) { - wavePreview.tick(true); - } - for (int i=0; idata[i]>wavePreviewHeight) { - wavePreview3[i]=wavePreviewHeight; - } else { - wavePreview3[i]=wavePreview.output[i]; - } - } - - float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale; - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize); - PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1); - if (isSingleWaveFX) { - ImGui::TableNextColumn(); - ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize); - PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2); - } - ImGui::TableNextColumn(); - ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize); - PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen,0,"Result",0,wavePreviewHeight,size3); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Wave 1"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) { - if (ins->ws.wave1<0) ins->ws.wave1=0; - if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1; - wavePreviewInit=true; - } - if (isSingleWaveFX) { - ImGui::TableNextColumn(); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Wave 2"); - ImGui::SameLine(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) { - if (ins->ws.wave2<0) ins->ws.wave2=0; - if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1; - wavePreviewInit=true; - } - } - ImGui::TableNextColumn(); - if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) { - wavePreviewPaused=!wavePreviewPaused; - } - if (ImGui::IsItemHovered()) { - if (wavePreviewPaused) { - ImGui::SetTooltip("Resume preview"); - } else { - ImGui::SetTooltip("Pause preview"); - } - } - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) { - wavePreviewInit=true; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Restart preview"); - } - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) { - curWave=e->addWave(); - if (curWave==-1) { - showError("too many wavetables!"); - } else { - wantScrollList=true; - MARK_MODIFIED; - RESET_WAVE_MACRO_ZOOM; - nextWindow=GUI_WINDOW_WAVE_EDIT; - - DivWavetable* copyWave=e->song.wave[curWave]; - copyWave->len=wavePreviewLen; - copyWave->max=wavePreviewHeight; - memcpy(copyWave->data,wavePreview.output,256*sizeof(int)); - } - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Copy to new wavetable"); - } - ImGui::SameLine(); - ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1); - ImGui::EndTable(); - } - - if (ImGui::InputScalar("Update Rate",ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_SEVEN)) { - wavePreviewInit=true; - } - int speed=ins->ws.speed+1; - if (ImGui::InputInt("Speed",&speed,1,16)) { - if (speed<1) speed=1; - if (speed>256) speed=256; - ins->ws.speed=speed-1; - wavePreviewInit=true; - } - - if (ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN)) { - wavePreviewInit=true; - } - - if (ins->ws.effect==DIV_WS_PHASE_MOD) { - if (ImGui::InputScalar("Power",ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_SEVEN)) { - wavePreviewInit=true; - } - } - - if (ImGui::Checkbox("Global",&ins->ws.global)) { - wavePreviewInit=true; + ImGui::TextWrapped("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument."); } ImGui::EndTabItem(); @@ -5636,6 +5703,7 @@ void FurnaceGUI::drawInsEdit() { 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_BEEPER) waveMax=0; if (ins->type==DIV_INS_POKEMINI) waveMax=0; if (ins->type==DIV_INS_TED) waveMax=0; if (ins->type==DIV_INS_C140) waveMax=0; diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index a1ba6336f..6c84c8d76 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -437,7 +437,7 @@ void FurnaceGUI::drawPattern() { ImGui::SetCursorPosX(ImGui::GetCursorPosX()+centerOff); } } - if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea|(settings.cursorFollowsWheel?ImGuiTableFlags_NoScrollWithMouse:0))) { + if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea|((settings.cursorFollowsWheel || wheelCalmDown)?ImGuiTableFlags_NoScrollWithMouse:0))) { ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed); char chanID[2048]; float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale); @@ -800,13 +800,14 @@ void FurnaceGUI::drawPattern() { if (e->isRunning()) { DivChannelState* cs=e->getChanState(i); - float stereoPan=(float)(e->convertPanSplitToLinearLR(cs->panL,cs->panR,256)-128)/128.0; + unsigned short chanPan=e->getChanPan(i); + float stereoPan=(float)(e->convertPanSplitToLinear(chanPan,8,256)-128)/128.0; switch (settings.channelVolStyle) { case 1: // simple - xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); + xRight=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); break; case 2: { // stereo - float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + float amount=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); xRight=0.5+amount*(1.0+MIN(0.0,stereoPan)); xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan)); break; @@ -950,13 +951,13 @@ void FurnaceGUI::drawPattern() { // cursor follows wheel if (settings.cursorFollowsWheel && (!e->isPlaying() || !followPattern) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) { if (wheelX!=0 || wheelY!=0) { - moveCursor(wheelX,wheelY,false); + moveCursor(wheelX,(settings.cursorFollowsWheel==2)?wheelY:-wheelY,false); } } // overflow changes order - // TODO: this is very unreliable and sometimes it can warp you out of the song - if (settings.scrollChangesOrder && (!e->isPlaying() || !followPattern) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !settings.cursorFollowsWheel) { + if (--wheelCalmDown<0) wheelCalmDown=0; + if (settings.scrollChangesOrder && (!e->isPlaying() || !followPattern) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows) && !settings.cursorFollowsWheel && !wheelCalmDown) { if (wheelY!=0) { if (wheelY>0) { if (ImGui::GetScrollY()<=0) { @@ -965,10 +966,12 @@ void FurnaceGUI::drawPattern() { setOrder(curOrder-1); ImGui::SetScrollY(ImGui::GetScrollMaxY()); updateScroll(e->curSubSong->patLen); + wheelCalmDown=2; } else if (settings.scrollChangesOrder==2) { setOrder(e->curSubSong->ordersLen-1); ImGui::SetScrollY(ImGui::GetScrollMaxY()); updateScroll(e->curSubSong->patLen); + wheelCalmDown=2; } haveHitBounds=false; } else { @@ -984,10 +987,12 @@ void FurnaceGUI::drawPattern() { setOrder(curOrder+1); ImGui::SetScrollY(0); updateScroll(0); + wheelCalmDown=2; } else if (settings.scrollChangesOrder==2) { setOrder(0); ImGui::SetScrollY(0); updateScroll(0); + wheelCalmDown=2; } haveHitBounds=false; } else { diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 74a10e9b1..02d0aed58 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -293,6 +293,9 @@ void FurnaceGUI::drawSampleEdit() { if (sample->samples>131070) { SAMPLE_WARN(warnLength,"Amiga: maximum sample length is 131070"); } + if (dispatch!=NULL) { + MAX_RATE("Amiga",31250.0); + } break; case DIV_SYSTEM_SEGAPCM: case DIV_SYSTEM_SEGAPCM_COMPAT: @@ -785,7 +788,7 @@ void FurnaceGUI::drawSampleEdit() { sameLineMaybe(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); sameLineMaybe(); - ImGui::Button(ICON_FA_ARROWS_H "##SResize"); + ImGui::Button(ICON_FUR_SAMPLE_RESIZE "##SResize"); if (ImGui::IsItemClicked()) { resizeSize=sample->samples; } @@ -820,7 +823,7 @@ void FurnaceGUI::drawSampleEdit() { resizeSize=sample->samples; } sameLineMaybe(); - ImGui::Button(ICON_FA_EXPAND "##SResample"); + ImGui::Button(ICON_FUR_SAMPLE_RESAMPLE "##SResample"); if (ImGui::IsItemClicked()) { resampleTarget=targetRate; } @@ -962,7 +965,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SetTooltip("Fade out"); } sameLineMaybe(); - ImGui::Button(ICON_FA_ADJUST "##SInsertSilence"); + ImGui::Button(ICON_FUR_SAMPLE_INSERT_SILENCE "##SInsertSilence"); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Insert silence"); } @@ -1016,14 +1019,14 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); sameLineMaybe(); - if (ImGui::Button(ICON_FA_BACKWARD "##SReverse")) { + if (ImGui::Button(ICON_FUR_SAMPLE_REVERSE "##SReverse")) { doAction(GUI_ACTION_SAMPLE_REVERSE); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Reverse"); } sameLineMaybe(); - if (ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert")) { + if (ImGui::Button(ICON_FUR_SAMPLE_INVERT "##SInvert")) { doAction(GUI_ACTION_SAMPLE_INVERT); } if (ImGui::IsItemHovered()) { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 8b7348b09..348671bb7 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -29,6 +29,7 @@ #include "IconsFontAwesome4.h" #include "furIcons.h" #include "misc/cpp/imgui_stdlib.h" +#include "scaling.h" #include #include @@ -1189,46 +1190,113 @@ void FurnaceGUI::drawSettings() { CONFIG_SECTION("Emulation") { // SUBSECTION LAYOUT CONFIG_SUBSECTION("Cores"); - ImGui::AlignTextToFramePadding(); - ImGui::Text("Arcade/YM2151 core"); - ImGui::SameLine(); - ImGui::Combo("##ArcadeCore",&settings.arcadeCore,arcadeCores,2); + if (ImGui::BeginTable("##Cores",3)) { + ImGui::TableSetupColumn("##System",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("##PlaybackCores",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("##RenderCores",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("System"); + ImGui::TableNextColumn(); + ImGui::Text("Playback Core(s)"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("used for playback"); + } + ImGui::TableNextColumn(); + ImGui::Text("Render Core(s)"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("used in audio export"); + } - ImGui::AlignTextToFramePadding(); - ImGui::Text("Genesis/YM2612 core"); - ImGui::SameLine(); - ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Arcade/YM2151"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ArcadeCore",&settings.arcadeCore,arcadeCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##ArcadeCoreRender",&settings.arcadeCoreRender,arcadeCores,2); - ImGui::AlignTextToFramePadding(); - ImGui::Text("SN76489 core"); - ImGui::SameLine(); - ImGui::Combo("##SNCore",&settings.snCore,snCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("Genesis/YM2612"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##YM2612CoreRender",&settings.ym2612CoreRender,ym2612Cores,2); - ImGui::AlignTextToFramePadding(); - ImGui::Text("NES core"); - ImGui::SameLine(); - ImGui::Combo("##NESCore",&settings.nesCore,nesCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("SN76489"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##SNCore",&settings.snCore,snCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##SNCoreRender",&settings.snCoreRender,snCores,2); - ImGui::AlignTextToFramePadding(); - ImGui::Text("FDS core"); - ImGui::SameLine(); - ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("NES"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NESCore",&settings.nesCore,nesCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##NESCoreRender",&settings.nesCoreRender,nesCores,2); - ImGui::AlignTextToFramePadding(); - ImGui::Text("SID core"); - ImGui::SameLine(); - ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,3); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("FDS"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##FDSCoreRender",&settings.fdsCoreRender,nesCores,2); - ImGui::AlignTextToFramePadding(); - ImGui::Text("POKEY core"); - ImGui::SameLine(); - ImGui::Combo("##POKEYCore",&settings.pokeyCore,pokeyCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("SID"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,3); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##C64CoreRender",&settings.c64CoreRender,c64Cores,3); - ImGui::AlignTextToFramePadding(); - ImGui::Text("OPN/OPNA/OPNB cores"); - ImGui::SameLine(); - ImGui::Combo("##OPNCore",&settings.opnCore,opnCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("POKEY"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##POKEYCore",&settings.pokeyCore,pokeyCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##POKEYCoreRender",&settings.pokeyCoreRender,pokeyCores,2); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("OPN/OPNA/OPNB"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##OPNCore",&settings.opnCore,opnCores,2); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::Combo("##OPNCoreRender",&settings.opnCoreRender,opnCores,2); + ImGui::EndTable(); + } ImGui::Separator(); ImGui::AlignTextToFramePadding(); @@ -1236,6 +1304,7 @@ void FurnaceGUI::drawSettings() { ImGui::SameLine(); ImGui::Combo("##PCSOutMethod",&settings.pcSpeakerOutMethod,pcspkrOutMethods,5); + /* ImGui::Separator(); ImGui::Text("Sample ROMs:"); @@ -1265,6 +1334,7 @@ void FurnaceGUI::drawSettings() { if (ImGui::Button(ICON_FA_FOLDER "##MU5Load")) { openFileDialog(GUI_FILE_MU5_ROM_OPEN); } + */ END_SECTION; } @@ -1905,10 +1975,18 @@ void FurnaceGUI::drawSettings() { settings.cursorMoveNoScroll=cursorMoveNoScrollB; } - bool cursorFollowsWheelB=settings.cursorFollowsWheel; - if (ImGui::Checkbox("Move cursor with scroll wheel",&cursorFollowsWheelB)) { - settings.cursorFollowsWheel=cursorFollowsWheelB; + ImGui::Text("Move cursor with scroll wheel:"); + ImGui::Indent(); + if (ImGui::RadioButton("No##csw0",settings.cursorFollowsWheel==0)) { + settings.cursorFollowsWheel=0; } + if (ImGui::RadioButton("Yes##csw1",settings.cursorFollowsWheel==1)) { + settings.cursorFollowsWheel=1; + } + if (ImGui::RadioButton("Inverted##csw2",settings.cursorFollowsWheel==2)) { + settings.cursorFollowsWheel=2; + } + ImGui::Unindent(); END_SECTION; } @@ -2938,6 +3016,14 @@ void FurnaceGUI::syncSettings() { settings.c64Core=e->getConfInt("c64Core",0); settings.pokeyCore=e->getConfInt("pokeyCore",1); settings.opnCore=e->getConfInt("opnCore",1); + settings.arcadeCoreRender=e->getConfInt("arcadeCoreRender",1); + settings.ym2612CoreRender=e->getConfInt("ym2612CoreRender",0); + settings.snCoreRender=e->getConfInt("snCoreRender",0); + settings.nesCoreRender=e->getConfInt("nesCoreRender",0); + settings.fdsCoreRender=e->getConfInt("fdsCoreRender",1); + settings.c64CoreRender=e->getConfInt("c64CoreRender",1); + settings.pokeyCoreRender=e->getConfInt("pokeyCoreRender",1); + settings.opnCoreRender=e->getConfInt("opnCoreRender",1); settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0); settings.yrw801Path=e->getConfString("yrw801Path",""); settings.tg100Path=e->getConfString("tg100Path",""); @@ -3098,6 +3184,14 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.c64Core,0,2); clampSetting(settings.pokeyCore,0,1); clampSetting(settings.opnCore,0,1); + clampSetting(settings.arcadeCoreRender,0,1); + clampSetting(settings.ym2612CoreRender,0,1); + clampSetting(settings.snCoreRender,0,1); + clampSetting(settings.nesCoreRender,0,1); + clampSetting(settings.fdsCoreRender,0,1); + clampSetting(settings.c64CoreRender,0,2); + clampSetting(settings.pokeyCoreRender,0,1); + clampSetting(settings.opnCoreRender,0,1); clampSetting(settings.pcSpeakerOutMethod,0,4); clampSetting(settings.mainFont,0,6); clampSetting(settings.patFont,0,6); @@ -3209,7 +3303,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.pullDeleteRow,0,1); clampSetting(settings.newSongBehavior,0,1); clampSetting(settings.memUsageUnit,0,1); - clampSetting(settings.cursorFollowsWheel,0,1); + clampSetting(settings.cursorFollowsWheel,0,2); clampSetting(settings.noDMFCompat,0,1); clampSetting(settings.removeInsOff,0,1); clampSetting(settings.removeVolOff,0,1); @@ -3287,7 +3381,15 @@ void FurnaceGUI::commitSettings() { settings.fdsCore!=e->getConfInt("fdsCore",0) || settings.c64Core!=e->getConfInt("c64Core",0) || settings.pokeyCore!=e->getConfInt("pokeyCore",1) || - settings.opnCore!=e->getConfInt("opnCore",1) + settings.opnCore!=e->getConfInt("opnCore",1) || + settings.arcadeCoreRender!=e->getConfInt("arcadeCoreRender",0) || + settings.ym2612CoreRender!=e->getConfInt("ym2612CoreRender",0) || + settings.snCoreRender!=e->getConfInt("snCoreRender",0) || + settings.nesCoreRender!=e->getConfInt("nesCoreRender",0) || + settings.fdsCoreRender!=e->getConfInt("fdsCoreRender",0) || + settings.c64CoreRender!=e->getConfInt("c64CoreRender",0) || + settings.pokeyCoreRender!=e->getConfInt("pokeyCoreRender",1) || + settings.opnCoreRender!=e->getConfInt("opnCoreRender",1) ); e->setConf("mainFontSize",settings.mainFontSize); @@ -3312,6 +3414,14 @@ void FurnaceGUI::commitSettings() { e->setConf("c64Core",settings.c64Core); e->setConf("pokeyCore",settings.pokeyCore); e->setConf("opnCore",settings.opnCore); + e->setConf("arcadeCoreRender",settings.arcadeCoreRender); + e->setConf("ym2612CoreRender",settings.ym2612CoreRender); + e->setConf("snCoreRender",settings.snCoreRender); + e->setConf("nesCoreRender",settings.nesCoreRender); + e->setConf("fdsCoreRender",settings.fdsCoreRender); + e->setConf("c64CoreRender",settings.c64CoreRender); + e->setConf("pokeyCoreRender",settings.pokeyCoreRender); + e->setConf("opnCoreRender",settings.opnCoreRender); e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod); e->setConf("yrw801Path",settings.yrw801Path); e->setConf("tg100Path",settings.tg100Path); @@ -3954,7 +4064,20 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { setupLabel(settings.emptyLabel.c_str(),emptyLabel,3); setupLabel(settings.emptyLabel2.c_str(),emptyLabel2,2); - if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale; + // get scale factor + const char* videoBackend=SDL_GetCurrentVideoDriver(); + if (settings.dpiScale>=0.5f) { + logD("setting UI scale factor from config (%f).",settings.dpiScale); + dpiScale=settings.dpiScale; + } else { + logD("auto-detecting UI scale factor."); + dpiScale=getScaleFactor(videoBackend); + logD("scale factor: %f",dpiScale); + if (dpiScale<0.1f) { + logW("scale what?"); + dpiScale=1.0f; + } + } // colors if (updateFonts) { @@ -4134,6 +4257,23 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImFontGlyphRangesBuilder range; ImVector outRange; + ImFontConfig fontConf; + ImFontConfig fontConfP; + ImFontConfig fontConfB; + ImFontConfig fontConfH; + + fontConf.OversampleV=1; + fontConf.OversampleH=2; + fontConfP.OversampleV=1; + fontConfP.OversampleH=2; + fontConfB.OversampleV=1; + fontConfB.OversampleH=1; + fontConfH.OversampleV=1; + fontConfH.OversampleH=1; + + //fontConf.RasterizerMultiply=1.5; + //fontConfP.RasterizerMultiply=1.5; + range.AddRanges(upTo800); if (settings.loadJapanese) { range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesJapanese()); @@ -4177,23 +4317,26 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImFontConfig fc1; fc1.MergeMode=true; + // save memory + fc1.OversampleH=1; + fc1.OversampleV=1; if (settings.mainFont==6) { // custom font - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { logW("could not load UI font! reverting to default font"); settings.mainFont=0; - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } } } else if (settings.mainFont==5) { // system font - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { logW("could not load UI font! reverting to default font"); settings.mainFont=0; - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } @@ -4201,7 +4344,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { } } } else { - if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),NULL,fontRange))==NULL) { + if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],MAX(1,e->getConfInt("mainFontSize",18)*dpiScale),&fontConf,fontRange))==NULL) { logE("could not load UI font! falling back to Proggy Clean."); mainFont=ImGui::GetIO().Fonts->AddFontDefault(); } @@ -4213,6 +4356,9 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImFontConfig fc; fc.MergeMode=true; + fc.OversampleH=1; + fc.OversampleV=1; + fc.PixelSnapH=true; fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale; static const ImWchar fontRangeIcon[]={ICON_MIN_FA,ICON_MAX_FA,0}; if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,MAX(1,e->getConfInt("iconSize",16)*dpiScale),&fc,fontRangeIcon))==NULL) { @@ -4229,21 +4375,21 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { patFont=mainFont; } else { if (settings.patFont==6) { // custom font - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { logW("could not load pattern font! reverting to default font"); settings.patFont=0; - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { logE("could not load pattern font! falling back to Proggy Clean."); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } } } else if (settings.patFont==5) { // system font - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { logW("could not load pattern font! reverting to default font"); settings.patFont=0; - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { logE("could not load pattern font! falling back to Proggy Clean."); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } @@ -4251,7 +4397,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { } } } else { - if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),NULL,upTo800))==NULL) { + if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],MAX(1,e->getConfInt("patFontSize",18)*dpiScale),&fontConfP,upTo800))==NULL) { logE("could not load pattern font!"); patFont=ImGui::GetIO().Fonts->AddFontDefault(); } @@ -4261,7 +4407,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { // 0x39B = Λ static const ImWchar bigFontRange[]={0x20,0xFF,0x39b,0x39b,0}; - if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,MAX(1,40*dpiScale),NULL,bigFontRange))==NULL) { + if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,MAX(1,40*dpiScale),&fontConfB,bigFontRange))==NULL) { logE("could not load big UI font!"); } @@ -4270,21 +4416,21 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { headFont=mainFont; } else { if (settings.headFont==6) { // custom font - if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.headFontPath.c_str(),MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.headFontPath.c_str(),MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { logW("could not load header font! reverting to default font"); settings.headFont=0; - if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { logE("could not load header font! falling back to IBM Plex Sans."); headFont=ImGui::GetIO().Fonts->AddFontDefault(); } } } else if (settings.headFont==5) { // system font - if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_1,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { - if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_2,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { - if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_3,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_1,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_2,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_HEAD_FONT_PATH_3,MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { logW("could not load header font! reverting to default font"); settings.headFont=0; - if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { logE("could not load header font! falling back to IBM Plex Sans."); headFont=ImGui::GetIO().Fonts->AddFontDefault(); } @@ -4292,7 +4438,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { } } } else { - if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),NULL,upTo800))==NULL) { + if ((headFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.headFont],builtinFontLen[settings.headFont],MAX(1,e->getConfInt("headFontSize",27)*dpiScale),&fontConfH,upTo800))==NULL) { logE("could not load header font!"); headFont=ImGui::GetIO().Fonts->AddFontDefault(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index d32e43aba..1609ca7b0 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -484,10 +484,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } break; } - case DIV_SYSTEM_NES: - case DIV_SYSTEM_VRC6: - case DIV_SYSTEM_FDS: - case DIV_SYSTEM_MMC5: { + case DIV_SYSTEM_NES: { int clockSel=flags.getInt("clockSel",0); bool dpcmMode=flags.getBool("dpcmMode",true); @@ -529,6 +526,35 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } break; } + case DIV_SYSTEM_VRC6: + case DIV_SYSTEM_FDS: + case DIV_SYSTEM_MMC5: { + int clockSel=flags.getInt("clockSel",0); + + ImGui::Text("Clock rate:"); + + ImGui::Indent(); + if (ImGui::RadioButton("NTSC (1.79MHz)",clockSel==0)) { + clockSel=0; + altered=true; + } + if (ImGui::RadioButton("PAL (1.67MHz)",clockSel==1)) { + clockSel=1; + altered=true; + } + if (ImGui::RadioButton("Dendy (1.77MHz)",clockSel==2)) { + clockSel=2; + altered=true; + } + ImGui::Unindent(); + + if (altered) { + e->lockSave([&]() { + flags.set("clockSel",clockSel); + }); + } + break; + } case DIV_SYSTEM_C64_8580: case DIV_SYSTEM_C64_6581: { int clockSel=flags.getInt("clockSel",0); diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index c1be89127..ea753205a 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -255,12 +255,6 @@ void FurnaceGUI::drawTutorial() { ImGui::Text("welcome to Furnace, the biggest open-source chiptune tracker!"); - ImGui::TextWrapped( - "did I say that 0.6pre5 will have a tutorial? well, it doesn't...\n" - "the reason is because 0.6pre5 fixes a critical bug which may cause config loss in some machines.\n" - "furthermore, it dramatically improves the backup system. couldn't put this version on hold anymore." - ); - ImGui::Separator(); ImGui::TextWrapped("here are some tips to get you started:"); @@ -280,7 +274,7 @@ void FurnaceGUI::drawTutorial() { ImGui::TextWrapped( "if you need help, you may:\n" "- read the (incomplete) manual: https://github.com/tildearrow/furnace/blob/master/doc/README.md\n" - "- ask for help in Discussions (https://github.com/tildearrow/furnace/discussions) or the Furnace Discord (https://discord.gg/EfrwT2wq7z)" + "- ask for help in Discussions (https://github.com/tildearrow/furnace/discussions), the Furnace Discord (https://discord.gg/EfrwT2wq7z) or Furnace in Revolt (https://rvlt.gg/GRPS6tmc)" ); ImGui::Separator(); diff --git a/src/gui/waveEdit.cpp b/src/gui/waveEdit.cpp index 3905b7614..de7cee606 100644 --- a/src/gui/waveEdit.cpp +++ b/src/gui/waveEdit.cpp @@ -1093,7 +1093,7 @@ void FurnaceGUI::drawWaveEdit() { MARK_MODIFIED; }); } - if (ImGui::Button("Invert",buttonSize)) { + if (ImGui::Button("Invert",buttonSizeHalf)) { e->lockEngine([this,wave]() { for (int i=0; ilen; i++) { wave->data[i]=wave->max-wave->data[i]; @@ -1101,6 +1101,18 @@ void FurnaceGUI::drawWaveEdit() { MARK_MODIFIED; }); } + ImGui::SameLine(); + if (ImGui::Button("Reverse",buttonSizeHalf)) { + e->lockEngine([this,wave]() { + int origData[256]; + memcpy(origData,wave->data,wave->len*sizeof(int)); + + for (int i=0; ilen; i++) { + wave->data[i]=origData[wave->len-1-i]; + } + MARK_MODIFIED; + }); + } if (ImGui::Button("Half",buttonSizeHalf)) { int origData[256]; diff --git a/src/log.cpp b/src/log.cpp index 9cfabe901..2fbf24dd3 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -97,7 +97,11 @@ int writeLog(int level, const char* msg, fmt::printf_args args) { time_t thisMakesNoSense=time(NULL); int pos=(logPosition.fetch_add(1))&TA_LOG_MASK; +#if FMT_VERSION >= 100100 + logEntries[pos].text.assign(fmt::vsprintf(fmt::basic_string_view(msg),args)); +#else logEntries[pos].text.assign(fmt::vsprintf(msg,args)); +#endif // why do I have to pass a pointer // can't I just pass the time_t directly?! #ifdef _WIN32 diff --git a/src/main.cpp b/src/main.cpp index 2c12678a9..dd0cc2bf2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -210,7 +210,7 @@ TAParamResult pVersion(String) { printf("- ASAP POKEY emulator by Piotr Fusik ported to C++ by laoo (GPLv2)\n"); printf("- SM8521 emulator (modified version) by cam900 (zlib license)\n"); printf("- D65010G031 emulator (modified version) by cam900 (zlib license)\n"); - printf("- C140 emulator (modified version) by cam900 (zlib license)\n"); + printf("- C140/C219 emulator (modified version) by cam900 (zlib license)\n"); return TA_PARAM_QUIT; } diff --git a/src/utfutils.cpp b/src/utfutils.cpp index 889b9a9bd..408a5e712 100644 --- a/src/utfutils.cpp +++ b/src/utfutils.cpp @@ -88,7 +88,14 @@ WString utf8To16(const char* s) { p=0; while (s[p]!=0) { ch=decodeUTF8((const unsigned char*)&s[p],chs); - ret+=(unsigned short)ch; + // surrogates + if (ch>=0x10000) { + ch-=0x10000; + ret+=(unsigned short)(0xd800|((ch>>10)&0x3ff)); + ret+=(unsigned short)(0xdc00|(ch&0x3ff)); + } else if (ch<0xd800 || ch>0xdfff) { + ret+=(unsigned short)ch; + } p+=chs; } return ret; @@ -96,16 +103,30 @@ WString utf8To16(const char* s) { String utf16To8(const wchar_t* s) { String ret; + unsigned int next=0; for (size_t i=0; i>6)&31)); - ret+=(0x80+((s[i])&63)); + if (s[i]>=0xd800 && s[i]<0xdc00) { + next=0x10000+((s[i]&0x3ff)<<10); + continue; + } else if (s[i]>=0xdc00 && s[i]<0xe000) { + next|=s[i]&0x3ff; } else { - ret+=(0xe0+((s[i]>>12)&15)); - ret+=(0x80+((s[i]>>6)&63)); - ret+=(0x80+((s[i])&63)); + next=s[i]; + } + if (next<0x80) { + ret+=next; + } else if (next<0x800) { + ret+=(0xc0+((next>>6)&31)); + ret+=(0x80+((next)&63)); + } else if (next<0x10000) { + ret+=(0xe0+((next>>12)&15)); + ret+=(0x80+((next>>6)&63)); + ret+=(0x80+((next)&63)); + } else { + ret+=(0xf0+((next>>18)&7)); + ret+=(0x80+((next>>12)&63)); + ret+=(0x80+((next>>6)&63)); + ret+=(0x80+((next)&63)); } } return ret;