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:
" | | | | | | | | | | | |"