Moteur audio temps reel

Soyez le premier à donner votre avis sur cette source.

Vue 16 210 fois - Téléchargée 4 464 fois

Description

Fonctionnement: le signal en entrée ligne du PC sort directement à la sortie avec un léger retard du au temps de rotation de tous les buffers.

Ce code permet d'effectuer du traitement de signal en temps réel en modifiant le contenu du buffer (Buffer)

Source / Exemple :


#include <windows.h>
#include "stdafx.h"
#include "resource.h"
#include <mmsystem.h>
#include <malloc.h>
#include <stdio.h>
#include <commctrl.h>

#define BUFFER_SIZE 16384
#define SAMPLERATE 44100
#define CANAUX 2
#define OCTETS 2

HWND DlgMain;
PBYTE Buffer;
HWAVEIN hWaveIn;
HWAVEOUT hWaveOut;
PBYTE pBufferIn1, pBufferIn2, pBufferIn3, pBufferOut1, pBufferOut2, pBufferOut3;
PWAVEHDR pWaveHdrIn1, pWaveHdrIn2, pWaveHdrIn3, pWaveHdrOut1, pWaveHdrOut2, pWaveHdrOut3;
WAVEFORMATEX waveform;
BOOL flag_in_open = FALSE;
BOOL flag_out_open = FALSE;

HANDLE WorkerThreadHandleIn;
DWORD WorkerThreadIdIn;
HANDLE WorkerThreadHandleOut;
DWORD WorkerThreadIdOut;

//****************************************************************************

DWORD WINAPI WorkerThreadProcIn (void *Arg)
{
  SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
  MSG Msg;

  while (GetMessage (&Msg, NULL, 0, 0) == TRUE)
   {
    switch (Msg.message)
     {
      case MM_WIM_OPEN:
       {
        MessageBox(DlgMain,"In open","RTA",MB_OK);
        flag_in_open = TRUE;
        waveInAddBuffer(hWaveIn,pWaveHdrIn1,sizeof(WAVEHDR));
        waveInAddBuffer(hWaveIn,pWaveHdrIn2,sizeof(WAVEHDR));
        waveInAddBuffer(hWaveIn,pWaveHdrIn3,sizeof(WAVEHDR));
        waveInStart(hWaveIn);  
        break;
       }

      case MM_WIM_DATA:
       {
        WAVEHDR *Hdr = (WAVEHDR *)Msg.lParam;
        CopyMemory(Buffer,Hdr->lpData,BUFFER_SIZE);
        waveInAddBuffer (hWaveIn, Hdr, sizeof (*Hdr));
        break;
       }
     }
   }
  return 0; 
}

//****************************************************************************

DWORD WINAPI WorkerThreadProcOut (void *Arg)
{
  SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
  MSG Msg;

  while (GetMessage (&Msg, NULL, 0, 0) == TRUE)
   {
    switch (Msg.message)
     {
      case MM_WOM_OPEN:
       {
        MessageBox(DlgMain,"Out open","RTA",MB_OK);
        flag_out_open = TRUE;
        waveOutPrepareHeader(hWaveOut,pWaveHdrOut1,sizeof(WAVEHDR));
        waveOutWrite(hWaveOut,pWaveHdrOut1,sizeof(WAVEHDR));
        waveOutPrepareHeader(hWaveOut,pWaveHdrOut2,sizeof(WAVEHDR));
        waveOutWrite(hWaveOut,pWaveHdrOut2,sizeof(WAVEHDR));
        waveOutPrepareHeader(hWaveOut,pWaveHdrOut3,sizeof(WAVEHDR));
        waveOutWrite(hWaveOut,pWaveHdrOut3,sizeof(WAVEHDR));
        break;
       }

      case MM_WOM_DONE:
       {
        WAVEHDR *Hdr = (WAVEHDR *)Msg.lParam;
        waveOutPrepareHeader (hWaveOut, Hdr, sizeof (*Hdr));
        waveOutWrite (hWaveOut, Hdr, sizeof (*Hdr));
        CopyMemory(Hdr->lpData,Buffer,BUFFER_SIZE);
        break;
       }
     }
   }
  return 0; 
}

//****************************************************************************

BOOL CALLBACK DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{  

  static int volume_general;

  if (msg == WM_INITDIALOG)
   {
    DlgMain = hWnd;
    return 0;
   }

  if (msg == WM_COMMAND)
   {
    if (wParam == ID_START)
     {
      if(flag_in_open == TRUE)
       {
        MessageBox(hWnd,"périphérique déjà ouvert","Erreur",0);
        return 0;
       }
       
      WorkerThreadHandleIn = CreateThread (NULL, 0, WorkerThreadProcIn, NULL, 0, &WorkerThreadIdIn );
      WorkerThreadHandleOut = CreateThread (NULL, 0, WorkerThreadProcOut, NULL, 0, &WorkerThreadIdOut );
      pWaveHdrIn1 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      pWaveHdrIn2 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      pWaveHdrIn3 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      pWaveHdrOut1 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      pWaveHdrOut2 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      pWaveHdrOut3 = (PWAVEHDR) malloc(sizeof(WAVEHDR));
      
      Buffer   = (PBYTE)malloc(BUFFER_SIZE);
      pBufferIn1 = (PBYTE)malloc(BUFFER_SIZE);
      pBufferIn2 = (PBYTE)malloc(BUFFER_SIZE);
      pBufferIn3 = (PBYTE)malloc(BUFFER_SIZE);
      pBufferOut1 = (PBYTE)malloc(BUFFER_SIZE);
      pBufferOut2 = (PBYTE)malloc(BUFFER_SIZE);
      pBufferOut3 = (PBYTE)malloc(BUFFER_SIZE);
    
      if(!pBufferIn1 || !pBufferIn2 || !pBufferIn3 || !pBufferOut1 || !pBufferOut2 || !pBufferOut3)
       {
        if(pBufferIn1) free (pBufferIn1);
        if(pBufferIn2) free (pBufferIn2);
        if(pBufferIn3) free (pBufferIn3);
        if(pBufferOut1) free (pBufferOut1);
        if(pBufferOut2) free (pBufferOut2);
        if(pBufferOut3) free (pBufferOut3);
        MessageBox(hWnd,"Erreur d'allocation de mémoire","Erreur",0);
        return TRUE;
       }     
    
      waveform.nChannels = CANAUX; // 1 pour mono 2 pour stereo
      waveform.wBitsPerSample = 8 * OCTETS; // 8 ou 16 bit
      waveform.nAvgBytesPerSec = SAMPLERATE * waveform.nChannels * waveform.wBitsPerSample/8; // nombre d'octets par seconde
      waveform.wFormatTag = 1; // 1 pour PCM
      waveform.nSamplesPerSec = SAMPLERATE; // frequence d'echantillonnage
      waveform.nBlockAlign = 1;
      waveform.cbSize = 0;

      if(waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,(DWORD)WorkerThreadIdIn,0,CALLBACK_THREAD))
       {
        free(pBufferIn1);
        free(pBufferIn2);
        free(pBufferIn3);
        MessageBox(hWnd,"ouverture du périphérique d'entrée impossible","WARNING",MB_OK);
        return 0;
       }

      pWaveHdrIn1->lpData          = (LPSTR)pBufferIn1;
      pWaveHdrIn1->dwBufferLength  = BUFFER_SIZE;
      pWaveHdrIn1->dwBytesRecorded = 0;
      pWaveHdrIn1->dwUser          = 0;
      pWaveHdrIn1->dwFlags         = 0;
      pWaveHdrIn1->dwLoops         = 0;
      pWaveHdrIn1->lpNext          = NULL;
      pWaveHdrIn1->reserved        = 0;    
      waveInPrepareHeader(hWaveIn,pWaveHdrIn1,sizeof(WAVEHDR));
    
      pWaveHdrIn2->lpData          = (LPSTR)pBufferIn2;
      pWaveHdrIn2->dwBufferLength  = BUFFER_SIZE;
      pWaveHdrIn2->dwBytesRecorded = 0;
      pWaveHdrIn2->dwUser          = 0;
      pWaveHdrIn2->dwFlags         = 0;
      pWaveHdrIn2->dwLoops         = 0;
      pWaveHdrIn2->lpNext          = NULL;
      pWaveHdrIn2->reserved        = 0;    
      waveInPrepareHeader(hWaveIn,pWaveHdrIn2,sizeof(WAVEHDR));

      pWaveHdrIn3->lpData          = (LPSTR)pBufferIn3;
      pWaveHdrIn3->dwBufferLength  = BUFFER_SIZE;
      pWaveHdrIn3->dwBytesRecorded = 0;
      pWaveHdrIn3->dwUser          = 0;
      pWaveHdrIn3->dwFlags         = 0;
      pWaveHdrIn3->dwLoops         = 0;
      pWaveHdrIn3->lpNext          = NULL;
      pWaveHdrIn3->reserved        = 0;    
      waveInPrepareHeader(hWaveIn,pWaveHdrIn3,sizeof(WAVEHDR));      

      if(waveOutOpen(&hWaveOut,WAVE_MAPPER,&waveform,(DWORD)WorkerThreadIdOut,0,CALLBACK_THREAD))
       {
        free(pBufferOut1);
        free(pBufferOut2);
        free(pBufferOut3);
        MessageBox(hWnd,"ouverture du périphérique de sortie impossible","WARNING",MB_OK);
        return 0;
       }    

      pWaveHdrOut1->lpData = (LPSTR)pBufferOut1;
      pWaveHdrOut1->dwBufferLength = BUFFER_SIZE;
      pWaveHdrOut1->dwBytesRecorded = 0;
      pWaveHdrOut1->dwUser = 0;
      pWaveHdrOut1->dwFlags = 0;
      pWaveHdrOut1->dwLoops = 0;
      pWaveHdrOut1->lpNext = NULL;
      pWaveHdrOut1->reserved = 0;    
      waveOutPrepareHeader(hWaveOut,pWaveHdrOut1,sizeof(WAVEHDR));
    
      pWaveHdrOut2->lpData = (LPSTR)pBufferOut2;
      pWaveHdrOut2->dwBufferLength = BUFFER_SIZE;
      pWaveHdrOut2->dwBytesRecorded = 0;
      pWaveHdrOut2->dwUser = 0;
      pWaveHdrOut2->dwFlags = 0;
      pWaveHdrOut2->dwLoops = 0;
      pWaveHdrOut2->lpNext = NULL;
      pWaveHdrOut2->reserved = 0;    
      waveOutPrepareHeader(hWaveOut,pWaveHdrOut2,sizeof(WAVEHDR));
    
      pWaveHdrOut3->lpData =(LPSTR)pBufferOut3;
      pWaveHdrOut3->dwBufferLength =BUFFER_SIZE;
      pWaveHdrOut3->dwBytesRecorded =0;
      pWaveHdrOut3->dwUser =0;
      pWaveHdrOut3->dwFlags =0;
      pWaveHdrOut3->dwLoops =0;
      pWaveHdrOut3->lpNext =NULL;
      pWaveHdrOut3->reserved =0;    
      waveOutPrepareHeader(hWaveOut,pWaveHdrOut3,sizeof(WAVEHDR));      

      return 0;
     }

    if (wParam == IDCANCEL)
     {
      if(MessageBox(hWnd, "Voulez-vous vraiment arrêter l'application en cours ?", "Real Time Audio",MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2) == IDNO)
       {
        return TRUE;
       }
      EndDialog(hWnd, 0);
      return 0;
     }
   }

  return 0;
}

//****************************************************************************
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  InitCommonControls();
  DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1),HWND_DESKTOP,DlgProc);
  return 0;
}

//****************************************************************************

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

Messages postés
4
Date d'inscription
vendredi 31 octobre 2008
Statut
Membre
Dernière intervention
8 novembre 2013

hum... Et si un pur débutant de chez débutant souhaitait juste enregistrer le son entrant dans un genre de bloc note ?
Bon, je sais, ça ressemblerait presque à du sur mesure, mais... (et je m'explique peut-être mal, aussi, mais c'est juste pour le retoucher, j'ai envie de m'amuser à créer des programmes qui modifient les sons)
je crois que c'est beaucoup demander, quand même, du sur-mesure, mais bon... ?
Messages postés
53
Date d'inscription
jeudi 31 juillet 2003
Statut
Membre
Dernière intervention
28 mars 2007

salut TTNICOLAS,

C'est normal que le temps soit plus long, sachant que BUFFER_SIZE ne varie pas. C'est comme sur une route dont la longueur ne varie pas et la vitesse des voitures change, le temps pour faire toute la route varie en fonction de la vitesse des voitures.
Messages postés
2
Date d'inscription
jeudi 27 mai 2004
Statut
Membre
Dernière intervention
20 mai 2007

Salut gabuzomeuh. Bravo pour ta source, j'aimerai savoir pourquoi lorsque je dimminue la frequence d'echantillonage, le delai entre la lecture et la restitution est plus long ?. Sinon j'ai traduit ta source pour Borland Builder et je suis en train de la modifier pour transferer le son via ethernet, pour l'instant ca marche pendant seulement 5 secondes.
Messages postés
53
Date d'inscription
jeudi 31 juillet 2003
Statut
Membre
Dernière intervention
28 mars 2007

J'ai ajouté un SetThreadPriority pour chaque procédure In et Out mais ca ne change rien, quand la fenêtre est réduite ou restaurée, il y a une courte interruption du processus. Quelqu'un a une piste ?
Messages postés
53
Date d'inscription
jeudi 31 juillet 2003
Statut
Membre
Dernière intervention
28 mars 2007

Quand la fenêtre est réduite ou restaurée, il y a une courte interruption du processus.
Doit-on utiliser un thread ou un SetPriorityClass ou un EnterCriticalSection ?
Afficher les 20 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.