NAudioで信号処理 (その10)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
NAudioで信号処理 (その10)
グラフ描画!
C# Audio Tutorial 10 - Plotting Audio Waveforms
いよいよグラフ描画です。信号処理はグラフを描画することから始まります。チュートリアルでは独自グラフの実装ではなく、chartクラスと、NAudioのWaveViewerクラスを使っての実装となります。
using System; using System.Windows.Forms; using NAudio.Wave; using System.Drawing; namespace Tutorial { public partial class Form1 : Form { #region form public Form1() { InitializeComponent(); } private void openToolStripMenuItem_Click(object sender, EventArgs e) { // WAV File Open OpenFileDialog open = new OpenFileDialog(); open.Filter = "WAV File (*.wav)|*.wav;"; if (open.ShowDialog() != DialogResult.OK) return; // NAudio WaveViewerのセットアップ waveViewer1.BackColor = Color.White; waveViewer1.SamplesPerPixel = 400; waveViewer1.StartPosition = 40000; waveViewer1.WaveStream = new WaveFileReader(open.FileName); // ストリームを指定するだけでよい // 以下、chartのセットアップ chart1.Series.Add("wave"); chart1.Series["wave"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine; chart1.Series["wave"].ChartArea = "ChartArea1"; WaveChannel32 wave = new WaveChannel32(new WaveFileReader(open.FileName)); byte[] buffer = new byte[16384]; int read = 0; while(wave.Position < wave.Length) { read = wave.Read(buffer, 0, 16384); for (int i = 0; i < read/4; i++) { chart1.Series["wave"].Points.Add(BitConverter.ToSingle(buffer, i * 4)); } } } } }
NAudioで信号処理 (その9)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
NAudioで信号処理 (その9)
エフェクト処理 Part3 (Echo!!!!)
C# Audio Tutorial 9 - EffectStream Part 3 (Echo!)
やっとエフェクトの処理を実装します!
Echo.cs
先ほど作ったIEffect.csインターフェイスを実装したEcho.csを作ります。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tutorial { public class Echo : IEffect { public int EchoLength { get; private set; } public float EchoFactor { get; set; } private Queue<float> samples; public Echo(int length = 20000, float factor = 0.5f) { this.EchoLength = length; this.EchoFactor = factor; this.samples = new Queue<float>(); for (int i = 0; i < length; i++) samples.Enqueue(0f); } float IEffect.ApplyEffect(float sample) { samples.Enqueue(sample); // add que return sample + EchoFactor * samples.Dequeue(); } } }
EffectStream.cs
using System; using System.Collections.Generic; using NAudio.Wave; namespace Tutorial { public class EffectStream : WaveStream { public WaveStream SourceStream { get; set; } public List<IEffect> Effects { get; set; } public EffectStream(WaveStream stream) { this.SourceStream = stream; this.Effects = new List<IEffect>(); } //... 省略 private int channel = 0; public override int Read(byte[] buffer, int offset, int count) { //*****************************************************************// // ここで信号処理をする //*****************************************************************// Console.WriteLine("DirectSoundOut request {0} bytes", count); int read = this.SourceStream.Read(buffer, offset, count); // 以下信号処理 for (int i = 0; i < read/4; i++) { // float = single = 32bit float sample = BitConverter.ToSingle(buffer, i * 4); // Single=4Byte // エフェクト処理 if (Effects.Count == WaveFormat.Channels) { sample = Effects[channel].ApplyEffect(sample); // ? channel = (channel + 1) % WaveFormat.Channels; // [1ch, 2ch, ...] } // float -> byte列に変換 byte[] bytes = BitConverter.GetBytes(sample); // 4Byteなので,bytes[4] // コピー //bytes.CopyTo(buffer, i * 4); // 遅い buffer[i * 4 + 0] = bytes[0]; buffer[i * 4 + 1] = bytes[1]; buffer[i * 4 + 2] = bytes[2]; buffer[i * 4 + 3] = bytes[3]; } return read; } } }
form1.cs
あとは再生系にエフェクトを指定すると使えます。
// WAV File Open OpenFileDialog open = new OpenFileDialog(); open.Filter = "WAV File (*.wav)|*.wav;"; if (open.ShowDialog() != DialogResult.OK) return; // Audio Chain WaveChannel32 wave = new WaveChannel32(new WaveFileReader(open.FileName)); EffectStream effect = new EffectStream(wave); // エフェクトをかけるためのパイプライン stream = new BlockAlignReductionStream(effect); // Effects for (int i = 0; i < wave.WaveFormat.Channels; i++) { effect.Effects.Add(new Echo(20000, 0.5f)); } // Out output = new DirectSoundOut(200); output.Init(stream); output.Play();
NAudioで信号処理 (その8)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
NAudioで信号処理 (その8)
エフェクトの準備その2
C# Audio Tutorial 8 - EffectStream Part 2
その6)の続きです。
エフェクト用のインターフェイスを準備
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tutorial { public interface IEffect { float ApplyEffect(float sample); } }
using System; using System.Collections.Generic; using NAudio.Wave; namespace Tutorial { public class EffectStream : WaveStream { public WaveStream SourceStream { get; set; } public List<IEffect> Effects { get; set; } // インターフェイスのリスト public EffectStream(WaveStream stream) { this.SourceStream = stream; this.Effects = new List<IEffect>(); // エフェクト初期化 } public override WaveFormat WaveFormat { get { return this.SourceStream.WaveFormat; } } public override long Length { get { return SourceStream.Length; } } public override long Position { get { return this.SourceStream.Position; } set { this.SourceStream.Position = value; } } private int channel = 0; public override int Read(byte[] buffer, int offset, int count) { //*****************************************************************// // ここで信号処理をする //*****************************************************************// Console.WriteLine("DirectSoundOut request {0} bytes", count); int read = this.SourceStream.Read(buffer, offset, count); // 以下信号処理 for (int i = 0; i < read/4; i++) { // float = single = 32bit float sample = BitConverter.ToSingle(buffer, i * 4); // Single=4Byte // エフェクト処理 if (Effects.Count == WaveFormat.Channels) { sample = Effects[channel].ApplyEffect(sample); channel = (channel + 1) % WaveFormat.Channels; } // float -> byte列に変換 byte[] bytes = BitConverter.GetBytes(sample); // 4Byteなので,bytes[4] // コピー //bytes.CopyTo(buffer, i * 4); // 遅い buffer[i * 4 + 0] = bytes[0]; buffer[i * 4 + 1] = bytes[1]; buffer[i * 4 + 2] = bytes[2]; buffer[i * 4 + 3] = bytes[3]; } return read; } } }