Music Practice Journal - With Existing Plugins?

What I’m trying to do

Hi there! I’m a musician (amateur) who is trying get more organized and intentional about practicing.

I’ve been using Obsidian for the past year or so in a very dumb way: A single page for music practice notes, another for lesson notes, a bunch of misc pages organized by folders, no links.

It’s nice to have at least a record, but it’s not doing all that I want: I need something more dynamic that’s built around the pieces that are being worked on rather than just a dumb log I have to sift through.

In my dream-scenario, I’d open up my daily note, and start an outline. Each item in the outline would link back to something I worked on, a song or ideally, a section of a song.

Each song is its own note. On each song note I’d be able to say when the last time I worked on it. There’d be a list with items (or headings?) for each part of the song: “Melody, Part A”, “Rhythm Part A”, “Melody Part B” etc…and when those sections were worked on. Maybe it would be able to pull some metadata from the practice log as well, so it could show something like “Last Played at 120bpm on 1/1/26. Status: Solid”

I’d also like a home page dashboard, where it shows what’s currently being worked on and their statuses.

Things I have tried

My first thought was that I’d create a note per song, and add headings for each individual thing I’d want to work on for that song (eg. Song parts, melody, comping). Then I’d link to those in the notes, and use a dataview to grab the the backlinks to the section.

The (first) problem as you probably already figured out is that in dataview you cannot ask for the backlinks of a heading. This is the big problem.

The more I dug into it, I realized more problems: even if I got rid of the idea of song sections, if there are multiple things I practiced in a given session, I’m not sure how to extract the metadata for just a given outline item that has the link.

So my questions are:

  • Is dataview or any plugin (or set of plugins) up to the task I’m trying to do? Or does this need to be a custom plugin? Does it make it more tractable if I give up the idea of linkable song sections?
  • Is there a better way to organize these notes that would make this easier?

Things I really don’t want to do are:

  • have a note per song section
  • have multiple notes per practice section.

I don’t mind programming, I do it professionally, but I’d like to leverage what’s out there as much as possible.

Thanks

Bobby

A couple of ideas. Here’s a dataview LIST query that displays the date of the most recent daily note to link to a Song Part (Obsidian 1.12.7, Dataview 0.5.68):

LIST date
FROM [[Song]]
WHERE length(filter(file.outlinks, (x) => meta(x).subpath = "Part")) > 0
SORT date DESC
LIMIT 1

It has to be a list, and it can only render properties of the entire daily note. The advantage is that it only needs the daily note to link to the song part to appear in the list.

To render the full “Last Played at 120bpm on 1/1/26. Status: Solid” in the Song-Part text, I would expect you’d need rich structured metadata, as YAML source on the daily note. To render the result cleanly, it’d need to be a dataviewjs, but you could capture it in a plugin that just provides the rendering function.

Here’s a working example of that. In the daily note YAML source metadata:

---
date: 2026-05-31
practiced:
  - song: "Song"
    part: "Part One"
    bpm: 120
    status: solid
  - song: "Song"
    part: "Part Two"
    bpm: 80
    status: weak
---

Function (which could be provided by a plugin) and its use (on the Song page):

function mostRecentPracticed(song, part) {
	let practiceFilter = p => (p.song == song && p.part == part);
	let mostRecentPage = dv.pages()
		.where(d => d.practiced && d.practiced.some(practiceFilter))
		.sort(d => d.date, "desc")
		.first();
	let practiceRecord = mostRecentPage?.practiced.filter(practiceFilter).first();
	if (!practiceRecord) {
		return "Not yet practiced";
	}
	return "Last played at " + practiceRecord.bpm + " bpm on " + new Date(mostRecentPage.date).toLocaleDateString() + ". Status: " + practiceRecord.status;
}

dv.paragraph(mostRecentPracticed("Song", "Part One"));

I’m still learning Dataview so I welcome refinements and other suggestions.

Ah, thanks Dan! That first query is especially helpful. As for the properties (bpm, status etc.) I played around with doing them as inline fields eg. “I played it at [bpm:: 120]”and then extracting via some tedious DataviewJS. But maybe I can rework your query to extract the fields as well.