Accueil > > > ACQUISITION DE LA VOIX AVEC VISUALISATION DU SIGNAL
ACQUISITION DE LA VOIX AVEC VISUALISATION DU SIGNAL
Information sur la source
Description
Mon programme récupère le signal provenant d'un micro. Il affiche sous forme de graphique l'état du signal en live. Le son est enregistrer au format WAVE
Source
-
- using System;
- using System.Runtime.InteropServices; // For the DLLImport
- using System.Text; // For the SrtingBuilders
- using System.Threading; // To use threads
- using System.IO; // To use files
- using AudioRepresentationClass;
- using Softphone;
-
- namespace VoiceStreamsFunctions
- {
- /// <summary>
- /// VoiceStreamsFunctions = it containes the functions related to retreive the voice and save it in a wave file
- /// </summary>
-
- #region Aliases
- using HWAVEIN = System.IntPtr; // Handler on Input Wave
- using HWAVEOUT = System.IntPtr; // Handler on Ouout Wave
- using WAVEHDR = System.IntPtr; // Pointer on a structure of a Wave file
- #endregion
-
- #region Wave Format Tag
- public enum WaveFormatTag : ushort
- {
- UNKNOWN = 0x0000, /* Microsoft Corporation */
- PCM = 0x0001, /* Microsoft Corporation */
-
- EXTENSIBLE = 0xFFFE /* Microsoft */
- }
- #endregion
-
- public class VoiceFunction
- {
-
- #region DLL Import
- /// <summary>
- /// DLL Import :
- /// There are many because we use the CLS Multimedia functions.
- /// </summary>
-
- [DllImport ("winmm.dll")]
- public static extern int mciSendString(String s1, StringBuilder s2, int l1, int l2); // Multimedia Control Interface : Command Line
- [DllImport ("winmm.dll")]
- public static extern int mciGetErrorString(int l1, StringBuilder s1, int l2); // Error Handler
-
- [DllImport ("winmm.dll")] // Open the communication with the MIC
- public static extern int waveInOpen(out IntPtr hWaveIn, int uDeviceID, ref WAVEFORMATEX lpFormat, FunctionDelegate dwCallback, IntPtr dwInstance, int dwFlags);
- // hWaveIn is a pointer to the handler
- // lpFormat is a pointer to WAVEFORMATEX structure
- // dwCallback specifies the address of the callback function
- // dwInstance specifies user-instance data passed to the callback mechanism
- // dwFlags is a flag for opening the device
-
- [DllImport ("winmm.dll")]
- public static extern int waveInStart( IntPtr hWaveIn ); // Starts recording
- [DllImport ("winmm.dll")]
- public static extern int waveInAddBuffer (IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh); // Buffer Handler
- [DllImport ("winmm.dll")]
- public static extern int waveInStop( IntPtr hWaveIn ); // Stop recording
- [DllImport ("winmm.dll")]
- public static extern int waveInClose(IntPtr hWaveIn); // Close the communication with the MIC
- [DllImport ("winmm.dll")]
- public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh ); // Prepare the header to create a wave file
- [DllImport ("winmm.dll")]
- public static extern int waveInUnprepareHeader( IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh ); // Cleans up the header
- #endregion
-
- // Variables
- private string WorkingDir; // Working directory
- private HWAVEOUT hWaveIn; // Handler to WAVE IN
-
- private IntPtr dwInstance; // Pointeur on callback instance
- private int dwFlags; // Openning Flag
- private WAVEFORMATEX StrcutWaveFMT; // Wave format
- private WAVEHDR StructWaveHeader; // Buffer handle
- private StringBuilder errorBuffer; // Error Buffer
- private bool StillRecording; // To check if we are currently recording
- private object MyLock; // Lock for variable acces in mutlithread environment
- private GCHandle HeaderDataHandle; // To recover data from unmanaged memory
- private int BufSize; // Recording buffer
- private AudioRepresentation DFunct; // To call the audio representation class
- private System.Windows.Forms.TextBox textBoxVFunct;
- private byte[] ByteArray; // Array which contains A DATA CHUNK sent by the MIC
- private byte[] TempArray; // Array which contains ALL THE DATA sent by the MIC
- private int n; // index for storing in TempArray
- private int Index; // index for storing in TempArray
- private char FileSize1;
- private char FileSize2;
- private char FileSize3;
- private char FileSize4;
-
- // Callback
- public delegate void FunctionDelegate(IntPtr hWaveIn, uint Msg, int dwInstance, ref WAVEHDR dwParam1, int dwParam2);
- private FunctionDelegate dwCallback;
-
-
- #region ThreadHandle
- Thread RecordingThread; // Thread which handles the recording
- Thread RecordHandleThread; // It launches the record function
- #endregion
-
- #region Constants
- private const int WAVE_MAPPER = -1; // ID of the default MIC
- private const int WHDR_PREPARED = 0; // States that buffers are prepared by windows multimedia function
- private const int MM_WIM_OPEN = 0x3BE; // Message send by the audio device when it is opened by the application
- private const int MM_WIM_CLOSE = 0x3BF; // Message send by the audio device when it is closed by the application
- private const int MM_WIM_DATA = 0x3C0; // Message send by the audio device when a buffer is full
- private const int CALLBACK_FUNCTION = 0x30000; // I specify that the callback is handled by a function
- private const int MaxRecord = 512000; // FOR DEBUG ONLY !
- #endregion
-
- #region Struct WAVEHDR
- public struct WAVEHDR
- {
- public IntPtr lpData;
- public int dwBufferLength;
- public int dwBytesRecorded;
- public IntPtr dwUser;
- public int dwFlags;
- public int dwLoops;
- public IntPtr lpNext; // Reserved
- public IntPtr reserved; // Reserved
-
- public static WAVEHDR Empty
- {
- get{return new WAVEHDR();}
- }
- public static int SizeOfEmptyWAVEHDR ()
- {
- return 28;
- }
- }
- #endregion
-
- #region Struct WAVEFORMATEX
- public struct WAVEFORMATEX
- {
- public WaveFormatTag formatTag;
- public short nChannels;
- public int nSamplesPerSec;
- public int nAvgBytesPerSec;
- public short nBlockAlign;
- public short wBitsPerSample;
- public short cbSize;
- public byte extraInfo;
-
- public WAVEFORMATEX(int rate, int bits, int channels)
- {
- formatTag = WaveFormatTag.PCM;
- nChannels = (short)channels;
- nSamplesPerSec = rate;
- wBitsPerSample = (short)bits;
- cbSize = 0;
- nBlockAlign = (short)(channels * (bits / 8));
- nAvgBytesPerSec = nSamplesPerSec * nBlockAlign;
- extraInfo = 0;
- }
-
- public static WAVEFORMATEX Empty
- {
- get{return new WAVEFORMATEX();}
- }
-
- public static int SizeOfEmpty
- {
- get{return 18;}
- }
-
- public int SizeOf
- {
- get{return (SizeOfEmpty + cbSize);}
- }
-
- }
- #endregion
-
- // Initialise
- public VoiceFunction(string wdir, int BufferSize, System.Windows.Forms.TextBox textBox, AudioRepresentation DisplayFunct)
- {
- this.WorkingDir = wdir; // I set the working directory for my functions
- this.errorBuffer = new StringBuilder(128,128); // Juste in case ;)
- this.hWaveIn = IntPtr.Zero;
- this.dwCallback = new FunctionDelegate(waveInProc); // Pointeur on callback function
- this.dwInstance = IntPtr.Zero;
- this.dwFlags = CALLBACK_FUNCTION;
- this.RecordingThread = new Thread(new ThreadStart( StartRec ));
- this.RecordingThread.Name = "PickUpSound";
- this.RecordHandleThread = new Thread(new ThreadStart( RecordHandle ));
- this.RecordHandleThread.Name = "RecordManager";
- this.StillRecording = false;
- this.BufSize = BufferSize;
- this.MyLock = new object(); // Lock for variable access in mutlithread environment
- this.TempArray = new byte[MaxRecord]; // I store everything and I will write in a file afterwards
- this.n = -1; // index for recording
- this.Index = 0;
- this.textBoxVFunct = textBox;
- this.DFunct = DisplayFunct;
- }
-
- // Record Launcher, called by the main
- public void RecordLauncher()
- {
- this.RecordHandleThread.Start(); // I launch the thread which will handle all the recording process
- }
-
-
- // Record Handle
- private void RecordHandle()
- {
- int RetVal = 0;
-
- PrepareFormat();
- RetVal = OpenComm();
- //this.DFunct = new AudioRepresentation(this.BufSize);
- if(RetVal ==1)
- {
- Record();
- }
-
- // The end of the recording is handled by the user, when she clicks on the appropriate button
- }
-
-
- // Prepare the format
- private void PrepareFormat()
- {
- this.StrcutWaveFMT = WAVEFORMATEX.Empty;
-
- // Init wave format
- this.StrcutWaveFMT.formatTag = WaveFormatTag.PCM;
- this.StrcutWaveFMT.nChannels = 1; // MONO
- this.StrcutWaveFMT.nSamplesPerSec = 11025; // Samples per Second
- this.StrcutWaveFMT.wBitsPerSample = 8; // Bits per Sample
- this.StrcutWaveFMT.nBlockAlign = (short)(StrcutWaveFMT.nChannels * (StrcutWaveFMT.wBitsPerSample/8));
- this.StrcutWaveFMT.nAvgBytesPerSec = StrcutWaveFMT.nSamplesPerSec * StrcutWaveFMT.nBlockAlign;
- this.StrcutWaveFMT.cbSize = 0;
- }
-
- // Open the communication with the audio input device, error ID N°1
- private int OpenComm ()
- {
- int ReturnVal = 0;
-
- // WAVE_MAPPER is a constant defined in mmsystem.h at -1, it take the default MIC
- int err = waveInOpen(out this.hWaveIn, WAVE_MAPPER, ref this.StrcutWaveFMT, this.dwCallback, this.dwInstance, this.dwFlags);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 1";
- }
- else ReturnVal =1;
- return(ReturnVal);
- }
-
- // Record, error ID N°3, 4 and 5
- private void Record ()
- {
- int RetVal = 0;
-
- Monitor.Enter(MyLock);
- RetVal = PrepareHeader (); // Error 3
- if(RetVal == 1)
- {
- PrepareBuffer (); // Error 4
- }
-
- Monitor.Exit(MyLock);
-
- // We create a thread to handle all the recording
- this.StillRecording = true;
- this.RecordingThread.Priority = ThreadPriority.Highest;
- this.RecordingThread.Start();
- this.RecordingThread.Join();
- }
-
- // Prepare Header
- private int PrepareHeader ()
- {
- int RetVal = 0;
-
- // Prepare the buffer
- this.StructWaveHeader = WAVEHDR.Empty;
- this.StructWaveHeader.dwBufferLength = BufSize;
- this.StructWaveHeader.dwFlags = WHDR_PREPARED;
-
- this.ByteArray = new byte[BufSize];
- HeaderDataHandle = GCHandle.Alloc(this.ByteArray, GCHandleType.Pinned);
- this.StructWaveHeader.lpData = HeaderDataHandle.AddrOfPinnedObject();
- this.StructWaveHeader.dwUser = (IntPtr)GCHandle.Alloc(this);
-
- int IntTmp = Marshal.SizeOf(this.StructWaveHeader);
- uint UIntTmp = Convert.ToUInt32(IntTmp);
-
- int err = waveInPrepareHeader(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 3";
- }
- else RetVal = 1;
- return(RetVal);
- }
-
- // Unprepare Header
- private void UnPrepareHeader()
- {
- int IntTmp = BufSize + WAVEHDR.SizeOfEmptyWAVEHDR();
- uint UIntTmp = Convert.ToUInt32(IntTmp);
-
- int err = waveInUnprepareHeader(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 6";
- }
- }
-
- // Prepare Buffer
- private void PrepareBuffer ()
- {
- int IntTmp = BufSize + WAVEHDR.SizeOfEmptyWAVEHDR();
- uint UIntTmp = Convert.ToUInt32(IntTmp);
-
- int err = waveInAddBuffer(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 4";
- }
- }
-
- // Start Recording
- private void StartRec ()
- {
- Monitor.Enter(MyLock);
- int err = waveInStart(this.hWaveIn);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 5";
- }
- Monitor.Exit(MyLock);
- }
-
-
- // Listens to the message that the audio device sends
- // It enables to retreive the data when a buffer has been filled
- private void waveInProc(IntPtr hWaveIn, uint Msg, int dwInstance, ref WAVEHDR dwParam1, int dwParam2)
- {
- /*
- ATTENTION:
- Don't call any system-function in waveInProc
- */
- int correcting_factor = 0;
-
- switch(Msg)
- {
- case MM_WIM_DATA:
-
- if (StillRecording == true) // we are still recording
- {
- // File recording
- this.n++;
- for (int i = 0; i<dwParam1.dwBytesRecorded; i++)
- {
- this.Index = (BufSize*this.n)+i;
- correcting_factor = (int)this.ByteArray[i];
- correcting_factor = (int)(correcting_factor/2);
- this.TempArray[this.Index] = (byte)correcting_factor;
- DFunct.GetDataToDisplay(correcting_factor);
- }
-
- // Prepare the next stage of recording
- UnPrepareHeader();
- dwParam1.lpData = IntPtr.Zero;
- dwParam1.dwBytesRecorded = 0;
- HeaderDataHandle.Free();
-
- // We now sent another buffer to capture another chunk of data
- PrepareHeader ();
- PrepareBuffer ();
- }
- break;
-
- case MM_WIM_OPEN:
- break;
-
- case MM_WIM_CLOSE:
- this.HeaderDataHandle.Free();
- break;
-
- default:
- this.textBoxVFunct.Text = "Unknonw message sent by the MIC";
- break;
- }
- }
-
-
- // Close communication, error ID N°2 and 6
- public int CloseComm ()
- {
- int RetVal = 0;
-
- // Stop Recording
- this.StillRecording = false;
-
-
- // We Stop the recording, error ID N°6
- int err = waveInStop(this.hWaveIn);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 7";
- }
- else
- {
- // We close the communication with the MIC, error ID N°2
- err = waveInClose(this.hWaveIn);
- if (err != 0)
- {
- int retval = mciGetErrorString(err, errorBuffer, 128);
- this.textBoxVFunct.Text = "WaveIn error 2";
- }
- else
- {
- RetVal = 1;
- // free the allocated memory
- this.errorBuffer = null;
- this.dwCallback = null;
- this.MyLock = null;
-
- // Now I write the file with the data I have just recorded
- PrepareFile();
- }
- }
- return(RetVal);
- }
-
- #region ConvertToHexa
- private void ConvertToHexa(int IntToConvert)
- {
- int Current = IntToConvert;
- char[] rank = new char[8];
- int i = 0;
- char temp;
- int b = 0;
-
- do
- {
- rank[i] = (char)(Current%16);
- Current = (int)(Current/16);
- i++;
- }while(Current>16);
- rank[i] = (char)(Current);
- if (i<7)
- {
- do{
- rank[i] = (char)0;
- }while(i==7);
- }
-
- // invert the values in rank[]
- for(int a=i;a>=b;a--)
- {
- temp = rank[a];
- rank[a] = rank[b];
- rank[b] = temp;
- b++;
- }
-
- // The expression is inverted in the File :)
- this.FileSize1 = (char)(rank[6]*16 + rank[7]);
- this.FileSize2 = (char)(rank[4]*16 + rank[5]);
- this.FileSize3 = (char)(rank[2]*16 + rank[3]);
- this.FileSize4 = (char)(rank[0]*16 + rank[1]);
- }
- #endregion
-
- #region Write the recorded WAVE
- private void PrepareFile()
- {
-
-
- // File handling
- Directory.CreateDirectory(this.WorkingDir);
- string FileToCreate = this.WorkingDir + "/AudioFile.wav";
- StreamWriter AudioFile = new StreamWriter(FileToCreate,false,ASCIIEncoding.Default,1024);
- this.WorkingDir = null;
-
- char FormatLen1 = (char)0x10; // size of the header chunk
- char FormatLen2 = (char)0x0;
- char FormatLen3 = (char)0x0;
- char FormatLen4 = (char)0x0;
- char AudioFormat1 = (char)0x1; // PCM
- char AudioFormat2 = (char)0x0;
- char channel1 = (char)0x1; // channel
- char channel2 = (char)0x0;
- char SampleRate1 = (char)0x11; // sample rate
- char SampleRate2 = (char)0x2B;
- char SampleRate3 = (char)0x0;
- char SampleRate4 = (char)0x0;
- char BlockAlign1 = (char)0x1;
- char BlockAlign2 = (char)0x0;
- char BitsPerSample1 = (char)0x8;
- char BitsPerSample2 = (char)0x0;
-
- // copy of the header
- //RIFF CHUNK
- AudioFile.Write("RIFF");
- ConvertToHexa(this.Index+44);
- AudioFile.Write(this.FileSize1); // I will replace these 4 bits by the total size of the Wave File
- AudioFile.Write(this.FileSize2);
- AudioFile.Write(this.FileSize3);
- AudioFile.Write(this.FileSize4);
-
-
- AudioFile.Write("WAVE");
- // Format Chunk
- AudioFile.Write("fmt ");
- AudioFile.Write(FormatLen1);
- AudioFile.Write(FormatLen2);
- AudioFile.Write(FormatLen3);
- AudioFile.Write(FormatLen4);
- AudioFile.Write(AudioFormat1);
- AudioFile.Write(AudioFormat2);
- AudioFile.Write(channel1);
- AudioFile.Write(channel2);
- AudioFile.Write(SampleRate1);
- AudioFile.Write(SampleRate2);
- AudioFile.Write(SampleRate3);
- AudioFile.Write(SampleRate4);
- AudioFile.Write(SampleRate1);
- AudioFile.Write(SampleRate2);
- AudioFile.Write(SampleRate3);
- AudioFile.Write(SampleRate4);
- AudioFile.Write(BlockAlign1);
- AudioFile.Write(BlockAlign2);
- AudioFile.Write(BitsPerSample1);
- AudioFile.Write(BitsPerSample2);
- // data chunk
- AudioFile.Write("data");
- ConvertToHexa(this.Index);
- AudioFile.Write(this.FileSize1);
- AudioFile.Write(this.FileSize2);
- AudioFile.Write(this.FileSize3);
- AudioFile.Write(this.FileSize4);
-
- // data
- for(int i=0; i<this.Index;i++)
- {
- AudioFile.Write((char)this.TempArray[i]);
- }
-
- AudioFile.Close();
-
- }
- #endregion
-
- // destructor
- ~VoiceFunction()
- {
-
- }
- } // End of class VoiceFunction
- } // End of namespace
-
- using System;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Collections;
- using System.ComponentModel;
- using System.Windows.Forms;
- using System.Data;
- using Softphone; // To draw the graph
-
- namespace AudioRepresentationClass
- {
- public class AudioRepresentation
- {
- // Variables
- private int AudioSigSize;
- private short[] GetAudioSig;
- private short[] DisplayAudioSig;
- private int n;
- private Graphics dc;
- private Form1 MainHandler;
-
-
- public AudioRepresentation(int BufSize, Graphics graph, Form1 Handler)
- {
- this.AudioSigSize = BufSize; // Audio chunks
- this.GetAudioSig = new short[this.AudioSigSize];
- this.DisplayAudioSig = new short[this.AudioSigSize];
- this.n = 0;
- this.dc = graph;
- this.MainHandler = Handler;
- }
-
-
- public void GetDataToDisplay(int DataValue)
- {
- this.GetAudioSig[this.n] = (short)(DataValue-60);
- this.n++;
- if(this.n == this.AudioSigSize) // A buffer has been filled !
- {
- this.GetAudioSig.CopyTo(DisplayAudioSig,0);
- DefineGraph();
- this.n = 0;
- }
- }
-
-
- private void DefineGraph()
- {
- // Init the graph
- int X = 55;
- int Y = 10;
- int var1 = 0; // Y position
- int var2 = 0; // X2
- int j = 0;
-
- this.MainHandler.Refresh();
- while(j < this.AudioSigSize)
- {
- var1 = Y + (int)(j/2);
- var2 = X - (int)((this.DisplayAudioSig[j]*50)/128); // *50/128 is to adapt to the 50 px space I have
- // Draw a line > TOOL.color, Y1 = Position from the left side, X1 = position from the top side, Y2, X2
- this.dc.DrawLine(Pens.Red,var1,X,var1,var2);
- j++;
- }
- } // end of DefineGraph()
-
- } // end of class AudioRepresentation
- } //end of namespace AudioRepresentationClass
using System;
using System.Runtime.InteropServices; // For the DLLImport
using System.Text; // For the SrtingBuilders
using System.Threading; // To use threads
using System.IO; // To use files
using AudioRepresentationClass;
using Softphone;
namespace VoiceStreamsFunctions
{
/// <summary>
/// VoiceStreamsFunctions = it containes the functions related to retreive the voice and save it in a wave file
/// </summary>
#region Aliases
using HWAVEIN = System.IntPtr; // Handler on Input Wave
using HWAVEOUT = System.IntPtr; // Handler on Ouout Wave
using WAVEHDR = System.IntPtr; // Pointer on a structure of a Wave file
#endregion
#region Wave Format Tag
public enum WaveFormatTag : ushort
{
UNKNOWN = 0x0000, /* Microsoft Corporation */
PCM = 0x0001, /* Microsoft Corporation */
EXTENSIBLE = 0xFFFE /* Microsoft */
}
#endregion
public class VoiceFunction
{
#region DLL Import
/// <summary>
/// DLL Import :
/// There are many because we use the CLS Multimedia functions.
/// </summary>
[DllImport ("winmm.dll")]
public static extern int mciSendString(String s1, StringBuilder s2, int l1, int l2); // Multimedia Control Interface : Command Line
[DllImport ("winmm.dll")]
public static extern int mciGetErrorString(int l1, StringBuilder s1, int l2); // Error Handler
[DllImport ("winmm.dll")] // Open the communication with the MIC
public static extern int waveInOpen(out IntPtr hWaveIn, int uDeviceID, ref WAVEFORMATEX lpFormat, FunctionDelegate dwCallback, IntPtr dwInstance, int dwFlags);
// hWaveIn is a pointer to the handler
// lpFormat is a pointer to WAVEFORMATEX structure
// dwCallback specifies the address of the callback function
// dwInstance specifies user-instance data passed to the callback mechanism
// dwFlags is a flag for opening the device
[DllImport ("winmm.dll")]
public static extern int waveInStart( IntPtr hWaveIn ); // Starts recording
[DllImport ("winmm.dll")]
public static extern int waveInAddBuffer (IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh); // Buffer Handler
[DllImport ("winmm.dll")]
public static extern int waveInStop( IntPtr hWaveIn ); // Stop recording
[DllImport ("winmm.dll")]
public static extern int waveInClose(IntPtr hWaveIn); // Close the communication with the MIC
[DllImport ("winmm.dll")]
public static extern int waveInPrepareHeader(IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh ); // Prepare the header to create a wave file
[DllImport ("winmm.dll")]
public static extern int waveInUnprepareHeader( IntPtr hWaveIn, ref WAVEHDR pWaveHDR, uint cbwh ); // Cleans up the header
#endregion
// Variables
private string WorkingDir; // Working directory
private HWAVEOUT hWaveIn; // Handler to WAVE IN
private IntPtr dwInstance; // Pointeur on callback instance
private int dwFlags; // Openning Flag
private WAVEFORMATEX StrcutWaveFMT; // Wave format
private WAVEHDR StructWaveHeader; // Buffer handle
private StringBuilder errorBuffer; // Error Buffer
private bool StillRecording; // To check if we are currently recording
private object MyLock; // Lock for variable acces in mutlithread environment
private GCHandle HeaderDataHandle; // To recover data from unmanaged memory
private int BufSize; // Recording buffer
private AudioRepresentation DFunct; // To call the audio representation class
private System.Windows.Forms.TextBox textBoxVFunct;
private byte[] ByteArray; // Array which contains A DATA CHUNK sent by the MIC
private byte[] TempArray; // Array which contains ALL THE DATA sent by the MIC
private int n; // index for storing in TempArray
private int Index; // index for storing in TempArray
private char FileSize1;
private char FileSize2;
private char FileSize3;
private char FileSize4;
// Callback
public delegate void FunctionDelegate(IntPtr hWaveIn, uint Msg, int dwInstance, ref WAVEHDR dwParam1, int dwParam2);
private FunctionDelegate dwCallback;
#region ThreadHandle
Thread RecordingThread; // Thread which handles the recording
Thread RecordHandleThread; // It launches the record function
#endregion
#region Constants
private const int WAVE_MAPPER = -1; // ID of the default MIC
private const int WHDR_PREPARED = 0; // States that buffers are prepared by windows multimedia function
private const int MM_WIM_OPEN = 0x3BE; // Message send by the audio device when it is opened by the application
private const int MM_WIM_CLOSE = 0x3BF; // Message send by the audio device when it is closed by the application
private const int MM_WIM_DATA = 0x3C0; // Message send by the audio device when a buffer is full
private const int CALLBACK_FUNCTION = 0x30000; // I specify that the callback is handled by a function
private const int MaxRecord = 512000; // FOR DEBUG ONLY !
#endregion
#region Struct WAVEHDR
public struct WAVEHDR
{
public IntPtr lpData;
public int dwBufferLength;
public int dwBytesRecorded;
public IntPtr dwUser;
public int dwFlags;
public int dwLoops;
public IntPtr lpNext; // Reserved
public IntPtr reserved; // Reserved
public static WAVEHDR Empty
{
get{return new WAVEHDR();}
}
public static int SizeOfEmptyWAVEHDR ()
{
return 28;
}
}
#endregion
#region Struct WAVEFORMATEX
public struct WAVEFORMATEX
{
public WaveFormatTag formatTag;
public short nChannels;
public int nSamplesPerSec;
public int nAvgBytesPerSec;
public short nBlockAlign;
public short wBitsPerSample;
public short cbSize;
public byte extraInfo;
public WAVEFORMATEX(int rate, int bits, int channels)
{
formatTag = WaveFormatTag.PCM;
nChannels = (short)channels;
nSamplesPerSec = rate;
wBitsPerSample = (short)bits;
cbSize = 0;
nBlockAlign = (short)(channels * (bits / 8));
nAvgBytesPerSec = nSamplesPerSec * nBlockAlign;
extraInfo = 0;
}
public static WAVEFORMATEX Empty
{
get{return new WAVEFORMATEX();}
}
public static int SizeOfEmpty
{
get{return 18;}
}
public int SizeOf
{
get{return (SizeOfEmpty + cbSize);}
}
}
#endregion
// Initialise
public VoiceFunction(string wdir, int BufferSize, System.Windows.Forms.TextBox textBox, AudioRepresentation DisplayFunct)
{
this.WorkingDir = wdir; // I set the working directory for my functions
this.errorBuffer = new StringBuilder(128,128); // Juste in case ;)
this.hWaveIn = IntPtr.Zero;
this.dwCallback = new FunctionDelegate(waveInProc); // Pointeur on callback function
this.dwInstance = IntPtr.Zero;
this.dwFlags = CALLBACK_FUNCTION;
this.RecordingThread = new Thread(new ThreadStart( StartRec ));
this.RecordingThread.Name = "PickUpSound";
this.RecordHandleThread = new Thread(new ThreadStart( RecordHandle ));
this.RecordHandleThread.Name = "RecordManager";
this.StillRecording = false;
this.BufSize = BufferSize;
this.MyLock = new object(); // Lock for variable access in mutlithread environment
this.TempArray = new byte[MaxRecord]; // I store everything and I will write in a file afterwards
this.n = -1; // index for recording
this.Index = 0;
this.textBoxVFunct = textBox;
this.DFunct = DisplayFunct;
}
// Record Launcher, called by the main
public void RecordLauncher()
{
this.RecordHandleThread.Start(); // I launch the thread which will handle all the recording process
}
// Record Handle
private void RecordHandle()
{
int RetVal = 0;
PrepareFormat();
RetVal = OpenComm();
//this.DFunct = new AudioRepresentation(this.BufSize);
if(RetVal ==1)
{
Record();
}
// The end of the recording is handled by the user, when she clicks on the appropriate button
}
// Prepare the format
private void PrepareFormat()
{
this.StrcutWaveFMT = WAVEFORMATEX.Empty;
// Init wave format
this.StrcutWaveFMT.formatTag = WaveFormatTag.PCM;
this.StrcutWaveFMT.nChannels = 1; // MONO
this.StrcutWaveFMT.nSamplesPerSec = 11025; // Samples per Second
this.StrcutWaveFMT.wBitsPerSample = 8; // Bits per Sample
this.StrcutWaveFMT.nBlockAlign = (short)(StrcutWaveFMT.nChannels * (StrcutWaveFMT.wBitsPerSample/8));
this.StrcutWaveFMT.nAvgBytesPerSec = StrcutWaveFMT.nSamplesPerSec * StrcutWaveFMT.nBlockAlign;
this.StrcutWaveFMT.cbSize = 0;
}
// Open the communication with the audio input device, error ID N°1
private int OpenComm ()
{
int ReturnVal = 0;
// WAVE_MAPPER is a constant defined in mmsystem.h at -1, it take the default MIC
int err = waveInOpen(out this.hWaveIn, WAVE_MAPPER, ref this.StrcutWaveFMT, this.dwCallback, this.dwInstance, this.dwFlags);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 1";
}
else ReturnVal =1;
return(ReturnVal);
}
// Record, error ID N°3, 4 and 5
private void Record ()
{
int RetVal = 0;
Monitor.Enter(MyLock);
RetVal = PrepareHeader (); // Error 3
if(RetVal == 1)
{
PrepareBuffer (); // Error 4
}
Monitor.Exit(MyLock);
// We create a thread to handle all the recording
this.StillRecording = true;
this.RecordingThread.Priority = ThreadPriority.Highest;
this.RecordingThread.Start();
this.RecordingThread.Join();
}
// Prepare Header
private int PrepareHeader ()
{
int RetVal = 0;
// Prepare the buffer
this.StructWaveHeader = WAVEHDR.Empty;
this.StructWaveHeader.dwBufferLength = BufSize;
this.StructWaveHeader.dwFlags = WHDR_PREPARED;
this.ByteArray = new byte[BufSize];
HeaderDataHandle = GCHandle.Alloc(this.ByteArray, GCHandleType.Pinned);
this.StructWaveHeader.lpData = HeaderDataHandle.AddrOfPinnedObject();
this.StructWaveHeader.dwUser = (IntPtr)GCHandle.Alloc(this);
int IntTmp = Marshal.SizeOf(this.StructWaveHeader);
uint UIntTmp = Convert.ToUInt32(IntTmp);
int err = waveInPrepareHeader(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 3";
}
else RetVal = 1;
return(RetVal);
}
// Unprepare Header
private void UnPrepareHeader()
{
int IntTmp = BufSize + WAVEHDR.SizeOfEmptyWAVEHDR();
uint UIntTmp = Convert.ToUInt32(IntTmp);
int err = waveInUnprepareHeader(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 6";
}
}
// Prepare Buffer
private void PrepareBuffer ()
{
int IntTmp = BufSize + WAVEHDR.SizeOfEmptyWAVEHDR();
uint UIntTmp = Convert.ToUInt32(IntTmp);
int err = waveInAddBuffer(this.hWaveIn, ref this.StructWaveHeader, UIntTmp);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 4";
}
}
// Start Recording
private void StartRec ()
{
Monitor.Enter(MyLock);
int err = waveInStart(this.hWaveIn);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 5";
}
Monitor.Exit(MyLock);
}
// Listens to the message that the audio device sends
// It enables to retreive the data when a buffer has been filled
private void waveInProc(IntPtr hWaveIn, uint Msg, int dwInstance, ref WAVEHDR dwParam1, int dwParam2)
{
/*
ATTENTION:
Don't call any system-function in waveInProc
*/
int correcting_factor = 0;
switch(Msg)
{
case MM_WIM_DATA:
if (StillRecording == true) // we are still recording
{
// File recording
this.n++;
for (int i = 0; i<dwParam1.dwBytesRecorded; i++)
{
this.Index = (BufSize*this.n)+i;
correcting_factor = (int)this.ByteArray[i];
correcting_factor = (int)(correcting_factor/2);
this.TempArray[this.Index] = (byte)correcting_factor;
DFunct.GetDataToDisplay(correcting_factor);
}
// Prepare the next stage of recording
UnPrepareHeader();
dwParam1.lpData = IntPtr.Zero;
dwParam1.dwBytesRecorded = 0;
HeaderDataHandle.Free();
// We now sent another buffer to capture another chunk of data
PrepareHeader ();
PrepareBuffer ();
}
break;
case MM_WIM_OPEN:
break;
case MM_WIM_CLOSE:
this.HeaderDataHandle.Free();
break;
default:
this.textBoxVFunct.Text = "Unknonw message sent by the MIC";
break;
}
}
// Close communication, error ID N°2 and 6
public int CloseComm ()
{
int RetVal = 0;
// Stop Recording
this.StillRecording = false;
// We Stop the recording, error ID N°6
int err = waveInStop(this.hWaveIn);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 7";
}
else
{
// We close the communication with the MIC, error ID N°2
err = waveInClose(this.hWaveIn);
if (err != 0)
{
int retval = mciGetErrorString(err, errorBuffer, 128);
this.textBoxVFunct.Text = "WaveIn error 2";
}
else
{
RetVal = 1;
// free the allocated memory
this.errorBuffer = null;
this.dwCallback = null;
this.MyLock = null;
// Now I write the file with the data I have just recorded
PrepareFile();
}
}
return(RetVal);
}
#region ConvertToHexa
private void ConvertToHexa(int IntToConvert)
{
int Current = IntToConvert;
char[] rank = new char[8];
int i = 0;
char temp;
int b = 0;
do
{
rank[i] = (char)(Current%16);
Current = (int)(Current/16);
i++;
}while(Current>16);
rank[i] = (char)(Current);
if (i<7)
{
do{
rank[i] = (char)0;
}while(i==7);
}
// invert the values in rank[]
for(int a=i;a>=b;a--)
{
temp = rank[a];
rank[a] = rank[b];
rank[b] = temp;
b++;
}
// The expression is inverted in the File :)
this.FileSize1 = (char)(rank[6]*16 + rank[7]);
this.FileSize2 = (char)(rank[4]*16 + rank[5]);
this.FileSize3 = (char)(rank[2]*16 + rank[3]);
this.FileSize4 = (char)(rank[0]*16 + rank[1]);
}
#endregion
#region Write the recorded WAVE
private void PrepareFile()
{
// File handling
Directory.CreateDirectory(this.WorkingDir);
string FileToCreate = this.WorkingDir + "/AudioFile.wav";
StreamWriter AudioFile = new StreamWriter(FileToCreate,false,ASCIIEncoding.Default,1024);
this.WorkingDir = null;
char FormatLen1 = (char)0x10; // size of the header chunk
char FormatLen2 = (char)0x0;
char FormatLen3 = (char)0x0;
char FormatLen4 = (char)0x0;
char AudioFormat1 = (char)0x1; // PCM
char AudioFormat2 = (char)0x0;
char channel1 = (char)0x1; // channel
char channel2 = (char)0x0;
char SampleRate1 = (char)0x11; // sample rate
char SampleRate2 = (char)0x2B;
char SampleRate3 = (char)0x0;
char SampleRate4 = (char)0x0;
char BlockAlign1 = (char)0x1;
char BlockAlign2 = (char)0x0;
char BitsPerSample1 = (char)0x8;
char BitsPerSample2 = (char)0x0;
// copy of the header
//RIFF CHUNK
AudioFile.Write("RIFF");
ConvertToHexa(this.Index+44);
AudioFile.Write(this.FileSize1); // I will replace these 4 bits by the total size of the Wave File
AudioFile.Write(this.FileSize2);
AudioFile.Write(this.FileSize3);
AudioFile.Write(this.FileSize4);
AudioFile.Write("WAVE");
// Format Chunk
AudioFile.Write("fmt ");
AudioFile.Write(FormatLen1);
AudioFile.Write(FormatLen2);
AudioFile.Write(FormatLen3);
AudioFile.Write(FormatLen4);
AudioFile.Write(AudioFormat1);
AudioFile.Write(AudioFormat2);
AudioFile.Write(channel1);
AudioFile.Write(channel2);
AudioFile.Write(SampleRate1);
AudioFile.Write(SampleRate2);
AudioFile.Write(SampleRate3);
AudioFile.Write(SampleRate4);
AudioFile.Write(SampleRate1);
AudioFile.Write(SampleRate2);
AudioFile.Write(SampleRate3);
AudioFile.Write(SampleRate4);
AudioFile.Write(BlockAlign1);
AudioFile.Write(BlockAlign2);
AudioFile.Write(BitsPerSample1);
AudioFile.Write(BitsPerSample2);
// data chunk
AudioFile.Write("data");
ConvertToHexa(this.Index);
AudioFile.Write(this.FileSize1);
AudioFile.Write(this.FileSize2);
AudioFile.Write(this.FileSize3);
AudioFile.Write(this.FileSize4);
// data
for(int i=0; i<this.Index;i++)
{
AudioFile.Write((char)this.TempArray[i]);
}
AudioFile.Close();
}
#endregion
// destructor
~VoiceFunction()
{
}
} // End of class VoiceFunction
} // End of namespace
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Softphone; // To draw the graph
namespace AudioRepresentationClass
{
public class AudioRepresentation
{
// Variables
private int AudioSigSize;
private short[] GetAudioSig;
private short[] DisplayAudioSig;
private int n;
private Graphics dc;
private Form1 MainHandler;
public AudioRepresentation(int BufSize, Graphics graph, Form1 Handler)
{
this.AudioSigSize = BufSize; // Audio chunks
this.GetAudioSig = new short[this.AudioSigSize];
this.DisplayAudioSig = new short[this.AudioSigSize];
this.n = 0;
this.dc = graph;
this.MainHandler = Handler;
}
public void GetDataToDisplay(int DataValue)
{
this.GetAudioSig[this.n] = (short)(DataValue-60);
this.n++;
if(this.n == this.AudioSigSize) // A buffer has been filled !
{
this.GetAudioSig.CopyTo(DisplayAudioSig,0);
DefineGraph();
this.n = 0;
}
}
private void DefineGraph()
{
// Init the graph
int X = 55;
int Y = 10;
int var1 = 0; // Y position
int var2 = 0; // X2
int j = 0;
this.MainHandler.Refresh();
while(j < this.AudioSigSize)
{
var1 = Y + (int)(j/2);
var2 = X - (int)((this.DisplayAudioSig[j]*50)/128); // *50/128 is to adapt to the 50 px space I have
// Draw a line > TOOL.color, Y1 = Position from the left side, X1 = position from the top side, Y2, X2
this.dc.DrawLine(Pens.Red,var1,X,var1,var2);
j++;
}
} // end of DefineGraph()
} // end of class AudioRepresentation
} //end of namespace AudioRepresentationClass
Conclusion
C'est là base d'une application de VoIP. Là c'est l'acquisition et le début du traitement de la voix. On trouve beaucoup de sources en C++ mais pas en C#. Je me suis dit que ça pourrait être utile à certain. Je continue à travailler dessus, donc n'hésitez pas à me contacter. Voici mon site Web, je mettrai à jour mon projet de temps en temps: http://www.ece.fr/~gbonnet
Historique
- 16 mai 2006 11:32:54 :
- Juste pour dire: J'utilise de prog en tant que prototype pour une application de plus grande envergure. Je ne me suis donc pas amusé à tout blinder.
L'enregistrement va saturer si vous le laisser trop longtemps. Si vous voulez vous pouvez modifier la taille du tableau : TempArray.
J'enregistre en WAVE pour tester la qualité de la voix.
Si vous avez des commentaires, n'hésitez pas :)
- 29 mai 2006 10:48:59 :
- DSL, je pensais pourtant avoir inclu la Windows Form... J'ai remis à jour les fichiers et le Zip.
J'ai rajouté une fonction qui affiche l'ensemble du signal enregistré.
Maintenant j'aimerai appliquer un codec audio au son que j'enregistre, du type: g711 ou speex. ce n'est pas évident du tout. J'ai trouvé un exemple de code en C mais quand je l'adapte au C# je n'obtient pas un bon son du tout. Est ce que quelqu'un a déjà travaillé là dessus ?
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Acquisition et numérisation de la voix. [ par naoufal_chatt ]
Pour la mise en ?uvre d?u logiciel en vue d?échange de données de type voix sur un réseau je me demande si quelqu?un d?entre vous a déjà travaillé sur
travailler avec micro et haut-parleur [ par vtvdung ]
salut,Je veux creer un programme voice chat, mais je ne connais pas les fonctions pour capturer la voix du micro, et comment transmettre la voix vers
[Interface graphique] Recherche de composants style VisualStudio [ par ip2x ]
Bonsoir, je suis à la recherche de composants utilisés dans l'interface graphique de Visual Studio, à savoir :- Les volets deroulants à gauche et à dr
construire un graphique (courbe 2D) ?? [ par superkiller ]
bonjour,j'aurai souhaiter savoir comment creer des graphiques, des courbes 2D ou 3D en c# ? avec quel composant faut-il travailler ?j'utilise studio 2
Séparer l'interface graphique de la gestion des évènements [ par adaemon ]
Bonjour, je débute en C# et j'essaie de trouver la meilleure solution pour séparer l'interface graphique de la gestion des évènements liés aux objets
graphique [ par thr_dreamer_57 ]
Salut tout le monde, je suis sur le point de réaliser une application dans laquel j'ai besoin d'intégrer une zone graphique qui décrit le fonctionn
faire un effet graphique lié a un son (audiovideoplayback) [ par dehx ]
Salut !J'ai fait un lecteur audio avec AudioVideoPlayback de DirectX, l'application marche correctement, mais j'aimerais rajouter un petit effet graph
Graphique Zedgraph [ par floralies ]
Salut à tous !J'utilise la librairie Zedgraph pour dessiner un graphique. Seulement je n'arrive pas à changer le type de données des axes . par exempl
GDI : Graphique qui scintille [ par narfight ]
Bonjours,Je travail actuellement sur un programme en c# qui affiche dans un graphique ce que renvois une sonde de lumiére par le port rs232. Le problé
Changer de voix Microsoft [ par SatanicPunker ]
Bonjour, Je voudrais avoir un petit renseignement à propos des applications Text to Speech qui utilisent le Microsoft SpeechSDK.J'ai dév
|
Derniers Blogs
UNE JOLIE-HORLOGE ET PAS QU'UN PEU !UNE JOLIE-HORLOGE ET PAS QU'UN PEU ! par neodante
Pour les possesseurs d'iPhone, ça y est Bijin Tokei - qui se traduit littéralement en Français par " Jolie Horloge " - est arrivé et GRATUITEMENT s'il vous plaît ! Après la version Tokyo, Hokkaido, night club, racing, Gal, "pour les mademoiselles'", . voi...
Cliquez pour lire la suite de l'article par neodante TECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICESTECHDAYS PARIS 2010 : CONNECTEZ VOS DONNéES à SHAREPOINT 2010 AVEC LES BUSINESS CONNECTIVITY SERVICES par ROMELARD Fabrice
Animé par: Gaetan Bouveret et Julien Chomarat Business Connectivity Services (BCS) est dans SharePoint 2010 la version 2 de Business Data Catalog (BDC dans SharePoint 2007). Il s'agit de la solution permettant de visualiser des données provenan...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice [DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE[DIVERS] SUIVRE VOS SéRIES PRéFéRéS SUR LA TOILE par orion
Comme de nombreux geek, je suis un grand amateur de série TV et je rate régulièrement des épisodes de mes séries préférés. Une solution s'offre à vous avec ce merveilleux site : Tv Gorge - www.tvgorge.com Moteur de recherche à l'appui, vous pouvez ...
Cliquez pour lire la suite de l'article par orion TECHDAYS PARIS 2010 : LA BI DANS SHAREPOINT 2010TECHDAYS PARIS 2010 : LA BI DANS SHAREPOINT 2010 par ROMELARD Fabrice
Animé par: Vincent Bellet et Baptiste Giraudier La BI dans SharePoint 2010, Les nouveaux services d'application dans SP2010 et SQL Server Reporting services 2008 R2. La BI dans SharePoint est généralisée pour tous afin de permettre à tous les coll...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice
Logiciels
DB-MAIN (9.1.0)DB-MAIN (9.1.0)DB-MAIN is a data-modeling and data-architecture tool. It is designed to help developers and anal... Cliquez pour télécharger DB-MAIN Xilisoft DPG Convertisseur (5.1.37.0120)XILISOFT DPG CONVERTISSEUR (5.1.37.0120)Xilisoft DPG Convertisseur offre aux fans de Nintendo DS une bonne solution leur permettant de dé... Cliquez pour télécharger Xilisoft DPG Convertisseur GraphicsGale (2.01.01)GRAPHICSGALE (2.01.01)GraphicsGale est un logiciel de PixelArt avec de nombreuse fonctionnalités permettant de réalisé ... Cliquez pour télécharger GraphicsGale Architecte 3D (Platinum 2010)ARCHITECTE 3D (PLATINUM 2010)Architecte 3D Platinium vous permet de concevoir facilement les plans votre future maison, de l'é... Cliquez pour télécharger Architecte 3D TeamViewer 5 (TeamViewer 5)TEAMVIEWER 5 (TEAMVIEWER 5)Dépanner un ami,expliquer une manipulation devient un jeu d'enfant.
Prise en main d'un autre ord... Cliquez pour télécharger TeamViewer 5
|