Opening Mixer Dialogs

Please discuss general Delphi programming topics here.

Opening Mixer Dialogs

Postby ajt » March 6th, 2010, 4:43 am

Have a TAudioPlayer and TAudioRecorder on a Settings form in my application and am filling two radiogroups with sound devices for each (using the sample code in viewtopic.php?f=7&t=479). The user can select which play and record device to use and all works as it should... except for one thing.

Below the radiogroups I have 2 buttons to open the play and record mixer dialogs. Using the deviceIDs from above I am using ShellExecute to run SndVol32.exe with command line switches, i.e. sndvol32.exe -P -D<play deviceID> and sndvol32.exe -R -D<record deviceID> This works on some systems but not others. The systems it has trouble with is where the built in sound card is 2 separate devices (input and output) and I am trying to open the the play or record mixer for a USB soundbox also connected to that system and it keeps opening the built in sound card device's mixer dialog.

What is the preferred way to open mixer dialogs that hopefully won't have this problem?
ajt
Active Member
Active Member
 
Posts: 5
Joined: February 18th, 2010, 4:34 pm

Re: Opening Mixer Dialogs

Postby Kambiz » March 7th, 2010, 1:26 am

I am not sure, but I think the value after -D options should be mixerID.

Put instances of TAudioMixer, TComboBox, and TButton on a form and try the following code:

Code: Select all
uses
  ShellAPI;

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  ComboBox1.Style := csDropDownList;
  ComboBox1.Items.Clear;
  for I := 0 to AudioMixer1.MixerCount - 1 do
  begin
    AudioMixer1.MixerID := I;
    ComboBox1.Items.Add(AudioMixer1.MixerName);
  end;
  ComboBox1.ItemIndex := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  CmdLine: String;
begin
  CmdLine := Format('sndvol32.exe -R -D%u', [ComboBox1.ItemIndex]);
  ShellExecute(Handle, 'open', PChar(CmdLine), nil, nil, SW_NORMAL);
end;


I didn't test the code.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm

Re: Opening Mixer Dialogs

Postby ajt » March 7th, 2010, 3:10 am

Thanks

The code works with the ShellExecute syntax changed to:
Code: Select all
ShellExecute(Handle, '', 'Sndvol32.exe', PChar(CmdLine), '', SW_SHOWNORMAL);


However, this is one of the variations I tried. It has the same issue where even if a mixer with a different MixerID is selected in the ComboBox it only opens the dialog for the one selected in mmsys.cpl (Sounds and Audio Devices | Audio). Interestingly, this code won't open if the mixer selected in the combobox is a playback mixer only. I think that's a good thing if it would only open the correct recording mixer.

Again, this only seems to be a problem with the an audio device which shows up as two distinct mixers, e.g, "Conextant HD Audio output" and "Conextant HD Audio input". It is the latter that opens up for both itself and the USB sound device even if I select the USB device in the combobox. It actually is opening the record mixer selected in mmsys.cpl apparently independent of -D parameter. Note that this same problem exists if I type the sndvol32 command at Run or in a command box. That's why I was looking for a different way other than sndvol32.

I am beginning to think this is a Microsoft "feature" (this is XP SP3, BTW).
ajt
Active Member
Active Member
 
Posts: 5
Joined: February 18th, 2010, 4:34 pm

Re: Opening Mixer Dialogs

Postby Kambiz » March 7th, 2010, 1:48 pm

You can find out which mixer has Playback and Record capabilities.

Code: Select all
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, WaveMixer;

type
  TMainForm = class(TForm)
    MixerList: TListView;
    btnOpenPlayback: TButton;
    btnOpenRecord: TButton;
    AudioMixer: TAudioMixer;
    procedure FormCreate(Sender: TObject);
    procedure MixerListSelectItem(Sender: TObject; Item: TListItem;
      Selected: Boolean);
    procedure btnOpenPlaybackClick(Sender: TObject);
    procedure btnOpenRecordClick(Sender: TObject);
  private
    procedure PrepareMixerList;
    procedure OpenMixer(MixerID: DWORD; Mode: Char);
    function IsPlaybackMixer: Boolean;
    function IsRecordMixer: Boolean;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

uses
  ShellAPI;

function Is64BitWindows: Boolean;
var
  Wow64Process: BOOL;
  IsWow64Process: function(Process: DWORD; var Wow64Process: BOOL): BOOL; stdcall;
begin
  Result := False;
  @IsWow64Process := GetProcAddress(GetModuleHandle(kernel32), 'IsWow64Process');
  if Assigned(IsWow64Process) then
  begin
    Wow64Process := False;
    if IsWow64Process(GetCurrentProcess, Wow64Process) then
      Result := Wow64Process;
  end;
end;

procedure TMainForm.OpenMixer(MixerID: DWORD; Mode: Char);
var
  SndVol: String;
  Params: String;
begin
  if Is64BitWindows then
    SndVol := 'sndvol.exe'
  else
    SndVol := 'sndvol32.exe';
  Params := Format('-%s -D%u', [Mode, MixerID]);
  ShellExecute(Handle, 'open', PChar(SndVol), PChar(Params), nil, SW_NORMAL);
end;

function TMainForm.IsPlaybackMixer: Boolean;
var
  D: Integer;
begin
  Result := False;
  for D := 0 to AudioMixer.DestinationCount - 1 do
  begin
    AudioMixer.DestinationID := D;
    if AudioMixer.Master.TargetType in [tgUndefined, tgWaveOut, tgMidiOut, tgAux] then
    begin
      Result := True;
      Exit;
    end;
  end;
end;

function TMainForm.IsRecordMixer: Boolean;
var
  D: Integer;
begin
  Result := False;
  for D := 0 to AudioMixer.DestinationCount - 1 do
  begin
    AudioMixer.DestinationID := D;
    if AudioMixer.Master.TargetType in [tgUndefined, tgWaveIn, tgMidiIn, tgAux] then
    begin
      Result := True;
      Exit;
    end;
  end;
end;

procedure TMainForm.PrepareMixerList;
var
  M: Integer;
begin
  MixerList.Items.BeginUpdate;
  try
    MixerList.Items.Clear;
    for M := 0 to AudioMixer.MixerCount - 1 do
    begin
      AudioMixer.MixerID := M;
      with MixerList.Items.Add do
      begin
        Data := Pointer(M);
        Caption := AudioMixer.MixerName;
        if IsPlaybackMixer then
          SubItems.Add('Yes')
        else
          SubItems.Add('No');
        if IsRecordMixer then
          SubItems.Add('Yes')
        else
          SubItems.Add('No');
      end;
    end;
  finally
    MixerList.Items.EndUpdate;
  end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  PrepareMixerList;
end;

procedure TMainForm.MixerListSelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  btnOpenPlayback.Enabled := Selected and (Item.SubItems[0] = 'Yes');
  btnOpenRecord.Enabled := Selected and (Item.SubItems[1] = 'Yes');
end;

procedure TMainForm.btnOpenPlaybackClick(Sender: TObject);
begin
  OpenMixer(DWORD(MixerList.Selected.Data), 'P');
end;

procedure TMainForm.btnOpenRecordClick(Sender: TObject);
begin
  OpenMixer(DWORD(MixerList.Selected.Data), 'R');
end;

end.

On Windows Vista and later, Microsoft has changed the mixer thing and I don't know whether this code works on those versions as expected or not.
Attachments
WinMixer.zip
Windows Mixer Dialog
(2.46 KiB) Downloaded 207 times
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2429
Joined: March 7th, 2003, 7:10 pm


Return to Delphi Programming

Who is online

Users browsing this forum: No registered users and 2 guests

cron