概要
C#でwavを動的生成して再生するサンプル。
環境
Visual Studio Community 2017
wavファイルの再生
先ずwavファイル再生のおさらい。
Visual C#のフォームアプリケーションを作成し、フォームにボタンとClickイベントハンドラを作る。そして適当なwavファイルを用意する。
private void button1_Click(object sender, EventArgs e)
{
var player = new SoundPlayer();
player.SoundLocation = @"c:\tmp\sample.wav";
player.Load();
player.Play();
}
private void button2_Click(object sender, EventArgs e)
{
var player = new SoundPlayer(@"c:\tmp\sample.wav");
player.Play();
}
private void button3_Click(object sender, EventArgs e)
{
var stream = File.OpenRead(@"c:\tmp\sample.wav");
var player = new SoundPlayer(stream);
player.Play();
}
wavの動的生成と再生
波形データを生成し、WaveFileHeaderを付けてMemoryStreamに書き込んで再生する。またFileStreamに書き込めばそのままwavファイルとなる。
Form1.cs
using System;
using System.IO;
using System.Media;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace GenerateWave
{
[StructLayout(LayoutKind.Sequential)]
class WaveFileHeader
{
public uint riff_ckid = 0x46464952; // "RIFF"
public uint riff_cksize;
public uint fccType = 0x45564157; // "WAVE"
public uint fmt_ckid = 0x20746d66; // "fmt "
public uint fmt_cksize = 16;
public ushort wFormatTag = 0x0001; // WAVE_FORMAT_PCM
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public uint data_ckid = 0x61746164; // "data"
public uint data_cksize;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
const uint sampleRate = 48000; // サンプリング周波数
// 波形データの生成
uint wavelen = sampleRate / 2;
byte[] wave = new byte[wavelen];
double t = 0;
for (uint i = 0; i < wavelen; i++)
{
double freq = (i < wavelen / 2) ? 2000 : 1000;
t = (t + freq / sampleRate) % 1;
wave[i] = (byte)(128 + (t < 0.5 ? 1 : -1) * 10);
}
// WAVEファイルヘッダ
var wfh = new WaveFileHeader();
wfh.nChannels = 1;
wfh.nSamplesPerSec = sampleRate;
wfh.nAvgBytesPerSec = sampleRate;
wfh.nBlockAlign = 1;
wfh.wBitsPerSample = 8;
wfh.riff_cksize = 36 + wavelen;
wfh.data_cksize = wavelen;
//using (FileStream stream = new FileStream(@"c:\tmp\hoge.wav", FileMode.Create))
using (MemoryStream stream = new MemoryStream())
{
FieldInfo[] infos = typeof(WaveFileHeader).GetFields();
foreach (FieldInfo info in infos)
{
byte[] ba = BitConverter.GetBytes(Convert.ToUInt32(info.GetValue(wfh)));
stream.Write(ba, 0, Marshal.SizeOf(info.FieldType));
}
stream.Write(wave, 0, wave.Length);
stream.Seek(0, SeekOrigin.Begin);
var player = new SoundPlayer(stream);
player.Play();
}
}
}
}
別の方法
Form1.cs
using System;
using System.IO;
using System.Media;
using System.Text;
using System.Windows.Forms;
namespace GenerateWave
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
const uint sampleRate = 44100; // サンプリング周波数
// 波形データの生成
uint wavelen = (uint)(sampleRate * 1.0);
byte[] wave = new byte[wavelen];
double t = 0;
for (uint i = 0; i < wavelen; i++)
{
t = (t + 880.0 / sampleRate) % 1;
wave[i] = (byte)(128 + Math.Sin(2 * Math.PI * t) * (1 - i / (double)wavelen) * 10);
}
//using (FileStream st = new FileStream(@"c:\tmp\hoge.wav", FileMode.Create))
using (MemoryStream st = new MemoryStream())
{
// WAVEファイルヘッダ
WriteStr(st, "RIFF");
WriteVal(st, 4, wavelen + 36);
WriteStr(st, "WAVE");
WriteStr(st, "fmt ");
WriteVal(st, 4, 16);
WriteVal(st, 2, 0x0001); // WAVE_FORMAT_PCM
WriteVal(st, 2, 1); // nChannels
WriteVal(st, 4, sampleRate); // nSamplesPerSec
WriteVal(st, 4, sampleRate); // nAvgBytesPerSec
WriteVal(st, 2, 1); // nBlockAlign
WriteVal(st, 2, 8); // wBitsPerSample
WriteStr(st, "data");
WriteVal(st, 4, wavelen);
st.Write(wave, 0, wave.Length);
st.Seek(0, SeekOrigin.Begin);
SoundPlayer player = new SoundPlayer(st);
player.Play();
}
}
private void WriteVal(Stream st, int len, uint value)
{
byte[] ba = BitConverter.GetBytes(value);
st.Write(ba, 0, len);
}
private void WriteStr(Stream st, string str)
{
byte[] ba = Encoding.ASCII.GetBytes(str);
st.Write(ba, 0, ba.Length);
}
}
}