//DTW without pruning
        public static double DTW_Distance(Sequence sequence1, Sequence sequence2)
        {
            int numberOfFrames_Sequence1 = sequence1.Frames.Count();
            int numberOfFrames_Sequence2 = sequence2.Frames.Count();

            double[,] DTW = new double[3, numberOfFrames_Sequence2 + 1];

            for (int i = 0; i <= numberOfFrames_Sequence2; i++)
            {
                DTW[0, i] = DTW[1, i] = DTW[2, i] = double.MaxValue;
            }
            DTW[0, 0] = 0;

            //Applying dimension compression to DTW array
            for (int i = 2; i <= numberOfFrames_Sequence1 + 1; i++)
            {
                for (int j = 1; j <= numberOfFrames_Sequence2; j++)
                {
                    double cost = distance(sequence1.Frames[i - 2], sequence2.Frames[j - 1]);
                    DTW[i % 3, j] = cost + Math.Min(DTW[i % 3, j - 1],          //horizontal, stretching
                                            Math.Min(DTW[(i + 1) % 3, j - 1],      //diagnoal, aligning
                                            DTW[(i + 2) % 3, j - 1]));              //far diagonal, shrinking
                }
            }

            return DTW[(numberOfFrames_Sequence1 + 1) % 3, numberOfFrames_Sequence2];
        }
        public MainForm()
        {
            InitializeComponent();

            // Configure the wavechart
            chart.SimpleMode = true;
            chart.AddWaveform("wave", Color.Green, 1, false);
            updateButtons();

            List<User> listOfUsers = TestcaseLoader.LoadTestcase1Testing("E:\\Complete SpeakerID Dataset\\TestingList.txt");

            foreach (User user in listOfUsers)
            {
                int counter = 0, counter1 = 0;
                foreach (AudioSignal signal in user.UserTemplates)
                {
                    AudioSignal signal_ = signal;
                    sequence = AudioOperations.ExtractFeatures(ref signal_);

                    ClosestMatch match = FileOperations.GetUserName(sequence, signal, true);
                    ClosestMatch match1 = FileOperations.GetUserName(sequence, signal, false);

                    Console.WriteLine(user.UserName + " : " + match.Username + ", " + match1.Username);
                    if (user.UserName == match.Username) counter++;
                    if (user.UserName == match1.Username) counter1++;
                }
                Console.WriteLine("====== " + counter + " out of " + user.UserTemplates.Count + " with pruning.");
                Console.WriteLine("====== " + counter1 + " out of " + user.UserTemplates.Count + " without pruning.");
            }

            Console.WriteLine("Done");
        }
 public static Sequence ExtractFeatures(double[] pSignal, int samplingRate)
 {
     Sequence sequence = new Sequence();
     double[,] mfcc = MATLABMFCCfunction(pSignal, samplingRate);
     int numOfFrames = mfcc.GetLength(1);
     int numOfCoefficients = mfcc.GetLength(0);
     Debug.Assert(numOfCoefficients == 13);
     sequence.Frames = new MFCCFrame[numOfFrames];
     for (int i = 0; i < numOfFrames; i++)
     {
         sequence.Frames[i] = new MFCCFrame();
         for (int j = 0; j < numOfCoefficients; j++)
         {
             sequence.Frames[i].Features[j] = mfcc[j, i];
         }
     }
     return sequence;
 }
        public static void SaveSequenceInDatabase(Sequence toBeSavedSequence, string username, AudioSignal signal)
        {
            //UPDATE
            //you should save the four values in the last row before the username, with the order (first, last, min, max) respectively

            FileStream SavingStream = new FileStream("savedSequences.txt", FileMode.Append);
            StreamWriter Saving = new StreamWriter(SavingStream);
            double TempFeature = 0f;
            StringBuilder FramesRow = new StringBuilder();

            int size = signal.data.Length;
            double maxElement = double.MinValue,
                    minElement = double.MaxValue,
                    firstElement, lastElement;
            
            for (int i = 0; i < 13; i++)
            {
                for (int j = 0; j < toBeSavedSequence.Frames.Length; j++)
                {
                    TempFeature = toBeSavedSequence.Frames[j].Features[i];
                    FramesRow.Append(TempFeature.ToString() + "|");
                }
                Saving.WriteLine(FramesRow);
                FramesRow.Clear(); //clear it to start a new row (VIP)
            }

            firstElement = signal.data[0];
            lastElement = signal.data[size - 1];

            for (int i = 0; i < size; i++)
            {
                maxElement = Math.Max(maxElement, signal.data[i]);
                minElement = Math.Min(minElement, signal.data[i]);
            }

            // UPDATE: On 26/12 @ 6:50 - Writing the 4 values into the file
            Saving.WriteLine(firstElement + " " + lastElement + " " + minElement + " " + maxElement);
            Saving.WriteLine("Username:" + username);
            Saving.Close();
        }
        //Identify button opens the file explorer to choose a pre existing audio file or recorded sound to be identified
        private void btnIdentify_Click(object sender, EventArgs e)
        {
            ClosestMatch User = new ClosestMatch();

            if (sequence != null && RecordRadio.Checked == false)
            {
                var watch = Stopwatch.StartNew();

                User = FileOperations.GetUserName(sequence, signal, WithPruningRadioBTN.Checked);

                watch.Stop();

                var elapsedMs = watch.ElapsedMilliseconds;

                Console.WriteLine("Elapsed Milliseconds = " + elapsedMs);

                MessageBox.Show("Username: "******"\nWith Minimum Difference: " + User.MinimumDistance.ToString());
            }
            else if (SavedRadio.Checked)
            {
                OpenFileDialog open = new OpenFileDialog();
                if (open.ShowDialog() == DialogResult.OK)
                {
                    isRecorded = false;
                    path = open.FileName;
                    //Open the selected audio file
                    signal = AudioOperations.OpenAudioFile(path);
                    sequence = AudioOperations.ExtractFeatures(ref signal);
                    
                    var watch = Stopwatch.StartNew();

                    User = FileOperations.GetUserName(sequence, signal, WithPruningRadioBTN.Checked);

                    watch.Stop();

                    var elapsedMs = watch.ElapsedMilliseconds;

                    Console.WriteLine("Elapsed Milliseconds = " + elapsedMs);

                    MessageBox.Show("Username: "******"\nWith Minimum Difference: " + User.MinimumDistance.ToString());
                }
            }
            //Dev: Omar Moataz Abdel-Wahed Attia
            else
            {
                if (isRecorded)
                {
                    InitializeDecoder();        //Initializes a decoder to get the value of the recorded stream.
                    AudioSignal signal = new AudioSignal(); //Signal sent to Feature extraction function.
                    signal.data = new double[this.decoder.frames];  //Reserve space for double array that will be filled later.
                    signal.sampleRate = this.decoder.GetTempSignal().SampleRate;
                    //TempSignal has the double array I need to extract features, Check function Decoder::getWholeSignal() for more explanation.
                    this.decoder.GetTempSignal().CopyTo(signal.data);
                    //Copies the values of the signal to an object "signal" of type AudioSignal which is sent to feature extraction.
                    sequence = AudioOperations.ExtractFeatures(ref signal);
                    //Get name of user that has the closest match.
                    var watch = Stopwatch.StartNew();

                    User = FileOperations.GetUserName(sequence, signal, WithPruningRadioBTN.Checked);

                    watch.Stop();

                    var elapsedMs = watch.ElapsedMilliseconds;

                    Console.WriteLine("Elapsed Milliseconds = " + elapsedMs);

                    MessageBox.Show("Username: "******"\nWith Minimum Difference: " + User.MinimumDistance.ToString());
                }
                else
                {
                    MessageBox.Show("Please record your voice first!"); //In case the user tries to identify without recording any sound.
                }
            }

            sequence = null;
            updateButtons();
        }
        public void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();
            if (open.ShowDialog() == DialogResult.OK)
            {
                isRecorded = false;
                path = open.FileName;
                //Open the selected audio file
                signal = AudioOperations.OpenAudioFile(path);
                sequence = AudioOperations.ExtractFeatures(ref signal);

                updateButtons();
            }
        }
        private void saveFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (this.encoder != null)
            {
                Stream fileStream = saveFileDialog1.OpenFile();
                this.encoder.Save(fileStream);

                path = saveFileDialog1.FileName;
                signal = AudioOperations.OpenAudioFile(path);
                sequence = AudioOperations.ExtractFeatures(ref signal);

            }
        }
        //======================================================
        /* 
        Dev: Omar Moataz Abdel-Wahed Attia
        Last Edit: 12/8/2015
        To understand the code in function GetUserName, you need to understand the file structure
        I'm  looping over.
        The file will contain 13 lines which represent a Frame (0-12) (Each Column is a frame)
        on the 14th line, it will contain the name of the person that's tied to the previous sequence.
        */
        //======================================================
        public static ClosestMatch GetUserName(Sequence sequence, AudioSignal signal, bool pruned) 
        {
            ClosestMatch User = new ClosestMatch();
            //Opening the file.
            using (StreamReader Reader = new StreamReader("savedSequences.txt"))
            {
                //Initializing a new sequence.
                Sequence ToBeCompared = new Sequence();
                //This line string contains every line I go through in the file
                string Line;
                //Holds the value of the current frame
                int Index = 0;
                bool flag = true, Updated = false;
                //Variables used in lowerbounding
                double FirstElement = 0, LastElement = 0, MaxElement = 0, MinElement = 0; 
                while ((Line = Reader.ReadLine()) != null)
                {
                    if (Index == 13)
                    {
                        double TrueDistance;
                        string[] Temp = Line.Split(' ');       /*Just a string array that holds the values I'll take into FirstElement, 
                        LastElement, MinElement and MaxElement.*/
                        FirstElement = double.Parse(Temp[0]);
                        LastElement = double.Parse(Temp[1]);
                        MinElement = double.Parse(Temp[2]);
                        MaxElement = double.Parse(Temp[3]);
                        
                        if (pruned)
                        {
                            double LowerBoundDistance = DynamicTimeWarpingOperations.LowerBound_Kim(signal, FirstElement, LastElement, MinElement, MaxElement);
                            if (LowerBoundDistance > User.MinimumDistance) goto skip;
                            TrueDistance = DynamicTimeWarpingOperations.Pruned_DTW_Distance(ToBeCompared, sequence);
                        }
                        else
                        {
                            TrueDistance = DynamicTimeWarpingOperations.DTW_Distance(ToBeCompared, sequence);
                        }
                        //Here I compare the two Distances together to see if I need to update the minimum or not.
                        if (TrueDistance < User.MinimumDistance)
                        {
                            //Here I update the minimum distance between two values.
                            User.MinimumDistance = TrueDistance;
                            Updated = true;
                        }
                    skip:
                        //This is a reinitialization just to clear out old values from the previous iteration
                        flag = true;
                        ToBeCompared = new Sequence();
                    }
                    else if(Index == 14)
                    {
                        if (Updated)
                        {
                            //I update the name of the person to line because on the 13th index line, it'll have the name of the person.
                            User.Username = Line.Substring(9, Line.Length - 9);
                        }
                        Updated = false; //resetting the update value.
                        Index = -1;
                        //So, it goes back to 0 when the loop continues.
                    }
                    else
                    {
                        string[] ExtractedStringsFromLine = Line.Split('|');

                        if (flag == true)
                        {
                            ToBeCompared.Frames = new MFCCFrame[ExtractedStringsFromLine.Length - 1];
                        }
                        //Here I split all the values from every line to an array of Strings.
                        for (int i = 0; i < ExtractedStringsFromLine.Length - 1; i++)
                        {
                            if (flag == true)
                            {
                                ToBeCompared.Frames[i] = new MFCCFrame();
                            }
                            ToBeCompared.Frames[i].Features[Index] = double.Parse(ExtractedStringsFromLine[i]);
                        }
                        flag = false;
                    }
                    //I increment the index of the 2D array for the next iteration through the file.
                    ++Index;
                }
            }
            //I return type ClosestMatch.
            return User;
        }
 public AddUser(Sequence sequence_, AudioSignal signal_)
 {
     sequence = sequence_;
     signal = signal_;
     InitializeComponent();
 }