   @wcp: (n) ->
     floor((n + 7) / 12 * 7)
 
+  # the inverse of wcp: given a wcp number,
+  # translates to a midi key position.
+  @mcp: (n) ->
+    ceil(n / 7 * 12) - 7
+
   # A code for the shape of the key number.
   # C,D,E,F,G,A,B are 1,2,3,4,5,6,7 and
   # C#,D#,F#,G#,A# are 8,9,10,11,12.
   @keyshape: (n) ->
-    [1,8,2,9,3,4,10,5,11,6,12,7][n % 12]
+    [1,8,2,9,3,4,10,5,11,6,12,7][((n % 12) + 12) % 12]
 
   # A colorful color to use for the key number.
   @keycolor: (n) ->

###

class Keyboard extends Sprite
  constructor: (options = {}) ->
    # default key width
    defwidth = if options.kh?
        (options.kh / 5)
      else
        10
    # Calculate some geometry constants for the keyboard:
    @kw = options.kw ? defwidth          # white key width
    @kh = options.kh ? @kw * 5           # white key height
    @bkw = options.bkw ? @kw * 3 / 5     # black key width
    @bkh = options.bkh ? @kh * 3 / 5     # black key height
    @lowest = options.lowest ? 21        # midi num for lowest key
    @highest = options.highest ? 108     # midi num for highest key
    @hlw = (options.lw ? 1.6) / 2        # half line width
    @horiz = @calcHoriz()                # {left, right} boundaries
    @ckw = (3 * @kw - 2 * @bkw) / 3      # top width of the c key
    @fkw = (4 * @kw - 3 * @bkw) / 4      # top width of the f key
    # Render the keyboard as its own sprite
    # that can be moved around.
    super
      width: Math.ceil(@horiz.right - @horiz.left + @hlw * 2)
      height: Math.ceil(@kh + @hlw * 2)
    do @drawall

  # Calculates the bounding left and right pixel positions

    # Here we compute it exactly for white keys and get
    # the closest white key position for black keys.
    # Black keys will further modify startx below.
    startx = @halfex + @kw * Keyboard.wcp(n) - @horiz.left
    starty = @halfex
    ks = Keyboard.keyshape(n)
    # key shapes are modified for the lowest
    # and highest keys on the piano.
