IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Diriger un son sur un seul canal


Sujet :

Langage Delphi

  1. #1
    Inactif  
    Inscrit en
    Février 2004
    Messages
    97
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 97
    Points : 53
    Points
    53
    Par défaut Diriger un son sur un seul canal
    On trouve dans l'aide (auteur Waskol notamment) comment créer un son sur une carte avec DUREE et FREQUENCE.

    Mon problème est que je voudrais diriger ce son tantôt à droite, tantôt à gauche (genre audiogramme)
    Dans le code on trouve un "mono" mais pas de stéréo ...
    Comment faire ?
    Ce code est très difficile pour moi, je ne vois pas comment le transformer.
    Merci d'avance aux spécialistes "SON"...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    uses
      MMSystem;
     
    type
      TVolumeLevel = 0..127;
     
    procedure MakeSound(Frequency{Hz}, Duration{mSec}: Integer; Volume: TVolumeLevel);
    var
      WaveFormatEx: TWaveFormatEx;
      MS: TMemoryStream;
      i, TempInt, DataCount, RiffCount: integer;
      SoundValue: byte;
      w: double; // omega=2*pi*fréquence
    const
      Mono: Word = $0001; //Son Mono
      SampleRate: Integer = 11025; // autres taux d'échantillonnage possibles 8000, 11025, 22050, or 44100
     
      //Champs de l'en-tête d'un fichier .WAV
      RiffId: string = 'RIFF';
      WaveId: string = 'WAVE';
      FmtId: string = 'fmt ';
      DataId: string = 'data';
    begin
      //si la fréquence de la note est trop élevée par rapport au taux d'échantillonnage
      if Frequency > (0.6 * SampleRate) then
      begin
        //... on considère que la note sera injouable.
        ShowMessage(Format('Un taux d''échantillonage de %d est trop bas pour jouer une tonalité de %dHz',
          [SampleRate, Frequency]));
        Exit;
      end;
     
      with WaveFormatEx do
      begin
       //Paramètres d'un en-tête de fichier WAV au format PCM
        wFormatTag := WAVE_FORMAT_PCM;
        nChannels := Mono;
        nSamplesPerSec := SampleRate;
        wBitsPerSample := $0008;
        nBlockAlign := (nChannels * wBitsPerSample) div 8;
        nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
        cbSize := 0;
      end;
     
      MS := TMemoryStream.Create;
      with MS do
      begin
        //Calcule la longueur des données du son à jouer et celle du fichier WAV qui en découle
        DataCount := (Duration * SampleRate) div 1000; // sound data
        RiffCount := Length(WaveId) + Length(FmtId) + SizeOf(DWORD) +
          SizeOf(TWaveFormatEx) + Length(DataId) + SizeOf(DWORD) + DataCount; // données du fichier
        //écriture de l'en-tête du fichier WAV dans le flux mémoire
        Write(RiffId[1], 4); // 'RIFF'
        Write(RiffCount, SizeOf(DWORD)); // taille du fichier
        Write(WaveId[1], Length(WaveId)); // 'WAVE'
        Write(FmtId[1], Length(FmtId)); // 'fmt '
        TempInt := SizeOf(TWaveFormatEx);
        Write(TempInt, SizeOf(DWORD)); // taille de TWaveFormat
        Write(WaveFormatEx, SizeOf(TWaveFormatEx)); // taille d'un enregistrement WaveFormatEx
        Write(DataId[1], Length(DataId)); // 'data'
        Write(DataCount, SizeOf(DWORD)); // taille des données du son
        //calcule et écrit le signal sonore
        // calcul des valeurs qui composent le son, 
        // c'est une courbe sinusoïdale dont les valeurs sont comprises entre 0 et 255, 
        //donc l'axe médian de la sinusoïde est en y=127)
        w := 2 * Pi * Frequency; // omega
        for i := 0 to DataCount - 1 do
        begin
          SoundValue := 127 + trunc(Volume * sin(i * w / SampleRate));  // explication : wt = w * i / SampleRate
         //on écrit notre "point" de la courbe dans notre fichier WAV
          Write(SoundValue, SizeOf(Byte));
        end;
        //Maintenant on joue le son en disant à Windows :
        //-SND_MEMORY : c'est un son écrit dans un flux mémoire
        //-SND_SYNC : de jouer le son de façon synchrone (tant que le son n'est pas terminé, le code ne se déroule plus.
    	// Ainsi, un deuxième appel consécutif à notre procédure ne "coupera pas le sifflet" du premier appel.
        sndPlaySound(MS.Memory, SND_MEMORY or SND_SYNC);
        MS.Free;
      end;
    end;
    OH, OH ! Je vois après quelques jours que les spécialistes "SON" ne sont pas légion !
    Le message a été lu ... mais pour l'instant personne ne peut me dire comment envoyer le son généré sur l'une ou l'autre enceinte (ou écouteurs).
    Je commence à désespérer ! A l'aide ! Help !

  2. #2
    Membre actif Avatar de liazidf
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations forums :
    Inscription : Mai 2002
    Messages : 281
    Points : 261
    Points
    261
    Par défaut
    Bonsoir,
    Je m'y connais pas trés bien en gestion son, j'espère que vous aurai une idée ICI.
    Bon courage.

  3. #3
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Je t'apporte une réponse ce soir.

    (Je fus Waskol, donc je saurais te répondre )


    Vite fais comme ça, il faut créer le son en Stereo ( nChannels := 2; ), et placer les données sur le canal gauche, ou le canal droite (et sur l'autre canal, mettre le son à 0, selon l'effet désiré. :

    Donc au lieu de ça pour du Mono :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for i := 0 to DataCount - 1 do
        begin
          SoundValue := 127 + trunc(Volume * sin(i * w / SampleRate));  // explication : wt = w * i / SampleRate
         //on écrit notre "point" de la courbe dans notre fichier WAV
          Write(SoundValue, SizeOf(Byte)); //<-- on écrit 1 octet (1 canal)
        end;
    Il faut écrire deux octets consécutifs, un pour le canel gauche, l'autre pour le canal droit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for i := 0 to DataCount - 1 do
        begin
          SoundValueLeft := 127 + trunc(Volume * sin(i * w / SampleRate));  // explication : wt = w * i / SampleRate
          SoundValueRight:=SoundValueLeft ;
         //on écrit notre "point" de la courbe dans notre fichier WAV
          Write(SoundValueLeft, SizeOf(Byte)); //<-- on écrit 1 octet (canal gauche)
          Write(SoundValueRight, SizeOf(Byte)); //<-- on écrit un 2ème octet (canal droit)
        end;

    Et dans ton cas, on dirige l'octet de son vers l'un ou l'autre canal, A supposer qu'on est déclaré une variable booléenne "SonAGauche", ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    for i := 0 to DataCount - 1 do
        begin
          SoundValue := 127 + trunc(Volume * sin(i * w / SampleRate));  // explication : wt = w * i / SampleRate
         if SonAGauche then
         begin         
             Write(SoundValue, SizeOf(Byte)); //son à gauche,
              Write(0, SizeOf(Byte)); //rien à droite
         end else
         begin
             Write(0, SizeOf(Byte)); //rien à gauche
             Write(SoundValue, SizeOf(Byte)); //son à droite
         end;
    Pour faire ça bien, évidemment, il faut savoir comment est structuré un fichier wav, pusqu'en fait, c'est un fichier Wav ce qu'on envoie à la carte son, mais en passant directement par la mémoire vive (au lieu de créer le fichier, l'écrire sur le disque dur et le lire depuis le disque dur)
    http://sub0.developpez.com/FormatWAV/FormatWAV.htm

    En attendant, c'est pas mal
    tu vas y arriver ?

  4. #4
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    J'ai pas mon Delphi pour tester, alors j'ai fais à la main, croisons les doigts
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    uses
      MMSystem;
     
    type
      TVolumeLevel = 0..127;
     
      TCanal=(cGauche,cDroit,CGaucheDroit);
     
    procedure MakeSound(Frequency{Hz}, Duration{mSec}: Integer; Volume: TVolumeLevel;Canal:TCanal);
    var
      WaveFormatEx: TWaveFormatEx;
      MS: TMemoryStream;
      i, TempInt, DataCount, RiffCount: integer;
      SoundValue: byte;
      w: double; // omega=2*pi*fréquence
    const
      Mono: Word = $0001; //Son Mono
      Stereo: Word = $0002; //Son Stereo
      SampleRate: Integer = 11025; // autres taux d'échantillonnage possibles 8000, 11025, 22050, or 44100
     
      //Champs de l'en-tête d'un fichier .WAV
      RiffId: string = 'RIFF';
      WaveId: string = 'WAVE';
      FmtId: string = 'fmt ';
      DataId: string = 'data';
    begin
      //si la fréquence de la note est trop élevée par rapport au taux d'échantillonnage
      if Frequency > (0.6 * SampleRate) then
      begin
        //... on considère que la note sera injouable.
        ShowMessage(Format('Un taux d''échantillonage de %d est trop bas pour jouer une tonalité de %dHz',
          [SampleRate, Frequency]));
        Exit;
      end;
     
      with WaveFormatEx do
      begin
       //Paramètres d'un en-tête de fichier WAV au format PCM
        wFormatTag := WAVE_FORMAT_PCM;
        nChannels := Stereo;
        nSamplesPerSec := SampleRate;
        wBitsPerSample := $0008;
        nBlockAlign := (nChannels * wBitsPerSample) div 8;
        nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
        cbSize := 0;
      end;
     
      MS := TMemoryStream.Create;
      with MS do
      begin
        //Calcule la longueur des données du son à jouer et celle du fichier WAV qui en découle
        DataCount := (Duration * SampleRate) div 1000; // sound data
        RiffCount := Length(WaveId) + Length(FmtId) + SizeOf(DWORD) +
          SizeOf(TWaveFormatEx) + Length(DataId) + SizeOf(DWORD) + DataCount; // données du fichier
        //écriture de l'en-tête du fichier WAV dans le flux mémoire
        Write(RiffId[1], 4); // 'RIFF'
        Write(RiffCount, SizeOf(DWORD)); // taille du fichier
        Write(WaveId[1], Length(WaveId)); // 'WAVE'
        Write(FmtId[1], Length(FmtId)); // 'fmt '
        TempInt := SizeOf(TWaveFormatEx);
        Write(TempInt, SizeOf(DWORD)); // taille de TWaveFormat
        Write(WaveFormatEx, SizeOf(TWaveFormatEx)); // taille d'un enregistrement WaveFormatEx
        Write(DataId[1], Length(DataId)); // 'data'
        Write(DataCount, SizeOf(DWORD)); // taille des données du son
        //calcule et écrit le signal sonore
        // calcul des valeurs qui composent le son, 
        // c'est une courbe sinusoïdale dont les valeurs sont comprises entre 0 et 255, 
        //donc l'axe médian de la sinusoïde est en y=127)
        w := 2 * Pi * Frequency; // omega
        for i := 0 to DataCount - 1 do
        begin
          SoundValue := 127 + trunc(Volume * sin(i * w / SampleRate));  // explication : wt = w * i / SampleRate
         //on écrit notre "point" de la courbe dans notre fichier WAV
         Case Canal of
           cGauche: begin        
                            Write(SoundValue, SizeOf(Byte)); //son à gauche,
                            Write(0, SizeOf(Byte)); //rien à droite
                         end;
         cDroit : begin
                       Write(0, SizeOf(Byte)); //rien à gauche
                       Write(SoundValue, SizeOf(Byte)); //son à droite
                    end;
         cGaucheDroit:begin
                       Write(SoundValue, SizeOf(Byte)); //son à gauche,
                       Write(SoundValue, SizeOf(Byte)); //son à droite
                    end; 
         end;
     
     
        end;
        //Maintenant on joue le son en disant à Windows :
        //-SND_MEMORY : c'est un son écrit dans un flux mémoire
        //-SND_SYNC : de jouer le son de façon synchrone (tant que le son n'est pas terminé, le code ne se déroule plus.
    	// Ainsi, un deuxième appel consécutif à notre procédure ne "coupera pas le sifflet" du premier appel.
        sndPlaySound(MS.Memory, SND_MEMORY or SND_SYNC);
        MS.Free;
      end;
    end;

    Voilà, ça devrait fonctionner, et ceci devrait sortir un LA3 à gauche, de 5 secondes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cGauche);
    et là à droite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cDroit );
    et des deux cotés à la fois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cGaucheDroit);

  5. #5
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 929
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 929
    Points : 15 363
    Points
    15 363
    Par défaut
    Salut,

    Puis-je me permettre de m'immiscer (j'aime bien quand il y a les mots "son", "wave", etc.) ?

    Citation Envoyé par LadyWasky Voir le message
    Voilà, ça devrait fonctionner, et ceci devrait sortir un LA3 à gauche, de 5 secondes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cGauche);
    et là à droite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cDroit );
    et des deux cotés à la fois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MakeSound(440, 5, 127, cGaucheDroit);
    Après visite chez Torry et tests, ça sera mieux comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    MakeSound(440, 5000, 127, cGauche);
    MakeSound(440, 5000, 127, cDroit );
    MakeSound(440, 5000, 127, cGaucheDroit);
    Mais avant, et pour que Delphi soit content, il faut remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            Write(0, SizeOf(Byte));
    par, pourquoi pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            Write(zero, SizeOf(Byte));
    sans oublier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const
      zero: byte = 128; // à rajouter (0..255, donc le milieu c'est 128 [ou 127 mais c'est plus joli avec 128, GoldWave dixit !])
    Sinon,
    [Erreur] Unit1.pas(108): Variable requise

  6. #6
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Merci jipété.

    Bah oui, c'est ça de tout faire à la mimine à l'avaugle, c'est qu'on écrit n'importe quoi

  7. #7
    Inactif  
    Inscrit en
    Février 2004
    Messages
    97
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 97
    Points : 53
    Points
    53
    Par défaut
    Voilà,
    je suis venu,
    j'ai vu,
    j'ai testé !
    Et c'est tout bon !

    Vous êtes pour moi des dieux ...
    Encore une fois cette solidarité du forum m'épate et me ravit ...

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 23
    Points : 28
    Points
    28
    Par défaut
    Binjour

    J'ai copié-collé le code de waskol-aka-ladywasky qui fonctionne à merveille.

    Moi c'est pareil, je cherche à générer un bip d'une certaine fréquence à un certain volume. Je m'étais intéressé à la fonction windows.beep(frequency, duration) mais je n'entends rien quand je l'invoque. Alors qu'avec le code de wask' ça marche bien.

    Mais je m'aperçois que ce code crée carrément un enregistrement wav pour le donner à manger à la carte son... y a quand même plus simple, non, ou bien? genre un windows.beep() mais qui fonctionnerait... ou alors, y a pas, faut vraiment générer de toutes pièces la forme d'onde ?

    Remarquez, dans un sens c'est pas plus mal, ça peut me permettre de générer un decrescendo sur la fin pour terminer le son joliment, mais dans l'autre sens, ça va me bouffer les perfs si je dois recalculer à chaque fois la forme d'onde de tous les bips que je veux générer (parce qu'il y en aura plusieurs, les bougres). Ou alors faudra que je calcule au prélavable toutes les formes d'ondes de tous les différents bips que je veux générer...

    Bon en tous cas merci Waskolady... non, Whisky d'ado... non, pardon, enfin, mes hommages madame.

  9. #9
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Citation Envoyé par darinze Voir le message
    non, pardon, enfin, mes hommages madame.
    De rien jeune homme

    Sinon, y'a pas, faut vraiment générer la forme d'onde, contrairement à ce qu'on pouvait faire sous DOS (la belle époque). D'ailleurs, c'est super "" pour faire un émulateur qui ne tousse pas (c'est le problème de DOSBOX entre autres), parce qu'on aligne pleins de petits de bout de wav les uns à la suite des autres, un petit retard de temporisation et hop, c'est la cata.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Jouer son sur une seule enceinte
    Par benjop dans le forum Windows Forms
    Réponses: 4
    Dernier message: 17/11/2007, 18h06
  2. ROLLBACK sur une seul enregistrement
    Par toctoc80 dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 30/04/2004, 20h22
  3. Recherche multi-mots sur une seule colonne
    Par Badiste dans le forum Langage SQL
    Réponses: 2
    Dernier message: 31/03/2004, 11h24
  4. Son sur portable
    Par kacedda dans le forum Matériel
    Réponses: 8
    Dernier message: 21/03/2004, 18h42
  5. Query Begin et Commit son sur un bateau....
    Par faoz75 dans le forum Requêtes
    Réponses: 5
    Dernier message: 15/08/2003, 11h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo