synScript.c 9.22 KB
/*====================================================================
 * synScript.c
 *
 * Synopsis: This test file was actually built off of test2.c and
 * was rewritten to perform scripted actions not random actions.
 * I used this to track down the "stopping and stopped voice" bug.
 * Currently, this test only provides one voice and one sound.
 *
 * Copyright 1993, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
 * Inc.; the contents of this file may not be disclosed to third
 * parties, copied or duplicated in any form, in whole or in part,
 * without the prior written permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to
 * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS
 * 252.227-7013, and/or in similar or successor clauses in the FAR,
 * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
 * Copyright Laws of the United States.
 *====================================================================*/

#include <assert.h>
#include <libaudio.h>
#include "audiotest.h"
#include "audio.h"
#include "synScript.h"


static void	InitTest(u32 subTestNum);
static void	StopTest(u32 subTestNum);
static void	ButtonProc(u16 oldButtons,u16 newButtons);
static void	InitScript0(TScript *pScript);

static void	playerNew(TTestPlayer *p, int numVoices, ALBank *bank);
static void	playerDelete(TTestPlayer *p);
static void	playerSetBank(TTestPlayer *p, ALBank *bank);
static int	playerPlay(TTestPlayer *p);
static int	playerStop(TTestPlayer *p);
static ALMicroTime _voiceHandler(void *node);
static ALMicroTime _voiceHandler2(void *node);

static void	nullAction(TTestPlayer *p);
static void	done(TTestPlayer *p);
static void	allocVoice(TTestPlayer *p);
static void	freeVoice(TTestPlayer *p);
static void	startVoice(TTestPlayer *p);
static void	stopVoice(TTestPlayer *p);

static void	TestPitchLimit (void);

static TTestPlayer *p;
static char doStart = FALSE, doStop = FALSE;

extern ALHeap   gHeapRec;
extern u8       gHeapBuf[AUDIO_HEAP_SIZE];


test_cntrl synScriptTest = {
    &InitTest,
    &StopTest,
    &ButtonProc,
    NULL,
    NULL,            /* void *retraceData */
    1                /* u32  numSubTests */
};



static TScriptAction script0[] = 
{
    (TScriptActionProc)allocVoice, 0,
    (TScriptActionProc)stopVoice, 0,
    (TScriptActionProc)startVoice, 2*ONE_SEC,

    (TScriptActionProc)stopVoice, 0,
    (TScriptActionProc)stopVoice, 2*ONE_SEC,

    (TScriptActionProc)stopVoice, 2*ONE_SEC,

    (TScriptActionProc)stopVoice, 0,
    (TScriptActionProc)startVoice, 2*ONE_SEC,

    (TScriptActionProc)stopVoice, 0,
    (TScriptActionProc)done, END_OF_SCRIPT
};



static
void InitTest (u32 subTestNum) 
{
    ALSynConfig         c;
    u32                 bankLen;
    ALBankFile          *bankPtr;
    ALBank              *bank;
    amConfig            amc;

    alHeapInit(&gHeapRec, gHeapBuf, sizeof(gHeapBuf));    

    /**** Load the bank file from ROM ****/
    bankLen = _midibankSegmentRomEnd - _midibankSegmentRomStart;
    bankPtr = alHeapAlloc(&gHeapRec, 1, bankLen);
    romCopy(_midibankSegmentRomStart, (char *)bankPtr, bankLen);

    alBnkfNew(bankPtr, (u8 *) _miditableSegmentRomStart);
    bank = bankPtr->bankArray[0];

    /**** Create the Audio Manager ****/
    c.maxVVoices = MAX_SYNTH_VVOICES;
    c.maxPVoices = MAX_SYNTH_PVOICES;
    c.maxUpdates = MAX_SYNTH_UPDATES;
    c.dmaproc    = 0;                  /* audio mgr will fill this in */
    c.fxType     = AL_FX_NONE;
    c.heap       = &gHeapRec;
    
    amc.outputRate = 44100;
    amc.framesPerField = NUM_FIELDS;
    amc.maxACMDSize = MAX_RSP_CMDS;
    amCreateAudioMgr(&c, AUDIO_PRIORITY, &amc);

    /* create the test player */
    p = (TTestPlayer *) alHeapAlloc(&gHeapRec, 1 , sizeof(TTestPlayer));
    playerNew(p, MAX_VOICES, bank);
}



static void StopTest (u32 subTestNum) 
{
    playerDelete(p);
    amDestroyAM();
}


static void ButtonProc(u16 oldButtons,u16 newButtons)
{
    u16 button;

    button = oldButtons^newButtons;  /* get the ones that have changed */
    button &= newButtons;            /* get only button downs */

    /* CONT_A and CONT_B controls only affect _voiceHander2 */
    if (button & CONT_A)
	doStop = TRUE;

    if (button & CONT_B)
	doStart = TRUE;

    if (button & CONT_START)
	TestDone ();

    if (button & CONT_C)
	TestPitchLimit ();
}
    


/***********************************************************************
 * Player for this test
 ***********************************************************************/
static void playerNew(TTestPlayer *p, int numVoices, ALBank *bank) 
{
    int i;

    PRINTF("\tnew player\n");
    p->numVoices = numVoices;
    p->drvr = &alGlobals->drvr;
    
    /* initialize the state machine */
    InitScript0 (&p->script);

    /* initialize the wave tables */
    p->numWaveTables = 0;
    playerSetBank(p, bank);
    
    /* add ourselves to the driver */
    p->node.next       = NULL;
    p->node.handler    = _voiceHandler;
    p->node.clientData = p;
    alSynAddPlayer(p->drvr, &p->node);
}


void
playerDelete(TTestPlayer *p) 
{
    PRINTF("\tdelete player\n");
    alSynRemovePlayer(p->drvr, &p->node);
}


void
playerSetBank(TTestPlayer *p, ALBank *bank)
{
    int i, k;
    ALInstrument *inst;
    ALSound      *sound;
    
    for (i = 0; i < bank->instCount; i++)
    {
        inst = bank->instArray[i];
        for (k = 0; k < inst->soundCount; k++)
	{
            sound = inst->soundArray[k];
            p->waves[p->numWaveTables++] = sound->wavetable;

            if (p->numWaveTables >= MAX_WAVES)
                return;
        }    
    }
}

/*
  This script tests stopping and already stopped voice.
  This caused a crash in ultra 2.0C and before.
*/
static void
InitScript0 (TScript *pScript)
{
    PRINTF("Test stopping an already stopped voice.\n");
    PRINTF("Press start to continue when test completes.\n");

    pScript->fActionIndex = 0;
    pScript->fActionTable = script0;
}


/*
  This is the default voice handler.
  It simply executes the scripted actions defined
  in the player's script.
*/
ALMicroTime
_voiceHandler (void *node)
{
    TTestPlayer *	p = (TTestPlayer *)node;
    TScript *		pScript = &p->script;
    TScriptAction *	pAction;

    do
    {
        pAction = &pScript->fActionTable[pScript->fActionIndex++];
	(*(pAction->fActionProc))((TTestPlayerPtr)p);
       
    } while (pAction->fDeltaUsecs == 0);

    return pAction->fDeltaUsecs;
}


/*
  This is another useful voice handler worth keeping around.
  It simply starts and stops voices according to controller
  commands.
*/
ALMicroTime
_voiceHandler2 (void *node)
{
    TTestPlayer *	p = (TTestPlayer *)node;
    static char		allocated = FALSE;

    if (!allocated)
    {
	allocated = TRUE;
	allocVoice (p);
    }

    if (doStart)
    {
	startVoice (p);
	doStart = FALSE;
    }
    
    if (doStop)
    {
	stopVoice (p);
	doStop = FALSE;
    }

    return 1000;
}


void
nullAction(TTestPlayer *p)
{
    PRINTF("\tnull\n");
}


void
done(TTestPlayer *p)
{
    PRINTF("\tdone\n");
}


void
allocVoice(TTestPlayer *p)
{
    ALVoiceConfig vc;

    vc.priority = AL_MAX_PRIORITY;	   /* voice priority       */
    vc.fxBus = 0;                          /* bus assignment       */
    vc.unityPitch = 0;
    
    PRINTF("\talloc voice\n");
    if (alSynAllocVoice(p->drvr, &p->voices[0], &vc) == 0)
	PRINTF("\talloc failed\n");
}

void
freeVoice(TTestPlayer *p)
{
    PRINTF("\tfree voice\n");
    alSynFreeVoice(p->drvr, &p->voices[0]);
}

void
startVoice(TTestPlayer *p)
{
    if (!p->numWaveTables)
    {
	PRINTF("\tcan't start voice\n");
        return;
    }

    PRINTF("\tstart voice\n");
    alSynStartVoiceParams(p->drvr, &p->voices[0], p->waves[0], 1.0, 0x7fff, AL_PAN_CENTER, AL_DEFAULT_FXMIX, 0);
}

void
stopVoice(TTestPlayer *p)
{
    PRINTF("\tstop voice\n");
    alSynStopVoice(p->drvr, &p->voices[0]);
}


static void
TestPitchLimit (void)
{
    #define kTinyInt	1
    #define kBigInt	0x7fffffff
    #define kTinyFloat	1.07549430E-38			/* from /usr/include/float.h */
    #define kBigFloat	3.40282347E+38			/* from /usr/include/float.h */
    #define kMinFloat	kTinyFloat	       /*(kBigInt * kTinyFloat - kTinyFloat) */

    s32		opInt, resultInt;
    float	opFloat, resultFloat;

    opInt = kBigInt;
    opFloat = kBigFloat;
    PRINTF("big/big:\t%d / %e = ", opInt, opFloat);
    resultFloat = opInt/opFloat;
    resultInt = resultFloat;
    PRINTF("%e, %d\n\n", resultFloat, resultInt);

    opInt = kTinyInt;
    opFloat = kBigFloat;
    PRINTF("tiny/big:\t%d / %e = ", opInt, opFloat);
    resultFloat = opInt/opFloat;
    resultInt = resultFloat;
    PRINTF("%e, %d\n\n", resultFloat, resultInt);

    opInt = kTinyInt;
    opFloat = kMinFloat;
    /*PRINTF("tiny/tiny:\t%d / %e = ", opInt, opFloat);*/
    PRINTF("tiny/tiny: ");
    resultFloat = opInt/opFloat;
    resultInt = resultFloat;
    /*PRINTF("%e, %d\n\n", resultFloat, resultInt);*/
    /* PRINTF("%d\n\n", resultInt); */

    opInt = kBigInt;
    opFloat = kMinFloat;
    /*PRINTF("big/tiny:\t%d / %e = ", opInt, opFloat); */
    PRINTF("big/tiny: ");
    resultFloat = opInt/opFloat;
    resultInt = resultFloat;
    /*PRINTF("%e, %d\n\n", resultFloat, resultInt);*/
    /*PRINTF("%d\n\n", resultInt);*/
}