/// <summary> /// Creates a <see cref="WaveDataReader"/> instance created from a WAV stream. /// </summary> /// <param name="waveStream">The WAV stream. The data in the stream must include all headers that would be present in a WAV file.</param> /// <returns>The WaveData instance created from a WAV stream.</returns> /// <remarks> /// This method is similar to the <see cref="WaveDataReader(Stream)"/> constructor, /// however this method will first search the stream for a format chunk in order to set /// up the WaveData object with proper format info. /// </remarks> public static WaveDataReader FromStream(Stream waveStream) { RiffChunk riffChunk; WaveFormatChunk waveFormat = null; WaveDataReader waveData = null; while ((object)waveData == null) { riffChunk = RiffChunk.ReadNext(waveStream); switch (riffChunk.TypeID) { case RiffHeaderChunk.RiffTypeID: // ReSharper disable once ObjectCreationAsStatement new RiffHeaderChunk(riffChunk, waveStream, "WAVE"); break; case WaveFormatChunk.RiffTypeID: waveFormat = new WaveFormatChunk(riffChunk, waveStream); break; case WaveDataChunk.RiffTypeID: waveData = new WaveDataReader(waveFormat, waveStream); break; default: // Skip unnecessary sections waveStream.Seek(riffChunk.ChunkSize, SeekOrigin.Current); break; } } return(waveData); }
/// <summary> /// Creates a <see cref="WaveDataReader"/> instance created from a WAV stream. /// </summary> /// <param name="waveStream">The WAV stream. The data in the stream must include all headers that would be present in a WAV file.</param> /// <returns>The WaveData instance created from a WAV stream.</returns> /// <remarks> /// This method is similar to the <see cref="WaveDataReader.WaveDataReader(Stream)"/> constructor, /// however this method will first search the stream for a format chunk in order to set /// up the WaveData object with proper format info. /// </remarks> public static WaveDataReader FromStream(Stream waveStream) { RiffChunk riffChunk; WaveFormatChunk waveFormat = null; WaveDataReader waveData = null; while ((object)waveData == null) { riffChunk = RiffChunk.ReadNext(waveStream); switch (riffChunk.TypeID) { case RiffHeaderChunk.RiffTypeID: new RiffHeaderChunk(riffChunk, waveStream, "WAVE"); break; case WaveFormatChunk.RiffTypeID: waveFormat = new WaveFormatChunk(riffChunk, waveStream); break; case WaveDataChunk.RiffTypeID: waveData = new WaveDataReader(waveFormat, waveStream); break; default: // Skip unnecessary sections waveStream.Seek(riffChunk.ChunkSize, SeekOrigin.Current); break; } } return waveData; }
private void ProcessMeasurements() { List<IMeasurement> measurements = new List<IMeasurement>((int)(Ticks.ToSeconds(GapThreshold) * m_sampleRate * m_channels * 1.1D)); LittleBinaryValue[] sample; while (Enabled) { try { SpinWait spinner = new SpinWait(); // Determine what time it is now long now = DateTime.UtcNow.Ticks; // Assign a timestamp to the next sample based on its location // in the file relative to the other samples in the file long timestamp = m_startTime + (m_dataIndex * Ticks.PerSecond / m_sampleRate); if (now - timestamp > GapThreshold) { // Reset the start time and delay next transmission in an attempt to catch up m_startTime = now - (m_dataIndex * Ticks.PerSecond / m_sampleRate) + Ticks.FromSeconds(RecoveryDelay); timestamp = now; OnStatusMessage(MessageLevel.Info, "Start time reset."); } // Keep generating measurements until // we catch up to the current time. while (timestamp < now) { sample = m_dataReader.GetNextSample(); // If the sample is null, we've reached the end of the file - close and reopen, // resetting the data index and start time if (sample == null) { m_dataReader.Close(); m_dataReader.Dispose(); m_dataReader = OpenWaveDataReader(); m_dataIndex = 0; m_startTime = timestamp; sample = m_dataReader.GetNextSample(); } // Create new measurements, one for each channel, and add them to the measurements list for (int i = 0; i < m_channels; i++) measurements.Add(Measurement.Clone(OutputMeasurements[i], sample[i].ConvertToType(TypeCode.Double), timestamp)); // Update the data index and recalculate the assigned timestamp for the next sample m_dataIndex++; timestamp = m_startTime + (m_dataIndex * Ticks.PerSecond / m_sampleRate); } OnNewMeasurements(measurements); measurements.Clear(); while (DateTime.UtcNow.Ticks - timestamp <= GapThreshold / 100) { // Ahead of schedule -- pause for a moment spinner.SpinOnce(); } } catch (Exception ex) { OnProcessException(MessageLevel.Warning, ex); } } }
/// <summary> /// Releases the unmanaged resources used by the <see cref="WavInputAdapter"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_dataReader != null) { m_dataReader.Close(); m_dataReader.Dispose(); m_dataReader = null; } if ((object)m_dataCache != null) m_dataCache.Dispose(); } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
/// <summary> /// Attempts to close the file and release resources held by the adapter. /// </summary> protected override void AttemptDisconnection() { if ((object)m_dataReader != null) { m_dataReader.Close(); m_dataReader.Dispose(); m_dataReader = null; } }
/// <summary> /// Attempts to open the file to start getting wave data. /// </summary> protected override void AttemptConnection() { m_dataReader = OpenWaveDataReader(); m_dataIndex = 0; m_startTime = DateTime.UtcNow.Ticks; new Thread(ProcessMeasurements) { IsBackground = true }.Start(); }