Advertisement
honey_the_codewitch

m5 fire audio, partial

Jul 20th, 2022
428
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.03 KB | None | 0 0
  1. #include <m5fire_audio.hpp>
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "driver/i2s.h"
  5. #include "driver/gpio.h"
  6. #include "esp_system.h"
  7. #include "esp_log.h"
  8. #include <math.h>
  9. #include <string.h>
  10. #define SAMPLE_RATE     (44100)
  11. #define DMA_BUF_LEN     (32)
  12. #define DMA_NUM_BUF     (2)
  13. #define I2S_NUM         (0)
  14. #define WAVE_FREQ_HZ    (440.0f)
  15. #define TWOPI           (6.28318531f)
  16. static bool m5fire_audio_initialized = false;
  17. static TaskHandle_t m5fire_audio_task;
  18. static QueueHandle_t m5fire_audio_queue;
  19. static uint16_t m5fire_audio_out_buf[DMA_BUF_LEN];
  20. struct m5fire_audio_queue_message {
  21.     int cmd;
  22.     uint32_t data[2];
  23. };
  24. m5fire_audio_queue_message m5fire_audio_msg;
  25.  
  26. void m5fire_audio_sin(m5fire_audio_queue_message& msg) {
  27.     struct sdata {
  28.         float frequency;
  29.         float volume;
  30.     };
  31.     // Accumulated phase
  32.     float p = 0.0f;
  33.     float samp = 0.0f;
  34.     size_t bytes_written;
  35.     void* pv;
  36.     sdata s = *(sdata*)msg.data;
  37.     size_t sz = sizeof(m5fire_audio_queue_message);
  38.    
  39.     while(!xQueueReceive(m5fire_audio_queue,&msg,0)) {
  40.        
  41.         for (int i=0; i < DMA_BUF_LEN; i++) {
  42.             // Scale sine sample to 0-1 for internal DAC
  43.             // (can't output negative voltage)
  44.             float f;
  45.             switch(msg.cmd) {
  46.                 case 2:
  47.                     // sine wave  
  48.                     f = (sinf(p) + 1.0f) * 0.5f;
  49.                     break;
  50.                 case 3:
  51.                     // square wave
  52.                     // DOESN'T WORK
  53.                     f = p>PI;
  54.                     break;
  55.                 case 4:
  56.                     // triangle wave
  57.                     f=(p/TWO_PI);
  58.                     break;
  59.             }
  60.            
  61.            
  62.             // Increment and wrap phase
  63.             p += TWOPI * s.frequency / SAMPLE_RATE;
  64.             if (p >= TWOPI)
  65.                 p -= TWOPI;
  66.            
  67.             // Scale to 16-bit integer range
  68.             samp = f* 255.0f * s.volume;
  69.  
  70.             // Shift to MSB of 16-bit int for internal DAC
  71.             m5fire_audio_out_buf[i] = (uint16_t)samp << 8;
  72.         }
  73.         // Write with max delay. We want to push buffers as fast as we
  74.         // can into DMA memory. If DMA memory isn't transmitted yet this
  75.         // will yield the task until the interrupt fires when DMA buffer has
  76.         // space again. If we aren't keeping up with the real-time deadline,
  77.         // audio will glitch and the task will completely consume the CPU,
  78.         // not allowing any task switching interrupts to be processed.
  79.         i2s_write((i2s_port_t)I2S_NUM, m5fire_audio_out_buf, sizeof(m5fire_audio_out_buf), &bytes_written, portMAX_DELAY);
  80.  
  81.         // You could put a taskYIELD() here to ensure other tasks always have a chance to run.
  82.         vTaskDelay(1);
  83.     }
  84.    
  85.     /*if(m5fire_audio_msg.cmd==2) {
  86.         i2s_zero_dma_buffer((i2s_port_t)I2S_NUM);
  87.     }*/
  88.     xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  89. }
  90. void m5fire_audio_task_fn(void* state) {
  91.     m5fire_audio_queue_message msg;
  92.     msg.cmd = 0;
  93.     size_t sz;
  94.     void *pv;
  95. m5fire_audio_task_fn_restart:
  96.     if(m5fire_audio_queue!=nullptr) {
  97.         sz = sizeof(m5fire_audio_queue_message);
  98.         if(xQueueReceive(m5fire_audio_queue,&msg,portMAX_DELAY)) {
  99.             switch(msg.cmd) {
  100.                 case 0:
  101.                     goto m5fire_audio_task_fn_restart;
  102.                 case 1:
  103.                     i2s_zero_dma_buffer((i2s_port_t)I2S_NUM);
  104.                     goto m5fire_audio_task_fn_restart;
  105.                 default:
  106.                     m5fire_audio_sin(msg);
  107.                     break;
  108.                    
  109.                    
  110.             }
  111.         }
  112.     }
  113.     vTaskDelay(1);
  114.     goto m5fire_audio_task_fn_restart;
  115. }
  116. bool m5fire_audio::initialized() const {
  117.     return m5fire_audio_initialized;
  118. }
  119. bool m5fire_audio::initialize() {
  120.     if(!m5fire_audio_initialized) {
  121.         i2s_config_t i2s_config;
  122.         memset(&i2s_config,0,sizeof(i2s_config_t));
  123.         i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN );
  124.         i2s_config.sample_rate = SAMPLE_RATE;
  125.         i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
  126.         i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
  127.         i2s_config.communication_format = I2S_COMM_FORMAT_STAND_MSB;
  128.         i2s_config.dma_buf_count = DMA_NUM_BUF;
  129.         i2s_config.dma_buf_len = DMA_BUF_LEN;
  130.         i2s_config.use_apll = true;
  131.         i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2;
  132.         i2s_driver_install((i2s_port_t)I2S_NUM, &i2s_config, 0, NULL);
  133.         i2s_set_pin((i2s_port_t)I2S_NUM, NULL);
  134.         m5fire_audio_queue = xQueueCreate(1,sizeof(m5fire_audio_queue_message));
  135.         // m5fire_audio_msg is global
  136.         if(m5fire_audio_queue == nullptr) {
  137.        
  138.             return false;
  139.         }
  140.        
  141.         // Highest possible priority for realtime audio task
  142.         xTaskCreate(m5fire_audio_task_fn, "m5fire_audio", 1024, nullptr, configMAX_PRIORITIES - 1,&m5fire_audio_task);
  143.        
  144.         m5fire_audio_msg.cmd = 0;
  145.         m5fire_audio_initialized = true;
  146.         xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  147.        
  148.     }
  149.     return true;
  150. }
  151.  
  152. bool m5fire_audio::stop() {
  153.     m5fire_audio_msg.cmd = 1;
  154.     if(m5fire_audio_queue!=nullptr) {
  155.         xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  156.         return true;
  157.     }
  158.     return false;
  159. }
  160. bool m5fire_audio::sinw(float frequency,float volume = 1.0) {
  161.     if(volume==0.0) {
  162.         return true;
  163.     }
  164.     struct start_data {
  165.         float frequency;
  166.         float volume;
  167.     } ;
  168.     start_data sd;
  169.     sd.frequency = frequency;
  170.     sd.volume = volume;
  171.     m5fire_audio_msg.cmd = 2;
  172.     memcpy(m5fire_audio_msg.data,&sd,sizeof(start_data));
  173.     if(m5fire_audio_queue!=nullptr) {
  174.         xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  175.         return true;
  176.     }
  177.     return false;
  178. }
  179. /*bool m5fire_audio::sqrw(float frequency,float volume = 1.0) {
  180.     if(volume==0.0) {
  181.         return true;
  182.     }
  183.     struct start_data {
  184.         float frequency;
  185.         float volume;
  186.     } ;
  187.     start_data sd;
  188.     sd.frequency = frequency;
  189.     sd.volume = volume;
  190.     m5fire_audio_msg.cmd = 3;
  191.     memcpy(m5fire_audio_msg.data,&sd,sizeof(start_data));
  192.     if(m5fire_audio_queue!=nullptr) {
  193.         xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  194.         return true;
  195.     }
  196.     return false;
  197. }*/
  198. bool m5fire_audio::triw(float frequency,float volume = 1.0) {
  199.     if(volume==0.0) {
  200.         return true;
  201.     }
  202.     struct start_data {
  203.         float frequency;
  204.         float volume;
  205.     } ;
  206.     start_data sd;
  207.     sd.frequency = frequency;
  208.     sd.volume = volume;
  209.     m5fire_audio_msg.cmd = 4;
  210.     memcpy(m5fire_audio_msg.data,&sd,sizeof(start_data));
  211.     if(m5fire_audio_queue!=nullptr) {
  212.         xQueueSend(m5fire_audio_queue,&m5fire_audio_msg,portMAX_DELAY);
  213.         return true;
  214.     }
  215.     return false;
  216. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement