GithubHelp home page GithubHelp logo

sh123 / esp32_codec2_arduino Goto Github PK

View Code? Open in Web Editor NEW
18.0 3.0 2.0 1.92 MB

Codec2 low bit rate audio codec Arduino library for ESP32

License: GNU General Public License v3.0

C 100.00%
arduino codec2 esp32 hamradio freedv espressif dv codec digital-voice hf

esp32_codec2_arduino's Introduction

ESP32 Codec2 Arduino Library

This is latest version of Codec2 library packaged for ESP32 Arduino usage.

For more information about Codec2 visit https://github.com/drowe67/codec2

esp32_codec2_arduino's People

Contributors

sh123 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

esp32_codec2_arduino's Issues

Frame splitting in 2s_lora_walkie_talkie example

Hi!

Could you please explain this code part in i2s_lora_walkie_talkie example?

// split by frame, decode and play
        for (int i = 0; i < packet_size; i++) {
          c2_bits_[i % c2_bytes_per_frame_] = lora_radio_rx_queue_.shift();
          if (i % c2_bytes_per_frame_ == c2_bytes_per_frame_ - 1) {
            codec2_decode(c2_, c2_samples_, c2_bits_);
            i2s_write(I2S_NUM_0, c2_samples_, sizeof(uint16_t) * c2_samples_per_frame_, &bytes_written, portMAX_DELAY);
            vTaskDelay(1);

I experimenting with this code and notased that it return every 3-d byte from codec2 queue (450 mode), but we need every byte. Or not? This works fine, but why?

At bottom my extended example of loopback codec2 with packaging by 48 bytes and read back again. Please run it for detail understanding.

Based on this algorithm its possible to add a half-duplex repeater function to loraDV radio...

#include <driver/i2s.h>
#include <codec2.h>
#include <CircularBuffer.h> 

// serial
#define SERIAL_BAUD_RATE      115200

// audio speaker
#define AUDIO_SPEAKER_BCLK    26
#define AUDIO_SPEAKER_LRC     25
#define AUDIO_SPEAKER_DIN     22

// audio microphone
#define AUDIO_MIC_SD          27
#define AUDIO_MIC_WS          14
#define AUDIO_MIC_SCK         13

#define AUDIO_SAMPLE_RATE     8000  // 44100



#define QUEUE_LEN    512   
CircularBuffer<uint8_t, QUEUE_LEN> tx_rx_queue_; 
CircularBuffer<uint8_t, QUEUE_LEN> tx_rx_queue_index_;


TaskHandle_t audio_task_;
struct CODEC2* c2_;
int c2_samples_per_frame_;
int c2_bytes_per_frame_;
int16_t *c2_samples_;
uint8_t *c2_bits_;

void setup() {

  Serial.begin(SERIAL_BAUD_RATE);
  while (!Serial);
  Serial.println(F("Board setup started"));

  // create i2s speaker
  i2s_config_t i2s_speaker_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
    .sample_rate = AUDIO_SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = 1024,
    .use_apll=0,
    .tx_desc_auto_clear= true, 
    .fixed_mclk=-1    
  };
  i2s_pin_config_t i2s_speaker_pin_config = {
    .bck_io_num = AUDIO_SPEAKER_BCLK,
    .ws_io_num = AUDIO_SPEAKER_LRC,
    .data_out_num = AUDIO_SPEAKER_DIN,
    .data_in_num = I2S_PIN_NO_CHANGE
  };
  if (i2s_driver_install(I2S_NUM_0, &i2s_speaker_config, 0, NULL) != ESP_OK) {
    Serial.println(F("Failed to install i2s speaker driver"));
  }
  if (i2s_set_pin(I2S_NUM_0, &i2s_speaker_pin_config) != ESP_OK) {
    Serial.println(F("Failed to set i2s speaker pins"));
  }

  // create i2s microphone
  i2s_config_t i2s_mic_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
    .sample_rate = AUDIO_SAMPLE_RATE,
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
    .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
    .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
    .dma_buf_count = 8,
    .dma_buf_len = 1024,
    .use_apll=0,
    .tx_desc_auto_clear= true,
    .fixed_mclk=-1
  };
  i2s_pin_config_t i2s_mic_pin_config = {
    .bck_io_num = AUDIO_MIC_SCK,
    .ws_io_num = AUDIO_MIC_WS,
    .data_out_num = I2S_PIN_NO_CHANGE,
    .data_in_num = AUDIO_MIC_SD
  };
  if (i2s_driver_install(I2S_NUM_1, &i2s_mic_config, 0, NULL) != ESP_OK) {
    Serial.println(F("Failed to install i2s mic driver"));   
  }
  if (i2s_set_pin(I2S_NUM_1, &i2s_mic_pin_config) != ESP_OK) {
    Serial.println(F("Failed to set i2s mic pins"));
  }

  // run codec2 audio loopback on a separate task
  xTaskCreate(&audio_task, "audio_task", 32000, NULL, 5, &audio_task_);

  Serial.println(F("Board setup completed"));
}

void audio_task(void *param) {
  // construct and configure codec2
  c2_ = codec2_create(CODEC2_MODE_3200);
  if (c2_ == NULL) {
    Serial.println(F("Failed to create Codec2"));
    return;
  } else {
    //codec2_set_lpc_post_filter(c2_, 1, 0, 0.8, 0.2);
    c2_samples_per_frame_ = codec2_samples_per_frame(c2_);
    c2_bytes_per_frame_ = codec2_bytes_per_frame(c2_);
    c2_samples_ = (int16_t*)malloc(sizeof(int16_t) * c2_samples_per_frame_);
    c2_bits_ = (uint8_t*)malloc(sizeof(uint8_t) * c2_bytes_per_frame_);
    Serial.println(F("Codec2 constructed"));
    Serial.print(F("Semples per frame-"));
    Serial.println(c2_samples_per_frame_);
    Serial.print(F("Bytes per frame-"));
    Serial.println(c2_bytes_per_frame_);
  }

  // run loopback record-encode-decode-playback loop
  size_t bytes_read, bytes_written;
  int packet_size = 0; 
  Serial.println(F("Audio task started"));
  while(true) {
      if (tx_rx_queue_index_.size() != 0) { // Then the mark of 48 bytes exsist in index queue
        int packet_size_rx = tx_rx_queue_index_.shift(); // take the mark of 48 bytes is present in frames queue
        Serial.println(F("Packet Recived"));
        // devided by frames and play 
        for (int i = 0; i < packet_size_rx; i++) { // ??? HOW ITS WORK ???
         c2_bits_[i % c2_bytes_per_frame_] = tx_rx_queue_.shift(); // ??? HOW ITS WORK ???
          if (i % c2_bytes_per_frame_ == c2_bytes_per_frame_ - 1) { // ??? HOW ITS WORK ???
            codec2_decode(c2_, c2_samples_, c2_bits_); 
            i2s_write(I2S_NUM_0, c2_samples_, sizeof(uint16_t) * c2_samples_per_frame_, &bytes_written, portMAX_DELAY);
            Serial.print(F("RX byte - "));
            Serial.println(*c2_bits_);
            vTaskDelay(1); 
          } // Why we have extract every 8-th byte from bytes queue? Why? ??? HOW ITS WORK ???
        } // All 48 bytes extracted from queue and played
         Serial.println(F("Packet Played"));
     } // Played all 48 bytes of queue
      else {
        // If enoth bytes - 48 - we can decodd
        if (packet_size + c2_bytes_per_frame_ > 48) { 
           tx_rx_queue_index_.push(packet_size); // push to queue what we have 48 bytes of packet for decodd by codec2  
           packet_size = 0; // we have sended 48 bytes packet and start to accumulate new 48 bytes packet
           Serial.println(F("Packet Done"));
           }
        // read and codding one frame
        size_t bytes_read; 
        i2s_read(I2S_NUM_1, c2_samples_, sizeof(uint16_t) * c2_samples_per_frame_, &bytes_read, portMAX_DELAY); // read I2S sending semples to codec2
        codec2_encode(c2_, c2_bits_, c2_samples_); // codding semples - return one byte to another
        for (int n = 0; n < c2_bytes_per_frame_; n++) {
          tx_rx_queue_.push(c2_bits_[n]); // push to circular bufer n byte, n+1 byte, n+2 byte, and etc.
          Serial.print(F("TX byte - "));
          Serial.println(*c2_bits_);
         }
        packet_size += c2_bytes_per_frame_; // +3 add to packet size each frame coded (for 450 Codec2 mode, + 8 for 3200 mode)
          Serial.print(F("Packet size cumulative - "));
          Serial.println(packet_size);

        vTaskDelay(1);
      }
      
  }

}

void loop() {
  delay(100);
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.