1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
SPDX-License-Identifier: GPL-3.0-or-later
Copyright © 2024 Mike Robeson [dijksterhuis]
*/
use crateDefaults;
use ;
use ;
use from_fn;
pub
pub
/// # Trig Repeats, Conditions and Offsets
///
/// This is ..... a slightly frustrating implementation.
///
/// There is a 64 length array consisting of a pair of bytes.
/// Each pair of elements actually represents three different types of data...
/// Trig Counts and Trig Conditions use the two bytes independently,
/// so they're easier to explain first.
///
/// After that -- see the section on Trig Offsets below, which makes everything more complicated.
///
/// ## Trig Counts and Trig Conditions
///
/// Trig Counts and Trig Conditions data is interleaved for each trig.
/// For Trig position 1, array index 0 is the count value and array index 1 is the Trig
/// Condition.
///
/// For trig counts (1st byte), the value (zero-indexed) is multiplied by 32.
/// - 8 trig counts (7 repeats) --> 7 * 3 = 224
/// - 4 trig counts (3 repeats) -- 3 * 32 = 96
/// - 1 trig counts (0 repeats) -- 0 * 32 = 0
///
/// For conditionals, see the `TrigCondition` enum and associated traits for more details.
/// The maximum value for a Trig Condition byte is 64.
///
/// ```rust
/// // no trig micro-timings at all
/// [
/// // trig 1
/// [
/// 0, // trig counts (number)
/// 0, // trig condition (enum rep)
/// ],
/// // trig 2
/// [
/// 224, // trig counts (max value)
/// 64, // trig condition (max value)
/// ],
/// // trig 3
/// [
/// 32, // trig counts (minimum non-zero value)
/// 1, // trig condition (minimum non-zero value)
/// ],
/// // ... and so on
/// ];
/// ```
///
/// ## Trig Offsets
///
/// Trig Offset values use both of these interleaved bytes on top of the
/// trig repeat and trig condition values... Which makes life more complex
/// and somewhat frustrating.
///
/// Inspected values
/// - -23/384 -> 1st byte 20, 2nd byte 128
/// - -1/32 -> 1st byte 26, 2nd byte 0
/// - -1/64 -> 1st byte 29, 2nd byte 0
/// - -1/128 -> 1st byte 30, 2nd byte 128
/// - 1/128 -> 1st byte 1, 2nd byte 128
/// - 1/64 -> 1st byte 3, 2nd byte 0
/// - 1/32 -> 1st byte 6, 2nd byte 0
/// - 23/384 -> 1st byte 11, 2nd byte 128
///
/// ### 1st byte
/// The 1st byte only has 31 possible values: 255 - 224 (trig count max) = 31.
/// So it makes sense sort of that this is a mask? I guess?
///
/// ### 2nd byte
/// From what I can tell, the second offset byte is either 0 or 128.
/// So a 2nd byte for an offset adjusted trig with a `8:8` trig condition is either
/// - 128 + 64 = 192
/// - 0 + 64 = 64
///
/// So you will need to a `x.rem_euclid(128)` somewhere if you want to parse this.
///
/// Combining the trig offset with trig count and trig conditions, we end up with
/// ```rust
/// [
/// // trig one, -23/384 offset with 1x trig count and None condition
/// [
/// 20, // 20 + (32 * 0)
/// 128, // 128 + 0
/// ],
/// // trig two, -23/384 offset with 2x trig count and Fill condition
/// [
/// 52, // 20 + (32 * 1)
/// 129, // 128 + 1
/// ],
/// // trig three, -23/384 offset with 3x trig count and Fill condition
/// [
/// 84, // 20 + (32 * 2)
/// 129, // 128 + 1
/// ],
/// // trig four, -23/384 offset with 3x trig count and NotFill condition
/// [
/// 84, // 20 + (32 * 2)
/// 130, // 128 + 2
/// ],
/// // trig five, +1/32 offset with 2x trig count and Fill condition
/// [
/// 38, // 6 + (32 * 1)
/// 1, // 0 + 1
/// ],
/// // trig six, +1/32 offset with 3x trig count and Fill condition
/// [
/// 70, // 6 + (32 * 2)
/// 1, // 0 + 1
/// ],
/// // trig seven, +1/32 offset with 3x trig count and NotFill condition
/// [
/// 70, // 6 + (32 * 2)
/// 2, // 0 + 2
/// ],
/// // .... and so on
/// ];
/// ```
///
/// ### Extending pages and offsets
///
/// If you have a trig offset on Trig 1 with only one pattern page activated,
/// the trig offsets for Trig 1 are replicated over the relevant trig
/// positions for each first trig in the inactive pages in this array.
///
/// So, for a 1/32 offset on trig 1 with only one page active, you get the
/// following values showing up in this array:
/// - pair of bytes at array index 15 -> 1/32
/// - pair of bytes at array index 31 -> 1/32
/// - pair of bytes at array index 47 -> 1/32
///
/// This does not happen for offset values at any other trig position
/// (from what I can tell in my limited testing -- trig values 2-4 and 9-11
/// inclusive are not replicated in the same way).
///
/// This 'replicating trig offset values over unused pages' behaviour does
/// not happen for trig counts. I haven't tested whether this applies to trig
/// conditions yet.
///
/// It seems that this behaviour could be to make sure the octatrack plays
/// correctly offset trigs when you extend a page live, i.e. when extending
/// a one-page pattern to a two-page pattern, if there is a negative offset
/// value there the octatrack will need to play the offset trig before the
/// first page has completed.
///
/// Or it could be a bug :shrug: