ASCII piano keyboard

JavaScript (ES6), 155 149 147 bytes

n=>[`_`[r=`repeat`](n*4+(9>>n%7&1)),s=[...Array(n*12/7|0)].map((_,i)=>1998>>i%12&1?` |`:`  |`).join``,s,s,s,s=`   |`[r](n),s,`___|`[r](n)].join`\n|`

Where \n represents the literal newline character. Leverages the fact that all the lines after the first start with a | character. Explanation:

f=
n=>[                        // Start by building up a list of rows
 `_`[r=`repeat`](n*4+       // 4 underscores per key
  (9>>n%7&1)),              // Third and seventh keys have one extra
 s=[...Array(n*12/7|0)]     // Calculate total of white and black keys
  .map((_,i)=>              // Process each key in turn
   1998>>i%12&1?` |`:`  |`  // Bitmap of narrow and wide keys
  ).join``,                 // Join the keys together
 s,s,s,                     // Repeated 4 times in total
 s=`   |`[r](n),            // Full width part of the white keys
 s,                         // Repeated twice in total
 `___|`[r](n)               // Base of the white keys
].join`\n|`                 // Join the rows together
<input type="number" oninput="o.textContent=f(this.value);"><pre id=o>

Edit: Saved 2 bytes by fixing my misreading of the spec on the height of the keys.


Pyth, 68 65 63 bytes

*lJ:+\|s@Lj;*L" |"_j4536 7*4Q" $"k\_jb+*4]J*2]K+\|*Q"   |":Kd\_

Try it online!

Test suite.

In this version, I just substituted the assignments (J and K) inside to save 2 bytes. Therefore, read the version below.

Previous 65-byte version with explanation

J:+\|s@Lj;*L" |"_j4536 7*4Q" $"kK+\|*Q"   |"*lJ\_jb+*4]J*2]K:Kd\_

Try it online!

J:+\|s@Lj;*L" |"_j4536 7*4Q" $"k    This part generates the most irregular line.

        j;*L" |"_j4536 7            Generate the whole line by black magic
      @L                *4Q         Get the first (4*input) characters of it, with wrapping.
  +\|                               Add "|" in front of it (we took away the first "|")
 :                         " $"k    Replace the ending space by nothing
J                                   Store the line to J.


K+\|*Q"   |"      This part generates the line just below the irregular line.
    *Q"   |"      Repeat "   |" input times
 +\|              Prepend "|"
K                 Store to K


*lJ\_     Now we can actually start printing

*  \_     Repeat "_" ...
 lJ                      [the length of J] times
          (and implicitly print it out)


jb+*4]J*2]K

   *4]J             Repeat J 4 times
       *2]K         Repeat K 2 times
  +                 Concatenate them together
jb                  Join with newlines
                    (and implicitly print it out)

:Kd\_

:K      Replace in K
  d                  " "
   \_                    by "_"
        (and implicitly print it out)

Black magic

We find the irregular line from input=7, and cut out the first "|":
"  | | | |  |  | | | | | |  |"
 2  1 1 1 2  2  1 1 1 1 1 2

j;*L" |"_j4536 7    Black magic.

         j4536 7    4536 converted to base 7: [1,6,1,4,0]
        _           Reverse: [0,4,1,6,1]
  *L" |"            Repeat " |" <each element> times:
                    [""," | | | |"," |"," | | | | | |"," |"]
j;                  Join by whitespace:
                    "  | | | |  |  | | | | | |  |"