Log In  


Cart #impossible-2 | 2022-01-28 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
143

Impossible Mission R.T.

Discovered #pico8's secret 5512Hz 8-bit digital audio out API.

Created a homage to this legendary 80's masterpiece to celebrate.

Thanks zep!

143


2

:O


5

There have been so many amazing carts made for PICO-8. Yet somehow you have proven that we haven't scratched the surface of greatness until now. Absolutely incredible.


3

excellent finding!


14

I had made a cart privately a while back demonstrating the possibility of a wavetable/PCM software mixing engine taking a small fraction of the PICO-8's CPU budget, which could've possibly allowed MOD playback with samples outputted from the GPIO pins. With some updates, I can now finally hear what it's actually generating!

I was darn hoping there would be a way to play samples from RAM, but I never even thought it would be done through a serial channel. And I never bothered to look for undocumented serial channels!

Cart #sb06_soft_synth-0 | 2021-03-14 | Code ▽ | Embed ▽ | No License
14

Also, I came across a PICO-8 bug where the mute shortcut (CTRL+M) or the mute button on the BBS player doesn't mute the undocumented PCM DMA channel, but otherwise does mute the normal PSG audio. I don't know if it should use either the music or SFX volume in the config, but I'm assuming it would be used for short voice clips so the latter would be a good choice. But no less, can this bug be fixed @zep?


10

Very nicely done @carlc27843. And I can't imagine a more fitting demo cart ~~ it's perfect!

@StinkerB06 thanks, will fix that for 0.2.2d. (PICO-8 only observes the global volume setting, so it will be straightforward).


1

Thanks @zep, and very nice demo @StinkerB06!

I can't wait to see what other procedural audio the PICO-8 community comes up with.

The first person to create PICO-8-SID will be awarded a gold star personally delivered through the internet from me. ;)


1

This is so cool! I was actually just thinking the other day about whether I could wire PICO-8 up to some Javascript to play samples on cue; this would be a way to do that without the external gubbins.

...now I'm wishing I knew how to do, like, speech synthesis, because it'd be awesome to have a library for converting X-SAMPA phonetic transcription into PICO-8 serial audio.


1

I was sure that sample playback is possible! Now we can create synths!


1

how did you go about encoding audio into a string?


7

@tesselode that's a really good question. I have a custom build system but the audio conversion part boils down to:

  1. use ffmpeg (https://ffmpeg.org/) to convert to 5512hz sample rate and single channel, and output an ogg, e.g.
    ffmpeg -i inputpath -ar 5512 -ac 1 outputpath.ogg
  2. use stb_vorbis.c (https://github.com/nothings/stb/blob/master/stb_vorbis.c) stb_vorbis_decode_filename() to load the file into 16-bit samples
  3. for each sample do sample_p8 = (uint8_t)((sample_16>>8)+128)
  4. encode the sample bytes into a pico8 string and insert it in the code

The last step required some care:

  • 0 needs to be encoded as \0 {92,48} unless it is followed by a digit (48 through 57) in which case it needs to be encoded as \000 {92,48,48,48}
  • 10 needs to be encoded as \n {92,10}
  • 13 needs to be encoded as \r {92,13}
  • 92 needs to be encoded as \\ {92,92}
  • if you use ' as your quote character then 39 needs to be encoded as \' {92,39}
  • if you use " as your quote character then 34 needs to be encoded as \" {92,34}
  • otherwise the encoded byte can be the input byte
  • surround the encoded bytes with your favorite quote character

I kept bumping into the compressed code size limit and ended up storing 16128 bytes of audio data in rom. The pk function in the cart reads memory into a string using s..=chr(peek(a))

Oh and because of the limited rom/code size I reduced the sample bitcount. A couple of the clips use 5 bits per sample, and the C64 clips use 4 bits per sample. They are expanded to 8 bits at runtime in the updatemix function.

The cart explains but I should mention for searchability: use serial(0x808,address,length) to write your 8-bit samples to the audio output buffer. Use stat(108) to read how many bytes remain buffered for output. I believe at most 2048 bytes can be buffered.


another interesting aspect is how did you find? poking around? reverse engineering of pico code?

again, thanks for the finding, it puts my Another World/Out of this World port back on track!


2

Impressive ! Now if @zep will just let us play WAVs without all this complexity, we'll be all set.


1

@freds72 I think he was just poking around for look for undocumented serial channels, and when he did a write to channel 0x808, he heard a loud noise, assuming he was triggering some hidden audio capabilities.


1

@dw817 by my calculation, with the 32k cart size limit, you can't store very much raw audio directly - like, 32k uncompressed only buys you about six seconds. I think a lot of using serial audio samples is going to be about implementing the right compression tools, and I don't see how zep can know what the standard will be in advance.


6

@freds72/@StinkerB06 I was noodling with serial channels 0x804 (stdin) and 0x805 (stdout) trying to get realtime messaging with an external app working (to replace the DLL injected mqtt library I had been using but which was becoming a bear to maintain with zep's prolific updates). I thought I noticed that stdout was only being flushed at 30hz even though I had a 60hz cart so I decided to peek behind the curtain a little...

When I saw what was going on with 0x808 I felt like a kid who noticed the biggest most brightly wrapped present ever behind the tree on christmas morning. Couldn't believe my eyes so I wrote some data to 0x808 - static had never sounded so sweet, knowing that the PICO-8 community would be able to do some amazing carts with the channel. I immediately dropped everything to unwrap that gift and share it with my friends.

You'd think that present would be sufficient, but @zep put a pretty bow on it too. Channel 0x808 just like the famous Roland TR-808 drum machine from the early 80's. Stat 0x6c for the six-cee sounds everyone will be making with it!

I don't think @zep minds if we peek behind the curtain every now and then. If I ever stumble across more undocumented features I plan to only reveal them with entertaining carts that make good use of them.


indeed right on time for this side project of mine!


2

@carlc27843
I was wondering why you didn't convert straight to unsigned char pcm:

ffmpeg -i input.wav -ac 1 -ar 5512 -acodec pcm_8 -f data output.u8

seems straightforward? well, never got it to work. ¯\_(ツ)_/¯

but,

sox.exe input.wav -c 1 -r 5512 out.u8

works a treat!


2

@zep It also appears that using extcmd"audio_rec" to capture the audio output doesn't capture the PCM channel. Will that get fixed too?


3

@ultrabrite I couldn't find the correct incantation to get ffmpeg to the conversion directly to pcm u8 either. Great to know that sox does it, thanks for the tip.


This is Awesome! I can't believe I just got rick rolled in pico-8, looking forward to seeing the first pico-8 based DAW someday.


10

Excellent discovery ! So it is the also the open gate to Viznut ByteBeat ... :)

It is a bit crunchy in webplayer

Cart #bytebeat-5 | 2021-05-21 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
10

In Pico8, it sounds slightly better
https://www.youtube.com/watch?v=xpiwTpyF-ZU


4

I can’t believe I got RickRolled


1

Absolutely amazing! 100/10!! Best game I have EVER played!!!


1

...you know what this means, right?

We've gotta get the Software Automatic Mouth in Pico-8. We Gotta


How do you do that, furthermore how can I do that? Is there an application for doing that?


I wonder if, using a similar method to this, the entire Never Gonna Give You Up song could be emulated in PICO-8


This is easily one of the best versions I have seen of this game. Brilliant! I immediately shared with 3 friends.


This would be perfect for re-creating a Sega logo in PICO-8!


3

Advice: stat(109) returns the PICO-8 app audio buffer size divided by 4. In the _update() or _update60() function, you'll need to fill the PCM FIFO with stat(109)-stat(108) samples to ensure that playback is smooth regardless of the user's audio buffer size setting.

Here's an update to my synth demo that uses it:

Cart #stat_109_demo-0 | 2021-08-22 | Code ▽ | Embed ▽ | No License
3


The numbers at the bottom are CPU usage, number of currently-queued samples, and minimum number of samples to be queued to avoid crackling, obtained from stat() values 1, 108, and 109 respectively. Note that you may get visual glitches with the oscilloscope here.



Does synth cost lots of tokens to use? How much did it take for you to make those voice lines and how much tokens can they take up?


1

Yes! It is now our mission to bring this to as many other people as possible. Unexpected and perfect.


Hi @carlc27843 -- Just a heads up I updated this cart to impossible-2 to fix a breaking change in the p8scii commands: "\^." for dotty mode is now "\^=" for 'stripey' mode. 0.2.4b's "\^." is for printing a glyph, causing a garbage character to appear in impossible-1.


Thanks @zep, much appreciated. I'm curious how you found this use of it; do you grep all the carts?


Clever... TO clever


I use this to prank friends lol



[Please log in to post a comment]