[sharing] Explore scala alternative tunings in Max with sslider
Hi all!
I would like to share this small library of abstractions that hopefully make the usage of alternative/microtonal tunings more accessible! It uses the library of 5000+ scala tuning files from the Stichting Huygens-Fokker, and you can also import your own.
download: https://github.com/tmhglnd/th.scala
The package contains 3 abstractions and a custom jsui file:
th.scala - Load a scala scale into a dictionary, refered to by other objects to easily switch scales for multiple scalaToFrequency converters (stof)
th.stof - Convert a number from scala scale-format to the corresponding frequency based on the tune, center and cents value.
th.stof~ - Similar as the th.stof object, except it works in the signal domain.
th.sslider.js - A custom jsui file that shows a kslider-like object to allow for playing with the custom tuning files. The keys are displayed side-by-side (no black keys), and their width denote the relative interval. A light-gray key denotes the octaves.
Works very nicely with the lately released Leimma platform by Khyam Allami and Counterpoint: https://isartum.net/leimma
Feedback/suggestions/bugs are very much welcome, here as a comment or in the github issues page.

Wow. Thanks!
Going to check this out at some point - thanks!
One extra object has been included: th.ftomb (Frequency to Midi & Bend)
This object converts any frequency and outputs an integer MIDI note number together with a pitch bending value between 0 - 127 to allow for controlling external midi devices via [noteout] and [bendout] or [midiformat] and [midiout].

Hi Timo,
great tool but it seems that the new version (8.2 beta) has broken something in the code.
Opening th.scala.maxhelp, the console returns a series of errors related to the js code:
js: error calling function loadScala [th.scala.js]
js: th.scala.js: Javascript TypeError: f is null, line 120
js: error calling function getmenu [th.scala.js]
js: error calling function loadScala [th.scala.js]
js: th.scala.js: Javascript TypeError: f is null, line 120
js: error calling function getmenu [th.scala.js]
Thanks.
mati
Hi! Thanks for letting me know. Have not tried the objects with the 8.2 beta, but will look into this soon and see what is going on.
Hi Mati, I am not getting these errors, so I'm wondering what the problem is. Are you on windows or mac? Did it work in the 8.1 version of Max? Did you put the package in the max searchpath? It looks like it is not able to find the /scl files that are shipped with the package. Can you try to click (getmenu) message and see if you still get the error? Can you try to just load a single .scl file from the /scl folder with the [opendialog]? Let me know :)
Hi Timo, thanks for the quick reaction!
I'm on Mac and it's weird… With version 8.1 it works flawlessly and yes, the package is in a recognized directory.
Using 'getmenu' or loading a single file returns the same error.
A short video explains the behaviour.
Thanks for the video. I will have to investigate a bit deeper, but it seems that maybe the reading/loading of files via JS has changed in some way. Do you get any errors if you try from the menubar Help>Examples>javascript>file both `filetester` and the `folderiter` patches?
No errors if I load the files you indicated.
Just to be sure, also no errors if you click those message boxes with (readfile) (c74:/init) etc?
Exactly. No errors.
Thanks!
Hey, I could replicate the bug after I downloaded the latest 8.2 beta from the forum (I had one version before I think). It seemed to have something to do with the .readbytes() method that I used in the js. I changed it to a different approach and now the bug should be fixed, please clone the latest commit from the github and give it a try: https://github.com/tmhglnd/th.scala
Hi Timo,
It runs again with the latest build.
Thanks for the quick reaction.
Great! Good to hear.
Hi,
I've run into another problem.
When randomly selecting files, Max would sometimes crash (the very last beta). At least I found a file that crashes every time: bell_mt_partials.scl
Are you experiencing it, too?
I'm not so JS savvy to unearth the eventual problem....
I baste a rough patch to load in dict a .scl file without js.
I get this crash as well, but I also get this crash when trying to open it with the js file example, so not sure why this is. I'll investigate. Great that you've got a patch version that works in the meantime.
Just stumbled onto this and would like to express my thanks - very helpful, thank you Timo!
It’s brilliant.
timo, pls could you explain this?

why not the full range?
was the idea that a pb range of 2 semitones is more likely default than a range of 1 in synthesizers´ presets?
i am about to make a decision if i should eventually use 0 as center and then only pitch up or use a center in my version. (to avoid having two different halves around the center.)
@Dan/@Yaniki, thanks! If you have any feedback on the user experience let me know!
@Roman: Yes, the idea was that because -2/+2 semitones pb range is custom for most midi devices the user does not really have to change anything in the receiving devices settings. On the other hand of course the full range would give more precision. I could also include an MSB/LSB output option, making the range more precise. But since [midiformat] also has an @hires 1 option, allowing floating-point input, I thought using that option is more than enough for this object.
i came up with that question because if you only use half the range you could as well only use the positive or negative part.
it is interesting that i have never thought about the range contained in most presets (i had a lot of hardware back in the days)
but i just figured that your stuff are not externals but abstractions so maybe i will just look inside. :P
my (very old) approach looks like that (but there is an error in the mapping, i assumed 128 beeing the highest number which makes the whole range splitting procedure pointless^^) - and it is also 7 bit only (for the same reason: i have never investigated how common 14 bit actually is among hardware)
- mtof
- div/rest
- round integer (also missing here? not good. what did i do.)
- split rest into 0-64 and 64-127
- map these two parts from linear to the "center 64 problem"
- round PB to int
but maybe it would be more perfect to provide different modes from 1 to 12 semitones? hmm...

I personally also don't know how common 14-bit is amongst hardware. I made this object more for others (i think it was even a request) then that I actually use it myself.
You can definitely look at my code, it is al done with codebox in gen.
This is amazing - thank you so much Timo
edit - (and yes it did take me that long to check it out - looking at my post above ; )