Log In  

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.

Cart #acid_jam_512-3 | 2022-06-22 | Code ▽ | Embed ▽ | No License

An entry to the Pico-8 512-Char Jam. Kick, hat, acid.

Jam entry
Itch page

Update 1: Moved the delay time slightly off the beat. Also saved a few characters thanks to @SmellyFishstiks, which let me thicken the oscilloscope line.

Update 2: Improved visualization and stability.

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#113246 2022-06-17 05:03 ( Edited 2022-06-22 21:08)


Really cool! I don't make "tweet"carts a lot so I find the use of the 2 labels really interesting having one for draw and one for grabbing the pcm

P#113247 2022-06-17 05:07

Thanks! Yeah, I needed to be able to skip synthesis if the buffer was full, and just sticking a label right before flip() seemed like the most expedient approach.

But now that you've got me looking at it, I've realized that just using a big if block actually saves a few characters, so if I make any more changes to this I should probably do that instead. Thanks for making me think about this a bit more!

P#113248 2022-06-17 05:39

gah! I like the labels though but glad I could help!

P#113249 2022-06-17 05:41

Cart #tweet_acid_jam-2 | 2022-06-22 | Code ▽ | Embed ▽ | No License

With enough sacrifices it's possible to get this down to tweetcart length! I'll probably noodle on this one a bit before actually posting to Twitter, I think I can get this down a few more chars and maybe use those to get some of the quality back?


  • No delay
  • No hihat
  • Tuning is less accurate and there are fewer possible notes
  • Synth plays every 16th note instead of only sometimes
  • No oversampling
  • 2-pole instead of 4-pole filter
  • No saturation in filter
  • Simpler visualization (dots instead of lines, no color)
  • Favoring shorter values over better-sounding values

The lessons learned from the tweet-shortening process also got the 512-char version down to 487 characters, which is probably enough space to do something interesting.

Update 1: visualization with dots instead of circles, less flickery display.

Update 2: slightly improved visualization and sound.

P#113254 2022-06-17 08:09 ( Edited 2022-06-22 03:28)

Infinitely listenable. So good.

P#113386 2022-06-19 19:48

@bikibird Thank you! I'm really happy that you enjoyed it.

P#113472 2022-06-22 03:30

Whoa this is super cool! Do you fill the audio buffer manually or how do you manage to do this? Oh and do you have somewhere where I can read about it if I want to do it myself?

P#113478 2022-06-22 08:07

So so cool!
THAT is my jam @luchak

I had a go at the tweetcart version and brought it down to 268bytes

x=0y=0p=0g=0::_::n=min(512-stat(108),188)for i=0,n-1do
goto _
P#113481 2022-06-22 08:50

Why didn't I learn about this Pico8 512 chars jam before :p

P#113482 2022-06-22 09:00

@p01 Nice! I think I have some real ?-blindness, I'll have to remember these tricks for next time. :) Glad you liked it!

Sending 1 byte at a time let me shave another 8 bytes:

x=0y=0p=0g=0::_::for i=0,min(511-stat(108),187)do
goto _
P#113490 2022-06-22 15:04 ( Edited 2022-06-22 15:14)

@Wistpotion Yeah, this is using the PCM output - the last paragraph of this comment gives a summary of how to use it. Looking at the #pcm tag should also turn up a bunch more examples.

Here's an annotated version of the source (with @p01's improvements) if that helps:

x=0 y=0 -- Filter internal state
p=0 -- Oscillator phase
g=0 -- Samples left in beat
::_:: -- Label for start of frame

-- Make sure we have at least 512 samples in the buffer, but also don't get
-- too far ahead. Since we clear the screen every frame, the output will be
-- very flickery if we skip synthesis too often. 5512.5/30=183.75, but I've
-- found that adding a few extra samples helps avoid audio dropouts.
for i=0,min(511-stat(108),187) do

-- 646 samples per 16th note at 128 bpm.
-- q is the oscillator phase increment, chosen from a bag of pitch ratios
-- quantized to 1 decimal place.
-- e is the filter envelope amount, which is modulated with an LFO.

-- 2584 samples per beat at 128 bpm.
-- k is the kick drum amplitude. 62 is just what sounded best to me.

k*=.999 e*=.999 -- apply decay to kick amplitude and filter env
g-=1 -- advance sample counter
o=p>>11 -- we use overflow for osc phase reset, so we need to scale down
o-=9*(y-o) -- filter feedback (so we have some nice resonance)
x+=e*(o-x) y+=e*(x-y) -- this filter is just 2 1-pole filters in series

-- Mix in the kick drum. The cubic exponent was necessary to get a reasonable
-- amount of pitch decay. 64 is added since we need offsets of 64 and 128
-- later and adding one offset here helps keep the char count down.

poke(0,v+64) -- write output audio to memory
serial(2056,0,1) -- send audio byte to output
p+=q -- increment oscillator phase
?"+",i,v,9 -- draw oscilloscope dot
?"⁶1⁶c0" -- end frame and clear screen
goto _ -- next frame
P#113492 2022-06-22 15:34 ( Edited 2022-06-22 19:01)

@luchak thanks a bunch, reading super minimized code is still a bit hard for me, but that helps a ton. Thanks!

P#113720 2022-06-27 10:16

[Please log in to post a comment]