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

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

/*----------------------------------------------------------------------*/
/*	nuAuMgrInitEx -オーディオマネージャの初期化			*/
/*									*/
/*	AI_FIFO_EVENTを使うオーディオマネージャの初期化			*/
/*	IN:	ヒープバッファの先頭ポインタ				*/
/*	RET:	使用ヒープサイズ					*/
/*----------------------------------------------------------------------*/
s32 nuAuMgrInitEx(void* heap_ptr, u32 size, ALSynConfig* synConfig)
{
    s32 frameRate;
    nuAuTaskStop = NU_AU_TASK_RUN;	/* タスク実行可 */
    
    frameRate = nuScGetFrameRate();	/* フレームレートの取得 */

    /* 1フレームに必要なサンプル数の計算。小数点以下切り上げ 	*/
    nuAuFrameSampleSize = (nusched.retraceCount * synConfig->outputRate + frameRate - 1)/frameRate;
    nuAuFrameSampleSize += nuAuExtraSampleSize;
    nuAuFrameSampleSize = ((nuAuFrameSampleSize + (NU_AU_AUDIO_SAMPLES -1)) / NU_AU_AUDIO_SAMPLES) * NU_AU_AUDIO_SAMPLES;
    
    /* オーディオヒープの初期化 	*/
    nuAuHeapInit(&nuAuHeap, heap_ptr, size);

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

    /* オーディオバッファの確保 */
    auBuffer_ptr[0] = nuAuHeapAlloc(nuAuFrameSampleSize * sizeof(s32));
    auBuffer_ptr[1] = nuAuHeapAlloc(nuAuFrameSampleSize * 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];

    NUScMsg*	mesg_type;
    NUScMsg	aiEventMsg;
    Acmd*	cmdListAfter_ptr;
    s32		cmdList_len;
    u32		bufCnt;
    u32		bufPtr;
    s32		readCnt;
    
    osCreateMesgQueue(&nuAuMesgQ, nuAuMsgBuf, NU_AU_MESG_MAX);

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

    /* AIイベントメッセージの設定	*/
    aiEventMsg = NU_AU_AI_FIFO_MSG;
    osSetEventMesg(OS_EVENT_AI, &nuAuMesgQ, (OSMesg*)&aiEventMsg);

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

    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_FIFOOFF)
	   && (*mesg_type == NU_AU_AI_FIFO_MSG)){
	    continue;
	}
	if((nuAuDebFlag & NU_AU_DEBUG_RETRACEOFF)
	   &&(*mesg_type == NU_SC_RETRACE_MSG)){
	    continue;
	}
#endif	/* NU_DEBUG	*/
	switch(*mesg_type){
	    
	    /* AIのFIFO(DMAの設定をするレジスタ)が1->0になったとき 	*/
	    /* AIイベントが発生する。その時,未転送の合成波形データが	*/
	    /* ある場合FIFOにDMAの設定をおこなう			*/
	    /* この機構により,ノイズが発生することはなくなる		*/
	    /* しかし、最初はFIFOは空なのでAIイベントは発生しない。	*/
	    /* そこでAIイベントが発生するまでリトレースメッセージで	*/
	    /* RSPコマンド作成,マクロコードの起動,FIFOの設定をおこなう	*/
	    /* AIイベントが発生すれば,後はリトレースメッセージは不要	*/
	    /* なので、メッセージ登録をなくす				*/
	    /* もしなんらかの理由でAIイベント時にバッファを設定		*/
	    /* 出来なかったら、もう一度リトレースメッセージが来るように	*/
	    /* 設定しなおす。						*/
	case NU_SC_RETRACE_MSG:
	    if((bufCnt > 1) && !nuAuPreNMI){
		nuScResetClientMesgType(&nuAuClient, nuAuClient.msgType ^ NU_SC_RETRACE_MSG);
	    }
	    
	case NU_AU_AI_FIFO_MSG:
#ifdef	NU_DEBUG
	case NU_AU_AI_DEBUG_MSG:
#endif	/* NU_DEBUG */

	    /* 未転送のデータがバッファにある場合,DMAのFIFOレジスタを	*/
	    /* チェックし,OKであれば転送設定する			*/
	    if(bufCnt > 0){
		u32 status;
		
		status = osAiGetStatus();
		
		/* バッファの切り替え。これによりAIにデータが送られて音が鳴る*/
		if(!(status & AI_STATUS_FIFO_FULL)){
#ifdef	NU_DEBUG
		    if(!(nuAuDebFlag & NU_AU_DEBUG_DISABLEAI)){
#endif	/* NU_DEBUG */
		    osAiSetNextBuffer(auBuffer_ptr[readCnt], nuAuFrameSampleSize<<2);
#ifdef	NU_DEBUG
		    }
#endif	/* NU_DEBUG */
		    readCnt ^= 1;
		    bufCnt--;
		}
	    } else if(!(nuAuClient.msgType & NU_SC_RETRACE_MSG)){
		/* FIFOが空になりAIイベントが発生しなくなるので		*/
		/* リトレースメッセージを送るように再登録する		*/
		nuScResetClientMesgType(&nuAuClient, nuAuClient.msgType | NU_SC_RETRACE_MSG);
	    }
	    
	    /* タスク起動。コマンドリストが無い場合はタスクを起動しない */
	    if((cmdList_len > 0) && (bufCnt < 2) && (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 */

                bufPtr ^=1;
                bufCnt++;
                cmdList_len = 0;
	    }
	    
	    if(cmdList_len == 0){
		/* オーディオコマンドリストの作成 */
		cmdListAfter_ptr = alAudioFrame(nuAuCmdListBuf, &cmdList_len,
						(s16*)osVirtualToPhysical(auBuffer_ptr[bufPtr]),
						nuAuFrameSampleSize);
		
		/* DMAバッファのクリア。2フレーム未使用のバッファは	*/
		/* クリアする。						*/
		nuAuCleanDMABuffers();
		
		/* シーケンスのコントロール	*/
		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((nuAuPreNMI) && (*mesg_type & NU_SC_RETRACE_MSG)){
		if((u32)nuAuPreNMIFunc){
		    (*nuAuPreNMIFunc)(NU_SC_RETRACE_MSG, nuAuPreNMI);
		}
		nuAuPreNMI++;
	    }
	break;
    case NU_SC_PRENMI_MSG:
	    /* PRE NMIメッセージがきたら関数を呼ぶ */
	    if(nuAuPreNMIFunc){
		/* リトレースメッセージを送るように再登録する		*/
		nuScResetClientMesgType(&nuAuClient, nuAuClient.msgType | NU_SC_RETRACE_MSG);
		
		(*nuAuPreNMIFunc)(NU_SC_PRENMI_MSG, nuAuPreNMI);
	    }
	    nuAuPreNMI++;
	    break;
	default:
#ifdef NU_DEBUG
	    if(nuAuDebFlag & NU_AU_DEBUG_NORMAL){
		osSyncPrintf("nuAuMgr: Unknown message %d received \n", *mesg_type);
	    }
#endif /* NU_DEBUG */
	    break;
        }
    }
}