@swiftbrowser/native 0.18.3 → 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.
- package/README.md +53 -11
- package/bin/swiftbrowser-native.mjs +47 -0
- package/dist/blob.d.ts +85 -11
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +184 -34
- package/dist/blob.js.map +1 -1
- package/dist/bridge.d.ts +66 -8
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js.map +1 -1
- package/dist/encoding.d.ts +13 -0
- package/dist/encoding.d.ts.map +1 -1
- package/dist/encoding.js +24 -0
- package/dist/encoding.js.map +1 -1
- package/dist/fetch.d.ts +27 -13
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +117 -45
- package/dist/fetch.js.map +1 -1
- package/dist/hostRequests.d.ts +24 -6
- package/dist/hostRequests.d.ts.map +1 -1
- package/dist/hostRequests.js +108 -15
- package/dist/hostRequests.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/ios.d.ts +79 -0
- package/dist/ios.d.ts.map +1 -0
- package/dist/ios.js +181 -0
- package/dist/ios.js.map +1 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +16 -7
- package/dist/runtime.js.map +1 -1
- package/dist/subtle.d.ts +1 -1
- package/dist/subtle.d.ts.map +1 -1
- package/dist/subtle.js +9 -5
- package/dist/subtle.js.map +1 -1
- package/dist/webSocket.d.ts +12 -5
- package/dist/webSocket.d.ts.map +1 -1
- package/dist/webSocket.js +37 -11
- package/dist/webSocket.js.map +1 -1
- package/package.json +7 -3
- package/src/blob.ts +215 -34
- package/src/bridge.ts +56 -8
- package/src/encoding.ts +22 -0
- package/src/fetch.ts +111 -48
- package/src/hostRequests.ts +129 -22
- package/src/index.ts +1 -2
- package/src/ios.ts +253 -0
- package/src/runtime.ts +23 -8
- package/src/subtle.ts +10 -6
- package/src/webSocket.ts +37 -13
- package/swift/Packages/SwiftBrowserDSP/Package.swift +31 -0
- package/swift/Packages/SwiftBrowserDSP/README.md +42 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ProgramNode.swift +306 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ScopeView.swift +79 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Machine.swift +1561 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Program.swift +483 -0
- package/swift/Packages/SwiftBrowserLocalModel/Package.swift +35 -0
- package/swift/Packages/SwiftBrowserLocalModel/README.md +66 -0
- package/swift/Packages/SwiftBrowserLocalModel/Sources/SwiftBrowserLocalModel/LlamaEngine.swift +223 -0
- package/swift/Packages/SwiftBrowserLocalModel/Sources/SwiftBrowserLocalModel/LocalLanguageModel.swift +409 -0
- package/swift/Packages/SwiftBrowserShader/Package.swift +31 -0
- package/swift/Packages/SwiftBrowserShader/README.md +45 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderRenderer.swift +103 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShader/ShaderView.swift +168 -0
- package/swift/Packages/SwiftBrowserShader/Sources/SwiftBrowserShaderCore/ShaderProps.swift +120 -0
- package/swift/Sources/SwiftBrowserNative/Host/AudioEngineBridge.swift +921 -0
- package/swift/Sources/SwiftBrowserNative/Host/AudioEngineNodes.swift +70 -0
- package/swift/Sources/SwiftBrowserNative/Host/BodyStream.swift +166 -0
- package/swift/Sources/SwiftBrowserNative/Host/FilesBridge.swift +144 -10
- package/swift/Sources/SwiftBrowserNative/Host/HostBridge.swift +151 -27
- package/swift/Sources/SwiftBrowserNative/Host/HostRequestBridge.swift +139 -40
- package/swift/Sources/SwiftBrowserNative/Host/JSHost.swift +116 -0
- package/swift/Sources/SwiftBrowserNative/Host/JavaScriptCoreHost.swift +141 -2
- package/swift/Sources/SwiftBrowserNative/Host/LanguageModelBridge.swift +511 -0
- package/swift/Sources/SwiftBrowserNative/Host/LanguageModelProvider.swift +195 -0
- package/swift/Sources/SwiftBrowserNative/Host/WebSocketBridge.swift +24 -11
- package/swift/Sources/SwiftBrowserNative/Host/WorkerHost.swift +3 -2
- package/swift/Sources/SwiftBrowserNative/Runtime/NativeFunctions.swift +1 -1
- package/swift/Sources/SwiftBrowserNative/Runtime/ViewRegistry.swift +57 -0
- package/swift/Sources/SwiftBrowserNative/Views/ElementView.swift +12 -7
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Controls.swift +18 -1
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Drawing.swift +378 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Lists.swift +41 -1
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/More.swift +88 -17
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Navigation.swift +87 -21
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/PinchTracker.swift +200 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/PopTap.swift +103 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Stacks.swift +3 -2
- package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +146 -0
- package/swift/Sources/SwiftBrowserProtocol/Drawing.swift +306 -0
- package/swift/Sources/SwiftBrowserProtocol/Props.swift +31 -2
- package/swift/Sources/SwiftBrowserProtocol/RendererEvent.swift +24 -3
- package/swift/Sources/SwiftBrowserProtocol/Style.swift +87 -0
- package/swift/Sources/SwiftBrowserTree/OpTree.swift +25 -0
- package/wasm/SwiftBrowserNative.wasm +2 -2
- package/dist/native.d.ts +0 -19
- package/dist/native.d.ts.map +0 -1
- package/dist/native.js +0 -17
- package/dist/native.js.map +0 -1
- package/src/native.ts +0 -35
- package/swift/Sources/SwiftBrowserNative/Runtime/NativeRegistry.swift +0 -53
|
@@ -0,0 +1,1561 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// The DSP machine: runs a `DSPProgram` for up to 16 voices, a lane each, in
|
|
4
|
+
/// blocks of up to 128 frames. It is the JavaScript machine
|
|
5
|
+
/// (packages/dsp/src/machine.ts) instruction for instruction, so a program
|
|
6
|
+
/// sounds the same in a native app and on a page; ParityTests hold the two
|
|
7
|
+
/// to the samples the JavaScript one renders.
|
|
8
|
+
///
|
|
9
|
+
/// Real-time safe once made: `render` and the note and parameter calls
|
|
10
|
+
/// allocate nothing, take no lock and call nothing that might; every buffer
|
|
11
|
+
/// is sized from the program in `init`, and the program was checked there,
|
|
12
|
+
/// so no instruction can reach outside them. One thread at a time: the audio
|
|
13
|
+
/// thread renders and applies events, which another thread hands it
|
|
14
|
+
/// (ProgramNode.swift in SwiftBrowserDSP).
|
|
15
|
+
///
|
|
16
|
+
/// Events apply at the next block. A note takes the lane already playing it,
|
|
17
|
+
/// else a free one, else the oldest released, else the oldest; a lane's gate
|
|
18
|
+
/// is up from its note on to its note off, or under the sustain pedal until
|
|
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. 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.
|
|
46
|
+
public final class DSPMachine: @unchecked Sendable {
|
|
47
|
+
public let program: DSPProgram
|
|
48
|
+
public let sampleRate: Float
|
|
49
|
+
|
|
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.
|
|
56
|
+
private let registers: UnsafeMutablePointer<Float>
|
|
57
|
+
private let width: Int
|
|
58
|
+
private let state: UnsafeMutablePointer<Float>
|
|
59
|
+
private let stateCount: Int
|
|
60
|
+
private let noise: UnsafeMutablePointer<UInt32>
|
|
61
|
+
private let noiseCount: Int
|
|
62
|
+
private let blockCode: UnsafeMutablePointer<Int32>
|
|
63
|
+
private let blockCount: Int
|
|
64
|
+
private let sampleCode: UnsafeMutablePointer<Int32>
|
|
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]
|
|
73
|
+
/// Each instance's builtin and where its state starts (in floats, lanes included; a noise instance's in `noise`).
|
|
74
|
+
private let instanceKinds: [DSPBuiltin]
|
|
75
|
+
private let instanceOffsets: [Int]
|
|
76
|
+
private let envelopeOffsets: [Int]
|
|
77
|
+
private let filterOffsets: [Int]
|
|
78
|
+
private let parameterRegisters: [Int]
|
|
79
|
+
private let parameterRanges: [(min: Float, max: Float)]
|
|
80
|
+
private let parameterIndices: [String: Int]
|
|
81
|
+
private let targets: UnsafeMutablePointer<Float>
|
|
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]
|
|
113
|
+
|
|
114
|
+
private let laneNote: UnsafeMutablePointer<Int32>
|
|
115
|
+
private let laneGate: UnsafeMutablePointer<Float>
|
|
116
|
+
private let laneVelocity: UnsafeMutablePointer<Float>
|
|
117
|
+
private let laneHeld: UnsafeMutablePointer<Bool>
|
|
118
|
+
private let laneActive: UnsafeMutablePointer<Float>
|
|
119
|
+
private let laneAge: UnsafeMutablePointer<Double>
|
|
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
|
|
125
|
+
private var age: Double = 0
|
|
126
|
+
private var pedal = false
|
|
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
|
|
139
|
+
|
|
140
|
+
public init(program: DSPProgram, sampleRate: Double) {
|
|
141
|
+
let L = Self.lanes
|
|
142
|
+
self.program = program
|
|
143
|
+
self.sampleRate = Float(sampleRate)
|
|
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
|
|
159
|
+
var kinds: [DSPBuiltin] = []
|
|
160
|
+
var offsets: [Int] = []
|
|
161
|
+
var envelopes: [Int] = []
|
|
162
|
+
var filters: [Int] = []
|
|
163
|
+
var words = 0
|
|
164
|
+
var noises = 0
|
|
165
|
+
for (i, builtin) in program.instances.enumerated() {
|
|
166
|
+
kinds.append(builtin)
|
|
167
|
+
if builtin == .noise {
|
|
168
|
+
offsets.append(noises * L)
|
|
169
|
+
noises += 1
|
|
170
|
+
} else {
|
|
171
|
+
offsets.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) }
|
|
175
|
+
words += builtin.words
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
instanceKinds = kinds
|
|
179
|
+
instanceOffsets = offsets
|
|
180
|
+
envelopeOffsets = envelopes
|
|
181
|
+
filterOffsets = filters
|
|
182
|
+
stateCount = max(1, words) * L
|
|
183
|
+
state = .allocate(capacity: stateCount)
|
|
184
|
+
state.initialize(repeating: 0, count: stateCount)
|
|
185
|
+
noiseCount = max(1, noises) * L
|
|
186
|
+
noise = .allocate(capacity: noiseCount)
|
|
187
|
+
noise.initialize(repeating: 1, count: noiseCount)
|
|
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)
|
|
238
|
+
for constant in program.constants {
|
|
239
|
+
(registers + constant.register * W).update(repeating: constant.value, count: W)
|
|
240
|
+
}
|
|
241
|
+
registers.update(repeating: Float(sampleRate), count: W)
|
|
242
|
+
parameterRegisters = program.parameters.map(\.register)
|
|
243
|
+
parameterRanges = program.parameters.map { ($0.min, $0.max) }
|
|
244
|
+
parameterIndices = Dictionary(program.parameters.enumerated().map { ($1.name, $0) }, uniquingKeysWith: { first, _ in first })
|
|
245
|
+
targets = .allocate(capacity: max(1, program.parameters.count))
|
|
246
|
+
for (i, parameter) in program.parameters.enumerated() {
|
|
247
|
+
targets[i] = parameter.defaultValue
|
|
248
|
+
(registers + parameter.register * W).update(repeating: parameter.defaultValue, count: W)
|
|
249
|
+
}
|
|
250
|
+
laneNote = .allocate(capacity: L)
|
|
251
|
+
laneNote.initialize(repeating: -1, count: L)
|
|
252
|
+
laneGate = .allocate(capacity: L)
|
|
253
|
+
laneGate.initialize(repeating: 0, count: L)
|
|
254
|
+
laneVelocity = .allocate(capacity: L)
|
|
255
|
+
laneVelocity.initialize(repeating: 0, count: L)
|
|
256
|
+
laneHeld = .allocate(capacity: L)
|
|
257
|
+
laneHeld.initialize(repeating: false, count: L)
|
|
258
|
+
laneActive = .allocate(capacity: L)
|
|
259
|
+
laneActive.initialize(repeating: 0, count: L)
|
|
260
|
+
laneAge = .allocate(capacity: L)
|
|
261
|
+
laneAge.initialize(repeating: 0, count: L)
|
|
262
|
+
trigger = .allocate(capacity: L)
|
|
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)
|
|
272
|
+
for lane in 0..<L { resetLane(lane) }
|
|
273
|
+
resetMaster()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
deinit {
|
|
277
|
+
for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger, masterTrigger, shapePoints, sampleAudio] { pointer.deallocate() }
|
|
278
|
+
noise.deallocate()
|
|
279
|
+
routeRegisters.deallocate()
|
|
280
|
+
routeState.deallocate()
|
|
281
|
+
tableSamples.deallocate()
|
|
282
|
+
delaySamples.deallocate()
|
|
283
|
+
blockCode.deallocate()
|
|
284
|
+
sampleCode.deallocate()
|
|
285
|
+
masterCode.deallocate()
|
|
286
|
+
laneNote.deallocate()
|
|
287
|
+
stack.deallocate()
|
|
288
|
+
queueBeat.deallocate()
|
|
289
|
+
queueEvent.deallocate()
|
|
290
|
+
laneHeld.deallocate()
|
|
291
|
+
laneAge.deallocate()
|
|
292
|
+
}
|
|
293
|
+
|
|
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>) {
|
|
301
|
+
var out: [Int32] = []
|
|
302
|
+
var from = 0
|
|
303
|
+
var to = 0
|
|
304
|
+
var pc = 0
|
|
305
|
+
while pc < code.count {
|
|
306
|
+
if pc == serial?.lowerBound { from = out.count / 12 }
|
|
307
|
+
if pc == serial?.upperBound { to = out.count / 12 }
|
|
308
|
+
let op = DSPOpcode(rawValue: code[pc])!
|
|
309
|
+
var slot = [Int32](repeating: 0, count: 12)
|
|
310
|
+
slot[0] = op.rawValue
|
|
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
|
+
}
|
|
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
|
+
}
|
|
323
|
+
out += slot
|
|
324
|
+
pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
|
|
325
|
+
}
|
|
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))
|
|
330
|
+
out.withUnsafeBufferPointer { pointer.update(from: $0.baseAddress!, count: out.count) }
|
|
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)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// MARK: Events
|
|
448
|
+
|
|
449
|
+
/// The index `setParameter(at:_:)` takes for a parameter's name: look it up off the audio thread.
|
|
450
|
+
public func parameterIndex(_ name: String) -> Int? {
|
|
451
|
+
parameterIndices[name]
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/// A parameter, clamped to its range; it glides there over about 20 ms.
|
|
455
|
+
public func setParameter(at index: Int, _ value: Float) {
|
|
456
|
+
guard index >= 0, index < parameterRegisters.count, value.isFinite else { return }
|
|
457
|
+
targets[index] = Swift.min(Swift.max(value, parameterRanges[index].min), parameterRanges[index].max)
|
|
458
|
+
}
|
|
459
|
+
|
|
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) {
|
|
548
|
+
if velocity <= 0 {
|
|
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
|
+
}
|
|
573
|
+
return
|
|
574
|
+
}
|
|
575
|
+
let voices = program.voices
|
|
576
|
+
var lane = -1
|
|
577
|
+
for l in 0..<voices where lane < 0 && laneNote[l] == note && laneGate[l] > 0.5 { lane = l }
|
|
578
|
+
var fresh = false
|
|
579
|
+
if lane < 0 {
|
|
580
|
+
for l in 0..<voices where lane < 0 && laneActive[l] == 0 { lane = l }
|
|
581
|
+
fresh = lane >= 0
|
|
582
|
+
}
|
|
583
|
+
if lane < 0 {
|
|
584
|
+
// Steal: the oldest released voice, else the oldest.
|
|
585
|
+
var best = -1
|
|
586
|
+
for l in 0..<voices where laneGate[l] <= 0.5 && !laneHeld[l] && (best < 0 || laneAge[l] < laneAge[best]) { best = l }
|
|
587
|
+
if best < 0 { for l in 0..<voices where best < 0 || laneAge[l] < laneAge[best] { best = l } }
|
|
588
|
+
lane = best
|
|
589
|
+
fresh = true
|
|
590
|
+
}
|
|
591
|
+
if fresh { resetLane(lane) }
|
|
592
|
+
laneNote[lane] = note
|
|
593
|
+
laneGate[lane] = 1
|
|
594
|
+
laneHeld[lane] = false
|
|
595
|
+
laneVelocity[lane] = Float(Double(Swift.min(127, velocity)) / 127)
|
|
596
|
+
laneActive[lane] = 1
|
|
597
|
+
trigger[lane] += 1
|
|
598
|
+
masterTrigger[0] += 1
|
|
599
|
+
newestLane = lane
|
|
600
|
+
age += 1
|
|
601
|
+
laneAge[lane] = age
|
|
602
|
+
}
|
|
603
|
+
|
|
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
|
+
}
|
|
620
|
+
for l in 0..<program.voices where laneNote[l] == note && laneGate[l] > 0.5 {
|
|
621
|
+
// Under the pedal the gate stays up until it lifts.
|
|
622
|
+
if pedal { laneHeld[l] = true } else { laneGate[l] = 0 }
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
private func control(_ number: Int32, value: Int32) {
|
|
627
|
+
let L = Self.lanes
|
|
628
|
+
switch number {
|
|
629
|
+
case 64:
|
|
630
|
+
pedal = value >= 64
|
|
631
|
+
if !pedal {
|
|
632
|
+
for l in 0..<L where laneHeld[l] { laneGate[l] = 0 }
|
|
633
|
+
laneHeld.update(repeating: false, count: L)
|
|
634
|
+
}
|
|
635
|
+
case 123:
|
|
636
|
+
laneGate.update(repeating: 0, count: L)
|
|
637
|
+
laneHeld.update(repeating: false, count: L)
|
|
638
|
+
stackCount = 0
|
|
639
|
+
case 120:
|
|
640
|
+
stackCount = 0
|
|
641
|
+
for l in 0..<L {
|
|
642
|
+
laneGate[l] = 0
|
|
643
|
+
laneHeld[l] = false
|
|
644
|
+
laneActive[l] = 0
|
|
645
|
+
resetLane(l)
|
|
646
|
+
}
|
|
647
|
+
resetMaster()
|
|
648
|
+
default:
|
|
649
|
+
break
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
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
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/// Silences every voice, and the master stage, at once, and drops what waits.
|
|
664
|
+
public func reset() {
|
|
665
|
+
controller(120, value: 0)
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/// How many voices sound now.
|
|
669
|
+
public var sounding: Int {
|
|
670
|
+
(0..<Self.lanes).reduce(0) { $0 + (laneActive[$1] != 0 ? 1 : 0) }
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// MARK: Rendering
|
|
674
|
+
|
|
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).
|
|
677
|
+
public func render(into out: UnsafeMutablePointer<Float>, frames: Int) {
|
|
678
|
+
var done = 0
|
|
679
|
+
while done < frames {
|
|
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)
|
|
697
|
+
done += n
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/// A voice starts over: its state and its builtins', not the master stage's.
|
|
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) {
|
|
717
|
+
let L = Self.lanes
|
|
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
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
private func block(_ out: UnsafeMutablePointer<Float>, _ right: UnsafeMutablePointer<Float>?, _ n: Int) {
|
|
745
|
+
let L = Self.lanes
|
|
746
|
+
let F = Self.frames
|
|
747
|
+
let W = width
|
|
748
|
+
let R = registers
|
|
749
|
+
let sr = sampleRate
|
|
750
|
+
// Parameters glide toward their targets, about 20 ms.
|
|
751
|
+
let alpha = snapped ? Float(1) : 1 - exp(-Float(n) / (0.02 * sr))
|
|
752
|
+
snapped = false
|
|
753
|
+
for (i, register) in parameterRegisters.enumerated() {
|
|
754
|
+
let at = R + register * W
|
|
755
|
+
at.update(repeating: at[0] + (targets[i] - at[0]) * alpha, count: W)
|
|
756
|
+
}
|
|
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
|
|
767
|
+
out.update(repeating: 0, count: n)
|
|
768
|
+
right?.update(repeating: 0, count: n)
|
|
769
|
+
return
|
|
770
|
+
}
|
|
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 } }
|
|
797
|
+
}
|
|
798
|
+
let o = R + program.output * W
|
|
799
|
+
let or = R + (program.outputRight ?? program.output) * W
|
|
800
|
+
let V = program.voices
|
|
801
|
+
var check: Float = 0
|
|
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
|
|
859
|
+
}
|
|
860
|
+
guard check.isFinite else {
|
|
861
|
+
// A voice or the master stage went to infinity or NaN: silence the block and start everything over.
|
|
862
|
+
out.update(repeating: 0, count: n)
|
|
863
|
+
right?.update(repeating: 0, count: n)
|
|
864
|
+
for l in 0..<L {
|
|
865
|
+
laneActive[l] = 0
|
|
866
|
+
laneGate[l] = 0
|
|
867
|
+
laneHeld[l] = false
|
|
868
|
+
resetLane(l)
|
|
869
|
+
}
|
|
870
|
+
resetMaster()
|
|
871
|
+
return
|
|
872
|
+
}
|
|
873
|
+
// Denormals in the filters' integrators would slow every frame after.
|
|
874
|
+
for offset in filterOffsets {
|
|
875
|
+
for k in offset..<(offset + 2 * L) where Swift.abs(state[k]) < 1e-20 { state[k] = 0 }
|
|
876
|
+
}
|
|
877
|
+
// A released voice sounds until its envelopes finish.
|
|
878
|
+
for l in 0..<L where laneActive[l] != 0 && laneGate[l] <= 0.5 && !laneHeld[l] {
|
|
879
|
+
var sounding = false
|
|
880
|
+
for offset in envelopeOffsets where state[offset + l] != 0 { sounding = true }
|
|
881
|
+
if !sounding { laneActive[l] = 0 }
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
@inline(__always)
|
|
886
|
+
private static func blep(_ t: Float, _ dt: Float) -> Float {
|
|
887
|
+
if t < dt {
|
|
888
|
+
let x = t / dt
|
|
889
|
+
return x + x - x * x - 1
|
|
890
|
+
}
|
|
891
|
+
if t > 1 - dt {
|
|
892
|
+
let x = (t - 1) / dt
|
|
893
|
+
return x * x + x + x + 1
|
|
894
|
+
}
|
|
895
|
+
return 0
|
|
896
|
+
}
|
|
897
|
+
|
|
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
|
+
) {
|
|
910
|
+
let L = Self.lanes
|
|
911
|
+
let F = Self.frames
|
|
912
|
+
let R = registers
|
|
913
|
+
let S = state
|
|
914
|
+
let N = noise
|
|
915
|
+
let sr = sampleRate
|
|
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
|
|
935
|
+
while at < end {
|
|
936
|
+
let op = code[at]
|
|
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)
|
|
946
|
+
switch op {
|
|
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
|
+
}
|
|
1073
|
+
case 40, 41, 42, 43, 44:
|
|
1074
|
+
// Oscillators: the output from the phase now, then the phase steps by freq / sampleRate.
|
|
1075
|
+
let s = S + Int(code[at + 7])
|
|
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)
|
|
1096
|
+
}
|
|
1097
|
+
d[el] = v
|
|
1098
|
+
let next = p + dt
|
|
1099
|
+
s[l] = next >= 0 && next < 1 ? next : next - next.rounded(.down)
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
case 45:
|
|
1103
|
+
let s = N + Int(code[at + 7])
|
|
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
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
case 46:
|
|
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.
|
|
1119
|
+
let s = S + Int(code[at + 7])
|
|
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
|
|
1139
|
+
}
|
|
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
|
+
}
|
|
1150
|
+
}
|
|
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 {
|
|
1180
|
+
level = 0
|
|
1181
|
+
}
|
|
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
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
case 47, 48, 49:
|
|
1201
|
+
// A state-variable filter (Simper's form): resonance 0 … 1.
|
|
1202
|
+
let s = S + Int(code[at + 7])
|
|
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]
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
default:
|
|
1556
|
+
break
|
|
1557
|
+
}
|
|
1558
|
+
at += 12
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
}
|