Added support for OpenAL software audio mixing
Updated GBA sound engine to support new audiosavestate format Several improvements to audio cores Updated sample buffer length in DirectSound
This commit is contained in:
parent
6363b66a21
commit
5eed13e880
|
@ -31,7 +31,8 @@
|
|||
#define SAVE_GAME_VERSION_7 7
|
||||
#define SAVE_GAME_VERSION_8 8
|
||||
#define SAVE_GAME_VERSION_9 9
|
||||
#define SAVE_GAME_VERSION SAVE_GAME_VERSION_9
|
||||
#define SAVE_GAME_VERSION_10 10
|
||||
#define SAVE_GAME_VERSION SAVE_GAME_VERSION_10
|
||||
|
||||
typedef struct {
|
||||
u8 *address;
|
||||
|
|
361
src/Sound.cpp
361
src/Sound.cpp
|
@ -27,40 +27,42 @@
|
|||
#include "Util.h"
|
||||
#include "Port.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
//#include <float.h>
|
||||
#endif
|
||||
|
||||
#include "gb/gb_apu/Gb_Apu.h"
|
||||
#include "gb/gb_apu/Multi_Buffer.h"
|
||||
|
||||
#define USE_TICKS_AS 380
|
||||
|
||||
extern bool stopState; // TODO: silence sound when true
|
||||
|
||||
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)
|
||||
int soundQuality = 2;
|
||||
int soundInterpolation = 0;
|
||||
float soundFiltering = 1;
|
||||
static float soundFiltering_;
|
||||
int soundVolume = 0;
|
||||
static int soundVolume_;
|
||||
bool soundEcho = false;
|
||||
bool soundLowPass = false;
|
||||
bool soundReverse = false;
|
||||
int soundEnableFlag = 0x3ff; // emulator channels enabled
|
||||
|
||||
// Number of 16.8 MHz clocks until soundTick() will be called
|
||||
int soundTicks = soundQuality * USE_TICKS_AS;
|
||||
int const SOUND_CLOCK_TICKS_ = 167772;
|
||||
int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_;
|
||||
int soundTicks = SOUND_CLOCK_TICKS_;
|
||||
|
||||
// Number of 16.8 MHz clocks between calls to soundTick()
|
||||
int SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS;
|
||||
|
||||
u16 soundFinalWave [1470]; // 16-bit SIGNED stereo sample buffer
|
||||
int soundBufferLen = 1470; // size of sound buffer in BYTES
|
||||
u16 soundFinalWave [1470];
|
||||
int soundBufferLen = 1470;
|
||||
int soundBufferTotalLen = 14700;
|
||||
|
||||
void interp_rate() { /* empty for now */ }
|
||||
|
||||
// Unknown purpose
|
||||
int soundDebug = 0;
|
||||
u32 soundNextPosition = 0;
|
||||
bool soundOffFlag = false;
|
||||
bool soundPaused = true;
|
||||
|
||||
bool soundLowPass = false;
|
||||
bool soundReverse = false;
|
||||
|
||||
void interp_rate() { /* empty for now */ }
|
||||
|
||||
class Gba_Pcm {
|
||||
public:
|
||||
void init();
|
||||
|
@ -83,15 +85,17 @@ public:
|
|||
void write_control( int data );
|
||||
void write_fifo( int data );
|
||||
void timer_overflowed( int which_timer );
|
||||
|
||||
private:
|
||||
|
||||
// public only so save state routines can access it
|
||||
int readIndex;
|
||||
int count;
|
||||
int writeIndex;
|
||||
bool enabled;
|
||||
int timer;
|
||||
u8 fifo [32];
|
||||
int dac;
|
||||
private:
|
||||
|
||||
int timer;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static Gba_Pcm_Fifo pcm [2];
|
||||
|
@ -157,7 +161,7 @@ void Gba_Pcm::update( int dac )
|
|||
{
|
||||
blip_time_t time = blip_time();
|
||||
|
||||
dac >>= shift;
|
||||
dac = (s8) dac >> shift;
|
||||
int delta = dac - last_amp;
|
||||
if ( delta )
|
||||
{
|
||||
|
@ -193,7 +197,7 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
|
|||
CPUCheckDMA( 3, which ? 4 : 2 );
|
||||
if ( count <= 16 )
|
||||
{
|
||||
// Not filled by DMA, so fill with silence
|
||||
// Not filled by DMA, so fill with 16 bytes of silence
|
||||
int reg = which ? FIFOB_L : FIFOA_L;
|
||||
for ( int n = 4; n--; )
|
||||
{
|
||||
|
@ -205,7 +209,7 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
|
|||
|
||||
// Read next sample from FIFO
|
||||
count--;
|
||||
dac = (s8) fifo [readIndex];
|
||||
dac = fifo [readIndex];
|
||||
readIndex = (readIndex + 1) & 31;
|
||||
pcm.update( dac );
|
||||
}
|
||||
|
@ -299,15 +303,20 @@ static void apply_volume( bool apu_only = false )
|
|||
}
|
||||
}
|
||||
|
||||
static void write_SGCNT0_H( int data )
|
||||
{
|
||||
WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F );
|
||||
pcm [0].write_control( data );
|
||||
pcm [1].write_control( data >> 4 );
|
||||
apply_volume( true );
|
||||
}
|
||||
|
||||
void soundEvent(u32 address, u16 data)
|
||||
{
|
||||
switch ( address )
|
||||
{
|
||||
case SGCNT0_H:
|
||||
WRITE16LE( &ioMem[address], data );
|
||||
pcm [0].write_control( data );
|
||||
pcm [1].write_control( data >> 4 );
|
||||
apply_volume( true );
|
||||
write_SGCNT0_H( data );
|
||||
break;
|
||||
|
||||
case FIFOA_L:
|
||||
|
@ -351,6 +360,9 @@ static void end_frame( blip_time_t time )
|
|||
|
||||
static void flush_samples()
|
||||
{
|
||||
// soundBufferLen should have a whole number of sample pairs
|
||||
assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 );
|
||||
|
||||
// number of samples in output buffer
|
||||
int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
|
||||
|
||||
|
@ -368,6 +380,22 @@ static void flush_samples()
|
|||
}
|
||||
}
|
||||
|
||||
static void apply_filtering()
|
||||
{
|
||||
soundFiltering_ = soundFiltering;
|
||||
|
||||
int const base_freq = (int) (32768 - soundFiltering_ * 16384);
|
||||
int const nyquist = stereo_buffer->sample_rate() / 2;
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
int cutoff = base_freq >> i;
|
||||
if ( cutoff > nyquist )
|
||||
cutoff = nyquist;
|
||||
pcm_synth [i].treble_eq( blip_eq_t( 0, 0, stereo_buffer->sample_rate(), cutoff ) );
|
||||
}
|
||||
}
|
||||
|
||||
static void soundTick()
|
||||
{
|
||||
if ( systemSoundOn && gb_apu && stereo_buffer )
|
||||
|
@ -377,6 +405,9 @@ static void soundTick()
|
|||
|
||||
flush_samples();
|
||||
|
||||
if ( soundFiltering_ != soundFiltering )
|
||||
apply_filtering();
|
||||
|
||||
if ( soundVolume_ != soundVolume )
|
||||
apply_volume();
|
||||
}
|
||||
|
@ -386,9 +417,9 @@ void (*psoundTickfn)() = soundTick;
|
|||
|
||||
static void apply_muting()
|
||||
{
|
||||
|
||||
if ( !stereo_buffer || !ioMem )
|
||||
return;
|
||||
if ( !stereo_buffer || !ioMem )
|
||||
return;
|
||||
|
||||
// PCM
|
||||
apply_control();
|
||||
|
||||
|
@ -406,8 +437,27 @@ if ( !stereo_buffer || !ioMem )
|
|||
}
|
||||
}
|
||||
|
||||
static void reset_apu()
|
||||
{
|
||||
gb_apu->reset( gb_apu->mode_agb, true );
|
||||
|
||||
if ( stereo_buffer )
|
||||
stereo_buffer->clear();
|
||||
|
||||
soundTicks = SOUND_CLOCK_TICKS;
|
||||
}
|
||||
|
||||
static void remake_stereo_buffer()
|
||||
{
|
||||
if ( !ioMem )
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Direct3D might mess with FPU mode. Try uncommenting if more sound problems
|
||||
// occur (also need to uncomment #include <float.h> above).
|
||||
//_fpreset();
|
||||
#endif
|
||||
|
||||
// Clears pointers kept to old stereo_buffer
|
||||
pcm [0].pcm.init();
|
||||
pcm [1].pcm.init();
|
||||
|
@ -424,17 +474,14 @@ static void remake_stereo_buffer()
|
|||
// 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 ) );
|
||||
}
|
||||
apply_filtering();
|
||||
|
||||
// APU
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu; // TODO: handle out of memory
|
||||
|
||||
gb_apu->reset( gb_apu->mode_agb, true );
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
apply_muting();
|
||||
apply_volume();
|
||||
|
@ -458,7 +505,7 @@ void soundShutdown()
|
|||
void soundPause()
|
||||
{
|
||||
systemSoundPause();
|
||||
setsoundPaused(true);
|
||||
setsoundPaused(true);
|
||||
}
|
||||
|
||||
void soundResume()
|
||||
|
@ -489,10 +536,11 @@ void soundReset()
|
|||
systemSoundReset();
|
||||
|
||||
remake_stereo_buffer();
|
||||
reset_apu();
|
||||
|
||||
setsoundPaused(true);
|
||||
SOUND_CLOCK_TICKS = 167772;
|
||||
soundTicks = SOUND_CLOCK_TICKS;
|
||||
SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_;
|
||||
soundTicks = SOUND_CLOCK_TICKS_;
|
||||
|
||||
soundNextPosition = 0;
|
||||
|
||||
|
@ -533,12 +581,235 @@ void soundSetQuality(int quality)
|
|||
}
|
||||
}
|
||||
|
||||
void soundSaveGame(gzFile gzFile)
|
||||
static int dummy_state [16];
|
||||
|
||||
#define SKIP( type, name ) { dummy_state, sizeof (type) }
|
||||
|
||||
#define LOAD( type, name ) { &name, sizeof (type) }
|
||||
|
||||
static struct {
|
||||
gb_apu_state_t apu;
|
||||
|
||||
// old state
|
||||
u8 soundDSAValue;
|
||||
int soundDSBValue;
|
||||
} state;
|
||||
|
||||
// Old GBA sound state format
|
||||
static variable_desc old_gba_state [] =
|
||||
{
|
||||
// TODO: implement
|
||||
SKIP( int, soundPaused ),
|
||||
SKIP( int, soundPlay ),
|
||||
SKIP( int, soundTicks ),
|
||||
SKIP( int, SOUND_CLOCK_TICKS ),
|
||||
SKIP( int, soundLevel1 ),
|
||||
SKIP( int, soundLevel2 ),
|
||||
SKIP( int, soundBalance ),
|
||||
SKIP( int, soundMasterOn ),
|
||||
SKIP( int, soundIndex ),
|
||||
SKIP( int, sound1On ),
|
||||
SKIP( int, sound1ATL ),
|
||||
SKIP( int, sound1Skip ),
|
||||
SKIP( int, sound1Index ),
|
||||
SKIP( int, sound1Continue ),
|
||||
SKIP( int, sound1EnvelopeVolume ),
|
||||
SKIP( int, sound1EnvelopeATL ),
|
||||
SKIP( int, sound1EnvelopeATLReload ),
|
||||
SKIP( int, sound1EnvelopeUpDown ),
|
||||
SKIP( int, sound1SweepATL ),
|
||||
SKIP( int, sound1SweepATLReload ),
|
||||
SKIP( int, sound1SweepSteps ),
|
||||
SKIP( int, sound1SweepUpDown ),
|
||||
SKIP( int, sound1SweepStep ),
|
||||
SKIP( int, sound2On ),
|
||||
SKIP( int, sound2ATL ),
|
||||
SKIP( int, sound2Skip ),
|
||||
SKIP( int, sound2Index ),
|
||||
SKIP( int, sound2Continue ),
|
||||
SKIP( int, sound2EnvelopeVolume ),
|
||||
SKIP( int, sound2EnvelopeATL ),
|
||||
SKIP( int, sound2EnvelopeATLReload ),
|
||||
SKIP( int, sound2EnvelopeUpDown ),
|
||||
SKIP( int, sound3On ),
|
||||
SKIP( int, sound3ATL ),
|
||||
SKIP( int, sound3Skip ),
|
||||
SKIP( int, sound3Index ),
|
||||
SKIP( int, sound3Continue ),
|
||||
SKIP( int, sound3OutputLevel ),
|
||||
SKIP( int, sound4On ),
|
||||
SKIP( int, sound4ATL ),
|
||||
SKIP( int, sound4Skip ),
|
||||
SKIP( int, sound4Index ),
|
||||
SKIP( int, sound4Clock ),
|
||||
SKIP( int, sound4ShiftRight ),
|
||||
SKIP( int, sound4ShiftSkip ),
|
||||
SKIP( int, sound4ShiftIndex ),
|
||||
SKIP( int, sound4NSteps ),
|
||||
SKIP( int, sound4CountDown ),
|
||||
SKIP( int, sound4Continue ),
|
||||
SKIP( int, sound4EnvelopeVolume ),
|
||||
SKIP( int, sound4EnvelopeATL ),
|
||||
SKIP( int, sound4EnvelopeATLReload ),
|
||||
SKIP( int, sound4EnvelopeUpDown ),
|
||||
LOAD( int, soundEnableFlag ),
|
||||
SKIP( int, soundControl ),
|
||||
LOAD( int, pcm [0].readIndex ),
|
||||
LOAD( int, pcm [0].count ),
|
||||
LOAD( int, pcm [0].writeIndex ),
|
||||
SKIP( u8, soundDSAEnabled ), // was bool, which was one byte on MS compiler
|
||||
SKIP( int, soundDSATimer ),
|
||||
LOAD( u8 [32], pcm [0].fifo ),
|
||||
LOAD( u8, state.soundDSAValue ),
|
||||
LOAD( int, pcm [1].readIndex ),
|
||||
LOAD( int, pcm [1].count ),
|
||||
LOAD( int, pcm [1].writeIndex ),
|
||||
SKIP( int, soundDSBEnabled ),
|
||||
SKIP( int, soundDSBTimer ),
|
||||
LOAD( u8 [32], pcm [1].fifo ),
|
||||
LOAD( int, state.soundDSBValue ),
|
||||
|
||||
// skipped manually
|
||||
//LOAD( int, soundBuffer[0][0], 6*735 },
|
||||
//LOAD( int, soundFinalWave[0], 2*735 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
variable_desc old_gba_state2 [] =
|
||||
{
|
||||
LOAD( u8 [0x20], state.apu.regs [0x20] ),
|
||||
SKIP( int, sound3Bank ),
|
||||
SKIP( int, sound3DataSize ),
|
||||
SKIP( int, sound3ForcedOutput ),
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
// New state format
|
||||
static variable_desc gba_state [] =
|
||||
{
|
||||
// PCM
|
||||
LOAD( int, pcm [0].readIndex ),
|
||||
LOAD( int, pcm [0].count ),
|
||||
LOAD( int, pcm [0].writeIndex ),
|
||||
LOAD(u8[32],pcm[0].fifo ),
|
||||
LOAD( int, pcm [0].dac ),
|
||||
|
||||
SKIP( int [4], room_for_expansion ),
|
||||
|
||||
LOAD( int, pcm [1].readIndex ),
|
||||
LOAD( int, pcm [1].count ),
|
||||
LOAD( int, pcm [1].writeIndex ),
|
||||
LOAD(u8[32],pcm[1].fifo ),
|
||||
LOAD( int, pcm [1].dac ),
|
||||
|
||||
SKIP( int [4], room_for_expansion ),
|
||||
|
||||
// APU
|
||||
LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks)
|
||||
LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action
|
||||
LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run
|
||||
|
||||
LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register
|
||||
LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action
|
||||
LOAD( int, state.apu.sweep_enabled ),
|
||||
LOAD( int, state.apu.sweep_neg ), // obscure internal flag
|
||||
LOAD( int, state.apu.noise_divider ),
|
||||
LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM
|
||||
|
||||
LOAD( int [4], state.apu.delay ), // clocks until next channel action
|
||||
LOAD( int [4], state.apu.length_ctr ),
|
||||
LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR
|
||||
LOAD( int [4], state.apu.enabled ), // internal enabled flag
|
||||
|
||||
LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action
|
||||
LOAD( int [3], state.apu.env_volume ),
|
||||
LOAD( int [3], state.apu.env_enabled ),
|
||||
|
||||
SKIP( int [13], room_for_expansion ),
|
||||
|
||||
// Emulator
|
||||
LOAD( int, soundEnableFlag ),
|
||||
|
||||
SKIP( int [15], room_for_expansion ),
|
||||
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
// Reads and discards count bytes from in
|
||||
static void skip_read( gzFile in, int count )
|
||||
{
|
||||
char buf [512];
|
||||
|
||||
while ( count )
|
||||
{
|
||||
int n = sizeof buf;
|
||||
if ( n > count )
|
||||
n = count;
|
||||
|
||||
count -= n;
|
||||
utilGzRead( in, buf, n );
|
||||
}
|
||||
}
|
||||
|
||||
void soundReadGame(gzFile gzFile, int version)
|
||||
void soundSaveGame( gzFile out )
|
||||
{
|
||||
// TODO: implement
|
||||
gb_apu->save_state( &state.apu );
|
||||
|
||||
// Be sure areas for expansion get written as zero
|
||||
memset( dummy_state, 0, sizeof dummy_state );
|
||||
|
||||
utilWriteData( out, gba_state );
|
||||
}
|
||||
|
||||
static void soundReadGameOld( gzFile in, int version )
|
||||
{
|
||||
// Read main data
|
||||
utilReadData( in, old_gba_state );
|
||||
skip_read( in, 6*735 + 2*735 );
|
||||
|
||||
// Copy APU regs
|
||||
static int const regs_to_copy [] = {
|
||||
NR10, NR11, NR12, NR13, NR14,
|
||||
NR21, NR22, NR23, NR24,
|
||||
NR30, NR31, NR32, NR33, NR34,
|
||||
NR41, NR42, NR43, NR44,
|
||||
NR50, NR51, NR52, -1
|
||||
};
|
||||
|
||||
ioMem [NR52] |= 0x80; // old sound played even when this wasn't set (power on)
|
||||
|
||||
for ( int i = 0; regs_to_copy [i] >= 0; i++ )
|
||||
state.apu.regs [gba_to_gb_sound( regs_to_copy [i] ) - 0xFF10] = ioMem [regs_to_copy [i]];
|
||||
|
||||
// Copy wave RAM to both banks
|
||||
memcpy( &state.apu.regs [0x20], &ioMem [0x90], 0x10 );
|
||||
memcpy( &state.apu.regs [0x30], &ioMem [0x90], 0x10 );
|
||||
|
||||
// Read both banks of wave RAM if available
|
||||
if ( version >= SAVE_GAME_VERSION_3 )
|
||||
utilReadData( in, old_gba_state2 );
|
||||
|
||||
// Restore PCM
|
||||
pcm [0].dac = state.soundDSAValue;
|
||||
pcm [1].dac = state.soundDSBValue;
|
||||
|
||||
int quality = utilReadInt( in ); // ignore this crap
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void soundReadGame( gzFile in, int version )
|
||||
{
|
||||
// Prepare APU and default state
|
||||
reset_apu();
|
||||
gb_apu->save_state( &state.apu );
|
||||
|
||||
if ( version > SAVE_GAME_VERSION_9 )
|
||||
utilReadData( in, gba_state );
|
||||
else
|
||||
soundReadGameOld( in, version );
|
||||
|
||||
gb_apu->load_state( state.apu );
|
||||
write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F );
|
||||
|
||||
apply_muting();
|
||||
}
|
||||
|
|
30
src/Sound.h
30
src/Sound.h
|
@ -69,20 +69,26 @@ extern void setsystemSoundOn(bool value);
|
|||
extern void setsoundPaused(bool value);
|
||||
extern void interp_rate();
|
||||
|
||||
extern int SOUND_CLOCK_TICKS;
|
||||
extern int soundTicks;
|
||||
extern bool soundOffFlag;
|
||||
extern bool soundPaused;
|
||||
extern int soundQuality;
|
||||
extern int soundBufferLen;
|
||||
extern int soundBufferTotalLen;
|
||||
extern u32 soundNextPosition;
|
||||
extern u16 soundFinalWave[1470];
|
||||
extern int soundVolume;
|
||||
extern int soundInterpolation;
|
||||
extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to soundTick()
|
||||
extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called
|
||||
extern int soundQuality; // sample rate = 44100 / soundQuality
|
||||
extern int soundBufferLen; // size of sound buffer in BYTES
|
||||
extern u16 soundFinalWave[1470];// 16-bit SIGNED stereo sample buffer
|
||||
extern int soundVolume; // emulator volume code (not linear)
|
||||
|
||||
extern bool soundEcho;
|
||||
extern int soundInterpolation; // 1 if PCM should have low-pass filtering
|
||||
extern float soundFiltering; // 0.0 = none, 1.0 = max (only if soundInterpolation!=0)
|
||||
|
||||
extern bool soundEcho; // enables echo for GB, not GBA
|
||||
|
||||
// Not used anymore
|
||||
extern bool soundLowPass;
|
||||
extern bool soundReverse;
|
||||
|
||||
// Unknown purpose
|
||||
extern int soundBufferTotalLen;
|
||||
extern u32 soundNextPosition;
|
||||
extern bool soundPaused;
|
||||
extern bool soundOffFlag;
|
||||
|
||||
#endif // VBA_SOUND_H
|
||||
|
|
|
@ -137,6 +137,8 @@ void gbSoundTick()
|
|||
end_frame( SOUND_CLOCK_TICKS * ticks_to_time );
|
||||
|
||||
flush_samples();
|
||||
|
||||
gb_effects_config.enabled = soundEcho;
|
||||
|
||||
// Update effects config if it was changed
|
||||
if ( memcmp( &gb_effects_config_current, &gb_effects_config,
|
||||
|
@ -145,6 +147,17 @@ void gbSoundTick()
|
|||
}
|
||||
}
|
||||
|
||||
static void reset_apu()
|
||||
{
|
||||
// Use DMG or CGB sound differences based on type of game
|
||||
gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb );
|
||||
|
||||
if ( stereo_buffer )
|
||||
stereo_buffer->clear();
|
||||
|
||||
soundTicks = SOUND_CLOCK_TICKS;
|
||||
}
|
||||
|
||||
static void remake_stereo_buffer()
|
||||
{
|
||||
// Stereo_Buffer
|
||||
|
@ -163,21 +176,26 @@ static void remake_stereo_buffer()
|
|||
stereo_buffer->set_channel_count( chan_count, chan_types );
|
||||
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu;
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
apply_effects();
|
||||
|
||||
// Use DMG or CGB sound differences based on type of game
|
||||
gb_apu->reset( gbHardware & 1 ? gb_apu->mode_dmg : gb_apu->mode_cgb );
|
||||
}
|
||||
|
||||
void gbSoundReset()
|
||||
{
|
||||
gb_effects_config.echo = 0.20;
|
||||
gb_effects_config.stereo = 0.15;
|
||||
gb_effects_config.surround = false;
|
||||
|
||||
SOUND_CLOCK_TICKS = 20000;
|
||||
|
||||
remake_stereo_buffer();
|
||||
reset_apu();
|
||||
|
||||
soundPaused = 1;
|
||||
SOUND_CLOCK_TICKS = 20000;
|
||||
soundTicks = SOUND_CLOCK_TICKS;
|
||||
soundNextPosition = 0;
|
||||
|
||||
// don't translate
|
||||
|
@ -253,12 +271,142 @@ void gbSoundSetQuality(int quality)
|
|||
}
|
||||
}
|
||||
|
||||
static char dummy_buf [735 * 2];
|
||||
|
||||
#define SKIP( type, name ) { dummy_buf, sizeof (type) }
|
||||
|
||||
// funny expr at end ensures that type matches type of variable
|
||||
#define LOAD( type, name ) { &name, sizeof (name) + (&name - (type*) &name) }
|
||||
|
||||
static variable_desc gbsound_format [] =
|
||||
{
|
||||
SKIP( int, soundPaused ),
|
||||
SKIP( int, soundPlay ),
|
||||
SKIP( int, soundTicks ),
|
||||
SKIP( int, SOUND_CLOCK_TICKS ),
|
||||
SKIP( int, soundLevel1 ),
|
||||
SKIP( int, soundLevel2 ),
|
||||
SKIP( int, soundBalance ),
|
||||
SKIP( int, soundMasterOn ),
|
||||
SKIP( int, soundIndex ),
|
||||
SKIP( int, soundVIN ),
|
||||
SKIP( int, soundOn [0] ),
|
||||
SKIP( int, soundATL [0] ),
|
||||
SKIP( int, sound1Skip ),
|
||||
SKIP( int, soundIndex [0] ),
|
||||
SKIP( int, sound1Continue ),
|
||||
SKIP( int, soundEnvelopeVolume [0] ),
|
||||
SKIP( int, soundEnvelopeATL [0] ),
|
||||
SKIP( int, sound1EnvelopeATLReload ),
|
||||
SKIP( int, sound1EnvelopeUpDown ),
|
||||
SKIP( int, sound1SweepATL ),
|
||||
SKIP( int, sound1SweepATLReload ),
|
||||
SKIP( int, sound1SweepSteps ),
|
||||
SKIP( int, sound1SweepUpDown ),
|
||||
SKIP( int, sound1SweepStep ),
|
||||
SKIP( int, soundOn [1] ),
|
||||
SKIP( int, soundATL [1] ),
|
||||
SKIP( int, sound2Skip ),
|
||||
SKIP( int, soundIndex [1] ),
|
||||
SKIP( int, sound2Continue ),
|
||||
SKIP( int, soundEnvelopeVolume [1] ),
|
||||
SKIP( int, soundEnvelopeATL [1] ),
|
||||
SKIP( int, sound2EnvelopeATLReload ),
|
||||
SKIP( int, sound2EnvelopeUpDown ),
|
||||
SKIP( int, soundOn [2] ),
|
||||
SKIP( int, soundATL [2] ),
|
||||
SKIP( int, sound3Skip ),
|
||||
SKIP( int, soundIndex [2] ),
|
||||
SKIP( int, sound3Continue ),
|
||||
SKIP( int, sound3OutputLevel ),
|
||||
SKIP( int, soundOn [3] ),
|
||||
SKIP( int, soundATL [3] ),
|
||||
SKIP( int, sound4Skip ),
|
||||
SKIP( int, soundIndex [3] ),
|
||||
SKIP( int, sound4Clock ),
|
||||
SKIP( int, sound4ShiftRight ),
|
||||
SKIP( int, sound4ShiftSkip ),
|
||||
SKIP( int, sound4ShiftIndex ),
|
||||
SKIP( int, sound4NSteps ),
|
||||
SKIP( int, sound4CountDown ),
|
||||
SKIP( int, sound4Continue ),
|
||||
SKIP( int, soundEnvelopeVolume [2] ),
|
||||
SKIP( int, soundEnvelopeATL [2] ),
|
||||
SKIP( int, sound4EnvelopeATLReload ),
|
||||
SKIP( int, sound4EnvelopeUpDown ),
|
||||
SKIP( int, soundEnableFlag ),
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static variable_desc gbsound_format2 [] =
|
||||
{
|
||||
SKIP( int, sound1ATLreload ),
|
||||
SKIP( int, freq1low ),
|
||||
SKIP( int, freq1high ),
|
||||
SKIP( int, sound2ATLreload ),
|
||||
SKIP( int, freq2low ),
|
||||
SKIP( int, freq2high ),
|
||||
SKIP( int, sound3ATLreload ),
|
||||
SKIP( int, freq3low ),
|
||||
SKIP( int, freq3high ),
|
||||
SKIP( int, sound4ATLreload ),
|
||||
SKIP( int, freq4 ),
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static variable_desc gbsound_format3 [] =
|
||||
{
|
||||
SKIP( u8[2*735], soundBuffer ),
|
||||
SKIP( u8[2*735], soundBuffer ),
|
||||
SKIP( u16[735], soundFinalWave ),
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
void gbSoundSaveGame(gzFile gzFile)
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
enum {
|
||||
nr10 = 0,
|
||||
nr11, nr12, nr13, nr14,
|
||||
nr20, nr21, nr22, nr23, nr24,
|
||||
nr30, nr31, nr32, nr33, nr34,
|
||||
nr40, nr41, nr42, nr43, nr44,
|
||||
nr50, nr51, nr52
|
||||
};
|
||||
|
||||
void gbSoundReadGame(int version,gzFile gzFile)
|
||||
{
|
||||
// TODO: implement
|
||||
return; // TODO: apparently GB save states don't work in the main emulator
|
||||
|
||||
// Load state
|
||||
utilReadData( gzFile, gbsound_format );
|
||||
|
||||
if ( version >= 11 )
|
||||
utilReadData( gzFile, gbsound_format2 );
|
||||
|
||||
utilReadData( gzFile, gbsound_format3 );
|
||||
|
||||
int quality = 1;
|
||||
if ( version >= 7 )
|
||||
quality = utilReadInt( gzFile );
|
||||
|
||||
gbSoundSetQuality( quality );
|
||||
|
||||
// Convert to format Gb_Apu uses
|
||||
reset_apu();
|
||||
gb_apu_state_t s;
|
||||
gb_apu->save_state( &s ); // use fresh values for anything not restored
|
||||
|
||||
// Only some registers are properly preserved
|
||||
static int const regs_to_copy [] = {
|
||||
nr10, nr11, nr12, nr21, nr22, nr30, nr32, nr42, nr43, nr50, nr51, nr52, -1
|
||||
};
|
||||
for ( int i = 0; regs_to_copy [i] >= 0; i++ )
|
||||
s.regs [regs_to_copy [i]] = gbMemory [0xFF10 + regs_to_copy [i]];
|
||||
|
||||
memcpy( &s.regs [0x20], &gbMemory [0xFF30], 0x10 ); // wave
|
||||
|
||||
gb_apu->load_state( s );
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Gb_Snd_Emu 0.2.0. http://www.slack.net/~ant/
|
||||
// Gb_Snd_Emu $vers. http://www.slack.net/~ant/
|
||||
|
||||
#include "Gb_Apu.h"
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// a Game Boy Advance emulator.
|
||||
#define GB_APU_OVERCLOCK 4
|
||||
|
||||
#define GB_APU_CUSTOM_STATE 1
|
||||
|
||||
// Uncomment to enable platform-specific (and possibly non-portable) optimizations.
|
||||
//#define BLARGG_NONPORTABLE 1
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ bool DirectSound::init()
|
|||
freq = 44100;
|
||||
break;
|
||||
}
|
||||
soundBufferLen = freq*2/30;
|
||||
soundBufferLen = freq/60*4;
|
||||
soundBufferTotalLen = soundBufferLen * 10;
|
||||
|
||||
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
|
||||
|
@ -310,7 +310,7 @@ void DirectSound::write()
|
|||
if( !speedup && synchronize && !theApp.throttle ) {
|
||||
hr = dsbSecondary->GetStatus(&status);
|
||||
if( status & DSBSTATUS_PLAYING ) {
|
||||
if( !soundPaused ) {
|
||||
if( soundPaused ) {
|
||||
while( true ) {
|
||||
dsbSecondary->GetCurrentPosition(&play, NULL);
|
||||
int BufferLeft = ((soundNextPosition <= play) ?
|
||||
|
|
|
@ -2007,3 +2007,4 @@ void MainWnd::OnUpdateOutputapiOpenal(CCmdUI *pCmdUI)
|
|||
pCmdUI->SetCheck( ( theApp.audioAPI == OPENAL ) ? 1 : 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,10 @@ bool OpenAL::init()
|
|||
winlog( "OpenAL::init\n" );
|
||||
assert( initialized == false );
|
||||
|
||||
if (theApp.OpenALAudiomixing)
|
||||
{
|
||||
device = alcOpenDevice( "Generic Software" );
|
||||
}
|
||||
device = alcOpenDevice( NULL );
|
||||
assert( device != NULL );
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@ VBA::VBA()
|
|||
input = NULL;
|
||||
joypadDefault = 0;
|
||||
autoFire = 0;
|
||||
OpenALAudiomixing = false;
|
||||
autoFireToggle = false;
|
||||
winPauseNextFrame = false;
|
||||
soundRecording = false;
|
||||
|
@ -1420,6 +1421,7 @@ void VBA::loadSettings()
|
|||
audioAPI = DIRECTSOUND;
|
||||
}
|
||||
|
||||
OpenALAudiomixing = regQueryDwordValue( "OpenALAudiomixing", 0 );
|
||||
windowPositionX = regQueryDwordValue("windowX", 0);
|
||||
if(windowPositionX < 0)
|
||||
windowPositionX = 0;
|
||||
|
|
|
@ -148,6 +148,7 @@ class VBA : public CWinApp
|
|||
u32 autoFrameSkipLastTime;
|
||||
bool autoFrameSkip;
|
||||
bool vsync;
|
||||
bool OpenALAudiomixing;
|
||||
bool changingVideoSize;
|
||||
GUID videoDriverGUID;
|
||||
GUID *pVideoDriverGUID;
|
||||
|
|
|
@ -806,13 +806,14 @@
|
|||
#define IDC_COMBO_PLUGIN 40345
|
||||
#define ID_OUTPUTAPI_DIRECTSOUND 40346
|
||||
#define ID_OUTPUTAPI_OPENAL 40347
|
||||
#define ID_OUTPUTAPI_SOFTWAREMIXING 40348
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 159
|
||||
#define _APS_NEXT_COMMAND_VALUE 40348
|
||||
#define _APS_NEXT_COMMAND_VALUE 40349
|
||||
#define _APS_NEXT_CONTROL_VALUE 1269
|
||||
#define _APS_NEXT_SYMED_VALUE 103
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue