private void btnReadBCI2000_Click(object sender, EventArgs e) { // clear the output txtOutput.Text = ""; // try to read the file Data_BCI2000 info = new Data_BCI2000(); double[][] samples = null; bool result = readBCI2000dat(txtInputFile.Text, out info, out samples); if (!result) { return; } // output txtOutput.Text = info.firstLine + Environment.NewLine + Environment.NewLine; txtOutput.Text += "Header length: " + info.headerLen + Environment.NewLine; txtOutput.Text += "Source channels: " + info.sourceCh + Environment.NewLine; txtOutput.Text += "State vector length: " + info.stateVectorLen + Environment.NewLine; txtOutput.Text += Environment.NewLine; //txtOutput.Text += "Header: " + Environment.NewLine + data.header; txtOutput.Text += "Sample rate: " + info.samplingRate + Environment.NewLine; txtOutput.Text += Environment.NewLine; txtOutput.Text += "Number of samples: " + info.numSamples + Environment.NewLine + Environment.NewLine; string strOutput = ""; for (int i = 0; i < info.numSamples; i++) { for (int j = 0; j < info.sourceCh; j++) { if (j != 0) { strOutput += "\t"; } strOutput += samples[i][j]; } strOutput += Environment.NewLine; } txtOutput.Text += strOutput; }
private bool readBCI2000dat(string filename, out Data_BCI2000 info, out double[][] samples) { FileStream dataStream = null; StreamReader dataReader = null; // check if the file exists if (!File.Exists(filename)) { MessageBox.Show("Could not find input file", "File error", MessageBoxButtons.OK, MessageBoxIcon.Error); info = null; samples = null; return(false); } try { // open file stream dataStream = new FileStream(filename, FileMode.Open); // open reader //dataReader = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128); dataReader = new System.IO.StreamReader(dataStream); } catch (Exception) { // message MessageBox.Show("Could not create filestream to data file '" + filename + "' for reading"); info = null; samples = null; return(false); } // create a new bci2000 data object info = new Data_BCI2000(); // retrieve the first line info.firstLine = dataReader.ReadLine(); // retrieve HeaderLen string fieldName = "HeaderLen="; int fieldValueLength = 6; int pos = info.firstLine.IndexOf(fieldName); if (pos == -1 || info.firstLine.Length < pos + fieldName.Length + fieldValueLength) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } bool result = Int32.TryParse(info.firstLine.Substring(pos + fieldName.Length, fieldValueLength), out info.headerLen); if (!result) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } // retrieve SourceCh fieldName = "SourceCh="; fieldValueLength = 2; pos = info.firstLine.IndexOf(fieldName); if (pos == -1 || info.firstLine.Length < pos + fieldName.Length + fieldValueLength) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } result = Int32.TryParse(info.firstLine.Substring(pos + fieldName.Length, fieldValueLength), out info.sourceCh); if (!result) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } // retrieve StatevectorLen fieldName = "StatevectorLen="; //fieldValueLength = 3; pos = info.firstLine.IndexOf(fieldName); fieldValueLength = Math.Min(3, info.firstLine.Length - (pos + fieldName.Length)); // adjusted: fieldValueLength is variable: so it is either three, or in case the string is shorter, the remainder of the string: either 1 or 2 if (pos == -1 || info.firstLine.Length < pos + fieldName.Length + fieldValueLength) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } result = Int32.TryParse(info.firstLine.Substring(pos + fieldName.Length, fieldValueLength), out info.stateVectorLen); if (!result) { MessageBox.Show("Could not retrieve " + fieldName + ", aborting"); info = null; samples = null; return(false); } // retrieve entire header char[] buffer = new char[info.headerLen]; dataStream.Position = 0; dataReader.DiscardBufferedData(); dataReader.ReadBlock(buffer, 0, info.headerLen); info.header = new string(buffer); // retrieve the sample rate from the header if (!getDoubleParameterFromHeader(info.header, "SamplingRate", out info.samplingRate)) { MessageBox.Show("Could not retrieve sample rate from header, aborting"); info = null; samples = null; return(false); } // set the dataStream position to the start of the data (needed, readblock before messed it up) dataStream.Position = info.headerLen; // set int mDataSize = 2; // each sample in BCI2000 is stored as an int16 (2 bytes) // calculate the number of samples info.numSamples = (int)(dataStream.Length - info.headerLen) / (mDataSize * info.sourceCh + info.stateVectorLen); // init matrix for all samples values samples = new double[info.numSamples][]; // retrieve the data for (int i = 0; i < info.numSamples; i++) { // init the row of samples samples[i] = new double[info.sourceCh]; // read the samples byte[] channels = new byte[mDataSize * info.sourceCh]; dataStream.Read(channels, 0, mDataSize * info.sourceCh); // convert each channel for (int j = 0; j < info.sourceCh; j++) { samples[i][j] = BitConverter.ToInt16(channels, j * mDataSize); } // read the state vector data byte[] stateVector = new byte[info.stateVectorLen]; dataStream.Read(stateVector, 0, info.stateVectorLen); // TODO: interpret state vector } // close the datastream if (dataStream != null) { dataStream.Close(); } dataReader = null; dataStream = null; // return success return(true); }
private void btnConvertBCIToPalmtree_Click(object sender, EventArgs e) { // clear the output txtOutput.Text = ""; // try to read the file Data_BCI2000 info = new Data_BCI2000(); double[][] samples = null; bool result = readBCI2000dat(txtInputFile.Text, out info, out samples); // open file dialog to save dat file SaveFileDialog dlgSaveDatFile = new SaveFileDialog(); dlgSaveDatFile.Filter = "Data files (*.dat)|*.dat|Data files (*.src)|*.src|All files (*.*)|*.*"; dlgSaveDatFile.RestoreDirectory = true; // restores current directory to the previously selected directory, potentially beneficial if other code relies on the currently set directory // check if ok has been clicked on the dialog if (dlgSaveDatFile.ShowDialog() != DialogResult.OK) { return; } FileStream dataStream = null; try { // create filestream: create file if it does not exists, allow to write, do not share with other processes and use buffer of 8192 bytes (roughly 1000 samples) dataStream = new FileStream(dlgSaveDatFile.FileName, FileMode.Create, FileAccess.Write, FileShare.None, 8192); } catch (Exception exc) { MessageBox.Show("Unable to create data file at " + dlgSaveDatFile.FileName + " (" + exc.ToString() + ")"); return; } // generate stream names for the header (bci2000 does not have these) string[] streamNames = new string[info.sourceCh]; for (int i = 0; i < streamNames.Length; i++) { streamNames[i] = "Ch" + (i + 1); } // create header DataHeader header = new DataHeader(); header.version = 1; header.code = "dat"; header.columnNames = streamNames; header.numPlaybackStreams = streamNames.Length; header.sampleRate = info.samplingRate; // write header if (dataStream != null) { DataWriter.writeBinaryHeader(dataStream, header); } // write data uint dataSampleCounter = 0; byte[] dataElapsedTimeBinary = BitConverter.GetBytes((1000.0 / header.sampleRate)); for (int i = 0; i < info.numSamples; i++) { // transform variables that will be stored in .dat to binary arrays (except for dataStreamValues array which is copied directly) byte[] dataSampleCounterBinary = BitConverter.GetBytes(dataSampleCounter); // transfer the values for output double[] dataStreamValues = new double[info.sourceCh]; for (int j = 0; j < info.sourceCh; j++) { dataStreamValues[j] = samples[i][j]; } // create new array to hold all bytes int l1 = dataSampleCounterBinary.Length; int l2 = dataElapsedTimeBinary.Length; int l3 = dataStreamValues.Length * sizeof(double); byte[] streamOut = new byte[l1 + l2 + l3]; // blockcopy all bytes to this array Buffer.BlockCopy(dataSampleCounterBinary, 0, streamOut, 0, l1); Buffer.BlockCopy(dataElapsedTimeBinary, 0, streamOut, l1, l2); Buffer.BlockCopy(dataStreamValues, 0, streamOut, l1 + l2, l3); // write data to file if (dataStream != null) { dataStream.Write(streamOut, 0, streamOut.Length); } // increase sample counter dataSampleCounter++; } // set output text txtOutput.Text = "Done"; // clear dataStream.Close(); dataStream = null; }