查看: 1719|回复: 0

M5Stack Fire的录音使用

[复制链接]

该用户从未签到

发表于 2020-7-18 14:57 | 显示全部楼层 |阅读模式
       单通道录音,使用硬件定时器与中断进行采样,通过DAC进行播放
  1. #include <M5Stack.h>
  2. #include <atomic> /* https://baptiste-wicht.com/posts/2012/07/c11-concurrency-tutorial-part-4-atomic-type.html */

  3. #define MICROPHONE 34
  4. #define SPEAKER 25
  5. #define BACKLIGHT 32
  6. #define BUFFER_SIZE 4*1000*1000
  7. #define SAMPLING_FREQUENCY 48000

  8. #define LOWNOISE true /* set to false to enable backlight dimming */

  9. TFT_eSPI tft = TFT_eSPI();

  10. // set log level to debug for output
  11. void logMemory() {
  12. log_d("Used PSRAM: %d from: %d", ESP.getPsramSize() - ESP.getFreePsram(), ESP.getPsramSize() );
  13. }

  14. int8_t* sampleBuffer;
  15. uint32_t allocatedSamples;
  16. std::atomic<std::uint32_t> currentSample{0};
  17. static hw_timer_t * sampleTimer{NULL}; /* only one timer is (re)used for both sampling and playback */
  18. unsigned int sampling_period_us = round( 1000000 * ( 1.0 / SAMPLING_FREQUENCY ) );

  19. static void IRAM_ATTR _sampleISR() {
  20. uint32_t pos = currentSample.load();
  21. if ( pos > BUFFER_SIZE - 1 ) {
  22. timerEnd( sampleTimer );
  23. sampleTimer = NULL;
  24. return;
  25. }
  26. sampleBuffer[pos] = analogRead( MICROPHONE ) >> 4;
  27. currentSample++;
  28. }

  29. bool startSampler() {
  30. if ( NULL != sampleTimer ) return false;
  31. delay(170); /* to not record the click from releasing the button */
  32. currentSample.store( 0, std::memory_order_relaxed );
  33. sampleTimer = timerBegin( 0, 80, true );
  34. timerAttachInterrupt( sampleTimer, &_sampleISR, true );
  35. timerAlarmWrite( sampleTimer, sampling_period_us, true );
  36. timerAlarmEnable( sampleTimer );
  37. return true;
  38. }

  39. void setup() {
  40. pinMode( MICROPHONE, INPUT );
  41. pinMode( SPEAKER, OUTPUT );
  42. logMemory();

  43. tft.init();
  44. tft.setRotation( 1 );
  45. tft.fillScreen( TFT_BLACK );
  46. tft.setTextSize( 2 );
  47. tft.drawString( "M5-Stack voicerecorder", 10, 5, 2 );

  48. if ( LOWNOISE ) {
  49. pinMode( BACKLIGHT, OUTPUT );
  50. digitalWrite( BACKLIGHT, HIGH ); // This gives the least noise
  51. } else {
  52. ledcAttachPin( BACKLIGHT, 0);
  53. ledcSetup( 0, 1300, 16 );
  54. ledcWrite( 0, 0xFFFF / 16 ); // Dimming the BACKLIGHT will produce more base noise
  55. }

  56. if ( !ESP.getPsramSize() ) {
  57. tft.setCursor( 55, 40 );
  58. tft.print( "NO PSRAM FOUND!" );
  59. while ( 1 ) delay( 100 );
  60. }


  61. sampleBuffer = (int8_t*)ps_malloc( BUFFER_SIZE * sizeof( int8_t ) );

  62. tft.setCursor( 15, 40 );
  63. tft.printf( "%3.1fkHz %5.1fkB %6.2fs", SAMPLING_FREQUENCY / 1000.0, ( BUFFER_SIZE * sizeof( int8_t ) ) / 1000.0, BUFFER_SIZE / (float)SAMPLING_FREQUENCY );
  64. tft.drawString( "REC", 45, 200, 2 );
  65. tft.drawString( "PLAY", 130, 200, 2 );
  66. tft.drawString( "STOP", 220, 200, 2 );
  67. }

  68. void loop() {
  69. M5.update();
  70. if ( !sampleTimer && M5.BtnA.pressedFor( 5 ) ) startSampler();
  71. if ( !sampleTimer && M5.BtnB.pressedFor( 5 ) ) startPlayback();
  72. uint32_t pos = currentSample.load();
  73. tft.setCursor( 85, 100 );
  74. tft.printf( "%3i%% %6.2fs", map( pos, 0, BUFFER_SIZE - 1, 0, 100 ), pos / (float)SAMPLING_FREQUENCY );
  75. tft.setCursor( 60, 130 );
  76. tft.printf( " %7i/%7i", pos, BUFFER_SIZE );
  77. if ( sampleTimer && M5.BtnC.pressedFor( 2 ) ) {
  78. timerAlarmDisable( sampleTimer );
  79. timerEnd( sampleTimer );
  80. sampleTimer = NULL;
  81. dacWrite( SPEAKER, 0 );
  82. }
  83. delay(10);
  84. }

  85. void IRAM_ATTR _playThroughDAC_ISR() {
  86. uint32_t pos = currentSample.load();
  87. if ( pos > BUFFER_SIZE - 1 ) {
  88. timerEnd( sampleTimer );
  89. sampleTimer = NULL;
  90. dacWrite( SPEAKER, 0 );
  91. return;
  92. }
  93. dacWrite( SPEAKER, sampleBuffer[pos] );
  94. currentSample++;
  95. }

  96. bool startPlayback() {
  97. if ( NULL != sampleTimer ) return false;
  98. currentSample.store( 0, std::memory_order_relaxed );
  99. sampleTimer = timerBegin( 0, 80, true );
  100. timerAttachInterrupt( sampleTimer, &_playThroughDAC_ISR, true );
  101. timerAlarmWrite( sampleTimer, sampling_period_us, true );
  102. timerAlarmEnable( sampleTimer );
  103. return true;
  104. }
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

arduino程序设计基础 blinker物联网解决方案

热门推荐

【教程】pico+hx711电子秤
【教程】pico+hx711电子秤
pico+hx711电子秤 【前言】 我做过多款电子秤,这次移植到pico上
ESP8266+Onenet平台远程数据传输和控制
ESP8266+Onenet平台远程数
这是我的第一个diy,主要功能实现了onenet云平台温湿度数据的传输和远程控制LED灯平台
【Arduino】108种传感器模块系列实验(48)---三轴ADXL345模块
【Arduino】108种传感器模
37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是
ps2遥控小车——uno实现
ps2遥控小车——uno实现
前几天在阁楼发现了好久以前3d打印,激光切割的底盘,于是决定做这个东西 正好手上又
震惊!OLED菜单竟只用10行代码就可以完成到完美!!!
震惊!OLED菜单竟只用10行
震惊!OLED菜单竟只用10行代码就可
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表