SSブログ

四月の電子工作「SPRESENSEでデジタルエフェクターを作ろう!」ーSPRESENSEアンプ編ー [SPRESENSE]

四月は案の定忙しく、結局5月に割り込んでしまいました。前回、プリアンプの動作をブレッドボードで確認できましたので、今回は基板に収めることにしました。思ったよりも小さなユニバーサル基板に収めることができました。


プリアンプ.png


前回との変更点が一点あります。前回、電源をデジタル電源3.3Vを利用しましたが、使用したオペアンプは1Vから動作可能ということに気づいたので、マイクバイアス電源(2V)を使うことにしました。これでマイク端子だけでエレキギターの音を取り込めます。


マイク入力.png


実装してSPRESENSEに装着をしてみました。プリアンプらしくボリュームはマイク入力へのレベル調整のためにつけています。これによってデジタル処理ではないですがオーバードライブが可能になります。


DSC02138.JPG



■ プリアンプの動作を確認する
何もせずにバイアス電源をあたってみると、なんと0V。あれ?ここって2V出てるんじゃなかったっけ?と思って慌てたのですが、サンプルのレコーダーアプリをインストールしてみたら、2Vが出力されていました。さすが省電力を意識した設計になっています。

プリアンプにギタープラグを入れて、マイク入力の波形をオシロスコープであたってみました。無事にアンプ出力が出ていることが確認できました。


プリアンプ出力.jpg


■ SPRESENSEでエレキギターの音を出す
ハードウェアの準備は全てできましたので、いよいよソフトウェアの出番です。ギターの音をそのままスルーで出力するようにプログラミングします。なるべく遅延が小さくなるようにフレームはできるだけ小さくしてみました。


#include <MediaRecorder.h>
#include <MediaPlayer.h>
#include <OutputMixer.h>
#include <MemoryUtil.h>

MediaRecorder *theRecorder;
MediaPlayer *thePlayer;
OutputMixer *theMixer;

const int32_t s_buffer_size = 4096*sizeof(int16_t);
uint8_t s_buffer[s_buffer_size];
uint8_t out_buffer[s_buffer_size];
int request_size = 128 * sizeof(int16_t);
int read_size;

/* callback functions */
static void attention_callback(const ErrorAttentionParam *atprm) {}

static bool mediarecorder_event_callback(AsRecorderEvent event, uint32_t result, uint32_t sub_result) {
  return true;
}

static void outputmixer_event_callback(MsgQueId requester_dtq, MsgType reply_of, AsOutputMixDoneParam *done_param) { }

static void outmixer_rendering_callback(int32_t identifier, bool is_end) {
  AsRequestNextParam next;
  next.type = (!is_end) ? AsNextNormalRequest : AsNextStopResRequest;
  AS_RequestNextPlayerProcess(AS_PLAYER_ID_0, &next);
  return;
}

static bool mediaplayer_event_callback(AsPlayerEvent event, uint32_t result, uint32_t sub_result) {
  return true;
}

void mediaplayer_decode_callback(AsPcmDataParam pcm_param) {
  theMixer->sendData(OutputMixer0, outmixer_rendering_callback, pcm_param);
}

/* setup function from here */
void setup() {
  initMemoryPools();
  createStaticPools(MEM_LAYOUT_RECORDINGPLAYER);

  Serial.println("Init Audio Library");
  theRecorder = MediaRecorder::getInstance();
  thePlayer = MediaPlayer::getInstance();
  theMixer  = OutputMixer::getInstance();

  theRecorder->begin();
  thePlayer->begin();

  Serial.println("initialization MediaRecorder, MediaPlayer and OutputMixer");
  theMixer->activateBaseband();

  thePlayer->create(MediaPlayer::Player0, attention_callback);
  theMixer->create(attention_callback);

  theRecorder->activate(AS_SETRECDR_STS_INPUTDEVICE_MIC, mediarecorder_event_callback);
  thePlayer->activate(MediaPlayer::Player0, AS_SETPLAYER_OUTPUTDEVICE_SPHP, mediaplayer_event_callback);
  theMixer->activate(OutputMixer0, outputmixer_event_callback);

  usleep(100000);
  
  Serial.println("Initialize Recorder");
  theRecorder->init(AS_CODECTYPE_LPCM, AS_CHANNEL_MONO, AS_SAMPLINGRATE_16000, AS_BITLENGTH_16, 0);
  
  Serial.println("Initialize Player");
  thePlayer->init(MediaPlayer::Player0, AS_CODECTYPE_WAV, "/mnt/sd0/BIN", AS_SAMPLINGRATE_16000, AS_CHANNEL_MONO);

  theMixer->setVolume(-100, -100, -100);

  Serial.println("Start Recorder");
  theRecorder->start();

  /* fill the sound data to FIFO before starting the player */
  int frame_size = 0;
  while (frame_size < request_size) {
    err_t err = theRecorder->readFrames(s_buffer, request_size, &read_size);
    if (err != 0) { 
      Serial.println("Error! readFrames: read_size = " + String(read_size)); 
    } 

    if (read_size > 0) {
      memset(out_buffer, 0, s_buffer_size);
      memcpy(out_buffer, s_buffer, read_size);
      thePlayer->writeFrames(MediaPlayer::Player0, out_buffer, read_size);
      frame_size += read_size;
    }
  }
  
  Serial.println("Start Player");
  thePlayer->start(MediaPlayer::Player0, mediaplayer_decode_callback);
}

/* loop function from here */
void loop() { 

  int ret = theRecorder->readFrames(s_buffer, request_size, &read_size);
  if (ret != 0) { 
    Serial.println("Error! readFrames: read_size = " + String(read_size)); 
  }
   
  if (read_size > 0) {
    memset(out_buffer, 0, s_buffer_size);
    memcpy(out_buffer, s_buffer, read_size);
    thePlayer->writeFrames(MediaPlayer::Player0, out_buffer, read_size);
  }
}



さて、実際のサウンドを聞いてみましょう。マイク入力のレンジ 0.9Vpp に対して 1.0Vpp 程度で入力してオーバードライブをかけてみました。それらしく聞こえるものですね。





聞いていただいてわかるように遅延量が大きいです。いろいろエフェクトを考える前に、この遅延をなんとかしたいところですが、これ以上短くできる気がしない…
(´・ω・`)





JRC(新日本無線) 1回路 低雑音 オペアンプ NJM5534DD (5個セット)

JRC(新日本無線) 1回路 低雑音 オペアンプ NJM5534DD (5個セット)

  • 出版社/メーカー: JRC(新日本無線)
  • メディア:



SONY SPRESENSE メインボード CXD5602PWBMAIN1

SONY SPRESENSE メインボード CXD5602PWBMAIN1

  • 出版社/メーカー: スプレッセンス(Spresense)
  • メディア: Tools & Hardware



SONY SPRESENSE 拡張ボード CXD5602PWBEXT1

SONY SPRESENSE 拡張ボード CXD5602PWBEXT1

  • 出版社/メーカー: スプレッセンス(Spresense)
  • メディア: Tools & Hardware




nice!(26)  コメント(0) 
共通テーマ:趣味・カルチャー

nice! 26

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。