TwlIPL/build/systemMenu_RED/Launcher/ARM9/src/sound.c
yutaka 1b321cadab 属性変更 (subversionの設定をちゃんとしましょう)
git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@612 b08762b0-b915-fc4b-9d8c-17b2551a87ff
2008-02-07 09:51:53 +00:00

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);
}