Ansible bug reports (official)

I noticed in the MIDI code that the pitch calculation uses the SEMI14[] lookup table, based on 16384 DAC ticks / (10 octaves * 12 notes). But other apps on Ansible use the ET[] table from libavr32, based on 4092 DAC ticks / (10 octaves * 12 notes), and always shifts left by 2 before sending a value from this pitch table to DACs. So the SEMI14 values are higher resolution, but since 16384 / 4092 = 4.00391… these values actually wind up drifting apart from each other by a good deal more than 2 bits:

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit (Intel)] on win32
>>> semi14 = [int(n * 16384.0 / 120) for n in range(0, 128)]
>>> et = [int(n * 4092.0 / 120.0) << 2 for n in range(0, 120)]
>>> [(a - b) for (a, b) in zip(et, semi14)]
[0, 0, -1, -1, -2, -2, -3, -3, -4, -4, -1, -1, -2, -2, -3, -4, -4, -5, -5, -6, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -4, -4, -5, -5, -6, -6, -7, -7, -8, -8, -5, -5, -6, -6, -7, -8, -8, -9, -9, -10, -6, -7, -7, -8, -8, -9, -9, -10, -10, -11, -8, -8, -9, -9, -10, -10, -1
1, -11, -12, -12, -9, -9, -10, -10, -11, -12, -12, -13, -13, -14, -10, -11, -11, -12, -12, -13, -13, -14, -14, -15, -12, -12, -13, -13, -14, -14, -15, -15, -16, -16, -13, -13, -14, -14, -15, -16, -16, -17, -17, -18, -14, -15, -15, -16, -16, -17, -17, -18, -18, -19]

Has anyone who uses both MIDI and other apps on Ansible noticed different pitch behavior in grid or arc apps vs. MIDI? Teletype, Aleph, and Trilogy don’t seem to use the ET table, just Ansible. Paging @ngwese, @tehn.

I had thought the SEMI14 table dated back to the original MIDI mode for earthsea but that does not appear to be the case. Roughly spot checking the git commit history the ET table does pre-date the SEMI14 table so I honestly don’t remember why I did what I did (a case of premature optimization perhaps?)

Without sitting down, thinking through the details, and reading the spec sheet for the DAC I’m not sure one is obviously more correct than the other. In my particular case the pitch tracking of any given oscillator could have potentially masked the difference. I only have analog oscillators across my various systems so I tend to just run with it until something seems off then tune to the range of whatever I’m doing at the moment.

Regardless consistency in expression of pitch across ansible modes seems most desirable in the long run so I’d probably advocate moving away from the SEMI14 table in the MIDI mode(s) in favor of the ET table used in the other modes.

2 Likes

Here’s a short example of the pitch deviation of Ansible in MIDI: in the first half of the recording, all the CVs for the 4 voices (digital oscillators put thru simple VCFs/VCAs) are put thru quantizers, in the second half the CVs are put directly to the 4 voices.

It would be great not having to use quantizers.

Here is a build which ought to use the programmable tuning table (based on ET[]) for MIDI, and be able to pass MIDI pitches to I2C followers.

ansible.hex (371.5 KB - 10677b4 - 2020/06/13)

Let me know if it works any better for you, and how the pitch tracking compares to previous builds using the SEMI14 table. I’m hesitant to add these changes to the Ansible beta thread until it’s been checked out by someone else, I have only done minimal testing so far and I don’t have a great ear for pitch.

3 Likes

Thanks very much, but unfortunately, I was still on 3.0.0, so while I was able to save to a USB stick, the .json file that was saved was empty (0kb size). Nevertheless I updated to the preliminary firmware you provided, but from initial experiments it sounds like the update not only erased the preset, but also the tuning table I made (by tuning each and every individual note on all four outputs with a tuner).

Is this expected behavior that a firmware update not only erases the presets, but also erases the tuning table (which is, at least to my understanding, the only way to correct the DACs’s outputs to get an equal-tempered scale)?

If it is expected behavior, is this tuning table stored inside the ansible presets .json file? If it is stored outside of this preset .json file, how do I save the tuning table to USB disk, as I could not find another file on my USB disk beside the preset .json after I executed a store to USB disk (after I updated to your new firmware).

In any case, I will need some time to repeat the tuning process, and as I will be out of town the next 3 days (unfortunately without my system :frowning: ), I won’t get to this before Thursday, sorry. Eager to return and check it out!

1 Like

Yes, the entire contents of module flash are overwritten.

Yes, they are supposed to be saved to the same file but there is a bug in the released 3.0.0 that prevents saving from working at all.

Very sorry about the broken preset saving behavior in 3.0.0. If you created a hex backup file it might still be possible for me to recover presets from this using some Python scripts I have. In addition to the fix for this there are a couple other small changes. If the midi changes work I think that would perhaps be a good time to do a new version.

I did not create a hex backup file, the save to USB disk was the only one I knew of. Out of curiosity: Is the hex backup file the procedure described here? If yes: Lesson learned, from now on I will read the entire page, because I stopped after reading this paragraph :crazy_face:.

Nevermind, recreating the tuning will be an excercise in “practice makes perfect” – and I will update my second Ansible (that recently arrived) to the preliminary firmware right NOW to make sure I will be able to make proper backups. :slight_smile:

@csboling: Today I tuned my Ansible’s CV outs again, this time with the latest firmware from 2020/06/13, but unfortunately the tuning table is still not being used by MIDI Allocation 1 “Poly”.
:frowning:
I did not test the other allocation styles, nor the i2c routing (as I don’t use i2c with Ansible).

Some additional comments:

1. Grid UI Bug when leaving Tuning page via KEY1
When leaving the Tuning page by pressing KEY1, the grid changes to display standard Kria user interface elements, but
(a) notes that were switched on while on the Tuning page continue to sound, and
(b) button presses are executed as if the Tuning page was still active.
While pressing KEY2 ends this rogue behavior, it can be quite unsettling to the novice user.

2. Question regarding leaving Tuning page via KEY2
Tuning changes made in the lowest row or in second lowest row are not discarded when leaving the Tuning page via KEY2. It is not clear from the Tuning page documentation whether or not this is the intended behavior or not. While I do understand that leaving the Tuning page without discarding the edits, but also without saving the edits to Flash, might be desireable in order to “test” the tuning edits before committing them to Flash, the current current behavior can be confusing for a novice user like me, as there is no easy way to leave the Tuning page and discard the potential mayhem I created accidentially.

Suggestion for items 1 and 2: Leave with the behavior of KEY2 unchanged, but turn KEY1 into a “panic” button, i.e. it discards all unsaved tuning edits, and returns the user to Kria. This way, the KEY1 behavior would also be aligned to its “Panic” button behavior in MIDI modes.

3. Bug in MIDI Poly Allocation mode
In Poly Allocation, keys actively held down on the keyboard are not excluded from voice stealing. So if I want to play a single note melody (say E-G-A-B) over a held bass note (“pedal point”, e.g. C), the fourth note of the melody steals the bass note, although I hold its key down. All other implementations of this rotate voice assignment I know from other instruments respect held notes.

4. Question regarding Tuning page documentation
On this page it says:
The row above the bottom row displays and sets the absolute DAC value of the note slot. As the DAC value increases, the leftmost key will get brighter, then it will turn off and the next key over will get brighter, etc., with keys that have already been passed staying dimly lit, visualizing the full CV range of the track.
There is no visual indication happening anywhere on the grid when I press buttons in the second lowest row. The buttons in the second lowest row remain unlit, all they are doing is to switch the CV output voltage in intervals of roughly fifths. Is this intentional?

In general there is zero visual feedback of any button press I do on the Tuning page, I can press any button, but this does not change the visual pattern of the Tuning page at all. It is not clear to me from the documentation if this is expected.

5. Feature Request for additional MIDI Reset Allocation mode
It would be great to have an additional MIDI voice allocation mode, in addition to the existing Poly allocation. This Reset mode would also be four voice polyphonic, but it would assign a new incoming note to the first inactive CV/TR pair with the lowest index number. Here are some more details about this mode.

1 Like

The POLY mode does not track held notes. It simply assigns each incoming note to the next TR/CV pair in ascending order wrapping back to the first pair as of the fifth note. The documentation describes this as “a shift register” but that in retrospect doesn’t paint a very clear picture.

Based on the description it sounds like what you are after is some sort of priority mechanism. I have seen lower note priority, higher note priority, and various forms of stealing the oldest or newest note. The reason priority wasn’t implemented originally came down to UI - with only two buttons, no screen, and a midi device with arbitrary capability plugged in it wasn’t obvious how to allow much if any configuration.

I understand, but I fail to see the benefit of the current implementation, which is disregarding an essential information the performer gives to the instrument: “I am holding down these keys because I want them to sound for as long as I hold them.” Please help me understand the benefit of the current implementation.

No, I am not looking for some sort of low/high/oldest/newest note priority mechanism.

What I am looking for is that incoming MIDI Note On events are assigned to “free” TR/CV pairs only,
with a TR/CV pair being “freed up” the moment it has received the matching Note Off event for the Note On event is has been assigned to. If performers hold down four notes, then play a fifth, the oldest of the held note is stolen. That is the implementation of “rotate” voice allocation I’ve seen in all polyphonic synthesizers I’ve played in the past 35 years.

If rotate is implemented with respect for held notes, there is no need for a special configuration, as the behavior depends completely on the playing style: If performers want all voices to participate in the rotation, they play staccato; but if performers want certain notes to be excluded from the rotation, they hold down these notes.

looking at the source i think this is down to simple expedience, not a design decision.

it’s still not really a “bug,” its a known limitation; the firmware does exactly what the documentation says: sticks a shift register in front of the voices.

in any case i agree that the shift register is less obvious than voice stealing for keyboard input, and this is a good feature request. (aligns with some TODOs in the source.)

a full polyphonic keyboard mode would need other stuff too, like a reasonable interpretation of legato. it’s considerably more complex than the other modes.

1 Like

Thanks!

I don’t think this more advanced stuff you mention like polyphonic legato interpretation is needed to make Ansible’s current Polyphonic mode significantly more useful. I’d certainly rather see just my enhancement request [exclude held notes from voice stealing] being implemented, than waiting (potentially in vain) for a complete full polyphonic implementation with all bells and whistles – which would be “death by overspecification” in my book.

Talking about legato: I have not yet encountered any polyphonic synthesizer that offered a useful polyphonic legato mode. Instead you have to switch to monophonic operation to get legato behavior. From my experience, a really satisfactory polyphonic legato is best achieved with an MPE-capable “fretless keyboard” like the Continuum Fingerboard.

One last plea for an additional Reset polyphonic mode
Reg. my other enhancement request to implement an additional Polyphonic Reset assignment mode: I believe that when implementing polyphonic voices in an analogue modular synthesizer context, only a minority of these implementations will have identical modules across all voices (e.g. 4x Mangroves, 4x 3Sisters etc for a four voice system). Instead, the majority of the implementations will have non-identical modules across all voices (e.g. 1x Mangrove, 1x Plaids, 1x Doepfer VCO, 1x Loquelic Iteritas…just looking at the oscillators for a four voice system). So it will probably be more likely that each voice will a different sound, than that all voices will have exactly the same sound.

This means that an assignment mode that gives the performer precise real-time control over which note shall be played by which voice (aka sound) is preferable to a rotate implementation. The reset assignment mode offers exactly that: You can play a chord, and just by the order in which you press the keys, you can precisely control which note of the chord will be played with which sound.

Examples for such implementations are the “Poly-2” mode of the Roland 184 polyphonic keyboard from their 100m modular synthesizer series, the “Reset” mode of the Polyphonic Keyboard module of the Oberheim Four Voice, or the 225e MIDI Decoder / Preset Manager of the Buchla 200e (which only offered Reset when bundling multiple monophonic voices for polyphonic operation).

it may interest you to know that i helped implement the 200e midi voice handling. trust me when i say that just the basic note stealing logic is significantly more complex than what’s in ansible. :slight_smile:

we’re not talking rocket science, but it’s clear to me that the POLY mode was implemented pretty quickly and is definitely an “add-on.” so let’s just try and be nice when requesting new features and enhancements. it’s a good rule of thumb to assume that no software feature is “trivial” and that features aren’t left off due to ignorance.

Thanks for this explanation. But please understand that as a customer I don’t view the POLY mode as an “add-on”, on the contrary, it was one of the reasons why I bought a second Ansible.

I was trying to thorougly explain the reasoning why I asked for specific features. If the part of my reply with the “death by overspecification” came across as not being nice, please accept my apologies. That part of my reply was not intended to suggest that the implementation of a “full polyphonic keyboard mode” was trivial, but to clarify that I don’t ask for the implementation of a “full polyphonic keyboard mode”.

Or in other words: I tried to say “hey, I don’t want the full cake, just a small piece of it”, whereas you say (at least that’s how I understand you now) “hey, to make that small piece is almost as much work as baking the whole cake”. Does that make sense? :slight_smile:

1 Like

New build (abb6360) posted here.

Hm, I did a brief test in poly mode just applying a large pitch offset and it works, I don’t really understand how this is happening unless I uploaded the wrong build or something. In which case my apologies! The midi code should now be doing all pitch assignments through the function other apps use for setting note values – the only exceptions to this are the velocity / pressure / CC outputs in some modes.

Good catch!

I like this idea, implemented. Note that you can also use the panic grid key on the tuning page (5th from the right on the 3rd from the bottom row) to reload your previously saved tuning, or long-press it to reset to the factory default tuning table.

What grid edition are you using? The bottom two rows take advantage of the 16 brightness steps of current-edition grids, selected brightness levels may need some tweaking for usability on 4-step grids. Pressing the rightmost key on the bottom row seven times results in both the leftmost key on the bottom row and the leftmost key on the 2nd-from-bottom row being fully lit, I expect this to also be the result on a 4-step grid.

2 Likes

Thank you!

I tried that as well, and yes, large pitch changes (= setting one waypoint ridiculously high and let Ansible do the interpolation) transfer well to POLY mode. But unfortunately, the fine pitch adjustments I made on the TUNING page to correct the DAC offsets are still not working in POLY. I made 2 videos to illustrate. In TUNING mode, I tuned every waypoint of every voice as precise as possible. This is how each of the four voices (starting with voice 1) sounds when using this tuning table in KRIA:

This is great, pitches deviate 2 cents mex. Now, this is how the same notes sound when played in POLY:

Not good, pitch deviates somewhat like 15 to 18 cents.

So it looks like large pitch adjustments are carried over from KRIA to POLY, but subtle ones somewhat get lost. Unfortunately, these subtle changes are essential for POLY usage.


Thanks much for implementing the change to KEY1 behavior, works great!

16 level brightness from end of 2015. Here’s how it looks:

1 Like

Yeah this is interesting. I think what’s going on here is probably that the same tuning table is being used, but the midi mode pitch calculation is not quite the same. In particular there is an additional pitch shift applied when assigning midi pitches, this spot in the code notes that there is a -2 octave shift. With the way the CV output code is structured this is effectively being applied as a pitch bend, ignoring the tuning table for those 2 octaves.

The note on this says this value (-3277) is chosen because this is N -24 on Teletype. This is true, but it does not match up with the pitch table being used – it turns out the Teletype N op uses another slightly different note -> DAC ticks lookup table.

Of the three tuning tables Teletype’s seems the most correct to me.

Comparison using a Python shell
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit
(Intel)] on win32

# ansible ET method
# different slope from the others and discards 2 bits of precision
>>> [round(i * 4092 / 120) << 2 for i in range(121)]
[0, 136, 272, 408, 544, 680, 820, 956, 1092, 1228, 1364, 1500, 1636,
...
14732, 14868, 15004, 15140, 15276, 15412, 15548, 15688, 15824, 15960, 16096, 16232, 16368]

# ansible midi SEMI14 method
# uses integer truncation rather than rounding
>>> [int(i * 16384 / 120) for i in range(121)]
[0, 136, 273, 409, 546, 682, 819, 955, 1092, 1228, 1365, 1501, 1638, 
 ...
14745, 14882, 15018, 15155, 15291, 15428, 15564, 15701, 15837, 15974, 16110, 16247, 16384]

# teletype N op method
# rounds and keeps full precision
>>> [round(i * 16384 / 120) for i in range(121)]
[0, 137, 273, 410, 546, 683, 819, 956, 1092, 1229, 1365, 1502, 1638, 
 ...
14746, 14882, 15019, 15155, 15292, 15428, 15565, 15701, 15838, 15974, 16111, 16247, 16384]

The DAC hardware and control code should all be the same, so I think we should just move the table Teletype defines into libavr32 and use it for all the pitch calculations on Ansible as well as the Teletype note table. Looking at the DAC’s datasheet I think 16384 / 120 = 136.5333… ticks per semitone is the correct value rather than 4092 * 4 / 120 = 136.4 ticks per semitone, but there could be a consideration I’m overlooking, like something that’s different about Ansible’s design.


Do you have a Teletype or Crow connected to Ansible? As a short-term way to address the tuning issues while this is getting sorted out on the code side I believe you can use MIDI.SHIFT or a crow equivalent (does not look like this is wired up in the crow firmware yet but this is easy to add) to reprogram this -2 octave shift, then save it to flash on Ansible. You may have to experiment with this value, 15+ cents seems like a lot for this discrepancy to completely account for it but it’s at least part of the problem.

3 Likes

Thanks for explaining what is happening there, although I have to admit that I don’t quite understand it. Or in other words: My understanding of what you wrote is that there is -2 octave shift between POLY and KRIA, which is in contrast to my observations:
(a) The pitch range that’s covered is the same in POLY as it is in KRIA, so there is no 2 octave pitch shift between POLY and KRIA.
(b) The pitch deviations between the four voices happen in every octave of the whole pitch range of POLY, so they are not limited to a specific 2 octave range.
Don’t know if this helps…in any case, I am thankful for you looking into this.

P.S. One last thing: When using the bottom row of the TUNING page in Kria, I noticed that sometimes I was not able to get the tuning of a specific note completely on spot, as it was either 1 or 2 cents too high or too low. Don’t know if it is at all relevant in this context, it certainly doesn’t bother me.

I think it’s more like this: specifying a midi note results in some corresponding output voltage being calculated based on the midi note number. The pitch calculation then subtracts 2V from the calculated voltage to get the CV output into a more usable range – this results in the pitch range being basically the same as for Kria / Earthsea / etc. But the constant value the code is using to represent this shift is not actually the right offset because of the slightly different tuning tables, so it doesn’t exactly cancel out the note-based shift, resulting in (or at least contributing to) the discrepancy you measured between Kria and midi output voltages.

This is an inevitable result of quantization error and non-ideal DAC characteristics, the DACs can only output a finite set of voltages and some of those are closer approximations to the perfect pitch value than others.

2 Likes

Been playing around with Kria a lot lately.

I’ve been noticing that when two Ansible gate outputs fire at the same time the behaviour of my envelope generator change a bit.

With one gate firing (ch 4 → envelope) the envelope fires and I hear the oscillator come through my VCA.

With another gate firing at the same time (ch 1, 2, or 3) the Oscillator sounds a bit louder, almost as if the short trigger out becomes a little longer.

With all triggers channels firing at the same time the oscillator becomes louder yet.

Of course varying the envelope’s attack value will change how this subtle change in the trigger/gate will change the volume…

I have tried this with two different envelopes (Peaks, Z4000) so far and have verified that it happens with both.

This could be considered a feature I suppose. I’ll also try to see if Earthsea does the same thing in a little bit.