開発環境 |
Microsoft Visual Studio Community 2017 |
実行環境 |
Microsoft Windows 10 Home (64-bit) |
プロジェクトの種類 |
Visual C# / Windows フォーム アプリケーション (.NET Framework) |
プロジェクト名 |
waveout |
Form1.cs
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
[StructLayout(LayoutKind.Sequential)]
struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
}
[StructLayout(LayoutKind.Sequential)]
struct WAVEHDR
{
public IntPtr lpData;
public uint dwBufferLength;
public uint dwBytesRecorded;
public uint dwUser;
public uint dwFlags;
public uint dwLoops;
public IntPtr lpNext;
public uint reserved;
}
namespace waveout
{
public partial class Form1 : Form
{
[DllImport("winmm.dll")]
private static extern uint waveOutOpen(ref IntPtr phwo, uint uDeviceID,
ref WAVEFORMATEX pwfx, IntPtr dwCallback, uint dwCallbackInstance, uint fdwOpen);
[DllImport("winmm.dll")]
private static extern uint waveOutClose(IntPtr hwo);
[DllImport("winmm.dll")]
private static extern uint waveOutPrepareHeader(IntPtr hwo, ref WAVEHDR pwh, uint cbwh);
[DllImport("winmm.dll")]
private static extern uint waveOutUnprepareHeader(IntPtr hwo, ref WAVEHDR pwh, uint cbwh);
[DllImport("winmm.dll")]
private static extern uint waveOutWrite(IntPtr hwo, ref WAVEHDR pwh, uint cbwh);
[DllImport("winmm.dll")]
private static extern uint waveOutReset(IntPtr hwo);
private const ushort WAVE_FORMAT_PCM = 1;
private const uint WAVE_MAPPER = unchecked((uint)-1);
private const uint CALLBACK_NULL = 0;
private const uint CALLBACK_WINDOW = 0x00010000;
private const int MM_WOM_OPEN = 0x3BB;
private const int MM_WOM_CLOSE = 0x3BC;
private const int MM_WOM_DONE = 0x3BD;
private const int SAMPLE_RATE = 48000;
private readonly uint CBWH = (uint)Marshal.SizeOf(typeof(WAVEHDR));
private IntPtr hwo = IntPtr.Zero;
private WAVEHDR wh = new WAVEHDR();
private IntPtr lpData = IntPtr.Zero;
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case MM_WOM_OPEN:
Trace.WriteLine(">> MM_WOM_OPEN:");
OnWomOpen();
break;
case MM_WOM_CLOSE:
Trace.WriteLine(">> MM_WOM_CLOSE:");
break;
case MM_WOM_DONE:
Trace.WriteLine(">> MM_WOM_DONE:");
Stop();
break;
}
}
private void button1_Click(object sender, EventArgs e)
{
Play();
}
private void button2_Click(object sender, EventArgs e)
{
Stop();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Stop();
}
private void OnWomOpen()
{
uint mmr;
mmr = waveOutWrite(hwo, ref wh, CBWH);
Trace.WriteLine("waveOutWrite:" + mmr);
}
private void Play()
{
byte[] data = GenerateWaveform();
lpData = Marshal.AllocHGlobal(data.Length);
Marshal.Copy(data, 0, lpData, data.Length);
//
uint mmr;
WAVEFORMATEX wfx = new WAVEFORMATEX();
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 1;
wfx.nSamplesPerSec = SAMPLE_RATE;
wfx.nAvgBytesPerSec = SAMPLE_RATE;
wfx.nBlockAlign = 1;
wfx.wBitsPerSample = 8;
wfx.cbSize = 0;
mmr = waveOutOpen(ref hwo, WAVE_MAPPER, ref wfx, Handle, 0, CALLBACK_WINDOW);
Trace.WriteLine("waveOutOpen:" + mmr);
wh.lpData = lpData;
wh.dwBufferLength = (uint)data.Length;
wh.dwFlags = 0;
mmr = waveOutPrepareHeader(hwo, ref wh, CBWH);
Trace.WriteLine("waveOutPrepareHeader:" + mmr);
button1.Enabled = false;
}
private void Stop()
{
Trace.WriteLine("Stop()");
if (hwo != IntPtr.Zero)
{
uint mmr;
mmr = waveOutReset(hwo);
Trace.WriteLine("waveOutReset:" + mmr);
mmr = waveOutUnprepareHeader(hwo, ref wh, CBWH);
Trace.WriteLine("waveOutUnprepareHeader:" + mmr);
mmr = waveOutClose(hwo);
Trace.WriteLine("waveOutClose:" + mmr);
hwo = IntPtr.Zero;
}
if (lpData != IntPtr.Zero)
{
Marshal.FreeHGlobal(lpData);
lpData = IntPtr.Zero;
}
button1.Enabled = true;
}
private byte[] GenerateWaveform()
{
int[] note = new int[] { 0, 2, 4, 5, 7, 9, 11, 12 };
int data_len = SAMPLE_RATE * 4;
byte[] data = Enumerable.Repeat((byte)128, data_len).ToArray();
int pos = 0;
for (int i = 0; i < 8; i++)
{
double freq = 440 * Math.Pow(2, (note[i] - 9) / 12.0);
int gate = SAMPLE_RATE / 2;
for (int j = 0; j < gate; j++)
{
double t = (j * freq / SAMPLE_RATE) % 1.0;
data[pos + j] += (byte)((t < 0.5 ? 1 : -1) * 8);
}
pos += gate;
}
return data;
}
}
}
最終更新:2018年03月27日 10:20