* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -6,6 +6,7 @@ |
| 6 | 6 |
#include "../apu/Gb_Apu.h" |
| 7 | 7 |
#include "../apu/Multi_Buffer.h" |
| 8 | 8 |
#include "../common/SoundDriver.h" |
| 9 |
+#include "XSFCommon.h" |
|
| 9 | 10 |
|
| 10 | 11 |
extern SoundDriver *systemSoundInit(); |
| 11 | 12 |
|
| ... | ... |
@@ -117,7 +118,7 @@ void Gba_Pcm::apply_control(int idx) |
| 117 | 118 |
// base filtering on how long since last sample was output |
| 118 | 119 |
int32_t period = time - this->last_time; |
| 119 | 120 |
|
| 120 |
- int idx = period / 512; |
|
| 121 |
+ idx = period / 512; |
|
| 121 | 122 |
if (idx >= 3) |
| 122 | 123 |
idx = 3; |
| 123 | 124 |
|
| ... | ... |
@@ -189,11 +190,11 @@ void Gba_Pcm_Fifo::timer_overflowed(int which_timer) |
| 189 | 190 |
if (!this->count) |
| 190 | 191 |
{
|
| 191 | 192 |
// Not filled by DMA, so fill with 16 bytes of silence |
| 192 |
- int reg = this->which ? FIFOB_L : FIFOA_L; |
|
| 193 |
+ int regi = this->which ? FIFOB_L : FIFOA_L; |
|
| 193 | 194 |
for (int n = 8; n--; ) |
| 194 | 195 |
{
|
| 195 |
- soundEvent(reg, static_cast<uint16_t>(0)); |
|
| 196 |
- soundEvent(reg + 2, static_cast<uint16_t>(0)); |
|
| 196 |
+ soundEvent(regi, static_cast<uint16_t>(0)); |
|
| 197 |
+ soundEvent(regi + 2, static_cast<uint16_t>(0)); |
|
| 197 | 198 |
} |
| 198 | 199 |
} |
| 199 | 200 |
} |
| ... | ... |
@@ -393,10 +394,10 @@ void psoundTickfn() |
| 393 | 394 |
|
| 394 | 395 |
flush_samples(stereo_buffer.get()); |
| 395 | 396 |
|
| 396 |
- if (soundFiltering_ != soundFiltering) |
|
| 397 |
+ if (!fEqual(soundFiltering_, soundFiltering)) |
|
| 397 | 398 |
apply_filtering(); |
| 398 | 399 |
|
| 399 |
- if (soundVolume_ != soundVolume) |
|
| 400 |
+ if (!fEqual(soundVolume_, soundVolume)) |
|
| 400 | 401 |
apply_volume(); |
| 401 | 402 |
} |
| 402 | 403 |
} |
| ... | ... |
@@ -412,10 +413,12 @@ static void apply_muting() |
| 412 | 413 |
if (gb_apu) |
| 413 | 414 |
// APU |
| 414 | 415 |
for (int i = 0; i < 4; ++i) |
| 416 |
+ {
|
|
| 415 | 417 |
if (soundEnableFlag >> i & 1) |
| 416 | 418 |
gb_apu->set_output(stereo_buffer->center(), stereo_buffer->left(), stereo_buffer->right(), i); |
| 417 | 419 |
else |
| 418 | 420 |
gb_apu->set_output(nullptr, nullptr, nullptr, i); |
| 421 |
+ } |
|
| 419 | 422 |
} |
| 420 | 423 |
|
| 421 | 424 |
static void reset_apu() |
| ... | ... |
@@ -115,7 +115,7 @@ void Gba_Pcm::apply_control(int idx) |
| 115 | 115 |
if (soundInterpolation) |
| 116 | 116 |
{
|
| 117 | 117 |
// base filtering on how long since last sample was output |
| 118 |
- int period = time - this->last_time; |
|
| 118 |
+ int32_t period = time - this->last_time; |
|
| 119 | 119 |
|
| 120 | 120 |
int idx = period / 512; |
| 121 | 121 |
if (idx >= 3) |
| ... | ... |
@@ -158,7 +158,7 @@ void Gba_Pcm::update(int dac) |
| 158 | 158 |
if (soundInterpolation) |
| 159 | 159 |
{
|
| 160 | 160 |
// base filtering on how long since last sample was output |
| 161 |
- int period = time - this->last_time; |
|
| 161 |
+ int32_t period = time - this->last_time; |
|
| 162 | 162 |
|
| 163 | 163 |
int idx = period / 512; |
| 164 | 164 |
if (idx >= 3) |
| ... | ... |
@@ -350,22 +350,21 @@ void flush_samples(Multi_Buffer *buffer) |
| 350 | 350 |
// that don't use the length parameter of the write method. |
| 351 | 351 |
// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the |
| 352 | 352 |
// samples at once to help reducing the audio delay on all platforms. |
| 353 |
- int soundBufferLen = (soundSampleRate / 60) * 4; |
|
| 353 |
+ int32_t soundBufferLen = (soundSampleRate / 60) * 4; |
|
| 354 | 354 |
|
| 355 | 355 |
// soundBufferLen should have a whole number of sample pairs |
| 356 | 356 |
assert(!(soundBufferLen % (2 * sizeof(*soundFinalWave)))); |
| 357 | 357 |
|
| 358 | 358 |
// number of samples in output buffer |
| 359 |
- int out_buf_size = soundBufferLen / sizeof(*soundFinalWave); |
|
| 359 |
+ int32_t out_buf_size = soundBufferLen / sizeof(*soundFinalWave); |
|
| 360 | 360 |
|
| 361 |
- // Keep filling and writing soundFinalWave until it can't be fully filled |
|
| 362 |
- while (buffer->samples_avail() >= out_buf_size) |
|
| 361 |
+ while (buffer->samples_avail()) |
|
| 363 | 362 |
{
|
| 364 |
- buffer->read_samples(reinterpret_cast<blip_sample_t *>(soundFinalWave), out_buf_size); |
|
| 363 |
+ long samples_read = buffer->read_samples(reinterpret_cast<blip_sample_t *>(soundFinalWave), out_buf_size); |
|
| 365 | 364 |
if (soundPaused) |
| 366 | 365 |
soundResume(); |
| 367 | 366 |
|
| 368 |
- soundDriver->write(soundFinalWave, soundBufferLen); |
|
| 367 |
+ soundDriver->write(soundFinalWave, samples_read * sizeof(*soundFinalWave)); |
|
| 369 | 368 |
} |
| 370 | 369 |
} |
| 371 | 370 |
|
| ... | ... |
@@ -374,11 +373,11 @@ static void apply_filtering() |
| 374 | 373 |
soundFiltering_ = soundFiltering; |
| 375 | 374 |
|
| 376 | 375 |
int base_freq = static_cast<int>(32768 - soundFiltering_ * 16384); |
| 377 |
- int nyquist = stereo_buffer->sample_rate() / 2; |
|
| 376 |
+ int32_t nyquist = stereo_buffer->sample_rate() / 2; |
|
| 378 | 377 |
|
| 379 | 378 |
for (int i = 0; i < 3; ++i) |
| 380 | 379 |
{
|
| 381 |
- int cutoff = base_freq >> i; |
|
| 380 |
+ int32_t cutoff = base_freq >> i; |
|
| 382 | 381 |
if (cutoff > nyquist) |
| 383 | 382 |
cutoff = nyquist; |
| 384 | 383 |
pcm_synth[i].treble_eq(blip_eq_t(0, 0, stereo_buffer->sample_rate(), cutoff)); |
| ... | ... |
@@ -400,8 +399,6 @@ void psoundTickfn() |
| 400 | 399 |
if (soundVolume_ != soundVolume) |
| 401 | 400 |
apply_volume(); |
| 402 | 401 |
} |
| 403 |
- |
|
| 404 |
- ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f); |
|
| 405 | 402 |
} |
| 406 | 403 |
|
| 407 | 404 |
static void apply_muting() |
| ... | ... |
@@ -423,8 +420,11 @@ static void apply_muting() |
| 423 | 420 |
|
| 424 | 421 |
static void reset_apu() |
| 425 | 422 |
{
|
| 426 |
- gb_apu->reduce_clicks(true); |
|
| 427 |
- gb_apu->reset(gb_apu->mode_agb, true); |
|
| 423 |
+ if (gb_apu) |
|
| 424 |
+ {
|
|
| 425 |
+ gb_apu->reduce_clicks(true); |
|
| 426 |
+ gb_apu->reset(Gb_Apu::mode_agb, true); |
|
| 427 |
+ } |
|
| 428 | 428 |
|
| 429 | 429 |
if (stereo_buffer) |
| 430 | 430 |
stereo_buffer->clear(); |
| ... | ... |
@@ -438,23 +438,24 @@ static void remake_stereo_buffer() |
| 438 | 438 |
pcm[0].pcm.init(); |
| 439 | 439 |
pcm[1].pcm.init(); |
| 440 | 440 |
|
| 441 |
- // APU |
|
| 442 |
- if (!gb_apu) |
|
| 443 |
- {
|
|
| 444 |
- gb_apu.reset(new Gb_Apu); // TODO: handle out of memory |
|
| 445 |
- reset_apu(); |
|
| 446 |
- } |
|
| 447 |
- |
|
| 448 | 441 |
// Stereo_Buffer |
| 449 | 442 |
stereo_buffer.reset(new Stereo_Buffer); // TODO: handle out of memory |
| 450 | 443 |
stereo_buffer->set_sample_rate(soundSampleRate); // TODO: handle out of memory |
| 451 |
- stereo_buffer->clock_rate(gb_apu->clock_rate); |
|
| 452 | 444 |
|
| 453 | 445 |
// PCM |
| 454 | 446 |
pcm[0].which = 0; |
| 455 | 447 |
pcm[1].which = 1; |
| 456 | 448 |
apply_filtering(); |
| 457 | 449 |
|
| 450 |
+ // APU |
|
| 451 |
+ if (!gb_apu) |
|
| 452 |
+ {
|
|
| 453 |
+ gb_apu.reset(new Gb_Apu); // TODO: handle out of memory |
|
| 454 |
+ reset_apu(); |
|
| 455 |
+ gb_apu->treble_eq(blip_eq_t(0, 0, soundSampleRate, soundSampleRate / 2)); |
|
| 456 |
+ } |
|
| 457 |
+ stereo_buffer->clock_rate(gb_apu->clock_rate); |
|
| 458 |
+ |
|
| 458 | 459 |
// Volume Level |
| 459 | 460 |
apply_muting(); |
| 460 | 461 |
apply_volume(); |
| ... | ... |
@@ -8,7 +8,6 @@ |
| 8 | 8 |
#include "../common/SoundDriver.h" |
| 9 | 9 |
|
| 10 | 10 |
extern SoundDriver *systemSoundInit(); |
| 11 |
-bool soundDeclicking = true; |
|
| 12 | 11 |
|
| 13 | 12 |
static const uint32_t NR52 = 0x84; |
| 14 | 13 |
|
| ... | ... |
@@ -20,12 +19,12 @@ static uint16_t soundFinalWave[6400]; |
| 20 | 19 |
static long soundSampleRate = 44100; |
| 21 | 20 |
bool soundInterpolation = true; |
| 22 | 21 |
static bool soundPaused = true; |
| 23 |
-static float soundFiltering = 0.5f; // 0.0 = none, 1.0 = max |
|
| 22 |
+static float soundFiltering = 1.0f; |
|
| 24 | 23 |
int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
| 25 | 24 |
int soundTicks = SOUND_CLOCK_TICKS_; |
| 26 | 25 |
|
| 27 | 26 |
static float soundVolume = 1.0f; |
| 28 |
-static int soundEnableFlag = 0x30f; // emulator channels enabled |
|
| 27 |
+static int soundEnableFlag = 0x3ff; // emulator channels enabled |
|
| 29 | 28 |
static float soundFiltering_ = -1; |
| 30 | 29 |
static float soundVolume_ = -1; |
| 31 | 30 |
|
| ... | ... |
@@ -85,11 +84,11 @@ inline void Gba_Pcm::init() |
| 85 | 84 |
|
| 86 | 85 |
void Gba_Pcm::apply_control(int idx) |
| 87 | 86 |
{
|
| 88 |
- this->shift = (~ioMem[SGCNT0_H] >> (2 + idx)) & 1; |
|
| 87 |
+ this->shift = ~ioMem[SGCNT0_H] >> (2 + idx) & 1; |
|
| 89 | 88 |
|
| 90 | 89 |
int ch = 0; |
| 91 |
- if (((soundEnableFlag >> idx) & 0x100) && (ioMem[NR52] & 0x80)) |
|
| 92 |
- ch = (ioMem[SGCNT0_H + 1] >> (idx * 4)) & 3; |
|
| 90 |
+ if ((soundEnableFlag >> idx & 0x100) && (ioMem[NR52] & 0x80)) |
|
| 91 |
+ ch = ioMem[SGCNT0_H + 1] >> (idx * 4) & 3; |
|
| 93 | 92 |
|
| 94 | 93 |
Blip_Buffer *out = nullptr; |
| 95 | 94 |
switch (ch) |
| ... | ... |
@@ -108,7 +107,7 @@ void Gba_Pcm::apply_control(int idx) |
| 108 | 107 |
{
|
| 109 | 108 |
if (this->output) |
| 110 | 109 |
{
|
| 111 |
- blip_time_t time = blip_time(); |
|
| 110 |
+ auto time = blip_time(); |
|
| 112 | 111 |
|
| 113 | 112 |
this->output->set_modified(); |
| 114 | 113 |
|
| ... | ... |
@@ -147,7 +146,7 @@ void Gba_Pcm::update(int dac) |
| 147 | 146 |
{
|
| 148 | 147 |
if (this->output) |
| 149 | 148 |
{
|
| 150 |
- blip_time_t time = blip_time(); |
|
| 149 |
+ auto time = blip_time(); |
|
| 151 | 150 |
|
| 152 | 151 |
dac = static_cast<int8_t>(dac) >> this->shift; |
| 153 | 152 |
int delta = dac - this->last_amp; |
| ... | ... |
@@ -179,15 +178,19 @@ void Gba_Pcm_Fifo::timer_overflowed(int which_timer) |
| 179 | 178 |
{
|
| 180 | 179 |
if (which_timer == this->timer && this->enabled) |
| 181 | 180 |
{
|
| 182 |
- if (this->count <= 16) |
|
| 181 |
+ /* Mother 3 fix, refined to not break Metroid Fusion */ |
|
| 182 |
+ if (this->count == 16 || !this->count) |
|
| 183 | 183 |
{
|
| 184 | 184 |
// Need to fill FIFO |
| 185 |
+ int saved_count = this->count; |
|
| 185 | 186 |
CPUCheckDMA(3, this->which ? 4 : 2); |
| 186 |
- if (this->count <= 16) |
|
| 187 |
+ if (!saved_count && this->count == 16) |
|
| 188 |
+ CPUCheckDMA(3, this->which ? 4 : 2); |
|
| 189 |
+ if (!this->count) |
|
| 187 | 190 |
{
|
| 188 | 191 |
// Not filled by DMA, so fill with 16 bytes of silence |
| 189 | 192 |
int reg = this->which ? FIFOB_L : FIFOA_L; |
| 190 |
- for (int n = 4; n--; ) |
|
| 193 |
+ for (int n = 8; n--; ) |
|
| 191 | 194 |
{
|
| 192 | 195 |
soundEvent(reg, static_cast<uint16_t>(0)); |
| 193 | 196 |
soundEvent(reg + 2, static_cast<uint16_t>(0)); |
| ... | ... |
@@ -412,7 +415,7 @@ static void apply_muting() |
| 412 | 415 |
if (gb_apu) |
| 413 | 416 |
// APU |
| 414 | 417 |
for (int i = 0; i < 4; ++i) |
| 415 |
- if ((soundEnableFlag >> i) & 1) |
|
| 418 |
+ if (soundEnableFlag >> i & 1) |
|
| 416 | 419 |
gb_apu->set_output(stereo_buffer->center(), stereo_buffer->left(), stereo_buffer->right(), i); |
| 417 | 420 |
else |
| 418 | 421 |
gb_apu->set_output(nullptr, nullptr, nullptr, i); |
| ... | ... |
@@ -420,7 +423,7 @@ static void apply_muting() |
| 420 | 423 |
|
| 421 | 424 |
static void reset_apu() |
| 422 | 425 |
{
|
| 423 |
- gb_apu->reduce_clicks(soundDeclicking); |
|
| 426 |
+ gb_apu->reduce_clicks(true); |
|
| 424 | 427 |
gb_apu->reset(gb_apu->mode_agb, true); |
| 425 | 428 |
|
| 426 | 429 |
if (stereo_buffer) |
| ... | ... |
@@ -68,7 +68,7 @@ static Gba_Pcm_Fifo pcm[2]; |
| 68 | 68 |
static std::unique_ptr<Gb_Apu> gb_apu; |
| 69 | 69 |
static std::unique_ptr<Stereo_Buffer> stereo_buffer; |
| 70 | 70 |
|
| 71 |
-static Blip_Synth<blip_best_quality, 1> pcm_synth[3]; // 32 kHz, 16 kHz, 8 kHz |
|
| 71 |
+static Blip_Synth<blip_high_quality, 1> pcm_synth[3]; // 32 kHz, 16 kHz, 8 kHz |
|
| 72 | 72 |
|
| 73 | 73 |
static inline blip_time_t blip_time() |
| 74 | 74 |
{
|
(As an aside, blargg's code style makes me go blarg myself.)
| ... | ... |
@@ -1,275 +1,268 @@ |
| 1 |
-#include <string.h> |
|
| 2 |
- |
|
| 1 |
+#include <memory> |
|
| 3 | 2 |
#include "Sound.h" |
| 4 |
- |
|
| 5 | 3 |
#include "GBA.h" |
| 6 | 4 |
#include "Globals.h" |
| 7 |
-//#include "../Util.h" |
|
| 8 | 5 |
#include "../common/Port.h" |
| 9 |
- |
|
| 10 | 6 |
#include "../apu/Gb_Apu.h" |
| 11 | 7 |
#include "../apu/Multi_Buffer.h" |
| 12 |
- |
|
| 13 | 8 |
#include "../common/SoundDriver.h" |
| 14 | 9 |
|
| 15 | 10 |
extern SoundDriver *systemSoundInit(); |
| 16 | 11 |
bool soundDeclicking = true; |
| 17 | 12 |
|
| 18 |
-#define NR10 0x60 |
|
| 19 |
-#define NR11 0x62 |
|
| 20 |
-#define NR12 0x63 |
|
| 21 |
-#define NR13 0x64 |
|
| 22 |
-#define NR14 0x65 |
|
| 23 |
-#define NR21 0x68 |
|
| 24 |
-#define NR22 0x69 |
|
| 25 |
-#define NR23 0x6c |
|
| 26 |
-#define NR24 0x6d |
|
| 27 |
-#define NR30 0x70 |
|
| 28 |
-#define NR31 0x72 |
|
| 29 |
-#define NR32 0x73 |
|
| 30 |
-#define NR33 0x74 |
|
| 31 |
-#define NR34 0x75 |
|
| 32 |
-#define NR41 0x78 |
|
| 33 |
-#define NR42 0x79 |
|
| 34 |
-#define NR43 0x7c |
|
| 35 |
-#define NR44 0x7d |
|
| 36 |
-#define NR50 0x80 |
|
| 37 |
-#define NR51 0x81 |
|
| 38 |
-#define NR52 0x84 |
|
| 39 |
- |
|
| 40 |
-SoundDriver * soundDriver = 0; |
|
| 41 |
- |
|
| 42 |
-extern bool stopState; // TODO: silence sound when true |
|
| 43 |
- |
|
| 44 |
-int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second |
|
| 45 |
- |
|
| 46 |
-static uint16_t soundFinalWave [6400]; |
|
| 47 |
-long soundSampleRate = 44100; |
|
| 48 |
-bool soundInterpolation = true; |
|
| 49 |
-bool soundPaused = true; |
|
| 50 |
-float soundFiltering = 0.5f; |
|
| 51 |
-int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
|
| 52 |
-int soundTicks = SOUND_CLOCK_TICKS_; |
|
| 53 |
- |
|
| 54 |
-static float soundVolume = 1.0f; |
|
| 55 |
-static int soundEnableFlag = 0x3ff; // emulator channels enabled |
|
| 56 |
-static float soundFiltering_ = -1; |
|
| 57 |
-static float soundVolume_ = -1; |
|
| 13 |
+static const uint32_t NR52 = 0x84; |
|
| 14 |
+ |
|
| 15 |
+static std::unique_ptr<SoundDriver> soundDriver; |
|
| 58 | 16 |
|
| 59 |
-void interp_rate() { /* empty for now */ }
|
|
| 17 |
+static const int SOUND_CLOCK_TICKS_ = 167772; // 1/100 second |
|
| 60 | 18 |
|
| 61 |
-class Gba_Pcm {
|
|
| 19 |
+static uint16_t soundFinalWave[6400]; |
|
| 20 |
+static long soundSampleRate = 44100; |
|
| 21 |
+bool soundInterpolation = true; |
|
| 22 |
+static bool soundPaused = true; |
|
| 23 |
+static float soundFiltering = 0.5f; // 0.0 = none, 1.0 = max |
|
| 24 |
+int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
|
| 25 |
+int soundTicks = SOUND_CLOCK_TICKS_; |
|
| 26 |
+ |
|
| 27 |
+static float soundVolume = 1.0f; |
|
| 28 |
+static int soundEnableFlag = 0x30f; // emulator channels enabled |
|
| 29 |
+static float soundFiltering_ = -1; |
|
| 30 |
+static float soundVolume_ = -1; |
|
| 31 |
+ |
|
| 32 |
+class Gba_Pcm |
|
| 33 |
+{
|
|
| 62 | 34 |
public: |
| 63 | 35 |
void init(); |
| 64 |
- void apply_control( int idx ); |
|
| 65 |
- void update( int dac ); |
|
| 66 |
- void end_frame( blip_time_t ); |
|
| 36 |
+ void apply_control(int idx); |
|
| 37 |
+ void update(int dac); |
|
| 38 |
+ void end_frame(blip_time_t); |
|
| 67 | 39 |
|
| 68 | 40 |
private: |
| 69 |
- Blip_Buffer* output; |
|
| 41 |
+ Blip_Buffer *output; |
|
| 70 | 42 |
blip_time_t last_time; |
| 71 | 43 |
int last_amp; |
| 72 | 44 |
int shift; |
| 73 | 45 |
}; |
| 74 | 46 |
|
| 75 |
-class Gba_Pcm_Fifo {
|
|
| 47 |
+class Gba_Pcm_Fifo |
|
| 48 |
+{
|
|
| 76 | 49 |
public: |
| 77 |
- int which; |
|
| 50 |
+ int which; |
|
| 78 | 51 |
Gba_Pcm pcm; |
| 79 | 52 |
|
| 80 |
- void write_control( int data ); |
|
| 81 |
- void write_fifo( int data ); |
|
| 82 |
- void timer_overflowed( int which_timer ); |
|
| 53 |
+ void write_control(int data); |
|
| 54 |
+ void write_fifo(int data); |
|
| 55 |
+ void timer_overflowed(int which_timer); |
|
| 83 | 56 |
|
| 84 |
- // public only so save state routines can access it |
|
| 85 |
- int readIndex; |
|
| 86 |
- int count; |
|
| 87 |
- int writeIndex; |
|
| 88 |
- uint8_t fifo [32]; |
|
| 89 |
- int dac; |
|
| 90 | 57 |
private: |
| 91 |
- |
|
| 92 |
- int timer; |
|
| 58 |
+ int readIndex; |
|
| 59 |
+ int count; |
|
| 60 |
+ int writeIndex; |
|
| 61 |
+ uint8_t fifo[32]; |
|
| 62 |
+ int dac; |
|
| 63 |
+ int timer; |
|
| 93 | 64 |
bool enabled; |
| 94 | 65 |
}; |
| 95 | 66 |
|
| 96 |
-static Gba_Pcm_Fifo pcm [2]; |
|
| 97 |
-static Gb_Apu* gb_apu; |
|
| 98 |
-static Stereo_Buffer* stereo_buffer; |
|
| 67 |
+static Gba_Pcm_Fifo pcm[2]; |
|
| 68 |
+static std::unique_ptr<Gb_Apu> gb_apu; |
|
| 69 |
+static std::unique_ptr<Stereo_Buffer> stereo_buffer; |
|
| 99 | 70 |
|
| 100 |
-static Blip_Synth<blip_best_quality,1> pcm_synth [3]; // 32 kHz, 16 kHz, 8 kHz |
|
| 71 |
+static Blip_Synth<blip_best_quality, 1> pcm_synth[3]; // 32 kHz, 16 kHz, 8 kHz |
|
| 101 | 72 |
|
| 102 | 73 |
static inline blip_time_t blip_time() |
| 103 | 74 |
{
|
| 104 | 75 |
return SOUND_CLOCK_TICKS - soundTicks; |
| 105 | 76 |
} |
| 106 | 77 |
|
| 107 |
-void Gba_Pcm::init() |
|
| 78 |
+inline void Gba_Pcm::init() |
|
| 108 | 79 |
{
|
| 109 |
- output = 0; |
|
| 110 |
- last_time = 0; |
|
| 111 |
- last_amp = 0; |
|
| 112 |
- shift = 0; |
|
| 80 |
+ this->output = nullptr; |
|
| 81 |
+ this->last_time = 0; |
|
| 82 |
+ this->last_amp = 0; |
|
| 83 |
+ this->shift = 0; |
|
| 113 | 84 |
} |
| 114 | 85 |
|
| 115 |
-void Gba_Pcm::apply_control( int idx ) |
|
| 86 |
+void Gba_Pcm::apply_control(int idx) |
|
| 116 | 87 |
{
|
| 117 |
- shift = ~ioMem [SGCNT0_H] >> (2 + idx) & 1; |
|
| 88 |
+ this->shift = (~ioMem[SGCNT0_H] >> (2 + idx)) & 1; |
|
| 118 | 89 |
|
| 119 | 90 |
int ch = 0; |
| 120 |
- if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) ) |
|
| 121 |
- ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3; |
|
| 91 |
+ if (((soundEnableFlag >> idx) & 0x100) && (ioMem[NR52] & 0x80)) |
|
| 92 |
+ ch = (ioMem[SGCNT0_H + 1] >> (idx * 4)) & 3; |
|
| 122 | 93 |
|
| 123 |
- Blip_Buffer* out = 0; |
|
| 124 |
- switch ( ch ) |
|
| 94 |
+ Blip_Buffer *out = nullptr; |
|
| 95 |
+ switch (ch) |
|
| 125 | 96 |
{
|
| 126 |
- case 1: out = stereo_buffer->right(); break; |
|
| 127 |
- case 2: out = stereo_buffer->left(); break; |
|
| 128 |
- case 3: out = stereo_buffer->center(); break; |
|
| 97 |
+ case 1: |
|
| 98 |
+ out = stereo_buffer->right(); |
|
| 99 |
+ break; |
|
| 100 |
+ case 2: |
|
| 101 |
+ out = stereo_buffer->left(); |
|
| 102 |
+ break; |
|
| 103 |
+ case 3: |
|
| 104 |
+ out = stereo_buffer->center(); |
|
| 129 | 105 |
} |
| 130 | 106 |
|
| 131 |
- if ( output != out ) |
|
| 107 |
+ if (this->output != out) |
|
| 132 | 108 |
{
|
| 133 |
- if ( output ) |
|
| 109 |
+ if (this->output) |
|
| 134 | 110 |
{
|
| 135 |
- output->set_modified(); |
|
| 136 |
- pcm_synth [0].offset( blip_time(), -last_amp, output ); |
|
| 111 |
+ blip_time_t time = blip_time(); |
|
| 112 |
+ |
|
| 113 |
+ this->output->set_modified(); |
|
| 114 |
+ |
|
| 115 |
+ int filter = 0; |
|
| 116 |
+ if (soundInterpolation) |
|
| 117 |
+ {
|
|
| 118 |
+ // base filtering on how long since last sample was output |
|
| 119 |
+ int period = time - this->last_time; |
|
| 120 |
+ |
|
| 121 |
+ int idx = period / 512; |
|
| 122 |
+ if (idx >= 3) |
|
| 123 |
+ idx = 3; |
|
| 124 |
+ |
|
| 125 |
+ static const int filters[] = { 0, 0, 1, 2 };
|
|
| 126 |
+ filter = filters[idx]; |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ pcm_synth[filter].offset(time, -this->last_amp, this->output); |
|
| 137 | 130 |
} |
| 138 |
- last_amp = 0; |
|
| 139 |
- output = out; |
|
| 131 |
+ this->last_amp = 0; |
|
| 132 |
+ this->output = out; |
|
| 140 | 133 |
} |
| 141 | 134 |
} |
| 142 | 135 |
|
| 143 |
-void Gba_Pcm::end_frame( blip_time_t time ) |
|
| 136 |
+inline void Gba_Pcm::end_frame(blip_time_t time) |
|
| 144 | 137 |
{
|
| 145 |
- last_time -= time; |
|
| 146 |
- if ( last_time < -2048 ) |
|
| 147 |
- last_time = -2048; |
|
| 138 |
+ this->last_time -= time; |
|
| 139 |
+ if (this->last_time < -2048) |
|
| 140 |
+ this->last_time = -2048; |
|
| 148 | 141 |
|
| 149 |
- if ( output ) |
|
| 150 |
- output->set_modified(); |
|
| 142 |
+ if (this->output) |
|
| 143 |
+ this->output->set_modified(); |
|
| 151 | 144 |
} |
| 152 | 145 |
|
| 153 |
-void Gba_Pcm::update( int dac ) |
|
| 146 |
+void Gba_Pcm::update(int dac) |
|
| 154 | 147 |
{
|
| 155 |
- if ( output ) |
|
| 148 |
+ if (this->output) |
|
| 156 | 149 |
{
|
| 157 | 150 |
blip_time_t time = blip_time(); |
| 158 | 151 |
|
| 159 |
- dac = (int8_t) dac >> shift; |
|
| 160 |
- int delta = dac - last_amp; |
|
| 161 |
- if ( delta ) |
|
| 152 |
+ dac = static_cast<int8_t>(dac) >> this->shift; |
|
| 153 |
+ int delta = dac - this->last_amp; |
|
| 154 |
+ if (delta) |
|
| 162 | 155 |
{
|
| 163 |
- last_amp = dac; |
|
| 156 |
+ this->last_amp = dac; |
|
| 164 | 157 |
|
| 165 | 158 |
int filter = 0; |
| 166 |
- if ( soundInterpolation ) |
|
| 159 |
+ if (soundInterpolation) |
|
| 167 | 160 |
{
|
| 168 | 161 |
// base filtering on how long since last sample was output |
| 169 |
- int period = time - last_time; |
|
| 162 |
+ int period = time - this->last_time; |
|
| 170 | 163 |
|
| 171 |
- int idx = (unsigned) period / 512; |
|
| 172 |
- if ( idx >= 3 ) |
|
| 164 |
+ int idx = period / 512; |
|
| 165 |
+ if (idx >= 3) |
|
| 173 | 166 |
idx = 3; |
| 174 | 167 |
|
| 175 |
- static int const filters [4] = { 0, 0, 1, 2 };
|
|
| 176 |
- filter = filters [idx]; |
|
| 168 |
+ static const int filters[] = { 0, 0, 1, 2 };
|
|
| 169 |
+ filter = filters[idx]; |
|
| 177 | 170 |
} |
| 178 | 171 |
|
| 179 |
- pcm_synth [filter].offset( time, delta, output ); |
|
| 172 |
+ pcm_synth[filter].offset(time, delta, this->output); |
|
| 180 | 173 |
} |
| 181 |
- last_time = time; |
|
| 174 |
+ this->last_time = time; |
|
| 182 | 175 |
} |
| 183 | 176 |
} |
| 184 | 177 |
|
| 185 |
-void Gba_Pcm_Fifo::timer_overflowed( int which_timer ) |
|
| 178 |
+void Gba_Pcm_Fifo::timer_overflowed(int which_timer) |
|
| 186 | 179 |
{
|
| 187 |
- if ( which_timer == timer && enabled ) |
|
| 180 |
+ if (which_timer == this->timer && this->enabled) |
|
| 188 | 181 |
{
|
| 189 |
- if ( count <= 16 ) |
|
| 182 |
+ if (this->count <= 16) |
|
| 190 | 183 |
{
|
| 191 | 184 |
// Need to fill FIFO |
| 192 |
- CPUCheckDMA( 3, which ? 4 : 2 ); |
|
| 193 |
- if ( count <= 16 ) |
|
| 185 |
+ CPUCheckDMA(3, this->which ? 4 : 2); |
|
| 186 |
+ if (this->count <= 16) |
|
| 194 | 187 |
{
|
| 195 | 188 |
// Not filled by DMA, so fill with 16 bytes of silence |
| 196 |
- int reg = which ? FIFOB_L : FIFOA_L; |
|
| 197 |
- for ( int n = 4; n--; ) |
|
| 189 |
+ int reg = this->which ? FIFOB_L : FIFOA_L; |
|
| 190 |
+ for (int n = 4; n--; ) |
|
| 198 | 191 |
{
|
| 199 |
- soundEvent(reg , (uint16_t)0); |
|
| 200 |
- soundEvent(reg+2, (uint16_t)0); |
|
| 192 |
+ soundEvent(reg, static_cast<uint16_t>(0)); |
|
| 193 |
+ soundEvent(reg + 2, static_cast<uint16_t>(0)); |
|
| 201 | 194 |
} |
| 202 | 195 |
} |
| 203 | 196 |
} |
| 204 | 197 |
|
| 205 | 198 |
// Read next sample from FIFO |
| 206 |
- count--; |
|
| 207 |
- dac = fifo [readIndex]; |
|
| 208 |
- readIndex = (readIndex + 1) & 31; |
|
| 209 |
- pcm.update( dac ); |
|
| 199 |
+ --this->count; |
|
| 200 |
+ this->dac = this->fifo[this->readIndex]; |
|
| 201 |
+ this->readIndex = (this->readIndex + 1) & 31; |
|
| 202 |
+ this->pcm.update(this->dac); |
|
| 210 | 203 |
} |
| 211 | 204 |
} |
| 212 | 205 |
|
| 213 |
-void Gba_Pcm_Fifo::write_control( int data ) |
|
| 206 |
+void Gba_Pcm_Fifo::write_control(int data) |
|
| 214 | 207 |
{
|
| 215 |
- enabled = (data & 0x0300) ? true : false; |
|
| 216 |
- timer = (data & 0x0400) ? 1 : 0; |
|
| 208 |
+ this->enabled = !!(data & 0x0300); |
|
| 209 |
+ this->timer = !!(data & 0x0400); |
|
| 217 | 210 |
|
| 218 |
- if ( data & 0x0800 ) |
|
| 211 |
+ if (data & 0x0800) |
|
| 219 | 212 |
{
|
| 220 | 213 |
// Reset |
| 221 |
- writeIndex = 0; |
|
| 222 |
- readIndex = 0; |
|
| 223 |
- count = 0; |
|
| 224 |
- dac = 0; |
|
| 225 |
- memset( fifo, 0, sizeof fifo ); |
|
| 214 |
+ this->writeIndex = 0; |
|
| 215 |
+ this->readIndex = 0; |
|
| 216 |
+ this->count = 0; |
|
| 217 |
+ this->dac = 0; |
|
| 218 |
+ memset(this->fifo, 0, sizeof(this->fifo)); |
|
| 226 | 219 |
} |
| 227 | 220 |
|
| 228 |
- pcm.apply_control( which ); |
|
| 229 |
- pcm.update( dac ); |
|
| 221 |
+ this->pcm.apply_control(this->which); |
|
| 222 |
+ this->pcm.update(this->dac); |
|
| 230 | 223 |
} |
| 231 | 224 |
|
| 232 |
-void Gba_Pcm_Fifo::write_fifo( int data ) |
|
| 225 |
+inline void Gba_Pcm_Fifo::write_fifo(int data) |
|
| 233 | 226 |
{
|
| 234 |
- fifo [writeIndex ] = data & 0xFF; |
|
| 235 |
- fifo [writeIndex+1] = data >> 8; |
|
| 236 |
- count += 2; |
|
| 237 |
- writeIndex = (writeIndex + 2) & 31; |
|
| 227 |
+ this->fifo[this->writeIndex] = data & 0xFF; |
|
| 228 |
+ this->fifo[this->writeIndex + 1] = data >> 8; |
|
| 229 |
+ this->count += 2; |
|
| 230 |
+ this->writeIndex = (this->writeIndex + 2) & 31; |
|
| 238 | 231 |
} |
| 239 | 232 |
|
| 240 | 233 |
static void apply_control() |
| 241 | 234 |
{
|
| 242 |
- pcm [0].pcm.apply_control( 0 ); |
|
| 243 |
- pcm [1].pcm.apply_control( 1 ); |
|
| 235 |
+ pcm[0].pcm.apply_control(0); |
|
| 236 |
+ pcm[1].pcm.apply_control(1); |
|
| 244 | 237 |
} |
| 245 | 238 |
|
| 246 |
-static int gba_to_gb_sound( int addr ) |
|
| 239 |
+static int gba_to_gb_sound(int addr) |
|
| 247 | 240 |
{
|
| 248 |
- static const int table [0x40] = |
|
| 241 |
+ static const int table[] = |
|
| 249 | 242 |
{
|
| 250 |
- 0xFF10, 0,0xFF11,0xFF12,0xFF13,0xFF14, 0, 0, |
|
| 251 |
- 0xFF16,0xFF17, 0, 0,0xFF18,0xFF19, 0, 0, |
|
| 252 |
- 0xFF1A, 0,0xFF1B,0xFF1C,0xFF1D,0xFF1E, 0, 0, |
|
| 253 |
- 0xFF20,0xFF21, 0, 0,0xFF22,0xFF23, 0, 0, |
|
| 254 |
- 0xFF24,0xFF25, 0, 0,0xFF26, 0, 0, 0, |
|
| 255 |
- 0, 0, 0, 0, 0, 0, 0, 0, |
|
| 256 |
- 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37, |
|
| 257 |
- 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F, |
|
| 243 |
+ 0xFF10, 0, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0, 0, |
|
| 244 |
+ 0xFF16, 0xFF17, 0, 0, 0xFF18, 0xFF19, 0, 0, |
|
| 245 |
+ 0xFF1A, 0, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0, 0, |
|
| 246 |
+ 0xFF20, 0xFF21, 0, 0, 0xFF22, 0xFF23, 0, 0, |
|
| 247 |
+ 0xFF24, 0xFF25, 0, 0, 0xFF26, 0, 0, 0, |
|
| 248 |
+ 0, 0, 0, 0, 0, 0, 0, 0, |
|
| 249 |
+ 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, |
|
| 250 |
+ 0xFF38, 0xFF39, 0xFF3A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F, |
|
| 258 | 251 |
}; |
| 259 |
- if ( addr >= 0x60 && addr < 0xA0 ) |
|
| 260 |
- return table [addr - 0x60]; |
|
| 252 |
+ if (addr >= 0x60 && addr < 0xA0) |
|
| 253 |
+ return table[addr - 0x60]; |
|
| 261 | 254 |
return 0; |
| 262 | 255 |
} |
| 263 | 256 |
|
| 264 | 257 |
void soundEvent(uint32_t address, uint8_t data) |
| 265 | 258 |
{
|
| 266 |
- int gb_addr = gba_to_gb_sound( address ); |
|
| 267 |
- if ( gb_addr ) |
|
| 259 |
+ int gb_addr = gba_to_gb_sound(address); |
|
| 260 |
+ if (gb_addr) |
|
| 268 | 261 |
{
|
| 269 | 262 |
ioMem[address] = data; |
| 270 |
- gb_apu->write_register( blip_time(), gb_addr, data ); |
|
| 263 |
+ gb_apu->write_register(blip_time(), gb_addr, data); |
|
| 271 | 264 |
|
| 272 |
- if ( address == NR52 ) |
|
| 265 |
+ if (address == NR52) |
|
| 273 | 266 |
apply_control(); |
| 274 | 267 |
} |
| 275 | 268 |
|
| ... | ... |
@@ -278,102 +271,98 @@ void soundEvent(uint32_t address, uint8_t data) |
| 278 | 271 |
// TODO: what about byte writes to SGCNT0_H etc.? |
| 279 | 272 |
} |
| 280 | 273 |
|
| 281 |
-static void apply_volume( bool apu_only = false ) |
|
| 274 |
+static void apply_volume(bool apu_only = false) |
|
| 282 | 275 |
{
|
| 283 |
- if ( !apu_only ) |
|
| 276 |
+ if (!apu_only) |
|
| 284 | 277 |
soundVolume_ = soundVolume; |
| 285 | 278 |
|
| 286 |
- if ( gb_apu ) |
|
| 279 |
+ if (gb_apu) |
|
| 287 | 280 |
{
|
| 288 |
- static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
|
|
| 289 |
- gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] ); |
|
| 281 |
+ static const float apu_vols[] = { 0.25, 0.5, 1, 0.25 };
|
|
| 282 |
+ gb_apu->volume(soundVolume_ * apu_vols[ioMem[SGCNT0_H] & 3]); |
|
| 290 | 283 |
} |
| 291 | 284 |
|
| 292 |
- if ( !apu_only ) |
|
| 293 |
- {
|
|
| 294 |
- for ( int i = 0; i < 3; i++ ) |
|
| 295 |
- pcm_synth [i].volume( 0.66 / 256 * soundVolume_ ); |
|
| 296 |
- } |
|
| 285 |
+ if (!apu_only) |
|
| 286 |
+ for (int i = 0; i < 3; ++i) |
|
| 287 |
+ pcm_synth[i].volume(0.66 / 256 * soundVolume_); |
|
| 297 | 288 |
} |
| 298 | 289 |
|
| 299 |
-static void write_SGCNT0_H( int data ) |
|
| 290 |
+static void write_SGCNT0_H(int data) |
|
| 300 | 291 |
{
|
| 301 |
- WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F ); |
|
| 302 |
- pcm [0].write_control( data ); |
|
| 303 |
- pcm [1].write_control( data >> 4 ); |
|
| 304 |
- apply_volume( true ); |
|
| 292 |
+ WRITE16LE(&ioMem[SGCNT0_H], data & 0x770F); |
|
| 293 |
+ pcm[0].write_control(data); |
|
| 294 |
+ pcm[1].write_control(data >> 4); |
|
| 295 |
+ apply_volume(true); |
|
| 305 | 296 |
} |
| 306 | 297 |
|
| 307 | 298 |
void soundEvent(uint32_t address, uint16_t data) |
| 308 | 299 |
{
|
| 309 |
- switch ( address ) |
|
| 300 |
+ switch (address) |
|
| 310 | 301 |
{
|
| 311 |
- case SGCNT0_H: |
|
| 312 |
- write_SGCNT0_H( data ); |
|
| 313 |
- break; |
|
| 314 |
- |
|
| 315 |
- case FIFOA_L: |
|
| 316 |
- case FIFOA_H: |
|
| 317 |
- pcm [0].write_fifo( data ); |
|
| 318 |
- WRITE16LE( &ioMem[address], data ); |
|
| 319 |
- break; |
|
| 320 |
- |
|
| 321 |
- case FIFOB_L: |
|
| 322 |
- case FIFOB_H: |
|
| 323 |
- pcm [1].write_fifo( data ); |
|
| 324 |
- WRITE16LE( &ioMem[address], data ); |
|
| 325 |
- break; |
|
| 326 |
- |
|
| 327 |
- case 0x88: |
|
| 328 |
- data &= 0xC3FF; |
|
| 329 |
- WRITE16LE( &ioMem[address], data ); |
|
| 330 |
- break; |
|
| 331 |
- |
|
| 332 |
- default: |
|
| 333 |
- soundEvent( address & ~1, (uint8_t) (data ) ); // even |
|
| 334 |
- soundEvent( address | 1, (uint8_t) (data >> 8) ); // odd |
|
| 335 |
- break; |
|
| 302 |
+ case SGCNT0_H: |
|
| 303 |
+ write_SGCNT0_H(data); |
|
| 304 |
+ break; |
|
| 305 |
+ |
|
| 306 |
+ case FIFOA_L: |
|
| 307 |
+ case FIFOA_H: |
|
| 308 |
+ pcm[0].write_fifo(data); |
|
| 309 |
+ WRITE16LE(&ioMem[address], data); |
|
| 310 |
+ break; |
|
| 311 |
+ |
|
| 312 |
+ case FIFOB_L: |
|
| 313 |
+ case FIFOB_H: |
|
| 314 |
+ pcm[1].write_fifo(data); |
|
| 315 |
+ WRITE16LE(&ioMem[address], data); |
|
| 316 |
+ break; |
|
| 317 |
+ |
|
| 318 |
+ case 0x88: |
|
| 319 |
+ data &= 0xC3FF; |
|
| 320 |
+ WRITE16LE(&ioMem[address], data); |
|
| 321 |
+ break; |
|
| 322 |
+ |
|
| 323 |
+ default: |
|
| 324 |
+ soundEvent(address & ~1, static_cast<uint8_t>(data)); // even |
|
| 325 |
+ soundEvent(address | 1, static_cast<uint8_t>(data >> 8)); // odd |
|
| 336 | 326 |
} |
| 337 | 327 |
} |
| 338 | 328 |
|
| 339 | 329 |
void soundTimerOverflow(int timer) |
| 340 | 330 |
{
|
| 341 |
- pcm [0].timer_overflowed( timer ); |
|
| 342 |
- pcm [1].timer_overflowed( timer ); |
|
| 331 |
+ pcm[0].timer_overflowed(timer); |
|
| 332 |
+ pcm[1].timer_overflowed(timer); |
|
| 343 | 333 |
} |
| 344 | 334 |
|
| 345 |
-static void end_frame( blip_time_t time ) |
|
| 335 |
+static void end_frame(blip_time_t time) |
|
| 346 | 336 |
{
|
| 347 |
- pcm [0].pcm.end_frame( time ); |
|
| 348 |
- pcm [1].pcm.end_frame( time ); |
|
| 337 |
+ pcm[0].pcm.end_frame(time); |
|
| 338 |
+ pcm[1].pcm.end_frame(time); |
|
| 349 | 339 |
|
| 350 |
- gb_apu ->end_frame( time ); |
|
| 351 |
- stereo_buffer->end_frame( time ); |
|
| 340 |
+ gb_apu->end_frame(time); |
|
| 341 |
+ stereo_buffer->end_frame(time); |
|
| 352 | 342 |
} |
| 353 | 343 |
|
| 354 |
-void flush_samples(Multi_Buffer * buffer) |
|
| 344 |
+void flush_samples(Multi_Buffer *buffer) |
|
| 355 | 345 |
{
|
| 356 | 346 |
// We want to write the data frame by frame to support legacy audio drivers |
| 357 | 347 |
// that don't use the length parameter of the write method. |
| 358 | 348 |
// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the |
| 359 | 349 |
// samples at once to help reducing the audio delay on all platforms. |
| 360 |
- int soundBufferLen = ( soundSampleRate / 60 ) * 4; |
|
| 350 |
+ int soundBufferLen = (soundSampleRate / 60) * 4; |
|
| 361 | 351 |
|
| 362 | 352 |
// soundBufferLen should have a whole number of sample pairs |
| 363 |
- assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 ); |
|
| 353 |
+ assert(!(soundBufferLen % (2 * sizeof(*soundFinalWave)))); |
|
| 364 | 354 |
|
| 365 | 355 |
// number of samples in output buffer |
| 366 |
- int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; |
|
| 356 |
+ int out_buf_size = soundBufferLen / sizeof(*soundFinalWave); |
|
| 367 | 357 |
|
| 368 | 358 |
// Keep filling and writing soundFinalWave until it can't be fully filled |
| 369 |
- while ( buffer->samples_avail() >= out_buf_size ) |
|
| 359 |
+ while (buffer->samples_avail() >= out_buf_size) |
|
| 370 | 360 |
{
|
| 371 |
- buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); |
|
| 372 |
- if(soundPaused) |
|
| 361 |
+ buffer->read_samples(reinterpret_cast<blip_sample_t *>(soundFinalWave), out_buf_size); |
|
| 362 |
+ if (soundPaused) |
|
| 373 | 363 |
soundResume(); |
| 374 | 364 |
|
| 375 | 365 |
soundDriver->write(soundFinalWave, soundBufferLen); |
| 376 |
- //systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen); |
|
| 377 | 366 |
} |
| 378 | 367 |
} |
| 379 | 368 |
|
| ... | ... |
@@ -381,31 +370,31 @@ static void apply_filtering() |
| 381 | 370 |
{
|
| 382 | 371 |
soundFiltering_ = soundFiltering; |
| 383 | 372 |
|
| 384 |
- int const base_freq = (int) (32768 - soundFiltering_ * 16384); |
|
| 385 |
- int const nyquist = stereo_buffer->sample_rate() / 2; |
|
| 373 |
+ int base_freq = static_cast<int>(32768 - soundFiltering_ * 16384); |
|
| 374 |
+ int nyquist = stereo_buffer->sample_rate() / 2; |
|
| 386 | 375 |
|
| 387 |
- for ( int i = 0; i < 3; i++ ) |
|
| 376 |
+ for (int i = 0; i < 3; ++i) |
|
| 388 | 377 |
{
|
| 389 | 378 |
int cutoff = base_freq >> i; |
| 390 |
- if ( cutoff > nyquist ) |
|
| 379 |
+ if (cutoff > nyquist) |
|
| 391 | 380 |
cutoff = nyquist; |
| 392 |
- pcm_synth [i].treble_eq( blip_eq_t( 0, 0, stereo_buffer->sample_rate(), cutoff ) ); |
|
| 381 |
+ pcm_synth[i].treble_eq(blip_eq_t(0, 0, stereo_buffer->sample_rate(), cutoff)); |
|
| 393 | 382 |
} |
| 394 | 383 |
} |
| 395 | 384 |
|
| 396 | 385 |
void psoundTickfn() |
| 397 | 386 |
{
|
| 398 |
- if ( gb_apu && stereo_buffer ) |
|
| 387 |
+ if (gb_apu && stereo_buffer) |
|
| 399 | 388 |
{
|
| 400 | 389 |
// Run sound hardware to present |
| 401 |
- end_frame( SOUND_CLOCK_TICKS ); |
|
| 390 |
+ end_frame(SOUND_CLOCK_TICKS); |
|
| 402 | 391 |
|
| 403 |
- flush_samples(stereo_buffer); |
|
| 392 |
+ flush_samples(stereo_buffer.get()); |
|
| 404 | 393 |
|
| 405 |
- if ( soundFiltering_ != soundFiltering ) |
|
| 394 |
+ if (soundFiltering_ != soundFiltering) |
|
| 406 | 395 |
apply_filtering(); |
| 407 | 396 |
|
| 408 |
- if ( soundVolume_ != soundVolume ) |
|
| 397 |
+ if (soundVolume_ != soundVolume) |
|
| 409 | 398 |
apply_volume(); |
| 410 | 399 |
} |
| 411 | 400 |
|
| ... | ... |
@@ -414,32 +403,27 @@ void psoundTickfn() |
| 414 | 403 |
|
| 415 | 404 |
static void apply_muting() |
| 416 | 405 |
{
|
| 417 |
- if ( !stereo_buffer || !ioMem ) |
|
| 406 |
+ if (!stereo_buffer) |
|
| 418 | 407 |
return; |
| 419 | 408 |
|
| 420 | 409 |
// PCM |
| 421 | 410 |
apply_control(); |
| 422 | 411 |
|
| 423 |
- if ( gb_apu ) |
|
| 424 |
- {
|
|
| 412 |
+ if (gb_apu) |
|
| 425 | 413 |
// APU |
| 426 |
- for ( int i = 0; i < 4; i++ ) |
|
| 427 |
- {
|
|
| 428 |
- if ( soundEnableFlag >> i & 1 ) |
|
| 429 |
- gb_apu->set_output( stereo_buffer->center(), |
|
| 430 |
- stereo_buffer->left(), stereo_buffer->right(), i ); |
|
| 414 |
+ for (int i = 0; i < 4; ++i) |
|
| 415 |
+ if ((soundEnableFlag >> i) & 1) |
|
| 416 |
+ gb_apu->set_output(stereo_buffer->center(), stereo_buffer->left(), stereo_buffer->right(), i); |
|
| 431 | 417 |
else |
| 432 |
- gb_apu->set_output( 0, 0, 0, i ); |
|
| 433 |
- } |
|
| 434 |
- } |
|
| 418 |
+ gb_apu->set_output(nullptr, nullptr, nullptr, i); |
|
| 435 | 419 |
} |
| 436 | 420 |
|
| 437 | 421 |
static void reset_apu() |
| 438 | 422 |
{
|
| 439 | 423 |
gb_apu->reduce_clicks(soundDeclicking); |
| 440 |
- gb_apu->reset( gb_apu->mode_agb, true ); |
|
| 424 |
+ gb_apu->reset(gb_apu->mode_agb, true); |
|
| 441 | 425 |
|
| 442 |
- if ( stereo_buffer ) |
|
| 426 |
+ if (stereo_buffer) |
|
| 443 | 427 |
stereo_buffer->clear(); |
| 444 | 428 |
|
| 445 | 429 |
soundTicks = SOUND_CLOCK_TICKS; |
| ... | ... |
@@ -447,31 +431,25 @@ static void reset_apu() |
| 447 | 431 |
|
| 448 | 432 |
static void remake_stereo_buffer() |
| 449 | 433 |
{
|
| 450 |
- if ( !ioMem ) |
|
| 451 |
- return; |
|
| 452 |
- |
|
| 453 | 434 |
// Clears pointers kept to old stereo_buffer |
| 454 |
- pcm [0].pcm.init(); |
|
| 455 |
- pcm [1].pcm.init(); |
|
| 435 |
+ pcm[0].pcm.init(); |
|
| 436 |
+ pcm[1].pcm.init(); |
|
| 456 | 437 |
|
| 457 | 438 |
// APU |
| 458 |
- if ( !gb_apu ) |
|
| 439 |
+ if (!gb_apu) |
|
| 459 | 440 |
{
|
| 460 |
- gb_apu = new Gb_Apu; // TODO: handle out of memory |
|
| 441 |
+ gb_apu.reset(new Gb_Apu); // TODO: handle out of memory |
|
| 461 | 442 |
reset_apu(); |
| 462 | 443 |
} |
| 463 | 444 |
|
| 464 | 445 |
// Stereo_Buffer |
| 465 |
- delete stereo_buffer; |
|
| 466 |
- stereo_buffer = 0; |
|
| 467 |
- |
|
| 468 |
- stereo_buffer = new Stereo_Buffer; // TODO: handle out of memory |
|
| 469 |
- stereo_buffer->set_sample_rate( soundSampleRate ); // TODO: handle out of memory |
|
| 470 |
- stereo_buffer->clock_rate( gb_apu->clock_rate ); |
|
| 446 |
+ stereo_buffer.reset(new Stereo_Buffer); // TODO: handle out of memory |
|
| 447 |
+ stereo_buffer->set_sample_rate(soundSampleRate); // TODO: handle out of memory |
|
| 448 |
+ stereo_buffer->clock_rate(gb_apu->clock_rate); |
|
| 471 | 449 |
|
| 472 | 450 |
// PCM |
| 473 |
- pcm [0].which = 0; |
|
| 474 |
- pcm [1].which = 1; |
|
| 451 |
+ pcm[0].which = 0; |
|
| 452 |
+ pcm[1].which = 1; |
|
| 475 | 453 |
apply_filtering(); |
| 476 | 454 |
|
| 477 | 455 |
// Volume Level |
| ... | ... |
@@ -481,27 +459,13 @@ static void remake_stereo_buffer() |
| 481 | 459 |
|
| 482 | 460 |
void soundShutdown() |
| 483 | 461 |
{
|
| 484 |
- if (soundDriver) |
|
| 485 |
- {
|
|
| 486 |
- delete soundDriver; |
|
| 487 |
- soundDriver = 0; |
|
| 488 |
- } |
|
| 462 |
+ soundDriver.reset(); |
|
| 489 | 463 |
|
| 490 | 464 |
// APU |
| 491 |
- if ( gb_apu ) |
|
| 492 |
- {
|
|
| 493 |
- delete gb_apu; |
|
| 494 |
- gb_apu = 0; |
|
| 495 |
- } |
|
| 465 |
+ gb_apu.reset(); |
|
| 496 | 466 |
|
| 497 | 467 |
// Stereo_Buffer |
| 498 |
- if (stereo_buffer) |
|
| 499 |
- {
|
|
| 500 |
- delete stereo_buffer; |
|
| 501 |
- stereo_buffer = 0; |
|
| 502 |
- } |
|
| 503 |
- |
|
| 504 |
- //systemOnSoundShutdown(); |
|
| 468 |
+ stereo_buffer.reset(); |
|
| 505 | 469 |
} |
| 506 | 470 |
|
| 507 | 471 |
void soundPause() |
| ... | ... |
@@ -518,27 +482,12 @@ void soundResume() |
| 518 | 482 |
soundDriver->resume(); |
| 519 | 483 |
} |
| 520 | 484 |
|
| 521 |
-void soundSetVolume( float volume ) |
|
| 522 |
-{
|
|
| 523 |
- soundVolume = volume; |
|
| 524 |
-} |
|
| 525 |
- |
|
| 526 |
-float soundGetVolume() |
|
| 527 |
-{
|
|
| 528 |
- return soundVolume; |
|
| 529 |
-} |
|
| 530 |
- |
|
| 531 | 485 |
void soundSetEnable(int channels) |
| 532 | 486 |
{
|
| 533 | 487 |
soundEnableFlag = channels; |
| 534 | 488 |
apply_muting(); |
| 535 | 489 |
} |
| 536 | 490 |
|
| 537 |
-int soundGetEnable() |
|
| 538 |
-{
|
|
| 539 |
- return (soundEnableFlag & 0x30f); |
|
| 540 |
-} |
|
| 541 |
- |
|
| 542 | 491 |
void soundReset() |
| 543 | 492 |
{
|
| 544 | 493 |
soundDriver->reset(); |
| ... | ... |
@@ -547,16 +496,15 @@ void soundReset() |
| 547 | 496 |
reset_apu(); |
| 548 | 497 |
|
| 549 | 498 |
soundPaused = true; |
| 550 |
- SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
|
| 551 |
- soundTicks = SOUND_CLOCK_TICKS_; |
|
| 499 |
+ SOUND_CLOCK_TICKS = soundTicks = SOUND_CLOCK_TICKS_; |
|
| 552 | 500 |
|
| 553 |
- soundEvent( NR52, (uint8_t) 0x80 ); |
|
| 501 |
+ soundEvent(NR52, static_cast<uint8_t>(0x80)); |
|
| 554 | 502 |
} |
| 555 | 503 |
|
| 556 | 504 |
bool soundInit() |
| 557 | 505 |
{
|
| 558 |
- soundDriver = systemSoundInit(); |
|
| 559 |
- if ( !soundDriver ) |
|
| 506 |
+ soundDriver.reset(systemSoundInit()); |
|
| 507 |
+ if (!soundDriver) |
|
| 560 | 508 |
return false; |
| 561 | 509 |
|
| 562 | 510 |
if (!soundDriver->init(soundSampleRate)) |
| ... | ... |
@@ -566,266 +514,12 @@ bool soundInit() |
| 566 | 514 |
return true; |
| 567 | 515 |
} |
| 568 | 516 |
|
| 569 |
-void soundSetThrottle(unsigned short throttle) |
|
| 570 |
-{
|
|
| 571 |
- if(!soundDriver) |
|
| 572 |
- return; |
|
| 573 |
- soundDriver->setThrottle(throttle); |
|
| 574 |
-} |
|
| 575 |
- |
|
| 576 |
-long soundGetSampleRate() |
|
| 577 |
-{
|
|
| 578 |
- return soundSampleRate; |
|
| 579 |
-} |
|
| 580 |
- |
|
| 581 | 517 |
void soundSetSampleRate(long sampleRate) |
| 582 | 518 |
{
|
| 583 |
- if ( soundSampleRate != sampleRate ) |
|
| 519 |
+ if (soundSampleRate != sampleRate) |
|
| 584 | 520 |
{
|
| 585 |
- /*if ( systemCanChangeSoundQuality() ) |
|
| 586 |
- {
|
|
| 587 |
- soundShutdown(); |
|
| 588 |
- soundSampleRate = sampleRate; |
|
| 589 |
- soundInit(); |
|
| 590 |
- } |
|
| 591 |
- else*/ |
|
| 592 |
- {
|
|
| 593 |
- soundSampleRate = sampleRate; |
|
| 594 |
- } |
|
| 521 |
+ soundSampleRate = sampleRate; |
|
| 595 | 522 |
|
| 596 | 523 |
remake_stereo_buffer(); |
| 597 | 524 |
} |
| 598 | 525 |
} |
| 599 |
- |
|
| 600 |
-/*static int dummy_state [16]; |
|
| 601 |
- |
|
| 602 |
-#define SKIP( type, name ) { dummy_state, sizeof (type) }
|
|
| 603 |
- |
|
| 604 |
-#define LOAD( type, name ) { &name, sizeof (type) }
|
|
| 605 |
- |
|
| 606 |
-static struct {
|
|
| 607 |
- gb_apu_state_t apu; |
|
| 608 |
- |
|
| 609 |
- // old state |
|
| 610 |
- u8 soundDSAValue; |
|
| 611 |
- int soundDSBValue; |
|
| 612 |
-} state; |
|
| 613 |
- |
|
| 614 |
-// Old GBA sound state format |
|
| 615 |
-static variable_desc old_gba_state [] = |
|
| 616 |
-{
|
|
| 617 |
- SKIP( int, soundPaused ), |
|
| 618 |
- SKIP( int, soundPlay ), |
|
| 619 |
- SKIP( int, soundTicks ), |
|
| 620 |
- SKIP( int, SOUND_CLOCK_TICKS ), |
|
| 621 |
- SKIP( int, soundLevel1 ), |
|
| 622 |
- SKIP( int, soundLevel2 ), |
|
| 623 |
- SKIP( int, soundBalance ), |
|
| 624 |
- SKIP( int, soundMasterOn ), |
|
| 625 |
- SKIP( int, soundIndex ), |
|
| 626 |
- SKIP( int, sound1On ), |
|
| 627 |
- SKIP( int, sound1ATL ), |
|
| 628 |
- SKIP( int, sound1Skip ), |
|
| 629 |
- SKIP( int, sound1Index ), |
|
| 630 |
- SKIP( int, sound1Continue ), |
|
| 631 |
- SKIP( int, sound1EnvelopeVolume ), |
|
| 632 |
- SKIP( int, sound1EnvelopeATL ), |
|
| 633 |
- SKIP( int, sound1EnvelopeATLReload ), |
|
| 634 |
- SKIP( int, sound1EnvelopeUpDown ), |
|
| 635 |
- SKIP( int, sound1SweepATL ), |
|
| 636 |
- SKIP( int, sound1SweepATLReload ), |
|
| 637 |
- SKIP( int, sound1SweepSteps ), |
|
| 638 |
- SKIP( int, sound1SweepUpDown ), |
|
| 639 |
- SKIP( int, sound1SweepStep ), |
|
| 640 |
- SKIP( int, sound2On ), |
|
| 641 |
- SKIP( int, sound2ATL ), |
|
| 642 |
- SKIP( int, sound2Skip ), |
|
| 643 |
- SKIP( int, sound2Index ), |
|
| 644 |
- SKIP( int, sound2Continue ), |
|
| 645 |
- SKIP( int, sound2EnvelopeVolume ), |
|
| 646 |
- SKIP( int, sound2EnvelopeATL ), |
|
| 647 |
- SKIP( int, sound2EnvelopeATLReload ), |
|
| 648 |
- SKIP( int, sound2EnvelopeUpDown ), |
|
| 649 |
- SKIP( int, sound3On ), |
|
| 650 |
- SKIP( int, sound3ATL ), |
|
| 651 |
- SKIP( int, sound3Skip ), |
|
| 652 |
- SKIP( int, sound3Index ), |
|
| 653 |
- SKIP( int, sound3Continue ), |
|
| 654 |
- SKIP( int, sound3OutputLevel ), |
|
| 655 |
- SKIP( int, sound4On ), |
|
| 656 |
- SKIP( int, sound4ATL ), |
|
| 657 |
- SKIP( int, sound4Skip ), |
|
| 658 |
- SKIP( int, sound4Index ), |
|
| 659 |
- SKIP( int, sound4Clock ), |
|
| 660 |
- SKIP( int, sound4ShiftRight ), |
|
| 661 |
- SKIP( int, sound4ShiftSkip ), |
|
| 662 |
- SKIP( int, sound4ShiftIndex ), |
|
| 663 |
- SKIP( int, sound4NSteps ), |
|
| 664 |
- SKIP( int, sound4CountDown ), |
|
| 665 |
- SKIP( int, sound4Continue ), |
|
| 666 |
- SKIP( int, sound4EnvelopeVolume ), |
|
| 667 |
- SKIP( int, sound4EnvelopeATL ), |
|
| 668 |
- SKIP( int, sound4EnvelopeATLReload ), |
|
| 669 |
- SKIP( int, sound4EnvelopeUpDown ), |
|
| 670 |
- LOAD( int, soundEnableFlag ), |
|
| 671 |
- SKIP( int, soundControl ), |
|
| 672 |
- LOAD( int, pcm [0].readIndex ), |
|
| 673 |
- LOAD( int, pcm [0].count ), |
|
| 674 |
- LOAD( int, pcm [0].writeIndex ), |
|
| 675 |
- SKIP( u8, soundDSAEnabled ), // was bool, which was one byte on MS compiler |
|
| 676 |
- SKIP( int, soundDSATimer ), |
|
| 677 |
- LOAD( u8 [32], pcm [0].fifo ), |
|
| 678 |
- LOAD( u8, state.soundDSAValue ), |
|
| 679 |
- LOAD( int, pcm [1].readIndex ), |
|
| 680 |
- LOAD( int, pcm [1].count ), |
|
| 681 |
- LOAD( int, pcm [1].writeIndex ), |
|
| 682 |
- SKIP( int, soundDSBEnabled ), |
|
| 683 |
- SKIP( int, soundDSBTimer ), |
|
| 684 |
- LOAD( u8 [32], pcm [1].fifo ), |
|
| 685 |
- LOAD( int, state.soundDSBValue ), |
|
| 686 |
- |
|
| 687 |
- // skipped manually |
|
| 688 |
- //LOAD( int, soundBuffer[0][0], 6*735 }, |
|
| 689 |
- //LOAD( int, soundFinalWave[0], 2*735 }, |
|
| 690 |
- { NULL, 0 }
|
|
| 691 |
-}; |
|
| 692 |
- |
|
| 693 |
-variable_desc old_gba_state2 [] = |
|
| 694 |
-{
|
|
| 695 |
- LOAD( u8 [0x20], state.apu.regs [0x20] ), |
|
| 696 |
- SKIP( int, sound3Bank ), |
|
| 697 |
- SKIP( int, sound3DataSize ), |
|
| 698 |
- SKIP( int, sound3ForcedOutput ), |
|
| 699 |
- { NULL, 0 }
|
|
| 700 |
-}; |
|
| 701 |
- |
|
| 702 |
-// New state format |
|
| 703 |
-static variable_desc gba_state [] = |
|
| 704 |
-{
|
|
| 705 |
- // PCM |
|
| 706 |
- LOAD( int, pcm [0].readIndex ), |
|
| 707 |
- LOAD( int, pcm [0].count ), |
|
| 708 |
- LOAD( int, pcm [0].writeIndex ), |
|
| 709 |
- LOAD(u8[32],pcm[0].fifo ), |
|
| 710 |
- LOAD( int, pcm [0].dac ), |
|
| 711 |
- |
|
| 712 |
- SKIP( int [4], room_for_expansion ), |
|
| 713 |
- |
|
| 714 |
- LOAD( int, pcm [1].readIndex ), |
|
| 715 |
- LOAD( int, pcm [1].count ), |
|
| 716 |
- LOAD( int, pcm [1].writeIndex ), |
|
| 717 |
- LOAD(u8[32],pcm[1].fifo ), |
|
| 718 |
- LOAD( int, pcm [1].dac ), |
|
| 719 |
- |
|
| 720 |
- SKIP( int [4], room_for_expansion ), |
|
| 721 |
- |
|
| 722 |
- // APU |
|
| 723 |
- LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks) |
|
| 724 |
- LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action |
|
| 725 |
- LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run |
|
| 726 |
- |
|
| 727 |
- LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register |
|
| 728 |
- LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action |
|
| 729 |
- LOAD( int, state.apu.sweep_enabled ), |
|
| 730 |
- LOAD( int, state.apu.sweep_neg ), // obscure internal flag |
|
| 731 |
- LOAD( int, state.apu.noise_divider ), |
|
| 732 |
- LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM |
|
| 733 |
- |
|
| 734 |
- LOAD( int [4], state.apu.delay ), // clocks until next channel action |
|
| 735 |
- LOAD( int [4], state.apu.length_ctr ), |
|
| 736 |
- LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR |
|
| 737 |
- LOAD( int [4], state.apu.enabled ), // internal enabled flag |
|
| 738 |
- |
|
| 739 |
- LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action |
|
| 740 |
- LOAD( int [3], state.apu.env_volume ), |
|
| 741 |
- LOAD( int [3], state.apu.env_enabled ), |
|
| 742 |
- |
|
| 743 |
- SKIP( int [13], room_for_expansion ), |
|
| 744 |
- |
|
| 745 |
- // Emulator |
|
| 746 |
- LOAD( int, soundEnableFlag ), |
|
| 747 |
- |
|
| 748 |
- SKIP( int [15], room_for_expansion ), |
|
| 749 |
- |
|
| 750 |
- { NULL, 0 }
|
|
| 751 |
-}; |
|
| 752 |
- |
|
| 753 |
-// Reads and discards count bytes from in |
|
| 754 |
-static void skip_read( gzFile in, int count ) |
|
| 755 |
-{
|
|
| 756 |
- char buf [512]; |
|
| 757 |
- |
|
| 758 |
- while ( count ) |
|
| 759 |
- {
|
|
| 760 |
- int n = sizeof buf; |
|
| 761 |
- if ( n > count ) |
|
| 762 |
- n = count; |
|
| 763 |
- |
|
| 764 |
- count -= n; |
|
| 765 |
- utilGzRead( in, buf, n ); |
|
| 766 |
- } |
|
| 767 |
-} |
|
| 768 |
- |
|
| 769 |
-void soundSaveGame( gzFile out ) |
|
| 770 |
-{
|
|
| 771 |
- gb_apu->save_state( &state.apu ); |
|
| 772 |
- |
|
| 773 |
- // Be sure areas for expansion get written as zero |
|
| 774 |
- memset( dummy_state, 0, sizeof dummy_state ); |
|
| 775 |
- |
|
| 776 |
- utilWriteData( out, gba_state ); |
|
| 777 |
-} |
|
| 778 |
- |
|
| 779 |
-static void soundReadGameOld( gzFile in, int version ) |
|
| 780 |
-{
|
|
| 781 |
- // Read main data |
|
| 782 |
- utilReadData( in, old_gba_state ); |
|
| 783 |
- skip_read( in, 6*735 + 2*735 ); |
|
| 784 |
- |
|
| 785 |
- // Copy APU regs |
|
| 786 |
- static int const regs_to_copy [] = {
|
|
| 787 |
- NR10, NR11, NR12, NR13, NR14, |
|
| 788 |
- NR21, NR22, NR23, NR24, |
|
| 789 |
- NR30, NR31, NR32, NR33, NR34, |
|
| 790 |
- NR41, NR42, NR43, NR44, |
|
| 791 |
- NR50, NR51, NR52, -1 |
|
| 792 |
- }; |
|
| 793 |
- |
|
| 794 |
- ioMem [NR52] |= 0x80; // old sound played even when this wasn't set (power on) |
|
| 795 |
- |
|
| 796 |
- for ( int i = 0; regs_to_copy [i] >= 0; i++ ) |
|
| 797 |
- state.apu.regs [gba_to_gb_sound( regs_to_copy [i] ) - 0xFF10] = ioMem [regs_to_copy [i]]; |
|
| 798 |
- |
|
| 799 |
- // Copy wave RAM to both banks |
|
| 800 |
- memcpy( &state.apu.regs [0x20], &ioMem [0x90], 0x10 ); |
|
| 801 |
- memcpy( &state.apu.regs [0x30], &ioMem [0x90], 0x10 ); |
|
| 802 |
- |
|
| 803 |
- // Read both banks of wave RAM if available |
|
| 804 |
- if ( version >= SAVE_GAME_VERSION_3 ) |
|
| 805 |
- utilReadData( in, old_gba_state2 ); |
|
| 806 |
- |
|
| 807 |
- // Restore PCM |
|
| 808 |
- pcm [0].dac = state.soundDSAValue; |
|
| 809 |
- pcm [1].dac = state.soundDSBValue; |
|
| 810 |
- |
|
| 811 |
- (void) utilReadInt( in ); // ignore quality |
|
| 812 |
-} |
|
| 813 |
- |
|
| 814 |
-#include <stdio.h> |
|
| 815 |
- |
|
| 816 |
-void soundReadGame( gzFile in, int version ) |
|
| 817 |
-{
|
|
| 818 |
- // Prepare APU and default state |
|
| 819 |
- reset_apu(); |
|
| 820 |
- gb_apu->save_state( &state.apu ); |
|
| 821 |
- |
|
| 822 |
- if ( version > SAVE_GAME_VERSION_9 ) |
|
| 823 |
- utilReadData( in, gba_state ); |
|
| 824 |
- else |
|
| 825 |
- soundReadGameOld( in, version ); |
|
| 826 |
- |
|
| 827 |
- gb_apu->load_state( state.apu ); |
|
| 828 |
- write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F ); |
|
| 829 |
- |
|
| 830 |
- apply_muting(); |
|
| 831 |
-}*/ |
| ... | ... |
@@ -13,6 +13,7 @@ |
| 13 | 13 |
#include "../common/SoundDriver.h" |
| 14 | 14 |
|
| 15 | 15 |
extern SoundDriver *systemSoundInit(); |
| 16 |
+bool soundDeclicking = true; |
|
| 16 | 17 |
|
| 17 | 18 |
#define NR10 0x60 |
| 18 | 19 |
#define NR11 0x62 |
| ... | ... |
@@ -42,7 +43,7 @@ extern bool stopState; // TODO: silence sound when true |
| 42 | 43 |
|
| 43 | 44 |
int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second |
| 44 | 45 |
|
| 45 |
-static u16 soundFinalWave [6400]; |
|
| 46 |
+static uint16_t soundFinalWave [6400]; |
|
| 46 | 47 |
long soundSampleRate = 44100; |
| 47 | 48 |
bool soundInterpolation = true; |
| 48 | 49 |
bool soundPaused = true; |
| ... | ... |
@@ -84,7 +85,7 @@ public: |
| 84 | 85 |
int readIndex; |
| 85 | 86 |
int count; |
| 86 | 87 |
int writeIndex; |
| 87 |
- u8 fifo [32]; |
|
| 88 |
+ uint8_t fifo [32]; |
|
| 88 | 89 |
int dac; |
| 89 | 90 |
private: |
| 90 | 91 |
|
| ... | ... |
@@ -155,7 +156,7 @@ void Gba_Pcm::update( int dac ) |
| 155 | 156 |
{
|
| 156 | 157 |
blip_time_t time = blip_time(); |
| 157 | 158 |
|
| 158 |
- dac = (s8) dac >> shift; |
|
| 159 |
+ dac = (int8_t) dac >> shift; |
|
| 159 | 160 |
int delta = dac - last_amp; |
| 160 | 161 |
if ( delta ) |
| 161 | 162 |
{
|
| ... | ... |
@@ -195,8 +196,8 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer ) |
| 195 | 196 |
int reg = which ? FIFOB_L : FIFOA_L; |
| 196 | 197 |
for ( int n = 4; n--; ) |
| 197 | 198 |
{
|
| 198 |
- soundEvent(reg , (u16)0); |
|
| 199 |
- soundEvent(reg+2, (u16)0); |
|
| 199 |
+ soundEvent(reg , (uint16_t)0); |
|
| 200 |
+ soundEvent(reg+2, (uint16_t)0); |
|
| 200 | 201 |
} |
| 201 | 202 |
} |
| 202 | 203 |
} |
| ... | ... |
@@ -260,7 +261,7 @@ static int gba_to_gb_sound( int addr ) |
| 260 | 261 |
return 0; |
| 261 | 262 |
} |
| 262 | 263 |
|
| 263 |
-void soundEvent(u32 address, u8 data) |
|
| 264 |
+void soundEvent(uint32_t address, uint8_t data) |
|
| 264 | 265 |
{
|
| 265 | 266 |
int gb_addr = gba_to_gb_sound( address ); |
| 266 | 267 |
if ( gb_addr ) |
| ... | ... |
@@ -303,7 +304,7 @@ static void write_SGCNT0_H( int data ) |
| 303 | 304 |
apply_volume( true ); |
| 304 | 305 |
} |
| 305 | 306 |
|
| 306 |
-void soundEvent(u32 address, u16 data) |
|
| 307 |
+void soundEvent(uint32_t address, uint16_t data) |
|
| 307 | 308 |
{
|
| 308 | 309 |
switch ( address ) |
| 309 | 310 |
{
|
| ... | ... |
@@ -329,8 +330,8 @@ void soundEvent(u32 address, u16 data) |
| 329 | 330 |
break; |
| 330 | 331 |
|
| 331 | 332 |
default: |
| 332 |
- soundEvent( address & ~1, (u8) (data ) ); // even |
|
| 333 |
- soundEvent( address | 1, (u8) (data >> 8) ); // odd |
|
| 333 |
+ soundEvent( address & ~1, (uint8_t) (data ) ); // even |
|
| 334 |
+ soundEvent( address | 1, (uint8_t) (data >> 8) ); // odd |
|
| 334 | 335 |
break; |
| 335 | 336 |
} |
| 336 | 337 |
} |
| ... | ... |
@@ -435,6 +436,7 @@ static void apply_muting() |
| 435 | 436 |
|
| 436 | 437 |
static void reset_apu() |
| 437 | 438 |
{
|
| 439 |
+ gb_apu->reduce_clicks(soundDeclicking); |
|
| 438 | 440 |
gb_apu->reset( gb_apu->mode_agb, true ); |
| 439 | 441 |
|
| 440 | 442 |
if ( stereo_buffer ) |
| ... | ... |
@@ -485,6 +487,20 @@ void soundShutdown() |
| 485 | 487 |
soundDriver = 0; |
| 486 | 488 |
} |
| 487 | 489 |
|
| 490 |
+ // APU |
|
| 491 |
+ if ( gb_apu ) |
|
| 492 |
+ {
|
|
| 493 |
+ delete gb_apu; |
|
| 494 |
+ gb_apu = 0; |
|
| 495 |
+ } |
|
| 496 |
+ |
|
| 497 |
+ // Stereo_Buffer |
|
| 498 |
+ if (stereo_buffer) |
|
| 499 |
+ {
|
|
| 500 |
+ delete stereo_buffer; |
|
| 501 |
+ stereo_buffer = 0; |
|
| 502 |
+ } |
|
| 503 |
+ |
|
| 488 | 504 |
//systemOnSoundShutdown(); |
| 489 | 505 |
} |
| 490 | 506 |
|
| ... | ... |
@@ -534,7 +550,7 @@ void soundReset() |
| 534 | 550 |
SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
| 535 | 551 |
soundTicks = SOUND_CLOCK_TICKS_; |
| 536 | 552 |
|
| 537 |
- soundEvent( NR52, (u8) 0x80 ); |
|
| 553 |
+ soundEvent( NR52, (uint8_t) 0x80 ); |
|
| 538 | 554 |
} |
| 539 | 555 |
|
| 540 | 556 |
bool soundInit() |
| ... | ... |
@@ -42,7 +42,7 @@ extern bool stopState; // TODO: silence sound when true |
| 42 | 42 |
|
| 43 | 43 |
int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second |
| 44 | 44 |
|
| 45 |
-static u16 soundFinalWave [1600]; |
|
| 45 |
+static u16 soundFinalWave [6400]; |
|
| 46 | 46 |
long soundSampleRate = 44100; |
| 47 | 47 |
bool soundInterpolation = true; |
| 48 | 48 |
bool soundPaused = true; |
| ... | ... |
@@ -452,6 +452,13 @@ static void remake_stereo_buffer() |
| 452 | 452 |
pcm [0].pcm.init(); |
| 453 | 453 |
pcm [1].pcm.init(); |
| 454 | 454 |
|
| 455 |
+ // APU |
|
| 456 |
+ if ( !gb_apu ) |
|
| 457 |
+ {
|
|
| 458 |
+ gb_apu = new Gb_Apu; // TODO: handle out of memory |
|
| 459 |
+ reset_apu(); |
|
| 460 |
+ } |
|
| 461 |
+ |
|
| 455 | 462 |
// Stereo_Buffer |
| 456 | 463 |
delete stereo_buffer; |
| 457 | 464 |
stereo_buffer = 0; |
| ... | ... |
@@ -465,13 +472,7 @@ static void remake_stereo_buffer() |
| 465 | 472 |
pcm [1].which = 1; |
| 466 | 473 |
apply_filtering(); |
| 467 | 474 |
|
| 468 |
- // APU |
|
| 469 |
- if ( !gb_apu ) |
|
| 470 |
- {
|
|
| 471 |
- gb_apu = new Gb_Apu; // TODO: handle out of memory |
|
| 472 |
- reset_apu(); |
|
| 473 |
- } |
|
| 474 |
- |
|
| 475 |
+ // Volume Level |
|
| 475 | 476 |
apply_muting(); |
| 476 | 477 |
apply_volume(); |
| 477 | 478 |
} |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,814 @@ |
| 1 |
+#include <string.h> |
|
| 2 |
+ |
|
| 3 |
+#include "Sound.h" |
|
| 4 |
+ |
|
| 5 |
+#include "GBA.h" |
|
| 6 |
+#include "Globals.h" |
|
| 7 |
+//#include "../Util.h" |
|
| 8 |
+#include "../common/Port.h" |
|
| 9 |
+ |
|
| 10 |
+#include "../apu/Gb_Apu.h" |
|
| 11 |
+#include "../apu/Multi_Buffer.h" |
|
| 12 |
+ |
|
| 13 |
+#include "../common/SoundDriver.h" |
|
| 14 |
+ |
|
| 15 |
+extern SoundDriver *systemSoundInit(); |
|
| 16 |
+ |
|
| 17 |
+#define NR10 0x60 |
|
| 18 |
+#define NR11 0x62 |
|
| 19 |
+#define NR12 0x63 |
|
| 20 |
+#define NR13 0x64 |
|
| 21 |
+#define NR14 0x65 |
|
| 22 |
+#define NR21 0x68 |
|
| 23 |
+#define NR22 0x69 |
|
| 24 |
+#define NR23 0x6c |
|
| 25 |
+#define NR24 0x6d |
|
| 26 |
+#define NR30 0x70 |
|
| 27 |
+#define NR31 0x72 |
|
| 28 |
+#define NR32 0x73 |
|
| 29 |
+#define NR33 0x74 |
|
| 30 |
+#define NR34 0x75 |
|
| 31 |
+#define NR41 0x78 |
|
| 32 |
+#define NR42 0x79 |
|
| 33 |
+#define NR43 0x7c |
|
| 34 |
+#define NR44 0x7d |
|
| 35 |
+#define NR50 0x80 |
|
| 36 |
+#define NR51 0x81 |
|
| 37 |
+#define NR52 0x84 |
|
| 38 |
+ |
|
| 39 |
+SoundDriver * soundDriver = 0; |
|
| 40 |
+ |
|
| 41 |
+extern bool stopState; // TODO: silence sound when true |
|
| 42 |
+ |
|
| 43 |
+int const SOUND_CLOCK_TICKS_ = 167772; // 1/100 second |
|
| 44 |
+ |
|
| 45 |
+static u16 soundFinalWave [1600]; |
|
| 46 |
+long soundSampleRate = 44100; |
|
| 47 |
+bool soundInterpolation = true; |
|
| 48 |
+bool soundPaused = true; |
|
| 49 |
+float soundFiltering = 0.5f; |
|
| 50 |
+int SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
|
| 51 |
+int soundTicks = SOUND_CLOCK_TICKS_; |
|
| 52 |
+ |
|
| 53 |
+static float soundVolume = 1.0f; |
|
| 54 |
+static int soundEnableFlag = 0x3ff; // emulator channels enabled |
|
| 55 |
+static float soundFiltering_ = -1; |
|
| 56 |
+static float soundVolume_ = -1; |
|
| 57 |
+ |
|
| 58 |
+void interp_rate() { /* empty for now */ }
|
|
| 59 |
+ |
|
| 60 |
+class Gba_Pcm {
|
|
| 61 |
+public: |
|
| 62 |
+ void init(); |
|
| 63 |
+ void apply_control( int idx ); |
|
| 64 |
+ void update( int dac ); |
|
| 65 |
+ void end_frame( blip_time_t ); |
|
| 66 |
+ |
|
| 67 |
+private: |
|
| 68 |
+ Blip_Buffer* output; |
|
| 69 |
+ blip_time_t last_time; |
|
| 70 |
+ int last_amp; |
|
| 71 |
+ int shift; |
|
| 72 |
+}; |
|
| 73 |
+ |
|
| 74 |
+class Gba_Pcm_Fifo {
|
|
| 75 |
+public: |
|
| 76 |
+ int which; |
|
| 77 |
+ Gba_Pcm pcm; |
|
| 78 |
+ |
|
| 79 |
+ void write_control( int data ); |
|
| 80 |
+ void write_fifo( int data ); |
|
| 81 |
+ void timer_overflowed( int which_timer ); |
|
| 82 |
+ |
|
| 83 |
+ // public only so save state routines can access it |
|
| 84 |
+ int readIndex; |
|
| 85 |
+ int count; |
|
| 86 |
+ int writeIndex; |
|
| 87 |
+ u8 fifo [32]; |
|
| 88 |
+ int dac; |
|
| 89 |
+private: |
|
| 90 |
+ |
|
| 91 |
+ int timer; |
|
| 92 |
+ bool enabled; |
|
| 93 |
+}; |
|
| 94 |
+ |
|
| 95 |
+static Gba_Pcm_Fifo pcm [2]; |
|
| 96 |
+static Gb_Apu* gb_apu; |
|
| 97 |
+static Stereo_Buffer* stereo_buffer; |
|
| 98 |
+ |
|
| 99 |
+static Blip_Synth<blip_best_quality,1> pcm_synth [3]; // 32 kHz, 16 kHz, 8 kHz |
|
| 100 |
+ |
|
| 101 |
+static inline blip_time_t blip_time() |
|
| 102 |
+{
|
|
| 103 |
+ return SOUND_CLOCK_TICKS - soundTicks; |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+void Gba_Pcm::init() |
|
| 107 |
+{
|
|
| 108 |
+ output = 0; |
|
| 109 |
+ last_time = 0; |
|
| 110 |
+ last_amp = 0; |
|
| 111 |
+ shift = 0; |
|
| 112 |
+} |
|
| 113 |
+ |
|
| 114 |
+void Gba_Pcm::apply_control( int idx ) |
|
| 115 |
+{
|
|
| 116 |
+ shift = ~ioMem [SGCNT0_H] >> (2 + idx) & 1; |
|
| 117 |
+ |
|
| 118 |
+ int ch = 0; |
|
| 119 |
+ if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) ) |
|
| 120 |
+ ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3; |
|
| 121 |
+ |
|
| 122 |
+ Blip_Buffer* out = 0; |
|
| 123 |
+ switch ( ch ) |
|
| 124 |
+ {
|
|
| 125 |
+ case 1: out = stereo_buffer->right(); break; |
|
| 126 |
+ case 2: out = stereo_buffer->left(); break; |
|
| 127 |
+ case 3: out = stereo_buffer->center(); break; |
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ if ( output != out ) |
|
| 131 |
+ {
|
|
| 132 |
+ if ( output ) |
|
| 133 |
+ {
|
|
| 134 |
+ output->set_modified(); |
|
| 135 |
+ pcm_synth [0].offset( blip_time(), -last_amp, output ); |
|
| 136 |
+ } |
|
| 137 |
+ last_amp = 0; |
|
| 138 |
+ output = out; |
|
| 139 |
+ } |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+void Gba_Pcm::end_frame( blip_time_t time ) |
|
| 143 |
+{
|
|
| 144 |
+ last_time -= time; |
|
| 145 |
+ if ( last_time < -2048 ) |
|
| 146 |
+ last_time = -2048; |
|
| 147 |
+ |
|
| 148 |
+ if ( output ) |
|
| 149 |
+ output->set_modified(); |
|
| 150 |
+} |
|
| 151 |
+ |
|
| 152 |
+void Gba_Pcm::update( int dac ) |
|
| 153 |
+{
|
|
| 154 |
+ if ( output ) |
|
| 155 |
+ {
|
|
| 156 |
+ blip_time_t time = blip_time(); |
|
| 157 |
+ |
|
| 158 |
+ dac = (s8) dac >> shift; |
|
| 159 |
+ int delta = dac - last_amp; |
|
| 160 |
+ if ( delta ) |
|
| 161 |
+ {
|
|
| 162 |
+ last_amp = dac; |
|
| 163 |
+ |
|
| 164 |
+ int filter = 0; |
|
| 165 |
+ if ( soundInterpolation ) |
|
| 166 |
+ {
|
|
| 167 |
+ // base filtering on how long since last sample was output |
|
| 168 |
+ int period = time - last_time; |
|
| 169 |
+ |
|
| 170 |
+ int idx = (unsigned) period / 512; |
|
| 171 |
+ if ( idx >= 3 ) |
|
| 172 |
+ idx = 3; |
|
| 173 |
+ |
|
| 174 |
+ static int const filters [4] = { 0, 0, 1, 2 };
|
|
| 175 |
+ filter = filters [idx]; |
|
| 176 |
+ } |
|
| 177 |
+ |
|
| 178 |
+ pcm_synth [filter].offset( time, delta, output ); |
|
| 179 |
+ } |
|
| 180 |
+ last_time = time; |
|
| 181 |
+ } |
|
| 182 |
+} |
|
| 183 |
+ |
|
| 184 |
+void Gba_Pcm_Fifo::timer_overflowed( int which_timer ) |
|
| 185 |
+{
|
|
| 186 |
+ if ( which_timer == timer && enabled ) |
|
| 187 |
+ {
|
|
| 188 |
+ if ( count <= 16 ) |
|
| 189 |
+ {
|
|
| 190 |
+ // Need to fill FIFO |
|
| 191 |
+ CPUCheckDMA( 3, which ? 4 : 2 ); |
|
| 192 |
+ if ( count <= 16 ) |
|
| 193 |
+ {
|
|
| 194 |
+ // Not filled by DMA, so fill with 16 bytes of silence |
|
| 195 |
+ int reg = which ? FIFOB_L : FIFOA_L; |
|
| 196 |
+ for ( int n = 4; n--; ) |
|
| 197 |
+ {
|
|
| 198 |
+ soundEvent(reg , (u16)0); |
|
| 199 |
+ soundEvent(reg+2, (u16)0); |
|
| 200 |
+ } |
|
| 201 |
+ } |
|
| 202 |
+ } |
|
| 203 |
+ |
|
| 204 |
+ // Read next sample from FIFO |
|
| 205 |
+ count--; |
|
| 206 |
+ dac = fifo [readIndex]; |
|
| 207 |
+ readIndex = (readIndex + 1) & 31; |
|
| 208 |
+ pcm.update( dac ); |
|
| 209 |
+ } |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+void Gba_Pcm_Fifo::write_control( int data ) |
|
| 213 |
+{
|
|
| 214 |
+ enabled = (data & 0x0300) ? true : false; |
|
| 215 |
+ timer = (data & 0x0400) ? 1 : 0; |
|
| 216 |
+ |
|
| 217 |
+ if ( data & 0x0800 ) |
|
| 218 |
+ {
|
|
| 219 |
+ // Reset |
|
| 220 |
+ writeIndex = 0; |
|
| 221 |
+ readIndex = 0; |
|
| 222 |
+ count = 0; |
|
| 223 |
+ dac = 0; |
|
| 224 |
+ memset( fifo, 0, sizeof fifo ); |
|
| 225 |
+ } |
|
| 226 |
+ |
|
| 227 |
+ pcm.apply_control( which ); |
|
| 228 |
+ pcm.update( dac ); |
|
| 229 |
+} |
|
| 230 |
+ |
|
| 231 |
+void Gba_Pcm_Fifo::write_fifo( int data ) |
|
| 232 |
+{
|
|
| 233 |
+ fifo [writeIndex ] = data & 0xFF; |
|
| 234 |
+ fifo [writeIndex+1] = data >> 8; |
|
| 235 |
+ count += 2; |
|
| 236 |
+ writeIndex = (writeIndex + 2) & 31; |
|
| 237 |
+} |
|
| 238 |
+ |
|
| 239 |
+static void apply_control() |
|
| 240 |
+{
|
|
| 241 |
+ pcm [0].pcm.apply_control( 0 ); |
|
| 242 |
+ pcm [1].pcm.apply_control( 1 ); |
|
| 243 |
+} |
|
| 244 |
+ |
|
| 245 |
+static int gba_to_gb_sound( int addr ) |
|
| 246 |
+{
|
|
| 247 |
+ static const int table [0x40] = |
|
| 248 |
+ {
|
|
| 249 |
+ 0xFF10, 0,0xFF11,0xFF12,0xFF13,0xFF14, 0, 0, |
|
| 250 |
+ 0xFF16,0xFF17, 0, 0,0xFF18,0xFF19, 0, 0, |
|
| 251 |
+ 0xFF1A, 0,0xFF1B,0xFF1C,0xFF1D,0xFF1E, 0, 0, |
|
| 252 |
+ 0xFF20,0xFF21, 0, 0,0xFF22,0xFF23, 0, 0, |
|
| 253 |
+ 0xFF24,0xFF25, 0, 0,0xFF26, 0, 0, 0, |
|
| 254 |
+ 0, 0, 0, 0, 0, 0, 0, 0, |
|
| 255 |
+ 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37, |
|
| 256 |
+ 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F, |
|
| 257 |
+ }; |
|
| 258 |
+ if ( addr >= 0x60 && addr < 0xA0 ) |
|
| 259 |
+ return table [addr - 0x60]; |
|
| 260 |
+ return 0; |
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+void soundEvent(u32 address, u8 data) |
|
| 264 |
+{
|
|
| 265 |
+ int gb_addr = gba_to_gb_sound( address ); |
|
| 266 |
+ if ( gb_addr ) |
|
| 267 |
+ {
|
|
| 268 |
+ ioMem[address] = data; |
|
| 269 |
+ gb_apu->write_register( blip_time(), gb_addr, data ); |
|
| 270 |
+ |
|
| 271 |
+ if ( address == NR52 ) |
|
| 272 |
+ apply_control(); |
|
| 273 |
+ } |
|
| 274 |
+ |
|
| 275 |
+ ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f); |
|
| 276 |
+ |
|
| 277 |
+ // TODO: what about byte writes to SGCNT0_H etc.? |
|
| 278 |
+} |
|
| 279 |
+ |
|
| 280 |
+static void apply_volume( bool apu_only = false ) |
|
| 281 |
+{
|
|
| 282 |
+ if ( !apu_only ) |
|
| 283 |
+ soundVolume_ = soundVolume; |
|
| 284 |
+ |
|
| 285 |
+ if ( gb_apu ) |
|
| 286 |
+ {
|
|
| 287 |
+ static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
|
|
| 288 |
+ gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] ); |
|
| 289 |
+ } |
|
| 290 |
+ |
|
| 291 |
+ if ( !apu_only ) |
|
| 292 |
+ {
|
|
| 293 |
+ for ( int i = 0; i < 3; i++ ) |
|
| 294 |
+ pcm_synth [i].volume( 0.66 / 256 * soundVolume_ ); |
|
| 295 |
+ } |
|
| 296 |
+} |
|
| 297 |
+ |
|
| 298 |
+static void write_SGCNT0_H( int data ) |
|
| 299 |
+{
|
|
| 300 |
+ WRITE16LE( &ioMem [SGCNT0_H], data & 0x770F ); |
|
| 301 |
+ pcm [0].write_control( data ); |
|
| 302 |
+ pcm [1].write_control( data >> 4 ); |
|
| 303 |
+ apply_volume( true ); |
|
| 304 |
+} |
|
| 305 |
+ |
|
| 306 |
+void soundEvent(u32 address, u16 data) |
|
| 307 |
+{
|
|
| 308 |
+ switch ( address ) |
|
| 309 |
+ {
|
|
| 310 |
+ case SGCNT0_H: |
|
| 311 |
+ write_SGCNT0_H( data ); |
|
| 312 |
+ break; |
|
| 313 |
+ |
|
| 314 |
+ case FIFOA_L: |
|
| 315 |
+ case FIFOA_H: |
|
| 316 |
+ pcm [0].write_fifo( data ); |
|
| 317 |
+ WRITE16LE( &ioMem[address], data ); |
|
| 318 |
+ break; |
|
| 319 |
+ |
|
| 320 |
+ case FIFOB_L: |
|
| 321 |
+ case FIFOB_H: |
|
| 322 |
+ pcm [1].write_fifo( data ); |
|
| 323 |
+ WRITE16LE( &ioMem[address], data ); |
|
| 324 |
+ break; |
|
| 325 |
+ |
|
| 326 |
+ case 0x88: |
|
| 327 |
+ data &= 0xC3FF; |
|
| 328 |
+ WRITE16LE( &ioMem[address], data ); |
|
| 329 |
+ break; |
|
| 330 |
+ |
|
| 331 |
+ default: |
|
| 332 |
+ soundEvent( address & ~1, (u8) (data ) ); // even |
|
| 333 |
+ soundEvent( address | 1, (u8) (data >> 8) ); // odd |
|
| 334 |
+ break; |
|
| 335 |
+ } |
|
| 336 |
+} |
|
| 337 |
+ |
|
| 338 |
+void soundTimerOverflow(int timer) |
|
| 339 |
+{
|
|
| 340 |
+ pcm [0].timer_overflowed( timer ); |
|
| 341 |
+ pcm [1].timer_overflowed( timer ); |
|
| 342 |
+} |
|
| 343 |
+ |
|
| 344 |
+static void end_frame( blip_time_t time ) |
|
| 345 |
+{
|
|
| 346 |
+ pcm [0].pcm.end_frame( time ); |
|
| 347 |
+ pcm [1].pcm.end_frame( time ); |
|
| 348 |
+ |
|
| 349 |
+ gb_apu ->end_frame( time ); |
|
| 350 |
+ stereo_buffer->end_frame( time ); |
|
| 351 |
+} |
|
| 352 |
+ |
|
| 353 |
+void flush_samples(Multi_Buffer * buffer) |
|
| 354 |
+{
|
|
| 355 |
+ // We want to write the data frame by frame to support legacy audio drivers |
|
| 356 |
+ // that don't use the length parameter of the write method. |
|
| 357 |
+ // TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the |
|
| 358 |
+ // samples at once to help reducing the audio delay on all platforms. |
|
| 359 |
+ int soundBufferLen = ( soundSampleRate / 60 ) * 4; |
|
| 360 |
+ |
|
| 361 |
+ // soundBufferLen should have a whole number of sample pairs |
|
| 362 |
+ assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 ); |
|
| 363 |
+ |
|
| 364 |
+ // number of samples in output buffer |
|
| 365 |
+ int const out_buf_size = soundBufferLen / sizeof *soundFinalWave; |
|
| 366 |
+ |
|
| 367 |
+ // Keep filling and writing soundFinalWave until it can't be fully filled |
|
| 368 |
+ while ( buffer->samples_avail() >= out_buf_size ) |
|
| 369 |
+ {
|
|
| 370 |
+ buffer->read_samples( (blip_sample_t*) soundFinalWave, out_buf_size ); |
|
| 371 |
+ if(soundPaused) |
|
| 372 |
+ soundResume(); |
|
| 373 |
+ |
|
| 374 |
+ soundDriver->write(soundFinalWave, soundBufferLen); |
|
| 375 |
+ //systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen); |
|
| 376 |
+ } |
|
| 377 |
+} |
|
| 378 |
+ |
|
| 379 |
+static void apply_filtering() |
|
| 380 |
+{
|
|
| 381 |
+ soundFiltering_ = soundFiltering; |
|
| 382 |
+ |
|
| 383 |
+ int const base_freq = (int) (32768 - soundFiltering_ * 16384); |
|
| 384 |
+ int const nyquist = stereo_buffer->sample_rate() / 2; |
|
| 385 |
+ |
|
| 386 |
+ for ( int i = 0; i < 3; i++ ) |
|
| 387 |
+ {
|
|
| 388 |
+ int cutoff = base_freq >> i; |
|
| 389 |
+ if ( cutoff > nyquist ) |
|
| 390 |
+ cutoff = nyquist; |
|
| 391 |
+ pcm_synth [i].treble_eq( blip_eq_t( 0, 0, stereo_buffer->sample_rate(), cutoff ) ); |
|
| 392 |
+ } |
|
| 393 |
+} |
|
| 394 |
+ |
|
| 395 |
+void psoundTickfn() |
|
| 396 |
+{
|
|
| 397 |
+ if ( gb_apu && stereo_buffer ) |
|
| 398 |
+ {
|
|
| 399 |
+ // Run sound hardware to present |
|
| 400 |
+ end_frame( SOUND_CLOCK_TICKS ); |
|
| 401 |
+ |
|
| 402 |
+ flush_samples(stereo_buffer); |
|
| 403 |
+ |
|
| 404 |
+ if ( soundFiltering_ != soundFiltering ) |
|
| 405 |
+ apply_filtering(); |
|
| 406 |
+ |
|
| 407 |
+ if ( soundVolume_ != soundVolume ) |
|
| 408 |
+ apply_volume(); |
|
| 409 |
+ } |
|
| 410 |
+ |
|
| 411 |
+ ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f); |
|
| 412 |
+} |
|
| 413 |
+ |
|
| 414 |
+static void apply_muting() |
|
| 415 |
+{
|
|
| 416 |
+ if ( !stereo_buffer || !ioMem ) |
|
| 417 |
+ return; |
|
| 418 |
+ |
|
| 419 |
+ // PCM |
|
| 420 |
+ apply_control(); |
|
| 421 |
+ |
|
| 422 |
+ if ( gb_apu ) |
|
| 423 |
+ {
|
|
| 424 |
+ // APU |
|
| 425 |
+ for ( int i = 0; i < 4; i++ ) |
|
| 426 |
+ {
|
|
| 427 |
+ if ( soundEnableFlag >> i & 1 ) |
|
| 428 |
+ gb_apu->set_output( stereo_buffer->center(), |
|
| 429 |
+ stereo_buffer->left(), stereo_buffer->right(), i ); |
|
| 430 |
+ else |
|
| 431 |
+ gb_apu->set_output( 0, 0, 0, i ); |
|
| 432 |
+ } |
|
| 433 |
+ } |
|
| 434 |
+} |
|
| 435 |
+ |
|
| 436 |
+static void reset_apu() |
|
| 437 |
+{
|
|
| 438 |
+ gb_apu->reset( gb_apu->mode_agb, true ); |
|
| 439 |
+ |
|
| 440 |
+ if ( stereo_buffer ) |
|
| 441 |
+ stereo_buffer->clear(); |
|
| 442 |
+ |
|
| 443 |
+ soundTicks = SOUND_CLOCK_TICKS; |
|
| 444 |
+} |
|
| 445 |
+ |
|
| 446 |
+static void remake_stereo_buffer() |
|
| 447 |
+{
|
|
| 448 |
+ if ( !ioMem ) |
|
| 449 |
+ return; |
|
| 450 |
+ |
|
| 451 |
+ // Clears pointers kept to old stereo_buffer |
|
| 452 |
+ pcm [0].pcm.init(); |
|
| 453 |
+ pcm [1].pcm.init(); |
|
| 454 |
+ |
|
| 455 |
+ // Stereo_Buffer |
|
| 456 |
+ delete stereo_buffer; |
|
| 457 |
+ stereo_buffer = 0; |
|
| 458 |
+ |
|
| 459 |
+ stereo_buffer = new Stereo_Buffer; // TODO: handle out of memory |
|
| 460 |
+ stereo_buffer->set_sample_rate( soundSampleRate ); // TODO: handle out of memory |
|
| 461 |
+ stereo_buffer->clock_rate( gb_apu->clock_rate ); |
|
| 462 |
+ |
|
| 463 |
+ // PCM |
|
| 464 |
+ pcm [0].which = 0; |
|
| 465 |
+ pcm [1].which = 1; |
|
| 466 |
+ apply_filtering(); |
|
| 467 |
+ |
|
| 468 |
+ // APU |
|
| 469 |
+ if ( !gb_apu ) |
|
| 470 |
+ {
|
|
| 471 |
+ gb_apu = new Gb_Apu; // TODO: handle out of memory |
|
| 472 |
+ reset_apu(); |
|
| 473 |
+ } |
|
| 474 |
+ |
|
| 475 |
+ apply_muting(); |
|
| 476 |
+ apply_volume(); |
|
| 477 |
+} |
|
| 478 |
+ |
|
| 479 |
+void soundShutdown() |
|
| 480 |
+{
|
|
| 481 |
+ if (soundDriver) |
|
| 482 |
+ {
|
|
| 483 |
+ delete soundDriver; |
|
| 484 |
+ soundDriver = 0; |
|
| 485 |
+ } |
|
| 486 |
+ |
|
| 487 |
+ //systemOnSoundShutdown(); |
|
| 488 |
+} |
|
| 489 |
+ |
|
| 490 |
+void soundPause() |
|
| 491 |
+{
|
|
| 492 |
+ soundPaused = true; |
|
| 493 |
+ if (soundDriver) |
|
| 494 |
+ soundDriver->pause(); |
|
| 495 |
+} |
|
| 496 |
+ |
|
| 497 |
+void soundResume() |
|
| 498 |
+{
|
|
| 499 |
+ soundPaused = false; |
|
| 500 |
+ if (soundDriver) |
|
| 501 |
+ soundDriver->resume(); |
|
| 502 |
+} |
|
| 503 |
+ |
|
| 504 |
+void soundSetVolume( float volume ) |
|
| 505 |
+{
|
|
| 506 |
+ soundVolume = volume; |
|
| 507 |
+} |
|
| 508 |
+ |
|
| 509 |
+float soundGetVolume() |
|
| 510 |
+{
|
|
| 511 |
+ return soundVolume; |
|
| 512 |
+} |
|
| 513 |
+ |
|
| 514 |
+void soundSetEnable(int channels) |
|
| 515 |
+{
|
|
| 516 |
+ soundEnableFlag = channels; |
|
| 517 |
+ apply_muting(); |
|
| 518 |
+} |
|
| 519 |
+ |
|
| 520 |
+int soundGetEnable() |
|
| 521 |
+{
|
|
| 522 |
+ return (soundEnableFlag & 0x30f); |
|
| 523 |
+} |
|
| 524 |
+ |
|
| 525 |
+void soundReset() |
|
| 526 |
+{
|
|
| 527 |
+ soundDriver->reset(); |
|
| 528 |
+ |
|
| 529 |
+ remake_stereo_buffer(); |
|
| 530 |
+ reset_apu(); |
|
| 531 |
+ |
|
| 532 |
+ soundPaused = true; |
|
| 533 |
+ SOUND_CLOCK_TICKS = SOUND_CLOCK_TICKS_; |
|
| 534 |
+ soundTicks = SOUND_CLOCK_TICKS_; |
|
| 535 |
+ |
|
| 536 |
+ soundEvent( NR52, (u8) 0x80 ); |
|
| 537 |
+} |
|
| 538 |
+ |
|
| 539 |
+bool soundInit() |
|
| 540 |
+{
|
|
| 541 |
+ soundDriver = systemSoundInit(); |
|
| 542 |
+ if ( !soundDriver ) |
|
| 543 |
+ return false; |
|
| 544 |
+ |
|
| 545 |
+ if (!soundDriver->init(soundSampleRate)) |
|
| 546 |
+ return false; |
|
| 547 |
+ |
|
| 548 |
+ soundPaused = true; |
|
| 549 |
+ return true; |
|
| 550 |
+} |
|
| 551 |
+ |
|
| 552 |
+void soundSetThrottle(unsigned short throttle) |
|
| 553 |
+{
|
|
| 554 |
+ if(!soundDriver) |
|
| 555 |
+ return; |
|
| 556 |
+ soundDriver->setThrottle(throttle); |
|
| 557 |
+} |
|
| 558 |
+ |
|
| 559 |
+long soundGetSampleRate() |
|
| 560 |
+{
|
|
| 561 |
+ return soundSampleRate; |
|
| 562 |
+} |
|
| 563 |
+ |
|
| 564 |
+void soundSetSampleRate(long sampleRate) |
|
| 565 |
+{
|
|
| 566 |
+ if ( soundSampleRate != sampleRate ) |
|
| 567 |
+ {
|
|
| 568 |
+ /*if ( systemCanChangeSoundQuality() ) |
|
| 569 |
+ {
|
|
| 570 |
+ soundShutdown(); |
|
| 571 |
+ soundSampleRate = sampleRate; |
|
| 572 |
+ soundInit(); |
|
| 573 |
+ } |
|
| 574 |
+ else*/ |
|
| 575 |
+ {
|
|
| 576 |
+ soundSampleRate = sampleRate; |
|
| 577 |
+ } |
|
| 578 |
+ |
|
| 579 |
+ remake_stereo_buffer(); |
|
| 580 |
+ } |
|
| 581 |
+} |
|
| 582 |
+ |
|
| 583 |
+/*static int dummy_state [16]; |
|
| 584 |
+ |
|
| 585 |
+#define SKIP( type, name ) { dummy_state, sizeof (type) }
|
|
| 586 |
+ |
|
| 587 |
+#define LOAD( type, name ) { &name, sizeof (type) }
|
|
| 588 |
+ |
|
| 589 |
+static struct {
|
|
| 590 |
+ gb_apu_state_t apu; |
|
| 591 |
+ |
|
| 592 |
+ // old state |
|
| 593 |
+ u8 soundDSAValue; |
|
| 594 |
+ int soundDSBValue; |
|
| 595 |
+} state; |
|
| 596 |
+ |
|
| 597 |
+// Old GBA sound state format |
|
| 598 |
+static variable_desc old_gba_state [] = |
|
| 599 |
+{
|
|
| 600 |
+ SKIP( int, soundPaused ), |
|
| 601 |
+ SKIP( int, soundPlay ), |
|
| 602 |
+ SKIP( int, soundTicks ), |
|
| 603 |
+ SKIP( int, SOUND_CLOCK_TICKS ), |
|
| 604 |
+ SKIP( int, soundLevel1 ), |
|
| 605 |
+ SKIP( int, soundLevel2 ), |
|
| 606 |
+ SKIP( int, soundBalance ), |
|
| 607 |
+ SKIP( int, soundMasterOn ), |
|
| 608 |
+ SKIP( int, soundIndex ), |
|
| 609 |
+ SKIP( int, sound1On ), |
|
| 610 |
+ SKIP( int, sound1ATL ), |
|
| 611 |
+ SKIP( int, sound1Skip ), |
|
| 612 |
+ SKIP( int, sound1Index ), |
|
| 613 |
+ SKIP( int, sound1Continue ), |
|
| 614 |
+ SKIP( int, sound1EnvelopeVolume ), |
|
| 615 |
+ SKIP( int, sound1EnvelopeATL ), |
|
| 616 |
+ SKIP( int, sound1EnvelopeATLReload ), |
|
| 617 |
+ SKIP( int, sound1EnvelopeUpDown ), |
|
| 618 |
+ SKIP( int, sound1SweepATL ), |
|
| 619 |
+ SKIP( int, sound1SweepATLReload ), |
|
| 620 |
+ SKIP( int, sound1SweepSteps ), |
|
| 621 |
+ SKIP( int, sound1SweepUpDown ), |
|
| 622 |
+ SKIP( int, sound1SweepStep ), |
|
| 623 |
+ SKIP( int, sound2On ), |
|
| 624 |
+ SKIP( int, sound2ATL ), |
|
| 625 |
+ SKIP( int, sound2Skip ), |
|
| 626 |
+ SKIP( int, sound2Index ), |
|
| 627 |
+ SKIP( int, sound2Continue ), |
|
| 628 |
+ SKIP( int, sound2EnvelopeVolume ), |
|
| 629 |
+ SKIP( int, sound2EnvelopeATL ), |
|
| 630 |
+ SKIP( int, sound2EnvelopeATLReload ), |
|
| 631 |
+ SKIP( int, sound2EnvelopeUpDown ), |
|
| 632 |
+ SKIP( int, sound3On ), |
|
| 633 |
+ SKIP( int, sound3ATL ), |
|
| 634 |
+ SKIP( int, sound3Skip ), |
|
| 635 |
+ SKIP( int, sound3Index ), |
|
| 636 |
+ SKIP( int, sound3Continue ), |
|
| 637 |
+ SKIP( int, sound3OutputLevel ), |
|
| 638 |
+ SKIP( int, sound4On ), |
|
| 639 |
+ SKIP( int, sound4ATL ), |
|
| 640 |
+ SKIP( int, sound4Skip ), |
|
| 641 |
+ SKIP( int, sound4Index ), |
|
| 642 |
+ SKIP( int, sound4Clock ), |
|
| 643 |
+ SKIP( int, sound4ShiftRight ), |
|
| 644 |
+ SKIP( int, sound4ShiftSkip ), |
|
| 645 |
+ SKIP( int, sound4ShiftIndex ), |
|
| 646 |
+ SKIP( int, sound4NSteps ), |
|
| 647 |
+ SKIP( int, sound4CountDown ), |
|
| 648 |
+ SKIP( int, sound4Continue ), |
|
| 649 |
+ SKIP( int, sound4EnvelopeVolume ), |
|
| 650 |
+ SKIP( int, sound4EnvelopeATL ), |
|
| 651 |
+ SKIP( int, sound4EnvelopeATLReload ), |
|
| 652 |
+ SKIP( int, sound4EnvelopeUpDown ), |
|
| 653 |
+ LOAD( int, soundEnableFlag ), |
|
| 654 |
+ SKIP( int, soundControl ), |
|
| 655 |
+ LOAD( int, pcm [0].readIndex ), |
|
| 656 |
+ LOAD( int, pcm [0].count ), |
|
| 657 |
+ LOAD( int, pcm [0].writeIndex ), |
|
| 658 |
+ SKIP( u8, soundDSAEnabled ), // was bool, which was one byte on MS compiler |
|
| 659 |
+ SKIP( int, soundDSATimer ), |
|
| 660 |
+ LOAD( u8 [32], pcm [0].fifo ), |
|
| 661 |
+ LOAD( u8, state.soundDSAValue ), |
|
| 662 |
+ LOAD( int, pcm [1].readIndex ), |
|
| 663 |
+ LOAD( int, pcm [1].count ), |
|
| 664 |
+ LOAD( int, pcm [1].writeIndex ), |
|
| 665 |
+ SKIP( int, soundDSBEnabled ), |
|
| 666 |
+ SKIP( int, soundDSBTimer ), |
|
| 667 |
+ LOAD( u8 [32], pcm [1].fifo ), |
|
| 668 |
+ LOAD( int, state.soundDSBValue ), |
|
| 669 |
+ |
|
| 670 |
+ // skipped manually |
|
| 671 |
+ //LOAD( int, soundBuffer[0][0], 6*735 }, |
|
| 672 |
+ //LOAD( int, soundFinalWave[0], 2*735 }, |
|
| 673 |
+ { NULL, 0 }
|
|
| 674 |
+}; |
|
| 675 |
+ |
|
| 676 |
+variable_desc old_gba_state2 [] = |
|
| 677 |
+{
|
|
| 678 |
+ LOAD( u8 [0x20], state.apu.regs [0x20] ), |
|
| 679 |
+ SKIP( int, sound3Bank ), |
|
| 680 |
+ SKIP( int, sound3DataSize ), |
|
| 681 |
+ SKIP( int, sound3ForcedOutput ), |
|
| 682 |
+ { NULL, 0 }
|
|
| 683 |
+}; |
|
| 684 |
+ |
|
| 685 |
+// New state format |
|
| 686 |
+static variable_desc gba_state [] = |
|
| 687 |
+{
|
|
| 688 |
+ // PCM |
|
| 689 |
+ LOAD( int, pcm [0].readIndex ), |
|
| 690 |
+ LOAD( int, pcm [0].count ), |
|
| 691 |
+ LOAD( int, pcm [0].writeIndex ), |
|
| 692 |
+ LOAD(u8[32],pcm[0].fifo ), |
|
| 693 |
+ LOAD( int, pcm [0].dac ), |
|
| 694 |
+ |
|
| 695 |
+ SKIP( int [4], room_for_expansion ), |
|
| 696 |
+ |
|
| 697 |
+ LOAD( int, pcm [1].readIndex ), |
|
| 698 |
+ LOAD( int, pcm [1].count ), |
|
| 699 |
+ LOAD( int, pcm [1].writeIndex ), |
|
| 700 |
+ LOAD(u8[32],pcm[1].fifo ), |
|
| 701 |
+ LOAD( int, pcm [1].dac ), |
|
| 702 |
+ |
|
| 703 |
+ SKIP( int [4], room_for_expansion ), |
|
| 704 |
+ |
|
| 705 |
+ // APU |
|
| 706 |
+ LOAD( u8 [0x40], state.apu.regs ), // last values written to registers and wave RAM (both banks) |
|
| 707 |
+ LOAD( int, state.apu.frame_time ), // clocks until next frame sequencer action |
|
| 708 |
+ LOAD( int, state.apu.frame_phase ), // next step frame sequencer will run |
|
| 709 |
+ |
|
| 710 |
+ LOAD( int, state.apu.sweep_freq ), // sweep's internal frequency register |
|
| 711 |
+ LOAD( int, state.apu.sweep_delay ), // clocks until next sweep action |
|
| 712 |
+ LOAD( int, state.apu.sweep_enabled ), |
|
| 713 |
+ LOAD( int, state.apu.sweep_neg ), // obscure internal flag |
|
| 714 |
+ LOAD( int, state.apu.noise_divider ), |
|
| 715 |
+ LOAD( int, state.apu.wave_buf ), // last read byte of wave RAM |
|
| 716 |
+ |
|
| 717 |
+ LOAD( int [4], state.apu.delay ), // clocks until next channel action |
|
| 718 |
+ LOAD( int [4], state.apu.length_ctr ), |
|
| 719 |
+ LOAD( int [4], state.apu.phase ), // square/wave phase, noise LFSR |
|
| 720 |
+ LOAD( int [4], state.apu.enabled ), // internal enabled flag |
|
| 721 |
+ |
|
| 722 |
+ LOAD( int [3], state.apu.env_delay ), // clocks until next envelope action |
|
| 723 |
+ LOAD( int [3], state.apu.env_volume ), |
|
| 724 |
+ LOAD( int [3], state.apu.env_enabled ), |
|
| 725 |
+ |
|
| 726 |
+ SKIP( int [13], room_for_expansion ), |
|
| 727 |
+ |
|
| 728 |
+ // Emulator |
|
| 729 |
+ LOAD( int, soundEnableFlag ), |
|
| 730 |
+ |
|
| 731 |
+ SKIP( int [15], room_for_expansion ), |
|
| 732 |
+ |
|
| 733 |
+ { NULL, 0 }
|
|
| 734 |
+}; |
|
| 735 |
+ |
|
| 736 |
+// Reads and discards count bytes from in |
|
| 737 |
+static void skip_read( gzFile in, int count ) |
|
| 738 |
+{
|
|
| 739 |
+ char buf [512]; |
|
| 740 |
+ |
|
| 741 |
+ while ( count ) |
|
| 742 |
+ {
|
|
| 743 |
+ int n = sizeof buf; |
|
| 744 |
+ if ( n > count ) |
|
| 745 |
+ n = count; |
|
| 746 |
+ |
|
| 747 |
+ count -= n; |
|
| 748 |
+ utilGzRead( in, buf, n ); |
|
| 749 |
+ } |
|
| 750 |
+} |
|
| 751 |
+ |
|
| 752 |
+void soundSaveGame( gzFile out ) |
|
| 753 |
+{
|
|
| 754 |
+ gb_apu->save_state( &state.apu ); |
|
| 755 |
+ |
|
| 756 |
+ // Be sure areas for expansion get written as zero |
|
| 757 |
+ memset( dummy_state, 0, sizeof dummy_state ); |
|
| 758 |
+ |
|
| 759 |
+ utilWriteData( out, gba_state ); |
|
| 760 |
+} |
|
| 761 |
+ |
|
| 762 |
+static void soundReadGameOld( gzFile in, int version ) |
|
| 763 |
+{
|
|
| 764 |
+ // Read main data |
|
| 765 |
+ utilReadData( in, old_gba_state ); |
|
| 766 |
+ skip_read( in, 6*735 + 2*735 ); |
|
| 767 |
+ |
|
| 768 |
+ // Copy APU regs |
|
| 769 |
+ static int const regs_to_copy [] = {
|
|
| 770 |
+ NR10, NR11, NR12, NR13, NR14, |
|
| 771 |
+ NR21, NR22, NR23, NR24, |
|
| 772 |
+ NR30, NR31, NR32, NR33, NR34, |
|
| 773 |
+ NR41, NR42, NR43, NR44, |
|
| 774 |
+ NR50, NR51, NR52, -1 |
|
| 775 |
+ }; |
|
| 776 |
+ |
|
| 777 |
+ ioMem [NR52] |= 0x80; // old sound played even when this wasn't set (power on) |
|
| 778 |
+ |
|
| 779 |
+ for ( int i = 0; regs_to_copy [i] >= 0; i++ ) |
|
| 780 |
+ state.apu.regs [gba_to_gb_sound( regs_to_copy [i] ) - 0xFF10] = ioMem [regs_to_copy [i]]; |
|
| 781 |
+ |
|
| 782 |
+ // Copy wave RAM to both banks |
|
| 783 |
+ memcpy( &state.apu.regs [0x20], &ioMem [0x90], 0x10 ); |
|
| 784 |
+ memcpy( &state.apu.regs [0x30], &ioMem [0x90], 0x10 ); |
|
| 785 |
+ |
|
| 786 |
+ // Read both banks of wave RAM if available |
|
| 787 |
+ if ( version >= SAVE_GAME_VERSION_3 ) |
|
| 788 |
+ utilReadData( in, old_gba_state2 ); |
|
| 789 |
+ |
|
| 790 |
+ // Restore PCM |
|
| 791 |
+ pcm [0].dac = state.soundDSAValue; |
|
| 792 |
+ pcm [1].dac = state.soundDSBValue; |
|
| 793 |
+ |
|
| 794 |
+ (void) utilReadInt( in ); // ignore quality |
|
| 795 |
+} |
|
| 796 |
+ |
|
| 797 |
+#include <stdio.h> |
|
| 798 |
+ |
|
| 799 |
+void soundReadGame( gzFile in, int version ) |
|
| 800 |
+{
|
|
| 801 |
+ // Prepare APU and default state |
|
| 802 |
+ reset_apu(); |
|
| 803 |
+ gb_apu->save_state( &state.apu ); |
|
| 804 |
+ |
|
| 805 |
+ if ( version > SAVE_GAME_VERSION_9 ) |
|
| 806 |
+ utilReadData( in, gba_state ); |
|
| 807 |
+ else |
|
| 808 |
+ soundReadGameOld( in, version ); |
|
| 809 |
+ |
|
| 810 |
+ gb_apu->load_state( state.apu ); |
|
| 811 |
+ write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F ); |
|
| 812 |
+ |
|
| 813 |
+ apply_muting(); |
|
| 814 |
+}*/ |