{ SoundEx -- Version 3.0 }

{******************************************************************************
*
* Developer Technical Support Apple II Sample Code
*
* doLoad:       This routine allocates a buffer and reads the desired file 
*               into the buffer.   If a buffer has already been allocated, 
*               It will be disposed.  Note that it also sets the global 
*               variables BuffHndl and BuffSize.
*
* Inputs:       pathString contains the pathname of the file.
* Outputs:      NONE
* Calls:        NONE
}

procedure doLoad(pathString : GSString255Ptr);

var
    opRGS : OpenRecGS;
    eofGS : EOFRecGS;
    ioRGS : IORecGS;
    rnRGS : RefNumRecGS;
    
begin
    opRGS.pCount := 2;
    opRGS.pathname := pathString;
    OpenGS (OpRGS);

    eofGS.pCount := 2;
    eofGS.refNum := opRGS.refnum;
    GetEOFGS (eofGS);
    BuffSize := trunc(eofGS.eof);
    
    if BuffHndl <> NIL then         
        begin
            HUnlock(BuffHndl);
            DisposeHandle(BuffHndl);
        end;

    BuffHndl := NewHandle (Buffsize, MyMemoryID, $C00C, NIL);
    HLock(BuffHndl);
    
    iorGS.pCount := 4;
    iorGS.refNum := opRGS.refnum;
    iorGS.dataBuffer := BuffHndl^;
    iorGS.requestCount := BuffSize;
    ReadGS (ioRGS);

    rnRGS.pCount := 1;
    rnRGS.refNum := opRGS.refnum;
    CloseGS (rnRGS);
end;

{******************************************************************************
*
* doLoadFile:   Puts up SFGetFile, calls doLoad with the desired pathName,
*               updates the paramText for the staticText controls.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doLoad
}
procedure doLoadFile;

var
    myReply : SFReplyRec2;
    promptStr,
    tempStr : String255;
    x   : integer;

begin
    myReply.nameRefDesc := refIsNewHandle;
    myReply.pathRefDesc := refIsNewHandle;
    promptStr := 'Select a Sound File to Load:';
    SFGetFile2(
        10, 35,
        teRefIsPtr,
        Ref(@promptStr),
        NIL,            { filter proc }
        NIL,            { type list   }
        myReply
    );

    if myReply.good then 
        begin
            {update the file name for display }
            moveleft(Handle(myReply.nameRef)^^,tempStr,255);
            tempStr[3] := tempStr[2];
            
            for x := 0 to length(tempStr) - 3 do   {moveleft won't do this}
                tempStr[x] := tempStr[x+3];
                
            paramRec1.Str[1] := tempStr;                { set the paramText }
            DrawOneCtl(GetCtlHandleFromID(OurWindow,curfileID));

            {set up the pathRef for the doLoad call }
            moveleft(Handle(myReply.pathRef)^^,tempStr,255);
            
            for x := 0 to length(tempStr) - 2 do   {moveleft won't do this}
                tempStr[x] := tempStr[x+2];
                
            doLoad(@tempStr);
            
            { set up the buffer pointer for display }
            tempStr := '        ';
            Long2Hex (longint(BuffHndl^), Ptr(Longint(@tempStr)+1),8);
            
            paramRec1.Str[2] := tempStr;
            DrawOneCtl(GetCtlHandleFromID(OurWindow,loadedAtID));

            { set up the buffer size for display }
            tempStr := '    ';
            Long2Hex (BuffSize, Ptr(Longint(@tempStr)+1),4);
            
            paramRec1.Str[3] := tempStr;
            DrawOneCtl(GetCtlHandleFromID(OurWindow,buffSizeID));

            DisposeHandle(Handle(myReply.nameRef));
            DisposeHandle(Handle(myReply.pathRef));
        end
end;

{******************************************************************************
*
* setResult:    Updates the results of the last call.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        NONE
}
procedure setResult;

var
    resultStr : String;

begin
    resultStr := '        ';
    Long2Hex (CurCmdResult, @resultStr[1],8);
    
    paramRec1.Str[4] := resultStr;
    DrawOneCtl(GetCtlHandleFromID(OurWindow,resultID));

    resultStr := '    ';
    Int2Hex (CurCmdErr,@resultStr[1],4);
    
    paramRec1.Str[5] := resultStr;
    DrawOneCtl(GetCtlHandleFromID(OurWindow,toolErrID));
end;



{******************************************************************************
*
* setEditStr:   Places a Pascal string into a LineEdit control.
*
* Inputs:       updStr is the string to be set, and ctlItemID is the LineEdit
*               control ID to set.
*
* Outputs:      NONE
* Calls:        NONE
}
procedure setEditStr(updStr : String; ctlItemID : integer);

var
    theCtl      : CtlRecHndl;
    theLERec    : LERecHndl;

begin
    theCtl := GetCtlHandleFromID(ourwindow, ctlItemID);
    theLERec := LERecHndl(theCtl^^.ctlData);
    
    LESetSelect(0,256,theLERec);
    LESetText(Ptr(@updStr[1]), length(updStr),
              theLERec);
    LESetSelect(0, 256, theLERec)  ;

    DrawOneCtl(theCtl);
end;


{******************************************************************************
*
* getEditStr:   Updates a Pascal string from the contents of a LineEdit control.
*
* Inputs:       ctlItemID is the LineEdit control ID to obtain the string from.
* Outputs:      updStr contains the Pascal String.
* Calls:        NONE
}
procedure getEditStr(var updStr : String; ctlItemID : integer);

var
    theCtl   : CtlRecHndl;
    textHndl : Handle;
    textLen,x    : integer;

begin
    theCtl := GetCtlHandleFromID(ourwindow, ctlItemID);
    textHndl := LEGetTextHand(LERecHndl(theCtl^^.ctlData));
    textLen := LEGetTextLen(LERecHndl(theCtl^^.ctlData));
    moveleft(textHndl^^,updStr,textLen);
    for x := textlen+1 downto 0 do
        updStr[x+1] := updStr[x];
    updStr[0] := chr(textLen);
end;

{******************************************************************************
*
* getEditInt:   Updates an integer from the contents of a LineEdit control.
*
* Inputs:       ctlItem is the LineEdit control ID to obtain the value from.
* Outputs:      the result is the integer value of the Hex String in the control.
* Calls:        getEditStr
}
function getEditInt(ctlItem : integer) : integer;

var 
    valStr : String;

begin
    getEditStr(valStr,ctlItem);
    getEditInt := Hex2Int ( @valStr[1], length(valStr));
end;

{******************************************************************************
*
* getEditLong:  Updates a long from the contents of a LineEdit control.
*
* Inputs:       ctlItem is the LineEdit control ID to obtain the value from.
* Outputs:      the result is the long value of the Hex String in the control.
* Calls:        getEditStr
}
function getEditLong(ctlItem : integer) : longint;

var 
    valStr : String;

begin
    getEditStr(valStr,ctlItem);
    getEditLong := Hex2Long ( @valStr[1], length(valStr));
end;


{******************************************************************************
*
* setEditInt:   Updates a LineEdit control to the hex string representation
*               of an integer.
*
* Inputs:       value is the integer to be converted.
*               ctlItem is the LineEdit control ID to receive the hex string.
*               strLength is the desired length of the string.              
* Outputs:      the result is the long value of the Hex String in the control.
* Calls:        setEditStr
}
procedure setEditInt(value, ctlItem, strLength : integer);

var 
    valStr : String;

begin
    Int2Hex (value, @valStr[1], strLength);
    valStr[0] := chr(strLength);
    setEditStr(valStr, ctlItem);
end;

{******************************************************************************
*
* setEditLong:  Updates a LineEdit control to the hex string representation
*               of a long value passed to it. The string is assumed to be
*               8 characters wide.
*
* Inputs:       value is the long to be converted.
*               ctlItem is the LineEdit control ID to receive the hex string.
* Outputs:      the result is the long value of the Hex String in the control.
* Calls:        setEditStr
}
procedure setEditLong(value : longint; ctlItem:integer);

var 
    valStr : String;

begin
    Long2Hex (value, @valStr[1],8);
    valStr[0] := chr(8);
    setEditStr(valStr, ctlItem);
end;


{******************************************************************************
*
* setTargetCtl: After the proper controls have been "hilited", setTargetCtl
*               will determine which should be active and make it the 
*               current target control.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        NONE
}
procedure setTargetCtl;

var theCtlID : integer;

begin
    theCtlID := 0;
    
    if ctlHilite.docblk then
        theCtlID := oscGenTypeID
    else if ctlHilite.sndBlk then
        theCtlID := waveStartID
    else if ctlHilite.parm[1] then
        theCtlID := parm1ID;

    if theCtlID <> 0 then
        MakeThisCtlTarget (GetCtlHandleFromID(ourwindow,theCtlID));
end;


{******************************************************************************
*
* getDocBlk:    Returns the current DocRegParamBlock values from the 
*               LineEdit controls.
*
* Inputs:       NONE
* Outputs:      docBlock is the DOC register paramBlock.
* Calls:        getEditInt
}
procedure getDocBlk(var docBlk : DocRegParamBlk);

begin
    with docBlk do
        begin
            oscGenType  := getEditInt(oscGenTypeID);
            freqLow1    := getEditInt(freqLow1ID);
            freqHigh1   := getEditInt(freqHigh1ID);
            vol1        := getEditInt(vol1ID);
            tablePtr1   := getEditInt(tablePtr1ID);
            control1    := getEditInt(control1ID);
            tableSize1  := getEditInt(tableSize1ID);
            freqLow2    := getEditInt(freqLow2ID);
            freqHigh2   := getEditInt(freqHigh2ID);
            vol2        := getEditInt(vol2ID);
            tablePtr2   := getEditInt(tablePtr2ID);
            control2    := getEditInt(control2ID);
            tableSize2  := getEditInt(tableSize2ID);
        end;
end;
    
{******************************************************************************
*
* getSndBlk:    Returns the current SoundParamBlock values from the 
*               LineEdit controls.
*
* Inputs:       NONE
* Outputs:      sndBlk is the Sound paramBlock.
* Calls:        getEditInt, getEditLong
}
procedure getSndBlk(var sndBlk : SoundParamBlock);

begin
    with sndBlk do
        begin
            waveStart   := Ptr(getEditLong(waveStartID));
            waveSize    := getEditInt(waveSizeID);
            freqOffset  := getEditInt(freqOffsetID);
            docBuffer   := getEditInt(docBufferID);
            bufferSize  := getEditInt(bufferSizeID);
            nextWavePtr := SoundPBPtr(getEditLong(nextWavePtrID));
            volSetting  := getEditInt(volSettingID);
        end;
end;    

{******************************************************************************
*
* setDocBlk:    Updates the LineEdit controls based on the values in the 
*               current DocRegParamBlock.
*
* Inputs:       docBlock is the DOC register paramBlock.
* Outputs:      NONE
* Calls:        setEditInt
}
procedure setDocBlk(docBlk : DocRegParamBlk);

begin
    with docBlk do
        begin
            setEditInt(oscGenType, oscGenTypeID, 4);
            setEditInt(freqLow1, freqLow1ID, 2);
            setEditInt(freqHigh1, freqHigh1ID, 2);
            setEditInt(vol1, vol1ID, 2);
            setEditInt(tablePtr1, tablePtr1ID, 2);
            setEditInt(control1, control1ID, 2);
            setEditInt(tableSize1, tableSize1ID, 2);
            setEditInt(freqLow2, freqLow2ID, 2);
            setEditInt(freqHigh2, freqHigh2ID, 2);
            setEditInt(vol2, vol2ID, 2);
            setEditInt(tablePtr2, tablePtr2ID, 2);
            setEditInt(control2, control2ID, 2);
            setEditInt(tableSize2, tableSize2ID, 2);
        end;
end;
    
{******************************************************************************
*
* setSndBlk:    Updates the LineEdit controls based on the values in the 
*               current SoundParamBlock.
*               LineEdit controls.
*
* Inputs:       sndBlk is the Sound paramBlock.
* Outputs:      NONE
* Calls:        setEditInt, setEditLong
}
procedure setSndBlk(sndBlk : SoundParamBlock);

begin
    with sndblk do
        begin
            setEditLong(longint(waveStart), waveStartID);
            setEditInt(waveSize, waveSizeID, 4);
            setEditInt(freqOffset, freqOffsetID, 4);
            setEditInt(docBuffer, docBufferID, 4);
            setEditInt(bufferSize, bufferSizeID, 4);
            setEditLong(longint(nextWavePtr), nextWavePtrID);
            setEditInt(volSetting, volSettingID, 4);
        end;
end;    

{******************************************************************************
*
* doExecute:    doExecute executes the Sound Tools command chosen in the 
*               pop-up menu.  If necessary, it gets the values from the     
*               correct parameters (or paramBlocks) and makes the call
*               with them.  When the call is completed, it updates the
*               affected parameters, including the staticText results.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        setTargetCtl, getEditLong, getSndBlk, setSndBlk, getDocBlk, 
*               setDocBlk, setEditLong, setResult
}
procedure doExecute;

var
    docBlk : DocRegParamBlk;
    sndBlk : SoundParamBlock;
    parm1,
    parm2,
    parm3   : longint;
    
begin
    setTargetCtl;                   { set the target control }

    { update the parameter values to be passed to the calls }
    if ctlHilite.parm[1] then parm1 := getEditLong(Parm1ID);
    if ctlHilite.parm[2] then parm2 := getEditLong(Parm2ID);
    if ctlHilite.parm[3] then parm3 := getEditLong(Parm3ID);
    
    CurCmdErr := 0;     { reset the result values }
    CurCmdResult := 0;

    case CurCmdNum of       { based on the pop-up selection, make the call }
        SoundVersionID      : CurCmdResult := SoundVersion;
        SoundToolStatusID   : CurCmdResult := ord(SoundToolStatus);
        FFGeneratorStatusID : CurCmdResult := FFGeneratorStatus (parm1);
        FFSoundDoneStatusID : CurCmdResult := ord(FFSoundDoneStatus (parm1));
        FFSoundStatusID     : CurCmdResult := FFSoundStatus;
        FFStartSoundID      :
            begin
                getSndBlk(sndBlk);
                FFStartSound(trunc(parm1), @sndBlk);
                CurCmdErr := _toolErr;
                setSndBlk(sndBlk);
            end;
        FFStopSoundID       : FFStopSound(trunc(parm1))  ;
        GetSoundVolumeID    : CurCmdResult := GetSoundVolume (parm1);
        GetTableAddressID   : CurCmdResult := longint(GetTableAddress);
        ReadRamBlockID      : ReadRamBlock ( Ptr(parm1), parm2, parm3);
        SetSoundMIRQVID     : SetSoundMIRQV (parm1);
        SetSoundVolumeID    : SetSoundVolume (parm1, parm2);
        SetUserSoundIRQVID  : CurCmdResult := longint(SetUserSoundIRQV (ProcPtr(parm1)));
        WriteRamBlockID     : WriteRamBlock (Ptr(parm1), trunc(parm2), trunc(parm3));
        FFSetUpSoundID      :
            begin
                getSndBlk(sndBlk);
                FFSetUpSound (parm1, @sndBlk);
                CurCmdErr := _toolErr;
                setSndBlk(sndBlk);
            end;
        FFStartPlayingID    : FFStartPlaying (parm1);
        SetDOCRegID         :
            begin
                getDocBlk(docBlk);
                SetDOCReg (docBlk)  ;
                CurCmdErr := _toolErr;
                setDocBlk(docBlk);
            end;
        ReadDOCRegID        :
            begin
                getDocBlk(docBlk);
                ReadDOCReg (docBlk)  ;
                CurCmdErr := _toolErr;
                setDocBlk(docBlk);
            end;
    end;
    
    if CurCmdErr = 0 then CurCmdErr := _toolErr;

    if ctlHilite.parm[1] then setEditLong(Parm1, Parm1ID); { update the parameters }
    if ctlHilite.parm[2] then setEditLong(Parm2, Parm2ID);
    if ctlHilite.parm[3] then setEditLong(Parm3, Parm3ID);
    
    setResult;                  { update the result strings }
end;

{******************************************************************************
*
* editToStatic: Replaces a LineEdit control with a staticText control.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        getEditStr
}
procedure editToStatic(theCtlID : integer);

type 
    StaticTextTemplate = RECORD
        tpPCount    : integer;
        tpID        : longint;
        tpRect      : rect;
        tpProcRef   : longint;
        tpFlag      : integer;
        tpMoreFlags : integer;
        tpRefCon    : longint;
        tpTextRef   : longint;
        tpTextSize  : integer;
    end;

var 
    tempString  : String;
    theCtl      : CtlRecHndl;
    theTemplate : StaticTextTemplate;

begin
    getEditStr(tempString,theCtlID);
    parmArray[theCtlID] := tempString;
    theCtl := GetCtlHandleFromID(ourWindow, theCtlID);
    with theTemplate do
        begin
            tpPcount := 8;
            tpID := theCtlID;
            tpRect := theCtl^^.ctlRect;
            tpProcRef := $81000000;
            tpFlag := 0;
            tpMoreFlags := $1000;
            tpRefCon := 0;
            tpTextRef := longint(@parmArray[theCtlID]) + 1;
            tpTextSize := ord(parmArray[theCtlID][0]);
        end;
    DisposeControl(theCtl);
    theCtl := NewControl2(ourWindow, 0, Ref(@theTemplate));
end;

{******************************************************************************
*
* staticToEdit: Replaces a staticText control with a LineEdit control.
*
* Inputs:       theCtlID is the ID of the control to replace.
* Outputs:      NONE
* Calls:        NONE
}
procedure staticToEdit(theCtlID : integer);

Type 
    EditLineTemplate = RECORD
        tpPCount    : integer;
        tpID        : longint;
        tpRect      : rect;
        tpProcRef   : longint;
        tpFlag      : integer;
        tpMoreFlags : integer;
        tpRefCon    : longint;
        tpMaxSize   : integer;
        tpDefaultRef: longint;
    end;

var 
    theCtl      : CtlRecHndl;
    theTemplate : EditLineTemplate;

begin
    theCtl := GetCtlHandleFromID(ourWindow, theCtlID);
    with theTemplate do
        begin
            tpPcount := 8;
            tpID := theCtlID;
            tpRect := theCtl^^.ctlRect;
            tpProcRef := $83000000;
            tpFlag := 0;
            tpMoreFlags := $7000;
            tpRefCon := 0;
            tpMaxSize := 10;
            tpDefaultRef := longint(@parmArray[theCtlID]);
        end;
    DisposeControl(theCtl);
    theCtl := NewControl2(ourWindow, 0, Ref(@theTemplate));
end;

{******************************************************************************
*
* doHilite:     Dispatches to editToStatic or staticToEdit to toggle a 
*               control between a "hilited" and "unhilited" state.
*
* Inputs:       theCtlID is the ID of the control to replace.  hiliteVal
*               determines whether the control is hilited or not.
* Outputs:      NONE
* Calls:        editToStatic, staticToEdit
}
procedure doHilite(hiliteVal : integer; theCtlID : integer);

begin
    if hiliteVal = inactiveHilite then
        begin
            editToStatic(theCtlID);
        end
    else
        begin
            staticToEdit(theCtlID);
        end;
    MakeThisCtlTarget (GetCtlHandleFromID(ourwindow,oscGenTypeID));
    DrawOneCtl(GetCtlHandleFromID(ourWindow, theCtlID));
end;

{******************************************************************************
*
* hiliteSndBlk: Dispatches to doHilite to toggle the controls in the 
                Sound paramBlock between a "hilited" and "unhilited" state.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doHilite
}
procedure hiliteSndBlk;
    
var ctlID,
    hiliteVal: integer;

begin
    if ctlHilite.sndBlk then 
        begin
            hiliteVal := inactiveHilite;
            ctlHilite.sndBlk := FALSE;
        end
    else 
        begin
            hiliteVal := noHilite;
            ctlHilite.sndBlk := TRUE;
        end;
            
                        
    for ctlID := volSettingID downto waveStartID do
        doHilite(hiliteVal,ctlID);
end;

{******************************************************************************
*
* hiliteDocBlk: Dispatches to doHilite to toggle the controls in the 
*               DOC Register paramBlock between a "hilited" and 
*               "unhilited" state.
*
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doHilite
}
procedure hiliteDocBlk;
    
var ctlID,
    hiliteVal: integer;

begin
    if ctlHilite.docBlk then 
        begin
            hiliteVal := inactiveHilite;
            ctlHilite.docBlk := FALSE;
        end
    else 
        begin
            hiliteVal := noHilite;
            ctlHilite.docBlk := TRUE;
        end;
                        
    for ctlID := tableSize2ID downto oscGenTypeID do
        doHilite(hiliteVal,ctlID);
end;

{******************************************************************************
*
* hiliteParmX:  Dispatches to doHilite to toggle the controls for the 
*               parameters between a "hilited" and "unhilited" state.
*               It also is responsible for the naming of the parameters:
*               
*              -----------
*              |$00000000|  genNumFFSynth           for a hilited parm
*              -----------
*               
*               or
*
*               $00000000   Parm1                   for an unhilited parm
*                   ^         ^
*                   |         |____________________ the description
*                   |______________________________ the parameter itself
*               
* Inputs:       parmNum is the index to the controlID.  parmString describes 
*               the parameter.
* Outputs:      NONE
* Calls:        doHilite
}
procedure hiliteParmX(parmNum : integer; parmString : String);

var setString : String;
    hiliteVal: integer;

begin
    if ctlHilite.parm[parmNum] then 
        begin
            hiliteVal := inactiveHilite;
            setString := 'ParmX';
            setString[5] := chr(48 + parmNum);
            ctlHilite.parm[parmNum] := FALSE;
        end
    else 
        begin
            hiliteVal := noHilite;
            setString := parmString;
            ctlHilite.parm[parmNum] := TRUE;
        end;
        paramRec1.Str[5 + parmNum] := setString;
        DrawOneCtl(GetCtlHandleFromID(ourwindow, 223 + parmNum));
        doHilite(hiliteVal,320 + parmNum);
end;

{******************************************************************************
*
* doHiliteCtls: sets up the parameters for the call passed to it in cmdNum.
*               
* Inputs:       cmdNum is the call to set up for
* Outputs:      NONE
* Calls:        hiliteParmX, hiliteSndBlk, hiliteDocBlk
}
procedure doHiliteCtls(cmdNum : integer);

begin
    case cmdNum of
        SoundVersionID      :;
        SoundToolStatusID   :;
        FFGeneratorStatusID : hiliteParmX(1,'genNumber');
        FFSoundDoneStatusID : hiliteParmX(1,'genNumber');
        FFSoundStatusID     :;
        FFStartSoundID      :
            begin
                hiliteParmX(1,'genNumFFSynth');
                hiliteSndBlk;
            end;
        FFStopSoundID       : hiliteParmX(1,'genMask');
        GetSoundVolumeID    : hiliteParmX(1,'genNumber');
        GetTableAddressID   :;
        ReadRamBlockID      :
            begin
                hiliteParmX(3,'byteCount');
                hiliteParmX(2,'docStart');
                hiliteParmX(1,'destPtr');
            end;
        SetSoundMIRQVID     : hiliteParmX(1,'sMasterIRQ');
        SetSoundVolumeID    :
            begin
                hiliteParmX(2,'genNumber');
                hiliteParmX(1,'volume');
            end;
        SetUserSoundIRQVID  : hiliteParmX(1,'userIRQVector');
        WriteRamBlockID     :
            begin
                hiliteParmX(3,'byteCount');
                hiliteParmX(2,'docStart');
                hiliteParmX(1,'srcPtr');
            end;
        FFSetUpSoundID      :
            begin
                hiliteParmX(1,'channelGen');
                hiliteSndBlk;
            end;
        FFStartPlayingID    : hiliteParmX(1,'genWord');
        SetDocRegID         : hiliteDocBlk;
        ReadDOCRegID        : hiliteDocBlk;
    end;
end;

{******************************************************************************
*
* doSndCmdPopUp:    Updates the current command and calls the hilite routines
*                   to make the correct parameters available.
*               
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doHiliteCtls, setTargetCtl
}
procedure doSndCmdPopUp;                { update the Current Command }

var 
    theCtl : CtlRecHndl;
    theCmd : integer;

begin
    theCtl := GetCtlHandleFromID(ourwindow,sndCmdPopUp);
    theCmd := theCtl^^.ctlValue;
    doHiliteCtls(CurCmdNum);        { unhilite the controls for the previous command }
    doHiliteCtls(theCmd);           { hilite the controls for the current command }
    setTargetCtl;                   { Make the caret blink in the first available Ctl }
    CurCmdNum := theCmd;            { update the global variable }
end;

{******************************************************************************
*
* doInControl:  dispatches to the correct routine depending on the control 
*               that was activated.
*               
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doExecute, doLoadFile, doSndCmdPopUp
}
procedure doInControl;

var
    theID       : Integer;

begin
    theID := myEvent.wmTaskData4;               { what control ?}
                              
    case theID of
        execbut:        doExecute;              { execute the current command }
        loadbut:        doLoadFile;             { load a file }
        sndCmdPopUp:    doSndCmdPopUp;          { handle the pop-up result }
    end;
end;

{******************************************************************************
*
* InitSoundEx:  Initializes all of the global variables.
*               
* Inputs:       NONE
* Outputs:      NONE
* Calls:        doExecute, doLoadFile, doSndCmdPopUp
}
procedure InitSoundEx;

var x : integer;

begin
    for x := 0 to 9 do          { zero out the paramText Strings }
            begin
                paramRec1.StrPtr[x] := @paramRec1.Str[x];
                paramRec1.Str[x] := '';
            end;
            
    paramRec1.Str[0] := 'SoundVersion';     { set them how we want them }
    paramRec1.Str[1] := 'none';
    paramRec1.Str[2] := '00000000';
    paramRec1.Str[3] := '0000';
    paramRec1.Str[4] := '00000000';
    paramRec1.Str[5] := '0000';
    
    ctlHilite.docBlk := TRUE;               { set up the default hilites for ctls }
    ctlHilite.sndBlk := TRUE;
    for x := 1 to 3 do ctlHilite.parm[x] := TRUE;
    
    SetCtlParamPtr ( @paramRec1)  ;         { now we can set the paramText }
    
    CurCmdNum := SoundVersionID;            { the current command is SoundVersionID } 
    BuffHndl := NIL;                        { no buffer yet }
end;