音関連

こんな感じに定期的に音を採れるようにしてみた。parameter 部分は最初は不定値にして、上位から値を設定してみたもののなぜかちゃんと動かないので値をいれることにした。それの関係で桁の設定がかなりバラバラ。
ちょっと考えないと。あまりよく見てないが parameter は整数、小数、文字列(!)も入るってのが、ちょっと不思議。

module sound_recorder #(
	parameter kHz = 20, parameter CH = 1, 
	parameter RECORD_NS = 1000_000,
	parameter FILENAME = "stream.memh"
)(
	input signed [15:0] sound_r_or_mono, sound_l
);
	parameter ns = 1000000 / kHz;
	parameter SAMPLENUM = RECORD_NS / ns;
	
	reg [15:0] data [0:(SAMPLENUM * CH) - 1 + 2];
	integer i;
	
	initial begin
		data[0] = kHz * 1000;
		data[1] = CH;

		for(i = 0; i < (SAMPLENUM * CH); i = i + CH) begin
			#ns data[i+2+0] = sound_r_or_mono;
			if(CH == 2) begin
				data[i+2+1] = sound_l;
			end
		end
		
		$writememh(FILENAME, data);
		$display("%t: %s dumped", $time, FILENAME);
		$stop;
	end
endmodule

writememh で出力されたファイルを wav ファイルに変換する。簡単ね。

require 'wave.rb'

begin
	f = File.open(ARGV.shift, 'r')
	sample = []
	hz = nil
	ch = nil
	
	while t = f.gets
		t = t.chomp
		if(t =~ /\A[0-9a-fA-F]+\z/)
			v = t.to_i(0x10) & 0xffff
			if(hz == nil)
				hz = v
			elsif(ch == nil)
				ch = v
				p hz, ch
			else
				sample << v
			end
		elsif(t == 'xxxx')
			sample << 0
		end
	end
	f.close
	
	wave_write(ARGV.shift, hz, ch, 2, sample)
end

なんでこういうことをやってるかというと、テストベンチ毎に似たようなものを作ったり、周波数を 1 から割って、 10 の -何乗かを関数電卓で計算して、という不毛なことを割と繰り返してた verilog ソースと、似たようなものをコピペして書き捨てる ruby ソースも多かったので、さすがに汎用性があるものは require とか include とかしましょうよ、という基本的な話。

それをやってる自分が言うのもなんだが、他人の使い捨てではないソースでこういうのがあると、やはり完成度が低くやっつけで不親切で不安定というがよくあるので、戒め。