将 esp8266 代码(部分)转换为 c/c++ 或 c#

Convert esp8266 code(part of it) to c/c++ or c#

嗨,我正在尝试重复这个基于 esp8266 的 wifi 婴儿监视器项目: baby monitor project 但是我不想在另一个 esp8266 上接收数据,而是想在 pc 上接收数据。 我是一名 C# 程序员,我遇到了理解 c/c++ 指针数组如何在这里工作和接收 udp 的问题。

这是 esp8266 接收器源代码,可以正常工作,但它接收到的数据会将它们传递给 DAC。而且我无法弄清楚我在哪里可以只一个一个地读取 esp8266 发射器从 ADC 读取的值。从 ADC 读取的数据也是 12 位的,原始代码的作者使用所有 16 位并进行一些压缩来传输更多数据,而这个压缩部分是我难以理解的

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include "ESP8266mDNS.h"
#include <ArduinoOTA.h>

//#include "wifi_params.h"


const int mySDA = D7;
const int mySCL = D6;

const int AMPLI_MUTE_PIN = D2;
const int AMPLI_SHUTDOWN_PIN = D1;

const int RIGHT_BTN = D3;
const int LEFT_BTN = D4;
const int LED1 = D8;

const int udp_recv_port = 45990;

WiFiUDP udp;
TwoWire i2c;

#define NB_DATA_BUFS 5
uint16_t data_buf[NB_DATA_BUFS][700]; // data buffer, N buffered

unsigned int current_play_data_buf; // current data buf being played
unsigned int play_data_buf_pos; // position in the ADC data buffer
unsigned int current_recv_data_buf; // current data buf being received

bool play_waiting = true;
bool amplifier_stopped = false;
long play_waiting_at;

bool left_btn_pressed;
bool right_btn_pressed;

#define ICACHE_RAM_ATTR     __attribute__((section(".iram.text")))
#define twi_sda mySDA
#define twi_scl mySCL
#define twi_dcount 0
#define twi_clockStretchLimit 10
#define SDA_LOW()   (GPES = (1 << twi_sda)) //Enable SDA (becomes output and since GPO is 0 for the pin, it will pull the line low)
#define SDA_HIGH()  (GPEC = (1 << twi_sda)) //Disable SDA (becomes input and since it has pullup it will go high)
#define SDA_READ()  ((GPI & (1 << twi_sda)) != 0)
#define SCL_LOW()   (GPES = (1 << twi_scl))
#define SCL_HIGH()  (GPEC = (1 << twi_scl))
#define SCL_READ()  ((GPI & (1 << twi_scl)) != 0)

static void twi_delay(unsigned char v) {
  unsigned int i;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
  unsigned int reg;
  for (i = 0; i<v; i++) reg = GPI;
#pragma GCC diagnostic pop
}

static inline ICACHE_RAM_ATTR bool twi_write_start(void) {
  SCL_HIGH();
  SDA_HIGH();
  if (SDA_READ() == 0) return false;
  SDA_LOW();
  return true;
}

static inline ICACHE_RAM_ATTR bool twi_write_stop(void) {
  uint32_t i = 0;
  SCL_LOW();
  SDA_LOW();
  SCL_HIGH();
  while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit); // Clock stretching
  SDA_HIGH();

  return true;
}

static inline ICACHE_RAM_ATTR bool twi_write_bit(bool bit) {
  uint32_t i = 0;
  SCL_LOW();
  if (bit) SDA_HIGH();
  else SDA_LOW();
  twi_delay(twi_dcount + 1);
  SCL_HIGH();
  while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
  return true;
}

static inline ICACHE_RAM_ATTR bool twi_read_bit(void) {
  uint32_t i = 0;
  SCL_LOW();
  SDA_HIGH();
  twi_delay(twi_dcount + 2);
  SCL_HIGH();
  while (SCL_READ() == 0 && (i++) < twi_clockStretchLimit);// Clock stretching
  bool bit = SDA_READ();
  return bit;
}

static inline ICACHE_RAM_ATTR bool twi_write_byte(unsigned char byte) {
  unsigned char bit;
  for (bit = 0; bit < 8; bit++) {
    twi_write_bit(byte & 0x80);
    byte <<= 1;
  }
  return !twi_read_bit();//NACK/ACK
}

static inline ICACHE_RAM_ATTR unsigned char twi_read_byte(bool nack) {
  unsigned char byte = 0;
  unsigned char bit;
  for (bit = 0; bit < 8; bit++) byte = (byte << 1) | twi_read_bit();
  twi_write_bit(nack);
  return byte;
}


unsigned char inline ICACHE_RAM_ATTR mytwi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop) {
  unsigned int i;
  if (!twi_write_start()) return 4;//line busy
  if (!twi_write_byte(((address << 1) | 0) & 0xFF)) {
    if (sendStop) twi_write_stop();
    return 2; //received NACK on transmit of address
  }
  for (i = 0; i<len; i++) {
    if (!twi_write_byte(buf[i])) {
      if (sendStop) twi_write_stop();
      return 3;//received NACK on transmit of data
    }
  }
  if (sendStop) twi_write_stop();
  i = 0;
  while (SDA_READ() == 0 && (i++) < 10) {
    SCL_LOW();
    SCL_HIGH();
  }
  return 0;
}



static inline ICACHE_RAM_ATTR uint8_t DAC(uint16_t value)
{
  /* value is 76543210 XXXXBA98
  per the datasheet for fast write:
  1 1 0 0 A2 A1 A0 0 <ACK> 0 0 PD1 PD0 D11 D10 D9 D8 <ACK> D7 D6 D5 D4 D3 D2 D1 D0 <ACK>
  */






  uint8_t buf[2] = { (value >> 8) & 0x0F, (value & 0xFF) };
  int ret = mytwi_writeTo(0x60, buf, 2, true);

  Serial.println(value);

  return ret;
}

void ICACHE_RAM_ATTR playsample_isr(void)
{
  if (play_waiting) {
    return;
  }

  DAC(data_buf[current_play_data_buf][play_data_buf_pos]);
  play_data_buf_pos++;
  if (play_data_buf_pos >= sizeof(data_buf[0]) / sizeof(data_buf[0][0])) {
    play_data_buf_pos = 0;
    current_play_data_buf++;
    if (current_play_data_buf == NB_DATA_BUFS) {
      current_play_data_buf = 0;
    }

    if (current_play_data_buf == current_recv_data_buf) {
      play_waiting = true;
      play_waiting_at = micros();
    }
  }
}

void ota_onstart(void)
{
  // Disable timer when an OTA happens
  timer1_detachInterrupt();
  timer1_disable();
}

void ota_onprogress(unsigned int sz, unsigned int total)
{
  Serial.print("OTA: "); Serial.print(sz); Serial.print("/"); Serial.print(total);
  Serial.print("="); Serial.print(100 * sz / total); Serial.println("%");
}

void ota_onerror(ota_error_t err)
{
  Serial.print("OTA ERROR:"); Serial.println((int)err);
}

void left_btn_intr()
{
  left_btn_pressed = 1;
}

void right_btn_intr()
{
  right_btn_pressed = 1;
}

void setup(void)
{
  Serial.begin(115200);
  Serial.println("I was built on " __DATE__ " at " __TIME__ "");

  i2c.begin(mySDA, mySCL);
  i2c.setClock(400000);

  WiFi.mode(WIFI_STA);
  WiFi.begin("valik 2", "299745buhlo");
  WiFi.setSleepMode(WIFI_MODEM_SLEEP);

  Serial.print("Connecting to wifi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.print("Cnnectd to ");
  Serial.println("valik 2");
  Serial.print("IP ");
  Serial.println(WiFi.localIP());

  ArduinoOTA.onStart(ota_onstart);
  ArduinoOTA.onError(ota_onerror);
  ArduinoOTA.onProgress(ota_onprogress);
  ArduinoOTA.setHostname("bb-recv");
  ArduinoOTA.begin();

  timer1_isr_init();
  timer1_attachInterrupt(playsample_isr);
  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
  timer1_write(clockCyclesPerMicrosecond() / 16 * 50); //50us = 20 kHz sampling freq

  udp.begin(udp_recv_port);

  pinMode(AMPLI_MUTE_PIN, OUTPUT);
  pinMode(AMPLI_SHUTDOWN_PIN, OUTPUT);
  digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
  digitalWrite(AMPLI_MUTE_PIN, 0);

  pinMode(LEFT_BTN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(LEFT_BTN), left_btn_intr, FALLING);
  pinMode(RIGHT_BTN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(RIGHT_BTN), right_btn_intr, FALLING);

  pinMode(LED1, OUTPUT);
  digitalWrite(LED1, 0);

}

int do_undelta7(const uint8_t *val, int sz, uint16_t *out)
{
  // Implement delta 7 decompression.
  // First bit = 0 <=> uncompressed 15 bits following 
  // First bit = 1 <=> 7 bits follow representing delta
  // must switch to big endian...
  uint16_t last = 0;
  uint8_t *ptr = (uint8_t *)&out[0];
  const uint8_t *start = ptr;
  for (int i = 0; i < sz; i++) {
    uint16_t *ptr16 = (uint16_t *)ptr;
    const int8_t firstbyte = val[i];
    if (firstbyte & 0x80) {
      // Delta7 compressed
      // byte is CSMMMMMM
      int8_t delta = firstbyte & 0x3F;
      if (firstbyte & 0x40) {
        delta = -delta;
      }
      const uint16_t value = last + delta;
      *ptr16 = value;
      ptr += 2;

      last = value;
    }
    else {
      // uncompressed -- switch bytes back to LE
      *ptr++ = val[i + 1];
      *ptr++ = val[i];
      last = val[i + 1] | val[i] << 8;
      i++;
    }
  }

  return ptr - start;

}

void loop(void)
{
  ArduinoOTA.handle();
  int sz = udp.parsePacket();
  //Serial.println(current_play_data_buf);
  if (sz) {
    uint8_t buf[sz];
    udp.read(&buf[0], sz);
    current_recv_data_buf++;
    if (current_recv_data_buf == NB_DATA_BUFS) {
      current_recv_data_buf = 0;
      if (current_recv_data_buf == current_play_data_buf && !play_waiting) {
        Serial.println("buffer overflow when receiving");
      }
    }
    do_undelta7(buf, sz, &data_buf[current_recv_data_buf][0]);

    if (play_waiting) {
      Serial.print("Restarting play, was waiting (us)"); Serial.println(micros() - play_waiting_at);
      // Re-enable *then* unmute in that order to avoid pops
      digitalWrite(AMPLI_SHUTDOWN_PIN, 1);
      digitalWrite(AMPLI_MUTE_PIN, 1);
      play_waiting = false;
      amplifier_stopped = false;
      digitalWrite(LED1, 1);
    }

    Serial.println("");
  }

  // If not playing anything, but amplifier is still up
  if (!amplifier_stopped && play_waiting) {
    if ((micros() - play_waiting_at) > 2000 * 1000) {
      // If nothing has been played for two seconds, shut down the amplifier 
      Serial.println("Shutting down amplifier!");
      digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
      digitalWrite(AMPLI_MUTE_PIN, 0);
      amplifier_stopped = true;
      digitalWrite(LED1, 0);
    }
  }

  if (left_btn_pressed) {
    left_btn_pressed = 0;
    digitalWrite(AMPLI_MUTE_PIN, 0);
    digitalWrite(AMPLI_SHUTDOWN_PIN, 0);
  }

  if (right_btn_pressed) {
    digitalWrite(AMPLI_SHUTDOWN_PIN, 1);
    digitalWrite(AMPLI_MUTE_PIN, 1);
    udp.beginPacket(udp.remoteIP(), 45990);
    udp.write("sendnow");
    udp.endPacket();
    right_btn_pressed = 0;
  }

  // If the amplifier is stopped, add a delay for power saving
  if (amplifier_stopped) {
    delay(10);
  }

}

这是我尝试将 windows 的代码转换为 c++。但是我遇到了程序只是冻结而没有任何错误并且没有关闭的问题。

    #include "stdafx.h"
#include <winsock2.h>
#include <stdio.h>
#include <cstdint>
#include <ctime>
#pragma comment (lib, "ws2_32.lib")

#define NB_DATA_BUFS 5
uint16_t data_buf[NB_DATA_BUFS][700]; // data buffer, N buffered

unsigned int current_play_data_buf; // current data buf being played
unsigned int play_data_buf_pos; // position in the ADC data buffer
unsigned int current_recv_data_buf; // current data buf being received

bool play_waiting = true;
bool amplifier_stopped = false;
long play_waiting_at;

bool left_btn_pressed;
bool right_btn_pressed;
void InitWinsock()
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
}

int do_undelta7(const uint8_t *val, int sz, uint16_t *out)
{
    // Implement delta 7 decompression.
    // First bit = 0 <=> uncompressed 15 bits following 
    // First bit = 1 <=> 7 bits follow representing delta
    // must switch to big endian...
    uint16_t last = 0;
    uint8_t *ptr = (uint8_t *)&out[0];
    const uint8_t *start = ptr;
    for (int i = 0; i < sz; i++) {
        uint16_t *ptr16 = (uint16_t *)ptr;
        const int8_t firstbyte = val[i];
        if (firstbyte & 0x80) {
            // Delta7 compressed
            // byte is CSMMMMMM
            int8_t delta = firstbyte & 0x3F;
            if (firstbyte & 0x40) {
                delta = -delta;
            }
            const uint16_t value = last + delta;
            *ptr16 = value;
            ptr += 2;
            last = value;

        }
        else {
            // uncompressed -- switch bytes back to LE
            *ptr++ = val[i + 1];
            *ptr++ = val[i];
            last = val[i + 1] | val[i] << 8;

            i++;
        }
    }

    return ptr - start;

}



void DAC(uint16_t value)
{
    /* value is 76543210 XXXXBA98
    per the datasheet for fast write:
    1 1 0 0 A2 A1 A0 0 <ACK> 0 0 PD1 PD0 D11 D10 D9 D8 <ACK> D7 D6 D5 D4 D3 D2 D1 D0 <ACK>
    */

    uint8_t buf[2] = { (value >> 8) & 0x0F, (value & 0xFF) };

    printf("%u\n", value & 0xFFF);

}

int _tmain(int argc, _TCHAR* argv[])
{
    SOCKET socketC;

    InitWinsock();
    struct sockaddr_in serverInfo;
    int len = 2000;
    serverInfo.sin_family = AF_INET;
    serverInfo.sin_port = htons(45990);
    serverInfo.sin_addr.s_addr = inet_addr("192.168.1.105");

    socketC = socket(AF_INET, SOCK_DGRAM, 0);

    char buffers[16];
    ZeroMemory(buffers, sizeof(buffers));
    sendto(socketC, buffers, sizeof(IReleaseMarshalBuffers), 0, (sockaddr*)&serverInfo, len);



    while (1)
    {

        sockaddr_in from;
        const int paketSize = sizeof(from);

        int r = paketSize;

        char buffer[paketSize];
        sprintf(buffer, "%.7s", "sendnow");

        if (strcmp(buffer, "exit") == 0)
            break;

        recvfrom(socketC, buffer, sizeof(buffer), 0, (sockaddr*)&serverInfo, &len);


                uint8_t buf[sizeof(buffer)];
                uint8_t * bufeerPntr = (uint8_t*)buffer;
                uint8_t * bufPntr = (uint8_t*)buffer;

                for(int i=0;i<sizeof(buffer);i++)
                {
                    buf[i] = buffer[i];
                }

                //udp.read(&buf[0], sizeof(buffer));
                current_recv_data_buf++;
                if (current_recv_data_buf == NB_DATA_BUFS) {
                    current_recv_data_buf = 0;
                    if (current_recv_data_buf == current_play_data_buf && !play_waiting) {
                        printf("buffer overflow when receiving\n");
                    }
                }
                do_undelta7(buf, sizeof(buffer), &data_buf[current_recv_data_buf][0]);

            }

    closesocket(socketC);

    return 0;
}

这是我尝试将解码部分翻译成 c#(c# 对我来说更容易理解)但我不得不使用指针和奇怪的 * 和 & 我难以理解的东西:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class UDPListener
{
    private const int listenPort = 45990;
    public static int Main()
    {
        bool done = false;
        UdpClient listener = new UdpClient(listenPort);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.168.1.3"), listenPort);
        string received_data;
        int BUFSIZE = 700;
        byte[] receive_byte_array;
        uint current_recv_data_buf = 1;



        while (!done)
        {
            Console.WriteLine("Waiting for broadcast");
            receive_byte_array = listener.Receive(ref groupEP);
            Console.WriteLine("Received a broadcast from {0}", groupEP.ToString());

            received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);

            unsafe
            {

                UInt16*[,] data_buf = new UInt16*[5, 700];
                int sz = receive_byte_array.Length;
                if (sz > 0)
                {
                    byte[] buf = new byte[receive_byte_array.Length];

                    UInt16* f = stackalloc UInt16[2000];

                    //udp.read(&buf[0], sz);
                    buf = receive_byte_array;
                    current_recv_data_buf++;

                    UInt16 last = 0;

                        UInt16* @out1 = stackalloc UInt16[800];

                        for (int i = 0; i < 800; i++)
                        {
                            @out1[i] = (char)i;
                        }


                        //UIntPtr* ptr = (UIntPtr*)&@out[0];
                        UIntPtr* ptr = (UIntPtr*)&@out1[0];

                        UIntPtr* start = ptr;
                        for (int i = 0; i < sz; i++)
                        {
                            UIntPtr* ptr16 = ptr;
                            byte firstbyte = buf[i];

                            if ((firstbyte & 0x80) != 0)
                            {
                                // Delta7 compressed
                                // byte is CSMMMMMM
                                byte delta = (byte)(firstbyte & 0x3F);
                                if ((firstbyte & 0x40) != 0)
                                {
                                    delta = (byte)(0 - delta);
                                }

                                UInt16 value = (UInt16)(last + delta);

                                *ptr16 = (UIntPtr)value;
                                ptr += 2;

                                last = value;
                            }
                            else
                            {
                                *ptr++ = (UIntPtr)buf[i + 1];

                                *ptr++ = (UIntPtr)buf[i];
                                last = (UInt16)(buf[i + 1] | buf[i] << 8);
                                i++;
                            }
                        }
                    for (int i = 0; i < 91; i++)
                    {
                        System.Console.WriteLine(@out1[i]);
                    }


                    string b = "";
                }
            }
        }

        listener.Close();
        return 0;
    }
} // end of class UDPListener

udp.read(&buf[0], sz); 将接收到的 UDP 数据包复制到缓冲区 buf。然后函数 do_undelta7 将输入缓冲区中的数据解压缩到输出缓冲区 data_buf[current_recv_data_buf]data_buf 是缓冲区数组。中断 playsample_isr 播放 data_buf.

中缓冲区的内容

我在 do_undelta7 中遗漏了一个无符号字节 所以现在解码很好 c#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Media;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using NAudio.Wave;


public class UDPListener
{
    uint current_recv_data_buf;
    static int NB_DATA_BUFS = 5;
    static UInt16[] data_buf = new UInt16[700];

    uint current_play_data_buf; // current data buf being played
    uint play_data_buf_pos; // position in the ADC data buffer


    private const int listenPort = 45990;



    public static unsafe int Main()
    {
        bool done = false;
        UdpClient listener = new UdpClient(listenPort);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Parse("192.168.1.3"), listenPort);
        int BUFSIZE = 700;
        byte[] receive_byte_array;
        uint current_recv_data_buf = 1;
        List<byte> tenBuffsToPlay = new List<byte>();
        int iterBuffsToPLay = 0;
        byte[] byteArrToPlay = new byte[data_buf.Length * 2];
        byte[] byte10ArrToPlay;
        int pktcount = 0;

        var sampleRate = 20000;
        var frequency = 500;
        var amplitude = 0.2;
        var seconds = 5;

        while (!done)
        {
            receive_byte_array = listener.Receive(ref groupEP);
            if (receive_byte_array.Length > 0)
            {
                Console.WriteLine("received !"+pktcount++);
                int sz = receive_byte_array.Length;
                unsafe
                {

                    byte[] buf = new byte[sz];

                    buf = receive_byte_array;
                   fixed (UInt16* data_bufPtr = &data_buf[0])
                   fixed (byte* ptrbuf = buf)
                   do_undelta7(ptrbuf, sz, data_bufPtr);

                    //string firstPart = "";
                    //string secondPart = "";

                    for (int i =0;i<data_buf.Length;i++)
                    {
                        //Console.WriteLine("Hex: {0:X}", data_buf[i]);

                        byteArrToPlay[i*2] = (byte)((data_buf[i] >> 8)&0x0f);
                        byteArrToPlay[(i*2)+1] = (byte)(data_buf[i] & 0xff);
                        //firstPart = Convert.ToString(byteArrToPlay[i], 2).PadLeft(4, '0');
                        //Console.Write(firstPart);
                        //secondPart = Convert.ToString(byteArrToPlay[i+1], 2).PadLeft(4, '0');
                        //Console.Write(secondPart+"\n");
                    }

                    //byteArrToPlay = data_buf.SelectMany(BitConverter.GetBytes).ToArray();

                    //foreach (var Arr in byteArrToPlay)
                    // {
                    // Console.WriteLine("Hex: {0:X}", Arr);
                    // }
                    tenBuffsToPlay.AddRange(byteArrToPlay);
                    iterBuffsToPLay++;
                    if (iterBuffsToPLay == 3)
                    {
                        byte10ArrToPlay = tenBuffsToPlay.ToArray();


                        /*var raw = new byte[sampleRate * seconds * 2];

                        var multiple = 2.0 * frequency / sampleRate;
                        for (int n = 0; n < sampleRate * seconds; n++)
                        {
                            var sampleSaw = ((n * multiple) % 2) - 1;
                            var sampleValue = sampleSaw > 0 ? amplitude : -amplitude;
                            var sample = (short)(sampleValue * Int16.MaxValue);
                            var bytes = BitConverter.GetBytes(sample);
                            raw[n * 2] = bytes[0];
                            raw[n * 2 + 1] = bytes[1];
                        }*/


                        var ms = new MemoryStream(byte10ArrToPlay);
                        var rs = new RawSourceWaveStream(ms, new WaveFormat(sampleRate, 16, 1));


                        var wo = new WaveOutEvent();
                        wo.Init(rs);
                        wo.Play();
                        /*while (wo.PlaybackState == PlaybackState.Playing)
                        {
                            Thread.Sleep(1);
                        }*/
                        //wo.Dispose();







                        /*using (MemoryStream ms = new MemoryStream())
                        {
                            WriteWavHeader(ms, false, 1, 16, 20000, (byte10ArrToPlay.Length / 2 - 45));
                            // Construct the sound player
                            ms.Write(byte10ArrToPlay, 0, byte10ArrToPlay.Length);
                            ms.Position = 0;
                            SoundPlayer player = new SoundPlayer(ms);
                            player.Play();
                        }*/
                        tenBuffsToPlay.Clear();
                       iterBuffsToPLay = 0;
                    }

                }

            }
        }

        listener.Close();
        return 0;
    }


    static unsafe long do_undelta7(byte* val, int sz, UInt16* outArray)
    {
        // Implement delta 7 decompression.
        // First bit = 0 <=> uncompressed 15 bits following 
        // First bit = 1 <=> 7 bits follow representing delta
        // must switch to big endian...
        UInt16 last = 0;
        byte* ptr = (byte*)&outArray[0];
        byte* start = ptr;
        for (int i = 0; i < sz; i++)
        {
            UInt16* ptr16 = (UInt16*)ptr;
            byte firstbyte = val[i];
            var bit = (firstbyte & (1 << 8 - 1)) != 0;
            if (bit == true)
            {
                // Delta7 compressed
                // byte is CSMMMMMM
                sbyte delta = (sbyte)(firstbyte & 0x3f);
                bit = (firstbyte & (1 << 7 - 1)) != 0;
                if (bit == true)
                {
                    delta = (sbyte)(0x0 - delta);
                }
                UInt16 value = (UInt16)(last + delta);
                *ptr16 = value;
                ptr += 2;

                last = value;
            }
            else
            {
                // uncompressed -- switch bytes back to LE

                *ptr++ = val[i + 1];
                *ptr++ = val[i];
                last = (UInt16)(val[i + 1] | val[i] << 8);
                i++;
            }
        }

        return ptr - start;

    }
    private static void WriteWavHeader(MemoryStream stream, bool isFloatingPoint, ushort channelCount, ushort bitDepth, int sampleRate, int totalSampleCount)
    {
        stream.Position = 0;
        stream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);
        stream.Write(BitConverter.GetBytes((2* totalSampleCount) + 36), 0, 4);
        stream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);
        stream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
        stream.Write(BitConverter.GetBytes(16), 0, 4);
        stream.Write(BitConverter.GetBytes((ushort)(isFloatingPoint ? 3 : 1)), 0, 2);
        stream.Write(BitConverter.GetBytes(channelCount), 0, 2);
        stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
        stream.Write(BitConverter.GetBytes(sampleRate * 2), 0, 4);
        stream.Write(BitConverter.GetBytes((ushort)2), 0, 2);
        stream.Write(BitConverter.GetBytes(16), 0, 2);
        stream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
        stream.Write(BitConverter.GetBytes(2 * totalSampleCount), 0, 4);
    }


} // end of class UDPListener