001/* This actor decompresses a vector quantized signal. 002 @Copyright (c) 1998-2014 The Regents of the University of California. 003 All rights reserved. 004 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the 008 above copyright notice and the following two paragraphs appear in all 009 copies of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION 2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.domains.sdf.lib.vq; 028 029import java.io.FileNotFoundException; 030import java.io.IOException; 031import java.io.InputStream; 032import java.net.MalformedURLException; 033import java.net.URL; 034 035import ptolemy.actor.lib.Transformer; 036import ptolemy.data.IntMatrixToken; 037import ptolemy.data.IntToken; 038import ptolemy.data.StringToken; 039import ptolemy.data.expr.Parameter; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.CompositeEntity; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NameDuplicationException; 044import ptolemy.kernel.util.Workspace; 045import ptolemy.math.IntegerMatrixMath; 046import ptolemy.util.FileUtilities; 047 048/////////////////////////////////////////////////////////////////// 049//// VQDecode 050 051/** 052 This actor decompresses a vector quantized signal. This operation is simply 053 a table lookup into the codebook. 054 055 @see HTVQEncode 056 057 @author Steve Neuendorffer 058 @version $Id$ 059 @since Ptolemy II 0.2 060 @Pt.ProposedRating Yellow (neuendor) 061 @Pt.AcceptedRating Red 062 */ 063 064// FIXME This should be generalized to a Table-lookup actor. 065public class VQDecode extends Transformer { 066 /** Construct an actor in the specified container with the specified 067 * name. 068 * @param container The container. 069 * @param name The name of this adder within the container. 070 * @exception IllegalActionException If the actor cannot be contained 071 * by the proposed container. 072 * @exception NameDuplicationException If the name coincides with 073 * an actor already in the container. 074 */ 075 public VQDecode(CompositeEntity container, String name) 076 throws IllegalActionException, NameDuplicationException { 077 super(container, name); 078 079 input.setTypeEquals(BaseType.INT); 080 081 output.setTypeEquals(BaseType.INT_MATRIX); 082 083 codeBook = new Parameter(this, "codeBook", new StringToken( 084 "/ptolemy/domains/sdf" + "/lib/vq/data/usc_hvq_s5.dat")); 085 codeBook.setTypeEquals(BaseType.STRING); 086 087 blockCount = new Parameter(this, "blockCount", new IntToken("1")); 088 blockCount.setTypeEquals(BaseType.INT); 089 090 blockWidth = new Parameter(this, "blockWidth", new IntToken("4")); 091 blockWidth.setTypeEquals(BaseType.INT); 092 093 blockHeight = new Parameter(this, "blockHeight", new IntToken("2")); 094 blockHeight.setTypeEquals(BaseType.INT); 095 096 input_tokenConsumptionRate = new Parameter(input, 097 "tokenConsumptionRate"); 098 input_tokenConsumptionRate.setTypeEquals(BaseType.INT); 099 input_tokenConsumptionRate.setExpression("blockCount"); 100 101 output_tokenProductionRate = new Parameter(output, 102 "tokenProductionRate"); 103 output_tokenProductionRate.setTypeEquals(BaseType.INT); 104 output_tokenProductionRate.setExpression("blockCount"); 105 } 106 107 /////////////////////////////////////////////////////////////////// 108 //// ports and parameters //// 109 110 /** A Parameter of type String, giving the location of the codebook data 111 * file relative to the root classpath. 112 */ 113 public Parameter codeBook; 114 115 /** The number of blocks to be decoded during each firing. 116 * The default value is one, which will always work, but using a higher 117 * number (such as the number of blocks in a frame) will speed things up. 118 * This should contain an integer. 119 */ 120 public Parameter blockCount; 121 122 /** The width, in integer pixels, of the block to decode. */ 123 public Parameter blockWidth; 124 125 /** The width, in integer pixels, of the block to decode. */ 126 public Parameter blockHeight; 127 128 /** The input rate. */ 129 public Parameter input_tokenConsumptionRate; 130 131 /** The output rate. */ 132 public Parameter output_tokenProductionRate; 133 134 /////////////////////////////////////////////////////////////////// 135 //// public methods //// 136 137 /** Clone the actor into the specified workspace. 138 * @param workspace The workspace for the new object. 139 * @return A new actor. 140 * @exception CloneNotSupportedException If a derived class contains 141 * an attribute that cannot be cloned. 142 */ 143 @Override 144 public Object clone(Workspace workspace) throws CloneNotSupportedException { 145 VQDecode newObject = (VQDecode) super.clone(workspace); 146 newObject._codebook = new int[6][256][][]; 147 return newObject; 148 } 149 150 /** 151 * Fire this actor. 152 * Consume a number of tokens on the input port, each representing a 153 * VQ codeword. Index into the appropriate codebook given by the 154 * blockWidth and blockHeight parameters to find the decoded vector for 155 * each codeword. Output an IntMatrixToken representing each decoded 156 * vector on the output port. 157 * @exception IllegalActionException If the input or output are not 158 * connected 159 * @exception ArrayIndexOutOfBoundsException If the input codewords are 160 * not between 0 and 255. 161 */ 162 @Override 163 public void fire() throws IllegalActionException { 164 super.fire(); 165 int j; 166 int stage = _stages(_blockWidth * _blockHeight); 167 _codewords = input.get(0, _blockCount); 168 169 for (j = 0; j < _blockCount; j++) { 170 _blocks[j] = new IntMatrixToken( 171 _codebook[stage][((IntToken) _codewords[j]).intValue()]); 172 } 173 174 output.send(0, _blocks, _blocks.length); 175 } 176 177 /** 178 * Initialize this actor. 179 * Load the codebooks and lookup tables from the file given by the 180 * parameter "codeBook". 181 * @exception IllegalActionException If the parameters do not have 182 * legal values, or the codebook file cannot be read. 183 */ 184 @Override 185 public void initialize() throws IllegalActionException { 186 super.initialize(); 187 188 InputStream source = null; 189 190 _blockCount = ((IntToken) blockCount.getToken()).intValue(); 191 _blockWidth = ((IntToken) blockWidth.getToken()).intValue(); 192 _blockHeight = ((IntToken) blockHeight.getToken()).intValue(); 193 194 _codewords = new ptolemy.data.Token[_blockCount]; 195 _blocks = new IntMatrixToken[_blockCount]; 196 197 String filename = ((StringToken) codeBook.getToken()).stringValue(); 198 199 try { 200 if (filename != null) { 201 try { 202 URL dataurl = FileUtilities.nameToURL(filename, null, 203 getClass().getClassLoader()); 204 _debug("VQDecode: codebook = " + dataurl); 205 source = dataurl.openStream(); 206 } catch (MalformedURLException e) { 207 System.err.println(e.toString()); 208 } catch (FileNotFoundException e) { 209 System.err.println("File not found: " + e); 210 } catch (IOException e) { 211 throw new IllegalActionException( 212 "Error reading" + " input file: " + e.getMessage()); 213 } 214 } 215 216 int i; 217 int j; 218 int x; 219 int size = 1; 220 byte[] temp; 221 int[] intTemp; 222 int rows = 1; 223 int columns = 1; 224 225 for (i = 0; i < 5; i++) { 226 size = size * 2; 227 228 if (i % 2 == 0) { 229 columns = columns * 2; 230 } else { 231 rows = rows * 2; 232 } 233 234 temp = new byte[size]; 235 intTemp = new int[size]; 236 237 for (j = 0; j < 256; j++) { 238 if (_fullRead(source, temp) != size) { 239 throw new IllegalActionException( 240 "Error reading " + "codebook file!"); 241 } 242 243 for (x = 0; x < size; x++) { 244 intTemp[x] = temp[x] & 255; 245 } 246 247 _codebook[i][j] = IntegerMatrixMath 248 .toMatrixFromArray(intTemp, rows, columns); 249 } 250 251 // skip over the lookup tables. 252 temp = new byte[65536]; 253 254 // read in the lookup table. 255 if (_fullRead(source, temp) != 65536) { 256 throw new IllegalActionException( 257 "Error reading " + "codebook file!"); 258 } 259 } 260 } catch (Exception e) { 261 throw new IllegalActionException(e.getMessage()); 262 } finally { 263 if (source != null) { 264 try { 265 source.close(); 266 } catch (IOException e) { 267 } 268 } 269 } 270 } 271 272 /////////////////////////////////////////////////////////////////// 273 //// private methods //// 274 private int _fullRead(InputStream s, byte[] b) throws IOException { 275 int length = 0; 276 int remaining = b.length; 277 int bytesRead = 0; 278 279 while (remaining > 0) { 280 bytesRead = s.read(b, length, remaining); 281 282 if (bytesRead == -1) { 283 throw new IOException("Unexpected EOF"); 284 } 285 286 remaining -= bytesRead; 287 length += bytesRead; 288 } 289 290 return length; 291 } 292 293 /** Given a vector of the given length, compute the codebook stage 294 * appropriate. Basically, compute log base 2 of length, assuming 295 * length is a power of 2. 296 */ 297 private int _stages(int length) { 298 int x = 0; 299 300 if (length < 2) { 301 throw new RuntimeException( 302 "Vector length of " + length + "must be greater than 1"); 303 } 304 305 while (length > 2) { 306 length = length >> 1; 307 x++; 308 } 309 310 return x; 311 } 312 313 private int[][][][] _codebook = new int[6][256][][]; 314 315 private ptolemy.data.Token[] _codewords; 316 317 private IntMatrixToken[] _blocks; 318 319 private int _blockCount; 320 321 private int _blockWidth; 322 323 private int _blockHeight; 324}