DEV Community

JoeStrout
JoeStrout

Posted on

Mini Micro speaks like a droid!

A video went viral this week showing two AIs talking to each other, as if on the phone (see here). They start in English, but once they realize they are both AIs, they switch into an artificial "language" called Gibberlink (or more formally, GGWave). I was immediately fascinated because it sounds basically like the droids (e.g. R2-D2) from Star Wars — but this is real!

I went to the GGWave project page, and discovered that they have a web service that returns a GGWave sound file for a given message (along with some other options, like whether to use the slow or fast version). Mini Micro supports web services. So let's do this!

Make your Mini Micro talk like a droid

Fire up Mini Micro (if you don't already have it, download it here), and paste in this code at the prompt:

http.get("https://ggwave-to-file.ggerganov.com/?m=Hello%20world!").play
Enter fullscreen mode Exit fullscreen mode

You should hear a bunch of bleeps and blurps that are how you say "Hello world!" in droid speak. It's so easy!

Fancy it up

But I couldn't leave it there. I wanted to wrap up that call in a handy say function, so I could just do things like say "whatever" and have it play the appropriate sounds. And then, to be kind to the server, I decided to cache the sounds so that if you ask it to say the same message twice, it only hits the server once. I ended up with this code:

import "stringUtil"

_cache = {}  // key: url; value: sound

getGGWaveSound = function(message, protocolId)
    url = "https://ggwave-to-file.ggerganov.com/?m=" +
      message.urlEncode +
      "&p=" + protocolId
    if not _cache.hasIndex(url) then
        _cache[url] = http.get(url)
    end if
    return _cache[url]
end function

say = function(message, fast)
    if fast == null then fast = message.len > 16
    if fast then protocolId = 2 else protocolId = 1
    getGGWaveSound(message, protocolId).play
end function

if locals == globals then say "Hello world!"
Enter fullscreen mode Exit fullscreen mode

Still pretty simple! The other feature I added was support for the two protocols (fast and slow). If you don't specify, then the say function will speak (in Gibberlink!) fast if the message is over 16 characters, but slowly if it's shorter than that. I found this to be a pretty nice balance, letting short messages like "Hello" take their time, but switching to faster talk for longer speeches.

Still not fancy enough

Then, I felt it needed some visuals... and I thought about this post from late 2023 where I showed how to do lip-syncing in Mini Micro. What would it look like if an AI spoke in Gibberlink, but still moved its mouth as if speaking normally? I had to know!

So I cloned the code from that project, and made a few minor changes:

  1. I added import "ggwave" at the top, to bring in the code we wrote above.
  2. In place of file.loadSound, I create the speech file this way:
msg = "Hello! This is the MiniScript Control Program," +
  char(13) + "wishing you a very happy day."
speech = ggwave.getGGWaveSound(msg, fast)
Enter fullscreen mode Exit fullscreen mode
  1. I also added some code to print the message as it plays, character by character, for the benefit of us poor humans who can't actually understand Gibberlink.

(Twist this open to see the complete code.)
import "ggwave"

if not globals.hasIndex("fast") then fast = false

clear
mainImage = file.loadImage("mcp.png")
gfx.drawImage mainImage, 480-mainImage.width/2, 320-mainImage.height/2

jawSprite = new Sprite
jawSprite.image = file.loadImage("mcp-jaw.png")
jawSprite.x = 541; jawSprite.y = 151
jawSprite2 = new Sprite
jawSprite2.image = jawSprite.image
jawSprite2.x = 411; jawSprite2.y = 151
display(4).sprites = [jawSprite, jawSprite2]

list.swap = function(i,j)
temp = self[i]
self[i] = self[j]
self[j] = temp
end function
c = jawSprite2.corners
c.swap(0,1); c.swap(2,3) // (flips the image horizontally)
jawSprite2.setCorners c

openMouth = function(amount)
c = jawSprite.corners
dy = 32 * amount
c[0][1] = c[1][1] - dy // bottom inner corner
c[3][1] = c[2][1] - dy // top inner corner
jawSprite.setCorners c
c = jawSprite2.corners
c[0][1] = c[1][1] - dy // bottom inner corner
c[3][1] = c[2][1] - dy // top inner corner
jawSprite2.setCorners c
end function

//speech = file.loadSound("happyNewYear.ogg")
msg = "Hello! This is the MiniScript Control Program," +
char(13) + "wishing you a very happy day."
speech = ggwave.getGGWaveSound(msg, fast)
charsPerSec = msg.len / (speech.duration - 0.5)
text.color = "#88AAAA"
startTime = time
speech.play
amount = 0
while speech.isPlaying
a = speech.amp
target = a * 5 // (found experimentally)
amount = (amount + target*4) / 5
openMouth amount
charsToShow = (time - startTime) * charsPerSec
text.row = 2
print msg[:charsToShow]
yield
end while
openMouth 0
text.row = 2
print msg




And the result is the video you see at the top of this post. You can see that I also ran the waver app on my phone, which understands Gibberlink — the message from Mini Micro appears on my phone as soon as it's done speaking.

How cool is that?!

You can now make Mini Micro speak like a droid, and transmit messages or data to any Gibberlink-savvy device within hearing distance.

I'm not sure what I'll use this for, but I'm certain my future includes robots and AIs chattering away in Gibberlink — perhaps with a trusty protocol droid to interpret for me (when I'm not near the display panel of my X-wing fighter, of course). And if I don't start seeing (er, hearing) Gibberlink easter-egg messages in indie video games, I shall be sorely disappointed.

What do you think? Have any ideas for cool uses for this new technology? Share your thoughts in the comments below!

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post