program SB_16_Mixer;

type
  PListItem = ^ListItem;
  ListItem  = record
                Name  : String;
                Value : Byte;
                NextItem : PListItem;
              end;

const
  ReleaseDate = '13.09.1999';
  EMail = 'blingne@fkg.goe.ni.schule.de';

  DVolMasterL = 31;               { Defaults fr den Mixer }
  DVolMasterR = 31;
  DVolVoiceL = 30;
  DVolVoiceR = 30;
  DVolMidiL = 28;
  DVolMidiR = 28;
  DVolCdL = 28;
  DVolCdR = 28;
  DVolLineL = 27;
  DVolLineR = 27;
  DVolMic = 27;
  DVolSpeaker = 27;

  DTrebleL = 10;
  DTrebleR = 10;
  DBassL = 9;
  DBassR = 9;

  DInAmpL = 0;
  DInAmpR = 0;
  DOutAmpL = 0;
  DOutAmpR = 0;

  DOutLineL = 1;
  DOutLineR = 1;
  DOutCdL = 1;
  DOutCdR = 1;
  DOutMic = 1;

  DInLMidiL = 0;
  DInLMidiR = 0;
  DInLLineL = 0;
  DInLLineR = 0;
  DInLCdL = 0;
  DInLCdR = 0;
  DInLMic = 0;
  DInRMidiL = 0;
  DInRMidiR = 0;
  DInRLineL = 0;
  DInRLineR = 0;
  DInRCdL = 0;
  DInRCdR = 0;
  DInRMic = 0;

var
  FirstMixVar : PListItem;
  LastMixVar  : PListItem;
  BasePort    : Word;
  MixerIni    : String;

{==========================================================}
{== Funktionen zum Zugriff auf Listen                    ==}
{==========================================================}

{----------------------------------------------------------}
{ NewItemData.NextItem muá nil sein!                       }
{----------------------------------------------------------}

procedure AddListItem (NewItemData : ListItem);

var
  NewItem : PListItem;

begin { AddListItem }
  New(NewItem);
  NewItem^ := NewItemData;
  if (FirstMixVar = nil) then begin                  { erstes Listenelement }
    FirstMixVar := NewItem;
    LastMixVar := NewItem;
  end else begin
    LastMixVar^.NextItem := NewItem;
    LastMixVar := NewItem;
  end;
end;  { AddListItem }

{----------------------------------------------------------}

function GetListItemValue (Name : String) : Byte;

var
  ActItem  : PListItem;
  Ergebnis : Byte;

begin { GetListItemValue }
  Ergebnis := 255;
  ActItem := FirstMixVar;
  while (ActItem <> LastMixVar) do begin
    if (ActItem^.Name = Name) then Ergebnis := ActItem^.Value;
    ActItem := ActItem^.NextItem;
  end;
  GetListItemValue := Ergebnis;
end;  { GetListItemValue }

{----------------------------------------------------------}

function ListItemExists (Name : String) : Boolean;

var
  ActItem  : PListItem;
  Ergebnis : Boolean;

begin { ListItemExists }
  Ergebnis := false;
  ActItem := FirstMixVar;
  while (ActItem <> LastMixVar) do begin
    if (ActItem^.Name = Name) then Ergebnis := true;
    ActItem := ActItem^.NextItem;
  end;
  ListItemExists := Ergebnis;
end;  { ListItemExists }

{==========================================================}
{== Funktionen zum Zugriff auf den Mixer (Lowlevel)      ==}
{==========================================================}

{----------------------------------------------------------}

function GetReg (Nr : Byte) : Byte; Assembler;

asm  { GetReg }
  mov dx, BasePort
  add dl, 04h
  mov al, Nr
  out dx, al
  inc dl
  in  al, dx
end; { GetReg }

{----------------------------------------------------------}

procedure SetReg (Nr, Wert : Byte); Assembler;

asm  { SetReg }
  mov dx, BasePort
  add dl, 04h
  mov al, Nr
  out dx, al
  inc dl
  mov al, Wert
  out dx, al
end; { SetReg }

{==========================================================}
{== Funktionen zum Zugriff auf den DSP (Lowlevel)        ==}
{==========================================================}

{----------------------------------------------------------}
{ šberprft die Existenz eines DSP und somit eines SB      }
{ Achtung: Resettet den DSP!                               }
{----------------------------------------------------------}

function DspPresent : Boolean; Assembler;

asm   { DspPresent }
  mov   dx, BasePort            { 1 auf Reset-Port geben }
  add   dl, 6
  mov   al, 1
  out   dx, al

  sub   al, al                  { 3 Microsekunden warten }
@DspPresentLoop1:
  dec   al
  jne   @DspPresentLoop1

  out   dx, al                  { 0 auf Reset-Port geben }

  xor   cx, cx
  add   dl, 8
@DspPresentLoop2:
  in    al, dx
  test  al, 80h
  jne   @ByteAvail              { Byte am Read-Data-Port }
  loop  @DspPresentLoop2
  jmp   @KeinDsp                { Timeout: Kein DSP }

@ByteAvail:                     { Byte lesen und auf AAh prfen }
  sub   dl, 4
  in    al, dx
  cmp   al, 0AAh
  jne   @KeinDsp

  mov   al, true                { DSP vorhanden }
  jmp   @Ende

@KeinDsp:                        { kein DSP vorhanden }
  mov   al, false

@Ende:
end;  { DspPresent }

{----------------------------------------------------------}

procedure WriteDsp (Data : Byte); Assembler;

asm   { WriteDsp }
  mov   dx, BasePort
  add   dl, 0Ch
@WriteDspLoop:
  in    al, dx
  test  al, 80h
  jne   @WriteDspLoop

  mov   al, Data
  out   dx, al
end;  { WriteDsp }

{----------------------------------------------------------}

function ReadDsp : Byte; Assembler;

asm   { ReadDsp }
  mov   dx, BasePort
  add   dl, 0Eh
@ReadDspLoop:
  in    al, dx
  test  al, 80h
  je    @ReadDspLoop

  sub   dl, 4
  in    al, dx
end;  { ReadDsp }

{==========================================================}
{== Funktionen zum Zugriff auf die Kommandozeilenparam.  ==}
{==========================================================}

{----------------------------------------------------------}

function ArgSet (Argument : String) : Boolean;

var
  Lauf : Byte;
  Ergebnis : Boolean;

begin { ArgSet }
  Ergebnis := false;
  if (ParamCount <> 0) then begin
    for Lauf := 1 to ParamCount do begin
      if (ParamStr(Lauf) = Argument) then Ergebnis := true;
    end;
  end;
  ArgSet := Ergebnis;
end;  { ArgSet }

{----------------------------------------------------------}

function ArgNo (Argument : String) : Byte;

var
  Lauf : Byte;
  Ergebnis : Byte;

begin { ArgNo }
  Ergebnis := 0;
  if (ParamCount <> 0) then begin
    for Lauf := 1 to ParamCount do begin
      if (ParamStr(Lauf) = Argument) then Ergebnis := Lauf;
    end;
  end;
  ArgNo := Ergebnis;
end;  { ArgNo }

{----------------------------------------------------------}

function NextArg (Argument : String) : String;

begin { NextArg }
  if (ArgNo(Argument) <> 0) then NextArg := ParamStr(ArgNo(Argument) + 1)
  else NextArg := '';
end;  { NextArg }

{==========================================================}
{== Verschiedene Funktionen                              ==}
{==========================================================}

{----------------------------------------------------------}

procedure UCaseStr (var Str : String);

var
  Lauf : Byte;

begin { UCaseStr }
  if (length(Str) > 0) then
  for Lauf := 1 to length(Str) do
  Str[Lauf] := UpCase(Str[Lauf]);
end;  { UCaseStr }

{----------------------------------------------------------}

function IsDspVerOk : Boolean;

var
  MainVer : Byte;
  SubVer  : Byte;

begin { IsDspVerOk }
  WriteDsp($E1);
  MainVer := ReadDsp;
  SubVer := ReadDsp;
  if (MainVer >= 4) then IsDspVerOk := true else IsDspVerOk := false;
end;  { IsDspVerOk }

{----------------------------------------------------------}

procedure DispInfo;

begin { DispInfo }
  WriteLn('  Informationen:',#10#13);
  WriteLn('Dies ist SB-16-Mixer Release ',ReleaseDate,' von Burkart Lingner.');
  WriteLn('E-Mail: <',Email,'>');
  if (DspPresent) then begin
    WriteDsp($E1);
    WriteLn('DSP-Version ',ReadDsp,'.',ReadDsp);
  end;
  WriteLn('Sonst noch Fragen?!');
end;  { DispInfo }

{----------------------------------------------------------}

procedure DispHelp;

begin { DispHelp }
  WriteLn('  Hilfe:');
  WriteLn('');
  WriteLn('-reset                    resettet den Mixer');
  WriteLn('-s                        keine Ausgabe');
  WriteLn('-readonly                 keine Werte„nderung');
  WriteLn('-ro                       s.o.');
  WriteLn('-readini                  liest die Werte aus der Ini-Datei ein');
  WriteLn('-writeini                 schreibt die aktuellen Werte in die Ini-Datei');
  WriteLn('-inifile: [Ini-Datei]     alternative Ini-Datei (nicht mixer.ini)');
  WriteLn('-nooutdefaults            die Ausg„nge werden nicht von alleine freigeschaltet');
  WriteLn('');
  WriteLn('-h                        Hilfe');
  WriteLn('-help                     Hilfe');
  WriteLn('-?                        Hilfe');
  WriteLn('/?                        Hilfe');
  WriteLn('-info                     Informationen ber mixer.exe');
end;  { DispHelp }

{----------------------------------------------------------}

procedure DispRegs;

begin { DispRegs }
  Write('Master-Lautst„rke links:    ',GetReg($30) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLMASTERL')) then WriteLn(' -> ',GetListItemValue('VOLMASTERL'):2) else WriteLn('');
  Write('Master-Lautst„rke rechts:   ',GetReg($31) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLMASTERR')) then WriteLn(' -> ',GetListItemValue('VOLMASTERR'):2) else WriteLn('');
  Write('Voice-Lautst„rke links:     ',GetReg($32) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLVOICEL')) then WriteLn(' -> ',GetListItemValue('VOLVOICEL'):2) else WriteLn('');
  Write('Voice-Lautst„rke rechts:    ',GetReg($33) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLVOICER')) then WriteLn(' -> ',GetListItemValue('VOLVOICER'):2) else WriteLn('');
  Write('MIDI-Lautst„rke links:      ',GetReg($34) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLMIDIL')) then WriteLn(' -> ',GetListItemValue('VOLMIDIR'):2) else WriteLn('');
  Write('MIDI-Lautst„rke rechts:     ',GetReg($35) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLMIDIR')) then WriteLn(' -> ',GetListItemValue('VOLMIDIR'):2) else WriteLn('');
  Write('CD-Lautst„rke links:        ',GetReg($36) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLCDL')) then WriteLn(' -> ',GetListItemValue('VOLCDL'):2) else WriteLn('');
  Write('CD-Lautst„rke rechts:       ',GetReg($37) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLCDR')) then WriteLn(' -> ',GetListItemValue('VOLCDR'):2) else WriteLn('');
  Write('Line-Lautst„rke links:      ',GetReg($38) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLLINEL')) then WriteLn(' -> ',GetListItemValue('VOLLINEL'):2) else WriteLn('');
  Write('Line-Lautst„rke rechts:     ',GetReg($39) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLLINER')) then WriteLn(' -> ',GetListItemValue('VOLLINER'):2) else WriteLn('');
  Write('Mikrofon-Lautst„rke:        ',GetReg($3A) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLMIC')) then WriteLn(' -> ',GetListItemValue('VOLMIC'):2) else WriteLn('');
  Write('PC-Lautsprecher-Lautst„rke: ',GetReg($3B) and 248 shr 3:2,'/31');
    if (ListItemExists('VOLSPEAKER')) then WriteLn(' -> ',GetListItemValue('VOLSPEAKER'):2) else WriteLn('');

  Write('H”hen links:                ',GetReg($44) and 240 shr 4:2,'/15');
    if (ListItemExists('TREBLEL')) then WriteLn(' -> ',GetListItemValue('TREBLEL'):2) else WriteLn('');
  Write('H”hen rechts:               ',GetReg($45) and 240 shr 4:2,'/15');
    if (ListItemExists('TREBLER')) then WriteLn(' -> ',GetListItemValue('TREBLER'):2) else WriteLn('');
  Write('B„sse links:                ',GetReg($46) and 240 shr 4:2,'/15');
    if (ListItemExists('BASSL')) then WriteLn(' -> ',GetListItemValue('BASSL'):2) else WriteLn('');
  Write('B„sse rechts:               ',GetReg($47) and 240 shr 4:2,'/15');
    if (ListItemExists('BASSR')) then WriteLn(' -> ',GetListItemValue('BASSR'):2) else WriteLn('');

  Write('Eing.-Vorverst„rker links:  ',GetReg($3F) and 192 shr 6:2,'/ 3');
    if (ListItemExists('INAMPL')) then WriteLn(' -> ',GetListItemValue('INAMPL'):2) else WriteLn('');
  Write('Eing.-Vorverst„rker rechts: ',GetReg($40) and 192 shr 6:2,'/ 3');
    if (ListItemExists('INAMPR')) then WriteLn(' -> ',GetListItemValue('INAMPR'):2) else WriteLn('');
  Write('Ausg.-Vorverst„rker links:  ',GetReg($41) and 192 shr 6:2,'/ 3');
    if (ListItemExists('OUTAMPL')) then WriteLn(' -> ',GetListItemValue('OUTAMPL'):2) else WriteLn('');
  Write('Ausg.-Vorverst„rker rechts: ',GetReg($42) and 192 shr 6:2,'/ 3');
    if (ListItemExists('OUTAMPR')) then WriteLn(' -> ',GetListItemValue('OUTAMPR'):2) else WriteLn('');
end;  { DispRegs }

{----------------------------------------------------------}

procedure SetRegs;

begin { SetRegs }
  { Lautst„rken setzen: }
  if (ListItemExists('VOLMASTERL')) then SetReg($30, GetReg($30) and 7 + GetListItemValue('VOLMASTERL') shl 3);
  if (ListItemExists('VOLMASTERR')) then SetReg($31, GetReg($31) and 7 + GetListItemValue('VOLMASTERR') shl 3);
  if (ListItemExists('VOLVOICEL')) then SetReg($32, GetReg($32) and 7 + GetListItemValue('VOLVOICEL') shl 3);
  if (ListItemExists('VOLVOICER')) then SetReg($33, GetReg($33) and 7 + GetListItemValue('VOLVOICER') shl 3);
  if (ListItemExists('VOLMIDIL')) then SetReg($34, GetReg($34) and 7 + GetListItemValue('VOLMIDIL') shl 3);
  if (ListItemExists('VOLMIDIR')) then SetReg($35, GetReg($35) and 7 + GetListItemValue('VOLMIDIR') shl 3);
  if (ListItemExists('VOLCDL')) then SetReg($36, GetReg($36) and 7 + GetListItemValue('VOLCDL') shl 3);
  if (ListItemExists('VOLCDR')) then SetReg($37, GetReg($37) and 7 + GetListItemValue('VOLCDR') shl 3);
  if (ListItemExists('VOLLINEL')) then SetReg($38, GetReg($38) and 7 + GetListItemValue('VOLLINEL') shl 3);
  if (ListItemExists('VOLLINER')) then SetReg($39, GetReg($39) and 7 + GetListItemValue('VOLLINER') shl 3);
  if (ListItemExists('VOLMIC')) then SetReg($3A, GetReg($3A) and 7 + GetListItemValue('VOLMIC') shl 3);
  if (ListItemExists('VOLSPEAKER')) then SetReg($3B, GetReg($3B) and 7 + GetListItemValue('VOLSPEAKER') shl 3);

  { H”hen / Tiefen setzen: }
  if (ListItemExists('TREBLEL')) then SetReg($44, GetReg($44) and 15 + GetListItemValue('TREBLEL') shl 4);
  if (ListItemExists('TREBLER')) then SetReg($45, GetReg($45) and 15 + GetListItemValue('TREBLER') shl 4);
  if (ListItemExists('BASSL')) then SetReg($46, GetReg($46) and 15 + GetListItemValue('BASSL') shl 4);
  if (ListItemExists('BASSR')) then SetReg($47, GetReg($47) and 15 + GetListItemValue('BASSR') shl 4);

  { Vorverst„rker setzen: }
  if (ListItemExists('INAMPL')) then SetReg($3F, GetReg($3F) and 63 + GetListItemValue('INAMPL') shl 6);
  if (ListItemExists('INAMPR')) then SetReg($40, GetReg($40) and 63 + GetListItemValue('INAMPR') shl 6);
  if (ListItemExists('OUTAMPL')) then SetReg($41, GetReg($41) and 63 + GetListItemValue('OUTAMPL') shl 6);
  if (ListItemExists('OUTAMPR')) then SetReg($42, GetReg($42) and 63 + GetListItemValue('OUTAMPR') shl 6);

  { Ausg„nge freischalten: }
  if (ListItemExists('OUTLINEL')) then SetReg($3C, GetReg($3C) and 239 + GetListItemValue('OUTLINEL') shl 4);
  if (ListItemExists('OUTLINER')) then SetReg($3C, GetReg($3C) and 247 + GetListItemValue('OUTLINER') shl 3);
  if (ListItemExists('OUTCDL')) then SetReg($3C, GetReg($3C) and 251 + GetListItemValue('OUTCDL') shl 2);
  if (ListItemExists('OUTCDR')) then SetReg($3C, GetReg($3C) and 253 + GetListItemValue('OUTCDR') shl 1);
  if (ListItemExists('OUTMIC')) then SetReg($3C, GetReg($3C) and 254 + GetListItemValue('OUTMIC'));

  { Eing„nge freischalten: }
  if (ListItemExists('INLMIDIL')) then SetReg($3D, GetReg($3D) and 191 + GetListItemValue('INLMIDIL') shl 6);
  if (ListItemExists('INLMIDIR')) then SetReg($3D, GetReg($3D) and 223 + GetListItemValue('INLMIDIR') shl 5);
  if (ListItemExists('INLLINEL')) then SetReg($3D, GetReg($3D) and 239 + GetListItemValue('INLLINEL') shl 4);
  if (ListItemExists('INLLINER')) then SetReg($3D, GetReg($3D) and 247 + GetListItemValue('INLLINER') shl 3);
  if (ListItemExists('INLCDL')) then SetReg($3D, GetReg($3D) and 251 + GetListItemValue('INLCDL') shl 2);
  if (ListItemExists('INLCDR')) then SetReg($3D, GetReg($3D) and 253 + GetListItemValue('INLCDR') shl 1);
  if (ListItemExists('INLMIC')) then SetReg($3D, GetReg($3D) and 254 + GetListItemValue('INLMIC'));
  if (ListItemExists('INRMIDIL')) then SetReg($3E, GetReg($3E) and 191 + GetListItemValue('INRMIDIL') shl 6);
  if (ListItemExists('INRMIDIR')) then SetReg($3E, GetReg($3E) and 223 + GetListItemValue('INRMIDIR') shl 5);
  if (ListItemExists('INRLINEL')) then SetReg($3E, GetReg($3E) and 239 + GetListItemValue('INRLINEL') shl 4);
  if (ListItemExists('INRLINER')) then SetReg($3E, GetReg($3E) and 247 + GetListItemValue('INRLINER') shl 3);
  if (ListItemExists('INRCDL')) then SetReg($3E, GetReg($3E) and 251 + GetListItemValue('INRCDL') shl 2);
  if (ListItemExists('INRCDR')) then SetReg($3E, GetReg($3E) and 253 + GetListItemValue('INRCDR') shl 1);
  if (ListItemExists('INRMIC')) then SetReg($3E, GetReg($3E) and 254 + GetListItemValue('INRMIC'));
end;  { SetRegs }

{----------------------------------------------------------}

procedure ReadIniFile (Dateiname : String);

var
  IniFile  : Text;
  Zeile    : String;
  Variable : String;
  WertStr  : String;
  Wert     : Byte;
  Error    : Integer;
  DummyLI  : ListItem;

begin { ReadIniFile }
  {$I-}
  Assign(IniFile, Dateiname);
  Reset(IniFile);
  {$I+}
  if (IOResult = 0) then begin
    repeat
      ReadLn(IniFile, Zeile);
      if (Zeile[1] <> ';') and (Zeile[1] <> '#') and (Zeile <> '') then begin
        if (Pos('=', Zeile) > 0) then begin
          Variable := Copy(Zeile, 1, Pos('=', Zeile)-1);
          WertStr := '';
          WertStr := Copy(Zeile, Pos('=', Zeile)+1, Length(Zeile)-Pos('=',Zeile)+1);
          Val(WertStr, Wert, Error);
          if (Error = 0) then begin
            DummyLI.Name := Variable;
            UCaseStr(DummyLI.Name);
            DummyLI.Value := Wert;
            DummyLI.NextItem := nil;
            AddListItem(DummyLI);
          end else WriteLn('[FEHLER] Fehler in ',Dateiname,': Der Variable ',Variable,
                           ' wurde keine Zahl zugewiesen (',WertStr,')',#10#13);
        end else WriteLn('[FEHLER] Fehlerhafte Zeile in ',Dateiname,': ',Zeile,#10#13);
      end;
    until (Eof(IniFile));
    Close(IniFile);
  end else WriteLn('[FEHLER] Konnte die Datei ',Dateiname,' nicht ”ffnen.',#10#13);
end;  { ReadIniFile }

{----------------------------------------------------------}

procedure WriteIniFile (Dateiname : String);

var
  IniFile : Text;

begin; { WriteIniFile }
  {$I-}
  Assign(IniFile, Dateiname);
  Rewrite(IniFile);
  {$I+}
  if (IOResult = 0) then begin
    WriteLn(IniFile, 'VolMasterL=',GetReg($30) and $F8 shr 3);
    WriteLn(IniFile, 'VolMasterR=',GetReg($31) and $F8 shr 3);
    WriteLn(IniFile, 'VolVoiceL=',GetReg($32) and $F8 shr 3);
    WriteLn(IniFile, 'VolVoiceR=',GetReg($33) and $F8 shr 3);
    WriteLn(IniFile, 'VolMidiL=',GetReg($34) and $F8 shr 3);
    WriteLn(IniFile, 'VolMidiR=',GetReg($35) and $F8 shr 3);
    WriteLn(IniFile, 'VolCdL=',GetReg($36) and $F8 shr 3);
    WriteLn(IniFile, 'VolCdR=',GetReg($37) and $F8 shr 3);
    WriteLn(IniFile, 'VolLineL=',GetReg($38) and $F8 shr 3);
    WriteLn(IniFile, 'VolLineR=',GetReg($39) and $F8 shr 3);
    WriteLn(IniFile, 'VolMic=',GetReg($3A) and $F8 shr 3);
    WriteLn(IniFile, 'VolSpeaker=',GetReg($3B) and $F8 shr 3);
    WriteLn(IniFile, 'TrebleL=',GetReg($44) and $F0 shr 4);
    WriteLn(IniFile, 'TrebleR=',GetReg($45) and $F0 shr 4);
    WriteLn(IniFile, 'BassL=',GetReg($46) and $F0 shr 4);
    WriteLn(IniFile, 'BassR=',GetReg($46) and $F0 shr 4);
    WriteLn(IniFile, 'InAmpL=',GetReg($3F) and $C0 shr 6);
    WriteLn(IniFile, 'InAmpR=',GetReg($40) and $C0 shr 6);
    WriteLn(IniFile, 'OutAmpL=',GetReg($41) and $C0 shr 6);
    WriteLn(IniFile, 'OutAmpR=',GetReg($42) and $C0 shr 6);
    WriteLn(IniFile, 'OutLineL=',GetReg($3C) and $10 shr 4);
    WriteLn(IniFile, 'OutLineR=',GetReg($3C) and $08 shr 3);
    WriteLn(IniFile, 'OutCdL=',GetReg($3C) and $04 shr 2);
    WriteLn(IniFile, 'OutCdR=',GetReg($3C) and $02 shr 1);
    WriteLn(IniFile, 'OutMic=',GetReg($3C) and $01);
    WriteLn(IniFile, 'InLMidiL=',GetReg($3D) and $40 shr 6);
    WriteLn(IniFile, 'InLMidiR=',GetReg($3D) and $20 shr 5);
    WriteLn(IniFile, 'InLLineL=',GetReg($3D) and $10 shr 4);
    WriteLn(IniFile, 'InLLineR=',GetReg($3D) and $08 shr 3);
    WriteLn(IniFile, 'InLCdL=',GetReg($3D) and $04 shr 2);
    WriteLn(IniFile, 'InLCdR=',GetReg($3D) and $02 shr 1);
    WriteLn(IniFile, 'InLMic=',GetReg($3D) and $01);
    WriteLn(IniFile, 'InRMidiL=',GetReg($3E) and $40 shr 6);
    WriteLn(IniFile, 'InRMidiR=',GetReg($3E) and $20 shr 5);
    WriteLn(IniFile, 'InRLineL=',GetReg($3E) and $10 shr 4);
    WriteLn(IniFile, 'InRLineR=',GetReg($3E) and $08 shr 3);
    WriteLn(IniFile, 'InRCdL=',GetReg($3E) and $04 shr 2);
    WriteLn(IniFile, 'InRCdR=',GetReg($3E) and $02 shr 1);
    WriteLn(IniFile, 'InRMic=',GetReg($3E) and $01);
    Close(IniFile);
  end else WriteLn('[FEHLER] Konnte die Datei ',Dateiname,' nicht ”ffnen.',#10#13);
end;   { WriteIniFile }

{----------------------------------------------------------}

procedure SetOutDefaults;

begin { SetOutDefaults }
  SetReg($3C, GetReg($3C) and $E0 + DOutLineL shl 4 + DOutLineR shl 3 + DOutCdL shl 2 + DOutCdR shl 1 + DOutMic);
end;  { SetOutDefaults }

{***************************************************************************}
{********** Hauptprogramm **************************************************}
{***************************************************************************}

begin { Hauptprogramm }

  BasePort := $0220;
  MixerIni := 'MIXER.INI';

  FirstMixVar := nil;
  LastMixVar := nil;

  if (NextArg('-inifile:') <> '') then MixerIni := NextArg('-inifile:');

  WriteLn('SB-16-Mixer --- Release ',ReleaseDate);
  WriteLn('');

  if (ArgSet('-help')) or (ArgSet('/?')) or (ArgSet('-?')) or (ArgSet('-h')) then DispHelp
  else if (ArgSet('-info')) then DispInfo
  else begin

    if (not DspPresent) then WriteLn('[FEHLER] Keine Soundkarte gefunden! Programm wurde beendet.') else begin

      { Soundkarte gefunden }

      if (not IsDspVerOk) then WriteLn('[FEHLER] Keine SB 16 oder besser gefunden! Programm wurde beendet.') else begin

        if (ArgSet('-writeini')) then WriteIniFile(MixerIni);
        if (ArgSet('-reset')) then SetReg($00, 0);
        if (not ArgSet('-nooutdefaults')) then SetOutDefaults;
        if (ArgSet('-readini')) then ReadIniFile(MixerIni);
        if (not ArgSet('-s')) then DispRegs;
        if (not (ArgSet('-readonly') or ArgSet('-ro'))) then SetRegs;

      end; { SB16+ ? }

    end; { DSP vorhanden? }

  end; { Hilfe? }

end.  { Hauptprogramm }