概要
windows版のjuliaで、実時間で作成(or MIX)した音声データを出力する技術メモです。PortAudioライブラリを用いています。
※TypeをInt16としていましたがFloat32の方が簡単ですので。サンプルプログラムを修正しました。
想定するアプリケーションと実行環境
アプリケーション:音声合成、音声処理、ラジオ
実行環境:julia, windows10
実行環境の準備
PortAudioモジュールを追加します。
解説
オーディオデバイスを調べる
PortAudio.devices()で使用可能なデバイス名を探す。
(input channel数)->(output channel数)
using PortAudio
PortAudio.devices()
音声デバイスにチャンクデータを出力
サンプルデータ作成
Floatではサンプルの値は-1.0から1.0の間にする。
※ Writing a Callback Functionには、サンプルの型はInt16でもよいがFloatが簡単と注記あり。
Nsmp=8000 #サンプル数
Nfs=8000 #サンプリング周波数
Fa =400 # 信号400Hz
Fb =600 # 信号600Hz
aT= (1:Nsmp)/Nfs
aDa= sin.(π*2*Fa*aT)
aDb= sin.(π*2*Fb*aT)
音声が出力されるかテスト
モノラルの場合は、サンプルをFloat型Arrayでwriteする。
T=Float32 # T=Int16
# 入力なし、出力1Ch、データ型、サンプリング周波数
stream=PortAudioStream("デバイス名",0,1, eltype=T,samplerate=Nfs)
#x=convert.(T,floor.(aDa*16000))
@time write(stream,aDa)
@time write(stream,aDb)
@time write(stream,aDa)
close(stream)
ステレオの場合は、サンプルをFloat型二次元Arrayに書き込みwriteする。
T=Float32 # T=Int16
# 入力なし、出力2Ch、データ型、サンプリング周波数
stream=PortAudioStream("デバイス名",0,2, eltype=T,samplerate=Nfs)
z1=zeros(T,Nsmp,2);z2=zeros(T,Nsmp,2)
z1[:,2]=aDa; z1[:,1]=aDb
z2[:,2]=aDb; z2[:,1]=aDa
write(stream,z1)
write(stream,z2)
write(stream,z1)
write(stream,z2)
close(stream)
非同期タスクで出力
T=Int16
ch=Channel(5)
# Consumer Task
function play()
stream=PortAudioStream("デバイス名",0,1, eltype=T,samplerate=Nfs)
try
while true
dat = take!(ch)
write(stream,dat)
end
finally
close(stream)
end
end
@async play()
x=convert.(T,floor.(aD*16000))
#Producer
put!(ch,x)
put!(ch,x)
put!(ch,x)
#close(stream)
応用
ラジオなら復調した音声データをChannelに積んでいけばよい。
ただ、オーディオデバイスのクロックとSDRのクロックを同期させないと、音飛びとか発生する。
Channelでキュー長を観測するインターフェースがあれば、キュー長を一定にするようにDDコンバータを作ってやればよいのだが。
参考情報
- PortAudioのTutorial
- ヘルプ:?PortAudioStream
- githubのJuliaAudio PortAudioのソース
- https://qiita.com/0x20FE/items/d8a4a477855b6e3aa36f