1 # Copyright (c) 2006 Carnegie Mellon University
3 # You may copy and modify this freely under the same terms as
6 """Read/write Sphinx-III binary parameter files.
8 All the various binary parameter files created by SphinxTrain and used
9 by Sphinx-III and PocketSphinx share a common file format. This
10 module contains some base classes for reading and writing these files.
13 __author__ = "David Huggins-Daines <dhuggins@cs.cmu.edu>"
14 __version__ = "$Revision: 8994 $"
16 from struct import unpack, pack
17 from numpy import array,reshape,shape,fromstring
20 "Read Sphinx-III binary files"
21 def __init__(self, filename=None, mode="rb"):
23 self.open(filename, mode)
28 def __getitem__(self, key):
29 return self._params[key]
31 def __setitem__(self, key, value):
32 self._params[key] = value
34 def __delitem__(self, key):
38 return iter(self._params)
41 return len(self._params)
43 def open(self, filename, mode="rb"):
44 self.filename = filename
45 self.fh = file(filename, mode)
50 Read binary header. Sets the following attributes:
52 - fileattr (a dictionary of attribute-value pairs)
53 - swap (a byteswap string as used by the struct module)
54 - otherend (a flag indicating if the file is wrong-endian
55 for the current platform)
56 - data_start (offset of the start of data in the file)
58 spam = self.fh.readline()
61 raise Exception("File ID not found or invalid: " + spam)
63 spam = self.fh.readline()
65 raise Exception("EOF while reading headers")
66 if spam.endswith("endhdr\n"):
69 k = spam[0:sp].strip()
72 # This is 0x11223344 in the file's byte order
73 spam = unpack("<i", self.fh.read(4))[0]
74 if spam == 0x11223344:
75 self.swap = "<" # little endian
76 elif spam == 0x44332211:
77 self.swap = ">" # big endian
79 raise Exception("Invalid byte-order mark %08x" % spam)
80 # Now determine whether we need to swap to get to native
81 # byteorder (shouldn't this be easier???)
82 self.otherend = (unpack('=i', pack(self.swap + 'i', spam))[0] != spam)
83 self.data_start = self.fh.tell()
86 self.d1 = unpack(self.swap + "I", self.fh.read(4))[0]
87 self.d2 = unpack(self.swap + "I", self.fh.read(4))[0]
88 self.d3 = unpack(self.swap + "I", self.fh.read(4))[0]
89 self._nfloats = unpack(self.swap + "I", self.fh.read(4))[0]
90 if self._nfloats != self.d1 * self.d2 * self.d3:
91 raise Exception(("Number of data points %d doesn't match "
92 + "total %d = %d*%d*%d")
95 self.d1 * self.d2 * self.d3,
96 self.d1, self.d2, self.d3))
97 spam = self.fh.read(self._nfloats * 4)
98 params = fromstring(spam, 'f')
100 params = params.byteswap()
101 return reshape(params, (self.d1, self.d2, self.d3)).astype('d')
104 self.d1 = unpack(self.swap + "I", self.fh.read(4))[0]
105 self.d2 = unpack(self.swap + "I", self.fh.read(4))[0]
106 self._nfloats = unpack(self.swap + "I", self.fh.read(4))[0]
107 if self._nfloats != self.d1 * self.d2:
108 raise Exception(("Number of data points %d doesn't match "
109 + "total %d = %d*%d")
114 spam = self.fh.read(self._nfloats * 4)
115 params = fromstring(spam, 'f')
117 params = params.byteswap()
118 return reshape(params, (self.d1, self.d2)).astype('d')
121 self.d1 = unpack(self.swap + "I", self.fh.read(4))[0]
122 self._nfloats = unpack(self.swap + "I", self.fh.read(4))[0]
123 if self._nfloats != self.d1:
124 raise Exception(("Number of data points %d doesn't match "
127 (self._nfloats, self.d1))
128 spam = self.fh.read(self._nfloats * 4)
129 params = fromstring(spam, 'f')
131 params = params.byteswap()
132 return params.astype('d')
135 "Write Sphinx-III binary files"
136 def __init__(self, filename=None, mode="wb", attr={"version":1.0}):
141 def open(self, filename):
142 self.filename = filename
143 self.fh = file(filename, "wb")
146 def writeheader(self):
147 self.fh.write("s3\n")
148 for k,v in self.fileattr.iteritems():
149 self.fh.write("%s %s\n" % (k,v))
150 # Make sure the binary data lives on a 4-byte boundary
151 lsb = (self.fh.tell() + len("endhdr\n")) & 3
154 self.fh.write("%sendhdr\n" % (" " * align))
156 self.fh.write("endhdr\n")
157 self.fh.write(pack("=i", 0x11223344))
158 self.data_start = self.fh.tell()
160 def write3d(self, stuff):
161 d1, d2, d3 = shape(stuff)
162 self.fh.write(pack("=IIII",
165 stuff.ravel().astype('f').tofile(self.fh)
167 def write2d(self, stuff):
168 d1, d2 = shape(stuff)
169 self.fh.write(pack("=III",
172 stuff.ravel().astype('f').tofile(self.fh)
174 def write1d(self, stuff):
176 self.fh.write(pack("=II", d1, d1))
177 stuff.ravel().astype('f').tofile(self.fh)