UNPKG

wavefile

Version:

Create, read and write wav files according to the specs.

177 lines (166 loc) 5.41 kB
/* * Copyright (c) 2017-2019 Rafael da Silva Rocha. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /** * @fileoverview The WaveFileTagEditor class. * @see https://github.com/rochars/wavefile */ import { WaveFileCreator } from './wavefile-creator'; /** * A class to edit meta information in wav files. * @extends WaveFileCreator * @ignore */ export class WaveFileTagEditor extends WaveFileCreator { /** * Return the value of a RIFF tag in the INFO chunk. * @param {string} tag The tag name. * @return {?string} The value if the tag is found, null otherwise. */ getTag(tag) { /** @type {!Object} */ let index = this.getTagIndex_(tag); if (index.TAG !== null) { return this.LIST[index.LIST].subChunks[index.TAG].value; } return null; } /** * Write a RIFF tag in the INFO chunk. If the tag do not exist, * then it is created. It if exists, it is overwritten. * @param {string} tag The tag name. * @param {string} value The tag value. * @throws {Error} If the tag name is not valid. */ setTag(tag, value) { tag = fixRIFFTag_(tag); /** @type {!Object} */ let index = this.getTagIndex_(tag); if (index.TAG !== null) { this.LIST[index.LIST].subChunks[index.TAG].chunkSize = value.length + 1; this.LIST[index.LIST].subChunks[index.TAG].value = value; } else if (index.LIST !== null) { this.LIST[index.LIST].subChunks.push({ chunkId: tag, chunkSize: value.length + 1, value: value}); } else { this.LIST.push({ chunkId: 'LIST', chunkSize: 8 + value.length + 1, format: 'INFO', subChunks: []}); this.LIST[this.LIST.length - 1].subChunks.push({ chunkId: tag, chunkSize: value.length + 1, value: value}); } } /** * Remove a RIFF tag from the INFO chunk. * @param {string} tag The tag name. * @return {boolean} True if a tag was deleted. */ deleteTag(tag) { /** @type {!Object} */ let index = this.getTagIndex_(tag); if (index.TAG !== null) { this.LIST[index.LIST].subChunks.splice(index.TAG, 1); return true; } return false; } /** * Return a Object<tag, value> with the RIFF tags in the file. * @return {!Object<string, string>} The file tags. */ listTags() { /** @type {?number} */ let index = this.getLISTIndex('INFO'); /** @type {!Object} */ let tags = {}; if (index !== null) { for (let i = 0, len = this.LIST[index].subChunks.length; i < len; i++) { tags[this.LIST[index].subChunks[i].chunkId] = this.LIST[index].subChunks[i].value; } } return tags; } /** * Return the index of a list by its type. * @param {string} listType The list type ('adtl', 'INFO') * @return {?number} * @protected */ getLISTIndex(listType) { for (let i = 0, len = this.LIST.length; i < len; i++) { if (this.LIST[i].format == listType) { return i; } } return null; } /** * Return the index of a tag in a FILE chunk. * @param {string} tag The tag name. * @return {!Object<string, ?number>} * Object.LIST is the INFO index in LIST * Object.TAG is the tag index in the INFO * @private */ getTagIndex_(tag) { /** @type {!Object<string, ?number>} */ let index = {LIST: null, TAG: null}; for (let i = 0, len = this.LIST.length; i < len; i++) { if (this.LIST[i].format == 'INFO') { index.LIST = i; for (let j=0, subLen = this.LIST[i].subChunks.length; j < subLen; j++) { if (this.LIST[i].subChunks[j].chunkId == tag) { index.TAG = j; break; } } break; } } return index; } } /** * Fix a RIFF tag format if possible, throw an error otherwise. * @param {string} tag The tag name. * @return {string} The tag name in proper fourCC format. * @private */ function fixRIFFTag_(tag) { if (tag.constructor !== String) { throw new Error('Invalid tag name.'); } else if (tag.length < 4) { for (let i = 0, len = 4 - tag.length; i < len; i++) { tag += ' '; } } return tag; }