思ったより簡単にできた。 winmm.dllは32bitを想定して作られているので、対象プラットフォームをx86としてbuildした。
参考になるソースが山ほどネットに上がっているので、必要な情報は苦労しなくても入手できた。
完全に理解できたわけではないけど、まあ、正常に動作しているようなので何か問題が起きた時に深く考えることにする。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
using System; using System.Windows.Forms; using System.Numerics; using System.Runtime.InteropServices; namespace WinMM_Sound { public partial class Form1 : Form { private double freq = 600; private int sample_rate = 44100; private static Complex osc_vect = new Complex(); private static Complex osc_phase = new Complex(); private const int BufferSize = 22050; private static short[] WaveDataOut1 = new short[BufferSize]; private static Int16[] WaveDataOut2 = new short[BufferSize]; private IntPtr hWaveOut = IntPtr.Zero; private WaveFormat WaveFormatOut; private WaveHdr WaveHdrOut1 = new WaveHdr(WaveDataOut1); private WaveHdr WaveHdrOut2 = new WaveHdr(WaveDataOut2); public Form1() { InitializeComponent(); } private static void waveOutProc( IntPtr hdrvr, int uMsg, int dwUser, ref WaveHdr wavhdr, int dwParam2) { switch (uMsg) { case MM_WOM_OPEN: break; case MM_WOM_CLOSE: break; case MM_WOM_DONE: Marshal.Copy(GetSndData(), 0, wavhdr.lpData, BufferSize); waveOutWrite(hdrvr, ref wavhdr, Marshal.SizeOf(wavhdr)); break; } } private void Form1_Load(object sender, EventArgs e) { var angpersec = 2.0 * Math.PI * freq / sample_rate; osc_phase = Math.Cos(angpersec) + Complex.ImaginaryOne * Math.Sin(angpersec); osc_vect = 1 + Complex.ImaginaryOne; WaveFormatOut = new WaveFormat(sample_rate, 16, 2); waveOutOpen(out hWaveOut, -1, WaveFormatOut, waveOutCallBack, 0, CALLBACK_FUNCTION); waveOutPrepareHeader(hWaveOut, ref WaveHdrOut1, Marshal.SizeOf(WaveHdrOut1)); waveOutPrepareHeader(hWaveOut, ref WaveHdrOut2, Marshal.SizeOf(WaveHdrOut2)); } private static short[] GetSndData() { short[] wavedata = new short[BufferSize]; for (int i = 0; i < BufferSize; i++) { osc_vect = osc_vect * osc_phase; wavedata[i] = (short)(1000 * osc_vect.Real); } return wavedata; } private void button1_Click(object sender, EventArgs e) { Marshal.Copy(GetSndData(), 0, WaveHdrOut1.lpData, BufferSize); waveOutWrite(hWaveOut, ref WaveHdrOut1, Marshal.SizeOf(WaveHdrOut1)); Marshal.Copy(GetSndData(), 0, WaveHdrOut2.lpData, BufferSize); waveOutWrite(hWaveOut, ref WaveHdrOut2, Marshal.SizeOf(WaveHdrOut2)); } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { waveOutReset(hWaveOut); waveOutUnprepareHeader(hWaveOut, ref WaveHdrOut1, Marshal.SizeOf(WaveHdrOut1)); waveOutUnprepareHeader(hWaveOut, ref WaveHdrOut2, Marshal.SizeOf(WaveHdrOut2)); waveOutClose(hWaveOut); } private void button2_Click(object sender, EventArgs e) { // waveOutPause(hWaveOut); } } } |
600Hzのサイン波を連続的に発生させている。 音を途切れなく出すために、2つのバッファを使って、交互にデータを書き込んでいる。 スタート直後に若干音が途切れる瞬間があるが、その後は連続して音が出る。 ちなみに、停止する方法は今のところ不明。
重松宏昌2021年7月8日 22:51 /
今日は? コードを拝見させて頂きました。 コピーしてコンパイルしましたはエラーが出ます。 .NET Framework4.8でコンパイルできますか? エラー内容: private WaveFormat WaveFormatOut; //CS0246 型または名前空間の名前 'WaveFormat' が見つかりませんでした //(using ディレクティブまたはアセンブリ参照が指定されていることを確認してください) コメント頂けますと有難いです。