Passed
Branch v8.x (741daf)
by Rafael S.
02:15
created

wavheader.js ➔ createExtensibleHeader_   A

Complexity

Conditions 1
Paths 2

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 2
nop 6
dl 0
loc 15
rs 9.8
1
/*
2
 * Copyright (c) 2018 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview A tool to create wav file headers.
27
 * @see https://github.com/rochars/wavefile
28
 */
29
30
/**
31
 * Audio formats.
32
 * Formats not listed here will be set to 65534,
33
 * the code for WAVE_FORMAT_EXTENSIBLE
34
 * @enum {number}
35
 * @private
36
 */
37
export const AUDIO_FORMATS = {
38
  '4': 17,
39
  '8': 1,
40
  '8a': 6,
41
  '8m': 7,
42
  '16': 1,
43
  '24': 1,
44
  '32': 1,
45
  '32f': 3,
46
  '64': 3
47
};
48
49
/**
50
 * Return the header for a wav file.
51
 * @param {string} bitDepthCode The audio bit depth
52
 * @param {number} numChannels The number of channels
53
 * @param {number} sampleRate The sample rate.
54
 * @param {number} numBytes The number of bytes each sample use.
55
 * @param {number} samplesLength The length of the samples in bytes.
56
 * @param {!Object} options The extra options, like container defintion.
57
 * @private
58
 */
59
export function wavHeader(bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
60
  let header = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable header seems to be never used. Consider removing it.
Loading history...
61
  if (bitDepthCode == '4') {
62
    header = createADPCMHeader_(
63
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
64
65
  } else if (bitDepthCode == '8a' || bitDepthCode == '8m') {
66
    header = createALawMulawHeader_(
67
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
68
69
  } else if(Object.keys(AUDIO_FORMATS).indexOf(bitDepthCode) == -1 ||
70
      numChannels > 2) {
71
    header = createExtensibleHeader_(
72
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
73
74
  } else {
75
    header = createPCMHeader_(
76
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);      
77
  }
78
  return header;
79
}
80
81
/**
82
 * Create the header of a linear PCM wave file.
83
 * @param {string} bitDepthCode The audio bit depth
84
 * @param {number} numChannels The number of channels
85
 * @param {number} sampleRate The sample rate.
86
 * @param {number} numBytes The number of bytes each sample use.
87
 * @param {number} samplesLength The length of the samples in bytes.
88
 * @param {!Object} options The extra options, like container defintion.
89
 * @private
90
 */
91
function createPCMHeader_(bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
92
  return {
93
    container: options.container,
94
    chunkSize: 36 + samplesLength,
95
    format: 'WAVE',
96
    fmt: {
97
      chunkId: 'fmt ',
98
      chunkSize: 16,
99
      audioFormat: AUDIO_FORMATS[bitDepthCode] ? AUDIO_FORMATS[bitDepthCode] : 65534,
100
      numChannels: numChannels,
101
      sampleRate: sampleRate,
102
      byteRate: (numChannels * numBytes) * sampleRate,
103
      blockAlign: numChannels * numBytes,
104
      bitsPerSample: parseInt(bitDepthCode, 10),
105
      cbSize: 0,
106
      validBitsPerSample: 0,
107
      dwChannelMask: 0,
108
      subformat: []
109
    }
110
  };
111
}
112
113
/**
114
 * Create the header of a ADPCM wave file.
115
 * @param {string} bitDepthCode The audio bit depth
116
 * @param {number} numChannels The number of channels
117
 * @param {number} sampleRate The sample rate.
118
 * @param {number} numBytes The number of bytes each sample use.
119
 * @param {number} samplesLength The length of the samples in bytes.
120
 * @param {!Object} options The extra options, like container defintion.
121
 * @private
122
 */
123
function createADPCMHeader_(bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
124
  let header = createPCMHeader_(
125
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
126
  header.chunkSize = 40 + samplesLength;
127
  header.fmt.chunkSize = 20;
128
  header.fmt.byteRate = 4055;
129
  header.fmt.blockAlign = 256;
130
  header.fmt.bitsPerSample = 4;
131
  header.fmt.cbSize = 2;
132
  header.fmt.validBitsPerSample = 505;
133
  header.fact = {
134
    chunkId: 'fact',
135
    chunkSize: 4,
136
    dwSampleLength: samplesLength * 2
137
  };
138
  return header;
139
}
140
141
/**
142
 * Create the header of WAVE_FORMAT_EXTENSIBLE file.
143
 * @param {string} bitDepthCode The audio bit depth
144
 * @param {number} numChannels The number of channels
145
 * @param {number} sampleRate The sample rate.
146
 * @param {number} numBytes The number of bytes each sample use.
147
 * @param {number} samplesLength The length of the samples in bytes.
148
 * @param {!Object} options The extra options, like container defintion.
149
 * @private
150
 */
151
function createExtensibleHeader_(
152
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
153
  let header = createPCMHeader_(
154
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
155
  header.chunkSize = 36 + 24 + samplesLength;
156
  header.fmt.chunkSize = 40;
157
  header.fmt.bitsPerSample = ((parseInt(bitDepthCode, 10) - 1) | 7) + 1;
158
  header.fmt.cbSize = 22;
159
  header.fmt.validBitsPerSample = parseInt(bitDepthCode, 10);
160
  header.fmt.dwChannelMask = getDwChannelMask_(numChannels);
161
  // subformat 128-bit GUID as 4 32-bit values
162
  // only supports uncompressed integer PCM samples
163
  header.fmt.subformat = [1, 1048576, 2852126848, 1905997824];
164
  return header;
165
}
166
167
/**
168
 * Create the header of mu-Law and A-Law wave files.
169
 * @param {string} bitDepthCode The audio bit depth
170
 * @param {number} numChannels The number of channels
171
 * @param {number} sampleRate The sample rate.
172
 * @param {number} numBytes The number of bytes each sample use.
173
 * @param {number} samplesLength The length of the samples in bytes.
174
 * @param {!Object} options The extra options, like container defintion.
175
 * @private
176
 */
177
function createALawMulawHeader_(
178
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
179
  let header = createPCMHeader_(
180
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
181
  header.chunkSize = 40 + samplesLength;
182
  header.fmt.chunkSize = 20;
183
  header.fmt.cbSize = 2;
184
  header.fmt.validBitsPerSample = 8;
185
  header.fact = {
186
    chunkId: 'fact',
187
    chunkSize: 4,
188
    dwSampleLength: samplesLength
189
  };
190
  return header;
191
}
192
193
/**
194
 * Get the value for dwChannelMask according to the number of channels.
195
 * @return {number} the dwChannelMask value.
196
 * @private
197
 */
198
function getDwChannelMask_(numChannels) {
199
  /** @type {number} */
200
  let dwChannelMask = 0;
201
  // mono = FC
202
  if (numChannels === 1) {
203
    dwChannelMask = 0x4;
204
  // stereo = FL, FR
205
  } else if (numChannels === 2) {
206
    dwChannelMask = 0x3;
207
  // quad = FL, FR, BL, BR
208
  } else if (numChannels === 4) {
209
    dwChannelMask = 0x33;
210
  // 5.1 = FL, FR, FC, LF, BL, BR
211
  } else if (numChannels === 6) {
212
    dwChannelMask = 0x3F;
213
  // 7.1 = FL, FR, FC, LF, BL, BR, SL, SR
214
  } else if (numChannels === 8) {
215
    dwChannelMask = 0x63F;
216
  }
217
  return dwChannelMask;
218
}
219