STM32のMCO2からPLLI2Sクロックを出力してみる

今回はSTM32のMCO(Master Clock Output)の機能を使ってPLLI2Sのクロックを出力してみる。
品質はどうなのかわからんけど主に外部オーディオコーディック用のMLCKとかに使えそうな予感

通常のMCO1に関しては以前やっている(STM32F3での実施)ので基礎に関しては以下の記事を参照
gsmcustomeffects.hatenablog.com

今回はSTM32F767を使うので上記の記事のレジスタ構成と多少異なる部分があるが基本は同じなのでリファレンスマニュアルを見るなりして対応してほしい

今回の試験環境

  • STM32F767 Nucleo144 board (評価ボード)
  • CubeMX Ver4.27(CubeF7 latest)(SDKというかHAL)
  • Atollic TrueStudio(IDE
  • RIGOL DS1054(オシロスコープ

というわけでやって行こう!

CubeMXでの作業

f:id:gsmcustomeffects:20181027232016p:plain

まずピンコンフィグ画面でMasterClockOutput2のチェックを入れる

f:id:gsmcustomeffects:20181027232647p:plain

次にクロック画面でPLLの設定とMCO2の設定をしてあげて24MHzあたりを出せるように設定してください

それが終わったらCubeから出力してください

AtollicTrueStudioでの作業

次にIDEでの作業ですがMCOの場合は何もいじらなくても初期コードだけで済みます。

まあそうはそうなんですがHALにバグ?みたいのがありましてクロックコンフィグ内の低レベルAPIを修正してあげないといけません

内容としてはSystemClock_Configの内部で呼ばれているHAL_RCCEx_PeriphCLKConfig内のI2SPLL部分です。
f:id:gsmcustomeffects:20181027233547p:plain

以上を修正したらビルドして書き込みしてください

見てみる

nucleoを使っているならここにオシロでもあててみてください

f:id:gsmcustomeffects:20181027234443p:plain

上手くできていればこのように波形が出ると思います
f:id:gsmcustomeffects:20181027234346p:plain

所感

MCO2からクロックを出力できた。

主な用途としてはエフェクターなどに使われているAK4558(32bit 192khz audio codec)のMLCKとかですかね。
f:id:gsmcustomeffects:20181027235224p:plain

24MHz与えると様々なサンプリングに対応できるのでこういったクロック出力機能は便利なんじゃないでしょうか?

bugfixへのアドバイス

最後に僕がどのような手順でデバッグしているかの話です。

まずはレジスタの値を確認する方法です。
f:id:gsmcustomeffects:20181027234233p:plain
SFRに関してはこの画面からレジスタに書き込んだりもできるので便利です。

最初行き詰ったらここを見てきちんとレジスタにされるべき設定が入っているか確認してください
もちろんこのSFRのjson定義にもバグがあるかもなので過信しすぎるのもよくないですけどね・・・・・

次に変数だったり構造体のトレースができる式タブですね
一般にはexpressionという名前で呼ばれています。

f:id:gsmcustomeffects:20181027234921p:plain

最近のマイコンではSDKで構造体を多用するのが増えていてそのメンバに対してif分岐するのが多いのでなんでこのループに入らないんだろう?とかbitシフト結果がほんとに正しいの?とかそういった疑問を実際に見れるのでHALの動作のステップ確認では便利です。

以上の二つを駆使していろいろ見てみると動作の勉強にもなりますし自身でfixできる癖がつきますので時間を溶かさないようにこういった機能を駆使してみてください。

STM32CubeProgでUARTを使ったフラッシュ書き換えを試す

STM32に関しては久しぶりですが
今回はSTからリリースされたSTM32CubeProgというソフトについてみていこうと思います。

STM32CubeProg

www.st.com

簡単に説明すると

STlink utility とかflash loaderとかdfuツールとかそういうのが一緒になってWindows,Mac ,Linuxに対応したものです。
以前できたことは一通りできます。

というわけで・・・・・

SWD接続とかDFUはいろんな方がやっているので
UARTブートローダーでもやってみようと思います。

UART bootloader

UARTからバイナリをぼこぼこ投げて書き込みできる機能。
特にまあたらしい物でもないからこんなもんで早速やって行きましょう。

今回使うものはSTM32F767 Nucleoを使うのでそれ用の設定で説明していきます。

STM32F767の場合UARTは以下のものが使えます。
f:id:gsmcustomeffects:20181020085513p:plain

んでまあ見てわかるんですが注意が必要でUART3ってSTLINKとつながってるのでそれが使えるやん?思う方もいると思うんですがところがどっこい
f:id:gsmcustomeffects:20181020085624p:plain

ブートローダーで使えるピンと違うとこからUART3を出してるのでSTLINK経由では使えません(このせいでなんでつながらないんだろうと5分位悩みました。
問題が整理できたとこでPC10,11が使えるとのことからこの辺から引っ張ってあげましょう

f:id:gsmcustomeffects:20181020090002p:plain

STLINKのTX RXピンから延ばしてもいいのですがシリアル変換器はこの辺の使ってます
f:id:gsmcustomeffects:20181020090144p:plain

次にbootloaderに遷移するための準備です。
STM32の場合は基本BOOT1とBOOT0の設定でフラッシュブートとsystem bootloaderから起動するか設定できるんですがF7の場合BOOTピン一個になりまして起動アドレス指定ができるようになりました。
f:id:gsmcustomeffects:20181020091839p:plain

初期状態でBOOTをHIGHにするとsystem bootloaderでいけるという感じですね。オプションバイトに関してはCubeProgで書き換えたり今の状態を見たりできるのでその都度確認してみてください。
ピンで言うとここです
f:id:gsmcustomeffects:20181020092138p:plain

ココまで終わるとフローチャート的にはこうなります
f:id:gsmcustomeffects:20181020092315p:plain

というわけでBOOTピンをHIGHにしてリセットしてUARTで接続してみましょう。
つながるとこのようになります。
f:id:gsmcustomeffects:20181020092536p:plain

先ほど示したオプションバイトはこのように確認できます。
f:id:gsmcustomeffects:20181020092623p:plain

書き込みはこの画面からできます
f:id:gsmcustomeffects:20181020093101p:plain

所感

というわけでかなり簡単にフラッシュの書き換えができるというわけです。
近年デバッガが安くなってきており持ってると特に使わない機能なんですが

エフェクターとか開発してると弾き手とかそういう人とやりとりする機会が結構あってアルゴリズム詰めてる時向こうが書き込み機を持ってないときとかに便利です。
あとは製品出荷後にアップデートとかしたいときに使えます。

あとF7ならDFUで書くほうが何もいらないのでいいと思いましたw

おまけ

ブートローダーについてCubeProgが自動でやってくれるので特に必要ありませんがマイコン間とかでファーム書き換えする場合は自前で打つ必要があります。
f:id:gsmcustomeffects:20181020093528p:plain

BOOTピンをHIGHにして該当UARTに0x7Fを送るとUARTブートするみたいです。
それを送るとACKがかえるみたいなのでTeratermで実験してみた。
f:id:gsmcustomeffects:20181020093833p:plain

Teratermを16進表記するとわかりやすいのでココを参考にしてみてください
shuzo-kino.hateblo.jp

デバッグmodeにできたら
信号を送信していきます。

ここでもTeratermのマクロ機能が便利です。

send $7F

とすると0x7Fを送ってくれます。

保存はこのような拡張子にします
f:id:gsmcustomeffects:20181020094134p:plain

次に接続設定です。
f:id:gsmcustomeffects:20181020094223p:plain

パリティEVEN以外は得に変わりはないです。

そうしたら上部メニューからコントロール/マクロを選択 先ほどのiniファイルを選択すると

f:id:gsmcustomeffects:20181020094332p:plain

きちんと79が帰ってきています。

そのあとはマニュアル通りにコマンドを打ってあげると書き込みできます。

ちなみにteratermのマクロはいろいろできるのでプロトコルとかそういった通信テストには便利だと思いますので覚えておくといいでしょう。

資料など

  • AN3155 Application note USART protocol used in the STM32 bootloader
  • UM2237 User manual STM32CubeProgrammer software description
  • AN2606 Application note STM32 microcontroller system memory boot mode

Python:ディレイの実装

今回はディレイを実装していきます。
いわゆる遅延系エフェクトでやまびこ効果とか言われるやつです。


ディレイの実装には参考文献に示すようにフィードバックの仕方によっていろいろな種類がありますが一般的なフィードバックありミックスありの通常のタイプをやって行きます。

f:id:gsmcustomeffects:20180820231509p:plain

まず時系列信号処理をするにあたってデータを保存するバッファを確保する必要があるのでリングバッファを使ってそれを実現します。
リングバッファの説明は参考文献の二つ目を参照してくれると理解しやすいと思う。

実装

というわけでさっそく実装していく

まずはエフェクトのパラメータであるfeedbackとmixとtimeを定義する。

delay_buffer_idx    = 0                                 #リングバッファのインデックス
feedback            = 0.4                               #フィードバック(0~1)
delay_ms            = 465                               #ディレイタイム[ms]
delay_buf_size      = int(frame_fs * delay_ms / 1000)   #バッファ確保[sample]
level                 = 0.1                               #level(0~1)

frame_fs は処理系によって異なりますが基本48000(48kHz)ぐらいだと思います。
48kHzサンプリングなので48000サンプルで1秒のディレイタイムが確保できる。
今回はPC上での実装なのでメモリはほぼ無限にあるがDSPだったり組み込みでの実装の場合限られた中で実装する必要もあるので頭に入れておくといいです。

次に入出力関係の整備を行う
ここはいつも通り入力バッファと出力バッファを確保しそれと今回使うディレイバッファを確保する。

input_buf    = in_data#wavデータだったり正弦波だったりを格納しておく
output_buf   = np.zeros(frame_size,dtype=np.float)#
delay_buffer = np.zeros(delay_buf_size, dtype=np.float)#パラメータのところで計算したサイズ分だけ確保する。

信号処理部分はコメントに示す通りの流れになる。

"""signal  processing"""
for i in range(frame_size):
    l_x = input_buf[i]*1.0+ delay_buffer[delay_buffer_idx] * level #入力(ゲインは1)+ディレイ
    delay_buffer[delay_buffer_idx] = input_buf[i] + delay_buffer[delay_buffer_idx]*feedback#入力とフェードバック分をバッファに書き込み
    delay_buffer_idx = int((delay_buffer_idx + 1) % delay_buf_size)#リングバッファをすすめる
    output_buf[i] = l_x#出力

これで処理自体は完了となる。
処理としてはメモリに入れて所定サンプル数経過後に原音と加算して出力してるだけなのでかなりコードが短い

最後に処理前後の波形を示しておきます。
f:id:gsmcustomeffects:20180821001507p:plain

音が切れてから残響効果により音が残る波形となっていることがわかる

サンプル音源

元音源

ディレイ

各種設定

"""delay param"""
delay_buffer_idx    = 0                                 #リングバッファのインデックス
feedback            = 0.4                               #フィードバック
delay_ms            = 465                               #ディレイタイム[ms]
delay_buf_size      = int(frame_fs * delay_ms / 1000)   #バッファ確保[sample]
level                 = 0.8                               #ミックス(エフェクトレベル)

コード全体

かなり走り書きなので参考程度にお願いします。

import numpy as np
import matplotlib.pyplot as plt
import create_func as cf
import wave
import audio_func as af
import struct
import scipy

wf = wave.open("GS04.wav", "r")#wav 扱うならお決まりのやつ
num_data = scipy.fromstring(wf.readframes(wf.getnframes()),dtype = "int16") / 32768.0#正規化
frame_fs = wf.getframerate()
frame_size = wf.getnframes()

"""delay param"""
delay_buffer_idx    = 0                                 #リングバッファのインデックス
feedback            = 0.4                               #フィードバック
delay_ms            = 400                              #ディレイタイム[ms]
delay_buf_size      = int(frame_fs * delay_ms / 1000)   #バッファ確保[sample]
level                 = 0.5                               #ミックス(エフェクトレベル)
if(wf.getnchannels() == 2):
    left = num_data[::2]#1 スライス
    right= num_data[1::2]
    in_data = left*0.5 + right*0.5#2ステレオモノラル化
    #1:スライスの説明
    #a[1,2,3,4,5]ていうリストがあったとして
    #a[::2]  -> 1,3,5
    #a[1::2] -> 2,4

    #2:ステレオ->モノラル化
    #もともとギターの録音で左右に同じ音ふってるのでLR分解して半分にして足せば同じようなもん

input_buf    = in_data
output_buf   = np.zeros(frame_size,dtype=np.float)
delay_buffer = np.zeros(delay_buf_size, dtype=np.float)


"""signal  processing"""
for i in range(frame_size):
    l_x = input_buf[i] + delay_buffer[delay_buffer_idx] * level #入力+ディレイ
    delay_buffer[delay_buffer_idx] = input_buf[i] + delay_buffer[delay_buffer_idx]*feedback#入力とフェードバック分をバッファに書き込み
    delay_buffer_idx = int((delay_buffer_idx + 1) % delay_buf_size)#リングバッファをすすめる
    output_buf[i] = l_x#出力

plt.subplot(211)
plt.plot(input_buf[0:frame_size])
plt.subplot(212)
plt.plot(output_buf[0:frame_size])
plt.show()

output = [int(x * 32768.0) for x in output_buf]
output = struct.pack("h" * len(output), *output)
af.play(output,wf.getsampwidth(),1,wf.getframerate()) #再生
#af.save(output, frame_fs,1,"delay2.wav")

Python:ビブラートとコーラス:2

前回の記事ではPythonでビブラートエフェクトとコーラスエフェクトを実装した。
今回はFM変調とBessel関数に関して面白い記述*1があったのでほとんどパクりだけど(情報は多いほうがいいに決まってるw)それについてみていく

FM変調

FM変調は以下の式で示されるのだった。

  • y(n) = Asin(2 \pi f_{c} \frac{n}{f_{s}} + Isin(2\pi f_{m}\frac{n}{f_{s}}))
  • A:原音信号振幅
  • fc:原音信号周波数
  • fs:サンプリング
  • fm:変調周波数
  • I:変調深度(エフェクターによくあるdepthつまみ)

このままでもいいのだが書くのがめんどいので2 \pi fの部分を\omegaに置き換えさせてもらう
置き換えるとこうなると思う。

\begin{align*}
y(t) = a_c \sin(\omega_c t + a_m \sin(\omega_m t))
\end{align*}

ここで
\begin{align*}
t &= n / fs\\
\omega_c&= carrier freq\\
\omega_m&=modulation freq
\end{align*}

キャリアは原音信号のこと

この式を加法定理を使って展開しておく。

\begin{align*}
\sin (\alpha+\beta)=\sin\alpha\cos\beta+\cos\alpha\sin\beta
\end{align*}


\begin{align*}
y(t) = a_c (\sin(\omega_c t)\cos(a_m \sin(\omega_m t)) + \cos(\omega_c t)\sin(a_m \sin(\omega_m t)) )
\end{align*}

第一種ベッセル関数

第一種ベッセル関数はベッセル微分方程式の解のひとつである。
第二種とか、特殊とかあるので詳しくは参考文献を見てくれたほうがいいと思う。
形としてはこんなグラフです。

f:id:gsmcustomeffects:20180819070610p:plain

ベッセル関数とFM基本式

参考文献よりベッセル関数から以下の関係式が得られます。

\begin{align*}
\cos(x \sin(y)) &= \sum_{n=-\infty}^{n=\infty} J_n (x) \cos (ny) \\
\sin(x \sin(y)) &= \sum_{n=-\infty}^{n=\infty} J_n (x) \sin (ny)
\end{align*}


それを用いて上の加法定理の式をそれで置き換えると
\begin{align*}
y(t)=&
a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) (\sin(\omega_c t)\cos(n \omega_m t) + \cos(\omega_c t)\sin(n \omega_m t)) \\
=&
a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) \sin ( (\omega_c + n \omega_m)t )
\end{align*}

となる。

もう一度まとめてみると

\begin{align*}
a_c \sin(\omega_c t + a_m \sin(\omega_m t)) = a_c
\sum_{n=-\infty}^{n=\infty} J_n (a_m) \sin ( (\omega_c + n \omega_m)t )
\end{align*}

ここからFM変調はベッセル関数と基音+倍音の積で表すことが可能だとわかる。

変調指数の大きさと倍音の関係

次に変調指数についてみていく


第一種ベッセル関数の\(J_{n}(\alpha)\)は一般的に変調指数と呼ばれる。
上で導いたようにFMの変調深度もそれにあたる。

というわけでこいつを大きくしていけばエフェクトとしては深くかかっていく理論。
その時ベッセル関数での挙動はどうなっているのか出してみた。
x軸を第一ベッセル関数の次数にしてy軸をJn(固定)にして表示すればよい

Jn(0.5)の場合

f:id:gsmcustomeffects:20180819071931p:plain

Jn(5)

f:id:gsmcustomeffects:20180819072006p:plain

Jn(10)

f:id:gsmcustomeffects:20180819072016p:plain

変調指数が低いと原音がきちんと聞こえるエフェクトとなるがJn(0.5)の時を見ると元スペクトルが大きく、側波帯が低くなっています。
第一種ベッセル関数は徐々に振幅が下がっていく特性を持つので側波帯のスペクトルは速やかに減衰する。すなわちエフェクトの効果通り原音の色が強い音色となる。


この記事で使ったPythonコード

scipy.specialモジュールを使います

from scipy.special import jv, yv
import numpy as np
import matplotlib.pyplot as plt

z = np.arange(-20,20,0.01)#x軸の範囲

for i in  range(0,5):#次数の決定(別に何個でもいい)
    bessel = (jv(i,z))
    plt.plot(z,bessel,label="J"+str(i))

plt.legend()
plt.show()

nを横軸にしたグラフのコード

from scipy.special import jv, yv
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(0,50,0.01)
x = []
bessel = []
jn = 0.5
jn_index = int(jn*100)
for i in  range(0,30):
    bessel.append(jv(i,z[jn_index]))
    x.append(i)

plt.xlabel("bessel order")
plt.ylabel("Jn(" +str(jn) + ")")
plt.scatter(x, bessel)
plt.show()

参考文献

*1:Analyzing an FM signal [John d .cook氏]

Python:ビブラートとコーラス:1

今回はFM変調を用いたビブラートとコーラスを実装していきたいと思います。

原理

遅延回路(アナログで言うところのBBD)のクロックをLFO(変調波形)で変えることにより周波数方向に揺れた音を作るエフェクトです。

基本式は以下のようになります。

  •  y(n) = Asin(2 \pi f_{c} \frac{n}{f_{s}} + Isin(2\pi f_{m}\frac{n}{f_{s}}))
  • A:原音信号振幅
  • fc:原音信号周波数
  • fs:サンプリング
  • fm:変調周波数
  • I:変調深度(エフェクターによくあるdepthつまみ)

sinの中にsinがあって.....うーんって感じがしますが、そのまま書いてグラフ出すと原理は理解しやすい
f:id:gsmcustomeffects:20180815160538p:plain

画像は上から原信号、変調波系、被変調波となっています。
時間によって周波数が変化している。
一方でトレモロの時はAM変調で単なる乗算だったので
\begin{align}
y = sin a\cdot sin b
\end{align}

な基本式が信号処理っぽく詳しく書くと
\begin{align}
y(n) = Asin(2 \pi f_{m}\frac{n}{f_{s}}) \cdot sin(2 \pi f_{c}\frac{n}{f_{s}})
\end{align}

こうなってx[n]を入力サンプルとすると

\begin{align}
x[n]\cdot Asin(2 \pi f_{m}\frac{n}{f_{s}})
\end{align}

に書き直せば一般的な問題として考えることが可能だった。

というわけで?

こいつらをどうやって実装していくかって話。
デジタル信号処理では遅延処理はメモリ(バッファ)を使う事で実現できる。
ということは入力x[n]をメモリM[n]に入れてnを変調してやればどうにかなりそう?

\begin{align}
y[n] = x[M[n]]
\end{align}

このように入れ子の構造にしてnを変調する

図で書いてみるとこんな感じになった。
f:id:gsmcustomeffects:20180815215038p:plain

次に変調ありとなしの場合のデータの流れを見ていく

f:id:gsmcustomeffects:20180815220144p:plain

変調なしの場合は順番にデータが取り出されるのでインデックス番号は一定になるが変調ありの場合はインデックスを変調したためインデックス番号が小数のところが現れる(というか整数になるとこが稀)。
まあC言語をやっている人はわかると思うが配列のインデックス番号は整数でないといけない

float buffer[10];

a = buffer[1]    // OK
b = buffer[1.1]//NG

というわけでキャストとかを使うと変調後のnは0,01,1,2,3.....のようになり複数回同じデータをyに出力することになる。
入力周波数が低い場合はいいが周波数が高いとサンプル点が少なくなるのでなめらかな波形でなくなる。
別にこの状態でもコーラスエフェクトとして使えるが一般にはこの現象を防ぐために補間を使って間のデータを補う手法が用いられる。*1

というわけで実装していきましょうか
まずは入力サンプルを作っていくので正弦波合成からですね。いきなりwaveファイルを通して実験してもいいのですがグラフだした時に確認しにくいのでこの方式にします。
正弦波の作り方はここに書いてますのでそれを参考にしてください

input = cf.create_sin(1.0,440,frame,sampling=48000)

まあこんな感じで良いでしょう
次はインデックスの変調を行う部分を作ります。

def index_mod(frame):
    n = np.zeros(frame, dtype=np.float)
    i_num = 0
    for i in range(0,frame):
        n[i] = i + depth_ms * (np.sin(i_num*(2.0 *np.pi * freq/fs)))
        i_num += 1
    return n

ここは別にどう書いてもいいですけど変調後のインデックスを返す関数を一個作っておきました。

あとはこういうふうにつかえばOK

n = index_mod(frame)#インデックスの変調
output = np.zeros(frame,dtype=np.float)#空の配列作成
for i in range(0,frame):
    output[i] = mix*input[int(n[i])] + (1-mix)*input[i] #原音と変調音を足している

サンプルサウンド

原音

エフェクト音(コーラス)

エフェクト音(えぐいビブラート)

実際のwavファイルのをつかった例

結構試行錯誤的な部分があるのでくそコードなのは勘弁していただきたい。
補間については別の記事でやりたいので今回は無補間で処理してます
無処理な割にはそこそこきれいな音になっているはず

import numpy as np
import matplotlib as pl
pl.use('TKagg')
import matplotlib.pyplot as plt
import wave
import audio_func as af
import struct
import scipy

def index_mod(frame):
    n = np.zeros(frame, dtype=np.float)
    i_num = 0
    for i in range(0,frame):
        n[i] = i + depth_ms * (np.sin(i_num*(2.0 *np.pi * freq/fs)))
        i_num += 1
    return n

wf = wave.open("GS05.wav", "r")#wav 扱うならお決まりのやつ
num_data = scipy.fromstring(wf.readframes(wf.getnframes()),dtype = "int16") / 32768.0#正規化
fs = wf.getframerate()
frame = wf.getnframes()

freq        = 9     #変調周波数
depth       = 6     #変調深度
depth_ms    = int(fs * depth /1000)
mix = 0.99          #ミックス(コーラスで言うエフェクト量高いほどヴィブラートになる)

if(wf.getnchannels() == 2):
    left = num_data[::2]#1 スライス
    right= num_data[1::2]
    in_data = left*0.5 + right*0.5#2ステレオモノラル化
    #1:スライスの説明
    #a[1,2,3,4,5]ていうリストがあったとして
    #a[::2]  -> 1,3,5
    #a[1::2] -> 2,4

    #2:ステレオ->モノラル化
    #もともとギターの録音で左右に同じ音ふってるのでLR分解して半分にして足せば同じようなもん


input = in_data

n = index_mod(frame)#インデックスの変調
output = np.zeros(frame,dtype=np.float)#空の配列作成


for i in range(0,frame-9000):#変調をあげすぎるとインデックスオーバーするから適宜調整する
    output[i] = mix*input[int(n[i])] + (1-mix)*input[i]
plt.subplot(211)
plt.plot(input[0:frame])
plt.subplot(212)
plt.plot(output[0:frame])
plt.show()

#正規化したデータを元に戻す
output = [int(x * 32768.0) for x in output]
output = struct.pack("h" * len(output), *output)
#af.play(output,wf.getsampwidth(),1,wf.getframerate()) #再生
af.save(output, fs,1,"custom_vib3.wav")

*1:音遊び!Blackfin DSP基板でディジタル信号処理初体験を参照

Python:正弦波合成

デジタル信号処理での正弦波の作り方

create_func.py

import numpy as np

def create_sin(amplitude,freq,frame,*,sampling = 48000):
    data = np.zeros(frame,dtype = np.float)
    for n in np.arange(1,frame):
       sine = amplitude * np.sin(2 * np.pi * freq * n / sampling)
       data[n] = sine
    return data

def create_cos(amplitude,freq,frame,*,sampling = 48000):
    data = np.zeros(frame,dtype = np.float)
    for n in np.arange(1,frame):
       cosine = amplitude * np.cos(2 * np.pi * freq * n / sampling)
       data[n] = sine
    return data

使い方

import audio_func as af
sinewave = cf.create_sin(1.0,1000,frame,sampling=48000)




参考文献