00001 #region License
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #endregion
00027
00028 using System;
00029 using System.Collections.Generic;
00030 using System.Diagnostics;
00031 using System.Runtime.InteropServices;
00032
00033 using OpenTK.Audio.OpenAL;
00034
00035 namespace OpenTK.Audio
00036 {
00037
00042 public sealed class AudioCapture : IDisposable
00043 {
00044 #region Fields
00045
00046
00047 IntPtr Handle;
00048
00049
00050 bool _isrecording = false;
00051
00052 ALFormat sample_format;
00053 int sample_frequency;
00054
00055 #endregion
00056
00057 #region Constructors
00058
00059 static AudioCapture()
00060 {
00061 if (AudioDeviceEnumerator.IsOpenALSupported)
00062 {
00063 }
00064 }
00065
00070 public AudioCapture()
00071 : this(AudioCapture.DefaultDevice, 22050, ALFormat.Mono16, 4096)
00072 {
00073 }
00074
00080 public AudioCapture(string deviceName, int frequency, ALFormat sampleFormat, int bufferSize)
00081 {
00082 if (!AudioDeviceEnumerator.IsOpenALSupported)
00083 throw new DllNotFoundException("openal32.dll");
00084 if (frequency <= 0)
00085 throw new ArgumentOutOfRangeException("frequency");
00086 if (bufferSize <= 0)
00087 throw new ArgumentOutOfRangeException("bufferSize");
00088
00089
00090 device_name = deviceName;
00091 Handle = Alc.CaptureOpenDevice(deviceName, frequency, sampleFormat, bufferSize);
00092
00093 if (Handle == IntPtr.Zero)
00094 {
00095 Debug.WriteLine(ErrorMessage(deviceName, frequency, sampleFormat, bufferSize));
00096 device_name = "IntPtr.Zero";
00097 Handle = Alc.CaptureOpenDevice(null, frequency, sampleFormat, bufferSize);
00098 }
00099
00100 if (Handle == IntPtr.Zero)
00101 {
00102 Debug.WriteLine(ErrorMessage("IntPtr.Zero", frequency, sampleFormat, bufferSize));
00103 device_name = AudioDeviceEnumerator.DefaultRecordingDevice;
00104 Handle = Alc.CaptureOpenDevice(AudioDeviceEnumerator.DefaultRecordingDevice, frequency, sampleFormat, bufferSize);
00105 }
00106
00107 if (Handle == IntPtr.Zero)
00108 {
00109
00110 Debug.WriteLine(ErrorMessage(AudioDeviceEnumerator.DefaultRecordingDevice, frequency, sampleFormat, bufferSize));
00111 device_name = "None";
00112
00113 throw new AudioDeviceException("All attempts to open capture devices returned IntPtr.Zero. See debug log for verbose list.");
00114 }
00115
00116
00117 CheckErrors();
00118
00119 SampleFormat = sampleFormat;
00120 SampleFrequency = frequency;
00121 }
00122
00123 #endregion Constructor
00124
00125 #region Public Members
00126
00127 #region CurrentDevice
00128
00129 private string device_name;
00130
00134 public string CurrentDevice
00135 {
00136 get
00137 {
00138 return device_name;
00139 }
00140 }
00141
00142 #endregion
00143
00144 #region AvailableDevices
00145
00149 public static IList<string> AvailableDevices
00150 {
00151 get
00152 {
00153 return AudioDeviceEnumerator.AvailableRecordingDevices;
00154 }
00155 }
00156
00157 #endregion
00158
00159 #region DefaultDevice
00160
00164 public static string DefaultDevice
00165 {
00166 get
00167 {
00168 return AudioDeviceEnumerator.DefaultRecordingDevice;
00169 }
00170 }
00171
00172 #endregion
00173
00174 #region CheckErrors
00175
00183 public void CheckErrors()
00184 {
00185 new AudioDeviceErrorChecker(Handle).Dispose();
00186 }
00187
00188 #endregion
00189
00190 #region CurrentError
00191
00193 public AlcError CurrentError
00194 {
00195 get
00196 {
00197 return Alc.GetError(Handle);
00198 }
00199 }
00200
00201 #endregion
00202
00203 #region Start & Stop
00204
00210 public void Start()
00211 {
00212 Alc.CaptureStart(Handle);
00213 _isrecording = true;
00214 }
00215
00217 public void Stop()
00218 {
00219 Alc.CaptureStop(Handle);
00220 _isrecording = false;
00221 }
00222
00223 #endregion Start & Stop Capture
00224
00225 #region AvailableSamples
00226
00228 public int AvailableSamples
00229 {
00230 get
00231 {
00232
00233
00234 int result;
00235 Alc.GetInteger(Handle, AlcGetInteger.CaptureSamples, 1, out result);
00236 return result;
00237 }
00238 }
00239
00240 #endregion Available samples property
00241
00242 #region ReadSamples
00243
00247 public void ReadSamples(IntPtr buffer, int sampleCount)
00248 {
00249 Alc.CaptureSamples(Handle, buffer, sampleCount);
00250 }
00251
00257 public void ReadSamples<TBuffer>(TBuffer[] buffer, int sampleCount)
00258 where TBuffer : struct
00259 {
00260 if (buffer == null)
00261 throw new ArgumentNullException("buffer");
00262
00263 int buffer_size = BlittableValueType<TBuffer>.Stride * buffer.Length;
00264
00265
00266
00267
00268
00269 if (sampleCount * GetSampleSize(SampleFormat) > buffer_size)
00270 throw new ArgumentOutOfRangeException("sampleCount");
00271
00272 GCHandle buffer_ptr = GCHandle.Alloc(buffer, GCHandleType.Pinned);
00273 try { ReadSamples(buffer_ptr.AddrOfPinnedObject(), sampleCount); }
00274 finally { buffer_ptr.Free(); }
00275 }
00276
00277 #endregion
00278
00279 #region SampleFormat & SampleFrequency
00280
00284 public ALFormat SampleFormat
00285 {
00286 get { return sample_format; }
00287 private set { sample_format = value; }
00288 }
00289
00293 public int SampleFrequency
00294 {
00295 get { return sample_frequency; }
00296 private set { sample_frequency = value; }
00297 }
00298
00299 #endregion
00300
00301 #region IsRunning
00302
00306 public bool IsRunning
00307 {
00308 get { return _isrecording; }
00309 }
00310
00311 #endregion
00312
00313 #endregion
00314
00315 #region Private Members
00316
00317
00318
00319 static int GetSampleSize(ALFormat format)
00320 {
00321 switch (format)
00322 {
00323 case ALFormat.Mono8: return 1;
00324 case ALFormat.Mono16: return 2;
00325 case ALFormat.Stereo8: return 2;
00326 case ALFormat.Stereo16: return 4;
00327 case ALFormat.MonoFloat32Ext: return 4;
00328 case ALFormat.MonoDoubleExt: return 8;
00329 case ALFormat.StereoFloat32Ext: return 8;
00330 case ALFormat.StereoDoubleExt: return 16;
00331
00332 case ALFormat.MultiQuad8Ext: return 4;
00333 case ALFormat.MultiQuad16Ext: return 8;
00334 case ALFormat.MultiQuad32Ext: return 16;
00335
00336 case ALFormat.Multi51Chn8Ext: return 6;
00337 case ALFormat.Multi51Chn16Ext: return 12;
00338 case ALFormat.Multi51Chn32Ext: return 24;
00339
00340 case ALFormat.Multi61Chn8Ext: return 7;
00341 case ALFormat.Multi71Chn16Ext: return 14;
00342 case ALFormat.Multi71Chn32Ext: return 28;
00343
00344 case ALFormat.MultiRear8Ext: return 1;
00345 case ALFormat.MultiRear16Ext: return 2;
00346 case ALFormat.MultiRear32Ext: return 4;
00347
00348 default: return 1;
00349 }
00350 }
00351
00352
00353 string ErrorMessage(string devicename, int frequency, ALFormat bufferformat, int buffersize)
00354 {
00355 string alcerrmsg;
00356 AlcError alcerrcode = CurrentError;
00357 switch (alcerrcode)
00358 {
00359 case AlcError.OutOfMemory:
00360 alcerrmsg = alcerrcode.ToString() + ": The specified device is invalid, or can not capture audio.";
00361 break;
00362 case AlcError.InvalidValue:
00363 alcerrmsg = alcerrcode.ToString() + ": One of the parameters has an invalid value.";
00364 break;
00365 default:
00366 alcerrmsg = alcerrcode.ToString();
00367 break;
00368 }
00369 return "The handle returned by Alc.CaptureOpenDevice is null." +
00370 "\nAlc Error: " + alcerrmsg +
00371 "\nDevice Name: " + devicename +
00372 "\nCapture frequency: " + frequency +
00373 "\nBuffer format: " + bufferformat +
00374 "\nBuffer Size: " + buffersize;
00375 }
00376
00377 #endregion
00378
00379 #region IDisposable Members
00380
00384 ~AudioCapture()
00385 {
00386 Dispose();
00387 }
00388
00389 private bool IsDisposed;
00390
00392 public void Dispose()
00393 {
00394 this.Dispose(true);
00395 GC.SuppressFinalize(this);
00396 }
00397
00398 private void Dispose(bool manual)
00399 {
00400 if (!this.IsDisposed)
00401 {
00402 if (this.Handle != IntPtr.Zero)
00403 {
00404 if (this._isrecording)
00405 this.Stop();
00406
00407 Alc.CaptureCloseDevice(this.Handle);
00408 }
00409 this.IsDisposed = true;
00410 }
00411 }
00412
00413 #endregion Destructor
00414 }
00415 }