25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

257 lines
7.0 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010–2024 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #pragma once
  13. //
  14. // The audio stream interface
  15. // ——————————————————————————
  16. // Stream, mix, and apply audio effects.
  17. //
  18. #include <functional> // std::function
  19. #include <memory> // std::shared_ptr
  20. #include <type_traits> // std::is_same_v
  21. #include <unordered_set> // std::unordered_set
  22. namespace lol::audio
  23. {
  24. template<typename T>
  25. class stream
  26. {
  27. public:
  28. using sample_type = T;
  29. virtual size_t get(T* buf, size_t frames) = 0;
  30. inline size_t channels() const { return m_channels; }
  31. inline int frequency() const { return m_frequency; }
  32. inline size_t frame_size() const { return channels() * sizeof(T); }
  33. virtual ~stream() = default;
  34. protected:
  35. stream(size_t channels, int frequency)
  36. : m_channels(channels),
  37. m_frequency(frequency)
  38. {}
  39. size_t m_channels;
  40. int m_frequency;
  41. };
  42. template<typename T>
  43. class generator : public stream<T>
  44. {
  45. public:
  46. generator(std::function<size_t(T*, size_t)> get, size_t channels, int frequency)
  47. : stream<T>(channels, frequency),
  48. m_get(get)
  49. {}
  50. virtual size_t get(T* buf, size_t frames) override
  51. {
  52. return m_get(buf, frames);
  53. }
  54. protected:
  55. std::function<size_t(T*, size_t)> m_get;
  56. };
  57. template<typename T>
  58. class mixer : public stream<T>
  59. {
  60. public:
  61. mixer(size_t channels, int frequency)
  62. : stream<T>(channels, frequency)
  63. {}
  64. void add(std::shared_ptr<stream<T>> s)
  65. {
  66. // FIXME: check the channel count!
  67. m_streams.insert(s);
  68. }
  69. void remove(std::shared_ptr<stream<T>> s)
  70. {
  71. m_streams.erase(s);
  72. }
  73. virtual size_t get(T *buf, size_t frames) override
  74. {
  75. std::vector<std::vector<T>> buffers;
  76. size_t const samples = frames * this->channels();
  77. for (auto s : m_streams)
  78. {
  79. buffers.push_back(std::vector<T>(samples));
  80. s->get(buffers.back().data(), frames);
  81. }
  82. for (size_t n = 0; n < samples; ++n)
  83. {
  84. T sample = T(0);
  85. for (auto const &b : buffers)
  86. sample += b[n];
  87. if constexpr (std::is_same_v<T, float>)
  88. buf[n] = std::min(1.0f, std::max(-1.0f, sample));
  89. else if constexpr (std::is_same_v<T, int16_t>)
  90. buf[n] = std::min(int16_t(32767), std::max(int16_t(-32768), sample));
  91. else if constexpr (std::is_same_v<T, uint16_t>)
  92. buf[n] = std::min(uint16_t(65535), std::max(uint16_t(0), sample));
  93. else
  94. buf[n] = sample;
  95. }
  96. return frames;
  97. }
  98. protected:
  99. std::unordered_set<std::shared_ptr<stream<T>>> m_streams;
  100. };
  101. template<typename T0, typename T>
  102. static inline T convert_sample(T0);
  103. template<>
  104. inline float convert_sample(float x) { return x; }
  105. template<>
  106. inline float convert_sample(int16_t x) { return x / 32768.0f; }
  107. template<>
  108. inline float convert_sample(uint16_t x) { return x / 32767.0f - 1.0f; }
  109. template<typename T, typename T0>
  110. class converter : public stream<T>
  111. {
  112. public:
  113. converter(std::shared_ptr<stream<T0>> s, size_t channels)
  114. : stream<T>(channels, s->frequency()),
  115. s0(s)
  116. {}
  117. virtual size_t get(T *buf, size_t frames) override
  118. {
  119. if constexpr(std::is_same_v<T0, T>)
  120. if (this->channels() == s0->channels())
  121. return s0->get(buf, frames);
  122. std::vector<T0> tmp(frames * s0->channels());
  123. s0->get(tmp.data(), frames);
  124. for (size_t f = 0; f < frames; ++f)
  125. {
  126. buf[f * this->channels()] = convert_sample<T0, T>(tmp[f * s0->channels()]);
  127. for (size_t ch = 1; ch < this->channels(); ++ch)
  128. {
  129. size_t ch0 = std::max(size_t(0), s0->channels() - (this->channels() - ch));
  130. buf[f * this->channels() + ch] = convert_sample<T0, T>(tmp[f * s0->channels() + ch0]);
  131. }
  132. }
  133. return frames;
  134. }
  135. protected:
  136. std::shared_ptr<stream<T0>> s0;
  137. };
  138. template<typename T>
  139. class resampler : public stream<T>
  140. {
  141. public:
  142. resampler(std::shared_ptr<stream<T>> s, int frequency)
  143. : stream<T>(s->channels(), frequency),
  144. m_in(s),
  145. m_pos(0)
  146. {}
  147. virtual size_t get(T *buf, size_t frames) override
  148. {
  149. if (m_in->frequency() == this->frequency())
  150. return m_in->get(buf, frames);
  151. double ratio = double(m_in->frequency()) / this->frequency();
  152. for (size_t n = 0; n < frames; ++n, m_pos += ratio)
  153. {
  154. // Fill internal buffer if we don’t have enough data
  155. while (m_cache.size() / this->channels() < size_t(m_pos) + 2)
  156. {
  157. // Remove obsolete frames on the left
  158. size_t todelete = std::min(size_t(m_pos), m_cache.size() / this->channels());
  159. std::vector<T>(m_cache.begin() + todelete * this->channels(), m_cache.end()).swap(m_cache);
  160. m_pos -= todelete;
  161. // Add new frames to the right
  162. size_t offset = m_cache.size();
  163. m_cache.resize(offset + frames * this->channels());
  164. m_in->get(&m_cache[offset], frames);
  165. }
  166. size_t n0 = size_t(m_pos);
  167. float alpha = float(m_pos - n0);
  168. for (size_t ch = 0; ch < this->channels(); ++ch)
  169. {
  170. buf[n * this->channels() + ch] = m_cache[n0 * this->channels() + ch] * (1.f - alpha)
  171. + m_cache[(n0 + 1) * this->channels() + ch] * alpha;
  172. }
  173. }
  174. return frames;
  175. }
  176. protected:
  177. std::shared_ptr<stream<T>> m_in;
  178. std::vector<T> m_cache;
  179. double m_pos;
  180. };
  181. template<typename T>
  182. static inline auto make_generator(std::function<size_t(T*, size_t)> f, size_t channels, int frequency)
  183. {
  184. return std::make_shared<generator<T>>(f, channels, frequency);
  185. }
  186. template<typename F>
  187. static inline auto make_generator(F f, size_t channels, int frequency)
  188. {
  189. return make_generator(std::function(f), channels, frequency);
  190. }
  191. template<typename T, typename S0, typename T0 = S0::sample_type>
  192. static inline auto make_converter(std::shared_ptr<S0> s, size_t channels)
  193. {
  194. return std::make_shared<converter<T, T0>>(std::shared_ptr<stream<T0>>(s), channels);
  195. }
  196. template<typename S, typename T = S::sample_type>
  197. static inline auto make_resampler(std::shared_ptr<S> s, int frequency)
  198. {
  199. return std::make_shared<resampler<T>>(std::shared_ptr<stream<T>>(s), frequency);
  200. }
  201. template<typename T, typename S0, typename T0 = S0::sample_type>
  202. static inline auto make_adapter(std::shared_ptr<S0> s, size_t channels, int frequency)
  203. {
  204. return make_resampler(make_converter<T>(s, channels), frequency);
  205. }
  206. } // namespace lol::audio