Discussion:
Helper macros for music analysis
Jérôme Plût
2018-11-01 13:43:34 UTC
Permalink
I wrote some macros to help write analysis of musical pieces.
Here is an example file (on Bach's Invention I).

Structural analysis is (of course) performed by hand, and displayed on
a Lyrics structure on top of the music. (This part is only a set of
very simple macros).

Harmonic analysis is performed mostly by hand (I also have some code
that does harmonic analysis, but it works mostly on chorales; the code
here only detects octave-drop cadences) and displayed on a Lyrics
structure below the music.

The code also does a bit of motif analysis, which is done
automatically (motives are declared once by hand, then later
occurrences and inversions are identified automatically).

The enclosed files:
motif.scm contains most of the parentheses
bwv772.ly is the example for Invention I

TThe code compiles with both v2.18 (Debian stable; this is the only
version I have access to on some of my systems) and v2.19.

I am interested in any feedback you would have on this code!
--
Jérôme
Thomas Morley
2018-11-01 15:21:03 UTC
Permalink
Post by Jérôme Plût
I wrote some macros to help write analysis of musical pieces.
Here is an example file (on Bach's Invention I).
Structural analysis is (of course) performed by hand, and displayed on
a Lyrics structure on top of the music. (This part is only a set of
very simple macros).
Harmonic analysis is performed mostly by hand (I also have some code
that does harmonic analysis, but it works mostly on chorales; the code
here only detects octave-drop cadences) and displayed on a Lyrics
structure below the music.
The code also does a bit of motif analysis, which is done
automatically (motives are declared once by hand, then later
occurrences and inversions are identified automatically).
motif.scm contains most of the parentheses
bwv772.ly is the example for Invention I
TThe code compiles with both v2.18 (Debian stable; this is the only
version I have access to on some of my systems) and v2.19.
I am interested in any feedback you would have on this code!
--
Jérôme
Hi Jérôme,

I've only started looking at it...

Very nice!
Some observations, though:

Right from looking at the output of bwv772.ly it bugged me that "Ainv"
(with it's arrow-head) is not in the same way aligned to the
NoteColumn like the simple "A".
So I changed 'mark-motif-leaf ' to:
(define (mark-motif-leaf leaf name first trans) (let* (
(p (ly:music-property leaf 'pitch))
(color (color-variant (get-motif-color name) trans))
(grobs '(NoteHead Stem Dots Flag Script Accidental))
)
(if first
(ly:music-set-property! leaf 'articulations
(cons (make-music 'TextScriptEvent
'direction 1
'tweaks
(list (cons (quote parent-alignment-X) 0)
(cons (quote self-alignment-X) 0))

'text (motif-markup name))
(ly:music-property leaf 'articulations))))
(make-sequential-music (append
(map (lambda (g) (prop-override `(Staff ,g color) color)) grobs)
(list leaf)
(map (lambda (g) (prop-revert `(Staff ,g color))) grobs)))
))

Iirc, 'parent-alignment-X is a 2.19.-feature, though.

I then intended to do similar with 'structural-corner'. But I failed.
Part of the problem is you use 'structure as a music-property without
declaring it. As a consequence using the option -dcheck-internal-types
makes the compilation fail. Even not using this option, \tweaks etc
can't be apllied in a reasonable way. One could change the basic
markup, ofcourse, but I'd recommend to better cope with the
'structure-music-property.

Furthermore, compiling your code with my guilev2-setup fails right
from the beginning with:
error: GUILE signaled an error for the expression beginning here
#
(load "motif.scm")
Unable to find file "./motif.scm" in load path

Maybe creating a module is more promising than using 'load', but now
I'm guessing ...

Didn't investigate further, though.


So far, many thanks for sharing your code,
Harm
Jérôme Plût
2018-11-01 18:37:53 UTC
Permalink
Post by Thomas Morley
Part of the problem is you use 'structure as a music-property without
declaring it. As a consequence using the option -dcheck-internal-types
makes the compilation fail.
This is why, in a previous iteration of this code, I used an invisible
articulation to hold the metadata (cf. my previous message on this
list; by the way, let me apologize for the triple posting, I was under
the impression that the sending had failed).

I just had a look at define-music-properties.scm -- I had not realized
that it was even possible to *declare* a music property. Adding these
lines makes my code compile even with -dcheck-internal-types:

(music-property-description 'structure markup? "structural markup")
(music-property-description 'harmony markup? "harmony markup")
(music-property-description 'motif-define markup? "motif name")

There are still a few warnings because of an invalid 'origin property,
but these would take quite a bit longer to fix (the correct location
object would need to be passed along a *long* chain of procedure
calls).

By the way, I have one more question: Given (on the Scheme side) a
list L of markup objects, I can build a column with
(make-column-markup L), but this column is left-aligned. How could I
make it right-aligned?
Thomas Morley
2018-11-01 21:50:37 UTC
Permalink
Post by Jérôme Plût
Post by Thomas Morley
Part of the problem is you use 'structure as a music-property without
declaring it. As a consequence using the option -dcheck-internal-types
makes the compilation fail.
This is why, in a previous iteration of this code, I used an invisible
articulation to hold the metadata (cf. my previous message on this
list; ...].
I had seen your request.
And tried several codings, to no avail until gave up.
In the light of your mail I retried with success. :)
I posted the code to this thread:
http://lilypond.1069038.n5.nabble.com/Three-questions-about-Scheme-functions-td216957.html
Post by Jérôme Plût
I just had a look at define-music-properties.scm -- I had not realized
that it was even possible to *declare* a music property. Adding these
(music-property-description 'structure markup? "structural markup")
(music-property-description 'harmony markup? "harmony markup")
(music-property-description 'motif-define markup? "motif name")
Not sure this will be sufficient, but this is only my gut feeling, I
haven't looked in the source again.
Post by Jérôme Plût
There are still a few warnings because of an invalid 'origin property,
but these would take quite a bit longer to fix (the correct location
object would need to be passed along a *long* chain of procedure
calls).
By the way, I have one more question: Given (on the Scheme side) a
list L of markup objects, I can build a column with
(make-column-markup L), but this column is left-aligned. How could I
make it right-aligned?
(make-right-column-markup '("one" "two" "three"))

Best,
Harm
Thomas Morley
2018-11-03 15:16:34 UTC
Permalink
Am Do., 1. Nov. 2018 um 16:21 Uhr schrieb Thomas Morley
Post by Thomas Morley
Furthermore, compiling your code with my guilev2-setup fails right
error: GUILE signaled an error for the expression beginning here
#
(load "motif.scm")
Unable to find file "./motif.scm" in load path
I tried to hunt this down...
Although, I still don't know why #(load "file.scm") done in a ly-file
stopped working, I've found #(primitive-load "file.scm) working for
guilv1 and guilev2.

While working on it I've found a little syntax-mistake in
'music-insert-before!' of your motif.scm
It should be
(fold (lambda (m b) (or b (music-insert-before! pos m items))) ...)
and not
(fold (lambda (m b) (b or (music-insert-before! pos m items))) ...)

No clue why guilev1 didn't warn.
Though, the guilev2 message is not that helpful either:
error: GUILE signaled an error for the expression beginning here
#
(primitive-load "motif.scm")
source expression failed to match any pattern

Meaning: "there's a problem in this multiple
hundred-lines-of-code-file, Good Luck."

Yeah...

Cheers,
Harm
Thomas Morley
2018-11-03 21:17:18 UTC
Permalink
Am Sa., 3. Nov. 2018 um 16:16 Uhr schrieb Thomas Morley
Post by Thomas Morley
Am Do., 1. Nov. 2018 um 16:21 Uhr schrieb Thomas Morley
Post by Thomas Morley
Furthermore, compiling your code with my guilev2-setup fails right
error: GUILE signaled an error for the expression beginning here
#
(load "motif.scm")
Unable to find file "./motif.scm" in load path
I tried to hunt this down...
Although, I still don't know why #(load "file.scm") done in a ly-file
stopped working, [...]
Still no clue, though, in ly-files (load ...) works only with an absolute path.
In native guilev2, it works with a relative path as well.

Any hints to boil this down even further?

Cheers,
Harm
Jérôme Plût
2018-11-07 18:25:22 UTC
Permalink
Post by Thomas Morley
Post by Thomas Morley
I tried to hunt this down...
Although, I still don't know why #(load "file.scm") done in a ly-file
stopped working, [...]
Still no clue, though, in ly-files (load ...) works only with an absolute path.
In native guilev2, it works with a relative path as well.
Any hints to boil this down even further?
I am really not that familiar with the Guile module management system.
My best guess is that it has to do with this:
https://www.gnu.org/software/guile/manual/html_node/Load-Paths.html

Also, scm/lily.scm contains some allusions to a difference of
behaviour between guile v1 and v2:

(define-public (ly:load x)
(let* ((file-name (%search-load-path x)))
(ly:debug "[~A" file-name)
(if (not file-name)
(ly:error (_ "cannot find: ~A") x))
(primitive-load-path file-name) ;; to support Guile V2 autocompile
;; TODO: Any chance to use ly:debug here? Need to extend it to prevent
;; a newline in this case
(if (ly:get-option 'verbose)
(ly:progress "]\n"))))

Loading...