Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language Lilypond

Date:12/15/06
Author:Nate Eldredge
URL:http://www.math.ucsd.edu/~neldredg/
Comments:1
Info:http://lilypond.org
Score: (3.01 in 158 votes)
% Lilypond is a music engraving system with an
% embedded Scheme interpreter.
% http://lilypond.org
% Output of this program is at 
% http://www.math.ucsd.edu/~neldredg/personal/99-lilypond.pdf

\include "english.ly"

% Necessary because we use deep recursion
#(debug-set! stack 0)

\header{
  title =        "Ninety-Nine Bottles of Beer"
  composer =	 "Traditional"
  arranger =     \markup{ "Nate Eldredge" }
}

\version "2.8.7"

totalbottles = #99

startmelody = {
  \time 6/8
  \clef treble
  \key c \major
  \autoBeamOff
}

endmelody = {
  \bar "|."
}

% text = \lyricmode {
%   Nine -- ty nine bot -- tles of beer on the wall
%   Nine -- ty nine bot -- tles of beer __
%   Take one down and pass it a -- round
%   Nine -- ty eight bot -- tles of beer on the wall
% }

zerosyl = { }
onesyl = \relative c''{ c4. }
twosyl = \relative c''{ c4 c8 }
threesyl = \relative c''{ c8 c8 c8 }
foursyl = \relative c''{ c16 c16 c8 c8 }
fivesyl = \relative c''{ c16 c16 c8 c16 c16 }

#(define (count-syllables L)
  (if (null? (ly:music-property L 'text))
   (apply + (map count-syllables (ly:music-property L 'elements)))
   1))

% FIXME - check the syllabication
zero = \lyricmode { } % because "seventy" will become { \seventy \zero }
one = \lyricmode { one }
two = \lyricmode { two }
three = \lyricmode { three }
four = \lyricmode { four }
five = \lyricmode { five }
six = \lyricmode { six }
seven = \lyricmode { se -- ven }
eight = \lyricmode { eight }
nine = \lyricmode { nine }
ten = \lyricmode { ten }
eleven = \lyricmode { e -- le -- ven }
twelve = \lyricmode { twelve }
thirteen = \lyricmode { thir -- teen }
fourteen = \lyricmode { four -- teen }
fifteen = \lyricmode { fif -- teen }
sixteen = \lyricmode { six -- teen }
seventeen = \lyricmode { se -- ven -- teen }
eighteen = \lyricmode { eigh -- teen }
nineteen = \lyricmode { nine -- teen }
twenty = \lyricmode { twen -- ty }
thirty = \lyricmode { thir -- ty }
forty = \lyricmode { for -- ty }
fifty = \lyricmode { fif -- ty }
sixty = \lyricmode { six -- ty }
seventy = \lyricmode { se -- ven -- ty }
eighty = \lyricmode { eigh -- ty }
ninety = \lyricmode { nine -- ty }
nomore = \lyricmode { no more }
error = \lyricmode { oh shit }

#(define (speak-small n)
  (cond 
   ((= n 0) zero)
   ((= n 1) one)
   ((= n 2) two)
   ((= n 3) three)
   ((= n 4) four)
   ((= n 5) five)
   ((= n 6) six)
   ((= n 7) seven)
   ((= n 8) eight)
   ((= n 9) nine)
   ((= n 10) ten)
   ((= n 11) eleven)
   ((= n 12) twelve)
   ((= n 13) thirteen)
   ((= n 14) fourteen)
   ((= n 15) fifteen)
   ((= n 16) sixteen)
   ((= n 17) seventeen)
   ((= n 18) eighteen)
   ((= n 19) nineteen)
   (else error)))

#(define (speak-tens n)
  (cond
   ((= n 1) ten)
   ((= n 2) twenty)
   ((= n 3) thirty)
   ((= n 4) forty)
   ((= n 5) fifty)
   ((= n 6) sixty)
   ((= n 7) seventy)
   ((= n 8) eighty)
   ((= n 9) ninety)
   (else error)))

#(define (speak-number n)
  (cond
   ((= n 0) nomore)
   ((< n 20) (speak-small n))
   (else (make-sequential-music 
	  (list
	   (speak-tens (quotient n 10))
	   (speak-small (modulo n 10)))))))

#(define (sing-syllables k)
  (cond
   ((= k 0) zerosyl)
   ((= k 1) onesyl)
   ((= k 2) twosyl)
   ((= k 3) threesyl)
   ((= k 4) foursyl)
   ((= k 5) fivesyl)))

#(define (sing-number n) (sing-syllables (count-syllables (speak-number n))))

SingNumber = #(define-music-function (parser location n)
	       (integer?)
	       (ly:music-deep-copy (sing-number n)))
SpeakNumber = #(define-music-function (parser location n)
	       (integer?)
		(ly:music-deep-copy (speak-number n)) )

#(define (capitalize! s) (string-set! s 0 (char-upcase (string-ref s 0))))
#(define (capitalize s)
  (let ((l (string->list s)))
   (list->string (cons (char-upcase (car l)) (cdr l)))))

% takes a list of music objects
#(define (capitalize-lyric-list L)
  (cond 
   ((null? L))
   ((not (null? (ly:music-property (car L) 'text))) 
    (ly:music-set-property! (car L) 'text 
     (capitalize (ly:music-property (car L) 'text))))
   (else (capitalize-lyric-list
	  (append 
	   (ly:music-property (car L) 'elements)
	   (cdr L))))))
       
CapitalizeLyric = 
       #(define-music-function (parser location lyr)
	 (ly:music?)
	 (let ((newlyr (ly:music-deep-copy lyr)))
	  (capitalize-lyric-list (list newlyr))
	  newlyr))
       
melodyone =   \relative c''{ g8 g g | c c c c4 r8 | }
melodytwo = \relative c''{ a8 a a | d4.~ d8 r8 r8 | b4 b8 b4 b8 | b8 b b b4 r8 | }
melodytwofinal = \relative c''{ a8 a a | d4.~ d8 r4 | b8 b8 b8 b4 b8 | b4 b8 b4 r8 | }
melodythree = \relative c''{ a8 a b | c c c c4 r8 |}

lyricsone = \lyricmode{ of beer on the wall, }
lyricstwo = \lyricmode{ of beer.  Take one down and pass it a -- round, }
lyricstwofinal = \lyricmode{ of beer.  Go to the store and buy some more, }
lyricsthree = \lyricmode { of beer on the wall. }

bottle = \lyricmode{ bot -- tle }
bottles = \lyricmode{ bot -- tles }

PluralBottle = #(define-music-function (parser location n)
	       (integer?)
		 (if (= n 1) bottle bottles))


SingVerse = #(define-music-function (parser location n)
	      (integer?)
	      (let 
	       ((nn (if (> n 0) (- n 1) totalbottles))
		(meltwo (if (> n 0) melodytwo melodytwofinal)))
	       #{
	      { { \SingNumber #$n }}
	      \melodyone
	       { \transpose c d { \SingNumber #$n }}
	      $meltwo
	       {  \transpose c' g { \SingNumber #$nn }}
	      \melodythree
	      #}))

SpeakVerse = #(define-music-function (parser location n)
	      (integer?)
	      (let 
	       ((nn (if (> n 0) (- n 1) totalbottles))
		(lyrtwo (if (> n 0) lyricstwo lyricstwofinal)))
	      #{
	       \CapitalizeLyric \SpeakNumber #$n
	       \PluralBottle #$n
	       \lyricsone
	       \SpeakNumber #$n
	       \PluralBottle #$n
	       $lyrtwo
	       \SpeakNumber #$nn
	       \PluralBottle #$nn
	       \lyricsthree
	       #}))

SingVerses = #(define-music-function (parser location nstart nend)
	      (integer? integer?)
	       (if (>= nstart nend)
		(let ((nextverse (- nstart 1)))
		 #{ \SingVerse #$nstart \SingVerses #$nextverse #$nend #})
		#{ #} ))

SpeakVerses = #(define-music-function (parser location nstart nend)
	      (integer? integer?)
	       (if (>= nstart nend)
		(let ((nextverse (- nstart 1)))
		 #{ \SpeakVerse #$nstart \SpeakVerses #$nextverse #$nend #})
		#{ #} ))


\score{
  {
    <<
      \new Voice = "one" {
	\transpose c' g  {
	  \startmelody
	  \SingVerses #totalbottles #0
	  \endmelody 
	}
      }
      \new Lyrics \lyricsto "one" { 
	\SpeakVerses #totalbottles #0
	  }
    >>
  }
  \layout { }
  \midi { }
}

Download Source | Write Comment

Alternative Versions

Comments

>>  plams said on 05/11/09 21:58:33

plams Wow! This is fucking great. People, this is the output:

http://www.math.ucsd.edu/~neldredg/personal/99-lilypond.pdf

!!!

It even takes the different number of syllables in the numbers into account in the music. Genius. Next step must be to sing it in csound or ChucK :D

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: