Start a new topic

Orba 2 Hacking Knowledge Base

image

This forum is intended to share Orba 2 hacking tips amongst the Orba 2 community. NOTE: Please post facts that are well understood & useful. If you have theories to discuss, please start another forum and link to it here.


2 people like this idea

@Subskybox - and I should have said that your Pandrum preset is really nice - it has become my default preset - because it's the most fun to play.

@Subskybox - I appreciate your reply, especially the warning about the Modifier Chains. I wasn't going to touch that section in the xml for now - but I might have in desperation to get something to work! With the mod entries  in the synth patch I have been copy and pasting entries from elsewhere and perhaps changing  values that have been used elsewhere. (and much the same with Seekers.)

I had seen Ian Walbachs  list and am currently trying to get an understanding of the seekers and this has helped - I'd like get to a point where I have the equivalent for the Orba 2.


By the way, I did have a thought about a glitch  with pitch bend that you or Ignis (I think) mentioned in the Orba 1 hacking thread - I wondered whether this could be a Y2K type problem - where when a value gets to a level where more bits are used they get misread. ie: if the program expects 4 bits but gets 8 it ignores the 4 high values, or perhaps only accepts them and ignores the lower bits. But that might be just my imagination running wild!



@David Benton

Thanks for documenting this! I did know some of it, but it was really nice to confirm some of what is known. You are spot on with your Seeker / Listener analogy. There was another user who documented uids/sensors/cc#s for Seekers for Orba 1. I haven't had time yet to check them against Orba 2:


https://github.com/IanHalbwachs/orba-presets/blob/main/All%20Gestures.xml


I believe they simply started unrolling the Base64 stuff so that it was easier to edit and work with in the future:

<!-- tap [note] -->
<!-- tilt [cc1] -->
<!-- vibrato [pitch wheel] -->
<!-- spin [cc 112] -->
<!-- radiate [cc74] -->
<!-- press [channel pressure] -->
<!-- shake note [note 69] -->
<!-- shake cc [cc 2] -->
<!-- move cc [cc 113] -->
<!-- bump [note 39] -->

BE CAREFUL! I wouldn't mess with the Modifier Chains unless you really know what you are doing. I believe this data is written directly to specific memory pointers in Orba firmware space. This can overwrite important parts of the firmware and brick your device. As a rule of thumb do not change the length of any arrays or ModifierChain pointers because the current firmware does not validate this.


2 people like this

Last night I was playing about with Orbasynth trying to create a particular sound but what I was got to instead was a harmonica sound.

Today I decided to see how well it would work with pitch bend and tried some presets for the Orba 2.


One observation was that using pitch bend with the MPE Y setting was by far the best way of getting a realistic blues harp sound - however, as was discussed in an Orba 1 thread on pitch bend, it is also prone to creating a cacophony when two discordant notes are sounding at the same time. (MPE Y changed the pitch by moving the finger from close to the centre of the Orba towards the circumference and vice versa)

Using MPE X was good to use at all, I felt. 

Another thing was that I found the best way of using tilt was by holding the orba facing me and vertical. The scale was diatonic in C but I was effectively playing in D and using tilt to lower the pitch.

The pitch thing  also worked  well on the keys.


This begs the question - is it possible to reverse the actions of gestures? I mean making the effect on by default and diminished by the gesture. I've not worked out if I can get a viable gesture to go from below the true pitch to above it, and if that is actually practical - I suspect it might not.


SInce the voice I have seems to be pretty good I will experiment with it to see if I can make a good preset without pitch bend. But I would be interested if anyone wanted to try them and comment.

I have made two versions (both with the same id and hash so they can just be written over by the other.

v1 uses the tilt gesture, v2 uses movement on the keys. These versions are not the finished things.

zip
zip

Oh, and another thought on seekers.

If the inMin and inMax defines the limits of what input  it will pay attention to, and the outMin and outMax are the top and bottom values it it will turn the input into for passing on -  this might explain some of the weird behaviour that has been noted elsewhere. The maxRate is then perhaps controlling how much data is being accepted - giving the device enough time to be able to process it.

Now I shall try and rest my weary mind.  

Oh, it's just dawned on me. The mod entries in the synthPatch define the parameters for each effect and the seekers tell the Orba when they should be used. So if there's no seeker to send the signal to an effect if won't do anything. (It seems to have a clear logic like that - even if I'm wrong!)

I have been trying to get to grips with synth based presets for the Orba 2.

I thought I would post what I've come to understand or suspect so far and hopefully it will be useful to others, and perhaps some can add their own input as well.


While the OrbaSynth app is only for Orba 1, it can be useful for the Orba 2 as a synthPatch from it can be pasted into a Orba 2 preset.

Unlike the Orba 1 the Orba 2 synth based presets don't have a Modifier List section, instead there is a Modifier Chain section but this seems to be un-used. The SeekerEntrys are now a set of parameters in human friendly-ish terms rather than the Base64 encoded strings. These things mean there are no Base64 strings to deal with at all. (I was misled about this at first because I was trying to convert Orba 1 presets for Orba 2.)


Seekers I guess are related to something like listeners which I have seen in PC programming where to get input from a device (eg: a digital pen) you have to add a listener to tell the computer to "listen" for it's output. The Seeker settings perhaps affect the way it handles or passes on these inputs.

In the SeekerEntrys the metricSelection can be Shake, MPE X, MPE Y, MPE Z. While these may seem to be for Midi output only, they do affect the Orba 2's standalone sound. As far as I can tell Shake refers to Shake events (obviously) for which midi may not have an equivalent (I don't know). MPE Z to Tilt, MPE Y to movement on the keypad from the circumference towards the A key, and MPE X from side to side on the keypad. But I'm not certain - it's just what I have observed.


I have been thinking of the SynthPatch in two parts. First the settings that relate to the oscilators, VCA, LFO etc. and the mod settings which I assume are relating to modifiers. If you change the first section eg: copy and paste from another preset it will affect the effects to some degree. In the case of pitch bend I found with the original synth settings I got a full tone pitch bend over 90 degrees tilt. With a different synth setting that became over 60 degrees (roughly) with no change in pitch beyond that.


The first seeker entry picks up the first touch of a keypad (perhaps it's lifting off as well) and so is necessary. The rest seem to be optional.


The mod section is a bit of a mystery to me still - it is divided into four groups mod1, mod2 etc. Each of the groups can have two or three divisions eg: mod1_2. I have some ideas about it but I've not established anything coherent about it yet. It is clearly dealing with modifying effects and I suspect each relates to a different effect - I guess some of those folks who have been hacking Orba1 presets may have ideas or knowledge about that.


I apologise if some or all of this is already known - but I hope it at least helps someone.


Thanks to SUbskybox,BJG145,Andrea Mannocci, Ignis32 and others. Even when I don't understand or it's not directly relevant to what I'm trying to do it still seems to help!

 

 

 

 

 

 

 

 

 

Thanks for this. When I first received my Orba 2, I had a look through the Orba 2 App binary and found the following:

  <TuningList category="percussion" keySelection="false">
    <TuningEntry name="All Kicks" />
    <TuningEntry name="Drum Kit" />
    <TuningEntry name="Electro Kit" />
  </TuningList>
  <TuningList category="tonal" keySelection="true">
      <TuningEntry name="Major"            type="tonal" intervals="P1, M2, M3, P4, P5, M6, M7, P8" />
      <TuningEntry name="Natural Minor"    type="tonal" intervals="P1, M2, m3, P4, P5, m6, m7, P8" />
      <TuningEntry name="Harmonic Minor"   type="tonal" intervals="P1, M2, m3, P4, P5, m6, M7, P8" />
      <TuningEntry name="Melodic Minor"    type="tonal" intervals="P1, M2, m3, P4, P5, M6, M7, P8" />
      <TuningEntry name="Major Pentatonic" type="tonal" intervals="P1, M2, M3, P5, M6, P8, M9, M10" />
      <TuningEntry name="Minor Pentatonic" type="tonal" intervals="P1, m3, P4, P5, m7, P8, m10, P11" />
      <!--
      <TuningEntry name="Dorian"     type="tonal" intervals="P1, M2, m3, P4, P5, M6, m7, P8" />
      <TuningEntry name="Phrygian"   type="tonal" intervals="P1, m2, m3, P4, P5, m6, m7, P8" />
      <TuningEntry name="Lydian"     type="tonal" intervals="P1, M2, M3, A4, P5, M6, M7, P8" />
      <TuningEntry name="Mixolydian" type="tonal" intervals="P1, M2, M3, P4, P5, M6, m7, P8" />
      <TuningEntry name="Locrian"    type="tonal" intervals="P1, m2, m3, P4, d5, m6, m7, P8" />
       -->
  </TuningList>

 I thought at one point I had succeeded in Harmonic Minor and Melodic Minor but I haven't been able to re-create this. I had tried setting tunings from the voices and also from the songs to see how to get these to take effect. I believe it had something to do with being in Chord mode but had not invested much time to figure this out. I found it interesting that there are other modes in there but they are commented out. This is likely because it really messes up Chord mode if you leave the current tunings.


1 person likes this

P.S. actually it is four types  of tunings in collectiions, if we take chords into considerations:

tunings = {

    "1efc1a01a23c5f12c4d0b44a076c2d6d": {

        "Bass": {

            "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

            "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

            "key": "C",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Major",

        },

        "Chords": {

            "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

            "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

            "key": "C",

            "chord_minor": "0, 3, 7, 0; 0, 3, 8, 0; 0, 4, 7, 0; 0, 3, 7, 0; 0, 3, 7, 0; 0, 4, 7, 0; 0, 4, 7, 0; 0, 3, 7, 0; ",

            "chord_major": "0, 7, 12, 16; 0, 7, 12, 15; 0, 7, 12, 15; 0, 4, 7, 16; 0, 4, 7, 12; 0, 3, 7, 12; 0, 3, 12, -4; 0, 4, 12, -5; ",

            "name": "Major",

        },

        "Lead": {

            "tuning": "60, 62, 64, 67, 69, 72, 74, 76",

            "intervals": "P1, M2, M3, P5, M6, P8, M9, M10",

            "key": "C",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Major Pentatonic",

        },

    },

    "4ca3e15c6794d6f08ef95c6475ad0b61": {

        "Bass": {

            "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

            "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

            "key": "C",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Major",

        },

        "Chords": {

            "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

            "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

            "key": "C",

            "chord_minor": "0, 7, 15, 24; 0, 8, 15, 24; 0, 7, 16, 24; 0, 7, 15, 19; 0, 7, 15, 19; 0, 7, 12, 16; 0, 7, 12, 16; -12, 3, 12, 19; ",

            "chord_major": "0, 7, 16, 24; 0, 7, 15, 24; 0, 7, 15, 24; 0, 7, 16, 24; 0, 4, 12, 19; 0, 3, 12, 19; 0, 3, 8, 15; -12, 4, 12, 19; ",

            "name": "Major",

        },

        "Lead": {

            "tuning": "60, 62, 64, 67, 69, 72, 74, 76",

            "intervals": "P1, M2, M3, P5, M6, P8, M9, M10",

            "key": "C",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Major Pentatonic",

        },

    },

    "739dc66cb7f613dd50afb537615686fa": {

        "Bass": {

            "tuning": "57, 59, 60, 62, 64, 65, 67, 69",

            "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

            "key": "A",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Major",

        },

        "Chords": {

            "tuning": "57, 59, 60, 62, 64, 65, 67, 69",

            "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

            "key": "A",

            "chord_minor": "0, 3, 7, 0; 0, 3, 8, 0; 0, 4, 7, 0; 0, 3, 7, 0; 0, 3, 7, 0; 0, 4, 7, 0; 0, 4, 7, 0; 0, 3, 7, 0; ",

            "chord_major": "0, 7, 12, 16; 0, 7, 12, 15; 0, 7, 12, 15; 0, 4, 7, 16; 0, 4, 7, 12; 0, 3, 7, 12; 0, 3, 12, -4; 0, 4, 12, -5; ",

            "name": "Natural Minor",

        },

        "Lead": {

            "tuning": "69, 72, 74, 76, 79, 81, 84, 86",

            "intervals": "P1, m3, P4, P5, m7, P8, m10, P11",

            "key": "A",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Minor Pentatonic",

        },

    },

    "0b9b7ef83936a6d57302e117d13aa6f9": {

        "Bass": {

            "tuning": "50, 52, 53, 55, 57, 58, 60, 62",

            "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

            "key": "D",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Natural Minor",

        },

        "Chords": {

            "tuning": "50, 52, 53, 55, 57, 58, 60, 62",

            "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

            "key": "D",

            "chord_minor": "0, 3, 7, 0; 0, 3, 8, 0; 0, 4, 7, 0; 0, 3, 7, 0; 0, 3, 7, 0; 0, 4, 7, 0; 0, 4, 7, 0; 0, 3, 7, 0; ",

            "chord_major": "0, 7, 12, 16; 0, 7, 12, 15; 0, 7, 12, 15; 0, 4, 7, 16; 0, 4, 7, 12; 0, 3, 7, 12; 0, 3, 12, -4; 0, 4, 12, -5; ",

            "name": "Natural Minor",

        },

        "Lead": {

            "tuning": "62, 65, 67, 69, 72, 74, 77, 79",

            "intervals": "P1, m3, P4, P5, m7, P8, m10, P11",

            "key": "D",

            "chord_minor": "n/a",

            "chord_major": "n/a",

            "name": "Minor Pentatonic",

        },

    },

}


I've generated a list of known unique  factory preset collections tunings.


By collections I mean presets starting with the same name like "EyesClosed" appearing in all three types of instruments - Lead Bass Chords. Also I excluded stem presets, as soon as tunings there could be random, and pitch is not transposed anyway.


Assuming that each factory collection contains instruments compatible with each other by tuning,   by using one of these sets of tunings , you should also get instruments compatible with each other the same way as original factory collection instruments are.


If I had not been mistaken with my python code for generating this stuff, there are 3 sets of  stock tunings used in Orba2 currently:


02ecf3facb473666d5ec99c721fca102

{

  "Bass": {

    "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

    "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

    "key": "C",

    "name": "Major"

  },

  "Chords": {

    "tuning": "48, 50, 52, 53, 55, 57, 59, 60",

    "intervals": "P1, M2, M3, P4, P5, M6, M7, P8",

    "key": "C",

    "name": "Major"

  },

  "Lead": {

    "tuning": "60, 62, 64, 67, 69, 72, 74, 76",

    "intervals": "P1, M2, M3, P5, M6, P8, M9, M10",

    "key": "C",

    "name": "Major Pentatonic"

  }

}

45308bef837ea0c8c556f3ad86bb11f1

{

  "Bass": {

    "tuning": "57, 59, 60, 62, 64, 65, 67, 69",

    "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

    "key": "A",

    "name": "Major"

  },

  "Chords": {

    "tuning": "57, 59, 60, 62, 64, 65, 67, 69",

    "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

    "key": "A",

    "name": "Natural Minor"

  },

  "Lead": {

    "tuning": "69, 72, 74, 76, 79, 81, 84, 86",

    "intervals": "P1, m3, P4, P5, m7, P8, m10, P11",

    "key": "A",

    "name": "Minor Pentatonic"

  }

}

793f94d1591e0df9e712b4b338be5376

{

  "Bass": {

    "tuning": "50, 52, 53, 55, 57, 58, 60, 62",

    "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

    "key": "D",

    "name": "Natural Minor"

  },

  "Chords": {

    "tuning": "50, 52, 53, 55, 57, 58, 60, 62",

    "intervals": "P1, M2, m3, P4, P5, m6, m7, P8",

    "key": "D",

    "name": "Natural Minor"

  },

  "Lead": {

    "tuning": "62, 65, 67, 69, 72, 74, 77, 79",

    "intervals": "P1, m3, P4, P5, m7, P8, m10, P11",

    "key": "D",

    "name": "Minor Pentatonic"

  }

}


1 person likes this

Some additional stuff I got bumped into during new year holidays.

1) Looks like there is a limit of SampleDrumPatches that can be used. My guess is that it is limited by 16 SampleDrumPatches (that's the maxmium amount for known factory presets). 

Everything that exceeds the limit will not be loaded, and therefore not played


2) Most probably there also is a limit for velocityThresholds / sampleMap  strings.   I could not estimate this limitation,  but  had bumped into it.


Found that when I'd made attempt to pseudo-randomize  samples.

Idea was that that slightest velocity change would be a kind of random seed for choosing variants of the sample, to produce more natural sound.
 
For example, let say we have 3 sample variants for the same note.

 velocity 50 choses sample 1,  velocity 51 - sample 2, velocity 53 - sample 3,

and then we go in circles - velocity 54 - sample 1 again, 55 will be2, and so on.


But such epic velocity/sample groups that has a different sample for each +1 velocity change, total of 126  velocity ranges for about 7 sample  groups - does not work.  Only some of the first groups are played, so I think it is a string length limitation in sampleMap and noteThreshold strings.. But I've pushed this too far in many directions, to be really sure where exactly limitation is.


3) And the last one for today.   I am starting to get more or less stable results in artipreset generation from sf2, and even wanted to share some example preset collection,  but looks like tunings are quite vital for a collection of presets to play together well. For example,  combination of ElectricBass   BigStrings    SoloViolin  used as templates for generating Bass, Chords and Lead respectively, produces a collection of preset that is not actually playable. Pitches are alright, and notes are the same that are produced  when using Orba as midi controller to play the same SF2 instrument from my PC, so I assume there is nothing wrong with preset generation. But "scales" on different instruments do not fit each other completely.


Tunings for lead, bass and chords should match together somehow. Otherwise you have all these instruments, each one plays more or less nice, but they do not fit each other melodically.


 I've generated a list of known tunings/intervals for the known factory presets, and I guess each Lead should have corresponding  compatible Bass and Chords here (and probably Chords should also have some corresponding chords setting), but at the moment I do not know good sounding combinations  / relations between them, nor I understand  what intervals string really mean.


My best bet for now is to write down all the tunings/intervals for the known factory collections, which were designed to be played together, and use these tunings to override tunings in the templates I am using to generate new presets.

 

  "Lead": {

    "60, 62, 64, 67, 69, 72, 74, 76": "P1, M2, M3, P5, M6, P8, M9, M10",

    "67, 69, 70, 72, 74, 75, 77, 79": "P1, M2, m3, P4, P5, m6, m7, P8",

    "69, 72, 74, 76, 79, 81, 84, 86": "P1, m3, P4, P5, m7, P8, m10, P11",

    "60, 62, 64, 65, 67, 69, 71, 72": "P1, M2, M3, P4, P5, M6, M7, P8",

    "62, 65, 67, 69, 72, 74, 77, 79": "P1, m3, P4, P5, m7, P8, m10, P11",

    "66, 68, 69, 71, 73, 74, 76, 78": "P1, M2, m3, P4, P5, m6, M7, P8"

  },

  "Bass": {

    "48, 50, 52, 53, 55, 57, 59, 60": "P1, M2, M3, P4, P5, M6, M7, P8",

    "55, 57, 58, 60, 62, 63, 65, 67": "P1, M2, m3, P4, P5, m6, m7, P8",

    "57, 59, 60, 62, 64, 65, 67, 69": "P1, M2, m3, P4, P5, m6, m7, P8",

    "50, 52, 53, 55, 57, 58, 60, 62": "P1, M2, m3, P4, P5, m6, m7, P8",

    "54, 56, 57, 59, 61, 62, 64, 66": "P1, M2, m3, P4, P5, m6, M7, P8",

    " 55, 57, 58, 60, 62, 63, 65, 67": "P1, M2, m3, P4, P5, m6, m7, P8"

  },

  "Chords": {

    "48, 50, 52, 53, 55, 57, 59, 60": "P1, M2, M3, P4, P5, M6, M7, P8",

    "67, 69, 70, 72, 74, 75, 77, 79": "P1, M2, m3, P4, P5, m6, m7, P8",

    "57, 59, 60, 62, 64, 65, 67, 69": "P1, M2, m3, P4, P5, m6, m7, P8",

    "50, 52, 53, 55, 57, 58, 60, 62": "P1, M2, m3, P4, P5, m6, m7, P8",

    "66, 68, 69, 71, 73, 74, 76, 78": "P1, M2, m3, P4, P5, m6, M7, P8"

  },

  "Drums": {

    "36,38,42,49,43,45,51,70": "P1, M2, A4, m9, P5, M6, m10, m21",

    "36, 38, 42, 49, 43, 45, 51, 70": "P1, M2, A4, m9, P5, M6, m10, m21"

  }



Questions are()if somebody knows):

1) How actually switching between Major/Minor and root note in the Orba2 app works?

XML stores only one hardcoded tuning, so probably it gots transformed on the fly somehow

2) What are these intervals in the XML exactly and how are they supposed to work?

@Ignis32 Wow! That is truly some great detective work and thanks for documenting it. This information will be vital for other Orba Hackers who join in the years to come. A few comments:


On using the same note. I had tried this a little while back when I shared my Tibetan Singing Bowl test in another forum. I assigned the same note to all pads so that you could circle your finger around like you were tracing the edge of an actual singing bowl. The thing I noticed is that it does not reset the note when you do this. If you hold down a note and then press another pad with the same note, it will not stop the initial note or restart it. I was hoping to find a way that making circles slowly would make the volume lower while making circles more quickly would make the sound louder.. Like when you do this with a wine glass.. I will probably go back to that idea once we know more about the Drum Preset setups.


I know that some of the older presets (Orba 1 generation) do not use samples, and the output is created in a different way by the synth module. Maybe looking at these may provide more insight into how the whole chain works.


I think there are a number of attributes in place that are not used (yet) such as note. I have found other examples of unused attributes as well and I believe they are there for future purposes. Since Artiphon is using the JUCE engine, some of these may be mandatory even if not used by Artiphon's implementation.

@SubSkybox, thank you for editing my post, I think  we will just leave it here posted from you,  to reduce amount of unnecessary actions.

Meanwhile, I guess that I've got some partial understanding of the drum presets sample mapping.

TL;DR:
 when we push a pad,  sample to play the pad is determined as below:
1) note number is taken from the Tuning
2) we lookup for  SampleDrumPatch element  by searching for the this note in  the noteMidi attributes
3) we take index  attribute of the SampleDrum patch and lookup for the corresponding  sampleMap sample group using this index.
4) choose sample by velocity using velocityThresholds.

Long read:

While decide chain that chooses which sample to play for the Lead/Bass - seems to be

 Pads->Tuning->noteThresholds->velocityThresholds->sampleMap->SampledSound[ ]

and the Chords is doing the same plus, you know, chords stuff, for Drums it is different.


For Drums this chain seems to be 

Pads->Tuning-> SampleDrumPatch[ ] -> velocityThresholds->sampleMap->SampledSound[ ]

(it is simplified version without DrumPatch, CymbalPatch and ShakerPatch which are doing something useful as well, but I am skipping it for now,

because it works without these elements and I have still no clue how do they work)


First of all, Tuning.

Tuning is responsible for the midi note numbers produced, and for drums it seems to be something static, with no octave shifts.

Each number means midi note for pads from 1 to 8.

Usually it will be stuff like 36,38,42,49,43,45,51,70, but for some demonstration purposes lets say it is like below, just the same numbers as pads just doubled.

 tuning="11,22,33,44,55,66,77,88" 

it works too, but will produce a preset which is kind of useless for controlling PC as midi controller sending some rarely used notes..

Here I assign note 11 for pad 1, note 22 for pad 2 and so on.


Also, 39 seems to be hardcoded for bump/shaker event, so it is kind of "11,22,33,44,55,66,77,88"+"39" under the hood. Btw, you even can assign same note to the different pads if you like.


Next element in the chain will be the list of SampleDrumPatch elements, where we determine required one exact  SampleDrumPatch by noteMidi attribute. 


For example, if we push Pad 2, and according to our tuning note is 22,  we are choosing SampleDrumPatch with noteMidi="22". In our case it will be SampleDrumPatch with index=1. This index is vital.    Order of SampleDrumPatch elements seems not to be vital, only index is.


  <SampleDrumPatch index="0" note="0" noteMidi="11" ....

  this one ->  <SampleDrumPatch index="1" note="0" noteMidi="22" ....

  <SampleDrumPatch index="2" note="0" noteMidi="33" ....


(There is also a "note" attribute, but it does not make any sense to me currently, and does nothing. I just suspect they are related to the DrumPatch/CymbalPatch stuff which I had omited.)


Anyway, now we've determined SampleDrumPatch index. In all factory presets, amount of SampleDrumPatches is equal to amount of sample groups in sampleMap and velocityThresholds, and that's not a coincidence.

Each SampleDrumPatch has his own dedcated sample group, determined by SampleDrumPatch's index attribute  (counting from zero).  


This index corresponds to the sample group number, so in case of sample mapping like below,

 sampleMap="[0][1][2][3][4][5][6][7][8]">

we have different sample groups with one sample in each, and if we are searching for the sample group for SampleDrumPatch with index=1, it is the second group from the left - [1]

In case if sample group has more than one sample, looks like the same velocityThresholds mechanics as in Lead presets kicks in, that allows to choose sample within a group based on the velocity.

This is the sample group that is going to be triggered. At least when no DrumPatch/CymbalPatch stuff is in the KitPatch.

Most confusing part is noteThresholds. From one side it seems to be ignored. It works for me fine with

noteThresholds="99,100,101,102,103,104,105,106" setting, where there is completely no meaningful corellation with other elements, so it looks useless. However, it still somehow mandatory to have the correct amount of numbers in the noteThresholds (sample groups amount minus 1 ), and each number should be bigger then the previous, otherwise it does not work properly.



For sure, I still can be mistaken in my theories, at least noteThresholds part is kind of strange, and note= attribute mystery is not solved yet at all.


But that's all I've got for now.


Also attaching an example xml that I used for testing and this post.



4 people like this

After tinkering with the .artipreset format for a while, I've finally written explanation of some internals of the .artipreset, regarding the SamplesSet, which is the core part of preset customization.

As we all know, Orba2 presets are configured by an .artipreset file, which is basically an xml file.

Artipresets that work with samples, at least modern ones, contain an xml element SampleSound that is explained below:

[SampleSet] contains a list of wav samples where each sample is described by SampleSound elements array, and some metadata.

>For example:

<SampledSound sampleIndex="0" name="E1" loopStart="130607" loopEnd="331519" pitch="44.847287" fileName="SF2_Synth-Square_E1_E2_b8dd7e94e9ae3436e93b391003f376f3.wav" subdirectory="SF2_Synth-Square" pool="User"></SampledSound>

  <SampledSound sampleIndex="1" name="G#1" loopStart="107400" loopEnd="287479" pitch="56.50404" fileName="SF2_Synth-Square_G#1_G#2_5ad6c793e97f1cc91d22abb82709eda4.wav" subdirectory="SF2_Synth-Square" pool="User"></SampledSound>

  <SampledSound sampleIndex="2" name="C2" loopStart="106165" loopEnd="330438" pitch="71.19063" fileName="SF2_Synth-Square_C2_C3_876a99e3f4e165a58d2997beb1d94c64.wav" subdirectory="SF2_Synth-Square" pool="User"></SampledSound>

[SampleSound] attributes information:

[sampleIndex] attribute is used in SampleSet sampleMap attribute, for composing "groups" from the samples.

[loopStart and loopEnd] define borders for "loop" part that happens if you hold a note for long enough to produce endless sounds, Orba plays this loop until you release the button. loopStart=0 and loopEnd=0 mean that there is no loop. Units here are not "time" based, these values are indexes of the data frames in the .wav file, or something like that.

[fileName] obviously, defines the wav file name, but with one caveat - it is mandatory to have _{uuid}.wav at the end of the filename. Without it, Orba rejects the sample.

UUID is a unique id of the sample, and each file should have its own uuid. UUID is a 16 symbol string, that contains numbers and lower case letters, like "b8dd7e94e9ae3436e93b391003f376f3" and by coincidence any md5 checksum can be used as UUID, at least if all samples have their own unique uuid.

[pool] means a sample pool subdirectory where sample is stored, both on the device itself and in the local Artiphon profile folder. All factory samplepools are like "AritphonExt1","ArtiphonExt2","ArtiphonBasic". But in our case, we always want to user "User" pool. At least this is a designated location for the user content. One day removal from this samplepool will work, I hope.

[subdirectory] is just a folder name for this specific sample set, and I keep it named the same as preset, but that's not an actual requirement.

[pitch] - This is an interesting one, and describes what is the tuning of the sample in Hz. It DOES NOT seem to be used by Orba2 in the process of deciding which sample it should play (it is defined by sampleMap/noteThresholds/velocityThresholds). Instead it is only used to decide how already chosen sample should be transposed during playback, changing both pitch and a speed of the playback.

For example, let's say, we are playing notes from 58 to 62, and according to sample mapping we are using the same sample for all this range, and its pitch is configured in SampledSound as 261.63.

For midinote 60, this sample would be played with no transformations, as note 60 perfectly matches this frequency. For note 58 the same sample will be played about 1.12 slower and therefore with a lower pitch compared to the original. And for note 62, sample will be played 1.12 times faster and higher.

Also, if negative, pitch attribute works differently. "-1" means that sample is never transposed, is static and sounds the same as in file.

If negative but not equal to -1, it will mean a static pitch correction coefficient. Like "how many times faster this sample is compared to what we want it to be".

For example pitch="-1.08844" seems to be fine as a correction coefficient for 44.1khz no-transpose samples. Basically it says "play this sample 1.08844 times slower"

As soon as Orba uses 48khz for playback, 44.1 khz samples will be played 1.08844 times faster without such compensation. But when pitch="-1.08844" is applied, sample is slowed again back by 1.08844, and in the end you hear sample with the same pitch as it is supposed to be.

Now to the sample mapping and thresholds in SampleSet element. They define how Orba2 decides which sample to play. At this point I should mention that I am not still sure about how it works for drums, it seems to choose samples in some other way, not still sure. But for Lead, Bass, and Chords that's how it seems to work.

Here is a snippet from the SampleSet element .artipreset xml:

<SampleSet name="PanDrum"
  noteThresholds="45,46,48,50,52,53"
  velocityThresholds="[50,90][50,90][50,90][50,90][50,90][50,90][50,90]"
  sampleMap="[0,1,2][3,4,5][6,7,8][9,10,11][12,13,14][15,16,17][18,19,20]">

 Let's start with sampleMap.

[sampleMap] creates something like a groups of samples.

In this case the first group contains samples with "index=0", "index=1", "index=2", second contains indexes 3,4,5, and so on.

Samples in one group are triggered by the same midi note, but which one - will be defined by the incoming note velocity and velocityThresholds.

Which sample group will be used to play will is defined by noteThresholds described later. For now let's pretend that we already know which group is triggered.

[velocityThresholds]

Amount of "groups" in velocityThresholds is the same as in sampleMap, and each group corresponds to the group from sampleMap in the same position.

Each velocityThreshold's "group" defines velocity ranges that are used to choose which sample from the corresponding sampleMap group to play.

velocityThresholds group is defined in a somewhat lazy way, omitting the edge values 0 and 127 of the ranges as they are always the same anyway.

That's why amount of the numbers in velocityThresholds group is always one less than in the corresponding sampleMap group.

For example

       velocityThresholds="[50,90]...

                sampleMap="[0,1,2]...

actually means, that there are three velocity ranges, (0-50), (51-90), and (91-127).

And, combined with the information from the corresponding sampleMap group, we know that sample with index=0 will be played if incoming note velocity is in the 0-50 range, index=1 sample is triggered by velocity 51 to 90, and sample with index=2 will play for velocity above 90.

Also [] means group that contains one single range from 0 to 127, and corresponding sampleMap group will contain only one sample's index, like [0] or [10]

Now for [noteThresholds]

This one defines which sampleMap group will be triggered according to the incoming midi note value.

Basically, it is an another lazy-defined list of ranges, with omitted 0 and 127 values on the edges.

noteThresholds="45,46,48,50,52,53" means that there are the following ranges: (0-45),(46-46),(47-48),(49-50),(51-52),(53-53) and, attention, invisibly assumed (54-127)

this last range towards 127 is not written, and that's why amount of numbers in noteThresholds is always one less than amount of groups in sampleMap and velocityThresholds.

Each range corresponds to the sampleMap groups.

For example, 45 note will use sampleMap group [0,1,2] and note 53 will use sampleMap group [15,16,17], and everything above 53 will trigger group [18,19,20].

Therefore, to conclude, when you play a note with a certain velocity, Orba2 uses noteThresholds to decide which sampleMap group is responsible for this note, and after that uses corresponding velocityThresholds group to decide which particular sample (index) should be played.


2 people like this

The reason you cannot see your Preset in the App is because it must have a unique uuid. That is the 32 character hexadecimal code (MD5) that follows the name. For example:


1981_ca0f71882db74f11a2ac6a25c418b841.artipreset


There are lots of ways to generate an MD5 code. A simple way is to use an online tool such as here.

You'll need to modify the filename with a new one as well as the uuid property inside the file.


Orba doesn't currently support musical modes. However, this feature has been requested numerous times since Orba 1. There are some hacks to accomplish this, but they have downsides. There are two known methods to do this today:


1. Change the Tuning Entry to that of a Drum preset. For example:

<!-- Change the Bass|Chord|Lead TuningEntry node from -->
  <TuningEntry key="C" name="Major" intervals="P1, M2, M3, P4, P5, M6, M7, P8"
               midiOctave="3" transpositionType="RetainNotes" type="tonal" tuning="60, 62, 64, 65, 67, 69, 71, 72"/>
<!-- To a Drum TuningEntry like this -->
  <TuningEntry key="C" name="Major" intervals="P1, M2, A4, m9, P5, M6, m10, m21"
               midiOctave="2" transpositionType="RetainNotes" type="percussion"
               tuning="36,38,42,49,43,45,51,70"/>

 -> Change the MIDI note numbers to the correct values for the mode you want. The downside here is that you cannot use the Orba 2 App's Tuning features to select a Key or Major/Minor modes.


 -- OR --


2. WARNING: This method is dangerous and doing this incorrectly could brick your Orba. Start your Preset as a Chord and modify the ChordModifierParams such that each of the groups of 4 numbers are the same. For example, a Phrygian mode would be "0,0,0,0;-1,-1,-1,-1;-1,-1,-1,-1;0,0,0,0;0,0,0,0;-1,-1,-1,-1;-1,-1,-1,-1;0,0,0,0"

<ChordModifierParams majorChordList="0, 11, 16, 19; 0, 10, 15, 19; 0, 10, 15, 19; 0, 4, 11, 19; 0, -5, 4, 10; 0, 3, 10, 19; 0, 6, 8, 15; 0, 4, 9, 14; "
                           minorChordList="0, 10, 15, 19; 0, 6, 10, 15; 0, 11, 16, 19; 0, 10, 15, 19; 0, 3, 10, 19; 0, 4, 11, 19; 0, 4, 7, 10; 0, 3, 7, 12; "/>

 -> The downside here is that using a Chord type only allows you to press one pad at a time :(


I believe Artiphon has put some changes in place that are going to make this possible in the future but for now... no other options.


5 people like this
Login or Signup to post a comment