/* unofficial gameplaySP kai
*
* Copyright (C) 2006 Exophase <exophase@gmail.com>
* Copyright (C) 2007 takka <takka@tfact.net>
* Copyright (C) 2007 ????? <?????>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/******************************************************************************
* sound.c
* サウンド周りの処理
******************************************************************************/
/******************************************************************************
* ヘッダファイルの読込み
******************************************************************************/
#include "common.h"
/******************************************************************************
* マクロ等の定義
******************************************************************************/
// TODO:パラメータの調整が必要(サウンドバッファの設定は現在無視されている/調整必要)
#define SAMPLE_COUNT PSP_AUDIO_SAMPLE_ALIGN(256) // サンプル数
//#define SAMPLE_COUNT 256
#define SAMPLE_SIZE (SAMPLE_COUNT * 2) // 1サンプルあたりのバッファ数
#define GBC_NOISE_WRAP_FULL 32767
#define GBC_NOISE_WRAP_HALF 126
#define RENDER_SAMPLE_NULL() \
// サウンドバッファにLEFT CHANNELのデータを書込む
#define RENDER_SAMPLE_LEFT() \
sound_buffer[sound_write_offset] += current_sample + \
FP16_16_TO_U32((next_sample - current_sample) * fifo_fractional) \
// サウンドバッファにRIGHT CHANNELのデータを書込む
#define RENDER_SAMPLE_RIGHT() \
sound_buffer[sound_write_offset + 1] += current_sample + \
FP16_16_TO_U32((next_sample - current_sample) * fifo_fractional) \
// サウンドバッファにLEFT/RIGHT CHANNELのデータを書込む
#define RENDER_SAMPLE_BOTH() \
dest_sample = current_sample + \
FP16_16_TO_U32((next_sample - current_sample) * fifo_fractional); \
sound_buffer[sound_write_offset] += dest_sample; \
sound_buffer[sound_write_offset + 1] += dest_sample \
#define RENDER_SAMPLES(type) \
while(fifo_fractional <= 0xFFFF) \
{ \
RENDER_SAMPLE_##type(); \
fifo_fractional += frequency_step; \
sound_write_offset = (sound_write_offset + 2) % BUFFER_SIZE; \
} \
#define UPDATE_VOLUME_CHANNEL_ENVELOPE(channel) \
volume_##channel = gbc_sound_envelope_volume_table[envelope_volume] * \
gbc_sound_channel_volume_table[gbc_sound_master_volume_##channel] * \
gbc_sound_master_volume_table[gbc_sound_master_volume] \
#define UPDATE_VOLUME_CHANNEL_NOENVELOPE(channel) \
volume_##channel = gs->wave_volume * \
gbc_sound_channel_volume_table[gbc_sound_master_volume_##channel] * \
gbc_sound_master_volume_table[gbc_sound_master_volume] \
#define UPDATE_VOLUME(type) \
UPDATE_VOLUME_CHANNEL_##type(left); \
UPDATE_VOLUME_CHANNEL_##type(right) \
#define UPDATE_TONE_SWEEP() \
if(gs->sweep_status) \
{ \
u32 sweep_ticks = gs->sweep_ticks - 1; \
\
if(sweep_ticks == 0) \
{ \
u32 rate = gs->rate; \
\
if(gs->sweep_direction) \
rate = rate - (rate >> gs->sweep_shift); \
else \
rate = rate + (rate >> gs->sweep_shift); \
\
if (rate > 2047) \
{ \
rate = 2047; \
gs->active_flag = 0; \
break; \
} \
\
frequency_step = FLOAT_TO_FP16_16(((131072.0 / (2048.0 - rate)) * 8.0) / SOUND_FREQUENCY); \
\
gs->frequency_step = frequency_step; \
gs->rate = rate; \
\
sweep_ticks = gs->sweep_initial_ticks; \
} \
gs->sweep_ticks = sweep_ticks; \
} \
#define UPDATE_TONE_NOSWEEP() \
#define UPDATE_TONE_ENVELOPE() \
if(gs->envelope_status) \
{ \
u32 envelope_ticks = gs->envelope_ticks - 1; \
envelope_volume = gs->envelope_volume; \
\
if(envelope_ticks == 0) \
{ \
if(gs->envelope_direction) \
{ \
if(envelope_volume != 15) \
envelope_volume = gs->envelope_volume + 1; \
} \
else \
{ \
if(envelope_volume != 0) \
envelope_volume = gs->envelope_volume - 1; \
} \
\
UPDATE_VOLUME(ENVELOPE); \
\
gs->envelope_volume = envelope_volume; \
gs->envelope_ticks = gs->envelope_initial_ticks; \
} \
else \
{ \
gs->envelope_ticks = envelope_ticks; \
} \
} \
#define UPDATE_TONE_NOENVELOPE() \
#define UPDATE_TONE_COUNTERS(envelope_op, sweep_op) \
tick_counter += gbc_sound_tick_step; \
if(tick_counter > 0xFFFF) \
{ \
tick_counter &= 0xFFFF; \
if(gs->length_status) \
{ \
u32 length_ticks = gs->length_ticks - 1; \
gs->length_ticks = length_ticks; \
\
if(length_ticks == 0) \
{ \
gs->active_flag = 0; \
break; \
} \
} \
UPDATE_TONE_##envelope_op(); \
UPDATE_TONE_##sweep_op(); \
} \
// サウンドバッファにLEFT CHANNELのデータを書込む
#define GBC_SOUND_RENDER_SAMPLE_LEFT() \
sound_buffer[sound_write_offset] += (current_sample * volume_left) >> 22 \
// サウンドバッファにRIGHT CHANNELのデータを書込む
#define GBC_SOUND_RENDER_SAMPLE_RIGHT() \
sound_buffer[sound_write_offset + 1] += (current_sample * volume_right) >> 22 \
// サウンドバッファにLEFT/RIGHT CHANNELのデータを書込む
#define GBC_SOUND_RENDER_SAMPLE_BOTH() \
GBC_SOUND_RENDER_SAMPLE_RIGHT(); \
GBC_SOUND_RENDER_SAMPLE_LEFT() \
#define GBC_SOUND_RENDER_SAMPLES(type, sample_length, envelope_op, sweep_op) \
for(i = 0; i < buffer_ticks; i++) \
{ \
current_sample = \
sample_data[FP16_16_TO_U32(sample_index) % sample_length]; \
GBC_SOUND_RENDER_SAMPLE_##type(); \
\
sample_index += frequency_step; \
sound_write_offset = (sound_write_offset + 2) % BUFFER_SIZE; \
\
UPDATE_TONE_COUNTERS(envelope_op, sweep_op); \
} \
#define GET_NOISE_SAMPLE_FULL() \
current_sample = \
((s32)(noise_table15[FP16_16_TO_U32(sample_index) >> 5] << \
(FP16_16_TO_U32(sample_index) & 0x1F)) >> 31) & 0x0F \
#define GET_NOISE_SAMPLE_HALF() \
current_sample = \
((s32)(noise_table7[FP16_16_TO_U32(sample_index) >> 5] << \
(FP16_16_TO_U32(sample_index) & 0x1F)) >> 31) & 0x0F \
#define GBC_SOUND_RENDER_NOISE(type, noise_type, envelope_op, sweep_op) \
for(i = 0; i < buffer_ticks; i++) \
{ \
GET_NOISE_SAMPLE_##noise_type(); \
GBC_SOUND_RENDER_SAMPLE_##type(); \
\
sample_index += frequency_step; \
\
if(sample_index >= U32_TO_FP16_16(GBC_NOISE_WRAP_##noise_type)) \
sample_index -= U32_TO_FP16_16(GBC_NOISE_WRAP_##noise_type); \
\
sound_write_offset = (sound_write_offset + 2) % BUFFER_SIZE; \
\
UPDATE_TONE_COUNTERS(envelope_op, sweep_op); \
} \
#define GBC_SOUND_RENDER_CHANNEL(type, sample_length, envelope_op, sweep_op) \
sound_write_offset = gbc_sound_buffer_index; \
sample_index = gs->sample_index; \
frequency_step = gs->frequency_step; \
tick_counter = gs->tick_counter; \
\
UPDATE_VOLUME(envelope_op); \
\
switch(gs->status) \
{ \
case GBC_SOUND_INACTIVE: \
break; \
\
case GBC_SOUND_LEFT: \
GBC_SOUND_RENDER_##type(LEFT, sample_length, envelope_op, sweep_op); \
break; \
\
case GBC_SOUND_RIGHT: \
GBC_SOUND_RENDER_##type(RIGHT, sample_length, envelope_op, sweep_op); \
break; \
\
case GBC_SOUND_LEFTRIGHT: \
GBC_SOUND_RENDER_##type(BOTH, sample_length, envelope_op, sweep_op); \
break; \
} \
\
gs->sample_index = sample_index; \
gs->tick_counter = tick_counter; \
#define GBC_SOUND_LOAD_WAVE_RAM(bank) \
wave_bank = wave_samples + (bank * 32); \
for(i = 0, i2 = 0; i < 16; i++, i2 += 2) \
{ \
current_sample = wave_ram[i]; \
wave_bank[i2] = (((current_sample >> 4) & 0x0F) - 8); \
wave_bank[i2 + 1] = ((current_sample & 0x0F) - 8); \
} \
#define CHECK_BUFFER() \
((gbc_sound_buffer_index - sound_read_offset) % BUFFER_SIZE) \
#define SET_AUDIO_BUFFER_SIZE() \
audio_buffer_size = SAMPLE_SIZE * (5 + g_game_config.audio_buffer_size_number) \
/******************************************************************************
* グローバル変数の定義
******************************************************************************/
DIRECT_SOUND_STRUCT direct_sound_channel[2];
GBC_SOUND_STRUCT gbc_sound_channel[4];
u32 sound_on = 0;
u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 };
u32 left_buffer;
/******************************************************************************
* ローカル変数の定義
******************************************************************************/
static u32 audio_buffer_size;
static s16 sound_buffer[BUFFER_SIZE]; // サウンド バッファ 2n = Left / 2n+1 = Right
static u32 sound_read_offset = 0; // サウンドバッファの読み込みオフセット
static SceUID sound_thread;
static u32 sound_last_cpu_ticks = 0;
static FIXED16_16 gbc_sound_tick_step;
volatile static u32 audio_thread_exit_flag; // オーディオスレッドの終了フラグ。
volatile static u32 pause_sound_flag;
/******************************************************************************
* ローカル関数の宣言
******************************************************************************/
static void init_sound_thread();
static void init_noise_table(u32 *table, u32 period, u32 bit_length);
static int sound_update_thread(SceSize args, void *argp);
/******************************************************************************
* グローバル関数の定義
******************************************************************************/
// Queue 1, 2, or 4 samples to the top of the DS FIFO, wrap around circularly
// マジカルバケーションの不具合修正
void sound_timer_queue32(u8 channel)
{
DIRECT_SOUND_STRUCT *ds = direct_sound_channel + channel;
u8 offset = channel * 4;
u8 i;
for (i = 0xA0; i <= 0xA3; i++)
{
ds->fifo[ds->fifo_top] = ADDRESS8(io_registers, i + offset);
ds->fifo_top = (ds->fifo_top + 1) % 32;
}
}
void sound_timer(FIXED16_16 frequency_step, u32 channel)
{
DIRECT_SOUND_STRUCT *ds = direct_sound_channel + channel;
FIXED16_16 fifo_fractional = ds->fifo_fractional;
u32 sound_write_offset = ds->buffer_index;
s16 current_sample, next_sample, dest_sample;
current_sample = ds->fifo[ds->fifo_base] << 4;
ds->fifo_base = (ds->fifo_base + 1) % 32;
next_sample = ds->fifo[ds->fifo_base] << 4;
if (sound_on == 1)
{
if (ds->volume == DIRECT_SOUND_VOLUME_50)
{
current_sample >>= 1;
next_sample >>= 1;
}
switch (ds->status)
{
case DIRECT_SOUND_INACTIVE:
RENDER_SAMPLES(NULL);
break;
case DIRECT_SOUND_RIGHT:
RENDER_SAMPLES(RIGHT);
break;
case DIRECT_SOUND_LEFT:
RENDER_SAMPLES(LEFT);
break;
case DIRECT_SOUND_LEFTRIGHT:
RENDER_SAMPLES(BOTH);
break;
}
}
else
{
RENDER_SAMPLES(NULL);
}
ds->buffer_index = sound_write_offset;
ds->fifo_fractional = FP16_16_FRACTIONAL_PART(fifo_fractional);
// マジカルバケーションで動作が遅くなるのが改善される
u8 fifo_length;
if (ds->fifo_top > ds->fifo_base)
fifo_length = ds->fifo_top - ds->fifo_base;
else
fifo_length = ds->fifo_top + (32 - ds->fifo_base);
if (fifo_length <= 16)
{
if (dma[1].direct_sound_channel == channel)
dma_transfer(dma + 1);
if (dma[2].direct_sound_channel == channel)
dma_transfer(dma + 2);
}
}
void sound_reset_fifo(u32 channel)
{
DIRECT_SOUND_STRUCT *ds = direct_sound_channel + channel;
memset(ds->fifo, 0, 32);
}
// Initial pattern data = 4bits (signed)
// Channel volume = 12bits
// Envelope volume = 14bits
// Master volume = 2bits
// Recalculate left and right volume as volume changes.
// To calculate the current sample, use (sample * volume) >> 16
// Square waves range from -8 (low) to 7 (high)
s8 square_pattern_duty[4][8] =
{
{ 0xF8, 0xF8, 0xF8, 0xF8, 0x07, 0xF8, 0xF8, 0xF8 },
{ 0xF8, 0xF8, 0xF8, 0xF8, 0x07, 0x07, 0xF8, 0xF8 },
{ 0xF8, 0xF8, 0x07, 0x07, 0x07, 0x07, 0xF8, 0xF8 },
{ 0x07, 0x07, 0x07, 0x07, 0xF8, 0xF8, 0x07, 0x07 },
};
s8 wave_samples[64];
u32 noise_table15[1024];
u32 noise_table7[4];
u32 gbc_sound_master_volume_table[4] = { 1, 2, 4, 0 };
u32 gbc_sound_channel_volume_table[8] =
{ FIXED_DIV(0, 7, 12),
FIXED_DIV(1, 7, 12),
FIXED_DIV(2, 7, 12),
FIXED_DIV(3, 7, 12),
FIXED_DIV(4, 7, 12),
FIXED_DIV(5, 7, 12),
FIXED_DIV(6, 7, 12),
FIXED_DIV(7, 7, 12)
};
u32 gbc_sound_envelope_volume_table[16] =
{ FIXED_DIV(0, 15, 14),
FIXED_DIV(1, 15, 14),
FIXED_DIV(2, 15, 14),
FIXED_DIV(3, 15, 14),
FIXED_DIV(4, 15, 14),
FIXED_DIV(5, 15, 14),
FIXED_DIV(6, 15, 14),
FIXED_DIV(7, 15, 14),
FIXED_DIV(8, 15, 14),
FIXED_DIV(9, 15, 14),
FIXED_DIV(10, 15, 14),
FIXED_DIV(11, 15, 14),
FIXED_DIV(12, 15, 14),
FIXED_DIV(13, 15, 14),
FIXED_DIV(14, 15, 14),
FIXED_DIV(15, 15, 14) };
u32 gbc_sound_buffer_index = 0;
u32 gbc_sound_last_cpu_ticks = 0;
u32 gbc_sound_partial_ticks = 0;
u32 gbc_sound_master_volume_left;
u32 gbc_sound_master_volume_right;
u32 gbc_sound_master_volume;
void update_gbc_sound(u32 cpu_ticks)
{
u32 i, i2;
GBC_SOUND_STRUCT *gs = gbc_sound_channel;
FIXED16_16 sample_index, frequency_step;
FIXED16_16 tick_counter;
u32 sound_write_offset;
s32 volume_left, volume_right;
u32 envelope_volume;
s32 current_sample;
u32 sound_status= ADDRESS16(io_registers, 0x84) & 0xFFF0;
s8 *sample_data;
s8 *wave_bank;
u8 *wave_ram = ((u8 *)io_registers) + 0x90;
u32 buffer_ticks = (cpu_ticks - gbc_sound_last_cpu_ticks) * (44100/4) + gbc_sound_partial_ticks;
gbc_sound_partial_ticks = buffer_ticks & 0x3FFFFF;
buffer_ticks = buffer_ticks >> 22 /* (16777216 / 4) */;
if (sound_on == 1)
{
// Channel 0
gs = gbc_sound_channel + 0;
if (gs->active_flag)
{
sound_status |= 0x01;
sample_data = gs->sample_data;
envelope_volume = gs->envelope_volume;
GBC_SOUND_RENDER_CHANNEL(SAMPLES, 8, ENVELOPE, SWEEP);
}
// Channel 1
gs = gbc_sound_channel + 1;
if (gs->active_flag)
{
sound_status |= 0x02;
sample_data = gs->sample_data;
envelope_volume = gs->envelope_volume;
GBC_SOUND_RENDER_CHANNEL(SAMPLES, 8, ENVELOPE, NOSWEEP);
}
// Channel 2
gs = gbc_sound_channel + 2;
if (gbc_sound_wave_update)
{
GBC_SOUND_LOAD_WAVE_RAM(gs->wave_bank);
gbc_sound_wave_update = 0;
}
if ((gs->active_flag) && (gs->master_enable))
{
sound_status |= 0x04;
sample_data = wave_samples;
if (gs->wave_type == 0)
{
if (gs->wave_bank == 1)
sample_data += 32;
GBC_SOUND_RENDER_CHANNEL(SAMPLES, 32, NOENVELOPE, NOSWEEP);
}
else
{
GBC_SOUND_RENDER_CHANNEL(SAMPLES, 64, NOENVELOPE, NOSWEEP);
}
}
// Channel 3
gs = gbc_sound_channel + 3;
if (gs->active_flag)
{
sound_status |= 0x08;
envelope_volume = gs->envelope_volume;
if (gs->noise_type == 1)
{
GBC_SOUND_RENDER_CHANNEL(NOISE, HALF, ENVELOPE, NOSWEEP);
}
else
{
GBC_SOUND_RENDER_CHANNEL(NOISE, FULL, ENVELOPE, NOSWEEP);
}
}
}
ADDRESS16(io_registers, 0x84) = sound_status;
gbc_sound_last_cpu_ticks = cpu_ticks;
// サウンドタイミングの調整
gbc_sound_buffer_index =(gbc_sound_buffer_index + (buffer_ticks << 1)) % BUFFER_SIZE;
}
int audio_handle; // オーディオチャンネルのハンドル。
void init_sound_thread()
{
// オーディオチャンネルの取得。
audio_handle = sceAudioChReserve( PSP_AUDIO_NEXT_CHANNEL, SAMPLE_COUNT, PSP_AUDIO_FORMAT_STEREO);
// sceAudioSRCChReserve(SAMPLE_COUNT, SOUND_FREQUENCY, 2);
// サウンド スレッドの作成
sound_thread = sceKernelCreateThread("Sound thread", sound_update_thread, 0x8, 0x8000, 0, NULL);
if (sound_thread < 0) quit(1);
//スレッドの開始
sceKernelStartThread(sound_thread, 0, 0);
}
void init_sound()
{
SET_AUDIO_BUFFER_SIZE();
gbc_sound_tick_step = FLOAT_TO_FP16_16(256.0 / SOUND_FREQUENCY);
init_noise_table(noise_table15, 32767, 14);
init_noise_table(noise_table7, 127, 6);
// 変数等の初期化
reset_sound();
// サウンド スレッドの初期化
init_sound_thread();
}
void reset_sound()
{
DIRECT_SOUND_STRUCT *ds = direct_sound_channel;
GBC_SOUND_STRUCT *gs = gbc_sound_channel;
u32 i;
audio_thread_exit_flag = 0;
sound_on = 0;
memset(sound_buffer, 0, sizeof(sound_buffer));
for (i = 0; i < 2; i++, ds++)
{
ds->buffer_index = 0;
ds->status = DIRECT_SOUND_INACTIVE;
ds->fifo_top = 0;
ds->fifo_base = 0;
ds->fifo_fractional = 0;
ds->last_cpu_ticks = 0;
memset(ds->fifo, 0, sizeof(ds->fifo));
}
gbc_sound_buffer_index = 0;
gbc_sound_last_cpu_ticks = 0;
gbc_sound_partial_ticks = 0;
sound_read_offset = 0;
gbc_sound_master_volume_left = 0;
gbc_sound_master_volume_right = 0;
gbc_sound_master_volume = 0;
memset(wave_samples, 0, sizeof(wave_samples));
pause_sound(1);
for (i = 0; i < 4; i++, gs++)
{
gs->status = GBC_SOUND_INACTIVE;
gs->sample_data = square_pattern_duty[2];
gs->active_flag = 0;
}
}
void pause_sound(u32 flag)
{
pause_sound_flag = flag;
SET_AUDIO_BUFFER_SIZE();
}
void sound_exit()
{
audio_thread_exit_flag = 1;
}
#define sound_savestate_body(type, ver) \
{ \
FILE_##type##_VARIABLE(g_state_buffer_ptr, sound_on); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, sound_read_offset); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, sound_last_cpu_ticks); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_buffer_index); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_last_cpu_ticks); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_partial_ticks); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_master_volume_left); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_master_volume_right); \
FILE_##type##_VARIABLE(g_state_buffer_ptr, gbc_sound_master_volume); \
FILE_##type##_ARRAY(g_state_buffer_ptr, wave_samples); \
FILE_##type##_ARRAY(g_state_buffer_ptr, direct_sound_channel); \
FILE_##type##_ARRAY(g_state_buffer_ptr, gbc_sound_channel); \
} \
void sound_read_mem_savestate(u32 ver)
sound_savestate_body(READ_MEM, ver);
void sound_write_mem_savestate(u32 ver)
sound_savestate_body(WRITE_MEM, ver);
/******************************************************************************
* ローカル関数の定義
******************************************************************************/
/*--------------------------------------------------------
サウンド スレッド
--------------------------------------------------------*/
static int sound_update_thread(SceSize args, void *argp)
{
s16 buffer[2][SAMPLE_SIZE];
u32 loop;
u32 buffer_num = 0;
s16 sample;
// TODO:初期設定に移動
sound_read_offset = 0;
memset(buffer, 0, sizeof(buffer) / 2);
left_buffer = 0;
// メインループ
while(!audio_thread_exit_flag)
{
left_buffer = CHECK_BUFFER() / SAMPLE_SIZE;
buffer_num = g_gpsp_config.enable_audio;
if((CHECK_BUFFER() > SAMPLE_SIZE) && (pause_sound_flag == 0))
{
// TODO memcopy*2と どっちが速い?
for(loop = 0; loop < SAMPLE_SIZE; loop++)
{
sample = sound_buffer[sound_read_offset];
if(sample > 2047) sample = 2047;
if(sample < -2048) sample = -2048;
// if(sample > 4095) sample = 4095;
// if(sample < -4096) sample = -4096;
buffer[1][loop] = sample << 4;
sound_buffer[sound_read_offset] = 0;
sound_read_offset = (sound_read_offset + 1) & BUFFER_SIZE;
}
}
else
{
if (pause_sound_flag == 1)
buffer_num = 0; // 全て0のデーターを再生
else
buffer_num = 1; // 前回のデーターをそのまま再生
}
sceAudioOutputPannedBlocking(audio_handle, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, &buffer[buffer_num][0]);
// sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, &buffer[buffer_num][0]);
// sceKernelDelayThread((SAMPLE_COUNT * 1000 * 1000 * 0.25) / SOUND_FREQUENCY);
}
sceAudioSRCChRelease();
sceKernelExitThread(0);
return 0;
}
// Special thanks to blarrg for the LSFR frequency used in Meridian, as posted
// on the forum at http://meridian.overclocked.org:
// http://meridian.overclocked.org/cgi-bin/wwwthreads/showpost.pl?Board=merid
// angeneraldiscussion&Number=2069&page=0&view=expanded&mode=threaded&sb=4
// Hope you don't mind me borrowing it ^_-
void init_noise_table(u32 *table, u32 period, u32 bit_length)
{
u32 shift_register = 0xFF;
u32 mask = ~(1 << bit_length);
s32 table_pos, bit_pos;
u32 current_entry;
u32 table_period = (period + 31) / 32;
// Bits are stored in reverse order so they can be more easily moved to
// bit 31, for sign extended shift down.
for (table_pos = 0; table_pos < table_period; table_pos++)
{
current_entry = 0;
for (bit_pos = 31; bit_pos >= 0; bit_pos--)
{
current_entry |= (shift_register & 0x01) << bit_pos;
shift_register =((1 & (shift_register ^ (shift_register >> 1)))
<< bit_length) |((shift_register >> 1) & mask);
}
table[table_pos] = current_entry;
}
}
// サウンドデータが一定以下になるまで、エミュレータを停止
void synchronize_sound()
{
while(CHECK_BUFFER() >= audio_buffer_size) // TODO:調整必要
sceKernelDelayThread((SAMPLE_COUNT * 1000) / SOUND_FREQUENCY);
}