NAudioで信号処理 (その5)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
NAudioで信号処理 (その5)
エフェクト処理の準備
C# Audio Tutorial 5 - EffectStream Part 1
Tutorial 5ではエフェクト処理の準備をします。WaveFIleReaderを使ってロードしたデータに対して、自作関数EffectStream(WaveStream継承)を間に挟みます。 これにより、任意の信号処理の後にBLockAlignReductionStreamを通して、再生が可能になります。
※ 本チュートリアルでは、エフェクトはかけてません。
// Audio Chain WaveChannel32 wave = new WaveChannel32(new WaveFileReader(open.FileName)); EffectStream effect = new EffectStream(wave); // エフェクトをかけるためのパイプライン stream = new BlockAlignReductionStream(effect); output = new DirectSoundOut(200); output.Init(stream); output.Play();
using System; using System.Windows.Forms; using NAudio.Wave; namespace Tutorial { public partial class Form1 : Form { #region form public Form1() { InitializeComponent(); } /// <summary> /// フォームの初期設定。 /// </summary> private void Form1_Load(object sender, EventArgs e) { // ボタンの初期状態 this.Text = @"Tutorial 6 - Audio Loopback using"; linkLabel1.Text = "https://www.youtube.com/watch?v=BjnTgIdTXwI"; } #endregion #region Member private DirectSoundOut output = null; private BlockAlignReductionStream stream = null; #endregion /// <summary> /// フォームのクロージング処理 /// Wave関連オブジェクトのDispose処理を担当 /// </summary> private void Form1_FormClosing(object sender, FormClosingEventArgs e) { output?.Dispose(); output = null; stream?.Dispose(); stream = null; } private void button_OpenWave_Click(object sender, EventArgs e) { // 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); output = new DirectSoundOut(200); output.Init(stream); output.Play(); } } }
EffectStream.cs
using System; using NAudio.Wave; namespace Tutorial { public class EffectStream : WaveStream { public WaveStream SourceStream { get; set; } public EffectStream(WaveStream stream) { this.SourceStream = stream; } 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; } } public override int Read(byte[] buffer, int offset, int count) { //*****************************************************************// // ここで信号処理をする //*****************************************************************// Console.WriteLine("DirectSoundOut request {0} bytes", count); return this.SourceStream.Read(buffer, offset, count); } } }
NAudioで信号処理 (その6)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
NAudioで信号処理 (その6)
録音デバイスの選択と、再生
C# Audio Tutorial 6 - Audio Loopback using
やっとデバイスの選択方法がでてきました。まずは録音デバイスということで入力側のデバイスの一覧を取得し、ListViewに表示します。
// SetUp WaveIn Devices List<WaveInCapabilities> sources = new List<WaveInCapabilities>(); for (int i = 0; i < WaveIn.DeviceCount; i++) { sources.Add(WaveIn.GetCapabilities(i)); } listView_Sources.Items.Clear(); foreach (var source in sources) { ListViewItem item = new ListViewItem(source.ProductName); item.SubItems.Add(new ListViewItem.ListViewSubItem(item, source.Channels.ToString())); listView_Sources.Items.Add(item); }
オーディオチェーンは以下のようになります。
#region Member private NAudio.Wave.WaveIn sourceStream = null; // 録音なのでWaveInを使用 private NAudio.Wave.DirectSoundOut waveOut = null; #endregion private void button_Start_Click(object sender, EventArgs e) { if (listView_Sources.SelectedItems.Count == 0) return; int deviceNumber = listView_Sources.SelectedItems[0].Index; // waveIn Select Recording Device sourceStream = new NAudio.Wave.WaveIn(); sourceStream.DeviceNumber = deviceNumber; // 使用するデバイスを選択 sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(44100, WaveIn.GetCapabilities(deviceNumber).Channels); // WaveInProviderで包み込む WaveInProvider waveIn = new NAudio.Wave.WaveInProvider(sourceStream); // ? // waveOut waveOut = new DirectSoundOut(); waveOut.Init(waveIn); sourceStream.StartRecording(); waveOut.Play(); }
using System; using System.Windows.Forms; using NAudio.Wave; using System.Collections.Generic; namespace Tutorial { public partial class Form1 : Form { #region form public Form1() { InitializeComponent(); } /// <summary> /// フォームの初期設定。 /// </summary> private void Form1_Load(object sender, EventArgs e) { // ボタンの初期状態 this.Text = @"Tutorial 5"; linkLabel1.Text = "https://www.youtube.com/watch?v=CFUBse8Rjko"; } /// <summary> /// フォームのクロージング処理 /// Wave関連オブジェクトのDispose処理を担当 /// </summary> private void Form1_FormClosing(object sender, FormClosingEventArgs e) { } #endregion private void button_Refresh_Click(object sender, EventArgs e) { // SetUp WaveIn Devices List<WaveInCapabilities> sources = new List<WaveInCapabilities>(); for (int i = 0; i < WaveIn.DeviceCount; i++) { sources.Add(WaveIn.GetCapabilities(i)); } listView_Sources.Items.Clear(); foreach (var source in sources) { ListViewItem item = new ListViewItem(source.ProductName); item.SubItems.Add(new ListViewItem.ListViewSubItem(item, source.Channels.ToString())); listView_Sources.Items.Add(item); } } #region Member private NAudio.Wave.WaveIn sourceStream = null; private NAudio.Wave.DirectSoundOut waveOut = null; #endregion private void button_Start_Click(object sender, EventArgs e) { if (listView_Sources.SelectedItems.Count == 0) return; int deviceNumber = listView_Sources.SelectedItems[0].Index; // waveIn Select Recording Device sourceStream = new NAudio.Wave.WaveIn(); sourceStream.DeviceNumber = deviceNumber; sourceStream.WaveFormat = new NAudio.Wave.WaveFormat(44100, WaveIn.GetCapabilities(deviceNumber).Channels); WaveInProvider waveIn = new NAudio.Wave.WaveInProvider(sourceStream); // ? // waveOut waveOut = new DirectSoundOut(); waveOut.Init(waveIn); sourceStream.StartRecording(); waveOut.Play(); } private void button_Stop_Click(object sender, EventArgs e) { waveOut?.Stop(); waveOut?.Dispose(); waveOut = null; sourceStream?.StopRecording(); sourceStream?.Dispose(); sourceStream = null; } private void button_Exit_Click(object sender, EventArgs e) { button_Stop_Click(sender, e); this.Close(); } } }
NAudioで信号処理 (その4)
NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.
チュートリアル その4
NAudioをつかってSin音を生成
C# Audio Tutorial 2 - MP3/WAV File with NAudio
// 再生デバイス private DirectSoundOut output = null; private BlockAlignReductionStream stream = null; // オーディオチェイン WaveTone tone = new WaveTone(1000, 0.1); stream = new BlockAlignReductionStream(tone); output = new DirectSoundOut(); output.Init(stream); output.Play(); // SinWaveを生成 for (int i = 0; i < samples; i++) { double sine = amplitude * Math.Sin(Math.PI * 2 * frequency * time); time += 1.0 / 44100; short truncated = (short)Math.Round(sine * (Math.Pow(2, 15) - 1)); //16bit buffer[i * 2] = (byte)(truncated & 0x00ff); // 下半分を取り出し 8bit buffer[i * 2 + 1] = (byte)((truncated & 0xff00) >> 8); // 上半分を取り出してシフト 8bit }
using System; using System.Windows.Forms; using NAudio.Wave; namespace Tutorial { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// <summary> /// フォームの初期設定。 /// </summary> private void Form1_Load(object sender, EventArgs e) { // ボタンの初期状態 this.Text = @"Tutorial 4"; linkLabel1.Text = "https://www.youtube.com/watch?v=Tumpkl-xJuA"; } #region Member private DirectSoundOut output = null; private BlockAlignReductionStream stream = null; #endregion /// <summary> /// フォームのクロージング処理 /// Wave関連オブジェクトのDispose処理を担当 /// </summary> private void Form1_FormClosing(object sender, FormClosingEventArgs e) { output?.Dispose(); output = null; stream?.Dispose(); stream = null; } private void button_StartTone_Click(object sender, EventArgs e) { WaveTone tone = new WaveTone(1000, 0.1); stream = new BlockAlignReductionStream(tone); output = new DirectSoundOut(); output.Init(stream); output.Play(); } private void button_StopTone_Click(object sender, EventArgs e) { output?.Stop(); } } /// <summary> /// /// WaveStreamは抽象クラス /// </summary> public class WaveTone : WaveStream { private double frequency; private double amplitude; private double time; public WaveTone(double f, double a) { this.time = 0; this.frequency = f; this.amplitude = a; } public override long Position { get; set; } public override long Length { get { return long.MaxValue; } } public override WaveFormat WaveFormat { get { return new WaveFormat(44100, 32, 1); } } /// <summary> /// </summary> public override int Read(byte[] buffer, int offset, int count) { // byte(8bit) // short(16bit) int samples = count / 2; // ? for (int i = 0; i < samples; i++) { double sine = amplitude * Math.Sin(Math.PI * 2 * frequency * time); time += 1.0 / 44100; short truncated = (short)Math.Round(sine * (Math.Pow(2, 15) - 1)); //16bit buffer[i * 2] = (byte)(truncated & 0x00ff); // 下半分を取り出し 8bit buffer[i * 2 + 1] = (byte)((truncated & 0xff00) >> 8); // 上半分を取り出してシフト 8bit } return count; } } }