31
\$\begingroup\$

Today, November 11, 2015, is Veterans Day in the United States. "Taps" is the bugle call played at U.S. military funerals:

("Taps" on SoundCloud from vtmiller)

It is a simple melody, only twenty-four notes long and using only four different notes. Here is the sheet music:

Taps sheet music (source)

Challenge

Write a program or function that plays "Taps" or outputs an audio file of "Taps" in any common audio file format (e.g. MP3, WAV, MIDI). It may be played in any key, using any type of instrument or beep noise available to your language. For example, it might sound like a piano instead of a bugle. (Though still only one instrument type should be used.)

All twenty-four notes must be played with accurate pitch, duration, and spacing. Someone who is familiar with "Taps" should be able to run your code and easily recognize the song being played.

The duration of the melody (from the start of the first note to the end of the last note) must be between 30 and 70 seconds. You may optionally have up to 5 seconds of silence padding the start and/or end of your sound file, so an 80 second file is the longest allowed.

You may not, of course, simply download the song online somewhere or extract it from an audio library that happens to have it as as sample. You may, however, use audio libraries that can play/compose individual notes and create audio files.

Scoring

This is , so the shortest answer in bytes wins. However, for this particular challenge I encourage you to not focus on your byte count, especially at the expense of sound quality. Golf your submissions but allow yourself to be creative with your instrument choice or sound output methodology. This challenge is meant to be about honoring veterans, not about screeching out a barely recognizable version of "Taps".

Note that you can embed SoundCloud audio files directly into posts by just pasting the link on an empty line. If you have a SoundCloud account this would be a great way to share your output.

\$\endgroup\$
  • \$\begingroup\$ I'm thinking ChucK. \$\endgroup\$ – The_Basset_Hound Nov 11 '15 at 20:27
  • 4
    \$\begingroup\$ Calvin, if you don't mind, I'll post a couple of golfy answers in old BASIC's and make a donation to a Veterans charity outside of PPCG. You have inspired me to do that. BTW in the UK we have Remembrance Sunday, the second Sunday in November, which means that this year it was last Sunday. One of my earliest memories is standing by a monument surrounded by poppies where 2 minutes of silence were observed. I was about 3. When I asked my mother why nobody was talking, she told me to be quiet. \$\endgroup\$ – Level River St Nov 11 '15 at 23:45
  • \$\begingroup\$ Are there any rules for the lengths of the fermatas? \$\endgroup\$ – SirPython Nov 12 '15 at 18:33
  • \$\begingroup\$ @SirPython I didn't even know what that symbol meant! According to en.wikipedia.org/wiki/Fermata "Exactly how much longer it is held is up to the discretion of the performer." Using discretion on the output doesn't really fit with codegolf, so I played it as written. I see where you're going though... Lengthening the dotted second note could compress the dotted eighth note down to a sixteenth note, making things simpler. But I think that's cheating :-) \$\endgroup\$ – Level River St Nov 12 '15 at 21:36

10 Answers 10

4
\$\begingroup\$

qb64, 100 84 bytes

Updated version of old Qbasic, downloadable at http://www.qb64.net/

Count excludes the spaces, which are not required and only there to split the data into three-note phrases for clarity.

PLAY"T99L4C.L8CL1F. L4C.L8FL1A. L4CFL2A L4CFL2A L4CFL1A. L4F.L8AL1>C< L2AFL1C. L4C.L8CL1F."

Commands in the play string

T99     set tempo to 99 quarter notes per minute (default is 120, only just too short)
CDEFGAB play notes in the current octave
><      up or down one octave
Lx      following notes are of note of 1/x duration
.       extend previous note duration by 50%

Golfing history:

First post: 4/4 time to 4/2 time, which means I have some whole notes, but no sixteenth notes.

Edit 1: Key changed from C (range G-G) to F (range C-C). Now I only have to perform an octave change once, for the high C, which only occurs once, rather than all the low G's as before.

Having got rid of all those octave changes, I don't think there's any more to golf. There are total of 20 L's but there is no obvious way to avoid them.

The last phrase (11 characters) is the same as the first, but there is no way to insert it twice in under 11 characters. The repeated data would be only 9 characters if the initial L4 were eliminated (It appears unnecessary as the default note length seems to be quarter note, but it's not documented so I left it in.)

\$\endgroup\$
9
\$\begingroup\$

JavaScript, 203 198 196 195 bytes

with(new AudioContext)for(t=i=0;n="301093301396202346202346202396331699464390301093"[i++];)with(createOscillator())i%2?l=n/2:(frequency.value=392+n*44,connect(destination),start(t+.1),stop(t+=l))

5 bytes saved thanks to Dendrobium and 1 thanks to @PatrickRoberts.

Explanation

with(new AudioContext)        // use HTML5 audio
  for(                        // iterate through the note pitches and lengths
    t=i=0;                    // t = current time to place the note
    n=                        // n = note pitch (or temporarily length)

    // This string contains the values of each note alternating between length and pitch
    //     (l1, p1, l2, p2, etc...)
    // Length value is in 16th notes (1 = 1/16th note, 2 = 1/8th, etc...)
    //     The longer notes are limited to 9 but I think it still sounds OK
    // Pitch value 0 = G4, 3 = C5, 6 = E5, 9 = G5 (multiples of 3 saves 1 byte)
    "301093301396202346202346202396331699464390301093"

  [i++];)
    with(createOscillator())  // create the note oscillator
      i%2?                    // alternate between length and pitch characters
        l=n/2                 // l = length (stored for use in the next iteration)
                              // dividing it by 2 sets the speed to 60 beats per minute
                              //     and casts it to a number
      :(
        frequency.value=392   // base note = G5 (392hz)
          +n*44,              // there is (conveniently) roughly 132hz between each note
        connect(destination), // send the note's sound through the speakers
        start(t               // schedule the note to sound
          +.1),               // short delay to distinguish two notes of the same pitch
        stop(t+=l)            // schedule the end of the note and increment the time
      )

Test it here in the browser! Works on any browser that supports the HTML5 Web Audio API.

\$\endgroup\$
  • 1
    \$\begingroup\$ -5 bytes: c=new AudioContext();for(t=i=0;n="301093301396202346202346202396331699464390301093"[i++];)with(c.createOscillator())i%2?l=n/2:(frequency.value=392+n*44,connect(c.destination),start(t+.1),stop(t+=l)) \$\endgroup\$ – Dendrobium Nov 12 '15 at 17:06
  • \$\begingroup\$ I'd say the duration (changing 12 units to 9) is inaccuate; it's made worse by the fact that the dotted half notes have fermatas on them and should really be 12 or longer. \$\endgroup\$ – lirtosiast Nov 16 '15 at 5:43
  • \$\begingroup\$ @ThomasKwa Yeah, it's not perfect, but the requirement is to be easily recognisable so I'd say it passes. (Also listen to the SoundCloud track in the question, the first dotted half note is exactly 10/16ths so if we're going by that version it's pretty close! :P ) \$\endgroup\$ – user81655 Nov 16 '15 at 7:14
8
\$\begingroup\$

Mathematica, 361 287 285 bytes

I went for accuracy here. Output is exactly as described in the score, played with the trumpet. You can find the file here.

"G"
e="E5";c="C5";EmitSound@Sound[SoundNote[#,5/#2,"Trumpet",SoundVolume->#3/17]&@@@{%,8,17,%,24,20,c,2,23,%,8,26,c,24,29,e,2,32,%,12,35,c,12,38,e,6,41,%,12,44,c,12,47,e,6,50,%,12,53,c,12,56,e,2,59,c,8,62,e,24,65,"G5",3,68,e,6,170/3,c,6,136/3,%,2,34,%,8,34,%,24,34,c,2,34}~Partition~3]

Thanks to @MartinBüttner for golfing suggestions.

\$\endgroup\$
  • 4
    \$\begingroup\$ Link does not allow me to hear the song. It seems to be either removed or not available for listening due to permissions. \$\endgroup\$ – d0nut Nov 12 '15 at 0:08
  • 2
    \$\begingroup\$ To be extra pedantic, you didn't account for the fermatas! \$\endgroup\$ – wchargin Nov 12 '15 at 1:49
  • \$\begingroup\$ "The duration of the melody must be between 30 and 70 seconds." This is a bit short at 24 seconds. \$\endgroup\$ – Calvin's Hobbies Nov 12 '15 at 8:37
  • 4
    \$\begingroup\$ @Calvin'sHobbies Wait... I'm doing all this at the recommended 50 BPM... I blame you :| \$\endgroup\$ – LegionMammal978 Nov 12 '15 at 11:37
  • 1
    \$\begingroup\$ %1,%2 and %% don't actually save any bytes over x="E5" --> x (in fact, seeing how often you use them you should actually save quite a lot by using variables). Then you can save tons of bytes by using EmitSount@Sound[SoundNote[#,5/#2,"Trumpet",SoundVolume->#3/17]&@@@{{%%,8,17},{%%,24,20},...} and storing the most-used note in %. And at 24 notes it might be shorter still to partition a flat list: SoundNote[#,5/#2,"Trumpet",SoundVolume->#3/17&@@@{%%,8,17,%%,24,20,%2,2,23,...}~Partition~3 \$\endgroup\$ – Martin Ender Nov 12 '15 at 13:27
5
\$\begingroup\$

Sonic Pi, 899 bytes

The timing is a little off, but I think it's ok.

Lightly golfed:

use_synth:blade
use_synth_defaults sustain:0.70,release:0.0
play:G4,release:0.05
wait 0.75
play:G4,sustain:0.25
wait 0.25
hold=rrand_i(3,4)
play:C5,sustain:hold,release:0.5
wait hold+0.5
play:G4,release:0.05
wait 0.75
play:C5,sustain:0.25
sleep 0.25
hold=rrand_i(3,4)
play:E5,sustain:hold,release:1.25
sleep hold+1.25
play:G4
sleep 0.70
play:C5
sleep 0.70
2.times do
  play:E5,sustain:1,release:0.25
  sleep 1.25
  play:G4
  sleep 0.7
  play:C5
  sleep 0.7
end
hold=rrand_i(3,5)
play:E5,sustain:hold,release:0.75
sleep hold+1
play:C5,release:0.05
sleep 0.75
play:E5,sustain:0.25
sleep 0.25
play:G5,sustain:2.45,release:0.05
sleep 2.5
play:E5,sustain:1,release:0.25
sleep 1.25
play:C5,sustain:1,release:0.25
sleep 1.25
hold=rrand_i(3,5)
play:G4,sustain:hold,release:0.5
sleep hold+0.5
play:G4,release:0.05
sleep 0.75
play:G4,sustain:0.25
sleep 0.25
hold=rrand_i(3,5)
play:C5,sustain:hold,release:1.5
\$\endgroup\$
  • \$\begingroup\$ Yeah, someone using Sonic Pi! \$\endgroup\$ – Mega Man Aug 1 '16 at 8:32
  • \$\begingroup\$ Could be slightly golfed through renaming hold with h, changing release:0.0 to release:0 and removing the spaces. \$\endgroup\$ – Mega Man Aug 1 '16 at 8:37
4
\$\begingroup\$

MATLAB, 338 327 262 258 230 bytes

o=@(L,f)sin(pi*.11*2^(f/12))*(1:600*L))
sound([o(3,-1) o(1,-1) o(12,2) o(3,-1) o(1,2) o(12,4) o(2,-1) o(2,2) o(4,4) o(2,-1) o(2,2) o(4,4) o(2,-1) o(2,2) o(12,4) o(3,2) o(1,4) o(8,6) o(4,4) o(4,2) o(12,-1) o(3,-1) o(1,-1) o(12,4)])
\$\endgroup\$
2
\$\begingroup\$

SmileBASIC, 73 bytes

BGMPLAY"@56T50L2.G8.G16B+G8.<C16E>[G8<C8E4>]2G8<C8EC8.E16G2E4C4>GG8.G16B+

All the notes and timings are correct. I used a trumpet because it's the closest thing in MIDI

<audio autoplay controls src="//12me21.github.io/resources/taps.mp3"></audio>

\$\endgroup\$
1
\$\begingroup\$

Powershell, 183 175 159 bytes

Nostalgia trip, who doesn't like beeps?!

foreach($i in 0..23){[console]::beep((196,262,330,392)[(001012012012012123210001-split'')[$i]],(3,1,12,3,1,12,2,2,4,2,2,4,2,2,12,3,1,8,4,4,12,3,1,12)[$i]*400)}


Explanation (sortof)

foreach($i in 0..23) { # foreach loop which ranges from 0 to 23
    [console]::beep( # [console]::beep(Pitch, Duration)
        (196,262,330,392) # the notes in Hertz
            [ # select which note to use
                (001012012012012123210001-split'') # -split '' creates an array of [0,0,1,0,1 ...], spaces can be omitted
                [$i] # select the n-th element
            ],
        (3,1,12,3,1,12,2,2,4,2,2,4,2,2,12,3,1,8,4,4,12,3,1,12) # array of durations
        [$i]*400 # duration in milliseconds * 400
    )
}


This will play in about 45 seconds.

This is my first time using Windows' Powershell, any tips on golfing this are welome.


Old versions

175

foreach($i in(0..23)){[console]::beep((196,262,330,392)[(0,0,1,0,1,2,0,1,2,0,1,2,0,1,2,1,2,3,2,1,0,0,0,1)[$i]],(3,1,12,3,1,12,2,2,4,2,2,4,2,2,12,3,1,8,4,4,12,3,1,12)[$i]*400)}

183

$d=3,1,12,3,1,12,2,2,4,2,2,4,2,2,12,3,1,8,4,4,12,3,1,12;$n=0,0,1,0,1,2,0,1,2,0,1,2,0,1,2,1,2,3,2,1,0,0,0,1;foreach($i in(0..23)){[console]::beep((196,262,330,392)[$n[$i]],$d[$i]*400)}
\$\endgroup\$
1
\$\begingroup\$

BBC Basic, 111

Download interpreter at http://www.bbcbasic.co.uk/bbcwin/bbcwin.html

Score excludes whitespace and newlines, which are non-essential and added for readability

FORk=1TO24
  x=ASC(MID$("')F'Lb(Ke(Ke(KbJhxeI#')F",k))
  SOUND1,-9,x DIV7*4+60,INT(12/1.4^(x MOD7))*5
  SOUND1,0,1,1
NEXT

Fairly standard compression, 1 ASCII character per note. Parameters of SOUND are as follows:

Channel (always 1 for the purposes of this challenge)
Amplitude (negative for on, 0 for off, positive is an envelope index)
Pitch (in increments of 1/4 semitone, with middle C at 100)
Duration (20ths of a second)

The range of the song is 13 notes, even though only 4 are used. To get this range into the 95-number range of printable ASCII, I had to squeeze the duration into an integer range of 7 and take it modulo 7. The following durations (in sixteenths) are used (with the exception of 6 which is never used): 1,2,3,4,6,8,12. To produce these numbers, I hit upon the idea of dividing 12 by a power of sqrt(2) (approximated by 1.4) and truncating.

The SOUND1,0,1,1 is an annoyance, costing 12 bytes. It's necessary to provide a pause between notes of identical pitch.

\$\endgroup\$
1
\$\begingroup\$

Ruby + beep, 178 bytes

f=[260,346,416,499]
n=[12,*1..4]
l=(a="001012012012012123210001310310224224220318440310".chars.map(&:to_i))[24..-1]
`beep#{24.times.map{|i|" -f#{f[a[i]]} -l#{n[l[i]]}00"}*" -n"}`

Took me awhile to make this, I think I missed the boat, but whatever.

f holds the four frequencies used. n holds the five note lengths used, in multiples of 16th notes.

a="00101... holds all the note pitchs followed by all the note lengths, as indexes into the respective arrays. l is then set to the 24th indice and onward of a. Then a beep command is constructed by iterating through all of the above, and executed

\$\endgroup\$
0
\$\begingroup\$

C - (Raw: 318 | WAV: 437)

8-bit (unsigned) mono PCM at 44800 Hz, 33.60 seconds.

The mezzo forte, fortissimo and forte dynamics are somewhat artistically implemented. The fermatas could be better.

Code relies on unsigned long long being 8 octets and system little endian.

#include<stdio.h>
#include<math.h>
#ifdef RAW
main(){unsigned long long D[]={0x422422c13c13,0xc13c44813c22},X[]={27863,37193,46860,55727},O=0x406e64924910,i=0,j;float Z,A,U=40,P;for(;i<24;D[i++/12]>>=4){Z=X[O&3]/1e6;P=0;O>>=2;A=i>18?--U:i<14?U+i/2:U+30;for(j=(D[i/12]&15)*13440;j;A-=--j<7e3&&A>0?.01:0)putchar(A*sin(P+=Z)+128);}}
#else
main(){unsigned long long D[]={0x422422c13c13,0xc13c44813c22},X[]={27863,37193,46860,55727},O=0x406e64924910,i=0,j;float Z,A,U=40,P;int W[]={0x46464952,1570852,0x45564157,544501094,16,65537,44800,44800,524289,0x61746164,1505280};fwrite(W,4,11,stdout);for(;i<24;D[i++/12]>>=4){Z=X[O&3]/1e6;P=0;O>>=2;A=i>18?--U:i<14?U+i/2:U+30;for(j=(D[i/12]&15)*13440;j;A-=--j<7e3&&A>0?.01:0)putchar(A*sin(P+=Z)+128);}}
#endif

Compile and run with something like:

gcc -std=c99 -o taps taps.c -lm
./taps > taps.wav
play taps.wav

Add -DRAW to compile-line for raw variant.

Raw output can be played with e.g. SoX play as:

play -c 1 -b 8 -r 44800 -t u8 <file>
       |    |       |       |
       |    |       |       +--- Unsigned 8-bit
       |    |       +----------- Sample rate
       |    +------------------- 8 Bits
       +------------------------ 1 Channel
\$\endgroup\$

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.