Concert tuning WAV

7

I used to play the oboe, the instrument that is, for some reason, used to tune the orchestra to A440. Anyways, continuing on with my story, I was bad at it and quit.

Write a program that generates a valid, full scale, 5 second, WAV file with a sample rate of 44.1 kHz that plays a 440 Hz (+3/-1 Hz) tone. Your code is responsible for generating the structure of the file format; no external resources.

+75 penalty if the tone does not approximate a sine wave (harmonic power must be less than 1% of the fundamental--a good polynomial approximation should be able to exceed 20 dB; I think parabolic is about -28 dB)

Nick T

Posted 2014-02-05T12:12:17.157

Reputation: 3 197

2

define "sine wave". Is it okay if I use a truncated triangle wave, a parabolic wave or (say) a 20-line approximation, or I have to get it right within a few ULP?

– John Dvorak – 2014-02-05T12:41:35.427

2Specifically, having a measurable metric as part of the goal (say, using Audacity spectral analysis) would be optimal. – Tobia – 2014-02-05T13:10:00.583

Can you clarify rules for amplitude? Does it have to be 0 dBFS? Or, taking it to the extreme, can I use only 1 bit, and just toggle the bit 880 times a second? – TypeIA – 2014-02-07T22:14:05.347

@dvnrrs yeah, full scale is basically what I was going for in saying "audible" (was trying to avoid 1 LSB WAVs). – Nick T – 2014-02-08T03:17:38.107

@Tobia I loosened "sine" to be things that are very-nearly-sinusoidal, if a polynomial or other approximation would work better. – Nick T – 2014-02-08T03:25:42.513

Answers

5

GolfScript, 89 bytes

This GolfScript program contains non-printable characters, so I'm providing it as a hex dump. On Unixish systems with the xxd program installed, you can feed this hex dump to xxd -r to reconstruct the actual program.

0000000: 2752 4946 4678 5d03 0057 4156 4566 6d74  'RIFFx]..WAVEfmt
0000010: 2010 0000 0001 0001 0044 ac00 0044 ac00   ........D...D..
0000020: 0001 0008 0064 6174 6154 5d03 0027 2784  .....dataT]..''.
0000030: 8c94 9ba3 abb2 bac1 c7ce d4da e0e5 e9ee  ................
0000040: f2f5 f8fa fcfe ffff 272e 2d31 252b 2e7b  ........'.-1%+.{
0000050: 7e7d 252b 3232 3035 2a                   ~}%+2205*

The output of this program is a 220,545 byte 44.1 kHz 8-bit PCM WAV file that should play a 441 Hz tone for five seconds.

The code itself simply consists of two literal single-quoted strings: the first one contains a minimal WAV header, while the second 25-byte string, representing a quarter of the sine wave, is cloned, reversed, joined to the original, cloned again, inverted, joined again and finally repeated 2205 times to produce the actual audio data.

Ps. The output of the program above includes as extra trailing 0x0A byte (i.e. a line feed), which is technically not part of the WAV data. Since it lies past the end of the RIFF chunk, reasonable decoders should ignore it. (This could be fixed, at the cost of two extra bytes of code.)

Ilmari Karonen

Posted 2014-02-05T12:12:17.157

Reputation: 19 513

1"generate a ... WAV file with a sample rate of 44.1 kHz" – John Dvorak – 2014-02-05T13:38:28.173

@JanDvorak: Oh. I could've sworn that wasn't there when I started writing this, but maybe I just missed it. :-( – Ilmari Karonen – 2014-02-05T13:40:45.237

@JanDvorak: OK, fixed it, now it's 44.1 kHz. – Ilmari Karonen – 2014-02-05T14:11:12.113

4

C, 204 bytes

Won't win, but here it is anyway :-)

x;main(i){char *h="riff\xec\xda& wave\x86\x8d\x94@0   ! ! d\xcc  \xa8x! \" 0 \x84\x81\x94\x81\xc8\xda& ";for(i=45;--i;)putchar(*h++-' ');for(;i++<220500;){x=(32767*sin(i/15.952));printf("%c%c",x,x>>8);}}

Needs to be compiled with the maths library, of course.

Outputs a 5-second WAV file to stdout (16-bit samples, 44.1 kHz sampling), but this can easily be redirected to a file (e.g., ./a.out >foo.wav)

r3mainer

Posted 2014-02-05T12:12:17.157

Reputation: 19 135

1

R, 285 characters

S=44100;s=sin(0:(5*S-1)*pi*880/S);c=32767*s/max(abs(s));a=file("c.wav","wb");w=writeChar;W=function(x,z)writeBin(as.integer(x),a,z,e="little");w("RIFF",a,4,NULL);W(441036,4);w("WAVEfmt ",a,8,NULL);W(16,4);W(c(1,1),2);W(S*1:2,4);W(c(2,16),2);w("data",a,4,NULL);W(S*10,4);W(c,2);close(a)

Create a wav file called c.wav in the working directory.

Indented:

S=44100
s=sin(0:(5*S-1)*pi*880/S) #Sin Wave
c=32767*s/max(abs(s)) #Normalized
a=file("c.wav","wb") #Open connection with empty wav file
w=writeChar #Write characters
W=function(x,z)writeBin(as.integer(x),a,z,e="little") #Write binary data
w("RIFF",a,4,NULL)
W(441036,4)
w("WAVEfmt ",a,8,NULL)
W(16,4)
W(c(1,1),2)
W(S*1:2,4)
W(c(2,16),2)
w("data",a,4,NULL)
W(S*10,4)
W(c,2)
close(a)

plannapus

Posted 2014-02-05T12:12:17.157

Reputation: 8 610

no external resources – Fez Vrasta – 2014-02-05T12:54:34.643

how is this an external resource? – plannapus – 2014-02-05T12:55:32.430

2"Your code is responsible for generating the structure of the file format" - this means that you can't use writeWave. The challenge lies in implementing the wav spec. – John Dvorak – 2014-02-05T12:56:17.933

ok ok, before I rewrite it, is the creation of the sinewave itself at least ok with you guys like that? – plannapus – 2014-02-05T13:04:13.207

It's fine for me. – John Dvorak – 2014-02-05T13:05:05.860

@FezVrasta JanDvorak Done... And i rewrote the sine wave creation as well, just because. – plannapus – 2014-02-05T15:31:15.253