Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

ACQUISITION DE LA VOIX AVEC VISUALISATION DU SIGNAL


Information sur la source

Catégorie :Multimédia Source .NET ( DotNet ) Classé sous : voix, acquisition, wave, graphique, micro Niveau : Débutant Date de création : 15/05/2006 Date de mise à jour : 29/05/2006 10:48:58 Vu / téléchargé: 14 107 / 1 300

Note :
9,5 / 10 - par 4 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (10)
Ajouter un commentaire et/ou une note

Description

Cliquez pour voir la capture en taille normale
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
 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

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 ?

Commentaires et avis

signaler à un administrateur
Commentaire de wizad le 16/05/2006 17:30:26

Ouch 773 ligne de code affiché... à éviter... (sauf pour battre un record codes cources :p)

signaler à un administrateur
Commentaire de MaxSoldier le 16/05/2006 22:28:14

Je suis pas vraiment sûr de la provenence du prog mais bon... ( "Copywrite Blueface 2006" et commentaires en anglais... ) Bref, sinon, bon prog !

signaler à un administrateur
Commentaire de MaxSoldier le 16/05/2006 22:30:23

Ah, autant pour moi je viens de lire ta présentation sur ton site, et c'est l'entreprise pour laquelle tu bosses :p ++

signaler à un administrateur
Commentaire de gbonnet_ece le 17/05/2006 10:22:23

Il y a pas mal de code oui. C'est qu'il faut utiliser toutes les fonctions multimedia de MSDN.
Blueface est la boite dans laquelle je fais un stage.
Désolé pour le copywrite, j'ai oublié de l'enlever. :)

signaler à un administrateur
Commentaire de iow4 le 18/05/2006 18:10:35

Je hate de tester ce code ;-)
Bien joué

signaler à un administrateur
Commentaire de programmateur le 28/05/2006 17:54:05