|
@@ -0,0 +1,95 @@
|
|
|
+#include "AudioPlayer.h"
|
|
|
+#include "spdlog/spdlog.h"
|
|
|
+
|
|
|
+#include <cassert>
|
|
|
+#include <cmath>
|
|
|
+
|
|
|
+struct AudioData {
|
|
|
+ float *data;
|
|
|
+};
|
|
|
+
|
|
|
+namespace Audio {
|
|
|
+
|
|
|
+AudioPlayer::AudioPlayer() {
|
|
|
+
|
|
|
+ spdlog::info("Started Audio Player {} {}", m_frequency, m_sample_rate);
|
|
|
+
|
|
|
+ generate_samples();
|
|
|
+ config = ma_device_config_init(ma_device_type_playback);
|
|
|
+ config.playback.format = ma_format_f32;
|
|
|
+ config.playback.channels = 2;
|
|
|
+ config.sampleRate = m_sample_rate;
|
|
|
+ config.dataCallback = data_callback;
|
|
|
+ AudioData ad;
|
|
|
+ ad.data = m_sample.data();
|
|
|
+ //ad.length = m_sample.size();
|
|
|
+ // ad.frequency = m_frequency;
|
|
|
+ // ad.sample_rate = m_sample_rate;
|
|
|
+ config.pUserData = static_cast<float *>(m_sample.data());
|
|
|
+ ma_device_init(NULL, &config, &device);
|
|
|
+
|
|
|
+ spdlog::info("Device: {} Channels: {}, Sample Rate: {}/{}", device.playback.name, device.playback.channels, device.sampleRate, device.playback.internalSampleRate);
|
|
|
+}
|
|
|
+
|
|
|
+void AudioPlayer::play() {
|
|
|
+
|
|
|
+ m_is_playing = true;
|
|
|
+ ma_device_start(&device);
|
|
|
+}
|
|
|
+
|
|
|
+void AudioPlayer::pause() {
|
|
|
+ m_is_playing = false;
|
|
|
+ ma_device_uninit(&device);
|
|
|
+}
|
|
|
+
|
|
|
+bool AudioPlayer::is_playing() { return m_is_playing; }
|
|
|
+
|
|
|
+void AudioPlayer::generate_samples() {
|
|
|
+ float tick = m_frequency / m_sample_rate;
|
|
|
+
|
|
|
+ for (float i = 0.f; i < 2 * PI_F; i += tick) {
|
|
|
+ m_sample.push_back(next_sample());
|
|
|
+ }
|
|
|
+
|
|
|
+ spdlog::info("Have {} samples", m_sample.size());
|
|
|
+}
|
|
|
+
|
|
|
+float AudioPlayer::next_sample() {
|
|
|
+ m_phase += m_frequency / m_sample_rate;
|
|
|
+ if (m_phase >= 1.0) {
|
|
|
+ m_phase -= floorf(m_phase);
|
|
|
+ }
|
|
|
+ return sinf(2 * PI_F * m_phase) * m_amplitude;
|
|
|
+}
|
|
|
+
|
|
|
+int AudioPlayer::get_next_frame_pos(float frequency, float sample_rate) {
|
|
|
+ float tick = frequency / sample_rate;
|
|
|
+ float max = PI_F / tick;
|
|
|
+ s_frame_pos++;
|
|
|
+ if (s_frame_pos >= max) {
|
|
|
+ s_frame_pos = 0;
|
|
|
+ }
|
|
|
+ return s_frame_pos;
|
|
|
+}
|
|
|
+
|
|
|
+void AudioPlayer::data_callback(ma_device *device, void *output,
|
|
|
+ const void *input, ma_uint32 frame_count) {
|
|
|
+ float *output_f32 = (float *)output;
|
|
|
+ float *ad = (float *)(device->pUserData);
|
|
|
+
|
|
|
+ int j = get_next_frame_pos(440.0f, 44100.f);
|
|
|
+ // spdlog::info("Got frame pos: {} with length: {} and value: {}", j, 0, (float)ad[j]);
|
|
|
+ //if (ad->length == 0)
|
|
|
+ // return;
|
|
|
+
|
|
|
+ for (uint32_t curFrame = 0; curFrame < frame_count; curFrame+=2) {
|
|
|
+ //assert(j < ad->length);
|
|
|
+ // spdlog::info("Got value {} -> {}", j, ad->data[j]);
|
|
|
+ float value = (float)ad[j];
|
|
|
+ output_f32[curFrame * 2 + 0] = value;
|
|
|
+ output_f32[curFrame * 2 + 1] = value;
|
|
|
+ //if (++j >= ad->length)
|
|
|
+ // j = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+} // namespace Audio
|