There are 88 keys on a standard piano and 95 printable ascii characters (hex codes 20 through 7E):
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
('character' refers to any printable-ASCII character from here on)
In this JSFiddle I've taken advantage of that and made a simple syntax that generates piano tunes using AudioSynth. (If anyone can direct me to a linkable set of real piano note sounds I'll be grateful.)
Each character in the input string besides () 01+-
corresponds to one piano key:
CHARACTER: ! " # $ % & ' * , . / 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
KEY NUMBER: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
NOTE: A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C C# D D# E F F# G G# A A# B C
OCTAVE: 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 7 8
So RPNPRRR
plays the first 7 notes of Mary Had a Little Lamb using the preset timing parameters you can see in the JSFiddle.
Space (
) represents a musical rest that lasts for one note interval. So RPNPRRR PPP RUU
plays the first 13 notes of Mary Had a Little Lamb with rests in their proper places.
If any character besides ()01
is prefixed by a sequence of 0
's and 1
's (regex [01]+
), that sequence is read as a binary number b, and the character is replaced with b copies of itself. So 101A11 10+1-0B01C
becomes AAAAA ++-C
because 101
= 5, 11
= 3, etc. (A sequence of 0
's and 1
's at the end of the string has no effect.)
Matched parentheses (()
) serve two purposes:
- If their content does not end with a sequence of
0
's and1
's, all the notes are played at the same time as a chord (which otherwise is no different than a note). So(NQU)
is a C minor chord on octave 4.
If duplicate notes are present their sound is also duplicated. So(NN)
and(NNN)
sound different. - If their content does end with a sequence of
0
's and1
's, that sequence is read as a binary number b, and the parentheses and their content are replaced with b copies of the content. So(NQU11)
becomes 9 individual notes:NQUNQUNQU
.
Parentheses Details:
- Nesting replicating parentheses (purpose 2) is fine:
(N(QU10)11)
→(NQUQU11)
→NQUQUNQUQUNQUQU
. - Nesting non-replicating parentheses (purpose 1) is fine but has no effect:
(A((+)C))
is the same as(A+C)
. - You can also combine both:
((N(QU10))11)
→(NQUQU)(NQUQU)(NQUQU)
. - A sequence of
0
's and1
's before non-replicating parentheses repeats them in the same way individual characters are repeated. So10(NQU)
becomes(NQU)(NQU)
. - A sequence of
0
's and1
's before replicating parentheses has no effect. (
must always have a matching)
, but not vice-versa: e.g.N)
is valid.
Plus (+
) and minus (-
) respectively increase and decrease the the duration of notes or the time interval between notes, depending on their context:
- When inside non-replicating parentheses, they immediately increase or decrease the note duration variable by some preset number of milliseconds (see JSFiddle). So
(++)N
will playN
at a longer duration than normal. - When outside non-replicating parentheses, they increase or decrease the interval between the start of the next note and the note after it (and each subsequent interval) by some preset number of milliseconds. So in
++NP
the interval between theN
andP
is longer than usual.
The duration of notes and the time interval between them cannot drop below 0.
Challenge
I intentionally chose () 01+-
to be the 7 special characters because they can be innocuously placed in many contexts in lots of programming languages.
Your task is to write a quine in 512 bytes or less that produces the best sounding tune when the code itself is used as the input string in the JSFiddle.
You may choose any initial values (non-negative integers) for the 4 interval/duration parameters, but your tune must not last more than 10 minutes. You should also tell us if your tune sounds best in a particular instrument.
Rules
- Only tabs, newlines, and printable-ASCII are allowed in your code. All non-printable ASCII is ignored by the tune creator.
- Output may go to a file or stdout or the closest alternative (e.g. JS alert). There is no input.
- No reading of source code. It must be a true quine.
- The removal of any 3 contiguous source characters must make the program no longer function as a quine. This is to ensure people don't write a good song in a string then have a tiny quine portion to output it.
- So if your program was
MYCODE
thenMYC
,MYE
,MDE
, andODE
should all not be quines (they may error or output something else).
- So if your program was
This is a popularity-contest, the highest voted answer wins.
Update: Relaxed last rule.