Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Understanding ArrayBuffer, Float32Array, and Uint8Array for Binary Data Handling

Notes 2

The ArrayBuffer object represents a fixed-length raw binary data buffer. It is a generic container for a sequence of bytes.

const dataBuffer = new ArrayBuffer(16); // Allocates 16 bytes of memory
console.log(dataBuffer.byteLength);     // 16

Once created, an ArrayBuffer cannot be resized. However, you can create a new buffer containing a portion of the original data using the slice method.

const originalBuffer = new ArrayBuffer(16);
const slicedBuffer = originalBuffer.slice(4, 12);
console.log(slicedBuffer.byteLength);   // 8

Float32Array is a typed array that provides a view into an ArrayBuffer for storing 32-bit floating-point numbers. It has a fixed length.

Fixed Length Demonstration:

let floatArray = new Float32Array(2);
floatArray[0] = 10.5;
floatArray[1] = 20.3;
floatArray[2] = 30.7; // This assignment is ignored; index is out of bounds.
console.log(floatArray); // Float32Array(2) [10.5, 20.3]

Unlike a regular JavaScript Array, a Float32Array cannot dynamically grow.

Numeric Type Enforcement: The array only accepts numeric values. Non-numeric assignments result in NaN.

let numericArray = new Float32Array(3);
numericArray[0] = 100;
numericArray[1] = "text"; // Converts to NaN
numericArray[2] = true;    // Converts to 1 (boolean true becomes 1)
console.log(numericArray); // Float32Array(3) [100, NaN, 1]

Creating a Float32Array:

  1. By specifying a length (elements initilaize to 0):
    let arrByLength = new Float32Array(5);
    console.log(arrByLength); // Float32Array(5) [0, 0, 0, 0, 0]
    
  2. From a standard array:
    let arrFromStandard = new Float32Array([5.1, 10.2, 15.3]);
    console.log(arrFromStandard); // Float32Array(3) [5.1, 10.2, 15.3]
    
    Non-numeric elements in the source array become NaN.
    let arrWithMixed = new Float32Array([9, null, {}, [1,2]]);
    console.log(arrWithMixed); // Float32Array(4) [9, 0, NaN, NaN]
    
  3. From another typed array (creates a copy):
    let sourceArray = new Float32Array([1.5, 2.5]);
    let copiedArray = new Float32Array(sourceArray);
    console.log(copiedArray); // Float32Array(2) [1.5, 2.5]
    

Properties:

  • length: The number of elements in the array.
    let demoArray = new Float32Array(7);
    console.log(demoArray.length); // 7
    
  • BYTES_PER_ELEMENT: Returns the size, in bytes, of each element.
    console.log(Float32Array.BYTES_PER_ELEMENT); // 4
    
  • buffer: A read-only reference to the underlying ArrayBuffer.
    let fArray = new Float32Array(4);
    console.log(fArray.buffer instanceof ArrayBuffer); // true
    console.log(fArray.buffer.byteLength); // 16 (4 elements * 4 bytes each)
    

Uint8Array represents an array of 8-bit unsigned integers. Its behavior is similar to Float32Array but each element is a single byte (0 to 255).

// Create from a length
let uintArr = new Uint8Array(3);
uintArr[0] = 255;
console.log(uintArr[0]); // 255
console.log(uintArr.length); // 3
console.log(Uint8Array.BYTES_PER_ELEMENT); // 1

// Create from an array
let fromList = new Uint8Array([40, 80, 160]);
console.log(fromList[2]); // 160

// Create from another TypedArray
let original = new Uint8Array([10, 20, 30]);
let duplicate = new Uint8Array(original);
console.log(duplicate[1]); // 20

// Create a view on a specific portion of an ArrayBuffer
let mainBuffer = new ArrayBuffer(10);
let partialView = new Uint8Array(mainBuffer, 2, 5); // Offset 2 bytes, length 5 elements
console.log(partialView.length); // 5

// Create from an iterable
function* numberGenerator() { yield* [99, 199, 299]; }
let fromIterable = new Uint8Array(numberGenerator());
console.log(fromIterable); // Uint8Array(3) [99, 199, 43] (299 is clamped to 255)

Data Conversion Between Types:

Covnerting Uint8Array data (byte values 0-255) to normalized Float32Array data (often in the range -1.0 to 1.0 for audio processing).

function normalizeAudioData(inputData) {
    // Input can be an ArrayBuffer or a Uint8Array
    const byteArray = inputData instanceof Uint8Array ? inputData : new Uint8Array(inputData);
    const sampleCount = byteArray.length;
    const floatArray = new Float32Array(sampleCount);

    for (let i = 0; i < sampleCount; i++) {
        // Map unsigned byte (0-255) to signed float (-1.0 to ~0.992)
        floatArray[i] = (byteArray[i] - 128) / 128.0;
    }
    return floatArray;
}

// Example usage with an ArrayBuffer
const testBuffer = new ArrayBuffer(4);
const testView = new Uint8Array(testBuffer);
testView.set([0, 128, 255, 64]);
const normalizedFloats = normalizeAudioData(testBuffer);
console.log(normalizedFloats); // Float32Array(4) [-1, 0, 0.9921875, -0.5]

// Example usage directly with a Uint8Array
const directUintArray = new Uint8Array([32, 192]);
const normalizedDirect = normalizeAudioData(directUintArray);
console.log(normalizedDirect); // Float32Array(2) [-0.75, 0.5]

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.