> Bibliothèque
PrograZine issue #10 - http://www.citeweb.net/discase/10/tsound.htm Edito Sommaire Contribution Contacts


La classe TSound
par Plouf - plouf@win.be http://www.citeweb.net/pmplayer
Initié Win9x Delphi

    La classe TSound se propose de fournir une interface entre les api sons de Windows et le programme, plus évoluées que les low-level de ce premier, mais sans entrer dans des routines high-level qui seraient par exemple des routines du genre PlayWav ou autre.

    Ce sont donc des routines "mid-level", qui devraient convenir dans 95% des cas pour des programmes désireux d'utiliser la mapeur son d'une façon un rien évoluée.

    Tous les réglages relatifs au périphérique son se font via des propriétés de cette classe. Ainsi, aucune méthode de TSound ne prend de paramètres.

    En théorie, il ne faut jamais modifier les valeurs de configuration pendant que le son est en train d'être joué. Néanmoins, TSound l'accepte, mais stocke cette valeur à part sans mettre à jour le périphérique. C'est ce qui explique la différence possible entre les valeurs lues des attributs et ceux écrits. Les valeurs lues sont toujours les valeurs courantes.
>Conditions et utilisation de TSound

     TSound s'utilise comme n'importe quelle unité, en l'incluant dans votre code avec un simple Uses Sound. Si vous désirez utiliser le DirectSound, vous devez avoir l'unité DSound.Pas disponible. Vous pouvez la charger sur le site du "Project Jedi" : http://www.delphi-jedi.org/

     Si tel n'est pas le cas, vous devez écrire la directive de macro compilation suivante au début de Sound.Pas : {$UNDEF DSound}

     TSound est conçu de manière à être totalement autonome, de ce fait vous pouvez très bien si le coeur vous en dit créer un tableau d'objets TSound, du genre Var SoundDevice:Array[0..15] Of TSound;

     Si votre carte son est capable de restituer plusieurs sons en même temps, ou si vous utilisez le DirectSound, vous pourrez même les utiliser simultanément sans aucun risque d'interférence.

     TSound est essentiellement prévu pour la gestion du mappeur son Microsoft sous Windows 9x et Windows 2000. C'est là qu'il sera le plus efficace. Lors de la sortie vers fichier .Wav, TSound tentera d'adopter un comportement qui se rapproche le plus d'un périphérique son classique : par exemple, la méthode Pause fonctionne lors d'une exporation Wav, mais pas la propriété Volume ou la méthode UpDate.

     En ce qui concerne le DirectSound, TSound ayant été programmé pour "survivre" le plus longtemps possible en l'absence d'appel de la méthode Perform, la taille du buffer DirectSound devra être importante. Comme il est interdit (du moins en théorie mais TSound se veut stable et compatible avec le maximum de configuration) de lire le contenu de ce buffer, une copie en mémoire de celui-ci devra être créée, entrainant un gaspillage certain. En effet, TSound doit pouvoir retrouver le contenu du buffer pour accomplir certaines de ses fonctions (Pointeur actuel, ...). En conclusion, n'utilisez DirectSound que si vraiment vous en avez un besoin spécifique.

     L'unité Sound est FREEWARE, elle peut s'utiliser sans charge d'aucune sorte, et sans obligatoirement avoir à m'en avertir (néamoins, j'aime savoir ce qu'on fait de mon travail :)). Si vous désirez la modifier, la perfectionner, la corriger ou l'adapter à vos besoins, bref si vous devez modifier son code, pas de problème mais cette fois j'exige en être avertit (par mail ou tout autre moyen) et connaître la nature de ces modifications.

     Je refuse par contre l'utilisation de cette unité dans un cadre lucratif : bref, interdit de se faire des sous avec mon travail tant que je n'ai pas ma part du gâteau :)

     Pour tout contact :
     plouf@win.be
     theplouf@yahoo.com
     www.citeweb.net/pmplayer
l

     ou par courier (le vrai cette-fois) :
     Philippe Detournay
     17 rue de Floreffe
     5150      Franière
     Belgium - Belgique
l

     Bien sur, si vous avez le moindre problème quand à son utilisation ou même d'un point de vue programation, n'hésitez pas à me contacter. Je reçois assez peu de courrier et j'ai donc du temps à y consacrer :)
>Les réglages sous formes de propriétés (Read/Write)
      Nom:Type [Valeur par défaut]
      DeviceType:Word [0]
        Type du périphérique utilisé
          0:Mappeur son microsoft
          1:Sauvegarde sur disque dur
          2:DirectSound
      DeviceIndex:LongWord [-1]
        Index du périphérique dont le type est défini par DeviceType
        DeviceType=0
          -1:WaveMapper : autodetection de la part de Windows
          Autre:Indice du périphérique son de Windows voulu
        DeviceType=1
          0:Sortie vers fichier .wav
        DeviceType=2
          0:Mapeur DirectSound
      OutFrequency:Word [22050]
        Vitesse de mixage utilisée
      OutStereo:Boolean [False]
        Utilisation ou non du son en stéréo
      Out16Bits:Boolean [False]
        Utilisation ou non du son en 16bits
      OutFileName:String ['']
        Nom de fichier utilisé si DeviceType=1
      InfoStructureSize:LongWord [0]
        Taille réservée pour le programme dans chacun des buffers,
        les pointers sont retournés via TSound.Info
        
      BufferSize:LongWord [4096]
        Taille en octet des buffers à utiliser
      BufferCount:Word [32]
        Nombre de buffers à utiliser
      PreBuffering:Single [0]
        Durée en seconde de la tentative de décodage prioritaire lors
        de l'initialisation afin de ne pas débuter avec des buffers vides.
      Volume:Word [65535]
        Le volume du périphérique allant de 0 (silence) à 65535 (maximum)
l
>Les propriétés read only

     A l'exception de Playing, ces propriétés sont indéfinies lorsque Playing est False et ne devraient pas être lues.
      DeviceHandle:LongWord
        Hande du périphérique son ouvert par Windows si DeviceType=0
      Info[BufferIndex:LongWord]:Pointer
        Pointeur vers la zone mémoire réservée pour le programe utilisant
        TSound dans le buffer BufferIndex
  
      PlayedBytes:LongWord
        Nombre d'octets joués par TSound depuis sa dernière initialisation
      CurrentBufferIndex:LongWord
        Index du buffer actuellement joué
      OffsetInCurrentBuffer:LongWord
        Décalage en octet par rapport au début du buffer courant de l'octet
        actuellement joué
      BuffersReady:LongWord
        Nombre de buffers prêts et en attente d'être joués. Si ce nombre est
        bas, il y a risque de coupure du son.
      CurrentBufferAddress:Pointer
        Pointeur vers le buffer actuellement joué
      Timer:LongWord
        Retourne la durée en millisecondes écoulée depuis la dernière réinitialisation
        du périphérique son.
      Playing:Boolean
        Vaut True si le son est actuelement joué, False sinon.
      Paused:Boolean
        Vaut true si le son est joué mais en pause.
      DecodedBytes:LongWord
        Nombre d'octets actuellement décodés et envoyés au mappeur par TSound
l
>Les méthodes
      Function Play:Boolean;
        Lance le son en utilisant les réglages courants. Retourne True si l'opération
        à réussit, False sinon. Si False est retourné, une erreur est également générée
        dans TSound.ErrorHandler
      Procedure Stop;
        Arrête le son et désitialise le périphérique ainsi que les buffers. Tout buffer
        non joué est perdu. Utilisez FlushBuffers avant d'utiliser Stop afin
        d'éviter de perdre les dernières secondes du son.
      Procedure Pause;
        Arrête temporairement le son. Les buffers en attente ne sont pas perdus.
      Procedure Resume;
        Reprend le son suspendu avec Pause.
      Procedure Perform;
        Vous devez régulièrement appeler Perform afin de permettre à TSound de
        décoder de nouveaux buffers. En effet, TSound fonctionne passivement,
        aucun évènement ne sera jamais généré en dehors de l'appel Perform,
        et par conséquent DecodeHandler non plus. Plus vous pouvez garantir
        un appel fréquent de cette méthode, moins vous aurez de risque d'avoir
        des coupures dans le son. Si vous ne pouvez pas garantir une bonne
        fréquence d'appel, augmentez la taille des buffers.
      Procedure Update;
        Réinitialise les paramètres de périphérique afin de se mettre à jour
        avec les nouveaux réglages éventuellements entrés dans TSound. Les
        buffers en attente sont perdus. Update ne peut pas être utilisé si
        DeviceType=1.
      Procedure FlushBuffers;
        Cette méthode coupe la génération de l'évenement DecodeHandler, et
        génère l'évent MessageHandler avec comme paramètre SND_FLUSHDONE quand
        aucun buffer ne reste en attente. Il est conseillé d'appeler FlushBuffers
        avant d'appeler Stop. Il est déconseillé d'utiliser cette méthode avec
        DeviceType=2 car elle est peu précise.
      Procedure FlushThenStop;
        Même chose que FlushBuffers mais la méthode Stop est appelée automatiquement
        une fois le flush effectué.
      Procedure FlushThenUpdate;
        Même chose que FlushBuffers mais la méthode Update est appelée automatiquement
        une fois le flush effectué. FlushThenUpdate ne peut pas être utilisé si
        DeviceType=1.
      Procedure FloodFill;
        Rempli en une fois tous les buffers. Attention, ceci peut prendre du
        temps si vous avez spécifié de nombreux buffers de grande taille,
        votre application pourait alors ne plus répondre pendant un temps non
        négligeable.
      Procedure Continue;
        Cette méthode annule un ordre FlushBuffers précédement envoyé. Appeler
        Continue permet de regénérer des évents DecodeHandler.
l
>Les évènements
      TDecHandler=Procedure(Pntr,Nfo:Pointer);
      DecodeHandler:TDecHandler
l

     Est appelé lorsque TSound décode un nouveau buffer et vous demande de le remplir. Pntr contient un pointeur vers la zone donnée du buffer, et Nfo un pointeur vers la zone réservée pour l'application lors de l'initialisation. La taille du buffer à remplir est la taille des buffers précisés lors de l'initialisation du périphérique est peut être lue dans TSound.BufferSize.
      TErrHandler=Procedure(Err1,Err2:LongWord;Txt:String);
      ErrorHandler:TErrHandler
l

     Est appelé lorsqu'une erreur survient. Txt contient un texte précisant l'erreur survenue.
  • Err1=1 : une erreur venant du wavemappeur de Windows. Le numéro de l'erreur se trouve dans Err2
  • Err1=2 : une erreur est survenue lors de l'écriture sur le disque dur. Arrive si DeviceType=1 et que, par exemple, le disque est plein. Err2 contient le numéro de l'erreur I/O
  • Err1=3 : impossible de créer le fichier spécifié par OutFileName. Err2 contient le numéro de l'erreur I/O
  • Err1=4 : Type de périphérique inconnu
  • Err1=5 : Direct Sound non disponible
  • Err1=6 : Erreur à l'initialisation de DirectSound
  • Err1=7 : Une méthode a été utilisée incorectement

      TMsgHandler=Procedure(Msg,Param1,Param2:LongWord);
      MessageHandler:TMsgHandler
l

     Est appelée pour vous signaler des messages divers. Msg=SND_FLUSHDONE : suite à une instruction FlushBuffers, le dernier des buffers en attente a été joué. La suite logique à donner à ce message est Stop
>Remarques diverses

    TSound est totalement passif, il ne prend jamais la main, ce qui fait qu'il faut continuelement appeler Perform. TSound n'est capable d'envoyer des events que lors de cet appel, y compris SND_FLUSHDONE. On n'insistera que trop peu sur l'importance d'une fréquence élevée et régulière de l'appel de cette méthode.

    Les valeurs lues dans les propriétés ne refletent toujours que l'état actuel du périphérique. Elles peuvent ainsi différer des valeurs écrites. Les valeurs lues sont indéfinies quand le périphérique n'est pas activé.

    La propriété PreBuffering peut accueil n'importe quelle valeur, mais le prébuffer réelement effectué ne peut dépasser la longueur totale des buffers.

    DeviceHandle est fourni afin de pouvoir utiliser des fonctions non gérés par TSound. Il faut cependant éviter d'utiliser les fonctions mmedia suivantes :
    waveOutOpen
    waveOutPrepareHeader
    waveOutUnPrepareHeader
    waveOutWrite
    waveOutReset
    waveOutClose
    waveOutPause
    waveOutRestart
    waveOutSetVolume
    waveOutGetVolume
l

    Tout appel à ces fonctions en utilisant DeviceHandle peut provoquer des comportements imprévisibles de la part de TSound et éventuelement provoquer une erreur générale dans le programme.

     La compatibilité DirectSound est uniquement fournie afin de permettre l'utilisation simultanée de plusieurs programmes utilisant du son sur des drivers n'en proposant pas l'option. L'utilisation du DirectSound utilise beaucoup plus de mémoire que le mappeur son standard, et est également moins précis en ce qui concerne les flush de buffers. En général on préférera l'utilisation du mappeur son si l'utilisateur ne demande pas explicitement l'utilisation de DirectSound.
>Améliorations prévues dans les prochaines versions

     Une prise en charge de la recherche des périphériques disponibles, aussi bien en wave mappeur qu'en DSound

    Une possibilité d'optimisation d'utilisation de la mémoire si on ne désire pas utiliser les options du DirectSound nécéssitant une relecture des buffers.

    Un update un peu plus malin qu'un simple Stop/Play
Cet article est la propriété de Plouf. La copie et la diffusion sont libres sauf dans un but lucratif sans accord explicite de l'auteur.