DX Android Android-1 Voice Generation
The following text is an AI-generated(!) analysis of the Android-1 algorithm in the DX Android source code. I did, however, manually verify key points, such as the stated random value ranges of each parameter, before re-implementing the algorithm. I did also verify the PMS control-flow defect mentioned below, and fixed it to represent the original developer’s intent. I did not verify each referenced source code file line number. As with all AI-generated content, treat it with caution, and if in doubt check for yourself.
Android-1 is DX Android's "intelligent" random voice generator. Its assembly
entry point is droid in 11.S. It generates a new DX7 voice that favors
audible, conventionally useful results rather than choosing every parameter
independently. In particular, it ensures each operator envelope reaches a
maximum level of 99, assigns stronger output levels to carrier operators, and
limits carrier frequencies to low musical ratios.
The routine operates on DX Android's 160-byte workspace voice format:
| Byte range | Contents | Android-1 behavior |
|---|---|---|
0..125 |
Six 21-byte operator records, stored in DX7 order: operator 6 down to operator 1 | Regenerated |
126..144 |
The expanded 19-byte DX7 global-parameter section | Regenerated |
145..159 |
DX Android function parameters, such as mono/poly, pitch bend, portamento, and controller assignments | Unchanged |
The 145 DX7 voice bytes can then be sent as an individual-voice dump or repacked into the 128-byte-per-voice format used by a DX7 bank dump.
Random-number conventions
11.S implements helpers named random1, random3, random7, random31,
random63, and random99. Their names state their inclusive ranges:
| Helper | Result range |
|---|---|
random1 |
0..1 |
random3 |
0..3 |
random7 |
0..7 |
random31 |
0..31 |
random63 |
0..63 |
random99 |
0..99 |
They derive values from GEMDOS's random-number function and reject values outside a desired non-power-of-two range. Consequently, the intended results within each listed range are uniformly distributed.
Per-operator generation
Android-1 executes the following work six times, once for each 21-byte operator record. The record offsets below are relative to that operator's first byte; the packed records appear in operator order 6, 5, 4, 3, 2, 1.
Envelope generator
| Relative byte | Parameter | Generation |
|---|---|---|
0 |
EG rate 1 | 99 with probability 1/2; otherwise uniformly 68..99 |
1 |
EG rate 2 | Uniformly 0..99 |
2 |
EG rate 3 | Uniformly 0..99 |
3 |
EG rate 4 | Uniformly 36..99 |
4..6 |
EG levels 1, 2, 3 | Three independent values from 0..99, each increased by 99 - max(L1, L2, L3) |
7 |
EG level 4 | Always 0 |
The level adjustment is important. The generator first chooses raw L1, L2,
and L3, finds their maximum, and raises all three by the amount required for
that maximum to become 99. Thus at least one of L1--L3 is always 99, while the
differences between the three generated levels remain intact. Setting L4 to
zero makes every operator envelope terminate at silence.
Keyboard scaling and sensitivities
Android-1 disables keyboard scaling and velocity response:
| Relative byte | Parameter | Value |
|---|---|---|
8 |
Keyboard-scaling breakpoint | 0 |
9 |
Keyboard-scaling left depth | 0 |
10 |
Keyboard-scaling right depth | 0 |
11 |
Keyboard-scaling left curve | 0 |
12 |
Keyboard-scaling right curve | 0 |
13 |
Keyboard rate scaling | 0 |
14 |
Amplitude-modulation sensitivity | 0 with probability 1/2; otherwise uniformly 0..3 |
15 |
Velocity sensitivity | 0 |
20 |
Oscillator detune | 7 (DX7 center/no-detune value) |
The apparent AMS distribution has a consequence worth noting: because the random branch can itself return zero, AMS is zero 5/8 of the time, and each of 1, 2, and 3 occurs 1/8 of the time.
Algorithm before output levels
After the initial envelope and sensitivity pass, Android-1 selects the DX7
algorithm at absolute byte 134, uniformly from 0..31. DX7 algorithm
numbers are zero-based inside this workspace, so these values correspond to
the user-visible algorithm numbers 1 through 32.
The dx7algs table in 11.S supplies a six-entry descriptor for the selected
algorithm. Each entry says whether the corresponding packed operator is a
carrier: an operator whose output reaches the audible mixer rather than only
modulating another operator. The selected descriptor controls both output
level and coarse-frequency generation.
Output level and oscillator frequency
| Relative byte | Parameter | Generation |
|---|---|---|
16 |
Output level | Carrier: uniformly 68..99; non-carrier: uniformly 36..99 |
17 |
Oscillator mode | Fixed-frequency mode with probability 1/8; ratio mode with probability 7/8 |
18 |
Coarse frequency | Described below |
19 |
Fine frequency | Fixed mode: uniformly 0..99; ratio mode: 0 |
Carrier output levels are intentionally biased upward, so the algorithm's audible operators are unlikely to be too quiet. Modulators still have fairly high levels, allowing bright or complex spectra without overwhelming the carrier selection.
For a carrier, coarse frequency is calculated as random1 + random1, giving
the following zero-based DX7 coarse-frequency values:
| Value | Probability | DX7 ratio label |
|---|---|---|
0 |
1/4 | 0.5 |
1 |
1/2 | 1 |
2 |
1/4 | 2 |
For a non-carrier, Android-1 first obtains random3. A zero result selects
the wide range 0..31 (probability 1/4); any nonzero result selects 0..7
(probability 3/4). This favors ratios 0.5 through 8 for modulators but
occasionally allows the full DX7 coarse-ratio range. The original comment in
11.S says 66%/33%; the actual random3 branch produces 75%/25%.
When fixed-frequency mode is selected, the coarse-frequency byte is still generated by these carrier/non-carrier rules. The fine-frequency byte becomes fully random. In ratio mode, Android-1 forces fine frequency to zero.
Global DX7 parameters
Pitch envelope
Bytes 126..133 hold pitch EG rates 1--4 and levels 1--4. Android-1 chooses
between two forms:
| Probability | Pitch EG bytes 126..133 |
|---|---|
| 1/8 | Eight independent values, each uniformly 0..99 |
| 7/8 | 99, 99, 99, 99, 50, 50, 50, 50 |
The common value represents a rapid, neutral pitch envelope. The infrequent fully random envelope permits more extreme pitch motion.
Algorithm, feedback, and LFO
| Absolute byte | Parameter | Generation |
|---|---|---|
134 |
Algorithm | Uniformly 0..31 |
135 |
Feedback | Uniformly 0..7 |
136 |
Operator sync | Uniformly 0..1 |
137 |
LFO speed | Uniformly 0..99 |
138 |
LFO delay | Always 0 |
139 |
LFO pitch-modulation depth | Uniformly 0..99 |
140 |
LFO amplitude-modulation depth | Uniformly 0..99 |
141 |
LFO sync | Uniformly 0..1 |
142 |
LFO waveform | Uniformly 0..5 |
143 |
LFO pitch-modulation sensitivity (PMS) | Always 0 in the shipped code |
144 |
Transpose | Always 24, which is C3 |
PMS control-flow defect
The comments claim that pitch-modulation sensitivity should be zero 75% of
the time and randomly selected from 0..7 the other 25%. The source calls
random3 but then tests register d7, rather than d0, which holds the
newly generated random result:
bsr random3 ; 75% of the time PMS is zero
tst.b d7
bne .25
bsr random7 ; 25% of the time PMS is totally random
move.b d0,(a6)+
bra .26
.25 clr.b (a6)+
At this point d7 is still the counter from the preceding coarse-frequency
loop. That loop increments it from 0 through 5 and exits with d7 == 6.
Therefore tst.b d7 is always nonzero, bne .25 is always taken, and byte
143 is always cleared. The random-PMS path is unreachable in the assembled
program.
Replacing tst.b d7 with tst.b d0 would implement the documented
distribution: d0 == 0 takes the random 0..7 path (1/4), and the other
three results clear PMS (3/4).
Function parameters remain untouched
Android-1 returns immediately after setting transpose. It does not write the
editor-specific function bytes 145..159. Those bytes retain their current
values, including mono/poly mode, pitch-bend settings, portamento controls,
and controller ranges/assignments. This is deliberate and documented in
11.S as "function parameters are unchanged."
Source locations
| Source | Relevant content |
|---|---|
11.S:130-319 |
droid, the Android-1 generator |
11.S:1109-1125 |
dx7algs, algorithm carrier descriptors |
11.S:760-782 |
Random-number helper routines |
ED(M-Z).S:496-654 |
parminfo, packed workspace parameter definitions |
14.S:119-169 |
The 160-byte workspace-to-DX7 SysEx voice conversion |