@swiftbrowser/native 0.19.0 → 0.21.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 (64) 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 +122 -19
  35. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ScopeView.swift +79 -0
  36. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Machine.swift +1247 -209
  37. package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Program.swift +314 -19
  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/Drawing.swift +378 -0
  51. package/swift/Sources/SwiftBrowserNative/Views/Kinds/Navigation.swift +15 -10
  52. package/swift/Sources/SwiftBrowserNative/Views/Kinds/PopTap.swift +31 -28
  53. package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +142 -0
  54. package/swift/Sources/SwiftBrowserProtocol/Drawing.swift +306 -0
  55. package/swift/Sources/SwiftBrowserProtocol/Props.swift +5 -2
  56. package/swift/Sources/SwiftBrowserProtocol/RendererEvent.swift +24 -3
  57. package/swift/Sources/SwiftBrowserProtocol/Style.swift +87 -0
  58. package/wasm/SwiftBrowserNative.wasm +2 -2
  59. package/dist/native.d.ts +0 -19
  60. package/dist/native.d.ts.map +0 -1
  61. package/dist/native.js +0 -17
  62. package/dist/native.js.map +0 -1
  63. package/src/native.ts +0 -35
  64. package/swift/Sources/SwiftBrowserNative/Runtime/NativeRegistry.swift +0 -53
@@ -17,13 +17,44 @@ 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 the compiler marks), which runs
44
+ /// 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>
@@ -32,6 +63,13 @@ public final class DSPMachine: @unchecked Sendable {
32
63
  private let blockCount: Int
33
64
  private let sampleCode: UnsafeMutablePointer<Int32>
34
65
  private let sampleCount: Int
66
+ private let masterCode: UnsafeMutablePointer<Int32>
67
+ private let masterCount: Int
68
+ /// The parts of `sample` and `master` that run frame by frame, in instructions.
69
+ private let sampleSerial: Range<Int>
70
+ private let masterSerial: Range<Int>
71
+ /// Per instance: whether the master stage runs it.
72
+ private let instanceMaster: [Bool]
35
73
  /// Each instance's builtin and where its state starts (in floats, lanes included; a noise instance's in `noise`).
36
74
  private let instanceKinds: [DSPBuiltin]
37
75
  private let instanceOffsets: [Int]
@@ -42,6 +80,36 @@ public final class DSPMachine: @unchecked Sendable {
42
80
  private let parameterIndices: [String: Int]
43
81
  private let targets: UnsafeMutablePointer<Float>
44
82
  private var snapped = true
83
+ /// The wavetables' samples (table, level, 2048 samples, each its frames side by side), where each table starts
84
+ /// and its frames.
85
+ private let tableSamples: UnsafeMutablePointer<Float>
86
+ private let tableCount: Int
87
+ /// Envelopes' curves (attack, decay, release exponents), three a curve; an `adsr` names its curve in slot 11.
88
+ private let curveExponents: [Float]
89
+ private let tableBases: [Int]
90
+ private let tableFrames: [Int]
91
+ /// The delays' samples: each instance's buffer per lane, a power of two long; by instance, where it starts and its length.
92
+ private let delaySamples: UnsafeMutablePointer<Float>
93
+ private let delaySampleCount: Int
94
+ private let delayBases: [Int]
95
+ private let delayLengths: [Int]
96
+ /// The shapes' points, one after another; where each starts and its length.
97
+ private let shapePoints: UnsafeMutablePointer<Float>
98
+ private let shapeBases: [Int]
99
+ private let shapeLengths: [Int]
100
+ /// The samples' audio, one after another; per sample where it starts, its length, its frames a frame at this
101
+ /// rate, and its spray (20 ms) in frames.
102
+ private let sampleAudio: UnsafeMutablePointer<Float>
103
+ private let sampleBases: [Int]
104
+ private let sampleLengths: [Int]
105
+ private let sampleRatios: [Float]
106
+ private let sampleSprays: [UInt32]
107
+ /// `modsum`'s route lists one after another, as register offsets (× `width`): a source's, then its amount's, pair
108
+ /// after pair; list i is `routeStarts[i] ..< routeStarts[i + 1]`.
109
+ private let routeRegisters: UnsafeMutablePointer<Int>
110
+ /// Whether each route's register is state (one value a lane, not one a frame).
111
+ private let routeState: UnsafeMutablePointer<Bool>
112
+ private let routeStarts: [Int]
45
113
 
46
114
  private let laneNote: UnsafeMutablePointer<Int32>
47
115
  private let laneGate: UnsafeMutablePointer<Float>
@@ -50,31 +118,60 @@ public final class DSPMachine: @unchecked Sendable {
50
118
  private let laneActive: UnsafeMutablePointer<Float>
51
119
  private let laneAge: UnsafeMutablePointer<Double>
52
120
  private let trigger: UnsafeMutablePointer<Float>
121
+ /// The master stage's trigger: counts the notes (as the voice a mono program's starts over at).
122
+ private let masterTrigger: UnsafeMutablePointer<Float>
123
+ /// The lane of the newest note, for a master stage that reads it (-1 before the first).
124
+ private var newestLane = -1
53
125
  private var age: Double = 0
54
126
  private var pedal = false
55
127
  private var bend: Double = 0
128
+ private var tempo: Double = 120
129
+ private var beat: Double = 0
130
+ /// A mono program's held notes, oldest first.
131
+ private let stack: UnsafeMutablePointer<Int32>
132
+ private var stackCount = 0
133
+ /// Events waiting for their beat, soonest first: the beat, then the kind (note on, note off, controller,
134
+ /// bend) and two values.
135
+ private static let queueCapacity = 1024
136
+ private let queueBeat: UnsafeMutablePointer<Double>
137
+ private let queueEvent: UnsafeMutablePointer<Int32>
138
+ private var queueCount = 0
56
139
 
57
140
  public init(program: DSPProgram, sampleRate: Double) {
58
141
  let L = Self.lanes
59
142
  self.program = program
60
143
  self.sampleRate = Float(sampleRate)
61
- registers = .allocate(capacity: program.registers * L)
62
- registers.initialize(repeating: 0, count: program.registers * L)
144
+ let W = program.voices * Self.frames
145
+ width = W
146
+ registers = .allocate(capacity: program.registers * W)
147
+ registers.initialize(repeating: 0, count: program.registers * W)
148
+ let stateRegisters = Set(program.state.map(\.register))
149
+ var isMaster = [Bool](repeating: false, count: program.instances.count)
150
+ if let master = program.master {
151
+ var pc = 0
152
+ while pc < master.code.count {
153
+ let op = DSPOpcode(rawValue: master.code[pc])!
154
+ if op.builtin != nil { isMaster[Int(master.code[pc + 2 + op.arity])] = true }
155
+ pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
156
+ }
157
+ }
158
+ instanceMaster = isMaster
63
159
  var kinds: [DSPBuiltin] = []
64
160
  var offsets: [Int] = []
65
161
  var envelopes: [Int] = []
66
162
  var filters: [Int] = []
67
163
  var words = 0
68
164
  var noises = 0
69
- for builtin in program.instances {
165
+ for (i, builtin) in program.instances.enumerated() {
70
166
  kinds.append(builtin)
71
167
  if builtin == .noise {
72
168
  offsets.append(noises * L)
73
169
  noises += 1
74
170
  } else {
75
171
  offsets.append(words * L)
76
- if builtin == .adsr { envelopes.append(words * L) }
77
- if builtin == .lowpass || builtin == .highpass || builtin == .bandpass { filters.append(words * L) }
172
+ if builtin == .adsr && !isMaster[i] { envelopes.append(words * L) }
173
+ // The filters' integrators, a one-pole's, a DC blocker's and a comb's loop.
174
+ if [.lowpass, .highpass, .bandpass, .onepole, .dcblock, .comb].contains(builtin) { filters.append(words * L) }
78
175
  words += builtin.words
79
176
  }
80
177
  }
@@ -88,19 +185,67 @@ public final class DSPMachine: @unchecked Sendable {
88
185
  noiseCount = max(1, noises) * L
89
186
  noise = .allocate(capacity: noiseCount)
90
187
  noise.initialize(repeating: 1, count: noiseCount)
91
- (blockCode, blockCount) = Self.decode(program.block, offsets: offsets)
92
- (sampleCode, sampleCount) = Self.decode(program.sample, offsets: offsets)
188
+ (tableSamples, tableBases, tableFrames) = Self.buildTables(program.tables)
189
+ tableCount = program.tables.count
190
+ (shapePoints, shapeBases, shapeLengths) = Self.concatenate(program.shapes.map(\.points))
191
+ (sampleAudio, sampleBases, sampleLengths) = Self.concatenate(program.samples.map(\.data))
192
+ sampleRatios = program.samples.map { Float($0.rate / Double(Float(sampleRate))) }
193
+ routeStarts = program.routes.reduce(into: [0]) { starts, list in starts.append(starts.last! + list.count) }
194
+ routeRegisters = .allocate(capacity: Swift.max(1, routeStarts.last!))
195
+ routeState = .allocate(capacity: Swift.max(1, routeStarts.last!))
196
+ routeState.initialize(repeating: false, count: Swift.max(1, routeStarts.last!))
197
+ for (i, list) in program.routes.enumerated() {
198
+ for (k, r) in list.enumerated() {
199
+ routeRegisters[routeStarts[i] + k] = r * W
200
+ routeState[routeStarts[i] + k] = stateRegisters.contains(r)
201
+ }
202
+ }
203
+ sampleSprays = program.samples.map { UInt32(Swift.max(1, ($0.rate * 0.02).rounded(.down))) }
204
+ // Each delay's buffer: its longest time (a constant register) at this sample rate, rounded up to a power of
205
+ // two, per voice (the master stage's, once).
206
+ let constantValues = Dictionary(program.constants.map { ($0.register, $0.value) }, uniquingKeysWith: { _, last in last })
207
+ var bases = [Int](repeating: 0, count: program.instances.count)
208
+ var lengths = [Int](repeating: 0, count: program.instances.count)
209
+ var delayTotal = 0
210
+ for code in [program.sample, program.master?.code ?? []] {
211
+ var pc = 0
212
+ while pc < code.count {
213
+ let op = DSPOpcode(rawValue: code[pc])!
214
+ if let longestAt = op.longest {
215
+ let instance = Int(code[pc + 2 + op.arity])
216
+ let longest = Double(Swift.min(Swift.max(constantValues[Int(code[pc + 1 + longestAt])] ?? 1, 0), 2))
217
+ var length = 4
218
+ while Double(length) < (longest * Double(Float(sampleRate))).rounded(.up) + 2 { length *= 2 }
219
+ bases[instance] = delayTotal
220
+ lengths[instance] = length
221
+ delayTotal += length * (isMaster[instance] ? 1 : L)
222
+ }
223
+ pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
224
+ }
225
+ }
226
+ delayBases = bases
227
+ delayLengths = lengths
228
+ delaySampleCount = Swift.max(1, delayTotal)
229
+ delaySamples = .allocate(capacity: delaySampleCount)
230
+ delaySamples.initialize(repeating: 0, count: delaySampleCount)
231
+ curveExponents = program.curves.flatMap { [$0.attack, $0.decay, $0.release] }
232
+ let curves = Dictionary(program.curves.enumerated().map { ($1.instance, $0 + 1) }, uniquingKeysWith: { _, last in last })
233
+ (blockCode, blockCount, _) = Self.decode(program.block, nil, width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
234
+ (sampleCode, sampleCount, sampleSerial) = Self.decode(
235
+ program.sample, program.serial, width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
236
+ (masterCode, masterCount, masterSerial) = Self.decode(
237
+ program.master?.code ?? [], program.master?.serial, width: W, state: stateRegisters, offsets: offsets, delays: (bases, lengths), curves: curves)
93
238
  for constant in program.constants {
94
- (registers + constant.register * L).update(repeating: constant.value, count: L)
239
+ (registers + constant.register * W).update(repeating: constant.value, count: W)
95
240
  }
96
- registers.update(repeating: Float(sampleRate), count: L)
241
+ registers.update(repeating: Float(sampleRate), count: W)
97
242
  parameterRegisters = program.parameters.map(\.register)
98
243
  parameterRanges = program.parameters.map { ($0.min, $0.max) }
99
244
  parameterIndices = Dictionary(program.parameters.enumerated().map { ($1.name, $0) }, uniquingKeysWith: { first, _ in first })
100
245
  targets = .allocate(capacity: max(1, program.parameters.count))
101
246
  for (i, parameter) in program.parameters.enumerated() {
102
247
  targets[i] = parameter.defaultValue
103
- (registers + parameter.register * L).update(repeating: parameter.defaultValue, count: L)
248
+ (registers + parameter.register * W).update(repeating: parameter.defaultValue, count: W)
104
249
  }
105
250
  laneNote = .allocate(capacity: L)
106
251
  laneNote.initialize(repeating: -1, count: L)
@@ -116,37 +261,187 @@ public final class DSPMachine: @unchecked Sendable {
116
261
  laneAge.initialize(repeating: 0, count: L)
117
262
  trigger = .allocate(capacity: L)
118
263
  trigger.initialize(repeating: 0, count: L)
264
+ masterTrigger = .allocate(capacity: 1)
265
+ masterTrigger.initialize(to: 1)
266
+ stack = .allocate(capacity: L)
267
+ stack.initialize(repeating: 0, count: L)
268
+ queueBeat = .allocate(capacity: Self.queueCapacity)
269
+ queueBeat.initialize(repeating: 0, count: Self.queueCapacity)
270
+ queueEvent = .allocate(capacity: Self.queueCapacity * 3)
271
+ queueEvent.initialize(repeating: 0, count: Self.queueCapacity * 3)
119
272
  for lane in 0..<L { resetLane(lane) }
273
+ resetMaster()
120
274
  }
121
275
 
122
276
  deinit {
123
- for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger] { pointer.deallocate() }
277
+ for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger, masterTrigger, shapePoints, sampleAudio] { pointer.deallocate() }
124
278
  noise.deallocate()
279
+ routeRegisters.deallocate()
280
+ routeState.deallocate()
281
+ tableSamples.deallocate()
282
+ delaySamples.deallocate()
125
283
  blockCode.deallocate()
126
284
  sampleCode.deallocate()
285
+ masterCode.deallocate()
127
286
  laneNote.deallocate()
287
+ stack.deallocate()
288
+ queueBeat.deallocate()
289
+ queueEvent.deallocate()
128
290
  laneHeld.deallocate()
129
291
  laneAge.deallocate()
130
292
  }
131
293
 
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) {
294
+ /// Instructions at a stride of 12 (op, destination, five operands, state offset, which of slots 1 … 6 are state
295
+ /// registers as bits, then a delay line's buffer: where it starts and its length, then an envelope's curve, 1 up,
296
+ /// 0 for none), registers as offsets into the file. With the serial part's word offsets, its instructions.
297
+ private static func decode(
298
+ _ code: [Int32], _ serial: Range<Int>?, width: Int, state: Set<Int>, offsets: [Int], delays: (bases: [Int], lengths: [Int]),
299
+ curves: [Int: Int]
300
+ ) -> (UnsafeMutablePointer<Int32>, Int, Range<Int>) {
134
301
  var out: [Int32] = []
302
+ var from = 0
303
+ var to = 0
135
304
  var pc = 0
136
305
  while pc < code.count {
306
+ if pc == serial?.lowerBound { from = out.count / 12 }
307
+ if pc == serial?.upperBound { to = out.count / 12 }
137
308
  let op = DSPOpcode(rawValue: code[pc])!
138
- var slot = [Int32](repeating: 0, count: 8)
309
+ var slot = [Int32](repeating: 0, count: 12)
139
310
  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) }
311
+ for k in 0..<(1 + op.arity) {
312
+ let register = Int(code[pc + 1 + k])
313
+ slot[1 + k] = Int32(register * width)
314
+ if state.contains(register) { slot[8] |= 1 << (1 + k) }
315
+ }
142
316
  if op.builtin != nil { slot[7] = Int32(offsets[Int(code[pc + 2 + op.arity])]) }
317
+ if op == .adsr { slot[11] = Int32(curves[Int(code[pc + 2 + op.arity])] ?? 0) }
318
+ if op.longest != nil {
319
+ let instance = Int(code[pc + 2 + op.arity])
320
+ slot[9] = Int32(delays.bases[instance])
321
+ slot[10] = Int32(delays.lengths[instance])
322
+ }
143
323
  out += slot
144
324
  pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
145
325
  }
146
- let pointer = UnsafeMutablePointer<Int32>.allocate(capacity: max(8, out.count))
147
- pointer.initialize(repeating: 0, count: max(8, out.count))
326
+ if pc == serial?.lowerBound { from = out.count / 12 }
327
+ if pc == serial?.upperBound { to = out.count / 12 }
328
+ let pointer = UnsafeMutablePointer<Int32>.allocate(capacity: max(12, out.count))
329
+ pointer.initialize(repeating: 0, count: max(12, out.count))
148
330
  out.withUnsafeBufferPointer { pointer.update(from: $0.baseAddress!, count: out.count) }
149
- return (pointer, out.count / 8)
331
+ return (pointer, out.count / 12, from..<to)
332
+ }
333
+
334
+ /// Lists one after another: where each starts and its length.
335
+ private static func concatenate(_ lists: [[Float]]) -> (UnsafeMutablePointer<Float>, [Int], [Int]) {
336
+ let total = Swift.max(1, lists.reduce(0) { $0 + $1.count })
337
+ let pointer = UnsafeMutablePointer<Float>.allocate(capacity: total)
338
+ pointer.initialize(repeating: 0, count: total)
339
+ var bases: [Int] = []
340
+ var at = 0
341
+ for list in lists {
342
+ bases.append(at)
343
+ list.withUnsafeBufferPointer { (pointer + at).update(from: $0.baseAddress!, count: list.count) }
344
+ at += list.count
345
+ }
346
+ return (pointer, bases, lists.map(\.count))
347
+ }
348
+
349
+ /// The wavetables' samples: per table, per frame, per level (level n keeps the harmonics up to 512 >> n), 2048
350
+ /// samples from an inverse FFT of the frame's sine harmonics (and cosine ones, when it has them) in doubles, stored as floats, a level's samples in
351
+ /// order with each sample's frames side by side: the JavaScript machine's `buildTables`, step for step.
352
+ private static func buildTables(_ tables: [DSPProgram.Table]) -> (UnsafeMutablePointer<Float>, [Int], [Int]) {
353
+ let N = DSPProgram.tableFrame
354
+ let levels = DSPProgram.tableLevels
355
+ let frameCount = tables.reduce(0) { $0 + $1.frames.count }
356
+ let count = Swift.max(1, frameCount * levels * N)
357
+ let samples = UnsafeMutablePointer<Float>.allocate(capacity: count)
358
+ samples.initialize(repeating: 0, count: count)
359
+ var bases: [Int] = []
360
+ var frames: [Int] = []
361
+ var cosT = [Double](repeating: 0, count: N / 2)
362
+ var sinT = [Double](repeating: 0, count: N / 2)
363
+ for j in 0..<(N / 2) {
364
+ cosT[j] = Foundation.cos(2 * Double.pi * Double(j) / Double(N))
365
+ sinT[j] = Foundation.sin(2 * Double.pi * Double(j) / Double(N))
366
+ }
367
+ var re = [Double](repeating: 0, count: N)
368
+ var im = [Double](repeating: 0, count: N)
369
+ var at = 0
370
+ for table in tables {
371
+ bases.append(at)
372
+ let count = table.frames.count
373
+ frames.append(count)
374
+ // A level's samples one after another, each its frames side by side: a read between two samples and two
375
+ // frames is one span of memory.
376
+ func store(_ level: Int, _ n: Int, _ f: Int) -> Int { at + (level * N + n) * count + f }
377
+ for (f, amplitudes) in table.frames.enumerated() {
378
+ for level in 0..<levels {
379
+ let limit = Swift.min(512 >> level, amplitudes.count)
380
+ if level > 0 && limit == Swift.min(512 >> (level - 1), amplitudes.count) {
381
+ // No harmonic dropped: the level above's samples.
382
+ for n in 0..<N { samples[store(level, n, f)] = samples[store(level - 1, n, f)] }
383
+ continue
384
+ }
385
+ for i in 0..<N {
386
+ re[i] = 0
387
+ im[i] = 0
388
+ }
389
+ // sin(kθ) = (e^{ikθ} − e^{−ikθ}) / 2i
390
+ if limit >= 1 {
391
+ for k in 1...limit {
392
+ let a = Double(amplitudes[k - 1])
393
+ im[k] = -a / 2
394
+ im[N - k] = a / 2
395
+ }
396
+ // cos(kθ) = (e^{ikθ} + e^{−ikθ}) / 2
397
+ if let cosines = table.cosines?[f] {
398
+ for k in 1...limit {
399
+ let c = Double(cosines[k - 1])
400
+ re[k] = c / 2
401
+ re[N - k] = c / 2
402
+ }
403
+ }
404
+ }
405
+ // Bit reversal, then radix-2 butterflies with e^{+2πij/len}.
406
+ var j = 0
407
+ for i in 1..<N {
408
+ var bit = N >> 1
409
+ while j & bit != 0 {
410
+ j ^= bit
411
+ bit >>= 1
412
+ }
413
+ j ^= bit
414
+ if i < j {
415
+ re.swapAt(i, j)
416
+ im.swapAt(i, j)
417
+ }
418
+ }
419
+ var len = 2
420
+ while len <= N {
421
+ let half = len >> 1
422
+ let step = N / len
423
+ var i = 0
424
+ while i < N {
425
+ for k in 0..<half {
426
+ let wr = cosT[k * step]
427
+ let wi = sinT[k * step]
428
+ let xr = re[i + k + half] * wr - im[i + k + half] * wi
429
+ let xi = re[i + k + half] * wi + im[i + k + half] * wr
430
+ re[i + k + half] = re[i + k] - xr
431
+ im[i + k + half] = im[i + k] - xi
432
+ re[i + k] = re[i + k] + xr
433
+ im[i + k] = im[i + k] + xi
434
+ }
435
+ i += len
436
+ }
437
+ len <<= 1
438
+ }
439
+ for n in 0..<N { samples[store(level, n, f)] = Float(re[n]) }
440
+ }
441
+ }
442
+ at += count * levels * N
443
+ }
444
+ return (samples, bases, frames)
150
445
  }
151
446
 
152
447
  // MARK: Events
@@ -162,10 +457,119 @@ public final class DSPMachine: @unchecked Sendable {
162
457
  targets[index] = Swift.min(Swift.max(value, parameterRanges[index].min), parameterRanges[index].max)
163
458
  }
164
459
 
165
- /// MIDI note on: `velocity` 1 … 127 (0 is a note off).
166
- public func noteOn(_ note: Int32, velocity: Int32) {
460
+ /// The transport's tempo, in beats a minute (1 … 999), from the next block.
461
+ public func setTempo(_ bpm: Double) {
462
+ if bpm.isFinite { tempo = Swift.min(Swift.max(bpm, 1), 999) }
463
+ }
464
+
465
+ /// Moves the transport to `beat`.
466
+ public func seek(toBeat beat: Double) {
467
+ if beat.isFinite { self.beat = beat }
468
+ }
469
+
470
+ /// Where the transport is, in beats.
471
+ public var position: Double { beat }
472
+
473
+ /// MIDI note on: `velocity` 1 … 127 (0 is a note off); at `atBeat` on the transport, or at the next block. False
474
+ /// when too many wait.
475
+ @discardableResult
476
+ public func noteOn(_ note: Int32, velocity: Int32, atBeat: Double? = nil) -> Bool {
477
+ if let atBeat { return schedule(atBeat, 0, note, velocity) }
478
+ start(note, velocity: velocity)
479
+ return true
480
+ }
481
+
482
+ /// MIDI note off; at `atBeat` on the transport, or at the next block.
483
+ @discardableResult
484
+ public func noteOff(_ note: Int32, atBeat: Double? = nil) -> Bool {
485
+ if let atBeat { return schedule(atBeat, 1, note, 0) }
486
+ release(note)
487
+ return true
488
+ }
489
+
490
+ /// 64 the sustain pedal, 120 all sound off, 123 all notes off (both dropping what waits); at `atBeat`, or at the
491
+ /// next block.
492
+ @discardableResult
493
+ public func controller(_ number: Int32, value: Int32, atBeat: Double? = nil) -> Bool {
494
+ if let atBeat { return schedule(atBeat, 2, number, value) }
495
+ if number == 120 || number == 123 { queueCount = 0 }
496
+ control(number, value: value)
497
+ return true
498
+ }
499
+
500
+ /// The pitch wheel, 0 … 16383, 8192 centered: ±2 semitones; at `atBeat`, or at the next block.
501
+ @discardableResult
502
+ public func pitchBend(_ value: Int32, atBeat: Double? = nil) -> Bool {
503
+ if let atBeat { return schedule(atBeat, 3, value, 0) }
504
+ bend = Double(Swift.min(16383, Swift.max(0, value)) - 8192) / 8192 * 2
505
+ return true
506
+ }
507
+
508
+ /// Puts an event in the queue after those at or before its beat.
509
+ private func schedule(_ beat: Double, _ kind: Int32, _ a: Int32, _ b: Int32) -> Bool {
510
+ guard beat.isFinite, queueCount < Self.queueCapacity else { return false }
511
+ var at = queueCount
512
+ while at > 0 && queueBeat[at - 1] > beat { at -= 1 }
513
+ (queueBeat + at + 1).update(from: queueBeat + at, count: queueCount - at)
514
+ (queueEvent + (at + 1) * 3).update(from: queueEvent + at * 3, count: (queueCount - at) * 3)
515
+ queueBeat[at] = beat
516
+ queueEvent[at * 3] = kind
517
+ queueEvent[at * 3 + 1] = a
518
+ queueEvent[at * 3 + 2] = b
519
+ queueCount += 1
520
+ return true
521
+ }
522
+
523
+ /// Applies what is due: each event whose beat is nearer this frame than the next.
524
+ private func applyDue(_ step: Double) {
525
+ while queueCount > 0 && queueBeat[0] < beat + step / 2 {
526
+ let kind = queueEvent[0]
527
+ let a = queueEvent[1]
528
+ let b = queueEvent[2]
529
+ queueBeat.update(from: queueBeat + 1, count: queueCount - 1)
530
+ queueEvent.update(from: queueEvent + 3, count: (queueCount - 1) * 3)
531
+ queueCount -= 1
532
+ switch kind {
533
+ case 0: start(a, velocity: b)
534
+ case 1: release(a)
535
+ case 2: control(a, value: b)
536
+ default: pitchBend(a)
537
+ }
538
+ }
539
+ }
540
+
541
+ /// Frames to the next waiting event, at most a block's.
542
+ private func framesToNext(_ step: Double) -> Int {
543
+ let frames = ((queueBeat[0] - beat) / step).rounded()
544
+ return frames >= Double(DSPProgram.blockFrames) ? DSPProgram.blockFrames : Swift.max(1, Int(frames))
545
+ }
546
+
547
+ private func start(_ note: Int32, velocity: Int32) {
167
548
  if velocity <= 0 {
168
- noteOff(note)
549
+ release(note)
550
+ return
551
+ }
552
+ if let mode = program.mode {
553
+ // One voice: the newest note, legato while another is held.
554
+ unstack(note)
555
+ if stackCount == Self.lanes {
556
+ (stack).update(from: stack + 1, count: stackCount - 1)
557
+ stackCount -= 1
558
+ }
559
+ stack[stackCount] = note
560
+ stackCount += 1
561
+ let held = laneGate[0] > 0.5
562
+ if laneActive[0] == 0 { resetLane(0) }
563
+ laneNote[0] = note
564
+ laneGate[0] = 1
565
+ laneHeld[0] = false
566
+ laneVelocity[0] = Float(Double(Swift.min(127, velocity)) / 127)
567
+ laneActive[0] = 1
568
+ newestLane = 0
569
+ if mode == .mono || !held {
570
+ trigger[0] += 1
571
+ masterTrigger[0] += 1
572
+ }
169
573
  return
170
574
  }
171
575
  let voices = program.voices
@@ -191,19 +595,35 @@ public final class DSPMachine: @unchecked Sendable {
191
595
  laneVelocity[lane] = Float(Double(Swift.min(127, velocity)) / 127)
192
596
  laneActive[lane] = 1
193
597
  trigger[lane] += 1
598
+ masterTrigger[0] += 1
599
+ newestLane = lane
194
600
  age += 1
195
601
  laneAge[lane] = age
196
602
  }
197
603
 
198
- public func noteOff(_ note: Int32) {
604
+ private func release(_ note: Int32) {
605
+ if let mode = program.mode {
606
+ unstack(note)
607
+ guard laneNote[0] == note && laneGate[0] > 0.5 else { return }
608
+ if stackCount > 0 {
609
+ // Back to the note held before it.
610
+ laneNote[0] = stack[stackCount - 1]
611
+ laneHeld[0] = false
612
+ if mode == .mono { trigger[0] += 1 }
613
+ } else if pedal {
614
+ laneHeld[0] = true
615
+ } else {
616
+ laneGate[0] = 0
617
+ }
618
+ return
619
+ }
199
620
  for l in 0..<program.voices where laneNote[l] == note && laneGate[l] > 0.5 {
200
621
  // Under the pedal the gate stays up until it lifts.
201
622
  if pedal { laneHeld[l] = true } else { laneGate[l] = 0 }
202
623
  }
203
624
  }
204
625
 
205
- /// 64 the sustain pedal, 120 all sound off, 123 all notes off.
206
- public func controller(_ number: Int32, value: Int32) {
626
+ private func control(_ number: Int32, value: Int32) {
207
627
  let L = Self.lanes
208
628
  switch number {
209
629
  case 64:
@@ -215,24 +635,32 @@ public final class DSPMachine: @unchecked Sendable {
215
635
  case 123:
216
636
  laneGate.update(repeating: 0, count: L)
217
637
  laneHeld.update(repeating: false, count: L)
638
+ stackCount = 0
218
639
  case 120:
640
+ stackCount = 0
219
641
  for l in 0..<L {
220
642
  laneGate[l] = 0
221
643
  laneHeld[l] = false
222
644
  laneActive[l] = 0
223
645
  resetLane(l)
224
646
  }
647
+ resetMaster()
225
648
  default:
226
649
  break
227
650
  }
228
651
  }
229
652
 
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
653
+ /// Drops `note` from a mono program's held notes.
654
+ private func unstack(_ note: Int32) {
655
+ var kept = 0
656
+ for i in 0..<stackCount where stack[i] != note {
657
+ stack[kept] = stack[i]
658
+ kept += 1
659
+ }
660
+ stackCount = kept
233
661
  }
234
662
 
235
- /// Silences every voice at once.
663
+ /// Silences every voice, and the master stage, at once, and drops what waits.
236
664
  public func reset() {
237
665
  controller(120, value: 0)
238
666
  }
@@ -244,79 +672,202 @@ public final class DSPMachine: @unchecked Sendable {
244
672
 
245
673
  // MARK: Rendering
246
674
 
247
- /// Writes `frames` mono frames to `out`, in blocks of up to 128.
675
+ /// Writes `frames` frames to `out`, in blocks of up to 128: a program's two sides averaged (a mono program's
676
+ /// samples either way).
248
677
  public func render(into out: UnsafeMutablePointer<Float>, frames: Int) {
249
678
  var done = 0
250
679
  while done < frames {
251
- let n = Swift.min(DSPProgram.blockFrames, frames - done)
252
- block(out + done, n)
680
+ let step = tempo / 60 / Double(sampleRate)
681
+ applyDue(step)
682
+ // A block ends where the next event is due.
683
+ let n = Swift.min(DSPProgram.blockFrames, frames - done, queueCount > 0 ? framesToNext(step) : DSPProgram.blockFrames)
684
+ block(out + done, nil, n)
685
+ done += n
686
+ }
687
+ }
688
+
689
+ /// Writes `frames` frames, the left side to `left` and the right to `right`, in blocks of up to 128.
690
+ public func render(left: UnsafeMutablePointer<Float>, right: UnsafeMutablePointer<Float>, frames: Int) {
691
+ var done = 0
692
+ while done < frames {
693
+ let step = tempo / 60 / Double(sampleRate)
694
+ applyDue(step)
695
+ let n = Swift.min(DSPProgram.blockFrames, frames - done, queueCount > 0 ? framesToNext(step) : DSPProgram.blockFrames)
696
+ block(left + done, right + done, n)
253
697
  done += n
254
698
  }
255
699
  }
256
700
 
701
+ /// A voice starts over: its state and its builtins', not the master stage's.
257
702
  private func resetLane(_ l: Int) {
703
+ // A register holds the program's voices' lanes (a state register's value its lane's first frame).
704
+ if l < program.voices {
705
+ for entry in program.state where !entry.master { registers[entry.register * width + l] = entry.initial }
706
+ }
707
+ for i in instanceKinds.indices where !instanceMaster[i] { resetInstance(i, l) }
708
+ }
709
+
710
+ /// The master stage starts over, in lane 0.
711
+ private func resetMaster() {
712
+ for entry in program.state where entry.master { registers[entry.register * width] = entry.initial }
713
+ for i in instanceKinds.indices where instanceMaster[i] { resetInstance(i, 0) }
714
+ }
715
+
716
+ private func resetInstance(_ i: Int, _ l: Int) {
258
717
  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
- }
718
+ let kind = instanceKinds[i]
719
+ let base = instanceOffsets[i] + l
720
+ let seed = UInt32(truncatingIfNeeded: i + 1) &* 2_654_435_761 &+ UInt32(truncatingIfNeeded: l + 1) &* 2_246_822_519
721
+ if kind == .noise {
722
+ noise[base] = seed == 0 ? 1 : seed
723
+ return
724
+ }
725
+ for w in 0..<kind.words { state[base + w * L] = 0 }
726
+ if kind == .delay || kind == .comb || kind == .allpass {
727
+ (delaySamples + delayBases[i] + l * delayLengths[i]).update(repeating: 0, count: delayLengths[i])
728
+ }
729
+ if kind == .grains {
730
+ // Its random state, a word of raw bits.
731
+ UnsafeMutableRawPointer(state + base + L).storeBytes(of: seed == 0 ? 1 : seed, as: UInt32.self)
732
+ }
733
+ if kind == .adsr {
734
+ state[base + 4 * L] = .nan
735
+ state[base + 6 * L] = .nan
736
+ } else if kind.words == 8 {
737
+ state[base + 2 * L] = .nan
738
+ } else if kind == .smooth {
739
+ state[base] = .nan
740
+ state[base + L] = .nan
274
741
  }
275
742
  }
276
743
 
277
- private func block(_ out: UnsafeMutablePointer<Float>, _ n: Int) {
744
+ private func block(_ out: UnsafeMutablePointer<Float>, _ right: UnsafeMutablePointer<Float>?, _ n: Int) {
278
745
  let L = Self.lanes
746
+ let F = Self.frames
747
+ let W = width
279
748
  let R = registers
280
749
  let sr = sampleRate
281
750
  // Parameters glide toward their targets, about 20 ms.
282
751
  let alpha = snapped ? Float(1) : 1 - exp(-Float(n) / (0.02 * sr))
283
752
  snapped = false
284
753
  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)
754
+ let at = R + register * W
755
+ at.update(repeating: at[0] + (targets[i] - at[0]) * alpha, count: W)
287
756
  }
288
- var any = false
289
- for l in 0..<L where laneActive[l] != 0 { any = true }
290
- guard any else {
757
+ (R + 5 * W).update(repeating: Float(tempo), count: W)
758
+ let beatStep = tempo / 60 / Double(sr)
759
+ // The voices run up to the highest that sounds: a note takes the lowest free lane, and an idle one starts
760
+ // over before it sounds again, so what the ones above would compute is never heard.
761
+ var lanes = 0
762
+ for l in 0..<L where laneActive[l] != 0 { lanes = l + 1 }
763
+ let any = lanes > 0
764
+ let master = program.master
765
+ guard any || master != nil else {
766
+ beat += Double(n) * beatStep
291
767
  out.update(repeating: 0, count: n)
768
+ right?.update(repeating: 0, count: n)
292
769
  return
293
770
  }
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
771
+ if any {
772
+ let V = program.voices
773
+ for l in 0..<V {
774
+ let note = laneNote[l]
775
+ let freq = note >= 0 ? Float(440 * Foundation.pow(2, (Double(note) - 69 + bend) / 12)) : 0
776
+ for k in 0..<F {
777
+ R[1 * W + k * V + l] = freq
778
+ R[2 * W + k * V + l] = laneGate[l]
779
+ R[3 * W + k * V + l] = laneVelocity[l]
780
+ R[4 * W + k * V + l] = note >= 0 ? Float(note) : 0
781
+ }
782
+ }
783
+ run(blockCode, 0..<blockCount, lanes: lanes, trigger: trigger, frames: F)
784
+ }
785
+ if master != nil {
786
+ // The newest note, the master stage's inputs (registers 7 … 10), in lane 0.
787
+ let l = newestLane
788
+ let note = l >= 0 ? laneNote[l] : -1
789
+ let values: [Float] = [
790
+ note >= 0 ? Float(440 * Foundation.pow(2, (Double(note) - 69 + bend) / 12)) : 0,
791
+ l >= 0 ? laneGate[l] : 0,
792
+ l >= 0 ? laneVelocity[l] : 0,
793
+ note >= 0 ? Float(note) : 0,
794
+ ]
795
+ let V = program.voices
796
+ for (i, value) in values.enumerated() { for k in 0..<F { R[(7 + i) * W + k * V] = value } }
300
797
  }
301
- run(blockCode, blockCount)
302
- let o = R + program.output * L
798
+ let o = R + program.output * W
799
+ let or = R + (program.outputRight ?? program.output) * W
800
+ let V = program.voices
303
801
  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
802
+ // A chunk of up to 16 frames at a time: each instruction over all of them, the serial part frame by frame.
803
+ var chunk = 0
804
+ while chunk < n {
805
+ let fc = Swift.min(F, n - chunk)
806
+ for k in 0..<fc {
807
+ for l in 0..<Swift.max(lanes, 1) { R[6 * W + k * V + l] = Float(beat) }
808
+ beat += beatStep
809
+ }
810
+ if any {
811
+ run(sampleCode, 0..<sampleSerial.lowerBound, lanes: lanes, trigger: trigger, frames: fc)
812
+ if !sampleSerial.isEmpty {
813
+ for k in 0..<fc { run(sampleCode, sampleSerial, lanes: lanes, trigger: trigger, frames: 1, frame: k) }
814
+ }
815
+ run(sampleCode, sampleSerial.upperBound..<sampleCount, lanes: lanes, trigger: trigger, frames: fc)
816
+ }
817
+ for k in 0..<fc {
818
+ var leftSum: Float = 0
819
+ var rightSum: Float = 0
820
+ // The sounding voices only: an idle one may hold anything (log(0) of its freq, say), and NaN × 0 is NaN.
821
+ if any {
822
+ for l in 0..<lanes where laneActive[l] != 0 {
823
+ leftSum += o[k * V + l]
824
+ rightSum += or[k * V + l]
825
+ }
826
+ }
827
+ if let master {
828
+ R[master.inputs[0] * W + k * V] = leftSum
829
+ R[master.inputs[1] * W + k * V] = rightSum
830
+ } else {
831
+ if let right {
832
+ out[chunk + k] = leftSum
833
+ right[chunk + k] = rightSum
834
+ } else {
835
+ out[chunk + k] = (leftSum + rightSum) * 0.5
836
+ }
837
+ check += leftSum + rightSum
838
+ }
839
+ }
840
+ if let master {
841
+ run(masterCode, 0..<masterSerial.lowerBound, lanes: 1, trigger: masterTrigger, frames: fc)
842
+ if !masterSerial.isEmpty {
843
+ for k in 0..<fc { run(masterCode, masterSerial, lanes: 1, trigger: masterTrigger, frames: 1, frame: k) }
844
+ }
845
+ run(masterCode, masterSerial.upperBound..<masterCount, lanes: 1, trigger: masterTrigger, frames: fc)
846
+ for k in 0..<fc {
847
+ let leftSum = R[master.outputs[0] * W + k * V]
848
+ let rightSum = R[master.outputs[1] * W + k * V]
849
+ if let right {
850
+ out[chunk + k] = leftSum
851
+ right[chunk + k] = rightSum
852
+ } else {
853
+ out[chunk + k] = (leftSum + rightSum) * 0.5
854
+ }
855
+ check += leftSum + rightSum
856
+ }
857
+ }
858
+ chunk += fc
310
859
  }
311
860
  guard check.isFinite else {
312
- // A voice went to infinity or NaN: silence the block and start every voice over.
861
+ // A voice or the master stage went to infinity or NaN: silence the block and start everything over.
313
862
  out.update(repeating: 0, count: n)
863
+ right?.update(repeating: 0, count: n)
314
864
  for l in 0..<L {
315
865
  laneActive[l] = 0
316
866
  laneGate[l] = 0
317
867
  laneHeld[l] = false
318
868
  resetLane(l)
319
869
  }
870
+ resetMaster()
320
871
  return
321
872
  }
322
873
  // Denormals in the filters' integrators would slow every frame after.
@@ -344,180 +895,667 @@ public final class DSPMachine: @unchecked Sendable {
344
895
  return 0
345
896
  }
346
897
 
347
- // The interpreter: one instruction at a time, every lane per instruction.
348
- private func run(_ code: UnsafeMutablePointer<Int32>, _ count: Int) {
898
+ /// A table's, shape's or sample's index from its register: in range, or the first.
899
+ @inline(__always)
900
+ private static func index(_ value: Float, _ count: Int) -> Int {
901
+ value >= 0 && value < Float(count) ? Int(value) : 0
902
+ }
903
+
904
+ // The interpreter: instructions `range` of `code` in the first `lanes` lanes (every voice's, or the master
905
+ // stage's one), each lane's note on counted in `trigger`, over the chunk's first `frames` frames; or, given a
906
+ // `frame`, at that frame alone, as the serial part runs (a state register's one value a lane, its first).
907
+ private func run(
908
+ _ code: UnsafeMutablePointer<Int32>, _ range: Range<Int>, lanes: Int, trigger: UnsafeMutablePointer<Float>, frames: Int, frame: Int = -1
909
+ ) {
349
910
  let L = Self.lanes
911
+ let F = Self.frames
350
912
  let R = registers
351
913
  let S = state
352
914
  let N = noise
353
915
  let sr = sampleRate
354
- var at = 0
355
- let end = count * 8
916
+ let serial = frame >= 0
917
+ let fc = serial ? 1 : frames
918
+ let V = program.voices
919
+ let shift = serial ? frame * V : 0
920
+ // A stateless instruction: every lane's frames at once (the chunk's last ones, past fc, go unread), the
921
+ // sounding lanes of each frame; in the serial part, the one frame's.
922
+ @inline(__always) func each(_ body: (Int) -> Void) {
923
+ if serial {
924
+ for l in 0..<lanes { body(l) }
925
+ } else if lanes == V {
926
+ for i in 0..<(F * V) { body(i) }
927
+ } else {
928
+ for k in 0..<F {
929
+ for l in 0..<lanes { body(k * V + l) }
930
+ }
931
+ }
932
+ }
933
+ var at = range.lowerBound * 12
934
+ let end = range.upperBound * 12
356
935
  while at < end {
357
936
  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])
937
+ let states = code[at + 8]
938
+ // A register at this frame, or a state register's one value.
939
+ @inline(__always) func register(_ slot: Int) -> UnsafeMutablePointer<Float> {
940
+ R + Int(code[at + slot]) + (states & (1 << slot) != 0 ? 0 : shift)
941
+ }
942
+ let d = register(1)
943
+ let a = register(2)
944
+ let b = register(3)
945
+ let c = register(4)
362
946
  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]) }
947
+ case 0: each { d[$0] = a[$0] }
948
+ case 1: each { d[$0] = a[$0] + b[$0] }
949
+ case 2: each { d[$0] = a[$0] - b[$0] }
950
+ case 3: each { d[$0] = a[$0] * b[$0] }
951
+ case 4: each { d[$0] = a[$0] / b[$0] }
952
+ case 5: each { d[$0] = a[$0].truncatingRemainder(dividingBy: b[$0]) }
953
+ case 6: each { d[$0] = -a[$0] }
954
+ case 7: each { d[$0] = Swift.min(a[$0], b[$0]) }
955
+ case 8: each { d[$0] = Swift.max(a[$0], b[$0]) }
956
+ case 9: each { d[$0] = Swift.abs(a[$0]) }
957
+ case 10: each { d[$0] = a[$0].rounded(.down) }
958
+ case 11: each { d[$0] = a[$0].rounded(.up) }
959
+ case 12: each { d[$0] = (a[$0] + 0.5).rounded(.down) }
960
+ case 13: each { d[$0] = a[$0].squareRoot() }
961
+ case 14: each { d[$0] = Foundation.sin(a[$0]) }
962
+ case 15: each { d[$0] = Foundation.cos(a[$0]) }
963
+ case 16: each { d[$0] = Foundation.tan(a[$0]) }
964
+ case 17: each { d[$0] = Foundation.exp(a[$0]) }
965
+ case 18: each { d[$0] = Foundation.log(a[$0]) }
966
+ case 19: each { d[$0] = Foundation.pow(a[$0], b[$0]) }
967
+ case 20: each { d[$0] = Foundation.tanh(a[$0]) }
968
+ case 21: each { d[$0] = a[$0] < b[$0] ? 1 : 0 }
969
+ case 22: each { d[$0] = a[$0] <= b[$0] ? 1 : 0 }
970
+ case 23: each { d[$0] = a[$0] > b[$0] ? 1 : 0 }
971
+ case 24: each { d[$0] = a[$0] >= b[$0] ? 1 : 0 }
972
+ case 25: each { d[$0] = a[$0] == b[$0] ? 1 : 0 }
973
+ case 26: each { d[$0] = a[$0] != b[$0] ? 1 : 0 }
974
+ case 27: each { d[$0] = a[$0] != 0 && b[$0] != 0 ? 1 : 0 }
975
+ case 28: each { d[$0] = a[$0] != 0 || b[$0] != 0 ? 1 : 0 }
976
+ case 29: each { d[$0] = a[$0] == 0 ? 1 : 0 }
977
+ case 30: each { d[$0] = a[$0] != 0 ? b[$0] : c[$0] }
978
+ case 31: each { d[$0] = Swift.min(Swift.max(a[$0], b[$0]), c[$0]) }
979
+ case 32: each { d[$0] = a[$0] + (b[$0] - a[$0]) * c[$0] }
980
+ case 33: each { d[$0] = a[$0] - a[$0].rounded(.down) }
981
+ case 34: each { d[$0] = a[$0] > 0 ? 1 : a[$0] < 0 ? -1 : 0 }
982
+ case 35: each { d[$0] = Foundation.atan(a[$0]) }
983
+ // The superinstructions: the product or the sum a float, as its own instruction would have stored it.
984
+ case 58: each { d[$0] = a[$0] * b[$0] + c[$0] }
985
+ case 59: each { d[$0] = (a[$0] + b[$0]) * c[$0] }
986
+ case 60: each { d[$0] = Foundation.log2(a[$0]) }
987
+ case 61: each { d[$0] = Foundation.log10(a[$0]) }
988
+ case 62: each { d[$0] = Foundation.exp2(a[$0]) }
989
+ case 63: each { d[$0] = a[$0].rounded(.towardZero) }
990
+ case 64: each { d[$0] = Foundation.asin(a[$0]) }
991
+ case 65: each { d[$0] = Foundation.acos(a[$0]) }
992
+ case 66: each { d[$0] = Foundation.atan2(a[$0], b[$0]) }
993
+ case 67: each { d[$0] = Foundation.sinh(a[$0]) }
994
+ case 68: each { d[$0] = Foundation.cosh(a[$0]) }
995
+ case 69: each { d[$0] = Foundation.cbrt(a[$0]) }
996
+ case 70: each { d[$0] = Foundation.hypot(a[$0], b[$0]) }
997
+ case 71: each { d[$0] = Foundation.expm1(a[$0]) }
998
+ case 72: each { d[$0] = Foundation.log1p(a[$0]) }
999
+ case 73:
1000
+ // softclip(x): x (27 + x²) / (27 + 9x²) within ±3.
1001
+ each {
1002
+ let x = a[$0] > -3 ? (a[$0] < 3 ? a[$0] : 3) : -3
1003
+ let x2 = x * x
1004
+ d[$0] = x * (27 + x2) / (27 + 9 * x2)
1005
+ }
1006
+ case 74:
1007
+ // onepole(input, cutoff): toward the input by 1 − e^(−2π cutoff / sampleRate) a frame.
1008
+ let s = S + Int(code[at + 7])
1009
+ for fk in 0..<fc {
1010
+ for l in 0..<lanes {
1011
+ let el = fk * V + l
1012
+ let cutoff = Swift.min(Swift.max(b[el], 0), 0.49 * sr)
1013
+ if !(s[L + l] == cutoff) {
1014
+ s[L + l] = cutoff
1015
+ s[2 * L + l] = 1 - Foundation.exp(-2 * Float.pi * cutoff / sr)
1016
+ }
1017
+ let y = s[l]
1018
+ s[l] = y + (a[el] - y) * s[2 * L + l]
1019
+ d[el] = s[l]
1020
+ }
1021
+ }
1022
+ case 75:
1023
+ // dcblock(input): y = x − x before + r × y before, r = 1 − 2π 20 / sampleRate.
1024
+ let s = S + Int(code[at + 7])
1025
+ let r = 1 - Float(125.66370614359172) / sr
1026
+ for fk in 0..<fc {
1027
+ for l in 0..<lanes {
1028
+ let el = fk * V + l
1029
+ let x = a[el]
1030
+ let y = (x - s[l]) + r * s[L + l]
1031
+ s[l] = x
1032
+ s[L + l] = y
1033
+ d[el] = y
1034
+ }
1035
+ }
1036
+ case 76, 77:
1037
+ // comb(input, seconds, feedback, damp, longest): its line read seconds back, between samples, through a
1038
+ // one-pole (damp the share it keeps) back in with the input times feedback. allpass(input, seconds,
1039
+ // gain, longest): w = input + gain × w seconds back, out = w seconds back − gain × w.
1040
+ let s = S + Int(code[at + 7])
1041
+ let length = Int(code[at + 10])
1042
+ let mask = length - 1
1043
+ let memory = delaySamples + Int(code[at + 9])
1044
+ let damping = register(5)
1045
+ for fk in 0..<fc {
1046
+ for l in 0..<lanes {
1047
+ let el = fk * V + l
1048
+ let w = Int(s[l])
1049
+ var ds = b[el] * sr
1050
+ ds = ds >= 1 ? (ds <= Float(length - 2) ? ds : Float(length - 2)) : 1
1051
+ let position = Float(w) - ds
1052
+ let i0 = Int(position.rounded(.down))
1053
+ let fr = position - Float(i0)
1054
+ let line = memory + l * length
1055
+ let v0 = line[i0 & mask]
1056
+ let v = v0 + (line[(i0 + 1) & mask] - v0) * fr
1057
+ let x = a[el]
1058
+ let g = c[el]
1059
+ if op == 76 {
1060
+ let damp = damping[el] > 0 ? (damping[el] < 1 ? damping[el] : 1) : 0
1061
+ let store = v * (1 - damp) + s[L + l] * damp
1062
+ s[L + l] = store
1063
+ line[w & mask] = x + store * g
1064
+ d[el] = v
1065
+ } else {
1066
+ let into = x + g * v
1067
+ line[w & mask] = into
1068
+ d[el] = v - g * into
1069
+ }
1070
+ s[l] = Float((w + 1) & mask)
1071
+ }
1072
+ }
399
1073
  case 40, 41, 42, 43, 44:
400
1074
  // Oscillators: the output from the phase now, then the phase steps by freq / sampleRate.
401
1075
  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)
1076
+ for fk in 0..<fc {
1077
+ for l in 0..<lanes {
1078
+ let el = fk * V + l
1079
+ let p = s[l]
1080
+ let dt = a[el] / sr
1081
+ var v: Float
1082
+ switch op {
1083
+ case 40: v = p
1084
+ case 41: v = Foundation.sin(2 * Float.pi * p)
1085
+ case 42:
1086
+ v = 2 * p - 1
1087
+ if dt > 0 { v -= Self.blep(p, dt) }
1088
+ case 43:
1089
+ let w = Swift.min(Swift.max(b[el], 0), 1)
1090
+ v = p < w ? 1 : -1
1091
+ if dt > 0 {
1092
+ let q = p + 1 - w
1093
+ v += Self.blep(p, dt) - Self.blep(q - q.rounded(.down), dt)
1094
+ }
1095
+ default: v = 1 - 4 * Swift.abs(p - 0.5)
418
1096
  }
419
- default: v = 1 - 4 * Swift.abs(p - 0.5)
1097
+ d[el] = v
1098
+ let next = p + dt
1099
+ s[l] = next >= 0 && next < 1 ? next : next - next.rounded(.down)
420
1100
  }
421
- d[l] = v
422
- let next = p + dt
423
- s[l] = next - next.rounded(.down)
424
1101
  }
425
1102
  case 45:
426
1103
  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)
1104
+ for fk in 0..<fc {
1105
+ for l in 0..<lanes {
1106
+ let el = fk * V + l
1107
+ var x = s[l]
1108
+ x ^= x << 13
1109
+ x ^= x >> 17
1110
+ x ^= x << 5
1111
+ s[l] = x
1112
+ d[el] = Float(Double(x) / 4_294_967_296 * 2 - 1)
1113
+ }
434
1114
  }
435
1115
  case 46:
436
1116
  // adsr(gate, attack, decay, sustain, release): stage, level, trigger, gate before, decay time and coefficient, release time and coefficient.
1117
+ // With curves, what it puts out is each stage bent by its exponent, and a stage that starts takes up
1118
+ // where the last left off: its last output, and where a release started.
437
1119
  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))
1120
+ let sustainIn = register(5)
1121
+ let releaseIn = register(6)
1122
+ let curve = Int(code[at + 11]) - 1
1123
+ let curved = curve >= 0
1124
+ let ea = curved ? Double(curveExponents[curve * 3]) : 1
1125
+ let ed = curved ? Double(curveExponents[curve * 3 + 1]) : 1
1126
+ let er = curved ? Double(curveExponents[curve * 3 + 2]) : 1
1127
+ for fk in 0..<fc {
1128
+ for l in 0..<lanes {
1129
+ let el = fk * V + l
1130
+ let gate = a[el]
1131
+ var stage = s[l]
1132
+ var level = s[L + l]
1133
+ let before = stage
1134
+ if s[2 * L + l] != trigger[l] {
1135
+ s[2 * L + l] = trigger[l]
1136
+ if gate > 0.5 { stage = 1 }
1137
+ } else if gate > 0.5 && s[3 * L + l] <= 0.5 {
1138
+ stage = 1
464
1139
  }
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))
1140
+ if gate <= 0.5 && stage >= 1 && stage <= 3 { stage = 4 }
1141
+ s[3 * L + l] = gate
1142
+ if curved && stage != before {
1143
+ let last = s[8 * L + l]
1144
+ if stage == 1 {
1145
+ level = last > 0 ? Float(Foundation.pow(Double(last), 1 / ea)) : 0
1146
+ } else if stage == 4 {
1147
+ level = last
1148
+ s[9 * L + l] = last
1149
+ }
474
1150
  }
475
- level *= s[7 * L + l]
476
- if level < 0.0001 {
1151
+ let sustain = Swift.min(Swift.max(sustainIn[el], 0), 1)
1152
+ if stage == 1 {
1153
+ level += 1 / Swift.max(1, b[el] * sr)
1154
+ if level >= 1 {
1155
+ level = 1
1156
+ stage = 2
1157
+ }
1158
+ } else if stage == 2 {
1159
+ let time = c[el]
1160
+ if !(s[4 * L + l] == time) {
1161
+ s[4 * L + l] = time
1162
+ s[5 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1163
+ }
1164
+ level = sustain + (level - sustain) * s[5 * L + l]
1165
+ if level - sustain < 0.0001 { stage = 3 }
1166
+ } else if stage == 3 {
1167
+ level = sustain
1168
+ } else if stage == 4 {
1169
+ let time = releaseIn[el]
1170
+ if !(s[6 * L + l] == time) {
1171
+ s[6 * L + l] = time
1172
+ s[7 * L + l] = Foundation.exp(-9.2 / Swift.max(1, time * sr))
1173
+ }
1174
+ level *= s[7 * L + l]
1175
+ if level < 0.0001 {
1176
+ level = 0
1177
+ stage = 0
1178
+ }
1179
+ } else {
477
1180
  level = 0
478
- stage = 0
479
1181
  }
480
- } else {
481
- level = 0
1182
+ s[l] = stage
1183
+ s[L + l] = level
1184
+ var out = level
1185
+ if curved {
1186
+ if stage == 1 {
1187
+ out = Float(Foundation.pow(Double(level), ea))
1188
+ } else if stage == 2 {
1189
+ let span = 1 - sustain
1190
+ out = span > 1e-6 ? sustain + span * Float(Foundation.pow(Double(Swift.max(0, (level - sustain) / span)), ed)) : level
1191
+ } else if stage == 4 {
1192
+ let from = s[9 * L + l]
1193
+ out = from > 0 ? from * Float(Foundation.pow(Double(Swift.min(1, level / from)), er)) : 0
1194
+ }
1195
+ s[8 * L + l] = out
1196
+ }
1197
+ d[el] = out
482
1198
  }
483
- s[l] = stage
484
- s[L + l] = level
485
- d[l] = level
486
1199
  }
487
1200
  case 47, 48, 49:
488
1201
  // A state-variable filter (Simper's form): resonance 0 … 1.
489
1202
  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
1203
+ for fk in 0..<fc {
1204
+ for l in 0..<lanes {
1205
+ let el = fk * V + l
1206
+ let cutoff = Swift.min(Swift.max(b[el], 10), 0.49 * sr)
1207
+ let resonance = Swift.min(Swift.max(c[el], 0), 0.98)
1208
+ if !(s[2 * L + l] == cutoff && s[3 * L + l] == resonance) {
1209
+ s[2 * L + l] = cutoff
1210
+ s[3 * L + l] = resonance
1211
+ let g = Foundation.tan(Float.pi * cutoff / sr)
1212
+ let k = 2 - 2 * resonance
1213
+ let a1 = 1 / (1 + g * (g + k))
1214
+ s[4 * L + l] = a1
1215
+ s[5 * L + l] = g * a1
1216
+ s[6 * L + l] = g * g * a1
1217
+ s[7 * L + l] = k
1218
+ }
1219
+ let a1 = s[4 * L + l]
1220
+ let a2 = s[5 * L + l]
1221
+ let a3 = s[6 * L + l]
1222
+ let ic1 = s[l]
1223
+ let ic2 = s[L + l]
1224
+ let x = a[el]
1225
+ let v3 = x - ic2
1226
+ let v1 = a1 * ic1 + a2 * v3
1227
+ let v2 = ic2 + a2 * ic1 + a3 * v3
1228
+ s[l] = 2 * v1 - ic1
1229
+ s[L + l] = 2 * v2 - ic2
1230
+ d[el] = op == 47 ? v2 : op == 49 ? v1 : x - s[7 * L + l] * v1 - v2
1231
+ }
1232
+ }
1233
+ case 50:
1234
+ // wavetable(table, freq, position): the level that cannot alias at freq (worked out again only when freq
1235
+ // changes), read between samples and between frames.
1236
+ let s = S + Int(code[at + 7])
1237
+ let T = tableSamples
1238
+ // The table is a constant register's, the same in every lane.
1239
+ let index = a[0]
1240
+ let t = index >= 0 && Int(exactly: index.rounded(.down)).map { $0 < tableCount } == true ? Int(index) : 0
1241
+ let frames = tableFrames.isEmpty ? 1 : tableFrames[t]
1242
+ let base = tableBases.isEmpty ? 0 : tableBases[t]
1243
+ for fk in 0..<fc {
1244
+ for l in 0..<lanes {
1245
+ let el = fk * V + l
1246
+ let p = s[l]
1247
+ let f = b[el]
1248
+ let dt = f / sr
1249
+ if s[L + l] != f {
1250
+ s[L + l] = f
1251
+ var level = 0
1252
+ let allowed = 0.5 * Double(sr) / Double(Swift.abs(f))
1253
+ if allowed < 512 {
1254
+ let octaves = Foundation.log2(512 / allowed)
1255
+ level = octaves > 8 ? 9 : Int(octaves.rounded(.up))
1256
+ }
1257
+ s[2 * L + l] = Float(level)
1258
+ }
1259
+ let level = Int(s[2 * L + l])
1260
+ // NaN reads as 0 here, as in the JavaScript machine.
1261
+ let morph = c[el] > 0 ? (c[el] < 1 ? c[el] : 1) : 0
1262
+ let position = morph * Float(frames - 1)
1263
+ // Never below 0: truncating is rounding down.
1264
+ let f0 = Int(position)
1265
+ let f1 = Swift.min(f0 + 1, frames - 1)
1266
+ let ff = position - Float(f0)
1267
+ let x = p * 2048
1268
+ // A phase gone to NaN reads NaN, which the block's check silences.
1269
+ let i0 = x >= 0 && x < 2048 ? Int(x) : x.isFinite ? Int(x.rounded(.down)) : 0
1270
+ let fr = x - Float(i0)
1271
+ let j0 = i0 & 2047
1272
+ let j1 = (i0 + 1) & 2047
1273
+ // Samples j0 and j1, each its frames side by side.
1274
+ let row0 = base + (level * 2048 + j0) * frames
1275
+ let row1 = base + (level * 2048 + j1) * frames
1276
+ let v0 = T[row0 + f0] + (T[row1 + f0] - T[row0 + f0]) * fr
1277
+ let v1 = T[row0 + f1] + (T[row1 + f1] - T[row0 + f1]) * fr
1278
+ d[el] = v0 + (v1 - v0) * ff
1279
+ let next = p + dt
1280
+ s[l] = next >= 0 && next < 1 ? next : next - next.rounded(.down)
1281
+ }
1282
+ }
1283
+ case 51:
1284
+ // delay(input, seconds, longest): read at least a sample back, between samples, then write.
1285
+ let s = S + Int(code[at + 7])
1286
+ let length = Int(code[at + 10])
1287
+ let mask = length - 1
1288
+ let memory = delaySamples + Int(code[at + 9])
1289
+ for fk in 0..<fc {
1290
+ for l in 0..<lanes {
1291
+ let el = fk * V + l
1292
+ let w = Int(s[l])
1293
+ let x = a[el]
1294
+ var ds = b[el] * sr
1295
+ ds = ds >= 1 ? (ds <= Float(length - 2) ? ds : Float(length - 2)) : 1
1296
+ let position = Float(w) - ds
1297
+ let i0 = Int(position.rounded(.down))
1298
+ let fr = position - Float(i0)
1299
+ let line = memory + l * length
1300
+ let v0 = line[i0 & mask]
1301
+ let v1 = line[(i0 + 1) & mask]
1302
+ d[el] = v0 + (v1 - v0) * fr
1303
+ line[w & mask] = x
1304
+ s[l] = Float((w + 1) & mask)
1305
+ }
1306
+ }
1307
+ case 52:
1308
+ // shape(shape, x): x 0 … 1 along it, between points.
1309
+ let P = shapePoints
1310
+ for fk in 0..<fc {
1311
+ for l in 0..<lanes {
1312
+ let el = fk * V + l
1313
+ let t = Self.index(a[el], shapeLengths.count)
1314
+ let points = shapeLengths.isEmpty ? 1 : shapeLengths[t]
1315
+ let base = shapeBases.isEmpty ? 0 : shapeBases[t]
1316
+ let x = b[el]
1317
+ let position = (x > 0 ? (x < 1 ? x : 1) : 0) * Float(points - 1)
1318
+ let i0 = Int(position.rounded(.down))
1319
+ let v0 = P[base + i0]
1320
+ let v1 = P[base + Swift.min(i0 + 1, points - 1)]
1321
+ d[el] = v0 + (v1 - v0) * (position - Float(i0))
1322
+ }
1323
+ }
1324
+ case 53:
1325
+ // play(sample, rate, start): from start (0 … 1 along it) at each note on, at rate (1 its own pitch),
1326
+ // between samples; silent past either end. Where it plays is a whole sample and the fraction past it,
1327
+ // so it keeps time.
1328
+ let s = S + Int(code[at + 7])
1329
+ let A = sampleAudio
1330
+ for fk in 0..<fc {
1331
+ for l in 0..<lanes {
1332
+ let el = fk * V + l
1333
+ let t = Self.index(a[el], sampleLengths.count)
1334
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
1335
+ let base = sampleBases.isEmpty ? 0 : sampleBases[t]
1336
+ if s[2 * L + l] != trigger[l] {
1337
+ s[2 * L + l] = trigger[l]
1338
+ let start = c[el]
1339
+ let p = (start > 0 ? (start < 1 ? start : 1) : 0) * Float(length - 1)
1340
+ s[l] = p.rounded(.down)
1341
+ s[L + l] = p - p.rounded(.down)
1342
+ }
1343
+ let index = s[l]
1344
+ let fraction = s[L + l]
1345
+ var v: Float = 0
1346
+ if index >= 0 && index < Float(length) {
1347
+ // Past the last sample, silence.
1348
+ let k = base + Int(index)
1349
+ let after = index < Float(length - 1) ? A[k + 1] : 0
1350
+ v = A[k] + (after - A[k]) * fraction
1351
+ }
1352
+ d[el] = v
1353
+ var step = b[el] * (sampleRatios.isEmpty ? 1 : sampleRatios[t])
1354
+ step = step > -65536 ? (step < 65536 ? step : 65536) : -65536
1355
+ let next = fraction + step
1356
+ let whole = next.rounded(.down)
1357
+ let moved = index + whole
1358
+ s[l] = moved > -1 ? (moved < Float(length) ? moved : Float(length)) : -1
1359
+ s[L + l] = next - whole
1360
+ }
1361
+ }
1362
+ case 78:
1363
+ // tableread(table, phase, freq, position): wavetable's read, at a phase the program keeps (wrapped to
1364
+ // 0 … 1), at the level that cannot alias at freq (worked out again only when freq changes).
1365
+ let s = S + Int(code[at + 7])
1366
+ let T = tableSamples
1367
+ let e = register(5)
1368
+ // The table is a constant register's, the same in every lane.
1369
+ let index = a[0]
1370
+ let t = index >= 0 && Int(exactly: index.rounded(.down)).map { $0 < tableCount } == true ? Int(index) : 0
1371
+ let frames = tableFrames.isEmpty ? 1 : tableFrames[t]
1372
+ let base = tableBases.isEmpty ? 0 : tableBases[t]
1373
+ for fk in 0..<fc {
1374
+ for l in 0..<lanes {
1375
+ let el = fk * V + l
1376
+ let f = c[el]
1377
+ if s[l] != f {
1378
+ s[l] = f
1379
+ var level = 0
1380
+ let allowed = 0.5 * Double(sr) / Double(Swift.abs(f))
1381
+ if allowed < 512 {
1382
+ let octaves = Foundation.log2(512 / allowed)
1383
+ level = octaves > 8 ? 9 : Int(octaves.rounded(.up))
1384
+ }
1385
+ s[L + l] = Float(level)
1386
+ }
1387
+ let level = Int(s[L + l])
1388
+ let morph = e[el] > 0 ? (e[el] < 1 ? e[el] : 1) : 0
1389
+ let position = morph * Float(frames - 1)
1390
+ let f0 = Int(position)
1391
+ let f1 = Swift.min(f0 + 1, frames - 1)
1392
+ let ff = position - Float(f0)
1393
+ let phase = b[el]
1394
+ // 0 … 1 (1 itself, as a phase just below 0 rounds to); NaN past infinities.
1395
+ let p = phase - phase.rounded(.down)
1396
+ let x = p * 2048
1397
+ let i0 = x >= 0 && x <= 2048 ? Int(x) : 0
1398
+ let fr = x - Float(i0)
1399
+ let j0 = i0 & 2047
1400
+ let j1 = (i0 + 1) & 2047
1401
+ let row0 = base + (level * 2048 + j0) * frames
1402
+ let row1 = base + (level * 2048 + j1) * frames
1403
+ let v0 = T[row0 + f0] + (T[row1 + f0] - T[row0 + f0]) * fr
1404
+ let v1 = T[row0 + f1] + (T[row1 + f1] - T[row0 + f1]) * fr
1405
+ d[el] = v0 + (v1 - v0) * ff
1406
+ }
1407
+ }
1408
+ case 79:
1409
+ // loop(sample, rate, start): play's, but round and round: past either end it comes in at the other.
1410
+ let s = S + Int(code[at + 7])
1411
+ let A = sampleAudio
1412
+ for fk in 0..<fc {
1413
+ for l in 0..<lanes {
1414
+ let el = fk * V + l
1415
+ let t = Self.index(a[el], sampleLengths.count)
1416
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
1417
+ let base = sampleBases.isEmpty ? 0 : sampleBases[t]
1418
+ if s[2 * L + l] != trigger[l] {
1419
+ s[2 * L + l] = trigger[l]
1420
+ let start = c[el]
1421
+ let p = (start > 0 ? (start < 1 ? start : 1) : 0) * Float(length - 1)
1422
+ s[l] = p.rounded(.down)
1423
+ s[L + l] = p - p.rounded(.down)
1424
+ }
1425
+ // Always a sample of this one, though a lane's index may change samples under it.
1426
+ let index = ((Int(s[l]) % length) + length) % length
1427
+ let fraction = s[L + l]
1428
+ let k = base + index
1429
+ let after = index < length - 1 ? A[k + 1] : A[base]
1430
+ d[el] = A[k] + (after - A[k]) * fraction
1431
+ var step = b[el] * (sampleRatios.isEmpty ? 1 : sampleRatios[t])
1432
+ step = step > -65536 ? (step < 65536 ? step : 65536) : -65536
1433
+ let next = fraction + step
1434
+ let whole = next.rounded(.down)
1435
+ s[l] = Float((((index + Int(whole)) % length) + length) % length)
1436
+ s[L + l] = next - whole
1437
+ }
1438
+ }
1439
+ case 54:
1440
+ // grains(sample, position, density, length, pitch): a grain every 1 / density seconds from position
1441
+ // (0 … 1 along the sample, and up to 20 ms on), length seconds (0.001 … 1) long, at pitch (1/16 …
1442
+ // 16, 1 its own), under a parabola; up to 8 at once (with none free, one is skipped).
1443
+ let s = S + Int(code[at + 7])
1444
+ let lengthIn = register(5)
1445
+ let pitchIn = register(6)
1446
+ let A = sampleAudio
1447
+ for fk in 0..<fc {
1448
+ for l in 0..<lanes {
1449
+ let el = fk * V + l
1450
+ let t = Self.index(a[el], sampleLengths.count)
1451
+ let length = sampleLengths.isEmpty ? 2 : sampleLengths[t]
1452
+ let base = sampleBases.isEmpty ? 0 : sampleBases[t]
1453
+ let ratio = sampleRatios.isEmpty ? 1 : sampleRatios[t]
1454
+ let density = c[el]
1455
+ var countdown = s[l]
1456
+ if density > 0 {
1457
+ if countdown <= 0 {
1458
+ var g = 0
1459
+ while g < 8 && s[(3 + 4 * g) * L + l] < s[(4 + 4 * g) * L + l] { g += 1 }
1460
+ if g < 8 {
1461
+ let random = UnsafeMutableRawPointer(s + L + l)
1462
+ var x = random.load(as: UInt32.self)
1463
+ x ^= x << 13
1464
+ x ^= x >> 17
1465
+ x ^= x << 5
1466
+ random.storeBytes(of: x, as: UInt32.self)
1467
+ let position = b[el]
1468
+ let spray = sampleSprays.isEmpty ? 1 : sampleSprays[t]
1469
+ let start = ((position > 0 ? (position < 1 ? position : 1) : 0) * Float(length - 1)).rounded(.down) + Float(x % spray)
1470
+ let seconds = lengthIn[el]
1471
+ let frames = ((seconds > 0.001 ? (seconds < 1 ? seconds : 1) : 0.001) * sr).rounded(.down)
1472
+ let pitch = pitchIn[el]
1473
+ let w = s + (2 + 4 * g) * L + l
1474
+ w[0] = start < Float(length - 1) ? start : Float(length - 1)
1475
+ w[L] = 0
1476
+ w[2 * L] = frames > 1 ? frames : 1
1477
+ w[3 * L] = (pitch > 0.0625 ? (pitch < 16 ? pitch : 16) : 0.0625) * ratio
1478
+ }
1479
+ let interval = sr / density
1480
+ countdown += interval > 1 ? interval : 1
1481
+ }
1482
+ countdown -= 1
1483
+ } else {
1484
+ countdown = 0
1485
+ }
1486
+ s[l] = countdown
1487
+ var sum: Float = 0
1488
+ for g in 0..<8 {
1489
+ let w = s + (2 + 4 * g) * L + l
1490
+ let age = w[L]
1491
+ let frames = w[2 * L]
1492
+ guard age < frames else { continue }
1493
+ let offset = age * w[3 * L]
1494
+ let whole = offset.rounded(.down)
1495
+ let index = w[0] + whole
1496
+ if index >= 0 && index < Float(length - 1) {
1497
+ let k = base + Int(index)
1498
+ let v = A[k] + (A[k + 1] - A[k]) * (offset - whole)
1499
+ let phase = age / frames
1500
+ sum += v * (4 * phase * (1 - phase))
1501
+ }
1502
+ w[L] = age + 1
1503
+ }
1504
+ d[el] = sum
1505
+ }
1506
+ }
1507
+ case 57:
1508
+ // modsum(routes): Σ amount × source over the list, route by route. An amount is a parameter, the same
1509
+ // in every lane, so a route at 0 is passed over once for all of them and costs nothing.
1510
+ each { d[$0] = 0 }
1511
+ let index = Self.index(a[0], routeStarts.count - 1)
1512
+ guard index < routeStarts.count - 1 else { break }
1513
+ var k = routeStarts[index]
1514
+ let end = routeStarts[index + 1]
1515
+ while k < end {
1516
+ let amount = R + routeRegisters[k + 1]
1517
+ let source = R + routeRegisters[k] + (routeState[k] ? 0 : shift)
1518
+ k += 2
1519
+ if amount[0] == 0 { continue }
1520
+ each { d[$0] += amount[$0] * source[$0] }
1521
+ }
1522
+ case 55:
1523
+ // smooth(input, seconds): toward the input by 1 − e^(−1 / (seconds × sampleRate)) a frame, from where
1524
+ // the input is on its first.
1525
+ let s = S + Int(code[at + 7])
1526
+ for fk in 0..<fc {
1527
+ for l in 0..<lanes {
1528
+ let el = fk * V + l
1529
+ let x = a[el]
1530
+ var y = s[l]
1531
+ if y.isNaN { y = x }
1532
+ let time = b[el]
1533
+ if !(s[L + l] == time) {
1534
+ s[L + l] = time
1535
+ let frames = time * sr
1536
+ s[2 * L + l] = frames > 1 ? -Foundation.expm1(-1 / frames) : 1
1537
+ }
1538
+ y += (x - y) * s[2 * L + l]
1539
+ s[l] = y
1540
+ d[el] = y
1541
+ }
1542
+ }
1543
+ case 56:
1544
+ // hold(input, trigger): takes the input as the trigger rises above 0.5, and keeps it.
1545
+ let s = S + Int(code[at + 7])
1546
+ for fk in 0..<fc {
1547
+ for l in 0..<lanes {
1548
+ let el = fk * V + l
1549
+ let t = b[el]
1550
+ if t > 0.5 && !(s[L + l] > 0.5) { s[l] = a[el] }
1551
+ s[L + l] = t
1552
+ d[el] = s[l]
503
1553
  }
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
1554
  }
517
1555
  default:
518
1556
  break
519
1557
  }
520
- at += 8
1558
+ at += 12
521
1559
  }
522
1560
  }
523
1561
  }