-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Documentation and privitization * Adding util tests * Finish testing and moving things around * Fix analysis
- Loading branch information
1 parent
79f9c7d
commit 7acd05f
Showing
16 changed files
with
378 additions
and
250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// Copyright 2022 The wav authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'dart:typed_data'; | ||
|
||
import 'util.dart'; | ||
import 'wav_format.dart'; | ||
|
||
/// Utility class to incrementally read through a series of bytes, interpreting | ||
/// byte combinations as little endian ints and floats etc. Every read operation | ||
/// moves the read head forward by the corresponding number of bytes. | ||
class BytesReader { | ||
final Uint8List _bytes; | ||
int _p = 0; | ||
|
||
/// Constructs a [BytesReader]. | ||
BytesReader(this._bytes); | ||
|
||
/// Skip forward [n] bytes. | ||
void skip(int n) { | ||
_p += n; | ||
if (_p > _bytes.length) { | ||
throw FormatException('WAV is corrupted, or not a WAV file.'); | ||
} | ||
} | ||
|
||
ByteData _read(int n) { | ||
final p0 = _p; | ||
skip(n); | ||
return ByteData.sublistView(_bytes, p0, _p); | ||
} | ||
|
||
/// Reads a Uint8 from the buffer. | ||
int readUint8() => _read(1).getUint8(0); | ||
|
||
/// Reads a Uint16 from the buffer. | ||
int readUint16() => _read(2).getUint16(0, Endian.little); | ||
|
||
/// Reads a Uint24 from the buffer. | ||
int readUint24() => readUint8() + 0x100 * readUint16(); | ||
|
||
/// Reads a Uint32 from the buffer. | ||
int readUint32() => _read(4).getUint32(0, Endian.little); | ||
|
||
bool _checkString(String s) => | ||
s == | ||
String.fromCharCodes( | ||
Uint8List.sublistView(_read(s.length)), | ||
); | ||
|
||
/// Reads a string of the same length as [s], then checks that the read string | ||
/// matches [s]. Throws a [FormatException] if they don't match. [s] must be | ||
/// ASCII only. | ||
void assertString(String s) { | ||
if (!_checkString(s)) { | ||
throw FormatException('WAV is corrupted, or not a WAV file.'); | ||
} | ||
} | ||
|
||
/// Reads RIFF chunks until one is found that has the given [identifier]. When | ||
/// this function returns, the read head will either be just after the | ||
/// [identifier] (about to read the size), or at the end of the buffer. | ||
void findChunk(String identifier) { | ||
while (!_checkString(identifier)) { | ||
final size = readUint32(); | ||
skip(roundUpToEven(size)); | ||
} | ||
} | ||
|
||
double _readSample8bit() => intToSample(readUint8(), 8); | ||
double _readSample16Bit() => intToSample(fold(readUint16(), 16), 16); | ||
double _readSample24Bit() => intToSample(fold(readUint24(), 24), 24); | ||
double _readSample32Bit() => intToSample(fold(readUint32(), 32), 32); | ||
double _readSampleFloat32() => _read(4).getFloat32(0, Endian.little); | ||
double _readSampleFloat64() => _read(8).getFloat64(0, Endian.little); | ||
|
||
/// Returns a closure that reads samples of the given [format] from this | ||
/// buffer. Calling these closures advances the read head of this buffer. | ||
SampleReader getSampleReader(WavFormat format) { | ||
return [ | ||
_readSample8bit, | ||
_readSample16Bit, | ||
_readSample24Bit, | ||
_readSample32Bit, | ||
_readSampleFloat32, | ||
_readSampleFloat64, | ||
][format.index]; | ||
} | ||
} | ||
|
||
/// Reads a sample and returns it as a double, usually in the range [-1, 1]. | ||
typedef SampleReader = double Function(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2022 The wav authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import 'dart:typed_data'; | ||
|
||
import 'util.dart'; | ||
import 'wav_format.dart'; | ||
|
||
/// Utility class to construct a byte buffer by writing little endian ints and | ||
/// floats etc. Every write operation appends to the end of the buffer. | ||
class BytesWriter { | ||
final _bytes = BytesBuilder(); | ||
|
||
/// Writes a Uint8 to the buffer. | ||
void writeUint8(int x) => _bytes.addByte(x); | ||
|
||
/// Writes a Uint16 to the buffer. | ||
void writeUint16(int x) { | ||
writeUint8(x); | ||
writeUint8(x >> 8); | ||
} | ||
|
||
/// Writes a Uint24 to the buffer. | ||
void writeUint24(int x) { | ||
writeUint16(x); | ||
writeUint8(x >> 16); | ||
} | ||
|
||
/// Writes a Uint32 to the buffer. | ||
void writeUint32(int x) { | ||
writeUint24(x); | ||
writeUint8(x >> 24); | ||
} | ||
|
||
void _writeSample8Bit(double x) => writeUint8(sampleToInt(x, 8)); | ||
void _writeSample16Bit(double x) => writeUint16(fold(sampleToInt(x, 16), 16)); | ||
void _writeSample24Bit(double x) => writeUint24(fold(sampleToInt(x, 24), 24)); | ||
void _writeSample32Bit(double x) => writeUint32(fold(sampleToInt(x, 32), 32)); | ||
|
||
void _writeBytes(ByteData b, int n) => _bytes.add(b.buffer.asUint8List(0, n)); | ||
|
||
static final _fbuf = ByteData(8); | ||
void _writeSampleFloat32(double x) => | ||
_writeBytes(_fbuf..setFloat32(0, x, Endian.little), 4); | ||
void _writeSampleFloat64(double x) => | ||
_writeBytes(_fbuf..setFloat64(0, x, Endian.little), 8); | ||
|
||
/// Writes string [s] to the buffer. [s] must be ASCII only. | ||
void writeString(String s) { | ||
for (int c in s.codeUnits) { | ||
_bytes.addByte(c); | ||
} | ||
} | ||
|
||
/// Returns a closure that reads samples of the given [format] from this | ||
/// buffer. Calling these closures advances the read head of this buffer. | ||
SampleWriter getSampleWriter(WavFormat format) => [ | ||
_writeSample8Bit, | ||
_writeSample16Bit, | ||
_writeSample24Bit, | ||
_writeSample32Bit, | ||
_writeSampleFloat32, | ||
_writeSampleFloat64, | ||
][format.index]; | ||
|
||
/// Takes the byte buffer from [this] and clears [this]. | ||
Uint8List takeBytes() => _bytes.takeBytes(); | ||
} | ||
|
||
/// Writes a sample, usually clamping it to the range [-1, 1]. | ||
typedef SampleWriter = void Function(double); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// Copyright 2022 The wav authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
/// Returns the closest number to [x] int the range [0, y]. | ||
int clamp(int x, int y) => x < 0 | ||
? 0 | ||
: x > y | ||
? y | ||
: x; | ||
|
||
/// Shifts int [x] of bit width [bits] up by half the total range, then wraps | ||
/// any overflowing values around to maintain the bit width. This is used to | ||
/// convert between signed and unsigned PCM. | ||
int fold(int x, int bits) => (x + (1 << (bits - 1))) % (1 << bits); | ||
|
||
/// Rounds [x] up to the nearest even number. | ||
int roundUpToEven(int x) => x + (x % 2); | ||
|
||
double _writeScale(int bits) => (1 << (bits - 1)) * 1.0; | ||
double _readScale(int bits) => _writeScale(bits) - 0.5; | ||
|
||
/// Converts an audio sample [x] in the range [-1, 1] to an unsigned integer of | ||
/// bit width [bits]. | ||
int sampleToInt(double x, int bits) => | ||
clamp(((x + 1) * _writeScale(bits)).floor(), (1 << bits) - 1); | ||
|
||
/// Converts an int [x] of bit width [bits] to an audio sample in the range | ||
/// [-1, 1]. | ||
double intToSample(int x, int bits) => (x / _readScale(bits)) - 1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,4 +13,4 @@ | |
// limitations under the License. | ||
|
||
export 'wav_file.dart'; | ||
export 'wav_types.dart'; | ||
export 'wav_format.dart'; |
Oops, something went wrong.