Advertisement
honey_the_codewitch

m5core2_audio

Jul 20th, 2022
226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.79 KB | None | 0 0
  1. #include <m5core2_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 SAMPLE_RATE_INPUT     (44100)
  12. #define DMA_BUF_LEN     (32)
  13. #define DMA_BUF_LEN_INPUT     (32)
  14. #define DMA_NUM_BUF     (2)
  15. #define I2S_NUM         (0)
  16. #define TWOPI           (6.28318531f)
  17. static int m5core2_audio_init_mode = -1;
  18. static TaskHandle_t m5core2_audio_task;
  19. static QueueHandle_t m5core2_audio_queue;
  20. static m5core2_audio_record_callback m5core2_audio_record_fn;
  21. static void* m5core2_audio_record_state;
  22. static uint16_t m5core2_audio_out_buf[DMA_BUF_LEN];
  23. static uint16_t m5core2_audio_in_buf[DMA_BUF_LEN_INPUT];
  24. struct m5core2_audio_queue_message {
  25.     int cmd;
  26.     uint32_t data[2];
  27. };
  28. m5core2_audio_queue_message m5core2_audio_msg;
  29.  
  30. bool m5core2_audio_shape(unsigned shape,float frequency, float volume) {
  31.     struct start_data {
  32.         float frequency;
  33.         float volume;
  34.     };
  35.     if(shape>3) {
  36.         shape = 0;
  37.     }
  38.     start_data sd;
  39.     sd.frequency = frequency;
  40.     sd.volume = volume;
  41.     m5core2_audio_msg.cmd = shape+10;
  42.     memcpy(m5core2_audio_msg.data,&sd,sizeof(start_data));
  43.     if(m5core2_audio_queue!=nullptr) {
  44.         xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  45.         return true;
  46.     }
  47.     return false;
  48. }
  49. bool m5core2_audio_i2s_initialize(int mode) {
  50.     if(mode==m5core2_audio_init_mode) {
  51.         return true;
  52.     }
  53.    
  54.     if(m5core2_audio_init_mode!=0||mode==0) {
  55.         Serial.println("driver uninstalled");
  56.         i2s_driver_uninstall((i2s_port_t)I2S_NUM);
  57.     }
  58.     i2s_config_t i2s_config;
  59.     i2s_pin_config_t pins;
  60.     switch(mode) {
  61.         case 0:
  62.             break;
  63.         case 1: // output    
  64.             memset(&i2s_config,0,sizeof(i2s_config_t));
  65.             i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
  66.             i2s_config.sample_rate = SAMPLE_RATE;
  67.             i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
  68.             i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
  69.             i2s_config.communication_format = I2S_COMM_FORMAT_STAND_MSB;
  70.             i2s_config.dma_buf_count = DMA_NUM_BUF;
  71.             i2s_config.dma_buf_len = DMA_BUF_LEN;
  72.             i2s_config.use_apll = true;
  73.             i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2;
  74.             i2s_driver_install((i2s_port_t)I2S_NUM, &i2s_config, 0, NULL);
  75.             pins = {
  76.                 .mck_io_num = 0, // Unused
  77.                 .bck_io_num = 12,
  78.                 .ws_io_num = 0,
  79.                 .data_out_num = 2,
  80.                 .data_in_num = I2S_PIN_NO_CHANGE};
  81.             i2s_set_pin((i2s_port_t)I2S_NUM, &pins);
  82.  
  83.             break;
  84.         case 2: // input
  85.             memset(&i2s_config,0,sizeof(i2s_config_t));
  86.             i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
  87.             i2s_config.sample_rate = 64000;
  88.             i2s_config.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
  89.             i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
  90.             i2s_config.communication_format = I2S_COMM_FORMAT_STAND_I2S;
  91.             i2s_config.dma_buf_count = DMA_NUM_BUF;
  92.             i2s_config.dma_buf_len = DMA_BUF_LEN_INPUT;
  93.             i2s_config.use_apll = false;
  94.             i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1;
  95.             i2s_driver_install((i2s_port_t)I2S_NUM, &i2s_config, 0,  NULL);
  96.             pins = {
  97.                 .mck_io_num = 0, // Unused
  98.                 .bck_io_num = 12,
  99.                 .ws_io_num = 0,
  100.                 .data_out_num = 0,
  101.                 .data_in_num = 34};
  102.             i2s_set_pin((i2s_port_t)I2S_NUM, &pins);
  103.             break;
  104.     }
  105.     m5core2_audio_init_mode=mode;
  106.     return true;
  107. }
  108. void m5core2_audio_sin(m5core2_audio_queue_message& msg) {
  109.     struct sdata {
  110.         float frequency;
  111.         float volume;
  112.     };
  113.     // Accumulated phase
  114.     float p = 0.0f;
  115.     float p2 = 0.0f;
  116.    
  117.     float samp = 0.0f;
  118.     size_t bytes_written;
  119.     void* pv;
  120.     sdata s = *(sdata*)msg.data;
  121.     const float pdc = TWOPI*s.frequency/SAMPLE_RATE;
  122.     float pd = pdc;
  123.     size_t sz = sizeof(m5core2_audio_queue_message);
  124.    
  125.     while(!xQueueReceive(m5core2_audio_queue,&msg,0)) {
  126.        
  127.         for (int i=0; i < DMA_BUF_LEN; i++) {
  128.             // offset values by 1 and then scale to half since they can't be negative
  129.             float f;
  130.             switch(msg.cmd) {
  131.                 case 10:
  132.                     // sine wave  
  133.                     f = (sinf(p) + 1.0f) * 0.5f;
  134.                     break;
  135.                 case 11:
  136.                     // square wave
  137.                     // DOESN'T WORK
  138.                     f = p>PI;
  139.                     break;
  140.                 case 12:
  141.                     // saw wave
  142.                     f=(p2>=0.0);
  143.                     break;
  144.                 case 13:
  145.                     // triangle wave
  146.                     f=((p2/PI)+1.0)*.5;
  147.                     break;
  148.             }
  149.            
  150.            
  151.             // Increment and wrap phase
  152.             p += pdc;
  153.             if (p >= TWOPI) {
  154.                 p -= TWOPI;
  155.             }
  156.             if(p2+pd<=-PI || p2+pd>=PI) {
  157.                 pd=-pd;
  158.             }
  159.             p2+=pd;
  160.             // Scale to 16-bit integer range
  161.             samp = f* 65535.0f * s.volume;
  162.             m5core2_audio_out_buf[i] = (uint16_t)samp ;//<< 16;
  163.         }
  164.         // time critical
  165.         i2s_write((i2s_port_t)I2S_NUM, m5core2_audio_out_buf, sizeof(m5core2_audio_out_buf), &bytes_written, portMAX_DELAY);
  166.  
  167.         // You could put a taskYIELD() here to ensure other tasks always have a chance to run.
  168.         vTaskDelay(0);
  169.     }
  170.  
  171.     xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  172. }
  173. void m5core2_audio_rec() {
  174.     m5core2_audio_queue_message msg;
  175.     size_t read;
  176.     while(!xQueueReceive(m5core2_audio_queue,&msg,0)) {
  177.        
  178.         // time critical
  179.         i2s_read((i2s_port_t)I2S_NUM,m5core2_audio_in_buf,sizeof(m5core2_audio_in_buf),&read,portMAX_DELAY);
  180.         m5core2_audio_record_fn(m5core2_audio_in_buf,read,m5core2_audio_record_state);
  181.         // You could put a taskYIELD() here to ensure other tasks always have a chance to run.
  182.         vTaskDelay(0);
  183.     }
  184.  
  185.     xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  186. }
  187. void m5core2_audio_task_fn(void* state) {
  188.     m5core2_audio_queue_message msg;
  189.     msg.cmd = 0;
  190.     size_t sz;
  191.     void *pv;
  192. m5core2_audio_task_fn_restart:
  193.     if(m5core2_audio_queue!=nullptr) {
  194.         sz = sizeof(m5core2_audio_queue_message);
  195.         if(xQueueReceive(m5core2_audio_queue,&msg,portMAX_DELAY)) {
  196.             switch(msg.cmd) {
  197.                 case 0:
  198.                     goto m5core2_audio_task_fn_restart;
  199.                 case 1:
  200.                     i2s_zero_dma_buffer((i2s_port_t)I2S_NUM);
  201.                     goto m5core2_audio_task_fn_restart;
  202.                 case 3:
  203.                     m5core2_audio_rec();
  204.                 default:
  205.                     m5core2_audio_sin(msg);
  206.                     break;
  207.                    
  208.                    
  209.             }
  210.         }
  211.     }
  212.     vTaskDelay(0);
  213.     goto m5core2_audio_task_fn_restart;
  214. }
  215. bool m5core2_audio::initialized() const {
  216.     return m5core2_audio_init_mode;
  217. }
  218. bool m5core2_audio::initialize() {
  219.     if(m5core2_audio_init_mode==-1) {
  220.         m5core2_audio_queue = xQueueCreate(1,sizeof(m5core2_audio_queue_message));
  221.         // m5core2_audio_msg is global
  222.         if(m5core2_audio_queue == nullptr) {
  223.        
  224.             return false;
  225.         }
  226.        
  227.         // Highest possible priority for realtime audio task
  228.         xTaskCreate(m5core2_audio_task_fn, "m5core2_audio", 1024*4, nullptr, configMAX_PRIORITIES - 1,&m5core2_audio_task);
  229.        
  230.         m5core2_audio_msg.cmd = 0;
  231.         m5core2_audio_init_mode = 0;
  232.         xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  233.        
  234.     }
  235.     return true;
  236. }
  237.  
  238. bool m5core2_audio::stop() {
  239.     m5core2_audio_msg.cmd = 1;
  240.     if(m5core2_audio_queue!=nullptr) {
  241.         xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  242.         return true;
  243.     }
  244.     return false;
  245. }
  246. bool m5core2_audio::sinw(float frequency,float volume = 1.0) {
  247.     if(m5core2_audio_init_mode!=1) {
  248.         m5core2_audio_i2s_initialize(1);
  249.     }
  250.     return m5core2_audio_shape(0,frequency,volume);
  251. }
  252. bool m5core2_audio::triw(float frequency,float volume = 1.0) {
  253.     if(m5core2_audio_init_mode!=1) {
  254.         m5core2_audio_i2s_initialize(1);
  255.     }
  256.     return m5core2_audio_shape(3,frequency,volume);
  257. }
  258.  
  259. /*bool m5core2_audio::sqrw(float frequency,float volume = 1.0) {
  260.     return m5core2_audio_shape(1,frequency,volume);
  261. }*/
  262. bool m5core2_audio::saww(float frequency,float volume = 1.0) {
  263.     if(m5core2_audio_init_mode!=1) {
  264.         m5core2_audio_i2s_initialize(1);
  265.     }
  266.     return m5core2_audio_shape(2,frequency,volume);
  267. }
  268. bool m5core2_audio::start_recording(m5core2_audio_record_callback callback,void* state=nullptr) {
  269.     if(callback==nullptr || m5core2_audio_queue==nullptr) {
  270.         return false;
  271.     }
  272.     if(m5core2_audio_init_mode==2) {
  273.         if(!stop_recording()) {
  274.             return false;
  275.         }
  276.     } else {
  277.         m5core2_audio_i2s_initialize(2);
  278.     }
  279.     m5core2_audio_record_fn = callback;
  280.     m5core2_audio_record_state = state;
  281.     m5core2_audio_msg.cmd = 3;
  282.     xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  283.     return true;
  284. }
  285. bool m5core2_audio::stop_recording() {
  286.     m5core2_audio_msg.cmd = 0;
  287.     if(m5core2_audio_queue!=nullptr) {
  288.         xQueueSend(m5core2_audio_queue,&m5core2_audio_msg,portMAX_DELAY);
  289.         return true;
  290.     }
  291.     return false;
  292. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement