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