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);