/** * EDF+ annotation (TAL) decoding. * * The annotations channel stores UTF-8 text in place of samples. Its bytes are a * run of Time-stamped Annotation Lists, each terminated by a NUL, with the rest * of the channel NUL-padded: * * +[<0x15>]<0x14><0x14>...<0x00> * * The first TAL of every data record carries that record's start time; that is how an EDF+D * file states where each record actually sits in time. It may carry event text after that, * which the specification allows and writers use, so an unreadable one costs a position and * whatever events went with it — see `malformedTimekeepingWithText`. * * +1.25<0x15>0.5<0x14>Seizure onset<0x14><0x00> */ declare const SEP_TEXT = 20; declare const SEP_DURATION = 21; declare const TAL_END = 0; export interface Annotation { /** Seconds from the start of the recording. */ onset: number; /** * Seconds, or null when the TAL stated no duration that could be read. * * Null covers two cases the file distinguishes and this field does not: a TAL that omitted * the duration, and a TAL that stated one which is not a number. They are told apart by * `unreadableDurations`, which is what raises the warning; the value itself has nowhere * honest to put "the file said `abc`". */ duration: number | null; text: string; /** Index of the data record this annotation was stored in. */ recordIndex: number; /** * True when the file stated a duration that could not be read. * * `duration` is null either way, which is the ambiguity the counts beside it exist to * flag — and those counts were of the whole file while `annotations.csv` is filtered to * the requested window. A conversion of one second of a recording warned that "1 * annotation states a duration that is not a number, so its duration_s cell is empty" * about an event two seconds outside it, and failed `--strict` for it. Carrying the fact * on the event lets the count be taken where the window has already been applied. */ durationUnreadable?: boolean; } export interface DecodedRecordAnnotations { /** Record start time in seconds, from the leading timekeeping TAL. */ recordStart: number | null; annotations: Annotation[]; /** Non-empty chunks that were not valid TALs, so the caller can report them. */ malformed: number; /** Unreadable TALs in first position, which carry a record's start time, not an event. */ malformedTimekeeping: number; /** * How many of those also carried event text, and so lost events as well as a position. * * A TAL in first position holds the record's start time, and may hold events after it — the * specification allows both in the one entry, and writers use it. When such a TAL cannot be * parsed, both are gone, and counting it only as lost timekeeping let the warning beside it * say "No event was lost" over a conversion that had just dropped four of them. * * Counted rather than inferred, because the sentence has to be right in the ordinary case * too: a bare timekeeping TAL really does lose no event, and that is nearly all of them. */ malformedTimekeepingWithText: number; /** * Events kept whose stated duration could not be read. * * Counted apart again, for the same reason the two above are: the entry was exported and * nothing about it is missing except the one field, so calling it an entry that "could not * be exported" describes a loss that did not happen and hides the one that did. */ unreadableDurations: number; /** * Events kept whose stated duration is a readable number below zero. * * Separate from the count above because the value survives: it is written to the CSV as * the file gave it, and what is wrong with it is arithmetic rather than parsing. */ negativeDurations: number; } /** * Decode one data record's annotation bytes. * * Malformed TALs are skipped rather than thrown, because a single bad annotation * should not cost the user an entire conversion. The count of skipped chunks is * returned so the caller can tell the user rather than losing them in silence. */ export declare function decodeRecordAnnotations(bytes: Uint8Array, recordIndex: number, carriesTimekeeping?: boolean): DecodedRecordAnnotations; export { SEP_TEXT, SEP_DURATION, TAL_END };