1. spencercw
  2. gb_emulator

Commits

spencercw  committed 63a2dac

Increase audio buffer and generate audio on demand rather than frame-by-frame.

This is slightly less accurate, but not to any noticable degree, and it drastically reduces skipping.

  • Participants
  • Parent commits 2b30fde
  • Branches default

Comments (0)

Files changed (3)

File gb_emulator/gb_sound.cpp

View file
 #include "gb.hpp"
 #include "gb_sound.hpp"
 
-using boost::circular_buffer;
 using std::clog;
 using std::ios_base;
 using std::min;
 using std::vector;
 
 static const double PI = 3.14159265358979323846264338327950288;
-static const unsigned SOUND_BUF_SIZE = 4096;
 
 struct SdlAudioLock
 {
 	envelope1_(0),
 	envelope2_(0),
 	envelopeCountdown1_(0),
-	envelopeCountdown2_(0),
-	soundBuf_(SOUND_BUF_SIZE)
+	envelopeCountdown2_(0)
 {
 	// Open the device
 	if (!SDL_WasInit(SDL_INIT_AUDIO))
 	fmt.freq = 48000;
 	fmt.format = AUDIO_S16;
 	fmt.channels = 1;
-	fmt.samples = 512;
+	fmt.samples = 1024;
 	fmt.callback = soundCallback;
 	fmt.userdata = this;
 
 	// Save the values
 	sampleRate_ = actFmt.freq;
 	frameSamples_ = (FRAME_DURATION * 1e-9) * sampleRate_;
-	tmpSoundBuf_.resize(static_cast<size_t>(frameSamples_) + 1);
-}
 
-void GbSound::poll()
-{
-	// Calculate the number of samples to generate
-	double desiredSampleCount = frameSamples_ + excessSamples_;
-	int actSampleCount = static_cast<int>(desiredSampleCount + 0.5);
-	excessSamples_ = desiredSampleCount - actSampleCount;
-
-	// Generate the square wave
-	for (int i = 0; i != actSampleCount; ++i)
-	{
-		int16_t amplitude = 0;
-		amplitude += sound1();
-		amplitude += sound2();
-		tmpSoundBuf_[i] = amplitude;
-	}
-
-	// Copy the samples into the buffer
-	{
-		SdlAudioLock lock;
-		soundBuf_.insert(soundBuf_.end(), tmpSoundBuf_.begin(), tmpSoundBuf_.begin() + actSampleCount);
-
-		SDL_audiostatus status = SDL_GetAudioStatus();
-		if (status != SDL_AUDIO_PLAYING && soundBuf_.size() >= SOUND_BUF_SIZE / 2)
-		{
-			// Start playback if the buffer is half full
-			SDL_PauseAudio(0);
-		}
-		else if (status == SDL_AUDIO_PLAYING && soundBuf_.full())
-		{
-			// Overflow; discard the oldest data so we don't get repeated overflows
-			clog << "sound buffer overflow\n";
-			soundBuf_.erase_begin(SOUND_BUF_SIZE / 2);
-		}
-	}
+	// Begin playback
+	SDL_PauseAudio(0);
 }
 
 int16_t GbSound::sound1()
 {
 	GbSound *parent = static_cast<GbSound *>(userData);
 
-	// Copy the sound into the SDL buffer
-	size_t remaining = len / 2;
-	size_t consumed = 0;
-	circular_buffer<int16_t>::array_range range1 = parent->soundBuf_.array_one();
-	if (range1.second)
+	// Generate the audio
+	uint16_t *actStream = reinterpret_cast<uint16_t *>(stream);
+	for (int i = 0; i != len / 2; ++i)
 	{
-		size_t samples = min(remaining, range1.second);
-		memcpy(stream, range1.first, samples * 2);
-		remaining -= samples;
-		consumed  += samples;
-
-		if (remaining)
-		{
-			circular_buffer<int16_t>::array_range range2 = parent->soundBuf_.array_two();
-			if (range2.second)
-			{
-				samples = min(remaining, range2.second);
-				memcpy(&stream[consumed * 2], range2.first, samples * 2);
-				remaining -= samples;
-				consumed  += samples;
-			}
-		}
-
-		parent->soundBuf_.erase_begin(consumed);
-	}
-
-	if (remaining)
-	{
-		// Underflow; stop playback. It will be restarted when the internal buffer has enough data
-		// to avoid repeated underflows
-		clog << "sound buffer underflow\n";
-		SDL_PauseAudio(1);
+		int16_t amplitude = 0;
+		amplitude += parent->sound1();
+		amplitude += parent->sound2();
+		actStream[i] = amplitude;
 	}
 }
 

File gb_emulator/gb_sound.hpp

View file
 #ifndef GB_SOUND_HPP_A0F40D80_8AD9_11E0_B88E_0002A5D5C51B
 #define GB_SOUND_HPP_A0F40D80_8AD9_11E0_B88E_0002A5D5C51B
 
-// For boost::circular_buffer
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wsign-compare"
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#endif
-
-#include <boost/circular_buffer.hpp>
 #include <stdint.h>
 #include <vector>
 
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
 class Gb;
 class GbSoundData;
 
 	//! Constructor; sets the associated emulator container.
 	GbSound(Gb &gb);
 
-	//! Processes a frame's worth of sound.
-	void poll();
-
 	//! Saves the current state of the sound emulator into the given message.
 	void save(GbSoundData &data) const;
 
 	double envelopeStep1_, envelopeStep2_;
 	// Number of samples to the next envelope step
 	double envelopeCountdown1_, envelopeCountdown2_;
-	// Working buffer before the samples are copied into soundBuf_ in the critical section
-	std::vector<int16_t> tmpSoundBuf_;
-	// Buffer of samples used by the sound callback
-	boost::circular_buffer<int16_t> soundBuf_;
 
 	// Functions for each of the sound modes. The output is mixed in the main poll() function
 	int16_t sound1();

File gb_emulator/gb_video.cpp

View file
 	}
 	else if (gb_.mem_.ioPorts[LCDC_Y] == VBLANK_START)
 	{
-		// Generate the sound for this frame
-		gb_.sound_.poll();
-
 		// Spin for a while to get the correct emulation speed
 		gb_.spin();