TS3TestLoLevel.c

/*
 *  File:       TS3TestLoLevel.c
 *
 *  Copyright © 1996 Apple Computer, Inc.
 */
 
#include <assert.h>
#include <math.h>
#include <string.h>
 
#include <Dialogs.h>
#include <Fonts.h>
#include <Menus.h>
#include <Timer.h>
#include <fp.h>
 
#include "TS3Menu.h"
#include "TS3Message.h"
#include "TS3Resource.h"
#include "TS3Sound.h"
#include "TS3TestLoLevel.h"
#include "TS3Utils.h"
#include "TS3Window.h"
 
#include "SoundSprocket.h"
 
 
typedef struct TTestLoLevelData {
    float           duration;
    
    UInt32          cpuLoad1;
    UInt32          cpuLoad2;
    Boolean         cpuLoadRange;
    
    UInt32          medium;
    
    float           humidity1;
    float           humidity2;
    Boolean         humidityRange;
    
    float           roomSize1;
    float           roomSize2;
    Boolean         roomSizeRange;
    
    float           roomReflectivity1;
    float           roomReflectivity2;
    Boolean         roomReflectivityRange;
    
    float           reverbAttenuation1;
    float           reverbAttenuation2;
    Boolean         reverbAttenuationRange;
    
    UInt32          sourceMode;
    
    float           referenceDistance1;
    float           referenceDistance2;
    Boolean         referenceDistanceRange;
    
    float           coneAngleDeg1;
    float           coneAngleDeg2;
    Boolean         coneAngleDegRange;
    
    float           coneAttenuation1;
    float           coneAttenuation2;
    Boolean         coneAttenuationRange;
    
    float           elevationDeg1;
    float           elevationDeg2;
    Boolean         elevationDegRange;
    
    float           azimuthDeg1;
    float           azimuthDeg2;
    Boolean         azimuthDegRange;
    
    float           distance1;
    float           distance2;
    Boolean         distanceRange;
    
    float           projectionAngleDeg1;
    float           projectionAngleDeg2;
    Boolean         projectionAngleDegRange;
    
    float           sourceVelocity1;
    float           sourceVelocity2;
    Boolean         sourceVelocityRange;
    
    float           listenerVelocity1;
    float           listenerVelocity2;
    Boolean         listenerVelocityRange;
    
    float           coneAngleCos1;
    float           coneAngleCos2;
    
    float           elevation1;
    float           elevation2;
    
    float           azimuth1;
    float           azimuth2;
    
    float           projectionAngle1;
    float           projectionAngle2;
} TTestLoLevelData;
 
 
static MenuHandle               gTestLoLevelPresetMenu          = NULL;
static DialogPtr                gTestLoLevelDialog              = NULL;
static UserItemUPP              gTestLoLevelProgressUserItem    = NULL;
static UInt32                   gTestLoLevelCPULoadLimit;
static TTestLoLevelData         gTestLoLevelData;
 
static UnsignedWide             gTestLoLevelCycleStart;
static float                    gTestLoLevelInterpolant         = 0.0;
 
 
static WindowMethodPtr TestLoLevel_MetaHandler(
    WindowMethod        inMethod);
 
static void TestLoLevel_GetSleep(
    WindowPtr           inWindow,
    UInt32*             outSleep);
 
static void TestLoLevel_ConsumeEvent(
    WindowPtr           inWindow,
    const EventRecord*  inEvent,
    Boolean*            outConsumed);
 
static void TestLoLevel_Update(
    WindowPtr           inWindow);
 
static void TestLoLevel_Activate(
    WindowPtr           inWindow);
 
static void TestLoLevel_Deactivate(
    WindowPtr           inWindow);
 
static pascal void TestLoLevel_ProgressUserItem(
    DialogPtr           inDialog,
    short               inItem);
 
static void TestLoLevel_Interpolate(
    void);
 
static float TestLoLevel_DoInterpolate(
    float               inWhere,
    float               inVal0,
    float               inVal1,
    Boolean             inIsRange);
 
static void TestLoLevel_DeriveData(
    void);
 
static void TestLoLevel_SetDialogFields(
    void);
 
static void TestLoLevel_GetDialogFields(
    void);
 
 
/* =============================================================================
 *      TestLoLevel_Init (external)
 *
 *  Initializes our thing.
 * ========================================================================== */
void TestLoLevel_Init(
    void)
{
    OSStatus            err;
    TEHandle            textEdit;
    FontInfo            fontInfo;
    short               itemType;
    Handle              itemHandle;
    Rect                itemBounds;
    Str255              str;
    short               fNum;
    
    // Make sure we didn't mess up the dialog items
    assert(kLoLevelItem_COUNT == kLoLevelItem_ExpectedCOUNT);
    
    // Grab the maximum CPU load limit value
    gTestLoLevelCPULoadLimit = 999;
    err = SSpGetCPULoadLimit(&gTestLoLevelCPULoadLimit);
    Message_CheckError(err, "TestLoLevel_Init", "SSpGetCPULoadLimit");
    
    //¥ TODO: Read in gTestLoLevelData from preferences
    
    // Grab the menu
    gTestLoLevelPresetMenu = GetMenu(kMenuID_LoLevelPreset);
    
    // Grab the dialog
    gTestLoLevelDialog = GetNewDialog(kDlogID_LoLevel, NULL, (WindowPtr) -1);
    assert(gTestLoLevelDialog != NULL);
    
    SetPort(gTestLoLevelDialog);
    GetFNum("\pGeneva", &fNum);
    TextFont(fNum);
    TextSize(10);
    
    // Fix up the line height
    GetFontInfo(&fontInfo);
    
    textEdit = ((DialogPeek) gTestLoLevelDialog)->textH;
    
    (*textEdit)->lineHeight = fontInfo.ascent+fontInfo.descent+fontInfo.leading;
    (*textEdit)->fontAscent = fontInfo.ascent;
    
    // Set up our method table
    Window_New(gTestLoLevelDialog, TestLoLevel_MetaHandler);
    
    // Do the user items
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_UpdateHilite, &itemType, &itemHandle, &itemBounds);
    SetDialogItem(gTestLoLevelDialog, kLoLevelItem_UpdateHilite, itemType, (Handle) Utils_GetOKUserItemProc(), &itemBounds);
    
    gTestLoLevelProgressUserItem = NewUserItemProc(TestLoLevel_ProgressUserItem);
    assert(gTestLoLevelProgressUserItem != NULL);
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_Progress, &itemType, &itemHandle, &itemBounds);
    SetDialogItem(gTestLoLevelDialog, kLoLevelItem_Progress, itemType, (Handle) gTestLoLevelProgressUserItem, &itemBounds);
    
    // Show the quality limit
    sprintf((char*) str, "x[0..%ld]", gTestLoLevelCPULoadLimit);
    str[0] = strlen((char*) str)-1;
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_CPULoadUnits, &itemType, &itemHandle, &itemBounds);
    SetDialogItemText(itemHandle, str);
    
    // Set the initial field values
    TestLoLevel_Preset(1);
    
    // Select the first field
    SelectDialogItemText(gTestLoLevelDialog, kLoLevelItem_Duration, 0, 32767);
    
    // Show the dialog
    ShowWindow(gTestLoLevelDialog);
    
    // Initialize our cycle timer
    Microseconds(&gTestLoLevelCycleStart);
}
 
 
/* =============================================================================
 *      TestLoLevel_Exit (external)
 *
 *  Cleans up.
 * ========================================================================== */
void TestLoLevel_Exit(
    void)
{
    //¥ TODO: Save gTestLoLevel to preferences
    
    if (gTestLoLevelDialog != NULL)
    {
        DisposeDialog(gTestLoLevelDialog);
        gTestLoLevelDialog = NULL;
    }
    
    if (gTestLoLevelProgressUserItem != NULL)
    {
        DisposeRoutineDescriptor(gTestLoLevelProgressUserItem);
        gTestLoLevelProgressUserItem = NULL;
    }
}
 
 
/* =============================================================================
 *      TestLoLevel_MetaHandler (internal)
 *
 *  Returns the method function pointer that corresponds to the given ID.
 * ========================================================================== */
WindowMethodPtr TestLoLevel_MetaHandler(
    WindowMethod        inMethod)
{
    WindowMethodPtr     result;
    
    result = NULL;
    
    switch (inMethod)
    {
        case kWindowMethod_GetSleep:
            result = (WindowMethodPtr) TestLoLevel_GetSleep;
        break;
        
        case kWindowMethod_ConsumeEvent:
            result = (WindowMethodPtr) TestLoLevel_ConsumeEvent;
        break;
        
        case kWindowMethod_Update:
            result = (WindowMethodPtr) TestLoLevel_Update;
        break;
        
        case kWindowMethod_Activate:
            result = (WindowMethodPtr) TestLoLevel_Activate;
        break;
        
        case kWindowMethod_Deactivate:
            result = (WindowMethodPtr) TestLoLevel_Deactivate;
        break;
    }
    
    return result;
}
 
 
/* =============================================================================
 *      TestLoLevel_GetSleep (internal)
 *
 *  Returns the sleep time to pass to WaitNextEvent when we're in front.
 * ========================================================================== */
void TestLoLevel_GetSleep(
    WindowPtr           inWindow,
    UInt32*             outSleep)
{
    #pragma unused (inWindow)
    assert(outSleep != NULL);
    
    *outSleep = 0;
}
 
 
/* =============================================================================
 *      TestLoLevel_ConsumeEvent (internal)
 *
 *  Called for each event when this is the front window.
 * ========================================================================== */
void TestLoLevel_ConsumeEvent(
    WindowPtr           inWindow,
    const EventRecord*  inEvent,
    Boolean*            outConsumed)
{
    #pragma unused (inWindow)
    short               itemType;
    Handle              itemHandle;
    Rect                itemBounds;
    ControlHandle       updateButton;
    Boolean             consumed;
    Boolean             passToDialog;
    WindowPtr           window;
    short               item;
    unsigned long       timeout;
    UnsignedWide        now;
    
    assert(inEvent != NULL);
    assert(outConsumed != NULL);
    
    consumed = false;
    passToDialog = true;
    
    // We want to handle some events ourself
    switch (inEvent->what)
    {
        case keyDown:
        case autoKey:
            passToDialog = false;
            
            if (inEvent->modifiers & cmdKey)
            {
                if (inEvent->what != autoKey)
                {
                    switch (inEvent->message & charCodeMask)
                    {
                        case '.':
                            // anything here?
                        break;
                    }
                }
            }
            else
            {
                switch (inEvent->message & charCodeMask)
                {
                    case 0x08:  // backspace
                    case 0x09:  // tab
                    case 0x1C:  // cursor left
                    case 0x1D:  // cursor right
                    case 0x1E:  // cursor up
                    case 0x1F:  // cursor down
                    case '.':
                    case '-':
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        // Pass it to the dialog
                        passToDialog = true;
                    break;
                    
                    case 0x03:  // enter
                    case 0x0D:  // return
                        if (inEvent->what != autoKey)
                        {
                            // Update button equivalent
                            GetDialogItem(gTestLoLevelDialog, kLoLevelItem_Update, &itemType, &itemHandle, &itemBounds);
                            updateButton = (ControlHandle) itemHandle;
                            
                            if ((*updateButton)->contrlHilite == 0)
                            {
                                HiliteControl(updateButton, 1);
                                
                                timeout = TickCount()+6;
                                while (TickCount() < timeout) /* wait */;
                                
                                HiliteControl(updateButton, 0);
                                
                                TestLoLevel_GetDialogFields();
                                
                                consumed = true;
                            }
                        }
                    break;
                    
                    default:
                        SysBeep(10);
                        consumed = true;
                }
            }
        break;
        
        case activateEvt:
            // We need to look at the activate event here because it is
            // consumed by IsDialogEvent/DialogSelect below and so never
            // gets to the window stuff
            window = (WindowPtr) inEvent->message;
            
            if (inEvent->modifiers & activeFlag)
            {
                Window_Activate(window);
            }
            else
            {
                Window_Deactivate(window);
            }
        break;
        
        case nullEvent:
            // Find where we are in the cycle (0 is start, 1 is end)
            Microseconds(&now);
            gTestLoLevelInterpolant = Utils_Interval(&gTestLoLevelCycleStart, &now) / gTestLoLevelData.duration;
            
            switch (Menu_GetInterpolation())
            {
                case kInterpolationItem_Sinusoidal:
                    gTestLoLevelInterpolant = 0.5*sinf(gTestLoLevelInterpolant*pi*2.0) + 0.5;
                break;
                
                case kInterpolationItem_Triangular:
                    gTestLoLevelInterpolant = 2.0*fmodf(gTestLoLevelInterpolant, 1.0);
                    
                    if (gTestLoLevelInterpolant > 1.0)
                    {
                        gTestLoLevelInterpolant = 2.0-gTestLoLevelInterpolant;
                    }
                break;
                
                case kInterpolationItem_Sawtooth:
                    gTestLoLevelInterpolant = fmodf(2.0*gTestLoLevelInterpolant, 1.0);
                break;
            }
            
            TestLoLevel_Interpolate();
        break;
    }
    
    // Do dialog stuff
    if (passToDialog)
    {
        consumed = IsDialogEvent(inEvent);
        if (consumed)
        {
            if (DialogSelect(inEvent, &window, &item))
            {
                switch (item)
                {
                    case kLoLevelItem_Update:
                        TestLoLevel_GetDialogFields();
                    break;
                }
            }
        }
    }
    
    // Return the result
    *outConsumed = consumed;
}
 
 
/* =============================================================================
 *      TestLoLevel_Update (internal)
 *
 *  Updates the contents of the window.
 * ========================================================================== */
void TestLoLevel_Update(
    WindowPtr           inWindow)
{
    DrawDialog(inWindow);
}
 
 
/* =============================================================================
 *      TestLoLevel_Activate (internal)
 *
 *  Handles window activation.
 * ========================================================================== */
void TestLoLevel_Activate(
    WindowPtr           inWindow)
{
    #pragma unused (inWindow)
    InsertMenu(gTestLoLevelPresetMenu, 0);
    DrawMenuBar();
}
 
 
/* =============================================================================
 *      TestLoLevel_Deactivate (internal)
 *
 *  Handles window deactivation.
 * ========================================================================== */
void TestLoLevel_Deactivate(
    WindowPtr           inWindow)
{
    #pragma unused (inWindow)
    DeleteMenu(kMenuID_LoLevelPreset);
    DrawMenuBar();
}
 
 
/* =============================================================================
 *      TestLoLevel_ProgressUserItem (internal)
 *
 *  Draws the user item used for progress bar, based on gTestLoLevelInterpolant.
 * ========================================================================== */
pascal void TestLoLevel_ProgressUserItem(
    DialogPtr           inDialog,
    short               inItem)
{
    short               itemType;
    Handle              itemHandle;
    Rect                itemBounds;
    short               size;
    Rect                leftWhite;
    Rect                rightWhite;
    Rect                indicator;
    
    GetDialogItem(inDialog, inItem, &itemType, &itemHandle, &itemBounds);
    
    FrameRect(&itemBounds);
    
    InsetRect(&itemBounds, 1, 1);
    size = itemBounds.bottom-itemBounds.top;
    
    indicator = itemBounds;
    indicator.left = itemBounds.left + (long) (gTestLoLevelInterpolant*(itemBounds.right-itemBounds.left-size) + 0.5);
    indicator.right = indicator.left+size;
    
    leftWhite = itemBounds;
    leftWhite.right = indicator.left;
    
    rightWhite = itemBounds;
    rightWhite.left = indicator.right;
    
    FrameRect(&indicator);
    
    InsetRect(&indicator, 1, 1);
    FillRect(&indicator, &qd.gray);
    
    EraseRect(&leftWhite);
    EraseRect(&rightWhite);
}
 
 
/* =============================================================================
 *      TestLoLevel_Interpolate (internal)
 *
 *  Changes the sound channel to the correct values for the point between
 *  zero and one determined by gTestLoLevelInterpolant.
 * ========================================================================== */
void TestLoLevel_Interpolate(
    void)
{
    SSpLocalizationData         snd3DInfo;
    float                       elevation;
    float                       azimuth;
    
    snd3DInfo.cpuLoad = (UInt32) (TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            (float) gTestLoLevelData.cpuLoad1,
            (float) gTestLoLevelData.cpuLoad2,
            gTestLoLevelData.cpuLoadRange) + 0.5);
    
    snd3DInfo.medium = gTestLoLevelData.medium;
    
    snd3DInfo.humidity = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.humidity1,
            gTestLoLevelData.humidity2,
            gTestLoLevelData.humidityRange);
    
    snd3DInfo.roomSize = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.roomSize1,
            gTestLoLevelData.roomSize2,
            gTestLoLevelData.roomSizeRange);
    
    snd3DInfo.roomReflectivity = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.roomReflectivity1,
            gTestLoLevelData.roomReflectivity2,
            gTestLoLevelData.roomReflectivityRange);
    
    snd3DInfo.reverbAttenuation = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.reverbAttenuation1,
            gTestLoLevelData.reverbAttenuation2,
            gTestLoLevelData.reverbAttenuationRange);
    
    snd3DInfo.sourceMode = gTestLoLevelData.sourceMode;
    
    snd3DInfo.referenceDistance = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.referenceDistance1,
            gTestLoLevelData.referenceDistance2,
            gTestLoLevelData.referenceDistanceRange);
    
    snd3DInfo.coneAngleCos = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.coneAngleCos1,
            gTestLoLevelData.coneAngleCos2,
            gTestLoLevelData.coneAngleDegRange);
    
    snd3DInfo.coneAttenuation = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.coneAttenuation1,
            gTestLoLevelData.coneAttenuation2,
            gTestLoLevelData.coneAttenuationRange);
    
    // Wrap the azimuth and elevation to fit in their ranges
    elevation = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.elevation1,
            gTestLoLevelData.elevation2,
            gTestLoLevelData.elevationDegRange);
    
    azimuth = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.azimuth1,
            gTestLoLevelData.azimuth2,
            gTestLoLevelData.azimuthDegRange);
    
    // find azimuth in the range -2¹..2¹
    azimuth = fmodf(azimuth, 2.0*pi);
    
    // find azimuth in the range -¹..¹
    if (azimuth < -pi)
    {
        azimuth += 2.0*pi;
    }
    else if (azimuth > pi)
    {
        azimuth -= 2.0*pi;
    }
    
    // find azimuth in the range -¹/2..¹/2
    if (azimuth < -0.5*pi)
    {
        azimuth = -pi-azimuth;
        elevation -= pi;
    }
    else if (azimuth > 0.5*pi)
    {
        azimuth = pi-azimuth;
        elevation -= pi;
    }
    
    // find elevation in the range -2¹..2¹
    elevation = fmodf(elevation, 2.0*pi);
    
    // find elevation in the range -¹..¹
    if (elevation < -pi)
    {
        elevation += 2.0*pi;
    }
    else if (elevation > pi)
    {
        elevation -= 2.0*pi;
    }
    
    snd3DInfo.currentLocation.elevation = elevation;
    snd3DInfo.currentLocation.azimuth = azimuth;
    
    snd3DInfo.currentLocation.distance = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.distance1,
            gTestLoLevelData.distance2,
            gTestLoLevelData.distanceRange);
    
    snd3DInfo.currentLocation.projectionAngle = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.projectionAngle1,
            gTestLoLevelData.projectionAngle2,
            gTestLoLevelData.projectionAngleDegRange);
    
    snd3DInfo.currentLocation.sourceVelocity = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.sourceVelocity1,
            gTestLoLevelData.sourceVelocity2,
            gTestLoLevelData.sourceVelocityRange);
    
    snd3DInfo.currentLocation.listenerVelocity = TestLoLevel_DoInterpolate(
            gTestLoLevelInterpolant,
            gTestLoLevelData.listenerVelocity1,
            gTestLoLevelData.listenerVelocity2,
            gTestLoLevelData.listenerVelocityRange);
    
    snd3DInfo.reserved0 = 0;
    snd3DInfo.reserved1 = 0;
    snd3DInfo.reserved2 = 0;
    snd3DInfo.reserved3 = 0;
    
    snd3DInfo.virtualSourceCount = 0;
    
    // Make the filter changes
    Sound_Set3DInfo(&snd3DInfo);
    
    // Update the progress bar
    SetPort(gTestLoLevelDialog);
    TestLoLevel_ProgressUserItem(gTestLoLevelDialog, kLoLevelItem_Progress);
}
 
 
/* =============================================================================
 *      TestLoLevel_DoInterpolate (internal)
 *
 *  Linear interpolation.  When inWhere is zero, inVal0 is returned.  When it
 *  is one, inVal1 is returned.  In between is linear.  If inIsRange is false
 *  then we ignore inVal1 and always return inVal0.
 * ========================================================================== */
float TestLoLevel_DoInterpolate(
    float               inWhere,
    float               inVal0,
    float               inVal1,
    Boolean             inIsRange)
{
    float               result;
    
    if (inIsRange)
    {
        result = inWhere*(inVal1-inVal0) + inVal0;
    }
    else
    {
        result = inVal0;
    }
    
    return result;
}
 
 
/* =============================================================================
 *      TestLoLevel_DeriveData (internal)
 *
 *  Compute the derived fields in gTestLoLevelData.
 * ========================================================================== */
void TestLoLevel_DeriveData(
    void)
{
    gTestLoLevelData.coneAngleCos1          = cosf(0.5*(pi/180.0)*gTestLoLevelData.coneAngleDeg1);
    gTestLoLevelData.coneAngleCos2          = cosf(0.5*(pi/180.0)*gTestLoLevelData.coneAngleDeg2);
    
    gTestLoLevelData.elevation1             = (pi/180.0)*gTestLoLevelData.elevationDeg1;
    gTestLoLevelData.elevation2             = (pi/180.0)*gTestLoLevelData.elevationDeg2;
    
    gTestLoLevelData.azimuth1               = (pi/180.0)*gTestLoLevelData.azimuthDeg1;
    gTestLoLevelData.azimuth2               = (pi/180.0)*gTestLoLevelData.azimuthDeg2;
    
    gTestLoLevelData.projectionAngle1       = cosf((pi/180.0)*gTestLoLevelData.projectionAngleDeg1);
    gTestLoLevelData.projectionAngle2       = cosf((pi/180.0)*gTestLoLevelData.projectionAngleDeg2);
}
 
 
/* =============================================================================
 *      TestLoLevel_SetDialogFields (internal)
 *
 *  Changes the dialog's fields to reflect gTestLoLevelData.
 * ========================================================================== */
void TestLoLevel_SetDialogFields(
    void)
{
    short               itemType;
    Handle              itemHandle;
    Rect                itemBounds;
    short               value;
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Duration,
            gTestLoLevelData.duration,
            true);
    
    Utils_SetUInt32Field(
            gTestLoLevelDialog,
            kLoLevelItem_CPULoad1,
            gTestLoLevelData.cpuLoad1,
            true);
    
    Utils_SetUInt32Field(
            gTestLoLevelDialog,
            kLoLevelItem_CPULoad2,
            gTestLoLevelData.cpuLoad2,
            gTestLoLevelData.cpuLoadRange);
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_Medium, &itemType, &itemHandle, &itemBounds);
    SetControlValue((ControlHandle) itemHandle,
            (gTestLoLevelData.medium == kSSpMedium_Water)
                    ? kMediumItem_Water
                    : kMediumItem_Air);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Humidity1,
            gTestLoLevelData.humidity1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Humidity2,
            gTestLoLevelData.humidity2,
            gTestLoLevelData.humidityRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomSize1,
            gTestLoLevelData.roomSize1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomSize2,
            gTestLoLevelData.roomSize2,
            gTestLoLevelData.roomSizeRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomReflectivity1,
            gTestLoLevelData.roomReflectivity1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomReflectivity2,
            gTestLoLevelData.roomReflectivity2,
            gTestLoLevelData.roomReflectivityRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReverbAttenuation1,
            gTestLoLevelData.reverbAttenuation1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReverbAttenuation2,
            gTestLoLevelData.reverbAttenuation2,
            gTestLoLevelData.reverbAttenuationRange);
    
    value = kSourceModeItem_Unfiltered;
    switch (gTestLoLevelData.sourceMode)
    {
        case kSSpSourceMode_Localized:
            value = kSourceModeItem_Localized;
        break;
        
        case kSSpSourceMode_Ambient:
            value = kSourceModeItem_Ambient;
        break;
        
        case kSSpSourceMode_Binaural:
            value = kSourceModeItem_Binaural;
        break;
    }
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_SourceMode, &itemType, &itemHandle, &itemBounds);
    SetControlValue((ControlHandle) itemHandle, value);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReferenceDistance1,
            gTestLoLevelData.referenceDistance1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReferenceDistance2,
            gTestLoLevelData.referenceDistance2,
            gTestLoLevelData.referenceDistanceRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAngleDeg1,
            gTestLoLevelData.coneAngleDeg1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAngleDeg2,
            gTestLoLevelData.coneAngleDeg2,
            gTestLoLevelData.coneAngleDegRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAttenuation1,
            gTestLoLevelData.coneAttenuation1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAttenuation2,
            gTestLoLevelData.coneAttenuation2,
            gTestLoLevelData.coneAttenuationRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ElevationDeg1,
            gTestLoLevelData.elevationDeg1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ElevationDeg2,
            gTestLoLevelData.elevationDeg2,
            gTestLoLevelData.elevationDegRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_AzimuthDeg1,
            gTestLoLevelData.azimuthDeg1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_AzimuthDeg2,
            gTestLoLevelData.azimuthDeg2,
            gTestLoLevelData.azimuthDegRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Distance1,
            gTestLoLevelData.distance1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Distance2,
            gTestLoLevelData.distance2,
            gTestLoLevelData.distanceRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ProjectionAngleDeg1,
            gTestLoLevelData.projectionAngleDeg1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ProjectionAngleDeg2,
            gTestLoLevelData.projectionAngleDeg2,
            gTestLoLevelData.projectionAngleDegRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_SourceVelocity1,
            gTestLoLevelData.sourceVelocity1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_SourceVelocity2,
            gTestLoLevelData.sourceVelocity2,
            gTestLoLevelData.sourceVelocityRange);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ListenerVelocity1,
            gTestLoLevelData.listenerVelocity1,
            true);
    
    Utils_SetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ListenerVelocity2,
            gTestLoLevelData.listenerVelocity2,
            gTestLoLevelData.listenerVelocityRange);
}
 
 
/* =============================================================================
 *      TestLoLevel_GetDialogFields (internal)
 *
 *  Grabs the contents of the dialog fields and puts them into gTestLoLevelData.
 * ========================================================================== */
void TestLoLevel_GetDialogFields(
    void)
{
    const float         small = 0.000001;
    const float         big = 10000000.0;
    short               itemType;
    Handle              itemHandle;
    Rect                itemBounds;
    TTestLoLevelData    data;
    short               badItem;
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Duration,
            &data.duration,
            NULL,
            small,
            big))
    {
        badItem = kLoLevelItem_Duration;
        goto bail;
    }
    
    if (!Utils_GetUInt32Field(
            gTestLoLevelDialog,
            kLoLevelItem_CPULoad1,
            &data.cpuLoad1,
            NULL,
            0,
            gTestLoLevelCPULoadLimit))
    {
        badItem = kLoLevelItem_CPULoad1;
        goto bail;
    }
    
    if (!Utils_GetUInt32Field(
            gTestLoLevelDialog,
            kLoLevelItem_CPULoad2,
            &data.cpuLoad2,
            &data.cpuLoadRange,
            0,
            gTestLoLevelCPULoadLimit))
    {
        badItem = kLoLevelItem_CPULoad2;
        goto bail;
    }
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_Medium, &itemType, &itemHandle, &itemBounds);
    switch (GetControlValue((ControlHandle) itemHandle))
    {
        case kMediumItem_Air:
            data.medium = kSSpMedium_Air;
        break;
        
        case kMediumItem_Water:
            data.medium = kSSpMedium_Water;
        break;
        
        default:
            assert(0);
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Humidity1,
            &data.humidity1,
            NULL,
            0.0,
            100.0))
    {
        badItem = kLoLevelItem_Humidity1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Humidity2,
            &data.humidity2,
            &data.humidityRange,
            0.0,
            100.0))
    {
        badItem = kLoLevelItem_Humidity2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomSize1,
            &data.roomSize1,
            NULL,
            0.0,
            big))
    {
        badItem = kLoLevelItem_RoomSize1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomSize2,
            &data.roomSize2,
            &data.roomSizeRange,
            0.0,
            big))
    {
        badItem = kLoLevelItem_RoomSize2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomReflectivity1,
            &data.roomReflectivity1,
            NULL,
            -big,
            -small))
    {
        badItem = kLoLevelItem_RoomReflectivity1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_RoomReflectivity2,
            &data.roomReflectivity2,
            &data.roomReflectivityRange,
            -big,
            -small))
    {
        badItem = kLoLevelItem_RoomReflectivity2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReverbAttenuation1,
            &data.reverbAttenuation1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_ReverbAttenuation1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReverbAttenuation2,
            &data.reverbAttenuation2,
            &data.reverbAttenuationRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_ReverbAttenuation2;
        goto bail;
    }
    
    GetDialogItem(gTestLoLevelDialog, kLoLevelItem_SourceMode, &itemType, &itemHandle, &itemBounds);
    switch (GetControlValue((ControlHandle) itemHandle))
    {
        case kSourceModeItem_Unfiltered:
            data.sourceMode = kSSpSourceMode_Unfiltered;
        break;
        
        case kSourceModeItem_Localized:
            data.sourceMode = kSSpSourceMode_Localized;
        break;
        
        case kSourceModeItem_Ambient:
            data.sourceMode = kSSpSourceMode_Ambient;
        break;
        
        case kSourceModeItem_Binaural:
            data.sourceMode = kSSpSourceMode_Binaural;
        break;
        
        default:
            assert(0);
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReferenceDistance1,
            &data.referenceDistance1,
            NULL,
            small,
            big))
    {
        badItem = kLoLevelItem_ReferenceDistance1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ReferenceDistance2,
            &data.referenceDistance2,
            &data.referenceDistanceRange,
            small,
            big))
    {
        badItem = kLoLevelItem_ReferenceDistance2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAngleDeg1,
            &data.coneAngleDeg1,
            NULL,
            0.0,
            360.0))
    {
        badItem = kLoLevelItem_ConeAngleDeg1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAngleDeg2,
            &data.coneAngleDeg2,
            &data.coneAngleDegRange,
            0.0,
            360.0))
    {
        badItem = kLoLevelItem_ConeAngleDeg2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAttenuation1,
            &data.coneAttenuation1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_ConeAttenuation1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ConeAttenuation2,
            &data.coneAttenuation2,
            &data.coneAttenuationRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_ConeAttenuation2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ElevationDeg1,
            &data.elevationDeg1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_ElevationDeg1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ElevationDeg2,
            &data.elevationDeg2,
            &data.elevationDegRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_ElevationDeg2;
        goto bail;
    }
    
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_AzimuthDeg1,
            &data.azimuthDeg1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_AzimuthDeg1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_AzimuthDeg2,
            &data.azimuthDeg2,
            &data.azimuthDegRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_AzimuthDeg2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Distance1,
            &data.distance1,
            NULL,
            small,
            big))
    {
        badItem = kLoLevelItem_Distance1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_Distance2,
            &data.distance2,
            &data.distanceRange,
            small,
            big))
    {
        badItem = kLoLevelItem_Distance2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ProjectionAngleDeg1,
            &data.projectionAngleDeg1,
            NULL,
            0.0,
            180.0))
    {
        badItem = kLoLevelItem_ProjectionAngleDeg1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ProjectionAngleDeg2,
            &data.projectionAngleDeg2,
            &data.projectionAngleDegRange,
            0.0,
            180.0))
    {
        badItem = kLoLevelItem_ProjectionAngleDeg2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_SourceVelocity1,
            &data.sourceVelocity1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_SourceVelocity1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_SourceVelocity2,
            &data.sourceVelocity2,
            &data.sourceVelocityRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_SourceVelocity2;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ListenerVelocity1,
            &data.listenerVelocity1,
            NULL,
            -big,
            big))
    {
        badItem = kLoLevelItem_ListenerVelocity1;
        goto bail;
    }
    
    if (!Utils_GetFloatField(
            gTestLoLevelDialog,
            kLoLevelItem_ListenerVelocity2,
            &data.listenerVelocity2,
            &data.listenerVelocityRange,
            -big,
            big))
    {
        badItem = kLoLevelItem_ListenerVelocity2;
        goto bail;
    }
    
    // All fields are good -- finish up
    gTestLoLevelData = data;
    TestLoLevel_DeriveData();
    
    TestLoLevel_SetDialogFields();
    
    return;
    
    // Error exit
bail:
    SelectDialogItemText(gTestLoLevelDialog, badItem, 0, 32767);
    StopAlert(kAlrtID_BadField, NULL);
}
 
 
/* =============================================================================
 *      TestLoLevel_Preset (external)
 *
 *  Updates the fields to the chosen preset value.
 * ========================================================================== */
void TestLoLevel_Preset(
    UInt32          index)
{
    TTestLoLevelData preset[] = {
        { /* nothing for index zero */ 0 },
        { /* Side-to-Side */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */ -90.0,  90.0, true,
                /* distance             */   1.0,   0.0, false,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* dividing line */ 0 },
        { /* Ahead */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Ahead-Right */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */  45.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Right */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */  90.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Behind-Right */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */ 180.0,   0.0, false,
                /* azimuthDeg           */  45.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Behind */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */ 180.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Behind-Left */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */ 180.0,   0.0, false,
                /* azimuthDeg           */ -45.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Left */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */ -90.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Ahead-Left */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */ -45.0,   0.0, false,
                /* distance             */   1.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* dividing line */ 0 },
        { /* Around (1 meter) */
                /* duration             */    4.0,
                /* cpuLoad              */      0,     0, false,
                /* medium               */  kSSpMedium_Air,
                /* humidity             */    0.0,   0.0, false,
                /* roomSize             */    0.0,   0.0, false,
                /* roomReflectivity     */  -10.0,   0.0, false,
                /* reverbAttenuation    */  -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */    1.0,   0.0, false,
                /* coneAngleDeg         */   90.0,   0.0, false,
                /* coneAttenuation      */    0.0,   0.0, false,
                /* elevationDeg         */    0.0,   0.0, false,
                /* azimuthDeg           */ -180.0, 180.0, true,
                /* distance             */    1.0,   0.0, false,
                /* projectionAngleDeg   */    0.0,   0.0, false,
                /* sourceVelocity       */    0.0,   0.0, false,
                /* listenerVelocity     */    0.0,   0.0, false
        },
        { /* Around (10 meters) */
                /* duration             */    4.0,
                /* cpuLoad              */      0,     0, false,
                /* medium               */  kSSpMedium_Air,
                /* humidity             */    0.0,   0.0, false,
                /* roomSize             */    0.0,   0.0, false,
                /* roomReflectivity     */  -10.0,   0.0, false,
                /* reverbAttenuation    */  -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */    1.0,   0.0, false,
                /* coneAngleDeg         */   90.0,   0.0, false,
                /* coneAttenuation      */    0.0,   0.0, false,
                /* elevationDeg         */    0.0,   0.0, false,
                /* azimuthDeg           */ -180.0, 180.0, true,
                /* distance             */   10.0,   0.0, false,
                /* projectionAngleDeg   */    0.0,   0.0, false,
                /* sourceVelocity       */    0.0,   0.0, false,
                /* listenerVelocity     */    0.0,   0.0, false
        },
        { /* dividing line */ 0 },
        { /* Reverb Ñ Living Room */
                /* duration             */  10.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */  10.0,   0.0, false,
                /* roomReflectivity     */ -20.0,   0.0, false,
                /* reverbAttenuation    */   0.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   2.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Reverb Ñ Cave */
                /* duration             */  10.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */ 100.0,   0.0, false,
                /* roomReflectivity     */ -40.0,   0.0, false,
                /* reverbAttenuation    */  20.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   2.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Reverb Ñ Stadium */
                /* duration             */  10.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */ 250.0,   0.0, false,
                /* roomReflectivity     */ -15.0,   0.0, false,
                /* reverbAttenuation    */  -5.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   2.0,  10.0, true,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* dividing line */ 0 },
        { /* Source Doppler */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,   0.0, false,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */ -20.0,  20.0, true,
                /* listenerVelocity     */   0.0,   0.0, false
        },
        { /* Listener Doppler */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,   0.0, false,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */   0.0,   0.0, false,
                /* listenerVelocity     */ -20.0,  20.0, true
        },
        { /* Combined Doppler */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,   0.0, false,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */ -20.0,  20.0, true,
                /* listenerVelocity     */ -20.0,  20.0, true
        },
        { /* Cancelled Doppler */
                /* duration             */   4.0,
                /* cpuLoad              */     0,     0, false,
                /* medium               */ kSSpMedium_Air,
                /* humidity             */   0.0,   0.0, false,
                /* roomSize             */   0.0,   0.0, false,
                /* roomReflectivity     */ -10.0,   0.0, false,
                /* reverbAttenuation    */ -15.0,   0.0, false,
                /* sourceMode           */ kSSpSourceMode_Localized,
                /* referenceDistance    */   1.0,   0.0, false,
                /* coneAngleDeg         */  90.0,   0.0, false,
                /* coneAttenuation      */   0.0,   0.0, false,
                /* elevationDeg         */   0.0,   0.0, false,
                /* azimuthDeg           */   0.0,   0.0, false,
                /* distance             */   1.0,   0.0, false,
                /* projectionAngleDeg   */   0.0,   0.0, false,
                /* sourceVelocity       */  20.0, -20.0, true,
                /* listenerVelocity     */ -20.0,  20.0, true
        }
    };
    
    gTestLoLevelData = preset[index];
    
    TestLoLevel_DeriveData();
    TestLoLevel_SetDialogFields();
}