static autoTextGrid Table_to_TextGrid (Table me, const char32 *text, double xmin, double xmax) { //Table_createWithColumnNames (0, L"time type type-t t-pos length a-pos sample id uniq"); try { long length, textLength = str32len (text); long numberOfRows = my rows -> size; long timeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"time"); long typeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"type"); long tposColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"t-pos"); long idColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"id"); autoTextGrid thee = TextGrid_create (xmin, xmax, U"sentence clause word phoneme", U""); TextGrid_setIntervalText (thee.peek(), 1, 1, text); long p1c = 1, p1w = 1; double t1p = xmin; bool wordEnd = false; autoMelderString mark; IntervalTier itc = (IntervalTier) thy tiers -> item[2]; IntervalTier itw = (IntervalTier) thy tiers -> item[3]; IntervalTier itp = (IntervalTier) thy tiers -> item[4]; for (long i = 1; i <= numberOfRows; i++) { double time = Table_getNumericValue_Assert (me, i, timeColumnIndex); int type = Table_getNumericValue_Assert (me, i, typeColumnIndex); long pos = Table_getNumericValue_Assert (me, i, tposColumnIndex); if (type == espeakEVENT_SENTENCE) { // Only insert a new boundary, no text // text will be inserted at end sentence event if (time > xmin and time < xmax) { IntervalTier_addBoundaryUnsorted (itc, itc -> intervals -> size, time, U"", true); } p1c = pos; } else if (type == espeakEVENT_END) { // End of clause: insert new boundary, and fill left interval with text length = pos - p1c + 1; MelderString_ncopy (&mark, text + p1c - 1, length); MelderString_trimWhiteSpaceAtEnd (&mark); if (time > xmin and time < xmax) { IntervalTier_addBoundaryUnsorted (itc, itc -> intervals -> size, time, mark.string, true); } else { TextGrid_setIntervalText (thee.peek(), 2, itc -> intervals -> size, mark.string); } p1c = pos; // End of clause always signals "end of a word" if (pos <= textLength) { length = pos - p1w + 1; MelderString_ncopy (&mark, text + p1w - 1, length); MelderString_trimWhiteSpaceAtEnd (&mark); if (time > xmin and time < xmax) { IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, mark.string, true); } else { TextGrid_setIntervalText (thee.peek(), 3, itw -> intervals -> size, mark.string); } // now the next word event should not trigger setting the left interval text wordEnd = false; } } else if (type == espeakEVENT_WORD) { if (pos < p1w) { continue; } if (time > xmin and time < xmax) { length = pos - p1w; if (pos == textLength) length++; MelderString_ncopy (&mark, text + p1w - 1, length); MelderString_trimWhiteSpaceAtEnd (&mark); IntervalTier_addBoundaryUnsorted (itw, itw -> intervals -> size, time, (wordEnd ? mark.string : U""), true); } wordEnd = true; p1w = pos; } else if (type == espeakEVENT_PHONEME) { const char32 *id = Table_getStringValue_Assert (me, i, idColumnIndex); if (time > t1p) { // Insert new boudary and label interval with the id // TODO: Translate the id to the correct notation TextInterval ti = (TextInterval) itp -> intervals -> item[itp -> intervals -> size]; if (time > ti -> xmin and time < ti -> xmax) { IntervalTier_addBoundaryUnsorted (itp, itp -> intervals -> size, time, id, false); } } else { // Just in case the phoneme starts at xmin we only need to set interval text TextGrid_setIntervalText (thee.peek(), 4, itp -> intervals -> size, id); } t1p = time; } } Sorted_sort (itc -> intervals); Sorted_sort (itw -> intervals); Sorted_sort (itp -> intervals); return thee; } catch (MelderError) { Melder_throw (U"TextGrid not created from Table with events."); } }
static autoTextGrid Table_to_TextGrid (Table me, const char32 *text, double xmin, double xmax) { //Table_createWithColumnNames (0, L"time type type-t t-pos length a-pos sample id uniq"); try { long length, textLength = str32len (text); long numberOfRows = my rows.size; long timeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"time"); long typeColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"type"); long tposColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"t-pos"); long idColumnIndex = Table_getColumnIndexFromColumnLabel (me, U"id"); autoTextGrid thee = TextGrid_create (xmin, xmax, U"sentence clause word phoneme", U""); TextGrid_setIntervalText (thee.get(), 1, 1, text); long p1c = 1, p1w = 1; double time_phon_p = xmin; bool wordEnd = false; autoMelderString mark; IntervalTier clauses = (IntervalTier) thy tiers->at [2]; IntervalTier words = (IntervalTier) thy tiers->at [3]; IntervalTier phonemes = (IntervalTier) thy tiers->at [4]; for (long i = 1; i <= numberOfRows; i++) { double time = Table_getNumericValue_Assert (me, i, timeColumnIndex); int type = Table_getNumericValue_Assert (me, i, typeColumnIndex); long pos = Table_getNumericValue_Assert (me, i, tposColumnIndex); if (type == espeakEVENT_SENTENCE) { // Only insert a new boundary, no text // text will be inserted at end sentence event if (time > xmin && time < xmax) { IntervalTier_addBoundaryUnsorted (clauses, clauses -> intervals.size, time, U"", true); } p1c = pos; } else if (type == espeakEVENT_END) { // End of clause: insert new boundary, and fill left interval with text length = pos - p1c + 1; MelderString_ncopy (&mark, text + p1c - 1, length); MelderString_trimWhiteSpaceAtEnd (& mark); if (time > xmin && time < xmax) { IntervalTier_addBoundaryUnsorted (clauses, clauses -> intervals.size, time, mark.string, true); } else { TextGrid_setIntervalText (thee.get(), 2, clauses -> intervals.size, mark.string); } p1c = pos; // End of clause always signals "end of a word" if (pos <= textLength) { length = pos - p1w + 1; MelderString_ncopy (&mark, text + p1w - 1, length); MelderString_trimWhiteSpaceAtEnd (& mark); if (time > xmin && time < xmax) { IntervalTier_addBoundaryUnsorted (words, words -> intervals.size, time, mark.string, true); } else { TextGrid_setIntervalText (thee.get(), 3, words -> intervals.size, mark.string); } // now the next word event should not trigger setting the left interval text wordEnd = false; } } else if (type == espeakEVENT_WORD) { if (pos < p1w) { continue; } if (time > xmin && time < xmax) { length = pos - p1w; if (pos == textLength) { length++; } MelderString_ncopy (&mark, text + p1w - 1, length); MelderString_trimWhiteSpaceAtEnd (& mark); IntervalTier_addBoundaryUnsorted (words, words -> intervals.size, time, ( wordEnd ? mark.string : U"" ), true); } wordEnd = true; p1w = pos; } else if (type == espeakEVENT_PHONEME) { const char32 *id = Table_getStringValue_Assert (me, i, idColumnIndex); if (time > time_phon_p) { // Insert new boudary and label interval with the id // TODO: Translate the id to the correct notation TextInterval ti = phonemes -> intervals.at [phonemes -> intervals.size]; if (time > ti -> xmin && time < ti -> xmax) { IntervalTier_addBoundaryUnsorted (phonemes, phonemes -> intervals.size, time, id, false); } } else { // Just in case the phoneme starts at xmin we only need to set interval text TextGrid_setIntervalText (thee.get(), 4, phonemes -> intervals.size, id); } time_phon_p = time; } } clauses -> intervals. sort (); words -> intervals. sort (); phonemes -> intervals. sort (); IntervalTier_mergeSpecialIntervals (phonemes); // Merge neighbouring empty U"" and U"\001" intervals IntervalTier_removeVeryShortIntervals (words); IntervalTier_removeVeryShortIntervals (clauses); /* Use empty intervals in phoneme tier for more precision in the word tier */ IntervalTier_insertEmptyIntervalsFromOtherTier (words, phonemes); IntervalTier_mergeSpecialIntervals (words); // Merge neighbouring empty U"" and U"\001" intervals return thee; } catch (MelderError) { Melder_throw (U"TextGrid not created from Table with events."); } }
autoEEG EEG_readFromBdfFile (MelderFile file) { try { autofile f = Melder_fopen (file, "rb"); char buffer [81]; fread (buffer, 1, 8, f); buffer [8] = '\0'; bool is24bit = buffer [0] == (char) 255; fread (buffer, 1, 80, f); buffer [80] = '\0'; trace (U"Local subject identification: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 80, f); buffer [80] = '\0'; trace (U"Local recording identification: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; trace (U"Start date of recording: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; trace (U"Start time of recording: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; long numberOfBytesInHeaderRecord = atol (buffer); trace (U"Number of bytes in header record: ", numberOfBytesInHeaderRecord); fread (buffer, 1, 44, f); buffer [44] = '\0'; trace (U"Version of data format: \"", Melder_peek8to32 (buffer), U"\""); fread (buffer, 1, 8, f); buffer [8] = '\0'; long numberOfDataRecords = strtol (buffer, nullptr, 10); trace (U"Number of data records: ", numberOfDataRecords); fread (buffer, 1, 8, f); buffer [8] = '\0'; double durationOfDataRecord = atof (buffer); trace (U"Duration of a data record: ", durationOfDataRecord); fread (buffer, 1, 4, f); buffer [4] = '\0'; long numberOfChannels = atol (buffer); trace (U"Number of channels in data record: ", numberOfChannels); if (numberOfBytesInHeaderRecord != (numberOfChannels + 1) * 256) Melder_throw (U"Number of bytes in header record (", numberOfBytesInHeaderRecord, U") doesn't match number of channels (", numberOfChannels, U")."); autostring32vector channelNames (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 16, f); buffer [16] = '\0'; // labels of the channels /* * Strip all final spaces. */ for (int i = 15; i >= 0; i --) { if (buffer [i] == ' ') { buffer [i] = '\0'; } else { break; } } channelNames [ichannel] = Melder_8to32 (buffer); trace (U"Channel <<", channelNames [ichannel], U">>"); } bool hasLetters = str32equ (channelNames [numberOfChannels], U"EDF Annotations"); double samplingFrequency = NUMundefined; for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 80, f); buffer [80] = '\0'; // transducer type } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; // physical dimension of channels } autoNUMvector <double> physicalMinimum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; physicalMinimum [ichannel] = atof (buffer); } autoNUMvector <double> physicalMaximum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; physicalMaximum [ichannel] = atof (buffer); } autoNUMvector <double> digitalMinimum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; digitalMinimum [ichannel] = atof (buffer); } autoNUMvector <double> digitalMaximum (1, numberOfChannels); for (long ichannel = 1; ichannel <= numberOfChannels; ichannel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; digitalMaximum [ichannel] = atof (buffer); } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 80, f); buffer [80] = '\0'; // prefiltering } long numberOfSamplesPerDataRecord = 0; for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 8, f); buffer [8] = '\0'; // number of samples in each data record long numberOfSamplesInThisDataRecord = atol (buffer); if (samplingFrequency == NUMundefined) { numberOfSamplesPerDataRecord = numberOfSamplesInThisDataRecord; samplingFrequency = numberOfSamplesInThisDataRecord / durationOfDataRecord; } if (numberOfSamplesInThisDataRecord / durationOfDataRecord != samplingFrequency) Melder_throw (U"Number of samples per data record in channel ", channel, U" (", numberOfSamplesInThisDataRecord, U") doesn't match sampling frequency of channel 1 (", samplingFrequency, U")."); } for (long channel = 1; channel <= numberOfChannels; channel ++) { fread (buffer, 1, 32, f); buffer [32] = '\0'; // reserved } double duration = numberOfDataRecords * durationOfDataRecord; autoEEG him = EEG_create (0, duration); his numberOfChannels = numberOfChannels; autoSound me = Sound_createSimple (numberOfChannels, duration, samplingFrequency); Melder_assert (my nx == numberOfSamplesPerDataRecord * numberOfDataRecords); autoNUMvector <unsigned char> dataBuffer (0L, 3 * numberOfSamplesPerDataRecord - 1); for (long record = 1; record <= numberOfDataRecords; record ++) { for (long channel = 1; channel <= numberOfChannels; channel ++) { double factor = channel == numberOfChannels ? 1.0 : physicalMinimum [channel] / digitalMinimum [channel]; if (channel < numberOfChannels - EEG_getNumberOfExtraSensors (him.peek())) factor /= 1000000.0; if (is24bit) { fread (& dataBuffer [0], 3, numberOfSamplesPerDataRecord, f); unsigned char *p = & dataBuffer [0]; for (long i = 1; i <= numberOfSamplesPerDataRecord; i ++) { long sample = i + (record - 1) * numberOfSamplesPerDataRecord; Melder_assert (sample <= my nx); uint8_t lowByte = *p ++, midByte = *p ++, highByte = *p ++; uint32_t externalValue = ((uint32_t) highByte << 16) | ((uint32_t) midByte << 8) | (uint32_t) lowByte; if ((highByte & 128) != 0) // is the 24-bit sign bit on? externalValue |= 0xFF000000; // extend negative sign to 32 bits my z [channel] [sample] = (int32_t) externalValue * factor; } } else { fread (& dataBuffer [0], 2, numberOfSamplesPerDataRecord, f); unsigned char *p = & dataBuffer [0]; for (long i = 1; i <= numberOfSamplesPerDataRecord; i ++) { long sample = i + (record - 1) * numberOfSamplesPerDataRecord; Melder_assert (sample <= my nx); uint8 lowByte = *p ++, highByte = *p ++; uint16 externalValue = (uint16) ((uint16) highByte << 8) | (uint16) lowByte; my z [channel] [sample] = (int16) externalValue * factor; } } } } int numberOfStatusBits = 8; for (long i = 1; i <= my nx; i ++) { unsigned long value = (long) my z [numberOfChannels] [i]; if (value & 0x0000FF00) { numberOfStatusBits = 16; } } autoTextGrid thee; if (hasLetters) { thee = TextGrid_create (0, duration, U"Mark Trigger", U"Mark Trigger"); autoMelderString letters; double time = NUMundefined; for (long i = 1; i <= my nx; i ++) { unsigned long value = (long) my z [numberOfChannels] [i]; for (int byte = 1; byte <= numberOfStatusBits / 8; byte ++) { unsigned long mask = byte == 1 ? 0x000000ff : 0x0000ff00; char32 kar = byte == 1 ? (value & mask) : (value & mask) >> 8; if (kar != U'\0' && kar != 20) { MelderString_appendCharacter (& letters, kar); } else if (letters. string [0] != U'\0') { if (letters. string [0] == U'+') { if (NUMdefined (time)) { try { TextGrid_insertPoint (thee.peek(), 1, time, U""); } catch (MelderError) { Melder_throw (U"Did not insert empty mark (", letters. string, U") on Mark tier."); } time = NUMundefined; // defensive } time = Melder_atof (& letters. string [1]); MelderString_empty (& letters); } else { if (! NUMdefined (time)) { Melder_throw (U"Undefined time for label at sample ", i, U"."); } try { if (Melder_nequ (letters. string, U"Trigger-", 8)) { try { TextGrid_insertPoint (thee.peek(), 2, time, & letters. string [8]); } catch (MelderError) { Melder_clearError (); trace (U"Duplicate trigger at ", time, U" seconds: ", & letters. string [8]); } } else { TextGrid_insertPoint (thee.peek(), 1, time, & letters. string [0]); } } catch (MelderError) { Melder_throw (U"Did not insert mark (", letters. string, U") on Trigger tier."); } time = NUMundefined; // crucial MelderString_empty (& letters); } } } } if (NUMdefined (time)) { TextGrid_insertPoint (thee.peek(), 1, time, U""); time = NUMundefined; // defensive } } else { thee = TextGrid_create (0, duration, numberOfStatusBits == 8 ? U"S1 S2 S3 S4 S5 S6 S7 S8" : U"S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15 S16", U""); for (int bit = 1; bit <= numberOfStatusBits; bit ++) { unsigned long bitValue = 1 << (bit - 1); IntervalTier tier = (IntervalTier) thy tiers -> item [bit]; for (long i = 1; i <= my nx; i ++) { unsigned long previousValue = i == 1 ? 0 : (long) my z [numberOfChannels] [i - 1]; unsigned long thisValue = (long) my z [numberOfChannels] [i]; if ((thisValue & bitValue) != (previousValue & bitValue)) { double time = i == 1 ? 0.0 : my x1 + (i - 1.5) * my dx; if (time != 0.0) TextGrid_insertBoundary (thee.peek(), bit, time); if ((thisValue & bitValue) != 0) TextGrid_setIntervalText (thee.peek(), bit, tier -> intervals -> size, U"1"); } } } } f.close (file); his channelNames = channelNames.transfer(); his sound = me.move(); his textgrid = thee.move(); if (EEG_getNumberOfCapElectrodes (him.peek()) == 32) { EEG_setChannelName (him.peek(), 1, U"Fp1"); EEG_setChannelName (him.peek(), 2, U"AF3"); EEG_setChannelName (him.peek(), 3, U"F7"); EEG_setChannelName (him.peek(), 4, U"F3"); EEG_setChannelName (him.peek(), 5, U"FC1"); EEG_setChannelName (him.peek(), 6, U"FC5"); EEG_setChannelName (him.peek(), 7, U"T7"); EEG_setChannelName (him.peek(), 8, U"C3"); EEG_setChannelName (him.peek(), 9, U"CP1"); EEG_setChannelName (him.peek(), 10, U"CP5"); EEG_setChannelName (him.peek(), 11, U"P7"); EEG_setChannelName (him.peek(), 12, U"P3"); EEG_setChannelName (him.peek(), 13, U"Pz"); EEG_setChannelName (him.peek(), 14, U"PO3"); EEG_setChannelName (him.peek(), 15, U"O1"); EEG_setChannelName (him.peek(), 16, U"Oz"); EEG_setChannelName (him.peek(), 17, U"O2"); EEG_setChannelName (him.peek(), 18, U"PO4"); EEG_setChannelName (him.peek(), 19, U"P4"); EEG_setChannelName (him.peek(), 20, U"P8"); EEG_setChannelName (him.peek(), 21, U"CP6"); EEG_setChannelName (him.peek(), 22, U"CP2"); EEG_setChannelName (him.peek(), 23, U"C4"); EEG_setChannelName (him.peek(), 24, U"T8"); EEG_setChannelName (him.peek(), 25, U"FC6"); EEG_setChannelName (him.peek(), 26, U"FC2"); EEG_setChannelName (him.peek(), 27, U"F4"); EEG_setChannelName (him.peek(), 28, U"F8"); EEG_setChannelName (him.peek(), 29, U"AF4"); EEG_setChannelName (him.peek(), 30, U"Fp2"); EEG_setChannelName (him.peek(), 31, U"Fz"); EEG_setChannelName (him.peek(), 32, U"Cz"); } else if (EEG_getNumberOfCapElectrodes (him.peek()) == 64) { EEG_setChannelName (him.peek(), 1, U"Fp1"); EEG_setChannelName (him.peek(), 2, U"AF7"); EEG_setChannelName (him.peek(), 3, U"AF3"); EEG_setChannelName (him.peek(), 4, U"F1"); EEG_setChannelName (him.peek(), 5, U"F3"); EEG_setChannelName (him.peek(), 6, U"F5"); EEG_setChannelName (him.peek(), 7, U"F7"); EEG_setChannelName (him.peek(), 8, U"FT7"); EEG_setChannelName (him.peek(), 9, U"FC5"); EEG_setChannelName (him.peek(), 10, U"FC3"); EEG_setChannelName (him.peek(), 11, U"FC1"); EEG_setChannelName (him.peek(), 12, U"C1"); EEG_setChannelName (him.peek(), 13, U"C3"); EEG_setChannelName (him.peek(), 14, U"C5"); EEG_setChannelName (him.peek(), 15, U"T7"); EEG_setChannelName (him.peek(), 16, U"TP7"); EEG_setChannelName (him.peek(), 17, U"CP5"); EEG_setChannelName (him.peek(), 18, U"CP3"); EEG_setChannelName (him.peek(), 19, U"CP1"); EEG_setChannelName (him.peek(), 20, U"P1"); EEG_setChannelName (him.peek(), 21, U"P3"); EEG_setChannelName (him.peek(), 22, U"P5"); EEG_setChannelName (him.peek(), 23, U"P7"); EEG_setChannelName (him.peek(), 24, U"P9"); EEG_setChannelName (him.peek(), 25, U"PO7"); EEG_setChannelName (him.peek(), 26, U"PO3"); EEG_setChannelName (him.peek(), 27, U"O1"); EEG_setChannelName (him.peek(), 28, U"Iz"); EEG_setChannelName (him.peek(), 29, U"Oz"); EEG_setChannelName (him.peek(), 30, U"POz"); EEG_setChannelName (him.peek(), 31, U"Pz"); EEG_setChannelName (him.peek(), 32, U"CPz"); EEG_setChannelName (him.peek(), 33, U"Fpz"); EEG_setChannelName (him.peek(), 34, U"Fp2"); EEG_setChannelName (him.peek(), 35, U"AF8"); EEG_setChannelName (him.peek(), 36, U"AF4"); EEG_setChannelName (him.peek(), 37, U"AFz"); EEG_setChannelName (him.peek(), 38, U"Fz"); EEG_setChannelName (him.peek(), 39, U"F2"); EEG_setChannelName (him.peek(), 40, U"F4"); EEG_setChannelName (him.peek(), 41, U"F6"); EEG_setChannelName (him.peek(), 42, U"F8"); EEG_setChannelName (him.peek(), 43, U"FT8"); EEG_setChannelName (him.peek(), 44, U"FC6"); EEG_setChannelName (him.peek(), 45, U"FC4"); EEG_setChannelName (him.peek(), 46, U"FC2"); EEG_setChannelName (him.peek(), 47, U"FCz"); EEG_setChannelName (him.peek(), 48, U"Cz"); EEG_setChannelName (him.peek(), 49, U"C2"); EEG_setChannelName (him.peek(), 50, U"C4"); EEG_setChannelName (him.peek(), 51, U"C6"); EEG_setChannelName (him.peek(), 52, U"T8"); EEG_setChannelName (him.peek(), 53, U"TP8"); EEG_setChannelName (him.peek(), 54, U"CP6"); EEG_setChannelName (him.peek(), 55, U"CP4"); EEG_setChannelName (him.peek(), 56, U"CP2"); EEG_setChannelName (him.peek(), 57, U"P2"); EEG_setChannelName (him.peek(), 58, U"P4"); EEG_setChannelName (him.peek(), 59, U"P6"); EEG_setChannelName (him.peek(), 60, U"P8"); EEG_setChannelName (him.peek(), 61, U"P10"); EEG_setChannelName (him.peek(), 62, U"PO8"); EEG_setChannelName (him.peek(), 63, U"PO4"); EEG_setChannelName (him.peek(), 64, U"O2"); } return him; } catch (MelderError) {