音遊び日記

ハードウェアとソフトウェアの両面から”音”で遊んだ事を備忘録として書いています。

DE0 nano搭載SDRAM制御(便利なサイトまとめ)

1. はじめに

 Amazonでも売っているFPGA評価ボードDE0 nanoを買いました。これ、マジでおすすめです。スペックは下のリンクの通り。1万でこれだけいろいろ揃っているのは素晴らしすぎるし、何より給電と書き込みがUSBで出来る点。これが実はかなり重要。ロジック規模なども個人で使うには十分すぎる量です。

DE0-Nano 開発・学習ボード

 

2. SDRAMとは

 SDRAM(Synchronous Dynamic Random Access Memory)とはシンクロナス、つまり同期式のDRAMです。DRAMは下図のような構造になっており、コンデンサに充電されているかどうかで1,0を記録します(充電されていれば1、されていなければ0)。

f:id:hsy221:20191104224044p:plain

読み書き動作の説明はこのpdfがめちゃめちゃわかりやすい。

http://www.osakac.ac.jp/labs/matsuura/japanese/lecture/semicondic/oubun/ou001.pdf

 

 この構造上、時間が経てばコンデンサは自然放電してデータを消失してしまいます。これを避けるために、DRAM/SDRAMは定期的にデータを書き直すのですが、これをリフレッシュと言います。またさっきのpdfにもありますが読み込み時にも放電するので、読み込み後もそのビットはデータを書き直さなければなりません。

 こうやって見ると制御がすごく難しそうに見えますが、リフレッシュする時は定期的にリフレッシュコマンドを一つ投げれば、全データ自動でリフレッシュしてくれますし、読み込み後のデータ再書き込み(プリチャージ)も、オートプリチャージ付きリードコマンドを使う事で自動でやってくれます。

 

3 SDRAMの制御

 制御信号について話す前に、DE0 nanoに乗っているSDRAMIS42S16160G-7TLI」のアドレスマップについて紹介します。4M(Address)×4(bank)で、イメージとしては下記の図のようになります。これらのアドレスはRow Addressが13bit、Column Addressが9bitあり、2^13 × 2^9 = 2^22通りあります。2^22 = 2^2 × 2^10 × 2^10なので4M Addressとなります。ちなみに1アドレス当たり16bitのデータを保存できるので4M(Address)×4(bank)×2(byte data) = 32M(bit data)となります。

f:id:hsy221:20191201212915p:plain

 

↓制御の状態遷移図と参考にしたVerilogソース

http://www.hmwr-lsi.co.jp/fpga/fpga_10.htm

SDRAMの基本的な書き込み読み込みコマンドについてわかりやすく解説しています。

技術レポート「マイコンによるSRAM、SDRAM制御」|ソフテックだより|株式会社ソフテック

 

波形テーブルの作成~wavからcsvファイルに変換する~

1. はじめに

 マイコンなどで正弦波や方形波以外の複雑な音声を出力しようとした時、最もシンプルな方法として波形テーブルがあります。波形テーブルとは波形を定数の配列としてソースコード上に宣言し、それを順番に出力する事で音声を出力する方法です。図で表すとこんな感じ。

f:id:hsy221:20191023160003p:plain

 今回はC言語を使って簡単にwav音源ファイルからcsv数値列ファイルを作成する方法を紹介します。これでDTMプラグイン音源とか、自分で収録した楽器の音源ファイルから簡単に波形テーブルを作成できます。

 

2. ソースコード

 以前本ブログで紹介した、C言語でwavファイルを読み込む関数を使います。詳細はこちら↓

hwswsgps.hatenablog.com

 

 wavファイルを読み込む関数 audio_readを使ってwavファイルをヘッダ部分と音声データ部分に分けて変数に代入します。まずは宣言やらコマンドライン引数やらの準備部分とwavファイルの読み込み部分までのソースコードです。

#include <stdio.h>
#include <stdlib.h>
#include "audioio.h"

int main(int argcchar *argv[])
{
  //変数宣言
  FILE *fp;
  WAV_PRM prm_in;
  double *data_in;
  unsigned short wdata;
  int n;
  char filename[64];
  
  //コマンドライン引数が違う場合
  if(argc != 2){
    printf("引数が違います\n");
    exit1 );
  }
  
  //wavファイルの読み込み
  data_in = audio_read(&prm_in, argv[1]);

wavファイルの読み込みが完了したら、コマンドライン上で出力ファイル名(.csv)を入力させ、そのファイルをfopenで開きます。ここで、すでに同名のファイルがある場合は上書きされ、無い場合は新規作成されます。fopenはこのプログラム上でそのファイルを使えるようにするために行います。

  //出力ファイル名入力
  printf("output file name : ");
  scanf("%s", filename);

  //出力用ファイルオープン
  fp = fopen(filename, "w");
  if(fp == NULL){
    printf("%sが開けません\n", filename);
    return -1;
  }

最後に読み込んだデータを名前を先ほど入力したファイルに書き込みます。audio_readで読み込んだ値は-1~1で正規化されており、今回は0~65535の16bitで表現したかったので、変換しています。ここら辺は用途によって変わってくると思います。また記述もちゃんと型変換を行わないといけないと思うのですが、そこらへんちゃんと把握していないので無理やり代入してます(勉強しなくては、、、)。

  //データ書き込み
  for (n = 0;n < prm_in.L;n++){
    wdata = ((data_in[n] + 1* 65535 / 2);
    fprintf(fp, "%d,", wdata);
  //fprintf(fp, "%f", data_in[n])  ←-1~1の正規化データをそのまま使う場合
  }

  //メモリ解放
  free(data_in);

  return 0;

audio_read関数が便利なのと波形切り出したり、長さ調整とかをしていないので、かなり短いソースコードで済みました。このシンプルなコードではwavファイル上で正確なサンプル数で作りこまないといけません。

 打楽器音源をリズムマシンとして使う場合や単発の効果音などであれば問題ありませんが、弦楽器や管楽器など連続波形の一波形の波形テーブルを作りたい場合、正確なサンプル数で1波長分のwavファイルを作成しなければなりません。それに対する考察を次章以降で行います。

 

3. 1波長分の波形テーブルのサンプル数について

 この章の話は実装して検証したわけでは無いので、想像として聞いてください。。。

 

 プログラムの記述を考えれば波形テーブルのサンプル数は少ないに越したことはありません。ところがサンプル数が少なければその分、元の波形の再現度が低くなり、音質低下につながります。

 仮に8bit(256sample)で1波長を表現した場合、サンプリング周波数44.1kHzで再生すると、44.1k / 256 = 172Hzより高い周波数ではサンプルの間引きが行われ、それ未満ではサンプルが足りません。低周波ほど波長が長くなるため、たくさんのサンプルを必要とします。低周波もきちんと再生したい場合もっとサンプル数を増やす必要があると考える事が出来ます。

 サンプリング周波数44.1kHzで86Hzの音は1波長当たり512サンプルで表現されますが、波形テーブルは256サンプルの時、足りないサンプルは同じサンプル二回呼び出すことになりますがこれでいいと思います。なぜかと言うと様々なサンプル補完デジタルアルゴリズムがありますが、DA変換時のLPFでサンプル間は補完されるため、この規模であればデジタル補完はいらないと思うからです。

 また86Hzの音は半分の22.05kHzでサンプリングすれば1波長当たり256サンプルとなりますが、果たして86Hzの音に対してサンプリング周波数を半分にした所で、音質に違和感はないと思います。演算のしやすさから8bitで十分(ちょっと多いくらい)だと思っています。

 

4.課題

 さて本題の波形テーブルの作成についてですが、打楽器や単発の効果音の波形テーブルを作りたい場合は、音源から目的の音をsound engineとかで切り取ってさっきのプログラムに入れればいいですが、弦楽器や管楽器などで一波長だけ切り出して連続波形として使用したい場合、さっきのプログラムはwavデータすべてをcsvファイルに変換するため、一波長のみの音源ファイルを作る必要が出てきます。

 それはサンプリング周波数に対して正確な周波数の信号を鳴らした音源が必要となります。DTMで打ち込みで音源を作るなら可能かもしれませんが、生の音を収録してそれを使いたい場合は正確な周波数で鳴らすなど不可能です。

 今後はプログラムを改良して、自動で音源から一波長分のデータのみを抽出するように(気が向いたら)しようと思います。

 

 

プログラマブルスイッチャーの自作

 

1. はじめに

 AVRマイコンとリレーを使ったプログラマブルスイッチャーの自作記事です。自作エフェクターのいい所と言えば、安く作れる所だったりしますが、スイッチャだけはそうもいきません。金はかかる、時間はかかる、ケースの設計が大変。。。いいことないです。ただ決定的にいい点が一つあって、独自の機能を入れられる事です。市販品にはないパターンでループを切り替えたり、リズムに同期して切り替えられるようにしたりなど工夫次第で可能性は無限大です。

 今回のプログラマブルスイッチャの製作費はたぶん1万ちょいくらいだと思います。プログラマブルスイッチャとしては安いって思うかもしれませんが、ここ数年めちゃめちゃ安いスイッチャがたくさん出てきました。1万円台も当たり前にあります。スイッチャに限らずですが、安いエフェクターが大量に出てきてエフェクター自作勢にとっては複雑な気持ちですね。

 なおマイコンのプログラミングに関しては今回触れていません。やろうとしていた機能は実現しましたが、記述があまりきれいじゃない気がするので公開したくない。。。

 

2. 仕様 / 機能

 インターフェースとしてはこの表に示す感じ。使用しながら機能を変えられるように、プログラム書き換え用のUSBポートも用意しています。

エフェクトループ 4ループ
チューナーアウト 1出力
フットスイッチ 4個
2色(赤/青)LED 4個
赤色LED※ 4個
USBポート 1ポート
2桁7セグメントLED 1個
※エフェクトループの状態に連動

 ループとスイッチは4つずつ。 チューナーアウトは使用すると、メインの出力はミュートされる。2色LEDはフットスイッチと1対1で割り当てて、2色なので様々な機能を持たせられる。赤色LEDはエフェクトループのリレーと連動して点灯させます。

 

 次に機能面。まずは通常のプログラマブルスイッチャと同じ、スイッチ一つ一つにエフェクトループのオンオフのパターンを割り当てる方式で作ります。編集中は2色LEDを青色に点灯します。バンクや使用中のパッチの情報は7セグLEDに表示します。また編集したパッチの情報はAtmega328の内臓EEPROMに保存します。一番最後に動作を説明した動画があります。

スイッチ1,2同時 一つ上のバンクへ
スイッチ2,3同時 チューナーアウト ON / BYPASS
スイッチ3,4同時 一つ下のバンクへ
スイッチ長押し

パッチ編集

 

3. 回路

 回路ブロック図としてはこんな感じ。

f:id:hsy221:20190614192038p:plain

 FT232RLを使ってUSB⇔UART変換をしてatmega328をUSB経由で書き込みますこれは紛れもなくarduino nanoと同じ回路です。

 

・リレー駆動回路 / 赤色LED

 最小限の部品でリレー駆動回路を構成しています。電気回路に詳しい人が見たら怒られるような回路かもしれません。定数も適当です。でも一応動いてます。

f:id:hsy221:20191013163515p:plain

 atmega328の出力をHighにすると、トランジスタにベース電流が流れてONになり、コレクタ-エミッタ電流が流れる事で、リレーが駆動されます。リレーの詳しい動作原理はググって下さい。リレーはコイルのため、トランジスタがOFFになった時(コレクタ-エミッタ間電流が流れなくなった時)、逆起電力が発生します。それによって流れる電流を吸収するために並列でダイオードを入れます。
 またこの回路では、一つのピンでリレーとLEDを同時に制御する事で使用するピンを節約しています。

 

・フットスイッチ 

 プログラマブルスイッチャには押している間だけ接点が切り替わるモーメンタリタイプを使用します。これによって長押しや同時押しが可能で、多くの機能を付ける事ができるようになります。安価なモーメンタリフットスイッチは、自作エフェクターといえばこの店、秋葉原桜屋電気さん、もしくはギャレットオーディオさんで500円程度で売っています。普通に10kでプルアップして使用します。

 

・7セグメントLED

 Atmega328のディジタルピンはアナログピンをディジタルとして使用しても全部で20ピン。スイッチ、リレーの制御もするので、7セグLEDを直接制御しようと思うとピンが足りません。そこで、IOピンを拡張する「IOエキスパンダ」を使用します。ピン数、入手性などからMCP23017を採用しました。秋月で売ってます。ちょっと見づらいですが、回路としてはこんな感じ。

f:id:hsy221:20191013165258p:plain

 Atmega328のSCL(A5)とSDA(A4)をMCP23017に接続します。7セグLEDのアノードを5Vに接続し、点灯させたいセグメントのカソードをMCP23017でLowにします。

 

・2色LED

 フットスイッチ一つに対して一つの2色LEDを割り当てます。今回は赤と青が点灯できるLED(青色LEDって綺麗ですよね)。2色って言ってますけど赤と青両方光らせれば紫としても使えます。電流制限抵抗は赤青ともに1kΩにしましたが、赤、青、紫3色ともそこまで大きな輝度の差は感じませんでした。 

 

・電源 / USB-UART

 すべての回路は5Vで動作可能(リレーのみ手元に9V品しかなかったので9V駆動)なのですが、エフェクターボードに5Vの電源なんて置かないので、他のエフェクターと同じ9V入力としています。定番の三端子レギュレータ7805を使って5Vを作ります。この電源回路と、USB-UART変換回路はほぼArduino nanoの回路図を丸パクリしました。arduinoオープンソースなので、調べれば完全な回路図がネットに上がっていますので調べてみて下さい。

 

4. 最後に

 完成品はこんな感じ。基板上に簡易Arduino回路を構成しているので、いつでもプログラムを書き換えられます。そのため、4スイッチ、4ループ、チューナーアウト、4つの2色LED、7セグLEDの制御をこれからも好きに変更する事が出来ます。ただし実はこの構成だとピンが一つ足りません。今回使用したのはTQFPパッケージのAtmega328p-auで、ArduinoDIPタイプのAtmega328p-puには無い「Analog in6,7(arduinoはAnalog in5まで)」があり、これにスイッチを割り当てました。

 今回紹介したのはオーソドックスなプログラマブルスイッチャーですが、タップテンポを使ってリズムに同期してパッチを変更させたり、パッチ一つ一つに名前を付けて7セグLEDに表示したり(市販にもあるか?)、可能性は無限大です。今後色々プログラムを書き換えて変態的な機能を追加していきたい。

 


自作プログラマブルスイッチャー

 

 

 

 

mxr m-80のディストーションchの挙動がおかしいので修理

久しぶりに昔めちゃめちゃ愛用していたmxr m-80を引っ張り出してみた。でも電源を入れてみると何かおかしい。。。

症状①:ディストーションをOFFに切り替える時に徐々にLEDが消えていき、完全には消えない(GATEのLEDも同じ)

症状②:音も3秒くらい待たないと歪みがOFFにならず、ボッというノイズが入り歪みがOFFになる

完全にディストーションのスイッチまわりがイかれてます。正直この歪みはあまり好きではなく、GAINもBLENDも0にしてブースターとして使っていたので、もうディストーションCH使わなくていいかなーとも思ってたのですが、直して使えそうなら直そうってわけで修理する事にしました。

 

まず裏蓋を開けます。が、ネジがインチサイズなので家にあるレンチでサイズの合うものがない。。。ちょっと合わないだけならまだしも、どれを使っても全く合わない。

調べてみるとレンチのサイズは7/64インチとの事。裏蓋を開けて、ジャックやポットを固定するナットを全て外し、基板を取り出します。見た目で怪しい所はない。

回路図を下記のサイトから入手します。(画質が悪くて文字がほぼ読み取れません、登録とかすればちゃんとした画質の回路図が見れるのか?)

 

ja.scribd.com

 

回路図を追ってみると、下の画像の黒で囲まれたスイッチがDISTORTIONのフットスイッチ、赤で囲まれたLEDがDISTORTIONとGATEのLED。その間にあるエミッタ接地NPNトランジスタをフットスイッチで制御しているようです。

f:id:hsy221:20190705201943j:plain

「LEDが徐々に変化する」という症状から何か時定数を持って変化しているように感じたので、コンデンサの放電がうまくいっていないのかと考え、スイッチOFFの状態(LEDが少し光ってる)でコンデンサの両端を小さい値の抵抗でつないでみるも変化なし。スイッチOFF→すぐに抵抗繋ぐも症状に変化なし。

となるとトランジスタが壊れたか?3端子のSMDの交換は面倒臭いし、何とか交換せずに行けないか?

 

って訳でこの怪しいトランジスタを使わず直接制御する方法を考える。この回路ならとりあえずトランジスタのコレクタ-エミッタ間に電流が流れればONになるわけで、それを再現するため、ディストーションをOFFにした状態でコレクタ-エミッタ間をジャンパー線でショートしてみる。ちゃんとディストーションがONになった。さらにジャンパー線を離せばすぐにOFFになった。これで一応通常動作をさせる事が出来た。

完全に原因がわかったわけではないが、通常動作させる方法はわかったので、フットスイッチの足をトランジスタのコレクタとエミッタに直接はんだ付けして、回路図で書くと下記のように配線した。

f:id:hsy221:20190705203831j:plain

これで一応動作としては問題ない。こういうアナログ回路にそこまで詳しい訳ではないので解らないのが、なぜ最初から修理後の回路のように直接フットスイッチで制御せず、トランジスタを介して制御しているのか。わかる人いたら教えて欲しいです。

 

結局トランジスタ自体が壊れているのか、そのほかの部品の不良によってコレクタ電流をうまく制御出来ていないのか完全に原因はわからずじまいでしたが、何とか使えるモノにする事が出来たのでよしとします。

atmega328を組み込みとして使う

自分の作りたいものの基板にatmega328を載せる時、あらかじめ書き込まれたものを載せるのではなく、載せたまま書き換えられるようにしたいと思って色々調べた方法を二つまとめます。

一つ目は、別に用意したarduinoを書き込み装置としてSPI通信を用いて書き換える方法です。こちらは基板上にはatmega328とピンヘッダだけあればよく、省スペースで済みますが、書き込みに毎回若干の手間がかかります。

二つ目は、FT232RLというICを用いてUSB⇔シリアル変換で書き込む方法です。基板上に簡易版arduinoを構成するような形になります。基板上にFT232RLとUSBコネクタを実装する必要がありますが、普通のarduinoと同じように扱う事が出来るため、書き込みなどは手軽に行えます。

 

手法①

ブートローダ書き込み済みのatmega328を基板に実装し、SPI通信に必要な下記の6pinをピンヘッダとして取り出します。そしてそのpinを書き込み用arduinoと下記のように接続します。

pin 対象atmega328 書き込み用arduino
1 MISO(D12) MISO(D12)
2 Vcc Vcc
3 SCK(D13) SCK(D13)
4 MOSI(D11) MOSI(D11)
5 RESET SS(D10)
6 GND GND

arduinoの下の方に出ている6pinをつかってもいいですが、SSではなくRESETが取り出されているので、注意が必要です。接続方法としてはブートローダの書き込みと同じですが、内部クロックを使用するブートローダを書き込んだ場合は水晶発振器やセラロックを接続する必要はありません。

 接続が完了したら通常通りの方法で書き込み用arduinoに「ArduinoISP」を書き込みます。書き込み完了したら、ArduinoIDEの設定を下記の通り変更します。

ボード:書き込んだブートローダと同じ

書き込み装置:Arduino as ISP

そしてスケッチを書き込みますが通常の方法ではなく「スケッチ」→「書き込み装置を使って書き込む」を使って書き込みます。

 

手法②

16MHz外部クロックを使う時はarduino nano、内部クロックを使う時は、Atmega328 on a breadboard(internal 8MHz clock)のブートローダを書き込んで下さい。

下記の回路図のように接続します。これはarduino nanoの回路図を極限まで簡略化した回路になります。多分FT232RLのTESTやRESETは解放でも大丈夫です。回路図にはありませんが、内部クロック使用でない時は水晶発振器の接続も忘れないで下さい。

f:id:hsy221:20190331205547j:plain

接続すれば通常通りの方法で書き込めますが、内部クロックを使った時はArduino pro or pro miniの3.3V/8MHzのボードに設定して下さい(3.3V設定ですが5Vでも使用可能)。

 

あくまで備忘録なので完全に自分用の文章で省略しまくってます。将来の自分がわかればいいのです。。。

 

激安FPGA(WINGONEER Cyslonell EP2C5T144)の回路図と取り扱い注意点

amazonで買える激安FPGA(WINGONEER Cyslonell EP2C5T144)の基板を回路図に起こしたので紹介します。回路図書こうと思った理由は2点あります。

・最初、説明書無いけどクロックとかLEDとかどのピンにつながってるかわからずわざわざ目視でパターン追ってテスタで確認した。

・使っているうちにピンヘッダとして取り出されているにも関わらず使えないピンがある事に気づいた。

毎回使うときに確認し直すのが面倒で、該当するピンをメモればいい話ですけど、せっかくならと思って回路図書きました。スペースの関係でFPGA本体は書いていませんが番号が全てFPGAのピンにつながっているとして見てください。

f:id:hsy221:20190213200448p:plain

回路図に間違い見つけた方は連絡下さると助かります。またこの回路図を参考にして改造して壊れたとか、火が出たとか言われても責任はとれません。電子工作は全て自己責任だと思ってやっています。

 

回路図を踏まえて以下に取り扱いに注意が必要なピンについてまとめます。

ピン番号 機能
3 LED2
7 LED4
9 LED5
17 CLK
26 1.2V(0Ω抵抗接続)
27 GND(0Ω抵抗接続)
73 3.3Vpull up(10kΩ)
80 GND(0Ω抵抗接続)
81 1.2V(0Ω抵抗接続)
17,18,21,22
88,89,90,91
入力専用
144 key

基板上のスイッチやLEDは表の通り割り当てられています。リセット信号を144に割り当てて基板上SWをリセットスイッチとして使うのが一般的ですかね?

取り扱い注意なピンがあります。73は普通のIOピンにも関わらず外部で10kΩでプルアップされています。基板裏を見ると謎の0Ω抵抗が4つあります。こいつのせいで使えないピンが26,27,80,81です。これらはpin plannerで見ても特別な機能が割り当てられているわけではないのに、なんでこんな仕様になっているんだ。。。出力に設定したらショートするかもじゃん。初心者の私にはわからない何かがあるのか、、、?ちなみに0Ω抵抗を外せば普通にIOピンとして使えます。抵抗の周りをハンダもりもりにすれば簡単に外せます。

入力専用と書いてあるピンはクロック入力で、IOピンとして使う時は入力しか指定できません。pin plannerで信号にピンを割り当てる時に、その信号が出力の場合指定する事ができません(リストに出てきません)。

 

pythonによるwavファイルの入出力

 

1. はじめに

今の時代簡単な機械学習とか自分で出来るようになっておきたいと思って、ニューラルネットワークpythonの勉強を始めました。pythonは信号処理用のライブラリも揃っていて、matlabとかの代わりとしても使いやすいようですので、せっかくなら音声処理させる事にします。今回はその第一歩としてwavファイルの入出力についてです。pythonの基本的な記述も合わせて勉強したことをまとめていきます。

pythonはライブラリが本当に豊富にあるので、色々方法がありそうですが、情報量の多さなどからwaveライブラリを使ってnumpy arrayでデータを扱えるようにする方法を採用しました。C言語と違ってライブラリを使うので、wavファイルの詳しい事はわからなくても記述できますが、一応下記にwavファイルの中身について書いてますので参考にして下さい。

hwswsgps.hatenablog.com

 

2. ソースコード

①ライブラリのインポート

import numpy as np
import sys
import wave

C言語でいう所の#includeですね。pythonでは「ライブラリ名.関数」みたいな記述をよくするのですが、毎回numpyって書くのは面倒臭いです。そういう時にasを付けると自由な文字列に変更できます。ここで「as *」と宣言するとライブラリ名を省略していきなり関数を記述する事が出来ますが、使いすぎてライブラリ同士で関数名が被ると思い通りの動作をしません。

numpyは三種の神器とも呼ばれる有名なライブラリの一つで、数値計算に必要な関数が入っています。その上位版の「sciPy」というライブラリもあります。

sysは今回はコマンドライン引数を利用するためにimportしています。

waveは音声の入出力用に使うライブラリで以下に情報が載っています。

https://docs.python.jp/3/library/wave.html#wave.Wave_write.setparams

 

②ファイルの読み込み

args = sys.argv
inFilename = args[1]
fIn = wave.open(inFilename, "rb")

1行目の記述だけでコマンドライン引数を取得してくれます。コマンドラインには「python ソースファイル名 音声ファイル名」と記述するため、C言語同様にコマンドライン引数はこの場合、args[0] = "ソースファイル名"、args[1] = "音声ファイル名"となります。

2行目でコマンドラインの音声ファイル名を取得し、3行目でファイルオープンします。①で書いたようにwave.openはwaveというライブラリのopenという関数を使うことを意味します。関数の引数と戻り値はC言語のfopenとほぼ同じと考えていいと思います。

 

③wavファイルパラメータ読み込み

ch = fIn.getnchannels() #チャンネル(モノラル or ステレオ)
fs = fIn.getframerate() #サンプリング周波数
nbits = fIn.getsampwidth() #量子化ビット
L = fIn.getnframes() #サンプル数

ここの情報も①で紹介したwaveライブラリのリンクに色々情報が載っています。wave.openで取得したfInオブジェクトに対しての処理なので「fIn.関数」のように記述します。処理をする時に使う情報としてはこれくらいかなと思うのでこれだけに絞って読み込みました。chは単純にモノラルなら1、ステレオなら2で返されます。

 

④wavファイル音声フレーム読み込み

x = np.frombuffer(fIn.readframes(L), dtype = "int16")
fIn.close()

fIn.readframesはfinで示すファイルから音声フレームを読み込んできます。np.frombufferはデータをndarrayと呼ばれるnumpyで使える配列に変換します。オプションでdtypeを16bit整数型に指定しています。

これでwavファイルの読み込みが完了したので、fInをクローズします。

 

⑤処理

n = 0
y = np.zeros(L, dtype = "int16")
while n < L:
  #実処理(今回は入力をそのまま出力)
  y[n] = x[n]
  n += 1

出力データ用の変数yをndarray型使用するためにnp.zeros()で初期化しています。

処理としては今回はファイルの入出力が目的なので、入力をそのまま出力するために、while文で配列の1要素ずつコピーしています。ただしpythonインタプリタ言語であり、処理が遅いです。なのでこういう書き方は本来はせず、配列全体として代入するべきです。

 

⑥ファイル出力

fOut = wave.open("out.wav", "wb")
fOut.setparams( (ch, nbits, fs, L, "NONE", "not compressed") )
fOut.writeframes(y)
fOut.close()

こちらも①のリンク先に詳細が載っています。1行目で出力ファイルをオープンし、2行目でパラメータを設定。ここで括弧が二重になっているのは、引数がタプルだからです。5個目と6個目の要素は圧縮形式を示しますが、先ほどのリンク先を見るとまだ実装されていないので"NONE"と"not compressed"で固定です。3行目でデータを書き込み、完了したらファイルをクローズします。

 

まとめ

これでpythonで音声処理をするための下地が出来ました。今後pythonでも音声処理するかもしれません。

pythonはライブラリがたくさんあります。今回は勉強のためにnumpyで処理をする前提で書いていますが、信号処理用のライブラリが用意されているのでそちらで処理できるようにファイルを取り込んだ方がいいのかもしれません。それは今後時間があったらよろうかな。