Skip to content

Instantly share code, notes, and snippets.

@boochow
Last active December 25, 2019 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boochow/e4774a028a29c56d7c60e3c3afa5d6f9 to your computer and use it in GitHub Desktop.
Save boochow/e4774a028a29c56d7c60e3c3afa5d6f9 to your computer and use it in GitHub Desktop.
#include "audio_provider.h"
#include "micro_features/micro_model_settings.h"
#include <Arduino.h>
#include <M5Stack.h>
#include <driver/i2s.h>
#define ADC_INPUT ADC1_CHANNEL_6 //pin 34, for M5Stack Fire
#define PIN_MICROPHONE 34
#define ADC_OFFSET (ADC_INPUT * 0x1000 + 0xFFF)
#define BACKLIGHT 32
#define SAMPLING_FREQ 16000
#define BUFFER_SIZE 512
void CaptureSamples();
namespace {
bool g_is_audio_initialized = false;
constexpr int kAudioCaptureBufferSize = BUFFER_SIZE * 16;
int16_t g_audio_capture_buffer[kAudioCaptureBufferSize];
int16_t g_audio_output_buffer[kMaxAudioSampleSize];
volatile int32_t g_latest_audio_timestamp = 0;
volatile int16_t recording_buffer[BUFFER_SIZE];
volatile int max_audio = -32768, min_audio = 32768;
} // namespace
#define PIN_I2S_CLK 12
#define PIN_I2S_WS 13
#define PIN_I2S_DIN 34
#define PIN_I2S_DOUT 15
void InitI2S()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
.sample_rate = SAMPLING_FREQ, // The format of the signal using ADC_BUILT_IN
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_ALL_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 20,
.dma_buf_len = 32,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0
};
i2s_pin_config_t pin_config;
pin_config.bck_io_num = PIN_I2S_CLK;
pin_config.ws_io_num = PIN_I2S_WS;
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
pin_config.data_in_num = PIN_I2S_DIN;
adc1_config_channel_atten(ADC_INPUT, ADC_ATTEN_0db);
adc1_config_width(ADC_WIDTH_12Bit);
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, SAMPLING_FREQ, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
i2s_adc_enable(I2S_NUM_0);
}
void AudioRecordingTask(void *pvParameters) {
static uint16_t audio_idx = 0;
size_t bytes_read;
uint16_t i2s_data;
int16_t sample;
while(1){
if (audio_idx >= BUFFER_SIZE) {
CaptureSamples();
max_audio = -32768, min_audio = 32768;
audio_idx = 0;
}
i2s_read(I2S_NUM_0, &i2s_data, 2, &bytes_read, portMAX_DELAY );
if (bytes_read > 0) {
sample = ADC_OFFSET - i2s_data - 2047;
sample = sample << 4;
recording_buffer[audio_idx] = sample;
if (max_audio < sample) {
max_audio = sample;
}
//max_audio = max(max_audio, sample);
min_audio = min(min_audio, sample);
audio_idx++;
}
}
}
void CaptureSamples() {
const int number_of_samples = BUFFER_SIZE;
const int32_t time_in_ms =
g_latest_audio_timestamp +
(number_of_samples / (kAudioSampleFrequency / 1000));
const int32_t start_sample_offset =
g_latest_audio_timestamp * (kAudioSampleFrequency / 1000);
const int capture_index = start_sample_offset % kAudioCaptureBufferSize;
memcpy(g_audio_capture_buffer + capture_index, (void *)recording_buffer, BUFFER_SIZE*2);
g_latest_audio_timestamp = time_in_ms;
}
TfLiteStatus InitAudioRecording(tflite::ErrorReporter* error_reporter) {
Serial.begin(115200);
Serial.println("init audio"); delay(10);
pinMode( BACKLIGHT, OUTPUT );
digitalWrite( BACKLIGHT, HIGH ); // This gives the least noise
InitI2S();
xTaskCreatePinnedToCore(AudioRecordingTask, "AudioRecordingTask", 2048, NULL, 1, NULL, 1);
// Block until we have our first audio sample
while (!g_latest_audio_timestamp) {
delay(1);
}
return kTfLiteOk;
}
TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter,
int start_ms, int duration_ms,
int* audio_samples_size, int16_t** audio_samples) {
if (!g_is_audio_initialized) {
TfLiteStatus init_status = InitAudioRecording(error_reporter);
if (init_status != kTfLiteOk) {
return init_status;
}
g_is_audio_initialized = true;
}
const int start_offset = start_ms * (kAudioSampleFrequency / 1000);
const int duration_sample_count =
duration_ms * (kAudioSampleFrequency / 1000);
for (int i = 0; i < duration_sample_count; ++i) {
const int capture_index = (start_offset + i) % kAudioCaptureBufferSize;
g_audio_output_buffer[i] = g_audio_capture_buffer[capture_index];
}
*audio_samples_size = kMaxAudioSampleSize;
*audio_samples = g_audio_output_buffer;
return kTfLiteOk;
}
int32_t LatestAudioTimestamp() { return g_latest_audio_timestamp; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment