[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]

    {--Title:       MVFUNCT.PAS
       Author:      Patrick O'Malley AKA Silicom Slim
       Constact:    e-mail: d005530c@dcfreenet.seflin.lib.fl.us
       Language:    Turbo Pascal v6.0
       Description: Functions and procedures to interface with the ProAudio
                    Spectrum's mixer and volume controls.
       Status:      Public Domain

      This unit is a primer for programming the ProAudio Spectum basic or 16, it
    doesn't seem to matter.
      IMPORTANT TECH NOTE: All settings are in percent! Just a decimal from 0 to
    100. Very odd. And sometimes when you set a volume too low, it will just go
    to 0. Basically what you enter will result in a volume +-2 percentage points
    off what you entered. Doesn't make much difference.
      I have no idea what CrossChannels are. Or the FMSplitChips thing. They don't
    seem too interesting anyhow.
      For the unknowing, mixers and volumes are basically the same thing. Setting
    the output of a mixer changes it's volume if you play something that uses
    that mixer. For example, a cd-rom drive is attached to the internal mixer
    input. The volume functions aren't really just for volumes anyhow. They
    control the treble, bass, loudness & enhanced switches too.
      Most of the procedures and functions are simple to understand. The
    GetFunctionTable procedure is used internally by the unit.

      I'd like to request code re:SoundBlaster mixer/vol stuff. --}

    Unit MVFunct;

    interface

    CONST
    {--volume channel select constants--}
    {--These constants are used _only_ with the functions/procedures that use a
       call to functiontable.mvset(or get)volumefunction.
        VolMute is strange. It appears in the COMMON.INC file of the PAS-SDK
       but is never explained and doesn't seem to have an effect.
        VolLoudEnh is also odd. It is supposed to be used to set the Loudness
       and Enhanced switches (and it does). The only problem is that using
       a value of 100% turns _both_ on. Doing a 0% turns off only enhanced then.
       Maybe there is some trick I haven't discovered.
        VolBass & VolTreble set the Bass and Treble.
        VolLeft and VolRight are the master volume settings.
        VolMode is some sort of modal setting. No documentation in the PAS-SDK.--}

    VolMute    = $40;
    VolLoudEnh = $41;
    VolBass    = $42;
    VolTreble  = $43;
    VolLeft    = $44;
    VolRight   = $45;
    VolMode    = $46;

    {--mixer selection constants--}
    {--These constants are used when a mixer can either be an input of output
       mixer. For example, the internal connector (hooked to the cd-rom drive)
       can either output sound or input it. So you can select the levels at
       which it does these. For outputting sound levels use pmOUTPUTMIXER. --}
    pmOUTPUTMIXER = $00;
    pmINPUTMIXER  = $20;

    {--left channel selection values--}
    {--these constants are used to select which mixer (they are: internal which
       is usually the CD-ROM, external which _can_ be attached to external music
       equiptment, microphone, PCM or digital sound, the internal speaker which
       is re-routed by the pro-audio out it's speakers and the sound-blaster
       emulation mixer. I have no idea what R_ or L_IMIXER is.--}
    L_FM = $01;
    L_IMIXER = $02;
    L_EXT = $03;
    L_INT = $04;
    L_MIC = $05;
    L_PCM = $06;
    L_SPEAKER = $07;
    L_FREE = $00;
    L_SBDAC = $00;

    {--right channel selection values--}
    {--these constants can be used in places that ask for the channel to, for
       example, change the setting of. they are for the right channel only. --}
    R_FM = $08;
    R_IMIXER = $09;
    R_EXT = $0A;
    R_INT = $0B;
    R_MIC = $0C;
    R_PCM = $0D;
    R_SPEAKER = $0E;
    R_FREE = $0F;
    R_SBDAC = $0F;

    {--The following is used for the get/set, on/off procedures--}
    Get = True;
    Set_ = False;
    On = true;
    Off = false;

    Type tFunctionTable = record
                            MVSetMixerFunction,
                            MVSetVolumeFunction,
                            MVSetFilterFunction,
                            MVSetCrossChannel,
                            MVGetMixerFunction,
                            MVGetVolumeFunction,
                            MVGetFilterFunction,
                            MVGetCrossChannel,
                            MVRealSoundSwitch,
                            MVFMSplitSwitch     : Pointer;
                          end;
    Var FunctionTable : tFunctionTable;

    Function IsMVSOUNDInstalled : Boolean;
    Procedure GetFunctionTable;             {internal, used by MVFUNCT.TPU}
    Procedure SetMasterVolume(R,L : Boolean;R_Setting,L_Setting : Word);
    Procedure SetMixer(In_Out, Channel_Select : Byte; Mixer_Setting : Word);
    Procedure GetMasterVolume(R,L : Boolean; Var R_Setting, L_Setting : Word);
    Function GetMixer(In_Out, Channel_Select : Word) : Byte;
    Procedure SetFilter(Filter_Setting : Byte);
    Function GetFilter : Byte;
    Procedure Get_Set_RealSound(Get_Set : Boolean;Var On_Off : boolean);
    Procedure SetVolume(Channel,Setting : Word);
    Function GetVolume(Channel : Word) : Byte;
    Function GetIRQ : Byte;
    Function GetDMA : Byte;

    implementation

    Function IsMVSOUNDInstalled : Boolean;
    {Basically this function checks for MVSOUND.SYS, the device driver that is
     required to do the mixer functions that follow. Simple. }
    Var edx : Word;
    Begin
      IsMVSOUNDInstalled := FALSE;
      asm
        mov  ax, 0bc00h
        mov  bx, 03f3fh
        xor  cx, cx
        xor  dx, dx
        int  2fh
        xor  cx, bx
        xor  dx, cx
        mov  [edx], dx
      end;
      if edx = $4d56 then IsMVSOUNDInstalled := True
      else IsMVSOUNDInstalled := False;
    End;    {IsMVSOUNDInstalled func}

    Procedure GetFunctionTable;          {used by the unit}
    Var FTableSeg, FTableOfs : Word;
    Begin
      Asm
        mov  ax, 0bc03h
        int  2fh
        mov  [ftableofs], bx        {function table offset}
        mov  [ftableseg], dx        {function table segment}
      end;
      {--Move the table into the function table of pointers for pascal--}

    Move(Mem[ftableseg:ftableofs],Mem[seg(functiontable):ofs(functiontable)],40);
    End; {GetFunctionTable proc}

    Procedure SetMasterVolume(R,L : Boolean;R_Setting,L_Setting : Word);
    {This procedure is actually the SetVolume procedure but is master volume
     channel specific.
     Vars R&L : Boolean tell it which channel (right or left) to change.
     R_&L_Setting are the % (0-100) to set the channel to.
    }
    Begin
      If R then begin
      asm
        mov  bx, R_Setting
        mov  cx, VolRight
        {$F+}
        call functiontable.mvsetvolumefunction
        {$F-}
      end;
      end;
      if L then begin
      asm
        mov  bx, L_Setting
        mov  cx, VolLeft
        {$F+}
        call functiontable.mvsetvolumefunction
        {$F-}
      end;
      end;
    End; {setmastervolume func}

    Procedure SetMixer(In_Out, Channel_Select : Byte; Mixer_Setting : Word);
    { This procedure is used to set the I/O volume of one of the mixers.
      In_Out is a constant listed above under mixer selection constants.
      Channel_Select is either the right or left constant from the list above
      under channel selection values.
      Mixer_Setting is the % (0-100) to set the volume to.
    }
    Begin
      Asm
        mov  bx, Mixer_Setting
        xor  cx, cx
        xor  dx, dx
        mov  cl, In_Out
        mov  dl, Channel_Select
        {$F+}
        call functiontable.MVSetMixerFunction
        {$F-}
      End;
    End;    {setmixer proc}

    Procedure GetMasterVolume(R,L : Boolean; Var R_Setting, L_Setting : Word);
    { See SetMaster volume for the variable descriptions.
      Basically returns the current master volume.
    }
    Var Temp : Word;
    Begin
      If R then Begin
      Asm
        mov  cx, VolRight
        {$F+}
        call functiontable.mvgetvolumefunction
        {$F-}
        mov  [Temp], bx
      end;
      R_Setting := Temp;
      end;
      If L then Begin
      asm
        mov  cx, VolLeft
        {$F+}
        call functiontable.mvgetvolumefunction
        {$F-}
        mov  [Temp], bx
      end;
      L_Setting := Temp;
      end;
    End; {getmastervolume proc}

    Function GetMixer(In_Out, Channel_Select : Word) : Byte;
    { See SetMixer for variable descriptions.
      Basically just returns the volume of the selected mixer.
    }
    Var Temp : Byte;
    Begin
      asm
        mov  cx, In_Out
        mov  dx, Channel_Select
        {$F+}
        call functiontable.mvgetmixerfunction
        {$F-}
        mov  [temp], bl
      end;
      GetMixer := Temp;
    end;  {getmixersetting proc}

    Procedure SetFilter(Filter_Setting : Byte);
    { I'm a little unsure about this function call. Here is what the SDK says:
        0% filters out amything higher than 0khz  (mute)
        100% filters out anything lower than 20khz
      It does mute it, but I can't attach a spectrum analyzer to the speaker
      to test the frequency.
      Filter_Setting is the % to filter?
    }
    Begin
      Asm
        xor  bx, bx
        mov  bl, Filter_Setting
        {$F+}
        call functiontable.mvsetfilterfunction
        {$F-}
      end;
    End; {setfilter proc}

    Function GetFilter : Byte;
    { See SetFilter }
    Var Temp : Byte;
    Begin
      asm
        {$F+}
        call functiontable.mvgetfilterfunction
        {$F-}
        mov [Temp], bl
      end;
      GetFilter := Temp;
    End;  {getfilter proc}

    Procedure Get_Set_RealSound(Get_Set : Boolean;Var On_Off : boolean);
    { If Get_Set is true then it is gotten, otherwise it is set.
      If On_Off is true then it is turned on, otherwise turned off.

      I added some constants: Get, Set_, On, Off for this procedure. If someone
      wants to make this procedure better, you have my blessing. Yuk.
    }
    Var ebx, ecx, return : word;
    Begin
      if Get_Set then ecx := 0 else ecx := 1;
      if on_off then ebx := 100 else ebx := 0;
      asm
        mov bx, ebx
        mov cx, ecx
        {$F+}
        call functiontable.mvrealsoundswitch
        {$F-}
        mov [return], bx
      end;
      If Get_Set then
        If return = 100 then On_Off := True
        else On_Off := False;
    end;   {get_set_realsound}

    Function GetIRQ : Byte;
    { Returns the IRQ of the PAS }
    Var Res : Byte;
    Begin
      asm
        mov  ax, 0bc04h
        int  2fh
        mov  [res], cl
      end;
      GETIRQ := res;
    end;   {getirq proc}

    Function GetDMA : byte;
    { Returns the DMA of the PAS }
    Var res: byte;
    Begin
      asm
        mov  ax, 0bc04h
        int  2fh
        mov  [res], bl
      end;
      GetDMA := Res;
    End;  {getdma proc}

    Procedure SetVolume(Channel,Setting : Word);
    { This procedure will change the setting of a specific channel specified by
      the constants listed under volume channel selection constants.
      Channel is the constant specifying the channel to change
      Setting is the % volume (0-100)
    }
    Begin
      asm
        mov  bx, Setting
        mov  cx, Channel
        {$F+}
        call functiontable.mvsetvolumefunction
        {$F-}
      end;
    End;  {setvolume proc}

    Function GetVolume(Channel : Word) : Byte;
    { See setvolume }
    Var Res:Byte;
    Begin
      asm
        mov  cx, channel
        {$F+}
        call functiontable.mvgetvolumefunction
        {$F-}
        mov  [res], bl
      end;
      GetVolume := Res;
    End; {getvolume func}

    begin
      if isMVSOUNDInstalled then getfunctiontable
      else begin
             Writeln('MVSOUND.SYS is not installed.');
             Halt(1);
      End;
    end.

[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]