Passed
Push — master ( 6e4ba7...34794c )
by Rafael S.
02:21
created

make-wav-header.js ➔ createADPCMHeader_   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
c 0
b 0
f 0
nc 1
dl 0
loc 18
rs 9.6
nop 6
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
import WAV_AUDIO_FORMATS from './wav-audio-formats.js';
31
32
/**
33
 * Return the header for a wav file.
34
 * @param {string} bitDepthCode The audio bit depth
35
 * @param {number} numChannels The number of channels
36
 * @param {number} sampleRate The sample rate.
37
 * @param {number} numBytes The number of bytes each sample use.
38
 * @param {number} samplesLength The length of the samples in bytes.
39
 * @param {!Object} options The extra options, like container defintion.
40
 * @private
41
 */
42
export default function makeWavHeader(
43
  bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
44
  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...
45
  if (bitDepthCode == '4') {
46
    header = createADPCMHeader_(
47
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
48
49
  } else if (bitDepthCode == '8a' || bitDepthCode == '8m') {
50
    header = createALawMulawHeader_(
51
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
52
53
  } else if(Object.keys(WAV_AUDIO_FORMATS).indexOf(bitDepthCode) == -1 ||
54
      numChannels > 2) {
55
    header = createExtensibleHeader_(
56
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
57
58
  } else {
59
    header = createPCMHeader_(
60
      bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);      
61
  }
62
  return header;
63
}
64
65
/**
66
 * Create the header of a linear PCM wave file.
67
 * @param {string} bitDepthCode The audio bit depth
68
 * @param {number} numChannels The number of channels
69
 * @param {number} sampleRate The sample rate.
70
 * @param {number} numBytes The number of bytes each sample use.
71
 * @param {number} samplesLength The length of the samples in bytes.
72
 * @param {!Object} options The extra options, like container defintion.
73
 * @private
74
 */
75
function createPCMHeader_(
76
  bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
77
  return {
78
    container: options.container,
79
    chunkSize: 36 + samplesLength,
80
    format: 'WAVE',
81
    bitDepth: bitDepthCode,
82
    fmt: {
83
      chunkId: 'fmt ',
84
      chunkSize: 16,
85
      audioFormat: WAV_AUDIO_FORMATS[bitDepthCode] || 65534,
86
      numChannels: numChannels,
87
      sampleRate: sampleRate,
88
      byteRate: (numChannels * numBytes) * sampleRate,
89
      blockAlign: numChannels * numBytes,
90
      bitsPerSample: parseInt(bitDepthCode, 10),
91
      cbSize: 0,
92
      validBitsPerSample: 0,
93
      dwChannelMask: 0,
94
      subformat: []
95
    }
96
  };
97
}
98
99
/**
100
 * Create the header of a ADPCM wave file.
101
 * @param {string} bitDepthCode The audio bit depth
102
 * @param {number} numChannels The number of channels
103
 * @param {number} sampleRate The sample rate.
104
 * @param {number} numBytes The number of bytes each sample use.
105
 * @param {number} samplesLength The length of the samples in bytes.
106
 * @param {!Object} options The extra options, like container defintion.
107
 * @private
108
 */
109
function createADPCMHeader_(
110
  bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
111
  let header = createPCMHeader_(
112
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
113
  header.chunkSize = 40 + samplesLength;
114
  header.fmt.chunkSize = 20;
115
  header.fmt.byteRate = 4055;
116
  header.fmt.blockAlign = 256;
117
  header.fmt.bitsPerSample = 4;
118
  header.fmt.cbSize = 2;
119
  header.fmt.validBitsPerSample = 505;
120
  header.fact = {
121
    chunkId: 'fact',
122
    chunkSize: 4,
123
    dwSampleLength: samplesLength * 2
124
  };
125
  return header;
126
}
127
128
/**
129
 * Create the header of WAVE_FORMAT_EXTENSIBLE file.
130
 * @param {string} bitDepthCode The audio bit depth
131
 * @param {number} numChannels The number of channels
132
 * @param {number} sampleRate The sample rate.
133
 * @param {number} numBytes The number of bytes each sample use.
134
 * @param {number} samplesLength The length of the samples in bytes.
135
 * @param {!Object} options The extra options, like container defintion.
136
 * @private
137
 */
138
function createExtensibleHeader_(
139
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
140
  let header = createPCMHeader_(
141
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
142
  header.chunkSize = 36 + 24 + samplesLength;
143
  header.fmt.chunkSize = 40;
144
  header.fmt.bitsPerSample = ((parseInt(bitDepthCode, 10) - 1) | 7) + 1;
145
  header.fmt.cbSize = 22;
146
  header.fmt.validBitsPerSample = parseInt(bitDepthCode, 10);
147
  header.fmt.dwChannelMask = getDwChannelMask_(numChannels);
148
  // subformat 128-bit GUID as 4 32-bit values
149
  // only supports uncompressed integer PCM samples
150
  header.fmt.subformat = [1, 1048576, 2852126848, 1905997824];
151
  return header;
152
}
153
154
/**
155
 * Create the header of mu-Law and A-Law wave files.
156
 * @param {string} bitDepthCode The audio bit depth
157
 * @param {number} numChannels The number of channels
158
 * @param {number} sampleRate The sample rate.
159
 * @param {number} numBytes The number of bytes each sample use.
160
 * @param {number} samplesLength The length of the samples in bytes.
161
 * @param {!Object} options The extra options, like container defintion.
162
 * @private
163
 */
164
function createALawMulawHeader_(
165
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options) {
166
  let header = createPCMHeader_(
167
    bitDepthCode, numChannels, sampleRate, numBytes, samplesLength, options);
168
  header.chunkSize = 40 + samplesLength;
169
  header.fmt.chunkSize = 20;
170
  header.fmt.cbSize = 2;
171
  header.fmt.validBitsPerSample = 8;
172
  header.fact = {
173
    chunkId: 'fact',
174
    chunkSize: 4,
175
    dwSampleLength: samplesLength
176
  };
177
  return header;
178
}
179
180
/**
181
 * Get the value for dwChannelMask according to the number of channels.
182
 * @return {number} the dwChannelMask value.
183
 * @private
184
 */
185
function getDwChannelMask_(numChannels) {
186
  /** @type {number} */
187
  let dwChannelMask = 0;
188
  // mono = FC
189
  if (numChannels === 1) {
190
    dwChannelMask = 0x4;
191
  // stereo = FL, FR
192
  } else if (numChannels === 2) {
193
    dwChannelMask = 0x3;
194
  // quad = FL, FR, BL, BR
195
  } else if (numChannels === 4) {
196
    dwChannelMask = 0x33;
197
  // 5.1 = FL, FR, FC, LF, BL, BR
198
  } else if (numChannels === 6) {
199
    dwChannelMask = 0x3F;
200
  // 7.1 = FL, FR, FC, LF, BL, BR, SL, SR
201
  } else if (numChannels === 8) {
202
    dwChannelMask = 0x63F;
203
  }
204
  return dwChannelMask;
205
}
206