aboutsummaryrefslogtreecommitdiff
path: root/Src/adpcm/flv_adpcm_decoder.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/adpcm/flv_adpcm_decoder.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/adpcm/flv_adpcm_decoder.cpp')
-rw-r--r--Src/adpcm/flv_adpcm_decoder.cpp141
1 files changed, 141 insertions, 0 deletions
diff --git a/Src/adpcm/flv_adpcm_decoder.cpp b/Src/adpcm/flv_adpcm_decoder.cpp
new file mode 100644
index 00000000..69e02948
--- /dev/null
+++ b/Src/adpcm/flv_adpcm_decoder.cpp
@@ -0,0 +1,141 @@
+#include "flv_adpcm_decoder.h"
+#include "../f263/BitReader.h"
+
+int FLVDecoderCreator::CreateAudioDecoder(int stereo, int bits, int sample_rate, int format_type, ifc_flvaudiodecoder **decoder)
+{
+ if (format_type == FLV::AUDIO_FORMAT_ADPCM)
+ {
+ *decoder = new FLVADPCM(stereo?2:1);
+ return CREATEDECODER_SUCCESS;
+ }
+ return CREATEDECODER_NOT_MINE;
+}
+
+int FLVDecoderCreator::HandlesAudio(int format_type)
+{
+ if (format_type == FLV::AUDIO_FORMAT_ADPCM)
+ {
+ return CREATEDECODER_SUCCESS;
+ }
+ return CREATEDECODER_NOT_MINE;
+}
+
+#define CBCLASS FLVDecoderCreator
+START_DISPATCH;
+CB(CREATE_AUDIO_DECODER, CreateAudioDecoder)
+CB(HANDLES_AUDIO, HandlesAudio)
+END_DISPATCH;
+#undef CBCLASS
+
+/* --- */
+FLVADPCM::FLVADPCM(unsigned int channels) : channels(channels)
+{
+
+}
+
+int FLVADPCM::GetOutputFormat(unsigned int *sample_rate, unsigned int *channels, unsigned int *bits)
+{
+ *channels = this->channels;
+ *bits = 16;
+ return FLV_AUDIO_SUCCESS;
+}
+
+// padded to zero where table size is less then 16
+static const int swf_index_tables[4][16] = {
+ /*2*/ { -1, 2 },
+ /*3*/ { -1, -1, 2, 4 },
+ /*4*/ { -1, -1, -1, -1, 2, 4, 6, 8 },
+ /*5*/ { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
+};
+
+static const int step_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+int FLVADPCM::DecodeSample(const void *input_buffer, size_t input_buffer_bytes, void *_samples, size_t *samples_size_bytes, double *bitrate)
+{
+ int predictors[2] = {0, 0};
+ int16_t step_indices[2] = {0, 0};
+
+ int16_t *samples = (int16_t *)_samples;
+ const size_t max_samples = *samples_size_bytes / sizeof(int16_t);
+
+ BitReader bit_reader;
+ bit_reader.data = (uint8_t *)input_buffer;
+ bit_reader.numBits = (uint32_t)input_buffer_bytes * 8;
+
+ uint32_t bits = bit_reader.getbits(2);
+ const int *table = swf_index_tables[bits];
+ int k0 = 1 << bits++;
+ int signmask = 1 << bits++;
+
+ size_t sample_num=0;
+ while (bit_reader.size() >= 22*channels)
+ {
+ for (size_t i = 0; i != channels; i++)
+ {
+ samples[sample_num++] = predictors[i] = ((int32_t)bit_reader.getbits(16) << 16) >> 16;
+ step_indices[i] = bit_reader.getbits(6);
+ }
+
+ while (bit_reader.size() > bits*channels && sample_num < max_samples)
+ {
+ for (size_t i = 0; i != channels; i++)
+ {
+ int delta = bit_reader.getbits(bits);
+ int step = step_table[step_indices[i]];
+ long vpdiff = 0;
+ int k = k0;
+
+ do {
+ if (delta & k)
+ vpdiff += step;
+ step >>= 1;
+ k >>= 1;
+ } while(k);
+ vpdiff += step;
+
+ if (delta & signmask)
+ predictors[i] -= vpdiff;
+ else
+ predictors[i] += vpdiff;
+
+ step_indices[i] += table[delta & (~signmask)];
+
+ if (step_indices[i] < 0) step_indices[i] = 0;
+ if (step_indices[i] > 88) step_indices[i] = 88;
+
+ if (predictors[i] > 32767) predictors[i] = 32767;
+ if (predictors[i] < -32768) predictors[i] = -32768;
+
+ samples[sample_num++] = predictors[i];
+ }
+ }
+ }
+
+ *samples_size_bytes = sample_num * sizeof(int16_t);
+
+ return FLV_AUDIO_SUCCESS;
+}
+
+
+void FLVADPCM::Close()
+{
+ delete this;
+}
+
+#define CBCLASS FLVADPCM
+START_DISPATCH;
+CB(FLV_AUDIO_GETOUTPUTFORMAT, GetOutputFormat)
+CB(FLV_AUDIO_DECODE, DecodeSample)
+VCB(FLV_AUDIO_CLOSE, Close)
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file