Volume output meter (Views: 100)


Is there a way, like the Windows Volume Control, to get the current
volume output... not the Volume settings (loudness), but how "loud" the
playing sound is? The Volume Control has a "red-to-green" bar that show
the volume output... how could this be done?


Here's some code that will retrieve a handle to the meter attached to
the WaveOut source of the speaker line, if there is one:

  MixerControl: TMixerControl;
  MixerControlDetails: TMixerControlDetails;
  MixerControlDetailsSigned: TMixerControlDetailsSigned;
  Mixer: THandle;
  MixerLine: TMixerLine;
  MixerLineControls: TMixerLineControls;
  PeakMeter: DWord;
  Rslt: DWord;
  SourceCount: Cardinal;
  WaveOut: DWord;
  I: Integer;
  X: Integer;
  Y: Integer;
  Rslt := mixerOpen(@Mixer, 0, 0, 0, 0);
  if Rslt <> 0 then
    raise Exception.CreateFmt('Can''t open mixer (%d)', [Rslt]);
  FillChar(MixerLine, SizeOf(MixerLine), 0);
  MixerLine.cbStruct := SizeOf(MixerLine);
  Rslt := mixerGetLineInfo(Mixer, @MixerLine,
  if Rslt <> 0 then
    raise Exception.CreateFmt('Can''t find speaker line (%d)', [Rslt]);
  SourceCount := MixerLine.cConnections;
  WaveOut := $FFFFFFFF;
  for I := 0 to SourceCount - 1 do
    MixerLine.dwSource := I;
    Rslt := mixerGetLineInfo(Mixer, @MixerLine,
    if Rslt <> 0 then
      raise Exception.CreateFmt('Can''t get source line (%d)', [Rslt]);
    if MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT then
      WaveOut := MixerLine.dwLineId;
  if WaveOut = $FFFFFFFF then
    raise Exception.Create('Can''t find wave out device');
  FillChar(MixerLineControls, SizeOf(MixerLineControls), 0);
  with MixerLineControls do
    cbStruct := SizeOf(MixerLineControls);
    dwLineId := WaveOut;
    cControls := 1;
    cbmxctrl := SizeOf(TMixerControl);
    pamxctrl := @MixerControl;
  Rslt := mixerGetLineControls(Mixer, @MixerLineControls,
  if Rslt <> 0 then
    raise Exception.CreateFmt('Can''t find peak meter control (%d)',
  PeakMeter := MixerControl.dwControlID;

  // at this point, I have the meter control ID, so I can
  // repeatedly query its value and plot the resulting data
  // on a canvas

  X := 0;
  FillChar(MixerControlDetails, SizeOf(MixerControlDetails), 0);
  with MixerControlDetails do
    cbStruct := SizeOf(MixerControlDetails);
    dwControlId := PeakMeter;
    cChannels := 1;
    cbDetails := SizeOf(MixerControlDetailsSigned);
    paDetails := @MixerControlDetailsSigned;
    Rslt := mixerGetControlDetails(Mixer, @MixerControlDetails,
    if Rslt <> 0 then
      raise Exception.CreateFmt('Can''t get control details (%d)',
    Y := 300 - Round(300 * Abs(MixerControlDetailsSigned.lValue) /
    with Canvas do
      MoveTo(X, 0);
      Pen.Color := clBtnFace;
      LineTo(X, 300);
      Pen.Color := clWindowText;
      LineTo(X, Y);
  until X > 500;

  // don't forget to close the mixer handle when you're done

  Rslt := mixerClose(Mixer);
  if Rslt <> 0 then
    raise Exception.CreateFmt('Can''t close mixer (%d)', [Rslt]);

<< Back to main page