Hurdy Gurdy music app

Iv been working on a Hurdy Gurdy app for playdate
been working with Sam Wain to get some good sounding gurdy string sounds
heres a video of it in action.

I built it by having all the note loops loaded on init then set there volume to 0. from there i set the note value to the rate of change of the crank and if a button is pressed.

I based most of my understanding about the gurdy from this video

Key things,
-usualy 1 melody string active at a time.
-drone string, like the bagpipes, just drones in the bg
-trumpet string, a percusive elemetn that onyl activates if the crank moves quickly

Just gona leave this bit of code here too
checks if nothing is being pressed
playdate.getButtonState() == 0

You can toggle the drone and trumpet strings in the menu at the momeetn and i hope to add
-more scales
-trumpet threshold
-transpose (this is in code just need to link to menu)
-choice of skins, add a few different looks to the gurdy

but just realized u can only do 3 items in the menu :confused: mabie need to make a menu button to open the actual ingame menu then make that

then should probubly save all that and let u reset it too.


Neat! Sounds pretty authentic to me!

(What if reverting to G didn't happen on releasing the current button, but only on pressing the current button a second time? Like each button "locks" a note whether held down or not, then "unlocks" to G on a second press?)

Hmm interesting, could be worth a try but think it could be aquard to play. I was gona add a slight delat to jumping back to open g, hopefuly that will stopit jumping back or some kinda reset on crank stop.

The dealy idea would make songs like thunder struck not work but most other would. So could have that ad a toggle depending i. The song your trying to play.

1 Like

It's fun thinking about how to more with limited controls!

FWIW... one more and then I'll stop!

What if the 1st 4 notes were the d-pad... and then the next note was (B)... and then the second-to-last note was (B)+(A) together... and then the 7th note was just (A)? (Or the note requiring 2 buttons could be the last one... but (B)+(A) being in between its separatr components sounds convenient.)

Can't wait for this app!

1 Like

Im trying to get an options menu working.
Iv got the basics working from this tutorial

But i would like to have the text labels update in the list to show whatch key/ transpose number etc

droneOnD = "Off"
local listItems = {"Gmajor",("Drone:"..droneOnD), "trumpet","","","" }
I set up my list like this
droneOnD is a

this always shows off on the label

Whats the call i need to get the text in the list up update?

Is this what you need?


that may be but figured it out a different way.
realised i was only setting it initaly
local listItems = {"Key: Gmajor",("Drone: "..droneOnD), ("Trumpet: "..TrumpetOn),("<Gurdy Skin: 1>".. GurdySkin),("<Trumpet Active: ".. TrumpetSensitivity.. ">"),("<Transpose:".. TransposeAmount..">"),("<DetuneBackCrank:".. deTune..">"),("<Open Delay:".. gDelayCap..">") }

then never actualy setting the list = to new values,
I made a function that just calls that again and added it to my button input code, still didint update instantly it waited till the next grid view needs update, ie if i move up or down

--if gridview.needsDisplay then

    local gridviewImage =,200)    pd.timer.updateTimers()


        gridview:drawInRect(0,0,210,200)--this makes it draw




so for the meantime i just comented out the stuff that makes the lst only draw when it needs to.
whitch on device realy seems to tank the cpu but its just in the menu so not to botherd for now, il fix it later :stuck_out_tongue:

i I did also make this features video for tiktok and twitter yesterday, gettingprity close to done i think

I added a tweekable dealy setting for jumping back to the open g string. but that make me realise i probubly need a tail off period for all the notes as they stop abrubptly. also an overide to play the open g ifu stop cranking quickly then crank


been a while since i updated this.

Thanks to help from ☆Mina ☆ on the squad discord finaly got the wheel animating in both directions in my app for playdate

Heres the code for refrence of making an animation play forward and backward based on the crank

function spriteWheel:update()
local i = spriteWheel.i + 1
if change > 5 then
i = (i - 1) % #spriteWheelImages
spriteWheel.i = i + 1
if change < -5 then
i = (i + 1) % #spriteWheelImages
spriteWheel.i = i + 1


I also added a couple of requested features,
U can now chose the point where the acceleromiter decided where to switch to the high octave string and whitch axis it uses in the options menu.

last thing to figure out is how to add more scales, Not sur the way iv built it so far is rubust enough to do this withoght a lot of copy pasting which could cause troubles when updating in future but if it works noone needs to know and future me can deal with the ramifications.

1 Like

I was getting anoyed having to bring up the system menu to get into options all the time so added a shortcut to get there when u dock the crank
still need to make it not auto boot back to menu when u press b, would kinda like a crank was just docked function call

if optionsOn == false then
        if playdate.isCrankDocked()then
            --menu = true
            optionsOn = true

and i had some long decimal numbers on the floats so found a way to truncake a flat in lua
TransposeAmount = 5.252678 --your var
-- will give 5.25

1 Like

FWIW, playdate.crankDocked() is called on docking, if you want to define it.

And better yet, input handlers can include crankDocked = function() even though that's currently missing from the input handler docs. I have used this successfully in my Playtime clock app.

(In both cases, crankUndocked works too.)

1 Like

Im having a weird issue where some of the menu options are effecting others. the menu i still tanking performance when active
heres a gif. it changes the skin when i click the scale.
as far as i can see in the code they are completely unlinked and the gridvidew seems to know what option its on. Sometimes the maj minor images get broken too and ether overlap or go missing.

if pd.buttonJustPressed(pd.kButtonA)then
        if gridview:getSelectedRow() == (1) then
            if KeyScale == "GMaj" then
                KeyScale = "GMin"
                hgSprite:moveTo(-200, 120)
                hgminSprite:moveTo(200, 120)
                hgnatSprite:moveTo(-200, 120)
            elseif KeyScale == "GMin" then
                KeyScale = "GNat"
                hgSprite:moveTo(-200, 120)
                hgminSprite:moveTo(-200, 120)
                hgnatSprite:moveTo(200, 120)
            elseif KeyScale == "GNat" then
                KeyScale = "GMaj"
                hgSprite:moveTo(200, 120)
                hgminSprite:moveTo(-200, 120)
                hgnatSprite:moveTo(-200, 120)


I was wondering weather things could be getting garbled coz the cpu usage is high when menu is open or weather its likely something else?

Ok figured it out finally,
I was using the name hgSprite for both the major info sprite and the bg sprites. Think its all good now

Its out now on itch

1 Like

Bought it! I like it! (And I love the visual styles of your instruments!) Just one thing: I was confused when I opened the app because I wanted to close the options menu with B, but it kept opening again. Turns out I had the crank docked and needed to undock it. Not sure if this is intentional?

1 Like

Thanks, yip i know thats a thing just didint fix it. A couple peopl have mentioned it too. Il try to get a patch out soon.

1 Like