2007-11-14 12:28:27 +00:00
|
|
|
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
|
|
// Copyright (C) 2004 Forgotten and the VBA development team
|
|
|
|
// Copyright (C) 2004-2006 VBA development team
|
2007-12-05 04:25:47 +00:00
|
|
|
// Copyright (C) 2007 Shay Green (blargg)
|
2007-11-14 12:28:27 +00:00
|
|
|
|
|
|
|
// 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#include "Sound.h"
|
|
|
|
|
|
|
|
#include "GBA.h"
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "Util.h"
|
2007-12-05 04:25:47 +00:00
|
|
|
#include "Port.h"
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
#include "gb/gb_apu/Gb_Apu.h"
|
|
|
|
#include "gb/gb_apu/Multi_Buffer.h"
|
2007-11-14 12:28:27 +00:00
|
|
|
|
|
|
|
#define USE_TICKS_AS 380
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
extern bool stopState; // TODO: silence sound when true
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
int soundQuality = 2; // sample rate = 44100 / soundQuality
|
|
|
|
int soundInterpolation = 0; // 1 if PCM should have low-pass filtering
|
|
|
|
int soundVolume = 0; // emulator volume code (not linear)
|
|
|
|
static int soundVolume_;
|
|
|
|
bool soundEcho = false;
|
|
|
|
bool soundLowPass = false;
|
|
|
|
bool soundReverse = false;
|
|
|
|
int soundEnableFlag = 0x3ff; // emulator channels enabled
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
// Number of 16.8 MHz clocks until soundTick() will be called
|
2007-11-14 12:28:27 +00:00
|
|
|
int soundTicks = soundQuality * USE_TICKS_AS;
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
// Number of 16.8 MHz clocks between calls to soundTick()
|
|
|
|
int SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS;
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
u16 soundFinalWave [1470]; // 16-bit SIGNED stereo sample buffer
|
|
|
|
int soundBufferLen = 1470; // size of sound buffer in BYTES
|
|
|
|
int soundBufferTotalLen = 14700;
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void interp_rate() { /* empty for now */ }
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
// Unknown purpose
|
|
|
|
int soundDebug = 0;
|
|
|
|
u32 soundNextPosition = 0;
|
|
|
|
bool soundOffFlag = false;
|
|
|
|
bool soundPaused = true;
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
class Gba_Pcm {
|
|
|
|
public:
|
|
|
|
void init();
|
|
|
|
void apply_control( int idx );
|
|
|
|
void update( int dac );
|
|
|
|
void end_frame( blip_time_t );
|
|
|
|
|
|
|
|
private:
|
|
|
|
Blip_Buffer* output;
|
|
|
|
blip_time_t last_time;
|
|
|
|
int last_amp;
|
|
|
|
int shift;
|
2007-11-14 12:28:27 +00:00
|
|
|
};
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
class Gba_Pcm_Fifo {
|
|
|
|
public:
|
|
|
|
int which;
|
|
|
|
Gba_Pcm pcm;
|
|
|
|
|
|
|
|
void write_control( int data );
|
|
|
|
void write_fifo( int data );
|
|
|
|
void timer_overflowed( int which_timer );
|
|
|
|
|
|
|
|
private:
|
|
|
|
int readIndex;
|
|
|
|
int count;
|
|
|
|
int writeIndex;
|
|
|
|
bool enabled;
|
|
|
|
int timer;
|
|
|
|
u8 fifo [32];
|
|
|
|
int dac;
|
2007-11-14 12:28:27 +00:00
|
|
|
};
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static Gba_Pcm_Fifo pcm [2];
|
|
|
|
static Gb_Apu* gb_apu;
|
|
|
|
static Stereo_Buffer* stereo_buffer;
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static Blip_Synth<blip_best_quality,1> pcm_synth [3]; // 32 kHz, 16 kHz, 8 kHz
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static inline blip_time_t blip_time()
|
|
|
|
{
|
|
|
|
return SOUND_CLOCK_TICKS - soundTicks;
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm::init()
|
|
|
|
{
|
|
|
|
output = 0;
|
|
|
|
last_time = 0;
|
|
|
|
last_amp = 0;
|
|
|
|
shift = 0;
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm::apply_control( int idx )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
shift = ~ioMem [SGCNT0_H] >> (2 + idx) & 1;
|
|
|
|
|
|
|
|
int ch = 0;
|
|
|
|
if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) )
|
|
|
|
ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3;
|
|
|
|
|
|
|
|
Blip_Buffer* out = 0;
|
|
|
|
switch ( ch )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
case 1: out = stereo_buffer->right(); break;
|
|
|
|
case 2: out = stereo_buffer->left(); break;
|
|
|
|
case 3: out = stereo_buffer->center(); break;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
2007-12-05 04:25:47 +00:00
|
|
|
|
|
|
|
if ( output != out )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( output )
|
|
|
|
{
|
|
|
|
output->set_modified();
|
|
|
|
pcm_synth [0].offset( blip_time(), -last_amp, output );
|
|
|
|
}
|
|
|
|
last_amp = 0;
|
|
|
|
output = out;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm::end_frame( blip_time_t time )
|
|
|
|
{
|
|
|
|
last_time -= time;
|
|
|
|
if ( last_time < -2048 )
|
|
|
|
last_time = -2048;
|
|
|
|
|
|
|
|
if ( output )
|
|
|
|
output->set_modified();
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm::update( int dac )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( output )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
blip_time_t time = blip_time();
|
|
|
|
|
|
|
|
dac >>= shift;
|
|
|
|
int delta = dac - last_amp;
|
|
|
|
if ( delta )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
last_amp = dac;
|
|
|
|
|
|
|
|
int filter = 0;
|
|
|
|
if ( soundInterpolation )
|
|
|
|
{
|
|
|
|
// base filtering on how long since last sample was output
|
|
|
|
int period = time - last_time;
|
|
|
|
|
|
|
|
int idx = (unsigned) period / 512;
|
|
|
|
if ( idx >= 3 )
|
|
|
|
idx = 3;
|
|
|
|
|
|
|
|
static int const filters [4] = { 0, 0, 1, 2 };
|
|
|
|
filter = filters [idx];
|
|
|
|
}
|
|
|
|
|
|
|
|
pcm_synth [filter].offset( time, delta, output );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
2007-12-05 04:25:47 +00:00
|
|
|
last_time = time;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
2007-12-05 04:25:47 +00:00
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
|
|
|
|
{
|
|
|
|
if ( which_timer == timer && enabled )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( count <= 16 )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// Need to fill FIFO
|
|
|
|
CPUCheckDMA( 3, which ? 4 : 2 );
|
|
|
|
if ( count <= 16 )
|
|
|
|
{
|
|
|
|
// Not filled by DMA, so fill with silence
|
|
|
|
int reg = which ? FIFOB_L : FIFOA_L;
|
|
|
|
for ( int n = 4; n--; )
|
|
|
|
{
|
|
|
|
soundEvent(reg , (u16)0);
|
|
|
|
soundEvent(reg+2, (u16)0);
|
|
|
|
}
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
2007-12-05 04:25:47 +00:00
|
|
|
|
|
|
|
// Read next sample from FIFO
|
|
|
|
count--;
|
|
|
|
dac = (s8) fifo [readIndex];
|
|
|
|
readIndex = (readIndex + 1) & 31;
|
|
|
|
pcm.update( dac );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm_Fifo::write_control( int data )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
enabled = (data & 0x0300) ? true : false;
|
|
|
|
timer = (data & 0x0400) ? 1 : 0;
|
|
|
|
|
|
|
|
if ( data & 0x0800 )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// Reset
|
|
|
|
writeIndex = 0;
|
|
|
|
readIndex = 0;
|
|
|
|
count = 0;
|
|
|
|
dac = 0;
|
|
|
|
memset( fifo, 0, sizeof fifo );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
2007-12-05 04:25:47 +00:00
|
|
|
|
|
|
|
pcm.apply_control( which );
|
|
|
|
pcm.update( dac );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void Gba_Pcm_Fifo::write_fifo( int data )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
fifo [writeIndex ] = data & 0xFF;
|
|
|
|
fifo [writeIndex+1] = data >> 8;
|
|
|
|
count += 2;
|
|
|
|
writeIndex = (writeIndex + 2) & 31;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void apply_control()
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
pcm [0].pcm.apply_control( 0 );
|
|
|
|
pcm [1].pcm.apply_control( 1 );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static int gba_to_gb_sound( int addr )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
static const int table [0x40] =
|
|
|
|
{
|
|
|
|
0xFF10, 0,0xFF11,0xFF12,0xFF13,0xFF14, 0, 0,
|
|
|
|
0xFF16,0xFF17, 0, 0,0xFF18,0xFF19, 0, 0,
|
|
|
|
0xFF1A, 0,0xFF1B,0xFF1C,0xFF1D,0xFF1E, 0, 0,
|
|
|
|
0xFF20,0xFF21, 0, 0,0xFF22,0xFF23, 0, 0,
|
|
|
|
0xFF24,0xFF25, 0, 0,0xFF26, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,
|
|
|
|
0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F,
|
|
|
|
};
|
|
|
|
if ( addr >= 0x60 && addr < 0xA0 )
|
|
|
|
return table [addr - 0x60];
|
|
|
|
return 0;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundEvent(u32 address, u8 data)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
int gb_addr = gba_to_gb_sound( address );
|
|
|
|
if ( gb_addr )
|
|
|
|
{
|
|
|
|
ioMem[address] = data;
|
|
|
|
gb_apu->write_register( blip_time(), gb_addr, data );
|
|
|
|
|
|
|
|
if ( address == NR52 )
|
|
|
|
apply_control();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: what about byte writes to SGCNT0_H etc.?
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void apply_volume( bool apu_only = false )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( !apu_only )
|
|
|
|
soundVolume_ = soundVolume;
|
|
|
|
|
|
|
|
// Emulator volume
|
|
|
|
static float const vols [6] = { 1, 2, 3, 4, 0.25, 0.5 };
|
|
|
|
double const volume = vols [soundVolume_];
|
|
|
|
|
|
|
|
if ( gb_apu )
|
|
|
|
{
|
|
|
|
static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
|
|
|
|
gb_apu->volume( volume * apu_vols [ioMem [SGCNT0_H] & 3] );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !apu_only )
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < 3; i++ )
|
|
|
|
pcm_synth [i].volume( 0.66 / 256 * volume );
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void soundEvent(u32 address, u16 data)
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
switch ( address )
|
|
|
|
{
|
|
|
|
case SGCNT0_H:
|
|
|
|
WRITE16LE( &ioMem[address], data );
|
|
|
|
pcm [0].write_control( data );
|
|
|
|
pcm [1].write_control( data >> 4 );
|
|
|
|
apply_volume( true );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FIFOA_L:
|
|
|
|
case FIFOA_H:
|
|
|
|
pcm [0].write_fifo( data );
|
|
|
|
WRITE16LE( &ioMem[address], data );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FIFOB_L:
|
|
|
|
case FIFOB_H:
|
|
|
|
pcm [1].write_fifo( data );
|
|
|
|
WRITE16LE( &ioMem[address], data );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x88:
|
|
|
|
data &= 0xC3FF;
|
|
|
|
WRITE16LE( &ioMem[address], data );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
soundEvent( address & ~1, (u8) (data ) ); // even
|
|
|
|
soundEvent( address | 1, (u8) (data >> 8) ); // odd
|
|
|
|
break;
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void soundTimerOverflow(int timer)
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
pcm [0].timer_overflowed( timer );
|
|
|
|
pcm [1].timer_overflowed( timer );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void end_frame( blip_time_t time )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
pcm [0].pcm.end_frame( time );
|
|
|
|
pcm [1].pcm.end_frame( time );
|
|
|
|
|
|
|
|
gb_apu ->end_frame( time );
|
|
|
|
stereo_buffer->end_frame( time );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void flush_samples()
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// number of samples in output buffer
|
|
|
|
int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
|
|
|
|
|
|
|
|
// Keep filling and writing soundFinalWave until it can't be fully filled
|
|
|
|
while ( stereo_buffer->samples_avail() >= out_buf_size )
|
|
|
|
{
|
|
|
|
stereo_buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size );
|
|
|
|
if(systemSoundOn)
|
|
|
|
{
|
|
|
|
if(soundPaused)
|
|
|
|
soundResume();
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
systemWriteDataToSoundBuffer();
|
|
|
|
}
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void soundTick()
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( systemSoundOn && gb_apu && stereo_buffer )
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// Run sound hardware to present
|
|
|
|
end_frame( SOUND_CLOCK_TICKS );
|
|
|
|
|
|
|
|
flush_samples();
|
|
|
|
|
|
|
|
if ( soundVolume_ != soundVolume )
|
|
|
|
apply_volume();
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
void (*psoundTickfn)() = soundTick;
|
2007-11-14 12:28:27 +00:00
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void apply_muting()
|
2007-11-14 12:28:27 +00:00
|
|
|
{
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( !stereo_buffer || !ioMem )
|
|
|
|
return;
|
|
|
|
// PCM
|
|
|
|
apply_control();
|
|
|
|
|
|
|
|
if ( gb_apu )
|
|
|
|
{
|
|
|
|
// APU
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
|
|
{
|
|
|
|
if ( soundEnableFlag >> i & 1 )
|
|
|
|
gb_apu->set_output( stereo_buffer->center(),
|
|
|
|
stereo_buffer->left(), stereo_buffer->right(), i );
|
|
|
|
else
|
|
|
|
gb_apu->set_output( 0, 0, 0, i );
|
|
|
|
}
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
2007-12-05 04:25:47 +00:00
|
|
|
static void remake_stereo_buffer()
|
|
|
|
{
|
|
|
|
// Clears pointers kept to old stereo_buffer
|
|
|
|
pcm [0].pcm.init();
|
|
|
|
pcm [1].pcm.init();
|
|
|
|
|
|
|
|
// Stereo_Buffer
|
|
|
|
delete stereo_buffer;
|
|
|
|
stereo_buffer = 0;
|
|
|
|
|
|
|
|
stereo_buffer = new Stereo_Buffer; // TODO: handle out of memory
|
|
|
|
long const sample_rate = 44100 / soundQuality;
|
|
|
|
stereo_buffer->set_sample_rate( sample_rate ); // TODO: handle out of memory
|
|
|
|
stereo_buffer->clock_rate( gb_apu->clock_rate );
|
|
|
|
|
|
|
|
// PCM
|
|
|
|
pcm [0].which = 0;
|
|
|
|
pcm [1].which = 1;
|
|
|
|
for ( int i = 0; i < 3; i++ )
|
|
|
|
{
|
|
|
|
int freq = 32768 >> i;
|
|
|
|
pcm_synth [i].treble_eq( blip_eq_t( 0, 0, sample_rate, freq / 2 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// APU
|
|
|
|
if ( !gb_apu )
|
|
|
|
gb_apu = new Gb_Apu; // TODO: handle out of memory
|
|
|
|
|
|
|
|
gb_apu->reset( gb_apu->mode_agb, true );
|
|
|
|
|
|
|
|
apply_muting();
|
|
|
|
apply_volume();
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void setsystemSoundOn(bool value)
|
|
|
|
{
|
|
|
|
systemSoundOn = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setsoundPaused(bool value)
|
|
|
|
{
|
|
|
|
soundPaused = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void soundShutdown()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
systemSoundShutdown();
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundPause()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
systemSoundPause();
|
|
|
|
setsoundPaused(true);
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundResume()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
systemSoundResume();
|
|
|
|
setsoundPaused(false);
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundEnable(int channels)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
soundEnableFlag = channels;
|
|
|
|
apply_muting();
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundDisable(int channels)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
soundEnableFlag &= ~channels;
|
|
|
|
apply_muting();
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int soundGetEnable()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
return (soundEnableFlag & 0x30f);
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundReset()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
systemSoundReset();
|
|
|
|
|
|
|
|
remake_stereo_buffer();
|
|
|
|
|
|
|
|
setsoundPaused(true);
|
|
|
|
SOUND_CLOCK_TICKS = 167772;
|
|
|
|
soundTicks = SOUND_CLOCK_TICKS;
|
|
|
|
|
|
|
|
soundNextPosition = 0;
|
|
|
|
|
|
|
|
soundEvent( NR52, (u8) 0x80 );
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool soundInit()
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( !systemSoundInit() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
soundPaused = true;
|
|
|
|
return true;
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundSetQuality(int quality)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
if ( soundQuality != quality )
|
|
|
|
{
|
|
|
|
if ( systemCanChangeSoundQuality() )
|
|
|
|
{
|
|
|
|
if ( !soundOffFlag )
|
|
|
|
soundShutdown();
|
|
|
|
|
|
|
|
soundQuality = quality;
|
|
|
|
soundNextPosition = 0;
|
|
|
|
|
|
|
|
if ( !soundOffFlag )
|
|
|
|
soundInit();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
soundQuality = quality;
|
|
|
|
soundNextPosition = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
remake_stereo_buffer();
|
|
|
|
}
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundSaveGame(gzFile gzFile)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// TODO: implement
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void soundReadGame(gzFile gzFile, int version)
|
|
|
|
{
|
2007-12-05 04:25:47 +00:00
|
|
|
// TODO: implement
|
2007-11-14 12:28:27 +00:00
|
|
|
}
|