paint-brush
オーディオ用 Python FIFO バッファ クラス – アルゴリズム@giwyni
387 測定値
387 測定値

オーディオ用 Python FIFO バッファ クラス – アルゴリズム

GIWYNI5m2024/06/27
Read on Terminal Reader

長すぎる; 読むには

FIFO バッファは、多くのユースケースで一般的に必要とされるデータ構造です。アイテムはバッファに入れられ、任意の数量で取り出される点を除いて、入れられた順序で取り出されます。この記事では、このバッファのアルゴリズムについて説明します。
featured image - オーディオ用 Python FIFO バッファ クラス – アルゴリズム
GIWYNI HackerNoon profile picture
0-item
1-item
2-item

FIFO バッファは、多くのユースケースで一般的に必要とされるデータ構造です。アイテムはバッファに入れられ、入れられた順序で取り出されます。これはキューと同様の機能です。キューとバッファの違いは、バッファでは挿入されるデータがすべて同じデータ型であることです。さらに、任意の量のデータを挿入でき、取得量も任意です。


同じタイプの任意の数の項目を入れたり取り出したりするユースケースにはどのようなものがありますか? データ処理以外の分野に分岐します。銀行口座を考えてみましょう。お金はさまざまな金額で預けられ、必要に応じて大量に引き出されます。同じことが農場の穀物貯蔵にも当てはまります。しかし、銀行や穀倉がこれを行います。IT で私たちに残されているのはオーディオ データです。オーディオ データは非常に速く到着しますが、聞き取れるためには特定の速度で送信する必要があります。今日これの原因となっているのは、機械と人間の対話型コミュニケーションを容易にするテキスト読み上げエンジンです。機械はテキスト (おそらく AI エンジンから) を取得し、それをオーディオ バイトに変換して、人間が聞き取れる特定の速度で人間に送信します。予想どおり、機械はオーディオ バイトを高速で生成し、それをバッファリングして、人間への配信をはるかに遅い速度に保つ必要があります。類似点は、地元のガソリン スタンドです。テキスト読み上げ機能はガソリン タンカーのようなもので、大量のガソリンを高速で送り込み、ガソリン スタンドの奥にあるガソリン タンクを満タンにします。その後、ガソリンは顧客の車や他の車両に、はるかに遅い速度で供給されます。


要約すると、テキストから音声 (オーディオ) への変換は、はるかに高速に実行できます。バッファを埋めるために、テキストから音声 (TTS) へのオーディオを受信するオーディオ バッファが必要です。このバッファは、人間の発話の速度で空になり、人間が理解できるようになります。


オーディオ データ:データは、一定の間隔 (サンプリング レートと呼ばれる) でオーディオ信号の値を表す一連の数値で構成されます。また、複数の値のシーケンスを生成する複数のオーディオ信号であるチャンネルの概念もあります。


この記事では、入力側の 1 つのチャネルと出力側の 1 つのチャネルのみを検討します。


ナンピー:これは、パフォーマンスが最適化された数値配列の保存/取得を容易にするソフトウェアです。

デザイン:

要件は、任意の数のオーディオ データ フレーム (フレームはオーディオ データ ポイントを表す番号) を入力できることです。これは、オーディオ信号値の順序付けられた配列です。出力側では、これらのフレームを任意の数だけ取得できます。もちろん、制限されたバッファー サイズ (入力時にバッファーがいっぱいになる)、使用可能なオーディオ データがない (出力側でバッファーが空) などの制限に対処するための便利な機能を追加する必要があります。その他の便利な機能には、バッファー取得で使用可能な量よりも多くのオーディオ データが要求された場合に、オーディオ データをゼロで埋める機能が含まれます。

実装:

以下は、Python でのこのようなバッファの実装について説明します。


着信オーディオ バイトはバッファーに格納されます。バッファーには、バッファーが満たされた範囲を示す「ボトム」ポインターがあります。また、「開始ポインター」もあり、これは新しいデータをプッシュできるバッファーの先頭です。開始ポインターはバッファーの先頭に固定されています。ボトム ポインターは「動的」で、「上下」します。データが抽出されると上昇し、データが挿入されると「下降」します。データは常にバッファーの上部 (開始ポインター) に挿入されるため、バッファー内の既存のデータは「下」にプッシュされ、ボトム ポインターの値が増加します。


バッファ空の状態は、下部ポインタが開始ポインタと等しいときに発生します。バッファ満杯の状態は、下部ポインタがバッファの長さと等しいときに発生します。


バッファがいっぱいになった状況に対処するために、「正常な失敗」を含めることもできます。


バッファがいっぱいでデータを挿入する必要がある場合は、例外を発生させます。バッファが空の場合 (バッファにあるデータよりも多くのデータが要求された場合を含む)、不足しているデータに対して「ゼロ」を返します。これは、言葉が話されていないときの「無音」に相当するオーディオです。


このバッファの図は次のとおりです。


コーディング: (免責事項: 以下のコードを生成するために AI は使用されていません。すべての責任(賞賛の方が良い)は著者に帰属します。)


オブジェクト指向の原則に従って、コードはクラス/オブジェクトとして記述されており、使いやすいです。コード全体は次のとおりです。


 import numpy as np #numpy is the standard package or numerical array processing class AudioBuf: def __init__(self,bufSize:int,name:str='',dtype=np.int16): self.buffer = np.zeros((bufSize), dtype=dtype) self.bufSize=bufSize self.dtype=dtype self.idx=0 self.name=name #give a name to the buffer. def putInBuf(self,inData:np.ndarray[np.dtype[np.int16]]): inData=inData[:, 0] #Get the 1st col = channel 0 - mono remainder = self.bufSize - self.idx #space available for insertion if remainder < len(inData): msg=f'Error: Buffer {self.name} is full' print(msg) self.showBuf() raise ValueError(msg) self.buffer[self.idx:self.idx + len(inData)] = inData self.idx += len(inData) def getFromBuf(self,outDataLen:int = None)->np.ndarray: if not outDataLen: outDataLen=self.idx # return entire data of length is not specified if self.idx >= outDataLen: retVal = self.buffer[:outDataLen] self.buffer[0:self.idx-outDataLen]=self.buffer[outDataLen:self.idx] #move buffer up self.idx -= outDataLen else: retVal=np.zeros((outDataLen), dtype=self.dtype) retVal[0:self.idx] = self.buffer[0:self.idx] self.idx=0 return np.reshape(retVal,(-1,1)) #The -1 value automatically calculates to the number of elements def showBuf(self): print(f'AudioBuf : {self.name} has length= {self.idx} with capacity {self.bufSize}')

結論:

オーディオ バッファリングは不可欠であり、多数のオーディオ処理アプリケーションにより、ますます重要になっています。上記で紹介したオーディオ バッファ アルゴリズムは、便利な Python クラスです。