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

API, COM et SDKs Delphi Discussion :

Trouver les peak values des deux canaux du haut-parleur


Sujet :

API, COM et SDKs Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Mouais... j'avais vu cette bibliothèque. C'est un monument, c'est distribué sous forme de DLL, et il y a un wrapper Delphi autour de tout ça. Et c'est gratuit unquement pour des projets freeware...

    Or, tout mon projet qui est une DLL de fonctions d'extension à un langage freeware de type clone de Basic, est de distribuer mon produit de facto en Open Source, sans aucune contrrainte de licence, libre de droit pour tout usage: personnel, associatif, éducatif, commercial, avec le droit de copier et de modifier les sources sans restriction. Oui, je sais, je suis un peu "bizarre", mais c'est ma façon de rendre un peu au net ce qu'il m'a donné...

    Et puis, utiliser une grosse DLL d'une partie tièrce pour faire ce qu'une simple API Windows est supposée faire, c'est un peu tirer sur des moineaux avec des canons. Moi, j'aime bien comprendre, et là, je ne comprends pas où est mon erreur. Car, forcément, l'erreur vient de mon code, puisque d'autres logiciels sont capables de faire ce que je veux faire.

    EDIT

    Je cherche une solution à ce problème depuis plus d'une semaine. J'ai consulté des centaines de pages internet, y compris sur de siites russes, chinois, polonais, brésiliens, que sais-je. Il y a une multitude de sites documentant la récupération du volume général - je l'ai et ça marche bien. Mais il n'y a pratiquement rien concernant cette fichue méthode GetChannelsPeakValues. La seule information sérieuse à ce sujet vient de MSDN, mais c'est en syntaxe C. Je ne parle pas C, et j'ai donc un doute sur ma façon de traduire cela en Delphi. Le problème peut très bien venir de là. Ce qui est troublant, c'est que le nombre de canaux retourné est bien 2, la valeur pour le premier canal (le gauche) est bien retournée au bon endroit et est correcte, mais celle pour le canal 2 (le droit) n'apparaît jamais et reste à zéro, ceci sans signaler d'erreur.

    A toutes fins utiles, je poste ici l'état actuel de l'unité qui contient le code en difficulté:
    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
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    unit KGF_unit_SpeakerControl;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics,
      Controls, Forms, Dialogs, ActiveX, ComObj, MMSystem,     
      ComCtrls, ExtCtrls,
      KGF_unit_data;          // uniquement pour la variable MainFormHandle qui y est définie de façon globale
     
    type
      EDATAFLOW = TOleEnum;
      EROLE = TOleEnum;
     
      IMMDevice = interface(IUnknown)
        ['{D666063F-1587-4E43-81F1-B948E807363F}']
        function Activate(const iid: TGUID; const dwClsCtx: UINT; const pActivationParams: PPropVariant; out ppInterface: IUnknown)
          : HRESULT; stdcall;
      end;
     
      IMMDeviceCollection = interface(IUnknown)
        ['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
      end;
     
      IMMDeviceEnumerator = interface(IUnknown)
        ['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
        function EnumAudioEndpoints(const dataFlow: EDATAFLOW; const dwStateMask: DWORD; out ppDevices: IMMDeviceCollection): HRESULT; stdcall;
        function GetDefaultAudioEndpoint(const dataFlow: EDATAFLOW; const role: EROLE; out ppEndpoint: IMMDevice): HRESULT; stdcall;
      end;
     
      IAudioMeterInformation = interface(IUnknown)
        ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
        function GetPeakValue(out pfPeak: Single): HRESULT; stdcall;
        function GetMeteringChannelCount(out pnChannelCount: UINT): HRESULT; stdcall;
        function GetChannelsPeakValues(u32ChannelCount: UINT; out afPeakValues: pSingle): HRESULT; stdcall;
        function QueryHardwareSupport(out pdwHardwareSupportMask: UINT): HRESULT; stdcall;
      end;
     
     
    const
      IID_IMMDeviceEnumerator: TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
      CLASS_IMMDeviceEnumerator: TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
      IID_IAudioMeterInformation: TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
      eRender = $00000000;
      eConsole = $00000000;
     
    type TDummyForm = class
      class procedure Timer1Timer(Sender: TObject);
    end;
     
    var
      peak: IAudioMeterInformation = nil;
      SpeakerTimer: TTimer;
       pVolumeOutputL, pVolumeOutputR, pVolume: pinteger;   // <=== utilisé pour retourner dynamiquement les peak values deu volume
      MaxOutput: Integer;
      device: IMMDevice;
      deviceEnumerator: IMMDeviceEnumerator;
      nChannels: UINT;
      ApplicationTitle: String;                                                    // utilisé pour mémoriser le titre de la fenêtre principale
     
    implementation
     
     
    function InitSpeakerControl(time, MaxV: integer; poutL, poutR, pVol: pinteger):integer; stdcall; export;
    var
        n: integer;
    begin
      SpeakerTimer := TTimer.Create(nil);
      SpeakerTimer.Enabled := False;
      SpeakerTimer.OnTimer := TDummyForm.Timer1Timer;
      SpeakerTimer.Interval:= time;
      MaxOutput := MaxV;
      pVolumeOutputL := poutL;
      pVolumeOutputR := poutR;
      pVolume := pVol;
      CoCreateInstance(CLASS_IMMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, deviceEnumerator);
      deviceEnumerator.GetDefaultAudioEndpoint(eRender, eConsole, device);
      device.Activate(IID_IAudioMeterInformation, CLSCTX_ALL, nil, IUnknown(peak));
      peak.GetMeteringChannelCount(nChannels);
      SpeakerTimer.Enabled := true;
     
      // les 3 lignes suivantes sont essentielles - le titre de la fenêtre principale doit être réaffiché  dans la routine OnTimer, sinon, les valeurs restent à zéro !
      n := SendMessage(MainFormHandle,WM_GETTEXTLENGTH,0,0) + 1;                          // retourner la longeur du titre de la fenêtre principale
      SetLength(ApplicationTitle,n);                                                                                 // réserver de l'espace pour le titre
      SendMessage(MainFormHandle,WM_GETTEXT,n,integer(@ApplicationTitle[1]));           // récupérer le titre de la fenêtre principale
     
      result := 0;
    end;
    exports InitSpeakerControl;
     
    function CloseSpeakerControl():integer; stdcall; export;
    begin
      if assigned(SpeakerTimer) then begin
        SpeakerTimer.Enabled := false;
        SpeakerTimer.Free;
    //    peak.Free;
      end;
      result := 0;
    end;
    exports CloseSpeakerControl;
     
    // Ceci est la fonction évènement OnTimer du timer créé lors de la mise en route de la surveillance du volume
    class procedure TDummyForm.Timer1Timer(Sender: TObject);
    var
      ChannelVolumes: array[1..2] of Single;    // ces variables sont prévues pour recevoir les PeakValues des deux canaux, par la méthode GetChannelsPeakValues
      pVolumes: pSingle;                        // ce pointeur doit pointer sur le premier élément du tableau ci-dessus, et est passé en paramètre à GetChannelsPeakValues
      Temp: Single;                             // cette variable reçoit la peak value générale, par la méthode GetPeakValue
      vL, vR, vV: integer;                      // ce sont des variables techniques pour ajuster les valeurs reçues vers l'intervalle imposé [0..MaxOutput]
      s: string;                                // variable temporaire pour afficher le titre - utiliser ici la variable ApplicationTitle NE MARCHE PAS !
      HR: HResult;                              // code retour de la méthode GetChannelsPeakValues
    begin
      ttimer(sender).Enabled := false;          // arrêter le timer, le temps de traiter l'évènement
      ChannelVolumes[1] := 0;                   // assurer que le tableau est bien lis à zéro
      ChannelVolumes[2] := 0;
      pVolumes := pSingle(@ChannelVolumes[1]);  // créer le pointeur vers le début du tableau
                                                // si j'ai bien compris la documentation de MSDN, la méthode GetChannelsPeakValues prens 2 paramètres:
                                                // le premier donne le nombre de canaux (deux dans mon cas, et j'ai vérifié le contenu de la variab
     
      peak.GetPeakValue(Temp);                  // prendre la valeur instantané du volume global, résultat dans Temp ==> correct !
      // +++++++++++++++ la ligne suivante pose problème avec le volume du second canal:
      HR := peak.GetChannelsPeakValues(nChannels,pVolumes);      // prendre les valeurs instantanées des deux canaux <========== Seul [1] est retourné, [2] reste à zéro !
                                                           // un pointeur vers le premier élément d'un tableau de flottants (de type Single)
                                                           // la méthode est supposé remplir le tableau avec les deux valeurs...
      if nChannels<>2 then showmessage('nChannels='+inttostr(nChannels));
      if HR<>S_OK then begin
        if HR=E_INVALIDARG then showmessage('E_INVALIDARG')
          else if HR=E_POINTER then showmessage('E_POINTER')
            else showmessage('Erreur '+inttostr(integer(HR))+' = '+inttohex(integer(HR),8));
      end;
     
      // sans les deux lignes suivantes, le contenu du tableau ChannelVolumes reste à zéro, même pour le [1].
      // avec ces deux lignes stupides, le [1] est renseigné correctement,, mais le [2] reste toujours à zéro !
      s := ApplicationTitle;
      SendMessage(MainFormHandle,WM_SETTEXT,0,integer(@s[1]));
     
      // traduire en valeurs entre 0 et 100
      vL := Round(ChannelVolumes[1] * MaxOutput);             // valeur canal droit <======== valeur correcte !
      vR := Round(ChannelVolumes[2] * MaxOutput);             // valeur canal droit <======== ici, reste à zéro !
      vV := Round(temp * MaxOutput);                          // valeur canal gauche <====== valeur correcte !
     
      // envoyer ces valeurs dans des variables de l'application, si leur adresse a été passée en paramètre à la fonction InitSpeakerControl
      if pVolumeOutputL<>nil then pVolumeOutputL^ := vL;
      if pVolumeOutputR<>nil then pVolumeOutputR^ := vR;
      if pVolume<>nil then pVolume^ := vV;
      ttimer(sender).Enabled := true;                          // relancer le timer
    end;
     
     
    end.

  2. #2
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Je renouvelle mon appel. Est-ce quelqu'un a une idée pourquoi mon code ne marche pas ? Pourquoi mon code ne revoit-il pas la valeur du volume instantané (peak volume) du canal droit, alors que celui du canal gauche ainsi que le volume instantané général est bien trouvé ? Pourtant, le canal droit fonctionne bien, et le logiciel freeware VuMeter téléchargé chez SourceForge montre bien les deux canaux actifs ? Malheureusement, ce logiciel est distribué en EXE, sans les sources. J'ai essayé de suivre exactement la doc, mais il doit manquer quelque chose...

  3. #3
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 158
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Salut,

    Dans les "Remarks" de msdn, on peut lire
    Citation Envoyé par msdn
    If the stream contains n channels, the channels are numbered 0 to n– 1.
    Tu devrais donc peut-être tenter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      ChannelVolumes: array[0..1] of Single;    // ces variables sont prévues pour recevoir les PeakValues des deux canaux, par la méthode GetChannelsPeakValues
    et surtout
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      ChannelVolumes[0] := 0;                   // assurer que le tableau est bien lis à zéro
      ChannelVolumes[1] := 0;
      pVolumes := pSingle(@ChannelVolumes[0]);  // créer le pointeur vers le début du tableau
    Parce que si ça se trouve, avec ton code, tu ne lis qu'un seul channel, le second...

  4. #4
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    YES !!!!!!!!!!!

    C'est vrai - ça marche ! Un grand MERCI à vous, Jipété et Cirec !

    Mais enfin, j ene comprends pas. Caster un élément d'un tableau de single en pSingle - je ne comrprends pas. J'avais pourtant l'impression de construire un pointeur vers le premier élément de mon tableau avec la première ligne que tu supprimes, et dans la deuxième, je passais ce pointeur... Qu'est-ce que ça signifie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pSingle(ChannelVolumes[0])
    Je ne comprends pas vraiment cette expression.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Citation Envoyé par KlausGunther Voir le message
    C'est vrai - ça marche ! Un grand MERCI à toi, Jipété !
    Ben c'est surtout Cirec qu'il faut remercier, c'est lui qui a mis le doigt là où ça faisait mal, et qui va se faire un plaisir de nous expliquer les tréfonds du casting,

    PS : tu penseras à cliquer sur , merci

  6. #6
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 938
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 938
    Par défaut
    Citation Envoyé par KlausGunther Voir le message
    Caster un élément d'un tableau de single en pSingle - je ne comrprends pas.
    Ce n'est pas un transtypage, un transtypage est l'interprétation d'une donnée sous une autre forme. Ce n'est pas le cas ici, pSingle n'est pas un type mais un pointeur typé. pSingle(ChannelVolumes[0]) retourne donc un pointeur sur le premier élément ChannelVolumes. @ChannelVolumes serait identique pour ton utilisation, la seule différence étant que le pointeur est non typé mais cela n'aurait aucune incidence sur l'appel de la fonction qui n'attend finalement qu'une adresse.

    Partant de là, pSingle(@ChannelVolumes[0]) est un pointeur (pSingle) sur un pointeur (@) et non sur une donnée (ChannelVolumes). Tu as de la chance de ne pas avoir eu de VA.

    Bravo à Cirec , ces histoires de pointeur sont régulièrement à s'arracher les cheveux.

    pSingle (ou tout pointeur typé) est principalement utile dans les déclarations de variables pour permettre leur incrémentation en fonction du type de données. Pour un passage de paramètre, @ est suffisant.

    Tu pourrais maintenant apporter quelques améliorations à ton code. Tu pars du principe qu'il y a deux canaux mais ce n'est qu'une supposition. ChannelVolumes devrait être un array of single et sa taille dépendante de ChannelCount (SetLength). Mais attention, la déclaration d'un tableau dynamique n'étant qu'un pointeur, plus besoin de pSingle ou @.

  7. #7
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Merci d'avoir pris le temps de regarder cela, juste après Noël que je te souhaite heureux et paisible !
    J'ai essayé ce que tu m'as conseillé, mais le résultat est malheureusement identique. Voici ce que ça donne, visuellement:
    Nom : aa1.png
Affichages : 471
Taille : 112,8 Ko
    La série des Vu-meters en haut est l'affichage des valeurs que je capte, avec, de gauche à droite: canal gauche, volume général, canal droit
    et en bas, l'affichage du freeware VuMeter de SourceForge. Eux, ils détectent le canal droit. Pas moi. C'est frustrant...

  8. #8
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 158
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Salut,
    Citation Envoyé par KlausGunther Voir le message
    Nom : aa1.png
Affichages : 471
Taille : 112,8 Ko
    Rien à voir avec ton problème pour lequel je ne vois pas de solution à cette heure (retourne tout le web, il doit bien y avoir quelqu'un qui donne un exemple, même en C ou en JavaScript ou autre, après on peut toujours traduire), par contre, comme tout sert à tout dans la vie, juste un mot à propos de ton ihm : si je devais travailler avec, elle me ferait péter les plombs !
    Réorganise tes VU's de telle sorte qu'ils présentent les infos de la même manière, sinon c'est complètement perturbant, le rouge un coup en bas à droite un coup en haut à droite un coup au milieu à droite, non non, ça n'est pas productif, àmha.

    La preuve ? En supposant que les valeurs des deux canaux "montent", à gauche l'aiguille va descendre quand celle de droite va monter
    Totalement illogique pour moi (qui ai passé une partie de ma jeunesse avec des consoles, des VU's, ce genre de choses).
    D'ailleurs les Vu's du bas de l'image montrent bien la logique de ces choses.

  9. #9
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Ben c'est surtout Cirec qu'il faut remercier
    Oui, je viens de réaliser, et j'ai rectifié mon message ! C'est déjà bien de voir que des membres du forum s'occupent de mon problème, et en plus trouvent la solution ! C'est super ! Quoique un peu frustrant, car je ne comprends pas pourquoi ça marche et pas ma version du code. Mais Cirec aura sûrement pitié de mon ignorance...

  10. #10
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Réorganise tes VU's de telle sorte qu'ils présentent les infos de la même manière, sinon c'est complètement perturbant, le rouge un coup en bas à droite un coup en haut à droite un coup au milieu à droite, non non, ça n'est pas productif, àmha.
    Tu as évidemment raison. Pour le moment, je suis en train de mettre au point mes propres objets VuMeter, basés sur le tavail de Irnis Haliullin de 2002; mais avec une différence: mise à jour de l'affichage automatique sur changement du contenu d'une variable de type Integer, dans mon programme. Ainsi, j'ai 3 VuMeter, chacun attaché à une des 3 valeurs de son (gauche, global et droit). Et pour tester les affichages, jutilise les 3 représentations qui sont possibles pour cet objet. A terme, suivant l'utilisation, ce sera une des trois qui sera retenue pour l'utilisation finale (celle du milieu, certainement). Mais pour la phase des tests, je montre les trois pour être sûr que les trois fonctionnent.

    Par contre, si quelqu'un pouvait avoir une idée sur problème de base lié à la méthode GetChannelsPeakValues, ce serait vraiment un soulagement...

  11. #11
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 158
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Bonsoir,

    J'ai trouvé une discussion sur un forum, qui montre comment utiliser la fonction qui te pose problème, mais je ne sais même pas en quel langage c'est écrit,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    double waitPeriod; int channelCount
    IAudioMeterInformation meter=GetAudioMeter(waitPeriod channelCount)
     
    rep
    ,FLOAT peak; meter.GetPeakValue(peak)
    ,out peak
    ,
    ,;ARRAY(FLOAT) af.create(channelCount)
    ,;meter.GetChannelsPeakValues(af.len &af[0])
    ,;int i
    ,;for(i 0 af.len) out af[i]
    ,
    ,wait waitPeriod
    ,1 ;;debug

    Sinon, étudie ce code en Csharp.

    Et cette discussion avec du code en C++, peut-être la plus intéressante.


    Un qui m'a mis la haine, c'est celui qui dit qu'il a tout fait, bugs corrigés, sources fournies, mais lien mort...
    Je hais Internet pour ça


    Pas d'autres idées...

  12. #12
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Merci beaucoup pour ces explications. Cependant, il reste un point ouvert: mon compilateur n'aime pas beaucoup l'absence du pSingle ou du @. Suivant ton conseil, j'ai défini mon tableau en dynamique, et je l'ai dimensionné en fonction du nombre de canaux, tout en laissant l'appel de ma méthode identique. Ca marche sans problème. Dont acte pour la défintiion du tableau.

    Par contre, tu dis:
    la déclaration d'un tableau dynamique n'étant qu'un pointeur, plus besoin de pSingle ou @
    Et là, mon compilateur ne veut plus:
    Nom : aa1.png
Affichages : 267
Taille : 56,8 Ko
    absence du pSingle et du @ est refusée.

    Ou alors:
    Nom : aa2.png
Affichages : 235
Taille : 71,4 Ko
    idem sans spécifier l'indice.

    Ou alors:
    Nom : aa4.png
Affichages : 261
Taille : 59,2 Ko
    idem juste avec @.

    Voilà ce qui marche:
    Nom : aa3.png
Affichages : 266
Taille : 65,2 Ko

    Est-ce que c'est l'ancien Delphi 6 qui ne comprend pas qu'un tableau dynamique est juste un pointeur, ou est-ce que j'ai mal compris ton message ?

  13. #13
    Membre émérite
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Par défaut
    Citation Envoyé par KlausGunther
    C'est super ! Quoique un peu frustrant, car je ne comprends pas pourquoi ça marche et pas ma version du code. Mais Cirec aura sûrement pitié de mon ignorance...
    re,

    j'aurai bien aimer répondre à ta demande mais je crains de ne pas avoir de réponse a te donner !

    tout ce que je sais c'est que le fait d'avoir mis le doigt sur le "Pointeur sur Pointeur" n'a pas résolu le problème en soi.
    si on passe par une variable intermédiaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    pVolumes := pSingle(ChannelVolumes[0]);
    HR := peak.GetChannelsPeakValues(nChannels, pVolumes);
    ça ne fonctionne pas !!!
    par contre HR := peak.GetChannelsPeakValues(nChannels, pSingle(ChannelVolumes[0])); fonctionne

    et ça je ne me l'explique pas .... désolé

    Si quelqu'un a une explication je suis également preneur

    Cordialement,
    @+

  14. #14
    Membre émérite
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Par défaut
    pour illustrer les propos d'AndNotOr
    Mais attention, la déclaration d'un tableau dynamique n'étant qu'un pointeur, plus besoin de pSingle ou @.
    il te faut redéclarer la fonction "GetChannelsPeakValues" ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        function GetChannelsPeakValues(u32ChannelCount: UINT; out afPeakValues): HRESULT; stdcall;
    et du coup tu peux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    HR := peak.GetChannelsPeakValues(nChannels, ChannelVolumes[0]);
    Cordialement,
    @+

  15. #15
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    J'ai éudié les 3 codes. Je ne "parle" pas C, mais j'en sais suffisamment pour pouvoir lire un code et en comprendre la logique. J'ai isolé dans les 3 codes la partie qui récupère les valeurs PeakVolume des deux canaux, et je dois dire que je ne vois aucune différence avec ma propre implémentation. La méthode GetChannelsPeakValues de l'interface est appeléen dans tous ces cas, avec deux paramètres: le premier étant le nombre de canaux (2 dans ce cas), et le second est un pointeur vers un tableau de flottants simpre précision recevant les deux valeurs dans une fourchette entre 0.0 etg 1.0. Or, ça marche pour le premier canal (gauche) mais pour le second canal (droit), la valeur reste inchangée à zéro. Rien à faire.

    Effectivement, dans le 4ème exemple, celui où l'auteur a stipulé avoir résolu le problème, le lien vers le code est mort. Vraiment dommage, et difficile à comprendre lorsqu'in voit que la publication est relativement récente (2015).

    Je pense le le problème se situe au niveau de l'implémentation Delphi de l'interface, ou au niveau de la documentation qui est peut-être ambigue ou viciée quelque part. Est-ce que le tableau doit vraiment être déclaré comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ChannelVolumes: array[0..1] of Single;
    en Delphi pour recevoir les deux valeurs ? J'ai essayé avec Double, mais sans résultat. Je suis convaincu que le noed du problème se situe à cet endroit, au niveau du passage de paramètres entre la méthode de l'interface et mon code Delphi/

  16. #16
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 158
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Citation Envoyé par KlausGunther Voir le message
    Je ne "parle" pas C, mais j'en sais suffisamment pour pouvoir lire un code et en comprendre la logique.
    Pareil.

    Citation Envoyé par KlausGunther Voir le message
    J'ai isolé dans les 3 codes la partie qui récupère les valeurs PeakVolume des deux canaux, et je dois dire que je ne vois aucune différence avec ma propre implémentation.
    Possible d'y jeter un coup d'œil, si tu les as conservées ?
    Parce que je ne peux guère aider au niveau des tests réels (je suis sous Linux, alors les API Windows, -- mais j'aime bien le son), mais des fois, en regardant du code avec un œil neuf...

    Citation Envoyé par KlausGunther Voir le message
    Or, ça marche pour le premier canal (gauche) mais pour le second canal (droit), la valeur reste inchangée à zéro. Rien à faire.
    Comment le vois-tu ?
    Tu as rajouté des TEdit pour afficher les contenus ? Tu loggues dans un TMemo ?
    Parce que si jamais (je vais dire une grosse bêtise) ton second VU était branché à l'envers et que l'aiguille essayait de descendre sous zéro ?

    Citation Envoyé par KlausGunther Voir le message
    Je pense le le problème se situe au niveau de l'implémentation Delphi de l'interface, ou au niveau de la documentation qui est peut-être ambigue ou viciée quelque part. Est-ce que le tableau doit vraiment être déclaré comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ChannelVolumes: array[0..1] of Single;
    en Delphi pour recevoir les deux valeurs ? J'ai essayé avec Double, mais sans résultat
    Faut bien examiner comment font les codes que j'ai trouvés.
    D'après MSDN ça devrait être correct : le float de MS semble correspondre au single de Delphi (mais à confirmer quand même).

    EDIT : regarde ce truc, ça doit être facilement transposable en Delphi, j'ai trouvé les noms des fonctions sympathiquement utiles (ou utilement sympathiques, comme tu le sens, )
    Salut, Y. !

  17. #17
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 938
    Billets dans le blog
    6
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      IAudioMeterInformation = interface(IUnknown)
        ['{C02216F6-8C67-4B5B-9D00-D008E73E0064}']
        function GetPeakValue(out pfPeak: Single): HRESULT; stdcall; 
        // msdn dit : HRESULT GetPeakValue( [out] float *pfPeak) et tu passes un Single
        function GetMeteringChannelCount(out pnChannelCount: UINT): HRESULT; stdcall;
        function GetChannelsPeakValues(u32ChannelCount: UINT; out afPeakValues: pSingle): HRESULT; stdcall; 
        // msdn dit HRESULT GetChannelsPeakValues( [in]  UINT32 u32ChannelCount, [out] float  *afPeakValues) et tu passes un pSingle (l'adresse d'un Single)
        function QueryHardwareSupport(out pdwHardwareSupportMask: UINT): HRESULT; stdcall;
      end;
    Je pense que le out sert à passer l'adresse de la variable, que l'API reçoit comme un pointeur : essaye de déclarer out afPeakValues: Single et de passer ChannelVolumes[0] si tableau zero-based ; ChannelVolumes[1] sinon.
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  18. #18
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 158
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 158
    Par défaut
    Salut, Y.
    Citation Envoyé par tourlourou Voir le message
    Je pense que le out sert à passer l'adresse de la variable, que l'API reçoit comme un pointeur : essaye de déclarer out afPeakValues: Single et de passer ChannelVolumes[0] si tableau zero-based ; ChannelVolumes[1] sinon.
    et moi je n'en suis pas si sûr ! Il me semble que chez MSDN ces [in] et [out] servent à indiquer le sens du mouvement des données, et ce [out] n'a rien à voir, àmha, avec le out et son synonyme var de Pascal.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    HRESULT GetChannelsPeakValues(
      [in]  UINT32 u32ChannelCount,
      [out] float  *afPeakValues
    );
    [in] = vers la méthode qui attend un uint32
    [out] = un float exporté par la méthode.

    Mais il est vrai que ces "*" ça met une joyeuse pagaille en termes de lisibilité et de compréhension du code : font chichi avec leurs pointeurs partout, on se croirait revenu au temps du langage machine, dur dur...

  19. #19
    Membre éclairé

    Homme Profil pro
    Informaticien retraité
    Inscrit en
    Mars 2010
    Messages
    369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Informaticien retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2010
    Messages : 369
    Billets dans le blog
    1
    Par défaut
    Dans ce cas, le compilateur rejette pour cause de manque de type du paramètre:
    Nom : aa1.png
Affichages : 243
Taille : 27,9 Ko

  20. #20
    Membre émérite
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Par défaut
    le supprimer oui mais le remplacer par "const" serait plus juste puisque
    Citation Envoyé par Andnotor
    afPeakValues n'est pas modifié, c'est le tableau pointé qui l'est.
    Cordialement,
    @+

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. trouver les noeuds avec des valeurs nulles
    Par awalter1 dans le forum Général Python
    Réponses: 3
    Dernier message: 28/10/2010, 14h33
  2. Trouver les trous dans des périodes sur la même table
    Par CinePhil dans le forum Requêtes
    Réponses: 5
    Dernier message: 11/04/2009, 08h56
  3. Trouver les fichiers contenant des annotations
    Par lahitsitely78 dans le forum Eclipse Platform
    Réponses: 0
    Dernier message: 18/02/2009, 11h52
  4. Trouver les redirections dans des traces
    Par severine dans le forum Développement
    Réponses: 3
    Dernier message: 21/04/2004, 18h51

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