Musical Keyboard

-- MusicalNotes V6
--[[
Original concept by dave1707:
Allows you to move cursor forward or backward thru notes. You can also jump to the start or end of the notes, as well as delete notes.

Stuff by Scotty:
Notes are now selected via piano-style keyboard (three octives only) using a KeyBoard button class.
Music staff size can be scaled up or down (to a limit) via simple slider class control.
G- and F-clef symbols and keyboard can be had at pixabay.com
--]]


supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
    
    print("Set testing == true to:")
    print("View keyboard touch areas,\
Display note names.")
    testing = false
    
     -- Screen center
    X = WIDTH/2
    Y = HEIGHT/2  
    
    -- To locate and size piano image.
    wP    = 250
    hP    = 100
    xP    = X-wP/2
    yP    = Y-200
    diaP  = wP/7 -- diaP = width of keyboard sprite divided by 7 whole-note keys
    keySp = diaP
    whole =  .5
    sharp = 1.3
    
    -- Musical Note: The notes "B" and "E" do not have an associated sharp.
    nameTab={"C3","C3#","D3","D3#","E3","F3","F3#","G3","G3#","A3","A3#","B3", -- C3 octive
             "C4","C4#","D4","D4#","E4","F4","F4#","G4","G4#","A4","A4#","B4", -- C4 octive
             "C5","C5#","D5","D5#","E5","F5","F5#","G5","G5#","A5","A5#","B5"  -- C5 octive
            }

    
    -- C3 keyboard notes
    note_C3  = KBbutton(xP-wP+2+keySp*0.5,yP+diaP*whole, diaP/2,"C3",   1)
    note_C3s = KBbutton(xP-wP+2+keySp*1.0,yP+diaP*sharp, diaP/2,"C3#",  2)
    note_D3  = KBbutton(xP-wP+2+keySp*1.5,yP+diaP*whole, diaP/2,"D3",   3)
    note_D3s = KBbutton(xP-wP+2+keySp*2.0,yP+diaP*sharp, diaP/2,"D3#",  4)
    note_E3  = KBbutton(xP-wP+2+keySp*2.5,yP+diaP*whole, diaP/2,"E3",   5)
    note_F3  = KBbutton(xP-wP+2+keySp*3.5,yP+diaP*whole, diaP/2,"F3",   6)
    note_F3s = KBbutton(xP-wP+2+keySp*4.0,yP+diaP*sharp, diaP/2,"F3#",  7)
    note_G3  = KBbutton(xP-wP+2+keySp*4.5,yP+diaP*whole, diaP/2,"G3",   8)
    note_G3s = KBbutton(xP-wP+2+keySp*5.0,yP+diaP*sharp, diaP/2,"G3#",  9)
    note_A3  = KBbutton(xP-wP+2+keySp*5.5,yP+diaP*whole, diaP/2,"A3",  10)
    note_A3s = KBbutton(xP-wP+2+keySp*6.0,yP+diaP*sharp, diaP/2,"A3#", 11)
    note_B3  = KBbutton(xP-wP+2+keySp*6.5,yP+diaP*whole, diaP/2,"B3",  12)
    -- C4 keyboard notes
    note_C4  = KBbutton(xP+keySp*0.5,     yP+diaP*whole, diaP/2,"C4",  13)
    note_C4s = KBbutton(xP+keySp*1.0,     yP+diaP*sharp, diaP/2,"C4#", 14)
    note_D4  = KBbutton(xP+keySp*1.5,     yP+diaP*whole, diaP/2,"D4",  15)
    note_D4s = KBbutton(xP+keySp*2.0,     yP+diaP*sharp, diaP/2,"D4#", 16)
    note_E4  = KBbutton(xP+keySp*2.5,     yP+diaP*whole, diaP/2,"E4",  17)
    note_F4  = KBbutton(xP+keySp*3.5,     yP+diaP*whole, diaP/2,"F4",  18)
    note_F4s = KBbutton(xP+keySp*4.0,     yP+diaP*sharp, diaP/2,"F4#", 19)
    note_G4  = KBbutton(xP+keySp*4.5,     yP+diaP*whole, diaP/2,"G4",  20)
    note_G4s = KBbutton(xP+keySp*5.0,     yP+diaP*sharp, diaP/2,"G4#", 21)
    note_A4  = KBbutton(xP+keySp*5.5,     yP+diaP*whole, diaP/2,"A4",  22)
    note_A4s = KBbutton(xP+keySp*6.0,     yP+diaP*sharp, diaP/2,"A4#", 23)
    note_B4  = KBbutton(xP+keySp*6.5,     yP+diaP*whole, diaP/2,"B4",  24)
    -- C5 keyboard notes
    note_C5  = KBbutton(xP+wP-2+keySp*0.5,yP+diaP*whole, diaP/2,"C5",  25)
    note_C5s = KBbutton(xP+wP-2+keySp*1.0,yP+diaP*sharp, diaP/2,"C5#", 26)
    note_D5  = KBbutton(xP+wP-2+keySp*1.5,yP+diaP*whole, diaP/2,"D5",  27)
    note_D5s = KBbutton(xP+wP-2+keySp*2.0,yP+diaP*sharp, diaP/2,"D5#", 28)
    note_E5  = KBbutton(xP+wP-2+keySp*2.5,yP+diaP*whole, diaP/2,"E5",  29)
    note_F5  = KBbutton(xP+wP-2+keySp*3.5,yP+diaP*whole, diaP/2,"F5",  30)
    note_F5s = KBbutton(xP+wP-2+keySp*4.0,yP+diaP*sharp, diaP/2,"F5#", 31)
    note_G5  = KBbutton(xP+wP-2+keySp*4.5,yP+diaP*whole, diaP/2,"G5",  32)
    note_G5s = KBbutton(xP+wP-2+keySp*5.0,yP+diaP*sharp, diaP/2,"G5#", 33)
    note_A5  = KBbutton(xP+wP-2+keySp*5.5,yP+diaP*whole, diaP/2,"A5",  34)
    note_A5s = KBbutton(xP+wP-2+keySp*6.0,yP+diaP*sharp, diaP/2,"A5#", 35)
    note_B5  = KBbutton(xP+wP-2+keySp*6.5,yP+diaP*whole, diaP/2,"B5",  36)
    
    kbTab={}
    table.insert(kbTab,note_C3)
    table.insert(kbTab,note_C3s)
    table.insert(kbTab,note_D3)
    table.insert(kbTab,note_D3s)
    table.insert(kbTab,note_E3)
    table.insert(kbTab,note_F3)
    table.insert(kbTab,note_F3s)
    table.insert(kbTab,note_G3)
    table.insert(kbTab,note_G3s)
    table.insert(kbTab,note_A3)
    table.insert(kbTab,note_A3s)
    table.insert(kbTab,note_B3)
    
    table.insert(kbTab,note_C4)
    table.insert(kbTab,note_C4s)
    table.insert(kbTab,note_D4)
    table.insert(kbTab,note_D4s)
    table.insert(kbTab,note_E4)
    table.insert(kbTab,note_F4)
    table.insert(kbTab,note_F4s)
    table.insert(kbTab,note_G4)
    table.insert(kbTab,note_G4s)
    table.insert(kbTab,note_A4)
    table.insert(kbTab,note_A4s)
    table.insert(kbTab,note_B4)
    
    table.insert(kbTab,note_C5)
    table.insert(kbTab,note_C5s)
    table.insert(kbTab,note_D5)
    table.insert(kbTab,note_D5s)
    table.insert(kbTab,note_E5)
    table.insert(kbTab,note_F5)
    table.insert(kbTab,note_F5s)
    table.insert(kbTab,note_G5)
    table.insert(kbTab,note_G5s)
    table.insert(kbTab,note_A5)
    table.insert(kbTab,note_A5s)
    table.insert(kbTab,note_B5)
        
    keyTab={}
    
    js=button(X-250,80,"<<",20)
    bs=button(X-125,80,"<", 20)
    de=button(X,80,"Delete",20)
    fs=button(X+125,80,">", 20)
    je=button(X+250,80,">>",20)



    spacing = 16 -- initial line-spacing
    indent  = 50 
    keyPos  =  1
    dx      =  0
    cY      = 30
    

    
    -- slider related things
    sX  = WIDTH-75
    sY  = Y-150
    sW  = wP/7
    sH  = 100
    sLo = 8
    sHi = 32.5
    
    spacingSlider = Slider("Line-Spacing\
Slider",sX,sY,sW,sH,sLo,sHi)
    
end -- end of setup()



function draw()
    background(171, 171, 171, 255)

    noteSp  = spacing*2.5
    
    
    spacingSlider:draw()

    if testing == true then -- for testing
        -- origin of musical staff
        stroke(255, 0, 0, 128)
        strokeWidth(2)
        line(indent,HEIGHT,indent,HEIGHT-400) 
        line(0,500+cY,WIDTH,500+cY)
        
        -- musical staff slide zone
        line(0,HEIGHT-400, WIDTH,HEIGHT-400)
        
        -- touch locs
        fill(255, 0, 0, 128)
        pushStyle()
        textMode(CORNER)
        text("Red circles illustrate proper touch location on keyboard.", xP-wP,yP-20) 
        popStyle()
    end 

    
    pushMatrix()
        translate(0,500+spacing+cY)
        musicalStaff("G") -- 5-line musical staff with treble clef (G)
        translate(0,-spacing*6)
        musicalStaff("F") -- 5-line musical staff with bass clef (F)
        line(dx+50,spacing*4, dx+50,spacing*6) -- line that ties the two staffs together
        translate(50,-spacing*6.5)
        musicalNotes()
    popMatrix()
    
    popStyle()
    fill(0, 0, 0, 255)
    fontSize(16)
    text(string.format("Musical note %d of %d notes.",keyPos,#keyTab),X,125)
    popStyle()

    
    bs:draw()   -- back one space
    fs:draw()   -- forward one space
    de:draw()   -- delete a note
    js:draw()   -- jump to start
    je:draw()   -- jump to end
    

    spriteMode(CORNER)
    sprite("Dropbox:Piano",xP-wP+2,yP, wP,hP)   -- C3    
    sprite("Dropbox:Piano",     xP,yP, wP,hP)   -- C4
    sprite("Dropbox:Piano",xP+wP-2,yP, wP,hP)   -- C5       

    
    for z=1,#nameTab do
        kbTab[z]:draw()
    end    

    popMatrix()
        pushStyle()
        fill(0, 0, 0, 255)
        fontSize(12)
        textMode(RIGHT)
        translate(xP+keySp/2,yP+hP/2)
        rotate(90)
        text("Middle C (C4)",0,0)
        text("(C5)",0,-wP)
        text("(C3)",0,wP)
        popStyle()
    popMatrix()
        
end -- end of draw()



function touched(t)

    if t.y>HEIGHT-400 then
        if t.state==MOVING then
            dx=dx+t.deltaX
            if dx > 0 then dx = 0 end -- added to limit rightward movement of staff
        end
    end

    if t.state==BEGAN then
        bs:touched(t)
        fs:touched(t)
        de:touched(t)
        js:touched(t)
        je:touched(t)
    end
    
    if t.state==MOVING then
        spacingSlider:touched(t)
    end

    -- change "ENDED" to "MOVING" then slide your finger across the keyboard for a cool effect.
    if t.state==ENDED then
        for z=1,#nameTab do
            kbTab[z]:touched(t)
        end 
    end

end -- end of touched()
-- Original button class for notes and functions with minor mods
button = class()

function button:init(x,y,n,k)
    self.x=x
    self.y=y
    self.name=n
    self.key=k
end

function button:draw()
    sprite("Cargo Bot:Dialogue Button",self.x,self.y)
    fill(0, 0, 0, 255)
    text(self.name,self.x,self.y)
end

function button:touched(t)
    if t.x>self.x-50 and t.x<self.x+50 and t.y>self.y-25 and t.y<self.y+25 then
        
        -- function buttons
        if self.name=="<" and keyPos>1 then
            keyPos=keyPos-1
        end
        if self.name==">" and keyPos<=#keyTab then   
            keyPos=keyPos+1
        end
        if self.name=="Delete" and keyPos<=#keyTab and keyPos>0 then 
            table.remove(keyTab,keyPos) 
            if keyPos>#keyTab then
                keyPos=#keyTab
            end
            if keyPos == 0 then keyPos = 1 end -- added by Scotty
        end
        if self.name=="<<" then 
            keyPos=1
            dx=0
        end
        if self.name==">>" then 
            keyPos=#keyTab+1
        end
        
        if keyPos*(spacing*2.5) > WIDTH-(spacing*factor) then
            dx=WIDTH-(spacing*factor)-keyPos*(spacing*2.5)
        end
        
    end
end

-- Used for piano keyboard buttons. i.e., where on the piano key to touch.
-- By Scotty
KBbutton = class()



function KBbutton:init(x,y,rad,n,k)
    self.x    = x
    self.y    = y
    self.rad  = rad
    self.name = n
    self.key  = k
    
    
    factor = 9
end

function KBbutton:draw()
    --display ellipse for testing
    if testing == true then
        stroke(255, 0, 0, 255)
        strokeWidth(1)
        noFill()
        ellipse(self.x,self.y,self.rad) -- this highlights proper touch location, nothing more.
    end
    
end


function KBbutton:touched(t)
    if vec2(t.x,t.y):dist(vec2(self.x,self.y)) <= self.rad then
        -- individual notes
        if self.key < 37 then -- total number of keys on the keyboard plus 1
            if keyPos < #keyTab then
                table.insert(keyTab,keyPos,self.key)
                keyPos = keyPos+1
            else
                keyTab[keyPos] = self.key
                keyPos = keyPos+1
            end            
            if keyPos*(spacing*2.5) > WIDTH-(spacing*factor) then
                dx=WIDTH-(spacing*factor)-keyPos*(spacing*2.5)
            end
        end
    end
end
-- A simple slider to select a single spacing value within a specific range.
-- By Scotty
Slider = class()


function Slider:init(title,x,y,w,h,lo,hi)
    self.title = title
    self.x     = x
    self.y     = y
    self.w     = w
    self.h     = h
    self.lo    = lo
    self.hi    = hi
    
end



function Slider:draw()
    rectMode(CENTER)
    fill(255, 255, 255, 255)
    stroke(0, 0, 0, 255)
    strokeWidth(2)
    rect(self.x,self.y,self.w,self.h)
    
    fill(0, 0, 0, 255)
    fontSize(16)
    textAlign(CENTER)
    text(self.title,self.x,self.y-self.h/2-25)
    text(string.format("%.1f",spacing),self.x,self.y-self.h/2-50)
end



function Slider:touched(t)
    
    if  t.x>self.x-self.w/2 and t.x<self.x+self.w/2 and
        t.y>self.y-self.h/2 and t.y<self.y+self.h/2 then
        if  t.state==MOVING then
            spacing = spacing+t.deltaY
            -- limit the range of spacing to the defined hi and lo values
            if spacing > self.hi then spacing = self.hi end
            if spacing < self.lo then spacing = self.lo end
        end
    end
    
end


-- Misc functions
    
function musicalStaff(clef)
-- Draw 5-line staff and etc
    clef = clef -- G or F clef
    
--[[
    "spacing" refers to the vertical space between musical staff lines (controlled by the Slider)
--]]
        
    -- Locate and size G-Clef (treble clef) symbol relative to line spacing.
    xGClef = 2.2*spacing    
    yGClef = 1.8*spacing     
    wGClef = 4.5*spacing--375 orig size
    hGClef = 7.5*spacing--640 orig size

    -- Locate and size F-Clef (bass clef) symbol relative to line spacing (formerly "size").
    xFClef = 2.2*spacing   
    yFClef = 2.2*spacing    
    wFClef = 2.5*spacing--539 orig size
    hFClef = 3.5*spacing--640 orig size
    
    fill(0)
    strokeWidth(2) 

    
    pushMatrix()
        translate(indent ,0)
        for d=0,4 do
            stroke(0, 0, 0, 255)
            line(dx, d*spacing, WIDTH, d*spacing) -- staff lines
            for d=0,3 do
                line(dx, d*spacing, dx, d*spacing+spacing) -- vertical line
            end
        end
    
        spriteMode(CENTER)
        if clef == "G" then
            sprite("Dropbox:G_Clef", dx+xGClef, yGClef, wGClef, hGClef)
        elseif clef == "F" then
            sprite("Dropbox:F_Clef", dx+xFClef, yFClef, wFClef, hFClef)
        end
    popMatrix()
end





function musicalNotes()
-- Draw the musical notes

--[[
    "spacing" refers to the vertical space between musical staff lines (controlled by the Slider)
    "noteSp" refers to the horizantal space between notes.
--]]
    
    pushStyle()
    pushMatrix()
        --translate(indent,0)
        translate(spacing*3,0)
        for z=1,#keyTab do
            s=keyTab[z]
            pushMatrix()
                translate(z*noteSp+dx, s*spacing/2+spacing*5)
                stroke(0, 0, 0, 255)
                -- The following is to locate the notes properly on musical staff.
                -- I'm sure there is a better way to do this.
        -- C3 octive
                if nameTab[s]     == "C3"  then
                    translate(0,spacing*2.5)
                elseif nameTab[s] == "C3#" then
                    translate(0,spacing*2)
                    sharpSymbol()
                elseif nameTab[s] == "D3"  then
                    translate(0,spacing*2)
                elseif nameTab[s] == "D3#" then
                    translate(0,spacing*1.5)
                    sharpSymbol()
                elseif nameTab[s] == "E3"  then
                    translate(0,spacing*1.5)
                elseif nameTab[s] == "F3"  then
                    translate(0,spacing*1.5)
                elseif nameTab[s] == "F3#" then
                    translate(0,spacing)
                    sharpSymbol()
                elseif nameTab[s] == "G3"  then
                    translate(0,spacing)
                elseif nameTab[s] == "G3#" then
                    translate(0,spacing*.5)
                    sharpSymbol()
                elseif nameTab[s] == "A3"  then
                    translate(0,spacing*.5)
                elseif nameTab[s] == "A3#" then
                    translate(0,0)
                    sharpSymbol()
                elseif nameTab[s] == "B3"  then
                    translate(0,0)           
        -- C4 octive
                elseif nameTab[s] == "C4"  then -- this is what's called "Middle C"
                    translate(0,0)
                    pushStyle()
                    stroke(0, 0, 255, 255)
                    line(-spacing,0, spacing,0)
                    popStyle()
                elseif nameTab[s] == "C4#" then
                    translate(0,-spacing*.5)
                    sharpSymbol()
                    pushStyle()
                    stroke(0, 0, 255, 255)
                    line(-spacing,0, spacing,0)
                    popStyle()
                elseif nameTab[s] == "D4"  then
                    translate(0,-spacing*.5)
                elseif nameTab[s] == "D4#" then
                    translate(0,-spacing)
                    sharpSymbol()
                elseif nameTab[s] == "E4"  then
                    translate(0,-spacing)
                elseif nameTab[s] == "F4"  then
                    translate(0,-spacing)
                elseif nameTab[s] == "F4#" then
                    translate(0,-spacing*1.5)
                    sharpSymbol()
                elseif nameTab[s] == "G4"  then
                    translate(0,-spacing*1.5)
                elseif nameTab[s] == "G4#" then
                    translate(0,-spacing*2)
                    sharpSymbol()
                elseif nameTab[s] == "A4"  then
                    translate(0,-spacing*2)
                elseif nameTab[s] == "A4#" then
                    translate(0,-spacing*2.5)
                    sharpSymbol()
                elseif nameTab[s] == "B4"  then
                    translate(0,-spacing*2.5)
        -- C5 octive
                elseif nameTab[s] == "C5"  then
                    translate(0,-spacing*2.5)
                elseif nameTab[s] == "C5#" then
                    translate(0,-spacing*3)
                    sharpSymbol()
                elseif nameTab[s] == "D5"  then
                    translate(0,-spacing*3)
                elseif nameTab[s] == "D5#" then
                    translate(0,-spacing*3.5)
                    sharpSymbol()
                elseif nameTab[s] == "E5"  then
                    translate(0,-spacing*3.5)
                elseif nameTab[s] == "F5"  then
                    translate(0,-spacing*3.5)
                elseif nameTab[s] == "F5#" then
                    translate(0,-spacing*4)
                    sharpSymbol()
                elseif nameTab[s] == "G5"  then
                    translate(0,-spacing*4)
                elseif nameTab[s] == "G5#" then
                    translate(0,-spacing*4.5)
                    sharpSymbol()
                elseif nameTab[s] == "A5"  then
                    translate(0,-spacing*4.5)
                    line(-spacing,0, spacing,0)
                elseif nameTab[s] == "A5#" then
                    translate(0,-spacing*5)
                    sharpSymbol()
                    line(-spacing,0, spacing,0)
                elseif nameTab[s] == "B5"  then
                    translate(0,-spacing*5)
                    line(-spacing,0, spacing,0)
                end
    
    
                -- draw the note with it's stem
                line(-spacing/2, 0, -spacing/2, -spacing*3)
                rotate(30) -- for style points
                fill(0, 0, 0, 255)
                ellipse(0,0,spacing*1.25,spacing)
                -- display the notes's name if testing
                if testing == true then
                    rotate(-30)
                    fontSize(spacing*.5)
                    fill(255, 255, 255, 255)
                    text(nameTab[s],0,0)
                end
            popMatrix()
        end -- end of for loop
    popMatrix()

    -- cursor
    pushMatrix()
        pushStyle()
        strokeWidth(spacing*1.25)
        lineCapMode(SQUARE)
        stroke(255, 0, 0, 50)
        translate(spacing*3,0)
        line(keyPos*noteSp+dx,spacing*4.5, keyPos*noteSp+dx,spacing*19)
        popStyle()
    popMatrix()
end



function sharpSymbol()
    -- Build a sharp symbol from scratch since I could not find one to my liking online.
    -- Truth be told, I didn't spend much time looking.
    stroke(0, 0, 0, 255)
    strokeWidth(2)
    pushMatrix()
        pushStyle()
        scale(spacing *.075) -- quick and dirty way to adjust size according to line spacing
        translate(-16,-4)
        lineCapMode(SQUARE)
        line( 4,-10, 3,18)
        line(-3,-12,-3,16)
        strokeWidth(4)
        line(-6,-5,6, 0)
        line(-6, 5,6,10)
        popStyle()
    popMatrix()
end

That’s all there is, main plus four tabs.

This started out as a question answered by @dave1707 that morphed into what you see here. I started a new thread because the original is 2 1/2 years old.

Select notes via a piano-style keyboard and the notes pop up on a five-line staff. Two staffs really, bass and treble.

You can scale the staff up of down using the crude slider on the right. Setting the “testing” variable to true allows you to see the note names on the musical notes and the desired touch location on the keyboard.

The keyboard is limited to three octives due to time and space constraints. Maybe I’ll do a complete 88-key keyboard by dividing it two at middle C.

Note: The treble- and bass-clef symbols can be had at pixabay.com. Sorry that I could not provide then directly.

Enjoy.

@Scotty Looks good. That’s a lot of keying you did and it works great. You might want to specify where the keyboard is. I did a search for piano and looked for a small keyboard. I just happened to luck out and selected the correct one. At least I think it was the correct one. I don’t have time to play with it now, but I’ll do it later. Below is the keyboard I tried.

Thanks, @dave1707. The keyboard is also at pixabay. I’ll see if I can re-find it.

I think this is the keyboard I use. Follow this link: https://pixabay.com/illustrations/piano-vector-music-keys-802531/

I guess in the future I should save the URL in my source code.

@Scotty you should be able to export the project as a zip then attach it to the forum. I’ve added the files as part of the project assets and they should come across. Include any license files/terms and you should be ok

@West , I made minor mods (comments regarding links to the images I used) and figured out how to zip the project up. I’m not sure how to make it available to the forum. I’m not even sure what happens when I click on your zip file.

Thanks for your help on this. Zip looks like an easy way to share larger, multi-tab projects. All I have to do if figure out how to use it.

Thanks again.

@Scotty once you have the zip file (long hold and export from codea project selection page) then you can attach it to a forum post with the last button on the right along the menu bar (looks like a page with the corner folded over)

Tapping on the zip file in the forum on the iPad should take you to a page with a link to “Open in Codea” which will launch Codea and ask if you want to import it

Here is a Zip file for the above project.

@West, let me know if my link works because when I click on your link it goes nowhere. Might be user error on my part.

Thanks.

@West Your link worked for me. @Scotty Your link worked for me but there was no keyboard or clefs. Also when I load the code on my iPad Pro, the keyboard overlays the lines for the notes.

@dave1707, I made sure the three images were in my projects folder and redid the zip file. Hopefully they will come through this time.

As for the iPad Pro issue I’m not sure what is going on. I’m running a 3rd Gen iPad so my iPad has not seen an OS update nor a Codea update in forever. That’s the price I pay for running old technology.

Let me know if the new Zip changes anything.

Thanks.

@Scotty I didn’t look thru your code, but you might be positioning some things base on height or width and some other thing with a hard coded value. That has nothing to do with the iPad version, or OS version. So depending on the screen size, things can show up in different relations to other things. Normally if you want your programs to run on any device, you should position things based on width and height instead of hard coding values.

PS. Are you going to add a new zip file or update the one above.

@dave170, I try to locate things relative to screen center. I define that as X and Y (WIDTH/2 and HEIGHT/2). Also, location is relative to an image’s width and height. The piano is located relative to screen center. I modified the code so that the five blue nav/action buttons are also located relative to screen center. That little change may make some difference.

I also sized the treble clef, bass clef and notes based on line spacing and that is controlled using the slider on the right side of the screen.

I have re-Zipped the code so please try the new files. Also, please find the images I used. Since I’m not sure if they get automatically zipped if they are in the project assets folder I included them below.

If there is a specific graphics issue please let me know. I’m still learning.

Thanks.

@Scotty Your zip file didn’t include the keyboard or clefs. Those had to be loaded by themselves.

@dave1707, in my previous post I included the images as separate downloads because I was unsure that all works. I hope you found them and they were in the correct format.

Also, I hope the code edits made some sort of difference.