edfcore 0.1.6 → 0.1.8
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/dist/biosemi.d.ts +45 -0
- package/dist/biosemi.d.ts.map +1 -0
- package/dist/biosemi.js +122 -0
- package/dist/biosemi.js.map +1 -0
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/envelope.d.ts +48 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +263 -0
- package/dist/envelope.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/biosemi.ts +156 -0
- package/src/constants.ts +1 -1
- package/src/envelope.ts +352 -0
- package/src/index.ts +9 -0
- package/src/types.ts +79 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The BioSemi Status channel.
|
|
3
|
+
*
|
|
4
|
+
* Layer 7. BioSemi's ActiveTwo writes BDF files whose last channel is labelled `Status`, and its
|
|
5
|
+
* 24-bit samples are not a measurement — they are a bit field the amplifier latched at each
|
|
6
|
+
* sample. The low 16 bits are the parallel trigger input, which is how nearly every ERP
|
|
7
|
+
* experiment records stimulus onsets.
|
|
8
|
+
*
|
|
9
|
+
* Reading that is file access, not analysis. The codes were written by the hardware at
|
|
10
|
+
* acquisition time, exactly like an EDF+ annotation, and this module only reports what is in the
|
|
11
|
+
* bytes. Nothing here inspects a biosignal, so event detection remains a non-goal.
|
|
12
|
+
*
|
|
13
|
+
* Only the bits BioSemi documents are named. `raw` carries all 24 so a caller with a rig-specific
|
|
14
|
+
* convention can decode the rest without waiting for this module to learn about it — inventing
|
|
15
|
+
* meanings for the bits above 18 would be guessing, and a wrong trigger code is worse than none.
|
|
16
|
+
*/
|
|
17
|
+
import type { EdfHeader, EdfRecording, EdfSignal, EdfStatusWord, EdfTriggerEvent, ReadOptions, TriggerSelection } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* The `Status` channel of a BDF file, or `undefined` when there is none.
|
|
20
|
+
*
|
|
21
|
+
* Returns `undefined` rather than throwing for a plain EDF or a BDF without the channel: a file
|
|
22
|
+
* having no Status channel is an ordinary fact about the file, not an error.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getStatusSignal(header: EdfHeader): EdfSignal | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Decodes one 24-bit Status sample.
|
|
27
|
+
*
|
|
28
|
+
* `decodeDigital` sign-extends BDF samples, as it must for a measurement, so bit 23 of a Status
|
|
29
|
+
* word arrives as a negative number. The bit field is unsigned, so it is masked back before
|
|
30
|
+
* anything is read out of it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function decodeStatusWord(sample: number): EdfStatusWord;
|
|
33
|
+
/**
|
|
34
|
+
* Every change of the trigger word in a window, as timed events.
|
|
35
|
+
*
|
|
36
|
+
* A parallel trigger is held for as long as the stimulus computer asserts it, so the same code
|
|
37
|
+
* repeats over many samples. What an experimenter wants is the TRANSITION, which is why this
|
|
38
|
+
* reports changes rather than samples: one event per change, carrying the code it changed to.
|
|
39
|
+
*
|
|
40
|
+
* Code 0 is "no trigger asserted", so a return to 0 is reported as an event with `trigger: 0`
|
|
41
|
+
* and is easy to filter out. It is reported rather than dropped because the release time is what
|
|
42
|
+
* gives a trigger its duration.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readTriggers(recording: EdfRecording, selection: TriggerSelection, options?: ReadOptions): Promise<readonly EdfTriggerEvent[]>;
|
|
45
|
+
//# sourceMappingURL=biosemi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"biosemi.d.ts","sourceRoot":"","sources":["../src/biosemi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EAEX,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAWpB;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAOxE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CAS9D;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAiErC"}
|
package/dist/biosemi.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The BioSemi Status channel.
|
|
3
|
+
*
|
|
4
|
+
* Layer 7. BioSemi's ActiveTwo writes BDF files whose last channel is labelled `Status`, and its
|
|
5
|
+
* 24-bit samples are not a measurement — they are a bit field the amplifier latched at each
|
|
6
|
+
* sample. The low 16 bits are the parallel trigger input, which is how nearly every ERP
|
|
7
|
+
* experiment records stimulus onsets.
|
|
8
|
+
*
|
|
9
|
+
* Reading that is file access, not analysis. The codes were written by the hardware at
|
|
10
|
+
* acquisition time, exactly like an EDF+ annotation, and this module only reports what is in the
|
|
11
|
+
* bytes. Nothing here inspects a biosignal, so event detection remains a non-goal.
|
|
12
|
+
*
|
|
13
|
+
* Only the bits BioSemi documents are named. `raw` carries all 24 so a caller with a rig-specific
|
|
14
|
+
* convention can decode the rest without waiting for this module to learn about it — inventing
|
|
15
|
+
* meanings for the bits above 18 would be guessing, and a wrong trigger code is worse than none.
|
|
16
|
+
*/
|
|
17
|
+
import { decodeDigitalCounted } from './decode/digital.js';
|
|
18
|
+
import { readRecordBytes } from './io/read.js';
|
|
19
|
+
import { scanChunkRecords } from './record-index.js';
|
|
20
|
+
import { ticksToSeconds } from './tal/ticks.js';
|
|
21
|
+
import { resolveTimeWindow } from './time/window.js';
|
|
22
|
+
/** BioSemi's own label for the channel. Matched case-insensitively after trimming. */
|
|
23
|
+
const STATUS_LABEL = 'status';
|
|
24
|
+
/** The parallel input occupies the low 16 bits; the flags sit immediately above it. */
|
|
25
|
+
const TRIGGER_MASK = 0xffff;
|
|
26
|
+
const EPOCH_BIT = 1 << 16;
|
|
27
|
+
const CMS_IN_RANGE_BIT = 1 << 17;
|
|
28
|
+
const BATTERY_LOW_BIT = 1 << 18;
|
|
29
|
+
/**
|
|
30
|
+
* The `Status` channel of a BDF file, or `undefined` when there is none.
|
|
31
|
+
*
|
|
32
|
+
* Returns `undefined` rather than throwing for a plain EDF or a BDF without the channel: a file
|
|
33
|
+
* having no Status channel is an ordinary fact about the file, not an error.
|
|
34
|
+
*/
|
|
35
|
+
export function getStatusSignal(header) {
|
|
36
|
+
if (header.bytesPerSample !== 3)
|
|
37
|
+
return undefined;
|
|
38
|
+
for (const index of header.dataSignalIndices) {
|
|
39
|
+
const signal = header.signals[index];
|
|
40
|
+
if (signal !== undefined && signal.label.trim().toLowerCase() === STATUS_LABEL)
|
|
41
|
+
return signal;
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Decodes one 24-bit Status sample.
|
|
47
|
+
*
|
|
48
|
+
* `decodeDigital` sign-extends BDF samples, as it must for a measurement, so bit 23 of a Status
|
|
49
|
+
* word arrives as a negative number. The bit field is unsigned, so it is masked back before
|
|
50
|
+
* anything is read out of it.
|
|
51
|
+
*/
|
|
52
|
+
export function decodeStatusWord(sample) {
|
|
53
|
+
const raw = sample & 0xffffff;
|
|
54
|
+
return {
|
|
55
|
+
raw,
|
|
56
|
+
trigger: raw & TRIGGER_MASK,
|
|
57
|
+
newEpoch: (raw & EPOCH_BIT) !== 0,
|
|
58
|
+
cmsInRange: (raw & CMS_IN_RANGE_BIT) !== 0,
|
|
59
|
+
batteryLow: (raw & BATTERY_LOW_BIT) !== 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Every change of the trigger word in a window, as timed events.
|
|
64
|
+
*
|
|
65
|
+
* A parallel trigger is held for as long as the stimulus computer asserts it, so the same code
|
|
66
|
+
* repeats over many samples. What an experimenter wants is the TRANSITION, which is why this
|
|
67
|
+
* reports changes rather than samples: one event per change, carrying the code it changed to.
|
|
68
|
+
*
|
|
69
|
+
* Code 0 is "no trigger asserted", so a return to 0 is reported as an event with `trigger: 0`
|
|
70
|
+
* and is easy to filter out. It is reported rather than dropped because the release time is what
|
|
71
|
+
* gives a trigger its duration.
|
|
72
|
+
*/
|
|
73
|
+
export async function readTriggers(recording, selection, options) {
|
|
74
|
+
const { source, header, timeline } = recording;
|
|
75
|
+
const status = getStatusSignal(header);
|
|
76
|
+
if (status === undefined) {
|
|
77
|
+
throw new RangeError('readTriggers(): this file has no BioSemi Status channel — it is either not a BDF file, ' +
|
|
78
|
+
'or no signal is labelled "Status". Next: check header.signals, or read EDF+ ' +
|
|
79
|
+
'annotations with readAnnotations().');
|
|
80
|
+
}
|
|
81
|
+
const ranges = resolveTimeWindow(timeline, recording.index, selection.startSeconds, selection.durationSeconds);
|
|
82
|
+
const events = [];
|
|
83
|
+
// Carried across runs so a trigger held over a gap is not reported twice. `undefined` means
|
|
84
|
+
// nothing has been seen yet, which is what makes the very first sample an event.
|
|
85
|
+
let previous;
|
|
86
|
+
for (const records of ranges) {
|
|
87
|
+
const chunkRecords = scanChunkRecords(header, options?.maxMaterializeBytes);
|
|
88
|
+
let scanned = 0;
|
|
89
|
+
let scratch;
|
|
90
|
+
while (scanned < records.count) {
|
|
91
|
+
const slice = {
|
|
92
|
+
start: records.start + scanned,
|
|
93
|
+
count: Math.min(chunkRecords, records.count - scanned),
|
|
94
|
+
};
|
|
95
|
+
const bytes = await readRecordBytes(source, header, slice, options);
|
|
96
|
+
const decoded = decodeDigitalCounted(header, bytes, slice, status.index, scratch, options);
|
|
97
|
+
scratch = decoded.digital;
|
|
98
|
+
const sampleCount = status.samplesPerRecord * slice.count;
|
|
99
|
+
const firstSampleIndex = slice.start * status.samplesPerRecord;
|
|
100
|
+
for (let i = 0; i < sampleCount; i += 1) {
|
|
101
|
+
const word = decodeStatusWord(decoded.digital[i]);
|
|
102
|
+
if (previous !== undefined && word.trigger === previous)
|
|
103
|
+
continue;
|
|
104
|
+
previous = word.trigger;
|
|
105
|
+
const sampleIndex = firstSampleIndex + i;
|
|
106
|
+
const ticks = header.recordDurationTicks > 0n && status.samplesPerRecord > 0
|
|
107
|
+
? (BigInt(sampleIndex) * header.recordDurationTicks) / BigInt(status.samplesPerRecord)
|
|
108
|
+
: 0n;
|
|
109
|
+
events.push({
|
|
110
|
+
sampleIndex,
|
|
111
|
+
seconds: ticksToSeconds(ticks),
|
|
112
|
+
ticks,
|
|
113
|
+
trigger: word.trigger,
|
|
114
|
+
status: word,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
scanned += slice.count;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return Object.freeze(events);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=biosemi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"biosemi.js","sourceRoot":"","sources":["../src/biosemi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAYrD,sFAAsF;AACtF,MAAM,YAAY,GAAG,QAAQ,CAAC;AAE9B,uFAAuF;AACvF,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,CAAC;AAC1B,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,CAAC;AACjC,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,IAAI,MAAM,CAAC,cAAc,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,YAAY;YAAE,OAAO,MAAM,CAAC;IAChG,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,GAAG,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC9B,OAAO;QACL,GAAG;QACH,OAAO,EAAE,GAAG,GAAG,YAAY;QAC3B,QAAQ,EAAE,CAAC,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC;QACjC,UAAU,EAAE,CAAC,GAAG,GAAG,gBAAgB,CAAC,KAAK,CAAC;QAC1C,UAAU,EAAE,CAAC,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAuB,EACvB,SAA2B,EAC3B,OAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;IAE/C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAClB,yFAAyF;YACvF,8EAA8E;YAC9E,qCAAqC,CACxC,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAC9B,QAAQ,EACR,SAAS,CAAC,KAAK,EACf,SAAS,CAAC,YAAY,EACtB,SAAS,CAAC,eAAe,CAC1B,CAAC;IAEF,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,4FAA4F;IAC5F,iFAAiF;IACjF,IAAI,QAA4B,CAAC;IAEjC,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;QAC5E,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAA+B,CAAC;QAEpC,OAAO,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAgB;gBACzB,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,OAAO;gBAC9B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC;aACvD,CAAC;YACF,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YACpE,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC3F,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;YAE1B,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,GAAG,KAAK,CAAC,KAAK,CAAC;YAC1D,MAAM,gBAAgB,GAAG,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC;YAE/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxC,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAW,CAAC,CAAC;gBAC5D,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,QAAQ;oBAAE,SAAS;gBAClE,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC;gBAExB,MAAM,WAAW,GAAG,gBAAgB,GAAG,CAAC,CAAC;gBACzC,MAAM,KAAK,GACT,MAAM,CAAC,mBAAmB,GAAG,EAAE,IAAI,MAAM,CAAC,gBAAgB,GAAG,CAAC;oBAC5D,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC;oBACtF,CAAC,CAAC,EAAE,CAAC;gBACT,MAAM,CAAC,IAAI,CAAC;oBACV,WAAW;oBACX,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC;oBAC9B,KAAK;oBACL,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,MAAM,EAAE,IAAI;iBACb,CAAC,CAAC;YACL,CAAC;YAED,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -109,5 +109,5 @@ export declare const SIGNAL_FIELD_BLOCK_OFFSETS: {
|
|
|
109
109
|
readonly reserved: 224;
|
|
110
110
|
};
|
|
111
111
|
/** Published package version. Kept in sync with package.json by a test. */
|
|
112
|
-
export declare const VERSION = "0.1.
|
|
112
|
+
export declare const VERSION = "0.1.8";
|
|
113
113
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.js
CHANGED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Min/max envelope decimation.
|
|
3
|
+
*
|
|
4
|
+
* Layer 7. A twelve-hour recording at 256 Hz is eleven million samples per channel, and a plot is
|
|
5
|
+
* a thousand pixels wide. Something has to reduce eleven million numbers to a thousand, and which
|
|
6
|
+
* reduction you pick decides whether the picture is true.
|
|
7
|
+
*
|
|
8
|
+
* Taking every 11,000th sample is the obvious choice and the wrong one: a spike, a spindle or an
|
|
9
|
+
* artifact is a handful of samples wide, so subsampling hits it with probability near zero and
|
|
10
|
+
* the trace looks calm exactly where a reader most needs it not to. Keeping the MINIMUM and
|
|
11
|
+
* MAXIMUM of each bucket keeps every extreme, at two numbers per pixel. That is the reduction a
|
|
12
|
+
* waveform viewer wants, and it is why this exists as its own function rather than as an option
|
|
13
|
+
* on `readWindow`: the return type is different, so an option would have to change it.
|
|
14
|
+
*
|
|
15
|
+
* This is decimation for display, not analysis. There is no filtering and no anti-aliasing —
|
|
16
|
+
* an envelope is a faithful summary of the samples that are there, not a resampled signal, and
|
|
17
|
+
* resampling remains a permanent non-goal.
|
|
18
|
+
*
|
|
19
|
+
* Memory is bounded by the record chunk, never by the window: a run of a million records is
|
|
20
|
+
* folded into the buckets a chunk at a time, so an envelope over a whole recording costs the
|
|
21
|
+
* buckets plus one chunk.
|
|
22
|
+
*/
|
|
23
|
+
import type { EdfChunkSignal, EdfEnvelopeChunk, EdfEnvelopeSignal, EdfPhysicalEnvelope, EdfRecording, EdfSignal, EnvelopeSelection, ReadOptions } from './types.js';
|
|
24
|
+
/**
|
|
25
|
+
* Reduces a time window to per-bucket minima and maxima, one chunk per contiguous run.
|
|
26
|
+
*
|
|
27
|
+
* The shape mirrors `readWindow` exactly — an array of chunks, one per run, empty when the window
|
|
28
|
+
* selects nothing — so a caller that already handles gaps handles envelopes for free.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readEnvelope(recording: EdfRecording, selection: EnvelopeSelection, options?: ReadOptions): Promise<readonly EdfEnvelopeChunk[]>;
|
|
31
|
+
/**
|
|
32
|
+
* Converts a digital envelope to physical units.
|
|
33
|
+
*
|
|
34
|
+
* Not `toPhysical` applied twice, and the reason is the sign of the gain. The affine transform
|
|
35
|
+
* `bitValue * (offset + digital)` is DECREASING when `bitValue` is negative — a spec-sanctioned
|
|
36
|
+
* arrangement that edfcore reports rather than rejects — and a decreasing map sends the smallest
|
|
37
|
+
* digital value to the largest physical one. Mapping `min` to `min` would then produce an
|
|
38
|
+
* envelope whose lower bound is above its upper bound, and a viewer would draw it inside out.
|
|
39
|
+
*/
|
|
40
|
+
export declare function toPhysicalEnvelope(signal: EdfSignal, envelope: EdfEnvelopeSignal): EdfPhysicalEnvelope;
|
|
41
|
+
/**
|
|
42
|
+
* The envelope of an already-decoded chunk signal, without another read.
|
|
43
|
+
*
|
|
44
|
+
* For a caller who has samples in hand and wants them plotted: same reduction, same bucket rule,
|
|
45
|
+
* no I/O.
|
|
46
|
+
*/
|
|
47
|
+
export declare function envelopeOfSamples(chunkSignal: EdfChunkSignal, buckets: number): EdfEnvelopeSignal;
|
|
48
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EACV,cAAc,EAEd,gBAAgB,EAChB,iBAAiB,EAEjB,mBAAmB,EACnB,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,WAAW,EAEZ,MAAM,YAAY,CAAC;AAsBpB;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,YAAY,EACvB,SAAS,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,CAkBtC;AAsLD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,iBAAiB,GAC1B,mBAAmB,CAuBrB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAkCjG"}
|
package/dist/envelope.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Min/max envelope decimation.
|
|
3
|
+
*
|
|
4
|
+
* Layer 7. A twelve-hour recording at 256 Hz is eleven million samples per channel, and a plot is
|
|
5
|
+
* a thousand pixels wide. Something has to reduce eleven million numbers to a thousand, and which
|
|
6
|
+
* reduction you pick decides whether the picture is true.
|
|
7
|
+
*
|
|
8
|
+
* Taking every 11,000th sample is the obvious choice and the wrong one: a spike, a spindle or an
|
|
9
|
+
* artifact is a handful of samples wide, so subsampling hits it with probability near zero and
|
|
10
|
+
* the trace looks calm exactly where a reader most needs it not to. Keeping the MINIMUM and
|
|
11
|
+
* MAXIMUM of each bucket keeps every extreme, at two numbers per pixel. That is the reduction a
|
|
12
|
+
* waveform viewer wants, and it is why this exists as its own function rather than as an option
|
|
13
|
+
* on `readWindow`: the return type is different, so an option would have to change it.
|
|
14
|
+
*
|
|
15
|
+
* This is decimation for display, not analysis. There is no filtering and no anti-aliasing —
|
|
16
|
+
* an envelope is a faithful summary of the samples that are there, not a resampled signal, and
|
|
17
|
+
* resampling remains a permanent non-goal.
|
|
18
|
+
*
|
|
19
|
+
* Memory is bounded by the record chunk, never by the window: a run of a million records is
|
|
20
|
+
* folded into the buckets a chunk at a time, so an envelope over a whole recording costs the
|
|
21
|
+
* buckets plus one chunk.
|
|
22
|
+
*/
|
|
23
|
+
import { decodeDigitalCounted } from './decode/digital.js';
|
|
24
|
+
import { EdfScalingError } from './errors.js';
|
|
25
|
+
import { readRecordBytes } from './io/read.js';
|
|
26
|
+
import { scanChunkRecords } from './record-index.js';
|
|
27
|
+
import { decodeAnnotations } from './tal/annotations.js';
|
|
28
|
+
import { ticksToSeconds } from './tal/ticks.js';
|
|
29
|
+
import { resolveTimeWindow } from './time/window.js';
|
|
30
|
+
function assertPositiveInteger(value, name) {
|
|
31
|
+
if (Number.isSafeInteger(value) && value > 0)
|
|
32
|
+
return;
|
|
33
|
+
throw new RangeError(`readEnvelope(): ${name} must be a positive whole number, received ${value}. ` +
|
|
34
|
+
'Next: pass the pixel width of the plot you are drawing into.');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reduces a time window to per-bucket minima and maxima, one chunk per contiguous run.
|
|
38
|
+
*
|
|
39
|
+
* The shape mirrors `readWindow` exactly — an array of chunks, one per run, empty when the window
|
|
40
|
+
* selects nothing — so a caller that already handles gaps handles envelopes for free.
|
|
41
|
+
*/
|
|
42
|
+
export async function readEnvelope(recording, selection, options) {
|
|
43
|
+
assertPositiveInteger(selection.buckets, 'buckets');
|
|
44
|
+
// Validated before the window is resolved, for the same reason readWindow does it: a bad
|
|
45
|
+
// signalIndices must not read back as an empty stretch of recording.
|
|
46
|
+
resolveEnvelopeSignals(recording.header, selection.signalIndices);
|
|
47
|
+
const ranges = resolveTimeWindow(recording.timeline, recording.index, selection.startSeconds, selection.durationSeconds);
|
|
48
|
+
const chunks = [];
|
|
49
|
+
for (const records of ranges) {
|
|
50
|
+
chunks.push(await reduceRange(recording, records, selection, options));
|
|
51
|
+
}
|
|
52
|
+
return Object.freeze(chunks);
|
|
53
|
+
}
|
|
54
|
+
function resolveEnvelopeSignals(header, signalIndices) {
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
const signals = [];
|
|
57
|
+
for (const signalIndex of signalIndices) {
|
|
58
|
+
if (seen.has(signalIndex))
|
|
59
|
+
continue;
|
|
60
|
+
seen.add(signalIndex);
|
|
61
|
+
const signal = header.signals[signalIndex];
|
|
62
|
+
if (signal === undefined) {
|
|
63
|
+
throw new RangeError(`readEnvelope(): signalIndex ${signalIndex} is outside the ${header.signals.length} ` +
|
|
64
|
+
'signals this file declares. Next: pass an index from header.dataSignalIndices.');
|
|
65
|
+
}
|
|
66
|
+
if (signal.kind === 'annotations') {
|
|
67
|
+
throw new RangeError(`readEnvelope(): signal ${signalIndex} (${JSON.stringify(signal.label)}) is this file's ` +
|
|
68
|
+
'annotations channel; its bytes are TAL text, not samples, so an envelope over them ' +
|
|
69
|
+
'would be an envelope over ASCII. Next: call readAnnotations() instead.');
|
|
70
|
+
}
|
|
71
|
+
signals.push(signal);
|
|
72
|
+
}
|
|
73
|
+
return signals;
|
|
74
|
+
}
|
|
75
|
+
async function reduceRange(recording, records, selection, options) {
|
|
76
|
+
const { source, header, timeline } = recording;
|
|
77
|
+
const signals = resolveEnvelopeSignals(header, selection.signalIndices);
|
|
78
|
+
const diagnostics = [];
|
|
79
|
+
// More buckets than the densest signal has samples in this run would leave holes that mean
|
|
80
|
+
// nothing, so the request is clamped rather than honoured literally.
|
|
81
|
+
const densestSamples = signals.reduce((most, signal) => Math.max(most, signal.samplesPerRecord * records.count), 0);
|
|
82
|
+
const bucketCount = Math.max(1, Math.min(selection.buckets, densestSamples));
|
|
83
|
+
const accumulators = signals.map((signal) => ({
|
|
84
|
+
signal,
|
|
85
|
+
// Int32Array zero-fills, so the sentinels have to be written explicitly: a bucket nothing
|
|
86
|
+
// landed in must be distinguishable from a bucket whose samples were all zero.
|
|
87
|
+
min: new Int32Array(bucketCount).fill(0),
|
|
88
|
+
max: new Int32Array(bucketCount).fill(0),
|
|
89
|
+
counts: new Int32Array(bucketCount),
|
|
90
|
+
consumed: 0,
|
|
91
|
+
outOfRange: 0,
|
|
92
|
+
scratch: undefined,
|
|
93
|
+
}));
|
|
94
|
+
const chunkRecords = scanChunkRecords(header, options?.maxMaterializeBytes);
|
|
95
|
+
let byteLength = 0;
|
|
96
|
+
let firstOnsetTicks;
|
|
97
|
+
let lastOnsetTicks;
|
|
98
|
+
let scanned = 0;
|
|
99
|
+
while (scanned < records.count) {
|
|
100
|
+
const slice = {
|
|
101
|
+
start: records.start + scanned,
|
|
102
|
+
count: Math.min(chunkRecords, records.count - scanned),
|
|
103
|
+
};
|
|
104
|
+
const bytes = await readRecordBytes(source, header, slice, options);
|
|
105
|
+
byteLength += bytes.length;
|
|
106
|
+
// Never strict: a defect in one record must not cost the caller the whole picture.
|
|
107
|
+
const annotations = decodeAnnotations(header, bytes, slice, {
|
|
108
|
+
originTicks: timeline.startOffsetTicks,
|
|
109
|
+
});
|
|
110
|
+
for (const diagnostic of annotations.diagnostics)
|
|
111
|
+
diagnostics.push(diagnostic);
|
|
112
|
+
const onsets = annotations.recordOnsetTicks;
|
|
113
|
+
if (firstOnsetTicks === undefined)
|
|
114
|
+
firstOnsetTicks = onsets[0];
|
|
115
|
+
const lastInSlice = onsets[slice.count - 1];
|
|
116
|
+
if (lastInSlice !== undefined)
|
|
117
|
+
lastOnsetTicks = lastInSlice;
|
|
118
|
+
for (const accumulator of accumulators) {
|
|
119
|
+
foldChunk(accumulator, header, bytes, slice, records, bucketCount, options);
|
|
120
|
+
}
|
|
121
|
+
scanned += slice.count;
|
|
122
|
+
}
|
|
123
|
+
const durationTicks = header.recordDurationTicks;
|
|
124
|
+
const startTicks = (firstOnsetTicks ?? timeline.startOffsetTicks) - timeline.startOffsetTicks;
|
|
125
|
+
const spanTicks = firstOnsetTicks !== undefined && lastOnsetTicks !== undefined
|
|
126
|
+
? lastOnsetTicks + durationTicks - firstOnsetTicks
|
|
127
|
+
: durationTicks * BigInt(records.count);
|
|
128
|
+
const startSeconds = ticksToSeconds(startTicks);
|
|
129
|
+
const durationSeconds = ticksToSeconds(spanTicks);
|
|
130
|
+
const envelopeSignals = accumulators.map((accumulator) => ({
|
|
131
|
+
signalIndex: accumulator.signal.index,
|
|
132
|
+
min: accumulator.min,
|
|
133
|
+
max: accumulator.max,
|
|
134
|
+
counts: accumulator.counts,
|
|
135
|
+
sampleCount: accumulator.consumed,
|
|
136
|
+
firstSampleIndex: records.start * accumulator.signal.samplesPerRecord,
|
|
137
|
+
startSeconds,
|
|
138
|
+
outOfDigitalRangeCount: accumulator.outOfRange,
|
|
139
|
+
}));
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
records,
|
|
142
|
+
startSeconds,
|
|
143
|
+
durationSeconds,
|
|
144
|
+
bucketCount,
|
|
145
|
+
secondsPerBucket: bucketCount > 0 ? durationSeconds / bucketCount : 0,
|
|
146
|
+
byteLength,
|
|
147
|
+
signals: Object.freeze(envelopeSignals),
|
|
148
|
+
precededByGap: undefined,
|
|
149
|
+
diagnostics: Object.freeze(diagnostics),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Folds one chunk of one signal into the buckets.
|
|
154
|
+
*
|
|
155
|
+
* The bucket of a sample is decided by its position on the WHOLE run's grid, not the chunk's, so
|
|
156
|
+
* the chunk size cannot move a sample from one bucket to another. That is the same rule the
|
|
157
|
+
* record scan learned the hard way: chunking bounds memory and must never change the answer.
|
|
158
|
+
*/
|
|
159
|
+
function foldChunk(accumulator, header, bytes, slice, run, bucketCount, options) {
|
|
160
|
+
const totalSamples = accumulator.signal.samplesPerRecord * run.count;
|
|
161
|
+
if (totalSamples === 0)
|
|
162
|
+
return;
|
|
163
|
+
const decoded = decodeDigitalCounted(header, bytes, slice, accumulator.signal.index, accumulator.scratch, options);
|
|
164
|
+
// decodeDigitalCounted reuses the buffer when it is large enough, so the allocation happens
|
|
165
|
+
// once per signal per run rather than once per chunk.
|
|
166
|
+
accumulator.scratch = decoded.digital;
|
|
167
|
+
accumulator.outOfRange += decoded.outOfDigitalRangeCount;
|
|
168
|
+
const samples = decoded.digital;
|
|
169
|
+
// The buffer is reused across chunks, so it can be LONGER than this slice. The slice's own
|
|
170
|
+
// sample count is what must be folded, or the tail of a previous, larger chunk is counted again.
|
|
171
|
+
const sampleCount = accumulator.signal.samplesPerRecord * slice.count;
|
|
172
|
+
const { min, max, counts } = accumulator;
|
|
173
|
+
let position = accumulator.consumed;
|
|
174
|
+
for (let i = 0; i < sampleCount; i += 1) {
|
|
175
|
+
const value = samples[i];
|
|
176
|
+
// Integer arithmetic on the run grid: floor(position * buckets / totalSamples).
|
|
177
|
+
const bucket = Math.min(bucketCount - 1, Math.floor((position * bucketCount) / totalSamples));
|
|
178
|
+
const seen = counts[bucket];
|
|
179
|
+
if (seen === 0) {
|
|
180
|
+
min[bucket] = value;
|
|
181
|
+
max[bucket] = value;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
if (value < min[bucket])
|
|
185
|
+
min[bucket] = value;
|
|
186
|
+
if (value > max[bucket])
|
|
187
|
+
max[bucket] = value;
|
|
188
|
+
}
|
|
189
|
+
counts[bucket] = seen + 1;
|
|
190
|
+
position += 1;
|
|
191
|
+
}
|
|
192
|
+
accumulator.consumed = position;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Converts a digital envelope to physical units.
|
|
196
|
+
*
|
|
197
|
+
* Not `toPhysical` applied twice, and the reason is the sign of the gain. The affine transform
|
|
198
|
+
* `bitValue * (offset + digital)` is DECREASING when `bitValue` is negative — a spec-sanctioned
|
|
199
|
+
* arrangement that edfcore reports rather than rejects — and a decreasing map sends the smallest
|
|
200
|
+
* digital value to the largest physical one. Mapping `min` to `min` would then produce an
|
|
201
|
+
* envelope whose lower bound is above its upper bound, and a viewer would draw it inside out.
|
|
202
|
+
*/
|
|
203
|
+
export function toPhysicalEnvelope(signal, envelope) {
|
|
204
|
+
const scale = signal.scale;
|
|
205
|
+
if (scale === undefined) {
|
|
206
|
+
throw new EdfScalingError(`signal ${signal.index} (${JSON.stringify(signal.label)}) has no usable scale, so its ` +
|
|
207
|
+
'envelope has no physical units. Next: check signal.scale before converting, or plot ' +
|
|
208
|
+
'the digital envelope as it is.', { code: 'SCALE_UNAVAILABLE', signalIndex: signal.index, label: signal.label });
|
|
209
|
+
}
|
|
210
|
+
const length = envelope.min.length;
|
|
211
|
+
const low = new Float64Array(length);
|
|
212
|
+
const high = new Float64Array(length);
|
|
213
|
+
const decreasing = scale.bitValue < 0;
|
|
214
|
+
for (let i = 0; i < length; i += 1) {
|
|
215
|
+
const a = scale.bitValue * (scale.offset + envelope.min[i]);
|
|
216
|
+
const b = scale.bitValue * (scale.offset + envelope.max[i]);
|
|
217
|
+
low[i] = decreasing ? b : a;
|
|
218
|
+
high[i] = decreasing ? a : b;
|
|
219
|
+
}
|
|
220
|
+
return { min: low, max: high };
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The envelope of an already-decoded chunk signal, without another read.
|
|
224
|
+
*
|
|
225
|
+
* For a caller who has samples in hand and wants them plotted: same reduction, same bucket rule,
|
|
226
|
+
* no I/O.
|
|
227
|
+
*/
|
|
228
|
+
export function envelopeOfSamples(chunkSignal, buckets) {
|
|
229
|
+
assertPositiveInteger(buckets, 'buckets');
|
|
230
|
+
const samples = chunkSignal.digital;
|
|
231
|
+
const total = samples.length;
|
|
232
|
+
const bucketCount = Math.max(1, Math.min(buckets, total));
|
|
233
|
+
const min = new Int32Array(bucketCount);
|
|
234
|
+
const max = new Int32Array(bucketCount);
|
|
235
|
+
const counts = new Int32Array(bucketCount);
|
|
236
|
+
for (let i = 0; i < total; i += 1) {
|
|
237
|
+
const value = samples[i];
|
|
238
|
+
const bucket = Math.min(bucketCount - 1, Math.floor((i * bucketCount) / total));
|
|
239
|
+
const seen = counts[bucket];
|
|
240
|
+
if (seen === 0) {
|
|
241
|
+
min[bucket] = value;
|
|
242
|
+
max[bucket] = value;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
if (value < min[bucket])
|
|
246
|
+
min[bucket] = value;
|
|
247
|
+
if (value > max[bucket])
|
|
248
|
+
max[bucket] = value;
|
|
249
|
+
}
|
|
250
|
+
counts[bucket] = seen + 1;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
signalIndex: chunkSignal.signalIndex,
|
|
254
|
+
min,
|
|
255
|
+
max,
|
|
256
|
+
counts,
|
|
257
|
+
sampleCount: total,
|
|
258
|
+
firstSampleIndex: chunkSignal.firstSampleIndex,
|
|
259
|
+
startSeconds: chunkSignal.startSeconds,
|
|
260
|
+
outOfDigitalRangeCount: chunkSignal.outOfDigitalRangeCount,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
/** The trailing `options` argument shared by every primitive that can allocate. */
|
|
23
23
|
export type { MaterializeOptions } from './decode/digital.js';
|
|
24
24
|
export type { FormatDiagnosticsOptions } from './diagnostics/format.js';
|
|
25
|
-
export type { AbortSignalLike, BlobLike, BuildIndexOptions, ByteSource, CacheOptions, DecodeAnnotationsOptions, EdfAnnotation, EdfAnnotationsResult, EdfCalendarDate, EdfChunk, EdfChunkSignal, EdfClockTime, EdfDiagnostic, EdfDiagnosticCode, EdfGap, EdfHeader, EdfInspection, EdfKnownDiagnosticCode, EdfLocation, EdfPatientId, EdfRawHeaderFields, EdfRawSignalFields, EdfRecordIndex, EdfRecording, EdfRecordingId, EdfScale, EdfSegment, EdfSeverity, EdfSignal, EdfStartTime, EdfTimeline, EdfVariant, FetchLike, HttpResponseLike, HttpSourceOptions, OpenOptions, ParseOptions, ReadOptions, RecordRange, RecordSelection, WindowSelection, } from './types.js';
|
|
25
|
+
export type { AbortSignalLike, BlobLike, BuildIndexOptions, ByteSource, CacheOptions, DecodeAnnotationsOptions, EdfAnnotation, EdfAnnotationsResult, EdfCalendarDate, EdfChunk, EdfChunkSignal, EdfClockTime, EdfDiagnostic, EdfDiagnosticCode, EdfEnvelopeChunk, EdfEnvelopeSignal, EdfGap, EdfHeader, EdfInspection, EdfKnownDiagnosticCode, EdfLocation, EdfPatientId, EdfPhysicalEnvelope, EdfRawHeaderFields, EdfRawSignalFields, EdfRecordIndex, EdfRecording, EdfRecordingId, EdfScale, EdfSegment, EdfSeverity, EdfSignal, EdfStartTime, EdfStatusWord, EdfTimeline, EdfTriggerEvent, EdfVariant, EnvelopeSelection, FetchLike, HttpResponseLike, HttpSourceOptions, OpenOptions, ParseOptions, ReadOptions, RecordRange, RecordSelection, TriggerSelection, WindowSelection, } from './types.js';
|
|
26
26
|
export type { AnyEdfError, EdfErrorKind, EdfFormatErrorInit } from './errors.js';
|
|
27
27
|
export { EdfAmbiguousChannelError, EdfBudgetError, EdfChannelNotFoundError, EdfError, EdfFormatError, EdfRangeError, EdfScalingError, EdfSourceError, isEdfError, } from './errors.js';
|
|
28
28
|
export { BDF_ANNOTATIONS_LABEL, BDF_DIGITAL_MAX, BDF_DIGITAL_MIN, EDF_ANNOTATIONS_LABEL, EDF_DIGITAL_MAX, EDF_DIGITAL_MIN, EDF_HEADER_BLOCK_BYTES, EDF_RECOMMENDED_MAX_RECORD_BYTES, TICKS_PER_SECOND, VERSION, } from './constants.js';
|
|
@@ -41,6 +41,8 @@ export { cachedSource } from './io/cached.js';
|
|
|
41
41
|
export { httpSource } from './io/http.js';
|
|
42
42
|
export { readHeader, readRecordBytes } from './io/read.js';
|
|
43
43
|
export { buildRecordIndex, buildTimeline } from './record-index.js';
|
|
44
|
+
export { decodeStatusWord, getStatusSignal, readTriggers } from './biosemi.js';
|
|
45
|
+
export { envelopeOfSamples, readEnvelope, toPhysicalEnvelope } from './envelope.js';
|
|
44
46
|
export { inspectEdf } from './inspect.js';
|
|
45
47
|
export { openEdf, readAnnotations, readRecords, readWindow } from './recording.js';
|
|
46
48
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,mFAAmF;AACnF,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxE,YAAY,EACV,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,aAAa,EACb,sBAAsB,EACtB,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AAUpB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AAMrB,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gCAAgC,EAChC,gBAAgB,EAChB,OAAO,GACR,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAQnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMpE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,mFAAmF;AACnF,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxE,YAAY,EACV,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,aAAa,EACb,sBAAsB,EACtB,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,UAAU,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACZ,aAAa,EACb,WAAW,EACX,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,YAAY,CAAC;AAUpB,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AAMrB,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gCAAgC,EAChC,gBAAgB,EAChB,OAAO,GACR,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAQnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM1C,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMpE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,8 @@ export { buildRecordIndex, buildTimeline } from './record-index.js';
|
|
|
54
54
|
// ===========================================================================
|
|
55
55
|
// Convenience layer
|
|
56
56
|
// ===========================================================================
|
|
57
|
+
export { decodeStatusWord, getStatusSignal, readTriggers } from './biosemi.js';
|
|
58
|
+
export { envelopeOfSamples, readEnvelope, toPhysicalEnvelope } from './envelope.js';
|
|
57
59
|
export { inspectEdf } from './inspect.js';
|
|
58
60
|
export { openEdf, readAnnotations, readRecords, readWindow } from './recording.js';
|
|
59
61
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAsEH,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,uBAAuB,EACvB,QAAQ,EACR,cAAc,EACd,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gCAAgC,EAChC,gBAAgB,EAChB,OAAO,GACR,MAAM,gBAAgB,CAAC;AAExB,8EAA8E;AAC9E,2EAA2E;AAC3E,2CAA2C;AAC3C,8EAA8E;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEnE,8EAA8E;AAC9E,yEAAyE;AACzE,2EAA2E;AAC3E,6CAA6C;AAC7C,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,8EAA8E;AAC9E,uCAAuC;AACvC,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEpE,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|