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.

163 lines
4.6KB

  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_wav.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_WAV_IMPLEMENTATION
  26. #define DRWAV_API static
  27. #define DRWAV_PRIVATE static
  28. #include "dr_wav.h"
  29. #if defined(__GNUC__)
  30. # pragma GCC diagnostic pop
  31. #endif
  32. struct ysfx_wav_reader_t {
  33. ~ysfx_wav_reader_t() { drwav_uninit(wav.get()); }
  34. std::unique_ptr<drwav> wav;
  35. uint32_t nbuff = 0;
  36. std::unique_ptr<float[]> buff;
  37. };
  38. static bool ysfx_wav_can_handle(const char *path)
  39. {
  40. return ysfx::path_has_suffix(path, "wav");
  41. }
  42. static ysfx_audio_reader_t *ysfx_wav_open(const char *path)
  43. {
  44. std::unique_ptr<drwav> wav{new drwav};
  45. #if !defined(_WIN32)
  46. drwav_bool32 initok = drwav_init_file(wav.get(), path, nullptr);
  47. #else
  48. drwav_bool32 initok = drwav_init_file_w(wav.get(), ysfx::widen(path).c_str(), nullptr);
  49. #endif
  50. if (!initok)
  51. return nullptr;
  52. std::unique_ptr<ysfx_wav_reader_t> reader{new ysfx_wav_reader_t};
  53. reader->wav = std::move(wav);
  54. reader->buff.reset(new float[reader->wav->channels]);
  55. return (ysfx_audio_reader_t *)reader.release();
  56. }
  57. static void ysfx_wav_close(ysfx_audio_reader_t *reader_)
  58. {
  59. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  60. delete reader;
  61. }
  62. static ysfx_audio_file_info_t ysfx_wav_info(ysfx_audio_reader_t *reader_)
  63. {
  64. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  65. ysfx_audio_file_info_t info;
  66. info.channels = reader->wav->channels;
  67. info.sample_rate = (ysfx_real)reader->wav->sampleRate;
  68. return info;
  69. }
  70. static uint64_t ysfx_wav_avail(ysfx_audio_reader_t *reader_)
  71. {
  72. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  73. return reader->nbuff + reader->wav->channels * (reader->wav->totalPCMFrameCount - reader->wav->readCursorInPCMFrames);
  74. }
  75. static void ysfx_wav_rewind(ysfx_audio_reader_t *reader_)
  76. {
  77. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  78. drwav_seek_to_pcm_frame(reader->wav.get(), 0);
  79. reader->nbuff = 0;
  80. }
  81. static uint64_t ysfx_wav_unload_buffer(ysfx_audio_reader_t *reader_, ysfx_real *samples, uint64_t count)
  82. {
  83. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  84. uint32_t nbuff = reader->nbuff;
  85. if (nbuff > count)
  86. nbuff = (uint32_t)count;
  87. if (nbuff == 0)
  88. return 0;
  89. const float *src = &reader->buff[reader->wav->channels - reader->nbuff];
  90. for (uint32_t i = 0; i < nbuff; ++i)
  91. samples[i] = src[i];
  92. reader->nbuff -= nbuff;
  93. return nbuff;
  94. }
  95. static uint64_t ysfx_wav_read(ysfx_audio_reader_t *reader_, ysfx_real *samples, uint64_t count)
  96. {
  97. ysfx_wav_reader_t *reader = (ysfx_wav_reader_t *)reader_;
  98. uint32_t channels = reader->wav->channels;
  99. uint64_t readtotal = 0;
  100. if (count == 0)
  101. return readtotal;
  102. else {
  103. uint64_t copied = ysfx_wav_unload_buffer(reader_, samples, count);
  104. samples += copied;
  105. count -= copied;
  106. readtotal += copied;
  107. }
  108. if (count == 0)
  109. return readtotal;
  110. else {
  111. float *f32buf = (float *)samples;
  112. uint64_t readframes = drwav_read_pcm_frames_f32(reader->wav.get(), count / channels, f32buf);
  113. uint64_t readsamples = channels * readframes;
  114. // f32->f64
  115. for (uint64_t i = readsamples; i-- > 0; )
  116. samples[i] = f32buf[i];
  117. samples += readsamples;
  118. count -= readsamples;
  119. readtotal += readsamples;
  120. }
  121. if (count == 0)
  122. return readtotal;
  123. else if (drwav_read_pcm_frames_f32(reader->wav.get(), 1, reader->buff.get()) == 1) {
  124. reader->nbuff = channels;
  125. uint64_t copied = ysfx_wav_unload_buffer(reader_, samples, count);
  126. samples += copied;
  127. count -= copied;
  128. readtotal += copied;
  129. }
  130. return readtotal;
  131. }
  132. const ysfx_audio_format_t ysfx_audio_format_wav = {
  133. &ysfx_wav_can_handle,
  134. &ysfx_wav_open,
  135. &ysfx_wav_close,
  136. &ysfx_wav_info,
  137. &ysfx_wav_avail,
  138. &ysfx_wav_rewind,
  139. &ysfx_wav_read,
  140. };