15
\$\begingroup\$

Yup, you read the title right. play the sound of pi.

More specifically, for every digit of pi in the first 1000, map it to a musical note and output the resulting melody to a file.

Basically, each digit turns to a note on the C Major scale (basically the normal scale). so 1 turns to Middle C, 2 turns to D4, 3 turns to E4, 9 turns to D5 and so on.

Rules

  • Each note should be exactly 0.5 seconds long.
  • The melody should contain the first 1000 digits of pi, including the starting 3.
  • 1 to 7 represent Middle C to B4, 8 is C5, 9 is D5 and 0 is E5
  • All well supported file formats are allowed, as long as they were created before this challenge.
  • There may be no pauses anywhere in the file, including the start and end.
  • The instrument played does not matter. It could be a piano, sine wave, anything really, as long as the correct sound is easily hearable.
  • It must take no input and produce no output except for the file. Reading from other files is disallowed.
  • Standard loopholes are forbidden.

Example mathematica code:

(*please forgive me for this horrible, horrible mess of code*)
digits = RealDigits[Pi, 10, 1000][[1]] /. {0 -> 10};
weights = {0, 2, 4, 5, 7, 9, 11, 12, 14, 16}; 
melody = {};
For[i = 1, i < 1001, i++, melody = {melody , Sound[SoundNote[weights[[digits[[i]]]], 0.5]]}]
final = Sound[Flatten[melody]];
Export["C:\\Mathematica Shenanigans\\pi.wav", final];

Example melody showing first 100 digits: http://vocaroo.com/i/s0cfEILwYb8M

For your sanity, A table of pitches for each note and what note does each digit represent:

Digit 1: C: 261.63 Hz
Digit 2: D: 293.66 Hz
Digit 3: E: 329.63 Hz
Digit 4: F: 349.23 Hz
Digit 5: G: 392.00 Hz
Digit 6: A: 440.00 Hz
Digit 7: B: 493.88 Hz
Digit 8: C5: 523.25 Hz
Digit 9: D5: 587.33 Hz
Digit 0: E5: 659.25 Hz
\$\endgroup\$
  • 5
    \$\begingroup\$ 9 turns to D5 You should clarify that the other notes are in the 4-th octave. Also, in your table does digit 0 come last (E5)? \$\endgroup\$ – Luis Mendo Jan 17 '17 at 22:11
  • 1
    \$\begingroup\$ @LuisMendo Yes it does. I'll make these too more clear. \$\endgroup\$ – sagiksp Jan 18 '17 at 4:57
  • 1
    \$\begingroup\$ Can we assume 'well supported formats' to mean anything openable by vlc? \$\endgroup\$ – Pavel Jan 18 '17 at 6:14
  • \$\begingroup\$ @Pavel Pretty much \$\endgroup\$ – sagiksp Jan 18 '17 at 8:58
  • \$\begingroup\$ Can I output the note names (e.g. 3.14 --> ECF) if my language does not support sound or writing to sound files? \$\endgroup\$ – FinW Jan 18 '17 at 19:42
10
\$\begingroup\$

Mathematica, 107 87 bytes

Thanks to Martin Ender for saving 20 bytes!

"t.au"~Export~Sound[SoundNote[⌊12Mod[#,10,1]/7⌋-1,.5]&/@#&@@RealDigits[Pi,10,1000]]

#&@@RealDigits[Pi,10,1000] gives the list of the first 1000 digits of π. SoundNote[⌊12Mod[#,10,1]/7⌋-1 produces the correct pitch number (where 0 is middle C by default) from a digit. Then SoundNote[...,.5]&/@ turns that pitch name into a sound object of duration 1/2 second, which Sound gathers into an actual audio snippet. Finally "t.au"~Export~ exports to a Unix Audio Format file, mostly because the extension is the shortest supported one, but also because we get to make the filename a slap in the face to π!

Previous submission:

"t.au"~Export~Sound[StringSplit["E5 C D E F G A B C5 D5"][[#+1]]~SoundNote~.5&/@#&@@RealDigits[Pi,10,1000]]
\$\endgroup\$
10
\$\begingroup\$

Python 2, 182 bytes

x=p=6637
while~-p:x=p/2*x/p+2*10**999;p-=2
s="MThd\0\0\0\6\0\1\0\1\342\4MTrk\0\0\13\301\0\220"
for i in`x`:s+="JHGECA@><L\260"[~ord(i)%29]+'{<'
open('p.mid','w').write(s+"\0\377/\0")

`x` will produce 31415926...20198L. The trailing L is used to produce the final channel message byte, via the mapping ~ord(i)%29.

Outputs a single track Type 1 Midi file, named p.mid to the current working directory.

0000: 4d 54 68 64 00 00 00 06  MThd....  # Midi header, 6 bytes to follow
0008: 00 01 00 01              ....      # Type 1, 1 track
000c: e2 04                    â.        # (-)30 ticks per beat, 4 beats per second

000e: 4d 54 72 6b 00 00 0b c1  MTrk...Á  # Track header, 3009 bytes to follow
0016: 00 90 40 7b              ..@{      # Wait  0 ticks, play E4 (3), 97% volume
001a: 3c 3c 7b                 <<{       # Wait 60 ticks, play C4 (1), 97% volume
001d: 3c 41 7b                 <A{       # Wait 60 ticks, play F4 (4), 97% volume
0020: 3c 3c 7b                 <<{       # Wait 60 ticks, play C4 (1), 97% volume
0023: 3c 43 7b                 <C{       # Wait 60 ticks, play G4 (5), 97% volume
...
0bcf: 3c b0 7b 3c              <°{<      # Wait 60 ticks, all notes off
0bd3: 00 ff 2f 00              .ÿ/.      # End of track marker
\$\endgroup\$
6
\$\begingroup\$

Scratch, 530 bytes

Inspired by BookOwl's answer.

Online Demonstration. Playback will begin immediately, press space to stop and reset. Click the cat to start again.

Edit: golfed down slightly. I found some golfing tips on the official wiki.

when gf clicked
set[c v]to[4e3
repeat(c
add[2e3]to[f v
end
repeat(250
set[b v]to(c
set[h v]to((d)mod(1e4
change[c v]by(-16
repeat(b
set[d v]to(((d)*(b))+((1e4)*(item(b)of[f v
set[g v]to(((2)*(b))-(1
replace item(b)of[f v]with((d)mod(g
set[d v]to(((d)-((d)mod(g)))/(g
change[b v]by(-1
end
change[h v]by(((d)-((d)mod(1e4)))/(1e4
repeat(4
add((h)mod(10))to[a v
set[h v]to(((h)-((h)mod(10)))/(10
end
repeat(4
say(item(last v)of[a v
play note((round((((item(last v)of[a v])-(1))mod(10))*(1.78)))+(60))for(0.5)beats
delete(last v)of[a v

Graphical:

Uses the Rabinowitz Wagon spigot to produce 4 digits at a time.

\$\endgroup\$
3
\$\begingroup\$

R, 450 bytes

N=261.63*(2^(1/12))^c(16,0,2,4,5,7,9,11,12,14);S=44100;s=unlist(sapply(el(strsplit(as(Rmpfr::Const("pi",1e5),"character"),""))[c(1,3:1001)],function(x)sin(0:(0.5*S-1)*pi*2*N[(x:1)[1]+1]/S)));c=32767*s/max(abs(s));a=file("p.wav","wb");v=writeChar;w=function(x,z)writeBin(as.integer(x),a,z,e="little");v("RIFF",a,4,NULL);w(36+S*10,4);v("WAVEfmt ",a,8,NULL);w(16,4);w(c(1,1),2);w(S*1:2,4);w(c(2,16),2);v("data",a,4,NULL);w(2*length(s),4);w(c,2);close(a)

Uses package Rmpfr to get the correct precision on pi digits. Outputs a .wav file.

Indented, with new lines and comments:

N=261.63*(2^(1/12))^c(16,0,2,4,5,7,9,11,12,14) # Frequency of each notes
S=44100 #Sampling rate
s=unlist(sapply(el(strsplit(
                   as(Rmpfr::Const("pi",1e5),"character"), #get pi correct digits as a character string
                   ""))[c(1,3:1001)], #Grabs first 1000 digits
                function(x)sin(0:(0.5*S-1)*pi*2*N[(x:1)[1]+1]/S))) #Wave function
c=32767*s/max(abs(s)) #Normalize to range [-32767;32767] as per wav 16-bit standard
a=file("p.wav","wb")
v=writeChar
w=function(x,z)writeBin(as.integer(x),a,z,e="little")
v("RIFF",a,4,NULL)     #ChunkID
w(36+S*10,4)           #Chunksize
v("WAVEfmt ",a,8,NULL) #Format, followed by SubChunk1ID
w(16,4)                #SubChunk1Size
w(c(1,1),2)            #AudioFormat & NumChannels
w(S*1:2,4)             #SampleRate & ByteRate
w(c(2,16),2)           #BlockAlign & BitsPerSample
v("data",a,4,NULL)     #SubChunk2ID
w(2*length(s),4)       #Subchunk2Size
w(c,2)                 #Actual data
close(a)
\$\endgroup\$
0
\$\begingroup\$

C (gcc) 572 bytes

p(float f){i;char b[10000];p=3.14;for(i= 0;i<5000;i++){b[i]=35*sin(f*(2*p*i)/10000);putchar(b[i]);}} f(){i;FILE *f;char p[1001];float n[10];n[0]= 261.63;for(i=1;i<=6;i++){if(i==3)n[i]=349.23;else n[i]=1.12231*n[i-1];}for(i=7;i<=9;i++)n[i]=2*n[i-7];f=popen("pi 1000","r");fgets(p,sizeof(p)-1,f);for(i=0;i<999;i++){switch(p[i]){case'1':p(n[0]);break;case'2':p(n[1]);break;case'3':p(n[2]);break;case'4':p(n[3]);break;case'5':p(n[4]);break;case'6':p(n[5]);break;case'7':p(n[6]);break;case'8':p(n[7]);break;case'9':p(n[8]);break;case'0':p(n[9]);break;default:p(n[0]);break;}}}

Ungolfed version:

void play(float freq)
{
    char buffer[10000];
    float pi=3.14;
    for(int i = 0; i<5000; i++)
    {
       buffer[i] = 35*sin(freq*(2*pi*i)/10000 );
       putchar(buffer[i]);
    }
}

void f()
{
    FILE *fp;
    char pi[1001];
    float note[10];
    note[0]= 261.63;

    for(int i=1;i<=6;i++)     
    {
       if(i==3)
         note[i]=349.23;
       else
         note[i]=1.12231*note[i-1]; 
    }      

    for(int i=7;i<=9;i++)
      note[i]=2*note[i-7];

   fp=popen("pi 1000","r" );
   fgets(pi, sizeof(pi)-1, fp);  

   for(int i=0;i<1001;i++)
   {
    switch(pi[i])
    {   
        case '1': play(note[0]);break;
        case '2': play(note[1]);break;
        case '3': play(note[2]);break;
        case '4': play(note[3]);break;
        case '5': play(note[4]);break;
        case '6': play(note[5]);break; 
        case '7': play(note[6]);break;
        case '8': play(note[7]);break;
        case '9': play(note[8]);break;
        case '0': play(note[9]);break;
        default : play(note[0]);break;
    }

  }     
}

Explanation:

  • play(float freq) routine takes in the frequency as a parameter of the note (hardcoded) you want to play and stores a sine wave in a buffer.
  • In the function f(), i stored the frequencies corresponding to notes ranging from C4 to E5 in a notes array.
  • Store the pi value followed by 1000 digits in a buffer.In order to do this, I installed the pi package on my machine, and used popen to read the output of pi 1000 and store it in a char buffer.
  • Using a for loop and switch I called the play() function to produce notes that correspond to every single digit in the pi buffer. ,

Usage: ./binary_name.o | aplay on modern Linux distributions, on older distributions you would redirect it to /dev/audio

\$\endgroup\$
  • \$\begingroup\$ Suggest replacing the entire switch(foo){...} with something like play(note[(foo-'1')%10]). Also, read tips for golfing in C \$\endgroup\$ – ceilingcat Feb 8 '17 at 7:48

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.