/// <summary>
        ///     Initializes a new instance of the <see cref="GazeSelectionService" /> class.
        /// </summary>
        /// <param name="eventAggregator">Provides pub/sub events (obtained through DI).</param>
        public GazeSelectionService(IEventAggregator eventAggregator)
        {
            this.timedPoints     = new TimedPoints(Configuration.PointKeepAliveTimeSpan);
            this.averagingFilter = new AveragingLastNpointsWithinTimeSpanFilter(3, TimeSpan.FromMilliseconds(75));
            this.dataPerControl  = new ConcurrentDictionary <SelectableControl, ISelectableControlViewModel>();
            this.KnownWindows.Add(Application.Current.MainWindow);

            eventAggregator.GetEvent <Events.NewCoordinateEvent>().Subscribe(this.ProcessPoint);
            Application.Current.MainWindow.Closing +=
                (sender, args) => eventAggregator.GetEvent <Events.NewCoordinateEvent>().Unsubscribe(this.ProcessPoint);
        }
Exemple #2
0
        public void AdjustAndInterpolate(SpeechTypeSpecification speechTypeSpecification) // , double deltaTime, Boolean setUnvoicedPitch)
        {
            // Carry out median filtering to remove single errors
            List <double> correctedPitchValues = new List <double>();

            correctedPitchValues.Add(pitchPeriodSpecification.TimePitchPeriodTupleList[0].Item2);
            for (int ii = 1; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count - 1; ii++)
            {
                List <double> rawPitchValues = new List <double>()
                {
                    pitchPeriodSpecification.TimePitchPeriodTupleList[ii - 1].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[ii + 1].Item2
                };
                rawPitchValues.Sort();
                correctedPitchValues.Add(rawPitchValues[1]); // Median
            }
            // Finally adjust the end points (which are not touched by the initial median filtering)
            if (pitchPeriodSpecification.TimePitchPeriodTupleList.Count > 2)
            {
                List <double> rawPitchValues = new List <double>()
                {
                    pitchPeriodSpecification.TimePitchPeriodTupleList[0].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[1].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[2].Item2
                };
                rawPitchValues.Sort();
                correctedPitchValues[0] = rawPitchValues[1];
                int lastIndex = pitchPeriodSpecification.TimePitchPeriodTupleList.Count - 1;
                rawPitchValues = new List <double>()
                {
                    pitchPeriodSpecification.TimePitchPeriodTupleList[lastIndex].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[lastIndex - 1].Item2,
                    pitchPeriodSpecification.TimePitchPeriodTupleList[lastIndex - 2].Item2
                };
                rawPitchValues.Sort();
                correctedPitchValues.Add(rawPitchValues[1]);
            }
            for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count - 1; ii++)
            {
                pitchPeriodSpecification.TimePitchPeriodTupleList[ii] =
                    new Tuple <double, double>(pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item1,
                                               correctedPitchValues[ii]);
            }
            // Extend (extrapolate) the pitch period specification so that it runs to the end of the sound:
            double lastTime       = speechTypeSpecification.TimeSpeechTypeTupleList.Last().Item1;
            int    lastPitchIndex = pitchPeriodSpecification.TimePitchPeriodTupleList.Count - 1;
            double lastPitchTime  = pitchPeriodSpecification.TimePitchPeriodTupleList[lastPitchIndex].Item1;

            if (lastTime > lastPitchTime) // Should always be the case, but just to be sure ...
            {
                double lastPitch = pitchPeriodSpecification.TimePitchPeriodTupleList[lastPitchIndex].Item2;
                pitchPeriodSpecification.TimePitchPeriodTupleList.Add(new Tuple <double, double>(lastTime, lastPitch));
            }

            // Next, resample (upsample) the pitch period specification
            List <double> timeList  = new List <double>();
            List <double> pitchList = new List <double>();

            for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
            {
                double time  = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item1;
                double pitch = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item2;
                timeList.Add(time);
                pitchList.Add(pitch);
            }
            List <List <double> > timePitchList = new List <List <double> >()
            {
                timeList, pitchList
            };
            int numberOfPoints = (int)Math.Round(lastTime / deltaTime);
            List <List <double> > interpolatedTimePitchList = LinearInterpolation.Interpolate(timePitchList, numberOfPoints);

            pitchPeriodSpecification = new PitchPeriodSpecification();
            for (int ii = 0; ii < interpolatedTimePitchList[0].Count; ii++)
            {
                double time  = interpolatedTimePitchList[0][ii];
                double pitch = interpolatedTimePitchList[1][ii];
                pitchPeriodSpecification.TimePitchPeriodTupleList.Add(new Tuple <double, double>(time, pitch));
            }

            // Optionally (usually true) hard-set the (anyway rather arbitrary) pitch period for
            // unvoiced parts of the sound, by extending the pitch period from surrounding
            // voiced parts. This might cause occasional jumps (in the middle of an unvoiced
            // section), but those jumps are reoved in the subsequent lowpass filtering

            if (setUnvoicedPitch)
            {
                double     previousTime       = pitchPeriodSpecification.TimePitchPeriodTupleList[0].Item1;
                SpeechType previousSpeechType = speechTypeSpecification.GetSpeechType(previousTime);
                int        firstChangeIndex   = 0; // Will be changed later - must initialize here.
                int        lastChangeIndex    = -1;
                double     previousPitch;          // Must define here for use after the loop as well.
                for (int ii = 1; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
                {
                    double     time       = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item1;
                    SpeechType speechType = speechTypeSpecification.GetSpeechType(time);
                    if ((previousSpeechType == SpeechType.Voiced) && (speechType != SpeechType.Voiced))
                    {
                        firstChangeIndex = ii;
                        lastChangeIndex  = -1; // Not yet assigned. The value -1 is used for handling cases where the
                                               // sound remains not voiced until the end (see below).
                    }
                    else if ((previousSpeechType != SpeechType.Voiced) && (speechType == SpeechType.Voiced))
                    {
                        lastChangeIndex = ii - 1;
                        int middlexIndex = (firstChangeIndex + lastChangeIndex) / 2; // integer division
                                                                                     // assign the preceding pitch to the first half of the interval (unless firstChangeIndex = 0, meaning
                                                                                     // that the sound started with an unvoiced segment), and the  subsequent pitch to the second half of
                                                                                     // the interval:
                        double subsequentPitch = pitchPeriodSpecification.TimePitchPeriodTupleList[lastChangeIndex].Item2;
                        previousPitch = subsequentPitch;
                        if (firstChangeIndex > 0)
                        {
                            previousPitch = pitchPeriodSpecification.TimePitchPeriodTupleList[firstChangeIndex - 1].Item2;
                        }
                        for (int jj = firstChangeIndex; jj < middlexIndex; jj++)
                        {
                            time = pitchPeriodSpecification.TimePitchPeriodTupleList[jj].Item1;
                            pitchPeriodSpecification.TimePitchPeriodTupleList[jj] = new Tuple <double, double>(time, previousPitch);
                        }
                        for (int jj = middlexIndex; jj <= lastChangeIndex; jj++)
                        {
                            time = pitchPeriodSpecification.TimePitchPeriodTupleList[jj].Item1;
                            pitchPeriodSpecification.TimePitchPeriodTupleList[jj] = new Tuple <double, double>(time, subsequentPitch);
                        }
                    }
                    previousTime       = time;
                    previousSpeechType = speechType;
                }
                // At the end, if lastChangeIndex = -1, then the sound remained not voiced from the latest
                // change until the end. Thus:
                if ((lastChangeIndex == -1) && (firstChangeIndex > 0))
                {
                    previousPitch = pitchPeriodSpecification.TimePitchPeriodTupleList[firstChangeIndex - 1].Item2;
                    for (int jj = firstChangeIndex; jj < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; jj++)
                    {
                        double time = pitchPeriodSpecification.TimePitchPeriodTupleList[jj].Item1;
                        pitchPeriodSpecification.TimePitchPeriodTupleList[jj] = new Tuple <double, double>(time, previousPitch);
                    }
                }

                // Then, finally, low-pass filter the interpolated list, and assign the result:
                AveragingFilter averagingFilter = new AveragingFilter();
                List <double>   inputList       = new List <double>();
                for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
                {
                    double input = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item2;
                    inputList.Add(input);
                }
                List <double> outputList = averagingFilter.Run(inputList);
                for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
                {
                    double filteredPitch = outputList[ii];
                    double time          = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item1;
                    pitchPeriodSpecification.TimePitchPeriodTupleList[ii] = new Tuple <double, double>(time, filteredPitch);
                }

                /*     FirstOrderLowPassFilter lowPassFilter = new FirstOrderLowPassFilter();
                 *   lowPassFilter.SetAlpha(0.9); // To do: Parameterize.
                 *   for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
                 *   {
                 *       double input = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item2;
                 *       lowPassFilter.Step(input);
                 *   }
                 *   for (int ii = 0; ii < pitchPeriodSpecification.TimePitchPeriodTupleList.Count; ii++)
                 *   {
                 *       double filteredPitch = lowPassFilter.OutputList[ii];
                 *       double time = pitchPeriodSpecification.TimePitchPeriodTupleList[ii].Item1;
                 *       pitchPeriodSpecification.TimePitchPeriodTupleList[ii] = new Tuple<double, double>(time, filteredPitch);
                 *   }  */
            }
        }