Passed
Push — master ( 8b98db...7401ca )
by Rafael S.
01:13
created

T_CONST ➔ toBitDepth   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 24
nop 4
dl 0
loc 1
rs 8.8571
c 0
b 0
f 0
1
/**
2
 * bitdepth
3
 * Change the resolution of samples to and from 8, 11, 12, 16, 20, 24, 32, 48 & 64-bit.
4
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
5
 * https://github.com/rochars/bitdepth
6
 *
7
 */
8
9
/** @private */
10
const f64f32_ = new Float32Array(1);
11
12
/**
13
 * Change the bit depth of the data in a array.
14
 * The input array is modified in-place.
15
 * @param {!Array<number>} samples The samples.
16
 * @param {!string} original The original bit depth of the data.
17
 *      One of "8" ... "53", "32f", "64"
18
 * @param {!string} target The desired bit depth for the data.
19
 *      One of "8" ... "53", "32f", "64"
20
 * @param {Array<number>=} outputArray An optional array to write converted samples to.
21
 *      Useful for writing to typed arrays.
22
 */
23
function toBitDepth(samples, original, target, outputArray) {
24
    validateBitDepth_(original);
25
    validateBitDepth_(target);
26
    outputArray = outputArray || samples;
27
    let toFunction = getBitDepthFunction_(original, target);
28
    let options = {
29
        oldMin: Math.pow(2, parseInt(original, 10)) / 2,
30
        newMin: Math.pow(2, parseInt(target, 10)) / 2,
31
        oldMax: (Math.pow(2, parseInt(original, 10)) / 2) - 1,
32
        newMax: (Math.pow(2, parseInt(target, 10)) / 2) - 1,
33
    };
34
    const len = samples.length;
35
    // sign the samples if original is 8-bit
36
    if (original == "8") {
37
        for (let i=0; i<len; i++) {
38
            outputArray[i] = samples[i] -= 128;
39
        }
40
    }
41
    // change the resolution of the samples
42
    for (let i=0; i<len; i++) {        
43
        outputArray[i] = toFunction(samples[i], options);
44
    }
45
    // unsign the samples if target is 8-bit
46
    if (target == "8") {
47
        for (let i=0; i<len; i++) {
48
            outputArray[i] = outputArray[i] += 128;
49
        }
50
    }
51
}
52
53
/**
54
 * Change the bit depth from int to int.
55
 * @param {!number} sample The sample.
56
 * @param {!Object} args Data about the original and target bit depths.
57
 * @return {!number}
58
 * @private
59
 */
60
function intToInt_(sample, args) {
61
    if (sample > 0) {
62
        sample = parseInt((sample / args.oldMax) * args.newMax, 10);
63
    } else {
64
        sample = parseInt((sample / args.oldMin) * args.newMin, 10);
65
    }
66
    return sample;
67
}
68
69
/**
70
 * Change the bit depth from float to int.
71
 * @param {!number} sample The sample.
72
 * @param {!Object} args Data about the original and target bit depths.
73
 * @return {!number}
74
 * @private
75
 */
76
function floatToInt_(sample, args) {
77
    return parseInt(
78
        sample > 0 ? sample * args.newMax : sample * args.newMin, 10);
79
}
80
81
/**
82
 * Change the bit depth from int to float.
83
 * @param {!number} sample The sample.
84
 * @param {!Object} args Data about the original and target bit depths.
85
 * @return {!number}
86
 * @private
87
 */
88
function intToFloat_(sample, args) {
89
    return sample > 0 ? sample / args.oldMax : sample / args.oldMin;
90
}
91
92
/**
93
 * Change the bit depth from float to float.
94
 * @param {!number} sample The sample.
95
 * @return {!number}
96
 * @private
97
 */
98
function floatToFloat_(sample) {
99
    f64f32_[0] = sample;
100
    return f64f32_[0];
101
}
102
103
/**
104
 * Return the function to change the bit depth of a sample.
105
 * @param {!string} original The original bit depth of the data.
106
 *      One of "8" ... "53", "32f", "64"
107
 * @param {!string} target The new bit depth of the data.
108
 *      One of "8" ... "53", "32f", "64"
109
 * @return {!Function}
110
 * @private
111
 */
112
function getBitDepthFunction_(original, target) {
113
    /** @type {!Function} */
114
    let func;
115
    if (["32f", "64"].includes(original)) {
116
        if (["32f", "64"].includes(target)) {
117
            func = floatToFloat_;
118
        } else {
119
            func = floatToInt_;
120
        }
121
    } else {
122
        if (["32f", "64"].includes(target)) {
123
            return intToFloat_;
124
        } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
125
            func = intToInt_;
126
        }
127
    }
128
    if (original == target) {
129
        func = function(x,y) {return x;};
0 ignored issues
show
Unused Code introduced by
The parameter y is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
130
    }
131
    return func;
132
}
133
134
/**
135
 * Validate the bit depth.
136
 * @param {!string} bitDepth The original bit depth.
137
 *     Should be one of "8" ... "53", "32f" or "64".
138
 * @throws {Error} If any argument does not meet the criteria.
139
 * @private
140
 */
141
function validateBitDepth_(bitDepth) {
142
    if ((bitDepth != "32f" && bitDepth != "64") &&
143
            (parseInt(bitDepth, 10) < "8" || parseInt(bitDepth, 10) > "53")) {
144
        throw new Error("Invalid bit depth.");
145
    }
146
}
147
148
module.exports = toBitDepth;
149
module.exports.toBitDepth = toBitDepth;
150