Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
4.7KB

  1. // Copyright 2021 Jean Pierre Cimalando
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // SPDX-License-Identifier: Apache-2.0
  16. //
  17. #include "ysfx_audio_flac.hpp"
  18. #include "ysfx_utils.hpp"
  19. #include <memory>
  20. #include <cstring>
  21. #if defined(__GNUC__)
  22. # pragma GCC diagnostic push
  23. # pragma GCC diagnostic ignored "-Wunused-function"
  24. #endif
  25. #define DR_FLAC_IMPLEMENTATION
  26. #define DRFLAC_API static
  27. #define DRFLAC_PRIVATE static
  28. #include "dr_flac.h"
  29. #if defined(__GNUC__)
  30. # pragma GCC diagnostic pop
  31. #endif
  32. struct drflac_u_deleter {
  33. void operator()(drflac *x) const noexcept { drflac_close(x); }
  34. };
  35. using drflac_u = std::unique_ptr<drflac, drflac_u_deleter>;
  36. ///
  37. struct ysfx_flac_reader_t {
  38. drflac_u flac;
  39. uint32_t nbuff = 0;
  40. std::unique_ptr<float[]> buff;
  41. };
  42. static bool ysfx_flac_can_handle(const char *path)
  43. {
  44. return ysfx::path_has_suffix(path, "flac");
  45. }
  46. static ysfx_audio_reader_t *ysfx_flac_open(const char *path)
  47. {
  48. #if !defined(_WIN32)
  49. drflac_u flac{drflac_open_file(path, NULL)};
  50. #else
  51. drflac_u flac{drflac_open_file_w(ysfx::widen(path).c_str(), NULL)};
  52. #endif
  53. if (!flac)
  54. return nullptr;
  55. std::unique_ptr<ysfx_flac_reader_t> reader{new ysfx_flac_reader_t};
  56. reader->flac = std::move(flac);
  57. reader->buff.reset(new float[reader->flac->channels]);
  58. return (ysfx_audio_reader_t *)reader.release();
  59. }
  60. static void ysfx_flac_close(ysfx_audio_reader_t *reader_)
  61. {
  62. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  63. delete reader;
  64. }
  65. static ysfx_audio_file_info_t ysfx_flac_info(ysfx_audio_reader_t *reader_)
  66. {
  67. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  68. ysfx_audio_file_info_t info;
  69. info.channels = reader->flac->channels;
  70. info.sample_rate = (ysfx_real)reader->flac->sampleRate;
  71. return info;
  72. }
  73. static uint64_t ysfx_flac_avail(ysfx_audio_reader_t *reader_)
  74. {
  75. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  76. return reader->nbuff + reader->flac->channels * (reader->flac->totalPCMFrameCount - reader->flac->currentPCMFrame);
  77. }
  78. static void ysfx_flac_rewind(ysfx_audio_reader_t *reader_)
  79. {
  80. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  81. drflac_seek_to_pcm_frame(reader->flac.get(), 0);
  82. reader->nbuff = 0;
  83. }
  84. static uint64_t ysfx_flac_unload_buffer(ysfx_audio_reader_t *reader_, ysfx_real *samples, uint64_t count)
  85. {
  86. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  87. uint32_t nbuff = reader->nbuff;
  88. if (nbuff > count)
  89. nbuff = (uint32_t)count;
  90. if (nbuff == 0)
  91. return 0;
  92. const float *src = &reader->buff[reader->flac->channels - reader->nbuff];
  93. for (uint32_t i = 0; i < nbuff; ++i)
  94. samples[i] = src[i];
  95. reader->nbuff -= nbuff;
  96. return nbuff;
  97. }
  98. static uint64_t ysfx_flac_read(ysfx_audio_reader_t *reader_, ysfx_real *samples, uint64_t count)
  99. {
  100. ysfx_flac_reader_t *reader = (ysfx_flac_reader_t *)reader_;
  101. uint32_t channels = reader->flac->channels;
  102. uint64_t readtotal = 0;
  103. if (count == 0)
  104. return readtotal;
  105. else {
  106. uint64_t copied = ysfx_flac_unload_buffer(reader_, samples, count);
  107. samples += copied;
  108. count -= copied;
  109. readtotal += copied;
  110. }
  111. if (count == 0)
  112. return readtotal;
  113. else {
  114. float *f32buf = (float *)samples;
  115. uint64_t readframes = drflac_read_pcm_frames_f32(reader->flac.get(), count / channels, f32buf);
  116. uint64_t readsamples = channels * readframes;
  117. // f32->f64
  118. for (uint64_t i = readsamples; i-- > 0; )
  119. samples[i] = f32buf[i];
  120. samples += readsamples;
  121. count -= readsamples;
  122. readtotal += readsamples;
  123. }
  124. if (count == 0)
  125. return readtotal;
  126. else if (drflac_read_pcm_frames_f32(reader->flac.get(), 1, reader->buff.get()) == 1) {
  127. reader->nbuff = channels;
  128. uint64_t copied = ysfx_flac_unload_buffer(reader_, samples, count);
  129. samples += copied;
  130. count -= copied;
  131. readtotal += copied;
  132. }
  133. return readtotal;
  134. }
  135. const ysfx_audio_format_t ysfx_audio_format_flac = {
  136. &ysfx_flac_can_handle,
  137. &ysfx_flac_open,
  138. &ysfx_flac_close,
  139. &ysfx_flac_info,
  140. &ysfx_flac_avail,
  141. &ysfx_flac_rewind,
  142. &ysfx_flac_read,
  143. };