/// <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; }
// Generates new measurements since the last time this was called. private void ProcessMeasurements() { // Declare the variables use in this method. 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("Start time reset."); } // Keep generating measurements until // we catch up to the current time. while (timestamp < now) { sample = m_data.GetNextSample(); // If the sample is null, we've reached the end of the file. // Close and reopen it, resetting the data index and start time. if (sample == null) { m_data.Close(); m_data.Dispose(); m_data = WaveDataReader.FromFile(WavFileName); m_dataIndex = 0; m_startTime = timestamp; sample = m_data.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(ex); } } }
/// <summary> /// Attempts to close the file and release resources held by the adapter. /// </summary> protected override void AttemptDisconnection() { if (m_data != null) { m_data.Close(); m_data.Dispose(); } m_data = null; }
/// <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 (m_data != null) { m_data.Close(); m_data.Dispose(); } m_data = null; } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
/// <summary> /// Attempts to open the file to start getting wave data. /// </summary> protected override void AttemptConnection() { WaveFile fileInfo = WaveFile.Load(WavFileName, false); m_channels = fileInfo.Channels; m_sampleRate = fileInfo.SampleRate; m_numSamples = fileInfo.DataChunk.ChunkSize / fileInfo.BlockAlignment; m_audioLength = fileInfo.AudioLength; m_data = WaveDataReader.FromFile(WavFileName); m_dataIndex = 0; //if (file.Channels != OutputMeasurements.Length) // throw new ArgumentException(string.Format("The number of channels in the WAV file must match the number of output measurements. Channels: {0}, Measurements: {1}", file.Channels, OutputMeasurements.Length)); m_startTime = DateTime.UtcNow.Ticks; (new Thread(ProcessMeasurements)).Start(); }