aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/Resampler.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/Resampler.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Winamp/Resampler.cpp')
-rw-r--r--Src/Winamp/Resampler.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/Src/Winamp/Resampler.cpp b/Src/Winamp/Resampler.cpp
new file mode 100644
index 00000000..f6d27588
--- /dev/null
+++ b/Src/Winamp/Resampler.cpp
@@ -0,0 +1,172 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+#include "main.h"
+#include "Resampler.h"
+#include <ks.h>
+#include <ksmedia.h>
+
+static int GetChannelMask(size_t channels)
+{
+ switch(channels)
+ {
+ case 1: return KSAUDIO_SPEAKER_MONO;
+ case 2: return KSAUDIO_SPEAKER_STEREO;
+ case 4: return KSAUDIO_SPEAKER_SURROUND;
+ case 6: return KSAUDIO_SPEAKER_5POINT1;
+ case 8: return KSAUDIO_SPEAKER_7POINT1;
+ default: return 0;
+ }
+}
+static void FillWFX_float(WAVEFORMATIEEEFLOATEX *format, size_t channels, size_t bits, size_t sampleRate)
+{
+ ZeroMemory(format, sizeof(WAVEFORMATIEEEFLOATEX));
+ size_t padded_bits = (bits + 7) & (~7);
+ format->Format.nChannels = (WORD)channels;
+ format->Format.nSamplesPerSec = (DWORD)sampleRate;
+ format->Format.nAvgBytesPerSec = (DWORD)(sampleRate * channels * (padded_bits >> 3));
+ format->Format.nBlockAlign = (WORD)(channels * (padded_bits >> 3));
+ format->Format.wBitsPerSample = (WORD)padded_bits;
+
+ format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ format->Format.cbSize = sizeof(WAVEFORMATIEEEFLOATEX) - sizeof(WAVEFORMATEX);
+ format->Samples.wValidBitsPerSample = (WORD)bits;
+ format->dwChannelMask = GetChannelMask(channels);
+ format->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+}
+
+static void FillWFX(WAVEFORMATEXTENSIBLE *format, size_t channels, size_t bits, size_t sampleRate)
+{
+ ZeroMemory(format, sizeof(WAVEFORMATEXTENSIBLE));
+ size_t padded_bits = (bits + 7) & (~7);
+ format->Format.nChannels = (WORD)channels;
+ format->Format.nSamplesPerSec = (DWORD)sampleRate;
+ format->Format.nAvgBytesPerSec = (DWORD)(sampleRate * channels * (padded_bits >> 3));
+ format->Format.nBlockAlign = (WORD)(channels * (padded_bits >> 3));
+ format->Format.wBitsPerSample = (WORD)padded_bits;
+
+ if (channels > 2 || padded_bits != bits)
+ {
+ format->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ format->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+ format->Samples.wValidBitsPerSample = (WORD)bits;
+ format->dwChannelMask = GetChannelMask(channels);
+ format->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ }
+ else
+ {
+ format->Format.wFormatTag = WAVE_FORMAT_PCM;
+ format->Format.cbSize = 0;
+ }
+}
+
+Resampler::Resampler(size_t inputBits, size_t inputChannels, size_t inputSampleRate,
+ size_t outputBits, size_t outputChannels, size_t outputSampleRate, bool floatingPoint)
+ : sizeFactor(1.), hStream(0), buffer(0), eof(false)
+{
+ if (floatingPoint)
+ {
+ WAVEFORMATIEEEFLOATEX inputFormat;
+ FillWFX_float(&inputFormat, inputChannels, inputBits, inputSampleRate);
+
+ WAVEFORMATIEEEFLOATEX outputFormat;
+ FillWFX_float(&outputFormat, outputChannels, outputBits, outputSampleRate);
+
+ acmStreamOpen(&hStream, 0, &inputFormat.Format, &outputFormat.Format, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ }
+ else
+ {
+ WAVEFORMATEXTENSIBLE inputFormat = {0};
+ FillWFX(&inputFormat, inputChannels, inputBits, inputSampleRate);
+
+ WAVEFORMATEXTENSIBLE outputFormat = {0};
+ FillWFX(&outputFormat, outputChannels, outputBits, outputSampleRate);
+
+ acmStreamOpen(&hStream, 0, &inputFormat.Format, &outputFormat.Format, 0, 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ }
+
+ if (!hStream)
+ {
+ // error - what should we do?
+ return ;
+ }
+
+ bufferAlloc = MulDiv(1024, (int) (outputBits * outputChannels), 8); // TODO: use acmStreamSize
+ buffer = (__int8 *)calloc(bufferAlloc, sizeof(__int8));
+ bufferValid = 0;
+
+ sizeFactor = (outputChannels * outputBits * outputSampleRate) * (inputChannels * inputBits * inputSampleRate);
+}
+
+Resampler::~Resampler()
+{
+ if (hStream)
+ {
+ acmStreamClose(hStream, 0);
+ }
+ free(buffer);
+}
+
+size_t Resampler::UseInternalBuffer(void *output, size_t outputBytes)
+{
+ if (bufferValid)
+ {
+ size_t writeSize = min(outputBytes, bufferValid);
+ memcpy(output, buffer, writeSize);
+
+ if (writeSize)
+ memmove(buffer, buffer + writeSize, bufferValid - writeSize);
+ bufferValid -= writeSize;
+
+ return writeSize;
+ }
+ else
+ return 0;
+}
+
+void Resampler::Flush()
+{
+ eof = true;
+}
+
+size_t Resampler::Convert(void *input, size_t *inputBytes, void *output, size_t outputBytes)
+{
+ size_t x = UseInternalBuffer(output, outputBytes);
+ if (x)
+ return x;
+
+ ACMSTREAMHEADER streamHeader;
+ ZeroMemory(&streamHeader, sizeof(streamHeader));
+
+ streamHeader.cbStruct = sizeof(streamHeader);
+ streamHeader.pbSrc = reinterpret_cast<LPBYTE>(input);
+ streamHeader.cbSrcLength = (DWORD)*inputBytes;
+ streamHeader.pbDst = reinterpret_cast<LPBYTE>(buffer);
+ streamHeader.cbDstLength = (DWORD)bufferAlloc;
+
+ if (acmStreamPrepareHeader(hStream, &streamHeader, 0))
+ return 0; // m_error = 1;
+
+ if (input && *inputBytes && !eof)
+ acmStreamConvert(hStream, &streamHeader, ACM_STREAMCONVERTF_BLOCKALIGN);
+ else
+ acmStreamConvert(hStream, &streamHeader, ACM_STREAMCONVERTF_END);
+
+ *inputBytes -= streamHeader.cbSrcLengthUsed;
+ bufferValid = streamHeader.cbDstLengthUsed;
+
+ acmStreamUnprepareHeader(hStream, &streamHeader, 0);
+ return UseInternalBuffer(output, outputBytes);
+}
+
+bool Resampler::OK()
+{
+ if (hStream)
+ return true;
+ else
+ return false;
+}