Tonal.js: Functional music theory lib
github.com
github.com
Specifically https://strudel.cc/learn/tonal/
@tonaljs/key gives you some specifically functional info, but the vast bulk of it as useful for non-functional analysis – though it does assume 12-tone equal temperament.
It's "functional" because the chords in the harmony have the function of establishing key centres, moving towards and away from them, establishing transitions to remote key areas etc.
One of the best technical books about functional harmony is "Structural Functions of Harmony" by Arnold Schoenberg[1], which is much shorter than his "Harmonielehre" but really packed with interesting detail about key and chord relationships.
[1] Yes that Schoenberg but this isn't about serialism, it's about trying to explain all the harmony up to and including Mahler. Here is an online pdf of an early edition https://is.muni.cz/el/1421/podzim2007/VH_53/Schoenberg_Struc...
There are a few small areas where the library hiccups, like with bigger chords. I've been able to work around some of those things by reframing the chord as an inversion of N relative to the root of whatever scale I'm in. I haven't bothered to debug why it does that, but my little work around has been sufficient.
On back navigation, that's really bad bug! I'll repro it and fix. Thanks for finding that!
Just a heads up that your example at https://observablehq.com/@ricardomatias/playa doesn't seem to be working at the moment because of browser autoplay restrictions - the console errors that look relevant are:
> An AudioContext was prevented from starting automatically. It must be created or resumed after a user gesture on the page.
> The AudioContext is "suspended". Invoke Tone.start() from a user action to start the audio.
Congratz on Ambiphone, I'm using it right now, it's a nice concept of creating your own ambient mix!
This will be a great example to see how the library has handled the same problem.
https://beaugunderson.com/pedal-steel/
try highlight → scale degree colors or highlight → chord formula and put "1 3 5 7" in the chord formula box... then play with the pedal checkboxes to see how you can play that chord vertically, or more stylistically by using the pedal slides
you can set it to zero, to negative one... possibly to the imaginary constant
because this library does not actually make any sound. it's (to me) an implementation of 12tet, the standard western scale system which includes a bunch of scales and approximates the rest 'well' enough
https://github.com/tonaljs/tonal/blob/main/packages%2Fpitch-...
https://github.com/tonaljs/tonal/blob/main/packages%2Fmidi%2...
The ideal tuning isn't 440hz, it's (440+42i)hz /s
It definitely assumes you're on a 12-tone system so is really only useful within western european music theory. But that is usually what people mean when they say "music theory" anyway.
God i love to see this
[1] https://github.com/tonaljs/tonal/blob/main/packages/chord/in...
Data-structures beyond what the standard lib gives you (string and array) are the main reason the addition of classes to JS was so helpful.
You could have a completely stateless class/object that would manipulate those nodes and add them and remove them from the data structure.
data List a = Nil | Node a (List a)
data Tree a = Leaf a | Node (Tree a) (Tree a)
there is nothing stopping you from writing something like this in JS const list = { kind: 'node', val: 3, next: { kind: 'nil' } };
And then using a switch case to navigate the list/tree matching on the kind field.With the latter approach, the user is not limited to the bahaviors that the library author wrote. The data (not state) can be used freely. Similarly, the functions are not tied to any particular state - the data can come from anywhere, as long as it has the right shape.
The functions are kept pure and the data is kept pure.
As opposed to an object oriented programming style in which data and functions share the same object and create bug ridden state machines thats not as easy to reason about.
Some further explanation about this:
https://www.goodreads.com/quotes/702062-immutable-objects-ar...
a semi-nuanced discussion:
https://www.reddit.com/r/scala/comments/ejwsp1/is_mutability...
you can just Google mutable state to find more info.
separating your data structures and functions in many cases will make your code cleaner and more bug free.
Your first link's first sentence's first two words are "Immutable objects". No problem there. It doesn't conflate objects with mutability.
the point is obvious.
Being that every single language on Earth uses objects for non-primitive data structures that should be inferrable to a reasonable person.
a data structure in that context is clearly an ordered grouping of objects versus an unordered/loose grouping of objects.
I have ideas but I don't think I'm getting them through. Most of the problems functional proselytizers have with objects come from inheritance and mutability. Instance methods from classes don't seem to conflict with any of the functional tenets.
As for mutability, I think it's good sometimes. Dates should have been immutable, but Maps are a good fit for mutation. Immutable maps might make sense too sometimes.
But I find it difficult to communicate about any of this when fundamental terminology is used in novel ways.
like a binary tree for example
I honestly still don't understand what you're getting at.
> a data structure in that context is clearly an ordered grouping of objects versus an unordered/loose grouping of objects.
What's an "ordered grouping"? What does "loose" mean? These are not gotchas. I'm trying my best here.
For me, if I were implementing a data structure, I would probably use objects. In fact, I'd probably use a class. I'm not trying to argue that data structures shouldn't be implemented in terms of objects or anything. My point is just that the tonal.js description is kind of nonsensical. Or at least hard to understand.
I guess maybe low level c and assembly where you implement everything as bits in physical memory?
There's often a stack-/heap-allocated dichotomy. Some languages consider stack-allocated structs not to be objects. They have no reference identity. Assignment has copy semantics. C# is one such language.