Using KNN to realize Voise Control

Dependencies:   mbed-os-lychee

main.cpp

Committer:
jianger_88
Date:
2020-02-07
Revision:
1:2fa6911afef3
Parent:
0:61014bfdf244

File content as of revision 1:2fa6911afef3:

#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)

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

AUDIO_GRBoard audio(0x80, AUDIO_OUT_BUF_NUM - 1, AUDIO_IN_BUF_NUM); // I2S Codec
int led_rec;
int led_play;
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 KNN(char *file_name, int dat_size)
{
    double *cal_dat;
    double *com_dat;
    int record;
    int NUM_LIB=119;
    int class_num;
    double knn=10000000000;
    double temp=0;
    com_dat=(double*)malloc(sizeof(double)*dat_size);
    
    FILE *input_res,*compare_res;
    char *lib_name;
    input_res=fopen(file_name,"rb");
    for(int i=0;i<dat_size;i++)
    {
        fscanf(input_res,"lf",&cal_dat[i]);
    }
    fclose(input_res);
    
    for(int i=0;i<NUM_LIB;i++)
    {
        temp=0;
        sprintf(lib_name,"sample%03d.dat",i);
        compare_res=fopen(lib_name,"w");
        for(int i=0;i<dat_size;i++){
            fscanf(compare_res,"lf",&com_dat[i]);
        }
        for(int i=0;i<dat_size;i++)
        {
            temp+=pow((cal_dat[i]-com_dat[i]),2);
        }
        if (temp<knn)
        {
            knn=temp;
            record=i;
        }
    }
    if(0<record||record<=25||115<record||record<=119)
    //output is bird
    {
    class_num=1;
    led1=!led1;
                        }
    //output is monkey
    else if(25<record||record<=54)
    {
    class_num=2;
    led2=!led2;}
    //output is cat
    else if(54<record||record<=85||record==115)
    {
    class_num=3;
    led3=!led3;
                        }
    //output is dog
    else if(85<record||record<=114)
    {class_num=4;
     led4=!led4;
                        }

}



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() {
    
int count=0;

#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;
#if(0)
            //KNN(FINE_PATH,);
            char test_name[32];
            sprintf(test_name,"/"MOUNT_NAME"/sample%03d.dat",count++);
            FILE *test_lib=fopen(test_name,"w");
             fseek(test_lib, 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, test_lib);
            fclose(test_name);
#else
            led_play = 1;
            FILE * fp_rb = fopen(FINE_PATH, "rb");

            char test_name[32];
 //           sprintf(test_name,"/"MOUNT_NAME"/sample%03d.dat",count++);
            sprintf(test_name,"/"MOUNT_NAME"/recogniaze.dat");
            FILE *test_lib=fopen(test_name,"w");


            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);

                   fwrite(audio_out_buf[index], sizeof(char), read_size, test_lib);
                   

                    
                    index++;
                    if (index >= AUDIO_OUT_BUF_NUM) {
                        index = 0;
                    }
                }
                fclose(fp_rb);
                fclose(test_lib);
                KNN("/"MOUNT_NAME"/recogniaze.dat",5000);
               
 //               Thread::wait(AUDIO_OUT_WAIT);
            }
            led_play = 0;
#endif
        }
        Thread::wait(100);
              

    }
}