luchak [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=24137 sfxp - sfx design tool and generator <p>Want sfx fast? sfxp can help! Adjust the sliders for new sounds, or click &quot;random&quot; for instant inspiration.</p> <p> <table><tr><td> <a href="/bbs/?pid=134424#p"> <img src="/bbs/thumbs/pico8_sfxp-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=134424#p"> sfxp</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=134424#p"> [Click to Play]</a> </td></tr></table> </p> <p>Controls:</p> <ul> <li>click/drag sliders and buttons</li> <li>right click the random button to mutate the current sound instead of fully randomizing it</li> <li>z/x to replay the current sound</li> <li>left arrow to undo</li> <li>right arrow to redo</li> </ul> <p>You can export either to sfxp format (to share, or to edit more later) or to PICO-8 sfx format (to paste into the PICO-8 sfx editor and use in your PICO-8 games). Export works via the clipboard, which can be kind of weird on the web version of PICO-8. I highly recommend running sfxp on desktop PICO-8 if you have it.</p> <p>You can also find <a href="https://luchak.itch.io/sfxp">sfxp on Itch</a>.</p> <p>Made for the PICO-1K Jam.</p> <p>Update 2023-09-20: undo bug fixed and redo added.</p> https://www.lexaloffle.com/bbs/?tid=54142 https://www.lexaloffle.com/bbs/?tid=54142 Sat, 16 Sep 2023 08:24:00 UTC QPA: Lossy Audio Compression for PICO-8 <p>I am pleased to announce Questionable PICO-8 Audio (QPA), a compressed audio format for PICO-8.</p> <p>(Compatibility note: if you encoded any QPA files before 2023-09-07, please see the Changes section below.)</p> <h2>DON'T YOU LECTURE ME WITH YOUR 30K PICO-8 CART</h2> <p>Oh, but I will!</p> <p> <table><tr><td> <a href="/bbs/?pid=133755#p"> <img src="/bbs/thumbs/pico8_qpa_demo-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=133755#p"> qpa_demo</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=133755#p"> [Click to Play]</a> </td></tr></table> </p> <p>Your song is synced with the clipboard - you can copy your songs out to text files (or this thread!) and paste song strings back in to the cart. You can right-click samples to preview them, and you can right-click the play button to skip the intro sample. Numeric modifiers come <em>before</em> the thing they modify. Hopefully you can figure out the rest!</p> <p>Copy/paste is a little annoying on the web player, and PCM audio can also be unreliable on the web, so consider trying this cart on desktop PICO-8 if you have it.</p> <p>You can also check out this song by me:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>7⬆️✽0⬆️✽✽✽⬇️✽⬆️✽3⬇️▶▤웃⬆️7◀0⬆️ˇˇ♪♪♪□&and;7⬆️&and;7⬇️7⬇️&and;</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Or this much better song by <a href="https://www.lexaloffle.com/bbs/?uid=40166"> <a href="https://www.lexaloffle.com/bbs/?uid=40166"> @packbat</a></a>:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>➡️▶▒7◀▶&hellip;6◀░▶▒7◀▶&hellip;6◀★▶▒7◀▶&hellip;6◀█▶😐7◀▶⁘3◀⬆️▶⁘3◀⬇️▶▒7◀▶&hellip;6◀░▶▒7◀▶&hellip;6◀★▶▒7◀▶&hellip;6◀⬆️★⬇️⬇️⬇️⬇️▶★7◀▶▥▥⬆️2◀&and;</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>(<a href="https://thirtydollar.website/">The reference</a>, if you're not familiar)</p> <h2>Why QPA?</h2> <p>Because you want to put fun sound samples in your carts, but don't want to use too many tokens or too much space!</p> <p>QPA provides three main benefits:</p> <ul> <li>Tiny decoder. A fully-featured decoder that reads from strings, does quality-level detection, and rejects invalid files is 228 tokens. A minimal decoder is just 175 tokens.</li> <li>Reasonable quality at very low data rates. QPA encodes mostly-intelligible speech at just 1.14 bits/sample (788 bytes/second) - or completely-intelligible speech, as well as usable instrument samples, at twice that rate.</li> <li>Faster-than-realtime decoding speed. Precise speed depends on the decoder implementation, but around 4x realtime is a reasonable expectation for a token-efficient decoder.</li> </ul> <p>As for how this works in practice: the demo cart PNG is just under 32k. It contains about 18k of samples (split 17k in sprite/map/etc. space, 1k in code) and 2k of other compressed code; the rest of the space is taken up by the label and other overhead. That 18k of sample data stores almost 14 seconds of audio. The samples are stored at a variety of quality levels, but more audio could have been included at lower quality, or higher-quality audio could have been used in exchange for more space. There also could have been a lot more audio if I hadn't tried to keep the cart around 30k - there's another 12k of compressed code space that could have been filled with QPA data strings!</p> <h2>What Is QPA?</h2> <p>QPA is an adaptation of the Quite OK Audio Format (QOA) to PICO-8's constraints. As such, it is a lossy, constant-bitrate format, in which the decoder attempts to predict future sample values one at a time, and compressed files store approximate differences between these predictions and the real sample values. To better understand how this scheme works, I suggest reading <a href="https://phoboslab.org/log/2023/02/qoa-time-domain-audio-compression">this introduction to QOA</a>. QPA changes some details, but the basic structure remains the same.</p> <p>So what changed to put the PICO in QPA?</p> <ul> <li><strong>Multiple quality levels.</strong> QPA offers a choice of compression ratios so you can optimize your valuable cart space. The highest compression ratio (7x) is noisy, but is still suitable for some speech, percussion, and sound effects. The lowest two compression ratios (2.25x and 1.75x) are approximately transparent for most sounds.</li> <li><strong>Minimal metadata.</strong> The only pieces of metadata in a QPA file are a magic number and a sample count. QPA includes no sample rate information, and does not support multi-channel audio (PICO-8 is mono only) or seeking to arbitrary points in a file (PICO-8 carts are small). This makes the decoder simpler.</li> <li><strong>8-bit audio only.</strong> QPA assumes an 8-bit output resolution, and is tuned to avoid single-bit output noise.</li> <li><strong>PICO-8 numbers.</strong> Almost all arithmetic works on PICO-8's native q16.16 number representation, slices are now 32 bits to match PICO-8's word size, and the format is little-endian instead of big-endian.</li> <li><strong>Smarter encoder.</strong> At PICO-8's low sample rate, it is critical to avoid high-frequency noise, so the encoder includes some light perceptual tuning to push noise into lower frequencies. It also expands QOA's use of exhaustive search for parameter selection, making it easier to incorporate new encoding strategies in the future.</li> </ul> <h2>Resources</h2> <p>To use QPA in your own carts, please check out the following resources:</p> <ul> <li><a href="https://www.lexaloffle.com/bbs/?uid=49583"> <a href="https://www.lexaloffle.com/bbs/?uid=49583"> @bikibird</a></a>'s <a href="https://bikibird.itch.io/defy">Defy encoder</a> and <a href="https://www.lexaloffle.com/bbs/?tid=47089">Defy cart</a>. You can use these to encode and play back your own audio files.</li> <li>The <a href="https://raw.githubusercontent.com/luchak/qpa-format/main/pico8/qpa_util.p8">QPA utility cart</a>. This cart makes it easy to convert QPA files to strings, and contains low-token decoding functions to copy into your own carts.</li> <li>The <a href="https://github.com/luchak/qpa-format/">QPA repository on Github</a>. Here you can find more documentation, a format spec, and a CLI encoder/decoder for QPA files. (CLI requires Node and NPM.)</li> </ul> <h2>Changes</h2> <p>On 2023-09-06 and 2023-09-07, new versions of all tools, code, and encoders were released to fix problems identified by Packbat. These new versions broke compatibility with earlier versions - if you switch to the new code, please keep in mind that you will have to re-encode your files. Hopefully this is a one-time only sort of change.</p> <h2>Future Work</h2> <p>I'd like to focus on getting better quality at approximately 1 bit/sample. It's possible that VBR or variable sample rate enhancements to QPA could get there, or it might be necessary to explore frequency-domain techniques ... although that might bode poorly for keeping decoder token count low.</p> <p>But first - I think it's time to use QPA to build a tracker. No promises on release date!</p> <h2>Acknowledgements</h2> <ul> <li>Dominic Szablewski for the QOA audio format</li> <li><a href="https://www.lexaloffle.com/bbs/?uid=40166"> <a href="https://www.lexaloffle.com/bbs/?uid=40166"> @packbat</a></a> for discussions and a whole lot of listening tests</li> <li><a href="https://www.lexaloffle.com/bbs/?uid=49583"> <a href="https://www.lexaloffle.com/bbs/?uid=49583"> @bikibird</a></a> for Defy and being willing to integrate QPA</li> <li>ferris for providing design feedback and pointers for future work</li> <li>MissMouse for the demo cart suggestion</li> <li><a href="https://www.lexaloffle.com/bbs/?uid=25898"> @NerdyTeachers</a> and <a href="https://www.lexaloffle.com/bbs/?uid=66501"> @Heracleum</a> for help with the cookie/coffee test</li> <li>The entire #music-sfx channel on the Discord for discussions and for putting up with a whole lot of QPA chatter</li> </ul> https://www.lexaloffle.com/bbs/?tid=53933 https://www.lexaloffle.com/bbs/?tid=53933 Thu, 31 Aug 2023 01:00:55 UTC Sample Piano (and also a loop slicer) <p>Would you like to play the piano ... in PICO-8?</p> <p> <table><tr><td> <a href="/bbs/?pid=132750#p"> <img src="/bbs/thumbs/pico8_sample_piano-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=132750#p"> sample_piano</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=132750#p"> [Click to Play]</a> </td></tr></table> </p> <p>Well, I can't imagine why, but there you go. Use the tracker keys to play. It's polyphonic.</p> <p><del>If you want to change the sample, you can convert a .WAV file to any of the QPA formats - and <em>only</em> the QPA formats - supported by this WIP tool: <a href="https://luchak.github.io/defy/">https://luchak.github.io/defy/</a> . Then drag and drop the resulting file on the running cart and play away. This will also save the new sample to the cart using <code>cstore()</code> so you can make new carts for new instruments!</del> That URL has been updated with some format improvements, so it won't work here any more until I update these carts.</p> <p>Usual caveats apply about PCM output not always working well on the web.</p> <p>For this use case there's basically no reason not to use 3.2 bit QPA, the highest QPA quality, since the file will be truncated at ~32k samples (about 6 seconds) due to table indexing limits and my laziness, and at that length 3.2 bits fits easily in a cart. But for future use cases perhaps the 2.3 bit format will have a purpose, and maybe even the 1.1 bit...</p> <p>Yes, the WIP conversion tool is a fork of <a href="https://www.lexaloffle.com/bbs/?uid=49583"> @bikibird</a>'s Defy. There's a PR out to merge it into the official version!</p> <p>And if you're curious, QPA is closely derived from <a href="https://qoaformat.org/">https://qoaformat.org/</a> and currently stands for Questionable PICO-8 Audio. If you think it might stand for something else let me know, you could be correct.</p> https://www.lexaloffle.com/bbs/?tid=53646 https://www.lexaloffle.com/bbs/?tid=53646 Sat, 05 Aug 2023 05:43:31 UTC bbforth <p>This cart is a barebones Forth implementation in 279 tokens. It could be smaller, it could be more usable, but I haven't really touched it in weeks, so here you go. Probably full of bugs.</p> <h3>Features</h3> <ul> <li><code>eval()</code> function</li> <li>Interpret and compile modes - extend syntax in Forth!</li> <li><code>if</code>/<code>then</code> (implemented in Forth)</li> <li>A few useful comments, including some commented-out utility functions and basic smoke test.</li> </ul> <h3>Non-features / shortcomings</h3> <ul> <li><code>else</code> (you can add this in Forth)</li> <li>Arithmetic (you can add this for 11 tokens per binop, or 9 tokens if you're willing to use valid Lua identifiers as operator names)</li> <li>Looping (you can probably add this for the cost of a few arithmetic/comparison operators, then add the syntax in Forth for no token cost)</li> <li>Passing args or returning values when calling Lua functions from Forth (depending on how fancy you want to get, probably takes 20-50 tokens for a reasonable wrapper)</li> <li><code>[</code> and <code>]</code> are spelled <code>_lb</code> and <code>_rb</code> for some reason.</li> <li>The inner interpreter works in a non-standard way that will make it hard to call arbitrary Forth from Lua outside of <code>eval</code> - this is probably worth rethinking.</li> </ul> <h3>A few ways to make it smaller</h3> <ul> <li>A few functions could probably be moved from Lua to the initial Forth definitions as-is, although since <code>:</code> and <code>;</code> depend on them this will be a bit messy.</li> <li>With the right Forth/Lua binding util, even more functions could probably be moved.</li> <li>With some internal representation changes, even <code>_interp</code> and <code>eval</code> could probably be (mostly) boostrapped.</li> </ul> <p>Anyway, enjoy. This may not be useful for very much, but the question of how little material you need to bootstrap a reasonable eval is still kind of a fun question.</p> <p> <table><tr><td> <a href="/bbs/?pid=131852#p"> <img src="/bbs/thumbs/pico8_bbforth-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=131852#p"> bbforth</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=131852#p"> [Click to Play]</a> </td></tr></table> </p> https://www.lexaloffle.com/bbs/?tid=53375 https://www.lexaloffle.com/bbs/?tid=53375 Tue, 11 Jul 2023 21:17:31 UTC Raccoon Ball <p> <table><tr><td> <a href="/bbs/?pid=130491#p"> <img src="/bbs/thumbs/pico8_raccoon_ball-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=130491#p"> raccoon_ball</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=130491#p"> [Click to Play]</a> </td></tr></table> </p> <p>Does what it says on the box.</p> <p>(updated to fix a major oversight: now it bounces)</p> <p>Photo by <a href="https://unsplash.com/@toanchu">Toan Chu</a></p> https://www.lexaloffle.com/bbs/?tid=52976 https://www.lexaloffle.com/bbs/?tid=52976 Sun, 04 Jun 2023 06:02:33 UTC cmd/ctrl confusion in web exports on Mac <p>Copy/paste is super cumbersome when using web exports on Mac. It appears that to reliably copy, I have to press ctrl-C and then cmd-C after text is written to the clipboard, and to get pastes to work I have to press cmd-V and then ctrl-V for PICO-8 to pick up the paste.</p> <p>Is there a better way to do this? If not, can Mac exports be updated to only need cmd-C and cmd-V? I'd love to cut down the instructions on <a href="https://www.lexaloffle.com/bbs/?tid=52696">Tiny Drops</a>...</p> <p>It looks like this also may be affecting folks using the EDU edition: <a href="https://www.lexaloffle.com/bbs/?tid=51921">https://www.lexaloffle.com/bbs/?tid=51921</a></p> https://www.lexaloffle.com/bbs/?tid=52823 https://www.lexaloffle.com/bbs/?tid=52823 Mon, 22 May 2023 05:29:03 UTC Tiny Drops <p>Bounce tiny drops that fall from the sky to make music! This began as a 500-character cart for <a href="https://itch.io/jam/tweettweetjam-8">TweetTweetJam 8</a>. Or check this cart out <a href="https://luchak.itch.io/tiny-drops">on Itch</a>!</p> <p> <table><tr><td> <a href="/bbs/?pid=129682#p"> <img src="/bbs/thumbs/pico8_tiny_drops-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=129682#p"> tiny_drops</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=129682#p"> [Click to Play]</a> </td></tr></table> </p> <p>The latest version adds many more editing features, as well as save/load and audio export.</p> <h3>Controls</h3> <ul> <li>Click and drag the mouse to draw lines, or to move line endpoints.</li> <li>Z/X deletes a line. If your mouse is over a line endpoint, it'll delete that line, otherwise it'll delete the newest line.</li> <li>Left/right changes line sounds. If your mouse is over a line endpoint, it'll change that line's sound, otherwise it'll change the sound for new lines.</li> <li>Up/down changes the interval between drops.</li> <li>E to start/stop audio export.</li> <li>S to save to the clipboard. In the web version, you'll need to press ctrl-C after this to complete the copy. (Or, on a Mac, ctrl-C so PICO-8 notices and then cmd-C.)</li> <li>R to restore from the clipboard.</li> <li>N to get a new empty scene.</li> <li>When you paste a saved scene into PICO-8, Tiny Drops will automatically load it. In the web version on Mac, you'll need to press cmd-V to paste and then ctrl-V to get PICO-8 to notice the paste.</li> </ul> <h3>Known issues</h3> <ul> <li>Can get slow if you trap too many drops on the screen.</li> <li>When you start to create a line, you may hear &quot;phantom&quot; bounces until you start dragging the mouse. (Happens with 0-length lines.)</li> </ul> <h3>500-Character Jam Version</h3> <p>This version has no save/load, no audio export, and no concept of line hovering or editing existing lines:</p> <p> <table><tr><td> <a href="/bbs/?pid=129682#p"> <img src="/bbs/thumbs/pico8_tiny_drops-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=129682#p"> tiny_drops</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=129682#p"> [Click to Play]</a> </td></tr></table> </p> https://www.lexaloffle.com/bbs/?tid=52696 https://www.lexaloffle.com/bbs/?tid=52696 Sat, 13 May 2023 00:11:52 UTC Boundary Peaks <p> <table><tr><td> <a href="/bbs/?pid=129585#p"> <img src="/bbs/thumbs/pico8_boundary_peaks_tweetcart-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=129585#p"> boundary_peaks_tweetcart</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=129585#p"> [Click to Play]</a> </td></tr></table> </p> <p>Just a small tweetcart.</p> https://www.lexaloffle.com/bbs/?tid=52674 https://www.lexaloffle.com/bbs/?tid=52674 Wed, 10 May 2023 02:02:27 UTC Unexpected scoping with nested shorthand if <p>The following code block prints only the number 4, though I would expect it to print 2, 3, and 4.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>do if (false) if (true) print(1) print(2) print(3) end print(4)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Only the outer <code>if</code> has this property, the inner <code>if</code>'s scoping is fine. Similar behavior happens without the <code>do</code> block, I just included it to demonstrate the interaction of this behavior with &quot;normal&quot; Lua scopes.</p> https://www.lexaloffle.com/bbs/?tid=52571 https://www.lexaloffle.com/bbs/?tid=52571 Sun, 30 Apr 2023 19:56:20 UTC Simple tunable LZ-ish compression <p>Here's yet another piece of simple data compression code:</p> <p> <table><tr><td> <a href="/bbs/?pid=128358#p"> <img src="/bbs/thumbs/pico8_simple_lz-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=128358#p"> simple_lz</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=128358#p"> [Click to Play]</a> </td></tr></table> </p> <p>I wrote this for a (hopefully) upcoming player cart for RP-8 songs, in order to be able to pack as much RP-8 song data as possible into the spritesheet/map/sfx/music area of the cart. The compression technique is basically LZSS, with a couple of small changes / enhancements:</p> <ul> <li>The code supports strings longer than 32kB - it will break them into 32kB blocks for compression and reassemble those blocks after decompression.</li> <li>Literals are move-to-front encoded.</li> <li>Match offsets, match lengths, and MTF literals are encoded using <a href="https://en.wikipedia.org/wiki/Elias_gamma_coding">Elias gamma coding</a>. The lowest N bits (N is a separately tunable parameter for offsets and literals, N is fixed to 0 for lengths) are encoded as usual, the remaining high-order bits are Elias gamma encoded.</li> </ul> <p>The code works correctly on every string I've tested it on (so far) ... but I am less certain about whether there are efficiency bugs or not. The maximum supported match length is 1027.</p> <p>If you would like to use this code, I suggest the following process:</p> <ol> <li>Find some test data, and copy it into this cart.</li> <li>Play around with different values of <code>OFFB</code> and <code>MTFB</code> to see which produce the smallest files. Generally, smaller values of <code>OFFB</code> will be better for smaller amounts of compressed data, larger values will be better for larger amounts of compressed data. 3 seems to be a good value for <code>MTFB</code> for most strings I have tried, but maybe you will find a case where a different value is better.</li> <li>Modify this cart to save out your compressed data in whatever way makes sense to you.</li> <li>Copy the functions <code>pf_make_r</code>, <code>pf_decompress_block</code>, and <code>decompress</code> into whatever cart needs to read the compressed data. You may want to substitute the various constants at the top of this cart with their literal tuned values at this time to save tokens. If you do this, the decompression code will probably clock in at a little over 250 tokens. I'm sure it's possible to make it much shorter.</li> </ol> <p>At some point I may play around with having the compressor try out different <code>OFFB</code> and <code>MTFB</code> values on its own, or have it do some form of optimal LZ parsing. Basically, experimenting with different ways to trade slower compression times for slightly better compression ratios. Or perhaps I should just write a Pico-8 decompressor for upkr. </p> <p>And here's a 0-clause BSD license for this code so you can go ahead and use it without worrying about the CC attribution or share-alike provisions if you want:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED &ldquo;AS IS&rdquo; AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=52370 https://www.lexaloffle.com/bbs/?tid=52370 Sun, 09 Apr 2023 17:36:04 UTC Dead code affects CPU usage <p>This code uses 11% CPU according to Pico-8, but if I delete the <code>v[0]=1</code> lines in the <code>if false</code> block it uses 7% CPU:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>v={} ::_:: if false then v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 v[0]=1 end for i=0,1023 do v[0]=5 v[0]=5 v[0]=5 v[0]=5 end flip() goto _</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Other observations:</p> <ul> <li>If I put the <code>v[0]=1</code> lines in a for loop with a huge iteration count this code uses 7% CPU. (No bug.)</li> <li>If I put this code into <code>_update()</code> or <code>_draw()</code> it uses 7% CPU. (No bug.)</li> <li>Adding / removing <code>v[0]=5</code> lines bumps CPU by roughly 3% per line.</li> <li>Replacing <code>v[0]</code> with <code>v[1]</code> makes no difference.</li> <li>Pico-8 does act on this CPU info, the contents of the <code>if false</code> block will affect whether Pico-8 visibly stutters if I add draw code and the non-executing lines push CPU over 100%.</li> <li>If I add a table <code>u</code> and do <code>u[0]=5</code> in the second loop the bug still happens, no change in behavior.</li> <li>The number of top loop <code>v[0]=1</code> assignments only seems to matter between about 8 and 16 - the CPU usage seems to saturate outside of that range.</li> <li>If I make <code>v</code> local, this behavior persists, but it seems to take more <code>v[0]=1</code> lines to trigger it.</li> <li>I can produce this behavior on both 0.2.5e and 0.2.5c, <a href="https://www.lexaloffle.com/bbs/?uid=25532"> @freds72</a> reports also being able to repro on 0.2.4c</li> </ul> <p>Since this only happens outside of <code>_update()</code> (I think??) I assume this isn't a big issue for most carts, but for tweetcarts etc. it does seem fairly important.</p> https://www.lexaloffle.com/bbs/?tid=51437 https://www.lexaloffle.com/bbs/?tid=51437 Tue, 31 Jan 2023 19:30:41 UTC 3D Snowflake Generator <p>I've already posted this on the Discord and a couple other places, but, well, why not post it here too? Randomly generated snowflakes for the season.</p> <p> <table><tr><td> <a href="/bbs/?pid=122953#p"> <img src="/bbs/thumbs/pico8_snowflake_generator_3d-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=122953#p"> snowflake_generator_3d</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=122953#p"> [Click to Play]</a> </td></tr></table> </p> https://www.lexaloffle.com/bbs/?tid=50805 https://www.lexaloffle.com/bbs/?tid=50805 Sat, 24 Dec 2022 21:07:48 UTC extcmd(&quot;folder&quot;) and extcmd(&quot;set_title&quot;) do not work with &quot;load #rp8&quot; <p>This behavior feels possibly intentional, but I thought I'd check here just in case. If you run RP-8 with <code>load #rp8</code>, on loading carts, RP-8 gives the message <code>unknown extcmd: set_title</code>. If you ask it to open its folder with <code>extcmd(&quot;folder&quot;)</code>, it fails with a similar message. Both commands work fine if I save the cart to a .p8 and immediately re-load it. This is on 0.2.5c.</p> <p>It'd be nice if folks could use <code>load #rp8</code> to run RP-8 - even if this functionality doesn't end up enabled from Splore, perhaps it could work when loading carts by ID from the CLI? Also, is there some way to work around this and avoid showing the error message if the extcmd call isn't going to work?</p> <p>At this point I'm wondering if I'll need to just point to Itch as the canonical download source for folks to get reliable results. That wouldn't be the end of the world, but offering a <code>load #rp8</code> alternative would sure be nice!</p> https://www.lexaloffle.com/bbs/?tid=49419 https://www.lexaloffle.com/bbs/?tid=49419 Tue, 20 Sep 2022 22:19:00 UTC Feature request: rate-based printh limits <p>I've been working on a song in RP-8, and I've recently modified RP-8 to not just write song files to the clipboard, but also to timestamped save files on the desktop. After a long session of working on the song, I tried to save, and got a message about there being too many <code>printh</code> files.</p> <p>I wouldn't have lost too much work - the whole reason I have this many files is that I've been checkpointing frequently - and I was able to get the data out of the clipboard, but it was still frustrating. This was a very long session, Pico-8 had probably been open for 12 hours or more while I'd been working off and on. Creating so many save files would certainly be a problem if Pico-8 had only been open for a few minutes, but over 12 hours I feel like it's not unreasonable?</p> <p>I'd love for Pico-8 to reset its number of files / amount of data limits after some period of time, even an hour or two would be fine for my purposes.</p> <p>I'd imagine this isn't super high prio, but it would be very nice. As I get closer to releasing RP-8 I'm starting to think more about awkward situations and edge cases I'll have to explain in the docs, and this would certainly be one of them. The really awkward thing about this one is that it undermines trust (since the user feels like they're losing work), and it's somewhat difficult to get around in a nice-feeling way...</p> <p>I guess I could have a save counter and add some sort of visual warning and/or exit when you've created the last save possible in a session? Still awkward but better than nothing.</p> https://www.lexaloffle.com/bbs/?tid=48542 https://www.lexaloffle.com/bbs/?tid=48542 Sun, 17 Jul 2022 19:37:25 UTC 512 Character Infinite Acid Jam <p>As usual with PCM audio, be careful of your volume, and if this doesn't play back well in your browser, try it in desktop Pico-8. Earlier versions had filter instability problems that could result in loud sounds showing up out of nowhere - I think these are fixed now (I've let this play for over an hour with no problems) but I can't 100% promise it won't happen again.</p> <p> <table><tr><td> <a href="/bbs/?pid=113246#p"> <img src="/bbs/thumbs/pico8_acid_jam_512-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=113246#p"> acid_jam_512</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=113246#p"> [Click to Play]</a> </td></tr></table> </p> <p>An entry to the <a href="https://itch.io/jam/pico-8-512-char-jam">Pico-8 512-Char Jam</a>. Kick, hat, acid. </p> <p><a href="https://itch.io/jam/pico-8-512-char-jam/rate/1577849">Jam entry</a><br /> <a href="https://luchak.itch.io/512-character-infinite-acid-jam">Itch page</a></p> <p>Update 1: Moved the delay time slightly off the beat. Also saved a few characters thanks to <a href="https://www.lexaloffle.com/bbs/?uid=42184"> @SmellyFishstiks</a>, which let me thicken the oscilloscope line.</p> <p>Update 2: Improved visualization and stability.</p> <p>Update 3: More improvements to visualization and filter stability to avoid horrible loud sounds coming out of nowhere after letting the cart play for a long time. Hopefully the last update!</p> https://www.lexaloffle.com/bbs/?tid=48186 https://www.lexaloffle.com/bbs/?tid=48186 Fri, 17 Jun 2022 05:03:50 UTC You Have To Simulate The Rope <p>Based on a request for help in the Pico-8 Discord, I ended up working on a rope/string/ribbon/chain/etc. simulation:</p> <p> <table><tr><td> <a href="/bbs/?pid=112468#p"> <img src="/bbs/thumbs/pico8_rope_sim_demo-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=112468#p"> rope_sim_demo</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=112468#p"> [Click to Play]</a> </td></tr></table> </p> <p>The behavior of the rope changes substantially depending on the gravity and drag settings.</p> <p>This sim tries to model the object as inelastically as possible, although it's far from perfect in that regard. The rope here has 128 segments, which is very difficult to handle without (a) instability, (b) excess springiness in the rope, or (c) tons of damping. So i ended up having to write a slightly clever constraint solver (multigrid for n log n instead of n^2 performance), and I chose a step schedule that uses almost 100% CPU at 60fps. But if you use fewer segments and tune the solver differently, going down to 16 segments or so and using a less conservative step schedule, like one suggested in the cart comments, you can get the CPU usage closer to 5% at 60fps. That might be more suitable for inclusion in a game.</p> <p>The underlying technique is <a href="https://matthias-research.github.io/pages/publications/posBasedDyn.pdf">Position-Based Dynamics</a>, in which the constraint solver works directly on positions, and then velocities are updated accordingly at the end of the timestep. The nice thing about this technique is that hard constraints can be really easy to add - just push your vertices to where you want them! The bad thing about this technique is that friction or other forces can be hard to model since velocities aren't really considered in the constraint solution step.</p> <p>I've included a ground plane here to demonstrate how easy it is to get the rope to collide with objects - just project the rope vertices out of any objects it's in! (Assuming your steps are small enough that the rope is still near the surface, your objects tend to be pretty smooth, etc. etc.)</p> <p>Still, this was fun to write and I think it's kind of fun to play around with.</p> <p>There are still some shortcomings here: static friction with the ground is not modeled, rope self-collision isn't modeled either, the solver still allows for noticeable elasticity in the rope at high velocities, and the drag model is very simplistic and doesn't attempt to model internal forces in the rope.</p> <p>The default parameters give you something that feels vaguely rope-like, for something that feels more like a light ribbon or streamer, try drag=0.05 and gravity=0.01.</p> https://www.lexaloffle.com/bbs/?tid=47957 https://www.lexaloffle.com/bbs/?tid=47957 Mon, 30 May 2022 04:18:35 UTC pfft: DCT/DFT/FFT for Pico-8 (with audio demo) <p>I was thinking about what's keeping Pico-8 from being a popular platform for scientific computing and high-end DSP ... and I realized: I can't think of a single FFT library for Pico-8! That <em>must</em> be the reason. So I wrote one:</p> <p> <table><tr><td> <a href="/bbs/?pid=112429#p"> <img src="/bbs/thumbs/pico8_pfft-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=112429#p"> pfft</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=112429#p"> [Click to Play]</a> </td></tr></table> </p> <p>There are some comments at the top of the cart code on usage, if you want to copy/paste this into a project of your own for some reason. It's not too slow: you can do about 400 length-256 real FFTs per second, which is enough to get up to some audio shenanigans. (See next cart.) You can use the left/right arrow keys to switch modes between DFT, complex FFT, real FFT, and DCT in this demo, but be aware that if you happen to switch to DFT mode - it is sloooooooow and you may have to hold a button down for a while to get out of it. (DCT is also slow but ~3x faster than DFT.)</p> <p>If you want to try out a somewhat-contrived audio application, check out this cart:</p> <p> <table><tr><td> <a href="/bbs/?pid=112429#p"> <img src="/bbs/thumbs/pico8_pfft_demo-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=112429#p"> pfft_demo</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=112429#p"> [Click to Play]</a> </td></tr></table> </p> <p>If you drag in a short Pico-8 friendly raw PCM file (max ~6 seconds, use <a href="https://bikibird.itch.io/defy">Defy</a> to do the conversion) this cart will play it on loop, and boost/cut frequencies according to whatever curve you draw with the mouse. All the scaling is linear, which is not very natural (log scale for both frequency and amplitude would be more conventional), but you can still create some obnoxious notches and resonances. Give it a try!</p> <p>Now that I think about it, the <code>make_hann()</code> and <code>make_stft()</code> functions from the demo cart might be useful to other cart authors as well - those take care of the overlap-add process for FFT resynthesis in a fairly transparent way. I've added a comment to <code>make_stft()</code> that should hopefully help with usage. It handles windowing and overlapping in a simple but fairly inflexible way. There is no attempt at any kind of fancy phase consistency logic. (The demo should probably be windowing the synthesized audio as well before summing it - maybe I'll fix that eventually.)</p> <h2>Changelog</h2> <p>2022/08/29: added DCT and inverse DCT functions. These are very short, faster than DFT, and may be a good choice for some applications involving lossy compression of real-valued data.</p> https://www.lexaloffle.com/bbs/?tid=47945 https://www.lexaloffle.com/bbs/?tid=47945 Sun, 29 May 2022 05:04:24 UTC PCM audio issues on ARM Macs <p>One of the things that's been driving me nuts while working on RP-8 has been how unstable the PCM audio output has felt. I can check (via logs or asserts) that, at 60fps, stat(108) is always above 256 and stat(1) never exceeds 0.9, and I'll still get occasional crackles or small time skips in the output. If I record the audio out with <code>extcmd('audio_rec')</code> these issues generally appear there as well - most often as small intervals of 0 samples. The one or two dropout cases I've been able to inspect in Audacity made it look like the dropout was in the low 10s of milliseconds range. I have not yet been able to track down a skip on the Audacity waveform display.</p> <p>I've been trying to chase down the bugs in my code, but today I instead tried RP-8 - specifically the current BBS version, #rp8-2 - on two machines that aren't my normal development machine. It was rock solid. Flawless. (Or, well, nearly flawless, just heard a dropout on the Intel Mac after leaving it running for 15 minutes, but the ARM Mac shows problems much earlier and more frequently than that.) My main development machine is an ARM Mac, and the two other machines I tried today were a Windows box and an Intel Mac. The only conclusion I can draw right now is that there's something wonky about Pico-8's PCM audio out on ARM Macs that causes it to skip and/or drop frames.</p> <p>These issues will happen even what feels like it should be easy for the machine to handle - no other CPU-intensive apps running, Pico-8 is the foreground app, etc. I have not heard these problems with Pico-8's builtin music and SFX. I'm also seeing parallel issues on the web: I thought Pico-8's PCM output was super crackly on all Mac browsers, but RP-8 runs fine in Chrome on the Intel Mac I'm trying out right now.</p> <p>If there's more information I can give, I'm happy to try to help debug this!</p> <p>edit: Realized I was behind on OS patches - moved up to 12.3.1 and I'm still definitely getting skips forward, though mystery dropouts seem perhaps rarer? Browser audio has not improved. Not sure how much here is under Pico-8's control, but it's certainly experiencing more audio issues with Pico-8 than with anything else I use.</p> <p>edit 2: managed to get a skip captured with <code>extcmd</code> - hard to determine exactly how much got sliced out, but it was a small fraction of a kick drum hit.</p> https://www.lexaloffle.com/bbs/?tid=47418 https://www.lexaloffle.com/bbs/?tid=47418 Mon, 18 Apr 2022 04:00:55 UTC Utils from RP-8: stringify, parse, eval <p>Hello! I thought I'd try to (slightly) clean up and post some utility functions I've found useful while working on <a href="https://www.lexaloffle.com/bbs/?tid=47284">RP-8</a>. Maybe they'll be useful to others, maybe not. Let's see!</p> <p> <table><tr><td> <a href="/bbs/?pid=110311#p"> <img src="/bbs/thumbs/pico8_rp8utils-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=110311#p"> rp8utils</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=110311#p"> [Click to Play]</a> </td></tr></table> </p> <p>There are three possibly-useful functions here, plus their support code. Note that in the name of token conservation, all of these functions have essentially <strong>no error checking</strong> and can blow up in various exciting ways if you feed them bad data (or if they have bugs). The code also isn't the cleanest - maybe I'll tidy it up eventually, but I don't think it's completely unreadable right now. Anyway, we've got:</p> <ul> <li><strong>stringify()</strong>, 114 tokens. This serializes structured data into a string - RP-8 uses this to save songs. Escapes binary. Both the string format and the binary escaping are completely nonstandard, but the string format at least looks vaguely similar to Lua literals.</li> <li><strong>parse()</strong>, 286 tokens (can be cut to 246 if you don't want eval). This takes a string and transforms it into structured data. RP-8 uses this to load songs, as well as to set up some of its internal data. Uses the same weird format and binary escaping as stringify(), although it also supports some variations and syntactical sugar. You can probably cut more tokens if you don't need to support large input strings or binary unescaping.</li> <li><strong>eval()</strong>, two versions - 428 tokens for interpreted, and 556 for &quot;compiled&quot;, plus you need parse(). (Very loose use of the word &quot;compile&quot; here...) This evaluates a script in a vaguely LISP-formatted mini-language with Lua-ish behavior, and returns the result. RP-8 uses this to save tokens by encoding bulky logic that doesn't need to run fast, like UI init. This can help save tokens. Note that the token costs here are pretty squishy, since they depend on what builtins you want to define.</li> </ul> <p>While this eval may help you save tokens, if you're really serious you should probably consider external build tools and bytecode. (For more on this, check out what <a href="https://www.lexaloffle.com/bbs/?uid=23375"> <a href="https://www.lexaloffle.com/bbs/?uid=23375"> @carlc27843</a></a> did with <a href="https://carlc27843.github.io/post/picoscript/">Picoscript</a> in his unbelievable <a href="https://carlc27843.itch.io/nebulus">Nebulus cart</a>.) RP-8 uses a condensed version of the interpreted eval - 382 tokens, but that small token savings causes some questionable behavior with multivals and closures, so I'm posting something better behaved, if less well tested, here.</p> <p>The cart contains these three functions, some tests for the two versions of eval (none for parse or stringify, sorry), and a small and highly artificial performance comparison between the two versions of eval and native Pico-8 Lua code.</p> <h3>Examples</h3> <p>Here is a real-world example of parse()-formatted data, including using backticks to embed data from eval():</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>{ pat_store={}, tick=1, playing=false, base_note_len=750, note_len=750, drum_sel=bd, b0_bank=1, b1_bank=1, dr_bank=1, song_mode=false, samp=(0), patch={}, pat_seqs={}, pat_status={}, tl=`(timeline_new $default_patch), pat_patch=`(copy $default_patch), }</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>And here is an example of eval()-executable script:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>(set paste_state (fn () (audio_wait 2) (let pd (stat 4)) (if (not (eq $pd &quot;&quot;)) (seq (set state (or (state_load $pd) $state)) (@= $seq_helper state $state) )) ))</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>... which is equivalent to:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>paste_state=function() audio_wait(2) local pd=stat(4) if pd != &quot;&quot; then state=state_load(pd) or state seq_helper.state=state end end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Script usage</h3> <p>The script has mostly LISP-ish syntax, though the behavior is more Lua-ish, including (hopefully correct) support for multivalues in function argument lists and returns.</p> <p>The biggest syntactical quirk is that you must prepend the character $ to each variable name you want to be looked up instead of treated as a literal string. Since the parser operates independently of eval and does not pass any side information about the strings it finds, the alternative (all strings are treated as variable lookups) would require double-quoting of some strings, like <code>&quot;'hello world&quot;</code> or <code>(' &quot;hello world&quot;)</code> ... I found this even more distasteful, so the $ prefixes are the fix for now. The one place where $ is not required is function invocations: you can't call a string, so it's clear that a lookup is required. If you find this confusing, I don't blame you, but perhaps some of the tests in the cart will make things clearer?</p> <p>Possibly-incomplete list of script forms/builtins/keywords/whatever (I'm not a LISP person...):</p> <ul> <li><strong>(e1 e2 ... en)</strong> - if e1 evaluates to a function or the name of a function, call that function with the values of e2 through en as its arguments. For example, <code>(print &quot;hello world&quot; 0 0 8)</code> will print &quot;hello world&quot; in red. The argument evaluation also respects Lua's multival semantics, or at least it mostly should.</li> <li><strong>(fn (a1 a2 ...) e1 e2 ... en)</strong> - define a function. The args list is implicitly quoted. The function returns the value of en, the last expression.</li> <li><strong>(seq e1 e2 ... en)</strong> - evaluate expressions sequentially and return the value of the last one, en.</li> <li><strong>(' e1)</strong> - quote a value. e1 will be returned literally, without being evaluated at all. Use this to keep a table from being interpreted as an expression.</li> <li><strong>(if e1 e2 e3)</strong> - if e1 evaluates to a truthy value, evaluate and return e2, else evaluate and return e3.</li> <li><strong>(for e1 e2 e3)</strong> - executes <code>for i=e1,e2 do e3(i) end</code></li> <li><strong>(set e1 e2)</strong> - sets the global named by the value of e1 to the value of e2. (Maybe a better name for this one?)</li> <li><strong>(let e1 e2)</strong> - sets the local variable named by the value of e1 to the value of e2. Note that this behaves like Lua's local assignment and not like <code>let</code> in many LISP dialects.</li> <li><strong>(@ e1 e2)</strong> - property access. Returns e1[e2]. There is an alternative form (@ e1 e2 e3) that returns e1[e2][e3].</li> <li><strong>(@= e1 e2 e3)</strong> - Sets e1[e2]=e3. Does this name make any sense with <code>set</code> and <code>let</code>? No, it does not.</li> <li><strong>(~ e1 e2)</strong> - returns e1-e2. Uses ~ instead of - because - looks like a number to the parser.</li> <li><strong>(cat e1 e2)</strong> - returns e1..e2</li> <li><strong>(len e1)</strong> - returns #e1</li> <li><strong>+</strong>, <strong>*</strong>, <strong>eq</strong>, <strong>gt</strong>, <strong>or</strong> are all present. Many other operators and keywords are missing. (There's no <code>and</code>, no <code>while</code>, etc.) They're not hard to add if you need them! If you care about tokens you should also delete anything you're not using.</li> </ul> <h3>What is this &quot;compiled&quot; nonsense?</h3> <p>Ok, yeah, I maybe should have a better word for this - but I don't. Essentially, the script can be evaluated in two different ways.</p> <p>First, it can be interpreted straightforwardly by walking the parse tree on each execution, dispatching to different functions or builtin operators as required. This can be done in relatively few tokens (especially if you ditch multival support), and mostly doesn't care what's a builtin vs. an external function.</p> <p>Second, it can be executed in two steps - first, the parse tree can be walked to produce a closure. This closure invokes other similar closures, each of which takes a dictionary of locals as an argument. The reason I've been using the word &quot;compile&quot; for this step is that it is a transformation on the code to a new form based only on its statically observable properties, with no knowledge of runtime values. The second execution step is then to invoke the top-level closure (this may be done many times with different locals).</p> <p>The &quot;compiled&quot; method was motivated by <a href="https://www.lexaloffle.com/bbs/?uid=23375"> <a href="https://www.lexaloffle.com/bbs/?uid=23375"> @carlc27843</a></a>'s Picoscript, I definitely wouldn't have thought to try it otherwise.</p> <p>This second method is much faster than the naively-interpreted version - about 4x as fast in the small test that's in this cart. How much faster it might be in any other case depends on how much the script can use builtins vs. function calls. Function call overhead will be very similar - most of the arg and return packing/unpacking logic is essentialy identical. So if you're mostly just dispatching function calls, both versions should perform about the same, however, if you can mostly stick to builtins, you could potentially see bigger speedups.</p> <h3>Requests</h3> <p>If you have clever speedups, bug reports, bug fixes, or ways to save tokens, let me know! There have to be all kinds of horrible bugs lurking in here.</p> <h3>Caveats</h3> <p>The script eval functions are larger and slower than the ones I use in RP-8, in order to give them more consistent behavior with regard to variable scopes and multivals. If you're feeling adventurous you can modify the code to take some shortcuts here.</p> https://www.lexaloffle.com/bbs/?tid=47403 https://www.lexaloffle.com/bbs/?tid=47403 Sat, 16 Apr 2022 10:00:52 UTC RP-8 1.1 - now with pattern randomizer! <p><strong>v1.1.2 update:</strong> added loop jump hotkeys (v1.1.1) and fixed a crash bug.</p> <p>RP-8 is a synthesizer and groovebox inspired by Propellerhead Software's classic soft synth, <a href="https://en.wikipedia.org/wiki/ReBirth_RB-338">ReBirth RB-338</a>. It has everything you need to make entire tracks: two paraphonic synthesizers, a drum machine, a pile of effects to process your sound, and an integrated song mode sequencer to pull everything together. The audio is lo-fi, 8 bits at 5.5kHz, giving the output a distinctively crunchy sound.</p> <p>If you're nostalgic for the early era of soft synths, a fan of minimalist computing, an acid squelch connoisseur, or just someone who likes to discover new sounds: I made RP-8 for you.</p> <p>You can find this cart, including native builds, at <a href="https://luchak.itch.io/rp8">https://luchak.itch.io/rp8</a>, or try it out below. Note that this cart works much better natively than on the web - see the Web section under Compatibility Notes below for more info.</p> <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/iL1Ryas-c-Ep&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/iL1Ryas-c-Ep&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> <p> <table><tr><td> <a href="/bbs/?pid=109822#p"> <img src="/bbs/thumbs/pico8_rp8-23.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=109822#p"> RP-8 1.1.2</a><br><br> by <a href="/bbs/?uid=24137"> luchak</a> <br><br><br> <a href="/bbs/?pid=109822#p"> [Click to Play]</a> </td></tr></table> </p> <h2>Usage</h2> <p>See the <a href="https://luchak.github.io/rp8/">manual</a>, which includes a step-by-step tutorial. RP-8 also has in-app tooltips (enable with T) and a hotkey reference / help screen (view with H).</p> <h2>Updates</h2> <ul> <li>2023 November 4( (1.1.2) - fix crash on clicking page switch button.</li> <li>2023 October 10 (1.1.1) - loop jump hotkeys.</li> <li>2023 September 13 (1.1) - pattern randomizer, copy pattern beginning/end, paste to drum track, bugfixes.</li> <li>2023 March 4 (1.0) - much more versatile foldback distortion, new demo song, finished docs (now using mkdocs instead of pandoc), tons of sound adjustments and tuning.</li> <li>2022 September 19 (beta 9) - antialiased oscillators, toned down filter harshness, file menu, &quot;paste sound&quot;, tuning changes.</li> <li>2022 September 11 (beta 8) - vastly improved synth filters, secondary drum sounds, help screen, more hotkeys, song naming, paste-to-control, overdrive bias -&gt; overdrive shape, many tweaks and optimizations. (beta 8b) Updated user guide, next/previous bar hotkeys.</li> <li>2022 August 6 (beta 7) - overdrive bias control, improved kick decay range, improved hat sound, performance optimizations. (beta 7a) Toasts and UI bugfixes. (beta 7b) Visual improvements, better FM ratio knob scaling, better save compatibility, more hotkeys. </li> <li>2022 July 21 (beta 6) - lots of constant tweaking and sound adjustments. More filter overdrive, more low end, punchier kick, lots more.</li> <li>2022 July 17 (beta 5) - removed synth attack knob since it's not being used, reduced low cut on the synth oscillators. (beta 5a) Tweaked overdrive gain compensation. (beta 5b) Fixed page button.</li> <li>2022 July 15 (beta 4) - removed sample loading and playback, save song files to both desktop and clipboard, drop song file to load, improved synth knob graphics, variable pattern lengths (with awful UI), 2-op FM drum track (control ratio with tune knob, control pitch with chromatic drum sequencing), individual drum track FX bypass, chromatic drum sequencing, second synth oscillator with chromatic sequencing.</li> <li>2022 April 25 (beta 3) - better handling of changing delay time, level compensation for filter resonance, drum sound tweaks, minor UI improvements, early draft of a manual!</li> <li>2022 April 16 (beta 2) - fixes to overdrive, output saturation, and the synth filters. Filter resonance goes <em>much</em> higher now, overdrive kicks in more smoothly, and output saturation is gentler.</li> </ul> <h2>Features</h2> <ul> <li>Two vaguely 303-inspired monosynths</li> <li>One vaguely 808-inspired drum machine</li> <li>16 step pattern-based sequencer with slide and accent steps</li> <li>Pattern mode for real-time tweaking and song mode for recording your work</li> <li>Almost every control on the screen can be automated in song mode</li> <li>Per-synth overdrive insert effect</li> <li>Tempo-synced delay with 16th, triplet, and dotted-16th lengths</li> <li>Routable pattern-controlled lowpass/bandpass filter (like ReBirth's PCF)</li> <li>Master compressor to get the most out of your 8 bits of dynamic range</li> <li>Soft saturation on the output in case you try to get too much dynamic range</li> <li>Audio export</li> <li>Save/load functionality using the system clipboard (doubles as an easy checkpoint feature)</li> <li>Tooltips for most controls (can be turned on/off)</li> <li>Pico-8's PCM output filter is disabled so you can pretend that you have high frequencies</li> </ul> <h2>Known Issues</h2> <ul> <li>Occasional sound dropouts on M1 and M2 Macs, especially when running in the background. This appears to be a PICO-8 issue.</li> <li>Rarely, when re-enabling sequencing on a synth, a slide may not trigger correctly or a non-slide note may be played as a slide.</li> </ul> <h2>Compatibility Notes</h2> <h3>Web</h3> <p>Most features still work, but pointer lock does not (so large knob movements are difficult), audio recording time is limited, and some browser/platform combinations may have very glitchy audio. On some browsers PICO-8 may interpret pasted documents as keypresses instead of loading them into its clipboard buffer.</p> <h3>Future RP-8 Versions</h3> <p>Future versions may tweak the sound in various ways - if preserving your songs exactly is important to you, please keep your old RP-8 versions around. I'll try to avoid making major changes, though.</p> <h2>Thanks</h2> <p>... to the #music-sfx channel on the PICO-8 Discord, and <a href="https://www.lexaloffle.com/bbs/?uid=40166"> @packbat</a> in particular for testing, feedback, discussion, and encouragement. And to <a href="https://www.lexaloffle.com/bbs/?uid=29645"> @thisismypassword</a> for the essential-to-this-project shrinko8 minifier.</p> https://www.lexaloffle.com/bbs/?tid=47284 https://www.lexaloffle.com/bbs/?tid=47284 Thu, 07 Apr 2022 09:01:47 UTC