Initial commit — WPF guitar note name tutor using FFT frequency detection
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user