Pythonのなみのり! ぱーと2

前回、と言っても相当前ですけど、Pythonでwavファイルを読み込むってのを記事にしました。
今回はその焼き直しですが、かなり仕様みたいのは買えました。
いちいちキー指定なんてしてらんねーよ。
と、自分でも思ったので。


オブジェクト指向的なプログラミングを意識したつもりなんですが、そもそもオブジェクト指向を理解していないので、全然違う実装になっていると思います。


ソースは以下。
struct.unpackのくだりが遅いのは相変わらず。
格納をリストではなく文字列にしたり、ファイルの読み込みの段階からunpackしたりして実効速度の向上を図ってみましたが、結局この方法に落ち着きました。


コメントの英語に対するツッコミはご遠慮願います。

ソースコード

#!/usr/bin/env python
#coding: utf-8

import struct

class wavUtils(object):
    """
    This class is utilities for wav file.  At first, you make instance
    this class. Then, use "load" method for reading a wav file.
    """
    def __init__(self):
        self.__raw = None
        self.__raw_data = None
        self.__raw_header = None
        self.__unpacked_header = None
        self.__unpacked_data = None
        self.__meta_data = None

    def getDataList(self):
        return self.__unpacked_data

    def getHeaderList(self):
        return self.__unpacked_header

    def getPropertyList(self):
        return self.__meta_data

    def getRawStr(self):
        return self.__raw

    def getRawDataStr(self):
        return self.__raw_data

    def getRawHeaderStr(self):
        return self.__raw_header

    def load(self, fname):
        """
        At first, loading wav file in self.__raw. Then, separates
        self.__raw for header part and date part. Last, unpack binary
        data for int. Unpacking data needs time.
        """
        fp = open(fname, "rb")
        self.__raw = fp.read()
        fp.close()
        # separate header part and data part.
        header_end = self.__raw.find('data')+8
        self.__raw_header = self.__raw[:header_end]
        self.__raw_data = self.__raw[header_end:]
        # unpacked header and data
        self.__unpackRawHeader()
        self.__unpackRawData()

    def __unpackRawData(self):
        seek_head = 0
        tmp_result = []
        # counter tool's values
        cnt = 1
        cnt_delta = len(self.__raw_data)/10
        # 16 bit/sample? 8 bit/sample?
        if self.__unpacked_header[7] == 8:
            unpack_fmt = '<H'
            seek_delta = 1
        else:
            unpack_fmt = '<h'
            seek_delta = 2

        print "Now converting that binary for Integer..."
        while seek_head < len(self.__raw_data):
            tmp_result.append(struct.unpack(unpack_fmt, self.__raw_data[seek_head:seek_head+seek_delta])[0])
            seek_head += seek_delta
            # counter tool's implements
            if seek_head >= (cnt_delta*cnt):
                for i in range(cnt):
                    print ".",
                if cnt==10:
                    print cnt*10, "% done. Converting finish!"
                else:
                    print cnt*10, "% done."
                cnt+=1

        self.__unpacked_data = tmp_result

    def __unpackRawHeader(self):
        """
        This method unpack header from binary for int. And after
        unpacking, this makes property list.
        """
        tmp_result = []
        for current_chunk in ('RIFF','fmt','data'):
            tmp_value = 0
            seek_head = self.__raw_header.find(current_chunk)
            if current_chunk == 'fmt':
                seek_head += 4
                for seek_delta in (4,2,2,4,4,2,2):
                    if seek_delta == 4:
                        tmp_value = struct.unpack('<I',self.__raw_header[seek_head:seek_head+seek_delta])[0]
                    else:
                        tmp_value = struct.unpack('<H',self.__raw_header[seek_head:seek_head+seek_delta])[0]
                    seek_head += seek_delta
                    tmp_result.append(tmp_value)
            else:
                tmp_value = struct.unpack('<I',self.__raw_header[seek_head+4:seek_head+8])[0]
                tmp_result.append(tmp_value)

        self.__unpacked_header = tmp_result

        # Make property list.
        tmp_result = []
        wav_head_ref = ("File size (minus 8 byte).", "fmt chunk size", "FormatID",
                        "channel", "sampling rate", "Byte/sec",
                        "block size(Byte/sample*channel)",
                        "bit number(bit/sample)", "data size")
        for i in range(len(self.__unpacked_header)):
            tmp_result.append((wav_head_ref[i], self.__unpacked_header[i]))
        # add information of "bit rate".
        tmp_result.append(("bit rate (Byte/sec*8)", self.__unpacked_header[5]*8))

        self.__meta_data = tmp_result

def main():
    wu = wavUtils()
    wu.load("sample.wav")
    print wu.getRawStr()[0:5], wu.getRawHeaderStr(), wu.getHeaderList()[7]
    print wu.getDataList()[100000:100100]
    print wu.getPropertyList()

if __name__ == "__main__":
    main()

あとがき

まあ、前回掲載したものよりは、使いやすいと思います。
ソースも、心なしすっきりしたように見えます。
ああ、気のせいですか、そうですか。


オブジェクト指向って、こういうのじゃないのかなぁ……