Passed
Push — master ( bc809e...8b98db )
by Rafael S.
01:24
created

T_CONST ➔ toBitDepth   C

Complexity

Conditions 8
Paths 25

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 25
nop 4
dl 0
loc 1
rs 5.3846
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
    if (original == "64" && target == "64") {
25
        return;
26
    }
27
    validateBitDepth_(original);
28
    validateBitDepth_(target);
29
    outputArray = outputArray || samples;
30
    const len = samples.length;
31
    let toFunction = getBitDepthFunction_(original, target);
32
    let options = {
33
        oldMin: Math.pow(2, parseInt(original, 10)) / 2,
34
        newMin: Math.pow(2, parseInt(target, 10)) / 2,
35
        oldMax: (Math.pow(2, parseInt(original, 10)) / 2) - 1,
36
        newMax: (Math.pow(2, parseInt(target, 10)) / 2) - 1,
37
    };
38
    if (original == "8") {
39
        for (let i=0; i<len; i++) {
40
            outputArray[i] = samples[i] -= 128;
41
        }
42
    }
43
    for (let i=0; i<len; i++) {        
44
        outputArray[i] = toFunction(samples[i], options);
45
    }
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
    sample = f64f32_[0];
101
    return sample;
102
}
103
104
/**
105
 * Get the function to change the bit depth of a sample.
106
 * @param {!string} original The original bit depth of the data.
107
 *      One of "8" ... "53", "32f", "64"
108
 * @param {!string} target The new bit depth of the data.
109
 *      One of "8" ... "53", "32f", "64"
110
 * @return {!Function}
111
 * @private
112
 */
113
function getBitDepthFunction_(original, target) {
114
    if (["32f", "64"].includes(original)) {
115
        if (["32f", "64"].includes(target)) {
116
            return floatToFloat_;
117
        } 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...
118
            return floatToInt_;
119
        }
120
    } 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...
121
        if (["32f", "64"].includes(target)) {
122
            return intToFloat_;
123
        } 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...
124
            return intToInt_;
125
        }
126
    }
127
}
128
129
/**
130
 * Validate the bit depth.
131
 * @param {!string} bitDepth The original bit depth.
132
 *     Should be one of "8" ... "53", "32f" or "64".
133
 * @throws {Error} If any argument does not meet the criteria.
134
 * @return {!boolean}
135
 * @private
136
 */
137
function validateBitDepth_(bitDepth) {
138
    if ((bitDepth != "32f" && bitDepth != "64") &&
139
            (parseInt(bitDepth, 10) < "8" || parseInt(bitDepth, 10) > "53")) {
140
        throw new Error("Invalid bit depth.");
141
    }
142
    return true;
143
}
144
145
module.exports = toBitDepth;
146
module.exports.toBitDepth = toBitDepth;
147