Cheeze/src/infra/Audio.cpp
DarkSlein 6cc1cb34f1 Implemented preceding buffer
Implemented noise detection from preceding buffer

Bug with ready request (core is panicked)

Bug with noise detection (works sometimes)
2024-05-16 12:58:51 +03:00

182 lines
4.8 KiB
C++

#include "infra/Audio.h"
#include <base64.h>
#include "config/config.h"
#define PRECEDING_BUFFER_SIZE 4
Audio::Audio(MicType micType) {
_wavData = new char*[_wavDataSize/_dividedWavDataSize];
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i)
_wavData[i] = new char[_dividedWavDataSize];
_precedingWavBuffer = new CircularBuffer<char*>(PRECEDING_BUFFER_SIZE); // _precedingWavDataSize/_dividedWavDataSize
i2s = new I2S(micType);
}
Audio::~Audio() {
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) delete[] _wavData[i];
delete[] _wavData;
delete i2s;
emptyPrecedingBuffer();
}
void Audio::_createWavHeader(byte* header, int waveDataSize){
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
unsigned int fileSizeMinus8 = waveDataSize + 44 - 8;
header[4] = (byte)(fileSizeMinus8 & 0xFF);
header[5] = (byte)((fileSizeMinus8 >> 8) & 0xFF);
header[6] = (byte)((fileSizeMinus8 >> 16) & 0xFF);
header[7] = (byte)((fileSizeMinus8 >> 24) & 0xFF);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 0x10; // linear PCM
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
header[20] = 0x01; // linear PCM
header[21] = 0x00;
header[22] = 0x01; // monoral
header[23] = 0x00;
header[24] = 0x80; // sampling rate 16000
header[25] = 0x3E;
header[26] = 0x00;
header[27] = 0x00;
header[28] = 0x00; // Byte/sec = 16000x2x1 = 32000
header[29] = 0x7D;
header[30] = 0x00;
header[31] = 0x00;
header[32] = 0x02; // 16bit monoral
header[33] = 0x00;
header[34] = 0x10; // 16bit
header[35] = 0x00;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(waveDataSize & 0xFF);
header[41] = (byte)((waveDataSize >> 8) & 0xFF);
header[42] = (byte)((waveDataSize >> 16) & 0xFF);
header[43] = (byte)((waveDataSize >> 24) & 0xFF);
}
char** Audio::record() {
_noiseDetectedInPrecedingBuffer = false;
_createWavHeader(_paddedHeader, _wavDataSize);
_startMicros = micros();
//_readFromPrecedingBuffer(_wavData, _precedingWavDataSize);
//_recordToBuffer(_wavData + _precedingWavDataSize, _wavDataSize - _precedingWavDataSize);
_recordToBuffer(_wavData, _wavDataSize);
return _wavData;
}
void Audio::_recordToBuffer(char** wavBuffer, int waveDataSize) {
int bitBitPerSample = i2s->GetBitPerSample();
if (bitBitPerSample == 16) {
for (int j = 0; j < waveDataSize / _dividedWavDataSize; ++j) {
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
_convertBufferToWav(wavBuffer[j]);
}
}
else if (bitBitPerSample == 32) {
for (int j = 0; j < waveDataSize / _dividedWavDataSize; ++j) {
i2s->Read(_i2sBuffer, _i2sBufferSize);
for (int i = 0; i < _i2sBufferSize/8; ++i) {
wavBuffer[j][2*i] = _i2sBuffer[8*i + 2] << 4; // TODO: check << 4 in 16bit
wavBuffer[j][2*i + 1] = _i2sBuffer[8*i + 3] << 4;
}
}
}
}
void Audio::emptyPrecedingBuffer() {
while (!_precedingWavBuffer->isEmpty()) {
char* tmp;
_precedingWavBuffer->popFront(tmp);
delete tmp;
}
}
void Audio::writeToPrecedingBuffer() {
if (_precedingWavBuffer->isFull()) {
char* tmp;
_precedingWavBuffer->popFront(tmp);
delete tmp;
}
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
_noiseDetectedInPrecedingBuffer = _isNoiseDetectedInPrecedingBuffer();
char* _partialWavBuffer = new char[_precedingWavDataSize];
_convertBufferToWav(_partialWavBuffer);
CircularBufferErrorCode err = _precedingWavBuffer->pushBack(_partialWavBuffer);
}
void Audio::_readFromPrecedingBuffer(char** wavBuffer, int waveDataSize) {
char* tmp;
for (int i = 0; i < PRECEDING_BUFFER_SIZE; i++) {
_precedingWavBuffer->popFront(tmp);
wavBuffer[i] = tmp;
}
emptyPrecedingBuffer();
}
void Audio::_convertBufferToWav(char* partialWavBuffer) {
for (int i = 0; i < _i2sBufferSize/8; ++i) {
partialWavBuffer[2*i] = _i2sBuffer[4*i + 2];
partialWavBuffer[2*i + 1] = _i2sBuffer[4*i + 3];
}
}
int Audio::getSize() {
return (_wavDataSize + sizeof(_paddedHeader)) * 4 / 3; // 4/3 is from base64 encoding
}
String Audio::print(Stream* stream) {
String enc = base64::encode(_paddedHeader, sizeof(_paddedHeader));
enc.replace("\n", "");
stream->print(enc);
for (int j = 0; j < _wavDataSize / _dividedWavDataSize; ++j) {
enc = base64::encode((byte*)_wavData[j], _dividedWavDataSize);
enc.replace("\n", "");
stream->print(enc);
}
return enc;
}
unsigned long Audio::getStartMicros() {
return _startMicros;
}
bool Audio::_isNoiseDetectedInPrecedingBuffer() {
if (*(int*)_i2sBuffer > NOISE_THRESHOLD || *(int*)_i2sBuffer < -NOISE_THRESHOLD) {
Serial.println("Noise detected");
return true;
} else {
return false;
}
}
bool Audio::isNoiseDetected() {
return _noiseDetectedInPrecedingBuffer;
}