private int[][] readSamples(ByteBuffer buf) {
        // calculate the number of samples in the table
        int size = 1;
        for (int i = 0; i < getNumInputs(); i++) {
            size *= getSize(i);
        }
        
        // create the samples table
        int[][] samples = new int[size][getNumOutputs()];
        
        
        // the current location in the buffer, in bits from byteLoc
        int bitLoc = 0;
          
        // the current location in the buffer, in bytes
        int byteLoc = 0;
      
        // the current index in the samples array
        int index = 0;
        
        for (int i = 0; i < getNumInputs(); i++) {
            for (int j = 0; j < getSize(i); j++) {
                for (int k = 0; k < getNumOutputs(); k++) {
                    /** [JK FIXME one bit at a time is really inefficient */
                    int value = 0;
                    
                    int toRead = getBitsPerSample();
                    byte curByte = buf.get(byteLoc);
                    
                    while (toRead > 0) {
                        int nextBit = ((curByte >> (7 - bitLoc)) & 0x1);
                        value |= nextBit << (toRead - 1);
                        
                        if (++bitLoc == 8) {
                            bitLoc = 0;
                            byteLoc++;
                            
                            if (toRead > 1) {
                                curByte = buf.get(byteLoc);
                            }
                        }
                        
                        toRead--;
                    }
                    
                    samples[index][k] = value;
                }
                
                index++;
            }
        }
        
        return samples;
    }