2016-03-29 8 views
0

Ich schreibe eine Windows Forms-Anwendung mit C#, die Frequenzen von Benutzereingaben in das Mikrofon des Geräts erhält, möchte Frequenzen in bestimmten Intervallen berechnen,Inkrementieren eines Zählers in einem Timer (System.Windows.Forms.Timer) C#

ich habe gehofft, um dies zu erreichen, indem die zuletzt berechnete Frequenz zu einer globalen variablen zugewiesen und wenn das timer.tick Ereignis wird den Wert auf einen Index eines Arrays (userFrequencies) angehoben zuweisen,

Unterhalb der Code :

private void getFreqTimer_Tick(object sender, EventArgs e) 
    { 
     if (cIndex < userFrequencies.Length) 
     { 
      userFrequencies[cIndex] = currentFreq; 
      cIndex++; // Also tried ++cIndex; 
     } 
    } 

T Das Problem, das ich habe, ist, dass cIndex manchmal um 1 und manchmal um 2 erhöht wird, also dem Array keine Werte richtig zuweisst,

Ich weiß, dass der Timer um ca. 15ms ausgeschaltet sein kann und es viel los ist im Hintergrund der Form - könnte dies ein Faktor sein, der die Ereignisse beim Kompilieren unterschiedlich feuern lässt?

Jede Hilfe würde sehr geschätzt werden!

EDIT: Zusätzlicher Code wie gewünscht:

using NAudio.Dsp; 
using NAudio.Wave; 
using System; 
using System.Data.SqlClient; 
using System.Diagnostics; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Runtime.InteropServices; 
using System.Threading; 
using System.Windows.Forms; 
using System.Windows.Forms.DataVisualization.Charting; 

namespace VocalWarmUpFYP 
{ 
    public partial class Form1 : Form 
    { 
     private WaveIn waveIn; 
     public WaveFileWriter waveFile = null; 

    string timeHour = (DateTime.Now.Hour).ToString(); 
    string timeSecond = (DateTime.Now.Second).ToString(); 
    string timeMinute = (DateTime.Now.Minute).ToString(); 
    string timeDay = (DateTime.Now.Day).ToString(); 
    string chartImagePath; 
    int callStopBtnClick; 
    int timeForExercise; 
    int timerSecs; 

    private static int fftLength = 2048; 
    private static int sampleRate = 44100; 
    private SampleAggregator sampleAggregator = new SampleAggregator(fftLength); 

    bool CompFFT = false; 
    int userId = HelpData.UserID; 

    double[] userFrequencies = new double[20]; 
    double[] desiredFrequencies; 
    double currentFreq = 0; 
    public int cIndex = 0; 

    public Form1() 
    { 

     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     StartBtn.BackColor = HelpData.formBackColour; 
     StopBtn.BackColor = HelpData.formBackColour; 
     BackBtn.BackColor = HelpData.formBackColour; 
     BackColor = HelpData.formBackColour; 
     timer1.Tick += timer1_Tick; 
     getFreqTimer.Tick += getFreqTimer_Tick; 
     raiseStopTimer.Tick += raiseStopTimer_Tick; 
     chart1.Series.Clear(); 
     chart1.BackColor = HelpData.formBackColour; 

     switch (HelpData.selectedWarmUp) 
     { 
      case 1: 
       warmupImg.Image = Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Visual Studio 2015\Projects\VocalWarmUpFYP\Images\BumbleBee.png"); 
       getFreqTimer.Interval = 750; 
       timeForExercise = 13; 
       break; 
      case 2: 
       warmupImg.Image = Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Visual Studio 2015\Projects\VocalWarmUpFYP\Images\Lips.png"); 
       getFreqTimer.Interval = 450; 
       timeForExercise = 7; 
       break; 
      case 3: 
       warmupImg.Image = Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Visual Studio 2015\Projects\VocalWarmUpFYP\Images\Siren.png"); 
       getFreqTimer.Interval = 700; 
       timeForExercise = 12; 
       break; 
      case 4: 
       warmupImg.Image = Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Visual Studio 2015\Projects\VocalWarmUpFYP\Images\Mum.png"); 
       getFreqTimer.Interval = 800; 
       timeForExercise = 14; 
       break; 
      case 5: 
       warmupImg.Image = Image.FromFile(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + @"\Visual Studio 2015\Projects\VocalWarmUpFYP\Images\HummingBird.png"); 
       getFreqTimer.Interval = 450; 
       timeForExercise = 7; 
       break; 
     } 


     if (chart1.Series.Count == 0) // Check to make sure Series 0 exists 
     { 
      var series = chart1.Series.Add("Frequency"); // If it doesn't exist then create it. 
      series.ChartType = SeriesChartType.FastLine; 
      series.ChartArea = "ChartArea1"; 
      series.IsVisibleInLegend = false; 
      series.LabelBackColor = HelpData.formBackColour; 
      series.Color = Color.White; 
      series.BorderWidth = 5; 
     } 

     chart1.ChartAreas["ChartArea1"].BackColor = HelpData.formBackColour; 
     chart1.ChartAreas["ChartArea1"].AxisX.MinorGrid.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisX.MajorTickMark.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisX.MinorTickMark.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisX.Interval = 0; 
     chart1.ChartAreas["ChartArea1"].AxisY.LabelStyle.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisY.MajorTickMark.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisY.MinorTickMark.Enabled = false; 
     chart1.ChartAreas["ChartArea1"].AxisX.LineWidth = 0; 
     chart1.ChartAreas["ChartArea1"].AxisY.LineWidth = 0; 

     chart1.Visible = false; 
    } 

    private void StopBtn_Click(object sender, EventArgs e) 
    { 
     timer1.Stop(); 
     getFreqTimer.Stop(); 
     raiseStopTimer.Stop(); 
     string currentTimeStamp = timeDay + timeHour + timeMinute + timeSecond; 
     waveIn.StopRecording(); 
     waveFile.Dispose(); 
     waveIn.Dispose(); 

     StartBtn.Visible = true; 
     StopBtn.Visible = false; 

     chart1.SaveImage(@"C:\Temp\TestChart" + currentTimeStamp, ChartImageFormat.Png); 
     chartImagePath = @"C:\Temp\TestChart" + currentTimeStamp + ".Png"; 

     NameRecording NameRecording = new NameRecording(); 
     NameRecording.Tag = this; 
     NameRecording.Show(this); 

     for (int i = 0; i < userFrequencies.Length; i++) 
     { 
      Debug.WriteLine("User frequency at index " + i + ": " + userFrequencies[i]); 
     } 

    /*  
     var con = new SqlConnection("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=C:\\USERS\\OWNER\\DOCUMENTS\\VISUAL STUDIO 2015\\PROJECTS\\VOCALWARMUPFYP\\VOCALWARMUPFYP\\NEWDATABASE.MDF;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"); 

     using (con) 
     { 

      string oString = "SELECT COUNT (*) FROM VocalDetails"; 
      string oString2 = "INSERT INTO VocalDetails (VocalID, FreqImg, Name, Accuracy, Id, TimeStamp, RecordingRef) VALUES (@vocalid, @freqimg, @name, @accuracy, @userid, @timestamp, @filereference)"; 
      con.Open(); 

      SqlCommand oCmd = new SqlCommand(oString, con); 

      int newVocalID = (Convert.ToInt32(oCmd.ExecuteScalar()) + 1); 
      string recordingName = HelpData.userRecordingName; 
      string timeStamp = DateTime.Now.ToShortDateString(); 
      string freqImg = chartImagePath; 
      SqlCommand oCmd2 = new SqlCommand(oString2, con); 

      oCmd2.Parameters.AddWithValue("@vocalid", newVocalID); 
      oCmd2.Parameters.AddWithValue("@freqimg", freqImg); 
      oCmd2.Parameters.AddWithValue("@name", recordingName); 
      oCmd2.Parameters.AddWithValue("@accuracy", Accuracy); 
      oCmd2.Parameters.AddWithValue("@userid", userId); 
      oCmd2.Parameters.AddWithValue("@timestamp", timeStamp); 
      oCmd2.Parameters.AddWithValue("@filereference", fileReference); 

     } 
     con.Close(); 
     con.Dispose(); 
*/ 
     } 


    private void StartBtn_Click(object sender, EventArgs e) 
    { 
     StartBtn.Visible = false; 
     StopBtn.Visible = true; 
     warmupImg.Visible = false; 
     chart1.Visible = true; 
     string currentTimeStamp = timeDay + timeHour + timeMinute + timeSecond; 
     string fileToProcess = @"C:\Temp\Test" + currentTimeStamp + ".wav"; 

     sampleAggregator.PerformFFT = true; 
     sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated); 
     BufferedWaveProvider wavprov = new BufferedWaveProvider(new WaveFormat(sampleRate, 2)); 

     waveIn = new WaveIn(); 
     waveIn.WaveFormat = new WaveFormat(44100, WaveIn.GetCapabilities(0).Channels); 
     waveIn.DeviceNumber = 0; 
     waveFile = new WaveFileWriter(fileToProcess, waveIn.WaveFormat); 
     timerSecs = DateTime.Now.AddSeconds(timeForExercise).Second; 

     waveIn.DataAvailable += OnDataAvailable; 
     waveIn.StartRecording(); 

     timer1.Start(); 
     getFreqTimer.Start(); 
     raiseStopTimer.Start(); 
    } 

    void OnDataAvailable(object sender, WaveInEventArgs e) 
    { 
     if (InvokeRequired) 
     { 
      BeginInvoke(new EventHandler<WaveInEventArgs>(OnDataAvailable), sender, e); 
     } 
     else 
     { 
      byte[] buffer = e.Buffer; 
      int bytesRecorded = e.BytesRecorded; 
      int bufferIncrement = waveIn.WaveFormat.BlockAlign; 

      for (int index = 0; index < bytesRecorded; index += bufferIncrement) 
      { 
       float sample32 = BitConverter.ToInt16(buffer, index); 
       sampleAggregator.Add(sample32); 
      } 

      if (waveFile != null) 
      { 
       waveFile.Write(e.Buffer, 0, e.BytesRecorded); 
       waveFile.Flush(); 
      } 
     } 
    } 

    class SampleAggregator 
    { 
     // FFT 
     public event EventHandler<FftEventArgs> FftCalculated; 
     public bool PerformFFT { get; set; } 

     private Complex[] fftBuffer; 
     private FftEventArgs fftArgs; 
     private int fftPos; 
     private int fftLength; 
     private int m; 

     public SampleAggregator(int fftLength) 
     { 
      if (!IsPowerOfTwo(fftLength)) 
      { 
       throw new ArgumentException("FFT Length must be a power of two"); 
      } 
      m = (int)Math.Log(fftLength, 2.0); 
      this.fftLength = fftLength; 
      fftBuffer = new Complex[fftLength]; 
      fftArgs = new FftEventArgs(fftBuffer); 
     } 

     bool IsPowerOfTwo(int x) 
     { 
      return (x & (x - 1)) == 0; 
     } 

     public void Add(float value) 
     { 
      if (PerformFFT && FftCalculated != null) 
      { 
       fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HannWindow(fftPos, fftLength)); 
       fftBuffer[fftPos].Y = 0; // This is always zero with audio. 
       fftPos++; 
       if (fftPos >= fftLength) 
       { 
        fftPos = 0; 
        FastFourierTransform.FFT(true, m, fftBuffer); 
        FftCalculated(this, fftArgs); 
       } 
      } 
     } 
    } 

    public class FftEventArgs : EventArgs 
    { 
     [DebuggerStepThrough] 
     public FftEventArgs(Complex[] result) 
     { 
      this.Result = result; 
     } 
     public Complex[] Result { get; private set; } 
    } 

    private void FftCalculated(object sender, FftEventArgs e) 
    { 
     double[] Magnitude = new double[(e.Result.Length/2) - 1]; 
     double Freq; 
     double Power; 
     int Index = 0; 

     if (CompFFT == true) 
     { 
      for (int i = 1; i < (e.Result.Length/2) - 1; i++) 
      { 
       if (chart1.Series.Count <= fftLength) //<<======Now it wont give exception** 
       { 
        if (InvokeRequired == false) //<<====== Invoke method used to allow access to the chart control from custom event** 
        { 

         this.Invoke(new MethodInvoker(delegate 
         { 

          var series = 0; 
          double Max_Magnitude = 0; 
          double Max_Index = -1; 

          for (int j = 0; j < (e.Result.Length/2) - 1; j++) 
          { 

           e.Result[j].Y = 0; 
           Power = (e.Result[j].X * e.Result[j].X) + (e.Result[j].Y * e.Result[j].Y); 
           Magnitude[j] = Math.Sqrt(Power); 
          } 

          for (int j = 0; j < Magnitude.Length; j++) 
          { 

           if (Magnitude[j] > Max_Magnitude && j != 0 && Magnitude[j] > 1) 
           { 
            Index = j; 
            Max_Magnitude = Magnitude[Index]; 
            Max_Index = Index; 
           } 
          } 

          Freq = ((Max_Index * sampleRate)/fftLength); 

          if (Freq > 0) 
          { 
           currentFreq = Freq; 
          } 

          chart1.DataSource = Freq; 
          chart1.Series[series].Points.Add(Freq); 

          CompFFT = false; 
         })); 
         return; 
        } 
       } 

       chart1.Update(); 
      } 
     } 
    } 

    private void timer1_Tick(object sender, EventArgs e) 
    { 
     CompFFT = true; 
    } 

    private void BackBtn_Click(object sender, EventArgs e) 
    { 
     SelectWarmUp SelectWarmUp = new SelectWarmUp(); 
     SelectWarmUp.Tag = this; 
     SelectWarmUp.Show(this); 
     Hide(); 
    } 

    private void getFreqTimer_Tick(object sender, EventArgs e) 
    { 
     if (cIndex < userFrequencies.Length) 
     { 
      userFrequencies[cIndex] = currentFreq; 
      cIndex++; 
     } 
     Debug.WriteLine("cIndex: " + cIndex); 
    } 

    private void raiseStopTimer_Tick(object sender, EventArgs e) 
    { 
     callStopBtnClick = DateTime.Now.Second; 

     if (callStopBtnClick == timerSecs + 2) 
     { 
      StopBtn.PerformClick(); 
     } 
    } 
} 
} 

Das Intervall für timer1: 25ms Das Intervall für getFreqTimer: 750ms

Die Anwendung für 15 Sekunden vor dem StopBtn_Click Ereignisse ausgeführt wird, wird automatisch aufgerufen - dies sollte maximal 20 Werte

Ausgabe von @Eminem Vorschlag geben:

cIndex: 1 
x: 1 
cIndex: 2 
x: 2 
cIndex: 3 
x: 3 
cIndex: 4 
x: 4 
cIndex: 5 
x: 5 
cIndex: 6 
x: 6 
cIndex: 7 
x: 7 
cIndex: 8 
x: 8 
cIndex: 9 
x: 9 
cIndex: 10 
x: 10 
cIndex: 11 
x: 11 
cIndex: 12 
x: 12 
cIndex: 13 
x: 13 
cIndex: 14 
x: 14 
cIndex: 15 
x: 15 
cIndex: 16 
x: 16 
cIndex: 17 
x: 17 
cIndex: 18 
x: 18 
cIndex: 19 
x: 19 
cIndex: 20 
x: 20 
cIndex: 20 
x: 21 
cIndex: 20 
x: 22 
cIndex: 20 
x: 23 
cIndex: 20 
x: 24 
cIndex: 20 
x: 25 
cIndex: 20 
x: 26 
cIndex: 20 
x: 27 
cIndex: 20 
x: 28 
cIndex: 20 
x: 29 
cIndex: 20 
x: 30 
cIndex: 20 
x: 31 
cIndex: 20 
x: 32 
cIndex: 20 
x: 33 
cIndex: 20 
x: 34 
cIndex: 20 
x: 35 
cIndex: 20 
x: 36 
cIndex: 20 
x: 37 
cIndex: 20 
x: 38 

User frequency at index 0: 172.265625 
User frequency at index 1: 172.265625 
User frequency at index 2: 279.931640625 
User frequency at index 3: 279.931640625 
User frequency at index 4: 193.798828125 
User frequency at index 5: 193.798828125 
User frequency at index 6: 279.931640625 
User frequency at index 7: 279.931640625 
User frequency at index 8: 387.59765625 
User frequency at index 9: 387.59765625 
User frequency at index 10: 236.865234375 
User frequency at index 11: 236.865234375 
User frequency at index 12: 1098.193359375 
User frequency at index 13: 1098.193359375 
User frequency at index 14: 559.86328125 
User frequency at index 15: 559.86328125 
User frequency at index 16: 258.3984375 
User frequency at index 17: 258.3984375 
User frequency at index 18: 279.931640625 
User frequency at index 19: 279.931640625 
+0

Was ist das Intervall, das Sie verwenden? –

+0

@GlenThomas Es hängt davon ab, welche Taste verwendet wurde, um auf das Formular zuzugreifen (es gibt 5 Optionen), aber die, mit der ich getestet habe, ist 750 – JBrian30221

+0

Also in Ihrem Array haben Sie manchmal Null/Null-Werte bei bestimmten Indizes? –

Antwort

1

Ich tippte eine ähnliche App aus. Das Problem besteht in den folgenden 2 Zeilen:

getFreqTimer.Tick += getFreqTimer_Tick; 
raiseStopTimer.Tick += raiseStopTimer_Tick; 

Die Ereignisse werden zweimal ausgelöst. Entfernen Sie daher diese beiden Zeilen und behalten Sie nur die über den Eigenschafteninspektor hinzugefügten (überprüfen Sie, dass es nur in Ihrer Datei .Designer.cs)

+0

Ich habe versucht, die Werte einer Liste wie vorgeschlagen zuzuweisen, aber ich bekomme 36 Werte anstelle der erwarteten 20 – JBrian30221

+0

würde ich zustimmen. Die Funktion getFreqTimer_Tick sollte nur 20-mal aufgerufen werden, wenn das Intervall auf 750 ms festgelegt und auf 15 Sekunden eingestellt ist. Tun Sie uns einen Gefallen, fügen Sie eine weitere Zählvariable hinzu, die die Häufigkeit zählt, mit der die Funktion getFreqTimer_Tick eingegeben wird. Siehe angepasste Antwort – Eminem

+0

Ich änderte den Code wie vorgeschlagen, aktualisierte meine Frage mit der Ausgabe – JBrian30221