[GSF] Copied a few things from kode54's viogsf.
[GSF] Copied a few things from kode54's viogsf.

--- a/src/in_gsf/vbam/apu/Blip_Buffer.cpp
+++ b/src/in_gsf/vbam/apu/Blip_Buffer.cpp
@@ -60,7 +60,7 @@
 	}
 }
 
-void Blip_Buffer::set_sample_rate(long new_rate, int msec)
+void Blip_Buffer::set_sample_rate(long new_rate, long msec)
 {
 	// start with maximum length that resampled time can represent
 	long new_size = (ULONG_MAX >> BLIP_BUFFER_ACCURACY) - blip_buffer_extra_ - 64;
@@ -372,7 +372,7 @@
 	auto out = &this->buffer_[(this->offset_ >> BLIP_BUFFER_ACCURACY) + blip_widest_impulse_ / 2];
 
 	static const int sample_shift = blip_sample_bits - 16;
-	int prev = 0;
+	int32_t prev = 0;
 	while (count--)
 	{
 		int32_t s = static_cast<int32_t>(*in++) << sample_shift;

--- a/src/in_gsf/vbam/apu/Blip_Buffer.h
+++ b/src/in_gsf/vbam/apu/Blip_Buffer.h
@@ -19,7 +19,7 @@
 	// Sets output sample rate and buffer length in milliseconds (1/1000 sec, defaults
 	// to 1/4 second) and clears buffer. If there isn't enough memory, leaves buffer
 	// untouched and returns "Out of memory", otherwise returns NULL.
-	void set_sample_rate(long samples_per_sec, int msec_length = 250);
+	void set_sample_rate(long samples_per_sec, long msec_length = 250);
 
 	// Sets number of source time units per second
 	void clock_rate(long clocks_per_sec);
@@ -54,7 +54,7 @@
 	long sample_rate() const;
 
 	// Length of buffer in milliseconds
-	int length() const;
+	int32_t length() const;
 
 	// Number of source time units per second
 	long clock_rate() const;
@@ -107,7 +107,7 @@
 	long sample_rate_;
 	long clock_rate_;
 	int bass_freq_;
-	int length_;
+	int32_t length_;
 	Blip_Buffer *modified_; // non-zero = true (more optimal than using bool, heh)
 };
 
@@ -421,7 +421,7 @@
 inline blip_eq_t::blip_eq_t(double t) : treble(t), rolloff_freq(0), sample_rate(44100), cutoff_freq(0) { }
 inline blip_eq_t::blip_eq_t(double t, long rf, long sr, long cf) : treble(t), rolloff_freq(rf), sample_rate(sr), cutoff_freq(cf) { }
 
-inline int Blip_Buffer::length() const { return this->length_; }
+inline int32_t Blip_Buffer::length() const { return this->length_; }
 inline long Blip_Buffer::samples_avail() const { return static_cast<long>(this->offset_ >> BLIP_BUFFER_ACCURACY); }
 inline long Blip_Buffer::sample_rate() const { return this->sample_rate_; }
 inline int Blip_Buffer::output_latency() const { return blip_widest_impulse_ / 2; }

--- a/src/in_gsf/vbam/apu/Gb_Apu.cpp
+++ b/src/in_gsf/vbam/apu/Gb_Apu.cpp
@@ -24,7 +24,8 @@
 void Gb_Apu::treble_eq(const blip_eq_t &eq)
 {
 	this->good_synth.treble_eq(eq);
-	this->med_synth.treble_eq(eq);
+	this->med_synth[0].treble_eq(eq);
+	this->med_synth[1].treble_eq(eq);
 }
 
 int Gb_Apu::calc_output(int osc) const
@@ -57,7 +58,8 @@
 {
 	double v = this->volume_ * 0.60 / osc_count / 15 /*steps*/ / 8 /*master vol range*/ * iv;
 	this->good_synth.volume(v);
-	this->med_synth.volume(v);
+	this->med_synth[0].volume(v);
+	this->med_synth[1].volume(v * 1.4);
 }
 
 void Gb_Apu::apply_volume()
@@ -174,7 +176,7 @@
 		o.regs = &this->regs[i * 5];
 		o.output = o.outputs[0] = o.outputs[1] = o.outputs[2] = o.outputs[3] = nullptr;
 		o.good_synth = &this->good_synth;
-		o.med_synth = &this->med_synth;
+		o.med_synth = &this->med_synth[i == 3 ? 1 : 0];
 	}
 
 	this->reduce_clicks_ = false;
@@ -255,7 +257,7 @@
 		if (o.output)
 		{
 			o.output->set_modified();
-			this->med_synth.offset(this->last_time, delta, o.output);
+			this->med_synth[0].offset(this->last_time, delta, o.output);
 		}
 	}
 }

--- a/src/in_gsf/vbam/apu/Gb_Apu.h
+++ b/src/in_gsf/vbam/apu/Gb_Apu.h
@@ -101,7 +101,7 @@
 
 	// large objects after everything else
 	Gb_Osc::Good_Synth good_synth;
-	Gb_Osc::Med_Synth med_synth;
+	Gb_Osc::Med_Synth med_synth[2];
 
 	void reset_lengths();
 	void reset_regs();

--- a/src/in_gsf/vbam/apu/Gb_Oscs.cpp
+++ b/src/in_gsf/vbam/apu/Gb_Oscs.cpp
@@ -373,7 +373,7 @@
 		if (!vol)
 		{
 			// Maintain phase when not playing
-			int count = (end_time - time + per - 1) / per;
+			int32_t count = (end_time - time + per - 1) / per;
 			ph += count; // will be masked below
 			time += static_cast<blip_time_t>(count) * per;
 		}
@@ -402,7 +402,7 @@
 
 // Quickly runs LFSR for a large number of clocks. For use when noise is generating
 // no sound.
-static unsigned run_lfsr(unsigned s, unsigned mask, int count)
+static unsigned run_lfsr(unsigned s, unsigned mask, int32_t count)
 {
 	static const bool optimized = true; // set to false to use only unoptimized loop in middle
 
@@ -513,11 +513,11 @@
 	// Run timer and calculate time of next LFSR clock
 	static const uint8_t period1s[] = { 1, 2, 4, 6, 8, 10, 12, 14 };
 	int period1 = period1s[this->regs[3] & 7] * clk_mul;
-	int extra = (end_time - time) - this->delay;
+	int32_t extra = (end_time - time) - this->delay;
 	int per2 = this->period2();
 	time += this->delay + ((this->divider ^ (per2 >> 1)) & (per2 - 1)) * period1;
 
-	int count = extra < 0 ? 0 : (extra + period1 - 1) / period1;
+	int32_t count = extra < 0 ? 0 : (extra + period1 - 1) / period1;
 	this->divider = (this->divider - count) & period2_mask;
 	this->delay = count * period1 - extra;
 
@@ -533,7 +533,7 @@
 		else if (!vol)
 		{
 			// Maintain phase when not playing
-			int count = (end_time - time + per - 1) / per;
+			int32_t count = (end_time - time + per - 1) / per;
 			time += static_cast<blip_time_t>(count) * per;
 			bits = run_lfsr(bits, ~mask, count);
 		}
@@ -618,7 +618,7 @@
 		if (!playing)
 		{
 			// Maintain phase when not playing
-			int count = (end_time - time + per - 1) / per;
+			int32_t count = (end_time - time + per - 1) / per;
 			ph += count; // will be masked below
 			time += static_cast<blip_time_t>(count) * per;
 		}

--- a/src/in_gsf/vbam/apu/Gb_Oscs.h
+++ b/src/in_gsf/vbam/apu/Gb_Oscs.h
@@ -37,7 +37,7 @@
 	const Good_Synth *good_synth;
 	const Med_Synth *med_synth;
 
-	int delay; // clocks until frequency timer expires
+	int32_t delay; // clocks until frequency timer expires
 	int length_ctr; // length counter
 	unsigned phase; // waveform phase (or equivalent)
 	bool enabled; // internal enabled flag

--- a/src/in_gsf/vbam/apu/Multi_Buffer.cpp
+++ b/src/in_gsf/vbam/apu/Multi_Buffer.cpp
@@ -94,7 +94,7 @@
 
 Stereo_Buffer::~Stereo_Buffer() { }
 
-void Stereo_Buffer::set_sample_rate(long rate, int msec)
+void Stereo_Buffer::set_sample_rate(long rate, long msec)
 {
 	this->mixer.samples_read = 0;
 	for (int i = bufs_size; --i >= 0; )

--- a/src/in_gsf/vbam/apu/Multi_Buffer.h
+++ b/src/in_gsf/vbam/apu/Multi_Buffer.h
@@ -31,14 +31,14 @@
 	virtual channel_t channel(int index);
 
 	// See Blip_Buffer.h
-	virtual void set_sample_rate(long rate, int msec = blip_default_length);
+	virtual void set_sample_rate(long rate, long msec = blip_default_length);
 	virtual void clock_rate(long) { }
 	virtual void bass_freq(int) { }
 	virtual void clear() { }
 	long sample_rate() const;
 
 	// Length of buffer, in milliseconds
-	int length() const;
+	int32_t length() const;
 
 	// See Blip_Buffer.h
 	virtual void end_frame(blip_time_t) { }
@@ -66,7 +66,7 @@
 
 	unsigned channels_changed_count_;
 	long sample_rate_;
-	int length_;
+	int32_t length_;
 	int channel_count_;
 	const int samples_per_frame_;
 	const int *channel_types_;
@@ -115,7 +115,7 @@
 
 	Stereo_Buffer();
 	~Stereo_Buffer();
-	void set_sample_rate(long, int msec = blip_default_length);
+	void set_sample_rate(long, long msec = blip_default_length);
 	void clock_rate(long);
 	void bass_freq(int);
 	void clear();
@@ -134,7 +134,7 @@
 	long samples_avail_;
 };
 
-inline void Multi_Buffer::set_sample_rate(long rate, int msec)
+inline void Multi_Buffer::set_sample_rate(long rate, long msec)
 {
 	this->sample_rate_ = rate;
 	this->length_ = msec;
@@ -144,7 +144,7 @@
 
 inline long Multi_Buffer::sample_rate() const { return this->sample_rate_; }
 
-inline int Multi_Buffer::length() const { return this->length_; }
+inline int32_t Multi_Buffer::length() const { return this->length_; }
 
 inline void Multi_Buffer::set_channel_count(int n, const int *types)
 {

--- a/src/in_gsf/vbam/gba/Sound.cpp
+++ b/src/in_gsf/vbam/gba/Sound.cpp
@@ -115,7 +115,7 @@
 			if (soundInterpolation)
 			{
 				// base filtering on how long since last sample was output
-				int period = time - this->last_time;
+				int32_t period = time - this->last_time;
 
 				int idx = period / 512;
 				if (idx >= 3)
@@ -158,7 +158,7 @@
 			if (soundInterpolation)
 			{
 				// base filtering on how long since last sample was output
-				int period = time - this->last_time;
+				int32_t period = time - this->last_time;
 
 				int idx = period / 512;
 				if (idx >= 3)
@@ -350,22 +350,21 @@
 	// that don't use the length parameter of the write method.
 	// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the
 	// samples at once to help reducing the audio delay on all platforms.
-	int soundBufferLen = (soundSampleRate / 60) * 4;
+	int32_t soundBufferLen = (soundSampleRate / 60) * 4;
 
 	// soundBufferLen should have a whole number of sample pairs
 	assert(!(soundBufferLen % (2 * sizeof(*soundFinalWave))));
 
 	// number of samples in output buffer
-	int out_buf_size = soundBufferLen / sizeof(*soundFinalWave);
-
-	// Keep filling and writing soundFinalWave until it can't be fully filled
-	while (buffer->samples_avail() >= out_buf_size)
-	{
-		buffer->read_samples(reinterpret_cast<blip_sample_t *>(soundFinalWave), out_buf_size);
+	int32_t out_buf_size = soundBufferLen / sizeof(*soundFinalWave);
+
+	while (buffer->samples_avail())
+	{
+		long samples_read = buffer->read_samples(reinterpret_cast<blip_sample_t *>(soundFinalWave), out_buf_size);
 		if (soundPaused)
 			soundResume();
 
-		soundDriver->write(soundFinalWave, soundBufferLen);
+		soundDriver->write(soundFinalWave, samples_read * sizeof(*soundFinalWave));
 	}
 }
 
@@ -374,11 +373,11 @@
 	soundFiltering_ = soundFiltering;
 
 	int base_freq = static_cast<int>(32768 - soundFiltering_ * 16384);
-	int nyquist = stereo_buffer->sample_rate() / 2;
+	int32_t nyquist = stereo_buffer->sample_rate() / 2;
 
 	for (int i = 0; i < 3; ++i)
 	{
-		int cutoff = base_freq >> i;
+		int32_t cutoff = base_freq >> i;
 		if (cutoff > nyquist)
 			cutoff = nyquist;
 		pcm_synth[i].treble_eq(blip_eq_t(0, 0, stereo_buffer->sample_rate(), cutoff));
@@ -400,8 +399,6 @@
 		if (soundVolume_ != soundVolume)
 			apply_volume();
 	}
-
-	ioMem[NR52] = (ioMem[NR52] & 0x80) | (gb_apu->read_status() & 0x7f);
 }
 
 static void apply_muting()
@@ -423,8 +420,11 @@
 
 static void reset_apu()
 {
-	gb_apu->reduce_clicks(true);
-	gb_apu->reset(gb_apu->mode_agb, true);
+	if (gb_apu)
+	{
+		gb_apu->reduce_clicks(true);
+		gb_apu->reset(Gb_Apu::mode_agb, true);
+	}
 
 	if (stereo_buffer)
 		stereo_buffer->clear();
@@ -438,23 +438,24 @@
 	pcm[0].pcm.init();
 	pcm[1].pcm.init();
 
-	// APU
-	if (!gb_apu)
-	{
-		gb_apu.reset(new Gb_Apu); // TODO: handle out of memory
-		reset_apu();
-	}
-
 	// Stereo_Buffer
 	stereo_buffer.reset(new Stereo_Buffer); // TODO: handle out of memory
 	stereo_buffer->set_sample_rate(soundSampleRate); // TODO: handle out of memory
-	stereo_buffer->clock_rate(gb_apu->clock_rate);
 
 	// PCM
 	pcm[0].which = 0;
 	pcm[1].which = 1;
 	apply_filtering();
 
+	// APU
+	if (!gb_apu)
+	{
+		gb_apu.reset(new Gb_Apu); // TODO: handle out of memory
+		reset_apu();
+		gb_apu->treble_eq(blip_eq_t(0, 0, soundSampleRate, soundSampleRate / 2));
+	}
+	stereo_buffer->clock_rate(gb_apu->clock_rate);
+
 	// Volume Level
 	apply_muting();
 	apply_volume();