Generating a waveform in a buffer (array) & writing it directly to a line is probably the most space efficient way of getting sampled sound effects. However for music, you will need to keep checking the line & topping it up with the next note, which will use a bit more code. This also does not allow polyphonic sound (more than one note). To avoid clicks, each note must have attack & decay to zero.
I have had quite good results by generating an array of buffers with samples for each note across several octaves, then creating a buffer as long as the music track, then numerically adding the samples to it as required to make up the track. Create an AudioClip using the music track buffer & command it to loop indefinitely. SharpShooter16k used this technique. There is a slight difficulty when adding samples to the music track. This requires 16bit unsigned addition, but the buffer is in bytes. In SharpShooter I was already using NIO buffers for openGL & used those to map a byte buffer to a short buffer. For a 4k program, my best solution so far is to create the track using a normal int array, and then manually copy the values into a byte array.
You also need to store a set of note data to generate the track (frequency, length, start time). Currently mine is packed into an integer array, but this is very space inefficient. It would be better to encode this into a very long string. Must do this sometime
Oh... and you have to compose the tune of course. It helps to have some actual talent in this area
Unfortunately, having done all the above uses over 500 compressed bytes; much more for a long track. So It hasn't actually made it into any of my entries. Maybe soon, but I'm really really short on spare time