Tuning, Scala, Aleph waves module

Haven’t done this for the Aleph. My work was for the TXo’s unique lookup table format. Sorry.

In my experience, the SCALA files are pretty easy to deal with and well-documented.

My question is about Scala for teletype / telex…

I just want to be able to experiment with a bunch of them, and am not sure how to go about it.

Oops - sorry about that. My brain has been a bit scrambled the last few days.

It isn’t super complicated - but if you want to add custom scales to the firmware, you need to change the module’s code.

I have an ugly little utility that generates the proper code here:

  1. Put some Scala scales in a subdirectory (I used “scl/” and found them at the Scala site: http://www.huygens-fokker.org/docs/scales.zip).
  2. Reference the scales that you want in the order that you want in a text file; see “items.txt” for an example.
  3. Run the “table_builder.py” script and reference your input file. For example: python table_builder.py -i items.txt
  4. The script will output a “scales.cpp” file in your current directory.
  5. Cut and paste the two parts of the output into the corresponding areas of the “Quantizer.cpp” and the “Quantizer.h” files in your Arduino project directory for the TELEX.
  6. Deploy your updated code to your TELEX’s teensy.

Does that help (and answer your question)? :slight_smile:


let me clarify the crazy purist argument a little, just for fun…

yeah, sorry - i was pretty tired last night - the endpoint of the crazy purist thinking is that the ‘tune’ parameter can give you the additional microtonal control that the hz param scaler doesn’t.

without hz param interpolation, if you leave the tuning parameter fixed, then adding N to any hz parameter value will always give you “exactly” the same change in pitch - e.g. one semitone if N=8.

if you add linear interpolation to the hz table entries, this doesn’t hold true anymore - each interpolated step represents neither a fixed change in pitch, nor a fixed change in linear frequency, but rather a fixed ratio beteween two adjacent 1/8-semitone table entries.

so, given some number N, where (N%32) != 0, adding N to the hz param will change the pitch / linear frequency by a different amount, depending on where in between table entries you started. this hurts my brain! (my old teacher james tenney would have called me on the carpet for designing such a system!)

i guess it doesn’t really matter - you can always just ensure the hz parameter is a multiple of 32. but that’s the crazy logic. and you’re probably right that the difference is generally insignificant. it just felt like a complicated caveat to add, easier to forgo interpolation, ensuring that any two hz param values are always “in tune” (that is, known values specified in the table), and allow more arbitrary linear control with ‘tune’

in any case - by all means, certainly add interpolation on the hz table. (but be prepared to Justify it to the Ghost of Jim)

1 Like

Yes, thank you!
We are getting closer.

I have more questions, but:

I wonder if this should not be made into it’s own thread, like “loading Scala scales into Telex” or some such thing. I am feeling like we are drifting off topic in the mainly Aleph centered conversation.

Agree the errors are hard to reason about! So I decided to model the problem instead of fretting about it…

Here’s the lisp code that lead me to conclude in my last post & PR the linear interpolation errors are nearly two orders of magnitude too small to matter:

(defun ratio-to-semi (ratio)
  (* (log ratio 2) 12))

(defun semi-to-ratio (semitones)
  (expt 2 (/ semitones 12)))

(defun collect-ratios ()
  (loop for i below 32
     collect (list (semi-to-ratio (/ i 256))
		           (+ 1.0
		              (* (/ i 32)
			             (- (semi-to-ratio 1/8) 1.0))))))

(defun collect-semitone-errors ()
  (mapcar (lambda (el)
	        (- (ratio-to-semi (cadr el))
	           (ratio-to-semi (car el))))

(defun compute-max-semitone-error ()
  (reduce #'max (collect-semitone-errors)))

My definition of ‘too small to matter’ is anything less than 1/100 semitone. (ratio = 1.0005778). The max. error due to this linear interpolation (occuring halfway between two 1/8 semitone points) is 1.13122165e-4 semitones.

I was reading this http://www.kylegann.com/JIreasons.html, and it opened my eyes to the music-theoretic possibility there may be some interesting melodic constructs derived from (non-semitone) equal temperaments. So, once the gaps between 1/8 semitones are filled in, we can again use LINLIN to generate any equal temperament scale. The final result is (imo) a really beautiful system for juggling pitches. I guess one could even realise something like the ‘justonic’ sounds of this kranky old video ( https://www.youtube.com/watch?v=6NlI4No3s0M ) by combining Hz & tune.

aleph needs a simple chordal module - it’d be wicked to fork acid & replace one monosynth with a very simple poly synth, maybe replace half the dsyn-ish drum voices with some other computationally cheap digital percussion sounds. Microtonal groovebox!

As a silly aside, assuming the spacing between semitones on an unfretted string instrument is around 1cm, a human player would need finger accuracy of order 1 micron in order to beat the accuracy realised in latest PR. Also 1V/oct modular system would require better than than 10uV DC offset to match the pitch stability.

Hopefully no flaws in the above logic (or in the PR based on same line of reasoning). This feature would be even better PR if the ‘inbetween’ Hz values would display correctly on the BEES INS screen. Currently there’s no visual feedback to indicate the progression between 1/8 semitone increments, which kinda sucks now the log scale is not snapping to displayed values.


rawsc is supposed to be a simple block-processed polysynth … time time time

yeah i seem to remember KG using 22tet? ([ed] oop, no, erlich and others though…)

anyway of course i’m totally fine with the lin interp error

1 Like

Seems that rawsc is compiling no probs. Too late to actually fire up the aleph right now - do you reckon existing modules would get appreciable performance kick by simply porting toplevel module_process_frame to module_process_block? Obv porting all the frame-by-frame DSP object methods seems a little daunting, but I guess it could be done piecemeal, working downwards from toplevel DSP objects.

Assuming rawsc seems to basically work, I might port acid over to block processing & try to squeeze in a very simple polysynth to cpu budget… Suddenly got curious about block processing - time to find out what all the fuss is about!

reckon existing modules would get appreciable performance kick by simply porting toplevel module_process_frame to module_process_block

yeah, pretty sure there would be some gains there, simply from doing more work in each interrupt (and gcc can inline per-sample functions, perform commoning, &c)

one point of concern i have is that my recent attempts to use DMA for CV output driver apparently smashed memory. there’s a chance that my application of DMA for block processing is similarly borked (though it has had other, smarter eyes on it)

sorry, again i’m travelling and this time without aleph (though can get to one if needed)

Dang, I got distracted with hardware over the holidays and didn’t touch my Aleph for this subject. I’ll have some more time in January.

On the upside, I disassembled a digital piano and learned to weld acrylic together. That was fun!

1 Like