Hope is a Dream. Dream is a Hope.

非公開ブログは再開しました。

NAudioで信号処理 (その4)

NAudioで信号処理 (目次) - Hope is a Dream. Dream is a Hope.

チュートリアル その4

f:id:hope_is_dream:20170506085429p:plain

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;
        }
    }
}

NAudioで信号処理 (その3)

チュートリアル その3

hope-is-dream.hatenablog.com

NAudioをつかってMP3からWAVへ変換

C# Audio Tutorial 3 - Convert MP3 File to Wave File

f:id:hope_is_dream:20170505232831p:plain

MP3FileReaderでmp3ファイルをロード. WaveStreamに変換してあと、WaveFileWriterへ渡す。だけ。おまじない。

 // 3. Convert mp3 -> wav
using (Mp3FileReader mp3 = new Mp3FileReader(open.FileName))
{
    using(WaveStream pcm = WaveFormatConversionStream.CreatePcmStream(mp3))
    {
        WaveFileWriter.CreateWaveFile(save.FileName, pcm);
    }
}
 
using System;
using System.Windows.Forms;
using NAudio.Wave;
namespace Tutorial2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// フォームの初期設定。
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            // ボタンの初期状態
            this.Text = @"Tutorial 3";
            linkLabel1.Text = "https://www.youtuabe.com/watch?v=l9sT26LEiD4";
        }

        #region Member
        #endregion


        /// <summary>
        /// フォームのクロージング処理
        /// Wave関連オブジェクトのDispose処理を担当
        /// </summary>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
        }

        /// <summary>
        /// MP3ファイルをWAVファイルへコンバート
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_Convert_Click(object sender, EventArgs e)
        {

            // 1. Open MP3 File
            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "Mp3 File (*.mp3)|*.mp3;";

            if (open.ShowDialog() != DialogResult.OK) return;


            // 2. Select Save WAV File
            SaveFileDialog save = new SaveFileDialog();
            save.Filter = "WAV File (*.wav)|*.wav;";

            if (save.ShowDialog() != DialogResult.OK) return;


            // 3. Convert mp3 -> wav
            using (Mp3FileReader mp3 = new Mp3FileReader(open.FileName))
            {
                using(WaveStream pcm = WaveFormatConversionStream.CreatePcmStream(mp3))
                {
                    WaveFileWriter.CreateWaveFile(save.FileName, pcm);
                }
            }



        }
    }
}

NAudioで信号処理 (その2)

チュートリアル その2

hope-is-dream.hatenablog.com

NAudioを使ってMP3/Waveファイルの再生

C# Audio Tutorial 2 - MP3/WAV File with NAudio

f:id:hope_is_dream:20170505221730p:plain

肝は、MP3/WAVファイルをどちらもWaveStreamとしてロードして、DirectSoundで再生する。

private NAudio.Wave.BlockAlignReductionStream stream = null; 

...省略

if (open.FileName.EndsWith(".mp3"))
{
    NAudio.Wave.WaveStream pcm = 
        NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(new NAudio.Wave.Mp3FileReader(open.FileName));
    stream = new NAudio.Wave.BlockAlignReductionStream(pcm);

}
else if (open.FileName.EndsWith(".wav"))
{
    NAudio.Wave.WaveStream pcm = new NAudio.Wave.WaveChannel32(new NAudio.Wave.WaveFileReader(open.FileName));
    stream = new NAudio.Wave.BlockAlignReductionStream(pcm);
}

メインのソースコードは以下のようになる。WAVの再生には、WAVファイルの選択->WAVのReaderの設定->出力先を指定->再生開始。のほかにも再生中断/再開や、再生が停止されたときのDispose処理が関わってくる。このチュートリアル(その1)では基本的なWAVファイル再生をベースとして、周辺のプレ処理、クロージング処理を実装しているので注目して欲しい。

using System;
using System.Windows.Forms;

namespace Tutorial2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// フォームの初期設定。
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            // ボタンの初期状態
            // TODO: 初期化関数は別に準備

            button_PauseWav.Enabled = false;
            this.Text = @"Tutorial 2";
            linkLabel1.Text = "https://www.youtube.com/watch?v=2ij2vqgprU0";
        }

        #region Member
        private NAudio.Wave.BlockAlignReductionStream stream = null; 

        private NAudio.Wave.DirectSoundOut output = null;
        #endregion

        /// <summary>
        /// WAVオープンボタン
        /// </summary>
        private void button_OpenWav_Click(object sender, EventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();
            open.Filter = "Audio File (*.wav, *.mp3) |*.wav;*.mp3;|All files (*.*)|*.*";

            if (open.ShowDialog() != DialogResult.OK) return;

            DisposeWave();


            if (open.FileName.EndsWith(".mp3"))
            {
                NAudio.Wave.WaveStream pcm = 
                    NAudio.Wave.WaveFormatConversionStream.CreatePcmStream(new NAudio.Wave.Mp3FileReader(open.FileName));
                stream = new NAudio.Wave.BlockAlignReductionStream(pcm);

            }
            else if (open.FileName.EndsWith(".wav"))
            {
                NAudio.Wave.WaveStream pcm = new NAudio.Wave.WaveChannel32(new NAudio.Wave.WaveFileReader(open.FileName));
                stream = new NAudio.Wave.BlockAlignReductionStream(pcm);
            }
            else
            {
                MessageBox.Show("Not a correct audio file type.");
                return;
                //throw new InvalidOperationException("Not a correct audio file type.");
            }

            output = new NAudio.Wave.DirectSoundOut();
            output.Init(new NAudio.Wave.WaveChannel32(stream));
            output.Play();

            button_PauseWav.Enabled = true;
        }

        /// <summary>
        /// 再生/一時停止ボタン
        /// </summary>
        private void button_PauseWav_Click(object sender, EventArgs e)
        {
            if (output != null)
            {
                if (output.PlaybackState == NAudio.Wave.PlaybackState.Playing)
                    output.Pause();
                else if (output.PlaybackState == NAudio.Wave.PlaybackState.Paused)
                    output.Play();
            }
        }

        /// <summary>
        /// Wave関連オブジェクトのDispose処理。
        /// </summary>
        private void DisposeWave()
        {
            if (output != null)
            {
                if (output.PlaybackState == NAudio.Wave.PlaybackState.Playing) output.Stop();
                output.Dispose();
                output = null;
            }
            if (stream != null)
            {
                stream.Dispose();
                stream = null;
            }
        }

        /// <summary>
        /// フォームのクロージング処理
        /// Wave関連オブジェクトのDispose処理を担当
        /// </summary>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.DisposeWave();
        }
    }
}