UNPKG

jamp3

Version:

mp3, id3v1, id3v2 - reader & writer

99 lines (89 loc) 3.47 kB
import {IFrameImpl} from '../id3v2.frame'; import {ascii} from '../../../common/encodings'; import {IID3V2} from '../../id3v2.types'; import {neededStoreBytes} from '../../../common/utils'; export const FrameRelativeVolumeAdjustment2: IFrameImpl = { /** 4.11. Relative volume adjustment (2) This is a more subjective frame than the previous ones. It allows the user to say how much he wants to increase/decrease the volume on each channel when the file is played. The purpose is to be able to align all files to a reference volume, so that you don't have to change the volume constantly. This frame may also be used to balance adjust the audio. The volume adjustment is encoded as a fixed point decibel value, 16 bit signed integer representing (adjustment*512), giving +/- 64 dB with a precision of 0.001953125 dB. E.g. +2 dB is stored as $04 00 and -2 dB is $FC 00. There may be more than one "RVA2" frame in each tag, but only one with the same identification string. <Header for 'Relative volume adjustment (2)', ID: "RVA2"> Identification <text string> $00 The 'identification' string is used to identify the situation and/or device where this adjustment should apply. The following is then repeated for every channel Type of channel $xx Volume adjustment $xx xx Bits representing peak $xx Peak volume $xx (xx ...) Type of channel: $00 Other $01 Master volume $02 Front right $03 Front left $04 Back right $05 Back left $06 Front centre $07 Back centre $08 Subwoofer Bits representing peak can be any number between 0 and 255. 0 means that there is no peak volume field. The peak volume field is always padded to whole bytes, setting the most significant bits to zero. */ parse: async (reader, frame) => { if (frame.data.length === 0) { return {value: {}}; } // const AdjustmentType: any = { // 0: 'Other', // 1: 'Master volume', // 2: 'Front right', // 3: 'Front left', // 4: 'Back right', // 5: 'Back left', // 6: 'Front centre', // 7: 'Back centre', // 8: 'Subwoofer' // }; const id = reader.readStringTerminated(ascii); const channels: Array<IID3V2.FrameValue.RVA2Channel> = []; while (reader.unread() >= 3) { const type = reader.readByte(); const adjustment = reader.readSInt(2); // 16-bit signed const channel: IID3V2.FrameValue.RVA2Channel = {type, adjustment}; while (reader.unread() >= 1) { const bitspeakvolume = reader.readByte(); const bytesInPeak = bitspeakvolume > 0 ? Math.ceil(bitspeakvolume / 8) : 0; if (bytesInPeak > 0 && reader.unread() >= bytesInPeak) { channel.peak = reader.readUInt(bytesInPeak); } } channels.push(channel); } const value: IID3V2.FrameValue.RVA2 = {id, channels}; return {value}; }, write: async (frame, stream) => { const value = <IID3V2.FrameValue.RVA2>frame.value; await stream.writeStringTerminated(value.id, ascii); for (const channel of value.channels) { await stream.writeByte(channel.type); await stream.writeSInt(channel.adjustment, 2); const bytes = channel.peak === undefined ? 0 : neededStoreBytes(channel.peak, 2); await stream.writeUInt(bytes * 8, 2); if (channel.peak !== undefined && bytes > 0) { await stream.writeUInt(channel.peak, bytes); } } }, simplify: (value: IID3V2.FrameValue.RVA2) => { return null; // TODO simplify IID3V2.FrameValue.RVA2 } };