Hello! It's been a hot minute since the last update to Keysight, but don't be misled in thinking development has slowed down. In fact, version 1.4 is taking a while because it's another large-scale overhaul to core systems in Keysight!
The beta branch now contains the first preview build of 1.4 for you to try. If interested, simply right click on Keysight in your library, navigate to Properties > Betas, and select "beta" from the dropdown.
You may want to wipe your save data and start fresh, to take advantage of new default presets and configuration. This can be done by typing "reset" into the console command field under System, and will instantly yeet all your Appdata for Keysight and reboot into the setup wizard.
Warning: the entire basic menu is offline pending a rework, and only the main Core/Effects/Scene menus have been fully reworked at this time. It's going to take me another good few weeks to finish up all other menus, but I really can't keep all the exciting new features to myself anymore!
Changes
I'll save my usual novella-length announcement for when this actually hits the live branch, but here's a quick overview of the key changes:
Pulses
Pulses have been completely reworked, on the scale of particles moving from version 1.2 to 1.3. Pulses now use 2-axis graphical editors for animations, have a nicely organised editing menu, can animate their position over time, and use sprite sheets as stencils. GIF support!
Note object meshes
All note object 3D meshes have been rebuilt for consistency in Z-height, width, and border proportions. In addition, the way note objects scale has been changed to be entirely "relative". So minimum-scale of 1.00 now gives the natural shape of that geometry style, and a height offset of 1.00 gives a note-depth's worth of vertical displacement
Menu
This beta contains about 50% of a full menu rework, with Advanced Core/Effects/Scene menus featuring universal use of new slider and graphical editor UI elements. Tooltips are everywhere now, if you don't understand what an option does, try hovering over the slider title or any associated text for a quick explanation!
Default presets and particle templates
I've been pretty obstinate with not investing a ton of time creating great default presets in the past. With three graphics presets, it ends up being a good amount of work to perfectly configure a theme 3 times... BUT. The observation that most users do not touch default settings has convinced me that a bigger default preset line-up is important. So: 13 default presets up from 4! And 13 particle templates up from 9. Preset configuration and randomizer behaviour in Low/Very low is also much improved over 1.3
Performance
Speaking of particle templates, several older templates have been updated to perform better as part of a general optimisation pass! Identical presets from 1.3 to 1.4 should perform about the same, but new default presets and usage of certain particle templates perform upwards of 2x better. All Standard graphics preset default presets perform at a GPU cap of around 120-180fps at 1080p under shift+Q turbo note testing mode on my 2060 Super. On a 16" 2019 Macbook Pro (AMD 5500M), this drops to 30-45, but the Low presets are all 100+fps!
Full changelog
[This preview does not contain reworks for the basic menu mode, the colour settings menu, or anything below Core/Effects/Scene. Use at your own risk]
--- OVERHAULS ---
Overhauled pulses! This is on the scale of the particle rework from 1.2 to 1.3, so it's difficult to summarise the changes. Quick feature list:
- Pulses can now use sprite sheets as stencils! These can be easily generated from GIFs, so, basically: GIF support is now a thing!
- All animations are now controlled using 2-axis blends, and are properly organised
- Pulses can move their Y-position over time; with careful tuning these can match notes travelling up or down to lock a pulse to a notes
Overhauled default presets and particle templates! We now have 12 default presets + 1 exposed "default" plain preset for each of the graphics presets, and 13 particle templates. It is highly recommended to either fully reset Keysight using the "reset" command in Advanced System > enter console command, or reload default presets by clicking the desired graphics preset in Graphics
Menu style has been updated! Sub-headings, buttons and text now are much more visually distinct, which should aid in legibility of larger menus with lots of sub-headings. Large menus have been split into further sub-tabs, such as in the case of Impact Lights which now have 4 sub-tabs to break up that giant wall of sliders, and these subtabs are kept at the top of the tab to reduce the amount of scrolling up and down switching between sections. Additionally, text and buttons are using much more robust inherited styling to achieve this, which allows for easy global tweaks to menu style down the line if need be, and easier tooltip-ing! Which, speaking of, every single item in the menu now has a tooltip explaining its function. In the case of sliders and graphs, hovering over the title for the UI element will give a general explanation for what that element controls
Overhauled the way the menu switches between basic and advanced modes. The menu should now cleanly transition to the correct submenu in the other menu style, making it pretty seamless to play around in Basic mode, decide "I need to look at advanced options for a second", and click the button to quickly have a look, and then transition back without having to re-open any menus. The only menu that does not transition cleanly is Basic Colour, as this has no unambiguous equivalent in Advanced mode.
Overhauled the graphical editor and slider UI modules! This is getting its own separate entry in the Overhauls section because holy heck it took a lot of painstaking work to update. In the graph editor: big bulky buttons have been replaced with simple icon buttons, the layout has been tightened and tidied, graph bounds editing now auto-greys-out when the buttons will not do anything, and "use flat value" no longer changes the graph values and just uses the graph 'max' effect value (so you can switch between flat/dynamic response much smoother). In the slider: changed appearance of icon buttons, and fixed the bounds to properly update when trying to map to a value that sits outside the default min/max range. Snapping has been reworked from percentage based to a set snap amount that gets larger as the range increases, and the bounds for sliders and graphs can be re-written with finer control by clicking on the display and typing a new desired value. Additionally, very large values with many zeroes switch to using K (and M), such as 10,000 > 10K (and text entry respects this, so you can type in 20k and it works)
Overhauled impact lights! Candle flickering now uses 2-axis graphs for flicker speed and brightness deviation, as well as having a new property of "displacement by note activity"! This allows impact lights to subtly (or not so subtly) move around as they flicker, giving that classic candlelight dancing-shadows look. Vertical axis displacement is now also a 2-axis response with velocity, which allows for converting static on-piano impact lights to floating orbs that shoot up and down the backdrop in response to velocity! (Make sure to enable affect-backdrop for this, and you may need to tweak simulation values to get a good animation feel since these affect how impact lights react to note-offs)
Overhauled menu layout and "expose" behaviour for particle systems! Particle system editing now has a hiercharchical tab view to avoid being yeeted into the void when you open a giant tab, scroll down, and then opening a smaller tab below it (closing the first one). Particle behaviour sub-tabs are roughly organised by "importance of influence", with more-important options towards the front of a scroll box of tabs. "Expose" flags are also present per-tab, and control the entire tab. This means a basic user might see more options than previously, but it is also much more consistent and universal in terms of which tabs are visible in what mode
Overhauled particle randomization! This ties into the "expose" rework listed above, but the randomizer now randomizes each section of particle systems based on the "expose" flag for that section (if it choses to do randomize at all, based on the chance branch to randomize template particle systems). Previous behaviour simply randomized a handful of known-important values like path stretching and particle size, but notably did not touch things like particle shape as it was conceivable that particle shape is core to the template's function, and it should not be changed (as in the instance of the Steam template). Randomization operates within ranges of the original template value, and clamps to the graph min/max for each variable. This means that the randomizer will now more thoroughly and intelligently generate cool particle system modifications, and do so based off human-set value bounds so it doesn't go too crazy. If making your own particle templates, this means it is extra important to set good graph ranges even for things that are not used, along with deciding which sections should be exposed and therefore randomizable, and which ones should not
Overhauled note object shapes and scaling behaviour! Note objects are now much more consistent between shape versions, with each shape always being the same Z-height of 0.5cm and having identical border widths for narrow/wide borders. Black notes are also slightly wider across the board. On top of this, the way note objects scale to their minimum scale size and width scaling has changed significantly. Minimum scale is now relative to the size of two end caps, so 1.00 minimum size always gives a square/round note profile if released quickly. Cap size also scales with width, so the note object proportion is consistent across different sizes. Note scale can also be a dynamic response against note strength, bring on the chonky notes! You better be confident in your voicing, though
Overhauled (*clears throat*) translucent material domain sort priorities. Layman's terms: the layering of rings and pulses! Before, this was left up to the engine, and this worked just fine under most normal circumstances, but completely fell apart and gave weird "slow Z-fighting" if you layered a ton of fully opaque semi-transparency-supporting objects like pulses. Now, the sorting priority is manually set based on the Z-height above backdrop of pulses and particles, along with the order that they were spawned. Sort order is descending and goes in order of pulses > particles, so higher pulse slots and particles render underneath lower pulse slots/particles, but *ascending* with time. This means at each height, each new object is guaranteed to render on top of the last. The only limitation is that the accuracy of Z-height is limited to 0.01 thanks to int16 sort priority storage space. This opens up really exciting preset opportunities relating to deliberately overlaying TONS of stuff and letting it all bleed together, as this no longer flickers like crazy!
--- SMALL ADDITIONS ---
Added brightness slider for white key material and backdrop self-lighting to the Basic Effects > Backdrop menu. These two sliders should vastly simplify the common desire to have an always-visible backdrop, or brighter white keys
Added local cull horizontal and cull vertical rendering options to pulses and particles. This means that allowing or disabling pulses and particles clipping outside the active area is now controlled per pulse/particle, although both have both culling options enabled by default. Psst, some particle systems look great when falling below the keyboard dividing line, like "sandstorm"!
Repurposed the Core > Viewport culling toggles for horizontal and vertical axes. These now exclusively act on the backdrop, and are found under Scene > Backdrop. Enabling "extend backdrop bounds horizontally/vertically" will turn the backdrop into more of a "canvas" for advanced, not-specifically-piano visualisations. (I mention the repurposing because if you had culling disabled prior to this update, it will essentially turn ON these new extend-bounds options)
Added tooltip fade-in delay slider to System > Interface. This allows you to set a longer or shorter time period that you need to hover over something for it to show the tooltip
Added support for transparent piano key materials. You probably still shouldn't use these, but it was simpler to allow them than to check and block transparent material pasting
Added rename functionality to pulse and particle slot titles (just click on the text and edit it), and removed the rename field from the pulse picker
Added "force release after set time" function to particles. This overrides their usual release-when-note-is-released behaviour, and causes them to release a set amount of time after they spawn. This can create "bursts" of particles with a short release time and a high spawn count. Note that dynamic velocity response is disabled for this mode
Added time offset functionality to particle systems using force-release-after-set-time mode. This functions the same way as pulses, but is rather more niche in its utility
Added debug functionality to arrow keys. Left arrow pauses and unpauses Keysight, up/down changes time-stepping, right arrow increments time by specific amount
Added ability for vsync interval to be set to 0. This activates rhi.SyncWithDWM 1, which theoretically syncs frames to the desktop window manager rather than the monitor, which may assist in recording software frame pacing. But it also seems to remove all frame limits, so, this requires more testing
Added ability to have greater than 1.0 normal map strength on Advanced materials, and added ability to have negative normal map strengths. Large values increase the perceived geometry distortion, negative values "flip" the Z-direction of distortion
Added texture panning over time to note objects, backdrop and overlay materials! This allows texture unwrapping to change over time, adding another layer of complexity to visuals if desired. Speed is measured in the same speed units as notes, or 1.0 = 10cm/s
Added "flip mask" option to materials, and removed "- (inverted)" default masks for advanced materials with an alpha mask, or blended materials
Added "geometry normal strength" slider to note object behaviour. This is a complex one to explain, perhaps, but: setting geometry normal strength to 0.00 causes all pixels from a note object to believe they are pointing "upwards", and then modified by the normal map from the material (if using one). Functionally, this allows you to control the amount of reflection warping given by the note geometry without actually changing the geometry itself, which is useful for making flat-looking notes with a specific outline shape without having that shape's reflection warping (so, round notes without round reflections)
Added a metric to the information tab of the particle system menu to display the approximate GPU cost of the current system. This is calculated fairly lazily by taking the max time, size, spawn rate and lowest speed and multiplying them together, as the primary cost for high-intensity systems like Steam is the translucent shader render cost on all the overlaid particles. Higher = worse, and typically anything over 100.00 enters frame-drop territory on weaker systems. Be aware that particle systems have plenty of other costs associated with them, not just pixel translucency cost, such as: CPU cost to pass in dynamic variables to the particle system, GPU cost to simulate particles, and GPU memory cost to store particle data
Added culling to midi events that violate basic midi rules. This is to account for midi files that give weird, illegal messages like midi channels of 226 (when it should be 0-15), or velocities of >127. Any incoming events with either channel outside range of 0-15 (or 1-16 when offset) / control ID outside of 0-127 / velocity outside of 0-127 will be immediately culled
Added some additional websocket response data to the inbound socket. Just in case anyone other than me is listening for response messages over the inbound websocket: the response JSON now contains "display", which informs the server what the current preset or seed is (including edge cases like looping randomize and FMU)
--- CHANGES ---
Moved menu theme buttons from Advanced System > Menu styling to just System > Interface. This means they're accessible in basic mode, and not in a menu nobody in their right mind ever needs to enter
Changed tooltips to be left-aligned rather than centre-aligned, and added a thin border with the current selected button colour around the tooltip to make it more visible. Thanks to Kyrazell for the excellent suggestion!
Changed "Menu styling" to "Advanced menu styling" in System (only visible in advanced mode)
Changed the websocket query function to return the name of the current slot if the current preset was not generated using a random seed, and give a special message if automatic preset randomization is in effect
Changed basic mode note object border "glowing" button to use a value of 4.0 to 8.0 rather than 1.0 to 2.0 for brightness
Changed menu to only update its state when the menu is actually open, and otherwise just cache a pending menu update to be triggered when the menu is opened. This should drastically reduce the overhead for a rapid looping randomizer mode
Changed variable note speed to be a 2-axis graph. This does not auto-convert from old variable max speed + ramping, as I think only a single person has ever used this option, but a 2-axis response gives much better opportunity for cool things like max velocity notes suddenly being way faster
Changed the default "custom angle" to be an offset, perspective angle. Hopefully this can show off the 3D-ness of Keysight to curious button-clickers!
Changed keypress fade out animation curve to be a 2-axis graph. This gives a visual representation of how the keypress will fade without having to actually test it
Changed tooltip default fade-in delay time to 0.75 seconds, and sped up the fade-in animation from 1.0 seconds to 0.5 seconds
Changed note light brightness by velocity to be a 2-axis graph
Changed the name text on pulse and particle system tabs to be an editable text box, to allow for easy and rapid re-naming without going into submenus
Changed note light width slightly (wider for black keys, just a touch wider for white keys) and changed the way the lighting attentuation radius behaves. This should be indistinguishable from older note light behaviour under standard circumstances, but with excessively low concentration or high note height above backdrop, there may be discrepencies
Changed note light concentration slider bounds to be 0.5 to 1.0, although these can be edited down. This is to push users away from using really low note light concentrations, as it has a performance impact and isn't visually consistent in 100% of circumstances
Changed octave lines to always and only use backdrop lighting channel, instead of silently inheriting the overlay lighting channels
Changed particle velocity randomness to use gaussian distribution rather than the default distribution. This fixes the issue of seeing the "range" of paths a particle could take with a high enough spawn rate, as gaussian distribution means that at a randomness of 1.0, ~65% of random values fall within 0.0 to 1.0, 95% of random values fall within -1.0 to 2.0, 99.7% of values fall within -2.0 to 3.0. This means that randomness is now "more random" for the same input value for initial velocity, but the random range is far more natural and you do not see a hard edge at the bounds of particle paths. In testing, old randomness values appear approx 2x more random, so these values have been automatically multiplied down as part of 1.4 preset importing
Changed "Circle (outline)" pulse stencil to be half as thick
Changed "Fade (with speck)" to have a significantly larger centre in proportion to the fade, allowing smaller particles that use this stencil. Particle sizes have been auto-adjusted to compensate by multiplying size by 0.33
Changed impact light fade-out behaviour when in non-sustained-brightness mode. Impact lights now fade out with the given fade-in time, removing the harsh cut while keeping it controllable without additional variables
Changed minimum time dilation to 0.05, down from 0.1
Changed non-sustained note force behaviour to smoothly interpolate down to 0.0 force upon key release, rather than snapping to 0.0 (avoids instant responsiveness on particles, which looked a little odd)
Changed damper block lighting channel from "piano" to "backdrop" (as it looks nicer if they pick up note lights. Impact lights are usually blocked by the keybed divider)
Changed piano key texture unwrapping to use regular top-down mapping rather than custom UV mapping. When textured, the sides of notes might look a little strange, but this gives much greater flexibility in controlling the appearance of textured keys from a normal camera angle
Changed the user-controllable defaults to save to Defaults.sav rather than as part of SystemStruct.sav. This was primarily to avoid struct infrastructure breakdown (hah.) when editing certain low-level structs, but it has the benefit of defaulting everyone's default preset to reflect new 1.4 values too! (As a reminder: this default preset is very important as it is the baseline preset randomized from when using the randomizer)
Removed the "view full documentation in browser" button from the Changelog menu. This was not only wildly outdated, but also tooltips on all buttons within Keysight makes digging through a giant document for information redundant
Removed "key lighting" option. It is far better to use self-emissive materials for keys than to have a directional light on the "piano" light channel blasting at them, and this can now be done via the Basic menu
Removed "cull horizontal" and "cull vertical" global options from Core > Viewport. These are now activated per-particle and per-pulse, for greater flexibility
Removed ability to have CPU-simulated particles. There was never any reason to do this other than if, somehow, GPU particles were not supported on some specific hardware. After gathering some more data in that respect, it seems like not a single computer running Keysight has failed to run GPU particles
Removed some backend internal switching between no-note-wind and note-wind particle system versions based on parameters. The original idea was to have optimised systems based on what is needed, but in practice, the switching is more costly than simply running the un-needed particle modules with 0.00 values
Optimised some internal particle system code. Probably to no perceivable effect, but still!
Optimised texture displacement with notes. As a side effect, global texture displacement with dynamic note speed now makes all notes have the correct texture displacement speed over time (they just all spawn with the same starting offset). Additionally, this fixes a bizarre edge case relating to floating point precision leading to texture displacement speed "desyncing" randomly from notes when Keysight has been open for a long time and/or has a very low time dilation
Optimised material and colour assignment across the project. CPU usage should now be significantly lower unless using dynamic, over-time colours
--- BUG FIXES ---
Fixed notes that are forcibly released by another note spawning from "jumping" one frame's worth of displacement. Rapid notes now look significantly smoother at their origin point as a result
Fixed the no-texture-displacement mode in note object materials. Using non-random mapping and no texture displacement will now properly make notes "reveal" an underlying image
Fixed issue where changing basic mode colour options could set note border colour away from black, if border material is set to blank
Fixed particles and pulses velocity-based activation not functioning
Fixed overlapping pulses and particle slots with translucent material mode from Z-fighting
Fixed new slider UI element doing silly things when being updated to a value greater than the default slider max, or less than the default slider min
Fixed "note light change brightness over time" not working at all in top-down mode. Now, note lights will fade out with note activity once the note reaches it's target location. If you see any bugs with this, let me know, since I get the feeling it's gonna be buggy under some specific circumstances but I couldn't find anything on my end
Fixed toggling frame lighting channels causing white piano plane to appear underneath the piano keys and not go away until a full preset switch is called (SUPER important bug to fix. I expect my Nobel prize nomination in the coming weeks)
Fixed colour hex code display occasionally showing silly things like "#000" instead of the intended "#0F0F0F" when dragging sliders
Fixed note lights having a random black or white key driven width if note objects were disabled
Fixed particle systems not having a new random position within their vector field on repeat note presses, leading to identical particle pathing
Fixed note light brightness being too low when note objects are relatively small. The workaround is a bit of a hack, since it's a delicate balance of attenuation radius/light size/brightness multiplier, but as long as notes are not <0.15cm and concentration is not comically low, note light brightness should be more consistent with small notes (such as those in the default Chopin midi)
Fixed repeat notes causing first impact light to one-frame-flash to its target brightness before being destroyed by the second impact light (highly visible on slow-build impact light setups)
Fixed randomizer not altering default emissive min/max values when randomizing to a transparent material
Fixed normal maps being ever so slightly inaccurate to their intended effect
Fixed note objects with >1 scale from Z-fighting with each other (achieved via a small Z-height offset based on note position. Higher notes now are "on top" of lower notes)
Fixed note lights having a variable brightness when note object scale is changed, and made note light widths exactly the same as note objects
Fixed having large numbers of preset slots potentially tanking CPU performance on weaker systems (for no reason)
Fixed some edge case websocket messages having invalid JSON styling (forgot to escape some characters and crashed my server with it. Whoops! Sorry Adam)
Prospective fix for certain timings of note-on/note-off events causing some effects to become "stuck on" when they shouldn't be
Prospective (second) fix for pedal events sometimes arriving out of order in top-down mode, leading to pedals "stuck down" or not down when they should be
