TuneScope glitches & some suggestions

Glitches reported in posts #1, #6, #18.

I’m not sure if this can actually be classified as a bug, since I’ve been tweaking a library function (at my own risk) to see what it would do. I’m reporting it anyway, because - who knows? - it may be hinting at a bug at a more fundamental level.

The TRACK block from the Tunescope library
This is the original block:

I thought its code was rather much for what it’s apparently trying to achieve, and (partly for fun, partly to understand what it does) I made a rewrite:

And why not make it even simpler? (these might one day become famous last words :smirk:)

The third version doesn’t play
I tried to play each version, like this example with the original version of the TRACK block:

The original and version (2) play without any problem, but version (3) does nothing.

All of them report the same result (even with case sensitivity on):

Now isn’t that weird?
From a functional (or user) perspective each implementation reports the same result, but when fed to the PLAY TRACK block, the result of version (3) is apparently not up to par.

Unfortunately Tunescope isn’t very communicative about why it will not digest input.

So what is happening here?

My theory
The original TRACK block reports a list that is internally represented by a dynamic array. This is tested with the hidden LINKED? block from the List utilities library. So does version (2), whereas version (3) is diagnosed as a linked list. If original and version (2) are LINKed (another hidden block), they will not play anymore. Conversely, if version (3) is UNLINKed - I made that block myself - it WILL play.

IMAO it shouldn’t matter from a functional perspective what Snap!‘s internal representation of a list is. Apparently Tunescope does something unusual (perhaps underlying custom-made Javascript code will only work for dynamic arrays), or it may be an issue under the hood of Snap! itself.

This links to the code, so you can see for yourself.

I found the issue with processing linked lists even to exist within a chord. If a chord is internally represented as a linked list instead of a dynamic array.

For example: TuneScope sandbox script pic (3)
The result of the above block looks (and, from a functional perspective, is) exactly the same as:
TuneScope sandbox script pic (4)
... but the latter is played, while the first is ignored.

Sounds plausible. The result of your third version is actually partly-linked; it has one pair whose cdr is the original dynamic array as made by APPEND. (The historical Lisp-community name for such lists is "cdr-coded list." I'm not sure (getting old) whether they were invented in MACLISP or in Lisp Machine Lisp.)

@glenbull I believe the problem is in the function convertListToArrayRecursive in libraries/TuneScope/TS_init.js, which assumes that its input is a fully linked list. It should be written to use .../toArray() on the input list and then map itself over the items in the list that are lists.

Thanks for providing a starting point. We'll follow up over the holiday break at the end of the semester. (Thanks)

While you’re going to be at it, here’s some other improvement suggestions for TuneScope (see also here):

  1. Both Snap! and TuneScope offer a untitled script pic 154 block. Couldn’t they be replaced by a single primitive? (with some help from @bh and @jens, I guess)

  2. There’s untitled script pic 157, untitled script pic 158, and untitled script pic 156 (but not PLAY CHORD () FOR DURATION () AND WAIT). Wouldn’t it make more sense to instead define untitled script pic 159, and untitled script pic 160?

  3. Specifying a note with Tunescope sandbox script pic is a bit non-musical (and too much of a technical implementation); Tunescope sandbox script pic 2 is much better, but quite verbose - not helping to make short and readable scripts.
    My suggestion: Tunescope sandbox script pic 3.
    Or even Tunescope sandbox script pic 4, and Tunescope sandbox script pic 5 for chords (see also my 5th point).

  4. Additional scales, like “harmonic major”, [edit] and signatures (2/4 !) (random?).

  5. A new block for a chord with any number of user-specified notes: untitled script pic 162.

  6. A convenient way to specify any duration using Snap!’s tempo system (not seconds). [Edit] I’m not sure whether this is an actual issue. At least something strange happens if tempo < 20 bps. [end Edit]

  7. untitled script pic 161 is simpler than the current code (and it reports 100% the same … even “under the hood” :grin:)

BTW did I mention I already like TuneScope a lot? Thanks for creating it!


  1. Chord inversions, e.g. EGC and GCE as well as CEG.

  2. A more comprehensive note menu, including e.g. C#1 and Bb7.

  3. Durations of eighth triplet and sixteenth triplet notes should be halved (this is an actual error within the code).

  4. This one is a bit more complicated. E.g. in this (relatively simple) classical piece, measures 25, 26 and 29 have notes that continue while another note starts. To correctly specify this in present TuneScope, a separate track is necessary, consisting of mostly R’s. Perhaps some kind of micro-tracks could be invented within a measure or section? (I'm not sure if it can be done; it may cause unwanted complexity)
    An alternative approach to more or less the same effect is to support “sparse” tracks.

  5. Error handling: mainly testing for invalid input, and reporting helpful and precise error messages, such that a user can easily identify and correct the culprit.

  6. A facility to temporarily turn a track OFF.

  7. A facility to play only a few bars of a larger piece.

See this project for prototypes of some of the suggested improvements (suggestions 3, 5, 7, 8, 10, 11 alt.,12, 13, 14).

BTW I asked an experienced Snap! Forum contributor (and self-declared music lover) for a review.

I somehow lost some of my work on improving TuneScope, but reconstructed all of it by now.

A quibble: ♫ represents sequential notes (a melody), not simultaneous notes (a chord). I can't find a chord symbol (it would be three notes arranged vertically on the same stem) in Unicode.

I encountered another TuneScope glitch: my melody is played incorrectly at some tempi.
At tempo = 60, it is played correctly, and the same holds for 30, 120 and 240.
At tempo = 90, quarter notes are played twice in measures 6, 7 and 8 (as with tempo 45, 180).
At some other tempi (e.g. 75, 200), the melody is distorted in a different way.

Systems: iPad-Pro series 2 (2017), Safari 16.6.1 / Chrome; Windows PC (Intel i5 6200, W10 (x64) Enterprise), Chrome

Don’t just take my word on it, listen for yourself: sprite = Tempo issue.

Below is a list of the track:

Wild speculation
As to the cause, could it be a rounding problem?

Agreed. I asked ChatGPT, it didn't "know" of a universal chord symbol either.
How about Tunescope sandbox script pic ?

Yeah that's more nearly correct, and you know and I know what it's supposed to mean. :~P The "vertical ellipsis" ⋮ U+22EE is a closer match, but I'm not sure users will understand even that.

This is a Snap! question (inspired by the as yet unsuccesful search for an existing "chord" icon): is there a way to create a custom icon for use in a custom block's header?

Some of the icons in the title text menu (Block editor, +, title text, arrowhead) aren't in Unicode, so it's probably doable to add an icon, especially in an extension such as TuneScope. But afaik there's no way for a user to use an arbitrary costume as title text. That should maybe go on the When Things Slow Down™ list.

That would be nice.

It's a classic … and I spotted a variation just now:

I think I found a quick fix for the original glitch: use [id] OF when calling the TuneScope "playtracks" primitive, like

Tunescope recovered script pic

Thus all linked list (even lists within lists) wille be transformed to dynamic arrays, AFAIK (@bh, @jens?)

I have no idea. I sort of doubt the depth part though.

This is what I can see:

untitled script pic (6)

untitled script pic (8)

... but it's proof by induction only :frowning:

Huh, okay, that's what I would have tried if I weren't lazy. Thanks.

Meanwhile, I found confirmation from Jens:

RIght, good point, the other options in that block are functions of numbers, i.e., functions of scalars. But ID is kind of a special case because its domain includes non-numeric atoms, so I forgot it doesn't include lists, except by way of hyperblocks.

But that only implicitly applies to the question of changing a linked list to an array, which happens because Jens wants functions of vectors and matrices to be super fast.

@glenbull: I’m reporting another TuneScope glitch … the following measure (#7 right-hand from Chopin’s nocturne no. 2 in C#) should last a full tone, but is apparently calculated by TuneScope to be somewhat shorter; therefore the first note of the next measure (#8) within the same track is played before measure #8 of the parallel (left-hand) track, instead of simultaneously.

I suspect the whole thing is caused by a rounding error related to the Eighth Triplets.

Try it yourself: this project, sprite: Triplets

My suggestion for TuneScope software improvement: multiply all durations by 96, so as to work with integers only.

@qw23 Thanks so much for identifying the issues with TuneScope that you have found and for suggesting potential solutions. We haven't had much time to work on TuneScope during the fall semester, but a couple of the CS students enrolled in the Art & Music course have expressed interest in working with TuneScope in future semesters. If they follow through, we'll ask them to begin with the issues that you identified.

Thanks for your reply, and you’re welcome (I hope my findings contribute to making TuneScope even better). If I find any other issues (or solutions) I’ll let you know through this topic.