mirror of
https://github.com/rvtr/TwlIPL.git
synced 2025-10-31 06:01:12 -04:00
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@612 b08762b0-b915-fc4b-9d8c-17b2551a87ff
350 lines
10 KiB
C
350 lines
10 KiB
C
/*---------------------------------------------------------------------------*
|
|
Project: TwlIPL
|
|
File: sound.c
|
|
|
|
Copyright 2007 Nintendo. All rights reserved.
|
|
|
|
These coded instructions, statements, and computer programs contain
|
|
proprietary information of Nintendo of America Inc. and/or Nintendo
|
|
Company Ltd., and are protected by Federal copyright law. They may
|
|
not be disclosed to third parties or copied or duplicated in any form,
|
|
in whole or in part, without the prior written consent of Nintendo.
|
|
|
|
$Date:: $
|
|
$Rev$
|
|
$Author$
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include "sound.h"
|
|
|
|
static BOOL ReadWaveFormat(StreamInfo * strm);
|
|
static void ReadStrmData(StreamInfo * strm);
|
|
static void SoundAlarmHandler(void *arg);
|
|
static void VBlankIntr(void);
|
|
|
|
static u16 Cont;
|
|
static u16 Trg;
|
|
static OSMessageQueue msgQ;
|
|
static OSMessage msgBuf[1];
|
|
|
|
static u8 strm_lbuf[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
|
|
static u8 strm_rbuf[STRM_BUF_SIZE] ATTRIBUTE_ALIGN(32);
|
|
static u8 strm_tmp[STRM_BUF_PAGESIZE * 2] ATTRIBUTE_ALIGN(32);
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: PlayStream
|
|
|
|
Description: ストリーム再生を再生
|
|
|
|
Arguments: strm - ストリームオブジェクト
|
|
filename - ストリーム再生するファイル名
|
|
|
|
Returns: None.
|
|
*---------------------------------------------------------------------------*/
|
|
void PlayStream(StreamInfo * strm, const char *filename)
|
|
{
|
|
int timerValue;
|
|
u32 alarmPeriod;
|
|
|
|
// 再生中であれば停止する
|
|
if (strm->isPlay)
|
|
{
|
|
u32 tag;
|
|
StopStream(strm);
|
|
tag = SND_GetCurrentCommandTag();
|
|
(void)SND_FlushCommand(SND_COMMAND_NOBLOCK | SND_COMMAND_IMMEDIATE);
|
|
SND_WaitForCommandProc(tag); // 停止を待つ
|
|
}
|
|
|
|
// ファイル走査
|
|
if (FS_IsFile(&strm->file))
|
|
(void)FS_CloseFile(&strm->file);
|
|
if ( ! FS_OpenFile(&strm->file, filename) ) {
|
|
OS_Panic("Error: failed to open file %s\n", filename);
|
|
}
|
|
if (!ReadWaveFormat(strm))
|
|
{
|
|
OS_Panic("Error: failed to read wavefile\n");
|
|
}
|
|
|
|
strm->isPlay = TRUE;
|
|
|
|
/* パラメータ設定 */
|
|
timerValue = SND_TIMER_CLOCK / strm->format.sampleRate;
|
|
alarmPeriod = timerValue * STRM_BUF_PAGESIZE / 32U;
|
|
alarmPeriod /= (strm->format.bitPerSample == 16) ? sizeof(s16) : sizeof(s8);
|
|
|
|
// 初期ストリームデータ読み込み
|
|
(void)FS_SeekFile(&strm->file, (s32)strm->beginPos, FS_SEEK_SET);
|
|
strm->bufPage = 0;
|
|
ReadStrmData(strm);
|
|
ReadStrmData(strm);
|
|
|
|
// チャンネルとアラームをセットアップ
|
|
SND_SetupChannelPcm(L_CHANNEL,
|
|
(strm->format.bitPerSample ==
|
|
16) ? SND_WAVE_FORMAT_PCM16 : SND_WAVE_FORMAT_PCM8, strm_lbuf,
|
|
SND_CHANNEL_LOOP_REPEAT, 0, STRM_BUF_SIZE / sizeof(u32), 127,
|
|
SND_CHANNEL_DATASHIFT_NONE, timerValue, 0);
|
|
SND_SetupChannelPcm(R_CHANNEL,
|
|
(strm->format.bitPerSample ==
|
|
16) ? SND_WAVE_FORMAT_PCM16 : SND_WAVE_FORMAT_PCM8,
|
|
(strm->format.channels == 1) ? strm_lbuf : strm_rbuf,
|
|
SND_CHANNEL_LOOP_REPEAT, 0, STRM_BUF_SIZE / sizeof(u32), 127,
|
|
SND_CHANNEL_DATASHIFT_NONE, timerValue, 127);
|
|
SND_SetupAlarm(ALARM_NUM, alarmPeriod, alarmPeriod, SoundAlarmHandler, strm);
|
|
SND_StartTimer((1 << L_CHANNEL) | (1 << R_CHANNEL), 0, 1 << ALARM_NUM, 0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: StopStream
|
|
|
|
Description: ストリーム再生を停止
|
|
|
|
Arguments: strm - ストリームオブジェクト
|
|
|
|
Returns: None.
|
|
*---------------------------------------------------------------------------*/
|
|
void StopStream(StreamInfo * strm)
|
|
{
|
|
SND_StopTimer((1 << L_CHANNEL) | (1 << R_CHANNEL), 0, 1 << ALARM_NUM, 0);
|
|
if (FS_IsFile(&strm->file))
|
|
(void)FS_CloseFile(&strm->file);
|
|
strm->isPlay = FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: StrmThread
|
|
|
|
Description: ストリームスレッド
|
|
|
|
Arguments: arg - ユーザーデータ(未使用)
|
|
|
|
Returns: None.
|
|
*---------------------------------------------------------------------------*/
|
|
void StrmThread(void * /*arg */ )
|
|
{
|
|
OSMessage message;
|
|
|
|
OS_InitMessageQueue(&msgQ, msgBuf, 1);
|
|
|
|
while (1)
|
|
{
|
|
(void)OS_ReceiveMessage(&msgQ, &message, OS_MESSAGE_BLOCK);
|
|
(void)ReadStrmData((StreamInfo *) message);
|
|
}
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: SoundAlarmHandler
|
|
|
|
Description: アラームコールバック関数
|
|
|
|
Arguments: arg - ストリームオブジェクト
|
|
|
|
Returns: None.
|
|
*---------------------------------------------------------------------------*/
|
|
static void SoundAlarmHandler(void *arg)
|
|
{
|
|
(void)OS_SendMessage(&msgQ, (OSMessage)arg, OS_MESSAGE_NOBLOCK);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: ReadStrmData
|
|
|
|
Description: ストリームデータ読み込み関数
|
|
ファイルからバッファの1ページ分のストリームデータを読み込む
|
|
|
|
Arguments: strm - ストリームオブジェクト
|
|
|
|
Returns: None.
|
|
*---------------------------------------------------------------------------*/
|
|
static void ReadStrmData(StreamInfo * strm)
|
|
{
|
|
int i;
|
|
s32 readSize;
|
|
u8 *lbuf, *rbuf;
|
|
|
|
// ストリームが終端に達している
|
|
if (strm->dataSize <= 0)
|
|
{
|
|
StopStream(strm);
|
|
return;
|
|
}
|
|
|
|
// バッファのページ設定
|
|
if (strm->bufPage == 0)
|
|
{
|
|
lbuf = strm_lbuf;
|
|
rbuf = strm_rbuf;
|
|
strm->bufPage = 1;
|
|
}
|
|
else
|
|
{
|
|
lbuf = strm_lbuf + STRM_BUF_PAGESIZE;
|
|
rbuf = strm_rbuf + STRM_BUF_PAGESIZE;
|
|
strm->bufPage = 0;
|
|
}
|
|
|
|
// データ読み込み
|
|
if (strm->format.channels == 1)
|
|
{
|
|
// モノラル
|
|
readSize = FS_ReadFile(&strm->file,
|
|
strm_tmp,
|
|
(strm->dataSize <
|
|
STRM_BUF_PAGESIZE) ? strm->dataSize : STRM_BUF_PAGESIZE);
|
|
if (readSize == -1)
|
|
OS_Panic("read file end\n");
|
|
|
|
if (strm->format.bitPerSample == 16)
|
|
{
|
|
// 16bitデータ
|
|
for (i = 0; i < readSize / sizeof(s16); i++)
|
|
{
|
|
((s16 *)lbuf)[i] = ((s16 *)strm_tmp)[i];
|
|
}
|
|
for (; i < STRM_BUF_PAGESIZE / sizeof(s16); i++)
|
|
{
|
|
((s16 *)lbuf)[i] = 0; // ストリームの終端に達した場合、残りを0で埋める
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 8bitデータ
|
|
for (i = 0; i < readSize / sizeof(s8); i++)
|
|
{
|
|
((s8 *)lbuf)[i] = (s8)((s16)strm_tmp[i] - 128);
|
|
}
|
|
for (; i < STRM_BUF_PAGESIZE / sizeof(s8); i++)
|
|
{
|
|
((s8 *)lbuf)[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ステレオ
|
|
readSize = FS_ReadFile(&strm->file,
|
|
strm_tmp,
|
|
(strm->dataSize <
|
|
STRM_BUF_PAGESIZE * 2) ? strm->dataSize : STRM_BUF_PAGESIZE * 2);
|
|
if (readSize == -1)
|
|
OS_Panic("read file end\n");
|
|
|
|
if (strm->format.bitPerSample == 16)
|
|
{
|
|
// 16bitデータ
|
|
for (i = 0; i < (readSize / 2) / sizeof(s16); i++)
|
|
{
|
|
((s16 *)lbuf)[i] = ((s16 *)strm_tmp)[2 * i];
|
|
((s16 *)rbuf)[i] = ((s16 *)strm_tmp)[2 * i + 1];
|
|
}
|
|
for (; i < STRM_BUF_PAGESIZE / sizeof(s16); i++)
|
|
{
|
|
((s16 *)lbuf)[i] = 0;
|
|
((s16 *)rbuf)[i] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 8bitデータ
|
|
for (i = 0; i < (readSize / 2) / sizeof(s8); i++)
|
|
{
|
|
((s8 *)lbuf)[i] = (s8)((s16)strm_tmp[2 * i] - 128);
|
|
((s8 *)rbuf)[i] = (s8)((s16)strm_tmp[2 * i + 1] - 128);
|
|
}
|
|
for (; i < STRM_BUF_PAGESIZE / sizeof(s8); i++)
|
|
{
|
|
((s8 *)lbuf)[i] = 0;
|
|
((s8 *)rbuf)[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
strm->dataSize -= readSize;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
Name: ReadWaveFormat
|
|
|
|
Description: WAVEフォーマットのデータのヘッダとデータ列の先頭位置、データサイズを取得
|
|
|
|
Arguments: strm - ストリームオブジェクト
|
|
|
|
Returns: 読み取りに成功したらTRUE、失敗したらFALSE
|
|
*---------------------------------------------------------------------------*/
|
|
static BOOL ReadWaveFormat(StreamInfo * strm)
|
|
{
|
|
u32 tag;
|
|
s32 size;
|
|
BOOL fFmt = FALSE, fData = FALSE;
|
|
|
|
(void)FS_SeekFileToBegin(&strm->file);
|
|
|
|
(void)FS_ReadFile(&strm->file, &tag, 4);
|
|
if (tag != FOURCC_RIFF)
|
|
return FALSE;
|
|
|
|
(void)FS_ReadFile(&strm->file, &size, 4);
|
|
|
|
(void)FS_ReadFile(&strm->file, &tag, 4);
|
|
if (tag != FOURCC_WAVE)
|
|
return FALSE;
|
|
|
|
while (size > 0)
|
|
{
|
|
s32 chunkSize;
|
|
if (FS_ReadFile(&strm->file, &tag, 4) == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (FS_ReadFile(&strm->file, &chunkSize, 4) == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (tag)
|
|
{
|
|
case FOURCC_fmt:
|
|
if (FS_ReadFile(&strm->file, (u8 *)&strm->format, chunkSize) == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
fFmt = TRUE;
|
|
break;
|
|
case FOURCC_data:
|
|
strm->beginPos = FS_GetPosition(&strm->file);
|
|
strm->dataSize = chunkSize;
|
|
(void)FS_SeekFile(&strm->file, chunkSize, FS_SEEK_CUR);
|
|
fData = TRUE;
|
|
break;
|
|
default:
|
|
(void)FS_SeekFile(&strm->file, chunkSize, FS_SEEK_CUR);
|
|
break;
|
|
}
|
|
if (fFmt && fData)
|
|
{
|
|
return TRUE; // fmt と data を読み終えたら強制終了
|
|
}
|
|
|
|
size -= chunkSize;
|
|
}
|
|
|
|
if (size != 0)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// Vブランク割り込み処理
|
|
//
|
|
static void VBlankIntr(void)
|
|
{
|
|
// 割り込みチェックフラグ
|
|
OS_SetIrqCheckFlag(OS_IE_V_BLANK);
|
|
}
|