@neurodevs/node-lsl 18.1.0 → 20.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/build/__tests__/AbstractPackageTest.d.ts +19 -17
  2. package/build/__tests__/AbstractPackageTest.js +54 -39
  3. package/build/__tests__/AbstractPackageTest.js.map +1 -1
  4. package/build/__tests__/impl/BleDeviceController.test.d.ts +6 -1
  5. package/build/__tests__/impl/BleDeviceController.test.js +44 -15
  6. package/build/__tests__/impl/BleDeviceController.test.js.map +1 -1
  7. package/build/__tests__/impl/LslEventMarkerEmitter.test.js +13 -13
  8. package/build/__tests__/impl/LslEventMarkerEmitter.test.js.map +1 -1
  9. package/build/__tests__/impl/LslStreamInfo.test.js +2 -2
  10. package/build/__tests__/impl/LslStreamInfo.test.js.map +1 -1
  11. package/build/__tests__/impl/LslStreamInlet.test.d.ts +3 -5
  12. package/build/__tests__/impl/LslStreamInlet.test.js +13 -46
  13. package/build/__tests__/impl/LslStreamInlet.test.js.map +1 -1
  14. package/build/__tests__/impl/LslStreamOutlet.test.js +9 -16
  15. package/build/__tests__/impl/LslStreamOutlet.test.js.map +1 -1
  16. package/build/__tests__/impl/LslWebSocketBridge.test.js +9 -10
  17. package/build/__tests__/impl/LslWebSocketBridge.test.js.map +1 -1
  18. package/build/__tests__/impl/UsbDeviceController.test.d.ts +17 -0
  19. package/build/__tests__/impl/UsbDeviceController.test.js +81 -0
  20. package/build/__tests__/impl/UsbDeviceController.test.js.map +1 -0
  21. package/build/__tests__/impl/WindowedClockRegressor.test.d.ts +19 -0
  22. package/build/__tests__/impl/WindowedClockRegressor.test.js +172 -0
  23. package/build/__tests__/impl/WindowedClockRegressor.test.js.map +1 -0
  24. package/build/assertions.js +1 -1
  25. package/build/assertions.js.map +1 -1
  26. package/build/impl/LslEventMarkerEmitter.d.ts +12 -12
  27. package/build/impl/LslEventMarkerEmitter.js.map +1 -1
  28. package/build/impl/LslStreamInfo.d.ts +7 -7
  29. package/build/impl/LslStreamInfo.js.map +1 -1
  30. package/build/impl/LslStreamInlet.d.ts +63 -20
  31. package/build/impl/LslStreamInlet.js +221 -64
  32. package/build/impl/LslStreamInlet.js.map +1 -1
  33. package/build/impl/LslStreamOutlet.d.ts +16 -14
  34. package/build/impl/LslStreamOutlet.js +34 -37
  35. package/build/impl/LslStreamOutlet.js.map +1 -1
  36. package/build/impl/LslWebSocketBridge.d.ts +10 -10
  37. package/build/impl/LslWebSocketBridge.js.map +1 -1
  38. package/build/impl/clocks/WindowedClockRegressor.d.ts +24 -0
  39. package/build/impl/clocks/WindowedClockRegressor.js +73 -0
  40. package/build/impl/clocks/WindowedClockRegressor.js.map +1 -0
  41. package/build/impl/controllers/BleDeviceController.d.ts +3 -1
  42. package/build/impl/controllers/BleDeviceController.js +9 -1
  43. package/build/impl/controllers/BleDeviceController.js.map +1 -1
  44. package/build/impl/controllers/UsbDeviceController.d.ts +23 -0
  45. package/build/impl/controllers/UsbDeviceController.js +40 -0
  46. package/build/impl/controllers/UsbDeviceController.js.map +1 -0
  47. package/build/index.d.ts +32 -20
  48. package/build/index.js +39 -26
  49. package/build/index.js.map +1 -1
  50. package/build/scripts/{runLslEventMarkerEmitter.js → runLslEmitter.js} +5 -4
  51. package/build/scripts/runLslEmitter.js.map +1 -0
  52. package/build/scripts/{runLslStreamOutlet.js → runLslOutlet.js} +1 -1
  53. package/build/scripts/runLslOutlet.js.map +1 -0
  54. package/build/scripts/runMuse.js +1 -1
  55. package/build/scripts/runMuse.js.map +1 -1
  56. package/build/scripts/runUsb.js +14 -0
  57. package/build/scripts/runUsb.js.map +1 -0
  58. package/build/testDoubles/BleController/FakeBleController.d.ts +3 -1
  59. package/build/testDoubles/BleController/FakeBleController.js +5 -0
  60. package/build/testDoubles/BleController/FakeBleController.js.map +1 -1
  61. package/build/testDoubles/ClockRegressor/FakeClockRegressor.d.ts +17 -0
  62. package/build/testDoubles/ClockRegressor/FakeClockRegressor.js +23 -0
  63. package/build/testDoubles/ClockRegressor/FakeClockRegressor.js.map +1 -0
  64. package/build/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.d.ts → LslEmitter/FakeLslEmitter.d.ts} +4 -4
  65. package/build/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.js → LslEmitter/FakeLslEmitter.js} +7 -7
  66. package/build/testDoubles/LslEmitter/FakeLslEmitter.js.map +1 -0
  67. package/build/testDoubles/{EventMarkerEmitter/SpyEventMarkerEmitter.d.ts → LslEmitter/SpyLslEmitter.d.ts} +4 -4
  68. package/build/testDoubles/{EventMarkerEmitter/SpyEventMarkerEmitter.js → LslEmitter/SpyLslEmitter.js} +3 -3
  69. package/build/testDoubles/LslEmitter/SpyLslEmitter.js.map +1 -0
  70. package/build/testDoubles/LslEmitter/ThrowingLslEmitter.d.ts +9 -0
  71. package/build/testDoubles/{EventMarkerEmitter/ThrowingEventMarkerEmitter.js → LslEmitter/ThrowingLslEmitter.js} +2 -2
  72. package/build/testDoubles/LslEmitter/ThrowingLslEmitter.js.map +1 -0
  73. package/build/testDoubles/{StreamInfo/FakeStreamInfo.d.ts → LslInfo/FakeLslInfo.d.ts} +4 -4
  74. package/build/testDoubles/{StreamInfo/FakeStreamInfo.js → LslInfo/FakeLslInfo.js} +7 -7
  75. package/build/testDoubles/LslInfo/FakeLslInfo.js.map +1 -0
  76. package/build/testDoubles/LslInfo/SpyLslInfo.d.ts +10 -0
  77. package/build/testDoubles/{StreamInfo/SpyStreamInfo.js → LslInfo/SpyLslInfo.js} +4 -4
  78. package/build/testDoubles/LslInfo/SpyLslInfo.js.map +1 -0
  79. package/build/testDoubles/{StreamInlet/FakeStreamInlet.d.ts → LslInlet/FakeLslInlet.d.ts} +4 -4
  80. package/build/testDoubles/{StreamInlet/FakeStreamInlet.js → LslInlet/FakeLslInlet.js} +12 -11
  81. package/build/testDoubles/LslInlet/FakeLslInlet.js.map +1 -0
  82. package/build/testDoubles/LslInlet/SpyLslInlet.d.ts +4 -0
  83. package/build/testDoubles/{StreamInlet/SpyStreamInlet.js → LslInlet/SpyLslInlet.js} +2 -2
  84. package/build/testDoubles/LslInlet/SpyLslInlet.js.map +1 -0
  85. package/build/testDoubles/{StreamOutlet/FakeStreamOutlet.d.ts → LslOutlet/FakeLslOutlet.d.ts} +5 -5
  86. package/build/testDoubles/{StreamOutlet/FakeStreamOutlet.js → LslOutlet/FakeLslOutlet.js} +8 -8
  87. package/build/testDoubles/LslOutlet/FakeLslOutlet.js.map +1 -0
  88. package/build/testDoubles/LslWsBridge/FakeLslWsBridge.d.ts +14 -0
  89. package/build/testDoubles/{WebSocketBridge/FakeWebSocketBridge.js → LslWsBridge/FakeLslWsBridge.js} +14 -14
  90. package/build/testDoubles/LslWsBridge/FakeLslWsBridge.js.map +1 -0
  91. package/build/testDoubles/LslWsBridge/SpyLslWsBridge.d.ts +4 -0
  92. package/build/testDoubles/{WebSocketBridge/SpyLslWebSocketBridge.js → LslWsBridge/SpyLslWsBridge.js} +2 -2
  93. package/build/testDoubles/LslWsBridge/SpyLslWsBridge.js.map +1 -0
  94. package/build/testDoubles/UsbController/FakeUsbController.d.ts +12 -0
  95. package/build/testDoubles/UsbController/FakeUsbController.js +25 -0
  96. package/build/testDoubles/UsbController/FakeUsbController.js.map +1 -0
  97. package/build/testDoubles/consts.d.ts +2 -12
  98. package/build/testDoubles/consts.js +0 -20
  99. package/build/testDoubles/consts.js.map +1 -1
  100. package/build/testDoubles/generateRandomOutletOptions.d.ts +2 -2
  101. package/build/testDoubles/generateRandomOutletOptions.js.map +1 -1
  102. package/package.json +6 -5
  103. package/src/__tests__/AbstractPackageTest.ts +78 -49
  104. package/src/__tests__/impl/BleDeviceController.test.ts +59 -18
  105. package/src/__tests__/impl/LslEventMarkerEmitter.test.ts +19 -24
  106. package/src/__tests__/impl/LslStreamInfo.test.ts +8 -8
  107. package/src/__tests__/impl/LslStreamInlet.test.ts +21 -78
  108. package/src/__tests__/impl/LslStreamOutlet.test.ts +22 -28
  109. package/src/__tests__/impl/LslWebSocketBridge.test.ts +15 -18
  110. package/src/__tests__/impl/UsbDeviceController.test.ts +109 -0
  111. package/src/__tests__/impl/WindowedClockRegressor.test.ts +262 -0
  112. package/src/assertions.ts +1 -2
  113. package/src/impl/LslEventMarkerEmitter.ts +15 -17
  114. package/src/impl/LslStreamInfo.ts +7 -9
  115. package/src/impl/LslStreamInlet.ts +304 -77
  116. package/src/impl/LslStreamOutlet.ts +59 -57
  117. package/src/impl/LslWebSocketBridge.ts +15 -18
  118. package/src/impl/clocks/WindowedClockRegressor.ts +136 -0
  119. package/src/impl/controllers/BleDeviceController.ts +18 -1
  120. package/src/impl/controllers/UsbDeviceController.ts +65 -0
  121. package/src/index.ts +48 -28
  122. package/src/scripts/{runLslEventMarkerEmitter.ts → runLslEmitter.ts} +4 -3
  123. package/src/scripts/runMuse.ts +1 -1
  124. package/src/scripts/runUsb.ts +20 -0
  125. package/src/testDoubles/BleController/FakeBleController.ts +11 -0
  126. package/src/testDoubles/ClockRegressor/FakeClockRegressor.ts +46 -0
  127. package/src/testDoubles/{EventMarkerEmitter/FakeEventMarkerEmitter.ts → LslEmitter/FakeLslEmitter.ts} +10 -10
  128. package/src/testDoubles/{EventMarkerEmitter/SpyEventMarkerEmitter.ts → LslEmitter/SpyLslEmitter.ts} +4 -4
  129. package/src/testDoubles/{EventMarkerEmitter/ThrowingEventMarkerEmitter.ts → LslEmitter/ThrowingLslEmitter.ts} +4 -4
  130. package/src/testDoubles/{StreamInfo/FakeStreamInfo.ts → LslInfo/FakeLslInfo.ts} +9 -9
  131. package/src/testDoubles/{StreamInfo/SpyStreamInfo.ts → LslInfo/SpyLslInfo.ts} +5 -5
  132. package/src/testDoubles/{StreamInlet/FakeStreamInlet.ts → LslInlet/FakeLslInlet.ts} +15 -14
  133. package/src/testDoubles/LslInlet/SpyLslInlet.ts +10 -0
  134. package/src/testDoubles/{StreamOutlet/FakeStreamOutlet.ts → LslOutlet/FakeLslOutlet.ts} +11 -14
  135. package/src/testDoubles/{WebSocketBridge/FakeWebSocketBridge.ts → LslWsBridge/FakeLslWsBridge.ts} +19 -20
  136. package/src/testDoubles/LslWsBridge/SpyLslWsBridge.ts +9 -0
  137. package/src/testDoubles/UsbController/FakeUsbController.ts +34 -0
  138. package/src/testDoubles/consts.ts +3 -23
  139. package/src/testDoubles/generateRandomOutletOptions.ts +2 -2
  140. package/build/consts.d.ts +0 -11
  141. package/build/consts.js +0 -21
  142. package/build/consts.js.map +0 -1
  143. package/build/impl/workers/inlet/LslStreamInlet.worker.d.ts +0 -22
  144. package/build/impl/workers/inlet/LslStreamInlet.worker.js +0 -42
  145. package/build/impl/workers/inlet/LslStreamInlet.worker.js.map +0 -1
  146. package/build/impl/workers/inlet/StreamInletWorker.d.ts +0 -73
  147. package/build/impl/workers/inlet/StreamInletWorker.js +0 -253
  148. package/build/impl/workers/inlet/StreamInletWorker.js.map +0 -1
  149. package/build/impl/workers/outlet/LslStreamOutlet.worker.d.ts +0 -32
  150. package/build/impl/workers/outlet/LslStreamOutlet.worker.js +0 -82
  151. package/build/impl/workers/outlet/LslStreamOutlet.worker.js.map +0 -1
  152. package/build/scripts/discoverMuse.js +0 -40
  153. package/build/scripts/discoverMuse.js.map +0 -1
  154. package/build/scripts/runLslEventMarkerEmitter.js.map +0 -1
  155. package/build/scripts/runLslStreamOutlet.js.map +0 -1
  156. package/build/scripts/testDestroyOutlet.d.ts +0 -1
  157. package/build/scripts/testDestroyOutlet.js +0 -4
  158. package/build/scripts/testDestroyOutlet.js.map +0 -1
  159. package/build/testDoubles/EventMarkerEmitter/FakeEventMarkerEmitter.js.map +0 -1
  160. package/build/testDoubles/EventMarkerEmitter/SpyEventMarkerEmitter.js.map +0 -1
  161. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.d.ts +0 -9
  162. package/build/testDoubles/EventMarkerEmitter/ThrowingEventMarkerEmitter.js.map +0 -1
  163. package/build/testDoubles/StreamInfo/FakeStreamInfo.js.map +0 -1
  164. package/build/testDoubles/StreamInfo/SpyStreamInfo.d.ts +0 -10
  165. package/build/testDoubles/StreamInfo/SpyStreamInfo.js.map +0 -1
  166. package/build/testDoubles/StreamInlet/FakeStreamInlet.js.map +0 -1
  167. package/build/testDoubles/StreamInlet/SpyStreamInlet.d.ts +0 -4
  168. package/build/testDoubles/StreamInlet/SpyStreamInlet.js.map +0 -1
  169. package/build/testDoubles/StreamOutlet/FakeStreamOutlet.js.map +0 -1
  170. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.d.ts +0 -14
  171. package/build/testDoubles/WebSocketBridge/FakeWebSocketBridge.js.map +0 -1
  172. package/build/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.d.ts +0 -4
  173. package/build/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.js.map +0 -1
  174. package/build/testDoubles/WorkerThreads/FakeWorker.d.ts +0 -27
  175. package/build/testDoubles/WorkerThreads/FakeWorker.js +0 -67
  176. package/build/testDoubles/WorkerThreads/FakeWorker.js.map +0 -1
  177. package/src/consts.ts +0 -21
  178. package/src/impl/workers/inlet/LslStreamInlet.worker.ts +0 -74
  179. package/src/impl/workers/inlet/StreamInletWorker.ts +0 -348
  180. package/src/impl/workers/outlet/LslStreamOutlet.worker.ts +0 -144
  181. package/src/scripts/discoverMuse.ts +0 -50
  182. package/src/scripts/testDestroyOutlet.ts +0 -5
  183. package/src/testDoubles/StreamInlet/SpyStreamInlet.ts +0 -10
  184. package/src/testDoubles/WebSocketBridge/SpyLslWebSocketBridge.ts +0 -9
  185. package/src/testDoubles/WorkerThreads/FakeWorker.ts +0 -99
  186. /package/build/scripts/{discoverMuse.d.ts → runLslEmitter.d.ts} +0 -0
  187. /package/build/scripts/{runLslEventMarkerEmitter.d.ts → runLslOutlet.d.ts} +0 -0
  188. /package/build/scripts/{runLslStreamOutlet.d.ts → runUsb.d.ts} +0 -0
  189. /package/src/scripts/{runLslStreamOutlet.ts → runLslOutlet.ts} +0 -0
@@ -0,0 +1,262 @@
1
+ import { randomInt } from 'node:crypto'
2
+
3
+ import { test, assert } from '@neurodevs/node-tdd'
4
+
5
+ import WindowedClockRegressor, {
6
+ ClockRegressor,
7
+ } from '../../impl/clocks/WindowedClockRegressor.js'
8
+ import AbstractPackageTest from '../AbstractPackageTest.js'
9
+
10
+ export default class WindowedClockRegressorTest extends AbstractPackageTest {
11
+ private static instance: ClockRegressor
12
+
13
+ protected static readonly chunkSize = randomInt(10, 20)
14
+
15
+ private static readonly nominalHz = 50 + Math.random() * 50
16
+ private static readonly deviceTime = Math.random()
17
+ private static readonly earliestLslTime = Math.random()
18
+
19
+ protected static async beforeEach() {
20
+ await super.beforeEach()
21
+
22
+ this.instance = this.WindowedClockRegressor()
23
+ }
24
+
25
+ @test()
26
+ protected static async createsInstance() {
27
+ assert.isTruthy(this.instance, 'Failed to create instance!')
28
+ }
29
+
30
+ @test()
31
+ protected static async deriveReturnsChunkSizeEntries() {
32
+ const timestamps = this.deriveTimestamps()
33
+
34
+ assert.isEqual(
35
+ timestamps.length,
36
+ this.chunkSize,
37
+ 'Should return an array with chunkSize entries!'
38
+ )
39
+ }
40
+
41
+ @test()
42
+ protected static async deriveAnchorsLastTimestampOnRegressionLine() {
43
+ const nominalChunkStep = this.chunkSize / this.nominalHz
44
+
45
+ let deviceTime = this.deviceTime
46
+ let lslTime = this.earliestLslTime
47
+
48
+ for (let i = 0; i < 100; i++) {
49
+ deviceTime += nominalChunkStep
50
+ lslTime += nominalChunkStep
51
+ this.deriveTimestamps(deviceTime, lslTime)
52
+ }
53
+
54
+ deviceTime += nominalChunkStep
55
+ lslTime += nominalChunkStep
56
+
57
+ const jitter = nominalChunkStep * Math.random()
58
+
59
+ const timestamps = this.deriveTimestamps(deviceTime, lslTime + jitter)
60
+
61
+ for (let i = 0; i < timestamps.length; i++) {
62
+ const stepsFromLast = timestamps.length - 1 - i
63
+ const expected = lslTime - stepsFromLast / this.nominalHz
64
+
65
+ assert.isBetweenInclusive(
66
+ timestamps[i],
67
+ expected - jitter * 0.1,
68
+ expected + jitter * 0.1,
69
+ `Timestamp at index ${i} should be anchored on the fitted regression line, not the jittery arrival time!`
70
+ )
71
+ }
72
+ }
73
+
74
+ @test()
75
+ protected static async deriveSpacesEntriesByNominalHz() {
76
+ const timestamps = this.deriveTimestamps()
77
+
78
+ const expected = Array(this.chunkSize)
79
+ .fill(0)
80
+ .map((_, i) => {
81
+ return (
82
+ this.earliestLslTime -
83
+ (this.chunkSize - 1 - i) / this.nominalHz
84
+ )
85
+ })
86
+
87
+ assert.isEqualDeep(
88
+ timestamps,
89
+ expected,
90
+ 'Entries should be spaced 1/nominalHz apart, working backward from earliestLslTime!'
91
+ )
92
+ }
93
+
94
+ @test()
95
+ protected static async deriveUsesFittedSlopeOnceHistoryAccumulates() {
96
+ const trueSlope = 2
97
+ const nominalStep = this.chunkSize / this.nominalHz
98
+ const lslStep = nominalStep * trueSlope
99
+
100
+ let deviceTime = this.deviceTime
101
+ let earliestLslTime = this.earliestLslTime
102
+
103
+ for (let i = 0; i < 50; i++) {
104
+ deviceTime += nominalStep
105
+ earliestLslTime += lslStep
106
+
107
+ this.deriveTimestamps(deviceTime, earliestLslTime)
108
+ }
109
+
110
+ deviceTime += nominalStep
111
+ earliestLslTime += lslStep
112
+
113
+ const timestamps = this.deriveTimestamps(deviceTime, earliestLslTime)
114
+
115
+ const expectedSpacing = trueSlope / this.nominalHz
116
+
117
+ for (let i = 1; i < timestamps.length; i++) {
118
+ const actualSpacing = timestamps[i] - timestamps[i - 1]
119
+
120
+ assert.isBetweenInclusive(
121
+ actualSpacing,
122
+ expectedSpacing * 0.99,
123
+ expectedSpacing * 1.01,
124
+ `Spacing at index ${i} should reflect the fitted slope once history has accumulated!`
125
+ )
126
+ }
127
+ }
128
+
129
+ @test()
130
+ protected static async deriveThrowsWhenDeviceTimeDoesNotIncreaseMonotonically() {
131
+ this.deriveTimestamps()
132
+
133
+ assert.doesThrow(
134
+ () =>
135
+ this.deriveTimestamps(
136
+ this.deviceTime,
137
+ this.earliestLslTime + Math.random()
138
+ ),
139
+ `\nDevice time (${this.deviceTime}) did not increase from the previous device time (${this.deviceTime})! Device time is expected to always increase between calls, so this likely indicates a bug in the calling code.\n`
140
+ )
141
+ }
142
+
143
+ @test()
144
+ protected static async deriveForgetsHistoryOutsideWindowLenSec() {
145
+ const nominalChunkStep = this.chunkSize / this.nominalHz
146
+
147
+ // With chunkSize in [10, 20) and nominalHz in [50, 100), nominalChunkStep
148
+ // stays within [0.1, 0.4). A fixed 700 iterations always spans at least
149
+ // 70 device-seconds — comfortably more than 2x the 30s windowLenSec.
150
+ const oldPhaseCount = 700
151
+ const newPhaseCount = 700
152
+
153
+ let deviceTime = this.deviceTime
154
+ let earliestLslTime = this.earliestLslTime
155
+
156
+ const oldSlope = 2
157
+
158
+ for (let i = 0; i < oldPhaseCount; i++) {
159
+ deviceTime += nominalChunkStep
160
+ earliestLslTime += nominalChunkStep * oldSlope
161
+
162
+ this.deriveTimestamps(deviceTime, earliestLslTime)
163
+ }
164
+
165
+ const newSlope = 5
166
+ let timestamps: number[] = []
167
+
168
+ for (let i = 0; i < newPhaseCount; i++) {
169
+ deviceTime += nominalChunkStep
170
+ earliestLslTime += nominalChunkStep * newSlope
171
+
172
+ timestamps = this.deriveTimestamps(deviceTime, earliestLslTime)
173
+ }
174
+
175
+ const expectedSpacing = newSlope / this.nominalHz
176
+
177
+ for (let i = 1; i < timestamps.length; i++) {
178
+ const actualSpacing = timestamps[i] - timestamps[i - 1]
179
+
180
+ assert.isBetweenInclusive(
181
+ actualSpacing,
182
+ expectedSpacing * 0.99,
183
+ expectedSpacing * 1.01,
184
+ `Spacing at index ${i} should reflect the new slope once old history falls outside windowLenSec!`
185
+ )
186
+ }
187
+ }
188
+
189
+ @test()
190
+ protected static async deriveAllowsOverridingWindowLenSec() {
191
+ const nominalChunkStep = this.chunkSize / this.nominalHz
192
+ const customWindowLenSec = 5
193
+
194
+ // With nominalChunkStep in [0.1, 0.4), 150 iterations always spans at
195
+ // least 15 device-seconds — more than 2x the 5s customWindowLenSec,
196
+ // but well short of 2x the 30s default, so this only passes if the
197
+ // override actually takes effect.
198
+ const phaseCount = 150
199
+
200
+ const instance = WindowedClockRegressor.Create(this.nominalHz, {
201
+ windowLenSec: customWindowLenSec,
202
+ })
203
+
204
+ let deviceTime = this.deviceTime
205
+ let earliestLslTime = this.earliestLslTime
206
+
207
+ const oldSlope = 2
208
+
209
+ for (let i = 0; i < phaseCount; i++) {
210
+ deviceTime += nominalChunkStep
211
+ earliestLslTime += nominalChunkStep * oldSlope
212
+
213
+ instance.deriveTimestamps(
214
+ deviceTime,
215
+ earliestLslTime,
216
+ this.chunkSize
217
+ )
218
+ }
219
+
220
+ const newSlope = 5
221
+ let timestamps: number[] = []
222
+
223
+ for (let i = 0; i < phaseCount; i++) {
224
+ deviceTime += nominalChunkStep
225
+ earliestLslTime += nominalChunkStep * newSlope
226
+
227
+ timestamps = instance.deriveTimestamps(
228
+ deviceTime,
229
+ earliestLslTime,
230
+ this.chunkSize
231
+ )
232
+ }
233
+
234
+ const expectedSpacing = newSlope / this.nominalHz
235
+
236
+ for (let i = 1; i < timestamps.length; i++) {
237
+ const actualSpacing = timestamps[i] - timestamps[i - 1]
238
+
239
+ assert.isBetweenInclusive(
240
+ actualSpacing,
241
+ expectedSpacing * 0.99,
242
+ expectedSpacing * 1.01,
243
+ `Spacing at index ${i} should reflect the new slope once old history falls outside the custom windowLenSec!`
244
+ )
245
+ }
246
+ }
247
+
248
+ private static deriveTimestamps(
249
+ deviceTime = this.deviceTime,
250
+ earliestLslTime = this.earliestLslTime
251
+ ) {
252
+ return this.instance.deriveTimestamps(
253
+ deviceTime,
254
+ earliestLslTime,
255
+ this.chunkSize
256
+ )
257
+ }
258
+
259
+ private static WindowedClockRegressor() {
260
+ return WindowedClockRegressor.Create(this.nominalHz)
261
+ }
262
+ }
package/src/assertions.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { ChannelFormat } from '@neurodevs/ndx-native'
1
+ import { CHANNEL_FORMATS, ChannelFormat } from '@neurodevs/ndx-native'
2
2
 
3
- import { CHANNEL_FORMATS } from './consts.js'
4
3
  import {
5
4
  isGreaterThanOrEqualToZero,
6
5
  isPositiveInteger,
@@ -1,28 +1,28 @@
1
1
  import { generateShortId } from '@neurodevs/generate-id'
2
2
 
3
3
  import LslStreamOutlet, {
4
- StreamOutletOptions,
5
- StreamOutlet,
4
+ LslOutletOptions,
5
+ LslOutlet,
6
6
  } from './LslStreamOutlet.js'
7
7
 
8
- export default class LslEventMarkerEmitter implements EventMarkerEmitter {
9
- public static Class?: EventMarkerEmitterConstructor
8
+ export default class LslEventMarkerEmitter implements LslEmitter {
9
+ public static Class?: LslEmitterConstructor
10
10
 
11
- protected outlet: StreamOutlet
11
+ protected outlet: LslOutlet
12
12
  private isRunning = false
13
13
  private waitResolve?: () => void
14
14
  private timeout?: any
15
15
 
16
- protected constructor(outlet: StreamOutlet) {
16
+ protected constructor(outlet: LslOutlet) {
17
17
  this.outlet = outlet
18
18
  }
19
19
 
20
- public static async Create(options?: EventMarkerEmitterOptions) {
20
+ public static async Create(options?: LslEmitterOptions) {
21
21
  const outlet = await this.LslStreamOutlet(options)
22
22
  return new (this.Class ?? this)(outlet)
23
23
  }
24
24
 
25
- public async emit(markerName: string, options?: EventMarkerOptions) {
25
+ public async emit(markerName: string, options?: EmitOptions) {
26
26
  this.throwIfAlreadyRunning('emit')
27
27
  this.isRunning = true
28
28
 
@@ -99,10 +99,10 @@ export default class LslEventMarkerEmitter implements EventMarkerEmitter {
99
99
  channelFormat: 'string',
100
100
  sampleRateHz: 0,
101
101
  chunkSize: 1,
102
- } as StreamOutletOptions
102
+ } as LslOutletOptions
103
103
  }
104
104
 
105
- private static LslStreamOutlet(options?: Partial<StreamOutletOptions>) {
105
+ private static LslStreamOutlet(options?: Partial<LslOutletOptions>) {
106
106
  return LslStreamOutlet.Create({
107
107
  ...this.generateDefaultOutletOptions(),
108
108
  ...options,
@@ -110,20 +110,18 @@ export default class LslEventMarkerEmitter implements EventMarkerEmitter {
110
110
  }
111
111
  }
112
112
 
113
- export interface EventMarkerEmitter {
114
- emit(markerName: string, options?: EventMarkerOptions): Promise<void>
113
+ export interface LslEmitter {
114
+ emit(markerName: string, options?: EmitOptions): Promise<void>
115
115
  emitMany(markers: TimedEventMarker[]): Promise<void>
116
116
  interrupt(): void
117
117
  destroy(): void
118
118
  }
119
119
 
120
- export type EventMarkerEmitterOptions = Partial<StreamOutletOptions>
120
+ export type LslEmitterOptions = Partial<LslOutletOptions>
121
121
 
122
- export type EventMarkerEmitterConstructor = new (
123
- outlet: StreamOutlet
124
- ) => EventMarkerEmitter
122
+ export type LslEmitterConstructor = new (outlet: LslOutlet) => LslEmitter
125
123
 
126
- export interface EventMarkerOptions {
124
+ export interface EmitOptions {
127
125
  waitAfterMs?: number
128
126
  }
129
127
 
@@ -6,8 +6,8 @@ import {
6
6
  CHANNEL_FORMATS_MAP,
7
7
  } from '@neurodevs/ndx-native'
8
8
 
9
- export default class LslStreamInfo implements StreamInfo {
10
- public static Class?: StreamInfoConstructor
9
+ export default class LslStreamInfo implements LslInfo {
10
+ public static Class?: LslInfoConstructor
11
11
 
12
12
  public readonly name: string
13
13
  public readonly type: string
@@ -22,7 +22,7 @@ export default class LslStreamInfo implements StreamInfo {
22
22
 
23
23
  private lsl = LiblslAdapter.getInstance()
24
24
 
25
- protected constructor(options: StreamInfoOptions) {
25
+ protected constructor(options: LslInfoOptions) {
26
26
  const {
27
27
  name = `lsl-stream-info-${generateId()}`,
28
28
  type = generateId(),
@@ -46,7 +46,7 @@ export default class LslStreamInfo implements StreamInfo {
46
46
  this.appendChannelsToStreamInfo()
47
47
  }
48
48
 
49
- public static Create(options: StreamInfoOptions) {
49
+ public static Create(options: LslInfoOptions) {
50
50
  return new (this.Class ?? this)(options)
51
51
  }
52
52
 
@@ -81,7 +81,7 @@ export default class LslStreamInfo implements StreamInfo {
81
81
  }
82
82
  }
83
83
 
84
- export interface StreamInfo {
84
+ export interface LslInfo {
85
85
  destroy(): void
86
86
  readonly name: string
87
87
  readonly type: string
@@ -94,11 +94,9 @@ export interface StreamInfo {
94
94
  readonly infoHandle: InfoHandle
95
95
  }
96
96
 
97
- export type StreamInfoConstructor = new (
98
- options: StreamInfoOptions
99
- ) => StreamInfo
97
+ export type LslInfoConstructor = new (options: LslInfoOptions) => LslInfo
100
98
 
101
- export interface StreamInfoOptions {
99
+ export interface LslInfoOptions {
102
100
  channelNames: string[]
103
101
  channelFormat: ChannelFormat
104
102
  sampleRateHz: number