nuaumgr.c 8.85 KB
/*======================================================================*/
/*		NuSYS							*/
/*		nuaumgr.c						*/
/*									*/
/*		Copyright (C) 1997, NINTENDO Co,Ltd.			*/
/*	--/--/--	Created  by K.Ohki(SLANP)			*/
/*	98/12/10	Modified by K.Ohki(SLANP)			*/
/*======================================================================*/
/* $Id: nuaumgr.c,v 1.1.1.1 2002/10/30 02:07:09 blythe Exp $		*/
/*======================================================================*/
#include <nusys.h>
#include <nualsgi.h>


static s16*	auBuffer_ptr[3];	/* オーディオバッファ */
static void	nuAuMgr(void* arg);
static s32	minFrameSampleSize;
static s32	maxFrameSampleSize;

/*----------------------------------------------------------------------*/
/*	nuAuMgrInit -オーディオマネージャの初期化			*/
/*	IN:	ヒープバッファの先頭ポインタ				*/
/*	RET:	使用ヒープサイズ					*/
/*----------------------------------------------------------------------*/
s32 nuAuMgrInit(void* heap_ptr, u32 size, ALSynConfig* synConfig)
{

    u32	sampleSize;
    u32	frameRate;
    
    nuAuTaskStop = NU_AU_TASK_RUN;	/* タスク実行可 */
    
    frameRate = nuScGetFrameRate();	/* フレームレートの取得 */
    
    /* 1フレームに必要なサンプル数の計算。小数点以下切り上げ 	*/
    nuAuFrameSampleSize = (nuAuRetraceCount * synConfig->outputRate + frameRate)/frameRate;
    nuAuFrameSampleSize += nuAuExtraSampleSize;
    sampleSize = nuAuFrameSampleSize + nuAuFrameSampleSize / 4;    
#ifdef	N_AUDIO
    sampleSize = ((sampleSize + NU_AU_AUDIO_SAMPLES - 1) / NU_AU_AUDIO_SAMPLES) * NU_AU_AUDIO_SAMPLES;	
    minFrameSampleSize = sampleSize;
    maxFrameSampleSize = sampleSize + NU_AU_AUDIO_SAMPLES;
#else
    sampleSize = (sampleSize + NU_AU_AUDIO_SAMPLES - 1) & ~0x0f;
    minFrameSampleSize = nuAuFrameSampleSize & ~0x0f;
    maxFrameSampleSize = sampleSize + NU_AU_AUDIO_SAMPLES;
#endif	/* N_AUDIO */

    /* オーディオヒープの初期化 */
    nuAuHeapInit(&nuAuHeap, heap_ptr, size);

    /* コマンドリストバッファの確保 */
    nuAuCmdListBuf = nuAuHeapAlloc(nuAuAcmdLen * sizeof(Acmd));

    /* オーディオバッファの確保 */
    auBuffer_ptr[0] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
    auBuffer_ptr[1] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
    auBuffer_ptr[2] = nuAuHeapAlloc(maxFrameSampleSize * sizeof(s32));
    
    /* オーディオマネージャのスタック領域の確保 */
    nuAuMgrStack = nuAuHeapAlloc(NU_AU_STACK_SIZE);

    /* シンセサイズドライバの初期化	*/
    synConfig->dmaproc    = nuAuDmaNew;
    synConfig->heap	  = &nuAuHeap;
    synConfig->outputRate = osAiSetFrequency(synConfig->outputRate);
    alInit(&nuAuGlobal, synConfig);
    
    nuAuTask.msg			= 0;/* reply with this message */
    nuAuTask.list.t.type		= M_AUDTASK;
    nuAuTask.list.t.ucode_boot	     	= (u64*)rspbootTextStart;
    nuAuTask.list.t.ucode_boot_size   	=
	((int) rspbootTextEnd - (int) rspbootTextStart);
#ifdef N_AUDIO
    nuAuTask.list.t.ucode	     	= (u64*) n_aspMainTextStart;
    nuAuTask.list.t.ucode_data        	= (u64 *) n_aspMainDataStart;
#else
    nuAuTask.list.t.ucode	     	= (u64*) aspMainTextStart;
    nuAuTask.list.t.ucode_data       	= (u64 *) aspMainDataStart;
#endif	/* N_AUDIO */
    nuAuTask.list.t.ucode_data_size   	= SP_UCODE_DATA_SIZE;
    nuAuTask.list.t.dram_stack	     	= (u64 *) NULL;
    nuAuTask.list.t.dram_stack_size   	= 0;
    nuAuTask.list.t.output_buff	     	= (u64 *) NULL;
    nuAuTask.list.t.output_buff_size  	= 0;
    nuAuTask.list.t.yield_data_ptr    	= NULL;
    nuAuTask.list.t.yield_data_size   	= 0;

    nuAuSeqPlayer[0].mode 	= 0;
    nuAuSeqPlayer[1].mode 	= 0;
    nuAuSeqPlayer[0].data_ptr 	= NULL;
    nuAuSeqPlayer[1].data_ptr 	= NULL;    

    /* オーディオマネージャの起動 */
    osCreateThread(&nuAuMgrThread, NU_AU_MGR_THREAD_ID, nuAuMgr, (void*)NULL,
		   (nuAuMgrStack + NU_AU_STACK_SIZE/sizeof(u64)),
		   NU_AU_MGR_THREAD_PRI);
    osStartThread(&nuAuMgrThread);

    /* 使用しているヒープサイズを返す	*/
    return nuAuHeapGetUsed();
}


/*----------------------------------------------------------------------*/
/*	nuAuMgr - オーディオマネージャ					*/
/*	IN:	無し							*/
/*	RET:	無し							*/
/*----------------------------------------------------------------------*/
static void nuAuMgr(void* arg)
{
    OSMesgQueue nuAuRtnMesgQ;
    OSMesg	nuAuRtnMesgBuf;
    OSMesg	nuAuMsgBuf[NU_AU_MESG_MAX];
    s32		sampleSize[3];
    NUScMsg*	mesg_type;
    s32		samplesLeft, Samples=0;    
    Acmd*	cmdListAfter_ptr;    
    s32		cmdList_len;
    u32		status;
    s32		frameSampleSize;
    u32		bufCnt;
    u32		bufPtr;
    s32		readCnt;

    
    osCreateMesgQueue(&nuAuMesgQ, nuAuMsgBuf, NU_AU_MESG_MAX);

    /* オーディオタスクスレッドからのメッセージ待ちキュー */
    osCreateMesgQueue(&nuAuRtnMesgQ, &nuAuRtnMesgBuf, 1);

    /* スケジューラにRETRACEクライアント登録 */
    nuScAddClient(&nuAuClient, &nuAuMesgQ, NU_SC_RETRACE_MSG | NU_SC_PRENMI_MSG);

    frameSampleSize = nuAuFrameSampleSize * 2  + nuAuFrameSampleSize / 2;

    cmdList_len  = 0;
    bufCnt = 0;
    readCnt = 0;
    bufPtr = 0;
    while(1){
	(void)osRecvMesg(&nuAuMesgQ, (OSMesg*)&mesg_type, OS_MESG_BLOCK);
#ifdef	NU_DEBUG
	if((nuAuDebFlag & NU_AU_DEBUG_RETRACEOFF)
	   &&(*mesg_type == NU_SC_RETRACE_MSG)){
	    continue;
	}
#endif	/* NU_DEBUG */
	switch(*mesg_type){
#ifdef	NU_DEBUG
	case NU_AU_AI_DEBUG_MSG:
#endif	/* NU_DEBUG */
	case NU_SC_RETRACE_MSG:
	    /* AIのDMAレジスタの状態を取得 */
	    status = osAiGetStatus();

	    if(status & AI_STATUS_FIFO_FULL){
		continue;
	    }

    	    /* AIバッファに残存するサンプル数をゲット */
	    samplesLeft = osAiGetLength() >> 2;

#ifdef	NU_DEBUG
	    if(nuAuDebFlag & NU_AU_DEBUG_NORMAL){
		if(!samplesLeft && (nuAuFrameCounter > 4)){
		    osSyncPrintf("nuAuMgr: no samples left!!\n");
		}
	    }
#endif	/* NU_DEBUG */
	    /* この部分は,ループの1回目は実行されません 		*/
	    /* というのもループの1回目はまだデータが作成されてないから	*/
	    if(bufCnt){
#ifdef	NU_DEBUG
		if(!(nuAuDebFlag & NU_AU_DEBUG_DISABLEAI)){
#endif	/* NU_DEBUG */
		/* バッファの切り替え。これによりAIにデータが送られて音が鳴る*/
		osAiSetNextBuffer(auBuffer_ptr[readCnt], sampleSize[readCnt]<<2);
#ifdef	NU_DEBUG
		}
#endif	/* NU_DEBUG */
		Samples = sampleSize[readCnt];
		readCnt = (readCnt + 1) % 3;
		bufCnt--;
	    }

	    /* タスク起動。コマンドリストが無い場合はタスクを起動しない */
	    if(cmdList_len && (nuAuTaskStop)) {	
#ifdef	NU_DEBUG
		if(!(nuAuDebFlag & NU_AU_DEBUG_DISABLETASK)){
#endif	/* NU_DEBUG */
		nuAuTask.list.t.data_ptr  = (u64 *)nuAuCmdListBuf;
		nuAuTask.list.t.data_size =
		    (cmdListAfter_ptr - nuAuCmdListBuf) * sizeof(Acmd);
		nuAuTask.msgQ		 = &nuAuRtnMesgQ;
		osSendMesg(&nusched.audioRequestMQ, (OSMesg*)&nuAuTask, OS_MESG_BLOCK);
		
		osRecvMesg(&nuAuRtnMesgQ, NULL, OS_MESG_BLOCK);
		
		
#ifdef	NU_DEBUG
		}
#endif	/* NU_DEBUG */
		/* DMAバッファのクリア。			*/
		/*   2フレーム未使用のバッファはクリアする 	*/
		
		nuAuCleanDMABuffers();
		cmdList_len = 0;		
		bufPtr = (bufPtr + 1) % 3;
		bufCnt++;
	    }

	    /* サンプル数の制御方法					*/
	    /* 現在転送中のDMAの残りサンプル数と次に転送されるサンプル数*/
	    /* からこのフレームで作成するサンプル数を算出する。		*/
	    /* この合計と1.25フレーム分のサンプル数の差をとり,		*/
	    /* FIFOバッファに設定されている合計サンプル数が1.25フレーム	*/
	    /* 分になるようにサンプル数を制御するように計算。		*/
	    Samples = frameSampleSize - (Samples + samplesLeft);
	    
	    if(Samples > maxFrameSampleSize){
		Samples = maxFrameSampleSize;
	    } else if(Samples < minFrameSampleSize){
		Samples = minFrameSampleSize;
	    } else {
#ifdef N_AUDIO
		Samples = ((Samples + NU_AU_AUDIO_SAMPLES -1)/NU_AU_AUDIO_SAMPLES) * NU_AU_AUDIO_SAMPLES;
#else
		Samples = (Samples + NU_AU_AUDIO_SAMPLES - 1) & ~0x0f;
#endif	/* N_AUDIO */
	    }

	    /* オーディオコマンドリストの作成 		*/
	    cmdListAfter_ptr = alAudioFrame(nuAuCmdListBuf, &cmdList_len,
					    (s16*)osVirtualToPhysical(auBuffer_ptr[bufPtr]),
					    Samples);
	    sampleSize[bufPtr] = Samples;
	    Samples = 0;
	    
	    
	    /* シーケンスのコントロール	*/
	    if(nuAuMgrFunc){
		(*nuAuMgrFunc)();
	    }
#ifdef NU_DEBUG
	    /* オーディオコマンドリストのサイズの最大値の更新 */
	    if(cmdList_len >= nuAuDebAcmdLenMax){
		nuAuDebAcmdLenMax = cmdList_len;
	    }
	    if(cmdList_len >= nuAuAcmdLen){
		if(nuAuDebFlag & NU_AU_DEBUG_NORMAL){
		    osSyncPrintf("nuAuMgr: cmdlist_len %d is too big.\n",
				 cmdList_len);
		}
		nuAuDebStatus |= NU_AU_DEBUG_ACMDBUFOVER;
	    }
#endif /* NU_DEBUG */
	    
	    /* PRE NMIメッセージが来たら,その後この関数が呼ばれつづける */
	    if((u32)nuAuPreNMIFunc && nuAuPreNMI){
		(*nuAuPreNMIFunc)(NU_SC_RETRACE_MSG, nuAuPreNMI);
		nuAuPreNMI++;
	    }
	    break;
	case NU_SC_PRENMI_MSG:
	    /* PRE NMIメッセージがきたら関数を呼ぶ */
	    if(nuAuPreNMIFunc){
		(*nuAuPreNMIFunc)(NU_SC_PRENMI_MSG, nuAuPreNMI);
	    }
	    nuAuPreNMI++;
	    break;
	default:
#ifdef NU_DEBUG
	    osSyncPrintf("nuAuMgr: Unknown message %d received \n", *mesg_type);
#endif /* NU_DEBUG */
	    break;
        }
    }
}