@swiftbrowser/native 0.19.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +34 -11
  2. package/dist/blob.d.ts +85 -11
  3. package/dist/blob.d.ts.map +1 -1
  4. package/dist/blob.js +184 -34
  5. package/dist/blob.js.map +1 -1
  6. package/dist/bridge.d.ts +33 -2
  7. package/dist/bridge.d.ts.map +1 -1
  8. package/dist/bridge.js.map +1 -1
  9. package/dist/fetch.d.ts +19 -11
  10. package/dist/fetch.d.ts.map +1 -1
  11. package/dist/fetch.js +105 -41
  12. package/dist/fetch.js.map +1 -1
  13. package/dist/hostRequests.d.ts +3 -1
  14. package/dist/hostRequests.d.ts.map +1 -1
  15. package/dist/hostRequests.js +47 -6
  16. package/dist/hostRequests.js.map +1 -1
  17. package/dist/index.d.ts +1 -2
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/runtime.js +1 -1
  22. package/dist/runtime.js.map +1 -1
  23. package/dist/webSocket.d.ts.map +1 -1
  24. package/dist/webSocket.js +13 -1
  25. package/dist/webSocket.js.map +1 -1
  26. package/package.json +3 -3
  27. package/src/blob.ts +215 -34
  28. package/src/bridge.ts +27 -2
  29. package/src/fetch.ts +99 -41
  30. package/src/hostRequests.ts +62 -8
  31. package/src/index.ts +1 -2
  32. package/src/runtime.ts +1 -1
  33. package/src/webSocket.ts +10 -1
  34. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ProgramNode.swift +185 -24
  35. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ScopeView.swift +79 -0
  36. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Machine.swift +2075 -213
  37. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Program.swift +407 -16
  38. package/swift/Packages/SwiftBrowserShader/Package.swift +31 -0
  39. package/swift/Packages/SwiftBrowserShader/README.md +45 -0
  40. package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderRenderer.swift +103 -0
  41. package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderView.swift +168 -0
  42. package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShaderCore/ShaderProps.swift +120 -0
  43. package/swift/Sources/SwiftBrowserNative/Host/BodyStream.swift +166 -0
  44. package/swift/Sources/SwiftBrowserNative/Host/FilesBridge.swift +141 -7
  45. package/swift/Sources/SwiftBrowserNative/Host/HostBridge.swift +47 -1
  46. package/swift/Sources/SwiftBrowserNative/Host/HostRequestBridge.swift +98 -29
  47. package/swift/Sources/SwiftBrowserNative/Runtime/NativeFunctions.swift +1 -1
  48. package/swift/Sources/SwiftBrowserNative/Runtime/ViewRegistry.swift +57 -0
  49. package/swift/Sources/SwiftBrowserNative/Views/ElementView.swift +11 -7
  50. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Controls.swift +28 -6
  51. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Drawing.swift +378 -0
  52. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Navigation.swift +15 -10
  53. package/swift/Sources/SwiftBrowserNative/Views/Kinds/PopTap.swift +31 -28
  54. package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +142 -0
  55. package/swift/Sources/SwiftBrowserProtocol/Drawing.swift +306 -0
  56. package/swift/Sources/SwiftBrowserProtocol/Props.swift +5 -2
  57. package/swift/Sources/SwiftBrowserProtocol/RendererEvent.swift +24 -3
  58. package/swift/Sources/SwiftBrowserProtocol/Style.swift +87 -0
  59. package/swift/Sources/SwiftBrowserProtocol/TextChange.swift +17 -0
  60. package/wasm/SwiftBrowserNative.wasm +2 -2
  61. package/dist/native.d.ts +0 -19
  62. package/dist/native.d.ts.map +0 -1
  63. package/dist/native.js +0 -17
  64. package/dist/native.js.map +0 -1
  65. package/src/native.ts +0 -35
  66. package/swift/Sources/SwiftBrowserNative/Runtime/NativeRegistry.swift +0 -53
@@ -17,21 +17,121 @@ import Foundation
17
17
  /// else a free one, else the oldest released, else the oldest; a lane's gate
18
18
  /// is up from its note on to its note off, or under the sustain pedal until
19
19
  /// the pedal lifts, and it sounds while the gate is up and then while any
20
- /// `adsr` in the program has not finished its release.
20
+ /// `adsr` in the program has not finished its release. A `mono` or `legato`
21
+ /// program is one voice playing the newest of the notes held (up to 16
22
+ /// remembered): releasing it goes back to the one before, and `mono` starts
23
+ /// its envelopes over at every change of note, `legato` only when no note
24
+ /// was held.
25
+ ///
26
+ /// The transport: `tempo` beats a minute (120 until set) and `beat`, which
27
+ /// advances every frame from 0 (or where `seek` puts it), sounding or not.
28
+ /// An event given a beat waits for it (up to 1024 at once) and applies on
29
+ /// the frame nearest it, the block split there, so a sequencer that
30
+ /// schedules ahead plays in time; one whose beat has passed applies at the
31
+ /// next block. All notes off and all sound off drop what waits.
32
+ ///
33
+ /// Memory is sized in `init` and never after: the wavetables (built from
34
+ /// their harmonics with the JavaScript machine's inverse FFT, 2048 samples a
35
+ /// frame at ten band-limited levels), a ring buffer per voice for each
36
+ /// `delay`, the shapes' points and the samples' audio.
37
+ ///
38
+ /// With a `master` stage, the voices' sum goes through it once a frame, in
39
+ /// lane 0, whether or not a voice sounds; its state and its builtins' are
40
+ /// reset only in `init` and on `reset`.
41
+ ///
42
+ /// Block processing: a block runs in chunks of 16 frames, each instruction over every frame of the chunk for every
43
+ /// sounding lane, but for a stream's serial part (feedback through state, which it schedules when it loads the
44
+ /// program), which runs frame by frame within the chunk. Unlike the JavaScript machine's, a register holds a frame's lanes side by side,
45
+ /// then the next frame's, so the loops over lanes stay vector loops; the results are the same.
21
46
  public final class DSPMachine: @unchecked Sendable {
22
47
  public let program: DSPProgram
23
48
  public let sampleRate: Float
24
49
 
25
50
  private static let lanes = 16
51
+ /// Frames a chunk has: each instruction runs over a chunk's frames together (block processing).
52
+ private static let frames = 16
53
+ /// The registers, each `width` values: a chunk's frames one after another, each its lanes (as many as the
54
+ /// program has voices) side by side, so an instruction runs over lanes as a SIMD vector and a builtin's state
55
+ /// follows its lanes; a state register's value is its lane's at the first frame.
26
56
  private let registers: UnsafeMutablePointer<Float>
57
+ private let width: Int
27
58
  private let state: UnsafeMutablePointer<Float>
28
59
  private let stateCount: Int
29
60
  private let noise: UnsafeMutablePointer<UInt32>
30
61
  private let noiseCount: Int
62
+ /// The streams as they run: what reads a gated region's result reading what the region gives it, `sample` and
63
+ /// `master` without the regions that are off, and scheduled (their parts that run frame by frame, in instructions).
31
64
  private let blockCode: UnsafeMutablePointer<Int32>
32
65
  private let blockCount: Int
66
+ /// How many of `blockCode`'s instructions run (those the streams were last made with).
67
+ private var blockRunning: Int
33
68
  private let sampleCode: UnsafeMutablePointer<Int32>
34
- private let sampleCount: Int
69
+ private var sampleCount: Int
70
+ private let masterCode: UnsafeMutablePointer<Int32>
71
+ private var masterCount: Int
72
+ private var sampleSerial: Range<Int> = 0..<0
73
+ private var masterSerial: Range<Int> = 0..<0
74
+ /// The streams as the program has them, each instruction's region, each region's parameter, parent and results
75
+ /// (register, then what it reads as on and off, as offsets), whether each is on (2 before the program loads), and
76
+ /// per register what a result reads as now (-1 for a register that is none).
77
+ private let fullBlock: UnsafeMutablePointer<Int32>
78
+ private let fullSample: UnsafeMutablePointer<Int32>
79
+ private let fullSampleCount: Int
80
+ private let fullMaster: UnsafeMutablePointer<Int32>
81
+ private let fullMasterCount: Int
82
+ private let sampleGates: [Int32]?
83
+ private let masterGates: [Int32]?
84
+ private let groupParameters: [Int]
85
+ private let groupParents: [Int]
86
+ private let groupOutputs: [[(register: Int, on: Int32, off: Int32)]]
87
+ private var groupOn: [UInt8]
88
+ /// What runs: per instruction of the block, sample and master streams as the program has them, whether something
89
+ /// the outputs need reads it, now and when the streams were last made; per register, whether it is read, now and
90
+ /// then; whether the streams have been made; and each instruction's builtin (-1 for none). An instruction that comes
91
+ /// to run again starts over (its builtin, the state it writes), as one in a region coming on does.
92
+ private let aliveNow: [UnsafeMutablePointer<UInt8>]
93
+ private let aliveBefore: [UnsafeMutablePointer<UInt8>]
94
+ private let readNow: UnsafeMutablePointer<UInt8>
95
+ private let readBefore: UnsafeMutablePointer<UInt8>
96
+ private var made = false
97
+ private let streamInstances: [[Int32]]
98
+ private let streamCounts: [Int]
99
+ private let renameTable: UnsafeMutablePointer<Int32>
100
+ /// Scratch for making a stream again: its instructions before they are scheduled, a byte an instruction (touches
101
+ /// state, computed from it, needed by it) and a byte a register (tainted, needed).
102
+ private let staging: UnsafeMutablePointer<Int32>
103
+ private let instructionMarks: UnsafeMutablePointer<UInt8>
104
+ private let registerMarks: UnsafeMutablePointer<UInt8>
105
+ /// Choices: each one's parameter, register and options (as offsets); the option each reads as now (the last
106
+ /// choices with no cycle), the ones last asked for (so choices refused for a cycle are not tried every block),
107
+ /// and the ones asked for this block.
108
+ private let choiceParameters: [Int]
109
+ private let choiceRegisters: [Int]
110
+ private let choiceOptions: [[Int32]]
111
+ private let choiceScales: [Double]
112
+ private var choiceUsed: [Int]
113
+ private var choiceAsked: [Int]
114
+ private var choiceNow: [Int]
115
+ /// The voicing's parameters (nil: the program's own), and the voices and mode last played with (-1 before the
116
+ /// first block), so a turn lets go of what no longer plays.
117
+ private let voicesParameter: Int?
118
+ private let modeParameter: Int?
119
+ private var voicedLimit = -1
120
+ private var voicedMode = 0
121
+ /// Scratch for ordering a stream when choices change (made only when there are choices): the ordered sample and
122
+ /// master streams; per register its writer (not state) or the first of its writers (state, then linked by
123
+ /// instruction) and where its readers start in `readers`; per instruction how many it waits on; and a heap.
124
+ private let orderedSample: UnsafeMutablePointer<Int32>
125
+ private let orderedMaster: UnsafeMutablePointer<Int32>
126
+ private let writerOf: UnsafeMutablePointer<Int32>
127
+ private let stateWriterFirst: UnsafeMutablePointer<Int32>
128
+ private let stateWriterNext: UnsafeMutablePointer<Int32>
129
+ private let readerStarts: UnsafeMutablePointer<Int32>
130
+ private let readers: UnsafeMutablePointer<Int32>
131
+ private let waiting: UnsafeMutablePointer<Int32>
132
+ private let heap: UnsafeMutablePointer<Int32>
133
+ /// Per instance: whether the master stage runs it.
134
+ private let instanceMaster: [Bool]
35
135
  /// Each instance's builtin and where its state starts (in floats, lanes included; a noise instance's in `noise`).
36
136
  private let instanceKinds: [DSPBuiltin]
37
137
  private let instanceOffsets: [Int]
@@ -42,6 +142,60 @@ public final class DSPMachine: @unchecked Sendable {
42
142
  private let parameterIndices: [String: Int]
43
143
  private let targets: UnsafeMutablePointer<Float>
44
144
  private var snapped = true
145
+ /// Whether a parameter was set since the last block: only then can a region, a choice or the voicing turn.
146
+ private var retargeted = false
147
+ /// Each wavetable's samples (level, 2048 samples, each its frames side by side), how many floats, and its frames;
148
+ /// each its own, so one is replaced (`replaceTable`) by swapping it whole. (`Slots`, not arrays replaced in place,
149
+ /// which Swift would check for exclusive access at every read as it renders.)
150
+ private let tablePointers: Slots<UnsafeMutablePointer<Float>>
151
+ private let tableSizes: Slots<Int>
152
+ private let tableFrames: Slots<Int>
153
+ private let tableCount: Int
154
+ /// Envelopes' curves: the registers (as offsets) their attack, decay and release exponents are read from, three a
155
+ /// curve; an `adsr` names its curve in slot 11.
156
+ private let curveRegisters: [Int]
157
+ /// The delays' samples: each instance's buffer per lane, a power of two long; by instance, where it starts and its length.
158
+ private let delaySamples: UnsafeMutablePointer<Float>
159
+ private let delaySampleCount: Int
160
+ private let delayBases: [Int]
161
+ private let delayLengths: [Int]
162
+ /// Each shape's points and how many; each sample's audio, its length, its frames a frame at this rate, and its
163
+ /// spray (20 ms) in frames. Each its own, so one is replaced by swapping it whole.
164
+ private let shapePointers: Slots<UnsafeMutablePointer<Float>>
165
+ private let shapeLengths: Slots<Int>
166
+ private let samplePointers: Slots<UnsafeMutablePointer<Float>>
167
+ private let sampleLengths: Slots<Int>
168
+ private let sampleRatios: Slots<Float>
169
+ private let sampleSprays: Slots<UInt32>
170
+ /// `modsum`'s route lists, each with room for `DSPProgram.routesMax` registers (so one is replaced in place), as
171
+ /// register offsets (× `width`): a source's, then its amount's, pair after pair; list i starts at
172
+ /// `i × routesMax` and is `routeCounts[i]` long.
173
+ private let routeRegisters: UnsafeMutablePointer<Int>
174
+ /// Whether each route's register is state (one value a lane, not one a frame).
175
+ private let routeState: UnsafeMutablePointer<Bool>
176
+ private let routeCounts: UnsafeMutablePointer<Int>
177
+ private let routeCount: Int
178
+ /// Whether a route list was replaced since the last block: the streams are made again.
179
+ private var rerouted = false
180
+ /// Per register: whether it is a parameter, state, or one a machine renames (a choice's, a region's result).
181
+ private let parameterMask: UnsafeMutablePointer<UInt8>
182
+ private let stateMask: UnsafeMutablePointer<UInt8>
183
+ private let renamedMask: UnsafeMutablePointer<UInt8>
184
+ /// Folding: each register's value where it is a constant (NaN where not), an offset holding 0 (-1 for none), the
185
+ /// registers nothing may fold away (outputs, state, curves, the master stage's inputs) and those a route list names
186
+ /// now, and the registers folded when the streams were last made (their renaming undone before the next).
187
+ private let constantValues: UnsafeMutablePointer<Float>
188
+ /// Each parameter's range, by its register (NaN elsewhere): a clamp it is inside folds away.
189
+ private let parameterLowest: UnsafeMutablePointer<Float>
190
+ private let parameterHighest: UnsafeMutablePointer<Float>
191
+ private let zeroOffset: Int32
192
+ private let pinnedMask: UnsafeMutablePointer<UInt8>
193
+ private let routedMask: UnsafeMutablePointer<UInt8>
194
+ private let folded: UnsafeMutablePointer<Int32>
195
+ private var foldedCount = 0
196
+ /// Re-rating: per register whether it may change from frame to frame, and the sample stream's instructions kept.
197
+ private let changing: UnsafeMutablePointer<UInt8>
198
+ private let keptSample: UnsafeMutablePointer<Int32>
45
199
 
46
200
  private let laneNote: UnsafeMutablePointer<Int32>
47
201
  private let laneGate: UnsafeMutablePointer<Float>
@@ -50,31 +204,60 @@ public final class DSPMachine: @unchecked Sendable {
50
204
  private let laneActive: UnsafeMutablePointer<Float>
51
205
  private let laneAge: UnsafeMutablePointer<Double>
52
206
  private let trigger: UnsafeMutablePointer<Float>
207
+ /// The master stage's trigger: counts the notes (as the voice a mono program's starts over at).
208
+ private let masterTrigger: UnsafeMutablePointer<Float>
209
+ /// The lane of the newest note, for a master stage that reads it (-1 before the first).
210
+ private var newestLane = -1
53
211
  private var age: Double = 0
54
212
  private var pedal = false
55
213
  private var bend: Double = 0
214
+ private var tempo: Double = 120
215
+ private var beat: Double = 0
216
+ /// A mono program's held notes, oldest first.
217
+ private let stack: UnsafeMutablePointer<Int32>
218
+ private var stackCount = 0
219
+ /// Events waiting for their beat, soonest first: the beat, then the kind (note on, note off, controller,
220
+ /// bend) and two values.
221
+ private static let queueCapacity = 1024
222
+ private let queueBeat: UnsafeMutablePointer<Double>
223
+ private let queueEvent: UnsafeMutablePointer<Int32>
224
+ private var queueCount = 0
56
225
 
57
226
  public init(program: DSPProgram, sampleRate: Double) {
58
227
  let L = Self.lanes
59
228
  self.program = program
60
229
  self.sampleRate = Float(sampleRate)
61
- registers = .allocate(capacity: program.registers * L)
62
- registers.initialize(repeating: 0, count: program.registers * L)
230
+ let W = program.voices * Self.frames
231
+ width = W
232
+ registers = .allocate(capacity: program.registers * W)
233
+ registers.initialize(repeating: 0, count: program.registers * W)
234
+ let stateRegisters = Set(program.state.map(\.register))
235
+ var isMaster = [Bool](repeating: false, count: program.instances.count)
236
+ if let master = program.master {
237
+ var pc = 0
238
+ while pc < master.code.count {
239
+ let op = DSPOpcode(rawValue: master.code[pc])!
240
+ if op.builtin != nil { isMaster[Int(master.code[pc + 2 + op.arity])] = true }
241
+ pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
242
+ }
243
+ }
244
+ instanceMaster = isMaster
63
245
  var kinds: [DSPBuiltin] = []
64
246
  var offsets: [Int] = []
65
247
  var envelopes: [Int] = []
66
248
  var filters: [Int] = []
67
249
  var words = 0
68
250
  var noises = 0
69
- for builtin in program.instances {
251
+ for (i, builtin) in program.instances.enumerated() {
70
252
  kinds.append(builtin)
71
253
  if builtin == .noise {
72
254
  offsets.append(noises * L)
73
255
  noises += 1
74
256
  } else {
75
257
  offsets.append(words * L)
76
- if builtin == .adsr { envelopes.append(words * L) }
77
- if builtin == .lowpass || builtin == .highpass || builtin == .bandpass { filters.append(words * L) }
258
+ if builtin == .adsr && !isMaster[i] { envelopes.append(words * L) }
259
+ // The filters' integrators, a one-pole's, a DC blocker's and a comb's loop.
260
+ if [.lowpass, .highpass, .bandpass, .onepole, .dcblock, .comb].contains(builtin) { filters.append(words * L) }
78
261
  words += builtin.words
79
262
  }
80
263
  }
@@ -88,19 +271,195 @@ public final class DSPMachine: @unchecked Sendable {
88
271
  noiseCount = max(1, noises) * L
89
272
  noise = .allocate(capacity: noiseCount)
90
273
  noise.initialize(repeating: 1, count: noiseCount)
91
- (blockCode, blockCount) = Self.decode(program.block, offsets: offsets)
92
- (sampleCode, sampleCount) = Self.decode(program.sample, offsets: offsets)
274
+ let tables = program.tables.isEmpty ? [(Self.zeros(DSPProgram.tableLevels * DSPProgram.tableFrame), DSPProgram.tableLevels * DSPProgram.tableFrame)] : program.tables.map { Self.levels(frames: $0.frames, cosines: $0.cosines) }
275
+ tablePointers = Slots(tables.map(\.0))
276
+ tableSizes = Slots(tables.map(\.1))
277
+ tableFrames = Slots(program.tables.isEmpty ? [1] : program.tables.map(\.frames.count))
278
+ tableCount = program.tables.count
279
+ shapePointers = Slots(program.shapes.isEmpty ? [Self.zeros(2)] : program.shapes.map { Self.copy($0.points) })
280
+ shapeLengths = Slots(program.shapes.isEmpty ? [2] : program.shapes.map(\.points.count))
281
+ samplePointers = Slots(program.samples.isEmpty ? [Self.zeros(2)] : program.samples.map { Self.copy($0.data) })
282
+ sampleLengths = Slots(program.samples.isEmpty ? [2] : program.samples.map(\.data.count))
283
+ sampleRatios = Slots(program.samples.isEmpty ? [1] : program.samples.map { Float($0.rate / Double(Float(sampleRate))) })
284
+ let routesMax = DSPProgram.routesMax
285
+ routeCount = program.routes.count
286
+ routeCounts = .allocate(capacity: Swift.max(1, routeCount))
287
+ routeCounts.initialize(repeating: 0, count: Swift.max(1, routeCount))
288
+ for (i, list) in program.routes.enumerated() { routeCounts[i] = list.count }
289
+ routeRegisters = .allocate(capacity: Swift.max(1, routeCount * routesMax))
290
+ routeRegisters.initialize(repeating: 0, count: Swift.max(1, routeCount * routesMax))
291
+ routeState = .allocate(capacity: Swift.max(1, routeCount * routesMax))
292
+ routeState.initialize(repeating: false, count: Swift.max(1, routeCount * routesMax))
293
+ for (i, list) in program.routes.enumerated() {
294
+ for (k, r) in list.enumerated() {
295
+ routeRegisters[i * routesMax + k] = r * W
296
+ routeState[i * routesMax + k] = stateRegisters.contains(r)
297
+ }
298
+ }
299
+ let registerCount = program.registers
300
+ func mask() -> UnsafeMutablePointer<UInt8> {
301
+ let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: registerCount)
302
+ pointer.initialize(repeating: 0, count: registerCount)
303
+ return pointer
304
+ }
305
+ parameterMask = mask()
306
+ stateMask = mask()
307
+ renamedMask = mask()
308
+ pinnedMask = mask()
309
+ routedMask = mask()
310
+ changing = mask()
311
+ for p in program.parameters { parameterMask[p.register] = 1 }
312
+ for r in stateRegisters { stateMask[r] = 1 }
313
+ for c in program.choices { renamedMask[c.register] = 1 }
314
+ for g in program.groups { for o in g.outputs { renamedMask[o.register] = 1 } }
315
+ for r in [program.output, program.outputRight ?? program.output] + (program.master?.outputs ?? []) + (program.master?.inputs ?? []) { pinnedMask[r] = 1 }
316
+ for r in stateRegisters { pinnedMask[r] = 1 }
317
+ for c in program.curves { for r in [c.attack, c.decay, c.release] { pinnedMask[r] = 1 } }
318
+ for list in program.routes { for r in list { routedMask[r] = 1 } }
319
+ constantValues = .allocate(capacity: registerCount)
320
+ constantValues.initialize(repeating: .nan, count: registerCount)
321
+ parameterLowest = .allocate(capacity: registerCount)
322
+ parameterLowest.initialize(repeating: .nan, count: registerCount)
323
+ parameterHighest = .allocate(capacity: registerCount)
324
+ parameterHighest.initialize(repeating: .nan, count: registerCount)
325
+ for p in program.parameters {
326
+ parameterLowest[p.register] = p.min
327
+ parameterHighest[p.register] = p.max
328
+ }
329
+ var zero: Int32 = -1
93
330
  for constant in program.constants {
94
- (registers + constant.register * L).update(repeating: constant.value, count: L)
331
+ constantValues[constant.register] = constant.value
332
+ if constant.value == 0 && zero < 0 { zero = Int32(constant.register * W) }
333
+ }
334
+ zeroOffset = zero
335
+ sampleSprays = Slots(program.samples.isEmpty ? [1] : program.samples.map { UInt32(Swift.max(1, ($0.rate * 0.02).rounded(.down))) })
336
+ // Each delay's buffer: its longest time (a constant register) at this sample rate, rounded up to a power of
337
+ // two, per voice (the master stage's, once).
338
+ let constantValues = Dictionary(program.constants.map { ($0.register, $0.value) }, uniquingKeysWith: { _, last in last })
339
+ var bases = [Int](repeating: 0, count: program.instances.count)
340
+ var lengths = [Int](repeating: 0, count: program.instances.count)
341
+ var delayTotal = 0
342
+ for code in [program.sample, program.master?.code ?? []] {
343
+ var pc = 0
344
+ while pc < code.count {
345
+ let op = DSPOpcode(rawValue: code[pc])!
346
+ if let longestAt = op.longest {
347
+ let instance = Int(code[pc + 2 + op.arity])
348
+ let longest = Double(Swift.min(Swift.max(constantValues[Int(code[pc + 1 + longestAt])] ?? 1, 0), 2))
349
+ var length = 4
350
+ while Double(length) < (longest * Double(Float(sampleRate))).rounded(.up) + 2 { length *= 2 }
351
+ bases[instance] = delayTotal
352
+ lengths[instance] = length
353
+ delayTotal += length * (isMaster[instance] ? 1 : L)
354
+ }
355
+ pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
356
+ }
357
+ }
358
+ delayBases = bases
359
+ delayLengths = lengths
360
+ delaySampleCount = Swift.max(1, delayTotal)
361
+ delaySamples = .allocate(capacity: delaySampleCount)
362
+ delaySamples.initialize(repeating: 0, count: delaySampleCount)
363
+ curveRegisters = program.curves.flatMap { [$0.attack * W, $0.decay * W, $0.release * W] }
364
+ let curves = Dictionary(program.curves.enumerated().map { ($1.instance, $0 + 1) }, uniquingKeysWith: { _, last in last })
365
+ (fullBlock, blockCount) = Self.decode(program.block, width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
366
+ (fullSample, fullSampleCount) = Self.decode(program.sample, width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
367
+ (fullMaster, fullMasterCount) = Self.decode(program.master?.code ?? [], width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
368
+ // Each made again (renamed, compacted, scheduled) when the program has loaded, and when a region turns.
369
+ // The block stream's room takes the sample stream's too: what no longer changes frame by frame moves there.
370
+ blockCode = .allocate(capacity: max(12, (blockCount + fullSampleCount) * 12))
371
+ blockCode.initialize(repeating: 0, count: max(12, (blockCount + fullSampleCount) * 12))
372
+ blockCode.update(from: fullBlock, count: blockCount * 12)
373
+ keptSample = .allocate(capacity: max(12, fullSampleCount * 12))
374
+ folded = .allocate(capacity: max(1, blockCount + fullSampleCount + fullMasterCount))
375
+ blockRunning = blockCount
376
+ sampleCode = .allocate(capacity: max(12, fullSampleCount * 12))
377
+ sampleCode.update(from: fullSample, count: max(12, fullSampleCount * 12))
378
+ masterCode = .allocate(capacity: max(12, fullMasterCount * 12))
379
+ masterCode.update(from: fullMaster, count: max(12, fullMasterCount * 12))
380
+ (sampleCount, masterCount) = (fullSampleCount, fullMasterCount)
381
+ sampleGates = program.sampleGates
382
+ masterGates = program.masterGates
383
+ groupParameters = program.groups.map(\.parameter)
384
+ groupParents = program.groups.map(\.parent)
385
+ groupOutputs = program.groups.map { $0.outputs.map { (register: $0.register, on: Int32($0.on * W), off: Int32($0.off * W)) } }
386
+ groupOn = [UInt8](repeating: 2, count: program.groups.count)
387
+ streamInstances = [program.block, program.sample, program.master?.code ?? []].map { code in
388
+ var instances: [Int32] = []
389
+ var pc = 0
390
+ while pc < code.count, let op = DSPOpcode(rawValue: code[pc]) {
391
+ instances.append(op.builtin != nil ? code[pc + 2 + op.arity] : -1)
392
+ pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
393
+ }
394
+ return instances
395
+ }
396
+ streamCounts = [blockCount, fullSampleCount, fullMasterCount]
397
+ aliveNow = [blockCount, fullSampleCount, fullMasterCount].map { count in
398
+ let marks = UnsafeMutablePointer<UInt8>.allocate(capacity: Swift.max(1, count))
399
+ marks.initialize(repeating: 0, count: Swift.max(1, count))
400
+ return marks
401
+ }
402
+ aliveBefore = [blockCount, fullSampleCount, fullMasterCount].map { count in
403
+ let marks = UnsafeMutablePointer<UInt8>.allocate(capacity: Swift.max(1, count))
404
+ marks.initialize(repeating: 0, count: Swift.max(1, count))
405
+ return marks
406
+ }
407
+ readNow = .allocate(capacity: program.registers)
408
+ readNow.initialize(repeating: 0, count: program.registers)
409
+ readBefore = .allocate(capacity: program.registers)
410
+ readBefore.initialize(repeating: 0, count: program.registers)
411
+ renameTable = .allocate(capacity: program.registers)
412
+ renameTable.initialize(repeating: -1, count: program.registers)
413
+ let longest = max(1, blockCount, fullSampleCount, fullMasterCount)
414
+ staging = .allocate(capacity: longest * 12)
415
+ staging.initialize(repeating: 0, count: longest * 12)
416
+ instructionMarks = .allocate(capacity: longest)
417
+ instructionMarks.initialize(repeating: 0, count: longest)
418
+ registerMarks = .allocate(capacity: program.registers)
419
+ registerMarks.initialize(repeating: 0, count: program.registers)
420
+ choiceParameters = program.choices.map(\.parameter)
421
+ choiceRegisters = program.choices.map(\.register)
422
+ choiceOptions = program.choices.map { $0.options.map { Int32($0 * W) } }
423
+ choiceScales = program.choices.map(\.scale)
424
+ choiceUsed = [Int](repeating: -1, count: program.choices.count)
425
+ choiceAsked = choiceUsed
426
+ choiceNow = choiceUsed
427
+ voicesParameter = program.voicingVoices
428
+ modeParameter = program.voicingMode
429
+ // The most registers an instruction of the sample or master stream reads: its operands, and a modsum's routes.
430
+ let ordering = !program.choices.isEmpty || !program.routes.isEmpty
431
+ // A route list may be replaced by one as long as any may be.
432
+ let longestRoute = program.routes.isEmpty ? 0 : routesMax
433
+ func readsIn(_ code: UnsafeMutablePointer<Int32>, _ count: Int) -> Int {
434
+ (0..<count).reduce(0) { sum, i in
435
+ let op = DSPOpcode(rawValue: code[i * 12])!
436
+ return sum + op.arity + (op == .modsum ? longestRoute : 0)
437
+ }
95
438
  }
96
- registers.update(repeating: Float(sampleRate), count: L)
439
+ let readCount = ordering ? Swift.max(readsIn(fullSample, fullSampleCount), readsIn(fullMaster, fullMasterCount)) : 0
440
+ let orderable = ordering ? longest : 1
441
+ orderedSample = .allocate(capacity: Swift.max(12, fullSampleCount * 12))
442
+ orderedMaster = .allocate(capacity: Swift.max(12, fullMasterCount * 12))
443
+ writerOf = .allocate(capacity: ordering ? program.registers : 1)
444
+ writerOf.initialize(repeating: -1, count: ordering ? program.registers : 1)
445
+ stateWriterFirst = .allocate(capacity: ordering ? program.registers : 1)
446
+ stateWriterFirst.initialize(repeating: -1, count: ordering ? program.registers : 1)
447
+ stateWriterNext = .allocate(capacity: orderable)
448
+ readerStarts = .allocate(capacity: ordering ? program.registers + 1 : 1)
449
+ readers = .allocate(capacity: Swift.max(1, readCount))
450
+ waiting = .allocate(capacity: orderable)
451
+ heap = .allocate(capacity: orderable)
452
+ for constant in program.constants {
453
+ (registers + constant.register * W).update(repeating: constant.value, count: W)
454
+ }
455
+ registers.update(repeating: Float(sampleRate), count: W)
97
456
  parameterRegisters = program.parameters.map(\.register)
98
457
  parameterRanges = program.parameters.map { ($0.min, $0.max) }
99
458
  parameterIndices = Dictionary(program.parameters.enumerated().map { ($1.name, $0) }, uniquingKeysWith: { first, _ in first })
100
459
  targets = .allocate(capacity: max(1, program.parameters.count))
101
460
  for (i, parameter) in program.parameters.enumerated() {
102
461
  targets[i] = parameter.defaultValue
103
- (registers + parameter.register * L).update(repeating: parameter.defaultValue, count: L)
462
+ (registers + parameter.register * W).update(repeating: parameter.defaultValue, count: W)
104
463
  }
105
464
  laneNote = .allocate(capacity: L)
106
465
  laneNote.initialize(repeating: -1, count: L)
@@ -116,37 +475,684 @@ public final class DSPMachine: @unchecked Sendable {
116
475
  laneAge.initialize(repeating: 0, count: L)
117
476
  trigger = .allocate(capacity: L)
118
477
  trigger.initialize(repeating: 0, count: L)
478
+ masterTrigger = .allocate(capacity: 1)
479
+ masterTrigger.initialize(to: 1)
480
+ stack = .allocate(capacity: L)
481
+ stack.initialize(repeating: 0, count: L)
482
+ queueBeat = .allocate(capacity: Self.queueCapacity)
483
+ queueBeat.initialize(repeating: 0, count: Self.queueCapacity)
484
+ queueEvent = .allocate(capacity: Self.queueCapacity * 3)
485
+ queueEvent.initialize(repeating: 0, count: Self.queueCapacity * 3)
119
486
  for lane in 0..<L { resetLane(lane) }
487
+ resetMaster()
488
+ // The streams as they run: the regions its parameters turn on, scheduled.
489
+ turnRegions(loading: true)
490
+ revoice()
120
491
  }
121
492
 
122
493
  deinit {
123
- for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger] { pointer.deallocate() }
494
+ for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger, masterTrigger] { pointer.deallocate() }
495
+ for slots in [shapePointers, samplePointers, tablePointers] {
496
+ for i in 0..<slots.count { slots[i].deallocate() }
497
+ slots.deallocate()
498
+ }
499
+ for slots in [tableSizes, tableFrames, shapeLengths, sampleLengths] { slots.deallocate() }
500
+ sampleRatios.deallocate()
501
+ sampleSprays.deallocate()
124
502
  noise.deallocate()
503
+ routeRegisters.deallocate()
504
+ routeCounts.deallocate()
505
+ routeState.deallocate()
506
+ for pointer in [parameterMask, stateMask, renamedMask, pinnedMask, routedMask, changing] { pointer.deallocate() }
507
+ constantValues.deallocate()
508
+ parameterLowest.deallocate()
509
+ parameterHighest.deallocate()
510
+ keptSample.deallocate()
511
+ folded.deallocate()
512
+ delaySamples.deallocate()
125
513
  blockCode.deallocate()
126
514
  sampleCode.deallocate()
515
+ masterCode.deallocate()
516
+ fullBlock.deallocate()
517
+ fullSample.deallocate()
518
+ fullMaster.deallocate()
519
+ renameTable.deallocate()
520
+ staging.deallocate()
521
+ instructionMarks.deallocate()
522
+ registerMarks.deallocate()
523
+ for pointer in aliveNow + aliveBefore + [readNow, readBefore] { pointer.deallocate() }
524
+ for pointer in [orderedSample, orderedMaster, writerOf, stateWriterFirst, stateWriterNext, readerStarts, readers, waiting, heap] { pointer.deallocate() }
127
525
  laneNote.deallocate()
526
+ stack.deallocate()
527
+ queueBeat.deallocate()
528
+ queueEvent.deallocate()
128
529
  laneHeld.deallocate()
129
530
  laneAge.deallocate()
130
531
  }
131
532
 
132
- /// Instructions at a stride of 8 (op, destination, five operands, state offset), registers as offsets into the file.
133
- private static func decode(_ code: [Int32], offsets: [Int]) -> (UnsafeMutablePointer<Int32>, Int) {
533
+ /// Instructions at a stride of 12 (op, destination, five operands, state offset, which of slots 1 … 6 are state
534
+ /// registers as bits, then a delay line's buffer: where it starts and its length, then an envelope's curve, 1 up,
535
+ /// 0 for none), registers as offsets into the file. With how many there are.
536
+ /// Gated regions and choices: a region is on while its parameter is set above 0.5 and the region around it is on;
537
+ /// a choice reads as the option its parameter names. When either changes (or the program loads), the streams are
538
+ /// made again: without the regions that are off, with what reads a region's result or a choice reading what it
539
+ /// gives, without what nothing the outputs need reads (an option not chosen), ordered so what a choice reads comes
540
+ /// first, and scheduled. Into buffers made when the program loaded: nothing is allocated.
541
+ private func turnRegions(loading: Bool, force: Bool = false) {
542
+ var changed = loading || force
543
+ for g in 0..<groupParameters.count {
544
+ let parent = groupParents[g]
545
+ let on: UInt8 = (parent < 0 || groupOn[parent] == 1) && targets[groupParameters[g]] > 0.5 ? 1 : 0
546
+ if on != groupOn[g] {
547
+ groupOn[g] = on
548
+ changed = true
549
+ }
550
+ }
551
+ for c in 0..<choiceParameters.count {
552
+ let value = Float((Double(targets[choiceParameters[c]]) * choiceScales[c]).rounded())
553
+ let last = choiceOptions[c].count - 1
554
+ choiceNow[c] = value.isNaN ? 0 : value <= 0 ? 0 : value >= Float(last) ? last : Int(value)
555
+ if choiceNow[c] != choiceAsked[c] { changed = true }
556
+ }
557
+ guard changed else { return }
558
+ for c in 0..<choiceNow.count { choiceAsked[c] = choiceNow[c] }
559
+ // The choices asked for; if they would make a cycle, the last that did not (with the regions as they are now);
560
+ // and on loading, if even those would, the program's own order.
561
+ if make(choiceNow, sort: true) {
562
+ for c in 0..<choiceNow.count { choiceUsed[c] = choiceNow[c] }
563
+ } else if loading || !make(choiceUsed, sort: true) {
564
+ _ = make(loading ? choiceNow : choiceUsed, sort: false)
565
+ }
566
+ if loading { for c in 0..<choiceNow.count { choiceUsed[c] = choiceNow[c] } }
567
+ }
568
+
569
+ /// The streams made again for the regions as they are and the choices `chosen`; false (nothing made) on a cycle.
570
+ private func make(_ chosen: [Int], sort: Bool) -> Bool {
571
+ // What was folded last time reads as itself again, until folded again below.
572
+ for i in 0..<foldedCount { renameTable[Int(folded[i])] = -1 }
573
+ foldedCount = 0
574
+ var results = choiceRegisters.count
575
+ for g in groupOutputs.indices {
576
+ for output in groupOutputs[g] { renameTable[output.register] = groupOn[g] == 1 ? output.on : output.off }
577
+ results += groupOutputs[g].count
578
+ }
579
+ for c in 0..<choiceRegisters.count { renameTable[choiceRegisters[c]] = choiceOptions[c][chosen[c]] }
580
+ // A result or a choice may read as another (nested regions, a choice of results): followed, at most once each.
581
+ let W = Int32(width)
582
+ func resolve(_ register: Int) {
583
+ var target = renameTable[register]
584
+ var steps = 0
585
+ while steps < results, renameTable[Int(target / W)] >= 0 {
586
+ target = renameTable[Int(target / W)]
587
+ steps += 1
588
+ }
589
+ renameTable[register] = target
590
+ }
591
+ for g in groupOutputs.indices { for output in groupOutputs[g] { resolve(output.register) } }
592
+ for register in choiceRegisters { resolve(register) }
593
+ fold()
594
+ liveness()
595
+ // Ordered where something may read what comes after it (a choice of a value made later, a route from a source
596
+ // made later); kept apart from `staging`, which the next stream is compacted into.
597
+ let ordering = sort && (!choiceRegisters.isEmpty || routeCount > 0)
598
+ let samples = compact(fullSample, fullSampleCount, aliveNow[1])
599
+ if ordering {
600
+ guard order(samples, into: orderedSample) else { return false }
601
+ } else {
602
+ orderedSample.update(from: staging, count: samples * 12)
603
+ }
604
+ let masters = compact(fullMaster, fullMasterCount, aliveNow[2])
605
+ if ordering {
606
+ guard order(masters, into: orderedMaster) else { return false }
607
+ } else {
608
+ orderedMaster.update(from: staging, count: masters * 12)
609
+ }
610
+ revive()
611
+ blockRunning = compact(fullBlock, blockCount, aliveNow[0])
612
+ blockCode.update(from: staging, count: blockRunning * 12)
613
+ // What in the sample stream no longer changes frame by frame runs once a block (as machine.ts moves it).
614
+ sampleCount = rerate(samples, from: orderedSample)
615
+ sampleSerial = reschedule(sampleCount, from: keptSample, into: sampleCode)
616
+ masterCount = masters
617
+ masterSerial = reschedule(masters, from: orderedMaster, into: masterCode)
618
+ return true
619
+ }
620
+
621
+ /// Folds what turned constant, before what runs is found (as machine.ts folds it): an instruction that comes to
622
+ /// one of its operands (x + 0, x × 1, a mix at 0 or 1, a select of a constant, a mov) or to 0 (x × 0, an empty
623
+ /// route list) is passed over, what reads it reading that instead. Never one whose register is an output, state, a
624
+ /// curve or in a route list.
625
+ private func fold() {
626
+ let W = Int32(width)
627
+ let zero = zeroOffset
628
+ func pass(_ code: UnsafeMutablePointer<Int32>, _ count: Int) {
629
+ for i in 0..<count {
630
+ let slot = code + i * 12
631
+ let d = Int(slot[1] / W)
632
+ if pinnedMask[d] != 0 || routedMask[d] != 0 { continue }
633
+ let op = slot[0]
634
+ let arity = DSPOpcode(rawValue: op)!.arity
635
+ func operand(_ k: Int) -> Int32 {
636
+ guard k < arity else { return -1 }
637
+ let t = renameTable[Int(slot[2 + k] / W)]
638
+ return t >= 0 ? t : slot[2 + k]
639
+ }
640
+ let a = operand(0)
641
+ let b = operand(1)
642
+ let c = operand(2)
643
+ func value(_ offset: Int32) -> Float { offset >= 0 ? constantValues[Int(offset / W)] : .nan }
644
+ var to: Int32 = -1
645
+ switch op {
646
+ case 0: to = a
647
+ case 1: to = value(a) == 0 ? b : value(b) == 0 ? a : -1
648
+ case 2: to = value(b) == 0 ? a : -1
649
+ case 3: to = value(a) == 1 ? b : value(b) == 1 ? a : value(a) == 0 || value(b) == 0 ? zero : -1
650
+ case 58: to = value(a) == 0 || value(b) == 0 ? c : value(c) == 0 && value(a) == 1 ? b : value(c) == 0 && value(b) == 1 ? a : -1
651
+ case 59: to = value(c) == 0 ? zero : value(c) == 1 && value(a) == 0 ? b : value(c) == 1 && value(b) == 0 ? a : -1
652
+ case 30: to = a == b ? b : !value(a).isNaN ? (value(a) != 0 ? b : c) : -1
653
+ // A parameter clamped to a range its own is inside.
654
+ case 31: to = a >= 0 && value(b) <= parameterLowest[Int(a / W)] && parameterHighest[Int(a / W)] <= value(c) ? a : -1
655
+ case 32: to = value(c) == 0 || a == b ? a : value(c) == 1 ? b : -1
656
+ case 57:
657
+ let index = Self.index(registers[Int(slot[2])], routeCount)
658
+ to = index >= routeCount || routeCounts[index] == 0 ? zero : -1
659
+ default: break
660
+ }
661
+ if to < 0 || Int(to / W) == d { continue }
662
+ renameTable[d] = to
663
+ folded[foldedCount] = Int32(d)
664
+ foldedCount += 1
665
+ }
666
+ }
667
+ pass(fullBlock, blockCount)
668
+ pass(fullSample, fullSampleCount)
669
+ pass(fullMaster, fullMasterCount)
670
+ }
671
+
672
+ /// The `count` instructions of the sample stream at `source`, split (as machine.ts splits them): those that read
673
+ /// only what is set once a block (no state, nothing worked out frame by frame, not the beat) and are not builtins,
674
+ /// onto the end of `blockCode`; the rest into `keptSample`, in their order. How many stayed.
675
+ private func rerate(_ count: Int, from source: UnsafeMutablePointer<Int32>) -> Int {
676
+ let W = Int32(width)
677
+ changing[6] = 1
678
+ var kept = 0
679
+ for i in 0..<count {
680
+ let slot = source + i * 12
681
+ let d = Int(slot[1] / W)
682
+ var still = DSPOpcode(rawValue: slot[0])!.builtin == nil && stateMask[d] == 0
683
+ if still { forEachRead(slot) { r, state in if state || changing[r] != 0 { still = false } } }
684
+ if still {
685
+ (blockCode + blockRunning * 12).update(from: slot, count: 12)
686
+ blockRunning += 1
687
+ } else {
688
+ changing[d] = 1
689
+ (keptSample + kept * 12).update(from: slot, count: 12)
690
+ kept += 1
691
+ }
692
+ }
693
+ // The marks back to none, for the next time.
694
+ for i in 0..<kept { changing[Int(keptSample[i * 12 + 1] / W)] = 0 }
695
+ changing[6] = 0
696
+ return kept
697
+ }
698
+
699
+ /// Replaces route list `index` from the next block with `list`'s registers (a source's, then its amount's, pair
700
+ /// after pair, as floats), copied in place (as machine.ts `replaceRoutes`): the streams are made again. False where
701
+ /// there is no such list, or an amount is not a parameter, a register is past the program's or one renamed, or the
702
+ /// list is past `DSPProgram.routesMax`.
703
+ public func replaceRoutes(_ index: Int, registers list: DSPBuffer) -> Bool {
704
+ guard index >= 0, index < routeCount, list.count % 2 == 0, list.count <= DSPProgram.routesMax else { return false }
705
+ for k in 0..<list.count {
706
+ let x = list.pointer[k]
707
+ guard x >= 0, x < Float(program.registers), x == x.rounded(.down) else { return false }
708
+ let r = Int(x)
709
+ guard renamedMask[r] == 0, k % 2 == 0 || parameterMask[r] != 0 else { return false }
710
+ }
711
+ let start = index * DSPProgram.routesMax
712
+ for k in 0..<list.count {
713
+ let r = Int(list.pointer[k])
714
+ routeRegisters[start + k] = r * width
715
+ routeState[start + k] = stateMask[r] != 0
716
+ }
717
+ routeCounts[index] = list.count
718
+ routedMask.update(repeating: 0, count: program.registers)
719
+ for i in 0..<routeCount {
720
+ for k in 0..<routeCounts[i] { routedMask[routeRegisters[i * DSPProgram.routesMax + k] / width] = 1 }
721
+ }
722
+ rerouted = true
723
+ return true
724
+ }
725
+
726
+
727
+ /// The `count` instructions in `staging` into `out`, ordered so each comes after what writes what it reads (not
728
+ /// state), and a state register's readers before what writes it (they read the frame before's); program order
729
+ /// where neither says (as machine.ts orders). False on a cycle.
730
+ private func order(_ count: Int, into out: UnsafeMutablePointer<Int32>) -> Bool {
731
+ let W = Int32(width)
732
+ let registerCount = program.registers
733
+ for i in 0..<count {
734
+ let slot = staging + i * 12
735
+ let d = Int(slot[1] / W)
736
+ if (slot[8] >> 1) & 1 == 1 {
737
+ stateWriterNext[i] = stateWriterFirst[d]
738
+ stateWriterFirst[d] = Int32(i)
739
+ } else {
740
+ writerOf[d] = Int32(i)
741
+ }
742
+ waiting[i] = 0
743
+ }
744
+ // Each register's readers (reading it not as state), in program order: counted, summed to where each ends,
745
+ // then placed back to front so each ends where it starts.
746
+ readerStarts.update(repeating: 0, count: registerCount + 1)
747
+ for i in 0..<count { forEachRead(staging + i * 12) { r, state in if !state { readerStarts[r] += 1 } } }
748
+ var total: Int32 = 0
749
+ for r in 0..<registerCount {
750
+ total += readerStarts[r]
751
+ readerStarts[r] = total
752
+ }
753
+ readerStarts[registerCount] = total
754
+ for i in stride(from: count - 1, through: 0, by: -1) {
755
+ forEachRead(staging + i * 12) { r, state in
756
+ guard !state else { return }
757
+ readerStarts[r] -= 1
758
+ readers[Int(readerStarts[r])] = Int32(i)
759
+ }
760
+ }
761
+ for i in 0..<count {
762
+ forEachRead(staging + i * 12) { r, state in
763
+ if state {
764
+ var w = stateWriterFirst[r]
765
+ while w >= 0 {
766
+ if Int(w) != i { waiting[Int(w)] += 1 }
767
+ w = stateWriterNext[Int(w)]
768
+ }
769
+ } else if writerOf[r] >= 0, Int(writerOf[r]) != i {
770
+ waiting[i] += 1
771
+ }
772
+ }
773
+ }
774
+ // The ready instructions, least first (a binary heap), so program order holds where nothing else decides.
775
+ var size = 0
776
+ func push(_ i: Int32) {
777
+ var k = size
778
+ heap[k] = i
779
+ size += 1
780
+ while k > 0, heap[(k - 1) / 2] > heap[k] {
781
+ (heap[k], heap[(k - 1) / 2]) = (heap[(k - 1) / 2], heap[k])
782
+ k = (k - 1) / 2
783
+ }
784
+ }
785
+ func pop() -> Int {
786
+ let top = heap[0]
787
+ size -= 1
788
+ heap[0] = heap[size]
789
+ var k = 0
790
+ while true {
791
+ let l = 2 * k + 1
792
+ var m = k
793
+ if l < size, heap[l] < heap[m] { m = l }
794
+ if l + 1 < size, heap[l + 1] < heap[m] { m = l + 1 }
795
+ if m == k { break }
796
+ (heap[k], heap[m]) = (heap[m], heap[k])
797
+ k = m
798
+ }
799
+ return Int(top)
800
+ }
801
+ func done(_ j: Int) {
802
+ waiting[j] -= 1
803
+ if waiting[j] == 0 { push(Int32(j)) }
804
+ }
805
+ for i in 0..<count where waiting[i] == 0 { push(Int32(i)) }
806
+ var placed = 0
807
+ while size > 0 {
808
+ let i = pop()
809
+ let slot = staging + i * 12
810
+ (out + placed * 12).update(from: slot, count: 12)
811
+ placed += 1
812
+ forEachRead(slot) { r, state in
813
+ guard state else { return }
814
+ var w = stateWriterFirst[r]
815
+ while w >= 0 {
816
+ if Int(w) != i { done(Int(w)) }
817
+ w = stateWriterNext[Int(w)]
818
+ }
819
+ }
820
+ let d = Int(slot[1] / W)
821
+ if (slot[8] >> 1) & 1 == 0, Int(writerOf[d]) == i {
822
+ for k in Int(readerStarts[d])..<Int(readerStarts[d + 1]) where Int(readers[k]) != i { done(Int(readers[k])) }
823
+ }
824
+ }
825
+ // The tables back to none, for the next time.
826
+ for i in 0..<count {
827
+ let d = Int(staging[i * 12 + 1] / W)
828
+ writerOf[d] = -1
829
+ stateWriterFirst[d] = -1
830
+ }
831
+ return placed == count
832
+ }
833
+
834
+ /// An envelope's curve exponent as read: held to 1/16 … 16, 1 for NaN (as machine.ts reads it).
835
+ @inline(__always) private static func exponent(_ x: Float) -> Double {
836
+ x >= 0.0625 ? Double(x <= 16 ? x : 16) : x < 0.0625 ? 0.0625 : 1
837
+ }
838
+
839
+ /// Each register the instruction at `slot` reads (its operands, an envelope's curves, and a modsum's routes), and
840
+ /// whether it is state.
841
+ private func forEachRead(_ slot: UnsafeMutablePointer<Int32>, _ body: (Int, Bool) -> Void) {
842
+ let W = Int32(width)
843
+ let op = DSPOpcode(rawValue: slot[0])!
844
+ for k in 0..<op.arity { body(Int(slot[2 + k] / W), (slot[8] >> (2 + k)) & 1 == 1) }
845
+ if op == .adsr, slot[11] > 0 {
846
+ let curve = Int(slot[11]) - 1
847
+ for k in 0..<3 { body(curveRegisters[curve * 3 + k] / width, false) }
848
+ }
849
+ if op == .modsum {
850
+ let index = Self.index(registers[Int(slot[2])], routeCount)
851
+ if index < routeCount {
852
+ let start = index * DSPProgram.routesMax
853
+ for k in start..<(start + routeCounts[index]) { body(routeRegisters[k] / width, routeState[k]) }
854
+ }
855
+ }
856
+ }
857
+
858
+ /// What runs, into `aliveNow` and `readNow`, with what reads a result or a choice reading what `renameTable` says:
859
+ /// from the outputs back, each instruction outside a region that is off whose register something running reads,
860
+ /// and what it reads (a state register read, what writes it). Again until nothing more runs, since a choice or
861
+ /// state may read what comes after (as machine.ts finds it).
862
+ private func liveness() {
863
+ let W = Int32(width)
864
+ readNow.update(repeating: 0, count: program.registers)
865
+ readNow[program.output] = 1
866
+ if let right = program.outputRight { readNow[right] = 1 }
867
+ for r in program.master?.outputs ?? [] { readNow[r] = 1 }
868
+ for s in 0..<3 { aliveNow[s].update(repeating: 0, count: streamCounts[s]) }
869
+ /// One pass over a stream, back to front: whether anything more runs.
870
+ func sweep(_ code: UnsafeMutablePointer<Int32>, _ count: Int, _ gates: [Int32]?, _ marks: UnsafeMutablePointer<UInt8>) -> Bool {
871
+ var more = false
872
+ for i in stride(from: count - 1, through: 0, by: -1) {
873
+ let slot = code + i * 12
874
+ guard marks[i] == 0, readNow[Int(slot[1] / W)] != 0 else { continue }
875
+ if let gates, gates[i] >= 0, groupOn[Int(gates[i])] == 0 { continue }
876
+ marks[i] = 1
877
+ more = true
878
+ forEachRead(slot) { r, _ in
879
+ let renamed = renameTable[r]
880
+ readNow[renamed >= 0 ? Int(renamed / W) : r] = 1
881
+ }
882
+ }
883
+ return more
884
+ }
885
+ var more = true
886
+ while more {
887
+ more = sweep(fullMaster, fullMasterCount, masterGates, aliveNow[2])
888
+ more = sweep(fullSample, fullSampleCount, sampleGates, aliveNow[1]) || more
889
+ more = sweep(fullBlock, blockCount, nil, aliveNow[0]) || more
890
+ }
891
+ }
892
+
893
+ /// What comes to run again (it did not when the streams were last made) starts over: a builtin as when a voice
894
+ /// starts, a state register at its first value. Nothing does when the program loads. Then what runs now is what ran.
895
+ private func revive() {
896
+ let counts = streamCounts
897
+ if made {
898
+ for s in 0..<3 {
899
+ for i in 0..<counts[s] where aliveNow[s][i] != 0 && aliveBefore[s][i] == 0 && streamInstances[s][i] >= 0 {
900
+ let instance = Int(streamInstances[s][i])
901
+ if instanceMaster[instance] { resetInstance(instance, 0) } else { for l in 0..<program.voices { resetInstance(instance, l) } }
902
+ }
903
+ }
904
+ for entry in program.state where readNow[entry.register] != 0 && readBefore[entry.register] == 0 {
905
+ if entry.master { registers[entry.register * width] = entry.initial } else { for l in 0..<program.voices { registers[entry.register * width + l] = entry.initial } }
906
+ }
907
+ }
908
+ for s in 0..<3 { aliveBefore[s].update(from: aliveNow[s], count: counts[s]) }
909
+ readBefore.update(from: readNow, count: program.registers)
910
+ made = true
911
+ }
912
+
913
+ /// A stream's instructions that run (`alive`), their operands renamed, into `staging`: how many instructions.
914
+ private func compact(_ code: UnsafeMutablePointer<Int32>, _ count: Int, _ alive: UnsafeMutablePointer<UInt8>) -> Int {
915
+ let W = Int32(width)
916
+ var kept = 0
917
+ for i in 0..<count {
918
+ if alive[i] == 0 { continue }
919
+ let at = code + i * 12
920
+ let slot = staging + kept * 12
921
+ slot.update(from: at, count: 12)
922
+ for k in 0..<DSPOpcode(rawValue: at[0])!.arity {
923
+ let r = renameTable[Int(at[2 + k] / W)]
924
+ if r >= 0 { slot[2 + k] = r }
925
+ }
926
+ kept += 1
927
+ }
928
+ return kept
929
+ }
930
+
931
+ /// A stream's schedule over the `count` instructions at `source`, into `out`: those reading or writing state, and
932
+ /// those both computed from state and needed by it this frame, run frame by frame (the serial part, returned); what
933
+ /// they need comes before, what needs them after; program order kept within each part (as machine.ts schedules).
934
+ private func reschedule(_ count: Int, from source: UnsafeMutablePointer<Int32>, into out: UnsafeMutablePointer<Int32>) -> Range<Int> {
935
+ let W = Int32(width)
936
+ let touches: UInt8 = 1, downstream: UInt8 = 2, upstream: UInt8 = 4
937
+ let tainted: UInt8 = 1, needed: UInt8 = 2
938
+ for i in 0..<count {
939
+ let slot = source + i * 12
940
+ var marks: UInt8 = (slot[8] >> 1) & 1 == 1 ? touches : 0
941
+ var fromState = false
942
+ forEachRead(slot) { r, state in
943
+ if state { marks |= touches }
944
+ if registerMarks[r] & tainted != 0 { fromState = true }
945
+ }
946
+ if marks & touches != 0 || fromState {
947
+ marks |= downstream
948
+ if (slot[8] >> 1) & 1 == 0 { registerMarks[Int(slot[1] / W)] |= tainted }
949
+ }
950
+ instructionMarks[i] = marks
951
+ }
952
+ for i in stride(from: count - 1, through: 0, by: -1) {
953
+ let slot = source + i * 12
954
+ guard instructionMarks[i] & touches != 0 || registerMarks[Int(slot[1] / W)] & needed != 0 else { continue }
955
+ instructionMarks[i] |= upstream
956
+ forEachRead(slot) { r, state in if !state { registerMarks[r] |= needed } }
957
+ }
958
+ var kept = 0
959
+ var from = 0
960
+ var to = 0
961
+ for part in 0..<3 {
962
+ if part == 1 { from = kept }
963
+ if part == 2 { to = kept }
964
+ for i in 0..<count {
965
+ let marks = instructionMarks[i]
966
+ let serial = marks & touches != 0 || (marks & downstream != 0 && marks & upstream != 0)
967
+ guard (part == 0 && !serial && marks & downstream == 0) || (part == 1 && serial) || (part == 2 && !serial && marks & downstream != 0) else { continue }
968
+ (out + kept * 12).update(from: source + i * 12, count: 12)
969
+ kept += 1
970
+ }
971
+ }
972
+ // The marks back to none, for the next time.
973
+ for i in 0..<count {
974
+ let slot = source + i * 12
975
+ registerMarks[Int(slot[1] / W)] = 0
976
+ forEachRead(slot) { r, _ in registerMarks[r] = 0 }
977
+ }
978
+ return from..<to
979
+ }
980
+
981
+ private static func decode(
982
+ _ code: [Int32], width: Int, state: Set<Int>, offsets: [Int], delays: (bases: [Int], lengths: [Int]), curves: [Int: Int]
983
+ ) -> (UnsafeMutablePointer<Int32>, Int) {
134
984
  var out: [Int32] = []
135
985
  var pc = 0
136
986
  while pc < code.count {
137
987
  let op = DSPOpcode(rawValue: code[pc])!
138
- var slot = [Int32](repeating: 0, count: 8)
988
+ var slot = [Int32](repeating: 0, count: 12)
139
989
  slot[0] = op.rawValue
140
- slot[1] = code[pc + 1] * Int32(lanes)
141
- for k in 0..<op.arity { slot[2 + k] = code[pc + 2 + k] * Int32(lanes) }
990
+ for k in 0..<(1 + op.arity) {
991
+ let register = Int(code[pc + 1 + k])
992
+ slot[1 + k] = Int32(register * width)
993
+ if state.contains(register) { slot[8] |= 1 << (1 + k) }
994
+ }
142
995
  if op.builtin != nil { slot[7] = Int32(offsets[Int(code[pc + 2 + op.arity])]) }
996
+ if op == .adsr { slot[11] = Int32(curves[Int(code[pc + 2 + op.arity])] ?? 0) }
997
+ if op.longest != nil {
998
+ let instance = Int(code[pc + 2 + op.arity])
999
+ slot[9] = Int32(delays.bases[instance])
1000
+ slot[10] = Int32(delays.lengths[instance])
1001
+ }
143
1002
  out += slot
144
1003
  pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
145
1004
  }
146
- let pointer = UnsafeMutablePointer<Int32>.allocate(capacity: max(8, out.count))
147
- pointer.initialize(repeating: 0, count: max(8, out.count))
1005
+ let pointer = UnsafeMutablePointer<Int32>.allocate(capacity: max(12, out.count))
1006
+ pointer.initialize(repeating: 0, count: max(12, out.count))
148
1007
  out.withUnsafeBufferPointer { pointer.update(from: $0.baseAddress!, count: out.count) }
149
- return (pointer, out.count / 8)
1008
+ return (pointer, out.count / 12)
1009
+ }
1010
+
1011
+ /// Lists one after another: where each starts and its length.
1012
+ private static func zeros(_ count: Int) -> UnsafeMutablePointer<Float> {
1013
+ let pointer = UnsafeMutablePointer<Float>.allocate(capacity: Swift.max(1, count))
1014
+ pointer.initialize(repeating: 0, count: Swift.max(1, count))
1015
+ return pointer
1016
+ }
1017
+
1018
+ private static func copy(_ values: [Float]) -> UnsafeMutablePointer<Float> {
1019
+ let pointer = zeros(values.count)
1020
+ values.withUnsafeBufferPointer { pointer.update(from: $0.baseAddress!, count: values.count) }
1021
+ return pointer
1022
+ }
1023
+
1024
+ /// A wavetable's samples as the machine reads them (as machine.ts `tableLevels` makes them), off the audio thread,
1025
+ /// for `replaceTable`.
1026
+ public static func tableLevels(frames: [[Float]], cosines: [[Float]]? = nil) -> DSPBuffer {
1027
+ let (pointer, count) = levels(frames: frames, cosines: cosines)
1028
+ return DSPBuffer(taking: pointer, count: count)
1029
+ }
1030
+
1031
+ /// Replaces table `index`'s samples (`tableLevels`) from the next block, swapping them with `levels`, which then
1032
+ /// holds what the machine let go of, to free off the audio thread. False (nothing swapped) where they do not fit.
1033
+ public func replaceTable(_ index: Int, levels: DSPBuffer, frames: Int) -> Bool {
1034
+ guard index >= 0, index < tableCount, frames >= 1, levels.count == frames * DSPProgram.tableLevels * DSPProgram.tableFrame else { return false }
1035
+ var total = frames
1036
+ for i in 0..<tableFrames.count where i != index { total += tableFrames[i] }
1037
+ guard total <= DSPProgram.tableFramesMax else { return false }
1038
+ swap(&tablePointers[index], &levels.pointer)
1039
+ swap(&tableSizes[index], &levels.count)
1040
+ tableFrames[index] = frames
1041
+ return true
1042
+ }
1043
+
1044
+ /// Replaces shape `index`'s points from the next block, swapping them with `points` (as `replaceTable`).
1045
+ public func replaceShape(_ index: Int, points: DSPBuffer) -> Bool {
1046
+ guard index >= 0, index < program.shapes.count, (2...DSPProgram.shapePointsMax).contains(points.count) else { return false }
1047
+ var total = points.count
1048
+ for i in 0..<shapeLengths.count where i != index { total += shapeLengths[i] }
1049
+ guard total <= DSPProgram.shapesPointsMax else { return false }
1050
+ swap(&shapePointers[index], &points.pointer)
1051
+ swap(&shapeLengths[index], &points.count)
1052
+ return true
1053
+ }
1054
+
1055
+ /// Replaces sample `index`'s audio, at `rate` frames a second, from the next block, swapping it with `audio` (as
1056
+ /// `replaceTable`); a sound playing it goes on from where it is, inside the new length.
1057
+ public func replaceSample(_ index: Int, audio: DSPBuffer, rate: Double) -> Bool {
1058
+ guard index >= 0, index < program.samples.count, rate >= 1000, rate <= 384_000, audio.count >= 2 else { return false }
1059
+ var total = audio.count
1060
+ for i in 0..<sampleLengths.count where i != index { total += sampleLengths[i] }
1061
+ guard total <= DSPProgram.samplesMax else { return false }
1062
+ swap(&samplePointers[index], &audio.pointer)
1063
+ swap(&sampleLengths[index], &audio.count)
1064
+ sampleRatios[index] = Float(rate / Double(Float(sampleRate)))
1065
+ sampleSprays[index] = UInt32(Swift.max(1, (rate * 0.02).rounded(.down)))
1066
+ return true
1067
+ }
1068
+
1069
+ /// A table's samples and how many floats: each level one with the harmonics past 512, 256 … dropped, 2048 samples,
1070
+ /// each its frames side by side.
1071
+ private static func levels(frames tableFrames: [[Float]], cosines tableCosines: [[Float]]?) -> (UnsafeMutablePointer<Float>, Int) {
1072
+ let N = DSPProgram.tableFrame
1073
+ let levels = DSPProgram.tableLevels
1074
+ let count = Swift.max(1, tableFrames.count) * levels * N
1075
+ let samples = zeros(count)
1076
+ var cosT = [Double](repeating: 0, count: N / 2)
1077
+ var sinT = [Double](repeating: 0, count: N / 2)
1078
+ for j in 0..<(N / 2) {
1079
+ cosT[j] = Foundation.cos(2 * Double.pi * Double(j) / Double(N))
1080
+ sinT[j] = Foundation.sin(2 * Double.pi * Double(j) / Double(N))
1081
+ }
1082
+ var re = [Double](repeating: 0, count: N)
1083
+ var im = [Double](repeating: 0, count: N)
1084
+ do {
1085
+ let count = tableFrames.count
1086
+ // A level's samples one after another, each its frames side by side: a read between two samples and two
1087
+ // frames is one span of memory.
1088
+ func store(_ level: Int, _ n: Int, _ f: Int) -> Int { (level * N + n) * count + f }
1089
+ for (f, amplitudes) in tableFrames.enumerated() {
1090
+ for level in 0..<levels {
1091
+ let limit = Swift.min(512 >> level, amplitudes.count)
1092
+ if level > 0 && limit == Swift.min(512 >> (level - 1), amplitudes.count) {
1093
+ // No harmonic dropped: the level above's samples.
1094
+ for n in 0..<N { samples[store(level, n, f)] = samples[store(level - 1, n, f)] }
1095
+ continue
1096
+ }
1097
+ for i in 0..<N {
1098
+ re[i] = 0
1099
+ im[i] = 0
1100
+ }
1101
+ // sin(kθ) = (e^{ikθ} − e^{−ikθ}) / 2i
1102
+ if limit >= 1 {
1103
+ for k in 1...limit {
1104
+ let a = Double(amplitudes[k - 1])
1105
+ im[k] = -a / 2
1106
+ im[N - k] = a / 2
1107
+ }
1108
+ // cos(kθ) = (e^{ikθ} + e^{−ikθ}) / 2
1109
+ if let cosines = tableCosines?[f] {
1110
+ for k in 1...limit {
1111
+ let c = Double(cosines[k - 1])
1112
+ re[k] = c / 2
1113
+ re[N - k] = c / 2
1114
+ }
1115
+ }
1116
+ }
1117
+ // Bit reversal, then radix-2 butterflies with e^{+2πij/len}.
1118
+ var j = 0
1119
+ for i in 1..<N {
1120
+ var bit = N >> 1
1121
+ while j & bit != 0 {
1122
+ j ^= bit
1123
+ bit >>= 1
1124
+ }
1125
+ j ^= bit
1126
+ if i < j {
1127
+ re.swapAt(i, j)
1128
+ im.swapAt(i, j)
1129
+ }
1130
+ }
1131
+ var len = 2
1132
+ while len <= N {
1133
+ let half = len >> 1
1134
+ let step = N / len
1135
+ var i = 0
1136
+ while i < N {
1137
+ for k in 0..<half {
1138
+ let wr = cosT[k * step]
1139
+ let wi = sinT[k * step]
1140
+ let xr = re[i + k + half] * wr - im[i + k + half] * wi
1141
+ let xi = re[i + k + half] * wi + im[i + k + half] * wr
1142
+ re[i + k + half] = re[i + k] - xr
1143
+ im[i + k + half] = im[i + k] - xi
1144
+ re[i + k] = re[i + k] + xr
1145
+ im[i + k] = im[i + k] + xi
1146
+ }
1147
+ i += len
1148
+ }
1149
+ len <<= 1
1150
+ }
1151
+ for n in 0..<N { samples[store(level, n, f)] = Float(re[n]) }
1152
+ }
1153
+ }
1154
+ }
1155
+ return (samples, count)
150
1156
  }
151
1157
 
152
1158
  // MARK: Events
@@ -160,15 +1166,161 @@ public final class DSPMachine: @unchecked Sendable {
160
1166
  public func setParameter(at index: Int, _ value: Float) {
161
1167
  guard index >= 0, index < parameterRegisters.count, value.isFinite else { return }
162
1168
  targets[index] = Swift.min(Swift.max(value, parameterRanges[index].min), parameterRanges[index].max)
1169
+ retargeted = true
1170
+ }
1171
+
1172
+ /// The transport's tempo, in beats a minute (1 … 999), from the next block.
1173
+ public func setTempo(_ bpm: Double) {
1174
+ if bpm.isFinite { tempo = Swift.min(Swift.max(bpm, 1), 999) }
1175
+ }
1176
+
1177
+ /// Moves the transport to `beat`.
1178
+ public func seek(toBeat beat: Double) {
1179
+ if beat.isFinite { self.beat = beat }
1180
+ }
1181
+
1182
+ /// Where the transport is, in beats.
1183
+ public var position: Double { beat }
1184
+
1185
+ /// MIDI note on: `velocity` 1 … 127 (0 is a note off); at `atBeat` on the transport, or at the next block. False
1186
+ /// when too many wait.
1187
+ @discardableResult
1188
+ public func noteOn(_ note: Int32, velocity: Int32, atBeat: Double? = nil) -> Bool {
1189
+ if let atBeat { return schedule(atBeat, 0, note, velocity) }
1190
+ start(note, velocity: velocity)
1191
+ return true
1192
+ }
1193
+
1194
+ /// MIDI note off; at `atBeat` on the transport, or at the next block.
1195
+ @discardableResult
1196
+ public func noteOff(_ note: Int32, atBeat: Double? = nil) -> Bool {
1197
+ if let atBeat { return schedule(atBeat, 1, note, 0) }
1198
+ release(note)
1199
+ return true
163
1200
  }
164
1201
 
165
- /// MIDI note on: `velocity` 1 … 127 (0 is a note off).
166
- public func noteOn(_ note: Int32, velocity: Int32) {
1202
+ /// 64 the sustain pedal, 120 all sound off, 123 all notes off (both dropping what waits); at `atBeat`, or at the
1203
+ /// next block.
1204
+ @discardableResult
1205
+ public func controller(_ number: Int32, value: Int32, atBeat: Double? = nil) -> Bool {
1206
+ if let atBeat { return schedule(atBeat, 2, number, value) }
1207
+ if number == 120 || number == 123 { queueCount = 0 }
1208
+ control(number, value: value)
1209
+ return true
1210
+ }
1211
+
1212
+ /// The pitch wheel, 0 … 16383, 8192 centered: ±2 semitones; at `atBeat`, or at the next block.
1213
+ @discardableResult
1214
+ public func pitchBend(_ value: Int32, atBeat: Double? = nil) -> Bool {
1215
+ if let atBeat { return schedule(atBeat, 3, value, 0) }
1216
+ bend = Double(Swift.min(16383, Swift.max(0, value)) - 8192) / 8192 * 2
1217
+ return true
1218
+ }
1219
+
1220
+ /// Puts an event in the queue after those at or before its beat.
1221
+ private func schedule(_ beat: Double, _ kind: Int32, _ a: Int32, _ b: Int32) -> Bool {
1222
+ guard beat.isFinite, queueCount < Self.queueCapacity else { return false }
1223
+ var at = queueCount
1224
+ while at > 0 && queueBeat[at - 1] > beat { at -= 1 }
1225
+ (queueBeat + at + 1).update(from: queueBeat + at, count: queueCount - at)
1226
+ (queueEvent + (at + 1) * 3).update(from: queueEvent + at * 3, count: (queueCount - at) * 3)
1227
+ queueBeat[at] = beat
1228
+ queueEvent[at * 3] = kind
1229
+ queueEvent[at * 3 + 1] = a
1230
+ queueEvent[at * 3 + 2] = b
1231
+ queueCount += 1
1232
+ return true
1233
+ }
1234
+
1235
+ /// Applies what is due: each event whose beat is nearer this frame than the next.
1236
+ private func applyDue(_ step: Double) {
1237
+ while queueCount > 0 && queueBeat[0] < beat + step / 2 {
1238
+ let kind = queueEvent[0]
1239
+ let a = queueEvent[1]
1240
+ let b = queueEvent[2]
1241
+ queueBeat.update(from: queueBeat + 1, count: queueCount - 1)
1242
+ queueEvent.update(from: queueEvent + 3, count: (queueCount - 1) * 3)
1243
+ queueCount -= 1
1244
+ switch kind {
1245
+ case 0: start(a, velocity: b)
1246
+ case 1: release(a)
1247
+ case 2: control(a, value: b)
1248
+ default: pitchBend(a)
1249
+ }
1250
+ }
1251
+ }
1252
+
1253
+ /// Frames to the next waiting event, at most a block's.
1254
+ private func framesToNext(_ step: Double) -> Int {
1255
+ let frames = ((queueBeat[0] - beat) / step).rounded()
1256
+ return frames >= Double(DSPProgram.blockFrames) ? DSPProgram.blockFrames : Swift.max(1, Int(frames))
1257
+ }
1258
+
1259
+ /// The mode notes play in now: the voicing's parameter's, else the program's.
1260
+ private func currentMode() -> DSPProgram.Mode? {
1261
+ guard let p = modeParameter else { return program.mode }
1262
+ let m = targets[p].rounded()
1263
+ return m == 1 ? .mono : m == 2 ? .legato : nil
1264
+ }
1265
+
1266
+ /// How many voices play now: the voicing's parameter's (1 … the program's), else the program's.
1267
+ private func voiceLimit() -> Int {
1268
+ guard let p = voicesParameter else { return program.voices }
1269
+ let n = targets[p].rounded()
1270
+ return n.isNaN || n < 1 ? 1 : n >= Float(program.voices) ? program.voices : Int(n)
1271
+ }
1272
+
1273
+ /// At a block's start, where the voicing turned: the voices past those that play now let go, and the held notes a
1274
+ /// mode keeps start again from the one voice that sounds (as machine.ts does).
1275
+ private func revoice() {
1276
+ let mode = currentMode()
1277
+ let modeIndex = mode == .mono ? 1 : mode == .legato ? 2 : 0
1278
+ let limit = mode != nil ? 1 : voiceLimit()
1279
+ guard limit != voicedLimit || modeIndex != voicedMode else { return }
1280
+ let first = voicedLimit < 0
1281
+ voicedLimit = limit
1282
+ voicedMode = modeIndex
1283
+ if first { return }
1284
+ for l in limit..<Self.lanes {
1285
+ laneGate[l] = 0
1286
+ laneHeld[l] = false
1287
+ }
1288
+ stackCount = 0
1289
+ if mode != nil && laneGate[0] > 0.5 {
1290
+ stack[0] = laneNote[0]
1291
+ stackCount = 1
1292
+ }
1293
+ }
1294
+
1295
+ private func start(_ note: Int32, velocity: Int32) {
167
1296
  if velocity <= 0 {
168
- noteOff(note)
1297
+ release(note)
169
1298
  return
170
1299
  }
171
- let voices = program.voices
1300
+ if let mode = currentMode() {
1301
+ // One voice: the newest note, legato while another is held.
1302
+ unstack(note)
1303
+ if stackCount == Self.lanes {
1304
+ (stack).update(from: stack + 1, count: stackCount - 1)
1305
+ stackCount -= 1
1306
+ }
1307
+ stack[stackCount] = note
1308
+ stackCount += 1
1309
+ let held = laneGate[0] > 0.5
1310
+ if laneActive[0] == 0 { resetLane(0) }
1311
+ laneNote[0] = note
1312
+ laneGate[0] = 1
1313
+ laneHeld[0] = false
1314
+ laneVelocity[0] = Float(Double(Swift.min(127, velocity)) / 127)
1315
+ laneActive[0] = 1
1316
+ newestLane = 0
1317
+ if mode == .mono || !held {
1318
+ trigger[0] += 1
1319
+ masterTrigger[0] += 1
1320
+ }
1321
+ return
1322
+ }
1323
+ let voices = voiceLimit()
172
1324
  var lane = -1
173
1325
  for l in 0..<voices where lane < 0 && laneNote[l] == note && laneGate[l] > 0.5 { lane = l }
174
1326
  var fresh = false
@@ -191,19 +1343,35 @@ public final class DSPMachine: @unchecked Sendable {
191
1343
  laneVelocity[lane] = Float(Double(Swift.min(127, velocity)) / 127)
192
1344
  laneActive[lane] = 1
193
1345
  trigger[lane] += 1
1346
+ masterTrigger[0] += 1
1347
+ newestLane = lane
194
1348
  age += 1
195
1349
  laneAge[lane] = age
196
1350
  }
197
1351
 
198
- public func noteOff(_ note: Int32) {
1352
+ private func release(_ note: Int32) {
1353
+ if let mode = currentMode() {
1354
+ unstack(note)
1355
+ guard laneNote[0] == note && laneGate[0] > 0.5 else { return }
1356
+ if stackCount > 0 {
1357
+ // Back to the note held before it.
1358
+ laneNote[0] = stack[stackCount - 1]
1359
+ laneHeld[0] = false
1360
+ if mode == .mono { trigger[0] += 1 }
1361
+ } else if pedal {
1362
+ laneHeld[0] = true
1363
+ } else {
1364
+ laneGate[0] = 0
1365
+ }
1366
+ return
1367
+ }
199
1368
  for l in 0..<program.voices where laneNote[l] == note && laneGate[l] > 0.5 {
200
1369
  // Under the pedal the gate stays up until it lifts.
201
1370
  if pedal { laneHeld[l] = true } else { laneGate[l] = 0 }
202
1371
  }
203
1372
  }
204
1373
 
205
- /// 64 the sustain pedal, 120 all sound off, 123 all notes off.
206
- public func controller(_ number: Int32, value: Int32) {
1374
+ private func control(_ number: Int32, value: Int32) {
207
1375
  let L = Self.lanes
208
1376
  switch number {
209
1377
  case 64:
@@ -215,24 +1383,32 @@ public final class DSPMachine: @unchecked Sendable {
215
1383
  case 123:
216
1384
  laneGate.update(repeating: 0, count: L)
217
1385
  laneHeld.update(repeating: false, count: L)
1386
+ stackCount = 0
218
1387
  case 120:
1388
+ stackCount = 0
219
1389
  for l in 0..<L {
220
1390
  laneGate[l] = 0
221
1391
  laneHeld[l] = false
222
1392
  laneActive[l] = 0
223
1393
  resetLane(l)
224
1394
  }
1395
+ resetMaster()
225
1396
  default:
226
1397
  break
227
1398
  }
228
1399
  }
229
1400
 
230
- /// The pitch wheel, 0 … 16383, 8192 centered: ±2 semitones.
231
- public func pitchBend(_ value: Int32) {
232
- bend = Double(Swift.min(16383, Swift.max(0, value)) - 8192) / 8192 * 2
1401
+ /// Drops `note` from a mono program's held notes.
1402
+ private func unstack(_ note: Int32) {
1403
+ var kept = 0
1404
+ for i in 0..<stackCount where stack[i] != note {
1405
+ stack[kept] = stack[i]
1406
+ kept += 1
1407
+ }
1408
+ stackCount = kept
233
1409
  }
234
1410
 
235
- /// Silences every voice at once.
1411
+ /// Silences every voice, and the master stage, at once, and drops what waits.
236
1412
  public func reset() {
237
1413
  controller(120, value: 0)
238
1414
  }
@@ -244,79 +1420,214 @@ public final class DSPMachine: @unchecked Sendable {
244
1420
 
245
1421
  // MARK: Rendering
246
1422
 
247
- /// Writes `frames` mono frames to `out`, in blocks of up to 128.
1423
+ /// Writes `frames` frames to `out`, in blocks of up to 128: a program's two sides averaged (a mono program's
1424
+ /// samples either way).
248
1425
  public func render(into out: UnsafeMutablePointer<Float>, frames: Int) {
249
1426
  var done = 0
250
1427
  while done < frames {
251
- let n = Swift.min(DSPProgram.blockFrames, frames - done)
252
- block(out + done, n)
1428
+ let step = tempo / 60 / Double(sampleRate)
1429
+ applyDue(step)
1430
+ // A block ends where the next event is due.
1431
+ let n = Swift.min(DSPProgram.blockFrames, frames - done, queueCount > 0 ? framesToNext(step) : DSPProgram.blockFrames)
1432
+ block(out + done, nil, n)
1433
+ done += n
1434
+ }
1435
+ }
1436
+
1437
+ /// Writes `frames` frames, the left side to `left` and the right to `right`, in blocks of up to 128.
1438
+ public func render(left: UnsafeMutablePointer<Float>, right: UnsafeMutablePointer<Float>, frames: Int) {
1439
+ var done = 0
1440
+ while done < frames {
1441
+ let step = tempo / 60 / Double(sampleRate)
1442
+ applyDue(step)
1443
+ let n = Swift.min(DSPProgram.blockFrames, frames - done, queueCount > 0 ? framesToNext(step) : DSPProgram.blockFrames)
1444
+ block(left + done, right + done, n)
253
1445
  done += n
254
1446
  }
255
1447
  }
256
1448
 
1449
+ /// A voice starts over: its state and its builtins', not the master stage's.
257
1450
  private func resetLane(_ l: Int) {
1451
+ // A register holds the program's voices' lanes (a state register's value its lane's first frame).
1452
+ if l < program.voices {
1453
+ for entry in program.state where !entry.master { registers[entry.register * width + l] = entry.initial }
1454
+ }
1455
+ for i in instanceKinds.indices where !instanceMaster[i] { resetInstance(i, l) }
1456
+ }
1457
+
1458
+ /// The master stage starts over, in lane 0.
1459
+ private func resetMaster() {
1460
+ for entry in program.state where entry.master { registers[entry.register * width] = entry.initial }
1461
+ for i in instanceKinds.indices where instanceMaster[i] { resetInstance(i, 0) }
1462
+ }
1463
+
1464
+ private func resetInstance(_ i: Int, _ l: Int) {
258
1465
  let L = Self.lanes
259
- for entry in program.state { registers[entry.register * L + l] = entry.initial }
260
- for (i, kind) in instanceKinds.enumerated() {
261
- let base = instanceOffsets[i] + l
262
- if kind == .noise {
263
- let seed = UInt32(truncatingIfNeeded: i + 1) &* 2_654_435_761 &+ UInt32(truncatingIfNeeded: l + 1) &* 2_246_822_519
264
- noise[base] = seed == 0 ? 1 : seed
265
- continue
266
- }
267
- for w in 0..<kind.words { state[base + w * L] = 0 }
268
- if kind == .adsr {
269
- state[base + 4 * L] = .nan
270
- state[base + 6 * L] = .nan
271
- } else if kind.words == 8 {
272
- state[base + 2 * L] = .nan
273
- }
1466
+ let kind = instanceKinds[i]
1467
+ let base = instanceOffsets[i] + l
1468
+ let seed = UInt32(truncatingIfNeeded: i + 1) &* 2_654_435_761 &+ UInt32(truncatingIfNeeded: l + 1) &* 2_246_822_519
1469
+ if kind == .noise {
1470
+ noise[base] = seed == 0 ? 1 : seed
1471
+ return
1472
+ }
1473
+ for w in 0..<kind.words { state[base + w * L] = 0 }
1474
+ if kind == .delay || kind == .comb || kind == .allpass {
1475
+ (delaySamples + delayBases[i] + l * delayLengths[i]).update(repeating: 0, count: delayLengths[i])
1476
+ }
1477
+ if kind == .grains {
1478
+ // Its random state, a word of raw bits.
1479
+ UnsafeMutableRawPointer(state + base + L).storeBytes(of: seed == 0 ? 1 : seed, as: UInt32.self)
1480
+ }
1481
+ if kind == .adsr {
1482
+ state[base + 4 * L] = .nan
1483
+ state[base + 6 * L] = .nan
1484
+ } else if kind.words == 8 {
1485
+ state[base + 2 * L] = .nan
1486
+ } else if kind == .smooth {
1487
+ state[base] = .nan
1488
+ state[base + L] = .nan
274
1489
  }
275
1490
  }
276
1491
 
277
- private func block(_ out: UnsafeMutablePointer<Float>, _ n: Int) {
1492
+ private func block(_ out: UnsafeMutablePointer<Float>, _ right: UnsafeMutablePointer<Float>?, _ n: Int) {
278
1493
  let L = Self.lanes
1494
+ let F = Self.frames
1495
+ let W = width
279
1496
  let R = registers
280
1497
  let sr = sampleRate
281
- // Parameters glide toward their targets, about 20 ms.
1498
+ // Parameters glide toward their targets, about 20 ms, and come to rest on them: one at rest is left as it is.
282
1499
  let alpha = snapped ? Float(1) : 1 - exp(-Float(n) / (0.02 * sr))
283
1500
  snapped = false
284
1501
  for (i, register) in parameterRegisters.enumerated() {
285
- let at = R + register * L
286
- at.update(repeating: at[0] + (targets[i] - at[0]) * alpha, count: L)
1502
+ let at = R + register * W
1503
+ let now = at[0]
1504
+ let target = targets[i]
1505
+ if now == target { continue }
1506
+ var value = now + (target - now) * alpha
1507
+ if abs(target - value) <= 1e-6 * (1 + abs(target)) { value = target }
1508
+ at.update(repeating: value, count: W)
1509
+ }
1510
+ if retargeted || rerouted {
1511
+ let force = rerouted
1512
+ retargeted = false
1513
+ rerouted = false
1514
+ if !groupParameters.isEmpty || !choiceParameters.isEmpty || force { turnRegions(loading: false, force: force) }
1515
+ if voicesParameter != nil || modeParameter != nil { revoice() }
287
1516
  }
288
- var any = false
289
- for l in 0..<L where laneActive[l] != 0 { any = true }
290
- guard any else {
1517
+ (R + 5 * W).update(repeating: Float(tempo), count: W)
1518
+ let beatStep = tempo / 60 / Double(sr)
1519
+ // The voices run up to the highest that sounds: a note takes the lowest free lane, and an idle one starts
1520
+ // over before it sounds again, so what the ones above would compute is never heard.
1521
+ var lanes = 0
1522
+ for l in 0..<L where laneActive[l] != 0 { lanes = l + 1 }
1523
+ let any = lanes > 0
1524
+ let master = program.master
1525
+ guard any || master != nil else {
1526
+ beat += Double(n) * beatStep
291
1527
  out.update(repeating: 0, count: n)
1528
+ right?.update(repeating: 0, count: n)
292
1529
  return
293
1530
  }
294
- for l in 0..<L {
295
- let note = laneNote[l]
296
- R[1 * L + l] = note >= 0 ? Float(440 * Foundation.pow(2, (Double(note) - 69 + bend) / 12)) : 0
297
- R[2 * L + l] = laneGate[l]
298
- R[3 * L + l] = laneVelocity[l]
299
- R[4 * L + l] = note >= 0 ? Float(note) : 0
1531
+ if any {
1532
+ let V = program.voices
1533
+ for l in 0..<V {
1534
+ let note = laneNote[l]
1535
+ let freq = note >= 0 ? Float(440 * Foundation.pow(2, (Double(note) - 69 + bend) / 12)) : 0
1536
+ for k in 0..<F {
1537
+ R[1 * W + k * V + l] = freq
1538
+ R[2 * W + k * V + l] = laneGate[l]
1539
+ R[3 * W + k * V + l] = laneVelocity[l]
1540
+ R[4 * W + k * V + l] = note >= 0 ? Float(note) : 0
1541
+ }
1542
+ }
1543
+ run(blockCode, 0..<blockRunning, lanes: lanes, trigger: trigger, frames: F)
300
1544
  }
301
- run(blockCode, blockCount)
302
- let o = R + program.output * L
1545
+ if master != nil {
1546
+ // The newest note, the master stage's inputs (registers 7 … 10), in lane 0.
1547
+ let l = newestLane
1548
+ let note = l >= 0 ? laneNote[l] : -1
1549
+ let values: [Float] = [
1550
+ note >= 0 ? Float(440 * Foundation.pow(2, (Double(note) - 69 + bend) / 12)) : 0,
1551
+ l >= 0 ? laneGate[l] : 0,
1552
+ l >= 0 ? laneVelocity[l] : 0,
1553
+ note >= 0 ? Float(note) : 0,
1554
+ ]
1555
+ let V = program.voices
1556
+ for (i, value) in values.enumerated() { for k in 0..<F { R[(7 + i) * W + k * V] = value } }
1557
+ }
1558
+ let o = R + program.output * W
1559
+ let or = R + (program.outputRight ?? program.output) * W
1560
+ let V = program.voices
303
1561
  var check: Float = 0
304
- for i in 0..<n {
305
- run(sampleCode, sampleCount)
306
- var sum: Float = 0
307
- for l in 0..<L { sum += o[l] * laneActive[l] }
308
- out[i] = sum
309
- check += sum
1562
+ // A chunk of up to 16 frames at a time: each instruction over all of them, the serial part frame by frame.
1563
+ var chunk = 0
1564
+ while chunk < n {
1565
+ let fc = Swift.min(F, n - chunk)
1566
+ for k in 0..<fc {
1567
+ for l in 0..<Swift.max(lanes, 1) { R[6 * W + k * V + l] = Float(beat) }
1568
+ beat += beatStep
1569
+ }
1570
+ if any {
1571
+ run(sampleCode, 0..<sampleSerial.lowerBound, lanes: lanes, trigger: trigger, frames: fc)
1572
+ if !sampleSerial.isEmpty {
1573
+ for k in 0..<fc { run(sampleCode, sampleSerial, lanes: lanes, trigger: trigger, frames: 1, frame: k) }
1574
+ }
1575
+ run(sampleCode, sampleSerial.upperBound..<sampleCount, lanes: lanes, trigger: trigger, frames: fc)
1576
+ }
1577
+ for k in 0..<fc {
1578
+ var leftSum: Float = 0
1579
+ var rightSum: Float = 0
1580
+ // The sounding voices only: an idle one may hold anything (log(0) of its freq, say), and NaN × 0 is NaN.
1581
+ if any {
1582
+ for l in 0..<lanes where laneActive[l] != 0 {
1583
+ leftSum += o[k * V + l]
1584
+ rightSum += or[k * V + l]
1585
+ }
1586
+ }
1587
+ if let master {
1588
+ R[master.inputs[0] * W + k * V] = leftSum
1589
+ R[master.inputs[1] * W + k * V] = rightSum
1590
+ } else {
1591
+ if let right {
1592
+ out[chunk + k] = leftSum
1593
+ right[chunk + k] = rightSum
1594
+ } else {
1595
+ out[chunk + k] = (leftSum + rightSum) * 0.5
1596
+ }
1597
+ check += leftSum + rightSum
1598
+ }
1599
+ }
1600
+ if let master {
1601
+ run(masterCode, 0..<masterSerial.lowerBound, lanes: 1, trigger: masterTrigger, frames: fc)
1602
+ if !masterSerial.isEmpty {
1603
+ for k in 0..<fc { run(masterCode, masterSerial, lanes: 1, trigger: masterTrigger, frames: 1, frame: k) }
1604
+ }
1605
+ run(masterCode, masterSerial.upperBound..<masterCount, lanes: 1, trigger: masterTrigger, frames: fc)
1606
+ for k in 0..<fc {
1607
+ let leftSum = R[master.outputs[0] * W + k * V]
1608
+ let rightSum = R[master.outputs[1] * W + k * V]
1609
+ if let right {
1610
+ out[chunk + k] = leftSum
1611
+ right[chunk + k] = rightSum
1612
+ } else {
1613
+ out[chunk + k] = (leftSum + rightSum) * 0.5
1614
+ }
1615
+ check += leftSum + rightSum
1616
+ }
1617
+ }
1618
+ chunk += fc
310
1619
  }
311
1620
  guard check.isFinite else {
312
- // A voice went to infinity or NaN: silence the block and start every voice over.
1621
+ // A voice or the master stage went to infinity or NaN: silence the block and start everything over.
313
1622
  out.update(repeating: 0, count: n)
1623
+ right?.update(repeating: 0, count: n)
314
1624
  for l in 0..<L {
315
1625
  laneActive[l] = 0
316
1626
  laneGate[l] = 0
317
1627
  laneHeld[l] = false
318
1628
  resetLane(l)
319
1629
  }
1630
+ resetMaster()
320
1631
  return
321
1632
  }
322
1633
  // Denormals in the filters' integrators would slow every frame after.
@@ -344,180 +1655,731 @@ public final class DSPMachine: @unchecked Sendable {
344
1655
  return 0
345
1656
  }
346
1657
 
347
- // The interpreter: one instruction at a time, every lane per instruction.
348
- private func run(_ code: UnsafeMutablePointer<Int32>, _ count: Int) {
1658
+ /// A table's, shape's or sample's index from its register: in range, or the first.
1659
+ @inline(__always)
1660
+ private static func index(_ value: Float, _ count: Int) -> Int {
1661
+ value >= 0 && value < Float(count) ? Int(value) : 0
1662
+ }
1663
+
1664
+ // The interpreter: instructions `range` of `code` in the first `lanes` lanes (every voice's, or the master
1665
+ // stage's one), each lane's note on counted in `trigger`, over the chunk's first `frames` frames; or, given a
1666
+ // `frame`, at that frame alone, as the serial part runs (a state register's one value a lane, its first).
1667
+ private func run(
1668
+ _ code: UnsafeMutablePointer<Int32>, _ range: Range<Int>, lanes: Int, trigger: UnsafeMutablePointer<Float>, frames: Int, frame: Int = -1
1669
+ ) {
349
1670
  let L = Self.lanes
1671
+ let F = Self.frames
350
1672
  let R = registers
351
1673
  let S = state
352
1674
  let N = noise
353
1675
  let sr = sampleRate
354
- var at = 0
355
- let end = count * 8
356
- while at < end {
1676
+ let serial = frame >= 0
1677
+ let fc = serial ? 1 : frames
1678
+ let V = program.voices
1679
+ let shift = serial ? frame * V : 0
1680
+ // A stateless instruction: every lane's frames at once (the chunk's last ones, past fc, go unread), the
1681
+ // sounding lanes of each frame; in the serial part, the one frame's.
1682
+ @inline(__always) func each(_ body: (Int) -> Void) {
1683
+ if serial {
1684
+ for l in 0..<lanes { body(l) }
1685
+ } else if lanes == V {
1686
+ for i in 0..<(F * V) { body(i) }
1687
+ } else {
1688
+ for k in 0..<F {
1689
+ for l in 0..<lanes { body(k * V + l) }
1690
+ }
1691
+ }
1692
+ }
1693
+ var next = range.lowerBound * 12
1694
+ let end = range.upperBound * 12
1695
+ while next < end {
1696
+ // A constant for the instruction: a variable the kernels' closures read would be checked for exclusive
1697
+ // access at every read.
1698
+ let at = next
1699
+ next += 12
357
1700
  let op = code[at]
358
- let d = R + Int(code[at + 1])
359
- let a = R + Int(code[at + 2])
360
- let b = R + Int(code[at + 3])
361
- let c = R + Int(code[at + 4])
1701
+ let states = code[at + 8]
1702
+ // A register at this frame, or a state register's one value.
1703
+ @inline(__always) func register(_ slot: Int) -> UnsafeMutablePointer<Float> {
1704
+ R + Int(code[at + slot]) + (states & (1 << slot) != 0 ? 0 : shift)
1705
+ }
1706
+ let d = register(1)
1707
+ let a = register(2)
1708
+ let b = register(3)
1709
+ let c = register(4)
362
1710
  switch op {
363
- case 0: for l in 0..<L { d[l] = a[l] }
364
- case 1: for l in 0..<L { d[l] = a[l] + b[l] }
365
- case 2: for l in 0..<L { d[l] = a[l] - b[l] }
366
- case 3: for l in 0..<L { d[l] = a[l] * b[l] }
367
- case 4: for l in 0..<L { d[l] = a[l] / b[l] }
368
- case 5: for l in 0..<L { d[l] = a[l].truncatingRemainder(dividingBy: b[l]) }
369
- case 6: for l in 0..<L { d[l] = -a[l] }
370
- case 7: for l in 0..<L { d[l] = Swift.min(a[l], b[l]) }
371
- case 8: for l in 0..<L { d[l] = Swift.max(a[l], b[l]) }
372
- case 9: for l in 0..<L { d[l] = Swift.abs(a[l]) }
373
- case 10: for l in 0..<L { d[l] = a[l].rounded(.down) }
374
- case 11: for l in 0..<L { d[l] = a[l].rounded(.up) }
375
- case 12: for l in 0..<L { d[l] = (a[l] + 0.5).rounded(.down) }
376
- case 13: for l in 0..<L { d[l] = a[l].squareRoot() }
377
- case 14: for l in 0..<L { d[l] = Foundation.sin(a[l]) }
378
- case 15: for l in 0..<L { d[l] = Foundation.cos(a[l]) }
379
- case 16: for l in 0..<L { d[l] = Foundation.tan(a[l]) }
380
- case 17: for l in 0..<L { d[l] = Foundation.exp(a[l]) }
381
- case 18: for l in 0..<L { d[l] = Foundation.log(a[l]) }
382
- case 19: for l in 0..<L { d[l] = Foundation.pow(a[l], b[l]) }
383
- case 20: for l in 0..<L { d[l] = Foundation.tanh(a[l]) }
384
- case 21: for l in 0..<L { d[l] = a[l] < b[l] ? 1 : 0 }
385
- case 22: for l in 0..<L { d[l] = a[l] <= b[l] ? 1 : 0 }
386
- case 23: for l in 0..<L { d[l] = a[l] > b[l] ? 1 : 0 }
387
- case 24: for l in 0..<L { d[l] = a[l] >= b[l] ? 1 : 0 }
388
- case 25: for l in 0..<L { d[l] = a[l] == b[l] ? 1 : 0 }
389
- case 26: for l in 0..<L { d[l] = a[l] != b[l] ? 1 : 0 }
390
- case 27: for l in 0..<L { d[l] = a[l] != 0 && b[l] != 0 ? 1 : 0 }
391
- case 28: for l in 0..<L { d[l] = a[l] != 0 || b[l] != 0 ? 1 : 0 }
392
- case 29: for l in 0..<L { d[l] = a[l] == 0 ? 1 : 0 }
393
- case 30: for l in 0..<L { d[l] = a[l] != 0 ? b[l] : c[l] }
394
- case 31: for l in 0..<L { d[l] = Swift.min(Swift.max(a[l], b[l]), c[l]) }
395
- case 32: for l in 0..<L { d[l] = a[l] + (b[l] - a[l]) * c[l] }
396
- case 33: for l in 0..<L { d[l] = a[l] - a[l].rounded(.down) }
397
- case 34: for l in 0..<L { d[l] = a[l] > 0 ? 1 : a[l] < 0 ? -1 : 0 }
398
- case 35: for l in 0..<L { d[l] = Foundation.atan(a[l]) }
1711
+ case 0: each { d[$0] = a[$0] }
1712
+ case 1: each { d[$0] = a[$0] + b[$0] }
1713
+ case 2: each { d[$0] = a[$0] - b[$0] }
1714
+ case 3: each { d[$0] = a[$0] * b[$0] }
1715
+ case 4: each { d[$0] = a[$0] / b[$0] }
1716
+ case 5: each { d[$0] = a[$0].truncatingRemainder(dividingBy: b[$0]) }
1717
+ case 6: each { d[$0] = -a[$0] }
1718
+ case 7: each { d[$0] = Swift.min(a[$0], b[$0]) }
1719
+ case 8: each { d[$0] = Swift.max(a[$0], b[$0]) }
1720
+ case 9: each { d[$0] = Swift.abs(a[$0]) }
1721
+ case 10: each { d[$0] = a[$0].rounded(.down) }
1722
+ case 11: each { d[$0] = a[$0].rounded(.up) }
1723
+ case 12: each { d[$0] = (a[$0] + 0.5).rounded(.down) }
1724
+ case 13: each { d[$0] = a[$0].squareRoot() }
1725
+ case 14: each { d[$0] = Foundation.sin(a[$0]) }
1726
+ case 15: each { d[$0] = Foundation.cos(a[$0]) }
1727
+ case 16: each { d[$0] = Foundation.tan(a[$0]) }
1728
+ case 17: each { d[$0] = Foundation.exp(a[$0]) }
1729
+ case 18: each { d[$0] = Foundation.log(a[$0]) }
1730
+ case 19: each { d[$0] = Foundation.pow(a[$0], b[$0]) }
1731
+ case 20: each { d[$0] = Foundation.tanh(a[$0]) }
1732
+ case 21: each { d[$0] = a[$0] < b[$0] ? 1 : 0 }
1733
+ case 22: each { d[$0] = a[$0] <= b[$0] ? 1 : 0 }
1734
+ case 23: each { d[$0] = a[$0] > b[$0] ? 1 : 0 }
1735
+ case 24: each { d[$0] = a[$0] >= b[$0] ? 1 : 0 }
1736
+ case 25: each { d[$0] = a[$0] == b[$0] ? 1 : 0 }
1737
+ case 26: each { d[$0] = a[$0] != b[$0] ? 1 : 0 }
1738
+ case 27: each { d[$0] = a[$0] != 0 && b[$0] != 0 ? 1 : 0 }
1739
+ case 28: each { d[$0] = a[$0] != 0 || b[$0] != 0 ? 1 : 0 }
1740
+ case 29: each { d[$0] = a[$0] == 0 ? 1 : 0 }
1741
+ case 30: each { d[$0] = a[$0] != 0 ? b[$0] : c[$0] }
1742
+ case 31: each { d[$0] = Swift.min(Swift.max(a[$0], b[$0]), c[$0]) }
1743
+ case 32: each { d[$0] = a[$0] + (b[$0] - a[$0]) * c[$0] }
1744
+ case 33: each { d[$0] = a[$0] - a[$0].rounded(.down) }
1745
+ case 34: each { d[$0] = a[$0] > 0 ? 1 : a[$0] < 0 ? -1 : 0 }
1746
+ case 35: each { d[$0] = Foundation.atan(a[$0]) }
1747
+ // The superinstructions: the product or the sum a float, as its own instruction would have stored it.
1748
+ case 58: each { d[$0] = a[$0] * b[$0] + c[$0] }
1749
+ case 59: each { d[$0] = (a[$0] + b[$0]) * c[$0] }
1750
+ case 60: each { d[$0] = Foundation.log2(a[$0]) }
1751
+ case 61: each { d[$0] = Foundation.log10(a[$0]) }
1752
+ case 62: each { d[$0] = Foundation.exp2(a[$0]) }
1753
+ case 63: each { d[$0] = a[$0].rounded(.towardZero) }
1754
+ case 64: each { d[$0] = Foundation.asin(a[$0]) }
1755
+ case 65: each { d[$0] = Foundation.acos(a[$0]) }
1756
+ case 66: each { d[$0] = Foundation.atan2(a[$0], b[$0]) }
1757
+ case 67: each { d[$0] = Foundation.sinh(a[$0]) }
1758
+ case 68: each { d[$0] = Foundation.cosh(a[$0]) }
1759
+ case 69: each { d[$0] = Foundation.cbrt(a[$0]) }
1760
+ case 70: each { d[$0] = Foundation.hypot(a[$0], b[$0]) }
1761
+ case 71: each { d[$0] = Foundation.expm1(a[$0]) }
1762
+ case 72: each { d[$0] = Foundation.log1p(a[$0]) }
1763
+ case 73:
1764
+ // softclip(x): x (27 + x²) / (27 + 9x²) within ±3.
1765
+ each {
1766
+ let x = a[$0] > -3 ? (a[$0] < 3 ? a[$0] : 3) : -3
1767
+ let x2 = x * x
1768
+ d[$0] = x * (27 + x2) / (27 + 9 * x2)
1769
+ }
1770
+ case 74:
1771
+ // onepole(input, cutoff): toward the input by 1 − e^(−2π cutoff / sampleRate) a frame.
1772
+ let s = S + Int(code[at + 7])
1773
+ for fk in 0..<fc {
1774
+ for l in 0..<lanes {
1775
+ let el = fk * V + l
1776
+ let cutoff = Swift.min(Swift.max(b[el], 0), 0.49 * sr)
1777
+ if !(s[L + l] == cutoff) {
1778
+ s[L + l] = cutoff
1779
+ s[2 * L + l] = 1 - Foundation.exp(-2 * Float.pi * cutoff / sr)
1780
+ }
1781
+ let y = s[l]
1782
+ s[l] = y + (a[el] - y) * s[2 * L + l]
1783
+ d[el] = s[l]
1784
+ }
1785
+ }
1786
+ case 75:
1787
+ // dcblock(input): y = x − x before + r × y before, r = 1 − 2π 20 / sampleRate.
1788
+ let s = S + Int(code[at + 7])
1789
+ let r = 1 - Float(125.66370614359172) / sr
1790
+ for fk in 0..<fc {
1791
+ for l in 0..<lanes {
1792
+ let el = fk * V + l
1793
+ let x = a[el]
1794
+ let y = (x - s[l]) + r * s[L + l]
1795
+ s[l] = x
1796
+ s[L + l] = y
1797
+ d[el] = y
1798
+ }
1799
+ }
1800
+ case 76, 77:
1801
+ // comb(input, seconds, feedback, damp, longest): its line read seconds back, between samples, through a
1802
+ // one-pole (damp the share it keeps) back in with the input times feedback. allpass(input, seconds,
1803
+ // gain, longest): w = input + gain × w seconds back, out = w seconds back − gain × w.
1804
+ let s = S + Int(code[at + 7])
1805
+ let length = Int(code[at + 10])
1806
+ let mask = length - 1
1807
+ let memory = delaySamples + Int(code[at + 9])
1808
+ let damping = register(5)
1809
+ for fk in 0..<fc {
1810
+ for l in 0..<lanes {
1811
+ let el = fk * V + l
1812
+ let w = Int(s[l])
1813
+ var ds = b[el] * sr
1814
+ ds = ds >= 1 ? (ds <= Float(length - 2) ? ds : Float(length - 2)) : 1
1815
+ let position = Float(w) - ds
1816
+ let i0 = Int(position.rounded(.down))
1817
+ let fr = position - Float(i0)
1818
+ let line = memory + l * length
1819
+ let v0 = line[i0 & mask]
1820
+ let v = v0 + (line[(i0 + 1) & mask] - v0) * fr
1821
+ let x = a[el]
1822
+ let g = c[el]
1823
+ if op == 76 {
1824
+ let damp = damping[el] > 0 ? (damping[el] < 1 ? damping[el] : 1) : 0
1825
+ let store = v * (1 - damp) + s[L + l] * damp
1826
+ s[L + l] = store
1827
+ line[w & mask] = x + store * g
1828
+ d[el] = v
1829
+ } else {
1830
+ let into = x + g * v
1831
+ line[w & mask] = into
1832
+ d[el] = v - g * into
1833
+ }
1834
+ s[l] = Float((w + 1) & mask)
1835
+ }
1836
+ }
399
1837
  case 40, 41, 42, 43, 44:
400
1838
  // Oscillators: the output from the phase now, then the phase steps by freq / sampleRate.
401
1839
  let s = S + Int(code[at + 7])
402
- for l in 0..<L {
403
- let p = s[l]
404
- let dt = a[l] / sr
405
- var v: Float
406
- switch op {
407
- case 40: v = p
408
- case 41: v = Foundation.sin(2 * Float.pi * p)
409
- case 42:
410
- v = 2 * p - 1
411
- if dt > 0 { v -= Self.blep(p, dt) }
412
- case 43:
413
- let w = Swift.min(Swift.max(b[l], 0), 1)
414
- v = p < w ? 1 : -1
415
- if dt > 0 {
416
- let q = p + 1 - w
417
- v += Self.blep(p, dt) - Self.blep(q - q.rounded(.down), dt)
1840
+ for fk in 0..<fc {
1841
+ for l in 0..<lanes {
1842
+ let el = fk * V + l
1843
+ let p = s[l]
1844
+ let dt = a[el] / sr
1845
+ var v: Float
1846
+ switch op {
1847
+ case 40: v = p
1848
+ case 41: v = Foundation.sin(2 * Float.pi * p)
1849
+ case 42:
1850
+ v = 2 * p - 1
1851
+ if dt > 0 { v -= Self.blep(p, dt) }
1852
+ case 43:
1853
+ let w = Swift.min(Swift.max(b[el], 0), 1)
1854
+ v = p < w ? 1 : -1
1855
+ if dt > 0 {
1856
+ let q = p + 1 - w
1857
+ v += Self.blep(p, dt) - Self.blep(q - q.rounded(.down), dt)
1858
+ }
1859
+ default: v = 1 - 4 * Swift.abs(p - 0.5)
418
1860
  }
419
- default: v = 1 - 4 * Swift.abs(p - 0.5)
1861
+ d[el] = v
1862
+ let next = p + dt
1863
+ s[l] = next >= 0 && next < 1 ? next : next - next.rounded(.down)
420
1864
  }
421
- d[l] = v
422
- let next = p + dt
423
- s[l] = next - next.rounded(.down)
424
1865
  }
425
1866
  case 45:
426
1867
  let s = N + Int(code[at + 7])
427
- for l in 0..<L {
428
- var x = s[l]
429
- x ^= x << 13
430
- x ^= x >> 17
431
- x ^= x << 5
432
- s[l] = x
433
- d[l] = Float(Double(x) / 4_294_967_296 * 2 - 1)
1868
+ for fk in 0..<fc {
1869
+ for l in 0..<lanes {
1870
+ let el = fk * V + l
1871
+ var x = s[l]
1872
+ x ^= x << 13
1873
+ x ^= x >> 17
1874
+ x ^= x << 5
1875
+ s[l] = x
1876
+ d[el] = Float(Double(x) / 4_294_967_296 * 2 - 1)
1877
+ }
434
1878
  }
435
1879
  case 46:
436
1880
  // adsr(gate, attack, decay, sustain, release): stage, level, trigger, gate before, decay time and coefficient, release time and coefficient.
1881
+ // With curves, what it puts out is each stage bent by its exponent, and a stage that starts takes up
1882
+ // where the last left off: its last output, and where a release started.
437
1883
  let s = S + Int(code[at + 7])
438
- let sustainIn = R + Int(code[at + 5])
439
- let releaseIn = R + Int(code[at + 6])
440
- for l in 0..<L {
441
- let gate = a[l]
442
- var stage = s[l]
443
- var level = s[L + l]
444
- if s[2 * L + l] != trigger[l] {
445
- s[2 * L + l] = trigger[l]
446
- if gate > 0.5 { stage = 1 }
447
- } else if gate > 0.5 && s[3 * L + l] <= 0.5 {
448
- stage = 1
449
- }
450
- if gate <= 0.5 && stage >= 1 && stage <= 3 { stage = 4 }
451
- s[3 * L + l] = gate
452
- let sustain = Swift.min(Swift.max(sustainIn[l], 0), 1)
453
- if stage == 1 {
454
- level += 1 / Swift.max(1, b[l] * sr)
455
- if level >= 1 {
456
- level = 1
457
- stage = 2
458
- }
459
- } else if stage == 2 {
460
- let time = c[l]
461
- if !(s[4 * L + l] == time) {
462
- s[4 * L + l] = time
463
- s[5 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1884
+ let sustainIn = register(5)
1885
+ let releaseIn = register(6)
1886
+ let curve = Int(code[at + 11]) - 1
1887
+ let curved = curve >= 0
1888
+ // The curves' registers (a knob's, or modulated), read at the chunk's first frame a voice (as machine.ts
1889
+ // reads them), 1/16 … 16, 1 for NaN.
1890
+ let ra = curved ? R + curveRegisters[curve * 3] + shift : R
1891
+ let rd = curved ? R + curveRegisters[curve * 3 + 1] + shift : R
1892
+ let rr = curved ? R + curveRegisters[curve * 3 + 2] + shift : R
1893
+ for l in 0..<lanes {
1894
+ let ea = curved ? Self.exponent(ra[l]) : 1
1895
+ let ed = curved ? Self.exponent(rd[l]) : 1
1896
+ let er = curved ? Self.exponent(rr[l]) : 1
1897
+ // All three 1: no stage bent (what it put out kept all the same, for a curve turned later).
1898
+ let bent = curved && (ea != 1 || ed != 1 || er != 1)
1899
+ for fk in 0..<fc {
1900
+ let el = fk * V + l
1901
+ let gate = a[el]
1902
+ var stage = s[l]
1903
+ var level = s[L + l]
1904
+ let before = stage
1905
+ if s[2 * L + l] != trigger[l] {
1906
+ s[2 * L + l] = trigger[l]
1907
+ if gate > 0.5 { stage = 1 }
1908
+ } else if gate > 0.5 && s[3 * L + l] <= 0.5 {
1909
+ stage = 1
464
1910
  }
465
- level = sustain + (level - sustain) * s[5 * L + l]
466
- if level - sustain < 0.0001 { stage = 3 }
467
- } else if stage == 3 {
468
- level = sustain
469
- } else if stage == 4 {
470
- let time = releaseIn[l]
471
- if !(s[6 * L + l] == time) {
472
- s[6 * L + l] = time
473
- s[7 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1911
+ if gate <= 0.5 && stage >= 1 && stage <= 3 { stage = 4 }
1912
+ s[3 * L + l] = gate
1913
+ if curved && stage != before {
1914
+ let last = s[8 * L + l]
1915
+ if stage == 1 {
1916
+ level = last > 0 ? (ea == 1 ? last : Float(Foundation.pow(Double(last), 1 / ea))) : 0
1917
+ } else if stage == 4 {
1918
+ level = last
1919
+ s[9 * L + l] = last
1920
+ }
474
1921
  }
475
- level *= s[7 * L + l]
476
- if level < 0.0001 {
1922
+ let sustain = Swift.min(Swift.max(sustainIn[el], 0), 1)
1923
+ if stage == 1 {
1924
+ level += 1 / Swift.max(1, b[el] * sr)
1925
+ if level >= 1 {
1926
+ level = 1
1927
+ stage = 2
1928
+ }
1929
+ } else if stage == 2 {
1930
+ let time = c[el]
1931
+ if !(s[4 * L + l] == time) {
1932
+ s[4 * L + l] = time
1933
+ s[5 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1934
+ }
1935
+ level = sustain + (level - sustain) * s[5 * L + l]
1936
+ if level - sustain < 0.0001 { stage = 3 }
1937
+ } else if stage == 3 {
1938
+ level = sustain
1939
+ } else if stage == 4 {
1940
+ let time = releaseIn[el]
1941
+ if !(s[6 * L + l] == time) {
1942
+ s[6 * L + l] = time
1943
+ s[7 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1944
+ }
1945
+ level *= s[7 * L + l]
1946
+ if level < 0.0001 {
1947
+ level = 0
1948
+ stage = 0
1949
+ }
1950
+ } else {
477
1951
  level = 0
478
- stage = 0
479
1952
  }
480
- } else {
481
- level = 0
1953
+ s[l] = stage
1954
+ s[L + l] = level
1955
+ var out = level
1956
+ if bent {
1957
+ // An exponent of 1 is no bend: the stage as it is, with no power worked out.
1958
+ if stage == 1 {
1959
+ out = ea == 1 ? level : Float(Foundation.pow(Double(level), ea))
1960
+ } else if stage == 2 {
1961
+ let span = 1 - sustain
1962
+ let along = Swift.max(0, (level - sustain) / span)
1963
+ out = span > 1e-6 ? sustain + span * (ed == 1 ? along : Float(Foundation.pow(Double(along), ed))) : level
1964
+ } else if stage == 4 {
1965
+ let from = s[9 * L + l]
1966
+ let along = Swift.min(1, level / from)
1967
+ out = from > 0 ? from * (er == 1 ? along : Float(Foundation.pow(Double(along), er))) : 0
1968
+ }
1969
+ }
1970
+ if curved { s[8 * L + l] = out }
1971
+ d[el] = out
482
1972
  }
483
- s[l] = stage
484
- s[L + l] = level
485
- d[l] = level
486
1973
  }
487
1974
  case 47, 48, 49:
488
1975
  // A state-variable filter (Simper's form): resonance 0 … 1.
489
1976
  let s = S + Int(code[at + 7])
490
- for l in 0..<L {
491
- let cutoff = Swift.min(Swift.max(b[l], 10), 0.49 * sr)
492
- let resonance = Swift.min(Swift.max(c[l], 0), 0.98)
493
- if !(s[2 * L + l] == cutoff && s[3 * L + l] == resonance) {
494
- s[2 * L + l] = cutoff
495
- s[3 * L + l] = resonance
496
- let g = Foundation.tan(Float.pi * cutoff / sr)
497
- let k = 2 - 2 * resonance
498
- let a1 = 1 / (1 + g * (g + k))
499
- s[4 * L + l] = a1
500
- s[5 * L + l] = g * a1
501
- s[6 * L + l] = g * g * a1
502
- s[7 * L + l] = k
1977
+ for fk in 0..<fc {
1978
+ for l in 0..<lanes {
1979
+ let el = fk * V + l
1980
+ let cutoff = Swift.min(Swift.max(b[el], 10), 0.49 * sr)
1981
+ let resonance = Swift.min(Swift.max(c[el], 0), 0.98)
1982
+ if !(s[2 * L + l] == cutoff && s[3 * L + l] == resonance) {
1983
+ s[2 * L + l] = cutoff
1984
+ s[3 * L + l] = resonance
1985
+ let g = Foundation.tan(Float.pi * cutoff / sr)
1986
+ let k = 2 - 2 * resonance
1987
+ let a1 = 1 / (1 + g * (g + k))
1988
+ s[4 * L + l] = a1
1989
+ s[5 * L + l] = g * a1
1990
+ s[6 * L + l] = g * g * a1
1991
+ s[7 * L + l] = k
1992
+ }
1993
+ let a1 = s[4 * L + l]
1994
+ let a2 = s[5 * L + l]
1995
+ let a3 = s[6 * L + l]
1996
+ let ic1 = s[l]
1997
+ let ic2 = s[L + l]
1998
+ let x = a[el]
1999
+ let v3 = x - ic2
2000
+ let v1 = a1 * ic1 + a2 * v3
2001
+ let v2 = ic2 + a2 * ic1 + a3 * v3
2002
+ s[l] = 2 * v1 - ic1
2003
+ s[L + l] = 2 * v2 - ic2
2004
+ d[el] = op == 47 ? v2 : op == 49 ? v1 : x - s[7 * L + l] * v1 - v2
2005
+ }
2006
+ }
2007
+ case 50:
2008
+ // wavetable(table, freq, position): the level that cannot alias at freq (worked out again only when freq
2009
+ // changes), read between samples and between frames.
2010
+ let s = S + Int(code[at + 7])
2011
+ // The table is a constant register's, the same in every lane.
2012
+ let index = a[0]
2013
+ let t = index >= 0 && Int(exactly: index.rounded(.down)).map { $0 < tableCount } == true ? Int(index) : 0
2014
+ let frames = tableFrames.isEmpty ? 1 : tableFrames[t]
2015
+ let T = tablePointers[t]
2016
+ let base = 0
2017
+ for fk in 0..<fc {
2018
+ for l in 0..<lanes {
2019
+ let el = fk * V + l
2020
+ let p = s[l]
2021
+ let f = b[el]
2022
+ let dt = f / sr
2023
+ if s[L + l] != f {
2024
+ s[L + l] = f
2025
+ var level = 0
2026
+ let allowed = 0.5 * Double(sr) / Double(Swift.abs(f))
2027
+ if allowed < 512 {
2028
+ let octaves = Foundation.log2(512 / allowed)
2029
+ level = octaves > 8 ? 9 : Int(octaves.rounded(.up))
2030
+ }
2031
+ s[2 * L + l] = Float(level)
2032
+ }
2033
+ let level = Int(s[2 * L + l])
2034
+ // NaN reads as 0 here, as in the JavaScript machine.
2035
+ let morph = c[el] > 0 ? (c[el] < 1 ? c[el] : 1) : 0
2036
+ let position = morph * Float(frames - 1)
2037
+ // Never below 0: truncating is rounding down.
2038
+ let f0 = Int(position)
2039
+ let f1 = Swift.min(f0 + 1, frames - 1)
2040
+ let ff = position - Float(f0)
2041
+ let x = p * 2048
2042
+ // A phase gone to NaN reads NaN, which the block's check silences.
2043
+ let i0 = x >= 0 && x < 2048 ? Int(x) : x.isFinite ? Int(x.rounded(.down)) : 0
2044
+ let fr = x - Float(i0)
2045
+ let j0 = i0 & 2047
2046
+ let j1 = (i0 + 1) & 2047
2047
+ // Samples j0 and j1, each its frames side by side.
2048
+ let row0 = base + (level * 2048 + j0) * frames
2049
+ let row1 = base + (level * 2048 + j1) * frames
2050
+ let v0 = T[row0 + f0] + (T[row1 + f0] - T[row0 + f0]) * fr
2051
+ let v1 = T[row0 + f1] + (T[row1 + f1] - T[row0 + f1]) * fr
2052
+ d[el] = v0 + (v1 - v0) * ff
2053
+ let next = p + dt
2054
+ s[l] = next >= 0 && next < 1 ? next : next - next.rounded(.down)
2055
+ }
2056
+ }
2057
+ case 51:
2058
+ // delay(input, seconds, longest): read at least a sample back, between samples, then write.
2059
+ let s = S + Int(code[at + 7])
2060
+ let length = Int(code[at + 10])
2061
+ let mask = length - 1
2062
+ let memory = delaySamples + Int(code[at + 9])
2063
+ for fk in 0..<fc {
2064
+ for l in 0..<lanes {
2065
+ let el = fk * V + l
2066
+ let w = Int(s[l])
2067
+ let x = a[el]
2068
+ var ds = b[el] * sr
2069
+ ds = ds >= 1 ? (ds <= Float(length - 2) ? ds : Float(length - 2)) : 1
2070
+ let position = Float(w) - ds
2071
+ let i0 = Int(position.rounded(.down))
2072
+ let fr = position - Float(i0)
2073
+ let line = memory + l * length
2074
+ let v0 = line[i0 & mask]
2075
+ let v1 = line[(i0 + 1) & mask]
2076
+ d[el] = v0 + (v1 - v0) * fr
2077
+ line[w & mask] = x
2078
+ s[l] = Float((w + 1) & mask)
2079
+ }
2080
+ }
2081
+ case 52:
2082
+ // shape(shape, x): x 0 … 1 along it, between points.
2083
+ for fk in 0..<fc {
2084
+ for l in 0..<lanes {
2085
+ let el = fk * V + l
2086
+ let t = Self.index(a[el], shapeLengths.count)
2087
+ let points = shapeLengths.isEmpty ? 1 : shapeLengths[t]
2088
+ let P = shapePointers[t]
2089
+ let base = 0
2090
+ let x = b[el]
2091
+ let position = (x > 0 ? (x < 1 ? x : 1) : 0) * Float(points - 1)
2092
+ let i0 = Int(position.rounded(.down))
2093
+ let v0 = P[base + i0]
2094
+ let v1 = P[base + Swift.min(i0 + 1, points - 1)]
2095
+ d[el] = v0 + (v1 - v0) * (position - Float(i0))
2096
+ }
2097
+ }
2098
+ case 53:
2099
+ // play(sample, rate, start): from start (0 … 1 along it) at each note on, at rate (1 its own pitch),
2100
+ // between samples; silent past either end. Where it plays is a whole sample and the fraction past it,
2101
+ // so it keeps time.
2102
+ let s = S + Int(code[at + 7])
2103
+ for fk in 0..<fc {
2104
+ for l in 0..<lanes {
2105
+ let el = fk * V + l
2106
+ let t = Self.index(a[el], sampleLengths.count)
2107
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
2108
+ let A = samplePointers[t]
2109
+ let base = 0
2110
+ if s[2 * L + l] != trigger[l] {
2111
+ s[2 * L + l] = trigger[l]
2112
+ let start = c[el]
2113
+ let p = (start > 0 ? (start < 1 ? start : 1) : 0) * Float(length - 1)
2114
+ s[l] = p.rounded(.down)
2115
+ s[L + l] = p - p.rounded(.down)
2116
+ }
2117
+ let index = s[l]
2118
+ let fraction = s[L + l]
2119
+ var v: Float = 0
2120
+ if index >= 0 && index < Float(length) {
2121
+ // Past the last sample, silence.
2122
+ let k = base + Int(index)
2123
+ let after = index < Float(length - 1) ? A[k + 1] : 0
2124
+ v = A[k] + (after - A[k]) * fraction
2125
+ }
2126
+ d[el] = v
2127
+ var step = b[el] * (sampleRatios.isEmpty ? 1 : sampleRatios[t])
2128
+ step = step > -65536 ? (step < 65536 ? step : 65536) : -65536
2129
+ let next = fraction + step
2130
+ let whole = next.rounded(.down)
2131
+ let moved = index + whole
2132
+ s[l] = moved > -1 ? (moved < Float(length) ? moved : Float(length)) : -1
2133
+ s[L + l] = next - whole
2134
+ }
2135
+ }
2136
+ case 78:
2137
+ // tableread(table, phase, freq, position): wavetable's read, at a phase the program keeps (wrapped to
2138
+ // 0 … 1), at the level that cannot alias at freq (worked out again only when freq changes).
2139
+ let s = S + Int(code[at + 7])
2140
+ let e = register(5)
2141
+ // The table is a constant register's, the same in every lane.
2142
+ let index = a[0]
2143
+ let t = index >= 0 && Int(exactly: index.rounded(.down)).map { $0 < tableCount } == true ? Int(index) : 0
2144
+ let frames = tableFrames.isEmpty ? 1 : tableFrames[t]
2145
+ let T = tablePointers[t]
2146
+ let base = 0
2147
+ for fk in 0..<fc {
2148
+ for l in 0..<lanes {
2149
+ let el = fk * V + l
2150
+ let f = c[el]
2151
+ if s[l] != f {
2152
+ s[l] = f
2153
+ var level = 0
2154
+ let allowed = 0.5 * Double(sr) / Double(Swift.abs(f))
2155
+ if allowed < 512 {
2156
+ let octaves = Foundation.log2(512 / allowed)
2157
+ level = octaves > 8 ? 9 : Int(octaves.rounded(.up))
2158
+ }
2159
+ s[L + l] = Float(level)
2160
+ }
2161
+ let level = Int(s[L + l])
2162
+ let morph = e[el] > 0 ? (e[el] < 1 ? e[el] : 1) : 0
2163
+ let position = morph * Float(frames - 1)
2164
+ let f0 = Int(position)
2165
+ let f1 = Swift.min(f0 + 1, frames - 1)
2166
+ let ff = position - Float(f0)
2167
+ let phase = b[el]
2168
+ // 0 … 1 (1 itself, as a phase just below 0 rounds to); NaN past infinities.
2169
+ let p = phase - phase.rounded(.down)
2170
+ let x = p * 2048
2171
+ let i0 = x >= 0 && x <= 2048 ? Int(x) : 0
2172
+ let fr = x - Float(i0)
2173
+ let j0 = i0 & 2047
2174
+ let j1 = (i0 + 1) & 2047
2175
+ let row0 = base + (level * 2048 + j0) * frames
2176
+ let row1 = base + (level * 2048 + j1) * frames
2177
+ let v0 = T[row0 + f0] + (T[row1 + f0] - T[row0 + f0]) * fr
2178
+ let v1 = T[row0 + f1] + (T[row1 + f1] - T[row0 + f1]) * fr
2179
+ d[el] = v0 + (v1 - v0) * ff
2180
+ }
2181
+ }
2182
+ case 79:
2183
+ // loop(sample, rate, start): play's, but round and round: past either end it comes in at the other.
2184
+ let s = S + Int(code[at + 7])
2185
+ for fk in 0..<fc {
2186
+ for l in 0..<lanes {
2187
+ let el = fk * V + l
2188
+ let t = Self.index(a[el], sampleLengths.count)
2189
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
2190
+ let A = samplePointers[t]
2191
+ let base = 0
2192
+ if s[2 * L + l] != trigger[l] {
2193
+ s[2 * L + l] = trigger[l]
2194
+ let start = c[el]
2195
+ let p = (start > 0 ? (start < 1 ? start : 1) : 0) * Float(length - 1)
2196
+ s[l] = p.rounded(.down)
2197
+ s[L + l] = p - p.rounded(.down)
2198
+ }
2199
+ // Always a sample of this one, though a lane's index may change samples under it.
2200
+ let index = ((Int(s[l]) % length) + length) % length
2201
+ let fraction = s[L + l]
2202
+ let k = base + index
2203
+ let after = index < length - 1 ? A[k + 1] : A[base]
2204
+ d[el] = A[k] + (after - A[k]) * fraction
2205
+ var step = b[el] * (sampleRatios.isEmpty ? 1 : sampleRatios[t])
2206
+ step = step > -65536 ? (step < 65536 ? step : 65536) : -65536
2207
+ let next = fraction + step
2208
+ let whole = next.rounded(.down)
2209
+ s[l] = Float((((index + Int(whole)) % length) + length) % length)
2210
+ s[L + l] = next - whole
2211
+ }
2212
+ }
2213
+ case 54:
2214
+ // grains(sample, position, density, length, pitch): a grain every 1 / density seconds from position
2215
+ // (0 … 1 along the sample, and up to 20 ms on), length seconds (0.001 … 1) long, at pitch (1/16 …
2216
+ // 16, 1 its own), under a parabola; up to 8 at once (with none free, one is skipped).
2217
+ let s = S + Int(code[at + 7])
2218
+ let lengthIn = register(5)
2219
+ let pitchIn = register(6)
2220
+ for fk in 0..<fc {
2221
+ for l in 0..<lanes {
2222
+ let el = fk * V + l
2223
+ let t = Self.index(a[el], sampleLengths.count)
2224
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
2225
+ let A = samplePointers[t]
2226
+ let base = 0
2227
+ let ratio = sampleRatios.isEmpty ? 1 : sampleRatios[t]
2228
+ let density = c[el]
2229
+ var countdown = s[l]
2230
+ if density > 0 {
2231
+ if countdown <= 0 {
2232
+ var g = 0
2233
+ while g < 8 && s[(3 + 4 * g) * L + l] < s[(4 + 4 * g) * L + l] { g += 1 }
2234
+ if g < 8 {
2235
+ let random = UnsafeMutableRawPointer(s + L + l)
2236
+ var x = random.load(as: UInt32.self)
2237
+ x ^= x << 13
2238
+ x ^= x >> 17
2239
+ x ^= x << 5
2240
+ random.storeBytes(of: x, as: UInt32.self)
2241
+ let position = b[el]
2242
+ let spray = sampleSprays.isEmpty ? 1 : sampleSprays[t]
2243
+ let start = ((position > 0 ? (position < 1 ? position : 1) : 0) * Float(length - 1)).rounded(.down) + Float(x % spray)
2244
+ let seconds = lengthIn[el]
2245
+ let frames = ((seconds > 0.001 ? (seconds < 1 ? seconds : 1) : 0.001) * sr).rounded(.down)
2246
+ let pitch = pitchIn[el]
2247
+ let w = s + (2 + 4 * g) * L + l
2248
+ w[0] = start < Float(length - 1) ? start : Float(length - 1)
2249
+ w[L] = 0
2250
+ w[2 * L] = frames > 1 ? frames : 1
2251
+ w[3 * L] = (pitch > 0.0625 ? (pitch < 16 ? pitch : 16) : 0.0625) * ratio
2252
+ }
2253
+ let interval = sr / density
2254
+ countdown += interval > 1 ? interval : 1
2255
+ }
2256
+ countdown -= 1
2257
+ } else {
2258
+ countdown = 0
2259
+ }
2260
+ s[l] = countdown
2261
+ var sum: Float = 0
2262
+ for g in 0..<8 {
2263
+ let w = s + (2 + 4 * g) * L + l
2264
+ let age = w[L]
2265
+ let frames = w[2 * L]
2266
+ guard age < frames else { continue }
2267
+ let offset = age * w[3 * L]
2268
+ let whole = offset.rounded(.down)
2269
+ let index = w[0] + whole
2270
+ if index >= 0 && index < Float(length - 1) {
2271
+ let k = base + Int(index)
2272
+ let v = A[k] + (A[k + 1] - A[k]) * (offset - whole)
2273
+ let phase = age / frames
2274
+ sum += v * (4 * phase * (1 - phase))
2275
+ }
2276
+ w[L] = age + 1
2277
+ }
2278
+ d[el] = sum
2279
+ }
2280
+ }
2281
+ case 57:
2282
+ // modsum(routes): Σ amount × source over the list, route by route. An amount is a parameter, the same
2283
+ // in every lane, so a route at 0 is passed over once for all of them and costs nothing.
2284
+ each { d[$0] = 0 }
2285
+ let index = Self.index(a[0], routeCount)
2286
+ guard index < routeCount else { break }
2287
+ var k = index * DSPProgram.routesMax
2288
+ let end = k + routeCounts[index]
2289
+ while k < end {
2290
+ let amount = R + routeRegisters[k + 1]
2291
+ let source = R + routeRegisters[k] + (routeState[k] ? 0 : shift)
2292
+ k += 2
2293
+ if amount[0] == 0 { continue }
2294
+ each { d[$0] += amount[$0] * source[$0] }
2295
+ }
2296
+ case 55:
2297
+ // smooth(input, seconds): toward the input by 1 − e^(−1 / (seconds × sampleRate)) a frame, from where
2298
+ // the input is on its first.
2299
+ let s = S + Int(code[at + 7])
2300
+ for fk in 0..<fc {
2301
+ for l in 0..<lanes {
2302
+ let el = fk * V + l
2303
+ let x = a[el]
2304
+ var y = s[l]
2305
+ if y.isNaN { y = x }
2306
+ let time = b[el]
2307
+ if !(s[L + l] == time) {
2308
+ s[L + l] = time
2309
+ let frames = time * sr
2310
+ s[2 * L + l] = frames > 1 ? -Foundation.expm1(-1 / frames) : 1
2311
+ }
2312
+ y += (x - y) * s[2 * L + l]
2313
+ s[l] = y
2314
+ d[el] = y
2315
+ }
2316
+ }
2317
+ case 56:
2318
+ // hold(input, trigger): takes the input as the trigger rises above 0.5, and keeps it.
2319
+ let s = S + Int(code[at + 7])
2320
+ for fk in 0..<fc {
2321
+ for l in 0..<lanes {
2322
+ let el = fk * V + l
2323
+ let t = b[el]
2324
+ if t > 0.5 && !(s[L + l] > 0.5) { s[l] = a[el] }
2325
+ s[L + l] = t
2326
+ d[el] = s[l]
503
2327
  }
504
- let a1 = s[4 * L + l]
505
- let a2 = s[5 * L + l]
506
- let a3 = s[6 * L + l]
507
- let ic1 = s[l]
508
- let ic2 = s[L + l]
509
- let x = a[l]
510
- let v3 = x - ic2
511
- let v1 = a1 * ic1 + a2 * v3
512
- let v2 = ic2 + a2 * ic1 + a3 * v3
513
- s[l] = 2 * v1 - ic1
514
- s[L + l] = 2 * v2 - ic2
515
- d[l] = op == 47 ? v2 : op == 49 ? v1 : x - s[7 * L + l] * v1 - v2
516
2328
  }
517
2329
  default:
518
2330
  break
519
2331
  }
520
- at += 8
521
2332
  }
522
2333
  }
523
2334
  }
2335
+
2336
+ /// Memory a machine reads (a table's samples, a shape's points, a sample's audio), made off the audio thread and
2337
+ /// swapped into a machine whole (`replaceTable` …). After a swap it holds what the machine let go of: freed with it,
2338
+ /// off the audio thread.
2339
+ /// A fixed number of values in memory of their own, each changed in place: what the machine reads as it renders and
2340
+ /// swaps when data is replaced, with no exclusivity checks (as an array property changed in place would need).
2341
+ struct Slots<Element> {
2342
+ let base: UnsafeMutablePointer<Element>
2343
+ let count: Int
2344
+
2345
+ init(_ values: [Element]) {
2346
+ count = values.count
2347
+ base = .allocate(capacity: Swift.max(1, values.count))
2348
+ base.initialize(from: values, count: values.count)
2349
+ }
2350
+
2351
+ var isEmpty: Bool { count == 0 }
2352
+
2353
+ subscript(i: Int) -> Element {
2354
+ get { base[i] }
2355
+ nonmutating set { base[i] = newValue }
2356
+ }
2357
+
2358
+ func deallocate() {
2359
+ base.deinitialize(count: count)
2360
+ base.deallocate()
2361
+ }
2362
+ }
2363
+
2364
+ public final class DSPBuffer: @unchecked Sendable {
2365
+ public fileprivate(set) var pointer: UnsafeMutablePointer<Float>
2366
+ public fileprivate(set) var count: Int
2367
+
2368
+ /// `values`, copied.
2369
+ public init(_ values: [Float]) {
2370
+ let pointer = UnsafeMutablePointer<Float>.allocate(capacity: Swift.max(1, values.count))
2371
+ pointer.initialize(repeating: 0, count: Swift.max(1, values.count))
2372
+ values.withUnsafeBufferPointer { if let base = $0.baseAddress { pointer.update(from: base, count: values.count) } }
2373
+ self.pointer = pointer
2374
+ count = values.count
2375
+ }
2376
+
2377
+ fileprivate init(taking pointer: UnsafeMutablePointer<Float>, count: Int) {
2378
+ self.pointer = pointer
2379
+ self.count = count
2380
+ }
2381
+
2382
+ deinit {
2383
+ pointer.deallocate()
2384
+ }
2385
+ }