Microtonal tuning tables in AudioKit

202 views
Skip to first unread message

Marcus Hobbs

unread,
Feb 28, 2017, 5:15:03 AM2/28/17
to AudioKit Users Group
Hi guys,

On 2/11 Matthew Fecher tweeted that support for microtonal tuning tables would be coming in the AudioKit Synth and AK keyboard component.

I am very interested in the topic of extending AudioKit for microtonal tuning tables.  What is the best forum for participating/contributing?  I am a long-time professional iOS developer, and an expert microtonalist. Would love to help in any way I can...be it giving feedback, beta testing, or contributing code.

For example, I extended AKMorphingOscillatorBank.* with the following method (all they way down through AKMorphingOscillatorBankDSPKernal.hpp):

    open func play(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, frequency:Float) {

        self.internalAU!.startNote(noteNumber, velocity: velocity, frequency:frequency)

    }


And it sounds awesome.  I'm not proposing this as a design...it was an expedient way to integrate AK into my microtonal application without throwing around tuning tables.  I'm hesitant to invest more into this until I get a better understanding of the team's efforts.

Thanks for any info, and keep up the great work.  The SDK is a real joy to work with.

Marcus

Aurelius Prochazka Ph.D.

unread,
Feb 28, 2017, 5:29:56 AM2/28/17
to AudioKit Users Group
Hi Marcus,

Yep, that's Matthew Fecher's way of making sure something stays on my radar!  Anyway, I've added you to our AudioKit Slack group so we can have real time conversations whenever you need.  

Aure

Allan Hoeltje

unread,
Mar 13, 2017, 9:03:16 PM3/13/17
to AudioKit Users Group
I am also interested in implementing microtonal tunings with AK and very happy that someone else is too.

Before finding AudioKit I was experimenting with iOS apps and micro tunings using the PureData library.  PDLib represents a midi note number as a float so if you wanted a standard equal tempered C3 you played note 60.  Since there are 100 cents between each tempered interval it is fairly easy to detune a note to within one cent.

AK has defined MIDINoteNumber as UInt8 and it is used as an index into the noteStates array in the various AKxxOscillatorBankDSPKernel objects and the respective noteOn() methods calculate the frequency by a call to noteToHz().  From there on down it looks like audio unit magic, smoke and mirrors to me - precisely the reason why I am using AK instead of AU!  (Thank you, Aure!)

So, how can you detune a note in AK without redefining MIDINoteNumber as a float?

I don’t claim to be a microtonal tuning expert by any means but it seems to me that the OscilatorBank objects could be modified to be instantiated with a simple tuning table and a generator root tone. Standard midi is equal temperament with A=440 Hz.  What if you want a Ptolemy just intonation in the key of A=432 Hz?

I think the Scala tuning table specification is a good place to start. (see http://huygens-fokker.org/scala/)

For example, the Ptolemy 7 note scale is:

 7
 9/8
 5/4
 4/3
 3/2
 5/3
 15/8
 2/1

The 12 note equal tempered scale is 
 12
 100.0
 200.0
 300.0
 400.0
 500.0
 600.0
 700.0
 800.0
 900.0
 1000.0
 1100.0
 2/1

Marcus, your sample play() code is passing a frequency parameter to the AKxxOscillatorBankDSPKernel startNote method.  Is this an absolute frequency or a detune adjustment to be applied in noteOn() to the equal tempered frequency of the MIDINoteNumber?

-Allan

Marcus Hobbs

unread,
Mar 13, 2017, 11:04:46 PM3/13/17
to AudioKit Users Group
Hi Allan,

I had in mind a 128-tone absolute frequency tuning table and an opt-in protocol for using it, and yes it's possible that there's a small amount of implementation to be done in the root classes but it would break no existing code.  I would provide Scala support at a minimum and I intend to add many more tunings.

.

Allan Hoeltje

unread,
Apr 25, 2017, 1:46:16 PM4/25/17
to AudioKit Users Group
Hi Marcus,

I've been off the grid the last month working on house projects but now back to the computer and microtonal tunings in AudioKit.  I think we are on the same path here with a 128 tone table which maps the standard midi notes 0...127 to absolute frequencies.  My thought was to create an "AKTuningTable" subclassing MutableCollection and have the AKxxxOscillatorBank classes wrap an instance of the table.  The table would default to the standard midi map with note 69 as A6 at 440Hz.  The table will present an update method that takes text representing a Scala scale specification, a root generator note and a root frequency.  The AKxxxOscillatorBank "playNote" method subscripts the note number into the table for the frequency and passes it down to the AKxxxBankDSPKernel replacing the noteToHz calculation.

I am just about there.  How about you?

-Allan

Aurelius Prochazka Ph.D.

unread,
Apr 25, 2017, 1:50:01 PM4/25/17
to AudioKit Users Group
Marcus has a microtonality pull request I'll be merging later today:


Aure

Marcus Hobbs

unread,
Apr 26, 2017, 12:22:14 AM4/26/17
to AudioKit Users Group
@Allan, would love your feedback on the pull request.

Can we discuss via Slack?  There's a #microtonal channel if you want to talk more there

Marcus Hobbs

unread,
Apr 26, 2017, 12:22:20 AM4/26/17
to AudioKit Users Group
Allan,

Not sure if you have had a chance to review my pull request that Aure referred to, and I don't see you in Slack, so I'll reply here:

Short answer is the implementation is functionally the same as what you describe with very minor differences.

A new class AKTuningTable has some helper functions for some basic presets and reading Scala files; has root note and frequency at root note properties.  I intend to flesh this out more with more presets.

AKPolyphonicNode has a global instance of AKTuningTable which defaults to 12ET (practically identical to the note2Hz fn).  AKPolyphonicNode has a default AKPolyphonic protocol implementation of "play" that looks up frequency in the global tuning table based on note number and passes this down to the DSPKernal classes.

Subclasses of AKPolyphonicNode are AKFMOscillatorBank, AKMorphingOscillatorBank, AKOscillatorBank, AKPhaseDistortionOscillatorBank, and AKPWMOscillatorBank.

I wrote a simple playground illustrating some presets...really looking forward to fleshing this out more too.

Looking forward to any feedback you might have.

Marcus

On Tuesday, April 25, 2017 at 10:46:16 AM UTC-7, Allan Hoeltje wrote:

Allan Hoeltje

unread,
Apr 26, 2017, 9:49:10 PM4/26/17
to AudioKit Users Group
Marcus,

Wow!  Nice work!  I am sorry to have missed the opportunity to implement this myself but it is obvious that your expertise in microtonality is way, way ahead of mine and you deserve the honor and credit.  I had never heard of Erv Wilson before, or your “Wilsonic” app, so that alone makes this a great day.

It pleases me to see that your implementation is very similar to what I have done so far.  All I had left was code to parse the Scala text format.  I missed your invitation to the Slack channel because my computer was packed away at the time - I am in Baja at the moment working on our “getaway” house instead of software.  :-(

> Looking forward to any feedback you might have.

In AKTuningTable.swift, the private func named numberField confused me at first since it is named the same as the private var numberField.   I guess that’s not such a big deal, I am an old timer C/Obj-C engineer and relatively new to Swift.

But, can you make the numberField func public?  I was thinking in a real iPad app one could obtain Scala text from email or a webpage and paste it into your app’s tuning option.  Reading it from a file is nice but files are not as accessible in an iOS app as are raw text strings.

That’s it for tonight.  I have not run your playground yet but plan to do that tomorrow.

-Allan

Marcus Hobbs

unread,
Apr 27, 2017, 12:13:13 AM4/27/17
to AudioKit Users Group
Allan, that's a really good suggestion to make numberField public, and to rename the private method.  I'll do that tonight.

I'm going to add a ton of cool presets/tuning systems to this file.  My goal is to make it easy for folks to survey tons of tunings without needing to know anything about microtonality.

Allan Hoeltje

unread,
Apr 27, 2017, 4:36:30 PM4/27/17
to AudioKit Users Group
Marcus,

Playing here in the Microtonality playground.  The only problem I've found is when I try to use the hexany_1_45_135_225 preset.   I get the console message:

    scalaFile can't read filePath:hexany_1_45_135_225.scl

I don't see how this file is copied in Xcode to the Playground resources.  The file does exist in the AudioKit/Playgrounds/AudioKitPlaygrounds/Playgrounds/Synthesis.playground/Resources directory but it does not make it to the playground's DerivedData.

How do we put resource files into the Playground?

Oh, and two minor observations.  The Synthesis Table of Contents does not mention the Microtonality playground and the Presets do not include "Equal Temperament"

-Allan

Aurelius Prochazka Ph.D.

unread,
Apr 27, 2017, 5:11:01 PM4/27/17
to AudioKit Users Group
Regarding reading the file out of resources, that should work, probably just a small bug in the what load file is expecting. Looks like it's taking a string when it should be file path reference.  We'll get that worked out.  Thanks for checking this carefully!

Aure

Allan Hoeltje

unread,
Apr 27, 2017, 5:36:44 PM4/27/17
to AudioKit Users Group
In the file AKTuningTable.swift the frequencyAtMiddleC is defined as 261.0.  Shouldn't this be 261.6255653006?

-Allan

Allan Hoeltje

unread,
Apr 27, 2017, 7:16:17 PM4/27/17
to AudioKit Users Group
Marcus,

I believe there is a bug in the numberField(fromScalaString rawStr: String?) function.  I wanted to see the Scala parsing in action so I added a simple function to AKTuningTable.swift:

public func scalaText(_ contentStr: String) {

AKLog("scalaText: \(contentStr)")

if let scalaNumberField = numberField(fromScalaString: contentStr) {

tuningTable(fromNumberField: scalaNumberField)

}

}


And then passed it the string:

"! ptolemy.scl\n!\nPtolemy Intense Syntonon\n 7\n!\n 9/8\n 5/4\n 4/3\n 3/2\n 5/3\n 15/8\n 2/1\n"


The parse crashes on the "9/8".  A screen shot of the Xcode debug is attached.  The code line that fails is "scaleDegree = Element(lineStr)" where lineStr is "9/8"

-Allan




scalaParseError.jpeg

Marcus Hobbs

unread,
Apr 27, 2017, 11:06:47 PM4/27/17
to AudioKit Users Group
Allan, thanks for the excellent feedback.  I'm sizing some of the ideas discussed and planning the next steps.

Marcus Hobbs

unread,
Apr 28, 2017, 1:28:40 AM4/28/17
to AudioKit Users Group
Hey Allan,
Fixed the exception in your example:
 #865.
Thanks so much for testing this.
Marcus
Reply all
Reply to author
Forward
0 new messages