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
| 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(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:= 200;
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;
class procedure TDummyForm.Timer1Timer(Sender: TObject);
var
ChannelVolumes: array[1..2] of Single;
pVolumes: pSingle;
Temp: Single;
vL, vR, vV: integer;
s: string; // variable temporaire pour afficher le titre - utiliser ici la variable ApplicationTitle NE MARCHE PAS !
begin
ttimer(sender).Enabled := false; // arrêter le timer, le temps de traiter l'évènement
ChannelVolumes[1] := 0;
ChannelVolumes[2] := 0;
pVolumes := pSingle(@ChannelVolumes[1]);
peak.GetPeakValue(Temp);
peak.GetChannelsPeakValues(nChannels,pVolumes); // <========== Seul [1] est retourné, [2] reste à zéro !
// 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]));
// produire des valeurs entières entre 0 et 65535
vL := Round(ChannelVolumes[1] * 65535);
vR := Round(ChannelVolumes[2] * 65535);
// traduire en valeurs entre 0 et 100
vL := Round((vL * MaxOutput)/65536);
vR := Round((vR * MaxOutput)/65536);
vV := Round(temp * MaxOutput);
// 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. |
Partager