Non-12-TET Tunings

Has anybody dove into octave divisions outside of 12-TET with the ER-101?

I’ve got a python script that will that will do X ET, so you can set how many divisions the octave is split into. I’ve been meaning to post it but I got distracted by the arrival of my 301, I can put it up tonight.


I reckon 7ET should be pretty interesting

1 Like

Would this python script allow the user to define the root note too?

I’ve been wanting to create a python scripting to create pretty much any scale starting at a define toot note for a while so any working examples would be great!

No it doesn’t do that it is a modified version of Brian’s equal temp one. It just changes the divisor. So you had 32 tone equal temperament if u liked.

Do you want to change Brian’s one for creating the various 12tet based scales to allow you to set the root to a note other than C? You might be able to achieve that by adding an offset in the right place of the python code but I’d need to have another look.

Thinking about it should be possible to build any sequence of notes/pitches using a collection. I might look into this but I am quite new to python

Yeah, that’s exactly what I want to do!
I’m not a coder but I could probably hack some existing code if it has really good/clear commenting that assumes no previous coding.

I’ll have a look and see if I can work something out then. :slight_smile:

I gather the basic advantage/purpose for having a programmable/adjustable fundamental frequency as set by the 101 would allow you to tune your VCO to say A=27.5Hz (lowest A on the piano) and be able to send accurate pitch cv in any scale beginning on any root note in any (piano range) octave?

I do not have a 101/102 (yet!) but the possibility of using other tuning systems accurately within a patch is pretty alluring.

Ok here is the X-TET file in a zip.

It contains the python code and a few examples of what it produces.

To run on a mac:

  1. Copy the file to somewhere on your machine, I have it in my user folder and a sub folder called Code
  2. Open terminal and cd to that folder
  3. type python
  4. press return

It should create two new files in that folder, one with .BIN and .TXT file for reference.

To run different temperament tables, just change the Div value in the .py file and run it again.

# specify divisor, must be a float
div = 27.0

The above would generate 27 TET (4.6 KB)

1 Like

Ok here you go: (1.6 KB)

This is a little edit of Brian’s one, there is a line in here that you can edit that sets the offset of the first note and then effectively the whole scale.

Really it needs to edit the name of the scale too, so you could see C Pent separate to Eb Pent but haven’t quite worked how i could name them given the limitations on the file name length.

This is the bit that drives it:

# offset in tones
offset = 4

When you run it should print out the offset in 16bit values and the note, so 1 becomes Db.

1 Like

As a disclaimer, I haven’t tested these in my ER101 / 102 yet but it all looks about right to me, will be testing this weekend.


1 Like

Many many thanks!

I’ll report back once I’ve got it running and checked on my ER101/102.


1 Like

BTW for anyone wondering, I just tried some scales from and they do indeed work as expected.

There are some cool python codes on the 102 card that I need to get a better look at.


Awesome - would love to hear something! Also - though I do not own the 101/102 yet, I assume it’s possible to program voltages for just intonation?

Yeah I think that should be easy enough, apply some ratios, round them to the 16 bit integers the table uses and load em in.

1 Like

I see after rtfm that there are multiple reference/voltage tables. Very excited to get my hands on the 101/102, especially knowing custom octave divisions are possible.

1 Like

So finally got the 12-TET python script updated so that you can create different root note versions of the same scale. (3.6 KB)

All you have to do is change the ‘shift’ parameter to the root you want - the difference between this script and the earlier version above is that the the shift wraps round so you don’t need to retune your oscillator to the new root note. Just tune 0V to C0 (or any C you like) and you can then load different root note scales.

The name of the tables is limited to 4 characters so I decided to use the first two to describe the scale and the last two to define the root note.

If people want I can run this script for all the scales in the original python script for all root notes sometime over the next week and zip and load to here?


i can’t figure out how to use this script, i think i’m just too dumb for python. i can run it and it produces the scales, however i would like to have a peak inside and look if i could input my own scales to have them converted into the er101 format, is that possible? if so, can somebody explain it in simple terms?

You can open the file ending .py in any text edit to view the code.

This is probably not advertised well enough but there is another python script (linked from the ER-102 page) which can convert voltage tables in CSV file format into the ER-102’s binary format.

The script is listed here:

Also here is a direct link:

And the contents:

import ctypes
import csv
import sys
import getopt

def printHelp():
  print "This script converts a CSV file containing 2 columns (index and voltage) to the ER-102 voltage table format. Indices should extend from 0 to 99 and voltages should extend from 0 to 8.192.  The output file name should follow the format XXXX-P.BIN for tables that should be displayed as pitches by default, otherwise use XXXX.BIN."
  print 'python -i <inputfile> -o <outputfile>'
  print "EXAMPLE:"
  print "python -i test.csv -o TEST-P.BIN"

def main(argv):
  inputfile = None
  outputfile = None
    opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="])
  except getopt.GetoptError:
    print ' -i <inputfile> -o <outputfile>'
  for opt, arg in opts:
    if opt == '-h':
    elif opt in ("-i", "--ifile"):
      inputfile = arg
    elif opt in ("-o", "--ofile"):
      outputfile = arg

  if inputfile==None or outputfile==None:
    print "Error: no input or output file specified."
  # default voltage table
  voltages = [0]*100

  # parse the CSV file
  print "Reading:", inputfile
  count = 0
  with open(inputfile) as inputstream:
    reader = csv.DictReader(inputstream)
    for row in reader:
      # change field names to lower case
      row =  {k.lower(): v for k, v in row.items()}
      i = int(row["index"])
      v = float(row["voltage"])
      if i >= 0 and i < 100:
        count = count + 1
        voltages[i] = v
  print "Parsed",count,"entries."

  # output the voltage table as a flat binary array of unsigned shorts
  codes = [int(round(x*8000)) for x in voltages]
  # do not exceed the max for unsigned shorts
  codes = [x if x<(1<<16)-1 else (1<<16)-1 for x in codes]
  # convert the python list to a binary array
  table = (ctypes.c_uint16 * len(codes))(*codes)

  print "Writing:", outputfile
  with open(outputfile,"wb") as outputstream:

if __name__ == "__main__":