Le premier site francophone dédié au développement Pocket PC


Comment jouer une note ?
 
   



Jouer une note..

Je me suis amusé à développer un petit jeu style "Simon". Vous savez, ce jeu où vous devez répétser une séquence de plus en plus longue de notes couplées à des couleurs. Dans un premier temps j'ai associé à chaque couleur un petit fichier .wav correspondant à chaque note. Le problème c'est qu'à la longue le .exe devient assez volumineux, et ce à cause des 8 fichiers .wav que j'avais inclus aux ressources.

Une seule solution, trouver le moyen de jouer une note sans passer par le pré-enregistrement de celle-ci en .wav

Les fonction MIDI du Pocket PC

Si on regarde attentivement la documentation concernant le SDK Pocket PC 2002 on remarque une section "MIDI". Cette section implique que Pocket PC 2002 est capable de jouer des fichiers au format MIDI où la partition est décrite sous la forme de notes pour des instruments. Les fichiers MIDI sont très petits car ils expliquent à l'ordinateur comment jouer la musique et ne stockent pas la musique elle-même.

Attention tout de même, les fonctions MIDI sont présentes dans Pocket PC 2002, mais pas dans Pocket PC 2000. En les utilisant vous rendez votre programme incompatible avec les Pocket PC 2000, mais aujourd'hui, ce n'est pas trop un problème puisque la quasi totalité des Pocket PC du marché sont sous OS Pocket PC 2002.

La fonction "PlayNote"

En lisant la doc je suis tombé sur un exemple qui permet de jouer un son DTMF (vous savez les sons émis par les téléphone quand on tape un numéro). J'ai adapté cette exemple pour en faire une fonction directement utilisable. Cette fonction permet de jouer une note pendant un certain temps. En fait, c'est 2 fonctions que nous allons coder car l'appel étant asynchrone ont doit attendre la fin de la note pour fermer le service.

Pour commencer vous devez déclarer en variable globale un handle qui servira d'événement pour la gestion de la fin de la note :

HANDLE FinNoteEvent;

Vous devez ajouter une fonction qui sera utilisée comme callback par le service qui produit les sons. Voici son code (les paramètres doivent être impérativement du même type que dans le code qui suit) :

void CALLBACK PlayNoteProc(HWAVEOUT hwo,
   UINT uMsg, DWORD dwInstance,
   DWORD dwParam1, 
   DWORD dwParam2)
 {
    if (uMsg==WOM_DONE)
     {
       SetEvent(FinNoteEvent);
     }
    return;
 }

Vous pouvez ensuite ajouter le code même de la fonction "PlayNote". Le premier paramètre est la fréquence de la note. Plus cette fréquence est faible, plus la note des grave. Le second paramètre est le durée en 1/10ème de seconde.

void PlayNote(int wNote, int wDuree)
{

FinNoteEvent = CreateEvent(NULL,TRUE, FALSE, NULL);
  WAVEFORMAT_MIDI wfm;
  memset(&wfm,0,sizeof(wfm));
  wfm.wfx.wFormatTag=WAVE_FORMAT_MIDI;
  wfm.wfx.nChannels=1;
  wfm.wfx.nSamplesPerSec=32;
  wfm.wfx.nAvgBytesPerSec=32;
  wfm.wfx.nBlockAlign=sizeof(WAVEFORMAT_MIDI_MESSAGE);
  wfm.wfx.wBitsPerSample=16;
  wfm.wfx.cbSize=WAVEFORMAT_MIDI_EXTRASIZE;
  wfm.USecPerQuarterNote=9600000;

  MMRESULT Result;
  HWAVEOUT hWaveOut;
  Result = waveOutOpen(&hWaveOut,
    WAVE_MAPPER,
    (LPWAVEFORMATEX)&wfm,
    (DWORD)PlayNoteProc,
    0, 
    CALLBACK_FUNCTION);
  if (Result!=MMSYSERR_NOERROR) return;
  
  WAVEFORMAT_MIDI_MESSAGE MidiMessage[2];
  MidiMessage[0].DeltaTicks=0;
  MidiMessage[0].MidiMsg=0x203F0000 | wNote;
  MidiMessage[1].DeltaTicks=wDuree;
  MidiMessage[1].MidiMsg=0;
  WAVEHDR WaveHdr;
  WaveHdr.lpData = (LPSTR)&MidiMessage;
  WaveHdr.dwBufferLength = sizeof(MidiMessage);
  WaveHdr.dwFlags = WHDR_BEGINLOOP|WHDR_ENDLOOP;
  WaveHdr.dwLoops = 1;
  Result = waveOutPrepareHeader(hWaveOut, &WaveHdr, sizeof(WaveHdr));
  Result = waveOutWrite(hWaveOut, &WaveHdr, sizeof(WaveHdr));
  WaitForSingleObject(FinNoteEvent, INFINITE);
  Result = waveOutUnprepareHeader(hWaveOut, &WaveHdr, sizeof(WaveHdr));
  Result = waveOutClose(hWaveOut);
  CloseHandle(FinNotesEvent);
}

Pour jouer une note il vous suffit d'appeler dans votre code par exemple :

PlayNote(2000, 3);

Pour que la note dont la fréquence est 2000 soit jouée pendant 3/10ème de seconde.

Amélioration possible

Cette fonction est synchrone. Elle est utilisable dans la pluparts des cas. C'est un beep fortement amélioré. Son défaut c'est qu'elle ne vous rend la main qu'une fois la note complètement jouée. Dans l'exemple PlayNote(2000, 3); votre programme est suspendu pendant 3/10ème de seconde...

Si quelqu'un veut proposer une solution (qui marches) je suis prêt à la publier.

Si vous rencontrez des problèmes concernant cet article, n'hésitez pas à poser vos questions sur les forums "eVC++" ou "Articles eVC++" de CodePPC.

Stéphane Sibué

 

 

       
   
 
   
Copyright 2001-2004 - Tous droits réservés
 
   

iPAQ est un produit de COMPAQ.
Visual Tools est un produit de Microsoft Corporation.
Toutes les autres marques et produits présents dans ces pages sont la propriété exclusive de leurs sociétés respectives.