2018年9月9日日曜日

SONY SPRESENSEでハイレゾを再生する

SPRESENSEは、Arduino IDEのスケッチを使ってハイレゾ音源を再生できます。7/31発売当時のドキュメントは分量はとても多いのですが、とても不親切な書き方で、プログラム(ライブラリのC++のソース)を読んで自分で使い方を考えろ的な姿勢が強く出ていました。9/1ごろにArduino 1.0.2になって、ドキュメントも普通の表現になりました。
 メイン・ボード本体にD級アンプが搭載されていますが、デフォルトの出力であるヘッドホン端子は、出力にでっかいCを入れなくて済むという何やらわからない性能のヘッドホン・アンプがつながっています。
 ヘッドホン・アンプの手前にあるD級アンプ出力は、レベルの下げるための470Ωの抵抗がシリーズに入っています。内蔵のボリュームを最大値の0dBにしてもスピーカからはかすかな音しか出ません。
 解説によると、470Ωと小容量のコンデンサのパーツをLと大きめのCに変更することで、スピーカから音が出ます。しかし、たぶん、無理な作業です。電動のはんだ取り器を使えば、八つのパーツを安全に取り出せますが、新しいCをはんだ付けするのは、ほとんど不可能です。10セットあったら1セットぐらい成功するかもしれません。



 ポータブル機器にスピーカを接続する際、出力にローパス・フィルタを入れる設計が多いです。しかし、普通のスピーカ・ケーブルを数mのばして普通のスピーカをつなげるとき、フィルタは現実的には不要と考えられます。
 という根拠の薄い理由で、470Ωを0Ωにするだけで済ませます。
 はんだゴテの先をきれいにし、はんだをちょっとだけつけ、フラックスが飛びきらないうちに、チップ抵抗のはんだ面(もちろん上面)にはんだをわずかに盛ります。0.3mm程度のはんだメッキ線を押し付けて抵抗をショートします。

 推定500mW弱のアンプだと思います。96dBを超えるスピーカなら、オーケストラも十分再生できます。
 9/1ごろの更新で、ハイレゾは192kHz/24ビットだけと書かれました。48kHz/24ビットも再生できますが96kHzは再生できません。
(2018/10)1.1.0になって96kHzが対応しました。ただ、スピーカからの音がとても小さくなって実用上聞こえなくなりました。私のだけかも

 playerのスケッチの変更点です。再生するwavファイルはAUDIOフォルダの中に入れておきます。

theAudio->setRenderingClockMode(AS_CLKMODE_HIRES);

theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_192000,AS_BITLENGTH_24,AS_CHANNEL_STEREO);
myFile = theSD.open("AUDIO/192.wav");
効率90dB以下のスピーカならば、ボリュームは0でOKです。 爆音は出ません。ボリューム値を読み込んで音量を変更できますが、あんまり役に立っていません。


 で、一番重要な音ですが、最上の音楽が聴けますです。

SDメモリの音源を四つまで連続に再生するスケッチ
 SDメモリに入っている音源を全部再生できるはずなのですが、5曲目からは再生できないです。
 音源は192kHz/24ビット決め打ちにしてあります。
 ボリュームは、A0端子の電圧を読み取って値を決めています。ボリュームを付けないときは、-100とかの値を入れておいてください。

/*
    player.ino - Simple sound player example application
    Copyright 2018 Sony Semiconductor Solutions Corporation

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <Audio.h>
AudioClass *theAudio;
File myFile;
//#include <SDHCI.h>
SDClass SD;
#define  volumePin  A0
int volumeValue = 0;

/**
   @brief Setup audio player to play mp3 file

   Set output device to speaker <br>
   Set main player to decode stereo mp3. Stream sample rate is set to "auto detect" <br>
   System directory "/mnt/sd0/BIN" will be searched for MP3 decoder (MP3DEC file)
   Open "Sound.mp3" file <br>
   Set master volume to -16.0 dB
*/
void setup() {
  Serial.begin(115200);
  // start audio system
  theAudio = AudioClass::getInstance();
  theAudio->begin();
  Serial.println("initialization Audio Library");
    /* Set output device to speaker */
    theAudio->setRenderingClockMode(AS_CLKMODE_HIRES);
    theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_SPHP);//AS_SETPLAYER_OUTPUTDEVICE_I2SOUTPUT
     //theAudio->setPlayerMode(AS_SETPLAYER_OUTPUTDEVICE_I2SOUTPUT);
                 /*
                 * Set main player to decode stereo mp3. Stream sample rate is set to "auto detect"
                 * Search for MP3 decoder in " / mnt / sd0 / BIN" directory
                 */
     err_t err = theAudio->initPlayer(AudioClass::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_192000, AS_BITLENGTH_24,AS_CHANNEL_STEREO);
  Serial.println("setup AS_SAMPLINGRATE_192000");
                 /* Verify player initialize */
    if (err != AUDIOLIB_ECODE_OK) {
      printf("Player0 initialize error\n");
      exit(1);
  }
}

void loop() {
  Serial.println("---LOOP-start -------------------------------------");
  File root = SD.open("/AUDIO");
  while (true)  { // files pickup
  /* Open file placed on SD card */
        File entry = root.openNextFile();

    if (!entry) {
//      Serial.println("**nomorefiles**");
    }
 
  Serial.println("opened " + String( (entry.name())) );
  myFile = SD.open(entry.name());
   /* Verify file open */
  if (!myFile) {
     printf("File open error\n");
    exit(1);
  }
  printf("Open! % d\n",myFile);

  /* Send first frames to be decoded */
  int err = theAudio->writeFrames(AudioClass::Player0, myFile);
  if (err != AUDIOLIB_ECODE_OK) {
    printf("File Read Error! = % d\n",err);
    myFile.close();
    exit(1);
  }

  /* Main volume set to -16.0 dB */
  volumeValue = analogRead(volumePin) / 4 ;
    printf("Volume = % d\n",volumeValue);
    theAudio->setVolume(-1*(250-volumeValue));
  theAudio->startPlayer(AudioClass::Player0);

  Serial.print("Play!!!!!!!!!!!!\n");

while (1) {  // until read fifo? end
  /* Send new frames to decode in a loop until file ends */
  err = theAudio->writeFrames(AudioClass::Player0, myFile);
/*  Tell when player file ends */
  if (err == AUDIOLIB_ECODE_FILEEND) {
      printf("Main player File End!\n");
  }
/* Show error code from player and stop */
  if (err) {
//      printf("Main player error code: % d\n", err);
      goto stop_player;
  }
  usleep(30000);
  /* Don't go further and continue play */
 continue;

stop_player:
  delay(1);
      theAudio->stopPlayer(AudioClass::Player0);
      myFile.close();
//      exit(1);
        break;
}
  }
delay(100);
}