NAudio | STFT - peace098beat/windows_applicaciton GitHub Wiki
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace FiNAudio0
{
public enum SelectedChannel
{
Left,
Right,
Mono
}
public partial class Form1 : Form
{
public string CurrentFilePath = "";
public WaveFileReader reader;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
private void button_LoadWav_Click(object sender, EventArgs e)
{
/// file load
CurrentFilePath = Path.GetFullPath(@"audio\\TestAudio-44100-16-stereo-10m.wav");
Debug.Assert(File.Exists(CurrentFilePath));
if (File.Exists(CurrentFilePath))
{
}
else
{
MessageBox.Show(CurrentFilePath,
"エラー",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
/// file load
CurrentFilePath = Path.GetFullPath(@"audio\\TestAudio-44100-16-stereo-10m.wav");
Debug.Assert(File.Exists(CurrentFilePath));
/// NAudio
this.reader = new NAudio.Wave.WaveFileReader(CurrentFilePath);
TimeSpan totalTime = this.reader.TotalTime;
int fs = this.reader.WaveFormat.SampleRate;
int bits = this.reader.WaveFormat.BitsPerSample;
int channels = this.reader.WaveFormat.Channels;
this.Text = Path.GetFileName(CurrentFilePath);
textBox1.Text += Path.GetFileName(CurrentFilePath) + Environment.NewLine + Environment.NewLine;
textBox1.Text += "Total Time : " + totalTime.ToString() + Environment.NewLine;
textBox1.Text += "Sample Rate : " + fs.ToString() + Environment.NewLine;
textBox1.Text += "Bits Per Sampel : " + bits.ToString() + Environment.NewLine;
textBox1.Text += "Channels : " + channels.ToString() + Environment.NewLine;
textBox1.Text += "SampleCount : " + this.reader.SampleCount.ToString() + Environment.NewLine;
// Param
SelectedChannel selectedChannel = SelectedChannel.Mono;
//待機状態
this.Cursor = Cursors.WaitCursor;
// Current Reader
//var reader = this.reader;
//// 16bits Only
Debug.Assert(reader.WaveFormat.BitsPerSample == 16);
/*****************************************************************************************
/* Read Samples
/*****************************************************************************************/
//// Create Buffer
byte[] buffer = new byte[reader.Length];
int bytesRead = reader.Read(buffer, 0, buffer.Length);
float[] samples = new float[bytesRead / reader.BlockAlign];
// read byte
for (int i = 0; i < samples.Length; i++)
{
float samplesL = BitConverter.ToInt16(buffer, i * reader.BlockAlign) / 32768f;
float samplesR = BitConverter.ToInt16(buffer, i * reader.BlockAlign + reader.BlockAlign / 2) / 32768f;
switch (selectedChannel)
{
case SelectedChannel.Left:
samples[i] = samplesL;
break;
case SelectedChannel.Right:
samples[i] = samplesR;
break;
case SelectedChannel.Mono:
samples[i] = (samplesL + samplesR) / 2F;
break;
default:
break;
}
}
/*****************************************************************************************
/* STFT (no overlap)
/*****************************************************************************************/
// Parameters
int fftLength = 8096;
int fftPos = 0;
float[,] result = new float[samples.Length / fftLength, fftLength / 2];
Complex[] cBuffer = new NAudio.Dsp.Complex[fftLength];
for (int i = 0; i < samples.Length; i++)
{
cBuffer[fftPos].X = (float)(samples[i] * FastFourierTransform.HammingWindow(fftPos, fftLength));
cBuffer[fftPos].Y = 0.0f;
fftPos++;
if (fftLength <= fftPos)
{
fftPos = 0;
int m = (int)Math.Log(fftLength, 2.0);
FastFourierTransform.FFT(true, m, cBuffer);
for (int k = 0; k < result.GetLength(1); k++)
{
double thr = 1e-10;
double power = Math.Sqrt(cBuffer[k].X * cBuffer[k].X + cBuffer[k].Y * cBuffer[k].Y);
double LogPow = 10.0 * Math.Log10(power + thr);
//const double minDB = -60.0;
//double percent = (LogPow < minDB) ? 1.0 : LogPow / minDB;
result[i / fftLength, k] = (float)LogPow;
}
}
}
// End FFT
this.Invalidate();
this.Update();
this.Refresh();
/*****************************************************************************************
/* Chart 1
/*****************************************************************************************/
int CHART_SKIP = 10000;
//デフォルトで追加されているSeriesとLegendの初期化
chart1.Series.Clear();
chart1.Legends.Clear();
//Seriesの作成
Series test = new Series();
test.ChartType = SeriesChartType.Line;
for (int i = 0; i < samples.Length; i += CHART_SKIP)
{
test.Points.AddXY((double)i / fs, samples[i]);
}
chart1.Series.Add(test);
/*****************************************************************************************
/* Chart 2
/*****************************************************************************************/
int CurrentFrame = 1000;
// 準備
int MaxFrame = result.GetLength(0);
int NFreq = result.GetLength(1);
int NFreqHarf = NFreq / 2;
//デフォルトで追加されているSeriesとLegendの初期化
chart2.Series.Clear();
chart2.Legends.Clear();
//Seriesの作成
Series chart2_series = new Series();
chart2_series.ChartType = SeriesChartType.Line;
for (int i = 0; i < NFreqHarf; i++)
{
double x = (double)i * (double)fs / (double)NFreq;
double y = result[CurrentFrame, i];
chart2_series.Points.AddXY(x, y);
}
chart2.Series.Add(chart2_series);
//元に戻す
this.Cursor = Cursors.Default;
}
}
}