Multimedia

Ein CD-Laufwerk für die Audio-CD-Wiedergabe festlegen

Kann mir jemand sagen, wie man mit dem TMediaPlayer eine Audio-CD abspielen kann, die nicht im CD-Rom-Laufwerk mit dem niedrigsten Laufwerkbuchstaben ist. Ich habe schon alles probiert, aber ich schaffe es nicht auf ein anderes CD-Rom zuzugreifen!

1. mit MediaPlayer:

MediaPlayer1.Filename := 'g:';   // Laufwerk G:
2. ohne MediaPlayer:

uses MMSystem;

procedure TForm1.Button1Click(Sender: TObject);
var
  Laufwerk : String;
  Befehl   : String;
begin
  Laufwerk := 'k:';
  Befehl := 'open ' + Laufwerk + ' type cdaudio alias geraet';
  MCISendString(PChar(Befehl), nil, 0, 0);
  // tmsf = Track, Minuten, Sekunden, Frames
  MCISendString('set geraet time format tmsf', nil, 0, 0);
  // from 11 to 12 = nur 11. Lied abspielen
  MCISendString('play geraet from 11 to 12', nil, 0, 0);
  MCISendString('close geraet', nil, 0, 0);
end;

Die ID-Nummer einer Audio-CD ermitteln

Dieses Beispiel zeigt, wie man die ID-Nummer einer Audio-CD ermittelt, die auch der Windows-eigene CD-Player als Identifikation benutzt:

function TForm1.GetCDName : String;
var
  InfoParm      : TMCI_Info_Parms;
  lpInfoString  : PChar;
const
  lenInfoString = 17;
begin
  playerform.mp.DeviceType := dtCDAudio;
  if not playerform.mp.AutoOpen then 
    playerform.mp.Open;
  GetMem(lpInfoString,lenInfoString);
  InfoParm.dwCallback  := 0;
  InfoParm.lpstrReturn := lpInfoString;
  InfoParm.dwRetSize   := lenInfoString;
  mciSendCommand(playerform.mp.DeviceID, mci_Info, 
                 (mci_Wait or {MCI_INFO_MEDIA_UPC} 
                  MCI_INFO_MEDIA_IDENTITY), Longint(@InfoParm) );
  Result := StrPas(lpInfoString);
  FreeMem(lpInfoString,lenInfoString);
end;
verwendete Komponenten :
mp : TMediaPlayer
PlayerForm : TForm

Die (Master-) Lautstärke des Soundkarten-Mixers einstellen

Das folgende Sourcecode-Beispiel von Robert Roßmair demonstriert die Einstellung der Master-Lautstärke des Mixers. Der "Mixer" Parameter von "SetMasterVolume" muß entweder eine Mixer-Geräte-ID im Bereich 0..mixerGetNumDevs-1 sein oder ein von "MixerOpen" zurückgegebenes Mixerhandle:

interface

uses SysUtils, Windows, MMSystem;

procedure SetMasterVolume(
  Mixer: hMixerObj;
  Value: Word);

implementation

{Ermittelt den Masterkanal des Soundkarten-Mixers,
 gibt bei Erfolg "true" zurück:}
function GetMasterVolumeControl(Mixer: hMixerObj;
                                var Control: TMixerControl): MMResult;
var
  Line     : TMixerLine;
  Controls : TMixerLineControls;
begin
  ZeroMemory(@Line, SizeOf(Line));
  Line.cbStruct := SizeOf(Line);
  Line.dwComponentType := MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  Result := mixerGetLineInfo(Mixer, 
                             @Line,
                             MIXER_GETLINEINFOF_COMPONENTTYPE);
  if Result = MMSYSERR_NOERROR then begin
    ZeroMemory(@Controls, SizeOf(Controls));
    Controls.cbStruct := SizeOf(Controls);
    Controls.dwLineID := Line.dwLineID;
    Controls.cControls := 1;
    Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;
    Controls.cbmxctrl := SizeOf(Control);
    Controls.pamxctrl := @Control;
    Result := mixerGetLineControls(Mixer, 
                                   @Controls,
                                   MIXER_GETLINECONTROLSF_ONEBYTYPE);
  end;
end;

procedure SetMasterVolume(Mixer: hMixerObj;
                          Value: Word);
var
  MasterVolume    : TMixerControl;
  Details         : TMixerControlDetails;
  UnsignedDetails : TMixerControlDetailsUnsigned;
  Code            : MMResult;
begin
  Code := GetMasterVolumeControl(Mixer, MasterVolume);
  if Code = MMSYSERR_NOERROR then begin
    with Details do begin
      cbStruct := SizeOf(Details);
      dwControlID := MasterVolume.dwControlID;
      cChannels := 1;  // set all channels
      cMultipleItems := 0;
      cbDetails := SizeOf(UnsignedDetails);
      paDetails := @UnsignedDetails;
    end;
    UnsignedDetails.dwValue := Value;
    Code := mixerSetControlDetails(Mixer,  
                                   @Details,
                                   MIXER_SETCONTROLDETAILSF_VALUE);
  end;
  if Code <> MMSYSERR_NOERROR then
    raise Exception.CreateFmt('SetMasterVolume failure, '+
                              'multimedia system error #%d', 
                              [Code]);
end;

Zugriff auf die AUX-Kanäle des Soundkarten-Mixers

Dieses Sourcecdoe-Beispiel demonstriert den Zugriff auf die Mixereinstellungen der Auxiliary-Kanäle der Soundkarte:

uses MMSystem;

{Die Lautstärke des AUX-Kanals mit der ID-Nummer "DeviceID" ermitteln:}
procedure GetVolume(DeviceID : integer;var VolL,VolR : word);
var Vol : longint;
begin
  AuxGetVolume(DeviceID,@Vol);
  VolL:=Vol mod $10000;  //Die Lautstärke des linken Kanals
  VolR:=Vol shr 16;        //Die Lautstärke des rechen Kanals
end;

{Die Lautstärke des AUX-Kanals mit der ID-Nummer "DeviceID" setzen:}
procedure SetVolume(DeviceID : integer;VolL,VolR : byte);
var Vol  : longint;
    Temp : real;
begin
  Temp:=VolR/255;
  Vol:=round($FFFF*Temp) shl 16;
  Temp:=VolL/255;
  Vol:=Vol+round($FFFF*Temp);
  AuxSetVolume(DeviceID,Vol);
end;

{Informationen zu allen verfügbaren AUX-Kanälen ermitteln
 und in Memo1 anzeigen:}
procedure GetDevInfos;
var AuxCaps   : TAuxCaps;
    LVol,RVol,
    VHi,VLo   : word;
    i,NumDevs : integer;
begin
  Memo1.Lines.Clear;
  NumDevs:=AuxGetNumDevs;
  if NumDevs=0 then
    Exit;
  for i:=0 to NumDevs-1 do begin
    AuxGetDevCaps(i, @AuxCaps, SizeOf(AuxCaps));
    Memo1.Lines.Add('DeviceID: '+IntToStr(i));
    VLo:=AuxCaps.vDriverVersion mod $100;
    VHi:=AuxCaps.vDriverVersion div $100;
    Memo1.Lines.Add('Version: '+IntToStr(VHi)+'.'+IntToStr(VLo));
    Memo1.Lines.Add('DeviceName: '+String(AuxCaps.szPName));
    if (AuxCaps.wTechnology and AUXCAPS_CDAUDIO)<>0 then
      Memo1.Lines.Add('DeviceType: CD-Audio')
    else
      Memo1.Lines.Add('DeviceType: Extern');
    GetVolume(i,LVol,RVol);
    Memo1.Lines.Add('Links: '+IntToStr(LVol));
    Memo1.Lines.Add('Rechts: '+IntToStr(RVol));
    Memo1.Lines.Add('');
  end;
end;

Wie ermittle ich, ob eine Soundkarte vorhanden ist?

Hier ein einfaches Beispiel, in dem die Anzahl der Ausgabegräte für Wave-Dateien geprüft wird:

function IsSoundKarte:Longint;stdcall;external 'winmm.dll'
  name 'waveOutGetNumDevs';

If IsSoundKarte=0 then
  Showmessage('Das Abspielen des Tones ist leider nicht möglich.');

Wie ermittle ich, ob sich eine Audio-CD in einem CD-Laufwerk befindet?

In diesem Beispiel wird einfach auf dem angegebenen Laufwerk nach einer Datei mit der Endung *.cda gesucht:

function IsAudioCD(Drive : char):boolean;
var SR : TSearchRec;
begin
  if FindFirst(Drive+':\*.cda',faAnyFile,SR)=0 then begin
    Result:=true;
    FindClose(SR);
  end;
  else;
    Result:=false;
end;
Eine andere Möglichkeit besteht darin, den "VolumeName" der eingelegten CD zu ermitteln. Heißt dieser "Audio CD", handelt es sich um eine Audio.CD:

function IsAudioCD(Drive : char) : boolean;
var
  DrivePath : string;
  MaximumComponentLength : DWORD;
  FileSystemFlags : DWORD;
  VolumeName : string;
begin
  Result := false;
  DrivePath := Drive + ':\';
  if GetDriveType(PChar(DrivePath)) <> DRIVE_CDROM then exit;
  SetLength(VolumeName, 64);
  GetVolumeInformation(PChar(DrivePath),
                       PChar(VolumeName),
                       Length(VolumeName),
                       nil,
                       MaximumComponentLength,
                       FileSystemFlags,
                       nil,
                       0);
  if lStrCmp(PChar(VolumeName),'Audio CD') = 0 then result := true;
end;

Wie kann ich Töne verschiedener Frequenzen über den PC-Speaker ausgeben?

Diese Assembler-Routinen von Gerd Kayser realisieren die Klangausgabe über direkte Portzugriffe und funktionieren daher nicht unter Windows NT. Die Prozedur "Sound" erzeugt einen Ton mit der Frequenz "Hz", die Prozedur "NoSound" stoppt die Klangausgabe. Die Funktion der Prozeduren wird in diesem Beispiel-Projekt demonstriert.

function InPort(PortAddr:word): byte; assembler; stdcall;
asm
  mov dx,PortAddr
  in al,dx
end;

procedure OutPort(PortAddr: word; Databyte: byte); assembler; stdcall;
asm
  mov al,Databyte
  mov dx,PortAddr
  out dx,al
end;

Procedure Sound(Hz : Word);
var TmpW : Word;
begin
  OutPort($43,182);
  TmpW :=InPort($61);
  OutPort($61,TmpW or 3);
  OutPort($42,lo(1193180 div hz));
  OutPort($42, hi(1193180 div hz));
end;

Procedure NoSound;
var TmpW : Word;
begin
  OutPort($43,182);
  TmpW := InPort($61);
  OutPort($61,TmpW and 3);
end;
Unter Windows NT geht es wesentlich einfacher mit der Beep-Funktion aus der Windows-Unit:

Windows.Beep(Frequenz, Dauer);
Die Frequenz wird in Hertz angegeben und muß zwischen 37 und 32.767 (0x25 bis 0x7FFF) liegen, Die Dauer wird in Millisekunden angegeben. Wenn als Dauer -1 übergeben wird, wird der Ton asynchron so lange ausgegeben, bis die Funktion erneut aufgerufen wird.

Im Abschnitt "Tips&Tricks" wird beschrieben, wie man Töne über den Synthesizer der Soundkarte ausgibt.