7

PCM データを表示するプログラムを作成しようとしています。適切なレベルの抽象化を備えたライブラリを見つけようとして非常にイライラしましたが、python wave ライブラリを見つけて使用しています。ただし、データの解釈方法がわかりません。

wave.getparams 関数は (2 チャネル、2 バイト、44100 Hz、96333 フレーム、圧縮なし、圧縮なし) を返します。これはすべて陽気なようですが、4バイトの単一フレーム '\xc0\xff\xd0\xff' を印刷してみました。フレームが 2 つのサンプルである可能性はあると思いますが、あいまいさはそれだけではありません。

96333 フレーム * 2 サンプル/フレーム * (1/44.1k 秒/サンプル) = 4.3688 秒

ただし、iTunes は 2 秒に近い時間を報告しており、ファイル サイズとビットレートに基づく計算は 2.7 秒とほぼ同じです。何が起きてる?

さらに、バイトが署名されているか署名されていないかを知るにはどうすればよいですか?

どうもありがとう!

4

6 に答える 6

20

ご協力ありがとうございました!私はそれを機能させました。他の貧しい魂がそれを必要とする場合に備えて、誰もが使用できるように、ここにソリューションを投稿します。

import wave
import struct

def pcm_channels(wave_file):
    """Given a file-like object or file path representing a wave file,
    decompose it into its constituent PCM data streams.

    Input: A file like object or file path
    Output: A list of lists of integers representing the PCM coded data stream channels
        and the sample rate of the channels (mixed rate channels not supported)
    """
    stream = wave.open(wave_file,"rb")

    num_channels = stream.getnchannels()
    sample_rate = stream.getframerate()
    sample_width = stream.getsampwidth()
    num_frames = stream.getnframes()

    raw_data = stream.readframes( num_frames ) # Returns byte data
    stream.close()

    total_samples = num_frames * num_channels

    if sample_width == 1: 
        fmt = "%iB" % total_samples # read unsigned chars
    elif sample_width == 2:
        fmt = "%ih" % total_samples # read signed 2 byte shorts
    else:
        raise ValueError("Only supports 8 and 16 bit audio formats.")

    integer_data = struct.unpack(fmt, raw_data)
    del raw_data # Keep memory tidy (who knows how big it might be)

    channels = [ [] for time in range(num_channels) ]

    for index, value in enumerate(integer_data):
        bucket = index % num_channels
        channels[bucket].append(value)

    return channels, sample_rate
于 2010-02-09T06:18:05.923 に答える
10

「2 チャンネル」はステレオを意味するため、各チャンネルの長さを合計しても意味がありません。したがって、2 倍 (4.37 秒ではなく 2.18 秒) ずれています。署名については、たとえばここで説明されているように、次のように引用します。

8 ビットのサンプルは、0 ~ 255 の範囲の符号なしバイトとして格納されます。16 ビットのサンプルは、-32768 ~ 32767 の範囲の 2 の補数の符号付き整数として格納されます。

これは WAV 形式 (実際にはそのスーパーセット RIFF) の仕様の一部であるため、WAV ファイルを処理するために使用しているライブラリに依存しません。

于 2010-02-09T05:15:36.373 に答える
4

回答がすでに受け入れられていることは知っていますが、少し前にオーディオでいくつかのことを行ったので、このようなことをしてウェーブをアンパックする必要があります。

pcmdata = wave.struct.unpack("%dh"%(wavedatalength),wavedata)

また、私が使用した 1 つのパッケージは PyAudio と呼ばれていましたが、それでも wave パッケージを使用する必要がありました。

于 2010-02-09T05:52:49.890 に答える
2

この回答に基づいて、 numpy.fromstringまたはnumpy.fromfileを使用することで、パフォーマンスを大幅に向上させることができます。この回答も参照してください。

これが私がしたことです:

def interpret_wav(raw_bytes, n_frames, n_channels, sample_width, interleaved = True):

    if sample_width == 1:
        dtype = np.uint8 # unsigned char
    elif sample_width == 2:
        dtype = np.int16 # signed 2-byte short
    else:
        raise ValueError("Only supports 8 and 16 bit audio formats.")

    channels = np.fromstring(raw_bytes, dtype=dtype)

    if interleaved:
        # channels are interleaved, i.e. sample N of channel M follows sample N of channel M-1 in raw data
        channels.shape = (n_frames, n_channels)
        channels = channels.T
    else:
        # channels are not interleaved. All samples from channel M occur before all samples from channel M-1
        channels.shape = (n_channels, n_frames)

    return channels

データをメモリにコピーする必要がある場合、形状に新しい値を割り当てるとエラーがスローされます。これは、データをその場で使用したい (全体的に少ない時間とメモリを使用する) ため、良いことです。ndarray.T 関数も可能であればコピーしません (つまり、ビューを返します) が、コピーしないことを保証する方法がわかりません。

np.fromfile を使用してファイルから直接読み取るとさらに効果的ですが、カスタム dtype を使用してヘッダーをスキップする必要があります。私はまだこれを試していません。

于 2015-07-25T11:16:16.747 に答える
2

継続時間は、単純にフレーム数を 1 秒あたりのフレーム数で割ったものです。あなたのデータから、これは次のとおり96333 / 44100 = 2.18 secondsです。

于 2010-02-09T05:21:32.013 に答える
2

各サンプルは 16 ビットで 2 チャネルあるため、フレームは 4 バイトかかります

于 2010-02-09T05:17:05.000 に答える