This follows the classic Stable Fluids paper by Jos Stam. Use your mouse.
A few things that would make this better:
- More optimization
- Higher resolution (if possible)
- monotonic cubic interpolation for advection (likely too expensive)
- MAC grid (NOPE - saves a lot of time to backtrace all quantities from cell centers instead. A MAC grid would mitigate some of the boundary artifacts here, but it's just too slow.)
- vorticity confinement (expensive, but probably the next most important thing)
- better smoke vis - bilinear interpolation? (almost certainly too expensive)
- higher resolution for smoke than for velocity?
- other forces: gravity / heat / etc.
- better code quality (it's kind of a mess, sorry)
- Alternating Gauss-Seidel direction
- Control number of pressure iterations with left/right
- Some optimizations thanks to @freds72 (I'm loving the hack for
- @freds72 pointed out a few more optimizations and bugs (thanks!)
- Merged all advection together and integrated density decay - saves tons of CPU.
- Got rid of velocity diffusion - this also saved lots of CPU.
- Lots more micro-optimizations (pre-multiply dt, split up multiple assignments, treat fg/bg colors as a single unit, etc.)
- Increased resolution due to all the optimizations! Formerly, at 30fps, this could do 20x20 at 9 pressure iterations. Now it can do 24x24 at 10 iterations.
- Smoke gets introduced a little slower and fades a little slower.
- Sacrificed a little CPU (and a pressure iteration) for some tracer particles.
V0.4 (not posted yet)
- More verbose CPU time breakdown if desired
- Unroll pressure loop 4x to save about 6% CPU
Bonus GIF because it's neat: two vortex pairs approach each other, collide, vortices re-pair and move to the sides.
A demake of a software groovebox from decades past...
Pattern mode is nearly complete! There's a mixer section, pattern storage, and a few editing tools. Good thing, too, since I think I'm coming up at the limits of what the Pico-8 CPU can reliably handle.
WARNING: Be careful if you play this cart on the web! Audio playback performs poorly on some OS/browser combinations and you may get loud crackling or popping noises. Turn your volume down before playing for the first time. If you have browser trouble, try it in native Pico-8. Or in a forthcoming native app export that I'll probably put up somewhere!
- Arrow keys select buttons/knobs/etc.
- Z/X change control values. (Z is down, X is up)
- The autorepeat rate speeds up while you hold a button down.
- Step buttons for drums: gray is off, red is an accented hit, yellow is a soft/unaccented hit.
- Step buttons for synths: gray is off, red is a normal note, yellow is a slide. Bright red/yellow are accents.
- Note buttons: the little dots indicate octaves.
- You can save/load patterns to/from the clipboard in the pause menu. There's basically no error checking so you can easily crash/freeze the cart this way if you load in a misformatted or invalid pattern. Also, this seems to not work in the web player.
- You can also clear the sequence from the pause menu.
More editing features are sorely needed, and the device enable toggles (mute buttons or pattern enable? not sure) are not yet implemented. Otherwise, pattern mode is more or less done, leaving me with around 3k tokens for song mode and parameter automation.
The code is by and large a complete mess, though the sound driver is maybe of tolerable quality.
- Tuning: sound quality, parameter ranges/scaling and synth accent behavior need help too.
- Copy/paste on PiRC
- Device mute or pattern enable toggles (not sure which one to do)
- Probably some other editing tools: copy/paste notes only, clear single device only, etc.
- Highpass filter on delay feedback? (if CPU allows)
- Highpass filter on overdrive input for drums? Overdrive on the drums isn't super useful right now.
- Master HP/LP filter or selectable filter insert. Only if CPU allows. Even then, I'll be lucky to squeeze 1 in, doing this per-part is extremely unlikely. Or perhaps a master high/low shelving EQ? ... but were would the controls go? Or, wait, what if I scrap overdrive for drums (since it sounds awful there) and do a filter on drums only? Synths already have a filter, after all.... It could just be a simple non-oversampled biquad, hopefully I have at least enough CPU for that.
- Song mode and automation (the big one)
Please do not expect saved patterns to work at all in future versions.
- Initial version
- Added second synth
- Better sequence loaded on start
- Added clear sequence option to pause menu
- Added drum machine (BD/SD/CH only)
- Master compressor
- Mockup for mixer/transport/pattern selection UI
- Various tweaks and fixes
- Finished drum machine - PiRC
- Fixed compressor somewhat
- Added mixer with overdrive (insert) and delay (send) per part
- Removed overdrive/level controls from devices (those are on the mixer now)
- Tempo, shuffle, and basic transport controls
- Delay time and feedback controls
- Reworked input handler to save CPU
- Copy/paste pattern controls on PBL (still needed on PiRC)
- Transpose pattern control on PBL
- Increased max key repeat rate to 60Hz
I just learned about the PCM interface, so I thought I'd do a little adventure into sound synthesis.
This cart is an experiment in building up an audio system that can run dataflow graphs built up from smaller generator and effect components. Here, I've used it to generate some plucked string sounds, mix those together, and then apply some delay to the result. The audio system needs some work and probably should implement audio processors as objects instead of coroutines (as coroutines it's annoying to send control signals once a processor has been created), but it's still kinda fun.
The code has a bunch of other areas that could use cleanup too, but coroutines vs. objects is probably the one big design issue that should get sorted out.
The one big audio-system-side thing that really helped here was trying to generate at least 128 samples per frame so long as I wasn't too far ahead of the audio system's needs. This really helped smooth out maximum CPU usage, since without that tweak I was sometimes generating 256 samples and sometimes 0.
On the plucked string side, with such a low sample rate it was absolutely necessary to include the tuning allpass filter in the delay loop. I've also included decay stretching as well as decay shortening ... yes, they're sort of at odds, but mixing them gives you a range of different sounds. I haven't done any pick direction/position filtering, string stiffness, bridge effects, sympathetic vibrations, dynamics filtering so louder notes are brighter, etc. But those could all be done here if anyone were so inclined!
The cart works well on my machine, but I'm very curious about whether it will sound okay on the web. I've tried to keep the volume down, but please be careful about your levels when you hit play.
As for the "composition", I started with a standard guitar tuning, but each string loops through a sequence of interval offsets from that tuning, advancing one step each time it gets hit. Not my favorite but it sort of works, I think.
Update: I added some ways to tweak the sound (stretch and damp) as well as the speed of the balls (dt). Up and down arrows select parameters, left and right change them. It's definitely more interesting this way.... For stretch and damp - low stretch values kill high frequencies faster, whereas low damp values tend to reduce all frequencies equally.
Here's a little toy that makes sound. Balls bounce around the screen and make different noises when they collide with each other. You can nudge the white ball around with the arrow keys. I tried to add some very minor lighting effects on the balls and to make the sounds respond to the force imparted on each collision.
The code is, of course, a mess.
I started playing around with the shallow water equations and got to something that's maybe a little bit fun. Arrow keys make waves, Z switches boundaries between (approximately) open and reflecting. My implementation mostly follows https://graphics.ethz.ch/Downloads/Publications/Tutorials/2008/Mue08/coursenotes.pdf .
Current limitations/known bugs:
- Dissipates energy rapidly, although you'll probably only notice this if the boundaries are reflective.
- No handling of dry regions. Weird things may happen if depth goes to 0!
- Weird oscillations around both (nearly-)dry regions and shocks/big elevation changes. Not sure yet how much of this is attributable to bugs vs. limitations of the discretization I'm using.
- Liquid volume is not conserved. Not really a meaningful concept with open boundaries, but pretty noticeable with reflective boundaries.
- No wave breaking etc. Shallow water equations are a heightfield model and I don't think I'll get around to full liquids on PICO-8 any time soon. :)
I hope this cart is fun to play with! I'm hoping to fix a few of the items above, clean up the graphics a bit, and maybe find a way to build a little bit of a game around these dynamics.
Started playing around with 2D sims - fluids seem hard to do at reasonable resolution given CPU constraints, but waves are just fine. More natural boat control and bilinear interpolation for wave rendering (more detail! less blocky!) both might make this more fun.
I'm also wondering if there's a racing game here where you can interact with the waves and they aren't just part of the scenery.
A little cloud-based audio toy. Move your cloud around for different sounds. Would love to know what might make it more fun!
This is a little fire experiment I've started playing with. It uses basically the same lookup table setup as https://hackernoon.com/pico-8-lighting-part-1-thin-dark-line-8ea15d21fed7 , although that may not have turned out to be absolutely neccessary.
What I'm happy with:
- overall look
What could use work:
- sound could respond to player actions
- smoke could drift a little more interestingly
What might be fun to add:
- setting other things on fire
- scorch marks or some other permanent trace
Thoughts are more than welcome!