29#include "freertos/FreeRTOS.h"
30#include "freertos/timers.h"
36#include "driver/dac.h"
37#include "soc/i2s_reg.h"
38#include "driver/periph_ctrl.h"
40#include <soc/sens_reg.h>
42#include "driver/sigmadelta.h"
48#pragma GCC optimize ("O2")
59static const int8_t sinTable[257] = {
60 0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46,
61 49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88,
62 90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115, 116,
63 117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127,
64 127, 127, 127, 127, 126, 126, 126, 125, 125, 124, 123, 122, 122, 121, 120, 118,
65 117, 116, 115, 113, 112, 111, 109, 107, 106, 104, 102, 100, 98, 96, 94, 92,
66 90, 88, 85, 83, 81, 78, 76, 73, 71, 68, 65, 63, 60, 57, 54, 51,
67 49, 46, 43, 40, 37, 34, 31, 28, 25, 22, 19, 16, 12, 9, 6, 3,
68 0, -3, -6, -9, -12, -16, -19, -22, -25, -28, -31, -34, -37, -40, -43, -46,
69 -49, -51, -54, -57, -60, -63, -65, -68, -71, -73, -76, -78, -81, -83, -85, -88,
70 -90, -92, -94, -96, -98, -100, -102, -104, -106, -107, -109, -111, -112, -113, -115, -116,
71-117, -118, -120, -121, -122, -122, -123, -124, -125, -125, -126, -126, -126, -127, -127, -127,
72-127, -127, -127, -127, -126, -126, -126, -125, -125, -124, -123, -122, -122, -121, -120, -118,
73-117, -116, -115, -113, -112, -111, -109, -107, -106, -104, -102, -100, -98, -96, -94, -92,
74 -90, -88, -85, -83, -81, -78, -76, -73, -71, -68, -65, -63, -60, -57, -54, -51,
75 -49, -46, -43, -40, -37, -34, -31, -28, -25, -22, -19, -16, -12, -9, -6, -3,
80SineWaveformGenerator::SineWaveformGenerator()
89void SineWaveformGenerator::setFrequency(
int value) {
90 if (m_frequency != value) {
92 m_phaseInc = (((uint32_t)m_frequency * 256) << 11) / sampleRate();
97int SineWaveformGenerator::getSample() {
98 if (m_frequency == 0 || duration() == 0) {
101 else if (m_lastSample < 0)
109 uint32_t index = m_phaseAcc >> 11;
110 int sample = sinTable[index];
113 sample = sample * volume() / 127;
115 m_lastSample = sample;
117 m_phaseAcc = (m_phaseAcc + m_phaseInc) & 0x7ffff;
134SquareWaveformGenerator::SquareWaveformGenerator()
145 if (m_frequency != value) {
147 m_phaseInc = (((uint32_t)m_frequency * 256) << 11) /
sampleRate();
155 m_dutyCycle = dutyCycle;
160 if (m_frequency == 0 ||
duration() == 0) {
161 if (m_lastSample > 0)
163 else if (m_lastSample < 0)
170 uint32_t index = m_phaseAcc >> 11;
171 int sample = (index <= m_dutyCycle ? 127 : -127);
174 sample = sample *
volume() / 127;
176 m_lastSample = sample;
178 m_phaseAcc = (m_phaseAcc + m_phaseInc) & 0x7ffff;
193TriangleWaveformGenerator::TriangleWaveformGenerator()
203 if (m_frequency != value) {
205 m_phaseInc = (((uint32_t)m_frequency * 256) << 11) /
sampleRate();
211 if (m_frequency == 0 ||
duration() == 0) {
212 if (m_lastSample > 0)
214 else if (m_lastSample < 0)
221 uint32_t index = m_phaseAcc >> 11;
222 int sample = (index & 0x80 ? -1 : 1) * ((index & 0x3F) * 2 - (index & 0x40 ? 0 : 127));
225 sample = sample *
volume() / 127;
227 m_lastSample = sample;
229 m_phaseAcc = (m_phaseAcc + m_phaseInc) & 0x7ffff;
245SawtoothWaveformGenerator::SawtoothWaveformGenerator()
255 if (m_frequency != value) {
257 m_phaseInc = (((uint32_t)m_frequency * 256) << 11) /
sampleRate();
263 if (m_frequency == 0 ||
duration() == 0) {
264 if (m_lastSample > 0)
266 else if (m_lastSample < 0)
273 uint32_t index = m_phaseAcc >> 11;
274 int sample = index - 128;
277 sample = sample *
volume() / 127;
279 m_lastSample = sample;
281 m_phaseAcc = (m_phaseAcc + m_phaseInc) & 0x7ffff;
297NoiseWaveformGenerator::NoiseWaveformGenerator()
315 m_noise = (m_noise >> 1) ^ (-(m_noise & 1) & 0xB400u);
316 int sample = 127 - (m_noise >> 8);
319 sample = sample *
volume() / 127;
338VICNoiseGenerator::VICNoiseGenerator()
349 if (m_frequency != value) {
350 m_frequency = value >= 127 ? 0 : value;
368 for (
int i = 0; i < reduc; ++i) {
370 if (m_counter >= 127) {
373 m_counter = m_frequency;
376 m_outSR = ((m_outSR << 1) | ~(m_outSR >> 7));
379 int bit3 = (m_LFSR >> 3) & 1;
380 int bit12 = (m_LFSR >> 12) & 1;
381 int bit14 = (m_LFSR >> 14) & 1;
382 int bit15 = (m_LFSR >> 15) & 1;
383 m_LFSR |= (bit3 ^ bit12) ^ (bit14 ^ bit15);
387 sample += m_outSR & 1 ? 127 : -128;
392 sample = sample / reduc;
395 sample = sample *
volume() / 127;
412SamplesGenerator::SamplesGenerator(int8_t
const *
data,
int length)
431 int sample = m_data[m_index++];
433 if (m_index == m_length)
437 sample = sample *
volume() / 127;
455 : m_channels(nullptr),
458 m_sampleRate(sampleRate),
461 m_isr_handle(nullptr),
463 m_genMethod(genMethod),
465 m_timerHandle(nullptr)
470SoundGenerator::~SoundGenerator()
476 periph_module_disable(PERIPH_I2S0_MODULE);
477 esp_intr_free(m_isr_handle);
478 for (
int i = 0; i < 2; ++i)
479 heap_caps_free(m_sampleBuffer[i]);
480 heap_caps_free((
void*)m_DMAChain);
485 esp_timer_stop(m_timerHandle);
486 esp_timer_delete(m_timerHandle);
487 m_timerHandle =
nullptr;
490 #ifdef FABGL_EMULATED
491 SDL_CloseAudioDevice(m_device);
500 m_channels =
nullptr;
504void SoundGenerator::setDMANode(
int index,
volatile uint16_t * buf,
int len)
506 m_DMAChain[index].eof = 1;
507 m_DMAChain[index].sosf = 0;
508 m_DMAChain[index].owner = 1;
509 m_DMAChain[index].qe.stqe_next = (lldesc_t *) (m_DMAChain + index + 1);
510 m_DMAChain[index].offset = 0;
511 m_DMAChain[index].size = len *
sizeof(uint16_t);
512 m_DMAChain[index].length = len *
sizeof(uint16_t);
513 m_DMAChain[index].buf = (uint8_t*) buf;
517void SoundGenerator::dac_init()
519 m_DMAChain = (
volatile lldesc_t *) heap_caps_malloc(2 *
sizeof(lldesc_t), MALLOC_CAP_DMA);
521 for (
int i = 0; i < 2; ++i) {
522 m_sampleBuffer[i] = (uint16_t *) heap_caps_malloc(FABGL_SOUNDGEN_SAMPLE_BUFFER_SIZE *
sizeof(uint16_t), MALLOC_CAP_DMA);
523 for (
int j = 0; j < FABGL_SOUNDGEN_SAMPLE_BUFFER_SIZE; ++j)
524 m_sampleBuffer[i][j] = 0x7f00;
525 setDMANode(i, m_sampleBuffer[i], FABGL_SOUNDGEN_SAMPLE_BUFFER_SIZE);
527 m_DMAChain[1].sosf = 1;
528 m_DMAChain[1].qe.stqe_next = (lldesc_t *) m_DMAChain;
530 periph_module_enable(PERIPH_I2S0_MODULE);
533 I2S0.conf.tx_reset = 1;
534 I2S0.conf.tx_reset = 0;
537 I2S0.lc_conf.in_rst = 1;
538 I2S0.lc_conf.in_rst = 0;
541 I2S0.conf.rx_fifo_reset = 1;
542 I2S0.conf.rx_fifo_reset = 0;
544 I2S0.conf_chan.tx_chan_mod = (m_gpio == GPIO_NUM_25 ? 3 : 4);
546 I2S0.fifo_conf.tx_fifo_mod_force_en = 1;
547 I2S0.fifo_conf.tx_fifo_mod = 1;
548 I2S0.fifo_conf.dscr_en = 1;
550 I2S0.conf.tx_mono = 1;
551 I2S0.conf.tx_start = 0;
552 I2S0.conf.tx_msb_right = 1;
553 I2S0.conf.tx_right_first = 1;
554 I2S0.conf.tx_slave_mod = 0;
555 I2S0.conf.tx_short_sync = 0;
556 I2S0.conf.tx_msb_shift = 0;
558 I2S0.conf2.lcd_en = 1;
559 I2S0.conf2.camera_en = 0;
562 m_sampleRate = calcI2STimingParams(m_sampleRate, &a, &b, &num, &m);
563 I2S0.clkm_conf.clka_en = 0;
564 I2S0.clkm_conf.clkm_div_a = a;
565 I2S0.clkm_conf.clkm_div_b = b;
566 I2S0.clkm_conf.clkm_div_num = num;
567 I2S0.sample_rate_conf.tx_bck_div_num = m;
569 I2S0.sample_rate_conf.tx_bits_mod = 16;
571 if (m_isr_handle ==
nullptr) {
572 esp_intr_alloc_pinnedToCore(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, ISRHandler,
this, &m_isr_handle, CoreUsage::quietCore());
573 I2S0.int_clr.val = 0xFFFFFFFF;
574 I2S0.int_ena.out_eof = 1;
577 I2S0.out_link.addr = (uintptr_t) m_DMAChain;
578 I2S0.out_link.start = 1;
579 I2S0.conf.tx_start = 1;
582 dac_output_enable(m_gpio == GPIO_NUM_25 ? DAC_CHANNEL_1 : DAC_CHANNEL_2);
586void SoundGenerator::sigmadelta_init()
588 sigmadelta_config_t sigmadelta_cfg;
589 sigmadelta_cfg.channel = SIGMADELTA_CHANNEL_0;
590 sigmadelta_cfg.sigmadelta_prescale = 10;
591 sigmadelta_cfg.sigmadelta_duty = 0;
592 sigmadelta_cfg.sigmadelta_gpio = m_gpio;
593 sigmadelta_config(&sigmadelta_cfg);
595 esp_timer_create_args_t args = { };
596 args.callback = timerHandler;
598 args.dispatch_method = ESP_TIMER_TASK;
599 esp_timer_create(&args, &m_timerHandle);
604void SoundGenerator::sdl_init()
606 SDL_AudioSpec wantSpec, haveSpec;
608 wantSpec.freq = m_sampleRate;
609 wantSpec.format = AUDIO_U8;
610 wantSpec.channels = 1;
611 wantSpec.samples = 2048;
612 wantSpec.callback = SDLAudioCallback;
613 wantSpec.userdata =
this;
614 m_device = SDL_OpenAudioDevice(NULL, 0, &wantSpec, &haveSpec, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
615 m_sampleRate = haveSpec.freq;
620void SoundGenerator::init()
626 if (m_gpio == GPIO_AUTO)
635 #ifdef FABGL_EMULATED
646 if (value != m_play) {
650 I2S0.conf.tx_start = value;
653 esp_timer_start_periodic(m_timerHandle, 1000000 / m_sampleRate);
655 esp_timer_stop(m_timerHandle);
658 #ifdef FABGL_EMULATED
659 SDL_PauseAudioDevice(m_device, !value);
673 sgen->setAutoDestroy(
true);
675 sgen->setDuration(durationMS > 0 ? (m_sampleRate / 1000 * durationMS) : length );
686 bool isPlaying =
play(
false);
688 value->setSampleRate(m_sampleRate);
690 value->next = m_channels;
702 bool isPlaying =
play(
false);
703 detachNoSuspend(value);
710 for (
WaveformGenerator * c = m_channels, * prev =
nullptr; c; prev = c, c = c->next) {
713 prev->next = c->next;
715 m_channels = c->next;
716 if (value->autoDestroy())
724int IRAM_ATTR SoundGenerator::getSample()
726 int sample = 0, tvol = 0;
727 for (
auto g = m_channels; g; ) {
729 sample += g->getSample();
731 }
else if (g->duration() == 0 && g->autoDetach()) {
734 detachNoSuspend(curr);
740 int avol = tvol ? imin(127, 127 * 127 / tvol) : 127;
741 sample = sample * avol / 127;
742 sample = sample *
volume() / 127;
749void IRAM_ATTR SoundGenerator::ISRHandler(
void * arg)
751 if (I2S0.int_st.out_eof) {
754 auto desc = (
volatile lldesc_t*) I2S0.out_eof_des_addr;
756 auto buf = (uint16_t *) soundGenerator->m_sampleBuffer[desc->sosf];
758 for (
int i = 0; i < FABGL_SOUNDGEN_SAMPLE_BUFFER_SIZE; ++i)
759 buf[i ^ 1] = (soundGenerator->getSample() + 127) << 8;
762 I2S0.int_clr.val = I2S0.int_st.val;
767void SoundGenerator::timerHandler(
void * args)
771 sigmadelta_set_duty(SIGMADELTA_CHANNEL_0, soundGenerator->getSample());
776void SoundGenerator::SDLAudioCallback(
void *
data, Uint8 * buffer,
int length)
780 for (
int i = 0; i < length; ++i)
781 buffer[i] = soundGenerator->getSample() + 127;
int getSample()
Gets next sample.
void setFrequency(int value)
Sets output frequency.
void attach(WaveformGenerator *value)
Attaches a waveform generator.
void detach(WaveformGenerator *value)
Detaches a waveform generator.
SoundGenerator(int sampleRate=16384, gpio_num_t gpio=GPIO_AUTO, SoundGenMethod genMethod=SoundGenMethod::Auto)
Creates an instance of the sound generator. Only one instance is allowed.
int volume()
Determines current overall volume.
SamplesGenerator * playSamples(int8_t const *data, int length, int volume=100, int durationMS=0)
Plays the specified samples.
bool play(bool value)
Starts or stops playing.
void clear()
Stops playing and removes all attached waveform generators.
int getSample()
Gets next sample.
void setFrequency(int value)
Sets output frequency.
SoundGenMethod
Specifies sound generation method.
This file contains all classes related to FabGL Sound System.