public bool Read(ArraySegment <float> samples) { // Start the timer when the first sample is read. All subsequent timing will be based off this. if (!_timer.IsRunning) { _timer.Reset(); _timer.Start(); } // We always read the amount of requested data, update the count of total data read now _totalSamplesRead += samples.Count; // If the buffer is too small slighty increase the count of samples read (by 0.1ms) Desync compensation will think it is ahead of // where it should be and will slow down playback, which will cause the buffer to grow. if (_pipeline.BufferCount < 1) { _totalSamplesRead += WaveFormat.SampleRate / 10000; } // Calculate how out of sync playback is (based on actual samples read vs time passed) _desync.Update(IdealPlaybackPosition, PlaybackPosition); // If playback rate is too fast, slow down immediately (to prevent exhausting the buffer). If playback speed is too slow, ramp up over the next few frames. var corrected = _desync.CorrectedPlaybackSpeed; PlaybackRate = corrected < PlaybackRate ? corrected : Mathf.LerpUnclamped(PlaybackRate, _desync.CorrectedPlaybackSpeed, 0.25f); // Skip audio if necessary to resync the audio stream int skippedSamples; int skippedMilliseconds; var complete = Skip(_desync.DesyncMilliseconds, out skippedSamples, out skippedMilliseconds); if (skippedSamples > 0) { _totalSamplesRead += skippedSamples; _desync.Skip(skippedMilliseconds); } // If skipping completed the session return silence if (complete) { // ReSharper disable once AssignNullToNotNullAttribute Array.Clear(samples.Array, samples.Offset, samples.Count); return(true); } // Read from upstream return(_upstream.Read(samples)); }
public bool Read(ArraySegment <float> samples) { // If synchroniser is not enabled just pass the request upstream with no playback rate adjustment if (!_enabled) { PlaybackRate = 1; return(_upstream.Read(samples)); } // Start the timer when the first sample is read. All subsequent timing will be based off this. if (!_timer.IsRunning) { _timer.Reset(); _timer.Start(); } // We always read the amount of requested data, update the count of total data read now _totalSamplesRead += samples.Count; // Calculate how out of sync playback is (based on actual samples read vs time passed) _desync.Update(IdealPlaybackPosition, PlaybackPosition); // If playback rate is too fast, slow down immediately (to prevent exhausting the buffer). If playback speed is too slow, ramp up over the next few frames. var corrected = _desync.CorrectedPlaybackSpeed; PlaybackRate = corrected < PlaybackRate ? corrected : Mathf.LerpUnclamped(PlaybackRate, _desync.CorrectedPlaybackSpeed, 0.25f); // Skip audio if necessary to resync the audio stream int skippedSamples; int skippedMilliseconds; var complete = Skip(_desync.DesyncMilliseconds, out skippedSamples, out skippedMilliseconds); if (skippedSamples > 0) { _totalSamplesRead += skippedSamples; _desync.Skip(skippedMilliseconds); } // If skipping completed the session return silence if (complete) { // ReSharper disable once AssignNullToNotNullAttribute Array.Clear(samples.Array, samples.Offset, samples.Count); return(true); } // Read from upstream return(_upstream.Read(samples)); }
public void OnAudioFilterRead(float[] data, int channels) { //If there is no session, clear filter and early exit var maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } _sessionLock.EnterUpgradeableReadLock(); try { //Check if there is no session again, this time protected by a lock maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } //Detect if the session has changed since the last call to this method, if so reset if (!maybeSession.Value.Context.Equals(_lastPlayedSessionContext)) { _lastPlayedSessionContext = maybeSession.Value.Context; ApplyReset(); } //Calculate the difference between where we should be and where we are (in samples) var session = maybeSession.Value; _desync.Update(IdealPlaybackPosition, PlaybackPosition); //If necessary skip samples to bring us back in sync int deltaDesync, deltaSamples; var complete = Skip(session, _desync.DesyncMilliseconds, out deltaSamples, out deltaDesync); Interlocked.Add(ref _totalSamplesRead, deltaSamples); _desync.Skip(deltaDesync); //If the session wasn't completed by the skip, keep playing if (!complete) { int samples; float arv; complete = Filter(session, data, channels, _temp, _diagnosticOutput, out arv, out samples, MultiplyBySource); _arv = arv; Interlocked.Add(ref _totalSamplesRead, samples); } //Clean up now that this session is complete if (complete) { Log.Debug("Finished playback of speech session. id={0}", session.Context.Id); //Clear the session _sessionLock.EnterWriteLock(); try { Session = null; } finally { _sessionLock.ExitWriteLock(); } //Reset the state ApplyReset(); //Discard the diagnostic recorder if necessary if (_diagnosticOutput != null) { _diagnosticOutput.Dispose(); _diagnosticOutput = null; } } } finally { _sessionLock.ExitUpgradeableReadLock(); } }