Télécharger le cours
Transcription
Télécharger le cours
U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Audio Numérique Leçon n°2 : DirectSound Gestion de base Pascal Mignot [email protected] Plateforme de développement U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Avantage de DirectSound DirectX: • gratuit • maximum de flexibilité (interface de bas niveau). • maximum de stabilité (largement testé) • réactivité aux dernières évolutions technologiques (suit de très prêt les évolutions du hardware). • gestion dynamique possible. Bibliothèques: • en général payante, • multi-plateforme • toujours quelques bugs, • basée sur DirectSound. Conclusion: autant avoir sa propre implémentation, sauf si les utilisations sont élémentaires. U N IVERSIT É D E R EIMS Technologie DirectSound C H AMP AGN E-A RD EN N E Permet de jouer des sons: • • avec un temps de latence très faible. avec un niveau de contrôle bas-niveau sur les ressources. Principale fonctionnalité: • • • • • jouer des fichiers ou des ressources au format WAV (non compressé). jouer des sons simultanément. appliquer des effets dynamiquement sur des sons (echo, chorus, ..). jouer des sons dans environnement 3D. capturer de son. Interface de gestion bas-niveau: une gestion haut-niveau est possible avec l’interface DirectMusic. Architecture de base de DirectSound pour la lecture de sons U N IVERSIT É D E R EIMS Propriétés du buffer secondaire C H AMP AGN E-A RD EN N E Buffer secondaire Buffer secondaire Effets Effets Buffer secondaire Effets 3D Propriétés du buffer primaire Emetteur Recepteur Buffer Primaire Son Mixé • • • le mixage a lieu dans le buffer primaire. le son est construit dans le buffer primaire avec les propriétés fixées pour la carte son (mono, stéréo, 5.1), échantillonnage, … la carte son est virtuelle: les opérations effectuées sur la carte son dépendent des fonctionnalités de celles-ci. U N IVERSIT É D E R EIMS Niveau de coopération C H AMP AGN E-A RD EN N E Lorsqu’un périphérique est unique ou susceptible d’être partagé sur un système, il faut déterminer l’interaction de l’application: – avec le périphérique. – avec les autres applications qui utilisent le même périphérique. • Mode Exclusif (DSSCL_EXCLUSIVE): lorsque l’application a le focus, seuls les sons émis par celles-ci sont entendus (contrôle sur le buffer primaire). • Mode Partagé: les sons en provenance des applications sont mixés dans le buffer primaire. – Mode Normal (DSSCL_NORMAL): partage du périphérique sans contrôle sur le buffer primaire. – Mode Prioritaire (DSSCL_PRIORITY): partage du périphérique avec contrôle sur le buffer primaire. – Mode Primaire (DSSCL_WRITEPRIMARY): écriture directe dans le buffer primaire (pas de buffer secondaire). Principe d’utilisation de DirectSound U N IVERSIT É D E R EIMS pour la lecture d’un son C H AMP AGN E-A RD EN N E Etapes: 1. Créer l’interface DirectSound le buffer primaire automatiquement associé. fixer le niveau de coopération. 2. Créer le (ou les) buffer(s) secondaire(s). 3. L’utilisation d’un buffer secondaire: • • • charger le contenu du buffer (lock/unlock : pour verrouiller/déverrouiller le buffer). fixer les propriétés du buffer (Position, Format, Fréquence, FX, Pan, Volume). jouer/arrêter le lecture du son. U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Entête d’une application DirectSound // minimum syndical #include <dsound.h> #pragma comment(lib,"dsound.lib") // permet la définition des GUIDs et de certaines fonctions avancées. #define INITGUID #include <guiddef.h> #include <dsconf.h> #pragma comment(lib,"dxguid.lib") Rappel: la commande pragma comment(lib,X) permet d’ajouter automatiquement la bibliothèque X à la liste des bibliothèques avec lesquels le projet est linké. Initialisation de l’interface U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E la base En 2 étapes: 1. Création de l’interface DirectSound (IDIRECTSOUND8) : LPDIRECTSOUND8 pDSD = NULL; DirectSoundCreate8( NULL , &pDSD, NULL); premier NULL : utiliser le device par défaut (LPCGUID). pDSD [out] : pointeur sur l’interface DirectSound créé. dernier NULL : obligatoire. 2. Fixe le niveau de coopération: pSDN->SetCooperativeLevel(Hwnd,level) Hwnd est le handle associé à la fenêtre (renvoyé par CreateWindow). level est le niveau de coopération (DSSCL_*). Une fois complétées, on peut créer les buffers secondaires associés et destinés à accueillir les sons à jouer. HRESULT hr = DirectSoundCreate8( NULL , &pSND, NULL); if( FAILED(hr) ) { MessageBox(hWnd,"Erreur lors de la creation du peripherique","Erreur" ,MB_OK); return E_FAIL; } // Si on n’appelle pas cette fonction on ne peut pas joueur de son pSND->SetCooperativeLevel( hWnd ,DSSCL_PRIORITY ); Initialisation de l’interface U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Choix d’un périphérique: périphériques par défaut Les périphériques systèmes sont identifiés de manière unique grâce à un GUID (Globally Unique Identifier): ex: {BD6DD71A-3DEB-11D1-B171-00C04FC20006} On peut connaître les périphériques par défaut en utilisant: GetDeviceID(&guidtype,&guid); guidtype [in] est parmi: DSDEVID_DefaultPlayback DSDEVID_DefaultCapture DSDEVID_DefaultVoicePlayback DSDEVID_DefaultVoiceCapture périphérique de lecture. périphérique de capture. périphérique de lecture de la voix. périphérique d’enregistrement de la voix. guid [out] est le GUID du périphérique utilisé. La récupération des périphériques disponibles se fait par énumération. Initialisation de l’interface U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Choix d’un périphérique : énumération Principe de l’énumération: 1. Définir une fonction qui sera appelée pour chaque périphérique: BOOL CALLBACK EnumerationDeviceCallback( LPGUID pGuid, LPCSTR pDesc, LPCSTR pMode, LPVOID pCont ) à chaque appel, les paramètres de cette fonction contiennent: pGUID : pointeur vers le GUID du périphérique. pDesc : nom du périphérique (texte) pMode : nom du module associé au périphérique (texte) pCont : pointeur vers des données utilisateur. la fonction doit renvoyer TRUE pour que l’énumération continue et FALSE dans le cas contraire (par exemple, lorsque le device recherché convient). 2. Appeler DirectSoundEnumerate DirectSoundEnumerate( EnumerationDeviceCallback , data ) EnumerationDeviceCallback : fonction appelée pour l’énumération. data : pointeur vers les données utilisateur à passer à la fonction. Note: l’énumération contient le périphérique par défaut (GUID=NULL). Dans ce cas, les autres champs en sont pas renseignés. Initialisation de l’interface U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Choix d’un périphérique : exemple LPDIRECTSOUND8 pSND; struct DeviceInfo { LPGUID Guid; LPCSTR Description, Module; }; // fonction d’énumération BOOL CALLBACK EnumerationDeviceCallback( LPGUID lpGuid,LPCSTR lpcstrModule, LPVOID lpContext ) { DeviceInfo info; vector<DeviceInfo> *Device; info.Guid = lpGuid; info.Description = lpcstrDescription; info.Module = lpcstrModule; Device = reinterpret_cast<vector<DeviceInfo>*>(lpContext); Device->push_back( info ); return TRUE; } lpcstrDescription, LPCSTR … // énumération des périphériques vector<DeviceInfo> DeviceList; DirectSoundEnumerate( EnumerationDeviceCallback , reinterpret_cast<LPVOID>(&DeviceList) ); // n’importe quel GUID des périphériques de la liste peut être utilisé avec // DirectSoundCreate8 … U N IVERSIT É D E R EIMS Capacités d’un device Audio C H AMP AGN E-A RD EN N E On utilise la méthode GetCaps du device: DSCAPS SndCaps; pSND->GetCaps (&SndCaps); Le champs dwSize doit être initialisé à sizeof(DSCAPS) avant l’appel. Cette structure contient les informations suivantes: • quantification: 8/16 bits supportés sur les buffers primaire et secondaires (dwFlags) DSCAPS_PRIMARY8BIT, DSCAPS_PRIMARY16BIT, DSCAPS_SECONDARY8BIT, DSCAPS_SECONDARY16BIT • mode mono/stéréo sur les buffers primaire et secondaires (dwFlags) DSCAPS_PRIMARYMONO, DSCAPS_PRIMARYSTEREO, DSCAPS_SECONDARYMONO et DSCAPS_SECONDARYSTEREO • pas d’échantillonnage minimum et maximum disponible supporté par les buffers secondaires: dwMinSecondarySampleRate, dwMaxSecondarySampleRate • nombre de buffers qui peuvent être mixés simultanément en hardware par la carte: dwMaxHwMixingAllBuffers, • dwMaxHw3DStaticBuffers, dwMaxHw3DStreamingBuffers nombre de buffers disponibles (statique, 3D, streaming) au moment de GetCaps: dwFreeHwMixingAllBuffers, dwFreeHw3DAllBuffers, • dwMaxHwMixingStreamingBuffers nombre de maximum de buffers 3D (statique, streaming): dwMaxHw3DAllBuffers, • dwMaxHwMixingStaticBuffers, dwFreeHwMixingStaticBuffers, dwFreeHw3DStaticBuffers, dwFreeHwMixingStreamingBuffers dwFreeHw3DStreamingBuffers mémoire (en octets) sur la carte son: dwTotalHwMemBytes (totale) & dwFreeHwMemBytes (libre), dwMaxContigFreeHwMemBytes (contigüe), dwUnlockTransferRateHwBuffers (vitesse de transfert). • pourcentage CPU nécessaire pour mixer les buffers softwares: dwPlayCpuOverheadSwBuffers. Fichier son U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E format wav Le format waveform-audio data (extension wav) avait initialement pour but de stocker des données au format PCM mono ou stéréo non compressé. Dans le SDK, les champs suivant de la structure WAVEFORMATEX permet d’en décrire le contenu: wFormatTag nChannels nSamplesPerSec nAvgBytesPerSec nBlockAlign wBitsPerSample cbSize : WAVE_FORMAT_PCM pour du PCM mono ou stéréo. : 1 pour mono, 2 pour stéréo. : pas d’échantillonnage en Hz. : = nSamplesPerSec * nBlockAlign : = nChannels * wBitsPerSample / 8 (en bytes) : quantification (en nombre de bits par échantillon). :0 La WAVEFORMATEX est directement utilisée pour décrire le type de buffer secondaire souhaité lors de sa création. Question: combien de seconde dure un fichier stéréo wav de 64 Mo de 16 bits à 44KHz? Exemple: 16 bits stéréo @ 44.1 KHz WAVEFORMATEX fmt = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0} Ce format est flexible et permet de stocker des données compressées (non décrit ici). cf http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/WAVE/WAVE.html Chargement d’un son U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E la classe CWaveFile Il n’y a pas de fonction DirectSound permettant de lire des sons au format wav ou mp3 (par contre, possible avec DirectMusic). Le SDK propose dans DXUTsound une classe CWaveFile permettant de lire les fichiers au format wav. Principales méthodes de la classe CWaveFile pour lire un fichier: HRESULT Open( file, NULL, WAVEFILE_READ) pour ouvrir le fichier file en lecture. DWORD GetSize() pour connaître le nombre d’octets dans le fichier. HRESULT ResetFile() pour revenir au début du fichier. HRESULT Read( (BYTE*)pBuff, BuffSz, &nRead ) pour lire au plus BuffSz octets et les placer dans le buffer pBuff. nRead contient au retour le nombre d’octets lu. HRESULT Close() pour fermer le fichier. WAVEFORMATEX* GetFormat() pour récupérer le format du fichier audio. Création d’un buffer secondaire U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E avec la méthode suivant de IDirectSound8: CreateSoundBuffer(&BuffDesc, &pDSB, NULL) BuffDesc [in]: structure de type DSBUFFERDESC contenant la description du buffer à créer, dont les champs principaux sont: dwBufferBytes : taille en octets du buffer à créer. dwFlags : capacité particulière de réglage du buffer (voir la table cidessous). Combinaison bitwise de flags DSBCAPS_*: CTRL3D 3D CTRLFREQUENCY fréquence CTRLFX effets CTRLPAN balance (non 3D) CTRLVOLUME volume Note: chaque capacité consomme des ressources. Autres capacités disponibles: • interaction du buffer avec le système (cf transparent suivant) • contrôle 3D (voir la partie son3D). lpwfxFormat : format des données utilisées dans le buffer au format WAVEFORMATEX ou WAVEFORMATEXTENSIBLE. guid3DAlgorithm : algo 3D utilisé pour spatialiser le son ( DS3DALG_DEFAULT si pas de son 3D, voir la partie son3 D). pDSB [out]: l’adresse sur l’interface IDIRECTSOUNDBUFFER du buffer secondaire créé. Création d’un buffer secondaire U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E interaction avec le système Autres capacités possibles dans dwFlags: Focus: • • DSBCAPS_GLOBALFOCUS : le buffer est global (le son est entendu même si l’application n’a pas le focus). DSBCAPS_STICKYFOCUS : si l’application qui a le focus n’utilise pas DirectSound, le buffer continue d’être entendu. Gestion de la mémoire et des voies: Principe: • • • • • • Le nombre de voies hardware est limité sur la carte son (SB Audigy 2 = 64). Par défaut, s’il reste des voies, le buffer est alloué en hardware, sinon le buffer est alloué en software. Les buffers alloués en hardware (resp. software) sont mixés en hardware (resp. software). Mixage hardware = mixage sur la carte son. Mixage software = mixage sur le processeur. Rappel: sur les cartes son moderne, les buffers (hardware ou software) sont stockés dans la mémoire système. Une voie de la carte son est affectée à chaque buffer secondaire. Options mémoires de création d’un buffer secondaire: • • • • DSBCAPS_LOCDEFER : le buffer peut être attribué à une ressource software ou hardware (= localisation différée). Permet également une gestion dynamique (voir Dynamic Voice Management). DSBCAPS_LOCSOFTWARE : le buffer est mixé en software (donc, buffer placé en software). DSBCAPS_LOCHARDWARE : le buffer est mixé en hardware. DSBCAPS_STATIC : le buffer est placé en hardware (obsolète: carte son ancienne). Utilisation du buffer secondaire U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E curseurs un buffeur secondaire possède 2 curseurs: – un curseur de lecture (dernière position lue) – un curseur d’écriture (dernière position écrite, utile pour le streaming). Méthodes pour les manipuler: GetCurrentPosition(&PlayCur,&WriteCur) pour récupérer les valeurs des deux curseurs. SetCurrentPosition(PlayCur) pour fixer la valeur du curseur de lecture. Gestion: • la gestion des curseur de lecture et d’écriture est automatique. • lors de la création d’un buffer secondaire, spécifier dans dwFlags: – DSBCAPS_GETCURRENTPOSITION2 pour s’assurer d’un curseur de lecture précis. – DSBCAPS_CTRLPOSITIONNOTIFY pour avoir une notification sur curseur de lecture (voir la partie sur le streaming). Utilisation du buffer secondaire U N IVERSIT É D E R EIMS buffer statique ou streaming C H AMP AGN E-A RD EN N E un buffer ne peut contenir que des sons au format wav (en général du PCM). buffer statique: on charge le son complet dans le buffer une fois pour toute. avantage: pas de gestion. inconvénient: place mémoire importante. ⇒ à privilégier pour les sons répétitifs et cours. streaming: le son n’est jamais totalement chargé en mémoire mais chargé et lu progressivement dans un buffer circulaire de taille fixe. avantage: consommation mémoire réduite. inconvénient: gestion périodique pour charger le son à jouer, avec éventuellement fractionnement de la zone mémoire à remplir. p1 n1 Offset Size p2 n2 p1 Offset n1 n2 Size Chargement d’un son U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E dans un buffer secondaire Le buffer secondaire doit avoir été créé au format du fichier à charger dans le buffer. 1. Verrouiller le buffer secondaire avec la méthode: Lock(Offset, Size, &p1, &n1, &p2, &n2, flags) Offset [in]: offset depuis le début du buffer. Size [in]: taille à verrouiller. p1, n1 [out] : pointeur et taille sur la zone verrouillée. p2, n2 [out] : idem pour le cas d’un buffer circulaire (ou NULL). flags: DSBLOCK_FROMWRITECURSOR : pour utiliser automatiquement comme Offset la position du curseur d’écriture. DSBLOCK_ENTIREBUFFER : vérrouille tout le buffer. 2. 3. Remplir la zone mémoire pointée par p1 (et éventuellement p2). Déverrouiller le buffer secondaire avec la méthode: Unlock( p1, n1, p2, n2) permet de libérer correctement les zones verrouillées et de mettre à jour le pointeur d’écriture. p1 (et p2) : exactement les valeurs récupérées par lock. n1 (et n2) : exactement le nombre d’octets écrits (éventuellement < au n1,n2 initiaux). Chargement d’un son U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E dans un buffer secondaire (statique) Exemple LPDIRECTSOUND8 pSND = NULL; char filename[]=“sound.wav”; LPDIRECTSOUNDBUFFER pDSB = NULL; CWaveFile waveFile; // on suppose que l’initialisation de pSND a eu // création du buffer secondaire waveFile.Open( filename, NULL, WAVEFILE_READ ); DSBUFFERDESC bdesc; bdesc.dwSize = sizeof(DSBUFFERDESC); bdesc.dwFlags = DSBCAPS_CTRLVOLUME ; bdesc.dwBufferBytes = waveFile.GetSize(); bdesc.guid3DAlgorithm = DS3DALG_DEFAULT; bdesc.lpwfxFormat = waveFile.GetFormat(); pSND->CreateSoundBuffer( &ddesc, &pDSB, NULL ); lieu // contrôle du volume // taille du fichnier à charger // format du fichier // chargement des données depuis le fichier VOID* Buff = NULL; // pointeur vers le buffer vérouillé DWORD BuffSz; // taille effectivement vérouillée DWORD nRead = 0; // nombre d’octets lus dans le fichier pDSB->Lock(0, waveFile.GetSize(), &Buff, &BuffSz,NULL, NULL, 0 ); waveFile.ResetFile(); waveFile.Read( (BYTE*)Buff, BuffSz, &nRead ); pDSB->Unlock(Buff, nRead, NULL, 0 ); wavefile.Close(); Lecture du son U N IVERSIT É D E R EIMS contenu dans le buffer secondaire C H AMP AGN E-A RD EN N E avec les méthodes: • Play(0,priority,flag) joue immédiatement le son sélectionné. priority : 0 si la gestion dynamique de voies n’est pas utilisée. flag: combinaison bitwise de: DSBPLAY_LOOPING : répétition automatique. voir ci-après pour la gestion dynamique de voies. • Stop() arrête la lecture. le curseur de lecture est placé à l’endroit où la lecture s’est arrêtée. Conséquence: – l’appel à Play fait reprendre la lecture à l’endroit où elle s’est arrêtée. – pour reprendre la lecture du début, utiliser SetCurrentPosition. Remarque: • SetCurrentPosition/GetCurrentPosition peuvent être appelé pendant • la lecture pour changer/lire la position courant du curseur de lecture. si SetPriorityLevel n’a pas été appelé, le son ne sera pas entendu même si Play renvoie S_OK. Gestion dynamique de voies U N IVERSIT É D E R EIMS DirectSound permet une gestion dynamique des voies hardware (Dynamic Voice Management) de la carte son. C H AMP AGN E-A RD EN N E Utilisation: • Tous les buffers à gérer dynamiquement doivent être créés avec DSBCAPS_LOCDEFER. – Seuls ceux-ci sont candidats pour libérer les ressources. – C’est au moment du Play que sera déterminé si ce buffer secondaire est joué en hardware ou en software. • le flag de Play contient des informations additionnelles pour tenter de jouer le son en hardware: – pour forcer le mode avec lequel le buffer sera joué: DSBPLAY_LOCHARDWARE : pour forcer le mode hardware. DSBPLAY_LOCSOFTWARE : pour forcer le mode software. – pour choisir la stratégie de choix de libération d’un buffer hardware DSBPLAY_TERMINATEBY_TIME : choisir le buffer pour lequel il reste le moins de temps à jouer (exclue les buffers joués en boucle). DSBPLAY_TERMINATEBY_DISTANCE : choisir un buffer créé avec le flag DSBCAPS_MUTE3DATMAXDISTANCE et pour lequel le son se trouve au delà de la distance maximum. S’il n’y en a pas, la méthode échoue. DSBPLAY_TERMINATEBY_PRIORITY (peut être combiné avec l’un des deux modes précédents qui ne servent qu’en cas d’égalité): utiliser le paramètre de priorité passé à Play (0 = priorité la plus faible, 0xffffffff = priorité la plus forte). Le son de plus faible priorité est terminé immédiatement. • Remarque: – – en cas d’échec, le son est joué en software, sauf si le mode hardware est forcé. Dans ce cas, la méthode Play échoue. voir aussi la méthode AcquireResources, qui permet d’allouer des ressources avant le Play. Elle possède des arguments supplémentaires permettant d’allouer les ressources nécessaires aux effets. U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Réglages basique sur un buffer secondaire Méthode permettant de régler les propriétes du buffer: • SetVolume(vol) : fixe le volume où vol est l’atténuation en 1OOème de dB (-100=-1dB, -10000=-100dB), définie de DSBVOLUME_MAX (0) à DSBVOLUME_MIN (-10000). Le buffer doit avec été créé avec la capacité DSBCAPS_VOLUME. • SetPan(pan) : fixe la balance gauche/droite où pan va de -10000 (DSBPAN_LEFT) à 10000 (DSBPAN_RIGHT), centré à 0 (DSBPAN_CENTER). Le buffer doit avec été créé avec la capacité DSBCAPS_PAN. • SetFrequency(freq) : fréquence joue à une fréquence freq différente de sa fréquence d’échantillonnage originale. Conséquence: le pitch et la durée du son sont changés. Le buffer doit avec été créé avec la capacité DSBCAPS_FREQUENCY. Remarques: – DSBFREQUENCY_ORIGINAL rétablit la fréquence originale. – le fréquence doit être supportée (i.e. entre wMinSecondarySampleRate et dwMaxSecondarySampleRate). – certains OS ne permettent pas de dépasser 100KHz. Interface IDIRECTSOUNDBUFFER8 U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E sur un buffer secondaire Par défaut, la méthode CreateSoundBuffer crée un pointeur sur une interface de type IDIRECTSOUNDBUFFER qui est commune aux buffers primaire et secondaires. Certaines fonctionnalités caractéristiques des buffers secondaires ne sont pas disponibles à travers cette interface mais avec l’interface IDIRECTSOUNDBUFFER8 (qu’il est donc possible de récupérer pour un buffer secondaire). Récupérer un pointeur sur l’interface IDIRECTSOUNDBUFFER8 à partir d’un pointeur sur l’interface IDIRECTSOUNDBUFFER: // Initialiser l’interface COM (une seule fois dans tout l’application) CoInitialize( NULL ); … LPDIRECTSOUNDBUFFER pDSB = NULL; // initialiser le buffer secondaire pDSB ici LPDIRECTSOUNDBUFFER8 pDSB8 = NULL; pDSB->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*)&pDSB8 ); … // A la fin de l’application CoUninitialize(); Rappel: pensez au Release() sur les deux pointeurs. Effets de base sur un buffer secondaire U N IVERSIT É D E R EIMS Effets disponibles (1) C H AMP AGN E-A RD EN N E 8 effets sont intégrés de base dans DirectSound: Chorus : doublement de la voie créé en répétant le son original avec un petit délai. Compressor : reduction des fluctuations au-delà d’une certaine amplitude. Distortion : ajout d’harmoniques au son de façon à saturer les niveaux les plus hauts. Echo : répétition du son après un délai, avec réduction du volume. Le son répété est de nouveau répété. Flanger : echo pour lequel le delai entre le signal original et son écho est très court et varie avec le temps. Gargle : modulation de l’amplitude du signal. ParamEq : équaliseur paramétrique (permet d’amplifier ou d’atténuer certaines fréquences). WavesReverb : réverbération conçues pour la musique. Remarques: • Les effets ne sont disponible QUE sur un buffer secondaire (donc récupérer un pointeur IDIRECTSOUNDBUFFER8 sur le buffer secondaire). • Le buffer sur lequel l’effet est appliqué doit être arrêté pour pouvoir créer l’effet. • Tous les effets sont appliqués en software, et ceci même si la carte son les supporte en hardware. • Le buffer doit avoir une durée d’au moins 150ms de données (DSBSIZE_FX_MIN). Demonstration: voir l’application SoundFx dans le SDK. Effets de base sur un buffer secondaire U N IVERSIT É D E R EIMS Définition d’un effet (1/3) C H AMP AGN E-A RD EN N E Guid/Interface/Structure/IID associés à chaque effets: GUID Interface Structure Interface ID GUID_DSFX_STANDARD_CHORUS IDirectSoundFXChorus8 DSFXChorus IID_IDirectSoundFXChorus8 GUID_DSFX_STANDARD_COMPRESSOR IDirectSoundFXCompressor8 DSFXCompressor IID_IDirectSoundFXCompressor8 GUID_DSFX_STANDARD_DISTORTION IDirectSoundFXDistortion8 DSFXDistortion IID_IDirectSoundFXDistortion8 GUID_DSFX_STANDARD_ECHO IDirectSoundFXEcho8 DSFXEcho IID_IDirectSoundFXEcho8 GUID_DSFX_STANDARD_FLANGER IDirectSoundFXFlanger8 DSFXFlanger IID_IDirectSoundFXFlanger8 GUID_DSFX_STANDARD_GARGLE IDirectSoundFXGargle8 DSFXGargle IID_IDirectSoundFXGargle8 GUID_DSFX_STANDARD_PARAMEQ IDirectSoundFXParamEq8 DSFXParamEq IID_IDirectSoundFXParamEq8 GUID_DSFX_WAVES_REVERB IDirectSoundFXWavesReverb8 DSFXWavesReverb IID_IDirectSoundFXWavesReverb8 Structure à remplir pour définir un effet dans un buffer secondaire: structures DSEFFECTDESC: la structure contient principalement les champs suivants: dwSize = sizeof(DSEFFECTDESC); dwFlags : 0 ou DSFX_LOCHARDWARE : pour forcer l’effet en hardware (pas d’avantage à le faire). DSFX_LOCSOFTWARE : pour forcer l’effet en software. guidDSFXClass : classe de l’effet (voir table ci-dessous) Effets de base sur un buffer secondaire Définition d’un effet (2/3) U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Pour définir une suite de n effets, il faut: 1. Fixer les effets à utiliser: SetFX( n , desc, codes ) n : nombres d’effets desc : tableau de n structures de type DSEFFECTDESC (à remplir) décrivant la suite d’effets à appliquer dans l’ordre. codes : tableau de n DWORDs contenant au retour le status de création de l’effet (DSFXR_x où x est parmi LOCHARDWARE, LOCSOFTWARE, UNALLOCATED, FAILED, PRESENT). Remarque: • SetFX(0,NULL,NULL) désactive les effets sur le buffer. • pour utiliser SetFX, il faut récupérer l’interface IDIRECTSOUNDBUFFER8 associée au buffer secondaire. 2. Récupération du pointeur sur l’interface de chaque effet: GetObjectInPath( guid , i, iid, (LPVOID*)&pEff ); i [in]: index de l’effet dans la table. guid [in]: guid du ième effet. iid [in]: iid du ième effet. pEff [out]: pointeur sur l’interface de l’effet. 3. Configuration de l’effet 2 méthodes sont disponibles sur chaque effet: GetAllParameter: pour récupérer, dans la structure DSFX* associée, la configuration courante de l’effet. SetAllParameter: pour fixer, à partir de la structure DSFX* associée, la configuration de l’effet. Effets de base sur un buffer secondaire U N IVERSIT É D E R EIMS Définition d’un effet (3/3) C H AMP AGN E-A RD EN N E Exemple: définition de l’effet chorus sur un buffer secondaire // Initialise l’interface COM (une seule fois dans tout l’application) CoInitialize( NULL ); … LPDIRECTSOUNDBUFFER pDSB = NULL; // créer ici le buffer secondaire avec l’option DSBCAPS_CTRLFX // récupération de l’interface DIRECTSOUNDBUFFER8 LPDIRECTSOUNDBUFFER8 pDSB8 = NULL; pDSB->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*)&pDSB8 ); // Définition de l’effet sur le buffer DWORD code; // code de retour (à tester) DSEFFECTDESC Desc = {sizeof(DSEFFECTDESC), 0, GUID_DSFX_STANDARD_CHORUS, 0, 0 }; pDSB8->SetFX( 1, &Desc , &code); // récupération de l’interface sur l’effet LPDIRECTSOUNDFXCHORUS8 pChorus = NULL; DSFXChorus ChorusData; pDSB8->GetObjectInPath( GUID_DSFX_STANDARD_ECHO, 0, IID_IDirectSoundFXEcho8, (LPVOID*)&pChorus); // changement pChorus->GetAllParameters(&ChorusData); ChorusData.fWetDryMix = DSFXECHO_WETDRYMIX_MAX; ChorusData.fDepth = 100; pChorus->SetAllParameters(&ChorusData); U N IVERSIT É D E R EIMS Etat d’un buffer secondaire C H AMP AGN E-A RD EN N E méthode GetStatus(&status) au retour, status contient le statut courant du buffer. DSBSTATUS_BUFFERLOST buffer perdu: doit être restoré avant d’être lu ou verrouillé. DSBSTATUS_LOOPING lecture en boucle. DSBSTATUS_PLAYING lecture en cours. DSBSTATUS_LOCSOFTWARE buffer en mode software (LOCDEFER). DSBSTATUS_LOCHARDWARE buffer en mode hardware (LOCDEFER). DSBSTATUS_TERMINATED le buffer a subit une arret forcé (LOCDEFER). Remarques: méthode principalement utilisée pour deux raisons: – pour tester la perte d’un buffer. – pour tester l’état d’un buffer dans le cadre d’une gestion dynamique des voies. Gestion d’un buffer perdu U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Exemple de cas de perte d’un buffer: si une application en mode coopératif passe en arrière-plan, tous ses buffers sont alors perdus pour permettre à l’application du premier plan l’écriture directe dans le buffer primaire. Détection: – – GetStatus(…) & DSBSTATUS_BUFFERLOST est vrai. Play(…), Lock(…) renvoient DSERR_BUFFERLOST. Restoration d’un buffer perdu: 1. 2. faire appel à la méthode Restore() sur le buffer pour réallouer la mémoire. recopier le contenu du buffer (considérer que le contenu d’un buffer perdu est perdu). HRESULT h; DWORD dwStatus; pDSB->GetStatus( &dwStatus ); if( dwStatus & DSBSTATUS_BUFFERLOST ) { while( ( hr = pDSBuffer->Restore() ) == DSERR_BUFFERLOST ) Sleep( 10 ); // recopier ici le contenu du buffer perdu } Notification U N IVERSIT É D E R EIMS 1. Déclaration des notifications C H AMP AGN E-A RD EN N E Notification = déclenchement d’un évènement lorsqu’une position déterminée est atteinte par le curseur de lecture dans le buffer (préférable à l’utilisation de GetStatus). Mise en place: 1. Récupérer l’interface IDirectSoundNotify8 (appel COM avec IID_IDirectSoundNotify) sur le buffer. 2. Pour chaque notification attendu, remplir une structure DSBPOSITIONNOTIFY: dwOffset : offset dans le fichier qui déclenchera l’évènement lorsque le curseur de lecture l’atteindra. hEventNotify : handle associé à l’événement (crée avec CreateEvent, voir ci-après) 3. Appeler la méthode suivante de IDirectSoundNotify8: SetNotificationPositions( nNot, NotArray ) nNot : nombre de notifications à installer sur le buffer. NotArray : tableau de nNot structure de type DSBPOSITIONOTIFY. afin de mettre en place l’ensemble des notifications. Remarques: • • SetNotificationPositions(0,NULL) permet de désactiver les notifications sur le buffer. le buffer doit être arrêté lors de l’installation des notifications. Notification U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E • 2. Gestion d’évènements Création d’évènement (pour remplir le tableau DSBPOSITIONNOTIFY) h = CreateEvent(NULL, auto, init, name) h : handle de l’événement créé. auto : reset manuel (TRUE) / automatique (FALSE) manuel = nécessite l’appel à ResetEvent(h) pour que l’événement soit considéré comme non signalé. init : valeur initiale : signalé (TRUE) / non signalé (FALSE). • Boucle de message modifiée pour la lecture des événements supplémentaires: // EventHandleArray = tableau des handles dont on attend la notification r = MsgWaitForMultipleObjects( n, &EventHandleArray,FALSE, INFINITE, QS_ALLEVENTS ); switch( r ) { case WAIT_OBJECT_0 + i: // du handle numéro i dans le EventHandleArray // gestion de cet évènement break; case WAIT_OBJECT_0 + n: // traitement des autres événements // insérer ici la boucle de traitement des messages break; } • Attente passive d’un évènement: r = WaitForSingleObject(h, timeout) h : handle de l’événement timeout : attente avant retour forcé de la fonction (0=retour immédiat, n=nombre de ms, INFINITE=infini). r : WAIT_OBJECT_0 = l’évenement est survenu, WAIT_TIMEOUT = retour après un timeout. Attention: dans le cas d’une application multithread, voir les options de CreateEvent. • Destruction d’un événement: CloseHandle(h) où h est le handle obtenu par CreateEvent. Notification U N IVERSIT É D E R EIMS 3. Exemple C H AMP AGN E-A RD EN N E Création des événements associés aux notifications et initialisation de la table de notifications // pDSB : pointeur sur le buffer // BuffSize : taille du buffer // création de l’évenement LPDIRECTSOUNDNOTIFY pNot = NULL; HANDLE NEvent; NEvent = CreateEvent(NULL,FALSE,FALSE,NULL); // récupération de l’interface de gestion // des notifications pDSB->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pNot ); // création de la table de notifications const int nNot = 10; uint nSize = BuffSize / nNot; DSBPOSITIONNOTIFY NotPos[nNot]; for( INT i=0; i<nNot; i++ ) { PosNot[i].dwOffset = i*nSize; PosNot[i].hEventNotify = NEvent; } // fixe les positions de notification pNOT->SetNotificationPositions( nNot, PosNot ); Traitement des événements associés aux notifications et des messages Windows classiques Done = FALSE; while( !Done ) { // 1 : nombre d’évenement // &NEvent : tableau des évenements DWORD dwResult = MsgWaitForMultipleObjects( 1, &NEvent, FALSE, INFINITE, QS_ALLEVENTS ); switch( dwResult ) { case WAIT_OBJECT_0 + 0: // NEvent est signalé (premier évenement) // traitement de l’événement NEvent break; case WAIT_OBJECT_0 + 1: // messages Windows classiques // traitement classique des messages // Done = TRUE si le message est WM_QUIT break; } } Notification U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E 4. Problème potentiel avec les notifications Pour un buffer hardware, les notifications sont gérés à travers le driver: certains drivers ne gèrent pas les notifications de manière fiable, et peuvent générer de fausses notifications. Solutions: • appeler la méthode GetCurrentPosition pour vérifier la validité de la notification. • utiliser un buffer software: dans ce cas, les notifications sont toujours correctes. inconvénient majeur: le mixage et l’application d’effet se font en software (nuit à la performance). • utiliser plutôt des timers si la notification doit arriver à intervalle régulier (comme dans le cas du streaming). Remarque: la gestion des notifications dans le cas d’une application multi-threads demande une attention particulière (à commencer par les attributs de sécurité dans CreateEvent). Gestion d’un timer U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Gestion: SetTimer( h, id, lapse, tfunc) h : handle de la fenêtre auquel le timer est associé. id : numéro (UINT) associé au timer. Si le timer existe déjà, il est remplacé. lapse : temps à attendre avant le déclenchement du timer en ms. tfunc : NULL : un message WM_TIMER est posté à l’expiration du timer (donc à intégrer à la boucle de traitement des messages de h). L’id du timer se trouve dans wParam. (TIMERPROC)MyTimerProc : fonction appelée (par DispatchMessage) lors de l’expiration du timer. Une fonction peut différente peut être affectée par timer. KillTimer( h, id ) détruire le timer de numéro id associé à fenêtre de handle h. Fonction utilisateur: VOID CALLBACK MyTimerProc( HWND h, UINT uMsg, UINT_PTR id, DWORD time ) h : handle de la fenêtre auquel le timer est associé. uMsg : message (= WM_TIMER) id : identification du timer. time : valeur de GetTickCount du moment où le timer a expiré (= ms écoulés depuis le dernier boot). le paramètre id (et éventuellement h) permet d’utiliser la même fonction pour gérer plusieurs retour de timer. Problème potentiel: si la taille du buffer est trop petite, la précision du timer peut se révéler insuffisante. Streaming U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Principe de remplissage du buffer Rappel: pour les sons de durée importante (dialogue, musique), on utilise un petit buffer circulaire (quelques secondes) que l’on charge au fur et à mesure des besoins. Exemple: Première mise-à-jour Initialisation Mises-à-jour suivantes cplay cplay cplay d-ε d crec crec Le curseur de lecture Cplay et le curseur d’enregistrement Crec sont tous les deux au début du buffer. Le buffer complet est rempli avec le début du son. cplay cplay d-ε d-ε crec crec Lorsque d(Cplay,Crec) ≥ d, on copie les d-ε octets suivants dans le buffer à partir de Crec. Remarques: • le buffer est joué en mode DSBPLAY_LOOPING. • en fin de la lecture (la fin du fichier est atteinte): 1. il faut continuer à écrire de 0 jusqu’à ce que Crec atteigne la fin du buffer. 2. Lorsque Crec dépasse la fin du buffer, déactiver le mode DSBPLAY_LOOPING. crec Pour la deuxième mise à jour, le buffer d’écriture est coupé en deux. Paramétrage: d = 20% de la taille du buffer (par exemple). ε = 32 bits (imprécision du driver sur la position de Cplay). Streaming U N IVERSIT É D E R EIMS Gestion du remplissage C H AMP AGN E-A RD EN N E • A partir de notification: Placer la notification sur Cplay+d. Voir la partie sur les notifications pour voir les inconvénients de cette méthode. • A partir de timer: Les caractéristiques du buffer sont: n = nombre de canaux. f = fréquence d’échantillonnage. q = nombre de bits par valeur (quantification). Avec un buffer de taille b, on peut stocker s=b/nfq secondes. Attendre que p% du buffer s’écoule, c’est attendre: st = s.p% secondes Donc, dans le cas d’une lecture continue, on peut fixer le timer à st. Remarques: Les deux méthodes sont valables mais celle utilisant les timers est plus simple à mettre en place. U N IVERSIT É D E R EIMS Partage d’un buffer secondaire C H AMP AGN E-A RD EN N E Il est possible pour deux buffers secondaires différents de partager la même zone mémoire avec la méthode suivante de IDirectSound8: DuplicateSoundBuffer( OriginalBuff, &CopyBuff) crée une copie du buffer secondaire OriginalBuff appelée CopyBuff. OriginalBuff ne doit pas avoir la capacité DSBCAPS_CTRLFX. Différent d’un AddRef: – Initialement, les paramètres de CopyBuff sont les mêmes que ceux d’ OriginalBuff. – chaque buffer a ses propres paramètres (volume, balance, …) qui peuvent être changés indépendamment sans perturber l’autre buffer. – chaque buffer a ses propres curseurs de lecture et d’écriture (Play/Stop). – seule la mémoire du buffer est partagée. Note: le mémoire du buffer n’est libéré qu’une fois le dernier buffer secondaire l’utilisant est libéré. Applications (non limitatif): • pour des sons ayant des comportements exclusifs (bruit de l’arme du joueur, …). • pour partager des sons très court dans un même buffer (à conjuguer avec des notifications). U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Accès et manipulation du buffer primaire En général, on ne manipule pas directement le buffer primaire. Il est malgré tout possible d’y accéder. Pointeur sur le buffer primaire: utiliser la méthode CreateSoundBuffer avec la capacité DSBCAPS_PRIMARYBUFFER, dwBufferBytes=0 (la taille du buffer primaire n’est pas géré pas l’utilisateur), et lpwfxFormat = NULL (ne pas spécifier de format à la création). Changer le format du buffer primaire (de mixage) utiliser la méthode SetFormat(&fmt) où fmt est de type WAVEFORMATEX. doit être appelé avant la création de tout buffer secondaire. Autres opérations disponibles Stop/Play : pour couper/relancer le son. Lock/Unlock : pour verrouiller/déverrouiller le buffer primaire. SetVolume/SetPan/SetFrequency : pour fixer le son/balance/fréquence principal de l’application. Attention: bien lire la documentation de ces méthodes qui ont souvent un comportement particulier sur le buffer primaire. Capture Audio U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E principe En 4 étapes: 1. Enumérer les devices disponibles DirectSoundCaptureEnumerate (pour choisir) ou récupérer le device de capture par défaut avec GetDeviceID. 2. Créer un pointeur sur l’interface de capture IDirectSoundCapture8 avec la fonction DirectSoundCaptureCreate8. 3. Créer un pointeur sur l’interface du buffer de capture IDirectSoundCaptureBuffer8 avec la méthode CreateCaptureBuffer de IDirectSoundCapture8. 4. Utiliser les méthodes Start/Stop de IDirectSoundCaptureBuffer8. Remarque: • l’interface IDirectSoundFullDuplex8 permet de faire du full duplex. • des effets spécifiques pour la capture existent et permettent d’éliminer l’écho ou les bruits de fond. Capture Audio U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E devices de capture disponibles Récupération du GUID du périphérique de capture: 1. device par défaut: utiliser GetDeviceID avec DSDEVID_DefaultCapture ou DSDEVID_DefaultVoiceCapture. utiliser NULL comme synonyme de DSDEVID_DefaultCapture. 2. énumération: comme pour la lecture, il faut écrire une fonction de type EnumerationDeviceCallback (même prototype) et faire appel à la fonction DirectSoundCaptureEnumerate pour parcourir l’ensemble des device de capture disponibles. DirectSoundCaptureEnumerate( EnumerationDeviceCallback , data ) EnumerationDeviceCallback : fonction appelée pour l’énumération. data : pointeur vers les données utilisateur à passer à la fonction. Création de l’interface sur le device de capture: une fois le device choisi, créer l’interface de capture avec: DirectSoundCaptureCreate8(guid, &pREC, NULL) guid [in]: est le guid obtenu ci-dessus. pREC [out]: un pointeur sur l’interface IDIRECTSOUNDCAPTURE8. Capture Audio U N IVERSIT É D E R EIMS capacité du device de capture C H AMP AGN E-A RD EN N E On utilise la méthode GetCaps du device de capture: DSCCAPS RecCaps; pREC->GetCaps (&SndCaps); Le champs dwSize doit être initialisé à sizeof(DSCCAPS) avant l’appel. Cette structure contient les informations suivantes: • des informations sur le driver (dwFlags) : – DSCCAPS_EMULDRIVER : pas de driver de capture DirectSound. – DSCCAPS_MULTIPLECAPTURE : le driver peut supporter plusieurs capture en même temps. • • les formats de capture supporté (dwFormats) : contient une combinaison bitwise de WAVE_FORMAT_xyz avec: x Fréquence y canaux z Quantification 1 11.025 kHz M mono 08 8 bits 2 22.050 kHz S stéréo 16 16 bits 4 44.100 kHz Exemples: WAVE_FORMAT_1M08 = 11.025 kHz, mono, 8-bit WAVE_FORMAT_4S16 = 44.1 kHz, stereo, 16-bit le nombre de canaux (dwChannels) : 1=mono, 2=stéreo, ... Capture Audio U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E création du buffer de capture Avec la méthode suivante du device de capture: CreateCaptureBuffer( &BuffDesc, &pACB, NULL) BuffDesc [in]: structure de type DSCBUFFERDESC décrivant le buffer de capture à créer dont les champs principaux sont: dwFlags : DSCBCAPS_CTRLFX : pour autoriser les effets. DSCBCAPS_WAVEMAPPED : utiliser le wave mapper (=convertisseur chargeant les codecs software nécessaires) si le format (lpwfxFormat) demandé n’est pas supporté. dwBufferBytes : taille (en octets) du buffer à créer. lpwfxFormat : pointeur sur une structure de type WAVEFORMATEX décrivant le format de capture des données (voir format wav). dwFXCount : nombre d’élément dans le tableau de DSCEFFECTDESC décrivant la liste d’effets à appliquer (0 si DSCBCAPS_CTRLFX n’est pas présent dans dwFlags). lpDSCFXDesc : pointeur sur le tableau de DSCEFFECTDESC. pACB [out]: pointeur sur l’interface IDirectSoundCaptureBuffer de manipulation du buffer de capture créé. Note: les effets sont associés dès la création du buffer. Capture Audio U N IVERSIT É D E R EIMS gestion des effets à la création C H AMP AGN E-A RD EN N E Structure DSCEFFECTDESC de description des effets de capture: dwSize : sizeof(DSCBUFFERDESC) dwFlags : mode pour l’effet DSCFX_LOCHARDWARE : effet hardware DSCFX_LOCSOFTWARE : effet software au retour de CreateCaptureBuffer, ce champs indique comment l’effet à été effectivement créé. guidDSCFXClass : effet souhaité GUID_DSCFX_CLASS_AEC : élimination de l’écho. GUID_DSCFX_CLASS_NS : suppression du bruit. guidDSCFXInstance : choix de l’instance de l’effet SW Microsoft système élimination d’écho GUID_DSCFX_MS_AEC GUID_DSCFX_SYSTEM_AEC suppression de bruit GUID_DSCFX_MS_NS GUID_DSCFX_SYSTEM_NS Important: les effets ne sont utilisables qu’avec l’interface IDirectSoundCaptureBuffer8: LPDIRECTSOUNDCAPTURE8 pACB8 = NULL; pACB->QueryInterface(IID_IDirectSoundCaptureBuffer8, (LPVOID*)&pACB8 ); Capture Audio U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Gestion du buffer de capture Fonctionnement quasiment identique à un buffer secondaire. Gestion courante: Start(flag) : commencer la capture. flag: 0 ou DSCBSTART_LOOPING pour enregistrement en boucle. Stop() : arret de la capture. Lock/Unlock (même syntaxe) : pour verrouiller le buffer et y lire les données capturées. GetCurrentPosition(&RecCur,&ReadCur) : pour lire la position du curseur d’enregistrement et de lecture. GetStatus(&s) : pour lire le statut s du buffer (combinaison bitwise de DSCBSTATUS_CAPTURING si capture en cours, DSCBSTATUS_LOOPING si en boucle). Gestion des effets (IDirectSoundCaptureBuffer8): GetObjectInPath: pour récupérer le pointeur sur l’interface de l’effet (puis GetAllParameters/SetAllParameters pour configurer l’effet). Remarque: • si on ne fait pas de streaming (enregistrement en boucle), la durée de l’enregistrement est limité à la taille du buffer. • sous XP, voir aussi l’interface IDirectSoundFullDuplex8 (FullDuplex). Audio Haute-Résolution U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Extension du WAVEFORMAT (WAVEFORMATEXTENSIBLE) – utilisation de fréquence au-delà de 44kHz ou au delà de 16bits – multicanal (surround, 5.1, 6.1, 7.1, hémisphérique): 18 canaux max. Utiliser la structure WAVEFORMATEXTENSIBLE lors de la création du buffer primaire. Voir aussi: MSDN : Multiple Channel Audio Data and WAVE Files. http://www.microsoft.com/whdc/device/audio/multichaud.mspx WaveInOpen DirectSndCapture WaveOutOpen DirectSndPlayback Bits EX EXTENSIBLE EX EXTENSIBLE EX EXTENSIBLE EX EXTENSIBLE 8 PCM8 PCM8 OK OK HF HF HF HF 16 OK OK OK OK HF HF HF HF 24 N/A OK N/A OK N/A Trunc N/A Trunc 32 N/A OK N/A OK N/A Trunc N/A Trunc • • • “HF” 24 bit alternate interface is always used. Capture uses highest sample rate. PCM8 HF interface is used because Windows supports PCM8 rather than 8 bit PCM. Trunc – Playback uses the 24 bit alt interface but all values are truncated to 16 bits. EAX & Effets U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Filtres Haute-Qualités EAX4 EAX4 offre des filtres audio « qualité studio »: • Automatic Gain Control Compressor : ajustement automatique du niveau sonore pour garder un niveau constant. • Autowah : pedale Wah-Wah • Chorus : effet de choeur. • Distortion : saturation du signal et ajout d’harmoniques. • Echo : mouvement et extension spatiale. • Equalizer : equaliseur 4 bandes. • Flanger : effet de tunnel ou de wooshing (passage d’un jet). • Frequency Shifter : translation en fréquence. • Vocal Morpher : filtre 4 bandes spécialisés pour la voie. • Pitch Shifter : translation en fréquence avec conservation des harmoniques. • Ring Modulator : effet de trémolo. Voir la documentation pour les paramètres associés à ces filtres. EAX & Effets U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Ressources Hardware Ces remarques s’appliquent aux cartes supportant EAX4 4 slots hardwares sont présents sur la carte. • permet de gérer 4 effets différents simultanément sur les buffers hardware. • des slots fixes: Slot0 = Reverb, Slot1 = Chorus (limitation driver). • au plus 2 slots associables à une source (limitation driver). Au niveau optimisation: • changer l’effet contenu dans un slot est lent. • changer le paramétrage d’un effet est rapide (1ms). • une application peut verrouiller des slots pour être sur que l’effet qu’il contient ne changera pas. Gestion des ressources: comme pour le gestionnaire de ressource hardware de DirectSound (DEFER) EAX & Effets U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Environnement de programmation SDK: voir le site développeur de Creative. EAX2 : libre EAX4 : libre mais réservé aux entreprises (secrets industriels) Compilation: – header: eax.h – bibliothèque: eaxguid.lib Principaux objets EAX: – Slotn (n=0,1,2,3) : les 4 slots hardware utilisables. – Context : propriétés globales de l’auditeur. – Source : propriétés des sources. EAX & Effets Support d’EAX U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Accès à l’ensemble de propriétés: • Créer une interface IDirectSound3DBuffer8 (pDS3D) il doit être un buffer hardware 3D (DSBCAPS_CTRL3D | DSBCAPS_LOCHARDWARE). il n’est pas nécessaire de la conserver. • Appeler la méthode QueryInterface sur IKsPropertySet. façon qu’ont les drivers d’exposer leurs capacités matérielles à DS. QueryInterface renvoie: • • succès si des capacités sont disponibles. un pointeur (pPSET) sur l’ensemble de propriétés. Test des propriétés EAX disponibles sur IKsPropertySet: appeler la méthode QuerySupport(guid,prop,&supp) • guid : identification de la fonctionnalité offerte EAXPROPERTYID_EAX40_x où x est pami Context, FXSlotn, Source. • prop : pour support éventuellement partiel sur les paramètres. EAXx_ALLPARAMETERS où x comme ci-dessus (mais en majuscule). le support est effectif si les flags KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET sont activés dans supp. EAX & Effets U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Contrôle et utilisation pratique L’interface IKsPropertySet expose les méthodes: – Set : pour fixer le propriété du GUID spécifié. – Get : pour récupérer le propriété du GUID spécifié. Exemples: EAXPROPERTYID_EAX40_Slotn permet de: – charger l’effet souhaité dans le slot n. – fixer/lire les caractéristiques du filtre placé dans le slot n. EAXPROPERTYID_EAX40_Source permet de: – indiquer quels sont slots actifs pour cette source. En pratique: – Il y a un IKsPropertySet par buffer hardware. – On affecte les effets dans les slots une fois pour toute. – Chaque buffer indique quels sont les slots qu’il utilise (≤2) ainsi que ses paramètres de configuration. DirectSound U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E déboggage Dans la configuration de DirectX dans le panneau de configuration, il est possible d’effectuer les réglages cicontre. Debug Output Level: quantité de traces envoyée dans la fenêtre output en mode debug. Multimedia Properties: ouverture du control panel « sound and audio device ». Sound Playback/Sound Recording: permet de consulter le statut des devices: Full/Standard/Basic acceleration Emulation (voir ci-après) DirectSound U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Réglage de l’accelération matérielle Le réglage de l’accelération matérielle se fait dans: Control Panel/Sound and Audio Device/[Audio]/Advanced/[Performance] Deux paramètres réglables: Harware Acceleration : niveau d’utilisation des capacités matérielles de la carte. Sample rate conversion quality: qualité de l’échantillonnage utilisé pour les conversions. Le niveau d’accélération a un impact direct sur les capacités matérielles visibles depuis les applications: Full : accélération DirectSound complète – – toutes les capacités matérielles de la carte sont utilisées. accès aux ensembles de propriétés (extensions IKsPropertySet) Standard : accélération classique. – – accélération matérielle sur les buffers secondaires. toutes les accélérations spécifiques à la carte sont désactivées (i.e. l’accès au IKsPropertySet désactivé). Basic : accélération de base – – pas d’accélération matérielle sur les buffers secondaires. mode à utiliser pour simuler les cartes sans accélération matérielle None: émulation – – – tout est fait sur le CPU (y compris le mixage). résultat envoyé sur le Win32 waveform-audio device. en général, très lent. Lectures et programmes U N IVERSIT É D E R EIMS C H AMP AGN E-A RD EN N E Lectures: – Fundamentals of Audio and Video Programming for Games Turcan & Wasson (chapitres 1, 2, 5, 6) – DirectX 9 Audio Exposed Fay (chapitre 8) – Game Audio Programming Boer (chapitres 1 à 9 + 11) Codes: cf le site SDK: AdjustSound, AmplitudeModulation, CaptureSound, EnumDevices, FullDuplexFilter, PlaySound, SoundFX, VoiceManagement.