/** * Parsing for the time-range options. * * Researchers write offsets in whatever form is natural for the recording in front * of them: seconds for a short ECG strip, `30m` into a sleep study, `01:23:45` when * reading off a clock. All three are accepted; anything ambiguous is rejected with * a message that shows the forms that work. */ export declare class TimeRangeError extends Error { constructor(message: string); } /** * Every spelling of a unit this accepts, and what one of it is worth in seconds. * * Exported so the spellings can be enumerated by a test rather than listed a second time: * twelve of these sixteen are named nowhere in the tool or its documentation, and none of * their values was checked by anything. `hrs: 360` would have converted `--start 2hrs` from * twelve minutes in and said nothing, which is the one kind of mistake a window may not make. */ export declare const UNIT_SECONDS: Record; /** * Parse a duration or offset into seconds. * * Accepted: `90`, `90s`, `5m`, `1h30m`, `1h 30m 15s`, `00:30:00`, `30:00`, `250ms`. * * `allowNegative` is for the two options that name a position rather than a length. * * A recording is timed from its first record's timekeeping annotation, and nothing obliges that * to sit at or after zero: a file whose records run from -100 s to -97 s is one this tool reads, * times from -100, and describes with * * Timed from -100.000s (first sample; --start and --end use this clock) * * That line says the number can be typed straight back in, and it could not be. Every offset * such a recording has came back as "not a time I understand", so its whole clock was * unreachable and no window of it could be converted at all — the one file shape where a * window is refused for naming a moment the recording actually contains. * * A length below zero is still a different thing, and `--duration` still refuses one. */ export declare function parseTimeSpec(input: string, optionName?: string, allowNegative?: boolean): number; export interface ResolvedRange { /** Inclusive start, in seconds from the beginning of the recording. */ startSeconds: number; /** Exclusive end, in seconds. */ endSeconds: number; /** First data record touching the window. */ startRecord: number; /** One past the last data record touching the window. */ endRecord: number; /** True when the window covers the whole recording. */ isWholeRecording: boolean; /** Earliest record start, including EDF+D timing gaps. */ recordingStartSeconds: number; /** End of the latest record, including EDF+D timing gaps. */ recordingEndSeconds: number; } /** * Slack for comparisons at sample/window boundaries. * * A nanosecond is far below any real sampling interval — 20 kHz is 50 microseconds — so it * absorbs the arithmetic error in `recordStart + sample / rate` without reaching a * neighbouring sample. */ export declare const BOUNDARY_TOLERANCE = 1e-9; /** * The slack to use for a channel sampled this often. * * Never past half a sample interval, because slack that reaches the next sample stops being * slack — half is the most that cannot, since the nearest sample below a bound sits a whole * interval away from it. `Math.min` takes exactly half at rates above 500 MHz, which is where * this said "never as much as half" of a formula that returns it. A fixed nanosecond was * applied whatever the rate, and the format does not * oblige the interval to be larger than it: EDF's record duration is an 8-character field * that accepts `1e-9`. A recording of two 1 ns records holding ten samples each wrote ten of * its twenty rows — the window ends at 2e-9, the comparison asked for `time < 2e-9 - 1e-9`, * and the entire second record failed it. Exit 0, no warning, half the samples gone. */ export declare function toleranceFor(rate: number): number; /** Match the exact half-open boundary rules used while writing signal rows. */ export declare function sampleTimeIsInRange(time: number, startSeconds: number, endSeconds: number, tolerance?: number): boolean; /** Count samples from one record that fall inside a half-open requested window. */ export declare function countSamplesInRange(options: { recordStart: number; rate: number; samplesPerRecord: number; startSeconds: number; endSeconds: number; }): number; /** * Turn a requested window into both an exact time span and the record range that * contains it. Records are the unit the file can be read in; the exact span is what * decides which samples inside those records are actually written. */ export declare function resolveRange(options: { start?: number | undefined; /** The `--start` value exactly as typed, quoted back in the past-the-end error. */ startText?: string | undefined; duration?: number | undefined; /** The `--duration` value exactly as typed, quoted back in the window error. */ durationText?: string | undefined; end?: number | undefined; /** The `--end` value exactly as typed, quoted back in the window error. */ endText?: string | undefined; recordDuration: number; recordCount: number; /** * True start time of each data record, for discontinuous files. When absent, * records are assumed to sit end to end. */ recordStarts?: Float64Array | null | undefined; }): ResolvedRange;