|
\version "2.19.82" |
|
\language deutsch |
|
#(define seed 0) |
|
|
|
#(define solution #f) |
|
#(define useBE #f) |
|
#(define includeTasks #t) |
|
|
|
setSeed = |
|
#(define-void-function (newSeed) (number?) |
|
(begin |
|
(set! seed newSeed) |
|
(set! *random-state* |
|
(seed->random-state seed))) |
|
) |
|
|
|
randomizeSeed = |
|
#(define-void-function () () |
|
(let* ((time (gettimeofday))) |
|
(begin (set! seed (+ (car time) (cdr time))) |
|
#{ \setSeed #seed #} )) |
|
) |
|
\randomizeSeed |
|
|
|
showSeed = |
|
#(define-scheme-function (parser location) () |
|
#{ |
|
\markup { |
|
seed = #(number->string seed) |
|
} |
|
#} |
|
) |
|
|
|
showSolution = |
|
#(define-scheme-function () () |
|
(set! solution #t) |
|
) |
|
|
|
%turn solution of (only has effect after manually enabling it before) |
|
hideSolution = |
|
#(define-scheme-function () () |
|
(set! solution #f) |
|
) |
|
|
|
setBE = |
|
#(define-scheme-function () () |
|
(begin (set! useBE #t) (initTaskList #t)) |
|
) |
|
|
|
setTasks = |
|
#(define-scheme-function (tasksOn) (boolean?) |
|
(set! includeTasks tasksOn) |
|
) |
|
|
|
%%% Number of tasks, is updated automatically with every call to \task |
|
#(define taskNr 0) |
|
|
|
%%% Sum of points in all tasks |
|
#(define pointSum 0) |
|
|
|
%%%Predefined tasks |
|
taskList = #'() |
|
|
|
#(define (initTaskList BE) |
|
(if BE |
|
(set! taskList '( |
|
("timeSignatureTest" . "Bestimmen Sie die Taktart für jeden Takt!") |
|
("barLineTest" . "Setzen Sie Taktstriche, sodass vollständige Takte entstehen!") |
|
(("noteNameTest" . #\r) . "Benennen Sie die Töne inklusive Oktavbezeichnung!") |
|
(("noteNameTest" . #\w) . "Notieren Sie die angegebenen Töne!") |
|
(("noteNameTest" . #\s) . "Notieren Sie die angegebenen Töne! Wählen Sie einen passenden Schlüssel für jede Zeile!") |
|
(("containsTest" . 8) . "Geben Sie an, wie vielen Achtelnoten die folgenden Notenwerte entsprechen!") |
|
(("containsTest" . 16) . "Geben Sie an, wie vielen Achtelnoten die folgenden Notenwerte entsprechen!") |
|
(("intervalTest" . #\r) . "Bestimmen Sie die Intervalle!") |
|
(("intervalTest" . #\w) . "Bilden Sie die angegebenen Intervalle ausgehend von den jeweiligen Tönen!") |
|
(("scaleTest" . #\r) . "Bestimmen Sie folgende Tonleitern!") |
|
(("scaleTest" . #\w) . "Notieren Sie folgende Tonleitern!") |
|
(("chordTest" . #\r) . "Bestimmen Sie folgende Akkorde!") |
|
(("chordTest" . #\w) . "Notieren Sie folgende Akkorde!") |
|
)) |
|
(set! taskList '( |
|
("timeSignatureTest" . "Bestimme die Taktart für jeden Takt!") |
|
("barLineTest" . "Setze Taktstriche, sodass vollständige Takte entstehen!") |
|
(("noteNameTest" . #\r) . "Benenne die Töne inklusive Oktavbezeichnung!") |
|
(("noteNameTest" . #\w) . "Notiere die angegebenen Töne!") |
|
(("noteNameTest" . #\s) . "Notiere die angegebenen Töne! Wähle einen passenden Schlüssel für jede Zeile!") |
|
(("containsTest" . 8) . "Gib an, wie vielen Achtelnoten die folgenden Notenwerte entsprechen!") |
|
(("containsTest" . 16) . "Gib an, wie vielen Achtelnoten die folgenden Notenwerte entsprechen!") |
|
(("intervalTest" . #\r) . "Bestimme die Intervalle!") |
|
(("intervalTest" . #\w) . "Bilde die angegebenen Intervalle ausgehend von den jeweiligen Tönen!") |
|
(("scaleTest" . #\r) . "Bestimme folgende Tonleitern!") |
|
(("scaleTest" . #\w) . "Notiere folgende Tonleitern!") |
|
(("chordTest" . #\r) . "Bestimme folgende Akkorde!") |
|
(("chordTest" . #\w) . "Notiere folgende Akkorde!") |
|
))) |
|
) |
|
|
|
#(initTaskList useBE) |
|
|
|
%%% Task markup generator |
|
task = |
|
#(define-scheme-function (add text points) ((boolean?) string? number?) |
|
(begin (if (not add) (begin (set! taskNr (1+ taskNr)) (set! pointSum (+ pointSum points))) #{ #}) #{ |
|
\markup { |
|
\bold |
|
%\override #'(line-width . 100 ) |
|
\fill-with-pattern #1 #RIGHT " " |
|
\line { #(if add "Zusatz: " (string-append (number->string taskNr) ". ")) #text } |
|
\line { "/" #(number->string points) " " \concat {#(if add "Z" "") #(if useBE "BE" "P.")} } |
|
} |
|
#}) |
|
) |
|
|
|
resetTaskCounter = |
|
#(define-scheme-function () () |
|
(set! taskNr 0) |
|
(set! pointSum 0) |
|
) |
|
|
|
%%% Markup for keyboard |
|
whiteKeys = |
|
#(define-scheme-function (key-height key-width) ((number? 8) (number? 3)) |
|
#{ \markup { |
|
\concat { |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 (/ key-width 2)) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (-(/ key-width 2) 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 key-width) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0 (- key-width 0.1)) #(cons 0.1 (- key-height 0.1)) #0 |
|
\combine |
|
\with-color #black |
|
\filled-box #(cons 0 (/ key-width 2)) #(cons 0 key-height) #0 |
|
\with-color #white |
|
\filled-box #(cons 0.1 (/ key-width 2)) #(cons 0.1 (- key-height 0.1)) #0 |
|
} |
|
} |
|
#} |
|
) |
|
|
|
blackKeys = |
|
#(define-scheme-function (key-height key-width) ((number? 8) (number? 3)) |
|
#{ |
|
\markup { |
|
\concat { |
|
\filled-box #(cons (/ (* key-width 7) 6) (/ (* key-width 11) 6)) #(cons (/ key-height 3) key-height) #0 |
|
\filled-box #(cons (/ key-width 3) key-width) #(cons (/ key-height 3) key-height) #0 |
|
\filled-box #(cons (/ (* key-width 4) 3) (* key-width 2)) #(cons (/ key-height 3) key-height) #0 |
|
\filled-box #(cons (/ key-width 3) key-width) #(cons (/ key-height 3) key-height) #0 |
|
\filled-box #(cons (/ key-width 3) key-width) #(cons (/ key-height 3) key-height) #0 |
|
} |
|
} |
|
#} |
|
) |
|
keyboard = |
|
#(define-scheme-function (key-height key-width) ((number? 8) (number? 3)) |
|
#{ |
|
\markup{ |
|
\combine |
|
\whiteKeys #key-height #key-width |
|
\blackKeys #key-height #key-width |
|
} |
|
#} |
|
) |
|
|
|
%%% Markup for test result block |
|
result = |
|
#(define-scheme-function () () |
|
#{ |
|
|
|
\markup { |
|
\override #'(line-width . 35 ) |
|
\bold |
|
\column { |
|
\null |
|
\fill-line { #(if useBE "BE:" "Punkte:") \line { "/"#(number->string pointSum)} \line { "Note:" } } |
|
} } |
|
|
|
#} |
|
) |
|
|
|
%%% Markup for test result block |
|
resultKeyboard = |
|
#(define-scheme-function () () |
|
#{ |
|
|
|
\markup { |
|
\override #'(line-width . 105 ) |
|
\bold |
|
\column { |
|
\null |
|
\fill-line { |
|
\override #'(line-width . 35 ) |
|
\fill-line { #(if useBE "BE:" "Punkte:") \line { "/"#(number->string pointSum)} \line { "Note:" } } |
|
\line { \keyboard #10 #3.5 } |
|
} |
|
} } |
|
|
|
#} |
|
) |
|
|
|
%%% Markup for a test header table |
|
testHeader = |
|
#(define-scheme-function (date title) ((string? " ") list?) |
|
#{ \markup { |
|
%\override #'(line-width . 20 ) |
|
\column { |
|
\fill-line { Name: Klasse: \concat { "Datum: " #date }} |
|
\null |
|
\bold |
|
\fill-line { \fontsize #4 \center-column { #@title \null }} |
|
} } #} |
|
) |
|
|
|
%%% Blank box |
|
blankBox = |
|
#(define-scheme-function (width height) (number? number?) |
|
#{ |
|
\markup { |
|
\combine |
|
\combine |
|
%\filled-box #`(0 . ,width) #`(0 . ,height) #0 |
|
%\with-color #white |
|
%\filled-box #`(0.2 . ,(- width 0.2)) #`(0.2 . ,(- height 0.2)) #0 |
|
\draw-line #`(0 . ,height) |
|
\draw-line #`(,width . 0) |
|
\translate #`(,width . ,height) { |
|
\combine |
|
\draw-line #`(0 . ,(- 0 height)) |
|
\draw-line #`(,(- 0 width) . 0) } |
|
} #} |
|
) |
|
|
|
%% Readable ranges for allowed clefs |
|
#(define trebleRange '()) |
|
#(define bassRange '()) |
|
#(define altoRange '()) |
|
#(define tenorRange '()) |
|
#(define sopranoRange '()) |
|
#(define treble8vaRange '()) |
|
#(define treble8vbRange '()) |
|
#(define clef-ranges '()) |
|
|
|
setRange = |
|
#(define-scheme-function (clef pitch1 pitch2) (string? ly:pitch? ly:pitch?) |
|
(begin |
|
(cond |
|
((equal? clef "treble") (set! trebleRange (list pitch1 pitch2))) |
|
((equal? clef "alto") (set! altoRange (list pitch1 pitch2))) |
|
((equal? clef "tenor") (set! tenorRange (list pitch1 pitch2))) |
|
((equal? clef "soprano") (set! sopranoRange (list pitch1 pitch2))) |
|
((equal? clef "bass") (set! bassRange (list pitch1 pitch2))) |
|
((equal? clef "treble^8") (set! treble8vaRange (list pitch1 pitch2))) |
|
((equal? clef "treble_8") (set! treble8vbRange (list pitch1 pitch2)))) |
|
(set! clef-ranges |
|
`(("treble" . ,trebleRange) |
|
("alto" . ,altoRange) |
|
("tenor" . ,tenorRange) |
|
("soprano" . ,sopranoRange) |
|
("bass" . ,bassRange) |
|
("treble^8" . ,treble8vaRange) |
|
("treble_8" . ,treble8vbRange)))) |
|
) |
|
|
|
%initialize all clef ranges |
|
\setRange "treble" a c''' |
|
\setRange "bass" c, c' |
|
\setRange "alto" d d' |
|
\setRange "tenor" c h' |
|
\setRange "soprano" g f'' |
|
\setRange "treble^8" a' c'''' |
|
\setRange "treble_8" a, c'' |
|
|
|
#(define accidentals-no-doubles |
|
(list -1/2 0 0 0 1/2)) |
|
|
|
%weighted list to make double accidentals less likely |
|
#(define accidentals-doubles |
|
(list -1 -1/2 -1/2 0 0 0 1/2 1/2 1)) |
|
|
|
#(define no-accidentals |
|
(list 0)) |
|
|
|
newnames = |
|
#`( |
|
("c''''" . ,(markup "c" #:super "4")) ("cis''''" . ,(markup "cis" #:super "4")) ("ces''''" . ,(markup "ces" #:super "4")) ("cisis''''" . ,(markup "cisis" #:super "4")) ("ceses''''" . ,(markup "ceses" #:super "4")) |
|
("d''''" . ,(markup "d" #:super "4")) ("dis''''" . ,(markup "dis" #:super "4")) ("des''''" . ,(markup "des" #:super "4")) ("disis''''" . ,(markup "disis" #:super "4")) ("deses''''" . ,(markup "deses" #:super "4")) |
|
("e''''" . ,(markup "e" #:super "4")) ("eis''''" . ,(markup "eis" #:super "4")) ("ees''''" . ,(markup "es" #:super "4")) ("eisis''''" . ,(markup "eisis" #:super "4")) ("eeses''''" . ,(markup "eses" #:super "4")) |
|
("f''''" . ,(markup "f" #:super "4")) ("fis''''" . ,(markup "fis" #:super "4")) ("fes''''" . ,(markup "fes" #:super "4")) ("fisis''''" . ,(markup "fisis" #:super "4")) ("feses''''" . ,(markup "feses" #:super "4")) |
|
("g''''" . ,(markup "g" #:super "4")) ("gis''''" . ,(markup "gis" #:super "4")) ("ges''''" . ,(markup "ges" #:super "4")) ("gisis''''" . ,(markup "gisis" #:super "4")) ("geses''''" . ,(markup "geses" #:super "4")) |
|
("a''''" . ,(markup "a" #:super "4")) ("ais''''" . ,(markup "ais" #:super "4")) ("aes''''" . ,(markup "as" #:super "4")) ("aisis''''" . ,(markup "aisis" #:super "4")) ("aeses''''" . ,(markup "ases" #:super "4")) |
|
("b''''" . ,(markup "h" #:super "4")) ("bis''''" . ,(markup "his" #:super "4")) ("bes''''" . ,(markup "b" #:super "4")) ("bisis''''" . ,(markup "hisis" #:super "4")) ("beses''''" . ,(markup "hes" #:super "4")) |
|
("c'''" . "c³") ("cis'''" . "cis³") ("ces'''" . "ces³") ("cisis'''" . "cisis³") ("ceses'''" . "ceses³") |
|
("d'''" . "d³") ("dis'''" . "dis³") ("des'''" . "des³") ("disis'''" . "disis³") ("deses'''" . "deses³") |
|
("e'''" . "e³") ("eis'''" . "eis³") ("ees'''" . "es³") ("eisis'''" . "eisis³") ("eeses'''" . "eses³") |
|
("f'''" . "f³") ("fis'''" . "fis³") ("fes'''" . "fes³") ("fisis'''" . "fisis³") ("feses'''" . "feses³") |
|
("g'''" . "g³") ("gis'''" . "gis³") ("ges'''" . "ges³") ("gisis'''" . "gisis³") ("geses'''" . "geses³") |
|
("a'''" . "a³") ("ais'''" . "ais³") ("aes'''" . "as³") ("aisis'''" . "aisis³") ("aeses'''" . "ases³") |
|
("b'''" . "h³") ("bis'''" . "his³") ("bes'''" . "b³") ("bisis'''" . "hisis³") ("beses'''" . "hes³") |
|
("c''" . "c²") ("cis''" . "cis²") ("ces''" . "ces²") ("cisis''" . "cisis²") ("ceses''" . "ceses²") |
|
("d''" . "d²") ("dis''" . "dis²") ("des''" . "des²") ("disis''" . "disis²") ("deses''" . "deses²") |
|
("e''" . "e²") ("eis''" . "eis²") ("ees''" . "es²") ("eisis''" . "eisis²") ("eeses''" . "eses²") |
|
("f''" . "f²") ("fis''" . "fis²") ("fes''" . "fes²") ("fisis''" . "fisis²") ("feses''" . "feses²") |
|
("g''" . "g²") ("gis''" . "gis²") ("ges''" . "ges²") ("gisis''" . "gisis²") ("geses''" . "geses²") |
|
("a''" . "a²") ("ais''" . "ais²") ("aes''" . "as²") ("aisis''" . "aisis²") ("aeses''" . "ases²") |
|
("b''" . "h²") ("bis''" . "his²") ("bes''" . "b²") ("bisis''" . "hisis²") ("beses''" . "hes²") |
|
("c'" . "c¹") ("cis'" . "cis¹") ("ces'" . "ces¹") ("cisis'" . "cisis¹") ("ceses'" . "ceses¹") |
|
("d'" . "d¹") ("dis'" . "dis¹") ("des'" . "des¹") ("disis'" . "disis¹") ("deses'" . "deses¹") |
|
("e'" . "e¹") ("eis'" . "eis¹") ("ees'" . "es¹") ("eisis'" . "eisis¹") ("eeses'" . "eses¹") |
|
("f'" . "f¹") ("fis'" . "fis¹") ("fes'" . "fes¹") ("fisis'" . "fisis¹") ("feses'" . "feses¹") |
|
("g'" . "g¹") ("gis'" . "gis¹") ("ges'" . "ges¹") ("gisis'" . "gisis¹") ("geses'" . "geses¹") |
|
("a'" . "a¹") ("ais'" . "ais¹") ("aes'" . "as¹") ("aisis'" . "aisis¹") ("aeses'" . "ases¹") |
|
("b'" . "h¹") ("bis'" . "his¹") ("bes'" . "b¹") ("bisis'" . "hisis¹") ("beses'" . "hes¹") |
|
|
|
("c" . "c") ("cis" . "cis") ("ces" . "ces") ("cisis" . "cisis") ("ceses" . "ceses") |
|
("d" . "d") ("dis" . "dis") ("des" . "des") ("disis" . "disis") ("deses" . "deses") |
|
("e" . "e") ("eis" . "eis") ("ees" . "es") ("eisis" . "eisis") ("eeses" . "eses") |
|
("f" . "f") ("fis" . "fis") ("fes" . "fes") ("fisis" . "fisis") ("feses" . "feses") |
|
("g" . "g") ("gis" . "gis") ("ges" . "ges") ("gisis" . "gisis") ("geses" . "geses") |
|
("a" . "a") ("ais" . "ais") ("aes" . "as") ("aisis" . "aisis") ("aeses" . "ases") |
|
("b" . "h") ("bis" . "his") ("bes" . "b") ("bisis" . "hisis") ("beses" . "hes") |
|
|
|
("c," . "C") ("cis," . "Cis") ("ces," . "Ces") ("cisis," . "Cisis") ("ceses," . "Ceses") |
|
("d," . "D") ("dis," . "Dis") ("des," . "Des") ("disis," . "Disis") ("deses," . "Deses") |
|
("e," . "E") ("eis," . "Eis") ("ees," . "Es") ("eisis," . "Eisis") ("eeses," . "Eses") |
|
("f," . "F") ("fis," . "Fis") ("fes," . "Fes") ("fisis," . "Fisis") ("feses," . "Feses") |
|
("g," . "G") ("gis," . "Gis") ("ges," . "Ges") ("gisis," . "Gisis") ("geses," . "Geses") |
|
("a," . "A") ("ais," . "Ais") ("aes," . "As") ("aisis," . "Aisis") ("aeses," . "Ases") |
|
("b," . "H") ("bis," . "His") ("bes," . "B") ("bisis," . "Hisis") ("beses," . "Hes") |
|
|
|
("c,," . "C¹") ("cis,," . "Cis¹") ("ces,," . "Ces¹") ("cisis,," . "Cisis¹") ("ceses,," . "Ceses¹") |
|
("d,," . "D¹") ("dis,," . "Dis¹") ("des,," . "Des¹") ("disis,," . "Disis¹") ("deses,," . "Deses¹") |
|
("e,," . "E¹") ("eis,," . "Eis¹") ("ees,," . "Es¹") ("eisis,," . "Eisis¹") ("eeses,," . "Eses¹") |
|
("f,," . "F¹") ("fis,," . "Fis¹") ("fes,," . "Fes¹") ("fisis,," . "Fisis¹") ("feses,," . "Feses¹") |
|
("g,," . "G¹") ("gis,," . "Gis¹") ("ges,," . "Ges¹") ("gisis,," . "Gisis¹") ("geses,," . "Geses¹") |
|
("a,," . "A¹") ("ais,," . "Ais¹") ("aes,," . "As¹") ("aisis,," . "Aisis¹") ("aeses,," . "Ases¹") |
|
("b,," . "H¹") ("bis,," . "His¹") ("bes,," . "B¹") ("bisis,," . "Hisis¹") ("beses,," . "Hes¹") |
|
) |
|
|
|
germanNoteNames = |
|
#(lambda (grob) |
|
(let* ((default-name (ly:grob-property grob 'text)) |
|
(new-name (assoc-get default-name newnames))) |
|
(ly:grob-set-property! grob 'text new-name) |
|
(ly:text-interface::print grob))) |
|
|
|
blankNoteNames = |
|
#(lambda (grob) |
|
(let* ((default-name (ly:grob-property grob 'text))) |
|
(ly:grob-set-property! grob 'text "___") |
|
(ly:text-interface::print grob))) |
|
|
|
%% Calculate base interval |
|
#(define (calc-white-note-span note1 note2) |
|
(let ((o1 (ly:pitch-octave note1)) |
|
(o2 (ly:pitch-octave note2)) |
|
(nn1 (ly:pitch-notename note1)) |
|
(nn2 (ly:pitch-notename note2))) |
|
(+ (* (- o2 o1) 7) |
|
(1+ (- nn2 nn1))))) |
|
|
|
#(define (make-note pitch dur) |
|
(make-music |
|
'NoteEvent |
|
'duration |
|
(ly:make-duration dur) |
|
'pitch |
|
pitch)) |
|
|
|
#(define (get-random-pitch clef acc-pool) |
|
(let* ((range (ly:assoc-get clef clef-ranges)) |
|
(white-notes (calc-white-note-span (car range) (cadr range))) |
|
(random-pitch-diff (random white-notes))) |
|
(ly:make-pitch |
|
(ly:pitch-octave (car range)) |
|
(+ random-pitch-diff (ly:pitch-notename (car range))) |
|
(list-ref acc-pool (random (length acc-pool)))))) |
|
|
|
%Check for double accidentals |
|
#(define (has-doubles mus) |
|
(any (lambda (p) (not (< -1 (ly:pitch-alteration p) 1))) |
|
(music-pitches mus))) |
|
|
|
makeClefTest = |
|
#(define-music-function (allowDuplicates num clef acc-pool) |
|
(boolean? number? string? (list? accidentals-no-doubles)) |
|
(let loop ((x 0) (return '())) |
|
(if (< x num) |
|
(let ((item (make-note (get-random-pitch clef acc-pool) 0))) |
|
(if (or allowDuplicates (not (member item return))) |
|
(loop |
|
(1+ x) |
|
(append return |
|
(list |
|
#{ \clef #clef #} |
|
item)) |
|
) |
|
;;; retry to get a new pitch that doesn't exist for the current clef |
|
(loop x return) |
|
)) |
|
#{ |
|
{ |
|
#@return |
|
} |
|
#}))) |
|
|
|
makeNoteNameTest = |
|
#(define-scheme-function (allowDuplicates numTreble brTreble numBass brBass numC brC num8va br8va num8vb |
|
acc-pool cClef mode) |
|
( (boolean? #f) number? (boolean? #f) number? (boolean? #f) number? (boolean? #f) number? (boolean? #f) number? |
|
(list? accidentals-no-doubles) (string? "alto") char?) |
|
(let ((content #{ |
|
{ |
|
\makeClefTest #allowDuplicates #numTreble "treble" #acc-pool #(if brTreble #{ \break #} #{ #}) |
|
\makeClefTest #allowDuplicates #numBass "bass" #acc-pool #(if brBass #{ \break #} #{ #}) |
|
\makeClefTest #allowDuplicates #numC #cClef #acc-pool #(if brC #{ \break #} #{ #}) |
|
\makeClefTest #allowDuplicates #num8va "treble^8" #acc-pool #(if br8va #{ \break #} #{ #}) |
|
\makeClefTest #allowDuplicates #num8vb "treble_8" #acc-pool |
|
\undo \omit Score.BarLine |
|
\bar "|." |
|
} |
|
#})) |
|
(let ((result (scorify-music #{ |
|
\time 4/4 |
|
\omit Score.TimeSignature |
|
% \omit Score.BarLine |
|
|
|
%%%strict mode - hide clefs |
|
#(if (and (not solution) (equal? mode #\s)) #{ |
|
\override Score.Clef.stencil = #ly:text-interface::print |
|
\override Score.Clef #'Y-offset = -3 |
|
\hide Score.ClefModifier |
|
\override Score.Clef.text = \blankBox 5 8 |
|
#} #{ #}) |
|
|
|
\set Score.explicitClefVisibility = #end-of-line-invisible |
|
%%%Format solutions |
|
#(if solution (if (equal? mode #\r) |
|
#{ \override Score.NoteName.color = #red #} |
|
#{ \override Score.NoteHead.color = #red |
|
\override Score.Stem.color = #red |
|
\override Score.Accidental.color = #red |
|
\override Score.LedgerLineSpanner.color = #red |
|
#(if (equal? mode #\s) #{ |
|
\override Score.Clef.color = #red |
|
\override Score.ClefModifier.color = #red #} #{ #} ) #} ) #{ #}) |
|
|
|
\new Staff { |
|
\set Staff.explicitCueClefVisibility = ##f |
|
#(if (and (not solution) (or (equal? mode #\w) (equal? mode #\s))) #{ \hideNotes #} #{ #}) |
|
<< |
|
#content |
|
\context NoteNames \with { |
|
%%% Show notenames only for reading tasks |
|
\override NoteName #'stencil = #(if (and (not solution) (equal? mode #\r)) blankNoteNames germanNoteNames) |
|
\override NoteName #'Y-offset = -2 |
|
\override NoteName #'X-offset = -1 |
|
} { |
|
\set printOctaveNames = ##t |
|
#content |
|
} |
|
>> |
|
} |
|
#}))) |
|
(if includeTasks (add-text |
|
#{ |
|
\task #(assoc-get (cons "noteNameTest" mode) taskList) #(+ numTreble numBass numC num8va num8vb) |
|
#} ) '()) |
|
(add-score #{ #result #}) |
|
) |
|
) |
|
) |
|
|
|
blanks = |
|
#(define-scheme-function (num) (number?) |
|
(let ((str (map (lambda (n) "___") |
|
(iota num 1)))) |
|
#{ |
|
\lyricmode { #@str } |
|
#})) |
|
|
|
%%% RHYTHM TEST GENERATORS |
|
|
|
%list of possible time signature denominators - corresponding to numerators below |
|
#(define denominators |
|
(list 4 4 4 4 4 8 8) |
|
) |
|
|
|
%list of possible time signature numerators |
|
#(define numerators |
|
(list 2 3 4 5 6 3 6) |
|
) |
|
|
|
%list of possible rhythm patterns in various time signatures |
|
#(define note-pool |
|
(list |
|
;;; 2/4 |
|
(ly:music-property #{ |
|
{g'4 g'4} {g'8 g' g'4} {g'4. g'8} {g'8 g'4.} {g'8 g' g' g'} |
|
{g'16 g' g' g' g'4} {g'16 g' g'8 g' g'} |
|
{g'2} |
|
#} |
|
'elements) |
|
;;; 3/4 |
|
(ly:music-property #{ |
|
{g'4 g'4 g'4} {g'8 g' g'2} {g'4. g'8 g'4} {g'8 g'4. g'16 g' g'8} {g'8 g'4 g'8 g'4} |
|
{g'8 g' g'4 g'16 g' g' g'} {g'8 g'16 g'~ g'8. g'16 g'4} |
|
{g'2.} |
|
#} |
|
'elements) |
|
;;; 4/4 |
|
(ly:music-property #{ |
|
{g'2 g'2} {g'8 g' g'4. g'8 g'16 g' g'8 } |
|
{g'4. g'8 g'2} {g'8 g'4.~ g'8 g' g'4} {g'8 g'4 g' g' g'8} |
|
{g'16 g' g' g' g'4. g'8 g'4} {g'16 g' g'8 g' g' g' g'4.} |
|
{g'1} |
|
#} |
|
'elements) |
|
;;; 5/4 |
|
(ly:music-property #{ |
|
{g'1 g'4} {g'4 g'8 g' g'4 g'2} {g'4 g'16 g' g'8 g' g'16 g' g'8 g'4.} |
|
#} |
|
'elements) |
|
;;; 6/4 |
|
(ly:music-property #{ |
|
{g'2. g'} {g'8 g' g'4 g' g'2 g'8 g'} {g'2 g' g'} |
|
{g'4. g'8 g'16 g' g'8 g'2.} |
|
#} |
|
'elements) |
|
;;; 3/8 |
|
(ly:music-property #{ |
|
{g'4.} {g'16 g' g'8 g'8} {g'8 g'16 g' g'8} {g'8 g'4} |
|
#} |
|
'elements) |
|
;;; 6/8 |
|
(ly:music-property #{ |
|
{g'8 g' g' g'4.} {g'4 g'8 g'16 g' g'8 g'} |
|
#} |
|
'elements) |
|
) |
|
) |
|
|
|
%generate a time signature based on the lists above |
|
ts = |
|
#(define-music-function (idx) (number?) |
|
(let ((index (random (length denominators))))(make-music |
|
'TimeSignatureMusic |
|
'beat-structure |
|
'() |
|
'denominator |
|
(list-ref denominators idx) |
|
'numerator |
|
(list-ref numerators idx))) |
|
) |
|
|
|
%Time Signature Test Generator |
|
makeTimeSignatureTest = |
|
#(define-scheme-function (allowDuplicateSignature allowDuplicates num) ((boolean? #t) (boolean?) number?) |
|
(let loop ((i 0) (return '())) |
|
(if (< i num) |
|
(let* ((index (random (length denominators))) (timeSignature #{ \ts #index #}) (notes (list-ref note-pool index)) (item (list-ref notes (random (length notes))))) |
|
;;;check if unallowed duplicates exist |
|
(if (and (or allowDuplicates (not (member item return))) (or allowDuplicateSignature (not (member timeSignature return)))) |
|
(loop |
|
(1+ i) |
|
(append return |
|
(list |
|
timeSignature |
|
item))) |
|
(loop i return) |
|
)) |
|
|
|
(let ((result (scorify-music #{ |
|
{ |
|
#(if (not solution) #{ \hide Score.TimeSignature #} #{ \numericTimeSignature \override Score.TimeSignature.color = #red #}) |
|
\override Score.TimeSignature.break-visibility = #end-of-line-invisible |
|
#@return |
|
} |
|
#}))) |
|
(if includeTasks (add-text |
|
#{ |
|
|
|
\task #(assoc-get "timeSignatureTest" taskList) #num |
|
#} ) '()) |
|
(add-score #{ #result #})))) |
|
) |
|
|
|
%Barline Test Generator |
|
makeBarLineTest = |
|
#(define-scheme-function (allowDuplicateSignature allowDuplicates numSignatures numBars) ((boolean? #f) (boolean?) number? number?) |
|
(let loop ((i 0) (return '())) |
|
(if (< i numSignatures) |
|
(let* ((index (random 3)) (timeSignature #{ \ts #index #}) (notes (list-ref note-pool index)) ) |
|
;;;check if unallowed duplicates exist |
|
(if (or allowDuplicateSignature (not (member timeSignature return))) |
|
(loop |
|
(1+ i) |
|
(append return |
|
(list |
|
timeSignature |
|
(let iLoop ((k 0) (bars '())) |
|
(if (< k numBars) |
|
(let ((item (list-ref notes (random (length notes))))) |
|
(if (not (member item bars)) |
|
(iLoop (1+ k) (append bars (list item))) |
|
(iLoop k bars))) |
|
#{ { #@bars } #}) |
|
) |
|
#{ \break #} ))) |
|
(loop i return) |
|
)) |
|
|
|
(let ((result (scorify-music #{ |
|
{ |
|
\numericTimeSignature |
|
#(if (not solution) #{ \omit Score.BarLine #} #{ \override Score.BarLine.color = #red #}) |
|
\override Score.TimeSignature.break-visibility = #end-of-line-invisible |
|
#@return |
|
} |
|
#}))) |
|
(if includeTasks (add-text |
|
#{ |
|
|
|
\task #(assoc-get "barLineTest" taskList) #(* numSignatures numBars) |
|
#} ) '()) |
|
(add-score #{ #result #}) |
|
))) |
|
) |
|
|
|
%"How many notes contains..." test generator |
|
%pool of values |
|
#(define duration-pool |
|
(list |
|
;;; for 8th's |
|
(ly:music-property #{ |
|
{g'4} {g'8} {g'2} {g'1} |
|
{g'1.} {g'2.} {g'4.} |
|
{g'1~ g'4} {g'1~ g'8} {g'2~ g'8} {g'4~ g'1} {g'4~ g'8} |
|
{g'1~ g'4.} {g'2~ g'4.} {g'2.~ g'4} {g'2.~ g'4.} |
|
{g'16~ g'16} |
|
#} |
|
'elements) |
|
|
|
;;; for 16th's |
|
(ly:music-property #{ |
|
{g'4} {g'8} {g'2} {g'1} |
|
{g'1.} {g'2.} {g'4.} |
|
{g'1~ g'4} {g'1~ g'8} {g'2~ g'8} {g'4~ g'1} {g'4~ g'8} |
|
{g'1~ g'4.} {g'2~ g'4.} {g'2.~ g'4} {g'2.~ g'4.} |
|
{g'16~ g'16} |
|
{g'4~ g'16} {g'4~ g'8.} {g'8.} |
|
#} |
|
'elements) |
|
) |
|
) |
|
|
|
%main function for providing How-many-tests |
|
makeContainsTest = |
|
#(define-scheme-function (allowDuplicates unit num) ((boolean?) number? number?) |
|
(let loop ((x 0) (return '())) |
|
(if (< x num) |
|
(let* ( (pool (list-ref duration-pool (if (equal? unit 8) 0 1))) (index (random (length pool))) (item (list-ref pool index))) |
|
(if (or allowDuplicates (not (member item return))) |
|
(loop |
|
(1+ x) |
|
(append return |
|
(list |
|
item |
|
#{ \bar "|" #} )) |
|
) |
|
;;; retry to get a new pitch that doesn't exist for the current clef |
|
(loop x return) |
|
)) |
|
|
|
(let ((result (scorify-music #{ |
|
{ |
|
\time 99/4 |
|
\omit Score.TimeSignature |
|
|
|
{ #@return } \addlyrics { |
|
#(if (not solution) |
|
#{ \blanks #num #} |
|
#{\override Score.LyricText.color = #red |
|
\solveContains #unit #return #}) |
|
} |
|
} |
|
#}))) |
|
(if includeTasks (add-text |
|
#{ |
|
|
|
\task #(assoc-get (cons "containsTest" unit) taskList) #num |
|
#} ) '()) |
|
(add-score #{ #result #} )))) |
|
|
|
) |
|
|
|
%helper predicate to check if a string equals "0" |
|
#(define (stringZero? str) |
|
(if (equal? str "0") |
|
#t |
|
#f) |
|
) |
|
|
|
%provide solution for How many-tasks |
|
solveContains = |
|
#(define-music-function (unit music) (number? list?) |
|
(let ((solution (remove stringZero? |
|
(map (lambda (mus) (let* ( |
|
(mom (ly:music-length mus )) |
|
(p (ly:moment-main-numerator mom)) |
|
(q (ly:moment-main-denominator mom))) |
|
(number->string (* (/ unit q) p)))) |
|
music)))) |
|
#{ \lyricmode { #@solution } #} |
|
) |
|
) |
|
|
|
%%%Interval test suite |
|
tone-steps = |
|
#'(((1 . 1)."HT") ((1 . 2)."GT")) |
|
|
|
easy-intervals = |
|
#'( |
|
((0 . 0)."r1") |
|
((1 . 1)."k2") ((1 . 2)."g2") |
|
((2 . 3)."k3") ((2 . 4)."g3") |
|
((3 . 5)."r4") |
|
((4 . 7)."r5") |
|
((5 . 8)."k6") ((5 . 9)."g6") |
|
((6 . 10)."k7") ((6 . 11)."g7") |
|
((7 . 12)."r8")) |
|
|
|
normal-intervals = |
|
#'( |
|
((0 . 0)."r1") ((0 . 1)."ü1") |
|
((1 . 1)."k2") ((1 . 2)."g2") |
|
((2 . 3)."k3") ((2 . 4)."g3") |
|
((3 . 5)."r4") ((3 . 4)."v4") ((3 . 6)."ü4") |
|
((4 . 7)."r5") ((4 . 6)."v5") ((4 . 8)."ü5") |
|
((5 . 8)."k6") ((5 . 9)."g6") |
|
((6 . 10)."k7") ((6 . 11)."g7") |
|
((7 . 12)."r8") ((7 . 11)."v8") ((7 . 13)."ü8") |
|
) |
|
|
|
all-intervals = |
|
#'( |
|
((0 . 0)."r1") ((0 . 1)."ü1") |
|
((1 . 1)."k2") ((1 . 2)."g2") |
|
((2 . 3)."k3") ((2 . 4)."g3") |
|
((3 . 5)."r4") ((3 . 4)."v4") ((3 . 6)."ü4") |
|
((4 . 7)."r5") ((4 . 6)."v5") ((4 . 8)."ü5") |
|
((5 . 8)."k6") ((5 . 9)."g6") |
|
((6 . 10)."k7") ((6 . 11)."g7") |
|
((7 . 12)."r8") ((7 . 11)."v8") ((7 . 13)."ü8") |
|
((1 . 0)."v2") ((1 . 3)."ü2") |
|
((2 . 2)."v3") ((2 . 5)."ü3") |
|
((5 . 7)."v6") ((5 . 10)."ü6") |
|
((6 . 9)."v7") ((6 . 12)."ü7")) |
|
|
|
#(define (getIntervalName p1 p2 intervalList) |
|
(let ((steps (abs (- (ly:pitch-steps p1) (ly:pitch-steps p2)))) |
|
(semitones (abs (- (ly:pitch-semitones p1) (ly:pitch-semitones p2))))) |
|
(begin |
|
(assoc-get (cons steps semitones) intervalList))) |
|
) |
|
|
|
#(define (arrow p1 p2) |
|
(cond |
|
((< (ly:pitch-semitones p1) (ly:pitch-semitones p2)) |
|
#{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\translate #'(0 . 2) \arrow-head #Y #UP ##t |
|
\draw-line #'(0 . 2) |
|
} #} ) |
|
((equal? p1 p2) " ") |
|
(else #{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\draw-line #'(0 . 2) |
|
\arrow-head #Y #DOWN ##t |
|
}#})) |
|
) |
|
|
|
#(define arrow-up |
|
#{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\translate #'(0 . 2) \arrow-head #Y #UP ##t |
|
\draw-line #'(0 . 2) |
|
} #} ) |
|
#(define arrow-down |
|
#{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\draw-line #'(0 . 2) \arrow-head #Y #DOWN ##t |
|
} #} ) |
|
#(define arrow-left |
|
#{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\arrow-head #X #LEFT ##t |
|
\draw-line #'(2 . 0) |
|
} #} ) |
|
#(define arrow-right |
|
#{ \markup { |
|
|
|
\override #'(thickness . 1) |
|
\combine |
|
\draw-line #'(2 . 0) |
|
\translate #'(2 . 0) \arrow-head #X #RIGHT ##t |
|
} #} ) |
|
|
|
makeIntervalTest = |
|
#(define-scheme-function (allowDuplicates interval-list acc-pool num mode) |
|
((boolean?) (list? normal-intervals) (list? accidentals-no-doubles) number? char?) |
|
(let loop ((x 0) (return '()) (solutionList '())) |
|
(if (< x num) |
|
(let* ((p1 (get-random-pitch "treble" acc-pool)) |
|
(p2 (get-random-pitch "treble" acc-pool)) |
|
(name (getIntervalName p1 p2 interval-list))) |
|
(if (and name (or allowDuplicates (not (member name solutionList)))) |
|
(loop (1+ x) |
|
(append return (list (make-note p1 2) (if |
|
(equal? mode #\w) |
|
(if (not solution) |
|
#{ \hideNotes #} |
|
#{ \override Score.NoteHead.color = #red |
|
\override Score.Stem.color = #red |
|
\override Score.Accidental.color = #red |
|
\override Score.LedgerLineSpanner.color = #red |
|
#}) |
|
#{ #}) |
|
(make-note p2 2) |
|
(if (equal? mode #\w) |
|
(if (not solution) |
|
#{ \unHideNotes #} |
|
#{ \revert Score.NoteHead.color |
|
\revert Score.Stem.color |
|
\revert Score.Accidental.color #}) |
|
#{ #}))) |
|
(append solutionList (list name (arrow p1 p2)))) |
|
(loop x return solutionList) |
|
) |
|
) |
|
(let ((result (scorify-music #{ |
|
\time 2/4 |
|
\omit Score.TimeSignature |
|
{ |
|
#@return |
|
|
|
} \addlyrics { |
|
#(if (not solution) |
|
(if (equal? mode #\r) |
|
#{ \lyricmode { \repeat unfold #num { "___" " " } } #} |
|
#{ \lyricmode { #@solutionList } #}) |
|
(if (equal? mode #\r) |
|
#{\override Score.LyricText.color = #red |
|
\lyricmode { #@solutionList } #} |
|
#{ \lyricmode { #@solutionList } #})) |
|
} |
|
#}))) |
|
(if includeTasks (add-text |
|
#{ |
|
|
|
\task #(assoc-get (cons "intervalTest" mode) taskList) #num |
|
#} ) '()) |
|
(add-score |
|
#{ #result #})) |
|
) |
|
) |
|
) |
|
|
|
%%% Scale test generator |
|
|
|
noteNameLookup = |
|
#`( |
|
(0 . "c") |
|
(1 . "d") |
|
(2 . "e") |
|
(3 . "f") |
|
(4 . "g") |
|
(5 . "a") |
|
(6 . "b") |
|
) |
|
|
|
scaleNoteLookup = |
|
#`( |
|
("ionisch" . ,#{ \key c \major c'1 d' e' f' g' a' h' c'' #}) |
|
("Dur" . ,#{ \key c \major c'1 d' e' f' g' a' h' c'' #}) |
|
("dorisch" . ,#{ \key c \dorian c'1 d' es' f' g' a' b' c'' #}) |
|
("phrygisch" . ,#{ \key c \phrygian c'1 des' es' f' g' as' b' c'' #}) |
|
("lydisch" . ,#{ \key c \lydian c'1 d' e' fis' g' a' h' c'' #}) |
|
("mixolydisch" . ,#{ \key c \mixolydian c'1 d' e' f' g' a' b' c'' #}) |
|
("äolisch" . ,#{ \key c \minor c'1 d' es' f' g' as' b' c'' #}) |
|
("moll" . ,#{ \key c \minor c'1 d' es' f' g' as' b' c'' #}) |
|
("äolisch melodisch" . ,#{ \key c \minor c'1 d' es' f' g' a' h' c'' #}) |
|
("äolisch harmonisch" . ,#{ \key c \minor c'1 d' es' f' g' as' h' c'' #}) |
|
("moll melodisch" . ,#{ \key c \minor c'1 d' es' f' g' a' h' c'' #}) |
|
("moll harmonisch" . ,#{ \key c \minor c'1 d' es' f' g' as' h' c'' #}) |
|
("lokrisch" . ,#{ \key c \locrian c'1 des' es' f' ges' as' b' c'' #}) |
|
) |
|
|
|
#(define majorRoots (list |
|
(ly:make-pitch 0 0 0) ;;;C |
|
(ly:make-pitch 0 3 0) ;;;F |
|
(ly:make-pitch 0 4 0) ;;;G |
|
(ly:make-pitch 0 6 -1/2) ;;;Bb |
|
(ly:make-pitch 0 1 0) ;;;D |
|
(ly:make-pitch 0 2 -1/2) ;;;Es |
|
(ly:make-pitch 0 5 0) ;;;A |
|
(ly:make-pitch 0 5 -1/2) ;;;As |
|
(ly:make-pitch 0 2 0) ;;;E |
|
(ly:make-pitch 0 1 -1/2) ;;;Des |
|
(ly:make-pitch 0 6 0) ;;;H |
|
(ly:make-pitch 0 4 -1/2) ;;;Ges |
|
(ly:make-pitch 0 3 1/2) ;;;Fis |
|
)) |
|
|
|
#(define minorRoots (list |
|
(ly:make-pitch 0 5 0) ;;;a |
|
(ly:make-pitch 0 1 0) ;;;d |
|
(ly:make-pitch 0 2 0) ;;;e |
|
(ly:make-pitch 0 4 0) ;;;g |
|
(ly:make-pitch 0 6 0) ;;;h |
|
(ly:make-pitch 0 0 0) ;;;c |
|
(ly:make-pitch 0 3 0) ;;;f |
|
(ly:make-pitch 0 3 1/2) ;;;fis |
|
(ly:make-pitch 0 0 1/2) ;;;cis |
|
(ly:make-pitch 0 6 -1/2) ;;;b |
|
(ly:make-pitch 0 4 1/2) ;;;gis |
|
(ly:make-pitch 0 2 -1/2) ;;;es |
|
(ly:make-pitch 0 1 1/2) ;;;dis |
|
)) |
|
|
|
scaleRoots = |
|
#`( |
|
("ionisch" . ,majorRoots ) |
|
("Dur" . ,majorRoots) |
|
("dorisch" . ,minorRoots) |
|
("phrygisch" . ,minorRoots) |
|
("lydisch" . ,majorRoots) |
|
("mixolydisch" . ,majorRoots) |
|
("äolisch" . ,minorRoots) |
|
("moll" . ,minorRoots) |
|
("moll melodisch" . ,minorRoots) |
|
("moll harmonisch" . ,minorRoots) |
|
("äolisch melodisch" . ,minorRoots) |
|
("äolisch harmonisch" . ,minorRoots) |
|
("lokrisch" . ,minorRoots) |
|
) |
|
|
|
easy-scales = |
|
#(list |
|
"Dur" "moll" |
|
) |
|
|
|
normal-scales = |
|
#(list |
|
"Dur" "moll" "moll melodisch" "moll harmonisch" |
|
) |
|
|
|
|
|
modal-scales = |
|
#(list |
|
"ionisch" "dorisch" "phrygisch" "lydisch" "mixolydisch" "äolisch" "äolisch harmonisch" "äolisch melodisch" "lokrisch" |
|
) |
|
|
|
#(define (getNoteName pitch) |
|
(let* ((pitchName (assoc-get (ly:pitch-notename pitch) noteNameLookup)) |
|
(alteration (cond ((< (ly:pitch-alteration pitch) 0) "es") |
|
((> (ly:pitch-alteration pitch) 0) "is") |
|
(else ""))) |
|
(dutchName (string-append pitchName alteration ","))) |
|
(assoc-get dutchName newnames)) |
|
) |
|
|
|
makeScaleTest = |
|
#(define-scheme-function (allowDuplicates scales num maxAcc mode) ( (boolean?) (list? normal-scales) number? (number? 6) char?) |
|
(let loop ((x 0) (return '()) (lyrics '())) |
|
(if (< x num) |
|
(let* ((scale (list-ref scales (random (length scales)))) |
|
(rootIndex (if (> maxAcc 0) (random (* 2 maxAcc)) 0)) |
|
(possibleRoots (assoc-get scale scaleRoots)) |
|
(root (list-ref possibleRoots rootIndex)) |
|
(music #{ |
|
\transpose c' #root |
|
#(ly:music-deep-copy (assoc-get scale scaleNoteLookup)) #}) |
|
(solution (list (string-append (getNoteName root) " " scale) #{ \lyricmode { \repeat unfold 7 _ } #} ))) |
|
(if (and (not (member music return)) (not (has-doubles music))) |
|
(loop |
|
(1+ x) |
|
(append return |
|
(list music)) |
|
(append lyrics solution)) |
|
(loop x return lyrics))) |
|
(let ((result (scorify-music #{ |
|
\time 8/1 |
|
\omit Score.TimeSignature |
|
\override Score.KeySignature.break-visibility = #end-of-line-invisible |
|
\set Score.explicitKeySignatureVisibility = #end-of-line-invisible |
|
\set Staff.printKeyCancellation = ##f |
|
\override Score.KeyCancellation.break-visibility = #end-of-line-invisible |
|
{ |
|
#(if (equal? mode #\r) |
|
#{ \omit Score.KeyCancellation #} |
|
(if solution |
|
#{ \override Score.NoteHead.color = #red |
|
\override Score.Stem.color = #red |
|
\override Score.Accidental.color = #red |
|
\override Score.KeySignature.color = #red |
|
\omit Score.KeyCancellation |
|
\override Score.KeyCancellation.color = #red |
|
\override Score.LedgerLineSpanner.color = #red |
|
#} |
|
#{ |
|
%\override Staff.KeyCancellation #'stencil = ##f |
|
\omit Score.KeyCancellation |
|
\hideNotes |
|
\hide Score.KeySignature #})) |
|
|
|
#@return |
|
} \addlyrics { |
|
#(if (equal? mode #\r) |
|
(if solution |
|
#{ \override Score.LyricText.color = #red |
|
\lyricmode { #@lyrics } #} |
|
#{ \override Score.LyricText.Y-offset = -1 |
|
\lyricmode { \repeat unfold #num { "__________________________" \repeat unfold 7 _ } } #}) |
|
#{ \lyricmode { #@lyrics } #}) |
|
} #}))) |
|
(if includeTasks |
|
(add-text |
|
#{ |
|
\task #(assoc-get (cons "scaleTest" mode) taskList) #num |
|
#} ) '()) |
|
(add-score |
|
#{ #result #})) |
|
) |
|
) |
|
) |
|
|
|
%%Chord test suite |
|
chordNoteLookup = |
|
#`( |
|
("Dur" . ,#{<c' e' g'>1#}) |
|
("Moll" . ,#{<c' es' g'>1#}) |
|
("Dur 1.U" . ,#{<e' g' c''>1#}) |
|
("Moll 1.U" . ,#{<es' g' c''>1#}) |
|
("Dur 2.U" . ,#{<g' c'' e''>1#}) |
|
("Moll 2.U" . ,#{<g' c'' es''>1#}) |
|
("verm." . ,#{<c' es' ges'>1#}) |
|
("überm." . ,#{<c' e' gis'>1#}) |
|
("7" . ,#{<c' e' g' b'>1#}) |
|
("m7" . ,#{<c' es' g' b'>1#}) |
|
("Major7" . ,#{<c' e' g' h'>1#}) |
|
) |
|
|
|
#(define chordRoots (list |
|
(ly:make-pitch 0 0 0) ;;;C |
|
(ly:make-pitch 0 3 0) ;;;F |
|
(ly:make-pitch 0 4 0) ;;;G |
|
(ly:make-pitch 0 6 -1/2) ;;;Bb |
|
(ly:make-pitch 0 1 0) ;;;D |
|
(ly:make-pitch 0 2 -1/2) ;;;Es |
|
(ly:make-pitch 0 5 0) ;;;A |
|
(ly:make-pitch 0 5 -1/2) ;;;As |
|
(ly:make-pitch 0 2 0) ;;;E |
|
(ly:make-pitch 0 1 -1/2) ;;;Des |
|
(ly:make-pitch 0 6 0) ;;;H |
|
(ly:make-pitch 0 4 -1/2) ;;;Ges |
|
(ly:make-pitch 0 3 1/2) ;;;Fis |
|
(ly:make-pitch 0 0 1/2) ;;;cis |
|
(ly:make-pitch 0 4 1/2) ;;;gis |
|
)) |
|
|
|
easy-chords = |
|
#(list "Dur" "Moll") |
|
|
|
normal-chords = |
|
#(list "Dur" "Moll" "Dur" "Moll" "verm." "überm.") |
|
|
|
umkehrungen = |
|
#(list "Dur" "Moll" "Dur" "Moll" "Dur 1.U" "Dur 2.U" "Moll 1.U" "Moll 2.U") |
|
|
|
all-chords = |
|
#(list "Dur" "Moll" "Dur" "Moll" "verm." "überm." "7" "m7" "Major7") |
|
|
|
makeChordTest = |
|
#(define-scheme-function (allowDuplicates chords num mode) ( (boolean?) (list? normal-chords) number? char?) |
|
(let loop ((x 0) (return '()) (lyrics '())) |
|
(if (< x num) |
|
(let* ((chord (list-ref chords (random (length chords)))) |
|
(root (list-ref chordRoots (random (length chordRoots)))) |
|
(music #{ |
|
\transpose c' #root |
|
#(ly:music-deep-copy (assoc-get chord chordNoteLookup)) #}) |
|
(solution (list (string-append (getNoteName root) " " chord)))) |
|
(if (and (not (member music return)) (not (has-doubles music))) |
|
(loop |
|
(1+ x) |
|
(append return |
|
(list music)) |
|
(append lyrics solution)) |
|
(loop x return lyrics))) |
|
(let ((result (scorify-music #{ |
|
\time 1/1 |
|
\omit Score.TimeSignature |
|
\set Staff.printKeyCancellation = ##f |
|
\override Score.KeySignature.break-visibility = #end-of-line-invisible |
|
\set Score.explicitKeySignatureVisibility = #end-of-line-invisible |
|
\override Score.LyricText.self-alignment-X = #LEFT |
|
|
|
{ |
|
#(if (equal? mode #\r) |
|
#{ #} |
|
(if solution |
|
#{ \override Score.NoteHead.color = #red |
|
\override Score.Stem.color = #red |
|
\override Score.Accidental.color = #red |
|
\override Score.KeySignature.color = #red |
|
\override Score.KeyCancellation.color = #red |
|
\override Score.LedgerLineSpanner.color = #red |
|
#} |
|
#{ |
|
\hideNotes |
|
\hide Score.KeySignature #})) |
|
|
|
#@return } \addlyrics { |
|
#(if (equal? mode #\r) |
|
(if solution |
|
#{ \override Score.LyricText.color = #red |
|
\lyricmode { #@lyrics } #} |
|
#{ \override Score.LyricText.Y-offset = -1 |
|
\lyricmode { \repeat unfold #num { "________________" } } #}) |
|
#{ \lyricmode { #@lyrics } #}) |
|
} #}))) |
|
(if includeTasks |
|
(add-text |
|
#{ |
|
\task #(assoc-get (cons "chordTest" mode) taskList) #num |
|
#} ) '()) |
|
(add-score |
|
#{ #result #})) |
|
) |
|
) |
|
) |
|
|
|
\paper { |
|
indent = 0\mm |
|
oddFooterMarkup =##f |
|
|
|
evenFooterMarkup = ##f |
|
evenHeaderMarkup = ##f |
|
oddHeaderMarkup =##f |
|
bookTitleMarkup = ##f |
|
scoreTitleMarkup = ##f |
|
ragged-bottom = ##t |
|
#(define fonts |
|
(make-pango-font-tree "Calibri" |
|
"Calibri" |
|
"Calibri" |
|
(/ staff-height pt 20))) |
|
} |
|
|
|
\layout { |
|
ragged-right = ##f |
|
} |