ringbuf.js
Version:
Wait-free thread-safe single-consumer single-producer ring buffer using SharedArrayBuffer.
1 lines • 39.7 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/audioqueue.ts","../src/param.ts","../src/ringbuf.ts"],"sourcesContent":["import type { RingBuffer } from \"./ringbuf.ts\";\n\n/**\n * Interleaved -> Planar audio buffer conversion\n *\n * This is useful to get data from a codec, the network, or anything that is\n * interleaved, into a planar format, for example a Web Audio API AudioBuffer or\n * the output parameter of an AudioWorkletProcessor.\n *\n * @param input is an array of n*128 frames arrays, interleaved,\n * where n is the channel count.\n * @param output is an array of 128-frames arrays.\n */\nexport function deinterleave(\n input: Float32Array,\n output: Float32Array[],\n): void {\n const channel_count = input.length / 128;\n if (output.length !== channel_count) {\n throw new RangeError(\n `not enough space in output arrays ${output.length} != ${channel_count}`,\n );\n }\n\n /* Original algorithm:\n\n for (let i = 0; i < channel_count; i++) {\n const out_channel = output[i];\n let interleaved_idx = i;\n for (let j = 0; j < 128; ++j) {\n out_channel[j] = input[interleaved_idx];\n interleaved_idx += channel_count;\n }\n }\n\n Optimized algorithm:\n */\n\n for (let i = 0; i < channel_count; i++) {\n const out_channel = output[i];\n let interleaved_idx = i;\n\n // Unroll the inner loop by processing 4 samples at a time\n // Best unroll factor in 2025 for this is 4: https://github.com/padenot/ringbuf.js/issues/22#issuecomment-2591073674\n for (let j = 0; j < 128; j += 4) {\n out_channel[j] = input[interleaved_idx];\n out_channel[j + 1] = input[interleaved_idx + channel_count];\n out_channel[j + 2] = input[interleaved_idx + 2 * channel_count];\n out_channel[j + 3] = input[interleaved_idx + 3 * channel_count];\n interleaved_idx += 4 * channel_count;\n }\n }\n}\n\n/**\n * Planar -> Interleaved audio buffer conversion\n *\n * This function is useful to get data from the Web Audio API (that uses a\n * planar format), into something that a codec or network streaming library\n * would expect.\n *\n * @param input An array of n*128 frames Float32Array that hold the audio data.\n * @param output A Float32Array that is n*128 elements long.\n */\nexport function interleave(input: Float32Array[], output: Float32Array): void {\n if (input.length * 128 !== output.length) {\n throw new RangeError(\"input and output of incompatible sizes\");\n }\n\n // this algo, as of 2025 does not benefit from loop unrolling\n // https://github.com/padenot/ringbuf.js/issues/22#issuecomment-2591103602\n let out_idx = 0;\n for (let i = 0; i < 128; i++) {\n for (let channel = 0; channel < input.length; channel++) {\n output[out_idx] = input[channel][i];\n out_idx++;\n }\n }\n}\n\n/**\n * Send interleaved audio frames to another thread, wait-free.\n *\n * These classes allow communicating between a non-real time thread (browser\n * main thread or worker) and a real-time thread (in an AudioWorkletProcessor).\n * Write and Reader cannot change role after setup, unless externally\n * synchronized.\n *\n * GC _can_ happen during the initial construction of this object when hopefully\n * no audio is being output. This depends on how implementations schedule GC\n * passes. After the setup phase no GC is triggered on either side of the queue.\n */\nexport class AudioWriter {\n private ringbuf: RingBuffer;\n\n /**\n * From a RingBuffer, build an object that can enqueue enqueue audio in a ring\n * buffer.\n */\n constructor(ringbuf: RingBuffer) {\n if (ringbuf.type() !== \"Float32Array\") {\n throw new TypeError(\"This class requires a ring buffer of Float32Array\");\n }\n this.ringbuf = ringbuf;\n }\n\n /**\n * Enqueue a buffer of interleaved audio into the ring buffer.\n *\n * Care should be taken to enqueue a number of samples that is a multiple of the\n * channel count of the audio stream.\n *\n * @param buf An array of interleaved audio frames.\n *\n * @return The number of samples that have been successfully written to the\n * queue. `buf` is not written to during this call, so the samples that\n * haven't been written to the queue are still available.\n */\n enqueue(buf: Float32Array): number {\n return this.ringbuf.push(buf);\n }\n\n /**\n * @deprecated Use availableWrite() instead. This method is deprecated and will be removed in future versions.\n */\n available_write(): number {\n return this.availableWrite();\n }\n\n /**\n * @return The free space in the ring buffer. This is the amount of samples\n * that can be queued, with a guarantee of success.\n */\n availableWrite(): number {\n return this.ringbuf.availableWrite();\n }\n}\n\n/**\n * Receive interleaved audio frames to another thread, wait-free.\n *\n * GC _can_ happen during the initial construction of this object when hopefully\n * no audio is being output. This depends on how implementations schedule GC\n * passes. After the setup phase no GC is triggered on either side of the queue.\n */\nexport class AudioReader {\n private ringbuf: RingBuffer;\n\n /**\n * From a RingBuffer, build an object that can dequeue audio in a ring\n * buffer.\n */\n constructor(ringbuf: RingBuffer) {\n if (ringbuf.type() !== \"Float32Array\") {\n throw new TypeError(\"This class requires a ring buffer of Float32Array\");\n }\n this.ringbuf = ringbuf;\n }\n\n /**\n * Attempt to dequeue at most `buf.length` samples from the queue. This\n * returns the number of samples dequeued. If greater than 0, the samples are\n * at the beginning of `buf`.\n *\n * Care should be taken to dequeue a number of samples that is a multiple of the\n * channel count of the audio stream.\n *\n * @param buf A buffer in which to copy the dequeued\n * interleaved audio frames.\n * @return The number of samples dequeued.\n */\n dequeue(buf: Float32Array): number {\n if (this.ringbuf.empty()) {\n return 0;\n }\n return this.ringbuf.pop(buf);\n }\n\n /**\n * @deprecated Use availableRead() instead. This method is deprecated and will be removed in future versions.\n */\n available_read(): number {\n return this.availableRead();\n }\n\n /**\n * Query the occupied space in the queue.\n *\n * @return The amount of samples that can be read with a guarantee of success.\n */\n availableRead(): number {\n return this.ringbuf.availableRead();\n }\n}\n","import type { RingBuffer } from \"./ringbuf\";\n\n/**\n * Send parameter changes, lock free, no gc, between a UI thread (browser\n * main thread or worker) and a real-time thread (in an AudioWorkletProcessor).\n * Write and Reader cannot change roles after setup, unless externally\n * synchronized.\n *\n * GC _can_ happen during the initial construction of this object when hopefully\n * no audio is being output. This depends on the implementation.\n *\n * Parameter changes are like in the VST framework: an index and a float value\n * (no restriction on the value).\n *\n * This class supports up to 256 parameters, but this is easy to extend if\n * needed.\n *\n * An element is an index, that is an unsigned byte, and a float32, which is 4\n * bytes.\n */\nexport class ParameterWriter {\n private ringbuf: RingBuffer;\n private mem: ArrayBuffer;\n private array: Uint8Array;\n private view: DataView;\n\n /**\n * From a RingBuffer, build an object that can enqueue a parameter change in\n * the queue.\n * @param ringbuf A RingBuffer object of Uint8Array.\n */\n constructor(ringbuf: RingBuffer) {\n if (ringbuf.type() !== \"Uint8Array\") {\n throw new TypeError(\"This class requires a ring buffer of Uint8Array\");\n }\n const SIZE_ELEMENT = 5;\n this.ringbuf = ringbuf;\n this.mem = new ArrayBuffer(SIZE_ELEMENT);\n this.array = new Uint8Array(this.mem);\n this.view = new DataView(this.mem);\n }\n\n /**\n * Enqueue a parameter change for parameter of index `index`, with a new value\n * of `value`.\n *\n * @param index The index of the parameter.\n * @param value The value of the parameter.\n * @return True if enqueuing succeeded, false otherwise.\n */\n enqueueChange(index: number, value: number): boolean {\n const SIZE_ELEMENT = 5;\n if (this.ringbuf.availableWrite() < SIZE_ELEMENT) {\n return false;\n }\n this.view.setUint8(0, index);\n this.view.setFloat32(1, value);\n return this.ringbuf.push(this.array) === SIZE_ELEMENT;\n }\n\n /**\n * Enqueue a parameter change for parameter of index `index`, with a new value\n * of `value`.\n *\n * @param index The index of the parameter.\n * @param value The value of the parameter.\n * @return True if enqueuing succeeded, false otherwise.\n *\n * @deprecated\n */\n enqueue_change(index: number, value: number): boolean {\n return this.enqueueChange(index, value);\n }\n}\n\n/**\n * Receive parameter changes, lock free, no gc, between a UI thread (browser\n * main thread or worker) and a real-time thread (in an AudioWorkletProcessor).\n * Write and Reader cannot change roles after setup, unless externally\n * synchronized.\n *\n * GC _can_ happen during the initial construction of this object when hopefully\n * no audio is being output. This depends on the implementation.\n *\n * Parameter changes are like in the VST framework: an index and a float value\n * (no restriction on the value).\n *\n * This class supports up to 256 parameters, but this is easy to extend if\n * needed.\n *\n * An element is an index, that is an unsigned byte, and a float32, which is 4\n * bytes.\n */\nexport class ParameterReader {\n private ringbuf: RingBuffer;\n private mem: ArrayBuffer;\n private array: Uint8Array;\n private view: DataView;\n\n /**\n * @param ringbuf A RingBuffer setup to hold Uint8.\n */\n constructor(ringbuf: RingBuffer) {\n const SIZE_ELEMENT = 5;\n this.ringbuf = ringbuf;\n this.mem = new ArrayBuffer(SIZE_ELEMENT);\n this.array = new Uint8Array(this.mem);\n this.view = new DataView(this.mem);\n }\n\n /**\n * Attempt to dequeue a single parameter change.\n * @param o An object with two attributes: `index` and `value`.\n * @return true if a parameter change has been dequeued, false otherwise.\n */\n dequeueChange(o: { index: number; value: number }): boolean {\n if (this.ringbuf.empty()) {\n return false;\n }\n const rv = this.ringbuf.pop(this.array);\n o.index = this.view.getUint8(0);\n o.value = this.view.getFloat32(1);\n\n return rv === this.array.length;\n }\n\n /**\n * Attempt to dequeue a single parameter change.\n * @param o An object with two attributes: `index` and `value`.\n * @return true if a parameter change has been dequeued, false otherwise.\n *\n * @deprecated\n */\n dequeue_change(o: { index: number; value: number }): boolean {\n return this.dequeueChange(o);\n }\n}\n","import type {\n RingBufferWriteCallback,\n RingBufferWriteCallbackWithOffset,\n TypedArray,\n TypedArrayConstructor,\n} from \"./types\";\n\n/**\n * The base RingBuffer class\n *\n * A Single Producer - Single Consumer thread-safe wait-free ring buffer.\n *\n * The producer and the consumer can be on separate threads, but cannot change roles,\n * except with external synchronization.\n */\nexport class RingBuffer {\n /** Allocate the SharedArrayBuffer for a RingBuffer, based on the type and\n * capacity required\n * @param capacity The number of elements the ring buffer will be\n * able to hold.\n * @param type A typed array constructor, the type that this ring\n * buffer will hold.\n * @return A SharedArrayBuffer of the right size.\n */\n static getStorageForCapacity(\n capacity: number,\n type: TypedArrayConstructor,\n ): SharedArrayBuffer {\n if (!type.BYTES_PER_ELEMENT) {\n throw TypeError(\"Pass in an ArrayBuffer subclass\");\n }\n const bytes = 8 + (capacity + 1) * type.BYTES_PER_ELEMENT;\n return new SharedArrayBuffer(bytes);\n }\n\n private _type: TypedArrayConstructor;\n private _capacity: number;\n private buf: SharedArrayBuffer;\n private write_ptr: Uint32Array;\n private read_ptr: Uint32Array;\n private storage: TypedArray;\n\n /**\n * @param sab A SharedArrayBuffer obtained by calling\n * {@link RingBuffer.getStorageForCapacity}.\n * @param type A typed array constructor, the type that this ring\n * buffer will hold.\n */\n constructor(sab: SharedArrayBuffer, type: TypedArrayConstructor) {\n if (type.BYTES_PER_ELEMENT === undefined) {\n throw TypeError(\"Pass a concrete typed array class as second argument\");\n }\n\n // Maximum usable size is 1<<32 - type.BYTES_PER_ELEMENT bytes in the ring\n // buffer for this version, easily changeable.\n // -4 for the write ptr (uint32_t offsets)\n // -4 for the read ptr (uint32_t offsets)\n // capacity counts the empty slot to distinguish between full and empty.\n this._type = type;\n this._capacity = (sab.byteLength - 8) / type.BYTES_PER_ELEMENT;\n this.buf = sab;\n this.write_ptr = new Uint32Array(this.buf, 0, 1);\n this.read_ptr = new Uint32Array(this.buf, 4, 1);\n this.storage = new type(this.buf, 8, this._capacity);\n }\n\n /**\n * @return the type of the underlying ArrayBuffer for this RingBuffer. This\n * allows implementing crude type checking.\n */\n type(): string {\n return this._type.name;\n }\n\n /**\n * Push elements to the ring buffer.\n * @param elements A typed array of the same type as passed in the ctor, to be written to the queue.\n * @param length If passed, the maximum number of elements to push.\n * If not passed, all elements in the input array are pushed.\n * @param offset If passed, a starting index in elements from which\n * the elements are read. If not passed, elements are read from index 0.\n * @return the number of elements written to the queue.\n */\n push(elements: TypedArray, length?: number, offset = 0): number {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n if ((wr + 1) % this._storage_capacity() === rd) {\n // full\n return 0;\n }\n\n const len = length !== undefined ? length : elements.length;\n\n const to_write = Math.min(this._available_write(rd, wr), len);\n const first_part = Math.min(this._storage_capacity() - wr, to_write);\n const second_part = to_write - first_part;\n\n this._copy(elements, offset, this.storage, wr, first_part);\n this._copy(elements, offset + first_part, this.storage, 0, second_part);\n\n // publish the enqueued data to the other side\n Atomics.store(\n this.write_ptr,\n 0,\n (wr + to_write) % this._storage_capacity(),\n );\n\n return to_write;\n }\n\n /**\n * Write bytes to the ring buffer using callbacks. This create wrapper\n * objects and can GC, so it's best to no use this variant from a real-time\n * thread such as an AudioWorklerProcessor `process` method.\n * The callback is passed two typed arrays of the same type, to be filled.\n * This allows skipping copies if the API that produces the data writes is\n * passed arrays to write to, such as `AudioData.copyTo`.\n * @param amount The maximum number of elements to write to the ring\n * buffer. If amount is more than the number of slots available for writing,\n * then the number of slots available for writing will be made available: no\n * overwriting of elements can happen.\n * @param cb A callback with two parameters, that are two typed\n * array of the correct type, in which the data need to be copied. If the\n * callback doesn't return anything, it is assumed all the elements\n * have been written to. Otherwise, it is assumed that the returned number is\n * the number of elements that have been written to, and those elements have\n * been written started at the beginning of the requested buffer space.\n *\n * @return The number of elements written to the queue.\n */\n writeCallback(amount: number, cb: RingBufferWriteCallback) {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n if ((wr + 1) % this._storage_capacity() === rd) {\n // full\n return 0;\n }\n\n const to_write = Math.min(this._available_write(rd, wr), amount);\n const first_part = Math.min(this._storage_capacity() - wr, to_write);\n const second_part = to_write - first_part;\n\n // This part will cause GC: don't use in the real time thread.\n const first_part_buf = new this._type(\n this.storage.buffer,\n 8 + wr * this.storage.BYTES_PER_ELEMENT,\n first_part,\n );\n const second_part_buf = new this._type(\n this.storage.buffer,\n 8 + 0,\n second_part,\n );\n\n const written = cb(first_part_buf, second_part_buf) || to_write;\n\n // publish the enqueued data to the other side\n Atomics.store(this.write_ptr, 0, (wr + written) % this._storage_capacity());\n\n return written;\n }\n\n /**\n * Write bytes to the ring buffer using a callback.\n *\n * This allows skipping copies if the API that produces the data writes is\n * passed arrays to write to, such as `AudioData.copyTo`.\n *\n * @param amount The maximum number of elements to write to the ring\n * buffer. If amount is more than the number of slots available for writing,\n * then the number of slots available for writing will be made available: no\n * overwriting of elements can happen.\n * @param cb A callback with five parameters:\n *\n * (1) The internal storage of the ring buffer as a typed array\n * (2) An offset to start writing from\n * (3) A number of elements to write at this offset\n * (4) Another offset to start writing from\n * (5) A number of elements to write at this second offset\n *\n * If the callback doesn't return anything, it is assumed all the elements\n * have been written to. Otherwise, it is assumed that the returned number is\n * the number of elements that have been written to, and those elements have\n * been written started at the beginning of the requested buffer space.\n * @return The number of elements written to the queue.\n */\n writeCallbackWithOffset(\n amount: number,\n cb: RingBufferWriteCallbackWithOffset,\n ) {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n if ((wr + 1) % this._storage_capacity() === rd) {\n // full\n return 0;\n }\n\n const to_write = Math.min(this._available_write(rd, wr), amount);\n const first_part = Math.min(this._storage_capacity() - wr, to_write);\n const second_part = to_write - first_part;\n\n const written =\n cb(this.storage, wr, first_part, 0, second_part) || to_write;\n\n // publish the enqueued data to the other side\n Atomics.store(this.write_ptr, 0, (wr + written) % this._storage_capacity());\n\n return written;\n }\n\n /**\n * Read up to `elements.length` elements from the ring buffer. `elements` is a typed\n * array of the same type as passed in the ctor.\n * Returns the number of elements read from the queue, they are placed at the\n * beginning of the array passed as parameter.\n * @param elements An array in which the elements read from the\n * queue will be written, starting at the beginning of the array.\n * @param length If passed, the maximum number of elements to pop. If\n * not passed, up to elements.length are popped.\n * @param offset If passed, an index in elements in which the data is\n * written to. `elements.length - offset` must be greater or equal to\n * `length`.\n * @return The number of elements read from the queue.\n */\n pop(elements: TypedArray, length?: number, offset = 0): number {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n if (wr === rd) {\n return 0;\n }\n\n const len = length !== undefined ? length : elements.length;\n const to_read = Math.min(this._available_read(rd, wr), len);\n\n const first_part = Math.min(this._storage_capacity() - rd, to_read);\n const second_part = to_read - first_part;\n\n this._copy(this.storage, rd, elements, offset, first_part);\n this._copy(this.storage, 0, elements, offset + first_part, second_part);\n\n Atomics.store(this.read_ptr, 0, (rd + to_read) % this._storage_capacity());\n\n return to_read;\n }\n\n /**\n * @return True if the ring buffer is empty false otherwise. This can be late\n * on the reader side: it can return true even if something has just been\n * pushed.\n */\n empty(): boolean {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n return wr === rd;\n }\n\n /**\n * @return True if the ring buffer is full, false otherwise. This can be late\n * on the write side: it can return true when something has just been popped.\n */\n full(): boolean {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n\n return (wr + 1) % this._storage_capacity() === rd;\n }\n\n /**\n * @return The usable capacity for the ring buffer: the number of elements\n * that can be stored.\n */\n capacity(): number {\n return this._capacity - 1;\n }\n\n /**\n * @return The number of elements available for reading. This can be late, and\n * report less elements that is actually in the queue, when something has just\n * been enqueued.\n */\n availableRead(): number {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n return this._available_read(rd, wr);\n }\n\n /**\n * Compatibility alias for availableRead().\n *\n * @return The number of elements available for reading. This can be late, and\n * report less elements that is actually in the queue, when something has just\n * been enqueued.\n *\n * @deprecated\n */\n available_read(): number {\n return this.availableRead();\n }\n\n /**\n * @return The number of elements available for writing. This can be late, and\n * report less elements that is actually available for writing, when something\n * has just been dequeued.\n */\n availableWrite(): number {\n const rd = Atomics.load(this.read_ptr, 0);\n const wr = Atomics.load(this.write_ptr, 0);\n return this._available_write(rd, wr);\n }\n\n /**\n * Compatibility alias for availableWrite.\n *\n * @return The number of elements available for writing. This can be late, and\n * report less elements that is actually available for writing, when something\n * has just been dequeued.\n *\n * @deprecated\n */\n available_write(): number {\n return this.availableWrite();\n }\n\n // private methods //\n\n /**\n * @return Number of elements available for reading, given a read and write\n * pointer.\n * @private\n */\n private _available_read(rd: number, wr: number): number {\n return (wr + this._storage_capacity() - rd) % this._storage_capacity();\n }\n\n /**\n * @return Number of elements available from writing, given a read and write\n * pointer.\n * @private\n */\n private _available_write(rd: number, wr: number): number {\n return this.capacity() - this._available_read(rd, wr);\n }\n\n /**\n * @return The size of the storage for elements not accounting the space for\n * the index, counting the empty slot.\n * @private\n */\n private _storage_capacity(): number {\n return this._capacity;\n }\n\n /**\n * Copy `size` elements from `input`, starting at offset `offset_input`, to\n * `output`, starting at offset `offset_output`.\n * @param input The array to copy from\n * @param offset_input The index at which to start the copy\n * @param output The array to copy to\n * @param offset_output The index at which to start copying the elements to\n * @param size The number of elements to copy\n * @private\n */\n private _copy(\n input: TypedArray,\n offset_input: number,\n output: TypedArray,\n offset_output: number,\n size: number,\n ): void {\n if (!size) {\n return;\n }\n // Fast-path: use `set(...)` if possible: copying all the input linearly to the output.\n if (\n offset_input === 0 &&\n offset_output + input.length <= this._storage_capacity() &&\n input.length === size\n ) {\n output.set(input, offset_output);\n return;\n }\n\n // Slow path: copy element by element, but at least JIT-optimized.\n\n /* Original algorithm (unoptimized):\n\n for (let i = 0; i < size; i++) {\n output[offset_output + i] = input[offset_input + i];\n }\n\n Optimized algorithm (unrolled loop, factor 16):\n */\n\n let i = 0;\n const unrollFactor = 16;\n\n // unroll the loop for better performance; best unroll factor in 2025 for this is 16\n // across all engines: https://github.com/padenot/ringbuf.js/issues/22#issuecomment-2590990421\n for (; i <= size - unrollFactor; i += unrollFactor) {\n output[offset_output + i] = input[offset_input + i];\n output[offset_output + i + 1] = input[offset_input + i + 1];\n output[offset_output + i + 2] = input[offset_input + i + 2];\n output[offset_output + i + 3] = input[offset_input + i + 3];\n output[offset_output + i + 4] = input[offset_input + i + 4];\n output[offset_output + i + 5] = input[offset_input + i + 5];\n output[offset_output + i + 6] = input[offset_input + i + 6];\n output[offset_output + i + 7] = input[offset_input + i + 7];\n output[offset_output + i + 8] = input[offset_input + i + 8];\n output[offset_output + i + 9] = input[offset_input + i + 9];\n output[offset_output + i + 10] = input[offset_input + i + 10];\n output[offset_output + i + 11] = input[offset_input + i + 11];\n output[offset_output + i + 12] = input[offset_input + i + 12];\n output[offset_output + i + 13] = input[offset_input + i + 13];\n output[offset_output + i + 14] = input[offset_input + i + 14];\n output[offset_output + i + 15] = input[offset_input + i + 15];\n }\n\n // remaining elements for when the size is not a multiple of unrollFactor\n for (; i < size; i++) {\n output[offset_output + i] = input[offset_input + i];\n }\n }\n}\n"],"names":[],"mappings":"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"}