フォト
2019年10月
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
無料ブログはココログ

« VS1053 MP3 プレーヤー・シールドでMIDIファイルの再生 | トップページ | おもちゃ「ちっちゃなミーニャ」の修理 »

2019年1月11日 (金)

VS1053 MP3 プレーヤー・シールドの調査 (2) 録音機能

今回はVS1053 MP3 プレーヤー・シールド の録音機能の調査です。

先日利用したライブラリを調べると、録音機能に関するAPIが存在しません。
Wikiにも解説がありません。

このボード、ピン構成やElecrowWiki リンク先を見ると、
SparkFun MP3 Player Shield がベースとなっているようです。

ベースのボードには録音機能(コンデンサーマイク、マイク端子)が無いんですよね。
それで、録音機能については何も解説が無いようです。

  商品  SparkFun MP3 Player Shield  (チュートリアル MP3 Player Shield Hookup Guide V15
  01
  (チュートリアルのMP3 Player Shield Hookup Guide V15 はこれはこれで参考になります)
 

う~ん、困った..
色々と調べると、
VS1053の公式フォーラム(VSDSP Forum)を見るとAdafruitのボード用の
ライブラリ(Adafruit_VS1053_Library)を使うと録画が出来ると判明しました。

  参考: AdafruitのVS1053ボード
  VS1053 Codec + MicroSD Breakout - MP3/WAV/MIDI/OGG Play + Record - v4

 
02
 
チュートリアル Adafruit VS1053 MP3/AAC/Ogg/MIDI/WAV Codec Breakout Tutorial


録音機能の実装


前置きが長くなりましたが、本題の録音機能について試してみました。
Ogg Vorbisという形式にてSDカード上にファイルとして録音します。

まずは、ボード上のコンデンサーマイクを使った録音のお試しです。

Adafruitのチュートリアルを参考にして、Adafruit_VS1053_Library をダウンロードし、
サンプルスケッチのrecode_ogg を動かしてみました。

  05

そのままでは動かないので次の修正を行いました。
  1)利用するピンの変更(=>スケッチの変更)
  2)SDライブラリの利用からSdFatライブラリの利用に変更(=>スケッチ、ライブラリの変更)
  3)VS1053 ogg encoder プラグインの変更(=>スケッチの変更)

VS1053用プラグインのダウンロード

Adafruit_VS1053_Library
のサンプルスケッチ recode_ogg のフォルダに
モノラル 44.1KHz, 高品質録音のプラグイン v44k1q05.img が用意されているのですが、
Arduinoの処理が間に合わず、音飛び発生や、ファイルが壊れて再生出来ずでした。

そこで、別のプラグインを利用しました。
公式サイト(VLSI社) には、別のプラグインが公開されてます。
用途に応じて選択して利用することが出来ます。下記のリンクからダウンロードできます。

  ・VS1053 Ogg Vorbis Encoder Application
    http://www.vlsi.fi/fileadmin/software/VS10XX/vs1053-vorbis-encoder-170c.zip

解凍したフォルダprofilesの中の vencXXkYqZZ.img がプラグインです。
下記の組み合わせで複数用意されています。
  XX: サンプリング周波数 08: 8kHz、16:16kHz、44:44kHz、
  Y:   1:モノラル、2:ステレオ
  ZZ: 品質00~05 or 10 数字が大きいほど高品質

試した感じでは、44kHzでは、ステレオ録音は処理が追いつきません。
  44kHzでは モノラル venc44k1q04.img
  16kHzでは モノラル venc16k1q10.img 、ステレオ venc16k2q5.img
がちょうど良い感じでした。

ここでは、venc44k1q04.img  を v44k1q04.img にファイル名を変更して
SDカードのルートフォルダにコピーします。

ライブラリの修正


Sdfat対応のために、ヘッダーファイル Adafruit_VS1053.hに PREFER_SDFAT_LIBRARY の定義を追加します。

#define ADAFRUIT_VS1053_Hの次の行に追加しました。
  #ifndef ADAFRUIT_VS1053_H
  #define ADAFRUIT_VS1053_H
  #define PREFER_SDFAT_LIBRARY


スケッチの
修正

ピン割り付けを変更しています。録音開始のボタンはD3を使いました。
/*************************************************** 
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// This is a very beta demo of Ogg Vorbis recording. It works...
// Connect a button to digital 7 on the Arduino and use that to
// start and stop recording.

// A mic or line-in connection is required. See page 13 of the 
// datasheet for wiring

// Don't forget to copy the v44k1q05.img patch to your micro SD 
// card before running this example!


// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
// SDライブラリからSdFatライブラリの利用に変更 by たま吉さん
//#include <SD.h>
#include "SdFat.h"
SdFat SD;

// ピン割り付けの変更 by たま吉さん
// define the pins used
//#define RESET 9      // VS1053 reset pin (output)
//#define CS 10        // VS1053 chip select pin (output)
//#define DCS 8        // VS1053 Data/command select pin (output)
//#define CARDCS A0     // Card chip select pin
//#define DREQ A1       // VS1053 Data request, ideally an Interrupt pin

#define RESET 8      // VS1053 reset pin (output)
#define CS 6         // VS1053 chip select pin (output)
#define DCS 7        // VS1053 Data/command select pin (output)
#define CARDCS 9     // Card chip select pin
#define DREQ 2       // VS1053 Data request, ideally an Interrupt pin

//#define REC_BUTTON 7
#define REC_BUTTON 3

Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(RESET, CS, DCS, DREQ, CARDCS);

File recording;  // the file we will save our recording to
#define RECBUFFSIZE 128  // 64 or 128 bytes.
uint8_t recording_buffer[RECBUFFSIZE];

void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit VS1053 Ogg Recording Test");

  // initialise the music player
  if (!musicPlayer.begin()) {
    Serial.println("VS1053 not found");
    while (1);  // don't do anything more
  }

  musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working
 
  if (!SD.begin(CARDCS)) {
    Serial.println("SD failed, or not present");
    while (1);  // don't do anything more
  }
  Serial.println("SD OK!");
  
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(10,10);
  
  // when the button is pressed, record!
  pinMode(REC_BUTTON, INPUT);
  digitalWrite(REC_BUTTON, HIGH);
  
  // load plugin from SD card! We'll use mono 44.1KHz, high quality
  // プラグインの変更 by たま吉さん (mono 44.1KHz, middle quality)
  //  if (! musicPlayer.prepareRecordOgg("v44k1q05.img")) {
  if (! musicPlayer.prepareRecordOgg("v44k1q04.img")) {
     Serial.println("Couldn't load plugin!");
     while (1);    
  }
}

uint8_t isRecording = false;

void loop() {  
  if (!isRecording && !digitalRead(REC_BUTTON)) {
    Serial.println("Begin recording");
    isRecording = true;
    
    // Check if the file exists already
    char filename[15];
    strcpy(filename, "RECORD00.OGG");
    for (uint8_t i = 0; i < 100; i++) {
      filename[6] = '0' + i/10;
      filename[7] = '0' + i%10;
      // create if does not exist, do not open existing, write, sync after write
      if (! SD.exists(filename)) {
        break;
      }
    }
    Serial.print("Recording to "); Serial.println(filename);
    recording = SD.open(filename, FILE_WRITE);
    if (! recording) {
       Serial.println("Couldn't open file to record!");
       while (1);
    }
    musicPlayer.startRecordOgg(true); // use microphone (for linein, pass in 'false')
  }
  if (isRecording)
    saveRecordedData(isRecording);
  if (isRecording && !digitalRead(REC_BUTTON)) {
    Serial.println("End recording");
    musicPlayer.stopRecordOgg();
    isRecording = false;
    // flush all the data!
    saveRecordedData(isRecording);
    // close it up
    recording.close();
    delay(1000);
  }
}

uint16_t saveRecordedData(boolean isrecord) {
  uint16_t written = 0;
  
    // read how many words are waiting for us
  uint16_t wordswaiting = musicPlayer.recordedWordsWaiting();
  
  // try to process 256 words (512 bytes) at a time, for best speed
  while (wordswaiting > 256) {
    //Serial.print("Waiting: "); Serial.println(wordswaiting);
    // for example 128 bytes x 4 loops = 512 bytes
    for (int x=0; x < 512/RECBUFFSIZE; x++) {
      // fill the buffer!
      for (uint16_t addr=0; addr < RECBUFFSIZE; addr+=2) {
        uint16_t t = musicPlayer.recordedReadWord();
        //Serial.println(t, HEX);
        recording_buffer[addr] = t >> 8; 
        recording_buffer[addr+1] = t;
      }
      if (! recording.write(recording_buffer, RECBUFFSIZE)) {
            Serial.print("Couldn't write "); Serial.println(RECBUFFSIZE); 
            while (1);
      }
    }
    // flush 512 bytes at a time
    recording.flush();
    written += 256;
    wordswaiting -= 256;
  }
  
  wordswaiting = musicPlayer.recordedWordsWaiting();
  if (!isrecord) {
    Serial.print(wordswaiting); Serial.println(" remaining");
    // wrapping up the recording!
    uint16_t addr = 0;
    for (int x=0; x < wordswaiting-1; x++) {
      // fill the buffer!
      uint16_t t = musicPlayer.recordedReadWord();
      recording_buffer[addr] = t >> 8; 
      recording_buffer[addr+1] = t;
      if (addr > RECBUFFSIZE) {
          if (! recording.write(recording_buffer, RECBUFFSIZE)) {
                Serial.println("Couldn't write!");
                while (1);
          }
          recording.flush();
          addr = 0;
      }
    }
    if (addr != 0) {
      if (!recording.write(recording_buffer, addr)) {
        Serial.println("Couldn't write!"); while (1);
      }
      written += addr;
    }
    musicPlayer.sciRead(VS1053_SCI_AICTRL3);
    if (! (musicPlayer.sciRead(VS1053_SCI_AICTRL3) & _BV(2))) {
       recording.write(musicPlayer.recordedReadWord() & 0xFF);
       written++;
    }
    recording.flush();
  }

  return written;
}

ボタンを押すと録音開始、再度押して録音終了です。
(ボタン操作がちょっとシビアで、瞬間的に押さないと開始・終了を繰り返します)

動作状況は、シリアルコンソールで確認できます。

04

試してみた感じでは、一応は録音できました。
oggファイルの再生は、ブラウザのChromeにドラッグ&ドロップして再生しました。

ただし、現時点では
  ・音が小さい
  ・音質が今一
でした。

もうちょっとどうにかならないか、調べてみます。


« VS1053 MP3 プレーヤー・シールドでMIDIファイルの再生 | トップページ | おもちゃ「ちっちゃなミーニャ」の修理 »

arduino」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: VS1053 MP3 プレーヤー・シールドの調査 (2) 録音機能:

« VS1053 MP3 プレーヤー・シールドでMIDIファイルの再生 | トップページ | おもちゃ「ちっちゃなミーニャ」の修理 »