summaryrefslogtreecommitdiff
path: root/src/codecs/foxenflac.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-06-15 10:33:46 +1000
committerjacqueline <me@jacqueline.id.au>2023-06-15 10:33:46 +1000
commita2c1dfbabddc2b4abaf8bf27c9ed9d1b99594859 (patch)
tree47fa6b1a0d4d6f1160b8d60d04ee9f6d67e10ce4 /src/codecs/foxenflac.cpp
parent1238437717a49924cb45a12b934b3108c402e864 (diff)
downloadtangara-fw-a2c1dfbabddc2b4abaf8bf27c9ed9d1b99594859.tar.gz
Add vorbis and flac decoders, flesh out codec interface
vorbis doesn't quite work yet, not sure why. will pick it up again later.
Diffstat (limited to 'src/codecs/foxenflac.cpp')
-rw-r--r--src/codecs/foxenflac.cpp80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/codecs/foxenflac.cpp b/src/codecs/foxenflac.cpp
new file mode 100644
index 00000000..a2d6f000
--- /dev/null
+++ b/src/codecs/foxenflac.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "foxenflac.hpp"
+#include <stdint.h>
+
+#include <cstdlib>
+
+#include "esp_log.h"
+#include "foxen/flac.h"
+
+namespace codecs {
+
+FoxenFlacDecoder::FoxenFlacDecoder()
+ : flac_(FX_FLAC_ALLOC(FLAC_MAX_BLOCK_SIZE, 2)) {}
+
+FoxenFlacDecoder::~FoxenFlacDecoder() {
+ free(flac_);
+}
+
+auto FoxenFlacDecoder::BeginStream(const cpp::span<const std::byte> input)
+ -> Result<OutputFormat> {
+ uint32_t bytes_used = input.size_bytes();
+ fx_flac_state_t state =
+ fx_flac_process(flac_, reinterpret_cast<const uint8_t*>(input.data()),
+ &bytes_used, NULL, NULL);
+ if (state != FLAC_END_OF_METADATA) {
+ return {bytes_used, cpp::fail(Error::kMalformedData)};
+ }
+
+ int64_t channels = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_CHANNELS);
+ int64_t fs = fx_flac_get_streaminfo(flac_, FLAC_KEY_SAMPLE_RATE);
+ if (channels == FLAC_INVALID_METADATA_KEY ||
+ fs == FLAC_INVALID_METADATA_KEY) {
+ return {bytes_used, cpp::fail(Error::kMalformedData)};
+ }
+
+ return {bytes_used,
+ OutputFormat{
+ .num_channels = static_cast<uint8_t>(channels),
+ .bits_per_sample = 32, // libfoxenflac output is fixed-size.
+ .sample_rate_hz = static_cast<uint32_t>(fs),
+ }};
+}
+
+auto FoxenFlacDecoder::ContinueStream(cpp::span<const std::byte> input,
+ cpp::span<std::byte> output)
+ -> Result<OutputInfo> {
+ cpp::span<int32_t> output_as_samples{
+ reinterpret_cast<int32_t*>(output.data()), output.size_bytes() / 4};
+ uint32_t bytes_read = input.size_bytes();
+ uint32_t samples_written = output_as_samples.size();
+
+ fx_flac_state_t state =
+ fx_flac_process(flac_, reinterpret_cast<const uint8_t*>(input.data()),
+ &bytes_read, output_as_samples.data(), &samples_written);
+ if (state == FLAC_ERR) {
+ return {bytes_read, cpp::fail(Error::kMalformedData)};
+ }
+
+ if (samples_written > 0) {
+ return {bytes_read,
+ OutputInfo{.bytes_written = samples_written * 4,
+ .is_finished_writing = state == FLAC_END_OF_FRAME}};
+ }
+
+ // No error, but no samples written. We must be out of data.
+ return {bytes_read, cpp::fail(Error::kOutOfInput)};
+}
+
+auto FoxenFlacDecoder::SeekStream(cpp::span<const std::byte> input,
+ std::size_t target_sample) -> Result<void> {
+ // TODO(jacqueline): Implement me.
+ return {0, {}};
+}
+
+} // namespace codecs