Convert ieee754 half-precision bytes to double and vise versa in Flutter - flutter

I have a device that provides temperature data in ieee754 half-precision float format, i.e. [78, 100] = +25.5C.
Now, Dart/Flutter doesn't support HP-Float conversions out of the box. After googling around, I have found several solutions that I was able to put together into one that seems to be working fine. Having not done this for many years I am asking pro's to look this over. Also, I'm sure this will save some time to folks like me who need this functionality. This has been tested in temperatures from -10C to +35C and seems to convert correctly both ways. Here _ieee754HpBytesToDouble converts HPF bytes to 64-bit double and _ieee754HpBytesFromDouble converts 64-bit double to half-precision bytes.
///
/// Double to Uint8List
///
Uint8List _ieee754HpBytesFromDouble(double fval) {
int result = _doubleToBits(fval);
Uint8List beef = _int32bytes(result);
return Uint8List.fromList(beef.reversed.skip(2).toList());
}
///
/// Double to hp-float bits
///
int _doubleToBits(double fval) {
ByteData bdata = ByteData(8);
bdata.setFloat32(0, fval);
int fbits = bdata.getInt32(0);
int sign = fbits >> 16 & 0x8000;
int val = (fbits & 0x7fffffff) + 0x1000;
if (val >= 0x47800000) {
if ((fbits & 0x7fffffff) >= 0x47800000) {
if (val < 0x7f800000) return sign | 0x7c00;
return sign | 0x7c00 | (fbits & 0x007fffff) >> 13;
}
return sign | 0x7bff;
}
if (val >= 0x38800000) return sign | val - 0x38000000 >> 13;
if (val < 0x33000000) return sign;
val = (fbits & 0x7fffffff) >> 23;
return sign |
((fbits & 0x7fffff | 0x800000) + (0x800000 >> val - 102) >> 126 - val);
}
///
///
///
Uint8List _int32bytes(int value) =>
Uint8List(4)..buffer.asInt32List()[0] = value;
///
///
///
double _bitsToDouble(int bits) {
Uint8List list = _int32bytes(bits);
ByteBuffer buffer = new Int8List.fromList(list.reversed.toList()).buffer;
ByteData byteData = new ByteData.view(buffer);
double result = byteData.getFloat32(0);
return result;
}
///
///
///
double _ieee754HpBytesToDouble(List<int> i) {
int hbits = i[0] * 256 + i[1];
int mant = hbits & 0x03ff;
int exp = hbits & 0x7c00;
if (exp == 0x7c00)
exp = 0x3fc00;
else if (exp != 0) {
exp += 0x1c000;
if (mant == 0 && exp > 0x1c400) {
return _bitsToDouble((hbits & 0x8000) << 16 | exp << 13 | 0x3ff);
}
} else if (mant != 0) {
exp = 0x1c400;
do {
mant <<= 1;
exp -= 0x400;
} while ((mant & 0x400) == 0);
mant &= 0x3ff;
}
return _bitsToDouble((hbits & 0x8000) << 16 | (exp | mant) << 13);
}

For FP64<->FP32 conversion, use standard casting and for FP32<->FP16 conversion use these ultra-efficient conversion algorithms:
double half_to_double(const ushort x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
return (double)half_to_float(x);
}
ushort double_to_half(const double x) { // IEEE-754 16-bit floating-point format (without infinity): 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits
return float_to_half((float)x);
}

Related

Processing heterogenous information as it arrives from a Socket

A server sends heterogeneous information as stream of bytes. Strings, for instance, are sent with 4 bytes indicating the length and then the characters. This means that my client app must read 4 bytes as an int (which implies that the 4 bytes are available) and then read as many bytes as indicated (the strings are latin1-encoded).
So far I tried two methods: read synchronously with a RawSocket and read the full data dump asynchronously with Socket.listen and process it later. The first method blocks the application, the second is wasteful as it requires to store all the data before processing it.
What I could do for asynchronously read N bytes from a Socket, process them, then read M bytes, process them, etc?
This sounds like you need a ring buffer/byte queue where you can append more data when it arrives, then consume as much as needed from the head when it's available.
There are different ways to implement one, depending on how much you want to avoid copying the bytes. The simplest would be a growing backing buffer with copying. The second approach would be keeping the original lists and combining them when you read only.
Here's a sample implementation:
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: BSD-3-Clause
import "dart:typed_data" show Uint8List;
import "dart:collection" show Queue;
/// A cyclic buffer of bytes.
///
/// Bytes can be appended to the end of the buffer using [append]
/// and consumed from the start of the buffer by [read].
class ByteQueue {
Uint8List _buffer;
int _start = 0;
int _length = 0;
/// Creates a buffer with zero bytes.
///
/// If [initialCapacity] is provided, the buffer will start out
/// with that many bytes of initial capacity. It will not need to
/// grow until that capacity is exhausted.
ByteQueue({int initialCapacity = 256}) : _buffer = Uint8List(initialCapacity);
int get _end {
var end = _start + _length;
if (end > _buffer.length) end -= _buffer.length;
return end;
}
/// Number of bytes currently in the buffer.
///
/// This is the maximal number that can be read by [read] and [peek].
int get length => _length;
int operator [](int index) {
RangeError.checkValidIndex(index, _length);
var i = _start + index;
if (i > _buffer.length) i -= _buffer.length;
return _buffer[i];
}
/// Writes circular buffers into other circular buffers.
///
/// If [end] \< [start], the range of source wraps around at the end of the list.
/// If [offset] + ([end] - [start]) is greater than `target.length`, then
/// the write wraps around past the end of the list.
static void _write(
Uint8List source, int start, int end, Uint8List target, int offset) {
int length = end - start;
if (length >= 0) {
if (offset + length <= target.length) {
target.setRange(offset, offset + length, source, start);
} else {
var firstPart = target.length - offset;
target.setRange(offset, target.length, source, start);
target.setRange(0, length - firstPart, source, start + firstPart);
}
} else {
var firstPart = source.length - start;
_write(source, start, source.length, target, offset);
_write(source, 0, end, target, offset + firstPart);
}
}
static int _limit(int value, int limit) =>
value < limit ? value : value - limit;
/// Copies the next [count] bytes of the buffer into [target].
///
/// The bytes are *not* removed from the buffer, and can be read again.
/// The bytes are written starting at [offset] in [target].
void peek(int count, Uint8List target, [int offset = 0]) {
RangeError.checkValueInInterval(count, 0, _length, "count");
RangeError.checkValueInInterval(offset, 0, target.length, "offset");
if (target.length < count + offset) {
throw ArgumentError.value(
target, "target", "Must have room for $count elements");
}
var end = _limit(_start + count, _buffer.length);
_write(_buffer, _start, end, target, 0);
}
/// Returns the first byte of the buffer.
///
/// The buffer is not modified.
int peekByte() {
if (_length == 0) throw StateError("No element");
return _buffer[_start];
}
/// Consumes a single byte from the head of the buffer.
int readByte() {
if (_length == 0) throw StateError("No element");
var byte = _buffer[_start];
_start = _limit(_start + 1, _buffer.length);
_length -= 1;
return byte;
}
/// Consumes the next [count] bytes of the buffer and moves them into [target].
///
/// The bytes are removed from the head of the buffer.
/// The bytes are written starting at [offset] in [target].
void read(int count, Uint8List target, [int offset = 0]) {
RangeError.checkValueInInterval(count, 0, _length, "count");
RangeError.checkValueInInterval(offset, 0, target.length, "offset");
if (target.length < count + offset) {
throw ArgumentError.value(
target, "target", "Must have room for $count elements");
}
var end = _limit(_start + count, _buffer.length);
_write(_buffer, _start, end, target, 0);
_start = _limit(_start + count, _buffer.length);
_length -= count;
}
/// Removes the first [count] bytes from the buffer.
///
/// Can be useful after a [peek] has turned out to be the bytes
/// that you need, or if you know that the following bytes are
/// not useful.
void remove(int count) {
RangeError.checkValueInInterval(count, 0, _length, "count");
_start = _limit(_start + count, _buffer.length);
;
}
/// Appends [bytes] to the end of the buffer.
void append(Uint8List bytes) {
var newLength = _length + bytes.length;
if (newLength > _buffer.length) {
_grow(newLength);
}
_write(bytes, 0, bytes.length, _buffer, _end);
_length = newLength;
}
void _grow(int newLength) {
var capacity = _buffer.length;
do {
capacity *= 2;
} while (capacity < newLength);
var newBuffer = Uint8List(capacity);
_write(_buffer, _start, _end, newBuffer, 0);
_buffer = newBuffer;
_start = 0;
}
}
// Or another one with the same interface,
// but which doesn't copy bytes into the buffer, only out of it.
class ByteQueue2 {
final Queue<Uint8List> _source = Queue();
int _length = 0;
// The offset into the first element of _source that we haven't consumed.
int _start = 0;
int get length => _length;
void append(Uint8List bytes) {
_source.add(bytes);
_length += bytes.length;
}
int peekByte() {
if (_length == 0) throw StateError("No element");
return _source.first[_start];
}
int readByte() {
if (_length == 0) throw StateError("No element");
var first = _source.first;
var byte = first[_start];
_start += 1;
if (_start >= first.length) {
_source.removeFirst();
_start = 0;
}
_length -= 1;
return byte;
}
void peek(int count, Uint8List target, [int offset = 0]) {
RangeError.checkValueInInterval(count, 0, _length, "count");
RangeError.checkValueInInterval(offset, 0, target.length, "offset");
if (offset + count > target.length) {
throw ArgumentError.value(target, "target",
"Must have length >= ${offset + count}, was: ${target.length}");
}
var start = _start;
for (var source in _source) {
if (count == 0) return;
var length = source.length - start;
if (count <= length) {
target.setRange(offset, offset + count, source, start);
return;
}
target.setRange(offset, offset + length, source, start);
start = 0;
offset += length;
}
}
void read(int count, Uint8List target, [int offset = 0]) {
RangeError.checkValueInInterval(count, 0, _length, "count");
RangeError.checkValueInInterval(offset, 0, target.length, "offset");
if (offset + count > target.length) {
throw ArgumentError.value(target, "target",
"Must have length >= ${offset + count}, was: ${target.length}");
}
var start = _start;
while (count > 0) {
var source = _source.first;
var length = source.length - start;
if (count < length) {
target.setRange(offset, offset + count, source, start);
_start = start + count;
_length -= count;
return;
}
target.setRange(offset, offset + length, source, start);
offset += length;
count -= length;
_length -= length;
start = _start = 0;
_source.removeFirst();
}
}
}
(No priomises).

Why bool func of HasFlag analog ((data & flag) == flag) always return true

I am having a problem checking for flags. For some reason it always returns True. (The same function works correctly on the CPU.)
bool HasFlag(uint data, uint flag) { return (data & flag) == flag; }
Check:
if (HasFlag(tag, Invisible | Deleted))
When writing a check without a function, everything is considered correct:
if (tag & (Invisible | Deleted) == (Invisble | Deleted))
Full code:
const uint Invisible = 1 << 0;
const uint Deleted = 1 << 1;
const uint Selected = 1 << 2;
struct Tag
{
uint tag;
};
RWStructuredBuffer<uint> IndexBuffer;
StructuredBuffer<float3> PositionBuffer;
StructuredBuffer<float> ScaleBuffer;
RWStructuredBuffer<Tag> TagsBuffer;
AppendStructuredBuffer<uint> SelectedItems;
AppendStructuredBuffer<uint> SelectedIndex;
int Length;
float3 RayOrigin;
float3 RayDirection;
float ScaleFactor;
uint SetFlag(uint data, uint flag) { return data | flag; }
uint UnsetFlag(uint data, uint flag) { return data & (~flag); }
uint FlipFlag(uint data, uint flag) { return data ^ flag; }
bool HasFlag(uint data, uint flag) { return (data & flag) == flag; } //<-- problem func
#pragma kernel PointSelect
[numthreads(64, 1, 1)]
void PointSelect(uint3 id : SV_DispatchThreadID)
{
if (id.x < Length)
{
uint tag = TagsBuffer[id.x].tag;
if (HasFlag(tag, Invisible | Deleted)) //<--- always passes (tag == 0)
{
float3 pos = PositionBuffer[id.x];
float3 spos = pos - RayOrigin;
float scale = ScaleBuffer[id.x] * 0.2f * ScaleFactor;
float dist = sqrt(spos.x*spos.x + spos.y*spos.y + spos.z*spos.z);
float3 rayPos = RayOrigin + dist*RayDirection;
float3 srPos = rayPos - pos;
if (srPos.x*srPos.x + srPos.y*srPos.y + srPos.z*srPos.z <= scale * scale)
{
TagsBuffer[id.x].tag = tag | Selected;
SelectedItems.Append(IndexBuffer[id.x]);
SelectedIndex.Append(id.x);
}
}
}
}
Thank you in advance.
P.S. Google Translate
Edit 1: I noticed that in my example, differently arranged brackets and decided to check the priority of operators (https://en.cppreference.com/w/c/language/operator_precedence). As a result, == takes precedence over &. As a result, the "correctly executed variant" looks like: date & (flag == flag). Why it works - I can't imagine. I'll go figure it out.
Edit 2: These funcs work correctly on CPU, but on GPU always return true for some unknown reason:
inline bool AllFlags(uint data, uint flags) { return (data & flags) == flags; }
inline bool AnyFlags(uint data, uint flags) { return (data & flags) > 0; }
inline bool NoneFlags(uint data, uint flags) { return (data & flags) == 0; }
Edit 3: When I use numbers instead of constants when calling functions everything works. The error lies in the definition of constants.
As I was able to understand, the problem was hidden in the fact that when declaring constants I did not register that they are static. As a result, as I understand it, they took the value 0 regardless of what value I assigned them.
The problem was solved when changing:
const uint Invisible = 1 << 0;
const uint Deleted = 1 << 1;
const uint Selected = 1 << 2;
On the:
static const uint Invisible = 1 << 0;
static const uint Deleted = 1 << 1;
static const uint Selected = 1 << 2;
I hope no one else will step on my rake. A lot of hours went down the drain because of the most banal thing.

Converts a string into an array of bytes dart

I am consuming a web service that return an XML of data, how can i convert a string containing lexical representation xsd:hexBinary not base64 format to Uint8List, coming from java i can do this by :
import javax.xml.bind.DatatypeConverter;
....
byte[] decoder = DatatypeConverter.parseHexBinary(hexStringXls);
or
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
Is this what you want?
final s = "somestring";
final List<int> bytes = s.codeUnits;
https://api.dart.dev/stable/2.8.4/dart-core/String/codeUnits.html

How do I use BER encoding with object System.DirectoryServices.Protocols.BerConverter.Encode("???", myData)

I need to encode and decode BER data. .NET has the class System.DirectoryServices.Protocols.BerConverter
The static method requires me to enter a string in the first parameter as shown below
byte[] oid = { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA
var result2 = System.DirectoryServices.Protocols.BerConverter.Decoding("?what goes here?", oid);
BER encoding is used in LDAP, Certificates, and is commonplace in many other formats.
I'll be happy with information telling me how to Encode or Decode on this class. There is nothing on Stack Overflow or the first few pages of Google (or Bing) regarding this.
Question
How do I convert the byte array above to the corresponding OID using BER decoding?
How can I parse (or attempt to parse) SubjectPublicKeyInfo ASN.1 data in DER or BER format?
It seems the DER encoding\decoding classes are internal to the .NET framework. If so, where are they? (I'd like to ask connect.microsoft.com to make these members public)
How do I convert the byte array above to the corresponding OID using BER decoding?
After you have extracted the OID byte array, you can convert it to an OID string using OidByteArrayToString(). I have included the code below, since I couldn't find a similar function in the .NET libraries.
How can I parse (or attempt to parse) SubjectPublicKeyInfo ASN.1 data in DER or BER format?
I was not able to find a TLV parser in the .NET SDK either. Below is an implementation of a BER TLV parser, BerTlv. Since DER is a subset of BER, parsing will work the same way. Given a BER-TLV byte[] array, it will return a list of BerTlv objects that support access of sub TLVs.
It seems the DER encoding\decoding classes are internal to the .NET framework. If so, where are they? (I'd like to ask connect.microsoft.com to make these members public)
Maybe somebody else can answer this question.
Summary
Here is an example of how you can use the code provided below. I have used the public key data you provided in your previous post. The BerTlv should probably be augmented to support querying like BerTlv.getValue(rootTlvs, '/30/30/06');.
public static void Main(string[] args)
{
string pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB";
byte[] pubkeyByteArray = Convert.FromBase64String(pubkey);
List<BerTlv> rootTlvs = BerTlv.parseTlv(pubkeyByteArray);
BerTlv firstTlv = rootTlvs.Where(tlv => tlv.Tag == 0x30).First();//first sequence (tag 30)
BerTlv secondTlv = firstTlv.SubTlv.Where(tlv => tlv.Tag == 0x30).First();//second sequence (tag 30)
BerTlv oid = secondTlv.SubTlv.Where(tlv => tlv.Tag == 0x06).First();//OID tag (tag 30)
string strOid = OidByteArrayToString(oid.Value);
Console.WriteLine(strOid);
}
Output:
1.2.840.113549.1.1.1
OID Encode/Decode
public static byte[] OidStringToByteArray(string oid)
{
string[] split = oid.Split('.');
List<byte> retVal = new List<byte>();
//root arc
if (split.Length > 0)
retVal.Add((byte)(Convert.ToInt32(split[0])*40));
//first arc
if (split.Length > 1)
retVal[0] += Convert.ToByte(split[1]);
//subsequent arcs
for (int i = 2; i < split.Length; i++)
{
int arc_value = Convert.ToInt32(split[i]);
Stack<byte> bytes = new Stack<byte>();
while (arc_value != 0)
{
byte val = (byte) ((arc_value & 0x7F) | (bytes.Count == 0 ? 0x0:0x80));
arc_value >>= 7;
bytes.Push(val);
}
retVal.AddRange(bytes);
}
return retVal.ToArray();
}
public static string OidByteArrayToString(byte[] oid)
{
StringBuilder retVal = new StringBuilder();
//first byte
if (oid.Length > 0)
retVal.Append(String.Format("{0}.{1}", oid[0] / 40, oid[0] % 40));
// subsequent bytes
int current_arc = 0;
for (int i = 1; i < oid.Length; i++)
{
current_arc = (current_arc <<= 7) | oid[i] & 0x7F;
//check if last byte of arc value
if ((oid[i] & 0x80) == 0)
{
retVal.Append('.');
retVal.Append(Convert.ToString(current_arc));
current_arc = 0;
}
}
return retVal.ToString();
}
BER-TLV Parser
class BerTlv
{
private int tag;
private int length;
private int valueOffset;
private byte[] rawData;
private List<BerTlv> subTlv;
private BerTlv(int tag, int length, int valueOffset, byte[] rawData)
{
this.tag = tag;
this.length = length;
this.valueOffset = valueOffset;
this.rawData = rawData;
this.subTlv = new List<BerTlv>();
}
public int Tag
{
get { return tag; }
}
public byte[] RawData
{
get { return rawData; }
}
public byte[] Value
{
get
{
byte[] result = new byte[length];
Array.Copy(rawData, valueOffset, result, 0, length);
return result;
}
}
public List<BerTlv> SubTlv
{
get { return subTlv; }
}
public static List<BerTlv> parseTlv(byte[] rawTlv)
{
List<BerTlv> result = new List<BerTlv>();
parseTlv(rawTlv, result);
return result;
}
private static void parseTlv(byte[] rawTlv, List<BerTlv> result)
{
for (int i = 0, start=0; i < rawTlv.Length; start=i)
{
//parse Tag
bool constructed_tlv = (rawTlv[i] & 0x20) != 0;
bool more_bytes = (rawTlv[i] & 0x1F) == 0x1F;
while (more_bytes && (rawTlv[++i] & 0x80) != 0) ;
i++;
int tag = Util.getInt(rawTlv, start, i-start);
//parse Length
bool multiByte_Length = (rawTlv[i] & 0x80) != 0;
int length = multiByte_Length ? Util.getInt(rawTlv, i+1, rawTlv[i] & 0x1F) : rawTlv[i];
i = multiByte_Length ? i + (rawTlv[i] & 0x1F) + 1: i + 1;
i += length;
byte[] rawData = new byte[i - start];
Array.Copy(rawTlv, start, rawData, 0, i - start);
BerTlv tlv = new BerTlv(tag, length, i - length, rawData);
result.Add(tlv);
if (constructed_tlv)
parseTlv(tlv.Value, tlv.subTlv);
}
}
}
Here is a utility class that contains some functions used in the class above. It is included for the sake of clarity how it works.
class Util
{
public static string getHexString(byte[] arr)
{
StringBuilder sb = new StringBuilder(arr.Length * 2);
foreach (byte b in arr)
{
sb.AppendFormat("{0:X2}", b);
}
return sb.ToString();
}
public static byte[] getBytes(String str)
{
byte[] result = new byte[str.Length >> 1];
for (int i = 0; i < result.Length; i++)
{
result[i] = (byte)Convert.ToInt32(str.Substring(i * 2, 2), 16);
}
return result;
}
public static int getInt(byte[] data, int offset, int length)
{
int result = 0;
for (int i = 0; i < length; i++)
{
result = (result << 8) | data[offset + i];
}
return result;
}
}

How can i adapt speex echo canceller to process a float samples?

Good day! how сan i use float samples for echo cancellation processing? I tried to change interface and body of central function:
from
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out);
to
void float_speex_echo_cancellation(SpeexEchoState *st, const float rec[], const float play[], float out[]);
and from
...
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp_out;
tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
{
if (st->saturated == 0)
st->saturated = 1;
}
**out[i*C+chan] = (spx_int16_t)WORD2INT(tmp_out);**
st->memE[chan] = tmp_out;
}
...
to
...
for (i=0;i<st->frame_size;i++)
{
spx_word32_t tmp_out;
tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size]));
tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan])));
if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000)
{
if (st->saturated == 0)
st->saturated = 1;
}
**out[i*C+chan] = /*(spx_int16_t)WORD2INT(*/tmp_out*/)*/;**
st->memE[chan] = tmp_out;
}
...
and from
static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
{
int i;
spx_word16_t den2;
den2 = (spx_word16_t)(radius*radius + .7f*(1.f-radius)*(1.f-radius));
for (i=0;i<len;i++)
{
spx_int16_t vin = in[i*stride];
spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
mem[0] = mem[1] + 2*(-vin + radius*vout);
mem[1] = SHL32(EXTEND32(vin),15) - MULT16_32_Q15(den2,vout);
out[i] = SATURATE32(PSHR32(MULT16_32_Q15(radius,vout),15),32767);
}
}
to
static inline void float_filter_dc_notch16(const /*spx_int16_t*/spx_word16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride)
{
int i;
spx_word16_t den2;
den2 = /*(spx_word16_t)*/(radius*radius + .7f*(1.f-radius)*(1.f-radius));
for (i=0;i<len;i++)
{
/*spx_int16_t*/spx_word16_t vin = in[i*stride];
spx_word32_t vout = mem[0] + SHL32(EXTEND32(vin),15);
mem[0] = mem[1] + 2*(-vin + radius*vout);
mem[1] = SHL32(EXTEND32(vin),15) - MULT16_32_Q15(den2,vout);
out[i] = /*SATURATE32(*/PSHR32(MULT16_32_Q15(radius,vout),15)/*,32767)*/;
}
}
So, i prevented conversion from float type output result to short int, but now i get a warning:
speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now.");
that points to st->screwed_up parameter having 50 values and it signs of setting to zero all out samples:
...
if (!(Syy>=0 && Sxx>=0 && See >= 0)
|| !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9)
)
{ st->screwed_up += 50; for (i=0;iframe_size*C;i++) out[i] = 0; }
...
What can i do?
enter code here
Why do you want to use float samples?
Standard linear PCM audio is represented as integer samples according to the chosen bitrate - 8 bit, 16 bit and so on.
Where do you get that input from?
If I were you I would just convert whatever you got to shorts and provide it to Speex so it can work with it.