Fix doc path
[opentx.git] / sound / recorder / WaveIn.cs
blob449cae4adfa7c578408079494886800e86c55b3d
1 /* This file is part of OpenTX Recorder.
2 * OpenTX Recorder is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This code is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with OpenTX Recorder. If not, see <http://www.gnu.org/licenses/>.
15 * Copyright 2014 Tomas Andersson */
17 using System;
18 using System.IO;
19 using System.Threading;
20 using System.Runtime.InteropServices;
22 namespace WaveLib
24 public delegate void BufferDoneEventHandler(IntPtr data, int size);
26 internal class WaveInBuffer
28 private ManualResetEvent m_RecordEvent = new ManualResetEvent(false);
29 private IntPtr m_WaveIn;
31 private WaveNative.WaveHdr m_Header;
32 private byte[] m_HeaderData;
33 private GCHandle m_HeaderHandle;
34 private GCHandle m_HeaderDataHandle;
36 internal static void WaveInProc(IntPtr hdrvr, int uMsg, int dwUser, ref WaveNative.WaveHdr wavhdr, int dwParam2)
38 if (uMsg == WaveNative.MM_WIM_DATA)
40 GCHandle h = (GCHandle)wavhdr.dwUser;
41 WaveInBuffer buf = (WaveInBuffer)h.Target;
42 buf.OnCompleted();
46 public WaveInBuffer(IntPtr waveInHandle, int size)
48 m_WaveIn = waveInHandle;
50 m_HeaderHandle = GCHandle.Alloc(m_Header, GCHandleType.Pinned);
51 m_Header.dwUser = (IntPtr)GCHandle.Alloc(this);
52 m_HeaderData = new byte[size];
53 m_HeaderDataHandle = GCHandle.Alloc(m_HeaderData, GCHandleType.Pinned);
54 m_Header.lpData = m_HeaderDataHandle.AddrOfPinnedObject();
55 m_Header.dwBufferLength = size;
56 WaveInRecorder.ThrowOnError(WaveNative.waveInPrepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
59 public void Close()
61 WaveInRecorder.ThrowOnError(WaveNative.waveInUnprepareHeader(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
62 m_HeaderHandle.Free();
63 m_Header.lpData = IntPtr.Zero;
64 m_HeaderDataHandle.Free();
67 public int Size
69 get { return m_Header.dwBufferLength; }
72 public IntPtr Data
74 get { return m_Header.lpData; }
77 public void Record()
79 m_RecordEvent.Reset();
80 WaveInRecorder.ThrowOnError(WaveNative.waveInAddBuffer(m_WaveIn, ref m_Header, Marshal.SizeOf(m_Header)));
83 public void WaitFor()
85 m_RecordEvent.WaitOne();
88 private void OnCompleted()
90 m_RecordEvent.Set();
94 public class WavFileWriter
96 BinaryWriter filewriter;
97 long audiobyteswritten;
99 public WavFileWriter(string filename, int samplerate, int bits, int channels)
101 filewriter = new BinaryWriter(File.Open(filename, FileMode.Create));
103 filewriter.Write((uint)0x46464952); // "RIFF"
104 filewriter.Write((uint)0); // chunkisize (filled in when we close)
105 filewriter.Write((uint)0x45564157); // "WAVE"
107 // subchunk1
108 filewriter.Write((uint)0x20746d66); // "fmt "
109 filewriter.Write((uint)16);
110 filewriter.Write((UInt16)1);
111 filewriter.Write((UInt16)channels);
112 filewriter.Write((uint)samplerate);
113 filewriter.Write((uint)(channels * samplerate * bits / 8));
114 filewriter.Write((UInt16)(channels * bits / 8));
115 filewriter.Write((UInt16)bits);
117 // subchunk2
118 filewriter.Write((uint)0x61746164); // "data"
119 filewriter.Write((uint)0); // chunkisize (filled in when we close)
122 public void Write(byte[] data, int size)
124 filewriter.Write(data, 0, size);
125 audiobyteswritten += size;
128 public void Close()
130 filewriter.Seek(4, SeekOrigin.Begin);
131 filewriter.Write((uint)(audiobyteswritten + 36)); // 36 = total size of chunk headers
133 filewriter.Seek(40, SeekOrigin.Begin);
134 filewriter.Write((uint)audiobyteswritten);
136 filewriter.Close();
140 public class WaveInRecorder
142 private IntPtr m_WaveIn;
143 private WaveInBuffer buffer1, buffer2;
144 private WaveInBuffer m_CurrentBuffer;
145 private Thread m_Thread;
146 private BufferDoneEventHandler m_DoneProc;
147 private bool m_Finished;
149 private WaveNative.WaveDelegate m_BufferProc = new WaveNative.WaveDelegate(WaveInBuffer.WaveInProc);
151 public static int DeviceCount
153 get { return WaveNative.waveInGetNumDevs(); }
156 public WaveInRecorder(int device, WaveFormat format, int bufferSize, BufferDoneEventHandler doneProc)
158 m_DoneProc = doneProc;
159 WaveInRecorder.ThrowOnError(WaveNative.waveInOpen(out m_WaveIn, device, format, m_BufferProc, 0, WaveNative.CALLBACK_FUNCTION));
161 buffer1 = new WaveInBuffer(m_WaveIn, bufferSize);
162 buffer2 = new WaveInBuffer(m_WaveIn, bufferSize);
164 buffer1.Record();
165 buffer2.Record();
167 m_CurrentBuffer = buffer1;
169 WaveInRecorder.ThrowOnError(WaveNative.waveInStart(m_WaveIn));
170 m_Thread = new Thread(new ThreadStart(ThreadProc));
171 m_Thread.Start();
174 public void Close()
176 m_Finished = true;
177 WaveInRecorder.ThrowOnError(WaveNative.waveInReset(m_WaveIn));
179 m_Thread.Join();
180 m_Thread = null;
181 m_DoneProc = null;
183 buffer1.WaitFor();
184 buffer2.WaitFor();
186 buffer1.Close();
187 buffer2.Close();
189 WaveInRecorder.ThrowOnError(WaveNative.waveInClose(m_WaveIn));
190 m_WaveIn = IntPtr.Zero;
193 private void ThreadProc()
195 while (!m_Finished)
197 m_CurrentBuffer = (m_CurrentBuffer == buffer1) ? buffer2 : buffer1;
199 m_CurrentBuffer.WaitFor();
200 m_DoneProc(m_CurrentBuffer.Data, m_CurrentBuffer.Size);
202 if (m_Finished) break;
204 m_CurrentBuffer.Record();
208 public static void ThrowOnError(int err)
210 if (err != WaveNative.MMSYSERR_NOERROR) throw new Exception(err.ToString());