react-native-audio-api 0.8.3-nightly-ea268f4-20251006 → 0.9.0-nightly-96a5bcd-20251007
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/cpp/audioapi/android/core/{AudioDecoder.cpp → utils/AudioDecoder.cpp} +79 -75
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +99 -43
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +1 -101
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +0 -3
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +107 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +28 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +0 -2
- package/common/cpp/audioapi/core/AudioNode.cpp +3 -3
- package/common/cpp/audioapi/core/AudioNode.h +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +0 -35
- package/common/cpp/audioapi/core/BaseAudioContext.h +4 -12
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +0 -2
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +3 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +17 -12
- package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +2 -2
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +4 -2
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +4 -2
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +4 -2
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +7 -2
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +3 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +9 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.h +1 -1
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +6 -4
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +2 -2
- package/common/cpp/audioapi/core/types/AudioFormat.h +16 -0
- package/common/cpp/audioapi/core/utils/AudioDecoder.h +36 -90
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +241 -282
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +57 -19
- package/common/cpp/test/CMakeLists.txt +2 -1
- package/common/cpp/test/GainTest.cpp +9 -9
- package/common/cpp/test/StereoPannerTest.cpp +129 -0
- package/ios/audioapi/ios/core/IOSAudioRecorder.h +1 -2
- package/ios/audioapi/ios/core/utils/AudioDecoder.mm +160 -0
- package/lib/commonjs/api.js +14 -1
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/core/AudioDecoder.js +48 -0
- package/lib/commonjs/core/AudioDecoder.js.map +1 -0
- package/lib/commonjs/core/BaseAudioContext.js +11 -18
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/module/api.js +2 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/core/AudioDecoder.js +42 -0
- package/lib/module/core/AudioDecoder.js.map +1 -0
- package/lib/module/core/BaseAudioContext.js +11 -18
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/typescript/api.d.ts +3 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/core/AudioDecoder.d.ts +4 -0
- package/lib/typescript/core/AudioDecoder.d.ts.map +1 -0
- package/lib/typescript/core/BaseAudioContext.d.ts +3 -6
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +6 -3
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +5 -0
- package/src/core/AudioDecoder.ts +78 -0
- package/src/core/BaseAudioContext.ts +26 -29
- package/src/interfaces.ts +18 -6
- package/ios/audioapi/ios/core/AudioDecoder.mm +0 -156
|
@@ -21,6 +21,9 @@ OscillatorNode::OscillatorNode(BaseAudioContext *context)
|
|
|
21
21
|
type_ = OscillatorType::SINE;
|
|
22
22
|
periodicWave_ = context_->getBasicWaveForm(type_);
|
|
23
23
|
|
|
24
|
+
audioBus_ = std::make_shared<AudioBus>(
|
|
25
|
+
RENDER_QUANTUM_SIZE, 1, context_->getSampleRate());
|
|
26
|
+
|
|
24
27
|
isInitialized_ = true;
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -47,7 +50,7 @@ void OscillatorNode::setPeriodicWave(
|
|
|
47
50
|
type_ = OscillatorType::CUSTOM;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
std::shared_ptr<AudioBus> OscillatorNode::processNode(
|
|
51
54
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
52
55
|
int framesToProcess) {
|
|
53
56
|
size_t startOffset = 0;
|
|
@@ -57,7 +60,7 @@ void OscillatorNode::processNode(
|
|
|
57
60
|
|
|
58
61
|
if (!isPlaying() && !isStopScheduled()) {
|
|
59
62
|
processingBus->zero();
|
|
60
|
-
return;
|
|
63
|
+
return processingBus;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
auto time = context_->getCurrentTime() +
|
|
@@ -89,6 +92,8 @@ void OscillatorNode::processNode(
|
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
handleStopScheduled();
|
|
95
|
+
|
|
96
|
+
return processingBus;
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
} // namespace audioapi
|
|
@@ -24,7 +24,7 @@ class OscillatorNode : public AudioScheduledSourceNode {
|
|
|
24
24
|
void setPeriodicWave(const std::shared_ptr<PeriodicWave> &periodicWave);
|
|
25
25
|
|
|
26
26
|
protected:
|
|
27
|
-
|
|
27
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
28
28
|
|
|
29
29
|
private:
|
|
30
30
|
std::shared_ptr<AudioParam> frequencyParam_;
|
|
@@ -23,7 +23,7 @@ void RecorderAdapterNode::init(size_t bufferSize) {
|
|
|
23
23
|
buff_ = std::make_shared<CircularOverflowableAudioArray>(bufferSize);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
std::shared_ptr<AudioBus> RecorderAdapterNode::processNode(
|
|
27
27
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
28
28
|
int framesToProcess) {
|
|
29
29
|
float *outputChannel = processingBus->getChannel(0)->getData();
|
|
@@ -33,6 +33,8 @@ void RecorderAdapterNode::processNode(
|
|
|
33
33
|
processingBus->getChannel(i)->copy(
|
|
34
34
|
processingBus->getChannel(0), 0, framesToProcess);
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
return processingBus;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
void RecorderAdapterNode::readFrames(float *output, const size_t framesToRead) {
|
|
@@ -27,7 +27,7 @@ class RecorderAdapterNode : public AudioNode {
|
|
|
27
27
|
void init(size_t bufferSize);
|
|
28
28
|
|
|
29
29
|
protected:
|
|
30
|
-
|
|
30
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
31
31
|
std::shared_ptr<CircularOverflowableAudioArray> buff_;
|
|
32
32
|
|
|
33
33
|
private:
|
|
@@ -147,12 +147,18 @@ void StreamerNode::streamAudio() {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
std::shared_ptr<AudioBus> StreamerNode::processNode(
|
|
151
151
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
152
152
|
int framesToProcess) {
|
|
153
153
|
size_t startOffset = 0;
|
|
154
154
|
size_t offsetLength = 0;
|
|
155
155
|
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
|
|
156
|
+
|
|
157
|
+
if (!isPlaying() && !isStopScheduled()) {
|
|
158
|
+
processingBus->zero();
|
|
159
|
+
return processingBus;
|
|
160
|
+
}
|
|
161
|
+
|
|
156
162
|
// If we have enough buffered data, copy to output bus
|
|
157
163
|
if (bufferedBusIndex_ >= framesToProcess) {
|
|
158
164
|
Locker locker(mutex_);
|
|
@@ -169,6 +175,8 @@ void StreamerNode::processNode(
|
|
|
169
175
|
}
|
|
170
176
|
bufferedBusIndex_ -= offsetLength;
|
|
171
177
|
}
|
|
178
|
+
|
|
179
|
+
return processingBus;
|
|
172
180
|
}
|
|
173
181
|
|
|
174
182
|
bool StreamerNode::processFrameWithResampler(AVFrame *frame) {
|
|
@@ -44,7 +44,7 @@ class StreamerNode : public AudioScheduledSourceNode {
|
|
|
44
44
|
void stop(double when) override;
|
|
45
45
|
|
|
46
46
|
protected:
|
|
47
|
-
|
|
47
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
48
48
|
|
|
49
49
|
private:
|
|
50
50
|
#ifndef AUDIO_API_TEST_SUITE
|
|
@@ -22,12 +22,12 @@ WorkletSourceNode::WorkletSourceNode(
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
|
|
26
26
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
27
27
|
int framesToProcess) {
|
|
28
28
|
if (isUnscheduled() || isFinished() || !isEnabled()) {
|
|
29
29
|
processingBus->zero();
|
|
30
|
-
return;
|
|
30
|
+
return processingBus;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
size_t startOffset = 0;
|
|
@@ -38,7 +38,7 @@ void WorkletSourceNode::processNode(
|
|
|
38
38
|
|
|
39
39
|
if (nonSilentFramesToProcess == 0) {
|
|
40
40
|
processingBus->zero();
|
|
41
|
-
return;
|
|
41
|
+
return processingBus;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
size_t outputChannelCount = processingBus->getNumberOfChannels();
|
|
@@ -64,7 +64,7 @@ void WorkletSourceNode::processNode(
|
|
|
64
64
|
// It might happen if the runtime is not available
|
|
65
65
|
if (!result.has_value()) {
|
|
66
66
|
processingBus->zero();
|
|
67
|
-
return;
|
|
67
|
+
return processingBus;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Copy the processed data back to the AudioBus
|
|
@@ -77,6 +77,8 @@ void WorkletSourceNode::processNode(
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
handleStopScheduled();
|
|
80
|
+
|
|
81
|
+
return processingBus;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
} // namespace audioapi
|
|
@@ -23,7 +23,7 @@ class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
|
23
23
|
) : AudioScheduledSourceNode(context) {}
|
|
24
24
|
|
|
25
25
|
protected:
|
|
26
|
-
|
|
26
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override { return processingBus; }
|
|
27
27
|
};
|
|
28
28
|
#else
|
|
29
29
|
|
|
@@ -36,7 +36,7 @@ class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
protected:
|
|
39
|
-
|
|
39
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
40
40
|
private:
|
|
41
41
|
WorkletsRunner workletRunner_;
|
|
42
42
|
std::shared_ptr<worklets::SerializableWorklet> shareableWorklet_;
|
|
@@ -1,124 +1,68 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <audioapi/core/types/AudioFormat.h>
|
|
3
4
|
#include <audioapi/libs/audio-stretch/stretch.h>
|
|
4
5
|
#include <audioapi/libs/miniaudio/miniaudio.h>
|
|
6
|
+
#include <algorithm>
|
|
7
|
+
#include <cstring>
|
|
5
8
|
#include <memory>
|
|
6
9
|
#include <string>
|
|
7
10
|
#include <vector>
|
|
8
|
-
#include <cstring>
|
|
9
|
-
#include <algorithm>
|
|
10
11
|
|
|
11
12
|
namespace audioapi {
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
UNKNOWN,
|
|
15
|
-
WAV,
|
|
16
|
-
OGG,
|
|
17
|
-
FLAC,
|
|
18
|
-
AAC,
|
|
19
|
-
MP3,
|
|
20
|
-
M4A,
|
|
21
|
-
MP4,
|
|
22
|
-
MOV
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
class AudioBus;
|
|
14
|
+
class AudioBuffer;
|
|
26
15
|
|
|
27
16
|
static constexpr int CHUNK_SIZE = 4096;
|
|
28
17
|
|
|
29
18
|
class AudioDecoder {
|
|
30
19
|
public:
|
|
31
|
-
|
|
20
|
+
AudioDecoder() = delete;
|
|
32
21
|
|
|
33
|
-
[[nodiscard]] std::shared_ptr<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
[[nodiscard]] std::shared_ptr<AudioBus> decodeWithPCMInBase64(
|
|
39
|
-
const std::string &data,
|
|
40
|
-
float playbackSpeed) const;
|
|
22
|
+
[[nodiscard]] static std::shared_ptr<AudioBuffer> decodeWithFilePath(const std::string &path, float sampleRate);
|
|
23
|
+
[[nodiscard]] static std::shared_ptr<AudioBuffer>
|
|
24
|
+
decodeWithMemoryBlock(const void *data, size_t size, float sampleRate);
|
|
25
|
+
[[nodiscard]] static std::shared_ptr<AudioBuffer>
|
|
26
|
+
decodeWithPCMInBase64(const std::string &data, float inputSampleRate, int inputChannelCount, bool interleaved);
|
|
41
27
|
|
|
42
28
|
private:
|
|
43
|
-
float
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
static std::vector<int16_t> readAllPcmFrames(
|
|
47
|
-
ma_decoder &decoder,
|
|
48
|
-
int numChannels,
|
|
49
|
-
ma_uint64 &outFramesRead);
|
|
50
|
-
static std::shared_ptr<AudioBus> makeAudioBusFromInt16Buffer(
|
|
51
|
-
const std::vector<int16_t> &buffer,
|
|
52
|
-
int numChannels,
|
|
53
|
-
float sampleRate);
|
|
54
|
-
|
|
55
|
-
void changePlaybackSpeedIfNeeded(
|
|
56
|
-
std::vector<int16_t> &buffer,
|
|
57
|
-
size_t framesDecoded,
|
|
58
|
-
int numChannels,
|
|
59
|
-
float playbackSpeed) const {
|
|
60
|
-
if (playbackSpeed == 1.0f) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
auto stretcher = stretch_init(
|
|
65
|
-
static_cast<int>(sampleRate_ / 333.0f),
|
|
66
|
-
static_cast<int>(sampleRate_ / 55.0f),
|
|
67
|
-
numChannels,
|
|
68
|
-
0x1);
|
|
29
|
+
static std::vector<float> readAllPcmFrames(ma_decoder &decoder, int outputChannels);
|
|
30
|
+
static std::shared_ptr<AudioBuffer>
|
|
31
|
+
makeAudioBufferFromFloatBuffer(const std::vector<float> &buffer, float outputSampleRate, int outputChannels);
|
|
69
32
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
int outputFrames = stretch_samples(
|
|
75
|
-
stretcher,
|
|
76
|
-
buffer.data(),
|
|
77
|
-
static_cast<int>(framesDecoded),
|
|
78
|
-
stretchedBuffer.data(),
|
|
79
|
-
1 / playbackSpeed);
|
|
80
|
-
|
|
81
|
-
outputFrames +=
|
|
82
|
-
stretch_flush(stretcher, stretchedBuffer.data() + (outputFrames));
|
|
83
|
-
stretchedBuffer.resize(outputFrames);
|
|
84
|
-
|
|
85
|
-
buffer = stretchedBuffer;
|
|
86
|
-
|
|
87
|
-
stretch_deinit(stretcher);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
static AudioFormat detectAudioFormat(const void* data, size_t size) {
|
|
91
|
-
if (size < 12) return AudioFormat::UNKNOWN;
|
|
92
|
-
const auto* bytes = static_cast<const unsigned char*>(data);
|
|
33
|
+
static AudioFormat detectAudioFormat(const void *data, size_t size) {
|
|
34
|
+
if (size < 12)
|
|
35
|
+
return AudioFormat::UNKNOWN;
|
|
36
|
+
const auto *bytes = static_cast<const unsigned char *>(data);
|
|
93
37
|
|
|
94
38
|
// WAV/RIFF
|
|
95
39
|
if (std::memcmp(bytes, "RIFF", 4) == 0 && std::memcmp(bytes + 8, "WAVE", 4) == 0)
|
|
96
|
-
|
|
40
|
+
return AudioFormat::WAV;
|
|
97
41
|
|
|
98
42
|
// OGG
|
|
99
43
|
if (std::memcmp(bytes, "OggS", 4) == 0)
|
|
100
|
-
|
|
44
|
+
return AudioFormat::OGG;
|
|
101
45
|
|
|
102
46
|
// FLAC
|
|
103
47
|
if (std::memcmp(bytes, "fLaC", 4) == 0)
|
|
104
|
-
|
|
48
|
+
return AudioFormat::FLAC;
|
|
105
49
|
|
|
106
50
|
// AAC starts with 0xFF 0xF1 or 0xFF 0xF9
|
|
107
51
|
if (bytes[0] == 0xFF && (bytes[1] & 0xF6) == 0xF0)
|
|
108
|
-
|
|
52
|
+
return AudioFormat::AAC;
|
|
109
53
|
|
|
110
54
|
// MP3: "ID3" or 11-bit frame sync (0xFF 0xE0)
|
|
111
55
|
if (std::memcmp(bytes, "ID3", 3) == 0)
|
|
112
|
-
|
|
56
|
+
return AudioFormat::MP3;
|
|
113
57
|
if (bytes[0] == 0xFF && (bytes[1] & 0xE0) == 0xE0)
|
|
114
|
-
|
|
58
|
+
return AudioFormat::MP3;
|
|
115
59
|
|
|
116
60
|
if (std::memcmp(bytes + 4, "ftyp", 4) == 0) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
61
|
+
if (std::memcmp(bytes + 8, "M4A ", 4) == 0)
|
|
62
|
+
return AudioFormat::M4A;
|
|
63
|
+
else if (std::memcmp(bytes + 8, "qt ", 4) == 0)
|
|
64
|
+
return AudioFormat::MOV;
|
|
65
|
+
return AudioFormat::MP4;
|
|
122
66
|
}
|
|
123
67
|
return AudioFormat::UNKNOWN;
|
|
124
68
|
}
|
|
@@ -126,19 +70,21 @@ class AudioDecoder {
|
|
|
126
70
|
static inline bool pathHasExtension(const std::string &path, const std::vector<std::string> &extensions) {
|
|
127
71
|
std::string pathLower = path;
|
|
128
72
|
std::transform(pathLower.begin(), pathLower.end(), pathLower.begin(), ::tolower);
|
|
129
|
-
for (const auto&
|
|
130
|
-
|
|
131
|
-
|
|
73
|
+
for (const auto &ext : extensions) {
|
|
74
|
+
if (pathLower.ends_with(ext))
|
|
75
|
+
return true;
|
|
132
76
|
}
|
|
133
77
|
return false;
|
|
134
78
|
}
|
|
135
79
|
|
|
136
|
-
|
|
137
80
|
[[nodiscard]] static inline int16_t floatToInt16(float sample) {
|
|
138
|
-
return static_cast<int16_t>(sample *
|
|
81
|
+
return static_cast<int16_t>(sample * INT16_MAX);
|
|
139
82
|
}
|
|
140
83
|
[[nodiscard]] static inline float int16ToFloat(int16_t sample) {
|
|
141
|
-
return static_cast<float>(sample) /
|
|
84
|
+
return static_cast<float>(sample) / INT16_MAX;
|
|
85
|
+
}
|
|
86
|
+
[[nodiscard]] static inline float uint8ToFloat(uint8_t byte1, uint8_t byte2) {
|
|
87
|
+
return static_cast<float>(static_cast<int16_t>((byte2 << 8) | byte1)) / INT16_MAX;
|
|
142
88
|
}
|
|
143
89
|
};
|
|
144
90
|
|