157 lines
3.9 KiB
C#
157 lines
3.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.Windows;
|
|
using System.Collections.Generic;
|
|
using System.Windows.Threading;
|
|
using FrequencyDetection;
|
|
using SoundCapture;
|
|
|
|
namespace GuitarNoteNameTutor
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for Window1.xaml
|
|
/// </summary>
|
|
public partial class Window
|
|
{
|
|
private bool IsListenning { get; set; }
|
|
|
|
private static readonly Dictionary<int, string> HalfNoteSharpNames =
|
|
new Dictionary<int, string>
|
|
{
|
|
{0, "A"},
|
|
{1, "A\u266F"},
|
|
{2, "B"},
|
|
{3, "C"},
|
|
{4, "C\u266F"},
|
|
{5, "D"},
|
|
{6, "D\u266F"},
|
|
{7, "E"},
|
|
{8, "F"},
|
|
{9, "F\u266F"},
|
|
{10, "G"},
|
|
{11, "G\u266F"},
|
|
};
|
|
|
|
private static readonly Dictionary<int, string> HalfNoteFlatNames =
|
|
new Dictionary<int, string>
|
|
{
|
|
{0, "A"},
|
|
{1, "B\u266D"},
|
|
{2, "B"},
|
|
{3, "C"},
|
|
{4, "D\u266D"},
|
|
{5, "D"},
|
|
{6, "E\u266D"},
|
|
{7, "E"},
|
|
{8, "F"},
|
|
{9, "G\u266D"},
|
|
{10, "G"},
|
|
{11, "A\u266D"},
|
|
};
|
|
|
|
static readonly double ToneStep = Math.Pow(2, 1.0 / 12);
|
|
|
|
private readonly Random _rand = new Random();
|
|
|
|
FrequencyInfoSource _frequencyInfoSource;
|
|
|
|
public Window()
|
|
{
|
|
InitializeComponent();
|
|
|
|
//timer = new DispatcherTimer {Interval = TimeSpan.FromSeconds(2)};
|
|
//timer.Tick += timer_Tick;
|
|
//timer.Start();
|
|
}
|
|
|
|
private void StopListenning()
|
|
{
|
|
IsListenning = false;
|
|
_frequencyInfoSource.FrequencyDetected -= FrequencyInfoSource_FrequencyDetected;
|
|
_frequencyInfoSource.Stop();
|
|
_frequencyInfoSource = null;
|
|
}
|
|
|
|
private void StartListenning(SoundCaptureDevice device)
|
|
{
|
|
IsListenning = true;
|
|
_frequencyInfoSource = new SoundFrequencyInfoSource(device);
|
|
_frequencyInfoSource.FrequencyDetected += FrequencyInfoSource_FrequencyDetected;
|
|
_frequencyInfoSource.Listen();
|
|
}
|
|
|
|
void FrequencyInfoSource_FrequencyDetected(object sender, FrequencyDetectedEventArgs e)
|
|
{
|
|
if (!Dispatcher.CheckAccess())
|
|
{
|
|
Dispatcher.BeginInvoke(
|
|
new EventHandler<FrequencyDetectedEventArgs>(FrequencyInfoSource_FrequencyDetected), sender, e);
|
|
}
|
|
else
|
|
{
|
|
if (e.Frequency <= 0)
|
|
{
|
|
unknownFreqLabel.Visibility = Visibility.Visible;
|
|
frequencyLabel.Content = "?";
|
|
return;
|
|
}
|
|
unknownFreqLabel.Visibility = Visibility.Hidden;
|
|
|
|
NoteFrequency closestNote = FindClosestNote(e.Frequency);
|
|
label.Content = HalfNoteSharpNames[closestNote.HalfStepsFromA];
|
|
frequencyLabel.Content = string.Format("{0:0.0}Hz", e.Frequency);
|
|
}
|
|
}
|
|
|
|
private class NoteFrequency
|
|
{
|
|
public int HalfStepsFromA;
|
|
public double Frequency;
|
|
}
|
|
|
|
private static NoteFrequency FindClosestNote(double frequency)
|
|
{
|
|
const double aFrequency = 440.0;
|
|
const int toneIndexOffsetToPositives = 120;
|
|
|
|
int toneIndex = (int)Math.Round(Math.Log(frequency / aFrequency, ToneStep));
|
|
int toneHalfStep = (toneIndexOffsetToPositives + toneIndex) % HalfNoteSharpNames.Count;
|
|
Debug.WriteLine(string.Format("{0}, {1}", toneIndexOffsetToPositives + toneIndex, (toneIndexOffsetToPositives + toneIndex) / 12 - 7));
|
|
NoteFrequency noteFrequency = new NoteFrequency
|
|
{
|
|
HalfStepsFromA = toneHalfStep,
|
|
Frequency = Math.Pow(ToneStep, toneIndex)*aFrequency,
|
|
};
|
|
|
|
return noteFrequency;
|
|
}
|
|
|
|
private DispatcherTimer timer;
|
|
|
|
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
|
{
|
|
if (IsListenning)
|
|
{
|
|
StopListenning();
|
|
}
|
|
}
|
|
|
|
private void startButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
SoundCaptureDevice device = null;
|
|
SelectDevice form = new SelectDevice {Owner = this};
|
|
bool? dialogResponse = form.ShowDialog();
|
|
if (dialogResponse.HasValue && dialogResponse == true)
|
|
{
|
|
device = form.SelectedDevice;
|
|
}
|
|
|
|
if (device != null)
|
|
{
|
|
label.Content = string.Empty;
|
|
StartListenning(device);
|
|
}
|
|
}
|
|
}
|
|
}
|