/** * Finding a signal by name. * * Layer 2. Two functions and a predicate, and the reason they exist rather than being left to * the caller: deleting name lookup does not delete `signals.find(s => s.label === label)`, which * silently returns the first of a duplicate pair. CHB-MIT ships `'T8-P8'` twice, and picking one * of them by accident is how the wrong channel ends up in a paper. * * Matching is exact on the TRIMMED label and is case-sensitive. Nothing else is normalised: EDF * labels are electrode names, `'Fp1'` and `'FP1'` are written by different systems, and edfcore * has no montage vocabulary to decide they are the same thing. */ import type { EdfHeader, EdfSignal } from '../types.js'; /** * True for the two reserved annotation labels, matched on the trimmed text and case-sensitively. * * Both are accepted for either family: the label identifies the channel's ROLE, and a BDF+ file * written by an EDF+ library carries `'EDF Annotations'` — refusing to recognise it there would * expose a text channel as if it held samples. */ export declare function isAnnotationLabel(label: string): boolean; /** Every signal with this label, in signal order. Empty when none matches. */ export declare function findSignals(header: EdfHeader, label: string): readonly EdfSignal[]; /** * One signal, by index or by label. * * A numeric selector indexes `header.signals` directly. A label that matches nothing throws * `EdfChannelNotFoundError` carrying every available label; a label that matches more than one * signal throws `EdfAmbiguousChannelError` carrying the indices, because there is no answer * edfcore could return that would not be a guess. */ export declare function getSignal(header: EdfHeader, selector: number | string): EdfSignal; /** * A membership test over a caller's RegExp that cannot be poisoned by its own flags. * * `RegExp.prototype.test` is STATEFUL when the pattern carries `g` or `y`: it starts from * `lastIndex` and advances it on every match. Used across an array — which is what every filter * here does — that makes the result depend on what the previous element matched, so `/EEG/g` over * four EEG channels returns the first and third and silently drops the other two. The caller sees * half a montage with no error, and even a match-everything pattern stops returning every signal * once it carries the flag. * * A `g` flag on a membership test means nothing, so honouring its statefulness serves no one. The * regex is CLONED rather than reset in place: resetting the caller's object would mutate an * argument, and a module-level `const PATTERN = /x/g` shared with a `String.replace` elsewhere * would then behave differently depending on whether edfcore had been called first. */ /** * A matcher that arrived but is not one of the kinds the call takes. * * `assertSelector` above checks that one arrived; it never checked WHAT arrived, and `test` is then * assigned from whatever did. `matchSignals(header, 'Fp1')` — a plain string, which this module's * own docblock says is `findSignals`'s case — reached `test(signal.label)` and threw V8's "test is * not a function": an internal name, no `Next:` clause, and no mention of the function that does * take a label. * * `filterAnnotationsByText` did the same and worse. A predicate is only called once there is * something to call it on, so a wrong matcher returned `[]` for a recording with no events and * threw for the same argument on the next file — the third time in this package that the quality of * a refusal depended on the data rather than on the call (0.6.79, 0.6.86, and this one, fixed in * 0.6.103). */ export declare function assertMatcher(match: T, call: string, accepts: string, instead: string): T; export declare function matchesText(match: RegExp): (text: string) => boolean; /** * Every data signal whose label matches a pattern. * * `findSignals` matches one exact label, which is right when you know what you want. This is for * the other case: a montage is a family — `EEG Fpz-Cz`, `EEG Pz-Oz` — and picking it out by hand * means filtering `header.signals` and remembering to drop the annotations channel, which is the * step people forget. Its bytes are TAL text, so decoding them as samples produces numbers that * look like a signal. * * Annotation channels are never returned. Pass a RegExp or a predicate; a plain string is the * exact-match case `findSignals` already covers. */ export declare function matchSignals(header: EdfHeader, match: RegExp | ((label: string) => boolean)): readonly EdfSignal[]; /** * The recording's total declared length in seconds. * * The arithmetic every caller writes by hand — except that the hand-written version is * `recordCount * recordDurationSeconds`, and that product is float64. A record duration with no * exact binary representation lands just under the true value: 100 records of 0.29 s is exactly * 29 s and multiplies out to 28.999999999999996. The count is exact and the duration is exact in * ticks, so the product is computed there and converted once. * * That is the same defect `formatHeader`'s duration line was fixed for in 0.2.67, and until 0.3.1 * the two disagreed about the same file: the header line said `00:00:29` while this returned a * number that floors to 28. * * Zero for a file whose record duration is zero — legal EDF, and the honest answer, since such a * file's records do not advance in time. * * This is the DECLARED length. On an EDF+D file the recording spans longer than this, because the * gaps between records are not covered by any record; `timeline.spanSeconds` is that number. */ export declare function declaredDurationSeconds(header: EdfHeader): number; //# sourceMappingURL=lookup.d.ts.map