Sample program for audio recording and playback.

Dependencies:   mbed-os-lychee

Files at this revision

API Documentation at this revision

Comitter:
dkato
Date:
Thu Apr 19 09:29:26 2018 +0000
Commit message:
first commit

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-gr-libs.lib Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 61014bfdf244 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Apr 19 09:29:26 2018 +0000
@@ -0,0 +1,309 @@
+#include "mbed.h"
+#include "SdUsbConnect.h"
+#include "AUDIO_GRBoard.h"
+
+#define MOUNT_NAME             "storage"
+#define FINE_PATH              "/"MOUNT_NAME"/wav_rec.wav"
+
+#define SAMPLE_RATE            (8000)
+#define AUDIO_IN_BUF_SIZE      (2048)
+#define AUDIO_IN_BUF_NUM       (16)
+#define AUDIO_OUT_BUF_SIZE     (2048)
+#define AUDIO_OUT_BUF_NUM      (8)
+#define AUDIO_OUT_WAIT         ((AUDIO_OUT_BUF_SIZE * AUDIO_OUT_BUF_NUM / 4) * 1000 / SAMPLE_RATE)
+
+#define INFO_TYPE_OPEN         (0)
+#define INFO_TYPE_CLOSE        (1)
+#define INFO_TYPE_WRITE_DATA   (2)
+
+AUDIO_GRBoard audio(0x80, AUDIO_OUT_BUF_NUM - 1, AUDIO_IN_BUF_NUM); // I2S Codec
+DigitalOut  led_rec(LED_RED);
+DigitalOut  led_play(LED_GREEN);
+InterruptIn button_0(USER_BUTTON0);
+#if defined(TARGET_GR_LYCHEE)
+InterruptIn button_1(USER_BUTTON1);
+#endif
+static bool play_req = false;
+
+typedef struct {
+    uint32_t info_type;
+    void *   p_data;
+    int32_t  result;
+} mail_t;
+Mail<mail_t, (AUDIO_IN_BUF_NUM + 2)> mail_box;
+
+static Thread audioInTask(osPriorityNormal, 1024 * 8);
+//4 bytes aligned! No cache memory
+#if defined(__ICCARM__)
+#pragma data_alignment=4
+static uint8_t audio_in_buf[AUDIO_IN_BUF_NUM][AUDIO_IN_BUF_SIZE]@ ".mirrorram";
+#pragma data_alignment=4
+static uint8_t audio_out_buf[AUDIO_OUT_BUF_NUM][AUDIO_OUT_BUF_SIZE]@ ".mirrorram";
+#else
+static uint8_t audio_in_buf[AUDIO_IN_BUF_NUM][AUDIO_IN_BUF_SIZE]__attribute((section("NC_BSS"),aligned(4)));
+static uint8_t audio_out_buf[AUDIO_OUT_BUF_NUM][AUDIO_OUT_BUF_SIZE]__attribute((section("NC_BSS"),aligned(4)));
+#endif
+
+// wav file header
+static const char wav_header_tbl[] = {
+    0x52,0x49,0x46,0x46,0x00,0x00,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,
+    0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00,
+    0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x00
+};
+
+#if MBED_CONF_APP_LCD
+#include "EasyAttach_CameraAndLCD.h"
+
+#define FRAME_BUFFER_STRIDE    (((LCD_PIXEL_WIDTH * 2) + 31u) & ~31u)
+#define FRAME_BUFFER_HEIGHT    (LCD_PIXEL_HEIGHT)
+#if defined(__ICCARM__)
+#pragma data_alignment=32
+static uint8_t user_frame_buffer0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]@ ".mirrorram";
+#else
+static uint8_t user_frame_buffer0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((section("NC_BSS"),aligned(32)));
+#endif
+DisplayBase Display;
+
+static void Start_LCD_Display(void) {
+    DisplayBase::rect_t rect;
+
+    memset(user_frame_buffer0, 0xFF, sizeof(user_frame_buffer0));
+
+    rect.vs = 0;
+    rect.vw = LCD_PIXEL_HEIGHT;
+    rect.hs = 0;
+    rect.hw = LCD_PIXEL_WIDTH;
+    Display.Graphics_Read_Setting(
+        DisplayBase::GRAPHICS_LAYER_0,
+        (void *)user_frame_buffer0,
+        FRAME_BUFFER_STRIDE,
+        DisplayBase::GRAPHICS_FORMAT_RGB565,
+        DisplayBase::WR_RD_WRSWA_32_16BIT,
+        &rect
+    );
+    Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_0);
+
+    Thread::wait(50);
+    EasyAttach_LcdBacklight(true);
+}
+
+static void disp_audio_wave(int16_t * p_data, int32_t size, uint32_t color) {
+    uint16_t * p_bottom_left_pos = (uint16_t *)&user_frame_buffer0[FRAME_BUFFER_STRIDE * (FRAME_BUFFER_HEIGHT - 1)];
+    uint16_t * p_frame_buf;
+    uint32_t x = 0;
+    uint32_t data_pos;
+    uint32_t data_pos_last = ((p_data[0] + 0x8000ul) >> 8) + 8;
+    int loop_num;
+
+    if (size < 0) {
+        return;
+    }
+
+    memset(user_frame_buffer0, 0xFF, sizeof(user_frame_buffer0));
+    for (int i = 0; i < size; i += 2) {
+        data_pos = ((p_data[i] + 0x8000ul) >> 8) + 8;
+        p_frame_buf = &p_bottom_left_pos[x];
+
+        if (data_pos == data_pos_last) {
+            loop_num = 3;
+            p_frame_buf -= ((data_pos - 1) * LCD_PIXEL_WIDTH);
+        } else if (data_pos > data_pos_last) {
+            loop_num = data_pos - data_pos_last + 2;
+            p_frame_buf -= (data_pos_last * LCD_PIXEL_WIDTH);
+        } else {
+            loop_num = data_pos_last - data_pos + 2;
+            p_frame_buf -= ((data_pos - 1) * LCD_PIXEL_WIDTH);
+        }
+
+        for (int j = 0; j < loop_num; j++) {
+            *p_frame_buf = color;
+            p_frame_buf -= LCD_PIXEL_WIDTH;
+        }
+        data_pos_last = data_pos;
+
+        x++;
+        if (x >= LCD_PIXEL_WIDTH) {
+            break;
+        }
+    }
+}
+
+static void callback_audio_write_end(void * p_data, int32_t result, void * p_app_data) {
+    disp_audio_wave((int16_t *)p_data, result / 2, 0x07E0); // Green
+}
+#endif // MBED_CONF_APP_LCD
+
+static void send_mail(uint32_t info_type, void * p_data, int32_t result) {
+    mail_t *mail = mail_box.alloc();
+
+    if (mail != NULL) {
+        mail->info_type = info_type;
+        mail->p_data    = p_data;
+        mail->result    = result;
+        mail_box.put(mail);
+    }
+}
+
+static void rec_start(void) {
+    send_mail(INFO_TYPE_OPEN, NULL, 0);
+}
+
+static void rec_stop(void) {
+    send_mail(INFO_TYPE_CLOSE, NULL, 0);
+}
+
+static void play_start(void) {
+    play_req = true;
+}
+
+static void callback_audio_read_end(void * p_data, int32_t result, void * p_app_data) {
+#if MBED_CONF_APP_LCD
+    if (led_play == 0) {
+        uint32_t color;
+
+        if (led_rec == 0) {
+            color = 0x001F; // Blue
+        } else {
+            color = 0xF800; // Red
+        }
+        disp_audio_wave((int16_t *)p_data, result / 2, color);
+    }
+#endif
+    send_mail(INFO_TYPE_WRITE_DATA, p_data, result);
+}
+
+static void wire_data_4byte(uint32_t data, FILE * fp) {
+    char work_buf[4];
+
+    work_buf[0] = (uint8_t)(data >> 0);
+    work_buf[1] = (uint8_t)(data >> 8);
+    work_buf[2] = (uint8_t)(data >> 16);
+    work_buf[3] = (uint8_t)(data >> 24);
+    fwrite(work_buf, sizeof(char), 4, fp);
+}
+
+void audio_in_task(void) {
+    FILE * wav_fp = NULL;
+    uint32_t pcm_size = 0;
+    rbsp_data_conf_t audio_read_data  = {&callback_audio_read_end, NULL};
+
+    // Read buffer setting
+    for (uint32_t i = 0; i < AUDIO_IN_BUF_NUM; i++) {
+        if (audio.read(audio_in_buf[i], AUDIO_IN_BUF_SIZE, &audio_read_data) < 0) {
+            printf("read error\n");
+        }
+    }
+
+    while (1) {
+        osEvent evt = mail_box.get();
+        if (evt.status == osEventMail) {
+            mail_t *mail = (mail_t *)evt.value.p;
+
+            switch (mail->info_type) {
+                case INFO_TYPE_OPEN:
+                    wav_fp = fopen(FINE_PATH, "wb");
+                    if (wav_fp != NULL) {
+                        led_rec  = 1;  // REC start
+                        pcm_size = 0;
+                        fwrite(wav_header_tbl, sizeof(char), sizeof(wav_header_tbl), wav_fp);
+                    }
+                    break;
+
+                case INFO_TYPE_CLOSE:
+                    if (wav_fp != NULL) {
+                        // Set "RIFF" ChunkSize
+                        fseek(wav_fp, 4, SEEK_SET);
+                        wire_data_4byte(sizeof(wav_header_tbl) - 8 + pcm_size, wav_fp);
+                        // Set SampleRate
+                        fseek(wav_fp, 24, SEEK_SET);
+                        wire_data_4byte(SAMPLE_RATE, wav_fp);
+                        // Set ByteRate
+                        wire_data_4byte(SAMPLE_RATE * 2 * 2, wav_fp);
+                        // Set "data" ChunkSize
+                        fseek(wav_fp, 40, SEEK_SET);
+                        wire_data_4byte(pcm_size, wav_fp);
+                        fclose(wav_fp);
+                        wav_fp = NULL;
+                        led_rec = 0;  // REC end
+#if !defined(TARGET_GR_LYCHEE)
+                        play_start();
+#endif
+                    }
+                    break;
+
+                case INFO_TYPE_WRITE_DATA:
+                    if ((mail->result > 0) && (wav_fp != NULL)) {
+                        pcm_size += mail->result;
+                        fwrite(mail->p_data, sizeof(char), mail->result, wav_fp);
+                    }
+                    audio.read(mail->p_data, AUDIO_IN_BUF_SIZE, &audio_read_data);     // Resetting read buffer
+                    break;
+
+                default:
+                    // do nothing
+                    break;
+            }
+            mail_box.free(mail);
+        }
+    }
+}
+
+int main() {
+#if MBED_CONF_APP_LCD
+    rbsp_data_conf_t audio_write_data = {&callback_audio_write_end, NULL};
+
+    EasyAttach_Init(Display);
+    Start_LCD_Display();
+#else
+    rbsp_data_conf_t audio_write_data = {NULL, NULL};
+#endif
+
+    // Microphone
+    audio.micVolume(0.50);
+    audio.outputVolume(0.50, 0.50);
+    audio.power(true);
+    audio.frequency(SAMPLE_RATE);
+
+    SdUsbConnect storage(MOUNT_NAME);
+    audioInTask.start(callback(audio_in_task));
+
+    // button setting
+    button_0.fall(&rec_start);
+    button_0.rise(&rec_stop);
+#if defined(TARGET_GR_LYCHEE)
+    button_1.fall(&play_start);
+#endif
+
+    while (1) {
+        storage.wait_connect();
+
+        // Audio playback
+        if (play_req != false) {
+            while (led_rec == 1) {
+                Thread::wait(10); // Wait write end
+            }
+
+            size_t read_size = AUDIO_OUT_BUF_SIZE;
+            uint32_t index = 0;
+
+            play_req = false;
+            led_play = 1;
+            FILE * fp_rb = fopen(FINE_PATH, "rb");
+            if (fp_rb != NULL) {
+                fseek(fp_rb, sizeof(wav_header_tbl), SEEK_SET);
+                while (read_size == AUDIO_OUT_BUF_SIZE) {
+                    read_size = fread(audio_out_buf[index], sizeof(char), AUDIO_OUT_BUF_SIZE, fp_rb);
+                    audio.write(audio_out_buf[index], read_size, &audio_write_data);
+                    index++;
+                    if (index >= AUDIO_OUT_BUF_NUM) {
+                        index = 0;
+                    }
+                }
+                fclose(fp_rb);
+                Thread::wait(AUDIO_OUT_WAIT);
+            }
+            led_play = 0;
+        }
+        Thread::wait(100);
+    }
+}
diff -r 000000000000 -r 61014bfdf244 mbed-gr-libs.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-gr-libs.lib	Thu Apr 19 09:29:26 2018 +0000
@@ -0,0 +1,1 @@
+https://github.com/d-kato/mbed-gr-libs/#ab3c9adbc449c4ac541ca38ebee8dd7a4f87ddb8
diff -r 000000000000 -r 61014bfdf244 mbed-os.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os.lib	Thu Apr 19 09:29:26 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/dkato/code/mbed-os-lychee/#f782d9c66c49
diff -r 000000000000 -r 61014bfdf244 mbed_app.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Thu Apr 19 09:29:26 2018 +0000
@@ -0,0 +1,20 @@
+{
+    "config": {
+        "camera":{
+            "help": "0:disable 1:enable",
+            "value": "0"
+        },
+        "lcd":{
+            "help": "0:disable 1:enable",
+            "value": "1"
+        },
+        "usb-host-ch":{
+            "help": "(for GR-PEACH) 0:ch0 1:ch1",
+            "value": "1"
+        },
+        "audio-camera-shield":{
+            "help": "(for GR-PEACH) 0:not use 1:use",
+            "value": "1"
+        }
+    }
+}