Desmos, 148 116 bytes
The viewport has been manually changed to x=0 to 20, and y=0 to 12, because the audio trace feature in Desmos is affected by the viewport (the song will become distorted if the viewport is moved or zoomed in/out). I'm not sure if that contributes to the byte count or not. For now, I'm going to assume that it doesn't affect byte count, but please let me know otherwise if this isn't the case.
A=join(F(0,7,9,7,x),F(5,4,2,0,x))
B=F(7,5,4,2,x)
F(a,b,c,d,x)=\join([a,b,c]\{x<1,1.1<x<2.1\},d\{x<2\})
join(A,B,B,A)
Try It On Desmos!
Try It On Desmos! - Prettified
I focused on both song quality and code length (basically, shortest code in which the audio still sounds good).
To play the audio, click the join(A,B,B,A)
expression (it should be outlined in blue). Then press ALT+T, and after that, H, after which you will hear the audio play if everything is done correctly.
Big thanks to @hyper-neutrino for helping me find the sequence of numbers that represents the notes in chat. I was having a very hard time finding that myself; I don't know a thing about music lol.
Explanation
This answer takes advantage of one of Desmos's accessibility features: Audio Tracing, which can play any graph as a sound. By plotting horizontal line segments at specific places in the viewport, the audio tracing will be able to play that line segment as a single note for a certain duration, depending on how long that line segment is. Specifically, the viewport is split as follows:
Bottomest vs toppest lines of the graph correspond to the range of an octave... the 12 steps within this range correspond to the half-tones in the music scale. (Source)
As I am not familiar with music at all, I pretty much have no idea what this means, but hopefully that is understandable to all of you that know music.
The next part is to actually find the sequence of y-values so that it will play the song. As I mentioned above, hyper-neutrino basically did all the work and found the correct sequence of y-values which play the song (I pretty much have no idea how he found them; something about intervals and semitones?). The sequence is as follows:
0 0 7 7 9 9 7, 5 5 4 4 2 2 0, 7 7 5 5 4 4 2, 7 7 5 5 4 4 2, 0 0 7 7 9 9 7, 5 5 4 4 2 2 0
where every 7th note (the note before each comma, and the last note) is a half note, meaning it is played twice as long as the other notes, which are quarter notes. Graphically, this means that the line segment that represents a half note is twice as long as that of a quarter note.
With that out of the way, the next thing to do is to actually put all of this into Desmos. So how are we going to do this? Well, first I found that a line segment of length 1 is long enough for a note, so each quarter note will be length 1, while each half note will be length 2.
Secondly, we will need to put a short pause in between every note, or else two repeated notes will just play as one half note instead. I decided to use a 0.1 length pause in between each note.
My plan was to construct a huge list of line segments which Desmos can graph and audio trace over.
A pattern I noticed with the notes is that every 7 notes always follows a a a b b c c d (half note)
pattern. To take advantage of that, I made a function F
which takes in 4 notes a,b,c,d
and constructs a list of line segments in accordance to that pattern. Let's take a look at it:
F(a,b,c,d,x)=\join([a,b,c]\{x<1,1.1<x<2.1\},d\{x<2\})
The function F
takes first takes in 4 notes a,b,c,d
, then x
because we are plotting something (the function won't work without it).
Let's first take a look at the first part of the function:
[a,b,c]\{x<1,1.1<x<2.1\}
Because of the list [a,b,c]
, this entire expression results in a list of 3 horizontal line segments: one segment at y levels a
, b
, and c
. Now let's take a look at the domain restriction. It splits the lines y=[a,b,c]
into two parts: one where x<1
and another where 1.1<x<2.1
, effectively splitting it into two line segments of length 1 with a 0.1 gap in between them (the viewport is from x=0, so x<1
is functionally the same as 0<x<1
). The audio trace will first play the x<1
segment (one quarter note), then a very short pause later, play the 1.1<x<2.1
segment (another quarter note). It does this for a
, then b
, then c
.
Finally, this list is joined with d\{x<2\}
, which is a line segment of length 2 at y level d
. This will play the note d
for twice as long, emulating a half note.
With a full understanding of function F
, we can now encode the number sequence shown earlier with F
.
First note that the first 14 notes (0 0 7 7 9 9 7, 5 5 4 4 2 2 0
) are repeated at the end as well. Also, the middle 14 notes (7 7 5 5 4 4 2, 7 7 5 5 4 4 2
) is just 7 7 5 5 4 4 2
repeated twice.
We can encode 0 0 7 7 9 9 7
as F(0,7,9,7,x)
and 5 5 4 4 2 2 0
as F(5,4,2,0,x)
. By joining the two resultant lists and storing it in a variable A
, we can re-use these 14 notes at the end of the song.
We can encode 7 7 5 5 4 4 2
as F(7,5,4,2,x)
and set it to a variable B
so that we can re-use these notes.
Finally, we can join the notes like so: join(A,B,B,A)
to get the final sequence of notes. Desmos will then automatically graph all the line segments in the resultant list, which we can then audio trace over.