13
\$\begingroup\$

Output "Mozart - Alla Turca" to stdout (see the sample for "reference implementation")

Try to find how to pack both synthesizer and the music into minimal size.

Requirements:

  • Format suitable for feeding into aplay -f cd (signed 16-bit little endian, 2 channels);
  • Entire music should be played (no skipped notes or parts, at least not less than in sample program), polyphony is not required though;
  • Can't just call /usr/bin/timidity, /usr/bin/sox or something like that (e.g. require to install a special music module);
  • Can't access network or assume that the music is available locally;

"Reference implementation" with parsable score: https://gist.github.com/vi/5478693
(Old sample Perl program: https://gist.github.com/vi/5447962)

\$\endgroup\$
  • \$\begingroup\$ Do you have a link to sheet music? \$\endgroup\$ – beary605 Apr 23 '13 at 23:44
  • \$\begingroup\$ No currently, I was typing the sample program by listening and trial&error. Now looking for... \$\endgroup\$ – Vi. Apr 24 '13 at 0:56
  • \$\begingroup\$ For example, this. \$\endgroup\$ – Vi. Apr 24 '13 at 0:59
  • \$\begingroup\$ Also, I assume you've already realised this, but everyone is going to use square waves. \$\endgroup\$ – Peter Taylor Apr 24 '13 at 7:12
  • 2
    \$\begingroup\$ Note: the arrangement in the linked score is pretty useless for anyone trying to implement this with only one voice. I've downloaded various MIDI files and they don't agree on all of the notes - they can be in the same key, but disagree on some notes by 4 semitones! To make this a well-specified problem it really needs a single canonical score (preferably in some easily parsed format, so that implementers can convert it to a format convenient for their implementation without introducing transcription errors). \$\endgroup\$ – Peter Taylor Apr 27 '13 at 7:35
11
\$\begingroup\$

Polyphonic, Haskell, 2826 3177 4719

Audio output: https://www.dropbox.com/s/nba6489tfet740r/hs-golf-turca.ogg

Features:

  • All notes from the right hand. I could of course add the left hand, too (done that).
  • Proper articulation of the staccato notes etc.
  • Reasonably nice sound with dynamics. Not just simple volume modulation, but proper morphing of the attack character and overtone content, like you get on a real piano actually, rather more... hey this piece is supposed to be imitating Turkish Janissary bands, right?
  • Reverb. Doesn't sound amazingly great, but not too bad, either.
  • Dynamic compression. Don't ask...
  • Dithering of the output. This is kind of ridiculous: with proper 16-bit resolution, hardly anybody would hear the quantisation artifacts, but to avoid including the binary library, I effectively use only 7-bits resolution, which I can cover with ASCII output. The dither itself is rather loud, no noise-shaping...
  • Multithreaded calculation of polyphonic chords.

import Control.Parallel
main=mapM_ (\(d,s)->(\p->p>>p>>p>>p).putChar.toEnum.round.(+d).(*62).min 2.abs$s+1).zip(dθ 1).lim.rev.hgp 9. pl 9e6 (\_->0) . ä
 $[mT%8.1,t2%16.1,t3(∡7)%8,t4%8,t5%16,t3(∡7)%8,mT%8.1,t2%16.1,t3(tev arp8)%8,cdT%99] >>= \e->[e,e]
mM=ä[2-^8,1-^8,0-^8,1-^8,3-^4]
cM=ä[7-^20,8-^20,9.^4,F[(7,0),(6,1)](map((∡2).(.^4))[6,5,6])%0.75]
cMv=ä[10-^2,8.^4,9.^4,hom(.^4)[[24,5],[23,8,12],[22,4],[21,6,9],[22,3],[19,5,8],[20,4],[18,6,9],[17]]#7&(-14)%2.5,tr 2%0.4,1-^9,2-^12,1-^1]%4.5
 ⋎(ä[6-^4,lp(8.^4∡3)%(3/4),sil%2,lp(5.^4∡3)%h,lp(5.^4∡2)%h,1-^1∡7]&(-14)#7#4%5)
mMa f=ä[(1-3*f).^4,lp(5.^4∡(-2-f))%0.75,mMa f%1.5,mMa(f*2)%h,mMa f%1]#7
mTm=ä[mM%1,mM&2%1,mM#4&4%h,mM&7%h,mM&7%1,8.^4,ä[10.^4]%0.2,cM%1,cM%1,cM%0.85,ä[4.^4∡2,5.^2]#6#4%2]#7
mT=p$ä[mTm%8.1⋎(ä[sil%h,mMa 0%4,mMa 1%2.75,2.^4,(-2)-^2]&(-7)%8)]
m2=ä[ä(map((∡2).(.^4))[1,2,3,3]++[es[6,5,4,3]%h]++[0-^2∡2])%2
 ⋎(ä[sil%h,1.^4,8.^4,3.^4,10.^4,5-^2]⊿1.3&(-14)%2)]
t2=p$ä[m2&2%1.8,0-^5,m2&2%2,m2#7%1.8,(-2)-^5,m2#7%2,mT%3.5,cMv]
m3=ä$[3-^4,4-^4,5-^2]++map(-^4)[3,4,5,4,3,2,1,2,3,4,2,0]
m3a=ä[(ä[sil%(1/8),lp(8.^4)%1]:zw(\d n->ä[sil%(d/24),n-^1]⊿cos d)[0..][1,3,5],s),m3a%1]
m3ra=(map((%1). \[a,b,c]->es[a,c,b,c,a,c,b,c])[[1,3,5],[1,4,6],[-2,0,5]]!!)
t3 o=ä[ä[o$ḋ[m3%4,m3%2.5,1-^4,4-^4,2-^4,0-^4]&(-2)%7.5,1-^2∡7]%8
 ⋎(ḋ[sil%(3/8),m3a&4%2,m3a%h,m3a#4%h,m3a&1%1,m3a&4%2,m3a%h,m3a&1%(5/8),5-^2]&(-18)%8)]
mQ=es[2,1,0,2]
m4=mM⇆4
i4 e=ḋ[m4⇅11%h,m4⇅9%h,mQ⇆4⇅8%h,F[(5,e),(4,1)][mQ⇅7%h,mQ⇅5%h,m4&5%h,m4&7%h]%2,es[10,9,10,9]#2%h ]
mla[b,c,d]=ä[b-^4,lp(c-^4⋎(d-^4))%1]%1
i4a=ḋ[sil%h,ä(map mla[[1,3,5],[2,4,5],[1,3,5],[0,2,5]])#5%4,ä(map mla[[1,3,5],[2,5,7],[2,6,8]])#4%3,5-^2⋎(7-^2)]
t4=p$ä[ḋ[i4 1%4,i4 0%2.5,ä[mQ⇅6%h,mQ⇅4%h]#4#2%1,3-^2]%8⋎(i4a&(-9)%8)]
mlaa=mla[1,3,5]
m5=ä$map(-^8)[1..4]
i5=ḋ[m5⇅6%h,m5%h,m5&4%h,m5⇅9%h]
i5d=hom(-^4)[[2],[4,5],[0],[4,5]]%1
i5a=ḋ[sil%h,mlaa,i5d,mlaa,mla[-2,0,4],mlaa,i5d,sq 4[1,-1,-3,-2,-6,1]%2]&(-7)
t5=ḋ[ḋ[i5%2,i5%1.5,ä[8-^4,9-^4]#1%h,i5%2,ḋ[es[5,4,3,2,3,5,1,3,2,4,0,2]%2]%1.5,1-^2]%8⋎(i5a%8)
 ,p(ä[ä[i4 1%4,es[3,2,3,1,4,3,4,3,4,3,4,3]#2#1&7%1.5,m5⇅13%h,mQ⇅8%h,m5&7%(3/8),6-^8,mQ⇅7#5%h,6-^2]%8
 ⋎(ä[i4a%3.5,F[(1,-1),(7,0),(6,1)][hom(-^4)[[-2],[3,5],[2,5],[1,5]]%1]%1,mla[-3,1,4],mla[-3,2,4],hom(-^4)[[-2],[1,3],[-2],[2,4],[1,3]]%1.5]&(-9)%8)])%8]⊿0.8
am d=3-^d∡2∡5
amf=1-^υ∡2⋎(5-^1∡3)
vh v(c,d)=lp(ä[v-^12]:map(\t->ä[t⊿0%0.04,t%d])c,d)
aam=vh 11.am
aar=ä[1-^10,4-^10,6-^1]&4
eam=vh 10.em
dm=6-^1∡2⋎(11-^1)
em d=5-^d∡2⋎(9-^1)
cdM=ḋ[4-^8,3-^8,2.^8,3.^8,cdM%1]
cdT=ḋ[ä[3-^(8/3)∡7,10-^6,am 1,am 1,cdM&7%1,dm,aam 4.05%1,em(4/3),12-^4,am 1,am 1,cdM&7%1,dm,aam 1%1,eam 4%1]%12.5⋎(ä(sil%(11/24) : map((%1).(m3a&))[4,4,4,0,4,1,4,4,4,0,4,1])&(-18)%13.1)
 ,p(ä[ä[ä[8-^2]⊿2%h,aar%(3/8),10-^8,aar%1,aar%1,cdM&7%1,11-^1,vh 11(10-^4)%1,9-^(4/3)]%7⋎(ä(map m3ra[0,0,0,0,1,0,2])&(-7)%7)])%6.75
 ,ä[p(ä[12-^4])%(1/4),am 1,am 1,cdM&7%1,dm,aam 1%1,eam 4%1,amf,ä[3-^4,1-^υ,5-^4,1-^υ,3-^4,1-^4,3-^4,1-^4,5-^4,1-^2]%3.75∡7,ä[amf∡(-14)]%0.56,ä[amf∡(-14)]⊿0.8%1]%12⋎(ä(sil%(1/8):map((%1).(m3a&))[4,4,4,0,4,1,4,4,4]++[m3a&4%h,m3a&4%h,5-^(8/5)])&(-18)%12)]
type D=Double
data F=N Int D|F[(Int,D)][([F],D)]
φ⇸F a fs=F a$map(\(f,d)->(map φ f,d))fs
_⇸N i d=N i d
i##c
 |i<1=(i+7)##c/2
 |i>7=(i-7)##c*2
 |1>0=1.06**(c i+case i of{1->0;3->3;4->5;5->7;6->8;7->10;_->fri i})
pl dur acc(N n v)=(\ω η->map(sin.(\x->x+τ x^2/η). \i->v*exp(-i*η/s)*τ(i*v)*(0.8-τ((i-dur)/90))*sin(i*ω))[1..dur])(n##acc/15.5).exp$fri n/9
pl dur acc(F accm fs)=pl' dur (foldr(\(q,m)f i->if q==i then m else f i)acc accm) fs
pl' dur _ _|dur<=0 = []
pl' dur _ []=map(\_->0)[1..dur]
pl' dur acc((f,dr):fs)|n<-min dr dur=trans(round n)(foldr1(\a b->sum a`par`sum b`pseq`zw(+)a b)(map(pl(n+99)acc)f))$pl'(dur-dr)acc fs
trans n a b|(f,ol)<-splitAt n a,(or,l)<-splitAt 99 b=f++zw(+)ol or++l
fri=fromIntegral
F a fs#q=F((q,1):a)fs
N i d&n=N(n+i)d
f&n=(&n)⇸f
N i d⇅n=N(n-i)d
f⇅n=(⇅n)⇸f
N i d⇆_=N i d
F a fs⇆n=F a.reverse$take n fs
N i d⊿v=N i$d*v
f⊿v=(⊿v)⇸f
p=(⊿0.3)
n.^q=([F[][([N n 1],s/2/q)]],s/q)
n-^q=([N n 1],s/q)
(l,d)⋎(r,_)=(l++r,d)
(l,d)∡j=(l++map(\h->ä[h⊿0%0.01,h&j%100])l,d)
f%t=([f],s*t)
tr n=F[]$cycle[n-^15,(n+1)-^20]
ä=F[];ḋ=F$zip[6,3,7][1,1,1]
lp=ä.repeat
sil=N 0 0
tev f(l,d)=(map f l,d)
h=1/2
υ=4/3
s=4e+4
sq d=ä.map(-^d)
es=sq 8 
arp8 n@(N i v)=F[][([n,ä[n⊿0%(1/8),n&7⊿(v/υ)%100]],s)]
arp8 f=arp8⇸f
hom q=ä.map(foldr((⋎).q)$sil%1)
dθ l=2*asin l/pi:dθ(abs.sin$l*1e+9)
rev ls=(\z->z id(foldr(\m sg->(\v->z(*v)(map(*0)[0..m*14349]++sg)sg)$abs(cos$(m*3)^2)-0.6)ls.take 9$dθ 1)ls)$(.lwp 3 0).zw.((+).)
lwp ω c(x:l)=c:lwp ω((x+c*ω)/(ω+1))l
lwp _ _ _=[]
hgp ω l=zw(-)l$lwp ω 0 l
lime e(x:l)
 |abs(e*x)>1,e'<-((e*8+abs(1/x))/9)=e':lime e' l
 |1>0=e:lime((e*49999+1)/5e4)l
lime _[]=[]
lim ls=zw(\a u->τ$a/9+max(-2)(min 2$a*u)/6)(map(*0)[0..500]++ls).lwp 9 0.lime 1$hgp 9 ls
zw=zipWith
τ=tanh

$ make
ghc -o bin/def0-hs def0.hs -O2 -fllvm -threaded
[1 of 1] Compiling Main ( def0.hs, def0.o )
Linking bin/def0-hs ...
time sh -c 'bin/def0-hs +RTS -N4 > hsoutp.pcm'
189.39user 138.41system 2:06.62elapsed 258%CPU (0avgtext+0avgdata 6440240maxresident)k
0inputs+0outputs (0major+403037minor)pagefaults 0swaps
ffmpeg -loglevel panic -y -f s16le -ar 44.1k -ac 2 -i hsoutp.pcm hsoutp.ogg


Here's a partially ungolfed and commented version: https://gist.github.com/leftaroundabout/5517198.

\$\endgroup\$
  • \$\begingroup\$ Nice try. 2970 UTF-8 bytes, 2826 code points. As it is not a competitor for <600 python version, it could be better geared it towards nicer sound/polyphony (keeping it under 5000 bytes, for example). \$\endgroup\$ – Vi. Apr 26 '13 at 15:35
  • 1
    \$\begingroup\$ @Vi. If you consider as "length of a program" the number of bytes when UTF-8 encoded then I think you should state that in the question. Just to make clear, since some people do not use this definition(e.g. every APL programmer...) \$\endgroup\$ – Bakuriu Apr 26 '13 at 16:43
  • \$\begingroup\$ @Bakuriu Yeah, right LOL. \$\endgroup\$ – Soham Chowdhury Apr 27 '13 at 17:35
  • \$\begingroup\$ That was insane! I would love to get some idea how this program works. \$\endgroup\$ – shiona May 4 '13 at 9:30
  • \$\begingroup\$ @shiona: it's actually not that obfuscated, with type signatures it should be easy enough to understand for anyone familiar with Haskell and basic DSP. \$\endgroup\$ – ceased to turn counterclockwis May 4 '13 at 11:22
7
+50
\$\begingroup\$

Python, 331+286 = 617 (0.548 bytes per note)

My solution uses a data file and a python script. The data file should be used as input to the script. I don't have aplay, but it works when I import it as raw data in Audacity with signed 16-bit PCM, little-endian, and 2 channels.

The data file is 331 bytes. Here's a python script which outputs it:

import sys
sys.stdout.write('\x08\x1c\x9d\xb9"\xc7\xea\xf0\xb7)\xc0D!u\x0bB~\'\x91S\xb2\x0c\xe9\xf8T;\xfd\xc13\xcf\xb9\xa6r>\xbc\xc5\xb4\xbb\xf8\xa4\x9a\x05H\xa0\x1d\x0eIq\t\\+\t\xdbn\x03\xc3&\x98\xa0\x11\xc5\xaa\xef\xbcSR^\x13\xe7\xc7\x0e\xc0\xa9^\x91Z\xfc\x02\x11\xb9\x1bE\xfc/=\xb8\xaf5<\x12\xa2\xc4\x02\xec\xdcO\xc2a\x04<Q\xfd\xe9L\xbc\xab%\xf5wX1F\xa6\x88\xddP\xfec(_#\xb4\x0bN\xba&m\xe3\xa4\x08Q\xdb\xd9\xf3<Q\xc6\xf6\x0e\xd7\xacd\x1f"g\xce\xae.\xb0\x90{|\x04\xc5X\xe6x>\xefE\xc8\xb0\xd2?N\x83?\x04\x86"a\xcc\x9b\x8fq\x9c\xce\xa2\xb6f\x9ab\x92\x9e:\xc0S\xcd\th\xb1\x87\xecT\x9d\xf4\n\xaf\xc9$`E5\xcc\xc5\xa0m\xcc\n8\xf8:\x03\xf5\x02H\xf3k\xe5\x86\xa64\x90\xa2\xc2w\xfa\xb7\xc0\x1e*2\x93\xca\x12\xe3^!\xd5yQ,LXW\xb4\x96D\x8dB\x9c`\xbf\x96`s;\xb7}\xeb\x8c\xebI\xa0o\x00\x08\xfe\xf1\xd2M3}\x8e\xd0\xda\x97\'\xca\x83-\x14\xda\xa1ET\n\xe8\xc7@\x1c\xa2a\xbb\xa7\x1b\x014\xdcz\xc7\xa6\xc4\x1d\x18\x04\r\xb1\x9e\xe3\xd0\x18<\x98`N?a\xe4\x8e\x9d\xd5\r\xe7Z[\xf4\xed\xf1PQ')

Here's the python script:

import sys
k=0
m=185
p=[]
q=[]
for c in sys.stdin.read():k=k*256+ord(c)
while k:
    v=k%m;k/=m
    if v<184:q+=[v]
    elif v-m+1:q+=p[v-184]
    else:m+=1;p+=[q];q=[]
for n in q:r=[1,2,3,4,6,8,12,15,16][n%9]*2000;sys.stdout.write(''.join(chr(int(i*1.06**(n/9)/4.3)%99)for i in range(r*3))+'\0'*r)

Note: If you're running Windows, use the -u switch for both scripts since stdin and stdout are dealing with binary data.

\$\endgroup\$
  • \$\begingroup\$ Good job. Considering 331 + 286 + 10(for tying together the file and the script) == 627. \$\endgroup\$ – Vi. Apr 26 '13 at 3:07
  • \$\begingroup\$ You can shorten a bit using os.read/write instead of sys.stdin/stdout. \$\endgroup\$ – Bakuriu Apr 26 '13 at 16:39
  • \$\begingroup\$ +50 for the beautiful compression scheme. Using a grammar-based approach without entropy encoding I can't get that short just on the note values, without taking into account the lengths. \$\endgroup\$ – Peter Taylor May 1 '13 at 22:32
  • \$\begingroup\$ Can you describe how you compressed the data? I'm interested in knowing how you got it so small. \$\endgroup\$ – Sir_Lagsalot May 3 '13 at 16:37
  • 1
    \$\begingroup\$ @Sir_Lagsalot: it's basically a nested / recursive dictionary, i.e. you have motifs consisting of notes (pitch and length encoded in one number), then you have themes that contain these motifs and/or single notes, then parts consisting of themes etc.. My program uses essentially the same principle (expanded by transpositions, inversions etc.), just not further compressed into a tight binary file; I've simply made everything top-level variable definitions instead. \$\endgroup\$ – ceased to turn counterclockwis May 3 '13 at 18:52
4
\$\begingroup\$

GolfScript (129 + 369 = 498 bytes)

Both program and data file include unprintable characters, so I'm going to give Base64 and xxd representations.

Program (129 bytes):

MjU2YmFzZSA2OWJhc2VbMDpOXS8oNDMse1xbMSQpXS9cMiQ9Kn0vXCwpey19KyUuLDIvL3ppcHt+
TisyNSU6Tid7goqSm6SuuMPP2+j2/0FFSU1SV1xcYWdtdCc9OmY7MTc2MCosey41MD4qZioxNy8u
Li59JScnOm4rcHV0c30v

0000000: 3235 3662 6173 6520 3639 6261 7365 5b30  256base 69base[0
0000010: 3a4e 5d2f 2834 332c 7b5c 5b31 2429 5d2f  :N]/(43,{\[1$)]/
0000020: 5c32 243d 2a7d 2f5c 2c29 7b2d 7d2b 252e  \2$=*}/\,){-}+%.
0000030: 2c32 2f2f 7a69 707b 7e4e 2b32 3525 3a4e  ,2//zip{~N+25%:N
0000040: 277b 828a 929b a4ae b8c3 cfdb e8f6 ff41  '{.............A
0000050: 4549 4d52 575c 5c61 676d 7427 3d3a 663b  EIMRW\\agmt'=:f;
0000060: 3137 3630 2a2c 7b2e 3530 3e2a 662a 3137  1760*,{.50>*f*17
0000070: 2f2e 2e2e 7d25 2727 3a6e 2b70 7574 737d  /...}%'':n+puts}
0000080: 2f                                       /

Data (369 bytes):

LoDJFvCRQqNdL7+JDvjtSkX4HBS2FwgvjfdxAHrF1/DcMIBtG/g7QZBLLYHpzgaWaM1TaHwbtxG+
l1lqsL3A8nuprtpPI20YbHm3lf7NxmYNdEIMTlhwTG+TlSn802DzN3YgIwbcKbtty9gWmF2nVS55
iJHQZd4HCcokoLRwH1g2XqP8Yo5xj5/YQm9DH85obUv47mii5n+PwsoJZ6yaz4eSpGps6dQMl+Pa
YP/WC6cVDBBGs3vq5cGe51H2u7oVArFuHrsI2sHkGNYHlhWudKn5RRvJhe3sxfrtQE/MekKRuZBt
f4B9qdyss66vFipSi1zf2MXF9A/CzwvMQ/t9PEtxw8kzxxikp2Ek3kc9TiamLl+iG2vjdWp84JzY
Mg6cE+3bFI4kVdn+d1NEnBR/S9HMnksgEc9sdAcyWsbSaGjwetwGTr7UXkpKO9aHF01D2i5pCO40
/keR0+a+NsBEOXZfatpXav44AJjalywtLeWu

0000000: 2e80 c916 f091 42a3 5d2f bf89 0ef8 ed4a  ......B.]/.....J
0000010: 45f8 1c14 b617 082f 8df7 7100 7ac5 d7f0  E....../..q.z...
0000020: dc30 806d 1bf8 3b41 904b 2d81 e9ce 0696  .0.m..;A.K-.....
0000030: 68cd 5368 7c1b b711 be97 596a b0bd c0f2  h.Sh|.....Yj....
0000040: 7ba9 aeda 4f23 6d18 6c79 b795 fecd c666  {...O#m.ly.....f
0000050: 0d74 420c 4e58 704c 6f93 9529 fcd3 60f3  .tB.NXpLo..)..`.
0000060: 3776 2023 06dc 29bb 6dcb d816 985d a755  7v #..).m....].U
0000070: 2e79 8891 d065 de07 09ca 24a0 b470 1f58  .y...e....$..p.X
0000080: 365e a3fc 628e 718f 9fd8 426f 431f ce68  6^..b.q...BoC..h
0000090: 6d4b f8ee 68a2 e67f 8fc2 ca09 67ac 9acf  mK..h.......g...
00000a0: 8792 a46a 6ce9 d40c 97e3 da60 ffd6 0ba7  ...jl......`....
00000b0: 150c 1046 b37b eae5 c19e e751 f6bb ba15  ...F.{.....Q....
00000c0: 02b1 6e1e bb08 dac1 e418 d607 9615 ae74  ..n............t
00000d0: a9f9 451b c985 edec c5fa ed40 4fcc 7a42  ..E........@O.zB
00000e0: 91b9 906d 7f80 7da9 dcac b3ae af16 2a52  ...m..}.......*R
00000f0: 8b5c dfd8 c5c5 f40f c2cf 0bcc 43fb 7d3c  .\..........C.}<
0000100: 4b71 c3c9 33c7 18a4 a761 24de 473d 4e26  Kq..3....a$.G=N&
0000110: a62e 5fa2 1b6b e375 6a7c e09c d832 0e9c  .._..k.uj|...2..
0000120: 13ed db14 8e24 55d9 fe77 5344 9c14 7f4b  .....$U..wSD...K
0000130: d1cc 9e4b 2011 cf6c 7407 325a c6d2 6868  ...K ..lt.2Z..hh
0000140: f07a dc06 4ebe d45e 4a4a 3bd6 8717 4d43  .z..N..^JJ;...MC
0000150: da2e 6908 ee34 fe47 91d3 e6be 36c0 4439  ..i..4.G....6.D9
0000160: 765f 6ada 576a fe38 0098 da97 2c2d 2de5  v_j.Wj.8....,--.
0000170: ae                                       .

Explanation

I've mangled the (updated) supplied score (more on that later) into a single string containing bytes with values from 0 to 24. The note lengths come first; then the note values, represented mod 25 and difference-encoded. The reason for the difference encoding is so that passages which are repeated in transposition will be reduced to the same sequence and can be compressed.

I then ran this through a string-to-GolfScript compression program which I've mentioned before (and which I improved in order to be competitive in this golf) to get the data file, which is decompressed by the first part of the program:

256base 69base[0:N]/(43,{\[1$)]/\2$=*}/\,){-}+%

It's a simple grammar expansion of a type which is familiar to anyone who's looked at many questions tagged .

I then split this string into pairs [length note] and iterate through the pairs. The non-printable characters come from a magic string which contains frequency parameters for the notes: I'm using GolfScript's implicit truncation mod 256 of integer arrays which are converted to strings to produce a triangle wave*, so the base frequency is 22050/256 Hz. I wrote a program to find integer ratios which give a good tuning; the magic string contains numerators, and the denominator 17 is the same for all notes. The average tuning error is about 3.4 cents.

The note lengths are represented as is, and are much more plausible than the previous version of the score. As I suspected, the rounding has increased the redundancy in the string and shortened the compressed data file by 30 bytes, not to mention saving the lookup array. However, there are still some passages which I find suspicious:

72 13

or

71 9
69 2
71 2

give bars which are a sixth of a crochet longer than the rest of the bars in the score, and

85 9
85 4
85 24
85 23

or

83 18
88 7
85 24
85 23

are an integral number of bars, but with some dubious offsets.

The program could be slightly shorter. I have deliberately chosen to trade in shortness for execution time. With some speed improvements to the GolfScript interpreter which I've submitted to Darren Smith and which I believe he plans to publish at some point, the current version runs in less than 15 minutes on my computer. If I don't puts each note after generating it then it runs much slower.

* I hereby confess that my comment about everyone using square waves was wrong.

\$\endgroup\$
  • \$\begingroup\$ How to properly run GolfScript? I try base64 -d <<< 'MjU2Y.....9Lw==' | golfscript and it says golfscript:405:in 'scan': invalid byte sequence in UTF-8 (ArgumentError) (the same if I save the program to file, of course) \$\endgroup\$ – Vi. May 3 '13 at 22:48
  • \$\begingroup\$ Note lengths are extracted from MIDI file using crude algorithm (see the comment to the play.pl). I'll fix the notes lengths to be sane. \$\endgroup\$ – Vi. May 3 '13 at 22:54
  • \$\begingroup\$ Updated the gist. Now minimal length of the note is 1. \$\endgroup\$ – Vi. May 3 '13 at 23:15
  • \$\begingroup\$ If I try to run using online interpreter (the inserted code looks like 㔲戶獡⁥㌷慢敳せ为⽝㐨ⰴ屻ㅛ⤤⽝㉜㴤紪尯⤬⵻⭽⸥㈬⼯楺筰乾㈫┵为笧誂鮒꺤쎸��䇿䥅前屗慜浧❴㨽㭦∩ĦĂ༃ጔ؏༆ณؕḧ⸘研��⒖✏㰢⭻⩽㐴Ⱚ⹻〵⨾⩦㜱ⸯ⸮╽✧渺瀫瑵絳/), I get undefined method class_id' for nil:NilClass` \$\endgroup\$ – Vi. May 3 '13 at 23:29
  • 1
    \$\begingroup\$ And there's no way it will run in the online interpreter - that will time out. \$\endgroup\$ – Peter Taylor May 4 '13 at 8:30
2
\$\begingroup\$

x86 Machine Code - 513 Bytes

This doesn't fully meet the challenge, since instead of outputting in a format suitable for feeding into aplay, it plays the midi.

Executable .COM file and asm source code - It may take up to 14 seconds for the music to start. It will also play a little slow, since the timer resolution is 1/18th of a second.

The music is encoded in 375 bytes using Fibonacci coding and a dictionary composed of the previously decoded music.

Pseudocode Decoding Algorithm:

store_pos=0;
if ( !readBit() ){
    note = FibonacciDecode() + 63;
    time = FibonacciDecode();
    store(note, time);
    store_pos++;
} else {
    pos = FibonacciDecode();
    run = FibonacciDecode();
    copy(store_pos-pos,store_pos,run);
    store_pos+=run;
}

Once the music is decoded, it is a simple matter of outputting it to the Midi port.

\$\endgroup\$
  • 1
    \$\begingroup\$ It relies on existing synthesizer (MIDI inside audio card in this case) instead of providing it's own. \$\endgroup\$ – Vi. May 5 '13 at 17:26
  • \$\begingroup\$ You can hack up synthesizer and make it output samples to to the respective port or to stdout/file (using DOS or Linux syscalls). As a separate challenge you can make a version with fully fledged polyphonic MIDI (still with compression into single COM file). \$\endgroup\$ – Vi. May 5 '13 at 17:54
  • \$\begingroup\$ I'm just interested in the 'compact Mozart music' aspect of the challenge, not the synthesizer. I'm posting this because it's fun and should be interesting to others rather than to win the challenge. \$\endgroup\$ – Sir_Lagsalot May 5 '13 at 18:03
  • \$\begingroup\$ OK. Waiting for Arduino version... \$\endgroup\$ – Vi. May 5 '13 at 21:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.