mirror of
https://github.com/Gigaslav/HL2Overcharged.git
synced 2026-09-15 20:12:37 +03:00
420 lines
17 KiB
C#
420 lines
17 KiB
C#
/*===============================================================================================
|
|
Pitch detection example.
|
|
Copyright (c), Firelight Technologies Pty, Ltd 2004-2016.
|
|
|
|
This example combines recording with spectrum analysis to determine the pitch of the sound
|
|
being recorded.
|
|
===============================================================================================*/
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.Windows.Forms;
|
|
using System.Data;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace pitchdetection
|
|
{
|
|
public class PitchDetection : System.Windows.Forms.Form
|
|
{
|
|
private string[] note =
|
|
{
|
|
"C 0", "C#0", "D 0", "D#0", "E 0", "F 0", "F#0", "G 0", "G#0", "A 0", "A#0", "B 0",
|
|
"C 1", "C#1", "D 1", "D#1", "E 1", "F 1", "F#1", "G 1", "G#1", "A 1", "A#1", "B 1",
|
|
"C 2", "C#2", "D 2", "D#2", "E 2", "F 2", "F#2", "G 2", "G#2", "A 2", "A#2", "B 2",
|
|
"C 3", "C#3", "D 3", "D#3", "E 3", "F 3", "F#3", "G 3", "G#3", "A 3", "A#3", "B 3",
|
|
"C 4", "C#4", "D 4", "D#4", "E 4", "F 4", "F#4", "G 4", "G#4", "A 4", "A#4", "B 4",
|
|
"C 5", "C#5", "D 5", "D#5", "E 5", "F 5", "F#5", "G 5", "G#5", "A 5", "A#5", "B 5",
|
|
"C 6", "C#6", "D 6", "D#6", "E 6", "F 6", "F#6", "G 6", "G#6", "A 6", "A#6", "B 6",
|
|
"C 7", "C#7", "D 7", "D#7", "E 7", "F 7", "F#7", "G 7", "G#7", "A 7", "A#7", "B 7",
|
|
"C 8", "C#8", "D 8", "D#8", "E 8", "F 8", "F#8", "G 8", "G#8", "A 8", "A#8", "B 8",
|
|
"C 9", "C#9", "D 9", "D#9", "E 9", "F 9", "F#9", "G 9", "G#9", "A 9", "A#9", "B 9"
|
|
};
|
|
|
|
private float[] notefreq =
|
|
{
|
|
16.35f, 17.32f, 18.35f, 19.45f, 20.60f, 21.83f, 23.12f, 24.50f, 25.96f, 27.50f, 29.14f, 30.87f,
|
|
32.70f, 34.65f, 36.71f, 38.89f, 41.20f, 43.65f, 46.25f, 49.00f, 51.91f, 55.00f, 58.27f, 61.74f,
|
|
65.41f, 69.30f, 73.42f, 77.78f, 82.41f, 87.31f, 92.50f, 98.00f, 103.83f, 110.00f, 116.54f, 123.47f,
|
|
130.81f, 138.59f, 146.83f, 155.56f, 164.81f, 174.61f, 185.00f, 196.00f, 207.65f, 220.00f, 233.08f, 246.94f,
|
|
261.63f, 277.18f, 293.66f, 311.13f, 329.63f, 349.23f, 369.99f, 392.00f, 415.30f, 440.00f, 466.16f, 493.88f,
|
|
523.25f, 554.37f, 587.33f, 622.25f, 659.26f, 698.46f, 739.99f, 783.99f, 830.61f, 880.00f, 932.33f, 987.77f,
|
|
1046.50f, 1108.73f, 1174.66f, 1244.51f, 1318.51f, 1396.91f, 1479.98f, 1567.98f, 1661.22f, 1760.00f, 1864.66f, 1975.53f,
|
|
2093.00f, 2217.46f, 2349.32f, 2489.02f, 2637.02f, 2793.83f, 2959.96f, 3135.96f, 3322.44f, 3520.00f, 3729.31f, 3951.07f,
|
|
4186.01f, 4434.92f, 4698.64f, 4978.03f, 5274.04f, 5587.65f, 5919.91f, 6271.92f, 6644.87f, 7040.00f, 7458.62f, 7902.13f,
|
|
8372.01f, 8869.84f, 9397.27f, 9956.06f, 10548.08f, 11175.30f, 11839.82f, 12543.85f, 13289.75f, 14080.00f, 14917.24f, 15804.26f
|
|
};
|
|
|
|
private const int OUTPUTRATE = 48000;
|
|
private const int SPECTRUMSIZE = 8192;
|
|
private const float SPECTRUMRANGE = ((float)OUTPUTRATE / 2.0f); /* 0 to nyquist */
|
|
private const float BINSIZE = (SPECTRUMRANGE / (float)SPECTRUMSIZE);
|
|
|
|
private FMOD.System system = null;
|
|
private FMOD.Sound sound = null;
|
|
private FMOD.Channel channel = null;
|
|
private int outputfreq = 0;
|
|
private int bin = 0;
|
|
|
|
private System.Windows.Forms.Label label;
|
|
private System.Windows.Forms.ComboBox comboBoxOutput;
|
|
private System.Windows.Forms.ComboBox comboBoxPlayback;
|
|
private System.Windows.Forms.ComboBox comboBoxRecord;
|
|
private System.Windows.Forms.StatusBar statusBar;
|
|
private System.Windows.Forms.Button exit_button;
|
|
private System.Windows.Forms.Timer timer;
|
|
private System.ComponentModel.IContainer components;
|
|
|
|
public PitchDetection()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
protected override void Dispose( bool disposing )
|
|
{
|
|
if( disposing )
|
|
{
|
|
FMOD.RESULT result;
|
|
|
|
/*
|
|
Shut down
|
|
*/
|
|
if (sound != null)
|
|
{
|
|
result = sound.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (system != null)
|
|
{
|
|
result = system.close();
|
|
ERRCHECK(result);
|
|
result = system.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (components != null)
|
|
{
|
|
components.Dispose();
|
|
}
|
|
}
|
|
base.Dispose( disposing );
|
|
}
|
|
|
|
#region Windows Form Designer generated code
|
|
/// <summary>
|
|
/// Required method for Designer support - do not modify
|
|
/// the contents of this method with the code editor.
|
|
/// </summary>
|
|
private void InitializeComponent()
|
|
{
|
|
this.components = new System.ComponentModel.Container();
|
|
this.label = new System.Windows.Forms.Label();
|
|
this.comboBoxOutput = new System.Windows.Forms.ComboBox();
|
|
this.comboBoxPlayback = new System.Windows.Forms.ComboBox();
|
|
this.comboBoxRecord = new System.Windows.Forms.ComboBox();
|
|
this.statusBar = new System.Windows.Forms.StatusBar();
|
|
this.exit_button = new System.Windows.Forms.Button();
|
|
this.timer = new System.Windows.Forms.Timer(this.components);
|
|
this.SuspendLayout();
|
|
//
|
|
// label
|
|
//
|
|
this.label.Location = new System.Drawing.Point(64, 8);
|
|
this.label.Name = "label";
|
|
this.label.Size = new System.Drawing.Size(264, 32);
|
|
this.label.TabIndex = 7;
|
|
this.label.Text = "Copyright (c) Firelight Technologies 2004-2016";
|
|
this.label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
|
//
|
|
// comboBoxOutput
|
|
//
|
|
this.comboBoxOutput.Location = new System.Drawing.Point(72, 48);
|
|
this.comboBoxOutput.Name = "comboBoxOutput";
|
|
this.comboBoxOutput.Size = new System.Drawing.Size(248, 21);
|
|
this.comboBoxOutput.TabIndex = 8;
|
|
this.comboBoxOutput.Text = "Select OUTPUT type";
|
|
this.comboBoxOutput.SelectedIndexChanged += new System.EventHandler(this.comboBoxOutput_SelectedIndexChanged);
|
|
//
|
|
// comboBoxPlayback
|
|
//
|
|
this.comboBoxPlayback.Location = new System.Drawing.Point(72, 72);
|
|
this.comboBoxPlayback.Name = "comboBoxPlayback";
|
|
this.comboBoxPlayback.Size = new System.Drawing.Size(248, 21);
|
|
this.comboBoxPlayback.TabIndex = 9;
|
|
this.comboBoxPlayback.Text = "Select PLAYBACK driver";
|
|
this.comboBoxPlayback.SelectedIndexChanged += new System.EventHandler(this.comboBoxPlayback_SelectedIndexChanged);
|
|
//
|
|
// comboBoxRecord
|
|
//
|
|
this.comboBoxRecord.Location = new System.Drawing.Point(72, 96);
|
|
this.comboBoxRecord.Name = "comboBoxRecord";
|
|
this.comboBoxRecord.Size = new System.Drawing.Size(248, 21);
|
|
this.comboBoxRecord.TabIndex = 10;
|
|
this.comboBoxRecord.Text = "Select RECORD driver";
|
|
this.comboBoxRecord.SelectedIndexChanged += new System.EventHandler(this.comboBoxRecord_SelectedIndexChanged);
|
|
//
|
|
// statusBar
|
|
//
|
|
this.statusBar.Location = new System.Drawing.Point(0, 155);
|
|
this.statusBar.Name = "statusBar";
|
|
this.statusBar.Size = new System.Drawing.Size(392, 24);
|
|
this.statusBar.TabIndex = 17;
|
|
//
|
|
// exit_button
|
|
//
|
|
this.exit_button.Location = new System.Drawing.Point(160, 128);
|
|
this.exit_button.Name = "exit_button";
|
|
this.exit_button.Size = new System.Drawing.Size(72, 24);
|
|
this.exit_button.TabIndex = 18;
|
|
this.exit_button.Text = "Exit";
|
|
this.exit_button.Click += new System.EventHandler(this.exit_button_Click);
|
|
//
|
|
// timer
|
|
//
|
|
this.timer.Enabled = true;
|
|
this.timer.Interval = 10;
|
|
this.timer.Tick += new System.EventHandler(this.timer_Tick);
|
|
//
|
|
// PitchDetection
|
|
//
|
|
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
|
|
this.ClientSize = new System.Drawing.Size(392, 179);
|
|
this.Controls.Add(this.exit_button);
|
|
this.Controls.Add(this.statusBar);
|
|
this.Controls.Add(this.comboBoxRecord);
|
|
this.Controls.Add(this.comboBoxPlayback);
|
|
this.Controls.Add(this.comboBoxOutput);
|
|
this.Controls.Add(this.label);
|
|
this.Name = "PitchDetection";
|
|
this.Text = "Pitch Detection Example";
|
|
this.Load += new System.EventHandler(this.PitchDetection_Load);
|
|
this.ResumeLayout(false);
|
|
|
|
}
|
|
#endregion
|
|
|
|
[STAThread]
|
|
static void Main()
|
|
{
|
|
Application.Run(new PitchDetection());
|
|
}
|
|
|
|
private void PitchDetection_Load(object sender, System.EventArgs e)
|
|
{
|
|
int numdrivers = 0;
|
|
uint version = 0;
|
|
FMOD.RESULT result;
|
|
StringBuilder drivername = new StringBuilder(256);
|
|
FMOD.GUID guid = new FMOD.GUID();
|
|
|
|
comboBoxOutput.Enabled = true;
|
|
comboBoxPlayback.Enabled = false;
|
|
comboBoxRecord.Enabled = false;
|
|
|
|
/*
|
|
Global Settings
|
|
*/
|
|
result = FMOD.Factory.System_Create(ref system);
|
|
ERRCHECK(result);
|
|
|
|
result = system.getVersion(ref version);
|
|
ERRCHECK(result);
|
|
if (version < FMOD.VERSION.number)
|
|
{
|
|
MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + ".");
|
|
Application.Exit();
|
|
}
|
|
|
|
/*
|
|
Get output modes
|
|
*/
|
|
comboBoxOutput.Items.Add("DirectSound");
|
|
comboBoxOutput.Items.Add("Windows Multimedia WaveOut");
|
|
comboBoxOutput.Items.Add("ASIO");
|
|
|
|
/*
|
|
Get Playback drivers
|
|
*/
|
|
result = system.getNumDrivers(ref numdrivers);
|
|
ERRCHECK(result);
|
|
|
|
for (int count = 0; count < numdrivers; count++)
|
|
{
|
|
result = system.getDriverInfo(count, drivername, drivername.Capacity, ref guid);
|
|
ERRCHECK(result);
|
|
|
|
comboBoxPlayback.Items.Add(drivername.ToString());
|
|
}
|
|
|
|
/*
|
|
Get Record drivers
|
|
*/
|
|
result = system.getRecordNumDrivers(ref numdrivers);
|
|
ERRCHECK(result);
|
|
|
|
for (int count = 0; count < numdrivers; count++)
|
|
{
|
|
result = system.getRecordDriverInfo(count, drivername, drivername.Capacity, ref guid);
|
|
ERRCHECK(result);
|
|
|
|
comboBoxRecord.Items.Add(drivername.ToString());
|
|
}
|
|
}
|
|
|
|
private void comboBoxOutput_SelectedIndexChanged(object sender, System.EventArgs e)
|
|
{
|
|
FMOD.RESULT result = FMOD.RESULT.OK;
|
|
|
|
switch (comboBoxOutput.SelectedIndex)
|
|
{
|
|
case 0:
|
|
result = system.setOutput(FMOD.OUTPUTTYPE.DSOUND);
|
|
break;
|
|
case 1:
|
|
result = system.setOutput(FMOD.OUTPUTTYPE.WINMM);
|
|
break;
|
|
case 2:
|
|
result = system.setOutput(FMOD.OUTPUTTYPE.ASIO);
|
|
break;
|
|
}
|
|
ERRCHECK(result);
|
|
|
|
comboBoxPlayback.Enabled = true;
|
|
}
|
|
|
|
private void comboBoxPlayback_SelectedIndexChanged(object sender, System.EventArgs e)
|
|
{
|
|
FMOD.RESULT result;
|
|
int selected = comboBoxPlayback.SelectedIndex;
|
|
|
|
result = system.setDriver(selected);
|
|
ERRCHECK(result);
|
|
|
|
comboBoxRecord.Enabled = true;
|
|
}
|
|
|
|
private void comboBoxRecord_SelectedIndexChanged(object sender, System.EventArgs e)
|
|
{
|
|
FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO();
|
|
FMOD.RESULT result;
|
|
FMOD.DSP_RESAMPLER resampler = FMOD.DSP_RESAMPLER.MAX;
|
|
int selected = comboBoxRecord.SelectedIndex;
|
|
int temp = 0;
|
|
FMOD.SOUND_FORMAT format = FMOD.SOUND_FORMAT.NONE;
|
|
|
|
result = system.setSoftwareFormat(OUTPUTRATE, FMOD.SOUND_FORMAT.PCM16, 1, 0, 0);
|
|
ERRCHECK(result);
|
|
|
|
result = system.init(32, FMOD.INITFLAGS.NORMAL, (IntPtr)null);
|
|
ERRCHECK(result);
|
|
|
|
result = system.getSoftwareFormat(ref outputfreq, ref format, ref temp, ref temp, ref resampler, ref temp);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Create a sound to record to.
|
|
*/
|
|
exinfo.cbsize = Marshal.SizeOf(exinfo);
|
|
exinfo.numchannels = 1;
|
|
exinfo.format = FMOD.SOUND_FORMAT.PCM16;
|
|
exinfo.defaultfrequency = OUTPUTRATE;
|
|
exinfo.length = (uint)(exinfo.defaultfrequency * 2 * exinfo.numchannels * 5);
|
|
|
|
result = system.createSound((string)null, (FMOD.MODE._2D | FMOD.MODE.SOFTWARE | FMOD.MODE.LOOP_NORMAL | FMOD.MODE.OPENUSER), ref exinfo, ref sound);
|
|
ERRCHECK(result);
|
|
|
|
comboBoxOutput.Enabled = false;
|
|
comboBoxPlayback.Enabled = false;
|
|
comboBoxRecord.Enabled = false;
|
|
|
|
/*
|
|
Start recording
|
|
*/
|
|
result = system.recordStart(selected, sound, true);
|
|
ERRCHECK(result);
|
|
|
|
Thread.Sleep(200); /* Give it some time to record something */
|
|
|
|
result = system.playSound(FMOD.CHANNELINDEX.REUSE, sound, false, ref channel);
|
|
ERRCHECK(result);
|
|
|
|
/* Dont hear what is being recorded otherwise it will feedback. Spectrum analysis is done before volume scaling in the DSP chain */
|
|
result = channel.setVolume(0);
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
private void timer_Tick(object sender, System.EventArgs e)
|
|
{
|
|
if (channel != null)
|
|
{
|
|
FMOD.RESULT result;
|
|
float[] spectrum = new float[SPECTRUMSIZE];
|
|
float dominanthz = 0;
|
|
float max;
|
|
int dominantnote = 0;
|
|
int count = 0;
|
|
|
|
result = channel.getSpectrum(spectrum, SPECTRUMSIZE, 0, FMOD.DSP_FFT_WINDOW.TRIANGLE);
|
|
ERRCHECK(result);
|
|
|
|
max = 0;
|
|
|
|
for (count = 0; count < SPECTRUMSIZE; count++)
|
|
{
|
|
if (spectrum[count] > 0.01f && spectrum[count] > max)
|
|
{
|
|
max = spectrum[count];
|
|
bin = count;
|
|
}
|
|
}
|
|
|
|
dominanthz = (float)bin * BINSIZE; /* dominant frequency min */
|
|
|
|
dominantnote = 0;
|
|
for (count = 0; count < 120; count++)
|
|
{
|
|
if (dominanthz >= notefreq[count] && dominanthz < notefreq[count + 1])
|
|
{
|
|
// which is it closer to. This note or the next note
|
|
if (Math.Abs(dominanthz - notefreq[count]) < Math.Abs(dominanthz - notefreq[count+1]))
|
|
{
|
|
dominantnote = count;
|
|
}
|
|
else
|
|
{
|
|
dominantnote = count + 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
statusBar.Text = "Detected rate : " + dominanthz + " -> " + (((float)bin + 0.99f) * BINSIZE) + " Detected musical note : " + note[dominantnote] + " (" + notefreq[dominantnote]+")";
|
|
}
|
|
|
|
if (system != null)
|
|
{
|
|
system.update();
|
|
}
|
|
}
|
|
|
|
private void exit_button_Click(object sender, System.EventArgs e)
|
|
{
|
|
Application.Exit();
|
|
}
|
|
|
|
private void ERRCHECK(FMOD.RESULT result)
|
|
{
|
|
if (result != FMOD.RESULT.OK)
|
|
{
|
|
timer.Stop();
|
|
MessageBox.Show("FMOD error! " + result + " - " + FMOD.Error.String(result));
|
|
Environment.Exit(-1);
|
|
}
|
|
}
|
|
}
|
|
}
|