Files
2025-05-13 03:26:56 +03:00

117 lines
2.6 KiB
C++

/*
* sound.h
*
* Created on: 03 ÿíâ. 2016 ã.
* Author: Sergey
*/
#ifndef SOUND_H_
#define SOUND_H_
#include <cstdint>
#include <cstddef>
enum class SoundNodeType {
Wave,
Silence
};
struct SoundNode {
SoundNodeType type;
uint32_t freq;
uint32_t length; //in freq periods
};
struct Notes {
//First octave x100 mul
static constexpr uint32_t values[] = {
26163, 27718, 29366, 31113,
32963, 34923, 36999, 39200,
41530, 44000, 46616, 49388};
static constexpr uint32_t C() {return values[0]; }
static constexpr uint32_t C_d() {return values[1]; }
static constexpr uint32_t D() {return values[2]; }
static constexpr uint32_t D_d() {return values[3]; }
static constexpr uint32_t E() {return values[4]; }
static constexpr uint32_t F() {return values[5]; }
static constexpr uint32_t F_d() {return values[6]; }
static constexpr uint32_t G() {return values[7]; }
static constexpr uint32_t G_d() {return values[8]; }
static constexpr uint32_t A() {return values[9]; }
static constexpr uint32_t B_b() {return values[10]; }
static constexpr uint32_t B() {return values[11]; }
};
//int16_t get_sine(uint8_t phase8);
uint8_t get_sine(uint8_t phase8);
template<typename Base>
class SoundPlayer : public Base {
public:
uint8_t out;
bool is_playing;
SoundPlayer():out(0), is_playing(false), _loop(false), _nodes(nullptr), _nodes_count(0), _active_node(0), _sample_counter(0) {
}
void stop(){
if(is_playing){
Base::on_sound_stop();
}
}
template<size_t Count>
void play_sound(SoundNode(&nodes)[Count], bool loop = false){
play_sound(nodes, Count, loop);
}
void play_sound(SoundNode* nodes, size_t nodes_count, bool loop = false){
stop();
_loop = loop;
out = 0;
is_playing = true;
_nodes = nodes;
_nodes_count = nodes_count;
_active_node = 0;
_sample_counter = 0;
Base::on_sound_play();
}
void update(){
if(is_playing){
auto tmp = ((_sample_counter * 0x100 * (uint64_t)_nodes[_active_node].freq) / Base::get_sampling_rate()) / 100;
if(_nodes[_active_node].type == SoundNodeType::Silence){
out = 0;
} else {
uint8_t sample_interp = (uint8_t)(tmp % 0x100);
//out = sample_interp < 128 ? 0 : 0xff;
out = (int32_t)get_sine(sample_interp);
}
_sample_counter++;
if (_sample_counter >= _nodes[_active_node].length) {
_active_node++;
if (_active_node >= _nodes_count) {
if(_loop){
_active_node = 0;
}else{
is_playing = false;
Base::on_sound_stop();
}
}
_sample_counter = 0;
}
}
}
private:
bool _loop;
SoundNode* _nodes;
size_t _nodes_count;
size_t _active_node;
uint32_t _sample_counter;
};
#endif /* SOUND_H_ */