@swiftbrowser/native 0.18.3 → 0.19.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 +19 -0
- package/bin/swiftbrowser-native.mjs +47 -0
- package/dist/bridge.d.ts +34 -7
- 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 +10 -4
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +19 -11
- package/dist/fetch.js.map +1 -1
- package/dist/hostRequests.d.ts +22 -6
- package/dist/hostRequests.d.ts.map +1 -1
- package/dist/hostRequests.js +65 -13
- package/dist/hostRequests.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 +24 -10
- package/dist/webSocket.js.map +1 -1
- package/package.json +7 -3
- package/src/bridge.ts +30 -7
- package/src/encoding.ts +22 -0
- package/src/fetch.ts +18 -13
- package/src/hostRequests.ts +72 -19
- package/src/ios.ts +253 -0
- package/src/runtime.ts +23 -8
- package/src/subtle.ts +10 -6
- package/src/webSocket.ts +27 -12
- package/swift/Packages/SwiftBrowserDSP/Package.swift +31 -0
- package/swift/Packages/SwiftBrowserDSP/README.md +42 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSP/ProgramNode.swift +203 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Machine.swift +523 -0
- package/swift/Packages/SwiftBrowserDSP/Sources/SwiftBrowserDSPCore/Program.swift +188 -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/Sources/SwiftBrowserNative/Host/AudioEngineBridge.swift +921 -0
- package/swift/Sources/SwiftBrowserNative/Host/AudioEngineNodes.swift +70 -0
- package/swift/Sources/SwiftBrowserNative/Host/FilesBridge.swift +3 -3
- package/swift/Sources/SwiftBrowserNative/Host/HostBridge.swift +106 -28
- package/swift/Sources/SwiftBrowserNative/Host/HostRequestBridge.swift +43 -13
- 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/Views/ElementView.swift +1 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Controls.swift +18 -1
- 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 +81 -20
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/PinchTracker.swift +200 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/PopTap.swift +100 -0
- package/swift/Sources/SwiftBrowserNative/Views/Kinds/Stacks.swift +3 -2
- package/swift/Sources/SwiftBrowserNative/Views/StyleModifier.swift +4 -0
- package/swift/Sources/SwiftBrowserProtocol/Props.swift +26 -0
- package/swift/Sources/SwiftBrowserTree/OpTree.swift +25 -0
- package/wasm/SwiftBrowserNative.wasm +2 -2
|
@@ -0,0 +1,523 @@
|
|
|
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.
|
|
21
|
+
public final class DSPMachine: @unchecked Sendable {
|
|
22
|
+
public let program: DSPProgram
|
|
23
|
+
public let sampleRate: Float
|
|
24
|
+
|
|
25
|
+
private static let lanes = 16
|
|
26
|
+
private let registers: UnsafeMutablePointer<Float>
|
|
27
|
+
private let state: UnsafeMutablePointer<Float>
|
|
28
|
+
private let stateCount: Int
|
|
29
|
+
private let noise: UnsafeMutablePointer<UInt32>
|
|
30
|
+
private let noiseCount: Int
|
|
31
|
+
private let blockCode: UnsafeMutablePointer<Int32>
|
|
32
|
+
private let blockCount: Int
|
|
33
|
+
private let sampleCode: UnsafeMutablePointer<Int32>
|
|
34
|
+
private let sampleCount: Int
|
|
35
|
+
/// Each instance's builtin and where its state starts (in floats, lanes included; a noise instance's in `noise`).
|
|
36
|
+
private let instanceKinds: [DSPBuiltin]
|
|
37
|
+
private let instanceOffsets: [Int]
|
|
38
|
+
private let envelopeOffsets: [Int]
|
|
39
|
+
private let filterOffsets: [Int]
|
|
40
|
+
private let parameterRegisters: [Int]
|
|
41
|
+
private let parameterRanges: [(min: Float, max: Float)]
|
|
42
|
+
private let parameterIndices: [String: Int]
|
|
43
|
+
private let targets: UnsafeMutablePointer<Float>
|
|
44
|
+
private var snapped = true
|
|
45
|
+
|
|
46
|
+
private let laneNote: UnsafeMutablePointer<Int32>
|
|
47
|
+
private let laneGate: UnsafeMutablePointer<Float>
|
|
48
|
+
private let laneVelocity: UnsafeMutablePointer<Float>
|
|
49
|
+
private let laneHeld: UnsafeMutablePointer<Bool>
|
|
50
|
+
private let laneActive: UnsafeMutablePointer<Float>
|
|
51
|
+
private let laneAge: UnsafeMutablePointer<Double>
|
|
52
|
+
private let trigger: UnsafeMutablePointer<Float>
|
|
53
|
+
private var age: Double = 0
|
|
54
|
+
private var pedal = false
|
|
55
|
+
private var bend: Double = 0
|
|
56
|
+
|
|
57
|
+
public init(program: DSPProgram, sampleRate: Double) {
|
|
58
|
+
let L = Self.lanes
|
|
59
|
+
self.program = program
|
|
60
|
+
self.sampleRate = Float(sampleRate)
|
|
61
|
+
registers = .allocate(capacity: program.registers * L)
|
|
62
|
+
registers.initialize(repeating: 0, count: program.registers * L)
|
|
63
|
+
var kinds: [DSPBuiltin] = []
|
|
64
|
+
var offsets: [Int] = []
|
|
65
|
+
var envelopes: [Int] = []
|
|
66
|
+
var filters: [Int] = []
|
|
67
|
+
var words = 0
|
|
68
|
+
var noises = 0
|
|
69
|
+
for builtin in program.instances {
|
|
70
|
+
kinds.append(builtin)
|
|
71
|
+
if builtin == .noise {
|
|
72
|
+
offsets.append(noises * L)
|
|
73
|
+
noises += 1
|
|
74
|
+
} else {
|
|
75
|
+
offsets.append(words * L)
|
|
76
|
+
if builtin == .adsr { envelopes.append(words * L) }
|
|
77
|
+
if builtin == .lowpass || builtin == .highpass || builtin == .bandpass { filters.append(words * L) }
|
|
78
|
+
words += builtin.words
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
instanceKinds = kinds
|
|
82
|
+
instanceOffsets = offsets
|
|
83
|
+
envelopeOffsets = envelopes
|
|
84
|
+
filterOffsets = filters
|
|
85
|
+
stateCount = max(1, words) * L
|
|
86
|
+
state = .allocate(capacity: stateCount)
|
|
87
|
+
state.initialize(repeating: 0, count: stateCount)
|
|
88
|
+
noiseCount = max(1, noises) * L
|
|
89
|
+
noise = .allocate(capacity: noiseCount)
|
|
90
|
+
noise.initialize(repeating: 1, count: noiseCount)
|
|
91
|
+
(blockCode, blockCount) = Self.decode(program.block, offsets: offsets)
|
|
92
|
+
(sampleCode, sampleCount) = Self.decode(program.sample, offsets: offsets)
|
|
93
|
+
for constant in program.constants {
|
|
94
|
+
(registers + constant.register * L).update(repeating: constant.value, count: L)
|
|
95
|
+
}
|
|
96
|
+
registers.update(repeating: Float(sampleRate), count: L)
|
|
97
|
+
parameterRegisters = program.parameters.map(\.register)
|
|
98
|
+
parameterRanges = program.parameters.map { ($0.min, $0.max) }
|
|
99
|
+
parameterIndices = Dictionary(program.parameters.enumerated().map { ($1.name, $0) }, uniquingKeysWith: { first, _ in first })
|
|
100
|
+
targets = .allocate(capacity: max(1, program.parameters.count))
|
|
101
|
+
for (i, parameter) in program.parameters.enumerated() {
|
|
102
|
+
targets[i] = parameter.defaultValue
|
|
103
|
+
(registers + parameter.register * L).update(repeating: parameter.defaultValue, count: L)
|
|
104
|
+
}
|
|
105
|
+
laneNote = .allocate(capacity: L)
|
|
106
|
+
laneNote.initialize(repeating: -1, count: L)
|
|
107
|
+
laneGate = .allocate(capacity: L)
|
|
108
|
+
laneGate.initialize(repeating: 0, count: L)
|
|
109
|
+
laneVelocity = .allocate(capacity: L)
|
|
110
|
+
laneVelocity.initialize(repeating: 0, count: L)
|
|
111
|
+
laneHeld = .allocate(capacity: L)
|
|
112
|
+
laneHeld.initialize(repeating: false, count: L)
|
|
113
|
+
laneActive = .allocate(capacity: L)
|
|
114
|
+
laneActive.initialize(repeating: 0, count: L)
|
|
115
|
+
laneAge = .allocate(capacity: L)
|
|
116
|
+
laneAge.initialize(repeating: 0, count: L)
|
|
117
|
+
trigger = .allocate(capacity: L)
|
|
118
|
+
trigger.initialize(repeating: 0, count: L)
|
|
119
|
+
for lane in 0..<L { resetLane(lane) }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
deinit {
|
|
123
|
+
for pointer in [registers, state, targets, laneGate, laneVelocity, laneActive, trigger] { pointer.deallocate() }
|
|
124
|
+
noise.deallocate()
|
|
125
|
+
blockCode.deallocate()
|
|
126
|
+
sampleCode.deallocate()
|
|
127
|
+
laneNote.deallocate()
|
|
128
|
+
laneHeld.deallocate()
|
|
129
|
+
laneAge.deallocate()
|
|
130
|
+
}
|
|
131
|
+
|
|
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) {
|
|
134
|
+
var out: [Int32] = []
|
|
135
|
+
var pc = 0
|
|
136
|
+
while pc < code.count {
|
|
137
|
+
let op = DSPOpcode(rawValue: code[pc])!
|
|
138
|
+
var slot = [Int32](repeating: 0, count: 8)
|
|
139
|
+
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) }
|
|
142
|
+
if op.builtin != nil { slot[7] = Int32(offsets[Int(code[pc + 2 + op.arity])]) }
|
|
143
|
+
out += slot
|
|
144
|
+
pc += 2 + op.arity + (op.builtin == nil ? 0 : 1)
|
|
145
|
+
}
|
|
146
|
+
let pointer = UnsafeMutablePointer<Int32>.allocate(capacity: max(8, out.count))
|
|
147
|
+
pointer.initialize(repeating: 0, count: max(8, out.count))
|
|
148
|
+
out.withUnsafeBufferPointer { pointer.update(from: $0.baseAddress!, count: out.count) }
|
|
149
|
+
return (pointer, out.count / 8)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// MARK: Events
|
|
153
|
+
|
|
154
|
+
/// The index `setParameter(at:_:)` takes for a parameter's name: look it up off the audio thread.
|
|
155
|
+
public func parameterIndex(_ name: String) -> Int? {
|
|
156
|
+
parameterIndices[name]
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/// A parameter, clamped to its range; it glides there over about 20 ms.
|
|
160
|
+
public func setParameter(at index: Int, _ value: Float) {
|
|
161
|
+
guard index >= 0, index < parameterRegisters.count, value.isFinite else { return }
|
|
162
|
+
targets[index] = Swift.min(Swift.max(value, parameterRanges[index].min), parameterRanges[index].max)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// MIDI note on: `velocity` 1 … 127 (0 is a note off).
|
|
166
|
+
public func noteOn(_ note: Int32, velocity: Int32) {
|
|
167
|
+
if velocity <= 0 {
|
|
168
|
+
noteOff(note)
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
let voices = program.voices
|
|
172
|
+
var lane = -1
|
|
173
|
+
for l in 0..<voices where lane < 0 && laneNote[l] == note && laneGate[l] > 0.5 { lane = l }
|
|
174
|
+
var fresh = false
|
|
175
|
+
if lane < 0 {
|
|
176
|
+
for l in 0..<voices where lane < 0 && laneActive[l] == 0 { lane = l }
|
|
177
|
+
fresh = lane >= 0
|
|
178
|
+
}
|
|
179
|
+
if lane < 0 {
|
|
180
|
+
// Steal: the oldest released voice, else the oldest.
|
|
181
|
+
var best = -1
|
|
182
|
+
for l in 0..<voices where laneGate[l] <= 0.5 && !laneHeld[l] && (best < 0 || laneAge[l] < laneAge[best]) { best = l }
|
|
183
|
+
if best < 0 { for l in 0..<voices where best < 0 || laneAge[l] < laneAge[best] { best = l } }
|
|
184
|
+
lane = best
|
|
185
|
+
fresh = true
|
|
186
|
+
}
|
|
187
|
+
if fresh { resetLane(lane) }
|
|
188
|
+
laneNote[lane] = note
|
|
189
|
+
laneGate[lane] = 1
|
|
190
|
+
laneHeld[lane] = false
|
|
191
|
+
laneVelocity[lane] = Float(Double(Swift.min(127, velocity)) / 127)
|
|
192
|
+
laneActive[lane] = 1
|
|
193
|
+
trigger[lane] += 1
|
|
194
|
+
age += 1
|
|
195
|
+
laneAge[lane] = age
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public func noteOff(_ note: Int32) {
|
|
199
|
+
for l in 0..<program.voices where laneNote[l] == note && laneGate[l] > 0.5 {
|
|
200
|
+
// Under the pedal the gate stays up until it lifts.
|
|
201
|
+
if pedal { laneHeld[l] = true } else { laneGate[l] = 0 }
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/// 64 the sustain pedal, 120 all sound off, 123 all notes off.
|
|
206
|
+
public func controller(_ number: Int32, value: Int32) {
|
|
207
|
+
let L = Self.lanes
|
|
208
|
+
switch number {
|
|
209
|
+
case 64:
|
|
210
|
+
pedal = value >= 64
|
|
211
|
+
if !pedal {
|
|
212
|
+
for l in 0..<L where laneHeld[l] { laneGate[l] = 0 }
|
|
213
|
+
laneHeld.update(repeating: false, count: L)
|
|
214
|
+
}
|
|
215
|
+
case 123:
|
|
216
|
+
laneGate.update(repeating: 0, count: L)
|
|
217
|
+
laneHeld.update(repeating: false, count: L)
|
|
218
|
+
case 120:
|
|
219
|
+
for l in 0..<L {
|
|
220
|
+
laneGate[l] = 0
|
|
221
|
+
laneHeld[l] = false
|
|
222
|
+
laneActive[l] = 0
|
|
223
|
+
resetLane(l)
|
|
224
|
+
}
|
|
225
|
+
default:
|
|
226
|
+
break
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
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
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/// Silences every voice at once.
|
|
236
|
+
public func reset() {
|
|
237
|
+
controller(120, value: 0)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/// How many voices sound now.
|
|
241
|
+
public var sounding: Int {
|
|
242
|
+
(0..<Self.lanes).reduce(0) { $0 + (laneActive[$1] != 0 ? 1 : 0) }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// MARK: Rendering
|
|
246
|
+
|
|
247
|
+
/// Writes `frames` mono frames to `out`, in blocks of up to 128.
|
|
248
|
+
public func render(into out: UnsafeMutablePointer<Float>, frames: Int) {
|
|
249
|
+
var done = 0
|
|
250
|
+
while done < frames {
|
|
251
|
+
let n = Swift.min(DSPProgram.blockFrames, frames - done)
|
|
252
|
+
block(out + done, n)
|
|
253
|
+
done += n
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private func resetLane(_ l: Int) {
|
|
258
|
+
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
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private func block(_ out: UnsafeMutablePointer<Float>, _ n: Int) {
|
|
278
|
+
let L = Self.lanes
|
|
279
|
+
let R = registers
|
|
280
|
+
let sr = sampleRate
|
|
281
|
+
// Parameters glide toward their targets, about 20 ms.
|
|
282
|
+
let alpha = snapped ? Float(1) : 1 - exp(-Float(n) / (0.02 * sr))
|
|
283
|
+
snapped = false
|
|
284
|
+
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)
|
|
287
|
+
}
|
|
288
|
+
var any = false
|
|
289
|
+
for l in 0..<L where laneActive[l] != 0 { any = true }
|
|
290
|
+
guard any else {
|
|
291
|
+
out.update(repeating: 0, count: n)
|
|
292
|
+
return
|
|
293
|
+
}
|
|
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
|
|
300
|
+
}
|
|
301
|
+
run(blockCode, blockCount)
|
|
302
|
+
let o = R + program.output * L
|
|
303
|
+
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
|
|
310
|
+
}
|
|
311
|
+
guard check.isFinite else {
|
|
312
|
+
// A voice went to infinity or NaN: silence the block and start every voice over.
|
|
313
|
+
out.update(repeating: 0, count: n)
|
|
314
|
+
for l in 0..<L {
|
|
315
|
+
laneActive[l] = 0
|
|
316
|
+
laneGate[l] = 0
|
|
317
|
+
laneHeld[l] = false
|
|
318
|
+
resetLane(l)
|
|
319
|
+
}
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
// Denormals in the filters' integrators would slow every frame after.
|
|
323
|
+
for offset in filterOffsets {
|
|
324
|
+
for k in offset..<(offset + 2 * L) where Swift.abs(state[k]) < 1e-20 { state[k] = 0 }
|
|
325
|
+
}
|
|
326
|
+
// A released voice sounds until its envelopes finish.
|
|
327
|
+
for l in 0..<L where laneActive[l] != 0 && laneGate[l] <= 0.5 && !laneHeld[l] {
|
|
328
|
+
var sounding = false
|
|
329
|
+
for offset in envelopeOffsets where state[offset + l] != 0 { sounding = true }
|
|
330
|
+
if !sounding { laneActive[l] = 0 }
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@inline(__always)
|
|
335
|
+
private static func blep(_ t: Float, _ dt: Float) -> Float {
|
|
336
|
+
if t < dt {
|
|
337
|
+
let x = t / dt
|
|
338
|
+
return x + x - x * x - 1
|
|
339
|
+
}
|
|
340
|
+
if t > 1 - dt {
|
|
341
|
+
let x = (t - 1) / dt
|
|
342
|
+
return x * x + x + x + 1
|
|
343
|
+
}
|
|
344
|
+
return 0
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// The interpreter: one instruction at a time, every lane per instruction.
|
|
348
|
+
private func run(_ code: UnsafeMutablePointer<Int32>, _ count: Int) {
|
|
349
|
+
let L = Self.lanes
|
|
350
|
+
let R = registers
|
|
351
|
+
let S = state
|
|
352
|
+
let N = noise
|
|
353
|
+
let sr = sampleRate
|
|
354
|
+
var at = 0
|
|
355
|
+
let end = count * 8
|
|
356
|
+
while at < end {
|
|
357
|
+
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])
|
|
362
|
+
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]) }
|
|
399
|
+
case 40, 41, 42, 43, 44:
|
|
400
|
+
// Oscillators: the output from the phase now, then the phase steps by freq / sampleRate.
|
|
401
|
+
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)
|
|
418
|
+
}
|
|
419
|
+
default: v = 1 - 4 * Swift.abs(p - 0.5)
|
|
420
|
+
}
|
|
421
|
+
d[l] = v
|
|
422
|
+
let next = p + dt
|
|
423
|
+
s[l] = next - next.rounded(.down)
|
|
424
|
+
}
|
|
425
|
+
case 45:
|
|
426
|
+
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)
|
|
434
|
+
}
|
|
435
|
+
case 46:
|
|
436
|
+
// adsr(gate, attack, decay, sustain, release): stage, level, trigger, gate before, decay time and coefficient, release time and coefficient.
|
|
437
|
+
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))
|
|
464
|
+
}
|
|
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))
|
|
474
|
+
}
|
|
475
|
+
level *= s[7 * L + l]
|
|
476
|
+
if level < 0.0001 {
|
|
477
|
+
level = 0
|
|
478
|
+
stage = 0
|
|
479
|
+
}
|
|
480
|
+
} else {
|
|
481
|
+
level = 0
|
|
482
|
+
}
|
|
483
|
+
s[l] = stage
|
|
484
|
+
s[L + l] = level
|
|
485
|
+
d[l] = level
|
|
486
|
+
}
|
|
487
|
+
case 47, 48, 49:
|
|
488
|
+
// A state-variable filter (Simper's form): resonance 0 … 1.
|
|
489
|
+
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
|
|
503
|
+
}
|
|
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
|
+
}
|
|
517
|
+
default:
|
|
518
|
+
break
|
|
519
|
+
}
|
|
520
|
+
at += 8
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|