diff --git a/aegisub/audio_display.cpp b/aegisub/audio_display.cpp
index f02abe4d172405e6df441dec507d16ac48829305..1b3a3058ea006392eaa840c1a46601f4076249a6 100644
--- a/aegisub/audio_display.cpp
+++ b/aegisub/audio_display.cpp
@@ -792,21 +792,23 @@ void AudioDisplay::SetSamplesPercent(int percent,bool update,float pivot) {
 void AudioDisplay::UpdateSamples() {
 	// Set samples
 	if (!provider) return;
-	int64_t totalSamples = provider->GetNumSamples();
-	int total = totalSamples / w;
-	int max = 5760000 / w;	// 2 minutes at 48 kHz maximum
-	if (total > max) total = max;
-	int min = 8;
-	if (total < min) total = min;
-	int range = total-min;
-	samples = int(range*pow(samplesPercent/100.0,3)+min);
-
-	// Set position
-	int length = w * samples;
-	if (PositionSample + length > totalSamples) {
-		PositionSample = totalSamples - length;
-		if (PositionSample < 0) PositionSample = 0;
-		Position = PositionSample / samples;
+	if (w) {
+		int64_t totalSamples = provider->GetNumSamples();
+		int total = totalSamples / w;
+		int max = 5760000 / w;	// 2 minutes at 48 kHz maximum
+		if (total > max) total = max;
+		int min = 8;
+		if (total < min) total = min;
+		int range = total-min;
+		samples = int(range*pow(samplesPercent/100.0,3)+min);
+
+		// Set position
+		int length = w * samples;
+		if (PositionSample + length > totalSamples) {
+			PositionSample = totalSamples - length;
+			if (PositionSample < 0) PositionSample = 0;
+			if (samples) Position = PositionSample / samples;
+		}
 	}
 }
 
@@ -1915,8 +1917,8 @@ void AudioDisplay::OnSize(wxSizeEvent &event) {
 	h -= Options.AsBool(_T("Audio Draw Timeline")) ? 20 : 0;
 
 	// Update image
+	UpdateSamples();
 	if (samples) {
-		UpdateSamples();
 		UpdatePosition(PositionSample / samples);
 	}
 	UpdateImage();
diff --git a/aegisub/audio_provider.cpp b/aegisub/audio_provider.cpp
index af6ee865b051d3b6fa1b8f59a2971fb211a8d69e..debf69074c72adf3cf47c92ac185c4be53f2e82e 100644
--- a/aegisub/audio_provider.cpp
+++ b/aegisub/audio_provider.cpp
@@ -192,7 +192,7 @@ AudioProvider *AudioProviderFactory::GetAudioProvider(wxString filename, int cac
 	// Try a PCM provider first
 	provider = CreatePCMAudioProvider(filename);
 	if (provider) {
-		if (provider->GetBytesPerSample() == 2) return provider;
+		if (provider->GetBytesPerSample() == 2 && provider->GetSampleRate() >= 32000) return provider;
 		return new ConvertAudioProvider(provider);
 	}
 
@@ -221,7 +221,7 @@ AudioProvider *AudioProviderFactory::GetAudioProvider(wxString filename, int cac
 	if (!provider) throw error;
 
 	// Give it a conversor if needed
-	if (provider->GetBytesPerSample() != 2) provider = new ConvertAudioProvider(provider);
+	if (provider->GetBytesPerSample() != 2 || provider->GetSampleRate() < 32000) provider = new ConvertAudioProvider(provider);
 
 	// Change provider to RAM/HD cache if needed
 	if (cache == -1) cache = Options.AsInt(_T("Audio Cache"));
diff --git a/aegisub/audio_provider_convert.cpp b/aegisub/audio_provider_convert.cpp
index 0eb778f32b59c036816df34a6d10bbd6ff0e3484..f91c957b05fc9bc3b19b114a3b64cea42687a2f7 100644
--- a/aegisub/audio_provider_convert.cpp
+++ b/aegisub/audio_provider_convert.cpp
@@ -50,6 +50,12 @@ ConvertAudioProvider::ConvertAudioProvider(AudioProvider *src) {
 	num_samples = source->GetNumSamples();
 	sample_rate = source->GetSampleRate();
 	bytes_per_sample = 2;
+
+	sampleMult = 1;
+	if (sample_rate < 16000) sampleMult = 4;
+	else if (sample_rate < 32000) sampleMult = 2;
+	sample_rate *= sampleMult;
+	num_samples *= sampleMult;
 }
 
 
@@ -60,28 +66,99 @@ ConvertAudioProvider::~ConvertAudioProvider() {
 }
 
 
+/////////////////////
+// Convert to 16-bit
+void ConvertAudioProvider::Make16Bit(const char *src, short *dst, int64_t count) {
+	for (int64_t i=0;i<count;i++) {
+		dst[i] = (src[i]-128)*255;
+	}
+}
+
+
+//////////////////////
+// Change sample rate
+// This requres 16-bit input
+void ConvertAudioProvider::ChangeSampleRate(const short *src, short *dst, int64_t count) {
+	// Upsample by 2
+	if (sampleMult == 2) {
+		int64_t size = count/2;
+		short cur;
+		short next = 0;
+		for (int64_t i=0;i<size;i++) {
+			cur = next;
+			next = *src++;
+			*(dst++) = cur;
+			*(dst++) = (cur+next)/2;
+		}
+		if (count%2) *(dst++) = next;
+	}
+
+	// Upsample by 4
+	else if (sampleMult == 4) {
+		int64_t size = count/4;
+		short cur;
+		short next = 0;
+		for (int64_t i=0;i<size;i++) {
+			cur = next;
+			next = *(src++);
+			*(dst++) = cur;
+			*(dst++) = (cur*3+next)/4;
+			*(dst++) = (cur+next)/2;
+			*(dst++) = (cur+next*3)/4;
+		}
+		for (int i=0;i<count%4;i++) *(dst++) = next;
+	}
+
+	// Nothing to do (shouldn't really get here, but...)
+	else if (sampleMult == 1) memcpy((void*)src,dst,count);
+}
+
+
 /////////////
 // Get audio
 void ConvertAudioProvider::GetAudio(void *destination, int64_t start, int64_t count) {
 	// Bits per sample
 	int srcBps = source->GetBytesPerSample();
 
-	// Convert from 8-bit to 16-bit
-	if (srcBps == 1) {
-		unsigned char *buffer = new unsigned char[count];
-		source->GetAudio(buffer,start,count);
-		short temp;
-		short *dst = (short*) destination;
-		for (int64_t i=0;i<count;i++) {
-			temp = (short) buffer[i];
-			dst[i] = (temp-128)*256+temp;
-		}
-		delete [] buffer;
+	// Nothing to do
+	if (sampleMult == 1 && srcBps == 2) {
+		source->GetAudio(destination,start,count);
 	}
 
-	// No conversion needed
-	else if (srcBps == 2) source->GetAudio(destination,start,count);
+	// Convert
+	else {
+		// Allocate buffers with sufficient size for the entire operation
+		size_t fullSize = count;
+		int64_t srcCount = count / sampleMult;
+		short *buffer1 = NULL;
+		short *buffer2 = NULL;
+		short *last = NULL;
+
+		// Read audio
+		buffer1 = new short[fullSize];
+		source->GetAudio(buffer1,start/sampleMult,srcCount);
 
-	// Unsupported
-	else throw _T("Unknown bits per sample value.");
+		// Convert from 8-bit to 16-bit
+		if (srcBps == 1) {
+			if (sampleMult == 1) {
+				Make16Bit((const char*)buffer1,(short*)destination,srcCount);
+			}
+			else {
+				buffer2 = new short[fullSize];
+				Make16Bit((const char*)buffer1,buffer2,srcCount);
+				last = buffer2;
+			}
+		}
+
+		// Already 16-bit
+		else if (srcBps == 2) last = buffer1;
+
+		// Convert sample rate
+		if (sampleMult != 1) {
+			ChangeSampleRate(last,(short*)destination,count);
+		}
+
+		delete [] buffer1;
+		delete [] buffer2;
+	}
 }
diff --git a/aegisub/audio_provider_convert.h b/aegisub/audio_provider_convert.h
index 60f4f842971a16c40a979767779c0ee344887003..d88448650b3e09ee6f188794f980e0a8dc9a2b66 100644
--- a/aegisub/audio_provider_convert.h
+++ b/aegisub/audio_provider_convert.h
@@ -46,7 +46,11 @@
 // Audio provider class
 class ConvertAudioProvider : public AudioProvider {
 private:
+	int sampleMult;
+
 	AudioProvider *source;
+	void Make16Bit(const char *src, short *dst, int64_t count);
+	void ChangeSampleRate(const short *src, short *dst, int64_t count);
 
 public:
 	ConvertAudioProvider(AudioProvider *source);