parent
							
								
									7d3ddac0ea
								
							
						
					
					
						commit
						e7e6c70fb3
					
				@ -1,207 +0,0 @@ | 
				
			||||
/*
 | 
				
			||||
 * Copyright 2023 jacqueline <me@jacqueline.id.au> | 
				
			||||
 * | 
				
			||||
 * SPDX-License-Identifier: GPL-3.0-only | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include "miniflac.hpp" | 
				
			||||
 | 
				
			||||
#include <cstdint> | 
				
			||||
#include <cstdlib> | 
				
			||||
 | 
				
			||||
#include "esp_heap_caps.h" | 
				
			||||
#include "esp_log.h" | 
				
			||||
#include "miniflac.h" | 
				
			||||
#include "result.hpp" | 
				
			||||
#include "sample.hpp" | 
				
			||||
 | 
				
			||||
namespace codecs { | 
				
			||||
 | 
				
			||||
[[maybe_unused]] static const char kTag[] = "flac"; | 
				
			||||
 | 
				
			||||
static constexpr size_t kMaxFrameSize = 4608; | 
				
			||||
 | 
				
			||||
MiniFlacDecoder::MiniFlacDecoder() | 
				
			||||
    : input_(), | 
				
			||||
      buffer_(), | 
				
			||||
      flac_(reinterpret_cast<miniflac_t*>( | 
				
			||||
          heap_caps_malloc(sizeof(miniflac_t), | 
				
			||||
                           MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))), | 
				
			||||
      current_sample_() { | 
				
			||||
  miniflac_init(flac_.get(), MINIFLAC_CONTAINER_UNKNOWN); | 
				
			||||
  for (int i = 0; i < samples_by_channel_.size(); i++) { | 
				
			||||
    uint32_t caps; | 
				
			||||
    if (i == 0) { | 
				
			||||
      caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; | 
				
			||||
    } else { | 
				
			||||
      // FIXME: We can *almost* fit two channels into internal ram, but we're a
 | 
				
			||||
      // few KiB shy of being able to do it safely.
 | 
				
			||||
      caps = MALLOC_CAP_SPIRAM; | 
				
			||||
    } | 
				
			||||
    samples_by_channel_[i] = reinterpret_cast<int32_t*>( | 
				
			||||
        heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), caps)); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
MiniFlacDecoder::~MiniFlacDecoder() { | 
				
			||||
  for (int i = 0; i < samples_by_channel_.size(); i++) { | 
				
			||||
    heap_caps_free(samples_by_channel_[i]); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) | 
				
			||||
    -> cpp::result<OutputFormat, Error> { | 
				
			||||
  input_ = input; | 
				
			||||
 | 
				
			||||
  MINIFLAC_RESULT res; | 
				
			||||
  auto read_until_result = [&](auto fn) { | 
				
			||||
    while (true) { | 
				
			||||
      bool eof = buffer_.Refill(input_.get()); | 
				
			||||
      buffer_.ConsumeBytes(fn); | 
				
			||||
      if (res == MINIFLAC_CONTINUE && !eof) { | 
				
			||||
        continue; | 
				
			||||
      } | 
				
			||||
      break; | 
				
			||||
    } | 
				
			||||
  }; | 
				
			||||
 | 
				
			||||
  uint32_t sample_rate = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_sample_rate( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &sample_rate); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  uint8_t channels = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_channels( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &channels); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  uint64_t total_samples = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_total_samples( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &total_samples); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  if (channels == 0 || channels > 2) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  if (offset) { | 
				
			||||
    uint64_t samples_count = 0; | 
				
			||||
    uint32_t offset_count = 0; | 
				
			||||
    while (offset_count < offset) { | 
				
			||||
      read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
        uint32_t bytes_used = 0; | 
				
			||||
        res = miniflac_sync( | 
				
			||||
            flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
            buf.size_bytes(), &bytes_used); | 
				
			||||
        return bytes_used; | 
				
			||||
      }); | 
				
			||||
      if (res != MINIFLAC_OK) { | 
				
			||||
        return cpp::fail(Error::kMalformedData); | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      uint32_t frame_samplerate = flac_.get()->frame.header.sample_rate; | 
				
			||||
      uint16_t frame_blocksize = flac_.get()->frame.header.block_size; | 
				
			||||
      if (!frame_samplerate || !frame_blocksize) { | 
				
			||||
        continue; | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      samples_count += frame_blocksize; | 
				
			||||
      offset_count = samples_count / sample_rate; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  OutputFormat format{ | 
				
			||||
      .num_channels = static_cast<uint8_t>(channels), | 
				
			||||
      .sample_rate_hz = static_cast<uint32_t>(sample_rate), | 
				
			||||
      .total_samples = total_samples * channels, | 
				
			||||
  }; | 
				
			||||
 | 
				
			||||
  return format; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::DecodeTo(cpp::span<sample::Sample> output) | 
				
			||||
    -> cpp::result<OutputInfo, Error> { | 
				
			||||
  bool is_eof = false; | 
				
			||||
 | 
				
			||||
  if (!current_sample_) { | 
				
			||||
    MINIFLAC_RESULT res = MINIFLAC_CONTINUE; | 
				
			||||
    while (res == MINIFLAC_CONTINUE && !is_eof) { | 
				
			||||
      is_eof = buffer_.Refill(input_.get()); | 
				
			||||
      buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
        // FIXME: We should do a miniflac_sync first, in order to check that
 | 
				
			||||
        // our sample buffers have enough space for the next frame.
 | 
				
			||||
        uint32_t bytes_read = 0; | 
				
			||||
        res = miniflac_decode( | 
				
			||||
            flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
            buf.size_bytes(), &bytes_read, samples_by_channel_.data()); | 
				
			||||
        return bytes_read; | 
				
			||||
      }); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if (res == MINIFLAC_OK) { | 
				
			||||
      current_sample_ = 0; | 
				
			||||
    } else if (is_eof) { | 
				
			||||
      return OutputInfo{ | 
				
			||||
          .samples_written = 0, | 
				
			||||
          .is_stream_finished = true, | 
				
			||||
      }; | 
				
			||||
    } else { | 
				
			||||
      return cpp::fail(Error::kMalformedData); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  size_t samples_written = 0; | 
				
			||||
  if (current_sample_) { | 
				
			||||
    while (*current_sample_ < flac_->frame.header.block_size) { | 
				
			||||
      if (samples_written + flac_->frame.header.channels >= output.size()) { | 
				
			||||
        // We can't fit the next full PCM frame into the buffer.
 | 
				
			||||
        return OutputInfo{.samples_written = samples_written, | 
				
			||||
                          .is_stream_finished = false}; | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      for (int channel = 0; channel < flac_->frame.header.channels; channel++) { | 
				
			||||
        output[samples_written++] = | 
				
			||||
            sample::FromSigned(samples_by_channel_[channel][*current_sample_], | 
				
			||||
                               flac_->frame.header.bps); | 
				
			||||
      } | 
				
			||||
      (*current_sample_)++; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  current_sample_.reset(); | 
				
			||||
  return OutputInfo{.samples_written = samples_written, | 
				
			||||
                    .is_stream_finished = samples_written == 0 && is_eof}; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::SeekTo(size_t target) -> cpp::result<void, Error> { | 
				
			||||
  return {}; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
}  // namespace codecs
 | 
				
			||||
@ -1,266 +0,0 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright 2023 jacqueline <me@jacqueline.id.au> | 
				
			||||
 * | 
				
			||||
 * SPDX-License-Identifier: GPL-3.0-only | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
#include "miniflac.hpp" | 
				
			||||
 | 
				
			||||
#include <cstdint> | 
				
			||||
#include <cstdlib> | 
				
			||||
 | 
				
			||||
#include "esp_heap_caps.h" | 
				
			||||
#include "esp_log.h" | 
				
			||||
#include "miniflac.h" | 
				
			||||
#include "result.hpp" | 
				
			||||
#include "sample.hpp" | 
				
			||||
 | 
				
			||||
namespace codecs { | 
				
			||||
 | 
				
			||||
[[maybe_unused]] static const char kTag[] = "flac"; | 
				
			||||
 | 
				
			||||
static constexpr size_t kMaxFrameSize = 4608; | 
				
			||||
 | 
				
			||||
MiniFlacDecoder::MiniFlacDecoder() | 
				
			||||
    : input_(), | 
				
			||||
      buffer_(), | 
				
			||||
      flac_(reinterpret_cast<miniflac_t*>( | 
				
			||||
          heap_caps_malloc(sizeof(miniflac_t), | 
				
			||||
                           MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))), | 
				
			||||
      current_sample_() { | 
				
			||||
  miniflac_init(flac_.get(), MINIFLAC_CONTAINER_UNKNOWN); | 
				
			||||
  for (int i = 0; i < samples_by_channel_.size(); i++) { | 
				
			||||
    uint32_t caps; | 
				
			||||
    if (i == 0) { | 
				
			||||
      caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; | 
				
			||||
    } else { | 
				
			||||
      // FIXME: We can *almost* fit two channels into internal ram, but we're a | 
				
			||||
      // few KiB shy of being able to do it safely. | 
				
			||||
      caps = MALLOC_CAP_SPIRAM; | 
				
			||||
    } | 
				
			||||
    samples_by_channel_[i] = reinterpret_cast<int32_t*>( | 
				
			||||
        heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), caps)); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
MiniFlacDecoder::~MiniFlacDecoder() { | 
				
			||||
  for (int i = 0; i < samples_by_channel_.size(); i++) { | 
				
			||||
    heap_caps_free(samples_by_channel_[i]); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset) | 
				
			||||
    -> cpp::result<OutputFormat, Error> { | 
				
			||||
  input_ = input; | 
				
			||||
 | 
				
			||||
  MINIFLAC_RESULT res; | 
				
			||||
  bool is_eof; | 
				
			||||
  auto read_until_result = [&](auto fn) { | 
				
			||||
    while (true) { | 
				
			||||
      is_eof = buffer_.Refill(input_.get()); | 
				
			||||
      buffer_.ConsumeBytes(fn); | 
				
			||||
      if (res == MINIFLAC_CONTINUE && !eof) { | 
				
			||||
        continue; | 
				
			||||
      } | 
				
			||||
      break; | 
				
			||||
    } | 
				
			||||
  }; | 
				
			||||
 | 
				
			||||
  uint16_t min_block_size = 0; // In samples | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_min_block_size( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &min_block_size); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  uint16_t max_block_size = 0; // In samples | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_min_block_size( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &max_block_size); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  ESP_LOGI(kTag, "Blocksize min: %u max %u", min_block_size, max_block_size); | 
				
			||||
 | 
				
			||||
  uint32_t sample_rate = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_sample_rate( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &sample_rate); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  uint8_t channels = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_channels( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &channels); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  uint64_t total_samples = 0; | 
				
			||||
 | 
				
			||||
  read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    uint32_t bytes_used = 0; | 
				
			||||
    res = miniflac_streaminfo_total_samples( | 
				
			||||
        flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
        buf.size_bytes(), &bytes_used, &total_samples); | 
				
			||||
    return bytes_used; | 
				
			||||
  }); | 
				
			||||
 | 
				
			||||
  if (res != MINIFLAC_OK) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  if (channels == 0 || channels > 2) { | 
				
			||||
    return cpp::fail(Error::kMalformedData); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  // Seeking | 
				
			||||
  offset = 0; | 
				
			||||
  if (offset) { | 
				
			||||
    // Super dumb approach, but lets try it first | 
				
			||||
    // Go to the first frame | 
				
			||||
    while(flac_.get()->state == MINIFLAC_METADATA) { | 
				
			||||
        read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
          uint32_t bytes_used = 0; | 
				
			||||
          res = miniflac_sync( | 
				
			||||
              flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
              buf.size_bytes(), &bytes_used); | 
				
			||||
          return bytes_used; | 
				
			||||
        }); | 
				
			||||
        if (res != MINIFLAC_OK) { | 
				
			||||
          ESP_LOGI(kTag, "IT HAPPENED"); | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
    ESP_LOGI(kTag, "Flac state: %d", flac_->state); | 
				
			||||
      | 
				
			||||
     // Naive approach  | 
				
			||||
    uint64_t byte_offset = offset; // TODO | 
				
			||||
 | 
				
			||||
    ESP_LOGI(kTag, "Going to skip forward %llu bytes", byte_offset); | 
				
			||||
    if (input_.get()->CanSeek()) { | 
				
			||||
      ESP_LOGI(kTag, "Skipping forward %llu bytes", byte_offset); | 
				
			||||
      buffer_.Empty(); | 
				
			||||
      input_.get()->SeekTo(byte_offset, IStream::SeekFrom::kCurrentPosition); | 
				
			||||
    } | 
				
			||||
    // buffer_.Refill(input_.get()); | 
				
			||||
 | 
				
			||||
    // // Sync again | 
				
			||||
    // read_until_result([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
    //   uint32_t bytes_used = 0; | 
				
			||||
    //   res = miniflac_sync( | 
				
			||||
    //       flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
    //       buf.size_bytes(), &bytes_used); | 
				
			||||
    //   return bytes_used; | 
				
			||||
    // }); | 
				
			||||
    // if (res != MINIFLAC_OK) { | 
				
			||||
    //   ESP_LOGI(kTag, "IT HAPPENED HERE! %d", res); | 
				
			||||
    // } | 
				
			||||
 | 
				
			||||
    // ESP_LOGI(kTag, "Decoder state: %d", flac_->state); | 
				
			||||
    // ESP_LOGI(kTag, "Frame header state: %d", flac_->frame.header.state); | 
				
			||||
 | 
				
			||||
    // // TODO: Sample number is not guaranteed, could be block index. | 
				
			||||
    // ESP_LOGI(kTag, "Ended up... at sample %llu", flac_->frame.header.sample_number); | 
				
			||||
    // ESP_LOGI(kTag, "and block index: %lu", flac_->frame.header.frame_number); | 
				
			||||
    // ESP_LOGI(kTag, "total samples: %llu", total_samples); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
 | 
				
			||||
  OutputFormat format{ | 
				
			||||
      .num_channels = static_cast<uint8_t>(channels), | 
				
			||||
      .sample_rate_hz = static_cast<uint32_t>(sample_rate), | 
				
			||||
      .total_samples = total_samples * channels, | 
				
			||||
  }; | 
				
			||||
 | 
				
			||||
  return format; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::DecodeTo(cpp::span<sample::Sample> output) | 
				
			||||
    -> cpp::result<OutputInfo, Error> { | 
				
			||||
  bool is_eof = false; | 
				
			||||
 | 
				
			||||
  if (!current_sample_) { | 
				
			||||
    MINIFLAC_RESULT res = MINIFLAC_CONTINUE; | 
				
			||||
    while (res == MINIFLAC_CONTINUE && !is_eof) { | 
				
			||||
      is_eof = buffer_.Refill(input_.get()); | 
				
			||||
      ESP_LOGI(kTag, "EOF? %s", is_eof ? "true" : "false"); | 
				
			||||
      buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { | 
				
			||||
        // FIXME: We should do a miniflac_sync first, in order to check that | 
				
			||||
        // our sample buffers have enough space for the next frame. | 
				
			||||
        uint32_t bytes_read = 0; | 
				
			||||
        res = miniflac_decode( | 
				
			||||
            flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), | 
				
			||||
            buf.size_bytes(), &bytes_read, samples_by_channel_.data()); | 
				
			||||
        return bytes_read; | 
				
			||||
      }); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    if (res == MINIFLAC_OK) { | 
				
			||||
      current_sample_ = 0; | 
				
			||||
    } else if (is_eof) { | 
				
			||||
      return OutputInfo{ | 
				
			||||
          .samples_written = 0, | 
				
			||||
          .is_stream_finished = true, | 
				
			||||
      }; | 
				
			||||
    } else { | 
				
			||||
      ESP_LOGI(kTag, "Failed: decoder result: %d", res); | 
				
			||||
      return cpp::fail(Error::kMalformedData); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  size_t samples_written = 0; | 
				
			||||
  if (current_sample_) { | 
				
			||||
    while (*current_sample_ < flac_->frame.header.block_size) { | 
				
			||||
      if (samples_written + flac_->frame.header.channels >= output.size()) { | 
				
			||||
        // We can't fit the next full PCM frame into the buffer. | 
				
			||||
        return OutputInfo{.samples_written = samples_written, | 
				
			||||
                          .is_stream_finished = false}; | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      for (int channel = 0; channel < flac_->frame.header.channels; channel++) { | 
				
			||||
        output[samples_written++] = | 
				
			||||
            sample::FromSigned(samples_by_channel_[channel][*current_sample_], | 
				
			||||
                               flac_->frame.header.bps); | 
				
			||||
      } | 
				
			||||
      (*current_sample_)++; | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  current_sample_.reset(); | 
				
			||||
  ESP_LOGI(kTag, "Samples written %lu", (uint32_t)samples_written); | 
				
			||||
  return OutputInfo{.samples_written = samples_written, | 
				
			||||
                    .is_stream_finished = samples_written == 0 && is_eof}; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
auto MiniFlacDecoder::SeekTo(size_t target) -> cpp::result<void, Error> { | 
				
			||||
  return {}; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
}  // namespace codecs | 
				
			||||
					Loading…
					
					
				
		Reference in new issue