Is there a variable type of half byte? Is there a workaround?
If the point is to save program storage space, you're probably going to have to live with some unreadable bit mush or do bit-swapping in your head. Here's a code example that encodes your same array as a 32-byte array, but you have to combine pairs of your original numbers into bytes. It's not especially difficult because each hex digit represents one of your original numbers.
I.e., 8,9 becomes 0x89. Likewise, A is 10, B is 11, etc. Then you can iterate 1 thru 64 and do some division and bit-shifting to pull out the original value you wanted. This will iterate through your 32-byte array and pull out 64 half-byte values.
    const byte wave[32] = {0x89,0x9A,0xBB,0xCC,0xDD,0xEE,0xEF,0xFF,0xFF,0xFF,0xEE,0xED,0xDC,0xCB,0xBA,0x99,0x87,0x76,0x55,0x44,0x33,0x22,0x21,0x11,0x11,0x11,0x22,0x23,0x34,0x45,0x56,0x77};
    for(int i=0; i&lt;64; i++) {
        byte val;
        if (i % 2) {
            // the little byte is first (LITTLE ENDIAN)
            val = wave[i/2] &amp; 0x0F;
        } else {
            // the BIG byte is second
            val = (wave[i/2] &gt;&gt; 4) &amp; 0x0F;
        }
        Serial.printf(&quot;%i=%i\n&quot;, i, val);
    }

NOTE: that the Endianness if your system may be different than mine. Most systems are little-endian these days, but you never know.