Tangling Org Mode Properties Into Source Code Blocks
A problem I've been trying to solve on and off for a number of years is: I'd like to be able to consistently generate multiple artifacts (PDF, web graphics, MIDI) from a single Lilypond arrangement and collect multiple arrangements into a single document (using lilypond-book, for example.)
Lilypond supports this up to a point. You can assign chunks of notation to variables and then define multiple \score
blocks that re-use them, but I always find myself having to refresh my memory for things like unfolding repeats for MIDI output or transposing an entire score. Things get verbose and repetitive, and not unlike old-school static HTML web sites where tweaking the appearance of something means editing every single page because they all have quirks and inconsistencies.
Enter Org mode, a Swiss-army knife authoring environment/document format that can do all kinds of things. One of its most interesting features is the ability to evaluate/interpolate/export blocks of source code within an Org mode document. Using noweb reference syntax you can insert blocks of code into other blocks of code... in my case I am hoping I can come up with an Org mode template/workflow that will let me focus on just the actual content of arrangements, and use org-babel-tangle to generate lilypond files for different targets (PDF/svg/transposition/MIDI/lytex).
The first problem I needed to solve was being able to reuse properties across source code blocks, and I got it working:
# -*- mode: org; org-confirm-babel-evaluate: nil; -*-
# -*- mode: org; org-use-property-inheritance: t; -*-
:PROPERTIES:
:TITLE: The Quick Brown Fox
:COMPOSER: Arthur \"Two-Sheds"\ Jackson
:COPYRIGHT: 1969
:END:
* Lilypond
#+begin_src lilypond :tangle quick-brown-fox.ly :noweb yes :padline no
version "2.24"
\header {
title = "<<get("TITLE")>>"
composer = "<<get("COMPOSER")>>"
copyright = "<<get("COPYRIGHT")>>"
}
\score relative c' {
c d e f
}
\layout()
#+end_src
* Markdown
#+begin_src markdown :tangle quick-brown-fox.md :noweb yes :padline no
# <<get("TITLE")>>
## By <<get("COMPOSER")>>, <<get("COPYRIGHT")>>
Lorem ipsum dolor sit amet
#+end_src
# Helper function that can be used to insert org-mode properties into source blocks:
#+NAME: get
#+begin_src elisp :var prop="title" :results value :exports none
(prin1 (org-entry-get (point) prop 'selective))
#+end_src
Running org-babel-tangle
on this file generates two new files:
quick-brown-fox.ly
version "2.24"
\header {
title = "The Quick Brown Fox"
composer = "Arthur \"Two-Sheds"\ Jackson"
copyright = "1969"
}
\score relative c' {
c d e f
}
\layout()
and
quick-brown-fox.md
# The Quick Brown Fox
## By Arthur \"Two-Sheds"\ Jackson, 1969
Lorem ipsum dolor sit amet
This is a minimal and not super-useful example but it has promise.
Wed May 14 2025 20:00:00 GMT-0400 (Eastern Daylight Time)