diff --git a/src/tangara/audio/audio_events.hpp b/src/tangara/audio/audio_events.hpp index f7eaba67..55095d85 100644 --- a/src/tangara/audio/audio_events.hpp +++ b/src/tangara/audio/audio_events.hpp @@ -86,6 +86,10 @@ struct SetTrack : tinyfsm::Event { std::optional seek_to_second; }; +struct PlaySineWave : tinyfsm::Event { + uint32_t frequency; +}; + struct TogglePlayPause : tinyfsm::Event { std::optional set_to; }; diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index 71f41938..fb186acc 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -11,6 +11,8 @@ #include #include +#include "audio/audio_source.hpp" +#include "audio/sine_source.hpp" #include "cppbor.h" #include "cppbor_parse.h" #include "esp_heap_caps.h" @@ -146,6 +148,17 @@ void AudioState::react(const SetTrack& ev) { }); } +void AudioState::react(const PlaySineWave& ev) { + auto tags = std::make_shared(); + + std::stringstream title; + title << ev.frequency << "Hz Sine Wave"; + tags->title(title.str()); + + sDecoder->open(std::make_shared( + tags, std::make_unique(ev.frequency), title.str())); +} + void AudioState::react(const TogglePlayPause& ev) { sIsPaused = !ev.set_to.value_or(sIsPaused); if (!sIsPaused && is_in_state() && diff --git a/src/tangara/audio/audio_fsm.hpp b/src/tangara/audio/audio_fsm.hpp index 03aaddcb..82f0a3ad 100644 --- a/src/tangara/audio/audio_fsm.hpp +++ b/src/tangara/audio/audio_fsm.hpp @@ -44,6 +44,7 @@ class AudioState : public tinyfsm::Fsm { void react(const tinyfsm::Event& ev) {} void react(const QueueUpdate&); + void react(const PlaySineWave&); void react(const SetTrack&); void react(const TogglePlayPause&); diff --git a/src/tangara/audio/sine_source.cpp b/src/tangara/audio/sine_source.cpp new file mode 100644 index 00000000..9a5a12b9 --- /dev/null +++ b/src/tangara/audio/sine_source.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "audio/sine_source.hpp" + +#include +#include +#include +#include +#include +#include + +#include "esp_log.h" + +#include "audio/audio_source.hpp" +#include "codec.hpp" +#include "drivers/spi.hpp" +#include "sample.hpp" +#include "system_fsm/system_events.hpp" +#include "types.hpp" + +namespace audio { + +[[maybe_unused]] static constexpr char kTag[] = "sine_src"; + +SineSource::SineSource(uint32_t freq) + : IStream(codecs::StreamType::kNative), + step_(0), + increment_((2.0 * std::numbers::pi) / (48000.0 / freq)) {} + +auto SineSource::Read(std::span dest_bytes) -> ssize_t { + std::span dest{ + reinterpret_cast(dest_bytes.data()), + dest_bytes.size_bytes() / sizeof(sample::Sample)}; + + for (size_t i = 0; i < dest.size(); i++) { + dest[i] = std::numeric_limits::max() * + std::sin(step_ += increment_); + } + + return dest.size_bytes(); +} + +auto SineSource::CanSeek() -> bool { + return false; +} + +auto SineSource::SeekTo(int64_t destination, SeekFrom from) -> void {} + +auto SineSource::CurrentPosition() -> int64_t { + return 0; +} + +auto SineSource::Size() -> std::optional { + return {}; +} + +} // namespace audio diff --git a/src/tangara/audio/sine_source.hpp b/src/tangara/audio/sine_source.hpp new file mode 100644 index 00000000..6d514479 --- /dev/null +++ b/src/tangara/audio/sine_source.hpp @@ -0,0 +1,46 @@ +/* + * Copyright 2023 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include +#include + +#include "codec.hpp" +#include "ff.h" + +#include "audio/audio_source.hpp" + +namespace audio { + +/* + * Generates an infinitely long sine wave of a specified frequency. + */ +class SineSource : public codecs::IStream { + public: + SineSource(uint32_t frequency); + + auto Read(std::span dest) -> ssize_t override; + + auto CanSeek() -> bool override; + + auto SeekTo(int64_t destination, SeekFrom from) -> void override; + + auto CurrentPosition() -> int64_t override; + + auto Size() -> std::optional override; + + SineSource(const SineSource&) = delete; + SineSource& operator=(const SineSource&) = delete; + + private: + double step_; + double increment_; +}; + +} // namespace audio