Outline
Here is an example of schema and generated table for MIDI Gateway module:
{ "name": "midigw", "type": "Module", "member": [ { "name": "MIDI channel", "type": "NumberSelector", "min": 1, "max": 16 }, { "name": "Voices", "type": "Selector", "choices": ["mono", "duo", "poly 4", "poly 5", "poly 6", "poly 8", "poly 10", "poly 16"] }, { "name": "Retrigger", "type": "Switch", "default": True } ] } #define P_N1_MIDI_CHANNEL_OFFSET 0 #define P_L_VOICES_OFFSET 1 #define P_B_RETRIGGER_OFFSET 2 #define P_BUFFER_SIZE 3 static uint8_t p_buffer[P_BUFFER_SIZE]; #define P_N1_MIDI_CHANNEL (*(uint8_t*)&p_buffer[P_N1_MIDI_CHANNEL_OFFSET]) #define P_N1_MIDI_CHANNEL_VALUE_OFFSET 1 #define P_L_VOICES (*(uint8_t*)&p_buffer[P_L_VOICES_OFFSET]) #define P_L_VOICES__MONO 0 #define P_L_VOICES__DUO 1 #define P_L_VOICES__POLY_4 2 #define P_L_VOICES__POLY_5 3 #define P_L_VOICES__POLY_6 4 #define P_L_VOICES__POLY_8 5 #define P_L_VOICES__POLY_10 6 #define P_L_VOICES__POLY_16 7 int id_offset = 1;
There are two ways to modify a component parameter. They are:
- Direct control using a component address
- Indirect control through a unit
Component Address
Every component has its unique address in order to exchange its parameter via data bus. A component address is a 4 byte integer like IP address. Thus, you have two ways of address management — static and dynamic.
Unit
*** TODO: rename unit to union
Analog 3 will have many parameters that may cause difficulty in control them. Unit helps simplifying synth manipulation.
A unit is a virtual component that consists of zero or more components or units. It has its own control parameter. A unit is a component on data bus. Thus it has a component address. Updating the unit parameter causes changes in its sub-components at once.
An example usage of units is building polyphonic perspective. When you build a four-voice polyphonic synthesizer, you make a unit for each synth parameter (such as VCF cutoff frequency) and recruits corresponding physical components of the four voices. Its representation looks following:
{ "name": "cutoff frequency", "type": "KnobUnit", "members": [ "voice1.vcf.cutoff_frequency", "voice2.vcf.cutoff_frequency", "voice3.vcf.cutoff_frequency", "voice4.vcf.cutoff_frequency" ] }
Another example is bundling multiple parameters to simplify manipulation.
{ "name": "sharpness", "type": "KnobUnit", "members": [ "envelope_generator.hit.intensity", "envelope_generator.attack.time", "envelope_generator.1st_decay.time" ] }